import { GraphQLError } from 'graphql' import { prisma } from '@/lib/prisma' import { notifyOrganization } from '@/lib/realtime' import { Context } from '../context' export const fulfillmentConsumableV2Queries = { myFulfillmentConsumableSupplies: async (_: unknown, __: unknown, context: Context) => { if (!context.user) { throw new GraphQLError('Требуется авторизация', { extensions: { code: 'UNAUTHENTICATED' }, }) } try { const user = await prisma.user.findUnique({ where: { id: context.user.id }, include: { organization: true }, }) if (!user?.organization || user.organization.type !== 'FULFILLMENT') { throw new GraphQLError('Доступно только для фулфилмент-центров') } const supplies = await prisma.fulfillmentConsumableSupplyOrder.findMany({ where: { fulfillmentCenterId: user.organizationId!, }, include: { fulfillmentCenter: true, supplier: true, logisticsPartner: true, receivedBy: true, items: { include: { product: true, }, }, }, orderBy: { createdAt: 'desc', }, }) return supplies } catch (error) { console.error('Error fetching fulfillment consumable supplies:', error) return [] // Возвращаем пустой массив вместо throw } }, fulfillmentConsumableSupply: async (_: unknown, args: { id: string }, context: Context) => { if (!context.user) { throw new GraphQLError('Требуется авторизация', { extensions: { code: 'UNAUTHENTICATED' }, }) } try { const user = await prisma.user.findUnique({ where: { id: context.user.id }, include: { organization: true }, }) if (!user?.organization) { throw new GraphQLError('Организация не найдена') } const supply = await prisma.fulfillmentConsumableSupplyOrder.findUnique({ where: { id: args.id }, include: { fulfillmentCenter: true, supplier: true, logisticsPartner: true, receivedBy: true, items: { include: { product: true, }, }, }, }) if (!supply) { throw new GraphQLError('Поставка не найдена') } // Проверка доступа if ( user.organization.type === 'FULFILLMENT' && supply.fulfillmentCenterId !== user.organizationId ) { throw new GraphQLError('Нет доступа к этой поставке') } if ( user.organization.type === 'WHOLESALE' && supply.supplierId !== user.organizationId ) { throw new GraphQLError('Нет доступа к этой поставке') } return supply } catch (error) { console.error('Error fetching fulfillment consumable supply:', error) throw new GraphQLError('Ошибка получения поставки') } }, // Заявки на поставки для поставщиков (новая система v2) mySupplierConsumableSupplies: async (_: unknown, __: unknown, context: Context) => { if (!context.user) { throw new GraphQLError('Требуется авторизация', { extensions: { code: 'UNAUTHENTICATED' }, }) } try { const user = await prisma.user.findUnique({ where: { id: context.user.id }, include: { organization: true }, }) if (!user?.organization || user.organization.type !== 'WHOLESALE') { return [] } const supplies = await prisma.fulfillmentConsumableSupplyOrder.findMany({ where: { supplierId: user.organizationId!, }, include: { fulfillmentCenter: true, supplier: true, logisticsPartner: true, receivedBy: true, items: { include: { product: true, }, }, }, orderBy: { createdAt: 'desc', }, }) return supplies } catch (error) { console.error('Error fetching supplier consumable supplies:', error) return [] } }, } // ============================================================================= // 🔄 МУТАЦИИ ПОСТАВЩИКА ДЛЯ FULFILLMENT CONSUMABLE SUPPLY // ============================================================================= const supplierApproveConsumableSupply = async ( _: unknown, args: { id: string }, context: Context, ) => { if (!context.user) { throw new GraphQLError('Требуется авторизация', { extensions: { code: 'UNAUTHENTICATED' }, }) } try { const user = await prisma.user.findUnique({ where: { id: context.user.id }, include: { organization: true }, }) if (!user?.organization || user.organization.type !== 'WHOLESALE') { throw new GraphQLError('Только поставщики могут одобрять поставки') } const supply = await prisma.fulfillmentConsumableSupplyOrder.findUnique({ where: { id: args.id }, include: { supplier: true, fulfillmentCenter: true, }, }) if (!supply) { throw new GraphQLError('Поставка не найдена') } if (supply.supplierId !== user.organizationId) { throw new GraphQLError('Нет доступа к этой поставке') } if (supply.status !== 'PENDING') { throw new GraphQLError('Поставку можно одобрить только в статусе PENDING') } const updatedSupply = await prisma.fulfillmentConsumableSupplyOrder.update({ where: { id: args.id }, data: { status: 'SUPPLIER_APPROVED', supplierApprovedAt: new Date(), }, include: { fulfillmentCenter: true, supplier: true, items: { include: { product: true, }, }, }, }) return { success: true, message: 'Поставка одобрена успешно', order: updatedSupply, } } catch (error) { console.error('Error approving fulfillment consumable supply:', error) return { success: false, message: error instanceof Error ? error.message : 'Ошибка одобрения поставки', order: null, } } } const supplierRejectConsumableSupply = async ( _: unknown, args: { id: string; reason?: string }, context: Context, ) => { if (!context.user) { throw new GraphQLError('Требуется авторизация', { extensions: { code: 'UNAUTHENTICATED' }, }) } try { const user = await prisma.user.findUnique({ where: { id: context.user.id }, include: { organization: true }, }) if (!user?.organization || user.organization.type !== 'WHOLESALE') { throw new GraphQLError('Только поставщики могут отклонять поставки') } const supply = await prisma.fulfillmentConsumableSupplyOrder.findUnique({ where: { id: args.id }, include: { supplier: true, fulfillmentCenter: true, }, }) if (!supply) { throw new GraphQLError('Поставка не найдена') } if (supply.supplierId !== user.organizationId) { throw new GraphQLError('Нет доступа к этой поставке') } if (supply.status !== 'PENDING') { throw new GraphQLError('Поставку можно отклонить только в статусе PENDING') } const updatedSupply = await prisma.fulfillmentConsumableSupplyOrder.update({ where: { id: args.id }, data: { status: 'REJECTED', supplierNotes: args.reason || 'Поставка отклонена', }, include: { fulfillmentCenter: true, supplier: true, items: { include: { product: true, }, }, }, }) return { success: true, message: 'Поставка отклонена', order: updatedSupply, } } catch (error) { console.error('Error rejecting fulfillment consumable supply:', error) return { success: false, message: error instanceof Error ? error.message : 'Ошибка отклонения поставки', order: null, } } } const supplierShipConsumableSupply = async ( _: unknown, args: { id: string }, context: Context, ) => { if (!context.user) { throw new GraphQLError('Требуется авторизация', { extensions: { code: 'UNAUTHENTICATED' }, }) } try { const user = await prisma.user.findUnique({ where: { id: context.user.id }, include: { organization: true }, }) if (!user?.organization || user.organization.type !== 'WHOLESALE') { throw new GraphQLError('Только поставщики могут отправлять поставки') } const supply = await prisma.fulfillmentConsumableSupplyOrder.findUnique({ where: { id: args.id }, include: { supplier: true, fulfillmentCenter: true, }, }) if (!supply) { throw new GraphQLError('Поставка не найдена') } if (supply.supplierId !== user.organizationId) { throw new GraphQLError('Нет доступа к этой поставке') } if (!['SUPPLIER_APPROVED', 'LOGISTICS_CONFIRMED'].includes(supply.status)) { throw new GraphQLError('Поставку можно отправить только в статусе SUPPLIER_APPROVED или LOGISTICS_CONFIRMED') } const updatedSupply = await prisma.fulfillmentConsumableSupplyOrder.update({ where: { id: args.id }, data: { status: 'SHIPPED', shippedAt: new Date(), }, include: { fulfillmentCenter: true, supplier: true, logisticsPartner: true, items: { include: { product: true, }, }, }, }) return { success: true, message: 'Поставка отправлена', order: updatedSupply, } } catch (error) { console.error('Error shipping fulfillment consumable supply:', error) return { success: false, message: error instanceof Error ? error.message : 'Ошибка отправки поставки', order: null, } } } export const fulfillmentConsumableV2Mutations = { createFulfillmentConsumableSupply: async ( _: unknown, args: { input: { supplierId: string requestedDeliveryDate: string items: Array<{ productId: string requestedQuantity: number }> notes?: string } }, context: Context, ) => { if (!context.user) { throw new GraphQLError('Требуется авторизация', { extensions: { code: 'UNAUTHENTICATED' }, }) } try { const user = await prisma.user.findUnique({ where: { id: context.user.id }, include: { organization: true }, }) if (!user?.organization || user.organization.type !== 'FULFILLMENT') { throw new GraphQLError('Только фулфилмент-центры могут создавать поставки расходников') } // Проверяем что поставщик существует и является WHOLESALE const supplier = await prisma.organization.findUnique({ where: { id: args.input.supplierId }, }) if (!supplier || supplier.type !== 'WHOLESALE') { throw new GraphQLError('Поставщик не найден или не является оптовиком') } // Проверяем что все товары существуют и принадлежат поставщику const productIds = args.input.items.map(item => item.productId) const products = await prisma.product.findMany({ where: { id: { in: productIds }, organizationId: supplier.id, type: 'CONSUMABLE', }, }) if (products.length !== productIds.length) { throw new GraphQLError('Некоторые товары не найдены или не принадлежат поставщику') } // Создаем поставку с items const supplyOrder = await prisma.fulfillmentConsumableSupplyOrder.create({ data: { fulfillmentCenterId: user.organizationId!, supplierId: supplier.id, requestedDeliveryDate: new Date(args.input.requestedDeliveryDate), notes: args.input.notes, items: { create: args.input.items.map(item => { const product = products.find(p => p.id === item.productId)! return { productId: item.productId, requestedQuantity: item.requestedQuantity, unitPrice: product.price, totalPrice: product.price.mul(item.requestedQuantity), } }), }, }, include: { fulfillmentCenter: true, supplier: true, items: { include: { product: true, }, }, }, }) // Отправляем уведомление поставщику о новой заявке await notifyOrganization(supplier.id, { type: 'supply-order:new', title: 'Новая заявка на поставку расходников', message: `Фулфилмент-центр "${user.organization.name}" создал заявку на поставку расходников`, data: { supplyOrderId: supplyOrder.id, supplyOrderType: 'FULFILLMENT_CONSUMABLES_V2', fulfillmentCenterName: user.organization.name, itemsCount: args.input.items.length, requestedDeliveryDate: args.input.requestedDeliveryDate, }, }) return { success: true, message: 'Поставка расходников создана успешно', supplyOrder, } } catch (error) { console.error('Error creating fulfillment consumable supply:', error) return { success: false, message: error instanceof Error ? error.message : 'Ошибка создания поставки', supplyOrder: null, } } }, // Добавляем мутации поставщика supplierApproveConsumableSupply, supplierRejectConsumableSupply, supplierShipConsumableSupply, }