spree_vpago 0.1.0.pre.beta

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 (262) hide show
  1. checksums.yaml +7 -0
  2. data/.env.example +3 -0
  3. data/.github/workflows/test_and_publish_gem.yml +96 -0
  4. data/.gitignore +24 -0
  5. data/.rspec +3 -0
  6. data/.rubocop.yml +56 -0
  7. data/.ruby-version +1 -0
  8. data/.tool-versions +1 -0
  9. data/.travis.yml +45 -0
  10. data/Appraisals +20 -0
  11. data/Gemfile +27 -0
  12. data/Gemfile.lock +656 -0
  13. data/LICENSE +26 -0
  14. data/README.md +151 -0
  15. data/Rakefile +21 -0
  16. data/app/.gitkeep +0 -0
  17. data/app/assets/config/spree_vpago_manifest.js +3 -0
  18. data/app/assets/images/backend-process.svg +3 -0
  19. data/app/assets/images/vpago/payway/abapay.png +0 -0
  20. data/app/assets/images/vpago/payway/cards.png +0 -0
  21. data/app/assets/javascripts/vpago/vpago_payments/request_process_payment.js +44 -0
  22. data/app/assets/javascripts/vpago/vpago_payments/user_informers/firebase.js +15802 -0
  23. data/app/controllers/.gitkeep +0 -0
  24. data/app/controllers/spree/acleda_redirects_controller.rb +22 -0
  25. data/app/controllers/spree/admin/payment_methods_controller_decorator.rb +65 -0
  26. data/app/controllers/spree/admin/payment_payway_base_controller.rb +25 -0
  27. data/app/controllers/spree/admin/payment_payway_checkers_controller.rb +34 -0
  28. data/app/controllers/spree/admin/payment_payway_markers_controller.rb +44 -0
  29. data/app/controllers/spree/admin/payment_payway_queriers_controller.rb +39 -0
  30. data/app/controllers/spree/admin/payment_wing_sdk_base_controller.rb +21 -0
  31. data/app/controllers/spree/admin/payment_wing_sdk_checkers_controller.rb +26 -0
  32. data/app/controllers/spree/admin/payment_wing_sdk_markers_controller.rb +36 -0
  33. data/app/controllers/spree/admin/payment_wing_sdk_queriers_controller.rb +20 -0
  34. data/app/controllers/spree/admin/payments_controller_decorator.rb +19 -0
  35. data/app/controllers/spree/admin/payout_profile_products_controller.rb +21 -0
  36. data/app/controllers/spree/admin/payout_profile_shipping_methods_controller.rb +21 -0
  37. data/app/controllers/spree/admin/payout_profiles_controller.rb +91 -0
  38. data/app/controllers/spree/admin/payouts_controller.rb +16 -0
  39. data/app/controllers/spree/api/v2/storefront/checkout_controller_decorator.rb +84 -0
  40. data/app/controllers/spree/payway_card_popups_controller.rb +20 -0
  41. data/app/controllers/spree/payway_results_controller.rb +11 -0
  42. data/app/controllers/spree/payway_v2_card_popups_controller.rb +20 -0
  43. data/app/controllers/spree/vpago_payments_controller.rb +71 -0
  44. data/app/controllers/spree/webhook/acleda_mobiles_controller.rb +88 -0
  45. data/app/controllers/spree/webhook/acledas_controller.rb +80 -0
  46. data/app/controllers/spree/webhook/base_controller.rb +6 -0
  47. data/app/controllers/spree/webhook/payways_controller.rb +77 -0
  48. data/app/controllers/spree/webhook/wings_controller.rb +63 -0
  49. data/app/controllers/spree/wing/base_controller.rb +29 -0
  50. data/app/controllers/spree/wing/transactions_controller.rb +27 -0
  51. data/app/controllers/spree/wing_redirects_controller.rb +20 -0
  52. data/app/helpers/vpago/admin/base_helper_decorator.rb +40 -0
  53. data/app/helpers/vpago/vpago_payments_helper.rb +12 -0
  54. data/app/javascripts/vpago/vpago_payments/user_informers/firebase.js +62 -0
  55. data/app/jobs/application_unique_job.rb +1 -0
  56. data/app/jobs/vpago/payment_processor_job.rb +8 -0
  57. data/app/models/.gitkeep +0 -0
  58. data/app/models/concerns/vpago/payoutable.rb +11 -0
  59. data/app/models/spree/gateway/acleda.rb +63 -0
  60. data/app/models/spree/gateway/acleda_mobile.rb +46 -0
  61. data/app/models/spree/gateway/payway.rb +66 -0
  62. data/app/models/spree/gateway/payway_v2.rb +174 -0
  63. data/app/models/spree/gateway/wing_sdk.rb +51 -0
  64. data/app/models/spree/payout.rb +23 -0
  65. data/app/models/spree/payout_profile.rb +107 -0
  66. data/app/models/spree/payout_profile_product.rb +14 -0
  67. data/app/models/spree/payout_profile_shipping_method.rb +14 -0
  68. data/app/models/spree/payout_profiles/payway_v2.rb +40 -0
  69. data/app/models/spree/vpago_payment_source.rb +21 -0
  70. data/app/models/vpago/adjustment_decorator.rb +28 -0
  71. data/app/models/vpago/line_item_decorator.rb +75 -0
  72. data/app/models/vpago/order_decorator.rb +78 -0
  73. data/app/models/vpago/payment_decorator.rb +44 -0
  74. data/app/models/vpago/payment_method_decorator.rb +91 -0
  75. data/app/models/vpago/payouts_generator.rb +125 -0
  76. data/app/models/vpago/product_decorator.rb +30 -0
  77. data/app/models/vpago/promotion_action_decorator.rb +9 -0
  78. data/app/models/vpago/shipment_decorator.rb +23 -0
  79. data/app/models/vpago/shipping_method_decorator.rb +33 -0
  80. data/app/models/vpago/shipping_rate_decorator.rb +25 -0
  81. data/app/models/vpago/store_decorator.rb +17 -0
  82. data/app/models/vpago/tax_category_decorator.rb +9 -0
  83. data/app/models/vpago/variant_decorator.rb +22 -0
  84. data/app/models/vpago/vendor_decorator.rb +10 -0
  85. data/app/overrides/spree/admin/adjustments/_adjustment/handle_by_table_body.html.erb.deface +11 -0
  86. data/app/overrides/spree/admin/adjustments/_adjustments_table/handle_by_table_header.html.erb.deface +3 -0
  87. data/app/overrides/spree/admin/adjustments/_form/handle_by_field.html.erb.deface +10 -0
  88. data/app/overrides/spree/admin/orders/_shipment/edit_method.html.erb.deface +26 -0
  89. data/app/overrides/spree/admin/orders/_shipment/show_method.html.erb.deface +27 -0
  90. data/app/overrides/spree/admin/payment_methods/_form/enable_pre_auth_field.html.erb.deface +17 -0
  91. data/app/overrides/spree/admin/payment_methods/_form/vendor_field.html.erb.deface +6 -0
  92. data/app/overrides/spree/admin/payment_methods/index/list.html.erb.deface +45 -0
  93. data/app/overrides/spree/admin/payment_methods/index/payment_methods_tabs.html.erb.deface +9 -0
  94. data/app/overrides/spree/admin/payment_methods/index/vendor_body.html.erb.deface +5 -0
  95. data/app/overrides/spree/admin/payment_methods/index/vendor_header.html.erb.deface +5 -0
  96. data/app/overrides/spree/admin/payments/_list/actions.html.erb.deface +13 -0
  97. data/app/overrides/spree/admin/promotions/_promotion_action/run_by_field.html.erb.deface +13 -0
  98. data/app/overrides/spree/admin/shared/_order_tabs/payouts.html.erb.deface +8 -0
  99. data/app/overrides/spree/admin/shared/_product_tabs/payout_profile_products.html.erb.deface +8 -0
  100. data/app/overrides/spree/admin/shared/sub_menu/_integrations/payout_profiles.html.erb.deface +3 -0
  101. data/app/overrides/spree/admin/shipping_methods/_form/handle_by.html.erb.deface +12 -0
  102. data/app/overrides/spree/admin/shipping_methods/edit/shipping_method_tabs.html.erb.deface +3 -0
  103. data/app/overrides/spree/admin/tax_categories/_form/collect_by_field.html.erb.deface +10 -0
  104. data/app/overrides/spree/admin/tax_categories/index/collect_by_table_body.html.erb.deface +4 -0
  105. data/app/overrides/spree/admin/tax_categories/index/collect_by_table_header.html.erb.deface +4 -0
  106. data/app/serializers/spree/api/v2/platform/vpago_payment_source_serializer.rb +11 -0
  107. data/app/serializers/spree/v2/storefront/payment_method_serializer_decorator.rb +23 -0
  108. data/app/serializers/spree/v2/storefront/payment_redirect_serializer.rb +13 -0
  109. data/app/serializers/spree/v2/storefront/payment_serializer_decorator.rb +13 -0
  110. data/app/serializers/spree/v2/storefront/vpago_payment_source_serializer.rb +9 -0
  111. data/app/services/.gitkeep +0 -0
  112. data/app/services/vpago/payment_finder.rb +27 -0
  113. data/app/services/vpago/payment_processor.rb +72 -0
  114. data/app/services/vpago/payment_redirect_handler.rb +194 -0
  115. data/app/services/vpago/payment_url_constructor.rb +32 -0
  116. data/app/services/vpago/payments/find_or_create.rb +51 -0
  117. data/app/services/vpago/payout_profiles/payway/base_payout_profile_request.rb +38 -0
  118. data/app/services/vpago/payout_profiles/payway/open_ssl_encrypter.rb +31 -0
  119. data/app/services/vpago/payout_profiles/payway/payout_profile_request_creator.rb +50 -0
  120. data/app/services/vpago/payout_profiles/payway/payout_profile_request_params_builder.rb +58 -0
  121. data/app/services/vpago/payout_profiles/payway/payout_profile_request_updater.rb +28 -0
  122. data/app/services/vpago/payway_return_options_builder.rb +39 -0
  123. data/app/services/vpago/user_informers/firebase.rb +52 -0
  124. data/app/views/.gitkeep +0 -0
  125. data/app/views/layouts/acleda.html.erb +18 -0
  126. data/app/views/layouts/payway.html.erb +24 -0
  127. data/app/views/layouts/payway_v2.html.erb +18 -0
  128. data/app/views/layouts/vpago_payments.html.erb +18 -0
  129. data/app/views/layouts/wing.html.erb +18 -0
  130. data/app/views/spree/_payment_icon.html.erb +25 -0
  131. data/app/views/spree/acleda_redirects/show.html.erb +3 -0
  132. data/app/views/spree/admin/payments/source_forms/_payment_payway.html.erb +4 -0
  133. data/app/views/spree/admin/payments/source_forms/_payway_v2.html.erb +7 -0
  134. data/app/views/spree/admin/payments/source_views/_acleda.html.erb +1 -0
  135. data/app/views/spree/admin/payments/source_views/_acleda_mobile.html.erb +1 -0
  136. data/app/views/spree/admin/payments/source_views/_payment_payway.html.erb +98 -0
  137. data/app/views/spree/admin/payments/source_views/_payway_v2.html.erb +5 -0
  138. data/app/views/spree/admin/payments/source_views/_vpago_payment_tmpl.html.erb +113 -0
  139. data/app/views/spree/admin/payments/source_views/_wingsdk.html.erb +5 -0
  140. data/app/views/spree/admin/payout_profile_products/_form.html.erb +28 -0
  141. data/app/views/spree/admin/payout_profile_products/edit.html.erb +18 -0
  142. data/app/views/spree/admin/payout_profile_products/index.html.erb +58 -0
  143. data/app/views/spree/admin/payout_profile_products/new.html.erb +22 -0
  144. data/app/views/spree/admin/payout_profile_shipping_methods/_form.html.erb +28 -0
  145. data/app/views/spree/admin/payout_profile_shipping_methods/edit.html.erb +22 -0
  146. data/app/views/spree/admin/payout_profile_shipping_methods/index.html.erb +6 -0
  147. data/app/views/spree/admin/payout_profile_shipping_methods/new.html.erb +27 -0
  148. data/app/views/spree/admin/payout_profiles/_filter.html.erb +19 -0
  149. data/app/views/spree/admin/payout_profiles/_form.html.erb +72 -0
  150. data/app/views/spree/admin/payout_profiles/edit.html.erb +33 -0
  151. data/app/views/spree/admin/payout_profiles/index.html.erb +63 -0
  152. data/app/views/spree/admin/payout_profiles/new.html.erb +13 -0
  153. data/app/views/spree/admin/payouts/_line_item_info_with_popover.html.erb +43 -0
  154. data/app/views/spree/admin/payouts/index.html.erb +46 -0
  155. data/app/views/spree/admin/shared/_payment_methods_tabs.html.erb +15 -0
  156. data/app/views/spree/admin/shared/_shipping_method_tabs.html.erb +19 -0
  157. data/app/views/spree/admin/shared/payout_profile/_info_card.html.erb +24 -0
  158. data/app/views/spree/admin/shared/payout_profile/_status.html.erb +11 -0
  159. data/app/views/spree/checkout/payment/_acleda.html.erb +1 -0
  160. data/app/views/spree/checkout/payment/_acleda_checkout_form.html.erb +14 -0
  161. data/app/views/spree/checkout/payment/_acleda_mobile.html.erb +0 -0
  162. data/app/views/spree/checkout/payment/_payment_payway.html.erb +21 -0
  163. data/app/views/spree/checkout/payment/_payway_loader.html.erb +2 -0
  164. data/app/views/spree/checkout/payment/_payway_root.html.erb +9 -0
  165. data/app/views/spree/checkout/payment/_payway_script.html.erb +77 -0
  166. data/app/views/spree/checkout/payment/_payway_v2.html.erb +1 -0
  167. data/app/views/spree/checkout/payment/_payway_v2_loader.html.erb +2 -0
  168. data/app/views/spree/checkout/payment/_payway_v2_root.html.erb +9 -0
  169. data/app/views/spree/checkout/payment/_payway_v2_script.html.erb +79 -0
  170. data/app/views/spree/checkout/payment/_wing_checkout_form.html.erb +18 -0
  171. data/app/views/spree/checkout/payment/_wingsdk.html.erb +1 -0
  172. data/app/views/spree/checkout/payment/acleda_form.html.erb +3 -0
  173. data/app/views/spree/checkout/payment/payway_form.html.erb +10 -0
  174. data/app/views/spree/checkout/payment/payway_v2_form.html.erb +10 -0
  175. data/app/views/spree/checkout/payment/wingsdk_form.html.erb +3 -0
  176. data/app/views/spree/payway_card_popups/_form.html.erb +10 -0
  177. data/app/views/spree/payway_card_popups/show.html.erb +5 -0
  178. data/app/views/spree/payway_results/failed.html.erb +1 -0
  179. data/app/views/spree/payway_results/success.html.erb +1 -0
  180. data/app/views/spree/payway_v2_card_popups/_form.html.erb +15 -0
  181. data/app/views/spree/payway_v2_card_popups/show.html.erb +3 -0
  182. data/app/views/spree/vpago_payments/checkout.html.erb +3 -0
  183. data/app/views/spree/vpago_payments/forms/spree/gateway/_payway_v2.html.erb +13 -0
  184. data/app/views/spree/vpago_payments/processing.html.erb +49 -0
  185. data/app/views/spree/vpago_payments/success.html.erb +3 -0
  186. data/app/views/spree/wing_redirects/show.html.erb +3 -0
  187. data/bin/rails +8 -0
  188. data/build.js +9 -0
  189. data/config/initializers/assets.rb +1 -0
  190. data/config/initializers/spree_permitted_attributes.rb +5 -0
  191. data/config/locales/en.yml +28 -0
  192. data/config/locales/km.yml +24 -0
  193. data/config/routes.rb +92 -0
  194. data/db/migrate/20210128040625_create_spree_vpago_payment_sources.rb +14 -0
  195. data/db/migrate/20210430052432_add_fields_to_payment_sources.rb +7 -0
  196. data/db/migrate/20210824044737_add_preference_to_spree_vpago_payment_source.rb +5 -0
  197. data/db/migrate/20240506095140_create_spree_payout_profiles.rb +22 -0
  198. data/db/migrate/20240506095148_create_spree_payout_profile_products.rb +10 -0
  199. data/db/migrate/20240523070757_add_optional_spere_payout_profile_products.rb +5 -0
  200. data/db/migrate/20240715091228_create_spree_payouts.rb +25 -0
  201. data/db/migrate/20240718195510_create_spree_payout_profile_shipping_methods.rb +15 -0
  202. data/db/migrate/20240718201453_add_handle_by_to_spree_adjustments.rb +5 -0
  203. data/db/migrate/20240718201509_add_run_by_to_spree_promotion_actions.rb +5 -0
  204. data/db/migrate/20240718201523_add_collect_by_to_spree_tax_categories.rb +5 -0
  205. data/db/migrate/20240718201538_add_handle_by_to_spree_shipping_method.rb +5 -0
  206. data/db/migrate/20240718201554_add_handle_by_to_spree_shipping_rates.rb +5 -0
  207. data/db/migrate/20240808102853_add_vendor_reference_to_spree_payment_methods.rb +7 -0
  208. data/db/migrate/20240904030132_add_gateway_status_to_spree_payments.rb +5 -0
  209. data/db/migrate/20241029071959_add_pre_auth_response_to_spree_payment.rb +5 -0
  210. data/db/migrate/20241202104014_add_enable_pre_auth_to_spree_payment_method.rb +5 -0
  211. data/db/migrate/20250121044614_add_transaction_response_to_spree_payments.rb +5 -0
  212. data/docs/acleda.md +65 -0
  213. data/gemfiles/spree_3_7.gemfile +9 -0
  214. data/gemfiles/spree_4_0.gemfile +8 -0
  215. data/gemfiles/spree_4_1.gemfile +9 -0
  216. data/gemfiles/spree_master.gemfile +8 -0
  217. data/lib/generators/spree_vpago/install/install_generator.rb +26 -0
  218. data/lib/generators/spree_vpago/install/templates/app/assets/images/vpago/payway/acleda_merchant_logo_300x300.png +0 -0
  219. data/lib/spree_vpago/engine.rb +36 -0
  220. data/lib/spree_vpago/factories.rb +6 -0
  221. data/lib/spree_vpago/version.rb +9 -0
  222. data/lib/spree_vpago.rb +5 -0
  223. data/lib/vpago/acleda/base.rb +111 -0
  224. data/lib/vpago/acleda/checkout.rb +105 -0
  225. data/lib/vpago/acleda/deeplink_checkout.rb +74 -0
  226. data/lib/vpago/acleda/payment_request_updater.rb +38 -0
  227. data/lib/vpago/acleda/transaction_status.rb +71 -0
  228. data/lib/vpago/acleda_mobile/base.rb +28 -0
  229. data/lib/vpago/acleda_mobile/callback_validator.php +35 -0
  230. data/lib/vpago/acleda_mobile/callback_validator.rb +38 -0
  231. data/lib/vpago/acleda_mobile/checkout.rb +78 -0
  232. data/lib/vpago/acleda_mobile/payment_request_updater.rb +34 -0
  233. data/lib/vpago/acleda_mobile/payment_retriever.rb +24 -0
  234. data/lib/vpago/acleda_mobile/transaction_status.rb +35 -0
  235. data/lib/vpago/payment_amount_calculator.rb +23 -0
  236. data/lib/vpago/payment_request_updater.rb +19 -0
  237. data/lib/vpago/payment_status_marker.rb +109 -0
  238. data/lib/vpago/payway/base.rb +112 -0
  239. data/lib/vpago/payway/checkout.rb +24 -0
  240. data/lib/vpago/payway/payment_request_updater.rb +31 -0
  241. data/lib/vpago/payway/payment_status_marker.rb +84 -0
  242. data/lib/vpago/payway/transaction_status.rb +74 -0
  243. data/lib/vpago/payway.rb +13 -0
  244. data/lib/vpago/payway_v2/base.rb +153 -0
  245. data/lib/vpago/payway_v2/checkout.rb +35 -0
  246. data/lib/vpago/payway_v2/payment_request_updater.rb +65 -0
  247. data/lib/vpago/payway_v2/payouts_params_constructor.rb +47 -0
  248. data/lib/vpago/payway_v2/pre_auth_canceler.rb +43 -0
  249. data/lib/vpago/payway_v2/pre_auth_completer.rb +76 -0
  250. data/lib/vpago/payway_v2/transaction_status.rb +85 -0
  251. data/lib/vpago/wing_sdk/base.rb +58 -0
  252. data/lib/vpago/wing_sdk/checkout.rb +20 -0
  253. data/lib/vpago/wing_sdk/payment_request_updater.rb +46 -0
  254. data/lib/vpago/wing_sdk/payment_retriever.rb +34 -0
  255. data/lib/vpago/wing_sdk/transaction_status_checker.rb +64 -0
  256. data/lib/vpago/wing_sdk/transaction_status_response.rb +33 -0
  257. data/node_modules/.yarn-integrity +147 -0
  258. data/package-lock.json +1491 -0
  259. data/package.json +10 -0
  260. data/spree_vpago.gemspec +33 -0
  261. data/yarn.lock +921 -0
  262. metadata +403 -0
@@ -0,0 +1,71 @@
1
+ module Spree
2
+ class VpagoPaymentsController < ApplicationController
3
+ layout 'vpago_payments'
4
+ helper 'vpago/vpago_payments'
5
+
6
+ skip_before_action :verify_authenticity_token, only: [:process_payment]
7
+
8
+ rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
9
+ rescue_from CanCan::AccessDenied, with: :access_denied
10
+
11
+ # GET
12
+ def checkout
13
+ @payment = Vpago::PaymentFinder.new(params.permit!.to_h).find_and_verify
14
+ raise ActiveRecord::RecordNotFound unless @payment.present?
15
+
16
+ return redirect_to @payment.processing_url, allow_other_host: true unless @payment.checkout?
17
+
18
+ @order = @payment.order
19
+ end
20
+
21
+ # GET
22
+ def processing
23
+ @payment = Vpago::PaymentFinder.new(params.permit!.to_h).find_and_verify
24
+ raise ActiveRecord::RecordNotFound unless @payment.present?
25
+
26
+ @order = @payment.order
27
+ end
28
+
29
+ # GET
30
+ def success
31
+ @payment = Vpago::PaymentFinder.new(params.permit!.to_h).find_and_verify
32
+ raise ActiveRecord::RecordNotFound unless @payment.present?
33
+
34
+ @order = @payment.order
35
+ raise CanCan::AccessDenied unless @order.completed?
36
+ end
37
+
38
+ # POST
39
+ def process_payment
40
+ return render json: { status: :ok }, status: :ok if request.method != 'POST'
41
+
42
+ @payment = Vpago::PaymentFinder.new(params.permit!.to_h).find_and_verify
43
+ return render_not_found unless @payment.present?
44
+
45
+ unless @payment.order.paid?
46
+ Vpago::PaymentProcessorJob.perform_later(
47
+ payment_number: @payment.number
48
+ )
49
+ end
50
+
51
+ render json: { status: :ok }, status: :ok
52
+ rescue StandardError => e
53
+ Rails.logger.error("Failed to enqueued payment processor job: #{params} #{e.message}")
54
+ render json: { status: :internal_server_error, message: 'Failed to enqueue payment processor job' }, status: :internal_server_error
55
+ end
56
+
57
+ def record_not_found
58
+ respond_to do |format|
59
+ format.html { render file: Rails.public_path.join('404.html'), status: :not_found, layout: false }
60
+ format.json { render json: { status: :not_found }, status: :not_found }
61
+ end
62
+ end
63
+
64
+ def access_denied
65
+ respond_to do |format|
66
+ format.html { render file: Rails.public_path.join('422.html'), status: :not_found, layout: false }
67
+ format.json { render json: { status: :unauthorized }, status: :unauthorized }
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,88 @@
1
+ module Spree
2
+ module Webhook
3
+ class AcledaMobilesController < BaseController
4
+ skip_before_action :verify_authenticity_token
5
+ before_action :find_payment, only: [:return]
6
+
7
+ # {
8
+ # "TransactionId": "16de81d4-b5ef-ef59-16de-81d4b5efef59",
9
+ # "PaymentTokenId": "REF0361472663", VTENH payment number
10
+ # "TxnAmount": "30",
11
+ # "SenderName": "Test User",
12
+ # "SignedHash": "c5b9be690bde7dc8a0abebb1a45c0850359540a4977aecd4cdf13e15a2edfe79"
13
+ # }
14
+ def return
15
+ request_updater = ::Vpago::AcledaMobile::PaymentRequestUpdater.new(@payment)
16
+ request_updater.call
17
+
18
+ order = @payment.order
19
+ order = order.reload
20
+
21
+ if order.paid? || @payment.pending?
22
+ render_success
23
+ else
24
+ render_failed
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def find_payment
31
+ options = params.slice(:TransactionId, :PaymentTokenId, :TxnAmount, :SenderName, :SignedHash)
32
+
33
+ service = Vpago::AcledaMobile::PaymentRetriever.new(options)
34
+ service.call
35
+
36
+ return render_hashing_error unless service.data_valid?
37
+
38
+ @payment = service.payment
39
+ return render_payment_not_found if @payment.blank?
40
+ end
41
+
42
+ def render_success
43
+ status_code = 200
44
+ response_data = acleda_mobile_response_data('Success', status_code)
45
+
46
+ acleda_mobile_response(response_data, status_code)
47
+ end
48
+
49
+ def render_failed
50
+ status_code = 201
51
+ response_data = acleda_mobile_response_data('Failed', status_code)
52
+
53
+ acleda_mobile_response(response_data, status_code)
54
+ end
55
+
56
+ def render_payment_not_found
57
+ status_code = 203
58
+ response_data = acleda_mobile_response_data('Payment not found', status_code)
59
+
60
+ acleda_mobile_response(response_data, status_code)
61
+ end
62
+
63
+ def render_hashing_error
64
+ status_code = 403
65
+ response_data = acleda_mobile_response_data('Invalid SignedHash', status_code)
66
+
67
+ acleda_mobile_response(response_data, status_code)
68
+ end
69
+
70
+ def acleda_mobile_response(response_data, status_code)
71
+ render json: response_data, status: status_code
72
+ end
73
+
74
+ def acleda_mobile_response_data(message, code)
75
+ {
76
+ status: {
77
+ code: code,
78
+ message: message
79
+ },
80
+ data: {
81
+ TransactionId: params[:TransactionId],
82
+ PaymentTokenId: params[:PaymentTokenId]
83
+ }
84
+ }
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,80 @@
1
+ module Spree
2
+ module Webhook
3
+ class AcledasController < BaseController
4
+ skip_before_action :verify_authenticity_token, only: [:return]
5
+
6
+ before_action :find_payment, only: %i[success error return]
7
+
8
+ rescue_from ::ActiveRecord::RecordNotFound, with: :record_not_found
9
+
10
+ ## call back after transaction complete at acleda system
11
+ ## {"amount": "15.0", "_transactionid"=>"PJ9ETZD4", "_paymentresult"=>"SUCCESS", "_paymenttokenid"=>"lVqWKcLHVk6s0rIgk/T8Vdbzsg0=", "_resultCode"=>"0"}
12
+ def return
13
+ render_plain = true
14
+ check_and_redirect(render_plain)
15
+ end
16
+
17
+ ## success
18
+ ## {"_arNo"=>"PJ9ETZD4", "_transactionid"=>"PJ9ETZD4", "_paymentresult"=>"SUCCESS", "_paymenttokenid"=>"lVqWKcLHVk6s0rIgk/T8Vdbzsg0=", "_resultCode"=>"0", "controller"=>"spree/webhook/acledas", "action"=>"success"}
19
+ def success
20
+ check_and_redirect
21
+ end
22
+
23
+ def error
24
+ order = @payment.order
25
+
26
+ if order.paid?
27
+ flash[:order_completed] = '1' # required by order_just_completed for purchase tracking
28
+ end
29
+
30
+ pending_or_paid = order.paid? || @payment.pending?
31
+ if params[:app_checkout].to_s == '1'
32
+ redirect_to pending_or_paid ? success_payway_results_path : failed_payway_results_path
33
+ else
34
+ redirect_to pending_or_paid ? order_path(order) : checkout_state_path(:payment)
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def check_and_redirect(render_plain: false)
41
+ request_updater = ::Vpago::Acleda::PaymentRequestUpdater.new(@payment)
42
+ request_updater.call
43
+
44
+ order = @payment.order
45
+ order = order.reload
46
+
47
+ if render_plain
48
+ order.paid? || @payment.pending? ? render(plain: :success) : render(plain: :failed, status: 400)
49
+ else
50
+ redirect_order(order)
51
+ end
52
+ end
53
+
54
+ def redirect_order(order)
55
+ pending_or_paid = order.paid? || @payment.pending?
56
+
57
+ if params[:app_checkout].to_s == '1'
58
+ redirect_to pending_or_paid ? success_payway_results_path : failed_payway_results_path
59
+ else
60
+ flash[:order_completed] = '1' if order.paid? # required by order_just_completed for purchase tracking
61
+ redirect_to pending_or_paid ? order_path(order) : checkout_state_path(:payment)
62
+ end
63
+ end
64
+
65
+ def find_payment
66
+ @payment = nil
67
+ raise ::ActiveRecord::RecordNotFound if params[:_paymenttokenid].blank?
68
+
69
+ payment_source = Spree::VpagoPaymentSource.find_by(transaction_id: params[:_paymenttokenid])
70
+ raise ::ActiveRecord::RecordNotFound if payment_source.blank?
71
+
72
+ @payment = payment_source.payment
73
+ end
74
+
75
+ def record_not_found
76
+ render(plain: :payment_not_found, status: 404)
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,6 @@
1
+ module Spree
2
+ module Webhook
3
+ class BaseController < ::ApplicationController
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,77 @@
1
+ module Spree
2
+ module Webhook
3
+ class PaywaysController < BaseController
4
+ skip_before_action :verify_authenticity_token, only: %i[return v2_return continue v2_continue]
5
+
6
+ # match via: [:get, :post]
7
+ # {"response"=>"{\"tran_id\":\"PE13LXT1\",\"status\":0"}"}
8
+ def v2_return
9
+ handler_service = v2_request_updater_service
10
+
11
+ return_callback_handler(handler_service)
12
+ end
13
+
14
+ def return
15
+ handler_service = request_updater_service
16
+
17
+ return_callback_handler(handler_service)
18
+ end
19
+
20
+ # https://vtenh.herokuapp.com/payways/continue?tran_id=P2W2S1LB
21
+ def v2_continue
22
+ continue_callback_handler
23
+ end
24
+
25
+ def continue
26
+ continue_callback_handler
27
+ end
28
+
29
+ private
30
+
31
+ def v2_request_updater_service
32
+ ::Vpago::PaywayV2::PaymentRequestUpdater
33
+ end
34
+
35
+ def request_updater_service
36
+ ::Vpago::Payway::PaymentRequestUpdater
37
+ end
38
+
39
+ # the callback invoke by PAYWAY in case of success
40
+ def return_callback_handler(handler_service)
41
+ # pawway send get request with nothing
42
+ return render plain: :ok if request.method == 'GET'
43
+
44
+ builder = Vpago::PaywayReturnOptionsBuilder.new(params: params)
45
+ payment = builder.payment
46
+
47
+ request_updater = handler_service.new(payment)
48
+ request_updater.call
49
+
50
+ order = payment.order
51
+ order = order.reload
52
+
53
+ if order.paid? || payment.pending?
54
+ render plain: :success
55
+ else
56
+ render plain: :failed, status: 400
57
+ end
58
+ end
59
+
60
+ def continue_callback_handler
61
+ payment = Spree::Payment.find_by number: params[:tran_id]
62
+ order = payment.order
63
+
64
+ if order.paid?
65
+ flash[:order_completed] = '1' # required by order_just_completed for purchase tracking
66
+ end
67
+
68
+ pending_or_paid = order.paid? || payment.pending?
69
+ if params[:app_checkout] == 'yes'
70
+ redirect_to pending_or_paid ? success_payway_results_path : failed_payway_results_path
71
+ else
72
+ redirect_to pending_or_paid ? order_path(order) : checkout_state_path(:payment)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,63 @@
1
+ module Spree
2
+ module Webhook
3
+ class WingsController < BaseController
4
+ skip_before_action :verify_authenticity_token, only: %i[return continue create]
5
+
6
+ before_action :retrive_payment, only: [:create]
7
+ before_action :find_payment, only: %i[return continue]
8
+
9
+ def create
10
+ render_plain = true
11
+ check_and_redirect(render_plain)
12
+ end
13
+
14
+ ## click on button Done: POST { wing_id: payment_number, response: {"remark"=>"PNRE5V5E", "amount"=>" USD 30.00", "total"=>" USD 30.00", "transaction_id"=>"ONL031157", "customer_name"=>"Wing Testing WCX-USD", "biller_name"=>"VTENH"}}
15
+ ## click on button Back: GET { wing_id: payment_number }
16
+ def return
17
+ check_and_redirect
18
+ end
19
+
20
+ private
21
+
22
+ def find_payment
23
+ @payment = ::Spree::Payment.find_by(number: params[:wing_id])
24
+ end
25
+
26
+ def retrive_payment
27
+ wing_payment_method = Spree::PaymentMethod.find_by(type: Spree::PaymentMethod::TYPE_WINGSDK)
28
+ rest_api_key = wing_payment_method.preferences[:rest_api_key]
29
+ wing_response = params[:contents]
30
+
31
+ payment_retriever = ::Vpago::WingSdk::PaymentRetriever.new(rest_api_key, wing_response)
32
+ payment_retriever.call
33
+
34
+ @payment = payment_retriever.payment
35
+ end
36
+
37
+ def check_and_redirect(render_plain: false)
38
+ request_updater = ::Vpago::WingSdk::PaymentRequestUpdater.new(@payment)
39
+ request_updater.call
40
+
41
+ order = @payment.order
42
+ order = order.reload
43
+
44
+ pending_or_paid = order.paid? || @payment.pending?
45
+ if render_plain
46
+ pending_or_paid ? render(plain: :success) : render(plain: :failed, status: 400)
47
+ else
48
+ redirect_order(order)
49
+ end
50
+ end
51
+
52
+ def redirect_order(order)
53
+ pending_or_paid = order.paid? || @payment.pending?
54
+ if params[:app_checkout] == 'yes'
55
+ redirect_to pending_or_paid ? success_payway_results_path : failed_payway_results_path
56
+ else
57
+ flash[:order_completed] = '1' if order.paid? # required by order_just_completed for purchase tracking
58
+ redirect_to pending_or_paid ? order_path(order) : checkout_state_path(:payment)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,29 @@
1
+ module Spree
2
+ module Wing
3
+ class BaseController < ::ApplicationController
4
+ before_action :wing_http_authenticate!
5
+
6
+ rescue_from ActiveRecord::RecordNotFound, with: :not_found
7
+
8
+ def wing_http_authenticate!
9
+ wing_payment_method = Spree::PaymentMethod.find_by(type: Spree::PaymentMethod::TYPE_WINGSDK)
10
+
11
+ authenticate_or_request_with_http_basic do |username, password|
12
+ return false unless wing_payment_method.present?
13
+
14
+ if wing_payment_method.preferred_basic_auth_username.blank? ||
15
+ wing_payment_method.preferred_basic_auth_password.blank?
16
+ return false
17
+ end
18
+
19
+ username == wing_payment_method.preferred_basic_auth_username &&
20
+ password == wing_payment_method.preferred_basic_auth_password
21
+ end
22
+ end
23
+
24
+ def not_found
25
+ render json: { response_code: 404, response_msg: I18n.t(:resource_not_found, scope: 'spree.api') }, status: 404
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,27 @@
1
+ module Spree
2
+ module Wing
3
+ class TransactionsController < BaseController
4
+ before_action :load_payment_source
5
+ def show
6
+ @transaction_status_response = Vpago::WingSdk::TransactionStatusResponse.new(@payment_source)
7
+ @transaction_status_response.call
8
+
9
+ render_result
10
+ end
11
+
12
+ private
13
+
14
+ def load_payment_source
15
+ @payment_source = ::Spree::VpagoPaymentSource.find_by!(transaction_id: params[:id])
16
+ end
17
+
18
+ def render_result
19
+ if @transaction_status_response.success?
20
+ render json: @transaction_status_response.result, status: 200
21
+ else
22
+ render json: { response_code: 422, response_msg: 'Unable to load response from wing' }, status: 422
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,20 @@
1
+ module Spree
2
+ class WingRedirectsController < ApplicationController
3
+ layout 'wing'
4
+ before_action :load_payment, only: [:show]
5
+
6
+ def show
7
+ if @payment.present?
8
+ options = {
9
+ app_checkout: true
10
+ }
11
+
12
+ @client_redirect = ::Vpago::WingSdk::Checkout.new(@payment, options)
13
+ end
14
+ end
15
+
16
+ def load_payment
17
+ @payment = ::Spree::Payment.find_by(number: params[:payment_number])
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,40 @@
1
+ module Vpago
2
+ module Admin
3
+ module BaseHelperDecorator
4
+ def acleda_payment_card_options
5
+ { '0 - XPAY': 0, '1 - Visa, Master Card, etc.': 1 }
6
+ end
7
+
8
+ # frontend should implement these in UI
9
+ def available_payment_icons
10
+ %w[
11
+ payway_abapay_khqr
12
+ payway_abapay
13
+ payway_alipay
14
+ payway_wechat
15
+ acleda
16
+ acleda_khqr
17
+ acleda_cards
18
+ cheque
19
+ payway_cards
20
+ wingpay
21
+ ]
22
+ end
23
+
24
+ def preference_field_for(form, field, options)
25
+ case field
26
+ when 'preferred_acleda_type'
27
+ return form.select(:preferred_acleda_type, form.object.class::TYPES, {}, class: 'fullwidth select2')
28
+ when 'preferred_acleda_payment_card'
29
+ return form.select(:preferred_acleda_payment_card, acleda_payment_card_options, {},
30
+ class: 'fullwidth select2')
31
+ when 'preferred_icon_name'
32
+ return form.select(:preferred_icon_name, available_payment_icons, {}, class: 'fullwidth select2')
33
+ end
34
+ super
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ Spree::Admin::BaseHelper.prepend(Vpago::Admin::BaseHelperDecorator)
@@ -0,0 +1,12 @@
1
+ module Vpago
2
+ module VpagoPaymentsHelper
3
+ def user_informer
4
+ 'firebase'
5
+ end
6
+
7
+ # eg. forms/spree/gateway/payway_v2
8
+ def render_form
9
+ render partial: "spree/vpago_payments/forms/#{@payment.payment_method.class.to_s.underscore}"
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,62 @@
1
+ import { initializeApp } from "firebase/app";
2
+ import { getFirestore, doc, onSnapshot, setDoc } from "firebase/firestore";
3
+
4
+ async function listenToProcessingState({
5
+ firebaseConfigs,
6
+ orderNumber,
7
+ onPaymentIsProcessing,
8
+ onOrderIsProcessing,
9
+ onOrderIsCompleted,
10
+ onOrderProcessFailed,
11
+ onPaymentIsRefunded,
12
+ onPaymentProcessFailed,
13
+ onCompleted,
14
+ }) {
15
+ const app = initializeApp(firebaseConfigs);
16
+ const db = getFirestore(app);
17
+
18
+ const currentDate = new Date().toISOString().split("T")[0];
19
+
20
+ const documentRef = doc(db, "statuses", "cart", currentDate, orderNumber);
21
+ await setDoc(documentRef, { listening: true }, { merge: true });
22
+
23
+ onSnapshot(documentRef, (doc) => {
24
+ let documentData = doc.data();
25
+
26
+ let orderState = documentData["order_state"];
27
+ let paymentState = documentData["payment_state"];
28
+ let messageCode = documentData["message_code"];
29
+ let logMessage = documentData["log_message"];
30
+
31
+ let orderCompleted = orderState === "complete";
32
+ if (orderCompleted) {
33
+ onCompleted(orderState, paymentState);
34
+ return;
35
+ }
36
+
37
+ switch (messageCode) {
38
+ case "payment_is_processing":
39
+ onPaymentIsProcessing(orderState, paymentState, logMessage);
40
+ break;
41
+ case "order_is_processing":
42
+ onOrderIsProcessing(orderState, paymentState, logMessage);
43
+ break;
44
+ case "order_is_completed":
45
+ onOrderIsCompleted(orderState, paymentState, logMessage);
46
+ break;
47
+ case "order_process_failed":
48
+ onOrderProcessFailed(orderState, paymentState, logMessage);
49
+ break;
50
+ case "payment_is_refunded":
51
+ onPaymentIsRefunded(orderState, paymentState, logMessage);
52
+ break;
53
+ case "payment_process_failed":
54
+ onPaymentProcessFailed(orderState, paymentState, logMessage);
55
+ break;
56
+ default:
57
+ break;
58
+ }
59
+ });
60
+ }
61
+
62
+ window.listenToProcessingState = listenToProcessingState;
@@ -0,0 +1 @@
1
+ class ApplicationUniqueJob < ActiveJob::Base; end
@@ -0,0 +1,8 @@
1
+ module Vpago
2
+ class PaymentProcessorJob < ::ApplicationUniqueJob
3
+ def perform(options)
4
+ payment = Spree::Payment.find_by(number: options[:payment_number])
5
+ Vpago::PaymentProcessor.new(payment: payment).call
6
+ end
7
+ end
8
+ end
File without changes
@@ -0,0 +1,11 @@
1
+ module Vpago
2
+ module Payoutable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ has_many :payouts, class_name: 'Spree::Payout', as: :payoutable
7
+ has_many :confirmed_payouts_for_vendor, -> { confirmed.where(default: false) },
8
+ class_name: 'Spree::Payout', as: :payoutable
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,63 @@
1
+ module Spree
2
+ class Gateway::Acleda < PaymentMethod
3
+ preference :payment_expiry_time_in_mn, :integer
4
+ preference :host, :string
5
+ preference :login_id, :string
6
+ preference :password, :string
7
+ preference :merchant_id, :string
8
+ preference :merchant_name, :string
9
+ preference :signature, :string
10
+ preference :deeplink_partner_id, :string
11
+ preference :deeplink_data_encryption_key, :string
12
+ preference :success_url, :string
13
+ preference :error_url, :string
14
+ preference :other_url, :string
15
+ preference :acleda_company_name, :string
16
+ preference :acleda_payment_card, :integer
17
+
18
+ TYPES = %w[KHQR XPAY-MPGS].freeze
19
+ preference :acleda_type, :string
20
+
21
+ def xpay_mpgs?
22
+ preferred_acleda_type == 'XPAY-MPGS'
23
+ end
24
+
25
+ def khqr?
26
+ preferred_acleda_type == 'KHQR'
27
+ end
28
+
29
+ def payment_source_class
30
+ Spree::VpagoPaymentSource
31
+ end
32
+
33
+ def payment_profiles_supported?
34
+ false
35
+ end
36
+
37
+ # Custom PaymentMethod/Gateway can redefine this method to check method
38
+ # availability for concrete order.
39
+ def available_for_order?(_order)
40
+ true
41
+ end
42
+
43
+ # force to purchase instead of authorize
44
+ def auto_capture?
45
+ true
46
+ end
47
+
48
+ def process(_money, _source, gateway_options)
49
+ Rails.logger.debug { "About to create payment for order #{gateway_options[:order_id]}" }
50
+ # First of all, invalidate all previous tranx orders to prevent multiple paid orders
51
+ # source.save!
52
+ ActiveMerchant::Billing::Response.new(true, 'Order created')
53
+ end
54
+
55
+ def cancel(_response_code)
56
+ # we can use this to send request to payment gateway api to cancel the payment ( void )
57
+ # currently Payway does not support to cancel the gateway
58
+
59
+ # in our case don't do anything
60
+ ActiveMerchant::Billing::Response.new(true, 'Acleda order has been cancelled.')
61
+ end
62
+ end
63
+ end