Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

WHISTLE-1217: clean up and start of the crawler

  • Loading branch information...
commit b9ebf7611c1144444b2de77e63ad57c703773fd9 1 parent 5937f94
@k-anderson k-anderson authored
View
3  lib/whistle-1.0.0/include/wh_types.hrl
@@ -27,6 +27,9 @@
-type wh_deeplist() :: [term() | wh_deeplist()].
+-type wh_std_return() :: {'ok', _} | {'error', _}.
+-type wh_std_return(Thing) :: {'ok', Thing} | {'error', _}.
+
%% non-empty binary
-define(NE_BINARY, <<_:8,_/binary>>).
-type ne_binary() :: <<_:8,_:_*8>>.
View
3  lib/whistle_services-1.0.0/priv/couchdb/views/services.json
@@ -5,6 +5,9 @@
"cascade_quantities": {
"map": "function (doc) {if (doc.pvt_type != 'service' || doc.pvt_deleted || !doc.quantities) return;for (var key in doc.quantities) {var obj = doc.quantities[key];for (var prop in obj) {if (obj[prop] < 1) continue;for (var idx in doc.pvt_tree) {emit([doc.pvt_tree[idx] || doc._id, key, prop], obj[prop]);}}}}",
"reduce": "_sum"
+ },
+ "dirty": {
+ "map": "function (doc) {if (doc.pvt_type != 'service' || doc.pvt_deleted || !doc.pvt_dirty) return; emit(doc.pvt_modified, null); }"
}
}
}
View
36 lib/whistle_services-1.0.0/src/bookkeepers/wh_bookkeeper_braintree.erl
@@ -16,7 +16,7 @@
}).
-record(wh_service_updates, {bt_subscriptions = []
- ,billing_id
+ ,account_id
,bt_customer
}).
@@ -26,27 +26,35 @@
%%
%% @end
%%--------------------------------------------------------------------
-sync(Items, BillingId) ->
- Customer = fetch_or_create_customer(BillingId),
- sync(wh_service_items:to_list(Items), BillingId, #wh_service_updates{bt_customer=Customer}).
+sync(Items, AccountId) ->
+ Customer = fetch_or_create_customer(AccountId),
+ sync(wh_service_items:to_list(Items), AccountId, #wh_service_updates{bt_customer=Customer}).
-sync([], _BillingId, #wh_service_updates{bt_subscriptions=Subscriptions}) ->
+sync([], _AccountId, #wh_service_updates{bt_subscriptions=Subscriptions}) ->
_ = [braintree_subscription:update(Subscription)
|| #wh_service_update{bt_subscription=Subscription} <- Subscriptions
],
ok;
-sync([ServiceItem|ServiceItems], BillingId, Updates) ->
+sync([ServiceItem|ServiceItems], AccountId, Updates) ->
case braintree_plan_addon_id(ServiceItem) of
- {undefined, _} -> sync(ServiceItems, BillingId, Updates);
- {_, undefined} -> sync(ServiceItems, BillingId, Updates);
+ {undefined, _} ->
+ lager:debug("service item had no plan id: ~p", [ServiceItem]),
+ sync(ServiceItems, AccountId, Updates);
+ {_, undefined} ->
+ lager:debug("service item had no add on id: ~p", [ServiceItem]),
+ sync(ServiceItems, AccountId, Updates);
{PlanId, AddOnId}->
Quantity = wh_service_item:quantity(ServiceItem),
Routines = [fun(S) -> braintree_subscription:update_addon_quantity(S, AddOnId, Quantity) end
+ ,fun(S) ->
+ Rate = wh_service_item:rate(ServiceItem),
+ braintree_subscription:update_addon_amount(S, AddOnId, Rate)
+ end
,fun(S) -> handle_single_discount(ServiceItem, S) end
,fun(S) -> handle_cumulative_discounts(ServiceItem, S) end
],
Subscription = lists:foldl(fun(F, S) -> F(S) end, fetch_or_create_subscription(PlanId, Updates), Routines),
- sync(ServiceItems, BillingId, update_subscriptions(PlanId, Subscription, Updates))
+ sync(ServiceItems, AccountId, update_subscriptions(PlanId, Subscription, Updates))
end.
%%--------------------------------------------------------------------
@@ -96,14 +104,14 @@ handle_cumulative_discounts(ServiceItem, Subscription) ->
%% @end
%%--------------------------------------------------------------------
-spec fetch_or_create_customer/1 :: (ne_binary()) -> braintree_customer:customer().
-fetch_or_create_customer(BillingId) ->
- lager:debug("requesting braintree customer ~s", [BillingId]),
- try braintree_customer:find(BillingId) of
+fetch_or_create_customer(AccountId) ->
+ lager:debug("requesting braintree customer ~s", [AccountId]),
+ try braintree_customer:find(AccountId) of
Customer -> Customer
catch
throw:{not_found, _} ->
- lager:debug("creating new braintree customer ~s", [BillingId]),
- braintree_customer:create(BillingId)
+ lager:debug("creating new braintree customer ~s", [AccountId]),
+ braintree_customer:create(AccountId)
end.
%%--------------------------------------------------------------------
View
69 lib/whistle_services-1.0.0/src/wh_service_invoice.erl
@@ -1,69 +0,0 @@
-%%%-------------------------------------------------------------------
-%%% @copyright (C) 2012, VoIP, INC
-%%% @doc
-%%%
-%%% @end
-%%% @contributors
-%%%-------------------------------------------------------------------
--module(wh_service_invoice).
-
--include_lib("whistle_services/src/whistle_services.hrl").
-
--export([sync/1]).
-
--record(wh_invoice, {account_id = undefined
- ,account_db = undefined
- ,billing_id = undefined
- ,service_items = wh_service_items:empty() :: wh_service_items:items()
- ,service_plans = wh_service_plans:empty() :: wh_service_plans:plans()
- ,services = wh_services:empty()
- }).
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Create a collection of billable items and envoke the bookkeeper
-%% to actualize any billing changes.
-%% @end
-%%--------------------------------------------------------------------
--spec sync/1 :: (ne_binary()) -> #wh_invoice{}.
-sync(Account) ->
- #wh_invoice{billing_id=BillingId, service_items=ServiceItems} = create(Account),
- wh_bookkeeper_braintree:sync(ServiceItems, BillingId).
-
-%%--------------------------------------------------------------------
-%% @public
-%% @doc
-%% Create a new invoice for a given account. An invoice is a collection
-%% of service plans (provided by multiple vendors) applied to the
-%% services the account is currently consuming to generate a collection
-%% of items.
-%% @end
-%%--------------------------------------------------------------------
--spec create/1 :: (ne_binary()) -> #wh_invoice{}.
-create(Account) ->
- Routines = [fun(I) -> I#wh_invoice{account_id=wh_util:format_account_id(Account, raw)
- ,account_db=wh_util:format_account_id(Account, encoded)}
- end
- ,fun(#wh_invoice{account_db=AccountDb, account_id=AccountId}=I) ->
- case couch_mgr:open_doc(AccountDb, AccountId) of
- {ok, JObj} ->
- BillingId = wh_json:get_ne_value(<<"billing_id">>, JObj, AccountId),
- lager:debug("using billing id ~s for account ~s", [BillingId, AccountId]),
- I#wh_invoice{billing_id=BillingId};
- {error, _R} ->
- lager:debug("unable to open account definition for ~s (using account as billing id): ~p", [AccountId, _R]),
- I#wh_invoice{billing_id=AccountId}
- end
- end
- ,fun(#wh_invoice{account_id=AccountId}=I) ->
- I#wh_invoice{services=wh_services:fetch(AccountId)}
- end
- ,fun(#wh_invoice{billing_id=BillingId}=I) ->
- I#wh_invoice{service_plans=wh_service_plans:fetch(BillingId)}
- end
- ,fun(#wh_invoice{service_plans=ServicePlans, services=Services}=I) ->
- I#wh_invoice{service_items=wh_service_plans:create_items(Services, ServicePlans)}
- end
- ],
- lists:foldl(fun(F, I) -> F(I) end, #wh_invoice{}, Routines).
View
197 lib/whistle_services-1.0.0/src/wh_service_invoices.erl
@@ -7,4 +7,201 @@
%%%-------------------------------------------------------------------
-module(wh_service_invoices).
+-behaviour(gen_server).
+
+-export([start_link/0]).
+-export([run/0]).
+-export([init/1
+ ,handle_call/3
+ ,handle_cast/2
+ ,handle_info/2
+ ,terminate/2
+ ,code_change/3
+ ]).
+
-include_lib("whistle_services/src/whistle_services.hrl").
+
+-record(state, {}).
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+
+%%--------------------------------------------------------------------
+%% @doc
+%% Starts the server
+%%
+%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
+%% @end
+%%--------------------------------------------------------------------
+start_link() ->
+ gen_server:start_link(?MODULE, [], []).
+
+run() ->
+ maybe_sync_service().
+
+%%%===================================================================
+%%% gen_server callbacks
+%%%===================================================================
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Initializes the server
+%%
+%% @spec init(Args) -> {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%% @end
+%%--------------------------------------------------------------------
+init([]) ->
+ {ok, #state{}}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Handling call messages
+%%
+%% @spec handle_call(Request, From, State) ->
+%% {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} |
+%% {stop, Reason, State}
+%% @end
+%%--------------------------------------------------------------------
+handle_call(_Request, _From, State) ->
+ {reply, {error, not_implemented}, State}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Handling cast messages
+%%
+%% @spec handle_cast(Msg, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% @end
+%%--------------------------------------------------------------------
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Handling all non call/cast messages
+%%
+%% @spec handle_info(Info, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% @end
+%%--------------------------------------------------------------------
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% This function is called by a gen_server when it is about to
+%% terminate. It should be the opposite of Module:init/1 and do any
+%% necessary cleaning up. When it returns, the gen_server terminates
+%% with Reason. The return value is ignored.
+%%
+%% @spec terminate(Reason, State) -> void()
+%% @end
+%%--------------------------------------------------------------------
+terminate(_Reason, _State) ->
+ lager:debug("whistle service invoices terminating: ~p", [_Reason]).
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Convert process state when code is changed
+%%
+%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
+%% @end
+%%--------------------------------------------------------------------
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
+-spec maybe_sync_service/0 :: () -> wh_json:json_objects().
+maybe_sync_service() ->
+ ViewOptions = [{limit, 1}
+ ,include_docs
+ ],
+ case couch_mgr:get_results(?WH_SERVICES_DB, <<"services/dirty">>, ViewOptions) of
+ {error, _}=E -> E;
+ {ok, [JObj]} -> bump_modified(wh_json:get_value(<<"doc">>, JObj));
+ {ok, _} -> {error, no_dirty_services}
+ end.
+
+-spec bump_modified/1 :: (wh_json:json_object()) -> _.
+bump_modified(JObj) ->
+ AccountId = wh_json:get_value(<<"pvt_account_id">>, JObj),
+ UpdatedJObj = wh_json:set_value(<<"pvt_modified">>, wh_util:current_tstamp(), JObj),
+ case couch_mgr:save_doc(?WH_SERVICES_DB, UpdatedJObj) of
+ {error, _}=E ->
+ %% If we conflict or cant save the doc with a new modified timestamp
+ %% then another process is probably handling it, move on
+ E;
+ {ok, NewJObj} ->
+ %% If we can change the timestamp then (since the view requires the
+ %% modified time to be x mins in the past) we have gain exclusive
+ %% control for x mins.... good luck!
+ AccountId = wh_json:get_value(<<"pvt_account_id">>, NewJObj),
+ maybe_follow_billing_id(AccountId, NewJObj)
+ end.
+
+-spec maybe_follow_billing_id/2 :: (ne_binary(), wh_json:json_object()) -> wh_std_return().
+maybe_follow_billing_id(AccountId, JObj) ->
+ case get_billing_id(AccountId, JObj) of
+ AccountId -> sync_services(AccountId, JObj);
+ BillingId -> follow_billing_id(AccountId, BillingId)
+ end.
+
+-spec follow_billing_id/2 :: (ne_binary(), ne_binary()) -> wh_std_return().
+follow_billing_id(AccountId, BillingId) ->
+ case mark_dirty(BillingId) of
+ {ok, _} -> mark_clean(AccountId);
+ {error, _R}=E ->
+ lager:debug("unable to mark billing services ~s dirty: ~p", [BillingId, _R]),
+ E
+ end.
+
+-spec sync_services/2 :: (ne_binary(), wh_json:json_object()) -> wh_std_return().
+sync_services(AccountId, ServiceJObj) ->
+ ServiceItems = wh_service_plans:create_items(ServiceJObj),
+ %% TODO: support other bookkeepers...
+ try wh_bookkeeper_braintree:sync(ServiceItems, AccountId) of
+ _ -> mark_clean(AccountId)
+ catch
+ _E:R ->
+ lager:debug("unable to sync services(~p): ~p", [_E, R]),
+ {error, R}
+ end.
+
+-spec get_billing_id/2 :: (ne_binary(), wh_json:json_object()) -> ne_binary().
+get_billing_id(AccountId, JObj) ->
+ case wh_json:is_true(<<"pvt_reseller">>, JObj) of
+ true -> AccountId;
+ false -> wh_json:get_ne_value(<<"billing_id">>, JObj, AccountId)
+ end.
+
+-spec mark_dirty/1 :: (ne_binary()) -> wh_std_return().
+mark_dirty(AccountId) ->
+ case couch_mgr:open_doc(?WH_SERVICES_DB, AccountId) of
+ {error, _}=E -> E;
+ {ok, JObj} -> couch_mgr:save_doc(?WH_SERVICES_DB, wh_json:set_value(<<"pvt_dirty">>, true, JObj))
+ end.
+
+-spec mark_clean/1 :: (ne_binary()) -> wh_std_return().
+mark_clean(AccountId) ->
+ case couch_mgr:open_doc(?WH_SERVICES_DB, AccountId) of
+ {error, _}=E -> E;
+ {ok, JObj} -> couch_mgr:save_doc(?WH_SERVICES_DB, wh_json:set_value(<<"pvt_dirty">>, false, JObj))
+ end.
View
84 lib/whistle_services-1.0.0/src/wh_service_items.erl
@@ -59,39 +59,61 @@ find(Category, Item, ServiceItems) ->
%%--------------------------------------------------------------------
-spec update/2 :: (wh_service_item:item(), items()) -> wh_service_item:items().
update(ServiceItem, ServiceItems) ->
+ _ = log_update(ServiceItem),
+ Key = {wh_service_item:category(ServiceItem), wh_service_item:item(ServiceItem)},
+ dict:store(Key, ServiceItem, ServiceItems).
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Nasty conditional logging (but functional).... bleh...
+%% @end
+%%--------------------------------------------------------------------
+-spec log_update/1 :: (wh_service_item:item()) -> no_return.
+log_update(ServiceItem) ->
Category = wh_service_item:category(ServiceItem),
Item = wh_service_item:item(ServiceItem),
- _ = case wh_service_item:rate(ServiceItem) of
- undefined ->
- lager:debug("set '~s/~s' with quantity ~p @ default rate"
- ,[Category, Item, wh_service_item:quantity(ServiceItem)]);
- Rate ->
- lager:debug("set '~s/~s' with quantity ~p @ $~p"
- ,[Category, Item, wh_service_item:quantity(ServiceItem), Rate])
- end,
+ _ = log_update_rate(Category, Item, ServiceItem),
+ _ = log_update_cumulative_discount(Category, Item, ServiceItem),
+ log_update_single_discount(Category, Item, ServiceItem).
+
+-spec log_update_rate/3 :: (ne_binary(), ne_binary(), wh_service_item:item()) -> 'ok'.
+log_update_rate(Category, Item, ServiceItem) ->
+ case wh_service_item:rate(ServiceItem) of
+ undefined ->
+ lager:debug("set '~s/~s' with quantity ~p @ default rate"
+ ,[Category, Item, wh_service_item:quantity(ServiceItem)]);
+ Rate ->
+ lager:debug("set '~s/~s' with quantity ~p @ $~p"
+ ,[Category, Item, wh_service_item:quantity(ServiceItem), Rate])
+ end.
+
+-spec log_update_cumulative_discount/3 :: (ne_binary(), ne_binary(), wh_service_item:item()) -> 'ok'.
+log_update_cumulative_discount(Category, Item, ServiceItem) ->
CumulativeDiscount = wh_service_item:cumulative_discount(ServiceItem),
- _ = case wh_util:is_empty(CumulativeDiscount)
- orelse wh_service_item:cumulative_discount_rate(ServiceItem)
- of
- true -> ok;
- undefined ->
- lager:debug("set '~s/~s' cumulative discount with quantity ~p @ default rate"
- ,[Category, Item, CumulativeDiscount]);
- CumulativeRate ->
- lager:debug("set '~s/~s' cumulative discount with quantity ~p @ $~p"
- ,[Category, Item, CumulativeDiscount, CumulativeRate])
+ case wh_util:is_empty(CumulativeDiscount)
+ orelse wh_service_item:cumulative_discount_rate(ServiceItem)
+ of
+ true -> ok;
+ undefined ->
+ lager:debug("set '~s/~s' cumulative discount with quantity ~p @ default rate"
+ ,[Category, Item, CumulativeDiscount]);
+ CumulativeRate ->
+ lager:debug("set '~s/~s' cumulative discount with quantity ~p @ $~p"
+ ,[Category, Item, CumulativeDiscount, CumulativeRate])
+
+ end.
- end,
- _ = case wh_service_item:single_discount(ServiceItem)
- andalso wh_service_item:single_discount_rate(ServiceItem)
- of
- false -> ok;
+-spec log_update_single_discount/3 :: (ne_binary(), ne_binary(), wh_service_item:item()) -> 'ok'.
+log_update_single_discount(Category, Item, ServiceItem) ->
+ case wh_service_item:single_discount(ServiceItem)
+ andalso wh_service_item:single_discount_rate(ServiceItem)
+ of
+ false -> ok;
undefined ->
- lager:debug("set '~s/~s' single discount at default rate"
- ,[Category, Item]);
- SingleRate ->
- lager:debug("set '~s/~s' single discount for $~p"
- ,[Category, Item, SingleRate])
- end,
- Key = {wh_service_item:category(ServiceItem), wh_service_item:item(ServiceItem)},
- dict:store(Key, ServiceItem, ServiceItems).
+ lager:debug("set '~s/~s' single discount at default rate"
+ ,[Category, Item]);
+ SingleRate ->
+ lager:debug("set '~s/~s' single discount for $~p"
+ ,[Category, Item, SingleRate])
+ end.
View
6 lib/whistle_services-1.0.0/src/wh_service_plan.erl
@@ -83,7 +83,7 @@ create_items(Category, Item, ServiceItems, ServicePlan, Services) ->
CumulativeQuantity = case wh_json:get_integer_value(<<"maximum">>, CumulativeDiscount, 0) of
Max when Max < Quantity ->
lager:debug("item '~s/~s' quantity ~p exceeds cumulative discount max, using ~p"
- ,[Category, Item, Quantity, Max]),
+ ,[Category, As, Quantity, Max]),
Max;
_ -> Quantity
end,
@@ -95,9 +95,9 @@ create_items(Category, Item, ServiceItems, ServicePlan, Services) ->
wh_service_item:set_cumulative_discount_rate(CumulativeRate, I2)
end
end
- ,fun(I) -> wh_service_item:set_bookkeepers(bookkeeper_jobj(Category, Item, ServicePlan), I) end
+ ,fun(I) -> wh_service_item:set_bookkeepers(bookkeeper_jobj(Category, As, ServicePlan), I) end
],
- ServiceItem = lists:foldl(fun(F, I) -> F(I) end, wh_service_items:find(Category, Item, ServiceItems), Routines),
+ ServiceItem = lists:foldl(fun(F, I) -> F(I) end, wh_service_items:find(Category, As, ServiceItems), Routines),
wh_service_items:update(ServiceItem, ServiceItems)
end.
View
70 lib/whistle_services-1.0.0/src/wh_service_plans.erl
@@ -10,13 +10,15 @@
-include_lib("whistle_services/src/whistle_services.hrl").
-export([empty/0]).
--export([fetch/1]).
--export([create_items/2]).
+-export([from_service_json/1]).
+-export([create_items/1
+ ,create_items/2
+ ]).
-record(wh_service_plans, {vendor_id = undefined
- ,vendor_db = undefined
,plans = []
}).
+
-type(plans() :: [#wh_service_plans{},...] | []).
-export_type([plans/0]).
@@ -28,24 +30,17 @@
%%--------------------------------------------------------------------
-spec empty/0 :: () -> plans().
empty() -> [].
-
+
%%--------------------------------------------------------------------
%% @public
%% @doc
-%% Given an account id fetch object defining the current service
-%% plans that should be applied to the account
+%%
%% @end
%%--------------------------------------------------------------------
--spec fetch/1 :: (ne_binary()) -> plans().
-fetch(AccountId) ->
- Services = case couch_mgr:open_doc(?WH_SERVICES_DB, AccountId) of
- {ok, JObj} -> JObj;
- {error, _R} ->
- lager:debug("unable to open services doc for ~s: ~p", [AccountId, _R]),
- wh_json:new()
- end,
- PlanIds = wh_json:get_keys(<<"plans">>, Services),
- get_plans(PlanIds, Services).
+-spec from_service_json/1 :: (wh_json:json_object()) -> plans().
+from_service_json(ServicesJObj) ->
+ PlanIds = wh_json:get_keys(<<"plans">>, ServicesJObj),
+ get_plans(PlanIds, ServicesJObj).
%%--------------------------------------------------------------------
%% @public
@@ -55,7 +50,14 @@ fetch(AccountId) ->
%% suitable for use with the bookkeepers.
%% @end
%%--------------------------------------------------------------------
--spec create_items/2 :: (plans(), wh_services:services()) -> wh_service_items:items().
+-spec create_items/1 :: (wh_json:json_object()) -> wh_service_items:items().
+-spec create_items/2 :: (wh_services:services(), plans()) -> wh_service_items:items().
+
+create_items(ServiceJObj) ->
+ Services = wh_services:from_service_json(ServiceJObj),
+ ServicePlans = from_service_json(ServiceJObj),
+ create_items(Services, ServicePlans).
+
create_items(Services, ServicePlans) ->
Plans = [Plan
|| ServicePlan <- ServicePlans
@@ -72,6 +74,9 @@ create_items(Services, ServicePlans) ->
%% in the vendors #wh_service_plans data structure.
%% @end
%%--------------------------------------------------------------------
+-spec get_plans/2 :: ([ne_binary(),...] | [], wh_json:json_object()) -> plans().
+-spec get_plans/3 :: ([ne_binary(),...] | [], wh_json:json_object(), plans()) -> plans().
+
get_plans(PlanIds, Sevices) ->
get_plans(PlanIds, Sevices, empty()).
@@ -83,15 +88,24 @@ get_plans([PlanId|PlanIds], Services, ServicePlans) ->
Overrides = wh_json:get_value([<<"plans">>, PlanId, <<"overrides">>], Services, wh_json:new()),
case wh_service_plan:fetch(PlanId, VendorDb, Overrides) of
undefined -> get_plans(PlanIds, Services, ServicePlans);
- Plan ->
- case lists:keyfind(VendorId, #wh_service_plans.vendor_id, ServicePlans) of
- false ->
- ServicePlan = #wh_service_plans{vendor_id = VendorId
- ,vendor_db = VendorDb
- ,plans = [Plan]},
- get_plans(PlanIds, Services, [ServicePlan|ServicePlans]);
- #wh_service_plans{plans=Plans}=ServicePlan ->
- lists:keyreplace(VendorId, #wh_service_plans.vendor_id, ServicePlans
- ,ServicePlan#wh_service_plans{plans = [Plan|Plans]})
- end
+ Plan -> get_plans(PlanIds, Services, append_vendor_plan(Plan, VendorId, ServicePlans))
+ end.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Given a plan and a vendor id append it to the list of service plans
+%% for that vendor, creating a new list (record) if not present.
+%% @end
+%%--------------------------------------------------------------------
+-spec append_vendor_plan/3 :: (wh_service_plan:plan(), ne_binary(), plans()) -> plans().
+append_vendor_plan(Plan, VendorId, ServicePlans) ->
+ case lists:keyfind(VendorId, #wh_service_plans.vendor_id, ServicePlans) of
+ false ->
+ ServicePlan = #wh_service_plans{vendor_id=VendorId
+ ,plans=[Plan]},
+ [ServicePlan|ServicePlans];
+ #wh_service_plans{plans=Plans}=ServicePlan ->
+ lists:keyreplace(VendorId, #wh_service_plans.vendor_id, ServicePlans
+ ,ServicePlan#wh_service_plans{plans=[Plan|Plans]})
end.
View
20 lib/whistle_services-1.0.0/src/wh_services.erl
@@ -9,6 +9,7 @@
-export([empty/0]).
-export([allow_updates/1]).
+-export([from_service_json/1]).
-export([reconcile/1, reconcile/2]).
-export([fetch/1]).
-export([update/4]).
@@ -68,6 +69,18 @@ allow_updates(_Account) ->
%%
%% @end
%%--------------------------------------------------------------------
+-spec from_service_json/1 :: (wh_json:json_object()) -> services().
+from_service_json(JObj) ->
+ AccountId = wh_json:get_value(<<"pvt_account_id">>, JObj),
+ #wh_services{account_id=AccountId, jobj=JObj
+ ,cascade_quantities=cascade_quantities(AccountId)}.
+
+%%--------------------------------------------------------------------
+%% @public
+%% @doc
+%%
+%% @end
+%%--------------------------------------------------------------------
-spec reconcile/1 :: (ne_binary()) -> services().
reconcile(Account) ->
ServiceModules = get_service_modules(),
@@ -104,6 +117,7 @@ reconcile(Account, Module) ->
fetch(Account) ->
AccountId = wh_util:format_account_id(Account, raw),
AccountDb = wh_util:format_account_id(Account, encoded),
+ %% TODO: if reseller populate cascade via merchant id
case couch_mgr:open_doc(?WH_SERVICES_DB, AccountId) of
{ok, JObj} ->
lager:debug("loaded account service doc ~s", [AccountId]),
@@ -119,6 +133,7 @@ fetch(Account) ->
,{<<"pvt_vsn">>, <<"1">>}
,{<<"pvt_account_id">>, AccountId}
,{<<"pvt_account_db">>, AccountDb}
+ ,{<<"pvt_status">>, <<"good_standing">>}
,{?QUANTITIES, wh_json:new()}
],
#wh_services{account_id=AccountId, jobj=wh_json:from_list(New)
@@ -145,10 +160,10 @@ update(Category, Item, Quantity, #wh_services{updates=JObj}=Services) when is_bi
%% @end
%%--------------------------------------------------------------------
-spec save/1 :: (services()) -> services().
-save(#wh_services{jobj=JObj, updates=UpdatedQuantities, account_id=AccountId, dirty=Dirty}=Services) ->
+save(#wh_services{jobj=JObj, updates=UpdatedQuantities, account_id=AccountId}=Services) ->
CurrentQuantities = wh_json:get_value(?QUANTITIES, JObj, wh_json:new()),
Props = [{<<"_id">>, AccountId}
- ,{<<"pvt_dirty">>, Dirty}
+ ,{<<"pvt_dirty">>, true}
,{<<"pvt_modified">>, wh_util:current_tstamp()}
,{<<"pvt_tree">>, get_pvt_tree(AccountId)}
,{?QUANTITIES, wh_json:merge_jobjs(UpdatedQuantities, CurrentQuantities)}
@@ -260,7 +275,6 @@ cascade_category_quantity(Category, Exceptions, #wh_services{cascade_quantities=
reset_category(Category, #wh_services{updates=JObj}=Services) ->
Services#wh_services{updates=wh_json:set_value(Category, wh_json:new(), JObj)}.
-
%%%===================================================================
%%% Internal functions
%%%===================================================================
View
23 lib/whistle_services-1.0.0/src/whistle_services_maintenance.erl
@@ -7,8 +7,31 @@
%%%-------------------------------------------------------------------
-module(whistle_services_maintenance).
+-export([refresh/0]).
-export([reconcile/0, reconcile/1]).
+-include_lib("whistle_services/src/whistle_services.hrl").
+
+%%--------------------------------------------------------------------
+%% @public
+%% @doc
+%%
+%% @end
+%%--------------------------------------------------------------------
+-spec refresh/0 :: () -> 'ok'.
+refresh() ->
+ couch_mgr:db_create(?WH_SERVICES_DB),
+ couch_mgr:revise_docs_from_folder(?WH_SERVICES_DB, whistle_services, "views").
+
+%%--------------------------------------------------------------------
+%% @public
+%% @doc
+%%
+%% @end
+%%--------------------------------------------------------------------
+-spec reconcile/0 :: () -> 'no_return'.
+-spec reconcile/1 :: (text()) -> 'no_return'.
+
reconcile() ->
reconcile(all).
Please sign in to comment.
Something went wrong with that request. Please try again.