Repository: googlemaps/google-maps-services-go
Pull request #280 (2023-01-24 08:22:38)

feat: add new place details fields
Add support for new place details fields described in https://cloud.google.com/blog/products/maps-platform/help-users-discover-more-new-places-api-updates


Patch:
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index f32d216..e5e9936 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -21,11 +21,11 @@ jobs:
     runs-on: ubuntu-latest    
     steps:
     - name: Checkout
-      uses: actions/checkout@v2
+      uses: actions/checkout@v3
       with:
         token: ${{ secrets.SYNCED_GITHUB_TOKEN_REPO }} 
     - name: Semantic Release
-      uses: cycjimmy/semantic-release-action@v2
+      uses: cycjimmy/semantic-release-action@v3
       with:
         semantic_version: 19
         extra_plugins: |
diff --git a/places.go b/places.go
index d95db03..e847b9e 100644
--- a/places.go
+++ b/places.go
@@ -400,6 +400,15 @@ func (r *PlaceDetailsRequest) params() url.Values {
 		q.Set("region", r.Region)
 	}
 
+	if r.ReviewsNoTranslations {
+		q.Set("reviews_no_translations", "true")
+	}
+
+
+	if r.ReviewsSort != "" {
+		q.Set("reviews_sort", r.ReviewsSort)
+	}
+
 	return q
 }
 
@@ -413,7 +422,7 @@ type PlaceDetailsRequest struct {
 	Language string
 	// Fields allows you to select which parts of the returned details structure
 	// should be filled in. For more detail, please see the following URL:
-	// https://cloud.google.com/maps-platform/user-guide/product-changes/#places
+	// https://developers.google.com/maps/documentation/places/web-service/details#fields
 	Fields []PlaceDetailsFieldMask
 	// SessionToken is a token that marks this request as part of a Place Autocomplete
 	// Session. Optional.
@@ -422,6 +431,28 @@ type PlaceDetailsRequest struct {
 	// two-character value. Most ccTLD codes are identical to ISO 3166-1 codes, with
 	// some exceptions. This parameter will only influence, not fully restrict, results.
 	Region string
+	// ReviewsNoTranslations specifies whether to translate reviews. Specify
+	// ReviewsNoTranslations=true to disable translation of reviews; specify
+	// ReviewsNoTranslations=false to enable translation of reviews. Reviews
+	// are returned in their original language.
+	//
+	// If omitted, or passed with no value, translation of reviews is enabled. If
+	// the language parameter was specified in the request, use the specified
+	// language as the preferred language for translation. If language is
+	// omitted, the API attempts to use the Accept-Language header as the
+	// preferred language.
+	ReviewsNoTranslations bool
+	// ReviewsSort specifies the sorting method to use when returning reviews.
+	// Can be set to most_relevant (default) or newest.
+	//
+	//For most_relevant (default), reviews are sorted by relevance; the service
+	// will bias the results to return reviews originally written in the
+	// preferred language.
+	// For newest, reviews are sorted in chronological order; the preferred
+	// language does not affect the sort order.
+	// Google recommends that you display how the reviews are being sorted to the
+	// end user.
+	ReviewsSort string
 }
 
 // PlaceDetailsResult is an individual Places API Place Details result
@@ -433,6 +464,20 @@ type PlaceDetailsResult struct {
 	FormattedAddress string `json:"formatted_address,omitempty"`
 	// AdrAddress is the address in the "adr" microformat.
 	AdrAddress string `json:"adr_address,omitempty"`
+	// BusinessStatus is a string indicating the operational status of the
+	// place, if it is a business.
+	BusinessStatus string `json:"business_status,omitempty"`
+	// CurbsidePickup specifies if the business supports curbside pickup.
+	CurbsidePickup bool `json:"curbside_pickup,omitempty"`
+	// Delivery specifies if the business supports delivery.
+	Delivery bool `json:"delivery,omitempty"`
+	// DineIn specifies if the business supports seating options.
+	DineIn bool `json:"dine_in,omitempty"`
+	// EditorialSummary contains a summary of the place. A summary is comprised
+	// of a textual overview, and also includes the language code for these if
+	// applicable. Summary text must be presented as-is and can not be modified
+	// or altered.
+	EditorialSummary *PlaceEditorialSummary `json:"editorial_summary,omitempty"`
 	// FormattedPhoneNumber contains the place's phone number in its local format. For
 	// example, the formatted_phone_number for Google's Sydney, Australia office is
 	// (02) 9374 4000.
@@ -446,54 +491,90 @@ type PlaceDetailsResult struct {
 	// location (geocode) of the place and (optionally) the viewport identifying its
 	// general area of coverage.
 	Geometry AddressGeometry `json:"geometry,omitempty"`
-	// Name contains the human-readable name for the returned result. For establishment
-	// results, this is usually the business name.
-	Name string `json:"name,omitempty"`
 	// Icon contains the URL of a recommended icon which may be displayed to the user
 	// when indicating this result.
 	Icon string `json:"icon,omitempty"`
-	// PlaceID is a textual identifier that uniquely identifies a place.
-	PlaceID string `json:"place_id,omitempty"`
-	// Rating contains the place's rating, from 1.0 to 5.0, based on aggregated user
-	// reviews.
-	Rating float32 `json:"rating,omitempty"`
-	// UserRatingsTotal contains total number of the place's ratings
-	UserRatingsTotal int `json:"user_ratings_total,omitempty"`
-	// Types contains an array of feature types describing the given result.
-	Types []string `json:"types,omitempty"`
+	// Name contains the human-readable name for the returned result. For establishment
+	// results, this is usually the business name.
+	Name string `json:"name,omitempty"`
 	// OpeningHours may contain whether the place is open now or not.
 	OpeningHours *OpeningHours `json:"opening_hours,omitempty"`
-	// Photos is an array of photo objects, each containing a reference to an image.
-	Photos []Photo `json:"photos,omitempty"`
-	// PriceLevel is the price level of the place, on a scale of 0 to 4.
-	PriceLevel int `json:"price_level,omitempty"`
-	// Vicinity contains a feature name of a nearby location.
-	Vicinity string `json:"vicinity,omitempty"`
+	// CurrentOpeningHours may contain the hours of operation for the next seven
+	// days (including today). The time period starts at midnight on the date of
+	// the request and ends at 11:59 pm six days later. This field includes the
+	// special_days subfield of all hours, set for dates that have exceptional
+	// hours.
+	CurrentOpeningHours *OpeningHours `json:"current_opening_hours,omitempty"`
+	// SecondaryOpeningHours may contain an array of entries for the next seven
+	// days including information about secondary hours of a business. Secondary
+	// hours are different from a business's main hours. For example, a
+	// restaurant can specify drive through hours or delivery hours as its
+	// secondary hours. This field populates the type subfield, which draws from
+	// a predefined list of opening hours types (such as DRIVE_THROUGH, PICKUP,
+	// or TAKEOUT) based on the types of the place. This field includes the
+	// special_days subfield of all hours, set for dates that have exceptional
+	// hours.
+	SecondaryOpeningHours *OpeningHours `json:"secondary_opening_hours,omitempty"`
 	// PermanentlyClosed is a boolean flag indicating whether the place has permanently
 	// shut down (value true). If the place is not permanently closed, the flag is
 	// absent from the response.
+	//
+	// Deprecated: Use BusinessStatus instead.
 	PermanentlyClosed bool `json:"permanently_closed,omitempty"`
-	// BusinessStatus is a string indicating the operational status of the
-	// place, if it is a business.
-	BusinessStatus string `json:"business_status,omitempty"`
+	// Photos is an array of photo objects, each containing a reference to an image.
+	Photos []Photo `json:"photos,omitempty"`
+	// PlaceID is a textual identifier that uniquely identifies a place.
+	PlaceID string `json:"place_id,omitempty"`
+	// PriceLevel is the price level of the place, on a scale of 0 to 4.
+	PriceLevel int `json:"price_level,omitempty"`
+	// Rating contains the place's rating, from 1.0 to 5.0, based on aggregated user
+	// reviews.
+	Rating float32 `json:"rating,omitempty"`
+	// Reservable specifies if the place supports reservations.
+	Reservable bool `json:"reservable,omitempty"`
 	// Reviews is an array of up to five reviews. If a language parameter was specified
 	// in the Place Details request, the Places Service will bias the results to prefer
 	// reviews written in that language.
 	Reviews []PlaceReview `json:"reviews,omitempty"`
+	// ServesBeer specifies if the place serves beer.
+	ServesBeer bool `json:"serves_beer,omitempty"`
+	// ServesBreakfast specifies if the place serves breakfast.
+	ServesBreakfast bool `json:"serves_breakfast,omitempty"`
+	// ServesBrunch specifies if the place serves brunch.
+	ServesBrunch bool `json:"serves_brunch,omitempty"`
+	// ServesDinner specifies if the place serves dinner.
+	ServesDinner bool `json:"serves_dinner,omitempty"`
+	// ServesLunch specifies if the place serves lunch.
+	ServesLunch bool `json:"serves_lunch,omitempty"`
+	// ServesVegetarianFood specifies if the place serves vegetarian food.
+	ServesVegetarianFood bool `json:"serves_vegetarian_food,omitempty"`
+	// ServesWine specifies if the place serves wine.
+	ServesWine bool `json:"serves_wine,omitempty"`
+	// Takeout specifies if the business supports takeout.
+	Takeout bool `json:"takeout,omitempty"`
+	// Types contains an array of feature types describing the given result.
+	Types []string `json:"types,omitempty"`
+	// URL contains the URL of the official Google page for this place. This will be the
+	// establishment's Google+ page if the Google+ page exists, otherwise it will be the
+	// Google-owned page that contains the best available information about the place.
+	// Applications must link to or embed this page on any screen that shows detailed
+	// results about the place to the user.
+	URL string `json:"url,omitempty"`
+	// UserRatingsTotal contains total number of the place's ratings
+	UserRatingsTotal int `json:"user_ratings_total,omitempty"`
 	// UTCOffset contains the number of minutes this place’s current timezone is offset
 	// from UTC. For example, for places in Sydney, Australia during daylight saving
 	// time this would be 660 (+11 hours from UTC), and for places in California outside
 	// of daylight saving time this would be -480 (-8 hours from UTC).
 	UTCOffset *int `json:"utc_offset,omitempty"`
+	// Vicinity contains a feature name of a nearby location.
+	Vicinity string `json:"vicinity,omitempty"`
 	// Website lists the authoritative website for this place, such as a business'
 	// homepage.
 	Website string `json:"website,omitempty"`
-	// URL contains the URL of the official Google page for this place. This will be the
-	// establishment's Google+ page if the Google+ page exists, otherwise it will be the
-	// Google-owned page that contains the best available information about the place.
-	// Applications must link to or embed this page on any screen that shows detailed
-	// results about the place to the user.
-	URL string `json:"url,omitempty"`
+	// WheelchairAccessibleEntrance specifies if the place has an entrance that
+	// is wheelchair-accessible.
+	WheelchairAccessibleEntrance bool `json:"wheelchair_accessible_entrance,omitempty"`
 	// HTMLAttributions contain a set of attributions about this listing which must be
 	// displayed to the user.
 	HTMLAttributions []string `json:"html_attributions,omitempty"`
diff --git a/types.go b/types.go
index 78a5ab9..bf3b379 100644
--- a/types.go
+++ b/types.go
@@ -155,6 +155,17 @@ type Photo struct {
 	HTMLAttributions []string `json:"html_attributions"`
 }
 
+// PlaceEditorialSummary contains a summary of the place. A summary is
+// comprised of a textual overview, and also includes the language code for
+// these if applicable. Summary text must be presented as-is and can not be
+// modified or altered.
+type PlaceEditorialSummary struct {
+	// Language is the language of the previous fields. May not always be present.
+	Language string `json:"language,omitempty"`
+	// Overview is a medium-length textual summary of the place.
+	Overview string `json:"overview,omitempty"`
+}
+
 // Component specifies a key for the parts of a structured address. See
 // https://developers.google.com/maps/documentation/geocoding/intro#ComponentFiltering
 // for more detail.
@@ -502,7 +513,7 @@ func ParseAutocompletePlaceType(placeType string) (AutocompletePlaceType, error)
 
 // PlaceDetailsFieldMask allows you to specify which fields are to be returned with
 // a place details request. Please see the following URL for more detail:
-// https://cloud.google.com/maps-platform/user-guide/product-changes/#places
+// https://developers.google.com/maps/documentation/places/web-service/details#fields
 type PlaceDetailsFieldMask string
 
 // The individual Place Details Field Masks.
@@ -510,6 +521,10 @@ const (
 	PlaceDetailsFieldMaskAddressComponent             = PlaceDetailsFieldMask("address_component")
 	PlaceDetailsFieldMaskADRAddress                   = PlaceDetailsFieldMask("adr_address")
 	PlaceDetailsFieldMaskBusinessStatus               = PlaceDetailsFieldMask("business_status")
+	PlaceDetailsFieldMaskCurbsidePickup               = PlaceDetailsFieldMask("curbside_pickup")
+	PlaceDetailsFieldMaskDelivery                     = PlaceDetailsFieldMask("delivery")
+	PlaceDetailsFieldMaskDineIn                       = PlaceDetailsFieldMask("dine_in")
+	PlaceDetailsFieldMaskEditorialSummary             = PlaceDetailsFieldMask("editorial_summary")
 	PlaceDetailsFieldMaskFormattedAddress             = PlaceDetailsFieldMask("formatted_address")
 	PlaceDetailsFieldMaskFormattedPhoneNumber         = PlaceDetailsFieldMask("formatted_phone_number")
 	PlaceDetailsFieldMaskGeometry                     = PlaceDetailsFieldMask("geometry")
@@ -528,18 +543,30 @@ const (
 	PlaceDetailsFieldMaskInternationalPhoneNumber     = PlaceDetailsFieldMask("international_phone_number")
 	PlaceDetailsFieldMaskName                         = PlaceDetailsFieldMask("name")
 	PlaceDetailsFieldMaskOpeningHours                 = PlaceDetailsFieldMask("opening_hours")
+	PlaceDetailsFieldMaskCurrentOpeningHours          = PlaceDetailsFieldMask("current_opening_hours")
+	PlaceDetailsFieldMaskSecondaryOpeningHours        = PlaceDetailsFieldMask("secondary_opening_hours")
 	PlaceDetailsFieldMaskPermanentlyClosed            = PlaceDetailsFieldMask("permanently_closed")
 	PlaceDetailsFieldMaskPhotos                       = PlaceDetailsFieldMask("photos")
 	PlaceDetailsFieldMaskPlaceID                      = PlaceDetailsFieldMask("place_id")
 	PlaceDetailsFieldMaskPriceLevel                   = PlaceDetailsFieldMask("price_level")
 	PlaceDetailsFieldMaskRatings                      = PlaceDetailsFieldMask("rating")
 	PlaceDetailsFieldMaskUserRatingsTotal             = PlaceDetailsFieldMask("user_ratings_total")
+	PlaceDetailsFieldMaskReservable                   = PlaceDetailsFieldMask("reservable")
 	PlaceDetailsFieldMaskReviews                      = PlaceDetailsFieldMask("reviews")
+	PlaceDetailsFieldMaskServesBeer                   = PlaceDetailsFieldMask("serves_beer")
+	PlaceDetailsFieldMaskServesBreakfast              = PlaceDetailsFieldMask("serves_breakfast")
+	PlaceDetailsFieldMaskServesBrunch                 = PlaceDetailsFieldMask("serves_brunch")
+	PlaceDetailsFieldMaskServesDinner                 = PlaceDetailsFieldMask("serves_dinner")
+	PlaceDetailsFieldMaskServesLunch                  = PlaceDetailsFieldMask("serves_lunch")
+	PlaceDetailsFieldMaskServesVegetarianFood         = PlaceDetailsFieldMask("serves_vegetarian_food")
+	PlaceDetailsFieldMaskServesWine                   = PlaceDetailsFieldMask("serves_wine")
+	PlaceDetailsFieldMaskTakeout                      = PlaceDetailsFieldMask("takeout")
 	PlaceDetailsFieldMaskTypes                        = PlaceDetailsFieldMask("types")
 	PlaceDetailsFieldMaskURL                          = PlaceDetailsFieldMask("url")
 	PlaceDetailsFieldMaskUTCOffset                    = PlaceDetailsFieldMask("utc_offset")
 	PlaceDetailsFieldMaskVicinity                     = PlaceDetailsFieldMask("vicinity")
 	PlaceDetailsFieldMaskWebsite                      = PlaceDetailsFieldMask("website")
+	PlaceDetailsFieldMaskWheelchairAccessibleEntrance = PlaceDetailsFieldMask("wheelchair_accessible_entrance")
 )
 
 // ParsePlaceDetailsFieldMask will parse a string representation of
@@ -552,6 +579,14 @@ func ParsePlaceDetailsFieldMask(placeDetailsFieldMask string) (PlaceDetailsField
 		return PlaceDetailsFieldMaskADRAddress, nil
 	case "business_status":
 		return PlaceDetailsFieldMaskBusinessStatus, nil
+	case "curbside_pickup":
+		return PlaceDetailsFieldMaskCurbsidePickup, nil
+	case "delivery":
+		return PlaceDetailsFieldMaskDelivery, nil
+	case "dine_in":
+		return PlaceDetailsFieldMaskDineIn, nil
+	case "editorial_summary":
+		return PlaceDetailsFieldMaskEditorialSummary, nil
 	case "formatted_address":
 		return PlaceDetailsFieldMaskFormattedAddress, nil
 	case "formatted_phone_number":
@@ -588,6 +623,10 @@ func ParsePlaceDetailsFieldMask(placeDetailsFieldMask string) (PlaceDetailsField
 		return PlaceDetailsFieldMaskName, nil
 	case "opening_hours":
 		return PlaceDetailsFieldMaskOpeningHours, nil
+	case "current_opening_hours":
+		return PlaceDetailsFieldMaskCurrentOpeningHours, nil
+	case "secondary_opening_hours":
+		return PlaceDetailsFieldMaskSecondaryOpeningHours, nil
 	case "permanently_closed":
 		return PlaceDetailsFieldMaskPermanentlyClosed, nil
 	case "photos":
@@ -600,8 +639,26 @@ func ParsePlaceDetailsFieldMask(placeDetailsFieldMask string) (PlaceDetailsField
 		return PlaceDetailsFieldMaskRatings, nil
 	case "user_ratings_total":
 		return PlaceDetailsFieldMaskUserRatingsTotal, nil
+	case "reservable":
+		return PlaceDetailsFieldMaskReservable, nil
 	case "reviews":
 		return PlaceDetailsFieldMaskReviews, nil
+	case "serves_beer":
+		return PlaceDetailsFieldMaskServesBeer, nil
+	case "serves_breakfast":
+		return PlaceDetailsFieldMaskServesBreakfast, nil
+	case "serves_brunch":
+		return PlaceDetailsFieldMaskServesBrunch, nil
+	case "serves_dinner":
+		return PlaceDetailsFieldMaskServesDinner, nil
+	case "serves_lunch":
+		return PlaceDetailsFieldMaskServesLunch, nil
+	case "serves_vegetarian_food":
+		return PlaceDetailsFieldMaskServesVegetarianFood, nil
+	case "serves_wine":
+		return PlaceDetailsFieldMaskServesWine, nil
+	case "takeout":
+		return PlaceDetailsFieldMaskTakeout, nil
 	case "types":
 		return PlaceDetailsFieldMaskTypes, nil
 	case "url":
@@ -612,6 +669,8 @@ func ParsePlaceDetailsFieldMask(placeDetailsFieldMask string) (PlaceDetailsField
 		return PlaceDetailsFieldMaskVicinity, nil
 	case "website":
 		return PlaceDetailsFieldMaskWebsite, nil
+	case "wheelchair_accessible_entrance":
+		return PlaceDetailsFieldMaskWheelchairAccessibleEntrance, nil
 	default:
 		return PlaceDetailsFieldMask(""), fmt.Errorf("Unknown PlaceDetailsFieldMask \"%v\"", placeDetailsFieldMask)
 	}


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index b9e75f0..648f2e6 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -18,11 +18,11 @@ jobs:
   build:
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/setup-go@v1
+    - uses: actions/setup-go@v3
       with:
-        go-version: 1.13
+        go-version: 'stable'
       id: go
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
     - run: go build -v ./...
     - run: go test -v -race -coverprofile=coverage.txt -covermode=atomic ./...
-    - uses: codecov/codecov-action@v1
\ No newline at end of file
+    - uses: codecov/codecov-action@v3
diff --git a/places_test.go b/places_test.go
index 3118651..cd47ce7 100644
--- a/places_test.go
+++ b/places_test.go
@@ -651,84 +651,98 @@ func TestPlaceAutocompleteWithStructuredFormatting(t *testing.T) {
 func TestPlaceDetails(t *testing.T) {
 	response := `
 {
-   "html_attributions" : [],
-   "result" : {
-      "address_components" : [],
-      "formatted_address" : "3, Overseas Passenger Terminal, George St & Argyle Street, The Rocks NSW 2000, Australia",
-      "formatted_phone_number" : "(02) 9251 5600",
-      "geometry" : {
-         "location" : {
-            "lat" : -33.858018,
-            "lng" : 151.210091
-         }
-      },
-      "icon" : "https://maps.gstatic.com/mapfiles/place_api/icons/restaurant-71.png",
-      "international_phone_number" : "+61 2 9251 5600",
-      "name" : "Quay",
-      "opening_hours" : {
-         "open_now" : true,
-         "periods" : [
-            {
-               "close" : {
-                  "day" : 1,
-                  "time" : "1700"
-               },
-               "open" : {
-                  "day" : 1,
-                  "time" : "1330"
-               }
+    "html_attributions": [],
+    "result": {
+        "business_status": "OPERATIONAL",
+        "dine_in": true,
+        "formatted_address": "Upper Level Overseas Passenger Terminal, The Rocks NSW 2000, Australia",
+        "geometry": {
+            "location": {
+                "lat": -33.85756870000001,
+                "lng": 151.2100844
+            },
+            "viewport": {
+                "northeast": {
+                    "lat": -33.8561714197085,
+                    "lng": 151.2113682802915
+                },
+                "southwest": {
+                    "lat": -33.85886938029149,
+                    "lng": 151.2086703197085
+                }
             }
-         ],
-         "weekday_text" : [
-            "Monday: 1:30 – 5:00 pm"
-         ]
-      },
-      "photos" : [
-         {
-            "height" : 612,
-            "html_attributions" : [
-               "\u003ca href=\"https://maps.google.com/maps/contrib/107255044321733286691\"\u003eFrom a Google User\u003c/a\u003e"
+        },
+        "name": "Quay Restaurant",
+        "opening_hours": {
+            "open_now": false,
+            "periods": [
+                {
+                    "close": {
+                        "day": 0,
+                        "time": "2045"
+                    },
+                    "open": {
+                        "day": 0,
+                        "time": "1200"
+                    }
+                },
+                {
+                    "close": {
+                        "day": 4,
+                        "time": "2045"
+                    },
+                    "open": {
+                        "day": 4,
+                        "time": "1800"
+                    }
+                },
+                {
+                    "close": {
+                        "day": 5,
+                        "time": "2045"
+                    },
+                    "open": {
+                        "day": 5,
+                        "time": "1800"
+                    }
+                },
+                {
+                    "close": {
+                        "day": 6,
+                        "time": "2045"
+                    },
+                    "open": {
+                        "day": 6,
+                        "time": "1200"
+                    }
+                }
             ],
-            "photo_reference" : "CmRdAAAAm1qTaarpM_sUatFI7JxjwxVTgKCGSjz62q_vHpNMoZDP3PpBHGW-rAHQEEprl_c1MyvXFhvZb2mXj8yhKvnEMsSveb-cMuDaDgS7LS8sPPrMrt5s_Mx0G0ereom3j6KxEhAkaQH1_nWxpl4W2mFZ1CKoGhQV_Jx9MIn0skBS3tRAuIFzgHARww",
-            "width" : 816
-         }
-      ],
-      "place_id" : "ChIJ02qnq0KuEmsRHUJF4zo1x4I",
-      "price_level" : 4,
-      "rating" : 4.1,
-      "reviews" : [
-         {
-            "aspects" : [
-               {
-                  "rating" : 1,
-                  "type" : "overall"
-               }
-			],
-			"profile_photo_url": "https://lh3.googleusercontent.com/-EXtIWgDBHgs/AAAAAAAAAAI/AAAAAAAAAAA/AIcfdXCXHH76RsCp2i2B0qjO1WngDfIrQQ/s120-p-rw-no-mo/photo.jpg",
-            "author_name" : "Rachel Lewis",
-            "author_url" : "https://plus.google.com/114299517944848975298",
-            "language" : "en",
-            "rating" : 3,
-            "text" : "Overall disappointing. This is the second time i've been there and my experience was... Nothing to nibble on for 45 mins and then the bread came. My first entree was the marron which I thought was tasteless - perhaps others would say delicate? but there you go. The XO sea was fantastic. I chose the  vegetarian main dish which was all about the texture which was great but nothing at all outstanding about the dish. My husband and daughter chose the duck for their main course it was the smallest main course i've ever seen - their faces were priceless when it arrived!. Snow egg was beautiful but the granita on the bottom had some solid chunks of hard ice. The service was quite good...",
-            "time" : 1441848853
-         }
-      ],
-      "types" : [ "restaurant", "food", "point_of_interest", "establishment" ],
-      "url" : "https://plus.google.com/105746337161979416551/about?hl=en-US",
-      "user_ratings_total" : 275,
-      "utc_offset" : 660,
-      "vicinity" : "3 Overseas Passenger Terminal, George Street, The Rocks",
-      "website" : "http://www.quay.com.au/"
-   },
-   "status" : "OK"
+            "weekday_text": [
+                "Monday: Closed",
+                "Tuesday: Closed",
+                "Wednesday: Closed",
+                "Thursday: 6:00 – 8:45 PM",
+                "Friday: 6:00 – 8:45 PM",
+                "Saturday: 12:00 – 8:45 PM",
+                "Sunday: 12:00 – 8:45 PM"
+            ]
+        },
+        "place_id": "ChIJ4cQcDV2uEmsRMxTEHBIe9ZQ",
+        "serves_dinner": true,
+        "utc_offset": 660,
+        "wheelchair_accessible_entrance": true
+    },
+    "status": "OK"
 }
 `
 	server := mockServer(200, response)
 	defer server.Close()
 	c, _ := NewClient(WithAPIKey(apiKey), WithBaseURL(server.URL))
-	placeID := "ChIJ02qnq0KuEmsRHUJF4zo1x4I"
+	placeID := "ChIJ4cQcDV2uEmsRMxTEHBIe9ZQ"
+	fields := []PlaceDetailsFieldMask{PlaceDetailsFieldMaskBusinessStatus, PlaceDetailsFieldMaskDineIn, PlaceDetailsFieldMaskFormattedAddress, PlaceDetailsFieldMaskGeometry, PlaceDetailsFieldMaskName, PlaceDetailsFieldMaskCurrentOpeningHours, PlaceDetailsFieldMaskPlaceID, PlaceDetailsFieldMaskServesDinner, PlaceDetailsFieldMaskUTCOffset, PlaceDetailsFieldMaskWheelchairAccessibleEntrance}
 	r := &PlaceDetailsRequest{
 		PlaceID: placeID,
+		Fields: fields,
 	}
 
 	resp, err := c.PlaceDetails(context.Background(), r)
@@ -738,48 +752,34 @@ func TestPlaceDetails(t *testing.T) {
 		return
 	}
 
-	formattedAddress := "3, Overseas Passenger Terminal, George St & Argyle Street, The Rocks NSW 2000, Australia"
-	if formattedAddress != resp.FormattedAddress {
-		t.Errorf("expected %+v, was %+v", formattedAddress, resp.FormattedAddress)
+	businessStatus := "OPERATIONAL"
+	if businessStatus != resp.BusinessStatus {
+		t.Errorf("expected %+v, was %+v", businessStatus, resp.BusinessStatus)
 	}
 
-	formattedPhoneNumber := "(02) 9251 5600"
-	if formattedPhoneNumber != resp.FormattedPhoneNumber {
-		t.Errorf("expected %+v, was %+v", formattedPhoneNumber, resp.FormattedPhoneNumber)
-	}
-
-	icon := "https://maps.gstatic.com/mapfiles/place_api/icons/restaurant-71.png"
-	if icon != resp.Icon {
-		t.Errorf("expected %+v, was %+v", icon, resp.Icon)
+	if !*&resp.DineIn {
+		t.Errorf("Expected DineIn to be true")
 	}
 
-	internationalPhoneNumber := "+61 2 9251 5600"
-	if internationalPhoneNumber != resp.InternationalPhoneNumber {
-		t.Errorf("expected %+v, was %+v", internationalPhoneNumber, resp.InternationalPhoneNumber)
+	formattedAddress := "Upper Level Overseas Passenger Terminal, The Rocks NSW 2000, Australia"
+	if formattedAddress != resp.FormattedAddress {
+		t.Errorf("expected %+v, was %+v", formattedAddress, resp.FormattedAddress)
 	}
 
-	name := "Quay"
+	name := "Quay Restaurant"
 	if name != resp.Name {
 		t.Errorf("expected %+v, was %+v", name, resp.Name)
 	}
 
-	if !*resp.OpeningHours.OpenNow {
-		t.Errorf("Expected OpenNow to be true")
-	}
-
-	if *resp.UTCOffset != 660 {
-		t.Errorf("Expected UTCOffset to be 660")
-	}
-
-	if resp.OpeningHours.Periods[0].Open.Day != time.Monday || resp.OpeningHours.Periods[0].Close.Day != time.Monday {
+	if resp.OpeningHours.Periods[0].Open.Day != time.Sunday || resp.OpeningHours.Periods[0].Close.Day != time.Sunday {
 		t.Errorf("OpeningHours.Periods[0].Open.Day or Close.Day incorrect")
 	}
 
-	if resp.OpeningHours.Periods[0].Open.Time != "1330" || resp.OpeningHours.Periods[0].Close.Time != "1700" {
+	if resp.OpeningHours.Periods[0].Open.Time != "1200" || resp.OpeningHours.Periods[0].Close.Time != "2045" {
 		t.Errorf("OpeningHours.Periods[0].Open.Time or Close.Time incorrect")
 	}
 
-	weekdayText := "Monday: 1:30 – 5:00 pm"
+	weekdayText := "Monday: Closed"
 	if weekdayText != resp.OpeningHours.WeekdayText[0] {
 		t.Errorf("expected %+v, was %+v", weekdayText, resp.OpeningHours.WeekdayText[0])
 	}
@@ -788,89 +788,18 @@ func TestPlaceDetails(t *testing.T) {
 		t.Errorf("expected %+v, was %+v", placeID, resp.PlaceID)
 	}
 
-	authorName := "Rachel Lewis"
-	if authorName != resp.Reviews[0].AuthorName {
-		t.Errorf("expected %+v, was %+v", authorName, resp.Reviews[0].AuthorName)
-	}
-
-	authorProfilePhoto := "https://lh3.googleusercontent.com/-EXtIWgDBHgs/AAAAAAAAAAI/AAAAAAAAAAA/AIcfdXCXHH76RsCp2i2B0qjO1WngDfIrQQ/s120-p-rw-no-mo/photo.jpg"
-	if authorProfilePhoto != resp.Reviews[0].AuthorProfilePhoto {
-		t.Errorf("expected %+v, was %+v", authorProfilePhoto, resp.Reviews[0].AuthorProfilePhoto)
-	}
-
-	authorURL := "https://plus.google.com/114299517944848975298"
-	if authorURL != resp.Reviews[0].AuthorURL {
-		t.Errorf("expected %+v, was %+v", authorURL, resp.Reviews[0].AuthorURL)
-	}
-
-	language := "en"
-	if language != resp.Reviews[0].Language {
-		t.Errorf("expected %+v, was %+v", language, resp.Reviews[0].Language)
-	}
-
-	rating := 3
-	if rating != resp.Reviews[0].Rating {
-		t.Errorf("expected %+v, was %+v", rating, resp.Reviews[0].Rating)
-	}
-
-	text := "Overall disappointing. This is the second time i've been there and my experience was... Nothing to nibble on for 45 mins and then the bread came. My first entree was the marron which I thought was tasteless - perhaps others would say delicate? but there you go. The XO sea was fantastic. I chose the  vegetarian main dish which was all about the texture which was great but nothing at all outstanding about the dish. My husband and daughter chose the duck for their main course it was the smallest main course i've ever seen - their faces were priceless when it arrived!. Snow egg was beautiful but the granita on the bottom had some solid chunks of hard ice. The service was quite good..."
-	if text != resp.Reviews[0].Text {
-		t.Errorf("expected %+v, was %+v", text, resp.Reviews[0].Text)
-	}
-
-	time := 1441848853
-	if time != resp.Reviews[0].Time {
-		t.Errorf("expected %+v, was %+v", time, resp.Reviews[0].Time)
+	if !*&resp.ServesDinner {
+		t.Errorf("Expected ServesDinner to be true")
 	}
-}
 
-func TestPlaceDetailsUTCOffsetAbsent(t *testing.T) {
-	response := `
-{
-   "html_attributions" : [],
-   "result" : {
-      "address_components" : [],
-      "formatted_address" : "3, Overseas Passenger Terminal, George St & Argyle Street, The Rocks NSW 2000, Australia",
-      "formatted_phone_number" : "(02) 9251 5600",
-      "geometry" : {
-         "location" : {
-            "lat" : -33.858018,
-            "lng" : 151.210091
-         }
-      },
-      "icon" : "https://maps.gstatic.com/mapfiles/place_api/icons/restaurant-71.png",
-      "international_phone_number" : "+61 2 9251 5600",
-      "name" : "Quay",
-      "place_id" : "ChIJ02qnq0KuEmsRHUJF4zo1x4I",
-      "price_level" : 4,
-      "rating" : 4.1,
-      "types" : [ "restaurant", "food", "point_of_interest", "establishment" ],
-      "url" : "https://plus.google.com/105746337161979416551/about?hl=en-US",
-      "user_ratings_total" : 275,
-      "vicinity" : "3 Overseas Passenger Terminal, George Street, The Rocks",
-      "website" : "http://www.quay.com.au/"
-   },
-   "status" : "OK"
-}
-`
-	server := mockServer(200, response)
-	defer server.Close()
-	c, _ := NewClient(WithAPIKey(apiKey), WithBaseURL(server.URL))
-	placeID := "ChIJ02qnq0KuEmsRHUJF4zo1x4I"
-	r := &PlaceDetailsRequest{
-		PlaceID: placeID,
+	if *resp.UTCOffset != 660 {
+		t.Errorf("Expected UTCOffset to be 660")
 	}
 
-	resp, err := c.PlaceDetails(context.Background(), r)
-
-	if err != nil {
-		t.Errorf("r.Get returned non nil error: %v", err)
-		return
+	if !*&resp.WheelchairAccessibleEntrance {
+		t.Errorf("Expected WheelchairAccessibleEntrance to be true")
 	}
 
-	if resp.UTCOffset != nil {
-		t.Errorf("Expected UTCOffset to be nil")
-	}
 }
 
 func TestPlaceDetailsMissingPlaceID(t *testing.T) {
@@ -888,33 +817,6 @@ func TestPlaceDetailsMissingPlaceID(t *testing.T) {
 	}
 }
 
-func TestPlacePhoto(t *testing.T) {
-	photoReference := "ThisIsNotAPhotoReference"
-	expectedQuery := "key=AIzaNotReallyAnAPIKey&maxheight=400&maxwidth=400&photoreference=ThisIsNotAPhotoReference"
-
-	server := mockServerForQuery(expectedQuery, 200, "An Image?")
-	defer server.s.Close()
-
-	c, _ := NewClient(WithAPIKey(apiKey), WithBaseURL(server.s.URL))
-
-	r := &PlacePhotoRequest{
-		PhotoReference: photoReference,
-		MaxHeight:      400,
-		MaxWidth:       400,
-	}
-
-	_, err := c.PlacePhoto(context.Background(), r)
-
-	if err != nil {
-		t.Errorf("Unexpected error in constructing request URL: %+v", err)
-	}
-
-	if server.successful != 1 {
-		t.Errorf("Got URL(s) %v, want %s", server.failed, expectedQuery)
-	}
-
-}
-
 func TestPlacePhotoMissingPhotoReference(t *testing.T) {
 	c, _ := NewClient(WithAPIKey(apiKey))
 	r := &PlacePhotoRequest{}
@@ -1108,7 +1010,7 @@ func TestPlaceAutocompleteJsonMarshalLowerCase(t *testing.T) {
 
 func TestFindPlaceFromText(t *testing.T) {
 	expectedQuery := "fields=photos%2Cformatted_address%2Cname%2Copening_hours%2Crating&input=mongolian+grill&inputtype=textquery&key=AIzaNotReallyAnAPIKey&locationbias=circle%3A2000%4047.6918452%2C-122.2226413"
-	response := `	
+	response := `
 {
 	"candidates" : [
 	   {