提交 9bf2726e authored 作者: Jeff Lenk's avatar Jeff Lenk

FS-3950 --resolve nibblebill changes!

上级 842203f7
...@@ -52,19 +52,20 @@ ...@@ -52,19 +52,20 @@
typedef struct { typedef struct {
switch_time_t lastts; /* Last time we did any billing */ switch_time_t lastts; /* Last time we did any billing */
float total; /* Total amount billed so far */ double total; /* Total amount billed so far */
switch_time_t pausets; /* Timestamp of when a pause action started. 0 if not paused */ switch_time_t pausets; /* Timestamp of when a pause action started. 0 if not paused */
float bill_adjustments; /* Adjustments to make to the next billing, based on pause/resume events */ double bill_adjustments; /* Adjustments to make to the next billing, based on pause/resume events */
int lowbal_action_executed; /* Set to 1 once lowbal_action has been executed */
} nibble_data_t; } nibble_data_t;
typedef struct nibblebill_results { typedef struct nibblebill_results {
float balance; double balance;
float percall_max; /* Overrides global on a per-user level */ double percall_max; /* Overrides global on a per-user level */
float lowbal_amt; /* ditto */ double lowbal_amt; /* ditto */
} nibblebill_results_t; } nibblebill_results_t;
...@@ -80,11 +81,11 @@ static struct { ...@@ -80,11 +81,11 @@ static struct {
switch_mutex_t *mutex; switch_mutex_t *mutex;
/* Global billing config options */ /* Global billing config options */
float percall_max_amt; /* Per-call billing limit (safety check, for fraud) */ double percall_max_amt; /* Per-call billing limit (safety check, for fraud) */
char *percall_action; /* Exceeded length of per-call action */ char *percall_action; /* Exceeded length of per-call action */
float lowbal_amt; /* When we warn them they are near depletion */ double lowbal_amt; /* When we warn them they are near depletion */
char *lowbal_action; /* Low balance action */ char *lowbal_action; /* Low balance action */
float nobal_amt; /* Minimum amount that must remain in the account */ double nobal_amt; /* Minimum amount that must remain in the account */
char *nobal_action; /* Drop action */ char *nobal_action; /* Drop action */
/* Other options */ /* Other options */
...@@ -136,7 +137,7 @@ static int nibblebill_callback(void *pArg, int argc, char **argv, char **columnN ...@@ -136,7 +137,7 @@ static int nibblebill_callback(void *pArg, int argc, char **argv, char **columnN
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
if (!strcasecmp(columnNames[i], "nibble_balance")) { if (!strcasecmp(columnNames[i], "nibble_balance")) {
cbt->balance = (float) atof(argv[0]); cbt->balance = atof(argv[0]);
} }
} }
...@@ -179,15 +180,15 @@ static switch_status_t load_config(void) ...@@ -179,15 +180,15 @@ static switch_status_t load_config(void)
} else if (!strcasecmp(var, "percall_action")) { } else if (!strcasecmp(var, "percall_action")) {
set_global_percall_action(val); set_global_percall_action(val);
} else if (!strcasecmp(var, "percall_max_amt")) { } else if (!strcasecmp(var, "percall_max_amt")) {
globals.percall_max_amt = (float) atof(val); globals.percall_max_amt = atof(val);
} else if (!strcasecmp(var, "lowbal_action")) { } else if (!strcasecmp(var, "lowbal_action")) {
set_global_lowbal_action(val); set_global_lowbal_action(val);
} else if (!strcasecmp(var, "lowbal_amt")) { } else if (!strcasecmp(var, "lowbal_amt")) {
globals.lowbal_amt = (float) atof(val); globals.lowbal_amt = atof(val);
} else if (!strcasecmp(var, "nobal_action")) { } else if (!strcasecmp(var, "nobal_action")) {
set_global_nobal_action(val); set_global_nobal_action(val);
} else if (!strcasecmp(var, "nobal_amt")) { } else if (!strcasecmp(var, "nobal_amt")) {
globals.nobal_amt = (float) atof(val); globals.nobal_amt = atof(val);
} else if (!strcasecmp(var, "global_heartbeat")) { } else if (!strcasecmp(var, "global_heartbeat")) {
globals.global_heartbeat = atoi(val); globals.global_heartbeat = atoi(val);
} }
...@@ -252,6 +253,23 @@ void debug_event_handler(switch_event_t *event) ...@@ -252,6 +253,23 @@ void debug_event_handler(switch_event_t *event)
} }
} }
static switch_status_t exec_app(switch_core_session_t *session, const char *app_string)
{
switch_status_t status;
char *strings[2] = { 0 };
char *dup;
if (!app_string) {
return SWITCH_STATUS_FALSE;
}
dup = strdup(app_string);
switch_assert(dup);
switch_separate_string(dup, ' ', strings, sizeof(strings) / sizeof(strings[0]));
status = switch_core_session_execute_application(session, strings[0], strings[1]);
free(dup);
return status;
}
static void transfer_call(switch_core_session_t *session, char *destination) static void transfer_call(switch_core_session_t *session, char *destination)
{ {
...@@ -292,9 +310,8 @@ static void transfer_call(switch_core_session_t *session, char *destination) ...@@ -292,9 +310,8 @@ static void transfer_call(switch_core_session_t *session, char *destination)
free(mydup); free(mydup);
} }
/* At this time, billing never succeeds if you don't have a database. */ /* At this time, billing never succeeds if you don't have a database. */
static switch_status_t bill_event(float billamount, const char *billaccount, switch_channel_t *channel) static switch_status_t bill_event(double billamount, const char *billaccount, switch_channel_t *channel)
{ {
char *sql = NULL, *dsql = NULL; char *sql = NULL, *dsql = NULL;
switch_odbc_statement_handle_t stmt = NULL; switch_odbc_statement_handle_t stmt = NULL;
...@@ -306,7 +323,7 @@ static switch_status_t bill_event(float billamount, const char *billaccount, swi ...@@ -306,7 +323,7 @@ static switch_status_t bill_event(float billamount, const char *billaccount, swi
if (globals.custom_sql_save) { if (globals.custom_sql_save) {
if (switch_string_var_check_const(globals.custom_sql_save) || switch_string_has_escaped_data(globals.custom_sql_save)) { if (switch_string_var_check_const(globals.custom_sql_save) || switch_string_has_escaped_data(globals.custom_sql_save)) {
switch_channel_set_variable_printf(channel, "nibble_increment", "%f", billamount, SWITCH_FALSE); switch_channel_set_variable_printf(channel, "nibble_bill", "%f", billamount, SWITCH_FALSE);
sql = switch_channel_expand_variables(channel, globals.custom_sql_save); sql = switch_channel_expand_variables(channel, globals.custom_sql_save);
if (sql != globals.custom_sql_save) dsql = sql; if (sql != globals.custom_sql_save) dsql = sql;
} else { } else {
...@@ -339,14 +356,14 @@ static switch_status_t bill_event(float billamount, const char *billaccount, swi ...@@ -339,14 +356,14 @@ static switch_status_t bill_event(float billamount, const char *billaccount, swi
} }
static float get_balance(const char *billaccount, switch_channel_t *channel) static double get_balance(const char *billaccount, switch_channel_t *channel)
{ {
char *dsql = NULL, *sql = NULL; char *dsql = NULL, *sql = NULL;
nibblebill_results_t pdata; nibblebill_results_t pdata;
float balance = 0.00f; double balance = 0.0;
if (!switch_odbc_available()) { if (!switch_odbc_available()) {
return -1.00f; return -1.0;
} }
memset(&pdata, 0, sizeof(pdata)); memset(&pdata, 0, sizeof(pdata));
...@@ -369,7 +386,7 @@ static float get_balance(const char *billaccount, switch_channel_t *channel) ...@@ -369,7 +386,7 @@ static float get_balance(const char *billaccount, switch_channel_t *channel)
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error running this query: [%s]\n", sql); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error running this query: [%s]\n", sql);
/* Return -1 for safety */ /* Return -1 for safety */
balance = -1.00f; balance = -1.0;
} else { } else {
/* Successfully retrieved! */ /* Successfully retrieved! */
balance = pdata.balance; balance = pdata.balance;
...@@ -391,7 +408,7 @@ static switch_status_t do_billing(switch_core_session_t *session) ...@@ -391,7 +408,7 @@ static switch_status_t do_billing(switch_core_session_t *session)
/* Local vars */ /* Local vars */
nibble_data_t *nibble_data; nibble_data_t *nibble_data;
switch_time_t ts = switch_micro_time_now(); switch_time_t ts = switch_micro_time_now();
float billamount; double billamount;
char date[80] = ""; char date[80] = "";
char *uuid; char *uuid;
switch_size_t retsize; switch_size_t retsize;
...@@ -399,9 +416,9 @@ static switch_status_t do_billing(switch_core_session_t *session) ...@@ -399,9 +416,9 @@ static switch_status_t do_billing(switch_core_session_t *session)
const char *billrate; const char *billrate;
const char *billincrement; const char *billincrement;
const char *billaccount; const char *billaccount;
float nobal_amt = globals.nobal_amt; double nobal_amt = globals.nobal_amt;
//float lowbal_amt = globals.lowbal_amt; double lowbal_amt = globals.lowbal_amt;
float balance; double balance;
if (!session) { if (!session) {
/* Why are we here? */ /* Why are we here? */
...@@ -421,13 +438,13 @@ static switch_status_t do_billing(switch_core_session_t *session) ...@@ -421,13 +438,13 @@ static switch_status_t do_billing(switch_core_session_t *session)
billaccount = switch_channel_get_variable(channel, "nibble_account"); billaccount = switch_channel_get_variable(channel, "nibble_account");
if (!zstr(switch_channel_get_variable(channel, "nobal_amt"))) { if (!zstr(switch_channel_get_variable(channel, "nobal_amt"))) {
nobal_amt = (float)atof(switch_channel_get_variable(channel, "nobal_amt")); nobal_amt = atof(switch_channel_get_variable(channel, "nobal_amt"));
} }
/*
if (!zstr(switch_channel_get_variable(channel, "lowbal_amt"))) { if (!zstr(switch_channel_get_variable(channel, "lowbal_amt"))) {
lowbal_amt = (float)atof(switch_channel_get_variable(channel, "lowbal_amt")); lowbal_amt = atof(switch_channel_get_variable(channel, "lowbal_amt"));
} }
*/
/* Return if there's no billing information on this session */ /* Return if there's no billing information on this session */
if (!billrate || !billaccount) { if (!billrate || !billaccount) {
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
...@@ -497,11 +514,15 @@ static switch_status_t do_billing(switch_core_session_t *session) ...@@ -497,11 +514,15 @@ static switch_status_t do_billing(switch_core_session_t *session)
if ((ts - nibble_data->lastts) >= 0) { if ((ts - nibble_data->lastts) >= 0) {
/* If billincrement is set we bill by it and not by time elapsed */ /* If billincrement is set we bill by it and not by time elapsed */
if (!(switch_strlen_zero(billincrement))) { if (!(switch_strlen_zero(billincrement))) {
float chargedunits = ((int)((ts - nibble_data->lastts) / 1000000) <= (int)atof(billincrement)) ? ((float)atof(billincrement) * 1000000) : ceil((ts - nibble_data->lastts) / ((float)atof(billincrement) * 1000000)) * ((float)atof(billincrement) * 1000000); switch_time_t chargedunits = (ts - nibble_data->lastts) / 1000000 <= atol(billincrement) ? atol(billincrement) * 1000000 : (switch_time_t)(ceil((ts - nibble_data->lastts) / (atol(billincrement) * 1000000.0))) * atol(billincrement) * 1000000;
billamount = ((float) atof(billrate) / 1000000 / 60) * chargedunits - nibble_data->bill_adjustments; billamount = (atof(billrate) / 1000000 / 60) * chargedunits - nibble_data->bill_adjustments;
/* Account for the prepaid amount */
nibble_data->lastts += chargedunits;
} else { } else {
/* Convert billrate into microseconds and multiply by # of microseconds that have passed since last *successful* bill */ /* Convert billrate into microseconds and multiply by # of microseconds that have passed since last *successful* bill */
billamount = ((float) atof(billrate) / 1000000 / 60) * ((ts - nibble_data->lastts)) - nibble_data->bill_adjustments; billamount = (atof(billrate) / 1000000 / 60) * ((ts - nibble_data->lastts)) - nibble_data->bill_adjustments;
/* Update the last time we billed */
nibble_data->lastts = ts;
} }
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Billing $%f to %s (Call: %s / %f so far)\n", billamount, billaccount, switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Billing $%f to %s (Call: %s / %f so far)\n", billamount, billaccount,
...@@ -521,21 +542,31 @@ static switch_status_t do_billing(switch_core_session_t *session) ...@@ -521,21 +542,31 @@ static switch_status_t do_billing(switch_core_session_t *session)
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failed to log to database!\n"); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Failed to log to database!\n");
} }
} else { } else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Just tried to bill %s negative minutes! That should be impossible.\n", if (switch_strlen_zero(billincrement))
uuid); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Just tried to bill %s negative minutes! That should be impossible.\n", uuid);
} }
/* Update the last time we billed */
nibble_data->lastts = ts;
/* Save this location */ /* Save this location */
if (channel) { if (channel) {
switch_channel_set_private(channel, "_nibble_data_", nibble_data); switch_channel_set_private(channel, "_nibble_data_", nibble_data);
/* don't verify balance and transfer to nobal if we're done with call */ /* don't verify balance and transfer to nobal if we're done with call */
if (switch_channel_get_state(channel) != CS_REPORTING && switch_channel_get_state(channel) != CS_HANGUP) { if (switch_channel_get_state(channel) != CS_REPORTING && switch_channel_get_state(channel) != CS_HANGUP) {
/* See if this person has enough money left to continue the call */
balance = get_balance(billaccount, channel); balance = get_balance(billaccount, channel);
/* See if we've achieved low balance */
if (!nibble_data->lowbal_action_executed && balance <= lowbal_amt) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Balance of %f fell below low balance amount of %f! (Account %s)\n",
balance, lowbal_amt, billaccount);
if (exec_app(session, globals.lowbal_action) != SWITCH_STATUS_SUCCESS)
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Low balance action didn't execute\n");
else
nibble_data->lowbal_action_executed = 1;
}
/* See if this person has enough money left to continue the call */
if (balance <= nobal_amt) { if (balance <= nobal_amt) {
/* Not enough money - reroute call to nobal location */ /* Not enough money - reroute call to nobal location */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Balance of %f fell below allowed amount of %f! (Account %s)\n", switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Balance of %f fell below allowed amount of %f! (Account %s)\n",
...@@ -665,7 +696,7 @@ static void nibblebill_resume(switch_core_session_t *session) ...@@ -665,7 +696,7 @@ static void nibblebill_resume(switch_core_session_t *session)
billrate = switch_channel_get_variable(channel, "nibble_rate"); billrate = switch_channel_get_variable(channel, "nibble_rate");
/* Calculate how much was "lost" to billings during pause - we do this here because you never know when the billrate may change during a call */ /* Calculate how much was "lost" to billings during pause - we do this here because you never know when the billrate may change during a call */
nibble_data->bill_adjustments += ((float) atof(billrate) / 1000000 / 60) * ((ts - nibble_data->pausets)); nibble_data->bill_adjustments += (atof(billrate) / 1000000 / 60) * ((ts - nibble_data->pausets));
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Resumed billing! Subtracted %f from this billing cycle.\n", switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Resumed billing! Subtracted %f from this billing cycle.\n",
(atof(billrate) / 1000000 / 60) * ((ts - nibble_data->pausets))); (atof(billrate) / 1000000 / 60) * ((ts - nibble_data->pausets)));
...@@ -711,11 +742,11 @@ static void nibblebill_reset(switch_core_session_t *session) ...@@ -711,11 +742,11 @@ static void nibblebill_reset(switch_core_session_t *session)
} }
} }
static float nibblebill_check(switch_core_session_t *session) static double nibblebill_check(switch_core_session_t *session)
{ {
switch_channel_t *channel = switch_core_session_get_channel(session); switch_channel_t *channel = switch_core_session_get_channel(session);
nibble_data_t *nibble_data; nibble_data_t *nibble_data;
float amount = 0; double amount = 0;
if (!channel) { if (!channel) {
return -99999; return -99999;
...@@ -744,7 +775,7 @@ static float nibblebill_check(switch_core_session_t *session) ...@@ -744,7 +775,7 @@ static float nibblebill_check(switch_core_session_t *session)
return amount; return amount;
} }
static void nibblebill_adjust(switch_core_session_t *session, float amount) static void nibblebill_adjust(switch_core_session_t *session, double amount)
{ {
switch_channel_t *channel = switch_core_session_get_channel(session); switch_channel_t *channel = switch_core_session_get_channel(session);
const char *billaccount; const char *billaccount;
...@@ -780,7 +811,7 @@ SWITCH_STANDARD_APP(nibblebill_app_function) ...@@ -780,7 +811,7 @@ SWITCH_STANDARD_APP(nibblebill_app_function)
if (!zstr(data) && (lbuf = strdup(data)) if (!zstr(data) && (lbuf = strdup(data))
&& (argc = switch_separate_string(lbuf, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) { && (argc = switch_separate_string(lbuf, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
if (!strcasecmp(argv[0], "adjust") && argc == 2) { if (!strcasecmp(argv[0], "adjust") && argc == 2) {
nibblebill_adjust(session, (float) atof(argv[1])); nibblebill_adjust(session, atof(argv[1]));
} else if (!strcasecmp(argv[0], "flush")) { } else if (!strcasecmp(argv[0], "flush")) {
do_billing(session); do_billing(session);
} else if (!strcasecmp(argv[0], "pause")) { } else if (!strcasecmp(argv[0], "pause")) {
...@@ -812,7 +843,7 @@ SWITCH_STANDARD_API(nibblebill_api_function) ...@@ -812,7 +843,7 @@ SWITCH_STANDARD_API(nibblebill_api_function)
char *uuid = argv[0]; char *uuid = argv[0];
if ((psession = switch_core_session_locate(uuid))) { if ((psession = switch_core_session_locate(uuid))) {
if (!strcasecmp(argv[1], "adjust") && argc == 3) { if (!strcasecmp(argv[1], "adjust") && argc == 3) {
nibblebill_adjust(psession, (float) atof(argv[2])); nibblebill_adjust(psession, atof(argv[2]));
} else if (!strcasecmp(argv[1], "flush")) { } else if (!strcasecmp(argv[1], "flush")) {
do_billing(psession); do_billing(psession);
} else if (!strcasecmp(argv[1], "pause")) { } else if (!strcasecmp(argv[1], "pause")) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论