diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 01ee55f..1ee97c4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,4 +1,4 @@ -name: Ruby +name: CI on: push: @@ -25,7 +25,7 @@ jobs: with: ruby-version: ${{ matrix.ruby }} bundler-cache: true - - name: Cops + - name: Rubocop run: bundle exec rubocop - - name: Specs + - name: Rspec run: bundle exec rspec diff --git a/lib/yookassa/entity/authorization_details.rb b/lib/yookassa/entity/authorization_details.rb new file mode 100644 index 0000000..59d23d0 --- /dev/null +++ b/lib/yookassa/entity/authorization_details.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require_relative "./types" + +module Yookassa + module Entity + class AuthorizationDetails < Dry::Struct + # rrn [string, optional] + # Retrieval Reference Number is a unique identifier of a transaction in the issuer's system. Used for payments via bank card. + attribute? :rrn, Types::String + + # auth_code [string, optional] + # Bank card's authorization code. Provided by the issuer to confirm authorization. + attribute? :auth_code, Types::String + + # three_d_secure [object, optional] + # Information about user’s 3‑D Secure authentication for confirming the payment. + attribute? :three_d_secure, Types::Hash.schema( + + # applied [boolean, required] + # Information on whether the 3-D Secure authentication form is displayed to the user for confirming the payment or not. + # true: YooMoney displayed the form to the user, so that they could complete 3-D Secure authentication; + # false: payment was processed without 3-D Secure authentication. + applied: Types::Bool + ).with_key_transform(&:to_sym) + end + end +end diff --git a/lib/yookassa/entity/cancellation_details.rb b/lib/yookassa/entity/cancellation_details.rb new file mode 100644 index 0000000..55da223 --- /dev/null +++ b/lib/yookassa/entity/cancellation_details.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require_relative "./types" + +module Yookassa + module Entity + class CancellationDetails < Dry::Struct + # party [string, required] + # The participant of the payment process that made the decision to cancel the payment. + # Possible values are yoo_money, payment_network, and merchant. More about initiators of payment cancelation + attribute :party, Types::String.enum("yoo_money", "payment_network", "merchant") + + # reason [string, required] + # Reason behind the cancelation. Possible values https://yookassa.ru/en/developers/payments/declined-payments#cancellation-details-reason + attribute :reason, Types::String + end + end +end diff --git a/lib/yookassa/entity/card.rb b/lib/yookassa/entity/card.rb index 599220e..20904e4 100644 --- a/lib/yookassa/entity/card.rb +++ b/lib/yookassa/entity/card.rb @@ -5,12 +5,41 @@ require_relative "./types" module Yookassa module Entity class Card < Dry::Struct - attribute :first6, Types::Integer - attribute :last4, Types::Integer - attribute :expiry_month, Types::Integer - attribute :expiry_year, Types::Integer - attribute :card_type, Types::String - attribute :source, Types::String + # first6 [string, optional] + # First 6 digits of the card’s number (BIN). For payments with bank cards saved in YooMoney + # and other services, the specified BIN might not correspond with the last4, expiry_year, expiry_month values. + # For payments with bank cards saved in Apple Pay or Google Pay, the parameter contains Device Account Number. + attribute? :first6, Types::String + + # last4 [string, required] + # Last 4 digits of the card's number. + attribute :last4, Types::String + + # expiry_month [string, required] + # Expiration date, month, MM. + attribute :expiry_month, Types::Coercible::Integer + + # expiry_year [string, required] + # Expiration date, year, YYYY. + attribute :expiry_year, Types::Coercible::Integer + + # card_type [string, required] + # Type of bank card. Possible values: MasterCard (for Mastercard and Maestro cards), Visa (for Visa and Visa Electron cards), + # Mir, UnionPay, JCB, AmericanExpress, DinersClub, and Unknown. + attribute :card_type, Types::String.enum("MasterCard", "Visa", "Mir", "UnionPay", "JCB", "AmericanExpress", "DinersClub", "Unknown") + + # issuer_country [string, optional] + # Code of the country where the bank card was issued according to ISO-3166 alpha-2. Example: RU. + attribute? :issuer_country, Types::String + + # issuer_name [string, optional] + # Name of the issuing bank. + attribute? :issuer_name, Types::String + + # source [string, optional] + # Source of bank card details. Possible values: apple_pay, google_pay. + # For payments where the user selects a card saved in Apple Pay or Google Pay. + attribute? :source, Types::String.enum("apple_pay", "google_pay") end end end diff --git a/lib/yookassa/entity/payment.rb b/lib/yookassa/entity/payment.rb index 1e4667b..3eee770 100644 --- a/lib/yookassa/entity/payment.rb +++ b/lib/yookassa/entity/payment.rb @@ -2,25 +2,115 @@ require_relative "./types" require_relative "./amount" -require_relative "./payment_method" +require_relative "./payment_methods" require_relative "./confirmation" +require_relative "./recipient" +require_relative "./cancellation_details" +require_relative "./authorization_details" +require_relative "./transfer" module Yookassa module Entity class Payment < Dry::Struct + # id [string, required] + # Payment ID in YooMoney. attribute :id, Types::String + + # status [string, required] + # Payment status. Possible values: pending, waiting_for_capture, succeeded, and canceled. + # More about the life cycle of a payment https://yookassa.ru/en/developers/api#:~:text=life%20cycle%20of%20a%20payment%C2%A0 attribute :status, Types::String.enum("pending", "waiting_for_capture", "succeeded", "canceled") - attribute :paid, Types::Bool + + # amount [object, required] + # Payment amount. Sometimes YooMoney's partners charge additional commission from the users that is not included in this amount. attribute :amount, Entity::Amount + + # income_amount [object, optional] + # Amount of payment to be received by the store: the amount value minus the YooMoney commission. + # If you're a partner using an OAuth token for request authentication, make a request to the store for a right + # to get information about commissions on payments. attribute? :income_amount, Entity::Amount - attribute :created_at, Types::String - attribute? :captured_at, Types::String - attribute? :expires_at, Types::String - attribute? :description, Types::String - attribute :metadata, Types::Hash - attribute :payment_method, Entity::PaymentMethod - attribute :confirmation, Entity::Confirmation + + # description [string, optional] + # Description of the transaction (maximum 128 characters) displayed in your YooMoney Merchant Profile, + # and shown to the user during checkout. For example, "Payment for order No. 72 for user@yoomoney.ru". + attribute? :description, Types::String.constrained(max_size: 128) + + # recipient [object, required] + # Payment recipient. + attribute :recipient, Entity::Recipient + + # payment_method [object, optional] + # Payment method used for this payment. + attribute? :payment_method, Entity::PaymentMethods + + # captured_at [datetime, optional] + # Time of payment capture, based on UTC and specified in the ISO 8601 format. "2018-07-18T10:51:18.139Z" + attribute? :captured_at, Types::JSON::DateTime + + # created_at [datetime, required] + # Time of order creation, based on UTC and specified in the ISO 8601 format. Example: 2017-11-03T11:52:31.827Z + attribute :created_at, Types::JSON::DateTime + + # expires_at [string, optional] + # The period during which you can cancel or capture a payment for free. The payment with the waiting_for_capture status + # will be automatically canceled at the specified time. Based on UTC and specified in the ISO 8601 format. + attribute? :expires_at, Types::JSON::DateTime + + # confirmation [object, optional] + # Selected payment confirmation scenario. For payments requiring confirmation from the user. + # More about confirmation scenarios https://yookassa.ru/en/developers/api#:~:text=confirmation,from%20the%20user.%20More%20about%20confirmation%20scenarios%C2%A0 + attribute? :confirmation, Entity::Confirmation + + # test [boolean, required] + # The attribute of a test transaction. attribute :test, Types::Bool + + # refunded_amount [object, optional] + # The amount refunded to the user. Specified if the payment has successful refunds. + attribute? :refunded_amount, Entity::Amount + + # paid [boolean, required] + # The attribute of a paid order. + attribute :paid, Types::Bool + + # refundable [boolean, required] + # Availability of the option to make a refund via API. + attribute :refundable, Types::Bool + + # receipt_registration [string, optional] + # Delivery status of receipt data to online sales register (pending, succeeded, or canceled). For those who use the solution for 54-FZ . + attribute? :receipt_registration, Types::String.enum("pending", "succeeded", "canceled") + + # metadata [object, optional] + # Any additional data you might require for processing payments (for example, order number), specified as a “key-value” pair + # and returned in response from YooMoney. + # Limitations: + # - no more than 16 keys, + # - no more than 32 characters in the key’s title, + # - no more than 512 characters in the key’s value, + # - data type is a string in the UTF-8 format. + attribute? :metadata, Types::Hash + + # cancellation_details [object, optional] + # Commentary to the canceled status: who and why canceled the payment. + # More about canceled payments https://yookassa.ru/en/developers/api#:~:text=cancellation_details,about%20canceled%20payments%C2%A0 + attribute? :cancellation_details, Entity::CancellationDetails + + # authorization_details [object, optional] + # Payment authorization details. + attribute? :authorization_details, Entity::AuthorizationDetails + + # transfers [array, optional] + # Information about money distribution: the amounts of transfers and the stores to be transferred to. + # Specified if you use the YooMoney solution for marketplaces https://yookassa.ru/en/developers/special-solutions/checkout-for-platforms/basics + attribute? :transfers, Types::Array.of(Entity::Transfer) + + # merchant_customer_id [string, optional] + # The identifier of the customer in your system, such as email address or phone number. No more than 200 characters. + # Specified if you want to save a bank card and offer it for a recurring payment + # in the YooMoney payment widget https://yookassa.ru/en/developers/payment-forms/widget/basics. + attribute? :merchant_customer_id, Types::String end end end diff --git a/lib/yookassa/entity/payment_method.rb b/lib/yookassa/entity/payment_method.rb deleted file mode 100644 index 47358cc..0000000 --- a/lib/yookassa/entity/payment_method.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -require_relative "./types" -require_relative "./card" - -module Yookassa - module Entity - class PaymentMethod < Dry::Struct - attribute :type, Types::String - attribute :id, Types::String - attribute :saved, Types::Bool - attribute? :card, Entity::Card - attribute? :title, Types::String - end - end -end diff --git a/lib/yookassa/entity/payment_methods.rb b/lib/yookassa/entity/payment_methods.rb new file mode 100644 index 0000000..8e31396 --- /dev/null +++ b/lib/yookassa/entity/payment_methods.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +require_relative "./types" +require_relative "./card" + +module Yookassa + module Entity + module PaymentMethod + class Base < Dry::Struct + # id [string, required] + # Payment method ID. + attribute :id, Types::String + + # saved [boolean, required] + # Saving payment methods allows conducting automatic recurring payments . + attribute :saved, Types::Bool + + # title [string, optional] + # Payment method name. + attribute? :title, Types::String + end + + class BankCard < Base + attribute :type, Types.Value("bank_card") + + # login [string, optional] + # User's login in Alfa-Click (linked phone number or the additional login). + attribute? :card, Entity::Card + end + + class Alfabank < Base + attribute :type, Types.Value("alfabank") + + # login [string, optional] + # User's login in Alfa-Click (linked phone number or the additional login). + attribute? :login, Types::String + end + + class YooMoney < Base + attribute :type, Types.Value("yoo_money") + + # account_number [string, optional] + # The number of the YooMoney wallet used for making the payment. + attribute? :account_number, Types::String + end + + class Sberbank < Base + attribute :type, Types.Value("sberbank") + + # phone [string, optional] + # TThe phone number specified during the registration process of the SberBank Online/SberPay account, + # specified in the ITU-T E.164 format, for example, 79000000000. + attribute? :phone, Types::String + end + + class ApplePay < Base + attribute :type, Types.Value("apple_pay") + end + + class Cash < Base + attribute :type, Types.Value("cash") + end + + class DirectCarrierBilling < Base + attribute :type, Types.Value("mobile_balance") + end + + class GooglePay < Base + attribute :type, Types.Value("google_pay") + end + + class Installments < Base + attribute :type, Types.Value("installments") + end + + class Qiwi < Base + attribute :type, Types.Value("qiwi") + end + + class Tinkoff < Base + attribute :type, Types.Value("tinkoff_bank") + end + + class Wechat < Base + attribute :type, Types.Value("wechat") + end + + class Webmoney < Base + attribute :type, Types.Value("webmoney") + end + end + + PaymentMethods = PaymentMethod::BankCard | + PaymentMethod::Alfabank | + PaymentMethod::YooMoney | + PaymentMethod::Sberbank | + PaymentMethod::ApplePay | + PaymentMethod::Cash | + PaymentMethod::DirectCarrierBilling | + PaymentMethod::GooglePay | + PaymentMethod::Installments | + PaymentMethod::Qiwi | + PaymentMethod::Tinkoff | + PaymentMethod::Wechat | + PaymentMethod::Webmoney + end +end diff --git a/lib/yookassa/entity/recipient.rb b/lib/yookassa/entity/recipient.rb new file mode 100644 index 0000000..bc928c6 --- /dev/null +++ b/lib/yookassa/entity/recipient.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require_relative "./types" + +module Yookassa + module Entity + class Recipient < Dry::Struct + attribute :account_id, Types::String + attribute :gateway_id, Types::String + end + end +end diff --git a/lib/yookassa/entity/transfer.rb b/lib/yookassa/entity/transfer.rb new file mode 100644 index 0000000..48c9d17 --- /dev/null +++ b/lib/yookassa/entity/transfer.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require_relative "./types" +require_relative "./amount" + +module Yookassa + module Entity + class Transfer < Dry::Struct + # account_id [string, required] + # ID of the store in favor of which you're accepting the receipt. Provided by YooMoney, displayed in the Sellers section + # of your Merchant Profile (shopId column). + attribute :account_id, Types::String + + # amount [object, required] + # Amount to be transferred to the store. + attribute :amount, Entity::Amount + + # status [string, required] + # Status of the money distribution between stores. Possible values: pending, waiting_for_capture, succeeded, canceled. + attribute :status, Types::String.enum("pending", "waiting_for_capture", "succeeded", "canceled") + + # platform_fee_amount [object, optional] + # Commission for sold products or services charged in your favor. + attribute? :platform_fee_amount, Entity::Amount + + # metadata [object, optional] + # Any additional data you might require for processing payments (for example, order number), specified as a “key-value” pair + # and returned in response from YooMoney. Limitations: no more than 16 keys, no more than 32 characters in the key’s title, + # no more than 512 characters in the key’s value, data type is a string in the UTF-8 format. + attribute? :metadata, Types::Hash + end + end +end diff --git a/spec/yookassa/payment_spec.rb b/spec/yookassa/payment_spec.rb index 36c802e..f13b39a 100644 --- a/spec/yookassa/payment_spec.rb +++ b/spec/yookassa/payment_spec.rb @@ -16,7 +16,7 @@ RSpec.describe Yookassa::Payment do expect(subject.paid).to eq false expect(subject.status).to eq "pending" expect(subject.captured_at).to eq nil - expect(subject.created_at).to eq "2019-06-10T21:26:41.395Z" + expect(subject.created_at).to eq DateTime.parse("2019-06-10T21:26:41.395Z") expect(subject.description).to eq nil expect(subject.expires_at).to eq nil expect(subject.metadata).to eq({}) @@ -31,7 +31,8 @@ RSpec.describe Yookassa::Payment do expect(subject.confirmation.return_url).to eq "https://url.test" expect(subject.confirmation.enforce).to eq nil - expect(subject.payment_method).to be_a Yookassa::Entity::PaymentMethod + expect(Yookassa::Entity::PaymentMethods.valid?(subject.payment_method)).to be_truthy + expect(subject.payment_method).to be_a(Yookassa::Entity::PaymentMethod::BankCard) expect(subject.payment_method.card).to eq nil expect(subject.payment_method.id).to eq "2490ded1-000f-5000-8000-1f64111bc63e" expect(subject.payment_method.saved).to eq false