5.7 KiB
partner-center — nursing companies
Client seam
client/src/services/partnerCenter/·USE_PARTNER_MOCK = true(mock is primary) · 9 server ops Last verified: 2026-07-30 against commitd3ec723and swagger.v1.json (2026-07-29).
Nursing companies («مراکز») that sponsor nurses onto the platform. The domain with the widest gap between what the client wants and what the server serves — 6 of its client calls are phantom.
Endpoints
| Method | Path | Verdict |
|---|---|---|
| GET | /api/v1/admin/partner-centers |
wired · paginated |
| POST | /api/v1/admin/partner-centers |
wired |
| GET | /api/v1/admin/partner-centers/{id} |
wired |
| PATCH | /api/v1/admin/partner-centers/{id} |
wired |
| POST | /api/v1/admin/partner-centers/{id}/set-active |
wired — REQ-032's delivered half |
| POST | /api/v1/admin/partner-centers/{id}/sponsor-nurse |
wired |
| POST | /api/v1/admin/partner-centers/{id}/verify |
wired |
| GET | /api/v1/centers/{id}/dashboard |
unwired — the client wants centers/me/* splits instead |
| GET | /api/v1/internal/bookings/{bookingId}/center |
unwired — the MoR resolver, server-internal |
The seven admin/partner-centers routes are DynamicPermission + sensitive; centers is [Authorize];
internal/bookings is DynamicPermission.
This domain owns three of the four route-shape exceptions in the API: hyphens (partner-centers,
set-active, sponsor-nurse), a nested admin/ segment, and an internal/ namespace. It also has one of
only two PATCH verbs. See index.md.
Phantom — 6
| Client call | REQ | Note |
|---|---|---|
GET /api/v1/centers/me |
REQ-032 | The portal's own-center read |
GET /api/v1/centers/me/nurses |
REQ-032 | Split read — the server serves one aggregate instead |
GET /api/v1/centers/me/bookings |
REQ-032 | Split read |
GET /api/v1/centers/me/bookings/{id} |
REQ-064 | Partner-scoped booking detail |
GET /api/v1/centers/me/settlement |
REQ-033 | Per-booking commission invoices |
GET /api/v1/admin/partner-centers/{id}/nurses |
REQ-032 | The admin-side sponsored-nurse list |
The shape mismatch is the point. The server serves one aggregate, GET centers/{id}/dashboard →
CenterDashboardDto with sponsoredNurses inline. The portal wants /me plus paginated splits — it
cannot page an inline array, and it does not know its own center id without REQ-038. Until REQ-032 lands,
the portal is mock-only.
Merchant of record
The one business rule that changes where money goes:
isMerchantOfRecord = true→ the center is the seller. It invoices the customer, holds the commercial relationship, and Balinyaar's cut is a commission against the center.isMerchantOfRecord = false→ the nurse is the seller and the center is a sponsor only.
GET internal/bookings/{bookingId}/center is the MoR resolver the invoice pipeline calls to decide
which entity issues the invoice — which is why InvoiceDto.issuingEntityType exists. See
payment.md. commissionRate on the center is a per-center override of the platform
default, snapshotted at compute time like every other rate.
Shape rules the JSON does not express
- The settlement IBAN is write-then-masked.
settlementIbanMaskedis the only form on every read model; the full value never comes back after the write that set it. Same pattern as nurse.md. verifyis a licence check behind a seam.ILicenseVerificationServicechecks the eNamad code and the MoH establishment permit; by default it returnsNeedsManualReview, soverifyrecords a human admin decision.Seams:LicenseVerification:AutoApprovemakes the mock returnValidto test the auto-approve path. A real eNamad/MoH registry adapter ignores the knob.technicalDirectorNurseUserIdlinks to a real verified nurse, not a free-text name — Iranian regulation requires a named technical director («مدیر فنی») with a valid licence.set-activeis suspend/activate, not delete. A suspended center's sponsored nurses and past bookings stay resolvable.sponsoredNurseCountis denormalised onto both the list item and the detail so the queue needs no per-row count.legalEntityTypeandmohEstablishmentPermitNoare the regulatory identity;enamadCodeis the e-commerce trust seal. All three are distinct and none substitutes for another.
Enums
| Vocabulary | Values |
|---|---|
CenterOnboardingState |
draft pending_verification verified suspended |
MoadianStatus (on the center's invoices) |
pending submitted registered failed |
MoadianStatus is shared with payment.md — it is the سامانه مودیان submission state, and it
is the same vocabulary on both sides.
CenterOnboardingStateis the client's model of the center's position in onboarding. On the wire the server carries the facts it is derived from —isActiveandverifiedAton bothPartnerCenterListItemDtoandPartnerCenterDetailDto— not the state string itself. Derive, do not expect a field.
Open REQs
| REQ | Status | Effect |
|---|---|---|
| REQ-032 | partially delivered | set-active landed. The /me split reads and the IBAN write-then-masked flow are deferred → 5 phantom routes. The main reason this seam is mocked |
| REQ-033 | partially delivered | totalIrr is on InvoiceDto; the per-booking commission invoice list is deferred → 1 phantom |
| REQ-064 | open | No partner-scoped booking detail → 1 phantom |
| REQ-038 | open | /me carries no signal that the caller administers a center, so the portal cannot auto-route or discover its own center id. See auth.md |