From e825e5daed819ae9fa6d8dbefb09b663f7e212e2 Mon Sep 17 00:00:00 2001 From: efrilm Date: Fri, 1 Aug 2025 18:27:40 +0700 Subject: [PATCH] feat: report page --- README.md | 2 +- android/app/src/main/AndroidManifest.xml | 2 +- generate_app_icon.dart | 18 +- ios/Runner/Info.plist | 2 +- lib/core/utils/item_sales_invoice.dart | 4 +- lib/core/utils/revenue_invoice.dart | 21 +- lib/core/utils/transaction_sales_invoice.dart | 4 +- lib/data/dataoutputs/print_dataoutputs.dart | 52 +- lib/presentation/auth/login_page.dart | 2 +- .../report/pages/report_page.dart | 552 ++++++++++-------- .../widgets/item_sales_report_widget.dart | 263 ++++----- .../widgets/payment_method_report_widget.dart | 32 +- .../widgets/product_sales_chart_widget.dart | 107 ++-- .../report/widgets/report_menu.dart | 62 +- .../report/widgets/report_page_title.dart | 65 +++ .../report/widgets/report_title.dart | 68 ++- .../report/widgets/summary_report_widget.dart | 18 +- .../widgets/transaction_report_widget.dart | 346 +++++------ lib/presentation/sales/pages/sales_page.dart | 2 +- .../setting/pages/manage_printer_page.dart | 3 +- pubspec.yaml | 2 +- 21 files changed, 851 insertions(+), 776 deletions(-) create mode 100644 lib/presentation/report/widgets/report_page_title.dart diff --git a/README.md b/README.md index 16efea5..37a4403 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# EnakloPOS +# ApskelPOS A new Flutter project. diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 0b2dde7..159867a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -11,7 +11,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - EnakloPOS + ApskelPOS CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier diff --git a/lib/core/utils/item_sales_invoice.dart b/lib/core/utils/item_sales_invoice.dart index 4b46c87..751c321 100644 --- a/lib/core/utils/item_sales_invoice.dart +++ b/lib/core/utils/item_sales_invoice.dart @@ -38,7 +38,7 @@ class ItemSalesInvoice { return HelperPdfService.saveDocument( name: - 'Enaklo POS | Item Sales Report | ${DateTime.now().millisecondsSinceEpoch}.pdf', + 'Apskel POS | Item Sales Report | ${DateTime.now().millisecondsSinceEpoch}.pdf', pdf: pdf); } @@ -48,7 +48,7 @@ class ItemSalesInvoice { crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 1 * PdfPageFormat.cm), - Text('Enaklo POS | Item Sales Report', + Text('Apskel POS | Item Sales Report', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, diff --git a/lib/core/utils/revenue_invoice.dart b/lib/core/utils/revenue_invoice.dart index 4471e9a..42ca4e6 100644 --- a/lib/core/utils/revenue_invoice.dart +++ b/lib/core/utils/revenue_invoice.dart @@ -22,13 +22,14 @@ class RevenueInvoice { log("Starting PDF generation for summary report"); log("Summary model: ${summaryModel.toMap()}"); log("Search date formatted: $searchDateFormatted"); - + final pdf = Document(); log("PDF document created"); - + // Load logo image log("Loading logo image..."); - final ByteData dataImage = await rootBundle.load('assets/images/logo.png'); + final ByteData dataImage = + await rootBundle.load('assets/images/logo.png'); final Uint8List bytes = dataImage.buffer.asUint8List(); final image = pw.MemoryImage(bytes); log("Logo image loaded successfully, size: ${bytes.length} bytes"); @@ -49,7 +50,7 @@ class RevenueInvoice { log("Saving PDF document..."); return HelperPdfService.saveDocument( name: - 'Enaklo POS | Summary Sales Report | ${DateTime.now().millisecondsSinceEpoch}.pdf', + 'Apskel POS | Summary Sales Report | ${DateTime.now().millisecondsSinceEpoch}.pdf', pdf: pdf, ); } catch (e) { @@ -69,7 +70,7 @@ class RevenueInvoice { crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 1 * PdfPageFormat.cm), - Text('Enaklo POS | Summary Sales Report', + Text('Apskel POS | Summary Sales Report', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, @@ -93,7 +94,7 @@ class RevenueInvoice { static Widget buildTotal(SummaryModel summaryModel) { log("Building total section with summary model: ${summaryModel.toMap()}"); - + // Helper function to safely parse string to int int safeParseInt(String? value) { if (value == null || value.isEmpty) return 0; @@ -104,7 +105,7 @@ class RevenueInvoice { return 0; } } - + return Container( width: double.infinity, child: Column( @@ -125,7 +126,8 @@ class RevenueInvoice { buildText( title: 'Discount', titleStyle: TextStyle(fontWeight: FontWeight.normal), - value: "- ${safeParseInt(summaryModel.totalDiscount).currencyFormatRp}", + value: + "- ${safeParseInt(summaryModel.totalDiscount).currencyFormatRp}", unite: true, textStyle: TextStyle( color: PdfColor.fromHex('#FF0000'), @@ -147,7 +149,8 @@ class RevenueInvoice { titleStyle: TextStyle( fontWeight: FontWeight.normal, ), - value: safeParseInt(summaryModel.totalServiceCharge).currencyFormatRp, + value: + safeParseInt(summaryModel.totalServiceCharge).currencyFormatRp, unite: true, ), Divider(), diff --git a/lib/core/utils/transaction_sales_invoice.dart b/lib/core/utils/transaction_sales_invoice.dart index f7a7b70..44a684f 100644 --- a/lib/core/utils/transaction_sales_invoice.dart +++ b/lib/core/utils/transaction_sales_invoice.dart @@ -38,7 +38,7 @@ class TransactionSalesInvoice { return HelperPdfService.saveDocument( name: - 'Enaklo POS | Transaction Sales Report | ${DateTime.now().millisecondsSinceEpoch}.pdf', + 'Apskel POS | Transaction Sales Report | ${DateTime.now().millisecondsSinceEpoch}.pdf', pdf: pdf); } @@ -48,7 +48,7 @@ class TransactionSalesInvoice { crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 1 * PdfPageFormat.cm), - Text('Enaklo POS | Transaction Sales Report', + Text('Apskel POS | Transaction Sales Report', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, diff --git a/lib/data/dataoutputs/print_dataoutputs.dart b/lib/data/dataoutputs/print_dataoutputs.dart index c071a1f..3c68bce 100644 --- a/lib/data/dataoutputs/print_dataoutputs.dart +++ b/lib/data/dataoutputs/print_dataoutputs.dart @@ -35,7 +35,7 @@ class PrintDataoutputs { final total = totalPrice + pajak; bytes += generator.reset(); - bytes += generator.text('Enaklo POS', + bytes += generator.text('Apskel POS', styles: const PosStyles( bold: true, align: PosAlign.center, @@ -202,7 +202,7 @@ class PrintDataoutputs { // bytes += generator.feed(3); // } - bytes += generator.text('Enaklo POS', + bytes += generator.text('Apskel POS', styles: const PosStyles( bold: true, align: PosAlign.center, @@ -474,21 +474,21 @@ class PrintDataoutputs { } Future> printOrderV3( - List products, - int totalQuantity, - int totalPrice, - String paymentMethod, - int nominalBayar, - int kembalian, - int subTotal, - int discount, - int pajak, - int serviceCharge, - String namaKasir, - String customerName, - int paper, - {int taxPercentage = 11, int serviceChargePercentage = 5} - ) async { + List products, + int totalQuantity, + int totalPrice, + String paymentMethod, + int nominalBayar, + int kembalian, + int subTotal, + int discount, + int pajak, + int serviceCharge, + String namaKasir, + String customerName, + int paper, + {int taxPercentage = 11, + int serviceChargePercentage = 5}) async { List bytes = []; final profile = await CapabilityProfile.load(); @@ -778,8 +778,13 @@ class PrintDataoutputs { return bytes; } - Future> printChecker(List products, - String tableName, String draftName, String cashierName, int paper, String orderType) async { + Future> printChecker( + List products, + String tableName, + String draftName, + String cashierName, + int paper, + String orderType) async { List bytes = []; final profile = await CapabilityProfile.load(); @@ -908,8 +913,13 @@ class PrintDataoutputs { return bytes; } - Future> printKitchen(List products, - String tableNumber, String draftName, String cashierName, int paper, String orderType) async { + Future> printKitchen( + List products, + String tableNumber, + String draftName, + String cashierName, + int paper, + String orderType) async { List bytes = []; final profile = await CapabilityProfile.load(); diff --git a/lib/presentation/auth/login_page.dart b/lib/presentation/auth/login_page.dart index db91d5d..8c8aa96 100644 --- a/lib/presentation/auth/login_page.dart +++ b/lib/presentation/auth/login_page.dart @@ -49,7 +49,7 @@ class _LoginPageState extends State { const SpaceHeight(24.0), const Center( child: Text( - 'Enaklo POS', + 'Apskel POS', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w700, diff --git a/lib/presentation/report/pages/report_page.dart b/lib/presentation/report/pages/report_page.dart index 2bf9c10..3fb1c9c 100644 --- a/lib/presentation/report/pages/report_page.dart +++ b/lib/presentation/report/pages/report_page.dart @@ -34,264 +34,314 @@ class _ReportPageState extends State { DateTime fromDate = DateTime.now().subtract(const Duration(days: 30)); DateTime toDate = DateTime.now(); + @override + void initState() { + super.initState(); + context.read().add( + TransactionReportEvent.getReport( + startDate: DateFormatter.formatDateTime(fromDate), + endDate: DateFormatter.formatDateTime(toDate)), + ); + } + @override Widget build(BuildContext context) { String searchDateFormatted = '${fromDate.toFormattedDate2()} to ${toDate.toFormattedDate2()}'; return Scaffold( - body: Row( + backgroundColor: AppColors.background, + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - // LEFT CONTENT - Expanded( - flex: 2, - child: Align( - alignment: Alignment.topLeft, - child: SingleChildScrollView( - padding: const EdgeInsets.all(24.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const ReportTitle(), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Flexible( - child: CustomDatePicker( - prefix: const Text('From: '), - initialDate: fromDate, - onDateSelected: (selectedDate) { - fromDate = selectedDate; + ReportTitle( + actionWidget: [ + SizedBox( + width: 300, + child: CustomDatePicker( + prefix: const Text('From: '), + initialDate: fromDate, + onDateSelected: (selectedDate) { + fromDate = selectedDate; - setState(() {}); - }, - ), - ), - const SpaceWidth(24.0), - Flexible( - child: CustomDatePicker( - prefix: const Text('To: '), - initialDate: toDate, - onDateSelected: (selectedDate) { - toDate = selectedDate; - setState(() {}); - // context.read().add( - // TransactionReportEvent.getReport( - // startDate: - // DateFormatter.formatDateTime( - // fromDate), - // endDate: DateFormatter.formatDateTime( - // toDate)), - // ); - // context.read().add( - // ItemSalesReportEvent.getItemSales( - // startDate: - // DateFormatter.formatDateTime( - // fromDate), - // endDate: DateFormatter.formatDateTime( - // toDate)), - // ); - }, - ), - ), - ], - ), - Padding( - padding: const EdgeInsets.all(15.0), - child: Wrap( - children: [ - ReportMenu( - label: 'Transaction Report', - onPressed: () { - selectedMenu = 0; - title = 'Transaction Report'; - setState(() {}); - //enddate is 1 month before the current date - context.read().add( - TransactionReportEvent.getReport( - startDate: DateFormatter.formatDateTime( - fromDate), - endDate: DateFormatter.formatDateTime( - toDate)), - ); - }, - isActive: selectedMenu == 0, - ), - ReportMenu( - label: 'Item Sales Report', - onPressed: () { - selectedMenu = 1; - title = 'Item Sales Report'; - setState(() {}); - context.read().add( - ItemSalesReportEvent.getItemSales( - startDate: DateFormatter.formatDateTime( - fromDate), - endDate: DateFormatter.formatDateTime( - toDate)), - ); - }, - isActive: selectedMenu == 1, - ), - ReportMenu( - label: 'Product Sales Chart', - onPressed: () { - selectedMenu = 2; - title = 'Product Sales Chart'; - setState(() {}); - context.read().add( - ProductSalesEvent.getProductSales( - DateFormatter.formatDateTime(fromDate), - DateFormatter.formatDateTime(toDate)), - ); - }, - isActive: selectedMenu == 2, - ), - ReportMenu( - label: 'Summary Sales Report', - onPressed: () { - selectedMenu = 3; - title = 'Summary Sales Report'; - setState(() {}); - context.read().add( - SummaryEvent.getSummary( - DateFormatter.formatDateTime(fromDate), - DateFormatter.formatDateTime(toDate)), - ); - - log("Date ${DateFormatter.formatDateTime(fromDate)}"); - }, - isActive: selectedMenu == 3, - ), - ReportMenu( - label: 'Payment Method Report', - onPressed: () { - selectedMenu = 4; - title = 'Payment Method Report'; - setState(() {}); - context.read().add( - PaymentMethodReportEvent.getPaymentMethodReport( - startDate: DateFormatter.formatDateTime(fromDate), - endDate: DateFormatter.formatDateTime(toDate)), - ); - }, - isActive: selectedMenu == 4, - ), - ], - ), - ), - ], + setState(() {}); + }, ), ), + const SpaceWidth(24.0), + SizedBox( + width: 300, + child: CustomDatePicker( + prefix: const Text('To: '), + initialDate: toDate, + onDateSelected: (selectedDate) { + toDate = selectedDate; + setState(() {}); + // context.read().add( + // TransactionReportEvent.getReport( + // startDate: + // DateFormatter.formatDateTime( + // fromDate), + // endDate: DateFormatter.formatDateTime( + // toDate)), + // ); + // context.read().add( + // ItemSalesReportEvent.getItemSales( + // startDate: + // DateFormatter.formatDateTime( + // fromDate), + // endDate: DateFormatter.formatDateTime( + // toDate)), + // ); + }, + ), + ), + ], + ), + Expanded( + child: Row( + children: [ + // LEFT CONTENT + Expanded( + flex: 2, + child: Material( + color: AppColors.white, + child: Align( + alignment: Alignment.topLeft, + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ReportMenu( + label: 'Laporan Transaksi', + subtitle: + 'Menampilkan riwayat lengkap semua transaksi yang telah dilakukan.', + icon: Icons.receipt_long_outlined, + onPressed: () { + selectedMenu = 0; + title = 'Laporan Transaksi'; + setState(() {}); + //enddate is 1 month before the current date + context.read().add( + TransactionReportEvent.getReport( + startDate: + DateFormatter.formatDateTime( + fromDate), + endDate: DateFormatter.formatDateTime( + toDate)), + ); + }, + isActive: selectedMenu == 0, + ), + ReportMenu( + label: 'Laporan Penjualan Item', + subtitle: + 'Laporan penjualan berdasarkan masing-masing item atau produk.', + icon: Icons.inventory_2_outlined, + onPressed: () { + selectedMenu = 1; + title = 'Laporan Penjualan Item'; + setState(() {}); + context.read().add( + ItemSalesReportEvent.getItemSales( + startDate: + DateFormatter.formatDateTime( + fromDate), + endDate: DateFormatter.formatDateTime( + toDate)), + ); + }, + isActive: selectedMenu == 1, + ), + ReportMenu( + label: 'Chart Penjualan Produk', + subtitle: + 'Grafik visual penjualan produk untuk analisa performa penjualan.', + icon: Icons.bar_chart_outlined, + onPressed: () { + selectedMenu = 2; + title = 'Chart Penjualan Produk'; + setState(() {}); + context.read().add( + ProductSalesEvent.getProductSales( + DateFormatter.formatDateTime( + fromDate), + DateFormatter.formatDateTime(toDate)), + ); + }, + isActive: selectedMenu == 2, + ), + ReportMenu( + label: 'Ringkasan Laporan Penjualan', + subtitle: + 'Ringkasan total penjualan dalam periode tertentu.', + icon: Icons.insert_drive_file_outlined, + onPressed: () { + selectedMenu = 3; + title = 'Ringkasan Laporan Penjualan'; + setState(() {}); + context.read().add( + SummaryEvent.getSummary( + DateFormatter.formatDateTime( + fromDate), + DateFormatter.formatDateTime(toDate)), + ); + + log("Date ${DateFormatter.formatDateTime(fromDate)}"); + }, + isActive: selectedMenu == 3, + ), + ReportMenu( + label: 'Laporan Metode Pembayaran', + subtitle: + 'Laporan metode pembayaran yang digunakan.', + icon: Icons.payment_outlined, + onPressed: () { + selectedMenu = 4; + title = 'Laporan Metode Pembayaran'; + setState(() {}); + context.read().add( + PaymentMethodReportEvent + .getPaymentMethodReport( + startDate: + DateFormatter.formatDateTime( + fromDate), + endDate: + DateFormatter.formatDateTime( + toDate)), + ); + }, + isActive: selectedMenu == 4, + ), + ], + ), + ), + ), + ), + ), + + // RIGHT CONTENT + Expanded( + flex: 4, + child: selectedMenu == 0 + ? BlocBuilder( + builder: (context, state) { + return state.maybeWhen( + orElse: () => const Center( + child: CircularProgressIndicator(), + ), + error: (message) { + return Text(message); + }, + loaded: (transactionReport) { + return TransactionReportWidget( + transactionReport: transactionReport, + title: title, + searchDateFormatted: searchDateFormatted, + headerWidgets: _getTitleReportPageWidget(), + ); + }, + ); + }, + ) + : selectedMenu == 1 + ? BlocBuilder( + builder: (context, state) { + return state.maybeWhen( + orElse: () => const Center( + child: CircularProgressIndicator(), + ), + error: (message) { + return Text(message); + }, + loaded: (itemSales) { + return ItemSalesReportWidget( + itemSales: itemSales, + title: title, + searchDateFormatted: + searchDateFormatted, + headerWidgets: + _getItemSalesPageWidget(), + ); + }, + ); + }, + ) + : selectedMenu == 2 + ? BlocBuilder( + builder: (context, state) { + return state.maybeWhen( + orElse: () => const Center( + child: CircularProgressIndicator(), + ), + error: (message) { + return Text(message); + }, + success: (productSales) { + return ProductSalesChartWidgets( + title: title, + searchDateFormatted: + searchDateFormatted, + productSales: productSales, + ); + }, + ); + }, + ) + : selectedMenu == 3 + ? BlocBuilder( + builder: (context, state) { + return state.maybeWhen( + orElse: () => const Center( + child: + CircularProgressIndicator(), + ), + error: (message) { + return Text(message); + }, + success: (summary) { + return SummaryReportWidget( + summary: summary, + title: title, + searchDateFormatted: + searchDateFormatted, + ); + }, + ); + }, + ) + : selectedMenu == 4 + ? BlocBuilder( + builder: (context, state) { + return state.maybeWhen( + orElse: () => const Center( + child: + CircularProgressIndicator(), + ), + error: (message) { + return Text(message); + }, + loaded: (paymentMethodData) { + return PaymentMethodReportWidget( + paymentMethodData: + paymentMethodData, + title: title, + searchDateFormatted: + searchDateFormatted, + headerWidgets: + _getPaymentMethodPageWidget(), + ); + }, + ); + }, + ) + : const SizedBox.shrink()), + ], ), ), - - // RIGHT CONTENT - Expanded( - flex: 2, - child: selectedMenu == 0 - ? BlocBuilder( - builder: (context, state) { - return state.maybeWhen( - orElse: () => const Center( - child: CircularProgressIndicator(), - ), - error: (message) { - return Text(message); - }, - loaded: (transactionReport) { - return TransactionReportWidget( - transactionReport: transactionReport, - title: title, - searchDateFormatted: searchDateFormatted, - headerWidgets: _getTitleReportPageWidget(), - ); - }, - ); - }, - ) - : selectedMenu == 1 - ? BlocBuilder( - builder: (context, state) { - return state.maybeWhen( - orElse: () => const Center( - child: CircularProgressIndicator(), - ), - error: (message) { - return Text(message); - }, - loaded: (itemSales) { - return ItemSalesReportWidget( - itemSales: itemSales, - title: title, - searchDateFormatted: searchDateFormatted, - headerWidgets: _getItemSalesPageWidget(), - ); - }, - ); - }, - ) - : selectedMenu == 2 - ? BlocBuilder( - builder: (context, state) { - return state.maybeWhen( - orElse: () => const Center( - child: CircularProgressIndicator(), - ), - error: (message) { - return Text(message); - }, - success: (productSales) { - return ProductSalesChartWidgets( - title: title, - searchDateFormatted: searchDateFormatted, - productSales: productSales, - ); - }, - ); - }, - ) - : selectedMenu == 3 - ? BlocBuilder( - builder: (context, state) { - return state.maybeWhen( - orElse: () => const Center( - child: CircularProgressIndicator(), - ), - error: (message) { - return Text(message); - }, - success: (summary) { - return SummaryReportWidget( - summary: summary, - title: title, - searchDateFormatted: searchDateFormatted, - ); - }, - ); - }, - ) - : selectedMenu == 4 - ? BlocBuilder( - builder: (context, state) { - return state.maybeWhen( - orElse: () => const Center( - child: CircularProgressIndicator(), - ), - error: (message) { - return Text(message); - }, - loaded: (paymentMethodData) { - return PaymentMethodReportWidget( - paymentMethodData: paymentMethodData, - title: title, - searchDateFormatted: searchDateFormatted, - headerWidgets: _getPaymentMethodPageWidget(), - ); - }, - ); - }, - ) - : const SizedBox.shrink()), ], ), ); @@ -314,11 +364,11 @@ class _ReportPageState extends State { List _getItemSalesPageWidget() { return [ _getTitleItemWidget('ID', 80), - _getTitleItemWidget('Order', 60), - _getTitleItemWidget('Product', 160), + _getTitleItemWidget('Order', 100), + _getTitleItemWidget('Product', 200), _getTitleItemWidget('Qty', 60), - _getTitleItemWidget('Price', 140), - _getTitleItemWidget('Total Price', 140), + _getTitleItemWidget('Price', 150), + _getTitleItemWidget('Total Price', 160), ]; } diff --git a/lib/presentation/report/widgets/item_sales_report_widget.dart b/lib/presentation/report/widgets/item_sales_report_widget.dart index be0fffc..312f803 100644 --- a/lib/presentation/report/widgets/item_sales_report_widget.dart +++ b/lib/presentation/report/widgets/item_sales_report_widget.dart @@ -4,12 +4,12 @@ import 'package:enaklo_pos/core/components/spaces.dart'; import 'package:enaklo_pos/core/constants/colors.dart'; import 'package:enaklo_pos/core/extensions/int_ext.dart'; import 'package:enaklo_pos/core/utils/helper_pdf_service.dart'; +import 'package:enaklo_pos/presentation/report/widgets/report_page_title.dart'; import 'package:flutter/material.dart'; import 'package:enaklo_pos/core/utils/item_sales_invoice.dart'; import 'package:enaklo_pos/core/utils/permession_handler.dart'; import 'package:enaklo_pos/data/models/response/item_sales_response_model.dart'; import 'package:horizontal_data_table/horizontal_data_table.dart'; -import 'package:permission_handler/permission_handler.dart'; class ItemSalesReportWidget extends StatelessWidget { final String title; @@ -26,166 +26,123 @@ class ItemSalesReportWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return Card( - color: const Color.fromARGB(255, 255, 255, 255), - child: Column( - children: [ - const SpaceHeight(24.0), - Center( - child: Text( - title, - style: - const TextStyle(fontWeight: FontWeight.w800, fontSize: 16.0), - ), - ), - const SizedBox( - height: 8.0, - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 12), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - searchDateFormatted, - style: const TextStyle(fontSize: 16.0), + return Column( + children: [ + ReportPageTitle( + title: title, + searchDateFormatted: searchDateFormatted, + onExport: () async { + try { + final status = await PermessionHelper().checkPermission(); + if (status) { + final pdfFile = await ItemSalesInvoice.generate( + itemSales, searchDateFormatted); + log("pdfFile: $pdfFile"); + await HelperPdfService.openFile(pdfFile); + } else { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Storage permission is required to save PDF'), + backgroundColor: Colors.red, + ), + ); + } + } catch (e) { + log("Error generating PDF: $e"); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Failed to generate PDF: $e'), + backgroundColor: Colors.red, ), - GestureDetector( - onTap: () async { - try { - final status = await PermessionHelper().checkPermission(); - if (status) { - final pdfFile = await ItemSalesInvoice.generate( - itemSales, searchDateFormatted); - log("pdfFile: $pdfFile"); - await HelperPdfService.openFile(pdfFile); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Storage permission is required to save PDF'), - backgroundColor: Colors.red, - ), - ); - } - } catch (e) { - log("Error generating PDF: $e"); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Failed to generate PDF: $e'), - backgroundColor: Colors.red, - ), - ); - } - }, - child: const Row( - children: [ - Text( - "PDF", - style: TextStyle( - fontSize: 14.0, - fontWeight: FontWeight.bold, - color: AppColors.primary, - ), + ); + } + }, + ), + const SpaceHeight(16.0), + Expanded( + child: Padding( + padding: const EdgeInsets.all(12), + child: ClipRRect( + borderRadius: BorderRadius.circular(12), + child: HorizontalDataTable( + leftHandSideColumnWidth: 80, + rightHandSideColumnWidth: 670, + isFixedHeader: true, + headerWidgets: headerWidgets, + + // isFixedFooter: true, + // footerWidgets: _getTitleWidget(), + leftSideItemBuilder: (context, index) { + return Container( + width: 80, + height: 52, + alignment: Alignment.centerLeft, + child: Center(child: Text(itemSales[index].id.toString())), + ); + }, + rightSideItemBuilder: (context, index) { + return Row( + children: [ + Container( + width: 100, + height: 52, + alignment: Alignment.centerLeft, + child: Center( + child: Text(itemSales[index].orderId.toString())), + ), + Container( + width: 200, + height: 52, + alignment: Alignment.centerLeft, + child: + Center(child: Text(itemSales[index].productName!)), + ), + Container( + width: 60, + height: 52, + alignment: Alignment.centerLeft, + child: Center( + child: Text(itemSales[index].quantity.toString())), + ), + Container( + width: 150, + height: 52, + padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), + alignment: Alignment.centerLeft, + child: Center( + child: Text( + itemSales[index].price!.currencyFormatRp, + )), + ), + Container( + width: 160, + height: 52, + padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), + alignment: Alignment.centerLeft, + child: Center( + child: Text( + (itemSales[index].price! * itemSales[index].quantity!) + .currencyFormatRp, + )), ), - Icon( - Icons.download_outlined, - color: AppColors.primary, - ) ], - ), + ); + }, + itemCount: itemSales.length, + rowSeparatorWidget: const Divider( + color: Colors.black38, + height: 1.0, + thickness: 0.0, ), - ], - ), - ), - const SpaceHeight(16.0), - Expanded( - child: Padding( - padding: const EdgeInsets.all(12), - child: ClipRRect( - borderRadius: BorderRadius.circular(12), - child: HorizontalDataTable( - leftHandSideColumnWidth: 80, - rightHandSideColumnWidth: 560, - isFixedHeader: true, - headerWidgets: headerWidgets, + leftHandSideColBackgroundColor: AppColors.white, + rightHandSideColBackgroundColor: AppColors.white, - // isFixedFooter: true, - // footerWidgets: _getTitleWidget(), - leftSideItemBuilder: (context, index) { - return Container( - width: 80, - height: 52, - alignment: Alignment.centerLeft, - child: - Center(child: Text(itemSales[index].id.toString())), - ); - }, - rightSideItemBuilder: (context, index) { - return Row( - children: [ - Container( - width: 60, - height: 52, - alignment: Alignment.centerLeft, - child: Center( - child: Text(itemSales[index].orderId.toString())), - ), - Container( - width: 160, - height: 52, - alignment: Alignment.centerLeft, - child: Center( - child: Text(itemSales[index].productName!)), - ), - Container( - width: 60, - height: 52, - alignment: Alignment.centerLeft, - child: Center( - child: - Text(itemSales[index].quantity.toString())), - ), - Container( - width: 140, - height: 52, - padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), - alignment: Alignment.centerLeft, - child: Center( - child: Text( - itemSales[index].price!.currencyFormatRp, - )), - ), - Container( - width: 140, - height: 52, - padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), - alignment: Alignment.centerLeft, - child: Center( - child: Text( - (itemSales[index].price! * - itemSales[index].quantity!) - .currencyFormatRp, - )), - ), - ], - ); - }, - itemCount: itemSales.length, - rowSeparatorWidget: const Divider( - color: Colors.black38, - height: 1.0, - thickness: 0.0, - ), - leftHandSideColBackgroundColor: AppColors.white, - rightHandSideColBackgroundColor: AppColors.white, - - itemExtent: 55, - ), + itemExtent: 55, ), ), ), - ], - ), + ), + ], ); } } diff --git a/lib/presentation/report/widgets/payment_method_report_widget.dart b/lib/presentation/report/widgets/payment_method_report_widget.dart index 337fcb7..00e1659 100644 --- a/lib/presentation/report/widgets/payment_method_report_widget.dart +++ b/lib/presentation/report/widgets/payment_method_report_widget.dart @@ -1,9 +1,7 @@ import 'package:flutter/material.dart'; import 'package:enaklo_pos/core/constants/colors.dart'; -import 'package:enaklo_pos/core/extensions/int_ext.dart'; import 'package:enaklo_pos/core/extensions/string_ext.dart'; import 'package:enaklo_pos/data/models/response/payment_method_response_model.dart'; -import 'package:enaklo_pos/presentation/report/widgets/report_title.dart'; import '../../../core/components/spaces.dart'; @@ -109,20 +107,20 @@ class PaymentMethodReportWidget extends StatelessWidget { ), ), child: Row( - children: [ - _getBodyItemWidget( - item.paymentMethod ?? '-', - 180, - ), - _getBodyItemWidget( - item.totalAmount?.currencyFormatRpV2 ?? 'Rp 0', - 180, - ), - _getBodyItemWidget( - item.transactionCount?.toString() ?? '0', - 180, - ), - ], + children: [ + _getBodyItemWidget( + item.paymentMethod ?? '-', + 180, + ), + _getBodyItemWidget( + item.totalAmount?.currencyFormatRpV2 ?? 'Rp 0', + 180, + ), + _getBodyItemWidget( + item.transactionCount?.toString() ?? '0', + 180, + ), + ], ), ); }).toList() ?? @@ -150,4 +148,4 @@ class PaymentMethodReportWidget extends StatelessWidget { ), ); } -} \ No newline at end of file +} diff --git a/lib/presentation/report/widgets/product_sales_chart_widget.dart b/lib/presentation/report/widgets/product_sales_chart_widget.dart index 9170729..ca4c456 100644 --- a/lib/presentation/report/widgets/product_sales_chart_widget.dart +++ b/lib/presentation/report/widgets/product_sales_chart_widget.dart @@ -1,6 +1,7 @@ // ignore_for_file: public_member_api_docs, sort_constructors_first import 'package:enaklo_pos/core/components/spaces.dart'; +import 'package:enaklo_pos/presentation/report/widgets/report_page_title.dart'; import 'package:flutter/material.dart'; import 'package:pie_chart/pie_chart.dart'; @@ -67,59 +68,61 @@ class _ProductSalesChartWidgetsState extends State { @override Widget build(BuildContext context) { - return Card( - color: const Color.fromARGB(255, 255, 255, 255), - child: Padding( - padding: EdgeInsets.symmetric(horizontal: 8, vertical: 16), - child: Column( - children: [ - const SpaceHeight(24.0), - Center( - child: Text( - widget.title, - style: const TextStyle( - fontWeight: FontWeight.w800, fontSize: 16.0), - ), - ), - Center( - child: Text( - widget.searchDateFormatted, - style: const TextStyle(fontSize: 16.0), - ), - ), - const SpaceHeight(16.0), - PieChart( - dataMap: dataMap2, - animationDuration: Duration(milliseconds: 800), - chartLegendSpacing: 32, - chartRadius: MediaQuery.of(context).size.width / 3.2, - colorList: colorList, - initialAngleInDegree: 0, - chartType: ChartType.disc, - ringStrokeWidth: 32, - // centerText: "HYBRID", - legendOptions: LegendOptions( - showLegendsInRow: false, - legendPosition: LegendPosition.right, - showLegends: true, - legendShape: BoxShape.circle, - legendTextStyle: TextStyle( - fontWeight: FontWeight.bold, - ), - ), - chartValuesOptions: ChartValuesOptions( - showChartValueBackground: true, - showChartValues: true, - showChartValuesInPercentage: false, - showChartValuesOutside: false, - decimalPlaces: 0, - ), - // gradientList: ---To add gradient colors--- - // emptyColorGradient: ---Empty Color gradient--- - ) - ], + return Column( + children: [ + ReportPageTitle( + title: widget.title, + searchDateFormatted: widget.searchDateFormatted, + onExport: () async {}, + isExport: false, // Set to false if export is not needed ), - ), + const SpaceHeight(16.0), + Expanded( + child: SingleChildScrollView( + child: Container( + padding: const EdgeInsets.all(16.0), + margin: const EdgeInsets.all(12.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + ), + child: Column( + children: [ + PieChart( + dataMap: dataMap2, + animationDuration: Duration(milliseconds: 800), + chartLegendSpacing: 32, + chartRadius: MediaQuery.of(context).size.width / 3.2, + colorList: colorList, + initialAngleInDegree: 0, + chartType: ChartType.disc, + ringStrokeWidth: 32, + // centerText: "HYBRID", + legendOptions: LegendOptions( + showLegendsInRow: false, + legendPosition: LegendPosition.right, + showLegends: true, + legendShape: BoxShape.circle, + legendTextStyle: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + chartValuesOptions: ChartValuesOptions( + showChartValueBackground: true, + showChartValues: true, + showChartValuesInPercentage: false, + showChartValuesOutside: false, + decimalPlaces: 0, + ), + // gradientList: ---To add gradient colors--- + // emptyColorGradient: ---Empty Color gradient--- + ), + ], + ), + ), + ), + ) + ], ); } } diff --git a/lib/presentation/report/widgets/report_menu.dart b/lib/presentation/report/widgets/report_menu.dart index 9f36a7d..27eb85f 100644 --- a/lib/presentation/report/widgets/report_menu.dart +++ b/lib/presentation/report/widgets/report_menu.dart @@ -1,13 +1,12 @@ import 'package:flutter/material.dart'; -import 'package:enaklo_pos/core/assets/assets.gen.dart'; import '../../../core/components/spaces.dart'; import '../../../core/constants/colors.dart'; - - class ReportMenu extends StatelessWidget { final String label; + final String subtitle; + final IconData icon; final VoidCallback onPressed; final bool isActive; @@ -16,6 +15,8 @@ class ReportMenu extends StatelessWidget { required this.label, required this.onPressed, required this.isActive, + required this.subtitle, + required this.icon, }); @override @@ -23,38 +24,43 @@ class ReportMenu extends StatelessWidget { return GestureDetector( onTap: onPressed, child: Container( - margin: const EdgeInsets.all(5.0), - width: 180.0, - height: 160.0, - alignment: Alignment.center, + padding: const EdgeInsets.all(12.0), decoration: BoxDecoration( - color: - isActive ? AppColors.primary.withOpacity(0.13) : AppColors.white, - borderRadius: BorderRadius.circular(18.0), - border: Border.all( - color: isActive ? AppColors.primary : AppColors.stroke, + border: Border( + right: BorderSide( + color: isActive ? AppColors.primary : Colors.transparent, + width: 4.0, + ), ), ), - child: Column( - mainAxisAlignment: MainAxisAlignment.end, + child: Row( children: [ - Assets.icons.report.svg( - colorFilter: isActive - ? const ColorFilter.mode( - AppColors.primary, - BlendMode.srcIn, - ) - : null, + Icon( + icon, + size: 24.0, + color: isActive ? AppColors.primary : AppColors.grey, ), - const SpaceHeight(28.0), - Text( - label, - style: TextStyle( - color: isActive ? AppColors.primary : AppColors.black, - fontWeight: FontWeight.w600, + const SpaceWidth(12), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + label, + style: const TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 4.0), + Text( + subtitle, + style: + const TextStyle(fontSize: 14.0, color: AppColors.grey), + ), + ], ), ), - const SpaceHeight(24.0), ], ), ), diff --git a/lib/presentation/report/widgets/report_page_title.dart b/lib/presentation/report/widgets/report_page_title.dart new file mode 100644 index 0000000..ffe78d6 --- /dev/null +++ b/lib/presentation/report/widgets/report_page_title.dart @@ -0,0 +1,65 @@ +import 'package:enaklo_pos/core/constants/colors.dart'; +import 'package:flutter/material.dart'; + +class ReportPageTitle extends StatelessWidget { + final String title; + final String searchDateFormatted; + final Function() onExport; + final bool isExport; + const ReportPageTitle( + {super.key, + required this.title, + required this.searchDateFormatted, + required this.onExport, + this.isExport = true}); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.all(16.0), + decoration: BoxDecoration(color: AppColors.white), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + style: const TextStyle( + fontWeight: FontWeight.w800, fontSize: 16.0), + ), + const SizedBox( + height: 8.0, + ), + Text( + searchDateFormatted, + style: const TextStyle(fontSize: 16.0), + ), + ], + ), + if (isExport) + GestureDetector( + onTap: onExport, + child: const Row( + children: [ + Text( + "PDF", + style: TextStyle( + fontSize: 14.0, + fontWeight: FontWeight.bold, + color: AppColors.primary, + ), + ), + Icon( + Icons.download_outlined, + color: AppColors.primary, + ) + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/presentation/report/widgets/report_title.dart b/lib/presentation/report/widgets/report_title.dart index 06e3f21..30ab197 100644 --- a/lib/presentation/report/widgets/report_title.dart +++ b/lib/presentation/report/widgets/report_title.dart @@ -1,38 +1,60 @@ +import 'package:enaklo_pos/core/extensions/build_context_ext.dart'; import 'package:flutter/material.dart'; -import 'package:enaklo_pos/core/components/components.dart'; import 'package:enaklo_pos/core/extensions/date_time_ext.dart'; import '../../../core/constants/colors.dart'; - - class ReportTitle extends StatelessWidget { - const ReportTitle({super.key}); + final List? actionWidget; + const ReportTitle({super.key, this.actionWidget}); @override Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text( - 'Report', - style: TextStyle( - color: AppColors.primary, - fontSize: 28, - fontWeight: FontWeight.w600, + return Container( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + vertical: 10.0, + ), + width: double.infinity, + height: context.deviceHeight * 0.1, + decoration: const BoxDecoration( + color: AppColors.white, + border: Border( + bottom: BorderSide( + color: AppColors.background, + width: 1.0, ), ), - const SpaceHeight(4.0), - Text( - DateTime.now().toFormattedDate(), - style: const TextStyle( - color: AppColors.subtitle, - fontSize: 16, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Laporan', + style: TextStyle( + color: AppColors.black, + fontSize: 20, + fontWeight: FontWeight.w600, + ), + ), + Text( + DateTime.now().toFormattedDate2(), + style: TextStyle( + color: AppColors.grey, + fontSize: 14, + ), + ), + ], ), - ), - const SpaceHeight(20.0), - const Divider(), - ], + if (actionWidget != null) + Row( + children: actionWidget!, + ), + ], + ), ); } } diff --git a/lib/presentation/report/widgets/summary_report_widget.dart b/lib/presentation/report/widgets/summary_report_widget.dart index 677f51e..cdf77a3 100644 --- a/lib/presentation/report/widgets/summary_report_widget.dart +++ b/lib/presentation/report/widgets/summary_report_widget.dart @@ -9,7 +9,6 @@ import 'package:enaklo_pos/core/utils/helper_pdf_service.dart'; import 'package:enaklo_pos/core/utils/permession_handler.dart'; import 'package:enaklo_pos/data/models/response/summary_response_model.dart'; import 'package:flutter/material.dart'; -import 'package:permission_handler/permission_handler.dart'; import '../../../core/utils/revenue_invoice.dart'; @@ -55,27 +54,29 @@ class SummaryReportWidget extends StatelessWidget { log("PDF button clicked for summary report"); try { log("Checking permissions..."); - final status = await PermessionHelper().checkPermission(); + final status = + await PermessionHelper().checkPermission(); log("Permission status: $status"); - + if (status) { log("Permission granted, starting PDF generation..."); log("Summary data: ${summary.toMap()}"); log("Search date: $searchDateFormatted"); - + final pdfFile = await RevenueInvoice.generate( summary, searchDateFormatted); log("PDF file generated: ${pdfFile.path}"); log("PDF file exists: ${await pdfFile.exists()}"); log("PDF file size: ${await pdfFile.length()} bytes"); - + log("Attempting to open PDF file..."); await HelperPdfService.openFile(pdfFile); log("PDF file opened successfully"); - + ScaffoldMessenger.of(context).showSnackBar( SnackBar( - content: Text('PDF saved successfully: ${pdfFile.path}'), + content: Text( + 'PDF saved successfully: ${pdfFile.path}'), backgroundColor: Colors.green, ), ); @@ -83,7 +84,8 @@ class SummaryReportWidget extends StatelessWidget { log("Permission denied"); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( - content: Text('Storage permission is required to save PDF'), + content: Text( + 'Storage permission is required to save PDF'), backgroundColor: Colors.red, ), ); diff --git a/lib/presentation/report/widgets/transaction_report_widget.dart b/lib/presentation/report/widgets/transaction_report_widget.dart index 9665ab1..ffab5f7 100644 --- a/lib/presentation/report/widgets/transaction_report_widget.dart +++ b/lib/presentation/report/widgets/transaction_report_widget.dart @@ -5,12 +5,12 @@ import 'package:enaklo_pos/core/constants/colors.dart'; import 'package:enaklo_pos/core/extensions/date_time_ext.dart'; import 'package:enaklo_pos/core/extensions/int_ext.dart'; import 'package:enaklo_pos/core/utils/helper_pdf_service.dart'; +import 'package:enaklo_pos/presentation/report/widgets/report_page_title.dart'; import 'package:flutter/material.dart'; import 'package:enaklo_pos/core/utils/permession_handler.dart'; import 'package:enaklo_pos/core/utils/transaction_sales_invoice.dart'; import 'package:enaklo_pos/data/models/response/order_remote_datasource.dart'; import 'package:horizontal_data_table/horizontal_data_table.dart'; -import 'package:permission_handler/permission_handler.dart'; class TransactionReportWidget extends StatelessWidget { final String title; @@ -27,208 +27,168 @@ class TransactionReportWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return Card( - color: const Color.fromARGB(255, 255, 255, 255), - child: Column( - children: [ - const SpaceHeight(24.0), - Center( - child: Text( - title, - style: - const TextStyle(fontWeight: FontWeight.w800, fontSize: 16.0), - ), - ), - const SizedBox( - height: 8.0, - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 12), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - searchDateFormatted, - style: const TextStyle(fontSize: 16.0), + return Column( + children: [ + ReportPageTitle( + title: title, + searchDateFormatted: searchDateFormatted, + onExport: () async { + try { + final status = await PermessionHelper().checkPermission(); + if (status) { + final pdfFile = await TransactionSalesInvoice.generate( + transactionReport, searchDateFormatted); + log("pdfFile: $pdfFile"); + await HelperPdfService.openFile(pdfFile); + } else { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Storage permission is required to save PDF'), + backgroundColor: Colors.red, + ), + ); + } + } catch (e) { + log("Error generating PDF: $e"); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text('Failed to generate PDF: $e'), + backgroundColor: Colors.red, ), - GestureDetector( - onTap: () async { - try { - final status = await PermessionHelper().checkPermission(); - if (status) { - final pdfFile = await TransactionSalesInvoice.generate( - transactionReport, searchDateFormatted); - log("pdfFile: $pdfFile"); - await HelperPdfService.openFile(pdfFile); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Storage permission is required to save PDF'), - backgroundColor: Colors.red, + ); + } + }, + ), + const SpaceHeight(16.0), + Expanded( + child: Padding( + padding: const EdgeInsets.all(12), + child: ClipRRect( + borderRadius: BorderRadius.circular(12), + child: HorizontalDataTable( + leftHandSideColumnWidth: 50, + rightHandSideColumnWidth: 1020, + isFixedHeader: true, + headerWidgets: headerWidgets, + // isFixedFooter: true, + // footerWidgets: _getTitleWidget(), + leftSideItemBuilder: (context, index) { + return Container( + width: 40, + height: 52, + alignment: Alignment.centerLeft, + child: Center( + child: Text(transactionReport[index].id.toString())), + ); + }, + rightSideItemBuilder: (context, index) { + return Row( + children: [ + Container( + width: 120, + height: 52, + padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), + alignment: Alignment.centerLeft, + child: Center( + child: Text( + transactionReport[index].total!.currencyFormatRp, + )), + ), + Container( + width: 120, + height: 52, + padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), + alignment: Alignment.centerLeft, + child: Center( + child: Text( + transactionReport[index].subTotal!.currencyFormatRp, + )), + ), + Container( + width: 100, + height: 52, + padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), + alignment: Alignment.centerLeft, + child: Center( + child: Text( + transactionReport[index].tax!.currencyFormatRp, + )), + ), + Container( + width: 100, + height: 52, + padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), + alignment: Alignment.centerLeft, + child: Center( + child: Text( + int.parse(transactionReport[index] + .discountAmount! + .replaceAll('.00', '')) + .currencyFormatRp, ), - ); - } - } catch (e) { - log("Error generating PDF: $e"); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text('Failed to generate PDF: $e'), - backgroundColor: Colors.red, - ), - ); - } - }, - child: const Row( - children: [ - Text( - "PDF", - style: TextStyle( - fontSize: 14.0, - fontWeight: FontWeight.bold, - color: AppColors.primary, ), ), - Icon( - Icons.download_outlined, - color: AppColors.primary, - ) + Container( + width: 100, + height: 52, + padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), + alignment: Alignment.centerLeft, + child: Center( + child: Text( + transactionReport[index] + .serviceCharge! + .currencyFormatRp, + ), + ), + ), + Container( + width: 100, + height: 52, + padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), + alignment: Alignment.centerLeft, + child: Center( + child: Text( + transactionReport[index].totalItem.toString()), + ), + ), + Container( + width: 150, + height: 52, + padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), + alignment: Alignment.centerLeft, + child: Center( + child: Text(transactionReport[index].namaKasir!), + ), + ), + Container( + width: 230, + height: 52, + padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), + alignment: Alignment.centerLeft, + child: Center( + child: Text(transactionReport[index] + .transactionTime! + .toFormattedDate()), + ), + ), ], - ), + ); + }, + itemCount: transactionReport.length, + rowSeparatorWidget: const Divider( + color: Colors.black38, + height: 1.0, + thickness: 0.0, ), - ], - ), - ), - const SpaceHeight(16.0), - Expanded( - child: Padding( - padding: const EdgeInsets.all(12), - child: ClipRRect( - borderRadius: BorderRadius.circular(12), - child: HorizontalDataTable( - leftHandSideColumnWidth: 50, - rightHandSideColumnWidth: 1020, - isFixedHeader: true, - headerWidgets: headerWidgets, - // isFixedFooter: true, - // footerWidgets: _getTitleWidget(), - leftSideItemBuilder: (context, index) { - return Container( - width: 40, - height: 52, - alignment: Alignment.centerLeft, - child: Center( - child: Text(transactionReport[index].id.toString())), - ); - }, - rightSideItemBuilder: (context, index) { - return Row( - children: [ - Container( - width: 120, - height: 52, - padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), - alignment: Alignment.centerLeft, - child: Center( - child: Text( - transactionReport[index].total!.currencyFormatRp, - )), - ), - Container( - width: 120, - height: 52, - padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), - alignment: Alignment.centerLeft, - child: Center( - child: Text( - transactionReport[index].subTotal!.currencyFormatRp, - )), - ), - Container( - width: 100, - height: 52, - padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), - alignment: Alignment.centerLeft, - child: Center( - child: Text( - transactionReport[index].tax!.currencyFormatRp, - )), - ), - Container( - width: 100, - height: 52, - padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), - alignment: Alignment.centerLeft, - child: Center( - child: Text( - int.parse(transactionReport[index] - .discountAmount! - .replaceAll('.00', '')) - .currencyFormatRp, - ), - ), - ), - Container( - width: 100, - height: 52, - padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), - alignment: Alignment.centerLeft, - child: Center( - child: Text( - transactionReport[index] - .serviceCharge! - .currencyFormatRp, - ), - ), - ), - Container( - width: 100, - height: 52, - padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), - alignment: Alignment.centerLeft, - child: Center( - child: Text( - transactionReport[index].totalItem.toString()), - ), - ), - Container( - width: 150, - height: 52, - padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), - alignment: Alignment.centerLeft, - child: Center( - child: Text(transactionReport[index].namaKasir!), - ), - ), - Container( - width: 230, - height: 52, - padding: const EdgeInsets.fromLTRB(5, 0, 0, 0), - alignment: Alignment.centerLeft, - child: Center( - child: Text(transactionReport[index] - .transactionTime! - .toFormattedDate()), - ), - ), - ], - ); - }, - itemCount: transactionReport.length, - rowSeparatorWidget: const Divider( - color: Colors.black38, - height: 1.0, - thickness: 0.0, - ), - leftHandSideColBackgroundColor: AppColors.white, - rightHandSideColBackgroundColor: AppColors.white, + leftHandSideColBackgroundColor: AppColors.white, + rightHandSideColBackgroundColor: AppColors.white, - itemExtent: 55, - ), + itemExtent: 55, ), ), ), - ], - ), + ), + ], ); } } diff --git a/lib/presentation/sales/pages/sales_page.dart b/lib/presentation/sales/pages/sales_page.dart index 648ef0a..30b14d5 100644 --- a/lib/presentation/sales/pages/sales_page.dart +++ b/lib/presentation/sales/pages/sales_page.dart @@ -32,7 +32,7 @@ class _SalesPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( - 'Enaklo POS ', + 'Apskel POS ', style: TextStyle( color: AppColors.primary, fontSize: 22, diff --git a/lib/presentation/setting/pages/manage_printer_page.dart b/lib/presentation/setting/pages/manage_printer_page.dart index 3172b29..a8f936a 100644 --- a/lib/presentation/setting/pages/manage_printer_page.dart +++ b/lib/presentation/setting/pages/manage_printer_page.dart @@ -171,8 +171,7 @@ class _ManagePrinterPageState extends State { //bytes += generator.setGlobalFont(PosFontType.fontA); bytes += generator.reset(); - bytes += - generator.text('Enaklo POS', styles: const PosStyles(bold: true)); + bytes += generator.text('Apskel POS', styles: const PosStyles(bold: true)); bytes += generator.text('Reverse text', styles: const PosStyles(reverse: true)); bytes += generator.text('Underlined text', diff --git a/pubspec.yaml b/pubspec.yaml index f750bf1..1687d2e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: enaklo_pos -description: "EnakloPOS - Point of Sale Application" +description: "ApskelPOS - Point of Sale Application" # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: "none" # Remove this line if you wish to publish to pub.dev