Files
gps-backend/controllers/ServiceDriverController.js
2025-05-29 08:59:40 +00:00

2610 lines
111 KiB
JavaScript
Executable File

const fs = require('fs');
const moment = require('moment');
const Validator = require('validatorjs');
const path = require("path");
const axios = require('axios').default;
const url = require('url');
const mysql = require('mysql');
const response = require('../config/response');
const Helper = require('../library/LibHelper');
// const LibPassword = require('../library/LibPassword');
const LibJwt = require('../library/LibJwt');
const LibHelper = require('../library/LibHelper');
const LibFirebase = require('../library/LibFirebase');
const LibCurl = require('../library/LibCurl');
const LibFile = require('../library/LibFile');
const LibMail = require('../library/LibMail');
const LibLogReqResApi = require('../library/LibLogReqResApi');
const LibImgGeotagging = require('../library/LibImgGeotagging');
const GpsTracksModels = require('../models/GpsTracksModels');
const DriversModels = require('../models/DriversModels');
const OrdersModels = require('../models/OrdersModels');
const OrdersPickupsModels = require('../models/OrdersPickupsModels');
const OrdersDropsModels = require('../models/OrdersDropsModels');
const OrdersPckDropsModels = require('../models/OrdersPckDropsModels');
const OrdersDriversUploadsModels = require('../models/OrdersDriversUploadsModels');
const OrdersCheckpointsModels = require('../models/OrdersCheckpointsModels');
const VhcModels = require('../models/VhcModels');
const ZoneModels = require('../models/ZoneModels');
const UsersModels = require('../models/UsersModels');
const OrdersAItemsModels = require('../models/OrdersAItemsModels');
const OrdersTerminsModels = require('../models/OrdersTerminsModels');
const LogbookKeysModels = require('../models/LogbookKeysModels');
const LogbookOrdersModels = require('../models/LogbookOrdersModels');
const OrdersLogsTfModels = require('../models/OrdersLogsTfModels');
const DanaModels = require('../models/DanaModels');
Validator.useLang('id');
moment.locale('id');
class ServiceDriverController {
// AUTHENTIFICATION
async login(req, res) {
let apiRes = {}
try {
const now = moment().unix()
// input validation
const input = {
phone: req.body.phone,
device_id: req.body.device_id,
fcm_token: req.body.fcm_token,
lat: req.body.lat,
lng: req.body.lng,
brand: req.body.brand || '0',
product: req.body.product || '0',
model: req.body.model || '0',
type: req.body.type || '0',
manufacture: req.body.manufacture || '0',
android_id: req.body.android_id || '0',
host: req.body.host || '0',
hardware: req.body.hardware || '0',
display: req.body.display || '0',
board: req.body.board || '0',
bootloader: req.body.bootloader || '0',
v_sdk_int: req.body.v_sdk_int || '0',
v_preview_sdk_int: req.body.v_preview_sdk_int || '0',
v_release: req.body.v_release || '0',
v_incremental: req.body.v_incremental || '0',
v_codename: req.body.v_codename || '0',
v_base_os: req.body.v_base_os || '0',
v_security_patch: req.body.v_security_patch || '0',
// password: req.body.password,
};
const rulesInput = {
phone: 'required|integer',
device_id: 'required|string|max:16',
fcm_token: 'required|string|max:255',
lat: 'required|string|max:125',
lng: 'required|string|max:125',
brand: 'string|max:125',
product: 'string|max:125',
model: 'string|max:125',
type: 'string|max:125',
manufacture: 'string|max:125',
android_id: 'string|max:125',
host: 'string|max:125',
hardware: 'string|max:125',
display: 'string|max:125',
board: 'string|max:125',
bootloader: 'string|max:125',
v_sdk_int: 'string|max:125',
v_preview_sdk_int: 'string|max:125',
v_release: 'string|max:125',
v_incremental: 'string|max:125',
v_codename: 'string|max:125',
v_base_os: 'string|max:125',
v_security_patch: 'string|max:125',
// password: 'required|string',
};
const isInputValid = new Validator(input, rulesInput);
if (isInputValid.fails()) {
apiRes = JSON.parse(JSON.stringify(response[422]));
apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
// login
const getDrivers = await DriversModels.findPhone(input.phone);
if (getDrivers.length < 1) {
apiRes = JSON.parse(JSON.stringify(response[404]));
apiRes.meta.code += '_1';
apiRes.meta.message = 'account not found';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
// const isPwValid = await LibPassword.checkPw(getDrivers[0].password, input.password);
// if (!isPwValid) {
// apiRes.meta = JSON.parse(JSON.stringify(response['wrong_password'].meta));
// return res.status(200).json(apiRes);
// }
/**
* create or update t_users based on t_drivers data without password, with role as driver
* create or update t_phone_devices
* case multiple device => update hanya berlaku jika device_id(IMEI) sama, jadi did bisa duplicate namun device_id(IMEI) tidak ada yang duplicate
* case single device => update hanya berlaku jika did sama, jadi tidak ada did dan device_id(IMEI) yang duplicate
* harus tentuin salah satu mau single / multiple, soalnya nanti bingung ngambil fcm_tokennya
* is_login ? taro di t_phone_devices aja, jadi ketauan kalo dia logout
* login_lat & login_lng ? taro di t_phone_devices aja, jadi ketauan device ini adanya dimana
* jika sedang ada yang login maka driver tidak bisa dihapus
*/
// yang sekarang 1 device 1 driver
const checkDeviceByDid = await DriversModels.getDeviceByDid(getDrivers[0].id);
let phone_device_id = 0;
if (checkDeviceByDid.length < 1) {
const checkDeviceByImei = await DriversModels.getDeviceByImei(input.device_id);
if (checkDeviceByImei.length < 1) {
const insDevice = { ...input };
insDevice.did = getDrivers[0].id;
insDevice.is_active = DriversModels.IS_ACTIVE;
insDevice.is_login = DriversModels.IS_LOGIN;
insDevice.login_lat = input.lat;
insDevice.login_lng = input.lng;
insDevice.login_at = now;
insDevice.crt = now;
insDevice.updt = now;
delete insDevice.phone;
delete insDevice.lat;
delete insDevice.lng;
const insPhoneDevice = await DriversModels.insPhoneDevice(insDevice);
phone_device_id = insPhoneDevice.insertId;
} else {
if (checkDeviceByImei[0].is_login === DriversModels.IS_LOGIN) {
if (checkDeviceByImei[0].device_id !== input.device_id) { // || checkDeviceByImei[0].phone !== input.phone
apiRes = JSON.parse(JSON.stringify(response[400]));
apiRes.meta.code += '_2';
apiRes.meta.message = 'account is used by another phone, please contact customer service';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
}
const updtDevice = { ...input };
updtDevice.did = getDrivers[0].id;
updtDevice.is_active = DriversModels.IS_ACTIVE;
updtDevice.is_login = DriversModels.IS_LOGIN;
updtDevice.login_lat = input.lat;
updtDevice.login_lng = input.lng;
updtDevice.login_at = now;
updtDevice.updt = now;
delete updtDevice.phone;
delete updtDevice.lat;
delete updtDevice.lng;
const updtPhoneDevice = await DriversModels.updtPhoneDevice(updtDevice, checkDeviceByImei[0].id);
phone_device_id = checkDeviceByImei[0].id;
}
} else {
if (checkDeviceByDid[0].is_login === DriversModels.IS_LOGIN) {
if (checkDeviceByDid[0].device_id !== input.device_id) { // || checkDeviceByDid[0].phone !== input.phone
apiRes = JSON.parse(JSON.stringify(response[400]));
apiRes.meta.code += '_2';
apiRes.meta.message = 'account is used by another phone, please contact customer service';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
}
const updtDevice = { ...input };
updtDevice.did = getDrivers[0].id;
updtDevice.is_active = DriversModels.IS_ACTIVE;
updtDevice.is_login = DriversModels.IS_LOGIN;
updtDevice.login_lat = input.lat;
updtDevice.login_lng = input.lng;
updtDevice.login_at = now;
updtDevice.updt = now;
delete updtDevice.phone;
delete updtDevice.lat;
delete updtDevice.lng;
const updtPhoneDevice = await DriversModels.updtPhoneDevice(updtDevice, checkDeviceByDid[0].id);
phone_device_id = checkDeviceByDid[0].id;
}
delete getDrivers[0].client_group_id;
delete getDrivers[0].client_div_id;
delete getDrivers[0].client_gp_id;
// delete getDrivers[0].status;
delete getDrivers[0].is_in_ord;
delete getDrivers[0].ord_id;
delete getDrivers[0].ord_code;
delete getDrivers[0].ord_ids;
delete getDrivers[0].ord_code;
// success response
const jwt = await LibJwt.createToken({
did: getDrivers[0].id,
phone: getDrivers[0].phone,
device_id: input.device_id,
phone_device_id,
uid: 0,
});
const profileDriver = {
drv_id: getDrivers[0].id,
nik: getDrivers[0].nik,
fullname: getDrivers[0].fullname,
fullname2: getDrivers[0].fullname2 || '',
phone: getDrivers[0].phone_code + '' +getDrivers[0].phone,
phone2: getDrivers[0].phone2_code + '' +getDrivers[0].phone2,
email: getDrivers[0].email || '',
dob: moment(getDrivers[0].dob).format('DD-MM-YYYY'),
age: getDrivers[0].age || 0,
gender: (getDrivers[0].gender === 1) ? 'Laki-Laki' : 'Perempuan',
blood: getDrivers[0].blood || '',
fulladdress: getDrivers[0].fulladdress || '',
vdr_id: getDrivers[0].vendor_id || 0,
// status: getDrivers[0].status,
// is_in_ord: getDrivers[0].is_in_ord,
// ord_ids: (getDrivers[0].ord_ids === null) ? getDrivers[0].ord_ids : JSON.parse(getDrivers[0].ord_ids),
token: jwt.token,
};
apiRes = JSON.parse(JSON.stringify(response[200]));
apiRes.meta.message = 'success login';
apiRes.data = profileDriver;
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
} catch (e) {
apiRes = JSON.parse(JSON.stringify(response[500]));
apiRes.meta.message += Helper.setErrMsg(': ' + e.message);
LibLogReqResApi.log(req, apiRes);
return res.status(500).json(apiRes);
}
}
async profile(req, res) {
let apiRes = {}
try {
const now = moment().unix();
const { did } = req.auth;
const getDrivers = await DriversModels.find(did);
if (getDrivers.length < 1) {
apiRes = JSON.parse(JSON.stringify(response[404]));
apiRes.meta.code += '_1';
apiRes.meta.message = 'account not found, please login again';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const profileDriver = {
drv_id: getDrivers[0].id,
nik: getDrivers[0].nik,
fullname: getDrivers[0].fullname,
fullname2: getDrivers[0].fullname2 || '',
phone: getDrivers[0].phone_code + '' +getDrivers[0].phone,
phone2: getDrivers[0].phone2_code + '' +getDrivers[0].phone2,
email: getDrivers[0].email || '',
dob: (getDrivers[0].dob) ? moment(getDrivers[0].dob).format('DD-MM-YYYY') : '',
age: getDrivers[0].age || 0,
gender: (getDrivers[0].gender === 1) ? 'Laki-Laki' : 'Perempuan',
blood: getDrivers[0].blood || '',
fulladdress: getDrivers[0].fulladdress || '',
vdr_id: getDrivers[0].vendor_id || 0,
// status: getDrivers[0].status,
// is_in_ord: getDrivers[0].is_in_ord,
// ord_ids: (getDrivers[0].ord_ids === null) ? getDrivers[0].ord_ids : JSON.parse(getDrivers[0].ord_ids),
};
apiRes = JSON.parse(JSON.stringify(response[200]));
apiRes.data = profileDriver;
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
} catch (e) {
apiRes = JSON.parse(JSON.stringify(response[500]));
apiRes.meta.message += Helper.setErrMsg(': ' + e.message);
LibLogReqResApi.log(req, apiRes);
return res.status(500).json(apiRes);
}
}
async logout(req, res) {
let apiRes = {}
try {
const now = moment().unix();
const { phone_device_id } = req.auth;
const updtDevice = {
is_login: DriversModels.IS_LOGOUT,
logout_at: now,
};
const updtPhoneDevice = await DriversModels.updtPhoneDevice(updtDevice, phone_device_id);
apiRes = JSON.parse(JSON.stringify(response[200]));
apiRes.meta.message = 'success logout';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
} catch (e) {
apiRes = JSON.parse(JSON.stringify(response[500]));
apiRes.meta.message += Helper.setErrMsg(': ' + e.message);
LibLogReqResApi.log(req, apiRes);
return res.status(500).json(apiRes);
}
}
// JOBS
async listActiveJobs(req, res) {
let apiRes = {}
try {
const now = moment().unix();
// console.log(Buffer.from(`32_34_34_28`, 'ascii').toString('hex'));
const { did, device_id, phone } = req.auth;
const filter = {
is_active: OrdersModels.IS_ACTIVE,
// order_status: [OrdersModels.STTS_HAVE_GET_VHC,OrdersModels.STTS_PCK,OrdersModels.STTS_GO,OrdersModels.STTS_ARV,OrdersModels.STTS_DROP],
delivery_statuses: [
OrdersPckDropsModels.STTS_DELIVERY_OTW_PICKUP,OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_PICKUP,OrdersPckDropsModels.STTS_DELIVERY_PROCESS_PICKUP
,OrdersPckDropsModels.STTS_DELIVERY_FINISH_PICKUP,OrdersPckDropsModels.STTS_DELIVERY_TRAVEL_DOC,OrdersPckDropsModels.STTS_DELIVERY_OTW_DROP
,OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_DROP,OrdersPckDropsModels.STTS_DELIVERY_PROCESS_DROP,OrdersPckDropsModels.STTS_DELIVERY_FINISH_DROP
// ,OrdersPckDropsModels.STTS_DELIVERY_HANDOVER_DOC
],
get_prefer_type_truck: 1,
couple_pck_drop: 1,
get_pic_zone: 1,
did,
};
const activeOrders = await OrdersModels.listOrders(filter);
if (activeOrders.length < 1) {
apiRes = JSON.parse(JSON.stringify(response[404]));
apiRes.meta.code = '200'; // += '_1';
apiRes.meta.message = 'there are no active orders';
apiRes.data = [];
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const formattedActiveOrders = [], includedPckId = [], includedDropId = [];
for (const row of activeOrders) {
if (includedPckId.includes(row.ord_pck_id) || includedDropId.includes(row.ord_drop_id)) continue;
includedPckId.push(row.ord_pck_id);
includedDropId.push(row.ord_drop_id);
const detail_id = Buffer.from(`${row.ord_id}_${row.ord_pck_id}_${row.ord_drop_id}_${row.ord_pck_drop_id}`, 'ascii').toString('hex');
// const decoded_detail_id = Buffer.from('34365f34305f3339', 'hex').toString('ascii');
let status_desc = '';
if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_OTW_PICKUP) { status_desc = 'Kendaraan Menuju Lokasi Jemput'; }
else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_PICKUP) { status_desc = 'Kendaraan Tiba dilokasi Jemput'; }
else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_PROCESS_PICKUP) { status_desc = 'Kendaraan Memuat Barang'; }
else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_FINISH_PICKUP) { status_desc = 'Kendaraan Selesai Memuat Barang'; }
else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_TRAVEL_DOC) { status_desc = 'Driver Sudah Mengupload Dokumen Perjalanan'; }
else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_OTW_DROP) { status_desc = 'Kendaraan Menuju Lokasi Pengantaran'; }
else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_DROP) { status_desc = 'Kendaraan Sampai Dilokasi Pengantaran'; }
else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_PROCESS_DROP) { status_desc = 'Kendaraan Membongkar Barang'; }
else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_FINISH_DROP) { status_desc = 'Kendaraan Selesai Membongkar Barang'; }
else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_HANDOVER_DOC) { status_desc = 'Driver Sudah Mengupload Dokumen Serah Terima'; }
// validate is_going / ongoing by pickup date
let is_ongoing = false;
if (row.set_pck_at) {
let cur_date = moment.unix(now).set({hour:0,minute:0,second:0,millisecond:0}); // as start
let pck_date = moment.unix(row.set_pck_at).set({hour:0,minute:0,second:0,millisecond:0}); // as end
let duration = moment.duration(pck_date.diff(cur_date));
if (duration.asDays() <= 0) {
is_ongoing = true;
}
}
// https://stackoverflow.com/questions/23299950/convert-date-to-utc-using-moment-js
formattedActiveOrders.push({
detail_id,
// ord_pck_drop_id: row.ord_pck_drop_id,
ord_id: row.ord_id,
ord_code: row.ord_code,
// pck_total: row.pck_total,
// drop_total: row.drop_total,
is_ongoing,
pck: {
id: row.ord_pck_id,
set_at_unix: row.set_pck_at,
// set_at_raw: (row.set_pck_at != 0) ? moment.unix(row.set_pck_at).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', // utc
set_at_raw: (row.set_pck_at != 0) ? moment.unix(row.set_pck_at).format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', // gmt +7
// stts: row.stts_pck,
name: row.pck_name,
addr: row.pck_addr,
pic_name: row.pck_pic_name,
pic_phone: row.pck_pic_phone_code + '' + row.pck_pic_phone_val,
pic_mail: row.pck_pic_mail || '',
client_name: row.c_name,
client_phone: row.c_phone_code + '' + row.c_phone_val,
client_mail: row.c_mail,
client_prefer_truck_type: row.prefer_truck_type_name || '',
},
// going_at_unix: row.going_at,
// going_at_raw: (row.going_at != 0) ? moment.unix(row.going_at).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '',
// going_note: row.going_note,
drop: {
id: row.ord_drop_id,
// stts: row.ord_drop_stts,
name: row.drop_name,
addr: row.drop_addr,
pic_name: row.drop_pic_name,
pic_phone: row.drop_pic_phone_code + '' + row.drop_pic_phone_val,
pic_mail: row.drop_pic_mail || '',
client_name: row.c_name,
client_phone: row.c_phone_code + '' + row.c_phone_val,
client_mail: row.c_mail,
client_prefer_truck_type: row.prefer_truck_type_name || '',
},
// arrived_at_unix: row.arrived_at,
// arrived_at_raw: (row.arrived_at != 0) ? moment.unix(row.arrived_at).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '',
// arrived_note: row.arrived_note,
lead_time: row.lead_time,
lead_time_unit: row.lead_time_unit,
// buy_price: row.buy_price,
status: row.stts_delivery,
status_desc,
// c_name: row.c_name,
// c_phone: row.c_phone_code + '' + row.c_phone_val,
// c_mail: row.c_mail,
// prefer_truck_type: row.prefer_truck_type,
// prefer_truck_type_name: row.prefer_truck_type_name || '',
vdr: {
name: row.vdr_name,
phone: row.vdr_phone_code + '' + row.vdr_phone_val,
mail: row.vdr_mail,
addr: row.vdr_addr,
},
drv: {
name: row.drv_name,
kenek_name: row.drv_name2,
phone: row.drv_phone_code + '' + row.drv_phone_val,
kenek_phone: row.drv_phone2_code + '' + row.drv_phone2_val,
mail: row.drv_mail,
addr: row.drv_addr,
},
vhc: {
name_bukan_nopol: row.vhc_name,
nopol1: row.vhc_nopol1,
nopol2: row.vhc_nopol2,
nopol3: row.vhc_nopol3,
nopol_full: row.vhc_nopol1 + ' ' + row.vhc_nopol2 + ' ' + row.vhc_nopol3,
},
});
}
apiRes = JSON.parse(JSON.stringify(response[200]));
apiRes.data = formattedActiveOrders;
// apiRes.raw = activeOrders;
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
} catch (e) {
apiRes = JSON.parse(JSON.stringify(response[500]));
apiRes.meta.message += Helper.setErrMsg(': ' + e.message);
LibLogReqResApi.log(req, apiRes);
return res.status(500).json(apiRes);
}
}
async detailJobs(req, res) {
let apiRes = {}
try {
const now = moment().unix();
const { did, device_id, phone } = req.auth;
const { detail_id } = req.params;
// input validation
const input = {
detail_id,
};
const rulesInput = {
detail_id: 'required|string',
};
const isInputValid = new Validator(input, rulesInput);
if (isInputValid.fails()) {
apiRes = JSON.parse(JSON.stringify(response[422]));
apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const decoded_detail_id = Buffer.from(detail_id, 'hex').toString('ascii');
const split_detail_id = decoded_detail_id.split('_');
if (split_detail_id.length !== 4) {
apiRes = JSON.parse(JSON.stringify(response[422]));
apiRes.meta.code += '_1';
apiRes.meta.message = 'detail id not valid';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const [ ord_id, pck_id, drop_id, ord_pck_drop_id ] = split_detail_id;
const filter = {
ord_id,
pck_id,
drop_id,
ord_pck_drop_id,
// is_active: OrdersModels.IS_ACTIVE,
// order_status: [OrdersModels.STTS_HAVE_GET_VHC,OrdersModels.STTS_PCK,OrdersModels.STTS_GO,OrdersModels.STTS_ARV,OrdersModels.STTS_DROP],
get_prefer_type_truck: 1,
couple_pck_drop: 1,
get_pic_zone: 1,
did,
};
const activeOrders = await OrdersModels.listOrders(filter);
if (activeOrders.length < 1) {
apiRes = JSON.parse(JSON.stringify(response[404]));
apiRes.meta.code += '_4';
apiRes.meta.message = 'job not found';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const drvUps = await OrdersDriversUploadsModels.list({ ord_id,pck_id,drop_id,ord_pck_drop_id });
/**
* 0 => disable
* 1 => enable
* 2 => finish
*/
const menu = {
menu_arrived_pickup: {
content: '1. Foto sudah dilokasi muat',
status: 0,
photo: '',
},
menu_process_pickup: {
content: '2. Foto sedang memuat barang',
status: 0,
photo: '',
},
menu_finish_pickup: {
content: '3. Foto selesai memuat barang',
status: 0,
photo: '',
},
menu_travel_document: {
content: '4. Foto dokumen perjalanan',
status: 0,
photo: '',
},
menu_otw_drop: {
content: '5. Foto saat diperjalanan (/2jam)',
status: 0,
photo: [],
},
menu_arrived_drop: {
content: '6. Foto tiba dilokasi bongkar',
status: 0,
photo: '',
},
menu_process_drop: {
content: '7. Foto proses bongkar',
status: 0,
photo: '',
},
menu_finish_drop: {
content: '8. Foto selesai bongkar',
status: 0,
photo: '',
},
menu_handover_document: {
content: '9. Foto dokumen serah terima',
status: 0,
photo: '',
},
menu_accident: {
content: 'Menu Accident',
status: 1,
photo: [],
},
};
for (const drvUp of drvUps) {
if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_PICKUP) {
menu.menu_arrived_pickup.status = 2;
menu.menu_arrived_pickup.photo = drvUp.img;
} else if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_PICKUP) {
menu.menu_process_pickup.status = 2;
menu.menu_process_pickup.photo = drvUp.img;
} else if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_PICKUP) {
menu.menu_finish_pickup.status = 2;
menu.menu_finish_pickup.photo = drvUp.img;
} else if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_TRAVEL_DOCUMENT) {
menu.menu_travel_document.status = 2;
menu.menu_travel_document.photo = drvUp.img;
} else if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_OTW_DROP) {
// if (row.drv_app_lock_menu_otw_drop_at !== 0) { menu.menu_otw_drop.status = 2; } else { menu.menu_otw_drop.status = 1; }
menu.menu_otw_drop.status = 2;
menu.menu_otw_drop.photo.push(drvUp.img);
} else if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_DROP) {
menu.menu_arrived_drop.status = 2;
menu.menu_arrived_drop.photo = drvUp.img;
} else if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_DROP) {
menu.menu_process_drop.status = 2;
menu.menu_process_drop.photo = drvUp.img;
} else if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_DROP) {
menu.menu_finish_drop.status = 2;
menu.menu_finish_drop.photo = drvUp.img;
} else if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_HANDOVER_DOCUMENT) {
menu.menu_handover_document.status = 2;
menu.menu_handover_document.photo = drvUp.img;
} else if (drvUp.stts === OrdersDriversUploadsModels.PHOTO_STATUS_ACCIDENT) {
menu.menu_accident.status = 1;
menu.menu_accident.photo.push(drvUp.img);
}
}
const formattedActiveOrders = [], includedPckId = [], includedDropId = [];
for (const row of activeOrders) {
if (includedPckId.includes(row.ord_pck_id) || includedDropId.includes(row.ord_drop_id)) continue;
includedPckId.push(row.ord_pck_id);
includedDropId.push(row.ord_drop_id);
const detail_id = Buffer.from(`${row.ord_id}_${row.ord_pck_id}_${row.ord_drop_id}_${row.ord_pck_drop_id}`, 'ascii').toString('hex');
// const decoded_detail_id = Buffer.from('34365f34305f3339', 'hex').toString('ascii');
let status_desc = '';
let is_wait_aprv_otw_drop = 0; // 0=>disable, 1=>enable
let is_wait_aprv_otw_drop_desc = '';
// old way
// if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_OTW_PICKUP) { status_desc = 'Kendaraan Menuju Lokasi Jemput'; menu.menu_arrived_pickup.status = 1; }
// else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_PICKUP) { status_desc = 'Kendaraan Tiba dilokasi Jemput'; menu.menu_process_pickup.status = 1; }
// else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_PROCESS_PICKUP) { status_desc = 'Kendaraan Memuat Barang'; menu.menu_finish_pickup.status = 1; }
// else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_FINISH_PICKUP) {
// status_desc = 'Kendaraan Selesai Memuat Barang';
// if (menu.menu_travel_document.status === 2) { menu.menu_otw_drop.status = 1; } else { menu.menu_travel_document.status = 1; }
// }
// else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_OTW_DROP) {
// status_desc = 'Kendaraan Menuju Lokasi Pengantaran';
// if (row.drv_app_lock_menu_otw_drop_at !== 0) { menu.menu_arrived_drop.status = 1; } else { menu.menu_otw_drop.status = 1; }
// }
// else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_DROP) { status_desc = 'Kendaraan Sampai Dilokasi Pengantaran'; menu.menu_process_drop.status = 1; }
// else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_PROCESS_DROP) { status_desc = 'Kendaraan Membongkar Barang'; menu.menu_finish_drop.status = 1; }
// else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_FINISH_DROP) {
// status_desc = 'Kendaraan Selesai Membongkar Barang';
// if (menu.menu_handover_document.status === 2) { } else { menu.menu_handover_document.status = 1; }
// }
// new way
if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_OTW_PICKUP) { status_desc = 'Kendaraan Menuju Lokasi Jemput'; menu.menu_arrived_pickup.status = 1; }
else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_PICKUP) { status_desc = 'Kendaraan Tiba dilokasi Jemput'; menu.menu_process_pickup.status = 1; }
else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_PROCESS_PICKUP) { status_desc = 'Kendaraan Memuat Barang'; menu.menu_finish_pickup.status = 1; }
else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_FINISH_PICKUP) { status_desc = 'Kendaraan Selesai Memuat Barang'; menu.menu_travel_document.status = 1; }
else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_TRAVEL_DOC) {
status_desc = 'Driver Sudah Mengupload Dokumen Perjalanan';
if (row.is_aprv_pck == OrdersPckDropsModels.IS_APRV_YES) {
menu.menu_otw_drop.status = 1;
is_wait_aprv_otw_drop = 1;
is_wait_aprv_otw_drop_desc = 'Menunggu persetujuan dari checker';
} else {
menu.menu_otw_drop.status = 0; // disable sementara, seharusnya 0
}
}
else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_OTW_DROP) {
status_desc = 'Kendaraan Menuju Lokasi Pengantaran';
if (row.drv_app_lock_menu_otw_drop_at !== 0) { menu.menu_arrived_drop.status = 1; } else { menu.menu_otw_drop.status = 1; }
}
else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_DROP) { status_desc = 'Kendaraan Sampai Dilokasi Pengantaran'; menu.menu_process_drop.status = 1; }
else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_PROCESS_DROP) { status_desc = 'Kendaraan Membongkar Barang'; menu.menu_finish_drop.status = 1; }
else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_FINISH_DROP) { status_desc = 'Kendaraan Selesai Membongkar Barang'; menu.menu_handover_document.status = 1; }
else if (row.stts_delivery === OrdersPckDropsModels.STTS_DELIVERY_HANDOVER_DOC) { status_desc = 'Driver Sudah Mengupload Dokumen Serah Terima'; }
// validate is_going / ongoing by pickup date
let is_ongoing = false;
if (row.set_pck_at) {
let cur_date = moment.unix(now).set({hour:0,minute:0,second:0,millisecond:0}); // as start
let pck_date = moment.unix(row.set_pck_at).set({hour:0,minute:0,second:0,millisecond:0}); // as end
let duration = moment.duration(pck_date.diff(cur_date));
if (duration.asDays() <= 0) {
is_ongoing = true;
}
}
formattedActiveOrders.push({
detail_id,
// ord_pck_drop_id: row.ord_pck_drop_id,
ord_id: row.ord_id,
ord_code: row.ord_code,
// pck_total: row.pck_total,
// drop_total: row.drop_total,
is_ongoing,
pck: {
id: row.ord_pck_id,
set_at_unix: row.set_pck_at,
// set_at_raw: (row.set_pck_at != 0) ? moment.unix(row.set_pck_at).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', // utc
set_at_raw: (row.set_pck_at != 0) ? moment.unix(row.set_pck_at).format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '', // gmt +7
// stts: row.stts_pck,
name: row.pck_name,
addr: row.pck_addr,
pic_name: row.pck_pic_name,
pic_phone: row.pck_pic_phone_code + '' + row.pck_pic_phone_val,
pic_mail: row.pck_pic_mail || '',
client_name: row.c_name,
client_phone: row.c_phone_code + '' + row.c_phone_val,
client_mail: row.c_mail,
client_prefer_truck_type: row.prefer_truck_type_name || '',
},
// going_at_unix: row.going_at,
// going_at_raw: (row.going_at != 0) ? moment.unix(row.going_at).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '',
// going_note: row.going_note,
drop: {
id: row.ord_drop_id,
// stts: row.ord_drop_stts,
name: row.drop_name,
addr: row.drop_addr,
pic_name: row.drop_pic_name,
pic_phone: row.drop_pic_phone_code + '' + row.drop_pic_phone_val,
pic_mail: row.drop_pic_mail || '',
client_name: row.c_name,
client_phone: row.c_phone_code + '' + row.c_phone_val,
client_mail: row.c_mail,
client_prefer_truck_type: row.prefer_truck_type_name || '',
},
// arrived_at_unix: row.arrived_at,
// arrived_at_raw: (row.arrived_at != 0) ? moment.unix(row.arrived_at).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '',
// arrived_note: row.arrived_note,
lead_time: row.lead_time,
lead_time_unit: row.lead_time_unit,
// buy_price: row.buy_price,
status: row.stts_delivery,
status_desc,
is_wait_aprv_otw_drop,
is_wait_aprv_otw_drop_desc,
// c_name: row.c_name,
// c_phone: row.c_phone_code + '' + row.c_phone_val,
// c_mail: row.c_mail,
// prefer_truck_type: row.prefer_truck_type,
// prefer_truck_type_name: row.prefer_truck_type_name || '',
vdr: {
name: row.vdr_name,
phone: row.vdr_phone_code + '' + row.vdr_phone_val,
mail: row.vdr_mail,
addr: row.vdr_addr,
},
drv: {
name: row.drv_name,
kenek_name: row.drv_name2,
phone: row.drv_phone_code + '' + row.drv_phone_val,
kenek_phone: row.drv_phone2_code + '' + row.drv_phone2_val,
mail: row.drv_mail,
addr: row.drv_addr,
},
vhc: {
name_bukan_nopol: row.vhc_name,
nopol1: row.vhc_nopol1,
nopol2: row.vhc_nopol2,
nopol3: row.vhc_nopol3,
nopol_full: row.vhc_nopol1 + ' ' + row.vhc_nopol2 + ' ' + row.vhc_nopol3,
},
menu,
});
}
apiRes = JSON.parse(JSON.stringify(response[200]));
apiRes.data = formattedActiveOrders[0];
// apiRes.raw = activeOrders;
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
} catch (e) {
apiRes = JSON.parse(JSON.stringify(response[500]));
apiRes.meta.message += Helper.setErrMsg(': ' + e.message);
LibLogReqResApi.log(req, apiRes);
return res.status(500).json(apiRes);
}
}
async jobPhotoTransitions(req, res) {
let apiRes = {}
try {
const now = moment().unix();
const { did, device_id, phone } = req.auth;
const { detail_id, type_up_photo, photo, lat, lng, photo_at } = req.body;
// input validation
const input = {
detail_id,
type_up_photo,
photo,
lat,
lng,
photo_at,
};
const rulesInput = {
detail_id: 'required|string',
type_up_photo: 'required|numeric|max:12',
photo: 'required|string',
lat: 'required|string|max:125',
lng: 'required|string|max:125',
photo_at: 'required|numeric',
};
const isInputValid = new Validator(input, rulesInput);
if (isInputValid.fails()) {
apiRes = JSON.parse(JSON.stringify(response[422]));
apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const decoded_detail_id = Buffer.from(detail_id, 'hex').toString('ascii');
const split_detail_id = decoded_detail_id.split('_');
if (split_detail_id.length !== 4) {
apiRes = JSON.parse(JSON.stringify(response[422]));
apiRes.meta.code += '_1';
apiRes.meta.message = 'detail id not valid';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const [ ord_id, pck_id, drop_id, ord_pck_drop_id ] = split_detail_id;
const required_type_up_photo = [OrdersDriversUploadsModels.PHOTO_STATUS_OTW_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_TRAVEL_DOCUMENT,OrdersDriversUploadsModels.PHOTO_STATUS_OTW_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_HANDOVER_DOCUMENT,OrdersDriversUploadsModels.PHOTO_STATUS_ACCIDENT];
if (!required_type_up_photo.includes(type_up_photo)) {
apiRes = JSON.parse(JSON.stringify(response[422]));
apiRes.meta.code += '_2';
apiRes.meta.message = 'type up photo not valid';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const filter = {
ord_id,
pck_id,
drop_id,
ord_pck_drop_id,
// is_active: OrdersModels.IS_ACTIVE,
// order_status: [OrdersModels.STTS_HAVE_GET_VHC,OrdersModels.STTS_PCK,OrdersModels.STTS_GO,OrdersModels.STTS_ARV,OrdersModels.STTS_DROP],
get_prefer_type_truck: 1,
couple_pck_drop: 1,
get_pic_zone: 1,
did,
};
const activeOrders = await OrdersModels.listOrders(filter);
if (activeOrders.length < 1) {
apiRes = JSON.parse(JSON.stringify(response[404]));
apiRes.meta.code += '_4';
apiRes.meta.message = 'job not found';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
// validate inside zone
const check_pck_zone = [OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_TRAVEL_DOCUMENT];
const check_drop_zone = [OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_HANDOVER_DOCUMENT];
if (check_pck_zone.includes(type_up_photo)) {
const inCircle = await ZoneModels.getOrdInCircle(lat, lng, { zid: activeOrders[0].pck_id });
const inShape = await ZoneModels.getOrdInShape(lat, lng, { zid: activeOrders[0].pck_id });
if (inCircle.length < 1 && inShape.length < 1) {
apiRes = JSON.parse(JSON.stringify(response[400]));
apiRes.meta.code += '_2';
apiRes.meta.message = 'driver should inside pickup zone';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
}
// else if (check_drop_zone.includes(type_up_photo)) {
// const inCircle = await ZoneModels.getOrdInCircle(lat, lng, { zid: activeOrders[0].drop_id });
// const inShape = await ZoneModels.getOrdInShape(lat, lng, { zid: activeOrders[0].drop_id });
// if (inCircle.length < 1 && inShape.length < 1) {
// apiRes = JSON.parse(JSON.stringify(response[400]));
// apiRes.meta.code += '_3';
// apiRes.meta.message = 'driver should inside drop zone';
LibLogReqResApi.log(req, apiRes);
// return res.status(200).json(apiRes);
// }
// }
// status transitions
const insUploads = [];
const updtOrd = {}, updtPck = {}, updtDrop = {}, updtPckDrop = {};
if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_PICKUP) {
// t_orders
updtOrd.id = ord_id;
updtOrd.status = OrdersModels.STTS_PCK;
// t_orders_pickups
updtPck.id = pck_id;
updtPck.stts_pck = OrdersPickupsModels.STTS_PCK_WAIT;
// updtPck.pck_enter_at = now;
// t_orders_pck_drops
updtPckDrop.id = ord_pck_drop_id;
updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_PICKUP;
} else if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_PICKUP) {
// t_orders
updtOrd.id = ord_id;
updtOrd.status = OrdersModels.STTS_PCK;
// t_orders_pickups
updtPck.id = pck_id;
updtPck.stts_pck = OrdersPickupsModels.STTS_PCK_PICKING;
updtPck.pck_at = now;
// t_orders_pck_drops
updtPckDrop.id = ord_pck_drop_id;
updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_PROCESS_PICKUP;
} else if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_PICKUP) {
// t_orders
updtOrd.id = ord_id;
updtOrd.status = OrdersModels.STTS_GO;
updtOrd.going_at = now;
// t_orders_pickups
updtPck.id = pck_id;
updtPck.stts_pck = OrdersPickupsModels.STTS_PCK_PICKED;
// t_orders_pck_drops
updtPckDrop.id = ord_pck_drop_id;
updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_FINISH_PICKUP;
} else if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_TRAVEL_DOCUMENT) {
// t_orders
updtOrd.id = ord_id;
updtOrd.status = OrdersModels.STTS_GO;
// t_orders_pickups
updtPck.id = pck_id;
updtPck.stts_pck = OrdersPickupsModels.STTS_PCK_PICKED;
// updtPck.pck_leave_at = now;
// t_orders_pck_drops
updtPckDrop.id = ord_pck_drop_id;
updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_TRAVEL_DOC;
} else if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_OTW_DROP) {
// t_orders
updtOrd.id = ord_id;
updtOrd.status = OrdersModels.STTS_GO;
// t_orders_pickups
updtPck.id = pck_id;
updtPck.stts_pck = OrdersPickupsModels.STTS_PCK_PICKED;
// t_orders_drops
updtDrop.id = drop_id;
updtDrop.stts_drop = OrdersDropsModels.STTS_DROP_WAIT;
// t_orders_pck_drops
updtPckDrop.id = ord_pck_drop_id;
updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_OTW_DROP;
} else if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_DROP) {
// t_orders
updtOrd.id = ord_id;
updtOrd.status = OrdersModels.STTS_ARV;
updtOrd.arrived_at = now;
// t_orders_drops
updtDrop.id = drop_id;
updtDrop.stts_drop = OrdersDropsModels.STTS_DROP_WAIT;
// updtDrop.drop_enter_at = now;
// t_orders_pck_drops
updtPckDrop.id = ord_pck_drop_id;
updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_DROP;
} else if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_DROP) {
// t_orders
updtOrd.id = ord_id;
updtOrd.status = OrdersModels.STTS_ARV;
// t_orders_drops
updtDrop.id = drop_id;
updtDrop.stts_drop = OrdersDropsModels.STTS_DROP_DROPPING;
updtDrop.drop_at = now;
// t_orders_pck_drops
updtPckDrop.id = ord_pck_drop_id;
updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_PROCESS_DROP;
} else if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_DROP) {
// t_orders
updtOrd.id = ord_id;
updtOrd.status = OrdersModels.STTS_DROP;
// t_orders_drops
updtDrop.id = drop_id;
updtDrop.stts_drop = OrdersDropsModels.STTS_DROP_DROPED;
// t_orders_pck_drops
updtPckDrop.id = ord_pck_drop_id;
updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_FINISH_DROP;
} else if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_HANDOVER_DOCUMENT) {
// t_orders
updtOrd.id = ord_id;
updtOrd.status = OrdersModels.STTS_CLIENT_PAY;
// t_orders_drops
updtDrop.id = drop_id;
updtDrop.stts_drop = OrdersDropsModels.STTS_DROP_DROPED;
// updtDrop.drop_leave_at = now;
// t_orders_pck_drops
updtPckDrop.id = ord_pck_drop_id;
updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_HANDOVER_DOC;
// kalau sudah selesai drop vhc & driver bisa order lagi
let remaining_multi_drops = await OrdersPckDropsModels.listOrdPckDrop({ ord_id, not_stts: [OrdersPckDropsModels.STTS_DELIVERY_FINISH_DROP, OrdersPckDropsModels.STTS_DELIVERY_HANDOVER_DOC] });
let vehicle = await VhcModels.getVhcById(activeOrders[0].vhc_id);
let updtVhc = {};
if (vehicle[0].ord_ids) {
let vhc_in_ord_ids = JSON.parse(vehicle[0].ord_ids);
for (let key in vhc_in_ord_ids) {
if (vhc_in_ord_ids[key] == ord_id) {
if (vhc_in_ord_ids.length <= 1) {
if (remaining_multi_drops.length < 1) {
updtVhc = {
is_in_ord: VhcModels.IN_ORD_NO,
ord_id: 0,
ord_code: 0,
ord_ids: null,
};
} else {
vhc_in_ord_ids.splice(key, 1);
updtVhc['ord_ids'] = vhc_in_ord_ids;
updtVhc['ord_ids'] = JSON.stringify(updtVhc['ord_ids']);
if (vehicle[0].ord_id == ord_id) updtVhc['ord_id'] = 0;
if (vehicle[0].ord_code == activeOrders[0].ord_code) updtVhc['ord_code'] = 0;
}
} else {
vhc_in_ord_ids.splice(key, 1);
updtVhc['ord_ids'] = vhc_in_ord_ids;
updtVhc['ord_ids'] = JSON.stringify(updtVhc['ord_ids']);
if (vehicle[0].ord_id == ord_id) updtVhc['ord_id'] = 0;
if (vehicle[0].ord_code == activeOrders[0].ord_code) updtVhc['ord_code'] = 0;
}
}
}
}
// if (updtVhc) VhcModles.update(activeOrders[0].vhc_id, updtVhc);
let driver = await DriversModels.find(activeOrders[0].drv_id);
let updtDrv = {};
if (driver[0].ord_ids) {
let drv_in_ord_ids = JSON.parse(driver[0].ord_ids);
for (let key in drv_in_ord_ids) {
if (drv_in_ord_ids[key] == ord_id) {
if (drv_in_ord_ids.length <= 1) {
if (remaining_multi_drops.length < 1) {
updtDrv = {
is_in_ord: DriversModels.IN_ORD_NO,
ord_id: 0,
ord_code: 0,
ord_ids: null,
};
} else {
drv_in_ord_ids.splice(key, 1);
updtDrv['ord_ids'] = drv_in_ord_ids;
updtDrv['ord_ids'] = JSON.stringify(updtDrv['ord_ids']);
if (driver[0].ord_id == ord_id) updtDrv['ord_id'] = 0;
if (driver[0].ord_code == activeOrders[0].ord_code) updtDrv['ord_code'] = 0;
}
} else {
drv_in_ord_ids.splice(key, 1);
updtDrv['ord_ids'] = drv_in_ord_ids;
updtDrv['ord_ids'] = JSON.stringify(updtDrv['ord_ids']);
if (driver[0].ord_id == ord_id) updtDrv['ord_id'] = 0;
if (driver[0].ord_code == activeOrders[0].ord_code) updtDrv['ord_code'] = 0;
}
}
}
}
// if (updtDrv) DriversModels.update(updtDrv, activeOrders[0].drv_id);
} else if (type_up_photo == OrdersDriversUploadsModels.PHOTO_STATUS_ACCIDENT) {
// t_orders
updtOrd.id = ord_id;
// updtOrd.is_accident = OrdersModels.IS_ACCIDENT;
// updtOrd.acdnt_at = now;
// t_orders_pck_drops
updtPckDrop.id = ord_pck_drop_id;
updtPckDrop.is_accident = OrdersModels.IS_ACCIDENT;
updtPckDrop.acdnt_at = now;
}
let stts_reverse_geo = 0;
const respRGeo = await LibCurl.reverseGeo(lat, lng);
let { country_id, country_code, country_text, state_id, state_text, city_id, city_text, district_id, district_text, village_id, village_text, postcode, streets, fulladdress, log_reverse_geo } = respRGeo.addrData || {};
if (respRGeo.type === 'sc') {
stts_reverse_geo = GpsTracksModels.STTS_REVERSE_GEO_SC;
} else if (respRGeo.type === 'no_available') {
stts_reverse_geo = GpsTracksModels.STTS_REVERSE_GEO_LOST;
} else if (respRGeo.type === 'fail') {
stts_reverse_geo = GpsTracksModels.STTS_REVERSE_GEO_ER;
} else if (respRGeo.type === 'error') {
stts_reverse_geo = GpsTracksModels.STTS_REVERSE_GEO_ER;
}
// start geotagging image
const tempFileName = moment().valueOf() + '.jpeg';
const tempFileNamePath = path.resolve(__dirname, '../files/storage') + '/' + tempFileName;
await LibImgGeotagging.create(tempFileName, tempFileNamePath, photo, {fulladdress, lat, lng, photo_at});
const apiSavePhotos = process.env.FMS_URL + 'api/v1/storage/save_photos';
const namePhoto = `ords_pcks_drops/${ord_pck_drop_id}/drvs_ups/${did}/${now}.jpeg`;
const respSavePhotos = await LibCurl.formurlencoded(apiSavePhotos, {
names: [namePhoto],
photos: [fs.readFileSync(tempFileNamePath, {encoding: 'base64'})],
});
LibFile.remove(tempFileName);
if (respSavePhotos.type !== 'sc') {
apiRes = JSON.parse(JSON.stringify(response[400]));
apiRes.meta.code += '_1';
apiRes.meta.message = 'fail upload photo';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
// end geotagging image
// get region_id
if (!village_id) {
const region = await LibCurl.getRegionId(postcode);
if (typeof region.addrData !== 'undefined') {
if (region.addrData.state_id) state_id = region.addrData.state_id;
if (region.addrData.state_text) state_text = region.addrData.state_text.toUpperCase();
if (region.addrData.city_id) city_id = region.addrData.city_id;
if (region.addrData.city_text) city_text = region.addrData.city_text.toUpperCase();
if (region.addrData.district_id) district_id = region.addrData.district_id;
if (region.addrData.district_text) district_text = region.addrData.district_text.toUpperCase();
if (region.addrData.village_id) village_id = region.addrData.village_id;
if (region.addrData.village_text) village_text = region.addrData.village_text.toUpperCase();
}
}
// t_orders_drivers_uploads
insUploads.push({
did,
ord_id,
ord_code: activeOrders[0].ord_code,
pck_id,
drop_id,
ord_pck_drop_id,
stts: type_up_photo,
is_active: OrdersDriversUploadsModels.IS_ACTIVE,
img: process.env.FMS_URL + `storage/${namePhoto}`,
// desc: undefined,
lat, lng,
country_id: country_id || null,
country_code: country_code || null,
country_text: country_text || null,
state_id: state_id || null,
state_text: state_text || null,
city_id: city_id || null,
city_text: city_text || null,
district_id: district_id || null,
district_text: district_text || null,
village_id: village_id || null,
village_text: village_text || null,
postcode: postcode || null,
streets: streets || null,
fulladdress: fulladdress || null,
stts_reverse_geo, log_reverse_geo,
crt: now, crt_drv_at: photo_at, crt_by: did,
updt: now, updt_by: did,
});
OrdersModels.bundleInsDrvUploads(insUploads, updtOrd, updtPck, updtDrop, updtPckDrop);
apiRes = JSON.parse(JSON.stringify(response[200]));
// apiRes.data = activeOrders;
// apiRes.raw = respRGeo.addrData || {};
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
} catch (e) {
apiRes = JSON.parse(JSON.stringify(response[500]));
apiRes.meta.message += Helper.setErrMsg(': ' + e.message);
LibLogReqResApi.log(req, apiRes);
return res.status(500).json(apiRes);
}
}
async lockMenu(req, res) {
let apiRes = {}
try {
const now = moment().unix();
const { did, device_id, phone } = req.auth;
const { detail_id, type_lock_menu } = req.body;
// input validation
const input = {
detail_id,
type_lock_menu,
};
const rulesInput = {
detail_id: 'required|string',
type_lock_menu: 'required|numeric|max:12',
};
const isInputValid = new Validator(input, rulesInput);
if (isInputValid.fails()) {
apiRes = JSON.parse(JSON.stringify(response[422]));
apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const decoded_detail_id = Buffer.from(detail_id, 'hex').toString('ascii');
const split_detail_id = decoded_detail_id.split('_');
if (split_detail_id.length !== 4) {
apiRes = JSON.parse(JSON.stringify(response[422]));
apiRes.meta.code += '_1';
apiRes.meta.message = 'detail id not valid';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const [ ord_id, pck_id, drop_id, ord_pck_drop_id ] = split_detail_id;
const required_type_lock_menu = [OrdersDriversUploadsModels.PHOTO_STATUS_OTW_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_PICKUP,OrdersDriversUploadsModels.PHOTO_STATUS_TRAVEL_DOCUMENT,OrdersDriversUploadsModels.PHOTO_STATUS_OTW_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_ARRIVED_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_PROCESS_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_FINISH_DROP,OrdersDriversUploadsModels.PHOTO_STATUS_HANDOVER_DOCUMENT,OrdersDriversUploadsModels.PHOTO_STATUS_ACCIDENT];
if (!required_type_lock_menu.includes(type_lock_menu)) {
apiRes = JSON.parse(JSON.stringify(response[422]));
apiRes.meta.code += '_2';
apiRes.meta.message = 'type lock menu not valid';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const filter = {
ord_id,
pck_id,
drop_id,
ord_pck_drop_id,
// is_active: OrdersModels.IS_ACTIVE,
// order_status: [OrdersModels.STTS_HAVE_GET_VHC,OrdersModels.STTS_PCK,OrdersModels.STTS_GO,OrdersModels.STTS_ARV,OrdersModels.STTS_DROP],
get_prefer_type_truck: 1,
couple_pck_drop: 1,
get_pic_zone: 1,
did,
};
const activeOrders = await OrdersModels.listOrders(filter);
if (activeOrders.length < 1) {
apiRes = JSON.parse(JSON.stringify(response[404]));
apiRes.meta.code += '_4';
apiRes.meta.message = 'job not found';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const insUploads = [];
const updtOrd = {}, updtPck = {}, updtDrop = {}, updtPckDrop = {};
if (type_lock_menu === OrdersDriversUploadsModels.PHOTO_STATUS_OTW_DROP) {
// t_orders
updtOrd.id = ord_id;
updtOrd.status = OrdersModels.STTS_GO;
// t_orders_pickups
updtPck.id = pck_id;
updtPck.stts_pck = OrdersPickupsModels.STTS_PCK_PICKED;
// t_orders_drops
updtDrop.id = drop_id;
updtDrop.stts_drop = OrdersDropsModels.STTS_DROP_WAIT;
// t_orders_pck_drops
updtPckDrop.id = ord_pck_drop_id;
updtPckDrop.drv_app_lock_menu_otw_drop_at = now;
updtPckDrop.stts = OrdersPckDropsModels.STTS_DELIVERY_OTW_DROP;
}
OrdersModels.bundleInsDrvUploads(insUploads, updtOrd, updtPck, updtDrop, updtPckDrop);
apiRes = JSON.parse(JSON.stringify(response[200]));
// apiRes.data = activeOrders;
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
} catch (e) {
apiRes = JSON.parse(JSON.stringify(response[500]));
apiRes.meta.message += Helper.setErrMsg(': ' + e.message);
LibLogReqResApi.log(req, apiRes);
return res.status(500).json(apiRes);
}
}
// FINANCE
async listPockets(req, res) {
let apiRes = {}
try {
const now = moment().unix();
const { did, device_id, phone } = req.auth;
// input validation
const input = {};
const rulesInput = {};
const isInputValid = new Validator(input, rulesInput);
if (isInputValid.fails()) {
apiRes = JSON.parse(JSON.stringify(response[422]));
apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const checkpoints = await OrdersCheckpointsModels.list({
did,
is_paid: OrdersCheckpointsModels.IS_PAID_OFF,
order_by: ' ORDER BY checkpoint.pocket_paid_at ASC',
});
if (checkpoints.length < 1) {
apiRes = JSON.parse(JSON.stringify(response[404]));
apiRes.meta.code += '_1';
apiRes.meta.message = 'there are no received pocket money';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const formattedCheckpoints = [];
for (const checkpoint of checkpoints) {
formattedCheckpoints.push({
checkpoint_id: checkpoint.checkpoint_id,
ord_id: checkpoint.ord_id,
ord_code: checkpoint.ord_code,
ord_pocket_id: checkpoint.ord_pocket_id,
// pocket_sort: checkpoint.pocket_sort,
pocket_total: checkpoint.pocket_total,
pocket_is_paid: checkpoint.pocket_is_paid,
pocket_paid_at: checkpoint.pocket_paid_at,
pocket_paid_at_raw: (checkpoint.pocket_paid_at != 0) ? moment.unix(checkpoint.pocket_paid_at).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '',
// pocket_paid_by: checkpoint.pocket_paid_by,
pocket_paid_by_name: checkpoint.pocket_paid_by_name || '',
});
}
apiRes = JSON.parse(JSON.stringify(response[200]));
apiRes.data = formattedCheckpoints;
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
} catch (e) {
apiRes = JSON.parse(JSON.stringify(response[500]));
apiRes.meta.message += Helper.setErrMsg(': ' + e.message);
LibLogReqResApi.log(req, apiRes);
return res.status(500).json(apiRes);
}
}
async detailPocket(req, res) {
let apiRes = {}
try {
const now = moment().unix();
const { did, device_id, phone } = req.auth;
const { checkpoint_id } = req.params;
// input validation
const input = {
checkpoint_id,
};
const rulesInput = {
'checkpoint_id': 'required|integer',
};
const isInputValid = new Validator(input, rulesInput);
if (isInputValid.fails()) {
apiRes = JSON.parse(JSON.stringify(response[422]));
apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const checkpoints = await OrdersCheckpointsModels.list({
did,
checkpoint_id,
limit: 1,
});
if (checkpoints.length < 1) {
apiRes = JSON.parse(JSON.stringify(response[404]));
apiRes.meta.code += '_1';
apiRes.meta.message = 'pocket money not found';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const formattedCheckpoints = [];
for (const checkpoint of checkpoints) {
formattedCheckpoints.push({
checkpoint_id: checkpoint.checkpoint_id,
ord_id: checkpoint.ord_id,
ord_code: checkpoint.ord_code,
ord_pocket_id: checkpoint.ord_pocket_id,
// pocket_sort: checkpoint.pocket_sort,
pocket_total: checkpoint.pocket_total,
pocket_is_paid: checkpoint.pocket_is_paid,
pocket_paid_at: checkpoint.pocket_paid_at,
pocket_paid_at_raw: (checkpoint.pocket_paid_at != 0) ? moment.unix(checkpoint.pocket_paid_at).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '',
// pocket_paid_by: checkpoint.pocket_paid_by,
pocket_paid_by_name: checkpoint.pocket_paid_by_name || '',
});
}
apiRes = JSON.parse(JSON.stringify(response[200]));
apiRes.data = formattedCheckpoints[0];
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
} catch (e) {
apiRes = JSON.parse(JSON.stringify(response[500]));
apiRes.meta.message += Helper.setErrMsg(': ' + e.message);
LibLogReqResApi.log(req, apiRes);
return res.status(500).json(apiRes);
}
}
// LOGBOOK
async listLogBooks(req, res) {
let apiRes = {}
try {
const now = moment().unix();
const { did, device_id, phone } = req.auth;
const filter = {
is_active: LogbookKeysModels.IS_ACTIVE,
};
const listKeys = await LogbookKeysModels.list(filter);
if (listKeys.length < 1) {
apiRes = JSON.parse(JSON.stringify(response[404]));
apiRes.meta.code = '200'; // += '_1';
apiRes.meta.message = 'there are no list logbook';
apiRes.data = [];
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const formattedListKeys = [], includedLogbookId = [];
for (const row of listKeys) {
if (includedLogbookId.includes(row.lgb_id)) continue;
includedLogbookId.push(row.lgb_id);
// https://stackoverflow.com/questions/23299950/convert-date-to-utc-using-moment-js
formattedListKeys.push({
lgb_id: row.lgb_id,
lgb_name: row.name,
updt_at: row.updt,
updt_at_raw: (row.updt != 0) ? moment.unix(row.updt).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '',
});
}
apiRes = JSON.parse(JSON.stringify(response[200]));
apiRes.data = formattedListKeys;
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
} catch (e) {
apiRes = JSON.parse(JSON.stringify(response[500]));
apiRes.meta.message += Helper.setErrMsg(': ' + e.message);
LibLogReqResApi.log(req, apiRes);
return res.status(500).json(apiRes);
}
}
async detailLogBook(req, res) {
let apiRes = {}
try {
const now = moment().unix();
const { did, device_id, phone } = req.auth;
const { lgb_id } = req.params;
// input validation
const input = {
lgb_id,
};
const rulesInput = {
'lgb_id': 'required|integer',
};
const isInputValid = new Validator(input, rulesInput);
if (isInputValid.fails()) {
apiRes = JSON.parse(JSON.stringify(response[422]));
apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const filter = {
lgb_id,
is_active: LogbookKeysModels.IS_ACTIVE,
limit: 1,
};
const listKeys = await LogbookKeysModels.list(filter);
if (listKeys.length < 1) {
apiRes = JSON.parse(JSON.stringify(response[404]));
apiRes.meta.code += '_4';
apiRes.meta.message = 'logbook not found';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const formattedListKeys = [], includedLogbookId = [];
for (const row of listKeys) {
if (includedLogbookId.includes(row.lgb_id)) continue;
includedLogbookId.push(row.lgb_id);
const params = [];
row.keys = JSON.parse(row.keys);
row.units = JSON.parse(row.units);
row.dtypes = JSON.parse(row.dtypes);
for (let i in row.keys) {
params.push({
key: row.keys[i],
unit: row.units[i],
dtype: row.dtypes[i],
value: "",
})
}
// https://stackoverflow.com/questions/23299950/convert-date-to-utc-using-moment-js
formattedListKeys.push({
lgb_id: row.lgb_id,
lgb_name: row.name,
updt_at: row.updt,
updt_at_raw: (row.updt != 0) ? moment.unix(row.updt).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '',
params,
});
}
apiRes = JSON.parse(JSON.stringify(response[200]));
apiRes.data = formattedListKeys[0];
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
} catch (e) {
apiRes = JSON.parse(JSON.stringify(response[500]));
apiRes.meta.message += Helper.setErrMsg(': ' + e.message);
LibLogReqResApi.log(req, apiRes);
return res.status(500).json(apiRes);
}
}
async insOrdLogBook(req, res) {
let apiRes = {}
try {
const now = moment().unix();
const { did, device_id, phone } = req.auth;
const { lgb_id, detail_id, params } = req.body;
// input validation
const input = {
lgb_id,
detail_id,
params,
};
const rulesInput = {
'lgb_id': 'required|integer',
'detail_id': 'required|string',
'params': 'required|array',
'params.*.key': 'required|string|max:255',
'params.*.unit': 'required|string|max:255',
'params.*.dtype': 'required|string|max:255',
'params.*.value': 'required|string',
};
const isInputValid = new Validator(input, rulesInput);
if (isInputValid.fails()) {
apiRes = JSON.parse(JSON.stringify(response[422]));
apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const decoded_detail_id = Buffer.from(detail_id, 'hex').toString('ascii');
const split_detail_id = decoded_detail_id.split('_');
if (split_detail_id.length !== 4) {
apiRes = JSON.parse(JSON.stringify(response[422]));
apiRes.meta.code += '_1';
apiRes.meta.message = 'detail id not valid';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const [ ord_id, pck_id, drop_id, ord_pck_drop_id ] = split_detail_id;
const filter = {
ord_id,
pck_id,
drop_id,
ord_pck_drop_id,
// is_active: OrdersModels.IS_ACTIVE,
// order_status: [OrdersModels.STTS_HAVE_GET_VHC,OrdersModels.STTS_PCK,OrdersModels.STTS_GO,OrdersModels.STTS_ARV,OrdersModels.STTS_DROP],
get_prefer_type_truck: 1,
couple_pck_drop: 1,
get_pic_zone: 1,
did,
};
const activeOrders = await OrdersModels.listOrders(filter);
if (activeOrders.length < 1) {
apiRes = JSON.parse(JSON.stringify(response[404]));
apiRes.meta.code += '_4';
apiRes.meta.message = 'job not found';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const filter1 = {
lgb_id,
is_active: LogbookKeysModels.IS_ACTIVE,
join_type: 1,
limit: 1,
};
const listKeys = await LogbookKeysModels.list(filter1);
if (listKeys.length < 1) {
apiRes = JSON.parse(JSON.stringify(response[404]));
apiRes.meta.code += '_5';
apiRes.meta.message = 'logbook not found';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
let dy_cols = "(COLUMN_CREATE(", photo = '';
let values = [];
for (const param of params) {
// dy_cols += "'key', '" + param.key + "', 'unit', '" + param.unit + "', 'dtype', '" + param.dtype + "', 'value', '" + param.value + "',"; // as reference only
if (param.dtype === LogbookKeysModels.IMG_BASE64) {
// start reverse geo
let stts_reverse_geo = 0;
const respRGeo = await LibCurl.reverseGeo(param.lat, param.lng);
let { country_id, country_code, country_text, state_id, state_text, city_id, city_text, district_id, district_text, village_id, village_text, postcode, streets, fulladdress, log_reverse_geo } = respRGeo.addrData || {};
if (respRGeo.type === 'sc') {
stts_reverse_geo = GpsTracksModels.STTS_REVERSE_GEO_SC;
} else if (respRGeo.type === 'no_available') {
stts_reverse_geo = GpsTracksModels.STTS_REVERSE_GEO_LOST;
} else if (respRGeo.type === 'fail') {
stts_reverse_geo = GpsTracksModels.STTS_REVERSE_GEO_ER;
} else if (respRGeo.type === 'error') {
stts_reverse_geo = GpsTracksModels.STTS_REVERSE_GEO_ER;
}
// end reverse geo
// start get region_id
// if (!village_id) {
// const region = await LibCurl.getRegionId(postcode);
// if (typeof region.addrData !== 'undefined') {
// if (region.addrData.state_id) state_id = region.addrData.state_id;
// if (region.addrData.state_text) state_text = region.addrData.state_text.toUpperCase();
// if (region.addrData.city_id) city_id = region.addrData.city_id;
// if (region.addrData.city_text) city_text = region.addrData.city_text.toUpperCase();
// if (region.addrData.district_id) district_id = region.addrData.district_id;
// if (region.addrData.district_text) district_text = region.addrData.district_text.toUpperCase();
// if (region.addrData.village_id) village_id = region.addrData.village_id;
// if (region.addrData.village_text) village_text = region.addrData.village_text.toUpperCase();
// }
// }
// // end get region_id
// start geotagging image
const tempFileName = moment().valueOf() + '.jpeg';
const tempFileNamePath = path.resolve(__dirname, '../files/storage') + '/' + tempFileName;
await LibImgGeotagging.create(tempFileName, tempFileNamePath, param.value, {fulladdress: fulladdress || '', lat: param.lat || '', lng: param.lng || '', photo_at: param.photo_at || ''});
const apiSavePhotos = process.env.FMS_URL + 'api/v1/storage/save_photos';
const namePhoto = `ords_pcks_drops/${ord_pck_drop_id}/drvs_logbooks/${did}/${now}.jpeg`;
const respSavePhotos = await LibCurl.formurlencoded(apiSavePhotos, {
names: [namePhoto],
photos: [fs.readFileSync(tempFileNamePath, {encoding: 'base64'})],
});
LibFile.remove(tempFileName);
if (respSavePhotos.type !== 'sc') {
apiRes = JSON.parse(JSON.stringify(response[400]));
apiRes.meta.code += '_1';
apiRes.meta.message = 'fail upload photo';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
// end geotagging image
param.value = process.env.FMS_URL + `storage/${namePhoto}`;
}
// start dy_cols
dy_cols += "'" + param.key + "', '" + param.value + "',";
values.push(param.value);
// end dy_cols
}
dy_cols = dy_cols.slice(0, -1) + "))";
dy_cols = mysql.raw(dy_cols);
const insOrdLogbook = {
ord_id,
ord_code: activeOrders[0].ord_code,
lgb_key_id: lgb_id,
lgb_key_name: listKeys[0].name,
lgb_type_id: listKeys[0].type,
lgb_type_name: listKeys[0].type_name,
vhc_id: activeOrders[0].vhc_id,
drv_id: did,
is_active: LogbookOrdersModels.IS_ACTIVE,
dy_cols,
keys: listKeys[0].keys,
units: listKeys[0].units,
dtypes: listKeys[0].dtypes,
values: JSON.stringify(values),
crt: now,
crt_by: did,
updt: now,
updt_by: did,
};
await LogbookOrdersModels.ins(insOrdLogbook);
apiRes = JSON.parse(JSON.stringify(response[200]));
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
} catch (e) {
apiRes = JSON.parse(JSON.stringify(response[500]));
apiRes.meta.message += Helper.setErrMsg(': ' + e.message);
LibLogReqResApi.log(req, apiRes);
return res.status(500).json(apiRes);
}
}
async listOrdLogBooks(req, res) {
let apiRes = {}
try {
const now = moment().unix();
const { did, device_id, phone } = req.auth;
const filter = {
is_active: LogbookOrdersModels.IS_ACTIVE,
};
const listKeys = await LogbookOrdersModels.list(filter);
if (listKeys.length < 1) {
apiRes = JSON.parse(JSON.stringify(response[404]));
apiRes.meta.code = '200'; // += '_1';
apiRes.meta.message = 'there are no list orders logbooks';
apiRes.data = [];
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const formattedListKeys = [], includedLogbookId = [];
for (const row of listKeys) {
if (includedLogbookId.includes(row.ord_lgb_id)) continue;
includedLogbookId.push(row.ord_lgb_id);
// https://stackoverflow.com/questions/23299950/convert-date-to-utc-using-moment-js
formattedListKeys.push({
ord_lgb_id: row.ord_lgb_id,
lgb_key_id: row.lgb_key_id,
lgb_key_name: row.lgb_key_name,
lgb_type_id: row.lgb_type_id,
lgb_type_name: row.lgb_type_name,
dy_cols: (row.dy_cols_json == null) ? '' : JSON.parse(row.dy_cols_json),
keys: JSON.parse(row.keys),
units: JSON.parse(row.units),
dtypes: JSON.parse(row.dtypes),
values: JSON.parse(row.values),
crt_at: row.crt,
crt_at_raw: (row.crt != 0) ? moment.unix(row.crt).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '',
updt_at: row.updt,
updt_at_raw: (row.updt != 0) ? moment.unix(row.updt).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '',
});
}
apiRes = JSON.parse(JSON.stringify(response[200]));
apiRes.data = formattedListKeys;
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
} catch (e) {
apiRes = JSON.parse(JSON.stringify(response[500]));
apiRes.meta.message += Helper.setErrMsg(': ' + e.message);
LibLogReqResApi.log(req, apiRes);
return res.status(500).json(apiRes);
}
}
async detailOrdLogBook(req, res) {
let apiRes = {}
try {
const now = moment().unix();
const { did, device_id, phone } = req.auth;
const { ord_lgb_id } = req.params;
// input validation
const input = {
ord_lgb_id,
};
const rulesInput = {
'ord_lgb_id': 'required|integer',
};
const isInputValid = new Validator(input, rulesInput);
if (isInputValid.fails()) {
apiRes = JSON.parse(JSON.stringify(response[422]));
apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const filter = {
ord_lgb_id,
is_active: LogbookOrdersModels.IS_ACTIVE,
limit: 1,
};
const listKeys = await LogbookOrdersModels.list(filter);
if (listKeys.length < 1) {
apiRes = JSON.parse(JSON.stringify(response[404]));
apiRes.meta.code += '_4';
apiRes.meta.message = 'order logbook not found';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const formattedListKeys = [], includedLogbookId = [];
for (const row of listKeys) {
if (includedLogbookId.includes(row.ord_lgb_id)) continue;
includedLogbookId.push(row.ord_lgb_id);
// https://stackoverflow.com/questions/23299950/convert-date-to-utc-using-moment-js
formattedListKeys.push({
ord_lgb_id: row.ord_lgb_id,
lgb_key_id: row.lgb_key_id,
lgb_key_name: row.lgb_key_name,
lgb_type_id: row.lgb_type_id,
lgb_type_name: row.lgb_type_name,
dy_cols: (row.dy_cols_json == null) ? '' : JSON.parse(row.dy_cols_json),
keys: JSON.parse(row.keys),
units: JSON.parse(row.units),
dtypes: JSON.parse(row.dtypes),
values: JSON.parse(row.values),
crt_at: row.crt,
crt_at_raw: (row.crt != 0) ? moment.unix(row.crt).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '',
updt_at: row.updt,
updt_at_raw: (row.updt != 0) ? moment.unix(row.updt).utc().format('YYYY-MM-DDTHH:mm:ss.SSS') + 'Z' : '',
});
}
apiRes = JSON.parse(JSON.stringify(response[200]));
apiRes.data = formattedListKeys[0];
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
} catch (e) {
apiRes = JSON.parse(JSON.stringify(response[500]));
apiRes.meta.message += Helper.setErrMsg(': ' + e.message);
LibLogReqResApi.log(req, apiRes);
return res.status(500).json(apiRes);
}
}
// RUNNING BACKGROUD
// up lat,long data per 1 minute
async upLocation(req, res) {
let apiRes = {}
try {
const now = moment().unix();
const { did, device_id, phone, phone_device_id } = req.auth;
const { lat, lng, req_at } = req.body;
// input validation
const input = {
lat,
lng,
req_at,
};
const rulesInput = {
lat: 'required|string|max:125',
lng: 'required|string|max:125',
req_at: 'required|numeric',
};
const isInputValid = new Validator(input, rulesInput);
if (isInputValid.fails()) {
apiRes = JSON.parse(JSON.stringify(response[422]));
apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const filter = {
did,
// order_status: [OrdersModels.STTS_HAVE_GET_VHC,OrdersModels.STTS_PCK,OrdersModels.STTS_GO,OrdersModels.STTS_ARV,OrdersModels.STTS_DROP],
is_active: OrdersModels.IS_ACTIVE,
delivery_statuses: [
OrdersPckDropsModels.STTS_DELIVERY_OTW_PICKUP,OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_PICKUP,OrdersPckDropsModels.STTS_DELIVERY_PROCESS_PICKUP
,OrdersPckDropsModels.STTS_DELIVERY_FINISH_PICKUP,OrdersPckDropsModels.STTS_DELIVERY_TRAVEL_DOC,OrdersPckDropsModels.STTS_DELIVERY_OTW_DROP
,OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_DROP,OrdersPckDropsModels.STTS_DELIVERY_PROCESS_DROP,OrdersPckDropsModels.STTS_DELIVERY_FINISH_DROP
// ,OrdersPckDropsModels.STTS_DELIVERY_HANDOVER_DOC
],
couple_pck_drop: 1,
};
// kalo mau track yang nonactive, gausah ngeget vhc, lansung insert aja dengan vhc_id: 0
// const updtToOrders = await OrdersModels.listActiveOrdVhc(filter);
const updtToOrders = await OrdersModels.listOrders(filter);
/**
* get lat, lng to all checkpoints paid = 0, sort != 1, order.dlt is null,
* kenakan ke checkpoints yang order stts_deliverynya lebih dari travel dokumen
* jika ada case negative di inCircle ada dan di di inShape ada maka mana yang didahulukan ? langsung dikenain aja 2-2nya
* pastikan dulu ada di activeOrder
* kenakan yang ord_pck_id lebih awal
*/
// BISA BUAT DEBUGGING: where_not_pocket_is_paid: OrdersCheckpointsModels.IS_PAID_OFF
// BUAT PRODUCTION: pocket_is_paid: OrdersCheckpointsModels.IS_UNPAID
const inCircle = await ZoneModels.getCheckpointsInCircle(lat, lng, {drv_id: did, pocket_is_paid: OrdersCheckpointsModels.IS_UNPAID, pocket_sort: '!= 1', stts_delivery: [OrdersPckDropsModels.STTS_DELIVERY_OTW_DROP,OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_DROP,OrdersPckDropsModels.STTS_DELIVERY_PROCESS_DROP,OrdersPckDropsModels.STTS_DELIVERY_FINISH_DROP,OrdersPckDropsModels.STTS_DELIVERY_HANDOVER_DOC]});
const inShape = await ZoneModels.getCheckpointsInShape(lat, lng, {drv_id: did, pocket_is_paid: OrdersCheckpointsModels.IS_UNPAID, pocket_sort: '!= 1', stts_delivery: [OrdersPckDropsModels.STTS_DELIVERY_OTW_DROP,OrdersPckDropsModels.STTS_DELIVERY_ARRIVED_DROP,OrdersPckDropsModels.STTS_DELIVERY_PROCESS_DROP,OrdersPckDropsModels.STTS_DELIVERY_FINISH_DROP,OrdersPckDropsModels.STTS_DELIVERY_HANDOVER_DOC]});
let insideZones = [];
if (inCircle.length > 0 || inShape.length > 0) {
for (const circle of inCircle) {
// hit api disbure
if (circle.drv_bank_id == 0 || circle.drv_bank_acc_number == null) continue;
insideZones.push(circle);
}
for (const shape of inShape) {
// hit api disbure
if (shape.drv_bank_id == 0 || shape.drv_bank_acc_number == null) continue;
insideZones.push(shape);
}
}
// checkpoints
if (insideZones.length > 0) {
const UNIT_TYPE_UNIT = 3;
let admins = await UsersModels.getUsersActiveByRole(UsersModels.ROLE_FINANCE);
let admins_data = [];
for (const admin of admins) {
admins_data.push({
'admin_id': admin.id,
'admin_name': admin.first_name,
'admin_phone': admin.phone_code + ' ' + admin.phone,
'admin_mail': admin.email,
'admin_addr': ''
});
}
for (const insideZone of insideZones) {
const insOrdAItems = {
'ord_id': insideZone.ord_id,
'ord_code': insideZone.ord_code,
'flow_type': OrdersAItemsModels.FLOW_TYPE_PAYMENT,
'cash_type': OrdersAItemsModels.TYPE_CASH_OUT,
'a_item_type': OrdersAItemsModels.A_TYPE_SECONDARY,
'unit_id': 0,
'unit_type': UNIT_TYPE_UNIT,
'amt_base_flat': insideZone.pocket_total,
'unit_qty': 0,
'amt_tax_type': 0,
'amt_tax_ppn_percent': 0,
'amt_tax_ppn_flat': 0,
'amt_tax_pph_percent': 0,
'amt_tax_pph_flat': 0,
'amt_total_tax_flat': 0,
'amt_result_flat': insideZone.pocket_total,
'amt_total_flat': insideZone.pocket_total,
'only_vdr': OrdersAItemsModels.ONLY_VDR_YES,
'bank_id': insideZone.drv_bank_id,
'bank_name': insideZone.drv_bank_name,
'bank_code': insideZone.drv_bank_code,
'bank_short_name': insideZone.drv_bank_short_name,
'bank_branch_name': insideZone.drv_bank_branch_name || null,
'bank_acc_name': insideZone.drv_bank_acc_name,
'bank_acc_number': insideZone.drv_bank_acc_number,
'ref_ord_id': insideZone.ord_id,
'ref_ord_code': insideZone.ord_code,
'crt': now,
'crt_by': 0,
'updt': now,
'updt_by': 0,
'desc': 'Uang Saku Driver di ' + insideZone.name,
};
insOrdAItems.calc_to_vdr = OrdersAItemsModels.CALC_TO_VDR_YES;
let termins = [];
termins = await OrdersTerminsModels.listWithFilter({
'ord_id': insideZone.ord_id,
'termin_for': OrdersTerminsModels.TERMIN_FOR_VENDOR,
'termin_is_paid': OrdersTerminsModels.IS_PAID_NO,
'in_stts_merge': [
OrdersAItemsModels.STTS_MERGE_NO,
OrdersAItemsModels.STTS_MERGE_RESULT,
],
});
insOrdAItems.v_termin_id = 0;
insOrdAItems.ref_v_termin_id = 0;
if (termins.length > 0) {
insOrdAItems.v_termin_id = termins[0].id;
insOrdAItems.ref_v_termin_id = termins[0].id;
}
if (insOrdAItems.v_termin_id === 0) {
termins = await OrdersTerminsModels.listWithFilter({
'ord_id': insideZone.ord_id,
'termin_for': OrdersTerminsModels.TERMIN_FOR_VENDOR,
'in_stts_merge': [
OrdersAItemsModels.STTS_MERGE_NO,
OrdersAItemsModels.STTS_MERGE_RESULT,
],
});
insOrdAItems.v_termin_id = termins[termins.length - 1].id;
insOrdAItems.ref_v_termin_id = termins[termins.length - 1].id;
}
const mailData = {
trx_code: insideZone.ord_code,
drv_name: insideZone.drv_name,
// pickup_zone_title,
// pickup_zone_addr,
// drop_zone_title,
// drop_zone_addr,
pocket_total: 'Rp'+((new Intl.NumberFormat('id-ID')).format(insideZone.pocket_total)).split('.').join('-').split(',').join('.').split('-').join(','), // yang . => - || , => . || - => ,
bank_name: insideZone.drv_bank_name,
bank_code: insideZone.drv_bank_code,
bank_branch_name: insideZone.drv_bank_branch_name || '',
bank_acc_name: insideZone.drv_bank_acc_name,
bank_acc_no: insideZone.drv_bank_acc_number,
};
for (const updtOrd of updtToOrders) {
if (updtOrd.id === insideZone.ord_id) {
mailData.pickup_zone_title = updtOrd.pck_name;
mailData.pickup_zone_addr = updtOrd.pck_addr;
mailData.drop_zone_title = updtOrd.drop_name;
mailData.drop_zone_addr = updtOrd.drop_addr;
}
}
const danas = await DanaModels.list({'id': DanaModels.PK_ID, 'limit': 1});
if (danas.length < 1) {
apiRes = JSON.parse(JSON.stringify(response[400]));
apiRes.meta.message = 'dana error';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const dana = danas[0];
const payloadDana = {
'ord_id': insideZone.ord_id,
'ord_code': insideZone.ord_code,
'checkpoint_id': insideZone.checkpoint_id,
'bank_code': insideZone.drv_bank_code,
'bank_name': insideZone.drv_bank_name,
'bank_branch': insideZone.drv_bank_branch_name || null,
'amt': insideZone.pocket_total,
'acc_name': insideZone.drv_bank_acc_name,
'acc_number': insideZone.drv_bank_acc_number,
'device_id': device_id,
};
if (dana.amt > insideZone.pocket_total && dana.amt > DanaModels.MINIMUM_AMT) {
const axInstance = axios.create();
axios.defaults.timeout = 3000;
axios.defaults.crossDomain = true;
const respDana = await axInstance.post(process.env.API_DANA_BINGCORP + 'order/create', payloadDana, {
timeout: 3000,
headers: {
// 'Host': '127.0.0.1',
'Content-Type': 'application/json',
}
});
const respDataDana = respDana.data || {};
if (respDana.status != 200 || respDataDana.meta.code != 200) {
const insLogsTf = {
'ord_id': insideZone.ord_id,
'ord_code': insideZone.ord_code,
'type': OrdersLogsTfModels.TYPE_TF_CHECKPOINT,
'checkpoint_id': insideZone.checkpoint_id,
'amount': insideZone.pocket_total,
'stts': OrdersLogsTfModels.STTS_FAIL,
'fail_at': moment().unix(),
'note': respDataDana.data.note || 0,
'bank_id': insideZone.drv_bank_id,
'bank_name': insideZone.drv_bank_name,
'bank_code': insideZone.drv_bank_code,
'bank_short_name': insideZone.drv_bank_short_name,
'bank_branch_name': insideZone.drv_bank_branch_name || null,
'bank_acc_name': insideZone.drv_bank_acc_name,
'bank_acc_number': insideZone.drv_bank_acc_number,
'method': OrdersLogsTfModels.METHOD_DANA,
'url': process.env.API_DANA_BINGCORP + 'order/create',
'ref_code': respDataDana.data.dana_reference_no || 0,
'req_data': JSON.stringify(payloadDana),
'resp_data': JSON.stringify(respDataDana),
'crt': moment().unix(),
'updt': moment().unix(),
};
const updtOrdCheckpoint = {
'id': insideZone.checkpoint_id,
'pocket_is_paid': OrdersCheckpointsModels.IS_TF_FAIL,
'pocket_paid_note': respDataDana.data.note,
'pocket_paid_at': now,
'pocket_paid_by': 0,
'bank_id': insideZone.drv_bank_id,
'bank_name': insideZone.drv_bank_name,
'bank_code': insideZone.drv_bank_code,
'bank_short_name': insideZone.drv_bank_short_name,
'bank_branch_name': insideZone.drv_bank_branch_name || null,
'bank_acc_name': insideZone.drv_bank_acc_name,
'bank_acc_number': insideZone.drv_bank_acc_number,
'tf_method': OrdersCheckpointsModels.TF_METHOD_DANA,
'tf_at': now,
'tf_url': process.env.API_DANA_BINGCORP + 'order/create',
'tf_ref_code': respDataDana.data.dana_reference_no || 0,
'tf_note': respDataDana.data.note || 0,
'tf_req_data': JSON.stringify(payloadDana),
'tf_resp_data': JSON.stringify(respDataDana),
};
await OrdersCheckpointsModels.bundleUpdt(updtOrdCheckpoint, {}, insLogsTf);
continue;
}
const insLogsTf = {
'ord_id': insideZone.ord_id,
'ord_code': insideZone.ord_code,
'type': OrdersLogsTfModels.TYPE_TF_CHECKPOINT,
'checkpoint_id': insideZone.checkpoint_id,
'amount': insideZone.pocket_total,
'stts': OrdersLogsTfModels.STTS_PAID,
'paid_at': moment().unix(),
'note': respDataDana.data.note || 0,
'bank_id': insideZone.drv_bank_id,
'bank_name': insideZone.drv_bank_name,
'bank_code': insideZone.drv_bank_code,
'bank_short_name': insideZone.drv_bank_short_name,
'bank_branch_name': insideZone.drv_bank_branch_name || null,
'bank_acc_name': insideZone.drv_bank_acc_name,
'bank_acc_number': insideZone.drv_bank_acc_number,
'method': OrdersLogsTfModels.METHOD_DANA,
'url': process.env.API_DANA_BINGCORP + 'order/create',
'ref_code': respDataDana.data.dana_reference_no || 0,
'req_data': JSON.stringify(payloadDana),
'resp_data': JSON.stringify(respDataDana),
'crt': moment().unix(),
'updt': moment().unix(),
};
const updtOrdCheckpoint = {
'id': insideZone.checkpoint_id,
'pocket_is_paid': OrdersCheckpointsModels.IS_PAID_OFF,
'pocket_paid_at': now,
'pocket_paid_by': 0,
'bank_id': insideZone.drv_bank_id,
'bank_name': insideZone.drv_bank_name,
'bank_code': insideZone.drv_bank_code,
'bank_short_name': insideZone.drv_bank_short_name,
'bank_branch_name': insideZone.drv_bank_branch_name || null,
'bank_acc_name': insideZone.drv_bank_acc_name,
'bank_acc_number': insideZone.drv_bank_acc_number,
'tf_method': OrdersCheckpointsModels.TF_METHOD_DANA,
'tf_at': now,
'tf_url': process.env.API_DANA_BINGCORP + 'order/create',
'tf_ref_code': respDataDana.data.dana_reference_no || 0,
'tf_note': respDataDana.data.note || 0,
'tf_req_data': JSON.stringify(payloadDana),
'tf_resp_data': JSON.stringify(respDataDana),
};
const updtDana = {
'id': dana.id,
'amt': mysql.raw('amt-'+insideZone.pocket_total),
};
await OrdersCheckpointsModels.bundleUpdt(updtOrdCheckpoint, insOrdAItems, insLogsTf, updtDana);
} else {
for (const admin of admins_data) {
mailData.admin_name = admin.admin_name;
mailData.dana_current = 'Rp'+((new Intl.NumberFormat('id-ID')).format(dana.amt)).split('.').join('-').split(',').join('.').split('-').join(','); // yang . => - || , => . || - => ,,
mailData.dana_minimum = 'Rp'+((new Intl.NumberFormat('id-ID')).format(DanaModels.MINIMUM_AMT)).split('.').join('-').split(',').join('.').split('-').join(','); // yang . => - || , => . || - => ,,
LibMail.sendFinanceInfoDanaAmount('Saldo Dana Tidak Mencukupi', admin.admin_mail, mailData);
}
}
for (const admin of admins_data) {
mailData.admin_name = admin.admin_name;
LibMail.sendFinanceInfoTfPocket('Transfer uang saku order ' + mailData.trx_code, admin.admin_mail, mailData);
}
}
}
// spawn zone
const inSpawnCircle = await ZoneModels.getCheckpointsInCircle(lat, lng, {drv_id: did});
const inSpawnShape = await ZoneModels.getCheckpointsInShape(lat, lng, {drv_id: did});
let insideSpawnZone = [];
if (inSpawnCircle.length > 0 || inSpawnShape.length > 0) {
for (const circle of inSpawnCircle) {
// hit api disbure
if (circle.drv_bank_id == 0 || circle.drv_bank_acc_number == null) continue;
insideSpawnZone.push(circle);
}
for (const shape of inSpawnShape) {
// hit api disbure
if (shape.drv_bank_id == 0 || shape.drv_bank_acc_number == null) continue;
insideSpawnZone.push(shape);
}
}
let logDevices = [];
if (updtToOrders.length > 0) {
const includedVhcId = [];
for (const updtOrd of updtToOrders) {
if (includedVhcId.includes(updtOrd.vhc_id)) continue;
includedVhcId.push(updtOrd.vhc_id);
const logDevice = {
original_hex: null,
protocol: GpsTracksModels.PROTOCOL_SMARTPHONE,
action: GpsTracksModels.ACT_LOCATION,
device_id,
latitude: lat,
longitude: lng,
speed: null,
orientation: 0,
stts_engine: GpsTracksModels.STTS_EN_MOVING,
stts_gps: GpsTracksModels.STTS_GPS_ON,
stts_gsm: GpsTracksModels.STTS_GSM_STRONG_SIGNAL,
stts_reverse_geo: GpsTracksModels.STTS_REVERSE_GEO_NOT,
pre_milleage: 0, // dari jarak sebelumnya ke sekarang
sum_milleage: 0, // calculated on device_id (IMEI)
vhc_milleage: 0, // calucalted on vhc_id
drv_milleage: 0, // calucalted on drv_id
vhc_id: updtOrd.vhc_id,
drv_id: did,
source: GpsTracksModels.SOURCE_SMARTPHONE,
crt: now,
crt_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'),
crt_d: req_at,
crt_d_format: moment.unix(req_at).format('YYYY-MM-DD HH:mm:ss'),
crt_s: now,
crt_s_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'),
};
const lastTrack = await GpsTracksModels.get2LastLoc({vhc_id: updtOrd.vhc_id});
// const lastTrack = await GpsTracksModels.get2LastLoc({device_id}); // kurang cocok by device_id, karena ada case update lokasi tanpa orderan yang sedang aktif
// count milleage
if (logDevice.latitude != null && logDevice.longitude != null && lastTrack.length > 0) {
const distance = LibHelper.haversineGreatCircleDistance(lastTrack[0].latitude, lastTrack[0].longitude, logDevice.latitude, logDevice.longitude, LibHelper.EARTH_RADIUS_KM);
const distance_km = LibHelper.kmToKm(distance, 100000000);
console.log(`DRIVER UP LOCATION => vhc_id:${updtOrd.vhc_id}, did:${did}, distance_km:${distance_km}`);
if (distance_km < 3) {
const vhc = await VhcModels.getVhcById(logDevice.vhc_id);
if (vhc.length > 0) {
logDevice.pre_milleage = distance_km;
logDevice.sum_milleage = (lastTrack[0].sum_milleage + logDevice.pre_milleage).toFixed(8);
if (lastTrack[0].vhc_id == logDevice.vhc_id) {
logDevice.vhc_milleage = (lastTrack[0].vhc_milleage + logDevice.pre_milleage).toFixed(8);
} else {
logDevice.vhc_milleage = (vhc[0].sum_milleage + logDevice.pre_milleage).toFixed(8);
}
const drv = await DriversModels.find(did);
if (drv.length > 0) {
if (lastTrack[0].did == logDevice.did) {
logDevice.drv_milleage = (lastTrack[0].drv_milleage + logDevice.pre_milleage).toFixed(8);
} else {
logDevice.drv_milleage = (drv[0].sum_milleage + logDevice.pre_milleage).toFixed(8);
}
DriversModels.update({ sum_milleage: logDevice.drv_milleage }, did);
}
// VhcModels.update(updtOrd.vhc_id, { sum_milleage: logDevice.vhc_milleage });
}
}
}
logDevices.push(logDevice);
const currTrack = await GpsTracksModels.bundleCreate2(logDevice, {});
/**
* get lastSpawn desc index 0, where leave_at = 0
* kalo gaada create, dengan isi field enter_at aja, kalo ada didalam zona
* kalo ada update, dengan isi field leave_at aja, kalo udah diluar zona
*/
const lastSpawn = await GpsTracksModels.listSpawnZone({
source: GpsTracksModels.SOURCE_SMARTPHONE,
vhc_id: updtOrd.vhc_id,
drv_id: did,
ord_id: updtOrd.ord_id,
// ord_code: updtOrd.ord_code,
leave_at_d: 0,
order_by: 'ORDER BY id DESC',
limit: 1,
});
if (lastSpawn.length > 0) {
let is_leave_zone = 1, is_leave_zone_pck = 1, is_leave_zone_drop = 1;
for (const insideZone of insideSpawnZone) {
if (insideZone.ord_id === updtOrd.ord_id && insideZone.zid === lastSpawn[0].zone_id) is_leave_zone = 0;
if (insideZone.zid === updtOrd.pck_id) is_leave_zone_pck = 0;
if (insideZone.zid === updtOrd.drop_id) is_leave_zone_drop = 0;
}
if (is_leave_zone === 1 && lastSpawn[0].ord_id === updtOrd.ord_id) {
GpsTracksModels.updt2SpawnZone({
leave_lat: lat,
leave_lng: lng,
leave_at_d: req_at,
leave_at_d_format: moment.unix(req_at).format('YYYY-MM-DD HH:mm:ss'),
leave_at_s: now,
leave_at_s_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'),
updt: now,
updt_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'),
}, lastSpawn[0].id);
}
if (is_leave_zone_pck === 1 && updtOrd.pck_leave_at === 0) {
OrdersPickupsModels.updt({
id: updtOrd.ord_pck_id,
pck_leave_at: req_at,
});
}
if (is_leave_zone_drop === 1 && is_leave_zone_pck === 0 && updtOrd.pck_leave_at !== 0 && updtOrd.drop_leave_at === 0) {
OrdersDropsModels.updt({
id: updtOrd.ord_drop_id,
drop_leave_at: req_at,
});
}
} else {
for (const insideZone of insideSpawnZone) {
if (insideZone.ord_id === updtOrd.ord_id) {
GpsTracksModels.create2SpawnZone({
device_id: device_id,
master_id: Number(currTrack.result.insertId),
enter_lat: lat,
enter_lng: lng,
enter_at_d: req_at,
enter_at_d_format: moment.unix(req_at).format('YYYY-MM-DD HH:mm:ss'),
enter_at_s: now,
enter_at_s_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'),
zone_id: insideZone.zid,
zone_name: insideZone.name,
vhc_id: updtOrd.vhc_id,
drv_id: did,
ord_id: insideZone.ord_id,
ord_pck_drop_id: insideZone.ord_pck_drop_id,
// ord_code: insideZone.ord_code,
source: GpsTracksModels.SOURCE_SMARTPHONE,
crt: now,
crt_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'),
});
}
if (insideZone.zid === updtOrd.pck_id && updtOrd.pck_enter_at === 0) {
OrdersPickupsModels.updt({
id: updtOrd.ord_pck_id,
pck_enter_at: req_at,
});
}
if (insideZone.zid === updtOrd.drop_id && updtOrd.drop_enter_at === 0) {
OrdersDropsModels.updt({
id: updtOrd.ord_drop_id,
drop_enter_at: req_at,
});
}
}
}
}
} else {
const logDevice = {
original_hex: null,
protocol: GpsTracksModels.PROTOCOL_SMARTPHONE,
action: GpsTracksModels.ACT_LOCATION,
device_id,
latitude: lat,
longitude: lng,
speed: null,
orientation: 0,
stts_engine: GpsTracksModels.STTS_EN_MOVING,
stts_gps: GpsTracksModels.STTS_GPS_ON,
stts_gsm: GpsTracksModels.STTS_GSM_STRONG_SIGNAL,
stts_reverse_geo: GpsTracksModels.STTS_REVERSE_GEO_NOT,
pre_milleage: 0, // dari jarak sebelumnya ke sekarang
sum_milleage: 0, // calculated on device_id (IMEI)
vhc_milleage: 0, // calucalted on vhc_id
drv_milleage: 0, // calucalted on drv_id
vhc_id: 0,
drv_id: did,
source: GpsTracksModels.SOURCE_SMARTPHONE,
crt: now,
crt_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'),
crt_d: req_at,
crt_d_format: moment.unix(req_at).format('YYYY-MM-DD HH:mm:ss'),
crt_s: now,
crt_s_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'),
};
const lastTrack = await GpsTracksModels.get2LastLoc({drv_id: did});
// count milleage
if (logDevice.latitude != null && logDevice.longitude != null && lastTrack.length > 0) {
const distance = LibHelper.haversineGreatCircleDistance(lastTrack[0].latitude, lastTrack[0].longitude, logDevice.latitude, logDevice.longitude, LibHelper.EARTH_RADIUS_KM);
const distance_km = LibHelper.kmToKm(distance, 100000000);
console.log(`DRIVER UP LOCATION => did:${did}, distance_km:${distance_km}`);
if (distance_km < 3) {
const drv = await DriversModels.find(did);
if (drv.length > 0) {
logDevice.pre_milleage = distance_km;
logDevice.sum_milleage = (lastTrack[0].sum_milleage + logDevice.pre_milleage).toFixed(8);
if (lastTrack[0].did == logDevice.did) {
logDevice.drv_milleage = (lastTrack[0].drv_milleage + logDevice.pre_milleage).toFixed(8);
} else {
logDevice.drv_milleage = (drv[0].sum_milleage + logDevice.pre_milleage).toFixed(8);
}
DriversModels.update({ sum_milleage: logDevice.drv_milleage }, did);
}
}
}
logDevices.push(logDevice);
const currTrack = await GpsTracksModels.bundleCreate2(logDevice, {});
/**
* get lastSpawn desc index 0, where leave_at = 0
* kalo gaada create, dengan isi field enter_at aja, kalo ada didalam zona
* kalo ada update, dengan isi field leave_at aja, kalo udah diluar zona
*/
const lastSpawn = await GpsTracksModels.listSpawnZone({
source: GpsTracksModels.SOURCE_SMARTPHONE,
vhc_id: 0,
drv_id: did,
ord_id: 0,
// ord_code: 0,
leave_at_d: 0,
order_by: 'ORDER BY id DESC',
limit: 1,
});
if (lastSpawn.length > 0) {
let is_leave_zone = 1;
for (const insideZone of insideSpawnZone) {
if (insideZone.zid === lastSpawn[0].zone_id) is_leave_zone = 0;
}
if (is_leave_zone === 1) {
GpsTracksModels.updt2SpawnZone({
leave_lat: lat,
leave_lng: lng,
leave_at_d: req_at,
leave_at_d_format: moment.unix(req_at).format('YYYY-MM-DD HH:mm:ss'),
leave_at_s: now,
leave_at_s_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'),
updt: now,
updt_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'),
}, lastSpawn[0].id);
}
} else {
for (const insideZone of insideSpawnZone) {
GpsTracksModels.create2SpawnZone({
device_id: device_id,
master_id: Number(currTrack.result.insertId),
enter_lat: lat,
enter_lng: lng,
enter_at_d: req_at,
enter_at_d_format: moment.unix(req_at).format('YYYY-MM-DD HH:mm:ss'),
enter_at_s: now,
enter_at_s_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'),
zone_id: insideZone.zid,
zone_name: insideZone.name,
vhc_id: 0,
drv_id: did,
ord_id: 0,
// ord_code: 0,
source: GpsTracksModels.SOURCE_SMARTPHONE,
crt: now,
crt_format: moment.unix(now).format('YYYY-MM-DD HH:mm:ss'),
});
}
}
}
apiRes = JSON.parse(JSON.stringify(response[200]));
// apiRes.raw = updtToOrders;
// apiRes.logDevices = logDevices;
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
} catch (e) {
apiRes = JSON.parse(JSON.stringify(response[500]));
apiRes.meta.message += Helper.setErrMsg(': ' + e.message);
LibLogReqResApi.log(req, apiRes);
return res.status(500).json(apiRes);
}
}
// OTHERS
async notif(req, res) {
let apiRes = {}
try {
const now = moment().unix();
const { did, title, body, type, fcm_token, silent_notif } = req.body;
// input validation
const input = {
did,
fcm_token,
title,
body,
type,
silent_notif,
};
const rulesInput = {
did: 'required|integer',
fcm_token: 'required|string',
title: 'string|max:255',
body: 'string',
type: 'required|integer',
silent_notif: 'boolean',
};
const isInputValid = new Validator(input, rulesInput);
if (isInputValid.fails()) {
apiRes = JSON.parse(JSON.stringify(response[422]));
apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const optFirebase = {
priority: 'normal',
android: {
priority: 'high',
},
click_action: 'FLUTTER_NOTIFICATION_CLICK',
};
let content_available = 'false';
if (silent_notif === 'true' || silent_notif === true) {
optFirebase.content_available = true; // ios
content_available = 'true';
}
// const phoneDevice = await DriversModels.getDeviceByDid(did);
// if (phoneDevice.length < 1) {
// apiRes = JSON.parse(JSON.stringify(response[404]));
// apiRes.meta.code += '_1';
// apiRes.meta.message = 'account not found, driver not login';
LibLogReqResApi.log(req, apiRes);
// return res.status(200).json(apiRes);
// }
// if (phoneDevice[0].is_login !== DriversModels.IS_LOGIN) {
// apiRes = JSON.parse(JSON.stringify(response[404]));
// apiRes.meta.code += '_1';
// apiRes.meta.message = 'account not found, driver not login';
LibLogReqResApi.log(req, apiRes);
// return res.status(200).json(apiRes);
// }
// phoneDevice[0].fcm_token
const libFirebase = new LibFirebase();
let notifTitle = title || '';
let notifBody = body || '';
if (silent_notif === 'true' || silent_notif === true) {
optFirebase.priority = 'high';
await libFirebase.sendToDevice(fcm_token, {
notification: {
title: 'Notifikasi Cek Lokasi', // notifTitle,
body: 'Harap Dihiraukan', // notifBody,
},
data: {
title: notifTitle,
body: notifBody,
type: '' + type,
detail_id: '',
content_available,
}
}, optFirebase);
} else {
await libFirebase.sendToDevice(fcm_token, {
notification: {
title: notifTitle,
body: notifBody,
},
data: {
title: notifTitle,
body: notifBody,
type: '' + type,
detail_id: '',
content_available,
}
}, optFirebase);
}
apiRes = JSON.parse(JSON.stringify(response[200]));
apiRes.meta.message = 'success send notification';
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
} catch (e) {
apiRes = JSON.parse(JSON.stringify(response[500]));
apiRes.meta.message += Helper.setErrMsg(': ' + e.message);
LibLogReqResApi.log(req, apiRes);
return res.status(500).json(apiRes);
}
}
// DEV ONLY
async lastLatLng(req, res) {
let apiRes = {}
try {
const now = moment().unix();
const { did } = req.query;
// input validation
const input = {
did,
};
const rulesInput = {
did: 'required|integer',
};
const isInputValid = new Validator(input, rulesInput);
if (isInputValid.fails()) {
apiRes = JSON.parse(JSON.stringify(response[422]));
apiRes.meta.message += Helper.setErrMsg(': ' + Object.values(isInputValid.errors.all())[0][0]); // get first message
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
}
const getLastLoc = await GpsTracksModels.getLastLocAndAddrByDid({did, limit: 100});
const formatLastLoc = [];
for (const lst of getLastLoc) {
formatLastLoc.push({
id: lst.id,
did: lst.drv_id,
device_id: lst.device_id,
latitude: lst.latitude,
longitude: lst.longitude,
state_text: lst.state_text,
city_text: lst.city_text,
district_text: lst.district_text,
village_text: lst.village_text,
streets_text: lst.streets_text,
fulladdress: lst.fulladdress,
crt_device_unix: lst.crt_d,
crt_dvice_raw: lst.crt_d_format,
crt_server_unix: lst.crt_s,
crt_server_raw: lst.crt_s_format,
});
}
apiRes = JSON.parse(JSON.stringify(response[200]));
apiRes.data = formatLastLoc;
LibLogReqResApi.log(req, apiRes);
return res.status(200).json(apiRes);
} catch (e) {
apiRes = JSON.parse(JSON.stringify(response[500]));
apiRes.meta.message += Helper.setErrMsg(': ' + e.message);
LibLogReqResApi.log(req, apiRes);
return res.status(500).json(apiRes);
}
}
}
const object = new ServiceDriverController();
module.exports = object;