Files
portal/app/tests/Unit/ClientSms/ConsentLetterBuilderTest.php
T
Дмитрий 3ad2ffb771 feat(смс-клиент): бланк письма-разрешения — Word на все 8 случаев + выбор правообладателя
Имя отправителя Лидерра регистрирует у МТС от лица клиента, поэтому письмо-разрешение
нужно всегда. Собрал генератор бланка так, чтобы он покрывал все случаи и всегда
отдавал целый документ — заполненный, где есть данные, и с прочерками, где их нет.

- ConsentLetterBuilder — единый источник текста письма на все 8 комбинаций
  «объект (юр.наименование/название ИП/товарный знак/домен) × правообладатель
  (юрлицо/ИП/физлицо)» строго по образцам МТС. Паспорт физлица не храним — прочерк.
- ConsentDocxWriter — рендер в РЕДАКТИРУЕМЫЙ Word (.docx) вместо PDF, чтобы клиент
  дописал недостающее; акцент про паспорт («должны совпадать с документом на право»).
- consentForm(): убрана жёсткая блокировка (бланк отдаётся всегда), добавлен выбор
  правообладателя owner_type/owner_name — домен/знак могут быть на физлице даже
  у клиента-юрлица/ИП, тогда письмо от этого физлица.
- Экран: подсказки «как назвать имя» под каждый вид, общее правило (до 11 знаков,
  латиницей), радио «на кого зарегистрирован домен/знак» + поле ФИО, кнопка бланка
  активна после ввода имени, ярлык «Скачать бланк разрешения (Word)».
- consent-form.blade.php удалён (заменён docx); phpoffice/phpword ^1.4 в composer.

Тесты: бэкенд ClientSms 116, фронт SMS-спеки 44 — зелёные; pint чисто.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 18:33:45 +03:00

177 lines
13 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
use App\Services\ClientSms\ConsentLetterBuilder;
/**
* Генератор письма-разрешения от правообладателя — все 8 комбинаций «объект ×
* правообладатель» строго по образцам МТС (support.mts.ru → «Письмо-разрешение
* от правообладателя»). Имя у оператора регистрирует Лидерра, правообладатель —
* клиент, поэтому получатель во всех письмах один (мы). Что знаем о клиенте —
* подставляем; чего не знаем — оставляем пропуски (цельный бланк). Паспортные
* данные физлица НЕ храним (152-ФЗ) — всегда пропуск.
*/
$RECIPIENT = 'ИП Кондратьев П. Д. (ИНН 245210851872)';
$TERM = 'до 31.12.2027';
/** Реквизиты юрлица/ИП по умолчанию (валидный ИНН). */
function reqFull(array $over = []): array
{
return array_merge(
['legal_name' => 'ООО «Ромашка»', 'contact_name' => 'Иван Иванов', 'inn' => '7707083893'],
$over,
);
}
function letter(): ConsentLetterBuilder
{
return new ConsentLetterBuilder;
}
// ─── Объект «Юридическое наименование» — только правообладатель-юрлицо ────────
it('1. юр.наименование × юрлицо', function () use ($RECIPIENT, $TERM) {
$l = letter()->build('legal', 'legal_entity', 'ROMASHKA', reqFull(), $RECIPIENT, $TERM);
expect($l['title_object'])->toBe('юридического наименования');
expect($l['is_individual'])->toBeFalse();
expect($l['signer'])->toBe('ООО «Ромашка»');
expect($l['body'])->toBe(
'ООО «Ромашка» (ИНН 7707083893) в лице генерального директора ________________________, '
.'действующего на основании Устава, настоящим письмом даёт своё согласие для '
.'ИП Кондратьев П. Д. (ИНН 245210851872) на использование юридического наименования организации '
.'в виде имени отправителя для проведения рекламных SMS-рассылок, направленных на продвижение '
.'ООО «Ромашка» на территории Российской Федерации. Право на использование предоставлено '
.'безвозмездно на срок до 31.12.2027.'
);
});
// ─── Объект «Название ИП» — только правообладатель-ИП ─────────────────────────
it('2. наименование ИП × ИП (префикс «ИП» добавляется)', function () use ($RECIPIENT, $TERM) {
$l = letter()->build('ip', 'sole_proprietor', 'IVANOV', reqFull(['legal_name' => 'Иванов И. И.']), $RECIPIENT, $TERM);
expect($l['title_object'])->toBe('наименования ИП');
expect($l['is_individual'])->toBeFalse();
expect($l['signer'])->toBe('ИП Иванов И. И.');
expect($l['body'])->toBe(
'Я, ИП Иванов И. И. (ИНН 7707083893), настоящим письмом даю своё согласие для '
.'ИП Кондратьев П. Д. (ИНН 245210851872) на использование наименования индивидуального предпринимателя '
.'в виде имени отправителя для проведения рекламных SMS-рассылок на территории Российской Федерации. '
.'Право на использование предоставлено безвозмездно на срок до 31.12.2027.'
);
});
// ─── Объект «Товарный знак» — юрлицо / ИП / физлицо ──────────────────────────
it('3. товарный знак × юрлицо', function () use ($RECIPIENT, $TERM) {
$l = letter()->build('trademark', 'legal_entity', 'BREND', reqFull(), $RECIPIENT, $TERM);
expect($l['title_object'])->toBe('товарного знака');
expect($l['body'])->toBe(
'ООО «Ромашка» (ИНН 7707083893) в лице генерального директора ________________________, '
.'действующего на основании Устава, настоящим письмом даёт своё согласие для '
.'ИП Кондратьев П. Д. (ИНН 245210851872) на использование товарного знака № ____________ '
.'в виде имени отправителя для проведения рекламных SMS-рассылок, направленных на продвижение '
.'ООО «Ромашка» на территории Российской Федерации. Право на использование предоставлено '
.'безвозмездно на срок до 31.12.2027.'
);
});
it('4. товарный знак × ИП', function () use ($RECIPIENT, $TERM) {
$l = letter()->build('trademark', 'sole_proprietor', 'BREND', reqFull(['legal_name' => 'ИП Иванов И. И.']), $RECIPIENT, $TERM);
expect($l['is_individual'])->toBeFalse();
expect($l['body'])->toBe(
'Я, ИП Иванов И. И. (ИНН 7707083893), настоящим письмом даю своё согласие для '
.'ИП Кондратьев П. Д. (ИНН 245210851872) на использование товарного знака № ____________ '
.'в виде имени отправителя для проведения рекламных SMS-рассылок на территории Российской Федерации. '
.'Право на использование предоставлено безвозмездно на срок до 31.12.2027.'
);
});
it('5. товарный знак × физлицо (паспорт — пропуск)', function () use ($RECIPIENT, $TERM) {
$l = letter()->build('trademark', 'individual', 'BREND',
['legal_name' => '', 'contact_name' => 'Пётр Петров', 'inn' => ''], $RECIPIENT, $TERM);
expect($l['is_individual'])->toBeTrue();
expect($l['signer'])->toBe('Пётр Петров');
expect($l['body'])->toBe(
'Я, Пётр Петров (паспортные или иные дополнительные данные о физлице, позволяющие сопоставить их '
.'со сведениями из подтверждающего документа: серия ____ № __________, выдан ______________________), '
.'правообладатель товарного знака № ____________, настоящим письмом даю своё согласие для '
.'ИП Кондратьев П. Д. (ИНН 245210851872) на использование товарного знака № ____________ '
.'в виде имени отправителя для проведения рекламных SMS-рассылок на территории Российской Федерации. '
.'Право на использование предоставлено безвозмездно на срок до 31.12.2027.'
);
});
// ─── Объект «Домен» — юрлицо / ИП / физлицо ──────────────────────────────────
it('6. домен × юрлицо', function () use ($RECIPIENT, $TERM) {
$l = letter()->build('website', 'legal_entity', 'shop.ru', reqFull(), $RECIPIENT, $TERM);
expect($l['title_object'])->toBe('доменного имени');
expect($l['body'])->toBe(
'ООО «Ромашка» (ИНН 7707083893) в лице генерального директора ________________________, '
.'действующего на основании Устава, настоящим письмом даёт своё согласие для '
.'ИП Кондратьев П. Д. (ИНН 245210851872) на использование доменного имени «shop.ru» '
.'в виде имени отправителя для проведения рекламных SMS-рассылок, направленных на продвижение '
.'ООО «Ромашка» на территории Российской Федерации. Право на использование предоставлено '
.'безвозмездно на срок до 31.12.2027.'
);
});
it('7. домен × ИП', function () use ($RECIPIENT, $TERM) {
$l = letter()->build('website', 'sole_proprietor', 'shop.ru', reqFull(['legal_name' => 'ИП Иванов И. И.']), $RECIPIENT, $TERM);
expect($l['body'])->toBe(
'Я, ИП Иванов И. И. (ИНН 7707083893), настоящим письмом даю своё согласие для '
.'ИП Кондратьев П. Д. (ИНН 245210851872) на использование доменного имени «shop.ru» '
.'в виде имени отправителя для проведения рекламных SMS-рассылок на территории Российской Федерации. '
.'Право на использование предоставлено безвозмездно на срок до 31.12.2027.'
);
});
it('8. домен × физлицо (владелец домена, паспорт — пропуск)', function () use ($RECIPIENT, $TERM) {
$l = letter()->build('website', 'individual', 'shop.ru',
['legal_name' => '', 'contact_name' => 'Пётр Петров', 'inn' => ''], $RECIPIENT, $TERM);
expect($l['is_individual'])->toBeTrue();
expect($l['body'])->toBe(
'Я, Пётр Петров (паспортные или иные дополнительные данные о физлице, позволяющие сопоставить их '
.'со сведениями из подтверждающего документа: серия ____ № __________, выдан ______________________), '
.'владелец домена «shop.ru», настоящим письмом даю своё согласие для '
.'ИП Кондратьев П. Д. (ИНН 245210851872) на использование доменного имени «shop.ru» '
.'в виде имени отправителя для проведения рекламных SMS-рассылок на территории Российской Федерации. '
.'Право на использование предоставлено безвозмездно на срок до 31.12.2027.'
);
});
// ─── Пропуски: данных нет → цельный бланк с прочерками ───────────────────────
it('юрлицо без названия и ИНН → прочерки в бланке', function () use ($RECIPIENT, $TERM) {
$l = letter()->build('legal', 'legal_entity', 'ROMASHKA',
['legal_name' => '', 'contact_name' => '', 'inn' => ''], $RECIPIENT, $TERM);
expect($l['body'])->toContain('«______________________» (ИНН ____________) в лице генерального директора');
expect($l['signer'])->toBe('«______________________»');
});
it('физлицо без ФИО → прочерк вместо ФИО', function () use ($RECIPIENT, $TERM) {
$l = letter()->build('website', 'individual', 'shop.ru',
['legal_name' => '', 'contact_name' => '', 'inn' => ''], $RECIPIENT, $TERM);
expect($l['body'])->toStartWith('Я, ________________________ (паспортные');
expect($l['signer'])->toBe('________________________');
});
it('домен/товарный знак с неизвестным типом лица → трактуется как физлицо (цельный бланк)', function () use ($RECIPIENT, $TERM) {
$l = letter()->build('website', null, 'shop.ru',
['legal_name' => '', 'contact_name' => '', 'inn' => ''], $RECIPIENT, $TERM);
expect($l['is_individual'])->toBeTrue();
expect($l['body'])->toContain('владелец домена «shop.ru»');
});