A dispatch records the outbound movement of one or more medical gas cylinders to a client. Each dispatch captures who received the cylinders, when they left, supporting voucher and remission references, and an automatically computed document number derived from the source batch data. Every dispatched tank is locked from further allocation, and a correspondingDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/Janblack07/OxygenDispatch/llms.txt
Use this file to discover all available pages before exploring further.
SALIDA inventory movement is written to the audit trail — all within a single database transaction.
Dispatch methods
OxygenDispatch provides two ways to create a dispatch: hand-picking specific cylinders by serial number, or letting the system pull the right quantity automatically using FIFO selection.- Dispatch by serial selection
- Dispatch by quantity
Use this method when you know exactly which cylinder serials should leave the warehouse — for example, when a client requests a specific batch or a technician has pre-staged particular units.
The table is paginated at 15 rows per page. If the request carries an
| Step | Route |
|---|---|
| Open the create form | GET /dispatches/create |
| Submit the dispatch | POST /dispatches |
Browsing available tanks
The create page lists every tank whosestatus is DISPONIBLE (status = 1). You can narrow the table using the following query parameters:Partial match against the tank’s batch
batch_number or document_number. Useful when you know the purchase order reference but not individual serials.Partial match against the tank’s
serial field.Exact match on the cylinder capacity (e.g. 10 L, 40 L). Filters the table to a single size class.
X-Requested-With: XMLHttpRequest header (i.e. request()->ajax() is true), the endpoint returns JSON instead of a full page render:Form fields
ID of the client receiving the cylinders. Must exist in the
clients table. Leave blank to create a client-less dispatch — dispatches.entity_type will be stored as NULL.The date the cylinders were dispatched. Accepted in any format Laravel’s
date rule recognises (e.g. 2025-07-15).Do not populate this field manually. It is ignored on submission and overwritten automatically from the batch data of the selected tanks. See document_number auto-calculation.
Vehicle licence plate on the remission note. Maximum 50 characters.
Type of voucher (e.g.
Factura, Nota de entrega). Maximum 50 characters.Voucher reference number. Maximum 100 characters.
Remission note number. Maximum 100 characters.
Free-text observations. No length limit enforced at the application layer.
One or more string IDs identifying the
tank_units to dispatch. The array must contain at least one element. Each ID must exist in the tank_units table. Duplicate IDs are deduplicated automatically before processing.What happens during dispatch
Both creation paths delegate toDispatchService, which executes the following steps inside a single DB::transaction. If any step raises an exception the entire transaction is rolled back and the database is left unchanged.
- Row-level lock — each selected
TankUnitrow is fetched withlockForUpdate()to prevent concurrent dispatches from claiming the same cylinder. - Status transition —
tank.statusis set toDESPACHADOandtank.dispatched_atis stamped with the current timestamp. - Dispatch line — a
DispatchLinerecord is created linkingdispatch_id→tank_unit_id. Thedispatch_linestable enforces a unique constraint on this pair, so a tank can only appear once per dispatch and cannot be re-dispatched while its status remainsDESPACHADO. - Inventory movement — a
SALIDAInventoryMovementrecord is written, capturing the tank, the originating warehouse area, the batch, the performing user’s email, and the dispatch’sdocument_numberas the reference document.
document_number auto-calculation
Thedocument_number on a dispatch is never typed by the user — it is derived from the source batches of every cylinder included in the dispatch.
After all tanks have been selected, the controller collects each tank’s batch.document_number, drops any blank values, trims whitespace, deduplicates, and joins the results with ", ":
| Scenario | Resulting document_number |
|---|---|
All tanks originate from batch 42974328-HY | 42974328-HY |
Tanks come from batches 42974328-HY and 42974329-HY | 42974328-HY, 42974329-HY |
No batch carries a document_number | N/S |
N/S is written at creation time, and a separate syncDocumentNumberFromDispatchTanks() call recalculates and persists the real value once the transaction has committed and the assigned tank IDs are known.
Dispatch record fields
Each row in thedispatches table stores the following information:
| Field | Type | Description |
|---|---|---|
client_id | bigint nullable | FK → clients.id. Set to NULL if the client is deleted (null-on-delete). |
dispatched_at | datetime | Date and time the cylinders left the warehouse. |
document_number | string(100) nullable | Auto-calculated from batch data (see above). |
entity_type | tinyint nullable | Copied from the client at the time of dispatch: 1 = Entidad, 2 = Intradomiciliario IESS, 3 = No afiliado / Apoyo. |
remission_plate | string(50) nullable | Vehicle licence plate from the remission note. |
performed_by_user_email | string(150) | Email of the authenticated user who created the dispatch. |
voucher_type | string(50) nullable | Type label of the supporting voucher. |
voucher_number | string(100) nullable | Reference number of the supporting voucher. |
remission_number | string(100) nullable | Remission note reference number. |
notes | text nullable | Free-text observations. |
Viewing dispatches
List view —GET /dispatches returns a paginated list (15 per page) of all dispatches ordered by most recent first, with the associated client eager-loaded.
Detail view — GET /dispatches/{dispatch} loads the full dispatch record together with:
- The linked client (name, document)
- All dispatch lines, each carrying the tank’s serial number, gas type, cylinder capacity, and originating batch reference