docs(booking): document service booking mode and close task 00

docs/api/appointment.md gains the service-reschedule endpoint, the service-mode
section under PATCH, exclude_appointment_uuid and clinic_uuid on
appointment-service-slots, and the my/appointments additions. All JSON bodies are
real output captured from the running endpoints, not hand-written.

New docs/architecture/booking-modes.md holds the endpoint/mode matrix, the
duration contract with a worked example (35 + 10 buffer means a 45-minute step,
so 11:00 is not offered even though it looks free), the reserve-entry rules, and
a placeholder for the resource mode task 06 will add.

Also fixes a pre-existing flaky test that blocked a green suite:
NumericFieldNormalizerTest used a fixed national_code against db_test, which is
never reset, so depending on execution order the endpoint rejected it as a
duplicate. The test already looped for a unique mobile but not for the national
code. Out of this task's scope, fixed and declared so the definition of done is
actually green rather than apparently green.

phpstan was measured against the pre-task commit rather than asserted: 14 errors
in 9 files before, the same 14 in the same 9 files now.

Task 00 complete: 1026 tests green across three consecutive runs, 604 frontend
tests green, slot-mode contract frozen and verified.

Task: docs/new_feture/taskes/task-00-service-mode-completion/
Slot-mode contract: unchanged (--group=slot-mode-frozen green)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
hamed
2026-07-30 15:27:18 +03:30
co-authored by Claude Opus 5
parent 56a3c3c0d6
commit 9891c2e44a
4 changed files with 312 additions and 32 deletions
+17 -2
View File
@@ -15,6 +15,11 @@ use App\Tests\ApiTestCase;
*/
class NumericFieldNormalizerTest extends ApiTestCase
{
private function toPersianDigits(string $latin): string
{
return str_replace(range('0', '9'), ['۰','۱','۲','۳','۴','۵','۶','۷','۸','۹'], $latin);
}
public function testDigitsHelperTranslatesWithoutStripping(): void
{
self::assertSame('09123456789', PersianText::digits('۰۹۱۲۳۴۵۶۷۸۹'));
@@ -36,11 +41,21 @@ class NumericFieldNormalizerTest extends ApiTestCase
$latinMobile = PersianText::digits($persianMobile);
} while ($this->em->getRepository(User::class)->findOneBy(['mobileNumber' => $latinMobile]) !== null);
// کد ملی هم همین‌طور. ثابت‌بودنش این تست را flaky می‌کرد: در اجرای کامل سوئیت،
// بسته به ترتیب اجرا، ردیفِ اجرای قبلی باعث ۴۲۲ «تکراری» می‌شد و در اجرای تنها
// سبز بود.
$persianNationalCode = str_pad(
$this->toPersianDigits((string) random_int(0, 9_999_999_999)),
10,
'۰',
STR_PAD_LEFT,
);
$this->authJson('POST', '/api/v1/secretary', $owner, [
'doctor_uuid' => $doctor->getUuid(),
'mobile_number' => $persianMobile,
'name' => 'منشی تست',
'national_code' => '۰۰۱۲۳۴۵۶۷۸',
'national_code' => $persianNationalCode,
]);
self::assertSame(201, $this->responseCode(), 'Persian digits must not break validation');
@@ -50,7 +65,7 @@ class NumericFieldNormalizerTest extends ApiTestCase
self::assertNotNull($created, 'user is stored under the latin mobile');
$rel = $this->em->getRepository(DoctorSecretary::class)->findOneBy(['secretary' => $created]);
self::assertSame('0012345678', $rel->getNationalCode());
self::assertSame(PersianText::digits($persianNationalCode), $rel->getNationalCode());
}
public function testNestedArraysAreNormalized(): void