AMTI DEV NOTE:
It has been more than half a year since I have last received an issue or requires support in WDT module. I will only list down the common and recent issues that occurred as no other concerns have happened for months.
⚠ ️ SCENARIO: DTR already finished
This is the common WDT Mobile app that issue that occurs using the WDT Mobile App ver 2019, this is due to the bugs currently existing on the production WDT Mobile app.
Solution:
The only solution is to set the dtr_start to NULL in the database and were good to go. WDT Mobile App only checks if the app has already started trip via the dtr_start column in the wdt table in the ais database .
You can use your Database IDE to update the row or you can use the script below:
UPDATE ais.wdt w SET w.dtr_start = NULL WHERE w.dtr_no = <dtr_no> # change to a valid dtr_no
⚠ ️ SCENARIO: Delivery status is wrongly tagged
This usually happens when the delivery personnel is not mindful of their actions in settings the status. This an easy fix however logistics and sales personnel will also be notified on this mistake. It is advisable to remind the warehouse team to advice the sales and logistics that a delivery is wrongly tagged.
| Status ID | Status Name | Notification |
|---|---|---|
| 0 | Ongoing | no |
| 1 | Delivered | no |
| 2 | Undelivered | yes |
| 3 | Cancelled | yes |
You can use your Database IDE to update the row or you can use the script below:
# Settings status to Ongoing
UPDATE ais.wdt_data wd
SET
wd.status = 0, # This can be 0, 1, 2 or 3
wd.psn_latitude = NULL,
wd.psn_longitude = NULL,
wd.timestamp_delivered = NULL,
wd.is_synced_mobile = NULL,
wd.timestamp_synced = NULL,
WHERE wd.dtr_no = <dtr_no>
AND wd.picking_slip_no = <picking_slip_no>
Note that if delivery have assets and remarks (usually when delivery is tagged undelivered and cancelled), we must also remove those updates.
wd.signature = '',
wd.image1 = '',
wd.image2 = '',
wd.image3 = '',
wd.image4 = '',
wd.image5 = '',
wd.delivery_remarks = '',
⚠ ️ SCENARIO: Syncing Failed
There are many different causes of this error.
- No internet access.
- Low network reception.
- API took too long to return a response.
- Very large
POST requestdata. This mostly happens when the update contains assets (images and signature). - And mostly due to unhandled behavior of the mobile app that was unforeseen by the developer
This scope is broad as we have no control over the client side (which in our case is the WDT Mobile App). But the most recent causes of this syncing failure is the WDT notification.
The WDT notification is considered a Tech debt that I wasn't able to fix. To see full detail regarding this issue. See WDT Notification Tech Debt.
Explanation:
WDT Notification relies on the oracle database. Some of the Oracle Scripts used in the notification to retrieve the recipients of the notification is very slow which sometimes takes a minute to complete that causes the error to Syncing failure in the mobile App. Here is an overview of the error
Update Overview Logic Flow
graph TD;
app[1. WDT Mobile app]-->app1[1.1 App updates the delivery]
--Send POST Request to the server and WAITS FOR 30 SEC. TO RECEIVE THE RESPONSE
-->b[2. Server receives the request and process the delivery updates]
-->c[3. Server checks if the request is valid and correct]
--Send Error if update fails-->app
c-->d[4. Update is committed, will now send notifications to related personnel]
--Pass Data Parameters DTR,PSN and Delivery updates
-->e[5. Run Oracle Script to retrieve the related parties of the Delivery->PSN]
--Run 3 Separate scripts. Get the Warehouse, Sales and Logistics department
-->f[6. For each personnel send composed notification according to the parameters provided]
--// Sometimes messages are sent 2 seconds per personnel
-->g[7. All message sent]
--Return Response 200 OK
-->app
The diagram above is the old updating process (Update API) of the WDT Delivery when the Delivery personnel (driver) updates thru the WDT Mobile App. Here is the reasons why this has an issue:
- The App requires a 30 sec timeout. If I haven't done this. The app could be stuck in a very long loading indicator. This is bad user experience for user. Also note that:
- This could also cause multiple errors and bugs if we allow users to interact with the app while its waiting for a response in a request.
- This could also cause a longer loading if the user suddenly lost its signal reception as the connection between the App and the server is already disconnected without receiving a response.
- The notification needs to be awaited to receive a response. This is not necessary for the driver as he/she have no reason to ensure that the notification is sent to its recipients. Their only objective is to delivery and update the system about the delivery.
- Email sending is done iteratively, meaning every single personnel recipient must call the email sending API and this API call sometimes requires 2 seconds to be completed. Meaning it will be multiplied by the number of recipients
Below is an example duration of the old WDT Notification.
-
WHERE AS:
- dC as "Number of Deliveries"
- wP as "Warehouse Personnel"
- sP as "Sales Personnel"
- lP as "Logistics Personnel"
- sec as "Seconds"
Formula: Duration = ((wP + sP + lP) * sec) * dC \\
Assumption: 40 = ((2 + 1 + 1) * 2 ) * 5
The assumption above is is the average data per DTR. An average of 5 deliveries. A fixed sized of 2 Warehouse Personnel (according to current data). 1 Sales personnel and 1 Logistics personnel related to a said delivery.
This WDT Notification assumption already took 40 secs to complete
- EXCLUSIVE of the Delivery Update that also varies to the internet speed and reception which averagely takes 1 second.
- EXCLUSIVE of the oracle data pull of personnel related to the delivery which varies to the number of sales and logistic related to the delivery. Average second is undetermined.
Meaning we have already reached the limit of the App that requires a 30 sec timeout to receive a response just for the WDT Notification sending, which causes the Syncing Failed scenario.
Quick Solution:
One of the solution I came up with is to forcefully return the response regardless of the API finishes the function code block.
This is done by using the code line below:
set_time_limit(120); // Add time limit to the function to avoid memory leaks for unfinished execution
/**
* ...
* ... some code here ...
* ...
*/
header('Connection: close');
header('Content-Length: ' . ob_get_length());
ob_end_flush();
ob_flush();
flush();
if (session_id()) session_write_close();
/**
* ...
* ... some code here that doesn't need to return a response ...
* ...
*/
Note that it is advisable to include the
set_time_limitto avoid memory leaks. Unfinished API call is one thing we should avoid.
Using the code block above will in logic flow below:
graph TD;
app[1. WDT Mobile app]-->app1[1.1 App updates the delivery]
--Send POST Request to the server and WAITS FOR 30 SEC. TO RECEIVE THE RESPONSE
-->b[2. Server receives the request and process the delivery updates]
-->c[3. Server checks if the request is valid and correct]
--Send Error if update fails-->app
c-->d[4. Update is committed, will now send notifications to related personnel]
--Return Response 200 Ok-->app
d--Pass Data Parameters DTR,PSN and Delivery updates
-->e[5. Run Oracle Script to retrieve the related parties of the Delivery->PSN]
--Run 3 Separate scripts. Get the Warehouse, Sales and Logistics department
-->f[6. For each personnel send composed notification according to the parameters provided]
--// Sometimes messages are sent 2 seconds per personnel
-->g[7. All message sent]
The diagram above represents the immediate response of the API without traversing through the whole code block (Return a response in step 4).
The whole API code block below:
public function updateDelivery() {
set_time_limit(120); // Add time limit to the function to avoid memory leaks for unfinished execution
if ($this->input->request_headers()["authtoken"] != md5(bin2hex(md5(md5(md5("https://ais.amti.com.ph/wdt/")))))) {
echo json_encode(["code" => 1, "msg" => "Invalid token " . $this->input->request_headers()["authtoken"]]);
return;
}
$postData = json_decode($this->input->post('delivery_form_update'));
if ($postData == null) {
echo json_encode(['code' => 1, 'msg' => "invalid parameters"]);
return;
}
$dtrNo = $postData->dtr_no;
$psn = $postData->picking_slip_number;
$status = $postData->status;
$deliveryRemarks = $postData->delivery_remarks;
$timestampDelivered = $postData->timestamp_delivered;
$latitude = $postData->latitude;
$longitude = $postData->longitude;
$isSynced = $postData->is_synced;
$this->db->trans_start();
$this->db->set('status', $status);
$this->db->set('delivery_remarks', $deliveryRemarks);
$this->db->set('timestamp_delivered', $timestampDelivered);
$this->db->set('psn_latitude', $latitude);
$this->db->set('psn_longitude', $longitude);
$this->db->where('picking_slip_no', $psn);
$timestampSynced = date('Y-m-d H:i:s');
$this->db->set('is_synced_mobile', $isSynced); // API Generated value
$this->db->set('timestamp_synced', $timestampSynced); // API Generated value
$this->db->update('wdt_data');
if ($this->db->trans_status() === false) {
$this->db->trans_rollback();
echo json_encode(['code' => 2, 'msg' => 'Synced failed']);
return;
} else {
$this->db->trans_commit();
echo json_encode([
'code' => 0,
'msg' => 'Synced successful',
'data' => ['synced_at' => $timestampSynced, 'synced_status' => $isSynced]
]);
header('Connection: close');
header('Content-Length: ' . ob_get_length());
ob_end_flush();
ob_flush();
flush();
if (session_id()) session_write_close();
// All cancelled ("3") deliveries will not insert in wdt_shipping_detail
if ($status != 3) $this->mobile_wdt->tracking_detail_mobile($status, $dtrNo, $psn);
// SEND SMS NOTIFICATION IF DELIVERY STATUS IS CHANGED
// * [msgId] = [status] is the same where:
// - 1 => delivered
// - 2 => undelivered
// - 3 => cancelled
if ($status != "1" || $status != "0") $this->mobile_wdt->amti_sms_mobile($dtrNo, $psn, $status, $deliveryRemarks);
}
}
Other known solution:
One solution I could think of is to optimize the Oracle script by the previous developer in pulling the personnel related to the delivery. However I haven't used this solution as it does not solve the delay of Notification Sending API and Optimizing an oracle script is quite cumbersome as I am not familiar with the transactions database of the company (Not to mention that it is a dangerous place to tinker with).
Use the application/libraries/Mobile_wdt.php for notification handling. Note that this is an exact copy of some functions in the wdt.php in the controller. I separated this to avoid altering the previous developer work in case I modify something.
This is also considered a Tech Debt as the connection of the Oracle Database to the WDT Notification is only for retrieving the mobile numbers of the sales and logistics personnel. However due to the hardware malfunction of the SMS server. SMS Notifications is not used, indicating that the oracle dependency can be removed.