фикс создания фасовки

This commit is contained in:
2025-12-29 12:34:52 +03:00
parent 310a64e3ba
commit d6703e1a4b
8 changed files with 128 additions and 50 deletions

View File

@@ -2,11 +2,19 @@
import React, { useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { List, Typography, Tag, Spin, Empty, DatePicker, Flex } from "antd";
import {
List,
Typography,
Tag,
Spin,
Empty,
DatePicker,
Flex,
Button,
} from "antd";
import { useNavigate } from "react-router-dom";
import {
ArrowRightOutlined,
HistoryOutlined,
CheckCircleOutlined,
DeleteOutlined,
PlusOutlined,
@@ -14,53 +22,56 @@ import {
LoadingOutlined,
CloseCircleOutlined,
StopOutlined,
SyncOutlined,
CloudServerOutlined,
} from "@ant-design/icons";
import dayjs, { Dayjs } from "dayjs";
import { api } from "../services/api";
import type { UnifiedInvoice } from "../services/types";
const { Title, Text } = Typography;
const { RangePicker } = DatePicker;
export const DraftsList: React.FC = () => {
const navigate = useNavigate();
// Состояние фильтра дат: по умолчанию последние 7 дней
const [dateRange, setDateRange] = useState<[Dayjs, Dayjs]>([
dayjs().subtract(7, "day"),
dayjs(),
]);
const [startDate, setStartDate] = useState<Dayjs>(dayjs().subtract(7, "day"));
const [endDate, setEndDate] = useState<Dayjs>(dayjs());
const [syncLoading, setSyncLoading] = useState(false);
// Запрос данных с учетом дат (даты в ключе обеспечивают авто-перезапрос)
const {
data: invoices,
isLoading,
isError,
refetch,
} = useQuery({
queryKey: [
"drafts",
dateRange[0].format("YYYY-MM-DD"),
dateRange[1].format("YYYY-MM-DD"),
startDate.format("YYYY-MM-DD"),
endDate.format("YYYY-MM-DD"),
],
queryFn: () =>
api.getDrafts(
dateRange[0].format("YYYY-MM-DD"),
dateRange[1].format("YYYY-MM-DD")
startDate.format("YYYY-MM-DD"),
endDate.format("YYYY-MM-DD")
),
staleTime: 0,
refetchOnMount: true,
refetchOnWindowFocus: true,
});
const getStatusTag = (item: UnifiedInvoice) => {
if (item.type === "SYNCED") {
return (
<Tag icon={<HistoryOutlined />} color="success">
Синхронизировано
</Tag>
);
const handleSync = async () => {
setSyncLoading(true);
try {
await api.syncInvoices();
refetch();
} finally {
setSyncLoading(false);
}
};
const getStatusTag = (item: UnifiedInvoice) => {
switch (item.status) {
case "PROCESSING":
return (
@@ -95,19 +106,19 @@ export const DraftsList: React.FC = () => {
case "NEW":
return (
<Tag icon={<PlusOutlined />} color="blue">
Новый
Новая
</Tag>
);
case "PROCESSED":
return (
<Tag icon={<CheckCircleOutlined />} color="green">
Обработан
Проведена
</Tag>
);
case "DELETED":
return (
<Tag icon={<DeleteOutlined />} color="red">
Удален
Удалена
</Tag>
);
default:
@@ -133,9 +144,16 @@ export const DraftsList: React.FC = () => {
return (
<div style={{ padding: "0 4px 20px" }}>
<Title level={4} style={{ marginTop: 16, marginBottom: 16 }}>
Накладные
</Title>
<Flex align="center" gap={8} style={{ marginTop: 16, marginBottom: 16 }}>
<Title level={4} style={{ margin: 0 }}>
Накладные
</Title>
<Button
icon={<SyncOutlined />}
loading={syncLoading}
onClick={handleSync}
/>
</Flex>
{/* Фильтр дат */}
<div
@@ -152,13 +170,24 @@ export const DraftsList: React.FC = () => {
>
Период загрузки:
</Text>
<RangePicker
value={dateRange}
onChange={(dates) => dates && setDateRange([dates[0]!, dates[1]!])}
style={{ width: "100%" }}
allowClear={false}
format="DD.MM.YYYY"
/>
<Flex gap={8}>
<DatePicker
value={startDate}
onChange={(date) => date && setStartDate(date)}
style={{ flex: 1 }}
placeholder="Начало"
format="DD.MM.YYYY"
allowClear={false}
/>
<DatePicker
value={endDate}
onChange={(date) => date && setEndDate(date)}
style={{ flex: 1 }}
placeholder="Конец"
format="DD.MM.YYYY"
allowClear={false}
/>
</Flex>
</div>
{isLoading ? (
@@ -194,6 +223,9 @@ export const DraftsList: React.FC = () => {
<Text strong style={{ fontSize: 16 }}>
{item.document_number || "Без номера"}
</Text>
{item.type === "SYNCED" && (
<CloudServerOutlined style={{ color: "gray" }} />
)}
{item.is_app_created && (
<span title="Создано в RMSer">📱</span>
)}

View File

@@ -127,6 +127,7 @@ export const InvoiceDraftPage: React.FC = () => {
onSuccess: (data) => {
message.success(`Накладная ${data.document_number} создана!`);
navigate("/invoices");
queryClient.invalidateQueries({ queryKey: ["drafts"] });
},
onError: () => {
message.error("Ошибка при создании накладной");
@@ -499,7 +500,8 @@ export const InvoiceDraftPage: React.FC = () => {
{totalSum.toLocaleString("ru-RU", {
style: "currency",
currency: "RUB",
maximumFractionDigits: 0,
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
</span>
</div>

View File

@@ -78,17 +78,6 @@ export const InvoiceViewPage: React.FC = () => {
key: "quantity",
align: "right" as const,
},
{
title: "Цена",
dataIndex: "price",
key: "price",
align: "right" as const,
render: (price: number) =>
price.toLocaleString("ru-RU", {
style: "currency",
currency: "RUB",
}),
},
{
title: "Сумма",
dataIndex: "total",
@@ -187,10 +176,10 @@ export const InvoiceViewPage: React.FC = () => {
size="small"
summary={() => (
<Table.Summary.Row>
<Table.Summary.Cell index={0} colSpan={3}>
<Table.Summary.Cell index={0} colSpan={2}>
<Text strong>Итого:</Text>
</Table.Summary.Cell>
<Table.Summary.Cell index={3} align="right">
<Table.Summary.Cell index={2} align="right">
<Text strong>
{totalSum.toLocaleString("ru-RU", {
style: "currency",

View File

@@ -251,4 +251,8 @@ export const api = {
const { data } = await apiClient.get<InvoiceDetails>(`/invoices/${id}`);
return data;
},
syncInvoices: async (): Promise<void> => {
await apiClient.post('/invoices/sync');
},
};