> For the complete documentation index, see [llms.txt](https://atiysus-organization.gitbook.io/aty-scripts/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://atiysus-organization.gitbook.io/aty-scripts/dealership-v2/introduction.md).

# Introduction

## 🚗 aty\_dealershipv2

> **A fully-featured, player-owned vehicle dealership system for FiveM (ESX / QBCore)**\
> Version `2.0.1` · Author `atiysu` · Framework-agnostic via `aty_lib`

***

### 📖 Overview

`aty_dealershipv2` is an advanced, fully database-driven vehicle dealership resource for FiveM servers. It supports unlimited, fully customisable dealerships that can be either:

* **Self-Served** – Managed by server admins only; players can browse and buy freely.
* **Player-Owned** – Players can purchase, own, and manage entire dealerships as a business. Owners stock vehicles, set prices, run discounts, issue coupons, deliver ordered stock, and collect revenue to their dealership's balance.

The UI is built with **Vue 3 + Vite** and communicates over NUI callbacks. All dealership data is persisted in a MariaDB/MySQL database.

***

### ✨ Features

| Category            | Feature                                                                              |
| ------------------- | ------------------------------------------------------------------------------------ |
| **Dealerships**     | Unlimited dealerships, each with its own location set                                |
| **Shop Types**      | `self-served` (admin-only management) and `owned` (player-managed)                   |
| **Purchasing**      | Cash, Bank Card, or Installment (Finance) payments                                   |
| **Finance**         | Configurable interest rate, late fees, maximum months, first-payment requirement     |
| **Installments**    | Player installment dashboard, pay monthly or in full, overdue tracking               |
| **Coupons**         | Owner/admin creates coupon codes with % discount, expiry time, and usage limit       |
| **Discounts**       | Time-limited, usage-capped per-vehicle discounts                                     |
| **Ordering**        | Realistic order delivery mission – spawn truck, hitch trailer, deliver to dealership |
| **Showcase**        | Owners place real vehicles at custom world positions as showroom displays            |
| **Test Drive**      | Isolated routing bucket per test drive, timer countdown                              |
| **Admin Panel**     | Full in-game CRUD for dealerships and the global vehicle catalog                     |
| **Targets**         | Optional target interaction (works with `aty_lib` target module)                     |
| **Exports**         | Rich Lua exports for integration with other resources                                |
| **Dual-Framework**  | Supports both **ESX** and **QBCore** via `aty_lib`                                   |
| **Customisable UI** | All colours fully configurable from `config.lua` without touching source code        |
| **Job Restriction** | Restrict any dealership to a specific job or leave it open to all                    |

***

### 📦 Dependencies

| Dependency                                           | Notes                                                                                       |
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| [`aty_lib`](https://atiysu.tebex.io/package/6964982) | **Required** – provides framework abstraction, callbacks, SQL helpers, and shared utilities |
| `oxmysql` or compatible                              | Required by `aty_lib` for database queries                                                  |
| ESX **or** QBCore                                    | One framework must be present and started before `aty_lib`                                  |

> **Note:** `aty_lib` must be started **before** `aty_dealershipv2` in your `server.cfg`.

***

### 🛠️ Installation

#### Database Setup

**Fresh install** – run `data.sql`:

```sql
-- Creates the main dealership table and the vehicle_installments table
SOURCE aty_dealershipv2/data.sql
```

**Updating from an older version** – run `update.sql` instead:

```sql
-- Creates vehicle_installments if missing and adds the `coupons` column
SOURCE aty_dealershipv2/update.sql
```

The two tables created are:

| Table                  | Purpose                                                                                 |
| ---------------------- | --------------------------------------------------------------------------------------- |
| `aty_dealership`       | Stores every dealership: locations, vehicles, orders, sales, listings, coupons, balance |
| `vehicle_installments` | Tracks active finance/installment debt per player                                       |

#### Resource Setup

1. Copy the `aty_dealershipv2` folder into your resources directory (e.g. `resources/[aty]/`).
2. Add the following lines to your `server.cfg` **after** `aty_lib`:

```cfg
ensure aty_lib
ensure aty_dealershipv2
```

3. Import the SQL file(s) described above into your database.
4. Restart your server or use `refresh` + `start aty_dealershipv2`.

***

### ⚙️ Configuration Reference

All configuration lives in **`shared/config.lua`**. Changes here apply to both client and server automatically.

***

#### General Settings

```lua
Config = {
    Target          = false,       -- true = use ox_target/qtarget zones, false = proximity markers
    RealisticOrder  = true,        -- true = order delivery requires driving the truck
    OrderCooldown   = 1,           -- minutes between orders (per dealership)
    DefaultStock    = 1,           -- fallback stock when not specified
    MaxListings     = 5,           -- max showcase vehicle listings per dealership
    TestTime        = 60,          -- test-drive time limit in seconds
```

| Key              | Type      | Description                                                                 |
| ---------------- | --------- | --------------------------------------------------------------------------- |
| `Target`         | `boolean` | Enable ox\_target-style zone interactions instead of proximity `DrawText3D` |
| `RealisticOrder` | `boolean` | Requires the owner to drive a delivery truck to restock vehicles            |
| `OrderCooldown`  | `number`  | Minutes before another order can be placed on the same shop                 |
| `DefaultStock`   | `number`  | Stock assigned to a vehicle if none is specified                            |
| `MaxListings`    | `number`  | Maximum number of showcase listings per dealership                          |
| `TestTime`       | `number`  | Seconds a player gets for a test drive                                      |

**Order Pickup Locations** – the array of `vector4` coordinates where delivery trucks spawn:

```lua
OrderPickupLocation = {
    vector4(1204.3624, -3099.4116, 5.8572, 0.0),
    -- add more pickup points as needed
},
OrderTruckModel   = "phantom",   -- GTA model name for the delivery truck
OrderTrailerModel = "tr4",       -- GTA model name for the trailer
```

***

#### Finance Settings

```lua
PaymentInterval           = 24,    -- hours between installment payments (24 = daily)
MaxInstallmentMonths      = 24,    -- maximum months a player can spread payments over
MaxActiveInstallments     = 3,     -- max concurrent installment contracts per player

FinanceInterest           = 0.05,  -- 5% interest added to the total financed price
FinanceLateFee            = 0.02,  -- 2% compounding fee per overdue interval
FinanceCheckFullPrice     = true,  -- player must have full vehicle price in bank to finance
FinanceFirstPaymentRequired = true, -- first monthly payment is deducted immediately on purchase
```

| Key                           | Description                                                                         |
| ----------------------------- | ----------------------------------------------------------------------------------- |
| `PaymentInterval`             | Use `12` = every 12 h, `24` = daily, `168` = weekly, `720` = monthly                |
| `FinanceInterest`             | Multiplied onto selling price → total financed amount                               |
| `FinanceLateFee`              | Applied per each missed interval, compounding on the remaining balance              |
| `FinanceCheckFullPrice`       | Safety check – prevents players from taking finance they cannot theoretically repay |
| `FinanceFirstPaymentRequired` | Deducts the first monthly instalment at the moment of purchase                      |

***

#### UI Theme

Every colour used in the NUI can be overridden without touching Vue source code:

```lua
UI = {
    PrimaryColor          = "#69ffec",  -- Main accent / highlight colour
    PrimaryColorDark      = "#3f998e",  -- Darker shade of accent
    BackgroundPrimary     = "#0c0e12",  -- Main panel background
    BackgroundSecondary   = "#2c2f3a",  -- Card / secondary panel colour
    TextPrimary           = "#ffffff",
    TextSecondary         = "#999999",
    ButtonPrimaryStart    = "#69ffec",  -- Gradient start for primary buttons
    ButtonPrimaryEnd      = "#3f998e",  -- Gradient end for primary buttons
    StatusSuccess         = "#1f8a43",
    StatusWarning         = "#d78024",
    StatusError           = "#eb3333",
    StatusDanger          = "#d03737",
},
```

***

#### Interaction Zones

Controls the radius and visibility distance for each interaction point:

```lua
Interactions = {
    ZoneRadius       = 4.0,   -- radius of the main shop / ped zone
    ZoneDistance     = 4.0,   -- draw distance for the zone prompt
    ManageRadius     = 2.0,   -- boss management dashboard zone
    ManageDistance   = 2.0,
    PurchaseRadius   = 2.0,   -- "purchase this dealership" zone
    PurchaseDistance = 2.0,
    ShowcaseRadius   = 2.0,   -- around showcase-listed vehicles
    ShowcaseDistance = 2.0,
},
```

***

#### Vehicle Stats

Controls how vehicle performance data is fetched and displayed:

```lua
VehicleStats = {
    AWD_Threshold = 0.3,              -- acceleration value above which drivetrain reads "AWD"
    Normalization = {
        Speed        = { 100, 180 },  -- km/h min/max for bar chart
        Acceleration = { 0.1, 0.4 },
        Handling     = { 20, 45 },
        Braking      = { 0.0, 1.0 },
        Traction     = { 1, 3 },
    }
},
```

***

#### Callbacks & Hooks

**`OnVehiclePurchase`**

Called **server-side** every time a vehicle is successfully purchased:

```lua
OnVehiclePurchase = function(source, model, plate, price, method)
    -- source  = player server ID
    -- model   = vehicle model string
    -- plate   = generated license plate
    -- price   = final price after discounts/coupons
    -- method  = "cash" | "bank" | "finance"
    
    -- Example: award XP, log to Discord, grant keys, etc.
    print(string.format("Player %s bought %s (%s) for $%s via %s", source, model, plate, price, method))
end
```

***

### 🏪 Dealership Types

| Type          | Description                                                                                                                                 |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `self-served` | No owner. All vehicles are permanently in stock. Admins manage everything through the admin panel. Ideal for government/public dealerships. |
| `owned`       | Can be purchased by a player. The owner manages stock, orders, listings, prices, discounts, coupons, and the dealership's balance.          |

***

### 🛡️ Admin Panel Guide

#### Opening the Admin Panel

Use the in-game command (default: `dealershipadmin`):

```
/dealershipadmin
```

This command is restricted to the permission levels defined in:

```lua
Config.AdminPermissions = { "god", "admin", "superadmin" }
```

For **QBCore**, these are QBCore permission levels. For **ESX**, these map to ESX account ranks.

***

#### Creating a Dealership

1. Run `/dealershipadmin` to open the admin panel.
2. Click the **Create** (➕) button in the top-right.
3. Fill in the creation form:

| Field          | Description                                                                                          |
| -------------- | ---------------------------------------------------------------------------------------------------- |
| **Name**       | Unique identifier for the dealership (no spaces recommended)                                         |
| **Price**      | Cost for a player to purchase this dealership (set `0` if not for sale)                              |
| **Blip ID**    | GTA map blip sprite ID (see [blip sprites reference](https://docs.fivem.net/game-references/blips/)) |
| **Job**        | `all` for everyone, or a job name (e.g. `mechanic`) to restrict access                               |
| **Ped Model**  | Model name for the salesperson NPC (default: `ig_siemonyetarian`)                                    |
| **Type**       | `owned` or `self-served`                                                                             |
| **Locations**  | Click each button and confirm placement in the world                                                 |
| **Categories** | Select which vehicle categories appear in this dealership's stock                                    |

4. **Locations** – You must set all 8 points:

| Location      | Purpose                                             |
| ------------- | --------------------------------------------------- |
| `Dashboard`   | Where the boss management menu is accessed (marker) |
| `Dealership`  | Position of the map blip                            |
| `Purchase`    | Zone where players can buy the dealership itself    |
| `Ped`         | Where the salesperson NPC spawns                    |
| `Preview`     | Where vehicles are shown in the shopping camera     |
| `Spawn`       | Where the purchased vehicle appears after buying    |
| `Test`        | Where the vehicle spawns for a test drive           |
| `Order Point` | Where the delivery truck arrives after an order     |

5. Click **Create** to save. The dealership appears on all connected clients immediately.

***

#### Editing a Dealership

1. Open the admin panel.
2. Find the dealership in the list and click the **Edit** (⚙️) icon.
3. Modify any fields and re-set any locations as needed.
4. Click **Update**.

> All connected clients receive the updated dealership data in real time.

***

#### Deleting a Dealership

1. Open the admin panel.
2. Click the **Delete** icon next to the dealership.
3. Confirm in the popup.

> This permanently removes the dealership and all its data from the database.

***

#### Managing the Vehicle Catalog

The **global vehicle catalog** (`shared/catalog.lua`) defines every vehicle available to any dealership. Admins can manage it in-game:

1. Open `/dealershipadmin`.
2. Click **Edit Vehicles** (pencil icon).
3. Select the vehicle you want to modify from the dropdown.
4. Edit its **Name**, **Label**, **Model**, **Price**, and **Category**.
5. Alternatively click **Delete** to remove it from the catalog entirely.

To **add a new vehicle** to the catalog, use the `addVehicleToCatalog` server callback or manually add it to `shared/catalog.lua`.

> Changes to the catalog are saved directly to `shared/catalog.lua` and broadcast to all clients.

***

### 👤 Player Guide

#### Browsing Vehicles

1. Approach the **dealership NPC** on the map (look for the blip icon).
2. Press **\[E]** when the prompt appears to open the shop menu.
3. Use the **search bar** to filter by vehicle name.
4. Use the **category tabs** at the top to filter by type (Cars, Bikes, Boats, etc.).
5. Click any vehicle to select it – a **live 3D preview** will spawn at the preview point.
   * **Scroll** to rotate the 3D preview model.
   * **Pinch / scroll wheel** to zoom.
6. View the vehicle's **Technical Specifications** panel:
   * Max Speed, Acceleration, Braking, Traction, Seats, Drivetrain

***

#### Test Drive

1. Select a vehicle in the shop menu.
2. Click **Test Drive**.
3. The vehicle spawns at the test drive location. You have **`Config.TestTime` seconds** (default 60 s) before it is automatically returned.
4. Exit the vehicle at any time to end the test drive early.

> Test drives are isolated in a routing bucket – other players cannot see or interact with the test drive vehicle.

***

#### Purchasing a Vehicle

1. Select a vehicle in the shop menu.
2. Choose your **primary colour** and **secondary colour** using the colour pickers.
3. (Optional) Enter a **coupon code** and click **Apply** to receive a discount.
4. Choose your payment method:

| Method                              | Requirements                      |
| ----------------------------------- | --------------------------------- |
| **Pay with Card** (Bank)            | Must have sufficient bank balance |
| **Pay with Cash**                   | Must have sufficient cash on hand |
| **Pay with Installments** (Finance) | See finance conditions below      |

5. If using **Finance**:
   * Select the number of months (1 – `MaxInstallmentMonths`).
   * The UI shows the monthly payment and total amount with interest.
   * If `FinanceCheckFullPrice = true`, you need the full vehicle price in your bank.
   * If `FinanceFirstPaymentRequired = true`, the first instalment is deducted immediately.
6. Confirm the purchase. The vehicle spawns at the dealership spawn point with:
   * Your chosen colours applied.
   * Your vehicle keys granted (via `aty_lib` key export).
   * A full fuel tank (100%).
   * A unique license plate.

***

#### Using Coupons

1. In the purchase panel, locate the **Coupon Code** input.
2. Type the code provided by the dealership owner and click **Apply**.
3. If valid, the discount percentage is shown and the total price is reduced.
4. Coupons can expire or have a usage limit – if either is exceeded, the code is rejected.

***

#### Installment Payments

1. Use the command `/installments` (default) to open your **Installments Dashboard**.
2. All active finance contracts are listed, showing:
   * Vehicle name and plate
   * Total debt / remaining balance
   * Monthly payment amount
   * Next payment due date
   * Overdue status
3. Click **Make Payment** to pay one monthly instalment.
4. Click **Pay in Full** to clear the entire remaining balance in one go.

> **Late Fees:** If a payment is missed, a `FinanceLateFee` percentage is compounded onto the remaining balance for each overdue interval.

***

### 💼 Dealership Owner (Boss) Guide

#### Accessing the Boss Menu

1. Go to your dealership's **Dashboard** marker (the location you set when creating it).
2. Press **\[E]** when the prompt appears.
3. The Boss Menu opens, with tabs for: **Dashboard**, **Stock**, **Orders**, **Sales**, **Vehicle Listing**, **Coupons**.

***

#### Dashboard

Displays a real-time overview:

* **Account Balance** – money in the dealership's safe.
* **Vehicles in Stock** – total units across all models.
* **Listed Vehicles** – number of active showcase listings.
* **Total Sales** – revenue broken down by Day / Week / Month / Year.

***

#### Stock Management & Ordering

Navigate to the **Stock** tab:

* All vehicles in your dealership's catalog are listed with their current stock levels.
* For each vehicle you can:
  * **Edit Price** – set your own selling price (independent of the catalog base price).
  * **Order Vehicle** – place a restock order (see below).
  * **Set Discount** – configure a time-limited sale.
  * **Remove Discount** – cancel an active discount.

***

#### Order Delivery Mission

When `RealisticOrder = true` (default):

1. In the **Stock** tab, click **Order Vehicle** for the model you want.
2. Enter the **quantity** and confirm. The order cost is deducted from your **bank** immediately.
3. You receive a notification when the delivery truck has arrived.
4. Travel to the **truck blip** on your map. Get into the **Phantom** truck.
5. A new blip directs you to the **docks** to pick up the trailer – drive there and attach the trailer.
6. A final blip shows your **dealership's order point**. Drive the truck+trailer there.
7. Press **\[E]** at the delivery marker to complete the delivery.
8. The ordered vehicles are added to your stock automatically.

> Only **one active order** can be in progress at a time per dealership.

***

#### Vehicle Listings (Showcase)

The **Vehicle Listing** tab lets you place physical showcase vehicles in the world:

1. Click **Create Listing**.
2. Select the vehicle from your catalog.
3. Choose a colour.
4. The location selector opens in-world – aim at the ground where you want the car placed and confirm.
5. The vehicle spawns, frozen in place. Players who walk up to it see stats and price information.

Maximum listings per dealership: **`Config.MaxListings`** (default 5).

To remove a listing:

1. Open the **Vehicle Listing** tab.
2. Click **Delete Listing** next to the entry and confirm.

***

#### Discounts

1. Go to the **Stock** tab.
2. Click **Set Discount** on a vehicle.
3. Configure:
   * **Percentage %** – how much off (e.g. `20` = 20% discount)
   * **Duration (hours)** – how long the discount is active
   * **Usage Limit** – maximum times the discount can be applied before it expires
4. Click **Apply**. The discounted price is calculated automatically at checkout.
5. Click **Remove Discount** to end it early.

***

#### Coupons

1. Go to the **Coupons** tab.
2. Click **Create Coupon**.
3. Fill in:
   * **Code** – unique alphanumeric code players will type at checkout
   * **Percentage %** – discount value
   * **Duration (hours)** – expiry window
   * **Usage Limit** – max redemptions
4. Share the code with your customers. When a player redeems it, the usage count decrements.
5. Delete expired or unwanted coupons at any time.

***

#### Sales History

The **Sales** tab shows a chronological log of every vehicle sold:

| Column       | Description           |
| ------------ | --------------------- |
| Vehicle      | Model name            |
| Price        | Amount charged        |
| Payment Type | cash / bank / finance |
| Date         | Timestamp of the sale |

***

#### Treasury (Deposit / Withdraw)

The **Dashboard** tab contains the dealership's **Account Balance** with two actions:

* **Deposit** – move money from your bank into the dealership safe.
* **Withdraw** – move money from the dealership safe to your bank.

> Revenue from vehicle sales is automatically added to the dealership balance.\
> When customers pay installments, each payment also flows to the dealership balance.

***

### 📡 Exports API

These Lua exports are available to other resources:

```lua
-- Open the main shop UI for the closest dealership
exports["aty_dealershipv2"]:openDealership()

-- Open the player's installments dashboard
exports["aty_dealershipv2"]:openInstallments()

-- Returns a table of all shops (same structure as DB rows, decoded)
local shops = exports["aty_dealershipv2"]:getShops()

-- Returns data for a single shop by name
local shop = exports["aty_dealershipv2"]:getShopData("LuxuryCars")

-- Returns all active installments for the local player
local installments = exports["aty_dealershipv2"]:getPlayerInstallments()

-- Returns a single installment by its database ID
local inst = exports["aty_dealershipv2"]:getInstallmentById(5)

-- Returns the vehicle list (with stock > 0) for a shop
local vehicles = exports["aty_dealershipv2"]:getDealershipVehicles("LuxuryCars")
```

***

### 💻 Commands Reference

| Command            | Permission                             | Description                             |
| ------------------ | -------------------------------------- | --------------------------------------- |
| `/dealershipadmin` | Admin (`god` / `admin` / `superadmin`) | Opens the admin management panel        |
| `/directsale`      | —                                      | (Reserved / configurable)               |
| `/installments`    | Any player                             | Opens the installment payment dashboard |

Command names can be changed in `config.lua`:

```lua
Commands = {
    Admin       = "dealershipadmin",
    DirectSale  = "directsale",
    Installments = "installments",
},
```

***

### 📚 Catalog (`shared/catalog.lua`)

The catalog is a Lua table where each **key** is the vehicle's internal identifier:

```lua
Catalog = {
    ["adder"] = {
        name     = "Adder",           -- short display name
        label    = "Truffade",        -- manufacturer / brand
        model    = "adder",           -- GTA spawn model name
        price    = 1000000,           -- base purchase price in $
        category = "Super",           -- category string (used to filter per dealership)
    },
    -- ...
}
```

> The catalog file is written/saved by the admin panel. You can also edit it manually – just restart the resource afterwards.

***

### 🌐 Locale / Translations

Language strings are in **`shared/locale.lua`**. The active locale is set at the top:

```lua
Locale = 'en'
```

To add a new language, duplicate the `["en"]` block and change the key:

```lua
Locales = {
    ["en"] = { ... },
    ["tr"] = {
        ['no_vehicles_for_sale'] = "Bu galeride satılık araç yok",
        -- ... all keys
    }
}
```

Then set `Locale = 'tr'` at the top of the file.

***

### 📁 File Structure

```
aty_dealershipv2/
├── client/
│   └── client.lua          # All client-side logic (UI control, camera, preview, zones)
├── server/
│   ├── server.lua          # All server callbacks (purchasing, orders, installments, etc.)
│   └── admin.lua           # Admin commands, dealership CRUD, catalog management
├── shared/
│   ├── config.lua          # ⬅ Main configuration file
│   ├── catalog.lua         # Global vehicle catalog (read/written by admin panel)
│   └── locale.lua          # Localisation strings
├── web/                    # Vue 3 + Vite NUI source
│   └── src/
│       ├── components/     # ShopMenu, BossMenu, AdminMenu, Installments, Showcase…
│       ├── stores/         # Pinia state management
│       └── utils/          # fetchNui helper
├── ui/                     # Compiled NUI output (served by FiveM)
├── data.sql                # Fresh install database schema
├── update.sql              # Incremental migration for existing installs
└── fxmanifest.lua          # Resource manifest
```

***

### 🔧 Troubleshooting

#### Dealership NPC / Blip not appearing

* Ensure the resource started without errors (`server console`).
* Check that the database import was successful and at least one row exists in `aty_dealership`.
* Verify `aty_lib` is started **before** `aty_dealershipv2`.

#### UI opens but vehicles don't load

* The `shared/catalog.lua` may be empty or malformed. Check the file for syntax errors.
* Confirm the dealership has vehicles assigned (categories were selected when creating it).

#### "aty\_lib" not found error

* Ensure `aty_lib` is downloaded and listed in `server.cfg` before this resource.

#### Finance / installments not working

* Confirm the `vehicle_installments` table exists. Run `update.sql` if upgrading.
* Check `Config.PaymentInterval` is set correctly.

#### Order delivery mission doesn't trigger

* Ensure `Config.RealisticOrder = true`.
* Check that `OrderTruckModel` and `OrderTrailerModel` are valid GTA V model names on your server.
* Verify the `OrderPickupLocation` coordinates are reachable and not inside an interior.

#### Admin command not working

* Confirm the player's ESX grade / QBCore permission matches one of the `Config.AdminPermissions` values.
* Check the console for any errors when starting the resource.

***

### 📄 License

This resource is the intellectual property of **atiysu**. Redistribution, resale, or public release without explicit permission is prohibited. For support or licensing inquiries, contact the author directly.

***

> Made with ❤️ by **atiysu**
