c80_shared 0.1.59 → 0.1.60
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.
- checksums.yaml +4 -4
- data/app/repositories/accounts/admin_account_repository.rb +35 -0
- data/app/repositories/accounts/central_agent_account_repository.rb +46 -0
- data/app/repositories/accounts/client_account_repository.rb +43 -0
- data/app/repositories/accounts/manager_account_repository.rb +35 -0
- data/app/repositories/accounts/manager_guest_account_repository.rb +35 -0
- data/app/repositories/accounts/moderator_account_repository.rb +35 -0
- data/app/schemas/base.rb +67 -0
- data/app/schemas/base_boat_schema.rb +235 -0
- data/app/schemas/central_agent/save_boat_schema.rb +57 -0
- data/app/services/abstract_prices_service.rb +70 -0
- data/app/services/boats/boat_prices_save_service.rb +81 -0
- data/app/services/boats/boat_sale_prices_save_service.rb +60 -0
- data/app/services/boats/dimension_service.rb +44 -0
- data/app/services/central_agent/save_boat_service.rb +111 -0
- data/app/services/lease/create_broadcast_inquiry_service.rb +62 -0
- data/app/services/lease/destroy_inquiry_service.rb +5 -0
- data/config/initializers/core_ext/active_record_log_subscriber.rb +60 -0
- data/config/initializers/core_ext/string.rb +62 -0
- data/lib/c80_shared/dry/errors.rb +77 -0
- data/lib/c80_shared/dry/rule.rb +69 -0
- data/lib/c80_shared/dry/rules/and.rb +11 -0
- data/lib/c80_shared/dry/rules/between.rb +20 -0
- data/lib/c80_shared/dry/rules/binary.rb +18 -0
- data/lib/c80_shared/dry/rules/collection.rb +16 -0
- data/lib/c80_shared/dry/rules/composite.rb +19 -0
- data/lib/c80_shared/dry/rules/equal.rb +18 -0
- data/lib/c80_shared/dry/rules/format.rb +18 -0
- data/lib/c80_shared/dry/rules/greater_than.rb +18 -0
- data/lib/c80_shared/dry/rules/greater_than_or_equal.rb +18 -0
- data/lib/c80_shared/dry/rules/included.rb +18 -0
- data/lib/c80_shared/dry/rules/length_between.rb +18 -0
- data/lib/c80_shared/dry/rules/length_equal.rb +18 -0
- data/lib/c80_shared/dry/rules/less_than.rb +18 -0
- data/lib/c80_shared/dry/rules/less_than_or_equal.rb +18 -0
- data/lib/c80_shared/dry/rules/max_length.rb +18 -0
- data/lib/c80_shared/dry/rules/min_length.rb +18 -0
- data/lib/c80_shared/dry/rules/not_equal.rb +18 -0
- data/lib/c80_shared/dry/rules/or.rb +15 -0
- data/lib/c80_shared/dry/rules/present.rb +21 -0
- data/lib/c80_shared/dry/rules/then.rb +13 -0
- data/lib/c80_shared/dry/rules_factory.rb +118 -0
- data/lib/c80_shared/dry/schema.rb +148 -0
- data/lib/c80_shared/version.rb +1 -1
- data/lib/c80_shared.rb +1 -1
- metadata +44 -3
- data/scratch_105___02.txt +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 041f6a36b9dc94e33939939f808ffa80f7f6d69d34bcef15edc1eb49cbda7d81
|
4
|
+
data.tar.gz: 0c92d58789c52d96427c2b92911474f25d139e23f636faca8cb86ea59a9dbc00
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/app/schemas/base.rb
ADDED
@@ -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
|