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.
- checksums.yaml +4 -4
- data/app/controllers/cats/core/dispatch_authorizations_controller.rb +27 -0
- data/app/controllers/cats/core/dispatch_plan_items_controller.rb +2 -2
- data/app/controllers/cats/core/dispatch_transactions_controller.rb +4 -4
- data/app/controllers/cats/core/dispatches_controller.rb +2 -2
- data/app/controllers/cats/core/receipt_authorizations_controller.rb +28 -0
- data/app/controllers/cats/core/receipt_transactions_controller.rb +2 -20
- data/app/models/cats/core/authorization.rb +65 -0
- data/app/models/cats/core/dispatch.rb +44 -44
- data/app/models/cats/core/dispatch_authorization.rb +13 -0
- data/app/models/cats/core/dispatch_plan_item.rb +1 -0
- data/app/models/cats/core/dispatch_transaction.rb +39 -2
- data/app/models/cats/core/receipt_authorization.rb +26 -0
- data/app/models/cats/core/receipt_transaction.rb +16 -14
- data/app/models/cats/core/stack.rb +19 -0
- data/app/models/cats/core/transaction.rb +0 -30
- data/app/models/cats/core/transport_order.rb +1 -1
- data/app/serializers/cats/core/dispatch_authorization_serializer.rb +8 -0
- data/app/serializers/cats/core/dispatch_plan_item_serializer.rb +1 -1
- data/app/serializers/cats/core/dispatch_transaction_serializer.rb +1 -2
- data/app/serializers/cats/core/receipt_authorization_serializer.rb +8 -0
- data/app/serializers/cats/core/receipt_transaction_serializer.rb +2 -2
- data/config/routes.rb +16 -8
- data/db/migrate/20210718043401_create_cats_core_dispatch_plan_items.rb +1 -0
- data/db/migrate/20210718045516_create_cats_core_dispatches.rb +4 -0
- data/db/migrate/20210718055414_create_cats_core_dispatch_authorizations.rb +22 -0
- data/db/migrate/20210718202957_create_cats_core_dispatch_transactions.rb +9 -3
- data/db/migrate/20210727074646_create_cats_core_receipt_authorizations.rb +24 -0
- data/db/migrate/20210814160628_create_cats_core_receipt_transactions.rb +3 -3
- data/lib/cats/core/version.rb +1 -1
- data/spec/factories/cats/core/dispatch_authorizations.rb +26 -0
- data/spec/factories/cats/core/dispatch_plan_items.rb +1 -0
- data/spec/factories/cats/core/dispatch_transactions.rb +2 -7
- data/spec/factories/cats/core/dispatches.rb +22 -3
- data/spec/factories/cats/core/receipt_authorizations.rb +19 -0
- data/spec/factories/cats/core/receipt_transactions.rb +2 -22
- data/spec/factories/cats/core/routes.rb +1 -1
- data/spec/factories/cats/core/stacks.rb +1 -1
- metadata +13 -7
- data/app/controllers/cats/core/receipts_controller.rb +0 -45
- data/app/models/cats/core/receipt.rb +0 -44
- data/app/services/cats/core/receipt_service.rb +0 -48
- data/db/migrate/20210727074646_create_cats_core_receipts.rb +0 -20
- data/spec/factories/cats/core/receipts.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3a896be87ee316cd08b40a298effac694bfb59e1207699c50675b4242e0f630
|
4
|
+
data.tar.gz: 3b6d584ce3eacbf6a0f3ffda03c399d84db2c5bf3931666107cf9d7fd014e3ca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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,
|
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(
|
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
|
-
|
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, :
|
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, :
|
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(
|
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(:
|
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
|
-
|
17
|
-
|
18
|
-
has_many :
|
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 :
|
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
|
31
|
-
|
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
|
56
|
-
raise(StandardError, 'Dispatch has no
|
47
|
+
# Check if dispatch has authorizations
|
48
|
+
raise(StandardError, 'Dispatch has no authorizations.') unless dispatch_authorizations.count.positive?
|
57
49
|
|
58
|
-
Dispatch.
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
87
|
-
|
65
|
+
# Commit transactions
|
66
|
+
self.quantity = dispatch_transactions.sum(:quantity)
|
67
|
+
self.dispatch_status = STARTED
|
88
68
|
save!
|
89
|
-
|
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 :
|
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 :
|
4
|
+
belongs_to :receipt_authorization
|
5
5
|
belongs_to :destination, class_name: 'Cats::Core::Stack'
|
6
6
|
|
7
|
-
|
7
|
+
validates :transaction_date, presence: true
|
8
|
+
validates :quantity, presence: true, numericality: { greater_than: 0 }
|
9
|
+
validate :validate_receipt, :validate_quantity
|
8
10
|
|
9
|
-
|
10
|
-
return unless quantity.present? && destination.present? && receipt.present?
|
11
|
+
delegate(:code, to: :destination, prefix: true)
|
11
12
|
|
12
|
-
|
13
|
-
|
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
|
-
|
16
|
+
status = receipt_authorization.status
|
17
|
+
errors.add(:receipt_authorization, 'must be confirmed.') if status == ReceiptAuthorization::AUTHORIZED
|
18
|
+
end
|
20
19
|
|
21
|
-
|
22
|
-
|
20
|
+
def validate_quantity
|
21
|
+
return unless quantity && destination && receipt_authorization
|
23
22
|
|
24
|
-
|
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
|
|
@@ -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, :
|
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, :
|
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.
|
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 '
|
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 :
|
8
|
+
t.references :dispatch_authorization,
|
9
9
|
null: false,
|
10
|
-
index: { name: '
|
11
|
-
foreign_key: { to_table: :
|
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 :
|
4
|
+
t.references :receipt_authorization,
|
5
5
|
null: false,
|
6
|
-
index: { name: '
|
7
|
-
foreign_key: { to_table: :
|
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' },
|
data/lib/cats/core/version.rb
CHANGED
@@ -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
|
@@ -4,14 +4,9 @@ FactoryBot.define do
|
|
4
4
|
stack { create(:stack) }
|
5
5
|
end
|
6
6
|
source { stack }
|
7
|
-
|
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 {
|
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
|
-
|
23
|
-
|
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
|
-
|
4
|
-
|
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 }
|
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.
|
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-
|
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/
|
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/
|
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
|