Создан единый источник истины rules-complete.md v9.1 с полной интеграцией всех правил системы. Консолидированы правила создания предметов по ролям, уточнен статус брака (НЕ РЕАЛИЗОВАНО), обновлен механизм учета ПЛАН/ФАКТ с заменой брака на потери при пересчете. Добавлен экономический учет расходников фулфилмента для селлера через рецептуру. Удалены дублирующие файлы правил (CLAUDE.md, development-checklist.md, work-protocols.md, violation-prevention-protocol.md, self-validation.md, description.md). Интегрированы UI структуры создания поставок и концепция многоуровневых таблиц.
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -4,6 +4,8 @@ import React, { useState } from "react";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { GET_SUPPLY_ORDERS } from "@/graphql/queries";
|
||||
import {
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
@ -75,119 +77,14 @@ interface Supply {
|
||||
status: "planned" | "in-transit" | "delivered" | "completed";
|
||||
}
|
||||
|
||||
// Моковые данные для товаров
|
||||
const mockGoodsSupplies: Supply[] = [
|
||||
{
|
||||
id: "1",
|
||||
number: 1,
|
||||
deliveryDate: "2024-01-15",
|
||||
createdDate: "2024-01-10",
|
||||
status: "delivered",
|
||||
plannedTotal: 180,
|
||||
actualTotal: 173,
|
||||
defectTotal: 2,
|
||||
totalProductPrice: 3750000,
|
||||
totalFulfillmentPrice: 43000,
|
||||
totalLogisticsPrice: 27000,
|
||||
grandTotal: 3820000,
|
||||
routes: [
|
||||
{
|
||||
id: "r1",
|
||||
from: "Садовод",
|
||||
fromAddress: "Москва, 14-й км МКАД",
|
||||
to: "SFERAV Logistics",
|
||||
toAddress: "Москва, ул. Складская, 15",
|
||||
totalProductPrice: 3600000,
|
||||
fulfillmentServicePrice: 25000,
|
||||
logisticsPrice: 15000,
|
||||
totalAmount: 3640000,
|
||||
wholesalers: [
|
||||
{
|
||||
id: "w1",
|
||||
name: 'ООО "ТехноСнаб"',
|
||||
inn: "7701234567",
|
||||
contact: "+7 (495) 123-45-67",
|
||||
address: "Москва, ул. Торговая, 1",
|
||||
totalAmount: 3600000,
|
||||
products: [
|
||||
{
|
||||
id: "p1",
|
||||
name: "Смартфон iPhone 15",
|
||||
sku: "APL-IP15-128",
|
||||
category: "Электроника",
|
||||
plannedQty: 50,
|
||||
actualQty: 48,
|
||||
defectQty: 2,
|
||||
productPrice: 75000,
|
||||
parameters: [
|
||||
{ id: "param1", name: "Цвет", value: "Черный" },
|
||||
{ id: "param2", name: "Память", value: "128", unit: "ГБ" },
|
||||
{ id: "param3", name: "Гарантия", value: "12", unit: "мес" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
number: 2,
|
||||
deliveryDate: "2024-01-20",
|
||||
createdDate: "2024-01-12",
|
||||
status: "in-transit",
|
||||
plannedTotal: 30,
|
||||
actualTotal: 30,
|
||||
defectTotal: 0,
|
||||
totalProductPrice: 750000,
|
||||
totalFulfillmentPrice: 18000,
|
||||
totalLogisticsPrice: 12000,
|
||||
grandTotal: 780000,
|
||||
routes: [
|
||||
{
|
||||
id: "r3",
|
||||
from: "Садовод",
|
||||
fromAddress: "Москва, 14-й км МКАД",
|
||||
to: "WB Подольск",
|
||||
toAddress: "Подольск, ул. Складская, 25",
|
||||
totalProductPrice: 750000,
|
||||
fulfillmentServicePrice: 18000,
|
||||
logisticsPrice: 12000,
|
||||
totalAmount: 780000,
|
||||
wholesalers: [
|
||||
{
|
||||
id: "w3",
|
||||
name: 'ООО "АудиоТех"',
|
||||
inn: "7702345678",
|
||||
contact: "+7 (495) 555-12-34",
|
||||
address: "Москва, ул. Звуковая, 8",
|
||||
totalAmount: 750000,
|
||||
products: [
|
||||
{
|
||||
id: "p3",
|
||||
name: "Наушники AirPods Pro",
|
||||
sku: "APL-AP-PRO2",
|
||||
category: "Аудио",
|
||||
plannedQty: 30,
|
||||
actualQty: 30,
|
||||
defectQty: 0,
|
||||
productPrice: 25000,
|
||||
parameters: [
|
||||
{ id: "param6", name: "Тип", value: "Беспроводные" },
|
||||
{ id: "param7", name: "Шумоподавление", value: "Активное" },
|
||||
{ id: "param8", name: "Время работы", value: "6", unit: "ч" },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
// Данные поставок товаров из GraphQL
|
||||
|
||||
export function SuppliesGoodsTab() {
|
||||
// Загружаем реальные данные поставок товаров
|
||||
const { data: supplyOrdersData, loading, error } = useQuery(GET_SUPPLY_ORDERS, {
|
||||
errorPolicy: 'all'
|
||||
});
|
||||
|
||||
const [expandedSupplies, setExpandedSupplies] = useState<Set<string>>(
|
||||
new Set()
|
||||
);
|
||||
@ -199,6 +96,25 @@ export function SuppliesGoodsTab() {
|
||||
new Set()
|
||||
);
|
||||
|
||||
// Преобразуем данные из GraphQL в нужный формат
|
||||
const goodsSupplies: Supply[] = (supplyOrdersData?.supplyOrders || [])
|
||||
.filter((order: any) => order.status === 'CONFIRMED' || order.status === 'DELIVERED')
|
||||
.map((order: any, index: number) => ({
|
||||
id: order.id,
|
||||
number: index + 1,
|
||||
deliveryDate: order.deliveryDate || new Date().toISOString().split('T')[0],
|
||||
createdDate: order.createdAt?.split('T')[0] || new Date().toISOString().split('T')[0],
|
||||
status: order.status === 'DELIVERED' ? 'delivered' : 'in-transit',
|
||||
plannedTotal: order.totalItems || 0,
|
||||
actualTotal: order.totalItems || 0,
|
||||
defectTotal: 0,
|
||||
totalProductPrice: order.totalAmount || 0,
|
||||
totalFulfillmentPrice: 0,
|
||||
totalLogisticsPrice: 0,
|
||||
grandTotal: order.totalAmount || 0,
|
||||
routes: []
|
||||
}));
|
||||
|
||||
const toggleSupplyExpansion = (supplyId: string) => {
|
||||
const newExpanded = new Set(expandedSupplies);
|
||||
if (newExpanded.has(supplyId)) {
|
||||
@ -321,7 +237,7 @@ export function SuppliesGoodsTab() {
|
||||
<div>
|
||||
<p className="text-white/60 text-xs">Поставок товаров</p>
|
||||
<p className="text-xl font-bold text-white">
|
||||
{mockGoodsSupplies.length}
|
||||
{loading ? '...' : goodsSupplies.length}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -335,8 +251,8 @@ export function SuppliesGoodsTab() {
|
||||
<div>
|
||||
<p className="text-white/60 text-xs">Сумма товаров</p>
|
||||
<p className="text-xl font-bold text-white">
|
||||
{formatCurrency(
|
||||
mockGoodsSupplies.reduce(
|
||||
{loading ? '...' : formatCurrency(
|
||||
goodsSupplies.reduce(
|
||||
(sum, supply) => sum + supply.grandTotal,
|
||||
0
|
||||
)
|
||||
@ -354,8 +270,8 @@ export function SuppliesGoodsTab() {
|
||||
<div>
|
||||
<p className="text-white/60 text-xs">В пути</p>
|
||||
<p className="text-xl font-bold text-white">
|
||||
{
|
||||
mockGoodsSupplies.filter(
|
||||
{loading ? '...' :
|
||||
goodsSupplies.filter(
|
||||
(supply) => supply.status === "in-transit"
|
||||
).length
|
||||
}
|
||||
@ -372,8 +288,8 @@ export function SuppliesGoodsTab() {
|
||||
<div>
|
||||
<p className="text-white/60 text-xs">С браком</p>
|
||||
<p className="text-xl font-bold text-white">
|
||||
{
|
||||
mockGoodsSupplies.filter((supply) => supply.defectTotal > 0)
|
||||
{loading ? '...' :
|
||||
goodsSupplies.filter((supply) => supply.defectTotal > 0)
|
||||
.length
|
||||
}
|
||||
</p>
|
||||
@ -416,7 +332,25 @@ export function SuppliesGoodsTab() {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{mockGoodsSupplies.map((supply) => {
|
||||
{loading && (
|
||||
<tr>
|
||||
<td colSpan={11} className="p-8 text-center">
|
||||
<div className="text-white/60">Загрузка данных...</div>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
{!loading && goodsSupplies.length === 0 && (
|
||||
<tr>
|
||||
<td colSpan={11} className="p-8 text-center">
|
||||
<div className="text-white/60">
|
||||
<Package className="h-12 w-12 mx-auto mb-4 text-white/20" />
|
||||
<div className="text-lg font-semibold text-white mb-2">Поставки товаров не найдены</div>
|
||||
<div>Создайте первую поставку товаров через карточки или поставщиков</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
{!loading && goodsSupplies.map((supply) => {
|
||||
const isSupplyExpanded = expandedSupplies.has(supply.id);
|
||||
|
||||
return (
|
||||
|
Reference in New Issue
Block a user