feat(pacifictrans): address by current GPS location for trips and freight, reverse geocoding API, and web APK download links
This commit is contained in:
parent
ccb4db4e17
commit
9a1190cc0f
@ -49,7 +49,7 @@
|
|||||||
<a href="#reservas" id="nav-link-reservas" class="active">🚗 Viajar</a>
|
<a href="#reservas" id="nav-link-reservas" class="active">🚗 Viajar</a>
|
||||||
<a href="#fletes" id="nav-link-fletes">📦 Envíos</a>
|
<a href="#fletes" id="nav-link-fletes">📦 Envíos</a>
|
||||||
<a href="#estadisticas" id="nav-link-reviews">⭐ Reseñas</a>
|
<a href="#estadisticas" id="nav-link-reviews">⭐ Reseñas</a>
|
||||||
<a href="#descarga-apk" id="nav-link-app">📲 App Móvil</a>
|
<a href="/PacifictransGo.apk" download="PacifictransGo.apk" id="nav-link-app" style="background: rgba(16, 185, 129, 0.15); color: #34d399; border: 1px solid rgba(16, 185, 129, 0.35); border-radius: 999px; padding: 0.35rem 0.85rem; font-weight: 600; text-decoration: none; display: inline-flex; align-items: center; gap: 0.35rem;">📲 Descargar App</a>
|
||||||
|
|
||||||
<!-- Botón de apertura de Dashboard Administrativo (visible solo para Administrador) -->
|
<!-- Botón de apertura de Dashboard Administrativo (visible solo para Administrador) -->
|
||||||
<button type="button" class="btn-open-dashboard-header" id="nav-btn-open-admin" style="display: none;">
|
<button type="button" class="btn-open-dashboard-header" id="nav-btn-open-admin" style="display: none;">
|
||||||
@ -521,6 +521,27 @@
|
|||||||
<input type="text" class="form-input" id="package-desc" placeholder="Repuestos automotrices / Ropa / Medicamentos">
|
<input type="text" class="form-input" id="package-desc" placeholder="Repuestos automotrices / Ropa / Medicamentos">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- DIRECCIONES DE RECOGIDA Y ENTREGA CON UBICACIÓN GPS -->
|
||||||
|
<div class="form-group">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.35rem;">
|
||||||
|
<label class="form-label" for="freight-pickup-address" style="margin-bottom: 0;">📍 Dirección de Recogida del Paquete (Origen)</label>
|
||||||
|
<button type="button" id="btn-freight-gps-pickup" class="btn-gps-chip" title="Detectar mi ubicación actual para la recogida del paquete">
|
||||||
|
📍 Mi Ubicación Actual
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<input type="text" class="form-input" id="freight-pickup-address" placeholder="Ej: Calle 5 #66-20, Cali (o pulsa 'Mi Ubicación Actual')">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.35rem;">
|
||||||
|
<label class="form-label" for="freight-delivery-address" style="margin-bottom: 0;">🏁 Dirección de Entrega del Paquete (Destino)</label>
|
||||||
|
<button type="button" id="btn-freight-gps-delivery" class="btn-gps-chip" title="Detectar mi ubicación actual para la entrega del paquete">
|
||||||
|
📍 Mi Ubicación Actual
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<input type="text" class="form-input" id="freight-delivery-address" placeholder="Ej: Terminal Buenaventura, Muelle o Dirección exacta">
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- MODALIDAD DE DESPACHO DE ENCOMIENDA: URGENTE INMEDIATO VS PROGRAMADO -->
|
<!-- MODALIDAD DE DESPACHO DE ENCOMIENDA: URGENTE INMEDIATO VS PROGRAMADO -->
|
||||||
<div class="time-modality-container" id="freight-time-modality-container">
|
<div class="time-modality-container" id="freight-time-modality-container">
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem;">
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem;">
|
||||||
|
|||||||
@ -147,76 +147,125 @@ function initNativeBackButton() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Geolocalización GPS Nativa de Alta Precisión
|
// Variables globales de coordenadas GPS detectadas
|
||||||
function initNativeGPS() {
|
window.passengerGpsCoords = [-76.5320, 3.4215];
|
||||||
const btnGps = document.getElementById('btn-native-gps-cali');
|
window.freightPickupCoords = [-76.5320, 3.4215];
|
||||||
if (!btnGps) return;
|
window.freightDeliveryCoords = [-77.0250, 3.8820];
|
||||||
|
|
||||||
btnGps.addEventListener('click', async () => {
|
// Helper Centralizado: Obtiene coordenadas GPS y geocodifica a dirección humana real
|
||||||
|
async function getCurrentUserLocation(buttonEl = null) {
|
||||||
|
let originalText = '';
|
||||||
|
if (buttonEl) {
|
||||||
triggerHaptic('medium');
|
triggerHaptic('medium');
|
||||||
btnGps.disabled = true;
|
originalText = buttonEl.innerHTML;
|
||||||
const originalText = btnGps.innerHTML;
|
buttonEl.disabled = true;
|
||||||
btnGps.innerHTML = '⏳ Obteniendo GPS...';
|
buttonEl.innerHTML = '⏳ Obteniendo GPS...';
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let coords = null;
|
let coords = null;
|
||||||
if (window.Capacitor?.isPluginAvailable?.('Geolocation')) {
|
if (window.Capacitor?.isPluginAvailable?.('Geolocation')) {
|
||||||
const { Geolocation } = window.Capacitor.Plugins;
|
const { Geolocation } = window.Capacitor.Plugins;
|
||||||
|
try {
|
||||||
const check = await Geolocation.checkPermissions();
|
const check = await Geolocation.checkPermissions();
|
||||||
if (check.location !== 'granted') {
|
if (check.location !== 'granted') {
|
||||||
const req = await Geolocation.requestPermissions();
|
const req = await Geolocation.requestPermissions();
|
||||||
if (req.location !== 'granted') {
|
if (req.location !== 'granted') {
|
||||||
showNativeToast('⚠️ Permiso de ubicación requerido para GPS');
|
showNativeToast('⚠️ Permiso de ubicación requerido para GPS');
|
||||||
btnGps.disabled = false;
|
return null;
|
||||||
btnGps.innerHTML = originalText;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const pos = await Geolocation.getCurrentPosition({
|
} catch (pErr) { }
|
||||||
enableHighAccuracy: true,
|
|
||||||
timeout: 12000
|
const pos = await Geolocation.getCurrentPosition({
|
||||||
});
|
enableHighAccuracy: true,
|
||||||
coords = { lat: pos.coords.latitude, lng: pos.coords.longitude };
|
timeout: 12000
|
||||||
} else if (navigator.geolocation) {
|
});
|
||||||
coords = await new Promise((resolve, reject) => {
|
coords = { lat: pos.coords.latitude, lng: pos.coords.longitude };
|
||||||
navigator.geolocation.getCurrentPosition(
|
} else if (navigator.geolocation) {
|
||||||
p => resolve({ lat: p.coords.latitude, lng: p.coords.longitude }),
|
coords = await new Promise((resolve, reject) => {
|
||||||
err => reject(err),
|
navigator.geolocation.getCurrentPosition(
|
||||||
{ enableHighAccuracy: true, timeout: 12000 }
|
p => resolve({ lat: p.coords.latitude, lng: p.coords.longitude }),
|
||||||
);
|
err => reject(err),
|
||||||
|
{ enableHighAccuracy: true, timeout: 12000 }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!coords) {
|
||||||
|
showNativeToast('⚠️ No se pudo obtener la señal GPS');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buttonEl) buttonEl.innerHTML = '🔍 Identificando dirección...';
|
||||||
|
|
||||||
|
// Geocodificación inversa satelital a través del backend
|
||||||
|
let address = `Ubicación GPS (${coords.lat.toFixed(5)}, ${coords.lng.toFixed(5)})`;
|
||||||
|
let city = (coords.lat > 3.6 && coords.lng < -76.8) ? 'Buenaventura' : 'Cali';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`/api/geo/reverse?lat=${coords.lat}&lng=${coords.lng}`);
|
||||||
|
if (res.ok) {
|
||||||
|
const data = await res.json();
|
||||||
|
if (data.success && data.address) {
|
||||||
|
address = data.address;
|
||||||
|
city = data.city || city;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (geoErr) {
|
||||||
|
console.warn('⚠️ [Reverse geocode notice]:', geoErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerHaptic('success');
|
||||||
|
return {
|
||||||
|
lat: coords.lat,
|
||||||
|
lng: coords.lng,
|
||||||
|
address,
|
||||||
|
city
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('[GPS Location Error]:', err);
|
||||||
|
showNativeToast('⚠️ No se pudo obtener la ubicación actual');
|
||||||
|
triggerHaptic('warning');
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
if (buttonEl) {
|
||||||
|
buttonEl.disabled = false;
|
||||||
|
buttonEl.innerHTML = originalText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Geolocalización GPS Nativa de Alta Precisión para Pasajeros
|
||||||
|
function initNativeGPS() {
|
||||||
|
const btnGps = document.getElementById('btn-native-gps-cali');
|
||||||
|
if (!btnGps) return;
|
||||||
|
|
||||||
|
btnGps.addEventListener('click', async () => {
|
||||||
|
const loc = await getCurrentUserLocation(btnGps);
|
||||||
|
if (loc) {
|
||||||
|
window.passengerGpsCoords = [loc.lng, loc.lat];
|
||||||
|
|
||||||
|
// Centrar mapa de radar y posicionar marcador del pasajero
|
||||||
|
if (leafletMap && typeof L !== 'undefined') {
|
||||||
|
leafletMap.setView([loc.lat, loc.lng], 16);
|
||||||
|
const userIcon = L.divIcon({
|
||||||
|
className: 'user-live-gps-pin',
|
||||||
|
html: '<div class="pulse-user-dot">📍</div>',
|
||||||
|
iconSize: [36, 36],
|
||||||
|
iconAnchor: [18, 18]
|
||||||
});
|
});
|
||||||
|
L.marker([loc.lat, loc.lng], { icon: userIcon })
|
||||||
|
.addTo(leafletMap)
|
||||||
|
.bindPopup(`<b>📍 Tu Ubicación Actual</b><br>${loc.address}`)
|
||||||
|
.openPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coords) {
|
const addrInput = document.getElementById('cali-address');
|
||||||
// Centrar mapa de radar y posicionar marcador del pasajero
|
if (addrInput) {
|
||||||
if (leafletMap && typeof L !== 'undefined') {
|
addrInput.value = loc.address;
|
||||||
leafletMap.setView([coords.lat, coords.lng], 16);
|
|
||||||
const userIcon = L.divIcon({
|
|
||||||
className: 'user-live-gps-pin',
|
|
||||||
html: '<div class="pulse-user-dot">📍</div>',
|
|
||||||
iconSize: [36, 36],
|
|
||||||
iconAnchor: [18, 18]
|
|
||||||
});
|
|
||||||
L.marker([coords.lat, coords.lng], { icon: userIcon })
|
|
||||||
.addTo(leafletMap)
|
|
||||||
.bindPopup('<b>📍 Tu Ubicación Actual</b><br>Coordenadas GPS de alta precisión detectadas.')
|
|
||||||
.openPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
const addrInput = document.getElementById('cali-address');
|
|
||||||
if (addrInput) {
|
|
||||||
addrInput.value = `📍 GPS (${coords.lat.toFixed(5)}, ${coords.lng.toFixed(5)})`;
|
|
||||||
}
|
|
||||||
showNativeToast('✅ Ubicación GPS detectada con éxito');
|
|
||||||
triggerHaptic('success');
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
showNativeToast(`📍 Dirección detectada: ${loc.address}`);
|
||||||
console.warn('[GPS Error]:', err);
|
|
||||||
showNativeToast('No se pudo obtener el GPS actual');
|
|
||||||
triggerHaptic('warning');
|
|
||||||
} finally {
|
|
||||||
btnGps.disabled = false;
|
|
||||||
btnGps.innerHTML = originalText;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -2160,8 +2209,22 @@ function initPassengerCalculator() {
|
|||||||
function updateOriginDestination() {
|
function updateOriginDestination() {
|
||||||
if (!originSelect) return;
|
if (!originSelect) return;
|
||||||
const isCali = originSelect.value === 'CALI';
|
const isCali = originSelect.value === 'CALI';
|
||||||
if (addressGroup) addressGroup.style.display = isCali ? 'block' : 'none';
|
const caliAddressLabel = document.querySelector('label[for="cali-address"]');
|
||||||
if (buenaStopGroup) buenaStopGroup.style.display = isCali ? 'block' : 'none';
|
const buenaStopLabel = document.querySelector('label[for="buena-stop"]');
|
||||||
|
|
||||||
|
if (addressGroup) addressGroup.style.display = 'block';
|
||||||
|
if (buenaStopGroup) buenaStopGroup.style.display = 'block';
|
||||||
|
|
||||||
|
if (caliAddressLabel) {
|
||||||
|
caliAddressLabel.textContent = isCali
|
||||||
|
? '📍 Dirección Principal de Recogida en Cali (Domicilio Puerta a Puerta)'
|
||||||
|
: '🏁 Dirección Principal de Llegada en Cali (Entrega en Domicilio)';
|
||||||
|
}
|
||||||
|
if (buenaStopLabel) {
|
||||||
|
buenaStopLabel.textContent = isCali
|
||||||
|
? '🏁 Parada de Destino en Buenaventura'
|
||||||
|
: '📍 Punto Oficial de Salida en Buenaventura';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (originSelect) {
|
if (originSelect) {
|
||||||
@ -2232,14 +2295,18 @@ function initPassengerCalculator() {
|
|||||||
|
|
||||||
const pAddress = (!d.sameAddress && d.address && d.address.trim())
|
const pAddress = (!d.sameAddress && d.address && d.address.trim())
|
||||||
? d.address.trim()
|
? d.address.trim()
|
||||||
: (caliAddress || 'Punto Oficial Buenaventura');
|
: (caliAddress || (isCaliOrigin ? 'Cali, Valle del Cauca' : 'Buenaventura, Valle del Cauca'));
|
||||||
|
|
||||||
|
const pCoords = (i === 1 && window.passengerGpsCoords)
|
||||||
|
? window.passengerGpsCoords
|
||||||
|
: (isCaliOrigin ? [-76.5320, 3.4215] : [-77.0250, 3.8820]);
|
||||||
|
|
||||||
validatedPassengers.push({
|
validatedPassengers.push({
|
||||||
nombre: d.nombre.trim(),
|
nombre: d.nombre.trim(),
|
||||||
documentoIdentidad: d.doc.trim(),
|
documentoIdentidad: d.doc.trim(),
|
||||||
telefono: d.phone.trim(),
|
telefono: d.phone.trim(),
|
||||||
direccionRecogida: pAddress,
|
direccionRecogida: pAddress,
|
||||||
coordenadas: [-76.5320, 3.4215],
|
coordenadas: pCoords,
|
||||||
notas: d.notes ? d.notes.trim() : '',
|
notas: d.notes ? d.notes.trim() : '',
|
||||||
esTitular: (i === 1)
|
esTitular: (i === 1)
|
||||||
});
|
});
|
||||||
@ -2268,11 +2335,15 @@ function initPassengerCalculator() {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const userTripCoords = (window.passengerGpsCoords && window.passengerGpsCoords.length === 2)
|
||||||
|
? window.passengerGpsCoords
|
||||||
|
: (isCaliOrigin ? [-76.5320, 3.4215] : [-77.0250, 3.8820]);
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
usuarioId: currentUser ? currentUser._id : undefined,
|
usuarioId: currentUser ? currentUser._id : undefined,
|
||||||
sentido: isCaliOrigin ? 'CALI_A_BUENAVENTURA' : 'BUENAVENTURA_A_CALI',
|
sentido: isCaliOrigin ? 'CALI_A_BUENAVENTURA' : 'BUENAVENTURA_A_CALI',
|
||||||
direccionTexto: caliAddress || 'Terminal Buenaventura',
|
direccionTexto: caliAddress || (isCaliOrigin ? 'Cali, Valle del Cauca' : 'Buenaventura, Valle del Cauca'),
|
||||||
coordenadas: [-76.5320, 3.4215],
|
coordenadas: userTripCoords,
|
||||||
puntoFijoBuenaventura: {
|
puntoFijoBuenaventura: {
|
||||||
nombre: buenaStopSelect ? buenaStopSelect.options[buenaStopSelect.selectedIndex].text : 'Terminal de Transporte de Buenaventura',
|
nombre: buenaStopSelect ? buenaStopSelect.options[buenaStopSelect.selectedIndex].text : 'Terminal de Transporte de Buenaventura',
|
||||||
coordenadas: [-77.0250, 3.8820]
|
coordenadas: [-77.0250, 3.8820]
|
||||||
@ -2694,6 +2765,34 @@ function initFreightCalculator() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Botones GPS para Recogida y Entrega de Encomiendas
|
||||||
|
const btnFreightGpsPickup = document.getElementById('btn-freight-gps-pickup');
|
||||||
|
const btnFreightGpsDelivery = document.getElementById('btn-freight-gps-delivery');
|
||||||
|
const freightPickupInput = document.getElementById('freight-pickup-address');
|
||||||
|
const freightDeliveryInput = document.getElementById('freight-delivery-address');
|
||||||
|
|
||||||
|
if (btnFreightGpsPickup) {
|
||||||
|
btnFreightGpsPickup.addEventListener('click', async () => {
|
||||||
|
const loc = await getCurrentUserLocation(btnFreightGpsPickup);
|
||||||
|
if (loc) {
|
||||||
|
window.freightPickupCoords = [loc.lng, loc.lat];
|
||||||
|
if (freightPickupInput) freightPickupInput.value = loc.address;
|
||||||
|
showNativeToast(`📍 Recogida establecida: ${loc.address}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btnFreightGpsDelivery) {
|
||||||
|
btnFreightGpsDelivery.addEventListener('click', async () => {
|
||||||
|
const loc = await getCurrentUserLocation(btnFreightGpsDelivery);
|
||||||
|
if (loc) {
|
||||||
|
window.freightDeliveryCoords = [loc.lng, loc.lat];
|
||||||
|
if (freightDeliveryInput) freightDeliveryInput.value = loc.address;
|
||||||
|
showNativeToast(`🏁 Entrega establecida: ${loc.address}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Despacho / Creación de Encomienda con Pago Seguro y Cupón
|
// Despacho / Creación de Encomienda con Pago Seguro y Cupón
|
||||||
if (btnBookFreight) {
|
if (btnBookFreight) {
|
||||||
btnBookFreight.addEventListener('click', async (e) => {
|
btnBookFreight.addEventListener('click', async (e) => {
|
||||||
@ -2702,6 +2801,8 @@ function initFreightCalculator() {
|
|||||||
const senderPhone = document.getElementById('sender-phone')?.value.trim() || currentUser?.telefono || '';
|
const senderPhone = document.getElementById('sender-phone')?.value.trim() || currentUser?.telefono || '';
|
||||||
const receiverPhone = document.getElementById('receiver-phone')?.value.trim();
|
const receiverPhone = document.getElementById('receiver-phone')?.value.trim();
|
||||||
const packageDesc = document.getElementById('package-desc')?.value.trim();
|
const packageDesc = document.getElementById('package-desc')?.value.trim();
|
||||||
|
const freightPickupAddr = freightPickupInput?.value.trim() || 'Cali, Valle del Cauca';
|
||||||
|
const freightDeliveryAddr = freightDeliveryInput?.value.trim() || 'Terminal Buenaventura';
|
||||||
|
|
||||||
if (!senderPhone || senderPhone.replace(/\D/g, '').length < 7) {
|
if (!senderPhone || senderPhone.replace(/\D/g, '').length < 7) {
|
||||||
alert('⚠️ Por favor ingresa el teléfono/WhatsApp del remitente.');
|
alert('⚠️ Por favor ingresa el teléfono/WhatsApp del remitente.');
|
||||||
@ -2743,6 +2844,12 @@ function initFreightCalculator() {
|
|||||||
remitenteId: currentUser ? (currentUser._id || currentUser.id) : undefined,
|
remitenteId: currentUser ? (currentUser._id || currentUser.id) : undefined,
|
||||||
remitenteNombre: senderName || 'Remitente',
|
remitenteNombre: senderName || 'Remitente',
|
||||||
remitenteTelefono: senderPhone,
|
remitenteTelefono: senderPhone,
|
||||||
|
direccionRecogida: freightPickupAddr,
|
||||||
|
coordenadasRecogida: window.freightPickupCoords || [-76.5320, 3.4215],
|
||||||
|
ciudadOrigen: (window.freightPickupCoords && window.freightPickupCoords[1] > 3.6 && window.freightPickupCoords[0] < -76.8) ? 'BUENAVENTURA' : 'CALI',
|
||||||
|
direccionEntrega: freightDeliveryAddr,
|
||||||
|
coordenadasEntrega: window.freightDeliveryCoords || [-77.0250, 3.8820],
|
||||||
|
ciudadDestino: (window.freightDeliveryCoords && window.freightDeliveryCoords[1] < 3.6 && window.freightDeliveryCoords[0] > -76.8) ? 'CALI' : 'BUENAVENTURA',
|
||||||
tipoPaquete: packageTypeSelect ? packageTypeSelect.options[packageTypeSelect.selectedIndex].text : 'Paquete Pequeño',
|
tipoPaquete: packageTypeSelect ? packageTypeSelect.options[packageTypeSelect.selectedIndex].text : 'Paquete Pequeño',
|
||||||
factor: parseFloat(packageTypeSelect?.value || '1.2'),
|
factor: parseFloat(packageTypeSelect?.value || '1.2'),
|
||||||
valorDeclarado: parseFloat(declaredValueInput?.value || '100000'),
|
valorDeclarado: parseFloat(declaredValueInput?.value || '100000'),
|
||||||
|
|||||||
48
scripts/verify_gps_geocoding.py
Normal file
48
scripts/verify_gps_geocoding.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import io
|
||||||
|
import sys
|
||||||
|
import urllib.request
|
||||||
|
import json
|
||||||
|
import ssl
|
||||||
|
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
||||||
|
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')
|
||||||
|
|
||||||
|
ctx = ssl.create_default_context()
|
||||||
|
ctx.check_hostname = False
|
||||||
|
ctx.verify_mode = ssl.CERT_NONE
|
||||||
|
|
||||||
|
API_URL = "https://pacifictrans.almeira.com.co"
|
||||||
|
|
||||||
|
print("1. Probando geocodificacion inversa satelital en Cali...")
|
||||||
|
req_cali = urllib.request.Request(f"{API_URL}/api/geo/reverse?lat=3.4215&lng=-76.5320")
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(req_cali, context=ctx, timeout=10) as res:
|
||||||
|
data = json.loads(res.read().decode("utf-8"))
|
||||||
|
print(f" [OK] Cali geocodificado: {data.get('address')} | Ciudad: {data.get('city')}")
|
||||||
|
assert data.get('success') is True
|
||||||
|
except Exception as e:
|
||||||
|
print(" Aviso / Error:", e)
|
||||||
|
|
||||||
|
print("\n2. Probando geocodificacion inversa satelital en Buenaventura...")
|
||||||
|
req_bv = urllib.request.Request(f"{API_URL}/api/geo/reverse?lat=3.8820&lng=-77.0250")
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(req_bv, context=ctx, timeout=10) as res:
|
||||||
|
data = json.loads(res.read().decode("utf-8"))
|
||||||
|
print(f" [OK] Buenaventura geocodificado: {data.get('address')} | Ciudad: {data.get('city')}")
|
||||||
|
assert data.get('success') is True
|
||||||
|
except Exception as e:
|
||||||
|
print(" Aviso / Error:", e)
|
||||||
|
|
||||||
|
print("\n3. Verificando campos de direccion y botones GPS en index.html...")
|
||||||
|
req_html = urllib.request.Request(f"{API_URL}/")
|
||||||
|
with urllib.request.urlopen(req_html, context=ctx, timeout=10) as res:
|
||||||
|
html = res.read().decode("utf-8")
|
||||||
|
assert "freight-pickup-address" in html, "Falta freight-pickup-address"
|
||||||
|
assert "freight-delivery-address" in html, "Falta freight-delivery-address"
|
||||||
|
assert "btn-freight-gps-pickup" in html, "Falta btn-freight-gps-pickup"
|
||||||
|
assert "btn-freight-gps-delivery" in html, "Falta btn-freight-gps-delivery"
|
||||||
|
assert "btn-native-gps-cali" in html, "Falta btn-native-gps-cali"
|
||||||
|
print(" [OK] Todos los campos de direccion y botones GPS de ubicacion actual estan activos en la interfaz.")
|
||||||
|
|
||||||
|
print("\n[OK] Verificacion de direccion por ubicacion actual completada exitosamente.")
|
||||||
@ -49,7 +49,7 @@
|
|||||||
<a href="#reservas" id="nav-link-reservas" class="active">🚗 Viajar</a>
|
<a href="#reservas" id="nav-link-reservas" class="active">🚗 Viajar</a>
|
||||||
<a href="#fletes" id="nav-link-fletes">📦 Envíos</a>
|
<a href="#fletes" id="nav-link-fletes">📦 Envíos</a>
|
||||||
<a href="#estadisticas" id="nav-link-reviews">⭐ Reseñas</a>
|
<a href="#estadisticas" id="nav-link-reviews">⭐ Reseñas</a>
|
||||||
<a href="#descarga-apk" id="nav-link-app">📲 App Móvil</a>
|
<a href="/PacifictransGo.apk" download="PacifictransGo.apk" id="nav-link-app" style="background: rgba(16, 185, 129, 0.15); color: #34d399; border: 1px solid rgba(16, 185, 129, 0.35); border-radius: 999px; padding: 0.35rem 0.85rem; font-weight: 600; text-decoration: none; display: inline-flex; align-items: center; gap: 0.35rem;">📲 Descargar App</a>
|
||||||
|
|
||||||
<!-- Botón de apertura de Dashboard Administrativo (visible solo para Administrador) -->
|
<!-- Botón de apertura de Dashboard Administrativo (visible solo para Administrador) -->
|
||||||
<button type="button" class="btn-open-dashboard-header" id="nav-btn-open-admin" style="display: none;">
|
<button type="button" class="btn-open-dashboard-header" id="nav-btn-open-admin" style="display: none;">
|
||||||
@ -521,6 +521,27 @@
|
|||||||
<input type="text" class="form-input" id="package-desc" placeholder="Repuestos automotrices / Ropa / Medicamentos">
|
<input type="text" class="form-input" id="package-desc" placeholder="Repuestos automotrices / Ropa / Medicamentos">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- DIRECCIONES DE RECOGIDA Y ENTREGA CON UBICACIÓN GPS -->
|
||||||
|
<div class="form-group">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.35rem;">
|
||||||
|
<label class="form-label" for="freight-pickup-address" style="margin-bottom: 0;">📍 Dirección de Recogida del Paquete (Origen)</label>
|
||||||
|
<button type="button" id="btn-freight-gps-pickup" class="btn-gps-chip" title="Detectar mi ubicación actual para la recogida del paquete">
|
||||||
|
📍 Mi Ubicación Actual
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<input type="text" class="form-input" id="freight-pickup-address" placeholder="Ej: Calle 5 #66-20, Cali (o pulsa 'Mi Ubicación Actual')">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.35rem;">
|
||||||
|
<label class="form-label" for="freight-delivery-address" style="margin-bottom: 0;">🏁 Dirección de Entrega del Paquete (Destino)</label>
|
||||||
|
<button type="button" id="btn-freight-gps-delivery" class="btn-gps-chip" title="Detectar mi ubicación actual para la entrega del paquete">
|
||||||
|
📍 Mi Ubicación Actual
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<input type="text" class="form-input" id="freight-delivery-address" placeholder="Ej: Terminal Buenaventura, Muelle o Dirección exacta">
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- MODALIDAD DE DESPACHO DE ENCOMIENDA: URGENTE INMEDIATO VS PROGRAMADO -->
|
<!-- MODALIDAD DE DESPACHO DE ENCOMIENDA: URGENTE INMEDIATO VS PROGRAMADO -->
|
||||||
<div class="time-modality-container" id="freight-time-modality-container">
|
<div class="time-modality-container" id="freight-time-modality-container">
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem;">
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem;">
|
||||||
|
|||||||
@ -147,76 +147,125 @@ function initNativeBackButton() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Geolocalización GPS Nativa de Alta Precisión
|
// Variables globales de coordenadas GPS detectadas
|
||||||
function initNativeGPS() {
|
window.passengerGpsCoords = [-76.5320, 3.4215];
|
||||||
const btnGps = document.getElementById('btn-native-gps-cali');
|
window.freightPickupCoords = [-76.5320, 3.4215];
|
||||||
if (!btnGps) return;
|
window.freightDeliveryCoords = [-77.0250, 3.8820];
|
||||||
|
|
||||||
btnGps.addEventListener('click', async () => {
|
// Helper Centralizado: Obtiene coordenadas GPS y geocodifica a dirección humana real
|
||||||
|
async function getCurrentUserLocation(buttonEl = null) {
|
||||||
|
let originalText = '';
|
||||||
|
if (buttonEl) {
|
||||||
triggerHaptic('medium');
|
triggerHaptic('medium');
|
||||||
btnGps.disabled = true;
|
originalText = buttonEl.innerHTML;
|
||||||
const originalText = btnGps.innerHTML;
|
buttonEl.disabled = true;
|
||||||
btnGps.innerHTML = '⏳ Obteniendo GPS...';
|
buttonEl.innerHTML = '⏳ Obteniendo GPS...';
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let coords = null;
|
let coords = null;
|
||||||
if (window.Capacitor?.isPluginAvailable?.('Geolocation')) {
|
if (window.Capacitor?.isPluginAvailable?.('Geolocation')) {
|
||||||
const { Geolocation } = window.Capacitor.Plugins;
|
const { Geolocation } = window.Capacitor.Plugins;
|
||||||
|
try {
|
||||||
const check = await Geolocation.checkPermissions();
|
const check = await Geolocation.checkPermissions();
|
||||||
if (check.location !== 'granted') {
|
if (check.location !== 'granted') {
|
||||||
const req = await Geolocation.requestPermissions();
|
const req = await Geolocation.requestPermissions();
|
||||||
if (req.location !== 'granted') {
|
if (req.location !== 'granted') {
|
||||||
showNativeToast('⚠️ Permiso de ubicación requerido para GPS');
|
showNativeToast('⚠️ Permiso de ubicación requerido para GPS');
|
||||||
btnGps.disabled = false;
|
return null;
|
||||||
btnGps.innerHTML = originalText;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const pos = await Geolocation.getCurrentPosition({
|
} catch (pErr) { }
|
||||||
enableHighAccuracy: true,
|
|
||||||
timeout: 12000
|
const pos = await Geolocation.getCurrentPosition({
|
||||||
});
|
enableHighAccuracy: true,
|
||||||
coords = { lat: pos.coords.latitude, lng: pos.coords.longitude };
|
timeout: 12000
|
||||||
} else if (navigator.geolocation) {
|
});
|
||||||
coords = await new Promise((resolve, reject) => {
|
coords = { lat: pos.coords.latitude, lng: pos.coords.longitude };
|
||||||
navigator.geolocation.getCurrentPosition(
|
} else if (navigator.geolocation) {
|
||||||
p => resolve({ lat: p.coords.latitude, lng: p.coords.longitude }),
|
coords = await new Promise((resolve, reject) => {
|
||||||
err => reject(err),
|
navigator.geolocation.getCurrentPosition(
|
||||||
{ enableHighAccuracy: true, timeout: 12000 }
|
p => resolve({ lat: p.coords.latitude, lng: p.coords.longitude }),
|
||||||
);
|
err => reject(err),
|
||||||
|
{ enableHighAccuracy: true, timeout: 12000 }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!coords) {
|
||||||
|
showNativeToast('⚠️ No se pudo obtener la señal GPS');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buttonEl) buttonEl.innerHTML = '🔍 Identificando dirección...';
|
||||||
|
|
||||||
|
// Geocodificación inversa satelital a través del backend
|
||||||
|
let address = `Ubicación GPS (${coords.lat.toFixed(5)}, ${coords.lng.toFixed(5)})`;
|
||||||
|
let city = (coords.lat > 3.6 && coords.lng < -76.8) ? 'Buenaventura' : 'Cali';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(`/api/geo/reverse?lat=${coords.lat}&lng=${coords.lng}`);
|
||||||
|
if (res.ok) {
|
||||||
|
const data = await res.json();
|
||||||
|
if (data.success && data.address) {
|
||||||
|
address = data.address;
|
||||||
|
city = data.city || city;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (geoErr) {
|
||||||
|
console.warn('⚠️ [Reverse geocode notice]:', geoErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerHaptic('success');
|
||||||
|
return {
|
||||||
|
lat: coords.lat,
|
||||||
|
lng: coords.lng,
|
||||||
|
address,
|
||||||
|
city
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
console.warn('[GPS Location Error]:', err);
|
||||||
|
showNativeToast('⚠️ No se pudo obtener la ubicación actual');
|
||||||
|
triggerHaptic('warning');
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
if (buttonEl) {
|
||||||
|
buttonEl.disabled = false;
|
||||||
|
buttonEl.innerHTML = originalText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Geolocalización GPS Nativa de Alta Precisión para Pasajeros
|
||||||
|
function initNativeGPS() {
|
||||||
|
const btnGps = document.getElementById('btn-native-gps-cali');
|
||||||
|
if (!btnGps) return;
|
||||||
|
|
||||||
|
btnGps.addEventListener('click', async () => {
|
||||||
|
const loc = await getCurrentUserLocation(btnGps);
|
||||||
|
if (loc) {
|
||||||
|
window.passengerGpsCoords = [loc.lng, loc.lat];
|
||||||
|
|
||||||
|
// Centrar mapa de radar y posicionar marcador del pasajero
|
||||||
|
if (leafletMap && typeof L !== 'undefined') {
|
||||||
|
leafletMap.setView([loc.lat, loc.lng], 16);
|
||||||
|
const userIcon = L.divIcon({
|
||||||
|
className: 'user-live-gps-pin',
|
||||||
|
html: '<div class="pulse-user-dot">📍</div>',
|
||||||
|
iconSize: [36, 36],
|
||||||
|
iconAnchor: [18, 18]
|
||||||
});
|
});
|
||||||
|
L.marker([loc.lat, loc.lng], { icon: userIcon })
|
||||||
|
.addTo(leafletMap)
|
||||||
|
.bindPopup(`<b>📍 Tu Ubicación Actual</b><br>${loc.address}`)
|
||||||
|
.openPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coords) {
|
const addrInput = document.getElementById('cali-address');
|
||||||
// Centrar mapa de radar y posicionar marcador del pasajero
|
if (addrInput) {
|
||||||
if (leafletMap && typeof L !== 'undefined') {
|
addrInput.value = loc.address;
|
||||||
leafletMap.setView([coords.lat, coords.lng], 16);
|
|
||||||
const userIcon = L.divIcon({
|
|
||||||
className: 'user-live-gps-pin',
|
|
||||||
html: '<div class="pulse-user-dot">📍</div>',
|
|
||||||
iconSize: [36, 36],
|
|
||||||
iconAnchor: [18, 18]
|
|
||||||
});
|
|
||||||
L.marker([coords.lat, coords.lng], { icon: userIcon })
|
|
||||||
.addTo(leafletMap)
|
|
||||||
.bindPopup('<b>📍 Tu Ubicación Actual</b><br>Coordenadas GPS de alta precisión detectadas.')
|
|
||||||
.openPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
const addrInput = document.getElementById('cali-address');
|
|
||||||
if (addrInput) {
|
|
||||||
addrInput.value = `📍 GPS (${coords.lat.toFixed(5)}, ${coords.lng.toFixed(5)})`;
|
|
||||||
}
|
|
||||||
showNativeToast('✅ Ubicación GPS detectada con éxito');
|
|
||||||
triggerHaptic('success');
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
showNativeToast(`📍 Dirección detectada: ${loc.address}`);
|
||||||
console.warn('[GPS Error]:', err);
|
|
||||||
showNativeToast('No se pudo obtener el GPS actual');
|
|
||||||
triggerHaptic('warning');
|
|
||||||
} finally {
|
|
||||||
btnGps.disabled = false;
|
|
||||||
btnGps.innerHTML = originalText;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -2160,8 +2209,22 @@ function initPassengerCalculator() {
|
|||||||
function updateOriginDestination() {
|
function updateOriginDestination() {
|
||||||
if (!originSelect) return;
|
if (!originSelect) return;
|
||||||
const isCali = originSelect.value === 'CALI';
|
const isCali = originSelect.value === 'CALI';
|
||||||
if (addressGroup) addressGroup.style.display = isCali ? 'block' : 'none';
|
const caliAddressLabel = document.querySelector('label[for="cali-address"]');
|
||||||
if (buenaStopGroup) buenaStopGroup.style.display = isCali ? 'block' : 'none';
|
const buenaStopLabel = document.querySelector('label[for="buena-stop"]');
|
||||||
|
|
||||||
|
if (addressGroup) addressGroup.style.display = 'block';
|
||||||
|
if (buenaStopGroup) buenaStopGroup.style.display = 'block';
|
||||||
|
|
||||||
|
if (caliAddressLabel) {
|
||||||
|
caliAddressLabel.textContent = isCali
|
||||||
|
? '📍 Dirección Principal de Recogida en Cali (Domicilio Puerta a Puerta)'
|
||||||
|
: '🏁 Dirección Principal de Llegada en Cali (Entrega en Domicilio)';
|
||||||
|
}
|
||||||
|
if (buenaStopLabel) {
|
||||||
|
buenaStopLabel.textContent = isCali
|
||||||
|
? '🏁 Parada de Destino en Buenaventura'
|
||||||
|
: '📍 Punto Oficial de Salida en Buenaventura';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (originSelect) {
|
if (originSelect) {
|
||||||
@ -2232,14 +2295,18 @@ function initPassengerCalculator() {
|
|||||||
|
|
||||||
const pAddress = (!d.sameAddress && d.address && d.address.trim())
|
const pAddress = (!d.sameAddress && d.address && d.address.trim())
|
||||||
? d.address.trim()
|
? d.address.trim()
|
||||||
: (caliAddress || 'Punto Oficial Buenaventura');
|
: (caliAddress || (isCaliOrigin ? 'Cali, Valle del Cauca' : 'Buenaventura, Valle del Cauca'));
|
||||||
|
|
||||||
|
const pCoords = (i === 1 && window.passengerGpsCoords)
|
||||||
|
? window.passengerGpsCoords
|
||||||
|
: (isCaliOrigin ? [-76.5320, 3.4215] : [-77.0250, 3.8820]);
|
||||||
|
|
||||||
validatedPassengers.push({
|
validatedPassengers.push({
|
||||||
nombre: d.nombre.trim(),
|
nombre: d.nombre.trim(),
|
||||||
documentoIdentidad: d.doc.trim(),
|
documentoIdentidad: d.doc.trim(),
|
||||||
telefono: d.phone.trim(),
|
telefono: d.phone.trim(),
|
||||||
direccionRecogida: pAddress,
|
direccionRecogida: pAddress,
|
||||||
coordenadas: [-76.5320, 3.4215],
|
coordenadas: pCoords,
|
||||||
notas: d.notes ? d.notes.trim() : '',
|
notas: d.notes ? d.notes.trim() : '',
|
||||||
esTitular: (i === 1)
|
esTitular: (i === 1)
|
||||||
});
|
});
|
||||||
@ -2268,11 +2335,15 @@ function initPassengerCalculator() {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const userTripCoords = (window.passengerGpsCoords && window.passengerGpsCoords.length === 2)
|
||||||
|
? window.passengerGpsCoords
|
||||||
|
: (isCaliOrigin ? [-76.5320, 3.4215] : [-77.0250, 3.8820]);
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
usuarioId: currentUser ? currentUser._id : undefined,
|
usuarioId: currentUser ? currentUser._id : undefined,
|
||||||
sentido: isCaliOrigin ? 'CALI_A_BUENAVENTURA' : 'BUENAVENTURA_A_CALI',
|
sentido: isCaliOrigin ? 'CALI_A_BUENAVENTURA' : 'BUENAVENTURA_A_CALI',
|
||||||
direccionTexto: caliAddress || 'Terminal Buenaventura',
|
direccionTexto: caliAddress || (isCaliOrigin ? 'Cali, Valle del Cauca' : 'Buenaventura, Valle del Cauca'),
|
||||||
coordenadas: [-76.5320, 3.4215],
|
coordenadas: userTripCoords,
|
||||||
puntoFijoBuenaventura: {
|
puntoFijoBuenaventura: {
|
||||||
nombre: buenaStopSelect ? buenaStopSelect.options[buenaStopSelect.selectedIndex].text : 'Terminal de Transporte de Buenaventura',
|
nombre: buenaStopSelect ? buenaStopSelect.options[buenaStopSelect.selectedIndex].text : 'Terminal de Transporte de Buenaventura',
|
||||||
coordenadas: [-77.0250, 3.8820]
|
coordenadas: [-77.0250, 3.8820]
|
||||||
@ -2694,6 +2765,34 @@ function initFreightCalculator() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Botones GPS para Recogida y Entrega de Encomiendas
|
||||||
|
const btnFreightGpsPickup = document.getElementById('btn-freight-gps-pickup');
|
||||||
|
const btnFreightGpsDelivery = document.getElementById('btn-freight-gps-delivery');
|
||||||
|
const freightPickupInput = document.getElementById('freight-pickup-address');
|
||||||
|
const freightDeliveryInput = document.getElementById('freight-delivery-address');
|
||||||
|
|
||||||
|
if (btnFreightGpsPickup) {
|
||||||
|
btnFreightGpsPickup.addEventListener('click', async () => {
|
||||||
|
const loc = await getCurrentUserLocation(btnFreightGpsPickup);
|
||||||
|
if (loc) {
|
||||||
|
window.freightPickupCoords = [loc.lng, loc.lat];
|
||||||
|
if (freightPickupInput) freightPickupInput.value = loc.address;
|
||||||
|
showNativeToast(`📍 Recogida establecida: ${loc.address}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btnFreightGpsDelivery) {
|
||||||
|
btnFreightGpsDelivery.addEventListener('click', async () => {
|
||||||
|
const loc = await getCurrentUserLocation(btnFreightGpsDelivery);
|
||||||
|
if (loc) {
|
||||||
|
window.freightDeliveryCoords = [loc.lng, loc.lat];
|
||||||
|
if (freightDeliveryInput) freightDeliveryInput.value = loc.address;
|
||||||
|
showNativeToast(`🏁 Entrega establecida: ${loc.address}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Despacho / Creación de Encomienda con Pago Seguro y Cupón
|
// Despacho / Creación de Encomienda con Pago Seguro y Cupón
|
||||||
if (btnBookFreight) {
|
if (btnBookFreight) {
|
||||||
btnBookFreight.addEventListener('click', async (e) => {
|
btnBookFreight.addEventListener('click', async (e) => {
|
||||||
@ -2702,6 +2801,8 @@ function initFreightCalculator() {
|
|||||||
const senderPhone = document.getElementById('sender-phone')?.value.trim() || currentUser?.telefono || '';
|
const senderPhone = document.getElementById('sender-phone')?.value.trim() || currentUser?.telefono || '';
|
||||||
const receiverPhone = document.getElementById('receiver-phone')?.value.trim();
|
const receiverPhone = document.getElementById('receiver-phone')?.value.trim();
|
||||||
const packageDesc = document.getElementById('package-desc')?.value.trim();
|
const packageDesc = document.getElementById('package-desc')?.value.trim();
|
||||||
|
const freightPickupAddr = freightPickupInput?.value.trim() || 'Cali, Valle del Cauca';
|
||||||
|
const freightDeliveryAddr = freightDeliveryInput?.value.trim() || 'Terminal Buenaventura';
|
||||||
|
|
||||||
if (!senderPhone || senderPhone.replace(/\D/g, '').length < 7) {
|
if (!senderPhone || senderPhone.replace(/\D/g, '').length < 7) {
|
||||||
alert('⚠️ Por favor ingresa el teléfono/WhatsApp del remitente.');
|
alert('⚠️ Por favor ingresa el teléfono/WhatsApp del remitente.');
|
||||||
@ -2743,6 +2844,12 @@ function initFreightCalculator() {
|
|||||||
remitenteId: currentUser ? (currentUser._id || currentUser.id) : undefined,
|
remitenteId: currentUser ? (currentUser._id || currentUser.id) : undefined,
|
||||||
remitenteNombre: senderName || 'Remitente',
|
remitenteNombre: senderName || 'Remitente',
|
||||||
remitenteTelefono: senderPhone,
|
remitenteTelefono: senderPhone,
|
||||||
|
direccionRecogida: freightPickupAddr,
|
||||||
|
coordenadasRecogida: window.freightPickupCoords || [-76.5320, 3.4215],
|
||||||
|
ciudadOrigen: (window.freightPickupCoords && window.freightPickupCoords[1] > 3.6 && window.freightPickupCoords[0] < -76.8) ? 'BUENAVENTURA' : 'CALI',
|
||||||
|
direccionEntrega: freightDeliveryAddr,
|
||||||
|
coordenadasEntrega: window.freightDeliveryCoords || [-77.0250, 3.8820],
|
||||||
|
ciudadDestino: (window.freightDeliveryCoords && window.freightDeliveryCoords[1] < 3.6 && window.freightDeliveryCoords[0] > -76.8) ? 'CALI' : 'BUENAVENTURA',
|
||||||
tipoPaquete: packageTypeSelect ? packageTypeSelect.options[packageTypeSelect.selectedIndex].text : 'Paquete Pequeño',
|
tipoPaquete: packageTypeSelect ? packageTypeSelect.options[packageTypeSelect.selectedIndex].text : 'Paquete Pequeño',
|
||||||
factor: parseFloat(packageTypeSelect?.value || '1.2'),
|
factor: parseFloat(packageTypeSelect?.value || '1.2'),
|
||||||
valorDeclarado: parseFloat(declaredValueInput?.value || '100000'),
|
valorDeclarado: parseFloat(declaredValueInput?.value || '100000'),
|
||||||
|
|||||||
@ -123,6 +123,65 @@ const server = http.createServer(async (req, res) => {
|
|||||||
return authService.verifyRole(token, allowedRoles);
|
return authService.verifyRole(token, allowedRoles);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 1.1. Geocodificación inversa satelital (Dirección por ubicación actual)
|
||||||
|
if (pathname === '/api/geo/reverse' && req.method === 'GET') {
|
||||||
|
const lat = parseFloat(url.searchParams.get('lat') || '');
|
||||||
|
const lng = parseFloat(url.searchParams.get('lng') || url.searchParams.get('lon') || '');
|
||||||
|
if (isNaN(lat) || isNaN(lng)) {
|
||||||
|
return sendJson(400, { success: false, error: 'Coordenadas lat y lng inválidas' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const nominatimUrl = `https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${lat}&lon=${lng}&zoom=18&addressdetails=1`;
|
||||||
|
const fetchRes = await fetch(nominatimUrl, {
|
||||||
|
headers: {
|
||||||
|
'User-Agent': 'PacificTransGO/2.0 (admin@pacifictrans.co)',
|
||||||
|
'Accept-Language': 'es',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (fetchRes.ok) {
|
||||||
|
const data = await fetchRes.json();
|
||||||
|
const addr = data.address || {};
|
||||||
|
|
||||||
|
// Formatear dirección al estilo colombiano
|
||||||
|
const parts: string[] = [];
|
||||||
|
if (addr.road) {
|
||||||
|
let roadPart = addr.road;
|
||||||
|
if (addr.house_number) roadPart += ` #${addr.house_number}`;
|
||||||
|
parts.push(roadPart);
|
||||||
|
}
|
||||||
|
if (addr.neighbourhood || addr.suburb) {
|
||||||
|
parts.push(`Barrio ${addr.neighbourhood || addr.suburb}`);
|
||||||
|
}
|
||||||
|
const city = addr.city || addr.town || addr.municipality || (lat > 3.6 ? 'Buenaventura' : 'Cali');
|
||||||
|
parts.push(city);
|
||||||
|
if (addr.state) parts.push(addr.state);
|
||||||
|
|
||||||
|
const formattedAddress = parts.length > 0 ? parts.join(', ') : data.display_name;
|
||||||
|
|
||||||
|
return sendJson(200, {
|
||||||
|
success: true,
|
||||||
|
address: formattedAddress,
|
||||||
|
city,
|
||||||
|
coordinates: [lng, lat],
|
||||||
|
raw: addr,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
console.warn('⚠️ [Nominatim Reverse Geocode Warning]:', err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback inteligente si la red satelital o Nominatim no responde
|
||||||
|
const inferredCity = (lat > 3.7 && lng < -76.8) ? 'Buenaventura' : 'Cali';
|
||||||
|
return sendJson(200, {
|
||||||
|
success: true,
|
||||||
|
address: `Ubicación GPS (${lat.toFixed(5)}, ${lng.toFixed(5)}), ${inferredCity}`,
|
||||||
|
city: inferredCity,
|
||||||
|
coordinates: [lng, lat],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 2. Pooling inteligente (Transporte)
|
// 2. Pooling inteligente (Transporte)
|
||||||
if (pathname === '/api/trips/pool' && req.method === 'POST') {
|
if (pathname === '/api/trips/pool' && req.method === 'POST') {
|
||||||
const body = await getJsonBody();
|
const body = await getJsonBody();
|
||||||
@ -619,15 +678,38 @@ const server = http.createServer(async (req, res) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Descarga directa del APK Oficial Android
|
// Descarga directa del APK Oficial Android
|
||||||
if (pathname === '/PacifictransGo.apk' || pathname === '/download/apk') {
|
if (
|
||||||
|
pathname === '/PacifictransGo.apk' ||
|
||||||
|
pathname === '/download/apk' ||
|
||||||
|
pathname === '/apk' ||
|
||||||
|
pathname === '/app' ||
|
||||||
|
pathname === '/descarga-apk' ||
|
||||||
|
pathname === '/descargar-apk'
|
||||||
|
) {
|
||||||
const localApk = path.join(PUBLIC_DIR, 'PacifictransGo.apk');
|
const localApk = path.join(PUBLIC_DIR, 'PacifictransGo.apk');
|
||||||
const fallbackApk = path.resolve(__dirname, '../../../pacifictrans-app/public/PacifictransGo.apk');
|
const fallbackApk = path.resolve(__dirname, '../../../pacifictrans-app/public/PacifictransGo.apk');
|
||||||
const vpsApk = '/home/carlos/apps/dripzone-app/public/PacifictransGo.apk';
|
const vpsApk = '/home/carlos/apps/dripzone-app/public/PacifictransGo.apk';
|
||||||
|
|
||||||
const targetApk = fs.existsSync(localApk) ? localApk : (fs.existsSync(fallbackApk) ? fallbackApk : vpsApk);
|
const targetApk = fs.existsSync(localApk) ? localApk : (fs.existsSync(fallbackApk) ? fallbackApk : vpsApk);
|
||||||
if (serveStaticFile(targetApk, MIME_TYPES['.apk'])) return;
|
if (fs.existsSync(targetApk)) {
|
||||||
|
try {
|
||||||
|
const stat = fs.statSync(targetApk);
|
||||||
|
res.writeHead(200, {
|
||||||
|
'Content-Type': 'application/vnd.android.package-archive',
|
||||||
|
'Content-Length': stat.size,
|
||||||
|
'Content-Disposition': 'attachment; filename="PacifictransGo.apk"',
|
||||||
|
'Cache-Control': 'no-cache',
|
||||||
|
'Access-Control-Allow-Origin': '*',
|
||||||
|
});
|
||||||
|
fs.createReadStream(targetApk).pipe(res);
|
||||||
|
return;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error serving APK:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Archivo estático directo (HTML, CSS, JS, Imágenes)
|
// Archivo estático directo (HTML, CSS, JS, Imágenes)
|
||||||
let relativePath = pathname === '/' ? 'index.html' : pathname.replace(/^\//, '');
|
let relativePath = pathname === '/' ? 'index.html' : pathname.replace(/^\//, '');
|
||||||
let targetPath = path.join(PUBLIC_DIR, relativePath);
|
let targetPath = path.join(PUBLIC_DIR, relativePath);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user