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