%%%-----------------------------------------------------------------------------
%%% @copyright (C) 2010-2019, 2600Hz
%%% @doc APIs for events concerning money (like credits, debits, and others).
%%%
%%% Types of events known:
%%%
%%% - `credit'
- A credit has been added to account-id
%%% - `debit'
- A debit has been applied to account-id
%%% - `balance'
- A request for any whapp with the balance of account-id to reply
%%%
%%%
%%% @author James Aimonetti
%%% @end
%%%-----------------------------------------------------------------------------
-module(kapi_money).
-export([credit/1, credit_v/1
,debit/1, debit_v/1
,balance_req/1, balance_req_v/1
,balance_resp/1, balance_resp_v/1
,bind_q/2, unbind_q/2
,declare_exchanges/0
,publish_credit/1, publish_credit/2
,publish_debit/1, publish_debit/2
,publish_balance_req/1, publish_balance_req/2
,publish_balance_resp/2, publish_balance_resp/3
]).
-include_lib("kz_amqp_util.hrl").
-define(CREDIT_HEADERS, [<<"Account-ID">>, <<"Amount">>, <<"Transaction-ID">>]).
-define(OPTIONAL_CREDIT_HEADERS, []).
-define(CREDIT_VALUES, [{<<"Event-Category">>, <<"transaction">>}
,{<<"Event-Name">>, <<"credit">>}
]).
-define(CREDIT_TYPES, []).
-define(DEBIT_HEADERS, [<<"Account-ID">>, <<"Amount">>, <<"Transaction-ID">>]).
-define(OPTIONAL_DEBIT_HEADERS, []).
-define(DEBIT_VALUES, [{<<"Event-Category">>, <<"transaction">>}
,{<<"Event-Name">>, <<"debit">>}
]).
-define(DEBIT_TYPES, []).
-define(BALANCE_REQ_HEADERS, [<<"Account-ID">>]).
-define(OPTIONAL_BALANCE_REQ_HEADERS, []).
-define(BALANCE_REQ_VALUES, [{<<"Event-Category">>, <<"transaction">>}
,{<<"Event-Name">>, <<"balance_req">>}
]).
-define(BALANCE_REQ_TYPES, []).
-define(BALANCE_RESP_HEADERS, [<<"Account-ID">>]).
-define(OPTIONAL_BALANCE_RESP_HEADERS, [<<"Two-Way">>, <<"Inbound">>, <<"Prepay">>
,<<"Max-Two-Way">>, <<"Max-Inbound">>
,<<"Trunks">>, <<"Node">>
]).
-define(BALANCE_RESP_VALUES, [{<<"Event-Category">>, <<"transaction">>}
,{<<"Event-Name">>, <<"balance_resp">>}
]).
-define(BALANCE_RESP_TYPES, []).
%%------------------------------------------------------------------------------
%% @doc Credit Update.
%% Takes {@link kz_term:api_term()}, creates JSON string or error.
%% @end
%%------------------------------------------------------------------------------
-spec credit(kz_term:api_terms()) -> {'ok', iolist()} | {'error', string()}.
credit(Prop) when is_list(Prop) ->
case credit_v(Prop) of
true -> kz_api:build_message(Prop, ?CREDIT_HEADERS, ?OPTIONAL_CREDIT_HEADERS);
false -> {error, "Proplist failed validation for credit"}
end;
credit(JObj) ->
credit(kz_json:to_proplist(JObj)).
-spec credit_v(kz_term:api_terms()) -> boolean().
credit_v(Prop) when is_list(Prop) ->
kz_api:validate(Prop, ?CREDIT_HEADERS, ?CREDIT_VALUES, ?CREDIT_TYPES);
credit_v(JObj) ->
credit_v(kz_json:to_proplist(JObj)).
%%------------------------------------------------------------------------------
%% @doc Debit Update.
%% Takes {@link kz_term:api_term()}, creates JSON string or error.
%% @end
%%------------------------------------------------------------------------------
-spec debit(kz_term:api_terms()) -> {'ok', iolist()} | {'error', string()}.
debit(Prop) when is_list(Prop) ->
case debit_v(Prop) of
true -> kz_api:build_message(Prop, ?DEBIT_HEADERS, ?OPTIONAL_DEBIT_HEADERS);
false -> {error, "Proplist failed validation for debit"}
end;
debit(JObj) ->
debit(kz_json:to_proplist(JObj)).
-spec debit_v(kz_term:api_terms()) -> boolean().
debit_v(Prop) when is_list(Prop) ->
kz_api:validate(Prop, ?DEBIT_HEADERS, ?DEBIT_VALUES, ?DEBIT_TYPES);
debit_v(JObj) ->
debit_v(kz_json:to_proplist(JObj)).
%%------------------------------------------------------------------------------
%% @doc Balance Request.
%% Takes {@link kz_term:api_term()}, creates JSON string or error.
%% @end
%%------------------------------------------------------------------------------
-spec balance_req(kz_term:api_terms()) -> {'ok', iolist()} | {'error', string()}.
balance_req(Prop) when is_list(Prop) ->
case balance_req_v(Prop) of
true -> kz_api:build_message(Prop, ?BALANCE_REQ_HEADERS, ?OPTIONAL_BALANCE_REQ_HEADERS);
false -> {error, "Proplist failed validation for balance_req"}
end;
balance_req(JObj) ->
balance_req(kz_json:to_proplist(JObj)).
-spec balance_req_v(kz_term:api_terms()) -> boolean().
balance_req_v(Prop) when is_list(Prop) ->
kz_api:validate(Prop, ?BALANCE_REQ_HEADERS, ?BALANCE_REQ_VALUES, ?BALANCE_REQ_TYPES);
balance_req_v(JObj) ->
balance_req_v(kz_json:to_proplist(JObj)).
%%------------------------------------------------------------------------------
%% @doc Balance Response.
%% Takes {@link kz_term:api_term()}, creates JSON string or error.
%% @end
%%------------------------------------------------------------------------------
-spec balance_resp(kz_term:api_terms()) -> {'ok', iolist()} | {'error', string()}.
balance_resp(Prop) when is_list(Prop) ->
case balance_resp_v(Prop) of
true -> kz_api:build_message(Prop, ?BALANCE_RESP_HEADERS, ?OPTIONAL_BALANCE_RESP_HEADERS);
false -> {error, "Proplist failed validation for balance_resp"}
end;
balance_resp(JObj) ->
balance_resp(kz_json:to_proplist(JObj)).
-spec balance_resp_v(kz_term:api_terms()) -> boolean().
balance_resp_v(Prop) when is_list(Prop) ->
kz_api:validate(Prop, ?BALANCE_RESP_HEADERS, ?BALANCE_RESP_VALUES, ?BALANCE_RESP_TYPES);
balance_resp_v(JObj) ->
balance_resp_v(kz_json:to_proplist(JObj)).
-spec bind_q(kz_term:ne_binary(), kz_term:proplist()) -> 'ok'.
bind_q(Queue, Props) ->
Routing = routing_key(Props),
kz_amqp_util:bind_q_to_configuration(Queue, Routing).
-spec unbind_q(kz_term:ne_binary(), kz_term:proplist()) -> 'ok'.
unbind_q(Queue, Props) ->
Routing = routing_key(Props),
kz_amqp_util:unbind_q_from_configuration(Queue, Routing).
%%------------------------------------------------------------------------------
%% @doc Declare the exchanges used by this API
%% @end
%%------------------------------------------------------------------------------
-spec declare_exchanges() -> 'ok'.
declare_exchanges() ->
kz_amqp_util:configuration_exchange().
routing_key(Props) ->
list_to_binary([<<"transaction.">>
,props:get_value('type', Props, <<"*">>) %% credit/debit/balance/other
,<<".">>
,props:get_value('account_id', Props, <<"*">>)
]).
-spec publish_credit(kz_term:api_terms()) -> 'ok'.
publish_credit(Req) ->
publish_credit(Req, ?DEFAULT_CONTENT_TYPE).
-spec publish_credit(kz_term:api_terms(), kz_term:ne_binary()) -> 'ok'.
publish_credit(Req, ContentType) ->
RoutingKey = list_to_binary([<<"transaction.credit.">>, props:get_value(<<"Account-ID">>, Req)]),
{'ok', Payload} = kz_api:prepare_api_payload(Req, ?CREDIT_VALUES, fun credit/1),
kz_amqp_util:configuration_publish(RoutingKey, Payload, ContentType).
-spec publish_debit(kz_term:api_terms()) -> 'ok'.
publish_debit(Req) ->
publish_debit(Req, ?DEFAULT_CONTENT_TYPE).
-spec publish_debit(kz_term:api_terms(), kz_term:ne_binary()) -> 'ok'.
publish_debit(Req, ContentType) ->
RoutingKey = list_to_binary([<<"transaction.debit.">>, props:get_value(<<"Account-ID">>, Req)]),
{'ok', Payload} = kz_api:prepare_api_payload(Req, ?DEBIT_VALUES, fun debit/1),
kz_amqp_util:configuration_publish(RoutingKey, Payload, ContentType).
-spec publish_balance_req(kz_term:api_terms()) -> 'ok'.
publish_balance_req(Req) ->
publish_balance_req(Req, ?DEFAULT_CONTENT_TYPE).
-spec publish_balance_req(kz_term:api_terms(), kz_term:ne_binary()) -> 'ok'.
publish_balance_req(Req, ContentType) ->
RoutingKey = list_to_binary([<<"transaction.balance.">>, props:get_value(<<"Account-ID">>, Req)]),
{'ok', Payload} = kz_api:prepare_api_payload(Req, ?BALANCE_REQ_VALUES, fun balance_req/1),
kz_amqp_util:configuration_publish(RoutingKey, Payload, ContentType).
-spec publish_balance_resp(kz_term:ne_binary(), kz_term:api_terms()) -> 'ok'.
publish_balance_resp(Queue, Req) ->
publish_balance_resp(Queue, Req, ?DEFAULT_CONTENT_TYPE).
-spec publish_balance_resp(kz_term:ne_binary(), kz_term:api_terms(), kz_term:ne_binary()) -> 'ok'.
publish_balance_resp(Queue, Req, ContentType) ->
{'ok', Payload} = kz_api:prepare_api_payload(Req, ?BALANCE_RESP_VALUES, fun balance_resp/1),
kz_amqp_util:targeted_publish(Queue, Payload, ContentType).