updated the sheet
This commit is contained in:
@@ -3,15 +3,15 @@ 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:shared_preferences/shared_preferences.dart';
|
||||
import 'package:audioplayers/audioplayers.dart';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:miler/providers/pickuplog/pickuplog_provider.dart';
|
||||
import 'package:miler/data/api_config.dart';
|
||||
import 'package:miler/data/miler_api.dart';
|
||||
import 'package:miler/data/device_telemetry.dart';
|
||||
import 'package:miler/providers/notifications/notificationservce.dart';
|
||||
import 'package:miler/views/helpers/constants/apiconstants.dart';
|
||||
import 'package:miler/utils/kalman_filter.dart';
|
||||
|
||||
/// Background service for managing active pickup logs
|
||||
@@ -20,7 +20,6 @@ class BackgroundCollectionLog {
|
||||
static DateTime? _lastUpdateTime;
|
||||
|
||||
static final CreatePickupLogProvider _logProvider = CreatePickupLogProvider();
|
||||
static final http.Client _httpClient = http.Client();
|
||||
static final FlutterTts _tts = FlutterTts();
|
||||
static final AudioPlayer _proximityPlayer = AudioPlayer();
|
||||
|
||||
@@ -60,38 +59,39 @@ class BackgroundCollectionLog {
|
||||
final now = DateTime.now();
|
||||
final today = '${now.year}-${_pad(now.month)}-${_pad(now.day)}';
|
||||
|
||||
// Build API URL using v1 endpoint (getpickup)
|
||||
final bool isLive = ApiConstants.mainRoute == 'live';
|
||||
final baseUrl = isLive
|
||||
? ApiConstants.currentPickupLive
|
||||
: ApiConstants.currentPickupDev;
|
||||
|
||||
final uri = Uri.parse(baseUrl).replace(
|
||||
queryParameters: {
|
||||
'userid': userId.toString(),
|
||||
'fromdate': today,
|
||||
'todate': today,
|
||||
't': DateTime.now().millisecondsSinceEpoch.toString(),
|
||||
},
|
||||
);
|
||||
|
||||
debugPrint('[ACTIVE_COLLECTION_LOG][BG] Fetching Pickup: $uri');
|
||||
|
||||
// Fetch pickup from API using v1 endpoint
|
||||
final pickups = await _fetchPickupsFromApi(uri);
|
||||
// ── This asked the pre-v1 backend, with the wrong question ──
|
||||
//
|
||||
// It built a `pickups/getpickups` URL on the retired backend by hand
|
||||
// and fetched it with a bare `_httpClient.get` — **no bearer token**, and
|
||||
// `userid` in the query string, so the rider's day was readable by id
|
||||
// from an unauthenticated call.
|
||||
//
|
||||
// It could never have worked anyway. The filter below looked for
|
||||
// `orderstatus == 'active'`, and `active` is not a value this app's own
|
||||
// vocabulary contains: [ApiConfig.legacyStatusFromNew] maps the v1
|
||||
// statuses to `assigned` / `accepted` / `arrived` / `picked`, and never to
|
||||
// `active`. So on every tick this returned 0 items and fell through to
|
||||
// the shift-end check — which is exactly what the device log shows.
|
||||
//
|
||||
// `GET /miler/bookings` is the v1 question, asked with the token, about
|
||||
// the rider the token names. The filter is the real vocabulary: work the
|
||||
// rider has taken on and not yet collected.
|
||||
final res = await MilerApi.bookings(date: today);
|
||||
final pickups = res.list;
|
||||
|
||||
debugPrint(
|
||||
'[ACTIVE_COLLECTION_LOG][BG] API returned ${pickups.length} items',
|
||||
'[ACTIVE_COLLECTION_LOG][BG] /miler/bookings -> ${res.status}, '
|
||||
'${pickups.length} items',
|
||||
);
|
||||
|
||||
// Filter for active bookings only
|
||||
const inProgress = {'accepted', 'arrived'};
|
||||
final activeOrders = pickups.whereType<Map<String, dynamic>>().where((
|
||||
Booking,
|
||||
) {
|
||||
final status = (Booking['orderstatus']?.toString().toLowerCase() ?? '')
|
||||
.trim();
|
||||
final isActive = status == 'active';
|
||||
return isActive;
|
||||
final status = ApiConfig.legacyStatusFromNew(
|
||||
(Booking['status'] ?? Booking['orderstatus'])?.toString(),
|
||||
);
|
||||
return inProgress.contains(status);
|
||||
}).toList();
|
||||
|
||||
if (activeOrders.isEmpty) {
|
||||
@@ -189,7 +189,9 @@ class BackgroundCollectionLog {
|
||||
// so every per-stop breadcrumb reached the console with a position and
|
||||
// nothing to explain a gap in the trail. Read from the same place the
|
||||
// rider heartbeat reads it. See [DeviceTelemetry].
|
||||
final telemetry = await DeviceTelemetry.read(locationService: coords['status']);
|
||||
final telemetry = await DeviceTelemetry.read(
|
||||
locationService: coords['status'],
|
||||
);
|
||||
|
||||
// Build payload with coordinates and timestamp
|
||||
payloadWithCoords = <String, dynamic>{
|
||||
@@ -211,11 +213,6 @@ class BackgroundCollectionLog {
|
||||
'logstatus': await _resolveLogStatus(orderId, coords),
|
||||
};
|
||||
|
||||
// Determine API endpoint
|
||||
final url = ApiConstants.mainRoute == 'live'
|
||||
? ApiConstants.createPickupLogLive
|
||||
: ApiConstants.createPickupLogDev;
|
||||
|
||||
// Post the log
|
||||
debugPrint('[ACTIVE_COLLECTION_LOG][BG] Posting pickup log for $orderId');
|
||||
|
||||
@@ -427,33 +424,6 @@ class BackgroundCollectionLog {
|
||||
}
|
||||
|
||||
/// Fetch pickup from API using v1 endpoint
|
||||
static Future<List<dynamic>> _fetchPickupsFromApi(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');
|
||||
@@ -533,10 +503,6 @@ class BackgroundCollectionLog {
|
||||
final List<String> remaining = [];
|
||||
bool anySuccess = false;
|
||||
|
||||
final url = ApiConstants.mainRoute == 'live'
|
||||
? ApiConstants.createPickupLogLive
|
||||
: ApiConstants.createPickupLogDev;
|
||||
|
||||
for (final itemStr in queue) {
|
||||
try {
|
||||
final Map<String, dynamic> item = jsonDecode(itemStr);
|
||||
@@ -761,14 +727,18 @@ class BackgroundCollectionLog {
|
||||
'[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',
|
||||
@@ -776,61 +746,28 @@ class BackgroundCollectionLog {
|
||||
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 pickup 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(
|
||||
@@ -842,7 +779,7 @@ class BackgroundCollectionLog {
|
||||
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) {
|
||||
@@ -854,27 +791,15 @@ class BackgroundCollectionLog {
|
||||
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 (_) {}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user