updated the sheet

This commit is contained in:
2026-08-28 18:16:28 +05:30
parent 69f4f3e909
commit 074cc0eccf
43 changed files with 2617 additions and 1201 deletions

View File

@@ -3,7 +3,8 @@ import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter_tts/flutter_tts.dart';
import 'package:geolocator/geolocator.dart';
import 'package:http/http.dart' as http;
import 'package:miler/data/api_config.dart';
import 'package:miler/data/miler_api.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:audioplayers/audioplayers.dart';
import 'dart:math' as math;
@@ -20,7 +21,6 @@ class BackgroundDeliveryLog {
static final CreateDeliveryLogProvider _logProvider =
CreateDeliveryLogProvider();
static final http.Client _httpClient = http.Client();
static final FlutterTts _tts = FlutterTts();
static final AudioPlayer _proximityPlayer = AudioPlayer();
@@ -60,38 +60,37 @@ class BackgroundDeliveryLog {
final now = DateTime.now();
final today = '${now.year}-${_pad(now.month)}-${_pad(now.day)}';
// Build API URL using v1 endpoint (getdeliveries)
final bool isLive = ApiConstants.mainRoute == 'live';
final baseUrl = isLive
? ApiConstants.currentDeliveryLive
: ApiConstants.currentDeliveryDev;
final uri = Uri.parse(baseUrl).replace(
queryParameters: {
'userid': userId.toString(),
'fromdate': today,
'todate': today,
't': DateTime.now().millisecondsSinceEpoch.toString(),
},
);
debugPrint('[ACTIVE_DELIVERY_LOG][BG] Fetching deliveries: $uri');
// Fetch deliveries from API using v1 endpoint
final deliveries = await _fetchDeliveriesFromApi(uri);
// ── The delivery twin of the pickup fetch, with the same two faults ──
//
// It built a `deliveries/getdeliveries` URL by hand and fetched it with a
// bare `_httpClient.get` — **no bearer token** — and put `userid` in the
// query string. The URL itself already resolved to a v1 route through the
// [DeliveryApi] facade, so the call could only ever be answered 401.
//
// And the filter looked for `orderstatus == 'active'`, which is not a
// value this app's vocabulary contains: [ApiConfig.legacyStatusFromNew]
// maps the v1 statuses to `assigned` / `accepted` / `arrived` / `picked`,
// never to `active`. So it returned nothing on every tick and fell
// through to the shift-end check, which is what the device log shows.
//
// `GET /miler/bookings` through [MilerApi], asked with the session, about
// the rider the session names.
final res = await MilerApi.bookings(date: today);
final deliveries = res.list;
debugPrint(
'[ACTIVE_DELIVERY_LOG][BG] API returned ${deliveries.length} items',
'[ACTIVE_DELIVERY_LOG][BG] /miler/bookings -> ${res.status}, '
'${deliveries.length} items',
);
// Filter for active orders only
const inProgress = {'accepted', 'arrived', 'picked'};
final activeOrders = deliveries.whereType<Map<String, dynamic>>().where((
order,
) {
final status = (order['orderstatus']?.toString().toLowerCase() ?? '')
.trim();
final isActive = status == 'active';
return isActive;
final status = ApiConfig.legacyStatusFromNew(
(order['status'] ?? order['orderstatus'])?.toString(),
);
return inProgress.contains(status);
}).toList();
if (activeOrders.isEmpty) {
@@ -202,11 +201,8 @@ class BackgroundDeliveryLog {
'logstatus': await _resolveLogStatus(orderId, coords),
};
// Determine API endpoint
final url = ApiConstants.mainRoute == 'live'
? ApiConstants.createDeliveryLogLive
: ApiConstants.createDeliveryLogDev;
// v1: `/miler/consignments/logs`, via the DeliveryApi facade.
final url = ApiConstants.createDeliveryLogLive;
// Post the log
debugPrint('[ACTIVE_DELIVERY_LOG][BG] Posting log for $orderId');
@@ -434,33 +430,6 @@ class BackgroundDeliveryLog {
}
/// Fetch deliveries from API using v1 endpoint
static Future<List<dynamic>> _fetchDeliveriesFromApi(Uri uri) async {
try {
final res = await _httpClient
.get(uri)
.timeout(const Duration(seconds: 10));
if (res.statusCode >= 200 && res.statusCode < 300) {
final decoded = json.decode(res.body);
final data = decoded is Map<String, dynamic>
? (decoded['details'] ?? decoded['data'] ?? decoded)
: decoded;
if (data is List) {
return data;
}
if (data is Map && data['items'] is List) {
return data['items'] as List;
}
return [];
}
return [];
} catch (e) {
return [];
}
}
/// Helper to pad numbers with leading zero
static String _pad(int n) => n.toString().padLeft(2, '0');
@@ -540,10 +509,6 @@ class BackgroundDeliveryLog {
final List<String> remaining = [];
bool anySuccess = false;
final url = ApiConstants.mainRoute == 'live'
? ApiConstants.createDeliveryLogLive
: ApiConstants.createDeliveryLogDev;
for (final itemStr in queue) {
try {
final Map<String, dynamic> item = jsonDecode(itemStr);
@@ -554,6 +519,8 @@ class BackgroundDeliveryLog {
if (payload.isEmpty) continue;
// v1: `/miler/consignments/logs`, via the DeliveryApi facade.
final url = ApiConstants.createDeliveryLogLive;
debugPrint(
'[ACTIVE_DELIVERY_LOG][BG][OFFLINE] Retrying for orderId: $orderId',
);
@@ -770,14 +737,18 @@ class BackgroundDeliveryLog {
'[AUTO_SHIFT_END] 🚀 Initiating auto-break and offline sequence...',
);
// 1. Get Required IDs
// ── The four ids and the fix are no longer this function's business ──
//
// `userid`, `partnerid`, `shiftid`, `logid` and a position were assembled
// here to fill a legacy break-log body. On v1 the break and the duty end
// are both keyed on the **token**: `POST /miler/breaks/start` opens a
// break for whoever the session names, and `PUT /miler/duty/end` closes
// whichever duty log is open for them. Sending an id would not make it
// more correct; it is what let the old call be made unauthenticated.
//
// `userid` is still read, as the one guard worth keeping: no signed-in
// rider, nothing to end.
final int userid = prefs.getInt('userid') ?? prefs.getInt('userId') ?? 0;
final int partnerid =
prefs.getInt('partnerid') ?? prefs.getInt('partnerId') ?? 0;
final int shiftid =
prefs.getInt('shiftid') ?? prefs.getInt('shiftId') ?? 0;
final int logid = prefs.getInt('logid') ?? prefs.getInt('logId') ?? 0;
if (userid == 0) {
debugPrint(
'[AUTO_SHIFT_END] ❌ Missing userid, cannot create break log',
@@ -785,61 +756,28 @@ class BackgroundDeliveryLog {
return;
}
// 2. Get Location
final Map<String, String>? coords = await _getCoordinatesWithFallback();
final String lat = coords?['lat'] ?? '0';
final String lng = coords?['lng'] ?? '0';
// 3. Prepare Break Log Payload
final now = DateTime.now();
final int localBreakId =
(DateTime.now().millisecondsSinceEpoch % 900) + 100; // Random-ish ID
final String breakdate =
'${now.year}-${_pad(now.month)}-${_pad(now.day)} ${_pad(now.hour)}:${_pad(now.minute)}:${_pad(now.second)}';
final String breakstart =
'${_pad(now.hour)}:${_pad(now.minute)}:${_pad(now.second)}';
final payload = <String, dynamic>{
"breakid": localBreakId,
"logid": logid,
"breakdate": breakdate,
"userid": userid,
"partnerid": partnerid,
"shiftid": shiftid,
"breakstart": breakstart,
"breakend": "",
"breakhours": 0.0,
"latitude": lat,
"longitude": lng,
};
// 4. Call API to Create Break
final url = ApiConstants.mainRoute == 'live'
? ApiConstants.createBreakRiderLogLive
: ApiConstants.createBreakRiderLogDev;
debugPrint('[AUTO_SHIFT_END] Creating break log: $url');
// We use a separate provider instance or http call if needed,
// but _logProvider is for delivery logs. We need a generic post or use http directly.
// Since we don't have BreakRiderLogProvider here, we'll use http directly for simplicity and isolation.
// 4. Close the shift with a break, on v1.
//
// This hand-posted the retired backend's `partners/createbreaklog`
// with a bare `_httpClient.post` and no bearer
// token — an unauthenticated write keyed on a `userid` in the
// body. `POST /miler/breaks/start` is the v1 endpoint, and
// [MilerApi] attaches the session.
debugPrint('[AUTO_SHIFT_END] Creating break log (v1)');
try {
final response = await _httpClient
.post(
Uri.parse(url),
headers: {'Content-Type': 'application/json'},
body: jsonEncode(payload),
)
.timeout(const Duration(seconds: 10));
final res = await MilerApi.startBreak('Shift_End');
if (response.statusCode >= 200 && response.statusCode < 300) {
if (res.ok) {
debugPrint('[AUTO_SHIFT_END] ✅ Break log created successfully');
// Parse response to get server break ID if needed, but mainly we just need to go offline
final body = jsonDecode(response.body);
final det = (body['details'] is Map) ? body['details'] : body;
final serverBreakId = det['breakid'];
final serverBreakId = res.map['breaklogid'] ?? res.map['breakid'];
if (serverBreakId != null) {
await prefs.setInt(
@@ -851,7 +789,7 @@ class BackgroundDeliveryLog {
await prefs.setInt('break_start_epoch', now.millisecondsSinceEpoch);
} else {
debugPrint(
'[AUTO_SHIFT_END] ⚠️ Failed to create break log: ${response.statusCode}',
'[AUTO_SHIFT_END] ⚠️ Failed to create break log: ${res.status}',
);
}
} catch (e) {
@@ -863,27 +801,15 @@ class BackgroundDeliveryLog {
await prefs.setInt('onduty', 0);
await prefs.setBool('online', false);
// 6. Update Rider Log (Set Duty = 0)
// We should also update the main rider log to say onduty=0
final updateUrl = ApiConstants.mainRoute == 'live'
? ApiConstants.updateRiderLogLive
: ApiConstants.updateRiderLogDev;
final updatePayload = {
"userid": userid,
"onduty": 0,
"latitude": lat,
"longitude": lng,
};
// 6. End duty, on v1.
//
// Was an unauthenticated POST of `{userid, onduty: 0}` to the
// legacy `updateriderlog`. `PUT /miler/duty/end` closes whichever
// duty log is open for the token's rider, which is the same fact
// without the id or the open door.
try {
await _httpClient
.post(
Uri.parse(updateUrl),
headers: {'Content-Type': 'application/json'},
body: jsonEncode(updatePayload),
)
.timeout(const Duration(seconds: 5));
await MilerApi.endDuty();
debugPrint('[AUTO_SHIFT_END] ✅ Rider status updated to Offline');
} catch (_) {}

View File

@@ -6,7 +6,6 @@ import 'package:flutter/foundation.dart';
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
import 'dart:math' as math;
import 'package:shared_preferences/shared_preferences.dart';
import 'package:miler/xpress/views/helpers/constants/apiconstants.dart';
import 'package:miler/xpress/providers/Riderlog/riderlog_provider.dart';
import 'package:miler/xpress/background/backgroundservice.dart';
import 'package:geolocator/geolocator.dart';
@@ -354,12 +353,9 @@ class _BackgroundRiderLog {
payload['lastname'] = lastName.trim();
}
final base = ApiConstants.mainRoute == 'live'
? ApiConstants.createRiderLogLive
: ApiConstants.createRiderLogDev;
final provider = CreateRiderLogProvider();
final resp = await provider.createRiderLog(base, payload);
final resp = await provider.createRiderLog(payload);
if (resp == null || resp.isEmpty) return;
final det = (resp['details'] is Map<String, dynamic>)