class PriceLineBlock < ApplicationRecord
  belongs_to :price_lineable, :polymorphic => true
  validates :wish_date, :presence => true, :if => :wish_date_needed?
  has_many :price_lines
  accepts_nested_attributes_for :price_lines, allow_destroy: true
  belongs_to :p_devise
  
  validates :p_customer_id, :presence => true, :if => :p_customer_needed?
  validates :p_fournisseur_id, :presence => true, :if => :p_fournisseur_needed?
  validates :particular_bill_id, :presence => true, :if => :particular_bill_needed?
  validates :particular_send_id, :presence => true, :if => :particular_send_needed?
  
  belongs_to :particular_bill, :class_name => "Particular"#, :dependent => :destroy
  
  accepts_nested_attributes_for :particular_bill
  
  belongs_to :particular_send, :class_name => "Particular"#, :dependent => :destroy
  
  accepts_nested_attributes_for :particular_send
  
  has_many :line_blocks
  belongs_to :p_customer
  
  belongs_to :p_payment_type
  
  PURCHASE_BLOCKS = ["Facture d'achat", "Commande achat"]
  SALE_BLOCKS = ["Demande de commande", "Bon de commande", "Devis", "Bon de livraison", "Facture", "Avoir"]
  
  belongs_to :p_fournisseur
  accepts_nested_attributes_for :p_fournisseur
  
  def to_no_archive
    if self.imported
      %w()
    else
      %w(cost_ht marge_ht)
    end
  end
  
  def ca_cost_ht
    self.price_lines.sum(:cc_cost_ht)
  end
    
  def ca_marge_ht
    self.tot_amount_ht - self.ca_cost_ht
  end
    
    
  
  def test_if_stock_ok?
    to_r = true
    self.price_lines.each do |pl|
      
      
      
      if pl.p_product_ref && pl.p_product_ref.stocked
        
        if pl.p_product_ref.assembled
          pl.p_product_ref.p_product_assembleds.all.each do |ppa|
            if LineStock.where(:p_product_ref_id => ppa.p_product_ref_id).sum(:qte_available) >= (pl.qte.to_f * ppa.qte.to_f)
          
            else
              to_r = false
            end
            
            
          end
        else
        
          if LineStock.where(:p_product_ref_id => pl.p_product_ref_id).sum(:qte_available) >= pl.qte
          
          else
            to_r = false
          end
        end

        
      end
      
    end
    
    return to_r
  end
  
  def test_if_price_stock_ok?
    to_r = true
    self.price_lines.each do |pl|
      if pl.p_product_ref && pl.p_product_ref.stocked
        puts pl.p_product_ref.p_product_id
        if pl.p_product_ref.p_product and pl.p_product_ref.p_product.ct_purchase_price_ht.to_f > 0.0
        else
          to_r = false
        end
  
      end
      
    end
    
    return to_r
  end
  
  def update_stocks_from_average
    if self.block_type == "Facture" and !self.cost_ok
      
      if self.test_if_price_stock_ok?
        
        self.price_lines.each do |pl|
          if pl.p_product_ref
            pl.ct_cost_ht = pl.p_product_ref.p_product.ct_purchase_price_ht.to_f * pl.qte.to_f
            pl.save
            
          end
        end
        self.cost_ok = true
        self.save
        self.price_lineable.save if self.price_lineable
      end
      
    end
  end
  
  
  def update_stocks_for(p_product_ref, qte, pl)
    puts "TEST"
    puts "Référence : #{p_product_ref.id} #{p_product_ref.p_product.name}"
    if qte.to_f != 0.0
      decr_line_stock = LineStock.create(:date => self.price_lineable.date, :p_product_ref => p_product_ref, :qte => qte*-1, :description => "Attribution à la ligne d'une facture", :price_ht => 0.0, :price_line => pl, :price_line_block => self, :stockable => self.price_lineable)
   
  
      price = 0.0
      line_stock_usages = []
  
      qte_to_affect = qte
  
      LineStock.where(:p_product_ref_id => p_product_ref.id).where("date <= ?", self.price_lineable.date).where("qte_available > 0.0").each do |ls|
        if qte_to_affect <= ls.qte_available
          qte_here = qte_to_affect
        else
          qte_here = ls.qte_available
      
        end
    
        qte_to_affect = qte_to_affect - qte_here
    
        lsu = LineStockUsage.create(:qte => qte_here, :line_stock => ls, :dest_line_stock_id => decr_line_stock.id)
        line_stock_usages << lsu 
    
        price += lsu.price_ht
        ls.save
    
        break if qte_to_affect == 0.0
    
        #price_u_ht
    
      end
      decr_line_stock.price_ht = price * -1
      decr_line_stock.save
    end
    
  end
  
  def update_stocks
    if self.block_type == "Facture" and !self.cost_ok
      if self.test_if_stock_ok?
         
        self.price_lines.each do |pl|
          if pl.p_product_ref && pl.p_product_ref.stocked
            if pl.p_product_ref.assembled
              
              pl.p_product_ref.p_product_assembleds.all.each do |ppa|
              
            
                self.update_stocks_for(ppa.p_product_ref, (pl.qte.to_f * ppa.qte.to_f), pl)
            
              end
              
            else
              
              self.update_stocks_for(pl.p_product_ref, pl.qte, pl)
              
              
            
            end
           
        
          end
      
        end
        self.cost_ok = true
        
        
        self.save
        self.save # deuxième sauvegarde pour prendre en compte les couts de price_line
        
        
        self.price_lineable.save if self.price_lineable
        
        return true
      
      end
      
      
      
    end
  end
  
  def generate_stock
    self.price_lines.each do |pl|
      if pl.p_product_ref
        LineStock.create(:dluo => pl.dluo, :date => self.price_lineable.date, :p_product_ref => pl.p_product_ref, :description => "Entrée en stock par facture d'achat", :qte => pl.qte, :price_ht => pl.local_tot_amount_ht, :price_line => pl, :price_line_block => self, :stockable => self.price_lineable)
      
      end
      
      
    end
    
    self.stock_ok = true
    self.save
    
    self.price_lineable.save if self.price_lineable
  end
  
  def purchase?
    if PriceLineBlock::PURCHASE_BLOCKS.include?(self.block_type)
      true
    else
      false
    end
  end
  def sale?
    if PriceLineBlock::SALE_BLOCKS.include?(self.block_type)
      true
    else
      false
    end
  end
  
  
  def devise_symbol
    if self.p_devise
      self.p_devise.symbol
    else
      "€"
    end
  end
  
  def ca_devise_rate
    
    if self.local_amount_ttc
      if  self.tot_amount_ttc != 0.0
        self.local_amount_ttc / self.tot_amount_ttc
      else
        0.0
      end
    elsif self.p_devise
      return self.p_devise.rate.to_f
      
    else
      1.0
    end
  end
  
  def wish_date_needed?
    if PriceLineBlock::PURCHASE_BLOCKS.include?(self.block_type) or self.block_type == "Réponse fournisseur"
      false
    else
      true
    end
  end
  
  def particular_bill_needed?
    if !self.imported
      if PriceLineBlock::PURCHASE_BLOCKS.include?(self.block_type) or self.block_type == "Demande prix" or self.block_type == "Réponse fournisseur"
        false
      else
        true
      end
    end
  end
  
  def particular_send_needed?
    if !self.imported
      if PriceLineBlock::PURCHASE_BLOCKS.include?(self.block_type) or self.block_type == "Demande prix" or self.block_type == "Réponse fournisseur"
        false
      else
        true
      end
    end
  end
  
  def p_fournisseur_needed?
    if PriceLineBlock::PURCHASE_BLOCKS.include?(self.block_type)
      true
    else
      false
    end
  end
  
  def p_customer_needed?
    if PriceLineBlock::PURCHASE_BLOCKS.include?(self.block_type) or self.block_type == "Demande prix" or self.block_type == "Réponse fournisseur"
      false
    elsif !self.imported
      true
    end
  end
   
  acts_as_caching :fields => [:state, :solded_nbr_days, :solded_at, :cost_ht, :marge_ht, :devise_rate, :bon_de_commande_id, :bon_de_livraison_id, :facture_id, :reliquat, :customer_market_discount_percent, :block_type, :discount_comptant, :fdp_tva_rate, :weight_tot, :accounting_zone_id, :accounting_zone_name, :tot_lines_ht, :tot_lines_tva, :tot_lines_ttc, :tot_fdp_ht, :tot_fdp_tva, :tot_fdp_ttc, :tot_discount_ht, :tot_discount_tva, :tot_discount_ttc, :tot_amount_af_discount_ht, :tot_amount_af_discount_tva, :tot_amount_af_discount_ttc, :gen_discount_percent, :tot_gen_discount_ht, :tot_gen_discount_tva, :tot_gen_discount_ttc, :tot_amount_ht, :tot_amount_tva, :tot_amount_ttc, :remise_enrobage_ok, :remise_ecole_ok, :remise_pre_order_ok, :remise_qte_ok, :payment_comptant, :payment_delais, :payment_month_end, :payment_end_at, :acompte, :acompte_percent, :payment_days, :nbr_ship, :creation_date, :p_customer_cat_id]
  
  def ca_state
    self.price_lineable.state rescue nil
  end
  

  BON_DE_COMMANDE_TO_RESET =  %w(weight_tot tot_lines_ht tot_lines_tva tot_lines_ttc tot_fdp_ht tot_fdp_tva tot_fdp_ttc tot_discount_ht tot_discount_tva tot_discount_ttc tot_amount_af_discount_ht tot_amount_af_discount_tva tot_amount_af_discount_ttc gen_discount_percent tot_gen_discount_ht tot_gen_discount_tva tot_gen_discount_ttc tot_amount_ht tot_amount_tva tot_amount_ttc nbr_ship)
  
  BON_DE_LIVRAISON_TO_RESET = %w(weight_tot tot_lines_ht tot_lines_tva tot_lines_ttc tot_fdp_ht tot_fdp_tva tot_fdp_ttc tot_discount_ht tot_discount_tva tot_discount_ttc tot_amount_af_discount_ht tot_amount_af_discount_tva tot_amount_af_discount_ttc gen_discount_percent tot_gen_discount_ht tot_gen_discount_tva tot_gen_discount_ttc tot_amount_ht tot_amount_tva tot_amount_ttc nbr_ship)
  
  FACTURE_DACHAT_TO_RESET = %w(devise_rate weight_tot tot_lines_ht tot_lines_tva tot_lines_ttc tot_fdp_ht tot_fdp_tva tot_fdp_ttc tot_discount_ht tot_discount_tva tot_discount_ttc tot_amount_af_discount_ht tot_amount_af_discount_tva tot_amount_af_discount_ttc gen_discount_percent tot_gen_discount_ht tot_gen_discount_tva tot_gen_discount_ttc tot_amount_ht tot_amount_tva tot_amount_ttc nbr_ship)
  
  COMMANDE_ACHAT_TO_RESET = %w(weight_tot tot_lines_ht tot_lines_tva tot_lines_ttc tot_fdp_ht tot_fdp_tva tot_fdp_ttc tot_discount_ht tot_discount_tva tot_discount_ttc tot_amount_af_discount_ht tot_amount_af_discount_tva tot_amount_af_discount_ttc gen_discount_percent tot_gen_discount_ht tot_gen_discount_tva tot_gen_discount_ttc tot_amount_ht tot_amount_tva tot_amount_ttc nbr_ship)
  
  def reset_for_update
    
    self.price_lines.each do |pl|
      pl.reset_for_update
    end
    
    self.price_lines.each do |pl|
      pl.bk_price_ht = pl.default_price_u_ht if !pl.bk_price_ht
      pl.save
    end
    
    
    
    eval("#{self.block_type_slug.upcase}_TO_RESET").each do |qid|
    
      eval("self.ac_#{qid} = nil")
    end
    
    self.archive_now(:skip_personalised_archive => true)
    
    
    
    self.price_lines.each do |pl|
      pl.archive_now(:skip_personalised_archive => true)
    end
    
    
    
      
  end


  def ca_solded_at
    if self.price_lineable and self.price_lineable_type == "PriceDocument"
      self.price_lineable.solded_at
    end
      
  end
  
  def ca_solded_nbr_days
    if self.price_lineable and self.price_lineable_type == "PriceDocument"
      self.price_lineable.solded_nbr_days
    end
      
  end

  def ca_customer_market_discount_percent
    self.p_customer.market_discount.percent if self.p_customer and self.p_customer.market_discount
  end
  
 
  
  def personalised_archive
    self.price_lines.each do |pl|
      pl.archive_now
    end
  end
  
  def personalised_unarchive
    self.price_lines.each do |pl|
      pl.unarchive_now
    end
  end
  
  
  def ca_bon_de_commande_id 
    self.price_lineable.bon_de_commande_id if self.price_lineable_type == "PriceDocument" and self.price_lineable
  end
  
  def ca_bon_de_livraison_id 
    self.price_lineable.bon_de_livraison_id if self.price_lineable_type == "PriceDocument" and self.price_lineable
  end
  
  def ca_facture_id 
    self.price_lineable.facture_id if self.price_lineable_type == "PriceDocument" and self.price_lineable
  end
  
  def ca_reliquat 
    self.price_lineable.reliquat  if self.price_lineable_type == "PriceDocument" and self.price_lineable
  end
  
  
  def ca_block_type
    self.price_lineable.block_type if self.price_lineable
  end
  
  def block_type_slug
    self.block_type.to_slug.gsub("-", "_")
  end
  
  
  before_validation do
    
    self.cancelled = self.price_lineable.cancelled if self.price_lineable and self.price_lineable_type == "PriceDocument" 
    if !self.id and self.p_customer
      self.p_commercial_id = self.p_customer.p_commercial_id
      
      
      self.p_payment_type_id = self.p_customer.p_payment_type_id
      self.ct_payment_comptant = self.p_customer.comptant
      self.ct_acompte = self.p_customer.acompte
      self.ct_acompte_percent = self.p_customer.acompte_percent
      self.ct_payment_delais = self.p_customer.payment_delais
      self.ct_payment_month_end = self.p_customer.payment_fin_de_mois
      
      
    end
    
    if self.particular_bill_needed? and (!self.p_customer or !self.particular_bill or !self.particular_bill.owner or self.particular_bill.owner != self.p_customer)
      errors.add(:particular_bill_id, 'doit être une adresse du client') 
    end
    
    if self.particular_send_needed? and (!self.p_customer or !self.particular_send or !self.particular_send.owner or self.particular_send.owner != self.p_customer)
      errors.add(:particular_send_id, 'doit être une adresse du client') 
    end
    
  end
  
  
  def ca_remise_pre_order_ok
    
    if self.p_customer and self.p_customer_cat_id == 1 and self.wish_date and self.created_at and (self.wish_date >= (self.creation_date + 8.weeks))
      true
    else
      false
    end
  end
  
  
  def ca_remise_qte_ok
    
    if self.p_customer and self.p_customer_cat_id == 1
      true
    else
      false
    end
  end

  def ca_remise_enrobage_ok
    
    if !self.remise_ecole_ok and self.p_customer and self.p_customer.discount_enrobage
      true
    else
      false
    end
  end
  
  def ca_remise_ecole_ok
    if self.p_customer and self.p_customer_cat_id == 3
      true
    else
      false
    end
  end


  def ca_discount_comptant
    if self.p_customer 
      self.p_customer.discount_comptant
    end
  end

  
  
  
  after_save do
    self.price_lines.each do |pl|
      pl.save
    end
  end
  
  
  
  def ca_weight_tot
    r = 0.0
    self.price_lines.each do |pl|
      r+= pl.weight_tot
    end
    return r
  end
  
  def ca_accounting_zone_id
    self.price_lineable.accounting_zone_id if self.price_lineable
  end

  def ca_accounting_zone_name
    self.price_lineable.accounting_zone_name if self.price_lineable
  end

  def ca_tot_lines_ht
    r = 0.0
    self.price_lines.each do |pl|
      r+= pl.tot_amount_ht
    end
    return r
    
  end

  def ca_tot_lines_ht_for_discount
    r = 0.0
    self.price_lines.each do |pl|
      r+= pl.tot_amount_ht if !pl.product_no_remise
    end
    return r
    
  end


  def ca_tot_lines_tva
    r = 0.0
    self.price_lines.each do |pl|
      r+= pl.tot_amount_tva
    end
    return r
  end

  def ca_tot_lines_tva_for_discount
    r = 0.0
    self.price_lines.each do |pl|
      r+= pl.tot_amount_tva if !pl.product_no_remise
    end
    return r
  end

  def ca_tot_lines_ttc
    r = 0.0
    self.price_lines.each do |pl|
      r+= pl.tot_amount_ttc
    end
    return r
  end
  
  
  
  def default_tot_fdp_ht
    if self.p_customer_cat_id == 2
      if (self.tot_lines_ht + self.tot_discount_ht) >= 290.0
        0.0
      elsif (self.tot_lines_ht + self.tot_discount_ht) >= 150.0
        15.0
      else
        30.0
      end
    else
    
      if ca_weight_tot >= 45.0
        0.0
      elsif ca_weight_tot >= 30
        25.0
      else
        40.0
      end
    
    
    end
    
  end
  
  def ca_tot_fdp_ht 
    if PriceLineBlock::PURCHASE_BLOCKS.include?(self.block_type)
      return 0.0
    else
      if self.reliquat #false #self.price_lineable_type == "PriceDocument" and self.price_lineable and self.price_lineable.label == "Avoir"
        if self.reliquat_fdp_ht
          self.reliquat_fdp_ht
        else
          0.0
        end
      else
        if self.ct_tot_fdp_ht
          self.ct_tot_fdp_ht
        elsif self.bk_tot_fdp_ht
          self.bk_tot_fdp_ht
        else
          self.default_tot_fdp_ht
      
        end
      end
    end
      
  end
  
  def ca_fdp_tva_rate
    if self.accounting_zone_id == 1
      20.0
    else
      0.0
    end
  end
  
  def ca_tot_fdp_tva  
    self.tot_fdp_ht * (self.fdp_tva_rate/100)
  end
  
  def ca_tot_fdp_ttc 
    self.tot_fdp_ht + self.tot_fdp_tva
  end

  def ca_tot_discount_ht
    if self.ct_tot_discount_percent
      (self.ct_tot_discount_percent / -100.0) * self.ca_tot_lines_ht_for_discount
    else
      0.0
    end
  end

  def ca_tot_discount_tva
    if self.ct_tot_discount_percent
      (self.ct_tot_discount_percent / -100.0) * self.ca_tot_lines_tva_for_discount
    else
      0.0
    end
    
   
  end

  def ca_tot_discount_ttc
    self.tot_discount_ht + self.tot_discount_tva
  end

  def ca_tot_amount_af_discount_ht
    self.tot_lines_ht + self.tot_discount_ht + self.tot_fdp_ht
  end

  def ca_tot_amount_af_discount_tva
    self.tot_lines_tva + self.tot_discount_tva + self.tot_fdp_tva
  end

  def ca_tot_amount_af_discount_ttc
    self.tot_lines_ttc + self.tot_discount_ttc + self.tot_fdp_ttc
  end

  def ca_gen_discount_percent
    0.0
  end

  def ca_tot_gen_discount_ht
    0.0
  end

  def ca_tot_gen_discount_tva
    0.0
  end

  def ca_tot_gen_discount_ttc
    0.0
  end

  def ca_tot_amount_ht
    self.tot_amount_af_discount_ht + self.tot_gen_discount_ht
  end

  def ca_tot_amount_tva
    self.tot_amount_af_discount_tva + self.tot_gen_discount_tva
  end

  def ca_tot_amount_ttc
    self.tot_amount_af_discount_ttc + self.tot_gen_discount_ttc
  end
  
  
  def ca_payment_comptant
    if self.ct_payment_comptant
      self.ct_payment_comptant
    else
      if self.p_customer
        self.p_customer.comptant
      else
        nil
      end   
    end 
  end
  
  def ca_payment_delais
    if self.ct_payment_delais
      self.ct_payment_delais
    else
      if self.p_customer
        self.p_customer.payment_delais
      else
        nil
      end
    end
  end
  
  def ca_payment_month_end
    if self.ct_payment_month_end
      self.ct_payment_month_end
    else
      if self.p_customer
        self.p_customer.payment_fin_de_mois
      else
        nil
      end
    end
  end
  
  def ca_payment_end_at
    if self.price_lineable_type == "PriceDocument" and self.price_lineable 
      start_date = self.price_lineable.date
    elsif self.price_lineable_type == "PCustomerSheet" and self.price_lineable
      start_date = self.price_lineable.price_line_block.creation_date
    end



    if start_date
      if self.payment_delais.to_i == 0
        start_date
      else
        start_date + self.payment_delais.to_i.days
      end
    end
    
  end
  
  def ca_acompte
    if self.p_customer
      self.p_customer.acompte
    else
      nil
    end
  end
  
  def ca_acompte_percent
    if self.p_customer
      self.p_customer.acompte_percent
    else
      nil
    end
  end
  
  def ca_payment_days
  
  end
  
  def ca_nbr_ship
    if self.ct_nbr_ship
      self.ct_nbr_ship
    else
      nil
    end
      
  end
  
  def ca_creation_date
    if self.ct_creation_date
      self.ct_creation_date
    
    elsif self.price_lineable_type == "PriceDocument" and self.price_lineable and self.price_lineable.ref_element and self.price_lineable.ref_element.price_line_block
      self.price_lineable.ref_element.price_line_block.creation_date
    elsif self.id
      self.created_at
    else
      Date.today
    end
  end
  
  def ca_p_customer_cat_id
    if self.p_customer
      self.p_customer.p_customer_cat_id
    else
      nil
    end
  end
  
  def cumul_discount_ht
    r = 0.0
    self.price_lines.each do |pl|
      r += pl.ca_tot_discount_ht
      
    end
    return r
      
  end
  
  
  AVOIR_TO_RESET =  %w(weight_tot tot_lines_ht tot_lines_tva tot_lines_ttc tot_fdp_ht tot_fdp_tva tot_fdp_ttc tot_discount_ht tot_discount_tva tot_discount_ttc tot_amount_af_discount_ht tot_amount_af_discount_tva tot_amount_af_discount_ttc gen_discount_percent tot_gen_discount_ht tot_gen_discount_tva tot_gen_discount_ttc tot_amount_ht tot_amount_tva tot_amount_ttc nbr_ship)
  
  
  
  
  
  
end
