Добавлены модели и функциональность для управления логистикой, включая создание, обновление и удаление логистических маршрутов через GraphQL. Обновлены компоненты для отображения и управления логистикой, улучшен интерфейс взаимодействия с пользователем. Реализованы новые типы данных и интерфейсы для логистики, а также улучшена обработка ошибок.
This commit is contained in:
@ -602,7 +602,6 @@ export const CREATE_SUPPLY = gql`
|
||||
name
|
||||
description
|
||||
price
|
||||
quantity
|
||||
imageUrl
|
||||
createdAt
|
||||
updatedAt
|
||||
@ -621,7 +620,6 @@ export const UPDATE_SUPPLY = gql`
|
||||
name
|
||||
description
|
||||
price
|
||||
quantity
|
||||
imageUrl
|
||||
createdAt
|
||||
updatedAt
|
||||
@ -636,6 +634,51 @@ export const DELETE_SUPPLY = gql`
|
||||
}
|
||||
`
|
||||
|
||||
// Мутации для логистики
|
||||
export const CREATE_LOGISTICS = gql`
|
||||
mutation CreateLogistics($input: LogisticsInput!) {
|
||||
createLogistics(input: $input) {
|
||||
success
|
||||
message
|
||||
logistics {
|
||||
id
|
||||
fromLocation
|
||||
toLocation
|
||||
priceUnder1m3
|
||||
priceOver1m3
|
||||
description
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const UPDATE_LOGISTICS = gql`
|
||||
mutation UpdateLogistics($id: ID!, $input: LogisticsInput!) {
|
||||
updateLogistics(id: $id, input: $input) {
|
||||
success
|
||||
message
|
||||
logistics {
|
||||
id
|
||||
fromLocation
|
||||
toLocation
|
||||
priceUnder1m3
|
||||
priceOver1m3
|
||||
description
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const DELETE_LOGISTICS = gql`
|
||||
mutation DeleteLogistics($id: ID!) {
|
||||
deleteLogistics(id: $id)
|
||||
}
|
||||
`
|
||||
|
||||
// Мутации для товаров оптовика
|
||||
export const CREATE_PRODUCT = gql`
|
||||
mutation CreateProduct($input: ProductInput!) {
|
||||
|
@ -69,7 +69,6 @@ export const GET_MY_SUPPLIES = gql`
|
||||
name
|
||||
description
|
||||
price
|
||||
quantity
|
||||
imageUrl
|
||||
createdAt
|
||||
updatedAt
|
||||
@ -77,6 +76,21 @@ export const GET_MY_SUPPLIES = gql`
|
||||
}
|
||||
`
|
||||
|
||||
export const GET_MY_LOGISTICS = gql`
|
||||
query GetMyLogistics {
|
||||
myLogistics {
|
||||
id
|
||||
fromLocation
|
||||
toLocation
|
||||
priceUnder1m3
|
||||
priceOver1m3
|
||||
description
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const GET_MY_PRODUCTS = gql`
|
||||
query GetMyProducts {
|
||||
myProducts {
|
||||
|
@ -530,12 +530,31 @@ export const resolvers = {
|
||||
throw new GraphQLError('У пользователя нет организации')
|
||||
}
|
||||
|
||||
// Проверяем, что это фулфилмент центр
|
||||
if (currentUser.organization.type !== 'FULFILLMENT') {
|
||||
throw new GraphQLError('Расходники доступны только для фулфилмент центров')
|
||||
return await prisma.supply.findMany({
|
||||
where: { organizationId: currentUser.organization.id },
|
||||
include: { organization: true },
|
||||
orderBy: { createdAt: 'desc' }
|
||||
})
|
||||
},
|
||||
|
||||
// Логистика организации
|
||||
myLogistics: async (_: unknown, __: unknown, context: Context) => {
|
||||
if (!context.user) {
|
||||
throw new GraphQLError('Требуется авторизация', {
|
||||
extensions: { code: 'UNAUTHENTICATED' }
|
||||
})
|
||||
}
|
||||
|
||||
return await prisma.supply.findMany({
|
||||
const currentUser = await prisma.user.findUnique({
|
||||
where: { id: context.user.id },
|
||||
include: { organization: true }
|
||||
})
|
||||
|
||||
if (!currentUser?.organization) {
|
||||
throw new GraphQLError('У пользователя нет организации')
|
||||
}
|
||||
|
||||
return await prisma.logistics.findMany({
|
||||
where: { organizationId: currentUser.organization.id },
|
||||
include: { organization: true },
|
||||
orderBy: { createdAt: 'desc' }
|
||||
@ -2322,7 +2341,7 @@ export const resolvers = {
|
||||
},
|
||||
|
||||
// Создать расходник
|
||||
createSupply: async (_: unknown, args: { input: { name: string; description?: string; price: number; quantity: number; imageUrl?: string } }, context: Context) => {
|
||||
createSupply: async (_: unknown, args: { input: { name: string; description?: string; price: number; imageUrl?: string } }, context: Context) => {
|
||||
if (!context.user) {
|
||||
throw new GraphQLError('Требуется авторизация', {
|
||||
extensions: { code: 'UNAUTHENTICATED' }
|
||||
@ -2349,7 +2368,7 @@ export const resolvers = {
|
||||
name: args.input.name,
|
||||
description: args.input.description,
|
||||
price: args.input.price,
|
||||
quantity: args.input.quantity,
|
||||
quantity: 0, // Временно устанавливаем 0, так как поле убрано из интерфейса
|
||||
imageUrl: args.input.imageUrl,
|
||||
organizationId: currentUser.organization.id
|
||||
},
|
||||
@ -2371,7 +2390,7 @@ export const resolvers = {
|
||||
},
|
||||
|
||||
// Обновить расходник
|
||||
updateSupply: async (_: unknown, args: { id: string; input: { name: string; description?: string; price: number; quantity: number; imageUrl?: string } }, context: Context) => {
|
||||
updateSupply: async (_: unknown, args: { id: string; input: { name: string; description?: string; price: number; imageUrl?: string } }, context: Context) => {
|
||||
if (!context.user) {
|
||||
throw new GraphQLError('Требуется авторизация', {
|
||||
extensions: { code: 'UNAUTHENTICATED' }
|
||||
@ -2406,7 +2425,7 @@ export const resolvers = {
|
||||
name: args.input.name,
|
||||
description: args.input.description,
|
||||
price: args.input.price,
|
||||
quantity: args.input.quantity,
|
||||
quantity: 0, // Временно устанавливаем 0, так как поле убрано из интерфейса
|
||||
imageUrl: args.input.imageUrl
|
||||
},
|
||||
include: { organization: true }
|
||||
@ -3558,4 +3577,163 @@ export const resolvers = {
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Логистические мутации
|
||||
const logisticsMutations = {
|
||||
// Создать логистический маршрут
|
||||
createLogistics: async (_: unknown, args: { input: { fromLocation: string; toLocation: string; priceUnder1m3: number; priceOver1m3: number; description?: string } }, context: Context) => {
|
||||
if (!context.user) {
|
||||
throw new GraphQLError('Требуется авторизация', {
|
||||
extensions: { code: 'UNAUTHENTICATED' }
|
||||
})
|
||||
}
|
||||
|
||||
const currentUser = await prisma.user.findUnique({
|
||||
where: { id: context.user.id },
|
||||
include: { organization: true }
|
||||
})
|
||||
|
||||
if (!currentUser?.organization) {
|
||||
throw new GraphQLError('У пользователя нет организации')
|
||||
}
|
||||
|
||||
try {
|
||||
const logistics = await prisma.logistics.create({
|
||||
data: {
|
||||
fromLocation: args.input.fromLocation,
|
||||
toLocation: args.input.toLocation,
|
||||
priceUnder1m3: args.input.priceUnder1m3,
|
||||
priceOver1m3: args.input.priceOver1m3,
|
||||
description: args.input.description,
|
||||
organizationId: currentUser.organization.id
|
||||
},
|
||||
include: {
|
||||
organization: true
|
||||
}
|
||||
})
|
||||
|
||||
console.log('✅ Logistics created:', logistics.id)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'Логистический маршрут создан',
|
||||
logistics
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Error creating logistics:', error)
|
||||
return {
|
||||
success: false,
|
||||
message: 'Ошибка при создании логистического маршрута'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Обновить логистический маршрут
|
||||
updateLogistics: async (_: unknown, args: { id: string; input: { fromLocation: string; toLocation: string; priceUnder1m3: number; priceOver1m3: number; description?: string } }, context: Context) => {
|
||||
if (!context.user) {
|
||||
throw new GraphQLError('Требуется авторизация', {
|
||||
extensions: { code: 'UNAUTHENTICATED' }
|
||||
})
|
||||
}
|
||||
|
||||
const currentUser = await prisma.user.findUnique({
|
||||
where: { id: context.user.id },
|
||||
include: { organization: true }
|
||||
})
|
||||
|
||||
if (!currentUser?.organization) {
|
||||
throw new GraphQLError('У пользователя нет организации')
|
||||
}
|
||||
|
||||
try {
|
||||
// Проверяем, что маршрут принадлежит организации пользователя
|
||||
const existingLogistics = await prisma.logistics.findFirst({
|
||||
where: {
|
||||
id: args.id,
|
||||
organizationId: currentUser.organization.id
|
||||
}
|
||||
})
|
||||
|
||||
if (!existingLogistics) {
|
||||
throw new GraphQLError('Логистический маршрут не найден')
|
||||
}
|
||||
|
||||
const logistics = await prisma.logistics.update({
|
||||
where: { id: args.id },
|
||||
data: {
|
||||
fromLocation: args.input.fromLocation,
|
||||
toLocation: args.input.toLocation,
|
||||
priceUnder1m3: args.input.priceUnder1m3,
|
||||
priceOver1m3: args.input.priceOver1m3,
|
||||
description: args.input.description
|
||||
},
|
||||
include: {
|
||||
organization: true
|
||||
}
|
||||
})
|
||||
|
||||
console.log('✅ Logistics updated:', logistics.id)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'Логистический маршрут обновлен',
|
||||
logistics
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Error updating logistics:', error)
|
||||
return {
|
||||
success: false,
|
||||
message: 'Ошибка при обновлении логистического маршрута'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Удалить логистический маршрут
|
||||
deleteLogistics: async (_: unknown, args: { id: string }, context: Context) => {
|
||||
if (!context.user) {
|
||||
throw new GraphQLError('Требуется авторизация', {
|
||||
extensions: { code: 'UNAUTHENTICATED' }
|
||||
})
|
||||
}
|
||||
|
||||
const currentUser = await prisma.user.findUnique({
|
||||
where: { id: context.user.id },
|
||||
include: { organization: true }
|
||||
})
|
||||
|
||||
if (!currentUser?.organization) {
|
||||
throw new GraphQLError('У пользователя нет организации')
|
||||
}
|
||||
|
||||
try {
|
||||
// Проверяем, что маршрут принадлежит организации пользователя
|
||||
const existingLogistics = await prisma.logistics.findFirst({
|
||||
where: {
|
||||
id: args.id,
|
||||
organizationId: currentUser.organization.id
|
||||
}
|
||||
})
|
||||
|
||||
if (!existingLogistics) {
|
||||
throw new GraphQLError('Логистический маршрут не найден')
|
||||
}
|
||||
|
||||
await prisma.logistics.delete({
|
||||
where: { id: args.id }
|
||||
})
|
||||
|
||||
console.log('✅ Logistics deleted:', args.id)
|
||||
return true
|
||||
} catch (error) {
|
||||
console.error('❌ Error deleting logistics:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Добавляем логистические мутации к основным резолверам
|
||||
resolvers.Mutation = {
|
||||
...resolvers.Mutation,
|
||||
...logisticsMutations
|
||||
}
|
@ -29,6 +29,9 @@ export const typeDefs = gql`
|
||||
# Расходники организации
|
||||
mySupplies: [Supply!]!
|
||||
|
||||
# Логистика организации
|
||||
myLogistics: [Logistics!]!
|
||||
|
||||
# Товары оптовика
|
||||
myProducts: [Product!]!
|
||||
|
||||
@ -100,6 +103,11 @@ export const typeDefs = gql`
|
||||
updateSupply(id: ID!, input: SupplyInput!): SupplyResponse!
|
||||
deleteSupply(id: ID!): Boolean!
|
||||
|
||||
# Работа с логистикой
|
||||
createLogistics(input: LogisticsInput!): LogisticsResponse!
|
||||
updateLogistics(id: ID!, input: LogisticsInput!): LogisticsResponse!
|
||||
deleteLogistics(id: ID!): Boolean!
|
||||
|
||||
# Работа с товарами (для оптовиков)
|
||||
createProduct(input: ProductInput!): ProductResponse!
|
||||
updateProduct(id: ID!, input: ProductInput!): ProductResponse!
|
||||
@ -372,7 +380,6 @@ export const typeDefs = gql`
|
||||
name: String!
|
||||
description: String
|
||||
price: Float!
|
||||
quantity: Int!
|
||||
imageUrl: String
|
||||
createdAt: String!
|
||||
updatedAt: String!
|
||||
@ -383,7 +390,6 @@ export const typeDefs = gql`
|
||||
name: String!
|
||||
description: String
|
||||
price: Float!
|
||||
quantity: Int!
|
||||
imageUrl: String
|
||||
}
|
||||
|
||||
@ -393,6 +399,33 @@ export const typeDefs = gql`
|
||||
supply: Supply
|
||||
}
|
||||
|
||||
# Типы для логистики
|
||||
type Logistics {
|
||||
id: ID!
|
||||
fromLocation: String!
|
||||
toLocation: String!
|
||||
priceUnder1m3: Float!
|
||||
priceOver1m3: Float!
|
||||
description: String
|
||||
createdAt: String!
|
||||
updatedAt: String!
|
||||
organization: Organization!
|
||||
}
|
||||
|
||||
input LogisticsInput {
|
||||
fromLocation: String!
|
||||
toLocation: String!
|
||||
priceUnder1m3: Float!
|
||||
priceOver1m3: Float!
|
||||
description: String
|
||||
}
|
||||
|
||||
type LogisticsResponse {
|
||||
success: Boolean!
|
||||
message: String!
|
||||
logistics: Logistics
|
||||
}
|
||||
|
||||
# Типы для категорий товаров
|
||||
type Category {
|
||||
id: ID!
|
||||
|
Reference in New Issue
Block a user