diff --git a/camply/cli.py b/camply/cli.py index 0b2330c1..110956a3 100644 --- a/camply/cli.py +++ b/camply/cli.py @@ -457,6 +457,16 @@ def campgrounds( "equipment names include `Tent`, `RV`. `Trailer`, `Vehicle` and are " "not case-sensitive.", ) +include_walkin_argument = click.option( + "--include-walkin", + is_flag=True, + show_default=True, + default=False, + help="Include walk-in / non-web-bookable campsites in results. By default " + "these are filtered out because they show as 'Available' in the API but " + "can't actually be reserved online. Currently honored by the " + "ReserveCalifornia and other UseDirect-based providers.", +) equipment_id_argument = click.option( "--equipment-id", default=None, @@ -619,6 +629,7 @@ def _get_provider_kwargs_from_cli( offline_search_path: Optional[str], equipment: Tuple[Union[str, int]], equipment_id: Tuple[Union[str, int]], + include_walkin: bool, day: Optional[Tuple[str]], ) -> Tuple[Dict[str, Any], Dict[str, Any]]: """ @@ -666,6 +677,7 @@ def _get_provider_kwargs_from_cli( "offline_search_path": offline_search_path, "equipment": equipment, "equipment_id": equipment_id, + "include_walkin": include_walkin, "days_of_the_week": days_of_the_week, } search_kwargs = { @@ -701,6 +713,7 @@ def _get_provider_kwargs_from_cli( @notify_first_try_argument @equipment_argument @equipment_id_argument +@include_walkin_argument @provider_argument @debug_option @click.pass_obj @@ -726,6 +739,7 @@ def campsites( offline_search_path: Optional[str], equipment: Tuple[Union[str, int]], equipment_id: Tuple[Union[str, int]], + include_walkin: bool, day: Optional[Tuple[str]], ) -> None: """ @@ -767,6 +781,7 @@ def campsites( offline_search_path=offline_search_path, equipment=equipment, equipment_id=equipment_id, + include_walkin=include_walkin, day=day, yaml_config=yaml_config, ) diff --git a/camply/providers/usedirect/usedirect.py b/camply/providers/usedirect/usedirect.py index 65fec63d..af4f33bb 100644 --- a/camply/providers/usedirect/usedirect.py +++ b/camply/providers/usedirect/usedirect.py @@ -367,6 +367,7 @@ def get_campsites( sleeping_unit_id: Optional[int] = None, unit_sort: Optional[str] = "orderby", in_season_only: Optional[bool] = True, + include_walkin: bool = False, ) -> List[AvailableCampsite]: """ Get Campsites from UseDirect @@ -425,7 +426,17 @@ def get_campsites( unit=unit, ) campsite_available = campsite.availability_status == "Available" - if campsite_available is True: + # The API reports walk-in / non-web-bookable slices as + # "Available" but they can't actually be reserved online. + # IsWalkin can be set per-night even on units whose + # AllowWebBooking is True (a normally bookable site that's + # held back for walk-ups on specific dates), so both flags + # matter. Pass through unfiltered when --include-walkin is set. + is_bookable = ( + availability_slice.IsWalkin is not True + and unit.AllowWebBooking is not False + ) + if campsite_available is True and (include_walkin or is_bookable): if ( len(self.campsite_ids) == 0 or campsite.campsite_id in self.campsite_ids diff --git a/camply/search/search_usedirect.py b/camply/search/search_usedirect.py index 9827ebaf..01be7946 100644 --- a/camply/search/search_usedirect.py +++ b/camply/search/search_usedirect.py @@ -53,6 +53,7 @@ def __init__( weekends_only: bool = False, campgrounds: Optional[Union[List[str], str]] = None, nights: int = 1, + include_walkin: bool = False, **kwargs, ) -> None: """ @@ -78,6 +79,7 @@ def __init__( nights=nights, **kwargs, ) + self.include_walkin: bool = include_walkin self._recreation_area_ids: List[int] = make_list(recreation_area, coerce=int) self._campground_ids: List[int] = make_list(campgrounds, coerce=int) campsites = make_list(kwargs.get("campsites", []), coerce=int) or [] @@ -145,6 +147,7 @@ def get_all_campsites(self, **kwargs: Dict[str, Any]) -> List[AvailableCampsite] campground_id=campground.facility_id, start_date=month, end_date=end_date, + include_walkin=self.include_walkin, ) logger.info( f"\t{logging_utils.get_emoji(campsites)}\t"