afterpay-sdk 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Afterpay
4
+ class Discount
5
+ attr_accessor :name, :amount
6
+
7
+ def initialize(name:, amount:)
8
+ @name = name
9
+ @amount = amount
10
+ end
11
+
12
+ def to_hash
13
+ {
14
+ displayName: name,
15
+ amount: Utils::Money.api_hash(amount)
16
+ }
17
+ end
18
+
19
+ def self.from_response(response)
20
+ return nil if response.nil?
21
+
22
+ new(
23
+ name: response[:display_name],
24
+ amount: Utils::Money.from_response(response[:amount])
25
+ )
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Afterpay
4
+ # Error class with accessor to methods
5
+ # Afterpay error returns the same format containing
6
+ # `errorId`, `errorCode`, `message`
7
+ class Error
8
+ attr_accessor :code, :id, :message
9
+
10
+ def initialize(response)
11
+ @id = response[:errorId]
12
+ @code = response[:errorCode]
13
+ @message = response[:message]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "money"
4
+
5
+ module Afterpay
6
+ class Item
7
+ attr_accessor :name, :sku, :quantity, :page_url, :image_url, :price, :categories, :estimated_shipment_date
8
+
9
+ # rubocop:disable Metrics/ParameterLists
10
+ def initialize(name:, price:, page_url:, image_url:, categories:, estimated_shipment_date:, sku: nil, quantity: 1)
11
+ @name = name
12
+ @sku = sku
13
+ @quantity = quantity
14
+ @price = price
15
+ @page_url = page_url
16
+ @image_url = image_url
17
+ @categories = categories
18
+ @estimated_shipment_date = estimated_shipment_date
19
+ end
20
+ # rubocop:enable Metrics/ParameterLists
21
+
22
+ def to_hash
23
+ {
24
+ name: name,
25
+ sku: sku,
26
+ quantity: quantity,
27
+ price: {
28
+ amount: price.amount.to_f,
29
+ currency: price.currency.iso_code
30
+ },
31
+ page_url: page_url,
32
+ image_url: image_url,
33
+ categories: categories,
34
+ estimated_shipment_date: estimated_shipment_date
35
+ }
36
+ end
37
+
38
+ # Builds Item from response
39
+ def self.from_response(response)
40
+ return nil if response.nil?
41
+
42
+ new(
43
+ name: response[:name],
44
+ sku: response[:sku],
45
+ quantity: response[:quantity],
46
+ price: Utils::Money.from_response(response[:price]),
47
+ page_url: response[:pageUrl],
48
+ image_url: response[:imageUrl],
49
+ categories: response[:categories],
50
+ estimated_shipment_date: response[:estimatedShipmentDate]
51
+ )
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Afterpay
4
+ # The Order object for creating an order to `/v2/checkouts`
5
+ class Order
6
+ attr_accessor :total, :consumer, :items, :shipping, :tax, :discounts,
7
+ :billing, :shipping_address, :billing_address, :reference,
8
+ :payment_type, :success_url, :cancel_url, :redirect_checkout_url
9
+
10
+ attr_reader :expiry, :token, :error
11
+
12
+ # Finds Order from Afterpay API
13
+ # @param token [String]
14
+ # @return [Order]
15
+ def self.find(token)
16
+ request = Afterpay.client.get("/v2/checkouts/#{token}")
17
+
18
+ Order.from_response(request.body)
19
+ end
20
+
21
+ # Builds Order from response
22
+ # @param response [Hash] response params from API
23
+ # @return [Order]
24
+ def self.from_response(response)
25
+ return nil if response.nil?
26
+
27
+ new(
28
+ total: Utils::Money.from_response(response[:total]),
29
+ consumer: Consumer.from_response(response[:consumer]),
30
+ items: response[:items].map { |item| Item.from_response(item) },
31
+ billing_address: Address.from_response(response[:billing]),
32
+ shipping_address: Address.from_response(response[:shipping]),
33
+ discounts: response[:discounts].map { |discount| Discount.from_response(discount) },
34
+ tax: Utils::Money.from_response(response[:taxAmount]),
35
+ shipping: Utils::Money.from_response(response[:shippingAmount])
36
+ )
37
+ end
38
+
39
+ # Helper function to create an Order and calls #create
40
+ #
41
+ # @param (see #initialize)
42
+ # @return [Order::Response] containing token, error, valid?
43
+ def self.create(*args)
44
+ new(*args).create
45
+ end
46
+
47
+ # Initializes an Order object
48
+ #
49
+ # @overload initialize(total:, items:, consumer:, success_url:, cancel_url:, payment_type:)
50
+ # @param total [Money] a Money object
51
+ # @param items [Array<Afterpay::Item>] receives items for order
52
+ # @param consumer [Afterpay::Consume] the consumer for the order
53
+ # @param success_url [String] the path to redirect on successful payment
54
+ # @param cancel_url [String] the path to redirect on failed payment
55
+ # @param payment_type [String] Payment type defaults to {Config#type}
56
+ # @param shipping [Money] optional the billing Address
57
+ # @param discounts [Array<Afterpay::Discount>] optional discounts
58
+ # @param billing_address [<Afterpay::Address>] optional the billing Address
59
+ # @param shipping_address [<Afterpay::Address>] optional the shipping Address
60
+ def initialize(attributes = {})
61
+ attributes.each { |key, value| instance_variable_set(:"@#{key}", value) }
62
+ @apayment_type ||= Afterpay.config.type
63
+ @token ||= nil
64
+ @expiry ||= nil
65
+ @error = nil
66
+ end
67
+
68
+ # rubocop:disable Metrics/CyclomaticComplexity
69
+ # rubocop:disable Metrics/PerceivedComplexity
70
+
71
+ # Builds structure to API specs
72
+ def to_hash
73
+ data = {
74
+ amount: Utils::Money.api_hash(total),
75
+ consumer: consumer.to_hash,
76
+ merchant: {
77
+ redirectConfirmUrl: success_url,
78
+ redirectCancelUrl: cancel_url
79
+ },
80
+ merchantReference: reference,
81
+ taxAmount: tax,
82
+ paymentType: payment_type
83
+ }
84
+ data[items] = items.map(&:to_hash) if items
85
+ data[:taxAmount] = Utils::Money.api_hash(tax) if tax
86
+ data[:shippingAmount] = Utils::Money.api_hash(shipping) if shipping
87
+ data[:discounts] = discounts.map(&:to_hash) if discounts
88
+ data[:billing] = billing_address.to_hash if billing_address
89
+ data[:shipping] = shipping_address.to_hash if shipping_address
90
+ data
91
+ end
92
+
93
+ # rubocop:enable Metrics/CyclomaticComplexity
94
+ # rubocop:enable Metrics/PerceivedComplexity
95
+
96
+ # Sends the create request to Afterpay server
97
+ # @return [Response]
98
+ def create
99
+ request = Afterpay.client.post("/v2/checkouts") do |req|
100
+ req.body = to_hash
101
+ end
102
+ response = request.body
103
+ if request.success?
104
+ @expiry = response[:expires]
105
+ @token = response[:token]
106
+ @redirect_checkout_url = response[:redirectCheckoutUrl]
107
+ else
108
+ @error = Error.new(response)
109
+ end
110
+ self
111
+ end
112
+
113
+ def success?
114
+ !@token.nil?
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Metrics/ClassLength
4
+
5
+ module Afterpay
6
+ # They Payment object
7
+ class Payment
8
+ attr_accessor :id, :token, :status, :created, :original_amount, :open_to_capture_amount,
9
+ :payment_state, :merchant_reference, :refunds, :order, :events, :error
10
+
11
+ # Initialize Payment from response
12
+ def initialize(attributes)
13
+ @id = attributes[:id].to_i
14
+ @token = attributes[:token]
15
+ @status = attributes[:status]
16
+ @created = attributes[:created]
17
+ @original_amount = Utils::Money.from_response(attributes[:originalAmount])
18
+ @open_to_capture_amount = Utils::Money.from_response(attributes[:openToCaptureAmount])
19
+ @payment_state = attributes[:paymentState]
20
+ @merchant_reference = attributes[:merchantReference]
21
+ @refunds = attributes[:refunds]
22
+ @order = Order.from_response(attributes[:orderDetails])
23
+ @events = attributes[:events]
24
+ @error = Error.new(attributes) if attributes[:errorId]
25
+ end
26
+
27
+ def success?
28
+ @status == "APPROVED"
29
+ end
30
+
31
+ # Executes the Payment
32
+ #
33
+ # @param token [String] the Order token
34
+ # @param reference [String] the reference for payment
35
+ # @return [Payment] the Payment object
36
+ def self.execute(token:, reference:)
37
+ request = Afterpay.client.post("/v2/payments/capture") do |req|
38
+ req.body = {
39
+ token: token,
40
+ merchantRefernce: reference
41
+ }
42
+ end
43
+ new(request.body)
44
+ end
45
+
46
+ def self.execute_auth(request_id:, token:, merchant_reference:)
47
+ request = Afterpay.client.post("/v2/payments/auth") do |req|
48
+ req.body = {
49
+ requestId: request_id,
50
+ token: token,
51
+ merchantReference: merchant_reference
52
+ }
53
+ end
54
+ new(request.body)
55
+ end
56
+
57
+ def self.execute_deferred_payment(request_id:, reference:, amount:,
58
+ payment_event_merchant_reference:, order_id:)
59
+ request = Afterpay.client.post("/v2/payments/#{order_id}/capture") do |req|
60
+ req.body = {
61
+ requestId: request_id,
62
+ merchantRefernce: reference,
63
+ amount: Utils::Money.api_hash(amount),
64
+ paymentEventMerchantReference: payment_event_merchant_reference
65
+ }
66
+ end
67
+ new(request.body)
68
+ end
69
+
70
+ def self.execute_void(request_id:, order_id:, amount:)
71
+ request = Afterpay.client.post("/v2/payments/#{order_id}/void") do |req|
72
+ req.body = {
73
+ requestId: request_id,
74
+ amount: Utils::Money.api_hash(amount)
75
+ }
76
+ end
77
+ new(request.body)
78
+ end
79
+
80
+ def self.update_shipping_courier(order_id:, shipped_at:, name:, tracking:, priority:)
81
+ request = Afterpay.client.put("/v2/payments/#{order_id}/courier") do |req|
82
+ req.body = {
83
+ shippedAt: shipped_at,
84
+ name: name,
85
+ tracking: tracking,
86
+ priority: priority
87
+ }
88
+ end
89
+ new(request.body)
90
+ end
91
+
92
+ # This endpoint retrieves an individual payment along with its order details.
93
+ def self.get_payment_by_order_id(order_id:)
94
+ request = Afterpay.client.get("/v2/payments/#{order_id}")
95
+ new(request.body)
96
+ end
97
+
98
+ # This endpoint retrieves an individual payment along with its order details.
99
+ def self.get_payment_by_token(token:)
100
+ request = Afterpay.client.get("/v2/payments/token:#{token}")
101
+ new(request.body)
102
+ end
103
+
104
+ # This end point is for merchants that creates merchant side's order id after
105
+ # AfterPay order id creation. The merchants should call immediately after the
106
+ # AfterPay order is created in order to properly update with their order id
107
+ # that can be tracked.
108
+ def self.update_payment_by_order_id(order_id:, merchant_reference:)
109
+ request = Afterpay.client.put("/v2/payments/#{order_id}") do |req|
110
+ req.body = {
111
+ # The merchant's new order id to replace with
112
+ merchantReference: merchant_reference
113
+ }
114
+ end
115
+ request.body
116
+ end
117
+
118
+ # This endpoint performs a reversal of the checkout that is used to initiate
119
+ # the Afterpay payment process. This will cancel the order asynchronously as
120
+ # soon as it is created without the need of an additional call to the void endpoint.
121
+ # In order for a payment to be eligible, the order must be in an Auth-Approved or
122
+ # Captured state and must be issued within 10 minutes of the order being created.
123
+ # token paramater is the token of the checkout to be reversed (voided).
124
+ def self.reverse_payment_by_token(token:)
125
+ request = Afterpay.client.post("/v2/payments/token:#{token}/reversal") do |req|
126
+ req.body = {}
127
+ end
128
+ request.status
129
+ end
130
+
131
+ def self.create_url(url, type, values)
132
+ if values.size.positive?
133
+ values.each do |value|
134
+ url += "&#{type}=#{value}"
135
+ end
136
+ end
137
+ url
138
+ end
139
+
140
+ # rubocop:disable Metrics/ParameterLists
141
+
142
+ # This endpoint retrieves a collection of payments along with their order details.
143
+ def self.list_payments(to_created_date:, from_created_date:, limit:, offset:, tokens:, ids:,
144
+ merchant_ref:, statuses:, order_by:, asc:)
145
+ url = "/v2/payments?"
146
+ url += "toCreatedDate=#{to_created_date.gsub('+', '%2b')}" if to_created_date
147
+ url += "&fromCreatedDate=#{from_created_date.gsub('+', '%2b')}" if from_created_date
148
+ url += "&limit=#{limit}" if limit
149
+ url += "&offset=#{offset}" if offset
150
+ url += "&orderBy=#{order_by}" if order_by
151
+ url += "&ascending=#{asc}" if asc
152
+ url += create_url(url, "ids", ids)
153
+ url += create_url(url, "tokens", tokens)
154
+ url += create_url(url, "merchantReferences", merchant_ref)
155
+ url += create_url(url, "statuses", statuses)
156
+ request = Afterpay.client.get(url)
157
+ request.body
158
+ end
159
+
160
+ # rubocop:enable Metrics/ParameterLists
161
+ end
162
+ end
163
+
164
+ # rubocop:enable Metrics/ClassLength
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Afterpay
4
+ class PaymentEvent
5
+ attr_accessor :id, :created, :expires, :type, :amount, :payment_event_merchant_reference
6
+
7
+ def initialize(attributes)
8
+ @id = attributes[:id]
9
+ @created = attributes[:created]
10
+ @expires = attributes[:expires]
11
+ @type = attributes[:expires]
12
+ @amount = Utils::Money.from_response(attributes[:amount])
13
+ @payment_event_merchant_reference = attributes[:paymentEventMerchantReference]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Afterpay
4
+ class Refund
5
+ attr_accessor :request_id, :amount, :merchant_reference, :refund_id, :refunded_at,
6
+ :refund_merchant_reference, :error
7
+
8
+ def initialize(attributes)
9
+ @request_id = attributes[:requestId]
10
+ @amount = attributes[:amount]
11
+ @merchant_reference = attributes[:merchantReference]
12
+ @refund_id = attributes[:refundId]
13
+ @refunded_at = attributes[:refundAt]
14
+ @refund_merchant_reference = attributes[:refundMerchantReference]
15
+ @error = Error.new(attributes) if attributes[:errorId]
16
+ end
17
+
18
+ def self.execute(request_id:, order_id:, amount:, merchant_reference:,
19
+ refund_merchant_reference:)
20
+ request = Afterpay.client.post("/v2/payments/#{order_id}/refund") do |req|
21
+ req.body = {
22
+ requestId: request_id,
23
+ amount: Utils::Money.api_hash(amount),
24
+ merchantReference: merchant_reference,
25
+ refundMerchantReference: refund_merchant_reference
26
+ }
27
+ end
28
+ new(request.body)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Afterpay
4
+ class ShippingCourier
5
+ attr_accessor :shipped_at, :name, :tracking, :priority
6
+
7
+ def initialize(shipped_at:, name:, tracking:, priority:)
8
+ @shipped_at = shipped_at
9
+ @name = name
10
+ @tracking = tracking
11
+ @priority = priority
12
+ end
13
+ end
14
+ end