dscf-marketplace 0.1.2 → 0.1.4

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: 57b94e7df1ac8fe6e08df594a8a5509a16b2b6383071208a636a8981a0a6618a
4
- data.tar.gz: 78f4ea4db87b33c9ad5027b40a710f5c5070a928c54f2fd3c351321c378d7ef5
3
+ metadata.gz: 483c018a55aced4c97a7dc9443c45721ba6571dd16100736e36281349bdb65a3
4
+ data.tar.gz: 49feba6deeec8f69dd7ad693e61c7f6e8c648480b35a8da2d97acd3ddf9152db
5
5
  SHA512:
6
- metadata.gz: b0b2b27060010f601b6469c685302927b20d6559d13af18fac98ca6abaf0212a255739c1010952f63aeac14033283199fcfee734fdc97fa81f4b8ccdfa301fa6
7
- data.tar.gz: 250396abdd9c4f188a0ecb7be10ff9a9c52aafccb0811201b7d923994b56f3fe2e892a6eb3d9a28261788f9dc04e1eb7e5173a7049c840c77b87b5f2924ced9b
6
+ metadata.gz: 72d2b07581b5bbc8942c0b133d7a01b81be9238adc3a303a68c60f421a89145cf7d634c07fd77f7f2fa7b637d3ade0dd39f687442d7c678edc22edd52bc9b694
7
+ data.tar.gz: 4ac74190a143f232210958073b6720c5142da6f15052275121384dd162c08ea93f68f3e86ec59ddc2b161f5e745fdb9a7cc680a6f445d469bacf8b964300d42c
@@ -0,0 +1,62 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class Product < ApplicationRecord
4
+ belongs_to :category, class_name: "Dscf::Marketplace::Category"
5
+ belongs_to :unit, class_name: "Dscf::Marketplace::Unit"
6
+
7
+ has_many :supplier_products, class_name: "Dscf::Marketplace::SupplierProduct"
8
+ has_many :listings, class_name: "Dscf::Marketplace::Listing"
9
+ has_many :order_items, class_name: "Dscf::Marketplace::OrderItem"
10
+ has_many :rfq_items, class_name: "Dscf::Marketplace::RfqItem"
11
+ has_many :quotation_items, class_name: "Dscf::Marketplace::QuotationItem"
12
+
13
+ has_one_attached :thumbnail
14
+ has_many_attached :images
15
+
16
+ validates :sku, presence: true, uniqueness: true, length: {maximum: 50}
17
+ validates :name, presence: true, length: {maximum: 200}
18
+ validates :description, length: {maximum: 2000}, allow_blank: true
19
+ validates :category_id, presence: true
20
+ validates :base_price, presence: true, numericality: {greater_than: 0}
21
+ validates :business_only, inclusion: {in: [ true, false ]}
22
+ validates :unit_id, presence: true
23
+ validates :base_quantity, presence: true, numericality: {greater_than: 0}
24
+
25
+ scope :business_only, -> { where(business_only: true) }
26
+ scope :public_products, -> { where(business_only: false) }
27
+ scope :by_category, ->(category_id) { where(category_id: category_id) }
28
+ scope :by_unit, ->(unit_id) { where(unit_id: unit_id) }
29
+
30
+ def display_name
31
+ "#{name} (#{sku})"
32
+ end
33
+
34
+ def price_per_unit
35
+ return nil unless base_price && base_quantity && base_quantity > 0
36
+ base_price / base_quantity
37
+ end
38
+
39
+ def category_path
40
+ return nil unless category
41
+ category.ancestry_path
42
+ end
43
+
44
+ def convertible_to_units
45
+ return [] unless unit
46
+ unit.convertible_units
47
+ end
48
+
49
+ def thumbnail_url
50
+ return nil unless thumbnail.attached?
51
+ Rails.application.routes.url_helpers.rails_blob_url(thumbnail, only_path: true)
52
+ end
53
+
54
+ def images_urls
55
+ return [] unless images.attached?
56
+ images.map do |image|
57
+ Rails.application.routes.url_helpers.rails_blob_url(image, only_path: true)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -30,10 +30,10 @@ module Dscf
30
30
 
31
31
  def convertible_to?(other_unit)
32
32
  return false if other_unit.nil?
33
+ return true if id == other_unit.id
33
34
 
34
- # NOTE: UnitConversion model not yet implemented
35
- # For now, return false - will be implemented when UnitConversion is created
36
- false
35
+ unit_conversions.exists?(to_unit: other_unit) ||
36
+ other_unit.unit_conversions.exists?(to_unit: self)
37
37
  end
38
38
  end
39
39
  end
@@ -0,0 +1,33 @@
1
+ module Dscf
2
+ module Marketplace
3
+ class UnitConversion < ApplicationRecord
4
+ belongs_to :from_unit, class_name: "Dscf::Marketplace::Unit"
5
+ belongs_to :to_unit, class_name: "Dscf::Marketplace::Unit"
6
+
7
+ validates :from_unit_id, presence: true
8
+ validates :to_unit_id, presence: true
9
+ validates :conversion_factor, presence: true, numericality: {greater_than: 0}
10
+ validates :notes, length: {maximum: 500}, allow_blank: true
11
+
12
+ validate :units_must_be_different
13
+
14
+ def units_must_be_different
15
+ return unless from_unit_id && to_unit_id
16
+
17
+ return unless from_unit_id == to_unit_id
18
+
19
+ errors.add(:to_unit_id, "must be different from from_unit")
20
+ end
21
+
22
+ def reverse_conversion_factor
23
+ return nil unless conversion_factor && conversion_factor != 0
24
+
25
+ 1.0 / conversion_factor
26
+ end
27
+
28
+ def description
29
+ "#{from_unit&.display_name} → #{to_unit&.display_name} (×#{conversion_factor})"
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,23 @@
1
+ class CreateDscfMarketplaceUnitConversions < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :dscf_marketplace_unit_conversions do |t|
4
+ t.references :from_unit,
5
+ index: {name: "from_unit_on_dm_uc_indx"},
6
+ null: false,
7
+ foreign_key: {to_table: :dscf_marketplace_units}
8
+ t.references :to_unit,
9
+ index: {name: "to_unit_on_dm_uc_indx"},
10
+ null: false,
11
+ foreign_key: {to_table: :dscf_marketplace_units}
12
+ t.decimal :conversion_factor, precision: 15, scale: 6, null: false
13
+ t.string :notes, limit: 500
14
+
15
+ t.timestamps
16
+ end
17
+
18
+ add_index :dscf_marketplace_unit_conversions,
19
+ %i[from_unit_id to_unit_id],
20
+ unique: true,
21
+ name: "unique_unit_conversion_indx"
22
+ end
23
+ end
@@ -0,0 +1,30 @@
1
+ class CreateDscfMarketplaceProducts < ActiveRecord::Migration[8.0]
2
+ def change
3
+ create_table :dscf_marketplace_products do |t|
4
+ t.string :sku, null: false, limit: 50
5
+ t.string :name, null: false, limit: 200
6
+ t.text :description, limit: 2000
7
+ t.references :category,
8
+ index: {name: "category_on_dm_products_indx"},
9
+ null: false,
10
+ foreign_key: {to_table: :dscf_marketplace_categories}
11
+ t.decimal :base_price, precision: 15, scale: 2, null: false
12
+ t.boolean :business_only, null: false, default: false
13
+ t.references :unit,
14
+ index: {name: "unit_on_dm_products_indx"},
15
+ null: false,
16
+ foreign_key: {to_table: :dscf_marketplace_units}
17
+ t.decimal :base_quantity, precision: 15, scale: 6, null: false
18
+
19
+ t.timestamps
20
+ end
21
+
22
+ add_index :dscf_marketplace_products, :sku,
23
+ unique: true,
24
+ name: "sku_on_dm_products_indx"
25
+ add_index :dscf_marketplace_products, :business_only,
26
+ name: "business_only_on_dm_products_indx"
27
+ add_index :dscf_marketplace_products, [ :category_id, :business_only ],
28
+ name: "category_business_only_on_dm_products_indx"
29
+ end
30
+ end
@@ -1,5 +1,5 @@
1
1
  module Dscf
2
2
  module Marketplace
3
- VERSION = "0.1.2".freeze
3
+ VERSION = "0.1.4".freeze
4
4
  end
5
5
  end
@@ -0,0 +1,12 @@
1
+ FactoryBot.define do
2
+ factory :dscf_marketplace_product, class: 'Dscf::Marketplace::Product' do
3
+ sequence(:sku) { |n| "PRD-#{n.to_s.rjust(3, '0')}" }
4
+ sequence(:name) { |n| "Product #{n}" }
5
+ description { "Product description" }
6
+ category { create(:dscf_marketplace_category) }
7
+ base_price { 99.99 }
8
+ business_only { false }
9
+ unit { create(:dscf_marketplace_unit) }
10
+ base_quantity { 1.0 }
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ FactoryBot.define do
2
+ factory :dscf_marketplace_unit_conversion, class: "Dscf::Marketplace::UnitConversion" do
3
+ from_unit { create(:dscf_marketplace_unit) }
4
+ to_unit { create(:dscf_marketplace_unit) }
5
+ conversion_factor { 1.5 }
6
+ notes { "Conversion factor description" }
7
+ end
8
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dscf-marketplace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Asrat
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-08-27 00:00:00.000000000 Z
10
+ date: 2025-08-28 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rails
@@ -422,16 +422,22 @@ files:
422
422
  - app/mailers/dscf/marketplace/application_mailer.rb
423
423
  - app/models/dscf/marketplace/application_record.rb
424
424
  - app/models/dscf/marketplace/category.rb
425
+ - app/models/dscf/marketplace/product.rb
425
426
  - app/models/dscf/marketplace/unit.rb
427
+ - app/models/dscf/marketplace/unit_conversion.rb
426
428
  - config/routes.rb
427
429
  - db/migrate/20250827172043_create_dscf_marketplace_categories.rb
428
430
  - db/migrate/20250827173526_update_dscf_marketplace_categories_indexes.rb
429
431
  - db/migrate/20250827182550_create_dscf_marketplace_units.rb
432
+ - db/migrate/20250827185656_create_dscf_marketplace_unit_conversions.rb
433
+ - db/migrate/20250828062945_create_dscf_marketplace_products.rb
430
434
  - lib/dscf/marketplace.rb
431
435
  - lib/dscf/marketplace/engine.rb
432
436
  - lib/dscf/marketplace/version.rb
433
437
  - lib/tasks/dscf/marketplace_tasks.rake
434
438
  - spec/factories/dscf/marketplace/categories.rb
439
+ - spec/factories/dscf/marketplace/products.rb
440
+ - spec/factories/dscf/marketplace/unit_conversions.rb
435
441
  - spec/factories/dscf/marketplace/units.rb
436
442
  homepage: https://mksaddis.com/
437
443
  licenses:
@@ -446,7 +452,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
446
452
  requirements:
447
453
  - - ">="
448
454
  - !ruby/object:Gem::Version
449
- version: '3.2'
455
+ version: '3.4'
450
456
  required_rubygems_version: !ruby/object:Gem::Requirement
451
457
  requirements:
452
458
  - - ">="