cats_core 1.5.2 → 1.5.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 (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