bscf-core 0.3.1 → 0.3.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 02ed83b7ec66c52ec79915063727186f0b8a976a29ffc23db1a8da3aa94719cb
4
- data.tar.gz: a9c0bb068c864c59da70fce33bb1e58088b6748bfeabec939fda97c86a6fdadd
3
+ metadata.gz: dd47b3e011e60ef5b4cbcb310e70a01168420828e1fc9a14f28aead37b398e74
4
+ data.tar.gz: 50f8a023c47c05b92aad12a9e14aa56e09dfd4678100fd80b3ca799d1ba711f2
5
5
  SHA512:
6
- metadata.gz: 252d77e24bde7d0944bb27733fba588d64c06d6394bb2230153cce4640479fb80c55a6bd0f9d66d64a174166829ed441cc88a5d0f8600c9522eda5a732e8958d
7
- data.tar.gz: f62401b9132ac9289c6eb040cab41a15439dae36d6a987639fe0e5885fa0ca3d1785e38eca20de93c82c8ce303b79b7edff8f40136f8b755ab81e1830a308351
6
+ metadata.gz: 86941b153a3078dbfc9f47e1673eb51d3613d00cd719152779aba72fc28fc1d909c90682811f17e158b2e372284b44cba01838237b9dda9ff6fbcde73f2aca2f
7
+ data.tar.gz: 8e942a30a68662a7240e9ebf944a3f7692c6b4ae8afb51a353e8c2d91847611731b15f1ce83fe44ef1bef1c963c93bd2f0726e94152180a4360ec95bed0ee859
@@ -0,0 +1,40 @@
1
+ module Bscf
2
+ module Core
3
+ class BusinessDocument < ApplicationRecord
4
+ belongs_to :business
5
+ has_one_attached :file
6
+
7
+ before_validation :format_document_name
8
+
9
+ validates :document_number, presence: true
10
+ validates :document_name, presence: true
11
+ validates :business_id, presence: true
12
+ validates :verified_at, presence: true, if: :is_verified?
13
+ validates :file, presence: true
14
+ validate :block_executable_files
15
+
16
+ scope :verified, -> { where(is_verified: true) }
17
+ scope :unverified, -> { where(is_verified: false) }
18
+
19
+ private
20
+
21
+ def format_document_name
22
+ self.document_name = document_name.strip.titleize if document_name.present?
23
+ end
24
+
25
+ def block_executable_files
26
+ return unless file.attached?
27
+
28
+ if file.content_type.in?(%w[
29
+ application/x-msdownload
30
+ application/x-executable
31
+ application/x-msdos-program
32
+ application/x-ms-dos-executable
33
+ application/x-shellscript
34
+ ])
35
+ errors.add(:file, "cannot be an executable file")
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -8,7 +8,6 @@ module Bscf
8
8
 
9
9
  enum :listing_type, { buy: 0, sell: 1 }
10
10
  enum :status, { open: 0, partially_matched: 1, matched: 2, completed: 3, cancelled: 4 }
11
-
12
11
  end
13
12
  end
14
13
  end
@@ -2,7 +2,12 @@ module Bscf
2
2
  module Core
3
3
  class Product < ApplicationRecord
4
4
  belongs_to :category
5
+ has_one_attached :thumbnail
6
+ has_many_attached :images
5
7
 
8
+ validates :sku, presence: true, uniqueness: true
9
+ validates :name, presence: true
10
+ validates :description, presence: true
6
11
  has_many :rfq_items
7
12
  has_many :request_for_quotations, through: :rfq_items
8
13
 
@@ -0,0 +1,36 @@
1
+ module Bscf::Core
2
+ class WholesalerProduct < ApplicationRecord
3
+ belongs_to :business
4
+ belongs_to :product
5
+
6
+ validates :minimum_order_quantity, presence: true, numericality: { greater_than: 0 }
7
+ validates :wholesale_price, presence: true, numericality: { greater_than: 0 }
8
+ validates :available_quantity, presence: true, numericality: { greater_than_or_equal_to: 0 }
9
+ validates :status, presence: true
10
+
11
+ validate :business_must_be_wholesaler
12
+ validate :unique_product_per_wholesaler
13
+
14
+ enum :status, {
15
+ active: 0,
16
+ inactive: 1,
17
+ out_of_stock: 2
18
+ }
19
+
20
+ private
21
+
22
+ def business_must_be_wholesaler
23
+ if business && !business.wholesaler?
24
+ errors.add(:business, "must be a wholesaler")
25
+ end
26
+ end
27
+
28
+ def unique_product_per_wholesaler
29
+ if WholesalerProduct.where(business: business, product: product)
30
+ .where.not(id: id)
31
+ .exists?
32
+ errors.add(:product, "already exists for this wholesaler")
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,14 +1,14 @@
1
1
  class CreateBscfCoreMarketplaceListings < ActiveRecord::Migration[8.0]
2
2
  def change
3
3
  create_table :bscf_core_marketplace_listings do |t|
4
- t.references :user, null: false, foreign_key: {to_table: :bscf_core_users}
4
+ t.references :user, null: false, foreign_key: { to_table: :bscf_core_users }
5
5
  t.integer :listing_type, null: false
6
6
  t.integer :status, null: false
7
7
  t.boolean :allow_partial_match, null: false, default: false
8
8
  t.datetime :preferred_delivery_date
9
9
  t.datetime :expires_at
10
10
  t.boolean :is_active, default: true
11
- t.references :address, null: false, foreign_key: {to_table: :bscf_core_addresses}
11
+ t.references :address, null: false, foreign_key: { to_table: :bscf_core_addresses }
12
12
 
13
13
  t.timestamps
14
14
  end
@@ -0,0 +1,14 @@
1
+ class CreateBscfCoreWholesalerProducts < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :bscf_core_wholesaler_products do |t|
4
+ t.references :business, null: false, foreign_key: { to_table: :bscf_core_businesses }
5
+ t.references :product, null: false, foreign_key: { to_table: :bscf_core_products }
6
+ t.integer :minimum_order_quantity, null: false, default: 1
7
+ t.decimal :wholesale_price
8
+ t.integer :available_quantity, null: false, default: 0
9
+ t.integer :status, null: false, default: 0
10
+
11
+ t.timestamps
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ class CreateBscfCoreBusinessDocuments < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :bscf_core_business_documents do |t|
4
+ t.references :business, null: false, foreign_key: { to_table: :bscf_core_businesses }
5
+ t.string :document_number, null: false
6
+ t.string :document_name, null: false
7
+ t.string :document_description
8
+ t.datetime :verified_at
9
+ t.boolean :is_verified, null: false, default: false
10
+
11
+ t.timestamps
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,57 @@
1
+ # This migration comes from active_storage (originally 20170806125915)
2
+ class CreateActiveStorageTables < ActiveRecord::Migration[7.0]
3
+ def change
4
+ # Use Active Record's configured type for primary and foreign keys
5
+ primary_key_type, foreign_key_type = primary_and_foreign_key_types
6
+
7
+ create_table :active_storage_blobs, id: primary_key_type do |t|
8
+ t.string :key, null: false
9
+ t.string :filename, null: false
10
+ t.string :content_type
11
+ t.text :metadata
12
+ t.string :service_name, null: false
13
+ t.bigint :byte_size, null: false
14
+ t.string :checksum
15
+
16
+ if connection.supports_datetime_with_precision?
17
+ t.datetime :created_at, precision: 6, null: false
18
+ else
19
+ t.datetime :created_at, null: false
20
+ end
21
+
22
+ t.index [ :key ], unique: true
23
+ end
24
+
25
+ create_table :active_storage_attachments, id: primary_key_type do |t|
26
+ t.string :name, null: false
27
+ t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type
28
+ t.references :blob, null: false, type: foreign_key_type
29
+
30
+ if connection.supports_datetime_with_precision?
31
+ t.datetime :created_at, precision: 6, null: false
32
+ else
33
+ t.datetime :created_at, null: false
34
+ end
35
+
36
+ t.index [ :record_type, :record_id, :name, :blob_id ], name: :index_active_storage_attachments_uniqueness, unique: true
37
+ t.foreign_key :active_storage_blobs, column: :blob_id
38
+ end
39
+
40
+ create_table :active_storage_variant_records, id: primary_key_type do |t|
41
+ t.belongs_to :blob, null: false, index: false, type: foreign_key_type
42
+ t.string :variation_digest, null: false
43
+
44
+ t.index [ :blob_id, :variation_digest ], name: :index_active_storage_variant_records_uniqueness, unique: true
45
+ t.foreign_key :active_storage_blobs, column: :blob_id
46
+ end
47
+ end
48
+
49
+ private
50
+ def primary_and_foreign_key_types
51
+ config = Rails.configuration.generators
52
+ setting = config.options[config.orm][:primary_key_type]
53
+ primary_key_type = setting || :primary_key
54
+ foreign_key_type = setting || :bigint
55
+ [ primary_key_type, foreign_key_type ]
56
+ end
57
+ end
@@ -1,5 +1,5 @@
1
1
  module Bscf
2
2
  module Core
3
- VERSION = "0.3.1"
3
+ VERSION = "0.3.3"
4
4
  end
5
5
  end
@@ -0,0 +1,23 @@
1
+ FactoryBot.define do
2
+ factory :business_document, class: 'Bscf::Core::BusinessDocument' do
3
+ association :business, factory: :business
4
+ document_number { "DOC-#{SecureRandom.hex(4).upcase}" }
5
+ document_name { "Business License" }
6
+ document_description { "Official business license document" }
7
+ is_verified { false }
8
+
9
+ after(:build) do |document|
10
+ document.file.attach(
11
+ io: StringIO.new("test content"),
12
+ filename: 'sample.pdf',
13
+ content_type: 'application/pdf'
14
+ )
15
+ end
16
+
17
+ trait :verified do
18
+ is_verified { true }
19
+ verified_at { Time.current }
20
+ association :business, factory: :business
21
+ end
22
+ end
23
+ end
@@ -1,8 +1,28 @@
1
1
  FactoryBot.define do
2
2
  factory :product, class: 'Bscf::Core::Product' do
3
+ category
4
+ sequence(:sku) { |n| "SKU-#{n}" }
3
5
  name { Faker::Commerce.product_name }
4
6
  description { Faker::Lorem.paragraph }
5
- association :category, factory: :category
6
- base_price { Faker::Commerce.price(range: 0..1000.0) }
7
+
8
+ after(:build) do |product|
9
+ product.thumbnail.attach(
10
+ io: StringIO.new("test image"),
11
+ filename: 'thumbnail.jpg',
12
+ content_type: 'image/jpeg'
13
+ )
14
+ end
15
+
16
+ trait :with_images do
17
+ after(:build) do |product|
18
+ 2.times do |i|
19
+ product.images.attach(
20
+ io: StringIO.new("test image #{i}"),
21
+ filename: "image_#{i}.jpg",
22
+ content_type: 'image/jpeg'
23
+ )
24
+ end
25
+ end
26
+ end
7
27
  end
8
28
  end
@@ -0,0 +1,19 @@
1
+ FactoryBot.define do
2
+ factory :wholesaler_product, class: 'Bscf::Core::WholesalerProduct' do
3
+ association :business, :wholesaler
4
+ association :product
5
+ minimum_order_quantity { Faker::Number.between(from: 5, to: 100) }
6
+ wholesale_price { Faker::Commerce.price(range: 50..1000.0) }
7
+ available_quantity { Faker::Number.between(from: 100, to: 1000) }
8
+ status { :active }
9
+ end
10
+
11
+ trait :inactive do
12
+ status { :inactive }
13
+ end
14
+
15
+ trait :out_of_stock do
16
+ status { :out_of_stock }
17
+ available_quantity { 0 }
18
+ end
19
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bscf-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Asrat
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-04-01 00:00:00.000000000 Z
10
+ date: 2025-04-04 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: active_model_serializers
@@ -289,6 +289,7 @@ files:
289
289
  - app/models/bscf/core/address.rb
290
290
  - app/models/bscf/core/application_record.rb
291
291
  - app/models/bscf/core/business.rb
292
+ - app/models/bscf/core/business_document.rb
292
293
  - app/models/bscf/core/category.rb
293
294
  - app/models/bscf/core/delivery_order.rb
294
295
  - app/models/bscf/core/delivery_order_item.rb
@@ -306,7 +307,8 @@ files:
306
307
  - app/models/bscf/core/user_role.rb
307
308
  - app/models/bscf/core/virtual_account.rb
308
309
  - app/models/bscf/core/virtual_account_transaction.rb
309
- - app/services/token_service.rb
310
+ - app/models/bscf/core/wholesaler_product.rb
311
+ - app/services/bscf/core/token_service.rb
310
312
  - config/database.yml
311
313
  - config/routes.rb
312
314
  - db/migrate/20250326065606_create_bscf_core_users.rb
@@ -328,13 +330,16 @@ files:
328
330
  - db/migrate/20250330181143_create_bscf_core_delivery_orders.rb
329
331
  - db/migrate/20250330190145_create_bscf_core_delivery_order_items.rb
330
332
  - db/migrate/20250331113323_create_bscf_core_marketplace_listings.rb
333
+ - db/migrate/20250402120554_create_bscf_core_wholesaler_products.rb
334
+ - db/migrate/20250403190620_create_bscf_core_business_documents.rb
335
+ - db/migrate/20250403194629_create_active_storage_tables.active_storage.rb
331
336
  - lib/bscf/core.rb
332
337
  - lib/bscf/core/engine.rb
333
338
  - lib/bscf/core/version.rb
334
- - lib/bscf_core.rb
335
339
  - lib/tasks/bscf/core_tasks.rake
336
340
  - lib/tasks/release.rake
337
341
  - spec/factories/bscf/core/addresses.rb
342
+ - spec/factories/bscf/core/business_documents.rb
338
343
  - spec/factories/bscf/core/businesses.rb
339
344
  - spec/factories/bscf/core/categories.rb
340
345
  - spec/factories/bscf/core/delivery_order_items.rb
@@ -353,6 +358,7 @@ files:
353
358
  - spec/factories/bscf/core/users.rb
354
359
  - spec/factories/bscf/core/virtual_account_transactions.rb
355
360
  - spec/factories/bscf/core/virtual_accounts.rb
361
+ - spec/factories/bscf/core/wholesaler_products.rb
356
362
  homepage: https://mksaddis.com/
357
363
  licenses:
358
364
  - MIT
@@ -374,7 +380,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
374
380
  - !ruby/object:Gem::Version
375
381
  version: '0'
376
382
  requirements: []
377
- rubygems_version: 3.6.5
383
+ rubygems_version: 3.6.2
378
384
  specification_version: 4
379
385
  summary: An Engine for Supply Chain Financing
380
386
  test_files: []
data/lib/bscf_core.rb DELETED
@@ -1,7 +0,0 @@
1
- require "bscf/core/version"
2
- require "bscf/core/engine"
3
- require "active_model_serializers"
4
- require "ancestry"
5
- require "jwt"
6
- require "ransack"
7
- require "noticed"