Weight Discrepancy - High Level Design (Backend)
BRD: Weight discrepancy management
RATE-CALC FEES CREATION: Eshopbox shipping fee creation
Rate Calculator Figma: https://www.figma.com/proto/shNnoJdgeUDlRLsEXECaNp/WIP-%7C-June-2023?page-id=275%3A11126&type=design&node-id=275-11127&viewport=228%2C213%2C0.08&t=nUGItfXR1b6Itb0J-1&scaling=min-zoom
Rate Calculation : drive.google.com/Courier_Rate_Calculator.xlsx
EPIC: https://auperator.atlassian.net/browse/SHE-3799
Account Fees
https://docs.google.com/spreadsheets/d/1b14TlCfahCt3t-2_b_lXMJwlsIUgNB_lW0JdMtpDIos/edit?usp=sharing
Activity details to be displayed
Pending
Exports
CRON :
charging seller at end after specific time(to be discussed with mituj sir)
changing new to lost after specific time
update if excess charges is zero
Notifications
Weight Protection Plan - Frontend Changes for Shield
If status is won hide excess weight and excess charge
Contents:
Flowchart
Data Model
Excel: Weight_Discrepancy_Data_Model.xlsx
Sample Logs
status | actor | additionalDetails |
---|---|---|
new | eshopbox | img |
not_disputed | seller/system | - |
disputed | seller | img |
won | eshopbox | - |
lost | eshopbox | img |
escalated | seller | - |
Possible logs
new | new | new | new | new | new | new | new |
| not_disputed | disputed | disputed | disputed | disputed | disputed | disputed |
|
|
| won | lost | lost | lost | lost |
|
|
|
|
| escalate | escalate | escalate |
|
|
|
|
|
| won | lost |
NEW | NOT DISPUTED | DISPUTED | WON | LOST | ESCALATE | WON | LOST |
Import/Export Jobs
1. Import (Report Discrepancy ➤ New)
{
"resource": "import_job",
"eventType": "POST",
"eventSubType": "processing",
"accountSlug": "tab",
"email": "snehal.soni@eshopbox.com",
"geoIp": {
"country_code": "IN",
"country_code3": "IND",
"country_name": "India",
"city_name": "New Delhi",
"latitude": 28.652,
"longitude": 77.1663,
"time_zone": "Asia/Kolkata",
"continent_code": "AS",
"subdivision_code": "DL",
"subdivision_name": "National Capital Territory of Delhi",
"ip": "14.143.159.3"
},
"version": "v1",
"responseData": {
"id": 13554,
"jobType": "weightDiscrepancy",
"channelId": 0,
"userName": "snehal.soni@eshopbox.com",
"userId": 2664,
"filePath": "https://cdn.filestackcontent.com/j4u4uTYcTpCflYvm5LUa",
"status": "0",
"createdAt": "Feb 7, 2024, 9:12:12 AM",
"updatedAt": "Feb 7, 2024, 9:12:12 AM"
},
"machineOS": "Windows"
;Mandatory | Mandatory | Mandatory | Mandatory | Mandatory | Optional | Optional | Optional |
Tracking ID | Courier weight (in g) | Width (in cm) | Length (in cm) | Height (in cm) | Reference image URL 1 | Reference image URL 2 | Reference image URL 3 |
|
|
|
|
|
|
|
|
Read the excel data and create list of DTO and list of
tracking_id
'sFetch list of all the
shipping_id
's andweight
's for thetracking_id
'sSELECT shipments.id AS shipmentId, shipments.trackingID AS trackingId, shipments.weight AS shipmentWeight, shipments.dimension_length AS shipmentLength, shipments.dimension_width AS shipmentWidth, shipments.dimension_height AS shipmentHeight, warehouses.pincode AS warehousePincode, orders.shipping_postalCode AS ordersShippingPostalCode, IF(orders.isCOD='1', true, false) AS isCOD, order_items.brandAccountId AS brandAccountId, SUM(order_items.invoiceTotal) AS shipmentInvoiceTotal, COUNT(order_items.id) AS itemsInOrder, CASE WHEN courier_partners.standard='1' THEN 'Standard' WHEN courier_partners.express='1' THEN 'Express' WHEN courier_partners.priority='1' THEN 'Priority' END AS courierType FROM shipments LEFT JOIN orders ON orders.id = shipments.order_id LEFT JOIN order_items ON order_items.order_id = orders.id LEFT JOIN warehouses ON warehouses.id = shipments.warehouse_id LEFT JOIN courier_partners ON courier_partners.id = shipments.courier_partner_id WHERE trackingID IN (:trackingIdSet) GROUP BY shipments.id
Fetch existing data using it and do not update it
SELECT shipments.id AS shipmentId, shipments.trackingID AS trackingId FROM weight_discrepancy INNER JOIN shipments ON shipments.id = weight_discrepancy.shipment_id WHERE weight_discrepancy.shipment_id IN (:shipmentIdSet)
Prepare two lists:
If
CourierWeight
andShipmentWeight
are in same weight slab, then list withnew
statusIf in different slabs then list with
isDiscrepancy=0
status
Using spring-hibernate mapping insert data in both tables
Publish create event for all the new discrepancies in the Pub/Sub
{ "actor": "snehal.soni@eshopbox.com", "response_data": { [ { "trackingID" : 195041816874355, "shipmentID" : 289232983, "itemsInOrder" : 3, "excessWeight" : 0.9, "chargeableWeight" : 4.2, "appliedWeight" : 3.3 }, { ... }, {} ] }, "eventSubType": "new", "resource": "weight_discrepancy", "accountSlug": "tab", "eventType": "POST", "version": "v1" }
After all discrepancy have been created, update the import job on platform with below event :
URL: https://{{accountSlug}}.eshopbox.com/_ah/api/esb/v1/import-job/<jobId>
Headers:
Header | Value |
---|---|
Authorization | Bearer <token> |
ProxyHost | <accountSlug> |
Request body:
{
"jobType":"",
"additionalDetails":"",
"status":"1",
"successCount":"",
"failureCount":""
}
API’s
1. Get API (with filters)
GET
URL: https://{{accountSlug}}.myeshopbox.com/api/v1/dicrepancy
Params: ?page=1&perPage=10&createdOn=Yesterday&status=new,lost&searchParam=874320208778
Fetch
accountId
from the http sessionFetch weight dicrepancies and count
SELECT SQL_CALC_FOUND_ROWS weight_discrepancy.id AS id, orders.id AS order_id, orders.customerOrderNumber AS customerOrderNumber, orders.vendorOrderNumber AS vendorOrderNumber, weight_discrepancy.shipment_id AS shipment_id, shipments.externalShipmentID AS externalShipmentID, shipments.trackingID AS trackingID, weight_discrepancy.length AS length, weight_discrepancy.width AS width, weight_discrepancy.height AS height, weight_discrepancy.weight AS weight, shipments.weight AS shipmentWeight, weight_discrepancy.user_id AS user_id, users.email AS email, weight_discrepancy.additionalDetails AS additionalDetails, weight_discrepancy.excessCharge AS excessCharge, weight_discrepancy.isDiscrepancy AS isDiscrepancy, COUNT(order_items.id) AS itemsInOrder, UNIX_TIMESTAMP(weight_discrepancy.externalUpdatedAt) AS externalUpdatedAt, UNIX_TIMESTAMP(weight_discrepancy.created_at) AS created_at, UNIX_TIMESTAMP(weight_discrepancy.updated_at) AS updated_at, SUBSTRING_INDEX(GROUP_CONCAT(weight_discrepancy_status_logs.`status` ORDER BY weight_discrepancy_status_logs.id DESC), ',', 1) AS latestStatus, SUBSTRING_INDEX(GROUP_CONCAT(weight_discrepancy_status_logs.remarks ORDER BY weight_discrepancy_status_logs.id DESC), ',', 1) AS latestRemarks, SUBSTRING_INDEX(GROUP_CONCAT(UNIX_TIMESTAMP(weight_discrepancy_status_logs.externalUpdatedAt) ORDER BY weight_discrepancy_status_logs.id DESC), ',', 1) AS latestStatusExternalUpdatedAt, SUBSTRING_INDEX(GROUP_CONCAT(UNIX_TIMESTAMP(weight_discrepancy_status_logs.created_at) ORDER BY weight_discrepancy_status_logs.id DESC), ',', 1) AS latestStatusCreatedAt, SUBSTRING_INDEX(GROUP_CONCAT(UNIX_TIMESTAMP(weight_discrepancy_status_logs.updated_at) ORDER BY weight_discrepancy_status_logs.id DESC), ',', 1) AS latestStatusUpdatedAt FROM weight_discrepancy LEFT JOIN weight_discrepancy_status_logs ON weight_discrepancy.id = weight_discrepancy_status_logs.weight_discrepancy_id LEFT JOIN shipments ON shipments.id = weight_discrepancy.shipment_id LEFT JOIN orders ON orders.id = shipments.order_id LEFT JOIN order_items ON order_items.shipment_id = weight_discrepancy.shipment_id LEFT JOIN users ON users.id = weight_discrepancy.user_id WHERE weight_discrepancy.isDiscrepancy='1' AND ( orders.id IN (:searchParam ) OR shipments.id IN (:searchParam ) OR shipments.trackingID IN (:searchParam ) ) AND order_items.brandAccountId = :accountId AND weight_discrepancy.created_at >= :fromDate AND weight_discrepancy.created_at <= :toDate GROUP BY weight_discrepancy.id HAVING latestStatus IN (:status) LIMIT :limit;
SELECT FOUND_ROWS()
Fetch status logs and add it to response
SELECT weight_discrepancy_status_logs.id AS id, weight_discrepancy_status_logs.weight_discrepancy_id AS weight_discrepancy_id, weight_discrepancy_status_logs.`status` AS `status`, weight_discrepancy_status_logs.remarks AS remarks, weight_discrepancy_status_logs.actor AS actor, weight_discrepancy_status_logs.user_id AS user_id, users.email AS email, weight_discrepancy_status_logs.additionalDetails AS additionalDetails, UNIX_TIMESTAMP(weight_discrepancy_status_logs.externalUpdatedAt) AS externalUpdatedAt, UNIX_TIMESTAMP(weight_discrepancy_status_logs.created_at) AS created_at, UNIX_TIMESTAMP(weight_discrepancy_status_logs.updated_at) AS updated_at FROM weight_discrepancy_status_logs LEFT JOIN users ON users.id = weight_discrepancy_status_logs.user_id WHERE weight_discrepancy_status_logs.weight_discrepancy_id IN (:weightDiscrepancyIdList)
Fetch status count for each status
SELECT wdcStatus.latestStatus AS status, COUNT( wdcStatus.latestStatus ) AS statusCount FROM ( SELECT SUBSTRING_INDEX(GROUP_CONCAT(weight_discrepancy_status_logs.`status` ORDER BY weight_discrepancy_status_logs.id DESC), ',', 1) AS latestStatus FROM weight_discrepancy_status_logs LEFT JOIN weight_discrepancy ON weight_discrepancy.id = weight_discrepancy_status_logs.weight_discrepancy_id LEFT JOIN shipments ON shipments.id = weight_discrepancy.shipment_id LEFT JOIN orders ON orders.id = shipments.order_id LEFT JOIN order_items ON order_items.shipment_id = weight_discrepancy.shipment_id WHERE weight_discrepancy.isDiscrepancy='1' AND ( orders.id IN ( '11205905' ) OR shipments.id IN ( '11205905' ) OR shipments.trackingID IN ( '11205905' ) ) AND order_items.brandAccountId = 1541 AND weight_discrepancy.created_at >= '2024-02-21 17:13:01' AND weight_discrepancy.created_at <= '2024-03-13 12:26:52' GROUP BY weight_discrepancy.id HAVING latestStatus IN ('new','lost','disputed','not_disputed','won','escalated') ) AS wdcStatus GROUP BY wdcStatus.latestStatus;
If
accountId
is '5' then remove where condition from the above query as we need to fetch all the discrepancies possible
Convert it to required response based on latest status for each id
Sample Response
{ "page": 1, "perPage": 50, "total": "13", "totalPages": "13", "newCount": 6, "disputedCount": 2, "lostCount": 3, "notDisputedCount": 4, "wonCount": 5, "escalatedCount": 1, "data": [ { "id": "6", "order_id": "44213869", "customerOrderNumber": "5643620712515", "vendorOrderNumber": "#1009", "shipment_id": "11205815", "externalShipmentID": "5643620712515-6421-9758", "trackingID": "593816220555", "length": "30", "width": "20", "height": "20", "weight": "490", "shipmentWeight": "250", "user_id": "3354", "email": "snehal.soni@eshopbox.com", "additionalDetails":"", "excessCharge": 75.0, "isDiscrepancy": "1", "itemsInOrder": 2, "externalUpdatedAt": "", "created_at": "1709116180", "updated_at": "1709116180", "latestStatus": "not_disputed", "latestStatusExternalUpdatedAt": "", "latestStatusCreatedAt": "1709735588", "latestStatusUpdatedAt": "1709735588", "statusLogs": { "new": { "id": "2", "weight_discrepancy_id": "6", "status": "new", "remarks": "", "reason": "", "actor": "system", "user_id": "3354", "email": "snehal.soni@eshopbox.com", "additionalDetails": "{\"imageUrl1\":\"https://i.postimg.cc/pLRNcNgv/LCMSF652-PR10946-W1-0.jpg\",\"imageUrl2\":\"https://cdn.filestackcontent.com/hsq64kfTwKdRjWNgP4Mt\",\"imageUrl3\":\"https://i.postimg.cc/Kc3yRDn6/LCMSF652-PR10872-B2-0.jpg\"}", "externalUpdatedAt": "", "created_at": "1709116181", "updated_at": "1709116181" }, "not_disputed": { "id": "5", "weight_discrepancy_id": "6", "status": "not_disputed", "created_at": "1709735588", "updated_at": "1709735588" } } }, {...}, {...} ] }
gr
---Saurav---
2. Update Action PUT API
Implementation:
Action Types:
Accept Discrepancies ➤ Not Disputed (Seller)
Reject Discrepancy ➤ Disputed (Seller)
Accept Dispute ➤ Won (Admin)
Reject Dispute ➤ Lost (Admin)
Escalate ➤ Disputed (Seller)
3. Rate Calculator POST API
Rate Calculator - Internal
CRONS
1. CRON POST API
---In Progress---