Adding a forfait from the client detail dialog failed with `Update
failed: 417` because the code path manipulated ERPNext's stock
Subscription doctype — a parent/child (Subscription Plan rows) model
with tight validation ("Subscription End Date is mandatory to follow
calendar months"), and whose `plan` field expects an `SP-<hash>` doc
name rather than a free-form string.
Meanwhile all new subscription work — contract signing, chain
activation, prorated invoicing — already writes to our flat custom
`Service Subscription` doctype. The two systems were not talking to
each other: the Service Subscription created for CTR-00008 was
invisible in the client UI (which only read stock Subscription), and
the stock Subscription created by "Ajouter un service" was invisible
to the contract/chain system.
This commit makes Service Subscription the canonical doctype for
everything the ops UI does:
- useClientData.loadSubscriptions: read Service Subscription directly
(flat doc → UI row) instead of reading stock Subscription + joining
its Subscription Plan child rows to Items. Legacy stock Subscription
rows (~39k from the 2026-03-29 migration) stay as audit records
but are no longer surfaced.
- ClientDetailPage.createService: POST a Service Subscription doc
(category inferred from item_group). No parent/child logic, no
calendar-month coupling, no SP-<hash> plan reference. Manual
description + price entry now works without a catalog pick.
- useSubscriptionActions.updateSub: drop the bogus `ASUB-*` name-based
doctype detection (ASUB is not a real prefix — both stock and
Service subs are named SUB-<hex|digits>) and always target Service
Subscription. Also surface ERPNext's exception one-liner instead of
raw HTML when an update fails.
- searchPlans: empty/short query now returns top-50 of the Subscription
Plan catalog so dispatchers can browse instead of being forced to
guess a name prefix.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>