79 lines
7.0 KiB
Markdown
79 lines
7.0 KiB
Markdown
# 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 app’s `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 user’s lat/long. **No region** filter. Distance cap is `fitur.jarak_minimum`.
|
||
|
||
Driver’s `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. 1–2 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 fitur’s `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.
|