workarea-global_e 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (232) hide show
  1. checksums.yaml +7 -0
  2. data/.eslintrc.json +37 -0
  3. data/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
  4. data/.github/ISSUE_TEMPLATE/documentation-request.md +17 -0
  5. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  6. data/.github/workflows/ci.yml +77 -0
  7. data/.gitignore +20 -0
  8. data/.rubocop.yml +2 -0
  9. data/.ruby-version +1 -0
  10. data/CHANGELOG.md +261 -0
  11. data/Gemfile +16 -0
  12. data/README.md +39 -0
  13. data/Rakefile +59 -0
  14. data/app/assets/javascripts/workarea/storefront/global_e/modules/checkout_info_validator.js +122 -0
  15. data/app/assets/javascripts/workarea/storefront/global_e/modules/suppress_price_ranges.js +19 -0
  16. data/app/controllers/workarea/admin/country_exceptions_controller.rb +67 -0
  17. data/app/controllers/workarea/admin/fixed_prices_controller.rb +89 -0
  18. data/app/controllers/workarea/admin/orders_controller.decorator +6 -0
  19. data/app/controllers/workarea/storefront/application_controller.decorator +30 -0
  20. data/app/controllers/workarea/storefront/checkouts_controller.decorator +22 -0
  21. data/app/controllers/workarea/storefront/ge_checkouts_controller.rb +10 -0
  22. data/app/controllers/workarea/storefront/global_e_controller.rb +42 -0
  23. data/app/controllers/workarea/storefront/globale/api_controller.rb +108 -0
  24. data/app/controllers/workarea/storefront/globale/refund_controller.rb +65 -0
  25. data/app/controllers/workarea/storefront/users/logins_controller.decorator +13 -0
  26. data/app/helpers/workarea/admin/global_e_helpers.rb +28 -0
  27. data/app/models/workarea/address.decorator +11 -0
  28. data/app/models/workarea/catalog/product.decorator +14 -0
  29. data/app/models/workarea/fulfillment/status/partially_refunded.rb +13 -0
  30. data/app/models/workarea/fulfillment/status/refunded.rb +15 -0
  31. data/app/models/workarea/fulfillment.decorator +55 -0
  32. data/app/models/workarea/global_e/country_exception.rb +37 -0
  33. data/app/models/workarea/global_e/fixed_price.rb +93 -0
  34. data/app/models/workarea/global_e/order_api_events.rb +29 -0
  35. data/app/models/workarea/order/item.decorator +46 -0
  36. data/app/models/workarea/order/status/pending_global_e_fraud_check.rb +12 -0
  37. data/app/models/workarea/order.decorator +64 -0
  38. data/app/models/workarea/payment/status/global_e_appoved.rb +9 -0
  39. data/app/models/workarea/payment/status/pending_global_e_fraud_check.rb +9 -0
  40. data/app/models/workarea/payment/tender/global_e_payment.rb +16 -0
  41. data/app/models/workarea/payment.decorator +10 -0
  42. data/app/models/workarea/price_adjustment.decorator +13 -0
  43. data/app/models/workarea/price_adjustment_set.decorator +25 -0
  44. data/app/models/workarea/pricing/calculators/item_calculator.decorator +48 -0
  45. data/app/models/workarea/pricing/collection.decorator +90 -0
  46. data/app/models/workarea/pricing/discount/appliation_group.decorator +16 -0
  47. data/app/models/workarea/pricing/discount/international_item_proxy.rb +27 -0
  48. data/app/models/workarea/pricing/discount/international_order.rb +29 -0
  49. data/app/models/workarea/pricing/discount.decorator +65 -0
  50. data/app/models/workarea/pricing/price_distributor.decorator +37 -0
  51. data/app/models/workarea/pricing/request.decorator +17 -0
  52. data/app/models/workarea/pricing/sku.decorator +17 -0
  53. data/app/models/workarea/search/admin/order.decorator +11 -0
  54. data/app/models/workarea/shipping/sku.decorator +23 -0
  55. data/app/models/workarea/shipping.decorator +11 -0
  56. data/app/models/workarea/user.decorator +10 -0
  57. data/app/seeds/workarea/global_e_seeds.rb +66 -0
  58. data/app/services/workarea/create_fulfillment.decorator +12 -0
  59. data/app/services/workarea/global_e/address_details.rb +218 -0
  60. data/app/services/workarea/global_e/api/notify_order_refunded.rb +45 -0
  61. data/app/services/workarea/global_e/api/perform_order_payment.rb +46 -0
  62. data/app/services/workarea/global_e/api/remove_restricted_products.rb +28 -0
  63. data/app/services/workarea/global_e/api/send_order_to_merchant/item_pricer.rb +147 -0
  64. data/app/services/workarea/global_e/api/send_order_to_merchant/save_user.rb +59 -0
  65. data/app/services/workarea/global_e/api/send_order_to_merchant.rb +359 -0
  66. data/app/services/workarea/global_e/api/update_order_shipping_info.rb +38 -0
  67. data/app/services/workarea/global_e/api/update_order_status/canceled.rb +42 -0
  68. data/app/services/workarea/global_e/api/update_order_status.rb +28 -0
  69. data/app/services/workarea/global_e/attribute.rb +44 -0
  70. data/app/services/workarea/global_e/brand.rb +19 -0
  71. data/app/services/workarea/global_e/cart_user_details.rb +34 -0
  72. data/app/services/workarea/global_e/category.rb +19 -0
  73. data/app/services/workarea/global_e/checkout_cart_info.rb +358 -0
  74. data/app/services/workarea/global_e/custom_product_attribute.rb +19 -0
  75. data/app/services/workarea/global_e/discount.rb +215 -0
  76. data/app/services/workarea/global_e/merchant/brand.rb +21 -0
  77. data/app/services/workarea/global_e/merchant/category.rb +21 -0
  78. data/app/services/workarea/global_e/merchant/customer.rb +36 -0
  79. data/app/services/workarea/global_e/merchant/customer_details.rb +201 -0
  80. data/app/services/workarea/global_e/merchant/discount.rb +127 -0
  81. data/app/services/workarea/global_e/merchant/international_details.rb +296 -0
  82. data/app/services/workarea/global_e/merchant/order.rb +425 -0
  83. data/app/services/workarea/global_e/merchant/order_refund.rb +103 -0
  84. data/app/services/workarea/global_e/merchant/original_order.rb +28 -0
  85. data/app/services/workarea/global_e/merchant/parcel_tracking.rb +31 -0
  86. data/app/services/workarea/global_e/merchant/payment_details.rb +161 -0
  87. data/app/services/workarea/global_e/merchant/product.rb +222 -0
  88. data/app/services/workarea/global_e/merchant/refund_product.rb +69 -0
  89. data/app/services/workarea/global_e/merchant/response_info.rb +115 -0
  90. data/app/services/workarea/global_e/merchant_cart_product_attribute.rb +21 -0
  91. data/app/services/workarea/global_e/order_status.rb +20 -0
  92. data/app/services/workarea/global_e/order_status_details.rb +79 -0
  93. data/app/services/workarea/global_e/order_status_reason.rb +20 -0
  94. data/app/services/workarea/global_e/parcel.rb +53 -0
  95. data/app/services/workarea/global_e/product.rb +612 -0
  96. data/app/services/workarea/global_e/product_meta_data.rb +13 -0
  97. data/app/services/workarea/global_e/tracking_details.rb +23 -0
  98. data/app/services/workarea/global_e/update_order_dispatch_exception.rb +46 -0
  99. data/app/services/workarea/global_e/update_order_dispatch_request.rb +108 -0
  100. data/app/services/workarea/global_e/user_id_number_type.rb +21 -0
  101. data/app/services/workarea/global_e/users_details.rb +151 -0
  102. data/app/services/workarea/global_e/vat_category.rb +20 -0
  103. data/app/services/workarea/global_e/vat_rate_type.rb +27 -0
  104. data/app/services/workarea/save_order_analytics.decorator +18 -0
  105. data/app/view_models/workarea/admin/order_view_model.decorator +13 -0
  106. data/app/view_models/workarea/storefront/cart_view_model.decorator +7 -0
  107. data/app/view_models/workarea/storefront/order_item_view_model.decorator +16 -0
  108. data/app/view_models/workarea/storefront/order_view_model.decorator +45 -0
  109. data/app/view_models/workarea/storefront/product_view_model.decorator +35 -0
  110. data/app/views/workarea/admin/catalog_products/_country_exceptions_card.html.haml +31 -0
  111. data/app/views/workarea/admin/catalog_products/_global_e_attributes.html.haml +3 -0
  112. data/app/views/workarea/admin/catalog_products/_global_e_fields.html.haml +4 -0
  113. data/app/views/workarea/admin/country_exceptions/edit.html.haml +48 -0
  114. data/app/views/workarea/admin/country_exceptions/index.html.haml +47 -0
  115. data/app/views/workarea/admin/country_exceptions/new.html.haml +44 -0
  116. data/app/views/workarea/admin/fixed_prices/edit.html.haml +73 -0
  117. data/app/views/workarea/admin/fixed_prices/index.html.haml +55 -0
  118. data/app/views/workarea/admin/fixed_prices/new.html.haml +70 -0
  119. data/app/views/workarea/admin/orders/_global_e.html.haml +27 -0
  120. data/app/views/workarea/admin/orders/attributes.html.haml +131 -0
  121. data/app/views/workarea/admin/orders/global_e.html.haml +110 -0
  122. data/app/views/workarea/admin/orders/show.html.haml +27 -0
  123. data/app/views/workarea/admin/orders/tenders/_global_e_payment.html.haml +3 -0
  124. data/app/views/workarea/admin/pricing_skus/_cards.html.haml +98 -0
  125. data/app/views/workarea/storefront/cart_items/create.html.haml +71 -0
  126. data/app/views/workarea/storefront/carts/_pricing.html.haml +14 -0
  127. data/app/views/workarea/storefront/carts/show.html.haml +187 -0
  128. data/app/views/workarea/storefront/ge_checkouts/show.html.haml +1 -0
  129. data/app/views/workarea/storefront/global_e/_country_picker.html.haml +1 -0
  130. data/app/views/workarea/storefront/global_e/_head.html.haml +10 -0
  131. data/app/views/workarea/storefront/orders/_summary.html.haml +275 -0
  132. data/app/views/workarea/storefront/orders/tenders/_global_e_payment.html.haml +3 -0
  133. data/app/views/workarea/storefront/products/_pricing.html.haml +49 -0
  134. data/app/views/workarea/storefront/products/_restricted_item_text.html.haml +1 -0
  135. data/app/views/workarea/storefront/users/orders/_summary.html.haml +22 -0
  136. data/app/workers/workarea/global_e/update_order_dispatch.rb +28 -0
  137. data/app/workers/workarea/save_user_order_details.decorator +9 -0
  138. data/bin/rails +25 -0
  139. data/config/initializers/appends.rb +46 -0
  140. data/config/initializers/seeds.rb +1 -0
  141. data/config/initializers/workarea.rb +64 -0
  142. data/config/locales/en.yml +105 -0
  143. data/config/routes.rb +31 -0
  144. data/lib/workarea/global_e/engine.rb +10 -0
  145. data/lib/workarea/global_e/error.rb +8 -0
  146. data/lib/workarea/global_e/version.rb +5 -0
  147. data/lib/workarea/global_e.rb +58 -0
  148. data/script/admin_ci +5 -0
  149. data/script/ci +8 -0
  150. data/script/core_ci +5 -0
  151. data/script/plugins_ci +5 -0
  152. data/script/storefront_ci +5 -0
  153. data/test/dummy/.ruby-version +1 -0
  154. data/test/dummy/Rakefile +6 -0
  155. data/test/dummy/app/assets/config/manifest.js +3 -0
  156. data/test/dummy/app/assets/images/.keep +0 -0
  157. data/test/dummy/app/assets/javascripts/application.js +14 -0
  158. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  159. data/test/dummy/app/controllers/application_controller.rb +2 -0
  160. data/test/dummy/app/controllers/concerns/.keep +0 -0
  161. data/test/dummy/app/helpers/application_helper.rb +2 -0
  162. data/test/dummy/app/jobs/application_job.rb +2 -0
  163. data/test/dummy/app/mailers/application_mailer.rb +4 -0
  164. data/test/dummy/app/models/concerns/.keep +0 -0
  165. data/test/dummy/app/views/layouts/application.html.erb +15 -0
  166. data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
  167. data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
  168. data/test/dummy/bin/bundle +3 -0
  169. data/test/dummy/bin/rails +4 -0
  170. data/test/dummy/bin/rake +4 -0
  171. data/test/dummy/bin/setup +28 -0
  172. data/test/dummy/bin/update +28 -0
  173. data/test/dummy/bin/yarn +11 -0
  174. data/test/dummy/config/application.rb +23 -0
  175. data/test/dummy/config/boot.rb +5 -0
  176. data/test/dummy/config/environment.rb +5 -0
  177. data/test/dummy/config/environments/development.rb +52 -0
  178. data/test/dummy/config/environments/production.rb +83 -0
  179. data/test/dummy/config/environments/test.rb +45 -0
  180. data/test/dummy/config/initializers/application_controller_renderer.rb +8 -0
  181. data/test/dummy/config/initializers/assets.rb +14 -0
  182. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  183. data/test/dummy/config/initializers/content_security_policy.rb +25 -0
  184. data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
  185. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  186. data/test/dummy/config/initializers/inflections.rb +16 -0
  187. data/test/dummy/config/initializers/mime_types.rb +4 -0
  188. data/test/dummy/config/initializers/workarea.rb +5 -0
  189. data/test/dummy/config/initializers/wrap_parameters.rb +9 -0
  190. data/test/dummy/config/locales/en.yml +33 -0
  191. data/test/dummy/config/puma.rb +34 -0
  192. data/test/dummy/config/routes.rb +5 -0
  193. data/test/dummy/config/secrets.yml +18 -0
  194. data/test/dummy/config/spring.rb +6 -0
  195. data/test/dummy/config.ru +5 -0
  196. data/test/dummy/db/seeds.rb +2 -0
  197. data/test/dummy/lib/assets/.keep +0 -0
  198. data/test/dummy/log/.keep +0 -0
  199. data/test/factories/workarea/global_e_factories.rb +836 -0
  200. data/test/integration/workarea/admin/catalog_product_country_exceptions_integration_test.rb +81 -0
  201. data/test/integration/workarea/admin/global_e_jump_to_integration_test.rb +20 -0
  202. data/test/integration/workarea/admin/pricing_sku_fixed_prices_integration_test.rb +83 -0
  203. data/test/integration/workarea/storefront/global_e_api/receive_order_integration_test.rb +278 -0
  204. data/test/integration/workarea/storefront/global_e_api/receive_order_refund_integration_test.rb +25 -0
  205. data/test/integration/workarea/storefront/global_e_api/receive_payment_integration_test.rb +34 -0
  206. data/test/integration/workarea/storefront/global_e_api/receive_shipping_info_integration_test.rb +29 -0
  207. data/test/integration/workarea/storefront/global_e_api/remove_restricted_products_integration_test.rb +27 -0
  208. data/test/integration/workarea/storefront/global_e_api/update_order_status_integration_test.rb +29 -0
  209. data/test/integration/workarea/storefront/global_e_checkout_cart_info/fixed_pricing_test.rb +438 -0
  210. data/test/integration/workarea/storefront/global_e_checkout_cart_info/gift_card_test.rb +63 -0
  211. data/test/integration/workarea/storefront/global_e_checkout_cart_info_integration_test.rb +660 -0
  212. data/test/integration/workarea/storefront/global_e_checkouts_integration_test.rb +71 -0
  213. data/test/integration/workarea/storefront/users/global_e_logins_integration_test.rb +20 -0
  214. data/test/models/workarea/catalog/product_global_e_test.rb +13 -0
  215. data/test/models/workarea/fixed_pricing_test.rb +117 -0
  216. data/test/models/workarea/global_e/country_exception_test.rb +36 -0
  217. data/test/models/workarea/payment_test.decorator +31 -0
  218. data/test/models/workarea/pricing/calculators/item_calculator_fixed_prices_test.rb +83 -0
  219. data/test/models/workarea/pricing/collection_fixed_prices_test.rb +83 -0
  220. data/test/models/workarea/pricing/price_distributor_test.decorator +21 -0
  221. data/test/models/workarea/pricing/sku_fixed_price_test.rb +133 -0
  222. data/test/support/workarea/global_e_support.rb +18 -0
  223. data/test/system/workarea/admin/global_e_system_test.rb +21 -0
  224. data/test/system/workarea/storefront/global_e_cart_system_test.rb +48 -0
  225. data/test/system/workarea/storefront/global_e_order_history_system_test.rb +43 -0
  226. data/test/teaspoon_env.rb +6 -0
  227. data/test/test_helper.rb +9 -0
  228. data/test/view_models/workarea/admin/global_e_order_view_model_test.rb +22 -0
  229. data/test/workers/workarea/global_e/update_order_dispatch_test.rb +64 -0
  230. data/test/workers/workarea/global_e_save_user_order_details_test.rb +41 -0
  231. data/workarea-global_e.gemspec +16 -0
  232. metadata +293 -0
@@ -0,0 +1,147 @@
1
+ module Workarea
2
+ module GlobalE
3
+ module Api
4
+ class SendOrderToMerchant::ItemPricer
5
+ def self.perform(order_item, merchant_product, discounts, currency, international_currency)
6
+ new(order_item, merchant_product, discounts, currency, international_currency).perform!
7
+ end
8
+
9
+ attr_reader :order_item, :merchant_product, :discounts, :currency, :international_currency
10
+
11
+ def initialize(order_item, merchant_product, discounts, currency, international_currency)
12
+ @order_item = order_item
13
+ @merchant_product = merchant_product
14
+ @discounts = discounts
15
+ @currency = currency
16
+ @international_currency = international_currency
17
+ end
18
+
19
+ def perform!
20
+ order_item.update_attributes(
21
+ price_adjustments: base_currency_adjustments,
22
+ international_price_adjustments: international_currency_adjustments,
23
+
24
+ total_value: discounted_price,
25
+ international_total_value: international_discounted_price,
26
+
27
+ total_price: base_currency_adjustments.adjusting("item").sum,
28
+ international_total_price: international_currency_adjustments.adjusting("item").sum,
29
+
30
+ discounted_price_for_customs: discounted_price_for_customs,
31
+ generic_hs_code: merchant_product.generic_hs_code
32
+ )
33
+ end
34
+
35
+ private
36
+
37
+ delegate :order, to: :order_item
38
+
39
+ def base_currency_adjustments
40
+ original_item_price_adjustment = order_item.price_adjustments.first
41
+
42
+ PriceAdjustmentSet.new(
43
+ [PriceAdjustment.new(
44
+ price: "item",
45
+ quantity: order_item.quantity,
46
+ description: "Item Subtotal",
47
+ calculator: self.class.name,
48
+ data: {
49
+ "on_sale" => base_currency_sell_price < base_currency_list_price,
50
+ "original_price" => base_currency_list_price.to_f,
51
+ "nonadjusted_amount" => original_item_price_adjustment.amount,
52
+ "nonadjusted_price" => original_item_price_adjustment.data["original_price"]
53
+ },
54
+ amount: base_currency_sell_price * order_item.quantity
55
+ )]
56
+ ) + base_currency_discount_adjustments
57
+ end
58
+
59
+ def international_currency_adjustments
60
+ PriceAdjustmentSet.new(
61
+ [PriceAdjustment.new(
62
+ price: "item",
63
+ quantity: order_item.quantity,
64
+ description: "Item Subtotal",
65
+ calculator: self.class.name,
66
+ data: {
67
+ "on_sale" => international_currency_sell_price < international_currency_list_price,
68
+ "original_price" => international_currency_list_price.to_f
69
+ },
70
+ amount: international_currency_sell_price * order_item.quantity
71
+ )]
72
+ ) + international_currency_discount_adjustments
73
+ end
74
+
75
+ def base_currency_list_price
76
+ Money.from_amount(merchant_product.list_price, currency)
77
+ end
78
+
79
+ def base_currency_sell_price
80
+ Money.from_amount(merchant_product.price, currency)
81
+ end
82
+
83
+ def international_currency_list_price
84
+ Money.from_amount(merchant_product.international_list_price, international_currency)
85
+ end
86
+
87
+ def international_currency_sell_price
88
+ Money.from_amount(merchant_product.international_price, international_currency)
89
+ end
90
+
91
+ def discounted_price
92
+ Money.from_amount(merchant_product.discounted_price, currency)
93
+ end
94
+
95
+ def international_discounted_price
96
+ Money.from_amount(merchant_product.international_discounted_price, international_currency)
97
+ end
98
+
99
+ def product_discounts
100
+ discounts.select do |discount|
101
+ discount.product_cart_item_id == order_item.id.to_s
102
+ end
103
+ end
104
+
105
+ def base_currency_discount_adjustments
106
+ product_discounts.map do |discount|
107
+
108
+ original_price_adjustment = order
109
+ .price_adjustments
110
+ .discounts
111
+ .detect { |pa| pa.global_e_discount_code == discount.discount_code }
112
+
113
+ PriceAdjustment.new(
114
+ price: "item",
115
+ quantity: order_item.quantity,
116
+ description: discount.description,
117
+ calculator: self.class.name,
118
+ amount: -Money.from_amount(discount.price, currency),
119
+ data: original_price_adjustment.data
120
+ .merge("dicount_value" => -Money.from_amount(discount.price, currency))
121
+ .merge(discount.hash)
122
+ )
123
+ end
124
+ end
125
+
126
+ def international_currency_discount_adjustments
127
+ product_discounts.map do |discount|
128
+ PriceAdjustment.new(
129
+ price: "item",
130
+ quantity: order_item.quantity,
131
+ description: discount.description,
132
+ calculator: self.class.name,
133
+ amount: -Money.from_amount(discount.international_price, international_currency),
134
+ data: discount.hash
135
+ )
136
+ end
137
+ end
138
+
139
+ def discounted_price_for_customs
140
+ return unless merchant_product.discounted_price_for_customs
141
+
142
+ Money.from_amount(merchant_product.discounted_price_for_customs, currency)
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,59 @@
1
+ module Workarea
2
+ module GlobalE
3
+ module Api
4
+ class SendOrderToMerchant::SaveUser
5
+ attr_reader :user_id, :shipping_details, :billing_details, :culture_code
6
+
7
+ def self.perform!(user_id, shipping_details:, billing_details:, culture_code:)
8
+ new(
9
+ user_id,
10
+ shipping_details: shipping_details,
11
+ billing_details: billing_details,
12
+ culture_code: culture_code
13
+ ).perform!
14
+ end
15
+
16
+ # @param user_id [String, BSON::ObjectId]
17
+ # @param shipping_details [Workarea::GlobalE::Merchant::CustomerDetails]
18
+ # @param billing_details [Workarea::GlobalE::Merchant::CustomerDetails]
19
+ # @param culture_code [String]
20
+ #
21
+ def initialize(user_id, shipping_details:, billing_details:, culture_code:)
22
+ @user_id = user_id
23
+ @shipping_details = shipping_details
24
+ @billing_details = billing_details
25
+ @culture_code = culture_code
26
+ end
27
+
28
+ def perform!
29
+ return if user.nil?
30
+ upsert_address(shipping_details)
31
+ upsert_address(billing_details)
32
+ user.global_e_culture_code = culture_code
33
+
34
+ user.save
35
+ end
36
+
37
+ private
38
+
39
+ def user
40
+ @user ||= Workarea::User.find user_id rescue nil
41
+ end
42
+
43
+ # @param customer_details [Workarea::GlobalE::Merchant::CustomerDetails]
44
+ #
45
+ def upsert_address(customer_details)
46
+ existing_address = user.addresses.detect do |user_address|
47
+ user_address.id.to_s == customer_details.address_book_id.to_s
48
+ end
49
+
50
+ if existing_address.present?
51
+ existing_address.attributes = customer_details.workarea_address_attributes
52
+ else
53
+ user.addresses.build customer_details.workarea_address_attributes
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,359 @@
1
+ module Workarea
2
+ module GlobalE
3
+ module Api
4
+ class SendOrderToMerchant
5
+ attr_reader :order, :merchant_order, :order_discount_price_adjustments
6
+
7
+ def initialize(order, merchant_order)
8
+ @order = order
9
+ @merchant_order = merchant_order
10
+ @order_discount_price_adjustments = order
11
+ .price_adjustments
12
+ .discounts
13
+ .select { |pa| pa.price == "order" }
14
+ .group_discounts_by_id
15
+ end
16
+
17
+ def response
18
+ @response ||=
19
+ begin
20
+ with_order_lock do
21
+ set_product_prices
22
+ set_order_discounts
23
+ update_order
24
+ save_shippings
25
+ save_payment
26
+ save_user
27
+
28
+ raise GlobalE::UnpurchasableOrder, order.errors.full_messages.join("\n") unless @order.valid?(:purchasable)
29
+
30
+ capture_invetory
31
+ place_order
32
+ place_order_side_effects
33
+
34
+ Workarea::GlobalE::Merchant::ResponseInfo.new(order: order)
35
+ end
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ delegate :international_details, :discounts, to: :merchant_order
42
+
43
+ def place_order
44
+ order.place
45
+ end
46
+
47
+ def place_order_side_effects
48
+ CreateFulfillment.new(order, global_e: true).perform
49
+ SaveOrderAnalytics.new(order).perform
50
+ end
51
+
52
+ def update_order
53
+ order.assign_attributes(
54
+ global_e: true,
55
+ currency: international_details.currency_code,
56
+ global_e_id: merchant_order.order_id,
57
+ email: shipping_details.email,
58
+
59
+ subtotal_price: order.price_adjustments.adjusting('item').sum,
60
+ international_subtotal_price: order.international_price_adjustments.adjusting('item').sum,
61
+
62
+ shipping_total: discounted_shipping_price,
63
+ international_shipping_total: discounted_international_shipping_price,
64
+ discounted_international_shipping_total: discounted_international_shipping_price,
65
+
66
+ total_value: order.items.sum(&:total_value),
67
+ total_price: order.items.sum(&:total_price) - order.discount_adjustments.sum { |pa| pa.amount.abs },
68
+ international_total_price: international_total_price,
69
+
70
+ tax_total: total_duties_and_taxes_price,
71
+ total_duties_price: total_duties_price,
72
+ contains_clearance_fees_price: contains_clearance_fees_price,
73
+ duties_guaranteed: international_details.duties_guaranteed
74
+ )
75
+ end
76
+
77
+ def international_subtotal_price
78
+ subtotal = merchant_order.products.sum(&:international_discounted_price)
79
+ Money.from_amount(
80
+ subtotal,
81
+ merchant_order.international_details.currency_code
82
+ )
83
+ end
84
+
85
+ def international_total_price
86
+ Money.from_amount(
87
+ merchant_order.international_details.total_price,
88
+ merchant_order.international_details.currency_code
89
+ )
90
+ end
91
+
92
+ def total_duties_price
93
+ Money.from_amount(
94
+ merchant_order.international_details.total_duties_price,
95
+ merchant_order.international_details.currency_code
96
+ )
97
+ end
98
+
99
+ def international_shipping_price
100
+ Money.from_amount(
101
+ international_details.total_shipping_price,
102
+ international_details.currency_code
103
+ )
104
+ end
105
+
106
+ def discounted_shipping_price
107
+ Money.from_amount(
108
+ merchant_order.discounted_shipping_price,
109
+ merchant_order.currency_code
110
+ )
111
+ end
112
+
113
+ def discounted_international_shipping_price
114
+ Money.from_amount(
115
+ international_details.discounted_shipping_price,
116
+ international_details.currency_code
117
+ )
118
+ end
119
+
120
+ def total_duties_and_taxes_price
121
+ Money.from_amount(
122
+ merchant_order.total_duties_and_taxes_price,
123
+ merchant_order.currency_code
124
+ )
125
+ end
126
+
127
+ def contains_clearance_fees_price
128
+ Money.from_amount(
129
+ merchant_order.contains_clearance_fees_price,
130
+ merchant_order.currency_code
131
+ )
132
+ end
133
+
134
+ def save_shippings
135
+ Workarea::Shipping.where(order_id: order.id).destroy_all
136
+ shipping.update_attributes(
137
+ international_shipping_total: discounted_international_shipping_price,
138
+ address: shipping_address,
139
+ shipping_service: shipping_service,
140
+ price_adjustments: [
141
+ {
142
+ price: 'shipping',
143
+ amount: merchant_order.discounted_shipping_price.to_m,
144
+ description: shipping_service[:name],
145
+ calculator: self.class.name
146
+ }
147
+ ] + shipping_discount_adjustments,
148
+ international_price_adjustments: [
149
+ {
150
+ price: 'shipping',
151
+ amount: discounted_international_shipping_price,
152
+ description: shipping_service[:name],
153
+ calculator: self.class.name
154
+ }
155
+ ] + shipping_international_discount_adjustments
156
+ )
157
+ end
158
+
159
+ def shipping_discounts
160
+ discounts.select(&:shipping?)
161
+ end
162
+
163
+ def shipping_discount_adjustments
164
+ shipping_discounts.map do |discount|
165
+ {
166
+ price: "shipping",
167
+ quantity: 1,
168
+ description: discount.description,
169
+ calculator: self.class.name,
170
+ amount: -Money.from_amount(discount.price, merchant_order.currency_code),
171
+ data: discount.hash.merge(
172
+ "dicount_value" => -Money.from_amount(discount.price, merchant_order.currency_code)
173
+ )
174
+ }
175
+ end
176
+ end
177
+
178
+ def shipping_international_discount_adjustments
179
+ shipping_discounts.map do |discount|
180
+ {
181
+ price: "shipping",
182
+ quantity: 1,
183
+ description: discount.description,
184
+ calculator: self.class.name,
185
+ amount: -Money.from_amount(discount.international_price, international_details.currency_code),
186
+ data: discount.hash
187
+ }
188
+ end
189
+ end
190
+
191
+ def save_payment
192
+ payment.update_attributes(
193
+ address: billing_address,
194
+ global_e_payment: {
195
+ name: international_details.payment_method_name,
196
+ payment_method_code: international_details.payment_method_code,
197
+ last_four: international_details.card_number_last_four_digits,
198
+ expiration_date: international_details.expiration_date,
199
+ amount: Money.from_amount(
200
+ international_details.transaction_total_price,
201
+ international_details.currency_code
202
+ )
203
+ }
204
+ )
205
+ end
206
+
207
+ def save_user
208
+ return unless order.user_id.present?
209
+
210
+ SaveUser.perform!(
211
+ order.user_id,
212
+
213
+ shipping_details: shipping_details,
214
+ billing_details: billing_details,
215
+ culture_code: merchant_order.culture_code
216
+ )
217
+ end
218
+
219
+ # @raise [Workarea::GlobalE::InventoryCaptureFailure]
220
+ #
221
+ def capture_invetory
222
+ inventory.purchase
223
+ raise InventoryCaptureFailure, inventory.errors.full_messages.join("\n") unless inventory.captured?
224
+ end
225
+
226
+ def set_product_prices
227
+ merchant_order.products.each do |merchant_product|
228
+ order_item = order.items.find merchant_product.cart_item_id
229
+
230
+ ItemPricer.perform(
231
+ order_item,
232
+ merchant_product,
233
+ discounts,
234
+ merchant_order.currency_code,
235
+ international_details.currency_code
236
+ )
237
+ end
238
+ end
239
+
240
+ def set_order_discounts
241
+ order.discount_adjustments = order_discounts.map do |discount|
242
+ original_price_adjustment = order_discount_price_adjustments
243
+ .detect { |pa| pa.global_e_discount_code == discount.discount_code }
244
+
245
+ {
246
+ price: "order",
247
+ quantity: 1,
248
+ description: discount.description,
249
+ calculator: self.class.name,
250
+ amount: -Money.from_amount(discount.price, merchant_order.currency_code),
251
+ data: (original_price_adjustment&.data || {})
252
+ .merge("dicount_value" => -Money.from_amount(discount.price, merchant_order.currency_code))
253
+ .merge(discount.hash)
254
+ }
255
+ end
256
+
257
+ order.international_discount_adjustments = order_discounts.map do |discount|
258
+ {
259
+ price: "order",
260
+ quantity: 1,
261
+ description: discount.description,
262
+ calculator: self.class.name,
263
+ amount: -Money.from_amount(discount.international_price, international_details.currency_code),
264
+ data: discount.hash
265
+ }
266
+ end
267
+ end
268
+
269
+ def order_discounts
270
+ discounts.select do |merchant_discount|
271
+ merchant_discount.product_cart_item_id.blank? && !merchant_discount.shipping?
272
+ end
273
+ end
274
+
275
+ def inventory
276
+ @inventory ||= Inventory::Transaction.from_order(
277
+ order.id,
278
+ order.items.inject({}) do |memo, item|
279
+ memo[item.sku] ||= 0
280
+ memo[item.sku] += item.quantity
281
+ memo
282
+ end
283
+ )
284
+ end
285
+
286
+ # @return [Workarea::GlobalE::Merchant::CustomerDetails]
287
+ #
288
+ def shipping_details
289
+ if merchant_order.customer.is_end_customer_primary
290
+ merchant_order.primary_shipping
291
+ else
292
+ merchant_order.secondary_shipping
293
+ end
294
+ end
295
+
296
+ def shipping_address
297
+ {
298
+ first_name: shipping_details.first_name,
299
+ last_name: shipping_details.last_name,
300
+ street: shipping_details.address1,
301
+ street_2: shipping_details.address2,
302
+ city: shipping_details.city,
303
+ region: shipping_details.state_code,
304
+ postal_code: shipping_details.zip,
305
+ country: Country[shipping_details.country_code],
306
+ phone_number: shipping_details.phone1,
307
+ skip_region_presence: true
308
+ }
309
+ end
310
+
311
+ def shipping_service
312
+ {
313
+ carrier: merchant_order.international_details.shipping_method_name,
314
+ name: merchant_order.international_details.shipping_method_type_name,
315
+ service_code: merchant_order.international_details.shipping_method_code
316
+ }
317
+ end
318
+
319
+ def shipping
320
+ @shippipng ||= Shipping.create(order_id: order.id)
321
+ end
322
+
323
+ def billing_details
324
+ if merchant_order.customer.is_end_customer_primary
325
+ merchant_order.primary_billing
326
+ else
327
+ merchant_order.secondary_billing
328
+ end
329
+ end
330
+
331
+ def billing_address
332
+ {
333
+ first_name: billing_details.first_name,
334
+ last_name: billing_details.last_name,
335
+ street: billing_details.address1,
336
+ street_2: billing_details.address2,
337
+ city: billing_details.city,
338
+ region: billing_details.state_code,
339
+ postal_code: billing_details.zip,
340
+ country: Country[billing_details.country_code],
341
+ phone_number: billing_details.phone1,
342
+ skip_region_presence: true
343
+ }
344
+ end
345
+
346
+ def payment
347
+ @payment ||= Payment.find_or_create_by(id: order.id)
348
+ end
349
+
350
+ def with_order_lock
351
+ order.lock!
352
+ yield
353
+ ensure
354
+ order.unlock! if order
355
+ end
356
+ end
357
+ end
358
+ end
359
+ end
@@ -0,0 +1,38 @@
1
+ module Workarea
2
+ module GlobalE
3
+ module Api
4
+ class UpdateOrderShippingInfo
5
+ attr_reader :order, :merchant_order
6
+
7
+ def initialize(order, merchant_order)
8
+ @order = order
9
+ @merchant_order = merchant_order
10
+ end
11
+
12
+ def response
13
+ @response ||=
14
+ begin
15
+ ship_items
16
+ Merchant::ResponseInfo.new(order: order)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def fulfillment
23
+ @fulfillment ||= Fulfillment.find order.id
24
+ end
25
+
26
+ def ship_items
27
+ fulfillment.ship_items(
28
+ merchant_order.international_details.order_tracking_number,
29
+ order.items.map do |item|
30
+ { 'id' => item.id.to_s, 'quantity' => item.quantity }
31
+ end,
32
+ send_to_global_e: false
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,42 @@
1
+ module Workarea
2
+ module GlobalE
3
+ module Api
4
+ class UpdateOrderStatus::Canceled
5
+ attr_reader :order
6
+
7
+ def self.perform(order)
8
+ new(order).perform
9
+ end
10
+
11
+ def initialize(order)
12
+ @order = order
13
+ end
14
+
15
+ def perform
16
+ restock
17
+ update_fulfillment
18
+ order.cancel
19
+ end
20
+
21
+ private
22
+
23
+ def restock
24
+ transaction = Inventory::Transaction.captured_for_order(order.id)
25
+ transaction.rollback unless transaction.blank?
26
+ end
27
+
28
+ def fulfillment
29
+ @fulfillment ||= Fulfillment.find_or_initialize_by(id: order.id)
30
+ end
31
+
32
+ def update_fulfillment
33
+ cancellations = order.items.map do |item|
34
+ { 'id' => item.id.to_s, 'quantity' => item.quantity }
35
+ end
36
+
37
+ fulfillment.cancel_items(cancellations)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,28 @@
1
+ module Workarea
2
+ module GlobalE
3
+ module Api
4
+ class UpdateOrderStatus
5
+ attr_reader :order, :merchant_order
6
+
7
+ def initialize(order, merchant_order)
8
+ @order = order
9
+ @merchant_order = merchant_order
10
+ end
11
+
12
+ def response
13
+ @response ||=
14
+ begin
15
+ klass.perform(order)
16
+ Merchant::ResponseInfo.new(order: order)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def klass
23
+ "Workarea::GlobalE::Api::UpdateOrderStatus::#{merchant_order.status_code.classify}".constantize
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end