> For the complete documentation index, see [llms.txt](https://tyrix.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tyrix.gitbook.io/docs/script-resources/tyrix-droply/integration.md).

# Integration

Droply is a sibling resource of [tyrix\_business](https://tyrix.gitbook.io/docs/script-resources/tyrix-business) and consumes its read-only export surface. It never writes to `tyrix_business` state.

## What Droply consumes

| Export                                        | Used for                                                                                      |
| --------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `isBossOf(source)`                            | Boss role resolution — the first check in the permission resolver.                            |
| `getEmployeeBusiness(source)`                 | Employee / manager resolution and the accept-order job check.                                 |
| `getStationMenuItems(businessId, stationIds)` | **Menu projection.** Every customer menu, owner menu, and price validation derives from this. |
| `getOnlineEmployees(businessId)`              | Broadcasting new orders to on-duty staff without scanning all players.                        |
| `isPlayerAdmin(source)`                       | Gating the station-assignment endpoints.                                                      |
| `getCarriedBoxes(source)`                     | Detecting a full order packed inside a `business_box`.                                        |

## What tyrix\_business drives in Droply

The **Business Manager → Droply tab** in tyrix\_business calls two Droply events directly:

| Event                      | Purpose                                                                         |
| -------------------------- | ------------------------------------------------------------------------------- |
| `droply:admin:getData`     | Returns every business and every crafting station with current selections.      |
| `droply:admin:setStations` | Replaces a business's `station_ids`, auto-creating a stub storefront if needed. |

Both are gated on `isPlayerAdmin` and both validate that each requested station is whitelisted for that business in its `station_data.jobs` map.

> These handlers must not be removed — tyrix\_business depends on them. The standalone `/droplyadmin` overlay that previously drove them has been retired.

## Menu projection

A storefront's customer menu is the intersection of three things:

```
items the assigned stations can craft      (tyrix_business)
  ∩  items with a price > 0                (storefront.item_prices)
  −  items on the hidden list              (storefront.hidden_items)
```

The owner-facing menu skips the last two filters so a boss can price items that have no price yet.

This is why station assignment is the gating step in [Storefront Setup](/docs/script-resources/tyrix-droply/storefront-setup.md) — with no stations, the projection is empty and the store is hidden from the browse list entirely.

## Delivery HUD

Droply drives the tyrix\_business **DeliveryPanel** through its client exports rather than shipping a second HUD:

| Export                                         | Droply's use                                                      |
| ---------------------------------------------- | ----------------------------------------------------------------- |
| `openDeliveryPanel(payload)`                   | Opens the panel for the focused order, with custom status labels. |
| `updateDeliveryInventory(counts, allAcquired)` | Pushes per-item progress as the driver gathers items.             |
| `updateDeliveryStatus(status, coords)`         | Flips `crafting` → `enroute` and sets the GPS destination.        |
| `closeDeliveryPanel()`                         | Closes when the last order ends.                                  |

The panel renders **one** delivery, so `client/worker.lua` keeps a focused order and switches automatically — an `enroute` order outranks a `preparing` one, with the lowest order id breaking ties.

Droply also remaps its own `qty` field to the panel's expected `quantity`, and normalises per-item counts to the ordered quantity when an order is satisfied via the box path. Without that, the panel would show "Ready to deliver" in the header but `0/N` on every row, which reads as bugged.

## Box carry

A `business_box` is a separate stash, so its contents do not count against the carrier's weight limit. Droply treats an order as fulfilled when the whole order sits inside a **single** box.

When a driver carries several qualifying boxes, Droply selects the one with the **least excess** — counting every item beyond what the order needs, including unrelated items. A box packed exactly for this order has zero excess and always wins, so a box prepped for a different order cannot be shipped by accident.

At handover the box is transferred by **slot** rather than by a full metadata match, which avoids a stale metadata comparison failing the transfer.

## LB Phone

The app registers through `exports['lb-phone']:AddCustomApp`, waiting for lb-phone to report `started` before doing so, and re-registering automatically on an lb-phone restart.

The UI is served from `ui/dist/index.html` via the resource's `files{}` block. Server-to-app pushes go through `SendCustomAppMessage`; app-to-server calls go through an **allow-listed** NUI callback that forwards only known event names.

Droply also reads the customer's and driver's numbers via `GetEquippedPhoneNumber` so each can contact the other, and pushes phone notifications for order milestones through the notification API.

## ox\_inventory

Used for item counts on the driver's client, `CanCarryItem` capacity checks before any transfer, and the `RemoveItem` / `AddItem` pair that moves goods at handover. The delivery HUD refreshes off `ox_inventory:updateInventory` with a 2-second backstop poller that only runs while an order is active.

## ox\_target

The handover option is registered with `addGlobalPlayer`, visible within `handoverInteractDistance` and only when the targeted player actually owns one of the driver's `enroute` orders.
