From 3bf26d3650ef0cef91db66ebd205c43a47351dee Mon Sep 17 00:00:00 2001
From: vladtechno
Date: Tue, 18 Aug 2026 17:42:59 +1000
Subject: [PATCH] =?UTF-8?q?fix(pwa):=20=D0=B2=20=D1=88=D1=82=D1=80=D0=B0?=
=?UTF-8?q?=D1=84=D0=B0=D1=85=20=D1=82=D0=BE=D0=BB=D1=8C=D0=BA=D0=BE=20?=
=?UTF-8?q?=D1=84=D0=B0=D0=BA=D1=82=20=D0=B8=20=D1=81=D1=83=D0=BC=D0=BC?=
=?UTF-8?q?=D0=B0,=20=D0=B1=D0=B5=D0=B7=20=D0=BA=D1=83=D1=85=D0=BD=D0=B8?=
=?UTF-8?q?=20=D1=80=D0=B0=D1=81=D1=87=D1=91=D1=82=D0=BE=D0=B2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
С карточки убраны строки про номинал постановления, скидку и «в ГИБДД
постановление закрыто», из списка — абзац о том, кто и как платит ГИБДД.
Остаётся то, ради чего экран делался: фотография нарушения, статья, место,
скорость, начисленная сумма и погашен ли долг.
Co-Authored-By: Claude Opus 5
---
driver-pwa/frontend/src/api/driver.ts | 13 +++-------
.../frontend/src/pages/FineDetailPage.tsx | 25 +++----------------
.../frontend/src/pages/FinesPage.test.tsx | 20 ++++++++++-----
driver-pwa/frontend/src/pages/FinesPage.tsx | 5 ----
4 files changed, 22 insertions(+), 41 deletions(-)
diff --git a/driver-pwa/frontend/src/api/driver.ts b/driver-pwa/frontend/src/api/driver.ts
index b08a079..9d347a0 100644
--- a/driver-pwa/frontend/src/api/driver.ts
+++ b/driver-pwa/frontend/src/api/driver.ts
@@ -147,17 +147,12 @@ const FineBriefSchema = z.object({
article: z.string(),
address: z.string().default(""),
car_number: z.string().default(""),
- // Сумма, начисленная ВОДИТЕЛЮ (парк платит ГИБДД со скидкой и выставляет то,
- // что заплатил). fine_amount — номинал постановления, он бывает другим.
+ // Сумма, начисленная ВОДИТЕЛЮ. Номинала постановления, скидки и расчётов парка
+ // с ГИБДД в приложении нет намеренно — водителю нужен факт штрафа и сумма.
amount: z.number(),
- billed: z.boolean().default(false),
- fine_amount: z.number().default(0),
- discount_amount: z.number().default(0),
- discount_until: z.string().nullable().default(null),
- // Погашен ли штраф ВОДИТЕЛЕМ перед парком. Не путать с closed_with_gibdd:
- // постановление парк гасит авансом, долг водителя от этого не исчезает.
+ // Погашен ли штраф водителем перед парком. Постановление парк гасит авансом,
+ // и на этот признак его расчёты не влияют.
settled: z.enum(["owed", "paid", "not_charged", "cancelled", "unknown"]),
- closed_with_gibdd: z.boolean().default(false),
cancelled: z.boolean().default(false),
has_photo: z.boolean().default(false),
});
diff --git a/driver-pwa/frontend/src/pages/FineDetailPage.tsx b/driver-pwa/frontend/src/pages/FineDetailPage.tsx
index 3e4b686..c4c2c76 100644
--- a/driver-pwa/frontend/src/pages/FineDetailPage.tsx
+++ b/driver-pwa/frontend/src/pages/FineDetailPage.tsx
@@ -19,6 +19,10 @@ function Row({ k, v }: { k: string; v: string }) {
* Карточка штрафа. Главное здесь — фотография с камеры: по ней водитель узнаёт
* свою машину и свою поездку либо понимает, что штраф не его. Поэтому она стоит
* первой, до реквизитов, и открывается в полный размер по нажатию.
+ *
+ * Что парк заплатил ГИБДД, со скидкой ли и какой номинал у постановления — здесь
+ * не показывается: водителю нужен факт штрафа и сумма к возврату, а разбор
+ * расчётов парка уводит разговор от долга к внутренней кухне.
*/
export function FineDetailPage() {
const { fineId = "" } = useParams();
@@ -39,10 +43,6 @@ export function FineDetailPage() {
);
}
- const discountLive =
- f.discount_amount > 0 && !!f.discount_until && !f.closed_with_gibdd &&
- new Date(f.discount_until) >= new Date(new Date().toDateString());
-
return (
@@ -78,23 +78,6 @@ export function FineDetailPage() {
{formatMoney(f.amount)}
{fineStatusText(f)}
- {f.billed && f.fine_amount > 0 && f.fine_amount !== f.amount && (
- // Номинал постановления и начисление расходятся почти всегда: парк
- // платит со скидкой. Не показать этого — значит получить вопрос «почему
- // с меня 618, если в постановлении 750».
-
- Постановление — {formatMoney(f.fine_amount)}, парк оплатил его
- {f.fine_amount > f.amount ? " со скидкой" : ""} и выставил вам фактическую сумму
-
- )}
- {f.closed_with_gibdd && (
-
В ГИБДД постановление закрыто
- )}
- {discountLive && !f.billed && (
-
- До {formatDate(f.discount_until)} — {formatMoney(f.discount_amount)} со скидкой
-
- )}
{f.speed != null && f.speed_limit != null && (
diff --git a/driver-pwa/frontend/src/pages/FinesPage.test.tsx b/driver-pwa/frontend/src/pages/FinesPage.test.tsx
index 4e1b523..e965ae5 100644
--- a/driver-pwa/frontend/src/pages/FinesPage.test.tsx
+++ b/driver-pwa/frontend/src/pages/FinesPage.test.tsx
@@ -9,9 +9,8 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const FINE = {
id: 12, number: "18810525260813035846", date: "2026-08-12",
article: "12.09.2 - Превышение скорости", address: "Владивосток, Некрасовская, 90",
- car_number: "А947УТ125", amount: 618.75, billed: true, fine_amount: 750,
- discount_amount: 375, discount_until: "2026-09-01",
- settled: "owed" as const, closed_with_gibdd: true, cancelled: false, has_photo: true,
+ car_number: "А947УТ125", amount: 618.75,
+ settled: "owed" as const, cancelled: false, has_photo: true,
};
vi.mock("@/api/driver", () => ({
@@ -89,15 +88,24 @@ describe("карточка штрафа", () => {
expect(img.closest("a")).toHaveAttribute("target", "_blank");
});
- it("объясняет, почему начислено меньше номинала постановления", async () => {
+ it("показывает начисленную сумму, скорость и постановление", async () => {
wrap("/fines/12");
expect(await screen.findByText("618,75 ₽")).toBeInTheDocument();
- expect(screen.getByText(/Постановление — 750 ₽/)).toBeInTheDocument();
- expect(screen.getByText(/В ГИБДД постановление закрыто/)).toBeInTheDocument();
expect(screen.getByText(/63 км\/ч при разрешённых 40/)).toBeInTheDocument();
expect(screen.getByText("18810525260813035846")).toBeInTheDocument();
});
+ it("расчёты парка с ГИБДД водителю не показываются", async () => {
+ // Решение владельца: без номинала, скидки и «парк уже оплатил». В начисление
+ // заложена комиссия парка, и любая из этих строк рядом требует объяснений.
+ wrap("/fines/12");
+ await screen.findByText("618,75 ₽");
+ expect(screen.queryByText(/750/)).not.toBeInTheDocument();
+ expect(screen.queryByText(/скидк/i)).not.toBeInTheDocument();
+ expect(screen.queryByText(/ГИБДД/)).not.toBeInTheDocument();
+ expect(screen.queryByText(/парк/i)).not.toBeInTheDocument();
+ });
+
it("неоплаченный штраф ведёт к оплате штрафов", async () => {
wrap("/fines/12");
await userEvent.click(await screen.findByRole("button", { name: /Оплатить штрафы/ }));
diff --git a/driver-pwa/frontend/src/pages/FinesPage.tsx b/driver-pwa/frontend/src/pages/FinesPage.tsx
index 3198ab0..1cb4164 100644
--- a/driver-pwa/frontend/src/pages/FinesPage.tsx
+++ b/driver-pwa/frontend/src/pages/FinesPage.tsx
@@ -41,11 +41,6 @@ export function FinesPage() {
: " "}
-
- Постановление в ГИБДД оплачивает парк — как правило, сразу и со скидкой.
- Вы возвращаете парку начисленную сумму: она и складывается в долг по штрафам.
-
-
{([["open", "Не погашены"], ["all", "Все"]] as const).map(([key, label]) => (