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
+ require 'faraday'
2
+
3
+ module Vpago
4
+ module Acleda
5
+ class TransactionStatus < Base
6
+ attr_accessor :error_message, :result
7
+
8
+ def call
9
+ prepare
10
+ process
11
+ end
12
+
13
+ def prepare
14
+ @error_message = nil
15
+ @result = nil
16
+ end
17
+
18
+ def process
19
+ @response = check_acleda_payment_status
20
+
21
+ if @response.status == 200
22
+ if (json_response['result']['code']).zero?
23
+ @result = json_response
24
+ else
25
+ fail!(json_response['result']['errorDetails'])
26
+ end
27
+ else
28
+ fail!(@response.body)
29
+ end
30
+ end
31
+
32
+ def request_payload
33
+ payment_token_id = @payment.source.transaction_id
34
+
35
+ {
36
+ loginId: login_id,
37
+ password: password,
38
+ merchantName: merchant_name,
39
+ signature: signature,
40
+ merchantId: merchant_id,
41
+ paymentTokenid: payment_token_id
42
+ }
43
+ end
44
+
45
+ def check_acleda_payment_status
46
+ con = Faraday::Connection.new(url: host)
47
+
48
+ con.post(check_status_path) do |request|
49
+ request.headers['Content-Type'] = 'application/json'
50
+ request.body = request_payload.to_json
51
+ end
52
+ end
53
+
54
+ def check_status_path
55
+ ENV.fetch('ACLEDA_CHECK_STATUS_PATH', nil)
56
+ end
57
+
58
+ def json_response
59
+ @json_response ||= JSON.parse(@response.body)
60
+ end
61
+
62
+ def fail!(message)
63
+ @error_message = message
64
+ end
65
+
66
+ def success?
67
+ @error_message.nil?
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,28 @@
1
+ module Vpago
2
+ module AcledaMobile
3
+ class Base
4
+ include Vpago::PaymentAmountCalculator
5
+
6
+ def initialize(payment, options = {})
7
+ @options = options
8
+ @payment = payment
9
+ end
10
+
11
+ def payment_number
12
+ @payment.number
13
+ end
14
+
15
+ def encryption_key
16
+ @payment.payment_method.preferences[:data_encryption_key]
17
+ end
18
+
19
+ def return_to_app_url
20
+ @payment.payment_method.preferences[:app_url]
21
+ end
22
+
23
+ def partner_id
24
+ @payment.payment_method.preferences[:partner_id]
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,35 @@
1
+ <?php
2
+ $data = array(
3
+ "TransactionId" => "REF0361472663",
4
+ "PaymentTokenId" => "16de81d4-b5ef-ef59-16de-81d4b5efef59",
5
+ "TxnAmount" => "30",
6
+ "SenderName" => "Test User"
7
+ );
8
+
9
+ // will be provided
10
+ $secret_key = 'VTenhSecret';
11
+
12
+ // signed request fields
13
+ $hash_data = $data['TransactionId'] . ' ' . $data['PaymentTokenId'] . ' ' . $data['TxnAmount'];
14
+ $binary_output = false;
15
+
16
+ // calculate the signed input hash
17
+ echo "hash data: ${hash_data}";
18
+ $hash_value = hash_hmac('sha256', $hash_data, $secret_key, $binary_output);
19
+
20
+
21
+ $vtenh_request = $data;
22
+
23
+ // request payload with signed for vtenh callback
24
+ $vtenh_request["SignedHash"] = $hash_value;
25
+
26
+ print_r($vtenh_request);
27
+ // output
28
+ // Array
29
+ // (
30
+ // [TransactionId] => REF0361472663
31
+ // [PaymentTokenId] => 16de81d4-b5ef-ef59-16de-81d4b5efef59
32
+ // [TxnAmount] => 30
33
+ // [SenderName] => Test User
34
+ // [SignedHash] => c5b9be690bde7dc8a0abebb1a45c0850359540a4977aecd4cdf13e15a2edfe79
35
+ // )
@@ -0,0 +1,38 @@
1
+ module Vpago
2
+ module AcledaMobile
3
+ class CallbackValidator
4
+ # {
5
+ # "TransactionId": "REF0361472663",
6
+ # "PaymentTokenId": "16de81d4-b5ef-ef59-16de-81d4b5efef59",
7
+ # "TxnAmount": "30",
8
+ # "SenderName": "Test User",
9
+ # "SignedHash": "c5b9be690bde7dc8a0abebb1a45c0850359540a4977aecd4cdf13e15a2edfe79",
10
+ # }
11
+ def initialize(options)
12
+ @options = options
13
+ end
14
+
15
+ def call
16
+ valid?
17
+ end
18
+
19
+ def secret_key
20
+ ENV.fetch('ACLEDA_MOBILE_SECRET_HASH_KEY', nil)
21
+ end
22
+
23
+ def valid?
24
+ return false if secret_key.blank?
25
+
26
+ hmac_hash == @options[:SignedHash]
27
+ end
28
+
29
+ def hmac_hash
30
+ key = secret_key
31
+
32
+ message = "#{@options[:TransactionId]} #{@options[:PaymentTokenId]} #{@options[:TxnAmount]}"
33
+
34
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), key, message)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,78 @@
1
+ module Vpago
2
+ module AcledaMobile
3
+ class Checkout < Base
4
+ attr_accessor :error_message, :results
5
+
6
+ def call
7
+ @results = {
8
+ play_store: acleda_play_store,
9
+ app_store: acleda_app_store,
10
+ acleda_ios_deeplink: acleda_ios_deeplink,
11
+ acleda_android_deeplink: acleda_android_deeplink
12
+ }
13
+ end
14
+
15
+ def acleda_app_store
16
+ 'https://apps.apple.com/us/app/acleda-unity-toanchet/id1196285236'
17
+ end
18
+
19
+ def acleda_play_store
20
+ 'market://details?id=com.domain.acledabankqr'
21
+ end
22
+
23
+ def acleda_ios_deeplink
24
+ "ACLEDAmobile://?partner_id=#{partner_id}&payment_data=#{aes_encrypted_payment_data}"
25
+ end
26
+
27
+ def acleda_android_deeplink
28
+ "market://com.domain.acledabankqr/app?partner_id=#{partner_id}&payment_data=#{aes_encrypted_payment_data}"
29
+ end
30
+
31
+ def hmac_payment_data
32
+ message = payment_data.to_json
33
+ key = encryption_key
34
+
35
+ hmac_hash(key, message)
36
+ end
37
+
38
+ def hmac_hash(key, message)
39
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), key, message)
40
+ end
41
+
42
+ def aes_encrypted_payment_data
43
+ data = "#{payment_data.to_json}~#{hmac_payment_data}"
44
+ key = encryption_key
45
+ iv = [key].pack('H*') # #hex2bin
46
+ cipher = OpenSSL::Cipher.new('AES-256-CBC')
47
+ cipher.encrypt
48
+
49
+ cipher.key = pbkdf2_key
50
+ cipher.iv = iv
51
+
52
+ crypt = cipher.update(data) + cipher.final
53
+ encrypted_result = Base64.encode64(crypt).delete("\n")
54
+ encrypted_result.gsub('/', 'acledabankSecurityTC') # #follow acleda encrypting guide
55
+ end
56
+
57
+ def payment_data
58
+ {
59
+ app_name: 'VTENH',
60
+ payment_amount: amount_with_fee,
61
+ payment_amount_ccy: 'USD',
62
+ payment_purpose: 'VTENH Transaction',
63
+ txn_ref: payment_number,
64
+ app_url: return_to_app_url
65
+ }
66
+ end
67
+
68
+ def pbkdf2_key
69
+ pass = encryption_key
70
+ salt = pass
71
+ iter = 100
72
+ key_len = 32
73
+
74
+ OpenSSL::KDF.pbkdf2_hmac(pass, salt: salt, iterations: iter, length: key_len, hash: 'sha1')
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,34 @@
1
+ module Vpago
2
+ module AcledaMobile
3
+ class PaymentRequestUpdater < ::Vpago::PaymentRequestUpdater
4
+ def call
5
+ checker = payment_status_checker
6
+
7
+ if checker.success?
8
+ @error_message = nil
9
+ checker_result = {
10
+ status: true,
11
+ description: nil,
12
+ acleda_response: checker.result
13
+ }
14
+ marker_options = @options.merge(checker_result)
15
+
16
+ marker = ::Vpago::PaymentStatusMarker.new(@payment, marker_options)
17
+ marker.call
18
+ elsif !ignore_on_failed?
19
+ @error_message = checker.error_message
20
+ marker_options = @options.merge(status: false, description: @error_message)
21
+
22
+ marker = ::Vpago::PaymentStatusMarker.new(@payment, marker_options)
23
+ marker.call
24
+ end
25
+ end
26
+
27
+ def payment_status_checker
28
+ trans_status = Vpago::AcledaMobile::TransactionStatus.new(@payment)
29
+ trans_status.call(@options[:payment_token_id]) # #TO DO: remove payment_token_id when check transaction status api ready
30
+ trans_status
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,24 @@
1
+ module Vpago
2
+ module AcledaMobile
3
+ class PaymentRetriever
4
+ attr_accessor :payment
5
+
6
+ def initialize(options)
7
+ @options = options
8
+ end
9
+
10
+ def call
11
+ find_payment if data_valid?
12
+ end
13
+
14
+ def data_valid?
15
+ service = Vpago::AcledaMobile::CallbackValidator.new(@options)
16
+ service.valid?
17
+ end
18
+
19
+ def find_payment
20
+ @payment = Spree::Payment.find_by(number: @options[:PaymentTokenId])
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,35 @@
1
+ require 'faraday'
2
+
3
+ module Vpago
4
+ module AcledaMobile
5
+ class TransactionStatus < Base
6
+ attr_accessor :error_message, :result
7
+
8
+ # #TO DO: remove payment_token_id when check transaction status api ready
9
+ def call(payment_token_id = nil)
10
+ prepare
11
+ process(payment_token_id)
12
+ end
13
+
14
+ def prepare
15
+ @error_message = nil
16
+ @result = nil
17
+ end
18
+
19
+ def process(payment_token_id)
20
+ @result = {
21
+ ErrorCode: '200',
22
+ ErrorDescription: 'Success',
23
+ TransactionId: payment_number,
24
+ PaymentTokenId: payment_token_id,
25
+ Amount: '',
26
+ Currency: 'USD'
27
+ }
28
+ end
29
+
30
+ def success?
31
+ @error_message.nil?
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,23 @@
1
+ module Vpago
2
+ module PaymentAmountCalculator
3
+ def amount
4
+ @payment.amount
5
+ end
6
+
7
+ def amount_with_fee
8
+ format('%.2f', (amount + transaction_fee))
9
+ end
10
+
11
+ def transaction_fee_fix
12
+ @payment.payment_method.preferences[:transaction_fee_fix].to_f
13
+ end
14
+
15
+ def transaction_fee_percentage
16
+ @payment.payment_method.preferences[:transaction_fee_percentage].to_f
17
+ end
18
+
19
+ def transaction_fee
20
+ transaction_fee_fix + ((amount * transaction_fee_percentage) / 100)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ module Vpago
2
+ class PaymentRequestUpdater
3
+ attr_accessor :payment, :error_message
4
+
5
+ def initialize(payment, options = {})
6
+ @options = options
7
+ @payment = payment
8
+ @error_message = nil
9
+ end
10
+
11
+ def ignore_on_failed?
12
+ @options[:ignore_on_failed] || false
13
+ end
14
+
15
+ def success?
16
+ @error_message.nil?
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,109 @@
1
+ module Vpago
2
+ class PaymentStatusMarker
3
+ attr_accessor :payment, :error_message
4
+
5
+ # :status, :description, :updated_by_user_id, updated_reason
6
+ def initialize(payment, options = {})
7
+ @payment = payment
8
+ @options = options
9
+ @options[:status] = @options[:status] || false
10
+ end
11
+
12
+ def call
13
+ ActiveRecord::Base.transaction do
14
+ update_payment_source
15
+ update_payment_and_order
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def update_payment_source
22
+ source = @payment.source
23
+
24
+ payment_status = @options[:status] ? 'success' : 'failed'
25
+ source.payment_status = payment_status
26
+ source.payment_description = @options[:description]
27
+ ## for acleda, we already update the transaction_id at when checkout
28
+ source.transaction_id = @options[:transaction_id] if @options[:transaction_id].present?
29
+ source.preferred_wing_response = @options[:wing_response]
30
+ source.preferred_acleda_response = @options[:acleda_response]
31
+ source.preferred_payway_v2_response = @options[:payway_v2_response]
32
+
33
+ if @options[:status]
34
+ source.updated_by_user_id = @options[:updated_by_user_id]
35
+ source.updated_reason = @options[:updated_reason]
36
+ source.updated_by_user_at = Time.zone.now
37
+ end
38
+
39
+ return if source.save
40
+
41
+ @error_message = source.errors.full_messages.join('\n')
42
+ end
43
+
44
+ def update_payment_and_order
45
+ if @options[:status]
46
+ transition_to_paid!
47
+ else
48
+ transition_to_failed!
49
+ end
50
+
51
+ order_updater
52
+ end
53
+
54
+ def transition_to_paid!
55
+ complete_payment!
56
+ complete_order!
57
+ confirm_payouts!
58
+ end
59
+
60
+ def transition_to_failed!
61
+ @payment.failure! unless @payment.failed?
62
+ @payment.order.update(state: 'payment')
63
+
64
+ notify_failed_payment
65
+ end
66
+
67
+ def order_updater
68
+ @payment.order.update_with_updater!
69
+ end
70
+
71
+ def complete_payment!
72
+ return if @payment.completed?
73
+
74
+ # not follow state machine rule when it manual
75
+ if @options[:updated_by_user_id].present?
76
+ ApplicationRecord.transaction do
77
+ @payment.state_changes.create!(previous_state: @payment.state, next_state: 'completed', name: 'payment')
78
+ @payment.update(state: 'completed')
79
+ end
80
+ else
81
+ @payment.complete!
82
+ end
83
+ end
84
+
85
+ def complete_order!
86
+ return if @payment.order.completed?
87
+
88
+ order = @payment.order
89
+ order.finalize!
90
+ order.update(state: 'complete', completed_at: Time.zone.now)
91
+ end
92
+
93
+ def payout_confirmed?
94
+ @options[:payout_total] == @payment.payouts.sum(:amount)
95
+ end
96
+
97
+ def confirm_payouts!
98
+ return unless payout_confirmed?
99
+
100
+ @payment.payouts.find_each do |payout|
101
+ payout.update!(state: :confirmed)
102
+ end
103
+ end
104
+
105
+ def notify_failed_payment
106
+ Rails.logger.info("Gateway error check with: #{@options[:description]} and will be marked as failed")
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,112 @@
1
+ module Vpago
2
+ module Payway
3
+ class Base
4
+ def initialize(payment, options = {})
5
+ @options = options
6
+ @payment = payment
7
+ end
8
+
9
+ def host
10
+ @payment.payment_method.preferences[:host]
11
+ end
12
+
13
+ def amount
14
+ format('%.2f', (@payment.amount + transaction_fee))
15
+ end
16
+
17
+ def transaction_fee_fix
18
+ @payment.payment_method.preferences[:transaction_fee_fix].to_f
19
+ end
20
+
21
+ def transaction_fee_percentage
22
+ @payment.payment_method.preferences[:transaction_fee_percentage].to_f
23
+ end
24
+
25
+ def transaction_fee
26
+ transaction_fee_fix + ((@payment.amount * transaction_fee_percentage) / 100)
27
+ end
28
+
29
+ def merchant_id
30
+ @payment.payment_method.preferences[:merchant_id]
31
+ end
32
+
33
+ def transaction_id
34
+ @payment.number
35
+ end
36
+
37
+ def email
38
+ @payment.order.email.presence || ENV.fetch('DEFAULT_EMAIL_FOR_PAYMENT', nil)
39
+ end
40
+
41
+ def first_name
42
+ @payment.order.billing_address.first_name
43
+ end
44
+
45
+ def last_name
46
+ @payment.order.billing_address.last_name
47
+ end
48
+
49
+ def return_url
50
+ preferred_return_url = @payment.payment_method.preferences[:return_url]
51
+ return nil if preferred_return_url.blank?
52
+
53
+ Base64.encode64(preferred_return_url)
54
+ end
55
+
56
+ def app_checkout
57
+ app_checkout? ? 'yes' : 'no'
58
+ end
59
+
60
+ def app_checkout?
61
+ return false if @options[:app_checkout].blank?
62
+
63
+ @options[:app_checkout]
64
+ end
65
+
66
+ def continue_success_url
67
+ preferred_continue_url = @payment.payment_method.preferences[:continue_success_url]
68
+ return nil if preferred_continue_url.blank?
69
+
70
+ query_string = "tran_id=#{transaction_id}&app_checkout=#{app_checkout}"
71
+ preferred_continue_url.index('?').nil? ? "#{preferred_continue_url}?#{query_string}" : "#{preferred_continue_url}&#{query_string}"
72
+ end
73
+
74
+ def payment_option
75
+ card_option = @payment.payment_method.preferences[:payment_option]
76
+ Vpago::Payway::CARD_TYPES.index(card_option).nil? ? Vpago::Payway::CARD_TYPE_ABAPAY : card_option
77
+ end
78
+
79
+ def phone_country_code
80
+ '+855'
81
+ end
82
+
83
+ def phone
84
+ @payment.order.billing_address.phone
85
+ end
86
+
87
+ def api_key
88
+ @payment.payment_method.preferences[:api_key]
89
+ end
90
+
91
+ def return_params
92
+ { tran_id: transaction_id }.to_json
93
+ end
94
+
95
+ def hash_hmac
96
+ data = "#{merchant_id}#{transaction_id}#{amount}"
97
+ hash = Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha512'), api_key, data))
98
+
99
+ # somehow php counter part are not able to decode if the \n present.
100
+ hash.delete("\n")
101
+ end
102
+
103
+ def endpoint
104
+ @payment.payment_method.preferences[:endpoint]
105
+ end
106
+
107
+ def action_url
108
+ "#{host}#{endpoint}"
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,24 @@
1
+ module Vpago
2
+ module Payway
3
+ class Checkout < Base
4
+ def gateway_params
5
+ result = {
6
+ tran_id: transaction_id,
7
+ amount: amount,
8
+ hash: hash_hmac,
9
+ firstname: first_name,
10
+ lastname: last_name,
11
+ email: email,
12
+ payment_option: payment_option,
13
+ return_url: return_url,
14
+ continue_success_url: continue_success_url,
15
+ return_params: return_params
16
+ }
17
+
18
+ result[:phone_country_code] = phone_country_code
19
+ result[:phone] = phone
20
+ result
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,31 @@
1
+ module Vpago
2
+ module Payway
3
+ class PaymentRequestUpdater < ::Vpago::PaymentRequestUpdater
4
+ def call
5
+ checker = check_payway_status
6
+
7
+ if checker.success?
8
+ @error_message = nil
9
+
10
+ marker_options = @options.merge(status: true, description: nil)
11
+ marker = ::Vpago::Payway::PaymentStatusMarker.new(@payment, marker_options)
12
+ marker.call
13
+ elsif !ignore_on_failed?
14
+ @error_message = checker.error_message[0...255]
15
+ marker_options = @options.merge(status: false, description: @error_message)
16
+
17
+ marker = ::Vpago::Payway::PaymentStatusMarker.new(@payment, marker_options)
18
+ marker.call
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def check_payway_status
25
+ trans_status = Vpago::Payway::TransactionStatus.new(@payment)
26
+ trans_status.call
27
+ trans_status
28
+ end
29
+ end
30
+ end
31
+ end