SM-FreeSWITCH: fix postpaid calls not being allowed out, Various local test fixes and preparations for release

This commit is contained in:
DanB
2015-07-31 16:29:46 +02:00
parent 9176f56589
commit 9bd7ef2c37
17 changed files with 183 additions and 222 deletions

View File

@@ -13,12 +13,12 @@
"rater": {
"enabled": true, // enable Rater service: <true|false>
"cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234>
"users": "internal",
"pubsubs": "internal", // address where to reach the pubusb service, empty to disable pubsub functionality: <""|internal|x.y.z.y:1234>
"users": "internal", // address where to reach the user service, empty to disable user profile functionality: <""|internal|x.y.z.y:1234>
},
"scheduler": {
"enabled": true, // start Scheduler service: <true|false>
"save_interval": "5s",
},
"cdrs": {
@@ -31,8 +31,15 @@
"enabled": true, // starts the cdrstats service: <true|false>
},
"users": {
"enabled": true,
"pubsubs": {
"enabled": true, // starts PubSub service: <true|false>.
},
"users": {
"enabled": true, // starts User service: <true|false>.
"indexes": ["Uuid"], // user profile field indexes
},
}

View File

@@ -2,5 +2,7 @@
cgrates.org,1001,SysUserName,danb
cgrates.org,1001,SysPassword,hisPass321
cgrates.org,1001,Cli,+4986517174963
cgrates.org,1001,Uuid,388539dfd4f5cefee8f488b78c6c244b9e19138e
cgrates.org,1002,SysUserName,rif
cgrates.org,1002,RifAttr,RifVal
cgrates.org,1002,Uuid,27f37edec0670fa34cf79076b80ef5021e39c5b5
1 #Tenant[0] UserName[1] AttributeName[2] AttributeValue[3]
2 cgrates.org 1001 SysUserName danb
3 cgrates.org 1001 SysPassword hisPass321
4 cgrates.org 1001 Cli +4986517174963
5 cgrates.org 1001 Uuid 388539dfd4f5cefee8f488b78c6c244b9e19138e
6 cgrates.org 1002 SysUserName rif
7 cgrates.org 1002 RifAttr RifVal
8 cgrates.org 1002 Uuid 27f37edec0670fa34cf79076b80ef5021e39c5b5

View File

@@ -10,6 +10,9 @@
"rater": {
"enabled": true, // enable Rater service: <true|false>
"cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234>
"historys": "internal", // address where to reach the history service, empty to disable history functionality: <""|internal|x.y.z.y:1234>
"pubsubs": "internal", // address where to reach the pubusb service, empty to disable pubsub functionality: <""|internal|x.y.z.y:1234>
"users": "internal", // address where to reach the user service, empty to disable user profile functionality: <""|internal|x.y.z.y:1234>
},
@@ -24,6 +27,7 @@
"cdrstats": "internal", // address where to reach the cdrstats service. Empty to disable stats gathering <""|internal|x.y.z.y:1234>
},
"cdrstats": {
"enabled": true, // starts the cdrstats service: <true|false>
},
@@ -61,7 +65,34 @@
{"tag":"Cost", "cdr_field_id": "cost", "type": "cdrfield", "value": "cost"},
],
"trailer_fields": [], // template of the exported trailer fields
}
},
"customer_tpl": {
"cdr_format": "csv", // exported CDRs format <csv>
"field_separator": ";",
"data_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from KBytes to Bytes)
"sms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from SMS unit to call duration in some billing systems)
"generic_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from GENERIC unit to call duration in some billing systems)
"cost_multiply_factor": 1, // multiply cost before export, eg: add VAT
"cost_rounding_decimals": -1, // rounding decimals for Cost values. -1 to disable rounding
"cost_shift_digits": 0, // shift digits in the cost on export (eg: convert from EUR to cents)
"mask_destination_id": "MASKED_DESTINATIONS", // destination id containing called addresses to be masked on export
"mask_length": 0, // length of the destination suffix to be masked
"export_dir": "/tmp/cgr_fsevsock/cgrates/cdre", // path where the exported CDRs will be placed
"header_fields": [], // template of the exported header fields
"content_fields": [ // template of the exported content fields
{"tag": "CgrId", "cdr_field_id": "cgrid", "type": "cdrfield", "value": "cgrid"},
{"tag":"AccId", "cdr_field_id": "accid", "type": "cdrfield", "value": "accid"},
{"tag":"ReqType", "cdr_field_id": "reqtype", "type": "cdrfield", "value": "reqtype"},
{"tag":"Tenant", "cdr_field_id": "tenant", "type": "cdrfield", "value": "tenant"},
{"tag":"Category", "cdr_field_id": "category", "type": "cdrfield", "value": "category"},
{"tag":"Subject", "cdr_field_id": "account", "type": "cdrfield", "value": "account"},
{"tag":"Destination", "cdr_field_id": "destination", "type": "cdrfield", "value": "~destination:s/^1(\\d+)/+$1/:s/^\\+(\\d+)/00$1/"},
{"tag":"AnswerTime", "cdr_field_id": "answer_time", "type": "cdrfield", "value": "answer_time", "layout": "2006-01-02T15:04:05Z07:00"},
{"tag":"Usage", "cdr_field_id": "usage", "type": "cdrfield", "value": "usage"},
{"tag":"Cost", "cdr_field_id": "cost", "type": "cdrfield", "value": "cost"},
],
"trailer_fields": [],
},
},
@@ -77,14 +108,20 @@
},
"history_server": {
"enabled": true, // starts History service: <true|false>.
"historys": {
"enabled": true, // starts History service: <true|false>.
"history_dir": "/tmp/cgr_fsevsock/cgrates/history", // location on disk where to store history files.
},
"history_agent": {
"enabled": true, // starts History as a client: <true|false>.
"pubsubs": {
"enabled": true, // starts PubSub service: <true|false>.
},
"users": {
"enabled": true, // starts User service: <true|false>.
"indexes": ["Uuid"], // user profile field indexes
},

View File

@@ -7,66 +7,12 @@
// This is what you get when you load CGRateS with an empty configuration file.
//"general": {
// "http_skip_tls_veify": false, // if enabled Http Client will accept any TLS certificate
// "rounding_decimals": 10, // system level precision for floats
// "dbdata_encoding": "msgpack", // encoding used to store object data in strings: <msgpack|json>
// "tpexport_dir": "/var/log/cgrates/tpe", // path towards export folder for offline Tariff Plans
// "default_reqtype": "*rated", // default request type to consider when missing from requests: <""|*prepaid|*postpaid|*pseudoprepaid|*rated>
// "default_category": "call", // default Type of Record to consider when missing from requests
// "default_tenant": "cgrates.org", // default Tenant to consider when missing from requests
// "default_subject": "cgrates", // default rating Subject to consider when missing from requests
//},
//"listen": {
// "rpc_json": "127.0.0.1:2012", // RPC JSON listening address
// "rpc_gob": "127.0.0.1:2013", // RPC GOB listening address
// "http": "127.0.0.1:2080", // HTTP listening address
//},
//"rating_db": {
// "db_type": "redis", // rating subsystem database type: <redis>
// "db_host": "127.0.0.1", // rating subsystem database host address
// "db_port": 6379, // rating subsystem port to reach the database
// "db_name": "10", // rating subsystem database name to connect to
// "db_user": "", // rating subsystem username to use when connecting to database
// "db_passwd": "", // rating subsystem password to use when connecting to database
//},
//"accounting_db": {
// "db_type": "redis", // accounting subsystem database: <redis>
// "db_host": "127.0.0.1", // accounting subsystem database host address
// "db_port": 6379, // accounting subsystem port to reach the database
// "db_name": "11", // accounting subsystem database name to connect to
// "db_user": "", // accounting subsystem username to use when connecting to database
// "db_passwd": "", // accounting subsystem password to use when connecting to database
//},
//"stor_db": {
// "db_type": "mysql", // stor database type to use: <mysql|postgres>
// "db_host": "127.0.0.1", // the host to connect to
// "db_port": 3306, // the port to reach the stordb
// "db_name": "cgrates", // stor database name
// "db_user": "cgrates", // username to use when connecting to stordb
// "db_passwd": "CGRateS.org", // password to use when connecting to stordb
// "max_open_conns": 0, // maximum database connections opened
// "max_idle_conns": -1, // maximum database connections idle
//},
//"balancer": {
// "enabled": false, // start Balancer service: <true|false>
//},
"rater": {
"enabled": true, // enable Rater service: <true|false>
// "balancer": "", // register to Balancer as worker: <""|internal|x.y.z.y:1234>
"cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234>
"cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234>
"historys": "internal", // address where to reach the history service, empty to disable history functionality: <""|internal|x.y.z.y:1234>
"pubsubs": "internal", // address where to reach the pubusb service, empty to disable pubsub functionality: <""|internal|x.y.z.y:1234>
"users": "internal", // address where to reach the user service, empty to disable user profile functionality: <""|internal|x.y.z.y:1234>
},
@@ -77,35 +23,13 @@
"cdrs": {
"enabled": true, // start the CDR Server service: <true|false>
// "extra_fields": [], // extra fields to store in CDRs for non-generic CDRs
// "store_cdrs": true, // store cdrs in storDb
"rater": "internal", // address where to reach the Rater for cost calculation, empty to disable functionality: <""|internal|x.y.z.y:1234>
"cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234>
// "reconnects": 5, // number of reconnect attempts to rater or cdrs
// "cdr_replication":[], // replicate the raw CDR to a number of servers
"rater": "internal", // address where to reach the Rater for cost calculation: <""|internal|x.y.z.y:1234>
"cdrstats": "internal", // address where to reach the cdrstats service. Empty to disable stats gathering <""|internal|x.y.z.y:1234>
},
"cdrstats": {
"enabled": true, // starts the cdrstats service: <true|false>
// "queue_length": 50, // number of items in the stats buffer
// "time_window": "1h", // will only keep the CDRs who's call setup time is not older than time.Now()-TimeWindow
// "metrics": ["ASR", "ACD", "ACC"], // stat metric ids to build
// "setup_interval": [], // filter on CDR SetupTime
// "tors": [], // filter on CDR TOR fields
// "cdr_hosts": [], // filter on CDR CdrHost fields
// "cdr_sources": [], // filter on CDR CdrSource fields
// "req_types": [], // filter on CDR ReqType fields
// "directions": [], // filter on CDR Direction fields
// "tenants": [], // filter on CDR Tenant fields
// "categories": [], // filter on CDR Category fields
// "accounts": [], // filter on CDR Account fields
// "subjects": [], // filter on CDR Subject fields
// "destination_prefixes": [], // filter on CDR Destination prefixes
// "usage_interval": [], // filter on CDR Usage
// "mediation_run_ids": [], // filter on CDR MediationRunId fields
// "rated_accounts": [], // filter on CDR RatedAccount fields
// "rated_subjects": [], // filter on CDR RatedSubject fields
// "cost_interval": [], // filter on CDR Cost
},
@@ -172,103 +96,28 @@
},
//"cdrc": {
// "*default": {
// "enabled": false, // enable CDR client functionality
// "cdrs_address": "internal", // address where to reach CDR server. <internal|x.y.z.y:1234>
// "cdr_format": "csv", // CDR file format <csv|freeswitch_csv|fwv>
// "field_separator": ",", // separator used in case of csv files
// "run_delay": 0, // sleep interval in seconds between consecutive runs, 0 to use automation via inotify
// "data_usage_multiply_factor": 1024, // conversion factor for data usage
// "cdr_in_dir": "/var/log/cgrates/cdrc/in", // absolute path towards the directory where the CDRs are stored
// "cdr_out_dir": "/var/log/cgrates/cdrc/out", // absolute path towards the directory where processed CDRs will be moved
// "cdr_source_id": "freeswitch_csv", // free form field, tag identifying the source of the CDRs within CDRS database
// "cdr_filter": "", // Filter CDR records to import
// "content_fields":[ // import template, tag will match internally CDR field, in case of .csv value will be represented by index of the field value
// {"tag": "tor", "cdr_field_id": "tor", "type": "cdrfield", "value": "2", "mandatory": true},
// {"tag": "accid", "cdr_field_id": "accid", "type": "cdrfield", "value": "3", "mandatory": true},
// {"tag": "reqtype", "cdr_field_id": "reqtype", "type": "cdrfield", "value": "4", "mandatory": true},
// {"tag": "direction", "cdr_field_id": "direction", "type": "cdrfield", "value": "5", "mandatory": true},
// {"tag": "tenant", "cdr_field_id": "tenant", "type": "cdrfield", "value": "6", "mandatory": true},
// {"tag": "category", "cdr_field_id": "category", "type": "cdrfield", "value": "7", "mandatory": true},
// {"tag": "account", "cdr_field_id": "account", "type": "cdrfield", "value": "8", "mandatory": true},
// {"tag": "subject", "cdr_field_id": "subject", "type": "cdrfield", "value": "9", "mandatory": true},
// {"tag": "destination", "cdr_field_id": "destination", "type": "cdrfield", "value": "10", "mandatory": true},
// {"tag": "setup_time", "cdr_field_id": "setup_time", "type": "cdrfield", "value": "11", "mandatory": true},
// {"tag": "answer_time", "cdr_field_id": "answer_time", "type": "cdrfield", "value": "12", "mandatory": true},
// {"tag": "usage", "cdr_field_id": "usage", "type": "cdrfield", "value": "13", "mandatory": true},
// ],
// },
//},
//"sm_freeswitch": {
// "enabled": false, // starts SessionManager service: <true|false>
// "rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013>
// "cdrs": "", // address where to reach CDR Server, empty to disable CDR capturing <""|internal|x.y.z.y:1234>
// "reconnects": 5, // number of reconnect attempts to rater or cdrs
// "cdr_extra_fields": [], // extra fields to store in CDRs in case of processing them
// "debit_interval": "10s", // interval to perform debits on.
// "min_call_duration": "0s", // only authorize calls with allowed duration higher than this
// "max_call_duration": "3h", // maximum call duration a prepaid call can last
// "min_dur_low_balance": "5s", // threshold which will trigger low balance warnings for prepaid calls (needs to be lower than debit_interval)
// "low_balance_ann_file": "", // file to be played when low balance is reached for prepaid calls
// "empty_balance_context": "", // if defined, prepaid calls will be transfered to this context on empty balance
// "empty_balance_ann_file": "", // file to be played before disconnecting prepaid calls on empty balance (applies only if no context defined)
// "connections":[ // instantiate connections to multiple FreeSWITCH servers
// {"server": "127.0.0.1:8021", "password": "ClueCon", "reconnects": 5}
// ],
//},
"sm_kamailio": {
"enabled": true, // starts SessionManager service: <true|false>
// "rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013>
"cdrs": "internal", // address where to reach CDR Server, empty to disable CDR capturing <""|internal|x.y.z.y:1234>
// "reconnects": 5, // number of reconnect attempts to rater or cdrs
"create_cdr": true, // create CDR out of events and sends them to CDRS component
// "debit_interval": "10s", // interval to perform debits on.
// "min_call_duration": "0s", // only authorize calls with allowed duration higher than this
// "max_call_duration": "3h", // maximum call duration a prepaid call can last
// "connections":[ // instantiate connections to multiple Kamailio servers
// {"evapi_addr": "127.0.0.1:8448", "reconnects": 5} // reconnects -1 to indefinitely connect
// ],
},
//"sm_opensips": {
// "enabled": false, // starts SessionManager service: <true|false>
// "listen_udp": "127.0.0.1:2020", // address where to listen for datagram events coming from OpenSIPS
// "rater": "internal", // address where to reach the Rater <""|internal|127.0.0.1:2013>
// "cdrs": "", // address where to reach CDR Server, empty to disable CDR capturing <""|internal|x.y.z.y:1234>
// "debit_interval": "10s", // interval to perform debits on.
// "min_call_duration": "0s", // only authorize calls with allowed duration higher than this
// "max_call_duration": "3h", // maximum call duration a prepaid call can last
// "events_subscribe_interval": "60s", // automatic events subscription to OpenSIPS, 0 to disable it
// "mi_addr": "127.0.0.1:8020", // address where to reach OpenSIPS MI to send session disconnects
// "reconnects": -1, // reconnects -1 to indefinitely connect
//},
"history_server": {
"enabled": true, // starts History service: <true|false>.
"historys": {
"enabled": true, // starts History service: <true|false>.
"history_dir": "/tmp/cgr_kamevapi/cgrates/history", // location on disk where to store history files.
// "save_interval": "1s", // interval to save changed cache into .git archive
},
"history_agent": {
"enabled": true, // starts History as a client: <true|false>.
// "server": "internal", // address where to reach the master history server: <internal|x.y.z.y:1234>
"pubsubs": {
"enabled": true, // starts PubSub service: <true|false>.
},
//"mailer": {
// "server": "localhost", // the server to use when sending emails out
// "auth_user": "cgrates", // authenticate to email server using this user
// "auth_passwd": "CGRateS.org", // authenticate to email server with this password
// "from_address": "cgr-mailer@localhost.localdomain" // from address used when sending emails out
//},
"users": {
"enabled": true, // starts User service: <true|false>.
"indexes": ["Uuid"], // user profile field indexes
},
}

View File

@@ -103,7 +103,7 @@ route[CGR_LCR_REPLY] {
route[CGR_SESSION_DISCONNECT] {
json_get_field("$evapi(msg)", "HashEntry", "$var(HashEntry)");
json_get_field("$evapi(msg)", "HashId", "$var(HashId)");
son_get_field("$evapi(msg)", "Reason", "$var(Reason)");
json_get_field("$evapi(msg)", "Reason", "$var(Reason)");
jsonrpc_exec('{"jsonrpc":"2.0","id":1, "method":"dlg.end_dlg","params":[$(var(HashEntry){s.rm,"}),$(var(HashId){s.rm,"})]}');
#$jsonrpl($var(reply));
}

View File

@@ -200,9 +200,14 @@ route[CGRATES_AUTH_REPLY] {
sl_send_reply("503","CGR_ERROR");
exit;
}
if $var(CgrMaxSessionTime) != -1 && !dlg_set_timeout("$var(CgrMaxSessionTime)") {
sl_send_reply("503","CGR_MAX_SESSION_TIME_ERROR");
exit;
if $var(CgrMaxSessionTime) != -1 {
if $var(CgrMaxSessionTime) == 0 { // Not enough balance, do not allow the call to go through
sl_send_reply("403","Insufficient credit");
exit;
} else if !dlg_set_timeout("$var(CgrMaxSessionTime)") {
sl_send_reply("503","CGR_MAX_SESSION_TIME_ERROR");
exit;
}
}
if $var(CgrSuppliers) != "" { # Enforce the supplier variable to the first one received from CGRateS, more for testing purposes
$dlg_var(cgrSupplier) = $(var(CgrSuppliers){s.select,0,,});

View File

@@ -10,6 +10,9 @@
"rater": {
"enabled": true, // enable Rater service: <true|false>
"cdrstats": "internal", // address where to reach the cdrstats service, empty to disable stats functionality<""|internal|x.y.z.y:1234>
"historys": "internal", // address where to reach the history service, empty to disable history functionality: <""|internal|x.y.z.y:1234>
"pubsubs": "internal", // address where to reach the pubusb service, empty to disable pubsub functionality: <""|internal|x.y.z.y:1234>
"users": "internal", // address where to reach the user service, empty to disable user profile functionality: <""|internal|x.y.z.y:1234>
},
@@ -42,7 +45,7 @@
"cost_shift_digits": 0, // shift digits in the cost on export (eg: convert from EUR to cents)
"mask_destination_id": "MASKED_DESTINATIONS", // destination id containing called addresses to be masked on export
"mask_length": 0, // length of the destination suffix to be masked
"export_dir": "/tmp/cgr_fsevsock/cgrates/cdre", // path where the exported CDRs will be placed
"export_dir": "/tmp/cgr_osipsasync/cgrates/cdre", // path where the exported CDRs will be placed
"header_fields": [], // template of the exported header fields
"content_fields": [ // template of the exported content fields
{"tag": "CgrId", "cdr_field_id": "cgrid", "type": "cdrfield", "value": "cgrid"},
@@ -62,7 +65,34 @@
{"tag":"Cost", "cdr_field_id": "cost", "type": "cdrfield", "value": "cost"},
],
"trailer_fields": [], // template of the exported trailer fields
}
},
"customer_tpl": {
"cdr_format": "csv", // exported CDRs format <csv>
"field_separator": ";",
"data_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from KBytes to Bytes)
"sms_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from SMS unit to call duration in some billing systems)
"generic_usage_multiply_factor": 1, // multiply data usage before export (eg: convert from GENERIC unit to call duration in some billing systems)
"cost_multiply_factor": 1, // multiply cost before export, eg: add VAT
"cost_rounding_decimals": -1, // rounding decimals for Cost values. -1 to disable rounding
"cost_shift_digits": 0, // shift digits in the cost on export (eg: convert from EUR to cents)
"mask_destination_id": "MASKED_DESTINATIONS", // destination id containing called addresses to be masked on export
"mask_length": 0, // length of the destination suffix to be masked
"export_dir": "/tmp/cgr_osipsasync/cgrates/cdre", // path where the exported CDRs will be placed
"header_fields": [], // template of the exported header fields
"content_fields": [ // template of the exported content fields
{"tag": "CgrId", "cdr_field_id": "cgrid", "type": "cdrfield", "value": "cgrid"},
{"tag":"AccId", "cdr_field_id": "accid", "type": "cdrfield", "value": "accid"},
{"tag":"ReqType", "cdr_field_id": "reqtype", "type": "cdrfield", "value": "reqtype"},
{"tag":"Tenant", "cdr_field_id": "tenant", "type": "cdrfield", "value": "tenant"},
{"tag":"Category", "cdr_field_id": "category", "type": "cdrfield", "value": "category"},
{"tag":"Subject", "cdr_field_id": "account", "type": "cdrfield", "value": "account"},
{"tag":"Destination", "cdr_field_id": "destination", "type": "cdrfield", "value": "~destination:s/^1(\\d+)/+$1/:s/^\\+(\\d+)/00$1/"},
{"tag":"AnswerTime", "cdr_field_id": "answer_time", "type": "cdrfield", "value": "answer_time", "layout": "2006-01-02T15:04:05Z07:00"},
{"tag":"Usage", "cdr_field_id": "usage", "type": "cdrfield", "value": "usage"},
{"tag":"Cost", "cdr_field_id": "cost", "type": "cdrfield", "value": "cost"},
],
"trailer_fields": [],
},
},
@@ -78,15 +108,20 @@
},
"history_server": {
"enabled": true, // starts History service: <true|false>.
"historys": {
"enabled": true, // starts History service: <true|false>.
"history_dir": "/tmp/cgr_osipsasync/cgrates/history", // location on disk where to store history files.
},
"history_agent": {
"enabled": true, // starts History as a client: <true|false>.
"server": "internal", // address where to reach the master history server: <internal|x.y.z.y:1234>
"pubsubs": {
"enabled": true, // starts PubSub service: <true|false>.
},
"users": {
"enabled": true, // starts User service: <true|false>.
"indexes": ["Uuid"], // user profile field indexes
},

View File

@@ -91,22 +91,22 @@ modparam("db_flatstore", "single_file", 1)
loadmodule "acc.so"
modparam("acc", "detect_direction", 1)
#modparam("acc", "cdr_flag", "CDR")
#modparam("acc", "evi_flag", "CDR")
#modparam("acc", "evi_missed_flag", "CDR")
modparam("acc", "evi_flag", "CDR")
modparam("acc", "evi_missed_flag", "CDR")
modparam("acc", "evi_extra", "cgr_reqtype=$avp(cgr_reqtype);
cgr_account=$avp(cgr_account);
cgr_destination=$avp(cgr_destination);
cgr_supplier=$avp(cgr_supplier);
dialog_id=$DLG_did")
modparam("acc", "db_url", "flatstore:/tmp")
modparam("acc", "db_flag", "CDR")
modparam("acc", "db_missed_flag", "CDR")
modparam("acc", "db_table_missed_calls", "cgr_missed")
modparam("acc", "db_extra", "cgr_reqtype=$avp(cgr_reqtype);
cgr_account=$avp(cgr_account);
cgr_destination=$avp(cgr_destination);
cgr_supplier=$avp(cgr_supplier);
dialog_id=$DLG_did")
#modparam("acc", "db_url", "flatstore:/tmp")
#modparam("acc", "db_flag", "CDR")
#modparam("acc", "db_missed_flag", "CDR")
#modparam("acc", "db_table_missed_calls", "cgr_missed")
#modparam("acc", "db_extra", "cgr_reqtype=$avp(cgr_reqtype);
# cgr_account=$avp(cgr_account);
# cgr_destination=$avp(cgr_destination);
# cgr_supplier=$avp(cgr_supplier);
# dialog_id=$DLG_did")
#### CfgUtils module
loadmodule "cfgutils.so"
@@ -358,9 +358,6 @@ route[location] {
t_reply("404", "Not Found");
exit;
}
append_branch();
append_branch();
setflag(CDR);
}
failure_route[missed_call] {

View File

@@ -324,7 +324,6 @@ func (self *CdrServer) rateCDR(storedCdr *StoredCdr) error {
func (self *CdrServer) replicateCdr(cdr *StoredCdr) error {
Logger.Debug(fmt.Sprintf("replicateCdr cdr: %+v, configuration: %+v", cdr, self.cgrCfg.CDRSCdrReplication))
for _, rplCfg := range self.cgrCfg.CDRSCdrReplication {
Logger.Debug(fmt.Sprintf("Replicating CDR with configuration: %+v", rplCfg))
passesFilters := true
for _, cdfFltr := range rplCfg.CdrFilter {
if fltrPass, _ := cdr.PassesFieldFilter(cdfFltr); !fltrPass {

View File

@@ -45,21 +45,25 @@ type Responder struct {
ExitChan chan bool
CdrSrv *CdrServer
Stats StatsInterface
cnt int64
}
/*
RPC method thet provides the external RPC interface for getting the rating information.
*/
func (rs *Responder) GetCost(arg *CallDescriptor, reply *CallCost) (err error) {
rs.cnt += 1
if arg.Subject == "" {
arg.Subject = arg.Account
}
Logger.Debug(fmt.Sprintf("CD before load user profile: %+v, count: %d", arg, rs.cnt))
if upData, err := LoadUserProfile(arg, "ExtraFields"); err != nil {
return err
} else {
udRcv := upData.(*CallDescriptor)
*arg = *udRcv
}
Logger.Debug(fmt.Sprintf("CD after load user profile: %+v, count: %d", arg, rs.cnt))
if rs.Bal != nil {
r, e := rs.getCallCost(arg, "Responder.GetCost")
*reply, err = *r, e

View File

@@ -186,7 +186,7 @@ func (um *UserMap) GetUsers(up UserProfile, results *UserProfiles) error {
}
}
var candidates UserProfiles
candidates := make(UserProfiles, 0) // It should not return nil in case of no users but []
for key, values := range table {
ponder := 0
tableUP := &UserProfile{

View File

@@ -326,7 +326,7 @@ func TestTutFsCallsCdrs(t *testing.T) {
if reply[0].ReqType != utils.META_PREPAID {
t.Errorf("Unexpected ReqType for CDR: %+v", reply[0])
}
if reply[0].Usage != "65" { // Usage as seconds
if reply[0].Usage != "65" && reply[0].Usage != "66" { // Usage as seconds
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
if reply[0].Cost != 0 { // Cost was not calculated
@@ -386,7 +386,7 @@ func TestTutFsCallsCdrs(t *testing.T) {
if reply[0].Destination != "1001" {
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
}
if reply[0].Usage != "63" { // Usage as seconds
if reply[0].Usage != "63" && reply[0].Usage != "64" { // Usage as seconds, sometimes takes a second longer to disconnect
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
}
@@ -405,7 +405,7 @@ func TestTutFsCallsCdrs(t *testing.T) {
if reply[0].Destination != "1001" {
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
}
if reply[0].Usage != "62" { // Usage as seconds
if reply[0].Usage != "62" && reply[0].Usage != "63" { // Usage as seconds
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
}
@@ -424,7 +424,7 @@ func TestTutFsCallsCdrs(t *testing.T) {
if reply[0].Destination != "1002" {
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
}
if reply[0].Usage != "64" { // Usage as seconds
if reply[0].Usage != "64" && reply[0].Usage != "65" { // Usage as seconds
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
if reply[0].Cost == -1.0 { // Cost was not calculated
@@ -446,7 +446,7 @@ func TestTutFsCallsCdrs(t *testing.T) {
if reply[0].Destination != "1002" {
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
}
if reply[0].Usage != "66" { // Usage as seconds
if reply[0].Usage != "66" && reply[0].Usage != "67" { // Usage as seconds
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
if reply[0].Cost == -1.0 { // Cost was not calculated

View File

@@ -595,7 +595,6 @@ func TestTutKamCallsStopPjsuaListener(t *testing.T) {
time.Sleep(time.Duration(1) * time.Second) // Allow pjsua to finish it's tasks, eg un-REGISTER
}
/*
func TestTutKamCallsStopCgrEngine(t *testing.T) {
if !*testCalls {
return
@@ -611,4 +610,3 @@ func TestTutKamCallsStopKam(t *testing.T) {
}
engine.KillProcName("kamailio", 1000)
}
*/

View File

@@ -182,6 +182,18 @@ func TestTutLocalGetCachedItemAge(t *testing.T) {
*/
}
func TestTutLocalGetUsers(t *testing.T) {
if !*testLocal {
return
}
var users engine.UserProfiles
if err := tutLocalRpc.Call("UsersV1.GetUsers", engine.UserProfile{}, &users); err != nil {
t.Error("Got error on UsersV1.GetUsers: ", err.Error())
} else if len(users) != 2 {
t.Error("Calling UsersV1.GetUsers got users:", len(users))
}
}
// Check call costs
func TestTutLocalGetCosts(t *testing.T) {
if !*testLocal {
@@ -206,6 +218,24 @@ func TestTutLocalGetCosts(t *testing.T) {
} else if cc.Cost != 0.6 {
t.Errorf("Calling Responder.GetCost got callcost: %v", cc.Cost)
}
// Make sure that the same cost is returned via users aliasing
cd = engine.CallDescriptor{
Direction: "*out",
Category: "call",
Tenant: utils.USERS,
Subject: utils.USERS,
Account: utils.USERS,
Destination: "1002",
DurationIndex: 0,
TimeStart: tStart,
TimeEnd: tEnd,
ExtraFields: map[string]string{"Uuid": "388539dfd4f5cefee8f488b78c6c244b9e19138e"},
}
if err := tutLocalRpc.Call("Responder.GetCost", cd, &cc); err != nil {
t.Error("Got error on Responder.GetCost: ", err.Error())
} else if cc.Cost != 0.6 {
t.Errorf("Calling Responder.GetCost got callcost: %v", cc.Cost)
}
tStart, _ = utils.ParseDate("2014-08-04T13:00:00Z")
tEnd, _ = utils.ParseDate("2014-08-04T13:01:25Z")
cd = engine.CallDescriptor{

View File

@@ -71,7 +71,6 @@ func TestTutOsipsCallsResetStorDb(t *testing.T) {
}
}
/*
// start Kam server
func TestTutOsipsCallsStartOsips(t *testing.T) {
if !*testCalls {
@@ -82,7 +81,6 @@ func TestTutOsipsCallsStartOsips(t *testing.T) {
t.Fatal(err)
}
}
*/
// Start CGR Engine
func TestTutOsipsCallsStartEngine(t *testing.T) {
@@ -358,7 +356,7 @@ func TestTutOsipsCallsCdrs(t *testing.T) {
if reply[0].Destination != "1001" {
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
}
if reply[0].Usage != "62" { // Usage as seconds
if reply[0].Usage != "62" && reply[0].Usage != "63" { // Usage as seconds
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
}
@@ -448,11 +446,9 @@ func TestTutOsipsCallsStopCgrEngine(t *testing.T) {
}
}
/*
func TestTutOsipsCallsStopOpensips(t *testing.T) {
if !*testCalls {
return
}
engine.KillProcName("opensips", 100)
}
*/

View File

@@ -220,13 +220,15 @@ func (sm *FSSessionManager) onChannelPark(ev engine.Event, connId string) {
if err := sm.rater.GetDerivedMaxSessionTime(ev.AsStoredCdr(), &maxCallDuration); err != nil {
engine.Logger.Err(fmt.Sprintf("<SM-FreeSWITCH> Could not get max session time for %s, error: %s", ev.GetUUID(), err.Error()))
}
maxCallDur := time.Duration(maxCallDuration)
if maxCallDur <= sm.cfg.MinCallDuration {
//engine.Logger.Info(fmt.Sprintf("Not enough credit for trasferring the call %s for %s.", ev.GetUUID(), cd.GetKey(cd.Subject)))
sm.unparkCall(ev.GetUUID(), connId, ev.GetCallDestNr(utils.META_DEFAULT), INSUFFICIENT_FUNDS)
return
if maxCallDuration != -1 { // For calls different than unlimited, set limits
maxCallDur := time.Duration(maxCallDuration)
if maxCallDur <= sm.cfg.MinCallDuration {
//engine.Logger.Info(fmt.Sprintf("Not enough credit for trasferring the call %s for %s.", ev.GetUUID(), cd.GetKey(cd.Subject)))
sm.unparkCall(ev.GetUUID(), connId, ev.GetCallDestNr(utils.META_DEFAULT), INSUFFICIENT_FUNDS)
return
}
sm.setMaxCallDuration(ev.GetUUID(), connId, maxCallDur)
}
sm.setMaxCallDuration(ev.GetUUID(), connId, maxCallDur)
// ComputeLcr
if ev.ComputeLcr() {
cd, err := fsev.AsCallDescriptor()
@@ -341,7 +343,7 @@ func (sm *FSSessionManager) Shutdown() (err error) {
continue
}
engine.Logger.Info(fmt.Sprintf("<SM-FreeSWITCH> Shutting down all sessions on connection id: %s", connId))
if _, err = fSock.SendApiCmd("hupall MANAGER_REQUEST cgr_reqtype prepaid"); err != nil {
if _, err = fSock.SendApiCmd("hupall MANAGER_REQUEST cgr_reqtype *prepaid"); err != nil {
engine.Logger.Err(fmt.Sprintf("<SM-FreeSWITCH> Error on calls shutdown: %s, connection id: %s", err.Error(), connId))
}
}