Finalize tasks

This document assumes you understand how to create and use tasks. It provides specific examples for how to finalize shipment tasks as follows:

  • Close a task: Closing a shipment task changes its state to CLOSED and indicates that that task is no longer active.

  • Set the task outcome: Once a task is closed, you then finalize it by setting its outcome to either SUCCEEDED or FAILED. This is an important part of finalizing a task in order to show the delivery outcome in journey sharing and to ensure correct billing for the Fleet Engine service.

Close a task

You can close a task in the following ways:

  • Update the stop status for the vehicle. You remove the stop from the vehicle, which in turn closes all tasks associated with the stop. See Update stop status for details.
  • Remove the task from the list of vehicle stops. This involves updating the list of tasks for the stop, but with the closed task no longer part of the list. See Update task order in Update tasks.
  • Set the task state to CLOSED. This can only be done on tasks not assigned to vehicles. This section shows this approach.

Once you close a task, you may not reopen it.

Closing of a task does not indicate its success or failure. It indicates that the task is no longer considered in progress. In order to indicate the actual outcome of a task and to have that displayed for Fleet Tracking and journey sharing purposes, you must indicate the actual outcome of a task. See Set the task outcome below.

Task fields for closing tasks

This section documents the required fields to set when closing a task. Fleet engine ignores all other fields in the entity for the update.

Required field Value
state State.CLOSED

Close a task directly

The following examples show how to set an unassigned task to a closed state, either in gRPC or using an HTTP REST request call to UpdateTask

gRPC

 static final String PROJECT_ID = "my-delivery-co-gcp-project";
 static final String TASK_ID = "task-8241890";

 DeliveryServiceBlockingStub deliveryService =
   DeliveryServiceGrpc.newBlockingStub(channel);

 // Task settings
 String taskName = "providers/" + PROJECT_ID + "/tasks/" + TASK_ID;
 Task task = Task.newBuilder()
   .setName(taskName)
   .setState(Task.State.CLOSED) // You can only directly CLOSE a
   .build();                    // task that is NOT assigned to a vehicle.

 // Task request
 UpdateTaskRequest updateTaskRequest =
   UpdateTaskRequest.newBuilder()  // No need for the header
       .setTask(task)
       .setUpdateMask(FieldMask.newBuilder().addPaths("state"))
       .build();

 try {
   Task updatedTask = deliveryService.updateTask(updateTaskRequest);
 } catch (StatusRuntimeException e) {
   Status s = e.getStatus();
   switch (s.getCode()) {
      case NOT_FOUND:
        break;
      case PERMISSION_DENIED:
        break;
   }
   return;
 }

REST

PATCH https://fleetengine.googleapis.com/v1/providers/<project_id>/tasks/<id>?updateMask=state

  • <id> is a unique identifier for the task.
  • The request header must contain a field Authorization with the value Bearer <token>, where <token> is issued by your server according to the guidelines described in Service account roles and JSON Web tokens.
  • You must include a Task entity in the request body

Example curl command:

 # Set JWT, PROJECT_ID, and TASK_ID in the local environment
 curl -X PATCH "https://fleetengine.googleapis.com/v1/providers/${PROJECT_ID}/tasks/${TASK_ID}?updateMask=state,taskOutcome,taskOutcomeTime" \
   -H "Content-type: application/json" \
   -H "Authorization: Bearer ${JWT}" \
   --data-binary @- << EOM
 {
   "state": "CLOSED",
   "taskOutcome": "SUCCEEDED",
   "taskOutcomeTime": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
 }
 EOM

Set the task outcome

To indicate the actual outcome of a task, you set the outcome for closed tasks to either SUCCEEDED or FAILED. A task must be closed before you set its outcome. Fleet Engine only charges for delivery tasks with a state of SUCCEEDED.

Task outcome details

Tasks also provide additional details about the task outcome. You can set these directly and Fleet Engine respects your settings:

  • Task outcome location: Fleet Engine automatically fills in the task outcome location with the last known vehicle location. You can provide this instead if you prefer.
  • Task outcome time: Fleet Engine does not fill this field in, but is available for you to set.

You can use any of the following approaches to setting task_outcome_location and task_outcome_time:

  • Update them in the same request that sets the task outcome.
  • Update them later, after you have set task outcome.
  • Modify them again after they have been set.

Fleet Engine prevents the following updates related to task outcomes:

  • You can't modify a task outcome once it is set to either SUCCEEDED or FAILED.
  • You can't set a task outcome location or outcome time for tasks without a set outcome.

Task fields for setting outcome

This section documents the required and optional fields to set when setting a task outcome. Fleet Engine ignores other fields in the entity for the update.

Required field Value
taskOutcome Outcome.SUCCEEDED or Outcome.FAILED

Optional fieldValue
taskOutcomeLocation The location where the task was completed. If not set, Fleet Engine defaults this to the last vehicle location.
taskOutcomeTime The timestamp when the task was completed.

Task outcome examples

The following example shows how to use the Java gRPC library and an HTTP REST call to UpdateTask to set a task outcome to SUCCEEDED and set the location where the task was completed.

gRPC

 static final String PROJECT_ID = "my-delivery-co-gcp-project";
 static final String TASK_ID = "task-8241890";

 DeliveryServiceBlockingStub deliveryService =
   DeliveryServiceGrpc.newBlockingStub(channel);

 // Task settings
 String taskName = "providers/" + PROJECT_ID + "/tasks/" + TASK_ID;
 Task task = Task.newBuilder()
   .setName(taskName)
   .setTaskOutcome(TaskOutcome.SUCCEEDED)
   .setTaskOutcomeTime(now())
   .setTaskOutcomeLocation(               // Grand Indonesia East Mall
     LocationInfo.newBuilder().setPoint(
       LatLng.newBuilder().setLatitude(-6.195139).setLongitude(106.820826)))
   .build();

 // Task request
 UpdateTaskRequest updateTaskRequest =
   UpdateTaskRequest.newBuilder()  // No need for the header
       .setTask(task)
       .setUpdateMask(FieldMask.newBuilder().addPaths("task_outcome", "task_outcome_time", "task_outcome_location"))
       .build();

 try {
   Task updatedTask = deliveryService.updateTask(updateTaskRequest);
 } catch (StatusRuntimeException e) {
   Status s = e.getStatus();
   switch (s.getCode()) {
      case NOT_FOUND:
        break;
      case PERMISSION_DENIED:
        break;
   }
   return;
 }

REST

PATCH https://fleetengine.googleapis.com/v1/providers/<project_id>/tasks/<id>?updateMask=taskOutcome,taskOutcomeTime,taskOutcomeLocation

  • <id> is a unique identifier for the task.
  • The request header must contain a field Authorization with the value Bearer <token>, where <token> is issued by your server according to the guidelines described in Service account roles and JSON Web tokens.
  • The request body must contain a Task entity.
 # Set JWT, PROJECT_ID, and TASK_ID in the local environment
 curl -X PATCH "https://fleetengine.googleapis.com/v1/providers/${PROJECT_ID}/tasks/${TASK_ID}?updateMask=taskOutcome,taskOutcomeTime,taskOutcomeLocation" \
   -H "Content-type: application/json" \
   -H "Authorization: Bearer ${JWT}" \
   --data-binary @- << EOM
 {
   "taskOutcome": "SUCCEEDED",
   "taskOutcomeTime": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")",
   "taskOutcomeLocation": {
     "point": {
       "latitude": -6.195139,
       "longitude": 106.820826
     }
   }
 }
 EOM

What's next