diff --git a/lib/checkout_sdk/accounts/accounts.rb b/lib/checkout_sdk/accounts/accounts.rb index 3bf18ec..5316c68 100644 --- a/lib/checkout_sdk/accounts/accounts.rb +++ b/lib/checkout_sdk/accounts/accounts.rb @@ -34,6 +34,7 @@ require 'checkout_sdk/accounts/instrument_details_faster_payments' require 'checkout_sdk/accounts/instrument_details_sepa' require 'checkout_sdk/accounts/instrument_details_card_token' +require 'checkout_sdk/accounts/instrument_details_ach' require 'checkout_sdk/accounts/payment_instrument_request' require 'checkout_sdk/accounts/payment_instruments_query' require 'checkout_sdk/accounts/update_payment_instrument_request' diff --git a/lib/checkout_sdk/accounts/instrument_details_ach.rb b/lib/checkout_sdk/accounts/instrument_details_ach.rb new file mode 100644 index 0000000..ae3efec --- /dev/null +++ b/lib/checkout_sdk/accounts/instrument_details_ach.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Accounts + # ACH bank-account instrument details. Maps swagger `PlatformsInstrumentDetailsAch`. + # All three attributes are required. + # + # @!attribute account_number + # @return [String] The alphanumeric value that identifies the account. + # @!attribute routing_number + # @return [String] The 9-digit American Bankers Association (ABA) routing number that + # identifies the financial institution. + # @!attribute account_type + # @return [String] The type of bank account. One of `savings`, `checking`. + class InstrumentDetailsAch < InstrumentDetails + attr_accessor :account_number, + :routing_number, + :account_type + end + end +end diff --git a/lib/checkout_sdk/issuing/amend_dispute_request.rb b/lib/checkout_sdk/issuing/amend_dispute_request.rb new file mode 100644 index 0000000..3a59a35 --- /dev/null +++ b/lib/checkout_sdk/issuing/amend_dispute_request.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Issuing + # Request body for POST /issuing/disputes/{disputeId}/amend. + # Submit an amendment to a dispute that is currently blocked from proceeding. Maps swagger + # `amend-dispute-request`. All fields are optional. + # + # @!attribute reason + # @return [String] The updated four-digit scheme-specific reason code. If not provided, the + # existing reason code is retained. + # @!attribute amount + # @return [Numeric] The updated disputed amount, in the minor unit of the transaction currency. + # If not provided, the existing amount is retained. + # @!attribute evidence + # @return [Array] Evidence supporting the dispute (maps `IssuingDisputeEvidence`). + # @!attribute fraud_details + # @return [IssuingDisputeFraudDetails] Fraud-related details. Required if `reason` specifies a + # fraud-related dispute. + # @!attribute reason_change_justification + # @return [String] Justification for changing the reason at the escalation stage. Max 13000 + # characters. + # @!attribute action_response + # @return [String] Free-form text explaining your choices or asking questions about the + # requested changes. Max 1000 characters. + class AmendDisputeRequest + attr_accessor :reason, :amount, :evidence, :fraud_details, + :reason_change_justification, :action_response + end + end +end diff --git a/lib/checkout_sdk/issuing/create_dispute_request.rb b/lib/checkout_sdk/issuing/create_dispute_request.rb index 3fc7021..639c4e8 100644 --- a/lib/checkout_sdk/issuing/create_dispute_request.rb +++ b/lib/checkout_sdk/issuing/create_dispute_request.rb @@ -14,11 +14,14 @@ module Issuing # @return [Numeric] # @!attribute presentment_message_id # @return [String] + # @!attribute fraud_details + # @return [IssuingDisputeFraudDetails] Fraud-related information to send with the chargeback. + # Required if the dispute has a fraud-related reason code. # @!attribute justification # @return [String] class CreateDisputeRequest attr_accessor :transaction_id, :reason, :evidence, :amount, - :presentment_message_id, :justification + :presentment_message_id, :fraud_details, :justification end end end diff --git a/lib/checkout_sdk/issuing/escalate_dispute_request.rb b/lib/checkout_sdk/issuing/escalate_dispute_request.rb index 9cfbcd8..e1e58da 100644 --- a/lib/checkout_sdk/issuing/escalate_dispute_request.rb +++ b/lib/checkout_sdk/issuing/escalate_dispute_request.rb @@ -10,10 +10,14 @@ module Issuing # @return [Numeric] # @!attribute reason_change # @return [String] + # @!attribute fraud_details + # @return [IssuingDisputeFraudDetails] Fraud-related details. Required if the dispute has a + # fraud-related reason code at the escalation stage, or after a reason-code change to a + # fraud code. # @!attribute justification # @return [String] Required. class EscalateDisputeRequest - attr_accessor :additional_evidence, :amount, :reason_change, :justification + attr_accessor :additional_evidence, :amount, :reason_change, :fraud_details, :justification end end end diff --git a/lib/checkout_sdk/issuing/identification_document.rb b/lib/checkout_sdk/issuing/identification_document.rb deleted file mode 100644 index 5a192b0..0000000 --- a/lib/checkout_sdk/issuing/identification_document.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -module CheckoutSdk - module Issuing - # Identification document attached to a cardholder. Matches swagger - # `IdentificationDocument`. `type` and `front_document_id` are required. - # - # @!attribute type - # @return [String] Document type (e.g. "passport"). [Required] - # @!attribute front_document_id - # @return [String] File id of the front-side scan. [Required] - # @!attribute back_document_id - # @return [String] File id of the back-side scan (when applicable). - class IdentificationDocument - attr_accessor :type, :front_document_id, :back_document_id - end - end -end diff --git a/lib/checkout_sdk/issuing/issuing.rb b/lib/checkout_sdk/issuing/issuing.rb index b331c07..e59f99d 100644 --- a/lib/checkout_sdk/issuing/issuing.rb +++ b/lib/checkout_sdk/issuing/issuing.rb @@ -8,10 +8,8 @@ # Cardholders / Cards updates require 'checkout_sdk/issuing/issuing_phone_number' require 'checkout_sdk/issuing/issuing_address' -require 'checkout_sdk/issuing/identification_document' require 'checkout_sdk/issuing/update_cardholder_request' require 'checkout_sdk/issuing/update_card_request' -require 'checkout_sdk/issuing/schedule_revocation_request' # Simulations require 'checkout_sdk/issuing/simulate_refund_request' @@ -22,7 +20,11 @@ require 'checkout_sdk/issuing/update_control_profile_request' # Disputes +require 'checkout_sdk/issuing/issuing_dispute_fraud_type' +require 'checkout_sdk/issuing/issuing_dispute_fraud_details' require 'checkout_sdk/issuing/create_dispute_request' require 'checkout_sdk/issuing/escalate_dispute_request' +require 'checkout_sdk/issuing/amend_dispute_request' +require 'checkout_sdk/issuing/submit_dispute_request' require 'checkout_sdk/issuing/issuing_client' diff --git a/lib/checkout_sdk/issuing/issuing_client.rb b/lib/checkout_sdk/issuing/issuing_client.rb index f01d24e..4c35735 100644 --- a/lib/checkout_sdk/issuing/issuing_client.rb +++ b/lib/checkout_sdk/issuing/issuing_client.rb @@ -20,10 +20,11 @@ class IssuingClient < Client REVERSALS = 'reversals' REFUNDS = 'refunds' RENEW = 'renew' - SCHEDULE_REVOCATION = 'schedule-revocation' DISPUTES = 'disputes' CANCEL = 'cancel' ESCALATE = 'escalate' + AMEND = 'amend' + SUBMIT = 'submit' TRANSACTIONS = 'transactions' DIGITAL_CARDS = 'digital-cards' ADD = 'add' @@ -36,7 +37,7 @@ class IssuingClient < Client private_constant :ISSUING, :CARDHOLDERS, :CARDS, :THREE_DS, :ACTIVATE, :CREDENTIALS, :REVOKE, :SUSPEND, :CONTROLS, :CONTROL_GROUPS, :CONTROL_PROFILES, :SIMULATE, :AUTHORIZATIONS, :PRESENTMENTS, :REVERSALS, :REFUNDS, - :RENEW, :SCHEDULE_REVOCATION, :DISPUTES, :CANCEL, :ESCALATE, + :RENEW, :DISPUTES, :CANCEL, :ESCALATE, :AMEND, :SUBMIT, :TRANSACTIONS, :DIGITAL_CARDS, :ADD, :REMOVE # @param [ApiClient] api_client @@ -145,26 +146,6 @@ def renew_card(card_id, renew_request = nil) ) end - # Schedule a card revocation. POST /issuing/cards/{cardId}/schedule-revocation. - # @param [String] card_id - # @param [Hash, ScheduleRevocationRequest] schedule_revocation_request - def schedule_card_revocation(card_id, schedule_revocation_request) - api_client.invoke_post( - build_path(ISSUING, CARDS, card_id, SCHEDULE_REVOCATION), - sdk_authorization, - schedule_revocation_request - ) - end - - # Cancel a scheduled card revocation. DELETE /issuing/cards/{cardId}/schedule-revocation. - # @param [String] card_id - def cancel_scheduled_card_revocation(card_id) - api_client.invoke_delete( - build_path(ISSUING, CARDS, card_id, SCHEDULE_REVOCATION), - sdk_authorization - ) - end - # ====== Controls (legacy single endpoint) ====== # @param [Hash] control_request @@ -317,6 +298,32 @@ def escalate_issuing_dispute(dispute_id, escalate_dispute_request) ) end + # Submit an Issuing dispute. POST /issuing/disputes/{disputeId}/submit. + # @param [String] dispute_id + # @param [Hash, SubmitDisputeRequest] submit_dispute_request + # @deprecated Use {#create_issuing_dispute} to create and submit a dispute in one step, or + # {#amend_issuing_dispute} when the dispute status is `action_required`. + def submit_issuing_dispute(dispute_id, submit_dispute_request = nil) + api_client.invoke_post( + build_path(ISSUING, DISPUTES, dispute_id, SUBMIT), + sdk_authorization, + submit_dispute_request + ) + end + + # Amend an Issuing dispute. POST /issuing/disputes/{disputeId}/amend. + # Submit an amendment to a dispute that is currently blocked from proceeding. Handles both + # chargeback-stage and escalation-stage amendments using the same payload. + # @param [String] dispute_id + # @param [Hash, AmendDisputeRequest] amend_dispute_request + def amend_issuing_dispute(dispute_id, amend_dispute_request = nil) + api_client.invoke_post( + build_path(ISSUING, DISPUTES, dispute_id, AMEND), + sdk_authorization, + amend_dispute_request + ) + end + # ====== Transactions ====== # @param [Hash] transactions_query diff --git a/lib/checkout_sdk/issuing/issuing_dispute_fraud_details.rb b/lib/checkout_sdk/issuing/issuing_dispute_fraud_details.rb new file mode 100644 index 0000000..59558d6 --- /dev/null +++ b/lib/checkout_sdk/issuing/issuing_dispute_fraud_details.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Issuing + # Fraud-related information required when the dispute reason code is fraud-related. + # Maps swagger `IssuingDisputeFraudDetails`. Reused by create, escalate and amend dispute + # requests. + # + # @!attribute fraud_type + # @return [String] {IssuingDisputeFraudType} The type of fraud the cardholder is asserting. + # [Required] + # @!attribute description + # @return [String] Optional free-form description of the fraud. + class IssuingDisputeFraudDetails + attr_accessor :fraud_type, :description + end + end +end diff --git a/lib/checkout_sdk/issuing/issuing_dispute_fraud_type.rb b/lib/checkout_sdk/issuing/issuing_dispute_fraud_type.rb new file mode 100644 index 0000000..226e4cd --- /dev/null +++ b/lib/checkout_sdk/issuing/issuing_dispute_fraud_type.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Issuing + # The type of fraud the cardholder is asserting on an Issuing dispute. + # Maps swagger `IssuingDisputeFraudDetails.fraud_type`. + module IssuingDisputeFraudType + CARD_LOST = 'card_lost' + CARD_STOLEN = 'card_stolen' + CARD_NEVER_RECEIVED = 'card_never_received' + FRAUDULENT_ACCOUNT = 'fraudulent_account' + COUNTERFEIT_CARD = 'counterfeit_card' + ACCOUNT_TAKEOVER = 'account_takeover' + CARD_NOT_PRESENT_FRAUD = 'card_not_present_fraud' + MERCHANT_MISREPRESENTATION = 'merchant_misrepresentation' + CARDHOLDER_MANIPULATION = 'cardholder_manipulation' + INCORRECT_PROCESSING = 'incorrect_processing' + OTHER = 'other' + end + end +end diff --git a/lib/checkout_sdk/issuing/schedule_revocation_request.rb b/lib/checkout_sdk/issuing/schedule_revocation_request.rb deleted file mode 100644 index b29cc66..0000000 --- a/lib/checkout_sdk/issuing/schedule_revocation_request.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -module CheckoutSdk - module Issuing - # Request body for POST /issuing/cards/{cardId}/schedule-revocation. - # - # @!attribute revocation_date - # @return [String] ISO-8601 date the card revocation should take effect. - class ScheduleRevocationRequest - attr_accessor :revocation_date - end - end -end diff --git a/lib/checkout_sdk/issuing/submit_dispute_request.rb b/lib/checkout_sdk/issuing/submit_dispute_request.rb new file mode 100644 index 0000000..fec99e6 --- /dev/null +++ b/lib/checkout_sdk/issuing/submit_dispute_request.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Issuing + # Request body for POST /issuing/disputes/{disputeId}/submit. Maps swagger + # `submit-dispute-request`. All fields are optional. + # + # @!attribute reason + # @return [String] The updated four-digit scheme-specific reason code. If not provided, the + # existing reason code is used. + # @!attribute evidence + # @return [Array] Evidence for the chargeback, if updated since you created the dispute + # (maps `IssuingDisputeEvidence`). + # @!attribute amount + # @return [Numeric] The updated disputed amount, in the minor unit of the transaction currency. + # If not provided, the existing disputed amount is used. + class SubmitDisputeRequest + attr_accessor :reason, :evidence, :amount + end + end +end diff --git a/lib/checkout_sdk/issuing/update_card_request.rb b/lib/checkout_sdk/issuing/update_card_request.rb index cee6110..571aaa7 100644 --- a/lib/checkout_sdk/issuing/update_card_request.rb +++ b/lib/checkout_sdk/issuing/update_card_request.rb @@ -12,8 +12,16 @@ module Issuing # @return [Integer] # @!attribute expiry_year # @return [Integer] + # @!attribute activation_date + # @return [String] ISO-8601 date scheduling the card's activation. Supported formats: + # date only `yyyy-mm-dd` (treated as midnight UTC) or date with round hour + # `yyyy-mm-ddTHH:mmZ` / `yyyy-mm-ddTHH:mm±HH:mm`. Maps swagger `IssuingActivationDate`. + # @!attribute revocation_date + # @return [String] Date for the card to be automatically revoked, in the form `yyyy-mm-dd`. + # Must be after the current date. Maps swagger `IssuingRevocationDate`. class UpdateCardRequest - attr_accessor :reference, :metadata, :expiry_month, :expiry_year + attr_accessor :reference, :metadata, :expiry_month, :expiry_year, + :activation_date, :revocation_date end end end diff --git a/lib/checkout_sdk/issuing/update_cardholder_request.rb b/lib/checkout_sdk/issuing/update_cardholder_request.rb index 9401e75..8ebe12b 100644 --- a/lib/checkout_sdk/issuing/update_cardholder_request.rb +++ b/lib/checkout_sdk/issuing/update_cardholder_request.rb @@ -21,12 +21,9 @@ module Issuing # @return [IssuingAddress] # @!attribute residency_address # @return [IssuingAddress] - # @!attribute document - # @return [IdentificationDocument] class UpdateCardholderRequest attr_accessor :first_name, :middle_name, :last_name, :date_of_birth, - :phone_number, :email, :billing_address, :residency_address, - :document + :phone_number, :email, :billing_address, :residency_address end end end diff --git a/lib/checkout_sdk/payments/payments.rb b/lib/checkout_sdk/payments/payments.rb index 7a9e39e..05f4579 100644 --- a/lib/checkout_sdk/payments/payments.rb +++ b/lib/checkout_sdk/payments/payments.rb @@ -192,6 +192,10 @@ require 'checkout_sdk/payments/setups/account_funding_transaction_recipient' require 'checkout_sdk/payments/setups/payment_setup_account_funding_transaction' require 'checkout_sdk/payments/setups/blik_payment_method' +require 'checkout_sdk/payments/setups/bacs_payment_method' +require 'checkout_sdk/payments/setups/card_present_payment_method' +require 'checkout_sdk/payments/setups/pay_by_bank_payment_method' +require 'checkout_sdk/payments/setups/stablecoin_payment_method' require 'checkout_sdk/payments/setups/payment_setups_client' # Payment Flow diff --git a/lib/checkout_sdk/payments/setups/bacs_payment_method.rb b/lib/checkout_sdk/payments/setups/bacs_payment_method.rb new file mode 100644 index 0000000..83fe5c7 --- /dev/null +++ b/lib/checkout_sdk/payments/setups/bacs_payment_method.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # Bacs payment method configuration on a Payment Setup. Maps swagger `Bacs`. + # + # @!attribute status + # @return [String] (response-only) Payment method status. + # @!attribute flags + # @return [Array(String)] (response-only) Diagnostic flags returned by the API. + # @!attribute initialization + # @return [String] The initialization type for the payment method. + # @!attribute instrument_id + # @return [String] (response-only) The ID of the Bacs instrument used for the payment. + # @!attribute account_holder + # @return [Hash] The account holder details (`type`, `first_name`, `last_name`, + # `company_name`, `email`). + # @!attribute account_number + # @return [String] The account number of the Bacs Direct Debit account. + # @!attribute bank_code + # @return [String] The bank code (sort code) of the Bacs Direct Debit account. + # @!attribute country + # @return [String] {CheckoutSdk::Common::Country} + # @!attribute currency + # @return [String] {CheckoutSdk::Common::Currency} + # @!attribute allow_partial_match + # @return [TrueClass, FalseClass] Whether to allow a partial match of the account holder details. + class BacsPaymentMethod + attr_accessor :status, + :flags, + :initialization, + :instrument_id, + :account_holder, + :account_number, + :bank_code, + :country, + :currency, + :allow_partial_match + end + end +end diff --git a/lib/checkout_sdk/payments/setups/card_present_payment_method.rb b/lib/checkout_sdk/payments/setups/card_present_payment_method.rb new file mode 100644 index 0000000..2679164 --- /dev/null +++ b/lib/checkout_sdk/payments/setups/card_present_payment_method.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # Card Present payment method configuration on a Payment Setup. Maps swagger `CardPresent`. + # + # @!attribute status + # @return [String] (response-only) Payment method status. + # @!attribute flags + # @return [Array(String)] (response-only) Diagnostic flags returned by the API. + # @!attribute track2 + # @return [String] The Track 2 data read from card or device. + # @!attribute emv + # @return [String] The EMV data read from the card or device. + # @!attribute entry_mode + # @return [String] The mode used to capture the card details at the point of sale. + # @!attribute pin + # @return [Hash] The encrypted PIN block details (`key_set_id`, `block`, `block_format`). + # @!attribute store_for_future_use + # @return [TrueClass, FalseClass] Set to `true` if you intend to reuse the payment credentials + # in subsequent payments. + # @!attribute name + # @return [String] The cardholder name. + class CardPresentPaymentMethod + attr_accessor :status, + :flags, + :track2, + :emv, + :entry_mode, + :pin, + :store_for_future_use, + :name + end + end +end diff --git a/lib/checkout_sdk/payments/setups/pay_by_bank_payment_method.rb b/lib/checkout_sdk/payments/setups/pay_by_bank_payment_method.rb new file mode 100644 index 0000000..4fe6928 --- /dev/null +++ b/lib/checkout_sdk/payments/setups/pay_by_bank_payment_method.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # Pay by Bank (Open Banking) payment method configuration on a Payment Setup. + # Maps swagger `PayByBank`. + # + # @!attribute status + # @return [String] (response-only) Payment method status. + # @!attribute flags + # @return [Array(String)] (response-only) Diagnostic flags returned by the API. + # @!attribute bank_id + # @return [String] The identifier of the bank the customer has selected for the payment. + # @!attribute action + # @return [Hash] (response-only) The next available action for the payment method + # (`type`, `banks`). + class PayByBankPaymentMethod + attr_accessor :status, + :flags, + :bank_id, + :action + end + end +end diff --git a/lib/checkout_sdk/payments/setups/stablecoin_payment_method.rb b/lib/checkout_sdk/payments/setups/stablecoin_payment_method.rb new file mode 100644 index 0000000..cce50c0 --- /dev/null +++ b/lib/checkout_sdk/payments/setups/stablecoin_payment_method.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # Stablecoin payment method configuration on a Payment Setup. Maps swagger `Stablecoin`. + # + # @!attribute status + # @return [String] (response-only) Payment method status. + # @!attribute flags + # @return [Array(String)] (response-only) Diagnostic flags returned by the API. + class StablecoinPaymentMethod + attr_accessor :status, + :flags + end + end +end diff --git a/spec/checkout_sdk/accounts/instrument_details_ach_spec.rb b/spec/checkout_sdk/accounts/instrument_details_ach_spec.rb new file mode 100644 index 0000000..d9472b3 --- /dev/null +++ b/spec/checkout_sdk/accounts/instrument_details_ach_spec.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +RSpec.describe CheckoutSdk::Accounts::InstrumentDetailsAch do + it 'is an InstrumentDetails' do + expect(described_class.new).to be_a(CheckoutSdk::Accounts::InstrumentDetails) + end + + it 'serializes all three fields to their swagger keys' do + details = described_class.new + details.account_number = '12345100' + details.routing_number = '026009593' + details.account_type = 'savings' + + hash = CheckoutSdk::JsonSerializer.to_custom_hash(details) + + expect(hash['account_number']).to eq('12345100') + expect(hash['routing_number']).to eq('026009593') + expect(hash['account_type']).to eq('savings') + end +end diff --git a/spec/checkout_sdk/issuing/issuing_disputes_serialization_spec.rb b/spec/checkout_sdk/issuing/issuing_disputes_serialization_spec.rb new file mode 100644 index 0000000..ebd9128 --- /dev/null +++ b/spec/checkout_sdk/issuing/issuing_disputes_serialization_spec.rb @@ -0,0 +1,124 @@ +# frozen_string_literal: true + +RSpec.describe 'Issuing disputes/cards serialization' do + describe CheckoutSdk::Issuing::IssuingDisputeFraudType do + it 'maps every value to its exact swagger string' do + expected = { + CARD_LOST: 'card_lost', + CARD_STOLEN: 'card_stolen', + CARD_NEVER_RECEIVED: 'card_never_received', + FRAUDULENT_ACCOUNT: 'fraudulent_account', + COUNTERFEIT_CARD: 'counterfeit_card', + ACCOUNT_TAKEOVER: 'account_takeover', + CARD_NOT_PRESENT_FRAUD: 'card_not_present_fraud', + MERCHANT_MISREPRESENTATION: 'merchant_misrepresentation', + CARDHOLDER_MANIPULATION: 'cardholder_manipulation', + INCORRECT_PROCESSING: 'incorrect_processing', + OTHER: 'other' + } + expected.each do |const, value| + expect(described_class.const_get(const)).to eq(value) + end + expect(described_class.constants.size).to eq(11) + end + end + + describe CheckoutSdk::Issuing::IssuingDisputeFraudDetails do + it 'serializes fraud_type and description' do + details = described_class.new + details.fraud_type = CheckoutSdk::Issuing::IssuingDisputeFraudType::CARD_STOLEN + details.description = 'wallet was stolen' + + hash = CheckoutSdk::JsonSerializer.to_custom_hash(details) + + expect(hash['fraud_type']).to eq('card_stolen') + expect(hash['description']).to eq('wallet was stolen') + end + end + + describe CheckoutSdk::Issuing::CreateDisputeRequest do + it 'serializes nested fraud_details' do + details = CheckoutSdk::Issuing::IssuingDisputeFraudDetails.new + details.fraud_type = CheckoutSdk::Issuing::IssuingDisputeFraudType::COUNTERFEIT_CARD + + req = described_class.new + req.transaction_id = 'txn_1' + req.reason = '4808' + req.fraud_details = details + + hash = CheckoutSdk::JsonSerializer.to_custom_hash(req) + + expect(hash['transaction_id']).to eq('txn_1') + expect(hash['reason']).to eq('4808') + expect(hash['fraud_details']['fraud_type']).to eq('counterfeit_card') + end + end + + describe CheckoutSdk::Issuing::EscalateDisputeRequest do + it 'serializes nested fraud_details' do + details = CheckoutSdk::Issuing::IssuingDisputeFraudDetails.new + details.fraud_type = CheckoutSdk::Issuing::IssuingDisputeFraudType::ACCOUNT_TAKEOVER + + req = described_class.new + req.justification = 'reason' + req.fraud_details = details + + hash = CheckoutSdk::JsonSerializer.to_custom_hash(req) + + expect(hash['justification']).to eq('reason') + expect(hash['fraud_details']['fraud_type']).to eq('account_takeover') + end + end + + describe CheckoutSdk::Issuing::AmendDisputeRequest do + it 'serializes all six fields incl. action_response' do + details = CheckoutSdk::Issuing::IssuingDisputeFraudDetails.new + details.fraud_type = CheckoutSdk::Issuing::IssuingDisputeFraudType::OTHER + + req = described_class.new + req.reason = '4807' + req.amount = 1500 + req.evidence = [{ 'evidence_type' => 'proof_of_purchase' }] + req.fraud_details = details + req.reason_change_justification = 'updated reason' + req.action_response = 'answering the requested changes' + + hash = CheckoutSdk::JsonSerializer.to_custom_hash(req) + + expect(hash['reason']).to eq('4807') + expect(hash['amount']).to eq(1500) + expect(hash['evidence']).to eq([{ 'evidence_type' => 'proof_of_purchase' }]) + expect(hash['fraud_details']['fraud_type']).to eq('other') + expect(hash['reason_change_justification']).to eq('updated reason') + expect(hash['action_response']).to eq('answering the requested changes') + end + end + + describe CheckoutSdk::Issuing::SubmitDisputeRequest do + it 'serializes reason, evidence and amount' do + req = described_class.new + req.reason = '4807' + req.evidence = [{ 'evidence_type' => 'proof_of_purchase' }] + req.amount = 100 + + hash = CheckoutSdk::JsonSerializer.to_custom_hash(req) + + expect(hash['reason']).to eq('4807') + expect(hash['evidence']).to eq([{ 'evidence_type' => 'proof_of_purchase' }]) + expect(hash['amount']).to eq(100) + end + end + + describe CheckoutSdk::Issuing::UpdateCardRequest do + it 'serializes activation_date and revocation_date' do + req = described_class.new + req.activation_date = '2026-06-01T10:00Z' + req.revocation_date = '2027-03-12' + + hash = CheckoutSdk::JsonSerializer.to_custom_hash(req) + + expect(hash['activation_date']).to eq('2026-06-01T10:00Z') + expect(hash['revocation_date']).to eq('2027-03-12') + end + end +end diff --git a/spec/checkout_sdk/issuing/issuing_extras_spec.rb b/spec/checkout_sdk/issuing/issuing_extras_spec.rb index 10167c4..4748e5a 100644 --- a/spec/checkout_sdk/issuing/issuing_extras_spec.rb +++ b/spec/checkout_sdk/issuing/issuing_extras_spec.rb @@ -35,23 +35,6 @@ end end - describe '#schedule_card_revocation' do - it 'POSTs issuing/cards/{id}/schedule-revocation' do - req = CheckoutSdk::Issuing::ScheduleRevocationRequest.new - expect(api_client_mock).to receive(:invoke_post) - .with('issuing/cards/crd_1/schedule-revocation', 'secret_key', req).and_return('r') - expect(client.schedule_card_revocation('crd_1', req)).to eq('r') - end - end - - describe '#cancel_scheduled_card_revocation' do - it 'DELETEs issuing/cards/{id}/schedule-revocation' do - expect(api_client_mock).to receive(:invoke_delete) - .with('issuing/cards/crd_1/schedule-revocation', 'secret_key').and_return('r') - expect(client.cancel_scheduled_card_revocation('crd_1')).to eq('r') - end - end - describe '#simulate_refund' do it 'POSTs issuing/simulate/authorizations/{id}/refunds' do req = CheckoutSdk::Issuing::SimulateRefundRequest.new @@ -163,6 +146,28 @@ .with('issuing/disputes/dsp_1/escalate', 'secret_key', req).and_return('r') expect(client.escalate_issuing_dispute('dsp_1', req)).to eq('r') end + + it 'POSTs issuing/disputes/{id}/amend' do + req = CheckoutSdk::Issuing::AmendDisputeRequest.new + req.reason = '4807' + expect(api_client_mock).to receive(:invoke_post) + .with('issuing/disputes/dsp_1/amend', 'secret_key', req).and_return('r') + expect(client.amend_issuing_dispute('dsp_1', req)).to eq('r') + end + + it 'POSTs issuing/disputes/{id}/amend with nil body' do + expect(api_client_mock).to receive(:invoke_post) + .with('issuing/disputes/dsp_1/amend', 'secret_key', nil).and_return('r') + expect(client.amend_issuing_dispute('dsp_1')).to eq('r') + end + + it 'POSTs issuing/disputes/{id}/submit (deprecated)' do + req = CheckoutSdk::Issuing::SubmitDisputeRequest.new + req.reason = '4807' + expect(api_client_mock).to receive(:invoke_post) + .with('issuing/disputes/dsp_1/submit', 'secret_key', req).and_return('r') + expect(client.submit_issuing_dispute('dsp_1', req)).to eq('r') + end end describe '#get_transactions and #get_transaction' do diff --git a/spec/checkout_sdk/payments/setups/setup_payment_methods_serialization_spec.rb b/spec/checkout_sdk/payments/setups/setup_payment_methods_serialization_spec.rb new file mode 100644 index 0000000..bff3122 --- /dev/null +++ b/spec/checkout_sdk/payments/setups/setup_payment_methods_serialization_spec.rb @@ -0,0 +1,104 @@ +# frozen_string_literal: true + +RSpec.describe 'Payment Setups payment-method configs serialization' do + describe CheckoutSdk::Payments::BacsPaymentMethod do + it 'serializes its fields to their swagger keys' do + pm = described_class.new + pm.status = 'available' + pm.flags = %w[flag_a] + pm.instrument_id = 'src_wkq7552u245upl5h75x24554xy' + pm.initialization = 'setup' + pm.account_holder = { 'type' => 'individual', 'first_name' => 'John' } + pm.account_number = '12345678' + pm.bank_code = '200000' + pm.country = 'GB' + pm.currency = 'GBP' + pm.allow_partial_match = true + + hash = CheckoutSdk::JsonSerializer.to_custom_hash(pm) + + expect(hash['status']).to eq('available') + expect(hash['flags']).to eq(%w[flag_a]) + expect(hash['instrument_id']).to eq('src_wkq7552u245upl5h75x24554xy') + expect(hash['initialization']).to eq('setup') + expect(hash['account_holder']).to eq({ 'type' => 'individual', 'first_name' => 'John' }) + expect(hash['account_number']).to eq('12345678') + expect(hash['bank_code']).to eq('200000') + expect(hash['country']).to eq('GB') + expect(hash['currency']).to eq('GBP') + expect(hash['allow_partial_match']).to be(true) + end + end + + describe CheckoutSdk::Payments::CardPresentPaymentMethod do + it 'serializes its fields to their swagger keys' do + pm = described_class.new + pm.status = 'available' + pm.flags = %w[flag_a] + pm.track2 = 'track2-data' + pm.emv = 'emv-data' + pm.entry_mode = 'contactless' + pm.pin = { 'key_set_id' => 'ks_1', 'block' => 'b', 'block_format' => 'iso0' } + pm.store_for_future_use = true + pm.name = 'John Smith' + + hash = CheckoutSdk::JsonSerializer.to_custom_hash(pm) + + expect(hash['status']).to eq('available') + expect(hash['flags']).to eq(%w[flag_a]) + expect(hash['track2']).to eq('track2-data') + expect(hash['emv']).to eq('emv-data') + expect(hash['entry_mode']).to eq('contactless') + expect(hash['pin']).to eq({ 'key_set_id' => 'ks_1', 'block' => 'b', 'block_format' => 'iso0' }) + expect(hash['store_for_future_use']).to be(true) + expect(hash['name']).to eq('John Smith') + end + end + + describe CheckoutSdk::Payments::PayByBankPaymentMethod do + it 'serializes bank_id, status, flags and action' do + pm = described_class.new + pm.bank_id = 'ob-natwest' + pm.status = 'available' + pm.flags = %w[flag_a] + pm.action = { 'type' => 'select_bank', 'banks' => [{ 'bank_id' => 'ob-natwest' }] } + + hash = CheckoutSdk::JsonSerializer.to_custom_hash(pm) + + expect(hash['bank_id']).to eq('ob-natwest') + expect(hash['status']).to eq('available') + expect(hash['flags']).to eq(%w[flag_a]) + expect(hash['action']).to eq({ 'type' => 'select_bank', 'banks' => [{ 'bank_id' => 'ob-natwest' }] }) + end + end + + describe CheckoutSdk::Payments::StablecoinPaymentMethod do + it 'serializes its response fields' do + pm = described_class.new + pm.status = 'available' + pm.flags = %w[flag_a] + + hash = CheckoutSdk::JsonSerializer.to_custom_hash(pm) + + expect(hash['status']).to eq('available') + expect(hash['flags']).to eq(%w[flag_a]) + end + end + + describe 'order amount_allocations (reuses Common::AmountAllocations)' do + it 'serializes id, amount, reference and commission' do + allocation = CheckoutSdk::Common::AmountAllocations.new + allocation.id = 'ent_w4jelhppmfiufdnatam37wrfc4' + allocation.amount = 1000 + allocation.reference = 'ORD-5023-4E89' + allocation.commission = CheckoutSdk::Common::Commission.new + + hash = CheckoutSdk::JsonSerializer.to_custom_hash(allocation) + + expect(hash['id']).to eq('ent_w4jelhppmfiufdnatam37wrfc4') + expect(hash['amount']).to eq(1000) + expect(hash['reference']).to eq('ORD-5023-4E89') + expect(hash).to have_key('commission') + end + end +end