Created
March 14, 2024 12:55
-
-
Save ANNASBlackHat/9577fb6a8e5a86d0bc19800afa26436e to your computer and use it in GitHub Desktop.
Captain Order
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:core'; | |
import 'package:intl/intl.dart'; | |
void main() { | |
// Create dummy SalesEntity | |
var sales = dummySales(); | |
// Create dummy PrinterTicketEntity | |
var tickets = PrinterTicketEntity( | |
printersettingTicketId: 1, | |
name: 'Ticket 1', | |
detail: [ | |
PrinterTicketDetail(productSubcategoryFkid: 1), | |
], | |
); | |
// Call the function | |
var result = getPrintCaptainOrderFormat(sales, tickets); | |
// Print the result | |
print(result); | |
} | |
String getPrintCaptainOrderFormat( | |
SalesEntity sales, | |
PrinterTicketEntity? tickets, { | |
int? paperSize, | |
bool isReprint = false, | |
}) { | |
var header = ''; | |
var teks = ''; | |
var footer = ''; | |
var printed = 0; | |
var MAX = getMaxCharacter(paperSize ?? 58); | |
try { | |
sales.orderList.sort((a, b) => a.tmpId.compareTo(b.tmpId)); | |
var ordersToPrint = | |
sales.orderList.where((element) => element.qty > element.printed); | |
header += "CAPTAIN ORDER".center(MAX) + '\n'; | |
header += " BILL INFORMATION ".center(MAX, "=") + '\n\n'; | |
if (tickets != null) { | |
teks += "#${tickets.name}\n"; | |
} | |
if (sales.displayNota.isNotEmpty) { | |
teks += "No Nota : ${sales.displayNota}".width(MAX) + '\n'; | |
} | |
teks += "Pelanggan : ${sales.customer}".width(MAX) + '\n'; | |
if (sales.table.isNotEmpty) { | |
teks += "Meja : ${sales.table}".width(MAX) + '\n'; | |
} | |
var operator = ordersToPrint.first.employeeName; | |
if (operator != null) { | |
teks += "Nama Operator : $operator".width(MAX) + '\n'; | |
} | |
teks += "Nama Login : ${sales.employeeName}".width(MAX) + '\n'; | |
teks += | |
"Tanggal : ${sales.timeModified.dateTimeFormat('HH:mm dd/MM/yyyy')}" | |
.width(MAX) + | |
'\n\n'; | |
var ticketSubCategories = | |
tickets?.detail?.map((e) => e.productSubcategoryFkid) ?? []; | |
ordersToPrint.forEach((orders) { | |
var isParentPrinted = false; | |
if (tickets == null || | |
(ticketSubCategories.isNotEmpty && | |
ticketSubCategories | |
.any((it) => it == orders.product?.productSubcategoryFkid))) { | |
var qty = orders.qty - orders.printed; | |
if (sales.status == "Refund") { | |
orders.qty = orders.qty * -1; | |
orders.subTotal = orders.subTotal * -1; | |
} | |
var name = orders.isItemVoid | |
? "VOID: ${orders.product?.name}" | |
: orders.product.name; | |
var table = sales.table.isNotEmpty ? "/${sales.table}" : ""; | |
var customer = (sales.customer.length ?? 0) <= 6 | |
? sales.customer | |
: sales.customer.substring(0, 6); | |
teks += (qty.toCurrency() + "x").width(5); | |
teks += (name ?? '').width(MAX - 5 - 10, max: MAX, before: 5); | |
teks += " #$customer$table".widthRight(10) + '\n'; | |
printed++; | |
isParentPrinted = true; | |
} | |
orders.extra.forEach((extra) { | |
if (tickets == null || | |
(ticketSubCategories.isNotEmpty && | |
ticketSubCategories | |
.any((it) => it == extra.product.productSubcategoryFkid))) { | |
teks += "\n"; | |
var prefix = isParentPrinted | |
? "[EXTRA] ${orders.qty - orders.printed}x " | |
: "- "; | |
var name = "$prefix" + | |
(orders.isItemVoid | |
? "VOID: ${extra.product.name}" | |
: "${extra.product.name}"); | |
teks += name.width(24) + '\n'; | |
printed++; | |
} | |
}); | |
if (isParentPrinted && orders.note != null) { | |
teks += "(${orders.note})".width(32) + '\n'; | |
} | |
teks += "\n"; | |
}); | |
if (sales.status == "Refund") { | |
teks += " #Refund #Refund #Refund #Refund".center(MAX) + '\n\n'; | |
} | |
if (isReprint) { | |
teks += " REPRINT ".center(MAX, "=") + '\n'; | |
teks += " REPRINT ".center(MAX, "=") + '\n'; | |
} | |
teks += "\n\n"; | |
} catch (e) { | |
print("Create nota order error. $e"); | |
} | |
return printed > 0 ? header + teks + footer : ""; | |
} | |
int getMaxCharacter(int? paperSize) { | |
switch (paperSize) { | |
case 75: | |
return 40; | |
case 80: | |
return 48; | |
default: | |
return 32; | |
} | |
} | |
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 safeRepeat(int? count) { | |
return count != null && count > 0 ? this * count : ''; | |
} | |
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 ''; | |
} | |
} | |
class PrinterTicketEntity { | |
final int printersettingTicketId; | |
final int? printerSettingFkid; | |
final int? dataModified; | |
final String? settingType; | |
final String? name; | |
final List<PrinterTicketDetail> detail; | |
final int? dataCreated; | |
PrinterTicketEntity({ | |
required this.printersettingTicketId, | |
this.printerSettingFkid, | |
this.dataModified, | |
this.settingType, | |
this.name, | |
this.detail = const [], | |
this.dataCreated, | |
}); | |
} | |
class PrinterTicketDetail { | |
final int? productSubcategoryFkid; | |
final int? dataModified; | |
final int? printersettingTicketFkid; | |
PrinterTicketDetail({ | |
this.productSubcategoryFkid, | |
this.dataModified, | |
this.printersettingTicketFkid, | |
}); | |
} | |
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; | |
int customersQty; | |
String employeeName; | |
int timeModified; | |
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, | |
this.customersQty = 1, | |
required this.employeeName, | |
required this.timeModified, | |
}); | |
factory SalesEntity.fromJson(Map<String, dynamic> json) { | |
return SalesEntity( | |
displayNota: json['displayNota'] ?? '', | |
customer: json['customer'] ?? '', | |
timeCreated: json['timeCreated'] ?? 0, | |
payment: json['payment'] ?? '', | |
table: json['table'] ?? '', | |
payments: (json['payments'] ?? []) | |
.map<Payment>((paymentJson) => Payment.fromJson(paymentJson)) | |
.toList(), | |
orderList: (json['orderList'] ?? []) | |
.map<Order>((orderJson) => Order.fromJson(orderJson)) | |
.toList(), | |
promotions: (json['promotions'] ?? []) | |
.map<Promotion>((promotionJson) => Promotion.fromJson(promotionJson)) | |
.toList(), | |
discount: | |
json['discount'] != null ? Discount.fromJson(json['discount']) : null, | |
taxes: (json['taxes'] ?? []) | |
.map<Tax>((taxJson) => Tax.fromJson(taxJson)) | |
.toList(), | |
grandTotal: json['grandTotal'] ?? 0, | |
status: json['status'] ?? '', | |
salesTag: json['salesTag'] != null | |
? SalesTagEntity.fromJson(json['salesTag']) | |
: null, | |
employeeName: json['employee_name'] ?? '', | |
timeModified: json['time_modified'] ?? 0, | |
); | |
} | |
} | |
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, | |
}); | |
factory SalesTagEntity.fromJson(Map<String, dynamic> json) { | |
return SalesTagEntity( | |
salesTagId: json['salesTagId'], | |
adminFkid: json['adminFkid'], | |
dataStatus: json['dataStatus'], | |
dateCreated: json['dateCreated'], | |
dateModified: json['dateModified'], | |
name: json['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; | |
int total; | |
Payment({ | |
required this.method, | |
required this.pay, | |
this.bank, | |
required this.total, | |
}); | |
factory Payment.fromJson(Map<String, dynamic> json) { | |
return Payment( | |
method: json['method'] ?? '', | |
pay: json['pay'] ?? 0, | |
bank: json['bank'] != null | |
? Bank.fromJson(json['bank']) | |
: null, // Assuming Bank has a fromJson method | |
total: json['total'] ?? 0, | |
); | |
} | |
} | |
// Order model | |
class Order { | |
String? note; | |
bool isItemVoid; | |
Product product; | |
int qty; | |
int subTotal; | |
List<Order> extra; | |
Promotion? promotion; | |
Discount discount; | |
String? extraType; | |
int printed; | |
int tmpId; | |
String employeeName; | |
Order({ | |
this.note, | |
required this.isItemVoid, | |
required this.product, | |
required this.qty, | |
required this.subTotal, | |
required this.extra, | |
this.promotion, | |
required this.discount, | |
this.extraType, | |
required this.printed, | |
required this.tmpId, | |
required this.employeeName, | |
}); | |
factory Order.fromJson(Map<String, dynamic> json) { | |
return Order( | |
note: json['note'], | |
isItemVoid: json['isItemVoid'] ?? false, | |
product: Product.fromJson(json['product']), | |
qty: json['qty'] ?? 0, | |
subTotal: json['subTotal'] ?? 0, | |
extra: (json['extra'] as List<dynamic>?) | |
?.map((e) => Order.fromJson(e as Map<String, dynamic>)) | |
.toList() ?? | |
[], | |
promotion: json['promotion'] != null | |
? Promotion.fromJson(json['promotion'] as Map<String, dynamic>) | |
: null, | |
discount: Discount.fromJson(json['discount']), | |
extraType: json['extraType'], | |
printed: json['printed'] ?? 0, | |
tmpId: json['tmp_id'] ?? 0, | |
employeeName: json['employee_name']); | |
} | |
} | |
// Product model | |
class Product { | |
int productId; | |
String? name; | |
int productSubcategoryFkid; | |
int productDetailId; | |
Product({ | |
required this.productId, | |
this.name, | |
required this.productSubcategoryFkid, | |
required this.productDetailId, | |
}); | |
factory Product.fromJson(Map<String, dynamic> json) { | |
return Product( | |
productId: json['productId'], | |
name: json['name'], | |
productSubcategoryFkid: json['productSubcategoryFkid'], | |
productDetailId: json['productDetailId'], | |
); | |
} | |
} | |
// Promotion model | |
class Promotion { | |
String? name; | |
String? displayVoucher; | |
int promotionValue; | |
String? pomotionTypeFkid; | |
Promotion({ | |
this.name, | |
this.displayVoucher, | |
required this.promotionValue, | |
this.pomotionTypeFkid, | |
}); | |
factory Promotion.fromJson(Map<String, dynamic> json) { | |
return Promotion( | |
name: json['name'], | |
displayVoucher: json['displayVoucher'], | |
promotionValue: json['promotionValue'], | |
pomotionTypeFkid: json['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, | |
}); | |
factory Discount.fromJson(Map<String, dynamic> json) { | |
return Discount( | |
discount: json['discount'], | |
voucher: json['voucher'], | |
discountNominal: json['discountNominal'], | |
voucherNominal: json['voucherNominal'], | |
discountType: json['discountType'], | |
discountInfo: json['discountInfo'], | |
voucherInfo: json['voucherInfo'], | |
); | |
} | |
} | |
// Tax model | |
class Tax { | |
String? name; | |
int total; | |
String category; | |
Tax({ | |
this.name, | |
required this.total, | |
required this.category, | |
}); | |
factory Tax.fromJson(Map<String, dynamic> json) { | |
return Tax( | |
name: json['name'], | |
total: json['total'], | |
category: json['category'], | |
); | |
} | |
} | |
// Bank model | |
class Bank { | |
String name; | |
int bankId; | |
Bank({ | |
required this.name, | |
required this.bankId, | |
}); | |
factory Bank.fromJson(Map<String, dynamic> json) { | |
return Bank( | |
name: json['name'] ?? '', | |
bankId: json['bankId'] ?? 0, | |
); | |
} | |
} | |
SalesEntity dummySales() { | |
return SalesEntity( | |
employeeName: "Kartika", | |
timeModified: DateTime.now().millisecondsSinceEpoch, | |
displayNota: '1001', | |
customer: 'John Doe', | |
timeCreated: DateTime.now().millisecondsSinceEpoch, | |
payment: 'CASH', | |
table: 'Table 5', | |
payments: [ | |
Payment( | |
method: 'CARD', | |
pay: 5000, | |
total: 5000, | |
bank: Bank(name: 'BCA', bankId: 1), | |
), | |
], | |
orderList: [ | |
Order( | |
printed: 0, | |
tmpId: DateTime.now().millisecondsSinceEpoch, | |
employeeName: "Feni", | |
isItemVoid: false, | |
product: Product( | |
productId: 1, | |
name: 'Ayam Goreng', | |
productSubcategoryFkid: 1, | |
productDetailId: 1), | |
qty: 2, | |
subTotal: 20000, | |
extra: [], | |
promotion: Promotion( | |
name: "Promo Coblosan", | |
promotionValue: 500, | |
pomotionTypeFkid: '15', | |
), | |
discount: Discount( | |
discount: 5, | |
voucher: 0, | |
discountNominal: 2500, | |
voucherNominal: 0, | |
discountInfo: 'Flash Deals', | |
discountType: Constant.TYPE_NOMINAL), | |
), | |
Order( | |
printed: 0, | |
tmpId: DateTime.now().millisecondsSinceEpoch, | |
employeeName: "Feni", | |
isItemVoid: false, | |
product: Product( | |
productId: 2, | |
name: 'Es Teh', | |
productDetailId: 2, | |
productSubcategoryFkid: 2), | |
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: 50, category: "tax"), | |
Tax(name: 'Service', total: 10, category: "service"), | |
], | |
grandTotal: 5000, | |
status: 'Success'); | |
} | |
Outlet dummyOutlet() { | |
return Outlet( | |
name: 'Outlet ABC', | |
receiptAddress: '123 Main Street', | |
receiptPhone: '123-456-7890', | |
receiptNote: 'Thank you for your visit!', | |
receiptSocialmedia: '@OutletABC', | |
); | |
} | |
class Constant { | |
static const String TYPE_NOMINAL = "nominal"; | |
static const String TYPE_PERCENT = "percentage"; | |
static const String PROMO_TYPE_FREE_MEMBER = "free_member"; | |
static const String PROMO_TYPE_FREE = "free"; | |
static const String PROMO_TYPE_DISCOUNT_VOUCHER = "discount_voucher"; | |
static const String PROMO_TYPE_FREE_VOUCHER = "free_voucher"; | |
static const String PROMO_TYPE_SPECIAL_PRICE_VOUCHER = | |
"special_price_voucher"; | |
static const String TAX_CATEGORY_DISC = "disc"; | |
static const String TAX_CATEGORY_VOUCHER = "voucher"; | |
static const String PRINTER_CODE_LOGO = "[CUT]"; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment