class Sale < ApplicationRecord
  include NumberFormattable
  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, foreign_key: "cashier_id", class_name: "Employee"
  belongs_to :customer, :optional => true
  belongs_to :shift_sale
  has_one  :current_shift_by_cashier, through: :cashier, source: :current_shift
  has_one  :cashier_terminal_by_shift_sale, through: :shift_sale, source: :cashier_terminal
  has_one  :survey, foreign_key: "receipt_no"
  has_many :sale_audits
  has_many :sale_items
  has_many :sale_discount_items
  has_many :sale_discounts
  has_many :sale_taxes
  has_many :sale_payments
  has_many :payments_for_credits, through: :sale_audits
  has_many :sale_orders
  has_many :orders, through: :sale_orders
  has_many :order_items, through: :sale_orders
  has_many :bookings
  has_one  :booking
  has_many :product_commissions

  before_save :round_to_precision
  after_update :update_stock_journal

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

  scope :receipt_date_between, -> (from, to) { where(receipt_date: from..to) }
  scope :sale_payments_with_audit_except_void_between, -> (from, to) do
    joins(sanitize_sql_array(["LEFT JOIN sale_payments ON sales.sale_status != 'void' AND sale_payments.sale_id = sales.sale_id AND sale_payments.created_at BETWEEN ? and ?", from.utc, to.utc]))
    .joins("LEFT JOIN sale_audits ON sale_audits.sale_id = sale_payments.sale_id AND SUBSTRING_INDEX(sale_audits.remark,'||',1) = sale_payments.sale_payment_id")
  end

  def qty_of(item_instance_code)
    order_items.select(:order_items_id, :item_instance_code, 'SUM(qty) as qty').where(item_instance_code: item_instance_code).group(:item_instance_code).first
  end

  REPORT_TYPE = {
  "daily" => 0,
  "monthly" => 1,
  "yearly" => 2
  }
  SALE_STATUS_OUTSTANDING = "outstanding"
  SALE_STATUS_COMPLETED = "completed"
  def self.sync_sale_records(sales)
    if !sales.nil?
      sales.each do |s|
        sale = Sale.find_by_sale_id(s['sale_id'])
        # unless Sale.exists?(s['sale_id'])
        if sale.nil?
          sale = Sale.new
        end
        sale.sale_id = s['sale_id']
        sale.cashier_id = s['cashier_id']
        sale.cashier_name = s['cashier_name']
        sale.requested_by = s['requested_by']
        sale.requested_at = s['requested_at']
        sale.receipt_no = s['receipt_no']
        sale.receipt_date = s['receipt_date']
        sale.customer_id = s['customer_id']
        sale.payment_status = s['payment_status']
        sale.sale_status = s['sale_status']
        sale.total_amount = s['total_amount']
        sale.discount_type = s['discount_type']
        sale.total_tax = s['total_tax']
        sale.total_discount = s['total_discount']
        sale.tax_type = s['tax_type']
        sale.grand_total = s['grand_total']
        sale.rounding_adjustment = s['rounding_adjustment']
        sale.amount_received = s['amount_received']
        sale.amount_changed = s['amount_changed']
        sale.shift_sale_id = s['shift_sale_id']
        sale.old_grand_total = s['old_grand_total']
        sale.rebate_status = s['rebate_status']
        sale.equal_persons = s['equal_persons']
        sale.save
      end
      Rails.logger.debug '........ Sale data sync completed .......'
    end
  end

  def self.generate_invoice_from_booking(booking, requested_by, cashier, order_source = nil, in_duties_count = 0)
    Sale.transaction do
      if booking
        current = Time.current
        #get all order attached to this booking and combine into 1 invoice
        sale = booking.sale || booking.build_sale(
          {
            tax_type: "execulive" # Default Tax - Values
          }
        )

        if cashier.role == 'cashier'
          sale.cashier = cashier
          sale.shift_sale = cashier.current_shift
        elsif booking.dining_facility
          if sale.shift_sale = booking.current_shift_by_dining_facility
            sale.cashier = sale.shift_sale.employee
          end
        end

        if sale.shift_sale.nil?
          if sale.cashier = Employee.where(role: 'cashier').where.not(token_session: [nil, '']).first
            sale.shift_sale = sale.current_shift_by_cashier
          else
            sale.shift_sale = ShiftSale.current_shift
            sale.cashier = sale.shift_sale.employee
          end
        end

        sale.cashier_name = sale.cashier.name
        sale.requested_by = requested_by.name
        sale.requested_at = current

        sale.sale_items << booking.order_items.to_sale_items

        if booking.dining_facility.present? && dining_charge = booking.dining_facility.dining_charge
          block_count, dining_price = DiningCharge.amount_calculate(dining_charge, booking.checkin_at, booking.checkout_at)
          format = "%I:%M %p" if dining_charge.charge_type == "hr"
          format ||= "%B %d, %I:%M %p"
          dining_time = "#{booking.checkin_at.strftime(format)} - #{booking.checkout_at.strftime(format)}"

          sale.sale_items.build({
              menu_category_name: "Dining Charge",
              menu_category_code: "DiningCharge",
              product_name:       "#{booking.dining_facility.name} ( #{dining_time} )",
              product_code:       dining_charge.item_code,
              product_alt_name:   '-',
              account_id:         0,
              is_taxable:         dining_charge.taxable,
              qty:                block_count,
              unit_price:         dining_charge.unit_price,
              price:              dining_price,
              taxable_price:      dining_price,
          })

          if in_duties_count.to_i > 0
            basic_pay = Commission.find_by(commission_type: 'Basic Pay')
            in_duties_pay_amount = (in_duties_count.to_i * ((booking.checkout_at - booking.checkin_at) / 1.hours) * basic_pay_amount).to_i

            sale.sale_items.build({
                menu_category_name: "Induty Charge",
                menu_category_code: "IndutyCharge",
                product_name:       "#{basic_pay.name} ( #{dining_time} )",
                product_code:       "",
                product_alt_name:   '-',
                account_id:         0,
                is_taxable:         dining_charge.taxable,
                qty:                in_duties_count,
                unit_price:         basic_pay.amount,
                price:              in_duties_pay_amount,
                taxable_price:      in_duties_pay_amount,
            })
          end
        end
        sale.orders << booking.orders
        sale.customer_id = booking.orders[0].customer_id

        sale.compute(booking.orders[0].source)

        booking.orders.update_all(status: "billed")
        booking.order_items.update_all(order_item_status: "billed")

        booking.checkout_at = current unless booking.checkout_at && booking.checkout_at > current
        booking.checkout_by = requested_by.name

        booking.save
        return sale
      end
    end
  end

  #fOR Quick Service pay and create
  def self.request_bill(order, current_user, current_login_employee)
    if !ShiftSale.current_shift.nil?
      order_id = order.order_id # order_id
      booking = order.booking

      if booking.sale.nil?
        sale_data = Sale.generate_invoice_from_booking(booking, current_login_employee, current_user, order.source)
        # Promotion Activation
        Promotion.promo_activate(sale_data)
      end

      return true, sale_data
    else
      return false, "No Current Open Shift for This Employee"
    end
  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 = Time.current

    items.each do |item|
      add_item(item)
      if !item.set_menu_items.nil?
        add_sub_item(item.set_menu_items)
      end

      #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 generic_void?
    self.sale_status == 'void' && self.sale_audits.where(action: 'SALEVOID').exists?
  end

  def mmqr_cancel_void?
    self.sale_status == 'void' && self.sale_audits.where(action: 'CANCEL_MMQR_PAYMENT').exists?
  end

  def add_item (item)
    #check if the item is on promotion
    menu_category = MenuCategory.get_menu_category(item.item_code) #get menu category for menu items

    #save sale_audit
    sale_item = SaleItem.new

    #pull
    if !menu_category.nil?
      sale_item.menu_category_code = menu_category.code
      sale_item.menu_category_name = menu_category.name
    else
      sale_item.menu_category_name = "Product"
    end
    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.status = 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 add_sub_item (item)
    #check if the item is on promotion
    JSON.parse(item).each do |item|

      #save sale item
      sale_item = SaleItem.new

      #pull
      instance  = MenuItemInstance.find_by_item_instance_code(item["item_instance_code"])
      menu_item = instance.menu_item
      menu_category = MenuCategory.get_menu_category(menu_item.item_code) #get menu category for menu items

      sale_item.menu_category_code = menu_category.code ? menu_category.code : nil
      sale_item.menu_category_name = menu_category.name
      sale_item.product_code       = menu_item.item_code
      sale_item.item_instance_code = item["item_instance_code"]
      sale_item.product_name       = instance.item_instance_name
      sale_item.product_alt_name   = menu_item.alt_name
      sale_item.account_id         = menu_item.account_id
      sale_item.status             = nil

      sale_item.qty                = item["quantity"]
      sale_item.unit_price         = item["price"]
      sale_item.taxable_price      = sale_item.qty * sale_item.unit_price
      sale_item.is_taxable         = menu_item.taxable

      sale_item.price              = sale_item.qty * sale_item.unit_price

      self.sale_items << sale_item
    end
  end

  def create_saleitem_diningcharges(chargeObj, block_count, diningprice, dining_name, dining_time, order_source = nil)
    sale_item = SaleItem.new
    sale_item.menu_category_code = "DingingCharge"
    sale_item.menu_category_name = "Dining Charge"
    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
    self.sale_items << sale_item
    self.compute_by_sale_items(self.total_discount, nil, order_source)
  end
  def create_saleitem_indutycharges(chargeObj, current_checkin_induties_count, induties_pay_amount, dining_name, dining_time, order_source = nil, basic_pay_amount)
    sale_item = SaleItem.new
    sale_item.menu_category_code = "IndutyCharge"
    sale_item.menu_category_name = "Induty Charge"
    sale_item.product_code = ""
    sale_item.product_name ='Vocalist' + " ( " + dining_time.to_s + " )"
    sale_item.account_id = 0
    sale_item.product_alt_name = "-"
    sale_item.qty = current_checkin_induties_count
    sale_item.unit_price = basic_pay_amount
    sale_item.taxable_price = induties_pay_amount
    sale_item.is_taxable = chargeObj.taxable
    sale_item.sale_id = self.id
    sale_item.price = induties_pay_amount
    sale_item.save
    # Re-calc
    self.sale_items << sale_item
    self.compute_by_sale_items(self.total_discount, nil, order_source)
  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(order_source = nil, tax_type = nil)
    #Computation Fields
    subtotal_price = 0
    total_taxable = 0
    rounding_adjustment = 0

    self.sale_items.each do |item|
      #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
      # total_taxable = total_taxable + (item.taxable_price * item.qty)
    end

    apply_tax(total_taxable, order_source, tax_type)

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

  #compute - invoice total
  def compute_by_sale_items(total_discount, discount_type=nil, order_source=nil, tax_type=nil, type=nil)

    shop = Shop.current_shop

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

    self.sale_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(total_taxable, total_discount, order_source, tax_type)
    self.total_amount = subtotal_price
    self.total_discount = total_discount
    if type =="foc"
      self.grand_total = 0
    else
      self.grand_total = (self.total_amount - self.total_discount) + self.total_tax
      # sale.grand_total_round
    end

    if discount_type == "member_discount"
      self.discount_type = discount_type
    end
    #compute rounding adjustment
    # adjust_rounding
    self.save!
  end

  # No Use too many wrong
  def compute_without_void(order_source = nil)
    #Computation Fields
    subtotal_price = 0
    total_taxable = 0
    rounding_adjustment = 0

    self.sale_items.each do |item|
      if item.status != 'void' && item.status != '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, order_source)
    self.total_amount = subtotal_price
    # self.total_discount = total_discount
    self.grand_total = (self.total_amount - self.total_discount) + self.total_tax
    # self.grand_total_round
    #compute rounding adjustment
    # adjust_rounding

    self.save!
  end

  # Tax Re-Calculte
  def compute_tax(total_taxable, total_discount = 0, order_source = nil, tax_type = nil)
    shop = Shop.current_shop

    #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
    taxes = SaleTax.where("sale_id='#{self.sale_id}'").destroy_all

    total_tax_amount = 0
    tax_incl_exec = "exclusive"
    #tax_profile - list by order_by
    # tax_profiles = TaxProfile.all.order("order_by asc")
    # customer = Customer.find(sale.customer_id)

    if order_source.to_s == "emenu"
      order_source = "cashier"
    end

    tax_profiles = unique_tax_profiles(order_source, self.customer_id)
    # #Creat new tax records
    if self.payment_status != 'foc'
      tax_profiles.each do |tax|
        next if self.customer_id_before_last_save.nil? && !self.customer_id_changed? && tax_type.blank? && !taxes.map(&:tax_name).include?(tax.name)
        next unless tax_type == 'all' || tax_type.blank? || tax_type.include?(tax.name)
        sale_tax = self.sale_taxes.build
        sale_tax.tax_name = tax.name
        sale_tax.tax_rate = tax.rate

        total_tax = total_taxable - total_discount

        #include or execulive
        if tax.inclusive
          tax_incl_exec = "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
        end

        sale_tax.inclusive = tax.inclusive

        if !tax.inclusive
          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
      end
    end
    self.tax_type = tax_incl_exec
    self.total_tax = total_tax_amount
  end

  # Tax Calculate
  def apply_tax(total_taxable, order_source = nil, tax_type = nil)

    shop = Shop.current_shop

    #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

    taxes = SaleTax.where("sale_id='#{self.sale_id}'").destroy_all

    total_tax_amount = 0
    tax_incl_exec = "exclusive"
    #tax_profile - list by order_by
    # tax_profiles = TaxProfile.all.order("order_by asc")
    if order_source.to_s == "emenu"
      order_source = "cashier"
    elsif order_source.to_s == "app"
      order_source = "online_order"
    end

    # tax_data = TaxProfile.unscope(:order).where("group_type=?",order_source).pluck(:id)
    # customer = Customer.find(self.customer_id).tax_profiles

    tax_profiles = unique_tax_profiles(order_source, self.customer_id)

    #Create new tax records
    tax_profiles.each do |tax|
      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
      if tax.tax_type.to_s =="Net"
        sale_tax.tax_payable_amount = tax.rate
      else
        #include or execulive
        if tax.inclusive
          tax_incl_exec = "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
        end
      end
      sale_tax.inclusive = tax.inclusive
      sale_tax.save

      if !tax.inclusive
        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
    end
    self.tax_type   = tax_incl_exec
    self.total_tax  = total_tax_amount
  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?
      saleOrder = SaleOrder.new
      # sale = saleOrder.create_sale_order(self.id, order_id)
    end

    sale = saleOrder.create_sale_order(self.id, order_id)
    # 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.current.format(":short")
  end

  def adjust_rounding

    shop_details =  Shop.current_shop
      # rounding adjustment
    if shop_details.is_rounding_adj
      new_total = Sale.get_rounding_adjustment(self.grand_total)
      self.rounding_adjustment = new_total - self.grand_total
      self.old_grand_total = self.grand_total
      self.grand_total = new_total
    else
      self.rounding_adjustment = 0.00
    end

  end

  def self.get_foodcourt_current_shift_orders
    @current_shift = ShiftSale.current_shift
    @bookings = Booking.select("bookings.*,customers.*")
              .joins(" JOIN sales ON bookings.sale_id=sales.sale_id")
              .joins(" JOIN booking_orders ON booking_orders.booking_id=bookings.booking_id")
              .joins("JOIN orders ON orders.order_id=booking_orders.order_id")
              .joins("JOIN order_items ON orders.order_id=order_items.order_id")
              .joins("JOIN customers ON orders.customer_id=customers.customer_id")
              .where("sales.sale_status =? and sales.payment_status =? and orders.source='app' and sales.shift_sale_id = ?",
                'completed','paid', @current_shift.id
                ).order("bookings.created_at desc").uniq

    @completed = []
    @assigns = []
    @bookings.each do |b|
      if b.booking_status == 'completed'
        @completed << b
      else
        @assigns << b
      end
    end
    return @completed, @assigns
  end

  #Generate new Receipt No when it is not assigned
  def generate_receipt_no
    #shop_code and client_code

    shop_details =  Shop.current_shop
    #Date-Shift-
    if self.receipt_no.nil?
      prefix = Time.current().utc
      #self.receipt_no = prefix.to_s + "/" + self.shit_id.to_s + "/" + SeedGenerator.new_receipt_no().to_s
      new_receipt_no = SeedGenerator.new_receipt_no().to_s

      if !shop_details.nil?
        if !shop_details.shop_code.nil?
          self.receipt_no = shop_details.shop_code + "-" + prefix.strftime("%Y%m%d") + "-" + new_receipt_no
        else
          self.receipt_no = prefix.strftime("%Y%m%d") + "-" + new_receipt_no
        end
      else
        self.receipt_no = prefix.strftime("%Y%m%d") + "-" + new_receipt_no
      end

      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,shift)
    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?
      if shift.blank?
        sale = Sale.where("receipt_date BETWEEN ? AND ? and NOT sale_status = 'new'", from,to)
      else
        sale = Sale.where("receipt_date BETWEEN ? AND ?  and NOT sale_status = 'new' and shift_sale_id = '#{shift.id}'", from,to)
      end
        query = sale.where(keyword)
    else
      if shift.blank?
        where("receipt_no LIKE ? OR cashier_name LIKE ? OR sale_status ='#{filter}'","%#{filter}%","%#{filter}%")
      else
        where("(receipt_no LIKE ? OR cashier_name LIKE ? OR sale_status ='#{filter}') and shift_sale_id = ?","%#{filter}%","%#{filter}%",shift.id)
      end
    end
    .order("sale_id DESC")
  end

  def self.search_credit_sales(customer,filter,from,to,order_source="")
    sale = Sale.select(Sale.column_names)
    .select(SalePayment.column_names)
    .select(:source).includes(:customer)
    .joins(:sale_payments, :orders)
    .where(sale_payments: {payment_method: 'creditnote'})
    .group(:sale_payment_id)

    if from.present? && to.present?
      sale = sale.receipt_date_between(from, to)
    end

    if filter.present?
      sale = sale.where("sales.receipt_no LIKE ? OR sales.cashier_name LIKE ? OR sales.sale_status = ?", "%#{filter}%", "%#{filter}%", filter)
    end

    if customer.present?
      sale = sale.where(customer_id: customer)
    end

    if order_source.present?
      sale = sale.where(orders: {source: order_source})
    end
    return sale
  end

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

      # num = num.to_f.round
      mod = num % 50
      if mod > 0 && mod <= 25
        num -= mod
      elsif mod > 25
        num += 50 - mod
      end
    return num
  end

  def self.daily_sales_list(from,to)
    payment_methods = SalePayment.where.not(payment_method: ['cash', 'creditnote', 'foc']).distinct.pluck(:payment_method)

    tax_profiles = TaxProfile.group(:name).order(:order_by).pluck(:name)

    total_item_foc = SaleItem.select("SUM(ABS(sale_items.price)) AS total_amount, sale_items.sale_id")
                      .where("sale_items.status = ? AND sale_items.item_instance_code IS NOT NULL AND sale_items.qty < ?", 'foc', 0)
                      .group("sale_id")

    total_item_discount = SaleItem.select("SUM(ABS(sale_items.price)) AS total_amount, sale_items.sale_id")
                      .where("sale_items.status = ? AND sale_items.item_instance_code IS NOT NULL", 'Discount')
                      .group("sale_id")

    sales = select(Sale.column_names)
    .select("#{payment_methods.map { |method| "SUM(case when (sale_payments.payment_method='#{method}') then sale_payments.payment_amount else 0 end) as `#{method == 'paypar' ? 'redeem' : method}`"}.push('').join(', ')}
    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) -
    SUM(case when (sale_payments.payment_method not in('creditnote') and sale_audits.sale_audit_id IS NOT NULL) 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",
    "case when (item_foc.total_amount) then item_foc.total_amount else 0 end as item_foc_amount",
    "case when (item_discount.total_amount) then item_discount.total_amount else 0 end as item_discount_amount")
    .joins("LEFT JOIN (#{total_item_foc.to_sql}) AS item_foc ON item_foc.sale_id = sales.sale_id")
    .joins("LEFT JOIN (#{total_item_discount.to_sql}) AS item_discount ON item_discount.sale_id = sales.sale_id")
    .sale_payments_with_audit_except_void_between(from, to)
    .where("(sale_status = ? OR sale_status = ?) AND sales.receipt_date between ? AND ? ", 'completed', 'void', from, to)
    .where("sale_payments.payment_status != ? OR sales.payment_status =? ", 'cancelled', 'void')
    .group("sale_id")

    sale_taxes = Sale.select('sales.sale_id, sale_taxes.tax_name')
    .joins(:sale_taxes)
    .where('(sale_status = ? OR sale_status = ?) AND sales.receipt_date between ? AND ? ', 'completed', 'void', from, to)
    .group('sale_id')

    commercial_tax = ''
    if tax_profiles.present?
      sale_taxes = sale_taxes.select(tax_profiles.map { |name| "SUM(case when (sale_taxes.tax_name = '#{name}') then sale_taxes.tax_payable_amount else 0 end) as `#{name.parameterize}`"}.join(', '))
      if tax_profiles.include? 'Commercial Tax'
        commercial_tax = "IFNULL(SUM(case when (sale_status = 'completed' and payment_status != 'foc') then `commercial-tax` else 0 end),0)"
      end
    end

    daily_total = connection.select_all("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 grand_total else 0 end) - SUM(foc_amount),0) as total_sale,
      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' AND sa_salevoid.sale_audit_id IS NOT NULL) then grand_total else 0 end),0) as void_amount,
      IFNULL(SUM(case when (sale_status='void' AND sa_mmqr.sale_audit_id IS NOT NULL) then grand_total else 0 end),0) as mmqr_cancelled_void_amount,
      IFNULL(SUM(case when (sale_status='completed') then rounding_adjustment else 0 end),0) as rounding_adj,
      #{tax_profiles.map { |name| "IFNULL(SUM(case when (sale_status='completed') then `#{name.parameterize}` else 0 end),0) as `#{name.parameterize}`"}.push('').join(', ') if tax_profiles.present?}
      IFNULL(SUM(case when (sale_status='completed') then total_tax else 0 end),0) as tax,
      IFNULL(SUM(case when (sale_status='completed' and payment_status!='foc') then grand_total else 0 end),0)
      - #{commercial_tax} as net_sale,
      IFNULL(SUM(case when (sale_status='completed') then grand_total else 0 end),0)
      + IFNULL(SUM(case when (sale_status='completed') then total_discount else 0 end),0) as gross_sale,
      CAST((CONVERT_TZ(receipt_date,'+00:00','+06:30')) AS DATE) as sale_date,
      #{payment_methods.map { |method| pm = method == 'paypar' ? 'redeem' : method; "SUM(`#{pm}`) as `#{pm}`"}.push('').join(', ')}
      SUM(`cash_amount`) as `cash_amount`,
      SUM(`credit_amount`) as `credit_amount`,
      SUM(`foc_amount`) as `foc_amount`,
      SUM(`item_foc_amount`) as `item_foc_amount`,
      SUM(`item_discount_amount`) as `item_discount_amount`
      FROM (
      #{sales.to_sql}
      ) as s
      LEFT JOIN (#{sale_taxes.to_sql}) AS st ON s.sale_id = st.sale_id
      LEFT JOIN sale_audits sa_salevoid ON s.sale_id = sa_salevoid.sale_id AND sa_salevoid.action = 'SALEVOID'
      LEFT JOIN sale_audits sa_mmqr ON s.sale_id = sa_mmqr.sale_id AND sa_mmqr.action = 'CANCEL_MMQR_PAYMENT'
      GROUP BY DATE(CONVERT_TZ(receipt_date,'+00:00','+06:30'))").to_hash.map(&:symbolize_keys)
    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,
                       i.product_name,
                       sale_items.menu_category_name,
                       sale_items.menu_category_code")
                      .group('i.product_code')
                      .order("sale_items.menu_category_code")

  query = query.joins("JOIN sale_items i ON i.sale_id = sales.sale_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 - ShiftSale.get_by_shift_mmqr_payment(shift_sale.id).to_f).abs,
      :mmqr_sales => ShiftSale.get_by_shift_mmqr_payment(shift_sale.id).to_f,
      :foc_sales => foc,
      :grand_total => shift_sale.grand_total,
      :shift_id => shift_sale.id
    }
  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,
                          shift_closed_at," +
                          " 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_by_shift_sale_by_item(from,to,status)
  query = ShiftSale.select("shift_sales.id ,shift_started_at,
                          shift_closed_at," +
                          " 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 >= ?" , from)
end

def self.get_item_query(type)
  check_product = "i.menu_category_name != 'product'"
  if type == "revenue"
    sale_type = "i.qty > 0 and status IS NULL"
  elsif type == "all" || type.nil?
    sale_type = "#{check_product}"
  elsif type == "discount"
    sale_type = "#{check_product} and i.status = 'Discount'"
  elsif type == "foc"
    sale_type = "#{check_product} and i.status = 'foc' and i.item_instance_code IS NOT NULL and i.qty > 0"
  elsif type == "void"
    sale_type = "#{check_product} and i.status = 'void' and i.item_instance_code IS NOT NULL and i.qty > 0"
  elsif type == "other"
    sale_type = "#{check_product} and i.item_instance_code IS NULL"
  elsif type == "promotion"
    sale_type = "#{check_product} and i.status = 'promotion'"
  end
  query = Sale.select("sales.sale_id,acc.title as account_name,
                      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.status as status_type,i.remark as remark,"+
                     "i.unit_price,i.price as price,i.product_name as product_name, " +
                     "i.menu_category_name,i.menu_category_code as menu_category_id, " +
                     "date_format(CONVERT_TZ(receipt_date,'+00:00', '+06:30'), '%I %p')
                      as date_format")

  query = query.joins("JOIN sale_items i ON i.sale_id = sales.sale_id" +
                     " JOIN shift_sales sh ON sh.`id` = sales.shift_sale_id")
                     # "JOIN employee_accesses ea ON ea.`employee_id` = sales.cashier_id ")
  query = query.joins(" JOIN accounts acc ON acc.id = i.account_id")
  query = query.where("#{sale_type}")
  query = query.group("acc.title,i.account_id,i.menu_category_code,i.item_instance_code,i.product_name,i.unit_price")
               .order("acc.title desc, i.account_id desc, i.menu_category_code desc, i.item_instance_code asc, SUM(i.qty) desc, i.unit_price asc")
  # query = query.order("i.menu_category_name asc, SUM(i.qty) desc")
end

def self.get_staff_meal_query()
  sale_type = "foc"
  query = Sale.select("cus.name as staff_name,sales.sale_id,acc.title as account_name,
                      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.status as status_type,i.remark as remark,"+
                     "i.unit_price,i.price as price,i.product_name as product_name, " +
                     "i.menu_category_name,i.menu_category_code as menu_category_id, " +
                     "date_format(CONVERT_TZ(receipt_date,'+00:00', '+06:30'), '%I %p')
                      as date_format")

  query = query.joins("JOIN sale_items i ON i.sale_id = sales.sale_id " +
                     "JOIN shift_sales sh ON sh.`id` = sales.shift_sale_id " +
                     "JOIN customers cus ON cus.customer_id = sales.customer_id ")
  query = query.joins(" JOIN accounts acc ON acc.id = i.account_id")
  # query = query.where("#{sale_type}")
  query = query.group("acc.title,i.account_id,i.menu_category_code,i.item_instance_code,i.product_name,i.unit_price")
               .order("acc.title desc, i.account_id desc, i.menu_category_code desc, i.item_instance_code asc, SUM(i.qty) desc, i.unit_price asc")
  # query = query.order("i.menu_category_name asc, SUM(i.qty) 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.status as status_type,i.remark as remark,"+
                     " 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,type,account_type)
  # date_type_selection = get_sql_function_for_report_type(report_type)
  if account_type.blank?
    account_type = ''
  else
    account_type = " and acc.title = '#{account_type}'"
  end

  query = self.get_item_query(type)

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

  if type.nil? || type == 'all' || type == "other"
    other_charges = self.get_other_charges()
  end
  product       = self.get_product_sale()
  payment_methods = SalePayment.where.not(payment_method: ['cash', 'creditnote', 'foc']).distinct.pluck(:payment_method)

  if shift.present?
      query          = query.where("sales.shift_sale_id IN (?) #{account_type} and sale_status='completed'",shift.to_a)
      if type.nil? || type == 'all' || type == "other"
        other_charges  = other_charges.where("sales.shift_sale_id IN (?) and sale_status='completed'",shift.to_a)
      end
      product        = product.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      = select(Sale.column_names).select("SUM(case when (sale_payments.payment_method IN (#{payment_methods.empty? ? '""' : payment_methods.map{ |pm| "\"#{pm}\"" }.join(', ') })) 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 (?) #{account_type} and sale_status='completed'",shift_sale_range.to_a)
      if type.nil? || type == 'all' || type == "other"
        other_charges  = other_charges.where("sales.shift_sale_id IN (?) and sale_status='completed'",shift_sale_range.to_a)
      end
      product        = product.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      = select(Sale.column_names).select("SUM(case when (sale_payments.payment_method IN (#{payment_methods.empty? ? '""' : payment_methods.map{ |pm| "\"#{pm}\"" }.join(', ') })) 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 ? #{account_type} and sale_status='completed'",from,to)
      if type.nil? || type == 'all' || type == "other"
        other_charges  = other_charges.where("sales.receipt_date between ? and ? and sale_status='completed'",from,to)
      end
      product  = product.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      = select(Sale.column_names).select("SUM(case when (sale_payments.payment_method IN (#{payment_methods.empty? ? '""' : payment_methods.map{ |pm| "\"#{pm}\"" }.join(', ') })) 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, product, discount_query , total_cash_amount , total_card_amount , total_credit_amount , total_foc_amount , total_grand_total , change_amount
end

def self.get_staff_meal_items(shift_sale_range, shift, from, to, status, account_type, customer_id)
  # date_type_selection = get_sql_function_for_report_type(report_type)
  if account_type.blank?
    account_type = ''
  else
    account_type = " and acc.title = '#{account_type}'"
  end

  unless customer_id.empty?
    customer_id = customer_id.to_s
    customer_id[0] = ""
    customer_id = customer_id.chomp("]")
  else
    customer_id = "''"
  end

  query = self.get_staff_meal_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 = 0

  # if type.nil? || type == 'all' || type == "other"
  #   other_charges = self.get_other_charges()
  # end
  product       = self.get_product_sale()
  payment_methods = SalePayment.where.not(payment_method: ['cash', 'creditnote', 'foc']).distinct.pluck(:payment_method)

  if shift.present?
      query          = query.where("sales.shift_sale_id IN (?) #{account_type} and sale_status='completed' and sales.customer_id IN (#{customer_id})",shift.to_a)
      # if type.nil? || type == 'all' || type == "other"
      #   other_charges  = other_charges.where("sales.shift_sale_id IN (?) and sale_status='completed'",shift.to_a)
      # end
      product        = product.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      = select(Sale.column_names).select("SUM(case when (sale_payments.payment_method IN (#{payment_methods.empty? ? '""' : payment_methods.map{ |pm| "\"#{pm}\"" }.join(', ') })) 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 (?) #{account_type} and sale_status='completed' and sales.customer_id IN (#{customer_id})",shift_sale_range.to_a)
      # if type.nil? || type == 'all' || type == "other"
      #   other_charges  = other_charges.where("sales.shift_sale_id IN (?) and sale_status='completed'",shift_sale_range.to_a)
      # end
      product        = product.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      = select(Sale.column_names).select("SUM(case when (sale_payments.payment_method IN (#{payment_methods.empty? ? '""' : payment_methods.map{ |pm| "\"#{pm}\"" }.join(', ') })) 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 ? #{account_type} and sale_status='completed' and sales.customer_id IN (#{customer_id})",from,to)
      # if type.nil? || type == 'all' || type == "other"
      #   other_charges  = other_charges.where("sales.receipt_date between ? and ? and sale_status='completed'",from,to)
      # end
      product  = product.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      = select(Sale.column_names).select("SUM(case when (sale_payments.payment_method IN (#{payment_methods.empty? ? '""' : payment_methods.map{ |pm| "\"#{pm}\"" }.join(', ') })) 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, product, discount_query , total_cash_amount , total_card_amount , total_credit_amount , total_foc_amount , total_grand_total , change_amount
end

def self.get_product_sale()
  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.status as status_type,"+
                     " i.unit_price as unit_price,i.product_name as product_name,i.product_code as product_code")
  query = query.joins("JOIN sale_items i ON i.sale_id = sales.sale_id")
        .where("LOWER(i.menu_category_name) = 'product'")
  # query = query.joins("JOIN products p ON p.`item_code` = i.product_code")
  query = query.group("i.product_code")
end

#product sale report query
def self.get_menu_item_query(order_by)
  query = MenuItem.unscope(:order).select("acc.id as account_id,
                      acc.title as account_name,
                      mii.item_instance_code as item_code, " +
                     "(CASE WHEN si.qty IS NOT NULL THEN SUM(si.qty) ELSE 0 END) as total_item," +
                     "(CASE WHEN si.unit_price != mii.price THEN si.unit_price ELSE mii.price END) as unit_price," +
                     "(CASE WHEN si.qty IS NOT NULL THEN (SUM(si.qty) * si.unit_price) ELSE 0 END) as grand_total," +
                     "mii.price as unit_price, (CASE WHEN si.product_name IS NOT NULL THEN si.product_name ELSE CONCAT(menu_items.name,' - ',mii.item_instance_name) END) as product_name,
                     mc.name as" +
                     " menu_category_name,mc.id as menu_category_id, si.status as status_type,
                     si.price as price ")
          .joins(" LEFT JOIN menu_item_instances mii ON menu_items.id = mii.menu_item_id" +
               " LEFT JOIN menu_categories mc ON mc.id = menu_items.menu_category_id" +
               " LEFT JOIN accounts acc ON acc.id = menu_items.account_id" +
               " LEFT JOIN sale_items si ON si.item_instance_code = mii.item_instance_code" +
               " LEFT JOIN sales s ON s.sale_id = si.sale_id")
          .where("(CASE WHEN s.sale_status IS NOT NULL THEN s.sale_status='completed' ELSE 1 END)")
          .group("mc.id, (CASE WHEN si.product_name IS NOT NULL THEN si.product_name ELSE CONCAT(menu_items.name,' - ',mii.item_instance_name) END)")
          .order("si.qty #{order_by}, menu_items.menu_category_id #{order_by}")
end
#product sale report query

def self.get_shift_sales_by_receipt_no(shift_sale_range, shift, from, to, payment_type, customer_filter)
    ## => left join -> show all sales although no orders
    if payment_type.blank?
      payment_type = ''
    else
      payment_type = "sale_payments.payment_method = '#{payment_type}'"
    end

    query = Sale.includes(:sale_items).select("sales.*, sale_payments.*")
              .select("customers.customer_id, customers.name as customer_name, dining_facilities.name, dining_facilities.type")
              .joins("INNER JOIN sale_payments ON sale_payments.sale_id = sales.sale_id")
              .joins("INNER JOIN bookings ON bookings.sale_id = sales.sale_id")
              .joins("LEFT JOIN dining_facilities ON dining_facilities.id = bookings.dining_facility_id")
              .completed.where.not(total_amount: 0)
              .group("sales.sale_id")
    if payment_type != ''
      query = query.where("#{payment_type} and sale_payments.payment_amount!=0")
    end
    if customer_filter.present?
      query = query.joins(sanitize_sql_array(["INNER JOIN customers ON customers.customer_id = sales.customer_id AND " +
        "customers.name LIKE :filter", filter: "%#{customer_filter}%"]))
    else
      query = query.joins(:customer)
    end

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

    return query
end

def self.get_shift_sales_by_customer(shift_sale_range, shift, from, to, membership_type, customer_filter)
  ## => left join -> show all sales although no orders
  query = Sale.includes(:sale_items).select("sales.*, sale_payments.*")
            .select("customers.customer_id, customers.name as customer_name,customers.membership_type as membership_type, dining_facilities.name, dining_facilities.type")
            .joins("INNER JOIN sale_payments ON sale_payments.sale_id = sales.sale_id")
            .joins("INNER JOIN bookings ON bookings.sale_id = sales.sale_id")
            .joins("LEFT JOIN dining_facilities ON dining_facilities.id = bookings.dining_facility_id")
            .completed.where.not(total_amount: 0)
            .group("sales.sale_id")

  if customer_filter.present?
    query = query.joins(sanitize_sql_array(["INNER JOIN customers ON customers.customer_id = sales.customer_id AND " +
      "customers.name LIKE :filter", filter: "%#{customer_filter}%"]))
  else
    query = query.joins(:customer)
  end
  if !membership_type.blank?
    query = query.where("customers.membership_type = (?)", membership_type)
  end

  if shift.present?
    query = query.where("sales.shift_sale_id in (?)", shift.to_a)
  elsif shift_sale_range.present?
    query = query.where("sales.shift_sale_id in (?)", shift_sale_range.to_a)
  else
    query = query.where("sales.receipt_date between ? and ?", from, to)
  end
  return query.group_by(&:membership_type)
end

def self.get_shift_sales_by_receipt_no_detail(shift_sale_range, shift, from, to, payment_type, customer_filter)
    ## => left join -> show all sales although no orders
    puts customer_filter
    query = Sale.includes([:survey, :sale_payments])
            .select("sales.*, SUM(sale_payments.payment_amount) AS payments_for_credits_amount")
            .select("dining_facilities.type AS table_type, dining_facilities.name AS table_name")
            .select("customers.customer_id, customers.name AS customer_name, customers.company AS customer_company")
            .joins("INNER JOIN bookings ON bookings.sale_id = sales.sale_id")
            .joins("LEFT JOIN dining_facilities on dining_facilities.id = bookings.dining_facility_id")
            .left_joins(:payments_for_credits)
            .completed.where.not(total_amount: 0)
            .group(:sale_id).order(:receipt_date)

    if customer_filter.present?
      query = query.joins(sanitize_sql_array(["INNER JOIN customers ON customers.customer_id = sales.customer_id AND " +
        "customers.name LIKE :filter", filter: "%#{customer_filter}%"]))
    else
      query = query.joins(:customer)
    end

    if payment_type.present?
      if payment_type == 'card'
        query = query.where(sanitize_sql_array(["sp.payment_method IN (?)", SalePayment::CARD]))
      else
        query = query.where("sp.payment_method = (?)", payment_type)
      end
    end

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

    ActiveRecord::Associations::Preloader.new.preload(query, :sale_items, SaleItem.where.not(price: 0))

    return query
end

def self.get_by_shift_sale_credit_payment(shift_sale_range,shift,from,to,filter,customer_filter,order_source)
  payments_for_credits = SalePayment.select("
    sales.sale_id,
    DATE_FORMAT(CONVERT_TZ(sale_payments.created_at,'+00:00','+06:30'),'%d %b %y %h:%i%p') as credit_payment_receipt_date,
    sale_payments.payment_amount as credit_payment,
    employees.name as credit_payment_cashier_name,
    CONCAT(DATE_FORMAT(CONVERT_TZ(shift_sales.shift_started_at,'+00:00','+06:30'),'%d %b %y %h:%i%p'),' - ',DATE_FORMAT(CONVERT_TZ(shift_sales.shift_closed_at,'+00:00','+06:30'),'%d %b %y %h:%i%p')) as credit_payment_shift_name")
  .joins(:sale_audit)
  .joins(:sale => :shift_sale)
  .joins(:sale => :cashier).to_sql

  credits = SalePayment.select("
    sale_payments.sale_payment_id,
    sale_payments.payment_method,
    sale_payments.payment_amount,
    sale_payments.payment_status,
    sales_sale_payments.sale_id,
    sales_sale_payments.receipt_no,
    sales_sale_payments.receipt_date as sale_date,
    sales_sale_payments.cashier_name,
    orders.source as order_source,
    customers.name as customer_name,
    IFNULL(payments_for_credits.credit_payment_receipt_date, '-') as credit_payment_receipt_date,
    IFNULL(payments_for_credits.credit_payment, 0) as credit_payment,
    IFNULL(payments_for_credits.credit_payment_cashier_name, '-') as credit_payment_cashier_name,
    IFNULL(payments_for_credits.credit_payment_shift_name, '-') as credit_payment_shift_name")
  .joins("LEFT JOIN (#{payments_for_credits}) payments_for_credits ON payments_for_credits.sale_id = sales_sale_payments.sale_id")
  .joins(:sale => :orders)
  .credits
  .where("sales_sale_payments.sale_status = ?", 'completed')

  if customer_filter.present?
    credits = credits.joins(sanitize_sql_array(["INNER JOIN customers ON customers.customer_id = sales_sale_payments.customer_id AND " +
      "customers.name LIKE :filter", filter: "%#{customer_filter}%"]))
  else
    credits = credits.joins(:sale => :customer)
  end

  if order_source.present?
    if order_source == "cashier"
      credits = credits.where("orders.source IN (?)", ['cashier', 'emenu'])
    else
      credits = credits.where("orders.source = ?", order_source)
    end
  end

  if filter == 'paid'
    credits = credits.where("payments_for_credits.sale_id IS NOT NULL")
  elsif filter == 'unpaid'
    credits = credits.where("payments_for_credits.sale_id IS NULL")
  end

  if shift.present?
    credits = credits.where("sales_sale_payments.shift_sale_id in (?)",shift.to_a)
  elsif shift_sale_range.present?
    credits = credits.where("sales_sale_payments.shift_sale_id in (?)",shift_sale_range.to_a)
  else
    credits = credits.where("sales_sale_payments.receipt_date between ? and ?",from,to)
  end
  credits   = credits.group("sale_payments.sale_payment_id, sales_sale_payments.sale_id")
end

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

     query = Sale.select("sales.sale_id,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

    if status.present? && status == 'cancelled_mmqr'
      query = query.joins("INNER JOIN sale_audits sa ON sa.sale_id = sales.sale_id")
        .where("sa.action = 'CANCEL_MMQR_PAYMENT'")
    elsif status.present? && status == 'void'
      query = query.joins("LEFT JOIN sale_audits sa ON sa.sale_id = sales.sale_id AND sa.action = 'CANCEL_MMQR_PAYMENT'")
                 .where("sa.sale_id IS NULL")
    end

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

def self.get_total_waste(shift_id)
  query = Sale.where("sale_status = 'waste' and shift_sale_id = ?", shift_id)
end

def self.get_total_spoile(shift_id)
  query = Sale.where("sale_status = 'spoile' and shift_sale_id = ?", shift_id)
end

def self.get_separate_tax(shift_sale_range=nil,shift,from,to,payment_type)
  if payment_type.blank?
    payment_type = ''
  else
      payment_type = " and sale_payments.payment_method = '#{payment_type}'"
  end

  query = SaleTax.select("SUM(tax_payable_amount) AS st_amount,tax_name")
            .where("sale_status= 'completed'")
            .joins("LEFT JOIN sales ON sales.sale_id = sale_taxes.sale_id")
            .group("sale_taxes.tax_name")
            .order("sale_taxes.tax_name desc")

  if payment_type != ''
    query = query.where("#{payment_type} and sale_payments.payment_amount!=0")
  end

  if shift.present?
     query = query.where(sales: { shift_sale_id: shift })
  elsif shift_sale_range.present?
     query = query.where(sales: { shift_sale_id: shift_sale_range.to_a })
  else
     query = query.where("sales.receipt_date between ? and ? ", from,to)
  end
end

def self.get_separate_tax_by_customer(shift_sale_range, shift, from, to, payment_type,customer_filter, membership_type=nil)

  query = SaleTax.select("SUM(tax_payable_amount) AS st_amount,tax_name")
            .where("sale_status= 'completed'")
            .joins("LEFT JOIN sales ON sales.sale_id = sale_taxes.sale_id")
            .group("sale_taxes.tax_name")
            .order("sale_taxes.tax_name desc")
  if payment_type.present?
    query = query.joins("JOIN sale_payments ON sale_payments.sale_id = sale_taxes.sale_id AND sale_payments.payment_method = '#{payment_type}' and sale_payments.payment_amount!=0")
  end

  query = query.joins("INNER JOIN customers ON customers.customer_id = sales.customer_id
    #{sanitize_sql_array(['AND customers.name LIKE :filter', filter: "%#{customer_filter}%"]) if customer_filter.present?}
    #{sanitize_sql_array(['AND customers.membership_type = :type', type: membership_type]) if membership_type.present?}")

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

end

def self.get_payment_method_by_shift(shift,from,to,payment_type)
  payment_methods = SalePayment.where.not(payment_method: ['cash', 'creditnote', 'foc']).distinct.pluck(:payment_method)

  payments_total = SalePayment.select("
    sales.receipt_date as sale_date,
    #{payment_methods.map { |method| "SUM(case when (sale_payments.payment_method='#{method}') then sale_payments.payment_amount else 0 end) as #{method == 'paypar' ? 'redeem' : method}"}.join(', ')},
    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) -
    SUM(case when (sale_audits.sale_audit_id IS NOT NULL) then
    sale_payments.payment_amount else 0 end) as credit_amount,
    SUM(case when (sale_payments.payment_method='giftvoucher') then sale_payments.payment_amount else 0 end) as giftvoucher_amount,
    SUM(case when (sale_payments.payment_method='foc') then sale_payments.payment_amount else 0 end) as foc_amount")
    .joins(:sale).left_joins(:sale_audit)
    .merge(Sale.completed.receipt_date_between(from, to))

    sales = Sale.select(Sale.column_names)
            .select("SUM(sale_payments.payment_amount) as payment_for_credits_amount")
            .left_joins(:payments_for_credits)
            .group(:sale_id)

    sale_payment = SalePayment.select("sales.amount_changed as change_amount,sales.receipt_no, sale_payments.*, sales.receipt_date as sale_date,
    sales.cashier_name as cashier_name")
    .joins("JOIN (#{sales.to_sql}) as sales ON sales.sale_id = sale_payments.sale_id")
    .where("sale_payments.payment_method != 'creditnote' OR payment_for_credits_amount - sale_payments.payment_amount <= 0")
    .where.not(payment_amount: 0)
    .merge(Sale.completed.receipt_date_between(from, to))

    if shift.present?
      payments_total = payments_total.where(sales: {shift_sale_id: shift.to_a})
      sale_payment = sale_payment.merge(Sale.where(sales: {shift_sale_id: shift.to_a}))
    end

    if payment_type.present?
      if payment_type == 'card'
        sale_payment = sale_payment.where(sanitize_sql_array(["payment_method IN (?)", SalePayment::CARD]))
      else
        sale_payment = sale_payment.where("payment_method = (?)", payment_type)
      end
    end

    return payments_total, sale_payment
end

def self.get_wastes_and_spoilages(from,to,status)
  if status == "spoile"
    type = "and sales.sale_status = 'spoile'"
  else
    type = "and sales.sale_status = 'waste'"
  end
  query = Sale.select("sales.sale_id,sales.receipt_no,sales.created_at,sales.total_amount,sales.grand_total,sales.rounding_adjustment,sales.shift_sale_id,sale_items.product_name,sale_items.product_code,sale_items.item_instance_code,sale_items.qty,sale_items.price,sale_items.unit_price,sale_items.menu_category_name as name")
              .joins("JOIN sale_items ON sales.sale_id = sale_items.sale_id" )
              .where("sales.receipt_date between ? and ? #{type}",from,to)
              .group("sales.receipt_no,sale_items.menu_category_code,sale_items.item_instance_code")
              .order("sales.sale_id,sale_items.qty desc,sale_items.menu_category_name,sale_items.product_name")
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
    self.sale_payments.where(payment_method: 'cash', payment_status: 'paid')
    .pluck(:payment_amount).reduce(0, :+) - self.amount_changed
  end

  def get_credit_amount
    self.sale_payments.where(payment_method: 'creditnote')
    .pluck(:payment_status, :payment_amount)
    .inject(0.0) { |sum, pay|
      if pay[0] == 'outstanding'
        sum += pay[1]
      else
        sum -= pay[1]
      end
    }
  end

  def get_other_amount
    self.sale_payments.where.not(payment_method: ['cash', 'creditnote'])
    .pluck(:payment_status, :payment_amount)
    .inject(0.0) { |sum, pay|
      if pay[0] == 'paid'
        sum += pay[1]
      else
        sum -= pay[1]
      end
    }
  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_bottom_products(current_user,from,to,type)
    query = Sale.joins("JOIN sale_items ON sale_items.sale_id = sales.sale_id")
        .completed
        .where("qty > 0 AND price > 0")
        .group("SUBSTRING_INDEX(product_name, ' - ', 1)")

    if !from.nil? && !to.nil?
      query = query.receipt_date_between(from, to)
    else
      query = query.receipt_date_between(Time.current.beginning_of_day, Time.current.end_of_day)
    end

    if current_user.present? && !(current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account' || current_user.role == 'supervisor')
      if shift = ShiftSale.current_open_shift(current_user)
        query = query.where("shift_sale_id='#{shift.id}'")

      end
    end

    if type == "top"
      query = query.order("SUM(qty) DESC")
    else
      query = query.order("SUM(qty) ASC")
    end

    query.limit(20).sum('qty')
  end


  def self.hourly_sales(current_user,from,to)
    query = Sale.group("date_format(CONVERT_TZ(receipt_date,'+00:00', '#{Time.zone.formatted_offset}'), '%I %p')")
    .order('receipt_date').completed

    if !from.nil? && !to.nil?
      query = query.receipt_date_between(from, to)
    else
      query = query.receipt_date_between(Time.current.beginning_of_day, Time.current.end_of_day)
    end

    if current_user.present? && !(current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account' || current_user.role == 'supervisor')
      if shift = ShiftSale.current_open_shift(current_user)
        query = query.where("shift_sale_id='#{shift.id}'")
      end
    end

    query.sum(:grand_total)
  end


  def self.employee_sales(current_user,from,to)
    shift = if current_user.present? && !(current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account' || current_user.role == 'supervisor')
      ShiftSale.current_open_shift(current_user)
    end

    payments_for_credits = SalePayment.joins(:sale_audit).to_sql
    payment_methods = SalePayment.where.not(payment_method: ['cash', 'creditnote', 'foc']).distinct.pluck(:payment_method)

    query = employee_sale(shift, from, to)
    .joins("LEFT JOIN (#{payments_for_credits}) payments_for_credits ON payments_for_credits.sale_id = sales.sale_id")
    .select("SUM(sale_payments.payment_amount) - CASE WHEN sale_payments.payment_method = 'creditnote' THEN IFNULL(SUM(payments_for_credits.payment_amount), 0) ELSE ABS(SUM(CASE WHEN sale_payments.outstanding_amount < 0 THEN sale_payments.outstanding_amount ELSE 0 END)) END AS payment_amount,
    CASE WHEN sale_payments.payment_method IN (#{payment_methods.empty? ? '""' : payment_methods.map{ |pm| "\"#{pm}\"" }.join(', ') }) THEN 'card'
		ELSE sale_payments.payment_method END AS payment_method, employees.name AS e_name")
  end


  def self.total_trans(current_user=nil,from=nil,to=nil)
    query = Sale.select("SUM(grand_total) as total_sale, COUNT(sales.sale_id) as total_count")
            .where('sale_status = "completed"')

    if (!from.nil? && !to.nil?)
      query = query.receipt_date_between(from, to)

    else
      query = query.receipt_date_between(Time.current.beginning_of_day, Time.current.end_of_day)
    end

    if current_user.present? && !(current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account'  || current_user.role == 'supervisor')
      if shift = ShiftSale.current_open_shift(current_user)
        query = query.where("sales.shift_sale_id = ?", shift.id)
      end
    end

    return query
  end


  def self.total_card_sale(current_user=nil,from=nil,to=nil)
    payment_methods = SalePayment.where.not(payment_method: ['cash', 'creditnote', 'foc']).distinct.pluck(:payment_method)
    query = Sale.joins("JOIN sale_payments sp ON sp.sale_id = sales.sale_id")
                .where("sales.sale_status = 'completed' and (sp.payment_method IN (#{payment_methods.empty? ? '""' : payment_methods.map{ |pm| "\"#{pm}\"" }.join(', ') }))")

    if (!from.nil? && !to.nil?)
      query = query.receipt_date_between(from, to)
    else
      query = query.receipt_date_between(Time.current.beginning_of_day, Time.current.end_of_day)
    end

    if current_user.present? && !(current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account'  || current_user.role == 'supervisor')
      if shift = ShiftSale.current_open_shift(current_user)
        query = query.where("sales.shift_sale_id = ?", shift.id)
      end
    end

    query = query.sum("sp.payment_amount")
  end


  def self.credit_payment(current_user=nil,from=nil,to=nil)

    payments_for_credits = SalePayment.joins(:sale_audit).to_sql

    query = SalePayment.credits
    .joins(:sale)
    .joins("LEFT JOIN (#{payments_for_credits}) payments_for_credits ON payments_for_credits.sale_id = sale_payments.sale_id")
    .where("sale_payments.payment_method= ? AND sales.sale_status = ?", 'creditnote', 'completed')

    if (!from.nil? && !to.nil?)
      query = query.merge(Sale.receipt_date_between(from, to))
    else
      query = query.merge(Sale.receipt_date_between(Time.current.beginning_of_day, Time.current.end_of_day))
    end

    if current_user.present? && !(current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account'  || current_user.role == 'supervisor')
      if shift = ShiftSale.current_open_shift(current_user)
        query = query.where("sales.shift_sale_id = ?", shift.id)
      end
    end

    return query.sum("sale_payments.payment_amount - IFNULL(payments_for_credits.payment_amount, 0)")
  end


  def self.summary_sale_receipt(current_user=nil,from=nil,to=nil)
    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"')

    if (!from.nil? && !to.nil?)
      query = query.receipt_date_between(from, to)

    else
      query = query.receipt_date_between(Time.current.beginning_of_day, Time.current.end_of_day)
    end

    if current_user.present? && !(current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account'  || current_user.role == 'supervisor')
      if shift = ShiftSale.current_open_shift(current_user)
        query = query.where("sales.shift_sale_id = ?", shift.id)
      end
    end

    query = query.first()
  end


  def self.total_payment_methods(current_user=nil,from=nil,to=nil)
    query = Sale.select(sanitize_sql_array(["CASE WHEN sp.payment_method IN (?) THEN 'card' ELSE sp.payment_method END as payment_method", SalePayment::CARD]))
            .where("sales.sale_status = 'completed'")
            .joins("JOIN sale_payments as sp ON sp.sale_id = sales.sale_id")
            .group(sanitize_sql_array(["CASE WHEN sp.payment_method IN (?) THEN 'card' ELSE sp.payment_method END", SalePayment::CARD]))

    if (!from.nil? && !to.nil?)
      query = query.receipt_date_between(from, to)
    else
      query = query.receipt_date_between(Time.current.beginning_of_day, Time.current.end_of_day)
    end

    if current_user.present? && !(current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account'  || current_user.role == 'supervisor')
      if shift = ShiftSale.current_open_shift(current_user)
        query = query.where("sales.shift_sale_id = ?", shift.id)
      end
    end

    return query
  end


  def self.payment_sale(payment_method, current_user=nil,from=nil,to=nil)

    payments_for_credits = SalePayment.joins(:sale_audit).to_sql

    query = Sale.select("SUM(sale_payments.payment_amount) - CASE WHEN sale_payments.payment_method = 'creditnote' THEN IFNULL(SUM(payments_for_credits.payment_amount), 0) ELSE ABS(SUM(CASE WHEN sale_payments.outstanding_amount < 0 THEN sale_payments.outstanding_amount ELSE 0 END)) END AS payment_amount")
    .joins(:sale_payments)
    .joins("LEFT JOIN (#{payments_for_credits}) payments_for_credits ON payments_for_credits.sale_id = sales.sale_id")
    .completed

    if payment_method == 'card'
      query = query.merge(SalePayment.cards)
    else
      query = query.where("sale_payments.payment_method = ?", payment_method)
    end

    if (!from.nil? && !to.nil?)
      query = query.receipt_date_between(from, to)
    else
      query = query.receipt_date_between(Time.current.beginning_of_day, Time.current.end_of_day)
    end

    if current_user.present? && !(current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account' || current_user.role == 'supervisor')
        if shift = ShiftSale.current_open_shift(current_user)
          query = query.where("sales.shift_sale_id = ?", shift.id)
        end
    end

    query.first
  end


  def self.total_customer(current_user=nil,from=nil,to=nil)
    total_dinein_takeaway = self.total_dinein_takeaway(current_user,from,to)

    dinein_cnt = 0
    takeaway_cnt = 0

    if !total_dinein_takeaway.nil?
      if total_dinein_takeaway[0]
        dinein_cnt = total_dinein_takeaway[0].total_dinein_cus
        takeaway_cnt = total_dinein_takeaway[0].total_take_cus
      end
    end


    membership_cnt = self.total_membership(current_user,from,to)

    member_cnt = 0

    if !membership_cnt.nil?
      member_cnt = membership_cnt.total_memb_cus
    end

    total_cus = 0

    if dinein_cnt > dinein_cnt || takeaway_cnt > 0 || !membership_cnt.nil?
      total_cus = dinein_cnt.to_int + takeaway_cnt.to_int + member_cnt.to_int
    end

    return total_cus, dinein_cnt, takeaway_cnt, member_cnt
  end


  def self.total_dinein_takeaway(current_user=nil,from=nil,to=nil)
    query = Sale.select("(CASE WHEN c.customer_type='Dinein' THEN count(sales.customer_id) ELSE 0 END) as total_dinein_cus, (CASE WHEN c.customer_type='Takeaway' THEN count(sales.customer_id) ELSE 0 END) as total_take_cus")
            .joins("JOIN customers as c ON c.customer_id = sales.customer_id")
            .where('sales.sale_status = "completed" and c.membership_id is null')

    if (!from.nil? && !to.nil?)
      query = query.receipt_date_between(from, to)

    else
      query = query.receipt_date_between(Time.current.beginning_of_day, Time.current.end_of_day)
    end

    if current_user.present? && !(current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account'  || current_user.role == 'supervisor')
      if shift = ShiftSale.current_open_shift(current_user)
        query = query.where("sales.shift_sale_id = ?", shift.id)
      end
    end

    query = query.first()
  end


  def self.total_membership(current_user=nil,from=nil,to=nil,from_time=nil,to_time=nil)
    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 ((c.customer_type = "Dinein" and c.membership_id is not null) or (c.customer_type = "Takeaway" and c.membership_id is not null))')

    if (!from.nil? && !to.nil?)
      query = query.receipt_date_between(from, to)

    else
      query = query.receipt_date_between(Time.current.beginning_of_day, Time.current.end_of_day)
    end

    if current_user.present? && !(current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account'  || current_user.role == 'supervisor')
      if shift = ShiftSale.current_open_shift(current_user)
        query = query.where("sales.shift_sale_id = ?", shift.id)
      end
    end

    query = query.first()
  end

  # def self.total_other_customer(today,current_user=nil,from=nil,to=nil,from_time=nil,to_time=nil)
  #   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 c.customer_type is null and c.membership_id is null')
  #   if !from.nil? && !to.nil?
  #     if current_user.nil?
  #       if !from_time.nil? && !to_time.nil?
  #         query = query.where('DATE_FORMAT(CONVERT_TZ(sales.receipt_date,"+00:00","+06:30"),"%Y-%m-%d") between ? and ? and DATE_FORMAT(CONVERT_TZ(sales.receipt_date,"+00:00","+06:30"),"%H:%i") between ? and ?',from,to,from_time,to_time)
  #       else
  #         query = query.where('DATE_FORMAT(CONVERT_TZ(sales.receipt_date,"+00:00","+06:30"),"%Y-%m-%d") between ? and ?',from,to)
  #       end
  #     else
  #       if current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account' || current_user.role == 'supervisor'
  #         if !from_time.nil? && !to_time.nil?
  #           query = query.where('DATE_FORMAT(CONVERT_TZ(sales.receipt_date,"+00:00","+06:30"),"%Y-%m-%d") between ? and ? and DATE_FORMAT(CONVERT_TZ(sales.receipt_date,"+00:00","+06:30"),"%H:%i") between ? and ?',from,to,from_time,to_time)
  #         else
  #           query = query.where('DATE_FORMAT(CONVERT_TZ(sales.receipt_date,"+00:00","+06:30"),"%Y-%m-%d") between ? and ?',from,to)
  #         end
  #       else
  #         shift = ShiftSale.current_open_shift(current_user)
  #         if !shift.nil?
  #           if !from_time.nil? && !to_time.nil?
  #             query = query.where('DATE_FORMAT(CONVERT_TZ(sales.receipt_date,"+00:00","+06:30"),"%Y-%m-%d") between ? and ? and DATE_FORMAT(CONVERT_TZ(sales.receipt_date,"+00:00","+06:30"),"%H:%i") between ? and ? and sales.shift_sale_id=?',from,to,from_time,to_time,shift.id)
  #           else
  #             query = query.where('DATE_FORMAT(CONVERT_TZ(sales.receipt_date,"+00:00","+06:30"),"%Y-%m-%d") between ? and ? and sales.shift_sale_id=?',from,to,shift.id)
  #           end
  #         end
  #       end
  #     end
  #   else
  #     if current_user.nil?
  #       query = query.where('DATE_FORMAT(CONVERT_TZ(sales.receipt_date,"+00:00","+06:30"),"%Y-%m-%d") = ?',today)
  #     else
  #       if current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account' || current_user.role == 'supervisor'
  #         query = query.where('DATE_FORMAT(CONVERT_TZ(sales.receipt_date,"+00:00","+06:30"),"%Y-%m-%d") = ?',today)
  #       else
  #         shift = ShiftSale.current_open_shift(current_user)
  #         if !shift.nil?
  #           query = query.where('DATE_FORMAT(CONVERT_TZ(sales.receipt_date,"+00:00","+06:30"),"%Y-%m-%d") = ? and sales.shift_sale_id=?',today,shift.id)
  #         end
  #       end
  #     end
  #   end
  #   query = query.first()
  # end


  def self.total_order(current_user=nil,from=nil,to=nil)

    query = Sale.select("count(distinct sale_orders.order_id) as total_order")
            .joins(:sale_orders)
            .completed

    if (!from.nil? && !to.nil?)
      query = query.receipt_date_between(from, to)
    else
      query = query.receipt_date_between(Time.current.beginning_of_day, Time.current.end_of_day)
    end

    if current_user.present? && !(current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account'  || current_user.role == 'supervisor')
      if shift = ShiftSale.current_open_shift(current_user)
        query = query.where("sales.shift_sale_id = ?", shift.id)
      end
    end

    query = query.first
  end


  def self.account_data(account_id, current_user=nil,from=nil,to=nil)
    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}'")

    if (!from.nil? && !to.nil?)
      query = query.receipt_date_between(from, to)

    else
      query = query.receipt_date_between(Time.current.beginning_of_day, Time.current.end_of_day)
    end

    if current_user.present? && !(current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account'  || current_user.role == 'supervisor')
      if shift = ShiftSale.current_open_shift(current_user)
        query = query.where("sales.shift_sale_id = ?", shift.id)
      end
    end

    query = query.first
  end


  def self.top_items(current_user=nil,from=nil,to=nil)
    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'")

    if (!from.nil? && !to.nil?)
      query = query.receipt_date_between(from, to)

    else
      query = query.receipt_date_between(Time.current.beginning_of_day, Time.current.end_of_day)
    end

    if current_user.present? && !(current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account'  || current_user.role == 'supervisor')
      if shift = ShiftSale.current_open_shift(current_user)
        query = query.where("sales.shift_sale_id = ?", shift.id)
      end
    end

    query = query.group("a.product_code")
                    .order("SUM(a.qty) DESC")
                    .first()
  end


  def self.total_foc_items(current_user=nil,from=nil,to=nil)
    query = Sale.joins("JOIN sale_items as a ON a.sale_id = sales.sale_id")
              .where("sales.sale_status = 'completed' and a.status='foc' and a.product_name like '%FOC%'")

    if (!from.nil? && !to.nil?)
      query = query.receipt_date_between(from, to)

    else
      query = query.receipt_date_between(Time.current.beginning_of_day, Time.current.end_of_day)
    end

    if current_user.present? && !(current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account'  || current_user.role == 'supervisor')
      if shift = ShiftSale.current_open_shift(current_user)
        query = query.where("sales.shift_sale_id = ?", shift.id)
      end
    end

    query = query.count()
  end

  #card sale trans data
  def self.getCardSaleTrans(sale_id)
    query = Sale.select("cst.res_date,cst.res_time,cst.trace,cst.pan,cst.batch_no,cst.exp_date,cst.app,cst.res_type,cst.ref_no,cst.terminal_id,cst.merchant_id,cst.app_code")
            .joins("JOIN card_sale_trans as cst on cst.sale_id = sales.sale_id")
            .where("sales.sale_id=? and status = 'Approved'",sale_id)

    return query
  end

  def self.add_to_existing_pending_invoice(dining,sale_id,booking)

    sale = Sale.find(sale_id)
    existing_booking = Booking.find_by_sale_id(sale_id)

    if booking.sale_id.nil? || booking.booking_id != existing_booking.booking_id
      booking.orders.where(status: 'new').update(booking: existing_booking)
      booking.update(booking_status: 'moved')
    end

    existing_booking.orders.where(status: 'new').each do |order|
      order.status = 'billed'
      order.order_items.each do |item|
        item.order_item_status = 'billed'
        sale.add_item(item)
      end
      order.save
      sale.compute(order.source)
      sale.orders << order
    end

  end

  def self.get_shift_sale_items(sh_id)
    query = Sale.select("sales.shift_sale_id as shift_sale_id, i.account_id as account_id, acc.title as account_name, i.item_instance_code as item_code, i.menu_category_name, i.menu_category_code as menu_category_id, i.product_name as product_name, i.unit_price, i.price as price, i.qty as qty, SUM(i.qty) as total_item, SUM(i.qty * i.unit_price) as grand_total, i.status as status_type, i.remark as remark")
    .joins("JOIN sale_items i on i.sale_id = sales.sale_id")
    .joins("JOIN accounts acc on acc.id = i.account_id")
    .where("sales.shift_sale_id=?", sh_id)
    .group("acc.title,i.account_id,i.menu_category_code,i.item_instance_code,i.product_name,i.unit_price")
    .order("acc.title desc, i.account_id desc, i.menu_category_code desc, i.unit_price asc")
  end

  def self.pending_sale(type)
    query = Sale.all
    query = query.joins("join sale_orders as sale_orders on sale_orders.sale_id = sales.sale_id")
                 .joins("join orders as orders on orders.order_id = sale_orders.order_id")
    query = query.where("sales.sale_status = 'new' AND orders.status = 'billed' AND orders.source =? ","#{type}")
                  .group("sales.sale_id")
  end

  def self.pending_order(type)
    query = Booking.all
    query = query.joins("join booking_orders as booking_orders on booking_orders.booking_id = bookings.booking_id")
                 .joins("join orders as orders on orders.order_id = booking_orders.order_id")
    query = query.where("bookings.booking_status = 'assign' AND orders.status = 'new' AND orders.source =? ","#{type}")
                  .group("bookings.booking_id")
  end

  def self.completed_sale(type)
    if type == "cashier"
      type = "and orders.source = 'emenu' or orders.source = 'cashier'"
    else
      type = "and orders.source = '#{type}'"
    end
    query = Sale.all
    query = query.joins("join sale_orders as sale_orders on sale_orders.sale_id = sales.sale_id")
                 .joins("join orders as orders on orders.order_id = sale_orders.order_id")
    query = query.where("sales.sale_status != 'new' AND orders.status = 'billed' #{type}")
    query = query.receipt_date_between(Time.current.beginning_of_day, Time.current.end_of_day)
                  .group("sales.sale_id")
  end

  def self.all_receipts
    query = Sale.select("sales.*,sale_payments.created_at as receipt_close_time,
                case when (sale_audits.action='SALEPAYMENT') then sale_audits.remark else 0 end as remark,
                case when (sale_taxes.tax_name='Service Charges') then sale_taxes.tax_payable_amount else 0 end as service_charges,
                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='unionpay') then sale_payments.payment_amount else 0 end) as unionpay_amount,
                SUM(case when (sale_payments.payment_method='alipay') then sale_payments.payment_amount else 0 end) as alipay_amount,
                SUM(case when (sale_payments.payment_method='paymal') then sale_payments.payment_amount else 0 end) as paymal_amount,
                SUM(case when (sale_payments.payment_method='dinga') then sale_payments.payment_amount else 0 end) as dinga_amount,
                 SUM(case when (sale_payments.payment_method='JunctionPay') then sale_payments.payment_amount else 0 end) as junctionpay_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,
                 SUM(case when (sale_payments.payment_method='giftvoucher') then sale_payments.payment_amount else 0 end) as giftvoucher_amount,
                 SUM(case when (sale_items.status='foc') then sale_items.price else 0 end) as item_foc,
                 SUM(case when (sale_items.status='Discount') then sale_items.price else 0 end) as item_discount,
                 SUM(sale_items.qty) as qty,
                sales.cashier_name as cashier_name,
                surveys.child as child,
                surveys.adult as adult")
            .joins("join sale_payments on sale_payments.sale_id = sales.sale_id")
            .joins("join sale_taxes on sale_taxes.sale_id = sales.sale_id")
            .joins("join sale_items on sale_items.sale_id = sales.sale_id")
            .joins("join sale_audits on sale_audits.sale_id = sales.sale_id")
            .joins("left join surveys on surveys.receipt_no = sales.receipt_no")

    query = query.where("sales.sale_status != 'new' && sale_payments.payment_amount > 0")
    query = query.where("sales.created_at between ? and ?", '2017-11-01 00:00:00 +0630','2018-11-16 13:59:59 +0630')
                  .group("sales.sale_id")
    return query
end

def self.all_receipt_details
    query = SaleItem.select("sale_items.*, sale_payments.created_at as receipt_close_time,
            sales.requested_at as requested_at, sales.receipt_no as receipt_no,sales.sale_id as s_id")
            .joins("join sale_payments on sale_payments.sale_id = sale_items.sale_id")
            .joins("join sales on sales.sale_id = sale_items.sale_id")
            .group("sale_items.sale_item_id")
   query = query.where("sale_items.qty > 0 and sales.sale_status !='new'")
       query = query.where("sale_items.created_at between ? and ?", '2017-11-01 00:00:00 +0630','2018-11-16 13:59:59 +0630')
    return query
end

def self.get_sale_data_for_other_payment_credit(sale_id)
  query = Sale.select("sales.sale_id,sales.receipt_no,sales.customer_id,SUM(sp.payment_amount) as total_amount,SUM(sp.payment_amount) as grand_total")
                    .joins(" JOIN sale_payments sp on sp.sale_id=sales.sale_id")
                    .where("sp.payment_method ='creditnote' and sales.sale_id='#{sale_id}'")
                    .group("sales.sale_id")
                    .first
  return query
end

def unique_tax_profiles(order_source, customer_id)
  tax_data = TaxProfile.where(group_type: order_source)

  customer_tax_profiles = Customer.select(:tax_profiles).where(customer_id: customer_id).first
  if customer_tax_profiles.present?
    tax_data = tax_data.where(id: customer_tax_profiles.tax_profiles)
  end

  return tax_data
end


def self.employee_sale(shift=nil,from=nil,to=nil,from_time=nil,to_time=nil)

  query = Sale.joins(:cashier)
            .joins(:sale_payments)
            .paid.completed
  if !from.nil? && !to.nil?
    query = query.receipt_date_between(from, to)
  else
    query = query.receipt_date_between(Time.current.beginning_of_day, Time.current.end_of_day)
  end

  if !shift.nil?
    query = query.where("sales.shift_sale_id = ?", shift.id)
  end

  query = query.group("payment_method","employees.name")
              .order("employees.name")
end

# Start hourly sale item report
def self.get_by_hourly_items(shift_sale_range, shift, from, to, status,type,account_type,filter,start_time,end_time)
  # date_type_selection = get_sql_function_for_report_type(report_type)
  if account_type.blank?
    account_type = ''
  else
    account_type = " and acc.title = '#{account_type}'"
  end

  if start_time.blank? || end_time.blank?
    receipt_date = "sales.receipt_date between '#{from}' and '#{to}'"
    query = self.get_hourly_item_query(type,filter,true)
  else
    start_time = Time.zone.parse(start_time).utc
    end_time  = Time.zone.parse(end_time).utc
    receipt_date = "sales.receipt_date between '#{start_time}' and '#{end_time}'"
    query = self.get_hourly_item_query(type,filter,false)
  end

  unless start_time.blank? && end_time.blank?
    from_date = from.to_date
    to_date = to.to_date
    from_date_time = DateTime.new(from_date.year, from_date.month, from_date.day, start_time.hour, start_time.min, start_time.sec, start_time.zone)
    to_date_time = DateTime.new(to_date.year, to_date.month, to_date.day, end_time.hour, end_time.min, end_time.sec, end_time.zone)
    receipt_date = "sales.receipt_date between '#{from_date_time}' and '#{to_date_time}'"
    query = self.get_hourly_item_query(type,filter,false)
  end

  # query = self.get_hourly_item_query(type,filter)

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

  if type.nil? || type == 'all' || type == "other"
    other_charges = self.get_other_charges()
  end
  product       = self.get_product_sale()
  payment_methods = SalePayment.where.not(payment_method: ['cash', 'creditnote', 'foc']).distinct.pluck(:payment_method)

  if shift.present?
      query          = query.where("sales.shift_sale_id IN (?) #{account_type} and sale_status='completed'",shift.to_a)
      if type.nil? || type == 'all' || type == "other"
        other_charges  = other_charges.where("sales.shift_sale_id IN (?) and sale_status='completed'",shift.to_a)
      end
      product        = product.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 IN (#{payment_methods.empty? ? '""' : payment_methods.map{ |pm| "\"#{pm}\"" }.join(', ') })) 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 (?) #{account_type} and sale_status='completed'",shift_sale_range.to_a)
      if type.nil? || type == 'all' || type == "other"
        other_charges  = other_charges.where("sales.shift_sale_id IN (?) and sale_status='completed'",shift_sale_range.to_a)
      end
      product        = product.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 IN (#{payment_methods.empty? ? '""' : payment_methods.map{ |pm| "\"#{pm}\"" }.join(', ') })) 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("#{receipt_date} #{account_type} and sale_status='completed'")
      if type.nil? || type == 'all' || type == "other"
        other_charges  = other_charges.where("sales.receipt_date between ? and ? and sale_status='completed'",from,to)
      end
      product  = product.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 IN (#{payment_methods.empty? ? '""' : payment_methods.map{ |pm| "\"#{pm}\"" }.join(', ') })) 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, product, discount_query , total_cash_amount , total_card_amount , total_credit_amount , total_foc_amount , total_grand_total , change_amount
end

def self.get_hourly_item_query(type,filter,status)
  if status
    group_by = "acc.title,i.account_id,i.menu_category_code,i.item_instance_code,i.product_name,i.unit_price,hour"
  else
    group_by = "acc.title,i.account_id,i.menu_category_code,i.item_instance_code,i.product_name,i.unit_price"
  end
  check_product = "i.menu_category_name != 'product'"
  if type == "revenue"
    sale_type = "i.qty > 0 and status IS NULL"
  elsif type == "all" || type.nil? || type.empty?
    sale_type = "#{check_product}"
  elsif type == "discount"
    sale_type = "#{check_product} and i.status = 'Discount'"
  elsif type == "foc"
    sale_type = "#{check_product} and i.status = 'foc' and i.item_instance_code IS NOT NULL and i.qty > 0"
  elsif type == "void"
    sale_type = "#{check_product} and i.status = 'void' and i.item_instance_code IS NOT NULL and i.qty > 0"
  elsif type == "other"
    sale_type = "#{check_product} and i.item_instance_code IS NULL"
  elsif type == "promotion"
    sale_type = "#{check_product} and i.status = 'promotion'"
  end
  query = Sale.select("sales.sale_id,acc.title as account_name,
                      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.status as status_type,i.remark as remark,"+
                     "i.unit_price,i.price as price,i.product_name as product_name, " +
                     "i.menu_category_name,i.menu_category_code as menu_category_id, " +

                      "concat(hour(CONVERT_TZ(receipt_date,'+00:00', '+06:30')), ':00 - ', hour(CONVERT_TZ(receipt_date,'+00:00', '+06:30')) + 1, ':00') as date_format," +
                      "hour(CONVERT_TZ(receipt_date,'+00:00', '+06:30')) as hour")

  query = query.joins("JOIN sale_items i ON i.sale_id = sales.sale_id" +
                     " JOIN shift_sales sh ON sh.`id` = sales.shift_sale_id")
                     # "JOIN employee_accesses ea ON ea.`employee_id` = sales.cashier_id ")
  query = query.joins(" JOIN accounts acc ON acc.id = i.account_id")
  query = query.where("#{sale_type} and i.product_name LIKE '%#{filter}%'" )
  query = query.group("#{group_by}")
               .order("hour asc")
  # query = query.order("i.menu_category_name asc, SUM(i.qty) desc")
end

# End hourly sale item report


#not to show decimal in grand total
def grand_total_round
    print_settings = PrintSetting.get_precision_delimiter()
    if !print_settings.nil?
        self.grand_total =self.grand_total.round(precision)
    end
end

# Loader Service SFTP Start
def self.get_load_sale_range(load_time_start,load_time_end)
  query = Sale.select("sales.sale_id,
    CONVERT(receipt_date, TIME) as transaction_time,
    CONVERT(receipt_date, DATE) as transaction_date,
    receipt_no as transaction_no,
    SUM(i.qty) as item_no,
    'MMK' as currency_salesamount,
    IFNULL((total_amount-total_discount)-((total_amount-total_discount)/21),0) as total_salesamount,
    IFNULL(amount_changed,0) as change_amt,
    IFNULL(total_amount-total_discount,0) as grand_salesamount,
    '5' as tax_percent,
    'MMK' as currency_payment,
    IFNULL(amount_received,0) as paymentamount,
    sp.payment_amount as payment_method,
    CASE
    	WHEN sales.sale_status='completed' THEN 'Sales'
      WHEN sales.sale_status='void' THEN 'Void'
    END as sale_type,
    sales.updated_at as load_time")
  .joins("JOIN sale_items i ON i.sale_id = sales.sale_id" +
                      " JOIN sale_payments sp ON sp.sale_id = sales.sale_id")
  .where("(sale_status=? OR sale_status=?) AND sp.payment_method !=? AND sales.updated_at between ? AND ?", 'completed', 'void', 'foc', load_time_start, load_time_end)
  .group("receipt_no")
  .order("receipt_date")
end

def self.get_tender_sale_data(transaction_date)
  query = Sale.select("sales.receipt_no as check_num,
    DATE_FORMAT(sales.receipt_date, '%d %b %Y') as business_date,
    sales.receipt_date as transaction_date,
    '36017' as item_id,
    'Cash Received' as item_name,
    '1' as qty,
    'Tender' as transaction_type,
    '0' as sales,
    CASE WHEN sales.sale_status = 'void' THEN '1' ELSE '0' END as is_void
    ")
    .where("DATE(sales.receipt_date)=? AND sales.sale_status != ?", transaction_date, :void)
    .order("sales.receipt_no")
end

def self.get_daily_sale_data(transaction_date)
  query = Sale.connection.select_all("SELECT s.receipt_date as business_date,
    (SUM(s.grand_total)+SUM(s.total_discount)) as gross_sales,
    SUM(s.total_discount) as discount,
    SUM(s.grand_total) as sales,
    SUM(s.grand_total)/21 as tax,
    0 as service_charge,
    SUM(s.grand_total) - (SUM(s.grand_total)/21) as net_sales,
    SUM(s.credit_amount) as credit_amount,
    SUM(s.voucher_sales) as voucher_sales,
    0 as staff_meal_amt,
    0 as round_amt,
    0 as raw_wastage_amt,
    0 as semi_wastage_amt,
    CASE WHEN s.sale_status='waste' THEN SUM(s.total_amount) ELSE 0 END as wastage_amt,
    CASE WHEN s.sale_status='spoile' THEN SUM(s.total_amount) ELSE 0 END as spoilage_amt,
    0 as sampling_amt,
    0 as other_amt,
    SUM(s.qty) as total_qty,
    (SELECT COUNT(sales.sale_id) FROM sales WHERE DATE(sales.receipt_date)='#{transaction_date}') as total_transaction,
    (SELECT COUNT(sales.sale_id) FROM sales WHERE (sales.sale_status='completed' OR sales.sale_status='void') AND DATE(sales.receipt_date)='#{transaction_date}') as valid_transaction_count,
    (SELECT COUNT(sales.sale_id) FROM sales WHERE (sales.sale_status IN('new','pending',null)) AND DATE(sales.receipt_date)='#{transaction_date}') as invalid_transaction_count,
    0 as overing_transaction_count,
    0 as cancle_transaction_count,
    0 as no_of_pax,
    0 as no_of_adult,
    0 as no_of_child
    FROM (
    SELECT s.*, SUM(qty) as qty
    FROM (
    	SELECT sales.*,
    	SUM(CASE WHEN sp.payment_method IN('mpu','master','visa','jcb','unionpay','alipay') THEN sp.payment_amount ELSE 0 END) as credit_amount,
    	SUM(case when (sp.payment_method='giftvoucher') then sp.payment_amount else 0 end) as voucher_sales
    	FROM sales
    	LEFT JOIN sale_payments sp ON sp.sale_id = sales.sale_id
    	WHERE DATE(sales.receipt_date) = '#{transaction_date}'
    	AND sales.sale_status!='void'
    	AND sales.sale_status='completed'
    	GROUP BY sales.sale_id) AS s
    LEFT JOIN sale_items si ON si.sale_id = s.sale_id
    GROUP BY s.sale_id) as s
    GROUP BY DATE(s.receipt_date)").to_hash
  end

  def self.get_check_sale_data(transaction_date)
    payment_methods = SalePayment.where.not(payment_method: ['cash', 'creditnote', 'foc']).distinct.pluck(:payment_method)
    sale_receivables_subquery = "SELECT sale_payments.sale_id,
        SUM(case when (sale_payments.payment_method IN (#{payment_methods.empty? ? '""' : payment_methods.map{ |pm| "\"#{pm}\"" }.join(', ') })) then (sale_payments.payment_amount) else 0 end) as credit_card_sales,
        CASE WHEN sale_payments.payment_method = 'giftvoucher' THEN SUM(sale_payments.payment_amount) ELSE SUM(0) END as voucher_sales
        FROM sale_payments
        GROUP BY sale_payments.sale_id, sale_payments.payment_method"

    query = Sale.select("
      sales.receipt_no as check_num,
      sales.receipt_date as business_date,
      sales.requested_at as check_open_time,
      sales.updated_at as check_close_time,
      (sales.grand_total + sales.total_discount) as gross_sales,
      sales.total_discount as discount_amt,
      sales.grand_total as sales,
      (sales.grand_total/21) as tax_amt,
      0 as service_charges,
      (sales.grand_total - (sales.grand_total/21)) as net_sales,
      receivables.credit_card_sales as credit_card_sales,
      receivables.voucher_sales as voucher_sales,
      0 as staff_meal_amt,
      sales.rounding_adjustment as rounding_amt,
      CASE WHEN sales.sale_status='waste' THEN sales.total_amount ELSE 0 END as wastage_amt,
      CASE WHEN sales.sale_status='spoile' THEN sales.total_amount ELSE 0 END as spoilage_amt,
      0 as sampling_amt,
      SUM(i.qty) as qty,
      0 as no_of_pax,
      0 as no_of_adult,
      0 as no_of_child,
      shift_sales.cashier_terminal_id as pos_id,
      sales.cashier_id as employee_code,
      employees.name as employee_name,
      CASE WHEN sales.sale_status='completed' THEN 1 ELSE 0 END is_valid,
      0 as overing,
      0 as cancle,
      CONCAT( employees.name, ' Cash&Go receipt generated and completed.') as remarks")
      .joins("LEFT JOIN shift_sales ON shift_sales.id = sales.shift_sale_id")
      .joins("LEFT JOIN sale_items i ON i.sale_id = sales.sale_id")
      .joins("LEFT JOIN (" + sale_receivables_subquery + ") as receivables ON receivables.sale_id = sales.sale_id")
      .joins("LEFT JOIN employees ON employees.id = sales.cashier_id")
      .where("DATE(sales.receipt_date) = ? AND sales.sale_status != ?", transaction_date, :void)
      .group("sales.receipt_no,sales.sale_status")
  end

  def paymal_payment_void
    membership_setting = MembershipSetting.find_by_membership_type("paypar_url")
    membership_actions_data = MembershipAction.find_by_membership_type("void")
    if !membership_actions_data.nil?
      sale_payments =self.sale_payments.where("payment_reference is not null")
      if !sale_payments.empty?
        account_no =sale_payments[0].payment_reference
        url = membership_setting.gateway_url.to_s + membership_actions_data.gateway_url.to_s
        merchant_uid = membership_actions_data.merchant_account_id
        auth_token = membership_actions_data.auth_token
        params  = { receipt_no:self.receipt_no,
                    account_no:account_no,
                    merchant_uid:merchant_uid,
                    auth_token:auth_token}.to_json

          # Control for Paypar Cloud
          begin
            response = HTTParty.post(url,
                  :body => params,
                  :headers => {
                            'Content-Type' => 'application/json',
                            'Accept' => 'application/json; version=3'
                  },
                  :timeout => 10
            )
          rescue Errno::ECONNREFUSED
              response = { "status" => false, "message" => "Can't open membership server"}
          rescue Net::OpenTimeout
              response = { "status" => false, "message" => "No internet connection " }
          rescue OpenURI::HTTPError
              response = { "status" => false, "message" => "No internet connection "}
          rescue SocketError
              response = { "status" => false, "message" => "No internet connection "}
          end
      end
    else
        response = { "status" => false}
    end

    Rails.logger.debug "Void Payment response"
    Rails.logger.debug response.to_json
    return response;
  end
# Loader Service SFTP End

private

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

  def round_to_precision
    if (self.total_amount % 1 > 0 || self.total_discount % 1 > 0 || self.total_tax % 1 > 0)
      self.total_amount = self.total_amount.round(precision)
      self.total_discount = self.total_discount.round(precision)
      self.total_tax = self.total_tax.round(precision)
    end
    self.grand_total = (self.total_amount - self.total_discount) + self.total_tax
    if (!['foc', 'waste', 'spoile', 'void'].include? self.payment_status)
      adjust_rounding
    end
  end

  def update_stock_journal
      if self.sale_status == "void" && self.sale_status_before_last_save != "void"
        self.sale_items.each do |item|
          found, inventory_definition = InventoryDefinition.find_product_in_inventory(item)
          if found
            stock = StockJournal.where('item_code=?', item.item_instance_code).order("id DESC").first
            unless stock.nil?
              check_item = StockCheckItem.where('item_code=?', item.item_instance_code).order("id DESC").first
              StockJournal.add_to_journal(item.item_instance_code, -item.qty, stock.balance, "void", inventory_definition, item.id, StockJournal::SALES_TRANS)
              check_item.different = check_item.different + item.qty
              check_item.save
            end
          end
        end
      elsif self.sale_status == "waste" || self.sale_status == "spoile" || (self.payment_status == "foc" && self.payment_status_was != "foc")
        self.bookings.first.order_items.each do |item|
          found, inventory_definition = InventoryDefinition.find_product_in_inventory(item)
          if found
            if stock_journal = StockJournal.find_by_trans_ref(item.order_items_id)
              if self.payment_status == "foc" && self.payment_status_was != "foc"
                stock_journal.update(remark: self.payment_status)
              else
                stock_journal.update(remark: self.sale_status)
              end
            end
          end
        end
      end
  end
end
