kovakmedya 97a6031992 feat(jobs/new): clinic picks a lab catalog product, not a raw type
What the clinic sees has changed from a fixed 6-item Protez Türü dropdown
to the actual products that lab has published in its catalog. Picking 'Premium
Zirkonyum (1500 TRY / diş)' is now an option; picking the generic
'Zirkonyum' bucket is not.

Wiring
  - DB: jobs.prostheticId string column (optional — legacy jobs stay valid).
    The denormalised prostheticType is still written, sourced server-side
    from the chosen catalog row, so reports/aggregates keep working.
  - validation/job.ts: prostheticId required, prostheticType removed from
    the form payload (computed instead).
  - job-actions.ts: looks up the catalog row, verifies tenantId match +
    not archived, then pulls .type and .unitPrice from it to drive
    calculateJobPriceForProsthetic.

Pricing helper
  - New calculateJobPriceForProsthetic(prosthetic, clinicTenantId,
    teethCount). Reuses the same clinic_pricing cascade
    (custom price wins, otherwise discountPercent off catalog) but skips
    the type-based catalog lookup entirely — it already has the row.
  - /api/pricing/quote rewritten to accept { prostheticId, teethCount },
    still gated on an approved connection between clinic and the lab that
    owns the product.

UI
  - jobs/new page server-loads each connected lab's active prosthetics
    once and hands them to NewJobForm as prostheticsByLab.
  - NewJobForm: 'Ürün *' Select replaces 'Protez Türü *'. The list filters
    by the currently selected lab; switching labs clears the chosen
    product. Each option shows name + 'unitPrice / diş' on the right.
    Once selected, a small caption surfaces the underlying category
    label ('Kategori: Zirkonyum') so the clinic still understands what
    bucket the product falls into.
  - PriceQuoteCard's hasInputs gating moved off prostheticType to
    prostheticId.
2026-05-22 01:01:35 +03:00
S
Description
No description provided
5.8 MiB
Languages
TypeScript 99.2%
CSS 0.7%