Managing Customers#

Every Customer who wants to use MOIA’s Mobility Service needs to be registered in the Trip API. The Ridepooling Service uses the Customer data to address the Customer during different parts of the Trip or to contact them if something goes wrong.

Create the Client#

customerClient := customerv1.NewCustomerServiceClient(conn)
  const client = clientFactory.create(CustomerServiceDefinition, channel);
trait CustomerService:
  def createCustomer(): Task[String]
  def getCustomer(customerId: String): Task[Customer]
  def listCustomers(pageSize: Int): Task[Seq[Customer]]
  def updateCustomer(customer: Customer): Task[Customer]
  def addCustomerFlag(customerId: String, flag: String): Task[Unit]
  def removeCustomerFlag(customerId: String, flag: String): Task[Unit]
  def listCustomerFlags(customerId: String): Task[Seq[String]]
  def deleteCustomer(customerId: String): Task[Unit]

Creating a Customer#

When creating a Customer the Customer object is returned including the generated Customer id. This Customer id is essential for all further interactions related to a Customer. This includes but is not limited to updating a Customer or ordering an Offer for a Trip.

Important

There is no restriction on the uniqueness of any Customer properties except the id. And since the id is generated by the Customer Service multiple requests with the same Customer data will result in the creation of multiple Customers with different ids.

The following example details a CreateCustomerRequest to create a new Customer.

grpcurl \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -import-path ./protos/ \
  -proto "moia/trip/customer/v1/customer.proto" \
  -proto "google/rpc/error_details.proto" \
  -d "{\"email_address\":\"test-customer@moia.io\",\"family_name\":\"Customer\",\"given_name\":\"Test\",\"language_code\":\"en\",\"phone_number\":\"+4997259173740\"}" \
  "$API_URL" moia.trip.customer.v1.CustomerService/CreateCustomer
customer, err := customerClient.CreateCustomer(ctx, &customerv1.CreateCustomerRequest{
	EmailAddress: "test-customer@moia.io",
	FamilyName:   "Customer",
	GivenName:    "Test",
	LanguageCode: "en",
	PhoneNumber:  "+4997259173740",
})
if err != nil {
	log.Fatalf("Could not create customer: %v", err)
}
log.Printf("Successfully created customer: %v", jsonMarshalOptions.Format(customer))
  const customer = await client.createCustomer({
    emailAddress: "test-customer@moia.io",
    familyName: "Customer",
    givenName: "Test",
    languageCode: "en",
    phoneNumber: "+4997259173740",
  });
  console.log(
    "Successfully created customer:",
    JSON.stringify(customer, null, 2),
  );
def createCustomer(): Task[String] = ZIO.scoped:
  for
    accessToken    <- tokenManager.getAccessToken()
    authMetadata    = GrpcClientService.createAuthMetadata(accessToken)
    customerClient <- ZioCustomer.CustomerServiceClient.scoped(managedChannel, metadata = authMetadata)
    createRequest   = CreateCustomerRequest(
                        emailAddress = "test@example.com",
                        phoneNumber = "+4930726219941",
                        givenName = "Test",
                        familyName = "Customer",
                        languageCode = "en"
                      )
    response       <- customerClient.createCustomer(createRequest)
    customerId     <- ZIO
                        .fromOption(response.customer.map(_.id))
                        .mapError(_ => new Throwable("Customer creation failed - no customer returned"))
    _              <- ZIO.logInfo(s"Successfully created customer: $customerId")
  yield customerId

Listing all Customers#

To get all Customers, we can request them using the ListCustomers RPC.

This method returns a paginated list of Customers. When the next_page_token is set in the response, passing this token as page_token in the next request will return the next page of Customers.

Is the next_page_token not set in the response, we have reached the last page of Customers. The next_page_token should be considered as an opaque token and should not be interpreted in any way.

The following example details a ListCustomersRequest to get existing Customers through paginated requests.

grpcurl \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -import-path ./protos/ \
  -proto "moia/trip/customer/v1/customer.proto" \
  -proto "google/rpc/error_details.proto" \
  -d "{\"page_size\":5}" \
  "$API_URL" moia.trip.customer.v1.CustomerService/ListCustomers
pageSize := int32(5)

listCustomersResponse, err := customerClient.ListCustomers(ctx, &customerv1.ListCustomersRequest{
	PageSize: &pageSize,
})
if err != nil {
	log.Fatalf("Could not list customers: %v", err)
}
log.Printf("Successfully listed %d customers", len(listCustomersResponse.Customers))
  const listCustomersResponse = await client.listCustomers({
    pageSize: 5,
  });
  console.log(
    `Successfully listed ${listCustomersResponse.customers.length} customers`,
  );
def listCustomers(pageSize: Int): Task[Seq[Customer]] = ZIO.scoped:
  for
    accessToken    <- tokenManager.getAccessToken()
    authMetadata    = GrpcClientService.createAuthMetadata(accessToken)
    customerClient <- ZioCustomer.CustomerServiceClient.scoped(managedChannel, metadata = authMetadata)
    listRequest     = ListCustomersRequest(pageSize = Some(pageSize))
    response       <- customerClient.listCustomers(listRequest)
    _              <- ZIO.logInfo(s"Successfully listed ${response.customers.length} customers")
  yield response.customers

Deleting a Customer#

For deleting a Customer the DeleteCustomer RPC is used.

When a Customer is deleted while having an active Trip, the Customer will be able to finish the Trip. But the Customer will not be able to order any new Trips.

The following example details a DeleteCustomerRequest to delete an existing Customer.

# export CUSTOMER_ID="<replace with customer id>"

grpcurl \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -import-path ./protos/ \
  -proto "moia/trip/customer/v1/customer.proto" \
  -proto "google/rpc/error_details.proto" \
  -d "{\"id\":\"${CUSTOMER_ID}\"}" \
  "$API_URL" moia.trip.customer.v1.CustomerService/DeleteCustomer
_, err = customerClient.DeleteCustomer(ctx, &customerv1.DeleteCustomerRequest{
	Id: customer.Customer.Id,
})
if err != nil {
	log.Fatalf("Could not delete customer: %v", err)
}
log.Printf("Successfully removed customer with id %s", customer.Customer.Id)
  await client.deleteCustomer({ id: customer.customer?.id });
  console.log(
    `Successfully removed customer with id ${customer.customer?.id}`,
  );
def deleteCustomer(customerId: String): Task[Unit] = ZIO.scoped:
  for
    accessToken    <- tokenManager.getAccessToken()
    authMetadata    = GrpcClientService.createAuthMetadata(accessToken)
    customerClient <- ZioCustomer.CustomerServiceClient.scoped(managedChannel, metadata = authMetadata)
    deleteRequest   = DeleteCustomerRequest(id = customerId)
    _              <- customerClient.deleteCustomer(deleteRequest)
    _              <- ZIO.logInfo(s"Successfully deleted customer: $customerId")
  yield ()

Managing Customer Flags#

The flags of a Customer can be managed through the AddCustomerFlag RPC and RemoveCustomerFlag RPC. A Customer’s currently set flags are returned by the ListCustomerFlags RPC.

For more information about Customer flags, please refer to the Customer flags fundamentals.

The following example details an AddCustomerFlagRequest to attach a flag to an existing Customer.

# export CUSTOMER_ID="<replace with customer id>"
# export CUSTOMER_FLAG="<replace with customer flag>"

grpcurl \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -import-path ./protos/ \
  -proto "moia/trip/customer/v1/customer.proto" \
  -proto "google/rpc/error_details.proto" \
  -d "{\"customer_id\":\"${CUSTOMER_ID}\",\"flag\":\"${CUSTOMER_FLAG}\"}" \
  "$API_URL" moia.trip.customer.v1.CustomerService/AddCustomerFlag
addCustomerFlagResponse, err := customerClient.AddCustomerFlag(ctx, &customerv1.AddCustomerFlagRequest{
	CustomerId: customer.Customer.Id,
	// replace `customerFlag` with the customer flag to be added to the customer
	Flag: customerFlag,
})
if err != nil {
	log.Fatalf("Could not add customer flag: %v", err)
}
log.Printf("Successfully added customer flag: %v", jsonMarshalOptions.Format(addCustomerFlagResponse))
  const addCustomerFlagResponse = await client.addCustomerFlag({
    customerId: customer.customer?.id,
    // replace `customerFlag` with the customer flag to be added to the customer
    flag: customerFlag,
  });
  console.log(
    "Successfully added customer flag:",
    JSON.stringify(addCustomerFlagResponse, null, 2),
  );
def addCustomerFlag(customerId: String, flag: String): Task[Unit] = ZIO.scoped:
  for
    accessToken    <- tokenManager.getAccessToken()
    authMetadata    = GrpcClientService.createAuthMetadata(accessToken)
    customerClient <- ZioCustomer.CustomerServiceClient.scoped(managedChannel, metadata = authMetadata)
    addFlagRequest  = AddCustomerFlagRequest(customerId = customerId, flag = flag)
    _              <- customerClient.addCustomerFlag(addFlagRequest)
    _              <- ZIO.logInfo(s"Successfully added flag '$flag' to customer: $customerId")
  yield ()

The following example details a RemoveCustomerFlagRequest to remove a flag from an existing Customer.

# export CUSTOMER_ID="<replace with customer id>"
# export CUSTOMER_FLAG="<replace with customer flag>"

grpcurl \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -import-path ./protos/ \
  -proto "moia/trip/customer/v1/customer.proto" \
  -proto "google/rpc/error_details.proto" \
  -d "{\"customer_id\":\"${CUSTOMER_ID}\",\"flag\":\"${CUSTOMER_FLAG}\"}" \
  "$API_URL" moia.trip.customer.v1.CustomerService/RemoveCustomerFlag
_, err = customerClient.RemoveCustomerFlag(ctx, &customerv1.RemoveCustomerFlagRequest{
	CustomerId: customer.Customer.Id,
	// replace `customerFlag` with the customer flag to be removed from the customer
	Flag: customerFlag,
})
if err != nil {
	log.Fatalf("Could not remove customer flag: %v", err)
}
log.Printf("Successfully removed customer flag: %s", customerFlag)
  await client.removeCustomerFlag({
    customerId: customer.customer?.id,
    // replace `customerFlag` with the customer flag to be removed from the customer
    flag: customerFlag,
  });
  console.log("Successfully removed customer flag:", customerFlag);
def removeCustomerFlag(customerId: String, flag: String): Task[Unit] = ZIO.scoped:
  for
    accessToken      <- tokenManager.getAccessToken()
    authMetadata      = GrpcClientService.createAuthMetadata(accessToken)
    customerClient   <- ZioCustomer.CustomerServiceClient.scoped(managedChannel, metadata = authMetadata)
    removeFlagRequest = RemoveCustomerFlagRequest(customerId = customerId, flag = flag)
    _                <- customerClient.removeCustomerFlag(removeFlagRequest)
    _                <- ZIO.logInfo(s"Successfully removed flag '$flag' from customer: $customerId")
  yield ()

The following example details a ListCustomerFlagsRequest to read the flags of an existing Customer.

# export CUSTOMER_ID="<replace with customer id>"

grpcurl \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -import-path ./protos/ \
  -proto "moia/trip/customer/v1/customer.proto" \
  -proto "google/rpc/error_details.proto" \
  -d "{\"customer_id\":\"${CUSTOMER_ID}\",\"page_size\":5}" \
  "$API_URL" moia.trip.customer.v1.CustomerService/ListCustomerFlags
listCustomerFlagsResponse, err := customerClient.ListCustomerFlags(ctx, &customerv1.ListCustomerFlagsRequest{
	CustomerId: customer.Customer.Id,
})
if err != nil {
	log.Fatalf("Could not list customer flags: %v", err)
}
log.Printf("Successfully listed %d customer flags", len(listCustomerFlagsResponse.Flags))
  const listCustomerFlagResponse = await client.listCustomerFlags({
    customerId: customer.customer?.id,
  });
  console.log(
    `Successfully listed ${listCustomerFlagResponse.flags.length} customer flags`,
  );
def listCustomerFlags(customerId: String): Task[Seq[String]] = ZIO.scoped:
  for
    accessToken     <- tokenManager.getAccessToken()
    authMetadata     = GrpcClientService.createAuthMetadata(accessToken)
    customerClient  <- ZioCustomer.CustomerServiceClient.scoped(managedChannel, metadata = authMetadata)
    listFlagsRequest = ListCustomerFlagsRequest(customerId = customerId)
    response        <- customerClient.listCustomerFlags(listFlagsRequest)
    _               <- ZIO.logInfo(s"Successfully listed ${response.flags.length} flags for customer: $customerId")
  yield response.flags