flex_commerce_api 0.6.57
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/.env.example +6 -0
- data/.gitignore +14 -0
- data/.rspec +4 -0
- data/.rubocop.yml +1065 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +56 -0
- data/Rakefile +1 -0
- data/app/models/address.rb +41 -0
- data/app/models/asset_file.rb +26 -0
- data/app/models/asset_folder.rb +14 -0
- data/app/models/bundle.rb +20 -0
- data/app/models/bundle_group.rb +15 -0
- data/app/models/cart.rb +136 -0
- data/app/models/category.rb +70 -0
- data/app/models/category_tree.rb +11 -0
- data/app/models/component.rb +8 -0
- data/app/models/container_coupon.rb +12 -0
- data/app/models/country.rb +11 -0
- data/app/models/coupon.rb +18 -0
- data/app/models/customer_account.rb +96 -0
- data/app/models/customer_account_authentication.rb +5 -0
- data/app/models/customer_segment.rb +6 -0
- data/app/models/customer_segment_member.rb +6 -0
- data/app/models/data_attribute.rb +6 -0
- data/app/models/data_store_record.rb +9 -0
- data/app/models/data_store_type.rb +9 -0
- data/app/models/discount_summary.rb +12 -0
- data/app/models/email.rb +5 -0
- data/app/models/ewis_opt_in.rb +8 -0
- data/app/models/external_url.rb +6 -0
- data/app/models/free_shipping_promotion.rb +12 -0
- data/app/models/import.rb +6 -0
- data/app/models/import_entry.rb +6 -0
- data/app/models/line_item.rb +34 -0
- data/app/models/line_item_discount.rb +7 -0
- data/app/models/markdown_price.rb +11 -0
- data/app/models/menu.rb +36 -0
- data/app/models/menu_item.rb +7 -0
- data/app/models/menu_item_item.rb +5 -0
- data/app/models/note.rb +18 -0
- data/app/models/order.rb +38 -0
- data/app/models/password_recovery.rb +20 -0
- data/app/models/payment_address_verification.rb +13 -0
- data/app/models/payment_process.rb +13 -0
- data/app/models/payment_provider.rb +15 -0
- data/app/models/payment_transaction.rb +13 -0
- data/app/models/product.rb +99 -0
- data/app/models/product_asset_file.rb +12 -0
- data/app/models/promotion.rb +19 -0
- data/app/models/promotion_qualifying_product_exclusion.rb +8 -0
- data/app/models/redirect.rb +14 -0
- data/app/models/refund.rb +14 -0
- data/app/models/remote_address.rb +22 -0
- data/app/models/remote_line_item.rb +11 -0
- data/app/models/remote_order.rb +15 -0
- data/app/models/remote_shipping_method.rb +12 -0
- data/app/models/report.rb +18 -0
- data/app/models/report_invocation.rb +18 -0
- data/app/models/retail_store.rb +18 -0
- data/app/models/role.rb +6 -0
- data/app/models/search_suggestion.rb +17 -0
- data/app/models/section.rb +9 -0
- data/app/models/session.rb +8 -0
- data/app/models/shipping_method.rb +26 -0
- data/app/models/slug.rb +19 -0
- data/app/models/static_page.rb +60 -0
- data/app/models/static_page_folder.rb +8 -0
- data/app/models/stock_level.rb +21 -0
- data/app/models/tax_code.rb +6 -0
- data/app/models/taxonomy.rb +5 -0
- data/app/models/template.rb +9 -0
- data/app/models/template_component.rb +11 -0
- data/app/models/template_definition.rb +12 -0
- data/app/models/template_section.rb +12 -0
- data/app/models/user.rb +8 -0
- data/app/models/user_profile.rb +6 -0
- data/app/models/v2/create_order.rb +10 -0
- data/app/models/v2/deallocate_order.rb +10 -0
- data/app/models/v2/line_item.rb +9 -0
- data/app/models/v2/order.rb +9 -0
- data/app/models/v2/unallocate_order.rb +10 -0
- data/app/models/variant.rb +18 -0
- data/app/models/webhook.rb +17 -0
- data/app/services/param_to_shql.rb +72 -0
- data/app/services/surrogate_keys.rb +44 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/config/locales/payments.en.yml +3 -0
- data/flex-commerce-api.gemspec +41 -0
- data/lib/flex_commerce.rb +95 -0
- data/lib/flex_commerce_api.rb +21 -0
- data/lib/flex_commerce_api/api_base.rb +11 -0
- data/lib/flex_commerce_api/base_resource.rb +250 -0
- data/lib/flex_commerce_api/config.rb +55 -0
- data/lib/flex_commerce_api/error/access_denied.rb +6 -0
- data/lib/flex_commerce_api/error/bad_request.rb +10 -0
- data/lib/flex_commerce_api/error/base.rb +12 -0
- data/lib/flex_commerce_api/error/client_error.rb +7 -0
- data/lib/flex_commerce_api/error/connection_error.rb +6 -0
- data/lib/flex_commerce_api/error/internal_server.rb +37 -0
- data/lib/flex_commerce_api/error/not_found.rb +13 -0
- data/lib/flex_commerce_api/error/record_invalid.rb +16 -0
- data/lib/flex_commerce_api/error/unexpected_status.rb +7 -0
- data/lib/flex_commerce_api/errors.rb +13 -0
- data/lib/flex_commerce_api/json_api_client_extension/builder.rb +28 -0
- data/lib/flex_commerce_api/json_api_client_extension/capture_surrogate_keys_middleware.rb +16 -0
- data/lib/flex_commerce_api/json_api_client_extension/flexible_connection.rb +59 -0
- data/lib/flex_commerce_api/json_api_client_extension/has_many_association_proxy.rb +60 -0
- data/lib/flex_commerce_api/json_api_client_extension/included_data.rb +27 -0
- data/lib/flex_commerce_api/json_api_client_extension/json_format_middleware.rb +20 -0
- data/lib/flex_commerce_api/json_api_client_extension/logging_middleware.rb +24 -0
- data/lib/flex_commerce_api/json_api_client_extension/paginator.rb +26 -0
- data/lib/flex_commerce_api/json_api_client_extension/parse_json.rb +23 -0
- data/lib/flex_commerce_api/json_api_client_extension/parsers/parser.rb +16 -0
- data/lib/flex_commerce_api/json_api_client_extension/previewed_request_middleware.rb +17 -0
- data/lib/flex_commerce_api/json_api_client_extension/remote_builder.rb +29 -0
- data/lib/flex_commerce_api/json_api_client_extension/requestor.rb +42 -0
- data/lib/flex_commerce_api/json_api_client_extension/save_request_body_middleware.rb +20 -0
- data/lib/flex_commerce_api/json_api_client_extension/status_middleware.rb +40 -0
- data/lib/flex_commerce_api/v2/api_base.rb +13 -0
- data/lib/flex_commerce_api/version.rb +3 -0
- data/lib/json_erb.rb +9 -0
- data/lib/json_struct.rb +73 -0
- data/lib/patches.rb +4 -0
- data/lib/patches/json_api_client/resource.rb +50 -0
- data/lib/paypal_express.rb +3 -0
- data/lib/paypal_express/additional_info.rb +45 -0
- data/lib/paypal_express/api.rb +86 -0
- data/lib/paypal_express/auth.rb +83 -0
- data/lib/paypal_express/cart_shipping_method.rb +38 -0
- data/lib/paypal_express/exception/access_denied.rb +10 -0
- data/lib/paypal_express/exception/connection_error.rb +10 -0
- data/lib/paypal_express/exception/not_authorized.rb +10 -0
- data/lib/paypal_express/exception/transaction.rb +15 -0
- data/lib/paypal_express/generate_summary.rb +118 -0
- data/lib/paypal_express/process/paypal_params.rb +123 -0
- data/lib/paypal_express/process/response_parser.rb +146 -0
- data/lib/paypal_express/setup.rb +94 -0
- data/lib/paypal_express/shipping_methods_for_cart.rb +46 -0
- data/lib/retry.rb +20 -0
- data/schemas/jsonapi/schema.json +370 -0
- data/schemas/shift/v1/documents/collection/address.json +45 -0
- data/schemas/shift/v1/documents/collection/asset_file.json +43 -0
- data/schemas/shift/v1/documents/collection/asset_folder.json +43 -0
- data/schemas/shift/v1/documents/collection/customer_account.json +50 -0
- data/schemas/shift/v1/documents/collection/markdown_price.json +43 -0
- data/schemas/shift/v1/documents/collection/product.json +43 -0
- data/schemas/shift/v1/documents/collection/variant.json +43 -0
- data/schemas/shift/v1/documents/member/address.json +39 -0
- data/schemas/shift/v1/documents/member/asset_file.json +37 -0
- data/schemas/shift/v1/documents/member/asset_folder.json +39 -0
- data/schemas/shift/v1/documents/member/customer_account.json +44 -0
- data/schemas/shift/v1/documents/member/markdown_price.json +37 -0
- data/schemas/shift/v1/documents/member/product.json +39 -0
- data/schemas/shift/v1/documents/member/variant.json +46 -0
- data/schemas/shift/v1/resources/address.json +130 -0
- data/schemas/shift/v1/resources/asset_file.json +146 -0
- data/schemas/shift/v1/resources/asset_folder.json +188 -0
- data/schemas/shift/v1/resources/customer_account.json +339 -0
- data/schemas/shift/v1/resources/markdown_price.json +52 -0
- data/schemas/shift/v1/resources/product.json +230 -0
- data/schemas/shift/v1/resources/variant.json +298 -0
- data/tasks/json_schema.thor +275 -0
- data/todo.md +8 -0
- metadata +470 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'bigdecimal'
|
|
2
|
+
|
|
3
|
+
# @module FlexCommerce::PaypalExpress
|
|
4
|
+
module FlexCommerce
|
|
5
|
+
module PaypalExpress
|
|
6
|
+
# @class CartShippingMethod
|
|
7
|
+
#
|
|
8
|
+
# Used to decorate shipping methods based on Promotions
|
|
9
|
+
class CartShippingMethod < SimpleDelegator
|
|
10
|
+
|
|
11
|
+
ZERO = BigDecimal.new(0)
|
|
12
|
+
|
|
13
|
+
def initialize(shipping_method, free)
|
|
14
|
+
super(shipping_method)
|
|
15
|
+
self.free = free
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def is_free?
|
|
19
|
+
free
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def total
|
|
23
|
+
return ZERO if is_free?
|
|
24
|
+
super
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def tax
|
|
28
|
+
return ZERO if is_free?
|
|
29
|
+
super
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
attr_accessor :free
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module FlexCommerce
|
|
2
|
+
module PaypalExpress
|
|
3
|
+
module Exception
|
|
4
|
+
class Transaction < ::StandardError
|
|
5
|
+
attr_accessor :transaction_id, :gateway_transaction_id, :response
|
|
6
|
+
def initialize(message, options = {})
|
|
7
|
+
options.each_pair do |attr, value|
|
|
8
|
+
try("#{attr}=".to_sym, value)
|
|
9
|
+
end
|
|
10
|
+
super(message)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
require_relative 'api'
|
|
2
|
+
|
|
3
|
+
# @module FlexCommerce::PaypalExpress
|
|
4
|
+
module FlexCommerce
|
|
5
|
+
module PaypalExpress
|
|
6
|
+
# @class GenerateSummary
|
|
7
|
+
#
|
|
8
|
+
# This class is used while setting up the paypal for FE
|
|
9
|
+
# It deals with line items total, sub total, tax calculations and
|
|
10
|
+
# Also deals with discounted line items and discounts inorder to send to paypal
|
|
11
|
+
#
|
|
12
|
+
class GenerateSummary
|
|
13
|
+
include ::FlexCommerce::PaypalExpress::Api
|
|
14
|
+
|
|
15
|
+
def initialize(cart: , use_tax: false)
|
|
16
|
+
self.cart = cart
|
|
17
|
+
self.use_tax = use_tax
|
|
18
|
+
raise "use_tax is not yet supported. FlexCommerce::PaypalExpress::GenerateSummary should support it in the future" if use_tax
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @method call
|
|
22
|
+
#
|
|
23
|
+
# @returns an object with subtotal, tax, handling, shipping and items keys
|
|
24
|
+
def call
|
|
25
|
+
{
|
|
26
|
+
subtotal: subtotal,
|
|
27
|
+
tax: tax,
|
|
28
|
+
handling: handling,
|
|
29
|
+
shipping: shipping,
|
|
30
|
+
items: items
|
|
31
|
+
}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
# @method subtotal
|
|
37
|
+
#
|
|
38
|
+
# @returns the sum of line items total. This doesnt include any promotions
|
|
39
|
+
def subtotal
|
|
40
|
+
items.sum {|i| i[:quantity] * (i[:amount])}
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# @method total
|
|
44
|
+
#
|
|
45
|
+
# @return amount after converting cart total from pence to pounds
|
|
46
|
+
def total
|
|
47
|
+
convert_amount(cart.total)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @method tax
|
|
51
|
+
#
|
|
52
|
+
# @returns the sum of total line items tax
|
|
53
|
+
def tax
|
|
54
|
+
items.sum {|i| i[:tax] * i[:quantity]}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# @method handling
|
|
58
|
+
#
|
|
59
|
+
# @returns Payment handling charges, which is 0
|
|
60
|
+
def handling
|
|
61
|
+
0
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @method shipping
|
|
65
|
+
#
|
|
66
|
+
# @returns 0 if cart is eligible for free shipping
|
|
67
|
+
# @returns cart.shipping_total, if cart is not eligibl for free shipping
|
|
68
|
+
def shipping
|
|
69
|
+
return 0 if cart.free_shipping
|
|
70
|
+
convert_amount(cart.shipping_total)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# @mthod items
|
|
74
|
+
#
|
|
75
|
+
# @returns both line items and discounts
|
|
76
|
+
def items
|
|
77
|
+
normal_items + discount_items
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# @method discounts
|
|
81
|
+
#
|
|
82
|
+
# @returns [] if there are no discounts on cart
|
|
83
|
+
# @returns Array containing about the total discount amount, if any applied.
|
|
84
|
+
def discount_items
|
|
85
|
+
return [] if cart.total_discount == 0
|
|
86
|
+
[
|
|
87
|
+
{
|
|
88
|
+
name: "Total discounts",
|
|
89
|
+
number: "NA",
|
|
90
|
+
quantity: 1,
|
|
91
|
+
amount: convert_amount(BigDecimal(0) - cart.total_discount),
|
|
92
|
+
description: "Total discounts",
|
|
93
|
+
tax: 0
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# @method normal_items
|
|
99
|
+
#
|
|
100
|
+
# @returns Object, the normal line items added to cart
|
|
101
|
+
# @note these line items unit prices will be without any discounts
|
|
102
|
+
def normal_items
|
|
103
|
+
@normal_items ||= cart.line_items.map do |li|
|
|
104
|
+
{
|
|
105
|
+
name: li.title,
|
|
106
|
+
number: li.item.sku,
|
|
107
|
+
quantity: li.unit_quantity,
|
|
108
|
+
amount: convert_amount(li.unit_price),
|
|
109
|
+
description: li.title,
|
|
110
|
+
tax: 0
|
|
111
|
+
}
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
attr_accessor :cart, :use_tax
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
require 'paypal_express/api'
|
|
2
|
+
|
|
3
|
+
# @module FlexCommerce::PaypalExpress::Process
|
|
4
|
+
module FlexCommerce
|
|
5
|
+
module PaypalExpress
|
|
6
|
+
module Process
|
|
7
|
+
# @class PaypalParams
|
|
8
|
+
class PaypalParams
|
|
9
|
+
include ::FlexCommerce::PaypalExpress::Api
|
|
10
|
+
|
|
11
|
+
DEFAULT_DESCRIPTION = "Shift Commerce Order".freeze
|
|
12
|
+
|
|
13
|
+
# @initialize
|
|
14
|
+
#
|
|
15
|
+
# @param {FlexCommerce::PaymentProviderSetup} payment_provider_setup
|
|
16
|
+
# @param {FlexCommerce::Cart} cart
|
|
17
|
+
# @param {Paypal Gateway} [gateway_class = ::ActiveMerchant::Billing::PaypalExpressGateway]
|
|
18
|
+
# @param {URL} success_url - Generally Paypal confirmation page
|
|
19
|
+
# @param {URL} cancel_url - Generally new transaction page
|
|
20
|
+
# @param {IP} ip_address - User ip address
|
|
21
|
+
# @param {boolean} [allow_shipping_change = true] - true: display shipping options, false: dont display shipping options
|
|
22
|
+
# @param {URL} callback_url - Generally cart show page
|
|
23
|
+
# @param {FlexCommerce::ShippingMethod} shipping_method_model = FlexCommerce::ShippingMethod
|
|
24
|
+
# @param {boolean} [use_mobile_payments = false]
|
|
25
|
+
# @param {String} [description]
|
|
26
|
+
#
|
|
27
|
+
def initialize(cart:,success_url:, cancel_url:, ip_address:, allow_shipping_change: true, callback_url:, shipping_method_model: FlexCommerce::ShippingMethod, use_mobile_payments: false, description:)
|
|
28
|
+
self.cart = cart
|
|
29
|
+
self.allow_shipping_change = allow_shipping_change
|
|
30
|
+
self.success_url = success_url
|
|
31
|
+
self.cancel_url = cancel_url
|
|
32
|
+
self.ip_address = ip_address
|
|
33
|
+
self.callback_url = callback_url
|
|
34
|
+
self.shipping_method_model = shipping_method_model
|
|
35
|
+
self.use_mobile_payments = use_mobile_payments
|
|
36
|
+
self.description = description
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def call
|
|
40
|
+
base_paypal_params
|
|
41
|
+
.merge(paypal_shipping_address_params)
|
|
42
|
+
.merge(paypal_items)
|
|
43
|
+
.merge(ui_callback_params)
|
|
44
|
+
.merge(shipping_options_params)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
attr_accessor :description, :cart, :success_url, :cancel_url, :ip_address, :allow_shipping_change, :callback_url, :shipping_method_model, :use_mobile_payments
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def paypal_shipping_address_params
|
|
52
|
+
return {} unless cart.shipping_address
|
|
53
|
+
shipping_address = cart.shipping_address
|
|
54
|
+
{
|
|
55
|
+
address_override: true,
|
|
56
|
+
shipping_address: {
|
|
57
|
+
name: "#{shipping_address.first_name} #{shipping_address.middle_names} #{shipping_address.last_name}",
|
|
58
|
+
address1: shipping_address.address_line_1,
|
|
59
|
+
address2: "#{shipping_address.address_line_2} #{shipping_address.address_line_3}",
|
|
60
|
+
city: shipping_address.city,
|
|
61
|
+
state: shipping_address.state,
|
|
62
|
+
country: shipping_address.country,
|
|
63
|
+
zip: shipping_address.postcode
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def base_paypal_params
|
|
70
|
+
{
|
|
71
|
+
currency: "GBP",
|
|
72
|
+
description: description || DEFAULT_DESCRIPTION,
|
|
73
|
+
ip: ip_address,
|
|
74
|
+
return_url: success_url,
|
|
75
|
+
cancel_return_url: cancel_url,
|
|
76
|
+
subtotal: summary[:subtotal], # As the cart total wont include any shipping if it has no shipping method
|
|
77
|
+
handling: summary[:handling],
|
|
78
|
+
tax: 0,
|
|
79
|
+
shipping: summary[:shipping]
|
|
80
|
+
}
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def paypal_items
|
|
84
|
+
items = summary[:items]
|
|
85
|
+
{items: items}
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def ui_callback_params
|
|
89
|
+
return {} unless allow_shipping_change && shipping_methods.count > 0
|
|
90
|
+
{
|
|
91
|
+
callback_url: callback_url,
|
|
92
|
+
callback_timeout: 6,
|
|
93
|
+
callback_version: 95,
|
|
94
|
+
max_amount: convert_amount((cart.total * 1.2) + shipping_methods.last.total + shipping_methods.last.tax)
|
|
95
|
+
}
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# @method shipping_methods
|
|
99
|
+
#
|
|
100
|
+
# @returns shipping methods with promotions applied
|
|
101
|
+
def shipping_methods
|
|
102
|
+
@shipping_methods ||= ShippingMethodsForCart.new(cart: cart, shipping_methods: shipping_method_model.all).call.sort_by(&:total)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def shipping_method
|
|
106
|
+
cart.shipping_method || shipping_methods.first
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def shipping_options_params
|
|
110
|
+
return { shipping_options: [] } if !allow_shipping_change || shipping_method.nil?
|
|
111
|
+
shipping_method_id = shipping_method.id
|
|
112
|
+
{
|
|
113
|
+
shipping_options: shipping_methods.map {|sm| {name: sm.label, amount: convert_amount(sm.total), default: sm.id == shipping_method_id, label: "#{sm.description}#{sm.id}"}}
|
|
114
|
+
}
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def summary
|
|
118
|
+
@summary ||= GenerateSummary.new(cart: cart).call
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# @module FlexCommerce::PaypalExpress::Process
|
|
2
|
+
module FlexCommerce
|
|
3
|
+
module PaypalExpress
|
|
4
|
+
module Process
|
|
5
|
+
# @class ResponseParser
|
|
6
|
+
class ResponseParser
|
|
7
|
+
|
|
8
|
+
def initialize(response:, shipping_method_model:)
|
|
9
|
+
self.response = response
|
|
10
|
+
self.shipping_method_model = shipping_method_model
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @TODO: Need to validate the paypal response, to ensure it is
|
|
14
|
+
# returning all the attribute values as expected
|
|
15
|
+
# Related ticket: https://github.com/shiftcommerce/flex-ruby-gem/issues/152
|
|
16
|
+
#
|
|
17
|
+
def call
|
|
18
|
+
{
|
|
19
|
+
shipping_method_id: get_shipping_method_details,
|
|
20
|
+
email: get_email_address,
|
|
21
|
+
shipping_address_attributes: get_shipping_address_attributes,
|
|
22
|
+
billing_address_attributes: get_billing_address_attributes
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
attr_accessor :response, :shipping_method_model
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
# @method get_shipping_method_details
|
|
31
|
+
#
|
|
32
|
+
# Currently, Paypal will only return the shipping_option_name param
|
|
33
|
+
# which contains the shipping method label. Using this, we need to find
|
|
34
|
+
# the shipping method id and return it.
|
|
35
|
+
# @TODO: Incase of its missing, currently we are returning nil value. But ideally
|
|
36
|
+
# we have to log this error, just to ensure it is not platform issue.
|
|
37
|
+
#
|
|
38
|
+
def get_shipping_method_details
|
|
39
|
+
if response.params["shipping_option_name"]
|
|
40
|
+
shipping_option_name = response.params["shipping_option_name"]
|
|
41
|
+
shipping_method = find_shipping_method(shipping_option_name)
|
|
42
|
+
raise "Shipping method #{response.params["shipping_option_name"]} not found\n\nExact response from paypal were: \n#{response.to_json}" unless shipping_method
|
|
43
|
+
shipping_method.id
|
|
44
|
+
else
|
|
45
|
+
nil
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @!visibility private
|
|
50
|
+
#
|
|
51
|
+
# Currently Paypal is returning only shipping method label.
|
|
52
|
+
# And we cannot query for shipping method by using the label, so
|
|
53
|
+
# We are fetching all the shipping methods and filtering them by label
|
|
54
|
+
#
|
|
55
|
+
def find_shipping_method(shipping_option_name)
|
|
56
|
+
all_shipping_methods = shipping_method_model.all
|
|
57
|
+
sm = all_shipping_methods.select { |sm| sm.label == shipping_option_name }.first
|
|
58
|
+
sm ||= all_shipping_methods.select{ |sm| sm.label == de_dup_shipping_option_name(shipping_option_name) }.first
|
|
59
|
+
sm
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @!visibility private
|
|
63
|
+
#
|
|
64
|
+
# COPIED this comments from flex-platform code
|
|
65
|
+
#
|
|
66
|
+
# This is temporary but will do no harm if left in
|
|
67
|
+
# When paypal calls the "callback url" to get the list of shipping options
|
|
68
|
+
# then, the user clicks on "buy" - the resulting shipping method name is duplicated
|
|
69
|
+
# so, if you had "Shipping method 1" - you would get "Shipping method 1 Shipping method 1"
|
|
70
|
+
# This method looks for that duplication and removes it
|
|
71
|
+
# @TODO Debug system thoroughly to find the root cause of this
|
|
72
|
+
def de_dup_shipping_option_name(str)
|
|
73
|
+
parts = str.split(" ")
|
|
74
|
+
if parts.length.even?
|
|
75
|
+
mid = parts.length / 2
|
|
76
|
+
lft = parts[0...mid]
|
|
77
|
+
right = parts[mid..-1]
|
|
78
|
+
if lft == right
|
|
79
|
+
lft.join(" ")
|
|
80
|
+
else
|
|
81
|
+
str
|
|
82
|
+
end
|
|
83
|
+
else
|
|
84
|
+
str
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# @method get_shipping_address_attributes
|
|
89
|
+
#
|
|
90
|
+
# Paypal will return shipping address in PaymentDetails.ShipToAddress Object
|
|
91
|
+
#
|
|
92
|
+
def get_shipping_address_attributes
|
|
93
|
+
convert_address(response.params["PaymentDetails"]["ShipToAddress"])
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# @method get_billing_address_attributes
|
|
97
|
+
#
|
|
98
|
+
# Paypal will return shipping address in PayerInfo.Address Object
|
|
99
|
+
#
|
|
100
|
+
def get_billing_address_attributes
|
|
101
|
+
convert_address(response.params["PayerInfo"]["Address"])
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# @method get_billing_address_attributes
|
|
105
|
+
#
|
|
106
|
+
# Paypal will return shipping address in PayerInfo.Payer Object
|
|
107
|
+
#
|
|
108
|
+
def get_email_address
|
|
109
|
+
response.params["PayerInfo"]["Payer"]
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# @!visibility private
|
|
113
|
+
#
|
|
114
|
+
def convert_address(paypal_address)
|
|
115
|
+
mapping = address_direct_mapping
|
|
116
|
+
name_words = paypal_address["Name"].split(" ")
|
|
117
|
+
attrs = {
|
|
118
|
+
"first_name" => name_words.shift,
|
|
119
|
+
"last_name" => name_words.pop || "",
|
|
120
|
+
"middle_names" => name_words.join(" ")
|
|
121
|
+
}
|
|
122
|
+
paypal_address.inject(attrs) do |acc, (field, value)|
|
|
123
|
+
if mapping.key?(field)
|
|
124
|
+
acc.merge(mapping[field] => value || "")
|
|
125
|
+
else
|
|
126
|
+
acc
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# @!visibility private
|
|
132
|
+
#
|
|
133
|
+
def address_direct_mapping
|
|
134
|
+
{
|
|
135
|
+
"Street1" => "address_line_1",
|
|
136
|
+
"Street2" => "address_line_2",
|
|
137
|
+
"CityName" => "city",
|
|
138
|
+
"StateOrProvince" => "state",
|
|
139
|
+
"Country" => "country",
|
|
140
|
+
"PostalCode" => "postcode"
|
|
141
|
+
}
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|