class Sale < ApplicationRecord
  self.primary_key = "sale_id"

  #primary key - need to be unique generated for multiple shops
  before_create :generate_custom_id
  #before_create :generate_receipt_no
  belongs_to :cashier, :optional => true
  belongs_to :customer, :optional => true
  has_many :sale_items
  has_many :sale_discount_items
  has_many :sale_discounts
  has_many :sale_taxes
  has_many :sale_payments
  has_many :sale_orders
  has_many :bookings
  has_many :product_commissions

  scope :open_invoices, -> { where("sale_status = 'new' and receipt_date BETWEEN '#{DateTime.now.utc.end_of_day}' AND '#{DateTime.now.utc.beginning_of_day}'") }
  scope :complete_sale, -> { where("sale_status = 'completed' and receipt_date BETWEEN '#{DateTime.now.utc.beginning_of_day}' AND '#{DateTime.now.utc.end_of_day}'") }

  REPORT_TYPE = {
  "daily" => 0,
  "monthly" => 1,
  "yearly" => 2
  }
  SALE_STATUS_OUTSTANDING = "outstanding"
  SALE_STATUS_COMPLETED = "completed"

  def generate_invoice_from_booking(booking_id, requested_by, cashier)
    booking = Booking.find(booking_id)
    status = false
    Rails.logger.debug "Booking -> " + booking.id.to_s
    if (booking)
      Rails.logger.debug "Booking -> Booking Order Count -> " + booking.booking_orders.count.to_s
      #get all order attached to this booking and combine into 1 invoice

      booking.booking_orders.each do |order|
        if booking.sale_id
          status, sale_id = generate_invoice_from_order(order.order_id, nil, booking, requested_by, cashier)
        else
          status, sale_id = generate_invoice_from_order(order.order_id, booking.sale_id, booking, requested_by, cashier)
        end
        booking.sale_id = sale_id
      end

      order = booking.booking_orders.take.order
      link_order_sale(order.id)

      # dining charges
      charges = DiningCharge.where('dining_facility_id=?',booking.dining_facility_id).take
      if !charges.nil?        
        block_count, diningprice = DiningCharge.amount_calculate(charges, booking.checkin_at, booking.checkout_at)
        dining_time = booking.checkin_at.strftime('%H:%M %p').to_s + " - " + booking.checkout_at.strftime('%H:%M %p').to_s
        create_saleitem_diningcharges(charges, block_count, diningprice, booking.dining_facility.name, dining_time)
      end

      return status, sale_id
    end
  end

  def generate_invoice_from_order (order_id, sale_id, booking, requested_by, cashier = nil)
    taxable = true
    #if sale_id is exsit and validate
    #add order to that invoice
    if (sale_id)
      self.find(sale_id)
    end
    Rails.logger.debug "Does it have Existing Sale -> [#{self.id.to_s}] - Status [#{self.sale_status}]"

    if self.sale_status == "void"
      return false, "Invoice is void. Cannot be edited"
    else
      #if this is new sale generate_receipt_no
      generate_receipt_no
      order = Order.find(order_id)

      #Default Tax - Values
      self.tax_type = "exclusive"

      # set cashier
      if cashier != nil
        self.cashier_id = cashier.id
        self.cashier_name = cashier.name
      else
        self.cashier_id = requested_by.id
        self.cashier_name = requested_by.name
      end

      # set waiter
      self.requested_by = requested_by.name

      self.requested_at = DateTime.now.utc.getlocal

      Rails.logger.debug "Order -> #{order.id} | order_status -> #{order.status}"
      if order
        self.customer_id = order.customer_id
        Rails.logger.debug "Order -> #{order.id} | Items Count -> #{order.order_items.count}"

        order.order_items.each do |item|
          add_item(item)
        end

         link_order_sale(order.id)

      end
      self.save!

      #compute sales summary
      compute

      #Update the order items that is billed
      order.update_items_status_to_billed(nil)
      order.status = "billed"
      order.save

      booking.sale_id = self.id
      booking.checkout_at = Time.now.utc.getlocal
      booking.checkout_by = requested_by.name
      booking.save      

      InventoryJob.perform_now(self.id)

      return true, self.id
    end

      return false, nil

  end

  #This is when spilt bill is request - then we cannot link order to invoice
  #Cos there will be multiple orders - and items are spilt from there.
  #Unless order is spilt by then it is possible.
  def generate_invoice_by_items (items, requested_by)
    taxable = true
    self.requested_by = requested_by
    self.requested_at = DateTime.now.utc.getlocal

    items.each do |item|
      add_item(item)

      #this will result in multiple orders belonging in multiple invoices - because of spilt invoices.
      link_order_sale(item.order_id, taxable)
    end

    #Update item status as billed
    order.update_items_status_to_billed(items)

    status = self.save!
    return status, self.id

  end

  def add_item (item)
    #check if the item is on promotion

    #save sale_audit
    sale_item = SaleItem.new

    #pull
    sale_item.product_code = item.item_code
    sale_item.item_instance_code = item.item_instance_code
    sale_item.product_name = item.item_name
    sale_item.product_alt_name = item.alt_name
    sale_item.account_id = item.account_id
    sale_item.remark = item.remark

    sale_item.qty = item.qty
    sale_item.unit_price = item.price
    sale_item.taxable_price = sale_item.qty * sale_item.unit_price
    sale_item.is_taxable = item.taxable

    sale_item.price = sale_item.qty * sale_item.unit_price

    self.sale_items << sale_item
  end

  def create_saleitem_diningcharges(chargeObj, block_count, diningprice, dining_name, dining_time)
    sale_item = SaleItem.new
    sale_item.product_code = chargeObj.item_code
    sale_item.product_name = dining_name.to_s + " ( " + dining_time.to_s + " )"
    sale_item.account_id = 0
    sale_item.product_alt_name = "-"
    sale_item.qty = block_count
    sale_item.unit_price = chargeObj.unit_price
    sale_item.taxable_price = diningprice
    sale_item.is_taxable = chargeObj.taxable
    sale_item.sale_id = self.id
    sale_item.price = diningprice
    sale_item.save

    # Re-calc 
    sale = Sale.find(self.id)
    self.compute_by_sale_items(self.id, sale.sale_items, self.total_discount)
  end

  def update_item (item)
    #save sale_audit

  end

  def apply_item_discount (item_code, discount_type, discount_amount)

  end

  def apply_discount (discount_type, discount_code)
    #save action to sale_audit
  end

  def void_sales (void_by, reason, approval_code, request_by)
    #save sale_audit
    self.sale_status = "void"
  end

  #compute - invoice total
  def compute
    sales_items = self.sale_items

    #Computation Fields
    subtotal_price = 0
    total_taxable = 0
    rounding_adjustment = 0

    sales_items.each do |item|
      #compute each item and added to total
      puts "item.sales_item_id ddd"
      puts item.sale_item_id
      subtotal_price = subtotal_price + item.price

      # only calc tax when true
      if(item.is_taxable)
        total_taxable = total_taxable + item.taxable_price
      end
      # total_taxable = total_taxable + (item.taxable_price * item.qty)
    end

    apply_tax (total_taxable)

    self.total_amount = subtotal_price
    self.total_discount = total_discount
    self.grand_total = (self.total_amount - self.total_discount) + self.total_tax
    #compute rounding adjustment
    adjust_rounding

    self.save!

  end

  #compute - invoice total
  def compute_by_sale_items(sale_id, sale_itemss, total_discount,discount_type=nil)
    sale = Sale.find(sale_id)
    sales_items = sale_itemss

    #Computation Fields
    subtotal_price = 0
    total_taxable = 0
    rounding_adjustment = 0

    sales_items.each do |item|
      #compute each item and added to total
      subtotal_price = subtotal_price + item.price

      # check for item is taxable and calculate
      if item.is_taxable
        total_taxable = total_taxable + item.taxable_price
      end
    end

    compute_tax(sale, total_taxable, total_discount)
    sale.total_amount = subtotal_price
    sale.total_discount = total_discount
    sale.grand_total = (sale.total_amount - sale.total_discount) + sale.total_tax
    if discount_type == "member_discount"
      sale.discount_type = discount_type
    end
    #compute rounding adjustment
    # adjust_rounding
    sale.save!

  end

  # No Use too many wrong
  def compute_without_void
    sales_items = self.sale_items

    #Computation Fields
    subtotal_price = 0
    total_taxable = 0
    rounding_adjustment = 0

    sales_items.each do |item|
      if item.remark != 'void' && item.remark != 'foc'
        #compute each item and added to total
        subtotal_price = subtotal_price + item.price

        # only calc tax when true
        if(item.is_taxable)
          total_taxable = total_taxable + item.taxable_price
        end
      end
    end

    apply_tax (total_taxable)
    self.total_amount = subtotal_price
    self.total_discount = total_discount
    self.grand_total = (self.total_amount - self.total_discount) + self.total_tax
    #compute rounding adjustment
    adjust_rounding

    self.save!
  end

  # Tax Re-Calculte
  def compute_tax(sale, total_taxable, total_discount = 0)
    shop = Shop.first();

    #if tax is not apply create new record
    SaleTax.where("sale_id='#{sale.sale_id}'").find_each do |existing_tax|
      #delete existing and create new
      existing_tax.delete
    end

    total_tax_amount = 0
    #tax_profile - list by order_by
    tax_profiles = TaxProfile.all.order("order_by asc")
    customer = Customer.find(sale.customer_id)
    # #Creat new tax records
    tax_profiles.each do |tax|
      customer.tax_profiles.each do |cus_tax|
        if cus_tax.to_i == tax.id
          sale_tax = SaleTax.new(:sale => sale)
          sale_tax.tax_name = tax.name
          sale_tax.tax_rate = tax.rate

          # substract , to give after discount
          total_tax = total_taxable - total_discount
          #include or execulive
          if tax.inclusive
            rate = tax.rate
            divided_value = (100 + rate)/rate
            sale_tax.tax_payable_amount = total_tax / divided_value
          else
            sale_tax.tax_payable_amount = total_tax  * tax.rate / 100
            total_tax_amount = total_tax_amount + sale_tax.tax_payable_amount
          end
          #new taxable amount is standard rule for step by step
          if shop.calc_tax_order
            total_taxable = total_taxable + sale_tax.tax_payable_amount
          end

          sale_tax.inclusive = tax.inclusive
          sale_tax.save
        end
      end
    end

    sale.total_tax = total_tax_amount
  end

  # Tax Calculate
  def apply_tax(total_taxable)
    shop = Shop.first();
    
    #if tax is not apply create new record
    SaleTax.where("sale_id='#{self.sale_id}'").find_each do |existing_tax|
      #delete existing and create new
      existing_tax.delete
    end

    total_tax_amount = 0
    #tax_profile - list by order_by
    tax_profiles = TaxProfile.all.order("order_by asc")

    customer = Customer.find(self.customer_id)
    
    #Create new tax records
    tax_profiles.each do |tax|
      customer.tax_profiles.each do |cus_tax|
        if cus_tax.to_i == tax.id
          sale_tax = SaleTax.new(:sale => self)
          sale_tax.tax_name = tax.name
          sale_tax.tax_rate = tax.rate

          # substract , to give after discount
          total_tax = total_taxable - self.total_discount
          #include or execulive
          if tax.inclusive
            rate = tax.rate
            divided_value = (100 + rate)/rate
            sale_tax.tax_payable_amount = total_tax / divided_value
          else
            sale_tax.tax_payable_amount = total_tax  * tax.rate / 100
            total_tax_amount = total_tax_amount + sale_tax.tax_payable_amount
          end

          #new taxable amount is standard rule for step by step
          if shop.calc_tax_order
            total_taxable = total_taxable + sale_tax.tax_payable_amount
          end

          sale_tax.inclusive = tax.inclusive
          sale_tax.save
        end
      end
    end
      self.total_tax = total_tax_amount
  end

  def product_get_unit_price(item_code)
    menu_item_hash =MenuItem.search_by_item_code(item_code)
    if (menu_instance_code)
        return menu_  item_hash[:item_instance_code], menu_item_hash[:price]
    end
      return nil,nil
  end

  def link_order_sale(order_id)
    #create if it doesn't exist
    saleOrder = SaleOrder.where("sale_id=? and order_id=?", self.id, order_id).take

    if saleOrder.nil?
      sale_order = SaleOrder.new
      sale = sale_order.create_sale_order(self.id, order_id)
    end
    # if (SaleOrder.where("sale_id = #{self.id} and order_id=#{order_id}").nil?)
    #   SaleOrder.create(:sale_id => self.id, :order_id => order_id)
    # end
    #dosomrting here
    #puts Time.now.format(":short")
  end

  def adjust_rounding
    self.grand_total
    self.rounding_adjustment = 0.00
  end

  #Generate new Receipt No when it is not assigned
  def generate_receipt_no
    #Date-Shift-
    if self.receipt_no.nil?
      prefix = DateTime.now().utc
      #self.receipt_no = prefix.to_s + "/" + self.shit_id.to_s + "/" + SeedGenerator.new_receipt_no().to_s
      self.receipt_no = prefix.strftime("%Y%m%d") + "-" + SeedGenerator.new_receipt_no().to_s

      self.receipt_date = prefix
      Rails.logger.debug "Receipt No #{self.receipt_no} | Date #{ self.receipt_date.to_s}"
    end
  end

  def self.search(filter,from,to)
    if filter.blank?
        keyword = ''
    else
        keyword = "receipt_no LIKE ? OR cashier_name LIKE ? OR sale_status ='#{filter}'","%#{filter}%","%#{filter}%"
    end

    if from.present? && to.present?
       sale = Sale.where("DATE_FORMAT(receipt_date,'%d-%m-%Y') >= ?" + " AND DATE_FORMAT(receipt_date,'%d-%m-%Y') <= ? and NOT sale_status = 'void' ", from,to)
       query = sale.where(keyword)
    else
        where("receipt_no LIKE ? OR cashier_name LIKE ? OR sale_status ='#{filter}'","%#{filter}%","%#{filter}%")
    end

  end

  def self.search_credit_sales(customer,filter,from,to)
    if filter.blank?
        keyword = ''
    else
        keyword = "and receipt_no LIKE ? OR cashier_name LIKE ? OR sale_status ='#{filter}'","%#{filter}%","%#{filter}%"
    end

    if customer.blank?
        custo = ''
    else
        custo = "and customer_id = '#{customer}'"
    end

    if from.present? && to.present?
       sale = Sale.all.joins("JOIN sale_payments sp on sp.sale_id = sales.sale_id")
              .where("DATE_FORMAT(receipt_date,'%d-%m-%Y') >= ?" + " AND DATE_FORMAT(receipt_date,'%d-%m-%Y') <= ? and sp.payment_method = 'creditnote'  #{keyword} #{custo}", from,to)
    else
      sale = Sale.all.joins("JOIN sale_payments sp on sp.sale_id = sales.sale_id")
            .where("sp.payment_method ='creditnote' #{keyword} #{custo}")
    end
  end

  def self.get_rounding_adjustment(num)
    ## 0 -- 25 -- 50 -- 75 -- 100
    # if get_rounded_amt == true
      value = 0

      num = num.to_f.round
      get_last_no = num.to_s.last(2).to_f
      if get_last_no.between?(0,25)
        ## down to 0
        num -= get_last_no
      else
         if get_last_no.between?(26,50)
           ## up to 50
           value = 50 - get_last_no.to_f
           num += value
           puts 'up to 50'
         else
           if get_last_no.between?(51, 75)
             ## down to 50
             value = get_last_no.to_f - 50
             num -= value
             puts 'down to 50'
           else
             ## up to 100
             value = 100 - get_last_no.to_f
             num += value
             puts 'up to 100'
           end
         end
      end
    # end
    return num
  end


def self.daily_sales_list(from,to)
    payments_total = Sale.select("CAST((CONVERT_TZ(sales.receipt_date,'+00:00','+06:30')) AS DATE) as sale_date,
     SUM(case when (sale_payments.payment_method='mpu') then sale_payments.payment_amount else 0 end) as mpu_amount,
     SUM(case when (sale_payments.payment_method='master') then sale_payments.payment_amount else 0 end) as master_amount,
     SUM(case when (sale_payments.payment_method='visa') then sale_payments.payment_amount else 0 end) as visa_amount,
     SUM(case when (sale_payments.payment_method='jcb') then sale_payments.payment_amount else 0 end) as jcb_amount,
     SUM(case when (sale_payments.payment_method='paypar') then sale_payments.payment_amount else 0 end) as paypar_amount,
     SUM(case when (sale_payments.payment_method='cash') then sale_payments.payment_amount else 0 end) as cash_amount,
     SUM(case when (sale_payments.payment_method='creditnote') then sale_payments.payment_amount else 0 end) as credit_amount,
     SUM(case when (sale_payments.payment_method='foc') then sale_payments.payment_amount else 0 end) as foc_amount")
  .joins("join (select * from sale_payments group by sale_payments.sale_id, sale_payments.payment_method) sale_payments on sale_payments.sale_id = sales.sale_id")
  .where("sale_status = ? AND sales.receipt_date between ? and ? ", 'completed', from, to)
  .group("DATE_FORMAT((CONVERT_TZ(sales.receipt_date,'+00:00','+06:30')),'%Y-%m-%d')")

    daily_total = Array.new

    payments_total.each do |pay|
      sale_date = pay.sale_date
      diff_time = payments_total.first.sale_date.beginning_of_day.utc - from
      diff = diff_time % 86400
      from_date = sale_date.beginning_of_day.utc - diff
      to_date = sale_date.end_of_day.utc - diff

      total_sale = Sale.select("IFNULL(SUM(case when (sale_status='completed') then grand_total else 0 end),0) as grand_total,
                                IFNULL(SUM(case when (sale_status='completed') then old_grand_total else 0 end),0) as old_grand_total,
                                IFNULL(SUM(case when (sale_status='completed') then total_discount else 0 end),0) as total_discount,
                                IFNULL(SUM(case when (sale_status='completed') then amount_changed else 0 end),0) as total_change_amount,
                                IFNULL(SUM(case when (sale_status='void') then grand_total else 0 end),0) as void_amount,
                                IFNULL(SUM(case when (sale_status='completed') then rounding_adjustment else 0 end),0) as rounding_adj")
                            .where("(sale_status = ? OR sale_status = ?) AND receipt_date between ? and ? AND total_amount != 0", 'completed', 'void', from_date, to_date)

      total_sale.each do |sale|
        grand_total = sale.grand_total
        old_grand_total = sale.old_grand_total
        total_discount = sale.total_discount
        void_amount = sale.void_amount
        total_change_amount = sale.total_change_amount
        total = {:sale_date => pay.sale_date,
                 :mpu_amount => pay.mpu_amount,
                 :master_amount => pay.master_amount,
                 :visa_amount => pay.visa_amount,
                 :jcb_amount => pay.jcb_amount,
                 :paypar_amount => pay.paypar_amount,
                 :cash_amount => pay.cash_amount,
                 :credit_amount => pay.credit_amount,
                 :foc_amount => pay.foc_amount,
                 :total_discount => total_discount,
                 :total_change_amount => total_change_amount,
                 :grand_total => grand_total,
                 :old_grand_total => old_grand_total,
                 :void_amount => void_amount,
                 :rounding_adj => sale.rounding_adj}
        daily_total.push(total)
      end

    end
    return daily_total
end

def self.get_by_range_by_saleitems(from,to,status,report_type)
  query = Sale.select("
                      mi.item_code as code,(SUM(i.qty) * i.unit_price) as grand_total,
                      SUM(i.qty) as total_item," +
                       " i.unit_price as unit_price,
                       mi.name as product_name,
                       mc.name as menu_category_name,
                       mc.id as menu_category_id ")
                      .group('mi.id')
                      .order("mi.menu_category_id")

  query = query.joins("JOIN sale_items i ON i.sale_id = sales.sale_id
                        JOIN menu_items mi ON i.product_code = mi.item_code" +
                        " JOIN menu_categories mc ON mc.id = mi.menu_category_id
                        JOIN employees ea ON ea.id = sales.cashier_id")


  query = query.where("(receipt_date between ? and ? and sale_status=?) AND i.unit_price <> 0",from,to,status)
end

def self.get_by_shiftsales(from,to,shift)
  if !shift.blank?
    query = ShiftSale.where("shift_sales.id =?",shift.id)
  else
    query = ShiftSale.where("(shift_started_at between ? and ? OR shift_closed_at between ? and ? )", from, to, from, to)
  end

  shift_sale_data = Hash.new

  query.each do |shift_sale|
    foc = 0
    foc_data = Sale.select("SUM(sp.payment_amount) as foc_sales")
              .joins("JOIN sale_payments as sp on sp.sale_id=sales.sale_id")
              .where("sales.shift_sale_id=? and sp.payment_method='foc'",shift_sale.id)
              .first()
    
    if !foc_data.foc_sales.nil? && foc_data.foc_sales > 0
      shift_sale.other_sales -= foc_data.foc_sales
      foc = foc_data.foc_sales
    end

    shift_sale_data[shift_sale.id] = {
      :cashier_terminal_name => shift_sale.cashier_terminal.name,
      :employee_name => shift_sale.employee.name,
      :shift_started_at => shift_sale.shift_started_at,
      :shift_closed_at => shift_sale.shift_closed_at,
      :cash_sales => shift_sale.cash_sales,
      :credit_sales => shift_sale.credit_sales,
      :other_sales => shift_sale.other_sales.to_f,
      :foc_sales => foc,
      :grand_total => shift_sale.grand_total
    }
  end

  return shift_sale_data.values
end

def self.get_by_shift_sale(from,to,status)
  query = ShiftSale.select("shift_sales.id ,shift_started_at AS opening_date,
                          shift_closed_at As closing_date," +
                          " grand_total AS grand_total, cash_sales AS cash," +
                          "total_taxes AS total_tax,total_discounts As total_discount")
                          .order("shift_sales.id DESC")
  return query = query.where("shift_sales.shift_started_at >= ?" + " AND shift_sales.shift_closed_at <= ?", from,to)
end

def self.get_item_query()
  query = Sale.select("acc.title as account_name,mi.account_id, i.item_instance_code as item_code,i.account_id as account_id, " +
                     "SUM(i.qty * i.unit_price) as grand_total,SUM(i.qty) as total_item,i.qty as qty," +
                     "i.remark as status_type,"+
                     " i.unit_price as unit_price,i.product_name as product_name, mc.name as" +
                     " menu_category_name,mc.id as menu_category_id ")

  query = query.joins("JOIN sale_items i ON i.sale_id = sales.sale_id" + 
                     " JOIN menu_item_instances mii ON i.item_instance_code = mii.item_instance_code" +
                     " JOIN menu_items mi ON mi.id = mii.menu_item_id" +
                     " JOIN shift_sales sh ON sh.`id` = sales.shift_sale_id" + 
                     " JOIN menu_categories mc ON mc.id = mi.menu_category_id ")
                     # "JOIN employee_accesses ea ON ea.`employee_id` = sales.cashier_id ")
  query = query.joins(" JOIN accounts acc ON acc.id = mi.account_id")
  # query = query.where("i.item_instance_code IS NOT NULL")
  query = query.group("i.product_name").order("mi.account_id desc")
end

def self.get_other_charges()
  query = Sale.select("i.account_id as account_id, " +
                     "SUM(i.qty * i.unit_price) as grand_total,SUM(i.qty) as total_item," +
                     "i.remark as status_type,"+
                     " i.unit_price as unit_price,i.product_name as product_name")
  query = query.joins("JOIN sale_items i ON i.sale_id = sales.sale_id")
  query = query.where("i.item_instance_code IS NULL AND i.product_code = 'Other Charges'")
  query = query.group("i.sale_item_id")
end

def self.get_by_shift_items(shift_sale_range, shift, from, to, status)
  # date_type_selection = get_sql_function_for_report_type(report_type)

  query = self.get_item_query()

  discount_query = 0
  total_card_amount = 0
  total_cash_amount = 0
  total_credit_amount = 0
  total_foc_amount = 0
  total_grand_total = 0

  other_charges = self.get_other_charges()

  if shift.present?
      query          = query.where("sales.shift_sale_id IN (?) and sale_status='completed'",shift.to_a)
      other_charges  = other_charges.where("sales.shift_sale_id IN (?) and sale_status='completed'",shift.to_a)
      discount_query = Sale.where("sales.shift_sale_id in (?) and sale_status= 'completed' ", shift.to_a).sum(:total_discount)
      change_amount  = Sale.where("sales.shift_sale_id in (?) and sale_status= 'completed' ", shift.to_a).sum(:amount_changed)
      sale_cash      = Sale.select("SUM(case when (sale_payments.payment_method ='mpu' or sale_payments.payment_method = 'visa' or sale_payments.payment_method = 'master' or sale_payments.payment_method = 'jcb' or sale_payments.payment_method = 'paypar') then (sale_payments.payment_amount) else 0 end) as card_amount,
                                    SUM(case when (sale_payments.payment_method='cash') then (sale_payments.payment_amount) else 0 end) as cash_amount,
                                    SUM(case when (sale_payments.payment_method='creditnote') then (sale_payments.payment_amount) else 0 end) as credit_amount,
                                    SUM(case when (sale_payments.payment_method='foc') then (sale_payments.payment_amount) else 0 end) as foc_amount")
                                   .joins("join sale_payments on sale_payments.sale_id = sales.sale_id")
                                   .where("sales.shift_sale_id in (?) and sale_status = 'completed' and sale_payments.payment_amount != 0 ", shift.to_a)
      sale_cash.each do |s_c|
        total_cash_amount += s_c.cash_amount.to_f
        total_card_amount += s_c.card_amount.to_f
        total_credit_amount += s_c.credit_amount.to_f
        total_foc_amount += s_c.foc_amount.to_f
      end
      total_grand_total = total_cash_amount.to_f + total_card_amount.to_f + total_credit_amount.to_f

      ### => get all sales range in shift_sales
  elsif shift_sale_range.present?
      query          = query.where("sales.shift_sale_id IN (?) and sale_status='completed'",shift_sale_range.to_a)
      other_charges  = other_charges.where("sales.shift_sale_id IN (?) and sale_status='completed'",shift_sale_range.to_a)
      discount_query = Sale.where("sales.shift_sale_id IN (?) and sale_status ='completed'", shift_sale_range.to_a).sum(:total_discount)
      change_amount  = Sale.where("sales.shift_sale_id IN (?) and sale_status ='completed'", shift_sale_range.to_a).sum(:amount_changed)
      sale_cash      = Sale.select("SUM(case when (sale_payments.payment_method = 'mpu' or sale_payments.payment_method = 'visa' or sale_payments.payment_method = 'master' or sale_payments.payment_method = 'jcb' or sale_payments.payment_method = 'paypar') then (sale_payments.payment_amount) else 0 end) as card_amount,
                                    SUM(case when (sale_payments.payment_method='cash') then (sale_payments.payment_amount) else 0 end) as cash_amount,
                                    SUM(case when (sale_payments.payment_method='creditnote') then (sale_payments.payment_amount) else 0 end) as credit_amount,
                                    SUM(case when (sale_payments.payment_method='foc') then (sale_payments.payment_amount) else 0 end) as foc_amount")
                                   .joins("join sale_payments on sale_payments.sale_id = sales.sale_id")
                                   .where("sales.shift_sale_id in (?) and sale_status = 'completed' and sale_payments.payment_amount != 0 ", shift_sale_range.to_a)
      sale_cash.each do |s_c|
        total_cash_amount += s_c.cash_amount.to_f
        total_card_amount += s_c.card_amount.to_f
        total_credit_amount += s_c.credit_amount.to_f
        total_foc_amount += s_c.foc_amount.to_f
      end

      total_grand_total = total_cash_amount.to_f + total_card_amount.to_f + total_credit_amount.to_f

  else
      query          = query.where("sales.receipt_date between ? and ? and sale_status='completed'",from,to)
      other_charges  = other_charges.where("sales.receipt_date between ? and ? and sale_status='completed'",from,to)
      discount_query = Sale.where("sales.receipt_date between ? and ? and sale_status ='completed'", from,to).sum(:total_discount)
      change_amount  = Sale.where("sales.receipt_date between ? and ? and sale_status ='completed'", from,to).sum(:amount_changed)
      sale_cash      = Sale.select("SUM(case when (sale_payments.payment_method = 'mpu' or sale_payments.payment_method = 'visa' or sale_payments.payment_method = 'master' or sale_payments.payment_method = 'jcb' or sale_payments.payment_method = 'paypar') then (sale_payments.payment_amount) else 0 end) as card_amount,
                                    SUM(case when (sale_payments.payment_method='cash') then (sale_payments.payment_amount) else 0 end) as cash_amount,
                                    SUM(case when (sale_payments.payment_method='creditnote') then (sale_payments.payment_amount) else 0 end) as credit_amount,
                                    SUM(case when (sale_payments.payment_method='foc') then (sale_payments.payment_amount) else 0 end) as foc_amount")
                                   .joins("join sale_payments on sale_payments.sale_id = sales.sale_id")
                                   .where("sales.receipt_date between ? and ? and sale_status = 'completed' and sale_payments.payment_amount != 0 ", from,to)
      sale_cash.each do |s_c|
        total_cash_amount += s_c.cash_amount.to_f
        total_card_amount += s_c.card_amount.to_f
        total_credit_amount += s_c.credit_amount.to_f
        total_foc_amount += s_c.foc_amount.to_f
      end
      total_grand_total = total_cash_amount.to_f + total_card_amount.to_f + total_credit_amount.to_f

  end

  return query,other_charges, discount_query , total_cash_amount , total_card_amount , total_credit_amount , total_foc_amount , total_grand_total , change_amount
end

def self.get_shift_sales_by_receipt_no(shift_sale_range,shift,from,to,payment_type)
    ## => left join -> show all sales although no orders
    if payment_type.blank?
      payment_type = ''
    else
      if payment_type == 'card'
        payment_type = " and sale_payments.payment_method = 'mpu' or sale_payments.payment_method = 'visa' or sale_payments.payment_method = 'master' or sale_payments.payment_method = 'jcb' or sale_payments.payment_method = 'paypar'"
      else
        payment_type = " and sale_payments.payment_method = '#{payment_type}'"
      end
    end

    query = Sale.all
    if shift.present?
      query = query.where("sales.shift_sale_id in (?) #{payment_type} and sale_status= 'completed' and sales.payment_status= 'paid' and sale_payments.payment_amount != 0", shift.to_a)
              .joins("join sale_payments on sale_payments.sale_id = sales.sale_id")
              .group("sales.sale_id")
    elsif shift_sale_range.present?
      query = query.where("sale_status='completed' #{payment_type} and sale_payments.payment_amount != 0 and sales.payment_status= 'paid' and sales.shift_sale_id in (?)",shift_sale_range.to_a)
              .joins("join sale_payments on sale_payments.sale_id = sales.sale_id")
              .group("sales.sale_id")
    else
      query = query.where("sale_status='completed' and sales.receipt_date between ? and ? #{payment_type} and sales.payment_status= 'paid' and sale_payments.payment_amount != 0",from,to)
              .joins("join sale_payments on sale_payments.sale_id = sales.sale_id")
              .group("sales.sale_id")
    end
    return query
end

def self.get_by_shift_sale_credit_payment(shift_sale_range,shift,from,to)
    query = SalePayment.select("s.receipt_no, sale_payments.*,s.receipt_date as sale_date,
                                s.cashier_name as cashier_name")
                      .joins("INNER JOIN sales s ON s.sale_id = sale_payments.sale_id")

    if shift.present?
      query = query.where("payment_method= 'creditnote' and s.sale_status = 'completed' and s.shift_sale_id in (?)",shift.to_a)
    elsif shift_sale_range.present?
      query = query.where("payment_method='creditnote' and s.sale_status = 'completed'  and s.shift_sale_id in (?)",shift_sale_range.to_a)
    else
      query = query.where("payment_method='creditnote' and s.sale_status = 'completed' and s.receipt_date between ? and ? ",from,to)
    end
end

 def self.get_void_sale(shift,from,to)
     sale_arr = Array.new

     query = Sale.select("sales.receipt_no,sales.receipt_date, sales.payment_status, sales.sale_status,sales.total_amount,sales.grand_total, sales.rounding_adjustment")
                         # .joins("INNER JOIN shift_sales sh ON sh.id = sales.shift_sale_id")
                         # .where("sales.sale_status = 'void' and (sh.shift_started_at between ? and ?
                         #  OR sh.shift_closed_at between ? and ? )", from ,to, from, to)

    if shift.present?
      query = query.where("sales.sale_status = 'void' and sales.shift_sale_id in (?)",shift.to_a)
    else
      query = query.where("sales.sale_status = 'void' and sales.receipt_date between ? and ? ",from,to)
    end

     out = {:items => query}
     sale_arr.push(out)
     return sale_arr
end

def self.get_separate_tax(shift_sale_range=nil,shift,from,to,payment_type)

# wrong amount tax for service and commercial tax 

  # if payment_type.blank?
  #   payment_type = ''
  # else
  #   if payment_type == 'card'
  #     payment_type = " and sale_payments.payment_method = 'mpu' or sale_payments.payment_method = 'visa' or sale_payments.payment_method = 'master' or sale_payments.payment_method = 'jcb' or sale_payments.payment_method = 'paypar'"
  #   else
  #     payment_type = " and sale_payments.payment_method = '#{payment_type}'"
  #   end
  # end

  if shift.present?
    query = SaleTax.select("SUM(tax_payable_amount) AS st_amount,tax_name")
           .joins("LEFT JOIN sales ON sales.sale_id = sale_taxes.sale_id")
           .where("sales.shift_sale_id in (?) and sale_status= 'completed'", shift.to_a)
           .group("sale_taxes.tax_name")
           .order("sale_taxes.tax_name desc")
  elsif shift_sale_range.present?
    query = SaleTax.select("SUM(tax_payable_amount) AS st_amount,tax_name")
           .joins("LEFT JOIN sales ON sales.sale_id = sale_taxes.sale_id")
           .where("sales.shift_sale_id in (?) and sale_status= 'completed'", shift_sale_range.to_a)
           .group("sale_taxes.tax_name")
           .order("sale_taxes.tax_name desc")
  else
    query = SaleTax.select("SUM(tax_payable_amount) AS st_amount,tax_name")
           .joins("LEFT JOIN sales ON sales.sale_id = sale_taxes.sale_id")
           .where("sales.receipt_date between ? and ? and sale_status= 'completed'", from,to)
           .group("sale_taxes.tax_name")
           .order("sale_taxes.tax_name desc")
  end
end

def self.get_payment_method_by_shift(shift_sale_range,shift,from,to,payment_type)
    
    sale_payment   = SalePayment.select("s.amount_changed as change_amount,s.receipt_no, sale_payments.*,s.receipt_date as sale_date,
                                s.cashier_name as cashier_name")
                      .joins("INNER JOIN sales s ON s.sale_id = sale_payments.sale_id")
                      .order('s.receipt_no DESC')

    payments_total = SalePayment.select("CAST((CONVERT_TZ(sales.receipt_date,'+00:00','+06:30')) AS DATE) as sale_date,
                       SUM(case when (sale_payments.payment_method='mpu') then sale_payments.payment_amount else 0 end) as mpu_amount,
                       SUM(case when (sale_payments.payment_method='master') then sale_payments.payment_amount else 0 end) as master_amount,
                       SUM(case when (sale_payments.payment_method='visa') then sale_payments.payment_amount else 0 end) as visa_amount,
                       SUM(case when (sale_payments.payment_method='jcb') then sale_payments.payment_amount else 0 end) as jcb_amount,
                       SUM(case when (sale_payments.payment_method='paypar') then sale_payments.payment_amount else 0 end) as paypar_amount,
                       SUM(case when (sale_payments.payment_method='cash') then sale_payments.payment_amount else 0 end) as cash_amount,
                       SUM(case when (sale_payments.payment_method='cash') then sales.amount_changed else 0 end) as total_change_amount,
                      SUM(case when (sale_payments.payment_method='creditnote') then sale_payments.payment_amount else 0 end) as credit_amount,
                      SUM(case when (sale_payments.payment_method='foc') then sale_payments.payment_amount else 0 end) as foc_amount")
                    .joins("join sales on sales.sale_id = sale_payments.sale_id")            

    if shift.present?

      all_total = payments_total.where("sales.shift_sale_id in (?) and sale_status= 'completed' and sale_payments.payment_amount != 0", shift.to_a)
                # .group("DATE_FORMAT((CONVERT_TZ(sales.receipt_date,'+00:00','+06:30')),'%Y-%m-%d')")
      if payment_type.blank?
        sale_type = sale_payment.where("s.sale_status = 'completed' and payment_amount != 0 and s.shift_sale_id in (?)",shift.to_a)
         .order("payment_method")                       
      else
        sale_type = sale_payment.where("payment_method= '#{payment_type}' and payment_amount != 0 and s.sale_status = 'completed' and s.shift_sale_id in (?)",shift.to_a)
      end

    elsif shift_sale_range.present?

      all_total = payments_total.where("sales.shift_sale_id in (?) and sale_status= 'completed' and sale_payments.payment_amount != 0", shift_sale_range.to_a)
                  # .group("DATE_FORMAT((CONVERT_TZ(sales.receipt_date,'+00:00','+06:30')),'%Y-%m-%d')")
      if payment_type.blank?
        sale_type = sale_payment.where("s.sale_status = 'completed' and payment_amount != 0 and s.shift_sale_id in (?)",shift_sale_range.to_a)
          .order("payment_method")                      
      else
        sale_type = sale_payment.where("payment_method='#{payment_type}' and payment_amount != 0 and s.sale_status = 'completed'  and s.shift_sale_id in (?)",shift_sale_range.to_a)
      end
      
    else

      all_total = payments_total.where("sales.receipt_date between ? and ? and sales.sale_status= 'completed' and sale_payments.payment_amount != 0", from,to)
             # .group("DATE_FORMAT((CONVERT_TZ(sales.receipt_date,'+00:00','+06:30')),'%Y-%m-%d')")
      if payment_type.blank?
        sale_type = sale_payment.where("s.sale_status = 'completed' and payment_amount != 0 and s.receipt_date between ? and ? ",from,to)
          .order("payment_method")                     
      else
        sale_type = sale_payment.where("payment_method='#{payment_type}' and payment_amount != 0 and s.sale_status = 'completed' and s.receipt_date between ? and ? ",from,to)         
      end
    end

    return all_total,sale_type
end

# def self.get_separate_tax(from,to,payment_method=nil)

#     query = SaleTax.select("SUM(tax_payable_amount) AS st_amount,tax_name")
#                   .joins("INNER JOIN sales ON sales.sale_id = sale_taxes.sale_id")
#                   .group("sale_taxes.tax_name")

#       return query = query.where("sale_status=? and receipt_date between ? and ?","completed",from,to)
# end

def grand_total_after_rounding
    return self.grand_total.to_f + self.rounding_adjustment.to_f
end

  def get_cash_amount
    cash = 0.0
    self.sale_payments.each do |pay|
        if pay.payment_method == 'cash'
          cash = pay.payment_amount-self.amount_changed
        end
    end
    return cash
  end

  def get_credit_amount
    credit = 0.0
    self.sale_payments.each do |pay|
        if pay.payment_method == 'creditnote'
           credit = pay.payment_amount
        end
    end
    return credit
  end

  def get_other_amount
    other = 0.0
    self.sale_payments.each do |pay|
        if pay.payment_method != 'cash' && pay.payment_method != 'creditnote'
          other += pay.payment_amount
        end
    end
    return other
  end

  def get_commerical_tax
    tax = 0.0
     self.sale_taxes.each do |taxobj|
        if taxobj.tax_name == "Commercial Tax"
           tax += taxobj.tax_payable_amount
        end
     end
     return tax
  end

  def self.top_products(today)
    query = Sale.select("(SUM(i.qty) * i.price) as grand_total,SUM(i.qty) as total_item," +
                        " i.price as unit_price,mi.name as product_name")
                .joins("JOIN sale_items i ON i.sale_id = sales.sale_id JOIN menu_items mi ON i.product_code = mi.item_code")
                .where("(i.qty > 0 and i.price > 0) and DATE_FORMAT(receipt_date,'%Y-%m-%d') = '#{today}'"+
                      "and payment_status='paid' and sale_status= 'completed'")
                .group('mi.name')
                .order("SUM(i.qty) DESC").limit(10)
  end

  def self.bottom_products(today)
    query = Sale.select("(SUM(i.qty) * i.price) as grand_total,SUM(i.qty) as total_item," +
                        " i.price as unit_price,mi.name as product_name")
                .joins("JOIN sale_items i ON i.sale_id = sales.sale_id JOIN menu_items mi ON i.product_code = mi.item_code")
                .where("(i.qty > 0 and i.price > 0) and DATE_FORMAT(receipt_date,'%Y-%m-%d') = '#{today}'"+
                      "and payment_status='paid' and sale_status= 'completed'")
                .group('mi.name')
                .order("SUM(i.qty) ASC").limit(10)
  end

  def self.hourly_sales(today)
    query= Sale.select("grand_total")
            .where('payment_status="paid" and sale_status = "completed" and DATE_FORMAT(receipt_date,"%Y-%m-%d") = ?',today)
            .group("date_format(CONVERT_TZ(receipt_date,'+00:00', 'SYSTEM'), '%I %p')")
            .order('receipt_date')
  end

  def self.employee_sales(today)
    query = Sale.joins("JOIN employees as e on e.id=sales.cashier_id")
                .joins("JOIN sale_payments as sp on sp.sale_id=sales.sale_id")
                .where("sales.payment_status='paid' and sales.sale_status = 'completed' and DATE_FORMAT(sales.receipt_date,'%Y-%m-%d') = '#{today}'")
                .group("(CASE WHEN (sp.payment_method='mpu' or sp.payment_method='visa' or sp.payment_method='master' or sp.payment_method='jcb') THEN 'card' ELSE sp.payment_method END)","e.name")
                .order("e.name")
  end

  def self.total_sale(today)
  total = Sale.where('sale_status = "completed" and DATE_FORMAT(receipt_date,"%Y-%m-%d") = ?',today).sum("grand_total")

  end

  def self.total_count(today)
  total = Sale.where('sale_status = "completed" and DATE_FORMAT(receipt_date,"%Y-%m-%d") = ?',today).count
  end

  def self.total_card_sale(today)
    payment_type = " and payment_method = 'mpu' or payment_method = 'visa' or payment_method = 'master' or payment_method = 'jcb' "
    # query        = Sale.select("SUM(tax_payable_amount) AS st_amount,tax_name")
    #                 .where('sale_status = "completed" #{payment_type} and DATE_FORMAT(receipt_date,"%Y-%m-%d") = ?',today)
    #                 .joins("join sale_payments on sale_id = sales.sale_id")
    #                 .group("sales.sale_id")

    query = Sale.where('sales.sale_status = "completed" and DATE_FORMAT(sales.receipt_date,"%Y-%m-%d") = ? and (sp.payment_method = "mpu" or sp.payment_method = "visa" or sp.payment_method = "master" or sp.payment_method = "jcb")',today)
            .joins("JOIN sale_payments sp ON sp.sale_id = sales.sale_id")
            .sum("sp.payment_amount")

  end

  def self.credit_payment(today)
    query = SalePayment.where('s.sale_status = "completed" and payment_method="creditnote" and DATE_FORMAT(s.receipt_date,"%Y-%m-%d") = ?',today)
            .joins("INNER JOIN sales s ON s.sale_id = sale_payments.sale_id")
            .sum("payment_amount")
  end

  def self.summary_sale_receipt(today)
    query = Sale.select('count(sale_id) as total_receipt, (case when sum(total_amount) > 0 then sum(total_amount) else 0.0 end) as total_amount, (case when sum(grand_total) > 0 then sum(grand_total) else 0.0 end) as grand_total, (case when sum(total_discount) > 0 then sum(total_discount) else 0.0 end) as total_discount, (case when sum(total_tax) > 0 then sum(total_tax) else 0.0 end) as total_tax')
          .where('sale_status = "completed" and DATE_FORMAT(receipt_date,"%Y-%m-%d") = ?',today)
          .first()
  end

  def self.total_payment_methods(today)
    query = Sale.select("distinct sp.payment_method")
          .where('sales.sale_status = "completed" and DATE_FORMAT(sales.receipt_date,"%Y-%m-%d") = ?',today)
          .joins("JOIN sale_payments as sp ON sp.sale_id = sales.sale_id")
  end

  def self.payment_sale(payment_method, today)
    query = Sale.joins("JOIN sale_payments as sp ON sp.sale_id = sales.sale_id")
          if payment_method == 'card'
            query = query.where('sales.sale_status = "completed" and DATE_FORMAT(sales.receipt_date,"%Y-%m-%d") = ? and (sp.payment_method = "mpu" or sp.payment_method = "visa" or sp.payment_method = "master" or sp.payment_method = "jcb")',today)
          else
            query = query.where("sales.sale_status = 'completed' and sp.payment_method = '#{payment_method}' and DATE_FORMAT(sales.receipt_date,'%Y-%m-%d') = ?",today)
          end
          query.select("(CASE WHEN sp.payment_method='cash' THEN (SUM(sp.payment_amount) - SUM(sales.amount_changed)) ELSE SUM(sp.payment_amount) END) as payment_amount").first()
  end

  def self.total_customer(today)
    dinein_cnt = self.total_dinein(today)
    takeaway_cnt = self.total_takeaway(today)
    membership_cnt = self.total_membership(today)

    total_cus = 0
    if !dinein_cnt.nil? || !takeaway_cnt.nil? || !membership_cnt.nil?
      total_cus = dinein_cnt.total_dinein_cus.to_int + takeaway_cnt.total_take_cus.to_int + membership_cnt.total_memb_cus.to_int
    end

    return total_cus
  end

  def self.total_dinein(today)
    query = Sale.select("count(sales.customer_id) as total_dinein_cus")
          .joins("JOIN customers as c ON c.customer_id = sales.customer_id")
          .where('sales.sale_status = "completed" and DATE_FORMAT(sales.receipt_date,"%Y-%m-%d") = ? and c.customer_type = "Dinein" and c.membership_id is null',today)
          .first()
  end

  def self.total_takeaway(today)
    query = Sale.select("count(sales.customer_id) as total_take_cus")
          .joins("JOIN customers as c ON c.customer_id = sales.customer_id")
          .where('sales.sale_status = "completed" and DATE_FORMAT(sales.receipt_date,"%Y-%m-%d") = ? and c.customer_type = "Takeaway" and c.membership_id is null',today)
          .first()
  end

  def self.total_membership(today)
    query = Sale.select("count(distinct sales.customer_id) as total_memb_cus")
          .joins("JOIN customers as c ON c.customer_id = sales.customer_id")
          .where('sales.sale_status = "completed" and DATE_FORMAT(sales.receipt_date,"%Y-%m-%d") = ? and ((c.customer_type = "Dinein" and c.membership_id is not null) or (c.customer_type = "Takeaway" and c.membership_id is not null))',today)
          .first()
  end

  def self.total_other_customer(today)
    query = Sale.select("count(sales.customer_id) as total_cus")
          .joins("JOIN customers as c ON c.customer_id = sales.customer_id")
          .where('sales.sale_status = "completed" and DATE_FORMAT(sales.receipt_date,"%Y-%m-%d") = ? and c.customer_type is null and c.membership_id is null',today)
          .first()
  end

  def self.total_order(today)
    query = Sale.select("count(distinct a.order_id) as total_order")
          .joins("JOIN sale_orders as a ON a.sale_id = sales.sale_id")
          .joins("JOIN orders as b ON b.order_id = a.order_id")
          .where('b.status = "billed" and DATE_FORMAT(sales.receipt_date,"%Y-%m-%d") = ?',today)
          .first()
  end

  def self.total_account(today)
    query = Sale.select("distinct b.id as account_id, b.title as title")
          .joins("JOIN sale_items as a ON a.sale_id = sales.sale_id")
          .joins("JOIN accounts as b ON b.id = a.account_id")
          .where('sales.sale_status = "completed" and DATE_FORMAT(sales.receipt_date,"%Y-%m-%d") = ?',today)
  end

  def self.account_data(account_id, today)
    query = Sale.select("count(*) as cnt_acc, SUM(a.price) as total_acc")
          .joins("JOIN sale_items as a ON a.sale_id = sales.sale_id")
          .where("sales.sale_status = 'completed' and a.account_id ='#{account_id}' and DATE_FORMAT(sales.receipt_date,'%Y-%m-%d') = ?",today)
          .first()
  end

  def self.top_items(today)
    query = Sale.select("a.product_name as item_name, SUM(a.price) as item_total_price")
          .joins("JOIN sale_items as a ON a.sale_id = sales.sale_id")
          .where("(a.qty > 0 and a.price > 0) and payment_status='paid' and sales.sale_status = 'completed' and DATE_FORMAT(sales.receipt_date,'%Y-%m-%d') = ?",today)
          .group("a.product_code")
          .order("SUM(a.qty) DESC")
          .first()
  end

  def self.total_foc_items(today)
    query = Sale.joins("JOIN sale_items as a ON a.sale_id = sales.sale_id")
          .where("sales.sale_status = 'completed' and a.remark='foc' and a.product_name not like '%FOC%' and DATE_FORMAT(sales.receipt_date,'%Y-%m-%d') = ?",today)
          .sum("a.qty")
  end

  private

  def generate_custom_id
    self.sale_id = SeedGenerator.generate_id(self.class.name, "SAL")
  end
end
