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]) => (