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,122 @@
1
+ WORKAREA.registerModule('globalECheckoutInfoValidator', (function () {
2
+ var cartToken = function() {
3
+ return WORKAREA.cookie.read("GlobalECartId");
4
+ },
5
+
6
+ checkoutInfo = function() {
7
+ return $.getJSON(WORKAREA.routes.storefront.globalECheckoutCartInfoPath({cartToken: cartToken()}));
8
+ },
9
+
10
+ verifyProductPrices = function(product, discounts) {
11
+ var productContainer = $("[data-ge-basket-cartitemid='" + product.CartItemId + "']"),
12
+ salePrice, listPrice, subtotalPrice, totalPrice;
13
+
14
+ assertDom(productContainer, "Missing product container for " + product.CartItemId);
15
+
16
+ if (!_.isUndefined(productContainer.data('geBasketFreegift'))) {
17
+ return;
18
+ }
19
+
20
+ salePrice = $("[data-ge-basket-productsaleprice]", productContainer);
21
+ listPrice = $("[data-ge-basket-productlistprice]", productContainer);
22
+ subtotalPrice = $("[data-ge-basket-productsubtotalprice]", productContainer);
23
+ totalPrice = $("[data-ge-basket-producttotalprice]", productContainer);
24
+
25
+ assertDom(salePrice, "Missing sale price for " + product.Name + " : " + product.CartItemId);
26
+ assertPrice(salePrice, product.OriginalSalePrice);
27
+
28
+ assertDom(totalPrice, "Missing total price for " + product.Name + " : " + product.CartItemId);
29
+
30
+ if (product.OriginalListPrice === product.OriginalSalePrice) {
31
+ refuteDom(listPrice, "Expected not to find list price for " + product.Name + " : " + product.CartItemId);
32
+ } else {
33
+ assertDom(listPrice, "Expected to find list price for " + product.Name + " : " + product.CartItemId);
34
+ assertPrice(listPrice, product.OriginalListPrice);
35
+ }
36
+
37
+ _.forEach(productDiscounts(product.CartItemId, discounts), verifyProductDiscount);
38
+ if (productHasDiscounts(product.CartItemId, discounts)) {
39
+ assertDom(subtotalPrice, "Missing subtotalPrice " + product.Name + " : " + product.CartItemId);
40
+ assertPrice(subtotalPrice, product.OriginalSalePrice * product.OrderedQuantity);
41
+ } else {
42
+ refuteDom(subtotalPrice, "Expected not to find subtotalPrice for " + product.Name + " : " + product.CartItemId);
43
+ }
44
+ },
45
+
46
+ productDiscounts = function(cartItemId, discounts) {
47
+ return _.filter(discounts, { "ProductCartItemId": cartItemId });
48
+ },
49
+
50
+ verifyProductDiscount = function(discount) {
51
+ var discountPrice = $("[data-ge-basket-productdiscountsprice='" + discount.DiscountCode + "']");
52
+
53
+ assertDom(discountPrice, "Expected to find discount " + discount.name + " : " + discount.DiscountCode);
54
+ assertPrice(discountPrice, discount.OriginalDiscountValue);
55
+ },
56
+
57
+ productHasDiscounts = function(cartItemId, discounts) {
58
+ return !_.isUndefined(_.find(discounts, { "ProductCartItemId": cartItemId }));
59
+ },
60
+
61
+ verifyOrderPrices = function(products, discounts) {
62
+ var subtotal = $("[data-ge-basket-subtotals]"),
63
+ total = $("[data-ge-basket-totals]");
64
+
65
+ assertDom(subtotal, "Expected to find order subtotal");
66
+ assertDom(total, "Expected to find order total");
67
+
68
+ _.forEach(orderDiscounts(discounts), verifyOrderDiscount);
69
+ },
70
+
71
+ verifyOrderDiscount = function(discount) {
72
+ var element = $("[data-ge-basket-discounts='" + discount.DiscountCode + "']");
73
+
74
+ assertDom(element, "Expected to find order discount " + discount.Name + " : " + discount.DiscountCode);
75
+ assertPrice(element, discount.OriginalDiscountValue);
76
+ },
77
+
78
+ orderDiscounts = function(discounts) {
79
+ return _.filter(discounts, function(discount) { return _.isUndefined(discount.ProductCartItemId); });
80
+ },
81
+
82
+ assertDom = function(element, errorMessage) {
83
+ if (_.isEmpty(element)) {
84
+ throw errorMessage;
85
+ }
86
+ },
87
+
88
+ refuteDom = function(element, errorMessage) {
89
+ try {
90
+ assertDom(element, errorMessage);
91
+ throw errorMessage;
92
+ }
93
+ catch(error) { return true; }
94
+ },
95
+
96
+ assertPrice = function(element, expected) {
97
+ var actual = parseFloat(element.text().replace(/-?\$/, ""));
98
+ if (actual !== expected) {
99
+ throw "Expected " + actual + " to equal " + expected;
100
+ }
101
+ },
102
+
103
+ init = function() {
104
+ if (WORKAREA.url.parse(WORKAREA.url.current()).path !== "/cart") {
105
+ return;
106
+ }
107
+
108
+ checkoutInfo().done(function(cart) {
109
+ _.forEach(cart.productsList, function(product) {
110
+ verifyProductPrices(product, cart.discountsList);
111
+ });
112
+
113
+ if (!_.isEmpty(cart.productsList)) {
114
+ verifyOrderPrices(cart.productsList, cart.discountsList);
115
+ }
116
+ });
117
+ };
118
+
119
+ return {
120
+ init: init
121
+ };
122
+ }()));
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @namespace WORKAREA.global_e
3
+ */
4
+
5
+ WORKAREA.registerModule('global_e_price_filter', (function () {
6
+ var isOperatedByGlobalE = function() {
7
+ return WORKAREA.cookie.read('GlobalE_IsOperated') === "true";
8
+ },
9
+
10
+ init = function($scope) {
11
+ if (!isOperatedByGlobalE()) { return; }
12
+
13
+ $('.result-filters__section--price', $scope).hide();
14
+ };
15
+
16
+ return {
17
+ init: init
18
+ };
19
+ }()));
@@ -0,0 +1,67 @@
1
+ module Workarea
2
+ class Admin::CountryExceptionsController < Admin::ApplicationController
3
+ required_permissions :catalog
4
+ helper GlobalEHelpers
5
+
6
+ before_action :find_product
7
+ before_action :find_country_exception, except: [:index, :new]
8
+
9
+ def index
10
+ end
11
+
12
+ def new
13
+ @country_exception = GlobalE::CountryException.new
14
+ end
15
+
16
+ def create
17
+ if @country_exception.save
18
+ flash.now[:error] = t('workarea.admin.country_exceptions.flash_messages.saved')
19
+ redirect_to catalog_product_country_exceptions_path(@product)
20
+ else
21
+ @product.reload
22
+ flash.now[:error] = t('workarea.admin.country_exceptions.flash_messages.create_error')
23
+ render :new
24
+ end
25
+ end
26
+
27
+ def edit; end
28
+
29
+ def update
30
+ if @country_exception.update_attributes(country_exception_params)
31
+ flash[:success] = t('workarea.admin.country_exceptions.flash_messages.saved')
32
+ redirect_to catalog_product_country_exceptions_path(@product)
33
+ else
34
+ flash.now[:error] = t('workarea.admin.country_exceptions.flash_messages.update_error')
35
+ render :edit, status: :unprocessable_entity
36
+ end
37
+ end
38
+
39
+ def destroy
40
+ @country_exception.destroy
41
+
42
+ flash[:success] = t('workarea.admin.country_exceptions.flash_messages.deleted')
43
+ redirect_to catalog_product_country_exceptions_path(@product)
44
+ end
45
+
46
+ private
47
+
48
+ def find_product
49
+ model = Catalog::Product.find_by(slug: params[:catalog_product_id])
50
+ @product = Admin::ProductViewModel.new(model, view_model_options)
51
+ end
52
+
53
+ def find_country_exception
54
+ @country_exception ||= if params[:id].present?
55
+ @product.country_exceptions.find_or_create_by(id: params[:id])
56
+ else
57
+ @product.country_exceptions.build(country_exception_params)
58
+ end
59
+ end
60
+
61
+ def country_exception_params
62
+ @country_exception_params ||= params
63
+ .fetch(:country_exception, {})
64
+ .permit(:country, :restricted, :vat_rate)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,89 @@
1
+ module Workarea
2
+ module Admin
3
+ class FixedPricesController < ApplicationController
4
+ required_permissions :catalog
5
+ helper GlobalEHelpers
6
+
7
+ before_action :find_sku
8
+ before_action :find_price, except: [:index, :new]
9
+
10
+ def index
11
+ end
12
+
13
+ def new
14
+ @fixed_price = GlobalE::FixedPrice.new(fixed_price_params)
15
+ end
16
+
17
+ def create
18
+ if @fixed_price.save
19
+ flash[:success] = t('workarea.admin.fixed_prices.flash_messages.saved', sku: @sku.id)
20
+ redirect_to pricing_sku_fixed_prices_path(@sku)
21
+ else
22
+ @sku.reload
23
+ flash.now[:error] = t('workarea.admin.fixed_prices.flash_messages.create_error')
24
+ render :new
25
+ end
26
+ end
27
+
28
+ def edit
29
+ end
30
+
31
+ def update
32
+ if @fixed_price.update_attributes(fixed_price_params)
33
+ flash[:success] = t('workarea.admin.fixed_prices.flash_messages.saved', sku: @sku.id)
34
+ redirect_to pricing_sku_fixed_prices_path(@sku)
35
+ else
36
+ flash.now[:error] = t('workarea.admin.fixed_prices.flash_messages.update_error')
37
+ render :edit, status: :unprocessable_entity
38
+ end
39
+ end
40
+
41
+ def destroy
42
+ @fixed_price.destroy
43
+
44
+ flash[:success] = t('workarea.admin.fixed_prices.flash_messages.deleted', sku: @sku.id)
45
+ redirect_to pricing_sku_fixed_prices_path(@sku)
46
+ end
47
+
48
+ private
49
+
50
+ def fixed_price_params
51
+ @fixed_price_params ||=
52
+ begin
53
+ permitted = params.fetch(:fixed_price, {}).permit(:country, :currency_code, :sale, :regular, :active)
54
+ currency_code = permitted[:currency_code]
55
+
56
+ permitted[:regular] =
57
+ if permitted[:regular].present? && currency_code.present?
58
+ permitted[:regular].to_m(currency_code)
59
+ else
60
+ nil
61
+ end
62
+
63
+ permitted[:sale] =
64
+ if permitted[:sale].present? && currency_code.present?
65
+ permitted[:sale].to_m(currency_code)
66
+ else
67
+ nil
68
+ end
69
+
70
+ permitted
71
+ end
72
+ end
73
+
74
+ def find_sku
75
+ @sku = PricingSkuViewModel.wrap(
76
+ Pricing::Sku.find(params[:pricing_sku_id])
77
+ )
78
+ end
79
+
80
+ def find_price
81
+ @fixed_price = if params[:id].present?
82
+ @sku.fixed_prices.find_or_create_by(id: params[:id])
83
+ else
84
+ @sku.fixed_prices.build(fixed_price_params)
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,6 @@
1
+ module Workarea
2
+ decorate Admin::OrdersController, with: :global_e do
3
+ def global_e
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,30 @@
1
+ module Workarea
2
+ decorate Storefront::ApplicationController, with: :global_e do
3
+ decorated do
4
+ after_action :set_global_e_cart_id_cookie
5
+ end
6
+
7
+ def current_order
8
+ @current_order ||= super.tap do |order|
9
+ order.assign_attributes(
10
+ currency: global_e_cookie["currencyCode"] || order.currency,
11
+ shipping_country: Country[global_e_cookie["countryISO"]] || order.shipping_country
12
+ )
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def global_e_cookie
19
+ @global_e_cookie ||= JSON.parse cookies[:GlobalE_Data] rescue {}
20
+ end
21
+
22
+ def set_global_e_cart_id_cookie
23
+ if current_order.persisted?
24
+ cookies["GlobalECartId"] = current_order.global_e_token
25
+ else
26
+ cookies.delete "GlobalECartId"
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,22 @@
1
+ module Workarea
2
+ decorate Storefront::CheckoutsController, with: :global_e do
3
+ decorated { before_action :route_global_e_order, if: :is_operated_by_global_e? }
4
+
5
+ private
6
+
7
+ def route_global_e_order
8
+ current_checkout.reset!
9
+ current_order.update_attributes(user_id: current_user.id) if current_user.present?
10
+ Pricing.perform(current_order)
11
+ redirect_to ge_checkout_path
12
+ end
13
+
14
+ def global_e_cookie
15
+ JSON.parse cookies[:GlobalE_Data] rescue {}
16
+ end
17
+
18
+ def is_operated_by_global_e?
19
+ cookies.fetch(:GlobalE_IsOperated, 'false').casecmp?('true')
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,10 @@
1
+ module Workarea
2
+ module Storefront
3
+ class GeCheckoutsController < Storefront::ApplicationController
4
+ layout 'workarea/storefront/checkout'
5
+
6
+ def show
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,42 @@
1
+ module Workarea
2
+ module Storefront
3
+ class GlobalEController < ApplicationController
4
+ def get_checkout_cart_info
5
+ if checkout_cart_info_params[:countryCode].present? || checkout_cart_info_params[:MerchantGUID].present?
6
+ order.update_attribute(:checkout_started_at, Time.current)
7
+ end
8
+
9
+ if checkout_cart_info_params[:IsStockValidation]
10
+ InventoryAdjustment.new(order).tap(&:perform)
11
+ end
12
+
13
+ # GlobalE overriding fixed pricing for the order
14
+ #
15
+ if checkout_cart_info_params[:isFixedPriceSupported].present? &&
16
+ checkout_cart_info_params[:isFixedPriceSupported].to_s == "false"
17
+ order.update_attribute(:fixed_pricing, false)
18
+ end
19
+
20
+ render json: Workarea::GlobalE::CheckoutCartInfo.new(order).to_json
21
+ end
22
+
23
+ private
24
+
25
+ def order
26
+ @order ||= Order.find_by(
27
+ global_e_token: checkout_cart_info_params.require(:cartToken)
28
+ )
29
+ end
30
+
31
+ def checkout_cart_info_params
32
+ params.permit(
33
+ :cartToken,
34
+ :countryCode,
35
+ :IsStockValidation,
36
+ :MerchantGUID,
37
+ :isFixedPriceSupported
38
+ )
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,108 @@
1
+ module Workarea
2
+ module Storefront
3
+ module Globale
4
+ class ApiController < Storefront::ApplicationController
5
+ before_action :parse_merchant_order
6
+ before_action :validate_merchant_guid
7
+ before_action :find_order
8
+ after_action :log_api_event
9
+
10
+ rescue_from Exception, with: :api_error_response
11
+
12
+ # After this step is completed the order can be included in
13
+ # order history in the customer’s “My Account” section on the
14
+ # merchant’s site. It is also recommended to reserve the inventory
15
+ # for this order after the first step is completed, as long as usually
16
+ # the second step will follow too.
17
+ #
18
+ def receive_order
19
+ @response = GlobalE::Api::SendOrderToMerchant.new(@order, @merchant_order).response
20
+ render json: @response.to_json
21
+ end
22
+
23
+ # Posts order payment details for the order to the Merchant and performs
24
+ # the payment. Only order.OrderId and order.PaymentDetails members are
25
+ # mandatory for this method.
26
+ #
27
+ def receive_payment
28
+ @response = GlobalE::Api::PerformOrderPayment.new(@order, @merchant_order).response
29
+ render json: @response.to_json
30
+ end
31
+
32
+ def update_order_status
33
+ @response = GlobalE::Api::UpdateOrderStatus.new(@order, @merchant_order).response
34
+ render json: @response.to_json
35
+ end
36
+
37
+ # Updates order international shipping information on the Merchant’s
38
+ # site. Only order.OrderId and order.InternationalDetails members are
39
+ # mandatory for this method.
40
+ #
41
+ def receive_shipping_info
42
+ @response = GlobalE::Api::UpdateOrderShippingInfo.new(@order, @merchant_order).response
43
+ render json: @response.to_json
44
+ end
45
+
46
+ # Remove products from the order marked as restricted on Global-E's side.
47
+ def remove_restricted_products
48
+ @job = GlobalE::Api::RemoveRestrictedProducts.perform(
49
+ @order,
50
+ params['RemovedProductCodes']
51
+ )
52
+
53
+ render json: @job.response
54
+ end
55
+
56
+ private
57
+
58
+ def api_error_response(error)
59
+ GlobalE.report_error error
60
+ @response = GlobalE::Merchant::ResponseInfo.error(message: error.message, order: @order)
61
+ GlobalE::OrderApiEvents.upsert_one(
62
+ @order.id,
63
+ set: {
64
+ "#{params[:action]}" => @merchant_order.to_h,
65
+ "#{params[:action]}_response" => @response.to_h
66
+ }
67
+ )
68
+ render json: @response.to_json, status: :internal_server_error
69
+ end
70
+
71
+ def parse_merchant_order
72
+ @merchant_order = Workarea::GlobalE::Merchant::Order.new(
73
+ params.to_unsafe_hash.except(:controller, :action, :api)
74
+ )
75
+ end
76
+
77
+ def validate_merchant_guid
78
+ return if @merchant_order.merchant_guid == GlobalE.merchant_guid
79
+
80
+ head :bad_request
81
+ end
82
+
83
+ def find_order
84
+ @order ||=
85
+ if @merchant_order.cart_id.present?
86
+ Order.find_by(global_e_token: @merchant_order.cart_id)
87
+ elsif @merchant_order.merchant_order_id.present?
88
+ Order.find(@merchant_order.merchant_order_id)
89
+ elsif @merchant_order.order_id.present?
90
+ Order.find_by(global_e_id: @merchant_order.order_id)
91
+ end
92
+ end
93
+
94
+ def log_api_event
95
+ return unless @order && @response
96
+
97
+ GlobalE::OrderApiEvents.upsert_one(
98
+ @order.id,
99
+ set: {
100
+ "#{params[:action]}" => @merchant_order.to_h,
101
+ "#{params[:action]}_response" => @response.to_h
102
+ }
103
+ )
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,65 @@
1
+ module Workarea
2
+ module Storefront
3
+ module Globale
4
+ class RefundController < Storefront::ApplicationController
5
+ before_action :parse_order_refund
6
+ before_action :validate_merchant_guid
7
+ before_action :find_order
8
+ after_action :log_api_event
9
+
10
+ def receive_order_refund
11
+ @response = GlobalE::Api::NotifyOrderRefunded.new(@order, @order_refund).response
12
+ render json: @response.to_json
13
+ end
14
+
15
+ private
16
+
17
+ def api_error_response(error)
18
+ GlobalE.report_error error
19
+ @response = GlobalE::Merchant::ResponseInfo.error(message: error.message, order: @order)
20
+ GlobalE::OrderApiEvents.upsert_one(
21
+ @order.id,
22
+ set: {
23
+ "#{params[:action]}" => @order_refund.to_h,
24
+ "#{params[:action]}_response" => @response.to_h
25
+ }
26
+ )
27
+ render json: @response.to_json, status: :internal_server_error
28
+ end
29
+
30
+ def parse_order_refund
31
+ @order_refund = Workarea::GlobalE::Merchant::OrderRefund.new(
32
+ params.to_unsafe_hash.except(:controller, :action, :api)
33
+ )
34
+ end
35
+
36
+ def validate_merchant_guid
37
+ return if @order_refund.merchant_guid == GlobalE.merchant_guid
38
+
39
+ head :bad_request
40
+ end
41
+
42
+ def find_order
43
+ @order ||=
44
+ if @order_refund.merchant_order_id.present?
45
+ Order.find(@order_refund.merchant_order_id)
46
+ elsif @order_refund.order_id.present?
47
+ Order.find_by(global_e_id: @order_refund.order_id)
48
+ end
49
+ end
50
+
51
+ def log_api_event
52
+ return unless @order && @response
53
+
54
+ GlobalE::OrderApiEvents.upsert_one(
55
+ @order.id,
56
+ set: {
57
+ "#{params[:action]}" => @order_refund.to_h,
58
+ "#{params[:action]}_response" => @response.to_h
59
+ }
60
+ )
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,13 @@
1
+ module Workarea
2
+ decorate Storefront::Users::LoginsController, with: :global_e do
3
+ decorated { after_action :set_global_e_culture_code_cookie }
4
+
5
+ private
6
+
7
+ def set_global_e_culture_code_cookie
8
+ return unless current_user&.global_e_culture_code.present?
9
+
10
+ cookies["GlobalECultureCode"] = current_user.global_e_culture_code
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,28 @@
1
+ module Workarea
2
+ module Admin
3
+ module GlobalEHelpers
4
+ def currency_options(filtered_currencies = [])
5
+ filtered_currencies += [Money.default_currency]
6
+
7
+ [["---", nil]] + (all_currencies - filtered_currencies).map do |currency|
8
+ ["#{currency.name} (#{currency.symbol})", currency.iso_code]
9
+ end.compact
10
+ end
11
+
12
+ def global_e_country_options
13
+ [["---", nil]] + GlobalE.config.countries.map do |alpha2|
14
+ next unless country = Country[alpha2]
15
+ [country.name, alpha2]
16
+ end.compact
17
+ end
18
+
19
+ private
20
+
21
+ def all_currencies
22
+ @all_currencies ||= GlobalE.config.currencies.map do |iso_code|
23
+ Money::Currency.find iso_code
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,11 @@
1
+ module Workarea
2
+ decorate Address, with: :global_e do
3
+ decorated do
4
+ field :skip_region_presence, type: Boolean
5
+ end
6
+
7
+ def region_presence
8
+ skip_region_presence || super
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ module Workarea
2
+ decorate Catalog::Product, with: :global_e do
3
+ decorated do
4
+ field :global_e_forbidden, type: Boolean
5
+ embeds_many :country_exceptions,
6
+ class_name: "Workarea::GlobalE::CountryException",
7
+ inverse_of: :product
8
+ end
9
+
10
+ def global_e_forbidden
11
+ super || (Plugin.installed?(:gift_cards) && gift_card?)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ module Workarea
2
+ class Fulfillment
3
+ module Status
4
+ class PartiallyRefunded
5
+ include StatusCalculator::Status
6
+
7
+ def in_status?
8
+ order.items.any? { |i| i.quantity_refunded >= i.quantity }
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end