> For the complete documentation index, see [llms.txt](https://prfortiq.gitbook.io/wolfstudio/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://prfortiq.gitbook.io/wolfstudio/fivem/ws-advanced-shopsystem.md).

# WS Advanced Shopsystem

<figure><img src="/files/C8MCApYu94h8juO5t9Dd" alt=""><figcaption></figcaption></figure>

***

Thanks for your patience, Wolfstudio fam! After two months of waiting, we’re back with fresh news: the Advanced Shop System is ready with a full economy and shop framework in our signature style.

**Advanced Shop System – Complete economy & shop framework (Wolfstudio style)**

* **Modern NUI:** Dark glass look with clear categories, product cards, cart, and management area.
* **Shop Creator:** As an admin, you can use the Shop Creator panel to position and manage your entire shop yourself.
* **Player shops:** Buy, sell, manage; adjust prices & discounts live; track stock and finances.
* Deliveries & vehicles: Plan orders, role-based drivers, vehicle unlocks by level, scalable capacity and costs.
* **XP & levels:** Sales/deliveries grant XP; levels unlock discounts, features, vehicles, and credit lines.
* **Staff management:** Roles (Owner/Manager/Driver/Cashier) with permissions, wages, status, hire/fire in-panel.
* **Dynamic inventory:** Categories, icons, prices, min-level, discounts per item; data from DB/panel instead of hardcoding.
* **Notifications:** Optional qb-phone mails (low stock, auto-orders, payroll).
* Caching & performance: Server cache for shops/inventory; only needed data is loaded.
* **Configurable:** Framework (QB/QBX/ESX), accounts, target/keybinds, depots, delivery logic, abilities, icons. Security: ACE/framework permissions for admin/owner actions, validation on imports/updates.
* **Expansion:** Many more expansions will be added in the future, such as orders for the truck-job and Uber delivery.

***

## Requirements

Compatible with Fremdcore: ESX, Qbcore and Qbox

***

## Installation

1. **Copy the Resource**

Place the `ws-shopsystem` folder in `resources/` (or your preferred resource folder).<br>

2. **Import the SQL**

Run the file `sql/ws_shopsystem.sql` in your database (e.g., via phpMyAdmin or the `mysql` CLI).:<br>

```sql
CREATE TABLE IF NOT EXISTS `ws_shops` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `identifier` VARCHAR(64) NOT NULL,
    `label` VARCHAR(120) NOT NULL,
    `type` VARCHAR(60) NOT NULL,
    `coords` LONGTEXT DEFAULT NULL,
    `heading` FLOAT DEFAULT 0,
    `level` INT(11) NOT NULL DEFAULT 1,
    `xp` INT(11) NOT NULL DEFAULT 0,
    `owner_citizenid` VARCHAR(50) DEFAULT NULL,
    `owner_name` VARCHAR(120) DEFAULT NULL,
    `balance` INT(11) NOT NULL DEFAULT 0,
    `purchase_price` INT(11) NOT NULL DEFAULT 0,
    `sell_price` INT(11) NOT NULL DEFAULT 0,
    `discount` INT(11) NOT NULL DEFAULT 0,
    `webhook` TEXT DEFAULT NULL,
    `metadata` LONGTEXT DEFAULT NULL,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE KEY `identifier` (`identifier`)
);

CREATE TABLE IF NOT EXISTS `ws_shop_inventory` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `shop_id` INT(11) NOT NULL,
    `item` VARCHAR(60) NOT NULL,
    `label` VARCHAR(120) NOT NULL,
    `icon` VARCHAR(120) DEFAULT NULL,
    `category` VARCHAR(60) NOT NULL,
    `quantity` INT(11) NOT NULL DEFAULT 0,
    `base_price` INT(11) NOT NULL DEFAULT 0,
    `override_price` INT(11) DEFAULT NULL,
    `discount` INT(11) NOT NULL DEFAULT 0,
    `min_level` INT(11) NOT NULL DEFAULT 1,
    `metadata` LONGTEXT DEFAULT NULL,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `shop_item` (`shop_id`, `item`),
    CONSTRAINT `fk_inventory_shop` FOREIGN KEY (`shop_id`) REFERENCES `ws_shops` (`id`) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS `ws_shop_employees` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `shop_id` INT(11) NOT NULL,
    `citizenid` VARCHAR(50) NOT NULL,
    `name` VARCHAR(120) NOT NULL,
    `role` VARCHAR(32) NOT NULL,
    `wage` INT(11) NOT NULL DEFAULT 0,
    `status` ENUM('active','vacation','terminated') NOT NULL DEFAULT 'active',
    `last_activity` DATETIME DEFAULT CURRENT_TIMESTAMP,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE KEY `shop_employee_unique` (`shop_id`, `citizenid`),
    CONSTRAINT `fk_employee_shop` FOREIGN KEY (`shop_id`) REFERENCES `ws_shops` (`id`) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS `ws_shop_finance_log` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `shop_id` INT(11) NOT NULL,
    `type` VARCHAR(60) NOT NULL,
    `amount` INT(11) NOT NULL,
    `balance_after` INT(11) NOT NULL,
    `description` VARCHAR(255) DEFAULT NULL,
    `payload` LONGTEXT DEFAULT NULL,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `shop_finance_idx` (`shop_id`,`type`),
    CONSTRAINT `fk_finance_shop` FOREIGN KEY (`shop_id`) REFERENCES `ws_shops` (`id`) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS `ws_shop_deliveries` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `shop_id` INT(11) NOT NULL,
    `identifier` VARCHAR(64) NOT NULL,
    `type` VARCHAR(32) NOT NULL DEFAULT 'manual',
    `status` VARCHAR(32) NOT NULL DEFAULT 'pending',
    `citizenid` VARCHAR(50) DEFAULT NULL,
    `vehicle_model` VARCHAR(60) DEFAULT NULL,
    `vehicle_plate` VARCHAR(12) DEFAULT NULL,
    `capacity` INT(11) NOT NULL DEFAULT 0,
    `distance` FLOAT DEFAULT 0,
    `payout` INT(11) DEFAULT 0,
    `penalty` INT(11) DEFAULT 0,
    `metadata` LONGTEXT DEFAULT NULL,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
    `finished_at` TIMESTAMP NULL DEFAULT NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `delivery_identifier` (`identifier`),
    KEY `shop_delivery_idx` (`shop_id`,`status`),
    CONSTRAINT `fk_delivery_shop` FOREIGN KEY (`shop_id`) REFERENCES `ws_shops` (`id`) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS `ws_shop_delivery_items` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `delivery_id` INT(11) NOT NULL,
    `item` VARCHAR(60) NOT NULL,
    `label` VARCHAR(120) NOT NULL,
    `quantity` INT(11) NOT NULL DEFAULT 0,
    PRIMARY KEY (`id`),
    KEY `delivery_item` (`delivery_id`),
    CONSTRAINT `fk_delivery_items_delivery` FOREIGN KEY (`delivery_id`) REFERENCES `ws_shop_deliveries` (`id`) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS `ws_shop_vehicles` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `shop_id` INT(11) NOT NULL,
    `model` VARCHAR(60) NOT NULL,
    `plate` VARCHAR(12) NOT NULL,
    `base_capacity` INT(11) NOT NULL DEFAULT 0,
    `upgrades` LONGTEXT DEFAULT NULL,
    `level` INT(11) NOT NULL DEFAULT 1,
    `stored` TINYINT(1) NOT NULL DEFAULT 1,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE KEY `plate_unique` (`plate`),
    CONSTRAINT `fk_vehicle_shop` FOREIGN KEY (`shop_id`) REFERENCES `ws_shops` (`id`) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS `ws_shop_statistics_daily` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `shop_id` INT(11) NOT NULL,
    `stat_date` DATE NOT NULL,
    `sales_total` INT(11) NOT NULL DEFAULT 0,
    `sales_count` INT(11) NOT NULL DEFAULT 0,
    `deliveries_completed` INT(11) NOT NULL DEFAULT 0,
    `deliveries_failed` INT(11) NOT NULL DEFAULT 0,
    `employees_active` INT(11) NOT NULL DEFAULT 0,
    `xp_earned` INT(11) NOT NULL DEFAULT 0,
    `updated_at` TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE KEY `shop_day_unique` (`shop_id`,`stat_date`),
    CONSTRAINT `fk_statistics_shop` FOREIGN KEY (`shop_id`) REFERENCES `ws_shops` (`id`) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS `ws_shop_abilities` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `shop_id` INT(11) NOT NULL,
    `ability` VARCHAR(32) NOT NULL,
    `level` INT(11) NOT NULL DEFAULT 0,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE KEY `shop_ability_unique` (`shop_id`, `ability`),
    CONSTRAINT `fk_shop_ability_shop` FOREIGN KEY (`shop_id`) REFERENCES `ws_shops` (`id`) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS `ws_shop_dropoffs` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `shop_id` INT(11) NOT NULL,
    `sort_index` INT(11) NOT NULL DEFAULT 1,
    `label` VARCHAR(120) DEFAULT NULL,
    `x` FLOAT NOT NULL DEFAULT 0,
    `y` FLOAT NOT NULL DEFAULT 0,
    `z` FLOAT NOT NULL DEFAULT 0,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `shop_dropoff_idx` (`shop_id`),
    CONSTRAINT `fk_dropoff_shop` FOREIGN KEY (`shop_id`) REFERENCES `ws_shops` (`id`) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS `ws_shop_depots` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `shop_id` INT(11) NOT NULL,
    `sort_index` INT(11) NOT NULL DEFAULT 1,
    `label` VARCHAR(120) DEFAULT NULL,
    `x` FLOAT NOT NULL DEFAULT 0,
    `y` FLOAT NOT NULL DEFAULT 0,
    `z` FLOAT NOT NULL DEFAULT 0,
    `heading` FLOAT NOT NULL DEFAULT 0,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `shop_depot_idx` (`shop_id`),
    CONSTRAINT `fk_depot_shop` FOREIGN KEY (`shop_id`) REFERENCES `ws_shops` (`id`) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS `ws_shop_vehicle_spawns` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `shop_id` INT(11) NOT NULL,
    `sort_index` INT(11) NOT NULL DEFAULT 1,
    `label` VARCHAR(120) DEFAULT NULL,
    `x` FLOAT NOT NULL DEFAULT 0,
    `y` FLOAT NOT NULL DEFAULT 0,
    `z` FLOAT NOT NULL DEFAULT 0,
    `heading` FLOAT NOT NULL DEFAULT 0,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `shop_spawn_idx` (`shop_id`),
    CONSTRAINT `fk_spawn_shop` FOREIGN KEY (`shop_id`) REFERENCES `ws_shops` (`id`) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS `ws_shop_routes` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `shop_id` INT(11) NOT NULL,
    `sort_index` INT(11) NOT NULL DEFAULT 1,
    `label` VARCHAR(120) DEFAULT NULL,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `shop_route_idx` (`shop_id`),
    CONSTRAINT `fk_route_shop` FOREIGN KEY (`shop_id`) REFERENCES `ws_shops` (`id`) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS `ws_shop_route_points` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `route_id` INT(11) NOT NULL,
    `sort_index` INT(11) NOT NULL DEFAULT 1,
    `label` VARCHAR(120) DEFAULT NULL,
    `x` FLOAT NOT NULL DEFAULT 0,
    `y` FLOAT NOT NULL DEFAULT 0,
    `z` FLOAT NOT NULL DEFAULT 0,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `route_point_idx` (`route_id`),
    CONSTRAINT `fk_route_point_route` FOREIGN KEY (`route_id`) REFERENCES `ws_shop_routes` (`id`) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS `ws_shop_allowed_vehicles` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `shop_id` INT(11) NOT NULL,
    `sort_index` INT(11) NOT NULL DEFAULT 1,
    `vehicle_key` VARCHAR(60) NOT NULL,
    `model` VARCHAR(60) NOT NULL,
    `label` VARCHAR(120) NOT NULL,
    `price` INT(11) NOT NULL DEFAULT 0,
    `min_level` INT(11) NOT NULL DEFAULT 1,
    `capacity` INT(11) NOT NULL DEFAULT 0,
    `trunk_size` INT(11) NOT NULL DEFAULT 0,
    `fuel_modifier` FLOAT NOT NULL DEFAULT 1,
    `ability_level` INT(11) NOT NULL DEFAULT 1,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `shop_vehicle_idx` (`shop_id`),
    CONSTRAINT `fk_allowed_vehicle_shop` FOREIGN KEY (`shop_id`) REFERENCES `ws_shops` (`id`) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS `ws_shop_product_categories` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `shop_id` INT(11) NOT NULL,
    `sort_index` INT(11) NOT NULL DEFAULT 1,
    `category` VARCHAR(120) NOT NULL,
    `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `shop_category_idx` (`shop_id`),
    CONSTRAINT `fk_category_shop` FOREIGN KEY (`shop_id`) REFERENCES `ws_shops` (`id`) ON DELETE CASCADE
);
```

<br>

3. **Start the Resource**

Add the following line to your `server.cfg`:

```

ensure ws-shopsystem

```

4. **Restart the Server**

After restarting, you can create and manage all shops directly via the admin panel; the configuration no longer needs to contain any shop data.<br>

***

## Configuration

* **General (`WSShopConfig`)**: Language (`Locale` = `en`/`de`), target mode (`UseTarget`), low-stock thresholds, notifications, commands. `InteractionKey` and `ManagementKey` serve as fallback controls if `qb-target` is not used.
* **XP / Level (`WSShopConfig.XP`, `WSShopConfig.Levels`)**: Experience per action, unlockable features, vehicles, discounts.
* **Roles (`WSShopConfig.Roles`)**: Permissions, default wages, access to menu items.
* **Shop Types (`WSShopConfig.ShopTypes`)**: Items, prices, icons, buy/sell prices.
* **Shops**: are created exclusively via the admin panel and are stored directly in the database (no more configuration entries).
* **Depots (`WSShopConfig.Depots`)**: Predefined delivery locations, e.g., as default values ​​if needed in the admin panel.
* **Vehicles**: Managed exclusively in the admin panel and stored in the database – no further entry in `config.lua` is necessary.
* **Notifications (`WSShopConfig.Notifications`)**: Email texts, webhook settings.
* **Admin Access**: Uses your existing server permissions (ACE/QBCore/QBX). Ensure you have the appropriate group in `server.cfg`/`permissions.cfg` (e.g., `group.admin`/`admin`/`god`) to access the admin panel.

> **Note:** All umlauts have been defined as ASCII characters (e.g., `ae`, `oe`) to prevent issues with ANSI encoding. Adjust texts as needed.

***

## In-game process

#### Buy a Shop

1. Go to a shop (via Blip or Target).
2. Use the Target circle (`Open Shop`). If `qb-target` is not active, you can open the shop at any time with `InteractionKey` (default `E`) and access the administration with `ManagementKey` (default `G`).
3. If no owner is listed, you can buy the shop (price from `config.lua`).
4. After purchase, all administration functions are available.

#### Administration (Boss Menu)

* Open the shop → click on "Administration" (Owner/Manager role required).
* Tabs: `Dashboard`, `Inventory`, `Employees`, `Deliveries`, `Finance`, `Vehicles`.
* Adjust prices, hire/fire employees, arrange deliveries, and manage deposits/withdrawals.

#### Delivery Missions

1. Create a manual order in the "Deliveries" tab or wait for an automatic one when stock is low.
2. Drivers (with the role `driver` or higher) start the mission via the menu.
3. Pick up at the depot → marker `E` → load goods (blip is set).
4. Drive to the shop → marker `E` → unload.
5. Stock increases, finances/XP are recorded.
6. Cancellation or failure triggers penalties (`DeliveryFailurePenalty`).

#### Notifications

* Emails via `qb-phone` for low stock, automatic orders, or salary payments.
* Optional: Enable Discord webhooks via `WSShopConfig.Notifications.webhook`.

***

### Commands & Permissions

* `/shopadmin` – Admin overview; ensure you have admin ACE/group (QB/ESX/QBX).

***

## Troubleshooting

| Problem                | Solution                                                          |
| ---------------------- | ----------------------------------------------------------------- |
| SQL error on start     | Import `sql/ws_shopsystem.sql`                                    |
| No target interaction  | Check `qb-target` and `UseTarget` in `config.lua`                 |
| Mails missing          | Verify `qb-phone` API (`:server:sendNewMail`) and `PhoneResource` |
| Missing icons          | Ensure your `.png`/`.svg` icons are in `html/icons/`              |
| No items in shops      | Restart after config changes; inventory syncs automatically       |
| Deliveries won't start | Set role (`driver/manager/owner`); verify vehicle model/plate     |

***

## Recommended Addons

* Persistent vehicle storage (`ws_shop_vehicles` table).
* Stats tab with charts (`ws_shop_statistics_daily`).
* Additional shop types/items.
* Webhooks for high-level shops.

***

## Info:

Our scripts are available exclusively on tebex. All other third-party providers are considered leaks and therefore violate our terms of use and intellectual property rights.

If you discover that our scripts are found on third-party websites such as vag.gg, Launcher-Leaks, or other shopping systems that have nothing to do with fivem and cfx.re, please report them urgently via Discord. The third-party provider will face appropriate consequences.

It is also not permitted to download, purchase, upload, sell, or use third-party scripts. This can have consequences for both users and server owners.

If our scripts contain errors or you need help, you can also report them via our Discord.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://prfortiq.gitbook.io/wolfstudio/fivem/ws-advanced-shopsystem.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
