cats_core 1.3.36 → 1.3.37

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/cats/core/commodities_controller.rb +41 -0
  3. data/app/controllers/cats/core/dispatch_transactions_controller.rb +2 -2
  4. data/app/controllers/cats/core/dispatches_controller.rb +0 -8
  5. data/app/controllers/cats/core/lost_commodities_controller.rb +2 -2
  6. data/app/controllers/cats/core/monthly_plans_controller.rb +62 -0
  7. data/app/controllers/cats/core/receipt_transactions_controller.rb +3 -3
  8. data/app/models/cats/core/dispatch.rb +16 -10
  9. data/app/models/cats/core/dispatch_transaction.rb +3 -2
  10. data/app/models/cats/core/lost_commodity.rb +1 -1
  11. data/app/models/cats/core/receipt.rb +2 -2
  12. data/app/models/cats/core/receipt_transaction.rb +19 -1
  13. data/app/models/cats/core/stack_transaction.rb +11 -0
  14. data/app/models/cats/core/transaction.rb +14 -9
  15. data/app/serializers/cats/core/commodity_category_serializer.rb +5 -1
  16. data/app/serializers/cats/core/dispatch_transaction_serializer.rb +1 -1
  17. data/app/serializers/cats/core/lost_commodity_serializer.rb +1 -1
  18. data/app/serializers/cats/core/monthly_plan_serializer.rb +3 -0
  19. data/app/serializers/cats/core/receipt_transaction_serializer.rb +3 -3
  20. data/app/services/cats/core/dispatch_service.rb +17 -80
  21. data/app/services/cats/core/monthly_plan_service.rb +86 -0
  22. data/app/services/cats/core/receipt_service.rb +1 -1
  23. data/config/routes.rb +17 -5
  24. data/db/migrate/20210718045516_create_cats_core_dispatches.rb +1 -1
  25. data/db/migrate/20210718202957_create_cats_core_dispatch_transactions.rb +1 -1
  26. data/db/migrate/{20220221041505_create_cats_core_lost_commodities.rb → 20210728041505_create_cats_core_lost_commodities.rb} +3 -3
  27. data/db/migrate/20210814160628_create_cats_core_receipt_transactions.rb +1 -1
  28. data/lib/cats/core/version.rb +1 -1
  29. data/spec/factories/cats/core/dispatch_transactions.rb +10 -2
  30. data/spec/factories/cats/core/dispatches.rb +9 -1
  31. data/spec/factories/cats/core/lost_commodities.rb +1 -1
  32. data/spec/factories/cats/core/receipt_transactions.rb +23 -3
  33. data/spec/factories/cats/core/receipts.rb +1 -2
  34. metadata +7 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f7d2738616bb04e122c03cb503fe91bb1d8cb818c2ef909516d2e506efcad01c
4
- data.tar.gz: 7363415368111fa228b7d552f030bdce90009940c62365a27b9408d29745a21b
3
+ metadata.gz: bed830f2b21060736c309012ce715496a38df7a44e6afd7e83971600a5cd009a
4
+ data.tar.gz: b3fb80830191593df49aa191c551aa7c7282adaeb2163699c43cb47e0ce32128
5
5
  SHA512:
6
- metadata.gz: c04a0d21b349fe67c2367204df7dc876bd0ec250753124873583b387f035fe1290a7bb503f8aad9184dd8df6fddd787aaa785fd0f1e281e12c4b0f2a6320871f
7
- data.tar.gz: d0104ee1c25f2fa50e196c0daa671c30fbed484cb370116919bc01403e68d736595a0ab17c83f2b2f0921bff87d319840035f99ee6cfd3d20c55d93817a29595
6
+ metadata.gz: fee481c6274541b597cc4cacdbbfe1fcb60db2790e487969e69de92705d262dacb29793dba304cf995e937ab4e7cdc78120a3da2e3b11decdafe7da28d0a26dd
7
+ data.tar.gz: 9022d76253b7050228e138eb096ffa462010a00f4b42508219fcb164b95ee8030f53b51cffe6b28f9e7e8ea0e5389fdce2eb268fdbc8addc32ebdc6b7cf55f65
@@ -0,0 +1,41 @@
1
+ module Cats
2
+ module Core
3
+ class CommoditiesController < ApplicationController
4
+ include Common
5
+
6
+ def approve
7
+ commodity = Cats::Core::Commodity.find(params[:id])
8
+ result = commodity.approve
9
+ render json: { success: result, data: serialize(commodity) }
10
+ rescue StandardError => e
11
+ render json: { success: false, error: e.message }
12
+ end
13
+
14
+ def update
15
+ if @obj.status == Cats::Core::Commodity::APPROVED
16
+ render json: { success: false, error: 'An approved record cannot be edited.' }
17
+ return
18
+ end
19
+
20
+ if @obj.update(model_params)
21
+ render json: { success: true, data: serialize(@obj) }
22
+ else
23
+ render json: { success: false, error: @obj.errors.full_messages[0] }, status: :unprocessable_entity
24
+ end
25
+ end
26
+
27
+ def filter
28
+ query = Cats::Core::Commodity.ransack(params[:q])
29
+ render json: { success: true, data: serialize(query.result) }
30
+ end
31
+
32
+ private
33
+
34
+ def model_params
35
+ params.require(:payload).permit(:batch_no, :description, :unit_of_measure_id, :source_id,
36
+ :source_type, :quantity, :best_use_before, :volume_per_metric_ton,
37
+ :arrival_status)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -4,14 +4,14 @@ module Cats
4
4
  include Common
5
5
 
6
6
  def index
7
- transactions = Cats::Core::DispatchTransaction.where(destination_id: params[:id])
7
+ transactions = Cats::Core::DispatchTransaction.where(dispatch_id: params[:id])
8
8
  render json: { success: true, data: serialize(transactions) }
9
9
  end
10
10
 
11
11
  private
12
12
 
13
13
  def model_params
14
- params.require(:payload).permit(:source_id, :destination_id, :transaction_date, :quantity)
14
+ params.require(:payload).permit(:source_id, :dispatch_id, :transaction_date, :quantity)
15
15
  end
16
16
  end
17
17
  end
@@ -22,14 +22,6 @@ module Cats
22
22
  end
23
23
  end
24
24
 
25
- def create_receipt_authorization
26
- item = Cats::Core::DispatchPlanItem.find(params[:id])
27
- dispatch = @service.create_receipt_authorization(
28
- params[:reference_no], item, params[:quantity], params[:remark], current_user
29
- )
30
- render json: { success: true, data: serialize(dispatch) }
31
- end
32
-
33
25
  def approve
34
26
  @dispatch.approve
35
27
  render json: { success: true, data: serialize(@dispatch) }
@@ -4,12 +4,12 @@ module Cats
4
4
  include Common
5
5
 
6
6
  def index
7
- data = LostCommodity.where(receipt_id: params[:id])
7
+ data = LostCommodity.where(dispatch_id: params[:id])
8
8
  render json: { success: true, data: serialize(data) }
9
9
  end
10
10
 
11
11
  def model_params
12
- params.require(:payload).permit(:receipt_id, :quantity, :commodity_status, :remark)
12
+ params.require(:payload).permit(:dispatch_id, :quantity, :commodity_status, :remark)
13
13
  end
14
14
  end
15
15
  end
@@ -0,0 +1,62 @@
1
+ module Cats
2
+ module Core
3
+ class MonthlyPlansController < ApplicationController
4
+ include Common
5
+
6
+ before_action :set_service, only: %i[generate remove_items generate_monthly_needs]
7
+
8
+ def index
9
+ plans = Cats::Core::MonthlyPlan.where(plan: params[:id])
10
+ render json: { success: true, data: serialize(plans) }
11
+ end
12
+
13
+ def filter
14
+ query = Cats::Core::MonthlyPlan.ransack(params[:q])
15
+ render json: { success: true, data: serialize(query.result) }
16
+ end
17
+
18
+ def approve
19
+ plan = Cats::Core::MonthlyPlan.find(params[:id])
20
+ if plan.monthly_plan_items.count.zero?
21
+ render json: { success: false, error: 'Empty plan cannot be approved.' }, status: :unprocessable_entity
22
+ return
23
+ end
24
+ plan.update(status: Cats::Core::Plan::APPROVED)
25
+ render json: { success: true, data: serialize(plan) }
26
+ end
27
+
28
+ def generate
29
+ plan = @service.generate_monthly_plan(model_params)
30
+ render json: { success: true, data: serialize(plan) }
31
+ end
32
+
33
+ def generate_monthly_needs
34
+ plan = @service.generate_monthly_needs(params[:id])
35
+ render json: { success: true, data: serialize(plan) }
36
+ rescue StandardError => e
37
+ render json: { success: false, error: e.message }
38
+ end
39
+
40
+ def remove_items
41
+ plan = @service.remove_items(params[:id], remove_params)
42
+ render json: { success: true, data: serialize(plan) }
43
+ rescue StandardError => e
44
+ render json: { success: false, error: e.message }
45
+ end
46
+
47
+ private
48
+
49
+ def model_params
50
+ params.require(:payload).permit(:reference_no, :status, :plan_id, :region_id, :month, :no_of_days)
51
+ end
52
+
53
+ def set_service
54
+ @service = MonthlyPlanService.new
55
+ end
56
+
57
+ def remove_params
58
+ params.permit(ids: [])
59
+ end
60
+ end
61
+ end
62
+ end
@@ -4,7 +4,7 @@ module Cats
4
4
  include Common
5
5
 
6
6
  def index
7
- transactions = Cats::Core::ReceiptTransaction.where(source_id: params[:id])
7
+ transactions = Cats::Core::ReceiptTransaction.where(receipt_id: params[:id])
8
8
  render json: { success: true, data: serialize(transactions) }
9
9
  end
10
10
 
@@ -13,7 +13,7 @@ module Cats
13
13
 
14
14
  # Look for a transaction with the same destination as incoming
15
15
  transaction = Cats::Core::ReceiptTransaction.find_by(
16
- source_id: p[:source_id],
16
+ receipt_id: p[:receipt_id],
17
17
  destination_id: p[:destination_id]
18
18
  )
19
19
  if transaction
@@ -32,7 +32,7 @@ module Cats
32
32
  private
33
33
 
34
34
  def model_params
35
- params.require(:payload).permit(:source_id, :destination_id, :transaction_date, :quantity)
35
+ params.require(:payload).permit(:receipt_id, :destination_id, :transaction_date, :quantity)
36
36
  end
37
37
  end
38
38
  end
@@ -14,17 +14,23 @@ module Cats
14
14
  belongs_to :transporter
15
15
  belongs_to :dispatch_plan_item
16
16
  has_many :receipts
17
+ has_many :dispatch_transactions
18
+ has_many :lost_commodities
17
19
 
18
20
  validates :reference_no, :plate_no, :driver_name, :driver_phone, :quantity, :commodity_status, presence: true
19
21
  validates :dispatch_status, presence: true, inclusion: { in: DISPATCH_STATUSES }
20
22
  validates :reference_no, uniqueness: true
21
- validates :quantity, numericality: { greater_than: 0 }
23
+ validates :quantity, numericality: { greater_than_or_equal_to: 0 }
22
24
  validates :commodity_status, inclusion: { in: Cats::Core::Commodity::COMMODITY_STATUSES }
23
25
  validate :validate_quantity, :validate_dispatch_plan_status
24
26
 
25
27
  delegate(:name, to: :transporter, prefix: true)
26
28
  delegate(:email, to: :prepared_by, prefix: true)
27
29
 
30
+ def total_quantity
31
+ dispatch_transactions.sum(:quantity)
32
+ end
33
+
28
34
  def validate_quantity
29
35
  return unless quantity && dispatch_plan_item
30
36
 
@@ -46,14 +52,16 @@ module Cats
46
52
  def approve
47
53
  raise(StandardError, 'Dispatch has to be in draft state.') unless dispatch_status == Dispatch::DRAFT
48
54
 
49
- count = DispatchTransaction.where(destination_id: id).count
50
- raise(StandardError, 'Dispatch has no transactions.') unless count.positive?
55
+ # Check if dispatch has transactions
56
+ raise(StandardError, 'Dispatch has no transactions.') unless dispatch_transactions.count.positive?
51
57
 
52
- quantity = DispatchTransaction.where(destination_id: id).sum(:quantity)
53
- raise(StandardError, 'Transactions quantity is not equal to dispatch quantity.') if self.quantity != quantity
54
-
55
- self.dispatch_status = Dispatch::APPROVED
56
- save!
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!
64
+ end
57
65
  end
58
66
 
59
67
  def start
@@ -61,8 +69,6 @@ module Cats
61
69
 
62
70
  self.dispatch_status = Dispatch::STARTED
63
71
  save!
64
- transactions = DispatchTransaction.where(destination_id: id)
65
- transactions.each(&:commit)
66
72
  end
67
73
 
68
74
  def confirm
@@ -2,15 +2,16 @@ module Cats
2
2
  module Core
3
3
  class DispatchTransaction < Transaction
4
4
  belongs_to :source, class_name: 'Cats::Core::Stack'
5
- belongs_to :destination, class_name: 'Cats::Core::Dispatch'
5
+ belongs_to :dispatch
6
6
 
7
7
  delegate(:code, to: :source, prefix: true)
8
- delegate(:reference_no, to: :destination, prefix: true)
8
+ delegate(:reference_no, to: :dispatch, prefix: true)
9
9
 
10
10
  def commit
11
11
  Transaction.transaction do
12
12
  source.quantity -= quantity
13
13
  source.save!
14
+
14
15
  self.status = COMMITTED
15
16
  save!
16
17
  end
@@ -1,7 +1,7 @@
1
1
  module Cats
2
2
  module Core
3
3
  class LostCommodity < ApplicationRecord
4
- belongs_to :receipt
4
+ belongs_to :dispatch
5
5
 
6
6
  validates :quantity, presence: true
7
7
  validates :commodity_status, presence: true, inclusion: { in: Commodity::COMMODITY_STATUSES }
@@ -10,7 +10,7 @@ module Cats
10
10
 
11
11
  belongs_to :dispatch
12
12
  belongs_to :prepared_by, class_name: 'Cats::Core::User'
13
- has_many :receipt_transactions, foreign_key: :source_id
13
+ has_many :receipt_transactions
14
14
 
15
15
  validates :quantity, :commodity_status, :status, presence: true
16
16
  validates :quantity, numericality: { greater_than: 0 }
@@ -33,7 +33,7 @@ module Cats
33
33
  def validate_total_quantity
34
34
  return unless dispatch && quantity
35
35
 
36
- received = dispatch.receipts.sum(:quantity)
36
+ received = dispatch.receipts.sum(:quantity) + dispatch.lost_commodities.sum(:quantity)
37
37
  diff = dispatch.quantity - received
38
38
  diff += quantity_was if quantity_was
39
39
 
@@ -1,11 +1,29 @@
1
1
  module Cats
2
2
  module Core
3
3
  class ReceiptTransaction < Transaction
4
- belongs_to :source, class_name: 'Cats::Core::Receipt'
4
+ belongs_to :receipt
5
5
  belongs_to :destination, class_name: 'Cats::Core::Stack'
6
6
 
7
7
  delegate(:code, to: :destination, prefix: true)
8
8
 
9
+ def validate_quantity
10
+ return unless quantity.present? && destination.present? && receipt.present?
11
+
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)
18
+
19
+ received -= quantity_was if quantity_was
20
+
21
+ # Get quantity in hub authorization for source
22
+ available = authorized - received
23
+
24
+ errors.add(:quantity, "exceeds authorized quantity (Max = #{available}).") if quantity > available
25
+ end
26
+
9
27
  def commit
10
28
  ReceiptTransaction.transaction do
11
29
  destination.quantity += quantity
@@ -3,6 +3,17 @@ module Cats
3
3
  class StackTransaction < Transaction
4
4
  belongs_to :source, class_name: 'Cats::Core::Stack'
5
5
  belongs_to :destination, class_name: 'Cats::Core::Stack'
6
+
7
+ def validate_quantity
8
+ return unless quantity.present? && source.present?
9
+
10
+ dispatched = StackTransaction.where(source: source, status: DRAFT).sum(:quantity)
11
+
12
+ available = source.quantity - dispatched
13
+ available += quantity_was if quantity_was
14
+
15
+ errors.add(:quantity, "total is higher than source quantity (Max = #{available}).") if quantity > available
16
+ end
6
17
  end
7
18
  end
8
19
  end
@@ -15,14 +15,19 @@ module Cats
15
15
  validate :validate_quantity, unless: :skip_quantity_validation
16
16
 
17
17
  def validate_quantity
18
- return unless quantity.present? && source.present?
18
+ return unless quantity.present? && source.present? && dispatch.present?
19
19
 
20
- dispatched = self.class.where(source: source, status: DRAFT).sum(:quantity)
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
21
25
 
22
- available = source.quantity - dispatched
23
- available += quantity_was if quantity_was
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
24
29
 
25
- errors.add(:quantity, "total is higher than source quantity (Max = #{available}).") if quantity > available
30
+ errors.add(:quantity, "exceeds authorized quantity (Max = #{available}).") if quantity > available
26
31
  end
27
32
 
28
33
  def commit
@@ -33,12 +38,12 @@ module Cats
33
38
  # Quantity validation should be skipped if we are commiting transactions.
34
39
  (
35
40
  instance_of?(Cats::Core::DispatchTransaction) &&
36
- destination &&
37
- destination.dispatch_status == Cats::Core::Dispatch::STARTED
41
+ dispatch &&
42
+ status == COMMITTED
38
43
  ) || (
39
44
  instance_of?(Cats::Core::ReceiptTransaction) &&
40
- source &&
41
- source.status == Cats::Core::Receipt::STACKING
45
+ receipt &&
46
+ receipt.status == Cats::Core::Receipt::STACKING
42
47
  )
43
48
  end
44
49
 
@@ -1,7 +1,11 @@
1
1
  module Cats
2
2
  module Core
3
3
  class CommodityCategorySerializer < ActiveModel::Serializer
4
- attributes :id, :code, :name, :description, :parent_id
4
+ attributes :id, :code, :name, :description, :parent_id, :leaf
5
+
6
+ def leaf
7
+ !object.has_children?
8
+ end
5
9
  end
6
10
  end
7
11
  end
@@ -1,7 +1,7 @@
1
1
  module Cats
2
2
  module Core
3
3
  class DispatchTransactionSerializer < ActiveModel::Serializer
4
- attributes :id, :source_id, :source_code, :destination_id, :destination_reference_no, :quantity,
4
+ attributes :id, :source_id, :source_code, :dispatch_id, :dispatch_reference_no, :quantity,
5
5
  :transaction_date, :status
6
6
  end
7
7
  end
@@ -1,7 +1,7 @@
1
1
  module Cats
2
2
  module Core
3
3
  class LostCommoditySerializer < ActiveModel::Serializer
4
- attributes :id, :receipt_id, :quantity, :commodity_status, :remark
4
+ attributes :id, :dispatch_id, :quantity, :commodity_status, :remark
5
5
  end
6
6
  end
7
7
  end
@@ -0,0 +1,3 @@
1
+ class MonthlyPlanSerializer < ActiveModel::Serializer
2
+ attributes :id, :reference_no, :status, :plan_id, :plan_reference_no, :region_id, :region_name, :month, :no_of_days
3
+ end
@@ -1,11 +1,11 @@
1
1
  module Cats
2
2
  module Core
3
3
  class ReceiptTransactionSerializer < ActiveModel::Serializer
4
- attributes :id, :source_id, :dispatch_reference, :destination_id, :destination_code, :quantity, :transaction_date,
5
- :status
4
+ attributes :id, :receipt_id, :dispatch_reference, :destination_id, :destination_code, :quantity,
5
+ :transaction_date, :status
6
6
 
7
7
  def dispatch_reference
8
- object.source.dispatch.reference_no
8
+ object.receipt.dispatch.reference_no
9
9
  end
10
10
  end
11
11
  end
@@ -1,47 +1,6 @@
1
1
  module Cats
2
2
  module Core
3
3
  class DispatchService
4
- def create_receipt_authorization(reference_no, plan_item, quantity, remark, user)
5
- raise(StandardError, 'Dispatch plan is not an upstream plan.') unless plan_item.dispatch_plan.upstream?
6
-
7
- transporter = Cats::Core::Transporter.find_by(code: 'SUP-TRANS')
8
- raise(StandardError, 'Supplier transporter does not exist.') unless transporter
9
-
10
- store = Cats::Core::Store.find_by(code: 'SUP-STORE')
11
- raise(StandardError, 'Supplier store does not exist.') unless store
12
-
13
- commodity = plan_item.dispatch_plan.commodity
14
- stack = store.stacks.find_by(commodity: commodity)
15
-
16
- raise(StandardError, 'Commodity not found in supplier store.') unless stack
17
-
18
- dispatch = nil
19
- ApplicationRecord.transaction do
20
- dispatch = Cats::Core::Dispatch.create!(
21
- reference_no: reference_no,
22
- dispatch_plan_item: plan_item,
23
- transporter: transporter,
24
- plate_no: 'Supplier plate no',
25
- driver_name: 'Supplier driver',
26
- driver_phone: 'Supplier driver phone',
27
- quantity: quantity,
28
- remark: remark,
29
- prepared_by: user,
30
- dispatch_status: Cats::Core::Dispatch::DRAFT
31
- )
32
-
33
- # Create a dispatch transaction
34
- Cats::Core::DispatchTransaction.create!(
35
- source: stack,
36
- destination: dispatch,
37
- transaction_date: Date.today,
38
- quantity: quantity,
39
- status: Cats::Core::Transaction::DRAFT
40
- )
41
- end
42
- dispatch
43
- end
44
-
45
4
  def search(user, status)
46
5
  details = user.details
47
6
 
@@ -49,44 +8,20 @@ module Cats
49
8
  raise(StandardError, 'User does not have associated location.')
50
9
  end
51
10
 
52
- if details['stores']
53
- warehouse = Cats::Core::Store.find(details['stores'][0]).warehouse
54
- hub = warehouse.parent
55
-
56
- dispatches = Cats::Core::Dispatch.joins(:dispatch_plan_item)
57
- .where(
58
- dispatch_plan_item: { destination: hub },
59
- dispatch_status: status
60
- ).or(
61
- Cats::Core::Dispatch.joins(:dispatch_plan_item)
62
- .where(
63
- dispatch_plan_item: { destination: warehouse },
64
- dispatch_status: status
65
- )
66
- )
67
- elsif details['warehouse']
68
- warehouse = Cats::Core::Location.find(details['warehouse'])
69
- hub = warehouse.parent
70
- dispatches = Cats::Core::Dispatch.joins(:dispatch_plan_item)
71
- .where(
72
- dispatch_plan_item: { destination: hub },
73
- dispatch_status: status
74
- ).or(
75
- Cats::Core::Dispatch.joins(:dispatch_plan_item)
76
- .where(
77
- dispatch_plan_item: { destination: warehouse },
78
- dispatch_status: status
79
- )
80
- )
81
- elsif details['hub']
82
- hub = Cats::Core::Location.find(details['hub'])
83
- dispatches = Cats::Core::Dispatch.joins(:dispatch_plan_item)
84
- .where(
85
- dispatch_plan_item: { destination: hub },
86
- dispatch_status: status
87
- )
88
- end
89
- dispatches
11
+ # Get user's hub
12
+ hub = if details['stores']
13
+ Cats::Core::Store.find(details['stores'][0]).warehouse.parent
14
+ elsif details['warehouse']
15
+ Cats::Core::Location.find(details['warehouse']).parent
16
+ else
17
+ Cats::Core::Location.find(details['hub'])
18
+ end
19
+
20
+ Cats::Core::Dispatch.joins(:dispatch_plan_item)
21
+ .where(
22
+ dispatch_plan_item: { destination: hub },
23
+ dispatch_status: status
24
+ )
90
25
  end
91
26
 
92
27
  def start(dispatch)
@@ -101,9 +36,11 @@ module Cats
101
36
 
102
37
  users = Cats::Core::User.joins(:roles).where(cats_core_roles: { name: notification_rule.roles })
103
38
  location_id = dispatch.dispatch_plan_item.destination_id
39
+ hub = Cats::Core::Location.find(location_id)
104
40
  recipients = users.map do |user|
105
41
  details = user.details
106
- if (details.key?('warehouse') && details['warehouse'] == location_id) ||
42
+
43
+ if (details.key?('warehouse') && hub.child_ids.include?(details['warehouse'])) ||
107
44
  (details.key?('hub') && details['hub'] == location_id)
108
45
  user
109
46
  end
@@ -0,0 +1,86 @@
1
+ module Cats
2
+ module Core
3
+ class MonthlyPlanService
4
+ def generate_monthly_needs(plan_id)
5
+ plan = Cats::Core::MonthlyPlan.find(plan_id)
6
+ raise(StandardError, 'Plan has no rations.') if plan.monthly_rations.count.zero?
7
+
8
+ raise(StandardError, 'Plan has no plan items.') if plan.monthly_plan_items.count.zero?
9
+
10
+ plan.monthly_plan_item_details.delete_all if plan.monthly_plan_item_details.count.positive?
11
+
12
+ details = []
13
+ plan.monthly_plan_items.each do |plan_item|
14
+ plan.monthly_rations.each do |ration|
15
+ details << {
16
+ monthly_plan_item_id: plan_item.id,
17
+ monthly_ration_id: ration.id,
18
+ amount: (plan.no_of_days / ration.no_of_days * ration.amount) * plan_item.beneficiaries,
19
+ created_at: Date.today,
20
+ updated_at: Date.today
21
+ }
22
+ end
23
+ end
24
+
25
+ Cats::Core::MonthlyPlanItemDetail.insert_all!(details)
26
+ plan
27
+ end
28
+
29
+ def generate_monthly_plan(params)
30
+ region = Cats::Core::Location.find(params[:region_id])
31
+ plan = Cats::Core::Plan.includes(plan_items: :plan_item_details).find(params[:plan_id])
32
+ rations = Cats::Core::RationItem.where(ration_id: plan.ration_id)
33
+ monthly_plan = Cats::Core::MonthlyPlan.create!(
34
+ plan_id: plan.id,
35
+ reference_no: params[:reference_no],
36
+ region_id: params[:region_id],
37
+ status: Cats::Core::Plan::DRAFT,
38
+ month: params[:month],
39
+ no_of_days: params[:no_of_days]
40
+ )
41
+ ration_items = rations.map do |ration|
42
+ {
43
+ commodity_category_id: ration.commodity_category_id,
44
+ amount: ration.amount,
45
+ unit_of_measure_id: ration.unit_of_measure_id,
46
+ no_of_days: ration.no_of_days,
47
+ monthly_plan_id: monthly_plan.id,
48
+ created_at: Date.today,
49
+ updated_at: Date.today
50
+ }
51
+ end
52
+ Cats::Core::MonthlyRation.insert_all!(ration_items)
53
+
54
+ plan_items = plan.plan_items.where(woreda_id: region.descendant_ids).map do |plan_item|
55
+ {
56
+ monthly_plan_id: monthly_plan.id,
57
+ beneficiaries: plan_item.beneficiaries,
58
+ plan_item_id: plan_item.id,
59
+ created_at: Date.today,
60
+ updated_at: Date.today
61
+ }
62
+ end
63
+ Cats::Core::MonthlyPlanItem.insert_all!(plan_items)
64
+ monthly_plan
65
+ end
66
+
67
+ def remove_items(plan_id, ids)
68
+ raise(StandardError, 'No plan items specified.') if ids.count.zero?
69
+
70
+ begin
71
+ plan = Cats::Core::MonthlyPlan.find(plan_id)
72
+ rescue ActiveRecord::RecordNotFound
73
+ raise(StandardError, 'Monthly plan not found.') unless plan
74
+ end
75
+
76
+ plans = Cats::Core::MonthlyPlan.includes(:monthly_plan_items).where(monthly_plan_items: { id: ids })
77
+ raise(StandardError, 'Plan items should be from the same plan.') if plans.count > 1
78
+
79
+ raise(StandardError, 'Items are not from the given monthly plan.') unless plan_id == plans[0].id
80
+
81
+ Cats::Core::MonthlyPlanItem.delete_by(id: ids)
82
+ plan
83
+ end
84
+ end
85
+ end
86
+ end
@@ -16,9 +16,9 @@ module Cats
16
16
  raise(StandardError, 'Receipt should be in stacking state.')
17
17
  end
18
18
 
19
+ receipt.receipt_transactions.each(&:commit)
19
20
  receipt.status = Cats::Core::Receipt::STACKED
20
21
  receipt.save!
21
- receipt.receipt_transactions.each(&:commit)
22
22
  receipt
23
23
  end
24
24
  end
data/config/routes.rb CHANGED
@@ -65,6 +65,12 @@ Cats::Core::Engine.routes.draw do
65
65
  get 'children'
66
66
  end
67
67
  end
68
+ post '/commodities/filter', controller: :commodities, action: :filter
69
+ resources :commodities, except: %i[destroy] do
70
+ member do
71
+ post 'approve'
72
+ end
73
+ end
68
74
  resources :currencies, except: %i[destroy]
69
75
  resources :unit_of_measures, except: %i[destroy]
70
76
  resources :transporters, except: %i[destroy]
@@ -83,16 +89,13 @@ Cats::Core::Engine.routes.draw do
83
89
  resources :dispatch_plan_items, except: %i[index destroy]
84
90
 
85
91
  get '/dispatch_plan_items/:id/dispatches', controller: :dispatches, action: :index, as: :dispatches_plan_item
86
- post '/dispatch_plan_items/:id/receipt_authorizaton',
87
- controller: :dispatches,
88
- action: :create_receipt_authorization,
89
- as: :receipt_authorization_plan_item
90
92
 
91
93
  get '/dispatches/search', controller: :dispatches, action: :search, as: :search_dispatches
92
94
  resources :dispatches, except: %i[index destroy] do
93
95
  member do
94
96
  get 'transactions', controller: :dispatch_transactions, action: :index
95
97
  get 'receipts', controller: :receipts, action: :index
98
+ get 'lost', controller: :lost_commodities, action: :index
96
99
  get 'commodity'
97
100
  post 'approve'
98
101
  post 'start'
@@ -103,11 +106,20 @@ Cats::Core::Engine.routes.draw do
103
106
  resources :receipts, except: %i[index new edit destroy] do
104
107
  member do
105
108
  get 'transactions', controller: :receipt_transactions, action: :index
106
- get 'lost', controller: :lost_commodities, action: :index
107
109
  post 'start_stacking'
108
110
  post 'finish_stacking'
109
111
  end
110
112
  end
111
113
  resources :receipt_transactions, except: %i[index new edit destroy]
112
114
  resources :lost_commodities, except: %i[index destroy]
115
+ get '/plans/:id/monthly_plans', controller: :monthly_plans, action: :index, as: :monthly_plans_plan
116
+ post '/monthly_plans/generate'
117
+ post '/monthly_plans/filter'
118
+ resources :monthly_plans, except: %i[index destroy] do
119
+ member do
120
+ post 'remove_items'
121
+ post 'generate_monthly_needs'
122
+ post 'approve'
123
+ end
124
+ end
113
125
  end
@@ -13,7 +13,7 @@ class CreateCatsCoreDispatches < ActiveRecord::Migration[6.1]
13
13
  t.string :plate_no, null: false
14
14
  t.string :driver_name, null: false
15
15
  t.string :driver_phone, null: false
16
- t.float :quantity, null: false
16
+ t.float :quantity, null: false, default: 0
17
17
  t.string :commodity_status, null: false, default: 'Good'
18
18
  t.string :remark
19
19
  t.references :prepared_by,
@@ -5,7 +5,7 @@ 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 :destination,
8
+ t.references :dispatch,
9
9
  null: false,
10
10
  index: { name: 'dispatch_on_dt_indx' },
11
11
  foreign_key: { to_table: :cats_core_dispatches }
@@ -1,10 +1,10 @@
1
1
  class CreateCatsCoreLostCommodities < ActiveRecord::Migration[7.0]
2
2
  def change
3
3
  create_table :cats_core_lost_commodities do |t|
4
- t.references :receipt,
4
+ t.references :dispatch,
5
5
  null: false,
6
- index: { name: 'lc_on_receipt_indx' },
7
- foreign_key: { to_table: :cats_core_receipts }
6
+ index: { name: 'lc_on_dispatch_indx' },
7
+ foreign_key: { to_table: :cats_core_dispatches }
8
8
  t.float :quantity, null: false
9
9
  t.string :commodity_status, null: false
10
10
  t.string :remark
@@ -1,7 +1,7 @@
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 :source,
4
+ t.references :receipt,
5
5
  null: false,
6
6
  index: { name: 'receipt_on_rt_indx' },
7
7
  foreign_key: { to_table: :cats_core_receipts }
@@ -1,5 +1,5 @@
1
1
  module Cats
2
2
  module Core
3
- VERSION = '1.3.36'.freeze
3
+ VERSION = '1.3.37'.freeze
4
4
  end
5
5
  end
@@ -1,7 +1,15 @@
1
1
  FactoryBot.define do
2
2
  factory :dispatch_transaction, class: 'Cats::Core::DispatchTransaction' do
3
- source factory: :stack
4
- destination factory: :dispatch
3
+ transient do
4
+ stack { create(:stack) }
5
+ end
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
5
13
  transaction_date { Date.today }
6
14
  quantity { 10 }
7
15
  status { Cats::Core::Transaction::DRAFT }
@@ -1,18 +1,26 @@
1
1
  FactoryBot.define do
2
2
  factory :dispatch, class: 'Cats::Core::Dispatch' do
3
+ transient do
4
+ stack { create(:stack, quantity: 100) }
5
+ transaction? { true }
6
+ end
3
7
  reference_no { FFaker::Name.name }
4
8
  dispatch_plan_item do
5
9
  plan_item = create(:dispatch_plan_item, quantity: 100)
6
10
  plan_item.dispatch_plan.approve
11
+ create(:hub_authorization, dispatch_plan_item: plan_item, quantity: 100, store: stack.store)
7
12
  plan_item
8
13
  end
9
14
  transporter
10
15
  plate_no { FFaker::Name.name }
11
16
  driver_name { FFaker::Name.name }
12
17
  driver_phone { FFaker::Name.name }
13
- quantity { 50 }
14
18
  remark { FFaker::Name.name }
15
19
  prepared_by factory: :user
16
20
  dispatch_status { Cats::Core::Dispatch::DRAFT }
21
+
22
+ after :create do |dispatch, options|
23
+ create(:dispatch_transaction, dispatch: dispatch, source: options.stack, quantity: 100) if options.transaction?
24
+ end
17
25
  end
18
26
  end
@@ -1,6 +1,6 @@
1
1
  FactoryBot.define do
2
2
  factory :lost_commodity, class: 'Cats::Core::LostCommodity' do
3
- receipt
3
+ dispatch
4
4
  quantity { 100 }
5
5
  commodity_status { Cats::Core::Commodity::DAMAGED }
6
6
  remark { FFaker::Name.name }
@@ -1,9 +1,29 @@
1
1
  FactoryBot.define do
2
2
  factory :receipt_transaction, class: 'Cats::Core::ReceiptTransaction' do
3
- source factory: :receipt
4
- destination factory: :stack
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
5
25
  transaction_date { Date.today }
6
- quantity { 10 }
26
+ quantity { 100 }
7
27
  status { Cats::Core::Transaction::DRAFT }
8
28
  end
9
29
  end
@@ -2,12 +2,11 @@ FactoryBot.define do
2
2
  factory :receipt, class: 'Cats::Core::Receipt' do
3
3
  dispatch do
4
4
  dispatch = create(:dispatch)
5
- create(:dispatch_transaction, destination: dispatch, quantity: 50)
6
5
  dispatch.approve
7
6
  dispatch.start
8
7
  dispatch
9
8
  end
10
- quantity { 50 }
9
+ quantity { 100 }
11
10
  commodity_status { Cats::Core::Commodity::GOOD }
12
11
  status { Cats::Core::Receipt::DRAFT }
13
12
  remark { FFaker::Name.name }
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.3.36
4
+ version: 1.3.37
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-02-21 00:00:00.000000000 Z
11
+ date: 2022-03-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: active_model_serializers
@@ -232,6 +232,7 @@ files:
232
232
  - Rakefile
233
233
  - app/controllers/cats/core/access_controller.rb
234
234
  - app/controllers/cats/core/application_controller.rb
235
+ - app/controllers/cats/core/commodities_controller.rb
235
236
  - app/controllers/cats/core/commodity_categories_controller.rb
236
237
  - app/controllers/cats/core/currencies_controller.rb
237
238
  - app/controllers/cats/core/dispatch_plan_items_controller.rb
@@ -241,6 +242,7 @@ files:
241
242
  - app/controllers/cats/core/locations_controller.rb
242
243
  - app/controllers/cats/core/lost_commodities_controller.rb
243
244
  - app/controllers/cats/core/menus_controller.rb
245
+ - app/controllers/cats/core/monthly_plans_controller.rb
244
246
  - app/controllers/cats/core/notifications_controller.rb
245
247
  - app/controllers/cats/core/receipt_transactions_controller.rb
246
248
  - app/controllers/cats/core/receipts_controller.rb
@@ -323,6 +325,7 @@ files:
323
325
  - app/serializers/cats/core/dispatch_transaction_serializer.rb
324
326
  - app/serializers/cats/core/location_serializer.rb
325
327
  - app/serializers/cats/core/lost_commodity_serializer.rb
328
+ - app/serializers/cats/core/monthly_plan_serializer.rb
326
329
  - app/serializers/cats/core/receipt_serializer.rb
327
330
  - app/serializers/cats/core/receipt_transaction_serializer.rb
328
331
  - app/serializers/cats/core/role_menu_serializer.rb
@@ -334,6 +337,7 @@ files:
334
337
  - app/services/cats/core/dispatch_plan_service.rb
335
338
  - app/services/cats/core/dispatch_service.rb
336
339
  - app/services/cats/core/menu_service.rb
340
+ - app/services/cats/core/monthly_plan_service.rb
337
341
  - app/services/cats/core/notification_service.rb
338
342
  - app/services/cats/core/receipt_service.rb
339
343
  - app/services/cats/core/space_service.rb
@@ -376,6 +380,7 @@ files:
376
380
  - db/migrate/20210719133710_create_cats_core_stacking_rules.rb
377
381
  - db/migrate/20210724074657_create_cats_core_notifications.rb
378
382
  - db/migrate/20210727074646_create_cats_core_receipts.rb
383
+ - db/migrate/20210728041505_create_cats_core_lost_commodities.rb
379
384
  - db/migrate/20210814160628_create_cats_core_receipt_transactions.rb
380
385
  - db/migrate/20210814175406_create_cats_core_stack_transactions.rb
381
386
  - db/migrate/20211002050739_create_cats_core_notification_rules.rb
@@ -396,7 +401,6 @@ files:
396
401
  - db/migrate/20220107125025_create_cats_core_monthly_plan_items.rb
397
402
  - db/migrate/20220107132433_create_cats_core_monthly_plan_item_details.rb
398
403
  - db/migrate/20220209083928_create_cats_core_hub_authorizations.rb
399
- - db/migrate/20220221041505_create_cats_core_lost_commodities.rb
400
404
  - lib/cats/core.rb
401
405
  - lib/cats/core/engine.rb
402
406
  - lib/cats/core/version.rb