Skip to content

feat: Phase 3 - Quick Sales, GRN, Petty Cash, UI consistency - #4

Merged
hiranyasemindi merged 43 commits into
masterfrom
feat/phase-3
Jun 16, 2026
Merged

feat: Phase 3 - Quick Sales, GRN, Petty Cash, UI consistency#4
hiranyasemindi merged 43 commits into
masterfrom
feat/phase-3

Conversation

@iamvirul

@iamvirul iamvirul commented Jun 15, 2026

Copy link
Copy Markdown
Member

Summary

Completes Phase 3 of BMS development - adds three missing core features, fixes UI consistency across the entire app, and ships the brand identity (logo, banner, README).

Type

  • Feature
  • Bug fix
  • Docs
  • Chore

Changes

  • Quick Sales - no-invoice cash sale flow with stock deduction, ledger entry, and date-filtered history
  • GRN - goods receipt workflow: supplier picker, product picker, qty/cost inline editing, stock-in on confirm, cost price update, purchase history tab
  • Petty Cash - daily float card, receipt photo capture (gallery + camera), approval workflow, category chips
  • POS discounts - line-item percentage discount and bill-level discount
  • Sidebar grouping - nav items grouped into labelled sections (Sales, Stock, Contacts, Finance, Admin)
  • Sidebar overflow fix - all three sidebar widgets use LayoutBuilder to prevent overflow during collapse animation
  • Shared filter bar - BmsFilterRow and BmsDateBar components replace custom date/search implementations across all screens
  • Input consistency - isDense moved to InputDecorationTheme so every TextField is compact by default; removed all local overrides
  • Invoices AppBar - added missing AppBar to invoices screen
  • BMS logo - SVG icon mark added to sidebar header and web favicon; flutter_svg added as dependency
  • README - banner, detailed feature list, role permission table, Apache 2.0 license
  • Em dash removal - replaced all em dashes with hyphens across UI strings and code comments
  • PR and issue templates - bug report, feature request, task templates added

Screenshots

See README banner and individual screen descriptions above.

Test plan

  • Hot reloaded and tested manually
  • Checked on Chrome (flutter run -d chrome --web-port 9090 --no-wasm)
  • flutter analyze passes with no errors
  • No regressions in related screens

Related issues

Phase 3 scope completion.

Summary by CodeRabbit

Release Notes

  • New Features
    • Added Quick Sales and GRN screens (including GRN “New” flow and “History”), with searchable supplier/product selection.
    • Added Sales Returns support.
    • Enabled POS discounts (per-line and bill-level) and updated receipts/printing to reflect discounts.
    • Added Petty Cash receipt photo support.
  • Bug Fixes
    • Improved UI spacing/density across forms and standardized “-” separators; enhanced invoice filtering via a shared date-range + search bar.
    • Refreshed sidebar navigation layout for smaller screens.
  • Documentation / Chores
    • Added issue/PR templates, updated README/CHANGELOG, added Code Quality scanning workflow, and adjusted test placeholders.

iamvirul added 30 commits June 15, 2026 15:20
- PosState gets billDiscountPct, discountAmount, updated total
- setBillDiscount() and setLineDiscount() on PosNotifier
- Cart items show long-press sheet for per-item % discount
- Tap 'Add Discount' in bottom panel for bill-level %
- discountAmount saved on invoice at checkout
- Receipt PDF shows Subtotal + Discount rows when discount > 0
@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

@iamvirul Sure! I'll start reviewing PR #4 right away.

Note: I'm replying to your latest comment without full visibility into the earlier conversation thread, as it was too long to include in context.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds four new features—GRN (goods receipt note), Quick Sales (no-invoice sales), POS line/bill discounts, and Petty Cash receipt photos—alongside a shared filter bar widget library, sidebar navigation grouping with SVG branding, a sales-returns database v2 schema with migration, global input UI density and em-dash cleanup, and complete repository scaffolding (issue templates, CI, licensing, documentation).

Changes

BMS Feature Release

Layer / File(s) Summary
Repository and platform setup
.github/ISSUE_TEMPLATE/*, .github/pull_request_template.md, .github/workflows/codeql.yml, LICENSE, CHANGELOG.md, README.md, docs/org-profile/README.md, analysis_options.yaml, pubspec.yaml, web/index.html, windows/flutter/generated_*
Adds GitHub issue (bug, feature, task) and PR templates; defines CodeQL CI workflow for Flutter analysis and dependency auditing; includes Apache 2.0 license, "Keep a Changelog" format initial changelog, restructured README with tech stack and role-permissions matrix, organization-profile documentation; updates Dart lint rules to suppress inference failures and enforce error-only throws; adds share_plus, image_picker, flutter_svg dependencies; brands web app metadata as "BMS"; registers Windows plugins for Share Plus and URL Launcher.
Sales Returns schema v2, DAO, migration
lib/data/database/tables/returns_table.dart, lib/data/database/daos/returns_dao.dart, lib/data/database/app_database.dart, lib/providers/database_provider.dart
Defines SalesReturns and ReturnItems Drift tables with foreign keys, constraints, and defaults; implements ReturnsDao with transactional insertReturnWithItems(), getForInvoice(), and getItemsForReturn() methods; registers tables and DAO in AppDatabase, increments schema version to 2 with onUpgrade migration logic for tables creation; exposes ReturnsDao as a keepAlive Riverpod provider.
Inventory DAO: cost-price and stock-watch methods
lib/data/database/daos/inventory_dao.dart
Adds updateCostPrice(productId, costPrice) to update product cost and watchAllStock() stream to reactively watch all stock levels by product ID, enabling GRN cost tracking and real-time stock monitoring.
GRN feature: DAO, state, screen, routing
lib/data/database/daos/suppliers_dao.dart, lib/providers/grn_provider.dart, lib/features/grn/presentation/grn_screen.dart, lib/core/router/app_router.dart
Extends SuppliersDao with purchase/GRN queries and nextGrnNumber() transaction for sequential GRN generation; defines GrnCartItem, GrnState, and GrnNotifier with cart mutations and confirm() workflow that generates GRN numbers, inserts purchase + line items in transaction, updates inventory (stock upserts and movements), updates product cost prices, updates supplier balance, and writes audit logs; implements GrnScreen with two tabs (new GRN entry with supplier/product pickers and editable cart, plus GRN history with loading/error states); wires /grn route.
Quick Sales feature: providers, screen, routing
lib/providers/quick_sale_provider.dart, lib/features/quick_sales/presentation/quick_sales_screen.dart, lib/core/router/app_router.dart
Adds quickSaleDateRangeProvider (month-to-now range) and quickSalesListProvider (auto-disposing, date-filtered no-invoice sales fetch); implements QuickSaleActions.sell() with UUID v7 sale creation, inventory stock decrement with zero-floor clamping, stock movement recording (actual deducted qty), and audit log entry; creates QuickSalesScreen with date picker, revenue summary bar, sales list, and new-sale modal sheet with product search and qty/price/notes inputs; wires /quick-sales route.
POS line and bill discounts
lib/providers/pos_provider.dart, lib/features/pos/presentation/pos_screen.dart, lib/features/pos/presentation/receipt_pdf.dart
Extends PosState with billDiscountPct and derived discountAmount, updates total calculation (subtotal minus discount); adds setLineDiscount(productId, pct) and setBillDiscount(pct) methods with percentage clamping; persists discount amounts during checkout and in audit logs; adds line-discount and bill-discount bottom sheets to cart UI (long-press for line, row click for bill); updates ReceiptPdf.printOrPreview to accept and conditionally render discountAmount.
Petty Cash receipt photo support
lib/providers/petty_cash_provider.dart, lib/features/petty_cash/presentation/petty_cash_screen.dart
Extends PettyCashActions.addEntry with optional receiptPhotoPath parameter; refactors PettyCashScreen to use BmsDateBar, computes and displays in/out balance via _FloatCard summary, renders entry chips with optional receipt photo viewer, replaces inline status UI with _StatusBadge and conditional approval sheet; extends _AddEntrySheet with image_picker gallery/camera support, receipt preview, and simplified form decorations.
Shared filter widgets and invoice refactor
lib/shared/widgets/bms_filter_bar.dart, lib/features/invoices/presentation/invoices_screen.dart
Introduces BmsDateRangeField, BmsSearchField, BmsFilterRow, and BmsDateBar reusable filter widgets; refactors InvoicesScreen filter bar to use BmsFilterRow, removing inline date-picker and search implementations.
Sidebar navigation: grouped sections, SVG logo, responsive layout
lib/shared/widgets/sidebar_nav.dart
Replaces flat nav item list with _NavSection-grouped model and section labels; updates _Header with SVG logo asset and LayoutBuilder narrow-width logo-only mode; adds LayoutBuilder responsive behavior to _NavTile (narrow: icon-only) and _UserFooter (narrow: avatar-only); introduces _NavSection and _SectionLabel private widgets.
Global UI polish: density, punctuation, comments
lib/core/theme/app_theme.dart, lib/core/router/route_guard.dart, lib/features/**/presentation/*.dart, lib/providers/*.dart
Sets isDense: true and compact contentPadding in AppTheme.light's InputDecorationTheme; removes per-field isDense overrides across all feature screens; replaces em-dashes with hyphens in titles and labels; removes section-divider comments; standardizes provider file comment punctuation.
Test infrastructure cleanup
test/unit/auth/auth_repository_test.dart, test/unit/inventory/inventory_repository_test.dart, test/widget_test.dart
Removes non-flutter_test imports from unit test files; replaces widget smoke test with trivial placeholder assertion.

Sequence Diagrams

sequenceDiagram
  participant GrnScreen
  participant GrnNotifier
  participant SuppliersDao
  participant InventoryDao
  participant AuditLogDao

  GrnScreen->>GrnNotifier: confirm()
  GrnNotifier->>SuppliersDao: nextGrnNumber()
  SuppliersDao-->>GrnNotifier: GRN-00001
  GrnNotifier->>SuppliersDao: insertPurchase(entry)
  GrnNotifier->>SuppliersDao: insertPurchaseItems(items)
  loop each cart item
    GrnNotifier->>InventoryDao: upsertStock(productId, qty)
    GrnNotifier->>InventoryDao: insertStockMovement(in)
    GrnNotifier->>InventoryDao: updateCostPrice(productId)
  end
  GrnNotifier->>SuppliersDao: updateSupplierBalance()
  GrnNotifier->>AuditLogDao: insert(grn_event)
  GrnNotifier-->>GrnScreen: success with lastGrnNo
Loading
sequenceDiagram
  participant QuickSalesScreen
  participant QuickSaleActions
  participant InvoicesDao
  participant InventoryDao
  participant AuditLogDao

  QuickSalesScreen->>QuickSaleActions: sell(product, qty, price, notes)
  QuickSaleActions->>InvoicesDao: insertNoInvoiceSale(entry)
  QuickSaleActions->>InventoryDao: getCurrentStock(productId)
  QuickSaleActions->>InventoryDao: upsertStock(productId, clampedQty)
  QuickSaleActions->>InventoryDao: insertStockMovement(out, saleId)
  QuickSaleActions->>AuditLogDao: insert(quick_sale_event)
  QuickSaleActions-->>QuickSalesScreen: success or error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 Hippity-hoppity, features galore,
GRN and Quick Sales hop through the door!
Discounts on bills, receipts for the cash,
The sidebar now grouped in a svelte little flash.
Em-dashes retired, hyphens their heirs—
A rabbit keeps changelog and nothing compares! ✨

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

@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: 20

Caution

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

⚠️ Outside diff range comments (8)
lib/features/settings/presentation/settings_screen.dart (3)

13-13: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove unused import.

The audit_log_dao.dart import is unused and flagged by the analyzer.

🧹 Proposed fix
-import '../../../data/database/daos/audit_log_dao.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/features/settings/presentation/settings_screen.dart` at line 13, Remove
the unused import statement for audit_log_dao.dart from the file. This import is
not referenced anywhere in the settings_screen.dart file and is causing an
analyzer warning, so it should be deleted to keep the imports clean and improve
code quality.

Source: Pipeline failures


140-140: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add explicit type argument to showDialog.

The analyzer requires explicit type arguments to avoid inference failures.

🔧 Proposed fix
-    showDialog(
+    showDialog<void>(
🤖 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/settings/presentation/settings_screen.dart` at line 140, The
showDialog function call at line 140 in settings_screen.dart is missing explicit
type arguments, which causes analyzer inference failures. Add an explicit type
argument to the showDialog call by specifying the return type in angle brackets,
such as showDialog<T>() where T represents the expected return type of the
dialog (typically void, bool, or another appropriate type based on what the
dialog should return).

Source: Pipeline failures


96-96: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add explicit type argument to MaterialPageRoute.

The analyzer requires explicit type arguments to avoid inference failures.

🔧 Proposed fix
-              MaterialPageRoute(builder: (_) => const _AuditLogScreen()),
+              MaterialPageRoute<void>(builder: (_) => const _AuditLogScreen()),
🤖 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/settings/presentation/settings_screen.dart` at line 96, The
MaterialPageRoute constructor in the navigation call is missing an explicit type
argument, which the analyzer requires to avoid inference failures. Add an
explicit type argument to MaterialPageRoute, such as MaterialPageRoute<void>, to
specify the return type of the route. This applies to the MaterialPageRoute that
wraps the _AuditLogScreen widget.

Source: Pipeline failures

lib/features/invoices/presentation/invoice_pdf.dart (1)

230-230: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove unused colWidths variable.

Line 230 defines colWidths but the columnWidths map (lines 258–265) uses hardcoded FixedColumnWidth/FlexColumnWidth values instead. This unused variable triggers a pipeline warning.

🗑️ Proposed fix
   ) {
     const colWidths = [30.0, null, 40.0, 60.0, 50.0, 65.0];
-
     pw.Widget cell(

Remove line 230 entirely.

🤖 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/invoices/presentation/invoice_pdf.dart` at line 230, The
colWidths constant defined in the invoice_pdf.dart file is not being used
anywhere since the columnWidths map uses hardcoded FixedColumnWidth and
FlexColumnWidth values instead. Remove the unused colWidths variable declaration
entirely to eliminate the pipeline warning.
lib/features/petty_cash/presentation/petty_cash_screen.dart (1)

142-152: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remove dead _statusColor/_statusBg helpers to clear analyzer warnings.

Line 142 and Line 148 define unused methods already flagged by CI analyze output.

Suggested fix
-  Color _statusColor(String status) => switch (status) {
-        'approved' => AppColors.success,
-        'rejected' => AppColors.error,
-        _ => AppColors.warning,
-      };
-
-  Color _statusBg(String status) => switch (status) {
-        'approved' => AppColors.successLight,
-        'rejected' => AppColors.errorLight,
-        _ => AppColors.warningLight,
-      };
🤖 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/petty_cash/presentation/petty_cash_screen.dart` around lines 142
- 152, Remove the two unused helper methods `_statusColor` and `_statusBg` from
the petty cash screen class, as they are not being called anywhere in the
codebase and are causing analyzer warnings. Simply delete both method
definitions entirely to clean up the dead code and resolve the CI analyzer
output warnings.

Source: Pipeline failures

lib/providers/petty_cash_provider.dart (2)

52-68: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Enforce petty-cash amount/type invariants before insert.

addEntry persists amount and type as-is. Negative/zero/non-finite amounts (or unexpected type) can be stored and corrupt balance math downstream. Validate in the action layer before DAO writes.

Suggested fix
   Future<void> addEntry({
     required String description,
     required double amount,
     required String type,
     required String category,
     String? receiptPhotoPath,
   }) async {
+    if (!amount.isFinite || amount <= 0) {
+      throw ArgumentError.value(amount, 'amount', 'Must be a positive number');
+    }
+    if (type != 'in' && type != 'out') {
+      throw ArgumentError.value(type, 'type', "Must be 'in' or 'out'");
+    }
     final id = _uuid.v7();
🤖 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/petty_cash_provider.dart` around lines 52 - 68, In the addEntry
method, add validation logic before the DAO insert call to enforce invariants on
the amount and type parameters. Validate that amount is positive and finite (not
negative, zero, or NaN/infinity), and validate that type contains an
expected/valid value. If validation fails, throw an appropriate exception to
prevent corrupt data from being persisted to the database.

60-109: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Refresh pettyCashEntriesProvider after successful mutations.

addEntry/approve/reject write data but never invalidate pettyCashEntriesProvider, so the current screen can keep stale entries/status until another dependency changes.

Suggested fix
 class PettyCashActions {
   PettyCashActions(this._ref);
   final Ref _ref;
   final _uuid = const Uuid();
+  void _refreshEntries() => _ref.invalidate(pettyCashEntriesProvider);

@@
     await _ref.read(pettyCashDaoProvider).insert(PettyCashCompanion.insert(
@@
         ));
+    _refreshEntries();
@@
   Future<void> approve(String id) async {
     await _ref.read(pettyCashDaoProvider).approve(id, _userId);
+    _refreshEntries();
@@
   Future<void> reject(String id) async {
     await _ref.read(pettyCashDaoProvider).reject(id);
+    _refreshEntries();
🤖 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/petty_cash_provider.dart` around lines 60 - 109, The addEntry,
approve, and reject methods in PettyCashProvider perform mutations to the
database and log audit events, but they do not invalidate the
pettyCashEntriesProvider cache afterward. This causes the UI to display stale
data until another dependency triggers a refresh. After the
auditLogDaoProvider.log call completes in each of the three methods (addEntry,
approve, and reject), add a call to invalidate the pettyCashEntriesProvider by
using _ref.invalidate(pettyCashEntriesProvider) to ensure the cached entries are
refreshed and the UI displays the latest data.
lib/features/pos/presentation/pos_screen.dart (1)

264-264: ⚠️ Potential issue | 🟡 Minor

Add explicit generic type arguments for dialog APIs to clear analyzer warnings.

The showDialog and showModalBottomSheet calls at lines 264, 274, and 331 are missing explicit generic type arguments. Add <void> to each call since their return values are not used. Note that line 806 already includes the type argument, creating inconsistency.

Suggested patch
-    showDialog(
+    showDialog<void>(
       context: context,
       builder: (_) => const _CustomerSearchDialog(),
     );

-    showModalBottomSheet(
+    showModalBottomSheet<void>(
       context: context,
       isScrollControlled: true,
       builder: (ctx) => Padding(
         ...
       ),
     );

-    showModalBottomSheet(
+    showModalBottomSheet<void>(
       context: context,
       isScrollControlled: true,
       builder: (ctx) => Padding(
         ...
       ),
     );
🤖 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/pos/presentation/pos_screen.dart` at line 264, Add explicit
generic type argument `<void>` to the `showDialog` and `showModalBottomSheet`
calls that are missing them. Specifically, modify the calls at line 264, line
274, and line 331 in the pos_screen.dart file to include `<void>` as the generic
type argument (for example, change `showDialog(` to `showDialog<void>(`). This
will make these calls consistent with the existing implementation at line 806
which already includes the type argument, and will resolve analyzer warnings
since the return values of these calls are not used.

Source: Pipeline failures

🧹 Nitpick comments (5)
README.md (2)

61-91: 💤 Low value

Add language identifier to Project Structure code block.

Line 61 defines a fenced code block without a language identifier. For consistency and proper syntax highlighting, specify a language (e.g., text or tree).
[minor_issue]

✏️ Proposed fix
 ## Project Structure
 
-```
+```text
 lib/
🤖 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 `@README.md` around lines 61 - 91, The project structure code block in the
README starting with the lib/ directory listing is missing a language identifier
on the opening fence. Add a language identifier (such as `text` or `tree`)
immediately after the opening triple backticks to enable proper syntax
highlighting and maintain consistency with other code blocks in the document.

Source: Linters/SAST tools


147-154: 💤 Low value

Add language identifier to web database clearing code block.

Line 151 defines a fenced code block without a language identifier. For markdown consistency, specify a language (e.g., text or leave it blank if intended as plain output).
[minor_issue]

✏️ Proposed fix
 The web build uses IndexedDB. After a schema change, clear the old database:
 
-```
+```text
 Chrome DevTools -> Application -> IndexedDB -> delete bms_local -> refresh
-```
+```text
🤖 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 `@README.md` around lines 147 - 154, The fenced code block in the README.md
section "Clearing the web database" (the block containing the Chrome DevTools
instructions) is missing a language identifier. Add a language identifier such
as "text" to the opening triple backticks (change ``` to ```text) to ensure
markdown consistency and proper syntax highlighting compliance.

Source: Linters/SAST tools

lib/shared/widgets/sidebar_nav.dart (1)

133-133: ⚡ Quick win

Extract the repeated narrow-width threshold to a shared constant.

The < 120 threshold is duplicated across _Header, _NavTile, and _UserFooter. Extracting it to a top-level constant (e.g., _kNarrowThreshold = 120.0) improves maintainability.

♻️ Proposed refactor

Add the constant near the other layout constants:

 const double _kExpandedWidth = 224;
 const double _kCollapsedWidth = 56;
 const Duration _kAnimDuration = Duration(milliseconds: 200);
+const double _kNarrowThreshold = 120;

Then replace each occurrence:

-        final narrow = constraints.maxWidth < 120;
+        final narrow = constraints.maxWidth < _kNarrowThreshold;

Also applies to: 214-214, 290-290

🤖 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/shared/widgets/sidebar_nav.dart` at line 133, Extract the magic number
120 that appears in the narrow-width threshold comparisons across the file into
a top-level constant named _kNarrowThreshold with a value of 120.0. Then replace
all three occurrences of the hardcoded comparison (< 120) with comparisons using
this constant in the _Header widget at line 133, the _NavTile widget at line
214, and the _UserFooter widget at line 290 to improve maintainability and
reduce duplication.
lib/features/inventory/presentation/inventory_screen.dart (1)

28-28: ⚡ Quick win

Add explicit type arguments to all showModalBottomSheet calls to silence analyzer warnings.

All three screen files trigger Flutter analyzer inference_failure_on_function_invocation warnings on showModalBottomSheet calls. Adding an explicit <void> type argument resolves these.

  • lib/features/inventory/presentation/inventory_screen.dart#L28: Add <void> type argument
  • lib/features/suppliers/presentation/suppliers_screen.dart#L14,L85,L158: Add <void> type argument to all three calls
  • lib/features/users/presentation/users_screen.dart#L64,L145,L154,L235: Add <void> type argument to all four calls
🤖 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/inventory/presentation/inventory_screen.dart` at line 28, Add
explicit `<void>` type arguments to all `showModalBottomSheet` calls to resolve
Flutter analyzer inference warnings. In
lib/features/inventory/presentation/inventory_screen.dart at line 28, change
`showModalBottomSheet(` to `showModalBottomSheet<void>(`. In
lib/features/suppliers/presentation/suppliers_screen.dart, add `<void>` type
argument to the `showModalBottomSheet` calls at lines 14, 85, and 158. In
lib/features/users/presentation/users_screen.dart, add `<void>` type argument to
the `showModalBottomSheet` calls at lines 64, 145, 154, and 235. Each change
follows the same pattern: insert `<void>` immediately after the method name
`showModalBottomSheet`.

Source: Pipeline failures

lib/data/database/tables/returns_table.dart (1)

7-8: ⚡ Quick win

Index lookup keys used by returns queries.

invoiceId and returnId are hot filter paths in the DAO; without indexes, these queries degrade to full scans as return history grows.

Also applies to: 24-24

🤖 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/tables/returns_table.dart` around lines 7 - 8, Add indexes
to the columns used as hot filter paths in DAO queries to prevent full table
scans as data grows. In the ReturnsTable class, add indexing to the invoiceId
column (line 7) and the column at line 24 to enable efficient lookups. Use the
appropriate indexing method provided by the drift library to mark these columns
as indexed in the table schema definition.
🤖 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 @.github/workflows/codeql.yml:
- Line 15: The actions/checkout action on Line 15 is pinned to a version tag
(v4) instead of a specific commit hash, which creates a supply-chain attack
vulnerability since version tags can be reassigned. Replace the version tag
reference with a specific commit hash from the latest stable release in the
actions/checkout repository. Additionally, add the parameter
persist-credentials: false to the actions/checkout action to explicitly disable
credential persistence, which is a security best practice. Use the latest stable
commit hash available from the actions/checkout releases page rather than the
example hash mentioned in the comment.
- Line 17: The subosito/flutter-action is currently pinned to a version tag (v2)
instead of a specific commit hash, which poses a supply-chain security risk.
Replace the version tag reference with a specific commit hash by changing the
uses directive from the v2 tag format to use the format with a commit hash.
Check the subosito/flutter-action releases page to find the latest stable commit
hash and use that instead of the version tag.

In `@lib/data/database/daos/returns_dao.dart`:
- Around line 29-31: The nextReturnNumber() method in ReturnsDAO uses row count
for sequence generation, which produces duplicate return numbers after record
deletions and fails under concurrent requests, violating the unique constraint
on returnNo. Since the method is currently unused, either remove it entirely, or
if it needs to be retained, replace the row count logic with a proper sequence
generation approach that queries the maximum existing return number suffix and
increments it, while wrapping the operation in a transaction with conflict retry
handling to prevent duplicates under concurrent access.
- Around line 12-16: The `insertReturn` and `insertItems` methods are separate
operations that can lead to partial writes and database inconsistency if one
succeeds while the other fails. Combine both operations into a single
transactional method that executes the header insertion via `insertReturn` and
the items insertion via `insertItems` within a unified transaction block,
ensuring atomicity. Use the batch transaction pattern (similar to how
`insertItems` currently uses batch) to wrap both the return header and items
insertions in a single atomic operation so either both succeed or both fail
together.

In `@lib/data/database/daos/suppliers_dao.dart`:
- Around line 57-60: The nextGrnNumber() method has a race condition and
performance problem: it loads all purchases to count them (O(n) operation)
without transaction protection, allowing concurrent requests to generate the
same GRN number. Replace the current count-based approach with a database-level
sequence strategy using either a dedicated counter row that gets atomically
incremented within a transaction, or implement a retry-on-conflict pattern where
you attempt to insert a candidate number and regenerate if it conflicts. This
ensures atomicity at the database level and eliminates the need to load all
records just to get a count.

In `@lib/data/database/tables/returns_table.dart`:
- Around line 10-12: The type field in the returns table lacks database-level
validation for allowed values, which can lead to invalid data being stored. Add
a CHECK constraint to the type TextColumn getter method to enforce that only the
supported values ('refund', 'credit', 'exchange') can be inserted or updated.
Apply the constraint directly in the column definition to ensure data integrity
at the database layer.
- Around line 27-29: The qty, unitPrice, and subtotal real column definitions in
the ReturnItems table lack CHECK constraints, allowing invalid negative or zero
values that compromise financial data integrity. Modify each of these three
column definitions to add validation constraints using Drift's check method: for
the qty field, enforce that it must be greater than 0; for the unitPrice field,
enforce that it must be greater than or equal to 0; and for the subtotal field,
enforce that it must also be greater than or equal to 0. Chain the check method
to each real() call before the final parentheses to add these database-level
constraints.

In `@lib/features/grn/presentation/grn_screen.dart`:
- Around line 460-463: The TextButton in GRN screen (calling
ref.read(grnProvider.notifier).reset()) is currently always enabled, which
allows users to clear the form while a submission is in progress, causing state
desynchronization. Disable this button by setting its onPressed to null when a
submission is active. Check the GRN provider for an existing loading/submitting
state indicator, then conditionally set onPressed to null when submission is in
progress and keep the current reset callback when idle. Optionally, update the
button's styling (opacity or color) to visually indicate the disabled state to
users.
- Around line 224-225: The itemBuilder in the ListView.builder for _GrnItemRow
(lines 224-225) lacks a stable key, and the text controllers for quantity and
cost fields are initialized only once in initState (lines 331-337). When item
values update from the provider, these controllers do not reflect the changes,
causing drift between the UI and the provider state. Add a stable key to the
itemBuilder using a unique identifier from each item (such as item id), and
refactor the controller initialization logic in initState to either add
listeners that respond to item value changes from the provider, or implement a
mechanism that updates controller values whenever the underlying item data
changes, ensuring the qty and cost fields remain synchronized with the provider
state.

In `@lib/features/invoices/presentation/invoices_screen.dart`:
- Around line 67-73: The onDatePick and onSearch callbacks are using a captured
filter snapshot that can become stale if other fields change before the callback
executes, causing race conditions where later callbacks overwrite other filter
criteria. Instead of using the captured filter variable in the copyWith calls,
read the latest filter state directly from invoiceFilterProvider within each
callback by replacing the filter snapshot with a call to
ref.read(invoiceFilterProvider) at callback execution time, ensuring each update
always merges with the most current state rather than a stale snapshot.

In `@lib/features/petty_cash/presentation/petty_cash_screen.dart`:
- Around line 205-213: The _viewPhoto method uses Image.file(File(path)) without
verifying that the file still exists on disk, which can cause runtime failures
when persisted receipt paths reference deleted files. Before creating the
Image.file widget, check if the file exists using File(path).existsSync(). If
the file doesn't exist, display a fallback message or placeholder widget instead
of attempting to load the image. Apply this same defensive check at all
locations where receipt image files are directly loaded for display.

In `@lib/features/quick_sales/presentation/quick_sales_screen.dart`:
- Around line 167-170: The validation check for qty and price in the
quick_sales_screen.dart file currently returns silently when either value is
invalid (less than or equal to zero), providing no user feedback. Instead of
returning without action when the if condition (qty <= 0 || price <= 0) is true,
display an error message to the user using an appropriate feedback mechanism
such as a SnackBar or dialog to explain that both quantity and price must be
greater than zero. This ensures users receive clear feedback about why their
action was not processed.

In `@lib/providers/grn_provider.dart`:
- Around line 181-182: After resetting the state with the lastGrnNo assignment,
the grnListProvider is not being invalidated, which causes the History tab to
display stale data since the provider remains alive in the tab view. Add an
invalidation call to grnListProvider immediately after the state reset to ensure
the GRN history is refreshed and synchronized with the latest changes.
- Around line 119-179: Wrap all database operations in a single transaction to
ensure atomicity and prevent partial state commits on failure. In
lib/providers/grn_provider.dart (lines 119-179), wrap all operations from
insertPurchase through the final auditDao.log call in a database transaction. In
lib/providers/quick_sale_provider.dart (lines 62-104), wrap the sale insert,
stock upsert, stock movement insert, and audit log operations in a database
transaction. Use the Drift database transaction API to ensure that if any
operation fails, the entire sequence is rolled back, maintaining cross-table
consistency for inventory, supplier balances, and audit logs.
- Around line 104-179: The submit method reads state.supplier, state.items, and
state.total multiple times across awaits, risking inconsistent snapshots if
state mutates during the operation. Immediately after setting isSubmitting to
true, capture immutable local variables for supplier, items, and total from
state. Then replace all subsequent references to state.supplier, state.items,
and state.total (used in suppliersDao.insertPurchase, the for loop iterating
items, inventoryDao calls, suppliersDao.updateBalance, and auditDao.log) with
the corresponding local variables to ensure a consistent snapshot throughout the
entire async operation.

In `@lib/providers/pos_provider.dart`:
- Around line 134-140: The setLineDiscount method correctly updates the
discountPct in state, but the discountAmount is not being calculated and
persisted when items are inserted into the database during checkout. Find where
invoice items are being inserted during checkout (likely in a method that
persists the cart items to the database) and ensure that for each item, you
calculate the discountAmount based on the item's discountPct and price, then
persist both discountPercent and the calculated discountAmount to the
InvoiceItems table. This ensures discount analytics and exports reflect the
actual discount amounts applied to each line item.

In `@lib/providers/quick_sale_provider.dart`:
- Around line 51-56: The sell method in quick_sale_provider.dart accepts qty and
price parameters but does not validate them at the action layer, relying instead
only on UI-side guards which can be bypassed by non-UI callers. Add input
validation at the beginning of the sell method to reject non-positive values for
both qty and price parameters; throw an appropriate exception or error for
invalid inputs to ensure data integrity and prevent invalid writes from any
caller source.
- Around line 72-84: The issue is that when the requested qty exceeds available
stock, the newQty is clamped to zero but the recordMovement method still records
the full requested qty, creating a mismatch between inventory and the stock
ledger. Instead of recording the original requested qty in the recordMovement
call within the StockMovementsCompanion.insert, calculate and record the actual
quantity that was deducted from inventory, which is the difference between the
current stock and newQty (the actual amount that was removed).

In `@lib/shared/widgets/bms_filter_bar.dart`:
- Around line 24-26: The bms_filter_bar.dart widget contains hard-coded date
bounds (firstDate as DateTime(2020) and lastDate as DateTime(2035)) that
restrict valid date selections across all consuming screens. Replace these
hard-coded values with parameterized constructor parameters for the widget or
calculate them dynamically based on the current date and business requirements.
This allows different screens to use appropriate date ranges for their specific
needs without being constrained by fixed historical and future limits.

In `@lib/shared/widgets/sidebar_nav.dart`:
- Around line 288-331: The logout functionality is only available in the wide
layout (in the IconButton at the end of the Row), but is completely missing from
the narrow layout (the Tooltip-wrapped avatar). To fix this, add a
GestureDetector or InkWell around the avatar in the narrow mode branch (where
constraints.maxWidth < 120) and wire its onTap callback to trigger the same
logout action as the IconButton: ref.read(authStateProvider.notifier).logout().
This ensures users on narrow displays can still access the logout functionality
by tapping the avatar.

---

Outside diff comments:
In `@lib/features/invoices/presentation/invoice_pdf.dart`:
- Line 230: The colWidths constant defined in the invoice_pdf.dart file is not
being used anywhere since the columnWidths map uses hardcoded FixedColumnWidth
and FlexColumnWidth values instead. Remove the unused colWidths variable
declaration entirely to eliminate the pipeline warning.

In `@lib/features/petty_cash/presentation/petty_cash_screen.dart`:
- Around line 142-152: Remove the two unused helper methods `_statusColor` and
`_statusBg` from the petty cash screen class, as they are not being called
anywhere in the codebase and are causing analyzer warnings. Simply delete both
method definitions entirely to clean up the dead code and resolve the CI
analyzer output warnings.

In `@lib/features/pos/presentation/pos_screen.dart`:
- Line 264: Add explicit generic type argument `<void>` to the `showDialog` and
`showModalBottomSheet` calls that are missing them. Specifically, modify the
calls at line 264, line 274, and line 331 in the pos_screen.dart file to include
`<void>` as the generic type argument (for example, change `showDialog(` to
`showDialog<void>(`). This will make these calls consistent with the existing
implementation at line 806 which already includes the type argument, and will
resolve analyzer warnings since the return values of these calls are not used.

In `@lib/features/settings/presentation/settings_screen.dart`:
- Line 13: Remove the unused import statement for audit_log_dao.dart from the
file. This import is not referenced anywhere in the settings_screen.dart file
and is causing an analyzer warning, so it should be deleted to keep the imports
clean and improve code quality.
- Line 140: The showDialog function call at line 140 in settings_screen.dart is
missing explicit type arguments, which causes analyzer inference failures. Add
an explicit type argument to the showDialog call by specifying the return type
in angle brackets, such as showDialog<T>() where T represents the expected
return type of the dialog (typically void, bool, or another appropriate type
based on what the dialog should return).
- Line 96: The MaterialPageRoute constructor in the navigation call is missing
an explicit type argument, which the analyzer requires to avoid inference
failures. Add an explicit type argument to MaterialPageRoute, such as
MaterialPageRoute<void>, to specify the return type of the route. This applies
to the MaterialPageRoute that wraps the _AuditLogScreen widget.

In `@lib/providers/petty_cash_provider.dart`:
- Around line 52-68: In the addEntry method, add validation logic before the DAO
insert call to enforce invariants on the amount and type parameters. Validate
that amount is positive and finite (not negative, zero, or NaN/infinity), and
validate that type contains an expected/valid value. If validation fails, throw
an appropriate exception to prevent corrupt data from being persisted to the
database.
- Around line 60-109: The addEntry, approve, and reject methods in
PettyCashProvider perform mutations to the database and log audit events, but
they do not invalidate the pettyCashEntriesProvider cache afterward. This causes
the UI to display stale data until another dependency triggers a refresh. After
the auditLogDaoProvider.log call completes in each of the three methods
(addEntry, approve, and reject), add a call to invalidate the
pettyCashEntriesProvider by using _ref.invalidate(pettyCashEntriesProvider) to
ensure the cached entries are refreshed and the UI displays the latest data.

---

Nitpick comments:
In `@lib/data/database/tables/returns_table.dart`:
- Around line 7-8: Add indexes to the columns used as hot filter paths in DAO
queries to prevent full table scans as data grows. In the ReturnsTable class,
add indexing to the invoiceId column (line 7) and the column at line 24 to
enable efficient lookups. Use the appropriate indexing method provided by the
drift library to mark these columns as indexed in the table schema definition.

In `@lib/features/inventory/presentation/inventory_screen.dart`:
- Line 28: Add explicit `<void>` type arguments to all `showModalBottomSheet`
calls to resolve Flutter analyzer inference warnings. In
lib/features/inventory/presentation/inventory_screen.dart at line 28, change
`showModalBottomSheet(` to `showModalBottomSheet<void>(`. In
lib/features/suppliers/presentation/suppliers_screen.dart, add `<void>` type
argument to the `showModalBottomSheet` calls at lines 14, 85, and 158. In
lib/features/users/presentation/users_screen.dart, add `<void>` type argument to
the `showModalBottomSheet` calls at lines 64, 145, 154, and 235. Each change
follows the same pattern: insert `<void>` immediately after the method name
`showModalBottomSheet`.

In `@lib/shared/widgets/sidebar_nav.dart`:
- Line 133: Extract the magic number 120 that appears in the narrow-width
threshold comparisons across the file into a top-level constant named
_kNarrowThreshold with a value of 120.0. Then replace all three occurrences of
the hardcoded comparison (< 120) with comparisons using this constant in the
_Header widget at line 133, the _NavTile widget at line 214, and the _UserFooter
widget at line 290 to improve maintainability and reduce duplication.

In `@README.md`:
- Around line 61-91: The project structure code block in the README starting
with the lib/ directory listing is missing a language identifier on the opening
fence. Add a language identifier (such as `text` or `tree`) immediately after
the opening triple backticks to enable proper syntax highlighting and maintain
consistency with other code blocks in the document.
- Around line 147-154: The fenced code block in the README.md section "Clearing
the web database" (the block containing the Chrome DevTools instructions) is
missing a language identifier. Add a language identifier such as "text" to the
opening triple backticks (change ``` to ```text) to ensure markdown consistency
and proper syntax highlighting compliance.
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c15f774f-95d3-4245-b7f8-c170b2232613

📥 Commits

Reviewing files that changed from the base of the PR and between 4786e5e and 986a8b7.

⛔ Files ignored due to path filters (8)
  • assets/images/bms_logo.svg is excluded by !**/*.svg
  • docs/banner.png is excluded by !**/*.png
  • docs/banner.svg is excluded by !**/*.svg
  • docs/logo.png is excluded by !**/*.png
  • docs/org-banner.png is excluded by !**/*.png
  • docs/org-banner.svg is excluded by !**/*.svg
  • pubspec.lock is excluded by !**/*.lock
  • web/favicon.svg is excluded by !**/*.svg
📒 Files selected for processing (50)
  • .github/ISSUE_TEMPLATE/bug_report.md
  • .github/ISSUE_TEMPLATE/feature_request.md
  • .github/ISSUE_TEMPLATE/task.md
  • .github/pull_request_template.md
  • .github/workflows/codeql.yml
  • CHANGELOG.md
  • LICENSE
  • README.md
  • analysis_options.yaml
  • docs/org-profile/README.md
  • lib/core/router/app_router.dart
  • lib/core/router/route_guard.dart
  • lib/core/theme/app_theme.dart
  • lib/data/database/app_database.dart
  • lib/data/database/daos/inventory_dao.dart
  • lib/data/database/daos/returns_dao.dart
  • lib/data/database/daos/suppliers_dao.dart
  • lib/data/database/tables/returns_table.dart
  • lib/features/cheques/presentation/cheque_screen.dart
  • lib/features/customers/presentation/customers_screen.dart
  • lib/features/dashboard/presentation/dashboard_screen.dart
  • lib/features/grn/presentation/grn_screen.dart
  • lib/features/inventory/presentation/inventory_screen.dart
  • lib/features/invoices/presentation/invoice_detail_screen.dart
  • lib/features/invoices/presentation/invoice_pdf.dart
  • lib/features/invoices/presentation/invoices_screen.dart
  • lib/features/petty_cash/presentation/petty_cash_screen.dart
  • lib/features/pos/presentation/pos_screen.dart
  • lib/features/pos/presentation/receipt_pdf.dart
  • lib/features/quick_sales/presentation/quick_sales_screen.dart
  • lib/features/reports/presentation/reports_screen.dart
  • lib/features/settings/presentation/settings_screen.dart
  • lib/features/suppliers/presentation/suppliers_screen.dart
  • lib/features/users/presentation/users_screen.dart
  • lib/providers/cheques_provider.dart
  • lib/providers/customers_provider.dart
  • lib/providers/database_provider.dart
  • lib/providers/grn_provider.dart
  • lib/providers/inventory_provider.dart
  • lib/providers/petty_cash_provider.dart
  • lib/providers/pos_provider.dart
  • lib/providers/quick_sale_provider.dart
  • lib/providers/settings_provider.dart
  • lib/providers/suppliers_provider.dart
  • lib/shared/widgets/bms_filter_bar.dart
  • lib/shared/widgets/sidebar_nav.dart
  • pubspec.yaml
  • web/index.html
  • windows/flutter/generated_plugin_registrant.cc
  • windows/flutter/generated_plugins.cmake
💤 Files with no reviewable changes (2)
  • lib/features/invoices/presentation/invoice_detail_screen.dart
  • analysis_options.yaml

Comment thread .github/workflows/codeql.yml
Comment thread .github/workflows/codeql.yml Outdated
Comment thread lib/data/database/daos/returns_dao.dart Outdated
Comment thread lib/data/database/daos/returns_dao.dart Outdated
Comment thread lib/data/database/daos/suppliers_dao.dart
Comment thread lib/providers/pos_provider.dart
Comment thread lib/providers/quick_sale_provider.dart
Comment thread lib/providers/quick_sale_provider.dart
Comment thread lib/shared/widgets/bms_filter_bar.dart Outdated
Comment thread lib/shared/widgets/sidebar_nav.dart
@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 12 file(s) based on 20 unresolved review comments.

A stacked PR containing fixes has been created.

  • Stacked PR: #5
  • Files modified:
  • lib/data/database/daos/returns_dao.dart
  • lib/data/database/daos/suppliers_dao.dart
  • lib/data/database/tables/returns_table.dart
  • lib/features/grn/presentation/grn_screen.dart
  • lib/features/invoices/presentation/invoices_screen.dart
  • lib/features/petty_cash/presentation/petty_cash_screen.dart
  • lib/features/quick_sales/presentation/quick_sales_screen.dart
  • lib/providers/grn_provider.dart
  • lib/providers/pos_provider.dart
  • lib/providers/quick_sale_provider.dart
  • lib/shared/widgets/bms_filter_bar.dart
  • lib/shared/widgets/sidebar_nav.dart

Time taken: 6m 14s


⚠️ 1 file(s) could not be committed — the agent does not have permission to push to .github/workflows/. Please apply these changes manually:

.github/workflows/codeql.yml — 1 change:

Lines 12–20
     runs-on: ubuntu-latest
 
     steps:
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+        with:
+          persist-credentials: false
 
-      - uses: subosito/flutter-action@v2
+      - uses: subosito/flutter-action@f2c4f6686ca8e8d6e6d0f28410eeef506ed66aef # v2.16.0
         with:
           channel: stable

Fixed 12 file(s) based on 20 unresolved review comments.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>

@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 (2)
lib/providers/quick_sale_provider.dart (2)

103-109: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Audit log records requested qty, not actual deducted quantity.

The audit log at lines 107-108 uses the original qty and qty * price for the total. If an oversell scenario occurs (partially fulfilled), this audit entry will misrepresent what actually happened. Ensure the audit reflects reality by using actualDeducted if partial fulfillment is allowed, or this becomes moot if you fail on insufficient stock per the previous comment.

🤖 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/quick_sale_provider.dart` around lines 103 - 109, The audit
log's newValue dictionary is recording the requested quantity (qty) instead of
the actual deducted quantity in an oversell scenario where partial fulfillment
is allowed. Update the 'qty' field and the 'total' calculation in the newValue
dictionary to use actualDeducted instead of qty to ensure the audit log
accurately reflects what was actually deducted from inventory rather than what
was requested.

66-74: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Sale record should use actualDeducted to stay consistent with stock movement.

The fix at line 89 correctly records the actual deducted quantity in the stock movement. However, the sale record at line 70 still uses the original qty. When qty > currentQty, this creates a mismatch: the sale claims X units were sold, but only Y units were actually removed from inventory.

Consider either:

  1. Using actualDeducted for the sale record (and adjusting price/total accordingly), or
  2. Failing the sale when insufficient stock exists (throw before line 66)
Option 2: Fail early on insufficient stock
     if (qty <= 0 || price <= 0) {
       throw ArgumentError('Quantity and price must be greater than zero');
     }

+    final current = await _ref.read(inventoryDaoProvider).getStock(product.id);
+    final currentQty = current?.qty ?? 0;
+    if (qty > currentQty) {
+      throw StateError('Insufficient stock: requested $qty but only $currentQty available');
+    }
+
     final id = _uuid.v7();
     final inventoryDao = _ref.read(inventoryDaoProvider);

Then simplify lines 76-79:

-    final current = await inventoryDao.getStock(product.id);
-    final currentQty = current?.qty ?? 0;
-    final newQty = (currentQty - qty).clamp(0.0, double.infinity);
-    final actualDeducted = currentQty - newQty;
+    final newQty = currentQty - qty;
     await inventoryDao.upsertStock(StockCompanion(
       productId: Value(product.id),
       qty: Value(newQty),

And at line 89:

-      qty: actualDeducted,
+      qty: qty,
🤖 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/quick_sale_provider.dart` around lines 66 - 74, The
NoInvoiceSalesCompanion.insert call in the insertNoInvoiceSale method is
recording the requested qty quantity, but when insufficient stock exists, only
actualDeducted units are removed from inventory (as recorded at line 89),
creating a mismatch between the sale record and the actual stock movement. You
must align these by either: (1) passing actualDeducted to the qty parameter in
NoInvoiceSalesCompanion.insert and adjusting the price calculation accordingly
to reflect only the quantity actually deducted, or (2) validating that qty does
not exceed currentQty before the insertNoInvoiceSale call and throwing an
exception to fail the sale early if stock is insufficient. Choose the approach
that best fits your business requirements and implement it consistently.
🧹 Nitpick comments (1)
lib/providers/quick_sale_provider.dart (1)

61-94: Wrap multi-step writes in a transaction to ensure atomicity.

The sell() method performs four sequential writes: invoice insert, inventory upsert, stock movement insert, and audit log. If any operation fails mid-sequence, the database is left in an inconsistent state (e.g., sale created but stock not deducted).

Other providers in this codebase (e.g., grn_provider.dart) follow the established pattern of wrapping multi-step operations in db.transaction(() async { ... }). Access the database instance via _ref.read(appDatabaseProvider) and apply the same pattern here.

🤖 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/quick_sale_provider.dart` around lines 61 - 94, The sell()
method performs four sequential database operations (insertNoInvoiceSale,
upsertStock, recordMovement, and the audit log write) without transactional
protection, risking database inconsistency if any operation fails. Wrap all
these database writes in a transaction by first accessing the database instance
via _ref.read(appDatabaseProvider), then using its transaction() method with an
async callback to execute all operations atomically. This follows the
established pattern used in other providers like grn_provider.dart and ensures
that either all writes complete successfully or none of them do, maintaining
database integrity.
🤖 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/providers/quick_sale_provider.dart`:
- Around line 103-109: The audit log's newValue dictionary is recording the
requested quantity (qty) instead of the actual deducted quantity in an oversell
scenario where partial fulfillment is allowed. Update the 'qty' field and the
'total' calculation in the newValue dictionary to use actualDeducted instead of
qty to ensure the audit log accurately reflects what was actually deducted from
inventory rather than what was requested.
- Around line 66-74: The NoInvoiceSalesCompanion.insert call in the
insertNoInvoiceSale method is recording the requested qty quantity, but when
insufficient stock exists, only actualDeducted units are removed from inventory
(as recorded at line 89), creating a mismatch between the sale record and the
actual stock movement. You must align these by either: (1) passing
actualDeducted to the qty parameter in NoInvoiceSalesCompanion.insert and
adjusting the price calculation accordingly to reflect only the quantity
actually deducted, or (2) validating that qty does not exceed currentQty before
the insertNoInvoiceSale call and throwing an exception to fail the sale early if
stock is insufficient. Choose the approach that best fits your business
requirements and implement it consistently.

---

Nitpick comments:
In `@lib/providers/quick_sale_provider.dart`:
- Around line 61-94: The sell() method performs four sequential database
operations (insertNoInvoiceSale, upsertStock, recordMovement, and the audit log
write) without transactional protection, risking database inconsistency if any
operation fails. Wrap all these database writes in a transaction by first
accessing the database instance via _ref.read(appDatabaseProvider), then using
its transaction() method with an async callback to execute all operations
atomically. This follows the established pattern used in other providers like
grn_provider.dart and ensures that either all writes complete successfully or
none of them do, maintaining database integrity.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 52f5ca4a-e87e-4f99-91c3-bc0db25a4b38

📥 Commits

Reviewing files that changed from the base of the PR and between 986a8b7 and 7751ed2.

📒 Files selected for processing (12)
  • lib/data/database/daos/returns_dao.dart
  • lib/data/database/daos/suppliers_dao.dart
  • lib/data/database/tables/returns_table.dart
  • lib/features/grn/presentation/grn_screen.dart
  • lib/features/invoices/presentation/invoices_screen.dart
  • lib/features/petty_cash/presentation/petty_cash_screen.dart
  • lib/features/quick_sales/presentation/quick_sales_screen.dart
  • lib/providers/grn_provider.dart
  • lib/providers/pos_provider.dart
  • lib/providers/quick_sale_provider.dart
  • lib/shared/widgets/bms_filter_bar.dart
  • lib/shared/widgets/sidebar_nav.dart
🚧 Files skipped from review as they are similar to previous changes (10)
  • lib/data/database/daos/suppliers_dao.dart
  • lib/features/quick_sales/presentation/quick_sales_screen.dart
  • lib/providers/pos_provider.dart
  • lib/data/database/tables/returns_table.dart
  • lib/shared/widgets/sidebar_nav.dart
  • lib/features/invoices/presentation/invoices_screen.dart
  • lib/shared/widgets/bms_filter_bar.dart
  • lib/providers/grn_provider.dart
  • lib/features/grn/presentation/grn_screen.dart
  • lib/features/petty_cash/presentation/petty_cash_screen.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.

Actionable comments posted: 2

🤖 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 `@analysis_options.yaml`:
- Around line 6-7: Remove the global ignore directives for
inference_failure_on_function_invocation and
inference_failure_on_instance_creation from the analysis_options.yaml file
(lines 6-7). These global suppressions conflict with the strict-inference: true
setting and mask actual type inference issues. Instead, identify the specific
callsites where these diagnostics are triggered and either fix the type
inference problems directly at those locations or apply narrowly-scoped //
ignore comments only where absolutely necessary.

In `@test/widget_test.dart`:
- Around line 4-5: Replace the tautological placeholder test (which only
verifies true == true) with a real smoke test using testWidgets that verifies
app initialization and critical UI rendering. Remove the placeholder test and
add a testWidgets block that creates the app widget, pumps it, and includes
assertions to verify that key UI elements render correctly (such as checking for
presence of critical widgets or text on the main screen). This will restore
meaningful integration coverage to catch regressions in app boot and core
workflows.
🪄 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: 60a8905c-aefc-4167-80ac-b600ff9cba74

📥 Commits

Reviewing files that changed from the base of the PR and between 7751ed2 and e9159fc.

📒 Files selected for processing (8)
  • analysis_options.yaml
  • lib/features/invoices/presentation/invoice_pdf.dart
  • lib/features/petty_cash/presentation/petty_cash_screen.dart
  • lib/features/pos/presentation/pos_screen.dart
  • lib/features/settings/presentation/settings_screen.dart
  • test/unit/auth/auth_repository_test.dart
  • test/unit/inventory/inventory_repository_test.dart
  • test/widget_test.dart
💤 Files with no reviewable changes (6)
  • test/unit/auth/auth_repository_test.dart
  • test/unit/inventory/inventory_repository_test.dart
  • lib/features/settings/presentation/settings_screen.dart
  • lib/features/invoices/presentation/invoice_pdf.dart
  • lib/features/petty_cash/presentation/petty_cash_screen.dart
  • lib/features/pos/presentation/pos_screen.dart

Comment thread analysis_options.yaml
Comment thread test/widget_test.dart
@github-advanced-security

Copy link
Copy Markdown
Contributor

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

Comment thread .github/workflows/codeql.yml Fixed
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.

3 participants