Feature/224 intake notification #263
@@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* Where an item's price came from, and when that changes.
|
||||||
|
*
|
||||||
|
* This is the protection that used to live in the schema. Items are priced on
|
||||||
|
* arrival — the model's suggestion, or the 80.00 default — so nothing stops a
|
||||||
|
* number nobody chose from reaching the storefront except the review queue
|
||||||
|
* showing that it was never chosen.
|
||||||
|
*
|
||||||
|
* Pure and separately tested because the failure is silent. An item that sells
|
||||||
|
* at a default price looks exactly like one that sells at a chosen price;
|
||||||
|
* 80.00 was picked precisely because it reads as a decision rather than as an
|
||||||
|
* obvious sentinel the way 0.00 would.
|
||||||
|
*/
|
||||||
|
export type PriceSource = 'default' | 'ai' | 'admin';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Editing the number is the admin taking responsibility for it, and it is the
|
||||||
|
* only thing that can. Publishing without touching the field deliberately does
|
||||||
|
* NOT confirm it — that would turn "I did not look at this" into "I approved
|
||||||
|
* this", which is the exact misrecording the review queue exists to prevent.
|
||||||
|
*/
|
||||||
|
export function nextPriceSource(
|
||||||
|
current: PriceSource,
|
||||||
|
submittedCents: number,
|
||||||
|
storedCents: number
|
||||||
|
): PriceSource {
|
||||||
|
if (current === 'admin') return 'admin';
|
||||||
|
return submittedCents === storedCents ? current : 'admin';
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Anything a person did not choose, which the screen marks visibly. */
|
||||||
|
export function isUnconfirmed(source: PriceSource): boolean {
|
||||||
|
return source !== 'admin';
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { nextPriceSource, isUnconfirmed } from '../../src/intake/priceSource';
|
||||||
|
|
||||||
|
describe('nextPriceSource', () => {
|
||||||
|
// Touching the number is the admin taking responsibility for it. That is the
|
||||||
|
// only event that can confirm a price.
|
||||||
|
it('becomes admin when the number changes', () => {
|
||||||
|
expect(nextPriceSource('default', 9500, 8000)).toBe('admin');
|
||||||
|
expect(nextPriceSource('ai', 4000, 4500)).toBe('admin');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Publishing without touching the field must NOT silently confirm it. That
|
||||||
|
// is the whole failure this screen exists to prevent: an item selling at a
|
||||||
|
// number nobody chose, with nothing recording that.
|
||||||
|
it('leaves an untouched price unconfirmed', () => {
|
||||||
|
expect(nextPriceSource('default', 8000, 8000)).toBe('default');
|
||||||
|
expect(nextPriceSource('ai', 4500, 4500)).toBe('ai');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Already confirmed stays confirmed, including when re-submitted unchanged.
|
||||||
|
it('keeps admin once set', () => {
|
||||||
|
expect(nextPriceSource('admin', 9500, 9500)).toBe('admin');
|
||||||
|
expect(nextPriceSource('admin', 7000, 9500)).toBe('admin');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isUnconfirmed', () => {
|
||||||
|
it('treats anything but admin as unconfirmed', () => {
|
||||||
|
expect(isUnconfirmed('default')).toBe(true);
|
||||||
|
expect(isUnconfirmed('ai')).toBe(true);
|
||||||
|
expect(isUnconfirmed('admin')).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user