c80_shared 0.1.59 → 0.1.60

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/app/repositories/accounts/admin_account_repository.rb +35 -0
  3. data/app/repositories/accounts/central_agent_account_repository.rb +46 -0
  4. data/app/repositories/accounts/client_account_repository.rb +43 -0
  5. data/app/repositories/accounts/manager_account_repository.rb +35 -0
  6. data/app/repositories/accounts/manager_guest_account_repository.rb +35 -0
  7. data/app/repositories/accounts/moderator_account_repository.rb +35 -0
  8. data/app/schemas/base.rb +67 -0
  9. data/app/schemas/base_boat_schema.rb +235 -0
  10. data/app/schemas/central_agent/save_boat_schema.rb +57 -0
  11. data/app/services/abstract_prices_service.rb +70 -0
  12. data/app/services/boats/boat_prices_save_service.rb +81 -0
  13. data/app/services/boats/boat_sale_prices_save_service.rb +60 -0
  14. data/app/services/boats/dimension_service.rb +44 -0
  15. data/app/services/central_agent/save_boat_service.rb +111 -0
  16. data/app/services/lease/create_broadcast_inquiry_service.rb +62 -0
  17. data/app/services/lease/destroy_inquiry_service.rb +5 -0
  18. data/config/initializers/core_ext/active_record_log_subscriber.rb +60 -0
  19. data/config/initializers/core_ext/string.rb +62 -0
  20. data/lib/c80_shared/dry/errors.rb +77 -0
  21. data/lib/c80_shared/dry/rule.rb +69 -0
  22. data/lib/c80_shared/dry/rules/and.rb +11 -0
  23. data/lib/c80_shared/dry/rules/between.rb +20 -0
  24. data/lib/c80_shared/dry/rules/binary.rb +18 -0
  25. data/lib/c80_shared/dry/rules/collection.rb +16 -0
  26. data/lib/c80_shared/dry/rules/composite.rb +19 -0
  27. data/lib/c80_shared/dry/rules/equal.rb +18 -0
  28. data/lib/c80_shared/dry/rules/format.rb +18 -0
  29. data/lib/c80_shared/dry/rules/greater_than.rb +18 -0
  30. data/lib/c80_shared/dry/rules/greater_than_or_equal.rb +18 -0
  31. data/lib/c80_shared/dry/rules/included.rb +18 -0
  32. data/lib/c80_shared/dry/rules/length_between.rb +18 -0
  33. data/lib/c80_shared/dry/rules/length_equal.rb +18 -0
  34. data/lib/c80_shared/dry/rules/less_than.rb +18 -0
  35. data/lib/c80_shared/dry/rules/less_than_or_equal.rb +18 -0
  36. data/lib/c80_shared/dry/rules/max_length.rb +18 -0
  37. data/lib/c80_shared/dry/rules/min_length.rb +18 -0
  38. data/lib/c80_shared/dry/rules/not_equal.rb +18 -0
  39. data/lib/c80_shared/dry/rules/or.rb +15 -0
  40. data/lib/c80_shared/dry/rules/present.rb +21 -0
  41. data/lib/c80_shared/dry/rules/then.rb +13 -0
  42. data/lib/c80_shared/dry/rules_factory.rb +118 -0
  43. data/lib/c80_shared/dry/schema.rb +148 -0
  44. data/lib/c80_shared/version.rb +1 -1
  45. data/lib/c80_shared.rb +1 -1
  46. metadata +44 -3
  47. data/scratch_105___02.txt +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 993ce9456590de551437c7445c40261e3c33969538706dcfda35ff0cd432dae7
4
- data.tar.gz: 18ada8fe20f884a4c09754903e5d9fe7659ffa8f4331efbeaf6aa87e1628efc6
3
+ metadata.gz: 041f6a36b9dc94e33939939f808ffa80f7f6d69d34bcef15edc1eb49cbda7d81
4
+ data.tar.gz: 0c92d58789c52d96427c2b92911474f25d139e23f636faca8cb86ea59a9dbc00
5
5
  SHA512:
6
- metadata.gz: 8cfcf130e1d432127c312f57562ec0c3b759869fa24def12c122e51860816a212532d3928bcf2bb86b33951ee67cc9a1a4ff19373394391f26cc76e80be1a58d
7
- data.tar.gz: caf966a932a7ab15322fdcce8803fc4e32c13e73ea463784098132852ac0c640ff29f9e906ff37e3b6fbeeb0339b76ccae003d5c8106bcc7b8c79aa879989c43
6
+ metadata.gz: 698924b53ce5b331eb76555154bad6fe1015ceb33f87170de0b5249acce6c702de9a2efc1bcd146080d34e779734b3b444a59b9c3035eafdb1894a317e6a5c0b
7
+ data.tar.gz: 96996cb21f8db1cae96f2ecaedbd7d42165e0a9879253e34e15796ec88ddd4437d8d356bc495a77a7677c782dbf2b98c5a267933a29ae7b505f1fe9e07e6064d
@@ -0,0 +1,35 @@
1
+ module Accounts
2
+ class AdminAccountRepository
3
+
4
+ def create_account(user)
5
+ return unless user
6
+ return if user.accounts.admins.any?
7
+
8
+ account = ::Account.new(type_id: ::Dictionaries::AccountType::ADMIN)
9
+ admin = ::Accounts::Admin.new(account: account)
10
+
11
+ account.user = user
12
+ account.name = user.name.to_s
13
+ account.active = true
14
+
15
+ account.transaction do
16
+ account.save validate: false
17
+ admin.save validate: false
18
+ end
19
+ end
20
+
21
+ def destroy_account(user)
22
+ return unless user
23
+ return unless user.accounts.admins.any?
24
+
25
+ account = user.accounts.admins.first
26
+ admin = account.admin
27
+
28
+ ActiveRecord::Base.transaction do
29
+ admin.destroy
30
+ account.destroy
31
+ end
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,46 @@
1
+ module Accounts
2
+ class CentralAgentAccountRepository
3
+
4
+ # todo-my: перевести в self.
5
+ def create_account(user)
6
+ return unless user
7
+ return if user.accounts.central_agents.any?
8
+
9
+ account = ::Account.new(type_id: ::Dictionaries::AccountType::CENTRAL_AGENT)
10
+ central = ::Accounts::CentralAgent.new(account: account)
11
+
12
+ account.user = user
13
+ account.name = user.name.to_s
14
+ account.active = true
15
+ user.is_notify = true
16
+
17
+ ActiveRecord::Base.transaction do
18
+ account.save
19
+ central.save
20
+ user.save
21
+ end
22
+
23
+ central
24
+ end
25
+
26
+ # todo-my: перевести в self.
27
+ def destroy_account(user)
28
+ return unless user
29
+ return unless user.accounts.central_agents.any?
30
+
31
+ account = user.accounts.central_agents.first
32
+ central = account.central_agent
33
+
34
+ ActiveRecord::Base.transaction do
35
+ central.destroy
36
+ account.destroy
37
+ end
38
+ end
39
+
40
+ def self.fetch_or_create(user)
41
+ return unless user
42
+ return user.accounts.central_agents.first.central_agent if user.accounts.central_agents.any?
43
+ new.create_account(user)
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,43 @@
1
+ module Accounts
2
+ class ClientAccountRepository
3
+
4
+ def fetch_or_create(user)
5
+ return unless user
6
+ return user.accounts.clients.first.client if user.accounts.clients.any?
7
+ create_account(user)
8
+ end
9
+
10
+ def create_account(user)
11
+ return unless user
12
+ return if user.accounts.clients.any?
13
+
14
+ account = ::Account.new(type_id: ::Dictionaries::AccountType::CLIENT)
15
+ client = ::Accounts::Client.new(account: account)
16
+
17
+ account.user = user
18
+ account.name = user.name.to_s
19
+ account.active = true
20
+
21
+ account.transaction do
22
+ account.save validate: false
23
+ client.save validate: false
24
+ end
25
+
26
+ client
27
+ end
28
+
29
+ def destroy_account(user)
30
+ return unless user
31
+ return unless user.accounts.clients.any?
32
+
33
+ account = user.accounts.clients.first
34
+ client = account.client
35
+
36
+ ActiveRecord::Base.transaction do
37
+ client.destroy
38
+ account.destroy
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,35 @@
1
+ module Accounts
2
+ class ManagerAccountRepository
3
+
4
+ def create_account(user)
5
+ return unless user
6
+ return if user.accounts.managers.any?
7
+
8
+ account = ::Account.new(type_id: ::Dictionaries::AccountType::MANAGER)
9
+ manager = ::Accounts::Manager.new(account: account)
10
+
11
+ account.user = user
12
+ account.name = user.name.to_s
13
+ account.active = true
14
+
15
+ account.transaction do
16
+ account.save validate: false
17
+ manager.save validate: false
18
+ end
19
+ end
20
+
21
+ def destroy_account(user)
22
+ return unless user
23
+ return unless user.accounts.managers.any?
24
+
25
+ account = user.accounts.managers.first
26
+ manager = account.manager
27
+
28
+ ActiveRecord::Base.transaction do
29
+ manager.destroy
30
+ account.destroy
31
+ end
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,35 @@
1
+ module Accounts
2
+ class ManagerGuestAccountRepository
3
+
4
+ def create_account(user)
5
+ return unless user
6
+ return if user.accounts.managers_guests.any?
7
+
8
+ account = ::Account.new(type_id: ::Dictionaries::AccountType::MANAGER_GUEST)
9
+ manager = ::Accounts::ManagerGuest.new(account: account)
10
+
11
+ account.user = user
12
+ account.name = user.name.to_s
13
+ account.active = true
14
+
15
+ account.transaction do
16
+ account.save validate: false
17
+ manager.save validate: false
18
+ end
19
+ end
20
+
21
+ def destroy_account(user)
22
+ return unless user
23
+ return unless user.accounts.managers_guests.any?
24
+
25
+ account = user.accounts.managers_guests.first
26
+ manager = account.manager_guest
27
+
28
+ ActiveRecord::Base.transaction do
29
+ manager.destroy
30
+ account.destroy
31
+ end
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,35 @@
1
+ module Accounts
2
+ class ModeratorAccountRepository
3
+
4
+ def create_account(user)
5
+ return unless user
6
+ return if user.accounts.moderators.any?
7
+
8
+ account = ::Account.new(type_id: ::Dictionaries::AccountType::MODERATOR)
9
+ moderator = ::Accounts::Moderator.new(account: account)
10
+
11
+ account.user = user
12
+ account.name = user.name.to_s
13
+ account.active = true
14
+
15
+ account.transaction do
16
+ account.save validate: false
17
+ moderator.save validate: false
18
+ end
19
+ end
20
+
21
+ def destroy_account(user)
22
+ return unless user
23
+ return unless user.accounts.moderators.any?
24
+
25
+ account = user.accounts.moderators.first
26
+ moderator = account.moderator
27
+
28
+ ActiveRecord::Base.transaction do
29
+ moderator.destroy
30
+ account.destroy
31
+ end
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,67 @@
1
+ module Schemas
2
+ class Base
3
+
4
+ include Dry::Schema
5
+
6
+ def normalize_integer(value)
7
+ return nil if value.blank?
8
+ Integer(value.to_s.gsub(/\s/, '')) rescue value
9
+ end
10
+
11
+
12
+ def strip_string(value, empty_to_nil = true)
13
+ value = value.to_s.strip
14
+ value = nil if empty_to_nil && value.blank?
15
+ value
16
+ end
17
+
18
+
19
+ def to_date(value)
20
+ value.to_date rescue value
21
+ end
22
+
23
+
24
+ def clear_html(value)
25
+ Rails::Html::WhiteListSanitizer.new.sanitize(value)
26
+ end
27
+
28
+
29
+ def normalize_url(value)
30
+ return if value.blank?
31
+ value.to_s.strip.scan(/^https?:\/\//).present? ? value : sprintf('https://%s', value.to_s.strip)
32
+ end
33
+
34
+
35
+ def to_bool(value)
36
+ value.to_s.to_bool
37
+ end
38
+
39
+
40
+ def to_float(value)
41
+ return unless value.present?
42
+ BigDecimal.new(value.to_s.gsub(/\s/, '')) rescue value
43
+ end
44
+
45
+
46
+ def to_big_decimal(value)
47
+ return unless value.present?
48
+ BigDecimal.new(value.to_s.gsub(/\s/, '')) rescue value
49
+ end
50
+
51
+
52
+ def forced_array(value)
53
+ [value.present? ? value : nil].flatten.compact
54
+ end
55
+
56
+
57
+ def forced_hash(value)
58
+ value.blank? ? {} : value
59
+ end
60
+
61
+
62
+ def nullify_empty(value)
63
+ value.present? ? value : nil
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,235 @@
1
+ require_relative 'base'
2
+
3
+ module Schemas
4
+ class BaseBoatSchema < ::Schemas::Base
5
+ def schema
6
+ result = {
7
+ properties: {
8
+ id: {
9
+ type: %i[null number],
10
+ cast: ->(value) { normalize_integer(value) }
11
+ },
12
+ name: {
13
+ type: [:null, :string],
14
+ cast: ->(value) { clear_html(strip_string(value)) },
15
+ rule: ->(parents) { rule_name(parents) }
16
+ },
17
+ boat_type_id: {
18
+ enum: [nil, -1] + Dicts::BoatType::ALL.collect(&:id),
19
+ cast: ->(value) { normalize_integer(value) },
20
+ rule: ->(parents) { rule_boat_type_id(parents) }
21
+ },
22
+ boat_model: {
23
+ type: %i[null string],
24
+ cast: ->(value) { clear_html(strip_string(value)) }
25
+ },
26
+ builder: {
27
+ type: %i[null string],
28
+ cast: ->(value) { clear_html(strip_string(value)) }
29
+ },
30
+ length: {
31
+ type: :hash,
32
+ required: %i[value length_id],
33
+ properties: {
34
+ value: {
35
+ type: %i[null number string],
36
+ cast: ->(value) { to_float(value) }
37
+ },
38
+ length_id: {
39
+ enum: Dicts::Length.all.collect(&:id),
40
+ cast: ->(value) { normalize_integer(value) }
41
+ }
42
+ }
43
+ },
44
+ crew_total: {
45
+ type: %i[null number],
46
+ cast: ->(value) { normalize_integer(value) }
47
+ },
48
+ guest_cabins: {
49
+ type: %i[null number],
50
+ cast: ->(value) { normalize_integer(value) }
51
+ },
52
+ guests_total: {
53
+ type: %i[null number],
54
+ cast: ->(value) { normalize_integer(value) }
55
+ },
56
+ maximum_guests_during_cruise: {
57
+ type: %i[null number],
58
+ cast: ->(value) { normalize_integer(value) },
59
+ rule: ->(parents) { rule_maximum_guests_during_cruise(parents) }
60
+ },
61
+ boat_locations_attributes: {
62
+ type: %i[null array],
63
+ items: {
64
+ type: :hash,
65
+ required: %i[latitude longitude address is_main _destroy],
66
+ cast: ->(value) do
67
+ value[:latitude] = to_big_decimal value[:latitude]
68
+ value[:longitude] = to_big_decimal value[:longitude]
69
+ value[:address] = strip_string value[:address]
70
+ value[:is_main] = to_bool value[:is_main]
71
+ value[:_destroy] = to_bool value[:_destroy]
72
+
73
+ value[:latitude].nil? || value[:longitude].nil? || !value[:address].present? ? nil : value
74
+ end
75
+ },
76
+ cast: ->(value) { forced_array(value) }
77
+ }
78
+ }
79
+ }
80
+
81
+ result[:properties][:rent_prices] = {
82
+ type: [:null, :array], # это первая версия, где я пробую разобраться с массивом объектов (версия покруче тут - app/getboat/schemas/base_boat_schema.rb - с помощью :items)
83
+ cast: ->(value) do
84
+ value.inject([]) do |res, el|
85
+ el[:_delete] = to_bool el[:_delete]
86
+ el[:currency] = normalize_integer el[:currency]
87
+ el[:discount] = to_float el[:discount]
88
+ el[:duration] = to_float el[:duration]
89
+ el[:season] = normalize_integer el[:season]
90
+ el[:uom] = normalize_integer el[:uom]
91
+ el[:value] = normalize_integer(el[:value].is_a?(String) ? el[:value].split(/[, ]/).join : el[:value])
92
+ res << el
93
+ res
94
+ end
95
+ end
96
+ }
97
+
98
+ result[:properties][:sale_price] = {
99
+ type: [:null, :hash],
100
+ properties: {
101
+ currency_id: {
102
+ enum: Dicts::Currency.all.collect(&:id),
103
+ cast: ->(value) { normalize_integer(value) }
104
+ },
105
+ value: {
106
+ type: %i[number null string],
107
+ cast: ->(value) do
108
+ val = value.is_a?(String) ? value.split(/[, ]/).join : value
109
+ normalize_integer val
110
+ end
111
+ },
112
+ discount: {
113
+ type: %i[number null string],
114
+ cast: ->(value) { to_float(value) }
115
+ },
116
+ }
117
+ }
118
+
119
+ result[:properties][:boat_photos_attributes] = {
120
+ type: [:null, :hash],
121
+ cast: ->(value) { nullify_empty(value) },
122
+ rule: ->(parents) { rule_boat_photos_attributes(parents)}
123
+ }
124
+
125
+ result
126
+ end
127
+
128
+
129
+ def rule_name(parents)
130
+ messages = {
131
+ present: I18n.t('errors.boat.name.blank'),
132
+ length_between: I18n.t('errors.boat.name.length_invalid', min: 2, max: 255)
133
+ }
134
+ rule(:name, parents, messages) { present? & length_between?(2..255) }
135
+ end
136
+
137
+
138
+ def rule_boat_type_id(parents)
139
+ messages = {
140
+ present: I18n.t('errors.boat.boat_type_id.blank'),
141
+ gt: I18n.t('errors.boat.boat_type_id.blank')
142
+ }
143
+ rule(:boat_type_id, parents, messages) { present? & gt?(0) }
144
+ end
145
+
146
+
147
+ def rule_maximum_guests_during_cruise(parents)
148
+ messages = {
149
+ present: I18n.t('errors.boat.maximum_guests_during_cruise.blank'),
150
+ gt: I18n.t('errors.boat.maximum_guests_during_cruise.blank')
151
+ }
152
+ rule(:maximum_guests_during_cruise, parents, messages) { present? & gt?(0) }
153
+ end
154
+
155
+
156
+ def rule_boat_photos_attributes(parents)
157
+ messages = { present: I18n.t('errors.boat.boat_photos_attributes.blank') }
158
+ rule(:boat_photos_attributes, parents, messages) { present? }
159
+ end
160
+
161
+
162
+ def validate_location
163
+ unless boat_locations_attributes
164
+ errors.add :boat_locations, I18n.t('errors.boat.boat_locations.blank')
165
+ return
166
+ end
167
+
168
+ bls = boat_locations_attributes.compact.select { |loc| !loc[:_destroy] }
169
+ mbls = bls.select { |loc| loc[:is_main] }
170
+
171
+ if bls.size.zero?
172
+ errors.add :boat_locations, I18n.t('errors.boat.boat_locations.blank')
173
+ return
174
+ end
175
+
176
+ if bls.size > 5
177
+ errors.add :boat_locations, I18n.t('errors.boat.boat_locations.limit', max: 5)
178
+ return
179
+ end
180
+
181
+ if mbls.size == 0
182
+ errors.add :boat_locations, I18n.t('errors.boat.boat_locations.is_main')
183
+ return
184
+ end
185
+ end
186
+
187
+
188
+ def validate_length
189
+ errors.add(:length_value, I18n.t('errors.boat.length.blank')) unless length[:value]&.nonzero?
190
+ end
191
+
192
+
193
+ def validate_crew_total
194
+ errors.add(:crew_total, I18n.t('errors.boat.crew_total.blank')) unless crew_total.present?
195
+ end
196
+
197
+
198
+ def validate_guests_total
199
+ errors.add(:guests_total, I18n.t('errors.boat.guests_total.blank')) unless guests_total.present?
200
+ end
201
+
202
+
203
+ def validate_guest_cabins
204
+ errors.add(:guest_cabins, I18n.t('errors.boat.guest_cabins.blank')) unless guest_cabins.present?
205
+ end
206
+
207
+
208
+ def validate_prices_and_rent_prices
209
+ rent_prices_present = rent_prices.present? && rent_prices.count { |price| price[:_delete] } < rent_prices.count
210
+ sale_price_present = sale_price.present? && sale_price[:value]&.>(0)
211
+ return if rent_prices_present && sale_price_present
212
+
213
+ if !(rent_prices_present || sale_price_present)
214
+ errors.add :rent_prices, I18n.t('errors.boat.prices.any')
215
+ errors.add :sale_price, I18n.t('errors.boat.prices.any')
216
+ end
217
+ end
218
+
219
+
220
+ def validate_rent_prices
221
+ return unless rent_prices.present?
222
+
223
+ rent_prices.each do |price|
224
+ if price[:value].nil? || price[:value].zero?
225
+ errors.add :rent_prices, I18n.t('errors.boat.rent_prices.invalid')
226
+ break
227
+ end
228
+ if price[:duration].nil? || price[:duration].zero?
229
+ errors.add :rent_prices, I18n.t('errors.boat.rent_prices.invalid_duration')
230
+ break
231
+ end
232
+ end
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,57 @@
1
+ require_relative '../base_boat_schema'
2
+
3
+ module Schemas
4
+ module CentralAgent
5
+ class SaveBoatSchema < Schemas::BaseBoatSchema
6
+ def schema
7
+ boat_schema = super
8
+ boat_schema[:required] = %i[
9
+ name
10
+ boat_type_id
11
+ ]
12
+
13
+ boat_schema[:properties][:boat_photos_attributes] = {
14
+ type: [:null, :hash],
15
+ cast: ->(value) { nullify_empty(value) }
16
+ }
17
+
18
+ # второй вариант реализации property boat_length, который присутствует в базовой схеме
19
+ %i[boat_length_metrics boat_beam_metrics boat_draft_metrics].product([:meters, :ft]).map { |f,d| '%s_%s' % [f,d] }.each do |prop|
20
+ boat_schema[:properties][prop.to_sym] = {
21
+ type: %i[null string number],
22
+ cast: ->(value) do
23
+ val = value.is_a?(String) ? value.split(/[, ]/).join : value
24
+ to_float val
25
+ end
26
+ }
27
+ end
28
+
29
+ boat_schema
30
+ end
31
+
32
+
33
+ def validate_additional
34
+ validate_boat_photos
35
+ validate_prices_and_rent_prices
36
+ validate_rent_prices
37
+ validate_length
38
+ validate_location
39
+ validate_guests_total
40
+ # validate_guest_cabins
41
+ validate_crew_total
42
+ end
43
+
44
+ def validate_boat_photos
45
+ errors.add :boat_photos, I18n.t('errors.boat.boat_photos_attributes.blank') unless boat_photos_attributes.present?
46
+ end
47
+
48
+
49
+ def validate_length
50
+ val = boat_length_metrics_meters || boat_length_metrics_ft
51
+ unless val.present? && val > 0 && val < 1000
52
+ errors.add(:boat_length_metrics, I18n.t('errors.messages.invalid'))
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,70 @@
1
+ class AbstractPricesService
2
+
3
+ attr_reader :built_prices
4
+
5
+ def initialize(all_currencies = ::Dicts::Currency::ALL2) # all_currencies - список валют, в которых надо сохранить цены
6
+ @all_currencies = all_currencies
7
+ _reset_ivars
8
+ end
9
+
10
+ private
11
+
12
+ def _model
13
+ raise NotImplementedError
14
+ end
15
+
16
+ def _fields_for_create
17
+ raise NotImplementedError
18
+ end
19
+
20
+ def _save(prices) # помещаем в базу всё одним запросом
21
+ filtered = prices.select { |el| !el[:_delete] && el[:value].to_i != 0 } # игнорируя цены, которые были помечены "к удалению" или те, у которых значение 0 (0 можно подавать, если хотим "удалить" цену продажи)
22
+ return if filtered.size.zero?
23
+
24
+ values = filtered.map do |p|
25
+ _fields_for_create.map do |field|
26
+ p[field.to_sym]
27
+ end.compact * ','
28
+ end * '),('
29
+ values = '(%s)' % values
30
+ sql = 'INSERT INTO %s(%s) VALUES %s' % [_model.table_name, _fields_for_create * ',', values]
31
+ ActiveRecord::Base.connection.execute sql
32
+
33
+ filtered
34
+ end
35
+
36
+ # из базы удаляем все записи, принадлежащие данной лодке
37
+ # т.к. считаем, что с формы приходит полная картина по ценам
38
+ # кроме того, юзер может просто изменить, например, период в уже
39
+ # существующей строке с ценами, которую он видит на экране
40
+ def _delete_existing_records(boat_id)
41
+ sql = 'DELETE FROM %s WHERE boat_id = %s' % [_model.table_name, boat_id]
42
+ ActiveRecord::Base.connection.execute sql
43
+ end
44
+
45
+ def _build_other(price) # отталкиваясь от валюты входных данных, рассчитываем "те же" цены в других валютах
46
+ return if price[:_delete] || price[:value].to_i == 0 # игнорируя цены, которые были помечены "к удалению" или те, у которых значение 0 (0 можно подавать, если хотим "удалить" цену продажи)
47
+
48
+ incoming_curr = ::Dicts::Currency.find(price[:currency_id])
49
+ currs_to_build = @all_currencies - [incoming_curr]
50
+ rates = Currency.fresh(incoming_curr.index).rates
51
+ rates = JSON.parse(rates)['rates']
52
+
53
+ currs_to_build.each do |curr|
54
+ rate = rates[curr.index]
55
+ res = price.clone
56
+ res[:currency_id] = curr.id
57
+ res[:value] = res[:value].to_f * rate
58
+ res[:is_orig] = false
59
+ @built_prices << res
60
+ end
61
+ end
62
+
63
+ def _delete_bad_values(prices)
64
+ prices.delete_if { |price| price[:value].nil? || price[:value].to_f.zero? }
65
+ end
66
+
67
+ def _reset_ivars
68
+ @built_prices = []
69
+ end
70
+ end