Every storefront models delivery as one field. estimated_ship_date, sometimes a text blob, sometimes a date the theme renders with the word "about". That field carries a marketing promise and, under 16 CFR part 435, a legal one, and the two diverge the first time stock is late.
The rule is short enough to read in one sitting and specific enough to implement. What it does not do is fit into a single date column, because it keys obligations off three different moments: the time stated at solicitation, the receipt of a properly completed order, and the boundary 30 days after the applicable time. Modeling it as a promise with a status field is where the failures start.
The clocks
create table order_promise (
order_id text primary key,
channel text not null check (channel in ('mail','internet','telephone')),
stated_lead_days integer, -- null means the rule's default applies
credit_applied_at timestamptz, -- buyer asked seller for credit at ordering
order_complete_at timestamptz not null, -- payment AND everything needed to ship
applicable_ship_by timestamptz generated always as (
order_complete_at + make_interval(
days => coalesce(stated_lead_days,
case when credit_applied_at is not null then 50 else 30 end)
)
) stored
);
stated_lead_days being null is the important case. Section 435.2(a)(1) sets the expectation at the time clearly and conspicuously stated in the solicitation, and when no time was stated the default becomes 30 days measured from a properly completed order reaching the seller. A buyer who has applied for credit when placing the order gets a 50-day default instead. A column that silently defaults to 30 in application code hides the fact that a two-week claim on the product page is the number that governs, not the fallback.
order_complete_at is the other place where a schema lies. Section 435.1(c) ties receipt of a properly completed order to the seller receiving both the payment and an order containing all the information needed to process and ship it, with a reset when a non-cash tender is bounced or a credit sale is not approved. Recording paid_at and calling it the same thing will compute the wrong deadline for every order that arrived with a missing variant or an incomplete address.
The notice is an event with a deadline
type PromiseState =
| 'on_track'
| 'notice_required' // cannot ship by applicable_ship_by
| 'awaiting_response' // notice sent, 30-day boundary running
| 'consented' // buyer accepted a definite revised date
| 'deemed_canceled' // boundary passed without shipment or consent
| 'refund_due';
// Which default applies is decided by one comparison, not by a policy flag.
export function noticeKind(revisedShipBy: Date | null, applicableShipBy: Date) {
if (!revisedShipBy) return 'no_representation'; // 435.2(b)(1)(iii)
const days = (revisedShipBy.getTime() - applicableShipBy.getTime()) / 86_400_000;
return days <= 30 ? 'deemed_consent_possible' // 435.2(b)(1)(ii)
: 'deemed_cancellation_possible'; // 435.2(b)(1)(iii)
}
That comparison is the whole reversal, and it is the one most order pipelines get backwards. A revised date within 30 days of the applicable time is the branch where silence can be read as agreement, so long as the buyer stays free to reject before the parcel moves and before that date. Cross the same 30 days the other way, or admit you cannot name a date, and the default flips: the order is treated as canceled unless it ships inside 30 days of the applicable time with no cancellation on file, or the buyer says yes before then. An open-ended yes keeps a cancellation right alive until the carton actually leaves.
Two more obligations land on the same record. Section 435.2(b)(1) requires the offer to be made without waiting for a demand and no later than the applicable time, so notice_required cannot be a state a human notices after the fact. And 435.2(b)(2) requires a renewed offer when a consented revised date is missed, which means consented is not terminal and a single notices-sent boolean cannot represent it honestly.
The presumption is a query
create view defensible_lead_times as
select p.order_id,
p.stated_lead_days,
p.applicable_ship_by,
exists (select 1 from promise_notice n
where n.order_id = p.order_id
and n.sent_at <= p.applicable_ship_by) as notice_in_time,
exists (select 1 from shipment_event s
where s.order_id = p.order_id
and s.shipped_at <= p.applicable_ship_by) as shipped_in_promise
from order_promise p;
-- 435.2(a)(4): no documentary proof of systems that ship in the ordinary
-- course inside the applicable time creates a rebuttable presumption that
-- the seller lacked a reasonable basis for the expectation.
select count(*) filter (where not shipped_in_promise and not notice_in_time)
as orders_with_no_defensible_record
from defensible_lead_times;
The last block is why this belongs in a database rather than in a policy document. Section 435.2(a)(4) treats a missing record set, or any other documentary proof that systems and procedures exist to move goods in the ordinary course inside the applicable time, as a rebuttable presumption that no reasonable basis to ship then was ever there. A count you can run is the difference between a rebuttable position and an assertion.
One boundary, stated plainly. This is a model of what the published rule asks a system to record and to be able to show. Whether a specific order, listing or notice satisfied the rule is not decided by a view, and the refund timing in 435.1(b) is measured from the date a buyer's right to refund vests, which is a legal fact your code can only approximate. FulfillNexa by SBT (fulfillnexa.com) keeps seller inventory on three Chinese floors: Suzhou with 13,000 square meters, Dongguan with 8,000 and Shenzhen with 3,000, and our contribution to a defensible date is unglamorous: a count made and dated the day a pallet is put away, so the number in estimated_ship_date came from a pick path rather than from a hope.
Top comments (0)