entertaining-crib

    8.0.1 • Public • Published

    Overview

    We build a pipeline

    raw-cdr | rating | aggregation | invoicing
    
    • rating translates CDR-by-CDR, applying two rating tables, one for clients, one for carriers;
    • aggregation manages billing periods and applies contract elements (e.g. limits per billing period); only applied to clients;
    • invoicing is out-of-scope.

    For each call we create:

    • a trace CDR, used for troubleshooting;
    • two rated CDRs:
      • one for "client" invoicing;
      • one for "carrier" invoicing.
    • an invoicing CDR.

    Since LCR routing is now donne client-side, CDR generation will also happen client-side.

    Project Plan

    Rating

    Generate rated CDRs from call data. Projet entertaining-crib

    Aggregation

    Projet astonishing-competition

    Mapping a CDR to a rating table

    We add two fields, timezone and rating, in all endpoint records:

    {
      "type": "endpoint"
    
      "timezone": "{timezone}",
      "rating": {
        "{start-date}": {
            "table": "{tarif}"
            "plan": "{forfait}"
        },
        "{start-date}": {
            "table": "{tarif}"
            "plan": "{forfait}"
        }
      },
    
    }
    
    • {timezone}: billing timezone
    • {start-date}: YYYY-MM-DD (sorted alpha-numerically)
    • {tarif}: used in rating
    • {plan}: used in aggregation

    Rating tables

    Naming conventions

    Each rating table is identified by its name. Example conventions might be:

    • {tarif} = {client|carrier}-{start}
    • {client|carrier} = {client} | {carrier}
    • {client} = name of client tariff
    • {carrier} = name of carrier tariff
    • {start} = start of applicability (YYYYMMDD, ISO8601)

    Each rating table is created once and for all, and never modified.

    Each rating table is stored in a CouchDB database called rates-{tarif}.

    Each rating table contains records as defined in the following sections.

    Configuration

    One single record per rating database:

    {
      "_id": "configuration"
    
    , "name": {
        "en-US": "Tariff unlimited-special, starting October 12, 2015
        "fr-FR": "Tarif illimité spécial, au 12 octobre 2015"
      }
    
    , "currency": "EUR"
    , "divider": 1000
    , "per": 60
    
    , "ready": false
    }
    
    • divider: divider used on tariffs. In this example, values are computed in thousandth of Euros.
    • per: duration used for tariffs, defaults to 60 meaning all prices are expressed as "per minute" (even though computations use the time parameters, for example "per second starting with the first second").
    • currency: invoicing currency
    • name: names of the rating table in different locales.
    • ready: if false, the rating table can still be edited, but not used as a tariff; if true, the rating table can no longer be edited, but it may be used as a tariff.

    The configuration record is copied in the rated CDR in the field configuration.

    Prefixes

    There are two ways to provide rating data for a given prefix:

    1. Mapping prefix → destination, to send multiple prefixes into a common destination record (see below):

       {
         "_id": "prefix:336"
       , "type": "prefix"
       , "prefix": "336"
      
       , "destination": "fr-mobile"
       }
      
    2. Storing rating data directly inside the prefix record, for example for individual numbers with dedicated costs:

       {
         "_id": "prefix:3303614"
       , "type": "prefix"
       , "prefix": "3303614"
      
       , "description": {
           "fr-FR": "RSVA 3614"
         }
       , "country": "fr"
       , "fixed": false
       , "mobile": false
       # etc. see https://gitlab.k-net.fr/shimaore/numbering-plans for appropriate fields
      
       , "initial": {
           "duration": 60
         , "cost": 2000
         }
       , "subsequent": {
           "duration": 10
           "cost": 345
         }
       }
      

      Notes: duration is expressed in seconds, cost is expressed in currency*divider.

      In this example, costs is 2€ at connection time for the first minute, plus 0.345€/minute billed by 10s increments.

    Destination

    The destination records are used to ease translation.

    {
      "_id": "destination:fr-mobile"
    , "type": "destination"
    , "destination": "fr-mobile"
    
    , "description": {
        "fr-FR": "Mobile France"
      }
    , "mobile": true
    , "country": "fr"
    
    , "initial": {
        "duration": 0
      , "cost": 0
      }
    , "subsequent": {
        "duration": 1
        "cost": 12
      }
    }
    

    Notes: duration is expressed in seconds, cost is expressed in currency*divider.

    In this example, there are no connection costs, cost are 0.012€/minute rated per second starting with the first second of the call.

    What does the rating code do?

    The code will output rated records, with the indicated rates applied onto the record.

    The records are generated in the middleware of the earthy-slave project, which uses the code in entertaining-crib to build the CDRs.

    Time of rating

    Rating is based on the tarif applicable at the time the call is connected, in the selected timezone.

    Rated amount

    Pseudo-code:

    # assuming call was answered
    call_duration = ...
    if call_duration <= initial.duration
      amount = initial.cost
    else
      # periods of s.duration duration
      periods = Math.ceil (call_duration-initial.duration)/subsequent.duration
      amount = initial.cost + (subsequent.cost/tarif.per) * (periods*subsequent.duration)
    
    # roundup to the higher integer
    integer_amount = Math.ceil amount
    
    # this is the actual value (expressed in tarif.currency)
    actual_amount = integer_amount / tarif.divider
    

    Contents

    Format of a rated CDR:

    {
      "_id": "{billable-number}-{connect-stamp}-{remote-number}-{duration}"
    
      "source": "{CDR source table/DB}"
      "source_id": "{reference of the record in the source table/DB}"
    
      "rating": `rating` record for the date of the call
      "rating_table": full (CouchDB database) name of the rating table used
      "rating_data": {
        initial: {
          cost:
          duration:
        }
        subsequent: {
          cost:
          duration:
        }
        # and other data found in the `destination` record
      }
    
      "billable_number": CCNQ E.164 billable number (`33972222713`)
      "connect_stamp": ISO8601 connect stamp in local timezone
      "timezone":
      "remote_number":
      "duration":
    
      "period"
    
      "prefix" (object, from database)
      "destination" (object, from database, if applicable)
      "configuration" (object, from database)
    
      "periods"
      "amount"
      "integer_amount"
      "actual_amount"
    }
    

    Source code

    Projects entertaining-crib (rating algorithm) and earthy-slave (FreeSwitch middleware).

    What does the aggregation code

    The aggregation code in astonishing-competition uses the database-driven flat-ornament code execution module to convert a rated CDR into an invoicing CDR.

    Target database

    Note that the storing code is located in module astonishing-competition, not in the rating modules.

    • {period} name is algorithmic; by default = YYYY-MM based on local time

    Carrier-side: cdr-{carrier}-{period}

    Client-side: cdr-{client}-{period}

    Source

    Projet astonishing-competition.

    Install

    npm i entertaining-crib

    DownloadsWeekly Downloads

    3

    Version

    8.0.1

    License

    Unlicense

    Unpacked Size

    46.8 kB

    Total Files

    16

    Last publish

    Collaborators

    • shimaore