mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-07-14 11:06:36 +00:00
FS-3950 --resolve nibblebill changes!
This commit is contained in:
parent
842203f78f
commit
9bf2726e1b
@ -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 {
|
|||||||
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
|
|||||||
|
|
||||||
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)
|
|||||||
} 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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
|||||||
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
|
|||||||
|
|
||||||
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
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
/* 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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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")) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user