Class: Dscf::Marketplace::AggregatorListing
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- Dscf::Marketplace::AggregatorListing
- Defined in:
- app/models/dscf/marketplace/aggregator_listing.rb
Class Method Summary collapse
- .ransackable_associations(_auth_object = nil) ⇒ Object
- .ransackable_attributes(_auth_object = nil) ⇒ Object
Instance Method Summary collapse
- #available? ⇒ Boolean
-
#confirming_business ⇒ Object
The real external business that should confirm an order line placed against this listing on their OWN business dashboard, if any.
-
#cost_price ⇒ Object
The aggregator's cost basis for this listing (nil for catalog — the aggregator sets a selling price directly with no upstream cost to compare against).
-
#effective_status ⇒ Object
Status as retailers/aggregator should see it: a listing whose own status is :active but whose supplier has paused reads as :paused (auto-followed), without mutating the stored status.
- #margin ⇒ Object
-
#product ⇒ Object
Resolves the catalogue product regardless of how the listing was sourced.
-
#source_label ⇒ Object
Human-readable name of who ultimately fulfils a line placed against this listing.
- #total_value ⇒ Object
-
#upstream_active? ⇒ Boolean
Is the upstream source still offering this? For supplier/sub_supplier sources, an aggregator listing must follow the supplier: when the supplier pauses (deactivates their supplier product) or runs out of stock, the listing is no longer offerable even if its own status is still :active.
Class Method Details
.ransackable_associations(_auth_object = nil) ⇒ Object
43 44 45 |
# File 'app/models/dscf/marketplace/aggregator_listing.rb', line 43 def self.ransackable_associations(_auth_object = nil) %w[aggregator supplier_product product sub_supplier_product] end |
.ransackable_attributes(_auth_object = nil) ⇒ Object
39 40 41 |
# File 'app/models/dscf/marketplace/aggregator_listing.rb', line 39 def self.ransackable_attributes(_auth_object = nil) %w[id aggregator_id supplier_product_id product_id sub_supplier_product_id source_kind price quantity status created_at updated_at] end |
Instance Method Details
#available? ⇒ Boolean
117 118 119 |
# File 'app/models/dscf/marketplace/aggregator_listing.rb', line 117 def available? active? && quantity.to_i.positive? && upstream_active? end |
#confirming_business ⇒ Object
The real external business that should confirm an order line placed against this listing on their OWN business dashboard, if any. Only meaningful for :supplier — that business is a genuine third party, unambiguously distinct from the aggregator. :catalog has no external party (the aggregator fulfils it) and :sub_supplier's business is offline/has no login (requirements doc: sub-suppliers "don't act directly on the system"), so both stay aggregator-managed (nil here).
91 92 93 |
# File 'app/models/dscf/marketplace/aggregator_listing.rb', line 91 def confirming_business supplier_product&.business if supplier? end |
#cost_price ⇒ Object
The aggregator's cost basis for this listing (nil for catalog — the aggregator sets a selling price directly with no upstream cost to compare against).
58 59 60 61 62 63 |
# File 'app/models/dscf/marketplace/aggregator_listing.rb', line 58 def cost_price case source_kind when "supplier" then supplier_product&.supplier_price when "sub_supplier" then sub_supplier_product&.sub_supplier_price end end |
#effective_status ⇒ Object
Status as retailers/aggregator should see it: a listing whose own status is :active but whose supplier has paused reads as :paused (auto-followed), without mutating the stored status.
111 112 113 114 115 |
# File 'app/models/dscf/marketplace/aggregator_listing.rb', line 111 def effective_status return "paused" if active? && !upstream_active? status end |
#margin ⇒ Object
65 66 67 68 |
# File 'app/models/dscf/marketplace/aggregator_listing.rb', line 65 def margin return nil unless cost_price price - cost_price end |
#product ⇒ Object
Resolves the catalogue product regardless of how the listing was sourced.
48 49 50 51 52 53 54 |
# File 'app/models/dscf/marketplace/aggregator_listing.rb', line 48 def product case source_kind when "supplier" then supplier_product&.product when "sub_supplier" then sub_supplier_product&.product else super end end |
#source_label ⇒ Object
Human-readable name of who ultimately fulfils a line placed against this listing. An order line is auto-sourced to the AggregatorListing itself, so this drives the "Product source name" the requirements ask for:
catalog -> the aggregator (self-fulfilled)
supplier -> the supplier's business name
sub_supplier -> the sub-supplier's business name
76 77 78 79 80 81 82 |
# File 'app/models/dscf/marketplace/aggregator_listing.rb', line 76 def source_label case source_kind when "supplier" then supplier_product&.business&.name when "sub_supplier" then sub_supplier_product&.sub_supplier&.business_name else aggregator&.name end end |
#total_value ⇒ Object
121 122 123 |
# File 'app/models/dscf/marketplace/aggregator_listing.rb', line 121 def total_value price * quantity end |
#upstream_active? ⇒ Boolean
Is the upstream source still offering this? For supplier/sub_supplier sources, an aggregator listing must follow the supplier: when the supplier pauses (deactivates their supplier product) or runs out of stock, the listing is no longer offerable even if its own status is still :active. Catalog listings have no upstream — the aggregator fulfils them directly.
100 101 102 103 104 105 106 |
# File 'app/models/dscf/marketplace/aggregator_listing.rb', line 100 def upstream_active? case source_kind when "supplier" then supplier_product&.active? && supplier_product.available_quantity.to_i.positive? when "sub_supplier" then sub_supplier_product.present? else true end end |