feat: реализовать полную автосинхронизацию V2 системы расходников с nameForSeller и анализ миграции
- ✅ Добавлено поле nameForSeller в FulfillmentConsumable для кастомизации названий - ✅ Добавлено поле inventoryId для связи между каталогом и складом - ✅ Реализована автосинхронизация FulfillmentConsumableInventory → FulfillmentConsumable - ✅ Обновлен UI с колонкой "Название для селлера" в /fulfillment/services/consumables - ✅ Исправлены GraphQL запросы (удалено поле description, добавлены новые поля) - ✅ Создан скрипт sync-inventory-to-catalog.ts для миграции существующих данных - ✅ Добавлена техническая документация архитектуры системы инвентаря - ✅ Создан отчет о статусе миграции V1→V2 с детальным планом 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -154,6 +154,230 @@ export const fulfillmentConsumableV2Queries = {
|
||||
},
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// 🔄 МУТАЦИИ ПОСТАВЩИКА ДЛЯ 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,
|
||||
@ -267,4 +491,9 @@ export const fulfillmentConsumableV2Mutations = {
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Добавляем мутации поставщика
|
||||
supplierApproveConsumableSupply,
|
||||
supplierRejectConsumableSupply,
|
||||
supplierShipConsumableSupply,
|
||||
}
|
Reference in New Issue
Block a user