rerobe-js-orm 4.9.8 → 4.9.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -742,16 +742,30 @@ class OrderHelpers {
742
742
  fractionDigits: 2,
743
743
  }),
744
744
  refundLineItems: (order.refunds || []).flatMap((refund) => (refund.refundLineItems || []).map((item) => {
745
- var _a, _b;
746
- return ({
747
- title: item.title || '',
748
- quantity: item.quantity || 1,
745
+ var _a, _b, _c, _d, _e, _f, _g, _h;
746
+ // A stored RefundLineItem is { lineItem, quantityRefund,
747
+ // quantityCancel, subtotalRefund(Presentment), subtotalCanceled(
748
+ // Presentment) } — the title/amount live on `lineItem`, not flat on
749
+ // the item. Returned units = refunded + canceled (a cancellation of
750
+ // unfulfilled units still returns money). The subtotals are net of
751
+ // tax (originalUnitPrice basis), so gross them up for the receipt.
752
+ const lineItem = item.lineItem || {};
753
+ const quantity = Number(item.quantityRefund || 0) + Number(item.quantityCancel || 0);
754
+ const net = Number((_d = (_b = (_a = item.subtotalRefundPresentment) === null || _a === void 0 ? void 0 : _a.amount) !== null && _b !== void 0 ? _b : (_c = item.subtotalRefund) === null || _c === void 0 ? void 0 : _c.amount) !== null && _d !== void 0 ? _d : 0) +
755
+ Number((_h = (_f = (_e = item.subtotalCanceledPresentment) === null || _e === void 0 ? void 0 : _e.amount) !== null && _f !== void 0 ? _f : (_g = item.subtotalCanceled) === null || _g === void 0 ? void 0 : _g.amount) !== null && _h !== void 0 ? _h : 0);
756
+ const taxRate = Number(lineItem.taxRate || 0);
757
+ const gross = lineItem.isTaxable && taxRate ? net * (1 + taxRate) : net;
758
+ return {
759
+ title: (0, MarketplaceLineDisplayHelpers_1.formatMarketplaceLineDisplayTitle)({ lineItem }, { includeSellerPrefix: includeMarketplaceSellerPrefix }) ||
760
+ lineItem.title ||
761
+ '',
762
+ quantity,
749
763
  price: (0, Utilities_1.formatPrice)({
750
764
  currencyCode,
751
- amount: -Number(((_a = item.presentmentTotalPrice) === null || _a === void 0 ? void 0 : _a.amount) || ((_b = item.totalPrice) === null || _b === void 0 ? void 0 : _b.amount) || 0),
765
+ amount: -Math.abs(gross),
752
766
  fractionDigits: 2,
753
767
  }),
754
- });
768
+ };
755
769
  })),
756
770
  }));
757
771
  }
@@ -1,6 +1,16 @@
1
+ export type ReceiptPreviewLine = {
2
+ align: 'left' | 'center' | 'right';
3
+ bold: boolean;
4
+ size: number;
5
+ text: string;
6
+ cut?: boolean;
7
+ };
1
8
  export default class ReceiptXmlHelpers {
2
9
  static escapeXML(text: any): string;
3
10
  private static variantLabelForReceipt;
4
11
  static formatLineItemXML(lineItem: any): string;
5
12
  static buildReceiptContentXML(receiptData: any): string;
13
+ private static decodeXML;
14
+ private static parseAttrs;
15
+ static parseReceiptXml(xml: string): ReceiptPreviewLine[];
6
16
  }
@@ -231,5 +231,89 @@ class ReceiptXmlHelpers {
231
231
  receipt += '</epos-print>';
232
232
  return receipt;
233
233
  }
234
+ // Decode the 5 XML entities escapeXML produces, back to their characters.
235
+ // `&amp;` is decoded last so `&amp;lt;` round-trips to `&lt;`, not `<`.
236
+ static decodeXML(text) {
237
+ return String(text)
238
+ .replace(/&lt;/g, '<')
239
+ .replace(/&gt;/g, '>')
240
+ .replace(/&quot;/g, '"')
241
+ .replace(/&#39;/g, "'")
242
+ .replace(/&amp;/g, '&');
243
+ }
244
+ // Parse `attr="value"` pairs out of a tag's attribute string.
245
+ static parseAttrs(raw) {
246
+ const attrs = {};
247
+ const re = /(\w+)="([^"]*)"/g;
248
+ let m = re.exec(raw);
249
+ while (m) {
250
+ attrs[m[1]] = m[2];
251
+ m = re.exec(raw);
252
+ }
253
+ return attrs;
254
+ }
255
+ // Inverse of buildReceiptContentXML for PREVIEW rendering: turn the exact
256
+ // ePOS-Print XML the printer receives into an ordered list of styled lines, so
257
+ // a simulator can render byte-for-byte what will print without re-deriving the
258
+ // layout from raw receipt fields (which silently drifts when a field is added).
259
+ //
260
+ // ePOS-Print printer state (align, double width/height, emphasis) is sticky —
261
+ // it persists across <text> elements until changed — so we carry it forward.
262
+ // <feed/> ends a line; <cut/> is emitted as a cut marker. Spaces are preserved
263
+ // verbatim (line items pad to a fixed column width), so render with a
264
+ // fixed-width font and white-space: pre to reproduce the columns.
265
+ //
266
+ // Returns styled lines ({ align, bold, size (1|2), text, cut? }) in print order.
267
+ static parseReceiptXml(xml) {
268
+ const lines = [];
269
+ if (!xml)
270
+ return lines;
271
+ // Sticky printer state.
272
+ let align = 'left';
273
+ let bold = false;
274
+ let size = 1;
275
+ // Current line buffer (reflects the state at the time text was appended).
276
+ let buf = '';
277
+ let hasText = false;
278
+ const flush = () => {
279
+ lines.push({ align, bold, size, text: buf });
280
+ buf = '';
281
+ hasText = false;
282
+ };
283
+ const tokenRe = /<text\b([^>]*?)\/>|<text\b([^>]*)>([\s\S]*?)<\/text>|<feed\s*\/>|<cut\b[^>]*?\/>/g;
284
+ let t = tokenRe.exec(xml);
285
+ while (t) {
286
+ const whole = t[0];
287
+ if (whole.indexOf('<feed') === 0) {
288
+ flush();
289
+ }
290
+ else if (whole.indexOf('<cut') === 0) {
291
+ if (hasText || buf)
292
+ flush();
293
+ lines.push({ align: 'center', bold: false, size: 1, text: '', cut: true });
294
+ }
295
+ else {
296
+ // A <text> element: self-closing (state only) or with content.
297
+ const selfClosing = t[1] !== undefined;
298
+ const attrs = this.parseAttrs(selfClosing ? t[1] : t[2]);
299
+ if (attrs.align === 'left' || attrs.align === 'center' || attrs.align === 'right') {
300
+ align = attrs.align;
301
+ }
302
+ if (attrs.width)
303
+ size = parseInt(attrs.width, 10) >= 2 ? 2 : 1;
304
+ if (attrs.em !== undefined)
305
+ bold = attrs.em === 'true';
306
+ if (!selfClosing && t[3]) {
307
+ buf += this.decodeXML(t[3]);
308
+ hasText = true;
309
+ }
310
+ }
311
+ t = tokenRe.exec(xml);
312
+ }
313
+ // Trailing content with no closing <feed/>.
314
+ if (hasText || buf)
315
+ flush();
316
+ return lines;
317
+ }
234
318
  }
235
319
  exports.default = ReceiptXmlHelpers;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rerobe-js-orm",
3
- "version": "4.9.8",
3
+ "version": "4.9.10",
4
4
  "description": "ReRobe's Javascript ORM Framework",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",