From 57ea214871e83742f39e36c91ab4de5df520eb29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Salazar?= <73718835+joshrs23@users.noreply.github.com> Date: Mon, 26 Jan 2026 18:23:52 -0500 Subject: [PATCH] invoices history ready --- .../src/mocks/financial_repository_mock.dart | 2 + .../lib/src/entities/financial/invoice.dart | 12 +++- .../billing_repository_impl.dart | 58 +++++++++++++++++-- .../src/presentation/blocs/billing_bloc.dart | 10 +++- .../widgets/invoice_history_section.dart | 15 +++-- 5 files changed, 81 insertions(+), 16 deletions(-) diff --git a/apps/mobile/packages/data_connect/lib/src/mocks/financial_repository_mock.dart b/apps/mobile/packages/data_connect/lib/src/mocks/financial_repository_mock.dart index 0ae0c513..9da38f9f 100644 --- a/apps/mobile/packages/data_connect/lib/src/mocks/financial_repository_mock.dart +++ b/apps/mobile/packages/data_connect/lib/src/mocks/financial_repository_mock.dart @@ -13,6 +13,8 @@ class FinancialRepositoryMock { totalAmount: 1500.0, workAmount: 1400.0, addonsAmount: 100.0, + invoiceNumber: 'INV-1', + issueDate: null, ), ]; } diff --git a/apps/mobile/packages/domain/lib/src/entities/financial/invoice.dart b/apps/mobile/packages/domain/lib/src/entities/financial/invoice.dart index 2dc06f9c..4c5a0e3c 100644 --- a/apps/mobile/packages/domain/lib/src/entities/financial/invoice.dart +++ b/apps/mobile/packages/domain/lib/src/entities/financial/invoice.dart @@ -35,6 +35,8 @@ class Invoice extends Equatable { required this.totalAmount, required this.workAmount, required this.addonsAmount, + this.invoiceNumber, + this.issueDate, }); /// Unique identifier. final String id; @@ -57,6 +59,12 @@ class Invoice extends Equatable { /// Total amount for addons/extras. final double addonsAmount; + /// Human-readable invoice number. + final String? invoiceNumber; + + /// Date when the invoice was issued. + final DateTime? issueDate; + @override List get props => [ id, @@ -66,5 +74,7 @@ class Invoice extends Equatable { totalAmount, workAmount, addonsAmount, + invoiceNumber, + issueDate, ]; -} \ No newline at end of file +} diff --git a/apps/mobile/packages/features/client/billing/lib/src/data/repositories_impl/billing_repository_impl.dart b/apps/mobile/packages/features/client/billing/lib/src/data/repositories_impl/billing_repository_impl.dart index 24ec3861..663eeba2 100644 --- a/apps/mobile/packages/features/client/billing/lib/src/data/repositories_impl/billing_repository_impl.dart +++ b/apps/mobile/packages/features/client/billing/lib/src/data/repositories_impl/billing_repository_impl.dart @@ -44,12 +44,22 @@ class BillingRepositoryImpl implements BillingRepository { /// Fetches the history of paid invoices. @override Future> getInvoiceHistory() async { - final List invoices = await _financialRepository.getInvoices( - 'current_business', - ); - return invoices - .where((Invoice i) => i.status == InvoiceStatus.paid) - .toList(); + final String? businessId = + data_connect.ClientSessionStore.instance.session?.business?.id; + if (businessId == null || businessId.isEmpty) { + return []; + } + + final fdc.QueryResult result = + await _dataConnect + .listInvoicesByBusinessId( + businessId: businessId, + ) + .limit(10) + .execute(); + + return result.data.invoices.map(_mapInvoice).toList(); } /// Fetches pending invoices (Open or Disputed). @@ -161,6 +171,42 @@ class BillingRepositoryImpl implements BillingRepository { (dateTime.millisecondsSinceEpoch % 1000) * 1000000; return fdc.Timestamp(nanoseconds, seconds); } + + Invoice _mapInvoice(data_connect.ListInvoicesByBusinessIdInvoices invoice) { + return Invoice( + id: invoice.id, + eventId: invoice.orderId, + businessId: invoice.businessId, + status: _mapInvoiceStatus(invoice.status), + totalAmount: invoice.amount, + workAmount: invoice.amount, + addonsAmount: invoice.otherCharges ?? 0, + invoiceNumber: invoice.invoiceNumber, + issueDate: invoice.issueDate.toDateTime(), + ); + } + + InvoiceStatus _mapInvoiceStatus( + data_connect.EnumValue status, + ) { + if (status is data_connect.Known) { + switch (status.value) { + case data_connect.InvoiceStatus.PAID: + return InvoiceStatus.paid; + case data_connect.InvoiceStatus.OVERDUE: + return InvoiceStatus.overdue; + case data_connect.InvoiceStatus.DISPUTED: + return InvoiceStatus.disputed; + case data_connect.InvoiceStatus.APPROVED: + return InvoiceStatus.verified; + case data_connect.InvoiceStatus.PENDING_REVIEW: + case data_connect.InvoiceStatus.PENDING: + case data_connect.InvoiceStatus.DRAFT: + return InvoiceStatus.open; + } + } + return InvoiceStatus.open; + } } class _RoleSummary { diff --git a/apps/mobile/packages/features/client/billing/lib/src/presentation/blocs/billing_bloc.dart b/apps/mobile/packages/features/client/billing/lib/src/presentation/blocs/billing_bloc.dart index 98a57984..d6e3c7fb 100644 --- a/apps/mobile/packages/features/client/billing/lib/src/presentation/blocs/billing_bloc.dart +++ b/apps/mobile/packages/features/client/billing/lib/src/presentation/blocs/billing_bloc.dart @@ -114,17 +114,21 @@ class BillingBloc extends Bloc { // In a real app, fetches related Event/Business names via ID. // For now, mapping available fields and hardcoding missing UI placeholders. // Preserving "Existing Behavior" means we show something. + final String dateLabel = invoice.issueDate == null + ? '2024-01-24' + : invoice.issueDate!.toIso8601String().split('T').first; + final String titleLabel = invoice.invoiceNumber ?? invoice.id; return BillingInvoice( - id: invoice.id, + id: titleLabel, title: 'Invoice #${invoice.id}', // Placeholder as Invoice lacks title locationAddress: 'Location for ${invoice.eventId}', // Placeholder for address clientName: 'Client ${invoice.businessId}', // Placeholder for client name - date: '2024-01-24', // Placeholder date + date: dateLabel, totalAmount: invoice.totalAmount, workersCount: 5, // Placeholder count totalHours: invoice.workAmount / 25.0, // Estimating hours from amount - status: invoice.status.name, + status: invoice.status.name.toUpperCase(), ); } diff --git a/apps/mobile/packages/features/client/billing/lib/src/presentation/widgets/invoice_history_section.dart b/apps/mobile/packages/features/client/billing/lib/src/presentation/widgets/invoice_history_section.dart index 19f97c47..053ec29d 100644 --- a/apps/mobile/packages/features/client/billing/lib/src/presentation/widgets/invoice_history_section.dart +++ b/apps/mobile/packages/features/client/billing/lib/src/presentation/widgets/invoice_history_section.dart @@ -114,7 +114,7 @@ class _InvoiceItem extends StatelessWidget { '\$${invoice.totalAmount.toStringAsFixed(2)}', style: UiTypography.body2b.textPrimary, ), - const _PaidBadge(), + _StatusBadge(status: invoice.status), ], ), const SizedBox(width: UiConstants.space2), @@ -125,21 +125,24 @@ class _InvoiceItem extends StatelessWidget { } } -class _PaidBadge extends StatelessWidget { - const _PaidBadge(); +class _StatusBadge extends StatelessWidget { + const _StatusBadge({required this.status}); + + final String status; @override Widget build(BuildContext context) { + final bool isPaid = status.toUpperCase() == 'PAID'; return Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( - color: UiColors.tagSuccess, + color: isPaid ? UiColors.tagSuccess : UiColors.tagPending, borderRadius: BorderRadius.circular(4), ), child: Text( - t.client_billing.paid_badge, + isPaid ? t.client_billing.paid_badge : t.client_billing.pending_badge, style: UiTypography.titleUppercase4b.copyWith( - color: UiColors.iconSuccess, + color: isPaid ? UiColors.iconSuccess : UiColors.textWarning, ), ), );