cats_core 1.0.1 → 1.0.5

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: bd23a6a4b33e334c5dcecb23f886582c38c95c37e56107776a366787ff294f39
4
- data.tar.gz: fcbe1e8c6163fa0fb3e65b3e7852bc73e98558670c4d9cedd4b0a7906faf6ca4
3
+ metadata.gz: b6ff0706b8636cf94fea0714f73ed8fead005d08a2647f5365f43ac7ba6a53b6
4
+ data.tar.gz: ab055e9fc942f99eed1e28ab7a755e0c5f54098a854705cf46c6c9bc880d0cff
5
5
  SHA512:
6
- metadata.gz: 71a028925276687036297d99cedafbfeeaa66f4f2cfd2cc6f5b97d639ce1d5dc7685afc4cde1db91e38beede1e5054371721690656807b296ea0900686146b80
7
- data.tar.gz: 7f02f1afdace68ce5075c974a657d56869676c29196097a546d46ed3cdd9fc78d7e916d489c88bc5acd7893237894a44e042c662400f6d8fbf5afd1fdb69654f
6
+ metadata.gz: 82950facfa04e42a6aa4e934bfe9f950c158db65dbf55e61c6aff04ad2c9041354e2560a61222817864c5cd8288649282e099f362e7014f7abf65d3ba628a441
7
+ data.tar.gz: 8e951eebc249a57a1868dbc9155c1818bfc791ef6a0c987aaccf203c34e2d9fab7a3598b138c70de6e6c5f910cd8d2970e838c9719198f9ccd1d6380b9989143
@@ -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
@@ -2,6 +2,7 @@ module Cats
2
2
  module Core
3
3
  class Menu < ApplicationRecord
4
4
  belongs_to :application_module
5
+ has_many :menu_items
5
6
 
6
7
  validates :label, presence: true
7
8
  end
@@ -0,0 +1,9 @@
1
+ module Cats
2
+ module Core
3
+ class Notification < ApplicationRecord
4
+ include Noticed::Model
5
+
6
+ belongs_to :recipient, polymorphic: true
7
+ end
8
+ end
9
+ 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
@@ -2,6 +2,7 @@ module Cats
2
2
  module Core
3
3
  class Role < ApplicationRecord
4
4
  belongs_to :application_module
5
+ has_many :role_menus
5
6
 
6
7
  validates :name, presence: true
7
8
  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,59 @@ 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
+ rule
42
+ end
43
+
44
+ def validate_distance_from_wall
45
+ return unless store.present? && length.present? && width.present? && start_x.present? && start_y.present?
46
+
47
+ rule = stacking_rules
48
+ if start_x < rule.distance_from_wall || store.length - (start_y + length) < rule.distance_from_wall ||
49
+ store.width - (start_x + width) < rule.distance_from_wall || start_y < rule.distance_from_wall
50
+ errors.add(:base,
51
+ message: "The stack must be placed #{rule.distance_from_wall} meter away from a store wall")
52
+ end
53
+ end
54
+
55
+ def validate_overlap
56
+ return unless store.present? && length.present? && width.present? && start_x.present? && start_y.present?
57
+
58
+ stacks = store.stacks.where(stack_status: [RESERVED, ALLOCATED]).where.not(id: id)
59
+ stacks.each do |s|
60
+ errors.add(:base, message: "#{code} overlaps with #{s.code}") if overlaps?(self, s)
61
+ end
62
+ end
63
+
64
+ def validate_space_between_stack
65
+ return unless store.present? && length.present? && width.present? && start_x.present? && start_y.present?
66
+
67
+ stacks = store.stacks.where(stack_status: [RESERVED, ALLOCATED]).where.not(id: id)
68
+ rule = stacking_rules
69
+ new_stack = dup
70
+ new_stack.assign_attributes(start_x: start_x - rule.space_between_stack,
71
+ start_y: start_y - rule.space_between_stack,
72
+ length: length + (2 * rule.space_between_stack),
73
+ width: width + (2 * rule.space_between_stack))
74
+ stacks.each do |s|
75
+ errors.add(:base, message: "#{code} overlaps with #{s.code}") if overlaps?(new_stack, s)
76
+ end
77
+ end
78
+
79
+ # A method that checks if an overlap exists b/n two stacks.
80
+ # An overlap b/n stacks does not occur if one of the stacks is completely above the other stack or
81
+ # if one of the stacks is on the left side of the other stack.
82
+ # If both conditions fail, it means an overlap exists b/n the two stacks
83
+
84
+ def overlaps?(st1, st2)
85
+ return false if st1.start_x > (st2.start_x + st2.width) || st2.start_x > (st1.start_x + st1.width)
86
+
87
+ return false if st1.start_y > (st2.start_y + st2.length) || st2.start_y > (st1.start_y + st1.length)
88
+
89
+ true
90
+ end
37
91
  end
38
92
  end
39
93
  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,9 +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
+ has_and_belongs_to_many :roles, join_table: :cats_core_users_cats_core_roles
9
+ has_many :notifications, as: :recipient
8
10
 
9
11
  validates :first_name, :last_name, :email, presence: true
10
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,41 @@
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 notify
29
+ rules = notification_rules
30
+ clazz = rules[@code][:notification].constantize
31
+ app_code = rules[@code][:application]
32
+ roles = rules[@code][:recipients]
33
+
34
+ notification = clazz.with(**@params)
35
+ users = Cats::Core::User.joins(:application_module)
36
+ .where(application_module: { prefix: app_code }).with_all_roles(*roles)
37
+ notification.deliver(users)
38
+ end
39
+ end
40
+ end
41
+ 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
@@ -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.1'.freeze
3
+ VERSION = '1.0.5'.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'
@@ -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.1
4
+ version: 1.0.5
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-23 00:00:00.000000000 Z
11
+ date: 2021-07-29 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