fix(review): Create desc gate does not require price
This commit is contained in:
@@ -144,7 +144,7 @@
|
|||||||
// Prefer slab.species_id; fall back to Capture handoff if createSlab omitted it.
|
// Prefer slab.species_id; fall back to Capture handoff if createSlab omitted it.
|
||||||
$: resolvedSpeciesId = effectiveSpeciesId(slab?.species_id, capture?.speciesId ?? null);
|
$: resolvedSpeciesId = effectiveSpeciesId(slab?.species_id, capture?.speciesId ?? null);
|
||||||
$: canCreateTitle = canCreateTitleFromSpecies(resolvedSpeciesId, woodCatIds.length);
|
$: canCreateTitle = canCreateTitleFromSpecies(resolvedSpeciesId, woodCatIds.length);
|
||||||
// Create-desc gate: recompute on every field change (no blur required). Description not required.
|
// Create-desc gate: recompute on every field change (no blur required). Description and price not required.
|
||||||
$: createDescMissing = missingCreateDescLabels({
|
$: createDescMissing = missingCreateDescLabels({
|
||||||
contentLlmEnabled: canGenerateContent,
|
contentLlmEnabled: canGenerateContent,
|
||||||
title,
|
title,
|
||||||
@@ -156,7 +156,6 @@
|
|||||||
figureTermIds: figureIds,
|
figureTermIds: figureIds,
|
||||||
gradeTermId: gradeSel,
|
gradeTermId: gradeSel,
|
||||||
moistureTermId: moistureSel,
|
moistureTermId: moistureSel,
|
||||||
price,
|
|
||||||
});
|
});
|
||||||
$: canCreateDesc = createDescMissing.length === 0;
|
$: canCreateDesc = createDescMissing.length === 0;
|
||||||
// Monotonic token: each commit captures the current value and ignores its
|
// Monotonic token: each commit captures the current value and ignores its
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ const full = {
|
|||||||
figureTermIds: [328],
|
figureTermIds: [328],
|
||||||
gradeTermId: 342,
|
gradeTermId: 342,
|
||||||
moistureTermId: '326',
|
moistureTermId: '326',
|
||||||
price: '184.00',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
test('Create desc gate: full set passes; does not require description', () => {
|
test('Create desc gate: full set passes; does not require description', () => {
|
||||||
@@ -25,7 +24,13 @@ test('Create desc gate: full set passes; does not require description', () => {
|
|||||||
assert.deepEqual(missingCreateDesc(full), []);
|
assert.deepEqual(missingCreateDesc(full), []);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Create desc gate: lists each missing field; no description key', () => {
|
test('Create desc gate: empty price still passes when other fields full', () => {
|
||||||
|
// Price is publish-only; Create desc must not gate on it.
|
||||||
|
assert.equal(canCreateDesc(full), true);
|
||||||
|
assert.deepEqual(missingCreateDesc(full), []);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Create desc gate: lists each missing field; no description or price key', () => {
|
||||||
const miss = missingCreateDesc({
|
const miss = missingCreateDesc({
|
||||||
...full,
|
...full,
|
||||||
contentLlmEnabled: false,
|
contentLlmEnabled: false,
|
||||||
@@ -38,7 +43,6 @@ test('Create desc gate: lists each missing field; no description key', () => {
|
|||||||
figureTermIds: [],
|
figureTermIds: [],
|
||||||
gradeTermId: '',
|
gradeTermId: '',
|
||||||
moistureTermId: '',
|
moistureTermId: '',
|
||||||
price: '',
|
|
||||||
});
|
});
|
||||||
assert.deepEqual(miss, [
|
assert.deepEqual(miss, [
|
||||||
'content_llm',
|
'content_llm',
|
||||||
@@ -51,16 +55,15 @@ test('Create desc gate: lists each missing field; no description key', () => {
|
|||||||
'figure',
|
'figure',
|
||||||
'grade',
|
'grade',
|
||||||
'moisture',
|
'moisture',
|
||||||
'price',
|
|
||||||
]);
|
]);
|
||||||
assert.equal(miss.includes('description'), false);
|
assert.equal(miss.includes('description'), false);
|
||||||
|
assert.equal(miss.includes('price'), false);
|
||||||
const labels = missingCreateDescLabels({
|
const labels = missingCreateDescLabels({
|
||||||
...full,
|
...full,
|
||||||
figureTermIds: [],
|
figureTermIds: [],
|
||||||
price: '',
|
|
||||||
});
|
});
|
||||||
assert.ok(labels.includes('≥1 figure'));
|
assert.ok(labels.includes('≥1 figure'));
|
||||||
assert.ok(labels.includes('price'));
|
assert.equal(labels.includes('price'), false);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Create desc gate: recomputes on field change (reactive-ready)', () => {
|
test('Create desc gate: recomputes on field change (reactive-ready)', () => {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Create-desc gate (Call 2): disable Create desc unless these are present.
|
* Create-desc gate (Call 2): disable Create desc unless these are present.
|
||||||
* Does NOT require description (that is what Create desc writes).
|
* Does NOT require description OR price (price stays publish-only).
|
||||||
* Price included for parity with publish-ready.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export type CreateDescInput = {
|
export type CreateDescInput = {
|
||||||
@@ -15,7 +14,6 @@ export type CreateDescInput = {
|
|||||||
figureTermIds: number[];
|
figureTermIds: number[];
|
||||||
gradeTermId: number | string | '' | null | undefined;
|
gradeTermId: number | string | '' | null | undefined;
|
||||||
moistureTermId: number | string | '' | null | undefined;
|
moistureTermId: number | string | '' | null | undefined;
|
||||||
price: string | number | null | undefined;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Human labels shown under Create desc when the gate fails. */
|
/** Human labels shown under Create desc when the gate fails. */
|
||||||
@@ -30,7 +28,6 @@ export const CREATE_DESC_LABELS: Record<string, string> = {
|
|||||||
figure: '≥1 figure',
|
figure: '≥1 figure',
|
||||||
grade: 'grade',
|
grade: 'grade',
|
||||||
moisture: 'moisture',
|
moisture: 'moisture',
|
||||||
price: 'price',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function presentId(v: number | string | '' | null | undefined): boolean {
|
function presentId(v: number | string | '' | null | undefined): boolean {
|
||||||
@@ -39,12 +36,6 @@ function presentId(v: number | string | '' | null | undefined): boolean {
|
|||||||
return String(v).trim() !== '';
|
return String(v).trim() !== '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function presentPrice(v: string | number | null | undefined): boolean {
|
|
||||||
if (v === null || v === undefined || v === '') return false;
|
|
||||||
const n = typeof v === 'number' ? v : Number(v);
|
|
||||||
return Number.isFinite(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Return missing field keys (stable order). Empty ⇒ Create desc enabled. */
|
/** Return missing field keys (stable order). Empty ⇒ Create desc enabled. */
|
||||||
export function missingCreateDesc(input: CreateDescInput): string[] {
|
export function missingCreateDesc(input: CreateDescInput): string[] {
|
||||||
const missing: string[] = [];
|
const missing: string[] = [];
|
||||||
@@ -58,7 +49,6 @@ export function missingCreateDesc(input: CreateDescInput): string[] {
|
|||||||
if (!input.figureTermIds?.length) missing.push('figure');
|
if (!input.figureTermIds?.length) missing.push('figure');
|
||||||
if (!presentId(input.gradeTermId)) missing.push('grade');
|
if (!presentId(input.gradeTermId)) missing.push('grade');
|
||||||
if (!presentId(input.moistureTermId)) missing.push('moisture');
|
if (!presentId(input.moistureTermId)) missing.push('moisture');
|
||||||
if (!presentPrice(input.price)) missing.push('price');
|
|
||||||
return missing;
|
return missing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user