Tracking an order (Java)

In this use case, the user usually clicks on "Track Order" or sometimes, the application automatically renders the tracking screen as part of the order screen. Here the seller usually sends a tracking link to the tracking page of the order.

Track

Code snippets

Client calls the BAP server to trigger track:

    @PostMapping("/local_retail/track_order")
    public ResponseEntity trackOrder(
            @RequestHeader HttpHeaders headers,
            @RequestBody ClientOrderRequest request) {
        var response = bapApplicationService.trackOrder(request, headers);
        return ResponseEntity.ok(response);
    }

BAP server generates the protocol request body


/*
Example Request JSON:
{
    "context": {
        "domain": "nic2004:52110",
        "country": "IND",
        "city": "std:080",
        "action": "track",
        "core_version": "0.9.1",
        "bap_id": "https://mock_bap.com/",
        "bap_uri": "https://mock_bap.com/beckn/",
        "bpp_id": "https://mock_bpp.com/",
        "bpp_uri": "https://mock_bpp.com/beckn/",
        "transaction_id": "1209849124",
        "message_id": "12341242347",
        "timestamp": "2021-03-23T10:00:40.065Z"
    },
    "message": {
        "order_id": "order_1",
        "callback_url": "https://mock_bap.com/order_track?orderId=order_1"
    }
}
*/

    public Response trackOrder(ClientOrderRequest request, HttpHeaders headers) {

        // Generate message id
        var messageId = UUID.randomUUID().toString();

        // Check if transaction id exists in the request.
        // Generate if not exists
        var txnId = StringUtils.hasText(request.getTransactionId())
                ? request.getTransactionId()
                : UUID.randomUUID().toString();

        // Construct the Context based on the request parameters
        var context = Context.builder().domain(request.getDomain())
                .action(Context.ActionEnum.track)
                .messageId(messageId)
                .transactionId(txnId)
                .transactionId(UUID.randomUUID().toString())
                .timestamp(new Date().toString())
                .build();

        // Construct the protocol specific object to be passed to the BPP
        // to track the active order
        var trackRequest = TrackRequest.builder()
                .context(context)
                .message(StatusMessage.builder()
                        .orderId(request.getOrderId())
                        .callbackUrl(request.getTrackingCallbackUrl())
                        .build())
                .build();

        return invokeTrack(trackRequest, headers);
    }
}

BAP server calls protocol track to the network

    public Response invokeTrack(TrackRequest request, HttpHeaders headers) {

        // Call to look up function which returns the the public key and BPP Endpoint to be called
        var url = lookUp(headers);

        // Call BPP Track api from the returned endpoint.
        // Construct request headers with the public key
         var responseEntity = apiClient.post(url[0] + Context.ActionEnum.track,
                constructRequestHeaders(),
                request,
                Response.class);

        // Validate the received response
        if (responseEntity.getBody() == null || responseEntity.getBody().getError() != null ||
                "NACK".equals(responseEntity.getBody().getMessage().getAck().getStatus())) {
            // Return custom error to the client
            return null;
        }
        return Response.of("ACK", null);
    }

BAP receives protocol on_track

/*
Example Response JSON:
{
    "context": {
        "domain": "nic2004:52110",
        "country": "IND",
        "city": "std:080",
        "action": "on_track",
        "core_version": "0.9.1",
        "bap_id": "https://mock_bap.com/",
        "bap_uri": "https://mock_bap.com/beckn/",
        "bpp_id": "https://mock_bpp.com/",
        "bpp_uri": "https://mock_bpp.com/beckn/",
        "transaction_id": "1209849124",
        "message_id": "12341242343",
        "timestamp": "2021-03-23T10:00:40.065Z"
    },
    "message": {
        "tracking": {
            "tl_method": "http/get",
            "url": "https://track.mock_bpp.com?order_id=order_1",
            "status": "active"
        }
    }
}
*/
    @PostMapping("/bap/on_track")
    public ResponseEntity onTrack(
            @RequestHeader HttpHeaders headers,
            @RequestBody OnTrackRequest request) {
        var response = bapCallbackApplicationService.onTrack(request, headers);
        return ResponseEntity.ok(response);
    }

    public Response onTrack(OnTrackRequest request, HttpHeaders headers) {
        // Validate the headers received
        var isHeadersValid = validateHeaders(headers);
        // Construct and return error if the received headers are invalid
        if (!isHeadersValid) return null;

        // Store the data received based on message id for the client to poll
        saveToDB(request);

        return Response.of("ACK", null);
    }

Client polls BAP to get the on_track results

    // Endpoint for the client to poll the order tracking based on the message id
    @GetMapping("/local_retail/on_track_order")
    public ResponseEntity onTrackOrder(
            @PathVariable(ClientRoutes.PARAM_MESSAGE_ID) String messageId,
            @RequestHeader HttpHeaders headers) {
        var data = bapApplicationService.get(messageId);
        return ResponseEntity.ok(data);
    }