134 lines
3.4 KiB
Dart
134 lines
3.4 KiB
Dart
import 'package:pocketbase/pocketbase.dart';
|
|
|
|
import '../api/pocketbase_client.dart';
|
|
|
|
class FinanceService {
|
|
FinanceService._();
|
|
static final instance = FinanceService._();
|
|
|
|
PocketBase get _pb => PocketBaseClient.instance.pb;
|
|
|
|
Future<void> ensureEntriesForJob({
|
|
required String jobId,
|
|
required String clinicTenantId,
|
|
required String labTenantId,
|
|
required String clinicName,
|
|
required String labName,
|
|
required double amount,
|
|
required String currency,
|
|
}) async {
|
|
if (amount <= 0) return;
|
|
|
|
final existing = await _pb.collection('finance_entries').getFullList(
|
|
filter: 'job_id = "$jobId"',
|
|
batch: 200,
|
|
);
|
|
|
|
await _upsertEntry(
|
|
existing: existing,
|
|
jobId: jobId,
|
|
tenantId: clinicTenantId,
|
|
counterpartyTenantId: labTenantId,
|
|
counterpartyName: labName,
|
|
type: 'payable',
|
|
amount: amount,
|
|
currency: currency,
|
|
);
|
|
|
|
await _upsertEntry(
|
|
existing: existing,
|
|
jobId: jobId,
|
|
tenantId: labTenantId,
|
|
counterpartyTenantId: clinicTenantId,
|
|
counterpartyName: clinicName,
|
|
type: 'receivable',
|
|
amount: amount,
|
|
currency: currency,
|
|
);
|
|
}
|
|
|
|
Future<void> reportJobPayment(String jobId) async {
|
|
final existing = await _pb.collection('finance_entries').getFullList(
|
|
filter: 'job_id = "$jobId"',
|
|
batch: 200,
|
|
);
|
|
for (final record in existing) {
|
|
await _pb.collection('finance_entries').update(
|
|
record.id,
|
|
body: {
|
|
'status': 'reported',
|
|
'paid_at': null,
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
Future<void> confirmJobPayment(String jobId) async {
|
|
final existing = await _pb.collection('finance_entries').getFullList(
|
|
filter: 'job_id = "$jobId"',
|
|
batch: 200,
|
|
);
|
|
final paidAt = DateTime.now().toIso8601String();
|
|
for (final record in existing) {
|
|
await _pb.collection('finance_entries').update(
|
|
record.id,
|
|
body: {
|
|
'status': 'paid',
|
|
'paid_at': paidAt,
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
Future<void> deletePendingEntriesForJob(String jobId) async {
|
|
final existing = await _pb.collection('finance_entries').getFullList(
|
|
filter:
|
|
'job_id = "$jobId" && (status = "pending" || status = "reported")',
|
|
batch: 200,
|
|
);
|
|
for (final record in existing) {
|
|
await _pb.collection('finance_entries').delete(record.id);
|
|
}
|
|
}
|
|
|
|
Future<void> _upsertEntry({
|
|
required List<RecordModel> existing,
|
|
required String jobId,
|
|
required String tenantId,
|
|
required String counterpartyTenantId,
|
|
required String counterpartyName,
|
|
required String type,
|
|
required double amount,
|
|
required String currency,
|
|
}) async {
|
|
RecordModel? match;
|
|
try {
|
|
match = existing.firstWhere(
|
|
(record) =>
|
|
record.data['tenant_id'] == tenantId && record.data['type'] == type,
|
|
);
|
|
} catch (_) {
|
|
match = null;
|
|
}
|
|
|
|
final body = {
|
|
'tenant_id': tenantId,
|
|
'job_id': jobId,
|
|
'type': type,
|
|
'amount': amount,
|
|
'currency': currency,
|
|
'status': 'pending',
|
|
'paid_at': null,
|
|
'counterparty_tenant_id': counterpartyTenantId,
|
|
'counterparty_name': counterpartyName,
|
|
};
|
|
|
|
if (match == null) {
|
|
await _pb.collection('finance_entries').create(body: body);
|
|
return;
|
|
}
|
|
|
|
await _pb.collection('finance_entries').update(match.id, body: body);
|
|
}
|
|
}
|