[598][@ant] docs(marketplace): «Обработка возвратов на ПВЗ» — 1 e2e скриншот

Story 7.2-7.4: /market-pvz/returns. Председатель КУ загружает ленту
заявлений своего ПВЗ. Три секции жизненного цикла: «Ждут удалённого
рассмотрения» (teal), «Ожидают очного визита» (orange), «Архив»
(grey). Compensating forward через транзит 91: пара o.mkt.return +
o.mkt.return2 атомарно возвращает средства и имущество.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
ant
2026-05-21 00:16:07 +00:00
parent 5fd715de42
commit edeb5f9b7c
3 changed files with 110 additions and 33 deletions
@@ -0,0 +1,28 @@
// Сценарий: operator-стол гарантийных возвратов (Story 7.2-7.4).
// Председатель КУ рассматривает поступившие заявления удалённо,
// приглашает на очный осмотр, принимает или отказывает.
import { cleanViteOverlays, env, loginAsChairman } from '../../../lib/harness.mjs';
export const meta = {
title: 'Стол ПВЗ — гарантийные возвраты',
docPath: 'new/marketplace/branch-chairman/return-approve.md',
assetsDir: 'assets/new/marketplace/branch-chairman/return-approve',
role: 'chairman',
};
export default async ({ page, shot }) => {
await loginAsChairman(page);
await page.evaluate(() => localStorage.setItem('harness:noBranchOverlay', '1'));
await page.goto(`${env.BASE_URL}/${env.COOPNAME}/market-pvz/returns`, { waitUntil: 'domcontentloaded', timeout: 45000 });
await page.waitForLoadState('networkidle', { timeout: 20000 }).catch(() => {});
await page.waitForTimeout(3500);
await cleanViteOverlays(page);
await shot(
page,
'01-operator-returns-empty',
`«Гарантийные возвраты» председателя КУ. URL: \`${page.url()}\`.`,
);
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

@@ -1,55 +1,104 @@
---
title: Обработка гарантийных возвратов (operator-стол ПВЗ)
generated_by: docs-harness
scenario: marketplace/operator/returns
tags:
- Пайщик
- Председатель
---
# Обработка возвратных заявлений
# Гарантийный возврат — рассмотрение заявлений
Когда пайщик подаёт [заявление о возврате][return], оно попадает в очередь председателю кооперативного участка, который выдавал Заказ. Председатель обрабатывает заявление одним из трёх способов: принять удалённо, пригласить на очный осмотр или отказать удалённо.
Раздел `/<coopname>/market-pvz/returns` (Story 7.2-7.4) — рабочее место
**председателя кооперативного участка** по гарантийным возвратам, которые
подали пайщики на orderer-столе ([«Гарантийный возврат имущества»][orderer-returns]).
Здесь председатель рассматривает заявления удалённо, при необходимости
приглашает на очный осмотр, принимает или отказывает.
## Что показывает лента
Доступ — `roles: ['chairman']` в workspace `market-pvz`.
Каждое заявление — это карточка с:
![Гарантийный возврат — рассмотрение заявлений: поле «ID кооперативного участка» + кнопка «Загрузить заявления», три секции «Ждут удалённого рассмотрения», «Ожидают очного визита», «Архив», все пустые](/assets/new/marketplace/branch-chairman/return-approve/01-operator-returns-empty.png)
- Заказчиком (ФИО, контакт).
- Заказом и Предложением (с переходом в детальную карточку).
- **Категорией дефекта** (брак / повреждение / несоответствие).
- **Описанием** пайщика (свободный текст).
- **Фотографиями** дефекта.
- Суммой возврата (часть или полная фактическая сумма Заказа).
- Датой подачи.
## Загрузка ленты
## Удалённое решение
Над секциями — пара элементов:
Если председатель доверяет описанию и фото:
- **Поле «ID кооперативного участка»** — председатель вписывает
идентификатор КУ, чьи заявления хочет рассмотреть.
- **Кнопка «Загрузить заявления»** (primary, зелёная) — стартует запрос
и заполняет три секции ниже.
- **Принять возврат удалённо** — пайщик не приходит на ПВЗ, председатель оформляет возврат заочно. Возврат имущества в этом случае физический отсутствует (если, например, скоропортящийся товар не имеет смысла везти обратно), но в реестре имущество переходит на склад участка как «полученное для последующего списания». Сумма возвращается на программный кошелёк пайщика.
- **Отказать удалённо** — председатель не согласен с заявлением (например, на фото не видно дефекта, или категория дефекта не подпадает под гарантию). Заявление отклоняется, средства не возвращаются, имущество остаётся у пайщика.
Это тот же паттерн, что и у [«Открытия выдачи»][issuance] — председатель
кооператива может быть оператором сразу нескольких КУ, лента не угадывает
по умолчанию, а ждёт явного выбора участка.
В обоих случаях председатель заполняет **комментарий**, который видит пайщик в уведомлении.
## Три секции — три стадии флоу
## Очный осмотр
Страница разбита на три блока, повторяющих жизненный цикл заявления:
Если по описанию и фото нельзя точно определить, либо речь о дорогом имуществе:
### 1. Ждут удалённого рассмотрения
- **Пригласить на очный осмотр** — пайщику отправляется push «Приходите на ПВЗ для осмотра имущества». Заявление переходит в статус **AWAITING_ONSITE_INSPECTION**.
- Пайщик договаривается о времени с оператором и приходит на ПВЗ.
- Председатель встречает пайщика, осматривает имущество, при необходимости фотографирует.
- На стойке заполняет **результат осмотра** (текстовое поле, до 2000 знаков), прилагает фото осмотра.
> Заголовок секции — цвета **teal**, рядом счётчик `(0)`.
После осмотра — два варианта:
Сюда попадают **новые заявления** сразу после подачи пайщиком (Story 7.1).
На этой стадии председатель КУ изучает фото, описание дефекта,
`defect_category` и `actual_quantity`, и принимает решение:
- **Принять возврат на месте** — пайщик передаёт имущество, председатель ставит подпись акта возврата. Имущество возвращается на склад, средства восстанавливаются на программном кошельке пайщика, всё атомарно через compensating-forward (обратной транзакции нет — на блокчейне используется парная операция, аналогичная исходной выдаче, но с обратными движениями).
- **Отказать на месте** — председатель не согласен после осмотра. Имущество остаётся у пайщика, движений по средствам нет.
- **Принять удалённо** — composite-транзакция `accretrn` выполняет
compensating forward `o.mkt.return` + `o.mkt.return2` через транзит 91:
атомарно восстанавливает средства заказчику и возвращает имущество
на склад участка. Заявление уходит в **Архив**.
- **Отказать удалённо** — указывает причину; заявление уходит в
**Архив** со статусом «отказано».
- **Запросить очный осмотр** — заявление переходит в секцию **«Ожидают
очного визита»**.
## Что в подписном документе
В пустом состоянии — **«Нет заявлений, ожидающих удалённого
рассмотрения.»**
При приёме возврата (хоть удалённо, хоть на месте) формируется **акт возврата имущества**:
### 2. Ожидают очного визита
- Реквизиты пайщика, Заказа, имущества, фактической суммы возврата.
- Результат осмотра (только при очном).
- Подписи: председатель участка + при очном — заказчик.
> Заголовок секции — цвета **оранжевый**, рядом счётчик `(0)`.
После закрытия акта Заказ переходит в статус **RETURNED**.
Заявления, по которым председатель запросил очный осмотр имущества.
Пайщик должен прийти на ПВЗ; при визите председатель **принимает или
отказывает уже очно** (та же composite-транзакция, но с подписанным
актом осмотра).
[return]: ../orderer/return-claim.md
В пустом состоянии — **«Нет заявлений, по которым ожидается очный
визит.»**
### 3. Архив
> Заголовок секции — нейтрально-серый, счётчик `(0)`.
Закрытые заявления: принятые (имущество возвращено, деньги — обратно
пайщику), отказанные, отозванные. В пустом состоянии — **«Архив пуст.»**
## Откуда заявления берутся
Заявление приходит сюда после того, как пайщик на orderer-столе подал
форму [«Гарантийный возврат имущества»][orderer-returns] и подписал
**Заявление 1104** своей ЭП. Backend marketplace:
1. Создаёт `ReturnClaim` в БД со статусом «ждёт удалённого рассмотрения».
2. Привязывает его к КУ, на котором выдавался изначальный заказ
(вычисляется по `Order.branch_id`).
3. Уведомляет председателя КУ через push (если у него есть подписка
на канал заявлений по своему ПВЗ).
## Бизнес-смысл compensating forward
«Возврат» в marketplace не делается прямой обратной операцией к выдаче.
Он реализован **compensating forward** через транзит 91:
- `o.mkt.return` — списание у заказчика (возвращает имущество в кооператив).
- `o.mkt.return2` — зачисление пайщику средств (через транзит 91).
Это пара взаимных действий, выполняемая **атомарно**: если одно не
прошло — откатывается всё; если оба прошли — баланс кооператива
снова консистентен. Никакое «честное revert» исходной выдачи не делается,
потому что выдача уже зафиксирована подписями `signiss1/signiss2` и
юридически не отзывается — только компенсируется.
[orderer-returns]: ../orderer/return-claim.md
[issuance]: ./issuance-open.md