cats_core 1.4.35 → 1.4.38

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/cats/core/commodities_controller.rb +8 -2
  3. data/app/controllers/cats/core/dispatch_authorizations_controller.rb +2 -1
  4. data/app/controllers/cats/core/dispatch_plan_items_controller.rb +15 -3
  5. data/app/controllers/cats/core/dispatch_plans_controller.rb +7 -1
  6. data/app/controllers/cats/core/dispatch_transactions_controller.rb +1 -1
  7. data/app/controllers/cats/core/dispatches_controller.rb +12 -2
  8. data/app/controllers/cats/core/locations_controller.rb +6 -0
  9. data/app/controllers/cats/core/receipt_authorizations_controller.rb +3 -2
  10. data/app/controllers/cats/core/receipt_transactions_controller.rb +2 -1
  11. data/app/controllers/cats/core/round_plans_controller.rb +3 -3
  12. data/app/controllers/cats/core/routes_controller.rb +8 -2
  13. data/app/controllers/cats/core/stacks_controller.rb +2 -2
  14. data/app/controllers/cats/core/stores_controller.rb +4 -4
  15. data/app/controllers/cats/core/unit_conversions_controller.rb +6 -0
  16. data/app/helpers/cats/core/document_helper.rb +12 -0
  17. data/app/models/cats/core/commodity.rb +14 -4
  18. data/app/models/cats/core/dispatch.rb +5 -0
  19. data/app/models/cats/core/dispatch_plan_item.rb +3 -0
  20. data/app/models/cats/core/notification.rb +1 -1
  21. data/app/models/cats/core/project.rb +11 -0
  22. data/app/models/cats/core/transport_requisition_item.rb +1 -1
  23. data/app/serializers/cats/core/commodity_serializer.rb +3 -3
  24. data/app/serializers/cats/core/dispatch_plan_item_serializer.rb +2 -1
  25. data/app/serializers/cats/core/dispatch_serializer.rb +1 -5
  26. data/app/services/cats/core/dispatch_service.rb +11 -4
  27. data/app/services/cats/core/round_plan_service.rb +11 -5
  28. data/config/routes.rb +7 -0
  29. data/db/migrate/20210717032927_create_cats_core_projects.rb +13 -0
  30. data/db/migrate/20210717033223_create_cats_core_commodities.rb +4 -1
  31. data/db/migrate/20210718043401_create_cats_core_dispatch_plan_items.rb +4 -0
  32. data/lib/cats/core/version.rb +1 -1
  33. data/spec/factories/cats/core/commodities.rb +1 -1
  34. data/spec/factories/cats/core/dispatch_plan_items.rb +1 -0
  35. data/spec/factories/cats/core/projects.rb +9 -0
  36. metadata +6 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 186d5da451b5abf3212599586408ca925e553e855f185b2ac52038a7cfa7b651
4
- data.tar.gz: 7fa1c103c95c8f80d98f75be767bf346b4cb5bfab1cf066776e3ae8880a95621
3
+ metadata.gz: c9686d605fc55bee82820925cab018c53333b5d35885fddcb98bd211c61f6547
4
+ data.tar.gz: 938a5caa85d500edde7ae4302293beffc06cea17930cabffd2272e38861227cd
5
5
  SHA512:
6
- metadata.gz: cd85c7c41b4a8c7ab65f388969b4e9e6e5a6191c1eaf19c01bcf6cdbef36018d76136ab73c1bcf57b4fe47f81e5ab6062df1da4ca98970aaec7ddef593818bd7
7
- data.tar.gz: 885be8ea62166c70ae4bf3e4f900ed12a18ddecd0b9ba712643e3fe1e781b4099f7e2b8010ca5fdc14ef57089956fe2c43e2de0f36eabe343d69689b13c4b233
6
+ metadata.gz: dd42170550910db72d5056a21e126faebbbb285eadd135ec57acc09f76e1919c1768525eacae9068466472a88ca87dffca1cb33bd8a74533cf48bc6214e83ca5
7
+ data.tar.gz: be577e0ea6605492474c01825bb12e7a179aeddbb96fc0c6778e3a3c6a19813543715fa7a01b6e28e03e628b504b6f83cc6a37b2f5418039e16e47a037690bc2
@@ -3,6 +3,12 @@ module Cats
3
3
  class CommoditiesController < ApplicationController
4
4
  include Common
5
5
 
6
+ def index
7
+ super do
8
+ Commodity.all.includes({ project: { source: :commodity_category } }, :unit_of_measure)
9
+ end
10
+ end
11
+
6
12
  def approve
7
13
  commodity = Commodity.find(params[:id])
8
14
  result = commodity.approve
@@ -12,14 +18,14 @@ module Cats
12
18
  end
13
19
 
14
20
  def filter
15
- query = Commodity.ransack(params[:q])
21
+ query = Commodity.includes(:project, :unit_of_measure).ransack(params[:q])
16
22
  render json: { success: true, data: serialize(query.result) }
17
23
  end
18
24
 
19
25
  private
20
26
 
21
27
  def model_params
22
- params.require(:payload).permit(:batch_no, :description, :unit_of_measure_id, :source_id, :commodity_grade,
28
+ params.require(:payload).permit(:batch_no, :description, :unit_of_measure_id, :project_id, :commodity_grade,
23
29
  :source_type, :quantity, :best_use_before, :volume_per_metric_ton,
24
30
  :arrival_status, :shipping_reference)
25
31
  end
@@ -5,7 +5,7 @@ module Cats
5
5
 
6
6
  def index
7
7
  super do
8
- DispatchAuthorization.where(dispatch_id: params[:id])
8
+ DispatchAuthorization.includes(:dispatch, :store, :authorized_by).where(dispatch_id: params[:id])
9
9
  end
10
10
  end
11
11
 
@@ -21,6 +21,7 @@ module Cats
21
21
  storekeeper = User.find(params[:id])
22
22
  stores = storekeeper.stores
23
23
  authorizations = DispatchAuthorization.joins(:dispatch)
24
+ .includes(:dispatch, :store, :authorized_by)
24
25
  .where(store: stores, dispatch: { dispatch_status: Dispatch::APPROVED })
25
26
  render json: { success: true, data: serialize(authorizations) }
26
27
  end
@@ -5,12 +5,24 @@ module Cats
5
5
 
6
6
  def index
7
7
  super do
8
- DispatchPlanItem.where(dispatch_plan_id: params[:id])
8
+ DispatchPlanItem.includes(
9
+ :source,
10
+ :destination,
11
+ { commodity: { project: { source: :commodity_category } } },
12
+ :unit,
13
+ :dispatch_plan
14
+ ).where(dispatch_plan_id: params[:id])
9
15
  end
10
16
  end
11
17
 
12
18
  def filter
13
- query = DispatchPlanItem.ransack(params[:q])
19
+ query = DispatchPlanItem.includes(
20
+ :source,
21
+ :destination,
22
+ { commodity: { project: { source: :commodity_category } } },
23
+ :unit,
24
+ :dispatch_plan
25
+ ).ransack(params[:q])
14
26
  render json: { success: true, data: serialize(query.result) }
15
27
  end
16
28
 
@@ -18,7 +30,7 @@ module Cats
18
30
 
19
31
  def model_params
20
32
  params.require(:payload).permit(:reference_no, :dispatch_plan_id, :source_id, :destination_id, :quantity,
21
- :commodity_status, :status, :commodity_id)
33
+ :unit_id, :commodity_status, :status, :commodity_id)
22
34
  end
23
35
  end
24
36
  end
@@ -3,8 +3,14 @@ module Cats
3
3
  class DispatchPlansController < ApplicationController
4
4
  include Common
5
5
 
6
+ def index
7
+ super do
8
+ DispatchPlan.all.includes(:dispatchable)
9
+ end
10
+ end
11
+
6
12
  def plans_for_user
7
- plans = DispatchPlan.where(prepared_by: current_user)
13
+ plans = DispatchPlan.where(prepared_by: current_user).includes(:dispatchable)
8
14
  render json: { success: true, data: serialize(plans) }
9
15
  end
10
16
 
@@ -5,7 +5,7 @@ module Cats
5
5
 
6
6
  def index
7
7
  super do
8
- DispatchTransaction.where(dispatch_authorization_id: params[:id])
8
+ DispatchTransaction.includes(:source).where(dispatch_authorization_id: params[:id])
9
9
  end
10
10
  end
11
11
 
@@ -7,7 +7,12 @@ module Cats
7
7
 
8
8
  def index
9
9
  super do
10
- Dispatch.where(dispatch_plan_item_id: params[:id])
10
+ Dispatch.includes(
11
+ { dispatch_plan_item: :destination },
12
+ :transporter,
13
+ :prepared_by,
14
+ :unit
15
+ ).where(dispatch_plan_item_id: params[:id])
11
16
  end
12
17
  end
13
18
 
@@ -51,7 +56,12 @@ module Cats
51
56
  end
52
57
 
53
58
  def filter
54
- query = Dispatch.ransack(params[:q])
59
+ query = Dispatch.includes(
60
+ { dispatch_plan_item: :destination },
61
+ :transporter,
62
+ :prepared_by,
63
+ :unit
64
+ ).ransack(params[:q])
55
65
  render json: { success: true, data: serialize(query.result) }
56
66
  end
57
67
 
@@ -19,6 +19,12 @@ module Cats
19
19
  render json: { success: true, data: serialize(query.result) }
20
20
  end
21
21
 
22
+ def woredas
23
+ region = Location.find(params[:id])
24
+ woredas = Location.where(id: region.descendant_ids, location_type: Location::WOREDA)
25
+ render json: { success: true, data: serialize(woredas) }
26
+ end
27
+
22
28
  private
23
29
 
24
30
  def model_params
@@ -7,7 +7,7 @@ module Cats
7
7
 
8
8
  def index
9
9
  super do
10
- ReceiptAuthorization.where(dispatch_id: params[:id])
10
+ ReceiptAuthorization.includes(:dispatch, :store, :authorized_by).where(dispatch_id: params[:id])
11
11
  end
12
12
  end
13
13
 
@@ -40,7 +40,8 @@ module Cats
40
40
  storekeeper = User.find(params[:id])
41
41
  status = params[:status]
42
42
  stores = storekeeper.stores
43
- authorizations = ReceiptAuthorization.where(store: stores, status: status)
43
+ authorizations = ReceiptAuthorization.includes(:dispatch, :store, :authorized_by)
44
+ .where(store: stores, status: status)
44
45
  render json: { success: true, data: serialize(authorizations) }
45
46
  end
46
47
 
@@ -5,7 +5,8 @@ module Cats
5
5
 
6
6
  def index
7
7
  super do
8
- ReceiptTransaction.joins(receipt_authorization: :dispatch).where(receipt_authorization_id: params[:id])
8
+ ReceiptTransaction.includes(:destination, { receipt_authorization: :dispatch })
9
+ .where(receipt_authorization_id: params[:id])
9
10
  end
10
11
  end
11
12
 
@@ -7,12 +7,12 @@ module Cats
7
7
 
8
8
  def index
9
9
  super do
10
- RoundPlan.where(plan: params[:id])
10
+ RoundPlan.includes({ plan: :program }, :region).where(plan: params[:id])
11
11
  end
12
12
  end
13
13
 
14
14
  def filter
15
- query = RoundPlan.ransack(params[:q])
15
+ query = RoundPlan.includes({ plan: :program }, :region).ransack(params[:q])
16
16
  render json: { success: true, data: serialize(query.result) }
17
17
  end
18
18
 
@@ -37,7 +37,7 @@ module Cats
37
37
  end
38
38
 
39
39
  def remove_items
40
- plan = @service.remove_items(params[:id], remove_params)
40
+ plan = @service.remove_items(params[:id], remove_params[:ids])
41
41
  render json: { success: true, data: serialize(plan) }
42
42
  rescue StandardError => e
43
43
  render json: { success: false, error: e.message }
@@ -3,8 +3,14 @@ module Cats
3
3
  class RoutesController < ApplicationController
4
4
  include Common
5
5
 
6
+ def index
7
+ super do
8
+ Route.all.includes(:region)
9
+ end
10
+ end
11
+
6
12
  def filter
7
- query = Route.ransack(params[:q])
13
+ query = Route.includes(:region).ransack(params[:q])
8
14
  render json: { success: true, data: serialize(query.result) }
9
15
  end
10
16
 
@@ -23,7 +29,7 @@ module Cats
23
29
  end
24
30
 
25
31
  result = Route.insert_all!(data, record_timestamps: true)
26
- routes = Route.where(id: result.rows.flatten)
32
+ routes = Route.includes(:region).where(id: result.rows.flatten)
27
33
  render json: { success: true, data: serialize(routes) }
28
34
  end
29
35
 
@@ -5,12 +5,12 @@ module Cats
5
5
 
6
6
  def index
7
7
  super do
8
- Stack.where(store_id: params[:id])
8
+ Stack.includes(:commodity).where(store_id: params[:id])
9
9
  end
10
10
  end
11
11
 
12
12
  def filter
13
- query = Stack.where(store_id: params[:id]).ransack(params[:q])
13
+ query = Stack.includes(:commodity).where(store_id: params[:id]).ransack(params[:q])
14
14
  render json: { success: true, data: serialize(query.result) }
15
15
  end
16
16
 
@@ -4,19 +4,19 @@ module Cats
4
4
  include Common
5
5
 
6
6
  def index
7
- stores = Cats::Core::Store.where(warehouse_id: params[:id])
7
+ stores = Store.includes(:store_keeper, :stacks).where(warehouse_id: params[:id])
8
8
  render json: { success: true, data: serialize(stores) }
9
9
  end
10
10
 
11
11
  def filter
12
- query = Store.ransack(params[:q])
12
+ query = Store.includes(:store_keeper, :stacks).ransack(params[:q])
13
13
  render json: { success: true, data: serialize(query.result) }
14
14
  end
15
15
 
16
16
  def stores_for_hub
17
- warehouses = Cats::Core::Location.find(params[:id]).children
17
+ warehouses = Location.find(params[:id]).children
18
18
  ids = warehouses.map(&:id)
19
- stores = Cats::Core::Store.where(warehouse_id: ids)
19
+ stores = Store.includes(:store_keeper, :stacks).where(warehouse_id: ids)
20
20
  render json: { success: true, data: serialize(stores) }
21
21
  end
22
22
 
@@ -3,6 +3,12 @@ module Cats
3
3
  class UnitConversionsController < ApplicationController
4
4
  include Common
5
5
 
6
+ def index
7
+ super do
8
+ UnitConversion.all.includes(:from, :to)
9
+ end
10
+ end
11
+
6
12
  private
7
13
 
8
14
  def model_params
@@ -0,0 +1,12 @@
1
+ module Cats
2
+ module Core
3
+ module DocumentHelper
4
+ require 'sablon'
5
+
6
+ def generate_document(template, output, data)
7
+ tpl = Sablon.template(template)
8
+ tpl.render_to_file(output, data)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -16,7 +16,15 @@ module Cats
16
16
  # Commodity statuses
17
17
  GOOD = 'Good'.freeze
18
18
  DAMAGED = 'Damaged'.freeze
19
- COMMODITY_STATUSES = [GOOD, DAMAGED].freeze
19
+ LEAKAGE = 'Leakage'.freeze
20
+ WET = 'Wet'.freeze
21
+ MOLDY = 'Moldy'.freeze
22
+ INFESTED = 'Infested'.freeze
23
+ INSECT_INFECTED = 'Insect Infected'.freeze
24
+ FAECES_FROM_RODENTS = 'Faeces From Rodents'.freeze
25
+ UNDERWEIGHT_PACKAGE = 'Underweight Package'.freeze
26
+ COMMODITY_STATUSES = [GOOD, DAMAGED, LEAKAGE, WET, MOLDY, INFESTED, INSECT_INFECTED, FAECES_FROM_RODENTS,
27
+ UNDERWEIGHT_PACKAGE].freeze
20
28
 
21
29
  # Arrival Statuses
22
30
  AT_SOURCE = 'At Source'.freeze
@@ -35,7 +43,7 @@ module Cats
35
43
  ].freeze
36
44
 
37
45
  belongs_to :unit_of_measure
38
- belongs_to :source, polymorphic: true
46
+ belongs_to :project
39
47
 
40
48
  validates :best_use_before, presence: true
41
49
  validates :batch_no, presence: true, uniqueness: true
@@ -47,10 +55,12 @@ module Cats
47
55
  validate :validate_updateability, on: :update
48
56
 
49
57
  delegate(:abbreviation, to: :unit_of_measure, prefix: 'unit')
50
- delegate(:reference_no, to: :source, prefix: true)
58
+ delegate(:code, to: :project, prefix: true)
51
59
 
52
60
  def name
53
- source.commodity_category.name
61
+ # For this to be efficient, our query should use includes like
62
+ # Commodity.includes(project: { source: commodity_category })
63
+ project.source.commodity_category.name
54
64
  end
55
65
 
56
66
  def validate_updateability
@@ -29,6 +29,11 @@ module Cats
29
29
 
30
30
  delegate(:name, to: :transporter, prefix: true)
31
31
  delegate(:email, to: :prepared_by, prefix: true)
32
+ delegate(:abbreviation, to: :unit, prefix: true)
33
+
34
+ def destination
35
+ dispatch_plan_item.destination.name
36
+ end
32
37
 
33
38
  def authorized_quantity
34
39
  dispatch_authorizations.sum(:quantity)
@@ -11,6 +11,7 @@ module Cats
11
11
  belongs_to :destination, class_name: 'Cats::Core::Location'
12
12
  belongs_to :dispatch_plan
13
13
  belongs_to :commodity
14
+ belongs_to :unit, class_name: 'Cats::Core::UnitOfMeasure'
14
15
 
15
16
  has_many :dispatches
16
17
  has_many :hub_authorizations
@@ -26,6 +27,8 @@ module Cats
26
27
  delegate(:name, to: :destination, prefix: true)
27
28
  delegate(:location_type, to: :source, prefix: true)
28
29
  delegate(:location_type, to: :destination, prefix: true)
30
+ delegate(:abbreviation, to: :unit, prefix: true)
31
+ delegate(:shipping_reference, to: :commodity, prefix: true)
29
32
 
30
33
  # Authorize a dispatch plan item if it contains authorization entries
31
34
  # under it. A dispatch plan item can be authorized by source hub, or
@@ -10,7 +10,7 @@ module Cats
10
10
  end
11
11
 
12
12
  def self.messages(notifications)
13
- notifications.map(&:message)
13
+ notifications.includes(:recipient).map(&:message)
14
14
  end
15
15
  end
16
16
  end
@@ -0,0 +1,11 @@
1
+ module Cats
2
+ module Core
3
+ class Project < ApplicationRecord
4
+ belongs_to :source, polymorphic: true
5
+
6
+ validates :code, presence: true, uniqueness: true
7
+ validates :year, :implementing_agency, presence: true
8
+ validates :year, numericality: { greater_than: 2000 }
9
+ end
10
+ end
11
+ end
@@ -12,7 +12,7 @@ module Cats
12
12
  delegate(:source_name, to: :dispatch_plan_item, prefix: false)
13
13
 
14
14
  def commodity_name
15
- dispatch_plan_item.commodity.source.commodity_category.name
15
+ dispatch_plan_item.commodity.name
16
16
  end
17
17
 
18
18
  def woreda
@@ -1,9 +1,9 @@
1
1
  module Cats
2
2
  module Core
3
3
  class CommoditySerializer < ActiveModel::Serializer
4
- attributes :id, :name, :batch_no, :description, :unit_of_measure_id, :unit_abbreviation, :source_id,
5
- :source_type, :source_reference_no, :quantity, :best_use_before, :volume_per_metric_ton,
6
- :arrival_status, :status, :shipping_reference, :commodity_grade
4
+ attributes :id, :name, :batch_no, :description, :unit_of_measure_id, :unit_abbreviation, :project_id,
5
+ :project_code, :quantity, :best_use_before, :volume_per_metric_ton, :arrival_status, :status,
6
+ :shipping_reference, :commodity_grade
7
7
  end
8
8
  end
9
9
  end
@@ -3,7 +3,8 @@ module Cats
3
3
  class DispatchPlanItemSerializer < ActiveModel::Serializer
4
4
  attributes :id, :reference_no, :dispatch_plan_id, :plan_reference_no, :source_id, :source_name, :destination_id,
5
5
  :destination_name, :quantity, :source_location_type, :destination_location_type, :commodity_status,
6
- :status, :commodity_id, :commodity_name, :commodity_batch_no
6
+ :status, :commodity_id, :commodity_name, :commodity_batch_no, :unit_abbreviation,
7
+ :commodity_shipping_reference
7
8
  end
8
9
  end
9
10
  end
@@ -3,11 +3,7 @@ module Cats
3
3
  class DispatchSerializer < ActiveModel::Serializer
4
4
  attributes :id, :reference_no, :dispatch_plan_item_id, :transporter_id, :transporter_name, :plate_no,
5
5
  :driver_name, :driver_phone, :quantity, :remark, :prepared_by_id, :prepared_by_email,
6
- :dispatch_status, :destination, :auth_details
7
-
8
- def destination
9
- object.dispatch_plan_item.destination.name
10
- end
6
+ :dispatch_status, :destination, :auth_details, :unit_id, :unit_abbreviation, :commodity_status
11
7
  end
12
8
  end
13
9
  end
@@ -19,12 +19,14 @@ module Cats
19
19
 
20
20
  if authorized
21
21
  return Dispatch.joins(:dispatch_plan_item)
22
+ .includes({ dispatch_plan_item: :destination }, :transporter, :prepared_by, :unit)
22
23
  .where(
23
24
  dispatch_plan_item: { destination: hub, status: DispatchPlanItem::AUTHORIZED },
24
25
  dispatch_status: status
25
26
  )
26
27
  end
27
28
  Dispatch.joins(:dispatch_plan_item)
29
+ .includes({ dispatch_plan_item: :destination }, :transporter, :prepared_by, :unit)
28
30
  .where(
29
31
  dispatch_plan_item: { destination: hub },
30
32
  dispatch_status: status
@@ -38,7 +40,12 @@ module Cats
38
40
  end
39
41
 
40
42
  def start_with_pin(dispatch_id, pin)
41
- dispatch = Dispatch.find(dispatch_id)
43
+ dispatch = Dispatch.includes(
44
+ { dispatch_plan_item: :destination },
45
+ :transporter,
46
+ :prepared_by,
47
+ :unit
48
+ ).find(dispatch_id)
42
49
  raise(StandardError, 'Dispatch is already started.') if dispatch.dispatch_status == Dispatch::STARTED
43
50
 
44
51
  raise(StandardError, 'No pin has been generated for dispatch.') if dispatch.auth_details.nil?
@@ -60,12 +67,12 @@ module Cats
60
67
  end
61
68
 
62
69
  def send_notification(dispatch)
63
- notification_rule = Cats::Core::NotificationRule.find_by(code: 'dispatch')
70
+ notification_rule = NotificationRule.find_by(code: 'dispatch')
64
71
  raise(StandardError, 'Notification rule not found for dispatch notification.') unless notification_rule
65
72
 
66
- users = Cats::Core::User.joins(:roles).where(cats_core_roles: { name: notification_rule.roles })
73
+ users = User.joins(:roles).where(cats_core_roles: { name: notification_rule.roles })
67
74
  location_id = dispatch.dispatch_plan_item.destination_id
68
- hub = Cats::Core::Location.find(location_id)
75
+ hub = Location.find(location_id)
69
76
  recipients = users.map do |user|
70
77
  details = user.details
71
78
 
@@ -115,7 +115,7 @@ module Cats
115
115
  .where(beneficiary_round_plan_items: { id: ids })
116
116
  raise(StandardError, 'Round plan items should be from the same plan.') if plans.count > 1
117
117
 
118
- unless plans.count.positive? && plan_id == plans[0].id
118
+ unless plans.count.positive? && plan.id == plans[0].id
119
119
  raise(StandardError, 'Round plan items are not from the given round plan.')
120
120
  end
121
121
 
@@ -146,10 +146,16 @@ module Cats
146
146
  if plan.plan.program.code == 'PSNP'
147
147
  rounds = plan.rounds.count
148
148
  item_ids = plan.beneficiary_round_plan_items.pluck('beneficiary_plan_item_id').flatten
149
- plan_items = BeneficiaryPlanItem.where(id: item_ids)
150
- invalid = plan_items.select { |pi| pi.rounds - (pi.rounds_served || 0) < rounds }
151
- error = 'There are plan items whose served rounds may exceed the allowed number of rounds.'
152
- raise(StandardError, error) if invalid.count.positive?
149
+ plan_items = BeneficiaryPlanItem.includes(plan_item: :fdp).where(id: item_ids)
150
+ invalid = plan_items.select { |pi| pi.rounds - (pi.rounds_served || 0) < rounds }.map do |pi|
151
+ pi.plan_item.fdp.name
152
+ end
153
+
154
+ if invalid.count.positive?
155
+ msg = invalid.join(', ')
156
+ error = "The FDPs [#{msg}] exceeded their allowed number of rounds."
157
+ raise(StandardError, error)
158
+ end
153
159
 
154
160
  items = plan_items.each_with_object([]) do |plan_item, res|
155
161
  rounds_served = plan_item.rounds_served || 0
data/config/routes.rb CHANGED
@@ -39,6 +39,7 @@ Cats::Core::Engine.routes.draw do
39
39
  end
40
40
  end
41
41
 
42
+ get '/regions/:id/woredas', controller: :locations, action: :woredas, as: :region_woredas
42
43
  post '/locations/filter', controller: :locations, action: :filter
43
44
  resources :locations, except: %i[destroy] do
44
45
  member do
@@ -130,6 +131,12 @@ Cats::Core::Engine.routes.draw do
130
131
  action: :storekeeper_authorizations,
131
132
  as: :storekeeper_receipt_authorizations
132
133
  )
134
+ post(
135
+ '/receipt_authorizations/generate',
136
+ controller: :receipt_authorizations,
137
+ action: :generate,
138
+ as: :generate_receipt_authorizations
139
+ )
133
140
  resources :receipt_authorizations, except: %i[index destroy] do
134
141
  member do
135
142
  get 'transactions', controller: :receipt_transactions, action: :index
@@ -0,0 +1,13 @@
1
+ class CreateCatsCoreProjects < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :cats_core_projects do |t|
4
+ t.string :code, unique: true
5
+ t.string :description
6
+ t.references :source, polymorphic: true
7
+ t.integer :year, null: false
8
+ t.string :implementing_agency, null: false
9
+
10
+ t.timestamps
11
+ end
12
+ end
13
+ end
@@ -6,7 +6,10 @@ class CreateCatsCoreCommodities < ActiveRecord::Migration[6.1]
6
6
  null: false,
7
7
  index: { name: 'uom_on_commodities_indx' },
8
8
  foreign_key: { to_table: :cats_core_unit_of_measures }
9
- t.references :source, polymorphic: true
9
+ t.references :project,
10
+ null: false,
11
+ index: { name: 'project_on_commodity_indx' },
12
+ foreign_key: { to_table: :cats_core_projects }
10
13
  t.float :quantity, null: false
11
14
  t.string :description
12
15
  t.date :best_use_before, null: false
@@ -19,6 +19,10 @@ class CreateCatsCoreDispatchPlanItems < ActiveRecord::Migration[6.1]
19
19
  index: { name: 'commodity_on_dpi_indx' },
20
20
  foreign_key: { to_table: :cats_core_commodities }
21
21
  t.float :quantity, null: false
22
+ t.references :unit,
23
+ null: false,
24
+ index: { name: 'unit_on_dpi_indx' },
25
+ foreign_key: { to_table: :cats_core_unit_of_measures }
22
26
  t.string :commodity_status, null: false, default: 'Good'
23
27
  t.string :status, null: false, default: 'Unauthorized'
24
28
 
@@ -1,5 +1,5 @@
1
1
  module Cats
2
2
  module Core
3
- VERSION = '1.4.35'.freeze
3
+ VERSION = '1.4.38'.freeze
4
4
  end
5
5
  end
@@ -3,7 +3,7 @@ FactoryBot.define do
3
3
  batch_no { FFaker::Name.name }
4
4
  description { FFaker::Name.name }
5
5
  unit_of_measure
6
- source factory: :gift_certificate
6
+ project
7
7
  quantity { 100 }
8
8
  best_use_before { Date.today + 2.month }
9
9
  volume_per_metric_ton { 10 }
@@ -5,6 +5,7 @@ FactoryBot.define do
5
5
  destination factory: :location
6
6
  dispatch_plan
7
7
  quantity { 100 }
8
+ unit factory: :unit_of_measure
8
9
  commodity
9
10
  commodity_status { Cats::Core::Commodity::GOOD }
10
11
  status { Cats::Core::DispatchPlanItem::UNAUTHORIZED }
@@ -0,0 +1,9 @@
1
+ FactoryBot.define do
2
+ factory :project, class: 'Cats::Core::Project' do
3
+ code { FFaker::Name.name }
4
+ description { FFaker::Name.name }
5
+ source factory: :gift_certificate
6
+ year { 2022 }
7
+ implementing_agency { FFaker::Name.name }
8
+ end
9
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cats_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.35
4
+ version: 1.4.38
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-06-06 00:00:00.000000000 Z
11
+ date: 2022-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: active_model_serializers
@@ -258,6 +258,7 @@ files:
258
258
  - app/controllers/cats/core/unit_of_measures_controller.rb
259
259
  - app/controllers/cats/core/users_controller.rb
260
260
  - app/controllers/concerns/cats/core/common.rb
261
+ - app/helpers/cats/core/document_helper.rb
261
262
  - app/jobs/cats/core/application_job.rb
262
263
  - app/models/cats/core/application_module.rb
263
264
  - app/models/cats/core/application_record.rb
@@ -292,6 +293,7 @@ files:
292
293
  - app/models/cats/core/plan_item.rb
293
294
  - app/models/cats/core/plan_item_detail.rb
294
295
  - app/models/cats/core/program.rb
296
+ - app/models/cats/core/project.rb
295
297
  - app/models/cats/core/purchase_order.rb
296
298
  - app/models/cats/core/ration.rb
297
299
  - app/models/cats/core/receipt.rb
@@ -387,6 +389,7 @@ files:
387
389
  - db/migrate/20210717032330_create_cats_core_donations.rb
388
390
  - db/migrate/20210717032602_create_cats_core_gift_certificates.rb
389
391
  - db/migrate/20210717032855_create_cats_core_purchase_orders.rb
392
+ - db/migrate/20210717032927_create_cats_core_projects.rb
390
393
  - db/migrate/20210717033223_create_cats_core_commodities.rb
391
394
  - db/migrate/20210717140855_create_cats_core_stores.rb
392
395
  - db/migrate/20210717171101_create_cats_core_stacks.rb
@@ -467,6 +470,7 @@ files:
467
470
  - spec/factories/cats/core/plan_items.rb
468
471
  - spec/factories/cats/core/plans.rb
469
472
  - spec/factories/cats/core/programs.rb
473
+ - spec/factories/cats/core/projects.rb
470
474
  - spec/factories/cats/core/purchase_orders.rb
471
475
  - spec/factories/cats/core/rations.rb
472
476
  - spec/factories/cats/core/receipt_authorizations.rb