Introduce a prices_sum helper to factorize the calculation on reports

This commit is contained in:
François Turbelin
2025-12-12 13:55:55 +01:00
parent 30f702ea96
commit 8748bd76e2
22 changed files with 77 additions and 65 deletions

View File

@@ -61,4 +61,8 @@ module ReportsHelper
datetime = Time.zone.parse(datetime) if datetime.is_a? String
datetime.strftime('%Y-%m-%d %H:%M')
end
def prices_sum(prices_list)
prices_list.sum(&:to_f).round(2)
end
end

View File

@@ -88,7 +88,7 @@ module Reporting
# summary_row: proc do |group_key, items, rows|
# {
# quantity: rows.map(&:quantity).sum(&:to_i),
# price: "#{rows.map(&:price).sum(&:to_f).round(2)} #{currency_symbol}"
# price: "#{prices_sum(rows.map(&:price))} #{currency_symbol}"
# }
# end,
# summary_row_class: "", # by default 'text-bold'

View File

@@ -32,7 +32,7 @@ module Reporting
summary_row: proc do |_key, items, rows|
line_items = items.flatten
{
sum_total: rows.map(&:sum_total).sum(&:to_f).round(2),
sum_total: prices_sum(rows.map(&:sum_total)),
total_available: total_available(line_items),
unallocated: remainder(line_items),
max_quantity_excess: max_quantity_excess(line_items)

View File

@@ -96,7 +96,7 @@ module Reporting
def total_amount(line_items)
line_items.map { |li|
scaled_final_weight_volume(li)
}.sum(&:to_f).round(2)
}.sum(&:to_f).round(3)
end
def scaled_final_weight_volume(line_item)

View File

@@ -21,15 +21,15 @@ module Reporting
private
def customer_payments_total_cost(line_items)
unique_orders(line_items).map(&:total).sum(&:to_f).round(2)
prices_sum(unique_orders(line_items).map(&:total))
end
def customer_payments_amount_owed(line_items)
unique_orders(line_items).map(&:new_outstanding_balance).sum(&:to_f).round(2)
prices_sum(unique_orders(line_items).map(&:new_outstanding_balance))
end
def customer_payments_amount_paid(line_items)
unique_orders(line_items).map(&:payment_total).sum(&:to_f).round(2)
prices_sum(unique_orders(line_items).map(&:payment_total))
end
def unique_orders(line_items)

View File

@@ -32,7 +32,7 @@ module Reporting
summary_row: proc do |_key, items, rows|
line_items = items.flatten
{
sum_total: rows.map(&:sum_total).sum(&:to_f).round(2),
sum_total: prices_sum(rows.map(&:sum_total)),
units_required: units_required(line_items),
unallocated: remainder(line_items),
max_quantity_excess: max_quantity_excess(line_items)

View File

@@ -33,7 +33,7 @@ module Reporting
},
shipping_method: proc { |orders| last_completed_order(orders).shipping_method&.name },
total_orders: proc { |orders| orders.count },
total_incl_tax: proc { |orders| orders.map(&:total).sum(&:to_f).round(2) },
total_incl_tax: proc { |orders| prices_sum(orders.map(&:total)) },
last_completed_order_date: proc { |orders| last_completed_order_date(orders) },
}
end

View File

@@ -158,7 +158,7 @@ module Reporting
end
def enterprise_fees_sum(order)
amount = enterprise_fees(order).map(&:amount).sum(&:to_f).round(2)
amount = prices_sum(enterprise_fees(order).map(&:amount))
apply_voucher_on_amount(order, amount)
end
@@ -183,7 +183,7 @@ module Reporting
query = query.inclusive if included == true
query = query.additional if added == true
amount =
query.where(adjustable: enterprise_fees(order)).map(&:amount).sum(&:to_f).round(2)
prices_sum(query.where(adjustable: enterprise_fees(order)).map(&:amount))
apply_voucher_on_amount(order, amount)
end

View File

@@ -232,7 +232,7 @@ module Reporting
line_item.supplier_id == supplier_id
end
tax_for_enterprise_fees = rows.map(&:tax).sum(&:to_f).round(2)
tax_for_enterprise_fees = prices_sum(rows.map(&:tax))
total_excl_tax = total_fees_excl_tax(items) + line_items_excl_tax(line_items)
tax = tax_for_enterprise_fees + tax_for_line_items(line_items)
{
@@ -280,18 +280,18 @@ module Reporting
end
def line_items_excl_tax(line_items)
cost_of_line_items(line_items) - line_items.map(&:included_tax).sum(&:to_f).round(2)
cost_of_line_items(line_items) - prices_sum(line_items.map(&:included_tax))
end
def cost_of_line_items(line_items)
line_items.map(&:amount).sum(&:to_f).round(2)
prices_sum(line_items.map(&:amount))
end
# This query gets called twice for each set of line_items, ideally it would be cached.
def tax_for_line_items(line_items)
line_items.map do |line_item|
prices_sum(line_items.map do |line_item|
line_item.adjustments.eligible.tax.map(&:amount).sum(&:to_f)
end.sum(&:to_f).round(2)
end)
end
def included_tax_for_order_ids(order_ids, enterprise_fee_ids)

View File

@@ -23,9 +23,9 @@ module Reporting
variant: variant_name,
quantity: proc { |line_items| line_items.map(&:quantity).sum(&:to_i) },
item_price: proc { |line_items| line_items.map(&:amount).sum(&:to_f).round(2) },
item_price: proc { |line_items| prices_sum(line_items.map(&:amount)) },
item_fees_price: proc { |line_items|
line_items.map(&:amount_with_adjustments).sum(&:to_f).round(2)
prices_sum(line_items.map(&:amount_with_adjustments))
},
admin_handling_fees: proc { |_line_items| "" },
ship_price: proc { |_line_items| "" },
@@ -68,7 +68,7 @@ module Reporting
order_number: proc { |line_items| line_items.first.order.number },
date: proc { |line_items| line_items.first.order.completed_at.strftime("%F %T") },
final_weight_volume: proc { |line_items|
line_items.map(&:final_weight_volume).sum(&:to_f).round(2)
line_items.map(&:final_weight_volume).sum(&:to_f).round(3)
},
shipment_state: proc { |line_items| line_items.first.order.shipment_state },
}
@@ -129,8 +129,8 @@ module Reporting
{
hub: rows.last.hub,
customer: rows.last.customer,
item_price: rows.map(&:item_price).sum(&:to_f).round(2),
item_fees_price: rows.map(&:item_fees_price).sum(&:to_f).round(2),
item_price: prices_sum(rows.map(&:item_price)),
item_fees_price: prices_sum(rows.map(&:item_fees_price)),
admin_handling_fees: order.admin_and_handling_total,
ship_price: order.ship_total,
pay_fee_price: order.payment_fee,

View File

@@ -12,7 +12,7 @@ module Reporting
variant: variant_name,
quantity: proc { |line_items| line_items.to_a.map(&:quantity).sum(&:to_i) },
curr_cost_per_unit: proc { |line_items| line_items.first.price },
total_cost: proc { |line_items| line_items.map(&:amount).sum(&:to_f).round(2) },
total_cost: proc { |line_items| prices_sum(line_items.map(&:amount)) },
total_shipping_cost: proc { |_line_items| "" },
shipping_method: proc { |line_items| line_items.first.order.shipping_method&.name }
}
@@ -25,9 +25,9 @@ module Reporting
header: proc { |key, _items, _rows| "#{I18n.t(:report_header_hub)} #{key}" },
summary_row: proc do |_key, line_items, rows|
{
total_cost: rows.map(&:total_cost).sum(&:to_f).round(2),
total_cost: prices_sum(rows.map(&:total_cost)),
total_shipping_cost:
line_items.map(&:first).map(&:order).uniq.map(&:ship_total).sum(&:to_f).round(2)
prices_sum(line_items.map(&:first).map(&:order).uniq.map(&:ship_total))
}
end
}

View File

@@ -12,7 +12,7 @@ module Reporting
quantity: proc { |line_items| line_items.map(&:quantity).sum(&:to_i) },
total_units: proc { |line_items| total_units(line_items) },
curr_cost_per_unit: proc { |line_items| line_items.first.price },
total_cost: proc { |line_items| line_items.map(&:amount).sum(&:to_f).round(2) },
total_cost: proc { |line_items| prices_sum(line_items.map(&:amount)) },
sku: variant_sku,
producer_charges_sales_tax?: supplier_charges_sales_tax?,
product_tax_category:
@@ -27,14 +27,14 @@ module Reporting
summary_row: proc do |_key, _items, rows|
total_units = rows.map(&:total_units)
summary_total_units = if total_units.all?(&:present?)
rows.map(&:total_units).sum(&:to_f)
rows.map(&:total_units).sum(&:to_f).round(3)
else
" "
end
{
quantity: rows.map(&:quantity).sum(&:to_i),
total_units: summary_total_units,
total_cost: rows.map(&:total_cost).sum(&:to_f).round(2)
total_cost: prices_sum(rows.map(&:total_cost))
}
end
}

View File

@@ -12,7 +12,7 @@ module Reporting
hub: hub_name,
quantity: proc { |line_items| line_items.to_a.map(&:quantity).sum(&:to_i) },
curr_cost_per_unit: proc { |line_items| line_items.first.price },
total_cost: proc { |line_items| line_items.map(&:amount).sum(&:to_f).round(2) },
total_cost: proc { |line_items| prices_sum(line_items.map(&:amount)) },
shipping_method: proc { |line_items| line_items.first.order.shipping_method&.name }
}
end
@@ -32,7 +32,7 @@ module Reporting
summary_row: proc do |_key, _items, rows|
{
quantity: rows.map(&:quantity).sum(&:to_i),
total_cost: rows.map(&:total_cost).sum(&:to_f).round(2)
total_cost: prices_sum(rows.map(&:total_cost))
}
end,
}

View File

@@ -73,7 +73,7 @@ module Reporting
proc do |_key, _items, rows|
{
quantity: rows.map(&:quantity).sum(&:to_i),
price: rows.map(&:price).sum(&:to_f).round(2)
price: prices_sum(rows.map(&:price))
}
end
end

View File

@@ -8,12 +8,12 @@ module Reporting
{
payment_state: proc { |orders| payment_state(orders.first) },
distributor: proc { |orders| orders.first.distributor.name },
product_total_price: proc { |orders| orders.map(&:item_total).sum(&:to_f).round(2) },
shipping_total_price: proc { |orders| orders.map(&:ship_total).sum(&:to_f).round(2) },
product_total_price: proc { |orders| prices_sum(orders.map(&:item_total)) },
shipping_total_price: proc { |orders| prices_sum(orders.map(&:ship_total)) },
outstanding_balance_price: proc do |orders|
orders.map(&:outstanding_balance).sum(&:to_f).round(2)
prices_sum(orders.map(&:outstanding_balance))
end,
total_price: proc { |orders| orders.map(&:total).sum(&:to_f).round(2) }
total_price: proc { |orders| prices_sum(orders.map(&:total)) }
}
end
end

View File

@@ -8,13 +8,13 @@ module Reporting
{
payment_state: proc { |orders| payment_state(orders.first) },
distributor: proc { |orders| orders.first.distributor.name },
product_total_price: proc { |orders| orders.map(&:item_total).sum(&:to_f).round(2) },
shipping_total_price: proc { |orders| orders.map(&:ship_total).sum(&:to_f).round(2) },
total_price: proc { |orders| orders.map(&:total).sum(&:to_f).round(2) },
product_total_price: proc { |orders| prices_sum(orders.map(&:item_total)) },
shipping_total_price: proc { |orders| prices_sum(orders.map(&:ship_total)) },
total_price: proc { |orders| prices_sum(orders.map(&:total)) },
eft_price: proc { |orders| total_by_payment_method(orders, "EFT") },
paypal_price: proc { |orders| total_by_payment_method(orders, "PayPal") },
outstanding_balance_price: proc { |orders|
orders.map(&:outstanding_balance).sum(&:to_f).round(2)
prices_sum(orders.map(&:outstanding_balance))
}
}
end
@@ -22,9 +22,9 @@ module Reporting
private
def total_by_payment_method(orders, pay_method)
orders.map(&:payments).flatten.select { |payment|
prices_sum(orders.map(&:payments).flatten.select { |payment|
payment.completed? && payment.payment_method&.name.to_s.include?(pay_method)
}.map(&:amount).sum(&:to_f).round(2)
}.map(&:amount))
end
end
end

View File

@@ -18,7 +18,7 @@ module Reporting
payment_state: proc { |payments| payment_state(payments.first.order) },
distributor: proc { |payments| payments.first.order.distributor.name },
payment_type: proc { |payments| payments.first.payment_method&.name },
total_price: proc { |payments| payments.map(&:amount).sum(&:to_f).round(2) }
total_price: proc { |payments| prices_sum(payments.map(&:amount)) }
}
end
end

View File

@@ -60,8 +60,8 @@ module Reporting
grouped_orders.each do |orders|
voucher_adjustments = calculate_voucher_adjustments(orders)
total_incl_tax = orders.map(&:total).sum(&:to_f).round(2)
total_tax = orders.map(&:total_tax).sum(&:to_f).round(2) + voucher_adjustments
total_incl_tax = prices_sum(orders.map(&:total))
total_tax = prices_sum(orders.map(&:total_tax)) + voucher_adjustments
total_excl_tax = total_incl_tax - total_tax
@tax_data[distributor(orders).id] = {

View File

@@ -77,11 +77,11 @@ module Reporting
summary_row: proc do |_key, items, _rows|
line_items = items.flat_map(&:second).flatten.uniq
total_excl_tax =
line_items.map(&:amount).sum(&:to_f).round(2) -
line_items.map(&:included_tax).sum(&:to_f).round(2)
tax = line_items.map do |line_item|
prices_sum(line_items.map(&:amount)) -
prices_sum(line_items.map(&:included_tax))
tax = prices_sum(line_items.map do |line_item|
line_item.adjustments.eligible.tax.map(&:amount).sum(&:to_f)
end.sum(&:to_f).round(2)
end)
{
total_excl_tax:,
tax:,
@@ -127,17 +127,19 @@ module Reporting
end
def total_excl_tax(query_result_row)
line_items(query_result_row).map(&:amount).sum(&:to_f).round(2) -
line_items(query_result_row).map(&:included_tax).sum(&:to_f).round(2)
prices_sum(line_items(query_result_row).map(&:amount)) -
prices_sum(line_items(query_result_row).map(&:included_tax))
end
def tax(query_result_row)
line_items(query_result_row)&.map do |line_item|
line_item.adjustments.eligible.tax
.where(originator_id: tax_rate_id(query_result_row))
.map(&:amount)
.sum(&:to_f)
end&.sum(&:to_f)&.round(2)
prices_sum(
line_items(query_result_row).to_a.map do |line_item|
line_item.adjustments.eligible.tax
.where(originator_id: tax_rate_id(query_result_row))
.map(&:amount)
.sum(&:to_f)
end
)
end
def total_incl_tax(query_result_row)

View File

@@ -53,7 +53,7 @@ module Reporting
end
def tax_included_in(line_item)
line_item.adjustments.tax.inclusive.map(&:amount).sum(&:to_f).round(2)
prices_sum(line_item.adjustments.tax.inclusive.map(&:amount))
end
end
end

View File

@@ -207,29 +207,29 @@ module Reporting
end
def total_untaxable_products(order)
order.line_items.without_tax.map(&:amount).sum(&:to_f).round(2)
prices_sum(order.line_items.without_tax.map(&:amount))
end
def total_taxable_products(order)
order.line_items.with_tax.map(&:amount).sum(&:to_f).round(2)
prices_sum(order.line_items.with_tax.map(&:amount))
end
def total_untaxable_fees(order)
order.all_adjustments.enterprise_fee.where(tax_category: nil)
.map(&:amount).sum(&:to_f).round(2)
prices_sum(order.all_adjustments.enterprise_fee.where(tax_category: nil)
.map(&:amount))
end
def total_taxable_fees(order)
order.all_adjustments.enterprise_fee.where.not(tax_category: nil)
.map(&:amount).sum(&:to_f).round(2)
prices_sum(order.all_adjustments.enterprise_fee.where.not(tax_category: nil)
.map(&:amount))
end
def total_shipping(order)
order.all_adjustments.shipping.map(&:amount).sum(&:to_f).round(2)
prices_sum(order.all_adjustments.shipping.map(&:amount))
end
def total_transaction(order)
order.all_adjustments.payment_fee.map(&:amount).sum(&:to_f).round(2)
prices_sum(order.all_adjustments.payment_fee.map(&:amount))
end
def tax_on_shipping_s(order)
@@ -246,11 +246,11 @@ module Reporting
end
def total_untaxable_admin_adjustments(order)
order.adjustments.admin.where(tax_category: nil).map(&:amount).sum(&:to_f).round(2)
prices_sum(order.adjustments.admin.where(tax_category: nil).map(&:amount))
end
def total_taxable_admin_adjustments(order)
order.adjustments.admin.where.not(tax_category: nil).map(&:amount).sum(&:to_f).round(2)
prices_sum(order.adjustments.admin.where.not(tax_category: nil).map(&:amount))
end
def detail?

View File

@@ -21,4 +21,10 @@ RSpec.describe ReportsHelper do
expect(select_options).to eq [[payment_method.name, payment_method.id]]
end
end
describe "#prices_sum" do
it "sums to prices list roundind to 2 decimals" do
expect(helper.prices_sum([1, nil, 2.333333, 1.5, 2.0])).to eq(6.83)
end
end
end