manual edit cleaning and fix AI code
parent
b88c301d7d
commit
b3cb5e3e05
|
@ -13,38 +13,35 @@ class EscPosPrintService {
|
||||||
static Future<List<int>> generateEscPosBytes({
|
static Future<List<int>> generateEscPosBytes({
|
||||||
required List<ReceiptItem> items,
|
required List<ReceiptItem> items,
|
||||||
required DateTime transactionDate,
|
required DateTime transactionDate,
|
||||||
required String cashierId,
|
|
||||||
required String transactionId,
|
|
||||||
}) async {
|
}) async {
|
||||||
print('Memulai generateEscPosBytes...');
|
print('Memulai generateEscPosBytes...');
|
||||||
print('Jumlah item: ${items.length}');
|
print('Jumlah item: ${items.length}');
|
||||||
print('Tanggal transaksi: $transactionDate');
|
print('Tanggal transaksi: $transactionDate');
|
||||||
print('ID kasir: $cashierId');
|
|
||||||
print('ID transaksi: $transactionId');
|
|
||||||
|
|
||||||
// Load store info from shared preferences
|
// Load store info from shared preferences
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
final storeName = prefs.getString('store_name') ?? 'TOKO SEMBAKO MURAH';
|
final storeName = prefs.getString('store_name') ?? 'TOKO SEMBAKO MURAH';
|
||||||
final storeAddress = prefs.getString('store_address') ?? 'Jl. Merdeka No. 123';
|
final storeAddress =
|
||||||
|
prefs.getString('store_address') ?? 'Jl. Merdeka No. 123';
|
||||||
final adminName = prefs.getString('admin_name') ?? 'Budi Santoso';
|
final adminName = prefs.getString('admin_name') ?? 'Budi Santoso';
|
||||||
final adminPhone = prefs.getString('admin_phone') ?? '08123456789';
|
final adminPhone = prefs.getString('admin_phone') ?? '08123456789';
|
||||||
|
|
||||||
print('Nama toko: $storeName');
|
print('Nama toko: $storeName');
|
||||||
print('Alamat toko: $storeAddress');
|
print('Alamat toko: $storeAddress');
|
||||||
print('Nama admin: $adminName');
|
print('Nama admin: $adminName');
|
||||||
print('Telepon admin: $adminPhone');
|
print('Telepon admin: $adminPhone');
|
||||||
|
|
||||||
// Format tanggal
|
// Format tanggal
|
||||||
final dateFormatter = DateFormat('dd/MM/yyyy HH:mm');
|
final dateFormatter = DateFormat('dd/MM/yyyy HH:mm');
|
||||||
final formattedDate = dateFormatter.format(transactionDate);
|
final formattedDate = dateFormatter.format(transactionDate);
|
||||||
print('Tanggal yang diformat: $formattedDate');
|
print('Tanggal yang diformat: $formattedDate');
|
||||||
|
|
||||||
// Format angka ke rupiah
|
// Format angka ke rupiah
|
||||||
String formatRupiah(double amount) {
|
String formatRupiah(double amount) {
|
||||||
final formatter = NumberFormat("#,##0", "id_ID");
|
final formatter = NumberFormat("#,##0", "id_ID");
|
||||||
return "Rp ${formatter.format(amount)}";
|
return "Rp ${formatter.format(amount)}";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load capability profile with timeout
|
// Load capability profile with timeout
|
||||||
CapabilityProfile profile;
|
CapabilityProfile profile;
|
||||||
try {
|
try {
|
||||||
|
@ -54,9 +51,9 @@ class EscPosPrintService {
|
||||||
// Gunakan profile default jika gagal
|
// Gunakan profile default jika gagal
|
||||||
profile = await CapabilityProfile.load();
|
profile = await CapabilityProfile.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
final generator = Generator(PaperSize.mm58, profile);
|
final generator = Generator(PaperSize.mm58, profile);
|
||||||
|
|
||||||
// Mulai dengan inisialisasi printer
|
// Mulai dengan inisialisasi printer
|
||||||
List<int> bytes = [];
|
List<int> bytes = [];
|
||||||
|
|
||||||
|
@ -75,7 +72,7 @@ class EscPosPrintService {
|
||||||
print('Error loading or processing store logo: $e');
|
print('Error loading or processing store logo: $e');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tambahkan nama toko sebagai header
|
// Tambahkan nama toko sebagai header
|
||||||
bytes += generator.text(storeName,
|
bytes += generator.text(storeName,
|
||||||
styles: PosStyles(
|
styles: PosStyles(
|
||||||
|
@ -84,7 +81,7 @@ class EscPosPrintService {
|
||||||
width: PosTextSize.size1,
|
width: PosTextSize.size1,
|
||||||
align: PosAlign.center,
|
align: PosAlign.center,
|
||||||
));
|
));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
bytes += generator.text(storeAddress,
|
bytes += generator.text(storeAddress,
|
||||||
styles: PosStyles(align: PosAlign.center));
|
styles: PosStyles(align: PosAlign.center));
|
||||||
|
@ -94,25 +91,13 @@ class EscPosPrintService {
|
||||||
styles: PosStyles(align: PosAlign.center));
|
styles: PosStyles(align: PosAlign.center));
|
||||||
bytes += generator.text('$formattedDate',
|
bytes += generator.text('$formattedDate',
|
||||||
styles: PosStyles(align: PosAlign.center));
|
styles: PosStyles(align: PosAlign.center));
|
||||||
|
|
||||||
bytes += generator.feed(1);
|
bytes += generator.feed(1);
|
||||||
|
|
||||||
// Garis pemisah
|
// Garis pemisah
|
||||||
bytes += generator.text('================================',
|
bytes += generator.text('================================',
|
||||||
styles: PosStyles(align: PosAlign.center));
|
styles: PosStyles(align: PosAlign.center));
|
||||||
|
|
||||||
// Informasi transaksi
|
|
||||||
bytes += generator.text('Kasir: $cashierId',
|
|
||||||
styles: PosStyles(bold: true));
|
|
||||||
bytes += generator.text('ID Transaksi: $transactionId',
|
|
||||||
styles: PosStyles());
|
|
||||||
|
|
||||||
bytes += generator.feed(1);
|
|
||||||
|
|
||||||
// Garis pemisah
|
|
||||||
bytes += generator.text('================================',
|
|
||||||
styles: PosStyles(align: PosAlign.center));
|
|
||||||
|
|
||||||
// Tabel item
|
// Tabel item
|
||||||
bytes += generator.row([
|
bytes += generator.row([
|
||||||
PosColumn(
|
PosColumn(
|
||||||
|
@ -126,14 +111,15 @@ class EscPosPrintService {
|
||||||
styles: PosStyles(bold: true, align: PosAlign.right),
|
styles: PosStyles(bold: true, align: PosAlign.right),
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Item list dengan penanganan error
|
// Item list dengan penanganan error
|
||||||
print('Memulai iterasi item...');
|
print('Memulai iterasi item...');
|
||||||
for (int i = 0; i < items.length; i++) {
|
for (int i = 0; i < items.length; i++) {
|
||||||
try {
|
try {
|
||||||
var item = items[i];
|
var item = items[i];
|
||||||
print('Item $i: ${item.description}, qty: ${item.quantity}, price: ${item.price}, total: ${item.total}');
|
print(
|
||||||
|
'Item $i: ${item.description}, qty: ${item.quantity}, price: ${item.price}, total: ${item.total}');
|
||||||
|
|
||||||
// Untuk item dengan detail kuantitas dan harga
|
// Untuk item dengan detail kuantitas dan harga
|
||||||
bytes += generator.row([
|
bytes += generator.row([
|
||||||
PosColumn(
|
PosColumn(
|
||||||
|
@ -142,12 +128,15 @@ class EscPosPrintService {
|
||||||
styles: PosStyles(align: PosAlign.left),
|
styles: PosStyles(align: PosAlign.left),
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
bytes += generator.row([
|
bytes += generator.row([
|
||||||
PosColumn(
|
PosColumn(
|
||||||
text: '${item.quantity} x ${formatRupiah(item.price)}',
|
text: '${item.quantity} x ${formatRupiah(item.price)}',
|
||||||
width: 7,
|
width: 7,
|
||||||
styles: PosStyles(align: PosAlign.left, height: PosTextSize.size1, width: PosTextSize.size1),
|
styles: PosStyles(
|
||||||
|
align: PosAlign.left,
|
||||||
|
height: PosTextSize.size1,
|
||||||
|
width: PosTextSize.size1),
|
||||||
),
|
),
|
||||||
PosColumn(
|
PosColumn(
|
||||||
text: formatRupiah(item.total),
|
text: formatRupiah(item.total),
|
||||||
|
@ -162,11 +151,11 @@ class EscPosPrintService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print('Selesai iterasi item');
|
print('Selesai iterasi item');
|
||||||
|
|
||||||
// Garis pemisah sebelum total
|
// Garis pemisah sebelum total
|
||||||
bytes += generator.text('--------------------------------',
|
bytes += generator.text('--------------------------------',
|
||||||
styles: PosStyles(align: PosAlign.center));
|
styles: PosStyles(align: PosAlign.center));
|
||||||
|
|
||||||
// Total
|
// Total
|
||||||
double totalAmount = 0.0;
|
double totalAmount = 0.0;
|
||||||
try {
|
try {
|
||||||
|
@ -175,9 +164,9 @@ class EscPosPrintService {
|
||||||
print('Error saat menghitung total: $e');
|
print('Error saat menghitung total: $e');
|
||||||
totalAmount = 0.0;
|
totalAmount = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
print('Total amount: $totalAmount');
|
print('Total amount: $totalAmount');
|
||||||
|
|
||||||
bytes += generator.row([
|
bytes += generator.row([
|
||||||
PosColumn(
|
PosColumn(
|
||||||
text: 'TOTAL',
|
text: 'TOTAL',
|
||||||
|
@ -190,7 +179,7 @@ class EscPosPrintService {
|
||||||
styles: PosStyles(bold: true, align: PosAlign.right),
|
styles: PosStyles(bold: true, align: PosAlign.right),
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Garis pemisah setelah total
|
// Garis pemisah setelah total
|
||||||
bytes += generator.text('================================',
|
bytes += generator.text('================================',
|
||||||
styles: PosStyles(align: PosAlign.center));
|
styles: PosStyles(align: PosAlign.center));
|
||||||
|
@ -198,29 +187,31 @@ class EscPosPrintService {
|
||||||
// Memuat teks kustom dari shared preferences
|
// Memuat teks kustom dari shared preferences
|
||||||
String customDisclaimer;
|
String customDisclaimer;
|
||||||
try {
|
try {
|
||||||
customDisclaimer = prefs.getString('store_disclaimer_text') ??
|
customDisclaimer = prefs.getString('store_disclaimer_text') ??
|
||||||
'Barang yang sudah dibeli tidak dapat dikembalikan/ditukar. '
|
'Barang yang sudah dibeli tidak dapat dikembalikan/ditukar. '
|
||||||
'Harap periksa kembali struk belanja Anda sebelum meninggalkan toko.';
|
'Harap periksa kembali struk belanja Anda sebelum meninggalkan toko.';
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error saat memuat disclaimer: $e');
|
print('Error saat memuat disclaimer: $e');
|
||||||
customDisclaimer = 'Barang yang sudah dibeli tidak dapat dikembalikan/ditukar.';
|
customDisclaimer =
|
||||||
|
'Barang yang sudah dibeli tidak dapat dikembalikan/ditukar.';
|
||||||
}
|
}
|
||||||
|
|
||||||
String customThankYou;
|
String customThankYou;
|
||||||
try {
|
try {
|
||||||
customThankYou = prefs.getString('thank_you_text') ?? '*** TERIMA KASIH ***';
|
customThankYou =
|
||||||
|
prefs.getString('thank_you_text') ?? '*** TERIMA KASIH ***';
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error saat memuat thank you text: $e');
|
print('Error saat memuat thank you text: $e');
|
||||||
customThankYou = '*** TERIMA KASIH ***';
|
customThankYou = '*** TERIMA KASIH ***';
|
||||||
}
|
}
|
||||||
|
|
||||||
String customPantun;
|
String customPantun;
|
||||||
try {
|
try {
|
||||||
customPantun = prefs.getString('pantun_text') ??
|
customPantun = prefs.getString('pantun_text') ??
|
||||||
'Belanja di toko kami, hemat dan nyaman\n'
|
'Belanja di toko kami, hemat dan nyaman\n'
|
||||||
'Dengan penuh semangat, kami siap melayani\n'
|
'Dengan penuh semangat, kami siap melayani\n'
|
||||||
'Harapan kami, Anda selalu puas\n'
|
'Harapan kami, Anda selalu puas\n'
|
||||||
'Sampai jumpa lagi, selamat tinggal.';
|
'Sampai jumpa lagi, selamat tinggal.';
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error saat memuat pantun: $e');
|
print('Error saat memuat pantun: $e');
|
||||||
customPantun = '';
|
customPantun = '';
|
||||||
|
@ -228,7 +219,7 @@ class EscPosPrintService {
|
||||||
|
|
||||||
// Menambahkan disclaimer
|
// Menambahkan disclaimer
|
||||||
bytes += generator.feed(1);
|
bytes += generator.feed(1);
|
||||||
|
|
||||||
// Memecah disclaimer menjadi beberapa baris jika terlalu panjang
|
// Memecah disclaimer menjadi beberapa baris jika terlalu panjang
|
||||||
try {
|
try {
|
||||||
final disclaimerLines = customDisclaimer.split(' ');
|
final disclaimerLines = customDisclaimer.split(' ');
|
||||||
|
@ -248,8 +239,8 @@ class EscPosPrintService {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final line in wrappedDisclaimer) {
|
for (final line in wrappedDisclaimer) {
|
||||||
bytes += generator.text(line,
|
bytes +=
|
||||||
styles: PosStyles(align: PosAlign.center));
|
generator.text(line, styles: PosStyles(align: PosAlign.center));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error saat memproses disclaimer: $e');
|
print('Error saat memproses disclaimer: $e');
|
||||||
|
@ -269,8 +260,8 @@ class EscPosPrintService {
|
||||||
bytes += generator.feed(1);
|
bytes += generator.feed(1);
|
||||||
final pantunLines = customPantun.split('\n');
|
final pantunLines = customPantun.split('\n');
|
||||||
for (final line in pantunLines) {
|
for (final line in pantunLines) {
|
||||||
bytes += generator.text(line,
|
bytes +=
|
||||||
styles: PosStyles(align: PosAlign.center));
|
generator.text(line, styles: PosStyles(align: PosAlign.center));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error saat menambahkan pantun: $e');
|
print('Error saat menambahkan pantun: $e');
|
||||||
|
@ -286,9 +277,9 @@ class EscPosPrintService {
|
||||||
bytes += generator.feed(2);
|
bytes += generator.feed(2);
|
||||||
bytes += generator.cut();
|
bytes += generator.cut();
|
||||||
}
|
}
|
||||||
|
|
||||||
print('Jumlah byte yang dihasilkan: ${bytes.length}');
|
print('Jumlah byte yang dihasilkan: ${bytes.length}');
|
||||||
|
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,38 +290,30 @@ class EscPosPrintService {
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
required dynamic bluetoothService, // Kita akan sesuaikan tipe ini nanti
|
required dynamic bluetoothService, // Kita akan sesuaikan tipe ini nanti
|
||||||
}) async {
|
}) async {
|
||||||
// Definisikan cashierId dan transactionId di sini karena tidak berubah
|
|
||||||
final String cashierId = 'KSR001';
|
|
||||||
final String transactionId = 'TXN202508200001';
|
|
||||||
|
|
||||||
print('=== FUNGSI printToThermalPrinter DIPANGGIL ===');
|
print('=== FUNGSI printToThermalPrinter DIPANGGIL ===');
|
||||||
print('Memulai proses pencetakan struk...');
|
print('Memulai proses pencetakan struk...');
|
||||||
print('Jumlah item: ${items.length}');
|
print('Jumlah item: ${items.length}');
|
||||||
print('Tanggal transaksi: ${transactionDate}');
|
print('Tanggal transaksi: ${transactionDate}');
|
||||||
print('ID kasir: $cashierId');
|
|
||||||
print('ID transaksi: $transactionId');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
print('Menghasilkan byte array ESC/POS menggunakan flutter_esc_pos_utils...');
|
print(
|
||||||
|
'Menghasilkan byte array ESC/POS menggunakan flutter_esc_pos_utils...');
|
||||||
print('Jumlah item: ${items.length}');
|
print('Jumlah item: ${items.length}');
|
||||||
print('Tanggal transaksi: ${transactionDate}');
|
print('Tanggal transaksi: ${transactionDate}');
|
||||||
print('ID kasir: $cashierId');
|
|
||||||
print('ID transaksi: $transactionId');
|
|
||||||
|
|
||||||
// Generate struk dalam format byte array menggunakan EscPosPrintService
|
// Generate struk dalam format byte array menggunakan EscPosPrintService
|
||||||
final bytes = await generateEscPosBytes(
|
final bytes = await generateEscPosBytes(
|
||||||
items: items,
|
items: items,
|
||||||
transactionDate: transactionDate,
|
transactionDate: transactionDate,
|
||||||
cashierId: cashierId,
|
|
||||||
transactionId: transactionId,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
print('Byte array ESC/POS berhasil dihasilkan');
|
print('Byte array ESC/POS berhasil dihasilkan');
|
||||||
print('Jumlah byte: ${bytes.length}');
|
print('Jumlah byte: ${bytes.length}');
|
||||||
|
|
||||||
// Tampilkan byte array untuk debugging (dalam format hex)
|
// Tampilkan byte array untuk debugging (dalam format hex)
|
||||||
print('Isi byte array (hex):');
|
print('Isi byte array (hex):');
|
||||||
if (bytes.length <= 1000) { // Batasi tampilan untuk mencegah output terlalu panjang
|
if (bytes.length <= 1000) {
|
||||||
|
// Batasi tampilan untuk mencegah output terlalu panjang
|
||||||
print(bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join(' '));
|
print(bytes.map((b) => b.toRadixString(16).padLeft(2, '0')).join(' '));
|
||||||
} else {
|
} else {
|
||||||
print('Terlalu banyak byte untuk ditampilkan (${bytes.length} bytes)');
|
print('Terlalu banyak byte untuk ditampilkan (${bytes.length} bytes)');
|
||||||
|
@ -342,9 +325,9 @@ class EscPosPrintService {
|
||||||
print('Printer tidak terhubung saat akan mencetak');
|
print('Printer tidak terhubung saat akan mencetak');
|
||||||
throw SocketException('Printer tidak terhubung saat akan mencetak');
|
throw SocketException('Printer tidak terhubung saat akan mencetak');
|
||||||
}
|
}
|
||||||
|
|
||||||
print('Mengirim byte array ke printer...');
|
print('Mengirim byte array ke printer...');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Konversi List<int> ke Uint8List
|
// Konversi List<int> ke Uint8List
|
||||||
final Uint8List data = Uint8List.fromList(bytes);
|
final Uint8List data = Uint8List.fromList(bytes);
|
||||||
|
@ -355,7 +338,8 @@ class EscPosPrintService {
|
||||||
throw SocketException('Koneksi ke printer terputus: ${e.message}');
|
throw SocketException('Koneksi ke printer terputus: ${e.message}');
|
||||||
} on PlatformException catch (e) {
|
} on PlatformException catch (e) {
|
||||||
print('Platform error saat mengirim perintah cetak ke printer: $e');
|
print('Platform error saat mengirim perintah cetak ke printer: $e');
|
||||||
throw PlatformException(code: e.code, message: 'Error printer: ${e.message}');
|
throw PlatformException(
|
||||||
|
code: e.code, message: 'Error printer: ${e.message}');
|
||||||
} catch (printError) {
|
} catch (printError) {
|
||||||
print('Error saat mengirim perintah cetak ke printer: $printError');
|
print('Error saat mengirim perintah cetak ke printer: $printError');
|
||||||
throw Exception('Gagal mengirim perintah cetak: $printError');
|
throw Exception('Gagal mengirim perintah cetak: $printError');
|
||||||
|
|
|
@ -15,8 +15,9 @@ class FireflyApiService {
|
||||||
required String accessToken,
|
required String accessToken,
|
||||||
String? type,
|
String? type,
|
||||||
}) async {
|
}) async {
|
||||||
final uri =
|
final uri = type != null
|
||||||
type != null ? Uri.parse('$baseUrl/api/v1/accounts?type=$type') : Uri.parse('$baseUrl/api/v1/accounts');
|
? Uri.parse('$baseUrl/api/v1/accounts?type=$type')
|
||||||
|
: Uri.parse('$baseUrl/api/v1/accounts');
|
||||||
|
|
||||||
final response = await http.get(
|
final response = await http.get(
|
||||||
uri,
|
uri,
|
||||||
|
@ -28,14 +29,15 @@ class FireflyApiService {
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final dynamic responseBody = json.decode(response.body);
|
final dynamic responseBody = json.decode(response.body);
|
||||||
|
|
||||||
if (responseBody is Map<String, dynamic> && responseBody.containsKey('data')) {
|
if (responseBody is Map<String, dynamic> &&
|
||||||
|
responseBody.containsKey('data')) {
|
||||||
final List accountsJson = responseBody['data'] as List;
|
final List accountsJson = responseBody['data'] as List;
|
||||||
|
|
||||||
final List<FireflyAccount> accounts = accountsJson
|
final List<FireflyAccount> accounts = accountsJson
|
||||||
.map((accountJson) => FireflyAccount.fromJson(accountJson))
|
.map((accountJson) => FireflyAccount.fromJson(accountJson))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
return accounts;
|
return accounts;
|
||||||
} else {
|
} else {
|
||||||
throw Exception('Format respons API tidak sesuai');
|
throw Exception('Format respons API tidak sesuai');
|
||||||
|
@ -91,18 +93,17 @@ class FireflyApiService {
|
||||||
// Parse response to get transaction ID
|
// Parse response to get transaction ID
|
||||||
try {
|
try {
|
||||||
final dynamic responseBody = json.decode(response.body);
|
final dynamic responseBody = json.decode(response.body);
|
||||||
|
|
||||||
if (responseBody is Map<String, dynamic> &&
|
if (responseBody is Map<String, dynamic> &&
|
||||||
responseBody.containsKey('data')) {
|
responseBody.containsKey('data')) {
|
||||||
|
|
||||||
final dynamic data = responseBody['data'];
|
final dynamic data = responseBody['data'];
|
||||||
|
|
||||||
// Handle case where data is a single object with an 'id' field
|
// Handle case where data is a single object with an 'id' field
|
||||||
if (data is Map<String, dynamic> && data.containsKey('id')) {
|
if (data is Map<String, dynamic> && data.containsKey('id')) {
|
||||||
final transactionId = data['id'].toString();
|
final transactionId = data['id'].toString();
|
||||||
return transactionId;
|
return transactionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle case where data is a list with at least one object
|
// Handle case where data is a list with at least one object
|
||||||
if (data is List && data.isNotEmpty) {
|
if (data is List && data.isNotEmpty) {
|
||||||
final firstItem = data[0];
|
final firstItem = data[0];
|
||||||
|
@ -120,7 +121,7 @@ class FireflyApiService {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Don't crash if parsing fails, just return success
|
// Don't crash if parsing fails, just return success
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we can't parse the ID, return a default success indicator
|
// If we can't parse the ID, return a default success indicator
|
||||||
return "success";
|
return "success";
|
||||||
} else {
|
} else {
|
||||||
|
@ -144,7 +145,7 @@ class FireflyApiService {
|
||||||
required List<int> fileBytes,
|
required List<int> fileBytes,
|
||||||
}) async {
|
}) async {
|
||||||
final uri = Uri.parse('$baseUrl/api/v1/attachments/$transactionId/upload');
|
final uri = Uri.parse('$baseUrl/api/v1/attachments/$transactionId/upload');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Kirim file sebagai raw binary data dengan Content-Type: application/octet-stream
|
// Kirim file sebagai raw binary data dengan Content-Type: application/octet-stream
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
|
@ -173,7 +174,7 @@ class FireflyApiService {
|
||||||
/// Menguji koneksi ke Firefly III.
|
/// Menguji koneksi ke Firefly III.
|
||||||
static Future<bool> testConnection({required String baseUrl}) async {
|
static Future<bool> testConnection({required String baseUrl}) async {
|
||||||
try {
|
try {
|
||||||
final response = await http.get(Uri.parse('$baseUrl/api/v1/about'));
|
final response = await http.get(Uri.parse(baseUrl));
|
||||||
return response.statusCode == 200;
|
return response.statusCode == 200;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -181,7 +182,8 @@ class FireflyApiService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Menguji autentikasi dengan token.
|
/// Menguji autentikasi dengan token.
|
||||||
static Future<bool> testAuthentication({required String baseUrl, required String accessToken}) async {
|
static Future<bool> testAuthentication(
|
||||||
|
{required String baseUrl, required String accessToken}) async {
|
||||||
try {
|
try {
|
||||||
final response = await http.get(
|
final response = await http.get(
|
||||||
Uri.parse('$baseUrl/api/v1/about/user'),
|
Uri.parse('$baseUrl/api/v1/about/user'),
|
||||||
|
@ -195,4 +197,5 @@ class FireflyApiService {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,8 @@ class PrintService {
|
||||||
// Detail tanggal dan ID transaksi
|
// Detail tanggal dan ID transaksi
|
||||||
list.add(LineText(
|
list.add(LineText(
|
||||||
type: LineText.TYPE_TEXT,
|
type: LineText.TYPE_TEXT,
|
||||||
content: 'Tanggal: ${DateFormat('dd/MM/yyyy HH:mm').format(transaction.timestamp)}',
|
content:
|
||||||
|
'Tanggal: ${DateFormat('dd/MM/yyyy HH:mm').format(transaction.timestamp)}',
|
||||||
align: LineText.ALIGN_LEFT));
|
align: LineText.ALIGN_LEFT));
|
||||||
|
|
||||||
list.add(LineText(
|
list.add(LineText(
|
||||||
|
@ -62,7 +63,8 @@ class PrintService {
|
||||||
final itemTotal = item.price * item.quantity;
|
final itemTotal = item.price * item.quantity;
|
||||||
list.add(LineText(
|
list.add(LineText(
|
||||||
type: LineText.TYPE_TEXT,
|
type: LineText.TYPE_TEXT,
|
||||||
content: 'Rp ${CurrencyFormat.formatRupiahWithoutSymbol(itemTotal)}',
|
content:
|
||||||
|
'Rp ${CurrencyFormat.formatRupiahWithoutSymbol(itemTotal)}',
|
||||||
align: LineText.ALIGN_RIGHT,
|
align: LineText.ALIGN_RIGHT,
|
||||||
linefeed: 1));
|
linefeed: 1));
|
||||||
}
|
}
|
||||||
|
@ -82,7 +84,8 @@ class PrintService {
|
||||||
|
|
||||||
list.add(LineText(
|
list.add(LineText(
|
||||||
type: LineText.TYPE_TEXT,
|
type: LineText.TYPE_TEXT,
|
||||||
content: 'Rp ${CurrencyFormat.formatRupiahWithoutSymbol(transaction.total)}',
|
content:
|
||||||
|
'Rp ${CurrencyFormat.formatRupiahWithoutSymbol(transaction.total)}',
|
||||||
weight: 2,
|
weight: 2,
|
||||||
align: LineText.ALIGN_RIGHT,
|
align: LineText.ALIGN_RIGHT,
|
||||||
linefeed: 1));
|
linefeed: 1));
|
||||||
|
@ -138,4 +141,5 @@ class PrintService {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,9 +28,10 @@ class _ReceiptItemListState extends State<ReceiptItemList> {
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
// Baris tabel keterangan
|
// Baris tabel keterangan
|
||||||
Row(
|
const Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
|
SizedBox(width: 5),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 4,
|
flex: 4,
|
||||||
child: Text(
|
child: Text(
|
||||||
|
@ -79,6 +80,7 @@ class _ReceiptItemListState extends State<ReceiptItemList> {
|
||||||
textAlign: TextAlign.right,
|
textAlign: TextAlign.right,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
SizedBox(width: 5),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
// Garis pembatas
|
// Garis pembatas
|
||||||
|
@ -123,4 +125,5 @@ class _ReceiptItemListState extends State<ReceiptItemList> {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,15 +46,13 @@ class ReceiptSpeedDial extends StatelessWidget {
|
||||||
: () {
|
: () {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(
|
const SnackBar(
|
||||||
content: Text(
|
content:
|
||||||
'Pilih akun sumber dan tujuan terlebih dahulu'),
|
Text('Pilih akun sumber dan tujuan terlebih dahulu'),
|
||||||
duration: Duration(seconds: 2),
|
duration: Duration(seconds: 2),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
backgroundColor: hasItems &&
|
backgroundColor: hasItems && hasSourceAccount && hasDestinationAccount
|
||||||
hasSourceAccount &&
|
|
||||||
hasDestinationAccount
|
|
||||||
? Colors.blue
|
? Colors.blue
|
||||||
: Colors.grey,
|
: Colors.grey,
|
||||||
),
|
),
|
||||||
|
@ -72,7 +70,8 @@ class ReceiptSpeedDial extends StatelessWidget {
|
||||||
),
|
),
|
||||||
SpeedDialChild(
|
SpeedDialChild(
|
||||||
child: bluetoothService.isPrinting
|
child: bluetoothService.isPrinting
|
||||||
? const CircularProgressIndicator(color: Colors.white, strokeWidth: 2)
|
? const CircularProgressIndicator(
|
||||||
|
color: Colors.white, strokeWidth: 2)
|
||||||
: const Icon(Icons.receipt),
|
: const Icon(Icons.receipt),
|
||||||
label: 'Cetak Struk',
|
label: 'Cetak Struk',
|
||||||
onTap: bluetoothService.isPrinting
|
onTap: bluetoothService.isPrinting
|
||||||
|
@ -80,7 +79,7 @@ class ReceiptSpeedDial extends StatelessWidget {
|
||||||
: () async {
|
: () async {
|
||||||
// Panggil callback untuk memulai printing status
|
// Panggil callback untuk memulai printing status
|
||||||
onPrintingStart();
|
onPrintingStart();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Periksa koneksi secara real-time
|
// Periksa koneksi secara real-time
|
||||||
final isConnected = await onCheckConnection();
|
final isConnected = await onCheckConnection();
|
||||||
|
@ -91,43 +90,50 @@ class ReceiptSpeedDial extends StatelessWidget {
|
||||||
if (bluetoothService.connectedDevice != null) {
|
if (bluetoothService.connectedDevice != null) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(
|
const SnackBar(
|
||||||
content: Text('Mencoba menyambungkan ke printer...')),
|
content:
|
||||||
|
Text('Mencoba menyambungkan ke printer...')),
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
bool connectResult = await bluetoothService.connectToDevice(bluetoothService.connectedDevice!);
|
bool connectResult =
|
||||||
|
await bluetoothService.connectToDevice(
|
||||||
|
bluetoothService.connectedDevice!);
|
||||||
if (!connectResult) {
|
if (!connectResult) {
|
||||||
throw Exception('Gagal menyambungkan ke printer');
|
throw Exception('Gagal menyambungkan ke printer');
|
||||||
}
|
}
|
||||||
// Tunggu sebentar untuk memastikan koneksi stabil
|
// Tunggu sebentar untuk memastikan koneksi stabil
|
||||||
await Future.delayed(const Duration(milliseconds: 500));
|
await Future.delayed(
|
||||||
|
const Duration(milliseconds: 500));
|
||||||
// Periksa koneksi lagi
|
// Periksa koneksi lagi
|
||||||
final isConnectedAfterConnect = await onCheckConnection();
|
final isConnectedAfterConnect =
|
||||||
|
await onCheckConnection();
|
||||||
if (isConnectedAfterConnect) {
|
if (isConnectedAfterConnect) {
|
||||||
await onPrint();
|
await onPrint();
|
||||||
} else {
|
} else {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(
|
const SnackBar(
|
||||||
content: Text('Gagal menyambungkan ke printer')),
|
content:
|
||||||
|
Text('Gagal menyambungkan ke printer')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text('Gagal menyambungkan ke printer: $e')),
|
content:
|
||||||
|
Text('Gagal menyambungkan ke printer: $e')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(
|
const SnackBar(
|
||||||
content: Text('Hubungkan printer terlebih dahulu')),
|
content:
|
||||||
|
Text('Hubungkan printer terlebih dahulu')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Tangani error secara umum
|
// Tangani error secara umum
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(content: Text('Terjadi kesalahan: $e')),
|
||||||
content: Text('Terjadi kesalahan: $e')),
|
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
// Pastikan printing status selalu diakhiri
|
// Pastikan printing status selalu diakhiri
|
||||||
|
@ -139,4 +145,5 @@ class ReceiptSpeedDial extends StatelessWidget {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue