h-1.flutter.0/lib/services/receivable_repository.dart
2026-03-04 14:55:40 +09:00

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';
}
}
}