DEV Community

Tom
Tom

Posted on

Make Leave Unchanged Different From Clear This Order Note

An order update can omit a packing note because that field has not changed. If an adapter turns every missing note into an empty value, a later status update can erase the instruction the warehouse still needs.

Treat field presence as part of the data contract. For the small example below, an omitted packingNote leaves the current value alone, a nonblank string replaces it, and null explicitly clears it. This is an example contract to agree with both systems, not a claim about a particular store API.

Decode intent before applying a value

The JavaScript ?? operator is not enough for this contract: a fallback for null and undefined would collapse the explicit clear into the same path as an absent value. Conversely, defaulting an omitted field to an empty string would turn “unchanged” into a deletion.

Object.hasOwn checks whether the object itself has the property. In this example the boundary accepts ordinary parsed JSON objects. It rejects an empty string instead of quietly interpreting it as either a note or permission to clear one.

Save this as note-update.cjs and run it with Node.js:

const assert = require('node:assert/strict');

function decodeNotePatch(patch) {
  if (patch === null || typeof patch !== 'object' || Array.isArray(patch)) {
    throw new TypeError('Expected an update object');
  }
  if (!Object.hasOwn(patch, 'packingNote')) return { kind: 'unchanged' };
  const value = patch.packingNote;
  if (value === null) return { kind: 'clear' };
  if (typeof value !== 'string' || value.trim() === '') {
    throw new TypeError('Expected a nonblank note or explicit null');
  }
  return { kind: 'set', value };
}

function applyNotePatch(current, patch) {
  const intent = decodeNotePatch(patch);
  if (intent.kind === 'unchanged') return current;
  return { ...current, packingNote: intent.kind === 'clear' ? null : intent.value };
}

const original = Object.freeze({ orderId: 'DEMO-41', packingNote: 'Include care card' });
assert.strictEqual(applyNotePatch(original, JSON.parse('{"status":"ready"}')), original);
assert.equal(applyNotePatch(original, { packingNote: null }).packingNote, null);
assert.equal(applyNotePatch(original, { packingNote: 'Use paper sleeve' }).packingNote,
  'Use paper sleeve');
for (const value of ['', '   ', 0, false, [], {}, undefined]) {
  assert.throws(() => applyNotePatch(original, { packingNote: value }), TypeError);
}
for (const patch of [null, [], 'ready']) {
  assert.throws(() => applyNotePatch(original, patch), TypeError);
}
assert.equal(original.packingNote, 'Include care card');
console.log('Omission preserved the note; explicit clear and replacement stayed distinct.');
Enter fullscreen mode Exit fullscreen mode

The strict assertions check all three intended outcomes, rejected shapes and values, and preservation of the original object. The undefined case also checks an in-process value that JSON cannot carry as an object property value.

Keep the warehouse meaning attached

Only the note field is applied here; status in the first test is deliberately ignored. This example is not a generic update engine or a production integration. It does not handle authorization, message ordering, persistence or changes to work already released for packing.

An authorized clear still needs an operational rule. If a parcel has already been packed under the earlier instruction, changing a record does not undo that work. Check how the accepted change reaches the people using the instruction and how its result returns to the store.

I work with YX Fulfillment, whose published integration setup calls for demonstrating order fields and change handling for the account. The useful test is small: send an unrelated update, inspect the retained note, then send an explicit approved change and inspect the resulting warehouse instruction. That checks the contract on both sides of the handover.

Comparing two instruction cards beside a packed parcel

Reviewing a packing instruction before applying a change. Illustrative scene.

Top comments (0)