This commit is contained in:
seb
2026-10-21 11:55:21 +02:00
parent e085bcaeba
commit eb1e9e2eb9
8 changed files with 67 additions and 42 deletions

2
API.md
View File

@@ -209,7 +209,7 @@ The store is exposed as a `LibDashStore` instance (see `src/index.js`). Each met
- [order](API.order.md) - [order](API.order.md)
- `create(googleAuthId: number, body: {number: string, date: string, entityId: number, externalNumber?: string, lines?: Array<{sku?: string, name?: string, pu?: number, amount: number, net: number, rebate?: number, taxrate: number, comment?: string|null, shippable?: boolean}>}, tx?: object): Promise<{id: number, number: string, type: string, entityId: number, externalNumber: string|null, date: string, lines: Array<{id: number, sku: string|null, name: string|null, pu: number, amount: number, net: number, rebate: number, taxrate: number, comment: string|null}>}>` - `create(googleAuthId: number, body: {number: string, date: string, entityId: number, externalNumber?: string, lines?: Array<{sku?: string, name?: string, pu?: number, amount: number, net: number, rebate?: number, taxrate: number, comment?: string|null, shippable?: boolean}>}, tx?: object): Promise<{id: number, number: string, type: string, entityId: number, externalNumber: string|null, date: string, lines: Array<{id: number, sku: string|null, name: string|null, pu: number, amount: number, net: number, rebate: number, taxrate: number, comment: string|null}>}>`
- `createFromQuote(googleAuthId: number, quoteId: number, body?: {number?: string, date?: string, createdAt?: string, entityId?: number, externalNumber?: string, lines?: Array<{sku?: string, name?: string, pu?: number, amount: number, net: number, rebate?: number, taxrate: number, comment?: string|null, shippable?: boolean}>}, tx?: object): Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array<{id: number, sku: string|null, name: string|null, pu: number, amount: number, net: number, rebate: number, taxrate: number, comment: string|null}>}>` - `createFromQuote(googleAuthId: number, quoteId: number, body?: {number?: string, date?: string, createdAt?: string, entityId?: number, externalNumber?: string, lines?: Array<{sku?: string, name?: string, pu?: number, amount: number, net: number, rebate?: number, taxrate: number, comment?: string|null, shippable?: boolean}>}, tx?: object): Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array<{id: number, sku: string|null, name: string|null, pu: number, amount: number, net: number, rebate: number, taxrate: number, comment: string|null}>}>`
- `createShipment(googleAuthId: number, orderId: number, input: {lines: Array<{sku: string, amount?: number, name?: string, pu?: number, net?: number, rebate?: number, taxrate?: number, comment?: string}>, date?: string|Date, externalNumber?: string}, tx?: object): Promise<object>` - `createShipment(googleAuthId: number, orderId: number, input: {lines: Array<{sku: string, amount?: number, name?: string, pu?: number, net?: number, rebate?: number, taxrate?: number, comment?: string}>, date?: string|Date, externalNumber?: string, shipping: object}, tx?: object): Promise<object>`
- `delete(googleAuthId: number, id: number, tx?: object): Promise<void>` - `delete(googleAuthId: number, id: number, tx?: object): Promise<void>`
- `getById(googleAuthId: number, id: number, tx?: object): Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array<{id: number, sku: string|null, name: string|null, pu: number, amount: number, net: number, rebate: number, taxrate: number, comment: string|null}>}>` - `getById(googleAuthId: number, id: number, tx?: object): Promise<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, lines: Array<{id: number, sku: string|null, name: string|null, pu: number, amount: number, net: number, rebate: number, taxrate: number, comment: string|null}>}>`
- `list(googleAuthId: number, opts?: {offset?: number, limit?: number, search?: string, onlyUnpaid?: boolean, onlyUndelivered?: boolean, seekMonths?: number}, tx?: object): Promise<{orders: Array<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, createdAt: string|null, lines: Array<{id: number, sku: string|null, name: string|null, pu: number, amount: number, net: number, rebate: number, taxrate: number, comment: string|null}>}>, total: number, unfilteredTotal: number, offset: number, limit: number}|Array<object>>` - `list(googleAuthId: number, opts?: {offset?: number, limit?: number, search?: string, onlyUnpaid?: boolean, onlyUndelivered?: boolean, seekMonths?: number}, tx?: object): Promise<{orders: Array<{id: number, number: string, type: string, entityId: number|null, externalNumber: string|null, date: string, createdAt: string|null, lines: Array<{id: number, sku: string|null, name: string|null, pu: number, amount: number, net: number, rebate: number, taxrate: number, comment: string|null}>}>, total: number, unfilteredTotal: number, offset: number, limit: number}|Array<object>>`

View File

@@ -88,6 +88,7 @@ Creates a new shipment manifest for an order. Can contain specified items from t
| `input.lines` | `Array<{sku: string, amount?: number, name?: string, pu?: number, net?: number, rebate?: number, taxrate?: number, comment?: string}>` | Positions to ship. | | `input.lines` | `Array<{sku: string, amount?: number, name?: string, pu?: number, net?: number, rebate?: number, taxrate?: number, comment?: string}>` | Positions to ship. |
| `[input.date]` | `string|Date` | Optional shipment date. | | `[input.date]` | `string|Date` | Optional shipment date. |
| `[input.externalNumber]` | `string` | Optional external delivery reference. | | `[input.externalNumber]` | `string` | Optional external delivery reference. |
| `input.shipping` | `object` | Required shipping ({carrierId, type, state, trackingCode?, warehouseId?}); see shipment.create. |
| `[tx]` | `object` | Optional transaction. | | `[tx]` | `object` | Optional transaction. |
**Returns** **Returns**
@@ -97,7 +98,7 @@ Creates a new shipment manifest for an order. Can contain specified items from t
**Example** **Example**
```js ```js
const shipment = await store.order.createShipment(googleAuthId, 10, { lines: [{ sku: 'ITEM-A', amount: 5 }] }); const shipment = await store.order.createShipment(googleAuthId, 10, { lines: [{ sku: 'ITEM-A', amount: 5 }], shipping: { carrierId: 1, type: 'parcel', state: 'draft' } });
``` ```
## `order.delete` ## `order.delete`

View File

@@ -269,8 +269,12 @@ async function run() {
], ],
}); });
const testCarrier = await store.carrier.create(googleAuthId, { name: 'Test Carrier', hasPackages: true });
const testShipping = { carrierId: testCarrier.id, type: 'parcel', state: 'draft' };
const shipment = await store.shipment.create(googleAuthId, { const shipment = await store.shipment.create(googleAuthId, {
orderId: order2.id, orderId: order2.id,
shipping: testShipping,
lines: [{ sku: 'SKU-ABC', amount: 3 }], lines: [{ sku: 'SKU-ABC', amount: 3 }],
}); });
@@ -358,6 +362,7 @@ async function run() {
const shipment3 = await store.shipment.create(googleAuthId, { const shipment3 = await store.shipment.create(googleAuthId, {
orderId: order3.id, orderId: order3.id,
shipping: testShipping,
lines: [ lines: [
{ sku: 'SKU-ABC', amount: 4 }, { sku: 'SKU-ABC', amount: 4 },
{ sku: 'SKU-ABC', amount: -1 }, { sku: 'SKU-ABC', amount: -1 },
@@ -419,6 +424,7 @@ async function run() {
await assert.rejects( await assert.rejects(
async () => store.shipment.create(googleAuthId, { async () => store.shipment.create(googleAuthId, {
orderId: guardOrder.id, orderId: guardOrder.id,
shipping: testShipping,
warehouseId: wh1.id, warehouseId: wh1.id,
lines: [{ sku: article.sku, amount: curStock + 10 }], lines: [{ sku: article.sku, amount: curStock + 10 }],
}), }),

View File

@@ -95,14 +95,11 @@ async function run() {
entityId: customerBob.id, entityId: customerBob.id,
lines: [{ sku: art.sku, name: 'Widget', amount: 2, net: 100, taxrate: 19 }], lines: [{ sku: art.sku, name: 'Widget', amount: 2, net: 100, taxrate: 19 }],
}); });
const testCarrier = await store.carrier.create(googleAuthId, { name: 'Test Carrier', hasPackages: true });
const shipment2 = await store.shipment.create(googleAuthId, { const shipment2 = await store.shipment.create(googleAuthId, {
orderId: order2.id, orderId: order2.id,
lines: [{ sku: art.sku, amount: 2 }], lines: [{ sku: art.sku, amount: 2 }],
}); shipping: { carrierId: testCarrier.id, type: 'parcel', state: 'shipped' },
await store.shipping.create(googleAuthId, {
manifestId: shipment2.id,
type: 'parcel',
state: 'shipped',
}); });
// Order 3: Alice, O-1003, €59.50, Date: today (2026-10-13) // Order 3: Alice, O-1003, €59.50, Date: today (2026-10-13)
@@ -128,14 +125,10 @@ async function run() {
type: 'bank_transfer', type: 'bank_transfer',
amount: 150, // Overpaid! amount: 150, // Overpaid!
}); });
const shipment4 = await store.shipment.create(googleAuthId, { await store.shipment.create(googleAuthId, {
orderId: order4.id, orderId: order4.id,
lines: [{ sku: art.sku, amount: 1 }], lines: [{ sku: art.sku, amount: 1 }],
}); shipping: { carrierId: testCarrier.id, type: 'parcel', state: 'shipped' },
await store.shipping.create(googleAuthId, {
manifestId: shipment4.id,
type: 'parcel',
state: 'shipped',
}); });
console.log('Orders created successfully.'); console.log('Orders created successfully.');

View File

@@ -118,13 +118,9 @@ async function run() {
{ sku: trackedArt.sku, amount: 3 }, { sku: trackedArt.sku, amount: 3 },
{ sku: untrackedArt.sku, amount: 2 }, { sku: untrackedArt.sku, amount: 2 },
], ],
shipping: { carrierId: carrier.id, type: 'parcel', state: 'open' },
}); });
const shippingOpen = await store.shipping.create(googleAuthId, { const shippingOpen = shipment.shippings[0];
manifestId: shipment.id,
carrierId: carrier.id,
type: 'parcel',
state: 'open',
});
assert.equal(shippingOpen.state, 'open'); assert.equal(shippingOpen.state, 'open');
// Assert stock is still 10 // Assert stock is still 10
@@ -191,6 +187,7 @@ async function run() {
number: 'O-HIST-001', number: 'O-HIST-001',
date: historicalDate, date: historicalDate,
createdAt: historicalDate, createdAt: historicalDate,
entityId: customer.id,
lines: [{ sku: trackedArt.sku, amount: 1, net: 10, taxrate: 19 }], lines: [{ sku: trackedArt.sku, amount: 1, net: 10, taxrate: 19 }],
}); });
const histWithOld = await store.article.getHistoryBySku(googleAuthId, trackedArt.sku); const histWithOld = await store.article.getHistoryBySku(googleAuthId, trackedArt.sku);
@@ -253,14 +250,9 @@ async function run() {
const shipment2 = await store.shipment.create(googleAuthId, { const shipment2 = await store.shipment.create(googleAuthId, {
orderId: order2.id, orderId: order2.id,
lines: [{ sku: trackedArt.sku, amount: 2 }], lines: [{ sku: trackedArt.sku, amount: 2 }],
shipping: { carrierId: carrier.id, type: 'parcel', state: 'shipped' },
}); });
const directShipped = shipment2.shippings[0];
const directShipped = await store.shipping.create(googleAuthId, {
manifestId: shipment2.id,
carrierId: carrier.id,
type: 'parcel',
state: 'shipped',
});
assert.equal(directShipped.state, 'shipped'); assert.equal(directShipped.state, 'shipped');
const artFinal = await store.article.getBySku(googleAuthId, trackedArt.sku); const artFinal = await store.article.getBySku(googleAuthId, trackedArt.sku);

View File

@@ -84,8 +84,26 @@ async function run() {
assert.equal(order.number, 'AU-1001'); assert.equal(order.number, 'AU-1001');
console.log('Order created:', order.number); console.log('Order created:', order.number);
const carrier = await store.carrier.create(googleAuthId, {
name: 'DHL',
hasPackages: true,
isReverse: false,
});
assert.equal(carrier.name, 'DHL');
assert.equal(carrier.hasPackages, true);
assert.equal(carrier.isReverse, false);
const shipping = { carrierId: carrier.id, type: 'parcel', state: 'draft' };
// 0. Shipment without shipping is rejected
await assert.rejects(
() => store.shipment.create(googleAuthId, { orderId: order.id, lines: [{ sku: 'ITEM-A', amount: 1 }] }),
{ message: 'Shipping is required' },
);
console.log('PASS: Shipment without shipping rejected');
// 1. Create Shipment 1: 6x Item A, 3x Item B -> AU-1001-L-1 // 1. Create Shipment 1: 6x Item A, 3x Item B -> AU-1001-L-1
const shipment1 = await store.shipment.create(googleAuthId, { const shipment1 = await store.shipment.create(googleAuthId, {
shipping,
orderId: order.id, orderId: order.id,
lines: [ lines: [
{ sku: 'ITEM-A', amount: 6 }, { sku: 'ITEM-A', amount: 6 },
@@ -100,6 +118,7 @@ async function run() {
let ceilingErrorThrown = false; let ceilingErrorThrown = false;
try { try {
await store.shipment.create(googleAuthId, { await store.shipment.create(googleAuthId, {
shipping,
orderId: order.id, orderId: order.id,
lines: [{ sku: 'ITEM-A', amount: 5 }], lines: [{ sku: 'ITEM-A', amount: 5 }],
}); });
@@ -114,6 +133,7 @@ async function run() {
let foreignArticleErrorThrown = false; let foreignArticleErrorThrown = false;
try { try {
await store.shipment.create(googleAuthId, { await store.shipment.create(googleAuthId, {
shipping,
orderId: order.id, orderId: order.id,
lines: [{ sku: 'ITEM-UNKNOWN', amount: 1 }], lines: [{ sku: 'ITEM-UNKNOWN', amount: 1 }],
}); });
@@ -126,6 +146,7 @@ async function run() {
// 3. Create Shipment 2: 4x Item A, 2x Item B -> AU-1001-L-2 // 3. Create Shipment 2: 4x Item A, 2x Item B -> AU-1001-L-2
const shipment2 = await store.shipment.create(googleAuthId, { const shipment2 = await store.shipment.create(googleAuthId, {
shipping,
orderId: order.id, orderId: order.id,
lines: [ lines: [
{ sku: 'ITEM-A', amount: 4 }, { sku: 'ITEM-A', amount: 4 },
@@ -140,6 +161,7 @@ async function run() {
let exhaustedErrorThrown = false; let exhaustedErrorThrown = false;
try { try {
await store.shipment.create(googleAuthId, { await store.shipment.create(googleAuthId, {
shipping,
orderId: order.id, orderId: order.id,
lines: [{ sku: 'ITEM-A', amount: 1 }], lines: [{ sku: 'ITEM-A', amount: 1 }],
}); });
@@ -150,16 +172,7 @@ async function run() {
} }
assert.ok(exhaustedErrorThrown, 'Expected exhausted error to be thrown'); assert.ok(exhaustedErrorThrown, 'Expected exhausted error to be thrown');
// 5. Add packages to Shipment 1 with tracking codes and carrier // 5. Add further packages to Shipment 1 with tracking codes
const carrier = await store.carrier.create(googleAuthId, {
name: 'DHL',
hasPackages: true,
isReverse: false,
});
assert.equal(carrier.name, 'DHL');
assert.equal(carrier.hasPackages, true);
assert.equal(carrier.isReverse, false);
const pkg1 = await store.shipping.create(googleAuthId, { const pkg1 = await store.shipping.create(googleAuthId, {
manifestId: shipment1.id, manifestId: shipment1.id,
carrierId: carrier.id, carrierId: carrier.id,
@@ -194,13 +207,13 @@ async function run() {
// Check listByOrderId // Check listByOrderId
const orderShipments = await store.shipment.listByOrderId(googleAuthId, order.id); const orderShipments = await store.shipment.listByOrderId(googleAuthId, order.id);
assert.equal(orderShipments.length, 2); assert.equal(orderShipments.length, 2);
assert.equal(orderShipments[0].shippings.length, 2); assert.equal(orderShipments[0].shippings.length, 3);
console.log('PASS: store.shipment.listByOrderId returned both shipments'); console.log('PASS: store.shipment.listByOrderId returned both shipments');
// Check getById // Check getById
const fetchedShipment1 = await store.shipment.getById(googleAuthId, shipment1.id); const fetchedShipment1 = await store.shipment.getById(googleAuthId, shipment1.id);
assert.equal(fetchedShipment1.id, shipment1.id); assert.equal(fetchedShipment1.id, shipment1.id);
assert.equal(fetchedShipment1.shippings.length, 2); assert.equal(fetchedShipment1.shippings.length, 3);
console.log('PASS: store.shipment.getById returned shipment with shippings'); console.log('PASS: store.shipment.getById returned shipment with shippings');
// 6. Transition Package 1 to shipped (should deduct ledger stock for Shipment 1 lines: 6 of Item A, 3 of Item B) // 6. Transition Package 1 to shipped (should deduct ledger stock for Shipment 1 lines: 6 of Item A, 3 of Item B)
@@ -253,6 +266,7 @@ async function run() {
// 9a. Ship ONE item (3x ITEM-A) via store.order.createShipment // 9a. Ship ONE item (3x ITEM-A) via store.order.createShipment
const shOne = await store.order.createShipment(googleAuthId, order2.id, { const shOne = await store.order.createShipment(googleAuthId, order2.id, {
shipping,
lines: [{ sku: 'ITEM-A', amount: 3 }], lines: [{ sku: 'ITEM-A', amount: 3 }],
}); });
assert.equal(shOne.number, 'AU-1002-L-1'); assert.equal(shOne.number, 'AU-1002-L-1');
@@ -268,6 +282,7 @@ async function run() {
// 9b. Ship SOME items with omitted amount (e.g. ITEM-A with no amount -> defaults to remaining 7) // 9b. Ship SOME items with omitted amount (e.g. ITEM-A with no amount -> defaults to remaining 7)
const shSome = await store.order.createShipment(googleAuthId, order2.id, { const shSome = await store.order.createShipment(googleAuthId, order2.id, {
shipping,
lines: [{ sku: 'ITEM-A' }], lines: [{ sku: 'ITEM-A' }],
}); });
assert.equal(shSome.number, 'AU-1002-L-2'); assert.equal(shSome.number, 'AU-1002-L-2');
@@ -282,7 +297,7 @@ async function run() {
console.log('PASS: 9b. Shipped SOME items with omitted amount; ordersummary updated with shipped_quantity=10, is_shipped=0'); console.log('PASS: 9b. Shipped SOME items with omitted amount; ordersummary updated with shipped_quantity=10, is_shipped=0');
// 9c. Ship remaining items with explicit lines // 9c. Ship remaining items with explicit lines
const shAll = await store.order.createShipment(googleAuthId, order2.id, { lines: [{ sku: 'ITEM-B', amount: 5 }] }); const shAll = await store.order.createShipment(googleAuthId, order2.id, { shipping, lines: [{ sku: 'ITEM-B', amount: 5 }] });
assert.equal(shAll.number, 'AU-1002-L-3'); assert.equal(shAll.number, 'AU-1002-L-3');
assert.equal(shAll.lines.length, 1); assert.equal(shAll.lines.length, 1);
assert.equal(shAll.lines[0].sku, 'ITEM-B'); assert.equal(shAll.lines[0].sku, 'ITEM-B');

View File

@@ -13,11 +13,12 @@ export default function createShipment(provider) {
* @param {Array<{sku: string, amount?: number, name?: string, pu?: number, net?: number, rebate?: number, taxrate?: number, comment?: string}>} input.lines - Positions to ship. * @param {Array<{sku: string, amount?: number, name?: string, pu?: number, net?: number, rebate?: number, taxrate?: number, comment?: string}>} input.lines - Positions to ship.
* @param {string|Date} [input.date] - Optional shipment date. * @param {string|Date} [input.date] - Optional shipment date.
* @param {string} [input.externalNumber] - Optional external delivery reference. * @param {string} [input.externalNumber] - Optional external delivery reference.
* @param {object} input.shipping - Required shipping ({carrierId, type, state, trackingCode?, warehouseId?}); see shipment.create.
* @param {object} [tx] - Optional transaction. * @param {object} [tx] - Optional transaction.
* @returns {Promise<object>} The created shipment. * @returns {Promise<object>} The created shipment.
* *
* @example * @example
* const shipment = await store.order.createShipment(googleAuthId, 10, { lines: [{ sku: 'ITEM-A', amount: 5 }] }); * const shipment = await store.order.createShipment(googleAuthId, 10, { lines: [{ sku: 'ITEM-A', amount: 5 }], shipping: { carrierId: 1, type: 'parcel', state: 'draft' } });
*/ */
return async (googleAuthId, orderId, input = {}, tx) => { return async (googleAuthId, orderId, input = {}, tx) => {
return create(googleAuthId, { ...input, orderId }, tx); return create(googleAuthId, { ...input, orderId }, tx);

View File

@@ -3,6 +3,7 @@ import taxEnsure from '../tax/ensure.js';
import { insertLines, parseDate } from '../manifestLines.js'; import { insertLines, parseDate } from '../manifestLines.js';
import { assertUniqueManifestNumber } from '../manifestDoc/helpers.js'; import { assertUniqueManifestNumber } from '../manifestDoc/helpers.js';
import makeRunner from '../runner.js'; import makeRunner from '../runner.js';
import shippingCreate from '../shipping/create.js';
import { loadShipment, queriesFor } from './helpers.js'; import { loadShipment, queriesFor } from './helpers.js';
import { syncOrderSummary } from '../order/syncSummary.js'; import { syncOrderSummary } from '../order/syncSummary.js';
import { syncShipmentSummary } from './syncSummary.js'; import { syncShipmentSummary } from './syncSummary.js';
@@ -24,6 +25,7 @@ function requireId(val, name) {
export default function create(provider) { export default function create(provider) {
const access = resolveSelectedCompanyAccess(provider); const access = resolveSelectedCompanyAccess(provider);
const ensureTax = taxEnsure(provider); const ensureTax = taxEnsure(provider);
const createShipping = shippingCreate(provider);
const q = queriesFor(provider); const q = queriesFor(provider);
/** /**
@@ -37,14 +39,21 @@ export default function create(provider) {
* @param {string|Date} [input.date] - Optional shipment date (defaults to current date). * @param {string|Date} [input.date] - Optional shipment date (defaults to current date).
* @param {'new'|'delivered'|'returned'} [input.state='new'] - Optional delivery state (defaults to 'new'). * @param {'new'|'delivered'|'returned'} [input.state='new'] - Optional delivery state (defaults to 'new').
* @param {string} [input.externalNumber] - Optional external delivery note number (defaults to order.externalNumber or order.number). * @param {string} [input.externalNumber] - Optional external delivery note number (defaults to order.externalNumber or order.number).
* @param {object} input.shipping - Required shipping (package) created atomically with the shipment, so a shipment never exists without a carrier.
* @param {number} input.shipping.carrierId - The carrier id.
* @param {string} input.shipping.type - Shipping type.
* @param {string} input.shipping.state - Shipping state ('shipped' or other).
* @param {string} [input.shipping.trackingCode] - Carrier tracking code.
* @param {number} [input.shipping.warehouseId] - Optional warehouse ID for stock deduction when state is 'shipped'.
* @param {object} [tx] - Optional transaction. * @param {object} [tx] - Optional transaction.
* @returns {Promise<object>} The created shipment manifest. * @returns {Promise<object>} The created shipment manifest.
* @throws {Error} If order not found, invalid lines, or article ceiling invariant exceeded. * @throws {Error} If order not found, invalid lines, shipping/carrier missing or invalid, or article ceiling invariant exceeded.
* *
* @example * @example
* const shipment = await store.shipment.create(googleAuthId, { * const shipment = await store.shipment.create(googleAuthId, {
* orderId: 10, * orderId: 10,
* lines: [{ sku: 'ITEM-A', amount: 5 }] * lines: [{ sku: 'ITEM-A', amount: 5 }],
* shipping: { carrierId: 1, type: 'parcel', state: 'draft' }
* }); * });
*/ */
return async (googleAuthId, input = {}, tx) => { return async (googleAuthId, input = {}, tx) => {
@@ -54,6 +63,11 @@ export default function create(provider) {
throw new Error('Invalid lines'); throw new Error('Invalid lines');
} }
if (!input.shipping || typeof input.shipping !== 'object') {
throw new Error('Shipping is required');
}
requireId(input.shipping.carrierId, 'Carrier');
const shipmentDate = parseDate(input.date) || new Date(); const shipmentDate = parseDate(input.date) || new Date();
const run = async (runner, innerTx) => { const run = async (runner, innerTx) => {
@@ -289,6 +303,9 @@ export default function create(provider) {
state: validState, state: validState,
}); });
// 10. Create the shipping (carrier) atomically with the shipment
await createShipping(googleAuthId, { ...input.shipping, manifestId }, innerTx);
return loadShipment(runner, q, companyId, manifestId); return loadShipment(runner, q, companyId, manifestId);
}; };