dpay 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +29 -0
- data/LICENSE +201 -0
- data/README.md +191 -0
- data/lib/dpay/bank/bank.rb +28 -0
- data/lib/dpay/bank/bank_service.rb +28 -0
- data/lib/dpay/blik/blik_alias.rb +27 -0
- data/lib/dpay/blik/blik_alias_registration.rb +21 -0
- data/lib/dpay/blik/blik_alias_type.rb +18 -0
- data/lib/dpay/blik/blik_app.rb +17 -0
- data/lib/dpay/blik/blik_recurring_registration.rb +74 -0
- data/lib/dpay/blik/blik_recurring_registration_info.rb +26 -0
- data/lib/dpay/blik/blik_recurring_status.rb +28 -0
- data/lib/dpay/blik/blik_service.rb +51 -0
- data/lib/dpay/card/apple_pay_request.rb +38 -0
- data/lib/dpay/card/card_data.rb +30 -0
- data/lib/dpay/card/card_encryptor.rb +27 -0
- data/lib/dpay/card/card_payment_request.rb +59 -0
- data/lib/dpay/card/card_payment_result.rb +58 -0
- data/lib/dpay/card/card_recurring_frequency.rb +23 -0
- data/lib/dpay/card/card_recurring_operation.rb +19 -0
- data/lib/dpay/card/card_recurring_registration.rb +69 -0
- data/lib/dpay/card/card_service.rb +47 -0
- data/lib/dpay/card/dcc_decision.rb +18 -0
- data/lib/dpay/card/dcc_markup.rb +18 -0
- data/lib/dpay/card/dcc_offer.rb +36 -0
- data/lib/dpay/card/google_pay_request.rb +35 -0
- data/lib/dpay/card/redirect_type.rb +20 -0
- data/lib/dpay/client.rb +26 -0
- data/lib/dpay/config.rb +39 -0
- data/lib/dpay/currency.rb +19 -0
- data/lib/dpay/errors.rb +77 -0
- data/lib/dpay/http/client.rb +11 -0
- data/lib/dpay/http/net_http_client.rb +52 -0
- data/lib/dpay/http/request.rb +17 -0
- data/lib/dpay/http/response.rb +29 -0
- data/lib/dpay/internal/api_requestor.rb +65 -0
- data/lib/dpay/internal/base_urls.rb +38 -0
- data/lib/dpay/internal/checksum_calculator.rb +26 -0
- data/lib/dpay/internal/coerce.rb +46 -0
- data/lib/dpay/internal/error_mapper.rb +90 -0
- data/lib/dpay/internal/php.rb +71 -0
- data/lib/dpay/ipn/ipn_event.rb +84 -0
- data/lib/dpay/ipn/ipn_type.rb +19 -0
- data/lib/dpay/ipn/ipn_verifier.rb +57 -0
- data/lib/dpay/money.rb +85 -0
- data/lib/dpay/payment/device_info.rb +42 -0
- data/lib/dpay/payment/invoice_details.rb +48 -0
- data/lib/dpay/payment/payer.rb +26 -0
- data/lib/dpay/payment/payment_service.rb +35 -0
- data/lib/dpay/payment/payout_fee_mode.rb +18 -0
- data/lib/dpay/payment/payout_instruction.rb +26 -0
- data/lib/dpay/payment/payout_position.rb +23 -0
- data/lib/dpay/payment/register_payment_request.rb +246 -0
- data/lib/dpay/payment/registered_payment.rb +42 -0
- data/lib/dpay/payment/return_urls.rb +20 -0
- data/lib/dpay/payment/transaction.rb +54 -0
- data/lib/dpay/payment/transaction_refund.rb +21 -0
- data/lib/dpay/payment/transaction_status.rb +21 -0
- data/lib/dpay/payment/transaction_type.rb +23 -0
- data/lib/dpay/payout/payout_details.rb +50 -0
- data/lib/dpay/payout/payout_receiver.rb +22 -0
- data/lib/dpay/payout/payout_service.rb +23 -0
- data/lib/dpay/refund/refund.rb +22 -0
- data/lib/dpay/refund/refund_availability.rb +23 -0
- data/lib/dpay/refund/refund_service.rb +46 -0
- data/lib/dpay/testing/mock_http_client.rb +51 -0
- data/lib/dpay/testing.rb +4 -0
- data/lib/dpay/version.rb +5 -0
- data/lib/dpay.rb +68 -0
- data/sig/dpay/bank/bank.rbs +17 -0
- data/sig/dpay/bank/bank_service.rbs +13 -0
- data/sig/dpay/blik/blik_alias.rbs +17 -0
- data/sig/dpay/blik/blik_alias_registration.rbs +6 -0
- data/sig/dpay/blik/blik_alias_type.rbs +11 -0
- data/sig/dpay/blik/blik_app.rbs +10 -0
- data/sig/dpay/blik/blik_recurring_registration.rbs +24 -0
- data/sig/dpay/blik/blik_recurring_registration_info.rbs +17 -0
- data/sig/dpay/blik/blik_recurring_status.rbs +17 -0
- data/sig/dpay/blik/blik_service.rbs +13 -0
- data/sig/dpay/card/apple_pay_request.rbs +13 -0
- data/sig/dpay/card/card_data.rbs +15 -0
- data/sig/dpay/card/card_encryptor.rbs +9 -0
- data/sig/dpay/card/card_payment_request.rbs +17 -0
- data/sig/dpay/card/card_payment_result.rbs +22 -0
- data/sig/dpay/card/card_recurring_frequency.rbs +16 -0
- data/sig/dpay/card/card_recurring_operation.rbs +12 -0
- data/sig/dpay/card/card_recurring_registration.rbs +22 -0
- data/sig/dpay/card/card_service.rbs +16 -0
- data/sig/dpay/card/dcc_decision.rbs +11 -0
- data/sig/dpay/card/dcc_markup.rbs +10 -0
- data/sig/dpay/card/dcc_offer.rbs +21 -0
- data/sig/dpay/card/google_pay_request.rbs +12 -0
- data/sig/dpay/card/redirect_type.rbs +13 -0
- data/sig/dpay/client.rbs +21 -0
- data/sig/dpay/config.rbs +25 -0
- data/sig/dpay/currency.rbs +11 -0
- data/sig/dpay/errors.rbs +86 -0
- data/sig/dpay/http/client.rbs +7 -0
- data/sig/dpay/http/net_http_client.rbs +15 -0
- data/sig/dpay/http/request.rbs +12 -0
- data/sig/dpay/http/response.rbs +15 -0
- data/sig/dpay/internal/api_requestor.rbs +23 -0
- data/sig/dpay/internal/base_urls.rbs +13 -0
- data/sig/dpay/internal/checksum_calculator.rbs +9 -0
- data/sig/dpay/internal/coerce.rbs +12 -0
- data/sig/dpay/internal/error_mapper.rbs +16 -0
- data/sig/dpay/internal/php.rbs +16 -0
- data/sig/dpay/ipn/ipn_event.rbs +28 -0
- data/sig/dpay/ipn/ipn_type.rbs +12 -0
- data/sig/dpay/ipn/ipn_verifier.rbs +11 -0
- data/sig/dpay/money.rbs +25 -0
- data/sig/dpay/payment/device_info.rbs +25 -0
- data/sig/dpay/payment/invoice_details.rbs +17 -0
- data/sig/dpay/payment/payer.rbs +14 -0
- data/sig/dpay/payment/payment_service.rbs +11 -0
- data/sig/dpay/payment/payout_fee_mode.rbs +11 -0
- data/sig/dpay/payment/payout_instruction.rbs +8 -0
- data/sig/dpay/payment/payout_position.rbs +10 -0
- data/sig/dpay/payment/register_payment_request.rbs +56 -0
- data/sig/dpay/payment/registered_payment.rbs +20 -0
- data/sig/dpay/payment/return_urls.rbs +11 -0
- data/sig/dpay/payment/transaction.rbs +25 -0
- data/sig/dpay/payment/transaction_refund.rbs +14 -0
- data/sig/dpay/payment/transaction_status.rbs +14 -0
- data/sig/dpay/payment/transaction_type.rbs +16 -0
- data/sig/dpay/payout/payout_details.rbs +24 -0
- data/sig/dpay/payout/payout_receiver.rbs +15 -0
- data/sig/dpay/payout/payout_service.rbs +6 -0
- data/sig/dpay/refund/refund.rbs +11 -0
- data/sig/dpay/refund/refund_availability.rbs +12 -0
- data/sig/dpay/refund/refund_service.rbs +14 -0
- data/sig/dpay/testing/mock_http_client.rbs +16 -0
- data/sig/dpay/testing.rbs +4 -0
- data/sig/dpay/version.rbs +3 -0
- data/sig/dpay.rbs +2 -0
- metadata +180 -0
data/lib/dpay/money.rb
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DPay
|
|
4
|
+
class Money
|
|
5
|
+
DECIMAL = /\A(-?)(\d+)(?:\.(\d{1,2}))?\z/
|
|
6
|
+
|
|
7
|
+
attr_reader :minor, :currency
|
|
8
|
+
|
|
9
|
+
def self.pln(minor)
|
|
10
|
+
new(minor, Currency::PLN)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.of(minor, currency)
|
|
14
|
+
Currency.assert_valid(currency)
|
|
15
|
+
new(minor, currency)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.from_decimal(decimal, currency)
|
|
19
|
+
Currency.assert_valid(currency)
|
|
20
|
+
parsed = parse_decimal(decimal)
|
|
21
|
+
raise InvalidArgumentError, %(Invalid money amount "#{decimal}") if parsed.nil?
|
|
22
|
+
|
|
23
|
+
new(parsed, currency)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.from_api_number(value, currency)
|
|
27
|
+
case value
|
|
28
|
+
when Integer then of(value * 100, currency)
|
|
29
|
+
when Float then of(Internal::PHP.round(value * 100), currency)
|
|
30
|
+
when String then from_decimal(value, currency)
|
|
31
|
+
else raise InvalidArgumentError, "Money value must be Integer, Float or String"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def self.try_from_api_number(value, currency)
|
|
36
|
+
return nil unless Currency.valid?(currency)
|
|
37
|
+
|
|
38
|
+
case value
|
|
39
|
+
when Integer then new(value * 100, currency)
|
|
40
|
+
when Float then new(Internal::PHP.round(value * 100), currency)
|
|
41
|
+
when String
|
|
42
|
+
parsed = parse_decimal(value)
|
|
43
|
+
parsed.nil? ? nil : new(parsed, currency)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.parse_decimal(decimal)
|
|
48
|
+
match = DECIMAL.match(decimal.to_s)
|
|
49
|
+
return nil if match.nil?
|
|
50
|
+
|
|
51
|
+
minor = (match[2].to_i * 100) + (match[3] || "").ljust(2, "0").to_i
|
|
52
|
+
match[1] == "-" ? -minor : minor
|
|
53
|
+
end
|
|
54
|
+
private_class_method :parse_decimal
|
|
55
|
+
|
|
56
|
+
def initialize(minor, currency)
|
|
57
|
+
@minor = minor
|
|
58
|
+
@currency = currency
|
|
59
|
+
freeze
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def to_decimal
|
|
63
|
+
absolute = @minor.abs
|
|
64
|
+
sign = @minor.negative? ? "-" : ""
|
|
65
|
+
format("%<sign>s%<dollars>d.%<cents>02d", sign: sign, dollars: absolute / 100, cents: absolute % 100)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def negative?
|
|
69
|
+
@minor.negative?
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def ==(other)
|
|
73
|
+
other.is_a?(Money) && other.minor == @minor && other.currency == @currency
|
|
74
|
+
end
|
|
75
|
+
alias eql? ==
|
|
76
|
+
|
|
77
|
+
def hash
|
|
78
|
+
[@minor, @currency].hash
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def to_s
|
|
82
|
+
"#{to_decimal} #{@currency}"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DPay
|
|
4
|
+
class DeviceInfo
|
|
5
|
+
def self.create(browser_accept_header:, browser_language:, browser_color_depth:, browser_screen_height:,
|
|
6
|
+
browser_screen_width:, browser_tz:, browser_user_agent:, system_family:, geo_localization:,
|
|
7
|
+
device_id:, application_name:)
|
|
8
|
+
new(
|
|
9
|
+
{ "browserAcceptHeader" => browser_accept_header, "browserLanguage" => browser_language,
|
|
10
|
+
"browserColorDepth" => browser_color_depth, "browserScreenHeight" => browser_screen_height,
|
|
11
|
+
"browserScreenWidth" => browser_screen_width, "browserTZ" => browser_tz,
|
|
12
|
+
"browserUserAgent" => browser_user_agent, "systemFamily" => system_family,
|
|
13
|
+
"geoLocalization" => geo_localization, "deviceID" => bounded(device_id, "Device ID"),
|
|
14
|
+
"applicationName" => bounded(application_name, "Application name") }
|
|
15
|
+
)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.bounded(value, label)
|
|
19
|
+
raise InvalidArgumentError, "#{label} must be 1-64 characters" unless value.is_a?(String) &&
|
|
20
|
+
!value.empty? && value.length <= 64
|
|
21
|
+
|
|
22
|
+
value
|
|
23
|
+
end
|
|
24
|
+
private_class_method :bounded
|
|
25
|
+
|
|
26
|
+
def initialize(fields)
|
|
27
|
+
@fields = fields
|
|
28
|
+
@browser_java_enabled = nil
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def with_browser_java_enabled(enabled)
|
|
32
|
+
@browser_java_enabled = enabled
|
|
33
|
+
self
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def to_h
|
|
37
|
+
data = @fields.dup
|
|
38
|
+
data["browserJavaEnabled"] = @browser_java_enabled ? "true" : "false" unless @browser_java_enabled.nil?
|
|
39
|
+
data
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DPay
|
|
4
|
+
class InvoiceDetails
|
|
5
|
+
DATE = /\A\d{4}-\d{2}-\d{2}\z/
|
|
6
|
+
|
|
7
|
+
def self.create
|
|
8
|
+
new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
@data = {}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def with_payer_nip(payer_nip)
|
|
16
|
+
@data["payer_nip"] = payer_nip
|
|
17
|
+
self
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def with_payer_name(payer_name)
|
|
21
|
+
@data["payer_name"] = payer_name
|
|
22
|
+
self
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def with_invoice_number(invoice_number)
|
|
26
|
+
@data["invoice_number"] = invoice_number
|
|
27
|
+
self
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def with_payment_due_date(payment_due_date)
|
|
31
|
+
unless payment_due_date.is_a?(String) && DATE.match?(payment_due_date)
|
|
32
|
+
raise InvalidArgumentError, "Payment due date must be in YYYY-MM-DD format"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
@data["payment_due_date"] = payment_due_date
|
|
36
|
+
self
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def with_vat_amount(vat_amount)
|
|
40
|
+
@data["vat_amount"] = vat_amount.minor
|
|
41
|
+
self
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def to_h
|
|
45
|
+
@data.dup
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DPay
|
|
4
|
+
class Payer
|
|
5
|
+
EMAIL = /\A[^@\s]+@[^@\s]+\.[^@\s]+\z/
|
|
6
|
+
|
|
7
|
+
attr_reader :email, :first_name, :last_name
|
|
8
|
+
|
|
9
|
+
def self.create
|
|
10
|
+
new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def with_email(email)
|
|
14
|
+
raise InvalidArgumentError, %(Invalid email "#{email}") unless email.is_a?(String) && EMAIL.match?(email)
|
|
15
|
+
|
|
16
|
+
@email = email
|
|
17
|
+
self
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def with_name(first_name, last_name)
|
|
21
|
+
@first_name = first_name
|
|
22
|
+
@last_name = last_name
|
|
23
|
+
self
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DPay
|
|
4
|
+
class PaymentService
|
|
5
|
+
def initialize(api)
|
|
6
|
+
@api = api
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def register(request)
|
|
10
|
+
body = request.to_body(@api.service)
|
|
11
|
+
body["checksum"] = @api.checksum.secret_second(
|
|
12
|
+
@api.service,
|
|
13
|
+
[body["value"], body["url_success"], body["url_fail"], body["url_ipn"]]
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
data = @api.post_json(Internal::BaseUrls::API_PAYMENTS, "/api/v1_0/payments/register", body)
|
|
17
|
+
raise PaymentRejectedError.from_api(data) if rejected?(data)
|
|
18
|
+
|
|
19
|
+
RegisteredPayment.from_api(data)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def details(transaction_id)
|
|
23
|
+
body = { "service" => @api.service, "transaction_id" => transaction_id }
|
|
24
|
+
body["checksum"] = @api.checksum.ordered_body(body.values)
|
|
25
|
+
|
|
26
|
+
Transaction.from_api(@api.post_json(Internal::BaseUrls::PANEL, "/api/v1/pbl/details", body))
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def rejected?(data)
|
|
32
|
+
data["error"] == true || data["status"] == false
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DPay
|
|
4
|
+
module PayoutFeeMode
|
|
5
|
+
NET = "net"
|
|
6
|
+
GROSS = "gross"
|
|
7
|
+
|
|
8
|
+
ALL = [NET, GROSS].freeze
|
|
9
|
+
|
|
10
|
+
def self.valid?(value)
|
|
11
|
+
ALL.include?(value)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.assert_valid(value)
|
|
15
|
+
raise InvalidArgumentError, %(Invalid payout fee mode "#{value}") unless valid?(value)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DPay
|
|
4
|
+
class PayoutInstruction
|
|
5
|
+
def self.create(positions, fee_mode = PayoutFeeMode::NET)
|
|
6
|
+
new(positions, fee_mode)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def initialize(positions, fee_mode = PayoutFeeMode::NET)
|
|
10
|
+
raise InvalidArgumentError, "Payout instruction requires at least one position" if positions.empty?
|
|
11
|
+
unless positions.all?(PayoutPosition)
|
|
12
|
+
raise InvalidArgumentError, "Positions must be DPay::PayoutPosition instances"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
PayoutFeeMode.assert_valid(fee_mode)
|
|
16
|
+
|
|
17
|
+
@positions = positions.dup.freeze
|
|
18
|
+
@fee_mode = fee_mode
|
|
19
|
+
freeze
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def to_h
|
|
23
|
+
{ "fee_mode" => @fee_mode, "positions" => @positions.map(&:to_h) }
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DPay
|
|
4
|
+
class PayoutPosition
|
|
5
|
+
attr_reader :iban, :title, :amount
|
|
6
|
+
|
|
7
|
+
def initialize(iban, title, amount)
|
|
8
|
+
raise InvalidArgumentError, "Payout IBAN must not be empty" unless iban.is_a?(String) && !iban.empty?
|
|
9
|
+
unless title.is_a?(String) && !title.empty? && title.length <= 255
|
|
10
|
+
raise InvalidArgumentError, "Payout title must be 1-255 characters"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
@iban = iban
|
|
14
|
+
@title = title
|
|
15
|
+
@amount = amount
|
|
16
|
+
freeze
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_h
|
|
20
|
+
{ "iban" => @iban, "title" => @title, "amount" => @amount.to_decimal.to_f }
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DPay
|
|
4
|
+
class RegisterPaymentRequest
|
|
5
|
+
BLIK_CODE = /\A\d{6}\z/
|
|
6
|
+
PARTNER_PLATFORM = /\A[A-Z0-9]{1,64}\z/
|
|
7
|
+
HTTP_URL = %r{\Ahttps?://[^\s]+\z}
|
|
8
|
+
TOGGLES = { "creditcard" => :@credit_card, "paysafecard" => :@paysafecard, "blik" => :@blik,
|
|
9
|
+
"installment" => :@installment, "paypal" => :@paypal, "nobanks" => :@no_banks }.freeze
|
|
10
|
+
|
|
11
|
+
attr_reader :amount
|
|
12
|
+
|
|
13
|
+
def self.create(amount, transaction_type, urls)
|
|
14
|
+
new(amount, transaction_type, urls)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def initialize(amount, transaction_type, urls)
|
|
18
|
+
TransactionType.assert_valid(transaction_type)
|
|
19
|
+
|
|
20
|
+
@amount = amount
|
|
21
|
+
@transaction_type = transaction_type
|
|
22
|
+
@urls = urls
|
|
23
|
+
@optional = {}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def with_description(description)
|
|
27
|
+
set("description", description)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def with_custom(custom)
|
|
31
|
+
set("custom", custom)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def with_payer(payer)
|
|
35
|
+
@payer = payer
|
|
36
|
+
self
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def with_accept_tos(accept_tos)
|
|
40
|
+
set("accept_tos", accept_tos)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def with_channel(channel)
|
|
44
|
+
set("channel", channel)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def with_credit_card(enabled)
|
|
48
|
+
@credit_card = enabled
|
|
49
|
+
self
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def with_paysafecard(enabled)
|
|
53
|
+
@paysafecard = enabled
|
|
54
|
+
self
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def with_blik(enabled)
|
|
58
|
+
@blik = enabled
|
|
59
|
+
self
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def with_installment(enabled)
|
|
63
|
+
@installment = enabled
|
|
64
|
+
self
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def with_paypal(enabled)
|
|
68
|
+
@paypal = enabled
|
|
69
|
+
self
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def with_no_banks(disabled)
|
|
73
|
+
@no_banks = disabled
|
|
74
|
+
self
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def with_phone_number(phone_number, currency_code)
|
|
78
|
+
Currency.assert_valid(currency_code)
|
|
79
|
+
set("phone_number", phone_number)
|
|
80
|
+
set("currency_code", currency_code)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def with_currency_code(currency_code)
|
|
84
|
+
Currency.assert_valid(currency_code)
|
|
85
|
+
set("currency_code", currency_code)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def with_partner_platform(partner_platform)
|
|
89
|
+
unless partner_platform.is_a?(String) && PARTNER_PLATFORM.match?(partner_platform)
|
|
90
|
+
raise InvalidArgumentError, "Partner platform must match ^[A-Z0-9]{1,64}$"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
set("partner_platform", partner_platform)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def with_blik_code(blik_code, user_agent, user_ip)
|
|
97
|
+
raise InvalidArgumentError, "BLIK code must be exactly 6 digits" unless BLIK_CODE.match?(blik_code.to_s)
|
|
98
|
+
raise InvalidArgumentError, "blik_code cannot be combined with blik_alias" if @optional.key?("blik_alias")
|
|
99
|
+
|
|
100
|
+
set("blik_code", blik_code)
|
|
101
|
+
set("user_agent", user_agent)
|
|
102
|
+
set("user_ip", user_ip)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def with_blik_alias(alias_value, user_agent, user_ip)
|
|
106
|
+
if @optional.key?("blik_code") || @optional.key?("register_blik_alias") ||
|
|
107
|
+
@optional.key?("register_blik_recurring_alias")
|
|
108
|
+
raise InvalidArgumentError, "blik_alias cannot be combined with blik_code or alias registration"
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
set("blik_alias", alias_value)
|
|
112
|
+
set("user_agent", user_agent)
|
|
113
|
+
set("user_ip", user_ip)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def with_register_blik_alias(registration)
|
|
117
|
+
if @optional.key?("blik_alias")
|
|
118
|
+
raise InvalidArgumentError, "register_blik_alias cannot be combined with blik_alias"
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
set("register_blik_alias", registration.to_h)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def with_register_blik_recurring_alias(registration)
|
|
125
|
+
if @optional.key?("blik_alias")
|
|
126
|
+
raise InvalidArgumentError, "register_blik_recurring_alias cannot be combined with blik_alias"
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
set("register_blik_recurring_alias", registration.to_h)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def with_alias_ipn_url(url)
|
|
133
|
+
raise InvalidArgumentError, %(Invalid alias IPN URL "#{url}") unless url.is_a?(String) && HTTP_URL.match?(url)
|
|
134
|
+
|
|
135
|
+
set("alias_ipn_url", url)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def with_no_delay(no_delay)
|
|
139
|
+
set("no_delay", no_delay)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def with_card_recurring(registration)
|
|
143
|
+
if @optional.key?("card_recurring_alias")
|
|
144
|
+
raise InvalidArgumentError, "register_card_recurring cannot be combined with card_recurring_alias"
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
set("register_card_recurring", registration.to_h)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def with_card_recurring_alias(alias_value)
|
|
151
|
+
if @optional.key?("register_card_recurring")
|
|
152
|
+
raise InvalidArgumentError, "card_recurring_alias cannot be combined with register_card_recurring"
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
set("card_recurring_alias", alias_value)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def with_authorize_only(authorize_only)
|
|
159
|
+
set("authorize_only", authorize_only)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def with_card_recurring_operation(operation)
|
|
163
|
+
CardRecurringOperation.assert_valid(operation)
|
|
164
|
+
set("card_recurring_operation", operation)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def with_payout(payout)
|
|
168
|
+
set("payout", payout.to_h)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def with_billing_address(billing_address)
|
|
172
|
+
set("billing_address", billing_address)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def with_shipping_address(shipping_address)
|
|
176
|
+
set("shipping_address", shipping_address)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def with_device_info(device_info)
|
|
180
|
+
set("device_info", device_info.to_h)
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def with_products(products)
|
|
184
|
+
set("products", products)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def with_efaktura(invoice = nil)
|
|
188
|
+
unless @transaction_type == TransactionType::TRANSFERS
|
|
189
|
+
raise InvalidArgumentError, %(efaktura is allowed only for transactionType "transfers")
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
set("efaktura", true)
|
|
193
|
+
invoice.nil? ? self : set("invoice", invoice.to_h)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def to_body(service)
|
|
197
|
+
body = {
|
|
198
|
+
"service" => service,
|
|
199
|
+
"value" => @amount.to_decimal,
|
|
200
|
+
"transactionType" => @transaction_type,
|
|
201
|
+
"url_success" => @urls.success,
|
|
202
|
+
"url_fail" => @urls.fail,
|
|
203
|
+
"url_ipn" => @urls.ipn
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
append(body, "description")
|
|
207
|
+
append(body, "custom")
|
|
208
|
+
append_payer(body)
|
|
209
|
+
append(body, "accept_tos")
|
|
210
|
+
append(body, "channel")
|
|
211
|
+
append_toggles(body)
|
|
212
|
+
%w[phone_number currency_code partner_platform user_agent user_ip blik_code blik_alias register_blik_alias
|
|
213
|
+
register_blik_recurring_alias alias_ipn_url no_delay register_card_recurring card_recurring_alias
|
|
214
|
+
authorize_only card_recurring_operation payout billing_address shipping_address device_info products
|
|
215
|
+
efaktura invoice].each { |key| append(body, key) }
|
|
216
|
+
|
|
217
|
+
body
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
private
|
|
221
|
+
|
|
222
|
+
def set(key, value)
|
|
223
|
+
@optional[key] = value
|
|
224
|
+
self
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def append(body, key)
|
|
228
|
+
body[key] = @optional[key] if @optional.key?(key)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def append_payer(body)
|
|
232
|
+
return if @payer.nil?
|
|
233
|
+
|
|
234
|
+
body["email"] = @payer.email unless @payer.email.nil?
|
|
235
|
+
body["client_name"] = @payer.first_name unless @payer.first_name.nil?
|
|
236
|
+
body["client_surname"] = @payer.last_name unless @payer.last_name.nil?
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def append_toggles(body)
|
|
240
|
+
TOGGLES.each do |key, variable|
|
|
241
|
+
flag = instance_variable_defined?(variable) ? instance_variable_get(variable) : nil
|
|
242
|
+
body[key] = flag ? 1 : 0 unless flag.nil?
|
|
243
|
+
end
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DPay
|
|
4
|
+
class RegisteredPayment
|
|
5
|
+
REDIRECT = %r{\Ahttps?://}
|
|
6
|
+
PAID = "Transaction paid"
|
|
7
|
+
INTERNAL_PROCESSING = "Internal processing"
|
|
8
|
+
|
|
9
|
+
attr_reader :transaction_id, :message, :ipksef, :raw
|
|
10
|
+
|
|
11
|
+
def self.from_api(data)
|
|
12
|
+
new(data)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def initialize(data)
|
|
16
|
+
@raw = data
|
|
17
|
+
@transaction_id = Internal::Coerce.string(data["transactionId"]) || ""
|
|
18
|
+
@message = Internal::Coerce.string(data["msg"]) || ""
|
|
19
|
+
@ipksef = data["ipksef"].is_a?(String) ? data["ipksef"] : nil
|
|
20
|
+
freeze
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def redirect_url
|
|
24
|
+
REDIRECT.match?(@message) ? @message : nil
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def paid?
|
|
28
|
+
@message == PAID
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def internal_processing?
|
|
32
|
+
@message == INTERNAL_PROCESSING
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def card_recurring_alias
|
|
36
|
+
additional = @raw["additionalInfo"]
|
|
37
|
+
return nil unless additional.is_a?(Hash) && additional["card_recurring_alias"].is_a?(String)
|
|
38
|
+
|
|
39
|
+
additional["card_recurring_alias"]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DPay
|
|
4
|
+
class ReturnUrls
|
|
5
|
+
HTTP_URL = %r{\Ahttps?://[^\s]+\z}
|
|
6
|
+
|
|
7
|
+
attr_reader :success, :fail, :ipn
|
|
8
|
+
|
|
9
|
+
def initialize(success, fail, ipn)
|
|
10
|
+
{ "success" => success, "fail" => fail, "ipn" => ipn }.each do |name, url|
|
|
11
|
+
raise InvalidArgumentError, %(Invalid #{name} URL "#{url}") unless url.is_a?(String) && HTTP_URL.match?(url)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
@success = success
|
|
15
|
+
@fail = fail
|
|
16
|
+
@ipn = ipn
|
|
17
|
+
freeze
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DPay
|
|
4
|
+
class Transaction
|
|
5
|
+
attr_reader :id, :value, :status, :payment_method, :creation_date, :payment_date,
|
|
6
|
+
:refunded_amount, :available_refund_amount, :gateway_id, :payer, :refunds, :raw
|
|
7
|
+
|
|
8
|
+
def self.from_api(data)
|
|
9
|
+
new(data)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def initialize(data)
|
|
13
|
+
@raw = data
|
|
14
|
+
tx = data["transaction"].is_a?(Hash) ? data["transaction"] : {}
|
|
15
|
+
|
|
16
|
+
@id = Internal::Coerce.string(tx["id"]) || ""
|
|
17
|
+
@value = Internal::Coerce.money(tx["value"])
|
|
18
|
+
@status = Internal::Coerce.string(tx["status"]) || ""
|
|
19
|
+
@payment_method = Internal::Coerce.string(tx["payment_method"])
|
|
20
|
+
@creation_date = Internal::Coerce.string(tx["creation_date"])
|
|
21
|
+
@payment_date = tx["payment_date"].is_a?(String) ? tx["payment_date"] : nil
|
|
22
|
+
@settled = Internal::Coerce.boolean(tx["settled"])
|
|
23
|
+
@refunded = Internal::Coerce.boolean(tx["refunded"])
|
|
24
|
+
@refunded_amount = Internal::Coerce.money(tx["refunded_amount"])
|
|
25
|
+
@available_refund_amount = Internal::Coerce.money(tx["available_refund_amount"])
|
|
26
|
+
@fully_refunded = Internal::Coerce.boolean(tx["fully_refunded"])
|
|
27
|
+
@direct = Internal::Coerce.boolean(tx["direct"])
|
|
28
|
+
@gateway_id = tx["gateway_id"].is_a?(String) ? tx["gateway_id"] : nil
|
|
29
|
+
@payer = data["payer"].is_a?(Hash) ? data["payer"] : {}
|
|
30
|
+
@refunds = Internal::Coerce.list(data["refunds"]).map { |refund| TransactionRefund.from_api(refund) }
|
|
31
|
+
freeze
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def paid?
|
|
35
|
+
@status == TransactionStatus::PAID || @status == TransactionStatus::CAPTURED
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def settled?
|
|
39
|
+
@settled
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def refunded?
|
|
43
|
+
@refunded
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def fully_refunded?
|
|
47
|
+
@fully_refunded
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def direct?
|
|
51
|
+
@direct
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module DPay
|
|
4
|
+
class TransactionRefund
|
|
5
|
+
attr_reader :payment_id, :value, :status, :creation_date, :payment_date, :raw
|
|
6
|
+
|
|
7
|
+
def self.from_api(data)
|
|
8
|
+
new(data)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize(data)
|
|
12
|
+
@raw = data
|
|
13
|
+
@payment_id = Internal::Coerce.string(data["payment_id"]) || ""
|
|
14
|
+
@value = Internal::Coerce.money(data["value"])
|
|
15
|
+
@status = Internal::Coerce.string(data["status"]) || TransactionStatus::PAID
|
|
16
|
+
@creation_date = Internal::Coerce.string(data["creation_date"])
|
|
17
|
+
@payment_date = Internal::Coerce.string(data["payment_date"])
|
|
18
|
+
freeze
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|