ref: master
plugins/suppliers/lib/ext/products_plugin/product.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
require_dependency 'products_plugin/product' ActiveSupport.on_load :solr_product do ::ProductsPlugin::Product.class_eval do def solr_supplied self.supplied? end self.solr_extra_fields << :solr_supplied end end module ProductsPlugin class Product attr_accessible :from_products, :from_product, :supplier_id, :supplier has_many :sources_from_products, foreign_key: :to_product_id, class_name: 'SuppliersPlugin::SourceProduct', dependent: :destroy has_one :sources_from_product, foreign_key: :to_product_id, class_name: 'SuppliersPlugin::SourceProduct' has_many :sources_to_products, foreign_key: :from_product_id, class_name: 'SuppliersPlugin::SourceProduct', dependent: :destroy has_one :sources_to_product, foreign_key: :from_product_id, class_name: 'SuppliersPlugin::SourceProduct' has_many :to_products, -> { order 'id ASC' }, through: :sources_to_products has_one :to_product, -> { order 'id ASC' }, through: :sources_to_product, autosave: true has_many :from_products, -> { order 'id ASC' }, through: :sources_from_products has_one :from_product, -> { order 'id ASC' }, through: :sources_from_product, autosave: true has_many :sources_from_2x_products, through: :from_products, source: :sources_from_products has_one :sources_from_2x_product, through: :from_product, source: :sources_from_product has_many :sources_to_2x_products, through: :to_products, source: :sources_to_products has_one :sources_to_2x_product, through: :to_product, source: :sources_to_product has_many :from_2x_products, through: :sources_from_2x_products, source: :from_product has_one :from_2x_product, through: :sources_from_2x_product, source: :from_product has_many :to_2x_products, through: :sources_to_2x_products, source: :to_product has_one :to_2x_product, through: :sources_to_2x_product, source: :to_product # semantic alias for supplier_from_product(s) has_many :sources_supplier_products, foreign_key: :to_product_id, class_name: 'SuppliersPlugin::SourceProduct' has_one :sources_supplier_product, foreign_key: :to_product_id, class_name: 'SuppliersPlugin::SourceProduct' has_many :supplier_products, -> { order 'id ASC' }, through: :sources_supplier_products, source: :from_product has_one :supplier_product, -> { order 'id ASC' }, through: :sources_supplier_product, source: :from_product, autosave: true has_many :suppliers, -> { distinct.order 'id ASC' }, through: :sources_supplier_products has_one :supplier, -> { order 'id ASC' }, through: :sources_supplier_product has_many :consumers, -> { distinct.order 'id ASC' }, through: :to_products, source: :profile has_one :consumer, -> { order 'id ASC' }, through: :to_product, source: :profile # overhide original, FIXME: rename to available_and_supplier_active scope :available, -> { joins(:suppliers). where 'products.available = ? AND suppliers_plugin_suppliers.active = ?', true, true } scope :unavailable, -> { where 'products.available <> ? OR suppliers_plugin_suppliers.active <> ?', true, true } scope :with_available, -> (available) { op = if available then '=' else '<>' end cond = if available then 'AND' else 'OR' end where "products.available #{op} ? #{cond} suppliers_plugin_suppliers.active #{op} ?", true, true } scope :fp_name_like, -> (name) { where "from_products_products.name ILIKE ?", "%#{name}%" } scope :fp_with_product_category_id, -> (id) { where 'from_products_products.product_category_id = ?', id } # prefer #distributed_products has_many to use DistributedProduct scopes and eager loading scope :distributed, -> { where type: 'SuppliersPlugin::DistributedProduct'} scope :own, -> { where type: nil } scope :supplied, -> { # this remove duplicates and allow sorting on the fields, unlike distinct group('products.id'). where type: [nil, 'SuppliersPlugin::DistributedProduct'] } scope :supplied_for_count, -> { distinct. where type: [nil, 'SuppliersPlugin::DistributedProduct'] } scope :from_supplier, -> (supplier) { joins(:suppliers).where 'suppliers_plugin_suppliers.id = ?', supplier.id } scope :from_supplier_id, -> (supplier_id) { joins(:suppliers).where 'suppliers_plugin_suppliers.id = ?', supplier_id } after_create :distribute_to_consumers def own? self.class == Product end def distributed? self.class == SuppliersPlugin::DistributedProduct end def supplied? self.own? or self.distributed? end def supplier # FIXME: use self.suppliers when rails support for nested preload comes @supplier ||= self.sources_supplier_product.supplier rescue nil @supplier ||= self.profile.self_supplier rescue nil end def supplier= value @supplier = value end def supplier_id self.supplier.id end def supplier_id= id @supplier = profile.environment.profiles.find id end def supplier_dummy? self.supplier ? self.supplier.dummy? : self.profile.dummy? end def distribute_to_consumer consumer, attrs = {} distributed_product = consumer.distributed_products.includes(:from_products).where(profile_id: consumer.id, from_products_products: {id: self.id}).first distributed_product ||= SuppliersPlugin::DistributedProduct.create! profile: consumer, from_product: self distributed_product.update! attrs if attrs.present? distributed_product end def destroy_dependent self.to_products.each do |to_product| to_product.destroy if to_product.respond_to? :dependent? and to_product.dependent? end end # before_destroy and after_destroy don't work, # see http://stackoverflow.com/questions/14175330/associations-not-loaded-in-before-destroy-callback def destroy self.class.transaction do self.destroy_dependent super end end def diff from = self.from_product return @changed_attrs if @changed_attrs @changed_attrs = [] SuppliersPlugin::BaseProduct::CORE_DEFAULT_ATTRIBUTES.each do |attr| @changed_attrs << attr if self[attr].present? and self[attr] != from[attr] end @changed_attrs end protected def distribute_to_consumers # shopping_cart creates products without a profile... return unless self.profile self.profile.consumers.except_people.except_self.each do |consumer| self.distribute_to_consumer consumer.profile end end end end |