Files
Ontime/ORDERING_WORKFLOW.md
2026-03-11 15:29:37 +07:00

79 lines
7.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# OnTime Ordering Workflow & Firebase Alignment
## Order flow (User → Driver → Tujuan)
1. **User: Set jemput (pickup)** In RideCarActivity, user sets pickup via map/Places (`pickUpText`, `pickUpLatLang`).
2. **User: Set tujuan (destination)** User sets destination (`destinationText`, `destinationLatLang`). Route and price are calculated.
3. **User: Set payment** Cash or wallet (`checkedpaywallet`, `cashpayment` / `walletpayment`).
4. **Search driver** `GetNearRideCarRequestJson` / `GetNearRideCarResponseJson` loads nearby drivers; `driverAvailable` is used for FCM.
5. **User: Order** `sendRequestTransaksi()` calls backend, then `fcmBroadcast()` sends FCM to each driver token via **backend** `notification/send_generic`.
6. **Driver: Bid or auto bid** Driver receives FCM in `MessagingService` (type=1), opens `NewOrderActivity`. Manual: tap "order"; Auto: `getaccept(true)` after 2s if setting is ON.
7. **Driver: Accept** `getaccept()` calls backend `accept`, then sends FCM to **user token** (`regid`) with `OrderFCM` (response="2", type=1, id_driver, id_transaksi).
8. **User: Driver accepted** User app `MessagingService` gets type=1, response="2", posts `DriverResponse` via EventBus; `RideCarActivity.onMessageEvent` starts `ProgressActivity` (response "2").
9. **Progress (until tujuan)** User stays in `ProgressActivity`; driver in `OrderFragment` can tap "finish" (start) then "finish" (arrive). Each action: driver calls backend (`startrequest` / `finishrequest`), then FCM to user with response "3" (start) or "4" (finish/tujuan).
10. **User: Start / Finish** `MessagingService` parses type=1 and response "3"/"4", posts `DriverResponse`; `ProgressActivity` receives via EventBus or broadcast, `orderHandler()` updates status (e.g. "driver start", "finish/tiba di tujuan").
## Test backend API
**To test backend, use endpoint: `apitest.semestaterpadu.my.id`**
All apps and the backend panel use the same test API base URL:
| Component | Config location | Base URL | API base |
|-------------|-----------------|----------|----------|
| User app | `OnTime_User_live``Constants.java` | `https://apitest.semestaterpadu.my.id/` | `.../api/` |
| Driver app | `OnTime_Driver_live``Constants.java` | `https://apitest.semestaterpadu.my.id/` | `.../api/` |
| Backend | `backendpanel/application/config/config.php``$config['base_url']` | `https://apitest.semestaterpadu.my.id/` | same |
Example test endpoints:
- Base: `https://apitest.semestaterpadu.my.id/`
- API (login, transaksi, etc.): `https://apitest.semestaterpadu.my.id/api/`
- FCM send: `POST https://apitest.semestaterpadu.my.id/api/notification/send_generic`
---
## Firebase: same project for User, Backend, Driver
- **Backend** Single FCM project: uses `fcm_v1_helper` (HTTP v1) with service account (e.g. `FCM_CREDENTIALS_PATH` / `FCM_PROJECT_ID`). All sends go through **backend** `api/notification/send_generic` (POST).
- **User app** Receives FCM via `FirebaseMessagingService`; **sends** by calling same backend `Constants.CONNECTION + "notification/send_generic"` with `target` = driver token and `data` = `DriverRequest` (order offer).
- **Driver app** Receives FCM via `FirebaseMessagingService`; **sends** by calling same backend `Constants.CONNECTION + "notification/send_generic"` with `target` = user token and `data` = `OrderFCM` (accept/start/finish).
Both apps use the same `BASE_URL` (e.g. `https://apitest.semestaterpadu.my.id/`) and same endpoint, so they share the same Firebase project and backend.
## FCM type and payload alignment
| Type | Meaning | Sender | Receiver | Key payload |
|------|-----------|----------|----------|-------------|
| 1 | Order | User→Driver: `DriverRequest` (offer); Driver→User: `OrderFCM` (accept/start/finish/cancel) | Both | id_transaksi, id_driver, response ("2"/"3"/"4"/"5"), plus offer fields for driver |
| 2 | Chat | User/Driver | User/Driver | chat fields |
| 3 | Other | Backend | User/Driver | title, message |
| 4 | Other2 | Backend | User/Driver | title, message |
Backend `send_generic_to_token` / `send_generic_to_topic` flatten `data` and stringify values so FCM receives a flat string map.
## Driver & merchant matching: purely GPS (no region)
- **Driver nearby** (`list_ride` / `list_car`): Uses only **real GPS** driver position from `config_driver` (updated by driver apps `update_location`) and user/customer position from the request. **No region/wilayah** is used. Radius is `fitur.jarak_minimum` (km), with a minimum of 10 km.
- **Merchant nearby**: Uses only **real GPS** `merchant.latitude_merchant`, `merchant.longitude_merchant` and users lat/long. **No region** filter. Distance cap is `fitur.jarak_minimum`.
Drivers `wilayah` (partner_region) is only used in the admin panel for display; it is **not** used when finding nearby drivers or merchants for the user.
---
## "Tidak ada pengemudi di sekitar Anda" checklist
If the user always sees "Maaf, tidak ada pengemudi di sekitar Anda" even when a driver is close:
1. **Driver must be "online"** In the driver app the driver must be in "online" / status 1 mode. The backend only returns drivers where `config_driver.status = '1'`.
2. **Driver location** The driver app sends location via `driver/update_location`. Ensure the driver has opened the app and location permission is granted so `config_driver` has recent latitude/longitude.
3. **Backend radius** The backend uses `fitur.jarak_minimum` (km). A minimum radius of **10 km** is now applied so that small values in the admin panel (e.g. 12 km) still show drivers within 10 km. Admin can set **Services → jarak_minimum** to a larger value (e.g. 15 or 20 km) if needed.
4. **User app** If the first fetch was slow or location was not ready, the user can tap **Order** anyway: the app will **refetch** nearby drivers once (using pickup or last location) and then either place the order or show the message.
## Fixes applied
- **Backend:** Implemented `send_generic_to_token` and `send_generic_to_topic` in `Notification_model` using `fcm_v1_send`; controller loads `fcm_v1_helper` so generic FCM from both apps works.
- **User MessagingService:** Null-safe handling for `getData()` and `type`; broadcast bundle now includes `code`, `response`, `id_transaksi`, `id_driver` so ProgressActivity can update when driver sends start/finish.
- **ProgressActivity:** BroadcastReceiver only applies updates when `id_transaksi` matches; updates local `response` and calls `orderHandler(code)` so status and flow (e.g. sampai tujuan) stay correct.
- **Driver MessagingService:** Null-safe handling for `getData()`, `type`, and `harga` to avoid NPE/crash on malformed FCM.
- **"No driver near you":** Backend `get_driver_ride` now uses a minimum radius of 10 km (`GREATEST(COALESCE(f.jarak_minimum, 10), 10)`) so drivers within 10 km are found even if the fiturs `jarak_minimum` is set very small. User app: when the user taps Order and the driver list is empty, the app refetches nearby drivers once (using pickup or last location) and then proceeds or shows the message.