Cancellation of a diagnostic service appointment with reason for cancellation (Java)
In this use case, the user or the diagnostic center cancels the appointment with or without reason
Code snippets
Client calls the BAP server to trigger cancel:
@PostMapping("/healthcare_diagnostics/cancel_appointment")
public ResponseEntity cancelAppointment(
@RequestHeader HttpHeaders headers,
@RequestBody ClientOrderRequest request) {
var response = bapApplicationService.cancelOrder(request, headers);
return ResponseEntity.ok(response);
}
BAP server generates the protocol request body
/*
Example Request JSON:
{
"context": {
"domain": "nic2004:85195",
"country": "IND",
"city": "std:080",
"action": "cancel",
"core_version": "0.9.2",
"bap_id": "https://mock_bap.com/",
"bap_uri": "https://mock_bap.com/beckn/",
"transaction_id": "1239890342",
"message_id": "123793824",
"timestamp": "2021-03-23T10:00:40.065Z"
},
"message": {
"order_id": "order_1",
"cancellation_reason_id": "reason_3"
}
}
*/
public Response cancelOrder(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.cancel)
.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 cancel the order of given appointment id
// The valid cancellation reasons will be fetched by the BPP's /get_cancellation_reasons endpoint
var cancelRequest = CancelRequest.builder()
.context(context)
.message(CancelMessage.builder()
.orderId(request.getOrderId())
.cancellationReasonId(request.getCancellationReason())
.build())
.build();
return invokeCancel(cancelRequest, headers);
}
}
BAP server calls protocol cancel to the network
public Response invokeCancel(CancelRequest 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 Cancel api from the returned endpoint.
// Construct request headers with the public key
var responseEntity = apiClient.post(url[0] + Context.ActionEnum.cancel,
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_cancel
/*
Example Response JSON:
{
"context": {
"domain": "nic2004:85195",
"country": "IND",
"city": "std:080",
"action": "on_status",
"core_version": "0.9.2",
"bap_id": "https://mock_bap.com/",
"bap_uri": "https://mock_bap.com/beckn/",
"transaction_id": "1239890342",
"message_id": "123793824",
"timestamp": "2021-03-23T10:00:40.065Z"
},
"message": {
"order": {
"id": "order_1",
"state": "Cancelled",
"items": [
{
"id": "health_checkup",
"quantity": {
"count": 1
}
}
],
"billing": {
"name": "John Doe",
"address": {
"door": "21A",
"name": "ABC Apartments",
"locality": "HSR Layout",
"city": "Bengaluru",
"state": "Karnataka",
"country": "India",
"area_code": "560102"
},
"email": "[email protected]",
"phone": "+919876543210"
},
"fulfillment": {
"end": {
"location": {
"id": "srs-koramangala",
"gps": "12.9349377,77.6055586"
},
"time": {
"range": {
"start": "2021-08-11T04:30:00.000Z",
"end": "2021-08-11T05:30:00.000Z"
}
},
"contact": {
"phone": "+919876543210",
"email": "[email protected]"
}
}
},
"quote": {
"price": {
"currency": "INR",
"value": "1100"
},
"breakup": [
{
"title": "Lab Charges",
"price": {
"currency": "INR",
"value": "1000"
}
},
{
"title": "Service Charge",
"price": {
"currency": "INR",
"value": "100"
}
}
],
"ttl": "P1H"
},
"payment": {
"uri": "https://api.bpp.com/pay?amt=$amount&txn_id=ksh87yriuro34iyr3p4&mode=upi&vpa=bpp@upi",
"tl_method": "http/get",
"params": {
"transaction_id": "ksh87yriuro34iyr3p4",
"amount": "1100",
"mode": "upi",
"vpa": "bpp@upi"
},
"type": "ON-FULFILLMENT",
"status": "NOT-PAID"
}
}
}
}
*/
@PostMapping("/bap/on_cancel")
public ResponseEntity onCancel(
@RequestHeader HttpHeaders headers,
@RequestBody OnCancelRequest request) {
var response = bapCallbackApplicationService.onCancel(request, headers);
return ResponseEntity.ok(response);
}
public Response onCancel(OnCancelRequest 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_cancel results
// Endpoint for the client to poll the cancelled order based on the message id
@GetMapping("/healthcare_diagnostics/on_cancel_order")
public ResponseEntity onCancelOrder(
@PathVariable(ClientRoutes.PARAM_MESSAGE_ID) String messageId,
@RequestHeader HttpHeaders headers) {
var data = bapApplicationService.get(messageId);
return ResponseEntity.ok(data);
}