cats_core 1.4.1 → 1.4.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/cats/core/commodities_controller.rb +1 -1
- data/app/controllers/cats/core/commodity_categories_controller.rb +5 -0
- data/app/controllers/cats/core/dispatch_plan_items_controller.rb +1 -1
- data/app/controllers/cats/core/dispatch_plans_controller.rb +1 -1
- data/app/controllers/cats/core/dispatch_transactions_controller.rb +1 -1
- data/app/controllers/cats/core/dispatches_controller.rb +1 -1
- data/app/controllers/cats/core/monthly_plans_controller.rb +3 -5
- data/app/controllers/cats/core/stacks_controller.rb +2 -2
- data/app/controllers/cats/core/unit_conversions_controller.rb +13 -0
- data/app/models/cats/core/commodity.rb +1 -22
- data/app/models/cats/core/dispatch_plan.rb +2 -4
- data/app/models/cats/core/dispatch_plan_item.rb +3 -1
- data/app/models/cats/core/gift_certificate.rb +5 -2
- data/app/models/cats/core/location.rb +3 -1
- data/app/models/cats/core/monthly_plan.rb +24 -2
- data/app/models/cats/core/route.rb +9 -1
- data/app/models/cats/core/stack.rb +31 -4
- data/app/models/cats/core/transport_bid.rb +5 -1
- data/app/models/cats/core/transport_bid_item.rb +2 -0
- data/app/models/cats/core/transport_offer.rb +1 -0
- data/app/models/cats/core/unit_conversion.rb +25 -0
- data/app/models/concerns/cats/core/dispatchable.rb +2 -2
- data/app/notifications/cats/core/allocation_notification.rb +2 -2
- data/app/notifications/cats/core/dispatch_notification.rb +1 -1
- data/app/serializers/cats/core/commodity_serializer.rb +2 -2
- data/app/serializers/cats/core/dispatch_plan_serializer.rb +1 -2
- data/app/serializers/cats/core/unit_conversion_serializer.rb +7 -0
- data/app/services/cats/core/stack_service.rb +21 -33
- data/config/routes.rb +3 -1
- data/db/migrate/20210717032602_create_cats_core_gift_certificates.rb +6 -1
- data/db/migrate/20210717033223_create_cats_core_commodities.rb +1 -0
- data/db/migrate/20210718043328_create_cats_core_dispatch_plans.rb +0 -5
- data/db/migrate/20210718043401_create_cats_core_dispatch_plan_items.rb +4 -0
- data/db/migrate/20211215121151_create_cats_core_transport_bids.rb +3 -2
- data/db/migrate/20211215124452_create_cats_core_transport_bid_items.rb +4 -0
- data/db/migrate/20211229160125_create_cats_core_transport_offers.rb +2 -0
- data/db/migrate/20220416143416_create_cats_core_unit_conversions.rb +19 -0
- data/lib/cats/core/version.rb +1 -1
- data/spec/factories/cats/core/commodities.rb +1 -0
- data/spec/factories/cats/core/dispatch_plan_items.rb +1 -0
- data/spec/factories/cats/core/dispatch_plans.rb +14 -2
- data/spec/factories/cats/core/gift_certificates.rb +2 -0
- data/spec/factories/cats/core/stacking_rules.rb +3 -3
- data/spec/factories/cats/core/transport_bid_items.rb +1 -0
- data/spec/factories/cats/core/transport_bids.rb +3 -2
- data/spec/factories/cats/core/unit_conversions.rb +7 -0
- metadata +8 -9
- data/app/models/cats/core/allocation.rb +0 -78
- data/app/models/cats/core/allocation_item.rb +0 -42
- data/db/migrate/20210718042823_create_cats_core_allocations.rb +0 -25
- data/db/migrate/20210718043204_create_cats_core_allocation_items.rb +0 -19
- data/spec/factories/cats/core/allocation_items.rb +0 -9
- data/spec/factories/cats/core/allocations.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 05ec37047a728927e68df2e0a0ae34dd16cca869cfe658314ea5fb0738ae894b
|
4
|
+
data.tar.gz: 272f1c6cb33e96a8407cab42c3b9bd8b01540156feee9bf4d6012b5b97600b52
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 19a5247f29b37ca8dc8a0176719b22b924069166168ddcf684a84ca0bcbd45ae170a164516ffada4cb2066b428ece538f89c8daa45bfb2db15bd432fb9676dab
|
7
|
+
data.tar.gz: b41ed1c8028112b527cd21b01821187260ba85ab2647fe7f477422a69f40a72420aed74d6741d3525f5812d110354b85bc12cf23b54163ce921286be1d185e10
|
@@ -34,7 +34,7 @@ module Cats
|
|
34
34
|
def model_params
|
35
35
|
params.require(:payload).permit(:batch_no, :description, :unit_of_measure_id, :source_id,
|
36
36
|
:source_type, :quantity, :best_use_before, :volume_per_metric_ton,
|
37
|
-
:arrival_status)
|
37
|
+
:arrival_status, :shipping_reference)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
@@ -9,6 +9,11 @@ module Cats
|
|
9
9
|
render json: { success: true, data: data }
|
10
10
|
end
|
11
11
|
|
12
|
+
def all
|
13
|
+
data = Cats::Core::CommodityCategory.all
|
14
|
+
render json: { success: true, data: data }
|
15
|
+
end
|
16
|
+
|
12
17
|
def root
|
13
18
|
data = Cats::Core::CommodityCategory.roots
|
14
19
|
render json: { success: true, data: serialize(data) }
|
@@ -14,7 +14,7 @@ module Cats
|
|
14
14
|
# user to give us a source.
|
15
15
|
def create_allocation
|
16
16
|
dispatch = Dispatch.find(model_params[:dispatch_id])
|
17
|
-
commodity = dispatch.dispatch_plan_item.
|
17
|
+
commodity = dispatch.dispatch_plan_item.commodity
|
18
18
|
transaction = DispatchTransaction.new(model_params)
|
19
19
|
|
20
20
|
# Fetch supplier stack by commodity
|
@@ -17,12 +17,10 @@ module Cats
|
|
17
17
|
|
18
18
|
def approve
|
19
19
|
plan = Cats::Core::MonthlyPlan.find(params[:id])
|
20
|
-
|
21
|
-
render json: { success: false, error: 'Empty plan cannot be approved.' }, status: :unprocessable_entity
|
22
|
-
return
|
23
|
-
end
|
24
|
-
plan.update(status: Cats::Core::Plan::APPROVED)
|
20
|
+
plan.approve
|
25
21
|
render json: { success: true, data: serialize(plan) }
|
22
|
+
rescue StandardError => e
|
23
|
+
render json: { success: false, error: e.message }, status: :unprocessable_entity
|
26
24
|
end
|
27
25
|
|
28
26
|
def generate
|
@@ -13,9 +13,9 @@ module Cats
|
|
13
13
|
render json: { success: true, data: serialize(query.result) }
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
16
|
+
def items_for_location
|
17
17
|
service = StackService.new
|
18
|
-
commodities = service.
|
18
|
+
commodities = service.items_for_location(current_user)
|
19
19
|
render json: { success: true, data: serialize(commodities) }
|
20
20
|
end
|
21
21
|
|
@@ -31,8 +31,6 @@ module Cats
|
|
31
31
|
belongs_to :unit_of_measure
|
32
32
|
belongs_to :source, polymorphic: true
|
33
33
|
|
34
|
-
has_many :allocations
|
35
|
-
|
36
34
|
validates :best_use_before, presence: true
|
37
35
|
validates :batch_no, presence: true, uniqueness: true
|
38
36
|
validates :quantity, presence: true, numericality: { greater_than: 0 }
|
@@ -40,7 +38,7 @@ module Cats
|
|
40
38
|
validates :arrival_status, presence: true, inclusion: { in: ARRIVAL_STATUSES }
|
41
39
|
validates :status, presence: true, inclusion: { in: STATUSES }
|
42
40
|
|
43
|
-
delegate(:abbreviation, to: :unit_of_measure, prefix:
|
41
|
+
delegate(:abbreviation, to: :unit_of_measure, prefix: 'unit')
|
44
42
|
delegate(:reference_no, to: :source, prefix: true)
|
45
43
|
|
46
44
|
def name
|
@@ -74,25 +72,6 @@ module Cats
|
|
74
72
|
end
|
75
73
|
result
|
76
74
|
end
|
77
|
-
|
78
|
-
def allocate(ignore_errors: true)
|
79
|
-
statuses = Allocation.where(commodity_id: id).map(&:allocation_status).uniq
|
80
|
-
unless statuses.count == 1 && statuses[0] == APPROVED
|
81
|
-
return if ignore_errors
|
82
|
-
|
83
|
-
raise(StandardError, 'There are allocations in "Draft" state.')
|
84
|
-
end
|
85
|
-
|
86
|
-
quantity = allocations.sum(:quantity)
|
87
|
-
unless quantity == self.quantity
|
88
|
-
return if ignore_errors
|
89
|
-
|
90
|
-
raise(StandardError, 'Total allocations quantity is not the same as commodity quantity.')
|
91
|
-
end
|
92
|
-
|
93
|
-
self.status = ALLOCATED
|
94
|
-
save!
|
95
|
-
end
|
96
75
|
end
|
97
76
|
end
|
98
77
|
end
|
@@ -8,7 +8,6 @@ module Cats
|
|
8
8
|
belongs_to :dispatchable, polymorphic: true, optional: true
|
9
9
|
belongs_to :prepared_by, class_name: 'Cats::Core::User'
|
10
10
|
belongs_to :approved_by, class_name: 'Cats::Core::User', optional: true
|
11
|
-
belongs_to :commodity
|
12
11
|
|
13
12
|
has_many :dispatch_plan_items
|
14
13
|
|
@@ -16,7 +15,6 @@ module Cats
|
|
16
15
|
validates :status, inclusion: { in: STATUSES }
|
17
16
|
validate :validate_dispatchable, on: :create
|
18
17
|
|
19
|
-
delegate(:batch_no, :name, :quantity, to: :commodity, prefix: true)
|
20
18
|
delegate(:request_reference, to: :dispatchable, allow_nil: true)
|
21
19
|
delegate(:request_quantity, to: :dispatchable, allow_nil: true)
|
22
20
|
|
@@ -44,12 +42,12 @@ module Cats
|
|
44
42
|
|
45
43
|
# Raise error if the total dispatch plan quantity is not equal to the
|
46
44
|
# dispatchable quantity
|
47
|
-
if dispatchable && dispatchable.quantity != quantity
|
45
|
+
if dispatchable.instance_of?(RhnRequest) && dispatchable.quantity != quantity
|
48
46
|
raise(StandardError, 'Requested quantity and plan quantity do not match.')
|
49
47
|
end
|
50
48
|
|
51
49
|
self.status = APPROVED
|
52
|
-
dispatchable&.allocate
|
50
|
+
dispatchable&.allocate if dispatchable.instance_of?(RhnRequest)
|
53
51
|
save!
|
54
52
|
end
|
55
53
|
|
@@ -10,6 +10,8 @@ module Cats
|
|
10
10
|
belongs_to :source, class_name: 'Cats::Core::Location'
|
11
11
|
belongs_to :destination, class_name: 'Cats::Core::Location'
|
12
12
|
belongs_to :dispatch_plan
|
13
|
+
belongs_to :commodity
|
14
|
+
|
13
15
|
has_many :dispatches
|
14
16
|
has_many :hub_authorizations
|
15
17
|
|
@@ -18,7 +20,7 @@ module Cats
|
|
18
20
|
validates :status, presence: true, inclusion: { in: STATUSES }
|
19
21
|
|
20
22
|
delegate(:reference_no, to: :dispatch_plan, prefix: :plan, allow_nil: true)
|
21
|
-
delegate(:
|
23
|
+
delegate(:batch_no, :name, to: :commodity, prefix: true)
|
22
24
|
delegate(:name, to: :source, prefix: true)
|
23
25
|
delegate(:name, to: :destination, prefix: true)
|
24
26
|
delegate(:location_type, to: :source, prefix: true)
|
@@ -4,21 +4,24 @@ module Cats
|
|
4
4
|
belongs_to :donation, optional: true
|
5
5
|
belongs_to :commodity_category
|
6
6
|
belongs_to :unit_of_measure
|
7
|
+
belongs_to :currency
|
7
8
|
belongs_to :destination_warehouse, class_name: 'Cats::Core::Location'
|
8
9
|
|
9
10
|
validates :reference_no, presence: true, uniqueness: true
|
10
|
-
validates :gift_date, :quantity, :requested_by, :
|
11
|
+
validates :gift_date, :quantity, :requested_by, :customs_office, presence: true
|
11
12
|
validates :quantity, numericality: { greater_than: 0 }
|
12
13
|
|
13
14
|
delegate(:name, to: :commodity_category, prefix: true)
|
14
15
|
delegate(:name, to: :destination_warehouse, prefix: true)
|
15
16
|
delegate(:abbreviation, to: :unit_of_measure, prefix: true)
|
17
|
+
delegate(:code, to: :currency, prefix: true)
|
16
18
|
|
17
19
|
before_validation :set_commodity_category
|
18
20
|
after_create :update_donation
|
19
21
|
|
20
22
|
def update_donation
|
21
|
-
|
23
|
+
return unless donation
|
24
|
+
|
22
25
|
return if donation.active
|
23
26
|
|
24
27
|
donation.active = true
|
@@ -4,11 +4,12 @@ module Cats
|
|
4
4
|
REGION = 'Region'.freeze
|
5
5
|
ZONE = 'Zone'.freeze
|
6
6
|
WOREDA = 'Woreda'.freeze
|
7
|
+
FDP = 'Fdp'.freeze
|
7
8
|
KEBELE = 'Kebele'.freeze
|
8
9
|
HUB = 'Hub'.freeze
|
9
10
|
WAREHOUSE = 'Warehouse'.freeze
|
10
11
|
|
11
|
-
LOCATION_TYPES = [REGION, ZONE, WOREDA, KEBELE, HUB, WAREHOUSE].freeze
|
12
|
+
LOCATION_TYPES = [REGION, ZONE, WOREDA, KEBELE, HUB, WAREHOUSE, FDP].freeze
|
12
13
|
|
13
14
|
has_ancestry
|
14
15
|
|
@@ -23,6 +24,7 @@ module Cats
|
|
23
24
|
ZONE => [REGION],
|
24
25
|
WOREDA => [REGION, ZONE],
|
25
26
|
KEBELE => [REGION, ZONE, WOREDA],
|
27
|
+
FDP => [REGION, ZONE, WOREDA],
|
26
28
|
HUB => [REGION, ZONE, WOREDA, KEBELE],
|
27
29
|
WAREHOUSE => [REGION, ZONE, WOREDA, KEBELE, HUB]
|
28
30
|
}
|
@@ -3,6 +3,13 @@ module Cats
|
|
3
3
|
class MonthlyPlan < ApplicationRecord
|
4
4
|
include Dispatchable
|
5
5
|
|
6
|
+
DRAFT = 'Draft'.freeze
|
7
|
+
APPROVED = 'Approved'.freeze
|
8
|
+
RESERVED = 'Reserved'.freeze
|
9
|
+
NEEDS_APPROVED = 'Needs Approved'.freeze
|
10
|
+
|
11
|
+
STATUSES = [DRAFT, APPROVED, RESERVED, NEEDS_APPROVED].freeze
|
12
|
+
|
6
13
|
belongs_to :plan
|
7
14
|
belongs_to :region, class_name: 'Cats::Core::Location'
|
8
15
|
|
@@ -11,7 +18,7 @@ module Cats
|
|
11
18
|
has_many :monthly_rations
|
12
19
|
|
13
20
|
validates :reference_no, presence: true, uniqueness: true
|
14
|
-
validates :status, presence: true, inclusion: { in:
|
21
|
+
validates :status, presence: true, inclusion: { in: MonthlyPlan::STATUSES }
|
15
22
|
validates :no_of_days, :month, presence: true, numericality: { greater_than: 0 }
|
16
23
|
validate :validate_month, :validate_region
|
17
24
|
|
@@ -26,6 +33,21 @@ module Cats
|
|
26
33
|
nil
|
27
34
|
end
|
28
35
|
|
36
|
+
def approve
|
37
|
+
raise(StandardError, 'Plan is not in draft state.') unless status == DRAFT
|
38
|
+
|
39
|
+
raise(StandardError, 'Empty plan cannot be approved.') if monthly_plan_items.count.zero?
|
40
|
+
|
41
|
+
update!(status: APPROVED)
|
42
|
+
end
|
43
|
+
|
44
|
+
def reserve
|
45
|
+
raise(StandardError, 'Plan is not approved.') unless status == APPROVED
|
46
|
+
|
47
|
+
self.status = RESERVED
|
48
|
+
save!
|
49
|
+
end
|
50
|
+
|
29
51
|
def validate_month
|
30
52
|
return unless month
|
31
53
|
|
@@ -35,7 +57,7 @@ module Cats
|
|
35
57
|
def validate_region
|
36
58
|
return unless region
|
37
59
|
|
38
|
-
errors.add(:region, 'is not valid.') unless region.location_type ==
|
60
|
+
errors.add(:region, 'is not valid.') unless region.location_type == Location::REGION
|
39
61
|
end
|
40
62
|
end
|
41
63
|
end
|
@@ -8,7 +8,7 @@ module Cats
|
|
8
8
|
belongs_to :destination, class_name: 'Cats::Core::Location'
|
9
9
|
|
10
10
|
validates :source_id, uniqueness: { scope: :destination_id }
|
11
|
-
validate :validate_region, :validate_source, :validate_destination
|
11
|
+
validate :validate_region, :validate_source, :validate_destination, :validate_route
|
12
12
|
|
13
13
|
delegate(:name, to: :region, prefix: true)
|
14
14
|
|
@@ -35,6 +35,14 @@ module Cats
|
|
35
35
|
|
36
36
|
errors.add(:destination, 'cannot be a region.') if destination.location_type == Location::REGION
|
37
37
|
end
|
38
|
+
|
39
|
+
def validate_route
|
40
|
+
return unless source
|
41
|
+
|
42
|
+
return unless destination
|
43
|
+
|
44
|
+
errors.add(:base, 'Source and destination cannot be the same') if source == destination
|
45
|
+
end
|
38
46
|
end
|
39
47
|
end
|
40
48
|
end
|
@@ -20,7 +20,8 @@ module Cats
|
|
20
20
|
validates :commodity_status, inclusion: { in: Cats::Core::Commodity::COMMODITY_STATUSES }
|
21
21
|
validates :stack_status, inclusion: { in: STACK_STATUSES }
|
22
22
|
validate :validate_coordinates, :validate_dimensions, :validate_distance_from_wall, :validate_overlap,
|
23
|
-
:validate_space_between_stack,
|
23
|
+
:validate_space_between_stack, :validate_max_height, :validate_max_length, :validate_max_width,
|
24
|
+
:validate_distance_from_ceiling, unless: -> { store && store.code == 'SUP-STORE' }
|
24
25
|
|
25
26
|
delegate :batch_no, to: :commodity, prefix: true
|
26
27
|
|
@@ -48,9 +49,9 @@ module Cats
|
|
48
49
|
space_between_stack: 1,
|
49
50
|
distance_from_gangway: 2,
|
50
51
|
distance_from_ceiling: 1,
|
51
|
-
maximum_height:
|
52
|
-
maximum_length:
|
53
|
-
maximum_width:
|
52
|
+
maximum_height: 7,
|
53
|
+
maximum_length: 12,
|
54
|
+
maximum_width: 12,
|
54
55
|
distance_from_wall: 1
|
55
56
|
)
|
56
57
|
rule
|
@@ -92,6 +93,32 @@ module Cats
|
|
92
93
|
end
|
93
94
|
end
|
94
95
|
|
96
|
+
def validate_max_height
|
97
|
+
return unless height
|
98
|
+
|
99
|
+
errors.add(:height, 'exceeds stacking rule height.') if height > stacking_rules.maximum_height
|
100
|
+
end
|
101
|
+
|
102
|
+
def validate_max_length
|
103
|
+
return unless length
|
104
|
+
|
105
|
+
errors.add(:length, 'exceeds stacking rule length.') if length > stacking_rules.maximum_length
|
106
|
+
end
|
107
|
+
|
108
|
+
def validate_max_width
|
109
|
+
return unless width
|
110
|
+
|
111
|
+
errors.add(:width, 'exceeds stacking rule width.') if width > stacking_rules.maximum_width
|
112
|
+
end
|
113
|
+
|
114
|
+
def validate_distance_from_ceiling
|
115
|
+
return unless height && store
|
116
|
+
|
117
|
+
return unless store.height - height < stacking_rules.distance_from_ceiling
|
118
|
+
|
119
|
+
errors.add(:height, 'of stack is close to the ceiling.')
|
120
|
+
end
|
121
|
+
|
95
122
|
# A method that checks if an overlap exists b/n two stacks.
|
96
123
|
# An overlap b/n stacks does not occur if one of the stacks is completely above the other stack or
|
97
124
|
# if one of the stacks is on the left side of the other stack.
|
@@ -16,7 +16,7 @@ module Cats
|
|
16
16
|
belongs_to :transport_plan
|
17
17
|
|
18
18
|
validates :reference_no, presence: true, uniqueness: true
|
19
|
-
validates :start_date, :end_date, :status, :bid_bond_amount, presence: true
|
19
|
+
validates :start_date, :end_date, :opening_date, :status, :bid_bond_amount, presence: true
|
20
20
|
validates :bid_bond_amount, numericality: { greater_than_or_equal_to: 0 }
|
21
21
|
validates :status, inclusion: { in: STATUSES }
|
22
22
|
validate :validate_start_date_against_end_date
|
@@ -46,6 +46,10 @@ module Cats
|
|
46
46
|
save!
|
47
47
|
self
|
48
48
|
end
|
49
|
+
|
50
|
+
def quantity
|
51
|
+
transport_bid_items.sum(:quantity)
|
52
|
+
end
|
49
53
|
end
|
50
54
|
end
|
51
55
|
end
|
@@ -3,6 +3,7 @@ module Cats
|
|
3
3
|
class TransportBidItem < ApplicationRecord
|
4
4
|
belongs_to :transport_bid
|
5
5
|
belongs_to :transport_plan_item
|
6
|
+
belongs_to :unit, class_name: 'Cats::Core::UnitOfMeasure'
|
6
7
|
|
7
8
|
has_many :offer_items
|
8
9
|
|
@@ -10,6 +11,7 @@ module Cats
|
|
10
11
|
validates :transport_plan_item_id, uniqueness: true
|
11
12
|
|
12
13
|
delegate(:reference_no, to: :transport_bid, prefix: true)
|
14
|
+
delegate(:abbreviation, to: :unit, prefix: true)
|
13
15
|
|
14
16
|
def route
|
15
17
|
transport_plan_item.route.name
|
@@ -7,6 +7,7 @@ module Cats
|
|
7
7
|
|
8
8
|
validates :offer_date, :bid_bond_amount, presence: true
|
9
9
|
validates :bid_bond_amount, numericality: { greater_than_or_equal_to: 0 }
|
10
|
+
validates :transport_bid_id, uniqueness: { scope: :transporter_id }
|
10
11
|
|
11
12
|
delegate(:name, to: :transporter, prefix: true)
|
12
13
|
delegate(:reference_no, to: :transport_bid, prefix: 'bid')
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Cats
|
2
|
+
module Core
|
3
|
+
class UnitConversion < ApplicationRecord
|
4
|
+
belongs_to :from, class_name: 'Cats::Core::UnitOfMeasure'
|
5
|
+
belongs_to :to, class_name: 'Cats::Core::UnitOfMeasure'
|
6
|
+
|
7
|
+
validates :factor, presence: true
|
8
|
+
validates :from_id, uniqueness: { scope: :to_id }
|
9
|
+
validates :factor, numericality: { greater_than: 0 }
|
10
|
+
|
11
|
+
delegate(:abbreviation, to: :from, prefix: true)
|
12
|
+
delegate(:abbreviation, to: :to, prefix: true)
|
13
|
+
|
14
|
+
def self.convert(from, to, value)
|
15
|
+
return value if from == to
|
16
|
+
|
17
|
+
conversion = find_by(from: from, to: to)
|
18
|
+
error = "Conversion factor from #{from.abbreviation} to #{to.abbreviation} not found."
|
19
|
+
raise(StandardError, error) unless conversion
|
20
|
+
|
21
|
+
value * conversion.factor
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# A concern to represent entities that lead to dispatch plan.
|
2
|
-
# All classes including this concern must implement `request_reference()
|
3
|
-
# and `request_quantity()` methods, which will be used to generate
|
2
|
+
# All classes including this concern must implement `request_reference()`,
|
3
|
+
# `reserve()`, and `request_quantity()` methods, which will be used to generate
|
4
4
|
# reference information in dispatch plan serializer.
|
5
5
|
module Cats
|
6
6
|
module Core
|
@@ -12,14 +12,14 @@ module Cats
|
|
12
12
|
|
13
13
|
def message
|
14
14
|
allocation_item = params[:allocation_item]
|
15
|
-
commodity = allocation_item.
|
15
|
+
commodity = allocation_item.commodity.name
|
16
16
|
source = allocation_item.source.name
|
17
17
|
destination = allocation_item.destination.name
|
18
18
|
title = "Allocation Notification - #{commodity}"
|
19
19
|
date = Date.today
|
20
20
|
body = <<~BODY
|
21
21
|
Commodity with the following specification has been allocated to you:
|
22
|
-
Batch No. = #{allocation_item.
|
22
|
+
Batch No. = #{allocation_item.commodity.batch_no}
|
23
23
|
Commodity = #{commodity}
|
24
24
|
Quantity = #{allocation_item.quantity}
|
25
25
|
The commodity is expected to be delivered from #{source} to #{destination}
|
@@ -7,7 +7,7 @@ module Cats
|
|
7
7
|
|
8
8
|
def message
|
9
9
|
dispatch = params[:dispatch]
|
10
|
-
commodity = dispatch.dispatch_plan_item.
|
10
|
+
commodity = dispatch.dispatch_plan_item.commodity
|
11
11
|
title = "Dispatch Notification - #{commodity.name}"
|
12
12
|
date = Date.today
|
13
13
|
body = <<~BODY
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Cats
|
2
2
|
module Core
|
3
3
|
class CommoditySerializer < ActiveModel::Serializer
|
4
|
-
attributes :id, :name, :batch_no, :description, :unit_of_measure_id, :
|
4
|
+
attributes :id, :name, :batch_no, :description, :unit_of_measure_id, :unit_abbreviation, :source_id,
|
5
5
|
:source_type, :source_reference_no, :quantity, :best_use_before, :volume_per_metric_ton,
|
6
|
-
:arrival_status, :status
|
6
|
+
:arrival_status, :status, :shipping_reference
|
7
7
|
end
|
8
8
|
end
|
9
9
|
end
|
@@ -2,8 +2,7 @@ module Cats
|
|
2
2
|
module Core
|
3
3
|
class DispatchPlanSerializer < ActiveModel::Serializer
|
4
4
|
attributes :id, :reference_no, :status, :dispatchable_id, :dispatchable_type, :request_reference,
|
5
|
-
:request_quantity, :
|
6
|
-
:upstream
|
5
|
+
:request_quantity, :upstream
|
7
6
|
end
|
8
7
|
end
|
9
8
|
end
|
@@ -1,47 +1,35 @@
|
|
1
1
|
module Cats
|
2
2
|
module Core
|
3
3
|
class StackService
|
4
|
-
def
|
4
|
+
def items_for_location(user)
|
5
5
|
details = user.details
|
6
6
|
|
7
7
|
key_available = details.keys.any? { |key| %w[stores warehouse hub].include?(key) }
|
8
8
|
raise(StandardError, 'User does not have associated location.') unless key_available
|
9
9
|
|
10
|
-
if details['hub']
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
hub = warehouse.parent
|
23
|
-
end
|
24
|
-
allocation_items =
|
25
|
-
Cats::Core::AllocationItem
|
26
|
-
.joins(allocation: :commodity)
|
27
|
-
.where(destination: hub, allocation: { allocation_status: Cats::Core::Allocation::APPROVED })
|
28
|
-
.or(
|
29
|
-
Cats::Core::AllocationItem
|
30
|
-
.joins(allocation: :commodity)
|
31
|
-
.where(destination: warehouse, allocation: { allocation_status: Cats::Core::Allocation::APPROVED })
|
32
|
-
)
|
33
|
-
end
|
10
|
+
hub = if details['hub']
|
11
|
+
Location.find(details['hub'])
|
12
|
+
elsif details['warehouse']
|
13
|
+
Location.find(details['warehouse']).parent
|
14
|
+
else
|
15
|
+
Store.find(details['stores'][0]).warehouse.parent
|
16
|
+
end
|
17
|
+
|
18
|
+
allocation_items =
|
19
|
+
DispatchPlanItem
|
20
|
+
.joins(:dispatch_plan)
|
21
|
+
.where(destination: hub, dispatch_plan: { status: DispatchPlan::APPROVED })
|
34
22
|
|
35
23
|
allocation_items.map do |item|
|
36
24
|
{
|
37
|
-
reference_no: item.
|
38
|
-
source: item.
|
25
|
+
reference_no: item.dispatch_plan.reference_no,
|
26
|
+
source: item.source.name,
|
39
27
|
destination: item.destination.name,
|
40
28
|
quantity: item.quantity,
|
41
|
-
batch_no: item.
|
42
|
-
commodity_id: item.
|
43
|
-
commodity_name: item.
|
44
|
-
unit: item.
|
29
|
+
batch_no: item.commodity.batch_no,
|
30
|
+
commodity_id: item.commodity_id,
|
31
|
+
commodity_name: item.commodity.name,
|
32
|
+
unit: item.commodity.unit_abbreviation
|
45
33
|
}
|
46
34
|
end
|
47
35
|
end
|
@@ -51,7 +39,7 @@ module Cats
|
|
51
39
|
warehouses = location.children
|
52
40
|
stores = Store.where(warehouse: warehouses)
|
53
41
|
|
54
|
-
commodity = receipt.dispatch.dispatch_plan_item.
|
42
|
+
commodity = receipt.dispatch.dispatch_plan_item.commodity
|
55
43
|
Stack.where(commodity: commodity, store: stores)
|
56
44
|
end
|
57
45
|
|
@@ -60,7 +48,7 @@ module Cats
|
|
60
48
|
warehouses = location.children
|
61
49
|
stores = Store.where(warehouse: warehouses)
|
62
50
|
|
63
|
-
commodity = dispatch.dispatch_plan_item.
|
51
|
+
commodity = dispatch.dispatch_plan_item.commodity
|
64
52
|
Stack.where(commodity: commodity, store: stores)
|
65
53
|
end
|
66
54
|
end
|
data/config/routes.rb
CHANGED
@@ -60,6 +60,7 @@ Cats::Core::Engine.routes.draw do
|
|
60
60
|
defaults: { level: Cats::Core::SpaceService::STORE }
|
61
61
|
|
62
62
|
get '/commodity_categories/roots', to: 'commodity_categories#root', as: :commodity_category_roots
|
63
|
+
get '/commodity_categories/all', to: 'commodity_categories#all', as: :commodity_category_all
|
63
64
|
resources :commodity_categories, except: %i[destroy] do
|
64
65
|
member do
|
65
66
|
get 'children'
|
@@ -73,6 +74,7 @@ Cats::Core::Engine.routes.draw do
|
|
73
74
|
end
|
74
75
|
resources :currencies, except: %i[destroy]
|
75
76
|
resources :unit_of_measures, except: %i[destroy]
|
77
|
+
resources :unit_conversions, except: %i[destroy]
|
76
78
|
|
77
79
|
post '/transporters/filter', controller: :transporters, action: :filter
|
78
80
|
resources :transporters, except: %i[destroy]
|
@@ -135,7 +137,7 @@ Cats::Core::Engine.routes.draw do
|
|
135
137
|
|
136
138
|
get '/stores/:id/stacks', controller: :stacks, action: :index, as: :stacks_store
|
137
139
|
post '/stores/:id/stacks', controller: :stacks, action: :filter
|
138
|
-
get '/stacks/
|
140
|
+
get '/stacks/items_for_location', controller: :stacks, action: :items_for_location, as: :items_for_location
|
139
141
|
get '/receipts/:id/stacks', controller: :stacks, action: :receipt_stacks, as: :receipt_stacks
|
140
142
|
get '/dispatches/:id/stacks', controller: :stacks, action: :dispatch_stacks, as: :dispatch_stacks
|
141
143
|
resources :stacks, only: %i[show index create update]
|
@@ -30,9 +30,14 @@ class CreateCatsCoreGiftCertificates < ActiveRecord::Migration[6.1]
|
|
30
30
|
foreign_key: { to_table: :cats_core_locations }
|
31
31
|
t.float :estimated_price
|
32
32
|
t.float :estimated_tax
|
33
|
+
t.references :currency,
|
34
|
+
null: false,
|
35
|
+
index: { name: 'currency_on_gc_indx' },
|
36
|
+
foreign_key: { to_table: :cats_core_currencies }
|
33
37
|
t.string :registration_no
|
34
38
|
t.string :requested_by, null: false
|
35
|
-
t.string :request_reference
|
39
|
+
t.string :request_reference
|
40
|
+
t.string :customs_office, null: false
|
36
41
|
|
37
42
|
t.timestamps
|
38
43
|
end
|
@@ -13,6 +13,7 @@ class CreateCatsCoreCommodities < ActiveRecord::Migration[6.1]
|
|
13
13
|
t.float :volume_per_metric_ton
|
14
14
|
t.string :arrival_status, null: false, default: 'At Source'
|
15
15
|
t.boolean :approved, null: false, default: false
|
16
|
+
t.string :shipping_reference
|
16
17
|
|
17
18
|
t.timestamps
|
18
19
|
end
|
@@ -6,11 +6,6 @@ class CreateCatsCoreDispatchPlans < ActiveRecord::Migration[6.1]
|
|
6
6
|
t.string :status, null: false, default: 'Draft'
|
7
7
|
t.references :dispatchable, polymorphic: true
|
8
8
|
t.boolean :upstream, null: false, default: false
|
9
|
-
t.references :commodity,
|
10
|
-
null: false,
|
11
|
-
index: { name: 'commodity_on_dp_indx' },
|
12
|
-
foreign_key: { to_table: :cats_core_commodities }
|
13
|
-
|
14
9
|
t.references :prepared_by,
|
15
10
|
null: false,
|
16
11
|
index: { name: 'pb_on_dp_indx' },
|
@@ -13,6 +13,10 @@ class CreateCatsCoreDispatchPlanItems < ActiveRecord::Migration[6.1]
|
|
13
13
|
null: false,
|
14
14
|
index: { name: 'dpi_on_destination_indx'},
|
15
15
|
foreign_key: { to_table: :cats_core_locations }
|
16
|
+
t.references :commodity,
|
17
|
+
null: false,
|
18
|
+
index: { name: 'commodity_on_dpi_indx' },
|
19
|
+
foreign_key: { to_table: :cats_core_commodities }
|
16
20
|
t.float :quantity, null: false
|
17
21
|
t.string :commodity_status, null: false, default: 'Good'
|
18
22
|
t.string :status, null: false, default: 'Unauthorized'
|
@@ -3,8 +3,9 @@ class CreateCatsCoreTransportBids < ActiveRecord::Migration[6.1]
|
|
3
3
|
create_table :cats_core_transport_bids do |t|
|
4
4
|
t.string :reference_no, unique: true
|
5
5
|
t.string :description
|
6
|
-
t.
|
7
|
-
t.
|
6
|
+
t.datetime :start_date, null: false
|
7
|
+
t.datetime :end_date, null: false
|
8
|
+
t.datetime :opening_date, null: false
|
8
9
|
t.string :status, null: false, default: 'New'
|
9
10
|
t.float :bid_bond_amount, null: false, default: 0
|
10
11
|
t.references :transport_plan,
|
@@ -10,6 +10,10 @@ class CreateCatsCoreTransportBidItems < ActiveRecord::Migration[6.1]
|
|
10
10
|
index: { name: 'tpi_on_tbi_indx' },
|
11
11
|
foreign_key: { to_table: :cats_core_transport_plan_items }
|
12
12
|
t.float :quantity, null: false
|
13
|
+
t.references :unit,
|
14
|
+
null: false,
|
15
|
+
index: { name: 'unit_on_tbi_indx' },
|
16
|
+
foreign_key: { to_table: :cats_core_unit_of_measures }
|
13
17
|
|
14
18
|
t.timestamps
|
15
19
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class CreateCatsCoreUnitConversions < ActiveRecord::Migration[7.0]
|
2
|
+
def change
|
3
|
+
create_table :cats_core_unit_conversions do |t|
|
4
|
+
t.references :from,
|
5
|
+
null: false,
|
6
|
+
index: { name: 'from_on_uc_indx' },
|
7
|
+
foreign_key: { to_table: :cats_core_unit_of_measures }
|
8
|
+
t.references :to,
|
9
|
+
null: false,
|
10
|
+
index: { name: 'to_on_uc_indx' },
|
11
|
+
foreign_key: { to_table: :cats_core_unit_of_measures }
|
12
|
+
t.float :factor, null: false
|
13
|
+
|
14
|
+
t.timestamps
|
15
|
+
end
|
16
|
+
|
17
|
+
add_index(:cats_core_unit_conversions, [:from_id, :to_id], unique: true)
|
18
|
+
end
|
19
|
+
end
|
data/lib/cats/core/version.rb
CHANGED
@@ -4,12 +4,24 @@ FactoryBot.define do
|
|
4
4
|
status { Cats::Core::DispatchPlan::DRAFT }
|
5
5
|
dispatchable { nil }
|
6
6
|
upstream { false }
|
7
|
-
commodity
|
8
7
|
prepared_by factory: :user
|
9
8
|
approved_by { nil }
|
10
9
|
|
11
10
|
trait :with_rhn do
|
12
|
-
dispatchable
|
11
|
+
dispatchable do
|
12
|
+
disp = create(:rhn_request)
|
13
|
+
disp.approve
|
14
|
+
disp
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
trait :with_monthly_plan do
|
19
|
+
dispatchable do
|
20
|
+
disp = create(:monthly_plan)
|
21
|
+
3.times { create(:monthly_plan_item, monthly_plan: disp) }
|
22
|
+
disp.approve
|
23
|
+
disp
|
24
|
+
end
|
13
25
|
end
|
14
26
|
end
|
15
27
|
end
|
@@ -15,8 +15,10 @@ FactoryBot.define do
|
|
15
15
|
quantity { 1.5 }
|
16
16
|
estimated_price { 1.5 }
|
17
17
|
estimated_tax { 1.5 }
|
18
|
+
currency
|
18
19
|
registration_no { FFaker::Name.name }
|
19
20
|
requested_by { FFaker::Name.name }
|
20
21
|
request_reference { FFaker::Name.name }
|
22
|
+
customs_office { FFaker::Name.name }
|
21
23
|
end
|
22
24
|
end
|
@@ -3,9 +3,9 @@ FactoryBot.define do
|
|
3
3
|
space_between_stack { 1 }
|
4
4
|
distance_from_gangway { 1.5 }
|
5
5
|
distance_from_ceiling { 1 }
|
6
|
-
maximum_height {
|
7
|
-
maximum_length {
|
8
|
-
maximum_width {
|
6
|
+
maximum_height { 7 }
|
7
|
+
maximum_length { 12 }
|
8
|
+
maximum_width { 12 }
|
9
9
|
distance_from_wall { 1 }
|
10
10
|
end
|
11
11
|
end
|
@@ -2,8 +2,9 @@ FactoryBot.define do
|
|
2
2
|
factory :transport_bid, class: 'Cats::Core::TransportBid' do
|
3
3
|
reference_no { FFaker::Name.name }
|
4
4
|
description { FFaker::Name.name }
|
5
|
-
start_date {
|
6
|
-
end_date {
|
5
|
+
start_date { DateTime.now - 1.week }
|
6
|
+
end_date { DateTime.now }
|
7
|
+
opening_date { DateTime.now + 1.week }
|
7
8
|
bid_bond_amount { 100 }
|
8
9
|
transport_plan
|
9
10
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cats_core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Henock L.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: active_model_serializers
|
@@ -251,12 +251,11 @@ files:
|
|
251
251
|
- app/controllers/cats/core/spaces_controller.rb
|
252
252
|
- app/controllers/cats/core/stacks_controller.rb
|
253
253
|
- app/controllers/cats/core/transporters_controller.rb
|
254
|
+
- app/controllers/cats/core/unit_conversions_controller.rb
|
254
255
|
- app/controllers/cats/core/unit_of_measures_controller.rb
|
255
256
|
- app/controllers/cats/core/users_controller.rb
|
256
257
|
- app/controllers/concerns/cats/core/common.rb
|
257
258
|
- app/jobs/cats/core/application_job.rb
|
258
|
-
- app/models/cats/core/allocation.rb
|
259
|
-
- app/models/cats/core/allocation_item.rb
|
260
259
|
- app/models/cats/core/application_module.rb
|
261
260
|
- app/models/cats/core/application_record.rb
|
262
261
|
- app/models/cats/core/commodity.rb
|
@@ -311,6 +310,7 @@ files:
|
|
311
310
|
- app/models/cats/core/transport_plan.rb
|
312
311
|
- app/models/cats/core/transport_plan_item.rb
|
313
312
|
- app/models/cats/core/transporter.rb
|
313
|
+
- app/models/cats/core/unit_conversion.rb
|
314
314
|
- app/models/cats/core/unit_of_measure.rb
|
315
315
|
- app/models/cats/core/user.rb
|
316
316
|
- app/models/concerns/cats/core/dispatchable.rb
|
@@ -334,6 +334,7 @@ files:
|
|
334
334
|
- app/serializers/cats/core/route_serializer.rb
|
335
335
|
- app/serializers/cats/core/stack_serializer.rb
|
336
336
|
- app/serializers/cats/core/transporter_serializer.rb
|
337
|
+
- app/serializers/cats/core/unit_conversion_serializer.rb
|
337
338
|
- app/serializers/cats/core/unit_of_measure_serializer.rb
|
338
339
|
- app/serializers/cats/core/user_serializer.rb
|
339
340
|
- app/services/cats/core/dispatch_plan_service.rb
|
@@ -374,8 +375,6 @@ files:
|
|
374
375
|
- db/migrate/20210718040129_create_cats_core_routes.rb
|
375
376
|
- db/migrate/20210718042749_create_cats_core_transporters.rb
|
376
377
|
- db/migrate/20210718042755_create_cats_core_rhn_requests.rb
|
377
|
-
- db/migrate/20210718042823_create_cats_core_allocations.rb
|
378
|
-
- db/migrate/20210718043204_create_cats_core_allocation_items.rb
|
379
378
|
- db/migrate/20210718043328_create_cats_core_dispatch_plans.rb
|
380
379
|
- db/migrate/20210718043401_create_cats_core_dispatch_plan_items.rb
|
381
380
|
- db/migrate/20210718045516_create_cats_core_dispatches.rb
|
@@ -404,13 +403,12 @@ files:
|
|
404
403
|
- db/migrate/20220107125025_create_cats_core_monthly_plan_items.rb
|
405
404
|
- db/migrate/20220107132433_create_cats_core_monthly_plan_item_details.rb
|
406
405
|
- db/migrate/20220209083928_create_cats_core_hub_authorizations.rb
|
406
|
+
- db/migrate/20220416143416_create_cats_core_unit_conversions.rb
|
407
407
|
- lib/cats/core.rb
|
408
408
|
- lib/cats/core/engine.rb
|
409
409
|
- lib/cats/core/version.rb
|
410
410
|
- lib/cats_core.rb
|
411
411
|
- lib/tasks/cats_core_tasks.rake
|
412
|
-
- spec/factories/cats/core/allocation_items.rb
|
413
|
-
- spec/factories/cats/core/allocations.rb
|
414
412
|
- spec/factories/cats/core/application_modules.rb
|
415
413
|
- spec/factories/cats/core/commodities.rb
|
416
414
|
- spec/factories/cats/core/commodity_categories.rb
|
@@ -463,6 +461,7 @@ files:
|
|
463
461
|
- spec/factories/cats/core/transport_plan_items.rb
|
464
462
|
- spec/factories/cats/core/transport_plans.rb
|
465
463
|
- spec/factories/cats/core/transporters.rb
|
464
|
+
- spec/factories/cats/core/unit_conversions.rb
|
466
465
|
- spec/factories/cats/core/unit_of_measures.rb
|
467
466
|
- spec/factories/cats/core/users.rb
|
468
467
|
homepage: http://cats.ndrmcapps.org
|
@@ -488,7 +487,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
488
487
|
- !ruby/object:Gem::Version
|
489
488
|
version: '0'
|
490
489
|
requirements: []
|
491
|
-
rubygems_version: 3.3.
|
490
|
+
rubygems_version: 3.3.7
|
492
491
|
signing_key:
|
493
492
|
specification_version: 4
|
494
493
|
summary: Core module for CATS applications
|
@@ -1,78 +0,0 @@
|
|
1
|
-
module Cats
|
2
|
-
module Core
|
3
|
-
class Allocation < ApplicationRecord
|
4
|
-
DRAFT = 'Draft'.freeze
|
5
|
-
APPROVED = 'Approved'.freeze
|
6
|
-
ALLOCATION_STATUSES = [DRAFT, APPROVED].freeze
|
7
|
-
|
8
|
-
belongs_to :rhn_request, optional: true
|
9
|
-
belongs_to :commodity
|
10
|
-
belongs_to :source, class_name: 'Cats::Core::Location'
|
11
|
-
has_many :allocation_items
|
12
|
-
|
13
|
-
validates :commodity_status, :allocation_status, presence: true
|
14
|
-
validates :reference_no, presence: true, uniqueness: true
|
15
|
-
validates :quantity, presence: true, numericality: { greater_than: 0 }
|
16
|
-
validates :commodity_status, inclusion: { in: Commodity::COMMODITY_STATUSES }
|
17
|
-
validates :allocation_status, inclusion: { in: ALLOCATION_STATUSES }
|
18
|
-
validate :validate_quantity_against_items, :validate_quantity_against_commodity,
|
19
|
-
:validate_quantity_against_request, :validate_request_status, :validate_commodity_status
|
20
|
-
|
21
|
-
delegate(:reference_no, to: :rhn_request, prefix: :rhn, allow_nil: true)
|
22
|
-
delegate(:batch_no, to: :commodity, prefix: true)
|
23
|
-
delegate(:name, to: :source, prefix: true)
|
24
|
-
delegate(:location_type, to: :source, prefix: true)
|
25
|
-
|
26
|
-
def validate_quantity_against_items
|
27
|
-
return unless quantity
|
28
|
-
|
29
|
-
return unless quantity_changed?
|
30
|
-
|
31
|
-
allocated = allocation_items.sum(:quantity)
|
32
|
-
errors.add(:quantity, "is below items quantity. Minimum allowed is #{allocated}") if quantity < allocated
|
33
|
-
end
|
34
|
-
|
35
|
-
def validate_quantity_against_commodity
|
36
|
-
return unless quantity && commodity
|
37
|
-
|
38
|
-
allocated = Allocation.where(commodity: commodity).sum(:quantity)
|
39
|
-
remaining = commodity.quantity - allocated
|
40
|
-
|
41
|
-
remaining += quantity_was if quantity_was
|
42
|
-
errors.add(:quantity, "exceeds commodity quantity. Maximum allowed is #{remaining}") if quantity > remaining
|
43
|
-
end
|
44
|
-
|
45
|
-
def validate_quantity_against_request
|
46
|
-
return unless quantity && rhn_request
|
47
|
-
|
48
|
-
errors.add(:quantity, 'is not equal to requested quantity.') if quantity != rhn_request.quantity
|
49
|
-
end
|
50
|
-
|
51
|
-
def validate_request_status
|
52
|
-
return unless rhn_request
|
53
|
-
|
54
|
-
errors.add(:rhn_request, 'should be approved first.') if rhn_request.status != RhnRequest::APPROVED
|
55
|
-
end
|
56
|
-
|
57
|
-
def validate_commodity_status
|
58
|
-
return unless commodity
|
59
|
-
|
60
|
-
errors.add(:commodity, 'should be approved first.') unless commodity.status == Commodity::APPROVED
|
61
|
-
end
|
62
|
-
|
63
|
-
def approve
|
64
|
-
raise(StandardError, 'Allocation already approved.') if allocation_status == Allocation::APPROVED
|
65
|
-
|
66
|
-
item_quantity = allocation_items.sum(:quantity)
|
67
|
-
raise(StandardError, 'Allocation quantity and items quantity do not match.') if quantity != item_quantity
|
68
|
-
|
69
|
-
self.allocation_status = Allocation::APPROVED
|
70
|
-
save!
|
71
|
-
|
72
|
-
# If the commodity is all allocated, then we should
|
73
|
-
# set its status to allocated.
|
74
|
-
commodity.allocate
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
module Cats
|
2
|
-
module Core
|
3
|
-
class AllocationItem < ApplicationRecord
|
4
|
-
belongs_to :allocation
|
5
|
-
belongs_to :destination, class_name: 'Cats::Core::Location'
|
6
|
-
|
7
|
-
validates :from, :to, presence: true
|
8
|
-
validates :quantity, presence: true, numericality: { greater_than: 0 }
|
9
|
-
validate :validate_source_and_destination, :validate_quantity
|
10
|
-
validate :validate_allocation_status, on: %i[create update]
|
11
|
-
|
12
|
-
def validate_source_and_destination
|
13
|
-
return unless allocation.present? && destination.present?
|
14
|
-
|
15
|
-
errors.add(:base, 'source and destination cannot be the same') if allocation.source == destination
|
16
|
-
end
|
17
|
-
|
18
|
-
def validate_quantity
|
19
|
-
return unless quantity && allocation
|
20
|
-
|
21
|
-
return unless quantity_changed?
|
22
|
-
|
23
|
-
allocated = AllocationItem.where(allocation: allocation).sum(:quantity)
|
24
|
-
remaining = allocation.quantity - allocated
|
25
|
-
remaining += quantity_was if quantity_was
|
26
|
-
errors.add(:quantity, "exceeds allocated quantity. Maximum allowed is #{remaining}") if quantity > remaining
|
27
|
-
end
|
28
|
-
|
29
|
-
def validate_allocation_status
|
30
|
-
return unless allocation
|
31
|
-
|
32
|
-
return unless allocation.allocation_status == Cats::Core::Allocation::APPROVED
|
33
|
-
|
34
|
-
errors.add(:allocation, 'is alreay approved. Changes are not allowed at this point.')
|
35
|
-
end
|
36
|
-
|
37
|
-
delegate(:name, to: :destination, prefix: true)
|
38
|
-
delegate(:reference_no, to: :allocation, prefix: true)
|
39
|
-
delegate(:location_type, to: :destination, prefix: true)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
class CreateCatsCoreAllocations < ActiveRecord::Migration[6.1]
|
2
|
-
def change
|
3
|
-
create_table :cats_core_allocations do |t|
|
4
|
-
t.string :reference_no, unique: true
|
5
|
-
t.references :rhn_request,
|
6
|
-
null: true,
|
7
|
-
index: { name: 'rr_on_allocation_indx' },
|
8
|
-
foreign_key: { to_table: :cats_core_rhn_requests }
|
9
|
-
t.references :commodity,
|
10
|
-
null: false,
|
11
|
-
index: { name: 'ca_on_commodity_indx' },
|
12
|
-
foreign_key: { to_table: :cats_core_commodities }
|
13
|
-
t.references :source,
|
14
|
-
null: false,
|
15
|
-
index: { name: 'ca_on_source_indx' },
|
16
|
-
foreign_key: { to_table: :cats_core_locations }
|
17
|
-
t.float :quantity, null: false
|
18
|
-
t.string :commodity_status, null: false, default: 'Good'
|
19
|
-
t.string :allocation_status, null: false, default: 'Draft'
|
20
|
-
t.string :remark
|
21
|
-
|
22
|
-
t.timestamps
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
class CreateCatsCoreAllocationItems < ActiveRecord::Migration[6.1]
|
2
|
-
def change
|
3
|
-
create_table :cats_core_allocation_items do |t|
|
4
|
-
t.references :allocation,
|
5
|
-
null: false,
|
6
|
-
index: { name: 'allocation_on_ai_indx' },
|
7
|
-
foreign_key: { to_table: :cats_core_allocations }
|
8
|
-
t.references :destination,
|
9
|
-
null: false,
|
10
|
-
index: { name: 'destination_on_ai_indx'},
|
11
|
-
foreign_key: { to_table: :cats_core_locations }
|
12
|
-
t.float :quantity, null: false
|
13
|
-
t.date :from, null: false
|
14
|
-
t.date :to, null: false
|
15
|
-
|
16
|
-
t.timestamps
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
FactoryBot.define do
|
2
|
-
factory :allocation, class: 'Cats::Core::Allocation' do
|
3
|
-
reference_no { FFaker::Name.name }
|
4
|
-
rhn_request { nil }
|
5
|
-
commodity do
|
6
|
-
c = create(:commodity)
|
7
|
-
c.approve
|
8
|
-
c
|
9
|
-
end
|
10
|
-
source factory: :location
|
11
|
-
quantity { 50 }
|
12
|
-
commodity_status { Cats::Core::Commodity::GOOD }
|
13
|
-
allocation_status { Cats::Core::Allocation::DRAFT }
|
14
|
-
remark { FFaker::Name.name }
|
15
|
-
end
|
16
|
-
end
|