Skip to content

Commit

Permalink
KAZOO-6073: [master] api to get summary grouped by sub-accounts (2600…
Browse files Browse the repository at this point in the history
…hz#5618)

* KAZOO-6073: api to get summary grouped by sub-account

* KAZOO-6073: use map/reduce

* make fmt apis

* fix doc

* KAZOO-6073: put ledgers deeper in object and add total

* KAZOO-6073: add missing semicolon
  • Loading branch information
icehess authored and k-anderson committed Mar 28, 2019
1 parent 59a3e72 commit 185b0b9
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 32 deletions.
84 changes: 84 additions & 0 deletions applications/crossbar/doc/ledgers.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,90 @@ curl -v -X GET \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/{SOURCE_SERVICE}
```

## Get ledgers summary grouped by sub-accounts

> GET /v2/accounts/{ACCOUNT_ID}/ledgers/summary_by_accounts
```shell
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/summary_by_accounts
```

**Sample response:**

```json
{
"auth_token": "{AUTH_TOKEN}",
"data": {
"{ACCOUNT_ID_1}": {
"account": {
"name": "{ACCOUNT_NAME_1}",
"id": "{ACCOUNT_ID_1}"
},
"ledgers": {
"per-minute-voip": {
"amount": -5.655,
"usage": {
"type": "voice",
"quantity": 1500,
"unit": "sec"
}
},
"adjustments": {
"amount": -11200,
"usage": {
"type": "credit",
"quantity": 0,
"unit": "USD"
}
},
"payments": {
"amount": 30078.56,
"usage": {
"quantity": 0
}
},
"prorations": {
"amount": -29.9402,
"usage": {
"quantity": 0
}
},
"recurring": {
"amount": -10883.44,
"usage": {
"quantity": 0
}
}
},
"total": 7959.5248
},
"{ACCOUNT_ID_2}": {
"account": {
"name": "{ACCOUNT_NAME_2}",
"id": "{ACCOUNT_ID_2}"
},
"ledgers": {
"per-minute-voip": {
"amount": -0.2262,
"usage": {
"type": "voice",
"quantity": 60,
"unit": "sec"
}
}
},
"total": -0.2262
}
},
"node": "{NODE}",
"request_id": "{REQUEST_ID}",
"status": "success",
"timestamp": "{TIMESTAMP}",
"version": "{VERSION}"
}
```

## Get Ledger values

Expand Down
10 changes: 10 additions & 0 deletions applications/crossbar/doc/ref/ledgers.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ curl -v -X GET \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/{SOURCE_SERVICE}
```

## Fetch

> GET /v2/accounts/{ACCOUNT_ID}/ledgers/summary_by_accounts
```shell
curl -v -X GET \
-H "X-Auth-Token: {AUTH_TOKEN}" \
http://{SERVER}:8000/v2/accounts/{ACCOUNT_ID}/ledgers/summary_by_accounts
```

## Create

> PUT /v2/accounts/{ACCOUNT_ID}/ledgers/debit
Expand Down
17 changes: 17 additions & 0 deletions applications/crossbar/priv/api/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -40288,6 +40288,23 @@
}
}
},
"/accounts/{ACCOUNT_ID}/ledgers/summary_by_accounts": {
"get": {
"parameters": [
{
"$ref": "#/parameters/auth_token_header"
},
{
"$ref": "#/parameters/ACCOUNT_ID"
}
],
"responses": {
"200": {
"description": "request succeeded"
}
}
}
},
"/accounts/{ACCOUNT_ID}/ledgers/total": {
"get": {
"parameters": [
Expand Down
50 changes: 41 additions & 9 deletions applications/crossbar/src/modules/cb_ledgers.erl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
-define(TOTAL, <<"total">>).
-define(CREDIT, <<"credit">>).
-define(DEBIT, <<"debit">>).
-define(SUB_SUMMARY, <<"summary_by_accounts">>).

-define(VIEW_BY_TIMESTAMP, <<"ledgers/list_by_timestamp">>).
-define(VIEW_BY_SOURCE, <<"ledgers/list_by_source">>).
Expand Down Expand Up @@ -62,6 +63,8 @@ allowed_methods(?CREDIT) ->
[?HTTP_PUT];
allowed_methods(?DEBIT) ->
[?HTTP_PUT];
allowed_methods(?SUB_SUMMARY) ->
[?HTTP_GET];
allowed_methods(_SourceService) ->
[?HTTP_GET].

Expand Down Expand Up @@ -143,14 +146,14 @@ authorize_create(Context) ->
validate(Context) ->
Options = [{'group', 'true'}
,{'group_level', 0}
,{'mapper', crossbar_view:map_value_fun()}
,{'mapper', fun normalize_list_by_timestamp/2}
,{'reduce', 'true'}
,{'unchunkable', 'true'}
],
Context1 = crossbar_view:load_modb(Context, ?VIEW_BY_TIMESTAMP, Options),
case cb_context:resp_status(Context1) of
'success' ->
Summary = kz_json:sum_jobjs(cb_context:doc(Context1)),
Summary = cb_context:doc(Context1),
cb_context:set_resp_data(Context1, summary_to_dollars(Summary));
_ ->
Context1
Expand Down Expand Up @@ -178,6 +181,22 @@ validate(Context, ?TOTAL) ->
validate(Context, ?AVAILABLE) ->
Available = kz_ledgers:available_ledgers(cb_context:account_id(Context)),
crossbar_doc:handle_json_success(Available, Context);
validate(Context, ?SUB_SUMMARY) ->
Options = [{'group', 'true'}
,{'group_level', 0}
,{'reduce', 'true'}
,{'mapper', crossbar_view:map_value_fun()}
,{'unchunkable', 'true'}
,{'should_paginate', 'false'}
],
Context1 = crossbar_view:load_modb(Context, ?VIEW_BY_TIMESTAMP, Options),
case cb_context:resp_status(Context1) of
'success' ->
Summary = cb_context:doc(Context1),
cb_context:set_resp_data(Context1, summary_to_dollars(Summary));
_ ->
Context1
end;
validate(Context, SourceService) ->
ViewOptions = [{'is_chunked', 'true'}
,{'range_keymap', SourceService}
Expand Down Expand Up @@ -271,19 +290,23 @@ put(Context, Action) ->
%% @doc
%% @end
%%------------------------------------------------------------------------------
-spec summary_to_dollars(kz_json:object()) -> kz_json:object().
summary_to_dollars(Summary) ->
-spec summary_to_dollars(kz_json:objects()) -> kz_json:object().
summary_to_dollars([]) -> kz_json:new();
summary_to_dollars([Summary]) ->
kz_json:expand(
kz_json:from_list(
[{Path, maybe_convert_units(lists:last(Path), Value)}
|| {Path, Value} <- kz_json:to_proplist(kz_json:flatten(Summary))
[{Paths, maybe_convert_units(lists:last(Paths), Paths, Value)}
|| {Paths, Value} <- kz_json:to_proplist(kz_json:flatten(Summary))
])).

-spec maybe_convert_units(kz_term:ne_binary(), kz_currency:units() | T) ->
-spec maybe_convert_units(kz_json:key(), kz_json:keys(), kz_currency:units() | T) ->
kz_currency:dollars() | T when T::any().
maybe_convert_units(<<"amount">>, Units) when is_integer(Units) ->
maybe_convert_units(<<"amount">>, _, Units) when is_integer(Units) ->
kz_currency:units_to_dollars(Units);
maybe_convert_units(_, Value) -> Value.
maybe_convert_units(_, [_AccountId, <<"total">>], Units) ->
kz_currency:units_to_dollars(Units);
maybe_convert_units(_, _, Value) ->
Value.

%%------------------------------------------------------------------------------
%% @doc
Expand Down Expand Up @@ -376,6 +399,15 @@ build_success_response(AccountId, Ledger) ->
%% @doc
%% @end
%%------------------------------------------------------------------------------
-spec normalize_list_by_timestamp(kz_json:object(), kz_json:objects()) -> kz_json:objects().
normalize_list_by_timestamp(JObj, Acc) ->
[kz_json:sum_jobjs(
[kz_json:get_ne_json_value(<<"ledgers">>, J, kz_json:new())
|| J <- kz_json:values(kz_json:get_value(<<"value">>, JObj, kz_json:new()))
] ++ Acc
)
].

-spec normalize_view_results(cb_context:context(), kzd_ledgers:doc(), kz_json:objects()) ->
kz_json:objects().
normalize_view_results(_Context, JObj, Acc) ->
Expand Down
69 changes: 46 additions & 23 deletions core/kazoo_modb/priv/couchdb/views/ledgers.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,34 +27,57 @@
"function(doc) {",
" if (doc.pvt_deleted || doc.pvt_type !== 'ledger')",
" return;",
" var amount = doc.amount || 0;",
" var usage = doc.usage || {};",
" var service = doc.source.service;",
" if (doc.pvt_ledger_type === 'debit')",
" amount *= -1;",
" var o = {};",
" o[service] = {amount:amount, usage:usage};",
" emit(doc.pvt_created, o);",
" var accountId = doc.account.id;",
" var serviceName = doc.source.service;",
" var amount = (doc.amount || 0) * (doc.pvt_ledger_type === 'debit' ? -1 : 1);",
" var service = {",
" 'amount': amount,",
" 'usage': doc.usage || {}",
" };",
" var result = {};",
" result[accountId] = {",
" 'account': doc.account,",
" 'ledgers': {},",
" 'total': amount",
" };",
" result[accountId]['ledgers'][serviceName] = service;",
" emit(doc.pvt_created, result);",
"}"
],
"reduce": [
"function (keys, values, rereduce) {",
"function(keys, values, rereduce) {",
" return values.reduce(function(reduceObj, obj) {",
" for (var service in obj) {",
" if (!obj.hasOwnProperty(service)) continue;",
" var serviceObj = obj[service];",
" var objUsageObj = serviceObj.usage || {};",
" var reduceService = reduceObj[service] || {};",
" var reduceServiceUsage = reduceService.usage || {};",
" var tmp = {",
" 'amount': (serviceObj.amount || 0) + (reduceService.amount || 0),",
" 'usage': {",
" 'type': reduceServiceUsage.type || objUsageObj.type,",
" 'quantity': (reduceServiceUsage.quantity || 0) + (objUsageObj.quantity || 0),",
" 'unit': reduceServiceUsage.unit || objUsageObj.unit",
" }",
" for (var account in obj) {",
" if (!obj.hasOwnProperty(account)) continue;",
" var rootObj = obj[account];",
" var accountId = rootObj.account.id;",
" var ledgersObj = rootObj.ledgers;",
" var reduceAccount = reduceObj[accountId] || {};",
" var reduceLedgers = reduceAccount.ledgers || {};",
" var reduceTotal = reduceAccount.total || 0;",
" for (var service in ledgersObj) {",
" if (!ledgersObj.hasOwnProperty(service)) continue;",
" var serviceObj = ledgersObj[service];",
" var objUsageObj = serviceObj.usage || {};",
" var reduceService = reduceLedgers[service] || {};",
" var reduceServiceUsage = reduceService.usage || {};",
" var tmp = {",
" 'amount': (serviceObj.amount || 0) + (reduceService.amount || 0),",
" 'usage': {",
" 'type': reduceServiceUsage.type || objUsageObj.type,",
" 'quantity': (reduceServiceUsage.quantity || 0) + (objUsageObj.quantity || 0),",
" 'unit': reduceServiceUsage.unit || objUsageObj.unit",
" }",
" };",
" reduceLedgers[service] = tmp;",
" reduceTotal += (serviceObj.amount || 0);",
" }",
" reduceAccount = {",
" 'account': rootObj.account,",
" 'ledgers': reduceLedgers,",
" 'total': reduceTotal",
" };",
" reduceObj[service] = tmp;",
" reduceObj[accountId] = reduceAccount;",
" }",
" return reduceObj",
" }, {})",
Expand Down

0 comments on commit 185b0b9

Please sign in to comment.