cats_core 1.0.3 → 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 49ed88fd27d58f00d08ca4d5d4bb0bdfce88a64f2fd62aaf4e20abd735363e10
4
- data.tar.gz: e2cfc27e02352ab0d8e000820840b2f14cc48b058d72a8a625c8a832866fe296
3
+ metadata.gz: f63ca1ecd41f30f836b69ec7fe22516bfaa33bf2a11ee4ec5e6caed08e03e9bf
4
+ data.tar.gz: fa4684f9b135314f7a4ffd8a9f193d999075b01ee5dbdbd2468069bedac98453
5
5
  SHA512:
6
- metadata.gz: f295597bd16a8d23ebfa3baccaface0012d3bfd0da5a2800d17f73707f7f85e17b269bd262ab41d4c4b47197d8d3fca22397340d0534c3ba32d17d03316ff08e
7
- data.tar.gz: 9a2db31a794fbdc872f7e7a9b961ae80a887c1edaf54fa7d485bbc935807967afe26b3a6091e1416af6b195397f861dcbeb36d1c2196aca13f0f6184eda4d0b0
6
+ metadata.gz: 6155d6dde44af9a51af349e9528c1e139cfadb333f90324095a608f95aee7d2c5335f35965839d4f273083530d966188736047d9a9c451fa842cf028eb6cfbda
7
+ data.tar.gz: e015635c7c13d4418ecaec59c7d103831f362896732a6386369a22e12c7aa71fdf8e0654a149e8b7926491a6a771f0c5717e7a82e3666a6f9aa8abfb66e446a3
@@ -1,4 +1,30 @@
1
- module CatsCore
2
- class ApplicationController < ActionController::Base
1
+ module Cats
2
+ module Core
3
+ class ApplicationController < ActionController::Base
4
+ before_action :authenticate
5
+
6
+ def current_user
7
+ return if token.nil?
8
+
9
+ user = Cats::Core::User.find(auth['id'])
10
+ @current_user ||= user
11
+ end
12
+
13
+ def authenticate
14
+ render json: { error: 'Unauthorized' }, status: 401 if current_user.nil?
15
+ end
16
+
17
+ private
18
+
19
+ def token
20
+ return nil if request.env['HTTP_AUTHORIZATION'].nil?
21
+
22
+ request.env['HTTP_AUTHORIZATION'].scan(/Bearer (.*)$/).flatten.last
23
+ end
24
+
25
+ def auth
26
+ Cats::Core::TokenAuthService.decode(token)
27
+ end
28
+ end
3
29
  end
4
30
  end
@@ -0,0 +1,15 @@
1
+ module Cats
2
+ module Core
3
+ class NotificationsController < ApplicationController
4
+ def index
5
+ data = { success: true, data: current_user.notifications.newest_first }
6
+ render json: data
7
+ end
8
+
9
+ def unread
10
+ data = { success: true, data: current_user.notifications.unread.newest_first }
11
+ render json: data
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,6 @@
1
+ module Cats
2
+ module Core
3
+ class ApplicationJob < ActiveJob::Base
4
+ end
5
+ end
6
+ end
@@ -12,6 +12,7 @@ module Cats
12
12
  belongs_to :unit_of_measure
13
13
 
14
14
  validates :quantity, presence: true, numericality: { greater_than: 0 }
15
+ validates :volume_per_metric_ton, numericality: { greater_than: 0, allow_nil: true }
15
16
  end
16
17
  end
17
18
  end
@@ -0,0 +1,13 @@
1
+ module Cats
2
+ module Core
3
+ class Notification < ApplicationRecord
4
+ include Noticed::Model
5
+
6
+ belongs_to :recipient, polymorphic: true
7
+
8
+ def message
9
+ to_notification.message
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,24 @@
1
+ module Cats
2
+ module Core
3
+ class ReceiptPlan < ApplicationRecord
4
+ # receipt plan status
5
+ DRAFT = 'Draft'.freeze
6
+ ACCEPTED = 'Accepted'.freeze
7
+ DECLINED = 'Declined'.freeze
8
+ RECEIPT_PLAN_STATUSES = [DRAFT, ACCEPTED, DECLINED].freeze
9
+
10
+ validates :quantity, :status, presence: true
11
+ belongs_to :commodity
12
+ belongs_to :plan_recipient, polymorphic: true
13
+ validates :quantity, numericality: { greater_than: 0 }
14
+ validates :status, inclusion: { in: RECEIPT_PLAN_STATUSES }
15
+ validate :validate_reason_for_decline
16
+
17
+ def validate_reason_for_decline
18
+ return unless reason_for_decline.nil? || reason_for_decline == 'Accepted'
19
+
20
+ errors.add(:reason_for_decline, 'must be specified')
21
+ end
22
+ end
23
+ end
24
+ end
@@ -19,7 +19,8 @@ module Cats
19
19
  validates :quantity, numericality: { greater_than_or_equal_to: 0 }
20
20
  validates :commodity_status, inclusion: { in: Cats::Core::Commodity::COMMODITY_STATUSES }
21
21
  validates :stack_status, inclusion: { in: STACK_STATUSES }
22
- validate :validate_coordinates, :validate_dimensions
22
+ validate :validate_coordinates, :validate_dimensions, :validate_distance_from_wall, :validate_overlap,
23
+ :validate_space_between_stack
23
24
 
24
25
  def validate_coordinates
25
26
  return unless store.present? && length.present? && width.present? && start_x.present? && start_y.present?
@@ -34,6 +35,70 @@ module Cats
34
35
  errors.add(:length, 'cannot exceed store length') if start_x + length > store.length
35
36
  errors.add(:width, 'cannot exceed store width') if start_y + width > store.width
36
37
  end
38
+
39
+ def stacking_rules
40
+ rule = Cats::Core::StackingRule.first
41
+
42
+ # If no rule is defined, then define a default rule
43
+ rule ||= Cats::Core::StackingRule.new(
44
+ space_between_stack: 1,
45
+ distance_from_gangway: 2,
46
+ distance_from_ceiling: 1,
47
+ maximum_height: 5,
48
+ maximum_length: 5,
49
+ maximum_width: 5,
50
+ distance_from_wall: 1
51
+ )
52
+ rule
53
+ end
54
+
55
+ def validate_distance_from_wall
56
+ return unless store.present? && length.present? && width.present? && start_x.present? && start_y.present?
57
+
58
+ rule = stacking_rules
59
+ if start_x < rule.distance_from_wall || store.length - (start_y + length) < rule.distance_from_wall ||
60
+ store.width - (start_x + width) < rule.distance_from_wall || start_y < rule.distance_from_wall
61
+ errors.add(:base,
62
+ message: "The stack must be placed #{rule.distance_from_wall} meter away from a store wall")
63
+ end
64
+ end
65
+
66
+ def validate_overlap
67
+ return unless store.present? && length.present? && width.present? && start_x.present? && start_y.present?
68
+
69
+ stacks = store.stacks.where(stack_status: [RESERVED, ALLOCATED]).where.not(id: id)
70
+ stacks.each do |s|
71
+ errors.add(:base, message: "#{code} overlaps with #{s.code}") if overlaps?(self, s)
72
+ end
73
+ end
74
+
75
+ def validate_space_between_stack
76
+ return unless store.present? && length.present? && width.present? && start_x.present? && start_y.present?
77
+
78
+ stacks = store.stacks.where(stack_status: [RESERVED, ALLOCATED]).where.not(id: id)
79
+ rule = stacking_rules
80
+ new_stack = dup
81
+ new_stack.assign_attributes(start_x: start_x - rule.space_between_stack,
82
+ start_y: start_y - rule.space_between_stack,
83
+ length: length + (2 * rule.space_between_stack),
84
+ width: width + (2 * rule.space_between_stack))
85
+ stacks.each do |s|
86
+ errors.add(:base, message: "#{code} overlaps with #{s.code}") if overlaps?(new_stack, s)
87
+ end
88
+ end
89
+
90
+ # A method that checks if an overlap exists b/n two stacks.
91
+ # An overlap b/n stacks does not occur if one of the stacks is completely above the other stack or
92
+ # if one of the stacks is on the left side of the other stack.
93
+ # If both conditions fail, it means an overlap exists b/n the two stacks
94
+
95
+ def overlaps?(st1, st2)
96
+ return false if st1.start_x > (st2.start_x + st2.width) || st2.start_x > (st1.start_x + st1.width)
97
+
98
+ return false if st1.start_y > (st2.start_y + st2.length) || st2.start_y > (st1.start_y + st1.length)
99
+
100
+ true
101
+ end
37
102
  end
38
103
  end
39
104
  end
@@ -0,0 +1,16 @@
1
+ module Cats
2
+ module Core
3
+ class StackingRule < ApplicationRecord
4
+ validates :distance_from_wall, :space_between_stack, :distance_from_ceiling, :maximum_height, :maximum_length,
5
+ :maximum_width, :distance_from_gangway, presence: true, numericality: { greater_than: 0 }
6
+ validate :validate_only_a_record_exist
7
+
8
+ def validate_only_a_record_exist
9
+ return unless StackingRule.count > 1
10
+
11
+ errors.add(:base,
12
+ 'There is already a stacking rule entry. A new rule can not be added')
13
+ end
14
+ end
15
+ end
16
+ end
@@ -3,6 +3,7 @@ module Cats
3
3
  class Store < ApplicationRecord
4
4
  belongs_to :warehouse, class_name: 'Cats::Core::Location'
5
5
  has_many :stacks
6
+ has_many :receipt_plans, as: :receivable
6
7
 
7
8
  validates :name, :store_keeper_name, :length, :width, :height, presence: true
8
9
  validates :length, :width, :height, numericality: { greater_than: 0 }
@@ -2,10 +2,11 @@ module Cats
2
2
  module Core
3
3
  class User < ApplicationRecord
4
4
  has_secure_password
5
- rolify
5
+ rolify role_cname: 'Cats::Core::Role'
6
6
 
7
7
  belongs_to :application_module
8
8
  has_and_belongs_to_many :roles, join_table: :cats_core_users_cats_core_roles
9
+ has_many :notifications, as: :recipient
9
10
 
10
11
  validates :first_name, :last_name, :email, presence: true
11
12
  validates :password, length: { minimum: 6 }
@@ -0,0 +1,9 @@
1
+ # This is a simple notification class which delivers a
2
+ # message via database delivery method. It requires a
3
+ # +msg+ parameter to instantiate, which represents the
4
+ # text message to deliver.
5
+ class SimpleNotification < Noticed::Base
6
+ deliver_by :database
7
+
8
+ param :msg
9
+ end
@@ -0,0 +1,45 @@
1
+ module Cats
2
+ module Core
3
+ class NotificationService
4
+ NOTIFICATION_RULES = {
5
+ dispatch_plan: {
6
+ application: 'CATS-WH',
7
+ notification: 'DispatchPlanNotification',
8
+ params: [:way_bill],
9
+ recipients: [:warehouse_manager]
10
+ },
11
+ receipt_plan: {
12
+ application: 'CATS-WH',
13
+ notification: 'ReceiptPlanNotification',
14
+ params: [:receipt_plan],
15
+ recipients: [:store_keeper]
16
+ }
17
+ }.freeze
18
+
19
+ def initialize(code, params)
20
+ @code = code
21
+ @params = params
22
+ end
23
+
24
+ def notification_rules
25
+ NOTIFICATION_RULES
26
+ end
27
+
28
+ def create_notifier(rule)
29
+ clazz = rule[:notification].constantize
30
+ clazz.with(**@params)
31
+ end
32
+
33
+ def notify
34
+ rule = notification_rules[@code]
35
+ notifier = create_notifier(rule)
36
+ app_code = rule[:application]
37
+ roles = rule[:recipients]
38
+
39
+ users = Cats::Core::User.joins(:application_module)
40
+ .where(application_module: { prefix: app_code }).with_all_roles(*roles)
41
+ notifier.deliver(users)
42
+ end
43
+ end
44
+ end
45
+ end
data/config/routes.rb CHANGED
@@ -1,2 +1,5 @@
1
1
  Cats::Core::Engine.routes.draw do
2
+ get '/notifications/unread', controller: :notifications, action: :unread
3
+
4
+ resources :notifications, only: [:index]
2
5
  end
@@ -21,6 +21,7 @@ class CreateCatsCoreCommodities < ActiveRecord::Migration[6.1]
21
21
  t.string :description
22
22
  t.boolean :hazardous, null: false, default: false
23
23
  t.date :best_use_before
24
+ t.float :volume_per_metric_ton
24
25
 
25
26
  t.timestamps
26
27
  end
@@ -0,0 +1,15 @@
1
+ class CreateCatsCoreStackingRules < ActiveRecord::Migration[6.1]
2
+ def change
3
+ create_table :cats_core_stacking_rules do |t|
4
+ t.float :distance_from_wall, null: false
5
+ t.float :space_between_stack, null: false
6
+ t.float :distance_from_ceiling, null: false
7
+ t.float :maximum_height, null: false
8
+ t.float :maximum_length, null: false
9
+ t.float :maximum_width, null: false
10
+ t.float :distance_from_gangway, null: false
11
+
12
+ t.timestamps
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
1
+ class CreateCatsCoreNotifications < ActiveRecord::Migration[6.1]
2
+ def change
3
+ create_table :cats_core_notifications do |t|
4
+ t.references :recipient, polymorphic: true, null: false
5
+ t.string :type
6
+ t.jsonb :params
7
+ t.datetime :read_at
8
+
9
+ t.timestamps
10
+ end
11
+ add_index :cats_core_notifications, :read_at
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ class CreateCatsCoreReceiptPlans < ActiveRecord::Migration[6.1]
2
+ def change
3
+ create_table :cats_core_receipt_plans do |t|
4
+ t.float :quantity, null: false
5
+ t.string :status, default: 'Draft'
6
+ t.references :commodity,
7
+ null: false,
8
+ index: { name: 'commodity_on_receipt_plan_indx' },
9
+ foreign_key: { to_table: :cats_core_commodities }
10
+ t.string :reason_for_decline
11
+ t.references :plan_recipient, polymorphic: true
12
+
13
+ t.timestamps
14
+ end
15
+ end
16
+ end
@@ -1,5 +1,5 @@
1
1
  module Cats
2
2
  module Core
3
- VERSION = '1.0.3'.freeze
3
+ VERSION = '1.0.7'.freeze
4
4
  end
5
5
  end
data/lib/cats_core.rb CHANGED
@@ -3,3 +3,4 @@ require 'cats/core/engine'
3
3
  require 'ancestry'
4
4
  require 'rolify'
5
5
  require 'jwt'
6
+ require 'noticed'
@@ -8,5 +8,6 @@ FactoryBot.define do
8
8
  quantity { 100 }
9
9
  hazardous { false }
10
10
  best_use_before { Date.today + 2.month }
11
+ volume_per_metric_ton { 10 }
11
12
  end
12
13
  end
@@ -0,0 +1,8 @@
1
+ FactoryBot.define do
2
+ factory :notification, class: 'Cats::Core::Notification' do
3
+ recipient factory: :user
4
+ type { nil }
5
+ params { {} }
6
+ read_at { Date.today }
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ FactoryBot.define do
2
+ factory :receipt_plan, class: 'Cats::Core::ReceiptPlan' do
3
+ plan_recipient factory: :store
4
+ commodity
5
+ quantity { 1.5 }
6
+ status { 'Accepted' }
7
+ reason_for_decline { FFaker::Name.name }
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ FactoryBot.define do
2
+ factory :stacking_rule, class: 'Cats::Core::StackingRule' do
3
+ space_between_stack { 1 }
4
+ distance_from_gangway { 1.5 }
5
+ distance_from_ceiling { 1 }
6
+ maximum_height { 2.5 }
7
+ maximum_length { 6 }
8
+ maximum_width { 6 }
9
+ distance_from_wall { 1 }
10
+ end
11
+ 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.0.3
4
+ version: 1.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Henock L.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-24 00:00:00.000000000 Z
11
+ date: 2021-08-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ancestry
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: 2.2.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: noticed
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rails
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -189,6 +203,8 @@ files:
189
203
  - README.md
190
204
  - Rakefile
191
205
  - app/controllers/cats/core/application_controller.rb
206
+ - app/controllers/cats/core/notifications_controller.rb
207
+ - app/jobs/cats/core/application_job.rb
192
208
  - app/models/cats/core/application_module.rb
193
209
  - app/models/cats/core/application_record.rb
194
210
  - app/models/cats/core/commodity.rb
@@ -198,16 +214,21 @@ files:
198
214
  - app/models/cats/core/location.rb
199
215
  - app/models/cats/core/menu.rb
200
216
  - app/models/cats/core/menu_item.rb
217
+ - app/models/cats/core/notification.rb
201
218
  - app/models/cats/core/program.rb
219
+ - app/models/cats/core/receipt_plan.rb
202
220
  - app/models/cats/core/role.rb
203
221
  - app/models/cats/core/role_menu.rb
204
222
  - app/models/cats/core/stack.rb
223
+ - app/models/cats/core/stacking_rule.rb
205
224
  - app/models/cats/core/store.rb
206
225
  - app/models/cats/core/transporter.rb
207
226
  - app/models/cats/core/unit_of_measure.rb
208
227
  - app/models/cats/core/user.rb
209
228
  - app/models/cats/core/way_bill.rb
210
229
  - app/models/cats/core/way_bill_item.rb
230
+ - app/notifications/cats/core/simple_notification.rb
231
+ - app/services/cats/core/notification_service.rb
211
232
  - app/services/cats/core/token_auth_service.rb
212
233
  - config/routes.rb
213
234
  - db/migrate/20210715114238_create_cats_core_application_modules.rb
@@ -228,6 +249,9 @@ files:
228
249
  - db/migrate/20210718045516_create_cats_core_way_bills.rb
229
250
  - db/migrate/20210718050751_create_cats_core_way_bill_items.rb
230
251
  - db/migrate/20210718202957_create_cats_core_commodity_transactions.rb
252
+ - db/migrate/20210719133710_create_cats_core_stacking_rules.rb
253
+ - db/migrate/20210724074657_create_cats_core_notifications.rb
254
+ - db/migrate/20210727074646_create_cats_core_receipt_plans.rb
231
255
  - lib/cats/core.rb
232
256
  - lib/cats/core/engine.rb
233
257
  - lib/cats/core/version.rb
@@ -241,9 +265,12 @@ files:
241
265
  - spec/factories/cats/core/locations.rb
242
266
  - spec/factories/cats/core/menu_items.rb
243
267
  - spec/factories/cats/core/menus.rb
268
+ - spec/factories/cats/core/notifications.rb
244
269
  - spec/factories/cats/core/programs.rb
270
+ - spec/factories/cats/core/receipt_plans.rb
245
271
  - spec/factories/cats/core/role_menus.rb
246
272
  - spec/factories/cats/core/roles.rb
273
+ - spec/factories/cats/core/stacking_rules.rb
247
274
  - spec/factories/cats/core/stacks.rb
248
275
  - spec/factories/cats/core/stores.rb
249
276
  - spec/factories/cats/core/transporters.rb