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