Files
openfoodnetwork/app/models/variant_override.rb
Pau Perez 060530cda8 Do not fetch VOs with deleted variant
In the line below we filter them out in Ruby so it's a waste of
resources. The fundamental difference is that `#includes` and
`#references` results in LEFT JOINs, whereas `#joins` results in INNER
JOIN, and because there's a default scope on `deleted_at IS NULL`, these
are not included in the result set.

This however, requires us to move away from the current algorithm but
unfortunately we can't refactor it completely yet.

Before:

```sql
SELECT *
  FROM "variant_overrides"
  LEFT OUTER
  JOIN "spree_variants"
    ON "spree_variants"."id"              =  "variant_overrides"."variant_id"
   AND "spree_variants"."deleted_at" IS NULL
  LEFT OUTER
  JOIN "spree_products"
    ON "spree_products"."id"              =  "spree_variants"."product_id"
   AND "spree_products"."deleted_at" IS NULL
 WHERE "variant_overrides"."permission_revoked_at" IS NULL
   AND "variant_overrides"."hub_id" IN (
    SELECT "enterprises"."id"
      FROM "enterprises"
    INNER
      JOIN "enterprise_roles"
        ON "enterprise_roles"."enterprise_id" =  "enterprises"."id"
    WHERE (enterprise_roles.user_id          =  ?)
      AND (sells                             != 'none')
 ORDER BY name)
```

After:

```sql
SELECT "variant_overrides".*
  FROM "variant_overrides"
 INNER
  JOIN "spree_variants"
    ON "spree_variants"."id"              =  "variant_overrides"."variant_id"
   AND "spree_variants"."deleted_at" IS NULL
 INNER
  JOIN "spree_products"
    ON "spree_products"."id"              =  "spree_variants"."product_id"
   AND "spree_products"."deleted_at" IS NULL
 WHERE "variant_overrides"."permission_revoked_at" IS NULL
   AND "variant_overrides"."hub_id" IN (
    SELECT "enterprises"."id"
      FROM "enterprises"
    INNER
      JOIN "enterprise_roles"
        ON "enterprise_roles"."enterprise_id" =  "enterprises"."id"
    WHERE (enterprise_roles.user_id          =  ?)
      AND (sells                             != 'none')
 ORDER BY name)
```

This is covered in the test suite by
spec/controllers/admin/variant_overrides_controller_spec.rb:72. It keeps
passing so we're good to go.
2021-02-01 14:47:51 +01:00

81 lines
2.0 KiB
Ruby

class VariantOverride < ActiveRecord::Base
extend Spree::LocalizedNumber
include StockSettingsOverrideValidation
acts_as_taggable
belongs_to :hub, class_name: 'Enterprise'
belongs_to :variant, class_name: 'Spree::Variant'
validates :hub_id, presence: true
validates :variant_id, presence: true
# Default stock can be nil, indicating stock should not be reset or zero, meaning reset to zero. Need to ensure this can be set by the user.
validates :default_stock, numericality: { greater_than_or_equal_to: 0 }, allow_nil: true
default_scope { where(permission_revoked_at: nil) }
scope :for_hubs, lambda { |hubs|
where(hub_id: hubs)
}
scope :distinct_import_dates, lambda {
select('DISTINCT variant_overrides.import_date').
where('variant_overrides.import_date IS NOT NULL').
order('import_date DESC')
}
localize_number :price
def self.indexed(hub)
for_hubs(hub).preload(:variant).index_by(&:variant)
end
def stock_overridden?
# If count_on_hand is present, it means on_demand is false
# See StockSettingsOverrideValidation for details
count_on_hand.present?
end
def use_producer_stock_settings?
on_demand.nil?
end
def move_stock!(quantity)
unless stock_overridden?
Bugsnag.notify RuntimeError.new "Attempting to move stock of a VariantOverride without a count_on_hand specified."
return
end
if quantity > 0
increment! :count_on_hand, quantity
elsif quantity < 0
decrement! :count_on_hand, -quantity
end
end
def default_stock?
default_stock.present?
end
def reset_stock!
if resettable
if default_stock?
self.attributes = { on_demand: false, count_on_hand: default_stock }
save
else
Bugsnag.notify RuntimeError.new "Attempting to reset stock level for a variant with no default stock level."
end
end
self
end
def deletable?
price.blank? &&
count_on_hand.blank? &&
default_stock.blank? &&
resettable.blank? &&
sku.nil? &&
on_demand.nil?
end
end