comee_core 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +28 -0
  4. data/Rakefile +10 -0
  5. data/app/controllers/comee/core/access_controller.rb +33 -0
  6. data/app/controllers/comee/core/application_controller.rb +43 -0
  7. data/app/controllers/comee/core/currencies_controller.rb +13 -0
  8. data/app/controllers/comee/core/notifications_controller.rb +38 -0
  9. data/app/controllers/comee/core/product_types_controller.rb +18 -0
  10. data/app/controllers/comee/core/products_controller.rb +13 -0
  11. data/app/controllers/comee/core/suppliers_controller.rb +13 -0
  12. data/app/controllers/comee/core/units_controller.rb +13 -0
  13. data/app/controllers/comee/core/users_controller.rb +13 -0
  14. data/app/controllers/concerns/comee/core/common.rb +73 -0
  15. data/app/jobs/comee_core/application_job.rb +4 -0
  16. data/app/mailers/comee/core/application_mailer.rb +8 -0
  17. data/app/mailers/comee/core/supplier_mailer.rb +18 -0
  18. data/app/models/comee/core/application_record.rb +7 -0
  19. data/app/models/comee/core/back_order.rb +33 -0
  20. data/app/models/comee/core/back_order_item.rb +16 -0
  21. data/app/models/comee/core/client.rb +10 -0
  22. data/app/models/comee/core/client_order.rb +23 -0
  23. data/app/models/comee/core/client_order_item.rb +10 -0
  24. data/app/models/comee/core/client_price.rb +20 -0
  25. data/app/models/comee/core/currency.rb +8 -0
  26. data/app/models/comee/core/invoice.rb +23 -0
  27. data/app/models/comee/core/invoice_item.rb +18 -0
  28. data/app/models/comee/core/master_price.rb +35 -0
  29. data/app/models/comee/core/notification.rb +17 -0
  30. data/app/models/comee/core/product.rb +47 -0
  31. data/app/models/comee/core/product_lookup.rb +10 -0
  32. data/app/models/comee/core/product_type.rb +19 -0
  33. data/app/models/comee/core/supplier.rb +10 -0
  34. data/app/models/comee/core/unit.rb +10 -0
  35. data/app/models/comee/core/user.rb +13 -0
  36. data/app/notifications/comee/core/new_order_notification.rb +23 -0
  37. data/app/serializers/comee/core/currency_serializer.rb +7 -0
  38. data/app/serializers/comee/core/product_serializer.rb +8 -0
  39. data/app/serializers/comee/core/product_type_serializer.rb +7 -0
  40. data/app/serializers/comee/core/supplier_serializer.rb +7 -0
  41. data/app/serializers/comee/core/unit_serializer.rb +7 -0
  42. data/app/serializers/comee/core/user_serializer.rb +7 -0
  43. data/app/services/comee/core/product_lookup_service.rb +38 -0
  44. data/app/services/comee/core/token_service.rb +13 -0
  45. data/app/utils/comee/core/period.rb +35 -0
  46. data/app/views/comee/core/supplier_mailer/new_order_notification.html.erb +8 -0
  47. data/app/views/layouts/comee/core/mailer.html.erb +13 -0
  48. data/app/views/layouts/comee/core/mailer.text.erb +1 -0
  49. data/config/locales/de.yml +13 -0
  50. data/config/locales/en.yml +13 -0
  51. data/config/routes.rb +21 -0
  52. data/config/spring.rb +1 -0
  53. data/db/migrate/20230727153013_create_comee_core_units.rb +12 -0
  54. data/db/migrate/20230728011037_create_comee_core_currencies.rb +11 -0
  55. data/db/migrate/20230728012836_create_comee_core_product_types.rb +13 -0
  56. data/db/migrate/20230728014322_create_comee_core_products.rb +21 -0
  57. data/db/migrate/20230728014330_create_comee_core_users.rb +14 -0
  58. data/db/migrate/20230728122618_create_comee_core_suppliers.rb +17 -0
  59. data/db/migrate/20230728123039_create_comee_core_clients.rb +18 -0
  60. data/db/migrate/20230728123928_create_comee_core_back_orders.rb +20 -0
  61. data/db/migrate/20230728125723_create_comee_core_back_order_items.rb +22 -0
  62. data/db/migrate/20230730061225_create_comee_core_notifications.rb +13 -0
  63. data/db/migrate/20230812190652_create_comee_core_client_orders.rb +24 -0
  64. data/db/migrate/20230812212844_create_comee_core_client_order_items.rb +18 -0
  65. data/db/migrate/20230813235946_create_comee_core_master_prices.rb +26 -0
  66. data/db/migrate/20230814151601_create_comee_core_client_prices.rb +23 -0
  67. data/db/migrate/20230914041307_create_comee_core_external_products.rb +18 -0
  68. data/db/migrate/20230915205522_create_comee_core_invoices.rb +24 -0
  69. data/db/migrate/20230915205648_create_comee_core_invoice_items.rb +19 -0
  70. data/lib/comee/core/engine.rb +24 -0
  71. data/lib/comee/core/version.rb +5 -0
  72. data/lib/comee/core.rb +4 -0
  73. data/lib/comee_core.rb +6 -0
  74. data/lib/tasks/comee_core_tasks.rake +4 -0
  75. data/spec/factories/comee/core/back_order_items.rb +11 -0
  76. data/spec/factories/comee/core/back_orders.rb +13 -0
  77. data/spec/factories/comee/core/client_order_items.rb +8 -0
  78. data/spec/factories/comee/core/client_orders.rb +13 -0
  79. data/spec/factories/comee/core/client_prices.rb +12 -0
  80. data/spec/factories/comee/core/clients.rb +9 -0
  81. data/spec/factories/comee/core/currencies.rb +6 -0
  82. data/spec/factories/comee/core/invoice_items.rb +9 -0
  83. data/spec/factories/comee/core/invoices.rb +16 -0
  84. data/spec/factories/comee/core/master_prices.rb +15 -0
  85. data/spec/factories/comee/core/notifications.rb +8 -0
  86. data/spec/factories/comee/core/product_lookups.rb +7 -0
  87. data/spec/factories/comee/core/product_types.rb +8 -0
  88. data/spec/factories/comee/core/products.rb +10 -0
  89. data/spec/factories/comee/core/suppliers.rb +9 -0
  90. data/spec/factories/comee/core/units.rb +7 -0
  91. data/spec/factories/comee/core/users.rb +9 -0
  92. metadata +346 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 75efe50766a9b07ed19c73cf8102bc7b17dcd21d6b7936e1fc6df6f130e96ff2
4
+ data.tar.gz: bcc9e495cde736a992355c3e17b5f1fa6c1f1ce04bd56ca0c6f87f95a85966df
5
+ SHA512:
6
+ metadata.gz: e569094649d5a95f37c524620e5f54faee56d2a9751b29cf8e49b5f9fc43b30c37e767e67f49f065b0075c77a5d4a5ade1b5c08dc2951a4d4f54a6ea79e651f8
7
+ data.tar.gz: b930dc71cd29633746849fe94d2bd40163b36359215ecfe9d162d0d785a96320f5dd727bcfe5cf6eea9795ed27b389cacc67adb9dc36036ce721ca6244860e48
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2023 Henock L.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # ComeeCore
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ How to use my plugin.
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem "comee_core"
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+ ```bash
21
+ $ gem install comee_core
22
+ ```
23
+
24
+ ## Contributing
25
+ Contribution directions go here.
26
+
27
+ ## License
28
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
9
+ require "rspec/core/rake_task"
10
+ RSpec::Core::RakeTask.new(spec: "app:db:test:prepare")
@@ -0,0 +1,33 @@
1
+ module Comee
2
+ module Core
3
+ class AccessController < ApplicationController
4
+ skip_before_action :authenticate, only: [:login]
5
+
6
+ def login
7
+ user = User.find_by(email: auth_params[:email])
8
+ if user
9
+ if user.authenticate(auth_params[:password])
10
+ payload = {
11
+ id: user.id,
12
+ name: user.name,
13
+ email: user.email,
14
+ user_type: user.user_type
15
+ }
16
+ jwt = TokenService.issue(payload)
17
+ render json: {token: jwt, user: payload}
18
+ else
19
+ render json: {error: "Invalid password."}, status: 400
20
+ end
21
+ else
22
+ render json: {error: "User does not exist."}, status: 400
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def auth_params
29
+ params.require(:auth).permit(:email, :password)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,43 @@
1
+ module Comee
2
+ module Core
3
+ class ApplicationController < ActionController::API
4
+ before_action :authenticate
5
+
6
+ def current_user
7
+ return if token.nil?
8
+
9
+ user = 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
+ # In case we want to disable bullet for specific controller actions
18
+ def skip_bullet
19
+ previous_value = Bullet.enable?
20
+ Bullet.enable = false
21
+ yield
22
+ ensure
23
+ Bullet.enable = previous_value
24
+ end
25
+
26
+ private
27
+
28
+ def serialize(data)
29
+ ActiveModelSerializers::SerializableResource.new(data)
30
+ end
31
+
32
+ def token
33
+ return nil if request.env["HTTP_AUTHORIZATION"].nil?
34
+
35
+ request.env["HTTP_AUTHORIZATION"].scan(/Bearer (.*)$/).flatten.last
36
+ end
37
+
38
+ def auth
39
+ TokenService.decode(token)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,13 @@
1
+ module Comee
2
+ module Core
3
+ class CurrenciesController < ApplicationController
4
+ include Common
5
+
6
+ private
7
+
8
+ def model_params
9
+ params.require(:payload).permit(:code, :name)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,38 @@
1
+ module Comee
2
+ module Core
3
+ class NotificationsController < ApplicationController
4
+ before_action :set_notification, only: %i[mark_as_read mark_as_unread]
5
+
6
+ def index
7
+ data = Comee::Core::Notification.messages(current_user.notifications.newest_first)
8
+ render json: {success: true, data: data}
9
+ end
10
+
11
+ def read
12
+ data = Notification.messages(current_user.notifications.read.newest_first)
13
+ render json: {success: true, data: data}
14
+ end
15
+
16
+ def unread
17
+ data = Notification.messages(current_user.notifications.unread.newest_first)
18
+ render json: {success: true, data: data}
19
+ end
20
+
21
+ def mark_as_read
22
+ @notification.mark_as_read!
23
+ render json: {success: true, data: @notification.message}
24
+ end
25
+
26
+ def mark_as_unread
27
+ @notification.mark_as_unread!
28
+ render json: {success: true, data: @notification.message}
29
+ end
30
+
31
+ private
32
+
33
+ def set_notification
34
+ @notification = Notification.find(params[:id])
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,18 @@
1
+ module Comee
2
+ module Core
3
+ class ProductTypesController < ApplicationController
4
+ include Common
5
+
6
+ def products
7
+ products = Product.where(product_type_id: params[:id])
8
+ render json: {success: true, data: serialize(products)}
9
+ end
10
+
11
+ private
12
+
13
+ def model_params
14
+ params.require(:payload).permit(:code, :name, :description, metadata_schema: {})
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ module Comee
2
+ module Core
3
+ class ProductsController < ApplicationController
4
+ include Common
5
+
6
+ private
7
+
8
+ def model_params
9
+ params.required(:payload).permit(:code, :name, :description, :product_type_id, :unit_id, :metadata)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Comee
2
+ module Core
3
+ class SuppliersController < ApplicationController
4
+ include Common
5
+
6
+ private
7
+
8
+ def model_params
9
+ params.require(:payload).permit(:code, :name, :address, :locale)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Comee
2
+ module Core
3
+ class UnitsController < ApplicationController
4
+ include Common
5
+
6
+ private
7
+
8
+ def model_params
9
+ params.require(:payload).permit(:code, :name, :unit_type)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Comee
2
+ module Core
3
+ class UsersController < ApplicationController
4
+ include Common
5
+
6
+ private
7
+
8
+ def model_params
9
+ params.require(:payload).permit(:name, :email, :active, :password, :password_confirmation, :user_type)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,73 @@
1
+ module Comee
2
+ module Core
3
+ module Common
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ before_action :set_clazz
8
+ before_action :set_object, only: %i[show update]
9
+ end
10
+
11
+ def index
12
+ data = if block_given?
13
+ yield
14
+ else
15
+ @clazz.all
16
+ end
17
+ render json: {success: true, data: serialize(data)}
18
+ end
19
+
20
+ def show
21
+ render json: {success: true, data: serialize(@obj)}
22
+ end
23
+
24
+ def create
25
+ obj = if block_given?
26
+ yield
27
+ else
28
+ @clazz.new(model_params)
29
+ end
30
+ if obj.save
31
+ render json: {success: true, data: serialize(obj)}, status: :created
32
+ else
33
+ render json: {success: false, error: obj.errors.full_messages[0]}, status: :unprocessable_entity
34
+ end
35
+ rescue => e
36
+ render json: {success: false, error: e.message}
37
+ end
38
+
39
+ def update
40
+ obj = if block_given?
41
+ yield
42
+ else
43
+ obj = @obj
44
+ end
45
+ if obj.update(model_params)
46
+ render json: {success: true, data: serialize(obj)}
47
+ else
48
+ render json: {success: false, error: obj.errors.full_messages[0]}, status: :unprocessable_entity
49
+ end
50
+ rescue => e
51
+ render json: {success: false, error: e.message}
52
+ end
53
+
54
+ private
55
+
56
+ def serialize(data)
57
+ ActiveModelSerializers::SerializableResource.new(data)
58
+ end
59
+
60
+ def set_clazz
61
+ @clazz = "Comee::Core::#{controller_name.classify}".constantize
62
+ end
63
+
64
+ def set_object
65
+ @obj = @clazz.find(params[:id])
66
+ end
67
+
68
+ # This class should be overridden by respective child controllers
69
+ def model_params
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,4 @@
1
+ module ComeeCore
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,8 @@
1
+ module Comee
2
+ module Core
3
+ class ApplicationMailer < ActionMailer::Base
4
+ default from: "notifications@maveco.com"
5
+ layout "mailer"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,18 @@
1
+ module Comee
2
+ module Core
3
+ class SupplierMailer < ApplicationMailer
4
+ default from: "notifications@maveco.com"
5
+
6
+ def new_order_notification
7
+ @back_order = params[:back_order]
8
+ I18n.with_locale(@back_order.supplier.locale) do
9
+ mail(
10
+ from: "support@maveko.com",
11
+ to: @back_order.supplier.user.email,
12
+ subject: "New Order Notification"
13
+ )
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ module Comee
2
+ module Core
3
+ class ApplicationRecord < ActiveRecord::Base
4
+ self.abstract_class = true
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,33 @@
1
+ module Comee
2
+ module Core
3
+ class BackOrder < ApplicationRecord
4
+ enum :status, {draft: 0, confirmed: 1}
5
+
6
+ after_create_commit :notify_supplier
7
+
8
+ belongs_to :supplier
9
+ has_many :back_order_items
10
+
11
+ has_noticed_notifications model_name: "Comee::Core::Notification"
12
+
13
+ validates :order_number, presence: true, uniqueness: true
14
+ validates :order_date, :delivery_date, :terms, :delivery_address, :invoice_address, :status, presence: true
15
+
16
+ delegate(:name, to: :supplier, prefix: true)
17
+
18
+ def self.ransackable_attributes(auth_object = nil)
19
+ ["delivery_address", "delivery_date", "invoice_address", "order_date", "order_number", "status", "supplier_id"]
20
+ end
21
+
22
+ def self.ransackable_associations(auth_object = nil)
23
+ []
24
+ end
25
+
26
+ private
27
+
28
+ def notify_supplier
29
+ Comee::Core::NewOrderNotification.with(back_order: self).deliver_later(supplier.user)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,16 @@
1
+ module Comee
2
+ module Core
3
+ class BackOrderItem < ApplicationRecord
4
+ enum :item_status, {available: 0, out_of_stock: 1}
5
+
6
+ belongs_to :back_order
7
+ belongs_to :product
8
+
9
+ validates :item_status, presence: true
10
+ validates :requested_quantity, :requested_unit_price, :supplier_quantity, :supplier_unit_price, presence: true, numericality: {greater_than: 0}
11
+
12
+ delegate(:code, :name, :description, to: :product, prefix: true)
13
+ delegate(:unit_code, :unit_name, to: :product, prefix: false)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ module Comee
2
+ module Core
3
+ class Client < ApplicationRecord
4
+ belongs_to :user, optional: true
5
+
6
+ validates :code, :name, :address, :locale, presence: true
7
+ validates :code, uniqueness: true
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,23 @@
1
+ module Comee
2
+ module Core
3
+ class ClientOrder < ApplicationRecord
4
+ belongs_to :client
5
+ has_many :client_order_items
6
+
7
+ enum :status, {draft: 0, confirmed: 1}
8
+
9
+ validates :order_number, presence: true, uniqueness: true
10
+ validates :order_date, :delivery_date, :terms, :delivery_address, :invoice_address, :status, presence: true
11
+
12
+ delegate(:name, to: :client, prefix: true)
13
+
14
+ def self.ransackable_attributes(auth_object = nil)
15
+ ["delivery_address", "delivery_date", "invoice_address", "order_date", "order_number", "status", "client_id"]
16
+ end
17
+
18
+ def self.ransackable_associations(auth_object = nil)
19
+ []
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,10 @@
1
+ module Comee
2
+ module Core
3
+ class ClientOrderItem < ApplicationRecord
4
+ belongs_to :client_order
5
+ belongs_to :product
6
+
7
+ validates :quantity, :price, presence: true, numericality: {greater_than: 0}
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,20 @@
1
+ module Comee
2
+ module Core
3
+ class ClientPrice < ApplicationRecord
4
+ belongs_to :product
5
+ belongs_to :client
6
+
7
+ validates :valid_from, :valid_to, :new_price, presence: true
8
+ validates :old_price, :new_price, numericality: {greater_than: 0, allow_nil: true}
9
+ validates :product_id, uniqueness: {scope: :client_id}
10
+ validate :validate_price_validity_dates
11
+
12
+ def validate_price_validity_dates
13
+ return unless valid_from && valid_to
14
+
15
+ period = Period.new(valid_from, valid_to)
16
+ errors.add(:base, "Price validity date range is not correct.") unless period.valid?
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,8 @@
1
+ module Comee
2
+ module Core
3
+ class Currency < ApplicationRecord
4
+ validates :code, presence: true, uniqueness: true
5
+ validates :name, presence: true
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,23 @@
1
+ module Comee
2
+ module Core
3
+ class Invoice < ApplicationRecord
4
+ before_save :update_invoice_total
5
+ belongs_to :client_order
6
+ has_many :invoice_items
7
+
8
+ enum :status, {draft: 0, approved: 1}
9
+ enum :payment_status, {not_settled: 0, settled: 1}
10
+
11
+ validates :invoice_no, presence: true, uniqueness: true
12
+ validates :date_issued, :payment_term, :status, :payment_status, presence: true
13
+ validates :additional_charges, :total_price, numericality: {greater_than_or_equal_to: 0, allow_nil: true}
14
+
15
+ def update_invoice_total
16
+ self.additional_charges ||= 0
17
+ self.total_price ||= 0
18
+ self.total_price -= additional_charges_was if additional_charges_was && additional_charges_changed?
19
+ self.total_price += additional_charges
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ module Comee
2
+ module Core
3
+ class InvoiceItem < ApplicationRecord
4
+ before_save { self.total_price = unit_price * quantity }
5
+ after_save :update_invoice_total
6
+
7
+ belongs_to :client_order_item
8
+ belongs_to :invoice
9
+
10
+ validates :quantity, :unit_price, :total_price, presence: true, numericality: {greater_than: 0}
11
+
12
+ def update_invoice_total
13
+ invoice.total_price = InvoiceItem.where(invoice: invoice).map(&:total_price).sum
14
+ invoice.save!
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,35 @@
1
+ module Comee
2
+ module Core
3
+ class MasterPrice < ApplicationRecord
4
+ belongs_to :supplier
5
+ belongs_to :product
6
+
7
+ validates :pp_valid_from, :pp_valid_to, :sp_valid_from, :sp_valid_to, :new_pprice, :new_sprice, presence: true
8
+ validates :old_pprice, :old_sprice, numericality: {greater_than: 0, allow_nil: true}
9
+ validates :new_pprice, :new_sprice, numericality: {greater_than: 0}
10
+ validates :product_id, uniqueness: {scope: :supplier_id}
11
+ validate :validate_primary_price, :validate_purchase_price_validity_dates, :validate_selling_price_validity_dates
12
+
13
+ def validate_primary_price
14
+ return unless product && primary
15
+
16
+ count = MasterPrice.where(product:, primary: true).count
17
+ errors.add(:base, "There is already a primary supplier for item '#{product.code}'") if count.positive?
18
+ end
19
+
20
+ def validate_purchase_price_validity_dates
21
+ return unless pp_valid_from && pp_valid_to
22
+
23
+ period = Period.new(pp_valid_from, pp_valid_to)
24
+ errors.add(:base, "Purchase price validity date range is not correct.") unless period.valid?
25
+ end
26
+
27
+ def validate_selling_price_validity_dates
28
+ return unless sp_valid_from && sp_valid_to
29
+
30
+ period = Period.new(sp_valid_from, sp_valid_to)
31
+ errors.add(:base, "Selling price validity date range is not correct.") unless period.valid?
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,17 @@
1
+ module Comee
2
+ module Core
3
+ class Notification < ApplicationRecord
4
+ include Noticed::Model
5
+
6
+ belongs_to :recipient, polymorphic: true
7
+
8
+ def message
9
+ {id: id, read: !read_at.nil?, created_at: created_at}.merge(to_notification.message)
10
+ end
11
+
12
+ def self.messages(notifications)
13
+ notifications.includes(:recipient).map(&:message)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,47 @@
1
+ module Comee
2
+ module Core
3
+ class Product < ApplicationRecord
4
+ belongs_to :product_type
5
+ belongs_to :unit
6
+
7
+ validates :code, presence: true, uniqueness: true
8
+ validates :name, presence: true
9
+ validate :metadata_must_be_based_on_metadata_schema, if: -> { product_type.present? }
10
+
11
+ delegate(:code, :name, to: :product_type, prefix: true)
12
+ delegate(:code, :name, to: :unit, prefix: true)
13
+
14
+ def metadata_must_be_based_on_metadata_schema
15
+ metadata_schema = product_type.metadata_schema
16
+ return unless metadata_schema.present? && metadata.present?
17
+
18
+ properties = metadata_schema["properties"]
19
+ fields = properties.keys
20
+ required = metadata_schema["required"]
21
+ diff = metadata.keys - fields
22
+ unless diff.empty?
23
+ errors.add(:metadata, "holds fields that are not allowed #{diff}.")
24
+ return
25
+ end
26
+
27
+ diff = required - metadata.keys
28
+ unless diff.empty?
29
+ errors.add(:metadata, "should contain the following required fields #{diff}.")
30
+ return
31
+ end
32
+
33
+ metadata.each do |k, v|
34
+ if v.class.to_s.downcase != properties[k]["type"]
35
+ errors.add(:metadata, "contains invalid value for field #{k}.")
36
+ end
37
+ if properties[k].key?("min") && v < properties[k]["min"]
38
+ errors.add(:base, "The value of #{k} cannot be lower than #{properties[k]["min"]}.")
39
+ end
40
+ if properties[k].key?("max") && v > properties[k]["max"]
41
+ errors.add(:base, "The value of #{k} cannot be higher than #{properties[k]["max"]}.")
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end