diff --git a/.changeset/2097-lead-owner-not-required.md b/.changeset/2097-lead-owner-not-required.md new file mode 100644 index 00000000..594ce653 --- /dev/null +++ b/.changeset/2097-lead-owner-not-required.md @@ -0,0 +1,5 @@ +--- +'hotcrm': patch +--- + +A sales rep can create a lead without first picking themselves as its owner. The **New Lead** form marked **Lead Owner** as required, so clicking **Create** with the field left blank stopped at *"Lead Owner is required"* and nothing was saved. The form no longer requires it. A lead created with the field left blank is owned by the person who created it, as on the **Opportunity**, **Account** and **Contact** New forms. **Lead Owner** stays on the form. diff --git a/src/sales/views/lead.view.ts b/src/sales/views/lead.view.ts index 2493440a..989120df 100644 --- a/src/sales/views/lead.view.ts +++ b/src/sales/views/lead.view.ts @@ -287,10 +287,12 @@ export const LeadViews = defineView({ }, 'lead_source', 'industry', - { - field: 'owner_id', - required: true, - }, + // Offered, ⛔ not `required` (#2097): an insert that leaves it empty is + // stamped to the creator by the platform (see `lead.hook.ts`), so a + // rep's new lead is theirs without a pick. `required` blocked that + // save client-side. A pick of another owner on create is currently + // dropped by the console (objectui#12359). + 'owner_id', // `disqualification_reason` is enforced by the // `disqualification_reason_required` validation on crm_lead, so every // form that lets a user pick "Unqualified" must also offer the reason diff --git a/test/ownership-model.test.ts b/test/ownership-model.test.ts index 03bae963..abf24c91 100644 --- a/test/ownership-model.test.ts +++ b/test/ownership-model.test.ts @@ -6,6 +6,7 @@ import { InMemoryDriver } from '@objectstack/driver-memory'; import type { VerifyStack } from '@objectstack/verify'; import stack from './helpers/composed-stack'; import { hotcrmStack, signUpPerson, type Person } from './helpers/verify-stack'; +import { LeadViews } from '../src/sales/views/lead.view'; /** * ═══ HotCRM has ONE owner, and it is the platform's (#548) ════════════════ @@ -162,6 +163,21 @@ describe('one ownership column, and it is `owner_id`', () => { ); expect(withDefault, 'owner_id must have no schema default').toEqual([]); }); + + it('the New Lead form leaves `owner_id` to that stamp — offered, not required (#2097)', () => { + // `LeadViews.form` IS the create dialog (see `case-create-form-narrowing`), + // and a `required` entry there is a client-side submit check. Measured on + // 18.0.0-next.0: a rep's Leads → New stopped at "Lead Owner is required" + // with nothing POSTed, so the stamp never saw the insert. The server half — + // a rep's ownerless insert lands owned by the rep — is pinned end to end by + // `stands down when the middleware already stamped an owner` below. + const entries: unknown[] = ((LeadViews as AnyRec).form?.sections ?? []).flatMap( + (s: AnyRec) => s.fields ?? [], + ); + const owner = entries.find((f) => (typeof f === 'string' ? f : (f as AnyRec)?.field) === 'owner_id'); + expect(owner, 'owner_id left the New Lead form — this pin would judge nothing').toBeDefined(); + expect((owner as AnyRec)?.required === true, 'the New Lead form demands an owner again').toBe(false); + }); }); // ──────────────────────────────────── which writers the gate can see ──