The /api/v1/quotes/create route was wired to accept operator-supplied
quote_number + rfq_number + quote_notes + notes + status, but the
service-layer side never matched: QuoteNumberExistsError didn't exist
and CreateQuoteInput ignored the new fields. Production deploy was
failing on `Module has no exported member 'QuoteNumberExistsError'`.
Service changes:
- New QuoteNumberExistsError class (mirrors OrderNumberCollisionError):
carries existingId + attemptedNumber, mapped to 409 by the route
- CreateQuoteInput extended with quote_number, rfq_number, quote_notes,
notes, status; imported QuoteStatus from @/lib/types
- createQuote now uses input.quote_number verbatim when supplied, else
falls back to the existing atomic-counter generator
- createQuote's pb.create call is wrapped in try/catch: PB's UNIQUE
constraint violation on quote_number is re-thrown as the typed error
with the colliding row's id resolved via a follow-up getList
New route test file (9 cases) covers happy path with supplied
quote_number, the 409 collision branch, notes/quote_notes fallback
merge, auth-gate failures, missing customer/items validation, and
generic 500 fallback. Uses importOriginal so the real
QuoteNumberExistsError class survives the service-layer mock.
Co-Authored-By: Claude <noreply@anthropic.com>