Merge branch 'main' of https://gittea.biveki.ru/Sfera/sfera
This commit is contained in:
@ -99,6 +99,7 @@ model Organization {
|
|||||||
logistics Logistics[]
|
logistics Logistics[]
|
||||||
supplyOrders SupplyOrder[]
|
supplyOrders SupplyOrder[]
|
||||||
partnerSupplyOrders SupplyOrder[] @relation("SupplyOrderPartner")
|
partnerSupplyOrders SupplyOrder[] @relation("SupplyOrderPartner")
|
||||||
|
fulfillmentSupplyOrders SupplyOrder[] @relation("SupplyOrderFulfillmentCenter")
|
||||||
wildberriesSupplies WildberriesSupply[]
|
wildberriesSupplies WildberriesSupply[]
|
||||||
|
|
||||||
@@map("organizations")
|
@@map("organizations")
|
||||||
@ -446,18 +447,20 @@ model Logistics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model SupplyOrder {
|
model SupplyOrder {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
partnerId String
|
partnerId String
|
||||||
deliveryDate DateTime
|
deliveryDate DateTime
|
||||||
status SupplyOrderStatus @default(PENDING)
|
status SupplyOrderStatus @default(PENDING)
|
||||||
totalAmount Decimal @db.Decimal(12, 2)
|
totalAmount Decimal @db.Decimal(12, 2)
|
||||||
totalItems Int
|
totalItems Int
|
||||||
createdAt DateTime @default(now())
|
fulfillmentCenterId String?
|
||||||
updatedAt DateTime @updatedAt
|
createdAt DateTime @default(now())
|
||||||
organizationId String
|
updatedAt DateTime @updatedAt
|
||||||
items SupplyOrderItem[]
|
organizationId String
|
||||||
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
items SupplyOrderItem[]
|
||||||
partner Organization @relation("SupplyOrderPartner", fields: [partnerId], references: [id])
|
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
|
||||||
|
partner Organization @relation("SupplyOrderPartner", fields: [partnerId], references: [id])
|
||||||
|
fulfillmentCenter Organization? @relation("SupplyOrderFulfillmentCenter", fields: [fulfillmentCenterId], references: [id])
|
||||||
|
|
||||||
@@map("supply_orders")
|
@@map("supply_orders")
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,410 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { Card } from "@/components/ui/card";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
|
import { StatsCard } from "../../supplies/ui/stats-card";
|
||||||
|
import { StatsGrid } from "../../supplies/ui/stats-grid";
|
||||||
|
import { useQuery } from "@apollo/client";
|
||||||
|
import { GET_SUPPLY_ORDERS } from "@/graphql/queries";
|
||||||
|
import { useAuth } from "@/hooks/useAuth";
|
||||||
|
import {
|
||||||
|
Calendar,
|
||||||
|
Building2,
|
||||||
|
TrendingUp,
|
||||||
|
DollarSign,
|
||||||
|
Wrench,
|
||||||
|
Package2,
|
||||||
|
ChevronDown,
|
||||||
|
ChevronRight,
|
||||||
|
User,
|
||||||
|
} from "lucide-react";
|
||||||
|
|
||||||
|
interface SupplyOrderItem {
|
||||||
|
id: string;
|
||||||
|
quantity: number;
|
||||||
|
price: number;
|
||||||
|
totalPrice: number;
|
||||||
|
product: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
article: string;
|
||||||
|
description?: string;
|
||||||
|
category?: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SupplyOrder {
|
||||||
|
id: string;
|
||||||
|
deliveryDate: string;
|
||||||
|
status: string;
|
||||||
|
totalAmount: number;
|
||||||
|
totalItems: number;
|
||||||
|
fulfillmentCenterId?: string;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
partner: {
|
||||||
|
id: string;
|
||||||
|
name?: string;
|
||||||
|
fullName?: string;
|
||||||
|
inn: string;
|
||||||
|
address?: string;
|
||||||
|
phones?: string[];
|
||||||
|
emails?: string[];
|
||||||
|
};
|
||||||
|
organization: {
|
||||||
|
id: string;
|
||||||
|
name?: string;
|
||||||
|
fullName?: string;
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
fulfillmentCenter?: {
|
||||||
|
id: string;
|
||||||
|
name?: string;
|
||||||
|
fullName?: string;
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
items: SupplyOrderItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function FulfillmentConsumablesOrdersTab() {
|
||||||
|
const [expandedOrders, setExpandedOrders] = useState<Set<string>>(new Set());
|
||||||
|
const { user } = useAuth();
|
||||||
|
|
||||||
|
const { data, loading, error } = useQuery(GET_SUPPLY_ORDERS);
|
||||||
|
|
||||||
|
// Получаем ID текущей организации (фулфилмент-центра)
|
||||||
|
const currentOrganizationId = user?.organization?.id;
|
||||||
|
|
||||||
|
// Фильтруем заказы где текущая организация является получателем
|
||||||
|
const incomingSupplyOrders: SupplyOrder[] = (data?.supplyOrders || []).filter(
|
||||||
|
(order: SupplyOrder) => {
|
||||||
|
// Показываем заказы где текущий фулфилмент-центр указан как получатель
|
||||||
|
return order.fulfillmentCenterId === currentOrganizationId;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const toggleOrderExpansion = (orderId: string) => {
|
||||||
|
const newExpanded = new Set(expandedOrders);
|
||||||
|
if (newExpanded.has(orderId)) {
|
||||||
|
newExpanded.delete(orderId);
|
||||||
|
} else {
|
||||||
|
newExpanded.add(orderId);
|
||||||
|
}
|
||||||
|
setExpandedOrders(newExpanded);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStatusBadge = (status: string) => {
|
||||||
|
const statusMap: Record<string, { label: string; color: string }> = {
|
||||||
|
CREATED: {
|
||||||
|
label: "Новый заказ",
|
||||||
|
color: "bg-blue-500/20 text-blue-300 border-blue-500/30",
|
||||||
|
},
|
||||||
|
CONFIRMED: {
|
||||||
|
label: "Подтвержден",
|
||||||
|
color: "bg-green-500/20 text-green-300 border-green-500/30",
|
||||||
|
},
|
||||||
|
IN_PROGRESS: {
|
||||||
|
label: "Обрабатывается",
|
||||||
|
color: "bg-yellow-500/20 text-yellow-300 border-yellow-500/30",
|
||||||
|
},
|
||||||
|
DELIVERED: {
|
||||||
|
label: "Доставлен",
|
||||||
|
color: "bg-purple-500/20 text-purple-300 border-purple-500/30",
|
||||||
|
},
|
||||||
|
CANCELLED: {
|
||||||
|
label: "Отменен",
|
||||||
|
color: "bg-red-500/20 text-red-300 border-red-500/30",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const { label, color } = statusMap[status] || {
|
||||||
|
label: status,
|
||||||
|
color: "bg-gray-500/20 text-gray-300 border-gray-500/30",
|
||||||
|
};
|
||||||
|
|
||||||
|
return <Badge className={`${color} border`}>{label}</Badge>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatCurrency = (amount: number) => {
|
||||||
|
return new Intl.NumberFormat("ru-RU", {
|
||||||
|
style: "currency",
|
||||||
|
currency: "RUB",
|
||||||
|
minimumFractionDigits: 0,
|
||||||
|
}).format(amount);
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatDate = (dateString: string) => {
|
||||||
|
return new Date(dateString).toLocaleDateString("ru-RU", {
|
||||||
|
day: "2-digit",
|
||||||
|
month: "2-digit",
|
||||||
|
year: "numeric",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const formatDateTime = (dateString: string) => {
|
||||||
|
return new Date(dateString).toLocaleString("ru-RU", {
|
||||||
|
day: "2-digit",
|
||||||
|
month: "2-digit",
|
||||||
|
year: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Статистика для фулфилмент-центра
|
||||||
|
const totalOrders = incomingSupplyOrders.length;
|
||||||
|
const totalAmount = incomingSupplyOrders.reduce((sum, order) => sum + order.totalAmount, 0);
|
||||||
|
const totalItems = incomingSupplyOrders.reduce((sum, order) => sum + order.totalItems, 0);
|
||||||
|
const newOrders = incomingSupplyOrders.filter(order => order.status === "CREATED").length;
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-center h-64">
|
||||||
|
<div className="animate-spin rounded-full h-8 w-8 border-2 border-white border-t-transparent"></div>
|
||||||
|
<span className="ml-3 text-white/60">Загрузка заказов расходников...</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-center h-64">
|
||||||
|
<div className="text-center">
|
||||||
|
<Wrench className="h-12 w-12 text-red-400 mx-auto mb-4" />
|
||||||
|
<p className="text-red-400 font-medium">Ошибка загрузки заказов</p>
|
||||||
|
<p className="text-white/60 text-sm mt-2">{error.message}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
{/* Статистика входящих заказов расходников */}
|
||||||
|
<StatsGrid>
|
||||||
|
<StatsCard
|
||||||
|
title="Входящие заказы"
|
||||||
|
value={totalOrders}
|
||||||
|
icon={Package2}
|
||||||
|
iconColor="text-orange-400"
|
||||||
|
iconBg="bg-orange-500/20"
|
||||||
|
subtitle="Заказы от селлеров"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<StatsCard
|
||||||
|
title="Общая сумма"
|
||||||
|
value={formatCurrency(totalAmount)}
|
||||||
|
icon={TrendingUp}
|
||||||
|
iconColor="text-green-400"
|
||||||
|
iconBg="bg-green-500/20"
|
||||||
|
subtitle="Стоимость заказов"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<StatsCard
|
||||||
|
title="Всего единиц"
|
||||||
|
value={totalItems}
|
||||||
|
icon={Wrench}
|
||||||
|
iconColor="text-blue-400"
|
||||||
|
iconBg="bg-blue-500/20"
|
||||||
|
subtitle="Количество расходников"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<StatsCard
|
||||||
|
title="Новые заказы"
|
||||||
|
value={newOrders}
|
||||||
|
icon={Calendar}
|
||||||
|
iconColor="text-purple-400"
|
||||||
|
iconBg="bg-purple-500/20"
|
||||||
|
subtitle="Требуют обработки"
|
||||||
|
/>
|
||||||
|
</StatsGrid>
|
||||||
|
|
||||||
|
{/* Список входящих заказов расходников */}
|
||||||
|
{incomingSupplyOrders.length === 0 ? (
|
||||||
|
<Card className="bg-white/10 backdrop-blur border-white/20 p-8">
|
||||||
|
<div className="text-center">
|
||||||
|
<Wrench className="h-16 w-16 text-white/20 mx-auto mb-4" />
|
||||||
|
<h3 className="text-lg font-semibold text-white mb-2">
|
||||||
|
Пока нет заказов расходников
|
||||||
|
</h3>
|
||||||
|
<p className="text-white/60">
|
||||||
|
Здесь будут отображаться заказы расходников от селлеров
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
) : (
|
||||||
|
<Card className="bg-white/10 backdrop-blur border-white/20 overflow-hidden">
|
||||||
|
<div className="overflow-x-auto">
|
||||||
|
<table className="w-full">
|
||||||
|
<thead>
|
||||||
|
<tr className="border-b border-white/20">
|
||||||
|
<th className="text-left p-4 text-white font-semibold">ID</th>
|
||||||
|
<th className="text-left p-4 text-white font-semibold">
|
||||||
|
Селлер
|
||||||
|
</th>
|
||||||
|
<th className="text-left p-4 text-white font-semibold">
|
||||||
|
Поставщик
|
||||||
|
</th>
|
||||||
|
<th className="text-left p-4 text-white font-semibold">
|
||||||
|
Дата поставки
|
||||||
|
</th>
|
||||||
|
<th className="text-left p-4 text-white font-semibold">
|
||||||
|
Дата заказа
|
||||||
|
</th>
|
||||||
|
<th className="text-left p-4 text-white font-semibold">
|
||||||
|
Количество
|
||||||
|
</th>
|
||||||
|
<th className="text-left p-4 text-white font-semibold">
|
||||||
|
Сумма
|
||||||
|
</th>
|
||||||
|
<th className="text-left p-4 text-white font-semibold">
|
||||||
|
Статус
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{incomingSupplyOrders.map((order) => {
|
||||||
|
const isOrderExpanded = expandedOrders.has(order.id);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment key={order.id}>
|
||||||
|
{/* Основная строка заказа */}
|
||||||
|
<tr
|
||||||
|
className="border-b border-white/10 hover:bg-white/5 transition-colors cursor-pointer"
|
||||||
|
onClick={() => toggleOrderExpansion(order.id)}
|
||||||
|
>
|
||||||
|
<td className="p-4">
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
{isOrderExpanded ? (
|
||||||
|
<ChevronDown className="h-4 w-4 text-white/60" />
|
||||||
|
) : (
|
||||||
|
<ChevronRight className="h-4 w-4 text-white/60" />
|
||||||
|
)}
|
||||||
|
<span className="text-white font-medium">
|
||||||
|
{order.id.slice(-8)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className="p-4">
|
||||||
|
<div className="space-y-1">
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<User className="h-4 w-4 text-white/40" />
|
||||||
|
<span className="text-white font-medium">
|
||||||
|
{order.organization.name || order.organization.fullName || "Селлер"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-white/60 text-sm">
|
||||||
|
Тип: {order.organization.type}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className="p-4">
|
||||||
|
<div className="space-y-1">
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<Building2 className="h-4 w-4 text-white/40" />
|
||||||
|
<span className="text-white font-medium">
|
||||||
|
{order.partner.name || order.partner.fullName || "Поставщик"}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p className="text-white/60 text-sm">
|
||||||
|
ИНН: {order.partner.inn}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className="p-4">
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<Calendar className="h-4 w-4 text-white/40" />
|
||||||
|
<span className="text-white font-semibold">
|
||||||
|
{formatDate(order.deliveryDate)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className="p-4">
|
||||||
|
<span className="text-white/80">
|
||||||
|
{formatDateTime(order.createdAt)}
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td className="p-4">
|
||||||
|
<span className="text-white font-semibold">
|
||||||
|
{order.totalItems} шт
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td className="p-4">
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<DollarSign className="h-4 w-4 text-white/40" />
|
||||||
|
<span className="text-green-400 font-bold">
|
||||||
|
{formatCurrency(order.totalAmount)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td className="p-4">{getStatusBadge(order.status)}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{/* Развернутая информация о заказе */}
|
||||||
|
{isOrderExpanded && (
|
||||||
|
<tr>
|
||||||
|
<td colSpan={8} className="p-0">
|
||||||
|
<div className="bg-white/5 border-t border-white/10">
|
||||||
|
<div className="p-6">
|
||||||
|
<h4 className="text-white font-semibold mb-4">
|
||||||
|
Состав заказа от селлера:
|
||||||
|
</h4>
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||||
|
{order.items.map((item) => (
|
||||||
|
<Card
|
||||||
|
key={item.id}
|
||||||
|
className="bg-white/10 backdrop-blur border-white/20 p-4"
|
||||||
|
>
|
||||||
|
<div className="space-y-3">
|
||||||
|
<div>
|
||||||
|
<h5 className="text-white font-medium mb-1">
|
||||||
|
{item.product.name}
|
||||||
|
</h5>
|
||||||
|
<p className="text-white/60 text-sm">
|
||||||
|
Артикул: {item.product.article}
|
||||||
|
</p>
|
||||||
|
{item.product.category && (
|
||||||
|
<Badge className="bg-purple-500/20 text-purple-300 border-purple-500/30 text-xs mt-2">
|
||||||
|
{item.product.category.name}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="text-sm">
|
||||||
|
<p className="text-white/60">
|
||||||
|
Количество: {item.quantity} шт
|
||||||
|
</p>
|
||||||
|
<p className="text-white/60">
|
||||||
|
Цена: {formatCurrency(item.price)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="text-right">
|
||||||
|
<p className="text-green-400 font-semibold">
|
||||||
|
{formatCurrency(item.totalPrice)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -7,7 +7,7 @@ import { Package, Wrench, RotateCcw, Building2 } from "lucide-react";
|
|||||||
// Импорты компонентов подкатегорий
|
// Импорты компонентов подкатегорий
|
||||||
import { FulfillmentGoodsTab } from "./fulfillment-goods-tab";
|
import { FulfillmentGoodsTab } from "./fulfillment-goods-tab";
|
||||||
import { PvzReturnsTab } from "./pvz-returns-tab";
|
import { PvzReturnsTab } from "./pvz-returns-tab";
|
||||||
import { SuppliesConsumablesTab } from "../../supplies/consumables-supplies/consumables-supplies-tab";
|
import { FulfillmentConsumablesOrdersTab } from "./fulfillment-consumables-orders-tab";
|
||||||
|
|
||||||
// Новые компоненты для детального просмотра (копия из supplies модуля)
|
// Новые компоненты для детального просмотра (копия из supplies модуля)
|
||||||
import { FulfillmentDetailedSuppliesTab } from "./fulfillment-detailed-supplies-tab";
|
import { FulfillmentDetailedSuppliesTab } from "./fulfillment-detailed-supplies-tab";
|
||||||
@ -68,7 +68,7 @@ export function FulfillmentSuppliesTab() {
|
|||||||
|
|
||||||
<TabsContent value="consumables" className="flex-1 overflow-hidden">
|
<TabsContent value="consumables" className="flex-1 overflow-hidden">
|
||||||
<div className="h-full p-4 overflow-y-auto">
|
<div className="h-full p-4 overflow-y-auto">
|
||||||
<SuppliesConsumablesTab />
|
<FulfillmentConsumablesOrdersTab />
|
||||||
</div>
|
</div>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
|
@ -313,7 +313,7 @@ export function FulfillmentGoodsTab() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="h-full flex flex-col space-y-6">
|
||||||
{/* Статистика товаров ФФ */}
|
{/* Статистика товаров ФФ */}
|
||||||
<StatsGrid>
|
<StatsGrid>
|
||||||
<StatsCard
|
<StatsCard
|
||||||
@ -369,8 +369,8 @@ export function FulfillmentGoodsTab() {
|
|||||||
</StatsGrid>
|
</StatsGrid>
|
||||||
|
|
||||||
{/* Таблица поставок товаров ФФ */}
|
{/* Таблица поставок товаров ФФ */}
|
||||||
<Card className="bg-white/10 backdrop-blur border-white/20 overflow-hidden">
|
<Card className="bg-white/10 backdrop-blur border-white/20 overflow-hidden flex-1 flex flex-col">
|
||||||
<div className="overflow-x-auto">
|
<div className="overflow-auto flex-1">
|
||||||
<table className="w-full">
|
<table className="w-full">
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="border-b border-white/20">
|
<tr className="border-b border-white/20">
|
||||||
|
@ -10,11 +10,11 @@ export function FulfillmentSuppliesTab() {
|
|||||||
const [activeSubTab, setActiveSubTab] = useState("goods");
|
const [activeSubTab, setActiveSubTab] = useState("goods");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-full">
|
<div className="h-full overflow-hidden">
|
||||||
<Tabs
|
<Tabs
|
||||||
value={activeSubTab}
|
value={activeSubTab}
|
||||||
onValueChange={setActiveSubTab}
|
onValueChange={setActiveSubTab}
|
||||||
className="w-full h-full flex flex-col"
|
className="w-full h-full flex flex-col overflow-hidden"
|
||||||
>
|
>
|
||||||
{/* Подвкладки для ФФ */}
|
{/* Подвкладки для ФФ */}
|
||||||
<TabsList className="grid grid-cols-3 bg-white/5 backdrop-blur border-white/10 mb-4 w-fit">
|
<TabsList className="grid grid-cols-3 bg-white/5 backdrop-blur border-white/10 mb-4 w-fit">
|
||||||
@ -38,15 +38,15 @@ export function FulfillmentSuppliesTab() {
|
|||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
|
|
||||||
<TabsContent value="goods" className="mt-0 flex-1">
|
<TabsContent value="goods" className="mt-0 flex-1 overflow-hidden">
|
||||||
<FulfillmentGoodsTab />
|
<FulfillmentGoodsTab />
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="supplies" className="mt-0 flex-1">
|
<TabsContent value="supplies" className="mt-0 flex-1 overflow-hidden">
|
||||||
<RealSupplyOrdersTab />
|
<RealSupplyOrdersTab />
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="returns" className="mt-0 flex-1">
|
<TabsContent value="returns" className="mt-0 flex-1 overflow-hidden">
|
||||||
<PvzReturnsTab />
|
<PvzReturnsTab />
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
@ -318,7 +318,7 @@ export function PvzReturnsTab() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="h-full flex flex-col space-y-6">
|
||||||
{/* Статистика возвратов с ПВЗ */}
|
{/* Статистика возвратов с ПВЗ */}
|
||||||
<StatsGrid>
|
<StatsGrid>
|
||||||
<StatsCard
|
<StatsCard
|
||||||
@ -369,8 +369,8 @@ export function PvzReturnsTab() {
|
|||||||
</StatsGrid>
|
</StatsGrid>
|
||||||
|
|
||||||
{/* Таблица возвратов с ПВЗ */}
|
{/* Таблица возвратов с ПВЗ */}
|
||||||
<Card className="bg-white/10 backdrop-blur border-white/20 overflow-hidden">
|
<Card className="bg-white/10 backdrop-blur border-white/20 overflow-hidden flex-1 flex flex-col">
|
||||||
<div className="overflow-x-auto">
|
<div className="overflow-auto flex-1">
|
||||||
<table className="w-full">
|
<table className="w-full">
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="border-b border-white/20">
|
<tr className="border-b border-white/20">
|
||||||
|
@ -165,7 +165,7 @@ export function RealSupplyOrdersTab() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="h-full flex flex-col space-y-6">
|
||||||
{/* Статистика заказов расходников */}
|
{/* Статистика заказов расходников */}
|
||||||
<StatsGrid>
|
<StatsGrid>
|
||||||
<StatsCard
|
<StatsCard
|
||||||
@ -219,8 +219,8 @@ export function RealSupplyOrdersTab() {
|
|||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
) : (
|
) : (
|
||||||
<Card className="bg-white/10 backdrop-blur border-white/20 overflow-hidden">
|
<Card className="bg-white/10 backdrop-blur border-white/20 overflow-hidden flex-1 flex flex-col">
|
||||||
<div className="overflow-x-auto">
|
<div className="overflow-auto flex-1">
|
||||||
<table className="w-full">
|
<table className="w-full">
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="border-b border-white/20">
|
<tr className="border-b border-white/20">
|
||||||
|
@ -82,11 +82,11 @@ export function SuppliesDashboard() {
|
|||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TabsContent value="fulfillment" className="mt-0 flex-1">
|
<TabsContent value="fulfillment" className="mt-0 flex-1 overflow-hidden">
|
||||||
<FulfillmentSuppliesTab />
|
<FulfillmentSuppliesTab />
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
|
||||||
<TabsContent value="marketplace" className="mt-0 flex-1">
|
<TabsContent value="marketplace" className="mt-0 flex-1 overflow-hidden">
|
||||||
<MarketplaceSuppliesTab />
|
<MarketplaceSuppliesTab />
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
@ -763,6 +763,7 @@ export const GET_SUPPLY_ORDERS = gql`
|
|||||||
status
|
status
|
||||||
totalAmount
|
totalAmount
|
||||||
totalItems
|
totalItems
|
||||||
|
fulfillmentCenterId
|
||||||
createdAt
|
createdAt
|
||||||
updatedAt
|
updatedAt
|
||||||
partner {
|
partner {
|
||||||
@ -780,6 +781,12 @@ export const GET_SUPPLY_ORDERS = gql`
|
|||||||
fullName
|
fullName
|
||||||
type
|
type
|
||||||
}
|
}
|
||||||
|
fulfillmentCenter {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
fullName
|
||||||
|
type
|
||||||
|
}
|
||||||
items {
|
items {
|
||||||
id
|
id
|
||||||
quantity
|
quantity
|
||||||
|
@ -684,12 +684,13 @@ export const resolvers = {
|
|||||||
throw new GraphQLError("У пользователя нет организации");
|
throw new GraphQLError("У пользователя нет организации");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Возвращаем заказы где текущая организация является заказчиком или поставщиком
|
// Возвращаем заказы где текущая организация является заказчиком, поставщиком или получателем
|
||||||
return await prisma.supplyOrder.findMany({
|
return await prisma.supplyOrder.findMany({
|
||||||
where: {
|
where: {
|
||||||
OR: [
|
OR: [
|
||||||
{ organizationId: currentUser.organization.id }, // Заказы созданные организацией
|
{ organizationId: currentUser.organization.id }, // Заказы созданные организацией
|
||||||
{ partnerId: currentUser.organization.id }, // Заказы где организация - поставщик
|
{ partnerId: currentUser.organization.id }, // Заказы где организация - поставщик
|
||||||
|
{ fulfillmentCenterId: currentUser.organization.id }, // Заказы где организация - получатель (фулфилмент)
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
@ -703,6 +704,11 @@ export const resolvers = {
|
|||||||
users: true,
|
users: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
fulfillmentCenter: {
|
||||||
|
include: {
|
||||||
|
users: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
items: {
|
items: {
|
||||||
include: {
|
include: {
|
||||||
product: {
|
product: {
|
||||||
@ -3213,33 +3219,39 @@ export const resolvers = {
|
|||||||
totalAmount: new Prisma.Decimal(totalAmount),
|
totalAmount: new Prisma.Decimal(totalAmount),
|
||||||
totalItems: totalItems,
|
totalItems: totalItems,
|
||||||
organizationId: currentUser.organization.id,
|
organizationId: currentUser.organization.id,
|
||||||
|
fulfillmentCenterId: fulfillmentCenterId,
|
||||||
status: initialStatus as any,
|
status: initialStatus as any,
|
||||||
items: {
|
items: {
|
||||||
create: orderItems,
|
create: orderItems,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
partner: {
|
partner: {
|
||||||
include: {
|
include: {
|
||||||
users: true,
|
users: true,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
organization: {
|
},
|
||||||
include: {
|
organization: {
|
||||||
users: true,
|
include: {
|
||||||
},
|
users: true,
|
||||||
},
|
},
|
||||||
items: {
|
},
|
||||||
include: {
|
fulfillmentCenter: {
|
||||||
product: {
|
include: {
|
||||||
include: {
|
users: true,
|
||||||
category: true,
|
},
|
||||||
organization: true,
|
},
|
||||||
},
|
items: {
|
||||||
|
include: {
|
||||||
|
product: {
|
||||||
|
include: {
|
||||||
|
category: true,
|
||||||
|
organization: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Создаем расходники на основе заказанных товаров
|
// Создаем расходники на основе заказанных товаров
|
||||||
|
@ -519,6 +519,8 @@ export const typeDefs = gql`
|
|||||||
status: SupplyOrderStatus!
|
status: SupplyOrderStatus!
|
||||||
totalAmount: Float!
|
totalAmount: Float!
|
||||||
totalItems: Int!
|
totalItems: Int!
|
||||||
|
fulfillmentCenterId: ID
|
||||||
|
fulfillmentCenter: Organization
|
||||||
items: [SupplyOrderItem!]!
|
items: [SupplyOrderItem!]!
|
||||||
createdAt: DateTime!
|
createdAt: DateTime!
|
||||||
updatedAt: DateTime!
|
updatedAt: DateTime!
|
||||||
|
Reference in New Issue
Block a user