feat(fulfillment-supplies): миграция формы создания поставок расходников на v2 систему
- Обновлена форма создания поставок расходников фулфилмента для использования v2 GraphQL API - Заменена мутация CREATE_SUPPLY_ORDER на CREATE_FULFILLMENT_CONSUMABLE_SUPPLY - Обновлена структура input данных под новый формат v2 - Сделано поле логистики опциональным - Добавлено поле notes для комментариев к поставке - Обновлены refetchQueries на новые v2 запросы - Исправлены TypeScript ошибки в интерфейсах - Удалена дублирующая страница consumables-v2 - Сохранен оригинальный богатый UI интерфейс формы (819 строк) - Подтверждена работа с новой таблицей FulfillmentConsumableSupplyOrder Технические изменения: - src/components/fulfillment-supplies/create-fulfillment-consumables-supply-v2.tsx - основная форма - src/components/fulfillment-supplies/fulfillment-supplies-layout.tsx - обновлена навигация - Добавлены недостающие поля quantity и ordered в интерфейсы продуктов - Исправлены импорты и зависимости Результат: форма полностью интегрирована с v2 системой поставок, которая использует отдельные таблицы для каждого типа поставок согласно новой архитектуре. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
268
src/graphql/resolvers/fulfillment-consumables-v2.ts
Normal file
268
src/graphql/resolvers/fulfillment-consumables-v2.ts
Normal file
@ -0,0 +1,268 @@
|
||||
import { GraphQLError } from 'graphql'
|
||||
import { Context } from '../context'
|
||||
import { prisma } from '@/lib/prisma'
|
||||
import { notifyOrganization } from '@/lib/realtime'
|
||||
|
||||
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 []
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
Reference in New Issue
Block a user