sales_tax_totals_by_order report

This commit is contained in:
Mohamed ABDELLANI
2023-01-06 15:25:53 +01:00
parent 4e2430ea58
commit c43834915d
5 changed files with 634 additions and 1 deletions

View File

@@ -0,0 +1,13 @@
.row
.alpha.two.columns= label_tag nil, t(:report_producers)
.omega.fourteen.columns= select_tag(:supplier_id_in, options_from_collection_for_select(@data.orders_suppliers, :id, :name, params[:supplier_id_in]), {class: "select2 fullwidth", multiple: true})
.row
.alpha.two.columns= label_tag nil, t(:report_customers_cycle)
.omega.fourteen.columns
= f.select(:order_cycle_id_in, report_order_cycle_options(@data.order_cycles), {selected: params.dig(:q, :order_cycle_id_in)}, {class: "select2 fullwidth", multiple: true})
.row
.alpha.two.columns= label_tag nil, t(:report_customers)
.omega.fourteen.columns
= f.select(:customer_id_in, customer_email_options(@data.order_customers), {selected: params.dig(:q, :customer_id_in)}, {class: "select2 fullwidth", multiple: true})

View File

@@ -1416,6 +1416,7 @@ en:
payment_methods: Payment Methods Report
delivery: Delivery Report
sales_tax_totals_by_producer: Sales Tax Totals By Producer
sales_tax_totals_by_order: Sales Tax Totals By Order
tax_types: Tax Types
tax_rates: Tax Rates
pack_by_customer: Pack By Customer

View File

@@ -71,7 +71,8 @@ module Reporting
[
[i18n_translate("tax_types"), :tax_types],
[i18n_translate("tax_rates"), :tax_rates],
[i18n_translate("sales_tax_totals_by_producer"), :sales_tax_totals_by_producer]
[i18n_translate("sales_tax_totals_by_producer"), :sales_tax_totals_by_producer],
[i18n_translate("sales_tax_totals_by_order"), :sales_tax_totals_by_order]
]
end

View File

@@ -0,0 +1,194 @@
# frozen_string_literal: true
# rubocop:disable Metrics/ClassLength
module Reporting
module Reports
module SalesTax
class SalesTaxTotalsByOrder < Base
def search
report_line_items.orders
end
def order_permissions
@order_permissions ||= ::Permissions::Order.new(user, ransack_params)
end
def report_line_items
# Needed to filter by supplier_id
@report_line_items ||= Reporting::LineItems.new(order_permissions, params)
end
def query_result
# We'll group the line items by
# [tax_rate_id, order_id]
orders = report_line_items.list.map(&:order).uniq
orders.flat_map(&join_tax_rate)
.group_by(&group_key)
.map(&change_root_to_order)
end
def join_tax_rate
proc do |order|
tax_rate_ids = order.all_adjustments.tax.pluck("distinct(originator_id)")
tax_rate_ids << nil if tax_rate_ids.empty?
tax_rate_ids.map do |tax_rate_id|
{
tax_rate_id: tax_rate_id,
order: order
}
end
end
end
def group_key
proc do |hash|
[
hash[:tax_rate_id],
hash[:order].id
]
end
end
def change_root_to_order
proc do |key, value|
[key, value.first[:order]]
end
end
def columns
{
distributor: :distributor,
order_cycle: :order_cycle,
order_number: :order_number,
tax_category: :tax_category,
tax_rate_name: :tax_rate_name,
tax_rate: :tax_rate_amount,
total_excl_tax: :total_excl_tax,
tax: :tax_rate_total,
total_incl_tax: :total_incl_tax,
first_name: :first_name,
last_name: :last_name,
code: :code,
email: :email,
}
end
def columns_format
{
tax_rate: :percentage
}
end
def rules
[
{
group_by: :distributor,
},
{
group_by: :order_cycle,
},
{
group_by: :order_number,
summary_row: proc do |_key, items, _rows|
order = items.first.second
{
total_excl_tax: order.total - order.total_tax,
tax: order.total_tax,
total_incl_tax: order.total,
first_name: order.customer&.first_name,
last_name: order.customer&.last_name,
code: order.customer&.code,
email: order.email
}
end
}
]
end
def distributor(query_result_row)
order(query_result_row).distributor&.name
end
def order_cycle(query_result_row)
order(query_result_row).order_cycle&.name
end
def order_number(query_result_row)
order(query_result_row).number
end
def tax_category(query_result_row)
tax_rate(query_result_row)&.tax_category&.name
end
def tax_rate_name(query_result_row)
tax_rate(query_result_row)&.name
end
def tax_rate_amount(query_result_row)
tax_rate(query_result_row)&.amount
end
def total_excl_tax(query_result_row)
order(query_result_row).total - order(query_result_row).total_tax
end
def tax_rate_total(query_result_row)
order(query_result_row).all_adjustments
.tax
.where(originator_id: tax_rate_id(query_result_row))
.pluck('sum(amount)').first || 0
end
def total_incl_tax(query_result_row)
order(query_result_row).total -
order(query_result_row).total_tax +
tax_rate_total(query_result_row)
end
def first_name(query_result_row)
order(query_result_row).customer&.first_name
end
def last_name(query_result_row)
order(query_result_row).customer&.last_name
end
def code(query_result_row)
order(query_result_row).customer&.code
end
def email(query_result_row)
order(query_result_row).email
end
def tax_rate(query_result_row)
targeted_tax_rate_id = tax_rate_id(query_result_row)
tax_rates(query_result_row).find do |tax_rate|
tax_rate.id == targeted_tax_rate_id
end
end
def tax_rate_id(query_result_row)
key(query_result_row).first
end
def tax_rates(query_result_row)
order(query_result_row).all_adjustments
.tax
.select("distinct(originator_id)", "originator_type")
.map(&:originator)
end
def key(query_result_row)
query_result_row.first
end
def order(query_result_row)
query_result_row.second
end
end
end
end
end
# rubocop:enable Metrics/ClassLength

View File

@@ -0,0 +1,424 @@
# frozen_string_literal: true
require 'system_helper'
describe "Sales Tax Totals By order" do
# Scenarion 1: added tax
# 1 producer
# 1 distributor
# product that costs 100$
# shipping costs 10$
# the packaging cost is 5$
# 1 order with 1 line item
# the line item match 2 tax rates: country (2.5%) and state (1.5%)
let!(:table_header){
[
"Distributor",
"Order Cycle",
"Order Number",
"Tax Category",
"Tax Rate Name",
"Tax Rate",
"Total excl. Tax ($)",
"Tax",
"Total incl. Tax ($)",
"First Name",
"Last Name",
"Code",
"Email"
].join(" ").upcase
}
let!(:state_zone){ create(:zone_with_state_member) }
let!(:country_zone){ create(:zone_with_member) }
let!(:tax_category){ create(:tax_category, name: 'tax_category') }
let!(:state_tax_rate){
create(:tax_rate, zone: state_zone, tax_category: tax_category,
name: 'State', amount: 0.015)
}
let!(:country_tax_rate){
create(:tax_rate, zone: country_zone, tax_category: tax_category,
name: 'Country', amount: 0.025)
}
let!(:ship_address){
create(:ship_address,
state: state_zone.members.first.zoneable,
country: country_zone.members.first.zoneable)
}
let!(:variant){ create(:variant) }
let!(:product){ variant.product }
let!(:supplier){ create(:supplier_enterprise, name: 'Supplier', charges_sales_tax: true) }
let!(:distributor){
create(:distributor_enterprise_with_tax, name: 'Distributor', charges_sales_tax: true)
}
let!(:distributor_fee){
create(:enterprise_fee, :flat_rate, amount: 5,
tax_category_id: tax_category.id,
enterprise_id: distributor.id)
}
let!(:payment_method){ create(:payment_method, :flat_rate) }
let!(:shipping_method){
create(:shipping_method, :flat_rate, amount: 10, tax_category_id: tax_category.id)
}
let!(:order){ create(:order_with_distributor, distributor: distributor) }
let!(:order_cycle){
create(:simple_order_cycle, name: 'oc1', suppliers: [supplier], distributors: [distributor],
variants: [variant])
}
let!(:customer1){
create(:customer, enterprise: create(:enterprise),
user: create(:user),
first_name: 'cfname', last_name: 'clname', code: 'ABC123')
}
let(:admin){ create(:admin_user) }
before do
order_cycle.cached_outgoing_exchanges.first.enterprise_fees << distributor_fee
distributor.shipping_methods << shipping_method
distributor.payment_methods << payment_method
product.update!(
tax_category_id: tax_category.id,
supplier_id: supplier.id
)
order.update!(
number: 'ORDER_NUMBER_1',
order_cycle_id: order_cycle.id,
ship_address_id: ship_address.id,
customer_id: customer1.id,
email: 'order1@example.com'
)
order.line_items.create(variant: variant, quantity: 1, price: 100)
end
context 'added tax' do
before do
# the enterprise fees can be known only when the user selects the variants
# we'll need to create them by calling recreate_all_fees!
order.recreate_all_fees!
OrderWorkflow.new(order).complete!
end
it "generates the report" do
login_as admin
visit admin_reports_path
click_on I18n.t("admin.reports.sales_tax_totals_by_order")
expect(page).to have_button("Go")
click_on "Go"
expect(page.find("table.report__table thead tr").text).to have_content(table_header)
expect(page.find("table.report__table tbody").text).to have_content([
"Distributor",
"oc1",
"ORDER_NUMBER_1",
"tax_category",
"State",
"1.5 %",
"115.0",
"1.73",
"116.73",
"cfname",
"clname",
"ABC123",
"order1@example.com"
].join(" "))
expect(page.find("table.report__table tbody").text).to have_content([
"Distributor",
"oc1",
"ORDER_NUMBER_1",
"tax_category",
"Country",
"2.5 %",
"115.0",
"2.88",
"117.88",
"cfname",
"clname",
"ABC123",
"order1@example.com"
].join(" "))
expect(page.find("table.report__table tbody").text).to have_content([
"TOTAL",
"115.0",
"4.61",
"119.61",
"cfname",
"clname",
"ABC123",
"order1@example.com"
].join(" "))
end
end
context 'included tax' do
before do
state_tax_rate.update!({ included_in_price: true })
country_tax_rate.update!({ included_in_price: true })
order.recreate_all_fees!
OrderWorkflow.new(order).complete!
end
it "generates the report" do
login_as admin
visit admin_reports_path
click_on I18n.t("admin.reports.sales_tax_totals_by_order")
expect(page).to have_button("Go")
click_on "Go"
expect(page.find("table.report__table thead tr").text).to have_content(table_header)
expect(page.find("table.report__table tbody").text).to have_content([
"Distributor",
"oc1",
"ORDER_NUMBER_1",
"tax_category",
"State",
"1.5 %",
"110.5",
"1.7",
"112.2",
"cfname",
"clname",
"ABC123",
"order1@example.com"
].join(" "))
expect(page.find("table.report__table tbody").text).to have_content([
"Distributor",
"oc1",
"ORDER_NUMBER_1",
"tax_category",
"Country",
"2.5 %",
"110.5",
"2.8",
"113.3",
"cfname",
"clname",
"ABC123",
"order1@example.com"
].join(" "))
expect(page.find("table.report__table tbody").text).to have_content([
"TOTAL",
"110.5",
"4.5",
"115.0",
"cfname",
"clname",
"ABC123",
"order1@example.com"
].join(" "))
end
end
context 'should filter by customer' do
let!(:order2){ create(:order_with_distributor, distributor: distributor) }
let!(:customer2){ create(:customer, enterprise: create(:enterprise), user: create(:user)) }
let!(:customer_email_dropdown_selector){ "#s2id_q_customer_id_in" }
let!(:table_raw_selector){ "table.report__table tbody tr" }
let(:customer1_country_tax_rate_row){
[
"Distributor",
"oc1",
"ORDER_NUMBER_1",
"tax_category",
"Country",
"2.5 %",
"115.0",
"2.88",
"117.88",
"cfname",
"clname",
"ABC123",
"order1@example.com"
].join(" ")
}
let(:customer1_state_tax_rate_row){
[
"Distributor",
"oc1",
"ORDER_NUMBER_1",
"tax_category",
"State",
"1.5 %",
"115.0",
"1.73",
"116.73",
"cfname",
"clname",
"ABC123",
"order1@example.com"
].join(" ")
}
let(:customer1_summary_row){
[
"TOTAL",
"115.0",
"4.61",
"119.61",
"cfname",
"clname",
"ABC123",
"order1@example.com"
].join(" ")
}
let(:customer2_country_tax_rate_row){
[
"Distributor",
"oc1",
"ORDER_NUMBER_2",
"tax_category",
"Country",
"2.5 %",
"215.0",
"5.38",
"220.38",
"c2fname",
"c2lname",
"DEF456",
"order2@example.com"
].join(" ")
}
let(:customer2_state_tax_rate_row){
[
"Distributor",
"oc1",
"ORDER_NUMBER_2",
"tax_category",
"State",
"1.5 %",
"215.0",
"3.23",
"218.23",
"c2fname",
"c2lname",
"DEF456",
"order2@example.com"
].join(" ")
}
let(:customer2_summary_row){
[
"TOTAL",
"215.0",
"8.61",
"223.61",
"c2fname",
"c2lname",
"DEF456",
"order2@example.com"
].join(" ")
}
before do
order.recreate_all_fees!
OrderWorkflow.new(order).complete!
customer2.update!({ first_name: 'c2fname', last_name: 'c2lname', code: 'DEF456' })
order2.line_items.create({ variant: variant, quantity: 1, price: 200 })
order2.update!({
order_cycle_id: order_cycle.id,
ship_address_id: customer2.bill_address_id,
customer_id: customer2.id,
number: 'ORDER_NUMBER_2',
email: 'order2@example.com'
})
order2.recreate_all_fees!
OrderWorkflow.new(order2).complete!
login_as admin
visit admin_reports_path
click_on I18n.t("admin.reports.sales_tax_totals_by_order")
end
it "should load all the orders" do
expect(page).to have_button("Go")
click_on "Go"
expect(page.find("table.report__table thead tr").text).to have_content(table_header)
expect(
page.find("table.report__table tbody").text
).to have_content(customer1_country_tax_rate_row)
expect(
page.find("table.report__table tbody").text
).to have_content(customer1_state_tax_rate_row)
expect(page.find("table.report__table tbody").text).to have_content(customer1_summary_row)
expect(
page.find("table.report__table tbody").text
).to have_content(customer2_country_tax_rate_row)
expect(
page.find("table.report__table tbody").text
).to have_content(customer2_state_tax_rate_row)
expect(page.find("table.report__table tbody").text).to have_content(customer2_summary_row)
expect(page).to have_selector(table_raw_selector, count: 6)
end
it "should filter customer1 orders" do
page.find(customer_email_dropdown_selector).click
find('li', text: customer1.email).click
expect(page).to have_button("Go")
click_on "Go"
expect(page.find("table.report__table thead tr").text).to have_content(table_header)
expect(
page.find("table.report__table tbody").text
).to have_content(customer1_country_tax_rate_row)
expect(
page.find("table.report__table tbody").text
).to have_content(customer1_state_tax_rate_row)
expect(page.find("table.report__table tbody").text).to have_content(customer1_summary_row)
expect(page).to have_selector(table_raw_selector, count: 3)
end
it "should filter customer2 orders" do
page.find(customer_email_dropdown_selector).click
find('li', text: customer2.email).click
expect(page).to have_button("Go")
click_on "Go"
expect(page.find("table.report__table thead tr").text).to have_content(table_header)
expect(
page.find("table.report__table tbody").text
).to have_content(customer2_country_tax_rate_row)
expect(
page.find("table.report__table tbody").text
).to have_content(customer2_state_tax_rate_row)
expect(page.find("table.report__table tbody").text).to have_content(customer2_summary_row)
expect(page).to have_selector(table_raw_selector, count: 3)
end
it "should filter customer1 and customer2 orders" do
page.find(customer_email_dropdown_selector).click
find('li', text: customer1.email).click
page.find(customer_email_dropdown_selector).click
find('li', text: customer2.email).click
click_on "Go"
expect(page.find("table.report__table thead tr").text).to have_content(table_header)
expect(
page.find("table.report__table tbody").text
).to have_content(customer1_country_tax_rate_row)
expect(
page.find("table.report__table tbody").text
).to have_content(customer1_state_tax_rate_row)
expect(page.find("table.report__table tbody").text).to have_content(customer1_summary_row)
expect(
page.find("table.report__table tbody").text
).to have_content(customer2_country_tax_rate_row)
expect(
page.find("table.report__table tbody").text
).to have_content(customer2_state_tax_rate_row)
expect(page.find("table.report__table tbody").text).to have_content(customer2_summary_row)
expect(page).to have_selector(table_raw_selector, count: 6)
end
end
end