cats_core 1.4.1 → 1.4.4

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/cats/core/commodities_controller.rb +1 -1
  3. data/app/controllers/cats/core/commodity_categories_controller.rb +5 -0
  4. data/app/controllers/cats/core/dispatch_plan_items_controller.rb +1 -1
  5. data/app/controllers/cats/core/dispatch_plans_controller.rb +1 -1
  6. data/app/controllers/cats/core/dispatch_transactions_controller.rb +1 -1
  7. data/app/controllers/cats/core/dispatches_controller.rb +1 -1
  8. data/app/controllers/cats/core/monthly_plans_controller.rb +3 -5
  9. data/app/controllers/cats/core/stacks_controller.rb +2 -2
  10. data/app/controllers/cats/core/unit_conversions_controller.rb +13 -0
  11. data/app/models/cats/core/commodity.rb +1 -22
  12. data/app/models/cats/core/dispatch_plan.rb +2 -4
  13. data/app/models/cats/core/dispatch_plan_item.rb +3 -1
  14. data/app/models/cats/core/gift_certificate.rb +5 -2
  15. data/app/models/cats/core/location.rb +3 -1
  16. data/app/models/cats/core/monthly_plan.rb +24 -2
  17. data/app/models/cats/core/route.rb +9 -1
  18. data/app/models/cats/core/stack.rb +31 -4
  19. data/app/models/cats/core/transport_bid.rb +5 -1
  20. data/app/models/cats/core/transport_bid_item.rb +2 -0
  21. data/app/models/cats/core/transport_offer.rb +1 -0
  22. data/app/models/cats/core/unit_conversion.rb +25 -0
  23. data/app/models/concerns/cats/core/dispatchable.rb +2 -2
  24. data/app/notifications/cats/core/allocation_notification.rb +2 -2
  25. data/app/notifications/cats/core/dispatch_notification.rb +1 -1
  26. data/app/serializers/cats/core/commodity_serializer.rb +2 -2
  27. data/app/serializers/cats/core/dispatch_plan_serializer.rb +1 -2
  28. data/app/serializers/cats/core/unit_conversion_serializer.rb +7 -0
  29. data/app/services/cats/core/stack_service.rb +21 -33
  30. data/config/routes.rb +3 -1
  31. data/db/migrate/20210717032602_create_cats_core_gift_certificates.rb +6 -1
  32. data/db/migrate/20210717033223_create_cats_core_commodities.rb +1 -0
  33. data/db/migrate/20210718043328_create_cats_core_dispatch_plans.rb +0 -5
  34. data/db/migrate/20210718043401_create_cats_core_dispatch_plan_items.rb +4 -0
  35. data/db/migrate/20211215121151_create_cats_core_transport_bids.rb +3 -2
  36. data/db/migrate/20211215124452_create_cats_core_transport_bid_items.rb +4 -0
  37. data/db/migrate/20211229160125_create_cats_core_transport_offers.rb +2 -0
  38. data/db/migrate/20220416143416_create_cats_core_unit_conversions.rb +19 -0
  39. data/lib/cats/core/version.rb +1 -1
  40. data/spec/factories/cats/core/commodities.rb +1 -0
  41. data/spec/factories/cats/core/dispatch_plan_items.rb +1 -0
  42. data/spec/factories/cats/core/dispatch_plans.rb +14 -2
  43. data/spec/factories/cats/core/gift_certificates.rb +2 -0
  44. data/spec/factories/cats/core/stacking_rules.rb +3 -3
  45. data/spec/factories/cats/core/transport_bid_items.rb +1 -0
  46. data/spec/factories/cats/core/transport_bids.rb +3 -2
  47. data/spec/factories/cats/core/unit_conversions.rb +7 -0
  48. metadata +8 -9
  49. data/app/models/cats/core/allocation.rb +0 -78
  50. data/app/models/cats/core/allocation_item.rb +0 -42
  51. data/db/migrate/20210718042823_create_cats_core_allocations.rb +0 -25
  52. data/db/migrate/20210718043204_create_cats_core_allocation_items.rb +0 -19
  53. data/spec/factories/cats/core/allocation_items.rb +0 -9
  54. data/spec/factories/cats/core/allocations.rb +0 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: affaa1b4a210fc6234d49f105efd3a0e197b8d9e6c2ad7e00ae2dbefd23cfe31
4
- data.tar.gz: 608f4585d6c34f68a62a7bcfc187d495ac21a0fa528f905bcda7044801ab4c1f
3
+ metadata.gz: 05ec37047a728927e68df2e0a0ae34dd16cca869cfe658314ea5fb0738ae894b
4
+ data.tar.gz: 272f1c6cb33e96a8407cab42c3b9bd8b01540156feee9bf4d6012b5b97600b52
5
5
  SHA512:
6
- metadata.gz: 68b8a081e2ee0e3ad7edb1876b76a1cb2d2c0b8836de2af209acb01de699d004c0fd2f74c0357a27857fd287f249f3338950debe88c15ee2b742cfe72f4d62cd
7
- data.tar.gz: 4b5c89c2de473ec47255835b1862ddaa42f44b4a99d5410bd4c63515b73bef77d1ef92328a75358a00dd29992afa2bcf2c582cbde84a5d63de2833d10944aada
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) }
@@ -17,7 +17,7 @@ module Cats
17
17
 
18
18
  def model_params
19
19
  params.require(:payload).permit(:dispatch_plan_id, :source_id, :destination_id, :quantity, :commodity_status,
20
- :status)
20
+ :status, :commodity_id)
21
21
  end
22
22
  end
23
23
  end
@@ -33,7 +33,7 @@ module Cats
33
33
  private
34
34
 
35
35
  def model_params
36
- params.require(:payload).permit(:reference_no, :dispatchable_id, :dispatchable_type, :commodity_id)
36
+ params.require(:payload).permit(:reference_no, :dispatchable_id, :dispatchable_type)
37
37
  end
38
38
  end
39
39
  end
@@ -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.dispatch_plan.commodity
17
+ commodity = dispatch.dispatch_plan_item.commodity
18
18
  transaction = DispatchTransaction.new(model_params)
19
19
 
20
20
  # Fetch supplier stack by commodity
@@ -49,7 +49,7 @@ module Cats
49
49
  end
50
50
 
51
51
  def commodity
52
- data = @dispatch.dispatch_plan_item.dispatch_plan.commodity
52
+ data = @dispatch.dispatch_plan_item.commodity
53
53
  render json: { success: true, data: serialize(data) }
54
54
  end
55
55
 
@@ -17,12 +17,10 @@ module Cats
17
17
 
18
18
  def approve
19
19
  plan = Cats::Core::MonthlyPlan.find(params[:id])
20
- if plan.monthly_plan_items.count.zero?
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 commodity_for_location
16
+ def items_for_location
17
17
  service = StackService.new
18
- commodities = service.commodity_for_location(current_user)
18
+ commodities = service.items_for_location(current_user)
19
19
  render json: { success: true, data: serialize(commodities) }
20
20
  end
21
21
 
@@ -0,0 +1,13 @@
1
+ module Cats
2
+ module Core
3
+ class UnitConversionsController < ApplicationController
4
+ include Common
5
+
6
+ private
7
+
8
+ def model_params
9
+ params.require(:payload).permit(:from_id, :to_id, :factor)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -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: true)
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(:commodity_batch_no, :commodity_name, to: :dispatch_plan)
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, :request_reference, presence: true
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
- donation = self.donation
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: Cats::Core::Plan::STATUSES }
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 == Cats::Core::Location::REGION
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, unless: -> { store && store.code == 'SUP-STORE' }
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: 5,
52
- maximum_length: 5,
53
- maximum_width: 5,
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.dispatch_plan.commodity.name
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.dispatch_plan.commodity.batch_no}
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.dispatch_plan.commodity
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, :unit_of_measure_abbreviation, :source_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, :commodity_id, :commodity_name, :commodity_batch_no, :commodity_quantity,
6
- :upstream
5
+ :request_quantity, :upstream
7
6
  end
8
7
  end
9
8
  end
@@ -0,0 +1,7 @@
1
+ module Cats
2
+ module Core
3
+ class UnitConversionSerializer < ActiveModel::Serializer
4
+ attributes :id, :from_id, :from_abbreviation, :to_id, :to_abbreviation, :factor
5
+ end
6
+ end
7
+ end
@@ -1,47 +1,35 @@
1
1
  module Cats
2
2
  module Core
3
3
  class StackService
4
- def commodity_for_location(user)
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
- hub = Cats::Core::Location.find(details['hub'])
12
- allocation_items =
13
- Cats::Core::AllocationItem
14
- .joins(allocation: :commodity)
15
- .where(destination: hub, allocation: { allocation_status: Cats::Core::Allocation::APPROVED })
16
- else
17
- if details['stores']
18
- warehouse = Cats::Core::Store.find(details['stores'][0]).warehouse
19
- hub = warehouse.parent
20
- elsif details['warehouse']
21
- warehouse = Cats::Core::Location.find(details['warehouse'])
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.allocation.reference_no,
38
- source: item.allocation.source.name,
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.allocation.commodity.batch_no,
42
- commodity_id: item.allocation.commodity_id,
43
- commodity_name: item.allocation.commodity.name,
44
- unit: item.allocation.commodity.unit_of_measure.abbreviation
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.dispatch_plan.commodity
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.dispatch_plan.commodity
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/commodity_for_location', controller: :stacks, action: :commodity_for_location, as: :commodity_for_location
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, null: false
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.date :start_date, null: false
7
- t.date :end_date, null: false
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
@@ -13,6 +13,8 @@ class CreateCatsCoreTransportOffers < ActiveRecord::Migration[6.1]
13
13
  t.float :bid_bond_amount, null: false, default: 0
14
14
 
15
15
  t.timestamps
16
+
17
+ t.index [:transport_bid_id, :transporter_id], unique: true, name: 'tb_and_t_on_to_indx'
16
18
  end
17
19
  end
18
20
  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
@@ -1,5 +1,5 @@
1
1
  module Cats
2
2
  module Core
3
- VERSION = '1.4.1'.freeze
3
+ VERSION = '1.4.4'.freeze
4
4
  end
5
5
  end
@@ -9,5 +9,6 @@ FactoryBot.define do
9
9
  volume_per_metric_ton { 10 }
10
10
  arrival_status { Cats::Core::Commodity::AT_SOURCE }
11
11
  status { Cats::Core::Commodity::DRAFT }
12
+ shipping_reference { FFaker::Name.name }
12
13
  end
13
14
  end
@@ -4,6 +4,7 @@ FactoryBot.define do
4
4
  destination factory: :location
5
5
  dispatch_plan
6
6
  quantity { 100 }
7
+ commodity
7
8
  commodity_status { Cats::Core::Commodity::GOOD }
8
9
  status { Cats::Core::DispatchPlanItem::UNAUTHORIZED }
9
10
  end
@@ -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 { create(:rhn_request) }
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 { 2.5 }
7
- maximum_length { 6 }
8
- maximum_width { 6 }
6
+ maximum_height { 7 }
7
+ maximum_length { 12 }
8
+ maximum_width { 12 }
9
9
  distance_from_wall { 1 }
10
10
  end
11
11
  end
@@ -3,5 +3,6 @@ FactoryBot.define do
3
3
  transport_bid
4
4
  transport_plan_item
5
5
  quantity { 100 }
6
+ unit factory: :unit_of_measure
6
7
  end
7
8
  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 { Date.today - 1.week }
6
- end_date { Date.today }
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
@@ -0,0 +1,7 @@
1
+ FactoryBot.define do
2
+ factory :unit_conversion, class: 'Cats::Core::UnitConversion' do
3
+ from factory: :unit_of_measure
4
+ to factory: :unit_of_measure
5
+ factor { 1 }
6
+ end
7
+ 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.1
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-03-27 00:00:00.000000000 Z
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.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,9 +0,0 @@
1
- FactoryBot.define do
2
- factory :allocation_item, class: 'Cats::Core::AllocationItem' do
3
- allocation
4
- destination factory: :location
5
- quantity { 50 }
6
- from { Date.today }
7
- to { Date.today + 1.week }
8
- end
9
- 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