cats_core 1.5.2 → 1.5.3

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