Initial push of API v3 test utility.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..94809b7 --- /dev/null +++ b/CONTRIBUTING.md
@@ -0,0 +1,2 @@ +Unfortunately, given the nature of the tools provided here, we do not +accept contributions.
diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7a4a3ea --- /dev/null +++ b/LICENSE
@@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file
diff --git a/README.md b/README.md new file mode 100644 index 0000000..5cf8846 --- /dev/null +++ b/README.md
@@ -0,0 +1,133 @@ +# Maps Booking + +This repo contains tools and code samples for partners that wish to integrate +with [Reserve](https://www.google.com/maps/reserve/) API v3. + +## Testing Client + +Before using the test utility, the Go programming language must be installed +on your workstation. A precompiled Go binary for your operating system can +be [found here](https://golang.org/dl/) + +This guide will assume you're using the default GOPATH and subsequent GOBIN. +For a comprehensive explanation of the GOPATH env variable please see +[this document](https://golang.org/dl/) by the Go team. + +### Installing the utility with Linux + +First, build your Go directory structure. A comprehensive guide on the intended +structure of Go code can be [found here.](https://golang.org/doc/code.html) + + mkdir -p $HOME/go/bin $HOME/go/pkg $HOME/go/src/github.com/maps-booking + +Next, add the following to your ~/.bashrc + + export PATH=$PATH:$(go env GOPATH)/bin + export GOPATH=$(go env GOPATH) + export GOBIN=$(go env GOPATH)/bin + +Source changes + + source ~/.bashrc + +Next, retrieve the utility from the +[maps-booking repository](https://maps-booking.googlesource.com/) + + git clone https://maps-booking.googlesource.com/test_client $HOME/go/src/github.com/maps-booking/ + +Lastly, download all dependencies and install the tool. + + cd $HOME/go + go get -d ./... + go install $HOME/go/src/github.com/maps-booking/testclient/main.go + +### Installing the utility with Windows Powershell + +First, build your Go directory structure. A comprehensive guide on the intended +structure of Go code can be [found here.](https://golang.org/doc/code.html) + + $env:HOME = $env:USERPROFILE + md $env:HOME\go\bin + md $env:HOME\go\pkg + md $env:HOME\go\src\github.com\maps-booking + +Next, set the appropriate environment variables + + $env:PATH = $env:PATH + ";" + (go env GOPATH) + "\bin" + $env:GOPATH = (go env GOPATH) + $env:GOBIN = (go env GOPATH) + "\bin" + +Next, retrieve the utility from the +[maps-booking repository](https://maps-booking.googlesource.com/) + + git clone https://maps-booking.googlesource.com/test_client $env:HOME\go\src\github.com\maps-booking\ + +Lastly, download all dependencies and install the tool. + + cd $env:HOME\go + go get -d .\... + go install $env:HOME\go\src\github.com\maps-booking\testclient\main.go + +### Using the utility + +After following the install steps above an executable should now live in + + $HOME/go/bin/main + +or + + $env:HOME\go\bin\main.exe + +All available flags can be displayed using the '--help' flag. The currently +accepted flags are: + + -all_tests + Whether to test all endpoints. + -availability_feed string + Absolute path to availability feed required for all tests except health. + Feeds can be in either json or pb3 format + -booking_status_test + Whether to test the GetBookingStatus endpoint. + -booking_test + Whether to test the CreateBooking endpoint. + -ca_file string + Absolute path to your server's Certificate Authority root cert. + Downloading all roots currently recommended by the Google Internet + Authority is a suitable alternative https://pki.google.com/roots.pem + -cancel_all_bookings + This option assumes that the ListBookings and UpdateBooking endpoints + are fully functional. This is a convenience flag for purging your system + of all previously created bookings. + -check_availability_test + Whether to test the CheckAvailability endpoint. + -health_check_test + Whether to test the Health endpoint. + -list_bookings_test + Whether to test the ListBookings endpoint + -num_test_slots int + Maximum number of slots to test from availability_feed. Slots will be + selected randomly (default 10) + -output_dir string + Absolute path of dir to dump log file. + -rescheduling_test + Whether to test the UpdateBooking endpoint. + -server_addr string + Your http server's address in the format of host:port + (default "example.com:80") + -username_password string + (eg 'username:password') credentials for your server. Leave blank to bypass authentication. + +Example Usage: + + bin/main -health_check_test=true -check_availability_test=true + -output_dir="/tmp" -server_addr="http-service.google.com:50051” + -availability_feed="/tmp/test.json" + +### Parsing the output + +The test utility will output a file with the prefix 'http_test_client_log_' +followed by a timestamp in RFC3339 format. The output file contains a +complete log of all Requests and Responses sent/received by the testing tool as +well as diffs of the expected response in the event of errors. +Similar to a compiler, an overview of the entire run can be found at the end +of the file for user friendly digestion.
diff --git a/api/api.go b/api/api.go new file mode 100644 index 0000000..56d518f --- /dev/null +++ b/api/api.go
@@ -0,0 +1,368 @@ +/* +Copyright 2017 Google Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package api contains validation wrappers over BookingService endpoints. +package api + +import ( + "bytes" + "encoding/base64" + "errors" + "fmt" + "log" + "math/rand" + "net/http" + "sort" + "strconv" + "time" + + "github.com/golang/protobuf/jsonpb" + "github.com/golang/protobuf/proto" + "github.com/google/go-cmp/cmp" + "github.com/maps-booking/utils" + + fpb "github.com/maps-booking/feeds" + mpb "github.com/maps-booking/v3" +) + +const ( + userID = "0" + firstName = "Jane" + lastName = "Doe" + telephone = "+18007897890" + email = "test@example.com" +) + +// HTTPConnection is a convenience struct for holding connection-related objects. +type HTTPConnection struct { + client *http.Client + credentials string + marshaler *jsonpb.Marshaler + baseURL string +} + +// InitHTTPConnection creates and returns a new HTTPConnection object +// with a given server address and username/password. +func InitHTTPConnection(serverAddr string, usernamePassword string) *HTTPConnection { + return &HTTPConnection{ + client: &http.Client{Timeout: time.Duration(1 * time.Second)}, + credentials: "Basic " + base64.StdEncoding.EncodeToString([]byte(usernamePassword)), + marshaler: &jsonpb.Marshaler{}, + // TODO(wsilberm): Use https + baseURL: "http://" + serverAddr, + } +} + +func (h HTTPConnection) getURL(rpcName string) string { + if rpcName != "" { + return h.baseURL + "/v3/" + rpcName + } + return h.baseURL +} + +// Bookings is a convenience type for a booking array. +type Bookings []*mpb.Booking + +func (b Bookings) Len() int { + return len(b) +} + +func (b Bookings) Less(i, j int) bool { + return b[i].GetBookingId() < b[j].GetBookingId() +} + +func (b Bookings) Swap(i, j int) { + b[i], b[j] = b[j], b[i] +} + +// HealthCheck performs a health check. +func HealthCheck(conn *HTTPConnection) error { + utils.LogFlow("Health Check", "Start") + defer utils.LogFlow("Health Check", "End") + + // See if we get a response. + _, err := http.Get(conn.getURL("")) + if err != nil { + return fmt.Errorf("could not complete health check: %v", err) + } + log.Println("health check success!") + return nil +} + +// sendRequest sets up and sends the relevant HTTP request to the server and returns the HTTP response. +func sendRequest(rpcName string, req string, conn *HTTPConnection) (*http.Response, error) { + httpReq, err := http.NewRequest("POST", conn.getURL(rpcName), bytes.NewBuffer([]byte(req))) + httpReq.Header.Set("Content-Type", "application/json") + httpReq.Header.Set("Authorization", conn.credentials) + log.Printf("%v Request. Sent(unix): %s, Request %v\n", rpcName, time.Now().UTC().Format(time.RFC850), httpReq) + + httpResp, err := conn.client.Do(httpReq) + if err != nil { + return nil, fmt.Errorf("invalid response. CheckAvailability yielded error: %v", err) + } + return httpResp, nil +} + +// CheckAvailability beforms a maps booking availability check on all supplied availability slots. This function +// will return all slots with a valid return. +func CheckAvailability(a *fpb.Availability, conn *HTTPConnection) error { + slot, err := utils.BuildSlotFrom(a) + if err != nil { + return fmt.Errorf("unable to build request for check availability flow. err: %v, availability record: %v", err, a.String()) + } + reqPB := &mpb.CheckAvailabilityRequest{ + Slot: slot, + } + req, err := conn.marshaler.MarshalToString(reqPB) + if err != nil { + return fmt.Errorf("Could not convert pb3 to json: %v", reqPB) + } + httpResp, err := sendRequest("CheckAvailability", req, conn) + if err != nil { + return fmt.Errorf("invalid response. CheckAvailability yielded error: %v", err) + } + defer httpResp.Body.Close() + var resp mpb.CheckAvailabilityResponse + if err := jsonpb.Unmarshal(httpResp.Body, &resp); err != nil { + return fmt.Errorf("CheckAvailability: Could not parse HTTP response to pb3: %v", err) + } + + log.Printf("CheckAvailability Response. Received(unix): %s, Response %s", time.Now().UTC().Format(time.RFC850), resp.String()) + + if diff := cmp.Diff(resp.GetSlot(), slot, cmp.Comparer(proto.Equal)); diff != "" { + return fmt.Errorf("invalid response. CheckAvailability slots differ (-got +want)\n%s", diff) + } + + if resp.GetCountAvailable() == 0 { + return errors.New("no count available in response") + } + + return nil +} + +// CreateBooking attempts to create bookings from availability slots. +func CreateBooking(a *fpb.Availability, conn *HTTPConnection) (*mpb.Booking, error) { + slot, err := utils.BuildSlotFrom(a) + if err != nil { + return nil, fmt.Errorf("unable to build request for check availability flow. err: %v, availability record: %v", err, a.String()) + } + + gen := rand.New(rand.NewSource(time.Now().UnixNano())) + // Lease currently unsupported. + reqPB := &mpb.CreateBookingRequest{ + Slot: slot, + UserInformation: &mpb.UserInformation{ + UserId: userID, + GivenName: firstName, + FamilyName: lastName, + Telephone: telephone, + Email: email, + }, + PaymentInformation: &mpb.PaymentInformation{ + PrepaymentStatus: mpb.PrepaymentStatus_PREPAYMENT_NOT_PROVIDED, + }, + IdempotencyToken: strconv.Itoa(gen.Intn(1000000)), + } + req, err := conn.marshaler.MarshalToString(reqPB) + if err != nil { + return nil, fmt.Errorf("Could not convert pb3 to json: %v", reqPB) + } + + httpResp, err := sendRequest("CreateBooking", req, conn) + if err != nil { + return nil, fmt.Errorf("invalid response. CreateBooking yielded error: %v", err) + } + defer httpResp.Body.Close() + var resp mpb.CreateBookingResponse + if err := jsonpb.Unmarshal(httpResp.Body, &resp); err != nil { + return nil, fmt.Errorf("CreateBooking: Could not parse HTTP response to pb3: %v", err) + } + + log.Printf("CreateBooking Response. Received(unix): %s, Response %s", time.Now().UTC().Format(time.RFC850), resp.String()) + if resp.GetBookingFailure() != nil { + return nil, fmt.Errorf("invalid response. CreateBooking failed with booking failure %v", resp.GetBookingFailure()) + } + + b := resp.GetBooking() + if iE := utils.ValidateBooking(b, &mpb.Booking{ + Slot: reqPB.GetSlot(), + UserInformation: reqPB.GetUserInformation(), + PaymentInformation: reqPB.GetPaymentInformation(), + }); iE != nil { + return nil, fmt.Errorf("invalid response. CreateBooking invalid: %s", iE.Error()) + } + + // Perform idempotency test. + log.Printf("Idempotency check -- CreateBooking Request. Sent(unix): %s, Request %s", time.Now().UTC().Format(time.RFC850), reqPB.String()) + idemHTTPResp, err := sendRequest("CreateBooking", req, conn) + if err != nil { + return nil, fmt.Errorf("invalid response. Idempotency check yielded error: %v", err) + } + defer idemHTTPResp.Body.Close() + var idemResp mpb.CreateBookingResponse + if err := jsonpb.Unmarshal(httpResp.Body, &resp); err != nil { + return nil, fmt.Errorf("CreateBooking idem: Could not parse HTTP response to pb3: %v", err) + } + + log.Printf("Idempotency check -- Response. Received(unix): %s, Response %s", time.Now().UTC().Format(time.RFC850), idemResp.String()) + if diff := cmp.Diff(idemResp, resp); diff != "" { + return b, fmt.Errorf("Idempotency check invalid (-got +want)\n%s", diff) + } + + return b, nil +} + +// ListBookings calls the maps booking ListBookings rpc and compares the return with all input bookings. +func ListBookings(tB Bookings, conn *HTTPConnection) (Bookings, error) { + var out Bookings + reqPB := &mpb.ListBookingsRequest{ + UserId: userID, + } + req, err := conn.marshaler.MarshalToString(reqPB) + if err != nil { + return nil, fmt.Errorf("Could not convert pb3 to json: %v", reqPB) + } + httpResp, err := sendRequest("ListBookings", req, conn) + if err != nil { + return nil, fmt.Errorf("invalid response. ListBookings yielded error: %v. Abandoning all booking from this flow", err) + } + defer httpResp.Body.Close() + var resp mpb.ListBookingsResponse + if err := jsonpb.Unmarshal(httpResp.Body, &resp); err != nil { + return nil, fmt.Errorf("ListBookings: Could not parse HTTP response to pb3: %v", err) + } + + log.Printf("ListBookings Response. Received(unix): %s, Response %s", time.Now().UTC().Format(time.RFC850), resp.String()) + gB := Bookings(resp.GetBookings()) + if len(gB) != len(tB) { + return out, fmt.Errorf("number of bookings differ, ListBookings invalid. Got: %d, Want: %d. Abandoning all bookings from this flow", len(gB), len(tB)) + } + + sort.Sort(gB) + sort.Sort(tB) + for i := 0; i < len(tB); i++ { + if iE := utils.ValidateBooking(gB[i], tB[i]); iE != nil { + log.Printf("ListBookings invalid, %s, abandoning slot %d/%d", iE.Error(), i, len(tB)) + continue + } + out = append(out, tB[i]) + } + + return out, nil +} + +// GetBookingStatus checks that all input bookings are in an acceptable state. +func GetBookingStatus(b *mpb.Booking, conn *HTTPConnection) error { + reqPB := &mpb.GetBookingStatusRequest{ + BookingId: b.GetBookingId(), + } + + req, err := conn.marshaler.MarshalToString(reqPB) + if err != nil { + return fmt.Errorf("Could not convert pb3 to json: %v", reqPB) + } + httpResp, err := sendRequest("GetBookingStatus", req, conn) + if err != nil { + return fmt.Errorf("invalid response. GetBookingStatus yielded error: %v", err) + } + defer httpResp.Body.Close() + var resp mpb.GetBookingStatusResponse + if err := jsonpb.Unmarshal(httpResp.Body, &resp); err != nil { + return fmt.Errorf("GetBookingsStatus: Could not parse HTTP response to pb3: %v", err) + } + + log.Printf("GetBookingStatus Response. Received(unix): %s, Response %s", time.Now().UTC().Format(time.RFC850), resp.String()) + if diff := cmp.Diff(resp.GetBookingStatus(), mpb.BookingStatus_CONFIRMED); diff != "" { + return fmt.Errorf("invalid response. BookingStatus differ (-got +want)\n%s", diff) + } + + return nil +} + +// CancelBooking is a clean up method that cancels all supplied bookings. +func CancelBooking(b *mpb.Booking, conn *HTTPConnection) error { + b.Status = mpb.BookingStatus_CANCELED + reqPB := &mpb.UpdateBookingRequest{ + Booking: b, + } + req, err := conn.marshaler.MarshalToString(reqPB) + if err != nil { + return fmt.Errorf("Could not convert pb3 to json: %v", reqPB) + } + httpResp, err := sendRequest("UpdateBooking", req, conn) + if err != nil { + return fmt.Errorf("invalid response. UpdateBooking yielded error: %v", err) + } + defer httpResp.Body.Close() + var resp mpb.UpdateBookingResponse + if err := jsonpb.Unmarshal(httpResp.Body, &resp); err != nil { + return fmt.Errorf("CancelBooking: Could not parse HTTP response to pb3: %v", err) + } + + log.Printf("UpdateBooking Response. Received(unix): %s, Response %s", time.Now().UTC().Format(time.RFC850), resp.String()) + if iE := utils.ValidateBooking(resp.GetBooking(), reqPB.GetBooking()); iE != nil { + return fmt.Errorf("invalid response. UpdateBooking: %s", iE.Error()) + } + return nil +} + +// Rescheduling will attempt to create a booking, update the booking, then cancel. +func Rescheduling(av []*fpb.Availability, conn *HTTPConnection) error { + var slots []*fpb.Availability + for _, v := range utils.BuildMerchantServiceMap(av) { + // Need at least two slots for reschedule. + if len(v) <= 1 { + continue + } + slots = v + break + } + + if len(slots) == 0 { + return errors.New("no suitable availability for rescheduling flow. exiting") + } + // Book first slot. + newBooking, err := CreateBooking(slots[0], conn) + if err != nil { + return fmt.Errorf("could not complete booking, abandoning rescheduling flow: %v", err) + } + slot := newBooking.GetSlot() + + // New slot. + lastAvailability := slots[len(slots)-1] + slot.StartSec = lastAvailability.GetStartSec() + slot.DurationSec = lastAvailability.GetDurationSec() + + reqPB := &mpb.UpdateBookingRequest{ + Booking: newBooking, + } + req, err := conn.marshaler.MarshalToString(reqPB) + if err != nil { + return fmt.Errorf("Rescheduling UpdateBooking: Could not convert pb3 to json: %v", reqPB) + } + updateHTTPResp, err := sendRequest("UpdateBooking", req, conn) + defer updateHTTPResp.Body.Close() + var resp mpb.CreateBookingResponse + if err := jsonpb.Unmarshal(updateHTTPResp.Body, &resp); err != nil { + return fmt.Errorf("Rescheduling UpdateBooking: Could not parse HTTP response to pb3: %v", err) + } + + log.Printf("UpdateBooking Response. Received(unix): %s, Response %s", time.Now().UTC().Format(time.RFC850), resp.String()) + if iE := utils.ValidateBooking(resp.GetBooking(), newBooking); iE != nil { + return fmt.Errorf("invalid response. UpdateBooking: %s, abandoning slot 1/1", iE.Error()) + } + return CancelBooking(resp.GetBooking(), conn) +}
diff --git a/feeds/availability_feed.pb.go b/feeds/availability_feed.pb.go new file mode 100644 index 0000000..c41f821 --- /dev/null +++ b/feeds/availability_feed.pb.go
@@ -0,0 +1,637 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: availability_feed.proto + +/* +Package maps_booking_feeds is a generated protocol buffer package. + +It is generated from these files: + availability_feed.proto + +It has these top-level messages: + FeedMetadata + AvailabilityFeed + ServiceAvailability + Availability + Resources + TimeRange +*/ +package maps_booking_feeds + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +type FeedMetadata_ProcessingInstruction int32 + +const ( + // By default we will assume that this feed is an incremental feed. + FeedMetadata_PROCESS_UNKNOWN FeedMetadata_ProcessingInstruction = 0 + // This Feed message is one shard of a complete feed. Anything previously + // supplied by this partner will be deleted; the contents of this feed + // represent the entire state of the world. + FeedMetadata_PROCESS_AS_COMPLETE FeedMetadata_ProcessingInstruction = 1 + // This Feed message is one shard of an incremental feed. Existing entities + // will be left untouched except as modified in this feed. + FeedMetadata_PROCESS_AS_INCREMENTAL FeedMetadata_ProcessingInstruction = 2 +) + +var FeedMetadata_ProcessingInstruction_name = map[int32]string{ + 0: "PROCESS_UNKNOWN", + 1: "PROCESS_AS_COMPLETE", + 2: "PROCESS_AS_INCREMENTAL", +} +var FeedMetadata_ProcessingInstruction_value = map[string]int32{ + "PROCESS_UNKNOWN": 0, + "PROCESS_AS_COMPLETE": 1, + "PROCESS_AS_INCREMENTAL": 2, +} + +func (x FeedMetadata_ProcessingInstruction) String() string { + return proto.EnumName(FeedMetadata_ProcessingInstruction_name, int32(x)) +} +func (FeedMetadata_ProcessingInstruction) EnumDescriptor() ([]byte, []int) { + return fileDescriptor0, []int{0, 0} +} + +type FeedMetadata struct { + // Instructs us how to process the feed: either as a shard of a complete feed, + // or as a shard of an incremental update. + ProcessingInstruction FeedMetadata_ProcessingInstruction `protobuf:"varint,1,opt,name=processing_instruction,json=processingInstruction,enum=maps.booking.feeds.FeedMetadata_ProcessingInstruction" json:"processing_instruction,omitempty"` + // The current shard and total number of shards for this feed. + // + // Shard number is assumed to be zero-based. + // + // There does not need to be any relationship to the file name. + // + // Shards do not need to be transferred in order, and they may not be + // processed in order. + ShardNumber int32 `protobuf:"varint,2,opt,name=shard_number,json=shardNumber" json:"shard_number,omitempty"` + TotalShards int32 `protobuf:"varint,3,opt,name=total_shards,json=totalShards" json:"total_shards,omitempty"` + // An identifier that must be consistent across all shards in a feed. + // This value must be globally unique across each feed type. + // + // This value ensures that complete feeds spanning multiple shards are + // processed together correctly. + // + // Clients only need to set this value when the processing_instruction is set + // to PROCESS_AS_COMPLETE and the feed spans multiple shards (defined by + // total_shards). + // + // Feeds that span multiple shards must set this nonce to the same value. + Nonce uint64 `protobuf:"varint,5,opt,name=nonce" json:"nonce,omitempty"` + // The timestamp at which this feed shard was generated. + // + // In Unix time format (seconds since the epoch). + GenerationTimestamp int64 `protobuf:"varint,4,opt,name=generation_timestamp,json=generationTimestamp" json:"generation_timestamp,omitempty"` +} + +func (m *FeedMetadata) Reset() { *m = FeedMetadata{} } +func (m *FeedMetadata) String() string { return proto.CompactTextString(m) } +func (*FeedMetadata) ProtoMessage() {} +func (*FeedMetadata) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +func (m *FeedMetadata) GetProcessingInstruction() FeedMetadata_ProcessingInstruction { + if m != nil { + return m.ProcessingInstruction + } + return FeedMetadata_PROCESS_UNKNOWN +} + +func (m *FeedMetadata) GetShardNumber() int32 { + if m != nil { + return m.ShardNumber + } + return 0 +} + +func (m *FeedMetadata) GetTotalShards() int32 { + if m != nil { + return m.TotalShards + } + return 0 +} + +func (m *FeedMetadata) GetNonce() uint64 { + if m != nil { + return m.Nonce + } + return 0 +} + +func (m *FeedMetadata) GetGenerationTimestamp() int64 { + if m != nil { + return m.GenerationTimestamp + } + return 0 +} + +type AvailabilityFeed struct { + Metadata *FeedMetadata `protobuf:"bytes,1,opt,name=metadata" json:"metadata,omitempty"` + ServiceAvailability []*ServiceAvailability `protobuf:"bytes,2,rep,name=service_availability,json=serviceAvailability" json:"service_availability,omitempty"` +} + +func (m *AvailabilityFeed) Reset() { *m = AvailabilityFeed{} } +func (m *AvailabilityFeed) String() string { return proto.CompactTextString(m) } +func (*AvailabilityFeed) ProtoMessage() {} +func (*AvailabilityFeed) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func (m *AvailabilityFeed) GetMetadata() *FeedMetadata { + if m != nil { + return m.Metadata + } + return nil +} + +func (m *AvailabilityFeed) GetServiceAvailability() []*ServiceAvailability { + if m != nil { + return m.ServiceAvailability + } + return nil +} + +type ServiceAvailability struct { + // If provided, we will consider the Availability entities provided to be a + // complete snapshot from [start_timestamp_restrict, end_timestamp_restrict). + // That is, all existing availability will be deleted if the following + // condition holds true: + // + // start_timestamp_restrict <= Availability.start_sec && + // Availability.start_sec < end_timestamp_restrict + // + // If a resource_restrict message is set, the condition is further restricted: + // + // Availability.resource.staff_id == resource_restrict.staff_id && + // Availability.resource.room_id == resource_restrict.room_id + // + // These fields are typically used to provide a complete update of + // availability in a given time range. + // + // Setting start_timestamp_restrict while leaving end_timestamp_restrict unset + // is interpreted to mean all time beginning at start_timestamp_restrict. + // + // Setting end_timestamp_restrict while leaving start_timestamp_restrict unset + // is interpreted to mean all time up to the end_timestamp_restrict. + // + // In Unix time format (seconds since the epoch). + StartTimestampRestrict int64 `protobuf:"varint,1,opt,name=start_timestamp_restrict,json=startTimestampRestrict" json:"start_timestamp_restrict,omitempty"` + EndTimestampRestrict int64 `protobuf:"varint,2,opt,name=end_timestamp_restrict,json=endTimestampRestrict" json:"end_timestamp_restrict,omitempty"` + // If provided, the timestamp restricts will be applied only to the given + // merchant or service. + // + // These fields are typically used to provide complete snapshot of + // availability in a given range (defined above) for a specific merchant or + // service. + // + // Leaving these fields unset, or setting these to the empty string or null, + // is interpreted to mean that no restrict is intended. + MerchantIdRestrict string `protobuf:"bytes,3,opt,name=merchant_id_restrict,json=merchantIdRestrict" json:"merchant_id_restrict,omitempty"` + ServiceIdRestrict string `protobuf:"bytes,4,opt,name=service_id_restrict,json=serviceIdRestrict" json:"service_id_restrict,omitempty"` + // Setting resources_restrict further restricts the scope of the update to + // just this set of resources. All id fields of the resources must match + // exactly. + ResourcesRestrict *Resources `protobuf:"bytes,6,opt,name=resources_restrict,json=resourcesRestrict" json:"resources_restrict,omitempty"` + Availability []*Availability `protobuf:"bytes,5,rep,name=availability" json:"availability,omitempty"` +} + +func (m *ServiceAvailability) Reset() { *m = ServiceAvailability{} } +func (m *ServiceAvailability) String() string { return proto.CompactTextString(m) } +func (*ServiceAvailability) ProtoMessage() {} +func (*ServiceAvailability) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *ServiceAvailability) GetStartTimestampRestrict() int64 { + if m != nil { + return m.StartTimestampRestrict + } + return 0 +} + +func (m *ServiceAvailability) GetEndTimestampRestrict() int64 { + if m != nil { + return m.EndTimestampRestrict + } + return 0 +} + +func (m *ServiceAvailability) GetMerchantIdRestrict() string { + if m != nil { + return m.MerchantIdRestrict + } + return "" +} + +func (m *ServiceAvailability) GetServiceIdRestrict() string { + if m != nil { + return m.ServiceIdRestrict + } + return "" +} + +func (m *ServiceAvailability) GetResourcesRestrict() *Resources { + if m != nil { + return m.ResourcesRestrict + } + return nil +} + +func (m *ServiceAvailability) GetAvailability() []*Availability { + if m != nil { + return m.Availability + } + return nil +} + +// An availability of the merchant's service, indicating time and number +// of spots. +// The availability feed should be a list of this message. +// Please note that it's up to the partner to call out all the possible +// availabilities. +// If a massage therapist is available 9am-12pm, and they provide +// one-hour massage sessions, the aggregator should provide the feed as +// availability {start_sec: 9am, duration: 60 minutes, ...} +// availability {start_sec: 10am, duration: 60 minutes, ...} +// availability {start_sec: 11am, duration: 60 minutes, ...} +// instead of +// availability {start_sec: 9am, duration: 180 minutes, ...} +// +type Availability struct { + // An opaque string from an aggregator to identify a merchant. + MerchantId string `protobuf:"bytes,1,opt,name=merchant_id,json=merchantId" json:"merchant_id,omitempty"` + // An opaque string from aggregator to identify a service of the + // merchant. + ServiceId string `protobuf:"bytes,2,opt,name=service_id,json=serviceId" json:"service_id,omitempty"` + // Start time of this availability, using epoch time in seconds. + StartSec int64 `protobuf:"varint,3,opt,name=start_sec,json=startSec" json:"start_sec,omitempty"` + // Duration of the service in seconds, e.g. 30 minutes for a chair massage. + DurationSec int64 `protobuf:"varint,4,opt,name=duration_sec,json=durationSec" json:"duration_sec,omitempty"` + // Number of total spots and open spots of this availability. + // E.g. a Yoga class of 10 spots with 3 booked. + // availability {spots_total: 10, spots_open: 7 ...} + // E.g. a chair massage session which was already booked. + // availability {spots_total: 1, spots_open: 0 ...} + // + // Note: If sending requests using the availability compression format defined + // below, these two fields will be inferred. A Recurrence + // implies spots_total=1 and spots_open=1. A ScheduleException implies + // spots_total=1 and spots_open=0. + SpotsTotal int64 `protobuf:"varint,5,opt,name=spots_total,json=spotsTotal" json:"spots_total,omitempty"` + SpotsOpen int64 `protobuf:"varint,6,opt,name=spots_open,json=spotsOpen" json:"spots_open,omitempty"` + // An optional opaque string to identify this availability slot. If set, it + // will be included in the requests that book/update/cancel appointments. + AvailabilityTag string `protobuf:"bytes,7,opt,name=availability_tag,json=availabilityTag" json:"availability_tag,omitempty"` + // Optional resources used to disambiguate this availability slot from + // others when different staff, room, or party_size values are part + // of the service. + // + // E.g. the same Yoga class with two 2 instructors. + // availability { resources { staff_id: "1" staff_name: "Amy" } + // spots_total: 10 spots_open: 7 } + // availability { resources { staff_id: "2" staff_name: "John" } + // spots_total: 5 spots_open: 2 } + Resources *Resources `protobuf:"bytes,8,opt,name=resources" json:"resources,omitempty"` + // A list of ids referencing the payment options which can be used to pay + // for this slot. The actual payment options are defined at the Merchant + // level, and can also be shared among multiple Merchants. + // + // This field overrides any payment_option_ids specified in the service + // message. Similarly payment_option_ids specified here do NOT have to be + // present in the service message, though must be defined at the + // Merchant level. + PaymentOptionId []string `protobuf:"bytes,9,rep,name=payment_option_id,json=paymentOptionId" json:"payment_option_id,omitempty"` + // The recurrence information for the availability, representing more than one + // start time. A recurrence should contain appointments for one working day. + Recurrence *Availability_Recurrence `protobuf:"bytes,10,opt,name=recurrence" json:"recurrence,omitempty"` + // When this service cannot be scheduled. To limit the number of + // schedule_exception messages consider joining adjacent exceptions. + ScheduleException []*Availability_ScheduleException `protobuf:"bytes,11,rep,name=schedule_exception,json=scheduleException" json:"schedule_exception,omitempty"` +} + +func (m *Availability) Reset() { *m = Availability{} } +func (m *Availability) String() string { return proto.CompactTextString(m) } +func (*Availability) ProtoMessage() {} +func (*Availability) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func (m *Availability) GetMerchantId() string { + if m != nil { + return m.MerchantId + } + return "" +} + +func (m *Availability) GetServiceId() string { + if m != nil { + return m.ServiceId + } + return "" +} + +func (m *Availability) GetStartSec() int64 { + if m != nil { + return m.StartSec + } + return 0 +} + +func (m *Availability) GetDurationSec() int64 { + if m != nil { + return m.DurationSec + } + return 0 +} + +func (m *Availability) GetSpotsTotal() int64 { + if m != nil { + return m.SpotsTotal + } + return 0 +} + +func (m *Availability) GetSpotsOpen() int64 { + if m != nil { + return m.SpotsOpen + } + return 0 +} + +func (m *Availability) GetAvailabilityTag() string { + if m != nil { + return m.AvailabilityTag + } + return "" +} + +func (m *Availability) GetResources() *Resources { + if m != nil { + return m.Resources + } + return nil +} + +func (m *Availability) GetPaymentOptionId() []string { + if m != nil { + return m.PaymentOptionId + } + return nil +} + +func (m *Availability) GetRecurrence() *Availability_Recurrence { + if m != nil { + return m.Recurrence + } + return nil +} + +func (m *Availability) GetScheduleException() []*Availability_ScheduleException { + if m != nil { + return m.ScheduleException + } + return nil +} + +// Recurrence messages are optional, but allow for a more compact +// representation of consistently repeating availability slots. They typically +// represent a day's working schedule. +// ScheduleException messages are then used to represent booked/unavailable +// time ranges within the work day. +// +// Requirements: +// 1. The expansion of availability slots or recurrences must NOT create +// identical slots. If the ids, start_sec, duration_sec, and resources +// match, slots are considered identical. +// 2. Do NOT mix the standard availability format and recurrence within the +// slots of a single service. Recurrence benefits merchants/services that +// offer appointments. The standard format is geared towards +// merchants/services with regularly scheduled classes. +type Availability_Recurrence struct { + // The inclusive maximum UTC timestamp the availability repeats until. + RepeatUntilSec int64 `protobuf:"varint,1,opt,name=repeat_until_sec,json=repeatUntilSec" json:"repeat_until_sec,omitempty"` + // Defines the time between successive availability slots. + // + // E.g. An availability with a duration of 20 min, a repeat_every_sec of + // 30 min, a start_sec of 9:00am, and a repeat_until_sec of 11:00am will + // yield slots at 9-9:20am, 9:30-9:50am, 10-10:20am, 10:30-10:50am, + // 11-11:20am. + RepeatEverySec int32 `protobuf:"varint,2,opt,name=repeat_every_sec,json=repeatEverySec" json:"repeat_every_sec,omitempty"` +} + +func (m *Availability_Recurrence) Reset() { *m = Availability_Recurrence{} } +func (m *Availability_Recurrence) String() string { return proto.CompactTextString(m) } +func (*Availability_Recurrence) ProtoMessage() {} +func (*Availability_Recurrence) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3, 0} } + +func (m *Availability_Recurrence) GetRepeatUntilSec() int64 { + if m != nil { + return m.RepeatUntilSec + } + return 0 +} + +func (m *Availability_Recurrence) GetRepeatEverySec() int32 { + if m != nil { + return m.RepeatEverySec + } + return 0 +} + +// ScheduleException messages are used to represent booked/unavailable time +// ranges within the work day. As time slots are booked, the list of +// exceptions should grow to reflect the newly unavailable time ranges. +// The recurrence itself shouldn't be modified. +type Availability_ScheduleException struct { + // The time range of the exception. + TimeRange *TimeRange `protobuf:"bytes,1,opt,name=time_range,json=timeRange" json:"time_range,omitempty"` +} + +func (m *Availability_ScheduleException) Reset() { *m = Availability_ScheduleException{} } +func (m *Availability_ScheduleException) String() string { return proto.CompactTextString(m) } +func (*Availability_ScheduleException) ProtoMessage() {} +func (*Availability_ScheduleException) Descriptor() ([]byte, []int) { + return fileDescriptor0, []int{3, 1} +} + +func (m *Availability_ScheduleException) GetTimeRange() *TimeRange { + if m != nil { + return m.TimeRange + } + return nil +} + +// A resource is used to disambiguate availability slots from one another when +// different staff, room or party_size values are part of the service. +// Multiple slots for the same service and time interval can co-exist when they +// have different resources. +type Resources struct { + // Optional id for a staff member providing the service. This field identifies + // the staff member across all merchants, services, and availability records. + // It also needs to be stable over time to allow correlation with past + // bookings. + // This field must be present if staff_name is present. + StaffId string `protobuf:"bytes,1,opt,name=staff_id,json=staffId" json:"staff_id,omitempty"` + // Optional name of a staff member providing the service. This field will be + // displayed to users making a booking, and should be human readable, as + // opposed to an opaque identifier. + // This field must be present if staff_id is present. + StaffName string `protobuf:"bytes,2,opt,name=staff_name,json=staffName" json:"staff_name,omitempty"` + // An optional id for the room the service is located in. This field + // identifies the room across all merchants, services, and availability + // records. It also needs to be stable over time to allow correlation with + // past bookings. + // This field must be present if room_name is present. + RoomId string `protobuf:"bytes,3,opt,name=room_id,json=roomId" json:"room_id,omitempty"` + // An optional name for the room the service is located in. This + // field will be displayed to users making a booking, and should be human + // readable, as opposed to an opaque identifier. + // This field must be present if room_id is present. + RoomName string `protobuf:"bytes,4,opt,name=room_name,json=roomName" json:"room_name,omitempty"` + // Applicable only for Dining: The party size which can be accommodated + // during this time slot. A restaurant can be associated with multiple Slots + // for the same time, each specifying a different party_size, if for instance + // 2, 3, or 4 people can be seated with a reservation. + PartySize int32 `protobuf:"varint,5,opt,name=party_size,json=partySize" json:"party_size,omitempty"` +} + +func (m *Resources) Reset() { *m = Resources{} } +func (m *Resources) String() string { return proto.CompactTextString(m) } +func (*Resources) ProtoMessage() {} +func (*Resources) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } + +func (m *Resources) GetStaffId() string { + if m != nil { + return m.StaffId + } + return "" +} + +func (m *Resources) GetStaffName() string { + if m != nil { + return m.StaffName + } + return "" +} + +func (m *Resources) GetRoomId() string { + if m != nil { + return m.RoomId + } + return "" +} + +func (m *Resources) GetRoomName() string { + if m != nil { + return m.RoomName + } + return "" +} + +func (m *Resources) GetPartySize() int32 { + if m != nil { + return m.PartySize + } + return 0 +} + +type TimeRange struct { + BeginSec int64 `protobuf:"varint,1,opt,name=begin_sec,json=beginSec" json:"begin_sec,omitempty"` + EndSec int64 `protobuf:"varint,2,opt,name=end_sec,json=endSec" json:"end_sec,omitempty"` +} + +func (m *TimeRange) Reset() { *m = TimeRange{} } +func (m *TimeRange) String() string { return proto.CompactTextString(m) } +func (*TimeRange) ProtoMessage() {} +func (*TimeRange) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } + +func (m *TimeRange) GetBeginSec() int64 { + if m != nil { + return m.BeginSec + } + return 0 +} + +func (m *TimeRange) GetEndSec() int64 { + if m != nil { + return m.EndSec + } + return 0 +} + +func init() { + proto.RegisterType((*FeedMetadata)(nil), "maps.booking.feeds.FeedMetadata") + proto.RegisterType((*AvailabilityFeed)(nil), "maps.booking.feeds.AvailabilityFeed") + proto.RegisterType((*ServiceAvailability)(nil), "maps.booking.feeds.ServiceAvailability") + proto.RegisterType((*Availability)(nil), "maps.booking.feeds.Availability") + proto.RegisterType((*Availability_Recurrence)(nil), "maps.booking.feeds.Availability.Recurrence") + proto.RegisterType((*Availability_ScheduleException)(nil), "maps.booking.feeds.Availability.ScheduleException") + proto.RegisterType((*Resources)(nil), "maps.booking.feeds.Resources") + proto.RegisterType((*TimeRange)(nil), "maps.booking.feeds.TimeRange") + proto.RegisterEnum("maps.booking.feeds.FeedMetadata_ProcessingInstruction", FeedMetadata_ProcessingInstruction_name, FeedMetadata_ProcessingInstruction_value) +} + +func init() { proto.RegisterFile("availability_feed.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 859 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x55, 0xdb, 0x6e, 0x23, 0x45, + 0x10, 0xc5, 0x76, 0x9c, 0x64, 0xca, 0xd1, 0xae, 0xdd, 0xf6, 0x26, 0x43, 0x50, 0xb4, 0xc6, 0x2f, + 0x18, 0x90, 0x2c, 0x08, 0x08, 0x21, 0xb1, 0x2f, 0x51, 0x30, 0x52, 0xb4, 0x89, 0x1d, 0x7a, 0xbc, + 0x42, 0xe2, 0x65, 0x68, 0xcf, 0x54, 0x9c, 0x11, 0x9e, 0x9e, 0x51, 0x77, 0x3b, 0x22, 0xfb, 0x29, + 0x7c, 0x03, 0xff, 0xc1, 0xe7, 0xf0, 0x01, 0xbc, 0xa0, 0xae, 0xb9, 0x9a, 0x58, 0xca, 0xbe, 0x79, + 0x4e, 0x9d, 0xd3, 0x97, 0x73, 0xaa, 0xda, 0x70, 0x22, 0x1e, 0x44, 0xb4, 0x16, 0xcb, 0x68, 0x1d, + 0x99, 0x47, 0xff, 0x0e, 0x31, 0x9c, 0xa4, 0x2a, 0x31, 0x09, 0x63, 0xb1, 0x48, 0xf5, 0x64, 0x99, + 0x24, 0xbf, 0x47, 0x72, 0x35, 0xb1, 0x05, 0x3d, 0xfa, 0xa7, 0x09, 0x47, 0x3f, 0x21, 0x86, 0x37, + 0x68, 0x44, 0x28, 0x8c, 0x60, 0x31, 0x1c, 0xa7, 0x2a, 0x09, 0x50, 0xeb, 0x48, 0xae, 0xfc, 0x48, + 0x6a, 0xa3, 0x36, 0x81, 0x89, 0x12, 0xe9, 0x36, 0x86, 0x8d, 0xf1, 0x8b, 0xf3, 0xef, 0x26, 0x4f, + 0x57, 0x99, 0xd4, 0x57, 0x98, 0xdc, 0x96, 0xf2, 0xab, 0x4a, 0xcd, 0x5f, 0xa5, 0xbb, 0x60, 0xf6, + 0x29, 0x1c, 0xe9, 0x7b, 0xa1, 0x42, 0x5f, 0x6e, 0xe2, 0x25, 0x2a, 0xb7, 0x39, 0x6c, 0x8c, 0xdb, + 0xbc, 0x43, 0xd8, 0x8c, 0x20, 0x4b, 0x31, 0x89, 0x11, 0x6b, 0x9f, 0x40, 0xed, 0xb6, 0x32, 0x0a, + 0x61, 0x1e, 0x41, 0x6c, 0x00, 0x6d, 0x99, 0xc8, 0x00, 0xdd, 0xf6, 0xb0, 0x31, 0xde, 0xe3, 0xd9, + 0x07, 0xfb, 0x1a, 0x06, 0x2b, 0x94, 0xa8, 0x84, 0xdd, 0xc9, 0x37, 0x51, 0x8c, 0xda, 0x88, 0x38, + 0x75, 0xf7, 0x86, 0x8d, 0x71, 0x8b, 0xf7, 0xab, 0xda, 0xa2, 0x28, 0x8d, 0x04, 0xbc, 0xda, 0x79, + 0x7c, 0xd6, 0x87, 0x97, 0xb7, 0x7c, 0x7e, 0x39, 0xf5, 0x3c, 0xff, 0xdd, 0xec, 0xed, 0x6c, 0xfe, + 0xcb, 0xac, 0xfb, 0x11, 0x3b, 0x81, 0x7e, 0x01, 0x5e, 0x78, 0xfe, 0xe5, 0xfc, 0xe6, 0xf6, 0x7a, + 0xba, 0x98, 0x76, 0x1b, 0xec, 0x14, 0x8e, 0x6b, 0x85, 0xab, 0xd9, 0x25, 0x9f, 0xde, 0x4c, 0x67, + 0x8b, 0x8b, 0xeb, 0x6e, 0x73, 0xf4, 0x57, 0x03, 0xba, 0x17, 0xb5, 0x84, 0xac, 0x77, 0xec, 0x0d, + 0x1c, 0xc6, 0xb9, 0x7f, 0xe4, 0x73, 0xe7, 0x7c, 0xf8, 0x9c, 0xcf, 0xbc, 0x54, 0xb0, 0x5f, 0x61, + 0xa0, 0x51, 0x3d, 0x44, 0x01, 0xfa, 0xf5, 0xec, 0xdd, 0xe6, 0xb0, 0x35, 0xee, 0x9c, 0x7f, 0xb6, + 0x6b, 0x25, 0x2f, 0xe3, 0xd7, 0x0f, 0xc2, 0xfb, 0xfa, 0x29, 0x38, 0xfa, 0xb7, 0x09, 0xfd, 0x1d, + 0x64, 0xf6, 0x3d, 0xb8, 0xda, 0x08, 0x65, 0x2a, 0x5f, 0x7d, 0x85, 0xda, 0xa8, 0x28, 0x30, 0x74, + 0x83, 0x16, 0x3f, 0xa6, 0x7a, 0xe9, 0x2d, 0xcf, 0xab, 0xec, 0x5b, 0x38, 0x46, 0x19, 0xee, 0xd2, + 0x35, 0x49, 0x37, 0x40, 0x19, 0x3e, 0x55, 0x7d, 0x05, 0x83, 0x18, 0x55, 0x70, 0x2f, 0xa4, 0xf1, + 0xa3, 0xb0, 0xd2, 0xd8, 0x6e, 0x70, 0x38, 0x2b, 0x6a, 0x57, 0x61, 0xa9, 0x98, 0x40, 0x71, 0xa1, + 0x2d, 0xc1, 0x1e, 0x09, 0x7a, 0x79, 0xa9, 0xc6, 0xbf, 0x06, 0xa6, 0x50, 0x27, 0x1b, 0x15, 0xa0, + 0xae, 0xe8, 0xfb, 0x94, 0xc6, 0xd9, 0x2e, 0x0f, 0x79, 0xc1, 0xe6, 0xbd, 0x52, 0x58, 0xae, 0xf6, + 0x23, 0x1c, 0x6d, 0x65, 0xd1, 0xa6, 0x2c, 0x76, 0xa6, 0xba, 0x15, 0xc2, 0x96, 0x6a, 0xf4, 0x77, + 0x1b, 0x8e, 0xb6, 0x6c, 0x7f, 0x0d, 0x9d, 0x9a, 0x0d, 0xe4, 0xb4, 0xc3, 0xa1, 0xba, 0x3d, 0x3b, + 0x03, 0xa8, 0x6e, 0x4d, 0x8e, 0x3a, 0xdc, 0x29, 0x2f, 0xcb, 0x3e, 0x01, 0x27, 0x8b, 0x4d, 0x63, + 0x40, 0xde, 0xb5, 0xf8, 0x21, 0x01, 0x1e, 0x06, 0x76, 0xd2, 0xc2, 0x4d, 0x3e, 0x2e, 0xb6, 0x9e, + 0x0d, 0x4a, 0xa7, 0xc0, 0x2c, 0xe5, 0x35, 0x74, 0x74, 0x9a, 0x18, 0xed, 0xd3, 0xf8, 0xd1, 0xbc, + 0xb5, 0x38, 0x10, 0xb4, 0xb0, 0x08, 0xed, 0x4f, 0x84, 0x24, 0x45, 0x49, 0xee, 0xb5, 0xb8, 0x43, + 0xc8, 0x3c, 0x45, 0xc9, 0x3e, 0x87, 0xee, 0xd6, 0xf3, 0x64, 0xc4, 0xca, 0x3d, 0xa0, 0x43, 0xbe, + 0xac, 0xe3, 0x0b, 0xb1, 0x62, 0x3f, 0x80, 0x53, 0xda, 0xea, 0x1e, 0x7e, 0x48, 0x0c, 0x15, 0x9f, + 0x7d, 0x01, 0xbd, 0x54, 0x3c, 0xc6, 0x28, 0x8d, 0x9f, 0xa4, 0x74, 0xa1, 0x28, 0x74, 0x9d, 0x61, + 0xcb, 0x6e, 0x94, 0x17, 0xe6, 0x84, 0x5f, 0x85, 0xec, 0x2d, 0x80, 0xc2, 0x60, 0xa3, 0x14, 0xda, + 0x27, 0x04, 0x68, 0xa7, 0x2f, 0x9f, 0x0b, 0x6a, 0xc2, 0x4b, 0x09, 0xaf, 0xc9, 0x99, 0x00, 0xa6, + 0x83, 0x7b, 0x0c, 0x37, 0x6b, 0xf4, 0xf1, 0x8f, 0x00, 0x69, 0x13, 0xb7, 0x43, 0xe9, 0x9f, 0x3f, + 0xbb, 0xa8, 0x97, 0x4b, 0xa7, 0x85, 0x92, 0xf7, 0xf4, 0xff, 0xa1, 0xd3, 0xdf, 0x00, 0xaa, 0xcd, + 0xd9, 0x18, 0xba, 0x0a, 0x53, 0x14, 0xc6, 0xdf, 0x48, 0x13, 0xad, 0x29, 0xb8, 0x6c, 0x00, 0x5f, + 0x64, 0xf8, 0x3b, 0x0b, 0xdb, 0xec, 0x2a, 0x26, 0x3e, 0xa0, 0x7a, 0x24, 0x66, 0xf6, 0xde, 0xe6, + 0xcc, 0xa9, 0x85, 0x3d, 0x0c, 0x4e, 0x7f, 0x86, 0xde, 0x93, 0x93, 0xb0, 0x37, 0x00, 0x76, 0x66, + 0x7d, 0x25, 0xe4, 0x0a, 0xf3, 0x57, 0x6a, 0x67, 0x20, 0x76, 0x78, 0xb9, 0x25, 0x71, 0xc7, 0x14, + 0x3f, 0x47, 0x7f, 0x36, 0xc0, 0x29, 0x93, 0x62, 0x1f, 0x83, 0xed, 0xba, 0xbb, 0xbb, 0xaa, 0x87, + 0x0f, 0xe8, 0x3b, 0x6f, 0x60, 0x2a, 0x49, 0x11, 0x63, 0xd9, 0xc0, 0x16, 0x99, 0x89, 0x18, 0xd9, + 0x09, 0x1c, 0xa8, 0x24, 0x89, 0xad, 0x30, 0x1b, 0xfd, 0x7d, 0xfb, 0x99, 0x75, 0x36, 0x15, 0x48, + 0x96, 0x0d, 0xf9, 0xa1, 0x05, 0x48, 0x75, 0x06, 0x90, 0x0a, 0x65, 0x1e, 0x7d, 0x1d, 0xbd, 0xcf, + 0xfe, 0x25, 0xda, 0xdc, 0x21, 0xc4, 0x8b, 0xde, 0xe3, 0xe8, 0x02, 0x9c, 0xf2, 0xd0, 0x76, 0xa1, + 0x25, 0xae, 0x22, 0x59, 0x73, 0xf2, 0x90, 0x00, 0xeb, 0xe1, 0x09, 0x1c, 0xd8, 0xc7, 0xab, 0xb0, + 0xae, 0xc5, 0xf7, 0x51, 0x86, 0x1e, 0x06, 0xcb, 0x7d, 0xfa, 0x8f, 0xfd, 0xe6, 0xbf, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x08, 0xf3, 0x9e, 0x1d, 0x7e, 0x07, 0x00, 0x00, +}
diff --git a/feeds/availability_feed.proto b/feeds/availability_feed.proto new file mode 100644 index 0000000..e25bd0e --- /dev/null +++ b/feeds/availability_feed.proto
@@ -0,0 +1,249 @@ +syntax = "proto3"; + +package maps.booking.feeds; + +message FeedMetadata { + enum ProcessingInstruction { + // By default we will assume that this feed is an incremental feed. + PROCESS_UNKNOWN = 0; + + // This Feed message is one shard of a complete feed. Anything previously + // supplied by this partner will be deleted; the contents of this feed + // represent the entire state of the world. + PROCESS_AS_COMPLETE = 1; + + // This Feed message is one shard of an incremental feed. Existing entities + // will be left untouched except as modified in this feed. + PROCESS_AS_INCREMENTAL = 2; + } + + // Instructs us how to process the feed: either as a shard of a complete feed, + // or as a shard of an incremental update. + ProcessingInstruction processing_instruction = 1; + + // The current shard and total number of shards for this feed. + // + // Shard number is assumed to be zero-based. + // + // There does not need to be any relationship to the file name. + // + // Shards do not need to be transferred in order, and they may not be + // processed in order. + int32 shard_number = 2; + int32 total_shards = 3; + + // An identifier that must be consistent across all shards in a feed. + // This value must be globally unique across each feed type. + // + // This value ensures that complete feeds spanning multiple shards are + // processed together correctly. + // + // Clients only need to set this value when the processing_instruction is set + // to PROCESS_AS_COMPLETE and the feed spans multiple shards (defined by + // total_shards). + // + // Feeds that span multiple shards must set this nonce to the same value. + uint64 nonce = 5; + + // The timestamp at which this feed shard was generated. + // + // In Unix time format (seconds since the epoch). + int64 generation_timestamp = 4; +} + +message AvailabilityFeed { + FeedMetadata metadata = 1; + repeated ServiceAvailability service_availability = 2; +} + +message ServiceAvailability { + // If provided, we will consider the Availability entities provided to be a + // complete snapshot from [start_timestamp_restrict, end_timestamp_restrict). + // That is, all existing availability will be deleted if the following + // condition holds true: + // + // start_timestamp_restrict <= Availability.start_sec && + // Availability.start_sec < end_timestamp_restrict + // + // If a resource_restrict message is set, the condition is further restricted: + // + // Availability.resource.staff_id == resource_restrict.staff_id && + // Availability.resource.room_id == resource_restrict.room_id + // + // These fields are typically used to provide a complete update of + // availability in a given time range. + // + // Setting start_timestamp_restrict while leaving end_timestamp_restrict unset + // is interpreted to mean all time beginning at start_timestamp_restrict. + // + // Setting end_timestamp_restrict while leaving start_timestamp_restrict unset + // is interpreted to mean all time up to the end_timestamp_restrict. + // + // In Unix time format (seconds since the epoch). + int64 start_timestamp_restrict = 1; + int64 end_timestamp_restrict = 2; + + // If provided, the timestamp restricts will be applied only to the given + // merchant or service. + // + // These fields are typically used to provide complete snapshot of + // availability in a given range (defined above) for a specific merchant or + // service. + // + // Leaving these fields unset, or setting these to the empty string or null, + // is interpreted to mean that no restrict is intended. + string merchant_id_restrict = 3; + string service_id_restrict = 4; + + // Setting resources_restrict further restricts the scope of the update to + // just this set of resources. All id fields of the resources must match + // exactly. + Resources resources_restrict = 6; + + repeated Availability availability = 5; +} + +// An availability of the merchant's service, indicating time and number +// of spots. +// The availability feed should be a list of this message. +// Please note that it's up to the partner to call out all the possible +// availabilities. +// If a massage therapist is available 9am-12pm, and they provide +// one-hour massage sessions, the aggregator should provide the feed as +// availability {start_sec: 9am, duration: 60 minutes, ...} +// availability {start_sec: 10am, duration: 60 minutes, ...} +// availability {start_sec: 11am, duration: 60 minutes, ...} +// instead of +// availability {start_sec: 9am, duration: 180 minutes, ...} +// +message Availability { + // An opaque string from an aggregator to identify a merchant. + string merchant_id = 1; + // An opaque string from aggregator to identify a service of the + // merchant. + string service_id = 2; + // Start time of this availability, using epoch time in seconds. + int64 start_sec = 3; + // Duration of the service in seconds, e.g. 30 minutes for a chair massage. + int64 duration_sec = 4; + // Number of total spots and open spots of this availability. + // E.g. a Yoga class of 10 spots with 3 booked. + // availability {spots_total: 10, spots_open: 7 ...} + // E.g. a chair massage session which was already booked. + // availability {spots_total: 1, spots_open: 0 ...} + // + // Note: If sending requests using the availability compression format defined + // below, these two fields will be inferred. A Recurrence + // implies spots_total=1 and spots_open=1. A ScheduleException implies + // spots_total=1 and spots_open=0. + int64 spots_total = 5; + int64 spots_open = 6; + // An optional opaque string to identify this availability slot. If set, it + // will be included in the requests that book/update/cancel appointments. + string availability_tag = 7; + + // Optional resources used to disambiguate this availability slot from + // others when different staff, room, or party_size values are part + // of the service. + // + // E.g. the same Yoga class with two 2 instructors. + // availability { resources { staff_id: "1" staff_name: "Amy" } + // spots_total: 10 spots_open: 7 } + // availability { resources { staff_id: "2" staff_name: "John" } + // spots_total: 5 spots_open: 2 } + Resources resources = 8; + + // A list of ids referencing the payment options which can be used to pay + // for this slot. The actual payment options are defined at the Merchant + // level, and can also be shared among multiple Merchants. + // + // This field overrides any payment_option_ids specified in the service + // message. Similarly payment_option_ids specified here do NOT have to be + // present in the service message, though must be defined at the + // Merchant level. + repeated string payment_option_id = 9; + + // Recurrence messages are optional, but allow for a more compact + // representation of consistently repeating availability slots. They typically + // represent a day's working schedule. + // ScheduleException messages are then used to represent booked/unavailable + // time ranges within the work day. + // + // Requirements: + // 1. The expansion of availability slots or recurrences must NOT create + // identical slots. If the ids, start_sec, duration_sec, and resources + // match, slots are considered identical. + // 2. Do NOT mix the standard availability format and recurrence within the + // slots of a single service. Recurrence benefits merchants/services that + // offer appointments. The standard format is geared towards + // merchants/services with regularly scheduled classes. + message Recurrence { + // The inclusive maximum UTC timestamp the availability repeats until. + int64 repeat_until_sec = 1; + // Defines the time between successive availability slots. + // + // E.g. An availability with a duration of 20 min, a repeat_every_sec of + // 30 min, a start_sec of 9:00am, and a repeat_until_sec of 11:00am will + // yield slots at 9-9:20am, 9:30-9:50am, 10-10:20am, 10:30-10:50am, + // 11-11:20am. + int32 repeat_every_sec = 2; + } + // The recurrence information for the availability, representing more than one + // start time. A recurrence should contain appointments for one working day. + Recurrence recurrence = 10; + + // ScheduleException messages are used to represent booked/unavailable time + // ranges within the work day. As time slots are booked, the list of + // exceptions should grow to reflect the newly unavailable time ranges. + // The recurrence itself shouldn't be modified. + message ScheduleException { + // The time range of the exception. + TimeRange time_range = 1; + } + // When this service cannot be scheduled. To limit the number of + // schedule_exception messages consider joining adjacent exceptions. + repeated ScheduleException schedule_exception = 11; +} + +// A resource is used to disambiguate availability slots from one another when +// different staff, room or party_size values are part of the service. +// Multiple slots for the same service and time interval can co-exist when they +// have different resources. +message Resources { + // Optional id for a staff member providing the service. This field identifies + // the staff member across all merchants, services, and availability records. + // It also needs to be stable over time to allow correlation with past + // bookings. + // This field must be present if staff_name is present. + string staff_id = 1; + + // Optional name of a staff member providing the service. This field will be + // displayed to users making a booking, and should be human readable, as + // opposed to an opaque identifier. + // This field must be present if staff_id is present. + string staff_name = 2; + + // An optional id for the room the service is located in. This field + // identifies the room across all merchants, services, and availability + // records. It also needs to be stable over time to allow correlation with + // past bookings. + // This field must be present if room_name is present. + string room_id = 3; + + // An optional name for the room the service is located in. This + // field will be displayed to users making a booking, and should be human + // readable, as opposed to an opaque identifier. + // This field must be present if room_id is present. + string room_name = 4; + + // Applicable only for Dining: The party size which can be accommodated + // during this time slot. A restaurant can be associated with multiple Slots + // for the same time, each specifying a different party_size, if for instance + // 2, 3, or 4 people can be seated with a reservation. + int32 party_size = 5; +} + +message TimeRange { + int64 begin_sec = 1; + int64 end_sec = 2; +} \ No newline at end of file
diff --git a/proto/v3.proto b/proto/v3.proto new file mode 100644 index 0000000..1c217bb --- /dev/null +++ b/proto/v3.proto
@@ -0,0 +1,1085 @@ +syntax = "proto3"; + +package v3; + +// [START postaladdr_definition] +// The postal address for a merchant. +message PostalAddress { + // The country, e.g. "USA". (required) + string country = 1; + // The locality/city, e.g. "Mountain View". (required) + string locality = 2; + // The region/state/province, e.g. "CA". (required) + string region = 3; + // The postal code, e.g. "94043". (required) + string postal_code = 4; + // The street address, e.g. "1600 Amphitheatre Pkwy". (required) + string street_address = 5; +} +// [END postaladdr_definition] + +// [START geocoord_definition] +// The Geo data of a location, including latitude, longitude, and address. +message GeoCoordinates { + double latitude = 1; // In degrees. (optional) + double longitude = 2; // In degrees. (optional) + PostalAddress address = 3; // (required) +} +// [END geocoord_definition] + +// [START price_definition] +// The price of a service or a fee. +message Price { + // The price in micro-units of the currency. + // Fractions of smallest currency unit will be rounded using nearest even + // rounding. (e.g. For USD 2.5 cents rounded to 2 cents, 3.5 cents rounded to + // 4 cents, 0.5 cents rounded to 0 cents, 2.51 cents rounded to 3 cents). + // (required) + int64 price_micros = 1; + // The currency of the price that is defined in ISO 4217. (required) + string currency_code = 2; + // An optional and opaque string that identifies the pricing option that is + // associated with the extended price. (optional) + string pricing_option_tag = 3; +} +// [END price_definition] + +// [START taxrate_definition] +// A tax rate applied when charging the user for a service, and which can be set +// on either a per merchant, or per service basis. +message TaxRate { + // A tax rate in millionths of one percent, effectively giving 6 decimals of + // precision. For example, if the tax rate is 7.253%, this field should be set + // to 7253000. + // + // If this field is left unset or set to 0, the total price charged to a user + // for any service provided by this merchant is the exact price specified by + // Service.price. The service price is assumed to be exempt from or already + // inclusive of applicable taxes. Taxes will not be shown to the user as a + // separate line item. + // + // If this field is set to any nonzero value, the total price charged to a + // user for any service provided by this merchant will include the service + // price plus the tax assessed using the tax rate provided here. Fractions of + // the smallest currency unit (for example, fractions of one cent) will be + // rounded using nearest even rounding. Taxes will be shown to the user as a + // separate line item. (required) + int32 micro_percent = 1; +} +// [END taxrate_definition] + +// [START schedulingrules_definition] +// The scheduling rules for a service. +message SchedulingRules { + // The minimum advance notice in seconds required to book an appointment. + // (optional) + int64 min_advance_booking = 1; + + // The minimum advance notice in seconds required to cancel a booked + // appointment online. (optional) + int64 min_advance_online_canceling = 2; + + // The fee for canceling within the minimum advance notice period. + Price late_cancellation_fee = 3 [deprecated = true]; + + // The fee for no-show without canceling. + Price noshow_fee = 4 [deprecated = true]; +} +// [END schedulingrules_definition] + +// This defines the ingestion source type. +enum IngestionSource { + SOURCE_UNKNOWN = 0; + + // This ingestion is from an uploaded feed file. + SOURCE_FEED = 1; + + // This ingestion is from an API call. + SOURCE_API = 2; +} + +// An empty boilplate proto for the Ingestion Queue in Spanner. +message IngestionQueuePayload { +} + +// The types of content that we can ingest through feeds or APIs. +enum ContentType { + CONTENT_UNKNOWN = 0; + CONTENT_MERCHANT = 1; + CONTENT_SERVICE = 2; + CONTENT_AVAILABILITY = 3; + CONTENT_PAYMENT_OPTION = 4; + CONTENT_PAYMENT_OPTION_SERVICE = 5; +} + +message IngestionStatus { + // The status code of an Ingestion event: a feed upload or an API call. + // Only used for logging the ingestion status in the IngestionMetadata + // table, do NOT use it in the code's control flow. + enum Code { + // An unknown status for Ingestion, shouldn't use it. + STATUS_UNKNOWN = 0; + + // 1-99 for Feed upload. + // A feed has been uploaded. + STATUS_FEED_UPLOADED = 1; + // A feed has been added to the Ingestion Queue. + STATUS_FEED_ENQUEUED = 2; + // A feed has been picked up from the queue and started processing. + STATUS_FEED_PROCESSING_STARTED = 3; + // A feed has been processed successfully. + STATUS_FEED_PROCESSING_SUCCEEDED = 4; + // A feed has failed the processing. + STATUS_FEED_PROCESSING_FAILED = 5; + // A feed duplicate was uploaded. + STATUS_FEED_DUPLICATED = 6; + + // 101-199 for API. + // An API has been called. + STATUS_API_CALLED = 101; + // An API has been processed successfully. + STATUS_API_PROCESSING_SUCCEEDED = 102; + // An API has failed the processing. + STATUS_API_PROCESSING_FAILED = 103; + } + + // The code of the status. + Code code = 1; + + // Microseconds since epoch when the ingestion updates its status code. + int64 timestamp_micros = 2; + + // A human description of the error if any. + string internal_error_details = 3; + string partner_visible_error_details = 4; +} + +// [START timerange_definition] +// A closed-open time range, i.e. [begin_sec, end_sec) +message TimeRange { + // Seconds of UTC time since Unix epoch (required) + int64 begin_sec = 1; + // Seconds of UTC time since Unix epoch (required) + int64 end_sec = 2; +} +// [END timerange_definition] + +// [START pricetype_definition] +// Defines how a total price is determined from an availability. +enum PriceType { + // The price is for a fixed amount. This is the default value if the field is + // not set. + FIXED_RATE_DEFAULT = 0; + // The price specified is per person, and the total price is calculated + // according to the party size specified in Resources as + // price_micros * party_size. A PER_PERSON price must be accompanied by a + // party size in the availability resources. If it is not, a party size of one + // is used. + PER_PERSON = 1; +} +// [END pricetype_definition] + +// [START noshowfee_definition] +// A fee that a user may be charged if they have made a booking but do not +// show up. +message NoShowFee { + // The amount the user may be charged if they do not show up for their + // reservation. + Price fee = 1; + + // Defines how the fee is determined from the availability. + PriceType fee_type = 3; +} +// [END noshowfee_definition] + +// [START deposit_definition] +// A deposit that the user may be charged or have a hold on their credit card +// for. +message Deposit { + // Deposit amount. + Price deposit = 1; + + // Minimum advance cancellation for the deposit. + int64 min_advance_cancellation_sec = 2; + + // Defines how the deposit is determined from the availability. + PriceType deposit_type = 3; +} +// [END deposit_definition] + +// [START RequireCreditCard_definition] +// Defines whether a credit card is required in order to book an appointment. +enum RequireCreditCard { + // The credit card requirement is not explicitly specified and the + // behaviour is identical to the one specified for CONDITIONAL. + REQUIRE_CREDIT_CARD_UNSPECIFIED = 0; + + // Google will require a credit card for the booking if any of the following + // conditions are met: + // * the availability has a price and the prepayment_type is REQUIRED + // * the no_show_fee is set + // * the deposit field is set. + REQUIRE_CREDIT_CARD_CONDITIONAL = 1; + + // A credit card is always required in order to book this availability + // regardless of other field values. + REQUIRE_CREDIT_CARD_ALWAYS = 2; +} +// [END RequireCreditCard_definition] + +// [START ActionLink_definition] +// An action URL with associated language and list of countries restricted to. +message ActionLink { + // The entry point URL for this action link. + string url = 1; + + // The BCP-47 language tag identifying the language in which the content + // from this URI is available. + string language = 2; + + // ISO 3166-1 alpha-2 country code. Leave empty for unrestricted visibility. + repeated string restricted_country = 3; +} +// [END ActionLink_definition] + +// [START message_slot] +// An inventory slot +message Slot { + // ID of the merchant for the slot (required) + string merchant_id = 1; + + // ID of the merchant service (required) + string service_id = 2; + + // Start time of the appointment slot in seconds of UTC time since Unix epoch. + // (required) + int64 start_sec = 3; + + // Duration of the appointment slot (required) + int64 duration_sec = 4; + + // Opaque tag that identifies the availability slot and matches the value + // provided in the availability feed (optional) + string availability_tag = 5; + + // The set of resources that disambiguates the appointment slot, e.g. by + // indicating the staff member and room selected by the user (optional) + ResourceIds resources = 6; +} +// [END message_slot] + +// [START message_lease] +// Temporary lease for an inventory slot +message Lease { + // ID of the lease. + // Not populated in CreateLeaseRequest. The value is chosen by the partner and + // has to be returned in the response of CreateLease. (required) + string lease_id = 1; + + // The appointment slot that the lease is created for. (required) + Slot slot = 2; + + // Unique identifier for this lease, chosen by Reserve with Google. Serves as + // an idempotency token for CreateLease requests. (required) + string user_reference = 3; + + // Expiration time of the lease in UTC Timestamp (required) + int64 lease_expiration_time_sec = 4; +} + +// Reference to a Lease that has been created via CreateLease. +message LeaseReference { + // Lease ID (required) + string lease_id = 1; +} +// [END message_lease] + +// [START message_booking] +// A booking for an inventory slot +message Booking { + // ID of this booking (required) + string booking_id = 1; + + // The appointment slot of this booking (required) + Slot slot = 2; + + // Personal information of the user making the appointment (required) + UserInformation user_information = 3; + + // Status of the booking (required) + BookingStatus status = 4; + + // Information about payment transactions that relate to the booking. + // (optional) + PaymentInformation payment_information = 5; +} +// [END message_booking] + +// [START user_definition] +// Personal information about the person making a booking +message UserInformation { + // Unique ID of the user to the partner, chosen by Reserve with Google. + // (required) + string user_id = 1; + + // Given name of the user (required) + string given_name = 2; + + // Family name of the user (required) + string family_name = 3; + + // Address of the user (optional) + PostalAddress address = 4; + + // Phone number of the user (required) + string telephone = 5; + + // Email address of the user (required) + string email = 6; +} +// [END user_definition] + +// [START paymentprocessing_definition] +message PaymentProcessingParameters { + enum PaymentProcessor { + PAYMENT_PROCESSOR_UNSPECIFIED = 0; + PROCESSOR_STRIPE = 1; + PROCESSOR_BRAINTREE = 2; + } + // The payment processor used to process payment for a given booking. + // (required) + // + // Replaced by the payment_processor field. + PaymentProcessor processor = 1 [deprecated = true]; + + // The token representing the payment method that will be used to pay + // for this booking. This token can be only used once. This token can be + // only used for the merchant associated with this booking. + // + // Each processor may choose its own format for this field. + // An example of Stripe's token is "tok_1C3orL2eZvKYlo2CxReMgS4K". + // + // Replaced by unparsed_payment_method_token, which contains + // payment_method_token as one of its fields. + // For example, for Stripe, unparsed_payment_method_token is a serialized + // JSON object documented at https://stripe.com/docs/api#token_object. + // payment_method_token is the 'id' field parsed out of that. + string payment_method_token = 2 [deprecated = true]; + + // The full token received from Google Payments. This is typically a + // serialized JSON object. See documentation from Google Payments and your + // payment processor for the JSON format of the token for your processor. + // https://developers.google.com/pay/api/#participating-google-pay-processors + // + // This token can only be used once, and only for the merchant associated with + // this booking. + string unparsed_payment_method_token = 5; + + // The payment processor API version that the given payment token is valid + // for. + // + // Each processor may choose its own format for this field. + // Stripe uses a date (e.g. "2017-06-15"). (required) + string version = 3; + + // The payment processor whose configuration was used to generate this token. + // (required) + string payment_processor = 4; +} +// [END paymentprocessing_definition] + +// [START paymentoption_definition] +enum PaymentOptionType { + PAYMENT_OPTION_TYPE_UNSPECIFIED = 0; + PAYMENT_OPTION_SINGLE_USE = 1; + PAYMENT_OPTION_MULTI_USE = 2; + PAYMENT_OPTION_UNLIMITED_USE = 3; +} +// [END paymentoption_definition] + +// [START userpaymentoption_definition] +// This describes a payment option, such as a pack, membership, or +// single-session pass after it has been purchased by a user. It includes an +// identifier for the user payment option, as well as some information about +// the payment option with which it is associated. +message UserPaymentOption { + // A unique identifier for the user payment option. This Id MUST be unique + // for all UserPaymentOptions across all merchants and users. (required) + string user_payment_option_id = 1; + // The user payment option will be valid (usable) between start_time and + // end_time set in UTC. Attempts to use a user payment option to make a + // booking outside of this interval will fail. (both optional) + int64 valid_start_time_sec = 2; + int64 valid_end_time_sec = 3; + // The type of the payment option associated with this user payment option. + // This can be unlimited for a membership or subscription, multi-use for a + // pack, or single-use. (required) + PaymentOptionType type = 4; + // The original number of uses for this user payment option when it was + // purchased. This value is ignored for unlimited payment options. (required) + int32 original_count = 5; + // The number of uses remaining for this user payment option. If this number + // is 0 for a pack, attempts to use this payment option to make a booking will + // fail. (required) + int32 current_count = 6; + // The id of the payment option that has been used to purchase this user + // payment option. (required) + string payment_option_id = 7; +} +// [END userpaymentoption_definition] + +// [START paymentinfo_definition] +// Payment details that are sent when creating a new booking. +message PaymentInformation { + // Prepayment status of the booking. + // If the prepayment_status is PREPAYMENT_PROVIDED, then + // payment_transaction_id contains the associated unique transaction id for + // the purchase. + // If the prepayment status is PREPAYMENT_REFUNDED, then + // payment_transaction_id contains the associated unique transaction id for + // the refund. (required) + PrepaymentStatus prepayment_status = 1; + + // Unique identifier for a payment transaction associated with the booking. + // Empty if not applicable. (required) + string payment_transaction_id = 2; + + // These fields must match the service price (specified in the Services feed) + // or the PaymentOption corresponding with this service. + // They are included in the booking request and response to verify that + // the price indicated in the feed has not changed since the last feed + // update. + // + // The price of the booking or order, exclusive of any taxes. + // Existence of price or taxes does not imply that they have been paid, + // prepayment_state should be used for that purpose. (required) + Price price = 3; + // Taxes that are calculated to be paid for this booking. + // This field can only be absent in one of the following cases: + // (1) the price is exempt from or already inclusive of applicable taxes; or + // (2) the break down between taxes and fees is not available. + // (required when neither of the above holds) + Price tax_amount = 4; + + // Who handles payment processing? + // If payment is processed by the partner, CreateBooking request will + // include additional parameters (PaymentProcessingParameters) indicating + // the payment method to be used to process the payment. + enum PaymentProcessedBy { + PAYMENT_PROCESSED_BY_UNSPECIFIED = 0; + PROCESSED_BY_GOOGLE = 1; + PROCESSED_BY_PARTNER = 2; + } + // Whether the partner or Google processed the payment. (required) + PaymentProcessedBy payment_processed_by = 5; + + // The id of the payment option or user payment option associated with the + // booking. + // If a payment option is purchased as part of a booking, payment_option_id + // will be set with the id of that payment option. + // If an already purchased user payment option is being used to pay for a + // booking, user_payment_option_id will be set with the id of that user + // payment option. + // When included as part of a response proto, the user_payment_option_id + // should be set and must match the UserPaymentOption that is returned in the + // RPC response (e.g. the user_payment_option returned in + // CreateBookingResponse). (one of these required) + oneof payment_id { + // The id of the payment option associated with this booking. If this field + // is populated, price (and tax_amount, if applicable) must be populated as + // well. + string payment_option_id = 6; + + // The id of the user payment option used to pay for this booking. + string user_payment_option_id = 7; + } + // Defines how a deposit may be charged to the user. If there is a deposit, + // this field should be set. (optional) + Deposit deposit = 8; + // Defines a no show fee that may be charged to the user. If the user can be + // charged a no show fee, this field should be set. (optional) + NoShowFee no_show_fee = 9; + + // Total processing fees & taxes that the user needs to pay for the order; + // only applicable to partners that handle order based booking (e.g., with + // CreateOrder method). (optional) + Price fees_and_taxes = 10; +} +// [END paymentinfo_definition] + +// [START bookingstatus_definition] +// Status of a booking. +// +// Updating booking status does not change the status of the associated payment. +// Prepayment status updates should be done using the PrepaymentStatus enum. +// +// nextID: 6 +enum BookingStatus { + // Not specified. + BOOKING_STATUS_UNSPECIFIED = 0; + // Booking has been confirmed + CONFIRMED = 1; + // Booking is awaiting confirmation by the merchant before it can transition + // into CONFIRMED status + PENDING_MERCHANT_CONFIRMATION = 2; + // Booking has been canceled on behalf of the user. + // The merchant can still trigger a manual refund. + CANCELED = 3; + // User did not show for the appointment + NO_SHOW = 4; + // User did not show for the appointment in violation of the cancellation + // policy. + NO_SHOW_PENALIZED = 5; +} +// [END bookingstatus_definition] + +// [START creditcardtype_definition] +// Used when booking/order failure cause is PAYMENT_ERROR_CARD_TYPE_REJECTED to +// indicate the type of credit card that was rejected. +enum CreditCardType { + // Default value. Used if credit card type does not match to one below. + CREDIT_CARD_TYPE_UNSPECIFIED = 0; + VISA = 1; + MASTERCARD = 2; + AMERICAN_EXPRESS = 3; + DISCOVER = 4; +} +// [END creditcardtype_definition] + +// [START bookingfailure_definition] +// Status data that conveys why (1) creating a lease or (2) creating or updating +// a booking fails. +// BookingFailure is intended to primarily capture business logic errors. +message BookingFailure { + enum Cause { + // Default value: Don't use; amounts to an "unknown error" + CAUSE_UNSPECIFIED = 0; + // The referenced availability slot is not available any longer. + SLOT_UNAVAILABLE = 1; + // The user has already booked an appointment for the referenced + // availability slot. + SLOT_ALREADY_BOOKED_BY_USER = 2; + // The lease (if provided) has expired and cannot be used any longer to + // complete the requested booking. + LEASE_EXPIRED = 3; + // The requested cancellation cannot be performed at the current time due + // to time restrictions in the merchant's cancellation policy. + OUTSIDE_CANCELLATION_WINDOW = 4; + // An error was encountered while processing the payment because the + // provided credit card type was not accepted by the merchant. The credit + // card type must be supplied in rejected_card_type. + PAYMENT_ERROR_CARD_TYPE_REJECTED = 5; + // An error was encountered while processing the payment because the + // provided credit card was declined. + PAYMENT_ERROR_CARD_DECLINED = 6; + // An error was encountered with the pack/membership used to pay for the + // booking. There could be no valid uses left, it could have expired, etc. + PAYMENT_OPTION_NOT_VALID = 7; + // An error was encountered while processing the payment for this booking. + // Use this value to indicate a general payment related error, only if the + // error does not match to a specific payment error above. + PAYMENT_ERROR = 8; + // User cannot use the given payment option (e.g. user trying to use a + // first time price for the second time). + USER_CANNOT_USE_PAYMENT_OPTION = 9; + // A booking that the user tried to cancel has already been cancelled. + BOOKING_ALREADY_CANCELLED = 10; + // A booking that the user tried to cancel is not cancellable. + BOOKING_NOT_CANCELLABLE = 11; + } + // The reason why the booking failed. (required) + Cause cause = 1; + + // (required only if cause is PAYMENT_ERROR_CARD_TYPE_REJECTED) + CreditCardType rejected_card_type = 2; + + // This optional field is used for the partner to include additional + // information for debugging purpose only. (optional) + string description = 3; +} +// [END bookingfailure_definition] + +// [START prepaymentstatus_definition] +// Prepayment status of a booking. +// Updating payment status will trigger an update on the payment status of the +// associated booking (if applicable). +// Currently, the only supported transition is from PREPAYMENT_PROVIDED to +// PREPAYMENT_REFUNDED, which will initiate a non-reversible refund on the +// associated payment transaction. +enum PrepaymentStatus { + // Not specified, defaults to PREPAYMENT_NOT_PROVIDED. + PREPAYMENT_STATUS_UNSPECIFIED = 0; + // The fee for the booking has been paid in advance. + PREPAYMENT_PROVIDED = 1; + // The fee for the booking has not been paid in advance. + PREPAYMENT_NOT_PROVIDED = 2; + // The fee was previously PREPAYMENT_PROVIDED but has now been refunded. + PREPAYMENT_REFUNDED = 3; + // The fee was previously PREPAYMENT_PROVIDED but now has been credited + // (user given a UserPaymentOption as a voucher for the booking). + // If this is set, the response should also include the updated + // UserPaymentOption. + PREPAYMENT_CREDITED = 4; +} +// [END prepaymentstatus_definition] + +// [START message_slot_availability] +// An inventory slot and associated count of open spots. +message SlotAvailability { + Slot slot = 1; + // Number of available spots. + // 0 indicates that the appointment slot is not available. (required) + int32 count_available = 2; +} +// [END message_slot_availability] + +// [START message_availability_update] +// An update to one ore more slots indicating that the availability for the +// associated time has potentially changed. +message AvailabilityUpdate { + repeated SlotAvailability slot_availability = 1; +} +// [END message_availability_update] + +// [START resources_definition] +// Resource specification that disambiguates an appointment slot +message ResourceIds { + // The staff ID as provided in the feed or empty if not applicable or no staff + // was selected. (optional) + string staff_id = 1; + // The room ID as provided in the feed or empty if not applicable or no room + // was selected. (optional) + string room_id = 2; + // For Dining Reservations only: the number of seats requested in the booking. + // (optional) + int32 party_size = 3; +} +// [END resources_definition] + +// [START tickettype_definition] +// TicketType is used to differentiate among tickets (where a ticket can be a +// spot on a raft trip, an admission to a museum, etc.) with different prices +// and/or availabilities due to different user types or different service +// attributes. +message TicketType { + // The ticket id is used to differentiate among different ticket types of the + // same service, and is only expected to be unique within a service. + string ticket_type_id = 1; + + // This can be user visible, e.g., “adult”, "child", “veteran”, “Row J”, etc. + string short_description = 2; + + // The price of a single ticket of this type, exclusive of any taxes. The tax + // rate of Service is applied to its tickets. + Price price = 3; +} +// [END tickettype_definition] + +// [START lineitem_definition] +// A single item in an order--the booking of a single service in a single time +// slot. +message LineItem { + // ID of the merchant service. (required) + string service_id = 1; + // Start time of the appointment slot in seconds of UTC time since Unix epoch. + // (required) + int64 start_sec = 2; + // Duration of the appointment slot in seconds. (required) + int64 duration_sec = 3; + + message OrderedTickets { + string ticket_id = 1; + int32 count = 2; + } + // Number of tickets ordered by type. + repeated OrderedTickets tickets = 4; + + // In handling CreateOrderRequest and CheckOrderFulfillabilityRequest, + // the total price (excluding taxes) of the item must be verified to guard + // against price changes. In CreateOrderResponse and + // CheckOrderFulfillabilityResponse, the price should be updated to the + // correct value if the value from the request was incorrect or outdated. + // (reqired) + Price price = 5; + + // Status of the line item. (required in CreateOrderResponse and + // ListOrdersResponse; should not be set in requests) + BookingStatus status = 6; +} +// [END lineitem_definition] + +// [START lineitemfulfillability_definition] +// Fulfillability of a line item. +message LineItemFulfillability { + // The line item of question. (required) + LineItem item = 1; + + // The result of a line item fulfillability check. + enum ItemFulfillabilityResult { + // Default value: Don't use. + ITEM_FULFILLABILITY_RESULT_UNSPECIFIED = 0; + // This line item can be fulfilled. + CAN_FULFILL = 1; + // No adequate availability for the slot requested. + SLOT_UNAVAILABLE = 2; + // The combination of ticket types requested cannot be fulfilled. + UNFULFILLABLE_TICKET_COMBINATION = 3; + // The total price of this line item is not incorrect. + INCORRECT_PRICE = 4; + // The line item cannot be fulfilled for reasons that do not fall into + // the categories above. + ITEM_UNFULFILLABLE_OTHER_REASON = 5; + } + // (required) + ItemFulfillabilityResult result = 2; + // Additional description of the reason if the item is unfulfillable. + // (optional) + string unfulfillable_reason = 3; + // Updated availability for this slot can be piggybacked in + // CheckOrderFulfillabilityResponse. (optional) + int32 spots_open = 4; + // Updated ticket types can be piggybacked in + // CheckOrderFulfillabilityResponse. If non-empty, all available ticket types + // for this slot with up-to-date prices should be listed without omitting any. + // (optional) + repeated TicketType ticket_type = 5; +} +// [END lineitemfulfillability_definition] + +// [START orderfulfillability_definition] +message OrderFulfillability { + // The result of an order fulfillability check. + enum OrderFulfillabilityResult { + // Default value: Don't use. + ORDER_FULFILLABILITY_RESULT_UNSPECIFIED = 0; + // The order can be fulfilled. + CAN_FULFILL = 1; + // The order cannot be fulfilled due to one or more unfulfillable line + // item(s). + UNFULFILLABLE_LINE_ITEM = 2; + // The combination of the line items requested cannot be fulfilled. + UNFULFILLABLE_SERVICE_COMBINATION = 3; + // The order cannot be fulfilled due to reasons that do not fall into the + // categories above. + ORDER_UNFULFILLABLE_OTHER_REASON = 4; + } + + OrderFulfillabilityResult result = 1; + // Fulfillability results of all line items in this order (required). + repeated LineItemFulfillability item_fulfillability = 2; + // Additional description of the reason if the item is unfulfillable. + // (optional) + string unfulfillable_reason = 3; +} +// [END orderfulfillability_definition] + +// [START order_definition] +// An order for service appointments with a merchant. +message Order { + // ID of this order, chosen by the booking partner who handles the order + // (required in CreateOrderResponse and ListOrdersResponse, must not be set in + // CreateOrderRequest) + string order_id = 1; + // Personal information of the user making the order (required) + UserInformation user_information = 2; + // Information about payment transactions that relate to the order. + // (optional) + PaymentInformation payment_information = 3; + // The merchant that all services in this order belong to. + string merchant_id = 4; + // Line items in this order. + repeated LineItem item = 5; +} +// [END order_definition] + +// [START orderfailure_definition] +// Status data that conveys why creating an order fails. +// OrderFailure is intended to primarily capture business logic errors. +message OrderFailure { + enum Cause { + // Default value: Don't use; amounts to an "unknown error" + CAUSE_UNSPECIFIED = 0; + // The order is no longer fulfillable. + ORDER_UNFULFILLABLE = 1; + // An error was encountered while processing the payment because the + // provided credit card type was not accepted by the merchant. The credit + // card type must be supplied in rejected_card_type. + PAYMENT_ERROR_CARD_TYPE_REJECTED = 2; + // An error was encountered while processing the payment because the + // provided credit card was declined. + PAYMENT_ERROR_CARD_DECLINED = 3; + // An error was encountered while processing the payment for this order. + // Use this value to indicate a general payment related error, only if the + // error does not match to a specific payment error above. + PAYMENT_ERROR = 4; + } + // The reason why the order failed. (required) + Cause cause = 1; + + // (required only if cause is ORDER_UNFULFILLABLE) + OrderFulfillability fulfillability = 2; + + // (required only if cause is PAYMENT_ERROR_CARD_TYPE_REJECTED) + CreditCardType rejected_card_type = 3; + + // This optional field is used for the partner to include additional + // information for debugging purpose only. (optional) + string description = 4; +} +// [END orderfailure_definition] + +// [START method_check_availability] +// Request to check availability for a Slot. +message CheckAvailabilityRequest { + // The appointment slot that is being checked (required) + Slot slot = 1; +} + +// Response for the CheckAvailability RPC with the availability of the +// appointment slot. +message CheckAvailabilityResponse { + // The requested slot. (required) + Slot slot = 1; + // Number of available spots. + // 0 indicates that the appointment slot is not available. (required) + int32 count_available = 2; + // This enum indicates what requirements exist for the user to acknowledge or + // view the requested slots duration/end time. + enum DurationRequirement { + // The handling of the end time is not specified. This is the default. + DURATION_REQUIREMENT_UNSPECIFIED = 0; + + // The end time is not shown to the user. + DO_NOT_SHOW_DURATION = 1; + + // The end time has to be shown to the user before an appointment can be + // made. + MUST_SHOW_DURATION = 2; + } + // The requirement to show the slots duration and/or endtime. This field will + // be ignored if the slot is unavailable. (optional) + DurationRequirement duration_requirement = 3; + + // Optionally, the partner can return additional updated information about the + // availability for this merchant if this information is present when + // responding to the CheckAvailabilityRequest and if there is no negative + // impact on the CheckAvailability request latency. + // For instance an entire day of merchant availability for a superset of + // resources can be returned here. + AvailabilityUpdate availability_update = 4; +} +// [END method_check_availability] + +// [START method_get_booking_status] +// Request to get booking status and prepayment status for a Booking. +message GetBookingStatusRequest { + // ID of the existing booking (required) + string booking_id = 1; +} + +// Response for the GetBookingStatus RPC with booking status and prepayment +// status. +message GetBookingStatusResponse { + // ID of the booking (required) + string booking_id = 1; + + // Status of the booking (required) + BookingStatus booking_status = 2; + + // Prepayment status of the booking (required) + PrepaymentStatus prepayment_status = 3; +} +// [END method_get_booking_status] + +// [START method_check_order_fulfillability] +// Request to check the fulfillability of an order. +message CheckOrderFulfillabilityRequest { + // The merchant that this order is intended for. (required) + string merchant_id = 1; + + // The line items in this order. All services requested must belong to the + // specified merchant. (required) + repeated LineItem item = 2; +} + +// Response for the CheckOrderfulfillabilityRequest. +message CheckOrderFulfillabilityResponse { + // Fulfillability status of the order, potentially contains updated + // availabilities and prices of the requested line item. (required) + OrderFulfillability fulfillability = 1; + + // Total processing fees & taxes that need to be paid for this order. + // (required) + Price fees_and_taxes = 2; +} +// [END method_check_order_fulfillability] + +// [START method_create_booking] +// Request to create a Booking for an inventory slot. Consumes the lease if +// provided. +message CreateBookingRequest { + // The inventory slot that is being requested to make this booking. + // If lease_ref is provided, slot must match the lease; slot is provided for + // the partner to verify the lease information. + // If lease_ref is absent, then create the booking for the slot. (required) + Slot slot = 1; + + // The lease that is being confirmed to make this booking. + // If lease_ref is provided, then create the booking using the lease. + // (optional) + LeaseReference lease_ref = 2; + + // Personal information of the user making the appointment (required) + UserInformation user_information = 3; + + // Information about payments. When payment authorizations are handled by + // Google, if the booking request does not succeed, payment authorizations are + // automatically canceled. (optional) + PaymentInformation payment_information = 4; + + // The parameters to be used if the payment is processed by the partner + // (i.e. payment_information.payment_processed_by is equal to + // PROCESSED_BY_PARTNER). (optional) + PaymentProcessingParameters payment_processing_parameters = 5; + + // Idempotency token for CreateBooking requests. (required) + string idempotency_token = 6; + + // A string from the user which contains any special requests or additional + // information that they would like to notify the merchant about. (optional) + string additional_request = 7; +} + +// Response with the created Booking for an inventory slot. +message CreateBookingResponse { + // The created booking (required) + Booking booking = 1; + + // The updated user payment option used in this booking. + // If a new payment option was purchased to pay for the booking, this should + // be a newly created user payment option. + // If an already purchased user payment option was used for this booking, + // this should reflect an updated version of that user payment option. + // (optional) + UserPaymentOption user_payment_option = 2; + + // If creating a booking fails, this field should reflect the business logic + // error (e.g., slot has become unavailable) and all other fields in the + // CreateBookingResponse message are expected to be unset. (required if + // failure occurs) + BookingFailure booking_failure = 3; +} +// [END method_create_booking] + +// [START method_create_order] +// Request to create an order. +message CreateOrderRequest { + // The order to create. (required) + Order order = 1; + + // The parameters to be used if the payment is processed by the partner + // (i.e. order.payment_information.payment_processed_by is equal to + // PROCESSED_BY_PARTNER). (required if payment is processed by the partner) + PaymentProcessingParameters payment_processing_parameters = 2; + + // Idempotency token for CreateOrder requests. (required) + string idempotency_token = 3; +} + +// Response for the CreateOrderRequest. +message CreateOrderResponse { + // The order created. (required) + Order order = 1; + + // If creating an order fails, this field should reflect the business logic + // error (e.g., slot has become unavailable or price has changed) and all + // other fields in the CreateOrderResponse are expected to be unset. (required + // if failure occurs) + OrderFailure order_failure = 2; +} +// [END method_create_order] + +// [START method_create_lease] +// Request to create a Leaese for a slot in the inventory. The expiration time +// in the returned Lease may be modified by the backend, e.g. if the requested +// lease period is too long. +message CreateLeaseRequest { + // The lease to be created with information about the appointment slot + // (required) + Lease lease = 1; +} + +// Response for the CreateLease RPC with the created Lease. +message CreateLeaseResponse { + // The created Lease (required) + Lease lease = 1; + + // If creating a lease fails, this field should reflect the business logic + // error (e.g., slot has become unavailable) and lease field is expected to be + // unset. (required if failure occurs) + BookingFailure booking_failure = 2; +} +// [END method_create_lease] + +// [START method_list_bookings] +// Request to list all bookings for a user +message ListBookingsRequest { + // ID of the user (required) + string user_id = 1; +} + +// Response for the ListBookings RPC with all bookings for the requested user. +message ListBookingsResponse { + // All bookings of the user (required) + repeated Booking bookings = 1; +} +// [END method_list_bookings] + +// [START method_list_orders] +// Request to list orders. +message ListOrdersRequest { + // ID of the user (required only if order_id is not set). + string user_id = 1; + // If set, return only the specified orders; otherwise, return all orders of + // the user. (required only if user_id is not set). + repeated string order_id = 2; +} + +// Response for the ListOrders RPC. +message ListOrdersResponse { + // All requested orders (required) + repeated Order order = 1; +} +// [END method_list_orders] + +// [START method_update_booking] +// Request to update a Booking. +message UpdateBookingRequest { + // The booking to be updated + // The following fields can be set in a booking: + // - status, to cancel a booking. + // - start_time and duration in the slot, to reschedule a booking. (required) + Booking booking = 1; +} + +// Response with the updated Booking. +message UpdateBookingResponse { + // The updated booking (required) + Booking booking = 1; + + // The updated user payment option originally used to pay for this booking. + // This should be set if the UpdateBookingRequest results in a change to + // the UserPaymentOption. + // For instance, if the booking is canceled, the UserPaymentOption should + // reflect an additional credit to the user. In the case of a multi-use + // payment option, the current_count should be increased by one to + // allow the user to create another booking with this payment option. In the + // case of a single-use payment option, a new single-use user payment option + // should be returned. (required if altered in update) + UserPaymentOption user_payment_option = 2; + + // If updating a booking fails, this field should reflect the business logic + // error (e.g., booking is not cancellable) (required if failure occurs) + BookingFailure booking_failure = 3; +} +// [END method_update_booking]
diff --git a/testclient/main.go b/testclient/main.go new file mode 100644 index 0000000..522df19 --- /dev/null +++ b/testclient/main.go
@@ -0,0 +1,308 @@ +/* +Copyright 2017 Google Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package main + +import ( + "flag" + "fmt" + "log" + "os" + "path/filepath" + "time" + + "github.com/maps-booking/api" + "github.com/maps-booking/utils" + + fpb "github.com/maps-booking/feeds" + mpb "github.com/maps-booking/v3" +) + +const logFile = "http_test_client_log_" + +var ( + serverAddr = flag.String("server_addr", "example.com:80", "Your http server's address in the format of host:port") + usernamePassword = flag.String("username_password", "", "(eg 'username:password') credentials for your server. Leave blank to bypass authentication.") + testSlots = flag.Int("num_test_slots", 10, "Maximum number of slots to test from availability_feed. Slots will be selected randomly") + allFlows = flag.Bool("all_tests", false, "Whether to test all endpoints.") + healthFlow = flag.Bool("health_check_test", false, "Whether to test the Health endpoint.") + checkFlow = flag.Bool("check_availability_test", false, "Whether to test the CheckAvailability endpoint.") + bookFlow = flag.Bool("booking_test", false, "Whether to test the CreateBooking endpoint.") + listFlow = flag.Bool("list_bookings_test", false, "Whether to test the ListBookings endpoint") + statusFlow = flag.Bool("booking_status_test", false, "Whether to test the GetBookingStatus endpoint.") + rescheduleFlow = flag.Bool("rescheduling_test", false, "Whether to test the UpdateBooking endpoint.") + cancelAllBookings = flag.Bool("cancel_all_bookings", false, "This option assumes that the ListBookings and UpdateBooking endpoints are fully functional. This is a convenience flag for purging your system of all previously created bookings.") + availabilityFeed = flag.String("availability_feed", "", "Absolute path to availability feed required for all tests except health. Feeds can be in either json or pb3 format") + outputDir = flag.String("output_dir", "", "Absolute path of dir to dump log file.") +) + +type counters struct { + TotalSlotsProcessed int + HealthCheckSuccess bool + CheckAvailabilitySuccess int + CheckAvailabilityErrors int + CreateBookingSuccess int + CreateBookingErrors int + ListBookingsSuccess bool + GetBookingStatusSuccess int + GetBookingStatusErrors int + CancelBookingsSuccess int + CancelBookingsErrors int + ReschedulingSuccess bool +} + +// GenerateBookings creates bookings from an availability feed. +func GenerateBookings(av []*fpb.Availability, stats *counters, conn *api.HTTPConnection) api.Bookings { + log.Println("no previous bookings to use, acquiring new inventory") + utils.LogFlow("Generate Fresh Inventory", "Start") + defer utils.LogFlow("Generate Fresh Inventory", "End") + + var out api.Bookings + totalSlots := len(av) + for i, a := range av { + if err := api.CheckAvailability(a, conn); err != nil { + log.Printf("%s. skipping slot %d/%d", err.Error(), i, totalSlots) + stats.CheckAvailabilityErrors++ + continue + } + stats.CheckAvailabilitySuccess++ + + booking, err := api.CreateBooking(a, conn) + if err != nil { + log.Printf("%s. skipping slot %d/%d", err.Error(), i, totalSlots) + stats.CreateBookingErrors++ + continue + } + out = append(out, booking) + stats.CreateBookingSuccess++ + } + return out +} + +func createLogFile() (*os.File, error) { + var err error + outPath := *outputDir + if outPath == "" { + outPath, err = os.Getwd() + if err != nil { + return nil, err + } + } + + now := time.Now().UTC() + nowString := fmt.Sprintf("%d-%02d-%02d_%02d-%02d-%02d", now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second()) + outFile := filepath.Join(outPath, fmt.Sprintf("%s%s", logFile, nowString)) + + return os.Create(outFile) +} + +func logStats(stats counters) { + log.Println("\n************* Begin Stats *************\n") + var totalErrors int + if *healthFlow || *allFlows { + if stats.HealthCheckSuccess { + log.Println("HealthCheck Succeeded") + } else { + totalErrors++ + log.Println("HealthCheck Failed") + } + } + if *checkFlow || *allFlows { + totalErrors += stats.CheckAvailabilityErrors + log.Printf("CheckAvailability Errors: %d/%d", stats.CheckAvailabilityErrors, stats.CheckAvailabilityErrors+stats.CheckAvailabilitySuccess) + } + if *bookFlow || *allFlows { + totalErrors += stats.CreateBookingErrors + log.Printf("CreateBooking Errors: %d/%d", stats.CreateBookingErrors, stats.CreateBookingErrors+stats.CreateBookingSuccess) + } + if *listFlow || *allFlows { + if stats.ListBookingsSuccess { + log.Println("ListBookings Succeeded") + } else { + totalErrors++ + log.Println("ListBookings Failed") + } + } + if *statusFlow || *allFlows { + totalErrors += stats.GetBookingStatusErrors + log.Printf("GetBookingStatus Errors: %d/%d", stats.GetBookingStatusErrors, stats.GetBookingStatusErrors+stats.GetBookingStatusSuccess) + } + if *rescheduleFlow || *allFlows { + if stats.ReschedulingSuccess { + log.Println("Rescheduling Succeeded") + } else { + totalErrors++ + log.Println("Rescheduling Failed") + } + } + + log.Println("\n\n\n") + if totalErrors == 0 { + log.Println("All Tests Pass!") + } else { + log.Printf("Found %d Errors", totalErrors) + } + + log.Println("\n************* End Stats *************\n") + os.Exit(0) +} + +func main() { + flag.Parse() + var stats counters + + // Set up logging before continuing with flows + f, err := createLogFile() + if err != nil { + log.Fatalf("Failed to create log file %v", err) + } + defer f.Close() + log.SetOutput(f) + + conn := api.InitHTTPConnection(*serverAddr, *usernamePassword) + + // Health check doesn't affect the cancel booking flow so we let it through. + if *cancelAllBookings && (*allFlows || *checkFlow || *bookFlow || *listFlow || *statusFlow || *rescheduleFlow) { + log.Fatal("cancel_all_bookings is not supported with other test flows") + } + + // HealthCheck Flow + if *healthFlow || *allFlows { + stats.HealthCheckSuccess = true + if err := api.HealthCheck(conn); err != nil { + stats.HealthCheckSuccess = false + log.Println(err.Error()) + } + if !*allFlows && !*checkFlow && !*bookFlow && + !*listFlow && !*statusFlow && !*rescheduleFlow { + logStats(stats) + } + } + + var av []*fpb.Availability + if !*cancelAllBookings { + // Build availablility records. + if *availabilityFeed == "" { + log.Fatal("please set availability_feed flag if you wish to test additional flows") + } + av, err = utils.AvailabilityFrom(*availabilityFeed, *testSlots) + if err != nil { + log.Fatal(err.Error()) + } + stats.TotalSlotsProcessed += len(av) + } + + // AvailabilityCheck Flow + if *checkFlow || *allFlows { + utils.LogFlow("Availability Check", "Start") + totalSlots := len(av) + + j := 0 + for i, a := range av { + if err = api.CheckAvailability(a, conn); err != nil { + log.Printf("%s. skipping slot %d/%d", err.Error(), i, totalSlots) + stats.CheckAvailabilityErrors++ + continue + } + stats.CheckAvailabilitySuccess++ + av[j] = a + j++ + } + av = av[:j] + utils.LogFlow("Availability Check", "End") + } + // CreateBooking Flow. + var b []*mpb.Booking + if *bookFlow || *allFlows { + utils.LogFlow("Booking", "Start") + totalSlots := len(av) + for i, a := range av { + booking, err := api.CreateBooking(a, conn) + if err != nil { + log.Printf("%s. skipping slot %d/%d", err.Error(), i, totalSlots) + stats.CreateBookingErrors++ + continue + } + b = append(b, booking) + stats.CreateBookingSuccess++ + } + utils.LogFlow("Booking", "End") + } + // ListBookings Flow + if *listFlow || *allFlows || *cancelAllBookings { + if len(b) == 0 && !*cancelAllBookings { + b = GenerateBookings(av, &stats, conn) + } + utils.LogFlow("List Bookings", "Start") + b, err = api.ListBookings(b, conn) + stats.ListBookingsSuccess = true + if err != nil { + stats.ListBookingsSuccess = false + log.Println(err.Error()) + } + utils.LogFlow("List Bookings", "End") + } + + // GetBookingStatus Flow + if *statusFlow || *allFlows { + if len(b) == 0 { + b = GenerateBookings(av, &stats, conn) + } + + utils.LogFlow("BookingStatus", "Start") + totalBookings := len(b) + + j := 0 + for i, booking := range b { + if err = api.GetBookingStatus(booking, conn); err != nil { + log.Printf("%s. abandoning booking %d/%d", err.Error(), i, totalBookings) + stats.GetBookingStatusErrors++ + continue + } + stats.GetBookingStatusSuccess++ + b[j] = booking + j++ + } + b = b[:j] + utils.LogFlow("BookingStatus", "End") + } + // CancelBooking Flow + if len(b) > 0 { + utils.LogFlow("Cancel Booking", "Start") + for i, booking := range b { + if err = api.CancelBooking(booking, conn); err != nil { + log.Printf("%s. abandoning booking %d/%d", err.Error(), i, len(b)) + stats.CancelBookingsErrors++ + continue + } + stats.CancelBookingsSuccess++ + } + utils.LogFlow("Cancel Booking", "End") + } + + // Rescheduling is nuanced and can be isolated + // from the rest of the tests. + if *rescheduleFlow || *allFlows { + utils.LogFlow("Rescheduling", "Start") + stats.ReschedulingSuccess = true + if err = api.Rescheduling(av, conn); err != nil { + log.Println(err.Error()) + stats.ReschedulingSuccess = false + } + utils.LogFlow("Rescheduling", "End") + } + + logStats(stats) +}
diff --git a/utils/utils.go b/utils/utils.go new file mode 100644 index 0000000..ea9f1fa --- /dev/null +++ b/utils/utils.go
@@ -0,0 +1,147 @@ +/* +Copyright 2017 Google Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package utils contains common BookingService based helper functions. +package utils + +import ( + "errors" + "fmt" + "io/ioutil" + "log" + "math/rand" + "path" + "strings" + + "github.com/golang/protobuf/jsonpb" + "github.com/golang/protobuf/proto" + "github.com/google/go-cmp/cmp" + + fpb "github.com/maps-booking/feeds" + mpb "github.com/maps-booking/v3" +) + +// SlotKey is a struct representing a unique service. +type SlotKey struct { + MerchantID string + ServiceID string + StaffID string + RoomID string +} + +// LogFlow is a convenience function for logging common flows.. +func LogFlow(f string, status string) { + log.Println(strings.Join([]string{"\n##########\n", status, f, "Flow", "\n##########"}, " ")) +} + +// AvailabilityFrom parses the file specified in availabilityFeed, returning a random permutation of availability data, maximum entries specified in testSlots +func AvailabilityFrom(availabilityFeed string, testSlots int) ([]*fpb.Availability, error) { + LogFlow("Parse Input Feed", "Start") + defer LogFlow("Parse Input Feed", "End") + + var feed fpb.AvailabilityFeed + content, err := ioutil.ReadFile(availabilityFeed) + if err != nil { + return nil, fmt.Errorf("unable to read input file: %v", err) + } + if path.Ext(availabilityFeed) == ".json" { + if err := jsonpb.UnmarshalString(string(content), &feed); err != nil { + return nil, fmt.Errorf("unable to parse feed as json: %v", err) + } + } + if path.Ext(availabilityFeed) == ".pb3" { + if err := proto.Unmarshal(content, &feed); err != nil { + return nil, fmt.Errorf("unable to parse feed as pb3: %v", err) + } + } + + var finalAvailability []*fpb.Availability + var rawAvailability []*fpb.Availability + for _, sa := range feed.GetServiceAvailability() { + rawAvailability = append(rawAvailability, sa.GetAvailability()...) + } + if len(rawAvailability) == 0 || testSlots == 0 { + return finalAvailability, errors.New("no valid availability in feed, exiting workflows") + } + if len(rawAvailability) <= testSlots { + finalAvailability = rawAvailability + } else { + nums := rand.Perm(len(rawAvailability))[0:testSlots] + for _, n := range nums { + finalAvailability = append(finalAvailability, rawAvailability[n]) + } + } + log.Printf("Selected %d slots out of a possible %d", len(finalAvailability), len(rawAvailability)) + return finalAvailability, nil +} + +// ValidateBooking performs granular comparisons between all got and want Bookings. +func ValidateBooking(got *mpb.Booking, want *mpb.Booking) error { + if got.GetBookingId() == "" { + return errors.New("booking_id is empty") + } + if diff := cmp.Diff(got.GetSlot(), want.GetSlot(), cmp.Comparer(proto.Equal)); diff != "" { + return fmt.Errorf("slots differ (-got +want)\n%s", diff) + } + // UserId is the only required field for the partner to return. + if diff := cmp.Diff(got.GetUserInformation().GetUserId(), want.GetUserInformation().GetUserId()); diff != "" { + return fmt.Errorf("users differ (-got +want)\n%s", diff) + } + if diff := cmp.Diff(got.GetPaymentInformation(), want.GetPaymentInformation(), cmp.Comparer(proto.Equal)); diff != "" { + return fmt.Errorf("payment information differs (-got +want)\n%s", diff) + } + // BookingStatus_CONFIRMED is the default case unless want overrides it. + wantStatus := mpb.BookingStatus_CONFIRMED + if want.GetStatus() != mpb.BookingStatus_BOOKING_STATUS_UNSPECIFIED { + wantStatus = want.GetStatus() + } + if diff := cmp.Diff(got.GetStatus(), wantStatus); diff != "" { + return fmt.Errorf("status differs (-got +want)\n%s", diff) + } + return nil +} + +// BuildSlotFrom creates a bookingservice slot from an feed availability record. +func BuildSlotFrom(a *fpb.Availability) (*mpb.Slot, error) { + r := a.GetResources() + return &mpb.Slot{ + MerchantId: a.GetMerchantId(), + ServiceId: a.GetServiceId(), + StartSec: a.GetStartSec(), + DurationSec: a.GetDurationSec(), + AvailabilityTag: a.GetAvailabilityTag(), + Resources: &mpb.ResourceIds{ + StaffId: r.GetStaffId(), + RoomId: r.GetRoomId(), + PartySize: r.GetPartySize(), + }, + }, nil +} + +// BuildMerchantServiceMap creates a key value pair of unique services to all of their availability slots. +func BuildMerchantServiceMap(av []*fpb.Availability) map[SlotKey][]*fpb.Availability { + m := make(map[SlotKey][]*fpb.Availability) + for _, a := range av { + key := SlotKey{ + MerchantID: a.GetMerchantId(), + ServiceID: a.GetServiceId(), + StaffID: a.GetResources().GetStaffId(), + RoomID: a.GetResources().GetRoomId(), + } + m[key] = append(m[key], a) + } + return m +}
diff --git a/v3/v3.pb.go b/v3/v3.pb.go new file mode 100644 index 0000000..2df1389 --- /dev/null +++ b/v3/v3.pb.go
@@ -0,0 +1,3103 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// source: v3.proto + +/* +Package v3 is a generated protocol buffer package. + +It is generated from these files: + v3.proto + +It has these top-level messages: + PostalAddress + GeoCoordinates + Price + TaxRate + SchedulingRules + IngestionQueuePayload + IngestionStatus + TimeRange + NoShowFee + Deposit + ActionLink + Slot + Lease + LeaseReference + Booking + UserInformation + PaymentProcessingParameters + UserPaymentOption + PaymentInformation + BookingFailure + SlotAvailability + AvailabilityUpdate + ResourceIds + TicketType + LineItem + LineItemFulfillability + OrderFulfillability + Order + OrderFailure + CheckAvailabilityRequest + CheckAvailabilityResponse + GetBookingStatusRequest + GetBookingStatusResponse + CheckOrderFulfillabilityRequest + CheckOrderFulfillabilityResponse + CreateBookingRequest + CreateBookingResponse + CreateOrderRequest + CreateOrderResponse + CreateLeaseRequest + CreateLeaseResponse + ListBookingsRequest + ListBookingsResponse + ListOrdersRequest + ListOrdersResponse + UpdateBookingRequest + UpdateBookingResponse +*/ +package v3 + +import proto "github.com/golang/protobuf/proto" +import fmt "fmt" +import math "math" + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package + +// This defines the ingestion source type. +type IngestionSource int32 + +const ( + IngestionSource_SOURCE_UNKNOWN IngestionSource = 0 + // This ingestion is from an uploaded feed file. + IngestionSource_SOURCE_FEED IngestionSource = 1 + // This ingestion is from an API call. + IngestionSource_SOURCE_API IngestionSource = 2 +) + +var IngestionSource_name = map[int32]string{ + 0: "SOURCE_UNKNOWN", + 1: "SOURCE_FEED", + 2: "SOURCE_API", +} +var IngestionSource_value = map[string]int32{ + "SOURCE_UNKNOWN": 0, + "SOURCE_FEED": 1, + "SOURCE_API": 2, +} + +func (x IngestionSource) String() string { + return proto.EnumName(IngestionSource_name, int32(x)) +} +func (IngestionSource) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +// The types of content that we can ingest through feeds or APIs. +type ContentType int32 + +const ( + ContentType_CONTENT_UNKNOWN ContentType = 0 + ContentType_CONTENT_MERCHANT ContentType = 1 + ContentType_CONTENT_SERVICE ContentType = 2 + ContentType_CONTENT_AVAILABILITY ContentType = 3 + ContentType_CONTENT_PAYMENT_OPTION ContentType = 4 + ContentType_CONTENT_PAYMENT_OPTION_SERVICE ContentType = 5 +) + +var ContentType_name = map[int32]string{ + 0: "CONTENT_UNKNOWN", + 1: "CONTENT_MERCHANT", + 2: "CONTENT_SERVICE", + 3: "CONTENT_AVAILABILITY", + 4: "CONTENT_PAYMENT_OPTION", + 5: "CONTENT_PAYMENT_OPTION_SERVICE", +} +var ContentType_value = map[string]int32{ + "CONTENT_UNKNOWN": 0, + "CONTENT_MERCHANT": 1, + "CONTENT_SERVICE": 2, + "CONTENT_AVAILABILITY": 3, + "CONTENT_PAYMENT_OPTION": 4, + "CONTENT_PAYMENT_OPTION_SERVICE": 5, +} + +func (x ContentType) String() string { + return proto.EnumName(ContentType_name, int32(x)) +} +func (ContentType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +// [START pricetype_definition] +// Defines how a total price is determined from an availability. +type PriceType int32 + +const ( + // The price is for a fixed amount. This is the default value if the field is + // not set. + PriceType_FIXED_RATE_DEFAULT PriceType = 0 + // The price specified is per person, and the total price is calculated + // according to the party size specified in Resources as + // price_micros * party_size. A PER_PERSON price must be accompanied by a + // party size in the availability resources. If it is not, a party size of one + // is used. + PriceType_PER_PERSON PriceType = 1 +) + +var PriceType_name = map[int32]string{ + 0: "FIXED_RATE_DEFAULT", + 1: "PER_PERSON", +} +var PriceType_value = map[string]int32{ + "FIXED_RATE_DEFAULT": 0, + "PER_PERSON": 1, +} + +func (x PriceType) String() string { + return proto.EnumName(PriceType_name, int32(x)) +} +func (PriceType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +// [START RequireCreditCard_definition] +// Defines whether a credit card is required in order to book an appointment. +type RequireCreditCard int32 + +const ( + // The credit card requirement is not explicitly specified and the + // behaviour is identical to the one specified for CONDITIONAL. + RequireCreditCard_REQUIRE_CREDIT_CARD_UNSPECIFIED RequireCreditCard = 0 + // Google will require a credit card for the booking if any of the following + // conditions are met: + // * the availability has a price and the prepayment_type is REQUIRED + // * the no_show_fee is set + // * the deposit field is set. + RequireCreditCard_REQUIRE_CREDIT_CARD_CONDITIONAL RequireCreditCard = 1 + // A credit card is always required in order to book this availability + // regardless of other field values. + RequireCreditCard_REQUIRE_CREDIT_CARD_ALWAYS RequireCreditCard = 2 +) + +var RequireCreditCard_name = map[int32]string{ + 0: "REQUIRE_CREDIT_CARD_UNSPECIFIED", + 1: "REQUIRE_CREDIT_CARD_CONDITIONAL", + 2: "REQUIRE_CREDIT_CARD_ALWAYS", +} +var RequireCreditCard_value = map[string]int32{ + "REQUIRE_CREDIT_CARD_UNSPECIFIED": 0, + "REQUIRE_CREDIT_CARD_CONDITIONAL": 1, + "REQUIRE_CREDIT_CARD_ALWAYS": 2, +} + +func (x RequireCreditCard) String() string { + return proto.EnumName(RequireCreditCard_name, int32(x)) +} +func (RequireCreditCard) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +// [START paymentoption_definition] +type PaymentOptionType int32 + +const ( + PaymentOptionType_PAYMENT_OPTION_TYPE_UNSPECIFIED PaymentOptionType = 0 + PaymentOptionType_PAYMENT_OPTION_SINGLE_USE PaymentOptionType = 1 + PaymentOptionType_PAYMENT_OPTION_MULTI_USE PaymentOptionType = 2 + PaymentOptionType_PAYMENT_OPTION_UNLIMITED_USE PaymentOptionType = 3 +) + +var PaymentOptionType_name = map[int32]string{ + 0: "PAYMENT_OPTION_TYPE_UNSPECIFIED", + 1: "PAYMENT_OPTION_SINGLE_USE", + 2: "PAYMENT_OPTION_MULTI_USE", + 3: "PAYMENT_OPTION_UNLIMITED_USE", +} +var PaymentOptionType_value = map[string]int32{ + "PAYMENT_OPTION_TYPE_UNSPECIFIED": 0, + "PAYMENT_OPTION_SINGLE_USE": 1, + "PAYMENT_OPTION_MULTI_USE": 2, + "PAYMENT_OPTION_UNLIMITED_USE": 3, +} + +func (x PaymentOptionType) String() string { + return proto.EnumName(PaymentOptionType_name, int32(x)) +} +func (PaymentOptionType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } + +// [START bookingstatus_definition] +// Status of a booking. +// +// Updating booking status does not change the status of the associated payment. +// Prepayment status updates should be done using the PrepaymentStatus enum. +// +// nextID: 6 +type BookingStatus int32 + +const ( + // Not specified. + BookingStatus_BOOKING_STATUS_UNSPECIFIED BookingStatus = 0 + // Booking has been confirmed + BookingStatus_CONFIRMED BookingStatus = 1 + // Booking is awaiting confirmation by the merchant before it can transition + // into CONFIRMED status + BookingStatus_PENDING_MERCHANT_CONFIRMATION BookingStatus = 2 + // Booking has been canceled on behalf of the user. + // The merchant can still trigger a manual refund. + BookingStatus_CANCELED BookingStatus = 3 + // User did not show for the appointment + BookingStatus_NO_SHOW BookingStatus = 4 + // User did not show for the appointment in violation of the cancellation + // policy. + BookingStatus_NO_SHOW_PENALIZED BookingStatus = 5 +) + +var BookingStatus_name = map[int32]string{ + 0: "BOOKING_STATUS_UNSPECIFIED", + 1: "CONFIRMED", + 2: "PENDING_MERCHANT_CONFIRMATION", + 3: "CANCELED", + 4: "NO_SHOW", + 5: "NO_SHOW_PENALIZED", +} +var BookingStatus_value = map[string]int32{ + "BOOKING_STATUS_UNSPECIFIED": 0, + "CONFIRMED": 1, + "PENDING_MERCHANT_CONFIRMATION": 2, + "CANCELED": 3, + "NO_SHOW": 4, + "NO_SHOW_PENALIZED": 5, +} + +func (x BookingStatus) String() string { + return proto.EnumName(BookingStatus_name, int32(x)) +} +func (BookingStatus) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } + +// [START creditcardtype_definition] +// Used when booking/order failure cause is PAYMENT_ERROR_CARD_TYPE_REJECTED to +// indicate the type of credit card that was rejected. +type CreditCardType int32 + +const ( + // Default value. Used if credit card type does not match to one below. + CreditCardType_CREDIT_CARD_TYPE_UNSPECIFIED CreditCardType = 0 + CreditCardType_VISA CreditCardType = 1 + CreditCardType_MASTERCARD CreditCardType = 2 + CreditCardType_AMERICAN_EXPRESS CreditCardType = 3 + CreditCardType_DISCOVER CreditCardType = 4 +) + +var CreditCardType_name = map[int32]string{ + 0: "CREDIT_CARD_TYPE_UNSPECIFIED", + 1: "VISA", + 2: "MASTERCARD", + 3: "AMERICAN_EXPRESS", + 4: "DISCOVER", +} +var CreditCardType_value = map[string]int32{ + "CREDIT_CARD_TYPE_UNSPECIFIED": 0, + "VISA": 1, + "MASTERCARD": 2, + "AMERICAN_EXPRESS": 3, + "DISCOVER": 4, +} + +func (x CreditCardType) String() string { + return proto.EnumName(CreditCardType_name, int32(x)) +} +func (CreditCardType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } + +// [START prepaymentstatus_definition] +// Prepayment status of a booking. +// Updating payment status will trigger an update on the payment status of the +// associated booking (if applicable). +// Currently, the only supported transition is from PREPAYMENT_PROVIDED to +// PREPAYMENT_REFUNDED, which will initiate a non-reversible refund on the +// associated payment transaction. +type PrepaymentStatus int32 + +const ( + // Not specified, defaults to PREPAYMENT_NOT_PROVIDED. + PrepaymentStatus_PREPAYMENT_STATUS_UNSPECIFIED PrepaymentStatus = 0 + // The fee for the booking has been paid in advance. + PrepaymentStatus_PREPAYMENT_PROVIDED PrepaymentStatus = 1 + // The fee for the booking has not been paid in advance. + PrepaymentStatus_PREPAYMENT_NOT_PROVIDED PrepaymentStatus = 2 + // The fee was previously PREPAYMENT_PROVIDED but has now been refunded. + PrepaymentStatus_PREPAYMENT_REFUNDED PrepaymentStatus = 3 + // The fee was previously PREPAYMENT_PROVIDED but now has been credited + // (user given a UserPaymentOption as a voucher for the booking). + // If this is set, the response should also include the updated + // UserPaymentOption. + PrepaymentStatus_PREPAYMENT_CREDITED PrepaymentStatus = 4 +) + +var PrepaymentStatus_name = map[int32]string{ + 0: "PREPAYMENT_STATUS_UNSPECIFIED", + 1: "PREPAYMENT_PROVIDED", + 2: "PREPAYMENT_NOT_PROVIDED", + 3: "PREPAYMENT_REFUNDED", + 4: "PREPAYMENT_CREDITED", +} +var PrepaymentStatus_value = map[string]int32{ + "PREPAYMENT_STATUS_UNSPECIFIED": 0, + "PREPAYMENT_PROVIDED": 1, + "PREPAYMENT_NOT_PROVIDED": 2, + "PREPAYMENT_REFUNDED": 3, + "PREPAYMENT_CREDITED": 4, +} + +func (x PrepaymentStatus) String() string { + return proto.EnumName(PrepaymentStatus_name, int32(x)) +} +func (PrepaymentStatus) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } + +// The status code of an Ingestion event: a feed upload or an API call. +// Only used for logging the ingestion status in the IngestionMetadata +// table, do NOT use it in the code's control flow. +type IngestionStatus_Code int32 + +const ( + // An unknown status for Ingestion, shouldn't use it. + IngestionStatus_STATUS_UNKNOWN IngestionStatus_Code = 0 + // 1-99 for Feed upload. + // A feed has been uploaded. + IngestionStatus_STATUS_FEED_UPLOADED IngestionStatus_Code = 1 + // A feed has been added to the Ingestion Queue. + IngestionStatus_STATUS_FEED_ENQUEUED IngestionStatus_Code = 2 + // A feed has been picked up from the queue and started processing. + IngestionStatus_STATUS_FEED_PROCESSING_STARTED IngestionStatus_Code = 3 + // A feed has been processed successfully. + IngestionStatus_STATUS_FEED_PROCESSING_SUCCEEDED IngestionStatus_Code = 4 + // A feed has failed the processing. + IngestionStatus_STATUS_FEED_PROCESSING_FAILED IngestionStatus_Code = 5 + // A feed duplicate was uploaded. + IngestionStatus_STATUS_FEED_DUPLICATED IngestionStatus_Code = 6 + // 101-199 for API. + // An API has been called. + IngestionStatus_STATUS_API_CALLED IngestionStatus_Code = 101 + // An API has been processed successfully. + IngestionStatus_STATUS_API_PROCESSING_SUCCEEDED IngestionStatus_Code = 102 + // An API has failed the processing. + IngestionStatus_STATUS_API_PROCESSING_FAILED IngestionStatus_Code = 103 +) + +var IngestionStatus_Code_name = map[int32]string{ + 0: "STATUS_UNKNOWN", + 1: "STATUS_FEED_UPLOADED", + 2: "STATUS_FEED_ENQUEUED", + 3: "STATUS_FEED_PROCESSING_STARTED", + 4: "STATUS_FEED_PROCESSING_SUCCEEDED", + 5: "STATUS_FEED_PROCESSING_FAILED", + 6: "STATUS_FEED_DUPLICATED", + 101: "STATUS_API_CALLED", + 102: "STATUS_API_PROCESSING_SUCCEEDED", + 103: "STATUS_API_PROCESSING_FAILED", +} +var IngestionStatus_Code_value = map[string]int32{ + "STATUS_UNKNOWN": 0, + "STATUS_FEED_UPLOADED": 1, + "STATUS_FEED_ENQUEUED": 2, + "STATUS_FEED_PROCESSING_STARTED": 3, + "STATUS_FEED_PROCESSING_SUCCEEDED": 4, + "STATUS_FEED_PROCESSING_FAILED": 5, + "STATUS_FEED_DUPLICATED": 6, + "STATUS_API_CALLED": 101, + "STATUS_API_PROCESSING_SUCCEEDED": 102, + "STATUS_API_PROCESSING_FAILED": 103, +} + +func (x IngestionStatus_Code) String() string { + return proto.EnumName(IngestionStatus_Code_name, int32(x)) +} +func (IngestionStatus_Code) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{6, 0} } + +type PaymentProcessingParameters_PaymentProcessor int32 + +const ( + PaymentProcessingParameters_PAYMENT_PROCESSOR_UNSPECIFIED PaymentProcessingParameters_PaymentProcessor = 0 + PaymentProcessingParameters_PROCESSOR_STRIPE PaymentProcessingParameters_PaymentProcessor = 1 + PaymentProcessingParameters_PROCESSOR_BRAINTREE PaymentProcessingParameters_PaymentProcessor = 2 +) + +var PaymentProcessingParameters_PaymentProcessor_name = map[int32]string{ + 0: "PAYMENT_PROCESSOR_UNSPECIFIED", + 1: "PROCESSOR_STRIPE", + 2: "PROCESSOR_BRAINTREE", +} +var PaymentProcessingParameters_PaymentProcessor_value = map[string]int32{ + "PAYMENT_PROCESSOR_UNSPECIFIED": 0, + "PROCESSOR_STRIPE": 1, + "PROCESSOR_BRAINTREE": 2, +} + +func (x PaymentProcessingParameters_PaymentProcessor) String() string { + return proto.EnumName(PaymentProcessingParameters_PaymentProcessor_name, int32(x)) +} +func (PaymentProcessingParameters_PaymentProcessor) EnumDescriptor() ([]byte, []int) { + return fileDescriptor0, []int{16, 0} +} + +// Who handles payment processing? +// If payment is processed by the partner, CreateBooking request will +// include additional parameters (PaymentProcessingParameters) indicating +// the payment method to be used to process the payment. +type PaymentInformation_PaymentProcessedBy int32 + +const ( + PaymentInformation_PAYMENT_PROCESSED_BY_UNSPECIFIED PaymentInformation_PaymentProcessedBy = 0 + PaymentInformation_PROCESSED_BY_GOOGLE PaymentInformation_PaymentProcessedBy = 1 + PaymentInformation_PROCESSED_BY_PARTNER PaymentInformation_PaymentProcessedBy = 2 +) + +var PaymentInformation_PaymentProcessedBy_name = map[int32]string{ + 0: "PAYMENT_PROCESSED_BY_UNSPECIFIED", + 1: "PROCESSED_BY_GOOGLE", + 2: "PROCESSED_BY_PARTNER", +} +var PaymentInformation_PaymentProcessedBy_value = map[string]int32{ + "PAYMENT_PROCESSED_BY_UNSPECIFIED": 0, + "PROCESSED_BY_GOOGLE": 1, + "PROCESSED_BY_PARTNER": 2, +} + +func (x PaymentInformation_PaymentProcessedBy) String() string { + return proto.EnumName(PaymentInformation_PaymentProcessedBy_name, int32(x)) +} +func (PaymentInformation_PaymentProcessedBy) EnumDescriptor() ([]byte, []int) { + return fileDescriptor0, []int{18, 0} +} + +type BookingFailure_Cause int32 + +const ( + // Default value: Don't use; amounts to an "unknown error" + BookingFailure_CAUSE_UNSPECIFIED BookingFailure_Cause = 0 + // The referenced availability slot is not available any longer. + BookingFailure_SLOT_UNAVAILABLE BookingFailure_Cause = 1 + // The user has already booked an appointment for the referenced + // availability slot. + BookingFailure_SLOT_ALREADY_BOOKED_BY_USER BookingFailure_Cause = 2 + // The lease (if provided) has expired and cannot be used any longer to + // complete the requested booking. + BookingFailure_LEASE_EXPIRED BookingFailure_Cause = 3 + // The requested cancellation cannot be performed at the current time due + // to time restrictions in the merchant's cancellation policy. + BookingFailure_OUTSIDE_CANCELLATION_WINDOW BookingFailure_Cause = 4 + // An error was encountered while processing the payment because the + // provided credit card type was not accepted by the merchant. The credit + // card type must be supplied in rejected_card_type. + BookingFailure_PAYMENT_ERROR_CARD_TYPE_REJECTED BookingFailure_Cause = 5 + // An error was encountered while processing the payment because the + // provided credit card was declined. + BookingFailure_PAYMENT_ERROR_CARD_DECLINED BookingFailure_Cause = 6 + // An error was encountered with the pack/membership used to pay for the + // booking. There could be no valid uses left, it could have expired, etc. + BookingFailure_PAYMENT_OPTION_NOT_VALID BookingFailure_Cause = 7 + // An error was encountered while processing the payment for this booking. + // Use this value to indicate a general payment related error, only if the + // error does not match to a specific payment error above. + BookingFailure_PAYMENT_ERROR BookingFailure_Cause = 8 + // User cannot use the given payment option (e.g. user trying to use a + // first time price for the second time). + BookingFailure_USER_CANNOT_USE_PAYMENT_OPTION BookingFailure_Cause = 9 + // A booking that the user tried to cancel has already been cancelled. + BookingFailure_BOOKING_ALREADY_CANCELLED BookingFailure_Cause = 10 + // A booking that the user tried to cancel is not cancellable. + BookingFailure_BOOKING_NOT_CANCELLABLE BookingFailure_Cause = 11 +) + +var BookingFailure_Cause_name = map[int32]string{ + 0: "CAUSE_UNSPECIFIED", + 1: "SLOT_UNAVAILABLE", + 2: "SLOT_ALREADY_BOOKED_BY_USER", + 3: "LEASE_EXPIRED", + 4: "OUTSIDE_CANCELLATION_WINDOW", + 5: "PAYMENT_ERROR_CARD_TYPE_REJECTED", + 6: "PAYMENT_ERROR_CARD_DECLINED", + 7: "PAYMENT_OPTION_NOT_VALID", + 8: "PAYMENT_ERROR", + 9: "USER_CANNOT_USE_PAYMENT_OPTION", + 10: "BOOKING_ALREADY_CANCELLED", + 11: "BOOKING_NOT_CANCELLABLE", +} +var BookingFailure_Cause_value = map[string]int32{ + "CAUSE_UNSPECIFIED": 0, + "SLOT_UNAVAILABLE": 1, + "SLOT_ALREADY_BOOKED_BY_USER": 2, + "LEASE_EXPIRED": 3, + "OUTSIDE_CANCELLATION_WINDOW": 4, + "PAYMENT_ERROR_CARD_TYPE_REJECTED": 5, + "PAYMENT_ERROR_CARD_DECLINED": 6, + "PAYMENT_OPTION_NOT_VALID": 7, + "PAYMENT_ERROR": 8, + "USER_CANNOT_USE_PAYMENT_OPTION": 9, + "BOOKING_ALREADY_CANCELLED": 10, + "BOOKING_NOT_CANCELLABLE": 11, +} + +func (x BookingFailure_Cause) String() string { + return proto.EnumName(BookingFailure_Cause_name, int32(x)) +} +func (BookingFailure_Cause) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{19, 0} } + +// The result of a line item fulfillability check. +type LineItemFulfillability_ItemFulfillabilityResult int32 + +const ( + // Default value: Don't use. + LineItemFulfillability_ITEM_FULFILLABILITY_RESULT_UNSPECIFIED LineItemFulfillability_ItemFulfillabilityResult = 0 + // This line item can be fulfilled. + LineItemFulfillability_CAN_FULFILL LineItemFulfillability_ItemFulfillabilityResult = 1 + // No adequate availability for the slot requested. + LineItemFulfillability_SLOT_UNAVAILABLE LineItemFulfillability_ItemFulfillabilityResult = 2 + // The combination of ticket types requested cannot be fulfilled. + LineItemFulfillability_UNFULFILLABLE_TICKET_COMBINATION LineItemFulfillability_ItemFulfillabilityResult = 3 + // The total price of this line item is not incorrect. + LineItemFulfillability_INCORRECT_PRICE LineItemFulfillability_ItemFulfillabilityResult = 4 + // The line item cannot be fulfilled for reasons that do not fall into + // the categories above. + LineItemFulfillability_ITEM_UNFULFILLABLE_OTHER_REASON LineItemFulfillability_ItemFulfillabilityResult = 5 +) + +var LineItemFulfillability_ItemFulfillabilityResult_name = map[int32]string{ + 0: "ITEM_FULFILLABILITY_RESULT_UNSPECIFIED", + 1: "CAN_FULFILL", + 2: "SLOT_UNAVAILABLE", + 3: "UNFULFILLABLE_TICKET_COMBINATION", + 4: "INCORRECT_PRICE", + 5: "ITEM_UNFULFILLABLE_OTHER_REASON", +} +var LineItemFulfillability_ItemFulfillabilityResult_value = map[string]int32{ + "ITEM_FULFILLABILITY_RESULT_UNSPECIFIED": 0, + "CAN_FULFILL": 1, + "SLOT_UNAVAILABLE": 2, + "UNFULFILLABLE_TICKET_COMBINATION": 3, + "INCORRECT_PRICE": 4, + "ITEM_UNFULFILLABLE_OTHER_REASON": 5, +} + +func (x LineItemFulfillability_ItemFulfillabilityResult) String() string { + return proto.EnumName(LineItemFulfillability_ItemFulfillabilityResult_name, int32(x)) +} +func (LineItemFulfillability_ItemFulfillabilityResult) EnumDescriptor() ([]byte, []int) { + return fileDescriptor0, []int{25, 0} +} + +// The result of an order fulfillability check. +type OrderFulfillability_OrderFulfillabilityResult int32 + +const ( + // Default value: Don't use. + OrderFulfillability_ORDER_FULFILLABILITY_RESULT_UNSPECIFIED OrderFulfillability_OrderFulfillabilityResult = 0 + // The order can be fulfilled. + OrderFulfillability_CAN_FULFILL OrderFulfillability_OrderFulfillabilityResult = 1 + // The order cannot be fulfilled due to one or more unfulfillable line + // item(s). + OrderFulfillability_UNFULFILLABLE_LINE_ITEM OrderFulfillability_OrderFulfillabilityResult = 2 + // The combination of the line items requested cannot be fulfilled. + OrderFulfillability_UNFULFILLABLE_SERVICE_COMBINATION OrderFulfillability_OrderFulfillabilityResult = 3 + // The order cannot be fulfilled due to reasons that do not fall into the + // categories above. + OrderFulfillability_ORDER_UNFULFILLABLE_OTHER_REASON OrderFulfillability_OrderFulfillabilityResult = 4 +) + +var OrderFulfillability_OrderFulfillabilityResult_name = map[int32]string{ + 0: "ORDER_FULFILLABILITY_RESULT_UNSPECIFIED", + 1: "CAN_FULFILL", + 2: "UNFULFILLABLE_LINE_ITEM", + 3: "UNFULFILLABLE_SERVICE_COMBINATION", + 4: "ORDER_UNFULFILLABLE_OTHER_REASON", +} +var OrderFulfillability_OrderFulfillabilityResult_value = map[string]int32{ + "ORDER_FULFILLABILITY_RESULT_UNSPECIFIED": 0, + "CAN_FULFILL": 1, + "UNFULFILLABLE_LINE_ITEM": 2, + "UNFULFILLABLE_SERVICE_COMBINATION": 3, + "ORDER_UNFULFILLABLE_OTHER_REASON": 4, +} + +func (x OrderFulfillability_OrderFulfillabilityResult) String() string { + return proto.EnumName(OrderFulfillability_OrderFulfillabilityResult_name, int32(x)) +} +func (OrderFulfillability_OrderFulfillabilityResult) EnumDescriptor() ([]byte, []int) { + return fileDescriptor0, []int{26, 0} +} + +type OrderFailure_Cause int32 + +const ( + // Default value: Don't use; amounts to an "unknown error" + OrderFailure_CAUSE_UNSPECIFIED OrderFailure_Cause = 0 + // The order is no longer fulfillable. + OrderFailure_ORDER_UNFULFILLABLE OrderFailure_Cause = 1 + // An error was encountered while processing the payment because the + // provided credit card type was not accepted by the merchant. The credit + // card type must be supplied in rejected_card_type. + OrderFailure_PAYMENT_ERROR_CARD_TYPE_REJECTED OrderFailure_Cause = 2 + // An error was encountered while processing the payment because the + // provided credit card was declined. + OrderFailure_PAYMENT_ERROR_CARD_DECLINED OrderFailure_Cause = 3 + // An error was encountered while processing the payment for this order. + // Use this value to indicate a general payment related error, only if the + // error does not match to a specific payment error above. + OrderFailure_PAYMENT_ERROR OrderFailure_Cause = 4 +) + +var OrderFailure_Cause_name = map[int32]string{ + 0: "CAUSE_UNSPECIFIED", + 1: "ORDER_UNFULFILLABLE", + 2: "PAYMENT_ERROR_CARD_TYPE_REJECTED", + 3: "PAYMENT_ERROR_CARD_DECLINED", + 4: "PAYMENT_ERROR", +} +var OrderFailure_Cause_value = map[string]int32{ + "CAUSE_UNSPECIFIED": 0, + "ORDER_UNFULFILLABLE": 1, + "PAYMENT_ERROR_CARD_TYPE_REJECTED": 2, + "PAYMENT_ERROR_CARD_DECLINED": 3, + "PAYMENT_ERROR": 4, +} + +func (x OrderFailure_Cause) String() string { + return proto.EnumName(OrderFailure_Cause_name, int32(x)) +} +func (OrderFailure_Cause) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{28, 0} } + +// This enum indicates what requirements exist for the user to acknowledge or +// view the requested slots duration/end time. +type CheckAvailabilityResponse_DurationRequirement int32 + +const ( + // The handling of the end time is not specified. This is the default. + CheckAvailabilityResponse_DURATION_REQUIREMENT_UNSPECIFIED CheckAvailabilityResponse_DurationRequirement = 0 + // The end time is not shown to the user. + CheckAvailabilityResponse_DO_NOT_SHOW_DURATION CheckAvailabilityResponse_DurationRequirement = 1 + // The end time has to be shown to the user before an appointment can be + // made. + CheckAvailabilityResponse_MUST_SHOW_DURATION CheckAvailabilityResponse_DurationRequirement = 2 +) + +var CheckAvailabilityResponse_DurationRequirement_name = map[int32]string{ + 0: "DURATION_REQUIREMENT_UNSPECIFIED", + 1: "DO_NOT_SHOW_DURATION", + 2: "MUST_SHOW_DURATION", +} +var CheckAvailabilityResponse_DurationRequirement_value = map[string]int32{ + "DURATION_REQUIREMENT_UNSPECIFIED": 0, + "DO_NOT_SHOW_DURATION": 1, + "MUST_SHOW_DURATION": 2, +} + +func (x CheckAvailabilityResponse_DurationRequirement) String() string { + return proto.EnumName(CheckAvailabilityResponse_DurationRequirement_name, int32(x)) +} +func (CheckAvailabilityResponse_DurationRequirement) EnumDescriptor() ([]byte, []int) { + return fileDescriptor0, []int{30, 0} +} + +// [START postaladdr_definition] +// The postal address for a merchant. +type PostalAddress struct { + // The country, e.g. "USA". (required) + Country string `protobuf:"bytes,1,opt,name=country" json:"country,omitempty"` + // The locality/city, e.g. "Mountain View". (required) + Locality string `protobuf:"bytes,2,opt,name=locality" json:"locality,omitempty"` + // The region/state/province, e.g. "CA". (required) + Region string `protobuf:"bytes,3,opt,name=region" json:"region,omitempty"` + // The postal code, e.g. "94043". (required) + PostalCode string `protobuf:"bytes,4,opt,name=postal_code,json=postalCode" json:"postal_code,omitempty"` + // The street address, e.g. "1600 Amphitheatre Pkwy". (required) + StreetAddress string `protobuf:"bytes,5,opt,name=street_address,json=streetAddress" json:"street_address,omitempty"` +} + +func (m *PostalAddress) Reset() { *m = PostalAddress{} } +func (m *PostalAddress) String() string { return proto.CompactTextString(m) } +func (*PostalAddress) ProtoMessage() {} +func (*PostalAddress) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } + +func (m *PostalAddress) GetCountry() string { + if m != nil { + return m.Country + } + return "" +} + +func (m *PostalAddress) GetLocality() string { + if m != nil { + return m.Locality + } + return "" +} + +func (m *PostalAddress) GetRegion() string { + if m != nil { + return m.Region + } + return "" +} + +func (m *PostalAddress) GetPostalCode() string { + if m != nil { + return m.PostalCode + } + return "" +} + +func (m *PostalAddress) GetStreetAddress() string { + if m != nil { + return m.StreetAddress + } + return "" +} + +// [START geocoord_definition] +// The Geo data of a location, including latitude, longitude, and address. +type GeoCoordinates struct { + Latitude float64 `protobuf:"fixed64,1,opt,name=latitude" json:"latitude,omitempty"` + Longitude float64 `protobuf:"fixed64,2,opt,name=longitude" json:"longitude,omitempty"` + Address *PostalAddress `protobuf:"bytes,3,opt,name=address" json:"address,omitempty"` +} + +func (m *GeoCoordinates) Reset() { *m = GeoCoordinates{} } +func (m *GeoCoordinates) String() string { return proto.CompactTextString(m) } +func (*GeoCoordinates) ProtoMessage() {} +func (*GeoCoordinates) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } + +func (m *GeoCoordinates) GetLatitude() float64 { + if m != nil { + return m.Latitude + } + return 0 +} + +func (m *GeoCoordinates) GetLongitude() float64 { + if m != nil { + return m.Longitude + } + return 0 +} + +func (m *GeoCoordinates) GetAddress() *PostalAddress { + if m != nil { + return m.Address + } + return nil +} + +// [START price_definition] +// The price of a service or a fee. +type Price struct { + // The price in micro-units of the currency. + // Fractions of smallest currency unit will be rounded using nearest even + // rounding. (e.g. For USD 2.5 cents rounded to 2 cents, 3.5 cents rounded to + // 4 cents, 0.5 cents rounded to 0 cents, 2.51 cents rounded to 3 cents). + // (required) + PriceMicros int64 `protobuf:"varint,1,opt,name=price_micros,json=priceMicros" json:"price_micros,omitempty"` + // The currency of the price that is defined in ISO 4217. (required) + CurrencyCode string `protobuf:"bytes,2,opt,name=currency_code,json=currencyCode" json:"currency_code,omitempty"` + // An optional and opaque string that identifies the pricing option that is + // associated with the extended price. (optional) + PricingOptionTag string `protobuf:"bytes,3,opt,name=pricing_option_tag,json=pricingOptionTag" json:"pricing_option_tag,omitempty"` +} + +func (m *Price) Reset() { *m = Price{} } +func (m *Price) String() string { return proto.CompactTextString(m) } +func (*Price) ProtoMessage() {} +func (*Price) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } + +func (m *Price) GetPriceMicros() int64 { + if m != nil { + return m.PriceMicros + } + return 0 +} + +func (m *Price) GetCurrencyCode() string { + if m != nil { + return m.CurrencyCode + } + return "" +} + +func (m *Price) GetPricingOptionTag() string { + if m != nil { + return m.PricingOptionTag + } + return "" +} + +// [START taxrate_definition] +// A tax rate applied when charging the user for a service, and which can be set +// on either a per merchant, or per service basis. +type TaxRate struct { + // A tax rate in millionths of one percent, effectively giving 6 decimals of + // precision. For example, if the tax rate is 7.253%, this field should be set + // to 7253000. + // + // If this field is left unset or set to 0, the total price charged to a user + // for any service provided by this merchant is the exact price specified by + // Service.price. The service price is assumed to be exempt from or already + // inclusive of applicable taxes. Taxes will not be shown to the user as a + // separate line item. + // + // If this field is set to any nonzero value, the total price charged to a + // user for any service provided by this merchant will include the service + // price plus the tax assessed using the tax rate provided here. Fractions of + // the smallest currency unit (for example, fractions of one cent) will be + // rounded using nearest even rounding. Taxes will be shown to the user as a + // separate line item. (required) + MicroPercent int32 `protobuf:"varint,1,opt,name=micro_percent,json=microPercent" json:"micro_percent,omitempty"` +} + +func (m *TaxRate) Reset() { *m = TaxRate{} } +func (m *TaxRate) String() string { return proto.CompactTextString(m) } +func (*TaxRate) ProtoMessage() {} +func (*TaxRate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } + +func (m *TaxRate) GetMicroPercent() int32 { + if m != nil { + return m.MicroPercent + } + return 0 +} + +// [START schedulingrules_definition] +// The scheduling rules for a service. +type SchedulingRules struct { + // The minimum advance notice in seconds required to book an appointment. + // (optional) + MinAdvanceBooking int64 `protobuf:"varint,1,opt,name=min_advance_booking,json=minAdvanceBooking" json:"min_advance_booking,omitempty"` + // The minimum advance notice in seconds required to cancel a booked + // appointment online. (optional) + MinAdvanceOnlineCanceling int64 `protobuf:"varint,2,opt,name=min_advance_online_canceling,json=minAdvanceOnlineCanceling" json:"min_advance_online_canceling,omitempty"` + // The fee for canceling within the minimum advance notice period. + LateCancellationFee *Price `protobuf:"bytes,3,opt,name=late_cancellation_fee,json=lateCancellationFee" json:"late_cancellation_fee,omitempty"` + // The fee for no-show without canceling. + NoshowFee *Price `protobuf:"bytes,4,opt,name=noshow_fee,json=noshowFee" json:"noshow_fee,omitempty"` +} + +func (m *SchedulingRules) Reset() { *m = SchedulingRules{} } +func (m *SchedulingRules) String() string { return proto.CompactTextString(m) } +func (*SchedulingRules) ProtoMessage() {} +func (*SchedulingRules) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{4} } + +func (m *SchedulingRules) GetMinAdvanceBooking() int64 { + if m != nil { + return m.MinAdvanceBooking + } + return 0 +} + +func (m *SchedulingRules) GetMinAdvanceOnlineCanceling() int64 { + if m != nil { + return m.MinAdvanceOnlineCanceling + } + return 0 +} + +func (m *SchedulingRules) GetLateCancellationFee() *Price { + if m != nil { + return m.LateCancellationFee + } + return nil +} + +func (m *SchedulingRules) GetNoshowFee() *Price { + if m != nil { + return m.NoshowFee + } + return nil +} + +// An empty boilplate proto for the Ingestion Queue in Spanner. +type IngestionQueuePayload struct { +} + +func (m *IngestionQueuePayload) Reset() { *m = IngestionQueuePayload{} } +func (m *IngestionQueuePayload) String() string { return proto.CompactTextString(m) } +func (*IngestionQueuePayload) ProtoMessage() {} +func (*IngestionQueuePayload) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{5} } + +type IngestionStatus struct { + // The code of the status. + Code IngestionStatus_Code `protobuf:"varint,1,opt,name=code,enum=v3.IngestionStatus_Code" json:"code,omitempty"` + // Microseconds since epoch when the ingestion updates its status code. + TimestampMicros int64 `protobuf:"varint,2,opt,name=timestamp_micros,json=timestampMicros" json:"timestamp_micros,omitempty"` + // A human description of the error if any. + InternalErrorDetails string `protobuf:"bytes,3,opt,name=internal_error_details,json=internalErrorDetails" json:"internal_error_details,omitempty"` + PartnerVisibleErrorDetails string `protobuf:"bytes,4,opt,name=partner_visible_error_details,json=partnerVisibleErrorDetails" json:"partner_visible_error_details,omitempty"` +} + +func (m *IngestionStatus) Reset() { *m = IngestionStatus{} } +func (m *IngestionStatus) String() string { return proto.CompactTextString(m) } +func (*IngestionStatus) ProtoMessage() {} +func (*IngestionStatus) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{6} } + +func (m *IngestionStatus) GetCode() IngestionStatus_Code { + if m != nil { + return m.Code + } + return IngestionStatus_STATUS_UNKNOWN +} + +func (m *IngestionStatus) GetTimestampMicros() int64 { + if m != nil { + return m.TimestampMicros + } + return 0 +} + +func (m *IngestionStatus) GetInternalErrorDetails() string { + if m != nil { + return m.InternalErrorDetails + } + return "" +} + +func (m *IngestionStatus) GetPartnerVisibleErrorDetails() string { + if m != nil { + return m.PartnerVisibleErrorDetails + } + return "" +} + +// [START timerange_definition] +// A closed-open time range, i.e. [begin_sec, end_sec) +type TimeRange struct { + // Seconds of UTC time since Unix epoch (required) + BeginSec int64 `protobuf:"varint,1,opt,name=begin_sec,json=beginSec" json:"begin_sec,omitempty"` + // Seconds of UTC time since Unix epoch (required) + EndSec int64 `protobuf:"varint,2,opt,name=end_sec,json=endSec" json:"end_sec,omitempty"` +} + +func (m *TimeRange) Reset() { *m = TimeRange{} } +func (m *TimeRange) String() string { return proto.CompactTextString(m) } +func (*TimeRange) ProtoMessage() {} +func (*TimeRange) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{7} } + +func (m *TimeRange) GetBeginSec() int64 { + if m != nil { + return m.BeginSec + } + return 0 +} + +func (m *TimeRange) GetEndSec() int64 { + if m != nil { + return m.EndSec + } + return 0 +} + +// [START noshowfee_definition] +// A fee that a user may be charged if they have made a booking but do not +// show up. +type NoShowFee struct { + // The amount the user may be charged if they do not show up for their + // reservation. + Fee *Price `protobuf:"bytes,1,opt,name=fee" json:"fee,omitempty"` + // Defines how the fee is determined from the availability. + FeeType PriceType `protobuf:"varint,3,opt,name=fee_type,json=feeType,enum=v3.PriceType" json:"fee_type,omitempty"` +} + +func (m *NoShowFee) Reset() { *m = NoShowFee{} } +func (m *NoShowFee) String() string { return proto.CompactTextString(m) } +func (*NoShowFee) ProtoMessage() {} +func (*NoShowFee) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{8} } + +func (m *NoShowFee) GetFee() *Price { + if m != nil { + return m.Fee + } + return nil +} + +func (m *NoShowFee) GetFeeType() PriceType { + if m != nil { + return m.FeeType + } + return PriceType_FIXED_RATE_DEFAULT +} + +// [START deposit_definition] +// A deposit that the user may be charged or have a hold on their credit card +// for. +type Deposit struct { + // Deposit amount. + Deposit *Price `protobuf:"bytes,1,opt,name=deposit" json:"deposit,omitempty"` + // Minimum advance cancellation for the deposit. + MinAdvanceCancellationSec int64 `protobuf:"varint,2,opt,name=min_advance_cancellation_sec,json=minAdvanceCancellationSec" json:"min_advance_cancellation_sec,omitempty"` + // Defines how the deposit is determined from the availability. + DepositType PriceType `protobuf:"varint,3,opt,name=deposit_type,json=depositType,enum=v3.PriceType" json:"deposit_type,omitempty"` +} + +func (m *Deposit) Reset() { *m = Deposit{} } +func (m *Deposit) String() string { return proto.CompactTextString(m) } +func (*Deposit) ProtoMessage() {} +func (*Deposit) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{9} } + +func (m *Deposit) GetDeposit() *Price { + if m != nil { + return m.Deposit + } + return nil +} + +func (m *Deposit) GetMinAdvanceCancellationSec() int64 { + if m != nil { + return m.MinAdvanceCancellationSec + } + return 0 +} + +func (m *Deposit) GetDepositType() PriceType { + if m != nil { + return m.DepositType + } + return PriceType_FIXED_RATE_DEFAULT +} + +// [START ActionLink_definition] +// An action URL with associated language and list of countries restricted to. +type ActionLink struct { + // The entry point URL for this action link. + Url string `protobuf:"bytes,1,opt,name=url" json:"url,omitempty"` + // The BCP-47 language tag identifying the language in which the content + // from this URI is available. + Language string `protobuf:"bytes,2,opt,name=language" json:"language,omitempty"` + // ISO 3166-1 alpha-2 country code. Leave empty for unrestricted visibility. + RestrictedCountry []string `protobuf:"bytes,3,rep,name=restricted_country,json=restrictedCountry" json:"restricted_country,omitempty"` +} + +func (m *ActionLink) Reset() { *m = ActionLink{} } +func (m *ActionLink) String() string { return proto.CompactTextString(m) } +func (*ActionLink) ProtoMessage() {} +func (*ActionLink) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{10} } + +func (m *ActionLink) GetUrl() string { + if m != nil { + return m.Url + } + return "" +} + +func (m *ActionLink) GetLanguage() string { + if m != nil { + return m.Language + } + return "" +} + +func (m *ActionLink) GetRestrictedCountry() []string { + if m != nil { + return m.RestrictedCountry + } + return nil +} + +// [START message_slot] +// An inventory slot +type Slot struct { + // ID of the merchant for the slot (required) + MerchantId string `protobuf:"bytes,1,opt,name=merchant_id,json=merchantId" json:"merchant_id,omitempty"` + // ID of the merchant service (required) + ServiceId string `protobuf:"bytes,2,opt,name=service_id,json=serviceId" json:"service_id,omitempty"` + // Start time of the appointment slot in seconds of UTC time since Unix epoch. + // (required) + StartSec int64 `protobuf:"varint,3,opt,name=start_sec,json=startSec" json:"start_sec,omitempty"` + // Duration of the appointment slot (required) + DurationSec int64 `protobuf:"varint,4,opt,name=duration_sec,json=durationSec" json:"duration_sec,omitempty"` + // Opaque tag that identifies the availability slot and matches the value + // provided in the availability feed (optional) + AvailabilityTag string `protobuf:"bytes,5,opt,name=availability_tag,json=availabilityTag" json:"availability_tag,omitempty"` + // The set of resources that disambiguates the appointment slot, e.g. by + // indicating the staff member and room selected by the user (optional) + Resources *ResourceIds `protobuf:"bytes,6,opt,name=resources" json:"resources,omitempty"` +} + +func (m *Slot) Reset() { *m = Slot{} } +func (m *Slot) String() string { return proto.CompactTextString(m) } +func (*Slot) ProtoMessage() {} +func (*Slot) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{11} } + +func (m *Slot) GetMerchantId() string { + if m != nil { + return m.MerchantId + } + return "" +} + +func (m *Slot) GetServiceId() string { + if m != nil { + return m.ServiceId + } + return "" +} + +func (m *Slot) GetStartSec() int64 { + if m != nil { + return m.StartSec + } + return 0 +} + +func (m *Slot) GetDurationSec() int64 { + if m != nil { + return m.DurationSec + } + return 0 +} + +func (m *Slot) GetAvailabilityTag() string { + if m != nil { + return m.AvailabilityTag + } + return "" +} + +func (m *Slot) GetResources() *ResourceIds { + if m != nil { + return m.Resources + } + return nil +} + +// [START message_lease] +// Temporary lease for an inventory slot +type Lease struct { + // ID of the lease. + // Not populated in CreateLeaseRequest. The value is chosen by the partner and + // has to be returned in the response of CreateLease. (required) + LeaseId string `protobuf:"bytes,1,opt,name=lease_id,json=leaseId" json:"lease_id,omitempty"` + // The appointment slot that the lease is created for. (required) + Slot *Slot `protobuf:"bytes,2,opt,name=slot" json:"slot,omitempty"` + // Unique identifier for this lease, chosen by Reserve with Google. Serves as + // an idempotency token for CreateLease requests. (required) + UserReference string `protobuf:"bytes,3,opt,name=user_reference,json=userReference" json:"user_reference,omitempty"` + // Expiration time of the lease in UTC Timestamp (required) + LeaseExpirationTimeSec int64 `protobuf:"varint,4,opt,name=lease_expiration_time_sec,json=leaseExpirationTimeSec" json:"lease_expiration_time_sec,omitempty"` +} + +func (m *Lease) Reset() { *m = Lease{} } +func (m *Lease) String() string { return proto.CompactTextString(m) } +func (*Lease) ProtoMessage() {} +func (*Lease) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{12} } + +func (m *Lease) GetLeaseId() string { + if m != nil { + return m.LeaseId + } + return "" +} + +func (m *Lease) GetSlot() *Slot { + if m != nil { + return m.Slot + } + return nil +} + +func (m *Lease) GetUserReference() string { + if m != nil { + return m.UserReference + } + return "" +} + +func (m *Lease) GetLeaseExpirationTimeSec() int64 { + if m != nil { + return m.LeaseExpirationTimeSec + } + return 0 +} + +// Reference to a Lease that has been created via CreateLease. +type LeaseReference struct { + // Lease ID (required) + LeaseId string `protobuf:"bytes,1,opt,name=lease_id,json=leaseId" json:"lease_id,omitempty"` +} + +func (m *LeaseReference) Reset() { *m = LeaseReference{} } +func (m *LeaseReference) String() string { return proto.CompactTextString(m) } +func (*LeaseReference) ProtoMessage() {} +func (*LeaseReference) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{13} } + +func (m *LeaseReference) GetLeaseId() string { + if m != nil { + return m.LeaseId + } + return "" +} + +// [START message_booking] +// A booking for an inventory slot +type Booking struct { + // ID of this booking (required) + BookingId string `protobuf:"bytes,1,opt,name=booking_id,json=bookingId" json:"booking_id,omitempty"` + // The appointment slot of this booking (required) + Slot *Slot `protobuf:"bytes,2,opt,name=slot" json:"slot,omitempty"` + // Personal information of the user making the appointment (required) + UserInformation *UserInformation `protobuf:"bytes,3,opt,name=user_information,json=userInformation" json:"user_information,omitempty"` + // Status of the booking (required) + Status BookingStatus `protobuf:"varint,4,opt,name=status,enum=v3.BookingStatus" json:"status,omitempty"` + // Information about payment transactions that relate to the booking. + // (optional) + PaymentInformation *PaymentInformation `protobuf:"bytes,5,opt,name=payment_information,json=paymentInformation" json:"payment_information,omitempty"` +} + +func (m *Booking) Reset() { *m = Booking{} } +func (m *Booking) String() string { return proto.CompactTextString(m) } +func (*Booking) ProtoMessage() {} +func (*Booking) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{14} } + +func (m *Booking) GetBookingId() string { + if m != nil { + return m.BookingId + } + return "" +} + +func (m *Booking) GetSlot() *Slot { + if m != nil { + return m.Slot + } + return nil +} + +func (m *Booking) GetUserInformation() *UserInformation { + if m != nil { + return m.UserInformation + } + return nil +} + +func (m *Booking) GetStatus() BookingStatus { + if m != nil { + return m.Status + } + return BookingStatus_BOOKING_STATUS_UNSPECIFIED +} + +func (m *Booking) GetPaymentInformation() *PaymentInformation { + if m != nil { + return m.PaymentInformation + } + return nil +} + +// [START user_definition] +// Personal information about the person making a booking +type UserInformation struct { + // Unique ID of the user to the partner, chosen by Reserve with Google. + // (required) + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` + // Given name of the user (required) + GivenName string `protobuf:"bytes,2,opt,name=given_name,json=givenName" json:"given_name,omitempty"` + // Family name of the user (required) + FamilyName string `protobuf:"bytes,3,opt,name=family_name,json=familyName" json:"family_name,omitempty"` + // Address of the user (optional) + Address *PostalAddress `protobuf:"bytes,4,opt,name=address" json:"address,omitempty"` + // Phone number of the user (required) + Telephone string `protobuf:"bytes,5,opt,name=telephone" json:"telephone,omitempty"` + // Email address of the user (required) + Email string `protobuf:"bytes,6,opt,name=email" json:"email,omitempty"` +} + +func (m *UserInformation) Reset() { *m = UserInformation{} } +func (m *UserInformation) String() string { return proto.CompactTextString(m) } +func (*UserInformation) ProtoMessage() {} +func (*UserInformation) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{15} } + +func (m *UserInformation) GetUserId() string { + if m != nil { + return m.UserId + } + return "" +} + +func (m *UserInformation) GetGivenName() string { + if m != nil { + return m.GivenName + } + return "" +} + +func (m *UserInformation) GetFamilyName() string { + if m != nil { + return m.FamilyName + } + return "" +} + +func (m *UserInformation) GetAddress() *PostalAddress { + if m != nil { + return m.Address + } + return nil +} + +func (m *UserInformation) GetTelephone() string { + if m != nil { + return m.Telephone + } + return "" +} + +func (m *UserInformation) GetEmail() string { + if m != nil { + return m.Email + } + return "" +} + +// [START paymentprocessing_definition] +type PaymentProcessingParameters struct { + // The payment processor used to process payment for a given booking. + // (required) + // + // Replaced by the payment_processor field. + Processor PaymentProcessingParameters_PaymentProcessor `protobuf:"varint,1,opt,name=processor,enum=v3.PaymentProcessingParameters_PaymentProcessor" json:"processor,omitempty"` + // The token representing the payment method that will be used to pay + // for this booking. This token can be only used once. This token can be + // only used for the merchant associated with this booking. + // + // Each processor may choose its own format for this field. + // An example of Stripe's token is "tok_1C3orL2eZvKYlo2CxReMgS4K". + // + // Replaced by unparsed_payment_method_token, which contains + // payment_method_token as one of its fields. + // For example, for Stripe, unparsed_payment_method_token is a serialized + // JSON object documented at https://stripe.com/docs/api#token_object. + // payment_method_token is the 'id' field parsed out of that. + PaymentMethodToken string `protobuf:"bytes,2,opt,name=payment_method_token,json=paymentMethodToken" json:"payment_method_token,omitempty"` + // The full token received from Google Payments. This is typically a + // serialized JSON object. See documentation from Google Payments and your + // payment processor for the JSON format of the token for your processor. + // https://developers.google.com/pay/api/#participating-google-pay-processors + // + // This token can only be used once, and only for the merchant associated with + // this booking. + UnparsedPaymentMethodToken string `protobuf:"bytes,5,opt,name=unparsed_payment_method_token,json=unparsedPaymentMethodToken" json:"unparsed_payment_method_token,omitempty"` + // The payment processor API version that the given payment token is valid + // for. + // + // Each processor may choose its own format for this field. + // Stripe uses a date (e.g. "2017-06-15"). (required) + Version string `protobuf:"bytes,3,opt,name=version" json:"version,omitempty"` + // The payment processor whose configuration was used to generate this token. + // (required) + PaymentProcessor string `protobuf:"bytes,4,opt,name=payment_processor,json=paymentProcessor" json:"payment_processor,omitempty"` +} + +func (m *PaymentProcessingParameters) Reset() { *m = PaymentProcessingParameters{} } +func (m *PaymentProcessingParameters) String() string { return proto.CompactTextString(m) } +func (*PaymentProcessingParameters) ProtoMessage() {} +func (*PaymentProcessingParameters) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{16} } + +func (m *PaymentProcessingParameters) GetProcessor() PaymentProcessingParameters_PaymentProcessor { + if m != nil { + return m.Processor + } + return PaymentProcessingParameters_PAYMENT_PROCESSOR_UNSPECIFIED +} + +func (m *PaymentProcessingParameters) GetPaymentMethodToken() string { + if m != nil { + return m.PaymentMethodToken + } + return "" +} + +func (m *PaymentProcessingParameters) GetUnparsedPaymentMethodToken() string { + if m != nil { + return m.UnparsedPaymentMethodToken + } + return "" +} + +func (m *PaymentProcessingParameters) GetVersion() string { + if m != nil { + return m.Version + } + return "" +} + +func (m *PaymentProcessingParameters) GetPaymentProcessor() string { + if m != nil { + return m.PaymentProcessor + } + return "" +} + +// [START userpaymentoption_definition] +// This describes a payment option, such as a pack, membership, or +// single-session pass after it has been purchased by a user. It includes an +// identifier for the user payment option, as well as some information about +// the payment option with which it is associated. +type UserPaymentOption struct { + // A unique identifier for the user payment option. This Id MUST be unique + // for all UserPaymentOptions across all merchants and users. (required) + UserPaymentOptionId string `protobuf:"bytes,1,opt,name=user_payment_option_id,json=userPaymentOptionId" json:"user_payment_option_id,omitempty"` + // The user payment option will be valid (usable) between start_time and + // end_time set in UTC. Attempts to use a user payment option to make a + // booking outside of this interval will fail. (both optional) + ValidStartTimeSec int64 `protobuf:"varint,2,opt,name=valid_start_time_sec,json=validStartTimeSec" json:"valid_start_time_sec,omitempty"` + ValidEndTimeSec int64 `protobuf:"varint,3,opt,name=valid_end_time_sec,json=validEndTimeSec" json:"valid_end_time_sec,omitempty"` + // The type of the payment option associated with this user payment option. + // This can be unlimited for a membership or subscription, multi-use for a + // pack, or single-use. (required) + Type PaymentOptionType `protobuf:"varint,4,opt,name=type,enum=v3.PaymentOptionType" json:"type,omitempty"` + // The original number of uses for this user payment option when it was + // purchased. This value is ignored for unlimited payment options. (required) + OriginalCount int32 `protobuf:"varint,5,opt,name=original_count,json=originalCount" json:"original_count,omitempty"` + // The number of uses remaining for this user payment option. If this number + // is 0 for a pack, attempts to use this payment option to make a booking will + // fail. (required) + CurrentCount int32 `protobuf:"varint,6,opt,name=current_count,json=currentCount" json:"current_count,omitempty"` + // The id of the payment option that has been used to purchase this user + // payment option. (required) + PaymentOptionId string `protobuf:"bytes,7,opt,name=payment_option_id,json=paymentOptionId" json:"payment_option_id,omitempty"` +} + +func (m *UserPaymentOption) Reset() { *m = UserPaymentOption{} } +func (m *UserPaymentOption) String() string { return proto.CompactTextString(m) } +func (*UserPaymentOption) ProtoMessage() {} +func (*UserPaymentOption) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{17} } + +func (m *UserPaymentOption) GetUserPaymentOptionId() string { + if m != nil { + return m.UserPaymentOptionId + } + return "" +} + +func (m *UserPaymentOption) GetValidStartTimeSec() int64 { + if m != nil { + return m.ValidStartTimeSec + } + return 0 +} + +func (m *UserPaymentOption) GetValidEndTimeSec() int64 { + if m != nil { + return m.ValidEndTimeSec + } + return 0 +} + +func (m *UserPaymentOption) GetType() PaymentOptionType { + if m != nil { + return m.Type + } + return PaymentOptionType_PAYMENT_OPTION_TYPE_UNSPECIFIED +} + +func (m *UserPaymentOption) GetOriginalCount() int32 { + if m != nil { + return m.OriginalCount + } + return 0 +} + +func (m *UserPaymentOption) GetCurrentCount() int32 { + if m != nil { + return m.CurrentCount + } + return 0 +} + +func (m *UserPaymentOption) GetPaymentOptionId() string { + if m != nil { + return m.PaymentOptionId + } + return "" +} + +// [START paymentinfo_definition] +// Payment details that are sent when creating a new booking. +type PaymentInformation struct { + // Prepayment status of the booking. + // If the prepayment_status is PREPAYMENT_PROVIDED, then + // payment_transaction_id contains the associated unique transaction id for + // the purchase. + // If the prepayment status is PREPAYMENT_REFUNDED, then + // payment_transaction_id contains the associated unique transaction id for + // the refund. (required) + PrepaymentStatus PrepaymentStatus `protobuf:"varint,1,opt,name=prepayment_status,json=prepaymentStatus,enum=v3.PrepaymentStatus" json:"prepayment_status,omitempty"` + // Unique identifier for a payment transaction associated with the booking. + // Empty if not applicable. (required) + PaymentTransactionId string `protobuf:"bytes,2,opt,name=payment_transaction_id,json=paymentTransactionId" json:"payment_transaction_id,omitempty"` + // These fields must match the service price (specified in the Services feed) + // or the PaymentOption corresponding with this service. + // They are included in the booking request and response to verify that + // the price indicated in the feed has not changed since the last feed + // update. + // + // The price of the booking or order, exclusive of any taxes. + // Existence of price or taxes does not imply that they have been paid, + // prepayment_state should be used for that purpose. (required) + Price *Price `protobuf:"bytes,3,opt,name=price" json:"price,omitempty"` + // Taxes that are calculated to be paid for this booking. + // This field can only be absent in one of the following cases: + // (1) the price is exempt from or already inclusive of applicable taxes; or + // (2) the break down between taxes and fees is not available. + // (required when neither of the above holds) + TaxAmount *Price `protobuf:"bytes,4,opt,name=tax_amount,json=taxAmount" json:"tax_amount,omitempty"` + // Whether the partner or Google processed the payment. (required) + PaymentProcessedBy PaymentInformation_PaymentProcessedBy `protobuf:"varint,5,opt,name=payment_processed_by,json=paymentProcessedBy,enum=v3.PaymentInformation_PaymentProcessedBy" json:"payment_processed_by,omitempty"` + // The id of the payment option or user payment option associated with the + // booking. + // If a payment option is purchased as part of a booking, payment_option_id + // will be set with the id of that payment option. + // If an already purchased user payment option is being used to pay for a + // booking, user_payment_option_id will be set with the id of that user + // payment option. + // When included as part of a response proto, the user_payment_option_id + // should be set and must match the UserPaymentOption that is returned in the + // RPC response (e.g. the user_payment_option returned in + // CreateBookingResponse). (one of these required) + // + // Types that are valid to be assigned to PaymentId: + // *PaymentInformation_PaymentOptionId + // *PaymentInformation_UserPaymentOptionId + PaymentId isPaymentInformation_PaymentId `protobuf_oneof:"payment_id"` + // Defines how a deposit may be charged to the user. If there is a deposit, + // this field should be set. (optional) + Deposit *Deposit `protobuf:"bytes,8,opt,name=deposit" json:"deposit,omitempty"` + // Defines a no show fee that may be charged to the user. If the user can be + // charged a no show fee, this field should be set. (optional) + NoShowFee *NoShowFee `protobuf:"bytes,9,opt,name=no_show_fee,json=noShowFee" json:"no_show_fee,omitempty"` + // Total processing fees & taxes that the user needs to pay for the order; + // only applicable to partners that handle order based booking (e.g., with + // CreateOrder method). (optional) + FeesAndTaxes *Price `protobuf:"bytes,10,opt,name=fees_and_taxes,json=feesAndTaxes" json:"fees_and_taxes,omitempty"` +} + +func (m *PaymentInformation) Reset() { *m = PaymentInformation{} } +func (m *PaymentInformation) String() string { return proto.CompactTextString(m) } +func (*PaymentInformation) ProtoMessage() {} +func (*PaymentInformation) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{18} } + +type isPaymentInformation_PaymentId interface { + isPaymentInformation_PaymentId() +} + +type PaymentInformation_PaymentOptionId struct { + PaymentOptionId string `protobuf:"bytes,6,opt,name=payment_option_id,json=paymentOptionId,oneof"` +} +type PaymentInformation_UserPaymentOptionId struct { + UserPaymentOptionId string `protobuf:"bytes,7,opt,name=user_payment_option_id,json=userPaymentOptionId,oneof"` +} + +func (*PaymentInformation_PaymentOptionId) isPaymentInformation_PaymentId() {} +func (*PaymentInformation_UserPaymentOptionId) isPaymentInformation_PaymentId() {} + +func (m *PaymentInformation) GetPaymentId() isPaymentInformation_PaymentId { + if m != nil { + return m.PaymentId + } + return nil +} + +func (m *PaymentInformation) GetPrepaymentStatus() PrepaymentStatus { + if m != nil { + return m.PrepaymentStatus + } + return PrepaymentStatus_PREPAYMENT_STATUS_UNSPECIFIED +} + +func (m *PaymentInformation) GetPaymentTransactionId() string { + if m != nil { + return m.PaymentTransactionId + } + return "" +} + +func (m *PaymentInformation) GetPrice() *Price { + if m != nil { + return m.Price + } + return nil +} + +func (m *PaymentInformation) GetTaxAmount() *Price { + if m != nil { + return m.TaxAmount + } + return nil +} + +func (m *PaymentInformation) GetPaymentProcessedBy() PaymentInformation_PaymentProcessedBy { + if m != nil { + return m.PaymentProcessedBy + } + return PaymentInformation_PAYMENT_PROCESSED_BY_UNSPECIFIED +} + +func (m *PaymentInformation) GetPaymentOptionId() string { + if x, ok := m.GetPaymentId().(*PaymentInformation_PaymentOptionId); ok { + return x.PaymentOptionId + } + return "" +} + +func (m *PaymentInformation) GetUserPaymentOptionId() string { + if x, ok := m.GetPaymentId().(*PaymentInformation_UserPaymentOptionId); ok { + return x.UserPaymentOptionId + } + return "" +} + +func (m *PaymentInformation) GetDeposit() *Deposit { + if m != nil { + return m.Deposit + } + return nil +} + +func (m *PaymentInformation) GetNoShowFee() *NoShowFee { + if m != nil { + return m.NoShowFee + } + return nil +} + +func (m *PaymentInformation) GetFeesAndTaxes() *Price { + if m != nil { + return m.FeesAndTaxes + } + return nil +} + +// XXX_OneofFuncs is for the internal use of the proto package. +func (*PaymentInformation) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { + return _PaymentInformation_OneofMarshaler, _PaymentInformation_OneofUnmarshaler, _PaymentInformation_OneofSizer, []interface{}{ + (*PaymentInformation_PaymentOptionId)(nil), + (*PaymentInformation_UserPaymentOptionId)(nil), + } +} + +func _PaymentInformation_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { + m := msg.(*PaymentInformation) + // payment_id + switch x := m.PaymentId.(type) { + case *PaymentInformation_PaymentOptionId: + b.EncodeVarint(6<<3 | proto.WireBytes) + b.EncodeStringBytes(x.PaymentOptionId) + case *PaymentInformation_UserPaymentOptionId: + b.EncodeVarint(7<<3 | proto.WireBytes) + b.EncodeStringBytes(x.UserPaymentOptionId) + case nil: + default: + return fmt.Errorf("PaymentInformation.PaymentId has unexpected type %T", x) + } + return nil +} + +func _PaymentInformation_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { + m := msg.(*PaymentInformation) + switch tag { + case 6: // payment_id.payment_option_id + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.PaymentId = &PaymentInformation_PaymentOptionId{x} + return true, err + case 7: // payment_id.user_payment_option_id + if wire != proto.WireBytes { + return true, proto.ErrInternalBadWireType + } + x, err := b.DecodeStringBytes() + m.PaymentId = &PaymentInformation_UserPaymentOptionId{x} + return true, err + default: + return false, nil + } +} + +func _PaymentInformation_OneofSizer(msg proto.Message) (n int) { + m := msg.(*PaymentInformation) + // payment_id + switch x := m.PaymentId.(type) { + case *PaymentInformation_PaymentOptionId: + n += proto.SizeVarint(6<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(len(x.PaymentOptionId))) + n += len(x.PaymentOptionId) + case *PaymentInformation_UserPaymentOptionId: + n += proto.SizeVarint(7<<3 | proto.WireBytes) + n += proto.SizeVarint(uint64(len(x.UserPaymentOptionId))) + n += len(x.UserPaymentOptionId) + case nil: + default: + panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) + } + return n +} + +// [START bookingfailure_definition] +// Status data that conveys why (1) creating a lease or (2) creating or updating +// a booking fails. +// BookingFailure is intended to primarily capture business logic errors. +type BookingFailure struct { + // The reason why the booking failed. (required) + Cause BookingFailure_Cause `protobuf:"varint,1,opt,name=cause,enum=v3.BookingFailure_Cause" json:"cause,omitempty"` + // (required only if cause is PAYMENT_ERROR_CARD_TYPE_REJECTED) + RejectedCardType CreditCardType `protobuf:"varint,2,opt,name=rejected_card_type,json=rejectedCardType,enum=v3.CreditCardType" json:"rejected_card_type,omitempty"` + // This optional field is used for the partner to include additional + // information for debugging purpose only. (optional) + Description string `protobuf:"bytes,3,opt,name=description" json:"description,omitempty"` +} + +func (m *BookingFailure) Reset() { *m = BookingFailure{} } +func (m *BookingFailure) String() string { return proto.CompactTextString(m) } +func (*BookingFailure) ProtoMessage() {} +func (*BookingFailure) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{19} } + +func (m *BookingFailure) GetCause() BookingFailure_Cause { + if m != nil { + return m.Cause + } + return BookingFailure_CAUSE_UNSPECIFIED +} + +func (m *BookingFailure) GetRejectedCardType() CreditCardType { + if m != nil { + return m.RejectedCardType + } + return CreditCardType_CREDIT_CARD_TYPE_UNSPECIFIED +} + +func (m *BookingFailure) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +// [START message_slot_availability] +// An inventory slot and associated count of open spots. +type SlotAvailability struct { + Slot *Slot `protobuf:"bytes,1,opt,name=slot" json:"slot,omitempty"` + // Number of available spots. + // 0 indicates that the appointment slot is not available. (required) + CountAvailable int32 `protobuf:"varint,2,opt,name=count_available,json=countAvailable" json:"count_available,omitempty"` +} + +func (m *SlotAvailability) Reset() { *m = SlotAvailability{} } +func (m *SlotAvailability) String() string { return proto.CompactTextString(m) } +func (*SlotAvailability) ProtoMessage() {} +func (*SlotAvailability) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{20} } + +func (m *SlotAvailability) GetSlot() *Slot { + if m != nil { + return m.Slot + } + return nil +} + +func (m *SlotAvailability) GetCountAvailable() int32 { + if m != nil { + return m.CountAvailable + } + return 0 +} + +// [START message_availability_update] +// An update to one ore more slots indicating that the availability for the +// associated time has potentially changed. +type AvailabilityUpdate struct { + SlotAvailability []*SlotAvailability `protobuf:"bytes,1,rep,name=slot_availability,json=slotAvailability" json:"slot_availability,omitempty"` +} + +func (m *AvailabilityUpdate) Reset() { *m = AvailabilityUpdate{} } +func (m *AvailabilityUpdate) String() string { return proto.CompactTextString(m) } +func (*AvailabilityUpdate) ProtoMessage() {} +func (*AvailabilityUpdate) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{21} } + +func (m *AvailabilityUpdate) GetSlotAvailability() []*SlotAvailability { + if m != nil { + return m.SlotAvailability + } + return nil +} + +// [START resources_definition] +// Resource specification that disambiguates an appointment slot +type ResourceIds struct { + // The staff ID as provided in the feed or empty if not applicable or no staff + // was selected. (optional) + StaffId string `protobuf:"bytes,1,opt,name=staff_id,json=staffId" json:"staff_id,omitempty"` + // The room ID as provided in the feed or empty if not applicable or no room + // was selected. (optional) + RoomId string `protobuf:"bytes,2,opt,name=room_id,json=roomId" json:"room_id,omitempty"` + // For Dining Reservations only: the number of seats requested in the booking. + // (optional) + PartySize int32 `protobuf:"varint,3,opt,name=party_size,json=partySize" json:"party_size,omitempty"` +} + +func (m *ResourceIds) Reset() { *m = ResourceIds{} } +func (m *ResourceIds) String() string { return proto.CompactTextString(m) } +func (*ResourceIds) ProtoMessage() {} +func (*ResourceIds) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{22} } + +func (m *ResourceIds) GetStaffId() string { + if m != nil { + return m.StaffId + } + return "" +} + +func (m *ResourceIds) GetRoomId() string { + if m != nil { + return m.RoomId + } + return "" +} + +func (m *ResourceIds) GetPartySize() int32 { + if m != nil { + return m.PartySize + } + return 0 +} + +// [START tickettype_definition] +// TicketType is used to differentiate among tickets (where a ticket can be a +// spot on a raft trip, an admission to a museum, etc.) with different prices +// and/or availabilities due to different user types or different service +// attributes. +type TicketType struct { + // The ticket id is used to differentiate among different ticket types of the + // same service, and is only expected to be unique within a service. + TicketTypeId string `protobuf:"bytes,1,opt,name=ticket_type_id,json=ticketTypeId" json:"ticket_type_id,omitempty"` + // This can be user visible, e.g., “adult”, "child", “veteran”, “Row J”, etc. + ShortDescription string `protobuf:"bytes,2,opt,name=short_description,json=shortDescription" json:"short_description,omitempty"` + // The price of a single ticket of this type, exclusive of any taxes. The tax + // rate of Service is applied to its tickets. + Price *Price `protobuf:"bytes,3,opt,name=price" json:"price,omitempty"` +} + +func (m *TicketType) Reset() { *m = TicketType{} } +func (m *TicketType) String() string { return proto.CompactTextString(m) } +func (*TicketType) ProtoMessage() {} +func (*TicketType) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{23} } + +func (m *TicketType) GetTicketTypeId() string { + if m != nil { + return m.TicketTypeId + } + return "" +} + +func (m *TicketType) GetShortDescription() string { + if m != nil { + return m.ShortDescription + } + return "" +} + +func (m *TicketType) GetPrice() *Price { + if m != nil { + return m.Price + } + return nil +} + +// [START lineitem_definition] +// A single item in an order--the booking of a single service in a single time +// slot. +type LineItem struct { + // ID of the merchant service. (required) + ServiceId string `protobuf:"bytes,1,opt,name=service_id,json=serviceId" json:"service_id,omitempty"` + // Start time of the appointment slot in seconds of UTC time since Unix epoch. + // (required) + StartSec int64 `protobuf:"varint,2,opt,name=start_sec,json=startSec" json:"start_sec,omitempty"` + // Duration of the appointment slot in seconds. (required) + DurationSec int64 `protobuf:"varint,3,opt,name=duration_sec,json=durationSec" json:"duration_sec,omitempty"` + // Number of tickets ordered by type. + Tickets []*LineItem_OrderedTickets `protobuf:"bytes,4,rep,name=tickets" json:"tickets,omitempty"` + // In handling CreateOrderRequest and CheckOrderFulfillabilityRequest, + // the total price (excluding taxes) of the item must be verified to guard + // against price changes. In CreateOrderResponse and + // CheckOrderFulfillabilityResponse, the price should be updated to the + // correct value if the value from the request was incorrect or outdated. + // (reqired) + Price *Price `protobuf:"bytes,5,opt,name=price" json:"price,omitempty"` + // Status of the line item. (required in CreateOrderResponse and + // ListOrdersResponse; should not be set in requests) + Status BookingStatus `protobuf:"varint,6,opt,name=status,enum=v3.BookingStatus" json:"status,omitempty"` +} + +func (m *LineItem) Reset() { *m = LineItem{} } +func (m *LineItem) String() string { return proto.CompactTextString(m) } +func (*LineItem) ProtoMessage() {} +func (*LineItem) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{24} } + +func (m *LineItem) GetServiceId() string { + if m != nil { + return m.ServiceId + } + return "" +} + +func (m *LineItem) GetStartSec() int64 { + if m != nil { + return m.StartSec + } + return 0 +} + +func (m *LineItem) GetDurationSec() int64 { + if m != nil { + return m.DurationSec + } + return 0 +} + +func (m *LineItem) GetTickets() []*LineItem_OrderedTickets { + if m != nil { + return m.Tickets + } + return nil +} + +func (m *LineItem) GetPrice() *Price { + if m != nil { + return m.Price + } + return nil +} + +func (m *LineItem) GetStatus() BookingStatus { + if m != nil { + return m.Status + } + return BookingStatus_BOOKING_STATUS_UNSPECIFIED +} + +type LineItem_OrderedTickets struct { + TicketId string `protobuf:"bytes,1,opt,name=ticket_id,json=ticketId" json:"ticket_id,omitempty"` + Count int32 `protobuf:"varint,2,opt,name=count" json:"count,omitempty"` +} + +func (m *LineItem_OrderedTickets) Reset() { *m = LineItem_OrderedTickets{} } +func (m *LineItem_OrderedTickets) String() string { return proto.CompactTextString(m) } +func (*LineItem_OrderedTickets) ProtoMessage() {} +func (*LineItem_OrderedTickets) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{24, 0} } + +func (m *LineItem_OrderedTickets) GetTicketId() string { + if m != nil { + return m.TicketId + } + return "" +} + +func (m *LineItem_OrderedTickets) GetCount() int32 { + if m != nil { + return m.Count + } + return 0 +} + +// [START lineitemfulfillability_definition] +// Fulfillability of a line item. +type LineItemFulfillability struct { + // The line item of question. (required) + Item *LineItem `protobuf:"bytes,1,opt,name=item" json:"item,omitempty"` + // (required) + Result LineItemFulfillability_ItemFulfillabilityResult `protobuf:"varint,2,opt,name=result,enum=v3.LineItemFulfillability_ItemFulfillabilityResult" json:"result,omitempty"` + // Additional description of the reason if the item is unfulfillable. + // (optional) + UnfulfillableReason string `protobuf:"bytes,3,opt,name=unfulfillable_reason,json=unfulfillableReason" json:"unfulfillable_reason,omitempty"` + // Updated availability for this slot can be piggybacked in + // CheckOrderFulfillabilityResponse. (optional) + SpotsOpen int32 `protobuf:"varint,4,opt,name=spots_open,json=spotsOpen" json:"spots_open,omitempty"` + // Updated ticket types can be piggybacked in + // CheckOrderFulfillabilityResponse. If non-empty, all available ticket types + // for this slot with up-to-date prices should be listed without omitting any. + // (optional) + TicketType []*TicketType `protobuf:"bytes,5,rep,name=ticket_type,json=ticketType" json:"ticket_type,omitempty"` +} + +func (m *LineItemFulfillability) Reset() { *m = LineItemFulfillability{} } +func (m *LineItemFulfillability) String() string { return proto.CompactTextString(m) } +func (*LineItemFulfillability) ProtoMessage() {} +func (*LineItemFulfillability) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{25} } + +func (m *LineItemFulfillability) GetItem() *LineItem { + if m != nil { + return m.Item + } + return nil +} + +func (m *LineItemFulfillability) GetResult() LineItemFulfillability_ItemFulfillabilityResult { + if m != nil { + return m.Result + } + return LineItemFulfillability_ITEM_FULFILLABILITY_RESULT_UNSPECIFIED +} + +func (m *LineItemFulfillability) GetUnfulfillableReason() string { + if m != nil { + return m.UnfulfillableReason + } + return "" +} + +func (m *LineItemFulfillability) GetSpotsOpen() int32 { + if m != nil { + return m.SpotsOpen + } + return 0 +} + +func (m *LineItemFulfillability) GetTicketType() []*TicketType { + if m != nil { + return m.TicketType + } + return nil +} + +// [START orderfulfillability_definition] +type OrderFulfillability struct { + Result OrderFulfillability_OrderFulfillabilityResult `protobuf:"varint,1,opt,name=result,enum=v3.OrderFulfillability_OrderFulfillabilityResult" json:"result,omitempty"` + // Fulfillability results of all line items in this order (required). + ItemFulfillability []*LineItemFulfillability `protobuf:"bytes,2,rep,name=item_fulfillability,json=itemFulfillability" json:"item_fulfillability,omitempty"` + // Additional description of the reason if the item is unfulfillable. + // (optional) + UnfulfillableReason string `protobuf:"bytes,3,opt,name=unfulfillable_reason,json=unfulfillableReason" json:"unfulfillable_reason,omitempty"` +} + +func (m *OrderFulfillability) Reset() { *m = OrderFulfillability{} } +func (m *OrderFulfillability) String() string { return proto.CompactTextString(m) } +func (*OrderFulfillability) ProtoMessage() {} +func (*OrderFulfillability) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{26} } + +func (m *OrderFulfillability) GetResult() OrderFulfillability_OrderFulfillabilityResult { + if m != nil { + return m.Result + } + return OrderFulfillability_ORDER_FULFILLABILITY_RESULT_UNSPECIFIED +} + +func (m *OrderFulfillability) GetItemFulfillability() []*LineItemFulfillability { + if m != nil { + return m.ItemFulfillability + } + return nil +} + +func (m *OrderFulfillability) GetUnfulfillableReason() string { + if m != nil { + return m.UnfulfillableReason + } + return "" +} + +// [START order_definition] +// An order for service appointments with a merchant. +type Order struct { + // ID of this order, chosen by the booking partner who handles the order + // (required in CreateOrderResponse and ListOrdersResponse, must not be set in + // CreateOrderRequest) + OrderId string `protobuf:"bytes,1,opt,name=order_id,json=orderId" json:"order_id,omitempty"` + // Personal information of the user making the order (required) + UserInformation *UserInformation `protobuf:"bytes,2,opt,name=user_information,json=userInformation" json:"user_information,omitempty"` + // Information about payment transactions that relate to the order. + // (optional) + PaymentInformation *PaymentInformation `protobuf:"bytes,3,opt,name=payment_information,json=paymentInformation" json:"payment_information,omitempty"` + // The merchant that all services in this order belong to. + MerchantId string `protobuf:"bytes,4,opt,name=merchant_id,json=merchantId" json:"merchant_id,omitempty"` + // Line items in this order. + Item []*LineItem `protobuf:"bytes,5,rep,name=item" json:"item,omitempty"` +} + +func (m *Order) Reset() { *m = Order{} } +func (m *Order) String() string { return proto.CompactTextString(m) } +func (*Order) ProtoMessage() {} +func (*Order) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{27} } + +func (m *Order) GetOrderId() string { + if m != nil { + return m.OrderId + } + return "" +} + +func (m *Order) GetUserInformation() *UserInformation { + if m != nil { + return m.UserInformation + } + return nil +} + +func (m *Order) GetPaymentInformation() *PaymentInformation { + if m != nil { + return m.PaymentInformation + } + return nil +} + +func (m *Order) GetMerchantId() string { + if m != nil { + return m.MerchantId + } + return "" +} + +func (m *Order) GetItem() []*LineItem { + if m != nil { + return m.Item + } + return nil +} + +// [START orderfailure_definition] +// Status data that conveys why creating an order fails. +// OrderFailure is intended to primarily capture business logic errors. +type OrderFailure struct { + // The reason why the order failed. (required) + Cause OrderFailure_Cause `protobuf:"varint,1,opt,name=cause,enum=v3.OrderFailure_Cause" json:"cause,omitempty"` + // (required only if cause is ORDER_UNFULFILLABLE) + Fulfillability *OrderFulfillability `protobuf:"bytes,2,opt,name=fulfillability" json:"fulfillability,omitempty"` + // (required only if cause is PAYMENT_ERROR_CARD_TYPE_REJECTED) + RejectedCardType CreditCardType `protobuf:"varint,3,opt,name=rejected_card_type,json=rejectedCardType,enum=v3.CreditCardType" json:"rejected_card_type,omitempty"` + // This optional field is used for the partner to include additional + // information for debugging purpose only. (optional) + Description string `protobuf:"bytes,4,opt,name=description" json:"description,omitempty"` +} + +func (m *OrderFailure) Reset() { *m = OrderFailure{} } +func (m *OrderFailure) String() string { return proto.CompactTextString(m) } +func (*OrderFailure) ProtoMessage() {} +func (*OrderFailure) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{28} } + +func (m *OrderFailure) GetCause() OrderFailure_Cause { + if m != nil { + return m.Cause + } + return OrderFailure_CAUSE_UNSPECIFIED +} + +func (m *OrderFailure) GetFulfillability() *OrderFulfillability { + if m != nil { + return m.Fulfillability + } + return nil +} + +func (m *OrderFailure) GetRejectedCardType() CreditCardType { + if m != nil { + return m.RejectedCardType + } + return CreditCardType_CREDIT_CARD_TYPE_UNSPECIFIED +} + +func (m *OrderFailure) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +// [START method_check_availability] +// Request to check availability for a Slot. +type CheckAvailabilityRequest struct { + // The appointment slot that is being checked (required) + Slot *Slot `protobuf:"bytes,1,opt,name=slot" json:"slot,omitempty"` +} + +func (m *CheckAvailabilityRequest) Reset() { *m = CheckAvailabilityRequest{} } +func (m *CheckAvailabilityRequest) String() string { return proto.CompactTextString(m) } +func (*CheckAvailabilityRequest) ProtoMessage() {} +func (*CheckAvailabilityRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{29} } + +func (m *CheckAvailabilityRequest) GetSlot() *Slot { + if m != nil { + return m.Slot + } + return nil +} + +// Response for the CheckAvailability RPC with the availability of the +// appointment slot. +type CheckAvailabilityResponse struct { + // The requested slot. (required) + Slot *Slot `protobuf:"bytes,1,opt,name=slot" json:"slot,omitempty"` + // Number of available spots. + // 0 indicates that the appointment slot is not available. (required) + CountAvailable int32 `protobuf:"varint,2,opt,name=count_available,json=countAvailable" json:"count_available,omitempty"` + // The requirement to show the slots duration and/or endtime. This field will + // be ignored if the slot is unavailable. (optional) + DurationRequirement CheckAvailabilityResponse_DurationRequirement `protobuf:"varint,3,opt,name=duration_requirement,json=durationRequirement,enum=v3.CheckAvailabilityResponse_DurationRequirement" json:"duration_requirement,omitempty"` + // Optionally, the partner can return additional updated information about the + // availability for this merchant if this information is present when + // responding to the CheckAvailabilityRequest and if there is no negative + // impact on the CheckAvailability request latency. + // For instance an entire day of merchant availability for a superset of + // resources can be returned here. + AvailabilityUpdate *AvailabilityUpdate `protobuf:"bytes,4,opt,name=availability_update,json=availabilityUpdate" json:"availability_update,omitempty"` +} + +func (m *CheckAvailabilityResponse) Reset() { *m = CheckAvailabilityResponse{} } +func (m *CheckAvailabilityResponse) String() string { return proto.CompactTextString(m) } +func (*CheckAvailabilityResponse) ProtoMessage() {} +func (*CheckAvailabilityResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{30} } + +func (m *CheckAvailabilityResponse) GetSlot() *Slot { + if m != nil { + return m.Slot + } + return nil +} + +func (m *CheckAvailabilityResponse) GetCountAvailable() int32 { + if m != nil { + return m.CountAvailable + } + return 0 +} + +func (m *CheckAvailabilityResponse) GetDurationRequirement() CheckAvailabilityResponse_DurationRequirement { + if m != nil { + return m.DurationRequirement + } + return CheckAvailabilityResponse_DURATION_REQUIREMENT_UNSPECIFIED +} + +func (m *CheckAvailabilityResponse) GetAvailabilityUpdate() *AvailabilityUpdate { + if m != nil { + return m.AvailabilityUpdate + } + return nil +} + +// [START method_get_booking_status] +// Request to get booking status and prepayment status for a Booking. +type GetBookingStatusRequest struct { + // ID of the existing booking (required) + BookingId string `protobuf:"bytes,1,opt,name=booking_id,json=bookingId" json:"booking_id,omitempty"` +} + +func (m *GetBookingStatusRequest) Reset() { *m = GetBookingStatusRequest{} } +func (m *GetBookingStatusRequest) String() string { return proto.CompactTextString(m) } +func (*GetBookingStatusRequest) ProtoMessage() {} +func (*GetBookingStatusRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{31} } + +func (m *GetBookingStatusRequest) GetBookingId() string { + if m != nil { + return m.BookingId + } + return "" +} + +// Response for the GetBookingStatus RPC with booking status and prepayment +// status. +type GetBookingStatusResponse struct { + // ID of the booking (required) + BookingId string `protobuf:"bytes,1,opt,name=booking_id,json=bookingId" json:"booking_id,omitempty"` + // Status of the booking (required) + BookingStatus BookingStatus `protobuf:"varint,2,opt,name=booking_status,json=bookingStatus,enum=v3.BookingStatus" json:"booking_status,omitempty"` + // Prepayment status of the booking (required) + PrepaymentStatus PrepaymentStatus `protobuf:"varint,3,opt,name=prepayment_status,json=prepaymentStatus,enum=v3.PrepaymentStatus" json:"prepayment_status,omitempty"` +} + +func (m *GetBookingStatusResponse) Reset() { *m = GetBookingStatusResponse{} } +func (m *GetBookingStatusResponse) String() string { return proto.CompactTextString(m) } +func (*GetBookingStatusResponse) ProtoMessage() {} +func (*GetBookingStatusResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{32} } + +func (m *GetBookingStatusResponse) GetBookingId() string { + if m != nil { + return m.BookingId + } + return "" +} + +func (m *GetBookingStatusResponse) GetBookingStatus() BookingStatus { + if m != nil { + return m.BookingStatus + } + return BookingStatus_BOOKING_STATUS_UNSPECIFIED +} + +func (m *GetBookingStatusResponse) GetPrepaymentStatus() PrepaymentStatus { + if m != nil { + return m.PrepaymentStatus + } + return PrepaymentStatus_PREPAYMENT_STATUS_UNSPECIFIED +} + +// [START method_check_order_fulfillability] +// Request to check the fulfillability of an order. +type CheckOrderFulfillabilityRequest struct { + // The merchant that this order is intended for. (required) + MerchantId string `protobuf:"bytes,1,opt,name=merchant_id,json=merchantId" json:"merchant_id,omitempty"` + // The line items in this order. All services requested must belong to the + // specified merchant. (required) + Item []*LineItem `protobuf:"bytes,2,rep,name=item" json:"item,omitempty"` +} + +func (m *CheckOrderFulfillabilityRequest) Reset() { *m = CheckOrderFulfillabilityRequest{} } +func (m *CheckOrderFulfillabilityRequest) String() string { return proto.CompactTextString(m) } +func (*CheckOrderFulfillabilityRequest) ProtoMessage() {} +func (*CheckOrderFulfillabilityRequest) Descriptor() ([]byte, []int) { + return fileDescriptor0, []int{33} +} + +func (m *CheckOrderFulfillabilityRequest) GetMerchantId() string { + if m != nil { + return m.MerchantId + } + return "" +} + +func (m *CheckOrderFulfillabilityRequest) GetItem() []*LineItem { + if m != nil { + return m.Item + } + return nil +} + +// Response for the CheckOrderfulfillabilityRequest. +type CheckOrderFulfillabilityResponse struct { + // Fulfillability status of the order, potentially contains updated + // availabilities and prices of the requested line item. (required) + Fulfillability *OrderFulfillability `protobuf:"bytes,1,opt,name=fulfillability" json:"fulfillability,omitempty"` + // Total processing fees & taxes that need to be paid for this order. + // (required) + FeesAndTaxes *Price `protobuf:"bytes,2,opt,name=fees_and_taxes,json=feesAndTaxes" json:"fees_and_taxes,omitempty"` +} + +func (m *CheckOrderFulfillabilityResponse) Reset() { *m = CheckOrderFulfillabilityResponse{} } +func (m *CheckOrderFulfillabilityResponse) String() string { return proto.CompactTextString(m) } +func (*CheckOrderFulfillabilityResponse) ProtoMessage() {} +func (*CheckOrderFulfillabilityResponse) Descriptor() ([]byte, []int) { + return fileDescriptor0, []int{34} +} + +func (m *CheckOrderFulfillabilityResponse) GetFulfillability() *OrderFulfillability { + if m != nil { + return m.Fulfillability + } + return nil +} + +func (m *CheckOrderFulfillabilityResponse) GetFeesAndTaxes() *Price { + if m != nil { + return m.FeesAndTaxes + } + return nil +} + +// [START method_create_booking] +// Request to create a Booking for an inventory slot. Consumes the lease if +// provided. +type CreateBookingRequest struct { + // The inventory slot that is being requested to make this booking. + // If lease_ref is provided, slot must match the lease; slot is provided for + // the partner to verify the lease information. + // If lease_ref is absent, then create the booking for the slot. (required) + Slot *Slot `protobuf:"bytes,1,opt,name=slot" json:"slot,omitempty"` + // The lease that is being confirmed to make this booking. + // If lease_ref is provided, then create the booking using the lease. + // (optional) + LeaseRef *LeaseReference `protobuf:"bytes,2,opt,name=lease_ref,json=leaseRef" json:"lease_ref,omitempty"` + // Personal information of the user making the appointment (required) + UserInformation *UserInformation `protobuf:"bytes,3,opt,name=user_information,json=userInformation" json:"user_information,omitempty"` + // Information about payments. When payment authorizations are handled by + // Google, if the booking request does not succeed, payment authorizations are + // automatically canceled. (optional) + PaymentInformation *PaymentInformation `protobuf:"bytes,4,opt,name=payment_information,json=paymentInformation" json:"payment_information,omitempty"` + // The parameters to be used if the payment is processed by the partner + // (i.e. payment_information.payment_processed_by is equal to + // PROCESSED_BY_PARTNER). (optional) + PaymentProcessingParameters *PaymentProcessingParameters `protobuf:"bytes,5,opt,name=payment_processing_parameters,json=paymentProcessingParameters" json:"payment_processing_parameters,omitempty"` + // Idempotency token for CreateBooking requests. (required) + IdempotencyToken string `protobuf:"bytes,6,opt,name=idempotency_token,json=idempotencyToken" json:"idempotency_token,omitempty"` + // A string from the user which contains any special requests or additional + // information that they would like to notify the merchant about. (optional) + AdditionalRequest string `protobuf:"bytes,7,opt,name=additional_request,json=additionalRequest" json:"additional_request,omitempty"` +} + +func (m *CreateBookingRequest) Reset() { *m = CreateBookingRequest{} } +func (m *CreateBookingRequest) String() string { return proto.CompactTextString(m) } +func (*CreateBookingRequest) ProtoMessage() {} +func (*CreateBookingRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{35} } + +func (m *CreateBookingRequest) GetSlot() *Slot { + if m != nil { + return m.Slot + } + return nil +} + +func (m *CreateBookingRequest) GetLeaseRef() *LeaseReference { + if m != nil { + return m.LeaseRef + } + return nil +} + +func (m *CreateBookingRequest) GetUserInformation() *UserInformation { + if m != nil { + return m.UserInformation + } + return nil +} + +func (m *CreateBookingRequest) GetPaymentInformation() *PaymentInformation { + if m != nil { + return m.PaymentInformation + } + return nil +} + +func (m *CreateBookingRequest) GetPaymentProcessingParameters() *PaymentProcessingParameters { + if m != nil { + return m.PaymentProcessingParameters + } + return nil +} + +func (m *CreateBookingRequest) GetIdempotencyToken() string { + if m != nil { + return m.IdempotencyToken + } + return "" +} + +func (m *CreateBookingRequest) GetAdditionalRequest() string { + if m != nil { + return m.AdditionalRequest + } + return "" +} + +// Response with the created Booking for an inventory slot. +type CreateBookingResponse struct { + // The created booking (required) + Booking *Booking `protobuf:"bytes,1,opt,name=booking" json:"booking,omitempty"` + // The updated user payment option used in this booking. + // If a new payment option was purchased to pay for the booking, this should + // be a newly created user payment option. + // If an already purchased user payment option was used for this booking, + // this should reflect an updated version of that user payment option. + // (optional) + UserPaymentOption *UserPaymentOption `protobuf:"bytes,2,opt,name=user_payment_option,json=userPaymentOption" json:"user_payment_option,omitempty"` + // If creating a booking fails, this field should reflect the business logic + // error (e.g., slot has become unavailable) and all other fields in the + // CreateBookingResponse message are expected to be unset. (required if + // failure occurs) + BookingFailure *BookingFailure `protobuf:"bytes,3,opt,name=booking_failure,json=bookingFailure" json:"booking_failure,omitempty"` +} + +func (m *CreateBookingResponse) Reset() { *m = CreateBookingResponse{} } +func (m *CreateBookingResponse) String() string { return proto.CompactTextString(m) } +func (*CreateBookingResponse) ProtoMessage() {} +func (*CreateBookingResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{36} } + +func (m *CreateBookingResponse) GetBooking() *Booking { + if m != nil { + return m.Booking + } + return nil +} + +func (m *CreateBookingResponse) GetUserPaymentOption() *UserPaymentOption { + if m != nil { + return m.UserPaymentOption + } + return nil +} + +func (m *CreateBookingResponse) GetBookingFailure() *BookingFailure { + if m != nil { + return m.BookingFailure + } + return nil +} + +// [START method_create_order] +// Request to create an order. +type CreateOrderRequest struct { + // The order to create. (required) + Order *Order `protobuf:"bytes,1,opt,name=order" json:"order,omitempty"` + // The parameters to be used if the payment is processed by the partner + // (i.e. order.payment_information.payment_processed_by is equal to + // PROCESSED_BY_PARTNER). (required if payment is processed by the partner) + PaymentProcessingParameters *PaymentProcessingParameters `protobuf:"bytes,2,opt,name=payment_processing_parameters,json=paymentProcessingParameters" json:"payment_processing_parameters,omitempty"` + // Idempotency token for CreateOrder requests. (required) + IdempotencyToken string `protobuf:"bytes,3,opt,name=idempotency_token,json=idempotencyToken" json:"idempotency_token,omitempty"` +} + +func (m *CreateOrderRequest) Reset() { *m = CreateOrderRequest{} } +func (m *CreateOrderRequest) String() string { return proto.CompactTextString(m) } +func (*CreateOrderRequest) ProtoMessage() {} +func (*CreateOrderRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{37} } + +func (m *CreateOrderRequest) GetOrder() *Order { + if m != nil { + return m.Order + } + return nil +} + +func (m *CreateOrderRequest) GetPaymentProcessingParameters() *PaymentProcessingParameters { + if m != nil { + return m.PaymentProcessingParameters + } + return nil +} + +func (m *CreateOrderRequest) GetIdempotencyToken() string { + if m != nil { + return m.IdempotencyToken + } + return "" +} + +// Response for the CreateOrderRequest. +type CreateOrderResponse struct { + // The order created. (required) + Order *Order `protobuf:"bytes,1,opt,name=order" json:"order,omitempty"` + // If creating an order fails, this field should reflect the business logic + // error (e.g., slot has become unavailable or price has changed) and all + // other fields in the CreateOrderResponse are expected to be unset. (required + // if failure occurs) + OrderFailure *OrderFailure `protobuf:"bytes,2,opt,name=order_failure,json=orderFailure" json:"order_failure,omitempty"` +} + +func (m *CreateOrderResponse) Reset() { *m = CreateOrderResponse{} } +func (m *CreateOrderResponse) String() string { return proto.CompactTextString(m) } +func (*CreateOrderResponse) ProtoMessage() {} +func (*CreateOrderResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{38} } + +func (m *CreateOrderResponse) GetOrder() *Order { + if m != nil { + return m.Order + } + return nil +} + +func (m *CreateOrderResponse) GetOrderFailure() *OrderFailure { + if m != nil { + return m.OrderFailure + } + return nil +} + +// [START method_create_lease] +// Request to create a Leaese for a slot in the inventory. The expiration time +// in the returned Lease may be modified by the backend, e.g. if the requested +// lease period is too long. +type CreateLeaseRequest struct { + // The lease to be created with information about the appointment slot + // (required) + Lease *Lease `protobuf:"bytes,1,opt,name=lease" json:"lease,omitempty"` +} + +func (m *CreateLeaseRequest) Reset() { *m = CreateLeaseRequest{} } +func (m *CreateLeaseRequest) String() string { return proto.CompactTextString(m) } +func (*CreateLeaseRequest) ProtoMessage() {} +func (*CreateLeaseRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{39} } + +func (m *CreateLeaseRequest) GetLease() *Lease { + if m != nil { + return m.Lease + } + return nil +} + +// Response for the CreateLease RPC with the created Lease. +type CreateLeaseResponse struct { + // The created Lease (required) + Lease *Lease `protobuf:"bytes,1,opt,name=lease" json:"lease,omitempty"` + // If creating a lease fails, this field should reflect the business logic + // error (e.g., slot has become unavailable) and lease field is expected to be + // unset. (required if failure occurs) + BookingFailure *BookingFailure `protobuf:"bytes,2,opt,name=booking_failure,json=bookingFailure" json:"booking_failure,omitempty"` +} + +func (m *CreateLeaseResponse) Reset() { *m = CreateLeaseResponse{} } +func (m *CreateLeaseResponse) String() string { return proto.CompactTextString(m) } +func (*CreateLeaseResponse) ProtoMessage() {} +func (*CreateLeaseResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{40} } + +func (m *CreateLeaseResponse) GetLease() *Lease { + if m != nil { + return m.Lease + } + return nil +} + +func (m *CreateLeaseResponse) GetBookingFailure() *BookingFailure { + if m != nil { + return m.BookingFailure + } + return nil +} + +// [START method_list_bookings] +// Request to list all bookings for a user +type ListBookingsRequest struct { + // ID of the user (required) + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` +} + +func (m *ListBookingsRequest) Reset() { *m = ListBookingsRequest{} } +func (m *ListBookingsRequest) String() string { return proto.CompactTextString(m) } +func (*ListBookingsRequest) ProtoMessage() {} +func (*ListBookingsRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{41} } + +func (m *ListBookingsRequest) GetUserId() string { + if m != nil { + return m.UserId + } + return "" +} + +// Response for the ListBookings RPC with all bookings for the requested user. +type ListBookingsResponse struct { + // All bookings of the user (required) + Bookings []*Booking `protobuf:"bytes,1,rep,name=bookings" json:"bookings,omitempty"` +} + +func (m *ListBookingsResponse) Reset() { *m = ListBookingsResponse{} } +func (m *ListBookingsResponse) String() string { return proto.CompactTextString(m) } +func (*ListBookingsResponse) ProtoMessage() {} +func (*ListBookingsResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{42} } + +func (m *ListBookingsResponse) GetBookings() []*Booking { + if m != nil { + return m.Bookings + } + return nil +} + +// [START method_list_orders] +// Request to list orders. +type ListOrdersRequest struct { + // ID of the user (required only if order_id is not set). + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId" json:"user_id,omitempty"` + // If set, return only the specified orders; otherwise, return all orders of + // the user. (required only if user_id is not set). + OrderId []string `protobuf:"bytes,2,rep,name=order_id,json=orderId" json:"order_id,omitempty"` +} + +func (m *ListOrdersRequest) Reset() { *m = ListOrdersRequest{} } +func (m *ListOrdersRequest) String() string { return proto.CompactTextString(m) } +func (*ListOrdersRequest) ProtoMessage() {} +func (*ListOrdersRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{43} } + +func (m *ListOrdersRequest) GetUserId() string { + if m != nil { + return m.UserId + } + return "" +} + +func (m *ListOrdersRequest) GetOrderId() []string { + if m != nil { + return m.OrderId + } + return nil +} + +// Response for the ListOrders RPC. +type ListOrdersResponse struct { + // All requested orders (required) + Order []*Order `protobuf:"bytes,1,rep,name=order" json:"order,omitempty"` +} + +func (m *ListOrdersResponse) Reset() { *m = ListOrdersResponse{} } +func (m *ListOrdersResponse) String() string { return proto.CompactTextString(m) } +func (*ListOrdersResponse) ProtoMessage() {} +func (*ListOrdersResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{44} } + +func (m *ListOrdersResponse) GetOrder() []*Order { + if m != nil { + return m.Order + } + return nil +} + +// [START method_update_booking] +// Request to update a Booking. +type UpdateBookingRequest struct { + // The booking to be updated + // The following fields can be set in a booking: + // - status, to cancel a booking. + // - start_time and duration in the slot, to reschedule a booking. (required) + Booking *Booking `protobuf:"bytes,1,opt,name=booking" json:"booking,omitempty"` +} + +func (m *UpdateBookingRequest) Reset() { *m = UpdateBookingRequest{} } +func (m *UpdateBookingRequest) String() string { return proto.CompactTextString(m) } +func (*UpdateBookingRequest) ProtoMessage() {} +func (*UpdateBookingRequest) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{45} } + +func (m *UpdateBookingRequest) GetBooking() *Booking { + if m != nil { + return m.Booking + } + return nil +} + +// Response with the updated Booking. +type UpdateBookingResponse struct { + // The updated booking (required) + Booking *Booking `protobuf:"bytes,1,opt,name=booking" json:"booking,omitempty"` + // The updated user payment option originally used to pay for this booking. + // This should be set if the UpdateBookingRequest results in a change to + // the UserPaymentOption. + // For instance, if the booking is canceled, the UserPaymentOption should + // reflect an additional credit to the user. In the case of a multi-use + // payment option, the current_count should be increased by one to + // allow the user to create another booking with this payment option. In the + // case of a single-use payment option, a new single-use user payment option + // should be returned. (required if altered in update) + UserPaymentOption *UserPaymentOption `protobuf:"bytes,2,opt,name=user_payment_option,json=userPaymentOption" json:"user_payment_option,omitempty"` + // If updating a booking fails, this field should reflect the business logic + // error (e.g., booking is not cancellable) (required if failure occurs) + BookingFailure *BookingFailure `protobuf:"bytes,3,opt,name=booking_failure,json=bookingFailure" json:"booking_failure,omitempty"` +} + +func (m *UpdateBookingResponse) Reset() { *m = UpdateBookingResponse{} } +func (m *UpdateBookingResponse) String() string { return proto.CompactTextString(m) } +func (*UpdateBookingResponse) ProtoMessage() {} +func (*UpdateBookingResponse) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{46} } + +func (m *UpdateBookingResponse) GetBooking() *Booking { + if m != nil { + return m.Booking + } + return nil +} + +func (m *UpdateBookingResponse) GetUserPaymentOption() *UserPaymentOption { + if m != nil { + return m.UserPaymentOption + } + return nil +} + +func (m *UpdateBookingResponse) GetBookingFailure() *BookingFailure { + if m != nil { + return m.BookingFailure + } + return nil +} + +func init() { + proto.RegisterType((*PostalAddress)(nil), "v3.PostalAddress") + proto.RegisterType((*GeoCoordinates)(nil), "v3.GeoCoordinates") + proto.RegisterType((*Price)(nil), "v3.Price") + proto.RegisterType((*TaxRate)(nil), "v3.TaxRate") + proto.RegisterType((*SchedulingRules)(nil), "v3.SchedulingRules") + proto.RegisterType((*IngestionQueuePayload)(nil), "v3.IngestionQueuePayload") + proto.RegisterType((*IngestionStatus)(nil), "v3.IngestionStatus") + proto.RegisterType((*TimeRange)(nil), "v3.TimeRange") + proto.RegisterType((*NoShowFee)(nil), "v3.NoShowFee") + proto.RegisterType((*Deposit)(nil), "v3.Deposit") + proto.RegisterType((*ActionLink)(nil), "v3.ActionLink") + proto.RegisterType((*Slot)(nil), "v3.Slot") + proto.RegisterType((*Lease)(nil), "v3.Lease") + proto.RegisterType((*LeaseReference)(nil), "v3.LeaseReference") + proto.RegisterType((*Booking)(nil), "v3.Booking") + proto.RegisterType((*UserInformation)(nil), "v3.UserInformation") + proto.RegisterType((*PaymentProcessingParameters)(nil), "v3.PaymentProcessingParameters") + proto.RegisterType((*UserPaymentOption)(nil), "v3.UserPaymentOption") + proto.RegisterType((*PaymentInformation)(nil), "v3.PaymentInformation") + proto.RegisterType((*BookingFailure)(nil), "v3.BookingFailure") + proto.RegisterType((*SlotAvailability)(nil), "v3.SlotAvailability") + proto.RegisterType((*AvailabilityUpdate)(nil), "v3.AvailabilityUpdate") + proto.RegisterType((*ResourceIds)(nil), "v3.ResourceIds") + proto.RegisterType((*TicketType)(nil), "v3.TicketType") + proto.RegisterType((*LineItem)(nil), "v3.LineItem") + proto.RegisterType((*LineItem_OrderedTickets)(nil), "v3.LineItem.OrderedTickets") + proto.RegisterType((*LineItemFulfillability)(nil), "v3.LineItemFulfillability") + proto.RegisterType((*OrderFulfillability)(nil), "v3.OrderFulfillability") + proto.RegisterType((*Order)(nil), "v3.Order") + proto.RegisterType((*OrderFailure)(nil), "v3.OrderFailure") + proto.RegisterType((*CheckAvailabilityRequest)(nil), "v3.CheckAvailabilityRequest") + proto.RegisterType((*CheckAvailabilityResponse)(nil), "v3.CheckAvailabilityResponse") + proto.RegisterType((*GetBookingStatusRequest)(nil), "v3.GetBookingStatusRequest") + proto.RegisterType((*GetBookingStatusResponse)(nil), "v3.GetBookingStatusResponse") + proto.RegisterType((*CheckOrderFulfillabilityRequest)(nil), "v3.CheckOrderFulfillabilityRequest") + proto.RegisterType((*CheckOrderFulfillabilityResponse)(nil), "v3.CheckOrderFulfillabilityResponse") + proto.RegisterType((*CreateBookingRequest)(nil), "v3.CreateBookingRequest") + proto.RegisterType((*CreateBookingResponse)(nil), "v3.CreateBookingResponse") + proto.RegisterType((*CreateOrderRequest)(nil), "v3.CreateOrderRequest") + proto.RegisterType((*CreateOrderResponse)(nil), "v3.CreateOrderResponse") + proto.RegisterType((*CreateLeaseRequest)(nil), "v3.CreateLeaseRequest") + proto.RegisterType((*CreateLeaseResponse)(nil), "v3.CreateLeaseResponse") + proto.RegisterType((*ListBookingsRequest)(nil), "v3.ListBookingsRequest") + proto.RegisterType((*ListBookingsResponse)(nil), "v3.ListBookingsResponse") + proto.RegisterType((*ListOrdersRequest)(nil), "v3.ListOrdersRequest") + proto.RegisterType((*ListOrdersResponse)(nil), "v3.ListOrdersResponse") + proto.RegisterType((*UpdateBookingRequest)(nil), "v3.UpdateBookingRequest") + proto.RegisterType((*UpdateBookingResponse)(nil), "v3.UpdateBookingResponse") + proto.RegisterEnum("v3.IngestionSource", IngestionSource_name, IngestionSource_value) + proto.RegisterEnum("v3.ContentType", ContentType_name, ContentType_value) + proto.RegisterEnum("v3.PriceType", PriceType_name, PriceType_value) + proto.RegisterEnum("v3.RequireCreditCard", RequireCreditCard_name, RequireCreditCard_value) + proto.RegisterEnum("v3.PaymentOptionType", PaymentOptionType_name, PaymentOptionType_value) + proto.RegisterEnum("v3.BookingStatus", BookingStatus_name, BookingStatus_value) + proto.RegisterEnum("v3.CreditCardType", CreditCardType_name, CreditCardType_value) + proto.RegisterEnum("v3.PrepaymentStatus", PrepaymentStatus_name, PrepaymentStatus_value) + proto.RegisterEnum("v3.IngestionStatus_Code", IngestionStatus_Code_name, IngestionStatus_Code_value) + proto.RegisterEnum("v3.PaymentProcessingParameters_PaymentProcessor", PaymentProcessingParameters_PaymentProcessor_name, PaymentProcessingParameters_PaymentProcessor_value) + proto.RegisterEnum("v3.PaymentInformation_PaymentProcessedBy", PaymentInformation_PaymentProcessedBy_name, PaymentInformation_PaymentProcessedBy_value) + proto.RegisterEnum("v3.BookingFailure_Cause", BookingFailure_Cause_name, BookingFailure_Cause_value) + proto.RegisterEnum("v3.LineItemFulfillability_ItemFulfillabilityResult", LineItemFulfillability_ItemFulfillabilityResult_name, LineItemFulfillability_ItemFulfillabilityResult_value) + proto.RegisterEnum("v3.OrderFulfillability_OrderFulfillabilityResult", OrderFulfillability_OrderFulfillabilityResult_name, OrderFulfillability_OrderFulfillabilityResult_value) + proto.RegisterEnum("v3.OrderFailure_Cause", OrderFailure_Cause_name, OrderFailure_Cause_value) + proto.RegisterEnum("v3.CheckAvailabilityResponse_DurationRequirement", CheckAvailabilityResponse_DurationRequirement_name, CheckAvailabilityResponse_DurationRequirement_value) +} + +func init() { proto.RegisterFile("v3.proto", fileDescriptor0) } + +var fileDescriptor0 = []byte{ + // 3731 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5a, 0xcd, 0x73, 0x1b, 0xd9, + 0x56, 0x9f, 0xd6, 0x87, 0x6d, 0x1d, 0xdb, 0x72, 0xfb, 0xda, 0xb1, 0x95, 0x38, 0x19, 0x3b, 0x3d, + 0x33, 0x4c, 0xe2, 0xcc, 0x78, 0xde, 0x4b, 0xde, 0x54, 0x0d, 0x45, 0xc1, 0xd0, 0x6e, 0x5d, 0x67, + 0x9a, 0xc8, 0x2d, 0xcd, 0x55, 0x2b, 0x99, 0xc0, 0xa2, 0xe9, 0xa8, 0xaf, 0x95, 0x26, 0x52, 0xb7, + 0x5e, 0x77, 0xcb, 0x2f, 0x7e, 0x55, 0xaf, 0xea, 0x2d, 0xd9, 0x52, 0x50, 0xf5, 0x16, 0x14, 0x54, + 0x41, 0x15, 0xb0, 0xa4, 0x58, 0xc0, 0x1f, 0x00, 0x0b, 0x8a, 0xa2, 0xf8, 0x07, 0x58, 0xc1, 0x3f, + 0xc0, 0x86, 0x62, 0xc3, 0x8a, 0xba, 0x1f, 0xad, 0x6e, 0xb5, 0x24, 0x3b, 0x19, 0x60, 0xf1, 0x76, + 0xba, 0xe7, 0x9c, 0xfb, 0x71, 0x3e, 0xee, 0x39, 0xbf, 0x73, 0x5b, 0xb0, 0x76, 0xf9, 0xe4, 0x64, + 0x1c, 0x85, 0x49, 0x88, 0x4a, 0x97, 0x4f, 0xb4, 0xbf, 0x50, 0x60, 0xb3, 0x13, 0xc6, 0x89, 0x3b, + 0xd4, 0x3d, 0x2f, 0xa2, 0x71, 0x8c, 0x1a, 0xb0, 0xda, 0x0f, 0x27, 0x41, 0x12, 0x5d, 0x35, 0x94, + 0x23, 0xe5, 0x41, 0x8d, 0xa4, 0x43, 0x74, 0x07, 0xd6, 0x86, 0x61, 0xdf, 0x1d, 0xfa, 0xc9, 0x55, + 0xa3, 0xc4, 0x59, 0xd3, 0x31, 0xda, 0x83, 0x95, 0x88, 0x0e, 0xfc, 0x30, 0x68, 0x94, 0x39, 0x47, + 0x8e, 0xd0, 0x21, 0xac, 0x8f, 0xf9, 0xf2, 0x4e, 0x3f, 0xf4, 0x68, 0xa3, 0xc2, 0x99, 0x20, 0x48, + 0x46, 0xe8, 0x51, 0xf4, 0x09, 0xd4, 0xe3, 0x24, 0xa2, 0x34, 0x71, 0x5c, 0x71, 0x80, 0x46, 0x95, + 0xcb, 0x6c, 0x0a, 0xaa, 0x3c, 0x95, 0xf6, 0x13, 0xa8, 0x3f, 0xa5, 0xa1, 0x11, 0x86, 0x91, 0xe7, + 0x07, 0x6e, 0x42, 0x63, 0x7e, 0x1a, 0x37, 0xf1, 0x93, 0x89, 0x47, 0xf9, 0x41, 0x15, 0x32, 0x1d, + 0xa3, 0xbb, 0x50, 0x1b, 0x86, 0xc1, 0x40, 0x30, 0x4b, 0x9c, 0x99, 0x11, 0xd0, 0x23, 0x58, 0x4d, + 0xf7, 0x62, 0x87, 0x5d, 0x7f, 0xbc, 0x7d, 0x72, 0xf9, 0xe4, 0x64, 0xc6, 0x0a, 0x24, 0x95, 0xd0, + 0x7e, 0x06, 0xd5, 0x4e, 0xe4, 0xf7, 0x29, 0xba, 0x0f, 0x1b, 0x63, 0xf6, 0xc3, 0x19, 0xf9, 0xfd, + 0x28, 0x8c, 0xf9, 0x9e, 0x65, 0xb2, 0xce, 0x69, 0xe7, 0x9c, 0x84, 0x3e, 0x82, 0xcd, 0xfe, 0x24, + 0x8a, 0x68, 0xd0, 0xbf, 0x12, 0xea, 0x0a, 0x2b, 0x6d, 0xa4, 0x44, 0xae, 0xf0, 0x67, 0x80, 0xd8, + 0x1c, 0x3f, 0x18, 0x38, 0xe1, 0x38, 0xf1, 0xc3, 0xc0, 0x49, 0xdc, 0x81, 0xb4, 0x9a, 0x2a, 0x39, + 0x6d, 0xce, 0xb0, 0xdd, 0x81, 0x76, 0x02, 0xab, 0xb6, 0xfb, 0x96, 0xb8, 0x09, 0x65, 0xab, 0xf3, + 0xad, 0x9d, 0x31, 0x8d, 0xfa, 0x34, 0x48, 0xf8, 0x09, 0xaa, 0x64, 0x83, 0x13, 0x3b, 0x82, 0xa6, + 0xfd, 0xa7, 0x02, 0x5b, 0xdd, 0xfe, 0x6b, 0xea, 0x4d, 0x86, 0x7e, 0x30, 0x20, 0x93, 0x21, 0x8d, + 0xd1, 0x09, 0xec, 0x8c, 0xfc, 0xc0, 0x71, 0xbd, 0x4b, 0x37, 0xe8, 0x53, 0xe7, 0x55, 0x18, 0xbe, + 0xf1, 0x83, 0x81, 0x54, 0x60, 0x7b, 0xe4, 0x07, 0xba, 0xe0, 0x9c, 0x0a, 0x06, 0xfa, 0x1a, 0xee, + 0xe6, 0xe5, 0xc3, 0x60, 0xe8, 0x07, 0xd4, 0xe9, 0xb3, 0x01, 0x5b, 0x94, 0x6b, 0x55, 0x26, 0xb7, + 0xb3, 0x89, 0x6d, 0x2e, 0x61, 0xa4, 0x02, 0x48, 0x87, 0x5b, 0x43, 0x37, 0x49, 0xa7, 0x30, 0xaf, + 0x84, 0x81, 0x73, 0x41, 0xa9, 0x34, 0x77, 0x8d, 0x9b, 0x9b, 0xd9, 0xed, 0xb4, 0xd4, 0x50, 0xc8, + 0x0e, 0x93, 0x35, 0x72, 0xa2, 0x67, 0x94, 0x59, 0x09, 0x82, 0x30, 0x7e, 0x1d, 0xfe, 0x84, 0xcf, + 0xab, 0x2c, 0x9a, 0x57, 0x13, 0x02, 0x67, 0x94, 0x6a, 0xfb, 0x70, 0xcb, 0x0c, 0x06, 0x34, 0x66, + 0xb3, 0xbf, 0x9d, 0xd0, 0x09, 0xed, 0xb8, 0x57, 0xc3, 0xd0, 0xf5, 0xb4, 0x3f, 0xae, 0xc0, 0xd6, + 0x94, 0xd3, 0x4d, 0xdc, 0x64, 0x12, 0xa3, 0xcf, 0xa0, 0xc2, 0x9d, 0xc3, 0xf4, 0xaf, 0x3f, 0x6e, + 0xb0, 0x45, 0x0b, 0x22, 0x27, 0xcc, 0x51, 0x84, 0x4b, 0xa1, 0x87, 0xa0, 0x26, 0xfe, 0x88, 0xc6, + 0x89, 0x3b, 0x1a, 0xa7, 0xae, 0x17, 0x06, 0xd8, 0x9a, 0xd2, 0xa5, 0xfb, 0x7f, 0x04, 0x7b, 0x7e, + 0x90, 0xd0, 0x28, 0x70, 0x87, 0x0e, 0x8d, 0xa2, 0x30, 0x72, 0x3c, 0x9a, 0xb8, 0xfe, 0x30, 0x96, + 0xde, 0xdd, 0x4d, 0xb9, 0x98, 0x31, 0x9b, 0x82, 0x87, 0x74, 0xb8, 0x37, 0x76, 0xa3, 0x24, 0xa0, + 0x91, 0x73, 0xe9, 0xc7, 0xfe, 0xab, 0x21, 0x2d, 0x4c, 0x16, 0x77, 0xe6, 0x8e, 0x14, 0x7a, 0x2e, + 0x64, 0xf2, 0x4b, 0x68, 0x7f, 0x5b, 0x82, 0x0a, 0x8f, 0x2d, 0x04, 0xf5, 0xae, 0xad, 0xdb, 0xbd, + 0xae, 0xd3, 0xb3, 0x9e, 0x59, 0xed, 0x17, 0x96, 0xfa, 0x01, 0x6a, 0xc0, 0xae, 0xa4, 0x9d, 0x61, + 0xdc, 0x74, 0x7a, 0x9d, 0x56, 0x5b, 0x6f, 0xe2, 0xa6, 0xaa, 0x14, 0x39, 0xd8, 0xfa, 0xb6, 0x87, + 0x7b, 0xb8, 0xa9, 0x96, 0x90, 0x06, 0x1f, 0xe6, 0x39, 0x1d, 0xd2, 0x36, 0x70, 0xb7, 0x6b, 0x5a, + 0x4f, 0x9d, 0xae, 0xad, 0x13, 0x1b, 0x37, 0xd5, 0x32, 0xfa, 0x18, 0x8e, 0x96, 0xc9, 0xf4, 0x0c, + 0x03, 0x63, 0xb6, 0x47, 0x05, 0xdd, 0x87, 0x7b, 0x4b, 0xa4, 0xce, 0x74, 0xb3, 0x85, 0x9b, 0x6a, + 0x15, 0xdd, 0x81, 0xbd, 0xbc, 0x48, 0xb3, 0xd7, 0x69, 0x99, 0x86, 0xce, 0x36, 0x59, 0x41, 0xb7, + 0x60, 0x5b, 0xf2, 0xf4, 0x8e, 0xe9, 0x18, 0x7a, 0x8b, 0x4d, 0x61, 0x57, 0xe1, 0x30, 0x47, 0x5e, + 0xb8, 0xf5, 0x05, 0x3a, 0x82, 0xbb, 0x8b, 0x85, 0xe4, 0xce, 0x03, 0x4d, 0x87, 0x9a, 0xed, 0x8f, + 0x28, 0x71, 0x83, 0x01, 0x45, 0x07, 0x50, 0x7b, 0x45, 0x07, 0x7e, 0xe0, 0xc4, 0xb4, 0x2f, 0xef, + 0xc6, 0x1a, 0x27, 0x74, 0x69, 0x1f, 0xed, 0xc3, 0x2a, 0x0d, 0x3c, 0xce, 0x12, 0xce, 0x5f, 0xa1, + 0x81, 0xd7, 0xa5, 0x7d, 0x8d, 0x40, 0xcd, 0x0a, 0xbb, 0x22, 0x0c, 0xd1, 0x01, 0x94, 0x59, 0xb4, + 0x2a, 0x85, 0x68, 0x25, 0x8c, 0x8a, 0x1e, 0xc0, 0xda, 0x05, 0xa5, 0x4e, 0x72, 0x35, 0x16, 0xf7, + 0xa0, 0xfe, 0x78, 0x73, 0x2a, 0x61, 0x5f, 0x8d, 0x29, 0x59, 0xbd, 0xa0, 0xfc, 0x87, 0xf6, 0x67, + 0x0a, 0xac, 0x36, 0xe9, 0x38, 0x8c, 0xfd, 0x04, 0x7d, 0x04, 0xab, 0x9e, 0xf8, 0x39, 0xbf, 0x6c, + 0xca, 0x29, 0x5e, 0xd8, 0x99, 0x6b, 0x97, 0x1d, 0x39, 0x77, 0x61, 0xf3, 0xb7, 0x8d, 0xa9, 0xf7, + 0x03, 0xd8, 0x90, 0x6b, 0x5d, 0x73, 0xbe, 0x75, 0x29, 0xc2, 0xcf, 0xe8, 0x03, 0xe8, 0x7d, 0x36, + 0xbd, 0xe5, 0x07, 0x6f, 0x90, 0x0a, 0xe5, 0x49, 0x34, 0x94, 0xf5, 0x82, 0xfd, 0x14, 0xd9, 0x39, + 0x18, 0x4c, 0xdc, 0x01, 0x9d, 0xd6, 0x0a, 0x39, 0x46, 0x9f, 0x03, 0x8a, 0x68, 0x9c, 0x44, 0x7e, + 0x3f, 0xa1, 0x9e, 0x93, 0x16, 0x9b, 0xf2, 0x51, 0xf9, 0x41, 0x8d, 0x6c, 0x67, 0x1c, 0x43, 0x30, + 0xb4, 0x7f, 0x53, 0xa0, 0xd2, 0x1d, 0x86, 0x09, 0xab, 0x25, 0x23, 0x1a, 0xf5, 0x5f, 0xbb, 0x41, + 0xe2, 0xf8, 0x9e, 0xdc, 0x0d, 0x52, 0x92, 0xe9, 0xa1, 0x7b, 0x00, 0x31, 0x8d, 0x2e, 0x59, 0x92, + 0xf6, 0x3d, 0xb9, 0x6d, 0x4d, 0x52, 0x4c, 0x8f, 0x79, 0x38, 0x4e, 0xdc, 0x28, 0xe1, 0x36, 0x29, + 0x0b, 0x0f, 0x73, 0x02, 0x33, 0xc1, 0x7d, 0xd8, 0xf0, 0x26, 0x51, 0x66, 0xb3, 0x8a, 0x48, 0xef, + 0x29, 0x8d, 0x89, 0x3c, 0x04, 0xd5, 0xbd, 0x74, 0xfd, 0xa1, 0xfb, 0xca, 0x67, 0x35, 0x8f, 0xe7, + 0x6d, 0x51, 0xac, 0xb6, 0xf2, 0x74, 0xdb, 0x1d, 0xa0, 0xcf, 0xa1, 0x16, 0xd1, 0x38, 0x9c, 0x44, + 0x7d, 0x1a, 0x37, 0x56, 0xb8, 0xe3, 0xb6, 0x98, 0x35, 0x89, 0x24, 0x9a, 0x5e, 0x4c, 0x32, 0x09, + 0xed, 0xcf, 0x15, 0xa8, 0xb6, 0xa8, 0x1b, 0x53, 0x74, 0x1b, 0xd6, 0x86, 0xec, 0x47, 0xa6, 0xe0, + 0x2a, 0x1f, 0x9b, 0x1e, 0xba, 0x0b, 0x95, 0x78, 0x18, 0x26, 0x5c, 0xaf, 0xf5, 0xc7, 0x6b, 0x6c, + 0x39, 0x66, 0x16, 0xc2, 0xa9, 0xac, 0x8e, 0x4e, 0x62, 0x1a, 0x39, 0x11, 0xbd, 0xa0, 0xac, 0xd8, + 0x50, 0x99, 0x74, 0x36, 0x19, 0x95, 0xa4, 0x44, 0xf4, 0xab, 0x70, 0x5b, 0xac, 0x4f, 0xdf, 0x8e, + 0x7d, 0xa9, 0x2e, 0xcb, 0x63, 0x39, 0x9d, 0xf7, 0xb8, 0x00, 0x9e, 0xf2, 0xd9, 0x15, 0x61, 0xa1, + 0xfe, 0x08, 0xea, 0xfc, 0x8c, 0xd9, 0x62, 0xcb, 0x0f, 0xab, 0xfd, 0xb7, 0x02, 0xab, 0x69, 0x3d, + 0xb9, 0x07, 0x20, 0x6b, 0x4e, 0x26, 0x58, 0x93, 0x94, 0x1b, 0xf5, 0xfa, 0x0d, 0x50, 0xb9, 0x5e, + 0x7e, 0x70, 0x11, 0x46, 0x23, 0x7e, 0x20, 0x59, 0x46, 0x76, 0x98, 0x64, 0x2f, 0xa6, 0x91, 0x99, + 0xb1, 0xc8, 0xd6, 0x64, 0x96, 0x80, 0x1e, 0xc2, 0x4a, 0xcc, 0x93, 0x3a, 0xd7, 0xae, 0x2e, 0x6a, + 0xbd, 0x3c, 0x99, 0xc8, 0xf6, 0x44, 0x0a, 0xa0, 0xa7, 0xb0, 0x33, 0x76, 0xaf, 0x46, 0x94, 0x85, + 0x57, 0x6e, 0xb7, 0x2a, 0xdf, 0x6d, 0x8f, 0x5f, 0x06, 0xc1, 0xce, 0x6f, 0x88, 0xc6, 0x73, 0x34, + 0xed, 0x9f, 0x15, 0xd8, 0x2a, 0x1c, 0x8c, 0x65, 0x10, 0xa1, 0x47, 0x6a, 0x81, 0x15, 0x7e, 0x52, + 0x1e, 0xb4, 0x03, 0xff, 0x92, 0x06, 0x4e, 0xe0, 0x8e, 0xd2, 0xbb, 0x52, 0xe3, 0x14, 0xcb, 0x1d, + 0x51, 0x16, 0xf4, 0x17, 0xee, 0xc8, 0x1f, 0x5e, 0x09, 0xbe, 0x70, 0x2a, 0x08, 0x12, 0x17, 0xc8, + 0xa1, 0x99, 0xca, 0x4d, 0x68, 0x86, 0x01, 0xa3, 0x84, 0x0e, 0xe9, 0xf8, 0x75, 0x18, 0x50, 0x19, + 0xbb, 0x19, 0x01, 0xed, 0x42, 0x95, 0x8e, 0x5c, 0x7f, 0xc8, 0x23, 0xb6, 0x46, 0xc4, 0x40, 0xfb, + 0x45, 0x19, 0x0e, 0xa4, 0xe2, 0x9d, 0x28, 0xec, 0xd3, 0x38, 0xf6, 0x83, 0x41, 0xc7, 0x8d, 0xdc, + 0x11, 0x4d, 0x68, 0x14, 0x23, 0x02, 0xb5, 0xb1, 0xa0, 0x87, 0x91, 0x2c, 0xaa, 0x3f, 0xc8, 0x19, + 0x6b, 0xd1, 0x9c, 0x02, 0x2f, 0x8c, 0x44, 0x41, 0x9f, 0x2e, 0x83, 0x7e, 0x04, 0xbb, 0xa9, 0x2b, + 0x46, 0x34, 0x79, 0x1d, 0x7a, 0x4e, 0x12, 0xbe, 0xa1, 0x81, 0x30, 0x0f, 0x17, 0x4e, 0xed, 0x7e, + 0xce, 0xd9, 0x36, 0xe3, 0xb2, 0x52, 0x3a, 0x09, 0xc6, 0x6e, 0x14, 0x53, 0xcf, 0x59, 0x38, 0x5d, + 0x68, 0x7c, 0x27, 0x15, 0xea, 0xcc, 0x2f, 0xd1, 0x80, 0xd5, 0x4b, 0x1a, 0xc5, 0x19, 0x90, 0x4d, + 0x87, 0xe8, 0x11, 0x6c, 0xa7, 0x6b, 0x66, 0xea, 0x56, 0x24, 0x6c, 0x2b, 0xa8, 0xa3, 0x79, 0xa0, + 0x16, 0x55, 0x64, 0xa5, 0xb0, 0xa3, 0xbf, 0x3c, 0xc7, 0x96, 0x9d, 0x16, 0xa3, 0x36, 0x71, 0x7a, + 0x56, 0xb7, 0x83, 0x0d, 0xf3, 0xcc, 0xc4, 0x4d, 0xf5, 0x03, 0xb4, 0x0b, 0x6a, 0xc6, 0xea, 0xda, + 0xc4, 0xec, 0x60, 0x55, 0x41, 0xfb, 0xb0, 0x93, 0x51, 0x4f, 0x89, 0x6e, 0x5a, 0x36, 0xc1, 0x58, + 0x2d, 0x69, 0xff, 0x54, 0x82, 0x6d, 0x16, 0x67, 0x72, 0x2b, 0x81, 0x1a, 0xd1, 0x13, 0xd8, 0xe3, + 0x91, 0x96, 0x9e, 0x56, 0xa2, 0xcc, 0x69, 0xe0, 0xed, 0x4c, 0x8a, 0x53, 0x4c, 0x0f, 0x7d, 0x01, + 0xbb, 0x97, 0xee, 0xd0, 0xf7, 0x1c, 0x91, 0x21, 0xa7, 0x29, 0x41, 0x94, 0x8e, 0x6d, 0xce, 0xeb, + 0x32, 0x96, 0xcc, 0x06, 0xe8, 0x11, 0x20, 0x31, 0x81, 0xd5, 0xc5, 0xa9, 0xb8, 0xc8, 0xaa, 0x5b, + 0x9c, 0x83, 0x03, 0x2f, 0x15, 0x7e, 0x08, 0x15, 0x5e, 0x57, 0xc4, 0x15, 0xbc, 0x95, 0x8b, 0x0e, + 0x89, 0x74, 0x59, 0x7d, 0xe1, 0x22, 0x2c, 0x8f, 0x85, 0x91, 0x3f, 0xf0, 0x03, 0xde, 0x32, 0x4c, + 0x82, 0x84, 0x3b, 0xad, 0x4a, 0x36, 0x53, 0x2a, 0x2f, 0x0b, 0x19, 0xd4, 0x4e, 0xa4, 0xd4, 0x8a, + 0x00, 0xc3, 0x92, 0x28, 0x84, 0x8e, 0x33, 0x97, 0x65, 0x46, 0x58, 0x15, 0x19, 0x7b, 0x3c, 0x6b, + 0x00, 0xed, 0x4f, 0xab, 0x80, 0xe6, 0xaf, 0x37, 0xd2, 0x61, 0x7b, 0x1c, 0xd1, 0x74, 0x15, 0x99, + 0x49, 0x44, 0x90, 0xef, 0x8a, 0xf2, 0x98, 0x32, 0x65, 0x32, 0x51, 0xc7, 0x05, 0x0a, 0x83, 0x85, + 0xe9, 0xfc, 0x24, 0x72, 0x83, 0xd8, 0xed, 0xa7, 0x47, 0x11, 0x97, 0x3d, 0x8d, 0x74, 0x3b, 0x63, + 0x9a, 0x1e, 0x3a, 0x84, 0x2a, 0x6f, 0x2d, 0xe6, 0x30, 0x33, 0x11, 0x74, 0xf4, 0x00, 0x20, 0x71, + 0xdf, 0x3a, 0xee, 0x88, 0xab, 0x5f, 0x44, 0xc8, 0xa4, 0x96, 0xb8, 0x6f, 0x75, 0xce, 0x43, 0xbf, + 0x93, 0x5d, 0x26, 0x19, 0xb9, 0xd4, 0x73, 0x5e, 0x5d, 0x71, 0xc3, 0xd6, 0x1f, 0x3f, 0x5c, 0x9c, + 0xd8, 0x0a, 0x57, 0x94, 0x7a, 0xa7, 0x57, 0xd3, 0x3b, 0x97, 0xa3, 0xa1, 0xcf, 0x16, 0xd9, 0x98, + 0xe7, 0x8f, 0x6f, 0x3e, 0x98, 0xb3, 0x32, 0xfa, 0x72, 0x69, 0x6c, 0xae, 0xca, 0x29, 0x0b, 0xa3, + 0xf3, 0x93, 0x0c, 0x05, 0xad, 0x71, 0x45, 0xd7, 0xd9, 0xa1, 0x25, 0x46, 0xca, 0x70, 0xd0, 0xe7, + 0xb0, 0x1e, 0x84, 0xce, 0xb4, 0x6b, 0xa8, 0x71, 0x51, 0x8e, 0x62, 0xa6, 0x18, 0x8d, 0x75, 0x0d, + 0x29, 0x5c, 0xfb, 0x02, 0xea, 0x17, 0x94, 0xc6, 0x8e, 0xcb, 0x22, 0xd8, 0x7d, 0x4b, 0xe3, 0x06, + 0x14, 0xad, 0xb8, 0xc1, 0x04, 0xf4, 0xc0, 0xb3, 0x19, 0x5b, 0x1b, 0x4d, 0x43, 0x24, 0x6f, 0x81, + 0x8f, 0xe1, 0xa8, 0x70, 0xaf, 0x71, 0xd3, 0x39, 0x7d, 0x59, 0xb8, 0xda, 0xd9, 0x25, 0x16, 0xdc, + 0xa7, 0xed, 0xf6, 0xd3, 0x16, 0x16, 0x28, 0x7c, 0x86, 0xd1, 0xd1, 0x89, 0x6d, 0x61, 0xa2, 0x96, + 0x4e, 0x37, 0x00, 0xa6, 0xf5, 0xc8, 0xd3, 0x7e, 0xbf, 0x02, 0x75, 0x59, 0xb7, 0xce, 0x5c, 0x7f, + 0x38, 0x89, 0x28, 0x3a, 0x81, 0x6a, 0xdf, 0x9d, 0xc4, 0x33, 0xad, 0xcc, 0xac, 0xc8, 0x89, 0xc1, + 0xf8, 0x44, 0x88, 0xa1, 0xdf, 0x64, 0xc0, 0xeb, 0xf7, 0xa8, 0x80, 0x5d, 0x6e, 0xe4, 0x09, 0xb0, + 0x57, 0xe2, 0x93, 0x11, 0x9b, 0x6c, 0x44, 0xd4, 0xf3, 0x13, 0xc3, 0x8d, 0x3c, 0x7e, 0x23, 0xd5, + 0x54, 0x3a, 0xa5, 0xa0, 0x23, 0x58, 0xf7, 0x68, 0xdc, 0x8f, 0xfc, 0x71, 0x92, 0xa5, 0xc8, 0x3c, + 0x49, 0xfb, 0xf7, 0x12, 0x54, 0xf9, 0xa6, 0x0c, 0xbb, 0x1b, 0x7a, 0xaf, 0x8b, 0xe7, 0x73, 0x5c, + 0xb7, 0xd5, 0xb6, 0x9d, 0x9e, 0xa5, 0x3f, 0xd7, 0xcd, 0x96, 0x7e, 0xca, 0xad, 0x70, 0x08, 0x07, + 0x9c, 0xaa, 0xb7, 0x08, 0xd6, 0x9b, 0x2f, 0x9d, 0xd3, 0x76, 0xfb, 0x99, 0x34, 0x63, 0x97, 0x19, + 0x03, 0x6d, 0xc3, 0x66, 0x0b, 0xeb, 0x5d, 0xec, 0xe0, 0xef, 0x3a, 0x26, 0xe1, 0x1d, 0xc8, 0x21, + 0x1c, 0xb4, 0x7b, 0x76, 0xd7, 0x6c, 0x62, 0xc7, 0xd0, 0x2d, 0x03, 0xb7, 0x5a, 0xba, 0x6d, 0xb6, + 0x2d, 0xe7, 0x85, 0x69, 0x35, 0xdb, 0x2f, 0xd4, 0x4a, 0xde, 0x33, 0x98, 0x90, 0x36, 0x71, 0x0c, + 0x9d, 0x34, 0x1d, 0xfb, 0x65, 0x07, 0x3b, 0x04, 0xff, 0x16, 0x36, 0x6c, 0xde, 0x7f, 0x1c, 0xc2, + 0xc1, 0x02, 0xa9, 0x26, 0x36, 0x5a, 0xa6, 0xc5, 0x9b, 0x90, 0xbb, 0xd0, 0x48, 0x05, 0xda, 0x1d, + 0xbe, 0x83, 0xd5, 0xb6, 0x9d, 0xe7, 0x7a, 0xcb, 0x6c, 0xaa, 0xab, 0xec, 0x60, 0x33, 0xd3, 0xd5, + 0x35, 0xd6, 0x3e, 0xb1, 0x53, 0xb3, 0x53, 0x31, 0x49, 0x66, 0x83, 0xd9, 0x05, 0xd4, 0x1a, 0xba, + 0x07, 0xb7, 0x99, 0x8e, 0xac, 0x1f, 0x49, 0x75, 0x96, 0x4a, 0xe0, 0xa6, 0x0a, 0xe8, 0x00, 0xf6, + 0x53, 0x36, 0x5b, 0x22, 0xd5, 0x8f, 0x19, 0x6b, 0x5d, 0x7b, 0x09, 0x2a, 0x43, 0x48, 0x7a, 0x0e, + 0x74, 0x4e, 0x51, 0x94, 0xb2, 0x10, 0x45, 0x7d, 0x0a, 0x5b, 0x3c, 0x4d, 0x3a, 0x12, 0xa8, 0x0e, + 0x85, 0xdb, 0xab, 0xa4, 0xce, 0xc9, 0x7a, 0x4a, 0xd5, 0x5e, 0x00, 0xca, 0x2f, 0xdb, 0x1b, 0x7b, + 0x6e, 0x42, 0x59, 0x16, 0x64, 0xcb, 0x38, 0x79, 0x98, 0xdb, 0x50, 0x8e, 0xca, 0x0f, 0xd6, 0x45, + 0x16, 0x2c, 0x9e, 0x86, 0xa8, 0x71, 0x81, 0xa2, 0xfd, 0x2e, 0xac, 0xe7, 0xc0, 0x2f, 0x83, 0x8e, + 0x71, 0xe2, 0x5e, 0x5c, 0xe4, 0xa0, 0x23, 0x1f, 0x9b, 0x1e, 0x43, 0x4a, 0x51, 0x18, 0x8e, 0xb2, + 0x04, 0xb9, 0xc2, 0x86, 0x02, 0x29, 0xb1, 0x26, 0xf8, 0xca, 0x89, 0xfd, 0x9f, 0x8a, 0xbc, 0x58, + 0x25, 0x35, 0x4e, 0xe9, 0xfa, 0x3f, 0xa5, 0xda, 0xcf, 0x15, 0x00, 0xdb, 0xef, 0xbf, 0xa1, 0xbc, + 0x43, 0x41, 0x1f, 0x43, 0x3d, 0xe1, 0x23, 0x1e, 0xe5, 0xd9, 0x3e, 0x1b, 0xc9, 0x54, 0xc6, 0xf4, + 0x58, 0x55, 0x8f, 0x5f, 0x87, 0x51, 0xe2, 0xe4, 0xc3, 0x5a, 0x6c, 0xab, 0x72, 0x46, 0x33, 0xa3, + 0xdf, 0x98, 0x93, 0xb5, 0xbf, 0x29, 0xc1, 0x5a, 0xcb, 0x0f, 0xa8, 0x99, 0xd0, 0x51, 0xa1, 0x1b, + 0x51, 0xae, 0xed, 0x46, 0x4a, 0x37, 0x74, 0x23, 0xe5, 0xf9, 0x6e, 0xe4, 0x4b, 0x58, 0x15, 0x9a, + 0x30, 0xdc, 0xc7, 0x3c, 0x71, 0xc0, 0x8e, 0x93, 0xee, 0x7e, 0xd2, 0x8e, 0x3c, 0x1a, 0x51, 0x4f, + 0x18, 0x24, 0x26, 0xa9, 0x6c, 0xa6, 0x43, 0x75, 0x49, 0x5d, 0xc9, 0x00, 0xf3, 0xca, 0x0d, 0x80, + 0xf9, 0x8e, 0x01, 0xf5, 0xd9, 0x6d, 0x98, 0x52, 0xd2, 0xe8, 0x53, 0x95, 0xd7, 0x04, 0xc1, 0xf4, + 0x18, 0xbc, 0x14, 0xb5, 0x5a, 0x84, 0x9e, 0x18, 0x68, 0xff, 0x5a, 0x86, 0xbd, 0xf4, 0xd4, 0x67, + 0x93, 0xe1, 0x85, 0x3f, 0x9c, 0xc6, 0xf4, 0x11, 0x54, 0xfc, 0x84, 0x8e, 0x64, 0x4c, 0x6f, 0xe4, + 0xf5, 0x23, 0x9c, 0x83, 0x9e, 0xc1, 0x4a, 0x44, 0xe3, 0xc9, 0x30, 0x91, 0x59, 0xec, 0x49, 0x5e, + 0x66, 0x76, 0xb5, 0x93, 0x79, 0x12, 0xe1, 0x53, 0x89, 0x5c, 0x02, 0xfd, 0x10, 0x76, 0x27, 0xc1, + 0x45, 0x2a, 0x31, 0xa4, 0x4e, 0x44, 0xdd, 0x78, 0x9a, 0xe5, 0x76, 0x66, 0x78, 0x84, 0xb3, 0xb8, + 0x8f, 0xc7, 0x61, 0x12, 0x3b, 0xe1, 0x98, 0x06, 0xbc, 0x08, 0x57, 0x49, 0x8d, 0x53, 0xda, 0x63, + 0x1a, 0xa0, 0x2f, 0x60, 0x3d, 0x17, 0x83, 0x8d, 0x2a, 0xf7, 0x53, 0x9d, 0x9d, 0x31, 0x0b, 0x54, + 0x02, 0x59, 0x40, 0x6a, 0xff, 0xa2, 0x40, 0x63, 0xd9, 0x39, 0xd1, 0x31, 0xfc, 0x8a, 0x69, 0xe3, + 0x73, 0xe7, 0xac, 0xd7, 0x3a, 0x33, 0x59, 0x32, 0x30, 0x5b, 0xa6, 0xfd, 0xd2, 0x21, 0xb8, 0xdb, + 0x6b, 0xd9, 0x85, 0x2c, 0xbb, 0x05, 0xeb, 0x86, 0x6e, 0xa5, 0xa2, 0xaa, 0xb2, 0x30, 0xed, 0x96, + 0x58, 0x86, 0xec, 0x59, 0xd3, 0xf5, 0x5a, 0xd8, 0xb1, 0x4d, 0xe3, 0x19, 0xb6, 0x1d, 0xa3, 0x7d, + 0x7e, 0x6a, 0x5a, 0x3c, 0x9d, 0xaa, 0x65, 0xb4, 0x03, 0x5b, 0xa6, 0x65, 0xb4, 0x09, 0xc1, 0x06, + 0xab, 0x71, 0xa6, 0x81, 0xd5, 0x0a, 0xfa, 0x08, 0x0e, 0xf9, 0x69, 0x66, 0xe7, 0xb7, 0xed, 0x6f, + 0x30, 0x71, 0x08, 0xd6, 0xbb, 0x6d, 0x4b, 0xad, 0x6a, 0x7f, 0x59, 0x86, 0x1d, 0x1e, 0x22, 0x05, + 0xcf, 0x9a, 0x53, 0xbf, 0x89, 0xd2, 0xf5, 0x43, 0x66, 0x93, 0x05, 0x82, 0x8b, 0x68, 0x05, 0xaf, + 0x3d, 0x83, 0x1d, 0x16, 0x0a, 0xce, 0xc5, 0x8c, 0x50, 0xa3, 0xc4, 0x6d, 0x7d, 0x67, 0x79, 0x3c, + 0x10, 0xe4, 0xcf, 0x47, 0xdc, 0xfb, 0x87, 0x80, 0xf6, 0x0f, 0x0a, 0xdc, 0x5e, 0x7a, 0x4a, 0xf4, + 0x08, 0x3e, 0x6d, 0x93, 0x26, 0x26, 0xdf, 0xcf, 0x69, 0x07, 0xb0, 0x3f, 0x6b, 0x5e, 0x56, 0x92, + 0x1c, 0x66, 0x76, 0xb5, 0x84, 0x3e, 0x81, 0xfb, 0xb3, 0xcc, 0x2e, 0x26, 0xcf, 0x4d, 0x03, 0x17, + 0x9c, 0xf7, 0x31, 0x1c, 0x89, 0x13, 0x5c, 0xe3, 0xa8, 0x8a, 0xf6, 0x1f, 0x0a, 0x54, 0xb9, 0x16, + 0x2c, 0x33, 0x87, 0xec, 0x47, 0x2e, 0x33, 0xf3, 0xb1, 0xe9, 0x2d, 0xec, 0xc5, 0x4b, 0xef, 0xd1, + 0x8b, 0x2f, 0x69, 0xb0, 0xcb, 0xef, 0xdb, 0x60, 0x17, 0x5f, 0x82, 0x2a, 0x73, 0x2f, 0x41, 0x69, + 0xe6, 0x10, 0x37, 0x6e, 0x41, 0xe6, 0xd0, 0xfe, 0xab, 0x04, 0x1b, 0xc2, 0x6d, 0x12, 0x4c, 0x7d, + 0x36, 0x0b, 0xa6, 0xf6, 0xb2, 0x88, 0x5c, 0x04, 0xa5, 0xbe, 0x86, 0xfa, 0x5c, 0xc0, 0x31, 0x2d, + 0xf6, 0x97, 0x04, 0x32, 0x29, 0x88, 0x2f, 0xc1, 0x62, 0xe5, 0xef, 0x8f, 0xc5, 0x2a, 0xf3, 0x58, + 0xec, 0x0f, 0x94, 0x1b, 0xb0, 0xd8, 0x3e, 0xec, 0x2c, 0x88, 0x0d, 0x55, 0x79, 0x27, 0xe4, 0x54, + 0xba, 0x09, 0x39, 0x95, 0xe7, 0xb1, 0x51, 0x45, 0xfb, 0x0a, 0x1a, 0xc6, 0x6b, 0xda, 0x7f, 0x33, + 0x03, 0x17, 0xe8, 0x8f, 0x27, 0x34, 0x4e, 0xae, 0xc7, 0x30, 0xda, 0xcf, 0xcb, 0x70, 0x7b, 0xc1, + 0xd4, 0x78, 0x1c, 0x06, 0x31, 0xfd, 0x3f, 0xc2, 0x3f, 0xc8, 0x83, 0xdd, 0x69, 0xe1, 0x8d, 0xe8, + 0x8f, 0x27, 0x7e, 0x44, 0x59, 0xf0, 0x49, 0xc7, 0xf0, 0x34, 0xb5, 0xf4, 0x0c, 0x27, 0x4d, 0x39, + 0x93, 0x64, 0x13, 0xc9, 0x8e, 0x37, 0x4f, 0x64, 0x17, 0x61, 0xe6, 0x25, 0x71, 0xc2, 0x61, 0x96, + 0x6c, 0xe2, 0x78, 0xe4, 0xcd, 0x83, 0x30, 0x82, 0xdc, 0x39, 0x9a, 0x36, 0x82, 0x9d, 0x05, 0x9b, + 0x32, 0xf7, 0x35, 0x7b, 0x44, 0xa0, 0x61, 0x82, 0xbf, 0xed, 0x99, 0x04, 0x73, 0x27, 0xcc, 0x7a, + 0xbf, 0x01, 0xbb, 0xcd, 0x36, 0x87, 0x97, 0xdd, 0x6f, 0xda, 0x2f, 0x9c, 0x74, 0x86, 0xaa, 0xa0, + 0x3d, 0x40, 0xe7, 0xbd, 0x6e, 0x91, 0x5e, 0xd2, 0xbe, 0x82, 0xfd, 0xa7, 0x34, 0x99, 0x05, 0x03, + 0xd2, 0x77, 0xd7, 0x3f, 0xf2, 0x69, 0x7f, 0xa7, 0x40, 0x63, 0x7e, 0xaa, 0xf4, 0xdd, 0x0d, 0x0f, + 0x84, 0x5f, 0x41, 0x3d, 0x65, 0x4b, 0x64, 0x52, 0x5a, 0x86, 0x4c, 0x36, 0x5f, 0xe5, 0x87, 0x8b, + 0xbb, 0xf7, 0xf2, 0xfb, 0x74, 0xef, 0x9a, 0x07, 0x87, 0xdc, 0xe1, 0x0b, 0x53, 0xbc, 0x50, 0xfd, + 0xc6, 0x77, 0xe9, 0x34, 0x1b, 0x95, 0x96, 0x66, 0xa3, 0x3f, 0x52, 0xe0, 0x68, 0xf9, 0x36, 0xd2, + 0x4c, 0xf3, 0x39, 0x47, 0x79, 0xbf, 0x9c, 0x33, 0xdf, 0xf0, 0x96, 0xae, 0x6f, 0x78, 0xff, 0xba, + 0x0c, 0xbb, 0x46, 0x44, 0xdd, 0x24, 0xfd, 0x36, 0xf8, 0x4e, 0x37, 0x15, 0x7d, 0x01, 0x35, 0xf1, + 0x2e, 0x1c, 0xd1, 0x0b, 0xb9, 0x05, 0x4f, 0x69, 0xb3, 0xcf, 0xc7, 0x44, 0x3c, 0x1e, 0x13, 0x7a, + 0xf1, 0xbf, 0x7e, 0xe4, 0x5d, 0x52, 0x58, 0x2a, 0xef, 0x5d, 0x58, 0xfa, 0x70, 0xaf, 0xf0, 0x54, + 0xc2, 0xa2, 0x6e, 0x3c, 0x7d, 0xb8, 0x94, 0xa8, 0xf9, 0xf0, 0x86, 0xf7, 0x4d, 0x72, 0x30, 0xbe, + 0xe6, 0xc1, 0xf4, 0x11, 0x6c, 0xfb, 0x1e, 0x1d, 0x8d, 0xc3, 0x84, 0x7f, 0x29, 0x16, 0x4f, 0x93, + 0xe2, 0xc9, 0x55, 0xcd, 0x31, 0xc4, 0x83, 0xe4, 0xe7, 0x80, 0x5c, 0xcf, 0xf3, 0xd9, 0xe9, 0xdc, + 0x21, 0x4f, 0x49, 0x34, 0x4e, 0xe4, 0x23, 0xd6, 0x76, 0xc6, 0x91, 0x8e, 0xd1, 0xfe, 0x5e, 0x81, + 0x5b, 0x05, 0x8f, 0xc9, 0xe8, 0xf9, 0x04, 0x56, 0xf3, 0x5f, 0x7e, 0xe5, 0x1b, 0x4a, 0x2a, 0x95, + 0xf2, 0x10, 0x86, 0x9d, 0x05, 0x2f, 0x34, 0xd2, 0x8b, 0xb7, 0x52, 0x6f, 0xcc, 0x3c, 0xd0, 0x90, + 0xed, 0xb9, 0x37, 0x1b, 0xf4, 0x6b, 0xb0, 0x95, 0xde, 0xd9, 0x0b, 0x51, 0x3f, 0xa5, 0x43, 0xd1, + 0xfc, 0x23, 0x05, 0x49, 0xaf, 0xb7, 0x1c, 0x6b, 0xff, 0xa8, 0x00, 0x12, 0x4a, 0xf0, 0xa8, 0xce, + 0xee, 0x59, 0x95, 0x23, 0x91, 0xfc, 0x97, 0x30, 0x21, 0x20, 0xe8, 0x37, 0x7b, 0xaf, 0xf4, 0xff, + 0xe5, 0xbd, 0xf2, 0x62, 0xef, 0xb1, 0xfc, 0x3c, 0xa3, 0x88, 0xf4, 0xc5, 0x8d, 0x9a, 0x7c, 0x09, + 0x9b, 0x02, 0x84, 0xa5, 0xc6, 0x13, 0x27, 0x57, 0x8b, 0xa0, 0x84, 0x6c, 0x84, 0xb9, 0x91, 0xf6, + 0x65, 0x6a, 0x37, 0x79, 0xd3, 0xa6, 0x76, 0xe3, 0x37, 0x2d, 0xbf, 0x9b, 0x10, 0x10, 0x74, 0x2d, + 0x4e, 0x4f, 0x29, 0xa7, 0x65, 0xa7, 0xbc, 0x76, 0xde, 0x22, 0x27, 0x97, 0xde, 0xd9, 0xc9, 0x27, + 0xb0, 0xd3, 0xf2, 0xe3, 0xb4, 0x22, 0x4c, 0xeb, 0xc8, 0xb2, 0xef, 0x24, 0xda, 0xd7, 0xb0, 0x3b, + 0x2b, 0x2f, 0x4f, 0xf9, 0x29, 0xac, 0xc9, 0x95, 0x63, 0xf9, 0x24, 0x31, 0x13, 0xd8, 0x53, 0xa6, + 0xf6, 0x14, 0xb6, 0xd9, 0x02, 0xdc, 0x7c, 0x37, 0x6e, 0x37, 0x03, 0x83, 0x4b, 0xfc, 0xd3, 0x64, + 0x0a, 0x83, 0x99, 0x95, 0xf3, 0x0b, 0xcd, 0xfb, 0xb4, 0xbc, 0xc8, 0xa7, 0xda, 0xaf, 0xc3, 0xae, + 0xa8, 0xda, 0x85, 0x5c, 0xfa, 0x6e, 0x17, 0x93, 0xdf, 0xec, 0xc2, 0xfc, 0x5f, 0xba, 0x9b, 0x7d, + 0x7c, 0x96, 0xff, 0x3b, 0x06, 0x7f, 0x0c, 0xe2, 0xff, 0x59, 0x68, 0xf7, 0x88, 0x81, 0x73, 0xff, + 0x59, 0xd8, 0x82, 0x75, 0x49, 0x3b, 0xc3, 0xfc, 0xaf, 0x0a, 0x75, 0x00, 0x49, 0xd0, 0x3b, 0xa6, + 0x5a, 0x3a, 0xfe, 0x2b, 0x05, 0xd6, 0x8d, 0x30, 0x48, 0x68, 0x20, 0x1e, 0x7b, 0x76, 0x60, 0xcb, + 0x68, 0x5b, 0xb6, 0xc0, 0x38, 0xe9, 0x2a, 0xbb, 0xa0, 0xa6, 0xc4, 0x73, 0x4c, 0x8c, 0x6f, 0x74, + 0xcb, 0x56, 0x95, 0xbc, 0xa8, 0x6c, 0x98, 0xd4, 0x12, 0x83, 0x42, 0x29, 0x51, 0xb6, 0xc7, 0xbc, + 0x4d, 0x53, 0xcb, 0xe8, 0x0e, 0xec, 0xa5, 0x9c, 0xc2, 0x1b, 0x5e, 0x05, 0x69, 0xf0, 0xe1, 0x62, + 0xde, 0x74, 0xe5, 0xea, 0xf1, 0x13, 0xa8, 0x4d, 0x3f, 0xa1, 0x33, 0x5c, 0x75, 0x66, 0x7e, 0x87, + 0x9b, 0x0e, 0xd1, 0x6d, 0xec, 0x34, 0xf1, 0x99, 0xde, 0x6b, 0xd9, 0xea, 0x07, 0x4c, 0xbd, 0x0e, + 0x26, 0x4e, 0x07, 0x13, 0xd6, 0x8d, 0x29, 0xc7, 0x3f, 0x83, 0x6d, 0x09, 0xe7, 0xb2, 0x2e, 0x80, + 0x35, 0xdc, 0x12, 0xcb, 0x39, 0x06, 0xc1, 0x4d, 0xd3, 0x16, 0x70, 0x7b, 0x16, 0xd3, 0x2d, 0x11, + 0x32, 0xda, 0x56, 0xd3, 0x64, 0x27, 0xd3, 0x59, 0x5b, 0xf9, 0x21, 0xdc, 0x59, 0x24, 0xa4, 0xb7, + 0x5e, 0xe8, 0x2f, 0xbb, 0x6a, 0xe9, 0xf8, 0x17, 0x0a, 0x6c, 0xcf, 0x7d, 0x9f, 0x61, 0x4b, 0x17, + 0xb4, 0xe4, 0xfd, 0xc0, 0xec, 0xfe, 0xf7, 0xe0, 0x76, 0xd1, 0x14, 0xa6, 0xf5, 0xb4, 0x85, 0x9d, + 0x5e, 0x97, 0xf5, 0x15, 0xf3, 0x4f, 0xa9, 0xe7, 0xbd, 0x96, 0x6d, 0x72, 0x6e, 0x09, 0x1d, 0xc1, + 0xdd, 0x02, 0xb7, 0x67, 0xb5, 0xcc, 0x73, 0xd3, 0xc6, 0x4d, 0x2e, 0x51, 0x3e, 0xfe, 0x43, 0x05, + 0x36, 0x67, 0x10, 0x1f, 0xd3, 0x25, 0x7d, 0x28, 0x9d, 0xfe, 0xf5, 0x25, 0x7f, 0xa0, 0x4d, 0xa8, + 0x19, 0x6d, 0xeb, 0xcc, 0x24, 0xe7, 0x3c, 0x90, 0xee, 0xc3, 0xbd, 0x0e, 0xb6, 0x9a, 0x4c, 0x3c, + 0x8d, 0x09, 0x47, 0xf2, 0x25, 0xc8, 0x45, 0x1b, 0xb0, 0x26, 0x9e, 0x5b, 0x79, 0x0b, 0xb3, 0x0e, + 0xab, 0x56, 0x9b, 0x03, 0x61, 0xb5, 0xc2, 0xda, 0x28, 0x39, 0x70, 0x3a, 0xd8, 0xd2, 0x5b, 0xe6, + 0x6f, 0xe3, 0xa6, 0x5a, 0x3d, 0x1e, 0x43, 0x7d, 0xb6, 0x5b, 0x63, 0x9a, 0xe4, 0x2d, 0xbb, 0xc0, + 0x50, 0x6b, 0x50, 0x79, 0x6e, 0x76, 0x75, 0x11, 0xdb, 0xe7, 0x7a, 0xd7, 0xc6, 0x84, 0x89, 0xaa, + 0x25, 0x16, 0xb6, 0xfa, 0x39, 0x26, 0xa6, 0xa1, 0x5b, 0x0e, 0xfe, 0xae, 0x43, 0x70, 0xb7, 0xab, + 0x96, 0xd9, 0xa9, 0x9a, 0x66, 0xd7, 0x68, 0x3f, 0xc7, 0x44, 0xad, 0x1c, 0xff, 0x89, 0x02, 0x6a, + 0x11, 0xbc, 0x72, 0xdd, 0x08, 0x4e, 0x2d, 0xb8, 0xd0, 0x1a, 0xfc, 0x2b, 0x04, 0xce, 0x7d, 0xae, + 0x78, 0x6e, 0x8a, 0xff, 0x02, 0x1d, 0xc0, 0x7e, 0x8e, 0xc1, 0x7a, 0x82, 0x29, 0xb3, 0x54, 0x98, + 0x45, 0xf0, 0x59, 0xcf, 0x6a, 0x72, 0xe3, 0xcc, 0x32, 0x84, 0xc6, 0xb8, 0xa9, 0x56, 0x5e, 0xad, + 0xf0, 0x7f, 0x18, 0x3e, 0xf9, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x84, 0x9d, 0xca, 0x4f, 0x6d, + 0x28, 0x00, 0x00, +}