cats_core 1.5.2 → 1.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/cats/core/dispatch_authorizations_controller.rb +1 -1
  3. data/app/controllers/cats/core/dispatch_transactions_controller.rb +1 -1
  4. data/app/controllers/cats/core/lost_commodities_controller.rb +1 -1
  5. data/app/controllers/cats/core/receipt_authorizations_controller.rb +2 -1
  6. data/app/controllers/cats/core/receipt_transactions_controller.rb +2 -1
  7. data/app/controllers/cats/core/receipts_controller.rb +1 -1
  8. data/app/controllers/cats/core/stacks_controller.rb +1 -1
  9. data/app/models/cats/core/application_setting.rb +10 -0
  10. data/app/models/cats/core/authorization.rb +11 -0
  11. data/app/models/cats/core/commodity.rb +9 -0
  12. data/app/models/cats/core/dispatch.rb +4 -14
  13. data/app/models/cats/core/dispatch_authorization.rb +13 -0
  14. data/app/models/cats/core/dispatch_plan_item.rb +4 -3
  15. data/app/models/cats/core/dispatch_transaction.rb +23 -10
  16. data/app/models/cats/core/hub_authorization.rb +14 -9
  17. data/app/models/cats/core/lost_commodity.rb +27 -0
  18. data/app/models/cats/core/receipt.rb +20 -0
  19. data/app/models/cats/core/receipt_authorization.rb +5 -8
  20. data/app/models/cats/core/receipt_transaction.rb +13 -5
  21. data/app/models/cats/core/rhn_request.rb +24 -8
  22. data/app/models/cats/core/stack.rb +2 -0
  23. data/app/models/cats/core/stack_transaction.rb +1 -0
  24. data/app/models/cats/core/transaction.rb +2 -0
  25. data/app/models/cats/core/unit_conversion.rb +21 -3
  26. data/app/notifications/cats/core/dispatch_notification.rb +2 -0
  27. data/app/services/cats/core/authorization_service.rb +2 -0
  28. data/app/services/cats/core/dispatch_plan_service.rb +1 -0
  29. data/app/utils/cats/core/util.rb +9 -0
  30. data/app/utils/cats/core/validation_util.rb +20 -0
  31. data/db/migrate/20210717033223_create_cats_core_commodities.rb +5 -0
  32. data/db/migrate/20210717171101_create_cats_core_stacks.rb +4 -0
  33. data/db/migrate/20210718042755_create_cats_core_rhn_requests.rb +4 -0
  34. data/db/migrate/20210718045516_create_cats_core_dispatches.rb +1 -1
  35. data/db/migrate/20210718055414_create_cats_core_dispatch_authorizations.rb +4 -0
  36. data/db/migrate/20210718202957_create_cats_core_dispatch_transactions.rb +4 -0
  37. data/db/migrate/20210727074646_create_cats_core_receipt_authorizations.rb +4 -0
  38. data/db/migrate/20210727105834_create_cats_core_receipts.rb +4 -0
  39. data/db/migrate/20210728041505_create_cats_core_lost_commodities.rb +4 -0
  40. data/db/migrate/20210814160628_create_cats_core_receipt_transactions.rb +4 -0
  41. data/db/migrate/20210814175406_create_cats_core_stack_transactions.rb +4 -0
  42. data/db/migrate/20220209083928_create_cats_core_hub_authorizations.rb +4 -0
  43. data/db/migrate/20220923190857_create_cats_core_application_settings.rb +14 -0
  44. data/lib/cats/core/version.rb +1 -1
  45. data/spec/factories/cats/core/application_settings.rb +7 -0
  46. data/spec/factories/cats/core/commodities.rb +1 -0
  47. data/spec/factories/cats/core/dispatch_authorizations.rb +1 -0
  48. data/spec/factories/cats/core/dispatch_transactions.rb +5 -4
  49. data/spec/factories/cats/core/dispatches.rb +7 -1
  50. data/spec/factories/cats/core/hub_authorizations.rb +1 -0
  51. data/spec/factories/cats/core/lost_commodities.rb +1 -0
  52. data/spec/factories/cats/core/receipt_authorizations.rb +1 -0
  53. data/spec/factories/cats/core/receipt_transactions.rb +5 -1
  54. data/spec/factories/cats/core/receipts.rb +1 -0
  55. data/spec/factories/cats/core/rhn_requests.rb +1 -0
  56. data/spec/factories/cats/core/stack_transactions.rb +1 -0
  57. data/spec/factories/cats/core/stacks.rb +1 -0
  58. 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: 4b08867f616a2f760492e1a866ff5b0145babdb3099162319edd14b037bc4c10
4
+ data.tar.gz: 0b5237c0cd384b3b87b38b377bc87499d26e24fbd8fa1e31b48896730d313ce9
5
5
  SHA512:
6
- metadata.gz: 8dbba69e6545334259ca98493c13a2571754ff2d1eccf9ef6178e7a38105c319c3345106683415dc1654fa35c26d03df04ce7a072b235aa8e0e4c7f2afafd390
7
- data.tar.gz: 1e827e9172351fca12b42fc2910a639b2cb0556e64b1608bee56704892de22f39a897c03b0688a0cc1596b425c8ed5e41bbe9a894e20a3536f801b8d4e91bb2c
6
+ metadata.gz: 8764be6cd42ce15582359de5543f801b8b8d6f7974b15cbec6dc2bea649dba0ad698a9e44cbe60a4925ab5f8239c270cc9e4b6d01f9670e80417f214b77b68b0
7
+ data.tar.gz: 923adf41d9972d43697e7862697fc07ac9b76eab2706ea6c954612aa5467b86f24ddf515f3c5f54e4ec6e7495dba9c3286c05a1db5532fc952f7ccb183dd1fbb
@@ -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
@@ -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
@@ -10,7 +10,7 @@ module Cats
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
@@ -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
@@ -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
@@ -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
@@ -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_save :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 }
@@ -24,6 +26,14 @@ module Cats
24
26
  delegate(:plate_no, to: :dispatch)
25
27
  delegate(:driver_name, to: :dispatch)
26
28
 
29
+ def set_unit
30
+ return if unit
31
+
32
+ return unless dispatch
33
+
34
+ self.unit = dispatch.unit
35
+ end
36
+
27
37
  def validate_dispatch_status
28
38
  return unless dispatch
29
39
 
@@ -52,6 +62,7 @@ module Cats
52
62
  transactions.each(&:commit)
53
63
  self.status = CONFIRMED
54
64
  save!
65
+ reload
55
66
  if dispatch.all_authorizations_confirmed?
56
67
  dispatch.generate_pin
57
68
  dispatch.quantity = dispatch.dispatch_transactions.sum(:quantity)
@@ -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
@@ -57,6 +58,8 @@ module Cats
57
58
  delegate(:abbreviation, to: :unit_of_measure, prefix: 'unit')
58
59
  delegate(:code, to: :project, prefix: true)
59
60
 
61
+ alias_attribute :unit, :unit_of_measure
62
+
60
63
  def name
61
64
  # For this to be efficient, our query should use includes like
62
65
  # Commodity.includes(project: { source: commodity_category })
@@ -86,6 +89,7 @@ module Cats
86
89
  store: store,
87
90
  commodity: self,
88
91
  quantity: quantity,
92
+ unit: unit,
89
93
  commodity_status: GOOD,
90
94
  stack_status: Stack::ALLOCATED,
91
95
  length: 100,
@@ -98,6 +102,11 @@ module Cats
98
102
  end
99
103
  result
100
104
  end
105
+
106
+ def requested_quantity
107
+ requests = RhnRequest.where(commodity: self)
108
+ UnitConversion.harmonized_total(requests, unit_of_measure)
109
+ end
101
110
  end
102
111
  end
103
112
  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
@@ -131,7 +121,7 @@ module Cats
131
121
 
132
122
  def generate_pin
133
123
  pin = SecureRandom.hex(10)
134
- self.auth_details = { pin: pin, active: true, expires_at: DateTime.now + 1.hour }
124
+ self.auth_details = { pin: pin, active: true, expires_at: DateTime.now + 24.hour }
135
125
  save!
136
126
  end
137
127
  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
@@ -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_save :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_save :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 }
@@ -18,20 +21,22 @@ module Cats
18
21
  delegate(:full_name, to: :authorized_by, prefix: true)
19
22
  delegate(:name, to: :store, prefix: true)
20
23
 
21
- def validate_quantity
22
- return unless quantity
24
+ def set_unit
25
+ return if unit
23
26
 
24
27
  return unless dispatch_plan_item
25
28
 
26
- total = dispatch_plan_item.quantity
27
- used = HubAuthorization.where(
29
+ self.unit = dispatch_plan_item.unit
30
+ end
31
+
32
+ def validate_quantity
33
+ return unless quantity && unit && dispatch_plan_item
34
+
35
+ authorizations = HubAuthorization.where(
28
36
  dispatch_plan_item: dispatch_plan_item,
29
37
  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
38
+ )
39
+ ValidationUtil.validate_quantity(self, 'dispatch_plan_item', authorizations, 'allocated')
35
40
  end
36
41
  end
37
42
  end
@@ -1,9 +1,36 @@
1
1
  module Cats
2
2
  module Core
3
3
  class LostCommodity < ApplicationRecord
4
+ before_save :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
+ def set_unit
13
+ return if unit
14
+
15
+ return unless receipt_authorization
16
+
17
+ self.unit = receipt_authorization.unit
18
+ end
19
+
20
+ def validate_quantity
21
+ return unless quantity && unit && receipt_authorization
22
+
23
+ total = UnitConversion.convert(receipt_authorization.unit, unit, receipt_authorization.quantity)
24
+ receipts = Receipt.where(receipt_authorization: receipt_authorization)
25
+ losses = LostCommodity.where(receipt_authorization: receipt_authorization)
26
+ used = UnitConversion.harmonized_total(receipts, unit) + UnitConversion.harmonized_total(losses, unit)
27
+ used -= quantity_was if quantity_was
28
+
29
+ remaining = total - used
30
+ return unless quantity > remaining
31
+
32
+ errors.add(:quantity, "exceeds authorized quantity. Maximum allowed is #{remaining} #{unit.abbreviation}")
33
+ end
7
34
  end
8
35
  end
9
36
  end
@@ -1,11 +1,31 @@
1
1
  module Cats
2
2
  module Core
3
3
  class Receipt < ApplicationRecord
4
+ before_save :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
+ 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
+ receipts = Receipt.where(receipt_authorization: receipt_authorization)
26
+ losses = LostCommodity.where(receipt_authorization: receipt_authorization)
27
+ ValidationUtil.validate_quantity(self, 'receipt_authorization', receipts + losses, 'authorized')
28
+ end
9
29
  end
10
30
  end
11
31
  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_save :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
@@ -3,13 +3,13 @@ module Cats
3
3
  class RhnRequest < ApplicationRecord
4
4
  include Dispatchable
5
5
 
6
- # DRAFT = 'Draft'.freeze
7
- # APPROVED = 'Approved'.freeze
8
- # RESERVED = 'Reserved'.freeze
6
+ before_save :set_unit
7
+
9
8
  ALLOCATED = 'Allocated'.freeze
10
9
  STATUSES << ALLOCATED
11
10
 
12
11
  belongs_to :commodity
12
+ belongs_to :unit, class_name: 'Cats::Core::UnitOfMeasure'
13
13
 
14
14
  validates :reference_no, :request_date, :quantity, presence: true
15
15
  validates :reference_no, uniqueness: true
@@ -19,6 +19,14 @@ module Cats
19
19
 
20
20
  delegate(:batch_no, to: :commodity, prefix: true)
21
21
 
22
+ def set_unit
23
+ return if unit
24
+
25
+ return unless commodity
26
+
27
+ self.unit = commodity.unit
28
+ end
29
+
22
30
  def request_reference
23
31
  reference_no
24
32
  end
@@ -34,13 +42,21 @@ module Cats
34
42
  end
35
43
 
36
44
  def validate_quantity
37
- return unless commodity && quantity
45
+ return unless commodity && quantity && unit
38
46
 
39
- requested = RhnRequest.where(commodity: commodity).sum(:quantity)
40
- remaining = commodity.quantity - requested
47
+ requested = commodity.requested_quantity
41
48
 
42
- remaining += quantity_was if quantity_was
43
- errors.add(:quantity, "exceeds commodity quantity. Maximum allowed is #{remaining}") if quantity > remaining
49
+ remaining = commodity.quantity - requested
50
+ if quantity_was
51
+ additional = UnitConversion.convert(unit, commodity.unit_of_measure, quantity_was)
52
+ remaining += additional
53
+ end
54
+ new_quantity = UnitConversion.convert(unit, commodity.unit_of_measure, quantity)
55
+ return unless new_quantity > remaining
56
+
57
+ remaining = UnitConversion.convert(commodity.unit_of_measure, unit, remaining)
58
+ message = "exceeds commodity quantity. Maximum allowed is #{remaining} #{unit.abbreviation}"
59
+ errors.add(:quantity, message)
44
60
  end
45
61
 
46
62
  def approve
@@ -9,6 +9,8 @@ module Cats
9
9
 
10
10
  belongs_to :commodity
11
11
  belongs_to :store
12
+ belongs_to :unit, class_name: 'Cats::Core::UnitOfMeasure'
13
+
12
14
  has_many :dispatch_transactions, foreign_key: :source_id
13
15
  has_many :receipt_transactions, foreign_key: :destination_id
14
16
 
@@ -3,6 +3,7 @@ module Cats
3
3
  class StackTransaction < Transaction
4
4
  belongs_to :source, class_name: 'Cats::Core::Stack'
5
5
  belongs_to :destination, class_name: 'Cats::Core::Stack'
6
+ belongs_to :unit, class_name: 'Cats::Core::UnitOfMeasure'
6
7
 
7
8
  def validate_quantity
8
9
  return unless quantity.present? && source.present?
@@ -9,6 +9,8 @@ module Cats
9
9
  COMMITTED = 'Committed'.freeze
10
10
  STATUSES = [DRAFT, COMMITTED].freeze
11
11
 
12
+ belongs_to :unit, class_name: 'Cats::Core::UnitOfMeasure'
13
+
12
14
  validates :transaction_date, :quantity, :status, presence: true
13
15
  validates :quantity, numericality: { greater_than: 0 }
14
16
  validates :status, inclusion: { in: STATUSES }
@@ -15,10 +15,28 @@ module Cats
15
15
  return value if from == to
16
16
 
17
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
18
+ return value * conversion.factor if conversion
20
19
 
21
- value * conversion.factor
20
+ # Check if there is reverse conversion entry defined
21
+ conversion = find_by(from: to, to: from)
22
+ unless conversion
23
+ raise(StandardError, "Conversion factor between #{from.abbreviation} and #{to.abbreviation} not found.")
24
+ end
25
+
26
+ value / conversion.factor
27
+ end
28
+
29
+ ##
30
+ # This function calculates the sum of quantities of a list of objects with quantities and different
31
+ # units into one. The list can be a list of hub authorizations, RHN requests, dispatch plan items,
32
+ # etc ... This method assumes that quantity is represented by the attribute <tt>quantity</tt> and unit of
33
+ # measure is represented by the attribute <tt>unit</tt> for each object in the object list. If that is not
34
+ # true then one should create those two attributes as aliases in the respective models.
35
+ #
36
+ def self.harmonized_total(list, unit)
37
+ list.inject(0) do |res, obj|
38
+ res + UnitConversion.convert(obj.unit, unit, obj.quantity)
39
+ end
22
40
  end
23
41
  end
24
42
  end
@@ -12,11 +12,13 @@ module Cats
12
12
  date = Date.today
13
13
  body = <<~BODY
14
14
  Commodity with the following details has been dispatched to you:
15
+ Authorization no. = #{dispatch.dispatch_plan_item.reference_no}
15
16
  Dispatch Ref. = #{dispatch.reference_no}
16
17
  Batch No. = #{commodity.batch_no}
17
18
  Commodity = #{commodity.name}
18
19
  Allocated Quantity = #{dispatch.dispatch_plan_item.quantity}
19
20
  Quantity = #{dispatch.quantity}
21
+ Unit = #{dispatch.unit.abbreviation}
20
22
  Truck Plate No. = #{dispatch.plate_no}
21
23
  Driver Name = #{dispatch.driver_name}
22
24
  Driver Phone = #{dispatch.driver_phone}
@@ -46,6 +46,7 @@ module Cats
46
46
  start_x: 2,
47
47
  start_y: 2,
48
48
  commodity: commodity,
49
+ unit: commodity.package_unit,
49
50
  store: authorization.store,
50
51
  commodity_status: Commodity::GOOD,
51
52
  stack_status: Stack::ALLOCATED
@@ -54,6 +55,7 @@ module Cats
54
55
  receipt_authorization: authorization,
55
56
  destination: stack,
56
57
  quantity: authorization.received_quantity,
58
+ unit: authorization.unit,
57
59
  status: Transaction::DRAFT,
58
60
  transaction_date: Date.today
59
61
  )
@@ -15,6 +15,7 @@ module Cats
15
15
  dispatch_plan_item_id: item.id,
16
16
  store_id: store.id,
17
17
  quantity: item.quantity,
18
+ unit_id: item.unit_id,
18
19
  authorization_type: HubAuthorization::SOURCE,
19
20
  authorized_by_id: keeper.id,
20
21
  created_at: Date.today,
@@ -0,0 +1,9 @@
1
+ module Cats
2
+ module Core
3
+ class Util
4
+ def self.send_chain(obj, arr)
5
+ arr.inject(obj) { |o, a| o.send(a) }
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ module Cats
2
+ module Core
3
+ class ValidationUtil
4
+ def self.validate_quantity(obj, parent_attr, relation, error_key, quantity_attribs = nil, unit_attribs = nil)
5
+ parent = obj.send(parent_attr)
6
+ quantity = quantity_attribs ? Util.send_chain(parent, quantity_attribs) : parent.quantity
7
+ unit = unit_attribs ? Util.send_chain(parent, unit_attribs) : parent.unit
8
+ total = UnitConversion.convert(unit, obj.unit, quantity)
9
+ used = UnitConversion.harmonized_total(relation, obj.unit)
10
+ used -= obj.quantity_was if obj.quantity_was
11
+
12
+ remaining = total - used
13
+ return unless obj.quantity > remaining
14
+
15
+ error = "exceeds #{error_key} quantity. Maximum allowed is #{remaining} #{obj.unit.abbreviation}"
16
+ obj.errors.add(:quantity, error)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -10,6 +10,11 @@ class CreateCatsCoreCommodities < ActiveRecord::Migration[6.1]
10
10
  null: false,
11
11
  index: { name: 'project_on_commodity_indx' },
12
12
  foreign_key: { to_table: :cats_core_projects }
13
+ t.references :package_unit,
14
+ null: true,
15
+ index: { name: 'pu_on_commodity_indx' },
16
+ foreign_key: { to_table: :cats_core_unit_of_measures }
17
+
13
18
  t.float :quantity, null: false
14
19
  t.string :description
15
20
  t.date :best_use_before, null: false
@@ -18,6 +18,10 @@ class CreateCatsCoreStacks < ActiveRecord::Migration[6.1]
18
18
  t.string :commodity_status, null: false, default: 'Good'
19
19
  t.string :stack_status, null: false, default: 'Reserved'
20
20
  t.float :quantity, null: false, default: 0
21
+ t.references :unit,
22
+ null: false,
23
+ index: { name: 'unit_on_stack_indx' },
24
+ foreign_key: { to_table: :cats_core_unit_of_measures }
21
25
 
22
26
  t.timestamps
23
27
  end
@@ -7,6 +7,10 @@ class CreateCatsCoreRhnRequests < ActiveRecord::Migration[6.1]
7
7
  index: { name: 'commodity_on_rhn_indx' },
8
8
  foreign_key: { to_table: :cats_core_commodities }
9
9
  t.float :quantity, null: false
10
+ t.references :unit,
11
+ null: false,
12
+ index: { name: 'unit_on_rhn_indx' },
13
+ foreign_key: { to_table: :cats_core_unit_of_measures }
10
14
  t.date :request_date, null: false
11
15
  t.string :requested_by
12
16
 
@@ -17,7 +17,7 @@ class CreateCatsCoreDispatches < ActiveRecord::Migration[6.1]
17
17
  t.references :unit,
18
18
  null: false,
19
19
  index: { name: 'unit_on_dispatches_indx' },
20
- foreign_key: { to_table: :cats_core_unit_of_measures }
20
+ foreign_key: { to_table: :cats_core_unit_of_measures }
21
21
  t.string :commodity_status, null: false, default: 'Good'
22
22
  t.string :remark
23
23
  t.references :prepared_by,
@@ -10,6 +10,10 @@ class CreateCatsCoreDispatchAuthorizations < ActiveRecord::Migration[7.0]
10
10
  index: { name: 'store_on_da_indx' },
11
11
  foreign_key: { to_table: :cats_core_stores }
12
12
  t.float :quantity, null: false
13
+ t.references :unit,
14
+ null: false,
15
+ index: { name: 'unit_on_da_indx' },
16
+ foreign_key: { to_table: :cats_core_unit_of_measures }
13
17
  t.string :status, null: false, default: 'Authorized'
14
18
  t.references :authorized_by,
15
19
  null: false,
@@ -11,6 +11,10 @@ class CreateCatsCoreDispatchTransactions < ActiveRecord::Migration[6.1]
11
11
  foreign_key: { to_table: :cats_core_dispatch_authorizations }
12
12
  t.date :transaction_date, null: false
13
13
  t.float :quantity, null: false
14
+ t.references :unit,
15
+ null: false,
16
+ index: { name: 'unit_on_dt_indx' },
17
+ foreign_key: { to_table: :cats_core_unit_of_measures }
14
18
  t.string :status, null: false, default: 'Draft'
15
19
 
16
20
  t.timestamps
@@ -10,6 +10,10 @@ class CreateCatsCoreReceiptAuthorizations < ActiveRecord::Migration[6.1]
10
10
  index: { name: 'store_on_ra_indx' },
11
11
  foreign_key: { to_table: :cats_core_stores }
12
12
  t.float :quantity, null: false
13
+ t.references :unit,
14
+ null: false,
15
+ index: { name: 'r_unit_on_da_indx' },
16
+ foreign_key: { to_table: :cats_core_unit_of_measures }
13
17
  t.float :received_quantity, null: false, default: 0
14
18
  t.string :status, null: false, default: 'Authorized'
15
19
  t.string :remark
@@ -8,6 +8,10 @@ class CreateCatsCoreReceipts < ActiveRecord::Migration[7.0]
8
8
  t.string :commodity_status, null: false
9
9
  t.string :commodity_grade
10
10
  t.float :quantity, null: false
11
+ t.references :unit,
12
+ null: false,
13
+ index: { name: 'unit_on_receipts_indx' },
14
+ foreign_key: { to_table: :cats_core_unit_of_measures }
11
15
  t.string :remark
12
16
 
13
17
  t.timestamps
@@ -6,6 +6,10 @@ class CreateCatsCoreLostCommodities < ActiveRecord::Migration[7.0]
6
6
  index: { name: 'ra_on_lc_indx' },
7
7
  foreign_key: { to_table: :cats_core_receipt_authorizations }
8
8
  t.float :quantity, null: false
9
+ t.references :unit,
10
+ null: false,
11
+ index: { name: 'unit_on_lc_indx' },
12
+ foreign_key: { to_table: :cats_core_unit_of_measures }
9
13
  t.string :remark
10
14
 
11
15
  t.timestamps
@@ -11,6 +11,10 @@ class CreateCatsCoreReceiptTransactions < ActiveRecord::Migration[6.1]
11
11
  foreign_key: { to_table: :cats_core_stacks }
12
12
  t.date :transaction_date, null: false
13
13
  t.float :quantity, null: false
14
+ t.references :unit,
15
+ null: false,
16
+ index: { name: 'r_unit_on_dt_indx' },
17
+ foreign_key: { to_table: :cats_core_unit_of_measures }
14
18
  t.string :status, null: false, default: 'Draft'
15
19
 
16
20
  t.timestamps
@@ -11,6 +11,10 @@ class CreateCatsCoreStackTransactions < ActiveRecord::Migration[6.1]
11
11
  foreign_key: { to_table: :cats_core_stacks }
12
12
  t.date :transaction_date, null: false
13
13
  t.float :quantity, null: false
14
+ t.references :unit,
15
+ null: false,
16
+ index: { name: 'unit_on_st_indx' },
17
+ foreign_key: { to_table: :cats_core_unit_of_measures }
14
18
  t.string :status, null: false, default: 'Draft'
15
19
 
16
20
  t.timestamps
@@ -10,6 +10,10 @@ class CreateCatsCoreHubAuthorizations < ActiveRecord::Migration[7.0]
10
10
  index: { name: 'store_on_ha_indx' },
11
11
  foreign_key: { to_table: :cats_core_stores }
12
12
  t.float :quantity, null: false
13
+ t.references :unit,
14
+ null: false,
15
+ index: { name: 'unit_on_ha_indx' },
16
+ foreign_key: { to_table: :cats_core_unit_of_measures }
13
17
  t.string :authorization_type, null: false
14
18
  t.references :authorized_by,
15
19
  null: false,
@@ -0,0 +1,14 @@
1
+ class CreateCatsCoreApplicationSettings < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :cats_core_application_settings do |t|
4
+ t.string :key, unique: true
5
+ t.string :value, null: false
6
+ t.references :application_module,
7
+ null: false,
8
+ index: { name: 'am_on_as_indx' },
9
+ foreign_key: { to_table: :cats_core_application_modules }
10
+
11
+ t.timestamps
12
+ end
13
+ end
14
+ end
@@ -1,5 +1,5 @@
1
1
  module Cats
2
2
  module Core
3
- VERSION = '1.5.2'.freeze
3
+ VERSION = '1.5.3'.freeze
4
4
  end
5
5
  end
@@ -0,0 +1,7 @@
1
+ FactoryBot.define do
2
+ factory :application_setting, class: 'Cats::Core::ApplicationSetting' do
3
+ key { FFaker::Name.name }
4
+ value { FFaker::Name.name }
5
+ application_module
6
+ end
7
+ end
@@ -3,6 +3,7 @@ FactoryBot.define do
3
3
  batch_no { FFaker::Name.name }
4
4
  description { FFaker::Name.name }
5
5
  unit_of_measure
6
+ package_unit factory: :unit_of_measure
6
7
  project
7
8
  quantity { 100 }
8
9
  best_use_before { Date.today + 2.month }
@@ -7,6 +7,7 @@ FactoryBot.define do
7
7
  dispatch
8
8
  store { s }
9
9
  quantity { 100 }
10
+ unit { dispatch.unit }
10
11
  status { Cats::Core::ReceiptAuthorization::AUTHORIZED }
11
12
  authorized_by factory: :user
12
13
 
@@ -1,12 +1,13 @@
1
1
  FactoryBot.define do
2
2
  factory :dispatch_transaction, class: 'Cats::Core::DispatchTransaction' do
3
- transient do
4
- stack { create(:stack) }
5
- end
6
- source { stack }
7
3
  association :dispatch_authorization, :approved
4
+ source do
5
+ create(:stack, unit: dispatch_authorization.unit)
6
+ end
7
+
8
8
  transaction_date { Date.today }
9
9
  quantity { 100 }
10
+ unit { dispatch_authorization.unit }
10
11
  status { Cats::Core::Transaction::DRAFT }
11
12
  end
12
13
  end
@@ -10,7 +10,7 @@ FactoryBot.define do
10
10
  create(:hub_authorization, dispatch_plan_item: plan_item, quantity: 100, store: stack.store)
11
11
  plan_item
12
12
  end
13
- unit factory: :unit_of_measure
13
+ unit { dispatch_plan_item.unit }
14
14
  transporter
15
15
  plate_no { FFaker::Name.name }
16
16
  driver_name { FFaker::Name.name }
@@ -29,6 +29,8 @@ FactoryBot.define do
29
29
  after(:create) do |dispatch, options|
30
30
  authorization = create(:dispatch_authorization, dispatch: dispatch, store: options.stack.store)
31
31
  dispatch.approve
32
+ options.stack.unit = dispatch.unit
33
+ options.stack.save!
32
34
  create(:dispatch_transaction, dispatch_authorization: authorization, source: options.stack, quantity: 100)
33
35
  end
34
36
  end
@@ -37,6 +39,8 @@ FactoryBot.define do
37
39
  after(:create) do |dispatch, options|
38
40
  authorization = create(:dispatch_authorization, dispatch: dispatch, store: options.stack.store)
39
41
  dispatch.approve
42
+ options.stack.unit = dispatch.unit
43
+ options.stack.save!
40
44
  create(:dispatch_transaction, dispatch_authorization: authorization, source: options.stack, quantity: 100)
41
45
  authorization.confirm
42
46
  dispatch.quantity = 100
@@ -49,6 +53,8 @@ FactoryBot.define do
49
53
  after(:create) do |dispatch, options|
50
54
  authorization = create(:dispatch_authorization, dispatch: dispatch, store: options.stack.store)
51
55
  dispatch.approve
56
+ options.stack.unit = dispatch.unit
57
+ options.stack.save!
52
58
  create(:dispatch_transaction, dispatch_authorization: authorization, source: options.stack, quantity: 100)
53
59
  authorization.confirm
54
60
  dispatch.quantity = 100
@@ -3,6 +3,7 @@ FactoryBot.define do
3
3
  dispatch_plan_item
4
4
  store
5
5
  quantity { 100 }
6
+ unit { dispatch_plan_item.unit }
6
7
  authorization_type { Cats::Core::HubAuthorization::SOURCE }
7
8
  authorized_by factory: :user
8
9
  end
@@ -2,6 +2,7 @@ FactoryBot.define do
2
2
  factory :lost_commodity, class: 'Cats::Core::LostCommodity' do
3
3
  receipt_authorization
4
4
  quantity { 100 }
5
+ unit { receipt_authorization.unit }
5
6
  remark { FFaker::Name.name }
6
7
  end
7
8
  end
@@ -3,6 +3,7 @@ FactoryBot.define do
3
3
  association :dispatch, :started
4
4
  store
5
5
  quantity { 100 }
6
+ unit { dispatch.unit }
6
7
  received_quantity { 0 }
7
8
  remark { FFaker::Name.name }
8
9
  status { Cats::Core::ReceiptAuthorization::AUTHORIZED }
@@ -1,9 +1,13 @@
1
1
  FactoryBot.define do
2
2
  factory :receipt_transaction, class: 'Cats::Core::ReceiptTransaction' do
3
3
  association :receipt_authorization, :confirmed
4
- destination factory: :stack
4
+ destination do
5
+ create(:stack, unit: receipt_authorization.unit)
6
+ end
7
+
5
8
  transaction_date { Date.today }
6
9
  quantity { 100 }
10
+ unit { receipt_authorization.unit }
7
11
  status { Cats::Core::Transaction::DRAFT }
8
12
  end
9
13
  end
@@ -3,6 +3,7 @@ FactoryBot.define do
3
3
  receipt_authorization
4
4
  commodity_status { Cats::Core::Commodity::GOOD }
5
5
  quantity { 50 }
6
+ unit { receipt_authorization.unit }
6
7
  remark { FFaker::Name.name }
7
8
  end
8
9
  end
@@ -6,6 +6,7 @@ FactoryBot.define do
6
6
  c.approve
7
7
  c
8
8
  end
9
+ unit { commodity.unit_of_measure }
9
10
  quantity { 100 }
10
11
  request_date { Date.today }
11
12
  requested_by { FFaker::Name.name }
@@ -4,6 +4,7 @@ FactoryBot.define do
4
4
  destination factory: :stack
5
5
  transaction_date { Date.today }
6
6
  quantity { 25 }
7
+ unit { source.unit }
7
8
  status { Cats::Core::Transaction::DRAFT }
8
9
  end
9
10
  end
@@ -11,5 +11,6 @@ FactoryBot.define do
11
11
  commodity_status { Cats::Core::Commodity::GOOD }
12
12
  stack_status { Cats::Core::Stack::RESERVED }
13
13
  quantity { 100 }
14
+ unit { commodity.package_unit }
14
15
  end
15
16
  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.5.2
4
+ version: 1.5.3
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-07-17 00:00:00.000000000 Z
11
+ date: 2022-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: active_model_serializers
@@ -282,6 +282,7 @@ files:
282
282
  - app/jobs/cats/core/application_job.rb
283
283
  - app/models/cats/core/application_module.rb
284
284
  - app/models/cats/core/application_record.rb
285
+ - app/models/cats/core/application_setting.rb
285
286
  - app/models/cats/core/authorization.rb
286
287
  - app/models/cats/core/beneficiary.rb
287
288
  - app/models/cats/core/beneficiary_category.rb
@@ -398,6 +399,8 @@ files:
398
399
  - app/services/cats/core/space_service.rb
399
400
  - app/services/cats/core/stack_service.rb
400
401
  - app/services/cats/core/token_auth_service.rb
402
+ - app/utils/cats/core/util.rb
403
+ - app/utils/cats/core/validation_util.rb
401
404
  - config/routes.rb
402
405
  - db/migrate/20210715114238_create_cats_core_application_modules.rb
403
406
  - db/migrate/20210715114910_create_cats_core_users.rb
@@ -471,12 +474,14 @@ files:
471
474
  - db/migrate/20220626063501_create_cats_core_loans.rb
472
475
  - db/migrate/20220626063757_create_cats_core_swaps.rb
473
476
  - db/migrate/20220626132050_create_cats_core_round_beneficiaries.rb
477
+ - db/migrate/20220923190857_create_cats_core_application_settings.rb
474
478
  - lib/cats/core.rb
475
479
  - lib/cats/core/engine.rb
476
480
  - lib/cats/core/version.rb
477
481
  - lib/cats_core.rb
478
482
  - lib/tasks/cats_core_tasks.rake
479
483
  - spec/factories/cats/core/application_modules.rb
484
+ - spec/factories/cats/core/application_settings.rb
480
485
  - spec/factories/cats/core/beneficiaries.rb
481
486
  - spec/factories/cats/core/beneficiary_categories.rb
482
487
  - spec/factories/cats/core/beneficiary_plan_items.rb