Apply clinic lab workflow feedback
This commit is contained in:
@@ -85,4 +85,28 @@ class LabFinanceRepository {
|
||||
}
|
||||
await FinanceService.instance.confirmJobPayment(jobId);
|
||||
}
|
||||
|
||||
Future<void> confirmPayments(List<FinanceEntry> entries) async {
|
||||
final jobIds = <String>{};
|
||||
final standaloneIds = <String>[];
|
||||
for (final entry in entries) {
|
||||
if (!entry.status.isOpen) continue;
|
||||
if (entry.jobId.isNotEmpty) {
|
||||
jobIds.add(entry.jobId);
|
||||
} else {
|
||||
standaloneIds.add(entry.id);
|
||||
}
|
||||
}
|
||||
|
||||
for (final jobId in jobIds) {
|
||||
await FinanceService.instance.confirmJobPayment(jobId);
|
||||
}
|
||||
final paidAt = DateTime.now().toIso8601String();
|
||||
for (final id in standaloneIds) {
|
||||
await _pb.collection('finance_entries').update(id, body: {
|
||||
'status': 'paid',
|
||||
'paid_at': paidAt,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,6 +146,68 @@ class _LabFinanceScreenState extends ConsumerState<LabFinanceScreen>
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _confirmCounterpartyPayments(
|
||||
CounterpartyFinanceSummary item,
|
||||
List<FinanceEntry> pending,
|
||||
String Function(double) formatAmount,
|
||||
) async {
|
||||
final entries = pending
|
||||
.where((entry) =>
|
||||
entry.status.isOpen &&
|
||||
(entry.counterpartyTenantId == item.counterpartyTenantId ||
|
||||
entry.counterpartyName == item.counterpartyName))
|
||||
.toList();
|
||||
if (entries.isEmpty) return;
|
||||
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: const Text('Toplu Ödeme Onayla'),
|
||||
content: Text(
|
||||
'${item.counterpartyName} için ${entries.length} açık kayıt '
|
||||
'${formatAmount(item.pendingAmount)} toplam tutarla onaylansın mı?',
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx, false),
|
||||
child: const Text('İptal'),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () => Navigator.pop(ctx, true),
|
||||
child: const Text('Toplu Onayla'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
if (confirmed != true || !mounted) return;
|
||||
|
||||
try {
|
||||
await LabFinanceRepository.instance.confirmPayments(entries);
|
||||
_load();
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Toplu ödeme onaylandı.')),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text('Hata: $e')),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _sendPaymentReminder(CounterpartyFinanceSummary item) async {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
'${item.counterpartyName} için ödeme hatırlatması hazırlandı.',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isSortActive = _sort != _FinanceSort.newestFirst;
|
||||
@@ -252,6 +314,9 @@ class _LabFinanceScreenState extends ConsumerState<LabFinanceScreen>
|
||||
title: 'Klinik Bazlı Alacak',
|
||||
items: data.counterparties,
|
||||
formatAmount: formatAmount,
|
||||
onConfirmAll: (item) => _confirmCounterpartyPayments(
|
||||
item, pending, formatAmount),
|
||||
onSendReminder: _sendPaymentReminder,
|
||||
),
|
||||
),
|
||||
PillTabs(
|
||||
@@ -568,11 +633,15 @@ class _CounterpartySummaryList extends StatelessWidget {
|
||||
required this.title,
|
||||
required this.items,
|
||||
required this.formatAmount,
|
||||
required this.onConfirmAll,
|
||||
required this.onSendReminder,
|
||||
});
|
||||
|
||||
final String title;
|
||||
final List<CounterpartyFinanceSummary> items;
|
||||
final String Function(double) formatAmount;
|
||||
final Future<void> Function(CounterpartyFinanceSummary item) onConfirmAll;
|
||||
final Future<void> Function(CounterpartyFinanceSummary item) onSendReminder;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -616,6 +685,26 @@ class _CounterpartySummaryList extends StatelessWidget {
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
if (item.pendingAmount > 0) ...[
|
||||
const SizedBox(width: 8),
|
||||
IconButton(
|
||||
onPressed: () => onSendReminder(item),
|
||||
tooltip: 'Ödeme hatırlat',
|
||||
icon: const Icon(Icons.notifications_active_outlined),
|
||||
color: AppColors.pending,
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
TextButton.icon(
|
||||
onPressed: () => onConfirmAll(item),
|
||||
icon: const Icon(Icons.done_all_rounded, size: 16),
|
||||
label: const Text('Toplu Onay'),
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: AppColors.success,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
Reference in New Issue
Block a user