cats_core 1.5.2 → 1.5.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/cats/core/commodities_controller.rb +2 -2
  3. data/app/controllers/cats/core/dispatch_authorizations_controller.rb +3 -3
  4. data/app/controllers/cats/core/dispatch_transactions_controller.rb +2 -2
  5. data/app/controllers/cats/core/lost_commodities_controller.rb +2 -2
  6. data/app/controllers/cats/core/receipt_authorizations_controller.rb +4 -3
  7. data/app/controllers/cats/core/receipt_transactions_controller.rb +3 -2
  8. data/app/controllers/cats/core/receipts_controller.rb +2 -2
  9. data/app/controllers/cats/core/stacks_controller.rb +3 -3
  10. data/app/models/cats/core/application_setting.rb +10 -0
  11. data/app/models/cats/core/authorization.rb +14 -8
  12. data/app/models/cats/core/commodity.rb +10 -0
  13. data/app/models/cats/core/dispatch.rb +3 -19
  14. data/app/models/cats/core/dispatch_authorization.rb +13 -0
  15. data/app/models/cats/core/dispatch_plan.rb +3 -1
  16. data/app/models/cats/core/dispatch_plan_item.rb +4 -3
  17. data/app/models/cats/core/dispatch_transaction.rb +23 -10
  18. data/app/models/cats/core/hub_authorization.rb +15 -9
  19. data/app/models/cats/core/lost_commodity.rb +29 -0
  20. data/app/models/cats/core/receipt.rb +22 -0
  21. data/app/models/cats/core/receipt_authorization.rb +5 -8
  22. data/app/models/cats/core/receipt_transaction.rb +13 -5
  23. data/app/models/cats/core/rhn_request.rb +25 -8
  24. data/app/models/cats/core/stack.rb +3 -0
  25. data/app/models/cats/core/stack_transaction.rb +1 -0
  26. data/app/models/cats/core/transaction.rb +4 -0
  27. data/app/models/cats/core/unit_conversion.rb +21 -3
  28. data/app/notifications/cats/core/dispatch_notification.rb +2 -0
  29. data/app/serializers/cats/core/commodity_serializer.rb +1 -1
  30. data/app/serializers/cats/core/dispatch_authorization_serializer.rb +2 -1
  31. data/app/serializers/cats/core/dispatch_plan_item_serializer.rb +1 -1
  32. data/app/serializers/cats/core/dispatch_transaction_serializer.rb +2 -1
  33. data/app/serializers/cats/core/lost_commodity_serializer.rb +1 -1
  34. data/app/serializers/cats/core/receipt_authorization_serializer.rb +1 -1
  35. data/app/serializers/cats/core/receipt_serializer.rb +2 -1
  36. data/app/serializers/cats/core/receipt_transaction_serializer.rb +1 -1
  37. data/app/serializers/cats/core/stack_serializer.rb +1 -1
  38. data/app/services/cats/core/authorization_service.rb +2 -0
  39. data/app/services/cats/core/dispatch_plan_service.rb +1 -0
  40. data/app/utils/cats/core/util.rb +15 -0
  41. data/app/utils/cats/core/validation_util.rb +20 -0
  42. data/db/migrate/20210717033223_create_cats_core_commodities.rb +5 -0
  43. data/db/migrate/20210717171101_create_cats_core_stacks.rb +4 -0
  44. data/db/migrate/20210718042755_create_cats_core_rhn_requests.rb +4 -0
  45. data/db/migrate/20210718045516_create_cats_core_dispatches.rb +1 -1
  46. data/db/migrate/20210718055414_create_cats_core_dispatch_authorizations.rb +4 -0
  47. data/db/migrate/20210718202957_create_cats_core_dispatch_transactions.rb +4 -0
  48. data/db/migrate/20210727074646_create_cats_core_receipt_authorizations.rb +4 -0
  49. data/db/migrate/20210727105834_create_cats_core_receipts.rb +4 -0
  50. data/db/migrate/20210728041505_create_cats_core_lost_commodities.rb +4 -0
  51. data/db/migrate/20210814160628_create_cats_core_receipt_transactions.rb +4 -0
  52. data/db/migrate/20210814175406_create_cats_core_stack_transactions.rb +4 -0
  53. data/db/migrate/20220209083928_create_cats_core_hub_authorizations.rb +4 -0
  54. data/db/migrate/20220923190857_create_cats_core_application_settings.rb +14 -0
  55. data/lib/cats/core/version.rb +1 -1
  56. data/spec/factories/cats/core/application_settings.rb +7 -0
  57. data/spec/factories/cats/core/commodities.rb +1 -0
  58. data/spec/factories/cats/core/dispatch_authorizations.rb +1 -0
  59. data/spec/factories/cats/core/dispatch_transactions.rb +5 -4
  60. data/spec/factories/cats/core/dispatches.rb +7 -1
  61. data/spec/factories/cats/core/hub_authorizations.rb +1 -0
  62. data/spec/factories/cats/core/lost_commodities.rb +1 -0
  63. data/spec/factories/cats/core/receipt_authorizations.rb +1 -0
  64. data/spec/factories/cats/core/receipt_transactions.rb +5 -1
  65. data/spec/factories/cats/core/receipts.rb +1 -0
  66. data/spec/factories/cats/core/rhn_requests.rb +1 -0
  67. data/spec/factories/cats/core/stack_transactions.rb +1 -0
  68. data/spec/factories/cats/core/stacks.rb +1 -0
  69. metadata +7 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f44f88a61efb78a98b957e1125a822e36a3fba743e600f28da163dcf3ee8e1fd
4
- data.tar.gz: ba63704a7b079b931187ca2ea007202d57e94b3b4bba19c133dd9028873cae8d
3
+ metadata.gz: e9a6ea1b862a6804a3e215898c7aac9966ffedbdf7aa3c8d9661f9356c4b8a24
4
+ data.tar.gz: f08e17d946b62d02d148cffbe97ab52c9b1f113245d4dffca6f5d67256ec7ea0
5
5
  SHA512:
6
- metadata.gz: 8dbba69e6545334259ca98493c13a2571754ff2d1eccf9ef6178e7a38105c319c3345106683415dc1654fa35c26d03df04ce7a072b235aa8e0e4c7f2afafd390
7
- data.tar.gz: 1e827e9172351fca12b42fc2910a639b2cb0556e64b1608bee56704892de22f39a897c03b0688a0cc1596b425c8ed5e41bbe9a894e20a3536f801b8d4e91bb2c
6
+ metadata.gz: ea2045f6a7a7954a4157952747c932e096f5df6e8ab2a56e888ca1f656a85eb7bd08a572ad0f15a05b53b0defc51354c27755be960c69c4c0ec49b232ad9b5db
7
+ data.tar.gz: d91d382689b7abab6221e64457123334bc93bc0357ffdf6eb28e71466d46183ba3aeab2b0d01b24abb0184a7b01b06ae5d0e2331220b710b3a193ac751061ad6
@@ -5,7 +5,7 @@ module Cats
5
5
 
6
6
  def index
7
7
  super do
8
- Commodity.all.includes({ project: { source: :commodity_category } }, :unit_of_measure)
8
+ Commodity.all.includes({ project: { source: :commodity_category } }, :unit_of_measure, :package_unit)
9
9
  end
10
10
  end
11
11
 
@@ -18,7 +18,7 @@ module Cats
18
18
  end
19
19
 
20
20
  def filter
21
- query = Commodity.includes(:project, :unit_of_measure).ransack(params[:q])
21
+ query = Commodity.includes(:project, :unit_of_measure, :package_unit).ransack(params[:q])
22
22
  render json: { success: true, data: serialize(query.result) }
23
23
  end
24
24
 
@@ -5,7 +5,7 @@ module Cats
5
5
 
6
6
  def index
7
7
  super do
8
- DispatchAuthorization.includes(:dispatch, :store, :authorized_by).where(dispatch_id: params[:id])
8
+ DispatchAuthorization.includes(:dispatch, :store, :authorized_by, :unit).where(dispatch_id: params[:id])
9
9
  end
10
10
  end
11
11
 
@@ -21,7 +21,7 @@ module Cats
21
21
  storekeeper = User.find(params[:id])
22
22
  stores = storekeeper.stores
23
23
  authorizations = DispatchAuthorization.joins(:dispatch)
24
- .includes(:dispatch, :store, :authorized_by)
24
+ .includes(:dispatch, :store, :authorized_by, :unit)
25
25
  .where(store: stores, dispatch: { dispatch_status: Dispatch::APPROVED })
26
26
  render json: { success: true, data: serialize(authorizations) }
27
27
  end
@@ -29,7 +29,7 @@ module Cats
29
29
  private
30
30
 
31
31
  def model_params
32
- params.require(:payload).permit(:dispatch_id, :store_id, :quantity, :status, :authorized_by_id)
32
+ params.require(:payload).permit(:dispatch_id, :store_id, :quantity, :unit_id, :status, :authorized_by_id)
33
33
  end
34
34
  end
35
35
  end
@@ -5,7 +5,7 @@ module Cats
5
5
 
6
6
  def index
7
7
  super do
8
- DispatchTransaction.includes(:source).where(dispatch_authorization_id: params[:id])
8
+ DispatchTransaction.includes(:source, :unit).where(dispatch_authorization_id: params[:id])
9
9
  end
10
10
  end
11
11
 
@@ -37,7 +37,7 @@ module Cats
37
37
  private
38
38
 
39
39
  def model_params
40
- params.require(:payload).permit(:source_id, :dispatch_authorization_id, :transaction_date, :quantity)
40
+ params.require(:payload).permit(:source_id, :dispatch_authorization_id, :transaction_date, :quantity, :unit_id)
41
41
  end
42
42
  end
43
43
  end
@@ -5,12 +5,12 @@ module Cats
5
5
 
6
6
  def index
7
7
  super do
8
- LostCommodity.where(receipt_authorization_id: params[:id])
8
+ LostCommodity.includes(:unit).where(receipt_authorization_id: params[:id])
9
9
  end
10
10
  end
11
11
 
12
12
  def model_params
13
- params.require(:payload).permit(:receipt_authorization_id, :quantity, :remark)
13
+ params.require(:payload).permit(:receipt_authorization_id, :quantity, :unit_id, :remark)
14
14
  end
15
15
  end
16
16
  end
@@ -7,7 +7,7 @@ module Cats
7
7
 
8
8
  def index
9
9
  super do
10
- ReceiptAuthorization.includes(:dispatch, :store, :authorized_by).where(dispatch_id: params[:id])
10
+ ReceiptAuthorization.includes(:dispatch, :store, :authorized_by, :unit).where(dispatch_id: params[:id])
11
11
  end
12
12
  end
13
13
 
@@ -40,7 +40,7 @@ module Cats
40
40
  storekeeper = User.find(params[:id])
41
41
  status = params[:status]
42
42
  stores = storekeeper.stores
43
- authorizations = ReceiptAuthorization.includes(:dispatch, :store, :authorized_by)
43
+ authorizations = ReceiptAuthorization.includes(:dispatch, :store, :authorized_by, :unit)
44
44
  .where(store: stores, status: status)
45
45
  render json: { success: true, data: serialize(authorizations) }
46
46
  end
@@ -48,7 +48,8 @@ module Cats
48
48
  private
49
49
 
50
50
  def model_params
51
- params.require(:payload).permit(:dispatch_id, :store_id, :quantity, :remark, :status, :authorized_by_id)
51
+ params.require(:payload).permit(:dispatch_id, :store_id, :quantity, :unit_id, :remark, :status,
52
+ :authorized_by_id)
52
53
  end
53
54
 
54
55
  def driver_confirm_params
@@ -5,7 +5,7 @@ module Cats
5
5
 
6
6
  def index
7
7
  super do
8
- ReceiptTransaction.includes(:destination, { receipt_authorization: :dispatch })
8
+ ReceiptTransaction.includes(:destination, { receipt_authorization: :dispatch }, :unit)
9
9
  .where(receipt_authorization_id: params[:id])
10
10
  end
11
11
  end
@@ -18,7 +18,8 @@ module Cats
18
18
  private
19
19
 
20
20
  def model_params
21
- params.require(:payload).permit(:receipt_authorization_id, :destination_id, :transaction_date, :quantity)
21
+ params.require(:payload).permit(:receipt_authorization_id, :destination_id, :transaction_date, :quantity,
22
+ :unit_id)
22
23
  end
23
24
  end
24
25
  end
@@ -5,7 +5,7 @@ module Cats
5
5
 
6
6
  def index
7
7
  super do
8
- Receipt.where(receipt_authorization_id: params[:id])
8
+ Receipt.includes(:unit).where(receipt_authorization_id: params[:id])
9
9
  end
10
10
  end
11
11
 
@@ -13,7 +13,7 @@ module Cats
13
13
 
14
14
  def model_params
15
15
  params.require(:payload).permit(:receipt_authorization_id, :commodity_status, :commodity_grade, :quantity,
16
- :remark)
16
+ :unit_id, :remark)
17
17
  end
18
18
  end
19
19
  end
@@ -5,12 +5,12 @@ module Cats
5
5
 
6
6
  def index
7
7
  super do
8
- Stack.includes(:commodity).where(store_id: params[:id])
8
+ Stack.includes(:commodity, :unit).where(store_id: params[:id])
9
9
  end
10
10
  end
11
11
 
12
12
  def filter
13
- query = Stack.includes(:commodity).where(store_id: params[:id]).ransack(params[:q])
13
+ query = Stack.includes(:commodity, :unit).where(store_id: params[:id]).ransack(params[:q])
14
14
  render json: { success: true, data: serialize(query.result) }
15
15
  end
16
16
 
@@ -38,7 +38,7 @@ module Cats
38
38
 
39
39
  def model_params
40
40
  params.require(:payload).permit(:code, :length, :width, :height, :start_x, :start_y, :commodity_id, :store_id,
41
- :commodity_status, :stack_status, :quantity)
41
+ :commodity_status, :stack_status, :quantity, :unit_id)
42
42
  end
43
43
  end
44
44
  end
@@ -0,0 +1,10 @@
1
+ module Cats
2
+ module Core
3
+ class ApplicationSetting < ApplicationRecord
4
+ belongs_to :application_module
5
+
6
+ validates :key, presence: true, uniqueness: true
7
+ validates :value, presence: true
8
+ end
9
+ end
10
+ end
@@ -3,6 +3,7 @@ module Cats
3
3
  class Authorization < ApplicationRecord
4
4
  self.abstract_class = true
5
5
  after_initialize :set_status
6
+ before_validation :set_unit
6
7
 
7
8
  # Authorization statuses
8
9
  AUTHORIZED = 'Authorized'.freeze
@@ -11,6 +12,7 @@ module Cats
11
12
 
12
13
  belongs_to :dispatch
13
14
  belongs_to :store
15
+ belongs_to :unit, class_name: 'Cats::Core::UnitOfMeasure'
14
16
  belongs_to :authorized_by, class_name: 'Cats::Core::User'
15
17
 
16
18
  validates :quantity, presence: true, numericality: { greater_than: 0 }
@@ -23,6 +25,15 @@ module Cats
23
25
  delegate(:dispatch_status, to: :dispatch)
24
26
  delegate(:plate_no, to: :dispatch)
25
27
  delegate(:driver_name, to: :dispatch)
28
+ delegate(:abbreviation, to: :unit, prefix: true)
29
+
30
+ def set_unit
31
+ return if unit
32
+
33
+ return unless dispatch
34
+
35
+ self.unit = dispatch.unit
36
+ end
26
37
 
27
38
  def validate_dispatch_status
28
39
  return unless dispatch
@@ -52,8 +63,9 @@ module Cats
52
63
  transactions.each(&:commit)
53
64
  self.status = CONFIRMED
54
65
  save!
66
+ reload
55
67
  if dispatch.all_authorizations_confirmed?
56
- dispatch.generate_pin
68
+ Util.generate_pin(dispatch)
57
69
  dispatch.quantity = dispatch.dispatch_transactions.sum(:quantity)
58
70
  dispatch.dispatch_status = Dispatch::READY_TO_START
59
71
  dispatch.save!
@@ -70,17 +82,11 @@ module Cats
70
82
  self.received_quantity = total_received
71
83
  self.status = CONFIRMED
72
84
  save!
73
- generate_pin
85
+ Util.generate_pin(self)
74
86
  end
75
87
  self
76
88
  end
77
89
 
78
- def generate_pin
79
- pin = SecureRandom.hex(10)
80
- self.auth_details = { pin: pin, active: true, expires_at: DateTime.now + 1.hour }
81
- save!
82
- end
83
-
84
90
  private
85
91
 
86
92
  def set_status
@@ -44,6 +44,7 @@ module Cats
44
44
 
45
45
  belongs_to :unit_of_measure
46
46
  belongs_to :project
47
+ belongs_to :package_unit, class_name: 'Cats::Core::UnitOfMeasure', optional: true
47
48
 
48
49
  validates :best_use_before, presence: true
49
50
  validates :batch_no, presence: true, uniqueness: true
@@ -56,6 +57,9 @@ module Cats
56
57
 
57
58
  delegate(:abbreviation, to: :unit_of_measure, prefix: 'unit')
58
59
  delegate(:code, to: :project, prefix: true)
60
+ delegate(:abbreviation, to: :package_unit, prefix: true, allow_nil: true)
61
+
62
+ alias_attribute :unit, :unit_of_measure
59
63
 
60
64
  def name
61
65
  # For this to be efficient, our query should use includes like
@@ -86,6 +90,7 @@ module Cats
86
90
  store: store,
87
91
  commodity: self,
88
92
  quantity: quantity,
93
+ unit: unit,
89
94
  commodity_status: GOOD,
90
95
  stack_status: Stack::ALLOCATED,
91
96
  length: 100,
@@ -98,6 +103,11 @@ module Cats
98
103
  end
99
104
  result
100
105
  end
106
+
107
+ def requested_quantity
108
+ requests = RhnRequest.where(commodity: self)
109
+ UnitConversion.harmonized_total(requests, unit_of_measure)
110
+ end
101
111
  end
102
112
  end
103
113
  end
@@ -35,10 +35,6 @@ module Cats
35
35
  dispatch_plan_item.destination.name
36
36
  end
37
37
 
38
- def authorized_quantity
39
- dispatch_authorizations.sum(:quantity)
40
- end
41
-
42
38
  def validate_dispatch_plan_status
43
39
  return unless dispatch_plan_item
44
40
 
@@ -52,16 +48,9 @@ module Cats
52
48
  # Check if dispatch has authorizations
53
49
  raise(StandardError, 'Dispatch has no authorizations.') unless dispatch_authorizations.count.positive?
54
50
 
55
- dispatches = Dispatch.where(dispatch_plan_item: dispatch_plan_item)
56
- authorized = dispatches.inject(0) do |result, dispatch|
57
- result += dispatch.authorized_quantity
58
- result
59
- end
60
- diff = authorized - dispatch_plan_item.quantity
61
- error = "Total authorized quantity exceeds allocated quantity (Extra = #{diff})."
62
- raise(StandardError, error) if diff.positive?
63
-
51
+ dispatch_total = UnitConversion.harmonized_total(dispatch_authorizations, unit)
64
52
  self.dispatch_status = APPROVED
53
+ self.quantity = dispatch_total
65
54
  save!
66
55
  end
67
56
 
@@ -86,6 +75,7 @@ module Cats
86
75
  dispatch: self,
87
76
  store: store,
88
77
  quantity: quantity,
78
+ unit: unit,
89
79
  received_quantity: 0,
90
80
  status: Authorization::AUTHORIZED,
91
81
  authorized_by: authorized_by
@@ -128,12 +118,6 @@ module Cats
128
118
  }
129
119
  end
130
120
  end
131
-
132
- def generate_pin
133
- pin = SecureRandom.hex(10)
134
- self.auth_details = { pin: pin, active: true, expires_at: DateTime.now + 1.hour }
135
- save!
136
- end
137
121
  end
138
122
  end
139
123
  end
@@ -3,11 +3,24 @@ module Cats
3
3
  class DispatchAuthorization < Authorization
4
4
  has_many :dispatch_transactions
5
5
 
6
+ validate :validate_quantity
7
+
6
8
  def validate_dispatch_status
7
9
  return unless dispatch
8
10
 
9
11
  errors.add(:dispatch, 'is not in draft state.') unless dispatch.dispatch_status == Dispatch::DRAFT
10
12
  end
13
+
14
+ def validate_quantity
15
+ return unless dispatch && quantity && unit
16
+
17
+ authorizations = DispatchAuthorization.joins(:dispatch).where(
18
+ dispatch: { dispatch_plan_item_id: dispatch.dispatch_plan_item_id }
19
+ )
20
+ quantity_attribs = %w[dispatch_plan_item quantity]
21
+ unit_attribs = %w[dispatch_plan_item unit]
22
+ ValidationUtil.validate_quantity(self, 'dispatch', authorizations, 'allocated', quantity_attribs, unit_attribs)
23
+ end
11
24
  end
12
25
  end
13
26
  end
@@ -54,7 +54,9 @@ module Cats
54
54
  # A method which returns the total quantity in the dispatch plan
55
55
  # based on dispatch plan item quantities.
56
56
  def quantity
57
- dispatch_plan_items.sum(:quantity)
57
+ raise(StandardError, 'Dispatchable must be RHN request.') unless dispatchable.instance_of?(RhnRequest)
58
+
59
+ UnitConversion.harmonized_total(dispatch_plan_items, dispatchable.unit)
58
60
  end
59
61
 
60
62
  def region
@@ -58,8 +58,8 @@ module Cats
58
58
  )
59
59
  end
60
60
 
61
- total_src = source_auth.sum(&:quantity)
62
- total_dest = dest_auth.sum(&:quantity)
61
+ total_src = UnitConversion.harmonized_total(source_auth, unit)
62
+ total_dest = UnitConversion.harmonized_total(dest_auth, unit)
63
63
 
64
64
  if source_auth.count == count
65
65
  validate_quantity(total_src, SOURCE_AUTHORIZED)
@@ -81,9 +81,10 @@ module Cats
81
81
 
82
82
  diff = self.quantity - quantity
83
83
  desc = type.split(' ')[0].downcase
84
+ amount = "#{diff} #{unit.abbreviation}"
84
85
  raise(
85
86
  StandardError,
86
- "Authorized #{desc} quantity is not the same as plan item quantity (#{diff} unaccounted for)."
87
+ "Authorized #{desc} quantity is not the same as plan item quantity (#{amount} unaccounted for)."
87
88
  )
88
89
  end
89
90
  end
@@ -1,6 +1,8 @@
1
1
  module Cats
2
2
  module Core
3
3
  class DispatchTransaction < Transaction
4
+ before_validation :set_unit
5
+
4
6
  belongs_to :source, class_name: 'Cats::Core::Stack'
5
7
  belongs_to :dispatch_authorization
6
8
 
@@ -10,9 +12,17 @@ module Cats
10
12
 
11
13
  delegate(:code, to: :source, prefix: true)
12
14
 
15
+ def set_unit
16
+ return if unit
17
+
18
+ return unless dispatch_authorization
19
+
20
+ self.unit = dispatch_authorization.unit
21
+ end
22
+
13
23
  def commit
14
24
  Transaction.transaction do
15
- source.quantity -= quantity
25
+ source.quantity -= UnitConversion.convert(unit, source.unit, quantity)
16
26
  source.save!
17
27
 
18
28
  self.status = COMMITTED
@@ -30,19 +40,22 @@ module Cats
30
40
  def validate_source_quantity
31
41
  return unless quantity && source
32
42
 
33
- total = DispatchTransaction.where(status: DRAFT, source: source).sum(:quantity)
34
- diff = quantity - (source.quantity - total)
35
- diff -= quantity_was if quantity_was
36
- errors.add(:quantity, "exceeds source quantity by #{diff}") if diff.positive?
43
+ total = UnitConversion.convert(source.unit, unit, source.quantity)
44
+ transactions = DispatchTransaction.where(status: DRAFT, source: source)
45
+ used = UnitConversion.harmonized_total(transactions, unit)
46
+ used -= quantity_was if quantity_was
47
+
48
+ remaining = total - used
49
+ return unless quantity > remaining
50
+
51
+ errors.add(:quantity, "exceeds source quantity. Maximum allowed is #{remaining} #{unit.abbreviation}")
37
52
  end
38
53
 
39
54
  def validate_authorized_quantity
40
- return unless quantity && dispatch_authorization
55
+ return unless quantity && unit && dispatch_authorization
41
56
 
42
- total = DispatchTransaction.where(dispatch_authorization: dispatch_authorization).sum(:quantity)
43
- diff = dispatch_authorization.quantity - total
44
- diff += quantity_was if quantity_was
45
- errors.add(:quantity, "exceeds authorized quantity (Max. = #{diff}).") if quantity > diff
57
+ transactions = DispatchTransaction.where(dispatch_authorization: dispatch_authorization)
58
+ ValidationUtil.validate_quantity(self, 'dispatch_authorization', transactions, 'authorized')
46
59
  end
47
60
 
48
61
  def skip_quantity_validation
@@ -1,6 +1,8 @@
1
1
  module Cats
2
2
  module Core
3
3
  class HubAuthorization < ApplicationRecord
4
+ before_validation :set_unit
5
+
4
6
  SOURCE = 'Source'.freeze
5
7
  DESTINATION = 'Destination'.freeze
6
8
  AUTHORIZATION_TYPES = [SOURCE, DESTINATION].freeze
@@ -8,6 +10,7 @@ module Cats
8
10
  belongs_to :dispatch_plan_item, optional: true
9
11
  belongs_to :store
10
12
  belongs_to :authorized_by, class_name: 'Cats::Core::User'
13
+ belongs_to :unit, class_name: 'Cats::Core::UnitOfMeasure'
11
14
 
12
15
  validates :quantity, :authorization_type, presence: true
13
16
  validates :quantity, numericality: { greater_than: 0 }
@@ -17,21 +20,24 @@ module Cats
17
20
  delegate(:plan_reference_no, to: :dispatch_plan_item)
18
21
  delegate(:full_name, to: :authorized_by, prefix: true)
19
22
  delegate(:name, to: :store, prefix: true)
23
+ delegate(:abbreviation, to: :unit, prefix: true)
20
24
 
21
- def validate_quantity
22
- return unless quantity
25
+ def set_unit
26
+ return if unit
23
27
 
24
28
  return unless dispatch_plan_item
25
29
 
26
- total = dispatch_plan_item.quantity
27
- used = HubAuthorization.where(
30
+ self.unit = dispatch_plan_item.unit
31
+ end
32
+
33
+ def validate_quantity
34
+ return unless quantity && unit && dispatch_plan_item
35
+
36
+ authorizations = HubAuthorization.where(
28
37
  dispatch_plan_item: dispatch_plan_item,
29
38
  authorization_type: authorization_type
30
- ).sum(:quantity)
31
- used -= quantity_was if quantity_was
32
-
33
- remaining = total - used
34
- errors.add(:quantity, "exceeds allocated quantity. Maximum allowed is #{remaining}") if quantity > remaining
39
+ )
40
+ ValidationUtil.validate_quantity(self, 'dispatch_plan_item', authorizations, 'allocated')
35
41
  end
36
42
  end
37
43
  end
@@ -1,9 +1,38 @@
1
1
  module Cats
2
2
  module Core
3
3
  class LostCommodity < ApplicationRecord
4
+ before_validation :set_unit
5
+
4
6
  belongs_to :receipt_authorization
7
+ belongs_to :unit, class_name: 'Cats::Core::UnitOfMeasure'
5
8
 
6
9
  validates :quantity, presence: true, numericality: { greater_than: 0 }
10
+ validate :validate_quantity
11
+
12
+ delegate(:abbreviation, to: :unit, prefix: true)
13
+
14
+ def set_unit
15
+ return if unit
16
+
17
+ return unless receipt_authorization
18
+
19
+ self.unit = receipt_authorization.unit
20
+ end
21
+
22
+ def validate_quantity
23
+ return unless quantity && unit && receipt_authorization
24
+
25
+ total = UnitConversion.convert(receipt_authorization.unit, unit, receipt_authorization.quantity)
26
+ receipts = Receipt.where(receipt_authorization: receipt_authorization)
27
+ losses = LostCommodity.where(receipt_authorization: receipt_authorization)
28
+ used = UnitConversion.harmonized_total(receipts, unit) + UnitConversion.harmonized_total(losses, unit)
29
+ used -= quantity_was if quantity_was
30
+
31
+ remaining = total - used
32
+ return unless quantity > remaining
33
+
34
+ errors.add(:quantity, "exceeds authorized quantity. Maximum allowed is #{remaining} #{unit.abbreviation}")
35
+ end
7
36
  end
8
37
  end
9
38
  end
@@ -1,11 +1,33 @@
1
1
  module Cats
2
2
  module Core
3
3
  class Receipt < ApplicationRecord
4
+ before_validation :set_unit
5
+
4
6
  belongs_to :receipt_authorization
7
+ belongs_to :unit, class_name: 'Cats::Core::UnitOfMeasure'
5
8
 
6
9
  validates :commodity_status, presence: true, inclusion: { in: Commodity::COMMODITY_STATUSES }
7
10
  validates :commodity_grade, inclusion: { in: Commodity::COMMODITY_GRADES }, allow_nil: true
8
11
  validates :quantity, presence: true, numericality: { greater_than: 0 }
12
+ validate :validate_quantity
13
+
14
+ delegate(:abbreviation, to: :unit, prefix: true)
15
+
16
+ def set_unit
17
+ return if unit
18
+
19
+ return unless receipt_authorization
20
+
21
+ self.unit = receipt_authorization.unit
22
+ end
23
+
24
+ def validate_quantity
25
+ return unless quantity && unit && receipt_authorization
26
+
27
+ receipts = Receipt.where(receipt_authorization: receipt_authorization)
28
+ losses = LostCommodity.where(receipt_authorization: receipt_authorization)
29
+ ValidationUtil.validate_quantity(self, 'receipt_authorization', receipts + losses, 'authorized')
30
+ end
9
31
  end
10
32
  end
11
33
  end
@@ -6,16 +6,13 @@ module Cats
6
6
  has_many :receipt_transactions
7
7
 
8
8
  validates :received_quantity, presence: true, numericality: { greater_than_or_equal_to: 0 }
9
- validate :validate_total_quantity
9
+ validate :validate_quantity
10
10
 
11
- def validate_total_quantity
12
- return unless dispatch && quantity
11
+ def validate_quantity
12
+ return unless dispatch && quantity && unit
13
13
 
14
- received = dispatch.receipt_authorizations.sum(:quantity)
15
- diff = dispatch.quantity - received
16
- diff += quantity_was if quantity_was
17
-
18
- errors.add(:quantity, "authorized is higher than dispatch quantity (Max = #{diff}).") if quantity > diff
14
+ authorizations = ReceiptAuthorization.where(dispatch: dispatch)
15
+ ValidationUtil.validate_quantity(self, 'dispatch', authorizations, 'dispatch')
19
16
  end
20
17
  end
21
18
  end
@@ -1,6 +1,8 @@
1
1
  module Cats
2
2
  module Core
3
3
  class ReceiptTransaction < Transaction
4
+ before_validation :set_unit
5
+
4
6
  belongs_to :receipt_authorization
5
7
  belongs_to :destination, class_name: 'Cats::Core::Stack'
6
8
 
@@ -11,6 +13,14 @@ module Cats
11
13
  delegate(:code, to: :destination, prefix: true)
12
14
  delegate(:dispatch_reference_no, to: :receipt_authorization)
13
15
 
16
+ def set_unit
17
+ return if unit
18
+
19
+ return unless receipt_authorization
20
+
21
+ self.unit = receipt_authorization.unit
22
+ end
23
+
14
24
  def validate_receipt
15
25
  return unless receipt_authorization
16
26
 
@@ -21,15 +31,13 @@ module Cats
21
31
  def validate_quantity
22
32
  return unless quantity && destination && receipt_authorization
23
33
 
24
- total = ReceiptTransaction.where(receipt_authorization: receipt_authorization).sum(:quantity)
25
- diff = receipt_authorization.quantity - total
26
- diff += quantity_was if quantity_was
27
- errors.add(:quantity, "exceeds authorized quantity (Max. = #{diff}).") if quantity > diff
34
+ transactions = ReceiptTransaction.where(receipt_authorization: receipt_authorization)
35
+ ValidationUtil.validate_quantity(self, 'receipt_authorization', transactions, 'authorized')
28
36
  end
29
37
 
30
38
  def commit
31
39
  ReceiptTransaction.transaction do
32
- destination.quantity += quantity
40
+ destination.quantity += UnitConversion.convert(unit, destination.unit, quantity)
33
41
  destination.stack_status = Cats::Core::Stack::ALLOCATED
34
42
  destination.save!
35
43
  self.status = COMMITTED