Overview
drs_vehicleshop is the DRS-maintained, server-authoritative successor to the earlier QR-based shop. It supports Qbox and QB road, marine, and aviation dealerships, trusted factory checkout, server-created delivery, durable order recovery, DRS Garages integration, and a protected Qbox society-fleet service.
Requirements
- Required
- ox_lib, oxmysql, and OneSync
- Framework
- qbx_core with qbx_vehicles, or qb-core
- Interaction
- ox_target or qb-target
- Garage
- drs_garages preferred; lunar_garage legacy fallback
- Resource name
- Must remain drs_vehicleshop
Installation
Back up player_vehicles and both vehicle-shop journal families before replacing an earlier QR build.
Stop qr-vehicleshop and do not run it beside drs_vehicleshop.
Install the folder with the exact drs_vehicleshop name and start oxmysql, ox_lib, the framework, keys, target, and selected garage first.
Review framework, garage, checkout, dealership, category-access, test-drive, and fleet settings before enabling sales.
Allow the first startup migration to finish, then resolve any review-state order or schema warning before opening checkout to players.
Configuration
Select framework, target, keys, and garage
The supplied automatic modes resolve supported resources at runtime, but explicit providers make production behavior easier to audit. DRS Garages is preferred; lunar_garage is a legacy fallback. Do not start both garage resources.
Config.Framework = 'qbox' -- auto, qbox, qb
Config.Target = 'ox_target' -- auto, ox_target, qb-target
Config.KeySystem = 'qbx_vehiclekeys'
Config.GarageIntegration = 'drs'Migrate an earlier QR installation
Back up the database, stop both shops, and let the runtime migrator rename qr_vehicle_shop_orders and qr_vehicle_shop_plate_reservations to their DRS identities. The database account needs CREATE, ALTER, INDEX, DROP, and INSERT for the first successful upgrade. Use the documented manual rename and qbox_drs_vehicle_columns.sql only after inspecting the current schema; drs_vehicleshop.sql is a fresh-install reference, not an upgrade script.
Define dealerships and access rules
Config.Shops owns each shop's vehicle type, catalogue, ordered categories, ped, blip, interaction, test drive, delivery point, and garage. Config.CategoryAccess protects restricted categories; the supplied emergency rule allows the exact police group at grade 0 or higher while leaving visibility separate from purchase authorization.
Configure factory checkout
Checkout entries use stable option ids. The server resolves their GTA indexes, prices, availability, plate restrictions, and delivery support when creating a quote. Prefixes accept one to three uppercase letters or numbers and apply only to road vehicles.
Config.PaymentAccount = 'cash'
Config.DeliverPurchasedVehicles = true
Config.Checkout.quoteLifetime = 30000
Config.Checkout.platePrefix.enabled = trueAlign delivery and garage identifiers
Default car, boat, and air garage ids must exist in the selected garage configuration. Drive-away is removed when delivery is disabled or a shop lacks a spawn point; garage delivery remains the safe fallback. Keep the acknowledgement and handoff timeouts long enough for the configured fade and streaming transition.
Tune server-managed test drives
Review test-drive duration, geofence, handoff timeout, return fallback, and cleanup settings. The server creates, tracks, expires, and removes test vehicles; clients cannot grant keys or turn a test entity into an owned purchase.
07Enable society fleet checkout deliberately
Fleet checkout is Qbox-first and fails closed unless DRS Garages, an allowed caller, a supported society banking provider, a ready fleet journal, the exact job/boss/grade/on-duty authority, and a server-side model allowlist all pass. Reuse the same durable request id for every retry.
08Add authentic custom vehicle imagery
Save verified custom renders as html/assets/vehicles/<lowercase-spawn-model>.webp on a consistent 960 × 536 canvas. Add-on vehicles prefer local art, then a Cfx render, then a styled unavailable state; do not substitute AI artwork for an actual sale model.
Usage and validation
Validate every dealership path
Open each enabled road, marine, and aviation shop. Test category access, search, one successful and one rejected quote, test-drive expiry, drive-away delivery, garage delivery, keys, ownership, storage, and retrieval.
Verify purchase recovery
Interrupt a non-production test at delivery and restart boundaries. Confirm the journal reconciles the exact plate/model and returns incomplete delivery to stored state without duplicate charging, ownership, keys, or entities.
Monitor journal health
Treat committed results as authoritative, retain request ids across retries, and inspect any review-state row with the matching server, framework, bank, and garage history before staff changes it.
Purchase architecture
The purchase pipeline keeps authority on the server and makes every external side effect recoverable or reviewable.
Durable personal delivery
Plate reservation and order creation share a transaction. Payment, player_vehicles ownership, server entity creation, garage registration, persistence, keys, and the one-use client acknowledgement advance the journal through explicit states.
Safe failure convergence
Blocked spawns, failed persistence, failed keys, disconnects, resource stops, and acknowledgement timeouts converge to a stored owned vehicle. Ambiguous payment or refund exports become review states rather than automatic duplicate credits.
Database and recovery
Automatic schema checks
Startup adds missing compatibility columns without rebuilding player_vehicles, creates or upgrades personal and society journals, aligns plate collation, verifies InnoDB and indexes, and reconciles interrupted orders before checkout opens.
Conflicting legacy and DRS tables
If both identities exist, the migrator disables purchases and asks for manual reconciliation. Compare row ownership and index definitions; never delete or merge financial records based only on table age.
Restart behavior
The shop restores interrupted owned deliveries to stored state and removes only the entity recorded by that order. DRS Garages rebuilds its active cache by matching trusted plate/model rows instead of blanket-storing every live vehicle.
Troubleshooting
Checkout remains disabled after startup
Read the first schema or journal readiness error in the server log. Check for both QR- and DRS-named tables, duplicate plates, incompatible indexes, missing schema privileges, or an unresolved migration before changing configuration.
A purchase is stored instead of delivered
Verify the selected garage is started and compatible, its identifier exists, the delivery spawn is clear, and persistence and key providers are healthy. Stored state is the intended safe result when delivery cannot be proven.
An order is in a review state
Match the request, character, plate, and timestamp to the framework or society-bank transaction and the DRS Garages operation. Resolve the actual external outcome before marking, retrying, or refunding the journal row.
A catalogue vehicle has no image
Confirm the lowercase spawn name and local WebP filename. Vanilla models try the official Cfx render; addon models without a verified local or Cfx render intentionally show the unavailable state.
Reference
Client presentation export
ResolveVehiclePresentation(modelOrHash) returns the configured model, display name, brand, addon flag, and ordered image candidates. It is presentation-only and grants no purchase or ownership authority.
local presentation = exports.drs_vehicleshop:ResolveVehiclePresentation(modelOrHash)Protected society fleet exports
Only resources listed in Config.Fleet.AllowedCallers may request the server-resolved catalogue, purchase an allowlisted job vehicle, or inspect service health. PurchaseFleetVehicle requires a stable 8–64 character requestId and the acting player source.
local catalog = exports.drs_vehicleshop:GetFleetCatalog({
actorSource = source,
job = 'police'
})
local result = exports.drs_vehicleshop:PurchaseFleetVehicle({
requestId = durableRequestId,
actorSource = source,
action = 'society_purchase',
job = 'police',
model = 'police3',
garageIndex = 1
})
local status = exports.drs_vehicleshop:GetFleetServiceStatus()Legacy compatibility boundary
The client still accepts qr-vehicleshop:client:openShop during transition and reads two legacy state-bag keys during entity recovery. New calls and state use drs_vehicleshop:*; financial server callbacks are not exposed under QR aliases.
- Keep the resource folder named drs_vehicleshop and use the drs_vehicleshop:* namespace for new integrations.
- The public source currently has no tag or GitHub release. Pin the tested main-branch commit and review repository changes before updating production.
- The README describes a local preview directory that is not present in the audited public snapshot; it is not part of this deployment guide.
- The MIT license and NOTICE retain RaySist and QR Development attribution for the original qr-vehicleshop foundation.