workarea-global_e 1.2.1

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 (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