Add pricing entry flow and platform admin foundations
This commit is contained in:
@@ -101,8 +101,7 @@ class _ClinicFinanceScreenState extends ConsumerState<ClinicFinanceScreen>
|
||||
future: _headerFuture,
|
||||
builder: (ctx, snap) {
|
||||
if (snap.connectionState == ConnectionState.waiting) {
|
||||
return const LinearProgressIndicator(
|
||||
color: AppColors.accent);
|
||||
return const LinearProgressIndicator(color: AppColors.accent);
|
||||
}
|
||||
final data = snap.data ??
|
||||
const _ClinicFinanceHeaderData(
|
||||
@@ -117,7 +116,7 @@ class _ClinicFinanceScreenState extends ConsumerState<ClinicFinanceScreen>
|
||||
children: [
|
||||
Expanded(
|
||||
child: _SummaryCard(
|
||||
label: s.pendingReceivable,
|
||||
label: 'Açık Borç',
|
||||
amount: data.summary['pending'] ?? 0.0,
|
||||
currencyCode: currencyCode,
|
||||
color: AppColors.pending,
|
||||
@@ -128,7 +127,7 @@ class _ClinicFinanceScreenState extends ConsumerState<ClinicFinanceScreen>
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: _SummaryCard(
|
||||
label: s.collected,
|
||||
label: 'Onaylanan Ödeme',
|
||||
amount: data.summary['paid'] ?? 0.0,
|
||||
currencyCode: currencyCode,
|
||||
color: AppColors.success,
|
||||
@@ -230,8 +229,7 @@ class _SummaryCard extends StatelessWidget {
|
||||
width: 44,
|
||||
height: 44,
|
||||
decoration: BoxDecoration(
|
||||
color: bgColor,
|
||||
borderRadius: BorderRadius.circular(12)),
|
||||
color: bgColor, borderRadius: BorderRadius.circular(12)),
|
||||
child: Icon(icon, color: color, size: 22),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
@@ -304,12 +302,10 @@ class _FinanceTabState extends ConsumerState<_FinanceTab> {
|
||||
switch (widget.sort) {
|
||||
case _FinanceSort.newestFirst:
|
||||
list.sort((a, b) {
|
||||
final da = a.dateCreated != null
|
||||
? DateTime.tryParse(a.dateCreated!)
|
||||
: null;
|
||||
final db = b.dateCreated != null
|
||||
? DateTime.tryParse(b.dateCreated!)
|
||||
: null;
|
||||
final da =
|
||||
a.dateCreated != null ? DateTime.tryParse(a.dateCreated!) : null;
|
||||
final db =
|
||||
b.dateCreated != null ? DateTime.tryParse(b.dateCreated!) : null;
|
||||
if (da == null && db == null) return 0;
|
||||
if (da == null) return 1;
|
||||
if (db == null) return -1;
|
||||
@@ -323,15 +319,15 @@ class _FinanceTabState extends ConsumerState<_FinanceTab> {
|
||||
return list;
|
||||
}
|
||||
|
||||
Future<void> _markPaid(FinanceEntry entry) async {
|
||||
Future<void> _reportPayment(FinanceEntry entry) async {
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: const Text('Ödeme Onayı'),
|
||||
title: const Text('Ödeme Bildir'),
|
||||
content: Text(
|
||||
'${entry.counterpartyName ?? "Bu kayıt"} için '
|
||||
'${CurrencyFormatter.format(entry.amount, widget.currencyCode)} tutarındaki borcu '
|
||||
'ödendi olarak işaretlemek istiyor musunuz?',
|
||||
'laboratuvara ödendi olarak bildirmek istiyor musunuz?',
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
@@ -340,19 +336,21 @@ class _FinanceTabState extends ConsumerState<_FinanceTab> {
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () => Navigator.pop(ctx, true),
|
||||
child: const Text('Ödendi'),
|
||||
child: const Text('Bildir'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
if (confirmed != true || !mounted) return;
|
||||
try {
|
||||
await ClinicFinanceRepository.instance.markPaid(entry.id);
|
||||
await ClinicFinanceRepository.instance.reportPayment(entry.id);
|
||||
_load();
|
||||
widget.onPaymentMade();
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Ödeme kaydedildi.')),
|
||||
const SnackBar(
|
||||
content: Text('Ödeme bildirildi. Laboratuvar onayı bekleniyor.'),
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -392,8 +390,7 @@ class _FinanceTabState extends ConsumerState<_FinanceTab> {
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text('Hata: ${snap.error}',
|
||||
style: const TextStyle(
|
||||
color: AppColors.textSecondary)),
|
||||
style: const TextStyle(color: AppColors.textSecondary)),
|
||||
const SizedBox(height: 12),
|
||||
FilledButton.icon(
|
||||
onPressed: _load,
|
||||
@@ -437,10 +434,17 @@ class _FinanceTabState extends ConsumerState<_FinanceTab> {
|
||||
itemBuilder: (context, index) {
|
||||
final entry = entries[index];
|
||||
final isPending = entry.status == FinanceStatus.pending;
|
||||
final statusColor =
|
||||
isPending ? AppColors.pending : AppColors.success;
|
||||
final statusBg =
|
||||
isPending ? AppColors.pendingBg : AppColors.successBg;
|
||||
final isReported = entry.status == FinanceStatus.reported;
|
||||
final statusColor = isPending
|
||||
? AppColors.pending
|
||||
: isReported
|
||||
? AppColors.accent
|
||||
: AppColors.success;
|
||||
final statusBg = isPending
|
||||
? AppColors.pendingBg
|
||||
: isReported
|
||||
? AppColors.inProgressBg
|
||||
: AppColors.successBg;
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 10),
|
||||
@@ -448,7 +452,7 @@ class _FinanceTabState extends ConsumerState<_FinanceTab> {
|
||||
color: AppColors.surface,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
child: InkWell(
|
||||
onTap: isPending ? () => _markPaid(entry) : null,
|
||||
onTap: isPending ? () => _reportPayment(entry) : null,
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(14),
|
||||
@@ -472,7 +476,9 @@ class _FinanceTabState extends ConsumerState<_FinanceTab> {
|
||||
child: Icon(
|
||||
isPending
|
||||
? Icons.hourglass_empty_rounded
|
||||
: Icons.check_circle_outline,
|
||||
: isReported
|
||||
? Icons.verified_outlined
|
||||
: Icons.check_circle_outline,
|
||||
color: statusColor,
|
||||
size: 22,
|
||||
),
|
||||
@@ -486,8 +492,7 @@ class _FinanceTabState extends ConsumerState<_FinanceTab> {
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
entry.counterpartyName ??
|
||||
'Bilinmiyor',
|
||||
entry.counterpartyName ?? 'Bilinmiyor',
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w600,
|
||||
@@ -522,6 +527,25 @@ class _FinanceTabState extends ConsumerState<_FinanceTab> {
|
||||
color: AppColors.textMuted),
|
||||
),
|
||||
],
|
||||
if (isReported) ...[
|
||||
const SizedBox(height: 4),
|
||||
const Text(
|
||||
'Ödeme bildirildi, laboratuvar onayı bekleniyor.',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: AppColors.textSecondary,
|
||||
),
|
||||
),
|
||||
] else if (isPending) ...[
|
||||
const SizedBox(height: 4),
|
||||
const Text(
|
||||
'Dokunarak ödeme bildirimi yapabilirsiniz.',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: AppColors.textSecondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user