diff --git a/ecallmgr/src/ecallmgr_call_command.erl b/ecallmgr/src/ecallmgr_call_command.erl index dc4eef0e814..036eca1cfb6 100644 --- a/ecallmgr/src/ecallmgr_call_command.erl +++ b/ecallmgr/src/ecallmgr_call_command.erl @@ -675,15 +675,7 @@ bridge_handle_ringback(Node, UUID, JObj) -> case wh_json:get_value(<<"Ringback">>, JObj) of 'undefined' -> case wh_json:get_value([<<"Custom-Channel-Vars">>, <<"Ringback">>], JObj) of - 'undefined' -> - case ecallmgr_fs_channel:import_moh(UUID) of - 'true' -> - [{"application", "export hold_music=${hold_music}"} - ,{"application", "set import=hold_music"} - |DP - ]; - 'false' -> DP - end; + 'undefined' -> 'ok'; Media -> Stream = ecallmgr_util:media_path(Media, extant, UUID, JObj), lager:debug("bridge has custom ringback in channel vars: ~s", [Stream]), @@ -712,7 +704,15 @@ bridge_handle_hold_media(DP, Node, UUID, JObj) -> case wh_json:get_value(<<"Hold-Media">>, JObj) of 'undefined' -> case wh_json:get_value([<<"Custom-Channel-Vars">>, <<"Hold-Media">>], JObj) of - 'undefined' -> DP; + 'undefined' -> + case ecallmgr_fs_channel:import_moh(UUID) of + 'true' -> + [{"application", "export hold_music=${hold_music}"} + ,{"application", "set import=hold_music"} + |DP + ]; + 'false' -> DP + end; Media -> Stream = ecallmgr_util:media_path(Media, extant, UUID, JObj), lager:debug("bridge has custom music-on-hold in channel vars: ~s", [Stream]), diff --git a/ecallmgr/src/ecallmgr_call_control.erl b/ecallmgr/src/ecallmgr_call_control.erl index dd09019a80f..0f0e642240d 100644 --- a/ecallmgr/src/ecallmgr_call_control.erl +++ b/ecallmgr/src/ecallmgr_call_control.erl @@ -283,7 +283,11 @@ handle_cast({channel_redirected, _}, #state{callid=CallId ,controller_q=ControllerQ }=State) -> lager:debug("call control has been redirected, shutting down immediately"), - spawn(fun() -> publish_control_transfer(ControllerQ, CallId) end), + ConsumerPid = wh_amqp_channel:consumer_pid(), + spawn(fun() -> + wh_amqp_channel:consumer_pid(ConsumerPid), + publish_control_transfer(ControllerQ, CallId) + end), {stop, normal, State}; handle_cast({transferer, _}, #state{last_removed_leg=undefined ,other_legs=[] @@ -298,7 +302,11 @@ handle_cast({transferer, _}, #state{callid=CallId ,controller_q=ControllerQ }=State) -> lager:debug("call control has been transfered"), - spawn(fun() -> publish_control_transfer(ControllerQ, CallId) end), + ConsumerPid = wh_amqp_channel:consumer_pid(), + spawn(fun() -> + wh_amqp_channel:consumer_pid(ConsumerPid), + publish_control_transfer(ControllerQ, CallId) + end), {stop, normal, State}; handle_cast({transferee, JObj}, #state{other_legs=Legs ,node=Node @@ -314,7 +322,11 @@ handle_cast({transferee, JObj}, #state{other_legs=Legs lager:debug("new callid is the same as the old callid"), {noreply, State}; NewCallId -> - spawn(fun() -> publish_callid_update(PrevCallId, NewCallId, queue_name(Self)) end), + ConsumerPid = wh_amqp_channel:consumer_pid(), + spawn(fun() -> + wh_amqp_channel:consumer_pid(ConsumerPid), + publish_callid_update(PrevCallId, NewCallId, queue_name(Self)) + end), lager:debug("updating callid from ~s to ~s", [PrevCallId, NewCallId]), put(callid, NewCallId), lager:debug("removing call event bindings for ~s", [PrevCallId]), @@ -350,8 +362,10 @@ handle_cast({add_leg, JObj}, #state{other_legs=Legs true -> {noreply, State}; false -> lager:debug("added leg ~s to call", [LegId]), + ConsumerPid = wh_amqp_channel:consumer_pid(), _ = spawn(fun() -> _ = put(callid, CallId), + wh_amqp_channel:consumer_pid(ConsumerPid), publish_leg_addition(JObj) end), {noreply, State#state{other_legs=[LegId|Legs]}} @@ -370,8 +384,10 @@ handle_cast({rm_leg, JObj}, #state{other_legs=Legs {noreply, State}; true -> lager:debug("removed leg ~s from call", [LegId]), + ConsumerPid = wh_amqp_channel:consumer_pid(), _ = spawn(fun() -> put(callid, CallId), + wh_amqp_channel:consumer_pid(ConsumerPid), publish_leg_removal(JObj) end), {noreply, State#state{other_legs=lists:delete(LegId, Legs) diff --git a/lib/whistle-1.0.0/src/wh_util.erl b/lib/whistle-1.0.0/src/wh_util.erl index 8c5e8d38141..92a17e976de 100644 --- a/lib/whistle-1.0.0/src/wh_util.erl +++ b/lib/whistle-1.0.0/src/wh_util.erl @@ -690,7 +690,7 @@ a1hash(User, Realm, Password) -> -spec floor(integer() | float()) -> integer(). floor(X) when X < 0 -> T = trunc(X), - case X - T =:= 0 of + case X - T == 0 of 'true' -> T; 'false' -> T - 1 end; @@ -701,7 +701,7 @@ floor(X) -> trunc(X). ceiling(X) when X < 0 -> trunc(X); ceiling(X) -> T = trunc(X), - case X - T =:= 0 of + case X - T == 0 of 'true' -> T; 'false' -> T + 1 end. diff --git a/lib/whistle_transactions-1.0.0/src/wh_transaction.erl b/lib/whistle_transactions-1.0.0/src/wh_transaction.erl index cc7bfb686a4..4535262546b 100644 --- a/lib/whistle_transactions-1.0.0/src/wh_transaction.erl +++ b/lib/whistle_transactions-1.0.0/src/wh_transaction.erl @@ -19,6 +19,7 @@ -export([number/1]). -export([feature/1]). -export([bookkeeper_info/1]). +-export([metadata/1]). -export([reason/1]). -export([code/1]). -export([amount/1]). @@ -34,6 +35,7 @@ -export([set_number/2]). -export([set_feature/2]). -export([set_bookkeeper_info/2]). +-export([set_metadata/2]). -export([set_description/2]). -export([set_call_id/2]). -export([set_sub_account_id/2]). @@ -53,6 +55,7 @@ ,number :: api_binary() ,feature :: api_binary() ,bookkeeper_info :: 'undefined' | wh_json:object() + ,metadata :: 'undefined' | wh_json:object() ,pvt_reason :: ne_binary() ,pvt_code :: non_neg_integer() ,pvt_amount :: non_neg_integer() @@ -139,6 +142,15 @@ feature(#wh_transaction{feature=Feature}) -> bookkeeper_info(#wh_transaction{bookkeeper_info=BookkeeperInfo}) -> BookkeeperInfo. +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% +%% @end +%%-------------------------------------------------------------------- +metadata(#wh_transaction{metadata=MetaData}) -> + MetaData. + %%-------------------------------------------------------------------- %% @public %% @doc @@ -283,6 +295,16 @@ set_feature(Feature, #wh_transaction{}=Transaction) -> set_bookkeeper_info(BookkeeperInfo, #wh_transaction{}=Transaction) -> Transaction#wh_transaction{bookkeeper_info=BookkeeperInfo}. +%%-------------------------------------------------------------------- +%% @public +%% @doc +%% +%% @end +%%-------------------------------------------------------------------- +set_metadata(MetaData, #wh_transaction{}=Transaction) -> + Transaction#wh_transaction{metadata=MetaData}. + + %%-------------------------------------------------------------------- %% @public %% @doc @@ -344,6 +366,7 @@ to_json(#wh_transaction{}=T) -> ,{<<"number">>, T#wh_transaction.number} ,{<<"feature">>, T#wh_transaction.feature} ,{<<"bookkeeper_info">>, T#wh_transaction.bookkeeper_info} + ,{<<"metadata">>, T#wh_transaction.metadata} ,{<<"pvt_reason">>, T#wh_transaction.pvt_reason} ,{<<"pvt_code">>, T#wh_transaction.pvt_code} ,{<<"pvt_amount">>, T#wh_transaction.pvt_amount} @@ -423,6 +446,7 @@ from_json(JObj) -> ,number = wh_json:get_ne_value(<<"number">>, JObj) ,feature = wh_json:get_ne_value(<<"feature">>, JObj) ,bookkeeper_info = wh_json:get_ne_value(<<"bookkeeper_info">>, JObj) + ,metadata = wh_json:get_ne_value(<<"metadata">>, JObj) ,pvt_reason = wh_json:get_ne_value(<<"pvt_reason">>, JObj) ,pvt_code = wh_json:get_integer_value(<<"pvt_code">>, JObj, 0) ,pvt_amount = wh_json:get_integer_value(<<"pvt_amount">>, JObj, 0) diff --git a/lib/whistle_transactions-1.0.0/src/wh_transactions.erl b/lib/whistle_transactions-1.0.0/src/wh_transactions.erl index d164aa40c9e..402d4c786ef 100644 --- a/lib/whistle_transactions-1.0.0/src/wh_transactions.erl +++ b/lib/whistle_transactions-1.0.0/src/wh_transactions.erl @@ -15,7 +15,7 @@ ,call_charges/4 ]). -export([filter_by_reason/2]). --export([fetch_since/2]). +-export([fetch_since/3]). -export([fetch_last/2]). -export([save/1]). -export([remove/1]). @@ -150,17 +150,16 @@ fetch_last(AccountId, Count) -> %% fetch last transaction from date to now %% @end %%-------------------------------------------------------------------- --spec fetch_since(ne_binary(), integer()) -> wh_transactions(). -fetch_since(AccountId, Date) -> +-spec fetch_since(ne_binary(), integer(), integer()) -> wh_transactions(). +fetch_since(AccountId, From, To) -> AccountDB = wh_util:format_account_id(AccountId, 'encoded'), - Now = wh_util:current_tstamp(), - ViewOptions = [{'startkey', Date} - ,{'endkey', Now} + ViewOptions = [{'startkey', From} + ,{'endkey', To} ,'include_docs' ], case couch_mgr:get_results(AccountDB, <<"transactions/by_timestamp">>, ViewOptions) of {'ok', []} -> - lager:debug("no transactions for that range from ~p to ~p on ~p", [Date, Now, AccountId]), + lager:debug("no transactions for that range from ~p to ~p on ~p", [From, To, AccountId]), []; {'ok', ViewRes} -> viewres_to_recordlist(ViewRes) diff --git a/lib/whistle_transactions-1.0.0/src/wht_util.erl b/lib/whistle_transactions-1.0.0/src/wht_util.erl index 1988db0aaaf..31740428b56 100644 --- a/lib/whistle_transactions-1.0.0/src/wht_util.erl +++ b/lib/whistle_transactions-1.0.0/src/wht_util.erl @@ -282,6 +282,7 @@ collapse_call_transaction(CallId, JObj, Calls) -> Routines = [fun(C) -> collapse_created_time(C, JObj) end ,fun(C) -> collapse_ended_time(C, JObj) end ,fun(C) -> collapse_amount(C, JObj) end + ,fun(C) -> collapse_metadata(C, JObj) end ], C = lists:foldl(fun(F, C) -> F(C) end, Call, Routines), dict:store(CallId, C, Calls) @@ -328,6 +329,27 @@ collapse_amount(Call, JObj) -> CurrentAmount = wh_json:get_value(<<"amount">>, Call, 0), MaybeAmount = get_amount(JObj), wh_json:set_value(<<"amount">>, MaybeAmount+CurrentAmount, Call). + + +%%-------------------------------------------------------------------- +%% @private +%% @doc +%% +%% @end +%%-------------------------------------------------------------------- +-spec collapse_metadata(wh_json:object(), [wh_json:object(), ...]) -> wh_json:object(). +collapse_metadata(Call, JObj) -> + case wh_json:get_value(<<"metadata">>, Call, 'undefined') of + 'undefined' -> + case wh_json:get_value(<<"metadata">>, JObj, 'undefined') of + 'undefined' -> + Call; + MetaData -> + wh_json:set_value(<<"metadata">>, MetaData, Call) + end; + _ -> + Call + end. %%-------------------------------------------------------------------- %% @private diff --git a/whistle_apps/apps/crossbar/priv/couchdb/account/cdrs.json b/whistle_apps/apps/crossbar/priv/couchdb/account/cdrs.json index 3204ded16a5..9194c6ee189 100644 --- a/whistle_apps/apps/crossbar/priv/couchdb/account/cdrs.json +++ b/whistle_apps/apps/crossbar/priv/couchdb/account/cdrs.json @@ -3,7 +3,7 @@ "language": "javascript", "views": { "crossbar_listing": { - "map": "function (doc) {if (doc.pvt_deleted || doc.pvt_type != 'cdr') return;if (doc.pvt_type == 'cdr' && doc.custom_channel_vars && (doc.custom_channel_vars.account_billing == 'per_minute' || doc.custom_channel_vars.account_billing == 'per_minute_limit') && doc.custom_channel_vars.account_id == doc.pvt_account_id && doc.pvt_vsn && parseInt(doc.pvt_vsn) == 2) {var Secs = (parseInt(doc.billing_seconds) || 0) - (parseInt(doc.custom_channel_vars.billing_seconds_offset) || 0);var Cost = 0;if (Secs >= 1) {var R = parseInt(doc.custom_channel_vars.rate) || 0;var RInc = parseInt(doc.custom_channel_vars.increment) || 60;var RMin = parseInt(doc.custom_channel_vars.rate_minimum) || 0;var Sur = parseInt(doc.custom_channel_vars.surcharge) || 0;if (RInc < 1) {RInc = 60;}if (Secs <= RMin) {Cost = Sur + ((RMin / 60) * R);} else {Cost = Sur + ((RMin / 60) * R) + (Math.ceil((Secs - RMin) / RInc) * ((RInc / 60) * R));}}}if (Cost) {var Discount = (parseInt(doc.custom_channel_vars.discount_percentage) || 0) * 0.01 * Cost;emit(doc.pvt_created, {id: doc._id,caller_id_name: doc.caller_id_name,caller_id_number: doc.caller_id_number,callee_id_name: doc.callee_id_name,callee_id_number: doc.callee_id_number,duration_seconds: doc.duration_seconds,billing_seconds: doc.billing_seconds,timestamp: doc.timestamp,hangup_cause: doc.hangup_cause,other_leg_call_id: doc.other_leg_call_id,owner_id: doc.custom_channel_vars.owner_id,to: doc.to_uri,from: doc.from_uri,inception: doc.custom_channel_vars.inception,cost: Cost - Discount});} else {emit(doc.pvt_created, {id: doc._id,caller_id_name: doc.caller_id_name,caller_id_number: doc.caller_id_number,callee_id_name: doc.callee_id_name,callee_id_number: doc.callee_id_number,duration_seconds: doc.duration_seconds,billing_seconds: doc.billing_seconds,timestamp: doc.timestamp,hangup_cause: doc.hangup_cause,other_leg_call_id: doc.other_leg_call_id,owner_id: doc.custom_channel_vars.owner_id,to: doc.to_uri,from: doc.from_uri,inception: doc.custom_channel_vars.inception});}}" + "map": "function (doc) {if (doc.pvt_deleted || doc.pvt_type != 'cdr') return;if (doc.pvt_type == 'cdr' && doc.custom_channel_vars && (doc.custom_channel_vars.account_billing == 'per_minute' || doc.custom_channel_vars.account_billing == 'per_minute_limit') && doc.custom_channel_vars.account_id == doc.pvt_account_id && doc.pvt_vsn && parseInt(doc.pvt_vsn) == 2) {var Secs = (parseInt(doc.billing_seconds) || 0) - (parseInt(doc.custom_channel_vars.billing_seconds_offset) || 0);var Cost = 0;if (Secs >= 1) {var R = parseInt(doc.custom_channel_vars.rate) || 0;var RInc = parseInt(doc.custom_channel_vars.rate_increment) || 60;var RMin = parseInt(doc.custom_channel_vars.rate_minimum) || 0;var Sur = parseInt(doc.custom_channel_vars.surcharge) || 0;if (RInc < 1) {RInc = 60;}if (Secs <= RMin) {Cost = Sur + ((RMin / 60) * R);} else {Cost = Sur + ((RMin / 60) * R) + (Math.ceil((Secs - RMin) / RInc) * ((RInc / 60) * R));}}}if (Cost) {var Discount = (parseInt(doc.custom_channel_vars.discount_percentage) || 0) * 0.01 * Cost;emit(doc.pvt_created, {id: doc._id,caller_id_name: doc.caller_id_name,caller_id_number: doc.caller_id_number,callee_id_name: doc.callee_id_name,callee_id_number: doc.callee_id_number,duration_seconds: doc.duration_seconds,billing_seconds: doc.billing_seconds,timestamp: doc.timestamp,hangup_cause: doc.hangup_cause,other_leg_call_id: doc.other_leg_call_id,owner_id: doc.custom_channel_vars.owner_id,to: doc.to_uri,from: doc.from_uri,inception: doc.custom_channel_vars.inception,cost: Cost - Discount});} else {emit(doc.pvt_created, {id: doc._id,caller_id_name: doc.caller_id_name,caller_id_number: doc.caller_id_number,callee_id_name: doc.callee_id_name,callee_id_number: doc.callee_id_number,duration_seconds: doc.duration_seconds,billing_seconds: doc.billing_seconds,timestamp: doc.timestamp,hangup_cause: doc.hangup_cause,other_leg_call_id: doc.other_leg_call_id,owner_id: doc.custom_channel_vars.owner_id,to: doc.to_uri,from: doc.from_uri,inception: doc.custom_channel_vars.inception});}}" }, "listing_by_owner" : { "map": "function(doc) { if(doc.pvt_deleted || !doc.custom_channel_vars.owner_id || doc.pvt_type != 'cdr') return; emit([doc.custom_channel_vars.owner_id, doc.pvt_created], {'id':doc._id, 'caller_id_name': doc.caller_id_name, 'caller_id_number': doc.caller_id_number, 'callee_id_name': doc.callee_id_name, 'callee_id_number': doc.callee_id_number, 'duration_seconds': doc.duration_seconds, 'timestamp': doc.timestamp, 'hangup_cause':doc.hangup_cause, 'other_leg_call_id':doc.other_leg_call_id, 'call_direction':doc.call_direction, 'to': doc.to_uri, 'from': doc.from_uri, 'inception':doc.custom_channel_vars.inception})}" diff --git a/whistle_apps/apps/crossbar/priv/couchdb/account/transactions.json b/whistle_apps/apps/crossbar/priv/couchdb/account/transactions.json index d5bb3c5ea47..dd4c3748286 100644 --- a/whistle_apps/apps/crossbar/priv/couchdb/account/transactions.json +++ b/whistle_apps/apps/crossbar/priv/couchdb/account/transactions.json @@ -18,7 +18,7 @@ "map": "function(doc) { if ( (doc.pvt_type != 'credit' && doc.pvt_type != 'debit') || doc.pvt_deleted) return; emit(doc.pvt_created, doc._id); }" }, "reconcile_by_callid": { - "map": "function (doc) {if (doc.pvt_deleted || (doc.pvt_type != 'cdr' && doc.pvt_type != 'credit' && doc.pvt_type != 'debit') || !doc.pvt_vsn || parseInt(doc.pvt_vsn) != 2) return;if (doc.pvt_type == 'cdr' && doc.custom_channel_vars && (doc.custom_channel_vars.account_billing == 'per_minute' || doc.custom_channel_vars.account_billing == 'per_minute_limit') && doc.custom_channel_vars.account_id == doc.pvt_account_id) {var Secs = (parseInt(doc.billing_seconds) || 0) - (parseInt(doc.custom_channel_vars.billing_seconds_offset) || 0);var Cost = 0;if (Secs >= 1) {var R = parseInt(doc.custom_channel_vars.rate) || 0;var RInc = parseInt(doc.custom_channel_vars.increment) || 60;var RMin = parseInt(doc.custom_channel_vars.rate_minimum) || 0;var Sur = parseInt(doc.custom_channel_vars.surcharge) || 0;if (RInc < 1) {RInc = 60;}if (Secs <= RMin) {Cost = Sur + ((RMin / 60) * R);} else {Cost = Sur + ((RMin / 60) * R) + (Math.ceil((Secs - RMin) / RInc) * ((RInc / 60) * R));}}if (Cost) {var Discount = (parseInt(doc.custom_channel_vars.discount_percentage) || 0) * 0.01 * Cost;emit(doc._id, Cost - Discount);}} else if (doc.pvt_code && parseInt(doc.pvt_code) == 1001 && doc.call_id) {var modifier = (doc.pvt_type == 'credit' ? 1 : -1);var amount = doc.pvt_amount;emit(doc.call_id, amount * modifier);}}", + "map": "function (doc) {if (doc.pvt_deleted || (doc.pvt_type != 'cdr' && doc.pvt_type != 'credit' && doc.pvt_type != 'debit') || !doc.pvt_vsn || parseInt(doc.pvt_vsn) != 2) return;if (doc.pvt_type == 'cdr' && doc.custom_channel_vars && (doc.custom_channel_vars.account_billing == 'per_minute' || doc.custom_channel_vars.account_billing == 'per_minute_limit') && doc.custom_channel_vars.account_id == doc.pvt_account_id) {var Secs = (parseInt(doc.billing_seconds) || 0) - (parseInt(doc.custom_channel_vars.billing_seconds_offset) || 0);var Cost = 0;if (Secs >= 1) {var R = parseInt(doc.custom_channel_vars.rate) || 0;var RInc = parseInt(doc.custom_channel_vars.rate_increment) || 60;var RMin = parseInt(doc.custom_channel_vars.rate_minimum) || 0;var Sur = parseInt(doc.custom_channel_vars.surcharge) || 0;if (RInc < 1) {RInc = 60;}if (Secs <= RMin) {Cost = Sur + ((RMin / 60) * R);} else {Cost = Sur + ((RMin / 60) * R) + (Math.ceil((Secs - RMin) / RInc) * ((RInc / 60) * R));}}if (Cost) {var Discount = (parseInt(doc.custom_channel_vars.discount_percentage) || 0) * 0.01 * Cost;emit(doc._id, Cost - Discount);}} else if (doc.pvt_code && parseInt(doc.pvt_code) == 1001 && doc.call_id) {var modifier = (doc.pvt_type == 'credit' ? 1 : -1);var amount = doc.pvt_amount;emit(doc.call_id, amount * modifier);}}", "reduce": "_sum" } } diff --git a/whistle_apps/apps/crossbar/src/modules/cb_transactions.erl b/whistle_apps/apps/crossbar/src/modules/cb_transactions.erl index 770fa5dfbdb..d0cc39ff28a 100644 --- a/whistle_apps/apps/crossbar/src/modules/cb_transactions.erl +++ b/whistle_apps/apps/crossbar/src/modules/cb_transactions.erl @@ -16,6 +16,10 @@ -include("src/crossbar.hrl"). +%%-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). +%%-endif. + %% 1 month -define(FETCH_DEFAULT, 60*60*24*30). %% 1 year @@ -34,9 +38,9 @@ %%-------------------------------------------------------------------- -spec init/0 :: () -> 'ok'. init() -> - _ = crossbar_bindings:bind(<<"v1_resource.allowed_methods.transactions">>, ?MODULE, allowed_methods), - _ = crossbar_bindings:bind(<<"v1_resource.resource_exists.transactions">>, ?MODULE, resource_exists), - crossbar_bindings:bind(<<"v1_resource.validate.transactions">>, ?MODULE, validate). + _ = crossbar_bindings:bind(<<"v1_resource.allowed_methods.transactions">>, ?MODULE, 'allowed_methods'), + _ = crossbar_bindings:bind(<<"v1_resource.resource_exists.transactions">>, ?MODULE, 'resource_exists'), + crossbar_bindings:bind(<<"v1_resource.validate.transactions">>, ?MODULE, 'validate'). %%-------------------------------------------------------------------- %% @public @@ -63,8 +67,8 @@ allowed_methods(_) -> %%-------------------------------------------------------------------- -spec resource_exists/0 :: () -> 'true'. -spec resource_exists/1 :: (path_token()) -> 'true'. -resource_exists() -> true. -resource_exists(_) -> true. +resource_exists() -> 'true'. +resource_exists(_) -> 'true'. %%-------------------------------------------------------------------- %% @public @@ -79,14 +83,15 @@ resource_exists(_) -> true. -spec validate/1 :: (#cb_context{}) -> #cb_context{}. -spec validate/2 :: (#cb_context{}, path_token()) -> #cb_context{}. validate(#cb_context{req_verb = <<"get">>, query_json=Query}=Context) -> - From = wh_json:get_value(<<"created_from">>, Query, undefined), - Reason = wh_json:get_value(<<"reason">>, Query, undefined), + From = wh_json:get_integer_value(<<"created_from">>, Query, 0), + To = wh_json:get_integer_value(<<"created_to">>, Query, 0), + Reason = wh_json:get_value(<<"reason">>, Query, 'undefined'), case Reason of <<"no_call">> -> Reasons = wht_util:reasons(2000), - fetch(From, Context, Reasons); + fetch(From, To, Context, Reasons); _ -> - fetch(From, Context) + fetch(From, To, Context) end. validate(#cb_context{req_verb = <<"get">>, account_id=AccountId}=Context, <<"current_balance">>) -> @@ -94,7 +99,7 @@ validate(#cb_context{req_verb = <<"get">>, account_id=AccountId}=Context, <<"cur JObj = wh_json:from_list([{<<"balance">>, Balance}]), Context#cb_context{resp_status=success, resp_data=JObj}; validate(Context, _) -> - cb_context:add_system_error(bad_identifier, Context). + cb_context:add_system_error('bad_identifier', Context). %%-------------------------------------------------------------------- @@ -103,31 +108,25 @@ validate(Context, _) -> %% %% @end %%-------------------------------------------------------------------- --spec fetch/2 :: (integer(), #cb_context{}) -> #cb_context{}. --spec fetch/3 :: (integer(), #cb_context{}, ne_binary()) -> #cb_context{}. -fetch(From, Context) -> - case validate_date(From) of - {true, Date} -> - filter(Date, Context); - {false, undefined} -> - Month = (wh_util:current_tstamp() - ?FETCH_DEFAULT), - filter(Month, Context); - {false, R} -> - cb_context:add_validation_error(<<"created_from">> +-spec fetch/3 :: (integer(), integer(), #cb_context{}) -> #cb_context{}. +-spec fetch/4 :: (integer(), integer(), #cb_context{}, ne_binary()) -> #cb_context{}. +fetch(From, To, Context) -> + case validate_date(From, To) of + {'true', VFrom, VTo} -> + filter(VFrom, VTo, Context); + {'false', R} -> + cb_context:add_validation_error(<<"created_from/created_to">> ,<<"date_range">> ,R ,Context ) end. -fetch(From, Context, Reason) -> - case validate_date(From) of - {true, Date} -> - filter(Date, Context, Reason); - {false, undefined} -> - Month = (wh_util:current_tstamp() - ?FETCH_DEFAULT), - filter(Month, Context, Reason); - {false, R} -> - cb_context:add_validation_error(<<"created_from">> +fetch(From, To, Context, Reason) -> + case validate_date(From, To) of + {'true', VFrom, VTo} -> + filter(VFrom, VTo, Context, Reason); + {'false', R} -> + cb_context:add_validation_error(<<"created_from/created_to">> ,<<"date_range">> ,R ,Context @@ -140,24 +139,24 @@ fetch(From, Context, Reason) -> %% %% @end %%-------------------------------------------------------------------- --spec filter/2 :: (integer(), cb_context:context()) -> cb_context:context(). --spec filter/3 :: (integer(), #cb_context{}, ne_binary()) -> #cb_context{}. -filter(Date, #cb_context{account_id=AccountId}=Context) -> - try wh_transactions:fetch_since(AccountId, Date) of +-spec filter/3 :: (integer(), integer(), cb_context:context()) -> cb_context:context(). +-spec filter/4 :: (integer(), integer(), #cb_context{}, ne_binary()) -> #cb_context{}. +filter(From, To, #cb_context{account_id=AccountId}=Context) -> + try wh_transactions:fetch_since(AccountId, From, To) of Transactions -> - send_resp({ok, Transactions}, Context) + send_resp({'ok', Transactions}, Context) catch _:_ -> - send_resp({error, Context}, Context) + send_resp({'error', Context}, Context) end. -filter(Date, #cb_context{account_id=AccountId}=Context, Reason) -> - try wh_transactions:fetch_since(AccountId, Date) of +filter(From, To, #cb_context{account_id=AccountId}=Context, Reason) -> + try wh_transactions:fetch_since(AccountId, From, To) of Transactions -> Filtered = wh_transactions:filter_by_reason(Reason, Transactions), - send_resp({ok, Filtered}, Context) + send_resp({'ok', Filtered}, Context) catch _:_ -> - send_resp({error, Context}, Context) + send_resp({'error', Context}, Context) end. %%-------------------------------------------------------------------- @@ -168,13 +167,13 @@ filter(Date, #cb_context{account_id=AccountId}=Context, Reason) -> %%-------------------------------------------------------------------- send_resp(Resp, Context) -> case Resp of - {ok, Transactions} -> - JObj = wh_transactions:to_public_json(Transactions), + {'ok', Transactions} -> + JObj = wh_transactions:to_public_json(Transactions), Context#cb_context{resp_status=success ,resp_data=wht_util:collapse_call_transactions(JObj) }; - {error, C} -> - cb_context:add_system_error(bad_identifier, [{details,<<"something went wrong while fetching the transaction">>}], C) + {'error', C} -> + cb_context:add_system_error('bad_identifier', [{'details',<<"something went wrong while fetching the transaction">>}], C) end. @@ -184,26 +183,46 @@ send_resp(Resp, Context) -> %% %% @end %%-------------------------------------------------------------------- --spec validate_date/1 :: (any()) -> {true, integer()} | {false, 0} | {false, ne_binary()}. -validate_date(undefined) -> - {false, undefined}; -validate_date(Date) when is_integer(Date) -> - Now = wh_util:current_tstamp(), +-spec validate_date/2 :: (any(), any()) -> {true, integer(), integer()} | {false, ne_binary()}. +validate_date(0, 0) -> + validate_date(wh_util:current_tstamp()-?FETCH_DEFAULT, wh_util:current_tstamp()); +validate_date(0, To) -> + validate_date(To-?FETCH_DEFAULT, To); +validate_date(From, 0) -> + validate_date(From, From+?FETCH_DEFAULT); +validate_date(From, To) when is_integer(From) andalso is_integer(To) -> Max = ?FETCH_MAX, - Diff = Now - Date, + Diff = To - From, case {Diff < 0, Diff > Max} of - {true, _} -> - {false, <<"created_from is gretter than current timestamp">>}; - {_, true} -> - {false, <<"Max range is a year from now">>}; - {false, false} -> - {true, Date} + {'true', _} -> + {'false', <<"created_from is gretter than created_to">>}; + {_, 'true'} -> + {'false', <<"Max range is a year">>}; + {'false', 'false'} -> + {'true', From, To} end; -validate_date(Date) -> - try wh_util:to_integer(Date) of - Date1 -> - validate_date(Date1) +validate_date(From, To) -> + try {wh_util:to_integer(From), wh_util:to_integer(To)} of + {From1, To1} -> + validate_date(From1, To1) catch _:_ -> - {false, <<"created_from filter is not a timestamp">>} + {'false', <<"created_from or created_to filter is not a timestamp">>} end. + +-ifdef(TEST). + +validate_date_test() -> + Tstamp = wh_util:current_tstamp(), + MaxFrom = Tstamp - ?FETCH_DEFAULT, + MaxTo = Tstamp + ?FETCH_DEFAULT, + ?assertMatch({'true', _, _}, validate_date(0, 0)), + ?assertMatch({'true', MaxFrom, Tstamp}, validate_date(0, Tstamp)), + ?assertMatch({'true', Tstamp, MaxTo}, validate_date(Tstamp, 0)), + T1 = Tstamp + 10, + ?assertMatch({'true', Tstamp, T1}, validate_date(Tstamp, T1)), + ?assertMatch({'false', _}, validate_date(T1, Tstamp)), + T2 = Tstamp + ?FETCH_MAX + 1, + ?assertMatch({'false', _}, validate_date(Tstamp, T2)). + +-endif. diff --git a/whistle_apps/apps/crossbar/src/modules/provisioner_util.erl b/whistle_apps/apps/crossbar/src/modules/provisioner_util.erl index 4989795ab7a..a2bf1b808e2 100644 --- a/whistle_apps/apps/crossbar/src/modules/provisioner_util.erl +++ b/whistle_apps/apps/crossbar/src/modules/provisioner_util.erl @@ -334,7 +334,6 @@ send_to_full_provisioner(PartialURL) -> lager:debug("making ~s request to ~s", ['delete', FullUrl]), Res = ibrowse:send_req(FullUrl, Headers, 'delete', [], [{inactivity_timeout, 10000}]), lager:debug("response from server: ~p", [Res]), - io:format("MACPIE ~p~n", [Res]), true end. diff --git a/whistle_apps/apps/jonny5/src/j5_credit.erl b/whistle_apps/apps/jonny5/src/j5_credit.erl index 5f60d92d5ff..70f3f9fc64d 100644 --- a/whistle_apps/apps/jonny5/src/j5_credit.erl +++ b/whistle_apps/apps/jonny5/src/j5_credit.erl @@ -106,6 +106,14 @@ create_debit_transaction(Event, Units, LedgerId, JObj) -> ,fun(T) -> wh_transaction:set_description(<<"per minute call">>, T) end + ,fun(T) -> + case Event of + <<"end">> -> + wh_transaction:set_metadata(set_metadata(JObj), T); + _ -> + T + end + end ], T = lists:foldl(fun(F, T) -> F(T) end, wh_transaction:debit(LedgerId, Units), Routines), wh_transaction:save(T). @@ -127,10 +135,27 @@ create_credit_transaction(Event, Units, LedgerId, JObj) -> ,fun(T) -> wh_transaction:set_description(<<"per minute call">>, T) end + ,fun(T) -> + case Event of + <<"end">> -> + wh_transaction:set_metadata(set_metadata(JObj), T); + _ -> + T + end + end ], T = lists:foldl(fun(F, T) -> F(T) end, wh_transaction:credit(LedgerId, Units), Routines), wh_transaction:save(T). +set_metadata(JObj) -> + wh_json:set_values([{<<"direction">>, wh_json:get_value(<<"Call-Direction">>, JObj, 'undefined')} + ,{<<"duration">>, wh_json:get_value(<<"Billing-Seconds">>, JObj, 'undefined')} + ,{<<"account_id">>, wh_json:get_value([<<"Custom-Channel-Vars">>, <<"Account-ID">>], JObj, 'undefined')} + ,{<<"to">>, wh_json:get_value(<<"Callee-ID-Number">>, JObj, 'undefined')} + ,{<<"from">>, wh_json:get_value(<<"Caller-ID-Number">>, JObj, 'undefined')} + ] + ,wh_json:new()). + get_authz_account_id(JObj) -> wh_json:get_value([<<"Custom-Channel-Vars">>, <<"Account-ID">>], JObj).