Files
sfera-new/src/graphql/typedefs.ts
Veronika Smirnova a48efb8757 feat(v2-inventory): мигрировать систему расходников на V2 архитектуру
Переход от старой таблицы Supply к новой FulfillmentConsumableInventory:

- Обновлен mySupplies resolver для чтения из V2 таблицы с корректными остатками
- Добавлена V2 мутация updateFulfillmentInventoryPrice для обновления цен
- Исправлен counterpartySupplies для показа актуальных V2 цен в рецептурах
- Frontend использует новую мутацию UPDATE_FULFILLMENT_INVENTORY_PRICE
- Цены расходников корректно сохраняются и отображаются после перезагрузки
- Селлеры видят правильные цены при создании поставок товаров

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-25 22:26:29 +03:00

1971 lines
54 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { gql } from 'graphql-tag'
export const typeDefs = gql`
scalar DateTime
type Query {
me: User
organization(id: ID!): Organization
# Поиск организаций по типу для добавления в контрагенты
searchOrganizations(type: OrganizationType, search: String): [Organization!]!
# Мои контрагенты
myCounterparties: [Organization!]!
# Поставщики поставок
supplySuppliers: [SupplySupplier!]!
# Логистика организации
organizationLogistics(organizationId: ID!): [Logistics!]!
# Входящие заявки
incomingRequests: [CounterpartyRequest!]!
# Исходящие заявки
outgoingRequests: [CounterpartyRequest!]!
# Сообщения с контрагентом
messages(counterpartyId: ID!, limit: Int, offset: Int): [Message!]!
# Список чатов (последние сообщения с каждым контрагентом)
conversations: [Conversation!]!
# Услуги организации
myServices: [Service!]!
# Расходники селлеров (материалы клиентов)
mySupplies: [Supply!]!
# Доступные расходники для рецептур селлеров (только с ценой и в наличии)
getAvailableSuppliesForRecipe: [SupplyForRecipe!]!
# Расходники фулфилмента (материалы для работы фулфилмента)
myFulfillmentSupplies: [Supply!]!
# Расходники селлеров на складе фулфилмента (только для фулфилмента)
sellerSuppliesOnWarehouse: [Supply!]!
# Заказы поставок расходников
supplyOrders: [SupplyOrder!]!
# Мои поставки (для селлера) - многоуровневая таблица
mySupplyOrders: [SupplyOrder!]!
# Счетчик поставок, требующих одобрения
pendingSuppliesCount: PendingSuppliesCount!
# Логистика организации
myLogistics: [Logistics!]!
# Логистические партнеры (организации-логисты)
logisticsPartners: [Organization!]!
# Поставки Wildberries
myWildberriesSupplies: [WildberriesSupply!]!
# Товары поставщика
myProducts: [Product!]!
# Товары на складе фулфилмента
warehouseProducts: [Product!]!
# Данные склада с партнерами (3-уровневая иерархия)
warehouseData: WarehouseDataResponse!
# Все товары всех поставщиков для маркета
allProducts(search: String, category: String): [Product!]!
# Товары конкретной организации (для формы создания поставки)
organizationProducts(organizationId: ID!, search: String, category: String, type: String): [Product!]!
# Все категории
categories: [Category!]!
# Корзина пользователя
myCart: Cart
# Избранные товары пользователя
myFavorites: [Product!]!
# Сотрудники организации
myEmployees: [Employee!]!
employee(id: ID!): Employee
# Табель сотрудника за месяц
employeeSchedule(employeeId: ID!, year: Int!, month: Int!): [EmployeeSchedule!]!
# Публичные услуги контрагента (для фулфилмента)
counterpartyServices(organizationId: ID!): [Service!]!
# Публичные расходники контрагента (для поставщиков)
counterpartySupplies(organizationId: ID!): [Supply!]!
# Админ запросы
adminMe: Admin
allUsers(search: String, limit: Int, offset: Int): UsersResponse!
# Wildberries статистика
getWildberriesStatistics(period: String, startDate: String, endDate: String): WildberriesStatisticsResponse!
# Отладка рекламы (временно)
debugWildberriesAdverts: DebugAdvertsResponse!
# Статистика кампаний Wildberries
getWildberriesCampaignStats(input: WildberriesCampaignStatsInput!): WildberriesCampaignStatsResponse!
# Список кампаний Wildberries
getWildberriesCampaignsList: WildberriesCampaignsListResponse!
# Заявки покупателей на возврат от Wildberries (для фулфилмента)
wbReturnClaims(isArchive: Boolean!, limit: Int, offset: Int): WbReturnClaimsResponse!
# Типы для внешней рекламы
getExternalAds(dateFrom: String!, dateTo: String!): ExternalAdsResponse!
# Типы для кеша склада WB
getWBWarehouseData: WBWarehouseCacheResponse!
# Реферальная система
myReferralLink: String!
myPartnerLink: String!
myReferrals(
dateFrom: DateTime
dateTo: DateTime
type: OrganizationType
source: ReferralSource
search: String
limit: Int
offset: Int
): ReferralsResponse!
myReferralStats: ReferralStats!
myReferralTransactions(
limit: Int
offset: Int
): ReferralTransactionsResponse!
}
type Mutation {
# Авторизация через SMS
sendSmsCode(phone: String!): SmsResponse!
verifySmsCode(phone: String!, code: String!): AuthResponse!
# Валидация ИНН
verifyInn(inn: String!): InnValidationResponse!
# Обновление профиля пользователя
updateUserProfile(input: UpdateUserProfileInput!): UpdateUserProfileResponse!
# Обновление данных организации по ИНН
updateOrganizationByInn(inn: String!): UpdateOrganizationResponse!
# Регистрация организации
registerFulfillmentOrganization(input: FulfillmentRegistrationInput!): AuthResponse!
registerSellerOrganization(input: SellerRegistrationInput!): AuthResponse!
# Работа с API ключами
addMarketplaceApiKey(input: MarketplaceApiKeyInput!): ApiKeyResponse!
removeMarketplaceApiKey(marketplace: MarketplaceType!): Boolean!
# Выход из системы
logout: Boolean!
# Работа с контрагентами
sendCounterpartyRequest(organizationId: ID!, message: String): CounterpartyRequestResponse!
respondToCounterpartyRequest(requestId: ID!, accept: Boolean!): CounterpartyRequestResponse!
cancelCounterpartyRequest(requestId: ID!): Boolean!
removeCounterparty(organizationId: ID!): Boolean!
# Автоматическое создание записей склада при партнерстве
autoCreateWarehouseEntry(partnerId: ID!): AutoWarehouseEntryResponse!
# Работа с сообщениями
sendMessage(receiverOrganizationId: ID!, content: String, type: MessageType = TEXT): MessageResponse!
sendVoiceMessage(receiverOrganizationId: ID!, voiceUrl: String!, voiceDuration: Int!): MessageResponse!
sendImageMessage(
receiverOrganizationId: ID!
fileUrl: String!
fileName: String!
fileSize: Int!
fileType: String!
): MessageResponse!
sendFileMessage(
receiverOrganizationId: ID!
fileUrl: String!
fileName: String!
fileSize: Int!
fileType: String!
): MessageResponse!
markMessagesAsRead(conversationId: ID!): Boolean!
# Работа с услугами
createService(input: ServiceInput!): ServiceResponse!
updateService(id: ID!, input: ServiceInput!): ServiceResponse!
deleteService(id: ID!): Boolean!
# Работа с расходниками (только обновление цены разрешено)
# DEPRECATED: используйте updateFulfillmentInventoryPrice
updateSupplyPrice(id: ID!, input: UpdateSupplyPriceInput!): SupplyResponse!
updateFulfillmentInventoryPrice(id: ID!, input: UpdateSupplyPriceInput!): FulfillmentInventoryResponse!
# Использование расходников фулфилмента
useFulfillmentSupplies(input: UseFulfillmentSuppliesInput!): SupplyResponse!
# Заказы поставок расходников
createSupplyOrder(input: SupplyOrderInput!): SupplyOrderResponse!
updateSupplyOrderStatus(id: ID!, status: SupplyOrderStatus!): SupplyOrderResponse!
updateSupplyParameters(id: ID!, volume: Float, packagesCount: Int): SupplyOrderResponse!
# Назначение логистики фулфилментом
assignLogisticsToSupply(supplyOrderId: ID!, logisticsPartnerId: ID!, responsibleId: ID): SupplyOrderResponse!
# Действия поставщика
supplierApproveOrder(id: ID!): SupplyOrderResponse!
supplierRejectOrder(id: ID!, reason: String): SupplyOrderResponse!
supplierShipOrder(id: ID!): SupplyOrderResponse!
# Действия логиста
logisticsConfirmOrder(id: ID!): SupplyOrderResponse!
logisticsRejectOrder(id: ID!, reason: String): SupplyOrderResponse!
# Действия фулфилмента
fulfillmentReceiveOrder(id: ID!): SupplyOrderResponse!
# Новые действия для многоуровневой системы
fulfillmentAssignEmployee(supplyOrderId: ID!, employeeId: ID!): SupplyOrderResponse!
fulfillmentSelectLogistics(supplyOrderId: ID!, logisticsPartnerId: ID!): SupplyOrderResponse!
fulfillmentStartProcessing(supplyOrderId: ID!): SupplyOrderResponse!
# Действия поставщика с упаковкой
supplierApproveOrderWithPackaging(id: ID!, packagesCount: Int, volume: Float): SupplyOrderResponse!
# Работа с логистикой
createLogistics(input: LogisticsInput!): LogisticsResponse!
updateLogistics(id: ID!, input: LogisticsInput!): LogisticsResponse!
deleteLogistics(id: ID!): Boolean!
# Работа с товарами (для поставщиков)
createProduct(input: ProductInput!): ProductResponse!
updateProduct(id: ID!, input: ProductInput!): ProductResponse!
deleteProduct(id: ID!): Boolean!
# Валидация и управление остатками товаров
checkArticleUniqueness(article: String!, excludeId: ID): ArticleUniquenessResponse!
reserveProductStock(productId: ID!, quantity: Int!): ProductStockResponse!
releaseProductReserve(productId: ID!, quantity: Int!): ProductStockResponse!
updateProductInTransit(productId: ID!, quantity: Int!, operation: String!): ProductStockResponse!
# Работа с категориями
createCategory(input: CategoryInput!): CategoryResponse!
updateCategory(id: ID!, input: CategoryInput!): CategoryResponse!
deleteCategory(id: ID!): Boolean!
# Работа с корзиной
addToCart(productId: ID!, quantity: Int = 1): CartResponse!
updateCartItem(productId: ID!, quantity: Int!): CartResponse!
removeFromCart(productId: ID!): CartResponse!
clearCart: Boolean!
# Работа с избранным
addToFavorites(productId: ID!): FavoritesResponse!
removeFromFavorites(productId: ID!): FavoritesResponse!
# Работа с сотрудниками
createEmployee(input: CreateEmployeeInput!): EmployeeResponse!
updateEmployee(id: ID!, input: UpdateEmployeeInput!): EmployeeResponse!
deleteEmployee(id: ID!): Boolean!
updateEmployeeSchedule(input: UpdateScheduleInput!): Boolean!
# Работа с поставками Wildberries
createWildberriesSupply(input: CreateWildberriesSupplyInput!): WildberriesSupplyResponse!
updateWildberriesSupply(id: ID!, input: UpdateWildberriesSupplyInput!): WildberriesSupplyResponse!
deleteWildberriesSupply(id: ID!): Boolean!
# Работа с поставщиками для поставок
createSupplySupplier(input: CreateSupplySupplierInput!): SupplySupplierResponse!
# Админ мутации
adminLogin(username: String!, password: String!): AdminAuthResponse!
adminLogout: Boolean!
# Типы для внешней рекламы
createExternalAd(input: ExternalAdInput!): ExternalAdResponse!
updateExternalAd(id: ID!, input: ExternalAdInput!): ExternalAdResponse!
deleteExternalAd(id: ID!): ExternalAdResponse!
updateExternalAdClicks(id: ID!, clicks: Int!): ExternalAdResponse!
}
# Типы данных
type User {
id: ID!
phone: String!
avatar: String
managerName: String
organization: Organization
createdAt: DateTime!
updatedAt: DateTime!
}
type Organization {
id: ID!
inn: String!
kpp: String
name: String
fullName: String
address: String
addressFull: String
ogrn: String
ogrnDate: DateTime
type: OrganizationType!
market: String
status: String
actualityDate: DateTime
registrationDate: DateTime
liquidationDate: DateTime
managementName: String
managementPost: String
opfCode: String
opfFull: String
opfShort: String
okato: String
oktmo: String
okpo: String
okved: String
employeeCount: Int
revenue: String
taxSystem: String
phones: JSON
emails: JSON
users: [User!]!
apiKeys: [ApiKey!]!
services: [Service!]!
supplies: [Supply!]!
isCounterparty: Boolean
isCurrentUser: Boolean
hasOutgoingRequest: Boolean
hasIncomingRequest: Boolean
# Реферальная система
referralCode: String
referredBy: Organization
referrals: [Organization!]!
referralPoints: Int!
isMyReferral: Boolean!
createdAt: DateTime!
updatedAt: DateTime!
}
type ApiKey {
id: ID!
marketplace: MarketplaceType!
apiKey: String!
isActive: Boolean!
validationData: JSON
createdAt: DateTime!
updatedAt: DateTime!
}
# Входные типы для мутаций
input UpdateUserProfileInput {
# Аватар пользователя
avatar: String
# Контактные данные организации
orgPhone: String
managerName: String
telegram: String
whatsapp: String
email: String
# Банковские данные
bankName: String
bik: String
accountNumber: String
corrAccount: String
# Рынок для поставщиков
market: String
}
input FulfillmentRegistrationInput {
phone: String!
inn: String!
type: OrganizationType!
referralCode: String
partnerCode: String
}
input SellerRegistrationInput {
phone: String!
wbApiKey: String
ozonApiKey: String
ozonClientId: String
referralCode: String
partnerCode: String
}
input MarketplaceApiKeyInput {
marketplace: MarketplaceType!
apiKey: String!
clientId: String # Для Ozon
validateOnly: Boolean # Только валидация без сохранения
}
# Ответные типы
type SmsResponse {
success: Boolean!
message: String!
}
type AuthResponse {
success: Boolean!
message: String!
token: String
user: User
}
type InnValidationResponse {
success: Boolean!
message: String!
organization: ValidatedOrganization
}
type ValidatedOrganization {
name: String!
fullName: String!
address: String!
isActive: Boolean!
}
type ApiKeyResponse {
success: Boolean!
message: String!
apiKey: ApiKey
}
type UpdateUserProfileResponse {
success: Boolean!
message: String!
user: User
}
type UpdateOrganizationResponse {
success: Boolean!
message: String!
user: User
}
# Enums
enum OrganizationType {
FULFILLMENT
SELLER
LOGIST
WHOLESALE
}
enum MarketplaceType {
WILDBERRIES
OZON
}
# ProductType теперь String, чтобы поддерживать кириллические значения из БД
# Возможные значения: "ТОВАР", "БРАК", "РАСХОДНИКИ", "ПРОДУКТ"
enum CounterpartyRequestStatus {
PENDING
ACCEPTED
REJECTED
CANCELLED
}
# Типы для контрагентов
type CounterpartyRequest {
id: ID!
status: CounterpartyRequestStatus!
message: String
sender: Organization!
receiver: Organization!
createdAt: DateTime!
updatedAt: DateTime!
}
type CounterpartyRequestResponse {
success: Boolean!
message: String!
request: CounterpartyRequest
}
# Типы для автоматического создания записей склада
type WarehouseEntry {
id: ID!
storeName: String!
storeOwner: String!
storeImage: String
storeQuantity: Int!
partnershipDate: DateTime!
}
type AutoWarehouseEntryResponse {
success: Boolean!
message: String!
warehouseEntry: WarehouseEntry
}
# Типы для данных склада с 3-уровневой иерархией
type ProductVariant {
id: ID!
variantName: String!
variantQuantity: Int!
variantPlace: String
}
type ProductItem {
id: ID!
productName: String!
productQuantity: Int!
productPlace: String
variants: [ProductVariant!]!
}
type StoreData {
id: ID!
storeName: String!
storeOwner: String!
storeImage: String
storeQuantity: Int!
partnershipDate: DateTime!
products: [ProductItem!]!
}
type WarehouseDataResponse {
stores: [StoreData!]!
}
# Типы для сообщений
type Message {
id: ID!
content: String
type: MessageType
voiceUrl: String
voiceDuration: Int
fileUrl: String
fileName: String
fileSize: Int
fileType: String
senderId: ID!
senderOrganization: Organization!
receiverOrganization: Organization!
isRead: Boolean!
createdAt: DateTime!
updatedAt: DateTime!
}
enum MessageType {
TEXT
VOICE
IMAGE
FILE
}
type Conversation {
id: ID!
counterparty: Organization!
lastMessage: Message
unreadCount: Int!
updatedAt: DateTime!
}
type MessageResponse {
success: Boolean!
message: String!
messageData: Message
}
# Типы для услуг
type Service {
id: ID!
name: String!
description: String
price: Float!
imageUrl: String
createdAt: DateTime!
updatedAt: DateTime!
organization: Organization!
}
input ServiceInput {
name: String!
description: String
price: Float!
imageUrl: String
}
type ServiceResponse {
success: Boolean!
message: String!
service: Service
}
# Типы для расходников
enum SupplyType {
FULFILLMENT_CONSUMABLES # Расходники фулфилмента (купленные фулфилментом для себя)
SELLER_CONSUMABLES # Расходники селлеров (принятые от селлеров для хранения)
}
type Supply {
id: ID!
name: String!
article: String! # ДОБАВЛЕНО: Артикул СФ для уникальности
description: String
# Новые поля для Services архитектуры
pricePerUnit: Float # Цена за единицу для рецептур (может быть null)
unit: String! # Единица измерения: "шт", "кг", "м"
warehouseStock: Int! # Остаток на складе (readonly)
isAvailable: Boolean! # Есть ли на складе (влияет на цвет)
warehouseConsumableId: ID! # Связь со складом
# Поля из базы данных для обратной совместимости
price: Float! # Цена закупки у поставщика (не меняется)
quantity: Int! # Из Prisma schema (заказанное количество)
actualQuantity: Int # НОВОЕ: Фактически поставленное количество (NULL = еще не пересчитали)
category: String! # Из Prisma schema
status: String! # Из Prisma schema
date: DateTime! # Из Prisma schema
supplier: String! # Из Prisma schema
minStock: Int! # Из Prisma schema
currentStock: Int! # Из Prisma schema
usedStock: Int! # Из Prisma schema
type: String! # Из Prisma schema (SupplyType enum)
sellerOwnerId: ID # Из Prisma schema
sellerOwner: Organization # Из Prisma schema
shopLocation: String # Из Prisma schema
imageUrl: String
createdAt: DateTime!
updatedAt: DateTime!
organization: Organization!
}
# Для рецептур селлеров - только доступные с ценой
type SupplyForRecipe {
id: ID!
name: String!
pricePerUnit: Float! # Всегда не null
unit: String!
imageUrl: String
warehouseStock: Int! # Всегда > 0
}
# Для обновления цены расходника в разделе Услуги
input UpdateSupplyPriceInput {
pricePerUnit: Float # Может быть null (цена не установлена)
}
# V2 типы для инвентаря фулфилмента
type FulfillmentInventoryItem {
id: ID!
name: String!
description: String
pricePerUnit: Float # Цена перепродажи
unit: String!
imageUrl: String
warehouseStock: Int!
isAvailable: Boolean!
warehouseConsumableId: ID!
createdAt: DateTime!
updatedAt: DateTime!
organization: Organization!
}
type FulfillmentInventoryResponse {
success: Boolean!
message: String!
item: FulfillmentInventoryItem
}
input UseFulfillmentSuppliesInput {
supplyId: ID!
quantityUsed: Int!
description: String # Описание использования (например, "Подготовка 300 продуктов")
}
# Устаревшие типы для обратной совместимости
input SupplyInput {
name: String!
description: String
price: Float!
imageUrl: String
}
type SupplyResponse {
success: Boolean!
message: String!
supply: Supply
}
# Типы для заказов поставок расходников
type SupplyOrder {
id: ID!
organizationId: ID!
partnerId: ID!
partner: Organization!
deliveryDate: DateTime!
status: SupplyOrderStatus!
totalAmount: Float!
totalItems: Int!
fulfillmentCenterId: ID
fulfillmentCenter: Organization
logisticsPartnerId: ID
logisticsPartner: Organization
consumableType: String # Тип расходников: FULFILLMENT_CONSUMABLES, SELLER_CONSUMABLES
# Новые поля для многоуровневой системы поставок
packagesCount: Int # Количество грузовых мест (от поставщика)
volume: Float # Объём товара в м³ (от поставщика)
responsibleEmployee: ID # ID ответственного сотрудника ФФ
employee: Employee # Ответственный сотрудник
notes: String # Заметки и комментарии
routes: [SupplyRoute!]! # Маршруты поставки
items: [SupplyOrderItem!]!
createdAt: DateTime!
updatedAt: DateTime!
organization: Organization!
}
# Тип для маршрутов поставки (модульная архитектура)
type SupplyRoute {
id: ID!
supplyOrderId: ID!
logisticsId: ID # Ссылка на предустановленный маршрут
fromLocation: String! # Точка забора (рынок/поставщик)
toLocation: String! # Точка доставки (фулфилмент)
fromAddress: String # Полный адрес точки забора
toAddress: String # Полный адрес точки доставки
distance: Float # Расстояние в км
estimatedTime: Int # Время доставки в часах
price: Float # Стоимость логистики
status: String # Статус маршрута
createdAt: DateTime!
updatedAt: DateTime!
createdDate: DateTime! # Дата создания маршрута (уровень 2)
supplyOrder: SupplyOrder!
logistics: Logistics # Предустановленный логистический маршрут
}
type SupplyOrderItem {
id: ID!
productId: ID!
product: Product!
quantity: Int!
price: Float!
totalPrice: Float!
recipe: ProductRecipe
}
enum SupplyOrderStatus {
PENDING # Ожидает одобрения поставщика
CONFIRMED # Устаревший статус (для обратной совместимости)
IN_TRANSIT # Устаревший статус (для обратной совместимости)
SUPPLIER_APPROVED # Поставщик одобрил, ожидает подтверждения логистики
LOGISTICS_CONFIRMED # Логистика подтвердила, ожидает отправки
SHIPPED # Отправлено поставщиком, в пути
DELIVERED # Доставлено и принято фулфилментом
CANCELLED # Отменено (любой участник может отменить)
}
input SupplyOrderInput {
partnerId: ID!
deliveryDate: DateTime!
fulfillmentCenterId: ID # ID фулфилмент-центра для доставки
logisticsPartnerId: ID # ID логистической компании (опционально - может выбрать селлер или фулфилмент)
items: [SupplyOrderItemInput!]!
notes: String # Дополнительные заметки к заказу
consumableType: String # Классификация расходников: FULFILLMENT_CONSUMABLES, SELLER_CONSUMABLES
# Новые поля для многоуровневой системы
packagesCount: Int # Количество грузовых мест (заполняет поставщик)
volume: Float # Объём товара в м³ (заполняет поставщик)
routes: [SupplyRouteInput!] # Маршруты поставки
}
# Input тип для создания маршрутов поставки
input SupplyRouteInput {
logisticsId: ID # Ссылка на предустановленный маршрут
fromLocation: String! # Точка забора
toLocation: String! # Точка доставки
fromAddress: String # Полный адрес забора
toAddress: String # Полный адрес доставки
}
input SupplyOrderItemInput {
productId: ID!
quantity: Int!
recipe: ProductRecipeInput
}
type PendingSuppliesCount {
supplyOrders: Int!
ourSupplyOrders: Int! # Расходники фулфилмента
sellerSupplyOrders: Int! # Расходники селлеров
incomingSupplierOrders: Int! # 🔔 Входящие заказы для поставщиков
logisticsOrders: Int! # 🚚 Логистические заявки для логистики
incomingRequests: Int!
total: Int!
}
type SupplyOrderProcessInfo {
role: String! # Роль организации в процессе (SELLER, FULFILLMENT, LOGIST)
supplier: String! # Название поставщика
fulfillmentCenter: ID # ID фулфилмент-центра
logistics: ID # ID логистической компании
status: String! # Текущий статус заказа
}
# Типы для рецептуры продуктов
type ProductRecipe {
services: [Service!]!
fulfillmentConsumables: [Supply!]!
sellerConsumables: [Supply!]!
marketplaceCardId: String
}
input ProductRecipeInput {
services: [ID!]
fulfillmentConsumables: [ID!]
sellerConsumables: [ID!]
marketplaceCardId: String
}
type SupplyOrderResponse {
success: Boolean!
message: String!
order: SupplyOrder
processInfo: SupplyOrderProcessInfo # Информация о процессе поставки
}
# Типы для логистики
type Logistics {
id: ID!
fromLocation: String!
toLocation: String!
priceUnder1m3: Float!
priceOver1m3: Float!
description: String
createdAt: DateTime!
updatedAt: DateTime!
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!
name: String!
createdAt: DateTime!
updatedAt: DateTime!
}
# Типы для товаров поставщика
type Product {
id: ID!
name: String!
article: String!
description: String
price: Float!
pricePerSet: Float
quantity: Int!
setQuantity: Int
ordered: Int
inTransit: Int
stock: Int
sold: Int
type: String
category: Category
brand: String
color: String
size: String
weight: Float
dimensions: String
material: String
images: [String!]!
mainImage: String
isActive: Boolean!
createdAt: DateTime!
updatedAt: DateTime!
organization: Organization!
}
input ProductInput {
name: String!
article: String!
description: String
price: Float!
pricePerSet: Float
quantity: Int!
setQuantity: Int
ordered: Int
inTransit: Int
stock: Int
sold: Int
type: String
categoryId: ID
brand: String
color: String
size: String
weight: Float
dimensions: String
material: String
images: [String!]
mainImage: String
isActive: Boolean
}
type ProductResponse {
success: Boolean!
message: String!
product: Product
}
type ArticleUniquenessResponse {
isUnique: Boolean!
existingProduct: Product
}
type ProductStockResponse {
success: Boolean!
message: String!
product: Product
}
input CategoryInput {
name: String!
}
type CategoryResponse {
success: Boolean!
message: String!
category: Category
}
# Типы для корзины
type Cart {
id: ID!
items: [CartItem!]!
totalPrice: Float!
totalItems: Int!
createdAt: DateTime!
updatedAt: DateTime!
organization: Organization!
}
type CartItem {
id: ID!
product: Product!
quantity: Int!
totalPrice: Float!
isAvailable: Boolean!
availableQuantity: Int!
createdAt: DateTime!
updatedAt: DateTime!
}
type CartResponse {
success: Boolean!
message: String!
cart: Cart
}
# Типы для избранного
type FavoritesResponse {
success: Boolean!
message: String!
favorites: [Product!]
}
# Типы для сотрудников
type Employee {
id: ID!
firstName: String!
lastName: String!
middleName: String
fullName: String
name: String
birthDate: DateTime
avatar: String
passportPhoto: String
passportSeries: String
passportNumber: String
passportIssued: String
passportDate: DateTime
address: String
position: String!
department: String
hireDate: DateTime!
salary: Float
status: EmployeeStatus!
phone: String!
email: String
telegram: String
whatsapp: String
emergencyContact: String
emergencyPhone: String
scheduleRecords: [EmployeeSchedule!]!
organization: Organization!
createdAt: DateTime!
updatedAt: DateTime!
}
enum EmployeeStatus {
ACTIVE
VACATION
SICK
FIRED
}
type EmployeeSchedule {
id: ID!
date: DateTime!
status: ScheduleStatus!
hoursWorked: Float
overtimeHours: Float
notes: String
employee: Employee!
createdAt: DateTime!
updatedAt: DateTime!
}
enum ScheduleStatus {
WORK
WEEKEND
VACATION
SICK
ABSENT
}
input CreateEmployeeInput {
firstName: String!
lastName: String!
middleName: String
birthDate: DateTime
avatar: String
passportPhoto: String
passportSeries: String
passportNumber: String
passportIssued: String
passportDate: DateTime
address: String
position: String!
department: String
hireDate: DateTime!
salary: Float
phone: String!
email: String
telegram: String
whatsapp: String
emergencyContact: String
emergencyPhone: String
}
input UpdateEmployeeInput {
firstName: String
lastName: String
middleName: String
birthDate: DateTime
avatar: String
passportPhoto: String
passportSeries: String
passportNumber: String
passportIssued: String
passportDate: DateTime
address: String
position: String
department: String
hireDate: DateTime
salary: Float
status: EmployeeStatus
phone: String
email: String
telegram: String
whatsapp: String
emergencyContact: String
emergencyPhone: String
}
input UpdateScheduleInput {
employeeId: ID!
date: DateTime!
status: ScheduleStatus!
hoursWorked: Float
overtimeHours: Float
notes: String
}
type EmployeeResponse {
success: Boolean!
message: String!
employee: Employee
}
type EmployeesResponse {
success: Boolean!
message: String!
employees: [Employee!]!
}
# JSON скаляр
scalar JSON
# Админ типы
type Admin {
id: ID!
username: String!
email: String
isActive: Boolean!
lastLogin: String
createdAt: DateTime!
updatedAt: DateTime!
}
type AdminAuthResponse {
success: Boolean!
message: String!
token: String
admin: Admin
}
type UsersResponse {
users: [User!]!
total: Int!
hasMore: Boolean!
}
# Типы для поставок Wildberries
type WildberriesSupply {
id: ID!
deliveryDate: DateTime
status: WildberriesSupplyStatus!
totalAmount: Float!
totalItems: Int!
cards: [WildberriesSupplyCard!]!
organization: Organization!
createdAt: DateTime!
updatedAt: DateTime!
}
type WildberriesSupplyCard {
id: ID!
nmId: String!
vendorCode: String!
title: String!
brand: String
price: Float!
discountedPrice: Float
quantity: Int!
selectedQuantity: Int!
selectedMarket: String
selectedPlace: String
sellerName: String
sellerPhone: String
deliveryDate: DateTime
mediaFiles: [String!]!
selectedServices: [String!]!
createdAt: DateTime!
updatedAt: DateTime!
}
enum WildberriesSupplyStatus {
DRAFT
CREATED
IN_PROGRESS
DELIVERED
CANCELLED
}
input CreateWildberriesSupplyInput {
deliveryDate: DateTime
cards: [WildberriesSupplyCardInput!]!
}
input WildberriesSupplyCardInput {
nmId: String!
vendorCode: String!
title: String!
brand: String
price: Float!
discountedPrice: Float
quantity: Int!
selectedQuantity: Int!
selectedMarket: String
selectedPlace: String
sellerName: String
sellerPhone: String
deliveryDate: DateTime
mediaFiles: [String!]
selectedServices: [String!]
}
input UpdateWildberriesSupplyInput {
deliveryDate: DateTime
status: WildberriesSupplyStatus
cards: [WildberriesSupplyCardInput!]
}
type WildberriesSupplyResponse {
success: Boolean!
message: String!
supply: WildberriesSupply
}
# Wildberries статистика
type WildberriesStatistics {
date: String!
sales: Int!
orders: Int!
advertising: Float!
refusals: Int!
returns: Int!
revenue: Float!
buyoutPercentage: Float!
}
type WildberriesStatisticsResponse {
success: Boolean!
message: String
data: [WildberriesStatistics!]!
}
type DebugAdvertsResponse {
success: Boolean!
message: String
campaignsCount: Int!
campaigns: [DebugCampaign!]
}
type DebugCampaign {
id: Int!
name: String!
status: Int!
type: Int!
}
# Типы для поставщиков поставок
type SupplySupplier {
id: ID!
name: String!
contactName: String!
phone: String!
market: String
address: String
place: String
telegram: String
createdAt: DateTime!
}
input CreateSupplySupplierInput {
name: String!
contactName: String!
phone: String!
market: String
address: String
place: String
telegram: String
}
type SupplySupplierResponse {
success: Boolean!
message: String
supplier: SupplySupplier
}
# Типы для статистики кампаний
input WildberriesCampaignStatsInput {
campaigns: [CampaignStatsRequest!]!
}
input CampaignStatsRequest {
id: Int!
dates: [String!]
interval: CampaignStatsInterval
}
input CampaignStatsInterval {
begin: String!
end: String!
}
type WildberriesCampaignStatsResponse {
success: Boolean!
message: String
data: [WildberriesCampaignStats!]!
}
type WildberriesCampaignStats {
advertId: Int!
views: Int!
clicks: Int!
ctr: Float!
cpc: Float!
sum: Float!
atbs: Int!
orders: Int!
cr: Float!
shks: Int!
sum_price: Float!
interval: WildberriesCampaignInterval
days: [WildberriesCampaignDayStats!]!
boosterStats: [WildberriesBoosterStats!]!
}
type WildberriesCampaignInterval {
begin: String!
end: String!
}
type WildberriesCampaignDayStats {
date: String!
views: Int!
clicks: Int!
ctr: Float!
cpc: Float!
sum: Float!
atbs: Int!
orders: Int!
cr: Float!
shks: Int!
sum_price: Float!
apps: [WildberriesAppStats!]
}
type WildberriesAppStats {
views: Int!
clicks: Int!
ctr: Float!
cpc: Float!
sum: Float!
atbs: Int!
orders: Int!
cr: Float!
shks: Int!
sum_price: Float!
appType: Int!
nm: [WildberriesProductStats!]
}
type WildberriesProductStats {
views: Int!
clicks: Int!
ctr: Float!
cpc: Float!
sum: Float!
atbs: Int!
orders: Int!
cr: Float!
shks: Int!
sum_price: Float!
name: String!
nmId: Int!
}
type WildberriesBoosterStats {
date: String!
nm: Int!
avg_position: Float!
}
# Типы для списка кампаний
type WildberriesCampaignsListResponse {
success: Boolean!
message: String
data: WildberriesCampaignsData!
}
type WildberriesCampaignsData {
adverts: [WildberriesCampaignGroup!]!
all: Int!
}
type WildberriesCampaignGroup {
type: Int!
status: Int!
count: Int!
advert_list: [WildberriesCampaignItem!]!
}
type WildberriesCampaignItem {
advertId: Int!
changeTime: String!
}
# Типы для внешней рекламы
type ExternalAd {
id: ID!
name: String!
url: String!
cost: Float!
date: String!
nmId: String!
clicks: Int!
organizationId: String!
createdAt: String!
updatedAt: String!
}
input ExternalAdInput {
name: String!
url: String!
cost: Float!
date: String!
nmId: String!
}
type ExternalAdResponse {
success: Boolean!
message: String
externalAd: ExternalAd
}
type ExternalAdsResponse {
success: Boolean!
message: String
externalAds: [ExternalAd!]!
}
extend type Query {
getExternalAds(dateFrom: String!, dateTo: String!): ExternalAdsResponse!
}
extend type Mutation {
createExternalAd(input: ExternalAdInput!): ExternalAdResponse!
updateExternalAd(id: ID!, input: ExternalAdInput!): ExternalAdResponse!
deleteExternalAd(id: ID!): ExternalAdResponse!
updateExternalAdClicks(id: ID!, clicks: Int!): ExternalAdResponse!
}
# Типы для кеша склада WB
type WBWarehouseCache {
id: ID!
organizationId: String!
cacheDate: String!
data: String! # JSON строка с данными
totalProducts: Int!
totalStocks: Int!
totalReserved: Int!
createdAt: String!
updatedAt: String!
}
type WBWarehouseCacheResponse {
success: Boolean!
message: String
cache: WBWarehouseCache
fromCache: Boolean! # Указывает, получены ли данные из кеша
}
input WBWarehouseCacheInput {
data: String! # JSON строка с данными склада
totalProducts: Int!
totalStocks: Int!
totalReserved: Int!
}
extend type Query {
getWBWarehouseData: WBWarehouseCacheResponse!
}
extend type Mutation {
saveWBWarehouseCache(input: WBWarehouseCacheInput!): WBWarehouseCacheResponse!
}
# Типы для кеша статистики продаж селлера
type SellerStatsCache {
id: ID!
organizationId: String!
cacheDate: String!
period: String!
dateFrom: String
dateTo: String
productsData: String
productsTotalSales: Float
productsTotalOrders: Int
productsCount: Int
advertisingData: String
advertisingTotalCost: Float
advertisingTotalViews: Int
advertisingTotalClicks: Int
expiresAt: String!
createdAt: String!
updatedAt: String!
}
type SellerStatsCacheResponse {
success: Boolean!
message: String
cache: SellerStatsCache
fromCache: Boolean!
}
input SellerStatsCacheInput {
period: String!
dateFrom: String
dateTo: String
productsData: String
productsTotalSales: Float
productsTotalOrders: Int
productsCount: Int
advertisingData: String
advertisingTotalCost: Float
advertisingTotalViews: Int
advertisingTotalClicks: Int
expiresAt: String!
}
extend type Query {
getSellerStatsCache(period: String!, dateFrom: String, dateTo: String): SellerStatsCacheResponse!
}
extend type Mutation {
saveSellerStatsCache(input: SellerStatsCacheInput!): SellerStatsCacheResponse!
}
# Типы для заявок на возврат WB
type WbReturnClaim {
id: String!
claimType: Int!
status: Int!
statusEx: Int!
nmId: Int!
userComment: String!
wbComment: String
dt: String!
imtName: String!
orderDt: String!
dtUpdate: String!
photos: [String!]!
videoPaths: [String!]!
actions: [String!]!
price: Int!
currencyCode: String!
srid: String!
sellerOrganization: WbSellerOrganization!
}
type WbSellerOrganization {
id: String!
name: String!
inn: String!
}
type WbReturnClaimsResponse {
claims: [WbReturnClaim!]!
total: Int!
}
# Типы для статистики склада фулфилмента
type FulfillmentWarehouseStats {
products: WarehouseStatsItem!
goods: WarehouseStatsItem!
defects: WarehouseStatsItem!
pvzReturns: WarehouseStatsItem!
fulfillmentSupplies: WarehouseStatsItem!
sellerSupplies: WarehouseStatsItem!
}
type WarehouseStatsItem {
current: Int!
change: Int!
percentChange: Float!
}
# Типы для движений товаров (прибыло/убыло)
type SupplyMovements {
arrived: MovementStats!
departed: MovementStats!
}
type MovementStats {
products: Int!
goods: Int!
defects: Int!
pvzReturns: Int!
fulfillmentSupplies: Int!
sellerSupplies: Int!
}
extend type Query {
fulfillmentWarehouseStats: FulfillmentWarehouseStats!
supplyMovements(period: String): SupplyMovements!
}
# Типы для реферальной системы
type ReferralsResponse {
referrals: [Referral!]!
totalCount: Int!
totalPages: Int!
}
type Referral {
id: ID!
organization: Organization!
source: ReferralSource!
spheresEarned: Int!
registeredAt: DateTime!
status: ReferralStatus!
transactions: [ReferralTransaction!]!
}
type ReferralStats {
totalPartners: Int!
totalSpheres: Int!
monthlyPartners: Int!
monthlySpheres: Int!
referralsByType: [ReferralTypeStats!]!
referralsBySource: [ReferralSourceStats!]!
}
type ReferralTypeStats {
type: OrganizationType!
count: Int!
spheres: Int!
}
type ReferralSourceStats {
source: ReferralSource!
count: Int!
spheres: Int!
}
type ReferralTransactionsResponse {
transactions: [ReferralTransaction!]!
totalCount: Int!
}
type ReferralTransaction {
id: ID!
referrer: Organization!
referral: Organization!
spheres: Int!
type: ReferralTransactionType!
description: String
createdAt: DateTime!
}
enum ReferralSource {
REFERRAL_LINK
AUTO_BUSINESS
}
enum ReferralStatus {
ACTIVE
INACTIVE
BLOCKED
}
enum ReferralTransactionType {
REGISTRATION
AUTO_PARTNERSHIP
FIRST_ORDER
MONTHLY_BONUS
}
enum CounterpartyType {
MANUAL
REFERRAL
AUTO_BUSINESS
}
# ===============================================
# НОВАЯ СИСТЕМА ПОСТАВОК V2.0
# ===============================================
# Новый enum для статусов поставок v2
enum SupplyOrderStatusV2 {
PENDING # Ожидает одобрения поставщика
SUPPLIER_APPROVED # Одобрено поставщиком
LOGISTICS_CONFIRMED # Логистика подтверждена
SHIPPED # Отгружено поставщиком
IN_TRANSIT # В пути
DELIVERED # Доставлено и принято
CANCELLED # Отменено
}
# Типы для поставок расходников фулфилмента
type FulfillmentConsumableSupplyOrder {
id: ID!
status: SupplyOrderStatusV2!
fulfillmentCenterId: ID!
fulfillmentCenter: Organization!
requestedDeliveryDate: DateTime!
resalePricePerUnit: Float
minStockLevel: Int
notes: String
# Данные поставщика
supplierId: ID
supplier: Organization
supplierApprovedAt: DateTime
packagesCount: Int
estimatedVolume: Float
supplierContractId: String
supplierNotes: String
# Данные логистики
logisticsPartnerId: ID
logisticsPartner: Organization
estimatedDeliveryDate: DateTime
routeId: ID
logisticsCost: Float
logisticsNotes: String
# Данные отгрузки
shippedAt: DateTime
trackingNumber: String
# Данные приемки
receivedAt: DateTime
receivedById: ID
receivedBy: User
actualQuantity: Int
defectQuantity: Int
receiptNotes: String
items: [FulfillmentConsumableSupplyItem!]!
createdAt: DateTime!
updatedAt: DateTime!
}
type FulfillmentConsumableSupplyItem {
id: ID!
productId: ID!
product: Product!
requestedQuantity: Int!
approvedQuantity: Int
shippedQuantity: Int
receivedQuantity: Int
defectQuantity: Int
unitPrice: Float!
totalPrice: Float!
createdAt: DateTime!
updatedAt: DateTime!
}
# Input типы для создания поставок
input CreateFulfillmentConsumableSupplyInput {
supplierId: ID!
logisticsPartnerId: ID # Логистический партнер (опционально)
requestedDeliveryDate: DateTime!
items: [FulfillmentConsumableSupplyItemInput!]!
notes: String
}
input FulfillmentConsumableSupplyItemInput {
productId: ID!
requestedQuantity: Int!
}
# Input для приемки поставки
input ReceiveFulfillmentConsumableSupplyInput {
supplyOrderId: ID!
items: [ReceiveFulfillmentConsumableSupplyItemInput!]!
notes: String
}
input ReceiveFulfillmentConsumableSupplyItemInput {
productId: ID!
receivedQuantity: Int!
defectQuantity: Int
}
# Response типы
type CreateFulfillmentConsumableSupplyResult {
success: Boolean!
message: String!
supplyOrder: FulfillmentConsumableSupplyOrder
}
type SupplierConsumableSupplyResponse {
success: Boolean!
message: String!
order: FulfillmentConsumableSupplyOrder
}
# Расширяем Query и Mutation для новой системы
extend type Query {
# Новые запросы для системы поставок v2
myFulfillmentConsumableSupplies: [FulfillmentConsumableSupplyOrder!]!
mySupplierConsumableSupplies: [FulfillmentConsumableSupplyOrder!]!
myLogisticsConsumableSupplies: [FulfillmentConsumableSupplyOrder!]!
fulfillmentConsumableSupply(id: ID!): FulfillmentConsumableSupplyOrder
}
extend type Mutation {
# Новые мутации для системы поставок v2
createFulfillmentConsumableSupply(
input: CreateFulfillmentConsumableSupplyInput!
): CreateFulfillmentConsumableSupplyResult!
# Приемка поставки с автоматическим обновлением инвентаря
receiveFulfillmentConsumableSupply(
input: ReceiveFulfillmentConsumableSupplyInput!
): CreateFulfillmentConsumableSupplyResult!
# Мутации поставщика для V2 расходников фулфилмента
supplierApproveConsumableSupply(id: ID!): SupplierConsumableSupplyResponse!
supplierRejectConsumableSupply(id: ID!, reason: String): SupplierConsumableSupplyResponse!
supplierShipConsumableSupply(id: ID!): SupplierConsumableSupplyResponse!
# Мутации логистики для V2 расходников фулфилмента
logisticsConfirmConsumableSupply(id: ID!): SupplierConsumableSupplyResponse!
logisticsRejectConsumableSupply(id: ID!, reason: String): SupplierConsumableSupplyResponse!
# Мутация фулфилмента для приемки V2 расходников
fulfillmentReceiveConsumableSupply(
id: ID!
items: [ReceiveFulfillmentConsumableSupplyItemInput!]!
notes: String
): SupplierConsumableSupplyResponse!
}
# =============================================================================
# 📦 СИСТЕМА ПОСТАВОК РАСХОДНИКОВ СЕЛЛЕРА
# =============================================================================
# 5-статусная система для поставок селлера
enum SellerSupplyOrderStatus {
PENDING # Ожидает одобрения поставщика
APPROVED # Одобрено поставщиком
SHIPPED # Отгружено
DELIVERED # Доставлено
COMPLETED # Завершено
CANCELLED # Отменено
}
# Основной тип для поставки расходников селлера
type SellerConsumableSupplyOrder {
id: ID!
status: SellerSupplyOrderStatus!
# Данные селлера (создатель)
sellerId: ID!
seller: Organization!
fulfillmentCenterId: ID!
fulfillmentCenter: Organization!
requestedDeliveryDate: DateTime!
notes: String
# Данные поставщика
supplierId: ID
supplier: Organization
supplierApprovedAt: DateTime
packagesCount: Int
estimatedVolume: Float
supplierContractId: String
supplierNotes: String
# Данные логистики
logisticsPartnerId: ID
logisticsPartner: Organization
estimatedDeliveryDate: DateTime
routeId: ID
logisticsCost: Float
logisticsNotes: String
# Данные отгрузки
shippedAt: DateTime
trackingNumber: String
# Данные приемки
receivedAt: DateTime
receivedById: ID
receivedBy: User
actualQuantity: Int
defectQuantity: Int
receiptNotes: String
# Экономика (для будущего раздела экономики)
totalCostWithDelivery: Float
estimatedStorageCost: Float
items: [SellerConsumableSupplyItem!]!
createdAt: DateTime!
updatedAt: DateTime!
}
# Позиция в поставке селлера
type SellerConsumableSupplyItem {
id: ID!
productId: ID!
product: Product!
requestedQuantity: Int!
approvedQuantity: Int
shippedQuantity: Int
receivedQuantity: Int
defectQuantity: Int
unitPrice: Float!
totalPrice: Float!
createdAt: DateTime!
updatedAt: DateTime!
}
# Input типы для создания поставок селлера
input CreateSellerConsumableSupplyInput {
fulfillmentCenterId: ID! # куда доставлять (FULFILLMENT партнер)
supplierId: ID! # от кого заказывать (WHOLESALE партнер)
logisticsPartnerId: ID # кто везет (LOGIST партнер, опционально)
requestedDeliveryDate: DateTime! # когда нужно
items: [SellerConsumableSupplyItemInput!]!
notes: String
}
input SellerConsumableSupplyItemInput {
productId: ID! # какой расходник заказываем
requestedQuantity: Int! # сколько нужно
}
# Response типы для селлера
type CreateSellerConsumableSupplyResult {
success: Boolean!
message: String!
supplyOrder: SellerConsumableSupplyOrder
}
# Расширяем Query для селлерских поставок
extend type Query {
# Поставки селлера (мои заказы)
mySellerConsumableSupplies: [SellerConsumableSupplyOrder!]!
# Входящие заказы от селлеров (для фулфилмента)
incomingSellerSupplies: [SellerConsumableSupplyOrder!]!
# Поставки селлеров для поставщиков
mySellerSupplyRequests: [SellerConsumableSupplyOrder!]!
# Конкретная поставка селлера
sellerConsumableSupply(id: ID!): SellerConsumableSupplyOrder
}
# Расширяем Mutation для селлерских поставок
extend type Mutation {
# Создание поставки расходников селлера
createSellerConsumableSupply(
input: CreateSellerConsumableSupplyInput!
): CreateSellerConsumableSupplyResult!
# Обновление статуса поставки (для поставщиков и фулфилмента)
updateSellerSupplyStatus(
id: ID!
status: SellerSupplyOrderStatus!
notes: String
): SellerConsumableSupplyOrder!
# Отмена поставки селлером (только PENDING/APPROVED)
cancelSellerSupply(id: ID!): SellerConsumableSupplyOrder!
}
`