# Receipt Objects ## Sample receipt object This is an example of the data `global.apis.pos.onReceiptChange` and `global.apis.pos.onTransactionFinished` send to plugins. All data for a PostalPoint transaction is available in its receipt object. The money-related properties near the bottom of this sample are generated by PostalPoint from the items and payments. ### Notes: * The `due` property will be a negative number if change is owed to the customer. * `pendingEmailTo` is set to a suggested email address for the email receipt, and if the receipt should actually be emailed, it will be set in `emailTo`. * `uuid` is a unique 16-character alphanumeric receipt ID number, which is shown and used in several places. The `uuid` is generated using `global.apis.util.uuid.short()`. * `customerAccountId` is the UUID for the customer's account, or null if there isn't a customer attached. * This example happens to be the object used when test printing a receipt from the PostalPoint settings menu, so press that button to see what this is rendered into. ```javascript { "items": [ ReceiptItem.fromJSON({ "id": "9100123456789012345678", "label": "Test Package", "text": "Package Details\nTracking # 9100 1234 5678 9012 3456 78\nTo:\nTEST PERSON\nORGANIZATION INC\n123 TEST ROAD\nTESTTOWN TE 99999-0001", "priceEach": 8, "qty": 1, "cost": 0, "retail": 8, "taxRate": 0, "free": false, "barcode": "9100123456789012345678", "certifiedInfo": false, "isMerch": false, "surcharge": false, "toAddress": { "name": "TEST PERSON", "company": "ORGANIZATION INC", "street1": "123 TEST ROAD", "street2": null, "city": "TESTTOWN", "state": "TE", "zip": "99999-0001", "email": null, "phone": null, "country": "US" }, "fromAddress": { "name": "TEST PERSON", "company": "ORGANIZATION INC", "street1": "123 TEST ROAD", "street2": null, "city": "TESTTOWN", "state": "TE", "zip": "99999-0001", "email": null, "phone": null, "country": "US" } }), ReceiptItem.fromJSON({ "id": "testitem", "label": "Test Item", "text": "", "priceEach": 2, "qty": 1, "cost": 0, "retail": 2, "taxRate": 0.1, "free": false, "barcode": "", "certifiedInfo": false, "isMerch": true, "surcharge": false }) ], "payments": [ ReceiptPayment.fromJSON({ "amount": 10, "type": "cash", "text": "", "id": "testcash" }) ], "subtotal": 10, "subtotalFormatted": "$10.00", "tax": 0.2, "taxFormatted": "$0.20", "grandTotal": 10.2, "grandTotalFormatted": "$10.20", "paid": 10.2, "paidFormatted": "$10.20", "due": 0, "dueFormatted": "$0.00", "emailTo": null, "pendingEmailTo": null, "uuid": "1234567890abcdef", "customerAccountId": null, "topTextHTML": "", "bottomTextHTML": "" } ``` ## global.apis.pos.ReceiptItem ```javascript export class ReceiptItem { /** * * @param {string|number} id Unique ID number for this item (UPC code, inventory number, etc). Used to deduplicate line items. Unique items (like shipping labels) should be random or empty. * @param {string} label One-line item information. * @param {string} text Extra item information. * @param {number} priceEach Price per unit * @param {number} quantity Number of units * @param {number} cost Cost per unit. Used for automatic expense tracking. * @param {number} taxrate Examples: 0 (for 0%), 0.05 (for 5%), etc * @param {string} taxableAmount The part of the sale price that's taxable. "" for default (all), "markup" for only taxing profit. * @returns {ReceiptItem} */ constructor(id, label, text, priceEach, quantity, cost, taxrate = 0.0, taxableAmount = "") { this.id = id; this.label = label; if (text == null) { this.txt == ""; } else { this.txt = text; } this.priceEach = num(priceEach); this.qty = num(quantity); this.cost = num(cost); if (isNaN(taxrate)) { this.taxRate = 0; } else { this.taxRate = num(taxrate); } this.taxableAmount = taxableAmount; this.merch = false; this.merchid = null; this.surcharge = false; this.retail = 0; // For ensuring PostalPoint fee collection on office mode shipments this.mailboxNumber = null; this.mailboxDays = 0; this.mailboxMonths = 0; this.category = ""; // merch category this.electronicReturnReceipt = false; } static fromJSON(obj) { var item = new ReceiptItem(obj.id, obj.label, obj.text, obj.priceEach, obj.qty, obj.cost, obj.taxRate, obj.taxableAmount ?? ""); item.free = obj.free; item.barcode = obj.barcode; item.certifiedInfo = obj.certifiedInfo; item.toAddress = obj.toAddress; item.fromAddress = obj.fromAddress; item.merch = obj.isMerch == true || (typeof obj.merchid == "string" && obj.merchid.length > 0); item.merchid = obj.merchid ?? null; item.mailboxNumber = obj.mailboxNumber ?? null; item.mailboxDays = obj.mailboxDays ?? 0; item.mailboxMonths = obj.mailboxMonths ?? 0; item.surcharge = obj.surcharge; item.retailPrice = obj.retail; item.carrier = obj.carrier ?? null; item.service = obj.service ?? null; item.category = obj.category ?? ""; item.electronicReturnReceipt = obj.electronicReturnReceipt ?? false; return item; } toJSON() { return { id: this.id, label: this.label, text: this.text, priceEach: num(this.priceEach), qty: num(this.qty), cost: num(this.cost), retail: num(this.retail), taxRate: num(this.taxRate), taxableAmount: this.taxableAmount, taxTotal: this.taxAmount, free: this.free, barcode: this.barcode, certifiedInfo: this.certifiedInfo, isMerch: this.merch, merchid: this.merchid, surcharge: this.surcharge, toAddress: this.toAddress, fromAddress: this.fromAddress, mailboxNumber: this.mailboxNumber, mailboxDays: this.mailboxDays, mailboxMonths: this.mailboxMonths, carrier: this.carrier, service: this.service, category: this.category, electronicReturnReceipt: this.electronicReturnReceipt }; } get text() { if (typeof this.txt == "string") { return this.txt; } return ""; } set text(t) { if (typeof t == "string") { this.txt = t; } else { this.txt = ""; } } get certifiedInfo() { if (typeof this.certified == "undefined") { return false; } return this.certified; } set certifiedInfo(info) { this.certified = info; } setCertifiedInfo(tracking, certfee, extrafees, postage, date, location, toaddress) { this.certified = { tracking: tracking, certifiedFee: num(certfee), extraFees: extrafees, postage: num(postage), date: date, location: location, to: toaddress }; } setQuantity(q) { this.qty = num(q); } get free() { return this.isFree == true; } set free(free) { this.isFree = free == true; } get barcode() { if (typeof this.barcodeData != "string") { return ""; } return this.barcodeData; } set barcode(data) { this.barcodeData = data; } get linePrice() { return round(m(this.priceEach, this.qty), 2); } get priceEachFormatted() { return getCurrencySymbol() + round(num(this.priceEach), 2).toFixed(2); } get linePriceFormatted() { return getCurrencySymbol() + round(num(this.linePrice), 2).toFixed(2); } get texthtml() { if (typeof this.text != "string") { return ""; } var lines = this.text.split("\n"); for (var i = 0; i < lines.length; i++) { if (lines[i].startsWith("Tracking # ")) { // Allow copying tracking number lines[i] = "Tracking # " + lines[i].replace("Tracking # ", "") + ""; } } return lines.join("
"); } get taxAmount() { if (this.taxableAmount == "markup") { var lineCost = m(this.cost, this.qty); var margin = s(this.linePrice, lineCost); if (margin <= 0) { return 0; } return round(m(margin, this.taxRate), 2); } else { return round(m(this.linePrice, this.taxRate), 2); } } get retailPrice() { if (typeof this.retail == "number") { return this.retail; } return this.priceEach * this.qty; } set retailPrice(price) { this.retail = num(price); } } ``` ## global.apis.pos.ReceiptPayment ```javascript export class ReceiptPayment { /** * * @param {number} amount amount paid * @param {string} type payment type * @param {string} text extra data (credit card info, etc) * @returns {ReceiptPayment} */ constructor(amount, type, text) { this.id = (Math.random() * 100000000) + "_" + type + "_" + amount; this.text = (typeof text != "string" ? "" : text); this.type = type; this.amount = amount; } static fromJSON(obj) { var item = new ReceiptPayment(obj.amount, obj.type, obj.text); item.id = obj.id; return item; } toJSON() { return { amount: round(this.amount, 2), type: this.type, text: this.text, id: this.id }; } get texthtml() { if (typeof this.text != "string") { return ""; } return this.text.replaceAll("\n", "
"); } get amountFormatted() { return getCurrencySymbol() + this.amount.toFixed(2); } get label() { if (typeof this.type != "string") { return "Payment"; } switch (this.type) { case "cash": return "Cash"; case "check": return "Check"; case "card": return "Card"; case "card_manual": return "Card"; case "account": return "Account"; case "free": return "Free"; case "discount": return "Discount"; case "crypto": return "Cryptocurrency"; case "ach": return "ACH Debit"; case "rounding": return "Cash Rounding"; // Used in penniless countries to balance a cash-only transaction default: return this.type; } } } ```