comee_core 0.1.10

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 (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