Files
gps-backend/cron/UpdateJobStatusWorker.js
meusinfirmary f4ce94cab9 update
2025-06-17 10:39:22 +09:00

143 lines
4.3 KiB
JavaScript

const path = require("path");
require("dotenv").config({ path: path.resolve(__dirname, "../.env") });
const LibWinston = require("../library/LibWinston");
const OrderStatusModels = require("../models/OrderStatusModels");
const db = require("../config/dbMysqlConn");
const moment = require("moment");
const schedulerName = "UPDATE JOB STATUS";
const Logger = LibWinston.initialize(schedulerName);
// ✅ Status constants
const STATUS = {
AWAL: 22,
DI_PICKUP: 2,
OTW: 3,
SAMPAI: 4,
};
// 🔍 Fungsi Haversine untuk jarak circle
function haversine(lat1, lon1, lat2, lon2) {
const toRad = (x) => (x * Math.PI) / 180;
const R = 6371 * 1000; // radius bumi meter
const dLat = toRad(lat2 - lat1);
const dLon = toRad(lon2 - lon1);
const a = Math.sin(dLat / 2) ** 2 + Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLon / 2) ** 2;
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c; // hasil meter
}
// 🔍 Fungsi cek point di dalam square (bounding box)
function isPointInSquare(point, boundaryLatLngs) {
const lats = boundaryLatLngs.map((p) => parseFloat(p.lat));
const lngs = boundaryLatLngs.map((p) => parseFloat(p.lng));
const minLat = Math.min(...lats);
const maxLat = Math.max(...lats);
const minLng = Math.min(...lngs);
const maxLng = Math.max(...lngs);
return point.lat >= minLat && point.lat <= maxLat && point.lng >= minLng && point.lng <= maxLng;
}
const go = async () => {
Logger.log("info", `${schedulerName}: ${moment().format("YYYY-MM-DD HH:mm:ss")}`);
try {
const result = await OrderStatusModels.GetList();
const rows = result.rows;
if (!rows || rows.length === 0) return;
console.log("rows: ", rows);
for (let row of rows) {
if (!row.pck_latlng || !row.drp_latlng || !row.latitude || !row.longitude) continue;
const lat = parseFloat(row.latitude);
const lng = parseFloat(row.longitude);
if (isNaN(lat) || isNaN(lng)) continue;
let pckBoundary, drpBoundary;
try {
pckBoundary = JSON.parse(row.pck_latlng);
drpBoundary = JSON.parse(row.drp_latlng);
} catch (e) {
Logger.log("error", `Invalid JSON for order ${row.ord_code}`);
continue;
}
// Ambil center titik untuk perhitungan jarak circle
const pckCenter = pckBoundary[0];
const drpCenter = drpBoundary[0];
const distToPickup = haversine(lat, lng, parseFloat(pckCenter.lat), parseFloat(pckCenter.lng));
const distToDrop = haversine(lat, lng, parseFloat(drpCenter.lat), parseFloat(drpCenter.lng));
// Tentukan apakah di pickup zone
let inPickupZone = false;
if (row.pck_type === "circle") {
inPickupZone = distToPickup <= row.pck_radius;
} else if (row.pck_type === "square") {
inPickupZone = isPointInSquare({ lat, lng }, pckBoundary);
}
// Tentukan apakah di drop zone
let inDropZone = false;
if (row.drp_type === "circle") {
inDropZone = distToDrop <= row.drp_radius;
} else if (row.drp_type === "square") {
inDropZone = isPointInSquare({ lat, lng }, drpBoundary);
}
let newStatus = row.status;
if (inPickupZone) {
newStatus = STATUS.DI_PICKUP;
} else if (!inPickupZone && !inDropZone) {
newStatus = STATUS.OTW;
} else if (inDropZone) {
newStatus = STATUS.SAMPAI;
}
if (newStatus !== row.status) {
await new Promise((resolve, reject) => {
db.query(`UPDATE t_orders SET status = ? WHERE code = ?`, [newStatus, row.ord_code], (err) => {
if (err) {
Logger.log("error", `Gagal update status order ${row.ord_code}: ${err.message}`);
return reject(err);
}
console.log(`Order ${row.ord_code}: status updated from ${row.status} to ${newStatus}`);
resolve();
});
});
// Jika sudah sampai (status SAMPAI), reset data kendaraan
if (newStatus === STATUS.SAMPAI) {
await new Promise((resolve, reject) => {
db.query(`UPDATE t_vehicles SET is_in_ord = 2, ord_id = 0, ord_code = '0' WHERE id = ?`, [row.id], (err) => {
if (err) {
Logger.log("error", `Gagal reset kendaraan ID ${row.id}: ${err.message}`);
return reject(err);
}
console.log(`Vehicle ${row.id} reset: is_in_ord=2, ord_id=0, ord_code='0'`);
resolve();
});
});
}
}
}
} catch (error) {
Logger.log("error", `Job error: ${error.message}`);
}
};
const index = async () => {
while (true) {
await go();
await new Promise((r) => setTimeout(r, 3000));
}
};
index();