feat(api,web): peso total (kg) e cubagem (m3) do pedido na impressao
- vw_produtos passa a expor vol_m3 (coluna nova no FIM da view - CREATE OR REPLACE exige; aplicada no dev) - PedidoDetail calcula pesoTotal/m3Total (qtd x peso_liquido/vol_m3), tanto para pedidos SAR quanto ERP - Impressao mostra "Peso total: X kg" e "Volume: Y m3" ao lado dos totais (some quando zerado) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1022,14 +1022,31 @@ export class OrdersService {
|
||||
const grupoRows =
|
||||
prisma && prodIds.length > 0
|
||||
? await prisma.$queryRawUnsafe<
|
||||
{ id_erp: number; cod_grupo: number | null; cod_subgrupo: number | null }[]
|
||||
{
|
||||
id_erp: number;
|
||||
cod_grupo: number | null;
|
||||
cod_subgrupo: number | null;
|
||||
peso_liquido: string | null;
|
||||
vol_m3: string | null;
|
||||
}[]
|
||||
>(
|
||||
`SELECT id_erp, cod_grupo, cod_subgrupo FROM vw_produtos
|
||||
`SELECT id_erp, cod_grupo, cod_subgrupo, peso_liquido::text, vol_m3::text
|
||||
FROM vw_produtos
|
||||
WHERE id_empresa = ${idMatriz} AND id_erp IN (${prodIds.join(',')})`,
|
||||
)
|
||||
: [];
|
||||
const grupoMap = new Map(grupoRows.map((g) => [Number(g.id_erp), g]));
|
||||
|
||||
// Peso total (kg) e cubagem (m3) do pedido: soma de qtd x peso/vol do produto
|
||||
let pesoTotal = 0;
|
||||
let m3Total = 0;
|
||||
for (const it of o.itens) {
|
||||
const prod = grupoMap.get(it.idProduto);
|
||||
const qtd = Number(it.qtd);
|
||||
pesoTotal += qtd * Number(prod?.peso_liquido ?? 0);
|
||||
m3Total += qtd * Number(prod?.vol_m3 ?? 0);
|
||||
}
|
||||
|
||||
return {
|
||||
id: o.id,
|
||||
numPedSar: o.numPedSar,
|
||||
@@ -1042,6 +1059,8 @@ export class OrdersService {
|
||||
dtPedido: o.dtPedido.toISOString(),
|
||||
idPauta: o.idPauta,
|
||||
codFormapag: o.codFormapag,
|
||||
pesoTotal: pesoTotal.toFixed(3),
|
||||
m3Total: m3Total.toFixed(4),
|
||||
total: decimalToString(o.total),
|
||||
descontoPerc: decimalToString(o.descontoPerc),
|
||||
obs: o.obs,
|
||||
@@ -1132,6 +1151,8 @@ export class OrdersService {
|
||||
preco_unitario: string;
|
||||
desconto_perc: string;
|
||||
total: string;
|
||||
peso_liquido: string | null;
|
||||
vol_m3: string | null;
|
||||
}
|
||||
|
||||
const vendedorFilter =
|
||||
@@ -1164,7 +1185,8 @@ export class OrdersService {
|
||||
SELECT ei.ordem, ei.id_produto,
|
||||
TRIM(p.codigo) AS codigo, TRIM(p.descricao) AS descricao,
|
||||
ei.qtd::text, ei.preco_unitario::text,
|
||||
ei.desconto_perc::text, ei.total::text
|
||||
ei.desconto_perc::text, ei.total::text,
|
||||
p.peso_liquido::text AS peso_liquido, p.vol_m3::text AS vol_m3
|
||||
FROM vw_peditens_erp ei
|
||||
LEFT JOIN vw_produtos p
|
||||
ON p.id_erp = ei.id_produto
|
||||
@@ -1177,6 +1199,15 @@ export class OrdersService {
|
||||
if (!headerRows[0]) throw new NotFoundException(`Pedido ERP ${idPedido} não encontrado`);
|
||||
const h = headerRows[0];
|
||||
|
||||
const pesoTotalErp = itemRows.reduce(
|
||||
(acc, it) => acc + Number(it.qtd) * Number(it.peso_liquido ?? 0),
|
||||
0,
|
||||
);
|
||||
const m3TotalErp = itemRows.reduce(
|
||||
(acc, it) => acc + Number(it.qtd) * Number(it.vol_m3 ?? 0),
|
||||
0,
|
||||
);
|
||||
|
||||
return {
|
||||
id: `erp-${h.id_pedido}`,
|
||||
numPedSar: (h.num_ped_sar ?? '').trim(),
|
||||
@@ -1207,6 +1238,8 @@ export class OrdersService {
|
||||
aprovadoEm: null,
|
||||
motivoRecusa: null,
|
||||
idempotencyKey: null,
|
||||
pesoTotal: pesoTotalErp.toFixed(3),
|
||||
m3Total: m3TotalErp.toFixed(4),
|
||||
itens: itemRows.map((it) => ({
|
||||
id: `${idPedido}-${it.ordem}`,
|
||||
idProduto: Number(it.id_produto),
|
||||
|
||||
Reference in New Issue
Block a user