| 1 | |
|---|
| 2 | CDRTool rating engine |
|---|
| 3 | --------------------- |
|---|
| 4 | |
|---|
| 5 | CDRTool provides on-the-fly rating of CDRs from multiple data-sources like |
|---|
| 6 | OpenSIPS, Asterisk or Cisco gateways based on easy to build rating plan, |
|---|
| 7 | which can be provisioned in a web interface or imported from csv files. |
|---|
| 8 | |
|---|
| 9 | A Call Detail Record (CDR) is one record from the radius radacct table. The |
|---|
| 10 | CDR contains all information related to a session, its duration, the calling |
|---|
| 11 | and called party and media information. The rating engine calculates the |
|---|
| 12 | price of the session. The calculation is done once and its results are saved |
|---|
| 13 | in the CDR table for later use. It is possible to re-calculated the prices |
|---|
| 14 | at a later time for example when having to change the tariffs. |
|---|
| 15 | |
|---|
| 16 | Based on exceptions, different rates may be applied per caller party |
|---|
| 17 | identified by source IP, domain or subscriber. |
|---|
| 18 | |
|---|
| 19 | Rating is applied only after the call has ended. CDRTool considers that a |
|---|
| 20 | call has ended when there is a stop time. |
|---|
| 21 | |
|---|
| 22 | In case of missing BYEs, CDRTool relies on the fact that MediaProxy will |
|---|
| 23 | update the CDR with the proper stop time information based on the last |
|---|
| 24 | moment the media stream passed through the media proxy. This functionality |
|---|
| 25 | is not available when the end-points have negotiated using ICE another |
|---|
| 26 | candidate than MediaProxy. |
|---|
| 27 | |
|---|
| 28 | The rates are linked with profiles corresponding with different time of the |
|---|
| 29 | day, day of the week or holidays. For rating calls, which span multiple |
|---|
| 30 | profiles, the right rate is selected and applied for the call duration |
|---|
| 31 | within each profile. Each customer may be assigned its own dedicated rating |
|---|
| 32 | plans destination id and names. Chained profiles are possible to enable |
|---|
| 33 | exception based rating. Multiple customers may share a common rate list, |
|---|
| 34 | while some destinations may be rated differently, only the differences must |
|---|
| 35 | be provisioned. Multiple time zones are supported for multiple billing |
|---|
| 36 | parties hosted on the same platform. |
|---|
| 37 | |
|---|
| 38 | |
|---|
| 39 | Rating logic |
|---|
| 40 | ------------ |
|---|
| 41 | |
|---|
| 42 | Different customers can have different rating plans. A rating plan is a |
|---|
| 43 | unique combination of holidays, day of week, time of day, destination ids, |
|---|
| 44 | and associated costs. |
|---|
| 45 | |
|---|
| 46 | The following steps are performed to rate a CDR: |
|---|
| 47 | |
|---|
| 48 | 1. Determination of the billing party |
|---|
| 49 | 2. Determination of the destination id |
|---|
| 50 | 3. Determination of the costs |
|---|
| 51 | |
|---|
| 52 | The steps are described in detail below. |
|---|
| 53 | |
|---|
| 54 | |
|---|
| 55 | 1. Determination of the billing party |
|---|
| 56 | ------------------------------------- |
|---|
| 57 | |
|---|
| 58 | |
|---|
| 59 | To be able to calculate the Price for a call the rating engine must |
|---|
| 60 | determine whose rating plan to use. |
|---|
| 61 | |
|---|
| 62 | The rating engine does this by performing a match against entries in the |
|---|
| 63 | billing_customers table for the the BillingPartyId field of the the CDR |
|---|
| 64 | (radacct.UserName for radius based datasources) in the following order: |
|---|
| 65 | |
|---|
| 66 | a. SIP account user@domain |
|---|
| 67 | b. SIP domain of the SIP account |
|---|
| 68 | c. Source IP of the session |
|---|
| 69 | d. Default (when none of the above matches) |
|---|
| 70 | |
|---|
| 71 | The first match is considered to be the billing party for which the rating |
|---|
| 72 | plan is determined. |
|---|
| 73 | |
|---|
| 74 | The rating plan is further derived from the profiles associated with the |
|---|
| 75 | entry found in the billing_customers. |
|---|
| 76 | |
|---|
| 77 | Note |
|---|
| 78 | |
|---|
| 79 | The billing_customers table field that matches the Source IP is called |
|---|
| 80 | gateway. "gateway" or "trusted peer" terms are used interchangeably in this |
|---|
| 81 | document. They both relate to the source IP address that generated the SIP |
|---|
| 82 | session. |
|---|
| 83 | |
|---|
| 84 | If you want to use the multi-tenant features for OpenSIPS accounting you |
|---|
| 85 | must create an integer reseller_id column in the trusted and domain tables. |
|---|
| 86 | Traffic generated by IP addresses from the trusted peers table and local |
|---|
| 87 | domains will be marked as belonging to their correspondent reseller_id. The |
|---|
| 88 | reseller_id is then later used to lookup destinations and rates belonging to |
|---|
| 89 | the reseller_id. |
|---|
| 90 | |
|---|
| 91 | |
|---|
| 92 | 2. Determination of the destination id |
|---|
| 93 | -------------------------------------- |
|---|
| 94 | |
|---|
| 95 | The rating engine identifies the 'destination id', which has associated |
|---|
| 96 | rates depending on day of week and time of day. |
|---|
| 97 | |
|---|
| 98 | The 'destination id' is for example a country prefix like '31' for the |
|---|
| 99 | Netherlands. This 'destination id' has prices associated with it so all |
|---|
| 100 | calls to the Netherlands will have prices associated with prefix '31'. |
|---|
| 101 | |
|---|
| 102 | The 'destination id' is derived from the logical destination the SIP session |
|---|
| 103 | has been routed to. In SIP headers and Radius records there are multiple |
|---|
| 104 | places that contain information related to the destination. Some of them are |
|---|
| 105 | generated by the SIP User-Agents (hence cannot be trusted and must not be |
|---|
| 106 | used for accounting purposes) and others are generated by the SIP Proxy |
|---|
| 107 | configured by the operator and are suitable for accounting purposes. |
|---|
| 108 | |
|---|
| 109 | The rating engine considers the destination to be the first non-empty CDR |
|---|
| 110 | field in this order: |
|---|
| 111 | |
|---|
| 112 | a. CanonicalURI (the destination after all lookups inside the SIP Proxy) |
|---|
| 113 | b. SipTranslatedRequestURI (the Request URI as presented by the SIP UA) |
|---|
| 114 | c. CalledStationId (the content of the To header, used as a last resort) |
|---|
| 115 | |
|---|
| 116 | The CanonicalURI is the preferred because is reliable information generated |
|---|
| 117 | by the operator based on the logic configured in the SIP Proxy and the |
|---|
| 118 | subscriber cannot control it. OpenSIPS must be configured to send the |
|---|
| 119 | CanonicalURI Radius attribute when creating the radius accounting START |
|---|
| 120 | record. Instructions for this are available in INSTALL.txt file. |
|---|
| 121 | |
|---|
| 122 | The 'destination id' is then calculated based on the longest match of this |
|---|
| 123 | destination field in the billing_destinations table. |
|---|
| 124 | |
|---|
| 125 | The longest match for the chosen destination field is performed by the |
|---|
| 126 | E164_class, which by default uses E164_Europe that defines an European |
|---|
| 127 | numbering plan. It assumes the destinations start with a zero for a national |
|---|
| 128 | call and with double zero for an international call. See cdr_generic.php for |
|---|
| 129 | the actual logic. |
|---|
| 130 | |
|---|
| 131 | If your dialing plan is different, you must use other provided class like |
|---|
| 132 | E164_US or create a custom class and point to it in global.inc for each |
|---|
| 133 | datasource as follows: |
|---|
| 134 | |
|---|
| 135 | 'E164_class'=>'MyE164Class', |
|---|
| 136 | |
|---|
| 137 | For example the pre-defined E164_US class from cdr_generic.php matches the |
|---|
| 138 | American dialing plan. |
|---|
| 139 | |
|---|
| 140 | Destinations are uploaded into destination table. Each reseller_id can have |
|---|
| 141 | its own list of destinations. If the reseller_id of trusted peers and domain |
|---|
| 142 | tables have been set, then the rating engine will apply the rating |
|---|
| 143 | information belonging to them. |
|---|
| 144 | |
|---|
| 145 | Each destination has also a set of properties that can be used to alter the |
|---|
| 146 | calculation of the price. These properties are: |
|---|
| 147 | |
|---|
| 148 | - increment: the call duration is rounded to the next increment in seconds, |
|---|
| 149 | this is only used for rating, the actual CDR duration is not modified |
|---|
| 150 | - min_duration: set the duration to min_duration if the CDR duration is |
|---|
| 151 | smaller than min_duration, this is only used for rating, the actual CDR |
|---|
| 152 | duration is not modified |
|---|
| 153 | - max_duration: limit the duration to max_duration if CDR duration is |
|---|
| 154 | bigger than max_duration, this is only used for rating, the actual CDR |
|---|
| 155 | duration is not modified |
|---|
| 156 | - max_price: the price is set to max_price per call if the calculated price |
|---|
| 157 | is bigger than the max_price |
|---|
| 158 | |
|---|
| 159 | |
|---|
| 160 | 3. Determination of the costs |
|---|
| 161 | ----------------------------- |
|---|
| 162 | |
|---|
| 163 | The following steps are taken to determine the cost for the calls based on |
|---|
| 164 | the 'destination id' and the billing party determined at the previous steps. |
|---|
| 165 | |
|---|
| 166 | 1. Lookup the billing profiles in cdrtool.billing_customers table in the |
|---|
| 167 | following order: subscriber,domain,gateway (based on $this->dayofweek): |
|---|
| 168 | (as explained in "Determination of the billing party" above) |
|---|
| 169 | |
|---|
| 170 | - profile_name1 matches week days [1-5] |
|---|
| 171 | - profile_name1_alt matches week days [1-5] if no rates for profile_name1 |
|---|
| 172 | are found |
|---|
| 173 | - profile_name2 matches week-ends [6-0] |
|---|
| 174 | - profile_name2_alt matches week-ends [6-0] if no rates for profile_name2 |
|---|
| 175 | are found |
|---|
| 176 | - profile_name2 matches also holidays from billing_holidays table |
|---|
| 177 | |
|---|
| 178 | The week starts with 0 (Sunday) and ends with 6 (Saturday) |
|---|
| 179 | |
|---|
| 180 | This step determines which rates should be applied based on the day of |
|---|
| 181 | the week when the call started. |
|---|
| 182 | |
|---|
| 183 | 2. Using the profile_name found, lookup the rate_name based |
|---|
| 184 | on $this->hourofday in cdrtool.billing_profiles table |
|---|
| 185 | |
|---|
| 186 | If no rate_name is found for the given profiles a second set of profiles |
|---|
| 187 | are used, profile_name1_alt and profile_name2_alt. |
|---|
| 188 | |
|---|
| 189 | - the day may be split in maximum 4 periods |
|---|
| 190 | - the days starts with hour 0 and ends with hour 24 |
|---|
| 191 | - rate_name1 defines the first interval after hour 0 |
|---|
| 192 | - rate_name2 defines the first interval after rate_name1 |
|---|
| 193 | - rate_name3 defines the first interval after rate_name2 |
|---|
| 194 | - rate_name4 defines the first interval after rate_name3 |
|---|
| 195 | |
|---|
| 196 | When the hour matches an interval use the rate_nameX found to lookup the |
|---|
| 197 | rate in billing_rates, if no record is found use the rate called |
|---|
| 198 | 'default' |
|---|
| 199 | |
|---|
| 200 | This step determines which rate should be applied for the time of day |
|---|
| 201 | when the call started. |
|---|
| 202 | |
|---|
| 203 | 3. Lookup in the cdrtool.billing_rates table the record having same name |
|---|
| 204 | found at point 2 having billing_rates.destination = 'destination id' |
|---|
| 205 | and billing_rates.application = application type found in the steps above. |
|---|
| 206 | |
|---|
| 207 | - return an array with all the rating values and the duration rated |
|---|
| 208 | |
|---|
| 209 | No rate will be returned if no 'destination id' is found. Make sure each |
|---|
| 210 | possible destination has a 'corresponding id' and name in the destinations |
|---|
| 211 | table. |
|---|
| 212 | |
|---|
| 213 | This step determines the costs within the current time span associated |
|---|
| 214 | with the time of day and destination id. If the call duration exceeds |
|---|
| 215 | this time span (that is a new interval for which another rate applies is |
|---|
| 216 | reached), step 4 is performed. |
|---|
| 217 | |
|---|
| 218 | 4. If the duration rated at point 3 is less than total call duration, apply |
|---|
| 219 | point 3 again for the remaining call duration in the next profile. A |
|---|
| 220 | maximum of 10 spans (different rates depending of time of day, day of the |
|---|
| 221 | week) can be calculated using this mechanism. After 10 spans, the engine |
|---|
| 222 | bails out to avoid loops caused by invalid tables provisioning. |
|---|
| 223 | |
|---|
| 224 | 5. Calculate the total call Price based on its duration and connection fees. |
|---|
| 225 | |
|---|
| 226 | In global.inc there are several variables that affect how the price is |
|---|
| 227 | calculated. These settings are global per CDRTool installation but some |
|---|
| 228 | can be overwritten with per customer values in the billing_customers |
|---|
| 229 | table. |
|---|
| 230 | |
|---|
| 231 | $RatingEngine=array( |
|---|
| 232 | "priceDenominator" => 10000, // Rates units (global setting) |
|---|
| 233 | "priceDecimalDigits" => 4, // Decimal information (global setting) |
|---|
| 234 | "minimumDurationCharged" => 0, // Rate a minimum of X seconds (per customer) |
|---|
| 235 | "minimumDuration" => 0, // Minimum duration to rate, if call duration is shorter the price is zero (per customer) |
|---|
| 236 | "durationPeriodRated" => 60 // Rate is per 60 seconds (global setting) |
|---|
| 237 | "trafficSizeRated" => 1024, // Default we rate per 1 MB (global setting) |
|---|
| 238 | "reportMissingRates" => 0 // Send emails to administrator in case of missing rates |
|---|
| 239 | ); |
|---|
| 240 | |
|---|
| 241 | Pricing formula |
|---|
| 242 | --------------- |
|---|
| 243 | |
|---|
| 244 | if min_duration then |
|---|
| 245 | minimumDurationCharged = min_duration |
|---|
| 246 | else if minimumDurationCharged set in global inc |
|---|
| 247 | use minimumDurationCharged from global.inc |
|---|
| 248 | else |
|---|
| 249 | minimumDurationCharged = call duration |
|---|
| 250 | |
|---|
| 251 | if increment then |
|---|
| 252 | durationForRating = round to the next increment |
|---|
| 253 | else |
|---|
| 254 | durationForRating = call duration |
|---|
| 255 | |
|---|
| 256 | if durationForRating >= minimumDurationCharged then |
|---|
| 257 | Price = connectCost/priceDenominator+ |
|---|
| 258 | durationRate*durationForRating/durationPeriodRated/priceDenominator |
|---|
| 259 | else |
|---|
| 260 | Price = 0 |
|---|
| 261 | |
|---|
| 262 | |
|---|
| 263 | ENUM discounts |
|---|
| 264 | -------------- |
|---|
| 265 | |
|---|
| 266 | The rating engine can apply a discount associated with the ENUM top |
|---|
| 267 | level domain that returned the final destination. |
|---|
| 268 | |
|---|
| 269 | Price = Price - Price * ENUM discount / 100 |
|---|
| 270 | |
|---|
| 271 | To apply ENUM based discounts, the ENUM TLD must be saved with each CDR |
|---|
| 272 | and the TLDs with their corespondent discounts must be provisioned in the |
|---|
| 273 | Rating tables section. See ENUM TLD discounts section for more |
|---|
| 274 | information. |
|---|
| 275 | |
|---|
| 276 | |
|---|
| 277 | Purchasing price |
|---|
| 278 | ---------------- |
|---|
| 279 | |
|---|
| 280 | A second price called 'Price in' is calculated using the same formula but |
|---|
| 281 | based on connectCostIn and durationRateIn values. It can be used to match |
|---|
| 282 | the purchasing price and calculate the margin between purchasing and |
|---|
| 283 | selling prices. The information about both prices is stored in the |
|---|
| 284 | RateInfo field of the CDR. The values for connectCostIn and |
|---|
| 285 | durationRateIn must be provisioned in the billing_rates and |
|---|
| 286 | billing_rates_history tables using the web interface or by importing csv |
|---|
| 287 | files. |
|---|
| 288 | |
|---|
| 289 | |
|---|
| 290 | 7. Save the calculated Price, billing party and 'destination id' for each |
|---|
| 291 | call in the CDR table. Having the price stored in the database, it is |
|---|
| 292 | possible to build statistics to display consolidated revenues per country |
|---|
| 293 | code, network or subscriber. |
|---|
| 294 | |
|---|
| 295 | |
|---|
| 296 | Testing the rating engine |
|---|
| 297 | ------------------------- |
|---|
| 298 | |
|---|
| 299 | You can test the rating engine by telneting to the IP and port configured in |
|---|
| 300 | global.inc. Type 'help' once connected to see the available commands. Use |
|---|
| 301 | 'ShowPrice' command to simulate the rating of one session, for example: |
|---|
| 302 | |
|---|
| 303 | adigeo@w1:/var/www/CDRTool/doc$ telnet ws1 9024 |
|---|
| 304 | Trying 10.0.0.1 ... |
|---|
| 305 | Connected to 10.0.0.1. |
|---|
| 306 | Escape character is '^]'. |
|---|
| 307 | |
|---|
| 308 | ShowPrice From=sip:123@example.com To=sip:0031650222333@example.com Gateway=10.0.0.1 Duration=59 |
|---|
| 309 | 0.2023 |
|---|
| 310 | Duration: 59 s |
|---|
| 311 | App: audio |
|---|
| 312 | Destination: 31650 |
|---|
| 313 | Customer: domain=example.com |
|---|
| 314 | Connect: 0.0450 |
|---|
| 315 | StartTime: 2009-01-03 14:29:10 |
|---|
| 316 | -- |
|---|
| 317 | Span: 1 |
|---|
| 318 | Duration: 59 s |
|---|
| 319 | ProfileId: 442 / weekend |
|---|
| 320 | RateId: 442 / 0-24h |
|---|
| 321 | Rate: 0.1600 / 60 s |
|---|
| 322 | Price: 0.1573 |
|---|
| 323 | |
|---|
| 324 | |
|---|
| 325 | Below is a description of the fields that must be separated by one or more |
|---|
| 326 | spaces: |
|---|
| 327 | |
|---|
| 328 | * From - must contain the caller party |
|---|
| 329 | * Gateway - must contain the source IP of the session |
|---|
| 330 | * To - must contain the full CanonicalURI destination, its format must be synced |
|---|
| 331 | with the E164 class logic used to determine the 'destination id' |
|---|
| 332 | * Duration - the duration of the session in seconds |
|---|
| 333 | |
|---|
| 334 | Check the syslog for any errors, most the of the configuration errors like |
|---|
| 335 | missing rates are logged to the syslog. |
|---|
| 336 | |
|---|
| 337 | |
|---|
| 338 | Importing and exporting of rating files |
|---|
| 339 | --------------------------------------- |
|---|
| 340 | |
|---|
| 341 | It is important to set the impersonate field corectly for the login |
|---|
| 342 | accounts. To access in the CDRTool Rating web page all the rates table for |
|---|
| 343 | all resellers in the system you must set the impersonate field of the login |
|---|
| 344 | account to 0.0 |
|---|
| 345 | |
|---|
| 346 | There are different data files needed for rating. The data files are |
|---|
| 347 | imported into their corresponding MySQL tables. |
|---|
| 348 | |
|---|
| 349 | The files must be uploaded to /var/spool/cdrtool directory. To load the |
|---|
| 350 | files into the database run the following command: |
|---|
| 351 | |
|---|
| 352 | /var/www/CDRTool/scripts/importRatingTables.php |
|---|
| 353 | |
|---|
| 354 | Data partitioning for multiple resellers |
|---|
| 355 | |
|---|
| 356 | The reseller_id column present in all rating tables is used to filter access |
|---|
| 357 | based on Login account impersonate field. |
|---|
| 358 | |
|---|
| 359 | You may create numerical sub-directories under /var/spool/cdrtool directory. |
|---|
| 360 | When importing a file from such numerical directory, the reseller_id field |
|---|
| 361 | in all imported records is set to the directory name. |
|---|
| 362 | |
|---|
| 363 | The import script knows to import the files only once so you may dump |
|---|
| 364 | several files over time with the same name and safely run the import script |
|---|
| 365 | from cron. The import script detects whether each file have been imported by |
|---|
| 366 | building a unique key out of the filename and the hash of the file content. |
|---|
| 367 | So you may use the same filenames as long as the content differs and |
|---|
| 368 | viceversa. If the import file has changed any records, the rating engine is |
|---|
| 369 | automatically instructed to reload the changes. |
|---|
| 370 | |
|---|
| 371 | Sample csv files are found in the setup directory. The CSV field order is |
|---|
| 372 | described in setup/*.csv sample files. The first element on each line |
|---|
| 373 | specifies the operation will be performed with the current record. The |
|---|
| 374 | operation can be 2 (update/insert), 1 (insert) or 3 (delete). |
|---|
| 375 | |
|---|
| 376 | The updates are performed based on a unique key present in each table: |
|---|
| 377 | |
|---|
| 378 | billing_customers - cust_idx (reseller,gateway,domain,subscriber) |
|---|
| 379 | destinations - cust_dest_idx (reseller,gateway,domain,subscriber,dest_id) |
|---|
| 380 | billing_profiles - profile_idx (reseller,name) |
|---|
| 381 | billing_rates - rate_idx (reseller,name,destination,application) |
|---|
| 382 | billing_rates_history - rate_idx (reseller,name,destination,application,startDate,endDate) |
|---|
| 383 | |
|---|
| 384 | The content of the rating tables can be exported in the Rating tables page. |
|---|
| 385 | |
|---|
| 386 | The import script detects the type of file to import based on its filename. |
|---|
| 387 | |
|---|
| 388 | The filename must comply with the following naming convention: |
|---|
| 389 | |
|---|
| 390 | 1. Must start with the name of the table without the billing_ |
|---|
| 391 | 2. May optionally contain extra characters after the name |
|---|
| 392 | 3. Must end with .csv extension |
|---|
| 393 | |
|---|
| 394 | Examples: |
|---|
| 395 | |
|---|
| 396 | - rates.csv or rates20061201.cvs will be loaded into the rates table |
|---|
| 397 | - profiles.csv or profiles20061201.cvs will be loaded into the profiles table |
|---|
| 398 | - destinations200601.csv will be loaded in the destinations table |
|---|
| 399 | - ratesHistory200801.csv will be loaded in the rates_history table |
|---|
| 400 | |
|---|
| 401 | Do not use 'billing_' prefix in front of the file name. |
|---|
| 402 | |
|---|
| 403 | It is advisable to name the files in a consistent manner like tableYYYYMMDD.csv |
|---|
| 404 | |
|---|
| 405 | The results of the import operation is logged in the database and can be |
|---|
| 406 | viewed in the Log section of the web interface and the syslog. |
|---|
| 407 | |
|---|
| 408 | |
|---|
| 409 | MySQL schema |
|---|
| 410 | ------------ |
|---|
| 411 | |
|---|
| 412 | To see the rating tables and their structures connect to the cdrtool |
|---|
| 413 | database using mysql client. |
|---|
| 414 | |
|---|
| 415 | Run 'show tables' and 'describe table_name': |
|---|
| 416 | |
|---|
| 417 | billing_customers |
|---|
| 418 | +-------------------+ |
|---|
| 419 | | Field | |
|---|
| 420 | +-------------------+ |
|---|
| 421 | | id | |
|---|
| 422 | | reseller_id | |
|---|
| 423 | | gateway | |
|---|
| 424 | | domain | |
|---|
| 425 | | subscriber | |
|---|
| 426 | | profile_name1 | |
|---|
| 427 | | profile_name1_alt | |
|---|
| 428 | | profile_name2 | |
|---|
| 429 | | profile_name2_alt | |
|---|
| 430 | | timezone | |
|---|
| 431 | +-------------------+ |
|---|
| 432 | |
|---|
| 433 | billing_profiles |
|---|
| 434 | +------------+ |
|---|
| 435 | | Field | |
|---|
| 436 | +------------+ |
|---|
| 437 | | id | |
|---|
| 438 | | reseller_id| |
|---|
| 439 | | name | |
|---|
| 440 | | rate_name1 | |
|---|
| 441 | | hour1 | |
|---|
| 442 | | rate_name2 | |
|---|
| 443 | | hour2 | |
|---|
| 444 | | rate_name3 | |
|---|
| 445 | | hour3 | |
|---|
| 446 | | rate_name4 | |
|---|
| 447 | | hour4 | |
|---|
| 448 | +------------+ |
|---|
| 449 | |
|---|
| 450 | billing_rates |
|---|
| 451 | +-----------------+ |
|---|
| 452 | | Field | |
|---|
| 453 | +-----------------+ |
|---|
| 454 | | id | |
|---|
| 455 | | reseller_id | |
|---|
| 456 | | name | |
|---|
| 457 | | destination | |
|---|
| 458 | | application | |
|---|
| 459 | | connectCost | |
|---|
| 460 | | durationRate | |
|---|
| 461 | | connectCostIn | |
|---|
| 462 | | durationRateIn | |
|---|
| 463 | +-----------------+ |
|---|
| 464 | |
|---|
| 465 | billing_rates_history |
|---|
| 466 | +-----------------+ |
|---|
| 467 | | Field | |
|---|
| 468 | +-----------------+ |
|---|
| 469 | | id | |
|---|
| 470 | | reseller_id | |
|---|
| 471 | | name | |
|---|
| 472 | | destination | |
|---|
| 473 | | application | |
|---|
| 474 | | connectCost | |
|---|
| 475 | | durationRate | |
|---|
| 476 | | connectCostIn | |
|---|
| 477 | | durationRateIn | |
|---|
| 478 | | startDate | |
|---|
| 479 | | endDate | |
|---|
| 480 | +-----------------+ |
|---|
| 481 | |
|---|
| 482 | destinations |
|---|
| 483 | +--------------+ |
|---|
| 484 | | Field | |
|---|
| 485 | +--------------+ |
|---|
| 486 | | id | |
|---|
| 487 | | reseller_id | |
|---|
| 488 | | gateway | |
|---|
| 489 | | domain | |
|---|
| 490 | | subscriber | |
|---|
| 491 | | dest_id | |
|---|
| 492 | | dest_name | |
|---|
| 493 | | increment | |
|---|
| 494 | | min_duration | |
|---|
| 495 | | max_duration | |
|---|
| 496 | | max_price | |
|---|
| 497 | +--------------+ |
|---|
| 498 | |
|---|
| 499 | billing_holidays |
|---|
| 500 | +-------+ |
|---|
| 501 | | Field | |
|---|
| 502 | +-------+ |
|---|
| 503 | | day | |
|---|
| 504 | +-------+ |
|---|
| 505 | |
|---|
| 506 | prepaid |
|---|
| 507 | +------------------+ |
|---|
| 508 | | Field | |
|---|
| 509 | +------------------+ |
|---|
| 510 | | id | |
|---|
| 511 | | reseller_id | |
|---|
| 512 | | account | |
|---|
| 513 | | domain | |
|---|
| 514 | | balance | |
|---|
| 515 | | change_date | |
|---|
| 516 | | active_sessions | |
|---|
| 517 | | session_counter | |
|---|
| 518 | +------------------+ |
|---|
| 519 | |
|---|
| 520 | prepaid_history |
|---|
| 521 | +-------------+ |
|---|
| 522 | | Field | |
|---|
| 523 | +-------------+ |
|---|
| 524 | | id | |
|---|
| 525 | | reseller_id | |
|---|
| 526 | | username | |
|---|
| 527 | | domain | |
|---|
| 528 | | action | |
|---|
| 529 | | number | |
|---|
| 530 | | value | |
|---|
| 531 | | balance | |
|---|
| 532 | | date | |
|---|
| 533 | +-------------+ |
|---|
| 534 | |
|---|
| 535 | billing_enum_tlds |
|---|
| 536 | +-------------+ |
|---|
| 537 | | Field | |
|---|
| 538 | +-------------+ |
|---|
| 539 | | id | |
|---|
| 540 | | reseller_id | |
|---|
| 541 | | gateway | |
|---|
| 542 | | domain | |
|---|
| 543 | | subscriber | |
|---|
| 544 | | enum_tld | |
|---|
| 545 | | e164_regexp | |
|---|
| 546 | | discount | |
|---|
| 547 | +-------------+ |
|---|
| 548 | |
|---|
| 549 | |
|---|
| 550 | Web based rating tables management |
|---|
| 551 | ---------------------------------- |
|---|
| 552 | |
|---|
| 553 | The rating tables can be edited from the web, click on Rating tables link. |
|---|
| 554 | One may insert/update/delete records or apply changes on selections. For |
|---|
| 555 | example it is possible to increase with XX units the rate for a specific |
|---|
| 556 | destination. |
|---|
| 557 | |
|---|
| 558 | Numeric fields support mathematical operators [+-*/], one may update |
|---|
| 559 | using absolute or relative values the fields in the rating tables. |
|---|
| 560 | |
|---|
| 561 | The rates may be copied in bulk and start quickly working with a fresh |
|---|
| 562 | new rating table. Select in the Rates PSTN table by filtering on rate |
|---|
| 563 | name. A new button appears which allows the copy of all selected rates |
|---|
| 564 | into a new set. The rates are copied under the old rate id with _N |
|---|
| 565 | suffix where N is the next available number for which same rate id does |
|---|
| 566 | not exist. |
|---|
| 567 | |
|---|
| 568 | The content of the rating tables can be exported into comma separated |
|---|
| 569 | files. The CSV format has the same structure as the import file, is |
|---|
| 570 | fairly easy to modify an exported batch file into an external |
|---|
| 571 | application and load it back into CDRTool. |
|---|
| 572 | |
|---|
| 573 | Note |
|---|
| 574 | |
|---|
| 575 | When $RatingEngine['split_rating_table'] is true, after changing the rates |
|---|
| 576 | in the web interface or by importing them, you must run the script |
|---|
| 577 | scripts/splitRatingTables.php to split the central billing_rates table into |
|---|
| 578 | individual tables for each rate id. You do not need this feature if you have |
|---|
| 579 | less than 100K rates in your system. |
|---|
| 580 | |
|---|
| 581 | |
|---|
| 582 | ENUM TLD discounts |
|---|
| 583 | ------------------ |
|---|
| 584 | |
|---|
| 585 | To apply discounts based on ENUM certain conditions must be met. |
|---|
| 586 | |
|---|
| 587 | 1. The username part of the result of the ENUM lookup must be numeric and |
|---|
| 588 | contain a fully qualified E164 number, optional with a numeric prefix. |
|---|
| 589 | |
|---|
| 590 | Example: |
|---|
| 591 | |
|---|
| 592 | The user dialed 020800001, the SIP Proxy has normalized the destination |
|---|
| 593 | based on local policy by stripping 0 and adding country code 31 to obtain |
|---|
| 594 | the fully qualified E164 number 3120800001, than it performed an ENUM |
|---|
| 595 | lookup under top level domain e164.example.com for +3120800001. The ENUM |
|---|
| 596 | server responsable for e164.example.com returned a response with the |
|---|
| 597 | destination sip:01131208000011@gateway.example.com |
|---|
| 598 | |
|---|
| 599 | In the CDR, ENUMtld is stored as e164.example.com |
|---|
| 600 | |
|---|
| 601 | The rating logic checks if the TLD exists in the billing_enum_tlds table. |
|---|
| 602 | If it does, the rating engine tries to match the regexp field against the |
|---|
| 603 | username part of the destination from the ENUM response, which has been |
|---|
| 604 | saved in the Canonical URI. The match must return a fully qualified E164 |
|---|
| 605 | number otherwise the call is considered to have ended to a no E164 |
|---|
| 606 | destination and the call will be free of charge. |
|---|
| 607 | |
|---|
| 608 | 2. In the ENUM tld table you must provision (for the example above): |
|---|
| 609 | |
|---|
| 610 | - TLD: e164.example.com |
|---|
| 611 | - Regexp: 011([1-9][0-9]{7,}) |
|---|
| 612 | - Discount: 25 |
|---|
| 613 | |
|---|
| 614 | The parenthesis of the Regexp field indicate the E164 number returned by |
|---|
| 615 | the match and discount is a percentage that will be subtracted form the |
|---|
| 616 | total price of the call. The formula is described in the PSTN rating |
|---|
| 617 | section. |
|---|
| 618 | |
|---|
| 619 | |
|---|
| 620 | Reloading rating tables |
|---|
| 621 | ----------------------- |
|---|
| 622 | |
|---|
| 623 | The rating engine loads some of the rating tables in the memory, when the |
|---|
| 624 | tables change a reload is needed. Reload of rating tables is possible |
|---|
| 625 | without stopping the daemon by connecting to it and issuing the reload |
|---|
| 626 | command. The init.d script can also be used for reloading the rating engine |
|---|
| 627 | with the current values from the rating database. |
|---|
| 628 | |
|---|
| 629 | There are 3 ways of reloading the rating tables: |
|---|
| 630 | |
|---|
| 631 | a. Each change executed in the WEB interface for rate management may update |
|---|
| 632 | the rating tables. If there is a change made to the database that requires a |
|---|
| 633 | reload the link 'Reload rating tables' appears in red color on web page. |
|---|
| 634 | Click on the link to execute the reload. |
|---|
| 635 | |
|---|
| 636 | b. Telnet to the IP address and port number specified for the Rating engine |
|---|
| 637 | in global.inc. Type help to see the list of commands available. Locate the |
|---|
| 638 | reload rates command and execute it followed by \n. You may see the result |
|---|
| 639 | of the command in syslog. The results displayed by syslog will show how many |
|---|
| 640 | entries have been reloaded from the rating table. |
|---|
| 641 | |
|---|
| 642 | c. Run /etc/init.d/cdrtool reload command |
|---|
| 643 | |
|---|
| 644 | |
|---|
| 645 | Troubleshooting |
|---|
| 646 | --------------- |
|---|
| 647 | |
|---|
| 648 | To examine the rate information for a rated call click on the Id field on |
|---|
| 649 | the leftmost column. (Java script support in browser is required). A blue |
|---|
| 650 | area will open under the CDR line containing more information about the SIP |
|---|
| 651 | session. |
|---|
| 652 | |
|---|
| 653 | If you see no price in the CDR or no rating information appears in the call |
|---|
| 654 | details it means that either no destination was found in the destinations |
|---|
| 655 | table or no rate has been associated with that destination. Make sure that |
|---|
| 656 | for each entry in the destinations table there is a corespondent entry in |
|---|
| 657 | the rates table. CDRTool rating engine can send warning emails if it finds |
|---|
| 658 | missing entries in the rating tables if the system where CDRTool runs is |
|---|
| 659 | properly configured to send emails and the e-mail notification addresses are |
|---|
| 660 | set in global.inc: |
|---|
| 661 | |
|---|
| 662 | $CDRTool['provider']['toEmail'] = "support@example.com"; |
|---|
| 663 | $CDRTool['provider']['bccEmail'] = "cdrtool@example.com"; |
|---|
| 664 | |
|---|
| 665 | To log to syslog about missing rates or incorrect setup of the rating tables |
|---|
| 666 | enable 'reportMissingRates' in $CDRTool['rating'] section of global.inc |
|---|
| 667 | |
|---|
| 668 | |
|---|
| 669 | Renormalizing CDRs and historical rating |
|---|
| 670 | ---------------------------------------- |
|---|
| 671 | |
|---|
| 672 | Sometime is useful to be able to change the rates for calls that have been |
|---|
| 673 | already normalized and rated, for example after changing the rating tables |
|---|
| 674 | you wish to apply the changes for the previous month for a customer. |
|---|
| 675 | |
|---|
| 676 | To re-rate the CDRs do the following: |
|---|
| 677 | |
|---|
| 678 | 1. Change the current rates by using cvs files/WEB interface or add rates |
|---|
| 679 | valid for specific dates/destinations in the rates_history table |
|---|
| 680 | |
|---|
| 681 | 2. Re-normalize the calls to be re-rated by either selecting ReNormalize |
|---|
| 682 | check-box in the search screen or by changing the Normalized field in the |
|---|
| 683 | CDR MySQL table (e.g. radacct): |
|---|
| 684 | |
|---|
| 685 | Examples: |
|---|
| 686 | |
|---|
| 687 | a) Re-rate calls for this month (2004-12) SIP domain example.com: |
|---|
| 688 | UPDATE radacct set Normalized = '0' where Realm = 'example.com' |
|---|
| 689 | and AcctStartTime >= '2004-12-01' |
|---|
| 690 | |
|---|
| 691 | b) Re-rate calls for SIP subscriber sip01@example.com: |
|---|
| 692 | UPDATE radacct set Normalized = '0' where UserName = 'sip01@example.com' |
|---|
| 693 | |
|---|
| 694 | 3. Apply rating again using command: |
|---|
| 695 | |
|---|
| 696 | /var/www/CDRTool/scripts/normalize.php |
|---|
| 697 | |
|---|
| 698 | Notes |
|---|
| 699 | |
|---|
| 700 | Renormalization process can take long time during which your database |
|---|
| 701 | (radacct table) will be intermitently locked. Perform this operation |
|---|
| 702 | only during low traffic periods. |
|---|
| 703 | |
|---|
| 704 | It is advisable to re-rate only the CDRs for destinations that have |
|---|
| 705 | different rates. To do this, select a filter in the CDR search screen, if |
|---|
| 706 | the selection is right re-run the query by selecting Re-normalize button. |
|---|
| 707 | |
|---|
| 708 | After renormalization, the monthly usage information used by the quota |
|---|
| 709 | system will be out of date. At the next run of the quotaCheck script, a full |
|---|
| 710 | table scan will be performed. See QuotaSystem.txt for more information about |
|---|
| 711 | quota. |
|---|
| 712 | |
|---|
| 713 | Holidays must be added as individual days YYYY-MM-DD in table |
|---|
| 714 | billing_holidays. The profile applied for holidays is the same as for |
|---|
| 715 | week-ends. Holidays are global and cannot be specified per customer. |
|---|
| 716 | |
|---|
| 717 | Renormalization process does not affect the balance of prepaid users. |
|---|
| 718 | Prepaid is a real time un-reversible process, it goes in one direction. The |
|---|
| 719 | prepaid balance is changed only by placing a call or adding credit to it. |
|---|
| 720 | There are several reasons for this: |
|---|
| 721 | |
|---|
| 722 | - The balance before and after each CDR is not known to be able to roll it |
|---|
| 723 | back at a later time |
|---|
| 724 | - Re-rating correctly is mathematically not possible for prepaid users that |
|---|
| 725 | have calls in progress |
|---|
| 726 | - If the prices are higher than previously debited and end up with a |
|---|
| 727 | negative balance, the software cannot force the user to pay more |
|---|
| 728 | retroactively |
|---|
| 729 | |
|---|
| 730 | Re-normalization for the purpose of re-rating is useful only for postpaid |
|---|
| 731 | accounts where you send an invoice at the end of the month and your can |
|---|
| 732 | change things back and forth. If you need to perform manual credit/debit |
|---|
| 733 | operations to some prepaid users because of faulty pricing, you can edit in |
|---|
| 734 | CDRTool in the prepaid table the balance by using + or -. |
|---|
| 735 | |
|---|
| 736 | |
|---|
| 737 | Known limitations |
|---|
| 738 | ----------------- |
|---|
| 739 | |
|---|
| 740 | The rating engine does not calculate prices based on the outbound carriers |
|---|
| 741 | or outbound gateways, the rating plan is is assigned by the calling party |
|---|
| 742 | and not by called party. |
|---|
| 743 | |
|---|
| 744 | Price discounts (except those based on ENUM tld) must be applied outside |
|---|
| 745 | CDRTool, in the billing system that prints the actual invoices. CDRTool has |
|---|
| 746 | no possibility to rate only calls after X minutes per month for subscriber |
|---|
| 747 | Y, all calls are rated uniformly. |
|---|
| 748 | |
|---|
| 749 | |
|---|
| 750 | Performance |
|---|
| 751 | ----------- |
|---|
| 752 | |
|---|
| 753 | Rating is part of the normalization process that happens every time a query |
|---|
| 754 | is executed in the web interface or when the rating engine is contacted by |
|---|
| 755 | the SIP Proxy or by the User Agent that performs the prepaid application. |
|---|
| 756 | |
|---|
| 757 | The following tests have been performed between two machines with 3 GHz CPU |
|---|
| 758 | and 1 GB memory located on the same LAN having a round trip time of 0.2 ms. |
|---|
| 759 | |
|---|
| 760 | The rating tables have been populated durring the tests with: |
|---|
| 761 | |
|---|
| 762 | Aug 11 11:25:43 sip03 CDRTool[4945]: Loaded 8135 destinations |
|---|
| 763 | Aug 11 11:25:43 sip03 CDRTool[4945]: Loaded 6 profilesPSTN |
|---|
| 764 | Aug 11 11:25:43 sip03 CDRTool[4945]: Loaded 4 holidays |
|---|
| 765 | Aug 11 11:25:44 sip03 CDRTool[4945]: Loaded 7273 prepaid accounts |
|---|
| 766 | |
|---|
| 767 | Tests results for the postpaid application: |
|---|
| 768 | |
|---|
| 769 | Clients Rating command Execution speed |
|---|
| 770 | ---------------------------------------------------------------- |
|---|
| 771 | 1 ShowPrice 390/s per client |
|---|
| 772 | 5 ShowPrice 100/s per client |
|---|
| 773 | 10 ShowPrice 60/s per client |
|---|
| 774 | |
|---|
| 775 | |
|---|
| 776 | Tests results for the prepaid application |
|---|
| 777 | |
|---|
| 778 | Clients Rating command Execution speed |
|---|
| 779 | ---------------------------------------------------------------- |
|---|
| 780 | 1 MaxSessionTime/DebitBalance 250/s per client |
|---|
| 781 | 5 MaxSessionTime/DebitBalance 80/s per client |
|---|
| 782 | 10 MaxSessionTime/DebitBalance 40/s per client |
|---|
| 783 | |
|---|
| 784 | Client means either a SIP Proxy entity or a CDRTool server, which performs |
|---|
| 785 | the normalization process. |
|---|
| 786 | |
|---|
| 787 | The rates are read directly from MySQL from version 6.1 instead of |
|---|
| 788 | being cached as they are found based on a known index. |
|---|
| 789 | |
|---|
| 790 | To monitor the connections to the rating engin server telnet to |
|---|
| 791 | the rating engine port and issue the ShowClients command. Example output: |
|---|
| 792 | |
|---|
| 793 | ShowClients |
|---|
| 794 | |
|---|
| 795 | Clients: |
|---|
| 796 | |
|---|
| 797 | 1. 91.20.228.143:32837 |
|---|
| 798 | 2. 85.1.86.71:57945 |
|---|
| 799 | 3. 91.20.228.146:35098 |
|---|
| 800 | 4. 91.20.228.150:34285 |
|---|
| 801 | 5. 91.20.228.129:55090 |
|---|
| 802 | 6. 91.20.228.164:34147 |
|---|
| 803 | |
|---|
| 804 | Requests: |
|---|
| 805 | |
|---|
| 806 | 12 requests from 91.20.228.129 |
|---|
| 807 | 11 requests from 91.20.228.150 |
|---|
| 808 | 8 requests from 85.11.86.71 |
|---|
| 809 | 2 requests from 91.20.228.164 |
|---|
| 810 | |
|---|
| 811 | Statistics: |
|---|
| 812 | |
|---|
| 813 | Total requests: 33 |
|---|
| 814 | Uptime: 169 seconds |
|---|
| 815 | Load: 0.20/s |
|---|
| 816 | |
|---|