Skip to content

feat: Phase 4 - reports, sales returns, enterprise dashboard, POS improvements#17

Merged
hiranyasemindi merged 26 commits into
masterfrom
feat/phase-4
Jun 16, 2026
Merged

feat: Phase 4 - reports, sales returns, enterprise dashboard, POS improvements#17
hiranyasemindi merged 26 commits into
masterfrom
feat/phase-4

Conversation

@iamvirul

@iamvirul iamvirul commented Jun 16, 2026

Copy link
Copy Markdown
Member

Summary

Phase 4 delivers the Reports suite, Sales Returns flow, a full enterprise dashboard redesign, POS fractional quantity support, and a series of polish fixes across the app.

Type

  • Feature
  • Bug fix
  • Docs

Changes

Reports

  • P&L tab with date range picker, revenue/COGS/gross profit/margin summary cards, and daily bar chart filling full screen width
  • Stock Valuation tab with per-product value list and relative progress bar
  • Debtor Aging tab with donut chart bucketed into 0-30d / 31-60d / 61-90d / 90+ days
  • Empty state views on all three tabs (no data, no stock, all clear)
  • P&L summary grid replaced fixed aspect-ratio GridView with content-driven Row layout to prevent oversized cards on desktop

Sales Returns

  • "Process Return" button on invoice detail (admin/manager only) opens a bottom sheet for item selection, qty, return type (refund/credit/exchange), and reason
  • Return history section on invoice detail
  • nextReturnNumber() using MAX() aggregate for O(log n) generation
  • invoiceReturnsProvider for per-invoice return watching
  • Stock reversal with movementType: return_in on each returned item

Dashboard

  • Enterprise redesign: 30-day dual-series line chart (Revenue solid, GP dashed with gradient fill), 7-day grouped bar chart (Revenue vs GP), payment mix donut with progress bar legend
  • MTD card now shows Gross Profit, Margin %, and Avg Order Value sub-metrics
  • KPI cards redesigned with left accent stripe, large bold value, shadow instead of border, tighter height
  • AppBar title split into headline + date subtitle, no em-dash separator
  • Line chart tooltip text changed to white for legibility on dark background
  • Gross profit color on blue MTD card changed to light mint for contrast

POS

  • Fractional quantity support for weight/volume unit types (kg, g, l, ml)
  • Product card tap opens qty dialog with decimal input formatter
  • Stepper uses unit-appropriate increments: 0.25 for kg/l, 50 for g/ml
  • Cart qty display is tappable for direct edit

Login

  • BMS SVG logo from assets rendered at 72px height
  • Dynamic copyright footer using DateTime.now().year

Global

  • Input field label and hint font size reduced to 13sp via InputDecorationTheme

Screenshots

UI changes cover Dashboard, Reports, POS, Invoice Detail, and Login screens.

Test plan

  • Hot reloaded and tested manually
  • Checked on Chrome (flutter run -d chrome)
  • No regressions in related screens

Related issues

Phase 4 scope.

Summary by CodeRabbit

  • New Features

    • Multi-tab Reports screen with P&L, Stock Valuation, and Debtor Aging analysis
    • Sales returns processing from invoice details, including return history and automatic stock restoration
    • Enhanced Dashboard with MTD performance cards, revenue trends, and payment mix visualization
    • Unit-aware quantity entry and editing in POS
    • SVG logo on login screen
  • Improvements

    • Enhanced input styling (labels, hints, focus/error states)
    • Redesigned dashboard sections and stat cards (optional subtitle)
    • Receipt item quantities now display with cleaner decimal formatting

iamvirul added 25 commits June 16, 2026 10:24
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds a complete sales-returns flow on invoice detail (per-item quantity selection, inventory stock restoration, return history), introduces a ReportsDao with P&L/stock-valuation/debtor-aging queries backing a rewritten tabbed reports screen, expands the dashboard with MTD analytics and chart widgets, adds unit-aware quantity entry to POS, and polishes the login screen, StatCard, and input theme.

Changes

Sales Returns

Layer / File(s) Summary
Returns DAO, inventory movementType, and invoiceReturnsProvider
lib/data/database/daos/returns_dao.dart, lib/data/repositories/inventory_repository.dart, lib/providers/invoices_provider.dart
nextReturnNumber() selects the current MAX(returnNo) and returns the next RET-NNNNN value. adjustStock gains an optional movementType parameter to override the auto-derived 'in'/'out' type. invoiceReturnsProvider exposes a per-invoice FutureProvider.autoDispose.family for return history.
Invoice detail – Process Return sheet and return history UI
lib/features/invoices/presentation/invoice_detail_screen.dart
_DetailBody becomes a ConsumerWidget watching invoiceReturnsProvider. A canReturn role check gates a new "Process Return" button. _openReturnSheet presents _ProcessReturnSheet with per-item steppers, return-type selector, optional reason, and submit logic that inserts return records and calls adjustStock. _ReturnHistory renders past returns. Minor fixes to voided banner, _TotalRow, _TableHeader, and _StatusChip.

Reports and Dashboard Analytics

Layer / File(s) Summary
ReportsDao data models and queries
lib/data/database/daos/reports_dao.dart
Adds DailySales (with grossProfit), StockValuationRow, and DebtorAgingRow (with daysPastDue/agingBucket). getDailySales aggregates invoice and quick-sale revenue/COGS per day. getStockValuation left-joins products with stock sorted by descending value. getDebtorAging fetches the oldest unpaid invoice date per positive-balance customer.
ReportsDao and reports Riverpod providers
lib/providers/database_provider.dart, lib/providers/reports_provider.dart
database_provider gains a keepAlive reportsDao provider. reports_provider.dart introduces three @riverpod async providers (dailySales, stockValuation, debtorAging) delegating to reportsDaoProvider.
DashboardStats extensions and provider rework
lib/providers/dashboard_provider.dart
DashboardStats adds salesTrend, paymentMix, mtdSales, lastMonthSales, mtdInvoiceCount, avgOrderValue fields and computed getters mtdGrowthPct, last7Days, mtdGrossProfit, mtdGrossMarginPct. The provider parallelizes DAO calls, filters void invoices, and populates all new fields from 30-day daily sales.
Dashboard screen – MTD card and chart sections
lib/features/dashboard/presentation/dashboard_screen.dart
AppBar title becomes a two-line column. After the KPI grid, new sections add _MtdPerformanceCard, _RevenueTrendChart (30-day line), _WeeklyGroupedChart (7-day bars), conditional _PaymentMixCard (donut), and conditional _RecentInvoicesList. Shared helpers _SectionHeader, _ChartCard, and _ChartLegendDot are introduced.
Reports screen – tabbed P&L, Stock Value, and Aging
lib/features/reports/presentation/reports_screen.dart
ReportsScreen becomes a ConsumerStatefulWidget with a 3-tab TabController. P&L tab: date-range picker, bar chart, summary grid. Stock Value tab: stockValuationProvider, total card, _StockValueRow with progress bar. Aging tab: debtorAgingProvider, bucket sums, _AgingChart (pie), _AgingLegend, _DebtorRow cards. Shared _SummaryGrid, _SummaryCard, and _EmptyState helpers added.

POS Unit-Aware Quantities

Layer / File(s) Summary
PosNotifier qty param and POS screen unit utilities
lib/providers/pos_provider.dart, lib/features/pos/presentation/pos_screen.dart
addItem accepts an optional qty parameter (default 1). Shared helpers _isDecimalUnit, _stepFor, and _formatQty are added. _ProductCard opens a quantity dialog for decimal units. _CartPanel gains _editQty. Cart item rows use unit-step +/- controls and tap-to-edit quantity.

UI Polish and Infrastructure

Layer / File(s) Summary
Login screen SVG logo and InputDecorationTheme styles
lib/features/auth/presentation/login_screen.dart, lib/core/theme/app_theme.dart
Login screen imports flutter_svg, restructures to a SafeArea+Column+Expanded+footer layout, and replaces the Text('BMS') header with an SVG logo and styled title. InputDecorationTheme gains explicit labelStyle, floatingLabelStyle, hintStyle, and errorStyle using Inter and AppColors.
StatCard redesign, receipt formatting, CMake, and changelog
lib/shared/widgets/stat_card.dart, lib/features/pos/presentation/receipt_pdf.dart, windows/flutter/generated_plugins.cmake, CHANGELOG.md
StatCard gains an optional subtitle, replaces the Card layout with Material/InkWell+ClipRRect, and adds a left accent bar. Receipt PDF updates non-integer quantity formatting to use 3 decimals with trailing zeros trimmed. CMake adds flutter_local_notifications_windows to FLUTTER_FFI_PLUGIN_LIST. Changelog documents all unreleased entries including Sales Returns.

Sequence Diagram(s)

sequenceDiagram
  participant InvoiceDetailScreen
  participant _DetailBody
  participant _ProcessReturnSheet
  participant ReturnsDao
  participant InventoryRepository
  participant invoiceReturnsProvider

  InvoiceDetailScreen->>_DetailBody: canReturn=true
  _DetailBody->>invoiceReturnsProvider: watch(invoiceId)
  invoiceReturnsProvider-->>_DetailBody: List of SalesReturn
  _DetailBody->>_ProcessReturnSheet: showModalBottomSheet
  _ProcessReturnSheet->>ReturnsDao: nextReturnNumber()
  ReturnsDao-->>_ProcessReturnSheet: RET-00042
  _ProcessReturnSheet->>ReturnsDao: insertReturn + insertReturnItems
  loop each returned item
    _ProcessReturnSheet->>InventoryRepository: adjustStock(movementType: return_in)
  end
  _ProcessReturnSheet-->>_DetailBody: success
  _DetailBody->>invoiceReturnsProvider: invalidate(invoiceId)
Loading
sequenceDiagram
  participant ReportsScreen
  participant PLTab
  participant StockTab
  participant AgingTab
  participant ReportsDao

  ReportsScreen->>PLTab: TabBarView render
  PLTab->>ReportsDao: getDailySales(from, to)
  ReportsDao-->>PLTab: List<DailySales>
  ReportsScreen->>StockTab: TabBarView render
  StockTab->>ReportsDao: getStockValuation()
  ReportsDao-->>StockTab: List<StockValuationRow>
  ReportsScreen->>AgingTab: TabBarView render
  AgingTab->>ReportsDao: getDebtorAging()
  ReportsDao-->>AgingTab: List<DebtorAgingRow>
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Poem

🐰 Hop hop, the dashboard gleams with charts galore,
Returns are processed — stock restored once more!
The POS counts kilos with decimal care,
Reports now tabbed with aging and flair.
A logo SVG greets you at the door.
This rabbit ships features — who could ask for more? 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the major feature additions (Phase 4 scope) covering reports, sales returns, dashboard redesign, and POS improvements.
Description check ✅ Passed The description comprehensively covers all required sections: Summary, Type, Changes (detailed breakdown by feature area), Screenshots, Test plan, and Related issues.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/phase-4

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (3)
lib/providers/reports_provider.dart (1)

7-17: 💤 Low value

Consider using ref.watch instead of ref.read for consistency.

While ref.read works here because reportsDaoProvider is keepAlive and the DAO is stateless, using ref.watch is the idiomatic Riverpod pattern and ensures proper dependency tracking if the DAO provider ever changes behavior.

 `@riverpod`
 Future<List<DailySales>> dailySales(Ref ref, DateTime from, DateTime to) =>
-    ref.read(reportsDaoProvider).getDailySales(from, to);
+    ref.watch(reportsDaoProvider).getDailySales(from, to);

 `@riverpod`
 Future<List<StockValuationRow>> stockValuation(Ref ref) =>
-    ref.read(reportsDaoProvider).getStockValuation();
+    ref.watch(reportsDaoProvider).getStockValuation();

 `@riverpod`
 Future<List<DebtorAgingRow>> debtorAging(Ref ref) =>
-    ref.read(reportsDaoProvider).getDebtorAging();
+    ref.watch(reportsDaoProvider).getDebtorAging();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/providers/reports_provider.dart` around lines 7 - 17, Replace all
instances of `ref.read(reportsDaoProvider)` with `ref.watch(reportsDaoProvider)`
in the three provider functions: dailySales, stockValuation, and debtorAging.
This ensures consistency with idiomatic Riverpod patterns and maintains proper
dependency tracking in case the DAO provider behavior changes in the future.
lib/data/database/daos/reports_dao.dart (1)

152-174: 💤 Low value

N+1 query pattern in getDebtorAging.

The method executes one query per debtor to fetch the oldest unpaid invoice. For businesses with many debtors, this could degrade performance.

Consider batching with a single query using a correlated subquery or window function if Drift/SQLite supports it, or fetch all qualifying invoices grouped by customer in one query and compute the oldest in Dart.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/data/database/daos/reports_dao.dart` around lines 152 - 174, The
getDebtorAging method executes an N+1 query pattern by making one database query
per customer to fetch their oldest unpaid invoice. Instead of looping through
each customer and querying invoices individually, refactor the method to fetch
all qualifying invoices (with status 'open' or 'partial') in a single query,
then group them by customerId in Dart to find the oldest invoice date for each
customer. This eliminates the per-customer loop query and consolidates database
access into two queries total: one for customers and one for all relevant
invoices, significantly improving performance for scenarios with many debtors.
lib/features/dashboard/presentation/dashboard_screen.dart (1)

698-701: 💤 Low value

Unused totalSales parameter.

The totalSales parameter is passed to _PaymentMixCard but never used. Line 716 recomputes the total from mix.values instead.

Either remove the unused parameter or use it directly:

 class _PaymentMixCard extends StatelessWidget {
-  const _PaymentMixCard({required this.mix, required this.totalSales});
+  const _PaymentMixCard({required this.mix});
   final Map<String, double> mix;
-  final double totalSales;

Also applies to: 716-716

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/features/dashboard/presentation/dashboard_screen.dart` around lines 698 -
701, The `totalSales` parameter in the `_PaymentMixCard` constructor is declared
but never used in the class implementation. Remove the unused `totalSales`
parameter from both the constructor definition and any call sites where
`_PaymentMixCard` is instantiated, or alternatively, use the existing
`totalSales` parameter directly instead of recomputing the total from
`mix.values` at the location where it is currently being recalculated.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/data/database/daos/returns_dao.dart`:
- Around line 12-23: The nextReturnNumber() method has a race condition where
multiple concurrent calls can read the same MAX returnNo value and generate
duplicate return numbers. Move the return number generation logic from
nextReturnNumber() into the insertReturnWithItems transaction so that reading
the current maximum and generating the next number happen atomically within a
single database transaction. Then update all callers to remove the
pre-population of returnNo in the companion object, allowing the transaction to
generate and assign the unique return number during insert.

In `@lib/features/auth/presentation/login_screen.dart`:
- Around line 51-148: The current fixed Column + Expanded layout in the body of
LoginScreen will overflow when the soft keyboard appears, hiding the submit
button and making the form unreachable. Wrap the entire body content (the Column
with Expanded and Footer children) inside a SafeArea widget to protect from
system UI overlays, and then wrap the main Column's children within a
SingleChildScrollView to enable scrolling when the keyboard is active. This
ensures the login form remains accessible and the submit button stays reachable
even on short screens or with the keyboard displayed.

In `@lib/features/invoices/presentation/invoice_detail_screen.dart`:
- Around line 610-623: The return record insertion via
returnsDao.insertReturnWithItems and the subsequent stock adjustments in the
adjustStock loop are not wrapped in a single database transaction, creating a
risk of inconsistent state if any adjustStock call fails after the return is
already inserted. Wrap both the insertReturnWithItems call and the entire loop
of adjustStock calls within a single database transaction to ensure atomicity,
so that if any stock adjustment fails, the return record insertion is also
rolled back.
- Around line 544-551: The return amount calculations in the
`_totalReturnAmount` getter incorrectly use `unitPrice * qty` to calculate
refunds, but this does not account for discounts applied to invoice items. When
an item has `discountPercent > 0`, the customer actually paid the `subtotal`
(the discounted amount), not the full unit price. Replace the line calculating
`total += widget.detail.items[i].unitPrice * qty;` with `total +=
widget.detail.items[i].subtotal;` since subtotal already represents the
customer's actual charge. Apply the same fix to the other return calculation
elsewhere in the file (around line 585) by using `e.item.subtotal` instead of
calculating from unitPrice.

In `@lib/features/pos/presentation/pos_screen.dart`:
- Around line 928-944: The _stepFor function allows fine-grained unit steps
(0.25 for kg/l, 50 for g/ml) and _formatQty properly formats quantities to three
decimals with trailing zeros trimmed, but the receipt PDF formatting in
receipt_pdf.dart (lines 264-310) only formats fractional quantities to one
decimal place, causing 0.25 to display as 0.3 in the printed receipt. Update the
receipt quantity formatting in receipt_pdf.dart to use the same precision logic
as _formatQty, formatting to three decimals and trimming trailing zeros, so that
selected quantities match what appears on the printed receipt.

In `@lib/providers/dashboard_provider.dart`:
- Around line 48-54: The mtdGrossProfit getter is summing all 30 days from the
salesTrend list without filtering for the current calendar month, which causes
it to include data from the previous month. Fix this by filtering the salesTrend
list to only include entries with dates that fall within the current month
before folding to calculate the sum, or alternatively compute the gross profit
directly from the already-fetched MTD invoice data instead of relying on the
full 30-day trend data.

In `@lib/providers/pos_provider.dart`:
- Around line 88-95: The addItem method in lib/providers/pos_provider.dart does
not validate that the qty parameter is positive before processing, allowing zero
or negative quantities to enter the cart state and affect downstream checkout
calculations and stock movements. Add a guard clause at the start of the addItem
method that rejects non-positive quantities (check if qty <= 0) and either
returns early or throws an appropriate exception to prevent invalid quantities
from entering the state model.

In `@lib/shared/widgets/stat_card.dart`:
- Around line 26-44: The decorated Container inside the InkWell widget is
blocking the ripple/splash feedback from rendering properly, weakening the tap
affordance. Replace the Container widget (which contains the BoxDecoration with
borderRadius and boxShadow) with an Ink widget instead, preserving the same
decoration property and all its child widgets. This allows the InkWell's ripple
effect to display properly while maintaining the visual styling.

---

Nitpick comments:
In `@lib/data/database/daos/reports_dao.dart`:
- Around line 152-174: The getDebtorAging method executes an N+1 query pattern
by making one database query per customer to fetch their oldest unpaid invoice.
Instead of looping through each customer and querying invoices individually,
refactor the method to fetch all qualifying invoices (with status 'open' or
'partial') in a single query, then group them by customerId in Dart to find the
oldest invoice date for each customer. This eliminates the per-customer loop
query and consolidates database access into two queries total: one for customers
and one for all relevant invoices, significantly improving performance for
scenarios with many debtors.

In `@lib/features/dashboard/presentation/dashboard_screen.dart`:
- Around line 698-701: The `totalSales` parameter in the `_PaymentMixCard`
constructor is declared but never used in the class implementation. Remove the
unused `totalSales` parameter from both the constructor definition and any call
sites where `_PaymentMixCard` is instantiated, or alternatively, use the
existing `totalSales` parameter directly instead of recomputing the total from
`mix.values` at the location where it is currently being recalculated.

In `@lib/providers/reports_provider.dart`:
- Around line 7-17: Replace all instances of `ref.read(reportsDaoProvider)` with
`ref.watch(reportsDaoProvider)` in the three provider functions: dailySales,
stockValuation, and debtorAging. This ensures consistency with idiomatic
Riverpod patterns and maintains proper dependency tracking in case the DAO
provider behavior changes in the future.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6bc12ec7-d07a-4651-bafe-f6864c3f3210

📥 Commits

Reviewing files that changed from the base of the PR and between f94dc4a and 416dd9e.

📒 Files selected for processing (17)
  • CHANGELOG.md
  • lib/core/theme/app_theme.dart
  • lib/data/database/daos/reports_dao.dart
  • lib/data/database/daos/returns_dao.dart
  • lib/data/repositories/inventory_repository.dart
  • lib/features/auth/presentation/login_screen.dart
  • lib/features/dashboard/presentation/dashboard_screen.dart
  • lib/features/invoices/presentation/invoice_detail_screen.dart
  • lib/features/pos/presentation/pos_screen.dart
  • lib/features/reports/presentation/reports_screen.dart
  • lib/providers/dashboard_provider.dart
  • lib/providers/database_provider.dart
  • lib/providers/invoices_provider.dart
  • lib/providers/pos_provider.dart
  • lib/providers/reports_provider.dart
  • lib/shared/widgets/stat_card.dart
  • windows/flutter/generated_plugins.cmake

Comment thread lib/data/database/daos/returns_dao.dart Outdated
Comment thread lib/features/auth/presentation/login_screen.dart Outdated
Comment thread lib/features/invoices/presentation/invoice_detail_screen.dart
Comment thread lib/features/invoices/presentation/invoice_detail_screen.dart Outdated
Comment thread lib/features/pos/presentation/pos_screen.dart
Comment thread lib/providers/dashboard_provider.dart Outdated
Comment thread lib/providers/pos_provider.dart
Comment thread lib/shared/widgets/stat_card.dart

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/data/database/daos/returns_dao.dart (1)

15-23: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Filter MAX(returnNo) to valid RET-\d+ values before parsing.

Current logic takes the global lexicographic max, then falls back to 0 on parse failure. If the max row is malformed (legacy/manual value), this can regenerate RET-00001 and collide with existing records. Limit the query to strictly valid return numbers before computing the next suffix.

Suggested direction
- final maxExpr = salesReturns.returnNo.max();
- final row =
-     await (selectOnly(salesReturns)..addColumns([maxExpr])).getSingle();
- final maxVal = row.read(maxExpr);
+ // Only consider return numbers that match the RET numeric format
+ // (e.g., RET-00001), then compute max from that filtered set.
+ // This avoids resetting to 1 when malformed values exist.
+ final row = await /* filtered query for valid RET numeric values */;

  int maxNumber = 0;
  if (maxVal != null) {
-   final match = RegExp(r'RET-(\d+)').firstMatch(maxVal);
+   final match = RegExp(r'^RET-(\d+)$').firstMatch(maxVal);
    if (match != null) maxNumber = int.tryParse(match.group(1)!) ?? 0;
  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/data/database/daos/returns_dao.dart` around lines 15 - 23, The current
logic in the ReturnsDao method computes the global lexicographic MAX of the
returnNo column and then attempts to parse it, but if the maximum value is
malformed (doesn't match RET-\d+), parsing fails and defaults to 0, risking
collision with existing records. Modify the selectOnly query that computes
maxExpr to filter the returnNo column to only include values matching the
RET-\d+ pattern BEFORE computing the MAX aggregation. This ensures only valid
return numbers are considered when determining the next return number suffix,
eliminating the risk of regenerating numbers that already exist in the database.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@lib/data/database/daos/returns_dao.dart`:
- Around line 15-23: The current logic in the ReturnsDao method computes the
global lexicographic MAX of the returnNo column and then attempts to parse it,
but if the maximum value is malformed (doesn't match RET-\d+), parsing fails and
defaults to 0, risking collision with existing records. Modify the selectOnly
query that computes maxExpr to filter the returnNo column to only include values
matching the RET-\d+ pattern BEFORE computing the MAX aggregation. This ensures
only valid return numbers are considered when determining the next return number
suffix, eliminating the risk of regenerating numbers that already exist in the
database.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1c658763-44d2-4f56-8e7f-af9728070902

📥 Commits

Reviewing files that changed from the base of the PR and between 416dd9e and 07766a5.

📒 Files selected for processing (9)
  • lib/data/database/daos/returns_dao.dart
  • lib/features/auth/presentation/login_screen.dart
  • lib/features/dashboard/presentation/dashboard_screen.dart
  • lib/features/invoices/presentation/invoice_detail_screen.dart
  • lib/features/pos/presentation/receipt_pdf.dart
  • lib/providers/dashboard_provider.dart
  • lib/providers/pos_provider.dart
  • lib/providers/reports_provider.dart
  • lib/shared/widgets/stat_card.dart
✅ Files skipped from review due to trivial changes (1)
  • lib/providers/reports_provider.dart
🚧 Files skipped from review as they are similar to previous changes (6)
  • lib/providers/pos_provider.dart
  • lib/features/auth/presentation/login_screen.dart
  • lib/shared/widgets/stat_card.dart
  • lib/features/dashboard/presentation/dashboard_screen.dart
  • lib/features/invoices/presentation/invoice_detail_screen.dart
  • lib/providers/dashboard_provider.dart

@hiranyasemindi hiranyasemindi added this pull request to the merge queue Jun 16, 2026
Merged via the queue into master with commit 934f5ef Jun 16, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants