flex_commerce_api 0.6.57

Sign up to get free protection for your applications and to get access to all the features.
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