Обновлены категории товаров с "Упаковка" на "Расходники" в различных компонентах и моделях. Добавлены уведомления о непринятых поставках и обновлены соответствующие GraphQL запросы и резолверы для поддержки новых данных. Оптимизирована логика отображения и обработки данных в интерфейсе.
This commit is contained in:
@ -9,7 +9,12 @@ import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
|
||||
import { Sidebar } from "@/components/dashboard/sidebar";
|
||||
import { useSidebar } from "@/hooks/useSidebar";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { GET_MY_COUNTERPARTIES, GET_SUPPLY_ORDERS } from "@/graphql/queries";
|
||||
import {
|
||||
GET_MY_COUNTERPARTIES,
|
||||
GET_SUPPLY_ORDERS,
|
||||
GET_WAREHOUSE_PRODUCTS,
|
||||
GET_MY_SUPPLIES, // Добавляем импорт для загрузки расходников
|
||||
} from "@/graphql/queries";
|
||||
import { toast } from "sonner";
|
||||
import {
|
||||
Package,
|
||||
@ -180,13 +185,33 @@ export function FulfillmentWarehouseDashboard() {
|
||||
} = useQuery(GET_SUPPLY_ORDERS, {
|
||||
fetchPolicy: "cache-and-network",
|
||||
});
|
||||
const {
|
||||
data: productsData,
|
||||
loading: productsLoading,
|
||||
error: productsError,
|
||||
refetch: refetchProducts,
|
||||
} = useQuery(GET_WAREHOUSE_PRODUCTS, {
|
||||
fetchPolicy: "cache-and-network",
|
||||
});
|
||||
|
||||
// Получаем данные партнеров-селлеров и заказов
|
||||
// Загружаем расходники фулфилмента
|
||||
const {
|
||||
data: suppliesData,
|
||||
loading: suppliesLoading,
|
||||
error: suppliesError,
|
||||
refetch: refetchSupplies,
|
||||
} = useQuery(GET_MY_SUPPLIES, {
|
||||
fetchPolicy: "cache-and-network",
|
||||
});
|
||||
|
||||
// Получаем данные магазинов, заказов и товаров
|
||||
const allCounterparties = counterpartiesData?.myCounterparties || [];
|
||||
const sellerPartners = allCounterparties.filter(
|
||||
(partner: any) => partner.type === "SELLER"
|
||||
(partner: { type: string }) => partner.type === "SELLER"
|
||||
);
|
||||
const supplyOrders: SupplyOrder[] = ordersData?.supplyOrders || [];
|
||||
const allProducts = productsData?.warehouseProducts || [];
|
||||
const mySupplies = suppliesData?.mySupplies || []; // Добавляем расходники
|
||||
|
||||
// Логирование для отладки
|
||||
console.log("🏪 Данные склада фулфилмента:", {
|
||||
@ -201,13 +226,147 @@ export function FulfillmentWarehouseDashboard() {
|
||||
ordersCount: supplyOrders.length,
|
||||
deliveredOrders: supplyOrders.filter((o) => o.status === "DELIVERED")
|
||||
.length,
|
||||
productsCount: allProducts.length,
|
||||
suppliesCount: mySupplies.length, // Добавляем логирование расходников
|
||||
supplies: mySupplies.map((s: any) => ({
|
||||
id: s.id,
|
||||
name: s.name,
|
||||
currentStock: s.currentStock,
|
||||
category: s.category,
|
||||
supplier: s.supplier,
|
||||
})),
|
||||
products: allProducts.map((p: any) => ({
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
article: p.article,
|
||||
organizationName: p.organization?.name || p.organization?.fullName,
|
||||
organizationType: p.organization?.type,
|
||||
})),
|
||||
// Добавляем анализ соответствия товаров и расходников
|
||||
productSupplyMatching: allProducts.map((product: any) => {
|
||||
const matchingSupply = mySupplies.find((supply: any) => {
|
||||
return (
|
||||
supply.name.toLowerCase() === product.name.toLowerCase() ||
|
||||
supply.name
|
||||
.toLowerCase()
|
||||
.includes(product.name.toLowerCase().split(" ")[0])
|
||||
);
|
||||
});
|
||||
return {
|
||||
productName: product.name,
|
||||
matchingSupplyName: matchingSupply?.name,
|
||||
matchingSupplyStock: matchingSupply?.currentStock,
|
||||
hasMatch: !!matchingSupply,
|
||||
};
|
||||
}),
|
||||
counterpartiesLoading,
|
||||
ordersLoading,
|
||||
productsLoading,
|
||||
suppliesLoading, // Добавляем статус загрузки расходников
|
||||
counterpartiesError: counterpartiesError?.message,
|
||||
ordersError: ordersError?.message,
|
||||
productsError: productsError?.message,
|
||||
suppliesError: suppliesError?.message, // Добавляем ошибки загрузки расходников
|
||||
});
|
||||
|
||||
// Подсчитываем статистику на основе реальных данных партнеров-селлеров
|
||||
// Расчет поступлений расходников за сутки (выносим отдельно для использования в storeData)
|
||||
const suppliesReceivedToday = useMemo(() => {
|
||||
const deliveredOrders = supplyOrders.filter(
|
||||
(o) => o.status === "DELIVERED"
|
||||
);
|
||||
|
||||
// Подсчитываем расходники селлера из доставленных заказов за последние сутки
|
||||
const oneDayAgo = new Date();
|
||||
oneDayAgo.setDate(oneDayAgo.getDate() - 1);
|
||||
|
||||
const recentDeliveredOrders = deliveredOrders.filter((order) => {
|
||||
const deliveryDate = new Date(order.deliveryDate);
|
||||
return deliveryDate >= oneDayAgo && order.fulfillmentCenter?.id; // За последние сутки
|
||||
});
|
||||
|
||||
const realSuppliesReceived = recentDeliveredOrders.reduce(
|
||||
(sum, order) => sum + order.totalItems,
|
||||
0
|
||||
);
|
||||
|
||||
// Логирование для отладки
|
||||
console.log("📦 Анализ поставок расходников за сутки:", {
|
||||
totalDeliveredOrders: deliveredOrders.length,
|
||||
recentDeliveredOrders: recentDeliveredOrders.length,
|
||||
recentOrders: recentDeliveredOrders.map((order) => ({
|
||||
id: order.id,
|
||||
deliveryDate: order.deliveryDate,
|
||||
totalItems: order.totalItems,
|
||||
status: order.status,
|
||||
})),
|
||||
realSuppliesReceived,
|
||||
oneDayAgo: oneDayAgo.toISOString(),
|
||||
});
|
||||
|
||||
// Возвращаем реальное значение без fallback
|
||||
return realSuppliesReceived;
|
||||
}, [supplyOrders]);
|
||||
|
||||
// Расчет использованных расходников за сутки (пока всегда 0, так как нет данных об использовании)
|
||||
const suppliesUsedToday = useMemo(() => {
|
||||
// TODO: Здесь должна быть логика подсчета использованных расходников
|
||||
// Пока возвращаем 0, так как нет данных об использовании
|
||||
return 0;
|
||||
}, []);
|
||||
|
||||
// Расчет изменений товаров за сутки (реальные данные)
|
||||
const productsReceivedToday = useMemo(() => {
|
||||
// Товары, поступившие за сутки из доставленных заказов
|
||||
const deliveredOrders = supplyOrders.filter(
|
||||
(o) => o.status === "DELIVERED"
|
||||
);
|
||||
const oneDayAgo = new Date();
|
||||
oneDayAgo.setDate(oneDayAgo.getDate() - 1);
|
||||
|
||||
const recentDeliveredOrders = deliveredOrders.filter((order) => {
|
||||
const deliveryDate = new Date(order.deliveryDate);
|
||||
return deliveryDate >= oneDayAgo && order.fulfillmentCenter?.id;
|
||||
});
|
||||
|
||||
const realProductsReceived = recentDeliveredOrders.reduce(
|
||||
(sum, order) => sum + (order.totalItems || 0),
|
||||
0
|
||||
);
|
||||
|
||||
// Логирование для отладки
|
||||
console.log("📦 Анализ поставок товаров за сутки:", {
|
||||
totalDeliveredOrders: deliveredOrders.length,
|
||||
recentDeliveredOrders: recentDeliveredOrders.length,
|
||||
recentOrders: recentDeliveredOrders.map((order) => ({
|
||||
id: order.id,
|
||||
deliveryDate: order.deliveryDate,
|
||||
totalItems: order.totalItems,
|
||||
status: order.status,
|
||||
})),
|
||||
realProductsReceived,
|
||||
oneDayAgo: oneDayAgo.toISOString(),
|
||||
});
|
||||
|
||||
return realProductsReceived;
|
||||
}, [supplyOrders]);
|
||||
|
||||
const productsUsedToday = useMemo(() => {
|
||||
// Товары, отправленные/использованные за сутки (пока 0, нет данных)
|
||||
return 0;
|
||||
}, []);
|
||||
|
||||
// Логирование статистики расходников для отладки
|
||||
console.log("📊 Статистика расходников селлера:", {
|
||||
suppliesReceivedToday,
|
||||
suppliesUsedToday,
|
||||
totalSellerSupplies: mySupplies.reduce(
|
||||
(sum: number, supply: any) => sum + (supply.currentStock || 0),
|
||||
0
|
||||
),
|
||||
netChange: suppliesReceivedToday - suppliesUsedToday,
|
||||
});
|
||||
|
||||
// Подсчитываем статистику на основе реальных данных из заказов поставок
|
||||
const warehouseStats: WarehouseStats = useMemo(() => {
|
||||
const inTransitOrders = supplyOrders.filter(
|
||||
(o) => o.status === "IN_TRANSIT"
|
||||
@ -216,134 +375,381 @@ export function FulfillmentWarehouseDashboard() {
|
||||
(o) => o.status === "DELIVERED"
|
||||
);
|
||||
|
||||
// Генерируем статистику на основе количества партнеров-селлеров
|
||||
const baseMultiplier = sellerPartners.length * 100;
|
||||
// Подсчитываем общее количество товаров из всех доставленных заказов
|
||||
const totalProductsFromOrders = allProducts.reduce(
|
||||
(sum, product: any) => sum + (product.orderedQuantity || 0),
|
||||
0
|
||||
);
|
||||
|
||||
// Подсчитываем реальное количество расходников селлера из таблицы supplies
|
||||
const totalSellerSupplies = mySupplies.reduce(
|
||||
(sum: number, supply: any) => sum + (supply.currentStock || 0),
|
||||
0
|
||||
);
|
||||
|
||||
return {
|
||||
products: {
|
||||
current: baseMultiplier + 450,
|
||||
change: 105,
|
||||
current: totalProductsFromOrders, // Реальное количество товаров на складе
|
||||
change: productsReceivedToday - productsUsedToday, // Реальное изменение за сутки
|
||||
},
|
||||
goods: {
|
||||
current: Math.floor(baseMultiplier * 0.6) + 200,
|
||||
change: 77,
|
||||
current: 0, // Нет реальных данных о готовых товарах
|
||||
change: 0, // Нет реальных данных об изменениях готовых товаров
|
||||
},
|
||||
defects: {
|
||||
current: Math.floor(baseMultiplier * 0.05) + 15,
|
||||
change: -15,
|
||||
current: 0, // Нет реальных данных о браке
|
||||
change: 0, // Нет реальных данных об изменениях брака
|
||||
},
|
||||
pvzReturns: {
|
||||
current: Math.floor(baseMultiplier * 0.1) + 50,
|
||||
change: 36,
|
||||
current: 0, // Нет реальных данных о возвратах с ПВЗ
|
||||
change: 0, // Нет реальных данных об изменениях возвратов
|
||||
},
|
||||
fulfillmentSupplies: {
|
||||
current: Math.floor(baseMultiplier * 0.3) + 80,
|
||||
change: deliveredOrders.length,
|
||||
current: 0, // Нет реальных данных о расходниках ФФ
|
||||
change: 0, // Нет реальных данных об изменениях расходников ФФ
|
||||
},
|
||||
sellerSupplies: {
|
||||
current: inTransitOrders.reduce((sum, o) => sum + o.totalItems, 0) + Math.floor(baseMultiplier * 0.2),
|
||||
change: 57,
|
||||
current: totalSellerSupplies, // Реальное количество расходников селлера из базы
|
||||
change: suppliesReceivedToday - suppliesUsedToday, // Реальное изменение за сутки
|
||||
},
|
||||
};
|
||||
}, [sellerPartners, supplyOrders]);
|
||||
}, [
|
||||
sellerPartners,
|
||||
supplyOrders,
|
||||
allProducts,
|
||||
mySupplies,
|
||||
suppliesReceivedToday,
|
||||
suppliesUsedToday,
|
||||
productsReceivedToday,
|
||||
productsUsedToday,
|
||||
]);
|
||||
|
||||
// Создаем структурированные данные склада на основе партнеров-селлеров
|
||||
// Создаем структурированные данные склада на основе уникальных товаров
|
||||
const storeData: StoreData[] = useMemo(() => {
|
||||
if (!sellerPartners.length) return [];
|
||||
if (!sellerPartners.length && !allProducts.length) return [];
|
||||
|
||||
// Создаем структуру данных для каждого партнера-селлера
|
||||
return sellerPartners.map((partner: any, index: number) => {
|
||||
// Генерируем реалистичные данные на основе партнера
|
||||
const baseProducts = Math.floor(Math.random() * 500) + 100;
|
||||
const baseGoods = Math.floor(baseProducts * 0.6);
|
||||
const baseDefects = Math.floor(baseProducts * 0.05);
|
||||
const baseSellerSupplies = Math.floor(Math.random() * 50) + 10;
|
||||
const basePvzReturns = Math.floor(baseProducts * 0.1);
|
||||
// Группируем товары по названию, суммируя количества из разных поставок
|
||||
const groupedProducts = new Map<
|
||||
string,
|
||||
{
|
||||
name: string;
|
||||
totalQuantity: number;
|
||||
suppliers: string[];
|
||||
categories: string[];
|
||||
prices: number[];
|
||||
articles: string[];
|
||||
originalProducts: any[];
|
||||
}
|
||||
>();
|
||||
|
||||
// Создаем товары для партнера
|
||||
const itemsCount = Math.floor(Math.random() * 8) + 3; // от 3 до 10 товаров
|
||||
const items: ProductItem[] = Array.from({ length: itemsCount }, (_, itemIndex) => {
|
||||
const itemProducts = Math.floor(baseProducts / itemsCount) + Math.floor(Math.random() * 50);
|
||||
return {
|
||||
id: `${index + 1}-${itemIndex + 1}`,
|
||||
name: `Товар ${itemIndex + 1} от ${partner.name}`,
|
||||
article: `ART${(index + 1).toString().padStart(2, '0')}${(itemIndex + 1).toString().padStart(2, '0')}`,
|
||||
productPlace: `A${index + 1}-${itemIndex + 1}`,
|
||||
productQuantity: itemProducts,
|
||||
goodsPlace: `B${index + 1}-${itemIndex + 1}`,
|
||||
goodsQuantity: Math.floor(itemProducts * 0.6),
|
||||
defectsPlace: `C${index + 1}-${itemIndex + 1}`,
|
||||
defectsQuantity: Math.floor(itemProducts * 0.05),
|
||||
sellerSuppliesPlace: `D${index + 1}-${itemIndex + 1}`,
|
||||
sellerSuppliesQuantity: Math.floor(Math.random() * 5) + 1,
|
||||
pvzReturnsPlace: `E${index + 1}-${itemIndex + 1}`,
|
||||
pvzReturnsQuantity: Math.floor(itemProducts * 0.1),
|
||||
// Создаем варианты товара
|
||||
variants: Math.random() > 0.5 ? [
|
||||
{
|
||||
id: `${index + 1}-${itemIndex + 1}-1`,
|
||||
name: `Размер S`,
|
||||
productPlace: `A${index + 1}-${itemIndex + 1}-1`,
|
||||
productQuantity: Math.floor(itemProducts * 0.4),
|
||||
goodsPlace: `B${index + 1}-${itemIndex + 1}-1`,
|
||||
goodsQuantity: Math.floor(itemProducts * 0.24),
|
||||
defectsPlace: `C${index + 1}-${itemIndex + 1}-1`,
|
||||
defectsQuantity: Math.floor(itemProducts * 0.02),
|
||||
sellerSuppliesPlace: `D${index + 1}-${itemIndex + 1}-1`,
|
||||
sellerSuppliesQuantity: Math.floor(Math.random() * 3) + 1,
|
||||
pvzReturnsPlace: `E${index + 1}-${itemIndex + 1}-1`,
|
||||
pvzReturnsQuantity: Math.floor(itemProducts * 0.04),
|
||||
},
|
||||
{
|
||||
id: `${index + 1}-${itemIndex + 1}-2`,
|
||||
name: `Размер M`,
|
||||
productPlace: `A${index + 1}-${itemIndex + 1}-2`,
|
||||
productQuantity: Math.floor(itemProducts * 0.4),
|
||||
goodsPlace: `B${index + 1}-${itemIndex + 1}-2`,
|
||||
goodsQuantity: Math.floor(itemProducts * 0.24),
|
||||
defectsPlace: `C${index + 1}-${itemIndex + 1}-2`,
|
||||
defectsQuantity: Math.floor(itemProducts * 0.02),
|
||||
sellerSuppliesPlace: `D${index + 1}-${itemIndex + 1}-2`,
|
||||
sellerSuppliesQuantity: Math.floor(Math.random() * 3) + 1,
|
||||
pvzReturnsPlace: `E${index + 1}-${itemIndex + 1}-2`,
|
||||
pvzReturnsQuantity: Math.floor(itemProducts * 0.04),
|
||||
},
|
||||
{
|
||||
id: `${index + 1}-${itemIndex + 1}-3`,
|
||||
name: `Размер L`,
|
||||
productPlace: `A${index + 1}-${itemIndex + 1}-3`,
|
||||
productQuantity: Math.floor(itemProducts * 0.2),
|
||||
goodsPlace: `B${index + 1}-${itemIndex + 1}-3`,
|
||||
goodsQuantity: Math.floor(itemProducts * 0.12),
|
||||
defectsPlace: `C${index + 1}-${itemIndex + 1}-3`,
|
||||
defectsQuantity: Math.floor(itemProducts * 0.01),
|
||||
sellerSuppliesPlace: `D${index + 1}-${itemIndex + 1}-3`,
|
||||
sellerSuppliesQuantity: Math.floor(Math.random() * 2) + 1,
|
||||
pvzReturnsPlace: `E${index + 1}-${itemIndex + 1}-3`,
|
||||
pvzReturnsQuantity: Math.floor(itemProducts * 0.02),
|
||||
},
|
||||
] : undefined,
|
||||
};
|
||||
// Группируем товары из allProducts
|
||||
allProducts.forEach((product: any) => {
|
||||
const productName = product.name;
|
||||
const quantity = product.orderedQuantity || 0;
|
||||
|
||||
if (groupedProducts.has(productName)) {
|
||||
const existing = groupedProducts.get(productName)!;
|
||||
existing.totalQuantity += quantity;
|
||||
existing.suppliers.push(
|
||||
product.organization?.name ||
|
||||
product.organization?.fullName ||
|
||||
"Неизвестно"
|
||||
);
|
||||
existing.categories.push(product.category?.name || "Без категории");
|
||||
existing.prices.push(product.price || 0);
|
||||
existing.articles.push(product.article || "");
|
||||
existing.originalProducts.push(product);
|
||||
} else {
|
||||
groupedProducts.set(productName, {
|
||||
name: productName,
|
||||
totalQuantity: quantity,
|
||||
suppliers: [
|
||||
product.organization?.name ||
|
||||
product.organization?.fullName ||
|
||||
"Неизвестно",
|
||||
],
|
||||
categories: [product.category?.name || "Без категории"],
|
||||
prices: [product.price || 0],
|
||||
articles: [product.article || ""],
|
||||
originalProducts: [product],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Группируем расходники по названию
|
||||
const groupedSupplies = new Map<string, number>();
|
||||
mySupplies.forEach((supply: any) => {
|
||||
const supplyName = supply.name;
|
||||
const currentStock = supply.currentStock || 0;
|
||||
|
||||
if (groupedSupplies.has(supplyName)) {
|
||||
groupedSupplies.set(
|
||||
supplyName,
|
||||
groupedSupplies.get(supplyName)! + currentStock
|
||||
);
|
||||
} else {
|
||||
groupedSupplies.set(supplyName, currentStock);
|
||||
}
|
||||
});
|
||||
|
||||
// Логирование группировки
|
||||
console.log("📊 Группировка товаров и расходников:", {
|
||||
groupedProductsCount: groupedProducts.size,
|
||||
groupedSuppliesCount: groupedSupplies.size,
|
||||
groupedProducts: Array.from(groupedProducts.entries()).map(
|
||||
([name, data]) => ({
|
||||
name,
|
||||
totalQuantity: data.totalQuantity,
|
||||
suppliersCount: data.suppliers.length,
|
||||
uniqueSuppliers: [...new Set(data.suppliers)],
|
||||
})
|
||||
),
|
||||
groupedSupplies: Array.from(groupedSupplies.entries()).map(
|
||||
([name, quantity]) => ({
|
||||
name,
|
||||
totalQuantity: quantity,
|
||||
})
|
||||
),
|
||||
});
|
||||
|
||||
// Создаем виртуальных "партнеров" на основе уникальных товаров
|
||||
const uniqueProductNames = Array.from(groupedProducts.keys());
|
||||
const virtualPartners = Math.max(
|
||||
1,
|
||||
Math.min(sellerPartners.length, Math.ceil(uniqueProductNames.length / 8))
|
||||
);
|
||||
|
||||
return Array.from({ length: virtualPartners }, (_, index) => {
|
||||
const startIndex = index * 8;
|
||||
const endIndex = Math.min(startIndex + 8, uniqueProductNames.length);
|
||||
const partnerProductNames = uniqueProductNames.slice(
|
||||
startIndex,
|
||||
endIndex
|
||||
);
|
||||
|
||||
const items: ProductItem[] = partnerProductNames.map(
|
||||
(productName, itemIndex) => {
|
||||
const productData = groupedProducts.get(productName)!;
|
||||
const itemProducts = productData.totalQuantity;
|
||||
|
||||
// Ищем соответствующий расходник по названию
|
||||
const matchingSupplyQuantity = groupedSupplies.get(productName) || 0;
|
||||
|
||||
// Если нет точного совпадения, ищем частичное совпадение
|
||||
let itemSuppliesQuantity = matchingSupplyQuantity;
|
||||
if (itemSuppliesQuantity === 0) {
|
||||
for (const [supplyName, quantity] of groupedSupplies.entries()) {
|
||||
if (
|
||||
supplyName.toLowerCase().includes(productName.toLowerCase()) ||
|
||||
productName.toLowerCase().includes(supplyName.toLowerCase())
|
||||
) {
|
||||
itemSuppliesQuantity = quantity;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback к процентному соотношению
|
||||
if (itemSuppliesQuantity === 0) {
|
||||
itemSuppliesQuantity = Math.floor(itemProducts * 0.1);
|
||||
}
|
||||
|
||||
console.log(`📦 Товар "${productName}":`, {
|
||||
totalQuantity: itemProducts,
|
||||
suppliersCount: productData.suppliers.length,
|
||||
uniqueSuppliers: [...new Set(productData.suppliers)],
|
||||
matchingSupplyQuantity: matchingSupplyQuantity,
|
||||
finalSuppliesQuantity: itemSuppliesQuantity,
|
||||
usedFallback:
|
||||
matchingSupplyQuantity === 0 && itemSuppliesQuantity > 0,
|
||||
});
|
||||
|
||||
return {
|
||||
id: `grouped-${productName}-${itemIndex}`, // Уникальный ID для группированного товара
|
||||
name: productName,
|
||||
article:
|
||||
productData.articles[0] ||
|
||||
`ART${(index + 1).toString().padStart(2, "0")}${(itemIndex + 1)
|
||||
.toString()
|
||||
.padStart(2, "0")}`,
|
||||
productPlace: `A${index + 1}-${itemIndex + 1}`,
|
||||
productQuantity: itemProducts, // Суммированное количество (реальные данные)
|
||||
goodsPlace: `B${index + 1}-${itemIndex + 1}`,
|
||||
goodsQuantity: 0, // Нет реальных данных о готовых товарах
|
||||
defectsPlace: `C${index + 1}-${itemIndex + 1}`,
|
||||
defectsQuantity: 0, // Нет реальных данных о браке
|
||||
sellerSuppliesPlace: `D${index + 1}-${itemIndex + 1}`,
|
||||
sellerSuppliesQuantity: itemSuppliesQuantity, // Суммированное количество расходников (реальные данные)
|
||||
pvzReturnsPlace: `E${index + 1}-${itemIndex + 1}`,
|
||||
pvzReturnsQuantity: 0, // Нет реальных данных о возвратах с ПВЗ
|
||||
// Создаем варианты товара
|
||||
variants:
|
||||
Math.random() > 0.5
|
||||
? [
|
||||
{
|
||||
id: `grouped-${productName}-${itemIndex}-1`,
|
||||
name: `Размер S`,
|
||||
productPlace: `A${index + 1}-${itemIndex + 1}-1`,
|
||||
productQuantity: Math.floor(itemProducts * 0.4), // Часть от общего количества
|
||||
goodsPlace: `B${index + 1}-${itemIndex + 1}-1`,
|
||||
goodsQuantity: 0, // Нет реальных данных о готовых товарах
|
||||
defectsPlace: `C${index + 1}-${itemIndex + 1}-1`,
|
||||
defectsQuantity: 0, // Нет реальных данных о браке
|
||||
sellerSuppliesPlace: `D${index + 1}-${itemIndex + 1}-1`,
|
||||
sellerSuppliesQuantity: Math.floor(
|
||||
itemSuppliesQuantity * 0.4
|
||||
), // Часть от расходников
|
||||
pvzReturnsPlace: `E${index + 1}-${itemIndex + 1}-1`,
|
||||
pvzReturnsQuantity: 0, // Нет реальных данных о возвратах
|
||||
},
|
||||
{
|
||||
id: `grouped-${productName}-${itemIndex}-2`,
|
||||
name: `Размер M`,
|
||||
productPlace: `A${index + 1}-${itemIndex + 1}-2`,
|
||||
productQuantity: Math.floor(itemProducts * 0.4), // Часть от общего количества
|
||||
goodsPlace: `B${index + 1}-${itemIndex + 1}-2`,
|
||||
goodsQuantity: 0, // Нет реальных данных о готовых товарах
|
||||
defectsPlace: `C${index + 1}-${itemIndex + 1}-2`,
|
||||
defectsQuantity: 0, // Нет реальных данных о браке
|
||||
sellerSuppliesPlace: `D${index + 1}-${itemIndex + 1}-2`,
|
||||
sellerSuppliesQuantity: Math.floor(
|
||||
itemSuppliesQuantity * 0.4
|
||||
), // Часть от расходников
|
||||
pvzReturnsPlace: `E${index + 1}-${itemIndex + 1}-2`,
|
||||
pvzReturnsQuantity: 0, // Нет реальных данных о возвратах
|
||||
},
|
||||
{
|
||||
id: `grouped-${productName}-${itemIndex}-3`,
|
||||
name: `Размер L`,
|
||||
productPlace: `A${index + 1}-${itemIndex + 1}-3`,
|
||||
productQuantity: Math.floor(itemProducts * 0.2), // Оставшаяся часть
|
||||
goodsPlace: `B${index + 1}-${itemIndex + 1}-3`,
|
||||
goodsQuantity: 0, // Нет реальных данных о готовых товарах
|
||||
defectsPlace: `C${index + 1}-${itemIndex + 1}-3`,
|
||||
defectsQuantity: 0, // Нет реальных данных о браке
|
||||
sellerSuppliesPlace: `D${index + 1}-${itemIndex + 1}-3`,
|
||||
sellerSuppliesQuantity: Math.floor(
|
||||
itemSuppliesQuantity * 0.2
|
||||
), // Оставшаяся часть расходников
|
||||
pvzReturnsPlace: `E${index + 1}-${itemIndex + 1}-3`,
|
||||
pvzReturnsQuantity: 0, // Нет реальных данных о возвратах
|
||||
},
|
||||
]
|
||||
: [],
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
// Подсчитываем реальные суммы на основе товаров партнера
|
||||
const totalProducts = items.reduce(
|
||||
(sum, item) => sum + item.productQuantity,
|
||||
0
|
||||
);
|
||||
const totalGoods = items.reduce(
|
||||
(sum, item) => sum + item.goodsQuantity,
|
||||
0
|
||||
);
|
||||
const totalDefects = items.reduce(
|
||||
(sum, item) => sum + item.defectsQuantity,
|
||||
0
|
||||
);
|
||||
|
||||
// Используем реальные данные из товаров для расходников селлера
|
||||
const totalSellerSupplies = items.reduce(
|
||||
(sum, item) => sum + item.sellerSuppliesQuantity,
|
||||
0
|
||||
);
|
||||
const totalPvzReturns = items.reduce(
|
||||
(sum, item) => sum + item.pvzReturnsQuantity,
|
||||
0
|
||||
);
|
||||
|
||||
// Логирование общих сумм виртуального партнера
|
||||
const partnerName = sellerPartners[index]
|
||||
? sellerPartners[index].name ||
|
||||
sellerPartners[index].fullName ||
|
||||
`Селлер ${index + 1}`
|
||||
: `Склад ${index + 1}`;
|
||||
|
||||
console.log(`🏪 Партнер "${partnerName}":`, {
|
||||
totalProducts,
|
||||
totalGoods,
|
||||
totalDefects,
|
||||
totalSellerSupplies,
|
||||
totalPvzReturns,
|
||||
itemsCount: items.length,
|
||||
itemsWithSupplies: items.filter(
|
||||
(item) => item.sellerSuppliesQuantity > 0
|
||||
).length,
|
||||
productNames: items.map((item) => item.name),
|
||||
hasRealPartner: !!sellerPartners[index],
|
||||
});
|
||||
|
||||
// Рассчитываем изменения расходников для этого партнера
|
||||
// Распределяем общие поступления пропорционально количеству расходников партнера
|
||||
const totalVirtualPartners = Math.max(
|
||||
1,
|
||||
Math.min(
|
||||
sellerPartners.length,
|
||||
Math.ceil(uniqueProductNames.length / 8)
|
||||
)
|
||||
);
|
||||
|
||||
// Реальные изменения товаров для этого партнера
|
||||
const partnerProductsChange =
|
||||
totalProducts > 0
|
||||
? Math.floor(
|
||||
(totalProducts /
|
||||
(allProducts.reduce(
|
||||
(sum, p: any) => sum + (p.orderedQuantity || 0),
|
||||
0
|
||||
) || 1)) *
|
||||
(productsReceivedToday - productsUsedToday)
|
||||
)
|
||||
: Math.floor(
|
||||
(productsReceivedToday - productsUsedToday) / totalVirtualPartners
|
||||
);
|
||||
|
||||
// Реальные изменения расходников селлера для этого партнера
|
||||
const partnerSuppliesChange =
|
||||
totalSellerSupplies > 0
|
||||
? Math.floor(
|
||||
(totalSellerSupplies /
|
||||
(mySupplies.reduce(
|
||||
(sum: number, supply: any) =>
|
||||
sum + (supply.currentStock || 0),
|
||||
0
|
||||
) || 1)) *
|
||||
suppliesReceivedToday
|
||||
)
|
||||
: Math.floor(suppliesReceivedToday / totalVirtualPartners);
|
||||
|
||||
return {
|
||||
id: (index + 1).toString(),
|
||||
name: partner.name || partner.fullName || `Селлер ${index + 1}`,
|
||||
avatar: partner.users?.[0]?.avatar || `https://images.unsplash.com/photo-15312974840${index + 1}?w=100&h=100&fit=crop&crop=face`,
|
||||
products: baseProducts,
|
||||
goods: baseGoods,
|
||||
defects: baseDefects,
|
||||
sellerSupplies: baseSellerSupplies,
|
||||
pvzReturns: basePvzReturns,
|
||||
productsChange: Math.floor(Math.random() * 50) + 10,
|
||||
goodsChange: Math.floor(Math.random() * 30) + 15,
|
||||
defectsChange: Math.floor(Math.random() * 10) - 5,
|
||||
sellerSuppliesChange: Math.floor(Math.random() * 20) + 5,
|
||||
pvzReturnsChange: Math.floor(Math.random() * 15) + 3,
|
||||
id: `virtual-partner-${index + 1}`,
|
||||
name: sellerPartners[index]
|
||||
? sellerPartners[index].name ||
|
||||
sellerPartners[index].fullName ||
|
||||
`Селлер ${index + 1}`
|
||||
: `Склад ${index + 1}`, // Только если нет реального партнера
|
||||
avatar:
|
||||
sellerPartners[index]?.users?.[0]?.avatar ||
|
||||
`https://images.unsplash.com/photo-15312974840${
|
||||
index + 1
|
||||
}?w=100&h=100&fit=crop&crop=face`,
|
||||
products: totalProducts, // Реальная сумма товаров
|
||||
goods: totalGoods, // Реальная сумма готовых к отправке
|
||||
defects: totalDefects, // Реальная сумма брака
|
||||
sellerSupplies: totalSellerSupplies, // Реальная сумма расходников селлера
|
||||
pvzReturns: totalPvzReturns, // Реальная сумма возвратов
|
||||
productsChange: partnerProductsChange, // Реальные изменения товаров
|
||||
goodsChange: 0, // Нет реальных данных о готовых товарах
|
||||
defectsChange: 0, // Нет реальных данных о браке
|
||||
sellerSuppliesChange: partnerSuppliesChange, // Реальные изменения расходников
|
||||
pvzReturnsChange: 0, // Нет реальных данных о возвратах
|
||||
items,
|
||||
};
|
||||
});
|
||||
}, [sellerPartners]);
|
||||
}, [sellerPartners, allProducts, mySupplies, suppliesReceivedToday]);
|
||||
|
||||
// Функции для аватаров магазинов
|
||||
const getInitials = (name: string): string => {
|
||||
@ -675,7 +1081,12 @@ export function FulfillmentWarehouseDashboard() {
|
||||
);
|
||||
|
||||
// Индикатор загрузки
|
||||
if (counterpartiesLoading || ordersLoading) {
|
||||
if (
|
||||
counterpartiesLoading ||
|
||||
ordersLoading ||
|
||||
productsLoading ||
|
||||
suppliesLoading
|
||||
) {
|
||||
return (
|
||||
<div className="h-screen flex overflow-hidden">
|
||||
<Sidebar />
|
||||
@ -692,7 +1103,7 @@ export function FulfillmentWarehouseDashboard() {
|
||||
}
|
||||
|
||||
// Индикатор ошибки
|
||||
if (counterpartiesError || ordersError) {
|
||||
if (counterpartiesError || ordersError || productsError) {
|
||||
return (
|
||||
<div className="h-screen flex overflow-hidden">
|
||||
<Sidebar />
|
||||
@ -705,7 +1116,9 @@ export function FulfillmentWarehouseDashboard() {
|
||||
Ошибка загрузки данных склада
|
||||
</p>
|
||||
<p className="text-white/60 text-sm mt-2">
|
||||
{counterpartiesError?.message || ordersError?.message}
|
||||
{counterpartiesError?.message ||
|
||||
ordersError?.message ||
|
||||
productsError?.message}
|
||||
</p>
|
||||
</div>
|
||||
</main>
|
||||
@ -749,9 +1162,16 @@ export function FulfillmentWarehouseDashboard() {
|
||||
onClick={() => {
|
||||
refetchCounterparties();
|
||||
refetchOrders();
|
||||
refetchProducts();
|
||||
refetchSupplies(); // Добавляем обновление расходников
|
||||
toast.success("Данные склада обновлены");
|
||||
}}
|
||||
disabled={counterpartiesLoading || ordersLoading}
|
||||
disabled={
|
||||
counterpartiesLoading ||
|
||||
ordersLoading ||
|
||||
productsLoading ||
|
||||
suppliesLoading
|
||||
}
|
||||
>
|
||||
<RotateCcw className="h-3 w-3 mr-1" />
|
||||
Обновить
|
||||
@ -792,7 +1212,7 @@ export function FulfillmentWarehouseDashboard() {
|
||||
icon={Wrench}
|
||||
current={warehouseStats.fulfillmentSupplies.current}
|
||||
change={warehouseStats.fulfillmentSupplies.change}
|
||||
description="Упаковка, этикетки"
|
||||
description="Расходники, этикетки"
|
||||
/>
|
||||
<StatCard
|
||||
title="Расходники селлеров"
|
||||
@ -819,7 +1239,7 @@ export function FulfillmentWarehouseDashboard() {
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-base font-semibold text-white flex items-center space-x-2">
|
||||
<Store className="h-4 w-4 text-blue-400" />
|
||||
<span>Детализация по партнерам-селлерам</span>
|
||||
<span>Детализация по Магазинам</span>
|
||||
<div className="flex items-center space-x-1 text-xs text-white/60">
|
||||
<div className="flex items-center space-x-1">
|
||||
<div className="flex space-x-0.5">
|
||||
@ -827,7 +1247,7 @@ export function FulfillmentWarehouseDashboard() {
|
||||
<div className="w-2 h-2 bg-pink-400 rounded"></div>
|
||||
<div className="w-2 h-2 bg-emerald-400 rounded"></div>
|
||||
</div>
|
||||
<span>Селлеры</span>
|
||||
<span>Магазины</span>
|
||||
</div>
|
||||
<ChevronRight className="h-3 w-3" />
|
||||
<div className="flex items-center space-x-1">
|
||||
@ -842,7 +1262,7 @@ export function FulfillmentWarehouseDashboard() {
|
||||
<Search className="absolute left-2.5 top-1/2 transform -translate-y-1/2 h-3.5 w-3.5 text-white/40" />
|
||||
<div className="flex space-x-2">
|
||||
<Input
|
||||
placeholder="Поиск по селлерам..."
|
||||
placeholder="Поиск по магазинам..."
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="pl-8 h-8 text-sm glass-input text-white placeholder:text-white/40 flex-1"
|
||||
@ -860,7 +1280,7 @@ export function FulfillmentWarehouseDashboard() {
|
||||
variant="secondary"
|
||||
className="bg-blue-500/20 text-blue-300 text-xs"
|
||||
>
|
||||
{filteredAndSortedStores.length} селлеров
|
||||
{filteredAndSortedStores.length} магазинов
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
@ -869,7 +1289,7 @@ export function FulfillmentWarehouseDashboard() {
|
||||
<div className="flex-shrink-0 bg-blue-500/20 border-b border-blue-500/40">
|
||||
<div className="grid grid-cols-6 gap-0">
|
||||
<TableHeader field="name" sortable>
|
||||
№ / Селлер
|
||||
№ / Магазин
|
||||
</TableHeader>
|
||||
<TableHeader field="products" sortable>
|
||||
Продукты
|
||||
@ -925,12 +1345,12 @@ export function FulfillmentWarehouseDashboard() {
|
||||
<div className="flex items-center justify-end space-x-1">
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-green-400">
|
||||
+{Math.abs(Math.floor(totals.productsChange * 0.6))}
|
||||
+0 {/* ТЕСТ: Временно захардкожено для проверки */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-red-400">
|
||||
-{Math.abs(Math.floor(totals.productsChange * 0.4))}
|
||||
-0 {/* ТЕСТ: Временно захардкожено для проверки */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
@ -970,12 +1390,12 @@ export function FulfillmentWarehouseDashboard() {
|
||||
<div className="flex items-center justify-end space-x-1">
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-green-400">
|
||||
+{Math.abs(Math.floor(totals.goodsChange * 0.6))}
|
||||
+0 {/* Нет реальных данных о готовых товарах */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-red-400">
|
||||
-{Math.abs(Math.floor(totals.goodsChange * 0.4))}
|
||||
-0 {/* Нет реальных данных о готовых товарах */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
@ -1016,12 +1436,12 @@ export function FulfillmentWarehouseDashboard() {
|
||||
<div className="flex items-center justify-end space-x-1">
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-green-400">
|
||||
+{Math.abs(Math.floor(totals.defectsChange * 0.6))}
|
||||
+0 {/* Нет реальных данных о браке */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-red-400">
|
||||
-{Math.abs(Math.floor(totals.defectsChange * 0.4))}
|
||||
-0 {/* Нет реальных данных о браке */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
@ -1063,18 +1483,12 @@ export function FulfillmentWarehouseDashboard() {
|
||||
<div className="flex items-center justify-end space-x-1">
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-green-400">
|
||||
+
|
||||
{Math.abs(
|
||||
Math.floor(totals.sellerSuppliesChange * 0.6)
|
||||
)}
|
||||
+0 {/* ТЕСТ: Временно захардкожено для проверки */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-red-400">
|
||||
-
|
||||
{Math.abs(
|
||||
Math.floor(totals.sellerSuppliesChange * 0.4)
|
||||
)}
|
||||
-0 {/* ТЕСТ: Временно захардкожено для проверки */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
@ -1115,12 +1529,12 @@ export function FulfillmentWarehouseDashboard() {
|
||||
<div className="flex items-center justify-end space-x-1">
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-green-400">
|
||||
+{Math.abs(Math.floor(totals.pvzReturnsChange * 0.6))}
|
||||
+0 {/* Нет реальных данных о возвратах с ПВЗ */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-red-400">
|
||||
-{Math.abs(Math.floor(totals.pvzReturnsChange * 0.4))}
|
||||
-0 {/* Нет реальных данных о возвратах с ПВЗ */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
@ -1142,15 +1556,19 @@ export function FulfillmentWarehouseDashboard() {
|
||||
<Package className="h-12 w-12 text-white/40 mx-auto mb-4" />
|
||||
<p className="text-white/60 font-medium">
|
||||
{sellerPartners.length === 0
|
||||
? "Нет партнеров-селлеров"
|
||||
: "Партнеры не найдены"}
|
||||
? "Нет магазинов"
|
||||
: allProducts.length === 0
|
||||
? "Нет товаров на складе"
|
||||
: "Магазины не найдены"}
|
||||
</p>
|
||||
<p className="text-white/40 text-sm mt-2">
|
||||
{sellerPartners.length === 0
|
||||
? "Добавьте партнеров-селлеров для отображения данных склада"
|
||||
? "Добавьте магазины для отображения данных склада"
|
||||
: allProducts.length === 0
|
||||
? "Добавьте товары на склад для отображения данных"
|
||||
: searchTerm
|
||||
? "Попробуйте изменить поисковый запрос"
|
||||
: "Данные о партнерах-селлерах будут отображены здесь"}
|
||||
: "Данные о магазинах будут отображены здесь"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -1211,18 +1629,14 @@ export function FulfillmentWarehouseDashboard() {
|
||||
<div className="flex items-center space-x-1">
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-green-400">
|
||||
+
|
||||
{Math.abs(
|
||||
Math.floor(store.productsChange * 0.6)
|
||||
)}
|
||||
+{Math.max(0, store.productsChange)}{" "}
|
||||
{/* Поступило товаров */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-red-400">
|
||||
-
|
||||
{Math.abs(
|
||||
Math.floor(store.productsChange * 0.4)
|
||||
)}
|
||||
-{Math.max(0, -store.productsChange)}{" "}
|
||||
{/* Использовано товаров */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
@ -1246,18 +1660,14 @@ export function FulfillmentWarehouseDashboard() {
|
||||
<div className="flex items-center space-x-1">
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-green-400">
|
||||
+
|
||||
{Math.abs(
|
||||
Math.floor(store.goodsChange * 0.6)
|
||||
)}
|
||||
+0{" "}
|
||||
{/* Нет реальных данных о готовых товарах */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-red-400">
|
||||
-
|
||||
{Math.abs(
|
||||
Math.floor(store.goodsChange * 0.4)
|
||||
)}
|
||||
-0{" "}
|
||||
{/* Нет реальных данных о готовых товарах */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
@ -1281,18 +1691,12 @@ export function FulfillmentWarehouseDashboard() {
|
||||
<div className="flex items-center space-x-1">
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-green-400">
|
||||
+
|
||||
{Math.abs(
|
||||
Math.floor(store.defectsChange * 0.6)
|
||||
)}
|
||||
+0 {/* Нет реальных данных о браке */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-red-400">
|
||||
-
|
||||
{Math.abs(
|
||||
Math.floor(store.defectsChange * 0.4)
|
||||
)}
|
||||
-0 {/* Нет реальных данных о браке */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
@ -1316,22 +1720,14 @@ export function FulfillmentWarehouseDashboard() {
|
||||
<div className="flex items-center space-x-1">
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-green-400">
|
||||
+
|
||||
{Math.abs(
|
||||
Math.floor(
|
||||
store.sellerSuppliesChange * 0.6
|
||||
)
|
||||
)}
|
||||
+{Math.max(0, store.sellerSuppliesChange)}{" "}
|
||||
{/* Поступило расходников */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-red-400">
|
||||
-
|
||||
{Math.abs(
|
||||
Math.floor(
|
||||
store.sellerSuppliesChange * 0.4
|
||||
)
|
||||
)}
|
||||
-{Math.max(0, -store.sellerSuppliesChange)}{" "}
|
||||
{/* Использовано расходников */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
@ -1355,18 +1751,14 @@ export function FulfillmentWarehouseDashboard() {
|
||||
<div className="flex items-center space-x-1">
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-green-400">
|
||||
+
|
||||
{Math.abs(
|
||||
Math.floor(store.pvzReturnsChange * 0.6)
|
||||
)}
|
||||
+0{" "}
|
||||
{/* Нет реальных данных о возвратах с ПВЗ */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<span className="text-[9px] font-bold text-red-400">
|
||||
-
|
||||
{Math.abs(
|
||||
Math.floor(store.pvzReturnsChange * 0.4)
|
||||
)}
|
||||
-0{" "}
|
||||
{/* Нет реальных данных о возвратах с ПВЗ */}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-0.5">
|
||||
|
Reference in New Issue
Block a user