diff --git a/.gitignore b/.gitignore index 4bcbc48..8d70187 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ # rspec failure tracking .rspec_status .idea +.claude/rules/* +.cursor/rules/* +.cursor/skills/* diff --git a/.rubocop.yml b/.rubocop.yml index c5d4488..f4ff214 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -18,12 +18,21 @@ Metrics/ModuleLength: Metrics/MethodLength: Max: 25 + Exclude: + # Aggregator that wires up every product client; grows with each new product. + - "**/checkout_api.rb" Metrics/ParameterLists: Max: 10 Metrics/ClassLength: - Max: 120 + # Raised from 120: SDK classes (e.g. ApiClient, response DTOs) grow as new + # API conventions and fields are adopted upstream. + Max: 150 + Exclude: + # Endpoint-collection clients: one method per REST endpoint, grow with the API. + - "**/issuing_client.rb" + - "**/accounts_client.rb" Metrics/CyclomaticComplexity: Max: 10 @@ -37,6 +46,11 @@ Style/Documentation: Style/OpenStructUse: Enabled: false +Naming/AccessorMethodName: + # The SDK consistently prefixes read endpoints with get_ to mirror the REST API + # (e.g. get_cardholder, get_card_details). Zero-arg variants would otherwise flag. + Enabled: false + Naming/MethodName: Exclude: - "**/google_pay_token_data*" diff --git a/lib/checkout_sdk.rb b/lib/checkout_sdk.rb index f4b4fe9..5358f88 100644 --- a/lib/checkout_sdk.rb +++ b/lib/checkout_sdk.rb @@ -68,6 +68,13 @@ require 'checkout_sdk/financial/financial' require 'checkout_sdk/issuing/issuing' require 'checkout_sdk/forward/forward' +require 'checkout_sdk/onboarding_simulator/onboarding_simulator' +require 'checkout_sdk/agentic_commerce/agentic_commerce' +require 'checkout_sdk/compliance_requests/compliance_requests' +require 'checkout_sdk/standalone_account_updater/standalone_account_updater' +require 'checkout_sdk/network_tokens/network_tokens' +require 'checkout_sdk/payment_methods/payment_methods' +require 'checkout_sdk/identities/identities' # Checkout modules (previous) require 'checkout_sdk/sources/sources' diff --git a/lib/checkout_sdk/accounts/accounts.rb b/lib/checkout_sdk/accounts/accounts.rb index 6e594bc..3bf18ec 100644 --- a/lib/checkout_sdk/accounts/accounts.rb +++ b/lib/checkout_sdk/accounts/accounts.rb @@ -36,7 +36,6 @@ require 'checkout_sdk/accounts/instrument_details_card_token' require 'checkout_sdk/accounts/payment_instrument_request' require 'checkout_sdk/accounts/payment_instruments_query' -require 'checkout_sdk/accounts/headers' require 'checkout_sdk/accounts/update_payment_instrument_request' require 'checkout_sdk/accounts/additional_document' require 'checkout_sdk/accounts/additional_info' @@ -59,3 +58,13 @@ require 'checkout_sdk/accounts/shareholder_structure_type' require 'checkout_sdk/accounts/tax_verification' require 'checkout_sdk/accounts/tax_verification_type' +require 'checkout_sdk/accounts/submitter' +require 'checkout_sdk/accounts/entity_requirement_reason' +require 'checkout_sdk/accounts/entity_requirement_priority' +require 'checkout_sdk/accounts/entity_requirement_update_status' +require 'checkout_sdk/accounts/entity_requirement_update_request' +require 'checkout_sdk/accounts/reserve_rule_holding_duration' +require 'checkout_sdk/accounts/rolling_reserve_rule' +require 'checkout_sdk/accounts/reserve_rule_update_request' +require 'checkout_sdk/accounts/reserve_rule_create_request' +require 'checkout_sdk/accounts/entity_files_request' diff --git a/lib/checkout_sdk/accounts/accounts_client.rb b/lib/checkout_sdk/accounts/accounts_client.rb index bef0c89..81c6fd0 100644 --- a/lib/checkout_sdk/accounts/accounts_client.rb +++ b/lib/checkout_sdk/accounts/accounts_client.rb @@ -11,7 +11,11 @@ class AccountsClient < Client PAYOUT_SCHEDULE = 'payout-schedules' FILES = 'files' PAYMENT_INSTRUMENTS = 'payment-instruments' - private_constant :ACCOUNTS, :ENTITIES, :INSTRUMENT, :PAYOUT_SCHEDULE, :FILES, :PAYMENT_INSTRUMENTS + REQUIREMENTS = 'requirements' + RESERVE_RULES = 'reserve-rules' + MEMBERS = 'members' + private_constant :ACCOUNTS, :ENTITIES, :INSTRUMENT, :PAYOUT_SCHEDULE, :FILES, :PAYMENT_INSTRUMENTS, + :REQUIREMENTS, :RESERVE_RULES, :MEMBERS # @param [ApiClient] api_client # @param [ApiClient] files_client @@ -93,6 +97,135 @@ def retrieve_payout_schedule(entity_id) def upload_file(file_request) files_client.submit_file(FILES, sdk_authorization, file_request) end + + # Retrieve the list of pending requirements that a sub-entity must resolve. + # @param [String] entity_id + def get_entity_requirements(entity_id) + api_client.invoke_get( + build_path(ACCOUNTS, ENTITIES, entity_id, REQUIREMENTS), + sdk_authorization + ) + end + + # Retrieve detailed information for a single requirement. + # @param [String] entity_id + # @param [String] requirement_id + def get_entity_requirement_details(entity_id, requirement_id) + api_client.invoke_get( + build_path(ACCOUNTS, ENTITIES, entity_id, REQUIREMENTS, requirement_id), + sdk_authorization + ) + end + + # Submit a response to resolve a requirement. + # @param [String] entity_id + # @param [String] requirement_id + # @param [Hash, EntityRequirementUpdateRequest] update_request + def resolve_entity_requirement(entity_id, requirement_id, update_request) + api_client.invoke_put( + build_path(ACCOUNTS, ENTITIES, entity_id, REQUIREMENTS, requirement_id), + sdk_authorization, + update_request + ) + end + + # Add a reserve rule for a sub-entity. + # @param [String] entity_id + # @param [Hash, ReserveRuleCreateRequest] reserve_rule_request + def add_reserve_rule(entity_id, reserve_rule_request) + api_client.invoke_post( + build_path(ACCOUNTS, ENTITIES, entity_id, RESERVE_RULES), + sdk_authorization, + reserve_rule_request + ) + end + + # Query reserve rules for a sub-entity. + # @param [String] entity_id + def query_reserve_rules(entity_id) + api_client.invoke_get( + build_path(ACCOUNTS, ENTITIES, entity_id, RESERVE_RULES), + sdk_authorization + ) + end + + # Retrieve a reserve rule by id. + # @param [String] entity_id + # @param [String] reserve_rule_id + def get_reserve_rule(entity_id, reserve_rule_id) + api_client.invoke_get( + build_path(ACCOUNTS, ENTITIES, entity_id, RESERVE_RULES, reserve_rule_id), + sdk_authorization + ) + end + + # Update a reserve rule. + # The API enforces optimistic concurrency: the ETag returned by GET must be + # echoed back via {CheckoutSdk::Common::Headers#if_match}, otherwise the + # API responds 428 Precondition Required. + # @param [String] entity_id + # @param [String] reserve_rule_id + # @param [String] etag ETag value to forward as the `If-Match` HTTP header. + # @param [Hash, ReserveRuleUpdateRequest] reserve_rule_request + def update_reserve_rule(entity_id, reserve_rule_id, etag, reserve_rule_request) + headers = nil + if !etag.nil? && !etag.empty? + headers = CheckoutSdk::Common::Headers.new + headers.if_match = etag + end + + api_client.invoke_put( + build_path(ACCOUNTS, ENTITIES, entity_id, RESERVE_RULES, reserve_rule_id), + sdk_authorization, + reserve_rule_request, + headers + ) + end + + # List sub-entity members. + # @param [String] entity_id + def get_sub_entity_members(entity_id) + api_client.invoke_get( + build_path(ACCOUNTS, ENTITIES, entity_id, MEMBERS), + sdk_authorization + ) + end + + # Reinvite a sub-entity member. + # The API marks the request body as required; callers must provide a Hash + # (or `PlatformsHostedOnboardReinviteRequest`-shaped object), even if it + # is empty `{}` per the current swagger contract. + # @param [String] entity_id + # @param [String] user_id + # @param [Hash] reinvite_request Required body per swagger; pass `{}` if no fields are needed. + def reinvite_sub_entity_member(entity_id, user_id, reinvite_request) + api_client.invoke_put( + build_path(ACCOUNTS, ENTITIES, entity_id, MEMBERS, user_id), + sdk_authorization, + reinvite_request + ) + end + + # Upload a file scoped to a sub-entity. Hits POST /entities/{entityId}/files. + # @param [String] entity_id + # @param [Hash, EntityFilesRequest] file_request + def upload_entity_file(entity_id, file_request) + files_client.submit_file( + build_path(ENTITIES, entity_id, FILES), + sdk_authorization, + file_request + ) + end + + # Retrieve a file scoped to a sub-entity. Hits GET /entities/{entityId}/files/{fileId}. + # @param [String] entity_id + # @param [String] file_id + def get_entity_file(entity_id, file_id) + files_client.invoke_get( + build_path(ENTITIES, entity_id, FILES, file_id), + sdk_authorization + ) + end end end end diff --git a/lib/checkout_sdk/accounts/entity_files_request.rb b/lib/checkout_sdk/accounts/entity_files_request.rb new file mode 100644 index 0000000..84d4c3d --- /dev/null +++ b/lib/checkout_sdk/accounts/entity_files_request.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Accounts + # Request body for POST /entities/{entityId}/files. + # + # @!attribute purpose + # @return [String] Purpose of the file (e.g. "bank_verification"). + class EntityFilesRequest + attr_accessor :purpose + end + end +end diff --git a/lib/checkout_sdk/accounts/entity_requirement_priority.rb b/lib/checkout_sdk/accounts/entity_requirement_priority.rb new file mode 100644 index 0000000..6216139 --- /dev/null +++ b/lib/checkout_sdk/accounts/entity_requirement_priority.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Accounts + # Priority of a sub-entity requirement. "critical" if the deadline is within 7 days, + # otherwise "high" by default. + module EntityRequirementPriority + HIGH = 'high' + CRITICAL = 'critical' + end + end +end diff --git a/lib/checkout_sdk/accounts/entity_requirement_reason.rb b/lib/checkout_sdk/accounts/entity_requirement_reason.rb new file mode 100644 index 0000000..8f7f837 --- /dev/null +++ b/lib/checkout_sdk/accounts/entity_requirement_reason.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Accounts + # Reasons why a requirement was raised on a sub-entity. + module EntityRequirementReason + PERIODIC_REVIEW = 'periodic_review' + ATTESTATION = 'attestation' + end + end +end diff --git a/lib/checkout_sdk/accounts/entity_requirement_update_request.rb b/lib/checkout_sdk/accounts/entity_requirement_update_request.rb new file mode 100644 index 0000000..f1f8efc --- /dev/null +++ b/lib/checkout_sdk/accounts/entity_requirement_update_request.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Accounts + # Request body for PUT /accounts/entities/{id}/requirements/{requirementId}. + # + # The expected shape of `value` is defined by the JSON Schema returned in + # the requirement details response. Common shapes include a file reference + # (e.g. { "file_id": "file_..." }), a primitive value, or a structured object. + # + # @!attribute value + # The response to the requirement. Polymorphic per swagger + # (`oneOf [object, array, string, number, boolean]`), so the only valid + # Ruby annotation is `Object`. The concrete shape is dictated at runtime + # by the requirement's `_schema` returned from + # `GET /accounts/entities/{id}/requirements/{requirementId}`. + # @return [Object] + class EntityRequirementUpdateRequest + attr_accessor :value + end + end +end diff --git a/lib/checkout_sdk/accounts/entity_requirement_update_status.rb b/lib/checkout_sdk/accounts/entity_requirement_update_status.rb new file mode 100644 index 0000000..ecc17b5 --- /dev/null +++ b/lib/checkout_sdk/accounts/entity_requirement_update_status.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Accounts + # Status returned after submitting a requirement response. + # While processing, the requirement is no longer retrievable via GET endpoints; + # if validation fails downstream the requirement may reappear. + module EntityRequirementUpdateStatus + PROCESSING = 'processing' + end + end +end diff --git a/lib/checkout_sdk/accounts/headers.rb b/lib/checkout_sdk/accounts/headers.rb deleted file mode 100644 index ae549fd..0000000 --- a/lib/checkout_sdk/accounts/headers.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -module CheckoutSdk - module Accounts - # @!attribute if_match - # @return [String] - class Headers - attr_accessor :if_match - end - end -end diff --git a/lib/checkout_sdk/accounts/onboard_entity.rb b/lib/checkout_sdk/accounts/onboard_entity.rb index 7e6adb0..996f31e 100644 --- a/lib/checkout_sdk/accounts/onboard_entity.rb +++ b/lib/checkout_sdk/accounts/onboard_entity.rb @@ -20,6 +20,12 @@ module Accounts # @return [OnboardSubEntityDocuments] # @!attribute additional_info # @return [AdditionalInfo] + # @!attribute seller_category + # @return [String] Identifier of a seller category configured on the platform + # during onboarding. Used for US ISV onboarding variants. + # @!attribute submitter + # @return [Submitter] Captures evidence of the end-user's consent to onboarding. + # Used for US ISV onboarding variants. class OnboardEntity attr_accessor :reference, :is_draft, @@ -29,7 +35,9 @@ class OnboardEntity :processing_details, :individual, :documents, - :additional_info + :additional_info, + :seller_category, + :submitter end end end diff --git a/lib/checkout_sdk/accounts/reserve_rule_create_request.rb b/lib/checkout_sdk/accounts/reserve_rule_create_request.rb new file mode 100644 index 0000000..0fde08e --- /dev/null +++ b/lib/checkout_sdk/accounts/reserve_rule_create_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Accounts + # Request body for POST /accounts/entities/{id}/reserve-rules. + # Extends {ReserveRuleUpdateRequest} with `valid_from`. + # + # @!attribute valid_from + # @return [String] ISO-8601 timestamp; must be at least 15 minutes in the future. + class ReserveRuleCreateRequest < ReserveRuleUpdateRequest + attr_accessor :valid_from + end + end +end diff --git a/lib/checkout_sdk/accounts/reserve_rule_holding_duration.rb b/lib/checkout_sdk/accounts/reserve_rule_holding_duration.rb new file mode 100644 index 0000000..75ef120 --- /dev/null +++ b/lib/checkout_sdk/accounts/reserve_rule_holding_duration.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Accounts + # The length of time a rolling reserve collateral balance is held for. + # + # @!attribute weeks + # @return [Integer] Min 2, max 104. + class ReserveRuleHoldingDuration + attr_accessor :weeks + end + end +end diff --git a/lib/checkout_sdk/accounts/reserve_rule_update_request.rb b/lib/checkout_sdk/accounts/reserve_rule_update_request.rb new file mode 100644 index 0000000..5852703 --- /dev/null +++ b/lib/checkout_sdk/accounts/reserve_rule_update_request.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Accounts + # Request body for PUT /accounts/entities/{entityId}/reserve-rules/{id}. + # + # @!attribute type + # @return [String] Reserve rule type (e.g. "rolling"). + # @!attribute rolling + # @return [RollingReserveRule] + class ReserveRuleUpdateRequest + attr_accessor :type, :rolling + end + end +end diff --git a/lib/checkout_sdk/accounts/rolling_reserve_rule.rb b/lib/checkout_sdk/accounts/rolling_reserve_rule.rb new file mode 100644 index 0000000..7c9ae0c --- /dev/null +++ b/lib/checkout_sdk/accounts/rolling_reserve_rule.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Accounts + # Rolling reserve rule parameters. + # + # @!attribute percentage + # @return [Float] Min 0, max 100. + # @!attribute holding_duration + # @return [ReserveRuleHoldingDuration] + class RollingReserveRule + attr_accessor :percentage, :holding_duration + end + end +end diff --git a/lib/checkout_sdk/accounts/submitter.rb b/lib/checkout_sdk/accounts/submitter.rb new file mode 100644 index 0000000..a932746 --- /dev/null +++ b/lib/checkout_sdk/accounts/submitter.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Accounts + # Captures evidence of the end-user's consent to onboarding. + # + # @!attribute ip_address + # @return [String] IP address of the end-user submitting the onboarding request. + class Submitter + attr_accessor :ip_address + end + end +end diff --git a/lib/checkout_sdk/agentic_commerce/agentic_commerce.rb b/lib/checkout_sdk/agentic_commerce/agentic_commerce.rb new file mode 100644 index 0000000..127543e --- /dev/null +++ b/lib/checkout_sdk/agentic_commerce/agentic_commerce.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +require 'checkout_sdk/agentic_commerce/delegated_payment_method_card' +require 'checkout_sdk/agentic_commerce/delegated_payment_allowance' +require 'checkout_sdk/agentic_commerce/delegated_payment_billing_address' +require 'checkout_sdk/agentic_commerce/delegated_payment_risk_signal' +require 'checkout_sdk/agentic_commerce/delegated_payment_request' +require 'checkout_sdk/agentic_commerce/agentic_commerce_client' diff --git a/lib/checkout_sdk/agentic_commerce/agentic_commerce_client.rb b/lib/checkout_sdk/agentic_commerce/agentic_commerce_client.rb new file mode 100644 index 0000000..8cf6cde --- /dev/null +++ b/lib/checkout_sdk/agentic_commerce/agentic_commerce_client.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module CheckoutSdk + module AgenticCommerce + # Client for the Agentic Commerce Protocol API (Beta). + # Used by AI agents to create delegated payment tokens scoped to a single purchase. + class AgenticCommerceClient < Client + AGENTIC_COMMERCE = 'agentic_commerce' + DELEGATE_PAYMENT = 'delegate_payment' + private_constant :AGENTIC_COMMERCE, :DELEGATE_PAYMENT + + # @param [ApiClient] api_client + # @param [CheckoutConfiguration] configuration + def initialize(api_client, configuration) + super(api_client, configuration, CheckoutSdk::AuthorizationType::SECRET_KEY) + end + + # Create a delegated payment token. + # @param [Hash, DelegatedPaymentRequest] delegated_payment_request + # @param [String] idempotency_key Optional + def create_delegated_payment_token(delegated_payment_request, idempotency_key = nil) + api_client.invoke_post( + build_path(AGENTIC_COMMERCE, DELEGATE_PAYMENT), + sdk_authorization, + delegated_payment_request, + idempotency_key + ) + end + end + end +end diff --git a/lib/checkout_sdk/agentic_commerce/delegated_payment_allowance.rb b/lib/checkout_sdk/agentic_commerce/delegated_payment_allowance.rb new file mode 100644 index 0000000..a4b8dad --- /dev/null +++ b/lib/checkout_sdk/agentic_commerce/delegated_payment_allowance.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module CheckoutSdk + module AgenticCommerce + # Spend-limit allowance attached to a delegated payment. + # + # @!attribute reason + # @return [String] e.g. "purchase". + # @!attribute max_amount + # @return [Integer] Maximum amount in the minor currency unit. + # @!attribute currency + # @return [String] {CheckoutSdk::Common::Currency} + # @!attribute checkout_session_id + # @return [String] + # @!attribute merchant_id + # @return [String] + # @!attribute expires_at + # @return [String] RFC 3339 timestamp. + class DelegatedPaymentAllowance + attr_accessor :reason, + :max_amount, + :currency, + :checkout_session_id, + :merchant_id, + :expires_at + end + end +end diff --git a/lib/checkout_sdk/agentic_commerce/delegated_payment_billing_address.rb b/lib/checkout_sdk/agentic_commerce/delegated_payment_billing_address.rb new file mode 100644 index 0000000..acef4e4 --- /dev/null +++ b/lib/checkout_sdk/agentic_commerce/delegated_payment_billing_address.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module CheckoutSdk + module AgenticCommerce + # Billing address required for delegated payments. Mirrors swagger + # `DelegatedPaymentBillingAddress`. Required: `name`, `line_one`, `city`, + # `postal_code`, `country`. + # + # @!attribute name + # @return [String] Full customer name. [Required] + # @!attribute line_one + # @return [String] First line of the street address. [Required] + # @!attribute line_two + # @return [String] Second line of the street address. + # @!attribute city + # @return [String] [Required] + # @!attribute state + # @return [String] State / region. + # @!attribute postal_code + # @return [String] Postal/ZIP code. [Required] + # @!attribute country + # @return [String] ISO 3166-1 alpha-2. [Required] + class DelegatedPaymentBillingAddress + attr_accessor :name, + :line_one, + :line_two, + :city, + :state, + :postal_code, + :country + end + end +end diff --git a/lib/checkout_sdk/agentic_commerce/delegated_payment_method_card.rb b/lib/checkout_sdk/agentic_commerce/delegated_payment_method_card.rb new file mode 100644 index 0000000..8edb17a --- /dev/null +++ b/lib/checkout_sdk/agentic_commerce/delegated_payment_method_card.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +module CheckoutSdk + module AgenticCommerce + # Card payment-method block used inside a {DelegatedPaymentRequest}. + # Mirrors swagger `DelegatedPaymentMethodCard`. Required fields per spec: + # `type`, `card_number_type`, `number`, `metadata`. + # + # @!attribute type + # @return [String] Always "card". + # @!attribute card_number_type + # @return [String] Either "fpan" or "network_token". + # @!attribute number + # @return [String] The full card number. + # @!attribute exp_month + # @return [String] Two-digit expiry month (MM). + # @!attribute exp_year + # @return [String] Four-digit expiry year (YYYY). + # @!attribute name + # @return [String] Cardholder name. + # @!attribute cvc + # @return [String] Card verification code. + # @!attribute cryptogram + # @return [String] Cryptogram for network-token transactions. + # @!attribute eci_value + # @return [String] ECI / Security Level Indicator value. + # @!attribute checks_performed + # @return [Array] Verification checks performed on the card. + # @!attribute iin + # @return [String] Issuer Identification Number (BIN). + # @!attribute display_card_funding_type + # @return [String] "credit", "debit", or "prepaid". + # @!attribute display_wallet_type + # @return [String] Wallet type for display. + # @!attribute display_brand + # @return [String] Card brand for display (e.g. "Visa"). + # @!attribute display_last4 + # @return [String] Last four digits for display. + # @!attribute metadata + # @return [Hash{String => String}] Key-value pairs; required per swagger. + class DelegatedPaymentMethodCard + attr_accessor :type, + :card_number_type, + :number, + :exp_month, + :exp_year, + :name, + :cvc, + :cryptogram, + :eci_value, + :checks_performed, + :iin, + :display_card_funding_type, + :display_wallet_type, + :display_brand, + :display_last4, + :metadata + + def initialize + @type = 'card' + end + end + end +end diff --git a/lib/checkout_sdk/agentic_commerce/delegated_payment_request.rb b/lib/checkout_sdk/agentic_commerce/delegated_payment_request.rb new file mode 100644 index 0000000..479ca51 --- /dev/null +++ b/lib/checkout_sdk/agentic_commerce/delegated_payment_request.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module CheckoutSdk + module AgenticCommerce + # Request body for POST /agentic_commerce/delegate_payment. + # + # @!attribute payment_method + # @return [DelegatedPaymentMethodCard] + # @!attribute allowance + # @return [DelegatedPaymentAllowance] + # @!attribute billing_address + # @return [DelegatedPaymentBillingAddress] + # @!attribute risk_signals + # @return [Array] + # @!attribute metadata + # @return [Hash{String => String}] Free-form key/value metadata. + class DelegatedPaymentRequest + attr_accessor :payment_method, + :allowance, + :billing_address, + :risk_signals, + :metadata + end + end +end diff --git a/lib/checkout_sdk/agentic_commerce/delegated_payment_risk_signal.rb b/lib/checkout_sdk/agentic_commerce/delegated_payment_risk_signal.rb new file mode 100644 index 0000000..be034eb --- /dev/null +++ b/lib/checkout_sdk/agentic_commerce/delegated_payment_risk_signal.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module CheckoutSdk + module AgenticCommerce + # Risk signal attached to a delegated payment request. Mirrors swagger + # `DelegatedPaymentRiskSignal`. All three fields are required per spec. + # + # @!attribute type + # @return [String] Risk signal type. [Required] + # @!attribute score + # @return [Integer] Risk score. [Required] + # @!attribute action + # @return [String] Action taken based on the risk assessment. [Required] + class DelegatedPaymentRiskSignal + attr_accessor :type, + :score, + :action + end + end +end diff --git a/lib/checkout_sdk/api_client.rb b/lib/checkout_sdk/api_client.rb index 93cb534..8a19f43 100644 --- a/lib/checkout_sdk/api_client.rb +++ b/lib/checkout_sdk/api_client.rb @@ -22,8 +22,8 @@ def invoke_post(path, authorization, request = nil, idempotency_key = nil) invoke(:post, path, authorization, request, idempotency_key, params: nil) end - def invoke_put(path, authorization, request) - invoke(:put, path, authorization, request, nil, params: nil) + def invoke_put(path, authorization, request, headers = nil) + invoke(:put, path, authorization, request, nil, params: nil, extra_headers: headers) end def invoke_patch(path, authorization, request = nil) @@ -40,13 +40,15 @@ def submit_file(path, authorization, request) private - def invoke(method, path, authorization, body = nil, idempotency_key = nil, params: nil) + def invoke(method, path, authorization, body = nil, idempotency_key = nil, params: nil, extra_headers: nil) path = append_params(path, params) unless params.nil? headers = default_headers(authorization) headers[:'Content-Type'] = 'application/json' headers[:'Cko-Idempotency-Key'] = idempotency_key unless idempotency_key.nil? + apply_extra_headers(headers, extra_headers) + json_body = CheckoutSdk::JsonSerializer.to_custom_hash(body).to_json begin @@ -64,6 +66,16 @@ def default_headers(authorization) Authorization: authorization.authorization_header } end + # Map a typed headers container (e.g. {CheckoutSdk::Common::Headers}) onto the underlying + # HTTP header hash. Each attribute that's set is emitted as the corresponding + # canonical HTTP header. + def apply_extra_headers(http_headers, extra_headers) + return if extra_headers.nil? + return unless extra_headers.respond_to?(:if_match) && extra_headers.if_match + + http_headers[:'If-Match'] = extra_headers.if_match + end + def append_params(path, input_params) raise CheckoutArgumentException, 'Query parameters were not provided' if input_params.nil? diff --git a/lib/checkout_sdk/balances/balance_values.rb b/lib/checkout_sdk/balances/balance_values.rb new file mode 100644 index 0000000..8de1e37 --- /dev/null +++ b/lib/checkout_sdk/balances/balance_values.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Balances + # Balance values returned per currency account (swagger schema: Balance). + # + # @!attribute pending + # @return [Integer] Incoming funds that will be added to Available once cleared. + # @!attribute available + # @return [Integer] Funds available for processing. + # @!attribute payable + # @return [Integer] Funds reserved from Available for outgoing transactions not yet cleared. + # @!attribute collateral + # @return [Integer] Funds held to cover potential liabilities. + # @!attribute operational + # @return [Integer] Funds held for processing Payouts and Issuing payments when Available is insufficient. + # @!attribute collateral_breakdown + # @return [CollateralBreakdown] + class BalanceValues + attr_accessor :pending, + :available, + :payable, + :collateral, + :operational, + :collateral_breakdown + end + end +end diff --git a/lib/checkout_sdk/balances/balances.rb b/lib/checkout_sdk/balances/balances.rb index 0d648af..fd105d8 100644 --- a/lib/checkout_sdk/balances/balances.rb +++ b/lib/checkout_sdk/balances/balances.rb @@ -1,3 +1,7 @@ # frozen_string_literal: true +require 'checkout_sdk/balances/balances_query' +require 'checkout_sdk/balances/collateral_breakdown' +require 'checkout_sdk/balances/balance_values' +require 'checkout_sdk/balances/currency_account_balance' require 'checkout_sdk/balances/balances_client' diff --git a/lib/checkout_sdk/balances/balances_query.rb b/lib/checkout_sdk/balances/balances_query.rb new file mode 100644 index 0000000..1529afb --- /dev/null +++ b/lib/checkout_sdk/balances/balances_query.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Balances + # Query parameters accepted by GET /balances/{id}. + # + # @!attribute query + # @return [String] Search expression (e.g. "currency:EUR"). + # @!attribute with_currency_account_id + # @return [TrueClass, FalseClass] When true, the response includes the + # `currency_account_id` on each {CurrencyAccountBalance}. + # Serialised as `withCurrencyAccountId`. + # @!attribute balances_at + # @return [String] A UTC datetime (RFC 3339) to retrieve historical + # balances at a specific point in time. Must be in the past. + # Serialised as `balancesAt`. + class BalancesQuery + attr_accessor :query, + :with_currency_account_id, + :balances_at + + # Returns the params in the camelCase form expected by the API. + def to_h + { + query: query, + withCurrencyAccountId: with_currency_account_id, + balancesAt: balances_at + }.compact + end + end + end +end diff --git a/lib/checkout_sdk/balances/collateral_breakdown.rb b/lib/checkout_sdk/balances/collateral_breakdown.rb new file mode 100644 index 0000000..45c38b0 --- /dev/null +++ b/lib/checkout_sdk/balances/collateral_breakdown.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Balances + # Breakdown of the funds held in the `collateral` balance. + # + # @!attribute fixed_reserve + # @return [Integer] (required) The portion of the `collateral` balance held as a fixed reserve. + # @!attribute rolling_reserve + # @return [Integer] (required) The portion of the `collateral` balance held as a rolling reserve. + class CollateralBreakdown + attr_accessor :fixed_reserve, + :rolling_reserve + end + end +end diff --git a/lib/checkout_sdk/balances/currency_account_balance.rb b/lib/checkout_sdk/balances/currency_account_balance.rb new file mode 100644 index 0000000..2500dd4 --- /dev/null +++ b/lib/checkout_sdk/balances/currency_account_balance.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Balances + # A single currency account's balance details (swagger: CurrencyAccountBalance). + # + # @!attribute currency_account_id + # @return [String] The unique identifier of the currency account (sub-account). + # Returned only when the request is made with `withCurrencyAccountId=true`. + # @!attribute descriptor + # @return [String] + # @!attribute holding_currency + # @return [String] {CheckoutSdk::Common::Currency} + # @!attribute balances_as_of + # @return [String] UTC datetime (RFC 3339) reflecting when balance values were fetched. + # @!attribute balances + # @return [BalanceValues] + class CurrencyAccountBalance + attr_accessor :currency_account_id, + :descriptor, + :holding_currency, + :balances_as_of, + :balances + end + end +end diff --git a/lib/checkout_sdk/checkout_api.rb b/lib/checkout_sdk/checkout_api.rb index ad2fef7..ce07457 100644 --- a/lib/checkout_sdk/checkout_api.rb +++ b/lib/checkout_sdk/checkout_api.rb @@ -49,6 +49,32 @@ module CheckoutSdk # @return [CheckoutSdk::Payments::FlowClient] # @!attribute forward # @return [CheckoutSdk::Forward::ForwardClient] + # @!attribute onboarding_simulator + # @return [CheckoutSdk::OnboardingSimulator::OnboardingSimulatorClient] + # @!attribute agentic_commerce + # @return [CheckoutSdk::AgenticCommerce::AgenticCommerceClient] + # @!attribute compliance_requests + # @return [CheckoutSdk::ComplianceRequests::ComplianceRequestsClient] + # @!attribute standalone_account_updater + # @return [CheckoutSdk::StandaloneAccountUpdater::StandaloneAccountUpdaterClient] + # @!attribute network_tokens + # @return [CheckoutSdk::NetworkTokens::NetworkTokensClient] + # @!attribute payment_methods + # @return [CheckoutSdk::PaymentMethods::PaymentMethodsClient] + # @!attribute applicants + # @return [CheckoutSdk::Identities::Applicants::ApplicantsClient] + # @!attribute aml_screening + # @return [CheckoutSdk::Identities::AmlScreening::AmlScreeningClient] + # @!attribute id_document_verification + # @return [CheckoutSdk::Identities::IdDocumentVerification::IdDocumentVerificationClient] + # @!attribute identity_verification + # @return [CheckoutSdk::Identities::IdentityVerification::IdentityVerificationClient] + # @!attribute face_authentication + # @return [CheckoutSdk::Identities::FaceAuthentication::FaceAuthenticationClient] + # @!attribute apple_pay + # @return [CheckoutSdk::Payments::ApplePayClient] + # @!attribute google_pay + # @return [CheckoutSdk::Payments::GooglePayClient] class CheckoutApi attr_reader :customers, :disputes, @@ -73,7 +99,20 @@ class CheckoutApi :issuing, :contexts, :payment_sessions, - :forward + :forward, + :onboarding_simulator, + :agentic_commerce, + :compliance_requests, + :standalone_account_updater, + :network_tokens, + :payment_methods, + :applicants, + :aml_screening, + :id_document_verification, + :identity_verification, + :face_authentication, + :apple_pay, + :google_pay # @param [CheckoutConfiguration] configuration def initialize(configuration) @@ -102,6 +141,23 @@ def initialize(configuration) @payments_setups = CheckoutSdk::Payments::PaymentSetupsClient.new api_client, configuration @flow = CheckoutSdk::Payments::FlowClient.new api_client, configuration @forward = CheckoutSdk::Forward::ForwardClient.new(api_client, configuration) + @onboarding_simulator = CheckoutSdk::OnboardingSimulator::OnboardingSimulatorClient.new(api_client, configuration) + @agentic_commerce = CheckoutSdk::AgenticCommerce::AgenticCommerceClient.new(api_client, configuration) + @compliance_requests = CheckoutSdk::ComplianceRequests::ComplianceRequestsClient.new(api_client, configuration) + @standalone_account_updater = + CheckoutSdk::StandaloneAccountUpdater::StandaloneAccountUpdaterClient.new(api_client, configuration) + @network_tokens = CheckoutSdk::NetworkTokens::NetworkTokensClient.new(api_client, configuration) + @payment_methods = CheckoutSdk::PaymentMethods::PaymentMethodsClient.new(api_client, configuration) + @applicants = CheckoutSdk::Identities::Applicants::ApplicantsClient.new(api_client, configuration) + @aml_screening = CheckoutSdk::Identities::AmlScreening::AmlScreeningClient.new(api_client, configuration) + @id_document_verification = + CheckoutSdk::Identities::IdDocumentVerification::IdDocumentVerificationClient.new(api_client, configuration) + @identity_verification = + CheckoutSdk::Identities::IdentityVerification::IdentityVerificationClient.new(api_client, configuration) + @face_authentication = + CheckoutSdk::Identities::FaceAuthentication::FaceAuthenticationClient.new(api_client, configuration) + @apple_pay = CheckoutSdk::Payments::ApplePayClient.new(api_client, configuration) + @google_pay = CheckoutSdk::Payments::GooglePayClient.new(api_client, configuration) end private diff --git a/lib/checkout_sdk/common/common.rb b/lib/checkout_sdk/common/common.rb index ad955ec..739e199 100644 --- a/lib/checkout_sdk/common/common.rb +++ b/lib/checkout_sdk/common/common.rb @@ -29,3 +29,4 @@ require 'checkout_sdk/common/cardholder_account_age_indicator_type' require 'checkout_sdk/common/customer_retry' require 'checkout_sdk/common/destination' +require 'checkout_sdk/common/headers' diff --git a/lib/checkout_sdk/common/headers.rb b/lib/checkout_sdk/common/headers.rb new file mode 100644 index 0000000..298a3c7 --- /dev/null +++ b/lib/checkout_sdk/common/headers.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Common + # Optional HTTP headers that callers can pass to a client method, mirroring + # the SDK's `Headers` pattern. Currently exposes `If-Match` (required + # by endpoints with optimistic-concurrency semantics, e.g. update reserve + # rule); future shared headers can be added here. + # + # @!attribute if_match + # @return [String] ETag value to forward as the `If-Match` HTTP header. + class Headers + attr_accessor :if_match + end + end +end diff --git a/lib/checkout_sdk/common/payment_source_type.rb b/lib/checkout_sdk/common/payment_source_type.rb index 90c3355..932fb4d 100644 --- a/lib/checkout_sdk/common/payment_source_type.rb +++ b/lib/checkout_sdk/common/payment_source_type.rb @@ -44,6 +44,7 @@ module PaymentSourceType TNG = 'tng' AFTERPAY = 'afterpay' BENEFIT = 'benefit' + BLIK = 'blik' MBWAY = 'mbway' POSTFINANCE = 'postfinance' STCPAY = 'stcpay' diff --git a/lib/checkout_sdk/compliance_requests/compliance_request_responded_field.rb b/lib/checkout_sdk/compliance_requests/compliance_request_responded_field.rb new file mode 100644 index 0000000..8149962 --- /dev/null +++ b/lib/checkout_sdk/compliance_requests/compliance_request_responded_field.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module CheckoutSdk + module ComplianceRequests + # A single responded field for a compliance request. Matches swagger + # `ComplianceRequestRespondedField`. + # + # @!attribute name + # @return [String] The field name (e.g. "date_of_birth"). + # @!attribute value + # The value provided for the field. Intentionally untyped per swagger + # (no `type` declaration, `nullable: true`), so the only valid Ruby + # annotation is `Object`. Concrete shape depends on the field being + # responded to (e.g. a date string for `date_of_birth`). + # @return [Object] + # @!attribute not_available + # @return [Boolean] Whether the value is unavailable for this field. + class ComplianceRequestRespondedField + attr_accessor :name, :value, :not_available + end + end +end diff --git a/lib/checkout_sdk/compliance_requests/compliance_request_responded_fields.rb b/lib/checkout_sdk/compliance_requests/compliance_request_responded_fields.rb new file mode 100644 index 0000000..ed75fe7 --- /dev/null +++ b/lib/checkout_sdk/compliance_requests/compliance_request_responded_fields.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module CheckoutSdk + module ComplianceRequests + # Groups responded fields by party (sender/recipient). + # + # @!attribute sender + # @return [Array] + # @!attribute recipient + # @return [Array] + class ComplianceRequestRespondedFields + attr_accessor :sender, :recipient + end + end +end diff --git a/lib/checkout_sdk/compliance_requests/compliance_requests.rb b/lib/checkout_sdk/compliance_requests/compliance_requests.rb new file mode 100644 index 0000000..c0aaa16 --- /dev/null +++ b/lib/checkout_sdk/compliance_requests/compliance_requests.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +require 'checkout_sdk/compliance_requests/compliance_request_responded_field' +require 'checkout_sdk/compliance_requests/compliance_request_responded_fields' +require 'checkout_sdk/compliance_requests/compliance_response_request' +require 'checkout_sdk/compliance_requests/compliance_requests_client' diff --git a/lib/checkout_sdk/compliance_requests/compliance_requests_client.rb b/lib/checkout_sdk/compliance_requests/compliance_requests_client.rb new file mode 100644 index 0000000..bcee565 --- /dev/null +++ b/lib/checkout_sdk/compliance_requests/compliance_requests_client.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module CheckoutSdk + module ComplianceRequests + # Client for the Compliance Requests API. + class ComplianceRequestsClient < Client + COMPLIANCE_REQUESTS = 'compliance-requests' + private_constant :COMPLIANCE_REQUESTS + + # @param [ApiClient] api_client + # @param [CheckoutConfiguration] configuration + def initialize(api_client, configuration) + super(api_client, configuration, CheckoutSdk::AuthorizationType::SECRET_KEY_OR_OAUTH) + end + + # Retrieve an existing compliance request by payment ID. + # @param [String] payment_id + def get_compliance_request(payment_id) + api_client.invoke_get(build_path(COMPLIANCE_REQUESTS, payment_id), sdk_authorization) + end + + # Respond to a compliance request. + # @param [String] payment_id + # @param [Hash, ComplianceResponseRequest] compliance_response_request + def respond_to_compliance_request(payment_id, compliance_response_request) + api_client.invoke_post( + build_path(COMPLIANCE_REQUESTS, payment_id), + sdk_authorization, + compliance_response_request + ) + end + end + end +end diff --git a/lib/checkout_sdk/compliance_requests/compliance_response_request.rb b/lib/checkout_sdk/compliance_requests/compliance_response_request.rb new file mode 100644 index 0000000..0351d4e --- /dev/null +++ b/lib/checkout_sdk/compliance_requests/compliance_response_request.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module CheckoutSdk + module ComplianceRequests + # Request body for POST /compliance-requests/{payment_id}. + # Used to respond to a compliance information request raised against a payment. + # + # @!attribute fields + # @return [ComplianceRequestRespondedFields] + # @!attribute comments + # @return [String] Optional free-text comment. + class ComplianceResponseRequest + attr_accessor :fields, :comments + end + end +end diff --git a/lib/checkout_sdk/disputes/disputes_client.rb b/lib/checkout_sdk/disputes/disputes_client.rb index 9cc51fa..e294e77 100644 --- a/lib/checkout_sdk/disputes/disputes_client.rb +++ b/lib/checkout_sdk/disputes/disputes_client.rb @@ -9,7 +9,8 @@ class DisputesClient < Client EVIDENCE = 'evidence' SUBMITTED = 'submitted' SCHEME_FILES = 'schemefiles' - private_constant :DISPUTES, :FILES, :ACCEPT, :EVIDENCE, :SCHEME_FILES + ARBITRATION = 'arbitration' + private_constant :DISPUTES, :FILES, :ACCEPT, :EVIDENCE, :SCHEME_FILES, :ARBITRATION # @param [ApiClient] api_client # @param [CheckoutConfiguration] configuration @@ -67,6 +68,26 @@ def upload_file(file_request) def get_file_details(file_id) api_client.invoke_get(build_path(FILES, file_id), sdk_authorization) end + + # Submit arbitration evidence on a dispute. + # @param [String] dispute_id + # @param [Hash, DisputeArbitrationRequest] arbitration_request + def submit_arbitration(dispute_id, arbitration_request = nil) + api_client.invoke_post( + build_path(DISPUTES, dispute_id, EVIDENCE, ARBITRATION), + sdk_authorization, + arbitration_request + ) + end + + # Retrieve submitted arbitration evidence. + # @param [String] dispute_id + def get_submitted_arbitration_evidence(dispute_id) + api_client.invoke_get( + build_path(DISPUTES, dispute_id, EVIDENCE, ARBITRATION, SUBMITTED), + sdk_authorization + ) + end end end end diff --git a/lib/checkout_sdk/forward/create_secret_request.rb b/lib/checkout_sdk/forward/create_secret_request.rb new file mode 100644 index 0000000..7747c43 --- /dev/null +++ b/lib/checkout_sdk/forward/create_secret_request.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Forward + # Request body for POST /forward/secrets. + # + # @!attribute name + # @return [String] Secret name (1-64 alphanumeric chars). + # @!attribute value + # @return [String] Plaintext secret value (max 8KB). + # @!attribute entity_id + # @return [String] Optional entity scope. + class CreateSecretRequest + attr_accessor :name, :value, :entity_id + end + end +end diff --git a/lib/checkout_sdk/forward/forward.rb b/lib/checkout_sdk/forward/forward.rb index e31ac13..12ad4c7 100644 --- a/lib/checkout_sdk/forward/forward.rb +++ b/lib/checkout_sdk/forward/forward.rb @@ -1,3 +1,5 @@ # frozen_string_literal: true +require 'checkout_sdk/forward/create_secret_request' +require 'checkout_sdk/forward/update_secret_request' require 'checkout_sdk/forward/forward_client' diff --git a/lib/checkout_sdk/forward/forward_client.rb b/lib/checkout_sdk/forward/forward_client.rb index 7ab8fa2..8fc769b 100644 --- a/lib/checkout_sdk/forward/forward_client.rb +++ b/lib/checkout_sdk/forward/forward_client.rb @@ -4,7 +4,8 @@ module CheckoutSdk module Forward class ForwardClient < Client FORWARD = 'forward' - private_constant :FORWARD + SECRETS = 'secrets' + private_constant :FORWARD, :SECRETS # @param [ApiClient] api_client # @param [CheckoutConfiguration] configuration @@ -21,6 +22,31 @@ def forward_request(forward_request) def get(forward_id) api_client.invoke_get(build_path(FORWARD, forward_id), sdk_authorization) end + + # @param [Hash, CreateSecretRequest] create_secret_request + def create_secret(create_secret_request) + api_client.invoke_post(build_path(FORWARD, SECRETS), + sdk_authorization, + create_secret_request) + end + + def get_secrets + api_client.invoke_get(build_path(FORWARD, SECRETS), sdk_authorization) + end + + # @param [String] name + # @param [Hash, UpdateSecretRequest] update_secret_request + def update_secret(name, update_secret_request) + api_client.invoke_patch(build_path(FORWARD, SECRETS, name), + sdk_authorization, + update_secret_request) + end + + # @param [String] name + def delete_secret(name) + api_client.invoke_delete(build_path(FORWARD, SECRETS, name), + sdk_authorization) + end end end end diff --git a/lib/checkout_sdk/forward/update_secret_request.rb b/lib/checkout_sdk/forward/update_secret_request.rb new file mode 100644 index 0000000..033e18a --- /dev/null +++ b/lib/checkout_sdk/forward/update_secret_request.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Forward + # Request body for PATCH /forward/secrets/{name}. + # + # @!attribute value + # @return [String] New plaintext secret value (max 8KB). + # @!attribute entity_id + # @return [String] Update the entity scope. + class UpdateSecretRequest + attr_accessor :value, :entity_id + end + end +end diff --git a/lib/checkout_sdk/identities/aml_screening/aml_screening_client.rb b/lib/checkout_sdk/identities/aml_screening/aml_screening_client.rb new file mode 100644 index 0000000..29aaf98 --- /dev/null +++ b/lib/checkout_sdk/identities/aml_screening/aml_screening_client.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Identities + module AmlScreening + # Client for the Identities — AML Screening API. + class AmlScreeningClient < Client + AML_VERIFICATIONS = 'aml-verifications' + private_constant :AML_VERIFICATIONS + + # @param [ApiClient] api_client + # @param [CheckoutConfiguration] configuration + def initialize(api_client, configuration) + super(api_client, configuration, CheckoutSdk::AuthorizationType::SECRET_KEY_OR_OAUTH) + end + + # @param [Hash, AmlVerificationRequest] aml_verification_request + def create_aml_verification(aml_verification_request) + api_client.invoke_post(AML_VERIFICATIONS, sdk_authorization, aml_verification_request) + end + + # @param [String] aml_verification_id + def get_aml_verification(aml_verification_id) + api_client.invoke_get(build_path(AML_VERIFICATIONS, aml_verification_id), sdk_authorization) + end + end + end + end +end diff --git a/lib/checkout_sdk/identities/aml_screening/aml_search_parameters.rb b/lib/checkout_sdk/identities/aml_screening/aml_search_parameters.rb new file mode 100644 index 0000000..7fba0da --- /dev/null +++ b/lib/checkout_sdk/identities/aml_screening/aml_search_parameters.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Identities + module AmlScreening + # The screening configuration to use for an AML verification. + # + # @!attribute configuration_identifier + # @return [String] Your AML Screening configuration ID. + class AmlSearchParameters + attr_accessor :configuration_identifier + end + end + end +end diff --git a/lib/checkout_sdk/identities/aml_screening/aml_verification_request.rb b/lib/checkout_sdk/identities/aml_screening/aml_verification_request.rb new file mode 100644 index 0000000..3eb8cf1 --- /dev/null +++ b/lib/checkout_sdk/identities/aml_screening/aml_verification_request.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Identities + module AmlScreening + # Request body for POST /aml-verifications. + # + # @!attribute applicant_id + # @return [String] The applicant's unique identifier (e.g. "aplt_..."). + # @!attribute search_parameters + # @return [AmlSearchParameters] + # @!attribute monitored + # @return [Boolean] Whether to monitor the applicant's AML status. + class AmlVerificationRequest + attr_accessor :applicant_id, :search_parameters, :monitored + end + end + end +end diff --git a/lib/checkout_sdk/identities/applicants/applicants_client.rb b/lib/checkout_sdk/identities/applicants/applicants_client.rb new file mode 100644 index 0000000..fd3417d --- /dev/null +++ b/lib/checkout_sdk/identities/applicants/applicants_client.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Identities + module Applicants + # Client for the Identities — Applicants API. + class ApplicantsClient < Client + APPLICANTS = 'applicants' + ANONYMIZE = 'anonymize' + private_constant :APPLICANTS, :ANONYMIZE + + # @param [ApiClient] api_client + # @param [CheckoutConfiguration] configuration + def initialize(api_client, configuration) + super(api_client, configuration, CheckoutSdk::AuthorizationType::SECRET_KEY_OR_OAUTH) + end + + # @param [Hash, CreateApplicantRequest] create_applicant_request + def create_applicant(create_applicant_request) + api_client.invoke_post(APPLICANTS, sdk_authorization, create_applicant_request) + end + + # @param [String] applicant_id + def get_applicant(applicant_id) + api_client.invoke_get(build_path(APPLICANTS, applicant_id), sdk_authorization) + end + + # @param [String] applicant_id + # @param [Hash, UpdateApplicantRequest] update_applicant_request + def update_applicant(applicant_id, update_applicant_request) + api_client.invoke_patch(build_path(APPLICANTS, applicant_id), + sdk_authorization, + update_applicant_request) + end + + # @param [String] applicant_id + def anonymize_applicant(applicant_id) + api_client.invoke_post(build_path(APPLICANTS, applicant_id, ANONYMIZE), sdk_authorization) + end + end + end + end +end diff --git a/lib/checkout_sdk/identities/applicants/create_applicant_request.rb b/lib/checkout_sdk/identities/applicants/create_applicant_request.rb new file mode 100644 index 0000000..d4094c8 --- /dev/null +++ b/lib/checkout_sdk/identities/applicants/create_applicant_request.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Identities + module Applicants + # Request body for POST /applicants. + # + # @!attribute external_applicant_id + # @return [String] + # @!attribute email + # @return [String] + # @!attribute external_applicant_name + # @return [String] + class CreateApplicantRequest + attr_accessor :external_applicant_id, + :email, + :external_applicant_name + end + end + end +end diff --git a/lib/checkout_sdk/identities/applicants/update_applicant_request.rb b/lib/checkout_sdk/identities/applicants/update_applicant_request.rb new file mode 100644 index 0000000..4689b9b --- /dev/null +++ b/lib/checkout_sdk/identities/applicants/update_applicant_request.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Identities + module Applicants + # Request body for PATCH /applicants/{applicant_id}. + # + # @!attribute email + # @return [String] + # @!attribute external_applicant_name + # @return [String] + class UpdateApplicantRequest + attr_accessor :email, + :external_applicant_name + end + end + end +end diff --git a/lib/checkout_sdk/identities/face_authentication/face_authentication_attempt_request.rb b/lib/checkout_sdk/identities/face_authentication/face_authentication_attempt_request.rb new file mode 100644 index 0000000..d738b90 --- /dev/null +++ b/lib/checkout_sdk/identities/face_authentication/face_authentication_attempt_request.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Identities + module FaceAuthentication + # Request body for POST /face-authentications/{id}/attempts. + # + # @!attribute redirect_url + # @return [String] URL to redirect the applicant after the attempt. + # @!attribute client_information + # @return [CheckoutSdk::Identities::IdentityVerification::IdvClientInformation] + class FaceAuthenticationAttemptRequest + attr_accessor :redirect_url, :client_information + end + end + end +end diff --git a/lib/checkout_sdk/identities/face_authentication/face_authentication_client.rb b/lib/checkout_sdk/identities/face_authentication/face_authentication_client.rb new file mode 100644 index 0000000..a64d657 --- /dev/null +++ b/lib/checkout_sdk/identities/face_authentication/face_authentication_client.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Identities + module FaceAuthentication + # Client for the Identities — Face Authentication API. + class FaceAuthenticationClient < Client + FACE_AUTHENTICATIONS = 'face-authentications' + ANONYMIZE = 'anonymize' + ATTEMPTS = 'attempts' + private_constant :FACE_AUTHENTICATIONS, :ANONYMIZE, :ATTEMPTS + + # @param [ApiClient] api_client + # @param [CheckoutConfiguration] configuration + def initialize(api_client, configuration) + super(api_client, configuration, CheckoutSdk::AuthorizationType::SECRET_KEY_OR_OAUTH) + end + + # @param [Hash, FaceAuthenticationRequest] request + def create_face_authentication(request) + api_client.invoke_post(FACE_AUTHENTICATIONS, sdk_authorization, request) + end + + # @param [String] face_authentication_id + def get_face_authentication(face_authentication_id) + api_client.invoke_get(build_path(FACE_AUTHENTICATIONS, face_authentication_id), + sdk_authorization) + end + + # @param [String] face_authentication_id + def anonymize_face_authentication(face_authentication_id) + api_client.invoke_post( + build_path(FACE_AUTHENTICATIONS, face_authentication_id, ANONYMIZE), + sdk_authorization + ) + end + + # Create a new attempt for an existing face authentication. + # @param [String] face_authentication_id + # @param [Hash, FaceAuthenticationAttemptRequest] attempt_request + def create_face_authentication_attempt(face_authentication_id, attempt_request) + api_client.invoke_post( + build_path(FACE_AUTHENTICATIONS, face_authentication_id, ATTEMPTS), + sdk_authorization, + attempt_request + ) + end + + # @param [String] face_authentication_id + def get_face_authentication_attempts(face_authentication_id) + api_client.invoke_get( + build_path(FACE_AUTHENTICATIONS, face_authentication_id, ATTEMPTS), + sdk_authorization + ) + end + + # @param [String] face_authentication_id + # @param [String] attempt_id + def get_face_authentication_attempt(face_authentication_id, attempt_id) + api_client.invoke_get( + build_path(FACE_AUTHENTICATIONS, face_authentication_id, ATTEMPTS, attempt_id), + sdk_authorization + ) + end + end + end + end +end diff --git a/lib/checkout_sdk/identities/face_authentication/face_authentication_request.rb b/lib/checkout_sdk/identities/face_authentication/face_authentication_request.rb new file mode 100644 index 0000000..fecea9a --- /dev/null +++ b/lib/checkout_sdk/identities/face_authentication/face_authentication_request.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Identities + module FaceAuthentication + # Request body for POST /face-authentications. + # + # @!attribute applicant_id + # @return [String] + # @!attribute external_reference + # @return [String] + # @!attribute redirect_url + # @return [String] + class FaceAuthenticationRequest + attr_accessor :applicant_id, + :external_reference, + :redirect_url + end + end + end +end diff --git a/lib/checkout_sdk/identities/id_document_verification/id_document_verification_client.rb b/lib/checkout_sdk/identities/id_document_verification/id_document_verification_client.rb new file mode 100644 index 0000000..1780514 --- /dev/null +++ b/lib/checkout_sdk/identities/id_document_verification/id_document_verification_client.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Identities + module IdDocumentVerification + # Client for the Identities — ID Document Verification API. + class IdDocumentVerificationClient < Client + ID_DOCUMENT_VERIFICATIONS = 'id-document-verifications' + ANONYMIZE = 'anonymize' + ATTEMPTS = 'attempts' + PDF_REPORT = 'pdf-report' + private_constant :ID_DOCUMENT_VERIFICATIONS, :ANONYMIZE, :ATTEMPTS, :PDF_REPORT + + # @param [ApiClient] api_client + # @param [CheckoutConfiguration] configuration + def initialize(api_client, configuration) + super(api_client, configuration, CheckoutSdk::AuthorizationType::SECRET_KEY_OR_OAUTH) + end + + # @param [Hash, IdDocumentVerificationRequest] request + def create_id_document_verification(request) + api_client.invoke_post(ID_DOCUMENT_VERIFICATIONS, sdk_authorization, request) + end + + # @param [String] id_document_verification_id + def get_id_document_verification(id_document_verification_id) + api_client.invoke_get(build_path(ID_DOCUMENT_VERIFICATIONS, id_document_verification_id), + sdk_authorization) + end + + # @param [String] id_document_verification_id + def anonymize_id_document_verification(id_document_verification_id) + api_client.invoke_post( + build_path(ID_DOCUMENT_VERIFICATIONS, id_document_verification_id, ANONYMIZE), + sdk_authorization + ) + end + + # Create a new attempt for an existing ID document verification. + # @param [String] id_document_verification_id + # @param [Hash] attempt_request Optional body per swagger. + def create_id_document_verification_attempt(id_document_verification_id, attempt_request = nil) + api_client.invoke_post( + build_path(ID_DOCUMENT_VERIFICATIONS, id_document_verification_id, ATTEMPTS), + sdk_authorization, + attempt_request + ) + end + + # @param [String] id_document_verification_id + def get_id_document_verification_attempts(id_document_verification_id) + api_client.invoke_get( + build_path(ID_DOCUMENT_VERIFICATIONS, id_document_verification_id, ATTEMPTS), + sdk_authorization + ) + end + + # @param [String] id_document_verification_id + # @param [String] attempt_id + def get_id_document_verification_attempt(id_document_verification_id, attempt_id) + api_client.invoke_get( + build_path(ID_DOCUMENT_VERIFICATIONS, id_document_verification_id, ATTEMPTS, attempt_id), + sdk_authorization + ) + end + + # @param [String] id_document_verification_id + def get_id_document_verification_pdf_report(id_document_verification_id) + api_client.invoke_get( + build_path(ID_DOCUMENT_VERIFICATIONS, id_document_verification_id, PDF_REPORT), + sdk_authorization + ) + end + end + end + end +end diff --git a/lib/checkout_sdk/identities/id_document_verification/id_document_verification_request.rb b/lib/checkout_sdk/identities/id_document_verification/id_document_verification_request.rb new file mode 100644 index 0000000..45e0a34 --- /dev/null +++ b/lib/checkout_sdk/identities/id_document_verification/id_document_verification_request.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Identities + module IdDocumentVerification + # Request body for POST /id-document-verifications. + # + # @!attribute applicant_id + # @return [String] + # @!attribute external_reference + # @return [String] + # @!attribute document_type + # @return [String] + # @!attribute country + # @return [String] + # @!attribute redirect_url + # @return [String] + class IdDocumentVerificationRequest + attr_accessor :applicant_id, + :external_reference, + :document_type, + :country, + :redirect_url + end + end + end +end diff --git a/lib/checkout_sdk/identities/identities.rb b/lib/checkout_sdk/identities/identities.rb new file mode 100644 index 0000000..f743f1a --- /dev/null +++ b/lib/checkout_sdk/identities/identities.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +# Applicants +require 'checkout_sdk/identities/applicants/create_applicant_request' +require 'checkout_sdk/identities/applicants/update_applicant_request' +require 'checkout_sdk/identities/applicants/applicants_client' + +# AML Screening +require 'checkout_sdk/identities/aml_screening/aml_search_parameters' +require 'checkout_sdk/identities/aml_screening/aml_verification_request' +require 'checkout_sdk/identities/aml_screening/aml_screening_client' + +# ID Document Verification +require 'checkout_sdk/identities/id_document_verification/id_document_verification_request' +require 'checkout_sdk/identities/id_document_verification/id_document_verification_client' + +# Identity Verification +require 'checkout_sdk/identities/identity_verification/idv_declared_data' +require 'checkout_sdk/identities/identity_verification/idv_client_information' +require 'checkout_sdk/identities/identity_verification/identity_verification_attempt_request' +require 'checkout_sdk/identities/identity_verification/identity_verification_request' +require 'checkout_sdk/identities/identity_verification/identity_verification_client' + +# Face Authentication +require 'checkout_sdk/identities/face_authentication/face_authentication_attempt_request' +require 'checkout_sdk/identities/face_authentication/face_authentication_request' +require 'checkout_sdk/identities/face_authentication/face_authentication_client' diff --git a/lib/checkout_sdk/identities/identity_verification/identity_verification_attempt_request.rb b/lib/checkout_sdk/identities/identity_verification/identity_verification_attempt_request.rb new file mode 100644 index 0000000..71a285d --- /dev/null +++ b/lib/checkout_sdk/identities/identity_verification/identity_verification_attempt_request.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Identities + module IdentityVerification + # Request body for POST /identity-verifications/{id}/attempts. + # + # @!attribute redirect_url + # @return [String] URL to redirect the applicant after the attempt. + # @!attribute client_information + # @return [IdvClientInformation] + class IdentityVerificationAttemptRequest + attr_accessor :redirect_url, :client_information + end + end + end +end diff --git a/lib/checkout_sdk/identities/identity_verification/identity_verification_client.rb b/lib/checkout_sdk/identities/identity_verification/identity_verification_client.rb new file mode 100644 index 0000000..291d8ef --- /dev/null +++ b/lib/checkout_sdk/identities/identity_verification/identity_verification_client.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Identities + module IdentityVerification + # Client for the Identities — Identity Verification API. + class IdentityVerificationClient < Client + IDENTITY_VERIFICATIONS = 'identity-verifications' + CREATE_AND_OPEN_IDV = 'create-and-open-idv' + ANONYMIZE = 'anonymize' + ATTEMPTS = 'attempts' + PDF_REPORT = 'pdf-report' + private_constant :IDENTITY_VERIFICATIONS, :CREATE_AND_OPEN_IDV, :ANONYMIZE, :ATTEMPTS, :PDF_REPORT + + # @param [ApiClient] api_client + # @param [CheckoutConfiguration] configuration + def initialize(api_client, configuration) + super(api_client, configuration, CheckoutSdk::AuthorizationType::SECRET_KEY_OR_OAUTH) + end + + # Create an identity verification and immediately receive its hosted URL. + # @param [Hash, IdentityVerificationRequest] request + def create_and_open_idv(request) + api_client.invoke_post(CREATE_AND_OPEN_IDV, sdk_authorization, request) + end + + # @param [Hash, IdentityVerificationRequest] request + def create_identity_verification(request) + api_client.invoke_post(IDENTITY_VERIFICATIONS, sdk_authorization, request) + end + + # @param [String] identity_verification_id + def get_identity_verification(identity_verification_id) + api_client.invoke_get(build_path(IDENTITY_VERIFICATIONS, identity_verification_id), + sdk_authorization) + end + + # @param [String] identity_verification_id + def anonymize_identity_verification(identity_verification_id) + api_client.invoke_post( + build_path(IDENTITY_VERIFICATIONS, identity_verification_id, ANONYMIZE), + sdk_authorization + ) + end + + # Create a new attempt for an existing identity verification. + # @param [String] identity_verification_id + # @param [Hash, IdentityVerificationAttemptRequest] attempt_request + def create_identity_verification_attempt(identity_verification_id, attempt_request) + api_client.invoke_post( + build_path(IDENTITY_VERIFICATIONS, identity_verification_id, ATTEMPTS), + sdk_authorization, + attempt_request + ) + end + + # @param [String] identity_verification_id + def get_identity_verification_attempts(identity_verification_id) + api_client.invoke_get( + build_path(IDENTITY_VERIFICATIONS, identity_verification_id, ATTEMPTS), + sdk_authorization + ) + end + + # @param [String] identity_verification_id + # @param [String] attempt_id + def get_identity_verification_attempt(identity_verification_id, attempt_id) + api_client.invoke_get( + build_path(IDENTITY_VERIFICATIONS, identity_verification_id, ATTEMPTS, attempt_id), + sdk_authorization + ) + end + + # @param [String] identity_verification_id + def get_identity_verification_pdf_report(identity_verification_id) + api_client.invoke_get( + build_path(IDENTITY_VERIFICATIONS, identity_verification_id, PDF_REPORT), + sdk_authorization + ) + end + end + end + end +end diff --git a/lib/checkout_sdk/identities/identity_verification/identity_verification_request.rb b/lib/checkout_sdk/identities/identity_verification/identity_verification_request.rb new file mode 100644 index 0000000..0097605 --- /dev/null +++ b/lib/checkout_sdk/identities/identity_verification/identity_verification_request.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Identities + module IdentityVerification + # Request body for POST /identity-verifications and POST /create-and-open-idv. + # + # @!attribute applicant_id + # @return [String] The applicant's unique identifier (e.g. "aplt_..."). + # @!attribute user_journey_id + # @return [String] Your configuration ID (e.g. "usj_..."). + # @!attribute declared_data + # @return [IdvDeclaredData] + # @!attribute risk_labels + # @return [Array] + class IdentityVerificationRequest + attr_accessor :applicant_id, :user_journey_id, :declared_data, :risk_labels + end + end + end +end diff --git a/lib/checkout_sdk/identities/identity_verification/idv_client_information.rb b/lib/checkout_sdk/identities/identity_verification/idv_client_information.rb new file mode 100644 index 0000000..0dbd385 --- /dev/null +++ b/lib/checkout_sdk/identities/identity_verification/idv_client_information.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Identities + module IdentityVerification + # Pre-populated client information for an identity-verification attempt. + # + # @!attribute pre_selected_residence_country + # @return [String] ISO alpha-2 country code. + # @!attribute pre_selected_language + # @return [String] IETF BCP 47 language tag. + class IdvClientInformation + attr_accessor :pre_selected_residence_country, :pre_selected_language + end + end + end +end diff --git a/lib/checkout_sdk/identities/identity_verification/idv_declared_data.rb b/lib/checkout_sdk/identities/identity_verification/idv_declared_data.rb new file mode 100644 index 0000000..236325c --- /dev/null +++ b/lib/checkout_sdk/identities/identity_verification/idv_declared_data.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Identities + module IdentityVerification + # The personal details provided by the applicant for an identity verification. + # + # @!attribute name + # @return [String] The applicant's name (max 255 characters). + class IdvDeclaredData + attr_accessor :name + end + end + end +end diff --git a/lib/checkout_sdk/instruments/base_instruments_client.rb b/lib/checkout_sdk/instruments/base_instruments_client.rb index 894c2aa..6404c67 100644 --- a/lib/checkout_sdk/instruments/base_instruments_client.rb +++ b/lib/checkout_sdk/instruments/base_instruments_client.rb @@ -15,6 +15,15 @@ def get(instrument_id) def delete(instrument_id) api_client.invoke_delete(build_path(INSTRUMENTS, instrument_id), sdk_authorization) end + + # Revoke a payment instrument. The instrument status is set to INVALID + # with the reason `revoked_by_merchant`. The instrument record is + # retained for audit purposes. + # @param [String] instrument_id Pattern: ^(src_)[a-z0-9]{26}$ + def revoke(instrument_id) + api_client.invoke_patch(build_path(INSTRUMENTS, instrument_id, 'revoke'), + sdk_authorization) + end end end end diff --git a/lib/checkout_sdk/issuing/add_control_group_request.rb b/lib/checkout_sdk/issuing/add_control_group_request.rb new file mode 100644 index 0000000..7233875 --- /dev/null +++ b/lib/checkout_sdk/issuing/add_control_group_request.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Issuing + # Request body for POST /issuing/controls/control-groups. + # + # @!attribute description + # @return [String] + # @!attribute target_id + # @return [String] Card / cardholder / account / profile id. + # @!attribute fail_if + # @return [String] Control-group condition (e.g. "all", "any"). + # @!attribute controls + # @return [Array] Array of card controls. + class AddControlGroupRequest + attr_accessor :description, :target_id, :fail_if, :controls + end + end +end diff --git a/lib/checkout_sdk/issuing/add_control_profile_request.rb b/lib/checkout_sdk/issuing/add_control_profile_request.rb new file mode 100644 index 0000000..245d645 --- /dev/null +++ b/lib/checkout_sdk/issuing/add_control_profile_request.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Issuing + # Request body for POST /issuing/controls/control-profiles. + # + # @!attribute name + # @return [String] Required. + class AddControlProfileRequest + attr_accessor :name + end + end +end diff --git a/lib/checkout_sdk/issuing/cardholder_access_token_request.rb b/lib/checkout_sdk/issuing/cardholder_access_token_request.rb new file mode 100644 index 0000000..c7f7581 --- /dev/null +++ b/lib/checkout_sdk/issuing/cardholder_access_token_request.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Issuing + # Form-encoded body for POST /issuing/access/connect/token. + # The api_client encodes this as application/x-www-form-urlencoded. + # + # @!attribute grant_type + # @return [String] Must be "client_credentials". + # @!attribute client_id + # @return [String] Access key ID. + # @!attribute client_secret + # @return [String] Access key secret. + # @!attribute cardholder_id + # @return [String] The cardholder's unique identifier (e.g. "crh_..."). + # @!attribute single_use + # @return [Boolean] Whether the request is for a single-use token. + class CardholderAccessTokenRequest + attr_accessor :grant_type, :client_id, :client_secret, :cardholder_id, :single_use + + def initialize + @grant_type = 'client_credentials' + end + end + end +end diff --git a/lib/checkout_sdk/issuing/create_dispute_request.rb b/lib/checkout_sdk/issuing/create_dispute_request.rb new file mode 100644 index 0000000..3fc7021 --- /dev/null +++ b/lib/checkout_sdk/issuing/create_dispute_request.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Issuing + # Request body for POST /issuing/disputes. + # + # @!attribute transaction_id + # @return [String] + # @!attribute reason + # @return [String] + # @!attribute evidence + # @return [Array] + # @!attribute amount + # @return [Numeric] + # @!attribute presentment_message_id + # @return [String] + # @!attribute justification + # @return [String] + class CreateDisputeRequest + attr_accessor :transaction_id, :reason, :evidence, :amount, + :presentment_message_id, :justification + end + end +end diff --git a/lib/checkout_sdk/issuing/escalate_dispute_request.rb b/lib/checkout_sdk/issuing/escalate_dispute_request.rb new file mode 100644 index 0000000..9cfbcd8 --- /dev/null +++ b/lib/checkout_sdk/issuing/escalate_dispute_request.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Issuing + # Request body for POST /issuing/disputes/{disputeId}/escalate. + # + # @!attribute additional_evidence + # @return [Array] + # @!attribute amount + # @return [Numeric] + # @!attribute reason_change + # @return [String] + # @!attribute justification + # @return [String] Required. + class EscalateDisputeRequest + attr_accessor :additional_evidence, :amount, :reason_change, :justification + end + end +end diff --git a/lib/checkout_sdk/issuing/identification_document.rb b/lib/checkout_sdk/issuing/identification_document.rb new file mode 100644 index 0000000..5a192b0 --- /dev/null +++ b/lib/checkout_sdk/issuing/identification_document.rb @@ -0,0 +1,18 @@ +# 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 982b3fc..b331c07 100644 --- a/lib/checkout_sdk/issuing/issuing.rb +++ b/lib/checkout_sdk/issuing/issuing.rb @@ -1,3 +1,28 @@ # frozen_string_literal: true +# Authentication +require 'checkout_sdk/issuing/cardholder_access_token_request' +require 'checkout_sdk/issuing/oob_simulate_transaction_details' +require 'checkout_sdk/issuing/oob_authentication_request' + +# 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' + +# Controls +require 'checkout_sdk/issuing/add_control_group_request' +require 'checkout_sdk/issuing/add_control_profile_request' +require 'checkout_sdk/issuing/update_control_profile_request' + +# Disputes +require 'checkout_sdk/issuing/create_dispute_request' +require 'checkout_sdk/issuing/escalate_dispute_request' + require 'checkout_sdk/issuing/issuing_client' diff --git a/lib/checkout_sdk/issuing/issuing_address.rb b/lib/checkout_sdk/issuing/issuing_address.rb new file mode 100644 index 0000000..8577a9b --- /dev/null +++ b/lib/checkout_sdk/issuing/issuing_address.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Issuing + # Address block used in Issuing requests (billing/residency on cardholders). + # Matches swagger `IssuingAddress`. `address_line1`, `city`, `zip`, `country` + # are required per spec; other fields are optional. + # + # @!attribute address_line1 + # @return [String] [Required] + # @!attribute address_line2 + # @return [String] + # @!attribute city + # @return [String] [Required] + # @!attribute state + # @return [String] + # @!attribute zip + # @return [String] [Required] + # @!attribute country + # @return [String] ISO-3166 alpha-2 country code. [Required] + class IssuingAddress + attr_accessor :address_line1, :address_line2, :city, :state, :zip, :country + end + end +end diff --git a/lib/checkout_sdk/issuing/issuing_client.rb b/lib/checkout_sdk/issuing/issuing_client.rb index 5bab267..f01d24e 100644 --- a/lib/checkout_sdk/issuing/issuing_client.rb +++ b/lib/checkout_sdk/issuing/issuing_client.rb @@ -12,23 +12,32 @@ class IssuingClient < Client REVOKE = 'revoke' SUSPEND = 'suspend' CONTROLS = 'controls' + CONTROL_GROUPS = 'control-groups' + CONTROL_PROFILES = 'control-profiles' SIMULATE = 'simulate' AUTHORIZATIONS = 'authorizations' PRESENTMENTS = 'presentments' REVERSALS = 'reversals' - private_constant :ISSUING, - :CARDHOLDERS, - :CARDS, - :THREE_DS, - :ACTIVATE, - :CREDENTIALS, - :REVOKE, - :SUSPEND, - :CONTROLS, - :SIMULATE, - :AUTHORIZATIONS, - :PRESENTMENTS, - :REVERSALS + REFUNDS = 'refunds' + RENEW = 'renew' + SCHEDULE_REVOCATION = 'schedule-revocation' + DISPUTES = 'disputes' + CANCEL = 'cancel' + ESCALATE = 'escalate' + TRANSACTIONS = 'transactions' + DIGITAL_CARDS = 'digital-cards' + ADD = 'add' + REMOVE = 'remove' + ACCESS = 'access' + CONNECT = 'connect' + TOKEN = 'token' + OOB = 'oob' + AUTHENTICATION = 'authentication' + 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, + :TRANSACTIONS, :DIGITAL_CARDS, :ADD, :REMOVE # @param [ApiClient] api_client # @param [CheckoutConfiguration] configuration @@ -36,6 +45,8 @@ def initialize(api_client, configuration) super(api_client, configuration, CheckoutSdk::AuthorizationType::SECRET_KEY_OR_OAUTH) end + # ====== Cardholders ====== + # @param [Hash] cardholder_request def create_cardholder(cardholder_request) api_client.invoke_post(build_path(ISSUING, CARDHOLDERS), sdk_authorization, cardholder_request) @@ -46,11 +57,23 @@ def get_cardholder(cardholder_id) api_client.invoke_get(build_path(ISSUING, CARDHOLDERS, cardholder_id), sdk_authorization) end + # @param [String] cardholder_id + # @param [Hash, UpdateCardholderRequest] update_cardholder_request + def update_cardholder(cardholder_id, update_cardholder_request) + api_client.invoke_patch( + build_path(ISSUING, CARDHOLDERS, cardholder_id), + sdk_authorization, + update_cardholder_request + ) + end + # @param [String] cardholder_id def get_cardholder_cards(cardholder_id) api_client.invoke_get(build_path(ISSUING, CARDHOLDERS, cardholder_id, CARDS), sdk_authorization) end + # ====== Cards ====== + # @param [Hash] card_request def create_card(card_request) api_client.invoke_post(build_path(ISSUING, CARDS), sdk_authorization, card_request) @@ -61,6 +84,16 @@ def get_card_details(card_id) api_client.invoke_get(build_path(ISSUING, CARDS, card_id), sdk_authorization) end + # @param [String] card_id + # @param [Hash, UpdateCardRequest] update_card_request + def update_card(card_id, update_card_request) + api_client.invoke_patch( + build_path(ISSUING, CARDS, card_id), + sdk_authorization, + update_card_request + ) + end + # @param [String] card_id # @param [Hash] three_ds_request def enroll_three_ds(card_id, three_ds_request) @@ -101,6 +134,39 @@ def suspend_card(card_id, suspend_request) api_client.invoke_post(build_path(ISSUING, CARDS, card_id, SUSPEND), sdk_authorization, suspend_request) end + # Renew a card. POST /issuing/cards/{cardId}/renew. + # @param [String] card_id + # @param [Hash] renew_request + def renew_card(card_id, renew_request = nil) + api_client.invoke_post( + build_path(ISSUING, CARDS, card_id, RENEW), + sdk_authorization, + renew_request + ) + 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 def create_control(control_request) api_client.invoke_post(build_path(ISSUING, CONTROLS), sdk_authorization, control_request) @@ -127,6 +193,161 @@ def remove_card_control(control_id) api_client.invoke_delete(build_path(ISSUING, CONTROLS, control_id), sdk_authorization) end + # ====== Control Groups ====== + + # @param [Hash, AddControlGroupRequest] control_group_request + def create_control_group(control_group_request) + api_client.invoke_post( + build_path(ISSUING, CONTROLS, CONTROL_GROUPS), + sdk_authorization, + control_group_request + ) + end + + def get_control_groups + api_client.invoke_get(build_path(ISSUING, CONTROLS, CONTROL_GROUPS), sdk_authorization) + end + + # @param [String] control_group_id + def get_control_group(control_group_id) + api_client.invoke_get( + build_path(ISSUING, CONTROLS, CONTROL_GROUPS, control_group_id), + sdk_authorization + ) + end + + # @param [String] control_group_id + def delete_control_group(control_group_id) + api_client.invoke_delete( + build_path(ISSUING, CONTROLS, CONTROL_GROUPS, control_group_id), + sdk_authorization + ) + end + + # ====== Control Profiles ====== + + # @param [Hash, AddControlProfileRequest] control_profile_request + def create_control_profile(control_profile_request) + api_client.invoke_post( + build_path(ISSUING, CONTROLS, CONTROL_PROFILES), + sdk_authorization, + control_profile_request + ) + end + + def get_control_profiles + api_client.invoke_get(build_path(ISSUING, CONTROLS, CONTROL_PROFILES), sdk_authorization) + end + + # @param [String] control_profile_id + def get_control_profile(control_profile_id) + api_client.invoke_get( + build_path(ISSUING, CONTROLS, CONTROL_PROFILES, control_profile_id), + sdk_authorization + ) + end + + # @param [String] control_profile_id + # @param [Hash, UpdateControlProfileRequest] update_control_profile_request + def update_control_profile(control_profile_id, update_control_profile_request) + api_client.invoke_patch( + build_path(ISSUING, CONTROLS, CONTROL_PROFILES, control_profile_id), + sdk_authorization, + update_control_profile_request + ) + end + + # @param [String] control_profile_id + def delete_control_profile(control_profile_id) + api_client.invoke_delete( + build_path(ISSUING, CONTROLS, CONTROL_PROFILES, control_profile_id), + sdk_authorization + ) + end + + # @param [String] control_profile_id + # @param [String] target_id + def add_target_to_control_profile(control_profile_id, target_id) + api_client.invoke_post( + build_path(ISSUING, CONTROLS, CONTROL_PROFILES, control_profile_id, ADD, target_id), + sdk_authorization + ) + end + + # @param [String] control_profile_id + # @param [String] target_id + def remove_target_from_control_profile(control_profile_id, target_id) + api_client.invoke_post( + build_path(ISSUING, CONTROLS, CONTROL_PROFILES, control_profile_id, REMOVE, target_id), + sdk_authorization + ) + end + + # ====== Issuing Disputes ====== + + # @param [Hash, CreateDisputeRequest] create_dispute_request + def create_issuing_dispute(create_dispute_request) + api_client.invoke_post( + build_path(ISSUING, DISPUTES), + sdk_authorization, + create_dispute_request + ) + end + + # @param [String] dispute_id + def get_issuing_dispute(dispute_id) + api_client.invoke_get(build_path(ISSUING, DISPUTES, dispute_id), sdk_authorization) + end + + # @param [String] dispute_id + def cancel_issuing_dispute(dispute_id) + api_client.invoke_post( + build_path(ISSUING, DISPUTES, dispute_id, CANCEL), + sdk_authorization + ) + end + + # @param [String] dispute_id + # @param [Hash, EscalateDisputeRequest] escalate_dispute_request + def escalate_issuing_dispute(dispute_id, escalate_dispute_request) + api_client.invoke_post( + build_path(ISSUING, DISPUTES, dispute_id, ESCALATE), + sdk_authorization, + escalate_dispute_request + ) + end + + # ====== Transactions ====== + + # @param [Hash] transactions_query + def get_transactions(transactions_query = nil) + api_client.invoke_get( + build_path(ISSUING, TRANSACTIONS), + sdk_authorization, + transactions_query + ) + end + + # @param [String] transaction_id + def get_transaction(transaction_id) + api_client.invoke_get( + build_path(ISSUING, TRANSACTIONS, transaction_id), + sdk_authorization + ) + end + + # ====== Digital Cards ====== + + # @param [String] digital_card_id + def get_digital_card(digital_card_id) + api_client.invoke_get( + build_path(ISSUING, DIGITAL_CARDS, digital_card_id), + sdk_authorization + ) + end + + # ====== Simulations ====== + # @param [Hash] authorization_request def simulate_authorization(authorization_request) api_client.invoke_post(build_path(ISSUING, SIMULATE, AUTHORIZATIONS), sdk_authorization, authorization_request) @@ -161,6 +382,38 @@ def simulate_reversal(transaction_id, reversal_request) reversal_request ) end + + # Simulate a refund for an authorization. + # @param [String] transaction_id + # @param [Hash, SimulateRefundRequest] refund_request + def simulate_refund(transaction_id, refund_request) + api_client.invoke_post( + build_path(ISSUING, SIMULATE, AUTHORIZATIONS, transaction_id, REFUNDS), + sdk_authorization, + refund_request + ) + end + + # Request a Cardholder access token. + # The api_client serializes the body as application/x-www-form-urlencoded. + # @param [Hash, CardholderAccessTokenRequest] cardholder_token_request + def request_cardholder_access_token(cardholder_token_request) + api_client.invoke_post( + build_path(ISSUING, ACCESS, CONNECT, TOKEN), + sdk_authorization(CheckoutSdk::AuthorizationType::OAUTH), + cardholder_token_request + ) + end + + # Simulate an out-of-band (OOB) authentication request. + # @param [Hash, OobAuthenticationRequest] oob_authentication_request + def simulate_oob_authentication(oob_authentication_request) + api_client.invoke_post( + build_path(ISSUING, SIMULATE, OOB, AUTHENTICATION), + sdk_authorization(CheckoutSdk::AuthorizationType::OAUTH), + oob_authentication_request + ) + end end end end diff --git a/lib/checkout_sdk/issuing/issuing_phone_number.rb b/lib/checkout_sdk/issuing/issuing_phone_number.rb new file mode 100644 index 0000000..f43dfd7 --- /dev/null +++ b/lib/checkout_sdk/issuing/issuing_phone_number.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Issuing + # Phone number block used in Issuing requests (e.g. cardholder updates). + # Matches swagger `IssuingPhoneNumber`. + # + # @!attribute country_code + # @return [String] E.164 country dial code (e.g. "+1"). + # @!attribute number + # @return [String] Local subscriber number. + class IssuingPhoneNumber + attr_accessor :country_code, :number + end + end +end diff --git a/lib/checkout_sdk/issuing/oob_authentication_request.rb b/lib/checkout_sdk/issuing/oob_authentication_request.rb new file mode 100644 index 0000000..9a3a79a --- /dev/null +++ b/lib/checkout_sdk/issuing/oob_authentication_request.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Issuing + # Request body for POST /issuing/simulate/oob/authentication. + # + # @!attribute card_id + # @return [String] The card's unique identifier (e.g. "crd_..."). + # @!attribute transaction_details + # @return [OobSimulateTransactionDetails] + class OobAuthenticationRequest + attr_accessor :card_id, :transaction_details + end + end +end diff --git a/lib/checkout_sdk/issuing/oob_simulate_transaction_details.rb b/lib/checkout_sdk/issuing/oob_simulate_transaction_details.rb new file mode 100644 index 0000000..11aa174 --- /dev/null +++ b/lib/checkout_sdk/issuing/oob_simulate_transaction_details.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Issuing + # Details for a simulated OOB authentication transaction. + # + # @!attribute last_four + # @return [String] The last four digits of the card. + # @!attribute merchant_name + # @return [String] + # @!attribute purchase_amount + # @return [Numeric] + # @!attribute purchase_currency + # @return [String] ISO currency (e.g. "GBP"). + class OobSimulateTransactionDetails + attr_accessor :last_four, :merchant_name, :purchase_amount, :purchase_currency + end + end +end diff --git a/lib/checkout_sdk/issuing/schedule_revocation_request.rb b/lib/checkout_sdk/issuing/schedule_revocation_request.rb new file mode 100644 index 0000000..b29cc66 --- /dev/null +++ b/lib/checkout_sdk/issuing/schedule_revocation_request.rb @@ -0,0 +1,13 @@ +# 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/simulate_refund_request.rb b/lib/checkout_sdk/issuing/simulate_refund_request.rb new file mode 100644 index 0000000..9600dfb --- /dev/null +++ b/lib/checkout_sdk/issuing/simulate_refund_request.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Issuing + # Request body for POST /issuing/simulate/authorizations/{id}/refunds. + # + # @!attribute amount + # @return [Integer] + class SimulateRefundRequest + attr_accessor :amount + end + end +end diff --git a/lib/checkout_sdk/issuing/update_card_request.rb b/lib/checkout_sdk/issuing/update_card_request.rb new file mode 100644 index 0000000..cee6110 --- /dev/null +++ b/lib/checkout_sdk/issuing/update_card_request.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Issuing + # Request body for PATCH /issuing/cards/{cardId}. + # + # @!attribute reference + # @return [String] + # @!attribute metadata + # @return [Hash{String => String}] + # @!attribute expiry_month + # @return [Integer] + # @!attribute expiry_year + # @return [Integer] + class UpdateCardRequest + attr_accessor :reference, :metadata, :expiry_month, :expiry_year + end + end +end diff --git a/lib/checkout_sdk/issuing/update_cardholder_request.rb b/lib/checkout_sdk/issuing/update_cardholder_request.rb new file mode 100644 index 0000000..9401e75 --- /dev/null +++ b/lib/checkout_sdk/issuing/update_cardholder_request.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Issuing + # Request body for PATCH /issuing/cardholders/{cardholderId}. + # Maps swagger `update-cardholder-request`. + # + # @!attribute first_name + # @return [String] + # @!attribute middle_name + # @return [String] + # @!attribute last_name + # @return [String] + # @!attribute date_of_birth + # @return [String] ISO-8601 date. + # @!attribute phone_number + # @return [IssuingPhoneNumber] + # @!attribute email + # @return [String] Email address (rfc6530). Max 254 characters. + # @!attribute billing_address + # @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 + end + end +end diff --git a/lib/checkout_sdk/issuing/update_control_profile_request.rb b/lib/checkout_sdk/issuing/update_control_profile_request.rb new file mode 100644 index 0000000..bbfb02d --- /dev/null +++ b/lib/checkout_sdk/issuing/update_control_profile_request.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Issuing + # Request body for PATCH /issuing/controls/control-profiles/{controlProfileId}. + # + # @!attribute name + # @return [String] + class UpdateControlProfileRequest + attr_accessor :name + end + end +end diff --git a/lib/checkout_sdk/network_tokens/network_token_cryptogram_request.rb b/lib/checkout_sdk/network_tokens/network_token_cryptogram_request.rb new file mode 100644 index 0000000..c5b6343 --- /dev/null +++ b/lib/checkout_sdk/network_tokens/network_token_cryptogram_request.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module CheckoutSdk + module NetworkTokens + # Request body for POST /network-tokens/{network_token_id}/cryptograms. + # + # @!attribute transaction_type + # @return [String] One of "ecom", "recurring", "pos", "aft". + class NetworkTokenCryptogramRequest + attr_accessor :transaction_type + end + end +end diff --git a/lib/checkout_sdk/network_tokens/network_token_source_card.rb b/lib/checkout_sdk/network_tokens/network_token_source_card.rb new file mode 100644 index 0000000..9493ce4 --- /dev/null +++ b/lib/checkout_sdk/network_tokens/network_token_source_card.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module CheckoutSdk + module NetworkTokens + # Card-based source for provisioning a network token. Set `type = "card"`. + # + # @!attribute type + # @return [String] Always "card". + # @!attribute number + # @return [String] The card number. + # @!attribute cvv + # @return [String] + # @!attribute expiry_month + # @return [String] 1- or 2-digit month. + # @!attribute expiry_year + # @return [String] Four-digit year. + class NetworkTokenSourceCard + attr_accessor :type, :number, :cvv, :expiry_month, :expiry_year + + def initialize + @type = 'card' + end + end + end +end diff --git a/lib/checkout_sdk/network_tokens/network_token_source_id.rb b/lib/checkout_sdk/network_tokens/network_token_source_id.rb new file mode 100644 index 0000000..2284d5c --- /dev/null +++ b/lib/checkout_sdk/network_tokens/network_token_source_id.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module CheckoutSdk + module NetworkTokens + # Existing-instrument source for provisioning a network token. Set `type = "id"`. + # + # @!attribute type + # @return [String] Always "id". + # @!attribute id + # @return [String] The source instrument id (e.g. "src_..."). + class NetworkTokenSourceId + attr_accessor :type, :id + + def initialize + @type = 'id' + end + end + end +end diff --git a/lib/checkout_sdk/network_tokens/network_tokens.rb b/lib/checkout_sdk/network_tokens/network_tokens.rb new file mode 100644 index 0000000..a3b2f28 --- /dev/null +++ b/lib/checkout_sdk/network_tokens/network_tokens.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +require 'checkout_sdk/network_tokens/network_token_source_card' +require 'checkout_sdk/network_tokens/network_token_source_id' +require 'checkout_sdk/network_tokens/provision_network_token_request' +require 'checkout_sdk/network_tokens/network_token_cryptogram_request' +require 'checkout_sdk/network_tokens/network_tokens_client' diff --git a/lib/checkout_sdk/network_tokens/network_tokens_client.rb b/lib/checkout_sdk/network_tokens/network_tokens_client.rb new file mode 100644 index 0000000..688247d --- /dev/null +++ b/lib/checkout_sdk/network_tokens/network_tokens_client.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +module CheckoutSdk + module NetworkTokens + # Client for the Network Tokens API. + class NetworkTokensClient < Client + NETWORK_TOKENS = 'network-tokens' + CRYPTOGRAMS = 'cryptograms' + DELETE = 'delete' + private_constant :NETWORK_TOKENS, :CRYPTOGRAMS, :DELETE + + # @param [ApiClient] api_client + # @param [CheckoutConfiguration] configuration + def initialize(api_client, configuration) + super(api_client, configuration, CheckoutSdk::AuthorizationType::SECRET_KEY_OR_OAUTH) + end + + # Provision a Network Token. + # @param [Hash, ProvisionNetworkTokenRequest] provision_request + def provision_network_token(provision_request) + api_client.invoke_post(NETWORK_TOKENS, sdk_authorization, provision_request) + end + + # Retrieve a Network Token. + # @param [String] network_token_id + def get_network_token(network_token_id) + api_client.invoke_get(build_path(NETWORK_TOKENS, network_token_id), sdk_authorization) + end + + # Request a fresh cryptogram for a Network Token (for SCA / fresh payment flows). + # @param [String] network_token_id + # @param [Hash, NetworkTokenCryptogramRequest] cryptogram_request + def request_cryptograms(network_token_id, cryptogram_request = nil) + api_client.invoke_post( + build_path(NETWORK_TOKENS, network_token_id, CRYPTOGRAMS), + sdk_authorization, + cryptogram_request + ) + end + + # Soft-delete a Network Token. The API uses PATCH on .../delete. + # @param [String] network_token_id + def delete_network_token(network_token_id) + api_client.invoke_patch( + build_path(NETWORK_TOKENS, network_token_id, DELETE), + sdk_authorization + ) + end + end + end +end diff --git a/lib/checkout_sdk/network_tokens/provision_network_token_request.rb b/lib/checkout_sdk/network_tokens/provision_network_token_request.rb new file mode 100644 index 0000000..893e90c --- /dev/null +++ b/lib/checkout_sdk/network_tokens/provision_network_token_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module CheckoutSdk + module NetworkTokens + # Request body for POST /network-tokens. + # `source` must be either a NetworkTokenSourceCard or a NetworkTokenSourceId. + # + # @!attribute source + # @return [NetworkTokenSourceCard, NetworkTokenSourceId] + class ProvisionNetworkTokenRequest + attr_accessor :source + end + end +end diff --git a/lib/checkout_sdk/onboarding_simulator/onboarding_simulator.rb b/lib/checkout_sdk/onboarding_simulator/onboarding_simulator.rb new file mode 100644 index 0000000..cc043b1 --- /dev/null +++ b/lib/checkout_sdk/onboarding_simulator/onboarding_simulator.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +require 'checkout_sdk/onboarding_simulator/simulator_entity_status' +require 'checkout_sdk/onboarding_simulator/simulator_set_requirements_due_request' +require 'checkout_sdk/onboarding_simulator/simulator_set_status_request' +require 'checkout_sdk/onboarding_simulator/onboarding_simulator_client' diff --git a/lib/checkout_sdk/onboarding_simulator/onboarding_simulator_client.rb b/lib/checkout_sdk/onboarding_simulator/onboarding_simulator_client.rb new file mode 100644 index 0000000..05b4a96 --- /dev/null +++ b/lib/checkout_sdk/onboarding_simulator/onboarding_simulator_client.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +module CheckoutSdk + module OnboardingSimulator + # Client for the Onboarding Simulator API (Sandbox only). + # + # All endpoints require OAuth with the `accounts` scope. Calling these + # endpoints in Production returns 404. + class OnboardingSimulatorClient < Client + SIMULATE = 'simulate' + ENTITIES = 'entities' + REQUIREMENTS_DUE = 'requirements-due' + SCENARIOS = 'scenarios' + STATUS = 'status' + private_constant :SIMULATE, :ENTITIES, :REQUIREMENTS_DUE, :SCENARIOS, :STATUS + + # @param [ApiClient] api_client + # @param [CheckoutConfiguration] configuration + def initialize(api_client, configuration) + super(api_client, configuration, CheckoutSdk::AuthorizationType::OAUTH) + end + + # Marks the specified requirement fields as due on an entity. + # @param [String] entity_id + # @param [Hash, SimulatorSetRequirementsDueRequest] request + def set_requirements_due(entity_id, request) + api_client.invoke_post( + build_path(SIMULATE, ENTITIES, entity_id, REQUIREMENTS_DUE), + sdk_authorization, + request + ) + end + + # Executes a pre-defined scenario against an entity. + # @param [String] entity_id + # @param [String] scenario_id + def run_scenario(entity_id, scenario_id) + api_client.invoke_post( + build_path(SIMULATE, ENTITIES, entity_id, SCENARIOS, scenario_id), + sdk_authorization + ) + end + + # Forces the entity to the specified status. + # @param [String] entity_id + # @param [Hash, SimulatorSetStatusRequest] request + def set_entity_status(entity_id, request) + api_client.invoke_post( + build_path(SIMULATE, ENTITIES, entity_id, STATUS), + sdk_authorization, + request + ) + end + + # Returns all requirement fields that can be set as due on an entity. + def list_available_requirements + api_client.invoke_get( + build_path(SIMULATE, REQUIREMENTS_DUE), + sdk_authorization + ) + end + + # Returns all pre-defined scenarios available. + def list_scenarios + api_client.invoke_get( + build_path(SIMULATE, SCENARIOS), + sdk_authorization + ) + end + end + end +end diff --git a/lib/checkout_sdk/onboarding_simulator/simulator_entity_status.rb b/lib/checkout_sdk/onboarding_simulator/simulator_entity_status.rb new file mode 100644 index 0000000..c3f9061 --- /dev/null +++ b/lib/checkout_sdk/onboarding_simulator/simulator_entity_status.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module CheckoutSdk + module OnboardingSimulator + # Statuses accepted by POST /simulate/entities/{entityId}/status. + module SimulatorEntityStatus + DRAFT = 'draft' + REQUIREMENTS_DUE = 'requirements_due' + PENDING = 'pending' + ACTIVE = 'active' + RESTRICTED = 'restricted' + REJECTED = 'rejected' + INACTIVE = 'inactive' + end + end +end diff --git a/lib/checkout_sdk/onboarding_simulator/simulator_set_requirements_due_request.rb b/lib/checkout_sdk/onboarding_simulator/simulator_set_requirements_due_request.rb new file mode 100644 index 0000000..94ec27b --- /dev/null +++ b/lib/checkout_sdk/onboarding_simulator/simulator_set_requirements_due_request.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module CheckoutSdk + module OnboardingSimulator + # Request body for POST /simulate/entities/{entityId}/requirements-due. + # + # @!attribute fields + # @return [Array(String)] Requirement field paths to mark as due + # (e.g. ["individual.identification.document"]). + class SimulatorSetRequirementsDueRequest + attr_accessor :fields + end + end +end diff --git a/lib/checkout_sdk/onboarding_simulator/simulator_set_status_request.rb b/lib/checkout_sdk/onboarding_simulator/simulator_set_status_request.rb new file mode 100644 index 0000000..5ff92a5 --- /dev/null +++ b/lib/checkout_sdk/onboarding_simulator/simulator_set_status_request.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module CheckoutSdk + module OnboardingSimulator + # Request body for POST /simulate/entities/{entityId}/status. + # + # @!attribute status + # @return [String] {SimulatorEntityStatus} + class SimulatorSetStatusRequest + attr_accessor :status + end + end +end diff --git a/lib/checkout_sdk/payment_methods/payment_methods.rb b/lib/checkout_sdk/payment_methods/payment_methods.rb new file mode 100644 index 0000000..ebd7a4e --- /dev/null +++ b/lib/checkout_sdk/payment_methods/payment_methods.rb @@ -0,0 +1,4 @@ +# frozen_string_literal: true + +require 'checkout_sdk/payment_methods/payment_methods_query' +require 'checkout_sdk/payment_methods/payment_methods_client' diff --git a/lib/checkout_sdk/payment_methods/payment_methods_client.rb b/lib/checkout_sdk/payment_methods/payment_methods_client.rb new file mode 100644 index 0000000..a2149f4 --- /dev/null +++ b/lib/checkout_sdk/payment_methods/payment_methods_client.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module CheckoutSdk + module PaymentMethods + # Client for the Payment Methods configuration API. + # GET /payment-methods returns the configured payment methods for a processing channel. + class PaymentMethodsClient < Client + PAYMENT_METHODS = 'payment-methods' + private_constant :PAYMENT_METHODS + + # @param [ApiClient] api_client + # @param [CheckoutConfiguration] configuration + def initialize(api_client, configuration) + super(api_client, configuration, CheckoutSdk::AuthorizationType::SECRET_KEY_OR_OAUTH) + end + + # Get available payment methods. + # @param [Hash, PaymentMethodsQuery] payment_methods_query + def get_payment_methods(payment_methods_query) + api_client.invoke_get(PAYMENT_METHODS, sdk_authorization, payment_methods_query) + end + end + end +end diff --git a/lib/checkout_sdk/payment_methods/payment_methods_query.rb b/lib/checkout_sdk/payment_methods/payment_methods_query.rb new file mode 100644 index 0000000..0a3db5c --- /dev/null +++ b/lib/checkout_sdk/payment_methods/payment_methods_query.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module CheckoutSdk + module PaymentMethods + # Query params for GET /payment-methods. + # + # @!attribute processing_channel_id + # @return [String] (required) Pattern: ^(pc)_(\w{26})$ + class PaymentMethodsQuery + attr_accessor :processing_channel_id + end + end +end diff --git a/lib/checkout_sdk/payments/apple_pay/apple_pay_certificate_request.rb b/lib/checkout_sdk/payments/apple_pay/apple_pay_certificate_request.rb new file mode 100644 index 0000000..3fdc662 --- /dev/null +++ b/lib/checkout_sdk/payments/apple_pay/apple_pay_certificate_request.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # Request body for POST /applepay/certificates. + # + # @!attribute content + # @return [String] PEM-encoded certificate content. + class ApplePayCertificateRequest + attr_accessor :content + end + end +end diff --git a/lib/checkout_sdk/payments/apple_pay/apple_pay_client.rb b/lib/checkout_sdk/payments/apple_pay/apple_pay_client.rb new file mode 100644 index 0000000..7a0909c --- /dev/null +++ b/lib/checkout_sdk/payments/apple_pay/apple_pay_client.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # Client for the Apple Pay endpoints. + class ApplePayClient < Client + APPLEPAY = 'applepay' + CERTIFICATES = 'certificates' + ENROLLMENTS = 'enrollments' + SIGNING_REQUESTS = 'signing-requests' + private_constant :APPLEPAY, :CERTIFICATES, :ENROLLMENTS, :SIGNING_REQUESTS + + # @param [ApiClient] api_client + # @param [CheckoutConfiguration] configuration + def initialize(api_client, configuration) + super(api_client, configuration, CheckoutSdk::AuthorizationType::PUBLIC_KEY) + end + + # Upload a payment processing certificate. Public key auth per swagger. + # @param [Hash, ApplePayCertificateRequest] certificate_request + def upload_certificate(certificate_request) + api_client.invoke_post(build_path(APPLEPAY, CERTIFICATES), + sdk_authorization, + certificate_request) + end + + # Enroll a domain to the Apple Pay Service. OAuth required. + # @param [Hash, ApplePayEnrollmentRequest] enrollment_request + def enroll_domain(enrollment_request) + api_client.invoke_post(build_path(APPLEPAY, ENROLLMENTS), + sdk_authorization(CheckoutSdk::AuthorizationType::OAUTH), + enrollment_request) + end + + # Generate a certificate signing request. Public key auth per swagger. + # @param [Hash, ApplePaySigningRequest] signing_request + def generate_signing_request(signing_request) + api_client.invoke_post(build_path(APPLEPAY, SIGNING_REQUESTS), + sdk_authorization, + signing_request) + end + end + end +end diff --git a/lib/checkout_sdk/payments/apple_pay/apple_pay_enrollment_request.rb b/lib/checkout_sdk/payments/apple_pay/apple_pay_enrollment_request.rb new file mode 100644 index 0000000..bd8a8e6 --- /dev/null +++ b/lib/checkout_sdk/payments/apple_pay/apple_pay_enrollment_request.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # Request body for POST /applepay/enrollments. + # + # @!attribute domain + # @return [String] Domain to enroll with Apple Pay. + class ApplePayEnrollmentRequest + attr_accessor :domain + end + end +end diff --git a/lib/checkout_sdk/payments/apple_pay/apple_pay_signing_request.rb b/lib/checkout_sdk/payments/apple_pay/apple_pay_signing_request.rb new file mode 100644 index 0000000..39ecdee --- /dev/null +++ b/lib/checkout_sdk/payments/apple_pay/apple_pay_signing_request.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # Request body for POST /applepay/signing-requests. + # + # @!attribute protocol_version + # @return [String] CSR protocol version. + class ApplePaySigningRequest + attr_accessor :protocol_version + end + end +end diff --git a/lib/checkout_sdk/payments/base_payments_client.rb b/lib/checkout_sdk/payments/base_payments_client.rb index 80c8150..8fe995c 100644 --- a/lib/checkout_sdk/payments/base_payments_client.rb +++ b/lib/checkout_sdk/payments/base_payments_client.rb @@ -51,6 +51,25 @@ def reverse_payment(payment_id, reverse_request = nil, idempotency_key = nil) reverse_request, idempotency_key) end + + # Search payments. POST /payments/search. + # @param [Hash, PaymentsSearchRequest] search_request + def search_payments(search_request) + api_client.invoke_post(build_path(PAYMENTS_PATH, 'search'), + sdk_authorization, + search_request) + end + + # Cancel a scheduled retry. POST /payments/{id}/cancellations. + # @param [String] payment_id + # @param [Hash, CancellationRequest] cancellation_request + # @param [String, nil] idempotency_key + def cancel_payment(payment_id, cancellation_request = nil, idempotency_key = nil) + api_client.invoke_post(build_path(PAYMENTS_PATH, payment_id, 'cancellations'), + sdk_authorization, + cancellation_request, + idempotency_key) + end end end end diff --git a/lib/checkout_sdk/payments/cancellation_request.rb b/lib/checkout_sdk/payments/cancellation_request.rb new file mode 100644 index 0000000..aa47bb8 --- /dev/null +++ b/lib/checkout_sdk/payments/cancellation_request.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # Request body for POST /payments/{id}/cancellations. + # + # @!attribute reference + # @return [String] Optional merchant reference (max 80 chars). + class CancellationRequest + attr_accessor :reference + end + end +end diff --git a/lib/checkout_sdk/payments/google_pay/google_pay_client.rb b/lib/checkout_sdk/payments/google_pay/google_pay_client.rb new file mode 100644 index 0000000..c769ef6 --- /dev/null +++ b/lib/checkout_sdk/payments/google_pay/google_pay_client.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # Client for the Google Pay endpoints. All endpoints require OAuth. + class GooglePayClient < Client + GOOGLEPAY = 'googlepay' + ENROLLMENTS = 'enrollments' + DOMAIN = 'domain' + DOMAINS = 'domains' + STATE = 'state' + private_constant :GOOGLEPAY, :ENROLLMENTS, :DOMAIN, :DOMAINS, :STATE + + # @param [ApiClient] api_client + # @param [CheckoutConfiguration] configuration + def initialize(api_client, configuration) + super(api_client, configuration, CheckoutSdk::AuthorizationType::OAUTH) + end + + # @param [Hash, GooglePayEnrollmentRequest] enrollment_request + def enroll_entity(enrollment_request) + api_client.invoke_post(build_path(GOOGLEPAY, ENROLLMENTS), + sdk_authorization, + enrollment_request) + end + + # @param [String] entity_id + # @param [Hash, GooglePayDomainRequest] domain_request + def register_domain(entity_id, domain_request) + api_client.invoke_post(build_path(GOOGLEPAY, ENROLLMENTS, entity_id, DOMAIN), + sdk_authorization, + domain_request) + end + + # @param [String] entity_id + def get_registered_domains(entity_id) + api_client.invoke_get(build_path(GOOGLEPAY, ENROLLMENTS, entity_id, DOMAINS), + sdk_authorization) + end + + # @param [String] entity_id + def get_enrollment_state(entity_id) + api_client.invoke_get(build_path(GOOGLEPAY, ENROLLMENTS, entity_id, STATE), + sdk_authorization) + end + end + end +end diff --git a/lib/checkout_sdk/payments/google_pay/google_pay_domain_request.rb b/lib/checkout_sdk/payments/google_pay/google_pay_domain_request.rb new file mode 100644 index 0000000..156f17e --- /dev/null +++ b/lib/checkout_sdk/payments/google_pay/google_pay_domain_request.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # Request body for POST /googlepay/enrollments/{entity_id}/domain. + # + # @!attribute web_domain + # @return [String] Web domain to register for the enrolled entity. + class GooglePayDomainRequest + attr_accessor :web_domain + end + end +end diff --git a/lib/checkout_sdk/payments/google_pay/google_pay_enrollment_request.rb b/lib/checkout_sdk/payments/google_pay/google_pay_enrollment_request.rb new file mode 100644 index 0000000..c182369 --- /dev/null +++ b/lib/checkout_sdk/payments/google_pay/google_pay_enrollment_request.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # Request body for POST /googlepay/enrollments. + # + # @!attribute entity_id + # @return [String] Entity to enroll. + # @!attribute email_address + # @return [String] + # @!attribute accept_terms_of_service + # @return [Boolean] + class GooglePayEnrollmentRequest + attr_accessor :entity_id, :email_address, :accept_terms_of_service + end + end +end diff --git a/lib/checkout_sdk/payments/passenger.rb b/lib/checkout_sdk/payments/passenger.rb index af522d2..297dcd0 100644 --- a/lib/checkout_sdk/payments/passenger.rb +++ b/lib/checkout_sdk/payments/passenger.rb @@ -2,16 +2,30 @@ module CheckoutSdk module Payments - # @!attribute name + # Contains information about a passenger on the flight + # (PaymentInterfacesProcessingAirlinePassengerData). + # + # @!attribute first_name # @return [String] - # @!attribute date_of_birth + # @!attribute last_name # @return [String] - # @!attribute country_code - # @return [String] {CheckoutSdk::Common::Country} + # @!attribute date_of_birth + # @return [String] Format: YYYY-MM-DD + # @!attribute address + # @return [PassengerAddress] class Passenger - attr_accessor :name, + attr_accessor :first_name, + :last_name, :date_of_birth, - :country_code + :address + end + + # Partial address information for an airline passenger. + # + # @!attribute country + # @return [String] {CheckoutSdk::Common::Country} + class PassengerAddress + attr_accessor :country end end end diff --git a/lib/checkout_sdk/payments/passenger_name.rb b/lib/checkout_sdk/payments/passenger_name.rb deleted file mode 100644 index 286323b..0000000 --- a/lib/checkout_sdk/payments/passenger_name.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -module CheckoutSdk - module Payments - # @!attribute full_name - # @return [String] - class PassengerName - attr_accessor :full_name - end - end -end diff --git a/lib/checkout_sdk/payments/payment_plan.rb b/lib/checkout_sdk/payments/payment_plan.rb new file mode 100644 index 0000000..ed461d6 --- /dev/null +++ b/lib/checkout_sdk/payments/payment_plan.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # Details of a recurring subscription or installment plan associated with a payment. + # + # @!attribute amount_variability + # @return [String] Recurring-only. One of "Fixed" or "Variable". + # @!attribute financing + # @return [TrueClass, FalseClass] Installment-only. + # @!attribute amount + # @return [Integer] The amount to charge for each payment in the plan, in the minor currency unit. + # Required when source.type is "blik", amount_variability is "Fixed", and the recurring + # agreement is created without an initial payment (amount set to 0). + # @!attribute days_between_payments + # @return [Integer] + # @!attribute total_number_of_payments + # @return [Integer] + # @!attribute current_payment_number + # @return [Integer] + # @!attribute expiry + # @return [String] ISO 8601 date-time + # @!attribute name + # @return [String] The name of the payment plan. Required when source.type is "blik". + # For Blik merchant-initiated requests using an external partner_agreement_id, this value + # is used as the Blik Alias Label. Max 35 characters. + # @!attribute start_date + # @return [String] The date on which the first payment will be taken, in YYYYMMDD format. + # Required when source.type is "blik" and the recurring agreement is created without an + # initial payment (amount set to 0). + class PaymentPlan + attr_accessor :amount_variability, + :financing, + :amount, + :days_between_payments, + :total_number_of_payments, + :current_payment_number, + :expiry, + :name, + :start_date + end + end +end diff --git a/lib/checkout_sdk/payments/payment_request.rb b/lib/checkout_sdk/payments/payment_request.rb index f2bb2d2..9ce278b 100644 --- a/lib/checkout_sdk/payments/payment_request.rb +++ b/lib/checkout_sdk/payments/payment_request.rb @@ -99,7 +99,8 @@ class PaymentRequest :items, :retry, :metadata, - :instruction + :instruction, + :fallback_source end end end diff --git a/lib/checkout_sdk/payments/payments.rb b/lib/checkout_sdk/payments/payments.rb index 8cdfebc..ef14016 100644 --- a/lib/checkout_sdk/payments/payments.rb +++ b/lib/checkout_sdk/payments/payments.rb @@ -16,6 +16,8 @@ require 'checkout_sdk/payments/payment_instruction' require 'checkout_sdk/payments/payment_method_details' require 'checkout_sdk/payments/refund_request' +require 'checkout_sdk/payments/payments_search_request' +require 'checkout_sdk/payments/cancellation_request' require 'checkout_sdk/payments/product' require 'checkout_sdk/payments/refund_order' require 'checkout_sdk/payments/capture_type' @@ -32,8 +34,9 @@ require 'checkout_sdk/payments/three_ds_flow_type' require 'checkout_sdk/payments/void_request' require 'checkout_sdk/payments/payment_request' -require 'checkout_sdk/payments/passenger_name' require 'checkout_sdk/payments/processing_settings' +require 'checkout_sdk/payments/processing_data' +require 'checkout_sdk/payments/payment_plan' require 'checkout_sdk/payments/charge_bearer' require 'checkout_sdk/payments/instruction_scheme' require 'checkout_sdk/payments/network_token_type' @@ -66,6 +69,7 @@ require 'checkout_sdk/payments/source/apm/alipay_plus_source' require 'checkout_sdk/payments/source/apm/bancontact_source' require 'checkout_sdk/payments/source/apm/benefit_source' +require 'checkout_sdk/payments/source/apm/blik_source' require 'checkout_sdk/payments/source/apm/eps_source' require 'checkout_sdk/payments/source/apm/giropay_source' require 'checkout_sdk/payments/source/apm/ideal_source' @@ -179,7 +183,25 @@ require 'checkout_sdk/payments/sessions/store_payment_details_type' # Payment Setups +require 'checkout_sdk/payments/setups/account_funding_transaction_purpose' +require 'checkout_sdk/payments/setups/account_funding_transaction_identification_type' +require 'checkout_sdk/payments/setups/account_funding_transaction_identification' +require 'checkout_sdk/payments/setups/account_funding_transaction_sender' +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/payment_setups_client' # Payment Flow require 'checkout_sdk/payments/flow/flow_client' + +# Apple Pay +require 'checkout_sdk/payments/apple_pay/apple_pay_certificate_request' +require 'checkout_sdk/payments/apple_pay/apple_pay_enrollment_request' +require 'checkout_sdk/payments/apple_pay/apple_pay_signing_request' +require 'checkout_sdk/payments/apple_pay/apple_pay_client' + +# Google Pay +require 'checkout_sdk/payments/google_pay/google_pay_enrollment_request' +require 'checkout_sdk/payments/google_pay/google_pay_domain_request' +require 'checkout_sdk/payments/google_pay/google_pay_client' diff --git a/lib/checkout_sdk/payments/payments_search_request.rb b/lib/checkout_sdk/payments/payments_search_request.rb new file mode 100644 index 0000000..15d1194 --- /dev/null +++ b/lib/checkout_sdk/payments/payments_search_request.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # Request body for POST /payments/search. + # + # @!attribute query + # @return [String] The query string (max 1024 chars). + # @!attribute limit + # @return [Integer] Results per page (1-1000, default 10). + # @!attribute from_ + # @return [String] ISO 8601 UTC start. Required if `to` is set. + # Serialised as `from`. + # @!attribute to + # @return [String] ISO 8601 UTC end. Required if `from` is set. + class PaymentsSearchRequest + attr_accessor :query, :limit, :from_, :to + end + end +end diff --git a/lib/checkout_sdk/payments/processing_data.rb b/lib/checkout_sdk/payments/processing_data.rb new file mode 100644 index 0000000..e2c93ba --- /dev/null +++ b/lib/checkout_sdk/payments/processing_data.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # Response-side `processing` object returned alongside payment responses. + # Distinct from {ProcessingSettings} which is the request-side equivalent. + # + # Mirrors the swagger ProcessingData schema: + # preferred_scheme, app_id, partner_*, tax_amount, locale, retrieval_reference_number, + # cko_network_token_available (SDK-only), aft, merchant_category_code, scheme_merchant_id, + # pan_type_processed, fallback_source_used, failure_code, partner_code, partner_response_code, + # scheme, partner_fraud_status, partner_merchant_advice_code, accommodation_data, airline_data, + # custom_payment_method_ids + class ProcessingData + attr_accessor :preferred_scheme, + :app_id, + :partner_customer_id, + :partner_payment_id, + :tax_amount, + :locale, + :retrieval_reference_number, + :partner_order_id, + :partner_status, + :partner_transaction_id, + :partner_error_codes, + :partner_error_message, + :partner_authorization_code, + :partner_authorization_response_code, + :partner_fraud_status, + :partner_merchant_advice_code, + :custom_payment_method_ids, + :aft, + :merchant_category_code, + :scheme_merchant_id, + :pan_type_processed, + :fallback_source_used, + :failure_code, + :partner_code, + :partner_response_code, + :scheme, + :accommodation_data, + :airline_data + end + end +end diff --git a/lib/checkout_sdk/payments/processing_settings.rb b/lib/checkout_sdk/payments/processing_settings.rb index 5a6d232..e9d6369 100644 --- a/lib/checkout_sdk/payments/processing_settings.rb +++ b/lib/checkout_sdk/payments/processing_settings.rb @@ -72,6 +72,9 @@ module Payments # @return [string] # @!attribute affiliate_url # @return [string] + # @!attribute partner_code + # @return [String] The customer's 6-digit BLIK code. Required when source.type is "blik" + # and merchant_initiated is false. Pattern: ^\d{6}$ class ProcessingSettings attr_accessor :order_id, :tax_amount, @@ -107,7 +110,8 @@ class ProcessingSettings :senderInformation, :purpose, :affiliate_id, - :affiliate_url + :affiliate_url, + :partner_code end end end diff --git a/lib/checkout_sdk/payments/sessions/payment_sessions_client.rb b/lib/checkout_sdk/payments/sessions/payment_sessions_client.rb index 132e715..4e2edfb 100644 --- a/lib/checkout_sdk/payments/sessions/payment_sessions_client.rb +++ b/lib/checkout_sdk/payments/sessions/payment_sessions_client.rb @@ -4,6 +4,8 @@ module CheckoutSdk module Payments class PaymentSessionsClient < Client PAYMENT_SESSIONS = 'payment-sessions' + COMPLETE = 'complete' + private_constant :COMPLETE # @param [ApiClient] api_client # @param [CheckoutConfiguration] configuration @@ -15,6 +17,16 @@ def initialize(api_client, configuration) def create_payment_sessions(payment_sessions) api_client.invoke_post(PAYMENT_SESSIONS, sdk_authorization, payment_sessions) end + + # Create and immediately submit a payment session. POST /payment-sessions/complete. + # @param [Hash] payment_sessions_request + def create_and_complete_payment_sessions(payment_sessions_request) + api_client.invoke_post( + build_path(PAYMENT_SESSIONS, COMPLETE), + sdk_authorization, + payment_sessions_request + ) + end end end end diff --git a/lib/checkout_sdk/payments/setups/account_funding_transaction_identification.rb b/lib/checkout_sdk/payments/setups/account_funding_transaction_identification.rb new file mode 100644 index 0000000..8261931 --- /dev/null +++ b/lib/checkout_sdk/payments/setups/account_funding_transaction_identification.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # @!attribute type + # @return [String] {AccountFundingTransactionIdentificationType} + # @!attribute number + # @return [String] + # @!attribute issuing_country + # @return [String] {CheckoutSdk::Common::Country} + class AccountFundingTransactionIdentification + attr_accessor :type, + :number, + :issuing_country + end + end +end diff --git a/lib/checkout_sdk/payments/setups/account_funding_transaction_identification_type.rb b/lib/checkout_sdk/payments/setups/account_funding_transaction_identification_type.rb new file mode 100644 index 0000000..5ed9969 --- /dev/null +++ b/lib/checkout_sdk/payments/setups/account_funding_transaction_identification_type.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # Identification document type used by the sender of an Account Funding Transaction + # on a Payment Setup. + module AccountFundingTransactionIdentificationType + DRIVING_LICENSE = 'driving_license' + PASSPORT = 'passport' + NATIONAL_ID = 'national_id' + TAX_ID = 'tax_id' + OTHER = 'other' + end + end +end diff --git a/lib/checkout_sdk/payments/setups/account_funding_transaction_purpose.rb b/lib/checkout_sdk/payments/setups/account_funding_transaction_purpose.rb new file mode 100644 index 0000000..82ed946 --- /dev/null +++ b/lib/checkout_sdk/payments/setups/account_funding_transaction_purpose.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # Enum of allowed `purpose` values on a PaymentSetup AccountFundingTransaction. + # See https://api-reference.checkout.com (PaymentSetupAccountFundingTransaction.purpose). + module AccountFundingTransactionPurpose + DONATIONS = 'donations' + EDUCATION = 'education' + EMERGENCY_NEED = 'emergency_need' + EXPATRIATION = 'expatriation' + FAMILY_SUPPORT = 'family_support' + FINANCIAL_SERVICES = 'financial_services' + GIFTS = 'gifts' + INCOME = 'income' + INSURANCE = 'insurance' + INVESTMENT = 'investment' + IT_SERVICES = 'it_services' + LEISURE = 'leisure' + LOAN_PAYMENT = 'loan_payment' + MEDICAL_TREATMENT = 'medical_treatment' + OTHER = 'other' + PENSION = 'pension' + ROYALTIES = 'royalties' + SAVINGS = 'savings' + TRAVEL_AND_TOURISM = 'travel_and_tourism' + end + end +end diff --git a/lib/checkout_sdk/payments/setups/account_funding_transaction_recipient.rb b/lib/checkout_sdk/payments/setups/account_funding_transaction_recipient.rb new file mode 100644 index 0000000..855e319 --- /dev/null +++ b/lib/checkout_sdk/payments/setups/account_funding_transaction_recipient.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # @!attribute first_name + # @return [String] + # @!attribute last_name + # @return [String] + # @!attribute account_number + # @return [String] + # @!attribute account_type + # @return [String] + # @!attribute date_of_birth + # @return [String] Format: YYYY-MM-DD + # @!attribute address + # @return [CheckoutSdk::Common::Address] + class AccountFundingTransactionRecipient + attr_accessor :first_name, + :last_name, + :account_number, + :account_type, + :date_of_birth, + :address + end + end +end diff --git a/lib/checkout_sdk/payments/setups/account_funding_transaction_sender.rb b/lib/checkout_sdk/payments/setups/account_funding_transaction_sender.rb new file mode 100644 index 0000000..349a184 --- /dev/null +++ b/lib/checkout_sdk/payments/setups/account_funding_transaction_sender.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # @!attribute first_name + # @return [String] + # @!attribute last_name + # @return [String] + # @!attribute date_of_birth + # @return [String] Format: YYYY-MM-DD + # @!attribute country_of_birth + # @return [String] {CheckoutSdk::Common::Country} + # @!attribute nationality + # @return [String] {CheckoutSdk::Common::Country} + # @!attribute address + # @return [CheckoutSdk::Common::Address] + # @!attribute identification + # @return [AccountFundingTransactionIdentification] + class AccountFundingTransactionSender + attr_accessor :first_name, + :last_name, + :date_of_birth, + :country_of_birth, + :nationality, + :address, + :identification + end + end +end diff --git a/lib/checkout_sdk/payments/setups/blik_payment_method.rb b/lib/checkout_sdk/payments/setups/blik_payment_method.rb new file mode 100644 index 0000000..6ee1d26 --- /dev/null +++ b/lib/checkout_sdk/payments/setups/blik_payment_method.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # Blik payment method configuration on a Payment Setup. + # + # @!attribute status + # @return [String] (response-only) Payment method status (e.g. "available"). + # @!attribute flags + # @return [Array(String)] (response-only) Diagnostic flags returned by the API. + # @!attribute partner_code + # @return [String] The 6-digit Blik code generated by the customer's banking app. + # Pattern: ^[0-9]{6}$ + class BlikPaymentMethod + attr_accessor :status, + :flags, + :partner_code + end + end +end diff --git a/lib/checkout_sdk/payments/setups/payment_setup_account_funding_transaction.rb b/lib/checkout_sdk/payments/setups/payment_setup_account_funding_transaction.rb new file mode 100644 index 0000000..81ddee8 --- /dev/null +++ b/lib/checkout_sdk/payments/setups/payment_setup_account_funding_transaction.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # @!attribute enabled + # @return [TrueClass, FalseClass] + # @!attribute purpose + # @return [String] {AccountFundingTransactionPurpose} + # @!attribute sender + # @return [AccountFundingTransactionSender] + # @!attribute recipient + # @return [AccountFundingTransactionRecipient] + class PaymentSetupAccountFundingTransaction + attr_accessor :enabled, + :purpose, + :sender, + :recipient + end + end +end diff --git a/lib/checkout_sdk/payments/source/apm/blik_source.rb b/lib/checkout_sdk/payments/source/apm/blik_source.rb new file mode 100644 index 0000000..64ad36c --- /dev/null +++ b/lib/checkout_sdk/payments/source/apm/blik_source.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Payments + # Blik payment source for the /payments endpoint. + # + # When source.type is "blik": + # - currency must be PLN + # - amount must not exceed 5,000,000 (minor unit) + # - reference is limited to 35 characters + # For customer-initiated payments, provide the 6-digit BLIK code in + # `processing.partner_code`. For merchant-initiated recurring payments, + # use either source.type: "id" with a previous source.id, or + # source.type: "blik" with `partner_agreement_id`. + # + # @!attribute id + # @return [String] (response-only) The Checkout.com source identifier + # for a partner agreement created during a Blik recurring payment. + # @!attribute partner_agreement_id + # @return [String] The Blik PAYID identifying an external partner + # agreement created with another PSP. + class BlikSource < PaymentSource + attr_accessor :id, + :partner_agreement_id + + def initialize + super(CheckoutSdk::Common::PaymentSourceType::BLIK) + end + end + end +end diff --git a/lib/checkout_sdk/sessions/device_information.rb b/lib/checkout_sdk/sessions/device_information.rb new file mode 100644 index 0000000..0f0c716 --- /dev/null +++ b/lib/checkout_sdk/sessions/device_information.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Sessions + # Details of the device from which the authentication originated. + # + # @!attribute device_id + # @return [String] The unique identifier for the device. + # @!attribute device_session_id + # @return [String] Device session ID collected from the standalone Risk.js package. + # Pattern: ^(dsid)_(\w{26})$ + class DeviceInformation + attr_accessor :device_id, + :device_session_id + end + end +end diff --git a/lib/checkout_sdk/sessions/session_request.rb b/lib/checkout_sdk/sessions/session_request.rb index 534849c..f64f53b 100644 --- a/lib/checkout_sdk/sessions/session_request.rb +++ b/lib/checkout_sdk/sessions/session_request.rb @@ -73,7 +73,8 @@ class SessionRequest :recurring, :installment, :optimization, - :initial_transaction + :initial_transaction, + :device_information def initialize(source: CardSource.new, authentication_type: CheckoutSdk::Sessions::AuthenticationType::REGULAR, diff --git a/lib/checkout_sdk/sessions/sessions.rb b/lib/checkout_sdk/sessions/sessions.rb index 11f03ab..6a37d90 100644 --- a/lib/checkout_sdk/sessions/sessions.rb +++ b/lib/checkout_sdk/sessions/sessions.rb @@ -5,6 +5,7 @@ require 'checkout_sdk/sessions/card_holder_account_info' require 'checkout_sdk/sessions/category' require 'checkout_sdk/sessions/delivery_timeframe' +require 'checkout_sdk/sessions/device_information' require 'checkout_sdk/sessions/installment' require 'checkout_sdk/sessions/merchant_risk_info' require 'checkout_sdk/sessions/recurring' diff --git a/lib/checkout_sdk/standalone_account_updater/account_updater_card.rb b/lib/checkout_sdk/standalone_account_updater/account_updater_card.rb new file mode 100644 index 0000000..4ee4f92 --- /dev/null +++ b/lib/checkout_sdk/standalone_account_updater/account_updater_card.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module CheckoutSdk + module StandaloneAccountUpdater + # Card details for the standalone Account Updater request. + # + # @!attribute number + # @return [String] The card number. + # @!attribute expiry_month + # @return [Integer] + # @!attribute expiry_year + # @return [Integer] Four-digit expiry year. + class AccountUpdaterCard + attr_accessor :number, :expiry_month, :expiry_year + end + end +end diff --git a/lib/checkout_sdk/standalone_account_updater/account_updater_instrument.rb b/lib/checkout_sdk/standalone_account_updater/account_updater_instrument.rb new file mode 100644 index 0000000..846456f --- /dev/null +++ b/lib/checkout_sdk/standalone_account_updater/account_updater_instrument.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module CheckoutSdk + module StandaloneAccountUpdater + # Instrument reference for the standalone Account Updater request. + # + # @!attribute id + # @return [String] Unique instrument identifier (e.g. "src_..."). + class AccountUpdaterInstrument + attr_accessor :id + end + end +end diff --git a/lib/checkout_sdk/standalone_account_updater/account_updater_request.rb b/lib/checkout_sdk/standalone_account_updater/account_updater_request.rb new file mode 100644 index 0000000..fa4b659 --- /dev/null +++ b/lib/checkout_sdk/standalone_account_updater/account_updater_request.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module CheckoutSdk + module StandaloneAccountUpdater + # Request body for POST /account-updater/cards. + # + # @!attribute source_options + # @return [AccountUpdaterSourceOptions] + class AccountUpdaterRequest + attr_accessor :source_options + end + end +end diff --git a/lib/checkout_sdk/standalone_account_updater/account_updater_source_options.rb b/lib/checkout_sdk/standalone_account_updater/account_updater_source_options.rb new file mode 100644 index 0000000..ff79bd6 --- /dev/null +++ b/lib/checkout_sdk/standalone_account_updater/account_updater_source_options.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module CheckoutSdk + module StandaloneAccountUpdater + # The source to update. Provide either `card` or `instrument`, but not both. + # + # @!attribute card + # @return [AccountUpdaterCard] + # @!attribute instrument + # @return [AccountUpdaterInstrument] + class AccountUpdaterSourceOptions + attr_accessor :card, :instrument + end + end +end diff --git a/lib/checkout_sdk/standalone_account_updater/standalone_account_updater.rb b/lib/checkout_sdk/standalone_account_updater/standalone_account_updater.rb new file mode 100644 index 0000000..8778ec3 --- /dev/null +++ b/lib/checkout_sdk/standalone_account_updater/standalone_account_updater.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +require 'checkout_sdk/standalone_account_updater/account_updater_card' +require 'checkout_sdk/standalone_account_updater/account_updater_instrument' +require 'checkout_sdk/standalone_account_updater/account_updater_source_options' +require 'checkout_sdk/standalone_account_updater/account_updater_request' +require 'checkout_sdk/standalone_account_updater/standalone_account_updater_client' diff --git a/lib/checkout_sdk/standalone_account_updater/standalone_account_updater_client.rb b/lib/checkout_sdk/standalone_account_updater/standalone_account_updater_client.rb new file mode 100644 index 0000000..a2189d8 --- /dev/null +++ b/lib/checkout_sdk/standalone_account_updater/standalone_account_updater_client.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module CheckoutSdk + module StandaloneAccountUpdater + # Client for the Standalone Account Updater API. + # Uses OAuth with the `vault:real-time-account-updater` scope. + class StandaloneAccountUpdaterClient < Client + ACCOUNT_UPDATER = 'account-updater' + CARDS = 'cards' + private_constant :ACCOUNT_UPDATER, :CARDS + + # @param [ApiClient] api_client + # @param [CheckoutConfiguration] configuration + def initialize(api_client, configuration) + super(api_client, configuration, CheckoutSdk::AuthorizationType::OAUTH) + end + + # Get updated card credentials. + # @param [Hash, AccountUpdaterRequest] account_updater_request + def update_card(account_updater_request) + api_client.invoke_post( + build_path(ACCOUNT_UPDATER, CARDS), + sdk_authorization, + account_updater_request + ) + end + end + end +end diff --git a/lib/checkout_sdk/tokens/token_metadata_billing_address.rb b/lib/checkout_sdk/tokens/token_metadata_billing_address.rb new file mode 100644 index 0000000..f84c3af --- /dev/null +++ b/lib/checkout_sdk/tokens/token_metadata_billing_address.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Tokens + # Partial billing address (city + country) returned by GET /tokens/{tokenId}/metadata. + # + # @!attribute city + # @return [String] + # @!attribute country + # @return [String] {CheckoutSdk::Common::Country} + class TokenMetadataBillingAddress + attr_accessor :city, + :country + end + end +end diff --git a/lib/checkout_sdk/tokens/token_metadata_response.rb b/lib/checkout_sdk/tokens/token_metadata_response.rb new file mode 100644 index 0000000..36b9afc --- /dev/null +++ b/lib/checkout_sdk/tokens/token_metadata_response.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module CheckoutSdk + module Tokens + # Response from GET /tokens/{tokenId}/metadata. + # + # @!attribute token + # @return [String] + # @!attribute type + # @return [String] + # @!attribute expires_on + # @return [String] RFC 3339 timestamp. + # @!attribute expiry_month + # @return [Integer] + # @!attribute expiry_year + # @return [Integer] + # @!attribute scheme + # @return [String] + # @!attribute last4 + # @return [String] + # @!attribute bin + # @return [String] + # @!attribute card_type + # @return [String] One of CREDIT/DEBIT/PREPAID/CHARGE/"DEFERRED DEBIT". + # @!attribute card_category + # @return [String] One of CONSUMER/COMMERCIAL. + # @!attribute issuer + # @return [String] + # @!attribute issuer_country + # @return [String] ISO 3166-1 alpha-2. + # @!attribute product_id + # @return [String] + # @!attribute product_type + # @return [String] + # @!attribute billing_address + # @return [TokenMetadataBillingAddress] + class TokenMetadataResponse + attr_accessor :token, + :type, + :expires_on, + :expiry_month, + :expiry_year, + :scheme, + :last4, + :bin, + :card_type, + :card_category, + :issuer, + :issuer_country, + :product_id, + :product_type, + :billing_address + end + end +end diff --git a/lib/checkout_sdk/tokens/tokens.rb b/lib/checkout_sdk/tokens/tokens.rb index e993e16..fc58fd1 100644 --- a/lib/checkout_sdk/tokens/tokens.rb +++ b/lib/checkout_sdk/tokens/tokens.rb @@ -8,3 +8,5 @@ require 'checkout_sdk/tokens/google_pay_token_request' require 'checkout_sdk/tokens/apple_pay_token_data' require 'checkout_sdk/tokens/card_token_request' +require 'checkout_sdk/tokens/token_metadata_billing_address' +require 'checkout_sdk/tokens/token_metadata_response' diff --git a/lib/checkout_sdk/tokens/tokens_client.rb b/lib/checkout_sdk/tokens/tokens_client.rb index 88f578c..892d645 100644 --- a/lib/checkout_sdk/tokens/tokens_client.rb +++ b/lib/checkout_sdk/tokens/tokens_client.rb @@ -16,6 +16,17 @@ def initialize(api_client, configuration) def request_token(token_request) api_client.invoke_post(TOKENS, sdk_authorization, token_request) end + + # Returns the details for an active token without consuming it. + # The token remains usable after this call. + # Requires SecretKey or OAuth (not PublicKey). + # @param [String] token_id Pattern: ^(tok)_(\w{26})$ + def get_token_metadata(token_id) + api_client.invoke_get( + build_path(TOKENS, token_id, 'metadata'), + sdk_authorization(CheckoutSdk::AuthorizationType::SECRET_KEY_OR_OAUTH) + ) + end end end end diff --git a/lib/checkout_sdk/workflows/workflows_client.rb b/lib/checkout_sdk/workflows/workflows_client.rb index fcef4d0..afb02fd 100644 --- a/lib/checkout_sdk/workflows/workflows_client.rb +++ b/lib/checkout_sdk/workflows/workflows_client.rb @@ -120,7 +120,7 @@ def reflow_by_event_and_workflow(event_id, workflow_id) sdk_authorization) end - # @param [Reflow] reflow + # @param [Hash, Reflow] reflow def reflow(reflow) api_client.invoke_post(build_path(WORKFLOWS, EVENTS, REFLOW), sdk_authorization, reflow) end diff --git a/spec/checkout_sdk/accounts/reserve_rules_members_spec.rb b/spec/checkout_sdk/accounts/reserve_rules_members_spec.rb new file mode 100644 index 0000000..d5b3c34 --- /dev/null +++ b/spec/checkout_sdk/accounts/reserve_rules_members_spec.rb @@ -0,0 +1,110 @@ +RSpec.describe CheckoutSdk::Accounts do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:files_client_mock) { double('files_client') } + let(:configuration_mock) { double('configuration') } + let(:client) do + CheckoutSdk::Accounts::AccountsClient.new(api_client_mock, files_client_mock, configuration_mock) + end + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('secret_key') + end + + describe '#add_reserve_rule' do + it 'POSTs to accounts/entities/{id}/reserve-rules' do + req = CheckoutSdk::Accounts::ReserveRuleCreateRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('accounts/entities/ent_1/reserve-rules', 'secret_key', req).and_return('r') + expect(client.add_reserve_rule('ent_1', req)).to eq('r') + end + end + + describe '#query_reserve_rules' do + it 'GETs accounts/entities/{id}/reserve-rules' do + expect(api_client_mock).to receive(:invoke_get) + .with('accounts/entities/ent_1/reserve-rules', 'secret_key').and_return('r') + expect(client.query_reserve_rules('ent_1')).to eq('r') + end + end + + describe '#get_reserve_rule' do + it 'GETs accounts/entities/{id}/reserve-rules/{rid}' do + expect(api_client_mock).to receive(:invoke_get) + .with('accounts/entities/ent_1/reserve-rules/rsv_1', 'secret_key').and_return('r') + expect(client.get_reserve_rule('ent_1', 'rsv_1')).to eq('r') + end + end + + describe '#update_reserve_rule' do + it 'PUTs accounts/entities/{id}/reserve-rules/{rid} forwarding the etag as If-Match' do + req = CheckoutSdk::Accounts::ReserveRuleUpdateRequest.new + etag = 'W/"3a-fXqMK..."' + expect(api_client_mock).to receive(:invoke_put) do |path, auth, body, headers| + expect(path).to eq('accounts/entities/ent_1/reserve-rules/rsv_1') + expect(auth).to eq('secret_key') + expect(body).to eq(req) + expect(headers).to be_a(CheckoutSdk::Common::Headers) + expect(headers.if_match).to eq(etag) + 'r' + end + expect(client.update_reserve_rule('ent_1', 'rsv_1', etag, req)).to eq('r') + end + + it 'omits the Headers container when no etag is provided' do + req = CheckoutSdk::Accounts::ReserveRuleUpdateRequest.new + expect(api_client_mock).to receive(:invoke_put) + .with('accounts/entities/ent_1/reserve-rules/rsv_1', 'secret_key', req, nil) + .and_return('r') + expect(client.update_reserve_rule('ent_1', 'rsv_1', nil, req)).to eq('r') + end + + it 'omits the Headers container when etag is an empty string' do + req = CheckoutSdk::Accounts::ReserveRuleUpdateRequest.new + expect(api_client_mock).to receive(:invoke_put) + .with('accounts/entities/ent_1/reserve-rules/rsv_1', 'secret_key', req, nil) + .and_return('r') + expect(client.update_reserve_rule('ent_1', 'rsv_1', '', req)).to eq('r') + end + end + + describe '#get_sub_entity_members' do + it 'GETs accounts/entities/{id}/members' do + expect(api_client_mock).to receive(:invoke_get) + .with('accounts/entities/ent_1/members', 'secret_key').and_return('r') + expect(client.get_sub_entity_members('ent_1')).to eq('r') + end + end + + describe '#reinvite_sub_entity_member' do + it 'PUTs accounts/entities/{id}/members/{userId} with the required body' do + body = {} + expect(api_client_mock).to receive(:invoke_put) + .with('accounts/entities/ent_1/members/usr_1', 'secret_key', body).and_return('r') + expect(client.reinvite_sub_entity_member('ent_1', 'usr_1', body)).to eq('r') + end + + it 'raises when called without a body (required by swagger)' do + expect { client.reinvite_sub_entity_member('ent_1', 'usr_1') } + .to raise_error(ArgumentError, /wrong number of arguments/) + end + end + + describe '#upload_entity_file' do + it 'submits multipart to entities/{id}/files via files_client' do + req = CheckoutSdk::Accounts::EntityFilesRequest.new + expect(files_client_mock).to receive(:submit_file) + .with('entities/ent_1/files', 'secret_key', req).and_return('r') + expect(client.upload_entity_file('ent_1', req)).to eq('r') + end + end + + describe '#get_entity_file' do + it 'GETs entities/{id}/files/{fileId} via files_client' do + expect(files_client_mock).to receive(:invoke_get) + .with('entities/ent_1/files/file_1', 'secret_key').and_return('r') + expect(client.get_entity_file('ent_1', 'file_1')).to eq('r') + end + end +end diff --git a/spec/checkout_sdk/agentic_commerce/agentic_commerce_client_spec.rb b/spec/checkout_sdk/agentic_commerce/agentic_commerce_client_spec.rb new file mode 100644 index 0000000..ef35181 --- /dev/null +++ b/spec/checkout_sdk/agentic_commerce/agentic_commerce_client_spec.rb @@ -0,0 +1,37 @@ +RSpec.describe CheckoutSdk::AgenticCommerce do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::AgenticCommerce::AgenticCommerceClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('secret_key') + end + + describe '#create_delegated_payment_token' do + it 'POSTs typed DTO to agentic_commerce/delegate_payment with idempotency_key' do + request = CheckoutSdk::AgenticCommerce::DelegatedPaymentRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('agentic_commerce/delegate_payment', 'secret_key', request, 'idem-1') + .and_return('response') + expect(client.create_delegated_payment_token(request, 'idem-1')).to eq('response') + end + + it 'POSTs without idempotency_key when omitted' do + request = CheckoutSdk::AgenticCommerce::DelegatedPaymentRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('agentic_commerce/delegate_payment', 'secret_key', request, nil) + .and_return('response') + expect(client.create_delegated_payment_token(request)).to eq('response') + end + + it 'also accepts a raw Hash' do + hash_request = { 'metadata' => { 'order_id' => 'ord_1' } } + expect(api_client_mock).to receive(:invoke_post) + .with('agentic_commerce/delegate_payment', 'secret_key', hash_request, nil) + .and_return('response') + expect(client.create_delegated_payment_token(hash_request)).to eq('response') + end + end +end diff --git a/spec/checkout_sdk/agentic_commerce/agentic_commerce_integration_spec.rb b/spec/checkout_sdk/agentic_commerce/agentic_commerce_integration_spec.rb new file mode 100644 index 0000000..c6f0ba3 --- /dev/null +++ b/spec/checkout_sdk/agentic_commerce/agentic_commerce_integration_spec.rb @@ -0,0 +1,52 @@ +RSpec.describe CheckoutSdk::AgenticCommerce do + skip 'Requires a sandbox merchant with Agentic Commerce (Beta) enabled' do + let(:client) { default_sdk.agentic_commerce } + + describe '#create_delegated_payment_token' do + it 'creates a delegated payment token for a single purchase' do + # Card payment method — swagger required: type, card_number_type, number, metadata + card = CheckoutSdk::AgenticCommerce::DelegatedPaymentMethodCard.new + card.card_number_type = 'fpan' + card.number = '4242424242424242' + card.exp_month = '12' + card.exp_year = '2030' + card.name = 'Integration Test' + card.metadata = { 'merchant_reference' => 'INT-AC-001' } + + # Allowance — swagger required: reason, max_amount, currency, merchant_id, + # checkout_session_id, expires_at + allowance = CheckoutSdk::AgenticCommerce::DelegatedPaymentAllowance.new + allowance.reason = 'one_time' + allowance.max_amount = 1000 + allowance.currency = 'GBP' + allowance.merchant_id = ENV['CHECKOUT_AC_MERCHANT_ID'] + allowance.checkout_session_id = ENV['CHECKOUT_AC_SESSION_ID'] + allowance.expires_at = '2026-12-31T23:59:59Z' + + # Billing address — swagger required: name, line_one, city, postal_code, country + billing = CheckoutSdk::AgenticCommerce::DelegatedPaymentBillingAddress.new + billing.name = 'Integration Test' + billing.line_one = '1 Test Street' + billing.city = 'London' + billing.postal_code = 'SW1A 1AA' + billing.country = 'GB' + + # Risk signals — swagger required: type, score, action (array) + risk = CheckoutSdk::AgenticCommerce::DelegatedPaymentRiskSignal.new + risk.type = 'card_testing' + risk.score = 10 + risk.action = 'allow' + + request = CheckoutSdk::AgenticCommerce::DelegatedPaymentRequest.new + request.payment_method = card + request.allowance = allowance + request.billing_address = billing + request.risk_signals = [risk] + request.metadata = { 'order_id' => 'INT-AC-001' } + + response = client.create_delegated_payment_token(request, SecureRandom.uuid) + expect(response).not_to be_nil + end + end + end +end diff --git a/spec/checkout_sdk/api_client_spec.rb b/spec/checkout_sdk/api_client_spec.rb index 1cf1158..b8f2457 100644 --- a/spec/checkout_sdk/api_client_spec.rb +++ b/spec/checkout_sdk/api_client_spec.rb @@ -157,4 +157,54 @@ end end end + + describe 'header wiring' do + let(:auth) { double('auth', authorization_header: 'Bearer xxx') } + let(:response) { double('Response', status: 200, body: '{}', headers: { 'Content-Type' => 'application/json' }) } + let(:http_client) { api_client.client } + + before do + allow(CheckoutSdk::CheckoutUtils).to receive(:map_to_http_metadata).and_return( + OpenStruct.new(status_code: 200, body: '{}') + ) + end + + it 'emits the If-Match header on PUT when a Common::Headers carries one' do + captured = nil + allow(http_client).to receive(:run_request) do |_method, _path, _body, headers| + captured = headers + response + end + extra = CheckoutSdk::Common::Headers.new + extra.if_match = 'W/"etag-123"' + + api_client.invoke_put('accounts/entities/ent_1/reserve-rules/rsv_1', auth, {}, extra) + + expect(captured[:'If-Match']).to eq('W/"etag-123"') + end + + it 'omits the If-Match header when no headers container is passed' do + captured = nil + allow(http_client).to receive(:run_request) do |_method, _path, _body, headers| + captured = headers + response + end + + api_client.invoke_put('some/path', auth, {}) + + expect(captured).not_to have_key(:'If-Match') + end + + it 'omits the If-Match header when the headers container is empty' do + captured = nil + allow(http_client).to receive(:run_request) do |_method, _path, _body, headers| + captured = headers + response + end + + api_client.invoke_put('some/path', auth, {}, CheckoutSdk::Common::Headers.new) + + expect(captured).not_to have_key(:'If-Match') + end + end end \ No newline at end of file diff --git a/spec/checkout_sdk/compliance_requests/compliance_requests_client_spec.rb b/spec/checkout_sdk/compliance_requests/compliance_requests_client_spec.rb new file mode 100644 index 0000000..758807d --- /dev/null +++ b/spec/checkout_sdk/compliance_requests/compliance_requests_client_spec.rb @@ -0,0 +1,38 @@ +RSpec.describe CheckoutSdk::ComplianceRequests do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::ComplianceRequests::ComplianceRequestsClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('secret_key') + end + + describe '#get_compliance_request' do + it 'GETs compliance-requests/{payment_id}' do + expect(api_client_mock).to receive(:invoke_get) + .with('compliance-requests/pay_123', 'secret_key') + .and_return('response') + expect(client.get_compliance_request('pay_123')).to eq('response') + end + end + + describe '#respond_to_compliance_request' do + it 'POSTs typed DTO to compliance-requests/{payment_id}' do + request = CheckoutSdk::ComplianceRequests::ComplianceResponseRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('compliance-requests/pay_123', 'secret_key', request) + .and_return('response') + expect(client.respond_to_compliance_request('pay_123', request)).to eq('response') + end + + it 'also accepts a raw Hash' do + hash_request = { 'comments' => 'note', 'fields' => { 'sender' => [] } } + expect(api_client_mock).to receive(:invoke_post) + .with('compliance-requests/pay_123', 'secret_key', hash_request) + .and_return('response') + expect(client.respond_to_compliance_request('pay_123', hash_request)).to eq('response') + end + end +end diff --git a/spec/checkout_sdk/compliance_requests/compliance_requests_integration_spec.rb b/spec/checkout_sdk/compliance_requests/compliance_requests_integration_spec.rb new file mode 100644 index 0000000..2834549 --- /dev/null +++ b/spec/checkout_sdk/compliance_requests/compliance_requests_integration_spec.rb @@ -0,0 +1,29 @@ +RSpec.describe CheckoutSdk::ComplianceRequests do + skip 'Requires a sandbox payment with a pending compliance request' do + let(:client) { default_sdk.compliance_requests } + let(:payment_id) { ENV['CHECKOUT_COMPLIANCE_PAYMENT_ID'] } + + describe '#get_compliance_request' do + it 'retrieves a compliance request' do + response = client.get_compliance_request(payment_id) + expect(response).not_to be_nil + end + end + + describe '#respond_to_compliance_request' do + it 'responds to a compliance request' do + request = CheckoutSdk::ComplianceRequests::ComplianceResponseRequest.new + request.comments = 'Integration test response' + request.fields = CheckoutSdk::ComplianceRequests::ComplianceRequestRespondedFields.new + sender_field = CheckoutSdk::ComplianceRequests::ComplianceRequestRespondedField.new + sender_field.name = 'date_of_birth' + sender_field.value = '1990-01-01' + sender_field.not_available = false + request.fields.sender = [sender_field] + + response = client.respond_to_compliance_request(payment_id, request) + expect(response).not_to be_nil + end + end + end +end diff --git a/spec/checkout_sdk/disputes/disputes_arbitration_spec.rb b/spec/checkout_sdk/disputes/disputes_arbitration_spec.rb new file mode 100644 index 0000000..e4f2f75 --- /dev/null +++ b/spec/checkout_sdk/disputes/disputes_arbitration_spec.rb @@ -0,0 +1,27 @@ +RSpec.describe CheckoutSdk::Disputes do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::Disputes::DisputesClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('secret_key') + end + + describe '#submit_arbitration' do + it 'POSTs disputes/{id}/evidence/arbitration' do + expect(api_client_mock).to receive(:invoke_post) + .with('disputes/dsp_1/evidence/arbitration', 'secret_key', nil).and_return('r') + expect(client.submit_arbitration('dsp_1')).to eq('r') + end + end + + describe '#get_submitted_arbitration_evidence' do + it 'GETs disputes/{id}/evidence/arbitration/submitted' do + expect(api_client_mock).to receive(:invoke_get) + .with('disputes/dsp_1/evidence/arbitration/submitted', 'secret_key').and_return('r') + expect(client.get_submitted_arbitration_evidence('dsp_1')).to eq('r') + end + end +end diff --git a/spec/checkout_sdk/forward/forward_secrets_spec.rb b/spec/checkout_sdk/forward/forward_secrets_spec.rb new file mode 100644 index 0000000..8d90975 --- /dev/null +++ b/spec/checkout_sdk/forward/forward_secrets_spec.rb @@ -0,0 +1,54 @@ +RSpec.describe CheckoutSdk::Forward do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::Forward::ForwardClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('secret_key') + end + + describe '#create_secret' do + it 'POSTs typed DTO to forward/secrets' do + req = CheckoutSdk::Forward::CreateSecretRequest.new + req.name = 'sk_test' + req.value = 'secret' + expect(api_client_mock).to receive(:invoke_post) + .with('forward/secrets', 'secret_key', req).and_return('r') + expect(client.create_secret(req)).to eq('r') + end + + it 'also accepts a raw Hash' do + h = { 'name' => 's', 'value' => 'v' } + expect(api_client_mock).to receive(:invoke_post) + .with('forward/secrets', 'secret_key', h).and_return('r') + expect(client.create_secret(h)).to eq('r') + end + end + + describe '#get_secrets' do + it 'GETs forward/secrets' do + expect(api_client_mock).to receive(:invoke_get) + .with('forward/secrets', 'secret_key').and_return('r') + expect(client.get_secrets).to eq('r') + end + end + + describe '#update_secret' do + it 'PATCHes typed DTO to forward/secrets/{name}' do + req = CheckoutSdk::Forward::UpdateSecretRequest.new + expect(api_client_mock).to receive(:invoke_patch) + .with('forward/secrets/my_name', 'secret_key', req).and_return('r') + expect(client.update_secret('my_name', req)).to eq('r') + end + end + + describe '#delete_secret' do + it 'DELETEs forward/secrets/{name}' do + expect(api_client_mock).to receive(:invoke_delete) + .with('forward/secrets/my_name', 'secret_key').and_return('r') + expect(client.delete_secret('my_name')).to eq('r') + end + end +end diff --git a/spec/checkout_sdk/hash_request_compatibility_spec.rb b/spec/checkout_sdk/hash_request_compatibility_spec.rb new file mode 100644 index 0000000..c684f2d --- /dev/null +++ b/spec/checkout_sdk/hash_request_compatibility_spec.rb @@ -0,0 +1,131 @@ +RSpec.describe 'Hash <-> typed-DTO request compatibility' do + # Convention (per .cursor/rules/ruby-endpoint-review.mdc): + # every client request body / query param accepts EITHER a typed DTO + # OR a raw Hash. Both must serialize identically through JsonSerializer. + # This spec locks that rule in for the modules added in this revision. + + def serialize(value) + CheckoutSdk::JsonSerializer.serialize_by_type(value) + end + + it 'AgenticCommerce::DelegatedPaymentRequest equals its Hash form' do + typed = CheckoutSdk::AgenticCommerce::DelegatedPaymentRequest.new + typed.metadata = { 'order_id' => 'ord_1' } + hash_form = { 'metadata' => { 'order_id' => 'ord_1' } } + expect(serialize(typed)).to eq(serialize(hash_form)) + end + + it 'ComplianceRequests::ComplianceResponseRequest equals its Hash form' do + typed = CheckoutSdk::ComplianceRequests::ComplianceResponseRequest.new + typed.comments = 'note' + hash_form = { 'comments' => 'note' } + expect(serialize(typed)).to eq(serialize(hash_form)) + end + + it 'StandaloneAccountUpdater::AccountUpdaterRequest equals its Hash form' do + card = CheckoutSdk::StandaloneAccountUpdater::AccountUpdaterCard.new + card.number = '4242424242424242' + card.expiry_month = 12 + card.expiry_year = 2030 + src = CheckoutSdk::StandaloneAccountUpdater::AccountUpdaterSourceOptions.new + src.card = card + typed = CheckoutSdk::StandaloneAccountUpdater::AccountUpdaterRequest.new + typed.source_options = src + hash_form = { + 'source_options' => { + 'card' => { 'number' => '4242424242424242', 'expiry_month' => 12, 'expiry_year' => 2030 } + } + } + expect(serialize(typed)).to eq(serialize(hash_form)) + end + + it 'NetworkTokens::ProvisionNetworkTokenRequest equals its Hash form' do + source = CheckoutSdk::NetworkTokens::NetworkTokenSourceId.new + source.id = 'src_xxx' + typed = CheckoutSdk::NetworkTokens::ProvisionNetworkTokenRequest.new + typed.source = source + hash_form = { 'source' => { 'type' => 'id', 'id' => 'src_xxx' } } + expect(serialize(typed)).to eq(serialize(hash_form)) + end + + it 'NetworkTokens::NetworkTokenCryptogramRequest equals its Hash form' do + typed = CheckoutSdk::NetworkTokens::NetworkTokenCryptogramRequest.new + typed.transaction_type = 'ecom' + hash_form = { 'transaction_type' => 'ecom' } + expect(serialize(typed)).to eq(serialize(hash_form)) + end + + it 'AmlScreening::AmlVerificationRequest equals its Hash form' do + sp = CheckoutSdk::Identities::AmlScreening::AmlSearchParameters.new + sp.configuration_identifier = 'cfg_1' + typed = CheckoutSdk::Identities::AmlScreening::AmlVerificationRequest.new + typed.applicant_id = 'aplt_x' + typed.search_parameters = sp + typed.monitored = false + hash_form = { + 'applicant_id' => 'aplt_x', + 'search_parameters' => { 'configuration_identifier' => 'cfg_1' }, + 'monitored' => false + } + expect(serialize(typed)).to eq(serialize(hash_form)) + end + + it 'IdentityVerification::IdentityVerificationRequest equals its Hash form' do + declared = CheckoutSdk::Identities::IdentityVerification::IdvDeclaredData.new + declared.name = 'John Doe' + typed = CheckoutSdk::Identities::IdentityVerification::IdentityVerificationRequest.new + typed.applicant_id = 'aplt_x' + typed.user_journey_id = 'usj_x' + typed.declared_data = declared + typed.risk_labels = ['label_1'] + hash_form = { + 'applicant_id' => 'aplt_x', + 'user_journey_id' => 'usj_x', + 'declared_data' => { 'name' => 'John Doe' }, + 'risk_labels' => ['label_1'] + } + expect(serialize(typed)).to eq(serialize(hash_form)) + end + + it 'Issuing::CardholderAccessTokenRequest equals its Hash form' do + typed = CheckoutSdk::Issuing::CardholderAccessTokenRequest.new + typed.client_id = 'cid' + typed.client_secret = 'csec' + typed.cardholder_id = 'crh_x' + typed.single_use = true + hash_form = { + 'grant_type' => 'client_credentials', + 'client_id' => 'cid', + 'client_secret' => 'csec', + 'cardholder_id' => 'crh_x', + 'single_use' => true + } + expect(serialize(typed)).to eq(serialize(hash_form)) + end + + it 'Issuing::OobAuthenticationRequest equals its Hash form' do + td = CheckoutSdk::Issuing::OobSimulateTransactionDetails.new + td.merchant_name = 'Acme Ltd' + td.purchase_amount = 100 + td.purchase_currency = 'GBP' + typed = CheckoutSdk::Issuing::OobAuthenticationRequest.new + typed.card_id = 'crd_x' + typed.transaction_details = td + hash_form = { + 'card_id' => 'crd_x', + 'transaction_details' => { + 'merchant_name' => 'Acme Ltd', + 'purchase_amount' => 100, + 'purchase_currency' => 'GBP' + } + } + expect(serialize(typed)).to eq(serialize(hash_form)) + end + + it 'PaymentMethods::PaymentMethodsQuery equals its Hash form' do + typed = CheckoutSdk::PaymentMethods::PaymentMethodsQuery.new + typed.processing_channel_id = 'pc_x' + hash_form = { 'processing_channel_id' => 'pc_x' } + expect(serialize(typed)).to eq(serialize(hash_form)) + end +end diff --git a/spec/checkout_sdk/identities/aml_screening/aml_screening_client_spec.rb b/spec/checkout_sdk/identities/aml_screening/aml_screening_client_spec.rb new file mode 100644 index 0000000..ba6df90 --- /dev/null +++ b/spec/checkout_sdk/identities/aml_screening/aml_screening_client_spec.rb @@ -0,0 +1,40 @@ +RSpec.describe CheckoutSdk::Identities::AmlScreening do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::Identities::AmlScreening::AmlScreeningClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('secret_key') + end + + describe '#create_aml_verification' do + it 'POSTs typed DTO to aml-verifications' do + request = CheckoutSdk::Identities::AmlScreening::AmlVerificationRequest.new + request.applicant_id = 'aplt_x' + request.search_parameters = CheckoutSdk::Identities::AmlScreening::AmlSearchParameters.new + expect(api_client_mock).to receive(:invoke_post) + .with('aml-verifications', 'secret_key', request).and_return('response') + expect(client.create_aml_verification(request)).to eq('response') + end + + it 'also accepts a raw Hash' do + hash_request = { + 'applicant_id' => 'aplt_x', + 'search_parameters' => { 'configuration_identifier' => 'cfg_1' } + } + expect(api_client_mock).to receive(:invoke_post) + .with('aml-verifications', 'secret_key', hash_request).and_return('response') + expect(client.create_aml_verification(hash_request)).to eq('response') + end + end + + describe '#get_aml_verification' do + it 'GETs aml-verifications/{id}' do + expect(api_client_mock).to receive(:invoke_get) + .with('aml-verifications/amlv_x', 'secret_key').and_return('response') + expect(client.get_aml_verification('amlv_x')).to eq('response') + end + end +end diff --git a/spec/checkout_sdk/identities/aml_screening/aml_screening_integration_spec.rb b/spec/checkout_sdk/identities/aml_screening/aml_screening_integration_spec.rb new file mode 100644 index 0000000..f09bfea --- /dev/null +++ b/spec/checkout_sdk/identities/aml_screening/aml_screening_integration_spec.rb @@ -0,0 +1,24 @@ +RSpec.describe CheckoutSdk::Identities::AmlScreening do + skip 'Requires sandbox credentials with AML Screening entitlement' do + let(:client) { default_sdk.aml_screening } + + describe '#create_aml_verification' do + it 'creates an AML verification' do + request = CheckoutSdk::Identities::AmlScreening::AmlVerificationRequest.new + request.applicant_id = ENV['CHECKOUT_APPLICANT_ID'] + request.search_parameters = CheckoutSdk::Identities::AmlScreening::AmlSearchParameters.new + request.search_parameters.configuration_identifier = ENV['CHECKOUT_AML_CONFIG_ID'] + request.monitored = false + response = client.create_aml_verification(request) + expect(response).not_to be_nil + end + end + + describe '#get_aml_verification' do + it 'retrieves an AML verification' do + response = client.get_aml_verification(ENV['CHECKOUT_AML_VERIFICATION_ID']) + expect(response).not_to be_nil + end + end + end +end diff --git a/spec/checkout_sdk/identities/applicants/applicants_client_spec.rb b/spec/checkout_sdk/identities/applicants/applicants_client_spec.rb new file mode 100644 index 0000000..3fa17c0 --- /dev/null +++ b/spec/checkout_sdk/identities/applicants/applicants_client_spec.rb @@ -0,0 +1,59 @@ +RSpec.describe CheckoutSdk::Identities::Applicants do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::Identities::Applicants::ApplicantsClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('secret_key') + end + + describe '#create_applicant' do + it 'POSTs typed DTO to applicants' do + request = CheckoutSdk::Identities::Applicants::CreateApplicantRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('applicants', 'secret_key', request).and_return('response') + expect(client.create_applicant(request)).to eq('response') + end + + it 'also accepts a raw Hash' do + hash_request = { 'reference' => 'ref-1' } + expect(api_client_mock).to receive(:invoke_post) + .with('applicants', 'secret_key', hash_request).and_return('response') + expect(client.create_applicant(hash_request)).to eq('response') + end + end + + describe '#get_applicant' do + it 'GETs applicants/{id}' do + expect(api_client_mock).to receive(:invoke_get) + .with('applicants/aplt_x', 'secret_key').and_return('response') + expect(client.get_applicant('aplt_x')).to eq('response') + end + end + + describe '#update_applicant' do + it 'PATCHes typed DTO to applicants/{id}' do + request = CheckoutSdk::Identities::Applicants::UpdateApplicantRequest.new + expect(api_client_mock).to receive(:invoke_patch) + .with('applicants/aplt_x', 'secret_key', request).and_return('response') + expect(client.update_applicant('aplt_x', request)).to eq('response') + end + + it 'also accepts a raw Hash' do + hash_request = { 'reference' => 'ref-2' } + expect(api_client_mock).to receive(:invoke_patch) + .with('applicants/aplt_x', 'secret_key', hash_request).and_return('response') + expect(client.update_applicant('aplt_x', hash_request)).to eq('response') + end + end + + describe '#anonymize_applicant' do + it 'POSTs applicants/{id}/anonymize' do + expect(api_client_mock).to receive(:invoke_post) + .with('applicants/aplt_x/anonymize', 'secret_key').and_return('response') + expect(client.anonymize_applicant('aplt_x')).to eq('response') + end + end +end diff --git a/spec/checkout_sdk/identities/applicants/applicants_integration_spec.rb b/spec/checkout_sdk/identities/applicants/applicants_integration_spec.rb new file mode 100644 index 0000000..b428e1b --- /dev/null +++ b/spec/checkout_sdk/identities/applicants/applicants_integration_spec.rb @@ -0,0 +1,35 @@ +RSpec.describe CheckoutSdk::Identities::Applicants do + skip 'Requires sandbox credentials with Identities entitlement' do + let(:client) { default_sdk.applicants } + + describe '#create_applicant' do + it 'creates an applicant' do + request = CheckoutSdk::Identities::Applicants::CreateApplicantRequest.new + response = client.create_applicant(request) + expect(response).not_to be_nil + end + end + + describe '#get_applicant' do + it 'retrieves an applicant' do + response = client.get_applicant(ENV['CHECKOUT_APPLICANT_ID']) + expect(response).not_to be_nil + end + end + + describe '#update_applicant' do + it 'updates an applicant' do + request = CheckoutSdk::Identities::Applicants::UpdateApplicantRequest.new + response = client.update_applicant(ENV['CHECKOUT_APPLICANT_ID'], request) + expect(response).not_to be_nil + end + end + + describe '#anonymize_applicant' do + it 'anonymizes an applicant' do + response = client.anonymize_applicant(ENV['CHECKOUT_APPLICANT_ID']) + expect(response).not_to be_nil + end + end + end +end diff --git a/spec/checkout_sdk/identities/face_authentication/face_authentication_client_spec.rb b/spec/checkout_sdk/identities/face_authentication/face_authentication_client_spec.rb new file mode 100644 index 0000000..69b7511 --- /dev/null +++ b/spec/checkout_sdk/identities/face_authentication/face_authentication_client_spec.rb @@ -0,0 +1,59 @@ +RSpec.describe CheckoutSdk::Identities::FaceAuthentication do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::Identities::FaceAuthentication::FaceAuthenticationClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('secret_key') + end + + describe '#create_face_authentication' do + it 'POSTs typed DTO to face-authentications' do + request = CheckoutSdk::Identities::FaceAuthentication::FaceAuthenticationRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('face-authentications', 'secret_key', request).and_return('response') + expect(client.create_face_authentication(request)).to eq('response') + end + + it 'also accepts a raw Hash' do + hash_request = { 'applicant_id' => 'aplt_x' } + expect(api_client_mock).to receive(:invoke_post) + .with('face-authentications', 'secret_key', hash_request).and_return('response') + expect(client.create_face_authentication(hash_request)).to eq('response') + end + end + + describe '#get_face_authentication' do + it 'GETs face-authentications/{id}' do + expect(api_client_mock).to receive(:invoke_get) + .with('face-authentications/fa_x', 'secret_key').and_return('response') + expect(client.get_face_authentication('fa_x')).to eq('response') + end + end + + describe '#anonymize_face_authentication' do + it 'POSTs face-authentications/{id}/anonymize' do + expect(api_client_mock).to receive(:invoke_post) + .with('face-authentications/fa_x/anonymize', 'secret_key').and_return('response') + expect(client.anonymize_face_authentication('fa_x')).to eq('response') + end + end + + describe '#get_face_authentication_attempts' do + it 'GETs face-authentications/{id}/attempts' do + expect(api_client_mock).to receive(:invoke_get) + .with('face-authentications/fa_x/attempts', 'secret_key').and_return('response') + expect(client.get_face_authentication_attempts('fa_x')).to eq('response') + end + end + + describe '#get_face_authentication_attempt' do + it 'GETs face-authentications/{id}/attempts/{attempt_id}' do + expect(api_client_mock).to receive(:invoke_get) + .with('face-authentications/fa_x/attempts/att_1', 'secret_key').and_return('response') + expect(client.get_face_authentication_attempt('fa_x', 'att_1')).to eq('response') + end + end +end diff --git a/spec/checkout_sdk/identities/face_authentication/face_authentication_integration_spec.rb b/spec/checkout_sdk/identities/face_authentication/face_authentication_integration_spec.rb new file mode 100644 index 0000000..6a17536 --- /dev/null +++ b/spec/checkout_sdk/identities/face_authentication/face_authentication_integration_spec.rb @@ -0,0 +1,41 @@ +RSpec.describe CheckoutSdk::Identities::FaceAuthentication do + skip 'Requires sandbox credentials with Face Authentication entitlement' do + let(:client) { default_sdk.face_authentication } + + describe '#create_face_authentication' do + it 'creates a face authentication' do + request = CheckoutSdk::Identities::FaceAuthentication::FaceAuthenticationRequest.new + response = client.create_face_authentication(request) + expect(response).not_to be_nil + end + end + + describe '#get_face_authentication' do + it 'retrieves a face authentication' do + response = client.get_face_authentication(ENV['CHECKOUT_FACE_AUTH_ID']) + expect(response).not_to be_nil + end + end + + describe '#anonymize_face_authentication' do + it 'anonymizes the face authentication' do + response = client.anonymize_face_authentication(ENV['CHECKOUT_FACE_AUTH_ID']) + expect(response).not_to be_nil + end + end + + describe '#get_face_authentication_attempts' do + it 'lists face authentication attempts' do + response = client.get_face_authentication_attempts(ENV['CHECKOUT_FACE_AUTH_ID']) + expect(response).not_to be_nil + end + end + + describe '#get_face_authentication_attempt' do + it 'retrieves a single face authentication attempt' do + response = client.get_face_authentication_attempt(ENV['CHECKOUT_FACE_AUTH_ID'], ENV['CHECKOUT_FACE_AUTH_ATTEMPT_ID']) + expect(response).not_to be_nil + end + end + end +end diff --git a/spec/checkout_sdk/identities/id_document_verification/id_document_verification_client_spec.rb b/spec/checkout_sdk/identities/id_document_verification/id_document_verification_client_spec.rb new file mode 100644 index 0000000..b86b3e1 --- /dev/null +++ b/spec/checkout_sdk/identities/id_document_verification/id_document_verification_client_spec.rb @@ -0,0 +1,67 @@ +RSpec.describe CheckoutSdk::Identities::IdDocumentVerification do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::Identities::IdDocumentVerification::IdDocumentVerificationClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('secret_key') + end + + describe '#create_id_document_verification' do + it 'POSTs typed DTO to id-document-verifications' do + request = CheckoutSdk::Identities::IdDocumentVerification::IdDocumentVerificationRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('id-document-verifications', 'secret_key', request).and_return('response') + expect(client.create_id_document_verification(request)).to eq('response') + end + + it 'also accepts a raw Hash' do + hash_request = { 'applicant_id' => 'aplt_x' } + expect(api_client_mock).to receive(:invoke_post) + .with('id-document-verifications', 'secret_key', hash_request).and_return('response') + expect(client.create_id_document_verification(hash_request)).to eq('response') + end + end + + describe '#get_id_document_verification' do + it 'GETs id-document-verifications/{id}' do + expect(api_client_mock).to receive(:invoke_get) + .with('id-document-verifications/idv_x', 'secret_key').and_return('response') + expect(client.get_id_document_verification('idv_x')).to eq('response') + end + end + + describe '#anonymize_id_document_verification' do + it 'POSTs id-document-verifications/{id}/anonymize' do + expect(api_client_mock).to receive(:invoke_post) + .with('id-document-verifications/idv_x/anonymize', 'secret_key').and_return('response') + expect(client.anonymize_id_document_verification('idv_x')).to eq('response') + end + end + + describe '#get_id_document_verification_attempts' do + it 'GETs id-document-verifications/{id}/attempts' do + expect(api_client_mock).to receive(:invoke_get) + .with('id-document-verifications/idv_x/attempts', 'secret_key').and_return('response') + expect(client.get_id_document_verification_attempts('idv_x')).to eq('response') + end + end + + describe '#get_id_document_verification_attempt' do + it 'GETs id-document-verifications/{id}/attempts/{attempt_id}' do + expect(api_client_mock).to receive(:invoke_get) + .with('id-document-verifications/idv_x/attempts/att_1', 'secret_key').and_return('response') + expect(client.get_id_document_verification_attempt('idv_x', 'att_1')).to eq('response') + end + end + + describe '#get_id_document_verification_pdf_report' do + it 'GETs id-document-verifications/{id}/pdf-report' do + expect(api_client_mock).to receive(:invoke_get) + .with('id-document-verifications/idv_x/pdf-report', 'secret_key').and_return('response') + expect(client.get_id_document_verification_pdf_report('idv_x')).to eq('response') + end + end +end diff --git a/spec/checkout_sdk/identities/id_document_verification/id_document_verification_integration_spec.rb b/spec/checkout_sdk/identities/id_document_verification/id_document_verification_integration_spec.rb new file mode 100644 index 0000000..104179c --- /dev/null +++ b/spec/checkout_sdk/identities/id_document_verification/id_document_verification_integration_spec.rb @@ -0,0 +1,48 @@ +RSpec.describe CheckoutSdk::Identities::IdDocumentVerification do + skip 'Requires sandbox credentials with ID Document Verification entitlement' do + let(:client) { default_sdk.id_document_verification } + + describe '#create_id_document_verification' do + it 'creates an ID document verification' do + request = CheckoutSdk::Identities::IdDocumentVerification::IdDocumentVerificationRequest.new + response = client.create_id_document_verification(request) + expect(response).not_to be_nil + end + end + + describe '#get_id_document_verification' do + it 'retrieves an ID document verification' do + response = client.get_id_document_verification(ENV['CHECKOUT_IDV_DOC_ID']) + expect(response).not_to be_nil + end + end + + describe '#anonymize_id_document_verification' do + it 'anonymizes the verification' do + response = client.anonymize_id_document_verification(ENV['CHECKOUT_IDV_DOC_ID']) + expect(response).not_to be_nil + end + end + + describe '#get_id_document_verification_attempts' do + it 'lists the verification attempts' do + response = client.get_id_document_verification_attempts(ENV['CHECKOUT_IDV_DOC_ID']) + expect(response).not_to be_nil + end + end + + describe '#get_id_document_verification_attempt' do + it 'retrieves a single attempt' do + response = client.get_id_document_verification_attempt(ENV['CHECKOUT_IDV_DOC_ID'], ENV['CHECKOUT_IDV_DOC_ATTEMPT_ID']) + expect(response).not_to be_nil + end + end + + describe '#get_id_document_verification_pdf_report' do + it 'retrieves the verification PDF report' do + response = client.get_id_document_verification_pdf_report(ENV['CHECKOUT_IDV_DOC_ID']) + expect(response).not_to be_nil + end + end + end +end diff --git a/spec/checkout_sdk/identities/identities_attempts_spec.rb b/spec/checkout_sdk/identities/identities_attempts_spec.rb new file mode 100644 index 0000000..bead036 --- /dev/null +++ b/spec/checkout_sdk/identities/identities_attempts_spec.rb @@ -0,0 +1,42 @@ +RSpec.describe 'Identities — create attempt' do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('secret_key') + end + + describe 'FaceAuthenticationClient#create_face_authentication_attempt' do + let(:client) { CheckoutSdk::Identities::FaceAuthentication::FaceAuthenticationClient.new(api_client_mock, configuration_mock) } + + it 'POSTs face-authentications/{id}/attempts' do + req = CheckoutSdk::Identities::FaceAuthentication::FaceAuthenticationAttemptRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('face-authentications/fa_x/attempts', 'secret_key', req).and_return('r') + expect(client.create_face_authentication_attempt('fa_x', req)).to eq('r') + end + end + + describe 'IdentityVerificationClient#create_identity_verification_attempt' do + let(:client) { CheckoutSdk::Identities::IdentityVerification::IdentityVerificationClient.new(api_client_mock, configuration_mock) } + + it 'POSTs identity-verifications/{id}/attempts' do + req = CheckoutSdk::Identities::IdentityVerification::IdentityVerificationAttemptRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('identity-verifications/idv_x/attempts', 'secret_key', req).and_return('r') + expect(client.create_identity_verification_attempt('idv_x', req)).to eq('r') + end + end + + describe 'IdDocumentVerificationClient#create_id_document_verification_attempt' do + let(:client) { CheckoutSdk::Identities::IdDocumentVerification::IdDocumentVerificationClient.new(api_client_mock, configuration_mock) } + + it 'POSTs id-document-verifications/{id}/attempts' do + expect(api_client_mock).to receive(:invoke_post) + .with('id-document-verifications/idv_x/attempts', 'secret_key', nil).and_return('r') + expect(client.create_id_document_verification_attempt('idv_x')).to eq('r') + end + end +end diff --git a/spec/checkout_sdk/identities/identity_verification/identity_verification_client_spec.rb b/spec/checkout_sdk/identities/identity_verification/identity_verification_client_spec.rb new file mode 100644 index 0000000..fcbb1b5 --- /dev/null +++ b/spec/checkout_sdk/identities/identity_verification/identity_verification_client_spec.rb @@ -0,0 +1,83 @@ +RSpec.describe CheckoutSdk::Identities::IdentityVerification do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::Identities::IdentityVerification::IdentityVerificationClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('secret_key') + end + + describe '#create_and_open_idv' do + it 'POSTs typed DTO to create-and-open-idv' do + request = CheckoutSdk::Identities::IdentityVerification::IdentityVerificationRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('create-and-open-idv', 'secret_key', request).and_return('response') + expect(client.create_and_open_idv(request)).to eq('response') + end + + it 'also accepts a raw Hash' do + hash_request = { 'applicant_id' => 'aplt_x', 'user_journey_id' => 'usj_x' } + expect(api_client_mock).to receive(:invoke_post) + .with('create-and-open-idv', 'secret_key', hash_request).and_return('response') + expect(client.create_and_open_idv(hash_request)).to eq('response') + end + end + + describe '#create_identity_verification' do + it 'POSTs typed DTO to identity-verifications' do + request = CheckoutSdk::Identities::IdentityVerification::IdentityVerificationRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('identity-verifications', 'secret_key', request).and_return('response') + expect(client.create_identity_verification(request)).to eq('response') + end + + it 'also accepts a raw Hash' do + hash_request = { 'applicant_id' => 'aplt_x' } + expect(api_client_mock).to receive(:invoke_post) + .with('identity-verifications', 'secret_key', hash_request).and_return('response') + expect(client.create_identity_verification(hash_request)).to eq('response') + end + end + + describe '#get_identity_verification' do + it 'GETs identity-verifications/{id}' do + expect(api_client_mock).to receive(:invoke_get) + .with('identity-verifications/idv_x', 'secret_key').and_return('response') + expect(client.get_identity_verification('idv_x')).to eq('response') + end + end + + describe '#anonymize_identity_verification' do + it 'POSTs identity-verifications/{id}/anonymize' do + expect(api_client_mock).to receive(:invoke_post) + .with('identity-verifications/idv_x/anonymize', 'secret_key').and_return('response') + expect(client.anonymize_identity_verification('idv_x')).to eq('response') + end + end + + describe '#get_identity_verification_attempts' do + it 'GETs identity-verifications/{id}/attempts' do + expect(api_client_mock).to receive(:invoke_get) + .with('identity-verifications/idv_x/attempts', 'secret_key').and_return('response') + expect(client.get_identity_verification_attempts('idv_x')).to eq('response') + end + end + + describe '#get_identity_verification_attempt' do + it 'GETs identity-verifications/{id}/attempts/{attempt_id}' do + expect(api_client_mock).to receive(:invoke_get) + .with('identity-verifications/idv_x/attempts/att_1', 'secret_key').and_return('response') + expect(client.get_identity_verification_attempt('idv_x', 'att_1')).to eq('response') + end + end + + describe '#get_identity_verification_pdf_report' do + it 'GETs identity-verifications/{id}/pdf-report' do + expect(api_client_mock).to receive(:invoke_get) + .with('identity-verifications/idv_x/pdf-report', 'secret_key').and_return('response') + expect(client.get_identity_verification_pdf_report('idv_x')).to eq('response') + end + end +end diff --git a/spec/checkout_sdk/identities/identity_verification/identity_verification_integration_spec.rb b/spec/checkout_sdk/identities/identity_verification/identity_verification_integration_spec.rb new file mode 100644 index 0000000..2284a8f --- /dev/null +++ b/spec/checkout_sdk/identities/identity_verification/identity_verification_integration_spec.rb @@ -0,0 +1,64 @@ +RSpec.describe CheckoutSdk::Identities::IdentityVerification do + skip 'Requires sandbox credentials with Identity Verification entitlement' do + let(:client) { default_sdk.identity_verification } + + describe '#create_identity_verification' do + it 'creates an identity verification' do + request = CheckoutSdk::Identities::IdentityVerification::IdentityVerificationRequest.new + request.applicant_id = ENV['CHECKOUT_APPLICANT_ID'] + request.user_journey_id = ENV['CHECKOUT_USER_JOURNEY_ID'] + request.declared_data = CheckoutSdk::Identities::IdentityVerification::IdvDeclaredData.new + request.declared_data.name = Helpers::DataFactory::NAME + response = client.create_identity_verification(request) + expect(response).not_to be_nil + end + end + + describe '#create_and_open_idv' do + it 'creates and returns a hosted URL' do + request = CheckoutSdk::Identities::IdentityVerification::IdentityVerificationRequest.new + request.applicant_id = ENV['CHECKOUT_APPLICANT_ID'] + request.user_journey_id = ENV['CHECKOUT_USER_JOURNEY_ID'] + request.declared_data = CheckoutSdk::Identities::IdentityVerification::IdvDeclaredData.new + request.declared_data.name = Helpers::DataFactory::NAME + response = client.create_and_open_idv(request) + expect(response).not_to be_nil + end + end + + describe '#get_identity_verification' do + it 'retrieves an identity verification' do + response = client.get_identity_verification(ENV['CHECKOUT_IDENTITY_VERIFICATION_ID']) + expect(response).not_to be_nil + end + end + + describe '#anonymize_identity_verification' do + it 'anonymizes the verification' do + response = client.anonymize_identity_verification(ENV['CHECKOUT_IDENTITY_VERIFICATION_ID']) + expect(response).not_to be_nil + end + end + + describe '#get_identity_verification_attempts' do + it 'lists the verification attempts' do + response = client.get_identity_verification_attempts(ENV['CHECKOUT_IDENTITY_VERIFICATION_ID']) + expect(response).not_to be_nil + end + end + + describe '#get_identity_verification_attempt' do + it 'retrieves a single attempt' do + response = client.get_identity_verification_attempt(ENV['CHECKOUT_IDENTITY_VERIFICATION_ID'], ENV['CHECKOUT_IDENTITY_VERIFICATION_ATTEMPT_ID']) + expect(response).not_to be_nil + end + end + + describe '#get_identity_verification_pdf_report' do + it 'retrieves the verification PDF report' do + response = client.get_identity_verification_pdf_report(ENV['CHECKOUT_IDENTITY_VERIFICATION_ID']) + expect(response).not_to be_nil + end + end + end +end diff --git a/spec/checkout_sdk/issuing/issuing_client_spec.rb b/spec/checkout_sdk/issuing/issuing_client_spec.rb new file mode 100644 index 0000000..22239a9 --- /dev/null +++ b/spec/checkout_sdk/issuing/issuing_client_spec.rb @@ -0,0 +1,55 @@ +RSpec.describe CheckoutSdk::Issuing do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::Issuing::IssuingClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization) + .with(CheckoutSdk::AuthorizationType::SECRET_KEY_OR_OAUTH).and_return('secret_key_or_oauth') + allow(credentials_mock).to receive(:get_authorization) + .with(CheckoutSdk::AuthorizationType::OAUTH).and_return('oauth') + end + + describe '#request_cardholder_access_token' do + it 'POSTs typed DTO to issuing/access/connect/token using OAuth' do + request = CheckoutSdk::Issuing::CardholderAccessTokenRequest.new + request.client_id = 'cid' + request.client_secret = 'csec' + request.cardholder_id = 'crh_abc' + expect(api_client_mock).to receive(:invoke_post) + .with('issuing/access/connect/token', 'oauth', request).and_return('response') + expect(client.request_cardholder_access_token(request)).to eq('response') + end + + it 'also accepts a raw Hash' do + hash_request = { + 'grant_type' => 'client_credentials', + 'client_id' => 'cid', + 'client_secret' => 'csec', + 'cardholder_id' => 'crh_abc' + } + expect(api_client_mock).to receive(:invoke_post) + .with('issuing/access/connect/token', 'oauth', hash_request).and_return('response') + expect(client.request_cardholder_access_token(hash_request)).to eq('response') + end + end + + describe '#simulate_oob_authentication' do + it 'POSTs typed DTO to issuing/simulate/oob/authentication using OAuth' do + request = CheckoutSdk::Issuing::OobAuthenticationRequest.new + request.card_id = 'crd_xyz' + expect(api_client_mock).to receive(:invoke_post) + .with('issuing/simulate/oob/authentication', 'oauth', request).and_return('response') + expect(client.simulate_oob_authentication(request)).to eq('response') + end + + it 'also accepts a raw Hash' do + hash_request = { 'card_id' => 'crd_xyz' } + expect(api_client_mock).to receive(:invoke_post) + .with('issuing/simulate/oob/authentication', 'oauth', hash_request).and_return('response') + expect(client.simulate_oob_authentication(hash_request)).to eq('response') + end + end +end diff --git a/spec/checkout_sdk/issuing/issuing_extras_spec.rb b/spec/checkout_sdk/issuing/issuing_extras_spec.rb new file mode 100644 index 0000000..10167c4 --- /dev/null +++ b/spec/checkout_sdk/issuing/issuing_extras_spec.rb @@ -0,0 +1,190 @@ +RSpec.describe CheckoutSdk::Issuing do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::Issuing::IssuingClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('secret_key') + end + + describe '#update_cardholder' do + it 'PATCHes issuing/cardholders/{id}' do + req = CheckoutSdk::Issuing::UpdateCardholderRequest.new + expect(api_client_mock).to receive(:invoke_patch) + .with('issuing/cardholders/crh_1', 'secret_key', req).and_return('r') + expect(client.update_cardholder('crh_1', req)).to eq('r') + end + end + + describe '#update_card' do + it 'PATCHes issuing/cards/{id}' do + req = CheckoutSdk::Issuing::UpdateCardRequest.new + expect(api_client_mock).to receive(:invoke_patch) + .with('issuing/cards/crd_1', 'secret_key', req).and_return('r') + expect(client.update_card('crd_1', req)).to eq('r') + end + end + + describe '#renew_card' do + it 'POSTs issuing/cards/{id}/renew' do + expect(api_client_mock).to receive(:invoke_post) + .with('issuing/cards/crd_1/renew', 'secret_key', nil).and_return('r') + expect(client.renew_card('crd_1')).to eq('r') + 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 + req.amount = 100 + expect(api_client_mock).to receive(:invoke_post) + .with('issuing/simulate/authorizations/auth_1/refunds', 'secret_key', req).and_return('r') + expect(client.simulate_refund('auth_1', req)).to eq('r') + end + end + + describe 'control groups' do + it 'create POSTs issuing/controls/control-groups' do + req = CheckoutSdk::Issuing::AddControlGroupRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('issuing/controls/control-groups', 'secret_key', req).and_return('r') + expect(client.create_control_group(req)).to eq('r') + end + + it 'list GETs issuing/controls/control-groups' do + expect(api_client_mock).to receive(:invoke_get) + .with('issuing/controls/control-groups', 'secret_key').and_return('r') + expect(client.get_control_groups).to eq('r') + end + + it 'get single GETs issuing/controls/control-groups/{id}' do + expect(api_client_mock).to receive(:invoke_get) + .with('issuing/controls/control-groups/cg_1', 'secret_key').and_return('r') + expect(client.get_control_group('cg_1')).to eq('r') + end + + it 'delete DELETEs issuing/controls/control-groups/{id}' do + expect(api_client_mock).to receive(:invoke_delete) + .with('issuing/controls/control-groups/cg_1', 'secret_key').and_return('r') + expect(client.delete_control_group('cg_1')).to eq('r') + end + end + + describe 'control profiles' do + it 'create POSTs issuing/controls/control-profiles' do + req = CheckoutSdk::Issuing::AddControlProfileRequest.new + req.name = 'p' + expect(api_client_mock).to receive(:invoke_post) + .with('issuing/controls/control-profiles', 'secret_key', req).and_return('r') + expect(client.create_control_profile(req)).to eq('r') + end + + it 'list GETs issuing/controls/control-profiles' do + expect(api_client_mock).to receive(:invoke_get) + .with('issuing/controls/control-profiles', 'secret_key').and_return('r') + expect(client.get_control_profiles).to eq('r') + end + + it 'get single GETs issuing/controls/control-profiles/{id}' do + expect(api_client_mock).to receive(:invoke_get) + .with('issuing/controls/control-profiles/cp_1', 'secret_key').and_return('r') + expect(client.get_control_profile('cp_1')).to eq('r') + end + + it 'update PATCHes issuing/controls/control-profiles/{id}' do + req = CheckoutSdk::Issuing::UpdateControlProfileRequest.new + expect(api_client_mock).to receive(:invoke_patch) + .with('issuing/controls/control-profiles/cp_1', 'secret_key', req).and_return('r') + expect(client.update_control_profile('cp_1', req)).to eq('r') + end + + it 'delete DELETEs issuing/controls/control-profiles/{id}' do + expect(api_client_mock).to receive(:invoke_delete) + .with('issuing/controls/control-profiles/cp_1', 'secret_key').and_return('r') + expect(client.delete_control_profile('cp_1')).to eq('r') + end + + it 'add_target POSTs issuing/controls/control-profiles/{id}/add/{targetId}' do + expect(api_client_mock).to receive(:invoke_post) + .with('issuing/controls/control-profiles/cp_1/add/crd_1', 'secret_key').and_return('r') + expect(client.add_target_to_control_profile('cp_1', 'crd_1')).to eq('r') + end + + it 'remove_target POSTs issuing/controls/control-profiles/{id}/remove/{targetId}' do + expect(api_client_mock).to receive(:invoke_post) + .with('issuing/controls/control-profiles/cp_1/remove/crd_1', 'secret_key').and_return('r') + expect(client.remove_target_from_control_profile('cp_1', 'crd_1')).to eq('r') + end + end + + describe 'issuing disputes' do + it 'POSTs issuing/disputes' do + req = CheckoutSdk::Issuing::CreateDisputeRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('issuing/disputes', 'secret_key', req).and_return('r') + expect(client.create_issuing_dispute(req)).to eq('r') + end + + it 'GETs issuing/disputes/{id}' do + expect(api_client_mock).to receive(:invoke_get) + .with('issuing/disputes/dsp_1', 'secret_key').and_return('r') + expect(client.get_issuing_dispute('dsp_1')).to eq('r') + end + + it 'POSTs issuing/disputes/{id}/cancel' do + expect(api_client_mock).to receive(:invoke_post) + .with('issuing/disputes/dsp_1/cancel', 'secret_key').and_return('r') + expect(client.cancel_issuing_dispute('dsp_1')).to eq('r') + end + + it 'POSTs issuing/disputes/{id}/escalate' do + req = CheckoutSdk::Issuing::EscalateDisputeRequest.new + req.justification = 'reason' + expect(api_client_mock).to receive(:invoke_post) + .with('issuing/disputes/dsp_1/escalate', 'secret_key', req).and_return('r') + expect(client.escalate_issuing_dispute('dsp_1', req)).to eq('r') + end + end + + describe '#get_transactions and #get_transaction' do + it 'GETs issuing/transactions with query' do + query = { 'limit' => 10 } + expect(api_client_mock).to receive(:invoke_get) + .with('issuing/transactions', 'secret_key', query).and_return('r') + expect(client.get_transactions(query)).to eq('r') + end + + it 'GETs issuing/transactions/{id}' do + expect(api_client_mock).to receive(:invoke_get) + .with('issuing/transactions/txn_1', 'secret_key').and_return('r') + expect(client.get_transaction('txn_1')).to eq('r') + end + end + + describe '#get_digital_card' do + it 'GETs issuing/digital-cards/{id}' do + expect(api_client_mock).to receive(:invoke_get) + .with('issuing/digital-cards/dc_1', 'secret_key').and_return('r') + expect(client.get_digital_card('dc_1')).to eq('r') + end + end +end diff --git a/spec/checkout_sdk/issuing/issuing_oauth_integration_spec.rb b/spec/checkout_sdk/issuing/issuing_oauth_integration_spec.rb new file mode 100644 index 0000000..a2930b5 --- /dev/null +++ b/spec/checkout_sdk/issuing/issuing_oauth_integration_spec.rb @@ -0,0 +1,30 @@ +RSpec.describe CheckoutSdk::Issuing do + skip 'Requires sandbox OAuth credentials with the Issuing scope and a provisioned cardholder + card' do + let(:client) { oauth_sdk.issuing } + + describe '#request_cardholder_access_token' do + it 'returns a cardholder access token' do + request = CheckoutSdk::Issuing::CardholderAccessTokenRequest.new + request.client_id = ENV['CHECKOUT_OAUTH_CLIENT_ID'] + request.client_secret = ENV['CHECKOUT_OAUTH_CLIENT_SECRET'] + request.cardholder_id = ENV['CHECKOUT_CARDHOLDER_ID'] + request.single_use = true + response = client.request_cardholder_access_token(request) + expect(response).not_to be_nil + end + end + + describe '#simulate_oob_authentication' do + it 'simulates an OOB authentication' do + request = CheckoutSdk::Issuing::OobAuthenticationRequest.new + request.card_id = ENV['CHECKOUT_ISSUING_CARD_ID'] + request.transaction_details = CheckoutSdk::Issuing::OobSimulateTransactionDetails.new + request.transaction_details.merchant_name = 'Acme Ltd' + request.transaction_details.purchase_amount = 100 + request.transaction_details.purchase_currency = 'GBP' + response = client.simulate_oob_authentication(request) + expect(response).not_to be_nil + end + end + end +end diff --git a/spec/checkout_sdk/network_tokens/network_tokens_client_spec.rb b/spec/checkout_sdk/network_tokens/network_tokens_client_spec.rb new file mode 100644 index 0000000..973bbf4 --- /dev/null +++ b/spec/checkout_sdk/network_tokens/network_tokens_client_spec.rb @@ -0,0 +1,68 @@ +RSpec.describe CheckoutSdk::NetworkTokens do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::NetworkTokens::NetworkTokensClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('secret_key') + end + + describe '#provision_network_token' do + it 'POSTs typed DTO to network-tokens' do + request = CheckoutSdk::NetworkTokens::ProvisionNetworkTokenRequest.new + request.source = CheckoutSdk::NetworkTokens::NetworkTokenSourceId.new + request.source.id = 'src_xxx' + expect(api_client_mock).to receive(:invoke_post) + .with('network-tokens', 'secret_key', request) + .and_return('response') + expect(client.provision_network_token(request)).to eq('response') + end + + it 'also accepts a raw Hash' do + hash_request = { 'source' => { 'type' => 'id', 'id' => 'src_xxx' } } + expect(api_client_mock).to receive(:invoke_post) + .with('network-tokens', 'secret_key', hash_request) + .and_return('response') + expect(client.provision_network_token(hash_request)).to eq('response') + end + end + + describe '#get_network_token' do + it 'GETs network-tokens/{id}' do + expect(api_client_mock).to receive(:invoke_get) + .with('network-tokens/nt_123', 'secret_key') + .and_return('response') + expect(client.get_network_token('nt_123')).to eq('response') + end + end + + describe '#request_cryptograms' do + it 'POSTs typed DTO to network-tokens/{id}/cryptograms' do + request = CheckoutSdk::NetworkTokens::NetworkTokenCryptogramRequest.new + request.transaction_type = 'ecom' + expect(api_client_mock).to receive(:invoke_post) + .with('network-tokens/nt_123/cryptograms', 'secret_key', request) + .and_return('response') + expect(client.request_cryptograms('nt_123', request)).to eq('response') + end + + it 'also accepts a raw Hash' do + hash_request = { 'transaction_type' => 'ecom' } + expect(api_client_mock).to receive(:invoke_post) + .with('network-tokens/nt_123/cryptograms', 'secret_key', hash_request) + .and_return('response') + expect(client.request_cryptograms('nt_123', hash_request)).to eq('response') + end + end + + describe '#delete_network_token' do + it 'PATCHes network-tokens/{id}/delete' do + expect(api_client_mock).to receive(:invoke_patch) + .with('network-tokens/nt_123/delete', 'secret_key') + .and_return('response') + expect(client.delete_network_token('nt_123')).to eq('response') + end + end +end diff --git a/spec/checkout_sdk/network_tokens/network_tokens_integration_spec.rb b/spec/checkout_sdk/network_tokens/network_tokens_integration_spec.rb new file mode 100644 index 0000000..ff3113b --- /dev/null +++ b/spec/checkout_sdk/network_tokens/network_tokens_integration_spec.rb @@ -0,0 +1,42 @@ +RSpec.describe CheckoutSdk::NetworkTokens do + skip 'Requires a sandbox account configured for Network Tokens' do + let(:client) { default_sdk.network_tokens } + + describe '#provision_network_token' do + it 'provisions a network token from raw card details' do + request = CheckoutSdk::NetworkTokens::ProvisionNetworkTokenRequest.new + source = CheckoutSdk::NetworkTokens::NetworkTokenSourceCard.new + source.number = Helpers::DataFactory::CARD_NUMBER + source.cvv = Helpers::DataFactory::CVV + source.expiry_month = Helpers::DataFactory::EXPIRY_MONTH.to_s + source.expiry_year = Helpers::DataFactory::EXPIRY_YEAR.to_s + request.source = source + response = client.provision_network_token(request) + expect(response).not_to be_nil + end + end + + describe '#get_network_token' do + it 'retrieves a network token' do + response = client.get_network_token(ENV['CHECKOUT_NETWORK_TOKEN_ID']) + expect(response).not_to be_nil + end + end + + describe '#request_cryptograms' do + it 'returns a fresh cryptogram for the network token' do + request = CheckoutSdk::NetworkTokens::NetworkTokenCryptogramRequest.new + request.transaction_type = 'ecom' + response = client.request_cryptograms(ENV['CHECKOUT_NETWORK_TOKEN_ID'], request) + expect(response).not_to be_nil + end + end + + describe '#delete_network_token' do + it 'soft-deletes a network token' do + response = client.delete_network_token(ENV['CHECKOUT_NETWORK_TOKEN_ID']) + expect(response).not_to be_nil + end + end + end +end diff --git a/spec/checkout_sdk/onboarding_simulator/onboarding_simulator_client_spec.rb b/spec/checkout_sdk/onboarding_simulator/onboarding_simulator_client_spec.rb new file mode 100644 index 0000000..2480605 --- /dev/null +++ b/spec/checkout_sdk/onboarding_simulator/onboarding_simulator_client_spec.rb @@ -0,0 +1,74 @@ +RSpec.describe CheckoutSdk::OnboardingSimulator do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::OnboardingSimulator::OnboardingSimulatorClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('oauth') + end + + describe '#set_requirements_due' do + it 'POSTs typed DTO to simulate/entities/{id}/requirements-due' do + request = CheckoutSdk::OnboardingSimulator::SimulatorSetRequirementsDueRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('simulate/entities/ent_123/requirements-due', 'oauth', request) + .and_return('response') + expect(client.set_requirements_due('ent_123', request)).to eq('response') + end + + it 'also accepts a raw Hash' do + hash_request = { 'field_names' => ['individual.date_of_birth'] } + expect(api_client_mock).to receive(:invoke_post) + .with('simulate/entities/ent_123/requirements-due', 'oauth', hash_request) + .and_return('response') + expect(client.set_requirements_due('ent_123', hash_request)).to eq('response') + end + end + + describe '#run_scenario' do + it 'POSTs to simulate/entities/{id}/scenarios/{scenario_id}' do + expect(api_client_mock).to receive(:invoke_post) + .with('simulate/entities/ent_123/scenarios/scn_42', 'oauth') + .and_return('response') + expect(client.run_scenario('ent_123', 'scn_42')).to eq('response') + end + end + + describe '#set_entity_status' do + it 'POSTs typed DTO to simulate/entities/{id}/status' do + request = CheckoutSdk::OnboardingSimulator::SimulatorSetStatusRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('simulate/entities/ent_123/status', 'oauth', request) + .and_return('response') + expect(client.set_entity_status('ent_123', request)).to eq('response') + end + + it 'also accepts a raw Hash' do + hash_request = { 'status' => 'active' } + expect(api_client_mock).to receive(:invoke_post) + .with('simulate/entities/ent_123/status', 'oauth', hash_request) + .and_return('response') + expect(client.set_entity_status('ent_123', hash_request)).to eq('response') + end + end + + describe '#list_available_requirements' do + it 'GETs simulate/requirements-due' do + expect(api_client_mock).to receive(:invoke_get) + .with('simulate/requirements-due', 'oauth') + .and_return('response') + expect(client.list_available_requirements).to eq('response') + end + end + + describe '#list_scenarios' do + it 'GETs simulate/scenarios' do + expect(api_client_mock).to receive(:invoke_get) + .with('simulate/scenarios', 'oauth') + .and_return('response') + expect(client.list_scenarios).to eq('response') + end + end +end diff --git a/spec/checkout_sdk/onboarding_simulator/onboarding_simulator_integration_spec.rb b/spec/checkout_sdk/onboarding_simulator/onboarding_simulator_integration_spec.rb new file mode 100644 index 0000000..d7bc62d --- /dev/null +++ b/spec/checkout_sdk/onboarding_simulator/onboarding_simulator_integration_spec.rb @@ -0,0 +1,44 @@ +RSpec.describe CheckoutSdk::OnboardingSimulator do + skip 'Requires sandbox OAuth credentials with the `accounts` scope and a seeded entity' do + let(:client) { oauth_sdk.onboarding_simulator } + + describe '#list_available_requirements' do + it 'returns the catalogue of requirement fields' do + response = client.list_available_requirements + expect(response).not_to be_nil + end + end + + describe '#list_scenarios' do + it 'returns the catalogue of scenarios' do + response = client.list_scenarios + expect(response).not_to be_nil + end + end + + describe '#run_scenario' do + it 'executes a scenario against an entity' do + response = client.run_scenario(ENV['CHECKOUT_ONBOARDING_ENTITY_ID'], 'scn_pass') + expect(response).not_to be_nil + end + end + + describe '#set_requirements_due' do + it 'marks requirement fields as due' do + request = CheckoutSdk::OnboardingSimulator::SimulatorSetRequirementsDueRequest.new + request.field_names = ['individual.date_of_birth'] + response = client.set_requirements_due(ENV['CHECKOUT_ONBOARDING_ENTITY_ID'], request) + expect(response).not_to be_nil + end + end + + describe '#set_entity_status' do + it 'forces an entity to the requested status' do + request = CheckoutSdk::OnboardingSimulator::SimulatorSetStatusRequest.new + request.status = 'active' + response = client.set_entity_status(ENV['CHECKOUT_ONBOARDING_ENTITY_ID'], request) + expect(response).not_to be_nil + end + end + end +end diff --git a/spec/checkout_sdk/payment_methods/payment_methods_client_spec.rb b/spec/checkout_sdk/payment_methods/payment_methods_client_spec.rb new file mode 100644 index 0000000..026b486 --- /dev/null +++ b/spec/checkout_sdk/payment_methods/payment_methods_client_spec.rb @@ -0,0 +1,30 @@ +RSpec.describe CheckoutSdk::PaymentMethods do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::PaymentMethods::PaymentMethodsClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('secret_key') + end + + describe '#get_payment_methods' do + it 'GETs payment-methods with typed query' do + query = CheckoutSdk::PaymentMethods::PaymentMethodsQuery.new + query.processing_channel_id = 'pc_xxx' + expect(api_client_mock).to receive(:invoke_get) + .with('payment-methods', 'secret_key', query) + .and_return('response') + expect(client.get_payment_methods(query)).to eq('response') + end + + it 'also accepts a raw Hash query' do + hash_query = { 'processing_channel_id' => 'pc_xxx' } + expect(api_client_mock).to receive(:invoke_get) + .with('payment-methods', 'secret_key', hash_query) + .and_return('response') + expect(client.get_payment_methods(hash_query)).to eq('response') + end + end +end diff --git a/spec/checkout_sdk/payment_methods/payment_methods_integration_spec.rb b/spec/checkout_sdk/payment_methods/payment_methods_integration_spec.rb new file mode 100644 index 0000000..981bfdf --- /dev/null +++ b/spec/checkout_sdk/payment_methods/payment_methods_integration_spec.rb @@ -0,0 +1,14 @@ +RSpec.describe CheckoutSdk::PaymentMethods do + skip 'Requires a sandbox processing channel configured with payment methods' do + let(:client) { default_sdk.payment_methods } + + describe '#get_payment_methods' do + it 'returns the payment methods configured for the channel' do + query = CheckoutSdk::PaymentMethods::PaymentMethodsQuery.new + query.processing_channel_id = ENV['CHECKOUT_PROCESSING_CHANNEL_ID'] + response = client.get_payment_methods(query) + expect(response).not_to be_nil + end + end + end +end diff --git a/spec/checkout_sdk/payments/apple_pay/apple_pay_client_spec.rb b/spec/checkout_sdk/payments/apple_pay/apple_pay_client_spec.rb new file mode 100644 index 0000000..da66138 --- /dev/null +++ b/spec/checkout_sdk/payments/apple_pay/apple_pay_client_spec.rb @@ -0,0 +1,48 @@ +RSpec.describe CheckoutSdk::Payments do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::Payments::ApplePayClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization) + .with(CheckoutSdk::AuthorizationType::PUBLIC_KEY).and_return('public_key') + allow(credentials_mock).to receive(:get_authorization) + .with(CheckoutSdk::AuthorizationType::OAUTH).and_return('oauth') + end + + describe '#upload_certificate' do + it 'POSTs typed DTO to applepay/certificates' do + req = CheckoutSdk::Payments::ApplePayCertificateRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('applepay/certificates', 'public_key', req).and_return('r') + expect(client.upload_certificate(req)).to eq('r') + end + + it 'also accepts a raw Hash' do + h = { 'content' => '...' } + expect(api_client_mock).to receive(:invoke_post) + .with('applepay/certificates', 'public_key', h).and_return('r') + expect(client.upload_certificate(h)).to eq('r') + end + end + + describe '#enroll_domain' do + it 'POSTs typed DTO to applepay/enrollments using OAuth' do + req = CheckoutSdk::Payments::ApplePayEnrollmentRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('applepay/enrollments', 'oauth', req).and_return('r') + expect(client.enroll_domain(req)).to eq('r') + end + end + + describe '#generate_signing_request' do + it 'POSTs typed DTO to applepay/signing-requests' do + req = CheckoutSdk::Payments::ApplePaySigningRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('applepay/signing-requests', 'public_key', req).and_return('r') + expect(client.generate_signing_request(req)).to eq('r') + end + end +end diff --git a/spec/checkout_sdk/payments/google_pay/google_pay_client_spec.rb b/spec/checkout_sdk/payments/google_pay/google_pay_client_spec.rb new file mode 100644 index 0000000..181971f --- /dev/null +++ b/spec/checkout_sdk/payments/google_pay/google_pay_client_spec.rb @@ -0,0 +1,52 @@ +RSpec.describe CheckoutSdk::Payments do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::Payments::GooglePayClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('oauth') + end + + describe '#enroll_entity' do + it 'POSTs typed DTO to googlepay/enrollments' do + req = CheckoutSdk::Payments::GooglePayEnrollmentRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('googlepay/enrollments', 'oauth', req).and_return('r') + expect(client.enroll_entity(req)).to eq('r') + end + + it 'also accepts a raw Hash' do + h = { 'entity_id' => 'ent_1' } + expect(api_client_mock).to receive(:invoke_post) + .with('googlepay/enrollments', 'oauth', h).and_return('r') + expect(client.enroll_entity(h)).to eq('r') + end + end + + describe '#register_domain' do + it 'POSTs typed DTO to googlepay/enrollments/{id}/domain' do + req = CheckoutSdk::Payments::GooglePayDomainRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('googlepay/enrollments/ent_1/domain', 'oauth', req).and_return('r') + expect(client.register_domain('ent_1', req)).to eq('r') + end + end + + describe '#get_registered_domains' do + it 'GETs googlepay/enrollments/{id}/domains' do + expect(api_client_mock).to receive(:invoke_get) + .with('googlepay/enrollments/ent_1/domains', 'oauth').and_return('r') + expect(client.get_registered_domains('ent_1')).to eq('r') + end + end + + describe '#get_enrollment_state' do + it 'GETs googlepay/enrollments/{id}/state' do + expect(api_client_mock).to receive(:invoke_get) + .with('googlepay/enrollments/ent_1/state', 'oauth').and_return('r') + expect(client.get_enrollment_state('ent_1')).to eq('r') + end + end +end diff --git a/spec/checkout_sdk/payments/payments_search_and_cancellation_spec.rb b/spec/checkout_sdk/payments/payments_search_and_cancellation_spec.rb new file mode 100644 index 0000000..591111e --- /dev/null +++ b/spec/checkout_sdk/payments/payments_search_and_cancellation_spec.rb @@ -0,0 +1,45 @@ +RSpec.describe CheckoutSdk::Payments do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::Payments::PaymentsClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('secret_key') + end + + describe '#search_payments' do + it 'POSTs typed DTO to payments/search' do + req = CheckoutSdk::Payments::PaymentsSearchRequest.new + req.query = "id:'pay_x'" + expect(api_client_mock).to receive(:invoke_post) + .with('payments/search', 'secret_key', req).and_return('r') + expect(client.search_payments(req)).to eq('r') + end + + it 'also accepts a raw Hash' do + h = { 'query' => 'reference:ORD-1' } + expect(api_client_mock).to receive(:invoke_post) + .with('payments/search', 'secret_key', h).and_return('r') + expect(client.search_payments(h)).to eq('r') + end + end + + describe '#cancel_payment' do + it 'POSTs typed DTO to payments/{id}/cancellations' do + req = CheckoutSdk::Payments::CancellationRequest.new + req.reference = 'ORD-5023' + expect(api_client_mock).to receive(:invoke_post) + .with('payments/pay_1/cancellations', 'secret_key', req, nil).and_return('r') + expect(client.cancel_payment('pay_1', req)).to eq('r') + end + + it 'passes through an idempotency key' do + req = CheckoutSdk::Payments::CancellationRequest.new + expect(api_client_mock).to receive(:invoke_post) + .with('payments/pay_1/cancellations', 'secret_key', req, 'idem-1').and_return('r') + expect(client.cancel_payment('pay_1', req, 'idem-1')).to eq('r') + end + end +end diff --git a/spec/checkout_sdk/payments/sessions/payment_sessions_complete_spec.rb b/spec/checkout_sdk/payments/sessions/payment_sessions_complete_spec.rb new file mode 100644 index 0000000..4f8b835 --- /dev/null +++ b/spec/checkout_sdk/payments/sessions/payment_sessions_complete_spec.rb @@ -0,0 +1,20 @@ +RSpec.describe CheckoutSdk::Payments do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::Payments::PaymentSessionsClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('secret_key') + end + + describe '#create_and_complete_payment_sessions' do + it 'POSTs to payment-sessions/complete' do + req = double('request') + expect(api_client_mock).to receive(:invoke_post) + .with('payment-sessions/complete', 'secret_key', req).and_return('r') + expect(client.create_and_complete_payment_sessions(req)).to eq('r') + end + end +end diff --git a/spec/checkout_sdk/payments/setups/payment_setups_client_spec.rb b/spec/checkout_sdk/payments/setups/payment_setups_client_spec.rb new file mode 100644 index 0000000..2a25b7e --- /dev/null +++ b/spec/checkout_sdk/payments/setups/payment_setups_client_spec.rb @@ -0,0 +1,59 @@ +RSpec.describe CheckoutSdk::Payments do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::Payments::PaymentSetupsClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('secret_key') + end + + describe '#create_payment_setup' do + it 'POSTs an opaque request object to payments/setups' do + request = double('request') + expect(api_client_mock).to receive(:invoke_post) + .with('payments/setups', 'secret_key', request).and_return('response') + expect(client.create_payment_setup(request)).to eq('response') + end + + it 'also accepts a raw Hash' do + hash_request = { 'amount' => 1000, 'currency' => 'GBP' } + expect(api_client_mock).to receive(:invoke_post) + .with('payments/setups', 'secret_key', hash_request).and_return('response') + expect(client.create_payment_setup(hash_request)).to eq('response') + end + end + + describe '#update_payment_setup' do + it 'PUTs payments/setups/{id}' do + request = double('request') + expect(api_client_mock).to receive(:invoke_put) + .with('payments/setups/ps_1', 'secret_key', request).and_return('response') + expect(client.update_payment_setup('ps_1', request)).to eq('response') + end + + it 'also accepts a raw Hash' do + hash_request = { 'amount' => 2000 } + expect(api_client_mock).to receive(:invoke_put) + .with('payments/setups/ps_1', 'secret_key', hash_request).and_return('response') + expect(client.update_payment_setup('ps_1', hash_request)).to eq('response') + end + end + + describe '#get_payment_setup' do + it 'GETs payments/setups/{id}' do + expect(api_client_mock).to receive(:invoke_get) + .with('payments/setups/ps_1', 'secret_key').and_return('response') + expect(client.get_payment_setup('ps_1')).to eq('response') + end + end + + describe '#confirm_payment_setup' do + it 'POSTs payments/setups/{id}/confirm/{payment_method_option_id}' do + expect(api_client_mock).to receive(:invoke_post) + .with('payments/setups/ps_1/confirm/pmo_1', 'secret_key').and_return('response') + expect(client.confirm_payment_setup('ps_1', 'pmo_1')).to eq('response') + end + end +end diff --git a/spec/checkout_sdk/standalone_account_updater/standalone_account_updater_client_spec.rb b/spec/checkout_sdk/standalone_account_updater/standalone_account_updater_client_spec.rb new file mode 100644 index 0000000..68a7e5c --- /dev/null +++ b/spec/checkout_sdk/standalone_account_updater/standalone_account_updater_client_spec.rb @@ -0,0 +1,34 @@ +RSpec.describe CheckoutSdk::StandaloneAccountUpdater do + let(:credentials_mock) { double('credentials') } + let(:api_client_mock) { double('api_client') } + let(:configuration_mock) { double('configuration') } + let(:client) { CheckoutSdk::StandaloneAccountUpdater::StandaloneAccountUpdaterClient.new(api_client_mock, configuration_mock) } + + before do + allow(configuration_mock).to receive(:credentials).and_return(credentials_mock) + allow(credentials_mock).to receive(:get_authorization).and_return('oauth') + end + + describe '#update_card' do + it 'POSTs typed DTO to account-updater/cards' do + request = CheckoutSdk::StandaloneAccountUpdater::AccountUpdaterRequest.new + request.source_options = CheckoutSdk::StandaloneAccountUpdater::AccountUpdaterSourceOptions.new + expect(api_client_mock).to receive(:invoke_post) + .with('account-updater/cards', 'oauth', request) + .and_return('response') + expect(client.update_card(request)).to eq('response') + end + + it 'also accepts a raw Hash' do + hash_request = { + 'source_options' => { + 'card' => { 'number' => '4242424242424242', 'expiry_month' => 12, 'expiry_year' => 2030 } + } + } + expect(api_client_mock).to receive(:invoke_post) + .with('account-updater/cards', 'oauth', hash_request) + .and_return('response') + expect(client.update_card(hash_request)).to eq('response') + end + end +end diff --git a/spec/checkout_sdk/standalone_account_updater/standalone_account_updater_integration_spec.rb b/spec/checkout_sdk/standalone_account_updater/standalone_account_updater_integration_spec.rb new file mode 100644 index 0000000..67ab179 --- /dev/null +++ b/spec/checkout_sdk/standalone_account_updater/standalone_account_updater_integration_spec.rb @@ -0,0 +1,19 @@ +RSpec.describe CheckoutSdk::StandaloneAccountUpdater do + skip 'Requires sandbox OAuth credentials with the `vault:real-time-account-updater` scope' do + let(:client) { oauth_sdk.standalone_account_updater } + + describe '#update_card' do + it 'updates a card via account-updater/cards' do + request = CheckoutSdk::StandaloneAccountUpdater::AccountUpdaterRequest.new + request.source_options = CheckoutSdk::StandaloneAccountUpdater::AccountUpdaterSourceOptions.new + request.source_options.card = CheckoutSdk::StandaloneAccountUpdater::AccountUpdaterCard.new + request.source_options.card.number = Helpers::DataFactory::CARD_NUMBER + request.source_options.card.expiry_month = Helpers::DataFactory::EXPIRY_MONTH + request.source_options.card.expiry_year = Helpers::DataFactory::EXPIRY_YEAR + + response = client.update_card(request) + expect(response).not_to be_nil + end + end + end +end