ABIANAPP_NODE_PRODUCCION/src/controllers/locationController.js
2026-06-01 16:11:02 +02:00

311 lines
8.3 KiB
JavaScript

const db = require('../config/db');
const agheeraPushClient = require('../services/agheeraPushClient');
const AGHEERA_CLIENT_ID = 532;
const getDniFromLocation = (locationData) => {
if (locationData?.extras?.alias) {
return String(locationData.extras.alias);
}
if (locationData?.alias) {
return String(locationData.alias);
}
return null;
};
const getCoordinatesFromLocation = (locationData) => {
if (locationData?.location?.coords) {
return {
lat: locationData.location.coords.latitude,
lng: locationData.location.coords.longitude
};
}
if (locationData?.coords) {
return {
lat: locationData.coords.latitude,
lng: locationData.coords.longitude
};
}
if (
Object.prototype.hasOwnProperty.call(locationData || {}, 'latitude') &&
Object.prototype.hasOwnProperty.call(locationData || {}, 'longitude')
) {
return {
lat: locationData.latitude,
lng: locationData.longitude
};
}
return null;
};
const normalizeTripId = (rawValue) => {
if (rawValue === undefined || rawValue === null || String(rawValue).trim() === '') {
return null;
}
const parsed = Number.parseInt(String(rawValue).trim(), 10);
return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
};
const getTripIdFromLocation = (locationData) => {
const candidates = [
locationData?.id_viaje,
locationData?.tripId,
locationData?.idViaje,
locationData?.params?.id_viaje,
locationData?.params?.tripId,
locationData?.extras?.id_viaje,
locationData?.extras?.tripId
];
for (const value of candidates) {
const normalized = normalizeTripId(value);
if (normalized !== null) {
return normalized;
}
}
return null;
};
const getRawTimestampFromLocation = (locationData) => {
const candidates = [
locationData?.timestamp,
locationData?.location?.timestamp
];
for (const value of candidates) {
if (value !== undefined && value !== null && String(value).trim() !== '') {
return String(value).trim();
}
}
return null;
};
const getPersistedTimestampFromLocation = (locationData) => {
const rawTimestamp = getRawTimestampFromLocation(locationData);
if (rawTimestamp === null) {
return {
value: new Date(),
usedFallback: true,
reason: 'missing'
};
}
const parsedTimestamp = new Date(rawTimestamp);
if (Number.isNaN(parsedTimestamp.getTime())) {
return {
value: new Date(),
usedFallback: true,
reason: 'invalid',
rawTimestamp
};
}
return {
value: parsedTimestamp,
usedFallback: false,
reason: null,
rawTimestamp
};
};
const pushLocationToAgheera = async ({ latitude, longitude, dni, tripId, measurementTime }) => {
if (!tripId || !dni) {
return null;
}
const [tripRows] = await db.query(
`SELECT id_cliente
FROM c_viajes
WHERE id_viaje = ?
LIMIT 1`,
[tripId]
);
if (Number.parseInt(tripRows[0]?.id_cliente, 10) !== AGHEERA_CLIENT_ID) {
return null;
}
const baseResult = {
trip_id: tripId,
attempted: true,
success: false,
http_status: null,
error: null
};
const [authorizationRows] = await db.query(
`SELECT id_tipovehiculo AS matricula
FROM c_viajes_proveedor
WHERE id_viaje = ?
AND dni = ?
ORDER BY n_proveedor ASC
LIMIT 1`,
[tripId, dni]
);
const licensePlate = String(authorizationRows[0]?.matricula || '').trim();
if (!licensePlate) {
return {
...baseResult,
error: 'LICENSE_PLATE_NOT_FOUND'
};
}
try {
const result = await agheeraPushClient.pushPosition({
latitude,
longitude,
vehicleId: licensePlate,
licensePlate,
measurementTime
});
return {
...baseResult,
success: true,
http_status: result?.status ?? null
};
} catch (error) {
console.error('Agheera push failed after location update:', {
tripId,
dni,
message: error.message,
status: error.status || null
});
return {
...baseResult,
http_status: error.status || null,
error: error.message
};
}
};
const pushLocationsToAgheera = async (locationsToPush) => {
const results = [];
for (const location of locationsToPush) {
const result = await pushLocationToAgheera(location);
if (result) {
results.push(result);
}
}
return results;
};
const saveLocation = async (req, res) => {
try {
const data = req.body;
console.log('Location payload received:', JSON.stringify(data, null, 2));
let locations = [];
let globalDni = null;
let globalTripId = null;
if (req.user?.dni) {
globalDni = String(req.user.dni);
}
if (Array.isArray(data)) {
locations = data;
} else if (data?.location && Array.isArray(data.location)) {
locations = data.location;
if (!globalDni) {
if (data.alias) {
globalDni = String(data.alias);
} else if (data.params?.alias) {
globalDni = String(data.params.alias);
}
}
globalTripId = getTripIdFromLocation(data);
} else {
locations = [data];
globalTripId = getTripIdFromLocation(data);
}
const rowsToInsert = [];
const locationsToPush = [];
for (const loc of locations) {
const coords = getCoordinatesFromLocation(loc);
const dni = globalDni || getDniFromLocation(loc);
const tripId = globalTripId !== null ? globalTripId : getTripIdFromLocation(loc);
if (coords && coords.lat !== undefined && coords.lat !== null && coords.lng !== undefined && coords.lng !== null) {
const persistedTimestamp = getPersistedTimestampFromLocation(loc);
if (persistedTimestamp.usedFallback) {
console.warn('Location timestamp fallback applied:', {
reason: persistedTimestamp.reason,
rawTimestamp: persistedTimestamp.rawTimestamp || null,
uuid: loc?.uuid || loc?.location?.uuid || null,
tripId,
dni: dni || null
});
}
rowsToInsert.push([
String(coords.lat),
String(coords.lng),
dni || null,
persistedTimestamp.value,
tripId
]);
locationsToPush.push({
latitude: coords.lat,
longitude: coords.lng,
dni,
tripId,
measurementTime: persistedTimestamp.value
});
}
}
if (rowsToInsert.length === 0) {
return res.json({
success: false,
error: 'no_coords',
message: 'No valid coordinates found in batch/object'
});
}
await db.query(
`INSERT INTO c_trazabilidad_transportista
(latitud, longitud, id_usuario, fecha, id_viaje)
VALUES ?`,
[rowsToInsert]
);
const agheeraResults = await pushLocationsToAgheera(locationsToPush);
const responseBody = {
success: true,
count: rowsToInsert.length,
message: 'Locations saved'
};
if (agheeraResults.length > 0) {
responseBody.agheera_push = agheeraResults.length === 1 ? agheeraResults[0] : agheeraResults;
}
return res.json(responseBody);
} catch (error) {
console.error('Error saving location:', error);
return res.status(500).json({ success: false, error: error.message });
}
};
module.exports = {
saveLocation
};