c80_shared 0.1.67 → 0.1.68

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/app/getboat/schemas/base.rb +67 -0
  3. data/app/getboat/schemas/base_boat_schema.rb +233 -0
  4. data/app/getboat/schemas/central_agent/save_boat_schema.rb +55 -0
  5. data/app/getboat/schemas/site/lease/create_personal_inquiry_schema.rb +187 -0
  6. data/app/repositories/accounts/central_agent_account_repository.rb +46 -0
  7. data/app/repositories/accounts/client_account_repository.rb +43 -0
  8. data/app/services/abstract_prices_service.rb +70 -0
  9. data/app/services/boats/boat_prices_save_service.rb +79 -0
  10. data/app/services/boats/boat_sale_prices_save_service.rb +58 -0
  11. data/app/services/central_agent/save_boat_service.rb +117 -0
  12. data/app/services/dimension_service.rb +42 -0
  13. data/app/services/lease/create_broadcast_inquiry_service.rb +68 -0
  14. data/config/initializers/core_ext/string.rb +62 -0
  15. data/lib/c80_shared/version.rb +1 -1
  16. data/lib/c80_shared.rb +27 -0
  17. data/lib/dry/errors.rb +77 -0
  18. data/lib/dry/rule.rb +69 -0
  19. data/lib/dry/rules/and.rb +11 -0
  20. data/lib/dry/rules/between.rb +18 -0
  21. data/lib/dry/rules/binary.rb +16 -0
  22. data/lib/dry/rules/collection.rb +16 -0
  23. data/lib/dry/rules/composite.rb +19 -0
  24. data/lib/dry/rules/equal.rb +18 -0
  25. data/lib/dry/rules/format.rb +18 -0
  26. data/lib/dry/rules/greater_than.rb +18 -0
  27. data/lib/dry/rules/greater_than_or_equal.rb +18 -0
  28. data/lib/dry/rules/included.rb +18 -0
  29. data/lib/dry/rules/length_between.rb +18 -0
  30. data/lib/dry/rules/length_equal.rb +18 -0
  31. data/lib/dry/rules/less_than.rb +18 -0
  32. data/lib/dry/rules/less_than_or_equal.rb +18 -0
  33. data/lib/dry/rules/max_length.rb +18 -0
  34. data/lib/dry/rules/min_length.rb +18 -0
  35. data/lib/dry/rules/not_equal.rb +18 -0
  36. data/lib/dry/rules/or.rb +13 -0
  37. data/lib/dry/rules/present.rb +21 -0
  38. data/lib/dry/rules/then.rb +13 -0
  39. data/lib/dry/rules_factory.rb +118 -0
  40. data/lib/dry/schema.rb +148 -0
  41. metadata +39 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f4eda191e428d7623037ddd116757fac5e4439d92b3a74760ab9812cc77a835
4
- data.tar.gz: a11b13381e2d240a0010ef71501dc041cd87df86d7b85299213019c4f0c835fd
3
+ metadata.gz: 3667af28c965c19676a043379c8a15b8520b3ce1e9e83aa4ef6cbbbfb70f0249
4
+ data.tar.gz: 0a277eb1c4478fe49c9128e3a7b83e256859905adc07b2d9a6fff7f0b20712c2
5
5
  SHA512:
6
- metadata.gz: 3ad5054bbe6a6aafc32906344c86ad12934e54f8ac6bee15048aa030251e88e165fd48c5a87939c9ec2c998b170068c97eff0f926e0d1cbad70180aea26fc480
7
- data.tar.gz: 1c919e2971c134193d2bd196439181f881fc8f361fd9ebf18600feb0e81c6eb1ee512ba788f8f198a11f5709dfb9bacde4b6ac8520f010a3f0447550a838eb42
6
+ metadata.gz: cdc3c04bf31a5f23c181f78ec8127b502f602e326515415833c2351b6379d57f17a37df9f7ac83929951434712c2dd8be49f2a0710dda2a49fc81802438776d4
7
+ data.tar.gz: 9b9fad0a5d7a9a6518f0577397652e8430616e8c3e4f80e4828efd7d51aee560fa25afb05e89a6619caa294ef4701ae81286e4ee76fc3693eaf3c5dc3002e293
@@ -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,233 @@
1
+ module Schemas
2
+ class BaseBoatSchema < ::Schemas::Base
3
+ def schema
4
+ result = {
5
+ properties: {
6
+ id: {
7
+ type: %i[null number],
8
+ cast: ->(value) { normalize_integer(value) }
9
+ },
10
+ name: {
11
+ type: [:null, :string],
12
+ cast: ->(value) { clear_html(strip_string(value)) },
13
+ rule: ->(parents) { rule_name(parents) }
14
+ },
15
+ boat_type_id: {
16
+ enum: [nil, -1] + Dicts::BoatType::ALL.collect(&:id),
17
+ cast: ->(value) { normalize_integer(value) },
18
+ rule: ->(parents) { rule_boat_type_id(parents) }
19
+ },
20
+ boat_model: {
21
+ type: %i[null string],
22
+ cast: ->(value) { clear_html(strip_string(value)) }
23
+ },
24
+ builder: {
25
+ type: %i[null string],
26
+ cast: ->(value) { clear_html(strip_string(value)) }
27
+ },
28
+ length: {
29
+ type: :hash,
30
+ required: %i[value length_id],
31
+ properties: {
32
+ value: {
33
+ type: %i[null number string],
34
+ cast: ->(value) { to_float(value) }
35
+ },
36
+ length_id: {
37
+ enum: Dicts::Length.all.collect(&:id),
38
+ cast: ->(value) { normalize_integer(value) }
39
+ }
40
+ }
41
+ },
42
+ crew_total: {
43
+ type: %i[null number],
44
+ cast: ->(value) { normalize_integer(value) }
45
+ },
46
+ guest_cabins: {
47
+ type: %i[null number],
48
+ cast: ->(value) { normalize_integer(value) }
49
+ },
50
+ guests_total: {
51
+ type: %i[null number],
52
+ cast: ->(value) { normalize_integer(value) }
53
+ },
54
+ maximum_guests_during_cruise: {
55
+ type: %i[null number],
56
+ cast: ->(value) { normalize_integer(value) },
57
+ rule: ->(parents) { rule_maximum_guests_during_cruise(parents) }
58
+ },
59
+ boat_locations_attributes: {
60
+ type: %i[null array],
61
+ items: {
62
+ type: :hash,
63
+ required: %i[latitude longitude address is_main _destroy],
64
+ cast: ->(value) do
65
+ value[:latitude] = to_big_decimal value[:latitude]
66
+ value[:longitude] = to_big_decimal value[:longitude]
67
+ value[:address] = strip_string value[:address]
68
+ value[:is_main] = to_bool value[:is_main]
69
+ value[:_destroy] = to_bool value[:_destroy]
70
+
71
+ value[:latitude].nil? || value[:longitude].nil? || !value[:address].present? ? nil : value
72
+ end
73
+ },
74
+ cast: ->(value) { forced_array(value) }
75
+ }
76
+ }
77
+ }
78
+
79
+ result[:properties][:rent_prices] = {
80
+ type: [:null, :array], # это первая версия, где я пробую разобраться с массивом объектов (версия покруче тут - app/getboat/schemas/base_boat_schema.rb - с помощью :items)
81
+ cast: ->(value) do
82
+ value.inject([]) do |res, el|
83
+ el[:_delete] = to_bool el[:_delete]
84
+ el[:currency] = normalize_integer el[:currency]
85
+ el[:discount] = to_float el[:discount]
86
+ el[:duration] = to_float el[:duration]
87
+ el[:season] = normalize_integer el[:season]
88
+ el[:uom] = normalize_integer el[:uom]
89
+ el[:value] = normalize_integer(el[:value].is_a?(String) ? el[:value].split(/[, ]/).join : el[:value])
90
+ res << el
91
+ res
92
+ end
93
+ end
94
+ }
95
+
96
+ result[:properties][:sale_price] = {
97
+ type: [:null, :hash],
98
+ properties: {
99
+ currency_id: {
100
+ enum: Dicts::Currency.all.collect(&:id),
101
+ cast: ->(value) { normalize_integer(value) }
102
+ },
103
+ value: {
104
+ type: %i[number null string],
105
+ cast: ->(value) do
106
+ val = value.is_a?(String) ? value.split(/[, ]/).join : value
107
+ normalize_integer val
108
+ end
109
+ },
110
+ discount: {
111
+ type: %i[number null string],
112
+ cast: ->(value) { to_float(value) }
113
+ },
114
+ }
115
+ }
116
+
117
+ result[:properties][:boat_photos_attributes] = {
118
+ type: [:null, :hash],
119
+ cast: ->(value) { nullify_empty(value) },
120
+ rule: ->(parents) { rule_boat_photos_attributes(parents)}
121
+ }
122
+
123
+ result
124
+ end
125
+
126
+
127
+ def rule_name(parents)
128
+ messages = {
129
+ present: I18n.t('errors.boat.name.blank'),
130
+ length_between: I18n.t('errors.boat.name.length_invalid', min: 2, max: 255)
131
+ }
132
+ rule(:name, parents, messages) { present? & length_between?(2..255) }
133
+ end
134
+
135
+
136
+ def rule_boat_type_id(parents)
137
+ messages = {
138
+ present: I18n.t('errors.boat.boat_type_id.blank'),
139
+ gt: I18n.t('errors.boat.boat_type_id.blank')
140
+ }
141
+ rule(:boat_type_id, parents, messages) { present? & gt?(0) }
142
+ end
143
+
144
+
145
+ def rule_maximum_guests_during_cruise(parents)
146
+ messages = {
147
+ present: I18n.t('errors.boat.maximum_guests_during_cruise.blank'),
148
+ gt: I18n.t('errors.boat.maximum_guests_during_cruise.blank')
149
+ }
150
+ rule(:maximum_guests_during_cruise, parents, messages) { present? & gt?(0) }
151
+ end
152
+
153
+
154
+ def rule_boat_photos_attributes(parents)
155
+ messages = { present: I18n.t('errors.boat.boat_photos_attributes.blank') }
156
+ rule(:boat_photos_attributes, parents, messages) { present? }
157
+ end
158
+
159
+
160
+ def validate_location
161
+ unless boat_locations_attributes
162
+ errors.add :boat_locations, I18n.t('errors.boat.boat_locations.blank')
163
+ return
164
+ end
165
+
166
+ bls = boat_locations_attributes.compact.select { |loc| !loc[:_destroy] }
167
+ mbls = bls.select { |loc| loc[:is_main] }
168
+
169
+ if bls.size.zero?
170
+ errors.add :boat_locations, I18n.t('errors.boat.boat_locations.blank')
171
+ return
172
+ end
173
+
174
+ if bls.size > 5
175
+ errors.add :boat_locations, I18n.t('errors.boat.boat_locations.limit', max: 5)
176
+ return
177
+ end
178
+
179
+ if mbls.size == 0
180
+ errors.add :boat_locations, I18n.t('errors.boat.boat_locations.is_main')
181
+ return
182
+ end
183
+ end
184
+
185
+
186
+ def validate_length
187
+ errors.add(:length_value, I18n.t('errors.boat.length.blank')) unless length[:value]&.nonzero?
188
+ end
189
+
190
+
191
+ def validate_crew_total
192
+ errors.add(:crew_total, I18n.t('errors.boat.crew_total.blank')) unless crew_total.present?
193
+ end
194
+
195
+
196
+ def validate_guests_total
197
+ errors.add(:guests_total, I18n.t('errors.boat.guests_total.blank')) unless guests_total.present?
198
+ end
199
+
200
+
201
+ def validate_guest_cabins
202
+ errors.add(:guest_cabins, I18n.t('errors.boat.guest_cabins.blank')) unless guest_cabins.present?
203
+ end
204
+
205
+
206
+ def validate_prices_and_rent_prices
207
+ rent_prices_present = rent_prices.present? && rent_prices.count { |price| price[:_delete] } < rent_prices.count
208
+ sale_price_present = sale_price.present? && sale_price[:value]&.>(0)
209
+ return if rent_prices_present && sale_price_present
210
+
211
+ if !(rent_prices_present || sale_price_present)
212
+ errors.add :rent_prices, I18n.t('errors.boat.prices.any')
213
+ errors.add :sale_price, I18n.t('errors.boat.prices.any')
214
+ end
215
+ end
216
+
217
+
218
+ def validate_rent_prices
219
+ return unless rent_prices.present?
220
+
221
+ rent_prices.each do |price|
222
+ if price[:value].nil? || price[:value].zero?
223
+ errors.add :rent_prices, I18n.t('errors.boat.rent_prices.invalid')
224
+ break
225
+ end
226
+ if price[:duration].nil? || price[:duration].zero?
227
+ errors.add :rent_prices, I18n.t('errors.boat.rent_prices.invalid_duration')
228
+ break
229
+ end
230
+ end
231
+ end
232
+ end
233
+ end
@@ -0,0 +1,55 @@
1
+ module Schemas
2
+ module CentralAgent
3
+ class SaveBoatSchema < Schemas::BaseBoatSchema
4
+ def schema
5
+ boat_schema = super
6
+ boat_schema[:required] = %i[
7
+ name
8
+ boat_type_id
9
+ ]
10
+
11
+ boat_schema[:properties][:boat_photos_attributes] = {
12
+ type: [:null, :hash],
13
+ cast: ->(value) { nullify_empty(value) }
14
+ }
15
+
16
+ # второй вариант реализации property boat_length, который присутствует в базовой схеме
17
+ %i[boat_length_metrics boat_beam_metrics boat_draft_metrics].product([:meters, :ft]).map { |f,d| '%s_%s' % [f,d] }.each do |prop|
18
+ boat_schema[:properties][prop.to_sym] = {
19
+ type: %i[null string number],
20
+ cast: ->(value) do
21
+ val = value.is_a?(String) ? value.split(/[, ]/).join : value
22
+ to_float val
23
+ end
24
+ }
25
+ end
26
+
27
+ boat_schema
28
+ end
29
+
30
+
31
+ def validate_additional
32
+ validate_boat_photos
33
+ validate_prices_and_rent_prices
34
+ validate_rent_prices
35
+ validate_length
36
+ validate_location
37
+ validate_guests_total
38
+ # validate_guest_cabins
39
+ validate_crew_total
40
+ end
41
+
42
+ def validate_boat_photos
43
+ errors.add :boat_photos, I18n.t('errors.boat.boat_photos_attributes.blank') unless boat_photos_attributes.present?
44
+ end
45
+
46
+
47
+ def validate_length
48
+ val = boat_length_metrics_meters || boat_length_metrics_ft
49
+ unless val.present? && val > 0 && val < 1000
50
+ errors.add(:boat_length_metrics, I18n.t('errors.messages.invalid'))
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,187 @@
1
+ module Schemas
2
+ module Site
3
+ module Lease
4
+ class CreatePersonalInquirySchema < ::Schemas::Base
5
+ def schema
6
+ result = {
7
+ required: %i[
8
+ id
9
+ from
10
+ until
11
+ guests
12
+ kids
13
+ is_skippered
14
+ comments
15
+ email
16
+ name
17
+ _known_is_skippered
18
+ _known_maximum_guests_during_cruise
19
+ ],
20
+ properties: {
21
+ id: {
22
+ type: %i[null number],
23
+ cast: ->(value) { normalize_integer(value) }
24
+ },
25
+ from: {
26
+ type: %i[null date],
27
+ cast: ->(value) { to_date(value) }
28
+ },
29
+ until: {
30
+ type: %i[null date],
31
+ cast: ->(value) { to_date(value) }
32
+ },
33
+ guests: {
34
+ type: %i[null number],
35
+ cast: ->(value) { normalize_integer(value) },
36
+ rule: ->(parents) { rule_guests(parents) }
37
+ },
38
+ kids: {
39
+ type: %i[null number],
40
+ cast: ->(value) { normalize_integer(value) },
41
+ rule: ->(parents) { rule_kids(parents) }
42
+ },
43
+ is_skippered: {
44
+ type: :boolean,
45
+ cast: ->(value) { to_bool(value) }
46
+ },
47
+ watersports: {
48
+ type: :boolean,
49
+ cast: ->(value) { to_bool(value) }
50
+ },
51
+ transfer: {
52
+ type: :boolean,
53
+ cast: ->(value) { to_bool(value) }
54
+ },
55
+ comments: {
56
+ type: :string,
57
+ cast: ->(value) { clear_html(value) },
58
+ rule: ->(parents) { rule_comments(parents) }
59
+ },
60
+ email: {
61
+ type: %i[null string],
62
+ cast: ->(value) { strip_string(value) },
63
+ rule: ->(parents) { rule_email(parents) }
64
+ },
65
+ name: {
66
+ type: %i[null string],
67
+ cast: ->(value) { strip_string(value) },
68
+ rule: ->(parents) { rule_name(parents) }
69
+ },
70
+ phone: {
71
+ type: %i[null string],
72
+ cast: ->(value) { strip_string(value) },
73
+ rule: ->(parents) { rule_phone(parents) }
74
+ },
75
+ password: {
76
+ type: %i[null string]
77
+ },
78
+ _known_is_skippered: {
79
+ type: %i[string],
80
+ cast: ->(value) { strip_string(value) }
81
+ },
82
+ _known_maximum_guests_during_cruise: {
83
+ type: :number,
84
+ cast: ->(value) { normalize_integer(value) }
85
+ }
86
+ }
87
+ }
88
+
89
+ result
90
+ end
91
+
92
+ def validate_additional
93
+ validate_dates
94
+ validate_is_skippered
95
+ validate_guests_total
96
+ validate_kids_guests
97
+ end
98
+
99
+ def validate_dates
100
+ unless from
101
+ errors.add :from, I18n.t('errors.rent_form.from_until')
102
+ return
103
+ end
104
+
105
+ unless send(:until)
106
+ errors.add :until, I18n.t('errors.rent_form.from_until')
107
+ return
108
+ end
109
+ end
110
+
111
+ def validate_is_skippered
112
+ return if _known_is_skippered == 'null' # если 'null' - значит не указано, значит можно всё
113
+ return if to_bool(_known_is_skippered) == is_skippered
114
+
115
+ errors.add :is_skippered, 'It is impossible'
116
+ end
117
+
118
+ # если юзер указал детей, больше и равно чем guests - сообщим ему об этом, заявку не создаём
119
+ def validate_kids_guests
120
+ return if kids.nil?
121
+ return if guests > kids
122
+ return if errors.messages[:guests].present?
123
+
124
+ errors.add :kids, I18n.t('errors.messages.too_much_and', max: guests, and: I18n.t('activemodel.attributes.rent_form.guests'))
125
+ end
126
+
127
+ # если слишком много людей хотят вместить на лодку
128
+ def validate_guests_total
129
+ return if guests.nil?
130
+ return if _known_maximum_guests_during_cruise >= guests
131
+
132
+ errors.add :guests, I18n.t('errors.messages.too_much_eq_and', max: _known_maximum_guests_during_cruise, and: I18n.t('attributes.maximum_capacity_tip'))
133
+ end
134
+
135
+ def rule_guests(parents)
136
+ messages = {
137
+ present: I18n.t('errors.messages.too_low', min: 0),
138
+ gt: I18n.t('errors.messages.too_low', min: 0)
139
+ }
140
+ rule(:guests, parents, messages) { present? & gt?(0) }
141
+ end
142
+
143
+ def rule_kids(parents)
144
+ return if kids.nil?
145
+
146
+ messages = {
147
+ gt_eq: I18n.t('errors.messages.too_low_eq', min: 0)
148
+ }
149
+ rule(:kids, parents, messages) { gt_eq?(0) }
150
+ end
151
+
152
+ def rule_comments(parents)
153
+ return unless comments.present?
154
+
155
+ messages = {
156
+ length_between: I18n.t('errors.messages.length_invalid', min: 5, max: 2048)
157
+ }
158
+ rule(:comments, parents, messages) { length_between?(5..2048) }
159
+ end
160
+
161
+ def rule_name(parents)
162
+ messages = {
163
+ present: I18n.t('errors.messages.invalid'),
164
+ max_length: I18n.t('errors.messages.length_invalid', min: ::ValidationConstraints::USER_NAME_MIN_LENGTH, max: ::ValidationConstraints::USER_NAME_MAX_LENGTH)
165
+ }
166
+ rule(:name, parents, messages) { present? & max_length?(::ValidationConstraints::USER_NAME_MAX_LENGTH) }
167
+ end
168
+
169
+ def rule_phone(parents)
170
+ messages = {
171
+ present: I18n.t('errors.messages.invalid')
172
+ }
173
+ rule(:phone, parents, messages) { present? }
174
+ end
175
+
176
+ def rule_email(parents)
177
+ messages = {
178
+ present: I18n.t('errors.messages.invalid'),
179
+ max_length: I18n.t('errors.messages.length_invalid', min:0, max:100),
180
+ email_mx: I18n.t('errors.messages.invalid')
181
+ }
182
+ rule(:email, parents, messages) { present? & max_length?(100) & format?(ValidationConstraints::EMAIL_REGEX) }
183
+ end
184
+ end
185
+ end
186
+ end
187
+ 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