Last Mile Fleet Solution is currently available only to select customers. Contact sales to learn more.

Fleet Engine 使用入门

通过 Fleet Engine Deliveries API,您可以为车队的活动建模,以模拟交付的最后一公里和最后一公里。Deliveries API 通过 Driver SDK for Android 和 iOS 提供,而且也可以通过 HTTP REST 或 gRPC 调用直接使用。

初始设置

Fleet Engine Deliveries API 是通过 Google Cloud Console 配置的。如需了解在控制台中执行的步骤以及如何创建 JSON Web 令牌以进行授权,请参阅身份验证和授权。如需详细了解如何使用控制台,请参阅 Google Cloud Console 文档

验证设置

创建服务帐号后,您应验证设置已完成,并可以创建送货车辆。通过在工作流的此阶段进行验证,您可以确保您已在设置项目时解决常见的授权问题。按照验证您的设置指南操作。 本指南详细介绍了如何使用 gcloud 命令行实用程序来测试设置的两个关键部分:授权令牌签名和试用交付车辆创建。

或者,您也可以使用 Fleet Engine Auth 示例脚本来测试您的设置。

客户端库

我们以几种常见的编程语言发布客户端库。与原始 REST 或 gRPC 相比,这些库可提供更好的开发者体验。如需了解如何为服务器应用获取客户端库,请参阅客户端库

本文档中的 Java 示例假定您熟悉 gRPC。

数据结构

Deliveries API 使用两种数据结构来模拟商品的取货和交货:

  • 运送货物的送货工具。
  • 货物自提和配送任务。

此外,您还可以使用任务来对驱动程序的中断和全天的计划停止进行建模。

交车

车辆会将货物从仓库运送到交货地点,也从取件点运送到仓库。在某些情况下,快递员可能还能将商品直接从取件点运送到送货地点。

您可以使用 Driver SDK 在 Fleet Engine 中创建 DeliveryVehicle 对象,并发送位置更新以便进行物流和车队跟踪。

任务

每辆车都分配有任务。其中可能包括自提或配送任务、司机要求的休息时间,或到接送箱或客户地点的预定站点。每个任务都必须具有唯一的任务 ID,但可以具有相同的跟踪 ID。这些任务及其安排时间可用于计算每项任务的 ETA 时间范围。

使用 Driver SDK 任务管理器在 Fleet Engine 中创建任务。

装运任务

运单任务与自提或放下订单相关。 您必须在创建运单任务时指定跟踪编号或 ID。 您还必须指定停留时间,以留出额外的时间来完成任务、寻找停车地点或步行前往交接位置。

  • 创建用于自提商品的自提任务,指定自提位置和跟踪编号或 ID。
  • 创建送货任务,指定送货地点和跟踪编号或 ID。

不可用的任务

创建不可用任务的时间段,表示车辆无法自提或交货。这可以是为车辆加油的休息点,也可以是驾驶员休息的时段。

在创建任务时指定广告插播时长。休息时间不必在某个特定地点进行,但指定某个位置可以在一整天中提供更准确的 ETA 时间范围。

预定的停止任务

创建预定的停止任务,以模拟送货车辆的站点。 例如,您可以为特定地点的每日安排的充电站创建预定的停止任务,这与同一地点的其他配送或自提无关。您还可以为来自集合的集合创建预定的停止任务,或者为 Feeder 车辆的传输或服务中心和服务点的停靠点建模。

您可以查看 DeliveryVehiclegRPCREST)和 TaskgRPCREST)的 API 参考文档,了解每个数据结构中包含的特定字段。

任务 ID 指南

任务 ID 必须是唯一的,并且不得公开任何个人身份信息 (PII) 或明文数据。

任务 ID 必须符合以下格式要求:

  • ID 必须是有效的 Unicode 字符串。
  • ID 不得超过 64 个字符。
  • ID 将根据 Unicode 标准化表单 C 进行标准化。
  • ID 不得包含以下任意 ASCII 字符:“/”“:”“\”“?”或“#”。

以下是有效任务 ID 的一些示例:

  • 566c33d9-2a31-4b6a-9cd4-80ba1a0c643b
  • e4708eabcfa39bf2767c9546c9273f747b4626e8cc44e9630d50f6d129013d38
  • NTA1YTliYWNkYmViMTI0ZmMzMWFmOWY2NzNkM2Jk

下表显示了无效任务 ID 的示例:

任务 ID 无效 原因
2019 年 8 月 31 日 - 20:48-46.70746,-130.10807,-85.17909,61.33680 违反个人身份信息和字符要求:逗号、句号、冒号和斜杠。
JohnDoe-577b484da26f-Cupertino-SantaCruz 违反个人身份信息要求。
4R0oXLToF”112 Summer Dr. East Hartford, CT06118”577b484da26f8a 违反个人身份信息和字符要求:空格、逗号和引号。超过 64 个字符。

车辆的生命周期

DeliveryVehicle 对象表示第一英里或最后一公里的车辆运输。您可以使用以下命令创建 DeliveryVehicle 对象:

  • 包含用于调用 Fleet Engine API 的服务帐号的 Google Cloud 项目的 ID。
  • 客户拥有的车辆 ID。

每辆车的车辆 ID 都应是唯一的。不应将其重复用于其他车辆,除非该车辆没有待完成的任务。

当您调用 UpdateDeliveryVehicle 时,请务必检查是否存在 NOT_FOUND 错误,如有必要,请调用 CreateDeliveryVehicle 以创建新车辆。未使用 UpdateDeliveryVehicle 更新的 DeliveryVehicle 对象会在七天后自动删除。请注意,使用已存在的项目 ID/车辆 ID 对调用 CreateDeliveryVehicle 会生成错误。

车辆属性

DeliveryVehicle 实体包含 DeliveryVehicleAttribute 的重复字段。舰队引擎不会解读这些属性。ListDeliveryVehicles API 包含一个 filter 字段,该字段可将返回的 DeliveryVehicle 实体限制为具有指定属性的实体。

虽然 attributes 字段对 Fleet Engine 是不透明的,请勿在属性中包含个人身份信息或敏感信息,因为用户可能会看到此字段。

任务的生命周期

可以使用 Deliveries API gRPC 或 REST 接口创建、更新和询问 Fleet Engine 中的任务。

Task 对象有一个状态字段来跟踪其生命周期。相应值会从“打开”变为“关闭”。新创建的任务会处于“开启”状态,这表示:

  • 此任务尚未分配给送货车辆。
  • 送货车辆尚未超过分配给任务的车辆停车点。

只有当车辆处于“打开”状态时,才能将任务分配给车辆。

取消任务后,您可以从车辆停靠列表中将其移除。 随后,其状态会自动设置为“已关闭”。

当任务的车辆完成任务的车辆停止时,将任务的结果字段更新为 SUCCEEDED 或 FAILED,并指定事件的时间戳。任务结果可以在任务完成之前或之后的任何时间设置,但只能设置一次。

然后,JavaScript 装运跟踪库就可以指示任务的结果。任务状态会自动设置为“已关闭”。如需了解详情,请参阅使用 JavaScript 物流跟踪库跟踪物流

与车辆一样,如果任务在七天后仍未更新,则尝试创建已存在的 ID 的任务会返回错误。

注意:Fleet Engine 不支持明确删除任务。七天后,该服务会自动删除任务,但不会进行更新。如果您想将任务数据保留 7 天以上,则必须自行实现该功能。

集成 Deliveries API

您可以使用不受信任的模型或受信任的模型来集成 Deliveries API,该模型指示您可以使用 Driver SDK 进行的更新。首选不受信任的模型。可信模型目前为预览版。

不受信任的模型

对于不受信任的模型,您可以使用 Fleet Engine Delivery Untrusted Driver User 角色授予更新送货车辆位置的权限。具有此角色的服务帐号颁发的令牌通常用于您的交付驱动程序的移动设备。

不受信任的模型

可信模型

对于可信预览版(预览版),您可以使用 Fleet Engine Delivery Trusted Driver User 角色来授予创建和更新交付车辆和任务的权限,包括更新交付车辆的位置和任务状态或结果。具有此角色的服务帐号颁发的令牌通常用于您的交付驱动程序的移动设备或后端服务器。

可信模型

如需详细了解 Google Maps Platform 最后一公里舰队解决方案对可信模型和不可信模型使用的角色,请参阅 Cloud 项目设置

只有当您拥有和管理设备时,才能完成来自移动设备的完整集成。这样可确保它们完全可信。 然后,您可以直接从 Driver SDK 创建车辆和任务。

注意:出于安全考虑,您应仅在后端服务器上颁发令牌,然后将其分享给客户端。

为工作日建模

下表介绍了第一公里或最后一公里司机在快递公司和物流公司工作的时间。您的公司可能详细信息有所不同,但您可以查看如何建模一个工作日。

时间活动建模
一天内开始的 24 小时内 调度员负责将货物分配给送货车辆或路线。 您可以在 Fleet Engine 中提前创建送货、自提和休息等任务。例如,您可以创建物流自提任务物流交付任务计划不可用状态计划停止

当一组交付包裹及其交付顺序最终确定后,应将任务分配给车辆。
当天开始时间 驾驶员登录“驾驶员”应用后,以一天的站点为起点开始一天的工作。 初始化 Delivery Driver API。根据需要在 Fleet Engine 中创建送货车辆
司机将货物装入送货车辆,扫描物流信息。 如果不是提前创建送货任务,请在扫描时创建送货任务
驱动程序确认要执行的任务的顺序。 如果它们不是提前创建的,请创建取货任务安排不可用时间预定站点
驱动程序离开仓库,并承诺完成下一个需要完成的任务数量。 通过提交车辆的完成顺序,将所有任务或部分任务分配给车辆。
快递员送货。 到达送货站后,执行与到达停车点相关的操作。 交付货品后,关闭交付任务并视需要存储配送状态和其他元信息。 在停车点完成所有任务之前,以及在开始驾车前往下一个停车点之前,执行与车辆完成停车点车辆前往下一站的路线相关的操作。
司机与喂食器交错,将额外的货物运送到送货车辆。 喂食器和送货车辆之间中转的会议地点应建模为预定站点

转移并扫描运单后,创建交付任务(如果尚未创建任务)。然后,通过将任务分配给车辆更新任务顺序来更新任务完成顺序。
驾驶员会收到自提请求通知。 接受自提请求后,创建取货任务。然后,通过将任务分配给车辆更新任务顺序来更新任务执行顺序。
中午 司机在午休。 如果某个营业地点与不可用任务关联,请像处理其他任务一样处理该营业地点。执行与车辆到达停车点车辆完成停车点车辆前往下一站点相关的操作。

否则,在广告插播结束之前,无需执行进一步操作。 通过确认下一个任务和剩余任务,并更新任务排序来移除该任务。
司机取货。 这就像投放停止一样。执行与到达停车点关闭任务以及(可选)存储运送状态和其他元信息相关的操作。 在停靠站完成所有任务之前,以及开始驾车前往下一站之前,执行与车辆完成停车点车辆前往下一站的路线相关的操作。 注意:为了确保结算正确无误,所有自提订单都必须有相应的配送任务。如果取货人将在当天抵达司机所在路线上的其他位置,我们建议您将该送货任务建模为路线上的任何其他送货任务。如果司机将上车点送回仓库,我们建议在仓库目的地创建交付任务。
司机设定一个停车点,以便从快递箱取货。 这就像任何其他自提站点一样。执行与到达停车点关闭任务相关的操作。在停车点完成所有任务并开始驾车前往下一个停车点后,执行与车辆完成停车点车辆前往下一站的路线相关的操作。
司机会收到将货物转到其他地点的通知。 将原始装运任务状态设置为“已完成”,并为新的送货地点创建新的送货任务。如需了解详情,请参阅重新安排运单
司机尝试投递包裹,但未能成功。 此模式类似于成功的传送停止,用于将传送任务标记为已完成。执行与到达停车点相关的操作。未能交付运单后,关闭任务并视需要存储运单状态和其他元信息。 在停靠站完成所有任务之前,以及开始驾车前往下一站之前,执行与车辆完成停车点车辆前往下一站的路线相关的操作。
已通知驾驶员暂缓发货(不送货)。 收到通知并确认后,将任务状态设置为“已完成”。
然后,司机就被告知要送货上去,并更改承诺的送货顺序。 更新任务排序
司机选择不送货。 更新任务排序,然后继续照常操作。
司机将多个货物送到一个地点。 此模式类似于单个送货目的地。 到达停车点后,执行与到达停车点相关的操作。 交付每批货品后,关闭每项任务,并视需要存储发货状态和其他元信息。在停靠站完成所有任务之前,以及开始驾车前往下一站之前,执行与车辆完成停车点车辆前往下一站的路线相关的操作。
当天结束时间 驾驶员回到车站。 如果司机在运送途中取货,您还必须将每个包裹作为交付任务创建并关闭,以确保结算正确无误。为此,您可以对仓库进行建模,就像对任何其他停靠点进行建模一样。如果仓库未用作投递站,您仍然可以选择将仓库建模为计划停靠点。这样一来,您的司机就能够看到返回车站的路线,还能查看预计到达时间。

了解位置信息更新

一旦送货车辆从经停点前往车辆(包括停靠站)为止,位置更新会发送给 Fleet Engine,直到到达下一个经停点。由于系统不会自动检测这些事件,因此您必须以编程方式进行标记。使用可检测交通方式变化的库来触发将所需通知发送到 Fleet Engine。

当驾驶员没有驾车时,位置更新应暂停,因为当有人位于建筑物内时,位置信号的质量会显著降低。

位置更新频率可在 Driver SDK 中设置。默认每 10 秒发送一次更新。

车辆停靠点和送货地点

车辆停靠点是指送货车辆完成运输任务或其他某些任务。它是一个接入点,例如加载基座或道路吸附位置。

送货地点是指送货或自提的地方。往返交货地点可能需要从车辆停靠点步行一段路程。

例如,当司机将商品配送到商场的商店时,送货车辆会停在购物中心靠近停车场入口的停车场。这是车辆停靠站。然后,司机从车辆停靠处步行至商店所在的购物中心内的位置。这是送货地点。

为了给用户带来最佳的物流跟踪体验,请考虑如何将物流任务分配给车辆停靠站,并请注意,系统会向用户报告运输任务中剩余的车辆停放次数,以帮助用户查看物流进度。

例如,如果司机在一栋办公大楼中多次送货,不妨考虑将所有送货任务分配给一个车辆停靠点。如果每个送货任务都被分配给自己的车辆停靠点,您的送货跟踪体验对用户来说就没那么有用,因为只有当车辆在到达目的地之前有限的车辆停靠点内时,跟踪跟踪功能才可用。在短时间内完成许多车辆停靠不会为用户提供大量时间来跟踪其交付进度。

使用移动 SDK

在对 Driver SDK 进行任何调用之前,请务必对其进行初始化。

初始化 Delivery Driver API

在驱动程序 SDK 中初始化 Delivery Driver API 之前,请务必初始化 Navigation SDK。然后,初始化 Delivery Driver API,如以下示例所示:

static final String PROVIDER_ID = "provider-1234";
static final String VEHICLE_ID = "vehicle-8241890";

NavigationApi.getNavigator(
   this, // Activity.
   new NavigatorListener() {
     @Override
     public void onNavigatorReady(Navigator navigator) {
       DeliveryDriverApi.createInstance(DriverContext.builder(getApplication())
         .setNavigator(navigator)
         .setProviderId(PROVIDER_ID)
         .setVehicleId(VEHICLE_ID)
         .setAuthTokenFactory((context) -> "JWT") // AuthTokenFactory returns JWT for call context.
         .setRoadSnappedLocationProvider(NavigationApi.getRoadSnappedLocationProvider(getApplication()))
         .setNavigationTransactionRecorder(NavigationApi.getNavigationTransactionRecorder(getApplication()))
         .setStatusListener((statusLevel,statusCode,statusMsg) -> // Optional, surfaces polling errors.
             Log.d("TAG", String.format("New status update. %s, %s, %s", statusLevel, statusCode, statusMsg)))
         .build));
     }

     @Override
     public void onError(int errorCode) {
       Log.e("TAG", String.format("Error loading Navigator instance: %s", errorCode));
     }
   });

使用场景

本部分介绍如何使用 Deliveries API 为常见使用场景建模。

唯一实体标识符

REST 调用中使用的唯一实体标识符的格式和值对于 Fleet Engine 是不透明的。避免使用自动递增 ID,并确保标识符不包含任何个人身份信息 (PII),例如驾驶员的电话号码。

创建车辆

您可以通过 Driver SDK 或服务器环境创建车辆。

gRPC

如需创建新车,您需要对 Fleet Engine 进行 CreateDeliveryVehicle 调用。使用 CreateDeliveryVehicleRequest 对象定义新送货车辆的属性。请注意,根据用户指定的 ID 的 API 指南,系统会忽略为 Name 字段指定的任何值。您应使用 DeliveryVehicleId 字段设置车辆 ID。

创建 DeliveryVehicle 时,您可以选择指定两个字段:

  • 属性
  • 上次定位时间

所有其他字段均不得设置;否则,Fleet Engine 会返回错误,因为这些字段是只读字段或只能通过 UpdateDeliveryVehicle 调用进行更新。

如需在不设置任何可选字段的情况下创建车辆,您可以在 CreateDeliveryVehicleRequest 中不设置 DeliveryVehicle 字段。

以下示例展示了如何使用 Java gRPC 库创建车辆:

static final String PROJECT_ID = "my-delivery-co-gcp-project";
static final String VEHICLE_ID = "vehicle-8241890"; // Avoid auto-incrementing IDs.

DeliveryServiceBlockingStub deliveryService =
  DeliveryServiceGrpc.newBlockingStub(channel);

// Vehicle settings
String parent = "providers/" + PROJECT_ID;
DeliveryVehicle vehicle = DeliveryVehicle.newBuilder()
  .addAttributes(DeliveryVehicleAttribute.newBuilder()
    .setKey("route_number").setValue("1"))  // Opaque to the Fleet Engine
  .build();

// Vehicle request
CreateDeliveryVehicleRequest createVehicleRequest =
  CreateDeliveryVehicleRequest.newBuilder()  // No need for the header
      .setParent(parent)
      .setDeliveryVehicleId(VEHICLE_ID)     // Vehicle ID assigned by the Provider
      .setDeliveryVehicle(vehicle)
      .build();

// Error handling
// If Fleet Engine does not have vehicle with that ID and the credentials of the
// requestor pass, the service creates the vehicle successfully.

try {
  DeliveryVehicle createdVehicle =
    deliveryService.createDeliveryVehicle(createVehicleRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
     case ALREADY_EXISTS:
       break;
     case PERMISSION_DENIED:
       break;
  }
  return;
}

REST

如需从服务器环境创建车辆,请对 CreateDeliveryVehicle 进行 HTTP REST 调用:

POST https://fleetengine.googleapis.com/v1/providers/<project_id>/deliveryVehicles?deliveryVehicleId=<id>

<id> 是舰队中交货车辆的唯一标识符

请求标头必须包含字段 Authorization,其值为 Bearer <token>,其中 <token>Fleet Engine 令牌工厂发放的令牌

POST 正文表示要创建的 DeliveryVehicle 实体。您可以指定以下可选字段:

  • 属性
  • 最后一个位置

curl 命令示例:

# Set $JWT, $PROJECT_ID, and $VEHICLE_ID in the local
# environment
curl -X POST "https://fleetengine.googleapis.com/v1/providers/${PROJECT_ID}/deliveryVehicles?deliveryVehicleId=${VEHICLE_ID}" \
  -H "Content-type: application/json" \
  -H "Authorization: Bearer ${JWT}" \
--data-binary @- << EOM
{
  "attributes": [{"key": "model", "value": "sedan"}],
  "lastLocation": {"location": {"latitude": 12.1, "longitude": 14.5}}
}
EOM

根据用户指定 ID 的 API 指南,Fleet Engine 会忽略 DeliveryVehicle 实体的 name 字段。所有其他字段均不得设置;否则,Fleet Engine 会返回错误,因为这些字段是只读的,或者只能通过 UpdateDeliveryVehicle 调用进行更新。

如需在不设置任何字段的情况下创建车辆,可将 POST 请求的正文留空。新创建的车辆将通过 POST 网址中的 deliveryVehicleId 参数提取车辆 ID。

curl 命令示例:

# Set $JWT, $PROJECT_ID, and $VEHICLE_ID in the local
# environment
curl -X POST "https://fleetengine.googleapis.com/v1/providers/${PROJECT_ID}/deliveryVehicles?deliveryVehicleId=${VEHICLE_ID}" \
  -H "Content-type: application/json" \
  -H "Authorization: Bearer ${JWT}"

创建取货任务

您可以通过 Driver SDK 或服务器环境创建取货任务。

gRPC

以下示例展示了如何使用 Java gRPC 库创建取货任务:

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

DeliveryServiceBlockingStub deliveryService =
  DeliveryServiceGrpc.newBlockingStub(channel);

// Task settings
String parent = "providers/" + PROJECT_ID;
Task task = Task.newBuilder()
  .setType(Task.Type.PICKUP)
  .setState(Task.State.OPEN)
  .setTrackingId("my-tracking-id")
  .setPlannedLocation(               // Grand Indonesia East Mall
    LocationInfo.newBuilder().setPoint(
      LatLng.newBuilder().setLatitude(-6.195139).setLongitude(106.820826)))
  .setTaskDuration(
    Duration.newBuilder().setSeconds(2 * 60))
  .build();

// Task request
CreateTaskRequest createTaskRequest =
  CreateTaskRequest.newBuilder()  // No need for the header
      .setParent(parent)          // Avoid using auto-incrementing IDs for the taskId
      .setTaskId("task-8241890")  // Task ID assigned by the Provider
      .setTask(task)              // Initial state
      .build();

// Error handling
// If Fleet Engine does not have a task with that ID and the credentials of the
// requestor pass, the service creates the task successfully.

try {
  Task createdTask = deliveryService.createTask(createTaskRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
     case ALREADY_EXISTS:
       break;
     case PERMISSION_DENIED:
       break;
  }
  return;
}

REST

要从服务器环境创建取货任务,请对“CreateTask”进行 HTTP REST 调用:

POST https://fleetengine.googleapis.com/v1/providers/<project_id>/tasks?taskId=<id>

<id> 是任务的唯一标识符。它不能是发货的跟踪编号。如果您的系统中没有任务 ID,可以生成通用唯一标识符 (UUID)。

请求标头必须包含字段 Authorization,其值为 Bearer <token>,其中 <token>Fleet Engine 令牌工厂发放的令牌

请求正文必须包含 Task 实体:

  • 必填字段:

    字段
    类型 类型:自提
    state 状态。OPEN
    trackingId 用于跟踪货运的编号或标识符。
    计划位置 需要完成任务的位置,在本例中为取货位置。
    taskDuration 取件地点取货所需的预计时间(以秒为单位)。

  • 可选字段:

在创建实体时,系统会忽略实体中的所有其他字段。如果请求包含已分配的 VehicleVehicleId,Fleet Engine 会抛出异常。您可以使用 UpdateVehicleRequests 分配任务。如需了解详情,请参阅将任务分配给车辆

curl 命令示例:

# Set $JWT, $PROJECT_ID, $TRACKING_ID, and $TASK_ID in the local
# environment
curl -X POST "https://fleetengine.googleapis.com/v1/providers/${PROJECT_ID}/tasks?taskId=${TASK_ID}" \
  -H "Content-type: application/json" \
  -H "Authorization: Bearer ${JWT}" \
  --data-binary @- << EOM
{
  "type": "PICKUP",
  "state": "OPEN",
  "trackingId": "${TRACKING_ID}",
  "plannedLocation": {
     "point": {
        "latitude": -6.195139,
        "longitude": 106.820826
     }
  },
  "taskDuration": "90s"
}
EOM

创建送货任务

您可以通过 Driver SDK 或服务器环境创建运单交付任务。

gRPC

以下示例展示了如何使用 Java gRPC 库创建运单交付任务:

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

DeliveryServiceBlockingStub deliveryService =
  DeliveryServiceGrpc.newBlockingStub(channel);

// Task settings
String parent = "providers/" + PROJECT_ID;
Task task = Task.newBuilder()
  .setType(Task.Type.DELIVERY)
  .setState(Task.State.OPEN)
  .setTrackingId("my-tracking-id")
  .setPlannedLocation(               // Grand Indonesia East Mall
    LocationInfo.newBuilder().setPoint(
      LatLng.newBuilder().setLatitude(-6.195139).setLongitude(106.820826)))
  .setTaskDuration(
    Duration.newBuilder().setSeconds(2 * 60))
  .build();

// Task request
CreateTaskRequest createTaskRequest =
  CreateTaskRequest.newBuilder()  // No need for the header
      .setParent(parent)          // Avoid using auto-incrementing IDs for the taskId
      .setTaskId("task-8241890")  // Task ID assigned by the Provider
      .setTask(task)              // Initial state
      .build();

// Error handling
// If Fleet Engine does not have task with that ID and the credentials of the
// requestor pass, the service creates the task successfully.

try {
  Task createdTask = deliveryService.createTask(createTaskRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
     case ALREADY_EXISTS:
       break;
     case PERMISSION_DENIED:
       break;
  }
  return;
}

REST

要从服务器环境创建运单交付任务,请对 `CreateTask' 进行 HTTP REST 调用:

POST https://fleetengine.googleapis.com/v1/providers/<project_id>/tasks?taskId=<id>

<id> 是任务的唯一标识符。它不能是发货的跟踪编号。如果您的系统中没有任务 ID,可以生成通用唯一标识符 (UUID)。

请求标头必须包含字段 Authorization,其值为 Bearer <token>,其中 <token>Fleet Engine 令牌工厂发放的令牌

请求正文必须包含 Task 实体:

  • 必填字段:

    字段
    类型 类型:DELIVERY
    state 状态。OPEN
    trackingId 用于跟踪货运的编号或标识符。
    计划位置 需要完成任务的位置,在本例中为此运单的投递位置。
    taskDuration 送货地点所需的预计送货时间(以秒为单位)。

  • 可选字段:

在创建实体时,系统会忽略实体中的所有其他字段。如果请求包含已分配的 VehicleVehicleId,Fleet Engine 会抛出异常。您可以使用 UpdateVehicleRequests 分配任务。如需了解详情,请参阅将任务分配给车辆

curl 命令示例:

# Set $JWT, $PROJECT_ID, $TRACKING_ID, and $TASK_ID in the local
# environment
curl -X POST "https://fleetengine.googleapis.com/v1/providers/${PROJECT_ID}/tasks?taskId=${TASK_ID}" \
  -H "Content-type: application/json" \
  -H "Authorization: Bearer ${JWT}" \
  --data-binary @- << EOM
{
  "type": "DELIVERY",
  "state": "OPEN",
  "trackingId": "${TRACKING_ID}",
  "plannedLocation": {
     "point": {
        "latitude": -6.195139,
        "longitude": 106.820826
     }
  },
  "taskDuration": "90s"
}
EOM

批量创建任务

您可以从服务器环境中创建一批任务。

gRPC

以下示例展示了如何使用 Java gRPC 库创建两个任务,一个用于送货,另一个用于在同一位置自提:

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

DeliveryServiceBlockingStub deliveryService =
  DeliveryServiceGrpc.newBlockingStub(channel);

// Delivery Task settings
Task deliveryTask = Task.newBuilder()
  .setType(Task.Type.DELIVERY)
  .setState(Task.State.OPEN)
  .setTrackingId("delivery-tracking-id")
  .setPlannedLocation(               // Grand Indonesia East Mall
    LocationInfo.newBuilder().setPoint(
      LatLng.newBuilder().setLatitude(-6.195139).setLongitude(106.820826)))
  .setTaskDuration(
    Duration.newBuilder().setSeconds(2 * 60))
  .build();

// Delivery Task request
CreateTaskRequest createDeliveryTaskRequest =
  CreateTaskRequest.newBuilder()  // No need for the header or parent fields
      .setTaskId("task-8312508")  // Task ID assigned by the Provider
      .setTask(deliveryTask)      // Initial state
      .build();

// Pickup Task settings
Task pickupTask = Task.newBuilder()
  .setType(Task.Type.PICKUP)
  .setState(Task.State.OPEN)
  .setTrackingId("pickup-tracking-id")
  .setPlannedLocation(               // Grand Indonesia East Mall
    LocationInfo.newBuilder().setPoint(
      LatLng.newBuilder().setLatitude(-6.195139).setLongitude(106.820826)))
  .setTaskDuration(
    Duration.newBuilder().setSeconds(2 * 60))
  .build();

// Pickup Task request
CreateTaskRequest createPickupTaskRequest =
  CreateTaskRequest.newBuilder()  // No need for the header or parent fields
      .setTaskId("task-8241890")  // Task ID assigned by the Provider
      .setTask(pickupTask)        // Initial state
      .build();

// Batch Create Tasks settings
String parent = "providers/" + PROJECT_ID;

// Batch Create Tasks request
BatchCreateTasksRequest batchCreateTasksRequest =
  BatchCreateTasksRequest.newBuilder()
      .setParent(parent)
      .addRequests(createDeliveryTaskRequest)
      .addRequests(createPickupTaskRequest)
      .build();

// Error handling
// If Fleet Engine does not have any task(s) with these task ID(s) and the
// credentials of the requestor pass, the service creates the task(s)
// successfully.

try {
  BatchCreateTasksResponse createdTasks = deliveryService.batchCreateTasks(
    batchCreateTasksRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
     case ALREADY_EXISTS:
       break;
     case PERMISSION_DENIED:
       break;
  }
  return;
}

REST

如需在服务器环境中创建传送和自提任务,请对 BatchCreateTasks 进行 HTTP REST 调用:

POST https://fleetengine.googleapis.com/v1/providers/<project_id>/tasks:batchCreate

请求标头必须包含字段 Authorization,其值为 Bearer <token>,其中 <token>Fleet Engine 令牌工厂发放的令牌

请求正文必须包含 BatchCreateTasksRequest 实体:

  • 必填字段:

    字段
    个请求 数组<CreateTasksRequest>

  • 可选字段:

    字段
    标头 投放请求标头

requests 中的每个 CreateTasksRequest 元素都必须通过与 CreateTask 请求相同的验证规则,但 parentheader 字段是可选的。如果设置此参数,它们必须与其在顶级 BatchCreateTasksRequest 中的字段完全相同。请参阅创建取货任务创建运单交付任务,以了解各项验证的特定规则。

如需了解详情,请参阅 BatchCreateTasks 的 API 参考文档(gRPCREST)。

curl 命令示例:

# Set $JWT, $PROJECT_ID, $DELIVERY_TRACKING_ID, $DELIVERY_TASK_ID,
# $PICKUP_TRACKING_ID, and $PICKUP_TASK_ID in the local environment
curl -X POST "https://fleetengine.googleapis.com/v1/providers/${PROJECT_ID}/tasks:batchCreate" \
  -H "Content-type: application/json" \
  -H "Authorization: Bearer ${JWT}" \
  --data-binary @- << EOM
{
  "requests" : [
    {
      "taskId": "${DELIVERY_TASK_ID}",
      "task" : {
        "type": "DELIVERY",
        "state": "OPEN",
        "trackingId": "${DELIVERY_TRACKING_ID}",
        "plannedLocation": {
          "point": {
              "latitude": -6.195139,
              "longitude": 106.820826
          }
        },
        "taskDuration": "90s"
      }
    },
    {
      "taskId": "${PICKUP_TASK_ID}",
      "task" : {
        "type": "PICKUP",
        "state": "OPEN",
        "trackingId": "${PICKUP_TRACKING_ID}",
        "plannedLocation": {
          "point": {
              "latitude": -6.195139,
              "longitude": 106.820826
          }
        },
        "taskDuration": "90s"
      }
    }
  ]
}
EOM

按计划不可用

您可以从 Driver SDK 或服务器环境创建指示不可用(例如,为驾驶中断或车辆补救)的任务。计划不可用任务不得包含跟踪 ID。您可以选择提供位置信息。

gRPC

以下示例展示了如何使用 Java gRPC 库创建不可用任务:

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

DeliveryServiceBlockingStub deliveryService =
  DeliveryServiceGrpc.newBlockingStub(channel);

// Task settings
String parent = "providers/" + PROJECT_ID;
Task task = Task.newBuilder()
  .setType(Task.Type.UNAVAILABLE)
  .setState(Task.State.OPEN)
  .setTaskDuration(
    Duration.newBuilder().setSeconds(60 * 60))  // 1hr break
  .build();

// Task request
CreateTaskRequest createTaskRequest =
  CreateTaskRequest.newBuilder()  // No need for the header
      .setParent(parent)          // Avoid using auto-incrementing IDs for the taskId
      .setTaskId("task-8241890")  // Task ID assigned by the Provider
      .setTask(task)              // Initial state
      .build();

// Error handling
// If Fleet Engine does not have task with that ID and the credentials of the
// requestor pass, the service creates the task successfully.

try {
  Task createdTask = deliveryService.createTask(createTaskRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
     case ALREADY_EXISTS:
       break;
     case PERMISSION_DENIED:
       break;
  }
  return;
}

REST

如需在服务器环境中创建不可用任务,请对 CreateTask 进行 HTTP REST 调用:

POST https://fleetengine.googleapis.com/v1/providers/<project_id>/tasks?taskId=<id>

<id> 是任务的唯一标识符。如果您的系统中没有任务 ID,可以生成通用唯一标识符 (UUID)。

请求标头必须包含字段 Authorization,其值为 Bearer <token>,其中 <token>Fleet Engine 令牌工厂发放的令牌

请求正文必须包含 Task 实体:

  • 必填字段:

    字段
    类型 类型:UNAVAILABLE
    state 状态。OPEN
    taskDuration 广告插播时长(以秒为单位)。

  • 选填字段:

    字段
    计划位置 休息时间(如果必须在具体位置拍摄)。

在创建实体时,系统会忽略实体中的所有其他字段。如果请求包含已分配的 VehicleVehicleId,Fleet Engine 会抛出异常。您可以使用 UpdateVehicleRequests 分配任务。如需了解详情,请参阅将任务分配给车辆

curl 命令示例:

# Set $JWT, $PROJECT_ID, and $TASK_ID in the local environment
curl -X POST "https://fleetengine.googleapis.com/v1/providers/${PROJECT_ID}/tasks?taskId=${TASK_ID}" \
  -H "Content-type: application/json" \
  -H "Authorization: Bearer ${JWT}" \
  --data-binary @- << EOM
{
  "type": "UNAVAILABLE",
  "state": "OPEN",
  "plannedLocation": {
     "point": {
        "latitude": -6.195139,
        "longitude": 106.820826
     }
  },
  "taskDuration": "300s"
}
EOM

预定的经停点

您可以通过 Driver SDK 或服务器环境创建预定的停止任务。预定停止任务不得包含跟踪 ID。

gRPC

以下示例展示了如何使用 Java gRPC 库创建计划停止任务:

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

DeliveryServiceBlockingStub deliveryService =
  DeliveryServiceGrpc.newBlockingStub(channel);

// Task settings
String parent = "providers/" + PROJECT_ID;
Task task = Task.newBuilder()
  .setType(Task.Type.SCHEDULED_STOP)
  .setState(Task.State.OPEN)
  .setPlannedLocation(               // Grand Indonesia East Mall
    LocationInfo.newBuilder().setPoint(
      LatLng.newBuilder().setLatitude(-6.195139).setLongitude(106.820826)))
  .setTaskDuration(
    Duration.newBuilder().setSeconds(2 * 60))
  .build();

// Task request
CreateTaskRequest createTaskRequest =
  CreateTaskRequest.newBuilder()  // No need for the header
      .setParent(parent)
      .setTaskId("task-8241890")  // Task ID assigned by the Provider
      .setTrip(task)              // Initial state
      .build();

// Error handling
// If Fleet Engine does not have task with that ID and the credentials of the
// requestor pass, the service creates the task successfully.

try {
  Task createdTask = deliveryService.createTask(createTaskRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
     case ALREADY_EXISTS:
       break;
     case PERMISSION_DENIED:
       break;
  }
  return;
}

REST

要从服务器环境创建预定停止任务,请对 `CreateTask' 进行 HTTP REST 调用:

POST https://fleetengine.googleapis.com/v1/providers/<project_id>/tasks?taskId=<id>

<id> 是任务的唯一标识符。如果您的系统中没有任务 ID,可以生成通用唯一标识符 (UUID)。

请求标头必须包含字段 Authorization,其值为 Bearer <token>,其中 <token>Fleet Engine 令牌工厂发放的令牌

请求正文必须包含 Task 实体:

  • 必填字段:

    字段
    类型 类型:SCHEDULED_STOP
    state 状态。OPEN
    计划位置 经停点的位置。
    taskDuration 停止站点的预期时长(以秒为单位)。

  • 可选字段:

在创建实体时,系统会忽略实体中的所有其他字段。如果请求包含已分配的 VehicleVehicleId,Fleet Engine 会抛出异常。您可以使用 UpdateVehicleRequests 分配任务。如需了解详情,请参阅将任务分配给车辆

curl 命令示例:

# Set $JWT, $PROJECT_ID, and $TASK_ID in the local environment
curl -X POST "https://fleetengine.googleapis.com/v1/providers/${PROJECT_ID}/tasks?taskId=${TASK_ID}" \
  -H "Content-type: application/json" \
  -H "Authorization: Bearer ${JWT}" \
  --data-binary @- << EOM
{
  "type": "SCHEDULED_STOP",
  "state": "OPEN",
  "plannedLocation": {
     "point": {
        "latitude": -6.195139,
        "longitude": 106.820826
     }
  },
  "taskDuration": "600s"
}
EOM

将任务分配给车辆

通过更新车辆的任务排序,将任务分配给车辆。车辆的任务顺序由送货车辆的车辆停靠列表确定。每个车辆停靠站都可以分配一个或多个任务。

更新之前分配给其他车辆的任务的任务排序会生成错误。

如需将车辆从一个车辆更改为另一个车辆,请先关闭原始任务,然后重新创建该任务,然后再为其分配新车辆。

更新任务排序

您可以通过驱动程序 SDK 或服务器环境更新分配给车辆的任务的执行顺序。这两种方法不得混用以避免竞态条件。

更新任务排序还会将任务分配给车辆(如果任务之前未分配给车辆),以及关闭之前分配给车辆的任务,但不在更新后的排序中。将任务分配给其他车辆时(如果任务之前已分配给其他车辆)就会生成错误。先关闭现有任务,然后创建新任务,然后再将其分配给新车辆。

任务排序可以随时更新。

gRPC

以下示例展示了如何使用 Java gRPC 库更新车辆的任务排序:

static final String PROJECT_ID = "my-delivery-co-gcp-project";
static final String VEHICLE_ID = "vehicle-8241890";
static final String TASK1_ID = "task-756390";
static final String TASK2_ID = "task-849263";

DeliveryServiceBlockingStub deliveryService =
  DeliveryServiceGrpc.newBlockingStub(channel);

// Vehicle settings
String vehicleName = "providers/" + PROJECT_ID + "/deliveryVehicles/" + VEHICLE_ID;
DeliveryVehicle deliveryVehicle = DeliveryVehicle.newBuilder()
    .addRemainingVehicleJourneySegments(VehicleJourneySegment.newBuilder()  // 1st stop
       .setStop(VehicleStop.newBuilder()
           .setPlannedLocation(LocationInfo.newBuilder()
               .setPoint(LatLng.newBuilder()
                   .setLatitude(37.7749)
                   .setLongitude(122.4194)))
           .addTasks(TaskInfo.newBuilder().setTaskId(TASK1_ID))
           .setState(VehicleStop.State.NEW)))
    .addRemainingVehicleJourneySegments(VehicleJourneySegment.newBuilder()  // 2nd stop
       .setStop(VehicleStop.newBuilder()
           .setPlannedLocation(LocationInfo.newBuilder()
               .setPoint(LatLng.newBuilder()
                   .setLatitude(37.3382)
                   .setLongitude(121.8863)))
           .addTasks(TaskInfo.newBuilder().setTaskId(TASK2_ID))
           .setState(VehicleStop.State.NEW)))
    .build();

// DeliveryVehicle request
UpdateDeliveryVehicleRequest updateDeliveryRequest =
  UpdateDeliveryVehicleRequest.newBuilder()  // No need for the header
      .setName(vehicleName)
      .setDeliveryVehicle(deliveryVehicle)
      .setUpdateMask(FieldMask.newBuilder().addPaths("remaining_vehicle_journey_segments"))
      .build();

// Error handling
// If Fleet Engine does not have task with that ID and the credentials of the
// requestor pass, the service creates the task successfully.

try {
  DeliveryVehicle updatedDeliveryVehicle =
      deliveryService.updateDeliveryVehicle(updateDeliveryVehicleRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
     case NOT_FOUND:
       break;
     case PERMISSION_DENIED:
       break;
  }
  return;
}

REST

如需从服务器环境更新车辆的任务排序,请对“UpdateDeliveryVehicle”进行 HTTP REST 调用:

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

<id> 是您车队中负责更新任务排序的送货车辆的唯一标识符。它是您在创建车辆时指定的标识符。

请求标头必须包含字段 Authorization,其值为 Bearer <token>,其中 <token>Fleet Engine 令牌工厂发放的令牌

请求正文必须包含 DeliveryVehicle 实体:

  • 必填字段:

    字段
    剩余车辆历程细分 任务的历程细分列表,按任务的执行顺序排列。 列表中的第一个任务最先执行。
    剩余车辆历程 [i].stop 任务 i 在列表中的停止位置。
    剩余车辆行程 [i].stop.plannedLocation 充电站的计划位置。
    剩余车辆行程 [i].stop.tasks 要在此车辆停靠站执行的任务列表。
    剩余车辆历程 [i].stop.state 省/自治区/直辖市

  • 可选字段:

对于更新操作,实体中的所有其他字段都会被忽略。

curl 命令示例:

# Set JWT, PROJECT_ID, VEHICLE_ID, TASK1_ID, and TASK2_ID in the local
# environment
curl -X PATCH "https://fleetengine.googleapis.com/v1/providers/${PROJECT_ID}/deliveryVehicles/${VEHICLE_ID}?updateMask=remainingVehicleJourneySegments" \
  -H "Content-type: application/json" \
  -H "Authorization: Bearer ${JWT}" \
  --data-binary @- << EOM
{
  "remainingVehicleJourneySegments": [
    {
      "stop": {
        "state": "NEW",
        "plannedLocation": {
          "point": {
            "latitude": 37.7749,
            "longitude": -122.084061
          }
        },
        "tasks": [
          {
            "taskId": "${TASK1_ID}"
          }
        ]
      }
    },
    {
      "stop": {
        "state": "NEW",
        "plannedLocation": {
          "point": {
            "latitude": 37.3382,
            "longitude": 121.8863
          }
        },
        "tasks": [
          {
            "taskId": "${TASK2_ID}"
          }
        ]
      }
    }
  ]
}
EOM

车辆正在前往下一站

当车辆离开站点或开始导航时,必须通知 Fleet Engine。您可以通过驱动程序 SDK 或服务器环境通知 Fleet Engine。这两种方法不得混用,以避免竞态条件和保持单一可信来源。

gRPC

以下示例展示了如何使用 Java gRPC 库通知 Fleet Engine 车辆正在前往下一站。

static final String PROJECT_ID = "my-delivery-co-gcp-project";
static final String VEHICLE_ID = "vehicle-8241890";

DeliveryServiceBlockingStub deliveryService =
  DeliveryServiceGrpc.newBlockingStub(channel);

// Vehicle settings
DeliveryVehicle deliveryVehicle = DeliveryVehicle.newBuilder()
    // Next stop marked as ENROUTE
    .addRemainingVehicleJourneySegments(VehicleJourneySegment.newBuilder()  // 1st stop
       .setStop(VehicleStop.newBuilder()
           .setPlannedLocation(LocationInfo.newBuilder()
               .setPoint(LatLng.newBuilder()
                   .setLatitude(37.7749)
                   .setLongitude(122.4194)))
           .addTasks(TaskInfo.newBuilder().setTaskId(TASK1_ID))
           .setState(VehicleStop.State.ENROUTE)))
    // All other stops marked as NEW
    .addRemainingVehicleJourneySegments(VehicleJourneySegment.newBuilder()  // 2nd stop
       .setStop(VehicleStop.newBuilder()
           .setPlannedLocation(LocationInfo.newBuilder()
               .setPoint(LatLng.newBuilder()
                   .setLatitude(37.3382)
                   .setLongitude(121.8863)))
           .addTasks(TaskInfo.newBuilder().setTaskId(TASK2_ID))
           .setState(VehicleStop.State.NEW)))
    .build();


// DeliveryVehicle request
UpdateDeliveryVehicleRequest updateDeliveryVehicleRequest =
  UpdateDeliveryVehicleRequest.newBuilder()  // No need for the header
      .setName(vehicleName)
      .setDeliveryVehicle(deliveryVehicle)
      .setUpdateMask(FieldMask.newBuilder().addPaths("remaining_vehicle_journey_segments"))
      .build();

// Error handling
// If Fleet Engine does not have task with that ID and the credentials of the
// requestor pass, the service creates the task successfully.

try {
  DeliveryVehicle updatedDeliveryVehicle =
      deliveryService.updateDeliveryVehicle(updateDeliveryVehicleRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
     case NOT_FOUND:
       break;
     case PERMISSION_DENIED:
       break;
  }
  return;
}

REST

如需通知 Fleet Engine 车辆正从服务器环境前往其下一站,将对 `UpdateDeliveryVehicle' 进行 HTTP REST 调用:

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

<id> 是您车队中要为其更新任务排序的送货车辆的唯一标识符。它是您在创建车辆时指定的标识符。

请求标头必须包含字段 Authorization,其值为 Bearer <token>,其中 <token>Fleet Engine 令牌工厂发放的令牌

请求正文必须包含 DeliveryVehicle 实体:

  • 必填字段:

    字段
    剩余车辆历程细分 剩余车辆停放的列表,其状态已标记为 State.NEW。 列表中的第一个停止点必须将其状态标记为 State.ENROUTE。

  • 可选字段:

实体中的所有其他字段都会被忽略。

curl 命令示例:

# Set JWT, PROJECT_ID, VEHICLE_ID, TASK1_ID, and TASK2_ID in the local
# environment
curl -X PATCH "https://fleetengine.googleapis.com/v1/providers/${PROJECT_ID}/deliveryVehicles/${VEHICLE_ID}?updateMask=remainingVehicleJourneySegments" \
  -H "Content-type: application/json" \
  -H "Authorization: Bearer ${JWT}" \
  --data-binary @- << EOM
{
  "remainingVehicleJourneySegments": [
    {
      "stop": {
        "state": "ENROUTE",
        "plannedLocation": {
          "point": {
            "latitude": 37.7749,
            "longitude": -122.084061
          }
        },
        "tasks": [
          {
            "taskId": "${TASK1_ID}"
          }
        ]
      }
    },
    {
      "stop": {
        "state": "NEW",
        "plannedLocation": {
          "point": {
            "latitude": 37.3382,
            "longitude": 121.8863
          }
        },
        "tasks": [
          {
            "taskId": "${TASK2_ID}"
          }
        ]
      }
    }
  ]
}
EOM

车辆到达停车点

车辆到达停车点时,必须通知舰队引擎。您可以通过驱动程序 SDK 或服务器环境通知 Fleet Engine。这两种方法不得混用,以避免竞态条件和保持单一可信来源。

gRPC

以下示例展示了如何使用 Java gRPC 库通知 Fleet Engine 车辆停靠在站:

static final String PROJECT_ID = "my-delivery-co-gcp-project";
static final String VEHICLE_ID = "vehicle-8241890";

DeliveryServiceBlockingStub deliveryService =
  DeliveryServiceGrpc.newBlockingStub(channel);

// Vehicle settings
String vehicleName = "providers/" + PROJECT_ID + "/deliveryVehicles/" + VEHICLE_ID;
DeliveryVehicle deliveryVehicle = DeliveryVehicle.newBuilder()
    // Marking the arrival at stop.
    .addRemainingVehicleJourneySegments(VehicleJourneySegment.newBuilder()
       .setStop(VehicleStop.newBuilder()
           .setPlannedLocation(LocationInfo.newBuilder()
               .setPoint(LatLng.newBuilder()
                   .setLatitude(37.7749)
                   .setLongitude(122.4194)))
           .addTasks(TaskInfo.newBuilder().setTaskId(TASK1_ID))
           .setState(VehicleStop.State.ARRIVED)))
    // All other remaining stops marked as NEW.
    .addRemainingVehicleJourneySegments(VehicleJourneySegment.newBuilder()  // 2nd stop
       .setStop(VehicleStop.newBuilder()
           .setPlannedLocation(LocationInfo.newBuilder()
               .setPoint(LatLng.newBuilder()
                   .setLatitude(37.3382)
                   .setLongitude(121.8863)))
           .addTasks(TaskInfo.newBuilder().setTaskId(TASK2_ID))
           .setState(VehicleStop.State.NEW))) // Remaining stops must be NEW.
    .build();

// DeliveryVehicle request
UpdateDeliveryVehicleRequest updateDeliveryVehicleRequest =
  UpdateDeliveryVehicleRequest.newBuilder()  // No need for the header
      .setName(vehicleName)
      .setDeliveryVehicle(deliveryVehicle)
      .setUpdateMask(FieldMask.newBuilder()
          .addPaths("remaining_vehicle_journey_segments"))
      .build();

// Error handling
// If Fleet Engine does not have task with that ID and the credentials of the
// requestor pass, the service creates the task successfully.

try {
  DeliveryVehicle updatedDeliveryVehicle =
      deliveryService.updateDeliveryVehicle(updateDeliveryVehicleRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
     case NOT_FOUND:
       break;
     case PERMISSION_DENIED:
       break;
  }
  return;
}

REST

若要通知 Fleet Engine 车辆从服务器环境到达,请对“UpdateDeliveryVehicle”进行 HTTP REST 调用:

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

<id> 是您车队中要为其更新任务排序的送货车辆的唯一标识符。它是您在创建车辆时指定的标识符。

请求标头必须包含字段 Authorization,其值为 Bearer <token>,其中 <token>Fleet Engine 令牌工厂发放的令牌

请求正文必须包含 DeliveryVehicle 实体:

  • 必填字段:

    字段
    剩余车辆历程细分 您到达的停车点,其状态设置为 State.ARRIVED,后跟剩余车辆状态的列表,其状态被标记为 State.NEW。

  • 可选字段:

对于更新操作,实体中的所有其他字段都会被忽略。

curl 命令示例:

# Set JWT, PROJECT_ID, VEHICLE_ID, TASK1_ID, and TASK2_ID in the local
# environment
curl -X PATCH "https://fleetengine.googleapis.com/v1/providers/${PROJECT_ID}/deliveryVehicles/${VEHICLE_ID}?updateMask=remainingVehicleJourneySegments" \
  -H "Content-type: application/json" \
  -H "Authorization: Bearer ${JWT}" \
  --data-binary @- << EOM
{
  "remainingVehicleJourneySegments": [
    {
      "stop": {
        "state": "ARRIVED",
        "plannedLocation": {
          "point": {
            "latitude": 37.7749,
            "longitude": -122.084061
          }
        },
        "tasks": [
          {
            "taskId": "${TASK1_ID}"
          }
        ]
      }
    },
    {
      "stop": {
        "state": "NEW",
        "plannedLocation": {
          "point": {
            "latitude": 37.3382,
            "longitude": 121.8863
          }
        },
        "tasks": [
          {
            "taskId": "${TASK2_ID}"
          }
        ]
      }
    }
  ]
}
EOM

车辆停下

车辆完成停车点时,必须通知 Fleet Engine。这会导致与停靠站关联的所有任务都设置为“关闭”状态。您可以通过驱动程序 SDK 或服务器环境通知 Fleet Engine。这两种方法不得混用,以避免竞态条件和保持单一可信来源。

gRPC

以下示例展示了如何使用 Java gRPC 库通知 Fleet Engine 车辆已完成停车。

static final String PROJECT_ID = "my-delivery-co-gcp-project";
static final String VEHICLE_ID = "vehicle-8241890";

DeliveryServiceBlockingStub deliveryService =
  DeliveryServiceGrpc.newBlockingStub(channel);

// Vehicle settings
String vehicleName = "providers/" + PROJECT_ID + "/deliveryVehicles/" + VEHICLE_ID;
DeliveryVehicle deliveryVehicle = DeliveryVehicle.newBuilder()
    // This stop has been completed and is commented out to indicate it
    // should be removed from the list of vehicle journey segments.
    // .addRemainingVehicleJourneySegments(VehicleJourneySegment.newBuilder()
    //    .setStop(VehicleStop.newBuilder()
    //        .setPlannedLocation(LocationInfo.newBuilder()
    //            .setPoint(LatLng.newBuilder()
    //                .setLatitude(37.7749)
    //                .setLongitude(122.4194)))
    //        .addTasks(TaskInfo.newBuilder().setTaskId(TASK1_ID))
    //        .setState(VehicleStop.State.ARRIVED)))
    // All other remaining stops marked as NEW.
    // The next stop could be marked as ENROUTE if the vehicle has begun
    // its journey to the next stop.
    .addRemainingVehicleJourneySegments(VehicleJourneySegment.newBuilder()  // Next stop
       .setStop(VehicleStop.newBuilder()
           .setPlannedLocation(LocationInfo.newBuilder()
               .setPoint(LatLng.newBuilder()
                   .setLatitude(37.3382)
                   .setLongitude(121.8863)))
           .addTasks(TaskInfo.newBuilder().setTaskId(TASK2_ID))
           .setState(VehicleStop.State.NEW)))
    .build();

// DeliveryVehicle request
UpdateDeliveryVehicleRequest updateDeliveryVehicleRequest =
  UpdateDeliveryVehicleRequest.newBuilder()  // no need for the header
      .setName(vehicleName)
      .setDeliveryVehicle(deliveryVehicle)
      .setUpdateMask(FieldMask.newBuilder()
          .addPaths("remaining_vehicle_journey_segments"))
      .build();

// Error handling
// If Fleet Engine does not have task with that ID and the credentials of the
// requestor pass, the service creates the task successfully.

try {
  DeliveryVehicle updatedDeliveryVehicle =
      deliveryService.updateDeliveryVehicle(updateDeliveryVehicleRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
     case NOT_FOUND:
       break;
     case PERMISSION_DENIED:
       break;
  }
  return;
}

REST

如需通知 Fleet Engine 来自服务器环境的停止已完成,请对 `UpdateDeliveryVehicle' 进行 HTTP REST 调用:

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

<id> 是您车队中要为其更新任务排序的送货车辆的唯一标识符。它是您在创建车辆时指定的标识符。

请求标头必须包含字段 Authorization,其值为 Bearer <token>,其中 <token>Fleet Engine 令牌工厂发放的令牌

请求正文必须包含 DeliveryVehicle 实体:

  • 必填字段:

    字段
    剩余车辆历程细分 您已完成的停车点不应再在其余车辆停止点列表中。

  • 可选字段:

对于更新操作,实体中的所有其他字段都会被忽略。

curl 命令示例:

# Set JWT, PROJECT_ID, VEHICLE_ID, TASK1_ID, and TASK2_ID in the local
# environment
curl -X PATCH "https://fleetengine.googleapis.com/v1/providers/${PROJECT_ID}/deliveryVehicles/${VEHICLE_ID}?updateMask=remainingVehicleJourneySegments" \
  -H "Content-type: application/json" \
  -H "Authorization: Bearer ${JWT}" \
  --data-binary @- << EOM
{
  "remainingVehicleJourneySegments": [
    {
      "stop": {
        "state": "NEW",
        "plannedLocation": {
          "point": {
            "latitude": 37.3382,
            "longitude": 121.8863
          }
        },
        "tasks": [
          {
            "taskId": "${TASK2_ID}"
          }
        ]
      }
    }
  ]
}
EOM

更新任务

大多数任务字段都是不可变的。不过,您可以通过直接更新任务实体来修改状态、任务结果、任务结果时间和任务结果位置。例如,如果任务未分配给车辆,则可以通过直接更新状态来关闭任务。

gRPC

这是一个通过 gRPC 更新任务的示例。

REST

这是一个通过 REST 更新任务的示例。

关闭任务

如需关闭已分配给车辆的任务,请通知 Fleet Engine 车辆已完成任务的停止位置,或将其从车辆停止列表中移除。为此,您可以设置剩余的车辆列表,就像为车辆更新任务排序一样。

如果任务尚未分配车辆且需要关闭,请将任务更新为“关闭”状态。不过,您无法重新打开已关闭的任务。

结束任务并不表示成功或失败。它表示任务不再被视为正在进行。对于物流跟踪,必须指明任务的实际结果,以便显示交付成果。

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) // It's only possible to directly CLOSE a
  .build();                    // task which 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();

// Error handling
// If Fleet Engine does not have task with that ID and the credentials of the
// requestor pass, the service creates the task successfully.

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

如需将任务标记为在服务器环境中关闭,请对 UpdateTask 进行 HTTP REST 调用:

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

<id> 是任务的唯一标识符

请求标头必须包含字段 Authorization,其值为 Bearer <token>,其中 <token>Fleet Engine 令牌工厂发放的令牌

请求正文必须包含 Task 实体:

  • 必填字段:

    字段
    state 状态。关闭

  • 选填字段:

    字段
    taskResult Outcome.SUCCEEDED 或 Outcome.FAILED
    taskResultTime 任务完成的时间。
    taskResultLocation 任务完成的位置。除非被提供方手动替换,否则 Fleet Engine 会将此位置默认为上一个车辆位置。

对于更新操作,实体中的所有其他字段都会被忽略。

curl 命令示例:

# 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 --iso-8601=seconds)"
}
EOM

设置任务结果和结果位置

关闭任务并不表示成功或失败,而是表明该任务已不再被视为正在进行。对于物流跟踪,必须指明任务的实际结果,以便可以显示交付结果并为服务提供适当的结算。设置后,任务结果无法更改。设置任务结果时间和任务结果后,可以对其进行修改。

处于“已关闭”状态的任务可以将其结果设置为“成功”或“失败”。Fleet Engine 仅对状态为“成功”的交付任务收费。

标记任务结果时,Fleet Engine 会自动使用最后已知的车辆位置填充任务结果位置。您可以替换此行为。

gRPC

您可以在设置结果时设置任务结果位置。这样将阻止 Fleet Engine 将其设置为上次使用车辆时的默认位置。您还可以覆盖 Fleet Engine 稍后设置的任务结果位置。Fleet Engine 绝不会覆盖您提供的任务结果位置。无法为未设置任务结果的任务设置任务结果位置。可以在同一个请求中同时设置任务结果和任务结果位置。

以下示例展示了如何使用 Java gRPC 库将任务结果设置为 SUCCEEDED,并设置完成任务的位置:

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();

// Error handling
// If Fleet Engine does not have task with that ID and the credentials of the
// requestor pass, the service creates the task successfully.

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

如需在服务器环境中将任务标记为已完成,请对 UpdateTask 进行 HTTP REST 调用:

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

<id> 是任务的唯一标识符

请求标头必须包含字段 Authorization,其值为 Bearer <token>,其中 <token>Fleet Engine 令牌工厂发放的令牌

请求正文必须包含 Task 实体:

  • 必填字段:

    字段
    taskResult Outcome.SUCCEEDED 或 Outcome.FAILED
    taskResultTime 设置任务结果的时间戳(来自提供方)。这是任务完成的时间。

  • 选填字段:

    字段
    taskResultLocation 任务完成的位置。除非被提供方手动替换,否则 Fleet Engine 会将此位置默认为上一个车辆位置。

对于更新操作,实体中的所有其他字段都会被忽略。

curl 命令示例:

# 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 --iso-8601=seconds)",
  "taskOutcomeLocation": {
    "point": {
      "latitude": -6.195139,
      "longitude": 106.820826
    }
  }
}
EOM

更改运单

货运任务创建后,便无法更改其计划位置。如需重新安排运单,请在不设置结果的情况下关闭配送任务,然后使用更新后的计划位置创建新任务。创建新任务后,将该任务分配给同一辆车辆。如需了解详情,请参阅关闭配送任务分配任务

使用喂食器和送货车辆

如果您使用喂食器车辆在一整天内将货物运输到送货车辆,请将运输作业模拟为送货车辆的计划停止任务。为了确保位置跟踪准确无误,请仅在将已发货的货物装入送货车辆后为其分配送货任务。如需了解详情,请参阅预定的停止

商店配送状态和其他元信息

发货任务完成后,任务状态和结果会记录在任务中。不过,您可能需要更新专门针对该运单的其他元信息。如需存储您可以在 Fleet Engine 服务之外引用的其他元信息,请使用与任务关联的 tracking_id 作为外部表中的键。

如需了解详情,请参阅任务的生命周期

查询车辆

您可以通过驱动程序 SDK 或服务器环境查找车辆。

gRPC

以下示例展示了如何使用 Java gRPC 库查找车辆:

static final String PROJECT_ID = "my-delivery-co-gcp-project";
static final String VEHICLE_ID = "vehicle-8241890";

DeliveryServiceBlockingStub deliveryService =
  DeliveryServiceGrpc.newBlockingStub(channel);

// Vehicle request
String name = "providers/" + PROJECT_ID + "/deliveryVehicles/" + VEHICLE_ID;
GetDeliveryVehicleRequest getVehicleRequest = GetDeliveryVehicleRequest.newBuilder()  // No need for the header
    .setName(name)
    .build();

try {
  DeliveryVehicle vehicle = deliveryService.getDeliveryVehicle(getVehicleRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
     case NOT_FOUND:
       break;
     case PERMISSION_DENIED:
       break;
  }
  return;
}

REST

如需在服务器环境中查找车辆,请对“GetVehicle”进行 HTTP REST 调用:

GET https://fleetengine.googleapis.com/v1/providers/<project_id>/deliveryVehicles/<vehicleId>

<id> 是任务的唯一标识符

<vehicleId> 是要查询的车辆的 ID。

请求标头必须包含字段 Authorization,其值为 Bearer <token>,其中 <token>Fleet Engine 令牌工厂发放的令牌

请求正文必须为空。

如果查询成功,则响应正文包含车辆实体。

curl 命令示例:

# Set JWT, PROJECT_ID, and VEHICLE_ID in the local environment
curl -H "Authorization: Bearer ${JWT}" \
  "https://fleetengine.googleapis.com/v1/providers/${PROJECT_ID}/deliveryVehicles/${VEHICLE_ID}"

查找任务

您可以在服务器环境中查找任务。Driver SDK 不支持查询任务。

gRPC

以下示例展示了如何使用 Java gRPC 库查找任务:

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

DeliveryServiceBlockingStub deliveryService =
  DeliveryServiceGrpc.newBlockingStub(channel);

// Task request
String taskName = "providers/" + PROJECT_ID + "/tasks/" + TASK_ID;
GetTaskRequest getTaskRequest = GetTaskRequest.newBuilder()  // No need for the header
    .setName(taskName)
    .build();

try {
  Task task = deliveryService.getTask(getTaskRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
     case NOT_FOUND:
       break;

     case PERMISSION_DENIED:
       break;
  }
  return;
}

REST

如需在服务器环境中查找任务,请对“GetTask”进行 HTTP REST 调用:

GET https://fleetengine.googleapis.com/v1/providers/<project_id>/tasks/<taskId>

<id> 是任务的唯一标识符

<taskId> 是要查找的任务的 ID。

请求标头必须包含字段 Authorization,其值为 Bearer <token>,其中 <token>Fleet Engine 令牌工厂发放的令牌

请求正文必须为空。

如果查询成功,则响应正文包含任务实体。

curl 命令示例:

# Set JWT, PROJECT_ID, and TASK_ID in the local environment
curl -H "Authorization: Bearer ${JWT}" \
  "https://fleetengine.googleapis.com/v1/providers/${PROJECT_ID}/tasks/${TASK_ID}"

根据跟踪 ID 查找送货任务信息

您可以通过以下方式查找运单任务信息,每种方式都有不同的用途:

  • 由任务 ID 指定:由有权访问任务数据完整视图的用户(例如舰队操作员)使用。
  • 通过跟踪 ID:供客户端软件用于向最终用户提供有限的信息(例如当包裹何时到达他们的家中)。

本部分介绍如何按跟踪 ID 查找任务信息。如果要按任务 ID 查找任务,请参阅查找任务

如需按跟踪 ID 查找信息,您可以使用以下任一方法:

查询要求

  • 跟踪 ID 提供的发货信息遵循控制所跟踪位置的可见性中规定的可见性规则。

  • 使用 Fleet Engine 按跟踪 ID 查找发货信息。Driver SDK 不支持按跟踪 ID 查找信息。若要使用 Fleet Engine 实现此目的,您将使用服务器环境或浏览器环境。

  • 使用尽可能窄的令牌来限制安全风险。例如,如果您使用交付使用方令牌,则任何 Fleet Engine Deliveries API 调用仅返回与该最终用户相关的信息,例如发货人或运单的接收者。响应中的所有其他信息都会被遮盖。 如需详细了解令牌,请参阅创建 JSON Web 令牌 (JWT) 以进行授权

使用 gRPC 的 Java 查找

以下示例展示了如何使用 Java gRPC 库按跟踪 ID 查找送货任务的相关信息。

static final String PROJECT_ID = "my-delivery-co-gcp-project";
static final String TRACKING_ID = "TID-7449w087464x5";

DeliveryServiceBlockingStub deliveryService =
  DeliveryServiceGrpc.newBlockingStub(channel);

// Tasks request
String parent = "providers/" + PROJECT_ID;
GetTaskTrackingInfoRequest getTaskTrackingInfoRequest = GetTaskTrackingInfoRequest.newBuilder()  // No need for the header
    .setParent(parent)
    .setTrackingId(TRACKING_ID)
    .build();

try {
  TaskTrackingInfo taskTrackingInfo = deliveryService.getTaskTrackingInfo(getTaskTrackingInfoRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
     case NOT_FOUND:
       break;

     case PERMISSION_DENIED:
       break;
  }
  return;
}

使用 HTTP 查找

如需在浏览器中查找运单任务,请对 GetTaskTrackingInfo 进行 HTTP REST 调用:

GET https://fleetengine.googleapis.com/v1/providers/<project_id>/taskTrackingInfo/<tracking_id>

<tracking_id> 是与任务关联的跟踪 ID。

请求标头必须包含字段 Authorization,其值为 Bearer <token>,其中 <token>Fleet Engine 令牌工厂发放的令牌

如果查找成功,则响应正文包含 taskTrackingInfo 实体。

curl 命令示例:

# Set JWT, PROJECT_ID, and TRACKING_ID in the local environment
curl -H "Authorization: Bearer ${JWT}" \
  "https://fleetengine.googleapis.com/v1/providers/${PROJECT_ID}/taskTrackingInfo/${TRACKING_ID}"

列出任务

您可以从服务器或浏览器环境列出任务。Driver SDK 不支持列出任务。

列出任务会请求对任务的广泛访问权限。列出任务仅适用于受信任的用户。发出列出任务请求时,请使用交付舰队读取器或传送超级用户身份验证令牌。

列出的任务会隐去以下字段:

  • 车辆停止位置
  • 车辆停止状态
  • VehicleStop.TaskInfo.taskId

列出的任务可以按大多数任务属性进行过滤。如需了解过滤器查询语法,请参阅 AIP-160。以下列表显示了可用于过滤的有效任务属性:

  • delivery_vehicle_id [配送 ID]
  • state
  • 计划位置
  • task_duration
  • task_outcome 任务
  • task_outee 位置
  • task_outcome_location_source
  • task_outcome_time 任务时间
  • 跟踪 ID
  • 类型

请根据 Google API 改进建议使用以下字段格式:

字段类型 格式 示例
时间戳 RFC-3339 task_outcome_time = 2022-03-01T11:30:00-08:00
时长 后跟“s”的秒数 task_duration = 120s
枚举 字符串 state = CLOSED AND type = PICKUP
位置 point.latitudepoint.longitude planned_location.point.latitude > 36.1 AND planned_location.point.longitude < -122.0

如需查看过滤器查询运算符的完整列表,请参阅 AIP-160

如果未指定过滤器查询,则系统会列出所有任务。

任务列表已分页。页面大小请求可在列表任务请求中指定。 如果指定了页面大小,则返回的任务数不会大于指定的页面大小。如果未提供页面大小,则使用合理的默认值。如果请求的页面大小超过内部最大值,则使用内部最大值。

任务列表可以包含用于读取下一页结果的令牌。将页面令牌用于与上一个请求相同的请求,以检索下一页任务。当返回的页面令牌为空时,没有其他任务可检索。

gRPC

以下示例展示了如何使用 Java gRPC 库列出 deliveryVehicleId 的任务。成功的响应仍然可以为空。空响应表示没有与提供的 VehicleVehicleId 关联的任务。

static final String PROJECT_ID = "my-delivery-co-gcp-project";
static final String TRACKING_ID = "TID-7449w087464x5";

DeliveryServiceBlockingStub deliveryService =
  DeliveryServiceGrpc.newBlockingStub(channel);

// Tasks request
String parent = "providers/" + PROJECT_ID;
ListTasksRequest listTasksRequest = ListTasksRequest.newBuilder()  // No need for the header
    .setParent(parent)
    .setFilter("delivery_vehicle_id = 123")
    .build();

try {
  ListTasksResponse listTasksResponse = deliveryService.listTasks(listTasksRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
     case NOT_FOUND:
       break;

     case PERMISSION_DENIED:
       break;
  }
  return;
}

REST

如需通过浏览器列出任务,请对 ListTasks 进行 HTTP REST 调用:

GET https://fleetengine.googleapis.com/v1/providers/<project_id>/tasks

要对列出的任务应用过滤器,请添加“过滤器”网址参数,并将网址转义的过滤器查询作为其值。

请求标头必须包含字段 Authorization,其值为 Bearer <token>,其中 <token>Fleet Engine 令牌工厂发放的令牌

如果查询成功,则响应正文包含具有以下结构的数据:

// JSON representation
{
  "tasks": [
    {
      object (Task)
    }
  ],
  "nextPageToken": string,
  "totalSize": integer
}

成功的响应仍然可以为空。空响应表示未找到符合指定过滤条件的任务。

curl 命令示例:

# Set JWT, PROJECT_ID, and VEHICLE_ID in the local environment
curl -H "Authorization: Bearer ${JWT}" \
  "https://fleetengine.googleapis.com/v1/providers/${PROJECT_ID}/tasks?filter=state%20%3D%20OPEN%20AND%20delivery_vehicle_id%20%3D%20${VEHICLE_ID}"

列出送货车辆

您可以从服务器或浏览器环境中列出送货车辆。Driver SDK 不支持列出送货车辆。

列出送货工具申请的是送货工具的广泛使用权限,且仅适用于可信用户。发出列表交车请求时,可以使用交货舰队读取卡或投递超级用户身份验证令牌。

由于列出的车辆会对响应大小产生影响,因此以下字段会被隐去:

  • 当前路线段
  • RemainingVehicleJourneySegments

您可以按attributes属性过滤通过列表列出的车辆。例如,如需查询键为 my_key 且值为 my_value 的属性,请使用 attributes.my_key = my_value。如需查询多个属性,请使用 ANDOR 运算符(如 attributes.key1 = value1 AND attributes.key2 = value2)所示联接查询。如需查看过滤器查询语法的完整说明,请参阅 AIP-160

您可以使用 viewport 请求参数,按位置过滤列出的送货车辆。viewport 请求参数使用两个边界坐标来定义视口:high(东北)和 low(西南)纬度/经度。如果请求包含从地理位置上低于低纬度的高纬度,则请求会被拒绝。

默认情况下,系统会使用合理的页面大小对配送车辆列表进行分页。如果您指定页面大小,该请求仅会返回该限制指定的车辆数量,或返回较少数量。如果请求的页面大小超过内部最大值,则使用内部最大值。默认页面大小和页面大小上限都是 100 辆车。

送货车辆列表可以包含用于读取下一页结果的令牌。仅当有更多的车辆可检索时,响应中才会包含页面令牌。如需检索下一页任务,请使用页面令牌以及以其他方式与上一个请求相同的请求。

gRPC

以下示例展示了如何使用 Java gRPC 库列出具有特定特性的特定区域的送货车辆。成功的响应仍然可以为空。如果发生这种情况,这意味着目前在指定视口中没有具有指定属性的车辆。

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

DeliveryServiceBlockingStub deliveryService =
  DeliveryServiceGrpc.newBlockingStub(channel);

// Tasks request
String parent = "providers/" + PROJECT_ID;
ListDeliveryVehiclesRequest listDeliveryVehiclesRequest =
  ListDeliveryVehiclesRequest.newBuilder()  // No need for the header
      .setParent(parent)
      .setViewport(
            Viewport.newBuilder()
              .setHigh(LatLng.newBuilder()
                  .setLatitude(37.45)
                  .setLongitude(-122.06)
                  .build())
              .setLow(LatLng.newBuilder()
                  .setLatitude(37.41)
                  .setLongitude(-122.11)
                  .build())
      .setFilter("attributes.my_key = my_value")
      .build();

try {
  ListDeliveryVehiclesResponse listDeliveryVehiclesResponse =
      deliveryService.listDeliveryVehicles(listDeliveryVehiclesRequest);
} catch (StatusRuntimeException e) {
  Status s = e.getStatus();
  switch (s.getCode()) {
      case NOT_FOUND:
          break;

      case PERMISSION_DENIED:
          break;
  }
  return;
}

REST

如需通过浏览器列出任务,请对 ListDeliveryVehicles 进行 HTTP REST 调用:

GET https://fleetengine.googleapis.com/v1/providers/<project_id>/deliveryVehicles

要对列出的任务应用过滤器,请添加“过滤器”网址参数,并将网址转义的过滤器查询作为其值。

请求标头必须包含字段 Authorization,其值为 Bearer <token>,其中 <token>Fleet Engine 令牌工厂发放的令牌

如果查询成功,则响应正文包含具有以下结构的数据:

// JSON representation
{
  "deliveryVehicles": [
    {
      object (DeliveryVehicle)
    }
  ],
  "nextPageToken": string,
  "totalSize": integer
}

成功的响应仍然可以为空。如果发生这种情况,这意味着没有找到符合指定过滤条件查询和视口的送货工具。

curl 命令示例:

# Set JWT, PROJECT_ID, and VEHICLE_ID in the local environment
curl -H "Authorization: Bearer ${JWT}" \
  "https://fleetengine.googleapis.com/v1/providers/${PROJECT_ID}/deliveryVehicles?filter=attributes.my_key%20%3D%20my_value%20&viewport.high.latitude=37.45&viewport.high.longitude=-122.06&viewport.low.latitude=37.41&viewport.low.longitude=-122.11"

货运跟踪

您可以通过以下两种方式使用 Fleet Engine Deliveryies API 启用物流跟踪:

  • 首选:使用 JavaScript 物流跟踪库。借助该库,您可以直观呈现 Fleet Engine 中跟踪的车辆位置以及感兴趣的位置。它包含一个用于直接替换标准 google.maps.Map 对象的 JavaScript 地图组件,以及用于与 Fleet Engine 连接的数据组件。这样,您就可以通过 Web 应用或移动应用提供可自定义的动画配送跟踪体验。

  • 在 Fleet Engine Deliveries API 的基础上实现您自己的物流跟踪。 关键在于按跟踪 ID 查找送货任务

如果您使用交付消费者角色,则任何 Fleet Engine Deliveries API 调用仅返回与发货方或接收者相关的信息。响应中的所有其他信息都会被遮盖。您负责验证最终用户。此外,系统将根据当前正在执行的任务过滤位置信息。在不可用任务期间,系统不会与最终用户分享任何位置信息。

日志记录

您可以启用一个选项,以允许 Fleet Engine 将 RPC 日志发送到 Cloud Logging。如需了解详情,请参阅 Logging

授权角色和令牌

集成 Deliveries API 及针对个别用例的授权说明中所述,调用 Fleet Engine 需要使用通过服务帐号凭据签名的 JSON Web 令牌进行身份验证。用于创建这些令牌的服务帐号可以具有一个或多个角色,每个角色授予一组不同的权限。

如需了解详情,请参阅身份验证和授权

问题排查

弹性

Fleet Engine 并非可信来源。如有必要,您需负责恢复系统的状态,而不依赖于 Fleet Engine。

Fleet Engine 中丢失状态

使用 Fleet Engine 时,请实现客户端,以便在发生故障时系统自行修复。例如,当 Fleet Engine 尝试更新车辆时,可能会返回一条错误消息,指明该车辆不存在。然后,客户端应在新状态下重新创建车辆。这种情况很少发生,系统必须具有弹性,以防发生故障。

在极不可能发生 Fleet Engine 灾难性故障的情况下,您可能需要重新创建大多数或所有车辆和任务。如果创建速率变得过高,则某些请求可能会由于配额问题而再次失败,因为已实施配额检查,以避免拒绝服务 (DOS) 攻击。在这种情况下,可以使用退避策略来重试,从而降低重新创建速度。

驱动程序应用中的丢失状态

如果驱动程序应用崩溃,则必须在驱动程序 SDK 中重新创建当前状态。应用应尝试重新创建任务,以确保它们存在并恢复其当前状态。应用还应为 Driver SDK 重新创建并明确设置经停点列表。

请注意,这些恢复必须自主完成,而且无需依赖 Fleet Engine 提供的信息,只是有错误指出数据库中是否已存在某个实体。如果实体已经存在,则可以吸收该错误,并且可以使用其 ID 更新该实体。

常见问题解答

如果驾驶员因异常而停止操作,会发生什么情况?

在这种情况下,您应先更新任务的顺序,然后照常继续,标记到达到达点和完成任务等。否则,系统可能会变得不一致。加大型文字广告可能会变得不正确,并且可能会报告意外错误。