Оптимизирован резолвер статистики склада фулфилмента: улучшено форматирование кода, добавлены дополнительные логи для отслеживания изменений остатков и заказов. Исправлены условия выборки заказов, исключая заказы самого фулфилмента. Обновлены комментарии для лучшего понимания логики работы. Синхронизация остатков поставщика теперь включает обновление основных значений и логирование изменений.
This commit is contained in:
@ -1009,7 +1009,11 @@ export const resolvers = {
|
||||
},
|
||||
|
||||
// Статистика склада фулфилмента с изменениями за сутки
|
||||
fulfillmentWarehouseStats: async (_: unknown, __: unknown, context: Context) => {
|
||||
fulfillmentWarehouseStats: async (
|
||||
_: unknown,
|
||||
__: unknown,
|
||||
context: Context
|
||||
) => {
|
||||
console.log("🔥 FULFILLMENT WAREHOUSE STATS RESOLVER CALLED");
|
||||
if (!context.user) {
|
||||
throw new GraphQLError("Требуется авторизация", {
|
||||
@ -1036,41 +1040,53 @@ export const resolvers = {
|
||||
const oneDayAgo = new Date();
|
||||
oneDayAgo.setDate(oneDayAgo.getDate() - 1);
|
||||
|
||||
console.log(`🏢 Organization ID: ${organizationId}, Date 24h ago: ${oneDayAgo.toISOString()}`);
|
||||
console.log(
|
||||
`🏢 Organization ID: ${organizationId}, Date 24h ago: ${oneDayAgo.toISOString()}`
|
||||
);
|
||||
|
||||
// Сначала проверим ВСЕ заказы поставок
|
||||
const allSupplyOrders = await prisma.supplyOrder.findMany({
|
||||
where: { status: "DELIVERED" },
|
||||
include: {
|
||||
items: {
|
||||
include: { product: true }
|
||||
include: { product: true },
|
||||
},
|
||||
organization: { select: { id: true, name: true, type: true } },
|
||||
},
|
||||
organization: { select: { id: true, name: true, type: true } }
|
||||
}
|
||||
});
|
||||
console.log(`📦 ALL DELIVERED ORDERS: ${allSupplyOrders.length}`);
|
||||
allSupplyOrders.forEach(order => {
|
||||
console.log(` Order ${order.id}: org=${order.organizationId} (${order.organization?.name}), fulfillment=${order.fulfillmentCenterId}, items=${order.items.length}`);
|
||||
allSupplyOrders.forEach((order) => {
|
||||
console.log(
|
||||
` Order ${order.id}: org=${order.organizationId} (${order.organization?.name}), fulfillment=${order.fulfillmentCenterId}, items=${order.items.length}`
|
||||
);
|
||||
});
|
||||
|
||||
// Продукты (товары от селлеров) - заказы К нам, но исключаем расходники фулфилмента
|
||||
const allDeliveredOrders = await prisma.supplyOrder.findMany({
|
||||
const sellerDeliveredOrders = await prisma.supplyOrder.findMany({
|
||||
where: {
|
||||
fulfillmentCenterId: organizationId, // Доставлено к нам (фулфилменту)
|
||||
status: "DELIVERED"
|
||||
organizationId: { not: organizationId }, // ИСПРАВЛЕНО: исключаем заказы самого фулфилмента
|
||||
status: "DELIVERED",
|
||||
},
|
||||
include: {
|
||||
items: {
|
||||
include: { product: true }
|
||||
}
|
||||
}
|
||||
include: { product: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
console.log(`🛒 ALL ORDERS TO FULFILLMENT: ${allDeliveredOrders.length}`);
|
||||
console.log(
|
||||
`🛒 SELLER ORDERS TO FULFILLMENT: ${sellerDeliveredOrders.length}`
|
||||
);
|
||||
|
||||
const productsCount = sellerDeliveredOrders.reduce((sum, order) =>
|
||||
sum + order.items.reduce((itemSum, item) =>
|
||||
itemSum + (item.product.type === "PRODUCT" ? item.quantity : 0), 0
|
||||
), 0
|
||||
const productsCount = sellerDeliveredOrders.reduce(
|
||||
(sum, order) =>
|
||||
sum +
|
||||
order.items.reduce(
|
||||
(itemSum, item) =>
|
||||
itemSum + (item.product.type === "PRODUCT" ? item.quantity : 0),
|
||||
0
|
||||
),
|
||||
0
|
||||
);
|
||||
// Изменения товаров за сутки (от селлеров)
|
||||
const recentSellerDeliveredOrders = await prisma.supplyOrder.findMany({
|
||||
@ -1078,19 +1094,24 @@ export const resolvers = {
|
||||
fulfillmentCenterId: organizationId, // К нам
|
||||
organizationId: { not: organizationId }, // От селлеров
|
||||
status: "DELIVERED",
|
||||
updatedAt: { gte: oneDayAgo }
|
||||
updatedAt: { gte: oneDayAgo },
|
||||
},
|
||||
include: {
|
||||
items: {
|
||||
include: { product: true }
|
||||
}
|
||||
}
|
||||
include: { product: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const productsChangeToday = recentSellerDeliveredOrders.reduce((sum, order) =>
|
||||
sum + order.items.reduce((itemSum, item) =>
|
||||
itemSum + (item.product.type === "PRODUCT" ? item.quantity : 0), 0
|
||||
), 0
|
||||
const productsChangeToday = recentSellerDeliveredOrders.reduce(
|
||||
(sum, order) =>
|
||||
sum +
|
||||
order.items.reduce(
|
||||
(itemSum, item) =>
|
||||
itemSum + (item.product.type === "PRODUCT" ? item.quantity : 0),
|
||||
0
|
||||
),
|
||||
0
|
||||
);
|
||||
|
||||
// Товары (готовые товары = все продукты, не расходники)
|
||||
@ -1105,70 +1126,123 @@ export const resolvers = {
|
||||
const pvzReturnsCount = 0; // TODO: реальные данные о возвратах
|
||||
const pvzReturnsChangeToday = 0;
|
||||
|
||||
// Расходники фулфилмента - заказы ОТ фулфилмента К поставщикам
|
||||
// Расходники фулфилмента - заказы ОТ фулфилмента К поставщикам, НО доставленные на склад фулфилмента
|
||||
// Согласно правилам: фулфилмент заказывает расходники у поставщиков для своих операционных нужд
|
||||
const fulfillmentSupplyOrders = await prisma.supplyOrder.findMany({
|
||||
where: {
|
||||
organizationId: organizationId, // Заказчик = фулфилмент
|
||||
fulfillmentCenterId: null, // Не является доставкой к фулфилменту
|
||||
status: "DELIVERED"
|
||||
fulfillmentCenterId: organizationId, // ИСПРАВЛЕНО: доставлено НА склад фулфилмента
|
||||
status: "DELIVERED",
|
||||
},
|
||||
include: {
|
||||
items: {
|
||||
include: { product: true }
|
||||
}
|
||||
}
|
||||
include: { product: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
console.log(`🏭 FULFILLMENT SUPPLY ORDERS: ${fulfillmentSupplyOrders.length}`);
|
||||
const fulfillmentSuppliesCount = fulfillmentSupplyOrders.reduce(
|
||||
(sum, order) => sum + order.items.reduce((itemSum, item) =>
|
||||
itemSum + (item.product.type === "CONSUMABLE" ? item.quantity : 0), 0
|
||||
), 0
|
||||
|
||||
console.log(
|
||||
`🏭 FULFILLMENT SUPPLY ORDERS: ${fulfillmentSupplyOrders.length}`
|
||||
);
|
||||
|
||||
console.log(`🔥 FULFILLMENT SUPPLIES DEBUG: organizationId=${organizationId}, totalOrders=${fulfillmentSupplyOrders.length}, totalCount=${fulfillmentSuppliesCount}`);
|
||||
// Подсчитываем количество из таблицы Supply (актуальные остатки на складе фулфилмента)
|
||||
const fulfillmentSuppliesFromWarehouse = await prisma.supply.findMany({
|
||||
where: {
|
||||
organizationId: organizationId, // Склад фулфилмента
|
||||
},
|
||||
});
|
||||
|
||||
// Изменения расходников фулфилмента за сутки
|
||||
const fulfillmentSuppliesReceivedToday = await prisma.supplyOrder.findMany({
|
||||
const fulfillmentSuppliesCount = fulfillmentSuppliesFromWarehouse.reduce(
|
||||
(sum, supply) => sum + (supply.currentStock || 0),
|
||||
0
|
||||
);
|
||||
|
||||
console.log(
|
||||
`🔥 FULFILLMENT SUPPLIES DEBUG: organizationId=${organizationId}, ordersCount=${fulfillmentSupplyOrders.length}, warehouseCount=${fulfillmentSuppliesFromWarehouse.length}, totalStock=${fulfillmentSuppliesCount}`
|
||||
);
|
||||
console.log(
|
||||
`📦 FULFILLMENT SUPPLIES BREAKDOWN:`,
|
||||
fulfillmentSuppliesFromWarehouse.map((supply) => ({
|
||||
name: supply.name,
|
||||
currentStock: supply.currentStock,
|
||||
supplier: supply.supplier,
|
||||
}))
|
||||
);
|
||||
|
||||
// Изменения расходников фулфилмента за сутки (ПРИБЫЛО)
|
||||
// Ищем заказы фулфилмента, доставленные на его склад за последние сутки
|
||||
const fulfillmentSuppliesReceivedToday =
|
||||
await prisma.supplyOrder.findMany({
|
||||
where: {
|
||||
organizationId: organizationId, // Заказчик = фулфилмент
|
||||
fulfillmentCenterId: null, // Не доставка к фулфилменту
|
||||
fulfillmentCenterId: organizationId, // ИСПРАВЛЕНО: доставлено НА склад фулфилмента
|
||||
status: "DELIVERED",
|
||||
updatedAt: { gte: oneDayAgo }
|
||||
updatedAt: { gte: oneDayAgo },
|
||||
},
|
||||
include: {
|
||||
items: {
|
||||
include: { product: true }
|
||||
}
|
||||
}
|
||||
include: { product: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
const fulfillmentSuppliesChangeToday = fulfillmentSuppliesReceivedToday.reduce(
|
||||
(sum, order) => sum + order.items.reduce((itemSum, item) =>
|
||||
itemSum + (item.product.type === "CONSUMABLE" ? item.quantity : 0), 0
|
||||
), 0
|
||||
|
||||
const fulfillmentSuppliesChangeToday =
|
||||
fulfillmentSuppliesReceivedToday.reduce(
|
||||
(sum, order) =>
|
||||
sum +
|
||||
order.items.reduce(
|
||||
(itemSum, item) =>
|
||||
itemSum +
|
||||
(item.product.type === "CONSUMABLE" ? item.quantity : 0),
|
||||
0
|
||||
),
|
||||
0
|
||||
);
|
||||
|
||||
console.log(`📊 FULFILLMENT SUPPLIES RECEIVED TODAY: ${fulfillmentSuppliesReceivedToday.length} orders, ${fulfillmentSuppliesChangeToday} items`);
|
||||
console.log(
|
||||
`📊 FULFILLMENT SUPPLIES RECEIVED TODAY (ПРИБЫЛО): ${fulfillmentSuppliesReceivedToday.length} orders, ${fulfillmentSuppliesChangeToday} items`
|
||||
);
|
||||
|
||||
// Расходники селлеров - получаем из заказов от селлеров (расходники = CONSUMABLE)
|
||||
const sellerSuppliesCount = sellerDeliveredOrders.reduce((sum, order) =>
|
||||
sum + order.items.reduce((itemSum, item) =>
|
||||
itemSum + (item.product.type === "CONSUMABLE" ? item.quantity : 0), 0
|
||||
), 0
|
||||
// Согласно правилам: селлеры заказывают расходники у поставщиков и доставляют на склад фулфилмента
|
||||
const sellerSuppliesCount = sellerDeliveredOrders.reduce(
|
||||
(sum, order) =>
|
||||
sum +
|
||||
order.items.reduce(
|
||||
(itemSum, item) =>
|
||||
itemSum +
|
||||
(item.product.type === "CONSUMABLE" ? item.quantity : 0),
|
||||
0
|
||||
),
|
||||
0
|
||||
);
|
||||
|
||||
console.log(`💼 SELLER SUPPLIES DEBUG: totalCount=${sellerSuppliesCount} (from delivered orders)`);
|
||||
console.log(
|
||||
`💼 SELLER SUPPLIES DEBUG: totalCount=${sellerSuppliesCount} (from delivered orders)`
|
||||
);
|
||||
|
||||
// Изменения расходников селлеров за сутки - используем уже полученные данные
|
||||
const sellerSuppliesChangeToday = recentSellerDeliveredOrders.reduce((sum, order) =>
|
||||
sum + order.items.reduce((itemSum, item) =>
|
||||
itemSum + (item.product.type === "CONSUMABLE" ? item.quantity : 0), 0
|
||||
), 0
|
||||
const sellerSuppliesChangeToday = recentSellerDeliveredOrders.reduce(
|
||||
(sum, order) =>
|
||||
sum +
|
||||
order.items.reduce(
|
||||
(itemSum, item) =>
|
||||
itemSum +
|
||||
(item.product.type === "CONSUMABLE" ? item.quantity : 0),
|
||||
0
|
||||
),
|
||||
0
|
||||
);
|
||||
|
||||
console.log(`📊 SELLER SUPPLIES RECEIVED TODAY: ${recentSellerDeliveredOrders.length} orders, ${sellerSuppliesChangeToday} items`);
|
||||
console.log(
|
||||
`📊 SELLER SUPPLIES RECEIVED TODAY: ${recentSellerDeliveredOrders.length} orders, ${sellerSuppliesChangeToday} items`
|
||||
);
|
||||
|
||||
// Вычисляем процентные изменения
|
||||
const calculatePercentChange = (current: number, change: number): number => {
|
||||
const calculatePercentChange = (
|
||||
current: number,
|
||||
change: number
|
||||
): number => {
|
||||
if (current === 0) return change > 0 ? 100 : 0;
|
||||
return (change / current) * 100;
|
||||
};
|
||||
@ -1177,36 +1251,54 @@ export const resolvers = {
|
||||
products: {
|
||||
current: productsCount,
|
||||
change: productsChangeToday,
|
||||
percentChange: calculatePercentChange(productsCount, productsChangeToday)
|
||||
percentChange: calculatePercentChange(
|
||||
productsCount,
|
||||
productsChangeToday
|
||||
),
|
||||
},
|
||||
goods: {
|
||||
current: goodsCount,
|
||||
change: goodsChangeToday,
|
||||
percentChange: calculatePercentChange(goodsCount, goodsChangeToday)
|
||||
percentChange: calculatePercentChange(goodsCount, goodsChangeToday),
|
||||
},
|
||||
defects: {
|
||||
current: defectsCount,
|
||||
change: defectsChangeToday,
|
||||
percentChange: calculatePercentChange(defectsCount, defectsChangeToday)
|
||||
percentChange: calculatePercentChange(
|
||||
defectsCount,
|
||||
defectsChangeToday
|
||||
),
|
||||
},
|
||||
pvzReturns: {
|
||||
current: pvzReturnsCount,
|
||||
change: pvzReturnsChangeToday,
|
||||
percentChange: calculatePercentChange(pvzReturnsCount, pvzReturnsChangeToday)
|
||||
percentChange: calculatePercentChange(
|
||||
pvzReturnsCount,
|
||||
pvzReturnsChangeToday
|
||||
),
|
||||
},
|
||||
fulfillmentSupplies: {
|
||||
current: fulfillmentSuppliesCount,
|
||||
change: fulfillmentSuppliesChangeToday,
|
||||
percentChange: calculatePercentChange(fulfillmentSuppliesCount, fulfillmentSuppliesChangeToday)
|
||||
percentChange: calculatePercentChange(
|
||||
fulfillmentSuppliesCount,
|
||||
fulfillmentSuppliesChangeToday
|
||||
),
|
||||
},
|
||||
sellerSupplies: {
|
||||
current: sellerSuppliesCount,
|
||||
change: sellerSuppliesChangeToday,
|
||||
percentChange: calculatePercentChange(sellerSuppliesCount, sellerSuppliesChangeToday)
|
||||
}
|
||||
percentChange: calculatePercentChange(
|
||||
sellerSuppliesCount,
|
||||
sellerSuppliesChangeToday
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
console.log(`🏁 FINAL WAREHOUSE STATS RESULT:`, JSON.stringify(result, null, 2));
|
||||
console.log(
|
||||
`🏁 FINAL WAREHOUSE STATS RESULT:`,
|
||||
JSON.stringify(result, null, 2)
|
||||
);
|
||||
|
||||
return result;
|
||||
},
|
||||
@ -4037,9 +4129,12 @@ export const resolvers = {
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`📦 Зарезервированы товары для заказа ${supplyOrder.id}:`,
|
||||
args.input.items.map(item => `${item.productId}: +${item.quantity} шт.`).join(', '));
|
||||
|
||||
console.log(
|
||||
`📦 Зарезервированы товары для заказа ${supplyOrder.id}:`,
|
||||
args.input.items
|
||||
.map((item) => `${item.productId}: +${item.quantity} шт.`)
|
||||
.join(", ")
|
||||
);
|
||||
|
||||
// Создаем расходники на основе заказанных товаров
|
||||
// Расходники создаются в организации получателя (фулфилмент-центре)
|
||||
@ -4482,7 +4577,8 @@ export const resolvers = {
|
||||
}
|
||||
|
||||
// Проверяем доступность товара
|
||||
const availableStock = (product.stock || product.quantity) - (product.ordered || 0);
|
||||
const availableStock =
|
||||
(product.stock || product.quantity) - (product.ordered || 0);
|
||||
if (availableStock < args.quantity) {
|
||||
return {
|
||||
success: false,
|
||||
@ -4498,7 +4594,9 @@ export const resolvers = {
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`📦 Зарезервировано ${args.quantity} единиц товара ${product.name}`);
|
||||
console.log(
|
||||
`📦 Зарезервировано ${args.quantity} единиц товара ${product.name}`
|
||||
);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
@ -4551,7 +4649,9 @@ export const resolvers = {
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`🔄 Освобожден резерв ${args.quantity} единиц товара ${product.name}`);
|
||||
console.log(
|
||||
`🔄 Освобожден резерв ${args.quantity} единиц товара ${product.name}`
|
||||
);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
@ -4617,7 +4717,9 @@ export const resolvers = {
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`🚚 Обновлен статус "в пути" для товара ${product.name}: ${args.operation}`);
|
||||
console.log(
|
||||
`🚚 Обновлен статус "в пути" для товара ${product.name}: ${args.operation}`
|
||||
);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
@ -5729,7 +5831,9 @@ export const resolvers = {
|
||||
},
|
||||
context: Context
|
||||
) => {
|
||||
console.log(`[DEBUG] updateSupplyOrderStatus вызван для заказа ${args.id} со статусом ${args.status}`);
|
||||
console.log(
|
||||
`[DEBUG] updateSupplyOrderStatus вызван для заказа ${args.id} со статусом ${args.status}`
|
||||
);
|
||||
if (!context.user) {
|
||||
throw new GraphQLError("Требуется авторизация", {
|
||||
extensions: { code: "UNAUTHENTICATED" },
|
||||
@ -5795,10 +5899,13 @@ export const resolvers = {
|
||||
|
||||
// ОТКЛЮЧЕНО: Устаревшая логика для обновления расходников
|
||||
// Теперь используются специальные мутации для каждой роли
|
||||
const targetOrganizationId = existingOrder.fulfillmentCenterId || existingOrder.organizationId;
|
||||
const targetOrganizationId =
|
||||
existingOrder.fulfillmentCenterId || existingOrder.organizationId;
|
||||
|
||||
if (args.status === "CONFIRMED") {
|
||||
console.log(`[WARNING] Попытка использовать устаревший статус CONFIRMED для заказа ${args.id}`);
|
||||
console.log(
|
||||
`[WARNING] Попытка использовать устаревший статус CONFIRMED для заказа ${args.id}`
|
||||
);
|
||||
// Не обновляем расходники для устаревших статусов
|
||||
// await prisma.supply.updateMany({
|
||||
// where: {
|
||||
@ -5823,12 +5930,12 @@ export const resolvers = {
|
||||
organizationId: targetOrganizationId,
|
||||
status: "confirmed",
|
||||
name: {
|
||||
in: existingOrder.items.map(item => item.product.name)
|
||||
}
|
||||
in: existingOrder.items.map((item) => item.product.name),
|
||||
},
|
||||
},
|
||||
data: {
|
||||
status: "in-transit"
|
||||
}
|
||||
status: "in-transit",
|
||||
},
|
||||
});
|
||||
|
||||
console.log("✅ Статусы расходников обновлены на 'in-transit'");
|
||||
@ -5836,7 +5943,6 @@ export const resolvers = {
|
||||
|
||||
// Если статус изменился на DELIVERED, обновляем склад
|
||||
if (args.status === "DELIVERED") {
|
||||
|
||||
console.log("🚚 Обновляем склад организации:", {
|
||||
targetOrganizationId,
|
||||
fulfillmentCenterId: existingOrder.fulfillmentCenterId,
|
||||
@ -5848,21 +5954,34 @@ export const resolvers = {
|
||||
})),
|
||||
});
|
||||
|
||||
// 🔄 СИНХРОНИЗАЦИЯ: Обновляем товары поставщика (переводим из "в пути" в "продано")
|
||||
// 🔄 СИНХРОНИЗАЦИЯ: Обновляем товары поставщика (переводим из "в пути" в "продано" + обновляем основные остатки)
|
||||
for (const item of existingOrder.items) {
|
||||
const product = await prisma.product.findUnique({
|
||||
where: { id: item.product.id },
|
||||
});
|
||||
|
||||
if (product) {
|
||||
// Согласно правилам: Основные значения = Предыдущие остатки + Прибыло - Убыло
|
||||
const currentStock = product.stock || product.quantity || 0;
|
||||
const newStock = Math.max(currentStock - item.quantity, 0);
|
||||
|
||||
await prisma.product.update({
|
||||
where: { id: item.product.id },
|
||||
data: {
|
||||
inTransit: Math.max((product.inTransit || 0) - item.quantity, 0),
|
||||
// Обновляем основные остатки (УБЫЛО)
|
||||
stock: newStock,
|
||||
quantity: newStock, // Синхронизируем оба поля для совместимости
|
||||
// Обновляем дополнительные значения
|
||||
inTransit: Math.max(
|
||||
(product.inTransit || 0) - item.quantity,
|
||||
0
|
||||
),
|
||||
sold: (product.sold || 0) + item.quantity,
|
||||
},
|
||||
});
|
||||
console.log(`✅ Товар поставщика "${product.name}" обновлен: доставлено ${item.quantity} единиц`);
|
||||
console.log(
|
||||
`✅ Товар поставщика "${product.name}" обновлен: доставлено ${item.quantity} единиц (остаток: ${currentStock} -> ${newStock})`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5992,7 +6111,9 @@ export const resolvers = {
|
||||
};
|
||||
}
|
||||
|
||||
console.log(`[DEBUG] Поставщик ${currentUser.organization.name} одобряет заказ ${args.id}`);
|
||||
console.log(
|
||||
`[DEBUG] Поставщик ${currentUser.organization.name} одобряет заказ ${args.id}`
|
||||
);
|
||||
|
||||
// 🔄 СИНХРОНИЗАЦИЯ ОСТАТКОВ: Резервируем товары у поставщика
|
||||
const orderWithItems = await prisma.supplyOrder.findUnique({
|
||||
@ -6014,7 +6135,8 @@ export const resolvers = {
|
||||
});
|
||||
|
||||
if (product) {
|
||||
const availableStock = (product.stock || product.quantity) - (product.ordered || 0);
|
||||
const availableStock =
|
||||
(product.stock || product.quantity) - (product.ordered || 0);
|
||||
|
||||
if (availableStock < item.quantity) {
|
||||
return {
|
||||
@ -6023,14 +6145,32 @@ export const resolvers = {
|
||||
};
|
||||
}
|
||||
|
||||
// Согласно правилам: при одобрении заказа остаток должен уменьшиться
|
||||
const currentStock = product.stock || product.quantity || 0;
|
||||
const newStock = Math.max(currentStock - item.quantity, 0);
|
||||
|
||||
await prisma.product.update({
|
||||
where: { id: item.product.id },
|
||||
data: {
|
||||
// Уменьшаем основной остаток (товар зарезервирован для заказа)
|
||||
stock: newStock,
|
||||
quantity: newStock, // Синхронизируем оба поля для совместимости
|
||||
// Увеличиваем количество заказанного (для отслеживания)
|
||||
ordered: (product.ordered || 0) + item.quantity,
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`📦 Зарезервировано ${item.quantity} единиц товара "${product.name}"`);
|
||||
console.log(
|
||||
`📦 Товар "${product.name}" зарезервирован: ${item.quantity} единиц`
|
||||
);
|
||||
console.log(
|
||||
` 📊 Остаток: ${currentStock} -> ${newStock} (уменьшен на ${item.quantity})`
|
||||
);
|
||||
console.log(
|
||||
` 📋 Заказано: ${product.ordered || 0} -> ${
|
||||
(product.ordered || 0) + item.quantity
|
||||
}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6056,10 +6196,13 @@ export const resolvers = {
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`[DEBUG] Заказ ${args.id} успешно обновлен до статуса: ${updatedOrder.status}`);
|
||||
console.log(
|
||||
`[DEBUG] Заказ ${args.id} успешно обновлен до статуса: ${updatedOrder.status}`
|
||||
);
|
||||
return {
|
||||
success: true,
|
||||
message: "Заказ поставки одобрен поставщиком. Товары зарезервированы.",
|
||||
message:
|
||||
"Заказ поставки одобрен поставщиком. Товары зарезервированы, остатки обновлены.",
|
||||
order: updatedOrder,
|
||||
};
|
||||
} catch (error) {
|
||||
@ -6129,20 +6272,44 @@ export const resolvers = {
|
||||
});
|
||||
|
||||
// 📦 СНИМАЕМ РЕЗЕРВАЦИЮ ПРИ ОТКЛОНЕНИИ
|
||||
// Уменьшаем поле "ordered" для каждого отклоненного товара
|
||||
// Восстанавливаем остатки и убираем резервацию для каждого отклоненного товара
|
||||
for (const item of updatedOrder.items) {
|
||||
const product = await prisma.product.findUnique({
|
||||
where: { id: item.productId },
|
||||
});
|
||||
|
||||
if (product) {
|
||||
// Восстанавливаем основные остатки (на случай, если заказ был одобрен, а затем отклонен)
|
||||
const currentStock = product.stock || product.quantity || 0;
|
||||
const restoredStock = currentStock + item.quantity;
|
||||
|
||||
await prisma.product.update({
|
||||
where: { id: item.productId },
|
||||
data: {
|
||||
ordered: {
|
||||
decrement: item.quantity,
|
||||
},
|
||||
// Восстанавливаем основной остаток
|
||||
stock: restoredStock,
|
||||
quantity: restoredStock,
|
||||
// Уменьшаем количество заказанного
|
||||
ordered: Math.max((product.ordered || 0) - item.quantity, 0),
|
||||
},
|
||||
});
|
||||
|
||||
console.log(
|
||||
`🔄 Восстановлены остатки товара "${
|
||||
product.name
|
||||
}": ${currentStock} -> ${restoredStock}, ordered: ${
|
||||
product.ordered
|
||||
} -> ${Math.max((product.ordered || 0) - item.quantity, 0)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`📦 Снята резервация при отклонении заказа ${updatedOrder.id}:`,
|
||||
updatedOrder.items.map(item => `${item.productId}: -${item.quantity} шт.`).join(', '));
|
||||
console.log(
|
||||
`📦 Снята резервация при отклонении заказа ${updatedOrder.id}:`,
|
||||
updatedOrder.items
|
||||
.map((item) => `${item.productId}: -${item.quantity} шт.`)
|
||||
.join(", ")
|
||||
);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
@ -6223,7 +6390,9 @@ export const resolvers = {
|
||||
},
|
||||
});
|
||||
|
||||
console.log(`🚚 Товар "${product.name}" переведен в статус "в пути": ${item.quantity} единиц`);
|
||||
console.log(
|
||||
`🚚 Товар "${product.name}" переведен в статус "в пути": ${item.quantity} единиц`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6251,7 +6420,8 @@ export const resolvers = {
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Заказ отправлен поставщиком. Товары переведены в статус 'в пути'.",
|
||||
message:
|
||||
"Заказ отправлен поставщиком. Товары переведены в статус 'в пути'.",
|
||||
order: updatedOrder,
|
||||
};
|
||||
} catch (error) {
|
||||
@ -6295,7 +6465,8 @@ export const resolvers = {
|
||||
if (!existingOrder) {
|
||||
return {
|
||||
success: false,
|
||||
message: "Заказ не найден или недоступен для подтверждения логистикой",
|
||||
message:
|
||||
"Заказ не найден или недоступен для подтверждения логистикой",
|
||||
};
|
||||
}
|
||||
|
||||
@ -6472,7 +6643,54 @@ export const resolvers = {
|
||||
},
|
||||
});
|
||||
|
||||
// 🔄 СИНХРОНИЗАЦИЯ СКЛАДА ПОСТАВЩИКА: Обновляем остатки поставщика согласно правилам
|
||||
console.log("🔄 Начинаем синхронизацию остатков поставщика...");
|
||||
for (const item of existingOrder.items) {
|
||||
const product = await prisma.product.findUnique({
|
||||
where: { id: item.product.id },
|
||||
});
|
||||
|
||||
if (product) {
|
||||
// Согласно правилам: Основные значения = Предыдущие остатки + Прибыло - Убыло
|
||||
const currentStock = product.stock || product.quantity || 0;
|
||||
const newStock = Math.max(currentStock - item.quantity, 0);
|
||||
|
||||
await prisma.product.update({
|
||||
where: { id: item.product.id },
|
||||
data: {
|
||||
// Обновляем основные остатки (УБЫЛО)
|
||||
stock: newStock,
|
||||
quantity: newStock, // Синхронизируем оба поля для совместимости
|
||||
// Обновляем дополнительные значения
|
||||
inTransit: Math.max(
|
||||
(product.inTransit || 0) - item.quantity,
|
||||
0
|
||||
),
|
||||
sold: (product.sold || 0) + item.quantity,
|
||||
},
|
||||
});
|
||||
console.log(
|
||||
`✅ Товар поставщика "${product.name}" обновлен: доставлено ${item.quantity} единиц`
|
||||
);
|
||||
console.log(
|
||||
` 📊 Остатки: ${currentStock} -> ${newStock} (УБЫЛО: ${item.quantity})`
|
||||
);
|
||||
console.log(
|
||||
` 🚚 В пути: ${product.inTransit || 0} -> ${Math.max(
|
||||
(product.inTransit || 0) - item.quantity,
|
||||
0
|
||||
)}`
|
||||
);
|
||||
console.log(
|
||||
` 💰 Продано: ${product.sold || 0} -> ${
|
||||
(product.sold || 0) + item.quantity
|
||||
}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Обновляем склад фулфилмента
|
||||
console.log("📦 Обновляем склад фулфилмента...");
|
||||
for (const item of existingOrder.items) {
|
||||
const existingSupply = await prisma.supply.findFirst({
|
||||
where: {
|
||||
@ -6490,11 +6708,20 @@ export const resolvers = {
|
||||
status: "in-stock",
|
||||
},
|
||||
});
|
||||
console.log(
|
||||
`📈 Обновлен существующий расходник фулфилмента "${
|
||||
item.product.name
|
||||
}": ${existingSupply.currentStock} -> ${
|
||||
existingSupply.currentStock + item.quantity
|
||||
}`
|
||||
);
|
||||
} else {
|
||||
await prisma.supply.create({
|
||||
data: {
|
||||
name: item.product.name,
|
||||
description: item.product.description || `Расходники от ${updatedOrder.partner.name}`,
|
||||
description:
|
||||
item.product.description ||
|
||||
`Расходники от ${updatedOrder.partner.name}`,
|
||||
price: item.price,
|
||||
quantity: item.quantity,
|
||||
currentStock: item.quantity,
|
||||
@ -6502,16 +6729,25 @@ export const resolvers = {
|
||||
unit: "шт",
|
||||
category: item.product.category?.name || "Расходники",
|
||||
status: "in-stock",
|
||||
supplier: updatedOrder.partner.name || updatedOrder.partner.fullName || "Поставщик",
|
||||
supplier:
|
||||
updatedOrder.partner.name ||
|
||||
updatedOrder.partner.fullName ||
|
||||
"Поставщик",
|
||||
organizationId: currentUser.organization.id,
|
||||
},
|
||||
});
|
||||
console.log(
|
||||
`➕ Создан новый расходник фулфилмента "${item.product.name}": ${item.quantity} единиц`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("🎉 Синхронизация склада завершена успешно!");
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Заказ принят фулфилментом. Склад обновлен.",
|
||||
message:
|
||||
"Заказ принят фулфилментом. Склад обновлен. Остатки поставщика синхронизированы.",
|
||||
order: updatedOrder,
|
||||
};
|
||||
} catch (error) {
|
||||
|
Reference in New Issue
Block a user