# Приёмка liderra.ru — ПУНКТ №10: Два проекта одного клиента = одно списание

> **Для исполнителя:** формат PR1 (одобрен 20.06). Каждый шаг = `🔧 Код-факт (file:line)` · `🎬 Действие` · `📋 ОТЧЁТ (было→ожидали→стало + 📸/📝)` · `❌ Если не так`. Техника «под капотом»; владельцу — человеческие карточки.

**Цель:** показать, что если у одного клиента **два (или больше) проекта** ловят **один и тот же источник**, то на одну заявку он получает её **один раз** и платит **один раз** — портал не задваивает доставку и списание внутри одного клиента.

**Что снимаем глазами:** **Сделки** клиента (одна сделка на заявку, не две) и **Баланс** (одно списание). Живые 📸.

**Источник сценария:** свод проверок №10 (M-DOUBLEPROJ); R3 «движок».

---

## 🔧 Код-факты (подтверждено чтением 20.06)

- **По одному проекту на клиента в отборе** — `SELECT DISTINCT ON (snap.tenant_id)` — [LeadRouter.php:137](../../../app/app/Services/LeadRouter.php#L137): даже если у клиента несколько подходящих проектов на источнике, в кандидаты попадает **один** (с наибольшим остатком лимита — `ORDER BY (daily_limit - delivered_today) DESC` — [:154-157](../../../app/app/Services/LeadRouter.php#L154-L157)).
- **Замок поставки на (заявка × клиент)** — вторая страховка: `supplier_lead_deliveries` через `insertOrIgnore`; повтор по тому же клиенту → `0` → без второго списания — [RouteSupplierLeadJob.php:404-418](../../../app/app/Jobs/RouteSupplierLeadJob.php#L404-L418).
- CAP=3 считает **клиентов**, не проекты (см. №1) — [LeadDistributor.php:22](../../../app/app/Services/LeadDistributor.php#L22).

---

## Шаг 10-0 — Предусловие: у клиента 2 проекта на одном источнике

**🔧 Код:** отбор кандидатов — [LeadRouter::queryCandidates :104-160](../../../app/app/Services/LeadRouter.php#L104-L160).
**🎬 Действие (лок):** у одного клиента создать **два** проекта, оба ловят один источник и подходят по региону/лимиту/балансу. (Сценарий R1: P1 + P8 у C1, или два проекта на один `test-okna.ru`.)

**📋 ОТЧЁТ:**
| Что | Было | Ожидалось | Стало (факт) | Чем подтверждаем |
|---|---|---|---|---|
| Проекты клиента на источнике | — | 2 активных проекта, оба подходят | _(слот прогона)_ | 📸 Проекты клиента (2 шт); 📝 SQL |

**❌ Если не так:** проектов не два / разные источники → подготовить заново.

---

## Шаг 10-1 — Влить одну заявку → клиент получил её ОДИН раз

**🔧 Код:** DISTINCT ON — [LeadRouter :137](../../../app/app/Services/LeadRouter.php#L137); замок — [RouteSupplierLeadJob :404-418](../../../app/app/Jobs/RouteSupplierLeadJob.php#L404-L418).
**🎬 Действие (лок):** влить **1** заявку на этот источник; зафиксировать баланс «до» и число сделок.

**📋 ОТЧЁТ:**
| Что | Было | Ожидалось | Стало (факт) | Чем подтверждаем |
|---|---|---|---|---|
| Сделок у клиента на эту заявку | — | **1** (не 2, хотя проекта два) | _(слот)_ | 📸 Сделки клиента (одна новая) |
| Списание | X ₽ | **одно** списание (− цена один раз) | _(слот)_ | 📸 Биллинг (1 списание) |
| Баланс | X | X − цена (не дважды) | _(слот)_ | 📸 Баланс до/после |

**💡 Что внутри:** клиент может завести несколько проектов на один и тот же источник (например по-разному назвать или для разных менеджеров). Но заявка с этого источника — одна, и человек за ней — один. Поэтому портал отдаёт её клиенту **один раз** и списывает **один раз**, даже если у него на этот источник смотрят два проекта. Платят за заявку, а не за число своих проектов.

**❌ Если не так:** две сделки на одну заявку у одного клиента / двойное списание → денежный дефект (СТОП).

---

## Шаг 10-2 — Заявка по-прежнему доходит ДРУГИМ клиентам (CAP считает клиентов)

**🔧 Код:** CAP по клиентам — [LeadDistributor :22-43](../../../app/app/Services/LeadDistributor.php#L22-L43).
**🎬 Действие (лок):** на том же источнике есть ещё клиенты — проверить, что они тоже получают (до 3 клиентов суммарно).

**📋 ОТЧЁТ:**
| Что | Было | Ожидалось | Стало (факт) | Чем подтверждаем |
|---|---|---|---|---|
| Получатели заявки | — | до 3 **разных клиентов** (два проекта одного = один клиент) | _(слот)_ | 📸 Сделки нескольких клиентов |

**❌ Если не так:** два проекта одного клиента «съели» два из трёх слотов CAP → дефект (CAP должен считать клиентов).

---

## Verification №10 (выход из пункта)
- [ ] 📸 У клиента с 2 проектами на источник — ровно 1 сделка на заявку.
- [ ] 📸 Одно списание (баланс упал на одну цену, не на две).
- [ ] 📸 Заявка дошла до других клиентов; CAP считает клиентов, не проекты.
- [ ] 📝 SQL: одна строка `supplier_lead_deliveries` на (заявка×клиент); одно `lead_charges`.

## 📸 vs 📝 в этом пункте
- **📸 Скриншот:** Проекты клиента (2), Сделки (1 на заявку), Биллинг (1 списание).
- **📝 Текст:** DISTINCT ON, замок поставки, число списаний — частично текстом.

## Грабли
- Оба проекта должны реально подходить (регион/лимит/баланс), иначе тест вырождается в «один подходящий».
- Связка с №1 (CAP) и №5 (идемпотентность) — здесь проверяем именно дубль **внутри одного клиента**.
