Permalink
Browse files

WHISTLE-1217: refactor whistle_service to draw from a services db

  • Loading branch information...
1 parent d9d2256 commit bb3d8a84c7b1523a7c7c2690781c42f68f7d2aa2 @k-anderson k-anderson committed Jul 27, 2012
Showing with 326 additions and 1,551 deletions.
  1. +35 −0 lib/whistle-1.0.0/src/wh_util.erl
  2. +1 −1 lib/whistle_number_manager-1.0.0/include/wh_number_manager.hrl
  3. +31 −53 lib/whistle_number_manager-1.0.0/src/wnm_util.erl
  4. +0 −755 lib/whistle_service-1.0.0/src/wh_reseller.erl
  5. +0 −165 lib/whistle_service-1.0.0/src/wh_resellers.erl
  6. +0 −9 lib/whistle_service-1.0.0/src/wh_service.erl
  7. +0 −11 lib/whistle_service-1.0.0/src/wh_service.hrl
  8. +0 −53 lib/whistle_service-1.0.0/src/wh_service_devices.erl
  9. +0 −31 lib/whistle_service-1.0.0/src/wh_service_limits.erl
  10. +0 −86 lib/whistle_service-1.0.0/src/wh_service_numbers.erl
  11. +0 −231 lib/whistle_service-1.0.0/src/wh_service_plan.erl
  12. +0 −12 lib/whistle_service-1.0.0/src/whistle_service.app.src
  13. +0 −141 lib/whistle_service-1.0.0/src/whistle_service_maintenance.erl
  14. 0 lib/{whistle_service-1.0.0 → whistle_services-1.0.0}/Makefile
  15. 0 lib/{whistle_service-1.0.0 → whistle_services-1.0.0}/doc/README.org
  16. 0 lib/{whistle_service-1.0.0 → whistle_services-1.0.0}/include/wh_service.hrl
  17. 0 lib/{whistle_service-1.0.0 → whistle_services-1.0.0}/priv/example_service_plan.json
  18. 0 lib/{whistle_service-1.0.0 → whistle_services-1.0.0}/rebar.config
  19. +31 −0 lib/whistle_services-1.0.0/src/services/wh_service_devices.erl
  20. +33 −0 lib/whistle_services-1.0.0/src/services/wh_service_limits.erl
  21. +57 −0 lib/whistle_services-1.0.0/src/services/wh_service_phone_numbers.erl
  22. +109 −0 lib/whistle_services-1.0.0/src/wh_services.erl
  23. +12 −0 lib/whistle_services-1.0.0/src/whistle_services.app.src
  24. +4 −0 lib/whistle_services-1.0.0/src/whistle_services.hrl
  25. +2 −2 ..._service-1.0.0/src/whistle_service_app.erl → whistle_services-1.0.0/src/whistle_services_app.erl}
  26. +1 −1 ..._service-1.0.0/src/whistle_service_sup.erl → whistle_services-1.0.0/src/whistle_services_sup.erl}
  27. +10 −0 whistle_apps/apps/crossbar/priv/couchdb/account/services.json
View
35 lib/whistle-1.0.0/src/wh_util.erl
@@ -15,6 +15,8 @@
-export([get_account_realm/1, get_account_realm/2]).
-export([is_account_enabled/1]).
+-export([try_load_module/1]).
+
-export([to_integer/1, to_integer/2
,to_float/1, to_float/2
,to_number/1
@@ -243,6 +245,39 @@ get_hostname() ->
%%--------------------------------------------------------------------
%% @public
%% @doc
+%% Given a module name try to verify its existance, loading it into the
+%% the vm if possible.
+%% @end
+%%--------------------------------------------------------------------
+-spec try_load_module/1 :: (string() | binary()) -> atom() | false.
+try_load_module(Name) ->
+ try to_atom(Name) of
+ Module ->
+ case erlang:module_loaded(Module) of
+ true -> Module;
+ false ->
+ {module, Module} = code:ensure_loaded(Module),
+ Module
+ end
+ catch
+ error:badarg ->
+ lager:debug("module ~s not found", [Name]),
+ case code:where_is_file(to_list(<<(to_binary(Name))/binary, ".beam">>)) of
+ non_existing ->
+ lager:debug("beam file not found for ~s", [Name]),
+ false;
+ _Path ->
+ lager:debug("beam file found: ~s", [_Path]),
+ to_atom(Name, true), %% put atom into atom table
+ try_load_module(Name)
+ end;
+ _:_ ->
+ false
+ end.
+
+%%--------------------------------------------------------------------
+%% @public
+%% @doc
%% Ensure a binary is a minimum size, padding it if not with a given
%% value.
%% @end
View
2 lib/whistle_number_manager-1.0.0/include/wh_number_manager.hrl
@@ -13,7 +13,7 @@
-define(WNM_USER_AGENT, "Whistle Number Manager 1.0.0").
--define(WNM_DEAFULT_TOLLFREE_RE, "^(\\+?1)?(8[1-4,9]\\d{8}|80[1-9]\\d{7}|85[1-4,6-9]\\d{7}|86[1-5,7-9]\\d{7}|87[1-6,8-9]\\d{7}|88[1-7,9]\\d{7}|([1-7,9]\\d{9}))$").
+-define(WNM_DEAFULT_TOLLFREE_RE, <<"^\\+1(800|888|877|866|855)\\d{7}$">>).
-define(WNM_PHONE_NUMBER_DOC, <<"phone_numbers">>).
View
84 lib/whistle_number_manager-1.0.0/src/wnm_util.erl
@@ -9,11 +9,10 @@
%%%-------------------------------------------------------------------
-module(wnm_util).
--export([is_tollfree/1]).
+-export([classify_number/1]).
-export([is_reconcilable/1]).
-export([list_carrier_modules/0]).
-export([get_carrier_module/1]).
--export([try_load_module/1]).
-export([number_to_db_name/1]).
-export([normalize_number/1]).
-export([to_e164/1, to_npan/1, to_1npan/1]).
@@ -27,6 +26,34 @@
-include_lib("whistle/include/wh_databases.hrl").
-define(SERVER, ?MODULE).
+-define(DEFAULT_CLASSIFIERS, [{<<"tollfree_us">>, <<"^\\+1(800|888|877|866|855)\\d{7}$">>}
+ ,{<<"did_us">>, <<"^\\+1\\d{10}$">>}
+ ]).
+
+%%--------------------------------------------------------------------
+%% @public
+%% @doc
+%% Classify a provided number
+%% @end
+%%--------------------------------------------------------------------
+-spec classify_number/1 :: (ne_binary()) -> 'undefined' | ne_binary().
+-spec classify_number/2 :: (ne_binary(), proplist()) -> 'undefined' | ne_binary().
+
+classify_number(Number) ->
+ Default = wh_json:from_list(?DEFAULT_CLASSIFIERS),
+ Classifiers = whapps_config:get(?WNM_CONFIG_CAT, <<"classifiers">>, Default),
+ Num = wnm_util:normalize_number(Number),
+ classify_number(Num, wh_json:to_proplist(Classifiers)).
+
+classify_number(Num, []) ->
+ lager:debug("unable to classify number ~s", [Num]);
+classify_number(Num, [{Classification, Classifier}|Classifiers]) ->
+ case re:run(Num, Classifier) of
+ nomatch -> classify_number(Num, Classifiers);
+ _ ->
+ lager:debug("number '~s' is classified as ~s", [Num, Classification]),
+ wh_util:to_binary(Classification)
+ end.
%%--------------------------------------------------------------------
%% @public
@@ -50,21 +77,6 @@ is_reconcilable(Number) ->
%%--------------------------------------------------------------------
%% @public
%% @doc
-%% Determines if a given number is tollfree
-%% @end
-%%--------------------------------------------------------------------
--spec is_tollfree/1 :: (ne_binary()) -> boolean().
-is_tollfree(Number) ->
- Num = normalize_number(Number),
- Regex = whapps_config:get(?WNM_CONFIG_CAT, <<"is_tollfree_regex">>, ?WNM_DEAFULT_TOLLFREE_RE),
- case re:run(Num, Regex) of
- nomatch -> false;
- _ -> true
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
%% Given a number doc determine if the carrier module is available
%% and if return the name as well as the data
%% @end
@@ -77,7 +89,7 @@ get_carrier_module(JObj) ->
undefined;
Module ->
Carriers = list_carrier_modules(),
- Carrier = try_load_module(Module),
+ Carrier = wh_util:try_load_module(Module),
case lists:member(Carrier, Carriers) of
true -> Carrier;
false ->
@@ -96,7 +108,7 @@ get_carrier_module(JObj) ->
list_carrier_modules() ->
CarrierModules =
whapps_config:get(?WNM_CONFIG_CAT, <<"carrier_modules">>, ?WNM_DEAFULT_CARRIER_MODULES),
- [Module || M <- CarrierModules, (Module = try_load_module(M)) =/= false].
+ [Module || M <- CarrierModules, (Module = wh_util:try_load_module(M)) =/= false].
%%--------------------------------------------------------------------
%% @public
@@ -128,40 +140,6 @@ normalize_number(Number) when is_binary(Number) ->
normalize_number(Number) ->
normalize_number(wh_util:to_binary(Number)).
-%%--------------------------------------------------------------------
-%% @private
-%% @doc
-%% Given a module name try to verify its existance, loading it into the
-%% the vm if possible.
-%% @end
-%%--------------------------------------------------------------------
--spec try_load_module/1 :: (string() | binary()) -> atom() | false.
-try_load_module(Name) ->
- try
- Module = wh_util:to_atom(Name),
- case erlang:module_loaded(Module) of
- true ->
- Module;
- false ->
- {module, Module} = code:ensure_loaded(Module),
- Module
- end
- catch
- error:badarg ->
- lager:debug("carrier module ~s not found", [Name]),
- case code:where_is_file(wh_util:to_list(<<Name/binary, ".beam">>)) of
- non_existing ->
- lager:debug("beam file not found for ~s", [Name]),
- false;
- _Path ->
- lager:debug("beam file found: ~s", [_Path]),
- wh_util:to_atom(Name, true), %% put atom into atom table
- try_load_module(Name)
- end;
- _:_ ->
- false
- end.
-
-spec is_e164/1 :: (ne_binary()) -> boolean().
-spec is_npan/1 :: (ne_binary()) -> boolean().
-spec is_1npan/1 :: (ne_binary()) -> boolean().
View
755 lib/whistle_service-1.0.0/src/wh_reseller.erl
@@ -1,755 +0,0 @@
-%%%-------------------------------------------------------------------
-%%% @copyright (C) 2012, VoIP INC
-%%% @doc
-%%% @end
-%%%
-%%% @contributors
-%%% Karl Anderson <karl@2600hz.org>
-%%%-------------------------------------------------------------------
--module(wh_reseller).
-
--export([fetch/1, fetch/2]).
--export([find_reseller_id/1]).
--export([get_plans/1, get_plans/2]).
--export([get_reseller_id/1]).
--export([set_created_flag/2]).
--export([set_deleted_flag/2]).
--export([is_master_reseller/1]).
--export([process_activation_charges/3]).
--export([update_quantity/4]).
--export([increment_quantity/3]).
--export([reset_category_addons/2]).
--export([commit_changes/1]).
--export([find_reseller/1, find_reseller/2]).
--export([get_default_service_plan/1]).
--export([set_service_plans/2, set_service_plans/3]).
--export([assign/1]).
--export([unassign/1]).
--export([assign_representative/1]).
--export([unassign_representative/1]).
--export([get_represenative/1]).
--export([admins/1]).
--export([settings/2]).
-
--include("wh_service.hrl").
-
--record(wh_reseller, {reseller = 'undefined' :: 'undefined' | ne_binary()
- ,created = 'undefined' :: 'undefined' | ne_binary()
- ,deleted = 'undefined' :: 'undefined' | ne_binary()
- ,plans = [] :: [] | [wh_service_plan:plan(),...]
- ,billing_id = 'undefined' :: 'undefined' | ne_binary()
- ,account_id = 'undefined' :: 'undefined' | ne_binary()
- ,bt_customer = 'undefined' :: 'undefined' | #bt_customer{}
- ,bt_subscriptions = dict:new() :: dict()
- ,bt_transactions = dict:new() :: dict()
- ,bt_merchant_id = 'undefined' :: 'undefined' | ne_binary()
- ,bt_public_key = 'undefined' :: 'undefined' | ne_binary()
- ,bt_private_key = 'undefined' :: 'undefined' | ne_binary()
- ,reset_addons = sets:new() :: set()
- }).
-
--type(reseller() :: #wh_reseller{}).
--export_type([reseller/0]).
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Given an account id this will create a list of service plans that
-%% the account and possibly a reseller are subscribed to.
-%% @end
-%%--------------------------------------------------------------------
--spec fetch/1 :: (ne_binary()) -> {'ok', reseller()} | {'error', _}.
--spec fetch/2 :: (ne_binary(), ne_binary()) -> {'ok', reseller()} | {'error', _}.
-
-fetch(Account) ->
- fetch(Account, wh_util:format_account_id(Account, raw)).
-
-fetch(Account, InvokingAccountId) ->
- AccountId = wh_util:format_account_id(Account, raw),
- AccountDb = wh_util:format_account_id(Account, encoded),
- case couch_mgr:open_cache_doc(AccountDb, AccountId) of
- {error, _R}=E ->
- lager:debug("unabled to open account definition for ~s: ~p", [Account, _R]),
- E;
- {ok, JObj} ->
- ResellerId = get_reseller_id(JObj),
- BillingId = wh_json:get_value(<<"billing_id">>, JObj, AccountId),
- case get_plans(ResellerId, InvokingAccountId =/= AccountId, JObj) of
- [] -> {error, {no_service_plan, ResellerId}};
- Plans ->
- lager:debug("found reseller ~s for account ~s with billing id ~s", [ResellerId, AccountId, BillingId]),
- {ok, #wh_reseller{reseller = ResellerId
- ,plans = Plans
- ,bt_customer = bt_customer(BillingId)
- ,account_id = InvokingAccountId
- ,billing_id = BillingId
- }}
- end
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec find_reseller_id/1 :: ('undefined' | ne_binary()) -> 'undefined' | ne_binary().
-find_reseller_id(undefined) -> undefined;
-find_reseller_id(Account) ->
- AccountId = wh_util:format_account_id(Account, raw),
- AccountDb = wh_util:format_account_id(Account, encoded),
- case couch_mgr:open_cache_doc(AccountDb, AccountId) of
- {error, _R} ->
- lager:debug("unable to open account definition for ~s: ~p", [AccountId, _R]),
- undefined;
- {ok, JObj} ->
- {ok, MasterAccountId} = whapps_util:get_master_account_id(),
- case wh_json:get_value(<<"pvt_reseller_id">>, JObj) of
- AccountId -> undefined;
- MasterAccountId -> undefined;
- Else -> Else
- end
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec set_created_flag/2 :: (ne_binary(), #wh_reseller{}) -> #wh_reseller{}.
-set_created_flag(Type, #wh_reseller{}=Reseller) ->
- Reseller#wh_reseller{created=Type}.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec set_deleted_flag/2 :: (ne_binary(), #wh_reseller{}) -> #wh_reseller{}.
-set_deleted_flag(Type, #wh_reseller{}=Reseller) ->
- Reseller#wh_reseller{deleted=Type}.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Given the category and name of a service element process any
-%% activation charges
-%% @end
-%%--------------------------------------------------------------------
--spec process_activation_charges/3 :: (ne_binary(), ne_binary(), reseller()) -> reseller().
-process_activation_charges(Category, Name, #wh_reseller{plans=Plans}=Reseller) ->
- process_activation_charges(Category, Name, Reseller, Plans).
-
-process_activation_charges(_, _, Reseller, []) ->
- Reseller;
-process_activation_charges(Category, Name, #wh_reseller{billing_id=BillingId
- ,account_id=AccountId}=Reseller, [Plan|Plans]) ->
- case wh_service_plan:get_activation_charge(Category, Name, Plan) of
- undefined -> process_activation_charges(Category, Name, Reseller, Plans);
- Amount ->
- case current_balance(BillingId) >= wapi_money:dollars_to_units(wh_util:to_float(Amount)) of
- false ->
- lager:debug("insufficient credit on ledger ~s for activation charges $~s", [BillingId, wh_util:to_list(Amount)]),
- Error = wh_json:from_list([{<<"errors">>, []}
- ,{<<"verification">>, wh_json:new()}
- ,{<<"message">>, <<"Insufficient Funds">>}
- ]),
- throw({api_error, wh_json:from_list([{<<"api_error">>, Error}])});
- true ->
- case write_to_ledger(BillingId, Category, Name, wh_service_plan:get_id(Plan), AccountId, Amount) of
- {ok, _} ->
- lager:debug("debited ledger ~s for activation charges $~s", [BillingId, wh_util:to_list(Amount)]),
- process_activation_charges(Category, Name, Reseller, Plans);
- {error, _R} ->
- lager:debug("unable to debit $~s from ledger ~s: ~p", [wh_util:to_list(Amount), BillingId, _R]),
- Error = wh_json:from_list([{<<"errors">>, []}
- ,{<<"verification">>, wh_json:new()}
- ,{<<"message">>, <<"Database Fault">>}
- ]),
- throw({api_error, wh_json:from_list([{<<"api_error">>, Error}])})
- end
- end
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Update the quantity by finding all associated subscription/addon
-%% mappings for the given category.name service element. If the
-%% subscription is updated it is moved to #wh_reseller.bt_subscriptions
-%% @end
-%%--------------------------------------------------------------------
--spec update_quantity/4 :: (ne_binary(), ne_binary(), ne_binary() | integer(), reseller()) -> reseller().
-update_quantity(Category, Name, Quantity, #wh_reseller{plans=Plans}=Reseller) ->
- update_quantity(Category, Name, Quantity, Reseller, Plans).
-
-update_quantity(_, _, _, Reseller, []) ->
- Reseller;
-update_quantity(Category, Name, Quantity, #wh_reseller{account_id=AccountId}=Reseller, [Plan|Plans]) ->
- case wh_service_plan:get_recurring_plan(Category, Name, Plan) of
- undefined -> update_quantity(Category, Name, Quantity, Reseller, Plans);
- {PlanId, AddOnId} ->
- SubscriptionId = <<AccountId/binary, "_", PlanId/binary>>,
- Subscription = get_subscription(SubscriptionId, PlanId, Reseller),
- R = update_subscription_quanity(SubscriptionId, Subscription, AddOnId, Quantity, Reseller),
- update_quantity(Category, Name, Quantity, R, Plans)
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec increment_quantity/3 :: (ne_binary(), ne_binary(), reseller()) -> reseller().
-increment_quantity(Category, Name, #wh_reseller{plans=Plans}=Reseller) ->
- increment_quantity(Category, Name, Reseller, Plans).
-
-increment_quantity(_, _, Reseller, []) ->
- Reseller;
-increment_quantity(Category, Name, #wh_reseller{account_id=AccountId
- ,reset_addons=ResetAddOns}=Reseller
- ,[Plan|Plans]) ->
- case wh_service_plan:get_recurring_plan(Category, Name, Plan) of
- undefined -> increment_quantity(Category, Name, Reseller, Plans);
- {PlanId, AddOnId} ->
- SubscriptionId = <<AccountId/binary, "_", PlanId/binary>>,
- Subscription = get_subscription(SubscriptionId, PlanId, Reseller),
- AddOn = wh_util:to_list(AddOnId),
- R = case sets:is_element(AddOn, ResetAddOns) of
- false ->
- update_subscription_quanity(SubscriptionId, Subscription, AddOnId, 1, Reseller);
- true ->
- increment_subscription_quanity(SubscriptionId, Subscription, AddOnId, Reseller)
- end,
- increment_quantity(Category, Name, R#wh_reseller{reset_addons=sets:add_element(AddOn, ResetAddOns)}, Plans)
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Set the quantity of any subscribed addons on a given category to 0
-%% @end
-%%--------------------------------------------------------------------
--spec reset_category_addons/2 :: (ne_binary(), reseller()) -> reseller().
-reset_category_addons(Category, #wh_reseller{plans=Plans}=Reseller) ->
- reset_category_addons(Category, Plans, Reseller).
-
-reset_category_addons(_, [], Reseller) ->
- Reseller;
-reset_category_addons(Category, [Plan|Plans], #wh_reseller{account_id=AccountId}=Reseller) ->
- Updated = lists:foldr(fun({PlanId, AddOnId}, #wh_reseller{reset_addons=ResetAddOns}=R) ->
- SubscriptionId = <<AccountId/binary, "_", PlanId/binary>>,
- case subscribed_to_addon(SubscriptionId, AddOnId, R) of
- false -> R;
- true ->
- Subscription = get_subscription(SubscriptionId, PlanId, R),
- (update_subscription_quanity(SubscriptionId, Subscription, AddOnId, 0, R))
- #wh_reseller{reset_addons=sets:add_element(AddOnId, ResetAddOns)}
- end
- end, Reseller, wh_service_plan:get_category_addons(Category, Plan)),
- reset_category_addons(Category, Plans, Updated).
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
-update_base_mrc(#wh_reseller{plans=Plans}=Reseller) ->
- update_base_mrc(Plans, Reseller).
-
-update_base_mrc([], Reseller) ->
- Reseller;
-update_base_mrc([Plan|Plans], Reseller) ->
- update_base_mrc(Plans, lists:foldr(fun(JObj, R) ->
- base_mrc(JObj, R)
- end, Reseller, wh_service_plan:get_base_mrc(Plan))).
-
-base_mrc(JObj, #wh_reseller{account_id=AccountId, bt_subscriptions=Subscriptions, bt_customer=Customer}=Reseller) ->
- PlanId = wh_json:get_value(<<"plan">>, JObj),
- AddOnId = wh_json:get_value(<<"add_on">>, JObj),
- AccountDb = wh_util:format_account_id(AccountId, encoded),
- Type = wh_json:get_value(<<"type">>, JObj),
- ViewOptions = [{key, Type}],
- case couch_mgr:get_results(AccountDb, <<"maintenance/listing_by_type">>, ViewOptions) of
- {error, _R} ->
- lager:debug("unable to get count for document type ~s: ~p", [Type, _R]),
- Reseller;
- {ok, J} ->
- SubscriptionId = <<AccountId/binary, "_", PlanId/binary>>,
- Subscription = get_subscription(SubscriptionId, PlanId, Reseller),
- CustomerId = braintree_customer:get_id(Customer),
- Price = get_price(JObj, length(J), Type, Reseller),
- lager:debug("updating customer ~s subscription ~s addon ~s base mrc price to $~s", [CustomerId, SubscriptionId, AddOnId
- ,wh_util:to_list(Price)
- ]),
- S1 = braintree_subscription:update_addon_quantity(Subscription, AddOnId, 1),
- S2 = braintree_subscription:update_addon_amount(S1, AddOnId, Price),
- Reseller#wh_reseller{bt_subscriptions=dict:store(SubscriptionId, S2, Subscriptions)}
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec commit_changes/1 :: (reseller()) -> ok.
-commit_changes(#wh_reseller{}=Reseller) ->
- #wh_reseller{bt_subscriptions=Subscriptions} = update_base_mrc(Reseller),
- _ = [braintree_subscription:update(Subscription)
- || {_, Subscription} <- dict:to_list(Subscriptions)
- ],
- ok.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec find_reseller/1 :: ([ne_binary(),...] | []) -> ne_binary().
--spec find_reseller/2 :: ([ne_binary(),...] | [], ne_binary()) -> ne_binary().
-
-find_reseller(Tree) ->
- {ok, MasterAccountId} = whapps_util:get_master_account_id(),
- find_reseller(lists:reverse(Tree), MasterAccountId).
-
-find_reseller([], MasterAccountId) ->
- lager:debug("the master account ~s is the reseller for this account", [MasterAccountId]),
- MasterAccountId;
-find_reseller([ParentId|Tree], MasterAccountId) ->
- case couch_mgr:open_doc(?WH_ACCOUNTS_DB, ParentId) of
- {ok, JObj} ->
- case wh_json:is_true(<<"pvt_reseller">>, JObj) andalso get_reseller_id(JObj) =:= MasterAccountId of
- false -> find_reseller(Tree, MasterAccountId);
- true ->
- lager:debug("parent ~s is the reseller for this account", [ParentId]),
- ParentId
- end;
- {error, _R} ->
- lager:debug("ignoring the ancestor ~s during reseller hunt, unable to open the account definition: ~p", [ParentId, _R]),
- find_reseller(Tree, MasterAccountId)
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Given an account get all the service plans subscribed to
-%% from the resellers account.
-%% @end
-%%--------------------------------------------------------------------
--spec get_plans/1 :: (ne_binary()) -> [wh_service_plan:plan(),...] | [].
--spec get_plans/2 :: (ne_binary(), wh_json:json_object()) -> [wh_service_plan:plan(),...] | [].
-
-get_plans(Account) ->
- AccountId = wh_util:format_account_id(Account, raw),
- AccountDb = wh_util:format_account_id(Account, encoded),
- case couch_mgr:open_cache_doc(AccountDb, AccountId) of
- {error, _R}=E ->
- lager:debug("unabled to open account definition for ~s: ~p", [Account, _R]),
- E;
- {ok, JObj} ->
- Reseller = get_reseller_id(JObj),
- get_plans(Reseller, JObj)
- end.
-
-
-get_plans(Reseller, JObj) ->
- get_plans(Reseller, false, JObj).
-
-get_plans(Reseller, CascadeOnly, JObj) ->
- [Plan
- || PlanId <- wh_service_plan:get_plan_ids(JObj)
- ,begin
- {ok, Plan} = wh_service_plan:fetch(Reseller, CascadeOnly, PlanId),
- true
- end
- ].
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec set_service_plans/2 :: (wh_json:json_object(), 'undefined' | ne_binary() | [ne_binary(),...]) -> wh_json:json_object().
--spec set_service_plans/3 :: (wh_json:json_object(), 'undefined' | ne_binary() | [ne_binary(),...], 'undefined' | ne_binary())
- -> wh_json:json_object().
-
-set_service_plans(JObj, ServicePlans) ->
- set_service_plans(JObj, ServicePlans, undefined).
-
-set_service_plans(JObj, ServicePlans, undefined) ->
- Reseller = find_reseller(wh_json:get_value(<<"pvt_tree">>, JObj, [])),
- set_service_plans(JObj, ServicePlans, Reseller);
-set_service_plans(JObj, ServicePlans, Reseller) ->
- lager:debug("setting reseller id to ~s", [Reseller]),
- wh_service_plan:set_service_plans(wh_json:set_value(<<"pvt_reseller_id">>, Reseller, JObj)
- ,ServicePlans
- ,Reseller).
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec get_default_service_plan/1 :: (ne_binary()) -> 'undefined' | ne_binary().
-get_default_service_plan(Reseller) ->
- AccountId = wh_util:format_account_id(Reseller, raw),
- AccountDb = wh_util:format_account_id(Reseller, encoded),
- case couch_mgr:open_cache_doc(AccountDb, AccountId) of
- {error, _} -> undefined;
- {ok, JObj} -> wh_json:get_ne_value(<<"default_service_plan">>, JObj)
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Given an account definition or reseller record find the reseller id.
-%% If not present then assume it is being resold by the master account.
-%% @end
-%%--------------------------------------------------------------------
--spec get_reseller_id/1 :: (reseller() | wh_json:json_object()) -> ne_binary().
-get_reseller_id(#wh_reseller{reseller=Reseller}) ->
- Reseller;
-get_reseller_id(JObj) ->
- case wh_json:get_value(<<"pvt_reseller_id">>, JObj) of
- undefined ->
- {ok, MasterAccount} = whapps_util:get_master_account_id(),
- MasterAccount;
- Else -> Else
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Given an account definition or reseller record determine if it
-%% is being resold by the master account
-%% @end
-%%--------------------------------------------------------------------
--spec is_master_reseller/1 :: (reseller() | wh_json:json_object()) -> boolean().
-is_master_reseller(Reseller) ->
- {ok, MasterAccount} = whapps_util:get_master_account_id(),
- get_reseller_id(Reseller) =:= MasterAccount.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Assign the first account in the pvt_tree who is a reseller of the
-%% master account
-%% @end
-%%--------------------------------------------------------------------
--spec assign/1 :: (wh_json:json_object()) -> {'ok', wh_json:json_object()} | {'error', _}.
--spec assign/2 :: (ne_binary(), wh_json:json_object()) -> {'ok', wh_json:json_object()} | {'error', _}.
-
-assign(JObj) ->
- case whapps_util:get_master_account_id() of
- {error, _R}=E ->
- lager:debug("unable to assign reseller, master account is not known: ~p", [_R]),
- E;
- {ok, MasterAccountId} ->
- Tree = wh_json:get_value(<<"pvt_tree">>, JObj, []),
- ResellerId = find_reseller(Tree, MasterAccountId),
- assign(ResellerId, JObj)
- end.
-
-assign(ResellerId, JObj) ->
- ResellerDb = wh_util:format_account_id(ResellerId, encoded),
- case couch_mgr:db_exists(ResellerDb) of
- false -> {error, bad_reseller_id};
- true ->
- AccountId = wh_json:get_value(<<"_id">>, JObj),
- AccountDb = wh_util:format_account_id(AccountId, encoded),
- _ = assign_representative(JObj),
- case couch_mgr:save_doc(AccountDb, wh_json:set_value(<<"pvt_reseller_id">>, ResellerId, JObj)) of
- {error, _}=E -> E;
- {ok, JObj} ->
- couch_mgr:ensure_saved(?WH_ACCOUNTS_DB, JObj)
- end
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Assign the master account as the reseller for this account
-%% @end
-%%--------------------------------------------------------------------
--spec unassign/1 :: (wh_json:json_object()) -> {'ok', wh_json:json_object()} | {'error', _}.
-unassign(JObj) ->
- case whapps_util:get_master_account_id() of
- {error, _R}=E ->
- lager:debug("unable to unassign reseller, master account is not known: ~p", [_R]),
- E;
- {ok, MasterAccountId} ->
- AccountId = wh_json:get_value(<<"_id">>, JObj),
- AccountDb = wh_util:format_account_id(AccountId, encoded),
- _ = unassign_representative(JObj),
- case couch_mgr:save_doc(AccountDb, wh_json:set_value(<<"pvt_reseller_id">>, MasterAccountId, JObj)) of
- {error, _}=E -> E;
- {ok, JObj} ->
- couch_mgr:ensure_saved(?WH_ACCOUNTS_DB, JObj)
- end
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Attempt to assign to an account rep in the resellers account
-%% @end
-%%--------------------------------------------------------------------
--spec assign_representative/1 :: (wh_json:json_object()) -> {'ok', wh_json:json_object()} | {'error', _}.
-assign_representative(JObj) ->
- case wh_json:get_value(<<"pvt_reseller_id">>, JObj) of
- undefined -> {error, no_reseller};
- ResellerId ->
- ResellerDb = wh_util:format_account_id(ResellerId, encoded),
- ViewOptions = [{<<"limit">>, 1}
- ,{<<"include_docs">>, true}
- ],
- case couch_mgr:get_results(ResellerDb, <<"reseller/count_assignments">>, ViewOptions) of
- {error, _R}=E ->
- lager:debug("failed to assign reseller representative: ~p", [_R]),
- E;
- {ok, [Results]} ->
- AccountId = wh_json:get_value(<<"_id">>, JObj),
- Rep = wh_json:get_value(<<"doc">>, Results),
- Assignments = wh_json:get_value(<<"pvt_account_assignments">>, Rep, []),
- couch_mgr:save_doc(ResellerDb, wh_json:set_value(<<"pvt_account_assignments">>, [AccountId|Assignments], Rep))
- end
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Attempt to remove any assignments to a resellers rep
-%% @end
-%%--------------------------------------------------------------------
--spec unassign_representative/1 :: (json:json_object()) -> ok.
-unassign_representative(JObj) ->
- case wh_json:get_value(<<"pvt_reseller_id">>, JObj) of
- undefined -> ok;
- ResellerId ->
- AccountId = wh_json:get_value(<<"_id">>, JObj),
- ResellerDb = wh_util:format_account_id(ResellerId, encoded),
- ViewOptions = [{<<"include_docs">>, true}
- ,{<<"key">>, AccountId}
- ],
- case couch_mgr:get_results(ResellerDb, <<"reseller/find_assignments">>, ViewOptions) of
- {error, _R} ->
- lager:debug("failed to find reseller representatives: ~p", [_R]),
- ok;
- {ok, Results} ->
- _ = [begin
- Rep = wh_json:get_value(<<"doc">>, Result),
- Assignments = wh_json:get_value(<<"pvt_account_assignments">>, Rep, []),
- couch_mgr:save_doc(ResellerDb
- ,wh_json:set_value(<<"pvt_account_assignments">>
- ,lists:delete(AccountId, Assignments)
- ,Rep)
- )
- end || Result <- Results],
- ok
- end
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec get_represenative/1 :: (wh_json:json_object()) -> {'ok', wh_json:json_object()} | {'error', _}.
-get_represenative(JObj) ->
- AccountId = wh_json:get_value(<<"_id">>, JObj),
- ResellerId = get_reseller_id(JObj),
- ResellerDb = wh_util:format_account_id(ResellerId, encoded),
- ViewOptions = [{<<"include_docs">>, true}
- ,{<<"key">>, AccountId}
- ],
- case couch_mgr:get_results(ResellerDb, <<"reseller/find_assignments">>, ViewOptions) of
- {error, _R}=E ->
- lager:debug("unable to find reseller account represenatives: ~p", [_R]),
- E;
- {ok, []} -> assign_representative(JObj);
- {ok, [Rep|_]} -> {ok, wh_json:get_value(<<"doc">>, Rep, wh_json:new())}
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Return a list of users who are admins in the resellers account
-%% @end
-%%--------------------------------------------------------------------
--spec admins/1 :: (wh_json:json_object()) -> {'ok', wh_json:json_objects()} | {'error', _}.
-admins(JObj) ->
- ResellerId = get_reseller_id(JObj),
- ResellerDb = wh_util:format_account_id(ResellerId, encoded),
- ViewOptions = [{<<"key">>, <<"user">>}
- ,{<<"include_docs">>, true}
- ],
- case couch_mgr:get_results(ResellerDb, <<"maintenance/listing_by_type">>, ViewOptions) of
- {ok, Users} ->
- Admins = [wh_json:get_value(<<"doc">>, User)
- || User <- Users
- ,wh_json:get_value([<<"doc">>, <<"priv_level">>], User) =:= <<"admin">>
- ],
- {ok, Admins};
- {error, _R}=E ->
- lager:debug("failed to find reseller ~s account admins: ~p", [ResellerId, _R]),
- E
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec settings/2 :: (ne_binary(), wh_json:json_object()) -> wh_json:json_objects().
-settings(Key, JObj) ->
- ResellerId = get_reseller_id(JObj),
- whapps_account_config:get(ResellerId, Key).
-
-%%%===================================================================
-%%% Internal functions
-%%%===================================================================
-%%--------------------------------------------------------------------
-%% @private
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec bt_customer/1 :: (ne_binary()) -> #bt_customer{}.
-bt_customer(BillingId) ->
- lager:debug("requesting braintree customer ~s", [BillingId]),
- try braintree_customer:find(BillingId) of
- Customer -> Customer
- catch
- throw:{not_found, _} ->
- lager:debug("braintree customer ~s not found, creating new account", [BillingId]),
- braintree_customer:create(BillingId)
- end.
-
-%%--------------------------------------------------------------------
-%% @private
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec get_subscription/3 :: (ne_binary(), ne_binary(), reseller()) -> #bt_subscription{}.
-get_subscription(SubscriptionId, PlanId, #wh_reseller{bt_subscriptions=Subscriptions, bt_customer=Customer}) ->
- case dict:find(SubscriptionId, Subscriptions) of
- {ok, Subscription} -> Subscription;
- error ->
- try braintree_customer:get_subscription(SubscriptionId, Customer) of
- Subscription -> Subscription
- catch
- throw:{not_found, _} ->
- braintree_customer:new_subscription(SubscriptionId, PlanId, Customer)
- end
- end.
-
-%%--------------------------------------------------------------------
-%% @private
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec subscribed_to_addon/3 :: (ne_binary(), ne_binary(), reseller()) -> boolean().
-subscribed_to_addon(SubscriptionId, AddOnId, #wh_reseller{bt_customer=Customer}) ->
- try
- Subscription = braintree_customer:get_subscription(SubscriptionId, Customer),
- _ = braintree_subscription:get_addon(Subscription, AddOnId),
- true
- catch
- throw:{not_found, _} -> false
- end.
-
-%%--------------------------------------------------------------------
-%% @private
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec update_subscription_quanity/5 :: (ne_binary(), #bt_subscription{}, ne_binary(), ne_binary() | integer(), reseller()) -> reseller().
-update_subscription_quanity(SubscriptionId, Subscription, AddOnId, Quantity, #wh_reseller{bt_subscriptions=Subscriptions
- ,bt_customer=Customer}=Reseller) ->
- CustomerId = braintree_customer:get_id(Customer),
- lager:debug("updating customer ~s subscription ~s addon ~s quantity to ~p", [CustomerId, SubscriptionId, AddOnId, Quantity]),
- UpdatedSubscription = braintree_subscription:update_addon_quantity(Subscription, AddOnId, Quantity),
- Reseller#wh_reseller{bt_subscriptions=dict:store(SubscriptionId, UpdatedSubscription, Subscriptions)}.
-
-%%--------------------------------------------------------------------
-%% @private
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec increment_subscription_quanity/4 :: (ne_binary(), #bt_subscription{}, ne_binary(), reseller()) -> reseller().
-increment_subscription_quanity(SubscriptionId, Subscription, AddOnId, #wh_reseller{bt_subscriptions=Subscriptions
- ,bt_customer=Customer}=Reseller) ->
- CustomerId = braintree_customer:get_id(Customer),
- lager:debug("increment customer ~s subscription ~s addon ~s", [CustomerId, SubscriptionId, AddOnId]),
- UpdatedSubscription = braintree_subscription:increment_addon_quantity(Subscription, AddOnId),
- Reseller#wh_reseller{bt_subscriptions=dict:store(SubscriptionId, UpdatedSubscription, Subscriptions)}.
-
-%%--------------------------------------------------------------------
-%% @private
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec get_price/2 :: (wh_json:json_object(), non_neg_integer()) -> ne_binary().
--spec get_price/4 :: (wh_json:json_object(), non_neg_integer(), ne_binary(), #wh_reseller{}) -> ne_binary().
-
-get_price(JObj, Count) ->
- Prices = wh_json:get_value(<<"price_increments">>, JObj),
- L1 = [wh_util:to_integer(K) || K <- wh_json:get_keys(Prices)],
- case lists:dropwhile(fun(K) -> Count > K end, lists:sort(L1)) of
- [] -> wh_json:get_binary_value(<<"default_price">>, JObj);
- Range -> wh_json:get_binary_value(wh_util:to_binary(hd(Range)), Prices)
- end.
-
-get_price(JObj, Count, Type, #wh_reseller{created=Type}) ->
- get_price(JObj, Count + 1);
-get_price(JObj, Count, Type, #wh_reseller{deleted=Type}) ->
- get_price(JObj, Count - 1);
-get_price(JObj, Count, _, _) ->
- get_price(JObj, Count).
-
-
--spec write_to_ledger/6 :: (ne_binary(), ne_binary(), ne_binary(), ne_binary(), ne_binary(), ne_binary()) -> {'ok', wh_json:json_object()} |
- {'error', _}.
-write_to_ledger(Ledger, Category, Item, ServicePlanId, AccountId, Units) ->
- LedgerId = wh_util:format_account_id(Ledger, raw),
- LedgerDb = wh_util:format_account_id(Ledger, encoded),
- Timestamp = wh_util:current_tstamp(),
- Entry = wh_json:from_list([{<<"reason">>, <<"service plan transaction">>}
- ,{<<"category">>, Category}
- ,{<<"item">>, Item}
- ,{<<"service_plan_id">>, ServicePlanId}
- ,{<<"account_id">>, AccountId}
- ,{<<"amount">>, wapi_money:dollars_to_units(wh_util:to_float(Units))}
- ,{<<"pvt_account_id">>, LedgerId}
- ,{<<"pvt_account_db">>, LedgerDb}
- ,{<<"pvt_type">>, <<"debit">>}
- ,{<<"pvt_created">>, Timestamp}
- ,{<<"pvt_modified">>, Timestamp}
- ,{<<"pvt_vsn">>, 1}
- ]),
- couch_mgr:save_doc(LedgerDb, Entry).
-
--spec current_balance/1 :: (ne_binary()) -> integer().
-current_balance(Ledger) ->
- LedgerDb = wh_util:format_account_id(Ledger, encoded),
- ViewOptions = [{<<"reduce">>, true}],
- case couch_mgr:get_results(LedgerDb, <<"transactions/credit_remaining">>, ViewOptions) of
- {ok, []} -> 0;
- {ok, [ViewRes|_]} -> wh_json:get_integer_value(<<"value">>, ViewRes, 0);
- {error, _} -> 0
- end.
View
165 lib/whistle_service-1.0.0/src/wh_resellers.erl
@@ -1,165 +0,0 @@
-%%%-------------------------------------------------------------------
-%%% @copyright (C) 2012, VoIP INC
-%%% @doc
-%%%
-%%% Service plans may be applied in a hierarchy such as:
-%%%
-%%% 2600hz (Resller: 2600hz, Billing ID: 2600hz)
-%%% | -- Account 1 (Resller: 2600hz, Billing ID: Account 1)
-%%% | -- Account 2 (Resller: 2600hz, Billing ID: Account 2)
-%%% | -- Account 3 (Reseller: 2600hz, Billing ID: Reseller 1)
-%%% | | -- Account 4 (Reseller: Account 3, Billing ID: Account 4)
-%%% | | -- Account 5 (Reseller: Account 3, Billing ID: Account 5)
-%%% | | | -- Account 6 (Reseller: Account 3, Billing ID: Account 5)
-%%% | | | -- Account 7 (Reseller: Account 3, Billing ID: Account 7)
-%%% ... ... ...
-%%%
-%%% Currently only one additional level is supported;
-%%% the master account and one reseller. This is due to
-%%% limitations of the jonny5 whapp and additional PDD
-%%% incured when enforcing limits of deeply nested resellers.
-%%%
-%%% @end
-%%% @contributors
-%%%-------------------------------------------------------------------
--module(wh_resellers).
-
--export([fetch/1]).
--export([set_created_flag/2]).
--export([set_deleted_flag/2]).
--export([process_activation_charges/3]).
--export([update_quantity/4]).
--export([increment_quantity/3]).
--export([reset_category_addons/2]).
--export([commit_changes/1]).
-
--include("wh_service.hrl").
-
--type(resellers() :: [wh_reseller:reseller()] | []).
--export_type([resellers/0]).
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Given an account id this will create a list of service plans that
-%% the account and possibly a reseller are subscribed to.
-%% @end
-%%--------------------------------------------------------------------
--spec fetch/1 :: (ne_binary()) -> {'ok', resellers()} | {'error', 'no_service_plan'}.
--spec fetch/3 :: ('undefined'| ne_binary(), ne_binary(), resellers()) -> {'ok', resellers()} | {'error', 'no_service_plan'}.
-
-fetch(AccountId) ->
- fetch(AccountId, AccountId, []).
-
-fetch(undefined, _, []) ->
- {error, no_service_plan};
-fetch(undefined, _, Resellers) ->
- {ok, Resellers};
-fetch(AccountId, InvokingAccountId, Resellers) ->
- case wh_reseller:fetch(AccountId, InvokingAccountId) of
- {error, {no_service_plan, AccountId}} ->
- fetch(undefined, InvokingAccountId, Resellers);
- {error, {no_service_plan, ResellerId}} ->
- fetch(ResellerId, InvokingAccountId, Resellers);
- {error, _R} ->
- fetch(undefined, InvokingAccountId, Resellers);
- {ok, Reseller} ->
- case wh_reseller:get_reseller_id(Reseller) of
- AccountId ->
- fetch(undefined, InvokingAccountId, [Reseller|Resellers]);
- ResellerId ->
- fetch(ResellerId, InvokingAccountId, [Reseller|Resellers])
- end
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec set_created_flag/2 :: (ne_binary(), resellers()) -> resellers().
-set_created_flag(Created, Resellers) ->
- [wh_reseller:set_created_flag(Created, Reseller)
- || Reseller <- Resellers
- ].
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec set_deleted_flag/2 :: (ne_binary(), resellers()) -> resellers().
-set_deleted_flag(Deleted, Resellers) ->
- [wh_reseller:set_deleted_flag(Deleted, Reseller)
- || Reseller <- Resellers
- ].
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec process_activation_charges/3 :: (ne_binary(), ne_binary(), resellers()) -> resellers().
-process_activation_charges(Category, Name, Resellers) ->
- [wh_reseller:process_activation_charges(Category, Name, Reseller)
- || Reseller <- Resellers
- ].
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Given the plans that apply to this account update the quanity, and
-%% accumulate any transactions as required.
-%% @end
-%%--------------------------------------------------------------------
--spec update_quantity/4 :: (ne_binary(), ne_binary(), ne_binary() | integer(), resellers()) -> resellers().
-update_quantity(Category, Name, Quantity, Resellers) ->
- [wh_reseller:update_quantity(Category, Name, Quantity, Reseller)
- || Reseller <- Resellers
- ].
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Given the plans that apply to this account update the quanity, and
-%% accumulate any transactions as required.
-%% @end
-%%--------------------------------------------------------------------
--spec increment_quantity/3 :: (ne_binary(), ne_binary(), resellers()) -> resellers().
-increment_quantity(Category, Name, Resellers) ->
- [wh_reseller:increment_quantity(Category, Name, Reseller)
- || Reseller <- Resellers
- ].
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Set the quantity of all addons on a given category to 0
-%% @end
-%%--------------------------------------------------------------------
--spec reset_category_addons/2 :: (ne_binary(), resellers()) -> resellers().
-reset_category_addons(Category, Resellers) ->
- [wh_reseller:reset_category_addons(Category, Reseller)
- || Reseller <- Resellers
- ].
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Commit any billing changes to the resellers.
-%% @end
-%%--------------------------------------------------------------------
--spec commit_changes/1 :: (resellers()) -> 'ok'.
-commit_changes(Resellers) ->
- _ = [wh_reseller:commit_changes(Reseller)
- || Reseller <- Resellers
- ],
- ok.
-
-%%%===================================================================
-%%% Internal functions
-%%%===================================================================
-
View
9 lib/whistle_service-1.0.0/src/wh_service.erl
@@ -1,9 +0,0 @@
-%%%-------------------------------------------------------------------
-%%% @copyright (C) 2012, VoIP, INC
-%%% @doc
-%%%
-%%% @end
-%%% @contributors
-%%%-------------------------------------------------------------------
--module(wh_service).
-
View
11 lib/whistle_service-1.0.0/src/wh_service.hrl
@@ -1,11 +0,0 @@
--ifndef(WH_SERVICE_LOCAL_HRL).
-
--include_lib("whistle/include/wh_amqp.hrl").
--include_lib("whistle/include/wh_types.hrl").
--include_lib("whistle/include/wh_log.hrl").
--include_lib("whistle/include/wh_databases.hrl").
--include_lib("braintree/include/braintree.hrl").
--include_lib("whistle_service/include/wh_service.hrl").
-
--define(WH_SERVICE_LOCAL_HRL, true).
--endif.
View
53 lib/whistle_service-1.0.0/src/wh_service_devices.erl
@@ -1,53 +0,0 @@
-%%%-------------------------------------------------------------------
-%%% @copyright (C) 2012, VoIP INC
-%%% @doc
-%%%
-%%% @end
-%%% @contributors
-%%%-------------------------------------------------------------------
--module(wh_service_devices).
-
--export([update/2, update/3]).
--export([activate_device_type/2]).
-
--include("wh_service.hrl").
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec activate_device_type/2 :: (ne_binary(), wh_resellers:resellers()) -> wh_resellers:resellers().
-activate_device_type(DeviceType, Resellers) ->
- wh_resellers:process_activation_charges(<<"devices">>, DeviceType, Resellers).
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Given the account limit document reconcile the service
-%% charges
-%% @end
-%%--------------------------------------------------------------------
--spec update/2 :: ([] | [ne_binary(),...], wh_resellers:resellers()) -> wh_resellers:resellers().
--spec update/3 :: ([] | [ne_binary(),...], wh_resellers:resellers(), 'created' | 'deleted' | 'updated') -> wh_resellers:resellers().
-
-update(DeviceTypes, Resellers) ->
- update(DeviceTypes, Resellers, updated).
-
-update(DeviceTypes, Resellers, Action) ->
- Routines = [fun(R) -> wh_resellers:reset_category_addons(<<"devices">>, R) end
- ,fun(R) ->
- lists:foldr(fun(DeviceType, R1) ->
- wh_resellers:increment_quantity(<<"devices">>, DeviceType, R1)
- end, R, DeviceTypes)
- end
- ,fun(R) ->
- case Action of
- created -> wh_resellers:set_created_flag(<<"device">>, R);
- deleted -> wh_resellers:set_deleted_flag(<<"device">>, R);
- updated -> R
- end
- end
- ],
- lists:foldl(fun(F, R) -> F(R) end, Resellers, Routines).
View
31 lib/whistle_service-1.0.0/src/wh_service_limits.erl
@@ -1,31 +0,0 @@
-%%%-------------------------------------------------------------------
-%%% @copyright (C) 2012, VoIP INC
-%%% @doc
-%%%
-%%% @end
-%%% @contributors
-%%%-------------------------------------------------------------------
--module(wh_service_limits).
-
--export([update/2]).
-
--include("wh_service.hrl").
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Given the account limit document reconcile the service
-%% charges
-%% @end
-%%--------------------------------------------------------------------
--spec update/2 :: (wh_json:json_object(), wh_resellers:resellers()) -> wh_resellers:resellers().
-update(JObj, Resellers) ->
- R1 = wh_resellers:reset_category_addons(<<"limits">>, Resellers),
- Limits = wh_json:get_keys(wh_json:public_fields(JObj)),
- lists:foldr(fun(Limit, R) ->
- Quantity = wh_json:get_value(Limit, JObj, 0),
- case Quantity =< 0 of
- true -> wh_resellers:update_quantity(<<"limits">>, Limit, 0, R);
- false -> wh_resellers:update_quantity(<<"limits">>, Limit, Quantity, R)
- end
- end, R1, Limits).
View
86 lib/whistle_service-1.0.0/src/wh_service_numbers.erl
@@ -1,86 +0,0 @@
-%%%-------------------------------------------------------------------
-%%% @copyright (C) 2012, VoIP INC
-%%% @doc
-%%%
-%%% @end
-%%% @contributors
-%%%-------------------------------------------------------------------
--module(wh_service_numbers).
-
--export([activate_phone_number/2]).
--export([activate_feature/2]).
--export([update/2]).
-
--include("wh_service.hrl").
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec activate_phone_number/2 :: (ne_binary(), wh_resellers:resellers()) -> wh_resellers:resellers().
-activate_phone_number(Number, Resellers) ->
- wh_resellers:process_activation_charges(<<"phone_numbers">>, Number, Resellers).
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec activate_feature/2 :: (ne_binary(), wh_resellers:resellers()) -> wh_resellers:resellers().
-activate_feature(Feature, Resellers) ->
- wh_resellers:process_activation_charges(<<"number_services">>, Feature, Resellers).
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Given the account phone_number document reconcile the service
-%% charges
-%% @end
-%%--------------------------------------------------------------------
--spec update/2 :: (wh_json:json_object(), wh_resellers:resellers()) -> wh_resellers:resellers().
-update(JObj, Resellers) ->
- Routines = [fun(R) -> wh_resellers:reset_category_addons(<<"phone_numbers">>, R) end
- ,fun(R) -> wh_resellers:reset_category_addons(<<"number_services">>, R) end
- ,fun(R) ->
- lists:foldr(fun(PhoneNumber, R1) ->
- update_number(JObj, PhoneNumber, R1)
- end, R, wh_json:get_keys(wh_json:public_fields(JObj)))
- end
- ],
- lists:foldl(fun(F, R) -> F(R) end, Resellers, Routines).
-
-%%--------------------------------------------------------------------
-%% @private
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec update_number/3 :: (wh_json:json_object(), ne_binary(), wh_resellers:resellers()) -> wh_resellers:resellers().
-update_number(JObj, PhoneNumber, Resellers) ->
- case wh_json:is_true([PhoneNumber, <<"local_number">>], JObj) of
- true -> Resellers;
- false ->
- Routines = [fun(R) -> wh_resellers:increment_quantity(<<"phone_numbers">>, PhoneNumber, R) end
- ,fun(R) ->
- Services = wh_json:get_value([PhoneNumber, <<"features">>], JObj, []),
- update_number_services(Services, R)
- end
- ],
- lists:foldl(fun(F, R) -> F(R) end, Resellers , Routines)
- end.
-
-%%--------------------------------------------------------------------
-%% @private
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec update_number_services/2 :: ([ne_binary(),...] | [], wh_resellers:resellers()) -> wh_resellers:resellers().
-update_number_services(Services, Resellers) ->
- lists:foldr(fun(Service, R) ->
- wh_resellers:increment_quantity(<<"number_services">>, Service, R)
- end, Resellers, Services).
-
View
231 lib/whistle_service-1.0.0/src/wh_service_plan.erl
@@ -1,231 +0,0 @@
-%%%-------------------------------------------------------------------
-%%% @copyright (C) 2012, VoIP INC
-%%% @doc
-%%%
-%%% @end
-%%% @contributors
-%%%-------------------------------------------------------------------
--module(wh_service_plan).
-
--export([fetch/2, fetch/3]).
--export([get_id/1]).
--export([get_plan_ids/1]).
--export([add_plan_id/3]).
--export([set_service_plans/3]).
--export([is_valid_plan_id/2]).
--export([get_category_addons/2]).
--export([get_recurring_plan/3]).
--export([get_activation_charge/3]).
--export([get_base_mrc/1]).
--export([get_item/3]).
-
--include("wh_service.hrl").
-
--record(wh_service_plan, {id = 'undefined' :: 'undefined' | ne_binary()
- ,reseller = 'undefined' :: 'undefined' | ne_binary()
- ,cascade_only = false :: boolean()
- ,plan = wh_json:new() :: wh_json:json_object()
- }).
-
--type(plan() :: #wh_service_plan{}).
--export_type([plan/0]).
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Given a service plan id and a reseller attempt to fetch the plan
-%% drawing from the common cache if possible.
-%% @end
-%%--------------------------------------------------------------------
--spec fetch/2 :: (ne_binary(), ne_binary()) -> {'ok', plan()} | {'error', _}.
--spec fetch/3 :: (ne_binary(), boolean(), ne_binary()) -> {'ok', plan()} | {'error', _}.
-
-fetch(Reseller, PlanId) ->
- fetch(Reseller, false, PlanId).
-
-fetch(Reseller, CascadeOnly, PlanId) ->
- lager:debug("fetching service plan ~s from reseller ~s (cascades only ~s)", [PlanId, Reseller, CascadeOnly]),
- ResellerDb = wh_util:format_account_id(Reseller, encoded),
- case couch_mgr:open_cache_doc(ResellerDb, PlanId) of
- {ok, JObj} ->
- {ok, #wh_service_plan{id=PlanId, reseller=Reseller, plan=JObj, cascade_only=CascadeOnly}};
- {error, _R}=E ->
- lager:debug("unable to open reseller ~s service plan ~s: ~p", [Reseller, PlanId, _R]),
- E
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Given an account definition retreive the service plan ids off of
-%% it.
-%% @end
-%%--------------------------------------------------------------------
--spec get_plan_ids/1 :: (wh_json:json_object()) -> [ne_binary(),...] | [].
-get_plan_ids(JObj) ->
- wh_json:get_value(?WH_SERVICE_PLANS_FIELD, JObj, []).
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Given a service plan retreive the id
-%% @end
-%%--------------------------------------------------------------------
--spec get_id/1 :: (#wh_service_plan{}) -> ne_binary().
-get_id(#wh_service_plan{id=Id}) -> Id.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec add_plan_id/3 :: (wh_json:json_object(), ne_binary(), ne_binary()) -> wh_json:json_object().
-add_plan_id(JObj, PlanId, Reseller) ->
- case is_valid_plan_id(PlanId, Reseller) of
- false -> JObj;
- true ->
- lager:debug("adding service plan id ~s", [PlanId]),
- Plans = [PlanId|lists:delete(PlanId, get_plan_ids(JObj))],
- wh_json:set_value(?WH_SERVICE_PLANS_FIELD, Plans, JObj)
- end.
-
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec set_service_plans/3 :: (wh_json:json_object(), 'undefined' | ne_binary() | [ne_binary(),...], ne_binary())
- -> wh_json:json_object().
-set_service_plans(JObj, undefined, Reseller) ->
- case wh_reseller:get_default_service_plan(Reseller) of
- undefined -> JObj;
- ServicePlan -> set_service_plans(JObj, [ServicePlan], Reseller)
- end;
-set_service_plans(JObj, ServicePlan, Reseller) when not is_list(ServicePlan) ->
- set_service_plans(JObj, [ServicePlan], Reseller);
-set_service_plans(JObj, ServicePlans, Reseller) ->
- lists:foldl(fun(P, J) -> add_plan_id(J, P, Reseller) end, JObj, ServicePlans).
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec is_valid_plan_id/2 :: (ne_binary(), ne_binary()) -> boolean().
-is_valid_plan_id(PlanId, Reseller) ->
- case fetch(Reseller, PlanId) of
- {ok, _} -> true;
- {error, _} -> false
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Given an service category get a listing of all the addons
-%% @end
-%%--------------------------------------------------------------------
--spec get_category_addons/2 :: (ne_binary(), #wh_service_plan{}) -> [{ne_binary(), ne_binary()},...] | [].
-get_category_addons(Category, #wh_service_plan{plan=JObj, cascade_only=CascadeOnly}) ->
- Plan = wh_json:get_value(Category, JObj, wh_json:new()),
- [{PlanId, AddOnId}
- || Key <- wh_json:get_keys(Plan)
- ,(AddOnId = wh_json:get_ne_value([Key, <<"add_on">>], Plan)) =/= undefined
- ,(PlanId = wh_json:get_ne_value([Key, <<"plan">>], Plan)) =/= undefined
- ,((not CascadeOnly) orelse wh_json:is_true([Key, <<"cascade">>], Plan))
- ].
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Find the subscription name on a service plan for a given service
-%% element
-%% @end
-%%--------------------------------------------------------------------
--spec get_recurring_plan/3 :: (ne_binary(), ne_binary(), plan()) -> 'undefined' | {ne_binary(), ne_binary()}.
-get_recurring_plan(Category, Name, Plan) ->
- case get_item(Category, Name, Plan) of
- undefined -> undefined;
- Item ->
- PlanId = wh_json:get_value(<<"plan">>, Item),
- AddOnId = wh_json:get_value(<<"add_on">>, Item),
- case wh_util:is_empty(PlanId) orelse wh_util:is_empty(AddOnId) of
- true -> undefined;
- false -> {PlanId, AddOnId}
- end
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Find the subscription name on a service plan for a given service
-%% element
-%% @end
-%%--------------------------------------------------------------------
--spec get_activation_charge/3 :: (ne_binary(), ne_binary(), plan()) -> 'undefined' | ne_binary().
-get_activation_charge(Category, Name, Plan) ->
- case get_item(Category, Name, Plan) of
- undefined -> undefined;
- Item -> wh_json:get_ne_value(<<"activation_charge">>, Item)
- end.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec get_base_mrc/1 :: (#wh_service_plan{}) -> wh_json:json_objects().
-get_base_mrc(#wh_service_plan{plan=JObj}) ->
- wh_json:get_value(<<"base_mrc">>, JObj, []).
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Find the subscription name on a service plan for a given service
-%% element
-%% @end
-%%--------------------------------------------------------------------
--spec get_item/3 :: (ne_binary(), ne_binary(), #wh_service_plan{}) -> 'undefined' | wh_json:json_object().
-get_item(<<"phone_numbers">>, PhoneNumber, #wh_service_plan{plan=JObj, cascade_only=CascadeOnly}) ->
- case wh_json:get_value(<<"phone_numbers">>, JObj) of
- undefined -> undefined;
- PhoneNumbers ->
- Regexs = wh_json:get_keys(PhoneNumbers),
- case [wh_json:get_value(Regex, PhoneNumbers)
- || Regex <- Regexs
- ,re:run(PhoneNumber, Regex) =/= nomatch
- ]
- of
- [] -> undefined;
- [Item|_] ->
- case (not CascadeOnly) orelse wh_json:is_true(<<"cascade">>, Item) of
- false ->
- lager:debug("ignoring none cascade phone_number ~s", [PhoneNumber]),
- undefined;
- true ->
- wh_json:set_values([{<<"category">>, <<"phone_numbers">>}
- ,{<<"item">>, PhoneNumber}
- ,{<<"id">>, wh_json:get_value(<<"_id">>, JObj)}
- ], Item)
- end
- end
- end;
-get_item(Category, Name, #wh_service_plan{plan=JObj, cascade_only=CascadeOnly}) ->
- case wh_json:get_ne_value([Category, Name], JObj) of
- undefined -> undefined;
- Item ->
- case (not CascadeOnly) orelse wh_json:is_true(<<"cascade">>, Item) of
- false ->
- lager:debug("ignoring none cascade item ~s ~s", [Category, Name]),
- undefined;
- true ->
- wh_json:set_values([{<<"category">>, Category}
- ,{<<"item">>, Name}
- ,{<<"id">>, wh_json:get_value(<<"_id">>, JObj)}
- ], Item)
- end
- end.
View
12 lib/whistle_service-1.0.0/src/whistle_service.app.src
@@ -1,12 +0,0 @@
-{application, whistle_service,
- [
- {description, "Skel - A whistle_serviceeton application useful for quickly creating services"},
- {vsn, "1"},
- {registered, []},
- {applications, [
- kernel,
- stdlib
- ]},
- {mod, { whistle_service_app, []}},
- {env, []}
- ]}.
View
141 lib/whistle_service-1.0.0/src/whistle_service_maintenance.erl
@@ -1,141 +0,0 @@
-%%%-------------------------------------------------------------------
-%%% @copyright (C) 2012, VoIP INC
-%%% @doc
-%%%
-%%% @end
-%%%-------------------------------------------------------------------
--module(whistle_service_maintenance).
-
--export([credit/2, credit/3]).
--export([debit/2, debit/3]).
--export([sync_account/1]).
-
--include_lib("whistle/include/wh_types.hrl").
--include_lib("whistle/include/wh_databases.hrl").
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Add arbitrary credit to an account, without charing the accounts
-%% credit card
-%% @end
-%%--------------------------------------------------------------------
--spec credit/2 :: (text(), text()) -> 'no_return'.
--spec credit/3 :: (text(), text(), text()) -> 'no_return'.
-
-credit(Account, Amount) ->
- credit(Account, Amount, <<"System administrator discretionary credit addition">>).
-
-credit(Account, Amount, Description) when not is_binary(Account) ->
- credit(wh_util:to_binary(Account), Amount, Description);
-credit(Account, Amount, Description) when not is_float(Amount) ->
- credit(Account, wh_util:to_float(Amount), Description);
-credit(Account, Amount, Description) when not is_binary(Description) ->
- credit(Account, Amount, wh_util:to_binary(Description));
-credit(Account, Amount, Description) ->
- AccountId = wh_util:format_account_id(Account, raw),
- AccountDb = wh_util:format_account_id(Account, encoded),
- Timestamp = wh_util:current_tstamp(),
- JObj = wh_json:from_list([{<<"reason">>, <<"system administrator reconciliation">>}
- ,{<<"description">>, Description}
- ,{<<"account_id">>, AccountId}
- ,{<<"amount">>, wapi_money:dollars_to_units(Amount)}
- ,{<<"pvt_account_id">>, AccountId}
- ,{<<"pvt_account_db">>, AccountDb}
- ,{<<"pvt_type">>, <<"credit">>}
- ,{<<"pvt_created">>, Timestamp}
- ,{<<"pvt_modified">>, Timestamp}
- ,{<<"pvt_vsn">>, 1}
- ]),
- case couch_mgr:save_doc(AccountDb, JObj) of
- {ok, _} -> io:format("credited account ~s $~w~n", [AccountId, Amount]);
- {error, R} -> io:format("failed to credited account ~s: ~p~n", [AccountId, R])
- end,
- no_return.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Add arbitrary debit to an account, without charing the accounts
-%% debit card
-%% @end
-%%--------------------------------------------------------------------
--spec debit/2 :: (text(), text()) -> 'no_return'.
--spec debit/3 :: (text(), text(), text()) -> 'no_return'.
-
-debit(Account, Amount) ->
- debit(Account, Amount, <<"System administrator discretionary debit addition">>).
-
-debit(Account, Amount, Description) when not is_binary(Account) ->
- debit(wh_util:to_binary(Account), Amount, Description);
-debit(Account, Amount, Description) when not is_float(Amount) ->
- debit(Account, wh_util:to_float(Amount), Description);
-debit(Account, Amount, Description) when not is_binary(Description) ->
- debit(Account, Amount, wh_util:to_binary(Description));
-debit(Account, Amount, Description) ->
- AccountId = wh_util:format_account_id(Account, raw),
- AccountDb = wh_util:format_account_id(Account, encoded),
- Timestamp = wh_util:current_tstamp(),
- JObj = wh_json:from_list([{<<"reason">>, <<"system administrator reconciliation">>}
- ,{<<"description">>, Description}
- ,{<<"account_id">>, AccountId}
- ,{<<"amount">>, wapi_money:dollars_to_units(Amount)}
- ,{<<"pvt_account_id">>, AccountId}
- ,{<<"pvt_account_db">>, AccountDb}
- ,{<<"pvt_type">>, <<"debit">>}
- ,{<<"pvt_created">>, Timestamp}
- ,{<<"pvt_modified">>, Timestamp}
- ,{<<"pvt_vsn">>, 1}
- ]),
- case couch_mgr:save_doc(AccountDb, JObj) of
- {ok, _} -> io:format("debited account ~s $~w~n", [AccountId, Amount]);
- {error, R} -> io:format("failed to update account ~s ledger: ~p~n", [AccountId, R])
- end,
- no_return.
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%%
-%% @end
-%%--------------------------------------------------------------------
--spec sync_account/1 :: (text()) -> 'no_return'.
-sync_account(Account) when not is_binary(Account) ->
- sync_account(wh_util:to_binary(Account));
-sync_account(Account) ->
- AccountId = wh_util:format_account_id(Account, raw),
- AccountDb = wh_util:format_account_id(Account, encoded),
- case wh_resellers:fetch(AccountId) of
- {error, no_service_plan} ->
- io:format("account has no service plans~n", []),
- no_return;
- {ok, R1} ->
- lager:debug("sync devices~n", []),
- {ok, Devices} = couch_mgr:get_all_results(AccountDb, <<"devices/crossbar_listing">>),
- DeviceTypes = [get_device_type(Device) || Device <- Devices],
- R2 = wh_service_devices:update(DeviceTypes, R1, updated),
-
- lager:debug("sync numbers~n", []),
- {ok, PhoneNumbers} = couch_mgr:open_doc(AccountDb, <<"phone_numbers">>),
- R3 = wh_service_numbers:update(PhoneNumbers, R2),
-
- lager:debug("sync limits~n", []),
- {ok, Limits} = case couch_mgr:open_doc(AccountDb, <<"limits">>) of
- {ok, _}=Ok -> Ok;
- {error, not_found} -> {ok, wh_json:new()}
- end,
- R4 = wh_service_numbers:update(Limits, R3),
-
- lager:debug("commit changess~n", []),
- ok = wh_resellers:commit_changes(R4)
- end.
-
-
--spec get_device_type/1 :: (wh_json:json_object()) -> ne_binary().
-get_device_type(JObj) ->
- DeviceType = wh_json:get_value(<<"device_type">>, JObj
- ,wh_json:get_value([<<"value">>, <<"device_type">>], JObj, <<"sip_device">>)),
- case lists:member(DeviceType, [<<"sip_device">>, <<"cellphone">>, <<"softphone">>]) of
- true -> DeviceType;
- false -> <<"sip_device">>
- end.
View
0 lib/whistle_service-1.0.0/Makefile → lib/whistle_services-1.0.0/Makefile
File renamed without changes.
View
0 lib/whistle_service-1.0.0/doc/README.org → lib/whistle_services-1.0.0/doc/README.org
File renamed without changes.
View
0 ...stle_service-1.0.0/include/wh_service.hrl → ...tle_services-1.0.0/include/wh_service.hrl
File renamed without changes.
View
0 ...vice-1.0.0/priv/example_service_plan.json → ...ices-1.0.0/priv/example_service_plan.json
File renamed without changes.
View
0 lib/whistle_service-1.0.0/rebar.config → lib/whistle_services-1.0.0/rebar.config
File renamed without changes.
View
31 lib/whistle_services-1.0.0/src/services/wh_service_devices.erl
@@ -0,0 +1,31 @@
+%%%-------------------------------------------------------------------
+%%% @copyright (C) 2012, VoIP, INC
+%%% @doc
+%%%
+%%% @end
+%%% @contributors
+%%%-------------------------------------------------------------------
+-module(wh_service_devices).
+
+-export([reconcile/1]).
+
+-include_lib("whistle_services/src/whistle_services.hrl").
+
+-spec reconcile/1 :: (wh_services:services()) -> wh_services:services().
+reconcile(Services) ->
+ AccountId = wh_services:account_id(Services),
+ AccountDb = wh_util:format_account_id(AccountId, encoded),
+ ViewOptions = [reduce
+ ,group
+ ],
+ case couch_mgr:get_results(AccountDb, <<"services/devices">>, ViewOptions) of
+ {error, _R} ->
+ lager:debug("unable to get current devices in service: ~p", [_R]),
+ Services;
+ {ok, JObjs} ->
+ lists:foldl(fun(JObj, S) ->
+ Item = wh_json:get_value(<<"key">>, JObj),
+ Quantity = wh_json:get_integer_value(<<"value">>, JObj, 0),
+ wh_services:update(<<"devices">>, Item, Quantity, S)
+ end, wh_services:reset_category(<<"devices">>, Services), JObjs)
+ end.
View
33 lib/whistle_services-1.0.0/src/services/wh_service_limits.erl
@@ -0,0 +1,33 @@
+%%%-------------------------------------------------------------------
+%%% @copyright (C) 2012, VoIP, INC
+%%% @doc
+%%%
+%%% @end
+%%% @contributors
+%%%-------------------------------------------------------------------
+-module(wh_service_limits).
+
+-export([reconcile/1]).
+
+-include_lib("whistle_services/src/whistle_services.hrl").
+
+-spec reconcile/1 :: (wh_services:services()) -> wh_services:services().
+reconcile(Services) ->
+ AccountId = wh_services:account_id(Services),
+ AccountDb = wh_util:format_account_id(AccountId, encoded),
+ case couch_mgr:open_doc(AccountDb, <<"limits">>) of
+ {error, _R} ->
+ lager:debug("unable to get current limits in service: ~p", [_R]),
+ Services;
+ {ok, JObj} ->
+ Routines = [fun(S) ->
+ Quantity = wh_json:get_integer_value(<<"twoway_trunks">>, JObj, 0),
+ wh_services:update(<<"limits">>, <<"twoway_trunks">>, Quantity, S)
+ end
+ ,fun(S) ->
+ Quantity = wh_json:get_integer_value(<<"inbound_trunks">>, JObj, 0),
+ wh_services:update(<<"limits">>, <<"inbound_trunks">>, Quantity, S)
+ end
+ ],
+ lists:foldl(fun(F, S) -> F(S) end, wh_services:reset_category(<<"limits">>, Services), Routines)
+ end.
View
57 lib/whistle_services-1.0.0/src/services/wh_service_phone_numbers.erl
@@ -0,0 +1,57 @@
+%%%-------------------------------------------------------------------
+%%% @copyright (C) 2012, VoIP, INC
+%%% @doc
+%%%
+%%% @end
+%%% @contributors
+%%%-------------------------------------------------------------------
+-module(wh_service_phone_numbers).
+
+-export([reconcile/1]).
+
+-include_lib("whistle_services/src/whistle_services.hrl").
+
+-spec reconcile/1 :: (wh_services:services()) -> wh_services:services().
+reconcile(Services) ->
+ AccountId = wh_services:account_id(Services),
+ AccountDb = wh_util:format_account_id(AccountId, encoded),
+ case couch_mgr:open_doc(AccountDb, <<"phone_numbers">>) of
+ {error, _R} ->
+ lager:debug("unable to get current phone_numbers in service: ~p", [_R]),
+ Services;
+ {ok, JObj} ->
+ S1 = wh_services:reset_category(<<"phone_numbers">>, Services),
+ S2 = wh_services:reset_category(<<"number_features">>, S1),
+ update_numbers(wh_json:get_keys(wh_json:public_fields(JObj)), JObj, S2)
+ end.
+
+-spec update_numbers/3 :: ([ne_binary(),...] | [], wh_json:json_object(), wh_services:services()) -> wh_services:services().
+update_numbers([], _, Services) ->
+ Services;
+update_numbers([Number|Numbers], JObj, Services) ->
+ case wnm_util:is_reconcilable(Number) of
+ false -> Services;
+ true ->
+ Routines = [fun(S) -> update_number_quantities(Number, S) end
+ ,fun(S) ->
+ Features = wh_json:get_value([Number, <<"features">>], JObj, []),
+ update_feature_quantities(Features, S)
+ end
+ ],
+ UpdatedServices = lists:foldl(fun(F, S) -> F(S) end, Services, Routines),
+ update_numbers(Numbers, JObj, UpdatedServices)
+ end.
+
+-spec update_number_quantities/2 :: (ne_binary(), wh_services:services()) -> wh_services:services().
+update_number_quantities(Number, Services) ->
+ Classification = wnm_util:classify_number(Number),
+ Quantity = wh_services:get_quantity(<<"phone_numbers">>, Classification, Services),
+ wh_services:update(<<"phone_numbers">>, Classification, Quantity + 1, Services).
+
+-spec update_feature_quantities/2 :: ([ne_binary(),...] | [], wh_services:services()) -> wh_services:services().
+update_feature_quantities([], Services) ->
+ Services;
+update_feature_quantities([Feature|Features], Services) ->
+ Quantity = wh_services:get_quantity(<<"number_features">>, Feature, Services),
+ UpdatedServices = wh_services:update(<<"number_features">>, Feature, Quantity + 1, Services),
+ update_feature_quantities(Features, UpdatedServices).
View
109 lib/whistle_services-1.0.0/src/wh_services.erl
@@ -0,0 +1,109 @@
+%%%-------------------------------------------------------------------
+%%% @copyright (C) 2012, VoIP, INC
+%%% @doc
+%%%
+%%% @end
+%%% @contributors
+%%%-------------------------------------------------------------------
+-module(wh_services).
+
+-export([reconcile/1]).
+-export([fetch/1]).
+-export([update/4]).
+-export([save/1]).
+
+-export([account_id/1]).
+-export([get_quantity/3]).
+-export([reset_category/2]).
+
+-include_lib("whistle_services/src/whistle_services.hrl").
+-include_lib("whistle/include/wh_databases.hrl").
+
+-record(wh_services, {account_id
+ ,dirty = false
+ ,jobj = wh_json:new()
+ ,updates = wh_json:new()
+ }).
+
+-type(services() :: #wh_services{}).
+-export_type([services/0]).
+
+-spec reconcile/1 :: (ne_binary()) -> services().
+reconcile(Account) ->
+ ServiceModules = get_service_modules(),
+ Services = lists:foldl(fun(M, S) ->
+ M:reconcile(S)
+ end, fetch(Account), ServiceModules),
+ save(Services).
+
+-spec fetch/1 :: (ne_binary()) -> services().
+fetch(Account) ->
+ AccountId = wh_util:format_account_id(Account, raw),
+ case couch_mgr:open_doc(?WH_SERVICES_DB, AccountId) of
+ {ok, JObj} ->
+ #wh_services{account_id=AccountId, jobj=JObj};
+ {error, _R} ->
+ lager:debug("unable to open account ~s services doc: ~p", [_R]),
+ TStamp = wh_util:current_tstamp(),
+ New = [{<<"_id">>, AccountId}
+ ,{<<"pvt_created">>, TStamp}
+ ,{<<"pvt_modified">>, TStamp}
+ ,{<<"pvt_type">>, <<"service">>}
+ ,{<<"pvt_vsn">>, <<"1">>}
+ ],
+ #wh_services{account_id=AccountId, jobj=wh_json:from_list(New)}
+ end.
+
+-spec update/4 :: (ne_binary(), ne_binary(), integer(), services()) -> services().
+update(Category, Item, Quantity, Services) when not is_integer(Quantity) ->
+ update(Category, Item, wh_util:to_integer(Quantity), Services);
+update(Category, Item, Quantity, #wh_services{updates=JObj}=Services) when is_binary(Category), is_binary(Item) ->
+ Services#wh_services{updates=wh_json:set_value([Category, Item], Quantity, JObj)}.
+
+-spec save/1 :: (services()) -> services().
+save(#wh_services{jobj=JObj, updates=Updates, account_id=AccountId, dirty=Dirty}=Services) ->
+ Props = [{<<"_id">>, AccountId}
+ ,{<<"pvt_dirty">>, Dirty}
+ ,{<<"pvt_modified">>, wh_util:current_tstamp()}
+ ],
+ UpdatedJObj = wh_json:merge_jobjs(wh_json:set_values(Props, Updates), JObj),
+ case couch_mgr:save_doc(?WH_SERVICES_DB, UpdatedJObj) of
+ {ok, NewJObj} ->
+ Services#wh_services{jobj=NewJObj};
+ {error, not_found} ->
+ true = couch_mgr:db_create(?WH_SERVICES_DB),
+ save(Services);
+ {error, conflict} ->
+ {ok, Existing} = couch_mgr:open_doc(?WH_SERVICES_DB, AccountId),
+ save(Services#wh_services{jobj=Existing})
+ end.
+
+-spec account_id/1 :: (services()) -> ne_binary().
+account_id(#wh_services{account_id=AccountId}) ->
+ AccountId.
+
+-spec get_quantity/3 :: (ne_binary(), ne_binary(), services()) -> integer().
+get_quantity(Category, Item, #wh_services{updates=JObj}) ->
+ wh_json:get_integer_value([Category, Item], JObj, 0).
+
+-spec reset_category/2 :: (ne_binary(), services()) -> services().
+reset_category(Category, #wh_services{updates=JObj}=Services) ->
+ Services#wh_services{updates=wh_json:set_value(Category, wh_json:new(), JObj)}.
+
+-spec get_service_modules/0 :: () -> [atom(),...] | [].
+get_service_modules() ->
+ case whapps_config:get(?WHS_CONFIG_CAT, <<"modules">>) of
+ undefined ->
+ Mods = [Mod
+ || P <- filelib:wildcard([code:lib_dir(whistle_services), "/ebin/wh_service_*.beam"])
+ ,begin
+ Name = wh_util:to_binary(filename:rootname(filename:basename(P))),
+ (Mod = wh_util:try_load_module(Name)) =/= false
+ end
+ ],
+ lager:debug("found service modules: ~p", [Mods]),
+ Mods;
+ Modules ->
+ lager:debug("configured service modules: ~p", [Modules]),
+ [Module || M <- Modules, (Module = wh_util:try_load_module(M)) =/= false]
+ end.
View
12 lib/whistle_services-1.0.0/src/whistle_services.app.src
@@ -0,0 +1,12 @@
+{application, whistle_services,
+ [
+ {description, "Whistle Services provides billing and service limit support"},
+ {vsn, "1"},
+ {registered, []},
+ {applications, [
+ kernel,
+ stdlib
+ ]},
+ {mod, { whistle_services_app, []}},
+ {env, []}
+ ]}.
View
4 lib/whistle_services-1.0.0/src/whistle_services.hrl
@@ -0,0 +1,4 @@
+-include_lib("whistle/include/wh_types.hrl").
+
+-define(WH_SERVICES_DB, <<"services">>).
+-define(WHS_CONFIG_CAT, <<"services">>).
View
4 ...service-1.0.0/src/whistle_service_app.erl → ...rvices-1.0.0/src/whistle_services_app.erl
@@ -5,7 +5,7 @@
%%% @end
%%% @contributors
%%%-------------------------------------------------------------------
--module(whistle_service_app).
+-module(whistle_services_app).
-behaviour(application).
@@ -21,7 +21,7 @@
%%--------------------------------------------------------------------
-spec start/2 :: (term(), term()) -> {'ok', pid()} | {'error', startlink_err()}.
start(_Type, _Args) ->
- case whistle_service_sup:start_link() of
+ case whistle_services_sup:start_link() of
{ok, P} -> {ok, P};
{error, {already_started, P} } -> {ok, P};
{error, _}=E -> E
View
2 ...service-1.0.0/src/whistle_service_sup.erl → ...rvices-1.0.0/src/whistle_services_sup.erl
@@ -5,7 +5,7 @@
%%% @end
%%% @contributors
%%%-------------------------------------------------------------------
--module(whistle_service_sup).
+-module(whistle_services_sup).
-behaviour(supervisor).
View
10 whistle_apps/apps/crossbar/priv/couchdb/account/services.json
@@ -0,0 +1,10 @@
+{
+ "_id": "_design/services"
+ ,"language": "javascript"
+ ,"views": {
+ "devices": {
+ "map": "function(doc) { if (doc.pvt_type != 'device' || doc.pvt_deleted || !doc.enabled) return; emit(doc.device_type || 'sip_device', 1); }",
+ "reduce": "_sum"
+ }
+ }
+}

0 comments on commit bb3d8a8

Please sign in to comment.