All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m12s
118 lines
3.3 KiB
TypeScript
118 lines
3.3 KiB
TypeScript
import type { DateRange, OrderData, StockData } from '../types';
|
|
import { getBaseProductName, getOrderItemRevenue, isOrderInDateRange } from './orders';
|
|
|
|
export interface ProductSummary {
|
|
id: string;
|
|
name: string;
|
|
totalSold: number;
|
|
revenue: number;
|
|
lastPrice: number;
|
|
stock: number;
|
|
}
|
|
|
|
export interface ProductDetailsMetrics {
|
|
productInfo: {
|
|
id: string;
|
|
name: string;
|
|
price: number;
|
|
} | null;
|
|
chartData: Array<{
|
|
date: string;
|
|
value: number;
|
|
}>;
|
|
totalSold: number;
|
|
totalRevenue: number;
|
|
}
|
|
|
|
export const buildProductsSummary = (
|
|
ordersData: OrderData[],
|
|
stockData: StockData[],
|
|
dateRange: DateRange,
|
|
searchTerm: string
|
|
): ProductSummary[] => {
|
|
const productMap: Record<string, ProductSummary> = {};
|
|
|
|
stockData.forEach(item => {
|
|
productMap[item.produto_id] = {
|
|
id: item.produto_id,
|
|
name: item.nome,
|
|
totalSold: 0,
|
|
revenue: 0,
|
|
lastPrice: 0,
|
|
stock: item.saldo || 0
|
|
};
|
|
});
|
|
|
|
ordersData.forEach(order => {
|
|
if (!isOrderInDateRange(order, dateRange)) return;
|
|
|
|
if (!productMap[order.ID_Produto]) {
|
|
productMap[order.ID_Produto] = {
|
|
id: order.ID_Produto,
|
|
name: getBaseProductName(order.Descricao_Produto),
|
|
totalSold: 0,
|
|
revenue: 0,
|
|
lastPrice: order.Valor_Unitario,
|
|
stock: 0
|
|
};
|
|
}
|
|
|
|
if (productMap[order.ID_Produto].name === 'Unknown' || !productMap[order.ID_Produto].name) {
|
|
productMap[order.ID_Produto].name = getBaseProductName(order.Descricao_Produto);
|
|
}
|
|
|
|
productMap[order.ID_Produto].totalSold += order.Quantidade;
|
|
productMap[order.ID_Produto].revenue += getOrderItemRevenue(order);
|
|
productMap[order.ID_Produto].lastPrice = order.Valor_Unitario;
|
|
});
|
|
|
|
const normalizedSearch = searchTerm.trim().toLowerCase();
|
|
const products = Object.values(productMap);
|
|
const filteredProducts = normalizedSearch
|
|
? products.filter(product => product.name.toLowerCase().includes(normalizedSearch) || product.id.includes(searchTerm))
|
|
: products;
|
|
|
|
return filteredProducts.sort((a, b) => b.totalSold - a.totalSold);
|
|
};
|
|
|
|
export const buildProductDetailsMetrics = (
|
|
ordersData: OrderData[],
|
|
productId: string | undefined,
|
|
dateRange: DateRange
|
|
): ProductDetailsMetrics => {
|
|
const productOrders = ordersData.filter(order => order.ID_Produto === productId);
|
|
|
|
if (productOrders.length === 0) {
|
|
return { productInfo: null, chartData: [], totalSold: 0, totalRevenue: 0 };
|
|
}
|
|
|
|
const productInfo = {
|
|
id: productOrders[0].ID_Produto,
|
|
name: getBaseProductName(productOrders[0].Descricao_Produto),
|
|
price: productOrders[0].Valor_Unitario
|
|
};
|
|
|
|
const salesByDate: Record<string, number> = {};
|
|
let totalSold = 0;
|
|
let totalRevenue = 0;
|
|
|
|
productOrders.forEach(order => {
|
|
if (!isOrderInDateRange(order, dateRange)) return;
|
|
|
|
salesByDate[order.Data_Pedido] = (salesByDate[order.Data_Pedido] || 0) + order.Quantidade;
|
|
totalSold += order.Quantidade;
|
|
totalRevenue += getOrderItemRevenue(order);
|
|
});
|
|
|
|
const chartData = Object.keys(salesByDate).map(date => ({
|
|
date,
|
|
value: salesByDate[date]
|
|
})).sort((a, b) => {
|
|
const [da, ma, ya] = a.date.split('-').map(Number);
|
|
const [db, mb, yb] = b.date.split('-').map(Number);
|
|
return new Date(ya, ma - 1, da).getTime() - new Date(yb, mb - 1, db).getTime();
|
|
});
|
|
|
|
return { productInfo, chartData, totalSold, totalRevenue };
|
|
};
|