import 'package:intl/intl.dart'; import '../models/invoice_models.dart'; import '../models/receivable_models.dart'; import 'database_helper.dart'; class ReceivableRepository { ReceivableRepository(); final DatabaseHelper _dbHelper = DatabaseHelper(); final DateFormat _invoiceNumberDateFormat = DateFormat('yyyyMMdd'); Future> fetchSummaries({bool includeSettled = false}) async { final db = await _dbHelper.database; final rows = await db.rawQuery(''' SELECT i.id, i.customer_formal_name, i.date, i.total_amount, i.document_type, i.terminal_id, COALESCE(SUM(p.amount), 0) AS paid_amount FROM invoices i LEFT JOIN receivable_payments p ON p.invoice_id = i.id WHERE i.document_type = ? AND COALESCE(i.is_draft, 0) = 0 GROUP BY i.id HAVING (? = 1) OR (i.total_amount - COALESCE(SUM(p.amount), 0)) > 0 ORDER BY i.date DESC ''', [DocumentType.invoice.name, includeSettled ? 1 : 0]); return rows.map(_mapToSummary).toList(); } Future findSummaryById(String invoiceId) async { final db = await _dbHelper.database; final rows = await db.rawQuery(''' SELECT i.id, i.customer_formal_name, i.date, i.total_amount, i.document_type, i.terminal_id, COALESCE(SUM(p.amount), 0) AS paid_amount FROM invoices i LEFT JOIN receivable_payments p ON p.invoice_id = i.id WHERE i.id = ? GROUP BY i.id LIMIT 1 ''', [invoiceId]); if (rows.isEmpty) return null; return _mapToSummary(rows.first); } Future> fetchPayments(String invoiceId) async { final db = await _dbHelper.database; final rows = await db.query( 'receivable_payments', where: 'invoice_id = ?', whereArgs: [invoiceId], orderBy: 'payment_date DESC, created_at DESC', ); return rows.map(ReceivablePayment.fromMap).toList(); } Future findPaymentById(String paymentId) async { final db = await _dbHelper.database; final rows = await db.query( 'receivable_payments', where: 'id = ?', whereArgs: [paymentId], limit: 1, ); if (rows.isEmpty) return null; return ReceivablePayment.fromMap(rows.first); } Future insertPayment(ReceivablePayment payment) async { final db = await _dbHelper.database; await db.insert('receivable_payments', payment.toMap()); } Future deletePayment(String paymentId) async { final db = await _dbHelper.database; await db.delete('receivable_payments', where: 'id = ?', whereArgs: [paymentId]); } ReceivableInvoiceSummary _mapToSummary(Map row) { final invoiceDate = DateTime.parse(row['date'] as String); final dueDate = invoiceDate.add(const Duration(days: 30)); final totalAmount = row['total_amount'] as int? ?? 0; final paidAmount = row['paid_amount'] as int? ?? 0; final documentType = DocumentType.values.firstWhere( (type) => type.name == row['document_type'], orElse: () => DocumentType.invoice, ); final invoiceNumber = _buildInvoiceNumber( prefix: _documentPrefix(documentType), terminalId: row['terminal_id'] as String? ?? 'T1', invoiceDate: invoiceDate, id: row['id'] as String, ); return ReceivableInvoiceSummary( invoiceId: row['id'] as String, invoiceNumber: invoiceNumber, customerName: row['customer_formal_name'] as String? ?? '-', invoiceDate: invoiceDate, dueDate: dueDate, totalAmount: totalAmount, paidAmount: paidAmount, ); } String _buildInvoiceNumber({ required String prefix, required String terminalId, required DateTime invoiceDate, required String id, }) { final suffix = id.length >= 4 ? id.substring(id.length - 4) : id; final datePart = _invoiceNumberDateFormat.format(invoiceDate); return '$prefix-$terminalId-$datePart-$suffix'; } String _documentPrefix(DocumentType type) { switch (type) { case DocumentType.estimation: return 'EST'; case DocumentType.delivery: return 'DEL'; case DocumentType.invoice: return 'INV'; case DocumentType.receipt: return 'REC'; } } }