ref: master
plugins/suppliers/models/suppliers_plugin/base_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 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# for some unknown reason, if this is named SuppliersPlugin::Product then # cycle.products will go to an infinite loop class SuppliersPlugin::BaseProduct < ProductsPlugin::Product # undo ProductsPlugin::Product def self.sti_name self.name end has_one :supplier_image, through: :from_product, source: :image attr_accessible :default_margin_percentage, :margin_percentage, :default_unit, :unit_detail, :supplier_product_attributes accepts_nested_attributes_for :supplier_product # if abstract_class is true then it will trigger https://github.com/rails/rails/issues/20871 #self.abstract_class = true settings_items :minimum_selleable, type: Float, default: nil settings_items :margin_percentage, type: Float, default: nil settings_items :quantity, type: Float, default: nil settings_items :unit_detail, type: String, default: nil CORE_DEFAULT_ATTRIBUTES = [ :name, :description, :price, :unit_id, :product_category_id, :image_id, ] DEFAULT_ATTRIBUTES = CORE_DEFAULT_ATTRIBUTES + [ :margin_percentage, :stored, :minimum_selleable, :unit_detail, ] extend DefaultDelegate::ClassMethods default_delegate_setting :name, to: :supplier_product default_delegate_setting :description, to: :supplier_product default_delegate_setting :qualifiers, to: :supplier_product default_delegate :product_qualifiers, default_setting: :default_qualifiers, to: :supplier_product default_delegate_setting :image, to: :supplier_product, prefix: :_default default_delegate :image_id, default_setting: :_default_image, to: :supplier_product default_delegate_setting :unit, to: :supplier_product default_delegate :unit_id, default_setting: :default_unit, to: :supplier_product default_delegate_setting :margin_percentage, to: :profile, default_if: -> { self.own_margin_percentage.blank? or self.own_margin_percentage.zero? } default_delegate :price, default_setting: :default_margin_percentage, default_if: :equal?, to: -> { self.supplier_product.price_with_discount if self.supplier_product } default_delegate :unit_detail, default_setting: :default_unit, to: :supplier_product default_delegate_setting :minimum_selleable, to: :supplier_product extend CurrencyFields::ClassMethods has_currency :own_price has_currency :original_price has_number_with_locale :minimum_selleable has_number_with_locale :own_minimum_selleable has_number_with_locale :original_minimum_selleable has_number_with_locale :quantity has_number_with_locale :margin_percentage has_number_with_locale :own_margin_percentage has_number_with_locale :original_margin_percentage def self.default_product_category environment ProductCategory.top_level_for(environment).order('name ASC').first end def self.default_unit Unit.new(singular: I18n.t('suppliers_plugin.models.product.unit'), plural: I18n.t('suppliers_plugin.models.product.units')) end # override SuppliersPlugin::BaseProduct def self.search_scope scope, params scope = scope.from_supplier_id params[:supplier_id] if params[:supplier_id].present? && params[:supplier_id].to_s != "0" scope = scope.with_available(if params[:available] == 'true' then true else false end) if params[:available].present? scope = scope.fp_name_like params[:name] if params[:name].present? scope = scope.fp_with_product_category_id params[:category_id] if params[:category_id].present? && params[:category_id].to_s != "0" scope end def self.orphans_ids # FIXME: need references from rails4 to do it without raw query result = self.connection.execute <<-SQL SELECT products.id FROM products LEFT OUTER JOIN suppliers_plugin_source_products ON suppliers_plugin_source_products.to_product_id = products.id LEFT OUTER JOIN products from_products_products ON from_products_products.id = suppliers_plugin_source_products.from_product_id WHERE products.type IN (#{(self.descendants << self).map{ |d| "'#{d}'" }.join(',')}) GROUP BY products.id HAVING count(from_products_products.id) = 0; SQL result.values end def self.archive_orphans self.where(id: self.orphans_ids).find_each batch_size: 50 do |product| # need full save to trigger search index product.update archived: true end end def buy_price self.supplier_products.inject(0){ |sum, p| sum += p.price || 0 } end def buy_unit #TODO: handle multiple products (self.supplier_product.unit rescue nil) || self.class.default_unit end def available self[:available] end def available_with_supplier return self.available_without_supplier unless self.supplier self.available_without_supplier and self.supplier.active rescue false end def chained_available return self.available_without_supplier unless self.supplier_product self.available_without_supplier and self.supplier_product.available and self.supplier.active rescue false end alias_method_chain :available, :supplier def dependent? self.from_products.length >= 1 end def orphan? !self.dependent? end def minimum_selleable self[:minimum_selleable] || 0.1 end def price_with_margins base_price = nil, margin_source = nil margin_source ||= self margin_percentage = margin_source.margin_percentage margin_percentage ||= self.profile.margin_percentage if self.profile base_price ||= 0 base_price = base_price.to_f price = if margin_percentage and not base_price.zero? base_price.to_f + (margin_percentage.to_f / 100) * base_price.to_f else self.price_with_default end price end def price_without_margins self[:price] / (1 + self.margin_percentage/100) end # FIXME: move to core # just in case the from_products is nil def product_category_id self[:product_category_id] end def product_category_with_default self.product_category_without_default or self.class.default_product_category(self.environment) end def product_category_id_with_default self.product_category_id_without_default or self.product_category_with_default.id end alias_method_chain :product_category, :default alias_method_chain :product_category_id, :default # FIXME: move to core def unit_with_default self.unit_without_default or self.class.default_unit end alias_method_chain :unit, :default # FIXME: move to core def archive self.update! archived: true end def unarchive self.update! archived: false end def notifiable? false end def solr_index? false end protected def validate_uniqueness_of_column_name? false end # overhide Product's after_create callback to avoid infinite loop def distribute_to_consumers end end |