← back to Dw Activation Debug TK11314
lib/five-field-extra.js
44 lines
'use strict';
// The universal memo-sample price. A "sellable" (non-sample) variant stuck at
// exactly this value is the $4.25 sample-price LEAK, NOT a real sellable price —
// so it must NOT satisfy the price>0 gate (else the activator flips DRAFT→ACTIVE
// on a product that is orderable at $4.25). Fail-safe: this can only BLOCK an
// activation, never cause one. (TK-10456, 2026-08-31 — the rotation was
// re-activating reverted $4.25 murals/Chloe because $4.25 > 0 passed the gate.)
const SAMPLE_LEAK_PRICE = 4.25;
function fiveFieldExtra(product) {
const hasValidVariantsShape = Array.isArray(product?.variants?.nodes);
const hasValidTagsShape = Array.isArray(product?.tags);
const variants = hasValidVariantsShape ? product.variants.nodes : [];
const tags = hasValidTagsShape
? product.tags.map((tag) => String(tag).trim().toLowerCase())
: [];
const hasSample = variants.some((variant) => /-sample$/i.test(variant.sku || ''));
const sellable = variants.filter((variant) => !/-sample$/i.test(variant.sku || ''));
const pricedSellable = sellable.filter((variant) => {
if (typeof variant.price !== 'string' || !/^\d+(?:\.\d+)?$/.test(variant.price)) return false;
const price = Number(variant.price);
return Number.isFinite(price) && price > 0;
});
const hasSellablePriced = pricedSellable.length > 0;
// If the ONLY priced sellable variant(s) sit at the sample-leak price, this is a
// $4.25 leak, not a real price → block. A real price on any sellable variant
// (e.g. a $384 roll alongside a $4.25 sample) still passes.
const onlySampleLeakPriced = hasSellablePriced &&
pricedSellable.every((variant) => Number(variant.price) === SAMPLE_LEAK_PRICE);
const isQuoteOnly = tags.includes('quotes');
const reasons = [];
if (!hasValidVariantsShape) reasons.push('invalid-variants-shape');
if (!hasValidTagsShape) reasons.push('invalid-tags-shape');
if (!hasSample) reasons.push('no-sample-variant');
if (!sellable.length && !isQuoteOnly) reasons.push('no-sellable-variant');
if (!hasSellablePriced && !isQuoteOnly) reasons.push('sellable-price-not-gt-0');
else if (onlySampleLeakPriced && !isQuoteOnly) reasons.push('sellable-price-is-sample-leak-4.25');
if (tags.length < 2) reasons.push('fewer-than-2-tags');
return { ok: reasons.length === 0, reasons };
}
module.exports = { fiveFieldExtra };