Skip to content

Van Sales Mobile App

VanSalesMobileApp is the Flutter application for field sales agents who operate delivery routes. It is designed for offline-first usage — agents work in areas with intermittent connectivity and sync data when back in range or at end of day.


Overview

PropertyValue
DirectoryVanSalesMobileApp/
PlatformAndroid (primary), iOS
Backend servicesAppsPortal.Apis, Inventory.Apis
Keycloak realmmicrotec
Offline supportFull (core workflows operate without connectivity)
Auth flowKeycloak OIDC / PKCE

Key Features

Route Management

  • Daily route load: At start of day (or on last successful sync), the agent downloads their assigned delivery route — a list of customers, delivery addresses, and planned order quantities.
  • Route order: Customers are listed in delivery sequence with map pins.
  • Route navigation: Deep-links to the device's map app (Google Maps / Apple Maps) for turn-by-turn navigation to each stop.
  • Stop status tracking: Each stop is marked as Pending, Visited, Delivered, or Skipped with a timestamp.

Delivery Management

  • Delivery confirmation: Agent confirms delivery by entering actual quantities delivered (may differ from planned if customer is short-shipped).
  • Partial delivery: Agents can mark a partial delivery and note the reason (no storage space, customer refused, etc.).
  • Return collection: Agents can collect goods returned by customers — returned items are logged as a sales return.
  • Photo capture: Agents can attach delivery confirmation photos (uploaded to Attachment.Apis on sync).
  • Customer signature: Digital signature collection for proof of delivery.

Sales Order Creation

Agents can create new sales orders in the field for customers not on their pre-planned route:

  • Customer lookup from cached customer list
  • Item lookup from cached product catalogue with current pricing
  • Quantity entry and discount entry (within allowed discount limits)
  • Order submission (queued for sync if offline)

Cash Collection

  • Record cash payments received from customers
  • Generate a payment receipt (PDF via MobileDesignSystem)
  • Reconcile cash collected against invoices for the day
  • End-of-day cash summary report

Inventory Van Stock

  • View current stock loaded on the van (loaded from Inventory.Apis at day start)
  • Real-time deduction as deliveries are confirmed (local calculation)
  • End-of-day van stock count submission — agent physically counts remaining stock and enters quantities

Offline-First Architecture

The van sales app cannot rely on connectivity. The offline-first strategy is built into the data layer:

Morning Sync (Day Start)

When the agent opens the app at the start of their shift:

  1. The app checks connectivity.
  2. If online, it pulls the day's route, customer list, price list, and van stock from the backend.
  3. All pulled data is stored in the local SQLite database.
  4. The agent can now operate offline for the rest of the day.

Write Queue

Every action that modifies backend data (delivery confirmation, new order, cash collection) is written to a local sync queue first:

dart
// domain/entities/sync_event.dart
class SyncEvent {
  final String id;          // UUID
  final String type;        // 'delivery', 'new_order', 'payment', 'return'
  final Map<String, dynamic> payload;
  final DateTime createdAt;
  SyncStatus status;        // pending, inProgress, synced, failed
  int retryCount;
}

Sync Execution

The SyncManager processes the queue:

  • Runs automatically whenever connectivity is detected (connectivity_plus).
  • Processes events in creation order (FIFO).
  • On failure, retries up to 3 times with exponential backoff.
  • Events that fail permanently are flagged for manual review.
  • A sync status indicator (icon + count) is always visible in the app header.

Conflict Resolution

The backend is the source of truth for prices, discount limits, and customer credit status. On morning sync:

  • New pricing supersedes any locally cached prices.
  • If a locally queued order uses a price that the backend rejects, the order is flagged and the agent is prompted to review.

Architecture

VanSalesMobileApp/
├── lib/
│   ├── core/
│   │   ├── config/             # Environment config
│   │   ├── di/                 # GetIt DI setup
│   │   ├── navigation/         # go_router routes
│   │   ├── network/            # HTTP client + auth interceptor
│   │   └── sync/               # SyncManager, SyncQueue, ConnectivityWatcher
│   ├── data/
│   │   ├── api/                # Thin wrappers over MobileAPIClients
│   │   ├── local/
│   │   │   ├── database/       # Drift (SQLite) schema and DAOs
│   │   │   └── secure_storage/ # Token storage
│   │   └── repositories/       # Implementations combining local + remote
│   ├── domain/
│   │   ├── entities/           # Route, Stop, DeliveryOrder, SalesOrder, SyncEvent
│   │   ├── repositories/       # Abstract interfaces
│   │   └── use_cases/          # StartDaySync, ConfirmDelivery, CreateOrder, SubmitVanCount
│   ├── presentation/
│   │   ├── auth/               # Login
│   │   ├── day_start/          # Morning sync screen
│   │   ├── route/              # Today's route list and map view
│   │   ├── delivery/           # Stop detail, delivery confirmation, signature
│   │   ├── sales_order/        # New order creation
│   │   ├── cash/               # Cash collection and end-of-day reconciliation
│   │   ├── van_stock/          # Van stock view and end-of-day count
│   │   └── sync_status/        # Sync progress and error review
│   └── main.dart
├── android/
├── ios/
├── melos.yaml
└── pubspec.yaml

Local Database Schema (Drift)

Key tables in the SQLite database:

TableContent
routesToday's route header
stopsDelivery stops with customer and address
planned_ordersPre-loaded orders for each stop
deliveriesConfirmed deliveries (synced or pending)
sales_ordersNew field orders (synced or pending)
customersCached customer list
itemsCached product catalogue
van_stockCurrent van inventory
sync_queueAll pending sync events
paymentsCash collection records

Shared Libraries Used

LibraryUsage in VanSalesMobileApp
MobileDesignSystemAll UI — route cards, delivery forms, stock tables, PDF receipt layout
MobileAPIClientsGenerated Dart clients for AppsPortal.Apis and Inventory.Apis
MobileSharedCompKeycloak PKCE auth, token management, base sync utilities, connectivity helper

Setup and Running

bash
cd VanSalesMobileApp

# First-time setup
melos run init

# Install / update dependencies
melos run get

# Run in debug mode
melos run run

# Build Android APK
melos run build-apk

# Run tests
melos run test

Environment Configuration

dart
class Environment {
  static const apiBaseUrl  = String.fromEnvironment('API_BASE_URL');
  static const keycloakUrl = String.fromEnvironment('KEYCLOAK_URL');
  static const realm       = String.fromEnvironment('KEYCLOAK_REALM', defaultValue: 'microtec');
}
EnvironmentAPI Base URLKeycloak URL
devhttps://gateway.microtec-test.comhttps://keycloak.microtec-test.com
stagehttps://gateway.microtecstage.comhttps://keycloak.microtecstage.com
productionhttps://gateway.onlinemicrotec.com.sahttps://keycloak.onlinemicrotec.com.sa
bash
# Build for stage
flutter build apk \
  --dart-define=API_BASE_URL=https://gateway.microtecstage.com \
  --dart-define=KEYCLOAK_URL=https://keycloak.microtecstage.com

Permissions Required

PermissionPlatformPurpose
ACCESS_FINE_LOCATIONAndroidStop navigation and delivery geo-tag
ACCESS_COARSE_LOCATIONAndroidFallback location
CAMERAAndroid, iOSDelivery photo capture
INTERNETAndroidSync and morning data pull
NSLocationWhenInUseUsageDescriptioniOSStop navigation
NSCameraUsageDescriptioniOSDelivery photo

Troubleshooting

Morning sync fails — "No route assigned"

  1. Verify the agent has a route assigned for today in the backend (Distribution module in the web app).
  2. Confirm the agent's Keycloak user has the distribution.route.view role.
  3. Check backend logs for the GET /erp-apis/distribution/routes/today endpoint.

Sync queue stuck — events not syncing

  1. Check the sync status icon in the app header for the pending count.
  2. Go to Sync Status screen — review any failed events and their error messages.
  3. Verify internet connectivity (the sync icon shows offline state if disconnected).
  4. If an event has failed 3 times, it is marked for manual review — the backend-side record may need to be created manually by a supervisor.

Delivery confirmation rejected by backend

The backend validates delivery quantities against van stock. If the delivered quantity exceeds the van's loaded stock, the backend rejects the confirmation. Ensure the morning van stock was loaded correctly.

Internal Documentation — Microtec Platform Team