=== Ordrivo RideFlow — Taxi Booking ===
Contributors: ordrivo
Tags: taxi, chauffeur, ride booking, dispatch, trip tracking
Requires at least: 6.2
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 7.2.59
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

24/7 taxi ordering and dispatch workflow with optional scheduled pickups, country/postcode service zones, driver and dispatcher terminals, customer tracking, safety alerts, and extra-charge consent.

== Description ==

Ordrivo RideFlow provides a WordPress-based workflow for one taxi company per WordPress site. Configure the countries and postcode prefixes you serve, accept ride requests, assign eligible drivers, record trip progress, and give customers a private tracking page.

Features:
* Customer messages are limited to one every 10 seconds and 100 per ride; closed rides accept no new messages. Existing history is retained.
* Taxi ordering form for pickup and destination address, ISO country code, postcode, immediate 24/7 requests or optional scheduled pickups, passengers, luggage, a customer-selected fleet vehicle, child seats, and assistance requests.
* Online booking requires at least one valid service-area rule. Service-zone rules reject pickup or destination postcodes that do not match a configured country/prefix rule.
* Automatic optional server-side Google Routes API route distance and indicative fare; customers never enter kilometres. Without an estimate, requests are accepted and the company confirms the fare. The operator configures its own restricted API key and Google billing/quota.
* Private ride tracking link, trip status timeline, route link, dispatch-set taxi arrival estimates from 5 to 60 minutes, customer accept/cancel response, and optional customer-activated spoken status updates.
* Taxi Central and driver terminal, available through an **Open terminal** admin button or staff-only shortcode; the terminal refreshes automatically every 15 seconds while idle.
* Customer, driver and dispatch panic alerts record their explicit participant source. Customer safety events, timestamps and coordinates are included in that booking customer’s personal-data export; driver/dispatch alerts remain excluded. Each source can have one open alert at a time, with a 60-second repeat cooldown and five accepted alerts per ride per source per site-local day. Customer and driver alerts are independent and can be acknowledged individually. Closed rides reject new alerts; immediate emergencies require a direct call to local emergency services.
* Dispatch-only customer messages with no delete control in the terminal.
* Driver-requested extra charges require customer approval or decline. This records consent only and does not process payment.
* Admin can mark driver accounts eligible after off-platform licence/background checks. An expired licence date blocks assignment.
* Up to 20 configurable fleet vehicles with editable names, registrations, passenger capacity, fare multipliers, and Media Library photos. Customers select the vehicle for their request.
* Child seat, first-aid, accessibility, extra passenger-assistance, and planned security-assistance requests are shown to dispatch for confirmation.
* Daily operations summary and CSV export; WordPress personal-data export and batched erasure.

English is the source language. Translation catalogs are included for 13 locales; some strings are still untranslated and may fall back to English. Operator-entered content must be localized separately.

== Installation ==

1. Upload the `ordrivo-rideflow` folder to `/wp-content/plugins/` or upload the ZIP through Plugins → Add New → Upload Plugin.
2. Activate Ordrivo RideFlow — Taxi Booking. RideFlow creates the **Taxi Booking** customer page and the private **Ride Tracking** page. On existing installations, the booking page is created automatically on the next WordPress request after updating to 7.2.4 or later.
3. Open Ride bookings → Settings. Configure currency, prices, notification email, service-hours label (defaults to Open 24/7), service zones, emergency call number, and (optionally) Google Routes API key. Leave the key field blank to keep the saved key; check “Remove saved key and disable Google route estimates” to remove it. Bookings remain available without estimates.
4. Open Pages → Taxi Booking to view the customer form. The page contains `[ordrivo_ride_booking]`. If you prefer another page, add that shortcode to it; RideFlow reuses an existing published page containing the shortcode.
5. Create WordPress accounts with the RideFlow Driver role. An administrator must edit each driver account and mark its licence/background check as verified before the driver can be assigned. RideFlow does not perform those checks itself.
6. Open **Ride bookings → Open terminal** for Taxi Central, or add `[ordrivo_ride_terminal]` to a staff-only page. Administrators and RideFlow Dispatchers see Taxi Central; assigned drivers see their own trips.
7. The customer tracking page is created during activation. If it was removed, add `[ordrivo_ride_tracking]` to a page. The Taxi Booking page is created during activation and automatically on update if missing.

Service-area rules are required before online booking can be used. In **Ride bookings → Settings**, enter at least one valid rule and save it. If the field is empty or a rule is invalid, RideFlow keeps the previously saved rules and the customer booking form remains unavailable until a valid rule is saved.

Accepted format (one country per line):

* `CC|*` — allow every postcode entered for a country.
* `CC|PREFIX1,PREFIX2` — allow only postcodes beginning with one of the listed prefixes.

`CC` is a two-letter ISO country code. For example, `RO|*` allows every Romanian postcode; `RO|400,401` allows Romanian postcodes beginning with 400 or 401; `SE|97` allows Swedish postcodes beginning with 97. Separate multiple prefixes with commas. Each prefix must start with an A–Z letter or digit and may also contain spaces or hyphens; spaces and hyphens are ignored when matching. Do not repeat a country on multiple lines. This is an operator-maintained prefix allowlist, not a government postcode database or address verification service.

== Booking management ==

Ride bookings are created through the validated customer booking form. The WordPress **Add New** workflow is disabled so staff cannot create empty booking records. Administrators can review booking details, change the booking status, and assign a verified driver. Configure the 20 fleet rows and vehicle photos under **Ride bookings → Settings**.

== Privacy, safety, and limitations ==

Ride requests and operations records are stored in WordPress. Private tracking uses a long random bearer link; anyone with that link can view the trip and submit customer actions. Keep the link private. If route estimates are enabled, pickup/destination addresses and postcodes are sent server-to-server to Google Routes API. Configure a server-restricted key, billing limits, and quotas. To stop route requests, use the settings removal checkbox; it deletes the saved key and bookings continue without estimates.

Panic alerts send one email per accepted alert to the configured dispatch address and store an internal alert. A source may submit one alert per 60 seconds and up to five per ride per site-local day; an existing open alert is not duplicated. Customer and driver alerts are independent. Closed or cancelled rides do not create new alerts or send email. Throttle and closed-ride messages tell the caller that no new alert was sent and to contact dispatch or local emergency services directly. WordPress mail acceptance does not prove a human received or acted on it. The plugin does not call police, ambulance, or emergency dispatch. Configure the local emergency number for the operating country and call it directly in an immediate emergency.

Driver eligibility is a manual administrator attestation. RideFlow does not verify identity, query criminal-record registers, validate licences with authorities, upload ID photos, or integrate with government systems. Do not store criminal-record numbers in RideFlow.

The plugin is one WordPress site for one operator. It is not a global multi-company network, native iOS/Android app, live automatic GPS tracker, payment processor, emergency services integration, or guaranteed ETA/fare system. Dispatch-provided taxi arrival minutes are estimates that customers may accept or cancel; actual arrival can vary. Driver location is shared on demand; Google driving times are estimates and may not include live traffic.

Messages and safety records have no delete controls in the RideFlow terminal. Site administrators may still access server/database tools. WordPress privacy erasure permanently removes matching booking records and their attached history to fulfil an erasure request.

== Troubleshooting and support ==

* **The booking form is unavailable or rejects an address:** Ask the taxi company whether online bookings are enabled for your pickup and destination countries/postcode prefixes. The operator must add at least one valid service-area rule under Ride bookings → Settings. Check that country codes and postcodes are entered correctly. If the form remains unavailable, contact the taxi company with the page URL, the pickup and destination countries, and the displayed message; do not send private tracking links.
* **No booking confirmation email arrives:** Check spam/junk and confirm the email address entered in the form. If the request may have been submitted, do not submit it repeatedly; contact the taxi company with your name, email, approximate submission time and pickup time so staff can look for the request. Site operators should also verify WordPress email delivery with their hosting provider.
* **A route or fare estimate is missing:** You can still send a booking request; the taxi company will confirm the fare. Recheck the addresses, country codes and postcodes, then try the route estimate again. If estimates fail consistently, contact the taxi company. The site operator should check that Google Routes API is enabled, the server key is configured and restricted correctly, and billing/quotas are active.
* **The private tracking page will not open or update:** Open the original tracking link from the confirmation email and check that it is complete. Refresh the page and try another current browser or network. If the link was lost or expired, contact the taxi company to confirm the booking and request help. Do not post or email the private link publicly; anyone with it may see trip details or submit customer actions.
* **Location sharing or a safety alert has no location:** Allow location access for the browser and enable device location services, then retry outdoors or where GPS reception is available. A safety alert can still be submitted without coordinates. If anyone is in immediate danger, call local emergency services directly; RideFlow alerts only notify the taxi dispatch team.
* **A driver or dispatcher cannot use staff controls:** The account must use the matching RideFlow Driver or RideFlow Dispatcher role. An administrator must mark a driver's eligibility or verify a dispatcher in the WordPress user profile before assignment or shift controls become available. Ask the site administrator to check the role, verification marker, assigned ride and any licence-expiry date. RideFlow does not perform background checks or validate licences with authorities.

For a ride, booking, tracking, or safety issue, contact the dealership/taxi company that operates the website using its published phone number or email. For help with the RideFlow WordPress plugin, use the Ordrivo support page at https://ordrivo.com/contact/?lang=en or email developer@ordrivo.com. Include the website address, RideFlow version, WordPress and PHP versions, administrator language (for site owners), the steps that led to the problem, the date/time and time zone, and the exact error text or a redacted screenshot. Remove passenger names, phone numbers, addresses, safety coordinates, passwords, API keys, and private tracking tokens unless support specifically requests necessary details through a secure channel.

== Shortcodes ==

* `[ordrivo_ride_booking]` — customer booking form.
* `[ordrivo_ride_terminal]` — logged-in dispatch or driver terminal.
* `[ordrivo_ride_tracking]` — customer tracking page; a private token is required.
* `[ordrivo_driver_terminal]` — signed-in RideFlow drivers can view and update their assigned rides after administrator verification.

== Changelog ==

= 7.2.59 =
* Preserve valid zero-valued coordinates in customer safety exports and dispatch alert maps; validate numeric coordinate bounds.
* Localize operator admin labels and JavaScript feedback/fee-decision strings using the plugin text domain.
* Add troubleshooting steps and a public customer support route.


= 7.2.57 =
* Normalize each legacy message array and individual row consistently for dispatch, message limits and personal-data export.
* Use bounded cursor pagination: 25 messages per dispatch page, resuming within large legacy arrays.
* Keep original history unchanged; preserve repeated entries and archived booking messages.
* Newest messages / Older messages navigation replaces storage-row page counts.
* Retain the 7.2.56 editor locking and reentrancy fixes.


= 7.2.56 =
* Prevent internal status writes from re-entering booking-editor POST processing.
* Save status and driver assignment under one outer lock after validating both expected values.
* Derive early-stage status for assignment/unassignment; reject invalid or stale combined edits before saving booking state.
* Allow unchanged assignments on closed bookings and preserve historical drivers in the selector.
* Add runtime and WordPress integration checks. See docs/TEST-RESULTS-7.2.56.md for test scope.


= 7.2.55 =
* Separate daily estimate totals by each booking's stored currency; use the configured settings currency only for legacy bookings with no currency.
* Serialize customer message validation and writes with the shared ride-state lock. Accept at most one message per 10 seconds and 100 customer messages per ride, including legacy history. Return retry feedback and reject messages on closed rides without new message/event records.
* Preserve and count mixed legacy-array and individual-row history. Report message persistence failures without creating a message event.
* Acquire ride-state then fee-array locks for extra-charge creation; recheck current status, assignment, driver verification, licence eligibility and capability under the state lock. Reject stale requests without fee, event or email side effects.
* Retain the shared fee-array lock for customer decisions and verify persisted fee arrays. Add executable PHP regression coverage and explicit staging concurrency scenarios.


= 7.2.54 =
* Serialize ride status, ETA decisions, driver assignment, and safety-alert creation with one shared per-ride database lock; validate fresh database status and assignment values inside the lock and verify persisted status changes.
* Reject stale staff status and driver-assignment updates; protect generic ride editor saves from resetting a status changed by another request.
* Bound safety alerts to one open alert per source, one accepted alert per source per minute, and five per source per ride per site-local day. Customer and driver alerts stay independent and individually acknowledgeable.
* Reject alerts after delivery, completion, or cancellation and explain that no record/email was created; direct immediate emergencies to the local emergency number.
* Add source assertions and reviewer concurrency scenarios.

= 7.2.53 =
* Process privacy erasure in bounded 100-ride callbacks and return `done=false` while matching records remain.
* Keep first-page queries to avoid deletion-related skips; mark failed records for the current erasure run so later rides can be erased.
* Report failed records without retrying them on every callback, with a capped fallback ID list only when a marker cannot be saved.

= 7.2.52 =
* Serialize dispatch taxi arrival estimate replacements and customer accept/cancel responses with a shared per-ride lock.
* Require customer ETA responses to match the displayed estimate revision; stale responses conflict after a replacement.
* Verify ETA metadata and cancelled ride status before reporting success, and hide response controls after cancellation.
* Add an explicit settings control to remove the saved Google Routes API key and disable estimates while keeping bookings available.

= 7.2.51 =
* Serialize driver extra-charge requests and customer approve/decline decisions with one per-ride database lock and a fresh metadata read inside the lock.
* Verify the complete fee array was persisted before reporting success; write fee events only after the metadata mutation succeeds.
* Reject conflicting repeat decisions and return a retryable error when the lock or persistence check fails.
* Add source regression checks and concurrency-focused staging steps for simultaneous different-charge decisions, opposite decisions, and overlapping driver/customer updates.

= 7.2.50 =
* Persist customer approval or decline directly to the matching extra-charge array entry before returning success; reject malformed or already-decided requests.
* Show customer decision timestamps after reload and in tracking polls, and include them in WordPress personal-data exports.
* Use one date-independent nonce action for authorized daily CSV downloads; validate requested calendar dates separately.

= 7.2.49 =
* Query active rides separately from closed rides so a volume of newer completed or cancelled rides cannot hide ongoing work.
* Add separate 25-item pages for ongoing rides, closed rides, and dispatch messages. Drivers continue to see only rides assigned to their verified account.
* Paginate message records across active and archived rides. Open safety alerts remain in a separate dispatch list and do not depend on the selected message page.
* Closed ride cards are read-only; ride status actions remain available for ongoing rides only.

= 7.2.48 =
* Add server-side pagination for the dispatcher archive so all archived rides remain reachable.
* Redirect restored rides back to the live terminal.
* Reserve per-IP route estimate quota under a database advisory lock, then release the lock before calling Google Routes API.
* Add regression checks and reviewer verification notes for the archive and concurrent route quota cases.

= 7.2.46 =
* Add staff operator management and a dedicated driver terminal shortcode.
* Restrict driver trip access to assigned rides and require administrator verification before ride operations.
* Ensure the plugin header, runtime version constant, and readme stable tag all identify 7.2.47.
* Staging verification boundaries and the operator roster retest requirement are documented in the accompanying reviewer report.

= 7.2.45 =
* Add the dedicated driver terminal page and driver trip status workflow.
* WordPress role, assignment, and frontend access checks require staging verification.

= 7.2.43 =
* Align plugin header, runtime asset version and readme stable tag.
* Add WPBay reviewer verification checklist and translation completeness report; no unverified live-test claims.
* Retain unbounded open safety alert retrieval; no 500-ride cap for pending alerts.

= 7.2.42 =
* Record the reviewer verification checklist and translation coverage status.
* Keep live staging checks explicit; static query inspection is not a stress-test result.

= 7.2.37 =
* Make the stock fare disclaimer follow the visitor-selected language; preserve custom operator-authored notes.

= 7.2.33 =
* Supply missing Arabic and Persian translations for key booking form consent, placeholder and booking notice strings.
* Improve right-to-left booking form layout and preserve left-to-right input for phone, email and numeric data.
* Operator-configured fare notes remain site content and must be translated separately.

= 7.2.32 =
* Preserve overlapping customer and driver SOS alerts and acknowledge each pending alert independently.
* Generate secure browser booking request IDs, isolate tracking output buffers, and correct the successful-booking rate-limit regression assertion.

= 7.2.30 =
* Serialize identical booking request IDs and per-IP successful-booking counters to prevent duplicates and concurrent counter races.
* Live WordPress/browser concurrency verification remains required.

= 7.2.11 =
* Count only successfully created bookings toward the IP rate limit; validation errors, failed inserts, and idempotent recovery retries do not consume the allowance.
* Increase the cap to 10 successful bookings per IP per hour.

= 7.2.9 =
* Remove the autofill-prone `company_website` honeypot name and ignore that legacy POST field.
* Keep nonce checks, server-side booking validation and IP rate limiting.

= 7.2.8 =
* Recover a saved booking confirmation and private tracking link if the browser loses the POST response, without creating a duplicate booking.

= 7.2.7 =
* Add a dispatch control for taxi pickup arrival estimates from 5 to 60 minutes in 5-minute steps.
* Show the estimate on private tracking with customer accept/cancel actions.

= 7.2.6 =
* Send public booking and route requests to the current booking page, avoiding scoped WordPress Playground admin-ajax routing failures.
* Keep booking submission independent of a second Google Routes request and add idempotency recovery.

= 7.2.5 =
* Use a same-origin relative AJAX endpoint for customer booking submissions and terminal actions.

= 7.2.4 =
* Automatically create the public Taxi Booking page when missing and reuse an existing page with the booking shortcode.

= 7.2.3 =
* Validate service-area configuration and preserve prior valid rules after invalid input.

= 7.2.2 =
* Improve customer-visible route calculation and service-area setup feedback.

= 7.2.1 =
* Improve booking form setup, route estimate feedback, and desktop/mobile booking behavior.

= 7.2.0 =
* Add the initial taxi booking, service area, route estimate, dispatch and tracking workflows.

= 7.1.2 =
* Improve booking administration and terminal status handling.

= 7.1.1 =
* Improve booking notifications and operational status handling.

= 7.1.0 =
* Add immediate bookings, service-area controls, fleet setup and taxi terminal workflow.

= 7.0.1 =
* Preserve driver and Taxi Central ride states when editing other booking details in wp-admin.
* Show human-readable labels for operational ride statuses in the Ride bookings list.

= 7.0.0 =
* See CHANGELOG.md in the plugin package.
