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.
Files changed (170) hide show
  1. checksums.yaml +7 -0
  2. data/.env.example +6 -0
  3. data/.gitignore +14 -0
  4. data/.rspec +4 -0
  5. data/.rubocop.yml +1065 -0
  6. data/.ruby-gemset +1 -0
  7. data/.ruby-version +1 -0
  8. data/.travis.yml +3 -0
  9. data/Gemfile +4 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +56 -0
  12. data/Rakefile +1 -0
  13. data/app/models/address.rb +41 -0
  14. data/app/models/asset_file.rb +26 -0
  15. data/app/models/asset_folder.rb +14 -0
  16. data/app/models/bundle.rb +20 -0
  17. data/app/models/bundle_group.rb +15 -0
  18. data/app/models/cart.rb +136 -0
  19. data/app/models/category.rb +70 -0
  20. data/app/models/category_tree.rb +11 -0
  21. data/app/models/component.rb +8 -0
  22. data/app/models/container_coupon.rb +12 -0
  23. data/app/models/country.rb +11 -0
  24. data/app/models/coupon.rb +18 -0
  25. data/app/models/customer_account.rb +96 -0
  26. data/app/models/customer_account_authentication.rb +5 -0
  27. data/app/models/customer_segment.rb +6 -0
  28. data/app/models/customer_segment_member.rb +6 -0
  29. data/app/models/data_attribute.rb +6 -0
  30. data/app/models/data_store_record.rb +9 -0
  31. data/app/models/data_store_type.rb +9 -0
  32. data/app/models/discount_summary.rb +12 -0
  33. data/app/models/email.rb +5 -0
  34. data/app/models/ewis_opt_in.rb +8 -0
  35. data/app/models/external_url.rb +6 -0
  36. data/app/models/free_shipping_promotion.rb +12 -0
  37. data/app/models/import.rb +6 -0
  38. data/app/models/import_entry.rb +6 -0
  39. data/app/models/line_item.rb +34 -0
  40. data/app/models/line_item_discount.rb +7 -0
  41. data/app/models/markdown_price.rb +11 -0
  42. data/app/models/menu.rb +36 -0
  43. data/app/models/menu_item.rb +7 -0
  44. data/app/models/menu_item_item.rb +5 -0
  45. data/app/models/note.rb +18 -0
  46. data/app/models/order.rb +38 -0
  47. data/app/models/password_recovery.rb +20 -0
  48. data/app/models/payment_address_verification.rb +13 -0
  49. data/app/models/payment_process.rb +13 -0
  50. data/app/models/payment_provider.rb +15 -0
  51. data/app/models/payment_transaction.rb +13 -0
  52. data/app/models/product.rb +99 -0
  53. data/app/models/product_asset_file.rb +12 -0
  54. data/app/models/promotion.rb +19 -0
  55. data/app/models/promotion_qualifying_product_exclusion.rb +8 -0
  56. data/app/models/redirect.rb +14 -0
  57. data/app/models/refund.rb +14 -0
  58. data/app/models/remote_address.rb +22 -0
  59. data/app/models/remote_line_item.rb +11 -0
  60. data/app/models/remote_order.rb +15 -0
  61. data/app/models/remote_shipping_method.rb +12 -0
  62. data/app/models/report.rb +18 -0
  63. data/app/models/report_invocation.rb +18 -0
  64. data/app/models/retail_store.rb +18 -0
  65. data/app/models/role.rb +6 -0
  66. data/app/models/search_suggestion.rb +17 -0
  67. data/app/models/section.rb +9 -0
  68. data/app/models/session.rb +8 -0
  69. data/app/models/shipping_method.rb +26 -0
  70. data/app/models/slug.rb +19 -0
  71. data/app/models/static_page.rb +60 -0
  72. data/app/models/static_page_folder.rb +8 -0
  73. data/app/models/stock_level.rb +21 -0
  74. data/app/models/tax_code.rb +6 -0
  75. data/app/models/taxonomy.rb +5 -0
  76. data/app/models/template.rb +9 -0
  77. data/app/models/template_component.rb +11 -0
  78. data/app/models/template_definition.rb +12 -0
  79. data/app/models/template_section.rb +12 -0
  80. data/app/models/user.rb +8 -0
  81. data/app/models/user_profile.rb +6 -0
  82. data/app/models/v2/create_order.rb +10 -0
  83. data/app/models/v2/deallocate_order.rb +10 -0
  84. data/app/models/v2/line_item.rb +9 -0
  85. data/app/models/v2/order.rb +9 -0
  86. data/app/models/v2/unallocate_order.rb +10 -0
  87. data/app/models/variant.rb +18 -0
  88. data/app/models/webhook.rb +17 -0
  89. data/app/services/param_to_shql.rb +72 -0
  90. data/app/services/surrogate_keys.rb +44 -0
  91. data/bin/console +14 -0
  92. data/bin/setup +7 -0
  93. data/config/locales/payments.en.yml +3 -0
  94. data/flex-commerce-api.gemspec +41 -0
  95. data/lib/flex_commerce.rb +95 -0
  96. data/lib/flex_commerce_api.rb +21 -0
  97. data/lib/flex_commerce_api/api_base.rb +11 -0
  98. data/lib/flex_commerce_api/base_resource.rb +250 -0
  99. data/lib/flex_commerce_api/config.rb +55 -0
  100. data/lib/flex_commerce_api/error/access_denied.rb +6 -0
  101. data/lib/flex_commerce_api/error/bad_request.rb +10 -0
  102. data/lib/flex_commerce_api/error/base.rb +12 -0
  103. data/lib/flex_commerce_api/error/client_error.rb +7 -0
  104. data/lib/flex_commerce_api/error/connection_error.rb +6 -0
  105. data/lib/flex_commerce_api/error/internal_server.rb +37 -0
  106. data/lib/flex_commerce_api/error/not_found.rb +13 -0
  107. data/lib/flex_commerce_api/error/record_invalid.rb +16 -0
  108. data/lib/flex_commerce_api/error/unexpected_status.rb +7 -0
  109. data/lib/flex_commerce_api/errors.rb +13 -0
  110. data/lib/flex_commerce_api/json_api_client_extension/builder.rb +28 -0
  111. data/lib/flex_commerce_api/json_api_client_extension/capture_surrogate_keys_middleware.rb +16 -0
  112. data/lib/flex_commerce_api/json_api_client_extension/flexible_connection.rb +59 -0
  113. data/lib/flex_commerce_api/json_api_client_extension/has_many_association_proxy.rb +60 -0
  114. data/lib/flex_commerce_api/json_api_client_extension/included_data.rb +27 -0
  115. data/lib/flex_commerce_api/json_api_client_extension/json_format_middleware.rb +20 -0
  116. data/lib/flex_commerce_api/json_api_client_extension/logging_middleware.rb +24 -0
  117. data/lib/flex_commerce_api/json_api_client_extension/paginator.rb +26 -0
  118. data/lib/flex_commerce_api/json_api_client_extension/parse_json.rb +23 -0
  119. data/lib/flex_commerce_api/json_api_client_extension/parsers/parser.rb +16 -0
  120. data/lib/flex_commerce_api/json_api_client_extension/previewed_request_middleware.rb +17 -0
  121. data/lib/flex_commerce_api/json_api_client_extension/remote_builder.rb +29 -0
  122. data/lib/flex_commerce_api/json_api_client_extension/requestor.rb +42 -0
  123. data/lib/flex_commerce_api/json_api_client_extension/save_request_body_middleware.rb +20 -0
  124. data/lib/flex_commerce_api/json_api_client_extension/status_middleware.rb +40 -0
  125. data/lib/flex_commerce_api/v2/api_base.rb +13 -0
  126. data/lib/flex_commerce_api/version.rb +3 -0
  127. data/lib/json_erb.rb +9 -0
  128. data/lib/json_struct.rb +73 -0
  129. data/lib/patches.rb +4 -0
  130. data/lib/patches/json_api_client/resource.rb +50 -0
  131. data/lib/paypal_express.rb +3 -0
  132. data/lib/paypal_express/additional_info.rb +45 -0
  133. data/lib/paypal_express/api.rb +86 -0
  134. data/lib/paypal_express/auth.rb +83 -0
  135. data/lib/paypal_express/cart_shipping_method.rb +38 -0
  136. data/lib/paypal_express/exception/access_denied.rb +10 -0
  137. data/lib/paypal_express/exception/connection_error.rb +10 -0
  138. data/lib/paypal_express/exception/not_authorized.rb +10 -0
  139. data/lib/paypal_express/exception/transaction.rb +15 -0
  140. data/lib/paypal_express/generate_summary.rb +118 -0
  141. data/lib/paypal_express/process/paypal_params.rb +123 -0
  142. data/lib/paypal_express/process/response_parser.rb +146 -0
  143. data/lib/paypal_express/setup.rb +94 -0
  144. data/lib/paypal_express/shipping_methods_for_cart.rb +46 -0
  145. data/lib/retry.rb +20 -0
  146. data/schemas/jsonapi/schema.json +370 -0
  147. data/schemas/shift/v1/documents/collection/address.json +45 -0
  148. data/schemas/shift/v1/documents/collection/asset_file.json +43 -0
  149. data/schemas/shift/v1/documents/collection/asset_folder.json +43 -0
  150. data/schemas/shift/v1/documents/collection/customer_account.json +50 -0
  151. data/schemas/shift/v1/documents/collection/markdown_price.json +43 -0
  152. data/schemas/shift/v1/documents/collection/product.json +43 -0
  153. data/schemas/shift/v1/documents/collection/variant.json +43 -0
  154. data/schemas/shift/v1/documents/member/address.json +39 -0
  155. data/schemas/shift/v1/documents/member/asset_file.json +37 -0
  156. data/schemas/shift/v1/documents/member/asset_folder.json +39 -0
  157. data/schemas/shift/v1/documents/member/customer_account.json +44 -0
  158. data/schemas/shift/v1/documents/member/markdown_price.json +37 -0
  159. data/schemas/shift/v1/documents/member/product.json +39 -0
  160. data/schemas/shift/v1/documents/member/variant.json +46 -0
  161. data/schemas/shift/v1/resources/address.json +130 -0
  162. data/schemas/shift/v1/resources/asset_file.json +146 -0
  163. data/schemas/shift/v1/resources/asset_folder.json +188 -0
  164. data/schemas/shift/v1/resources/customer_account.json +339 -0
  165. data/schemas/shift/v1/resources/markdown_price.json +52 -0
  166. data/schemas/shift/v1/resources/product.json +230 -0
  167. data/schemas/shift/v1/resources/variant.json +298 -0
  168. data/tasks/json_schema.thor +275 -0
  169. data/todo.md +8 -0
  170. 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,10 @@
1
+ require_relative 'transaction'
2
+
3
+ module FlexCommerce
4
+ module PaypalExpress
5
+ module Exception
6
+ class AccessDenied < Transaction
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'transaction'
2
+
3
+ module FlexCommerce
4
+ module PaypalExpress
5
+ module Exception
6
+ class ConnectionError < Transaction
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ require_relative 'transaction'
2
+
3
+ module FlexCommerce
4
+ module PaypalExpress
5
+ module Exception
6
+ class NotAuthorized < Transaction
7
+ end
8
+ end
9
+ end
10
+ 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