TODO: - AJAX for add_p_article and add_stock_movement_p_article in stock_movement views - Fix select p_article with in stock_movement partial view - Fix query to display available p_article in stock_movement partial
636 lines
18 KiB
Ruby
636 lines
18 KiB
Ruby
class PriceLine < ApplicationRecord
|
|
belongs_to :price_line_block
|
|
belongs_to :p_product
|
|
belongs_to :p_product_ref
|
|
belongs_to :p_product_power
|
|
has_many :price_line_resp_selects, :foreign_key => :price_line_demand
|
|
has_many :price_line_resps, through: :price_line_resp_selects, :source => :price_line_resp
|
|
|
|
|
|
has_one :p_fournisseur, :through => :price_line_block
|
|
|
|
#has_many :price_line_demands, through: :price_line_resp_selects
|
|
has_many :price_line_p_articles
|
|
has_many :p_articles, through: :price_line_p_articles
|
|
accepts_nested_attributes_for :p_articles, allow_destroy: true
|
|
accepts_nested_attributes_for :price_line_p_articles
|
|
|
|
default_scope { order('position ASC') }
|
|
|
|
validates :p_product_ref_id, :presence => true, :if => :p_product_ref_needed?
|
|
validates :p_product_id, :presence => true, :if => :p_product_needed?
|
|
validates :qte, presence: true#, numericality: { greater_than_or_equal_to: :affected_qty }
|
|
validate :qte_greater_than_or_equal_to_affected_qty
|
|
|
|
attr_accessor :forced_price
|
|
|
|
has_many :line_stocks
|
|
|
|
after_update :memorize_p_fournisseur_ref, if: :p_fournisseur_ref_is_memorizable?
|
|
|
|
acts_as_sorting :fields => {
|
|
:ref => {:name => "Ref", :reorder => true},
|
|
:title => {:name => "Désignation", :reorder => true},
|
|
:qte => {:name => "Qté", :reorder => true},
|
|
:qte_available => {:name => "Qté dispo.", :reorder => true},
|
|
:ct_u_price_ht => {:name => "Prix de vente", :reorder => true},
|
|
:ref_fournisseur => {:name => "Réf. fournisseur", :reorder => true},
|
|
:p_product_power_id => {:name => "Chargeur", :reorder => true},
|
|
:p_product_zone_id => {:name => "Zone", :reorder => true},
|
|
:ready_stock => {:name => "Dispo stock ?", :reorder => true},
|
|
:ram => {:name => "Ram", :reorder => true},
|
|
:ram_unit => {:name => "Ram unité", :reorder => true},
|
|
:eu => {:name => "EU ?", :reorder => true},
|
|
:fullkit => {:name => "Fullkit ?", :reorder => true},
|
|
:lang_start => {:name => "Démarrage écran langue ?", :reorder => true},
|
|
:actions => {:name => "Actions"}
|
|
|
|
}
|
|
|
|
|
|
acts_as_caching :fields => [:validation_date, :creation_date, :wish_date, :state, :p_product_cat_id, :p_customer_id, :cost_ht, :marge_ht, :marge_u_ht, :cost_u_ht, :local_tot_amount_ht, :p_devise_id, :devise_rate, :block_type, :product_no_remise, :price_calc, :weight_u, :weight_tot, :accounting_zone_id, :accounting_zone_name, :tva_account_id, :tva_account_value, :ref, :title, :description, :price_u_ht, :price_u_tva, :price_u_ttc, :tot_line_ht, :tot_line_tva, :tot_line_ttc, :tot_discount_ht, :tot_discount_tva, :tot_discount_ttc, :tot_amount_ht, :tot_amount_tva, :tot_amount_ttc, :discount_market_percent, :discount_qte_percent, :discount_delay_percent, :discount_enrobage_percent, :discount_ecole_percent, :discount_comptant_percent, :product_remise_enrobage_ok, :uv, :p_product_specific_customer_id]
|
|
|
|
|
|
BON_DE_COMMANDE_TO_RESET = %w(block_type product_no_remise price_calc weight_u weight_tot tva_account_id tva_account_value ref title description price_u_ht price_u_tva price_u_ttc tot_line_ht tot_line_tva tot_line_ttc tot_discount_ht tot_discount_tva tot_discount_ttc tot_amount_ht tot_amount_tva tot_amount_ttc discount_market_percent discount_qte_percent discount_delay_percent discount_enrobage_percent discount_ecole_percent discount_comptant_percent product_remise_enrobage_ok uv p_product_specific_customer_id)
|
|
|
|
BON_DE_LIVRAISON_TO_RESET = %w(block_type weight_tot tot_line_ht tot_line_tva tot_line_ttc tot_discount_ht tot_discount_tva tot_discount_ttc tot_amount_ht tot_amount_tva tot_amount_ttc)
|
|
|
|
FACTURE_ACHAT_TO_RESET = %w(devise_rate local_tot_amount_ht block_type product_no_remise price_calc weight_u weight_tot tva_account_id tva_account_value ref title description price_u_ht price_u_tva price_u_ttc tot_line_ht tot_line_tva tot_line_ttc tot_discount_ht tot_discount_tva tot_discount_ttc tot_amount_ht tot_amount_tva tot_amount_ttc discount_market_percent discount_qte_percent discount_delay_percent discount_enrobage_percent discount_ecole_percent discount_comptant_percent product_remise_enrobage_ok uv p_product_specific_customer_id)
|
|
|
|
BON_DE_RECEPTION_ACHAT_TO_RESET = %w(devise_rate local_tot_amount_ht block_type product_no_remise price_calc weight_u weight_tot tva_account_id tva_account_value ref title description price_u_ht price_u_tva price_u_ttc tot_line_ht tot_line_tva tot_line_ttc tot_discount_ht tot_discount_tva tot_discount_ttc tot_amount_ht tot_amount_tva tot_amount_ttc discount_market_percent discount_qte_percent discount_delay_percent discount_enrobage_percent discount_ecole_percent discount_comptant_percent product_remise_enrobage_ok uv p_product_specific_customer_id)
|
|
|
|
COMMANDE_ACHAT_TO_RESET = %w(block_type product_no_remise price_calc weight_u weight_tot tva_account_id tva_account_value ref title description price_u_ht price_u_tva price_u_ttc tot_line_ht tot_line_tva tot_line_ttc tot_discount_ht tot_discount_tva tot_discount_ttc tot_amount_ht tot_amount_tva tot_amount_ttc discount_market_percent discount_qte_percent discount_delay_percent discount_enrobage_percent discount_ecole_percent discount_comptant_percent product_remise_enrobage_ok uv p_product_specific_customer_id)
|
|
|
|
|
|
def to_no_archive
|
|
if !self.imported
|
|
%w(cost_ht marge_ht)
|
|
else
|
|
%w()
|
|
end
|
|
end
|
|
|
|
|
|
def ca_validation_date
|
|
self.price_line_block.validation_date
|
|
end
|
|
|
|
def ca_creation_date
|
|
self.price_line_block.creation_date
|
|
end
|
|
|
|
def ca_wish_date
|
|
self.price_line_block.wish_date
|
|
end
|
|
|
|
def ca_state
|
|
self.price_line_block.state
|
|
end
|
|
|
|
def ca_p_product_cat_id
|
|
self.p_product_ref.p_product.p_product_cat_id if self.p_product_ref and self.p_product_ref.p_product
|
|
end
|
|
|
|
def ca_p_customer_id
|
|
self.price_line_block.p_customer_id if self.price_line_block
|
|
end
|
|
|
|
def ca_cost_ht
|
|
if self.ct_cost_ht
|
|
self.ct_cost_ht
|
|
else
|
|
self.line_stocks.sum(:price_ht) * -1
|
|
end
|
|
end
|
|
|
|
def ca_cost_u_ht
|
|
if self.qte.to_f != 0.0
|
|
self.cost_ht / qte.to_f
|
|
else
|
|
0.0
|
|
end
|
|
end
|
|
|
|
def ca_marge_ht
|
|
self.tot_amount_ht - self.cost_ht
|
|
end
|
|
|
|
def ca_marge_u_ht
|
|
if self.qte.to_f != 0.0
|
|
self.marge_ht / self.qte
|
|
else
|
|
0.0
|
|
end
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
def ca_local_tot_amount_ht
|
|
self.tot_amount_ht * self.devise_rate
|
|
end
|
|
|
|
|
|
def reset_for_update
|
|
|
|
|
|
eval("#{self.block_type_slug.upcase}_TO_RESET").each do |qid|
|
|
|
|
eval("self.ac_#{qid} = nil")
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def ca_p_devise_id
|
|
self.price_line_block.p_devise_id if self.price_line_block
|
|
end
|
|
|
|
def ca_devise_rate
|
|
self.price_line_block.devise_rate if self.price_line_block
|
|
end
|
|
|
|
def ca_block_type
|
|
self.price_line_block.block_type if self.price_line_block
|
|
end
|
|
|
|
def block_type_slug
|
|
self.block_type.to_slug.gsub("-", "_")
|
|
end
|
|
|
|
|
|
def p_product_ref_needed?
|
|
if !self.ct_title? and !self.imported
|
|
true
|
|
end
|
|
end
|
|
|
|
def p_product_needed?
|
|
if !self.ct_title? and !self.imported
|
|
true
|
|
end
|
|
end
|
|
|
|
def personalised_archive
|
|
|
|
end
|
|
|
|
def personalised_unarchive
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
belongs_to :price_line_ref, :class_name => "PriceLine"
|
|
|
|
|
|
|
|
|
|
before_validation do
|
|
self.cancelled = self.price_line_block.cancelled
|
|
|
|
self.p_product_id = self.p_product_ref.p_product_id if self.p_product_ref_id
|
|
|
|
if self.block_type == "Demande de commande"
|
|
errors.add(:qte, "Doit être supérieure à 0") if self.qte.to_f < 0.0
|
|
end
|
|
|
|
if self.block_type == "Bon de livraison" and !self.cancelled
|
|
|
|
if self.price_line_ref
|
|
qte_order = self.price_line_ref.qte
|
|
|
|
if self.id
|
|
qte_or_this = PriceLine.where("id != ?", self.id).where(:cc_block_type => self.block_type, :price_line_ref_id => self.price_line_ref_id, :cancelled => false).sum(:qte)
|
|
else
|
|
qte_or_this = PriceLine.where(:cc_block_type => self.block_type, :price_line_ref_id => self.price_line_ref_id, :cancelled => false).sum(:qte)
|
|
end
|
|
|
|
|
|
|
|
errors.add(:qte, "Dépasse la quantité commandée (#{qte_order})") if qte_order < (qte_or_this + self.qte)
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
def ca_product_no_remise
|
|
if false #self.p_product_ref and self.p_customer and p_customer_product_price = self.p_product_ref.p_customer_product_prices.where(:p_customer_id => self.p_customer.id).first
|
|
p_customer_product_price.no_remise
|
|
|
|
|
|
elsif self.p_product_ref
|
|
self.p_product_ref.no_remise
|
|
|
|
end
|
|
end
|
|
|
|
|
|
def ca_price_calc
|
|
if self.p_product_ref and self.p_product_ref.p_product
|
|
self.p_product_ref.p_product.price_calc
|
|
else
|
|
false
|
|
end
|
|
end
|
|
|
|
def ca_p_product_specific_customer_id
|
|
if self.p_product_ref and self.p_product_ref.p_product
|
|
self.p_product_ref.p_product.p_customer_id
|
|
else
|
|
nil
|
|
end
|
|
end
|
|
|
|
def ca_weight_u
|
|
if self.p_product_ref
|
|
self.p_product_ref.weight
|
|
else
|
|
0.0
|
|
end
|
|
end
|
|
|
|
def ca_weight_tot
|
|
self.weight_u.to_f * self.qte.to_f
|
|
end
|
|
|
|
def ca_accounting_zone_id
|
|
self.price_line_block.accounting_zone_id if self.price_line_block
|
|
end
|
|
|
|
def ca_accounting_zone_name
|
|
self.price_line_block.accounting_zone_name
|
|
end
|
|
|
|
def ca_tva_account_id
|
|
if self.ct_tva_account_id?
|
|
self.ct_tva_account_id
|
|
elsif self.p_product_ref and self.p_product_ref.p_product and tva_rate = self.p_product_ref.p_product.tva_rate(self.accounting_zone_id)
|
|
return tva_rate.id
|
|
end
|
|
end
|
|
|
|
def ca_tva_account_value
|
|
if self.tva_account_id
|
|
return (TvaRate.find( self.tva_account_id).rate).round(2)
|
|
|
|
else
|
|
return 0.0
|
|
end
|
|
end
|
|
|
|
def ca_ref
|
|
if self.p_product_ref and self.p_product_ref.p_product
|
|
self.p_product_ref.p_product.code
|
|
else
|
|
""
|
|
end
|
|
|
|
end
|
|
|
|
def ca_title
|
|
if self.ct_title?
|
|
self.ct_title
|
|
elsif self.p_product_ref
|
|
"#{self.p_product_ref.p_product.name} - #{self.p_product_ref.uv}"
|
|
else
|
|
""
|
|
end
|
|
end
|
|
|
|
def ca_uv
|
|
if self.p_product_ref
|
|
self.p_product_ref.uv
|
|
else
|
|
""
|
|
end
|
|
end
|
|
|
|
def ca_description
|
|
|
|
end
|
|
|
|
def th_price_u_ht
|
|
if self.p_product_ref
|
|
return self.p_product_ref.get_price(:p_customer_id => nil, :qte => self.qte)
|
|
else
|
|
return nil
|
|
end
|
|
end
|
|
|
|
|
|
def default_price_u_ht
|
|
if self.p_product_ref and self.p_customer and p_customer_product_price = self.p_product_ref.p_customer_product_prices.where(:p_customer_id => self.p_customer.id).first and p_customer_product_price.price?
|
|
p_customer_product_price.price
|
|
|
|
|
|
elsif self.p_product_ref
|
|
|
|
return self.p_product_ref.get_price(:p_customer_id => nil, :qte => self.qte)
|
|
|
|
|
|
|
|
else
|
|
return 0.0
|
|
end
|
|
end
|
|
|
|
def ca_price_u_ht
|
|
if self.ct_tot_amount_ht
|
|
if self.qte.to_f != 0.0
|
|
self.ct_tot_amount_ht.to_f / self.qte.to_f
|
|
else
|
|
0.0
|
|
end
|
|
elsif self.ct_u_price_ht
|
|
return self.ct_u_price_ht
|
|
|
|
elsif self.bk_price_ht
|
|
return self.bk_price_ht
|
|
|
|
elsif PriceLineBlock::SALE_BLOCKS.include?(self.block_type)
|
|
return self.default_price_u_ht
|
|
else
|
|
return 0.0
|
|
end
|
|
end
|
|
|
|
def ca_price_u_kg_ht
|
|
|
|
if self.price_calc == "Kg"
|
|
|
|
if self.weight_u.to_f != 0.0
|
|
self.price_u_ht.to_f / self.weight_u.to_f
|
|
else
|
|
0
|
|
end
|
|
|
|
else
|
|
self.price_u_ht
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
def weight_qte
|
|
if self.price_calc == "Kg"
|
|
self.qte.to_f * self.weight_u.to_f
|
|
else
|
|
self.qte.to_f
|
|
end
|
|
|
|
end
|
|
|
|
|
|
def ca_price_u_tva
|
|
((self.tva_account_value/100) * self.price_u_ht).round(2)
|
|
end
|
|
|
|
def ca_price_u_ttc
|
|
(self.price_u_ht + self.price_u_tva).round(2)
|
|
end
|
|
|
|
|
|
|
|
def ca_tot_line_ht
|
|
(self.price_u_ht * self.qte.to_f).round(2)
|
|
end
|
|
|
|
def ca_tot_line_tva
|
|
(self.tot_line_ht * (self.tva_account_value/100)).round(2)
|
|
end
|
|
|
|
def ca_tot_line_ttc
|
|
(self.tot_line_ht + self.tot_line_tva).round(2)
|
|
end
|
|
|
|
|
|
|
|
|
|
# REMISES
|
|
|
|
# Remise marché annuel
|
|
def ca_discount_market_percent
|
|
if !self.product_no_remise and !self.ct_u_price_ht and !self.p_product_specific_customer_id and self.discount_ecole_percent == 0 and self.p_customer and self.p_customer.market_discount
|
|
self.price_line_block.customer_market_discount_percent
|
|
else
|
|
0.0
|
|
end
|
|
|
|
end
|
|
|
|
def ca_discount_market_ht
|
|
((1-(self.discount_market_percent.to_f / 100)) * self.ca_price_u_kg_ht)
|
|
end
|
|
|
|
|
|
# Remise quantité livrée (par commande)
|
|
def ca_discount_qte_percent
|
|
if !self.product_no_remise and !self.ct_u_price_ht and !self.p_product_specific_customer_id and self.discount_ecole_percent == 0 and self.price_line_block and self.price_line_block.remise_qte_ok
|
|
weight = self.price_line_block.weight_tot
|
|
if weight >= 500
|
|
percent = 5
|
|
elsif weight >= 300
|
|
percent = 4
|
|
elsif weight >= 220
|
|
percent = 3
|
|
elsif weight >= 160
|
|
percent = 2
|
|
elsif weight >= 75
|
|
percent = 1
|
|
else
|
|
percent = 0
|
|
end
|
|
|
|
|
|
return percent
|
|
|
|
else
|
|
return 0.0
|
|
end
|
|
end
|
|
|
|
|
|
|
|
def ca_discount_qte_ht
|
|
((1-(self.discount_qte_percent.to_f / 100) )* self.ca_discount_market_ht)
|
|
end
|
|
|
|
def ca_discount_delay_percent
|
|
if !self.product_no_remise and !self.ct_u_price_ht and !self.p_product_specific_customer_id and self.discount_ecole_percent == 0 and self.price_line_block and self.price_line_block.remise_pre_order_ok
|
|
2
|
|
else
|
|
0
|
|
end
|
|
|
|
end
|
|
|
|
def ca_discount_delay_ht
|
|
((1-(self.discount_delay_percent.to_f / 100)) * self.ca_discount_qte_ht)
|
|
end
|
|
|
|
|
|
|
|
def ca_discount_comptant_percent
|
|
if !self.product_no_remise and !self.p_product_specific_customer_id and self.discount_ecole_percent == 0 and self.price_line_block and self.price_line_block.discount_comptant
|
|
2
|
|
else
|
|
0
|
|
end
|
|
end
|
|
|
|
def ca_discount_comptant_ht
|
|
((1-(self.discount_comptant_percent.to_f / 100)) * self.ca_discount_delay_ht)
|
|
end
|
|
|
|
def ca_product_remise_enrobage_ok
|
|
if !self.product_no_remise and !self.ct_u_price_ht and self.p_product_ref and self.p_product_ref.p_product and self.p_product_ref.p_product.discount_enrobage
|
|
true
|
|
else
|
|
false
|
|
end
|
|
end
|
|
def ca_discount_enrobage_percent
|
|
if !self.product_no_remise and !self.p_product_specific_customer_id and self.discount_ecole_percent == 0 and self.price_line_block and self.price_line_block.remise_enrobage_ok and self.product_remise_enrobage_ok
|
|
5
|
|
else
|
|
0
|
|
end
|
|
|
|
end
|
|
|
|
def ca_discount_enrobage_ht
|
|
((1-(self.discount_enrobage_percent.to_f / 100) )* self.ca_discount_comptant_ht)
|
|
end
|
|
|
|
def ca_discount_ecole_percent
|
|
if !self.product_no_remise and !self.ct_u_price_ht and !self.p_product_specific_customer_id and self.price_line_block and self.price_line_block.remise_ecole_ok
|
|
20
|
|
else
|
|
0
|
|
end
|
|
end
|
|
|
|
def ca_discount_ecole_ht
|
|
((1-(self.discount_ecole_percent.to_f / 100)) * self.ca_discount_enrobage_ht)
|
|
end
|
|
|
|
|
|
# FIN REMISES
|
|
|
|
def ca_price_u_kg_net_ht
|
|
self.ca_discount_ecole_ht
|
|
end
|
|
|
|
def ca_tot_amount_ht
|
|
if self.ct_tot_amount_ht
|
|
self.ct_tot_amount_ht
|
|
else
|
|
(self.ca_price_u_ht * self.qte.to_f).round(3)
|
|
end
|
|
end
|
|
|
|
def ca_tot_amount_tva
|
|
(self.tot_amount_ht * (self.tva_account_value/100)).round(3)
|
|
end
|
|
|
|
def ca_tot_amount_ttc
|
|
(self.tot_amount_ht + self.tot_amount_tva).round(3)
|
|
end
|
|
|
|
|
|
|
|
def ca_tot_discount_ht
|
|
(self.ca_price_u_ht * self.qte.to_f).round(3) - self.ca_tot_amount_ht
|
|
end
|
|
|
|
|
|
|
|
def ca_tot_discount_tva
|
|
(self.tot_discount_ht * (self.tva_account_value/100)).round(3)
|
|
end
|
|
|
|
def ca_tot_discount_ttc
|
|
(self.tot_discount_ht+self.tot_discount_tva).round(3)
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def p_customer
|
|
if self.price_line_block
|
|
self.price_line_block.p_customer
|
|
end
|
|
end
|
|
|
|
|
|
def sale_account
|
|
if self.p_product_ref and self.p_product_ref.p_product and self.p_product_ref.p_product.imp_sale_account?
|
|
self.p_product_ref.p_product.imp_sale_account
|
|
elsif self.p_product_ref and self.p_product_ref.p_product and self.p_product_ref.p_product.p_product_cat and self.p_product_ref.p_product.p_product_cat.sale_account?
|
|
self.p_product_ref.p_product.p_product_cat.sale_account
|
|
elsif self.p_product_ref and self.p_product_ref.ct_sub_name?
|
|
self.p_product_ref.ct_sub_name
|
|
else
|
|
"compte non défini"
|
|
end
|
|
end
|
|
|
|
|
|
AVOIR_TO_RESET = %w(block_type product_no_remise price_calc weight_u weight_tot tva_account_id tva_account_value ref title description price_u_ht price_u_tva price_u_ttc tot_line_ht tot_line_tva tot_line_ttc tot_discount_ht tot_discount_tva tot_discount_ttc tot_amount_ht tot_amount_tva tot_amount_ttc discount_market_percent discount_qte_percent discount_delay_percent discount_enrobage_percent discount_ecole_percent discount_comptant_percent product_remise_enrobage_ok uv p_product_specific_customer_id)
|
|
|
|
|
|
def self.asap_triage(limit)
|
|
total = self.sum(:qte).to_i
|
|
asap = self.where('cc_wish_date < ?', Date.today + limit).sum(:qte).to_i
|
|
non_asap = total - asap
|
|
return [asap, non_asap]
|
|
end
|
|
|
|
def p_fournisseur_ref_is_memorizable?
|
|
self.p_product_ref.present? && self.imported? && PFournisseurRef.where(p_fournisseur: self.p_fournisseur, ref: self.ct_ref, label: self.ct_title).empty?
|
|
end
|
|
|
|
def memorize_p_fournisseur_ref
|
|
PFournisseurRef.create(p_fournisseur: self.p_fournisseur, p_product_ref: self.p_product_ref, ref: self.ct_ref, label: self.ct_title)
|
|
end
|
|
|
|
def affected_qty_ok
|
|
return self.p_articles.count >= self.qte
|
|
end
|
|
|
|
def affected_qty
|
|
return self.p_articles.count
|
|
end
|
|
|
|
def qte_greater_than_or_equal_to_affected_qty
|
|
if self.affected_qty > self.qte
|
|
errors.add(:qte, "doit être supérieur ou égale à la quantité affectée")
|
|
end
|
|
end
|
|
|
|
end
|