gera 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +674 -0
- data/README.md +67 -0
- data/Rakefile +43 -0
- data/app/assets/config/gera_manifest.js +2 -0
- data/app/assets/javascripts/gera/application.js +14 -0
- data/app/assets/stylesheets/gera/application.css +15 -0
- data/app/authorizers/gera/application_authorizer.rb +6 -0
- data/app/authorizers/gera/currency_rate_authorizer.rb +9 -0
- data/app/authorizers/gera/currency_rate_mode_authorizer.rb +7 -0
- data/app/authorizers/gera/direction_rate_authorizer.rb +8 -0
- data/app/authorizers/gera/exchange_rate_authorizer.rb +8 -0
- data/app/authorizers/gera/payment_system_authorizer.rb +13 -0
- data/app/authorizers/gera/rate_source_authorizer.rb +7 -0
- data/app/controllers/gera/application_controller.rb +30 -0
- data/app/controllers/gera/currencies_controller.rb +8 -0
- data/app/controllers/gera/currency_rate_history_intervals_controller.rb +53 -0
- data/app/controllers/gera/currency_rate_mode_snapshots_controller.rb +83 -0
- data/app/controllers/gera/currency_rate_modes_controller.rb +60 -0
- data/app/controllers/gera/currency_rates_controller.rb +70 -0
- data/app/controllers/gera/direction_rate_history_intervals_controller.rb +62 -0
- data/app/controllers/gera/direction_rates_controller.rb +28 -0
- data/app/controllers/gera/exchange_rates_controller.rb +25 -0
- data/app/controllers/gera/external_rate_snapshots_controller.rb +35 -0
- data/app/controllers/gera/external_rates_controller.rb +28 -0
- data/app/controllers/gera/payment_systems_controller.rb +78 -0
- data/app/controllers/gera/rate_sources_controller.rb +8 -0
- data/app/decorators/gera/currency_rate_decorator.rb +148 -0
- data/app/decorators/gera/direction_rate_decorator.rb +47 -0
- data/app/decorators/gera/payment_system_decorator.rb +19 -0
- data/app/helpers/gera/application_helper.rb +110 -0
- data/app/helpers/gera/currency_rate_helper.rb +19 -0
- data/app/helpers/gera/currency_rate_modes_helper.rb +73 -0
- data/app/helpers/gera/direction_rate_helper.rb +36 -0
- data/app/helpers/gera/exchange_rates_helper.rb +21 -0
- data/app/jobs/gera/application_job.rb +6 -0
- data/app/models/concerns/gera/currency_pair_generator.rb +14 -0
- data/app/models/concerns/gera/currency_pair_support.rb +42 -0
- data/app/models/concerns/gera/currency_rate_mode_builder_support.rb +35 -0
- data/app/models/concerns/gera/direction_support.rb +14 -0
- data/app/models/concerns/gera/history_interval_concern.rb +46 -0
- data/app/models/gera/application_record.rb +8 -0
- data/app/models/gera/cbr_external_rate.rb +13 -0
- data/app/models/gera/cross_rate_mode.rb +13 -0
- data/app/models/gera/currency_rate.rb +78 -0
- data/app/models/gera/currency_rate_history_interval.rb +25 -0
- data/app/models/gera/currency_rate_history_interval_filter.rb +30 -0
- data/app/models/gera/currency_rate_mode.rb +20 -0
- data/app/models/gera/currency_rate_mode_snapshot.rb +26 -0
- data/app/models/gera/currency_rate_snapshot.rb +12 -0
- data/app/models/gera/direction.rb +44 -0
- data/app/models/gera/direction_rate.rb +136 -0
- data/app/models/gera/direction_rate_history_interval.rb +33 -0
- data/app/models/gera/direction_rate_history_interval_filter.rb +30 -0
- data/app/models/gera/direction_rate_snapshot.rb +7 -0
- data/app/models/gera/exchange_rate.rb +130 -0
- data/app/models/gera/external_rate.rb +38 -0
- data/app/models/gera/external_rate_snapshot.rb +20 -0
- data/app/models/gera/payment_system.rb +98 -0
- data/app/models/gera/rate_source.rb +77 -0
- data/app/models/gera/rate_source_auto.rb +25 -0
- data/app/models/gera/rate_source_bitfinex.rb +9 -0
- data/app/models/gera/rate_source_cbr.rb +13 -0
- data/app/models/gera/rate_source_cbr_avg.rb +6 -0
- data/app/models/gera/rate_source_exmo.rb +9 -0
- data/app/models/gera/rate_source_manual.rb +13 -0
- data/app/views/application/_exchange_rate_monitor.slim +1 -0
- data/app/views/gera/application/_attributes_table.slim +5 -0
- data/app/views/gera/application/_currencies_table.slim +18 -0
- data/app/views/gera/application/_currency_rate_mode_snapshots.slim +6 -0
- data/app/views/gera/application/_direction_rate.slim +6 -0
- data/app/views/gera/application/_directions_submenu.slim +11 -0
- data/app/views/gera/application/_directions_table.slim +15 -0
- data/app/views/gera/application/_exchange_rate.slim +6 -0
- data/app/views/gera/application/_external_rate.slim +6 -0
- data/app/views/gera/application/_header.slim +12 -0
- data/app/views/gera/application/_table.slim +28 -0
- data/app/views/gera/application/_topnav.slim +21 -0
- data/app/views/gera/application/direction_details.slim +75 -0
- data/app/views/gera/application/page.html.slim +1 -0
- data/app/views/gera/currencies/index.html.slim +20 -0
- data/app/views/gera/currency_rate_history_intervals/_filter.slim +11 -0
- data/app/views/gera/currency_rate_history_intervals/index.slim +39 -0
- data/app/views/gera/currency_rate_mode_snapshots/_snapshot.slim +20 -0
- data/app/views/gera/currency_rate_mode_snapshots/edit.html.slim +30 -0
- data/app/views/gera/currency_rate_modes/_cross_rate_mode_fields.slim +21 -0
- data/app/views/gera/currency_rate_modes/_currency_rate_mode.slim +7 -0
- data/app/views/gera/currency_rate_modes/_form.slim +29 -0
- data/app/views/gera/currency_rate_modes/edit.slim +11 -0
- data/app/views/gera/currency_rate_modes/index.html.slim +12 -0
- data/app/views/gera/currency_rates/_currency_rate.slim +22 -0
- data/app/views/gera/currency_rates/_currency_rate_humanized.slim +35 -0
- data/app/views/gera/currency_rates/diff.slim +12 -0
- data/app/views/gera/currency_rates/index.slim +27 -0
- data/app/views/gera/currency_rates/modes.slim +14 -0
- data/app/views/gera/currency_rates/show.slim +4 -0
- data/app/views/gera/direction_rate_history_intervals/_filter.slim +11 -0
- data/app/views/gera/direction_rate_history_intervals/index.slim +41 -0
- data/app/views/gera/direction_rates/_direction_rate_example_calculator.slim +28 -0
- data/app/views/gera/direction_rates/diff.slim +19 -0
- data/app/views/gera/direction_rates/index.slim +26 -0
- data/app/views/gera/direction_rates/legacy.html.slim +5 -0
- data/app/views/gera/direction_rates/minimals.slim +5 -0
- data/app/views/gera/direction_rates/show.slim +14 -0
- data/app/views/gera/external_rate_snapshots/index.slim +25 -0
- data/app/views/gera/external_rate_snapshots/show.slim +22 -0
- data/app/views/gera/external_rates/_flat_list.slim +22 -0
- data/app/views/gera/external_rates/index.html.slim +28 -0
- data/app/views/gera/external_rates/show.slim +1 -0
- data/app/views/gera/payment_systems/_fields.slim +4 -0
- data/app/views/gera/payment_systems/_fields_table.slim +18 -0
- data/app/views/gera/payment_systems/_form.slim +9 -0
- data/app/views/gera/payment_systems/edit.slim +7 -0
- data/app/views/gera/payment_systems/index.slim +3 -0
- data/app/views/gera/payment_systems/new.slim +9 -0
- data/app/views/gera/payment_systems/show.slim +1 -0
- data/app/views/gera/rate_sources/_list.slim +13 -0
- data/app/views/gera/rate_sources/_rate_source.slim +23 -0
- data/app/views/gera/rate_sources/index.html.slim +6 -0
- data/app/views/layouts/application.html.slim +15 -0
- data/app/views/layouts/gera/blank.html.slim +10 -0
- data/app/workers/concerns/gera/rates_worker.rb +87 -0
- data/app/workers/gera/bitfinex_rates_worker.rb +65 -0
- data/app/workers/gera/cbr_avg_rates_worker.rb +42 -0
- data/app/workers/gera/cbr_rates_worker.rb +192 -0
- data/app/workers/gera/create_history_intervals_worker.rb +38 -0
- data/app/workers/gera/currency_rates_worker.rb +64 -0
- data/app/workers/gera/directions_rates_worker.rb +51 -0
- data/app/workers/gera/exmo_rates_worker.rb +62 -0
- data/app/workers/gera/purge_currency_rates_worker.rb +21 -0
- data/app/workers/gera/purge_direction_rates_worker.rb +30 -0
- data/config/currencies.yml +559 -0
- data/config/routes.rb +30 -0
- data/db/migrate/20180912130000_setup.rb +228 -0
- data/db/migrate/20190314114844_add_is_available_to_payment_systems.rb +7 -0
- data/db/migrate/20190315113046_add_icon_url_to_payment_systems.rb +7 -0
- data/db/migrate/20190315132137_add_commission_to_payment_systems.rb +7 -0
- data/lib/banks/currency_exchange.rb +12 -0
- data/lib/builders/currency_rate_auto_builder.rb +38 -0
- data/lib/builders/currency_rate_builder.rb +60 -0
- data/lib/builders/currency_rate_cross_builder.rb +70 -0
- data/lib/builders/currency_rate_direct_builder.rb +26 -0
- data/lib/gera.rb +32 -0
- data/lib/gera/bitfinex_fetcher.rb +36 -0
- data/lib/gera/configuration.rb +47 -0
- data/lib/gera/currencies_purger.rb +28 -0
- data/lib/gera/currency_pair.rb +93 -0
- data/lib/gera/engine.rb +14 -0
- data/lib/gera/mathematic.rb +156 -0
- data/lib/gera/money_support.rb +89 -0
- data/lib/gera/numeric.rb +25 -0
- data/lib/gera/railtie.rb +8 -0
- data/lib/gera/rate.rb +22 -0
- data/lib/gera/rate_from_multiplicator.rb +54 -0
- data/lib/gera/repositories/currency_rate_modes_repository.rb +37 -0
- data/lib/gera/repositories/currency_rates_repository.rb +25 -0
- data/lib/gera/repositories/direction_rates_repository.rb +46 -0
- data/lib/gera/repositories/exchange_rates_repository.rb +23 -0
- data/lib/gera/repositories/payment_systems_repository.rb +21 -0
- data/lib/gera/repositories/universe.rb +47 -0
- data/lib/gera/version.rb +3 -0
- data/lib/tasks/auto_generate_diagram.rake +6 -0
- data/lib/tasks/gera_tasks.rake +4 -0
- metadata +765 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gera
|
4
|
+
class DirectionRateHistoryInterval < ApplicationRecord
|
5
|
+
include HistoryIntervalConcern
|
6
|
+
|
7
|
+
# Их не надо подключать, потому что иначе при создании записи
|
8
|
+
# ActiveRercord проверяет есить ли они в базе
|
9
|
+
#
|
10
|
+
# belongs_to :payment_system_from, class_name: 'PaymentSystem'
|
11
|
+
# belongs_to :payment_system_to, class_name: 'PaymentSystem'
|
12
|
+
|
13
|
+
def self.create_by_interval!(interval_from, interval_to = nil)
|
14
|
+
interval_to ||= interval_from + INTERVAL
|
15
|
+
DirectionRate
|
16
|
+
.where('created_at >= ? and created_at < ?', interval_from, interval_to)
|
17
|
+
.group(:ps_from_id, :ps_to_id)
|
18
|
+
.pluck(:ps_from_id, :ps_to_id, 'min(rate_value)', 'max(rate_value)', 'min(rate_percent)', 'max(rate_percent)')
|
19
|
+
.each do |ps_from_id, ps_to_id, min_rate, max_rate, min_comission, max_comission|
|
20
|
+
|
21
|
+
next if ps_from_id == ps_to_id
|
22
|
+
|
23
|
+
create!(
|
24
|
+
payment_system_from_id: ps_from_id,
|
25
|
+
payment_system_to_id: ps_to_id,
|
26
|
+
min_rate: min_rate, max_rate: max_rate,
|
27
|
+
min_comission: min_comission, max_comission: max_comission,
|
28
|
+
interval_from: interval_from, interval_to: interval_to
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gera
|
4
|
+
class DirectionRateHistoryIntervalFilter
|
5
|
+
include Virtus.model strict: true
|
6
|
+
include ActiveModel::Conversion
|
7
|
+
extend ActiveModel::Naming
|
8
|
+
include ActiveModel::Validations
|
9
|
+
|
10
|
+
attribute :payment_system_from_id, Integer, default: ->(_a, _b) { Gera::PaymentSystem.first.id }
|
11
|
+
attribute :payment_system_to_id, Integer, default: ->(_a, _b) { Gera::PaymentSystem.first.id }
|
12
|
+
attribute :value_type, String, default: 'rate'
|
13
|
+
|
14
|
+
def payment_system_from
|
15
|
+
@payment_system_from ||= Gera::PaymentSystem.find payment_system_from_id
|
16
|
+
end
|
17
|
+
|
18
|
+
def payment_system_to
|
19
|
+
@payment_system_to ||= Gera::PaymentSystem.find payment_system_to_id
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_param
|
23
|
+
to_hash
|
24
|
+
end
|
25
|
+
|
26
|
+
def persisted?
|
27
|
+
false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Комиссия для расчета конечного курса между платежными системами
|
4
|
+
# TODO: Пеерименовать в Direction
|
5
|
+
# Комиссии по направлениям платежных систем
|
6
|
+
# если в парсере операторы изменили курс/комиссию, то эта комиссия
|
7
|
+
# устанвливается сначала сюда, потом растекается по остальным
|
8
|
+
#
|
9
|
+
# * value - само значение комиссии
|
10
|
+
# * cor1/cor2 - границы коридора
|
11
|
+
#
|
12
|
+
# * position - позиция в best которую нужно установить?
|
13
|
+
# * on_notif - ???
|
14
|
+
# * on_corridor - в коридоре?
|
15
|
+
module Gera
|
16
|
+
class ExchangeRate < ApplicationRecord
|
17
|
+
include Authority::Abilities
|
18
|
+
|
19
|
+
DEFAULT_COMISSION = 50
|
20
|
+
|
21
|
+
include Mathematic
|
22
|
+
include DirectionSupport
|
23
|
+
|
24
|
+
belongs_to :payment_system_from, foreign_key: :income_payment_system_id, class_name: 'Gera::PaymentSystem'
|
25
|
+
belongs_to :payment_system_to, foreign_key: :outcome_payment_system_id, class_name: 'Gera::PaymentSystem'
|
26
|
+
|
27
|
+
scope :ordered, -> { order :id }
|
28
|
+
scope :enabled, -> { where is_enabled: true }
|
29
|
+
|
30
|
+
scope :with_payment_systems, lambda {
|
31
|
+
includes(:payment_system_from, :payment_system_to)
|
32
|
+
.joins(:payment_system_from, :payment_system_to)
|
33
|
+
}
|
34
|
+
|
35
|
+
scope :available, lambda {
|
36
|
+
with_payment_systems
|
37
|
+
.enabled
|
38
|
+
.where("#{PaymentSystem.table_name}.income_enabled and payment_system_tos_gera_exchange_rates.outcome_enabled")
|
39
|
+
.where("#{table_name}.income_payment_system_id <> #{table_name}.outcome_payment_system_id")
|
40
|
+
}
|
41
|
+
|
42
|
+
after_commit :update_direction_rates, if: -> { previous_changes.key?('value') }
|
43
|
+
|
44
|
+
before_create do
|
45
|
+
self.in_cur = payment_system_from.currency.to_s
|
46
|
+
self.out_cur = payment_system_to.currency.to_s
|
47
|
+
self.comission ||= DEFAULT_COMISSION
|
48
|
+
end
|
49
|
+
|
50
|
+
validates :commission, presence: true
|
51
|
+
|
52
|
+
delegate :rate, :currency_rate, to: :direction_rate
|
53
|
+
|
54
|
+
alias_attribute :ps_from_id, :income_payment_system_id
|
55
|
+
alias_attribute :ps_to_id, :outcome_payment_system_id
|
56
|
+
alias_attribute :payment_system_from_id, :income_payment_system_id
|
57
|
+
alias_attribute :payment_system_to_id, :outcome_payment_system_id
|
58
|
+
|
59
|
+
alias_attribute :comission, :value
|
60
|
+
alias_attribute :commission, :value
|
61
|
+
alias_attribute :comission_percents, :value
|
62
|
+
|
63
|
+
alias_attribute :income_payment_system, :payment_system_from
|
64
|
+
alias_attribute :outcome_payment_system, :payment_system_to
|
65
|
+
|
66
|
+
def self.list_rates
|
67
|
+
order('id asc').each_with_object({}) do |er, h|
|
68
|
+
h[er.income_payment_system_id] ||= {}
|
69
|
+
h[er.income_payment_system_id][er.outcome_payment_system_id] = h.value
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def available?
|
74
|
+
is_enabled?
|
75
|
+
end
|
76
|
+
|
77
|
+
def update_finite_rate!(finite_rate)
|
78
|
+
update! comission: calculate_comission(finite_rate, currency_rate.rate_value)
|
79
|
+
end
|
80
|
+
|
81
|
+
def custom_inspect
|
82
|
+
{
|
83
|
+
value: value,
|
84
|
+
exchange_rate_id: id,
|
85
|
+
payment_system_to: payment_system_to.to_s,
|
86
|
+
payment_system_from: payment_system_from.to_s,
|
87
|
+
out_currency: out_currency.to_s,
|
88
|
+
in_currency: in_currency.to_s
|
89
|
+
}.to_s
|
90
|
+
end
|
91
|
+
|
92
|
+
def currency_pair
|
93
|
+
@currency_pair ||= CurrencyPair.new in_currency, out_currency
|
94
|
+
end
|
95
|
+
|
96
|
+
def out_currency
|
97
|
+
Money::Currency.find out_cur
|
98
|
+
end
|
99
|
+
|
100
|
+
def currency_to
|
101
|
+
out_currency
|
102
|
+
end
|
103
|
+
|
104
|
+
def currency_from
|
105
|
+
in_currency
|
106
|
+
end
|
107
|
+
|
108
|
+
def in_currency
|
109
|
+
Money::Currency.find in_cur
|
110
|
+
end
|
111
|
+
|
112
|
+
def finite_rate
|
113
|
+
direction_rate.rate
|
114
|
+
end
|
115
|
+
|
116
|
+
def to_s
|
117
|
+
[in_currency, out_currency].join '/'
|
118
|
+
end
|
119
|
+
|
120
|
+
def direction_rate
|
121
|
+
Universe.direction_rates_repository.find_direction_rate_by_exchange_rate_id id
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def update_direction_rates
|
127
|
+
DirectionsRatesWorker.perform_async(exchange_rate_id: id)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Курсы внешних систем
|
4
|
+
module Gera
|
5
|
+
class ExternalRate < ApplicationRecord
|
6
|
+
include CurrencyPairSupport
|
7
|
+
|
8
|
+
belongs_to :source, class_name: 'RateSource'
|
9
|
+
belongs_to :snapshot, class_name: 'ExternalRateSnapshot'
|
10
|
+
|
11
|
+
scope :ordered, -> { order :cur_from, :cur_to }
|
12
|
+
|
13
|
+
before_validation do
|
14
|
+
self.source ||= snapshot.try :rate_source
|
15
|
+
end
|
16
|
+
|
17
|
+
before_validation :upcase_currencies
|
18
|
+
|
19
|
+
# TODO: validate cur_from, cur_to из списка разрешенных
|
20
|
+
|
21
|
+
delegate :actual_for, to: :snapshot
|
22
|
+
|
23
|
+
def direction_rate
|
24
|
+
Universe.direction_rates_repository.find_direction_rate_by_exchange_rate_id id
|
25
|
+
end
|
26
|
+
|
27
|
+
def dump
|
28
|
+
as_json(only: %i[id cur_from cur_to rate_value source_id created_at])
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def upcase_currencies
|
34
|
+
self.cur_from = cur_from.to_s.upcase if cur_from.present?
|
35
|
+
self.cur_to = cur_to.to_s.upcase if cur_to.present?
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gera
|
4
|
+
class ExternalRateSnapshot < ApplicationRecord
|
5
|
+
belongs_to :rate_source
|
6
|
+
|
7
|
+
has_many :external_rates, foreign_key: :snapshot_id
|
8
|
+
|
9
|
+
scope :ordered, -> { order 'actual_for desc' }
|
10
|
+
scope :last_actuals_by_rate_sources, -> { where id: group(:rate_source_id).maximum(:id).values }
|
11
|
+
|
12
|
+
before_save do
|
13
|
+
self.actual_for ||= Time.zone.now
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
"snapshot[#{id}]:#{rate_source}:#{actual_for}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gera
|
4
|
+
class PaymentSystem < ApplicationRecord
|
5
|
+
include ::Archivable
|
6
|
+
include Gera::Mathematic
|
7
|
+
include Authority::Abilities
|
8
|
+
|
9
|
+
scope :ordered, -> { order :priority }
|
10
|
+
scope :enabled, -> { where 'income_enabled>0 or outcome_enabled>0' }
|
11
|
+
scope :disabled, -> { where income_enabled: false, outcome_enabled: false }
|
12
|
+
scope :available, -> { where is_available: true }
|
13
|
+
|
14
|
+
# TODO: move to kassa-admin
|
15
|
+
enum total_computation_method: %i[regular_fee reverse_fee]
|
16
|
+
enum transfer_comission_payer: %i[user shop], _prefix: :transfer_comission_payer
|
17
|
+
|
18
|
+
validates :name, presence: true, uniqueness: true
|
19
|
+
validates :currency, presence: true
|
20
|
+
|
21
|
+
before_create do
|
22
|
+
self.priority = self.class.maximum(:priority).to_i + 1
|
23
|
+
end
|
24
|
+
|
25
|
+
after_create :create_exchange_rates
|
26
|
+
|
27
|
+
delegate :iso_code, to: :currency, prefix: true, allow_nil: true
|
28
|
+
|
29
|
+
alias_attribute :archived_at, :deleted_at
|
30
|
+
alias_attribute :enable_income, :income_enabled
|
31
|
+
alias_attribute :enable_outcome, :outcome_enabled
|
32
|
+
|
33
|
+
# TODO: rename type_cy to currency
|
34
|
+
def currency
|
35
|
+
return unless type_cy
|
36
|
+
|
37
|
+
@currency ||= Money::Currency.find_by_local_id(type_cy) || raise("Не найдена валюта #{type_cy}")
|
38
|
+
end
|
39
|
+
|
40
|
+
def currency=(cur)
|
41
|
+
cur = Money::Currency.find cur unless cur.is_a? Money::Currency
|
42
|
+
self.type_cy = cur.is_a?(Money::Currency) ? cur.local_id : nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
name
|
47
|
+
end
|
48
|
+
|
49
|
+
# TODO: move to kassa-admin
|
50
|
+
def total_with_fee(money)
|
51
|
+
calculate_total(money: money, fee: transfer_fee)
|
52
|
+
end
|
53
|
+
|
54
|
+
def unverified_total_with_fee(money)
|
55
|
+
calculate_total(money: money, fee: unverified_transfer_fee)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def calculate_total(money:, fee:)
|
61
|
+
if fee.computation_method == 'regular_fee'
|
62
|
+
calculate_total_using_regular_comission(money, fee.amount)
|
63
|
+
elsif fee.computation_method == 'reverse_fee'
|
64
|
+
calculate_total_using_reverse_comission(money, fee.amount)
|
65
|
+
else
|
66
|
+
raise NotImplementedError, "Нет расчета для #{fee.computation_method}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def transfer_fee
|
71
|
+
OpenStruct.new(
|
72
|
+
amount: income_fee,
|
73
|
+
computation_method: total_computation_method
|
74
|
+
).freeze
|
75
|
+
end
|
76
|
+
|
77
|
+
def unverified_transfer_fee
|
78
|
+
OpenStruct.new(
|
79
|
+
amount: unverified_income_fee,
|
80
|
+
computation_method: total_computation_method
|
81
|
+
).freeze
|
82
|
+
end
|
83
|
+
|
84
|
+
DEFAULT_COMMISSION = 10
|
85
|
+
|
86
|
+
def create_exchange_rates
|
87
|
+
PaymentSystem.pluck(:id).each do |foreign_id|
|
88
|
+
ExchangeRate
|
89
|
+
.create_with(commission: DEFAULT_COMMISSION)
|
90
|
+
.find_or_create_by(payment_system_from_id: id, payment_system_to_id: foreign_id)
|
91
|
+
|
92
|
+
ExchangeRate
|
93
|
+
.create_with(commission: DEFAULT_COMMISSION)
|
94
|
+
.find_or_create_by(payment_system_from_id: foreign_id, payment_system_to_id: id)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gera
|
4
|
+
class RateSource < ApplicationRecord
|
5
|
+
include Authority::Abilities
|
6
|
+
extend CurrencyPairGenerator
|
7
|
+
RateNotFound = Class.new StandardError
|
8
|
+
|
9
|
+
has_many :snapshots, class_name: 'ExternalRateSnapshot'
|
10
|
+
has_many :external_rates, foreign_key: :source_id
|
11
|
+
|
12
|
+
belongs_to :actual_snapshot, class_name: 'ExternalRateSnapshot', optional: true
|
13
|
+
|
14
|
+
scope :ordered, -> { order :priority }
|
15
|
+
scope :enabled, -> { where is_enabled: true }
|
16
|
+
|
17
|
+
scope :enabled_for_cross_rates, -> { enabled }
|
18
|
+
|
19
|
+
validates :key, presence: true, uniqueness: true
|
20
|
+
|
21
|
+
before_create do
|
22
|
+
self.priority ||= RateSource.maximum(:priority).to_i + 1
|
23
|
+
end
|
24
|
+
|
25
|
+
before_validation do
|
26
|
+
self.title ||= self.class.name.underscore
|
27
|
+
self.key ||= self.class.name.underscore
|
28
|
+
end
|
29
|
+
|
30
|
+
delegate :supported_currencies, :available_pairs, to: :class
|
31
|
+
|
32
|
+
def self.supported_currencies
|
33
|
+
raise 'not implemented'
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.available_pairs
|
37
|
+
generate_pairs_from_currencies supported_currencies
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.get!
|
41
|
+
where(type: name).take!
|
42
|
+
end
|
43
|
+
|
44
|
+
def find_rate_by_currency_pair!(pair)
|
45
|
+
find_rate_by_currency_pair(pair) || raise(RateNotFound, pair)
|
46
|
+
end
|
47
|
+
|
48
|
+
def find_rate_by_currency_pair(pair)
|
49
|
+
actual_rates.find_by_currency_pair pair
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_s
|
53
|
+
name
|
54
|
+
end
|
55
|
+
|
56
|
+
def actual_rates
|
57
|
+
external_rates.where(snapshot_id: actual_snapshot_id)
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_s
|
61
|
+
title
|
62
|
+
end
|
63
|
+
|
64
|
+
def is_currency_supported?(cur)
|
65
|
+
cur = Money::Currency.find cur unless cur.is_a? Money::Currency
|
66
|
+
supported_currencies.include? cur
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def validate_currency!(*curs)
|
72
|
+
curs.each do |cur|
|
73
|
+
raise "Источник #{self} не поддерживает валюту #{cur}" unless is_currency_supported? cur
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Gera
|
4
|
+
class RateSourceAuto < RateSource
|
5
|
+
def build_currency_rate(pair)
|
6
|
+
build_same(pair) ||
|
7
|
+
build_from_source(manual, pair) ||
|
8
|
+
build_from_source(cbr, pair) ||
|
9
|
+
build_from_source(exmo, pair) ||
|
10
|
+
build_cross(pair)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def build_from_source(source, pair, allow_inverse = true)
|
16
|
+
source.build_currency_rate pair, allow_inverse
|
17
|
+
end
|
18
|
+
|
19
|
+
def build_same(pair)
|
20
|
+
return unless pair.same?
|
21
|
+
|
22
|
+
CurrencyRate.new currency_pair: pair, rate_value: 1, mode: :same
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|