diff --git a/apps/ff_server/src/ff_codec.erl b/apps/ff_server/src/ff_codec.erl index 16090ef..db5085c 100644 --- a/apps/ff_server/src/ff_codec.erl +++ b/apps/ff_server/src/ff_codec.erl @@ -123,7 +123,17 @@ marshal(account, #{ accounter_account_id = marshal(event_id, AAID) }; -marshal(resource, {bank_card, BankCard = #{token := Token}}) -> +marshal(resource, {bank_card, #{bank_card := BankCard} = ResourceBankCard}) -> + {bank_card, #'ResourceBankCard'{ + bank_card = marshal(bank_card, BankCard), + auth_data = maybe_marshal(bank_card_auth_data, maps:get(auth_data, ResourceBankCard, undefined)) + }}; +marshal(resource, {crypto_wallet, #{crypto_wallet := CryptoWallet}}) -> + {crypto_wallet, #'ResourceCryptoWallet'{ + crypto_wallet = marshal(crypto_wallet, CryptoWallet) + }}; + +marshal(bank_card, BankCard = #{token := Token}) -> Bin = maps:get(bin, BankCard, undefined), PaymentSystem = maps:get(payment_system, BankCard, undefined), MaskedPan = maps:get(masked_pan, BankCard, undefined), @@ -132,7 +142,7 @@ marshal(resource, {bank_card, BankCard = #{token := Token}}) -> CardType = maps:get(card_type, BankCard, undefined), ExpDate = maps:get(exp_date, BankCard, undefined), BinDataID = maps:get(bin_data_id, BankCard, undefined), - {bank_card, #'BankCard'{ + #'BankCard'{ token = marshal(string, Token), bin = marshal(string, Bin), masked_pan = marshal(string, MaskedPan), @@ -142,13 +152,19 @@ marshal(resource, {bank_card, BankCard = #{token := Token}}) -> card_type = CardType, exp_date = maybe_marshal(exp_date, ExpDate), bin_data_id = marshal_msgpack(BinDataID) + }; + +marshal(bank_card_auth_data, {session, #{session_id := ID}}) -> + {session_data, #'SessionAuthData'{ + id = marshal(string, ID) }}; -marshal(resource, {crypto_wallet, #{id := ID, currency := Currency}}) -> - {crypto_wallet, #'CryptoWallet'{ + +marshal(crypto_wallet, #{id := ID, currency := Currency}) -> + #'CryptoWallet'{ id = marshal(string, ID), currency = marshal(crypto_currency, Currency), data = marshal(crypto_data, Currency) - }}; + }; marshal(exp_date, {Month, Year}) -> #'BankCardExpDate'{ @@ -343,10 +359,23 @@ unmarshal(account, #'account_Account'{ unmarshal(accounter_account_id, V) -> unmarshal(integer, V); -unmarshal(resource, {bank_card, BankCard}) -> - {bank_card, unmarshal(bank_card, BankCard)}; -unmarshal(resource, {crypto_wallet, CryptoWallet}) -> - {crypto_wallet, unmarshal(crypto_wallet, CryptoWallet)}; +unmarshal(resource, {bank_card, #'ResourceBankCard'{ + bank_card = BankCard, + auth_data = AuthData +}}) -> + {bank_card, genlib_map:compact(#{ + bank_card => unmarshal(bank_card, BankCard), + auth_data => maybe_unmarshal(bank_card_auth_data, AuthData) + })}; +unmarshal(resource, {crypto_wallet, #'ResourceCryptoWallet'{crypto_wallet = CryptoWallet}}) -> + {crypto_wallet, #{ + crypto_wallet => unmarshal(crypto_wallet, CryptoWallet) + }}; + +unmarshal(bank_card_auth_data, {session_data, #'SessionAuthData'{id = ID}}) -> + #{ + session_id => unmarshal(string, ID) + }; unmarshal(bank_card, #'BankCard'{ token = Token, diff --git a/apps/ff_server/src/ff_destination_codec.erl b/apps/ff_server/src/ff_destination_codec.erl index 14818b0..cf37a9d 100644 --- a/apps/ff_server/src/ff_destination_codec.erl +++ b/apps/ff_server/src/ff_destination_codec.erl @@ -129,9 +129,9 @@ maybe_unmarshal(Type, Value) -> -spec destination_test() -> _. destination_test() -> - Resource = {bank_card, #{ + Resource = {bank_card, #{bank_card => #{ token => <<"token auth">> - }}, + }}}, AAID = 12345, AccountID = genlib:unique(), In = #{ @@ -152,10 +152,10 @@ destination_test() -> -spec crypto_wallet_resource_test() -> _. crypto_wallet_resource_test() -> - Resource = {crypto_wallet, #{ + Resource = {crypto_wallet, #{crypto_wallet => #{ id => <<"9e6245a7a6e15f75769a4d87183b090a">>, currency => {bitcoin, #{}} - }}, + }}}, ?assertEqual(Resource, unmarshal(resource, marshal(resource, Resource))). -endif. diff --git a/apps/ff_server/src/ff_p2p_session_codec.erl b/apps/ff_server/src/ff_p2p_session_codec.erl index c70e02d..6d0e977 100644 --- a/apps/ff_server/src/ff_p2p_session_codec.erl +++ b/apps/ff_server/src/ff_p2p_session_codec.erl @@ -309,10 +309,10 @@ p2p_session_codec_test() -> extra => <<"Extra">> }, - Resource = {bank_card, #{ + Resource = {bank_card, #{bank_card => #{ token => <<"token">>, payment_system => visa - }}, + }}}, TransferParams = #{ id => genlib:unique(), diff --git a/apps/ff_server/src/ff_p2p_transfer_codec.erl b/apps/ff_server/src/ff_p2p_transfer_codec.erl index ec58470..5df1e36 100644 --- a/apps/ff_server/src/ff_p2p_transfer_codec.erl +++ b/apps/ff_server/src/ff_p2p_transfer_codec.erl @@ -73,10 +73,10 @@ marshal(quote, #{}) -> marshal(status, Status) -> ff_p2p_transfer_status_codec:marshal(status, Status); -marshal(participant, {raw, #{resource_params := Resource} = Raw}) -> +marshal(participant, {raw, #{resource_params := ResourceParams} = Raw}) -> ContactInfo = maps:get(contact_info, Raw, undefined), {resource, #p2p_transfer_RawResource{ - resource = marshal(resource, Resource), + resource = marshal(resource, ResourceParams), contact_info = marshal(contact_info, ContactInfo) }}; @@ -314,10 +314,10 @@ p2p_transfer_codec_test() -> external_id => genlib:unique() }, - Resource = {bank_card, #{ + Resource = {bank_card, #{bank_card => #{ token => genlib:unique(), bin_data_id => {binary, genlib:unique()} - }}, + }}}, Participant = {raw, #{ resource_params => Resource, diff --git a/apps/ff_server/test/ff_destination_handler_SUITE.erl b/apps/ff_server/test/ff_destination_handler_SUITE.erl index 215ba34..70f9a70 100644 --- a/apps/ff_server/test/ff_destination_handler_SUITE.erl +++ b/apps/ff_server/test/ff_destination_handler_SUITE.erl @@ -77,29 +77,29 @@ end_per_testcase(_Name, _C) -> -spec create_bank_card_destination_ok(config()) -> test_return(). create_bank_card_destination_ok(C) -> - Resource = {bank_card, #'BankCard'{ + Resource = {bank_card, #'ResourceBankCard'{bank_card = #'BankCard'{ token = <<"TOKEN shmOKEN">> - }}, + }}}, create_destination_ok(Resource, C). -spec create_crypto_wallet_destination_ok(config()) -> test_return(). create_crypto_wallet_destination_ok(C) -> - Resource = {crypto_wallet, #'CryptoWallet'{ + Resource = {crypto_wallet, #'ResourceCryptoWallet'{crypto_wallet = #'CryptoWallet'{ id = <<"f195298af836f41d072cb390ee62bee8">>, currency = bitcoin_cash, data = {bitcoin_cash, #'CryptoDataBitcoinCash'{}} - }}, + }}}, create_destination_ok(Resource, C). -spec create_ripple_wallet_destination_ok(config()) -> test_return(). create_ripple_wallet_destination_ok(C) -> - Resource = {crypto_wallet, #'CryptoWallet'{ + Resource = {crypto_wallet, #'ResourceCryptoWallet'{crypto_wallet = #'CryptoWallet'{ id = <<"ab843336bf7738dc697522fbb90508de">>, currency = ripple, data = {ripple, #'CryptoDataRipple'{tag = undefined}} - }}, + }}}, create_destination_ok(Resource, C). %%---------------------------------------------------------------------- diff --git a/apps/ff_server/test/ff_eventsink_SUITE.erl b/apps/ff_server/test/ff_eventsink_SUITE.erl index b45ff28..a91b2e2 100644 --- a/apps/ff_server/test/ff_eventsink_SUITE.erl +++ b/apps/ff_server/test/ff_eventsink_SUITE.erl @@ -275,11 +275,11 @@ get_create_p2p_transfer_events_ok(C) -> Sink = p2p_transfer_event_sink, LastEvent = ct_eventsink:last_id(Sink), - Resource = {bank_card, #{ + Resource = {bank_card, #{bank_card => #{ token => genlib:unique(), bin => <<"some bin">>, masked_pan => <<"some masked_pan">> - }}, + }}}, Participant = {raw, #{ resource_params => Resource, @@ -411,7 +411,7 @@ process_deposit(SrcID, WalID) -> DepID. create_destination(IID, C) -> - DestResource = {bank_card, ct_cardstore:bank_card(<<"4150399999000900">>, {12, 2025}, C)}, + DestResource = {bank_card, #{bank_card => ct_cardstore:bank_card(<<"4150399999000900">>, {12, 2025}, C)}}, DestID = create_instrument(destination, IID, <<"XDesination">>, <<"RUB">>, DestResource, C), authorized = ct_helper:await( authorized, diff --git a/apps/ff_server/test/ff_withdrawal_handler_SUITE.erl b/apps/ff_server/test/ff_withdrawal_handler_SUITE.erl index 19d66b6..794e6dd 100644 --- a/apps/ff_server/test/ff_withdrawal_handler_SUITE.erl +++ b/apps/ff_server/test/ff_withdrawal_handler_SUITE.erl @@ -537,7 +537,7 @@ create_destination(IID, Currency, Token, C) -> Token -> StoreSource#{token => Token} end, - Resource = {bank_card, NewStoreResource}, + Resource = {bank_card, #{bank_card => NewStoreResource}}, Params = #{id => ID, identity => IID, name => <<"XDesination">>, currency => Currency, resource => Resource}, ok = ff_destination:create(Params, ff_entity_context:new()), authorized = ct_helper:await( diff --git a/apps/ff_server/test/ff_withdrawal_session_repair_SUITE.erl b/apps/ff_server/test/ff_withdrawal_session_repair_SUITE.erl index b5654c4..b62ef34 100644 --- a/apps/ff_server/test/ff_withdrawal_session_repair_SUITE.erl +++ b/apps/ff_server/test/ff_withdrawal_session_repair_SUITE.erl @@ -139,7 +139,7 @@ create_identity(Party, ProviderID, ClassID, _C) -> ID. create_destination(IID, C) -> - DestResource = {bank_card, ct_cardstore:bank_card(<<"4150399999000900">>, {12, 2025}, C)}, + DestResource = {bank_card, #{bank_card => ct_cardstore:bank_card(<<"4150399999000900">>, {12, 2025}, C)}}, DestID = create_instrument(destination, IID, <<"XDesination">>, <<"RUB">>, DestResource, C), authorized = ct_helper:await( authorized, diff --git a/apps/ff_transfer/src/ff_adapter_withdrawal.erl b/apps/ff_transfer/src/ff_adapter_withdrawal.erl index 34f5025..6ec3826 100644 --- a/apps/ff_transfer/src/ff_adapter_withdrawal.erl +++ b/apps/ff_transfer/src/ff_adapter_withdrawal.erl @@ -199,12 +199,12 @@ encode_currency(#{ -spec encode_resource(resource()) -> domain_destination(). encode_resource( - {bank_card, #{ + {bank_card, #{bank_card := #{ token := Token, payment_system := PaymentSystem, bin := BIN, masked_pan := LastDigits - } = BankCard} + } = BankCard}} ) -> CardHolderName = genlib_map:get(cardholder_name, BankCard), ExpDate = genlib_map:get(exp_date, BankCard), @@ -217,10 +217,10 @@ encode_resource( exp_date = encode_exp_date(ExpDate) }}; encode_resource( - {crypto_wallet, #{ + {crypto_wallet, #{crypto_wallet := #{ id := CryptoWalletID, currency := {Currency, Data} - }} + }}} ) -> {crypto_wallet, #domain_CryptoWallet{ id = CryptoWalletID, diff --git a/apps/ff_transfer/src/ff_destination.erl b/apps/ff_transfer/src/ff_destination.erl index 1ef34b6..c8d545c 100644 --- a/apps/ff_transfer/src/ff_destination.erl +++ b/apps/ff_transfer/src/ff_destination.erl @@ -22,7 +22,7 @@ {bank_card, resource_bank_card()} | {crypto_wallet, resource_crypto_wallet()}. --type resource_full_id() :: +-type full_bank_card_id() :: #{binary() => ff_bin_data:bin_data_id()}. -type resource_full() :: @@ -30,6 +30,11 @@ {crypto_wallet, resource_crypto_wallet()}. -type resource_full_bank_card() :: #{ + bank_card := full_bank_card(), + auth_data => bank_card_auth_data() +}. + +-type full_bank_card() :: #{ token := binary(), bin => binary(), payment_system := atom(), % TODO @@ -43,16 +48,32 @@ }. -type resource_bank_card() :: #{ - token := binary(), - bin => binary(), - masked_pan => binary(), + bank_card := bank_card(), + auth_data => bank_card_auth_data() +}. + +-type bank_card() :: #{ + token := binary(), + bin => binary(), + masked_pan => binary(), cardholder_name => binary(), - exp_date => exp_date() + exp_date => exp_date() +}. + +-type bank_card_auth_data() :: + {session, session_auth_data()}. + +-type session_auth_data() :: #{ + session_id := binary() }. -type exp_date() :: {integer(), integer()}. -type resource_crypto_wallet() :: #{ + crypto_wallet := crypto_wallet() +}. + +-type crypto_wallet() :: #{ id := binary(), currency := crypto_currency() }. @@ -80,7 +101,7 @@ -export_type([resource/0]). -export_type([resource_type/0]). -export_type([resource_full/0]). --export_type([resource_full_id/0]). +-export_type([full_bank_card_id/0]). -export_type([event/0]). -export_type([params/0]). -export_type([exp_date/0]). @@ -97,7 +118,7 @@ -export([external_id/1]). -export([resource_full/1]). -export([resource_full/2]). --export([resource_full_id/1]). +-export([full_bank_card_id/1]). %% API @@ -145,7 +166,7 @@ external_id(T) -> ff_instrument:external_id(T). resource_full(Destination) -> resource_full(Destination, undefined). --spec resource_full(destination(), resource_full_id() | undefined) -> +-spec resource_full(destination(), full_bank_card_id() | undefined) -> {ok, resource_full()} | {error, {bin_data, not_found} @@ -154,23 +175,25 @@ resource_full(Destination) -> resource_full(Destination, ResourceID) -> do(fun() -> case resource(Destination) of - {bank_card, #{token := Token} = BankCard} -> + {bank_card, #{bank_card := #{token := Token} = BankCard} = Resource} -> UnwrappedResourceID = unwrap_resource_id(ResourceID), BinData = unwrap(bin_data, ff_bin_data:get(Token, UnwrappedResourceID)), KeyList = [payment_system, bank_name, iso_country_code, card_type], ExtendData = maps:with(KeyList, BinData), - {bank_card, maps:merge(BankCard, ExtendData#{bin_data_id => ff_bin_data:id(BinData)})}; + {bank_card, Resource#{ + bank_card => maps:merge(BankCard, ExtendData#{bin_data_id => ff_bin_data:id(BinData)}) + }}; {crypto_wallet, _CryptoWallet} = Resource -> Resource end end). --spec resource_full_id(resource_full() | undefined) -> - resource_full_id() | undefined. +-spec full_bank_card_id(resource_full() | undefined) -> + full_bank_card_id() | undefined. -resource_full_id({bank_card, #{bin_data_id := ID}}) -> +full_bank_card_id({bank_card, #{bank_card := #{bin_data_id := ID}}}) -> #{<<"bank_card">> => ID}; -resource_full_id(_) -> +full_bank_card_id(_) -> undefined. unwrap_resource_id(undefined) -> diff --git a/apps/ff_transfer/src/ff_instrument.erl b/apps/ff_transfer/src/ff_instrument.erl index d1fbb7c..7649d71 100644 --- a/apps/ff_transfer/src/ff_instrument.erl +++ b/apps/ff_transfer/src/ff_instrument.erl @@ -59,6 +59,7 @@ -export([apply_event/2]). -export([maybe_migrate/1]). +-export([maybe_migrate_resource/1]). %% Pipeline @@ -198,9 +199,18 @@ maybe_migrate({created, Instrument = #{ maybe_migrate(Event) -> Event. +-spec maybe_migrate_resource(any()) -> + any(). + maybe_migrate_resource({crypto_wallet, #{id := ID, currency := ripple, tag := Tag}}) -> - {crypto_wallet, #{id => ID, currency => {ripple, #{tag => Tag}}}}; + maybe_migrate_resource({crypto_wallet, #{id => ID, currency => {ripple, #{tag => Tag}}}}); maybe_migrate_resource({crypto_wallet, #{id := ID, currency := Currency}}) when is_atom(Currency) -> - {crypto_wallet, #{id => ID, currency => {Currency, #{}}}}; + maybe_migrate_resource({crypto_wallet, #{id => ID, currency => {Currency, #{}}}}); + +maybe_migrate_resource({crypto_wallet, #{id := _ID} = CryptoWallet}) -> + maybe_migrate_resource({crypto_wallet, #{crypto_wallet => CryptoWallet}}); +maybe_migrate_resource({bank_card, #{token := _Token} = BankCard}) -> + maybe_migrate_resource({bank_card, #{bank_card => BankCard}}); + maybe_migrate_resource(Resource) -> Resource. diff --git a/apps/ff_transfer/src/ff_withdrawal.erl b/apps/ff_transfer/src/ff_withdrawal.erl index 6b15430..49a842b 100644 --- a/apps/ff_transfer/src/ff_withdrawal.erl +++ b/apps/ff_transfer/src/ff_withdrawal.erl @@ -35,8 +35,7 @@ destination_id := ff_destination:id(), body := body(), external_id => id(), - quote => quote(), - destination_resource => destination_resource() + quote => quote() }. -type status() :: @@ -980,7 +979,7 @@ build_party_varset(#{body := Body, wallet_id := WalletID, party_id := PartyID} = -spec construct_payment_tool(ff_destination:resource_full() | ff_destination:resource()) -> dmsl_domain_thrift:'PaymentTool'(). -construct_payment_tool({bank_card, ResourceBankCard}) -> +construct_payment_tool({bank_card, #{bank_card := ResourceBankCard}}) -> {bank_card, #domain_BankCard{ token = maps:get(token, ResourceBankCard), bin = maps:get(bin, ResourceBankCard), @@ -990,7 +989,7 @@ construct_payment_tool({bank_card, ResourceBankCard}) -> bank_name = maps:get(bank_name, ResourceBankCard, undefined) }}; -construct_payment_tool({crypto_wallet, #{currency := {Currency, _}}}) -> +construct_payment_tool({crypto_wallet, #{crypto_wallet := #{currency := {Currency, _}}}}) -> {crypto_currency, Currency}. %% Quote helpers @@ -1058,7 +1057,7 @@ get_quote_(Params, Destination, Resource) -> Quote :: ff_adapter_withdrawal:quote(). wrap_quote(DomainRevision, PartyRevision, Timestamp, Resource, ProviderID, Quote) -> #{quote_data := QuoteData} = Quote, - ResourceID = ff_destination:resource_full_id(Resource), + ResourceID = ff_destination:full_bank_card_id(Resource), Quote#{quote_data := genlib_map:compact(#{ <<"version">> => 1, <<"quote_data">> => QuoteData, @@ -1485,6 +1484,9 @@ maybe_migrate({p_transfer, PEvent}) -> {p_transfer, ff_postings_transfer:maybe_migrate(PEvent, withdrawal)}; maybe_migrate({adjustment, _Payload} = Event) -> ff_adjustment_utils:maybe_migrate(Event); +maybe_migrate({resource_got, Resource}) -> + {resource_got, ff_instrument:maybe_migrate_resource(Resource)}; + % Old events maybe_migrate({limit_check, {wallet, Details}}) -> maybe_migrate({limit_check, {wallet_sender, Details}}); diff --git a/apps/ff_transfer/test/ff_transfer_SUITE.erl b/apps/ff_transfer/test/ff_transfer_SUITE.erl index 688dac0..b5a126a 100644 --- a/apps/ff_transfer/test/ff_transfer_SUITE.erl +++ b/apps/ff_transfer/test/ff_transfer_SUITE.erl @@ -460,7 +460,7 @@ process_deposit(SrcID, WalID) -> ok = await_wallet_balance({10000, <<"RUB">>}, WalID). create_destination(IID, C) -> - DestResource = {bank_card, ct_cardstore:bank_card(<<"4150399999000900">>, {12, 2025}, C)}, + DestResource = {bank_card, #{bank_card => ct_cardstore:bank_card(<<"4150399999000900">>, {12, 2025}, C)}}, DestID = create_instrument(destination, IID, <<"XDesination">>, <<"RUB">>, DestResource, C), authorized = ct_helper:await( authorized, @@ -472,10 +472,10 @@ create_destination(IID, C) -> DestID. create_crypto_destination(IID, C) -> - Resource = {crypto_wallet, #{ + Resource = {crypto_wallet, #{crypto_wallet => #{ id => <<"a30e277c07400c9940628828949efd48">>, currency => {litecoin, #{}} - }}, + }}}, DestID = create_instrument(destination, IID, <<"CryptoDestination">>, <<"RUB">>, Resource, C), authorized = ct_helper:await( authorized, diff --git a/apps/ff_transfer/test/ff_withdrawal_SUITE.erl b/apps/ff_transfer/test/ff_withdrawal_SUITE.erl index af7ebe1..a892e5c 100644 --- a/apps/ff_transfer/test/ff_withdrawal_SUITE.erl +++ b/apps/ff_transfer/test/ff_withdrawal_SUITE.erl @@ -599,7 +599,7 @@ create_destination(IID, Currency, Token, C) -> Token -> StoreSource#{token => Token} end, - Resource = {bank_card, NewStoreResource}, + Resource = {bank_card, #{bank_card => NewStoreResource}}, Params = #{id => ID, identity => IID, name => <<"XDesination">>, currency => Currency, resource => Resource}, ok = ff_destination:create(Params, ff_entity_context:new()), authorized = ct_helper:await( @@ -613,10 +613,10 @@ create_destination(IID, Currency, Token, C) -> create_crypto_destination(IID, _C) -> ID = generate_id(), - Resource = {crypto_wallet, #{ + Resource = {crypto_wallet, #{crypto_wallet => #{ id => <<"a30e277c07400c9940628828949efd48">>, currency => {litecoin, #{}} - }}, + }}}, Params = #{id => ID, identity => IID, name => <<"CryptoDestination">>, currency => <<"RUB">>, resource => Resource}, ok = ff_destination:create(Params, ff_entity_context:new()), authorized = ct_helper:await( diff --git a/apps/ff_transfer/test/ff_withdrawal_adjustment_SUITE.erl b/apps/ff_transfer/test/ff_withdrawal_adjustment_SUITE.erl index 7975e7f..218accf 100644 --- a/apps/ff_transfer/test/ff_withdrawal_adjustment_SUITE.erl +++ b/apps/ff_transfer/test/ff_withdrawal_adjustment_SUITE.erl @@ -440,7 +440,7 @@ generate_id() -> create_destination(IID, C) -> ID = generate_id(), - Resource = {bank_card, ct_cardstore:bank_card(<<"4150399999000900">>, {12, 2025}, C)}, + Resource = {bank_card, #{bank_card => ct_cardstore:bank_card(<<"4150399999000900">>, {12, 2025}, C)}}, Params = #{id => ID, identity => IID, name => <<"XDesination">>, currency => <<"RUB">>, resource => Resource}, ok = ff_destination:create(Params, ff_entity_context:new()), authorized = ct_helper:await( diff --git a/apps/fistful/src/ff_dmsl_codec.erl b/apps/fistful/src/ff_dmsl_codec.erl index 3adb00b..1dfbd65 100644 --- a/apps/fistful/src/ff_dmsl_codec.erl +++ b/apps/fistful/src/ff_dmsl_codec.erl @@ -151,14 +151,24 @@ unmarshal(resource, {disposable, #domain_DisposablePaymentResource{ payment_system = PaymentSystem, bin = Bin, last_digits = LastDigits - }} + }}, + payment_session_id = ID }}) -> - {bank_card, #{ - token => Token, - payment_system => PaymentSystem, - bin => Bin, - masked_pan => LastDigits - }}; + AuthData = case ID of + undefined -> + undefined; + ID -> + {session, #{session_id => unmarshal(string, ID)}} + end, + {bank_card, genlib_map:compact(#{ + bank_card => #{ + token => Token, + payment_system => PaymentSystem, + bin => Bin, + masked_pan => LastDigits + }, + auth_data => AuthData + })}; unmarshal(amount, V) -> unmarshal(integer, V); @@ -207,21 +217,30 @@ marshal(payment_resource_payer, Payer = #{resource := Resource}) -> ClientInfo = maps:get(client_info, Payer, undefined), ContactInfo = maps:get(contact_info, Payer, undefined), #domain_PaymentResourcePayer{ - resource = #domain_DisposablePaymentResource{ - payment_tool = marshal(resource, Resource), - client_info = maybe_marshal(client_info, ClientInfo) - }, + resource = marshal(disposable_payment_resource, {Resource, ClientInfo}), contact_info = marshal(contact_info, ContactInfo) }; -marshal(resource, {bank_card, BankCard}) -> - {bank_card, #domain_BankCard{ + +marshal(disposable_payment_resource, {Resource, ClientInfo}) -> + #domain_DisposablePaymentResource{ + payment_tool = marshal(payment_tool, Resource), + payment_session_id = try_get_session_auth_data(Resource), + client_info = maybe_marshal(client_info, ClientInfo) + }; + +marshal(payment_tool, {bank_card, #{bank_card := BankCard}}) -> + {bank_card, marshal(bank_card, BankCard)}; + +marshal(bank_card, BankCard) -> + #domain_BankCard{ token = ff_resource:token(BankCard), bin = ff_resource:bin(BankCard), last_digits = ff_resource:masked_pan(BankCard), payment_system = ff_resource:payment_system(BankCard), issuer_country = ff_resource:country_code(BankCard), bank_name = ff_resource:bank_name(BankCard) - }}; + }; + marshal(contact_info, undefined) -> #domain_ContactInfo{}; marshal(contact_info, ContactInfo) -> @@ -240,8 +259,8 @@ marshal(client_info, ClientInfo) -> marshal(p2p_tool, {Sender, Receiver}) -> #domain_P2PTool{ - sender = marshal(resource, Sender), - receiver = marshal(resource, Receiver) + sender = marshal(payment_tool, Sender), + receiver = marshal(payment_tool, Receiver) }; marshal(risk_score, low) -> @@ -264,4 +283,9 @@ marshal(_, Other) -> maybe_marshal(_Type, undefined) -> undefined; maybe_marshal(Type, Value) -> - marshal(Type, Value). \ No newline at end of file + marshal(Type, Value). + +try_get_session_auth_data({bank_card, #{auth_data := {session, #{session_id := ID}}}}) -> + marshal(string, ID); +try_get_session_auth_data(_) -> + undefined. diff --git a/apps/fistful/src/ff_resource.erl b/apps/fistful/src/ff_resource.erl index 3dace21..cb7aa4b 100644 --- a/apps/fistful/src/ff_resource.erl +++ b/apps/fistful/src/ff_resource.erl @@ -15,6 +15,15 @@ bin_data_id => bin_data_id() }. +-type resource_bank_card_params() :: #{ + bank_card := bank_card_params(), + auth_data => bank_card_auth_data() +}. + +-type resource_crypto_wallet_params() :: #{ + crypto_wallet := crypto_wallet_params() +}. + -type bank_card_params() :: #{ token := binary(), bin => binary(), @@ -24,19 +33,47 @@ }. -type exp_date() :: {binary(), binary()}. +-type bank_card_auth_data() :: + {session, session_auth_data()}. + +-type session_auth_data() :: #{ + session_id := binary() +}. -type crypto_wallet_params() :: #{ id := binary(), - currency := atom(), - tag => binary() + currency := crypto_currency() }. -type resource_id() :: {bank_card, bin_data_id()}. --type resource_params() :: {bank_card, bank_card_params()} | - {crypto_wallet, crypto_wallet_params()}. --type resource() :: {bank_card, bank_card()} | - {crypto_wallet, crypto_wallet()}. --type crypto_wallet() :: crypto_wallet_params(). +-type resource_params() :: {bank_card, resource_bank_card_params()} | + {crypto_wallet, resource_crypto_wallet_params()}. +-type resource() :: {bank_card, resource_bank_card()} | + {crypto_wallet, resource_crypto_wallet()}. + +-type resource_bank_card() :: #{ + bank_card := bank_card(), + auth_data => bank_card_auth_data() +}. + +-type resource_crypto_wallet() :: #{ + crypto_wallet := crypto_wallet() +}. + +-type crypto_wallet() :: #{ + id := binary(), + currency := crypto_currency() +}. + +-type crypto_currency() + :: {bitcoin, #{}} + | {bitcoin_cash, #{}} + | {litecoin, #{}} + | {ethereum, #{}} + | {zcash, #{}} + | {usdt, #{}} + | {ripple, #{tag => binary()}} + . -type token() :: binary(). -type bin() :: binary(). @@ -110,7 +147,7 @@ country_code(BankCard) -> bank_name(BankCard) -> maps:get(bank_name, BankCard, undefined). --spec create_resource(resource()) -> +-spec create_resource(resource_params()) -> {ok, resource()} | {error, {bin_data, not_found}}. @@ -121,15 +158,26 @@ create_resource(Resource) -> {ok, resource()} | {error, {bin_data, not_found}}. -create_resource({bank_card, #{token := Token} = BankCard}, ResourceID) -> +create_resource({bank_card, #{bank_card := #{token := Token} = BankCardParams} = Params}, ResourceID) -> do(fun() -> BinData = unwrap(bin_data, get_bin_data(Token, ResourceID)), KeyList = [payment_system, bank_name, iso_country_code, card_type], ExtendData = maps:with(KeyList, BinData), - {bank_card, maps:merge(BankCard, ExtendData#{bin_data_id => ff_bin_data:id(BinData)})} + {bank_card, genlib_map:compact(#{ + bank_card => maps:merge(BankCardParams, ExtendData#{bin_data_id => ff_bin_data:id(BinData)}), + auth_data => maps:get(auth_data, Params, undefined) + })} end); -create_resource({crypto_wallet, CryptoWallet}, _ResourceID) -> - {ok, CryptoWallet}. +create_resource({crypto_wallet, #{crypto_wallet := #{ + id := ID, + currency := Currency +}}}, _ResourceID) -> + {ok, {crypto_wallet, #{ + crypto_wallet => #{ + id => ID, + currency => Currency + } + }}}. get_bin_data(Token, undefined) -> ff_bin_data:get(Token, undefined); diff --git a/apps/p2p/src/p2p_adapter_codec.erl b/apps/p2p/src/p2p_adapter_codec.erl index 440dae5..df94faa 100644 --- a/apps/p2p/src/p2p_adapter_codec.erl +++ b/apps/p2p/src/p2p_adapter_codec.erl @@ -134,9 +134,7 @@ marshal(operation_info, OperationInfo = #{ }}; marshal(resource, Resource) -> - {disposable, #domain_DisposablePaymentResource{ - payment_tool = ff_dmsl_codec:marshal(resource, Resource) - }}; + {disposable, ff_dmsl_codec:marshal(disposable_payment_resource, {Resource, undefined})}; marshal(cash, {Amount, Currency}) -> #p2p_adapter_Cash{ diff --git a/apps/p2p/src/p2p_quote.erl b/apps/p2p/src/p2p_quote.erl index 9abb0cd..fce5961 100644 --- a/apps/p2p/src/p2p_quote.erl +++ b/apps/p2p/src/p2p_quote.erl @@ -117,7 +117,7 @@ receiver_id(#{receiver := {bank_card, #{bin_data_id := BinDataID}}}) -> -spec compact(ff_resource:resource()) -> compact_resource(). -compact({bank_card, BankCard}) -> +compact({bank_card, #{bank_card := BankCard}}) -> {bank_card, #{ token => ff_resource:token(BankCard), bin_data_id => ff_resource:bin_data_id(BankCard) diff --git a/apps/p2p/src/p2p_session.erl b/apps/p2p/src/p2p_session.erl index 89f3533..8ed97e1 100644 --- a/apps/p2p/src/p2p_session.erl +++ b/apps/p2p/src/p2p_session.erl @@ -38,7 +38,7 @@ %% %% Types %% --define(ACTUAL_FORMAT_VERSION, 1). +-define(ACTUAL_FORMAT_VERSION, 2). -opaque session() :: #{ version := ?ACTUAL_FORMAT_VERSION, @@ -430,10 +430,33 @@ set_session_status(SessionState, Session) -> -spec maybe_migrate(event() | legacy_event()) -> event(). + +maybe_migrate({created, #{version := 1} = Session}) -> + #{ + version := 1, + transfer_params := #{ + sender := Sender, + receiver := Receiver + } = Params + } = Session, + maybe_migrate({created, genlib_map:compact(Session#{ + version => 2, + transfer_params => Params#{ + sender => maybe_migrate_resource(Sender), + receiver => maybe_migrate_resource(Receiver) + } + })}); % Other events maybe_migrate(Ev) -> Ev. +maybe_migrate_resource({crypto_wallet, #{id := _ID} = CryptoWallet}) -> + maybe_migrate_resource({crypto_wallet, #{crypto_wallet => CryptoWallet}}); +maybe_migrate_resource({bank_card, #{token := _Token} = BankCard}) -> + maybe_migrate_resource({bank_card, #{bank_card => BankCard}}); +maybe_migrate_resource(Resource) -> + Resource. + -spec init(session(), action()) -> {list(event()), action() | undefined}. diff --git a/apps/p2p/src/p2p_transfer.erl b/apps/p2p/src/p2p_transfer.erl index bae7063..0d586b0 100644 --- a/apps/p2p/src/p2p_transfer.erl +++ b/apps/p2p/src/p2p_transfer.erl @@ -8,7 +8,7 @@ -type id() :: binary(). --define(ACTUAL_FORMAT_VERSION, 1). +-define(ACTUAL_FORMAT_VERSION, 2). -opaque p2p_transfer() :: #{ version := ?ACTUAL_FORMAT_VERSION, @@ -1111,7 +1111,33 @@ apply_event_({adjustment, _Ev} = Event, T) -> -spec maybe_migrate(event() | legacy_event()) -> event(). -% Actual events + +maybe_migrate({resource_got, Sender, Receiver}) -> + {resource_got, maybe_migrate_resource(Sender), maybe_migrate_resource(Receiver)}; +maybe_migrate({created, #{version := 1} = Transfer}) -> + #{ + version := 1, + sender := Sender, + receiver := Receiver + } = Transfer, + maybe_migrate({created, genlib_map:compact(Transfer#{ + version => 2, + sender => maybe_migrate_participant(Sender), + receiver => maybe_migrate_participant(Receiver) + })}); +% Other events maybe_migrate(Ev) -> Ev. +maybe_migrate_resource({crypto_wallet, #{id := _ID} = CryptoWallet}) -> + maybe_migrate_resource({crypto_wallet, #{crypto_wallet => CryptoWallet}}); +maybe_migrate_resource({bank_card, #{token := _Token} = BankCard}) -> + maybe_migrate_resource({bank_card, #{bank_card => BankCard}}); +maybe_migrate_resource(Resource) -> + Resource. + +maybe_migrate_participant({raw, #{resource_params := Resource} = Participant}) -> + maybe_migrate_participant({raw, Participant#{resource_params => maybe_migrate_resource(Resource)}}); + +maybe_migrate_participant(Resource) -> + Resource. diff --git a/apps/p2p/test/p2p_adapter_SUITE.erl b/apps/p2p/test/p2p_adapter_SUITE.erl index e4f599d..944e834 100644 --- a/apps/p2p/test/p2p_adapter_SUITE.erl +++ b/apps/p2p/test/p2p_adapter_SUITE.erl @@ -91,8 +91,13 @@ construct_operation_info(ID) -> construct_resource() -> {bank_card, #{ - token => <<"token">>, - bin => <<"bin">>, - payment_system => visa, - masked_pan => <<"masked_pan">> + bank_card => #{ + token => <<"token">>, + bin => <<"bin">>, + payment_system => visa, + masked_pan => <<"masked_pan">> + }, + auth_data => {session, #{ + session_id => <<"ID">> + }} }}. diff --git a/apps/p2p/test/p2p_ct_provider_handler.erl b/apps/p2p/test/p2p_ct_provider_handler.erl index 267c839..32cf12d 100644 --- a/apps/p2p/test/p2p_ct_provider_handler.erl +++ b/apps/p2p/test/p2p_ct_provider_handler.erl @@ -13,6 +13,20 @@ } }} }). + +-define(ADAPTER_CONTEXT(Amount, Token, SessionID, State), #p2p_adapter_Context{ + operation = {process, #p2p_adapter_ProcessOperationInfo{ + body = #p2p_adapter_Cash{amount = Amount}, + sender = {disposable, #domain_DisposablePaymentResource{ + payment_tool = {bank_card, #domain_BankCard{ + token = Token + }}, + payment_session_id = SessionID + }} + }}, + session = #p2p_adapter_Session{state = State} +}). + -define(ADAPTER_CONTEXT(Amount, Token, State), #p2p_adapter_Context{ operation = {process, #p2p_adapter_ProcessOperationInfo{ body = #p2p_adapter_Cash{amount = Amount}, @@ -76,6 +90,11 @@ handle_function(Func, Args, Ctx, Opts) -> end ). +handle_function_('Process', [?ADAPTER_CONTEXT(_Amount, _Token, undefined, _State)], _Ctx, _Opts) -> + {ok, ?ADAPTER_PROCESS_RESULT( + ?ADAPTER_FINISH_INTENT({failure, #domain_Failure{code = <<"unknown session id">>}}), + undefined + )}; handle_function_('Process', [?ADAPTER_CONTEXT(101, _Token, State)], _Ctx, _Opts) -> case State of undefined -> diff --git a/apps/p2p/test/p2p_quote_SUITE.erl b/apps/p2p/test/p2p_quote_SUITE.erl index 73f79d1..28ea51d 100644 --- a/apps/p2p/test/p2p_quote_SUITE.erl +++ b/apps/p2p/test/p2p_quote_SUITE.erl @@ -75,7 +75,7 @@ get_fee_ok_test(C) -> identity_id := Identity, sender := CardSender } = prepare_standard_environment(C), - Sender = {bank_card, CardSender}, + Sender = {bank_card, #{bank_card => CardSender}}, {ok, {Fee, CashVolume, _}} = p2p_quote:get_quote(Cash, Identity, Sender, Sender), ?assertEqual({share, {{65, 10000}, operation_amount, default}}, CashVolume), ?assertEqual({146, <<"RUB">>}, Fee). @@ -88,12 +88,12 @@ visa_to_nspkmir_not_allow_test(C) -> identity_id := Identity, sender := CardSender } = prepare_standard_environment(C), - Sender = {bank_card, CardSender}, - Receiver = {bank_card, #{ + Sender = {bank_card, #{bank_card => CardSender}}, + Receiver = {bank_card, #{bank_card => #{ bin => Bin, masked_pan => Pan, token => <<"NSPK MIR">> - }}, + }}}, Result = p2p_quote:get_quote(Cash, Identity, Sender, Receiver), ?assertEqual({error, {terms, {terms_violation, p2p_forbidden}}}, Result). diff --git a/apps/p2p/test/p2p_session_SUITE.erl b/apps/p2p/test/p2p_session_SUITE.erl index c39d517..0f6b3be 100644 --- a/apps/p2p/test/p2p_session_SUITE.erl +++ b/apps/p2p/test/p2p_session_SUITE.erl @@ -241,7 +241,12 @@ prepare_resource(#{token := Token} = RawBankCard) -> {ok, BinData} = ff_bin_data:get(Token, undefined), KeyList = [payment_system, bank_name, iso_country_code, card_type], ExtendData = maps:with(KeyList, BinData), - {bank_card, maps:merge(RawBankCard, ExtendData#{bin_data_id => ff_bin_data:id(BinData)})}. + {bank_card, #{ + bank_card => maps:merge(RawBankCard, ExtendData#{bin_data_id => ff_bin_data:id(BinData)}), + auth_data => {session, #{ + session_id => <<"ID">> + }} + }}. get_p2p_session(SessionID) -> {ok, Machine} = p2p_session_machine:get(SessionID), diff --git a/apps/p2p/test/p2p_tests_utils.erl b/apps/p2p/test/p2p_tests_utils.erl index 3694d28..e5f6ab4 100644 --- a/apps/p2p/test/p2p_tests_utils.erl +++ b/apps/p2p/test/p2p_tests_utils.erl @@ -63,7 +63,12 @@ create_resource_raw(Token, C) -> Token -> StoreSource#{token => Token} end, - p2p_participant:create(raw, {bank_card, NewStoreResource}). + p2p_participant:create(raw, {bank_card, #{ + bank_card => NewStoreResource, + auth_data => {session, #{ + session_id => <<"ID">> + }} + }}). create_person_identity(Party, C, ProviderID) -> create_identity(Party, ProviderID, <<"person">>, C). diff --git a/apps/p2p/test/p2p_transfer_SUITE.erl b/apps/p2p/test/p2p_transfer_SUITE.erl index e345775..c9a2775 100644 --- a/apps/p2p/test/p2p_transfer_SUITE.erl +++ b/apps/p2p/test/p2p_transfer_SUITE.erl @@ -216,7 +216,7 @@ session_callback_ok_test(C) -> ip_address => <<"some ip_address">>, fingerprint => <<"some fingerprint">> }, - {raw, #{resource_params := {bank_card, #{token := Token}}}} = ResourceSender, + {raw, #{resource_params := {bank_card, #{bank_card := #{token := Token}}}}} = ResourceSender, Callback = ?CALLBACK(Token, <<"payload">>), P2PTransferParams = #{ id => P2PTransferID, diff --git a/apps/p2p/test/p2p_transfer_adjustment_SUITE.erl b/apps/p2p/test/p2p_transfer_adjustment_SUITE.erl index 089d8c0..be9428a 100644 --- a/apps/p2p/test/p2p_transfer_adjustment_SUITE.erl +++ b/apps/p2p/test/p2p_transfer_adjustment_SUITE.erl @@ -387,7 +387,12 @@ generate_id() -> create_resource_raw(C) -> StoreSource = ct_cardstore:bank_card(<<"4150399999000900">>, {12, 2025}, C), - p2p_participant:create(raw, {bank_card, StoreSource}). + p2p_participant:create(raw, {bank_card, #{ + bank_card => StoreSource, + auth_data => {session, #{ + session_id => <<"ID">> + }} + }}). await_final_adjustment_status(P2PTransferID, AdjustmentID) -> finished = ct_helper:await( diff --git a/apps/wapi/src/wapi_destination_backend.erl b/apps/wapi/src/wapi_destination_backend.erl index 7b39504..6211c3b 100644 --- a/apps/wapi/src/wapi_destination_backend.erl +++ b/apps/wapi/src/wapi_destination_backend.erl @@ -118,13 +118,13 @@ when Type =:= <<"BankCardDestinationResource">> -> month = Month, year = Year } = BankCard#'BankCard'.exp_date, - CostructedResource = {bank_card, #{ + CostructedResource = {bank_card, #{bank_card => #{ token => BankCard#'BankCard'.token, bin => BankCard#'BankCard'.bin, masked_pan => BankCard#'BankCard'.masked_pan, cardholder_name => BankCard#'BankCard'.cardholder_name, exp_date => {Month, Year} - }}, + }}}, {ok, ff_codec:marshal(resource, CostructedResource)}; {error, {decryption_failed, _} = Error} -> logger:warning("Resource token decryption failed: ~p", [Error]), @@ -135,10 +135,10 @@ when Type =:= <<"CryptoWalletDestinationResource">> -> #{ <<"id">> := CryptoWalletID } = Resource, - CostructedResource = {crypto_wallet, genlib_map:compact(#{ + CostructedResource = {crypto_wallet, #{crypto_wallet => genlib_map:compact(#{ id => CryptoWalletID, currency => marshal_crypto_currency_data(Resource) - })}, + })}}, {ok, ff_codec:marshal(resource, CostructedResource)}. service_call(Params, Context) -> @@ -170,12 +170,12 @@ marshal(resource, #{ <<"token">> := Token }) -> BankCard = wapi_utils:base64url_to_map(Token), - Resource = {bank_card, #{ + Resource = {bank_card, #{bank_card => #{ token => maps:get(<<"token">>, BankCard), payment_system => erlang:binary_to_existing_atom(maps:get(<<"paymentSystem">>, BankCard), latin1), bin => maps:get(<<"bin">>, BankCard), masked_pan => maps:get(<<"lastDigits">>, BankCard) - }}, + }}}, ff_codec:marshal(resource, Resource); marshal(context, Context) -> @@ -228,21 +228,21 @@ unmarshal(status, {authorized, #dst_Authorized{}}) -> unmarshal(status, {unauthorized, #dst_Unauthorized{}}) -> <<"Unauthorized">>; -unmarshal(resource, {bank_card, #'BankCard'{ +unmarshal(resource, {bank_card, #'ResourceBankCard'{bank_card = #'BankCard'{ token = Token, bin = Bin, masked_pan = MaskedPan -}}) -> +}}}) -> genlib_map:compact(#{ <<"type">> => <<"BankCardDestinationResource">>, <<"token">> => unmarshal(string, Token), <<"bin">> => unmarshal(string, Bin), <<"lastDigits">> => wapi_utils:get_last_pan_digits(MaskedPan) }); -unmarshal(resource, {crypto_wallet, #'CryptoWallet'{ +unmarshal(resource, {crypto_wallet, #'ResourceCryptoWallet'{crypto_wallet = #'CryptoWallet'{ id = CryptoWalletID, data = Data -}}) -> +}}}) -> {Currency, Params} = unmarshal_crypto_currency_data(Data), genlib_map:compact(#{ <<"type">> => <<"CryptoWalletDestinationResource">>, diff --git a/apps/wapi/src/wapi_wallet_ff_backend.erl b/apps/wapi/src/wapi_wallet_ff_backend.erl index d9178f8..e918083 100644 --- a/apps/wapi/src/wapi_wallet_ff_backend.erl +++ b/apps/wapi/src/wapi_wallet_ff_backend.erl @@ -801,17 +801,30 @@ when Type =:= <<"BankCardDestinationResource">> -> unrecognized -> {ok, from_swag(destination_resource, Resource)}; {ok, BankCard} -> - {ok, encode_bank_card(BankCard)}; + {ok, {bank_card, encode_bank_card(BankCard)}}; + {error, {decryption_failed, _} = Error} -> + logger:warning("~s token decryption failed: ~p", [Type, Error]), + {error, {invalid_resource_token, Type}} + end; +construct_resource(#{<<"type">> := Type, <<"token">> := Token, <<"authData">> := AuthData}) +when Type =:= <<"BankCardSenderResourceParams">> -> + case wapi_crypto:decrypt_bankcard_token(Token) of + {ok, BankCard} -> + {ok, encode_resource_bank_card(BankCard, AuthData)}; + unrecognized -> + logger:warning("~s token unrecognized", [Type]), + {error, {invalid_resource_token, Type}}; {error, {decryption_failed, _} = Error} -> logger:warning("~s token decryption failed: ~p", [Type, Error]), {error, {invalid_resource_token, Type}} end; construct_resource(#{<<"type">> := Type, <<"token">> := Token}) when Type =:= <<"BankCardSenderResource">> -orelse Type =:= <<"BankCardReceiverResource">> -> +orelse Type =:= <<"BankCardReceiverResource">> +orelse Type =:= <<"BankCardReceiverResourceParams">> -> case wapi_crypto:decrypt_bankcard_token(Token) of {ok, BankCard} -> - {ok, encode_bank_card(BankCard)}; + {ok, {bank_card, encode_bank_card(BankCard)}}; unrecognized -> logger:warning("~s token unrecognized", [Type]), {error, {invalid_resource_token, Type}}; @@ -821,21 +834,27 @@ orelse Type =:= <<"BankCardReceiverResource">> -> end; construct_resource(#{<<"type">> := Type, <<"id">> := CryptoWalletID} = Resource) when Type =:= <<"CryptoWalletDestinationResource">> -> - {ok, {crypto_wallet, genlib_map:compact(#{ + {ok, {crypto_wallet, #{crypto_wallet => genlib_map:compact(#{ id => CryptoWalletID, currency => from_swag(crypto_wallet_currency, Resource) - })}}. + })}}}. + +encode_resource_bank_card(BankCard, AuthData) -> + EncodedBankCard = encode_bank_card(BankCard), + {bank_card, EncodedBankCard#{auth_data => {session, #{session_id => AuthData}}}}. encode_bank_card(BankCard) -> - {bank_card, genlib_map:compact(#{ - token => BankCard#'BankCard'.token, - bin => BankCard#'BankCard'.bin, - masked_pan => BankCard#'BankCard'.masked_pan, - cardholder_name => BankCard#'BankCard'.cardholder_name, - %% ExpDate is optional in swag_wallets 'StoreBankCard'. But some adapters waiting exp_date. - %% Add error, somethink like BankCardReject.exp_date_required - exp_date => encode_exp_date(BankCard#'BankCard'.exp_date) - })}. + #{ + bank_card => genlib_map:compact(#{ + token => BankCard#'BankCard'.token, + bin => BankCard#'BankCard'.bin, + masked_pan => BankCard#'BankCard'.masked_pan, + cardholder_name => BankCard#'BankCard'.cardholder_name, + %% ExpDate is optional in swag_wallets 'StoreBankCard'. But some adapters waiting exp_date. + %% Add error, somethink like BankCardReject.exp_date_required + exp_date => encode_exp_date(BankCard#'BankCard'.exp_date) + }) + }. encode_exp_date(undefined) -> undefined; @@ -1510,23 +1529,23 @@ from_swag(destination_resource, #{ <<"token">> := WapiToken }) -> BankCard = wapi_utils:base64url_to_map(WapiToken), - {bank_card, #{ + {bank_card, #{bank_card => #{ token => maps:get(<<"token">>, BankCard), payment_system => erlang:binary_to_existing_atom(maps:get(<<"paymentSystem">>, BankCard), latin1), bin => maps:get(<<"bin">>, BankCard), masked_pan => maps:get(<<"lastDigits">>, BankCard) - }}; + }}}; from_swag(destination_resource, Resource = #{ <<"type">> := <<"CryptoWalletDestinationResource">>, <<"id">> := CryptoWalletID, <<"currency">> := CryptoWalletCurrency }) -> Tag = maps:get(<<"tag">>, Resource, undefined), - {crypto_wallet, genlib_map:compact(#{ + {crypto_wallet, #{crypto_wallet => genlib_map:compact(#{ id => CryptoWalletID, currency => from_swag(crypto_wallet_currency, CryptoWalletCurrency), tag => Tag - })}; + })}}; from_swag(quote_p2p_params, Params) -> add_external_id(#{ sender => maps:get(<<"sender">>, Params), @@ -1870,19 +1889,19 @@ to_swag(destination_status, authorized) -> #{<<"status">> => <<"Authorized">>}; to_swag(destination_status, unauthorized) -> #{<<"status">> => <<"Unauthorized">>}; -to_swag(destination_resource, {bank_card, BankCard}) -> +to_swag(destination_resource, {bank_card, #{bank_card := BankCard}}) -> to_swag(map, #{ <<"type">> => <<"BankCardDestinationResource">>, <<"token">> => maps:get(token, BankCard), <<"bin">> => genlib_map:get(bin, BankCard), <<"lastDigits">> => to_swag(pan_last_digits, genlib_map:get(masked_pan, BankCard)) }); -to_swag(destination_resource, {crypto_wallet, CryptoWallet}) -> +to_swag(destination_resource, {crypto_wallet, #{crypto_wallet := CryptoWallet}}) -> to_swag(map, maps:merge(#{ <<"type">> => <<"CryptoWalletDestinationResource">>, <<"id">> => maps:get(id, CryptoWallet) }, to_swag(crypto_wallet_currency, maps:get(currency, CryptoWallet)))); -to_swag(sender_resource, {bank_card, BankCard}) -> +to_swag(sender_resource, {bank_card, #{bank_card := BankCard}}) -> to_swag(map, #{ <<"type">> => <<"BankCardSenderResource">>, <<"token">> => maps:get(token, BankCard), @@ -1890,7 +1909,7 @@ to_swag(sender_resource, {bank_card, BankCard}) -> <<"bin">> => genlib_map:get(bin, BankCard), <<"lastDigits">> => to_swag(pan_last_digits, genlib_map:get(masked_pan, BankCard)) }); -to_swag(receiver_resource, {bank_card, BankCard}) -> +to_swag(receiver_resource, {bank_card, #{bank_card := BankCard}}) -> to_swag(map, #{ <<"type">> => <<"BankCardReceiverResource">>, <<"token">> => maps:get(token, BankCard), @@ -2041,7 +2060,7 @@ to_swag(p2p_transfer_quote, {Cash, Token, ExpiresOn}) -> to_swag(p2p_transfer, P2PTransferState) -> #{ - version := 1, + version := 2, id := Id, body := Cash, created_at := CreatedAt, diff --git a/apps/wapi/test/wapi_destination_tests_SUITE.erl b/apps/wapi/test/wapi_destination_tests_SUITE.erl index 4ec3c40..74d24c6 100644 --- a/apps/wapi/test/wapi_destination_tests_SUITE.erl +++ b/apps/wapi/test/wapi_destination_tests_SUITE.erl @@ -117,7 +117,7 @@ end_per_testcase(_Name, C) -> -spec bank_card_resource_test(config()) -> _. bank_card_resource_test(C) -> {ok, Resource, SwagResource} = do_destination_lifecycle(bank_card, C), - {bank_card, R} = Resource, + {bank_card, #'ResourceBankCard'{bank_card = R}} = Resource, ?assertEqual(<<"BankCardDestinationResource">>, maps:get(<<"type">>, SwagResource)), ?assertEqual(R#'BankCard'.token, maps:get(<<"token">>, SwagResource)), ?assertEqual(R#'BankCard'.bin, maps:get(<<"bin">>, SwagResource)), @@ -128,7 +128,7 @@ bitcoin_resource_test(C) -> {ok, Resource, SwagResource} = do_destination_lifecycle(bitcoin, C), ?assertEqual(<<"CryptoWalletDestinationResource">>, maps:get(<<"type">>, SwagResource)), ?assertEqual(<<"Bitcoin">>, maps:get(<<"currency">>, SwagResource)), - {crypto_wallet, #'CryptoWallet'{id = ID}} = Resource, + {crypto_wallet, #'ResourceCryptoWallet'{crypto_wallet = #'CryptoWallet'{id = ID}}} = Resource, ?assertEqual(ID, maps:get(<<"id">>, SwagResource)). -spec litecoin_resource_test(config()) -> _. @@ -136,7 +136,7 @@ litecoin_resource_test(C) -> {ok, Resource, SwagResource} = do_destination_lifecycle(litecoin, C), ?assertEqual(<<"CryptoWalletDestinationResource">>, maps:get(<<"type">>, SwagResource)), ?assertEqual(<<"Litecoin">>, maps:get(<<"currency">>, SwagResource)), - {crypto_wallet, #'CryptoWallet'{id = ID}} = Resource, + {crypto_wallet, #'ResourceCryptoWallet'{crypto_wallet = #'CryptoWallet'{id = ID}}} = Resource, ?assertEqual(ID, maps:get(<<"id">>, SwagResource)). -spec bitcoin_cash_resource_test(config()) -> _. @@ -144,7 +144,7 @@ bitcoin_cash_resource_test(C) -> {ok, Resource, SwagResource} = do_destination_lifecycle(bitcoin_cash, C), ?assertEqual(<<"CryptoWalletDestinationResource">>, maps:get(<<"type">>, SwagResource)), ?assertEqual(<<"BitcoinCash">>, maps:get(<<"currency">>, SwagResource)), - {crypto_wallet, #'CryptoWallet'{id = ID}} = Resource, + {crypto_wallet, #'ResourceCryptoWallet'{crypto_wallet = #'CryptoWallet'{id = ID}}} = Resource, ?assertEqual(ID, maps:get(<<"id">>, SwagResource)). -spec ripple_resource_test(config()) -> _. @@ -152,12 +152,12 @@ ripple_resource_test(C) -> {ok, Resource, SwagResource} = do_destination_lifecycle(ripple, C), ?assertEqual(<<"CryptoWalletDestinationResource">>, maps:get(<<"type">>, SwagResource)), ?assertEqual(<<"Ripple">>, maps:get(<<"currency">>, SwagResource)), - {crypto_wallet, #'CryptoWallet'{ + {crypto_wallet, #'ResourceCryptoWallet'{crypto_wallet = #'CryptoWallet'{ id = ID, data = {ripple, #'CryptoDataRipple'{ tag = Tag }} - }} = Resource, + }}} = Resource, ?assertEqual(ID, maps:get(<<"id">>, SwagResource)), ?assertEqual(Tag, maps:get(<<"tag">>, SwagResource)). @@ -166,7 +166,7 @@ ethereum_resource_test(C) -> {ok, Resource, SwagResource} = do_destination_lifecycle(ethereum, C), ?assertEqual(<<"CryptoWalletDestinationResource">>, maps:get(<<"type">>, SwagResource)), ?assertEqual(<<"Ethereum">>, maps:get(<<"currency">>, SwagResource)), - {crypto_wallet, #'CryptoWallet'{id = ID}} = Resource, + {crypto_wallet, #'ResourceCryptoWallet'{crypto_wallet = #'CryptoWallet'{id = ID}}} = Resource, ?assertEqual(ID, maps:get(<<"id">>, SwagResource)). -spec usdt_resource_test(config()) -> _. @@ -174,7 +174,7 @@ usdt_resource_test(C) -> {ok, Resource, SwagResource} = do_destination_lifecycle(usdt, C), ?assertEqual(<<"CryptoWalletDestinationResource">>, maps:get(<<"type">>, SwagResource)), ?assertEqual(<<"USDT">>, maps:get(<<"currency">>, SwagResource)), - {crypto_wallet, #'CryptoWallet'{id = ID}} = Resource, + {crypto_wallet, #'ResourceCryptoWallet'{crypto_wallet = #'CryptoWallet'{id = ID}}} = Resource, ?assertEqual(ID, maps:get(<<"id">>, SwagResource)). -spec zcash_resource_test(config()) -> _. @@ -182,7 +182,7 @@ zcash_resource_test(C) -> {ok, Resource, SwagResource} = do_destination_lifecycle(zcash, C), ?assertEqual(<<"CryptoWalletDestinationResource">>, maps:get(<<"type">>, SwagResource)), ?assertEqual(<<"Zcash">>, maps:get(<<"currency">>, SwagResource)), - {crypto_wallet, #'CryptoWallet'{id = ID}} = Resource, + {crypto_wallet, #'ResourceCryptoWallet'{crypto_wallet = #'CryptoWallet'{id = ID}}} = Resource, ?assertEqual(ID, maps:get(<<"id">>, SwagResource)). %% @@ -266,19 +266,19 @@ build_destination_spec(D) -> <<"identity">> => (D#dst_Destination.account)#account_Account.identity, <<"currency">> => ((D#dst_Destination.account)#account_Account.currency)#'CurrencyRef'.symbolic_code, <<"externalID">> => D#dst_Destination.external_id, - <<"resource">> => build_resorce_spec(D#dst_Destination.resource) + <<"resource">> => build_resource_spec(D#dst_Destination.resource) }. -build_resorce_spec({bank_card, R}) -> +build_resource_spec({bank_card, R}) -> #{ <<"type">> => <<"BankCardDestinationResource">>, - <<"token">> => wapi_crypto:encrypt_bankcard_token(R) + <<"token">> => wapi_crypto:encrypt_bankcard_token(R#'ResourceBankCard'.bank_card) }; -build_resorce_spec({crypto_wallet, R}) -> - Spec = build_crypto_cyrrency_spec(R#'CryptoWallet'.data), +build_resource_spec({crypto_wallet, R}) -> + Spec = build_crypto_cyrrency_spec((R#'ResourceCryptoWallet'.crypto_wallet)#'CryptoWallet'.data), Spec#{ <<"type">> => <<"CryptoWalletDestinationResource">>, - <<"id">> => R#'CryptoWallet'.id + <<"id">> => (R#'ResourceCryptoWallet'.crypto_wallet)#'CryptoWallet'.id }. build_crypto_cyrrency_spec({bitcoin, #'CryptoDataBitcoin'{}}) -> @@ -342,7 +342,7 @@ generate_destination(IdentityID, Resource, Context) -> }. generate_resource(bank_card) -> - {bank_card, #'BankCard'{ + {bank_card, #'ResourceBankCard'{bank_card = #'BankCard'{ token = uniq(), bin = <<"424242">>, masked_pan = <<"4242">>, @@ -354,14 +354,14 @@ generate_resource(bank_card) -> month = 12, year = 2200 } - }}; + }}}; generate_resource(ResourceType) -> {Currency, Params} = generate_wallet_data(ResourceType), - {crypto_wallet, #'CryptoWallet'{ + {crypto_wallet, #'ResourceCryptoWallet'{crypto_wallet = #'CryptoWallet'{ id = uniq(), data = {Currency, Params}, currency = Currency - }}. + }}}. generate_wallet_data(bitcoin) -> {bitcoin, #'CryptoDataBitcoin'{}}; diff --git a/apps/wapi/test/wapi_p2p_tests_SUITE.erl b/apps/wapi/test/wapi_p2p_tests_SUITE.erl index f764136..97bd704 100644 --- a/apps/wapi/test/wapi_p2p_tests_SUITE.erl +++ b/apps/wapi/test/wapi_p2p_tests_SUITE.erl @@ -175,11 +175,12 @@ create_p2p_transfer_ok_test(C) -> <<"currency">> => ?RUB }, <<"sender">> => #{ - <<"type">> => <<"BankCardSenderResource">>, - <<"token">> => SenderToken + <<"type">> => <<"BankCardSenderResourceParams">>, + <<"token">> => SenderToken, + <<"authData">> => <<"session id">> }, <<"receiver">> => #{ - <<"type">> => <<"BankCardReceiverResource">>, + <<"type">> => <<"BankCardReceiverResourceParams">>, <<"token">> => ReceiverToken } } @@ -195,7 +196,7 @@ create_p2p_transfer_fail_test(C) -> #{ identity_id := IdentityID } = p2p_tests_utils:prepare_standard_environment({?INTEGER, ?RUB}, C), - {error, {400, #{<<"name">> := <<"BankCardReceiverResource">>}}} = call_api( + {error, {400, #{<<"name">> := <<"BankCardReceiverResourceParams">>}}} = call_api( fun swag_client_wallet_p2_p_api:create_p2_p_transfer/3, #{ body => #{ @@ -205,11 +206,12 @@ create_p2p_transfer_fail_test(C) -> <<"currency">> => ?RUB }, <<"sender">> => #{ - <<"type">> => <<"BankCardSenderResource">>, - <<"token">> => SenderToken + <<"type">> => <<"BankCardSenderResourceParams">>, + <<"token">> => SenderToken, + <<"authData">> => <<"session id">> }, <<"receiver">> => #{ - <<"type">> => <<"BankCardReceiverResource">>, + <<"type">> => <<"BankCardReceiverResourceParams">>, <<"token">> => ReceiverToken } } @@ -256,11 +258,12 @@ create_p2p_transfer_with_token_ok_test(C) -> <<"currency">> => ?RUB }, <<"sender">> => #{ - <<"type">> => <<"BankCardSenderResource">>, - <<"token">> => SenderToken + <<"type">> => <<"BankCardSenderResourceParams">>, + <<"token">> => SenderToken, + <<"authData">> => <<"session id">> }, <<"receiver">> => #{ - <<"type">> => <<"BankCardReceiverResource">>, + <<"type">> => <<"BankCardReceiverResourceParams">>, <<"token">> => ReceiverToken }, <<"quoteToken">> => Token @@ -287,11 +290,12 @@ get_p2p_transfer_ok_test(C) -> <<"currency">> => ?RUB }, <<"sender">> => #{ - <<"type">> => <<"BankCardSenderResource">>, - <<"token">> => SenderToken + <<"type">> => <<"BankCardSenderResourceParams">>, + <<"token">> => SenderToken, + <<"authData">> => <<"session id">> }, <<"receiver">> => #{ - <<"type">> => <<"BankCardReceiverResource">>, + <<"type">> => <<"BankCardReceiverResourceParams">>, <<"token">> => ReceiverToken } } @@ -339,11 +343,12 @@ get_p2p_transfer_events_ok_test(C) -> <<"currency">> => ?RUB }, <<"sender">> => #{ - <<"type">> => <<"BankCardSenderResource">>, - <<"token">> => SenderToken + <<"type">> => <<"BankCardSenderResourceParams">>, + <<"token">> => SenderToken, + <<"authData">> => <<"session id">> }, <<"receiver">> => #{ - <<"type">> => <<"BankCardReceiverResource">>, + <<"type">> => <<"BankCardReceiverResourceParams">>, <<"token">> => ReceiverToken } } diff --git a/rebar.lock b/rebar.lock index cab6478..a2a41d7 100644 --- a/rebar.lock +++ b/rebar.lock @@ -59,7 +59,7 @@ 0}, {<<"fistful_proto">>, {git,"git@github.com:rbkmoney/fistful-proto.git", - {ref,"45bfd9edfdc9a58699e1bd77a4150002c5335146"}}, + {ref,"509c8d3bccc40de9e3151e2869801adfd7b91a47"}}, 0}, {<<"fistful_reporter_proto">>, {git,"git@github.com:rbkmoney/fistful-reporter-proto.git", diff --git a/schemes/swag b/schemes/swag index 47ebaa3..832a525 160000 --- a/schemes/swag +++ b/schemes/swag @@ -1 +1 @@ -Subproject commit 47ebaa35181acac3ab4f6dd326132c2ddd24e1a1 +Subproject commit 832a525b871bc37c1a34a5eba230ca6259c6b68e