c80_shared 0.1.67 → 0.1.68

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 (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