first commit

This commit is contained in:
2026-02-07 15:57:09 +07:00
commit 157096f164
1153 changed files with 415766 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
Map<String, String> getPdfDateRangeForSelectedTime(
String selectedTime, {
DateTime? fromDate,
DateTime? toDate,
}) {
DateTime now = DateTime.now();
DateTime start;
DateTime end;
switch (selectedTime.toLowerCase()) {
case 'today':
start = DateTime(now.year, now.month, now.day);
end = start;
break;
case 'yesterday':
start = DateTime(now.year, now.month, now.day).subtract(const Duration(days: 1));
end = start;
break;
case 'last_seven_days':
end = now;
start = now.subtract(const Duration(days: 6));
break;
case 'last_thirty_days':
end = now;
start = now.subtract(const Duration(days: 29));
break;
case 'current_month':
start = DateTime(now.year, now.month, 1);
end = DateTime(now.year, now.month + 1, 0);
break;
case 'last_month':
final lastMonth = DateTime(now.year, now.month - 1, 1);
start = lastMonth;
end = DateTime(lastMonth.year, lastMonth.month + 1, 0);
break;
case 'current_year':
start = DateTime(now.year, 1, 1);
end = DateTime(now.year, 12, 31);
break;
case 'custom_date':
start = fromDate ?? now;
end = toDate ?? now;
break;
default:
start = now;
end = now;
}
final fromStr = "${start.day.toString().padLeft(2, '0')}-"
"${start.month.toString().padLeft(2, '0')}-"
"${start.year}";
final toStr = "${end.day.toString().padLeft(2, '0')}-"
"${end.month.toString().padLeft(2, '0')}-"
"${end.year}";
return {'from': fromStr, 'to': toStr};
}

View File

@@ -0,0 +1,297 @@
import 'dart:io';
import 'package:excel/excel.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:intl/intl.dart';
import 'package:mobile_pos/constant.dart';
import 'package:open_file/open_file.dart';
import 'package:path_provider/path_provider.dart';
import '../../Screens/party ledger/model/party_ledger_model.dart';
import '../../model/business_info_model.dart';
import 'generate_pdf_date_range.dart';
Future<void> generateLedgerReportExcel(
BuildContext context,
List<PartyLedgerModel>? data,
BusinessInformationModel business,
DateTime? fromDate,
DateTime? toDate,
String selectedTime,
) async {
EasyLoading.show(status: 'Generating Excel');
try {
if (data == null || data.isEmpty) {
EasyLoading.showInfo('No transactions available');
return;
}
// Create Excel
final excel = Excel.createExcel();
final sheet = excel['Party Ledger'];
// ---------------------------
// CALCULATE TOTALS
// ---------------------------
double creditBalance = 0;
double debitBalance = 0;
// for (var item in data) {
// if (item.type == 'credit') {
// creditBalance += item.amount ?? 0;
// } else {
// debitBalance += item.amount ?? 0;
// }
// }
for (var item in data) {
creditBalance += item.creditAmount ?? 0;
}
for (var item in data) {
debitBalance += item.debitAmount ?? 0;
}
// ---------------------------
// DATE RANGE (same as PDF)
// ---------------------------
final pdfRange = getPdfDateRangeForSelectedTime(
selectedTime,
fromDate: fromDate,
toDate: toDate,
);
final fromStr = pdfRange['from']!;
final toStr = pdfRange['to']!;
// ---------------------------
// HEADER SECTION
// ---------------------------
sheet.appendRow([
// TextCellValue(business.data?.companyName ?? ''),
TextCellValue(appsName),
]);
sheet.appendRow([
TextCellValue('Party Ledger'),
]);
sheet.appendRow([
TextCellValue('Duration: $fromStr to $toStr'),
]);
sheet.appendRow([]); // empty space row
// ---------------------------
// TABLE HEADER
// ---------------------------
final headerRow = sheet.maxRows;
sheet.appendRow([
TextCellValue('Date'),
TextCellValue('Reference No'),
TextCellValue('Description'),
TextCellValue('Credit'),
TextCellValue('Debit'),
TextCellValue('Balance'),
]);
// Style header row (bold)
for (int col = 0; col < 6; col++) {
final cell = sheet.cell(
CellIndex.indexByColumnRow(columnIndex: col, rowIndex: headerRow),
);
cell.cellStyle = CellStyle(bold: true);
}
sheet.appendRow([]);
// ---------------------------
// TABLE DATA
// ---------------------------
for (var item in data) {
bool isOpening = item.platform == 'opening_balance';
sheet.appendRow([
TextCellValue(DateFormat('dd-MM-yyyy').format(DateTime.parse(item.date.toString()))),
TextCellValue(item.invoiceNumber ?? ''),
TextCellValue(
isOpening ? "Opening" : item.platform?.replaceAll('_', ' ') ?? 'Transaction',
),
TextCellValue((item.creditAmount ?? 0).toStringAsFixed(2)),
TextCellValue((item.debitAmount ?? 0).toStringAsFixed(2)),
TextCellValue((item.balance ?? 0).toStringAsFixed(2)),
]);
}
// ---------------------------
// TOTAL ROW
// ---------------------------
final totalRow = sheet.maxRows;
sheet.appendRow([
TextCellValue(''),
TextCellValue(''),
TextCellValue('Total'),
TextCellValue(creditBalance.toStringAsFixed(2)),
TextCellValue(debitBalance.toStringAsFixed(2)),
TextCellValue((data.last.balance ?? 0).toStringAsFixed(2)),
]);
// Make TOTAL row bold
for (int col = 0; col < 6; col++) {
final cell = sheet.cell(
CellIndex.indexByColumnRow(columnIndex: col, rowIndex: totalRow),
);
cell.cellStyle = CellStyle(bold: true);
}
// ---------------------------
// SAVE FILE
// ---------------------------
final dir = await getApplicationDocumentsDirectory();
final timestamp = DateTime.now().millisecondsSinceEpoch;
final filePath = '${dir.path}/${business.data?.companyName ?? "Company"}_Ledger_Report_$timestamp.xlsx';
final file = File(filePath);
await file.writeAsBytes(excel.encode()!);
EasyLoading.showSuccess('Excel Generated Successfully!');
await OpenFile.open(filePath);
} catch (e) {
EasyLoading.showError("Error: $e");
debugPrint("Excel Error: $e");
}
}
// Future<void> generateLedgerReportExcel(
// BuildContext context,
// List<PartyLedgerModel>? data,
// BusinessInformationModel? business,
// DateTime? fromDate,
// DateTime? toDate,
// ) async {
// EasyLoading.show(status: 'Generating Excel');
//
// try {
// if (data == null) {
// EasyLoading.showError('Invalid data provided');
// return;
// }
//
// // Create Excel file & sheet
// final excel = Excel.createExcel();
// final sheet = excel['Party Ledger'];
//
// double creditBalance = 0;
// double debitBalance = 0;
//
// for (var item in data) {
// if (item.type == 'credit') {
// creditBalance += item.amount ?? 0;
// } else {
// debitBalance += item.amount ?? 0;
// }
// }
//
// // ---------------------------
// // HEADER SECTION
// // ---------------------------
//
// // Row 1: Company Name
// sheet.appendRow([
// TextCellValue(business?.data?.companyName ?? ''),
// ]);
//
// // Row 2: Report Title
// sheet.appendRow([
// TextCellValue('Party Ledger'),
// ]);
//
// // Row 3: Date Range
// if (fromDate != null && toDate != null) {
// final String formattedFrom = DateFormat('dd-MM-yyyy').format(fromDate);
// final String formattedTo = DateFormat('dd-MM-yyyy').format(toDate);
//
// sheet.appendRow([
// TextCellValue('Duration: $formattedFrom to $formattedTo'),
// ]);
// }
//
// // Empty row
// sheet.appendRow([]);
//
// // ---------------------------
// // LEDGER TABLE HEADER
// // ---------------------------
// final headerRowIndex = sheet.maxRows;
//
// sheet.appendRow([
// TextCellValue('Date'),
// TextCellValue('Invoice No'),
// TextCellValue('Details'),
// TextCellValue('Credit'),
// TextCellValue('Debit'),
// TextCellValue('Balance'),
// ]);
//
// // Add space row
// sheet.appendRow([]);
//
// // Apply bold style on table header
// for (var i = 0; i < 6; i++) {
// sheet.cell(CellIndex.indexByColumnRow(columnIndex: i, rowIndex: headerRowIndex)).cellStyle;
// }
//
// // ---------------------------
// // LEDGER TABLE BODY
// // ---------------------------
// for (int i = 0; i < data.length; i++) {
// final item = data[i];
// final isOpening = item.platform == 'opening_balance';
//
// sheet.appendRow([
// TextCellValue(item.date ?? 'n/a'),
// TextCellValue(item.invoiceNumber ?? ''),
// TextCellValue(isOpening ? "Opening" : item.platform?.replaceAll('_', ' ') ?? 'Transaction'),
// TextCellValue(item.type == 'credit' ? (item.amount ?? 0).toStringAsFixed(2) : '0.00'),
// TextCellValue(item.type != 'credit' ? (item.amount ?? 0).toStringAsFixed(2) : '0.00'),
// TextCellValue((item.balance ?? 0).toStringAsFixed(2)),
// ]);
// }
//
// // ---------------------------
// // TOTAL ROW
// // ---------------------------
// final totalRowIndex = sheet.maxRows;
//
// sheet.appendRow([
// TextCellValue(''),
// TextCellValue(''),
// TextCellValue('Total'),
// TextCellValue(creditBalance.toStringAsFixed(2)),
// TextCellValue(debitBalance.toStringAsFixed(2)),
// TextCellValue((data.last.balance ?? 0).toStringAsFixed(2)),
// ]);
//
// // Make total row bold
// for (var i = 0; i < 6; i++) {
// sheet.cell(CellIndex.indexByColumnRow(columnIndex: i, rowIndex: totalRowIndex)).cellStyle;
// }
//
// // ---------------------------
// // SAVE FILE
// // ---------------------------
// final dir = await getApplicationDocumentsDirectory();
// final filePath = '${dir.path}/${business?.data?.companyName ?? "Company"}_Ledger_Report.xlsx';
//
// final file = File(filePath);
// await file.writeAsBytes(excel.encode()!);
//
// EasyLoading.showSuccess('Ledger Excel Generated!');
// await OpenFile.open(filePath);
// } catch (e) {
// EasyLoading.showError('Error: $e');
// debugPrint('Ledger Excel Error: $e');
// }
// }

View File

@@ -0,0 +1,216 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:intl/intl.dart';
import 'package:mobile_pos/Screens/Customers/Model/parties_model.dart';
import 'package:mobile_pos/Screens/Products/Model/product_model.dart';
import 'package:mobile_pos/Screens/party%20ledger/model/party_ledger_model.dart';
import 'package:mobile_pos/constant.dart';
import 'package:path_provider/path_provider.dart';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:printing/printing.dart';
import '../../Screens/PDF/pdf.dart';
import '../../Screens/Products/Model/product_total_stock_model.dart';
import '../../currency.dart';
import '../../model/business_info_model.dart';
import 'generate_pdf_date_range.dart';
Future<void> generateLedgerReportPdf(
BuildContext context,
List<PartyLedgerModel>? data,
BusinessInformationModel business,
DateTime? fromDate,
DateTime? toDate,
String selectedTime, // pass selected filter
) async {
if (data == null || data.isEmpty) {
EasyLoading.showInfo('No transactions to generate PDF');
return;
}
final pdf = pw.Document();
try {
EasyLoading.show(status: 'Generating PDF...');
double creditBalance = 0;
double debitBalance = 0;
// for (var item in data) {
// if (item.type == 'credit') creditBalance += item.amount ?? 0;
// if (item.type != 'credit') debitBalance += item.amount ?? 0;
// }
for (var item in data) {
creditBalance += item.creditAmount ?? 0;
}
for (var item in data) {
debitBalance += item.debitAmount ?? 0;
}
// Calculate correct PDF date range
final pdfDateRange = getPdfDateRangeForSelectedTime(
selectedTime,
fromDate: fromDate,
toDate: toDate,
);
final fromDateStr = pdfDateRange['from']!;
final toDateStr = pdfDateRange['to']!;
pdf.addPage(
pw.MultiPage(
pageFormat: PdfPageFormat.letter.copyWith(marginBottom: 1.5 * PdfPageFormat.cm),
margin: const pw.EdgeInsets.symmetric(horizontal: 16),
header: (context) => pw.Center(
child: pw.Column(
children: [
pw.Text(appsName, style: pw.TextStyle(fontSize: 20, fontWeight: pw.FontWeight.bold)),
pw.Text('Party Ledger', style: pw.TextStyle(fontSize: 16, fontWeight: pw.FontWeight.bold)),
pw.SizedBox(height: 2),
pw.Text('$fromDateStr TO $toDateStr', style: const pw.TextStyle(fontSize: 14)),
pw.SizedBox(height: 4),
],
),
),
footer: (pw.Context context) {
return pw.Row(
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
children: [
pw.Text('${business.data?.developByLevel ?? ''} ${business.data?.developBy ?? ''}'),
pw.Text('Page-${context.pageNumber}'),
],
);
},
build: (pw.Context context) {
final List<List<String>> tableData = [];
for (int i = 0; i < data.length; i++) {
final isOpening = data[i].platform == 'opening_balance';
// final stockPrice = (data[i].stocks != null && data[i].stocks!.isNotEmpty) ? data[i].stocks!.last.productPurchasePrice?.toString() ?? '0' : '0';
tableData.add([
DateFormat('dd-MM-yyyy').format(DateTime.parse(data[i].date.toString())),
data[i].invoiceNumber ?? '--',
isOpening ? "Opening" : (data[i].platform?.replaceAll('_', ' ') ?? 'Transaction'),
'$currency${data[i].creditAmount ?? 0}',
'$currency${data[i].debitAmount ?? 0}',
'$currency${data[i].balance ?? 0}',
]);
}
return [
pw.SizedBox(height: 16),
pw.Table.fromTextArray(
headers: [
'Date',
'Reference No',
'Description',
'Credit',
'Debit',
'Balance',
],
data: tableData,
headerDecoration: const pw.BoxDecoration(
color: PdfColor.fromInt(0xffF7F7F7),
),
border: pw.TableBorder.all(color: PdfColor.fromInt(0xffD9D9D9)),
headerStyle: pw.TextStyle(
fontWeight: pw.FontWeight.bold,
color: PdfColors.black,
),
rowDecoration: const pw.BoxDecoration(
color: PdfColors.white,
),
// oddRowDecoration: pw.BoxDecoration(
// color: PdfColor.fromInt(0xffF7F7F7),
// ),
cellPadding: const pw.EdgeInsets.all(8),
columnWidths: {
0: const pw.FlexColumnWidth(3),
1: const pw.FlexColumnWidth(4),
2: const pw.FlexColumnWidth(4),
3: const pw.FlexColumnWidth(3),
4: const pw.FlexColumnWidth(3),
5: const pw.FlexColumnWidth(3),
},
cellAlignments: {
0: pw.Alignment.center,
1: pw.Alignment.center,
2: pw.Alignment.center,
3: pw.Alignment.center,
4: pw.Alignment.center,
5: pw.Alignment.center,
},
),
pw.Table.fromTextArray(
border: pw.TableBorder.all(color: PdfColor.fromInt(0xffD9D9D9)),
columnWidths: {
0: const pw.FlexColumnWidth(3),
1: const pw.FlexColumnWidth(4),
2: const pw.FlexColumnWidth(4),
3: const pw.FlexColumnWidth(3),
4: const pw.FlexColumnWidth(3),
5: const pw.FlexColumnWidth(3),
},
cellAlignments: {
0: pw.Alignment.center,
1: pw.Alignment.center,
2: pw.Alignment.center,
3: pw.Alignment.center,
4: pw.Alignment.center,
5: pw.Alignment.center,
},
data: [
[
'',
'',
'Total',
creditBalance,
debitBalance,
data.last.balance,
]
],
// headerDecoration: const pw.BoxDecoration(
// color: PdfColor.fromInt(0xffF7F7F7),
// ),
headerStyle: pw.TextStyle(
fontWeight: pw.FontWeight.bold,
color: PdfColors.black,
),
cellAlignment: pw.Alignment.center,
cellPadding: const pw.EdgeInsets.all(8),
),
];
},
),
);
final bytes = await pdf.save();
final dir = await getApplicationDocumentsDirectory();
final timestamp = DateTime.now().millisecondsSinceEpoch;
final file = File('${dir.path}/$appsName-leger-report-$timestamp.pdf');
await file.writeAsBytes(bytes);
await EasyLoading.dismiss();
if (context.mounted) {
await Printing.layoutPdf(
name: 'Leger Report',
usePrinterSettings: true,
dynamicLayout: true,
forceCustomPrintPaper: true,
onLayout: (PdfPageFormat format) async => pdf.save(),
);
}
// if (context.mounted) {
// Navigator.push(context, MaterialPageRoute(builder: (_) => PDFViewerPage(path: file.path)));
// }
} catch (e) {
await EasyLoading.dismiss();
EasyLoading.showError('Failed to generate PDF: $e');
}
}