improve receipt/details reports and implement number formatting

1) eager load reports for receipt/details
2) introduce number_format lookups to replace print_settings for number formatting
3) implement NumberFormattable concern, reference number_format lookups or print_settings if not exist, to get number format settings and number formatting
4) replace rails NumberHelper.number_with_precision with NumberFormattable.number_format hopefully to reduce overhead, formatting numbers for huge lists of data
This commit is contained in:
Thein Lin Kyaw
2019-11-25 23:17:53 +06:30
parent a36e170d94
commit 3c1cc737b5
71 changed files with 1338 additions and 1898 deletions

View File

@@ -1,4 +1,5 @@
class Sale < ApplicationRecord
include NumberFormattable
self.primary_key = "sale_id"
#primary key - need to be unique generated for multiple shops
@@ -7,12 +8,15 @@ class Sale < ApplicationRecord
belongs_to :cashier, foreign_key: "cashier_id", class_name: "Employee"
belongs_to :customer, :optional => true
belongs_to :shift_sale
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 :sale_orders
has_many :sale_payments_for_credits, through: :sale_audits
has_many :orders, through: :sale_orders
has_many :order_items, through: :sale_orders
has_many :bookings
@@ -28,7 +32,7 @@ class Sale < ApplicationRecord
scope :date_on, -> (date) { where("DATE(CONVERT_TZ(receipt_date, '+00:00', ?)) = ?", Time.zone.formatted_offset, date) }
scope :date_between, -> (from, to) { where("DATE(CONVERT_TZ(receipt_date, '+00:00', ?)) BETWEEN ? AND ?", Time.zone.formatted_offset, from, to) }
scope :time_between, -> (from, to) { where("TIME(CONVERT_TZ(receipt_date, '+00:00', ?)) BETWEEN ? AND ?", Time.zone.formatted_offset, from, to) }
scope :along_with_sale_payments_except_void, -> { joins("LEFT JOIN sale_payments on sales.sale_status != 'void' AND sale_payments.sale_id = sales.sale_id AND DATE(CONVERT_TZ(sale_payments.created_at,'+00:00','+06:30')) = DATE(CONVERT_TZ(sales.receipt_date,'+00:00','+06:30'))") }
scope :along_with_sale_payments_except_void, -> { joins("LEFT JOIN sale_payments on sales.sale_status != 'void' AND sale_payments.sale_id = sales.sale_id AND DATE(CONVERT_TZ(sale_payments.created_at,'+00:00', '#{Time.zone.formatted_offset}')) = DATE(CONVERT_TZ(sales.receipt_date,'+00:00', '#{Time.zone.formatted_offset}'))") }
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
@@ -542,15 +546,20 @@ class Sale < ApplicationRecord
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
sale_tax.tax_payable_amount = total_tax * tax.rate / 100
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
sale_tax.inclusive = tax.inclusive
sale_tax.save
end
end
self.tax_type = tax_incl_exec
@@ -598,6 +607,12 @@ class Sale < ApplicationRecord
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
sale_tax.save
if !tax.inclusive
total_tax_amount = total_tax_amount + sale_tax.tax_payable_amount
end
@@ -605,9 +620,6 @@ class Sale < ApplicationRecord
if shop.calc_tax_order
total_taxable = total_taxable + sale_tax.tax_payable_amount
end
sale_tax.inclusive = tax.inclusive
sale_tax.save
end
self.tax_type = tax_incl_exec
self.total_tax = total_tax_amount
@@ -1197,7 +1209,7 @@ def self.get_shift_sales_by_receipt_no(shift_sale_range,shift,from,to,payment_ty
payment_type = " and sale_payments.payment_method = '#{payment_type}'"
end
query = Sale.all.select("sales.*,sale_payments.*,df.name,df.type")
query = Sale.includes(:sale_items).select("sales.*,sale_payments.*,df.name,df.type")
.where("sale_status= 'completed' and sale_payments.payment_amount != 0 #{payment_type}")
.joins("join sale_payments on sale_payments.sale_id = sales.sale_id")
.joins("join bookings on bookings.sale_id = sales.sale_id")
@@ -1215,17 +1227,16 @@ end
def self.get_shift_sales_by_receipt_no_detail(shift_sale_range,shift,from,to,payment_type)
## => left join -> show all sales although no orders
if payment_type.blank?
payment_type = ''
else
payment_type = " and sale_payments.payment_method = '#{payment_type}'"
end
query = Sale.select("sales.*,bookings.dining_facility_id as table_id")
.where("sale_status= 'completed' and sale_payments.payment_amount != 0 #{payment_type}")
.joins("join sale_payments on sale_payments.sale_id = sales.sale_id")
.joins("join bookings on bookings.sale_id = sales.sale_id")
.group("sales.sale_id")
query = Sale.includes([:customer, :survey, :sale_payments])
.includes(:bookings => :dining_facility)
.select("sales.*, SUM(sale_payments.payment_amount) AS payments_for_credits_amount")
.joins(:bookings)
.left_joins(:sale_payments_for_credits)
.completed
.where.not(total_amount: 0)
.group(:sale_id)
.order(:receipt_date)
if shift.present?
query = query.where("sales.shift_sale_id in (?)", shift.to_a)
elsif shift_sale_range.present?
@@ -1233,6 +1244,9 @@ def self.get_shift_sales_by_receipt_no_detail(shift_sale_range,shift,from,to,pay
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
@@ -1503,101 +1517,53 @@ end
end
def self.top_bottom_products(today,current_user,from,to,from_time,to_time,type)
if (!from.nil? && !to.nil?) && (from != "" && to!="")
if current_user.nil?
query = Sale.top_bottom(today,nil,from,to,from_time,to_time)
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 type == "top"
query = query.group('i.product_name')
.order("SUM(i.qty) DESC").limit(20)
elsif type == "bottom"
query = query.group('i.product_name')
.order("SUM(i.qty) ASC").limit(20)
end
else
if current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account' || current_user.role == 'supervisor'
query = Sale.top_bottom(today,nil,from,to,from_time,to_time)
if type == "top"
query = query.group('i.product_name')
.order("SUM(i.qty) DESC").limit(20)
elsif type == "bottom"
query = query.group('i.product_name')
.order("SUM(i.qty) ASC").limit(20)
end
else
shift = ShiftSale.current_open_shift(current_user.id)
if !shift.nil?
query = Sale.top_bottom(today,shift,from,to,from_time,to_time)
if type == "top"
query = query.group('i.product_name')
.order("SUM(i.qty) DESC").limit(20)
elsif type == "bottom"
query = query.group('i.product_name')
.order("SUM(i.qty) ASC").limit(20)
end
end
end
if !from.nil? && !to.nil?
query = query.date_between(from, to)
if !from_time.nil? && !to_time.nil?
query = query.time_between(from_time, to_time)
end
else
if current_user.nil?
query = Sale.top_bottom(today).group('i.product_name')
if type == "top"
query = query.order("SUM(i.qty) DESC").limit(20)
elsif type == "bottom"
query = query.order("SUM(i.qty) ASC").limit(20)
end
else
if current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account' || current_user.role == 'supervisor'
query = Sale.top_bottom(today).group('i.product_name')
if type == "top"
query = query.order("SUM(i.qty) DESC").limit(20)
elsif type == "bottom"
query = query.order("SUM(i.qty) ASC").limit(20)
end
else
shift = ShiftSale.current_open_shift(current_user.id)
if !shift.nil?
query = Sale.top_bottom(today,shift).group('i.product_name')
if type == "top"
query = query.order("SUM(i.qty) DESC").limit(20)
elsif type == "bottom"
query = query.order("SUM(i.qty) ASC").limit(20)
end
end
end
query = query.date_on(today)
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.id)
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(today,current_user,from,to,from_time,to_time)
if (!from.nil? && !to.nil?) && (from != "" && to!="")
if current_user.nil?
query = Sale.hourly_sale_data(today,nil,from,to,from_time,to_time)
else
if current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account' || current_user.role == 'supervisor'
query = Sale.hourly_sale_data(today,nil,from,to,from_time,to_time)
else
shift = ShiftSale.current_open_shift(current_user.id)
if !shift.nil?
query = Sale.hourly_sale_data(today,shift,from,to,from_time,to_time)
end
end
query = Sale.group("date_format(CONVERT_TZ(receipt_date,'+00:00', '+06:30'), '%I %p')")
.order('receipt_date').completed
if !from.nil? && !to.nil?
query = query.date_between(from, to)
if !from_time.nil? && !to_time.nil?
query = query.time_between(from_time, to_time)
end
else
if current_user.nil?
query = Sale.hourly_sale_data(today)
else
if current_user.role == 'administrator' || current_user.role == 'manager' || current_user.role == 'account' || current_user.role == 'supervisor'
query = Sale.hourly_sale_data(today)
else
shift = ShiftSale.current_open_shift(current_user.id)
if !shift.nil?
query = Sale.hourly_sale_data(today,shift)
end
end
query = query.date_on(today)
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.id)
query = query.where("shift_sale_id='#{shift.id}'")
end
end
query.sum(:grand_total)
end
def self.employee_sales(today,current_user,from,to,from_time,to_time)
@@ -2074,60 +2040,6 @@ def unique_tax_profiles(order_source, customer_id)
return tax_data
end
def self.top_bottom(today,shift=nil,from=nil,to=nil,from_time=nil,to_time=nil)
if !from.nil? && !to.nil?
query = Sale.select("(SUM(i.qty) * i.price) as grand_total,SUM(i.qty) as total_item," +
" i.price as unit_price,i.product_name")
.joins("JOIN sale_items i ON i.sale_id = sales.sale_id")
if !from_time.nil? && !to_time.nil?
query = query.where("(i.qty > 0 and i.price > 0) and DATE_FORMAT(CONVERT_TZ(receipt_date,'+00:00','+06:30'),'%Y-%m-%d') between '#{from}' and '#{to}'"+
" and DATE_FORMAT(CONVERT_TZ(receipt_date,'+00:00','+06:30'),'%H:%i') between '#{from_time}' and '#{to_time}' and sale_status= 'completed'")
else
query = query.where("(i.qty > 0 and i.price > 0) and DATE_FORMAT(CONVERT_TZ(receipt_date,'+00:00','+06:30'),'%Y-%m-%d') between '#{from}' and '#{to}'"+
" and sale_status= 'completed'")
end
if !shift.nil?
query = query.where("shift_sale_id='#{shift.id}'")
end
else
query = Sale.select("(SUM(i.qty) * i.price) as grand_total,SUM(i.qty) as total_item," +
" i.price as unit_price,i.product_name")
.joins("JOIN sale_items i ON i.sale_id = sales.sale_id")
.where("(i.qty > 0 and i.price > 0) and DATE_FORMAT(receipt_date,'%Y-%m-%d') = '#{today}'"+
" and sale_status= 'completed'")
if !shift.nil?
query = query.where("shift_sale_id='#{shift.id}'")
end
end
return query
end
def self.hourly_sale_data(today,shift=nil,from=nil,to=nil,from_time=nil,to_time=nil)
if !from.nil? && !to.nil?
query = Sale.select("grand_total")
if !from_time.nil? && !to_time.nil?
query = query.where('sale_status = "completed" and DATE_FORMAT(CONVERT_TZ(receipt_date,"+00:00","+06:30"),"%Y-%m-%d") between ? and ? and DATE_FORMAT(CONVERT_TZ(receipt_date,"+00:00","+06:30"),"%H:%M") between ? and ?',from,to,from_time,to_time)
else
query = query.where('sale_status = "completed" and DATE_FORMAT(CONVERT_TZ(receipt_date,"+00:00","+06:30"),"%Y-%m-%d") between ? and ?',from,to)
end
if !shift.nil?
query = query.where("shift_sale_id='#{shift.id}'")
end
query = query.group("date_format(CONVERT_TZ(receipt_date,'+00:00', '+06:30'), '%I %p')")
.order('receipt_date')
else
query = Sale.select("grand_total")
.where('sale_status = "completed" and DATE_FORMAT(receipt_date,"%Y-%m-%d") = ?',today)
if !shift.nil?
query = query.where("shift_sale_id='#{shift.id}'")
end
query = query.group("date_format(CONVERT_TZ(receipt_date,'+00:00', '+06:30'), '%I %p')")
.order('receipt_date')
end
return query
end
def self.employee_sale(today,shift=nil,from=nil,to=nil,from_time=nil,to_time=nil)
query = Sale.joins(:cashier)
.joins(:sale_payments)
@@ -2291,7 +2203,7 @@ end
def grand_total_round
print_settings = PrintSetting.get_precision_delimiter()
if !print_settings.nil?
self.grand_total =self.grand_total.round(print_settings.precision.to_i)
self.grand_total =self.grand_total.round(precision)
end
end
@@ -2438,8 +2350,6 @@ private
def round_to_precision
if (self.total_amount != self.total_amount_was || self.total_discount != self.total_discount_was || self.total_tax != self.total_tax_was)
if (self.total_amount % 1 > 0 || self.total_discount % 1 > 0 || self.total_tax % 1 > 0)
precision = PrintSetting.get_precision_delimiter().precision.to_i
self.total_amount = self.total_amount.round(precision)
self.total_discount = self.total_discount.round(precision)
self.total_tax = self.total_tax.round(precision)