Skip to content

Instantly share code, notes, and snippets.

@ANNASBlackHat
Created February 12, 2024 09:32
Show Gist options
  • Save ANNASBlackHat/9d7e4d454380e71b7749112c819825f7 to your computer and use it in GitHub Desktop.
Save ANNASBlackHat/9d7e4d454380e71b7749112c819825f7 to your computer and use it in GitHub Desktop.
Receipt Note Format
import 'dart:core';
import 'package:intl/intl.dart';
void main() {
// Create dummy data
SalesEntity sales = dummySales();
Outlet outlet = dummyOutlet();
Employee employee = Employee(
name: 'Jane Doe',
);
var notaFormat = getPrintNotaFormat(sales, outlet, employee);
print(notaFormat);
}
String getPrintNotaFormat(SalesEntity sales, Outlet outlet, Employee employee,
{bool isBill = false,
int paperSize = 58,
bool isReprint = false,
String language = "id"}) {
StringBuffer teks = StringBuffer();
StringBuffer header = StringBuffer('[CUT]\n');
int MAX = getMaxCharacter(paperSize);
try {
header.writeln(outlet.name.trim().center(MAX));
header.writeln(outlet.receiptAddress?.trim()?.center(MAX));
if (outlet.receiptPhone != null) {
header.writeln(outlet.receiptPhone!.trim().center(MAX));
}
header.writeln("=" * MAX);
String paymentDetail = sales.payments.first.bank.name != null
? "(${sales.payments.first.bank.name})"
: "";
if (sales.salesTag != null) {
SalesTagEntity tag = sales.salesTag!;
teks.writeln("#${tag.name.toUpperCase()}");
}
ReceiptText lng = receiptLanguage(language);
teks.writeln("${lng.receiptNumber} : ${sales.displayNota}".padRight(MAX));
teks.writeln("${lng.customer} : ${sales.customer}".padRight(MAX));
teks.writeln(
"${lng.date} : ${sales.timeCreated.dateTimeFormat()}".padRight(MAX));
teks.writeln("${lng.cashier} : ${employee.name}".padRight(MAX));
teks.writeln(
"${lng.payment} : ${sales.payment} $paymentDetail".padRight(MAX));
if (sales.table.isNotEmpty) {
teks.writeln("${lng.table} : ${sales.table}".padRight(MAX));
}
String? voucherCode;
if (sales.promotions.isNotEmpty) {
voucherCode = sales.promotions.first.displayVoucher;
}
if (voucherCode != null) {
teks.writeln("Voucher: ${voucherCode.padRight(MAX)}");
}
teks.writeln("\n\n");
int disc = 0;
sales.orderList.sort((a, b) {
return a.product.productId.compareTo(b.product.productId);
});
sales.orderList.forEach((Order orders) {
double total = 0;
int promoItemValue = orders.promotion?.promotionValue ?? 0;
if (sales.status == "Refund") {
orders.qty = orders.qty * -1;
orders.subTotal = orders.subTotal * -1;
}
total += orders.subTotal;
String name;
if (orders.isItemVoid) {
name = "VOID: ${orders.product.name}";
} else {
name = orders.product.name ?? '';
}
teks.write(name.padRight(MAX - 4 - 8));
teks.write(orders.qty.toString().center(4));
teks.writeln((orders.subTotal + promoItemValue).toCurrency().padLeft(8));
orders.extra.forEach((Order extra) {
String name;
if (orders.isItemVoid) {
name = "-VOID: ${extra.product.name}";
} else {
name = "-${extra.product.name}";
}
teks.write(name.padRight(MAX - 4 - 8));
teks.write(extra.qty.toString().width(4));
teks.writeln(extra.subTotal.toCurrency().padLeft(8));
total += extra.subTotal;
});
// Print promotion details
if (orders.discount.discountNominal != 0) {
disc += orders.discount.discountNominal;
String txtDisc = "-Discount";
if (orders.discount.discountType == Constant.TYPE_PERCENT) {
txtDisc = "-Discount (${orders.discount.discount}%)";
}
teks
..write(txtDisc.padRight(MAX - 8))
..writeln(
("-${orders.discount.discountNominal.toCurrency()}").padLeft(8))
..writeln("( ${orders.discount.discountInfo} )".padRight(MAX));
}
if (!isBill && orders.note != null) {
teks.writeln(orders.note!.widthRight(MAX));
}
});
int extrasSubtotal = 0;
var extras = sales.orderList.expand((order) => order.extra).cast<Order>();
if (extras.isNotEmpty) {
extrasSubtotal = extras.map((e) => e.subTotal).reduce((a, b) => a + b);
}
var orderListSubtotal =
sales.orderList.map((order) => order.subTotal).reduce((a, b) => a + b);
var subtotal = orderListSubtotal + extrasSubtotal - disc;
// Print divider
teks.writeln('-' * MAX);
// Print subtotal
teks
..write('Total'.padRight(MAX - 13))
..writeln(subtotal.toCurrency().padLeft(13));
// Print discounts
if (sales.discount != null) {
var discount = sales.discount!;
if (discount.discount > 0) {
teks
..write('Discount'.padRight(MAX - 13))
..writeln(discount.discountNominal.toCurrency().padLeft(13));
}
if (discount.voucher > 0) {
var voucher = discount.voucherNominal;
if (voucher == 0) {
discount.voucher;
}
teks
..write('Voucher'.padRight(MAX - 13))
..writeln((voucher).toCurrency().padLeft(13));
}
}
// Print promotions
sales.promotions.forEach((promo) {
teks
..write(promo.name?.padRight(MAX - 13))
..writeln(promo.promotionValue.toCurrency().padLeft(13));
});
// Print taxes
sales.taxes?.where((tax) => tax.total > 0).forEach((tax) {
teks
..write(tax.name?.padRight(MAX - 13))
..writeln(tax.total.toCurrency().padLeft(13));
});
teks.writeln();
// Print grand total
teks.writeln('Grand Total : '.padRight(MAX - 13) +
sales.grandTotal.toCurrency().padLeft(13));
int totalPay = 0;
sales.payments.forEach((payment) {
totalPay += payment.pay < 0 && payment.method.toLowerCase() == "piutang"
? -payment.pay
: payment.pay;
teks.writeln("${payment.method} : ".padRight(MAX - 13) +
payment.pay.toCurrency().padLeft(13));
});
if (!isBill) {
teks.writeln("${lng.change} : ".padRight(MAX - 13) +
(totalPay - sales.grandTotal).toCurrency().padLeft(13));
}
// Print discount & voucher info
if (sales.discount != null) {
var discount = sales.discount!;
if (discount.discount > 0) {
teks.writeln("Ket. Disc: ${discount.discountInfo?.trim()}");
}
if (discount.voucher > 0) {
teks.writeln("Ket. Voucher: ${discount.voucherInfo?.trim()}");
}
}
// Print bill header
if (isBill) {
teks
..writeln("NOTA TAGIHAN".center(MAX, '='))
..writeln("NOTA TAGIHAN".center(MAX, '='));
}
// Print reprint header
if (isReprint) {
teks
..writeln("REPRINT".center(MAX, '='))
..writeln("REPRINT".center(MAX, '='))
..writeln();
}
// Print refund footer
if (sales.status == "Refund") {
teks.writeln("#REFUND #REFUND #REFUND".center(MAX, '='));
}
// Print receipt notes
String footer = """
powered by www.uniq.id
"""
.trim()
.center(MAX);
return "$header\n$teks\n$footer";
} catch (e) {
print('Err: ${e}');
}
return '--error--';
}
class ReceiptText {
String receiptNumber;
String customer;
String date;
String cashier;
String payment;
String table;
String change;
ReceiptText({
this.receiptNumber = 'No. Nota',
this.customer = 'Pelanggan',
this.date = 'Tanggal',
this.cashier = 'Kasir',
this.payment = 'Pembayaran',
this.table = 'Meja',
this.change = 'Kembalian',
});
}
ReceiptText receiptLanguage(String language) {
var receiptText = ReceiptText();
if (language == "en") {
receiptText.receiptNumber = "Receipt Number";
receiptText.customer = "Customer";
receiptText.date = "Date";
receiptText.cashier = "Cashier";
receiptText.payment = "Payment";
receiptText.table = "Table";
receiptText.change = "Change";
}
return receiptText;
}
int getMaxCharacter(int? paperSize) {
switch (paperSize) {
case 75:
return 40;
case 80:
return 48;
default:
return 32;
}
}
class Constant {
static const String TYPE_NOMINAL = "nominal";
static const String TYPE_PERCENT = "percentage";
}
extension IntExtension on int? {
String toCurrency({String prefix = ''}) {
var num = NumberFormat.decimalPattern();
try {
return prefix + num.format(this ?? 0);
} catch (e) {
return '${prefix}0';
}
}
String dateTimeFormat([String? format]) {
final DateFormat sdf = DateFormat(format ?? 'dd-MM-yyyy HH:mm');
return sdf.format(DateTime.fromMillisecondsSinceEpoch(this ?? 0));
}
}
extension StringExtensions on String {
String loop(int w) {
var newVal = '';
for (var i = 0; i < w; i++) {
newVal += this;
}
return newVal;
}
String width(int width, {int max = 32, int before = 0}) {
try {
var cursor = 0;
var wordSplit = StringBuffer();
do {
var suffix = '';
var start = cursor;
var end = (start + width) < length ? start + width : length;
var cutWord = substring(start, end);
var lastSpace = cutWord.contains(' ') && end != length
? cutWord.lastIndexOf(' ')
: cutWord.length;
if (lastSpace < (width ~/ 2) && (width - 1) < cutWord.length) {
lastSpace = width - 1;
cursor--;
suffix = '-';
}
cursor += lastSpace + 1;
suffix += cursor < length
? ' '.padRight(max - (before + lastSpace)) + '\n'
: ' '.padRight(width - (before + lastSpace));
wordSplit.write(cutWord.substring(0, lastSpace) + suffix);
} while (cursor < length);
return wordSplit.toString();
} catch (e) {
// Handle error
}
// Fallback logic
return padRight(width);
}
String widthRight(int w) {
return padLeft(w);
}
String center(int width, [String flanks = ' ']) {
if (length == width) {
return this;
} else if (length < width) {
var center = width ~/ 2;
var flank = center - (length ~/ 2);
var newValue = StringBuffer();
for (var i = 0; i < flank; i++) {
newValue.write(flanks);
}
newValue.write(this);
for (var i = newValue.length; i < width; i++) {
newValue.write(flanks);
}
return newValue.toString();
} else {
// Handle case where length > width
}
return '';
}
}
SalesEntity dummySales() {
return SalesEntity(
displayNota: '1001',
customer: 'John Doe',
timeCreated: DateTime.now().millisecondsSinceEpoch,
payment: 'Cash',
table: 'Table 5',
payments: [
Payment(
method: 'Cash',
pay: 50,
bank: Bank(name: 'Bank A'),
),
],
orderList: [
Order(
isItemVoid: false,
product: Product(productId: 1, name: 'Ayam Goreng'),
qty: 2,
subTotal: 20000,
extra: [],
promotion: Promotion(
promotionValue: 5,
pomotionTypeFkid: '15',
),
discount: Discount(
discount: 5,
voucher: 0,
discountNominal: 2500,
voucherNominal: 0,
discountInfo: 'Flash Deals',
discountType: Constant.TYPE_NOMINAL),
),
Order(
isItemVoid: false,
product: Product(productId: 2, name: 'Es Teh'),
qty: 1,
subTotal: 2000,
extra: [],
promotion: null,
discount: Discount(
discount: 0,
voucher: 0,
discountNominal: 0,
voucherNominal: 0,
discountType: Constant.TYPE_NOMINAL),
),
],
promotions: [],
discount: Discount(
discount: 5,
voucher: 0,
discountNominal: 1000,
voucherNominal: 0,
discountInfo: 'Diskon Karyawan',
discountType: Constant.TYPE_PERCENT),
taxes: [
Tax(name: 'Tax Pb1', total: 5),
Tax(name: 'Service', total: 10),
],
grandTotal: 50,
status: 'succcess',
);
}
Outlet dummyOutlet() {
return Outlet(
name: 'Outlet ABC',
receiptAddress: '123 Main Street',
receiptPhone: '123-456-7890',
receiptNote: 'Thank you for your visit!',
receiptSocialmedia: '@OutletABC',
);
}
// SalesEntity model
class SalesEntity {
String displayNota;
String customer;
int timeCreated;
String payment;
String table;
List<Payment> payments;
List<Order> orderList;
List<Promotion> promotions;
Discount? discount;
List<Tax>? taxes;
int grandTotal;
String status;
SalesTagEntity? salesTag;
SalesEntity({
required this.displayNota,
required this.customer,
required this.timeCreated,
required this.payment,
required this.table,
required this.payments,
required this.orderList,
required this.promotions,
this.discount,
this.taxes,
required this.grandTotal,
required this.status,
this.salesTag,
});
}
class SalesTagEntity {
final int salesTagId;
final int adminFkid;
final String dataStatus;
final int dateCreated;
final int dateModified;
final String name;
SalesTagEntity({
required this.salesTagId,
required this.adminFkid,
required this.dataStatus,
required this.dateCreated,
required this.dateModified,
required this.name,
});
}
// Outlet model
class Outlet {
String name;
String? receiptAddress;
String? receiptPhone;
String? receiptNote;
String? receiptSocialmedia;
Outlet({
required this.name,
this.receiptAddress,
this.receiptPhone,
this.receiptNote,
this.receiptSocialmedia,
});
}
// Employee model
class Employee {
String name;
Employee({
required this.name,
});
}
// Payment model
class Payment {
String method;
int pay;
Bank bank;
Payment({
required this.method,
required this.pay,
required this.bank,
});
}
// Order model
class Order {
String? note;
bool isItemVoid;
Product product;
int qty;
int subTotal;
List<Order> extra;
Promotion? promotion;
Discount discount;
Order({
this.note,
required this.isItemVoid,
required this.product,
required this.qty,
required this.subTotal,
required this.extra,
this.promotion,
required this.discount,
});
}
// Product model
class Product {
int productId;
String? name;
Product({
required this.productId,
this.name,
});
}
// Promotion model
class Promotion {
String? name;
String? displayVoucher;
int promotionValue;
String pomotionTypeFkid;
Promotion({
this.name,
this.displayVoucher,
required this.promotionValue,
required this.pomotionTypeFkid,
});
}
// Discount model
class Discount {
int discount;
int voucher;
int discountNominal;
int voucherNominal;
String discountType;
String? discountInfo;
String? voucherInfo;
Discount({
required this.discount,
required this.voucher,
required this.discountNominal,
required this.voucherNominal,
required this.discountType,
this.discountInfo,
this.voucherInfo,
});
}
// Tax model
class Tax {
String? name;
int total;
Tax({
this.name,
required this.total,
});
}
// Bank model
class Bank {
String name;
Bank({
required this.name,
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment