cats_core 1.4.19 → 1.4.22

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/cats/core/dispatch_authorizations_controller.rb +27 -0
  3. data/app/controllers/cats/core/dispatch_plan_items_controller.rb +2 -2
  4. data/app/controllers/cats/core/dispatch_transactions_controller.rb +4 -4
  5. data/app/controllers/cats/core/dispatches_controller.rb +2 -2
  6. data/app/controllers/cats/core/receipt_authorizations_controller.rb +28 -0
  7. data/app/controllers/cats/core/receipt_transactions_controller.rb +2 -20
  8. data/app/models/cats/core/authorization.rb +65 -0
  9. data/app/models/cats/core/dispatch.rb +44 -44
  10. data/app/models/cats/core/dispatch_authorization.rb +13 -0
  11. data/app/models/cats/core/dispatch_plan_item.rb +1 -0
  12. data/app/models/cats/core/dispatch_transaction.rb +39 -2
  13. data/app/models/cats/core/receipt_authorization.rb +26 -0
  14. data/app/models/cats/core/receipt_transaction.rb +16 -14
  15. data/app/models/cats/core/stack.rb +19 -0
  16. data/app/models/cats/core/transaction.rb +0 -30
  17. data/app/models/cats/core/transport_order.rb +1 -1
  18. data/app/serializers/cats/core/dispatch_authorization_serializer.rb +8 -0
  19. data/app/serializers/cats/core/dispatch_plan_item_serializer.rb +1 -1
  20. data/app/serializers/cats/core/dispatch_transaction_serializer.rb +1 -2
  21. data/app/serializers/cats/core/receipt_authorization_serializer.rb +8 -0
  22. data/app/serializers/cats/core/receipt_transaction_serializer.rb +2 -2
  23. data/config/routes.rb +16 -8
  24. data/db/migrate/20210718043401_create_cats_core_dispatch_plan_items.rb +1 -0
  25. data/db/migrate/20210718045516_create_cats_core_dispatches.rb +4 -0
  26. data/db/migrate/20210718055414_create_cats_core_dispatch_authorizations.rb +22 -0
  27. data/db/migrate/20210718202957_create_cats_core_dispatch_transactions.rb +9 -3
  28. data/db/migrate/20210727074646_create_cats_core_receipt_authorizations.rb +24 -0
  29. data/db/migrate/20210814160628_create_cats_core_receipt_transactions.rb +3 -3
  30. data/lib/cats/core/version.rb +1 -1
  31. data/spec/factories/cats/core/dispatch_authorizations.rb +26 -0
  32. data/spec/factories/cats/core/dispatch_plan_items.rb +1 -0
  33. data/spec/factories/cats/core/dispatch_transactions.rb +2 -7
  34. data/spec/factories/cats/core/dispatches.rb +22 -3
  35. data/spec/factories/cats/core/receipt_authorizations.rb +19 -0
  36. data/spec/factories/cats/core/receipt_transactions.rb +2 -22
  37. data/spec/factories/cats/core/routes.rb +1 -1
  38. data/spec/factories/cats/core/stacks.rb +1 -1
  39. metadata +13 -7
  40. data/app/controllers/cats/core/receipts_controller.rb +0 -45
  41. data/app/models/cats/core/receipt.rb +0 -44
  42. data/app/services/cats/core/receipt_service.rb +0 -48
  43. data/db/migrate/20210727074646_create_cats_core_receipts.rb +0 -20
  44. data/spec/factories/cats/core/receipts.rb +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f2cc951417c8b5c1586ad4deb540c51e54177eac53c54a689f31c35bfbfbb67
4
- data.tar.gz: f25cbb325f2eb8b8c9081ec0660b3c3028fe45ee0b7f003c40e96c91cdfebd15
3
+ metadata.gz: a3a896be87ee316cd08b40a298effac694bfb59e1207699c50675b4242e0f630
4
+ data.tar.gz: 3b6d584ce3eacbf6a0f3ffda03c399d84db2c5bf3931666107cf9d7fd014e3ca
5
5
  SHA512:
6
- metadata.gz: 610169114a8fd878d1fd47b771f55a5bfef3e79c3d660b8148642a8fd9def6e018f4cea2b6cda50ee381970f2bee3e9e98ff5d5f0a3f66436d340b8334e4bf75
7
- data.tar.gz: b0d90834aba82fd86dfb53bd6b51a875ff1131c4a3096813d6132efc860915e89ea4dd63c7272518158af8c0d21b355557e055b86d08938e82f063ce743a8f0a
6
+ metadata.gz: 234470131214a8e68da2123957a811c55c41c38079c34ec9dde9b9313c0d85c7b88607da5b0a3d7a2dd98f1c2f39942f5790a858d21eb76595a9f0572578d3a5
7
+ data.tar.gz: 4f3e4040eff76a430bbcaf24ec3bae51dc54905831f744f23802905c4d6df80cc440184de47c9398be98051be81519010cf4ca9e3818817a3b1fc67b9cd3dda8
@@ -0,0 +1,27 @@
1
+ module Cats
2
+ module Core
3
+ class DispatchAuthorizationsController < ApplicationController
4
+ include Common
5
+
6
+ def index
7
+ super do
8
+ DispatchAuthorization.where(dispatch_id: params[:id])
9
+ end
10
+ end
11
+
12
+ def confirm
13
+ authorization = DispatchAuthorization.find(params[:id])
14
+ authorization.confirm
15
+ render json: { success: true, data: serialize(authorization) }
16
+ rescue StandardError => e
17
+ render json: { success: false, error: e.message }
18
+ end
19
+
20
+ private
21
+
22
+ def model_params
23
+ params.require(:payload).permit(:dispatch_id, :store_id, :quantity, :status, :authorized_by_id)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -17,8 +17,8 @@ module Cats
17
17
  private
18
18
 
19
19
  def model_params
20
- params.require(:payload).permit(:dispatch_plan_id, :source_id, :destination_id, :quantity, :commodity_status,
21
- :status, :commodity_id)
20
+ params.require(:payload).permit(:reference_no, :dispatch_plan_id, :source_id, :destination_id, :quantity,
21
+ :commodity_status, :status, :commodity_id)
22
22
  end
23
23
  end
24
24
  end
@@ -5,7 +5,7 @@ module Cats
5
5
 
6
6
  def index
7
7
  super do
8
- DispatchTransaction.where(dispatch_id: params[:id])
8
+ DispatchTransaction.where(dispatch_authorization_id: params[:id])
9
9
  end
10
10
  end
11
11
 
@@ -14,8 +14,8 @@ module Cats
14
14
  # stack is a dummy one and we need to use that without waiting for the
15
15
  # user to give us a source.
16
16
  def create_allocation
17
- dispatch = Dispatch.find(model_params[:dispatch_id])
18
- commodity = dispatch.dispatch_plan_item.commodity
17
+ authorization = DispatchAuthorization.find(model_params[:dispatch_authorization_id])
18
+ commodity = authorization.dispatch.dispatch_plan_item.commodity
19
19
  transaction = DispatchTransaction.new(model_params)
20
20
 
21
21
  # Fetch supplier stack by commodity
@@ -32,7 +32,7 @@ module Cats
32
32
  private
33
33
 
34
34
  def model_params
35
- params.require(:payload).permit(:source_id, :dispatch_id, :transaction_date, :quantity)
35
+ params.require(:payload).permit(:source_id, :dispatch_authorization_id, :transaction_date, :quantity)
36
36
  end
37
37
  end
38
38
  end
@@ -60,8 +60,8 @@ module Cats
60
60
  end
61
61
 
62
62
  def model_params
63
- params.require(:payload).permit(:reference_no, :dispatch_plan_item_id, :transporter_id, :plate_no,
64
- :driver_name, :driver_phone, :quantity, :remark)
63
+ params.require(:payload).permit(:reference_no, :dispatch_plan_item_id, :transporter_id, :plate_no, :unit_id,
64
+ :driver_name, :driver_phone, :remark)
65
65
  end
66
66
  end
67
67
  end
@@ -0,0 +1,28 @@
1
+ module Cats
2
+ module Core
3
+ class ReceiptAuthorizationsController < ApplicationController
4
+ include Common
5
+
6
+ def index
7
+ super do
8
+ ReceiptAuthorization.where(dispatch_id: params[:id])
9
+ end
10
+ end
11
+
12
+ def confirm
13
+ authorization = ReceiptAuthorization.find(params[:id])
14
+ authorization.confirm
15
+ render json: { success: true, data: serialize(authorization) }
16
+ rescue StandardError => e
17
+ render json: { success: false, error: e.message }
18
+ end
19
+
20
+ private
21
+
22
+ def model_params
23
+ params.require(:payload).permit(:dispatch_id, :store_id, :quantity, :lost_quantity, :remark, :status,
24
+ :authorized_by_id)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -5,32 +5,14 @@ module Cats
5
5
 
6
6
  def index
7
7
  super do
8
- ReceiptTransaction.where(receipt_id: params[:id])
9
- end
10
- end
11
-
12
- def create
13
- super do
14
- p = model_params
15
-
16
- # Look for a transaction with the same destination as incoming
17
- transaction = ReceiptTransaction.find_by(
18
- receipt_id: p[:receipt_id],
19
- destination_id: p[:destination_id]
20
- )
21
- if transaction
22
- transaction.quantity += p[:quantity]
23
- else
24
- transaction = ReceiptTransaction.new(p)
25
- end
26
- transaction
8
+ ReceiptTransaction.joins(receipt_authorization: :dispatch).where(receipt_authorization_id: params[:id])
27
9
  end
28
10
  end
29
11
 
30
12
  private
31
13
 
32
14
  def model_params
33
- params.require(:payload).permit(:receipt_id, :destination_id, :transaction_date, :quantity)
15
+ params.require(:payload).permit(:receipt_authorization_id, :destination_id, :transaction_date, :quantity)
34
16
  end
35
17
  end
36
18
  end
@@ -0,0 +1,65 @@
1
+ module Cats
2
+ module Core
3
+ class Authorization < ApplicationRecord
4
+ self.abstract_class = true
5
+ after_initialize :set_status
6
+
7
+ # Authorization statuses
8
+ AUTHORIZED = 'Authorized'.freeze
9
+ CONFIRMED = 'Confirmed'.freeze
10
+ STATUSES = [AUTHORIZED, CONFIRMED].freeze
11
+
12
+ belongs_to :dispatch
13
+ belongs_to :store
14
+ belongs_to :authorized_by, class_name: 'Cats::Core::User'
15
+
16
+ validates :quantity, presence: true, numericality: { greater_than: 0 }
17
+ validates :status, presence: true, inclusion: { in: STATUSES }
18
+ validate :validate_dispatch_status, if: -> { status == AUTHORIZED }
19
+
20
+ delegate(:full_name, to: :authorized_by, prefix: :authorizer)
21
+ delegate(:name, to: :store, prefix: true)
22
+ delegate(:reference_no, to: :dispatch, prefix: true)
23
+
24
+ def validate_dispatch_status
25
+ return unless dispatch
26
+
27
+ if instance_of?(DispatchAuthorization)
28
+ errors.add(:dispatch, 'is not in draft state.') unless dispatch.dispatch_status == Dispatch::DRAFT
29
+ else
30
+ return if dispatch.dispatch_status == Cats::Core::Dispatch::STARTED
31
+
32
+ errors.add(:dispatch, 'should be in "Started" state.')
33
+ end
34
+ end
35
+
36
+ # A convenience method to return dispatch or receipt transactions based on the
37
+ # authorization type.
38
+ def transactions
39
+ return dispatch_transactions if instance_of?(DispatchAuthorization)
40
+
41
+ return receipt_transactions if instance_of?(ReceiptAuthorization)
42
+ end
43
+
44
+ def confirm
45
+ # Check if all transactions are committed first.
46
+ if instance_of?(DispatchAuthorization)
47
+ raise(StandardError, 'Authorization does not have transactions.') if transactions.blank?
48
+
49
+ count = transactions.where(status: Transaction::DRAFT).count
50
+ raise(StandardError, 'There are uncommitted transactions.') if count.positive?
51
+ end
52
+ self.status = CONFIRMED
53
+ save!
54
+ end
55
+
56
+ private
57
+
58
+ def set_status
59
+ return unless new_record?
60
+
61
+ self.status = AUTHORIZED
62
+ end
63
+ end
64
+ end
65
+ end
@@ -13,33 +13,25 @@ module Cats
13
13
  belongs_to :prepared_by, class_name: 'Cats::Core::User'
14
14
  belongs_to :transporter
15
15
  belongs_to :dispatch_plan_item
16
- has_many :receipts
17
- has_many :dispatch_transactions
18
- has_many :lost_commodities
16
+ belongs_to :unit, class_name: 'Cats::Core::UnitOfMeasure'
17
+
18
+ has_many :dispatch_authorizations
19
+ has_many :receipt_authorizations
20
+ has_many :dispatch_transactions, through: :dispatch_authorizations
21
+ has_many :receipt_transactions, through: :receipt_authorizations
19
22
 
20
23
  validates :reference_no, :plate_no, :driver_name, :driver_phone, :quantity, :commodity_status, presence: true
21
24
  validates :dispatch_status, presence: true, inclusion: { in: DISPATCH_STATUSES }
22
25
  validates :reference_no, uniqueness: true
23
26
  validates :quantity, numericality: { greater_than_or_equal_to: 0 }
24
27
  validates :commodity_status, inclusion: { in: Cats::Core::Commodity::COMMODITY_STATUSES }
25
- validate :validate_quantity, :validate_dispatch_plan_status
28
+ validate :validate_dispatch_plan_status
26
29
 
27
30
  delegate(:name, to: :transporter, prefix: true)
28
31
  delegate(:email, to: :prepared_by, prefix: true)
29
32
 
30
- def total_quantity
31
- dispatch_transactions.sum(:quantity)
32
- end
33
-
34
- def validate_quantity
35
- return unless quantity && dispatch_plan_item
36
-
37
- return unless quantity_changed?
38
-
39
- dispatched = dispatch_plan_item.dispatches.sum(:quantity)
40
- remaining = dispatch_plan_item.quantity - dispatched
41
- remaining += quantity_was if quantity_was
42
- errors.add(:quantity, "exceeds allocated quantity. Maximum allowed is #{remaining}") if quantity > remaining
33
+ def authorized_quantity
34
+ dispatch_authorizations.sum(:quantity)
43
35
  end
44
36
 
45
37
  def validate_dispatch_plan_status
@@ -52,41 +44,49 @@ module Cats
52
44
  def approve
53
45
  raise(StandardError, 'Dispatch has to be in draft state.') unless dispatch_status == Dispatch::DRAFT
54
46
 
55
- # Check if dispatch has transactions
56
- raise(StandardError, 'Dispatch has no transactions.') unless dispatch_transactions.count.positive?
47
+ # Check if dispatch has authorizations
48
+ raise(StandardError, 'Dispatch has no authorizations.') unless dispatch_authorizations.count.positive?
57
49
 
58
- Dispatch.transaction do
59
- # Commit transactions
60
- dispatch_transactions.each(&:commit)
61
- self.quantity = total_quantity
62
- self.dispatch_status = Dispatch::APPROVED
63
- save!
50
+ dispatches = Dispatch.where(dispatch_plan_item: dispatch_plan_item)
51
+ authorized = dispatches.inject(0) do |result, dispatch|
52
+ result += dispatch.authorized_quantity
53
+ result
64
54
  end
65
- end
55
+ diff = authorized - dispatch_plan_item.quantity
56
+ error = "Total authorized quantity exceeds allocated quantity (Extra = #{diff})."
57
+ raise(StandardError, error) if diff.positive?
66
58
 
67
- def start
68
- raise(StandardError, 'Dispatch has to be approved first.') unless dispatch_status == Dispatch::APPROVED
69
-
70
- self.dispatch_status = Dispatch::STARTED
59
+ self.dispatch_status = APPROVED
71
60
  save!
72
61
  end
73
62
 
74
- def confirm
75
- total = receipts.sum(:quantity)
76
-
77
- unless total == quantity
78
- diff = (quantity - total).abs
79
- raise(
80
- StandardError,
81
- "There is an amount of #{diff} in the dispatch which is unaccounted for."
82
- )
83
- end
84
-
63
+ def start
85
64
  Dispatch.transaction do
86
- self.dispatch_status = Dispatch::RECEIVED
87
- receipts.each { |r| r.status = Receipt::CONFIRMED }
65
+ # Commit transactions
66
+ self.quantity = dispatch_transactions.sum(:quantity)
67
+ self.dispatch_status = STARTED
88
68
  save!
89
- receipts.each(&:save!)
69
+ dispatch_transactions.each(&:commit)
70
+ end
71
+ end
72
+
73
+ def self.search_commodity(batch_no)
74
+ commodity = Commodity.find_by(batch_no: batch_no)
75
+ dispatches = Dispatch.includes(:dispatch_transactions)
76
+ .joins(:transporter)
77
+ .where(
78
+ dispatch_status: [APPROVED, STARTED, ARRIVED, UNLOADED]
79
+ )
80
+ dispatches.map do |dispatch|
81
+ {
82
+ batch_no: batch_no,
83
+ commodity_name: commodity.name,
84
+ quantity: dispatch.quantity,
85
+ unit: commodity.unit_abbreviation,
86
+ location: dispatch.transporter.name,
87
+ location_detail: "Plate No.: #{dispatch.plate_no}, Driver: #{dispatch.driver_name}",
88
+ stack: ''
89
+ }
90
90
  end
91
91
  end
92
92
  end
@@ -0,0 +1,13 @@
1
+ module Cats
2
+ module Core
3
+ class DispatchAuthorization < Authorization
4
+ has_many :dispatch_transactions
5
+
6
+ def validate_dispatch_status
7
+ return unless dispatch
8
+
9
+ errors.add(:dispatch, 'is not in draft state.') unless dispatch.dispatch_status == Dispatch::DRAFT
10
+ end
11
+ end
12
+ end
13
+ end
@@ -15,6 +15,7 @@ module Cats
15
15
  has_many :dispatches
16
16
  has_many :hub_authorizations
17
17
 
18
+ validates :reference_no, presence: true, uniqueness: true
18
19
  validates :commodity_status, presence: true, inclusion: { in: Commodity::COMMODITY_STATUSES }
19
20
  validates :quantity, presence: true, numericality: { greater_than: 0 }
20
21
  validates :status, presence: true, inclusion: { in: STATUSES }
@@ -2,10 +2,13 @@ module Cats
2
2
  module Core
3
3
  class DispatchTransaction < Transaction
4
4
  belongs_to :source, class_name: 'Cats::Core::Stack'
5
- belongs_to :dispatch
5
+ belongs_to :dispatch_authorization
6
+
7
+ validates :source_id, uniqueness: { scope: :dispatch_authorization_id }
8
+ validate :validate_dispatch
9
+ validate :validate_source_quantity, :validate_authorized_quantity, unless: :skip_quantity_validation
6
10
 
7
11
  delegate(:code, to: :source, prefix: true)
8
- delegate(:reference_no, to: :dispatch, prefix: true)
9
12
 
10
13
  def commit
11
14
  Transaction.transaction do
@@ -16,6 +19,40 @@ module Cats
16
19
  save!
17
20
  end
18
21
  end
22
+
23
+ def validate_dispatch
24
+ return unless dispatch_authorization
25
+
26
+ status = dispatch_authorization.dispatch.dispatch_status
27
+ errors.add(:base, 'Dispatch must be approved first.') if status == Dispatch::DRAFT
28
+ end
29
+
30
+ def validate_source_quantity
31
+ return unless quantity && source
32
+
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?
37
+ end
38
+
39
+ def validate_authorized_quantity
40
+ return unless quantity && dispatch_authorization
41
+
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
46
+ end
47
+
48
+ def skip_quantity_validation
49
+ # Quantity validation should be skipped if dispatch is already started.
50
+ return true unless dispatch_authorization
51
+
52
+ return true if status == COMMITTED
53
+
54
+ ![Dispatch::DRAFT, Dispatch::APPROVED].include?(dispatch_authorization.dispatch.dispatch_status)
55
+ end
19
56
  end
20
57
  end
21
58
  end
@@ -0,0 +1,26 @@
1
+ module Cats
2
+ module Core
3
+ class ReceiptAuthorization < Authorization
4
+ has_many :receipt_transactions
5
+
6
+ validates :lost_quantity, presence: true, numericality: { greater_than_or_equal_to: 0 }
7
+ validate :validate_total_quantity
8
+
9
+ def validate_total_quantity
10
+ return unless dispatch && quantity
11
+
12
+ received = dispatch.receipt_authorizations.sum(:quantity) + dispatch.receipt_authorizations.sum(:lost_quantity)
13
+ diff = dispatch.quantity - received
14
+ diff += quantity_was if quantity_was
15
+ diff += lost_quantity_was if lost_quantity_was
16
+
17
+ errors.add(:quantity, "authorized is higher than dispatch quantity (Max = #{diff}).") if quantity > diff
18
+ end
19
+
20
+ def confirm
21
+ self.status = CONFIRMED
22
+ save!
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,27 +1,29 @@
1
1
  module Cats
2
2
  module Core
3
3
  class ReceiptTransaction < Transaction
4
- belongs_to :receipt
4
+ belongs_to :receipt_authorization
5
5
  belongs_to :destination, class_name: 'Cats::Core::Stack'
6
6
 
7
- delegate(:code, to: :destination, prefix: true)
7
+ validates :transaction_date, presence: true
8
+ validates :quantity, presence: true, numericality: { greater_than: 0 }
9
+ validate :validate_receipt, :validate_quantity
8
10
 
9
- def validate_quantity
10
- return unless quantity.present? && destination.present? && receipt.present?
11
+ delegate(:code, to: :destination, prefix: true)
11
12
 
12
- authorized = receipt.dispatch.dispatch_plan_item.hub_authorizations.where(
13
- store: destination.store
14
- ).sum(:quantity)
15
- received = self.class.joins(:destination).where(
16
- destination: { store_id: destination.store_id }
17
- ).sum(:quantity)
13
+ def validate_receipt
14
+ return unless receipt_authorization
18
15
 
19
- received -= quantity_was if quantity_was
16
+ status = receipt_authorization.status
17
+ errors.add(:receipt_authorization, 'must be confirmed.') if status == ReceiptAuthorization::AUTHORIZED
18
+ end
20
19
 
21
- # Get quantity in hub authorization for source
22
- available = authorized - received
20
+ def validate_quantity
21
+ return unless quantity && destination && receipt_authorization
23
22
 
24
- errors.add(:quantity, "exceeds authorized quantity (Max = #{available}).") if quantity > available
23
+ total = ReceiptTransaction.where(receipt_authorization: receipt_authorization).sum(:quantity)
24
+ diff = receipt_authorization.quantity - total
25
+ diff += quantity_was if quantity_was
26
+ errors.add(:quantity, "exceeds authorized quantity (Max. = #{diff}).") if quantity > diff
25
27
  end
26
28
 
27
29
  def commit
@@ -146,6 +146,25 @@ module Cats
146
146
 
147
147
  store.save
148
148
  end
149
+
150
+ def self.search_commodity(batch_no)
151
+ commodity = Commodity.find_by(batch_no: batch_no)
152
+ stacks = Stack.joins(:commodity, store: :warehouse).where(
153
+ commodity: { batch_no: batch_no },
154
+ stack_status: Stack::ALLOCATED
155
+ )
156
+ stacks.map do |stack|
157
+ {
158
+ batch_no: batch_no,
159
+ commodity_name: commodity.name,
160
+ quantity: stack.quantity,
161
+ unit: commodity.unit_abbreviation,
162
+ location: stack.store.warehouse.name,
163
+ location_detail: stack.store.name,
164
+ stack: stack.code
165
+ }
166
+ end
167
+ end
149
168
  end
150
169
  end
151
170
  end
@@ -12,41 +12,11 @@ module Cats
12
12
  validates :transaction_date, :quantity, :status, presence: true
13
13
  validates :quantity, numericality: { greater_than: 0 }
14
14
  validates :status, inclusion: { in: STATUSES }
15
- validate :validate_quantity, unless: :skip_quantity_validation
16
-
17
- def validate_quantity
18
- return unless quantity.present? && source.present? && dispatch.present?
19
-
20
- dispatched = self.class.joins(:source, :dispatch).where(
21
- source: { store_id: source.store_id },
22
- dispatch: { dispatch_plan_item_id: dispatch.dispatch_plan_item_id }
23
- ).sum(:quantity)
24
- dispatched -= quantity_was if quantity_was
25
-
26
- # Get quantity in hub authorization for source
27
- authorized = dispatch.dispatch_plan_item.hub_authorizations.where(store_id: source.store_id).sum(:quantity)
28
- available = authorized - dispatched
29
-
30
- errors.add(:quantity, "exceeds authorized quantity (Max = #{available}).") if quantity > available
31
- end
32
15
 
33
16
  def commit
34
17
  raise(NotImplementedError, 'Method should be implemented in child classes.')
35
18
  end
36
19
 
37
- def skip_quantity_validation
38
- # Quantity validation should be skipped if we are commiting transactions.
39
- (
40
- instance_of?(Cats::Core::DispatchTransaction) &&
41
- dispatch &&
42
- status == COMMITTED
43
- ) || (
44
- instance_of?(Cats::Core::ReceiptTransaction) &&
45
- receipt &&
46
- receipt.status == Cats::Core::Receipt::STACKING
47
- )
48
- end
49
-
50
20
  def set_status
51
21
  return unless new_record?
52
22
 
@@ -36,7 +36,7 @@ module Cats
36
36
 
37
37
  errors.add(:status, 'cannot be set to "APPROVED" because the order has no items.') if status == APPROVED
38
38
  end
39
-
39
+
40
40
  def approve(user)
41
41
  raise(StandardError, 'Transport order is already approved.') if status == APPROVED
42
42
 
@@ -0,0 +1,8 @@
1
+ module Cats
2
+ module Core
3
+ class DispatchAuthorizationSerializer < ActiveModel::Serializer
4
+ attributes :id, :dispatch_id, :dispatch_reference_no, :store_id, :store_name, :quantity, :authorized_by_id,
5
+ :authorizer_full_name
6
+ end
7
+ end
8
+ end
@@ -1,7 +1,7 @@
1
1
  module Cats
2
2
  module Core
3
3
  class DispatchPlanItemSerializer < ActiveModel::Serializer
4
- attributes :id, :dispatch_plan_id, :plan_reference_no, :source_id, :source_name, :destination_id,
4
+ attributes :id, :reference_no, :dispatch_plan_id, :plan_reference_no, :source_id, :source_name, :destination_id,
5
5
  :destination_name, :quantity, :source_location_type, :destination_location_type, :commodity_status,
6
6
  :status, :commodity_id, :commodity_name, :commodity_batch_no
7
7
  end
@@ -1,8 +1,7 @@
1
1
  module Cats
2
2
  module Core
3
3
  class DispatchTransactionSerializer < ActiveModel::Serializer
4
- attributes :id, :source_id, :source_code, :dispatch_id, :dispatch_reference_no, :quantity,
5
- :transaction_date, :status
4
+ attributes :id, :source_id, :source_code, :dispatch_authorization_id, :quantity, :transaction_date, :status
6
5
  end
7
6
  end
8
7
  end
@@ -0,0 +1,8 @@
1
+ module Cats
2
+ module Core
3
+ class ReceiptAuthorizationSerializer < ActiveModel::Serializer
4
+ attributes :id, :dispatch_id, :dispatch_reference_no, :store_id, :store_name, :quantity, :lost_quantity, :remark,
5
+ :status, :authorized_by_id, :authorizer_full_name
6
+ end
7
+ end
8
+ end
@@ -1,11 +1,11 @@
1
1
  module Cats
2
2
  module Core
3
3
  class ReceiptTransactionSerializer < ActiveModel::Serializer
4
- attributes :id, :receipt_id, :dispatch_reference, :destination_id, :destination_code, :quantity,
4
+ attributes :id, :receipt_authorization_id, :dispatch_reference, :destination_id, :destination_code, :quantity,
5
5
  :transaction_date, :status
6
6
 
7
7
  def dispatch_reference
8
- object.receipt.dispatch.reference_no
8
+ object.receipt_authorization.dispatch.reference_no
9
9
  end
10
10
  end
11
11
  end
data/config/routes.rb CHANGED
@@ -99,7 +99,8 @@ Cats::Core::Engine.routes.draw do
99
99
  get '/dispatches/search', controller: :dispatches, action: :search, as: :search_dispatches
100
100
  resources :dispatches, except: %i[index destroy] do
101
101
  member do
102
- get 'transactions', controller: :dispatch_transactions, action: :index
102
+ get 'dispatch_authorizations', controller: :dispatch_authorizations, action: :index
103
+ get 'receipt_authorizations', controller: :receipt_authorizations, action: :index
103
104
  get 'receipts', controller: :receipts, action: :index
104
105
  get 'lost', controller: :lost_commodities, action: :index
105
106
  get 'commodity'
@@ -109,6 +110,20 @@ Cats::Core::Engine.routes.draw do
109
110
  end
110
111
  end
111
112
 
113
+ resources :dispatch_authorizations, except: %i[index destory] do
114
+ member do
115
+ get 'transactions', controller: :dispatch_transactions, action: :index
116
+ post 'confirm', controller: :dispatch_authorizations, action: :confirm
117
+ end
118
+ end
119
+
120
+ resources :receipt_authorizations, except: %i[index destroy] do
121
+ member do
122
+ get 'transactions', controller: :receipt_transactions, action: :index
123
+ post 'confirm', controller: :receipt_authorizations, action: :confirm
124
+ end
125
+ end
126
+
112
127
  post(
113
128
  'dispatch_transactions/allocation',
114
129
  controller: :dispatch_transactions,
@@ -116,13 +131,6 @@ Cats::Core::Engine.routes.draw do
116
131
  as: :allocation_transaction
117
132
  )
118
133
  resources :dispatch_transactions, except: %i[index new edit destroy]
119
- resources :receipts, except: %i[index new edit destroy] do
120
- member do
121
- get 'transactions', controller: :receipt_transactions, action: :index
122
- post 'start_stacking'
123
- post 'finish_stacking'
124
- end
125
- end
126
134
  resources :receipt_transactions, except: %i[index new edit destroy]
127
135
  resources :lost_commodities, except: %i[index destroy]
128
136
  get '/plans/:id/round_plans', controller: :round_plans, action: :index, as: :round_plans_plan
@@ -1,6 +1,7 @@
1
1
  class CreateCatsCoreDispatchPlanItems < ActiveRecord::Migration[6.1]
2
2
  def change
3
3
  create_table :cats_core_dispatch_plan_items do |t|
4
+ t.string :reference_no, null: false, unique: true
4
5
  t.references :dispatch_plan,
5
6
  null: false,
6
7
  index: { name: 'dpi_on_dp_indx' },
@@ -14,6 +14,10 @@ class CreateCatsCoreDispatches < ActiveRecord::Migration[6.1]
14
14
  t.string :driver_name, null: false
15
15
  t.string :driver_phone, null: false
16
16
  t.float :quantity, null: false, default: 0
17
+ t.references :unit,
18
+ null: false,
19
+ index: { name: 'unit_on_dispatches_indx' },
20
+ foreign_key: { to_table: :cats_core_unit_of_measures }
17
21
  t.string :commodity_status, null: false, default: 'Good'
18
22
  t.string :remark
19
23
  t.references :prepared_by,
@@ -0,0 +1,22 @@
1
+ class CreateCatsCoreDispatchAuthorizations < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :cats_core_dispatch_authorizations do |t|
4
+ t.references :dispatch,
5
+ null: false,
6
+ index: { name: 'dispatch_on_da_indx' },
7
+ foreign_key: { to_table: :cats_core_dispatches }
8
+ t.references :store,
9
+ null: false,
10
+ index: { name: 'store_on_da_indx' },
11
+ foreign_key: { to_table: :cats_core_stores }
12
+ t.float :quantity, null: false
13
+ t.string :status, null: false, default: 'Authorized'
14
+ t.references :authorized_by,
15
+ null: false,
16
+ index: { name: 'ab_on_da_indx' },
17
+ foreign_key: { to_table: :cats_core_users }
18
+
19
+ t.timestamps
20
+ end
21
+ end
22
+ end
@@ -5,15 +5,21 @@ class CreateCatsCoreDispatchTransactions < ActiveRecord::Migration[6.1]
5
5
  null: false,
6
6
  index: { name: 'stack_on_dt_indx' },
7
7
  foreign_key: { to_table: :cats_core_stacks }
8
- t.references :dispatch,
8
+ t.references :dispatch_authorization,
9
9
  null: false,
10
- index: { name: 'dispatch_on_dt_indx' },
11
- foreign_key: { to_table: :cats_core_dispatches }
10
+ index: { name: 'da_on_dt_indx' },
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
14
  t.string :status, null: false, default: 'Draft'
15
15
 
16
16
  t.timestamps
17
17
  end
18
+ add_index(
19
+ :cats_core_dispatch_transactions,
20
+ [:source_id, :dispatch_authorization_id],
21
+ unique: true,
22
+ name: 'sda_on_dt_uniq_indx'
23
+ )
18
24
  end
19
25
  end
@@ -0,0 +1,24 @@
1
+ class CreateCatsCoreReceiptAuthorizations < ActiveRecord::Migration[6.1]
2
+ def change
3
+ create_table :cats_core_receipt_authorizations do |t|
4
+ t.references :dispatch,
5
+ null: false,
6
+ index: { name: 'dispatch_on_receipt_authorizations_indx' },
7
+ foreign_key: { to_table: :cats_core_dispatches }
8
+ t.references :store,
9
+ null: false,
10
+ index: { name: 'store_on_ra_indx' },
11
+ foreign_key: { to_table: :cats_core_stores }
12
+ t.float :quantity, null: false
13
+ t.float :lost_quantity, null: false, default: 0
14
+ t.string :status, null: false, default: 'Authorized'
15
+ t.string :remark
16
+ t.references :authorized_by,
17
+ null: false,
18
+ index: { name: 'ab_on_receipt_authorizations_indx' },
19
+ foreign_key: { to_table: :cats_core_users }
20
+
21
+ t.timestamps
22
+ end
23
+ end
24
+ end
@@ -1,10 +1,10 @@
1
1
  class CreateCatsCoreReceiptTransactions < ActiveRecord::Migration[6.1]
2
2
  def change
3
3
  create_table :cats_core_receipt_transactions do |t|
4
- t.references :receipt,
4
+ t.references :receipt_authorization,
5
5
  null: false,
6
- index: { name: 'receipt_on_rt_indx' },
7
- foreign_key: { to_table: :cats_core_receipts }
6
+ index: { name: 'receipt_authorization_on_rt_indx' },
7
+ foreign_key: { to_table: :cats_core_receipt_authorizations }
8
8
  t.references :destination,
9
9
  null: false,
10
10
  index: { name: 'stack_on_rt_indx' },
@@ -1,5 +1,5 @@
1
1
  module Cats
2
2
  module Core
3
- VERSION = '1.4.19'.freeze
3
+ VERSION = '1.4.22'.freeze
4
4
  end
5
5
  end
@@ -0,0 +1,26 @@
1
+ FactoryBot.define do
2
+ factory :dispatch_authorization, class: 'Cats::Core::DispatchAuthorization' do
3
+ transient do
4
+ s { create(:store) }
5
+ stack { create(:stack, quantity: 100, store: s) }
6
+ end
7
+ dispatch
8
+ store { s }
9
+ quantity { 100 }
10
+ status { Cats::Core::ReceiptAuthorization::AUTHORIZED }
11
+ authorized_by factory: :user
12
+
13
+ trait :approved do
14
+ after(:create) do |obj|
15
+ obj.dispatch.approve
16
+ end
17
+ end
18
+
19
+ trait :with_transaction do
20
+ after(:create) do |obj, options|
21
+ obj.dispatch.approve
22
+ create(:dispatch_transaction, dispatch_authorization: obj, source: options.stack, quantity: 100)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,5 +1,6 @@
1
1
  FactoryBot.define do
2
2
  factory :dispatch_plan_item, class: 'Cats::Core::DispatchPlanItem' do
3
+ reference_no { FFaker::Name.name }
3
4
  source factory: :location
4
5
  destination factory: :location
5
6
  dispatch_plan
@@ -4,14 +4,9 @@ FactoryBot.define do
4
4
  stack { create(:stack) }
5
5
  end
6
6
  source { stack }
7
- dispatch do
8
- plan_item = create(:dispatch_plan_item, quantity: 100)
9
- plan_item.dispatch_plan.approve
10
- create(:hub_authorization, dispatch_plan_item: plan_item, quantity: 100, store: stack.store)
11
- create(:dispatch, dispatch_plan_item: plan_item, transaction?: false)
12
- end
7
+ association :dispatch_authorization, :approved
13
8
  transaction_date { Date.today }
14
- quantity { 10 }
9
+ quantity { 100 }
15
10
  status { Cats::Core::Transaction::DRAFT }
16
11
  end
17
12
  end
@@ -2,7 +2,6 @@ FactoryBot.define do
2
2
  factory :dispatch, class: 'Cats::Core::Dispatch' do
3
3
  transient do
4
4
  stack { create(:stack, quantity: 100) }
5
- transaction? { true }
6
5
  end
7
6
  reference_no { FFaker::Name.name }
8
7
  dispatch_plan_item do
@@ -11,6 +10,7 @@ FactoryBot.define do
11
10
  create(:hub_authorization, dispatch_plan_item: plan_item, quantity: 100, store: stack.store)
12
11
  plan_item
13
12
  end
13
+ unit factory: :unit_of_measure
14
14
  transporter
15
15
  plate_no { FFaker::Name.name }
16
16
  driver_name { FFaker::Name.name }
@@ -19,8 +19,27 @@ FactoryBot.define do
19
19
  prepared_by factory: :user
20
20
  dispatch_status { Cats::Core::Dispatch::DRAFT }
21
21
 
22
- after :create do |dispatch, options|
23
- create(:dispatch_transaction, dispatch: dispatch, source: options.stack, quantity: 100) if options.transaction?
22
+ trait :with_authorization do
23
+ after(:create) do |dispatch, options|
24
+ create(:dispatch_authorization, dispatch: dispatch, store: options.stack.store)
25
+ end
26
+ end
27
+
28
+ trait :with_transaction do
29
+ after(:create) do |dispatch, options|
30
+ authorization = create(:dispatch_authorization, dispatch: dispatch, store: options.stack.store)
31
+ dispatch.approve
32
+ create(:dispatch_transaction, dispatch_authorization: authorization, source: options.stack, quantity: 100)
33
+ end
34
+ end
35
+
36
+ trait :started do
37
+ after(:create) do |dispatch, options|
38
+ authorization = create(:dispatch_authorization, dispatch: dispatch, store: options.stack.store)
39
+ dispatch.approve
40
+ create(:dispatch_transaction, dispatch_authorization: authorization, source: options.stack, quantity: 100)
41
+ dispatch.start
42
+ end
24
43
  end
25
44
  end
26
45
  end
@@ -0,0 +1,19 @@
1
+ FactoryBot.define do
2
+ factory :receipt_authorization, class: 'Cats::Core::ReceiptAuthorization' do
3
+ dispatch do
4
+ dispatch = create(:dispatch, :with_transaction)
5
+ dispatch.start
6
+ dispatch
7
+ end
8
+ store
9
+ quantity { 100 }
10
+ lost_quantity { 0 }
11
+ remark { FFaker::Name.name }
12
+ status { Cats::Core::ReceiptAuthorization::AUTHORIZED }
13
+ authorized_by factory: :user
14
+
15
+ trait :confirmed do
16
+ status { Cats::Core::ReceiptAuthorization::CONFIRMED }
17
+ end
18
+ end
19
+ end
@@ -1,27 +1,7 @@
1
1
  FactoryBot.define do
2
2
  factory :receipt_transaction, class: 'Cats::Core::ReceiptTransaction' do
3
- transient do
4
- dispatch { create(:dispatch) }
5
- end
6
- transient do
7
- stack { create(:stack) }
8
- end
9
-
10
- destination { stack }
11
- receipt do
12
- dispatch.approve
13
- dispatch.start
14
- receipt = create(:receipt, dispatch: dispatch)
15
- dispatch.confirm
16
- create(
17
- :hub_authorization,
18
- authorization_type: Cats::Core::HubAuthorization::DESTINATION,
19
- dispatch_plan_item: dispatch.dispatch_plan_item,
20
- store: stack.store,
21
- quantity: 100
22
- )
23
- receipt
24
- end
3
+ association :receipt_authorization, :confirmed
4
+ destination factory: :stack
25
5
  transaction_date { Date.today }
26
6
  quantity { 100 }
27
7
  status { Cats::Core::Transaction::DRAFT }
@@ -3,6 +3,6 @@ FactoryBot.define do
3
3
  region factory: :location
4
4
  source factory: :woreda
5
5
  destination factory: :woreda
6
- name { "#{source.name} - #{destination.name}"}
6
+ name { "#{source.name} - #{destination.name}" }
7
7
  end
8
8
  end
@@ -10,6 +10,6 @@ FactoryBot.define do
10
10
  store
11
11
  commodity_status { Cats::Core::Commodity::GOOD }
12
12
  stack_status { Cats::Core::Stack::RESERVED }
13
- quantity { 50 }
13
+ quantity { 100 }
14
14
  end
15
15
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cats_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.19
4
+ version: 1.4.22
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-05-16 00:00:00.000000000 Z
11
+ date: 2022-05-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: active_model_serializers
@@ -235,6 +235,7 @@ files:
235
235
  - app/controllers/cats/core/commodities_controller.rb
236
236
  - app/controllers/cats/core/commodity_categories_controller.rb
237
237
  - app/controllers/cats/core/currencies_controller.rb
238
+ - app/controllers/cats/core/dispatch_authorizations_controller.rb
238
239
  - app/controllers/cats/core/dispatch_plan_items_controller.rb
239
240
  - app/controllers/cats/core/dispatch_plans_controller.rb
240
241
  - app/controllers/cats/core/dispatch_transactions_controller.rb
@@ -243,8 +244,8 @@ files:
243
244
  - app/controllers/cats/core/lost_commodities_controller.rb
244
245
  - app/controllers/cats/core/menus_controller.rb
245
246
  - app/controllers/cats/core/notifications_controller.rb
247
+ - app/controllers/cats/core/receipt_authorizations_controller.rb
246
248
  - app/controllers/cats/core/receipt_transactions_controller.rb
247
- - app/controllers/cats/core/receipts_controller.rb
248
249
  - app/controllers/cats/core/roles_controller.rb
249
250
  - app/controllers/cats/core/round_plans_controller.rb
250
251
  - app/controllers/cats/core/routes_controller.rb
@@ -258,6 +259,7 @@ files:
258
259
  - app/jobs/cats/core/application_job.rb
259
260
  - app/models/cats/core/application_module.rb
260
261
  - app/models/cats/core/application_record.rb
262
+ - app/models/cats/core/authorization.rb
261
263
  - app/models/cats/core/beneficiary.rb
262
264
  - app/models/cats/core/beneficiary_category.rb
263
265
  - app/models/cats/core/beneficiary_plan_item.rb
@@ -268,6 +270,7 @@ files:
268
270
  - app/models/cats/core/contract_item.rb
269
271
  - app/models/cats/core/currency.rb
270
272
  - app/models/cats/core/dispatch.rb
273
+ - app/models/cats/core/dispatch_authorization.rb
271
274
  - app/models/cats/core/dispatch_plan.rb
272
275
  - app/models/cats/core/dispatch_plan_item.rb
273
276
  - app/models/cats/core/dispatch_transaction.rb
@@ -289,7 +292,7 @@ files:
289
292
  - app/models/cats/core/program.rb
290
293
  - app/models/cats/core/purchase_order.rb
291
294
  - app/models/cats/core/ration.rb
292
- - app/models/cats/core/receipt.rb
295
+ - app/models/cats/core/receipt_authorization.rb
293
296
  - app/models/cats/core/receipt_transaction.rb
294
297
  - app/models/cats/core/rhn_request.rb
295
298
  - app/models/cats/core/role.rb
@@ -328,12 +331,14 @@ files:
328
331
  - app/serializers/cats/core/commodity_category_serializer.rb
329
332
  - app/serializers/cats/core/commodity_serializer.rb
330
333
  - app/serializers/cats/core/currency_serializer.rb
334
+ - app/serializers/cats/core/dispatch_authorization_serializer.rb
331
335
  - app/serializers/cats/core/dispatch_plan_item_serializer.rb
332
336
  - app/serializers/cats/core/dispatch_plan_serializer.rb
333
337
  - app/serializers/cats/core/dispatch_serializer.rb
334
338
  - app/serializers/cats/core/dispatch_transaction_serializer.rb
335
339
  - app/serializers/cats/core/location_serializer.rb
336
340
  - app/serializers/cats/core/lost_commodity_serializer.rb
341
+ - app/serializers/cats/core/receipt_authorization_serializer.rb
337
342
  - app/serializers/cats/core/receipt_serializer.rb
338
343
  - app/serializers/cats/core/receipt_transaction_serializer.rb
339
344
  - app/serializers/cats/core/role_menu_serializer.rb
@@ -349,7 +354,6 @@ files:
349
354
  - app/services/cats/core/dispatch_service.rb
350
355
  - app/services/cats/core/menu_service.rb
351
356
  - app/services/cats/core/notification_service.rb
352
- - app/services/cats/core/receipt_service.rb
353
357
  - app/services/cats/core/round_plan_service.rb
354
358
  - app/services/cats/core/space_service.rb
355
359
  - app/services/cats/core/stack_service.rb
@@ -387,10 +391,11 @@ files:
387
391
  - db/migrate/20210718043328_create_cats_core_dispatch_plans.rb
388
392
  - db/migrate/20210718043401_create_cats_core_dispatch_plan_items.rb
389
393
  - db/migrate/20210718045516_create_cats_core_dispatches.rb
394
+ - db/migrate/20210718055414_create_cats_core_dispatch_authorizations.rb
390
395
  - db/migrate/20210718202957_create_cats_core_dispatch_transactions.rb
391
396
  - db/migrate/20210719133710_create_cats_core_stacking_rules.rb
392
397
  - db/migrate/20210724074657_create_cats_core_notifications.rb
393
- - db/migrate/20210727074646_create_cats_core_receipts.rb
398
+ - db/migrate/20210727074646_create_cats_core_receipt_authorizations.rb
394
399
  - db/migrate/20210728041505_create_cats_core_lost_commodities.rb
395
400
  - db/migrate/20210814160628_create_cats_core_receipt_transactions.rb
396
401
  - db/migrate/20210814175406_create_cats_core_stack_transactions.rb
@@ -435,6 +440,7 @@ files:
435
440
  - spec/factories/cats/core/commodity_substitutions.rb
436
441
  - spec/factories/cats/core/contract_items.rb
437
442
  - spec/factories/cats/core/currencies.rb
443
+ - spec/factories/cats/core/dispatch_authorizations.rb
438
444
  - spec/factories/cats/core/dispatch_plan_items.rb
439
445
  - spec/factories/cats/core/dispatch_plans.rb
440
446
  - spec/factories/cats/core/dispatch_transactions.rb
@@ -457,8 +463,8 @@ files:
457
463
  - spec/factories/cats/core/programs.rb
458
464
  - spec/factories/cats/core/purchase_orders.rb
459
465
  - spec/factories/cats/core/rations.rb
466
+ - spec/factories/cats/core/receipt_authorizations.rb
460
467
  - spec/factories/cats/core/receipt_transactions.rb
461
- - spec/factories/cats/core/receipts.rb
462
468
  - spec/factories/cats/core/rhn_requests.rb
463
469
  - spec/factories/cats/core/role_menus.rb
464
470
  - spec/factories/cats/core/roles.rb
@@ -1,45 +0,0 @@
1
- module Cats
2
- module Core
3
- class ReceiptsController < ApplicationController
4
- include Common
5
-
6
- def index
7
- super do
8
- Receipt.where(dispatch_id: params[:id])
9
- end
10
- end
11
-
12
- def create
13
- super do
14
- service = ReceiptService.new
15
- receipt = service.init(model_params)
16
- receipt
17
- end
18
- end
19
-
20
- def start_stacking
21
- receipt = Receipt.find(params[:id])
22
- service = ReceiptService.new
23
- result = service.start_stacking(receipt)
24
- render json: { success: true, data: serialize(result) }
25
- rescue StandardError => e
26
- render json: { success: false, error: e.message }
27
- end
28
-
29
- def finish_stacking
30
- receipt = Receipt.find(params[:id])
31
- service = ReceiptService.new
32
- result = service.finish_stacking(receipt)
33
- render json: { success: true, data: serialize(result) }
34
- rescue StandardError => e
35
- render json: { success: false, error: e.message }
36
- end
37
-
38
- private
39
-
40
- def model_params
41
- params.require(:payload).permit(:dispatch_id, :quantity, :commodity_status, :status, :remark, :prepared_by_id)
42
- end
43
- end
44
- end
45
- end
@@ -1,44 +0,0 @@
1
- module Cats
2
- module Core
3
- class Receipt < ApplicationRecord
4
- # Receipt status
5
- DRAFT = 'Draft'.freeze
6
- CONFIRMED = 'Confirmed'.freeze
7
- STACKING = 'Stacking'.freeze
8
- STACKED = 'Stacked'.freeze
9
- RECEIPT_STATUSES = [DRAFT, CONFIRMED, STACKING, STACKED].freeze
10
-
11
- belongs_to :dispatch
12
- belongs_to :prepared_by, class_name: 'Cats::Core::User'
13
- has_many :receipt_transactions
14
-
15
- validates :quantity, :commodity_status, :status, presence: true
16
- validates :quantity, numericality: { greater_than: 0 }
17
- validates :status, inclusion: { in: RECEIPT_STATUSES }
18
- validates :commodity_status, inclusion: { in: Cats::Core::Commodity::COMMODITY_STATUSES }
19
- validate :validate_dispatch_status, :validate_total_quantity
20
-
21
- delegate(:reference_no, to: :dispatch, prefix: true)
22
- delegate(:email, to: :prepared_by, prefix: true)
23
-
24
- def validate_dispatch_status
25
- return unless dispatch
26
-
27
- statuses = [Cats::Core::Dispatch::STARTED, Cats::Core::Dispatch::RECEIVED]
28
- return if statuses.include?(dispatch.dispatch_status)
29
-
30
- errors.add(:dispatch, 'should be in "Started" state.')
31
- end
32
-
33
- def validate_total_quantity
34
- return unless dispatch && quantity
35
-
36
- received = dispatch.receipts.sum(:quantity) + dispatch.lost_commodities.sum(:quantity)
37
- diff = dispatch.quantity - received
38
- diff += quantity_was if quantity_was
39
-
40
- errors.add(:quantity, "total is higher than dispatch quantity (Max = #{diff}).") if quantity > diff
41
- end
42
- end
43
- end
44
- end
@@ -1,48 +0,0 @@
1
- module Cats
2
- module Core
3
- class ReceiptService
4
- def start_stacking(receipt)
5
- raise(StandardError, 'Receipt should be confirmed.') unless receipt.status == Cats::Core::Receipt::CONFIRMED
6
-
7
- raise(StandardError, 'There are no stack assignments in receipt.') if receipt.receipt_transactions.count.zero?
8
-
9
- receipt.status = Cats::Core::Receipt::STACKING
10
- receipt.save!
11
- receipt
12
- end
13
-
14
- def finish_stacking(receipt)
15
- unless receipt.status == Cats::Core::Receipt::STACKING
16
- raise(StandardError, 'Receipt should be in stacking state.')
17
- end
18
-
19
- receipt.receipt_transactions.each(&:commit)
20
- receipt.status = Cats::Core::Receipt::STACKED
21
- receipt.save!
22
- receipt
23
- end
24
-
25
- def init(params)
26
- receipt = Cats::Core::Receipt.find_by(
27
- dispatch_id: params[:dispatch_id],
28
- commodity_status: params[:commodity_status]
29
- )
30
-
31
- if receipt
32
- # We can assume that the plan item is destination authorized.
33
- # Therefore no need for checking destination authorization.
34
- receipt.quantity += params[:quantity]
35
- return receipt
36
- end
37
-
38
- # Check if plan item is destination authorized
39
- dispatch = Dispatch.find(params[:dispatch_id])
40
- status = dispatch.dispatch_plan_item.status
41
- statuses = [DispatchPlanItem::DESTINATION_AUTHORIZED, DispatchPlanItem::AUTHORIZED]
42
- raise(StandardError, 'Plan item is not destination authorized.') unless statuses.include?(status)
43
-
44
- Receipt.new(params)
45
- end
46
- end
47
- end
48
- end
@@ -1,20 +0,0 @@
1
- class CreateCatsCoreReceipts < ActiveRecord::Migration[6.1]
2
- def change
3
- create_table :cats_core_receipts do |t|
4
- t.references :dispatch,
5
- null: false,
6
- index: { name: 'dispatch_on_receipts_indx' },
7
- foreign_key: { to_table: :cats_core_dispatches }
8
- t.float :quantity, null: false
9
- t.string :commodity_status, null: false, default: 'Good'
10
- t.string :status, null: false, default: 'Draft'
11
- t.string :remark
12
- t.references :prepared_by,
13
- null: false,
14
- index: { name: 'pb_on_receipts_indx' },
15
- foreign_key: { to_table: :cats_core_users }
16
-
17
- t.timestamps
18
- end
19
- end
20
- end
@@ -1,15 +0,0 @@
1
- FactoryBot.define do
2
- factory :receipt, class: 'Cats::Core::Receipt' do
3
- dispatch do
4
- dispatch = create(:dispatch)
5
- dispatch.approve
6
- dispatch.start
7
- dispatch
8
- end
9
- quantity { 100 }
10
- commodity_status { Cats::Core::Commodity::GOOD }
11
- status { Cats::Core::Receipt::DRAFT }
12
- remark { FFaker::Name.name }
13
- prepared_by factory: :user
14
- end
15
- end