feat: завершить миграцию на доменно-модульную архитектуру резолверов
🏗️ КРУПНОЕ РЕФАКТОРИНГ: Полный переход от монолитной к доменной архитектуре ✅ УДАЛЕНЫ V2 файлы (8 шт): - employees-v2.ts, fulfillment-*-v2.ts, goods-supply-v2.ts - logistics-consumables-v2.ts, seller-inventory-v2.ts - Функционал перенесен в соответствующие domains/ ✅ УДАЛЕНЫ пустые заглушки (2 шт): - employees.ts, supplies.ts (содержали только пустые объекты) ✅ УДАЛЕНЫ дубликаты (3 шт): - logistics.ts, referrals.ts, seller-consumables.ts - Заменены версиями из domains/ ✅ АРХИВИРОВАН старый монолит: - src/graphql/resolvers.ts (354KB) → temp/archive/ - Не использовался, имел сломанные V2 импорты 🔄 РЕОРГАНИЗАЦИЯ: - auth.ts перемещен в domains/auth.ts - Обновлены импорты в resolvers/index.ts - Удалены закомментированные V2 импорты 🚀 ДОБАВЛЕНА недостающая функция: - fulfillmentReceiveConsumableSupply в domains/inventory.ts - Полная поддержка приемки товаров фулфилментом 📊 РЕЗУЛЬТАТ: - Чистая доменная архитектура без legacy кода - Все функции V1→V2 миграции сохранены - Система полностью готова к дальнейшему развитию 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -3,6 +3,7 @@ import { GraphQLError } from 'graphql'
|
||||
import { Context } from '../../context'
|
||||
import { prisma } from '../../../lib/prisma'
|
||||
import { notifyOrganization } from '../../../lib/realtime'
|
||||
import { processSupplyOrderReceipt } from '../../../lib/inventory-management'
|
||||
import { DomainResolvers } from '../shared/types'
|
||||
import {
|
||||
getCurrentUser,
|
||||
@ -948,6 +949,137 @@ export const inventoryResolvers: DomainResolvers = {
|
||||
}
|
||||
}),
|
||||
|
||||
// Фулфилмент принимает поставку расходников
|
||||
fulfillmentReceiveConsumableSupply: withAuth(async (
|
||||
_: unknown,
|
||||
args: {
|
||||
id: string
|
||||
items: Array<{ id: string; receivedQuantity: number; defectQuantity?: number }>
|
||||
notes?: string
|
||||
},
|
||||
context: Context,
|
||||
) => {
|
||||
console.log('🔍 FULFILLMENT_RECEIVE_CONSUMABLE_SUPPLY DOMAIN MUTATION STARTED:', {
|
||||
userId: context.user?.id,
|
||||
supplyId: args.id,
|
||||
itemsCount: args.items.length
|
||||
})
|
||||
|
||||
try {
|
||||
const user = await checkFulfillmentAccess(context.user!.id)
|
||||
|
||||
const supply = await prisma.fulfillmentConsumableSupplyOrder.findUnique({
|
||||
where: { id: args.id },
|
||||
include: {
|
||||
fulfillmentCenter: true,
|
||||
supplier: true,
|
||||
items: {
|
||||
include: {
|
||||
product: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if (!supply) {
|
||||
throw new GraphQLError('Поставка не найдена')
|
||||
}
|
||||
|
||||
if (supply.fulfillmentCenterId !== user.organizationId) {
|
||||
throw new GraphQLError('Нет доступа к этой поставке')
|
||||
}
|
||||
|
||||
if (supply.status !== 'SHIPPED') {
|
||||
throw new GraphQLError('Поставку можно принять только в статусе SHIPPED')
|
||||
}
|
||||
|
||||
// Обновляем статус поставки на DELIVERED
|
||||
const updatedSupply = await prisma.fulfillmentConsumableSupplyOrder.update({
|
||||
where: { id: args.id },
|
||||
data: {
|
||||
status: 'DELIVERED',
|
||||
receivedAt: new Date(),
|
||||
receivedById: user.id,
|
||||
receiptNotes: args.notes,
|
||||
},
|
||||
include: {
|
||||
fulfillmentCenter: true,
|
||||
supplier: true,
|
||||
items: {
|
||||
include: {
|
||||
product: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Обновляем фактические количества товаров
|
||||
for (const itemData of args.items) {
|
||||
await prisma.fulfillmentConsumableSupplyItem.updateMany({
|
||||
where: { id: itemData.id },
|
||||
data: {
|
||||
receivedQuantity: itemData.receivedQuantity,
|
||||
defectQuantity: itemData.defectQuantity || 0,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Обновляем складские остатки в FulfillmentConsumableInventory
|
||||
const inventoryItems = args.items.map(item => {
|
||||
const supplyItem = supply.items.find(si => si.id === item.id)
|
||||
if (!supplyItem) {
|
||||
throw new GraphQLError(`Товар поставки не найден: ${item.id}`)
|
||||
}
|
||||
return {
|
||||
productId: supplyItem.productId,
|
||||
receivedQuantity: item.receivedQuantity,
|
||||
unitPrice: parseFloat(supplyItem.unitPrice.toString()),
|
||||
}
|
||||
})
|
||||
|
||||
await processSupplyOrderReceipt(supply.id, inventoryItems)
|
||||
|
||||
console.log('✅ FULFILLMENT_RECEIVE_SUPPLY: Inventory updated:', {
|
||||
supplyId: supply.id,
|
||||
itemsCount: inventoryItems.length,
|
||||
totalReceived: inventoryItems.reduce((sum, item) => sum + item.receivedQuantity, 0),
|
||||
})
|
||||
|
||||
// Уведомляем поставщика о приемке
|
||||
if (supply.supplierId) {
|
||||
await notifyOrganization(supply.supplierId, {
|
||||
type: 'supply-order:delivered',
|
||||
title: 'Поставка принята фулфилментом',
|
||||
message: `Фулфилмент-центр "${supply.fulfillmentCenter.name}" принял поставку`,
|
||||
data: {
|
||||
supplyOrderId: supply.id,
|
||||
supplyOrderType: 'FULFILLMENT_CONSUMABLES_V2',
|
||||
fulfillmentCenterName: supply.fulfillmentCenter.name,
|
||||
itemsCount: inventoryItems.length,
|
||||
totalReceived: inventoryItems.reduce((sum, item) => sum + item.receivedQuantity, 0),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const result = {
|
||||
success: true,
|
||||
message: 'Поставка успешно принята',
|
||||
order: updatedSupply,
|
||||
}
|
||||
|
||||
console.log('✅ FULFILLMENT_RECEIVE_CONSUMABLE_SUPPLY DOMAIN SUCCESS:', { supplyId: updatedSupply.id })
|
||||
return result
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('❌ FULFILLMENT_RECEIVE_CONSUMABLE_SUPPLY DOMAIN ERROR:', error)
|
||||
return {
|
||||
success: false,
|
||||
message: error.message || 'Ошибка приемки поставки',
|
||||
order: null,
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
// V1 Legacy: Резервирование товара на складе
|
||||
reserveProductStock: async (
|
||||
_: unknown,
|
||||
|
Reference in New Issue
Block a user