122 lines
4.6 KiB
JavaScript
122 lines
4.6 KiB
JavaScript
import { http, clientIdHeaders } from './http.js';
|
|
|
|
/**
|
|
* Company-scoped goods receipts (manifest type = delivery).
|
|
* DeliverySummary = { id, number, externalNumber, type: 'delivery', supplierId, date }
|
|
* - number: server-allocated, read-only manifest number (from nextNumber('delivery')).
|
|
* - externalNumber: user-entered reference (nullable).
|
|
* DeliveryLine = { id, articleId, sku, amount, net, transactedAmount, rebate, tax, comment }
|
|
* Delivery = DeliverySummary & { lines: DeliveryLine[] }
|
|
* DeliveryLineInput = { sku, amount, net, tax, rebate?, transactedAmount?, comment? }
|
|
*/
|
|
export const delivery = {
|
|
/**
|
|
* GET /api/delivery
|
|
* @param {{ offset?: number, limit?: number, search?: string, onlyUnbooked?: boolean, supplierId?: number, seekMonths?: number }} [opts]
|
|
* → { deliveries: DeliverySummary[], total?: number, unfilteredTotal?: number, offset?: number, limit?: number }
|
|
*/
|
|
// #region GET /api/delivery — list
|
|
list(opts) {
|
|
if (opts && typeof opts === 'object') {
|
|
const params = new URLSearchParams();
|
|
if (opts.offset != null) params.set('offset', String(Math.max(0, Math.floor(Number(opts.offset) || 0))));
|
|
if (opts.limit != null) params.set('limit', String(Math.max(1, Math.floor(Number(opts.limit) || 50))));
|
|
if (opts.search && String(opts.search).trim()) params.set('search', String(opts.search).trim());
|
|
if (opts.onlyUnbooked === true || opts.onlyUnbooked === 'true') params.set('onlyUnbooked', 'true');
|
|
if (opts.supplierId != null) params.set('supplierId', String(opts.supplierId));
|
|
if (opts.seekMonths != null && Number(opts.seekMonths) < 0) {
|
|
params.set('seekMonths', String(Math.floor(Number(opts.seekMonths))));
|
|
}
|
|
const qs = params.toString();
|
|
return http(`/api/delivery${qs ? `?${qs}` : ''}`);
|
|
}
|
|
return http('/api/delivery');
|
|
},
|
|
// #endregion
|
|
|
|
/** POST /api/delivery/rebuild-summaries → { ok: boolean, companyId: number } */
|
|
rebuildSummaries() {
|
|
return http('/api/delivery/rebuild-summaries', { method: 'POST' });
|
|
},
|
|
|
|
/** GET /api/delivery/:id → { delivery: Delivery } */
|
|
// #region GET /api/delivery/:id — get
|
|
get(id) {
|
|
return http(`/api/delivery/${id}`);
|
|
},
|
|
// #endregion
|
|
|
|
/**
|
|
* POST /api/delivery
|
|
* Body: { externalNumber?, date, supplierId?, lines: DeliveryLineInput[] }
|
|
* number is NOT sent — the server allocates it automatically. The
|
|
* caller-supplied reference goes in externalNumber (nullable).
|
|
* Line requires sku, amount, net, tax. rebate→0, transactedAmount→amount.
|
|
* → 201 { delivery: Delivery }
|
|
*/
|
|
// #region POST /api/delivery — create
|
|
create(body) {
|
|
return http('/api/delivery', { method: 'POST', body });
|
|
},
|
|
// #endregion
|
|
|
|
/**
|
|
* PATCH /api/delivery/:id
|
|
* Body: partial { externalNumber?, date?, supplierId?, lines? }.
|
|
* number is read-only and cannot be edited. externalNumber is editable and
|
|
* can be cleared by sending null or an empty string.
|
|
* If lines present, replaces all lines; if omitted, lines unchanged.
|
|
* → 200 { delivery: Delivery }
|
|
*/
|
|
// #region PATCH /api/delivery/:id — update
|
|
update(id, body) {
|
|
return http(`/api/delivery/${id}`, { method: 'PATCH', body });
|
|
},
|
|
// #endregion
|
|
|
|
/** DELETE /api/delivery/:id → 204 */
|
|
// #region DELETE /api/delivery/:id — delete
|
|
delete(id) {
|
|
return http(`/api/delivery/${id}`, { method: 'DELETE' });
|
|
},
|
|
// #endregion
|
|
|
|
/**
|
|
* GET /api/delivery/:id/file/:fileId → Blob
|
|
* Full binary content of attached file (PDF, text, etc.)
|
|
*/
|
|
// #region GET /api/delivery/:id/file/:fileId — getFile
|
|
async getFile(id, fileId, { download = false } = {}) {
|
|
const query = download ? '?download=true' : '';
|
|
const res = await fetch(`/api/delivery/${encodeURIComponent(id)}/file/${encodeURIComponent(fileId)}${query}`, {
|
|
method: 'GET',
|
|
credentials: 'include',
|
|
});
|
|
if (!res.ok) {
|
|
let message = res.statusText;
|
|
try {
|
|
const data = await res.json();
|
|
message = data.error || data.message || message;
|
|
} catch { /* ignore */ }
|
|
const err = new Error(message || `Request failed (${res.status})`);
|
|
err.status = res.status;
|
|
throw err;
|
|
}
|
|
return res.blob();
|
|
},
|
|
// #endregion
|
|
|
|
/**
|
|
* DELETE /api/delivery/:id/file/:fileId
|
|
* Deletes delivery file attachment.
|
|
* @param {number|string} id Delivery ID
|
|
* @param {number|string} fileId File ID
|
|
* → 204 void
|
|
*/
|
|
// #region DELETE /api/delivery/:id/file/:fileId — deleteFile
|
|
deleteFile(id, fileId) {
|
|
return http(`/api/delivery/${id}/file/${fileId}`, { method: 'DELETE' });
|
|
},
|
|
// #endregion
|
|
};
|