126 lines
4.2 KiB
Dart
126 lines
4.2 KiB
Dart
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<List<ReceivableInvoiceSummary>> 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<ReceivableInvoiceSummary?> 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<List<ReceivablePayment>> 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<ReceivablePayment?> 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<void> insertPayment(ReceivablePayment payment) async {
|
|
final db = await _dbHelper.database;
|
|
await db.insert('receivable_payments', payment.toMap());
|
|
}
|
|
|
|
Future<void> deletePayment(String paymentId) async {
|
|
final db = await _dbHelper.database;
|
|
await db.delete('receivable_payments', where: 'id = ?', whereArgs: [paymentId]);
|
|
}
|
|
|
|
ReceivableInvoiceSummary _mapToSummary(Map<String, Object?> 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';
|
|
}
|
|
}
|
|
}
|