cats_core 1.3.36 → 1.3.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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