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:
Veronika Smirnova
2025-09-12 17:07:32 +03:00
parent 8d4b9ce97f
commit 2269de6c85
22 changed files with 3858 additions and 15718 deletions

View File

@ -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,