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.
- checksums.yaml +7 -0
- data/.env.example +3 -0
- data/.github/workflows/test_and_publish_gem.yml +96 -0
- data/.gitignore +24 -0
- data/.rspec +3 -0
- data/.rubocop.yml +56 -0
- data/.ruby-version +1 -0
- data/.tool-versions +1 -0
- data/.travis.yml +45 -0
- data/Appraisals +20 -0
- data/Gemfile +27 -0
- data/Gemfile.lock +656 -0
- data/LICENSE +26 -0
- data/README.md +151 -0
- data/Rakefile +21 -0
- data/app/.gitkeep +0 -0
- data/app/assets/config/spree_vpago_manifest.js +3 -0
- data/app/assets/images/backend-process.svg +3 -0
- data/app/assets/images/vpago/payway/abapay.png +0 -0
- data/app/assets/images/vpago/payway/cards.png +0 -0
- data/app/assets/javascripts/vpago/vpago_payments/request_process_payment.js +44 -0
- data/app/assets/javascripts/vpago/vpago_payments/user_informers/firebase.js +15802 -0
- data/app/controllers/.gitkeep +0 -0
- data/app/controllers/spree/acleda_redirects_controller.rb +22 -0
- data/app/controllers/spree/admin/payment_methods_controller_decorator.rb +65 -0
- data/app/controllers/spree/admin/payment_payway_base_controller.rb +25 -0
- data/app/controllers/spree/admin/payment_payway_checkers_controller.rb +34 -0
- data/app/controllers/spree/admin/payment_payway_markers_controller.rb +44 -0
- data/app/controllers/spree/admin/payment_payway_queriers_controller.rb +39 -0
- data/app/controllers/spree/admin/payment_wing_sdk_base_controller.rb +21 -0
- data/app/controllers/spree/admin/payment_wing_sdk_checkers_controller.rb +26 -0
- data/app/controllers/spree/admin/payment_wing_sdk_markers_controller.rb +36 -0
- data/app/controllers/spree/admin/payment_wing_sdk_queriers_controller.rb +20 -0
- data/app/controllers/spree/admin/payments_controller_decorator.rb +19 -0
- data/app/controllers/spree/admin/payout_profile_products_controller.rb +21 -0
- data/app/controllers/spree/admin/payout_profile_shipping_methods_controller.rb +21 -0
- data/app/controllers/spree/admin/payout_profiles_controller.rb +91 -0
- data/app/controllers/spree/admin/payouts_controller.rb +16 -0
- data/app/controllers/spree/api/v2/storefront/checkout_controller_decorator.rb +84 -0
- data/app/controllers/spree/payway_card_popups_controller.rb +20 -0
- data/app/controllers/spree/payway_results_controller.rb +11 -0
- data/app/controllers/spree/payway_v2_card_popups_controller.rb +20 -0
- data/app/controllers/spree/vpago_payments_controller.rb +71 -0
- data/app/controllers/spree/webhook/acleda_mobiles_controller.rb +88 -0
- data/app/controllers/spree/webhook/acledas_controller.rb +80 -0
- data/app/controllers/spree/webhook/base_controller.rb +6 -0
- data/app/controllers/spree/webhook/payways_controller.rb +77 -0
- data/app/controllers/spree/webhook/wings_controller.rb +63 -0
- data/app/controllers/spree/wing/base_controller.rb +29 -0
- data/app/controllers/spree/wing/transactions_controller.rb +27 -0
- data/app/controllers/spree/wing_redirects_controller.rb +20 -0
- data/app/helpers/vpago/admin/base_helper_decorator.rb +40 -0
- data/app/helpers/vpago/vpago_payments_helper.rb +12 -0
- data/app/javascripts/vpago/vpago_payments/user_informers/firebase.js +62 -0
- data/app/jobs/application_unique_job.rb +1 -0
- data/app/jobs/vpago/payment_processor_job.rb +8 -0
- data/app/models/.gitkeep +0 -0
- data/app/models/concerns/vpago/payoutable.rb +11 -0
- data/app/models/spree/gateway/acleda.rb +63 -0
- data/app/models/spree/gateway/acleda_mobile.rb +46 -0
- data/app/models/spree/gateway/payway.rb +66 -0
- data/app/models/spree/gateway/payway_v2.rb +174 -0
- data/app/models/spree/gateway/wing_sdk.rb +51 -0
- data/app/models/spree/payout.rb +23 -0
- data/app/models/spree/payout_profile.rb +107 -0
- data/app/models/spree/payout_profile_product.rb +14 -0
- data/app/models/spree/payout_profile_shipping_method.rb +14 -0
- data/app/models/spree/payout_profiles/payway_v2.rb +40 -0
- data/app/models/spree/vpago_payment_source.rb +21 -0
- data/app/models/vpago/adjustment_decorator.rb +28 -0
- data/app/models/vpago/line_item_decorator.rb +75 -0
- data/app/models/vpago/order_decorator.rb +78 -0
- data/app/models/vpago/payment_decorator.rb +44 -0
- data/app/models/vpago/payment_method_decorator.rb +91 -0
- data/app/models/vpago/payouts_generator.rb +125 -0
- data/app/models/vpago/product_decorator.rb +30 -0
- data/app/models/vpago/promotion_action_decorator.rb +9 -0
- data/app/models/vpago/shipment_decorator.rb +23 -0
- data/app/models/vpago/shipping_method_decorator.rb +33 -0
- data/app/models/vpago/shipping_rate_decorator.rb +25 -0
- data/app/models/vpago/store_decorator.rb +17 -0
- data/app/models/vpago/tax_category_decorator.rb +9 -0
- data/app/models/vpago/variant_decorator.rb +22 -0
- data/app/models/vpago/vendor_decorator.rb +10 -0
- data/app/overrides/spree/admin/adjustments/_adjustment/handle_by_table_body.html.erb.deface +11 -0
- data/app/overrides/spree/admin/adjustments/_adjustments_table/handle_by_table_header.html.erb.deface +3 -0
- data/app/overrides/spree/admin/adjustments/_form/handle_by_field.html.erb.deface +10 -0
- data/app/overrides/spree/admin/orders/_shipment/edit_method.html.erb.deface +26 -0
- data/app/overrides/spree/admin/orders/_shipment/show_method.html.erb.deface +27 -0
- data/app/overrides/spree/admin/payment_methods/_form/enable_pre_auth_field.html.erb.deface +17 -0
- data/app/overrides/spree/admin/payment_methods/_form/vendor_field.html.erb.deface +6 -0
- data/app/overrides/spree/admin/payment_methods/index/list.html.erb.deface +45 -0
- data/app/overrides/spree/admin/payment_methods/index/payment_methods_tabs.html.erb.deface +9 -0
- data/app/overrides/spree/admin/payment_methods/index/vendor_body.html.erb.deface +5 -0
- data/app/overrides/spree/admin/payment_methods/index/vendor_header.html.erb.deface +5 -0
- data/app/overrides/spree/admin/payments/_list/actions.html.erb.deface +13 -0
- data/app/overrides/spree/admin/promotions/_promotion_action/run_by_field.html.erb.deface +13 -0
- data/app/overrides/spree/admin/shared/_order_tabs/payouts.html.erb.deface +8 -0
- data/app/overrides/spree/admin/shared/_product_tabs/payout_profile_products.html.erb.deface +8 -0
- data/app/overrides/spree/admin/shared/sub_menu/_integrations/payout_profiles.html.erb.deface +3 -0
- data/app/overrides/spree/admin/shipping_methods/_form/handle_by.html.erb.deface +12 -0
- data/app/overrides/spree/admin/shipping_methods/edit/shipping_method_tabs.html.erb.deface +3 -0
- data/app/overrides/spree/admin/tax_categories/_form/collect_by_field.html.erb.deface +10 -0
- data/app/overrides/spree/admin/tax_categories/index/collect_by_table_body.html.erb.deface +4 -0
- data/app/overrides/spree/admin/tax_categories/index/collect_by_table_header.html.erb.deface +4 -0
- data/app/serializers/spree/api/v2/platform/vpago_payment_source_serializer.rb +11 -0
- data/app/serializers/spree/v2/storefront/payment_method_serializer_decorator.rb +23 -0
- data/app/serializers/spree/v2/storefront/payment_redirect_serializer.rb +13 -0
- data/app/serializers/spree/v2/storefront/payment_serializer_decorator.rb +13 -0
- data/app/serializers/spree/v2/storefront/vpago_payment_source_serializer.rb +9 -0
- data/app/services/.gitkeep +0 -0
- data/app/services/vpago/payment_finder.rb +27 -0
- data/app/services/vpago/payment_processor.rb +72 -0
- data/app/services/vpago/payment_redirect_handler.rb +194 -0
- data/app/services/vpago/payment_url_constructor.rb +32 -0
- data/app/services/vpago/payments/find_or_create.rb +51 -0
- data/app/services/vpago/payout_profiles/payway/base_payout_profile_request.rb +38 -0
- data/app/services/vpago/payout_profiles/payway/open_ssl_encrypter.rb +31 -0
- data/app/services/vpago/payout_profiles/payway/payout_profile_request_creator.rb +50 -0
- data/app/services/vpago/payout_profiles/payway/payout_profile_request_params_builder.rb +58 -0
- data/app/services/vpago/payout_profiles/payway/payout_profile_request_updater.rb +28 -0
- data/app/services/vpago/payway_return_options_builder.rb +39 -0
- data/app/services/vpago/user_informers/firebase.rb +52 -0
- data/app/views/.gitkeep +0 -0
- data/app/views/layouts/acleda.html.erb +18 -0
- data/app/views/layouts/payway.html.erb +24 -0
- data/app/views/layouts/payway_v2.html.erb +18 -0
- data/app/views/layouts/vpago_payments.html.erb +18 -0
- data/app/views/layouts/wing.html.erb +18 -0
- data/app/views/spree/_payment_icon.html.erb +25 -0
- data/app/views/spree/acleda_redirects/show.html.erb +3 -0
- data/app/views/spree/admin/payments/source_forms/_payment_payway.html.erb +4 -0
- data/app/views/spree/admin/payments/source_forms/_payway_v2.html.erb +7 -0
- data/app/views/spree/admin/payments/source_views/_acleda.html.erb +1 -0
- data/app/views/spree/admin/payments/source_views/_acleda_mobile.html.erb +1 -0
- data/app/views/spree/admin/payments/source_views/_payment_payway.html.erb +98 -0
- data/app/views/spree/admin/payments/source_views/_payway_v2.html.erb +5 -0
- data/app/views/spree/admin/payments/source_views/_vpago_payment_tmpl.html.erb +113 -0
- data/app/views/spree/admin/payments/source_views/_wingsdk.html.erb +5 -0
- data/app/views/spree/admin/payout_profile_products/_form.html.erb +28 -0
- data/app/views/spree/admin/payout_profile_products/edit.html.erb +18 -0
- data/app/views/spree/admin/payout_profile_products/index.html.erb +58 -0
- data/app/views/spree/admin/payout_profile_products/new.html.erb +22 -0
- data/app/views/spree/admin/payout_profile_shipping_methods/_form.html.erb +28 -0
- data/app/views/spree/admin/payout_profile_shipping_methods/edit.html.erb +22 -0
- data/app/views/spree/admin/payout_profile_shipping_methods/index.html.erb +6 -0
- data/app/views/spree/admin/payout_profile_shipping_methods/new.html.erb +27 -0
- data/app/views/spree/admin/payout_profiles/_filter.html.erb +19 -0
- data/app/views/spree/admin/payout_profiles/_form.html.erb +72 -0
- data/app/views/spree/admin/payout_profiles/edit.html.erb +33 -0
- data/app/views/spree/admin/payout_profiles/index.html.erb +63 -0
- data/app/views/spree/admin/payout_profiles/new.html.erb +13 -0
- data/app/views/spree/admin/payouts/_line_item_info_with_popover.html.erb +43 -0
- data/app/views/spree/admin/payouts/index.html.erb +46 -0
- data/app/views/spree/admin/shared/_payment_methods_tabs.html.erb +15 -0
- data/app/views/spree/admin/shared/_shipping_method_tabs.html.erb +19 -0
- data/app/views/spree/admin/shared/payout_profile/_info_card.html.erb +24 -0
- data/app/views/spree/admin/shared/payout_profile/_status.html.erb +11 -0
- data/app/views/spree/checkout/payment/_acleda.html.erb +1 -0
- data/app/views/spree/checkout/payment/_acleda_checkout_form.html.erb +14 -0
- data/app/views/spree/checkout/payment/_acleda_mobile.html.erb +0 -0
- data/app/views/spree/checkout/payment/_payment_payway.html.erb +21 -0
- data/app/views/spree/checkout/payment/_payway_loader.html.erb +2 -0
- data/app/views/spree/checkout/payment/_payway_root.html.erb +9 -0
- data/app/views/spree/checkout/payment/_payway_script.html.erb +77 -0
- data/app/views/spree/checkout/payment/_payway_v2.html.erb +1 -0
- data/app/views/spree/checkout/payment/_payway_v2_loader.html.erb +2 -0
- data/app/views/spree/checkout/payment/_payway_v2_root.html.erb +9 -0
- data/app/views/spree/checkout/payment/_payway_v2_script.html.erb +79 -0
- data/app/views/spree/checkout/payment/_wing_checkout_form.html.erb +18 -0
- data/app/views/spree/checkout/payment/_wingsdk.html.erb +1 -0
- data/app/views/spree/checkout/payment/acleda_form.html.erb +3 -0
- data/app/views/spree/checkout/payment/payway_form.html.erb +10 -0
- data/app/views/spree/checkout/payment/payway_v2_form.html.erb +10 -0
- data/app/views/spree/checkout/payment/wingsdk_form.html.erb +3 -0
- data/app/views/spree/payway_card_popups/_form.html.erb +10 -0
- data/app/views/spree/payway_card_popups/show.html.erb +5 -0
- data/app/views/spree/payway_results/failed.html.erb +1 -0
- data/app/views/spree/payway_results/success.html.erb +1 -0
- data/app/views/spree/payway_v2_card_popups/_form.html.erb +15 -0
- data/app/views/spree/payway_v2_card_popups/show.html.erb +3 -0
- data/app/views/spree/vpago_payments/checkout.html.erb +3 -0
- data/app/views/spree/vpago_payments/forms/spree/gateway/_payway_v2.html.erb +13 -0
- data/app/views/spree/vpago_payments/processing.html.erb +49 -0
- data/app/views/spree/vpago_payments/success.html.erb +3 -0
- data/app/views/spree/wing_redirects/show.html.erb +3 -0
- data/bin/rails +8 -0
- data/build.js +9 -0
- data/config/initializers/assets.rb +1 -0
- data/config/initializers/spree_permitted_attributes.rb +5 -0
- data/config/locales/en.yml +28 -0
- data/config/locales/km.yml +24 -0
- data/config/routes.rb +92 -0
- data/db/migrate/20210128040625_create_spree_vpago_payment_sources.rb +14 -0
- data/db/migrate/20210430052432_add_fields_to_payment_sources.rb +7 -0
- data/db/migrate/20210824044737_add_preference_to_spree_vpago_payment_source.rb +5 -0
- data/db/migrate/20240506095140_create_spree_payout_profiles.rb +22 -0
- data/db/migrate/20240506095148_create_spree_payout_profile_products.rb +10 -0
- data/db/migrate/20240523070757_add_optional_spere_payout_profile_products.rb +5 -0
- data/db/migrate/20240715091228_create_spree_payouts.rb +25 -0
- data/db/migrate/20240718195510_create_spree_payout_profile_shipping_methods.rb +15 -0
- data/db/migrate/20240718201453_add_handle_by_to_spree_adjustments.rb +5 -0
- data/db/migrate/20240718201509_add_run_by_to_spree_promotion_actions.rb +5 -0
- data/db/migrate/20240718201523_add_collect_by_to_spree_tax_categories.rb +5 -0
- data/db/migrate/20240718201538_add_handle_by_to_spree_shipping_method.rb +5 -0
- data/db/migrate/20240718201554_add_handle_by_to_spree_shipping_rates.rb +5 -0
- data/db/migrate/20240808102853_add_vendor_reference_to_spree_payment_methods.rb +7 -0
- data/db/migrate/20240904030132_add_gateway_status_to_spree_payments.rb +5 -0
- data/db/migrate/20241029071959_add_pre_auth_response_to_spree_payment.rb +5 -0
- data/db/migrate/20241202104014_add_enable_pre_auth_to_spree_payment_method.rb +5 -0
- data/db/migrate/20250121044614_add_transaction_response_to_spree_payments.rb +5 -0
- data/docs/acleda.md +65 -0
- data/gemfiles/spree_3_7.gemfile +9 -0
- data/gemfiles/spree_4_0.gemfile +8 -0
- data/gemfiles/spree_4_1.gemfile +9 -0
- data/gemfiles/spree_master.gemfile +8 -0
- data/lib/generators/spree_vpago/install/install_generator.rb +26 -0
- data/lib/generators/spree_vpago/install/templates/app/assets/images/vpago/payway/acleda_merchant_logo_300x300.png +0 -0
- data/lib/spree_vpago/engine.rb +36 -0
- data/lib/spree_vpago/factories.rb +6 -0
- data/lib/spree_vpago/version.rb +9 -0
- data/lib/spree_vpago.rb +5 -0
- data/lib/vpago/acleda/base.rb +111 -0
- data/lib/vpago/acleda/checkout.rb +105 -0
- data/lib/vpago/acleda/deeplink_checkout.rb +74 -0
- data/lib/vpago/acleda/payment_request_updater.rb +38 -0
- data/lib/vpago/acleda/transaction_status.rb +71 -0
- data/lib/vpago/acleda_mobile/base.rb +28 -0
- data/lib/vpago/acleda_mobile/callback_validator.php +35 -0
- data/lib/vpago/acleda_mobile/callback_validator.rb +38 -0
- data/lib/vpago/acleda_mobile/checkout.rb +78 -0
- data/lib/vpago/acleda_mobile/payment_request_updater.rb +34 -0
- data/lib/vpago/acleda_mobile/payment_retriever.rb +24 -0
- data/lib/vpago/acleda_mobile/transaction_status.rb +35 -0
- data/lib/vpago/payment_amount_calculator.rb +23 -0
- data/lib/vpago/payment_request_updater.rb +19 -0
- data/lib/vpago/payment_status_marker.rb +109 -0
- data/lib/vpago/payway/base.rb +112 -0
- data/lib/vpago/payway/checkout.rb +24 -0
- data/lib/vpago/payway/payment_request_updater.rb +31 -0
- data/lib/vpago/payway/payment_status_marker.rb +84 -0
- data/lib/vpago/payway/transaction_status.rb +74 -0
- data/lib/vpago/payway.rb +13 -0
- data/lib/vpago/payway_v2/base.rb +153 -0
- data/lib/vpago/payway_v2/checkout.rb +35 -0
- data/lib/vpago/payway_v2/payment_request_updater.rb +65 -0
- data/lib/vpago/payway_v2/payouts_params_constructor.rb +47 -0
- data/lib/vpago/payway_v2/pre_auth_canceler.rb +43 -0
- data/lib/vpago/payway_v2/pre_auth_completer.rb +76 -0
- data/lib/vpago/payway_v2/transaction_status.rb +85 -0
- data/lib/vpago/wing_sdk/base.rb +58 -0
- data/lib/vpago/wing_sdk/checkout.rb +20 -0
- data/lib/vpago/wing_sdk/payment_request_updater.rb +46 -0
- data/lib/vpago/wing_sdk/payment_retriever.rb +34 -0
- data/lib/vpago/wing_sdk/transaction_status_checker.rb +64 -0
- data/lib/vpago/wing_sdk/transaction_status_response.rb +33 -0
- data/node_modules/.yarn-integrity +147 -0
- data/package-lock.json +1491 -0
- data/package.json +10 -0
- data/spree_vpago.gemspec +33 -0
- data/yarn.lock +921 -0
- metadata +403 -0
@@ -0,0 +1,84 @@
|
|
1
|
+
module Vpago
|
2
|
+
module Payway
|
3
|
+
class PaymentStatusMarker
|
4
|
+
attr_accessor :payment, :error_message
|
5
|
+
|
6
|
+
# :status, :description, :updated_by_user_id, updated_reason
|
7
|
+
def initialize(payment, options = {})
|
8
|
+
@payment = payment
|
9
|
+
@options = options
|
10
|
+
|
11
|
+
@options[:status] = @options[:status] || false
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
ActiveRecord::Base.transaction do
|
16
|
+
update_payment_source
|
17
|
+
update_payment_and_order
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def update_payment_source
|
24
|
+
source = @payment.source
|
25
|
+
|
26
|
+
payment_status = @options[:status] ? 'success' : 'failed'
|
27
|
+
source.payment_status = payment_status
|
28
|
+
source.payment_description = @options[:description]
|
29
|
+
|
30
|
+
if @options[:status]
|
31
|
+
source.updated_by_user_id = @options[:updated_by_user_id]
|
32
|
+
source.updated_reason = @options[:updated_reason]
|
33
|
+
source.updated_by_user_at = Time.zone.now
|
34
|
+
end
|
35
|
+
|
36
|
+
return if source.save
|
37
|
+
|
38
|
+
@error_message = source.errors.full_messages.join('\n')
|
39
|
+
end
|
40
|
+
|
41
|
+
def update_payment_and_order
|
42
|
+
if @options[:status]
|
43
|
+
transition_to_paid!
|
44
|
+
else
|
45
|
+
transition_to_failed!
|
46
|
+
end
|
47
|
+
|
48
|
+
order_updater
|
49
|
+
end
|
50
|
+
|
51
|
+
def transition_to_paid!
|
52
|
+
complete_payment!
|
53
|
+
complete_order!
|
54
|
+
end
|
55
|
+
|
56
|
+
def transition_to_failed!
|
57
|
+
@payment.failure! unless @payment.failed?
|
58
|
+
@payment.order.update(state: 'payment')
|
59
|
+
|
60
|
+
notify_failed_payment
|
61
|
+
end
|
62
|
+
|
63
|
+
def order_updater
|
64
|
+
@payment.order.update_with_updater!
|
65
|
+
end
|
66
|
+
|
67
|
+
def complete_payment!
|
68
|
+
@payment.complete! unless @payment.completed?
|
69
|
+
end
|
70
|
+
|
71
|
+
def complete_order!
|
72
|
+
return if @payment.order.completed?
|
73
|
+
|
74
|
+
order = @payment.order
|
75
|
+
order.finalize!
|
76
|
+
order.update(state: 'complete', completed_at: Time.zone.now)
|
77
|
+
end
|
78
|
+
|
79
|
+
def notify_failed_payment
|
80
|
+
Rails.logger.info("Gateway error check with: #{@options[:description]} and will be marked as failed")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
module Vpago
|
4
|
+
module Payway
|
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 checker_hmac
|
19
|
+
data = "#{merchant_id}#{transaction_id}"
|
20
|
+
hash = Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha512'), api_key, data))
|
21
|
+
|
22
|
+
# somehow php counter part are not able to decode if the \n present.
|
23
|
+
hash.delete("\n")
|
24
|
+
end
|
25
|
+
|
26
|
+
def check_remote_status
|
27
|
+
conn = Faraday::Connection.new do |faraday|
|
28
|
+
faraday.request :url_encoded
|
29
|
+
end
|
30
|
+
|
31
|
+
data = {
|
32
|
+
tran_id: transaction_id,
|
33
|
+
hash: checker_hmac
|
34
|
+
}
|
35
|
+
|
36
|
+
conn.post(check_transaction_url, data)
|
37
|
+
end
|
38
|
+
|
39
|
+
def process
|
40
|
+
@response = check_remote_status
|
41
|
+
|
42
|
+
if @response.status == 200
|
43
|
+
if json_response['status'].zero?
|
44
|
+
@result = json_response
|
45
|
+
else
|
46
|
+
fail!(json_response['description'])
|
47
|
+
end
|
48
|
+
else
|
49
|
+
fail!(@response.body)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def json_response
|
54
|
+
@json_response ||= JSON.parse(@response.body)
|
55
|
+
end
|
56
|
+
|
57
|
+
def fail!(message)
|
58
|
+
@error_message = message
|
59
|
+
end
|
60
|
+
|
61
|
+
def success?
|
62
|
+
@error_message.nil?
|
63
|
+
end
|
64
|
+
|
65
|
+
def check_transaction_url
|
66
|
+
if endpoint[-1] == '/'
|
67
|
+
"#{host}#{endpoint}check/transaction/"
|
68
|
+
else
|
69
|
+
"#{host}#{endpoint}/check/transaction/"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/vpago/payway.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module Vpago
|
2
|
+
module Payway
|
3
|
+
CARD_TYPE_ABAPAY = 'abapay'.freeze
|
4
|
+
CARD_TYPE_ABAPAY_KHQR = 'abapay_khqr'.freeze
|
5
|
+
CARD_TYPE_ABAPAY_KHQR_DEEPLINK = 'abapay_khqr_deeplink'.freeze
|
6
|
+
CARD_TYPE_CARDS = 'cards'.freeze
|
7
|
+
CARD_TYPE_WECHAT = 'wechat'.freeze
|
8
|
+
CARD_TYPE_ALIPAY = 'alipay'.freeze
|
9
|
+
|
10
|
+
CARD_TYPES = [CARD_TYPE_ABAPAY, CARD_TYPE_ABAPAY_KHQR, CARD_TYPE_ABAPAY_KHQR_DEEPLINK, CARD_TYPE_CARDS,
|
11
|
+
CARD_TYPE_WECHAT, CARD_TYPE_ALIPAY].freeze
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
module Vpago
|
2
|
+
module PaywayV2
|
3
|
+
class Base
|
4
|
+
def initialize(payment, options = {})
|
5
|
+
@options = options
|
6
|
+
@payment = payment
|
7
|
+
end
|
8
|
+
|
9
|
+
def req_time
|
10
|
+
@payment.created_at.strftime('%Y%m%d%H%M%S')
|
11
|
+
end
|
12
|
+
|
13
|
+
def type
|
14
|
+
@payment.payment_method.enable_pre_auth ? 'pre-auth' : 'purchase'
|
15
|
+
end
|
16
|
+
|
17
|
+
def host
|
18
|
+
@payment.payment_method.preferences[:host]
|
19
|
+
end
|
20
|
+
|
21
|
+
def public_key
|
22
|
+
@payment.payment_method.preferences[:public_key]
|
23
|
+
end
|
24
|
+
|
25
|
+
def amount
|
26
|
+
format('%.2f', (@payment.amount + transaction_fee))
|
27
|
+
end
|
28
|
+
|
29
|
+
def transaction_fee_fix
|
30
|
+
@payment.payment_method.preferences[:transaction_fee_fix].to_f
|
31
|
+
end
|
32
|
+
|
33
|
+
def transaction_fee_percentage
|
34
|
+
@payment.payment_method.preferences[:transaction_fee_percentage].to_f
|
35
|
+
end
|
36
|
+
|
37
|
+
def transaction_fee
|
38
|
+
transaction_fee_fix + ((@payment.amount * transaction_fee_percentage) / 100)
|
39
|
+
end
|
40
|
+
|
41
|
+
def merchant_id
|
42
|
+
@payment.payment_method.preferences[:merchant_id]
|
43
|
+
end
|
44
|
+
|
45
|
+
def transaction_id
|
46
|
+
@payment.number
|
47
|
+
end
|
48
|
+
|
49
|
+
def email
|
50
|
+
@payment.order.email.presence || ENV.fetch('DEFAULT_EMAIL_FOR_PAYMENT', nil)
|
51
|
+
end
|
52
|
+
|
53
|
+
def first_name
|
54
|
+
@payment.order.billing_address.first_name.strip
|
55
|
+
end
|
56
|
+
|
57
|
+
def last_name
|
58
|
+
@payment.order.billing_address.last_name.strip
|
59
|
+
end
|
60
|
+
|
61
|
+
def return_url
|
62
|
+
uri = URI.parse(@payment.process_payment_url)
|
63
|
+
uri.query = nil
|
64
|
+
|
65
|
+
Base64.encode64(uri.to_s).delete("\n")
|
66
|
+
end
|
67
|
+
|
68
|
+
def continue_success_url
|
69
|
+
@payment.processing_url
|
70
|
+
end
|
71
|
+
|
72
|
+
# null, hosted_view, checkout, qr
|
73
|
+
def view_type
|
74
|
+
'hosted_view'
|
75
|
+
end
|
76
|
+
|
77
|
+
def payment_option
|
78
|
+
card_option = @payment.payment_method.preferences[:payment_option]
|
79
|
+
Vpago::Payway::CARD_TYPES.index(card_option).nil? ? Vpago::Payway::CARD_TYPE_ABAPAY : card_option
|
80
|
+
end
|
81
|
+
|
82
|
+
def phone_country_code
|
83
|
+
'+855'
|
84
|
+
end
|
85
|
+
|
86
|
+
def phone
|
87
|
+
@payment.order.billing_address.phone
|
88
|
+
end
|
89
|
+
|
90
|
+
def api_key
|
91
|
+
@payment.payment_method.preferences[:api_key]
|
92
|
+
end
|
93
|
+
|
94
|
+
def return_params
|
95
|
+
uri = URI.parse(@payment.process_payment_url)
|
96
|
+
query_params = Rack::Utils.parse_nested_query(uri.query)
|
97
|
+
query_params.to_json
|
98
|
+
end
|
99
|
+
|
100
|
+
def payout
|
101
|
+
@payout ||= begin
|
102
|
+
payouts = Vpago::PaywayV2::PayoutsParamsConstructor.new(@payment).call
|
103
|
+
payouts.empty? ? nil : Base64.strict_encode64(payouts.to_json)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# redirect to continue URL, let it handle redirecting to app.
|
108
|
+
# allowed override to specific app eg. from tg://t.me
|
109
|
+
def return_deeplink_url
|
110
|
+
return @options[:override_return_deeplink_url] if @options[:override_return_deeplink_url].present?
|
111
|
+
|
112
|
+
continue_success_url
|
113
|
+
end
|
114
|
+
|
115
|
+
def return_deeplink
|
116
|
+
return nil unless return_deeplink_url.present?
|
117
|
+
|
118
|
+
Base64.strict_encode64({ android_scheme: return_deeplink_url, ios_scheme: return_deeplink_url }.to_json)
|
119
|
+
end
|
120
|
+
|
121
|
+
def hash_hmac
|
122
|
+
hash = Base64.strict_encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha512'), api_key, hash_data))
|
123
|
+
|
124
|
+
log_hash_data = "Hash hmac: #{hash}"
|
125
|
+
Rails.logger.info(log_hash_data)
|
126
|
+
|
127
|
+
hash
|
128
|
+
end
|
129
|
+
|
130
|
+
def hash_data
|
131
|
+
result = "#{req_time}#{merchant_id}#{transaction_id}#{amount}#{first_name}#{last_name}#{email}#{phone}"
|
132
|
+
|
133
|
+
result += type if type.present?
|
134
|
+
result += payment_option if payment_option.present?
|
135
|
+
result += return_url if return_url.present?
|
136
|
+
result += continue_success_url if continue_success_url.present?
|
137
|
+
result += return_deeplink if return_deeplink.present?
|
138
|
+
result += return_params if return_params.present?
|
139
|
+
result += payout if payout.present?
|
140
|
+
|
141
|
+
log_hash_data = "Hash data: #{result}"
|
142
|
+
Rails.logger.info(log_hash_data)
|
143
|
+
|
144
|
+
result
|
145
|
+
end
|
146
|
+
|
147
|
+
def order_jwt_token
|
148
|
+
payload = { order_number: @payment.order.number, order_id: @payment.order.id }
|
149
|
+
JWT.encode(payload, @payment.order.token, 'HS256')
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Vpago
|
2
|
+
module PaywayV2
|
3
|
+
class Checkout < Base
|
4
|
+
def gateway_params
|
5
|
+
result = {
|
6
|
+
req_time: req_time,
|
7
|
+
merchant_id: merchant_id,
|
8
|
+
tran_id: transaction_id,
|
9
|
+
amount: amount,
|
10
|
+
type: type,
|
11
|
+
firstname: first_name,
|
12
|
+
lastname: last_name,
|
13
|
+
email: email,
|
14
|
+
phone: phone,
|
15
|
+
payment_option: payment_option,
|
16
|
+
return_url: return_url,
|
17
|
+
continue_success_url: continue_success_url,
|
18
|
+
return_params: return_params,
|
19
|
+
hash: hash_hmac
|
20
|
+
}
|
21
|
+
|
22
|
+
result[:return_deeplink] = return_deeplink unless return_deeplink.nil?
|
23
|
+
result[:view_type] = view_type unless view_type.nil?
|
24
|
+
result[:payout] = payout unless payout.nil?
|
25
|
+
result
|
26
|
+
end
|
27
|
+
|
28
|
+
def checkout_url
|
29
|
+
"#{host}#{ENV.fetch('PAYWAY_CHECKOUT_PATH', nil)}"
|
30
|
+
end
|
31
|
+
|
32
|
+
alias action_url checkout_url
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Vpago
|
2
|
+
module PaywayV2
|
3
|
+
class PaymentRequestUpdater < ::Vpago::PaymentRequestUpdater
|
4
|
+
def call
|
5
|
+
return if @payment.order.paid?
|
6
|
+
|
7
|
+
if items_eligible?
|
8
|
+
process_payment_status
|
9
|
+
else
|
10
|
+
mark_items_as_ineligible
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def mark_items_as_ineligible
|
17
|
+
@error_message = 'Items are not eligible due to insufficient stock'
|
18
|
+
marker_options = @options.merge(status: false, description: @error_message)
|
19
|
+
marker = ::Vpago::PaymentStatusMarker.new(@payment, marker_options)
|
20
|
+
marker.call
|
21
|
+
end
|
22
|
+
|
23
|
+
def process_payment_status
|
24
|
+
checker = check_payway_status
|
25
|
+
|
26
|
+
if checker.success?
|
27
|
+
mark_payment_as_success(checker)
|
28
|
+
elsif checker.failed?
|
29
|
+
mark_payment_as_failed(checker.error_message)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def mark_payment_as_success(checker)
|
34
|
+
@error_message = nil
|
35
|
+
checker_result = {
|
36
|
+
status: true,
|
37
|
+
description: nil,
|
38
|
+
payway_v2_response: checker.json_response,
|
39
|
+
payout_total: checker.payout_total
|
40
|
+
}
|
41
|
+
marker_options = @options.merge(checker_result)
|
42
|
+
marker = ::Vpago::PaymentStatusMarker.new(@payment, marker_options)
|
43
|
+
marker.call
|
44
|
+
end
|
45
|
+
|
46
|
+
def mark_payment_as_failed(error_message)
|
47
|
+
@error_message = error_message
|
48
|
+
marker_options = @options.merge(status: false, description: @error_message)
|
49
|
+
|
50
|
+
marker = ::Vpago::PaymentStatusMarker.new(@payment, marker_options)
|
51
|
+
marker.call
|
52
|
+
end
|
53
|
+
|
54
|
+
def check_payway_status
|
55
|
+
trans_status = Vpago::PaywayV2::TransactionStatus.new(@payment)
|
56
|
+
trans_status.call
|
57
|
+
trans_status
|
58
|
+
end
|
59
|
+
|
60
|
+
def items_eligible?
|
61
|
+
@payment&.order&.line_items&.all?(&:sufficient_stock?) == true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Vpago
|
2
|
+
module PaywayV2
|
3
|
+
class PayoutsParamsConstructor
|
4
|
+
attr_reader :payment, :payouts
|
5
|
+
|
6
|
+
def initialize(payment)
|
7
|
+
@payment = payment
|
8
|
+
@payouts = payment.payouts.includes(:payout_profile)
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
payouts = build_payouts_from_payment
|
13
|
+
payouts = group_payouts(payouts)
|
14
|
+
|
15
|
+
format_payouts(payouts)
|
16
|
+
end
|
17
|
+
|
18
|
+
def build_payouts_from_payment
|
19
|
+
payouts.each_with_object([]) do |payout, payouts_hash|
|
20
|
+
payouts_hash << {
|
21
|
+
acc: payout.payout_profile.bank_account_number,
|
22
|
+
amt: payout.amount
|
23
|
+
}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# group & sum amount by acc number.
|
28
|
+
def group_payouts(payouts)
|
29
|
+
payouts.group_by { |item| item[:acc] }.map do |acc, items|
|
30
|
+
{
|
31
|
+
acc: acc,
|
32
|
+
amt: items.sum { |item| item[:amt] }
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def format_payouts(payouts)
|
38
|
+
payouts.map do |payout|
|
39
|
+
{
|
40
|
+
acc: payout[:acc],
|
41
|
+
amt: format('%.2f', payout[:amt])
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
module Vpago
|
4
|
+
module PaywayV2
|
5
|
+
class PreAuthCanceler < PreAuthCompleter
|
6
|
+
# override
|
7
|
+
def pre_auth_response
|
8
|
+
conn = Faraday::Connection.new do |faraday|
|
9
|
+
faraday.request :url_encoded
|
10
|
+
end
|
11
|
+
|
12
|
+
conn.post(cancel_url, request_data)
|
13
|
+
end
|
14
|
+
|
15
|
+
def request_data
|
16
|
+
{
|
17
|
+
request_time: req_time,
|
18
|
+
merchant_id: merchant_id,
|
19
|
+
merchant_auth: merchant_auth_encryption,
|
20
|
+
hash: hash_data
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
# override
|
25
|
+
def hash_data
|
26
|
+
data = "#{merchant_id}#{merchant_auth_encryption}#{req_time}"
|
27
|
+
Base64.strict_encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha512'), api_key, data))
|
28
|
+
end
|
29
|
+
|
30
|
+
# override
|
31
|
+
def merchant_auth
|
32
|
+
{
|
33
|
+
'mc_id' => merchant_id,
|
34
|
+
'tran_id' => transaction_id
|
35
|
+
}.to_json
|
36
|
+
end
|
37
|
+
|
38
|
+
def cancel_url
|
39
|
+
"#{host}#{ENV.fetch('PAYWAY_V2_PRE_AUTH_CANCEL_PATH')}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
module Vpago
|
4
|
+
module PaywayV2
|
5
|
+
class PreAuthCompleter < Base
|
6
|
+
def call
|
7
|
+
return if completed? || cancelled?
|
8
|
+
|
9
|
+
@response = pre_auth_response
|
10
|
+
save_response if success?
|
11
|
+
end
|
12
|
+
|
13
|
+
def completed? = @payment.pre_auth_response['transaction_status'] == 'COMPLETED'
|
14
|
+
def cancelled? = @payment.pre_auth_response['transaction_status'] == 'CANCELLED'
|
15
|
+
|
16
|
+
def save_response
|
17
|
+
@payment.update(pre_auth_response: json_response)
|
18
|
+
end
|
19
|
+
|
20
|
+
def pre_auth_response
|
21
|
+
conn = Faraday::Connection.new do |faraday|
|
22
|
+
faraday.request :url_encoded
|
23
|
+
end
|
24
|
+
|
25
|
+
conn.post(complete_url, request_data)
|
26
|
+
end
|
27
|
+
|
28
|
+
def request_data
|
29
|
+
{
|
30
|
+
request_time: req_time,
|
31
|
+
merchant_id: merchant_id,
|
32
|
+
merchant_auth: merchant_auth_encryption,
|
33
|
+
hash: hash_data
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def hash_data
|
38
|
+
data = "#{merchant_auth_encryption}#{req_time}#{merchant_id}"
|
39
|
+
Base64.strict_encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha512'), api_key, data))
|
40
|
+
end
|
41
|
+
|
42
|
+
def merchant_auth
|
43
|
+
{
|
44
|
+
'mc_id' => merchant_id,
|
45
|
+
'tran_id' => transaction_id,
|
46
|
+
'complete_amount' => amount.to_s
|
47
|
+
}.to_json
|
48
|
+
end
|
49
|
+
|
50
|
+
def merchant_auth_encryption
|
51
|
+
@merchant_auth_encryption ||= Vpago::PayoutProfiles::Payway::OpenSslEncrypter.new(
|
52
|
+
content: merchant_auth,
|
53
|
+
rsa_public_key: public_key
|
54
|
+
).call
|
55
|
+
end
|
56
|
+
|
57
|
+
def complete_url
|
58
|
+
"#{host}#{ENV.fetch('PAYWAY_V2_PRE_AUTH_COMPLETE_PATH')}"
|
59
|
+
end
|
60
|
+
|
61
|
+
def success?
|
62
|
+
json_response['status']['code'] == '00'
|
63
|
+
end
|
64
|
+
|
65
|
+
def json_response
|
66
|
+
return @payment.pre_auth_response if @payment.pre_auth_response.present?
|
67
|
+
|
68
|
+
@json_response ||= begin
|
69
|
+
JSON.parse(@response.body)
|
70
|
+
rescue JSON::ParserError
|
71
|
+
{}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
module Vpago
|
4
|
+
module PaywayV2
|
5
|
+
class TransactionStatus < Base
|
6
|
+
# status:
|
7
|
+
# 0 – Approved, PRE_AUTH, PREAUTH_APPROVED
|
8
|
+
# 1 – Created
|
9
|
+
# 2 – Pending
|
10
|
+
# 3 – Declined
|
11
|
+
# 4 – Refunded
|
12
|
+
# 5 – Wrong Hash
|
13
|
+
# 7 - Cancelled
|
14
|
+
# 11 – Other Server-side Error
|
15
|
+
def call
|
16
|
+
@response = check_remote_status
|
17
|
+
end
|
18
|
+
|
19
|
+
def status
|
20
|
+
json_response['status']&.to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
def success?
|
24
|
+
status == '0'
|
25
|
+
end
|
26
|
+
|
27
|
+
# request failed does not mean payment failed.
|
28
|
+
# but it failed when status is failed.
|
29
|
+
def pending?
|
30
|
+
%w[1 2].include?(status)
|
31
|
+
end
|
32
|
+
|
33
|
+
def failed?
|
34
|
+
%w[3 4 5 7].include?(status)
|
35
|
+
end
|
36
|
+
|
37
|
+
def check_remote_status
|
38
|
+
conn = Faraday::Connection.new do |faraday|
|
39
|
+
faraday.request :url_encoded
|
40
|
+
end
|
41
|
+
|
42
|
+
data = {
|
43
|
+
req_time: req_time,
|
44
|
+
merchant_id: merchant_id,
|
45
|
+
tran_id: transaction_id,
|
46
|
+
hash: checker_hmac
|
47
|
+
}
|
48
|
+
|
49
|
+
conn.post(check_transaction_url, data)
|
50
|
+
end
|
51
|
+
|
52
|
+
def payout_total
|
53
|
+
payouts_response = json_response['payout']
|
54
|
+
|
55
|
+
return nil if payouts_response.nil? || !payouts_response.is_a?(Array) || payouts_response.empty?
|
56
|
+
|
57
|
+
payouts_response.map { |payout| payout['amt'].to_f || 0 }.sum
|
58
|
+
end
|
59
|
+
|
60
|
+
def error_message
|
61
|
+
json_response['description'].presence
|
62
|
+
end
|
63
|
+
|
64
|
+
def json_response
|
65
|
+
@json_response ||= begin
|
66
|
+
JSON.parse(@response.body)
|
67
|
+
rescue JSON::ParserError
|
68
|
+
{}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def checker_hmac
|
73
|
+
data = "#{req_time}#{merchant_id}#{transaction_id}"
|
74
|
+
hash = Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha512'), api_key, data))
|
75
|
+
|
76
|
+
# somehow php counter part are not able to decode if the \n present.
|
77
|
+
hash.delete("\n")
|
78
|
+
end
|
79
|
+
|
80
|
+
def check_transaction_url
|
81
|
+
"#{host}#{ENV.fetch('PAYWAY_CHECK_TRANSACTION_PATH', nil)}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|