barion 0.2.0

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 (38) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +158 -0
  4. data/Rakefile +34 -0
  5. data/app/assets/config/barion_manifest.js +1 -0
  6. data/app/assets/stylesheets/barion/application.css +15 -0
  7. data/app/assets/stylesheets/barion/main.css +4 -0
  8. data/app/controllers/barion/application_controller.rb +7 -0
  9. data/app/controllers/barion/main_controller.rb +28 -0
  10. data/app/helpers/barion/application_helper.rb +7 -0
  11. data/app/helpers/barion/main_helper.rb +7 -0
  12. data/app/models/barion/address.rb +60 -0
  13. data/app/models/barion/application_record.rb +10 -0
  14. data/app/models/barion/gift_card_purchase.rb +66 -0
  15. data/app/models/barion/item.rb +88 -0
  16. data/app/models/barion/payer_account.rb +119 -0
  17. data/app/models/barion/payment.rb +348 -0
  18. data/app/models/barion/payment_transaction.rb +134 -0
  19. data/app/models/barion/purchase.rb +107 -0
  20. data/app/models/concerns/barion/currencies.rb +11 -0
  21. data/app/models/concerns/barion/data_formats.rb +12 -0
  22. data/app/models/concerns/barion/json_serializer.rb +106 -0
  23. data/app/views/barion/main/land.html.erb +7 -0
  24. data/config/initializers/barion.rb +9 -0
  25. data/config/routes.rb +10 -0
  26. data/db/migrate/20201222235354_create_barion_payments.rb +59 -0
  27. data/db/migrate/20201223001557_create_barion_addresses.rb +21 -0
  28. data/db/migrate/20201223002427_create_barion_payment_transactions.rb +28 -0
  29. data/db/migrate/20201223003219_create_barion_purchases.rb +24 -0
  30. data/db/migrate/20210111051233_create_barion_payer_accounts.rb +28 -0
  31. data/db/migrate/20210128220347_create_barion_items.rb +21 -0
  32. data/db/migrate/20210201120609_create_barion_gift_card_purchases.rb +14 -0
  33. data/lib/barion.rb +100 -0
  34. data/lib/barion/engine.rb +14 -0
  35. data/lib/barion/version.rb +5 -0
  36. data/lib/tasks/auto_annotate_models.rake +59 -0
  37. data/lib/tasks/barion_tasks.rake +4 -0
  38. metadata +207 -0
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ # == Schema Information
4
+ #
5
+ # Table name: barion_payment_transactions
6
+ #
7
+ # id :integer not null, primary key
8
+ # comment :string
9
+ # currency :string(3)
10
+ # payee :string not null
11
+ # payer :string
12
+ # status :integer default("prepared"), not null
13
+ # total :decimal(, ) not null
14
+ # transaction_time :datetime
15
+ # transaction_type :integer
16
+ # created_at :datetime not null
17
+ # updated_at :datetime not null
18
+ # payee_transactions_id :bigint
19
+ # payment_id :bigint
20
+ # pos_transaction_id :string not null
21
+ # related_id :string
22
+ # transaction_id :string
23
+ #
24
+ # Indexes
25
+ #
26
+ # index_barion_payment_transactions_on_payee (payee)
27
+ # index_barion_payment_transactions_on_payee_transactions_id (payee_transactions_id)
28
+ # index_barion_payment_transactions_on_payment_id (payment_id)
29
+ # index_barion_payment_transactions_on_pos_transaction_id (pos_transaction_id)
30
+ # index_barion_payment_transactions_on_status (status)
31
+ # index_barion_payment_transactions_on_transaction_id (transaction_id)
32
+ #
33
+ # Foreign Keys
34
+ #
35
+ # payee_transactions_id (payee_transactions_id => barion_payment_transactions.id)
36
+ # payment_id (payment_id => barion_payments.id)
37
+ #
38
+ module Barion
39
+ # Barion Transaction implementation
40
+ class PaymentTransaction < ApplicationRecord
41
+ include ::Barion::Currencies
42
+ include ::Barion::JsonSerializer
43
+
44
+ enum status: {
45
+ prepared: 0, started: 1, succeeded: 2, timeout: 3, shop_is_deleted: 4,
46
+ shop_is_closed: 5, rejected: 6, rejected_by_shop: 12, storno: 13, reserved: 14,
47
+ deleted: 15, expired: 16, authorized: 17, reversed: 18, invalid_payment_record: 210,
48
+ payment_time_out: 211, invalid_payment_status: 212,
49
+ payment_sender_or_recipient_is_invalid: 213, unknown: 255
50
+ }, _default: :prepared
51
+ enum transaction_type: {
52
+ shop: 1, transfer_to_existing_user: 2, transfer_to_technical_account: 3,
53
+ reserve: 16, storno_reserve: 17, card_processing_fee: 21, gateway_fee: 22,
54
+ card_processing_fee_storno: 23, unspecified: 100, card_payment: 150,
55
+ refund: 151, refund_to_bank_card: 152, storno_un_successful_refund_to_bank_card: 153,
56
+ under_review: 180, release_review: 190, bank_transfer_payment: 200,
57
+ refund_to_bank_account: 201, storno_un_successful_refund_to_bank_account: 202,
58
+ bank_transfer_payment_fee: 203
59
+ }
60
+
61
+ belongs_to :payment, inverse_of: :payment_transactions
62
+ has_many :items,
63
+ inverse_of: :payment_transaction,
64
+ after_add: :calc_total,
65
+ after_remove: :calc_total
66
+ attribute :total, :decimal, default: 0.0
67
+ attribute :pos_transaction_id, :string
68
+
69
+ validates :payee, presence: true
70
+ validates :status, presence: true
71
+ validates :pos_transaction_id, presence: true
72
+ validates :items, presence: true
73
+ validates_associated :items
74
+
75
+ after_initialize :set_defaults
76
+
77
+ def currency=(val = nil)
78
+ super(val || payment&.currency)
79
+ end
80
+
81
+ def set_defaults
82
+ self.currency = payment&.currency if currency.nil?
83
+ self.payee = ::Barion.default_payee if payee.nil?
84
+ end
85
+
86
+ def total=(value)
87
+ value = calc_item_totals if value.nil?
88
+ super(value)
89
+ end
90
+
91
+ def serialize_options
92
+ { except: %i[id status created_at updated_at transaction_type related_id],
93
+ include: %i[items],
94
+ map: {
95
+ keys: {
96
+ _all: :camelize,
97
+ pos_transaction_id: 'POSTransactionId'
98
+ },
99
+ values: {
100
+ _all: proc { |v| v.respond_to?(:camelize) ? v.camelize : v },
101
+ _except: %w[items pos_transaction_id payee comment]
102
+ }
103
+ } }
104
+ end
105
+
106
+ def deserialize_options
107
+ {
108
+ except: %i[items],
109
+ map: {
110
+ keys: {
111
+ _all: :underscore,
112
+ POSTransactionId: 'pos_transaction_id'
113
+ },
114
+ values: {
115
+ _all: proc { |v| v.respond_to?(:underscore) ? v.underscore : v },
116
+ _except: %w[Currency]
117
+ }
118
+ }
119
+ }
120
+ end
121
+
122
+ protected
123
+
124
+ def calc_item_totals
125
+ items.sum(&:item_total)
126
+ end
127
+
128
+ private
129
+
130
+ def calc_total(_item)
131
+ self.total = calc_item_totals
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ # == Schema Information
4
+ #
5
+ # Table name: barion_purchases
6
+ #
7
+ # id :integer not null, primary key
8
+ # availability_indicator :integer
9
+ # delivery_email_address :string
10
+ # delivery_timeframe :integer
11
+ # pre_order_date :datetime
12
+ # purchase_date :datetime
13
+ # purchase_type :integer
14
+ # re_order_indicator :integer
15
+ # recurring_expiry :datetime
16
+ # recurring_frequency :integer
17
+ # shipping_address_indicator :integer
18
+ # created_at :datetime not null
19
+ # updated_at :datetime not null
20
+ # payment_id :bigint
21
+ #
22
+ # Indexes
23
+ #
24
+ # index_barion_purchases_on_delivery_email_address (delivery_email_address)
25
+ # index_barion_purchases_on_delivery_timeframe (delivery_timeframe)
26
+ # index_barion_purchases_on_payment_id (payment_id)
27
+ #
28
+ module Barion
29
+ # Represents a purchase in Barion engine
30
+ class Purchase < ApplicationRecord
31
+ include ::Barion::JsonSerializer
32
+
33
+ enum availability_indicator: {
34
+ merchandise_available: 0,
35
+ future_availability: 10
36
+ }, _default: :merchandise_available
37
+
38
+ attr_accessor :delivery_email_address
39
+
40
+ enum delivery_timeframe: {
41
+ electronic_delivery: 0,
42
+ same_day_shipping: 10,
43
+ overnight_shipping: 20,
44
+ two_day_or_more_shipping: 30
45
+ }
46
+ enum re_order_indicator: {
47
+ first_time_ordered: 0,
48
+ reordered: 10
49
+ }
50
+ enum shipping_address_indicator: {
51
+ ship_to_cardholders_billing_address: 0,
52
+ ship_to_another_verified_address: 10,
53
+ ship_to_different_address: 20,
54
+ ship_to_store: 30,
55
+ digital_goods: 40,
56
+ travel_and_event_tickets: 50,
57
+ other: 60
58
+ }
59
+ enum purchase_type: {
60
+ goods_and_service_purchase: 0,
61
+ check_acceptance: 1,
62
+ account_funding: 2,
63
+ quasi_cash_transaction: 3,
64
+ pre_paid_vacation_and_loan: 4
65
+ }
66
+
67
+ belongs_to :payment, inverse_of: :purchase_information
68
+ has_one :gift_card_purchase
69
+
70
+ validates :recurring_frequency,
71
+ numericality: { only_integer: true },
72
+ inclusion: { in: 0..9_999 },
73
+ allow_nil: true
74
+
75
+ with_options if: :initial_recurring_payment? do |purchase|
76
+ purchase.validates :recurring_frequency, presence: true
77
+ purchase.validates :recurring_expiry, presence: true
78
+ end
79
+
80
+ def serialize_options
81
+ { except: %i[id created_at updated_at],
82
+ include: %i[gift_card_purchase],
83
+ map: {
84
+ keys: {
85
+ _all: :camelize
86
+ },
87
+ values: {
88
+ _all: proc { |v| v.respond_to?(:camelize) ? v.camelize : v },
89
+ pre_order_date: :as_datetime,
90
+ recurring_expiry: :as_datetime,
91
+ purchase_date: :as_datetime,
92
+ availability_indicator: :as_enum_id,
93
+ delivery_timeframe: :as_enum_id,
94
+ re_order_indicator: :as_ennum_id,
95
+ shipping_address_indicator: :as_enum_id,
96
+ purchase_type: :as_enum_id
97
+ }
98
+ } }
99
+ end
100
+
101
+ private
102
+
103
+ def initial_recurring_payment?
104
+ payment.recurring? and payment.initiate_recurrence
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Barion
4
+ # Common data formats in Barion
5
+ module Currencies
6
+ extend ActiveSupport::Concern
7
+ included do
8
+ enum currency: { EUR: 'EUR', USD: 'USD', HUF: 'HUF', CZK: 'CZK' }, _default: :HUF
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Barion
4
+ # Common data formats in Barion
5
+ module DataFormats
6
+ extend ActiveSupport::Concern
7
+
8
+ def self.phone_number(number)
9
+ number.sub(/^\+/, '').sub(/^00/, '')[0..29]
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Barion
4
+ # JSON serialization solution for Barion
5
+ module JsonSerializer
6
+ extend ActiveSupport::Concern
7
+
8
+ def serialize_options
9
+ {}
10
+ end
11
+
12
+ def deserialize_options
13
+ {}
14
+ end
15
+
16
+ def key_names
17
+ {}
18
+ end
19
+
20
+ def serializable_hash(options = {})
21
+ options ||= serialize_options
22
+ result = super(serialize_options.merge(options))
23
+ if serialize_options.key?(:map)
24
+ map = serialize_options[:map]
25
+ convert_values(result, map[:values], &map[:values][:_all]) if map.key?(:values)
26
+ convert_keys(result, map[:keys], &map[:keys][:_all]) if map.key?(:keys)
27
+ end
28
+ result.compact!
29
+ end
30
+
31
+ def deserialize(hash, options = {})
32
+ options ||= deserialize_options
33
+ deserialize_options.merge(options)
34
+ return unless deserialize_options.key?(:map)
35
+
36
+ map = deserialize_options[:map]
37
+ convert_values(hash, map[:values], &map[:values][:_all]) if map.key?(:values)
38
+ return unless map.key?(:keys)
39
+
40
+ convert_keys(hash, map[:keys], &map[:keys][:_all])
41
+ end
42
+
43
+ def process_response(response)
44
+ exceptions = deserialize_options.fetch(:except, {})
45
+ associations = deserialize_options.fetch(:assoc, {})
46
+
47
+ hash = deserialize(response)
48
+ hash.map do |key, value|
49
+ next if exceptions.include?(key.to_sym)
50
+
51
+ association = self.class.reflect_on_association(key)
52
+ if association
53
+ (model_key_name, key_name) = associations[key.to_sym].shift
54
+ value.each do |params|
55
+ id = params[key_name]
56
+ item = association.klass.send("find_by_#{model_key_name}", id)
57
+ item.send(:process_response, params.compact!)
58
+ end
59
+ elsif respond_to?("#{key}=")
60
+ send("#{key}=", value)
61
+ end
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def convert_keys(hash, map, &block)
68
+ hash.transform_keys! { |k| map.fetch(k.to_sym, k) unless k.nil? }
69
+ hash.transform_keys!(&block) if block_given?
70
+ end
71
+
72
+ def convert_values(hash, map, &block)
73
+ hash.each do |k, v|
74
+ ks = k.to_sym
75
+ hash[k] = send(map[ks], ks, v) if v.present? && map.key?(ks) && respond_to?(map[ks], true)
76
+ end
77
+ hash_exceptions = hash.slice(*map[:_except])
78
+ hash.transform_values!(&block) if block_given?
79
+ hash.merge!(hash_exceptions)
80
+ end
81
+
82
+ def as_time(_, sec)
83
+ day, sec = sec.divmod(1.days)
84
+ hour, sec = sec.divmod(1.hour)
85
+ min, sec = sec.divmod(1.minute)
86
+ format('%<day>d.%02<hour>d:%02<min>d:%02<sec>d', day: day, hour: hour, min: min, sec: sec)
87
+ end
88
+
89
+ def as_datetime(_, date)
90
+ date.as_json.delete_suffix('Z')
91
+ end
92
+
93
+ def as_list(_, string)
94
+ string.camelize.split(',')
95
+ end
96
+
97
+ def as_enum_id(enum, id)
98
+ hash = self.class.send(enum.to_s.pluralize)
99
+ hash.fetch(id)
100
+ end
101
+
102
+ def as_string(_, value)
103
+ value.to_s
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,7 @@
1
+ <h1>Payment <%= @payment.status.to_s.camelize %></h1>
2
+ <dl>
3
+ <dt>Request id:</dt>
4
+ <dd><%= @payment.payment_request_id %></dd>
5
+ <dt>Order number:</dt>
6
+ <dd><%= @payment.order_number %></dd>
7
+ </dl>
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ # ::Barion.config do |shop|
4
+ # shop.poskey = 'test'
5
+ # shop.publickey = 'test2'
6
+ # shop.sandbox = true
7
+ # shop.acronym = ''
8
+ # shop.default_payee = 'me@example.org'
9
+ # end
data/config/routes.rb ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ # == Route Map
4
+ #
5
+
6
+ ::Barion::Engine.routes.draw do
7
+ root to: 'main#land'
8
+ post 'callback', to: 'main#callback', as: :gateway_callback
9
+ get 'land', to: 'main#land', as: :gateway_back
10
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Creates Barion::Payment record persistency
4
+ class CreateBarionPayments < ActiveRecord::Migration[6.0]
5
+ def change
6
+ # rubocop:disable Metrics/BlockLength
7
+ create_table :barion_payments do |t|
8
+ t.string :poskey, index: true, null: false
9
+ t.integer :payment_type, index: true, default: 0, null: false
10
+ t.integer :reservation_period, limit: 8
11
+ t.integer :delayed_capture_period, limit: 6
12
+ t.string :payment_window, limit: 6
13
+ t.boolean :guest_check_out
14
+ t.boolean :initiate_recurrence
15
+ t.string :recurrence_id, limit: 100, index: true
16
+ t.integer :funding_sources, default: 0
17
+ t.string :payment_request_id, limit: 100, index: true
18
+ t.string :payer_hint, limit: 256
19
+ t.string :card_holder_name_hint, limit: 45
20
+ t.integer :recurrence_type, default: 0
21
+ t.string :trace_id, limit: 100
22
+ t.string :redirect_url, limit: 2000
23
+ t.string :callback_url, limit: 2000
24
+
25
+ t.string :order_number, limit: 100, index: true
26
+ t.string :locale, limit: 10, null: false
27
+ t.string :currency, limit: 3, null: false
28
+ t.string :payer_phone_number, limit: 30
29
+ t.string :payer_work_phone_number, limit: 30
30
+ t.string :payer_home_number, limit: 30
31
+ t.integer :challenge_preference, default: 0
32
+ t.string :checksum, null: false
33
+
34
+ t.string :payment_id, index: true
35
+ t.integer :status, index: true, null: false
36
+ t.string :qr_url, limit: 2000
37
+ t.integer :recurrence_result
38
+ t.string :gateway_url, limit: 2000
39
+
40
+ t.string :pos_id
41
+ t.string :pos_name
42
+ t.string :pos_owner_email
43
+ t.string :pos_owner_country
44
+ t.integer :funding_source
45
+ t.datetime :created_at_barion
46
+ t.datetime :started_at
47
+ t.datetime :completed_at
48
+ t.datetime :valid_until
49
+ t.datetime :reserved_until
50
+ t.datetime :delayed_capture_until
51
+ t.decimal :total
52
+ t.string :suggested_local
53
+ t.integer :fraud_risk_score
54
+
55
+ t.timestamps
56
+ end
57
+ # rubocop:enable Metrics/BlockLength
58
+ end
59
+ end