cats_core 1.4.21 → 1.4.24
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/cats/core/dispatch_authorizations_controller.rb +35 -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 +7 -2
- data/app/controllers/cats/core/lost_commodities_controller.rb +2 -2
- data/app/controllers/cats/core/receipt_authorizations_controller.rb +27 -0
- data/app/controllers/cats/core/receipt_transactions_controller.rb +2 -20
- data/app/controllers/cats/core/receipts_controller.rb +2 -28
- data/app/models/cats/core/authorization.rb +77 -0
- data/app/models/cats/core/dispatch.rb +30 -48
- 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/lost_commodity.rb +2 -3
- data/app/models/cats/core/receipt.rb +3 -37
- data/app/models/cats/core/receipt_authorization.rb +22 -0
- data/app/models/cats/core/receipt_transaction.rb +17 -14
- data/app/models/cats/core/transaction.rb +0 -30
- 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/lost_commodity_serializer.rb +1 -1
- data/app/serializers/cats/core/receipt_authorization_serializer.rb +8 -0
- data/app/serializers/cats/core/receipt_serializer.rb +1 -2
- data/app/serializers/cats/core/receipt_transaction_serializer.rb +1 -5
- data/app/services/cats/core/authorization_service.rb +25 -0
- data/config/routes.rb +26 -9
- 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/20210727105834_create_cats_core_receipts.rb +15 -0
- data/db/migrate/20210728041505_create_cats_core_lost_commodities.rb +3 -4
- 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 +38 -3
- data/spec/factories/cats/core/lost_commodities.rb +1 -2
- data/spec/factories/cats/core/receipt_authorizations.rb +25 -0
- data/spec/factories/cats/core/receipt_transactions.rb +2 -22
- data/spec/factories/cats/core/receipts.rb +2 -9
- data/spec/factories/cats/core/stacks.rb +1 -1
- metadata +15 -4
- data/app/services/cats/core/receipt_service.rb +0 -48
- data/db/migrate/20210727074646_create_cats_core_receipts.rb +0 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3dd00b147a4dfa4ab46e10d7961b4291fbdb39ed68e49a0766e69a4a4d22704a
|
4
|
+
data.tar.gz: 1c37f11f41f76263cb197cdd881b820475a38e8addf1424fce593287ab1e30ad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce78191aa4dde60ba521f32f95a87088f7e9380fcba3e3a05f2cb570c4fd722b6b1962ddff54ab76ea0278552b1640f3a72b0e96571e0160b096bc49b00abd56
|
7
|
+
data.tar.gz: f5e36206d35c62b26cd16bdcaeea9f11c711d90c2c68b6f5c5eeb4e174621c4ad6e8ef28f0082ad74cb505e82bbc44876cd67da9be92b045beebfd0f22c1b269
|
@@ -0,0 +1,35 @@
|
|
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
|
+
service = AuthorizationService.new
|
14
|
+
authorization = service.confirm(params[:id])
|
15
|
+
render json: { success: true, data: serialize(authorization) }
|
16
|
+
rescue StandardError => e
|
17
|
+
render json: { success: false, error: e.message }
|
18
|
+
end
|
19
|
+
|
20
|
+
def storekeeper_authorizations
|
21
|
+
storekeeper = User.find(params[:id])
|
22
|
+
stores = storekeeper.stores
|
23
|
+
authorizations = DispatchAuthorization.joins(:dispatch)
|
24
|
+
.where(store: stores, dispatch: { dispatch_status: Dispatch::APPROVED })
|
25
|
+
render json: { success: true, data: serialize(authorizations) }
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def model_params
|
31
|
+
params.require(:payload).permit(:dispatch_id, :store_id, :quantity, :status, :authorized_by_id)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
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
|
@@ -43,6 +43,11 @@ module Cats
|
|
43
43
|
render json: { success: false, error: e.message }
|
44
44
|
end
|
45
45
|
|
46
|
+
def filter
|
47
|
+
query = Dispatch.ransack(params[:q])
|
48
|
+
render json: { success: true, data: serialize(query.result) }
|
49
|
+
end
|
50
|
+
|
46
51
|
def search
|
47
52
|
data = @service.search(current_user, params[:status])
|
48
53
|
render json: { success: true, data: serialize(data) }
|
@@ -60,8 +65,8 @@ module Cats
|
|
60
65
|
end
|
61
66
|
|
62
67
|
def model_params
|
63
|
-
params.require(:payload).permit(:reference_no, :dispatch_plan_item_id, :transporter_id, :plate_no,
|
64
|
-
:driver_name, :driver_phone, :
|
68
|
+
params.require(:payload).permit(:reference_no, :dispatch_plan_item_id, :transporter_id, :plate_no, :unit_id,
|
69
|
+
:driver_name, :driver_phone, :remark)
|
65
70
|
end
|
66
71
|
end
|
67
72
|
end
|
@@ -5,12 +5,12 @@ module Cats
|
|
5
5
|
|
6
6
|
def index
|
7
7
|
super do
|
8
|
-
LostCommodity.where(
|
8
|
+
LostCommodity.where(receipt_authorization_id: params[:id])
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
12
|
def model_params
|
13
|
-
params.require(:payload).permit(:
|
13
|
+
params.require(:payload).permit(:receipt_authorization_id, :quantity, :remark)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
@@ -0,0 +1,27 @@
|
|
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, :remark, :status, :authorized_by_id)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
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
|
@@ -5,40 +5,14 @@ module Cats
|
|
5
5
|
|
6
6
|
def index
|
7
7
|
super do
|
8
|
-
Receipt.where(
|
8
|
+
Receipt.where(receipt_authorization_id: params[:id])
|
9
9
|
end
|
10
10
|
end
|
11
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
12
|
private
|
39
13
|
|
40
14
|
def model_params
|
41
|
-
params.require(:payload).permit(:
|
15
|
+
params.require(:payload).permit(:receipt_authorization_id, :commodity_status, :quantity, :remark)
|
42
16
|
end
|
43
17
|
end
|
44
18
|
end
|
@@ -0,0 +1,77 @@
|
|
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
|
+
delegate(:dispatch_status, to: :dispatch)
|
24
|
+
delegate(:plate_no, to: :dispatch)
|
25
|
+
delegate(:driver_name, to: :dispatch)
|
26
|
+
|
27
|
+
def validate_dispatch_status
|
28
|
+
return unless dispatch
|
29
|
+
|
30
|
+
if instance_of?(DispatchAuthorization)
|
31
|
+
errors.add(:dispatch, 'is not in draft state.') unless dispatch.dispatch_status == Dispatch::DRAFT
|
32
|
+
else
|
33
|
+
return if dispatch.dispatch_status == Cats::Core::Dispatch::STARTED
|
34
|
+
|
35
|
+
errors.add(:dispatch, 'should be in "Started" state.')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# A convenience method to return dispatch or receipt transactions based on the
|
40
|
+
# authorization type.
|
41
|
+
def transactions
|
42
|
+
return dispatch_transactions if instance_of?(DispatchAuthorization)
|
43
|
+
|
44
|
+
return receipt_transactions if instance_of?(ReceiptAuthorization)
|
45
|
+
end
|
46
|
+
|
47
|
+
def confirm
|
48
|
+
if instance_of?(DispatchAuthorization)
|
49
|
+
raise(StandardError, 'Authorization does not have transactions.') if transactions.blank?
|
50
|
+
|
51
|
+
transactions.each(&:commit)
|
52
|
+
# count = transactions.where(status: Transaction::DRAFT).count
|
53
|
+
# raise(StandardError, 'There are uncommitted transactions.') if count.positive?
|
54
|
+
elsif instance_of?(ReceiptAuthorization)
|
55
|
+
raise(StandardError, 'Authorization does not have receipts.') unless receipts.count.positive?
|
56
|
+
|
57
|
+
total_received = receipts.sum(:quantity)
|
58
|
+
total_lost = lost_commodities.sum(:quantity)
|
59
|
+
diff = quantity - (total_received + total_lost)
|
60
|
+
raise(StandardError, "A quantity of #{diff} is unaccounted for.") unless diff.zero?
|
61
|
+
|
62
|
+
self.received_quantity = total_received
|
63
|
+
end
|
64
|
+
self.status = CONFIRMED
|
65
|
+
save!
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def set_status
|
71
|
+
return unless new_record?
|
72
|
+
|
73
|
+
self.status = AUTHORIZED
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -3,44 +3,36 @@ module Cats
|
|
3
3
|
class Dispatch < ApplicationRecord
|
4
4
|
DRAFT = 'Draft'.freeze
|
5
5
|
APPROVED = 'Approved'.freeze
|
6
|
+
READY_TO_START = 'Ready to Start'.freeze
|
6
7
|
STARTED = 'Started'.freeze
|
7
8
|
ARRIVED = 'Arrived'.freeze
|
8
9
|
UNLOADED = 'Unloaded'.freeze
|
9
10
|
RECEIVED = 'Received'.freeze
|
10
11
|
|
11
|
-
DISPATCH_STATUSES = [DRAFT, APPROVED, STARTED, ARRIVED, UNLOADED, RECEIVED].freeze
|
12
|
+
DISPATCH_STATUSES = [DRAFT, APPROVED, READY_TO_START, STARTED, ARRIVED, UNLOADED, RECEIVED].freeze
|
12
13
|
|
13
14
|
belongs_to :prepared_by, class_name: 'Cats::Core::User'
|
14
15
|
belongs_to :transporter
|
15
16
|
belongs_to :dispatch_plan_item
|
16
|
-
|
17
|
-
|
18
|
-
has_many :
|
19
|
-
has_many :
|
17
|
+
belongs_to :unit, class_name: 'Cats::Core::UnitOfMeasure'
|
18
|
+
|
19
|
+
has_many :dispatch_authorizations
|
20
|
+
has_many :receipt_authorizations
|
21
|
+
has_many :dispatch_transactions, through: :dispatch_authorizations
|
22
|
+
has_many :receipt_transactions, through: :receipt_authorizations
|
20
23
|
|
21
24
|
validates :reference_no, :plate_no, :driver_name, :driver_phone, :quantity, :commodity_status, presence: true
|
22
25
|
validates :dispatch_status, presence: true, inclusion: { in: DISPATCH_STATUSES }
|
23
26
|
validates :reference_no, uniqueness: true
|
24
27
|
validates :quantity, numericality: { greater_than_or_equal_to: 0 }
|
25
28
|
validates :commodity_status, inclusion: { in: Cats::Core::Commodity::COMMODITY_STATUSES }
|
26
|
-
validate :
|
29
|
+
validate :validate_dispatch_plan_status
|
27
30
|
|
28
31
|
delegate(:name, to: :transporter, prefix: true)
|
29
32
|
delegate(:email, to: :prepared_by, prefix: true)
|
30
33
|
|
31
|
-
def
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
def validate_quantity
|
36
|
-
return unless quantity && dispatch_plan_item
|
37
|
-
|
38
|
-
return unless quantity_changed?
|
39
|
-
|
40
|
-
dispatched = dispatch_plan_item.dispatches.sum(:quantity)
|
41
|
-
remaining = dispatch_plan_item.quantity - dispatched
|
42
|
-
remaining += quantity_was if quantity_was
|
43
|
-
errors.add(:quantity, "exceeds allocated quantity. Maximum allowed is #{remaining}") if quantity > remaining
|
34
|
+
def authorized_quantity
|
35
|
+
dispatch_authorizations.sum(:quantity)
|
44
36
|
end
|
45
37
|
|
46
38
|
def validate_dispatch_plan_status
|
@@ -53,42 +45,32 @@ module Cats
|
|
53
45
|
def approve
|
54
46
|
raise(StandardError, 'Dispatch has to be in draft state.') unless dispatch_status == Dispatch::DRAFT
|
55
47
|
|
56
|
-
# Check if dispatch has
|
57
|
-
raise(StandardError, 'Dispatch has no
|
48
|
+
# Check if dispatch has authorizations
|
49
|
+
raise(StandardError, 'Dispatch has no authorizations.') unless dispatch_authorizations.count.positive?
|
58
50
|
|
59
|
-
Dispatch.
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
self.dispatch_status = APPROVED
|
64
|
-
save!
|
51
|
+
dispatches = Dispatch.where(dispatch_plan_item: dispatch_plan_item)
|
52
|
+
authorized = dispatches.inject(0) do |result, dispatch|
|
53
|
+
result += dispatch.authorized_quantity
|
54
|
+
result
|
65
55
|
end
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
raise(StandardError, 'Dispatch has to be approved first.') unless dispatch_status == Dispatch::APPROVED
|
56
|
+
diff = authorized - dispatch_plan_item.quantity
|
57
|
+
error = "Total authorized quantity exceeds allocated quantity (Extra = #{diff})."
|
58
|
+
raise(StandardError, error) if diff.positive?
|
70
59
|
|
71
|
-
self.dispatch_status =
|
60
|
+
self.dispatch_status = APPROVED
|
72
61
|
save!
|
73
62
|
end
|
74
63
|
|
75
|
-
def
|
76
|
-
|
64
|
+
def all_authorizations_confirmed?
|
65
|
+
statuses = dispatch_authorizations.map(&:status).uniq
|
66
|
+
return true if statuses.length == 1 && statuses[0] == Authorization::CONFIRMED
|
77
67
|
|
78
|
-
|
79
|
-
|
80
|
-
raise(
|
81
|
-
StandardError,
|
82
|
-
"There is an amount of #{diff} in the dispatch which is unaccounted for."
|
83
|
-
)
|
84
|
-
end
|
68
|
+
false
|
69
|
+
end
|
85
70
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
save!
|
90
|
-
receipts.each(&:save!)
|
91
|
-
end
|
71
|
+
def start
|
72
|
+
self.dispatch_status = STARTED
|
73
|
+
save!
|
92
74
|
end
|
93
75
|
|
94
76
|
def self.search_commodity(batch_no)
|
@@ -102,7 +84,7 @@ module Cats
|
|
102
84
|
{
|
103
85
|
batch_no: batch_no,
|
104
86
|
commodity_name: commodity.name,
|
105
|
-
quantity: dispatch.
|
87
|
+
quantity: dispatch.quantity,
|
106
88
|
unit: commodity.unit_abbreviation,
|
107
89
|
location: dispatch.transporter.name,
|
108
90
|
location_detail: "Plate No.: #{dispatch.plate_no}, Driver: #{dispatch.driver_name}",
|
@@ -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
|
@@ -1,10 +1,9 @@
|
|
1
1
|
module Cats
|
2
2
|
module Core
|
3
3
|
class LostCommodity < ApplicationRecord
|
4
|
-
belongs_to :
|
4
|
+
belongs_to :receipt_authorization
|
5
5
|
|
6
|
-
validates :quantity, presence: true
|
7
|
-
validates :commodity_status, presence: true, inclusion: { in: Commodity::COMMODITY_STATUSES }
|
6
|
+
validates :quantity, presence: true, numericality: { greater_than: 0 }
|
8
7
|
end
|
9
8
|
end
|
10
9
|
end
|
@@ -1,44 +1,10 @@
|
|
1
1
|
module Cats
|
2
2
|
module Core
|
3
3
|
class Receipt < ApplicationRecord
|
4
|
-
|
5
|
-
DRAFT = 'Draft'.freeze
|
6
|
-
CONFIRMED = 'Confirmed'.freeze
|
7
|
-
STACKING = 'Stacking'.freeze
|
8
|
-
STACKED = 'Stacked'.freeze
|
9
|
-
RECEIPT_STATUSES = [DRAFT, CONFIRMED, STACKING, STACKED].freeze
|
4
|
+
belongs_to :receipt_authorization
|
10
5
|
|
11
|
-
|
12
|
-
|
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
|
6
|
+
validates :commodity_status, presence: true, inclusion: { in: Commodity::COMMODITY_STATUSES }
|
7
|
+
validates :quantity, presence: true, numericality: { greater_than: 0 }
|
42
8
|
end
|
43
9
|
end
|
44
10
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Cats
|
2
|
+
module Core
|
3
|
+
class ReceiptAuthorization < Authorization
|
4
|
+
has_many :receipts
|
5
|
+
has_many :lost_commodities
|
6
|
+
has_many :receipt_transactions
|
7
|
+
|
8
|
+
validates :received_quantity, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
9
|
+
validate :validate_total_quantity
|
10
|
+
|
11
|
+
def validate_total_quantity
|
12
|
+
return unless dispatch && quantity
|
13
|
+
|
14
|
+
received = dispatch.receipt_authorizations.sum(:quantity)
|
15
|
+
diff = dispatch.quantity - received
|
16
|
+
diff += quantity_was if quantity_was
|
17
|
+
|
18
|
+
errors.add(:quantity, "authorized is higher than dispatch quantity (Max = #{diff}).") if quantity > diff
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,27 +1,30 @@
|
|
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
|
-
|
11
|
+
delegate(:code, to: :destination, prefix: true)
|
12
|
+
delegate(:dispatch_reference_no, to: :receipt_authorization)
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
).sum(:quantity)
|
15
|
-
received = self.class.joins(:destination).where(
|
16
|
-
destination: { store_id: destination.store_id }
|
17
|
-
).sum(:quantity)
|
14
|
+
def validate_receipt
|
15
|
+
return unless receipt_authorization
|
18
16
|
|
19
|
-
|
17
|
+
status = receipt_authorization.status
|
18
|
+
errors.add(:receipt_authorization, 'must be confirmed.') if status == ReceiptAuthorization::AUTHORIZED
|
19
|
+
end
|
20
20
|
|
21
|
-
|
22
|
-
|
21
|
+
def validate_quantity
|
22
|
+
return unless quantity && destination && receipt_authorization
|
23
23
|
|
24
|
-
|
24
|
+
total = ReceiptTransaction.where(receipt_authorization: receipt_authorization).sum(:quantity)
|
25
|
+
diff = receipt_authorization.quantity - total
|
26
|
+
diff += quantity_was if quantity_was
|
27
|
+
errors.add(:quantity, "exceeds authorized quantity (Max. = #{diff}).") if quantity > diff
|
25
28
|
end
|
26
29
|
|
27
30
|
def commit
|