Store

Installation

How to install and set up legacy-billing

Dependencies#

ResourcePurpose
ox_libCallbacks, notifications, UI utilities
oxmysqlDatabase operations
legacy-libFramework abstraction (QBCore, ESX, etc.)

All dependencies must be started before legacy-billing in your server.cfg.

Database Setup#

Run the following SQL in your database. This creates all required tables and seeds default billing jobs (police, ambulance, mechanic).

Warning: The schema contains DROP TABLE statements. If you have existing data, remove those lines before importing.

DROP TABLE IF EXISTS `legacy_bill_payments`;
DROP TABLE IF EXISTS `legacy_bill_disputes`;
DROP TABLE IF EXISTS `legacy_bills`;
DROP TABLE IF EXISTS `legacy_bill_templates`;
DROP TABLE IF EXISTS `legacy_billing_jobs`;

CREATE TABLE `legacy_billing_jobs` (
    `id` INT AUTO_INCREMENT PRIMARY KEY,
    `job_name` VARCHAR(60) NOT NULL UNIQUE,
    `job_label` VARCHAR(100) NOT NULL,
    `can_bill` TINYINT(1) DEFAULT 1,
    `late_fee_pct` DECIMAL(5,2) DEFAULT 0.00,
    `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX `idx_job_name` (`job_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `legacy_bills` (
    `id` INT AUTO_INCREMENT PRIMARY KEY,
    `sender_id` VARCHAR(60) NOT NULL,
    `sender_name` VARCHAR(100) NOT NULL,
    `sender_job` VARCHAR(60) NOT NULL,
    `sender_job_label` VARCHAR(100) NOT NULL,
    `target_id` VARCHAR(60) NOT NULL,
    `target_name` VARCHAR(100) NOT NULL,
    `amount` INT NOT NULL,
    `amount_paid` INT DEFAULT 0,
    `description` VARCHAR(500) NOT NULL,
    `status` VARCHAR(20) DEFAULT 'unpaid',
    `due_date` TIMESTAMP NULL DEFAULT NULL,
    `late_fee_applied` TINYINT(1) DEFAULT 0,
    `late_fee_amount` INT DEFAULT 0,
    `metadata` JSON DEFAULT ('{}'),
    `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    `updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `paid_at` TIMESTAMP NULL DEFAULT NULL,
    `cancelled_at` TIMESTAMP NULL DEFAULT NULL,
    INDEX `idx_target_id` (`target_id`),
    INDEX `idx_sender_id` (`sender_id`),
    INDEX `idx_sender_job` (`sender_job`),
    INDEX `idx_status` (`status`),
    INDEX `idx_due_date` (`due_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `legacy_bill_payments` (
    `id` INT AUTO_INCREMENT PRIMARY KEY,
    `bill_id` INT NOT NULL,
    `payer_id` VARCHAR(60) NOT NULL,
    `amount` INT NOT NULL,
    `method` VARCHAR(20) NOT NULL,
    `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX `idx_bill_id` (`bill_id`),
    FOREIGN KEY (`bill_id`) REFERENCES `legacy_bills`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `legacy_bill_disputes` (
    `id` INT AUTO_INCREMENT PRIMARY KEY,
    `bill_id` INT NOT NULL,
    `disputer_id` VARCHAR(60) NOT NULL,
    `disputer_name` VARCHAR(100) NOT NULL,
    `reason` VARCHAR(500) NOT NULL,
    `status` VARCHAR(20) DEFAULT 'open',
    `resolved_by` VARCHAR(60) DEFAULT NULL,
    `resolved_by_name` VARCHAR(100) DEFAULT NULL,
    `resolution` VARCHAR(500) DEFAULT NULL,
    `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    `resolved_at` TIMESTAMP NULL DEFAULT NULL,
    INDEX `idx_bill_id` (`bill_id`),
    FOREIGN KEY (`bill_id`) REFERENCES `legacy_bills`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `legacy_bill_templates` (
    `id` INT AUTO_INCREMENT PRIMARY KEY,
    `job_name` VARCHAR(60) NOT NULL,
    `name` VARCHAR(100) NOT NULL,
    `amount` INT NOT NULL,
    `description` VARCHAR(500) NOT NULL,
    `created_by` VARCHAR(60) NOT NULL,
    `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX `idx_job_name` (`job_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT INTO `legacy_billing_jobs` (`job_name`, `job_label`, `late_fee_pct`) VALUES
('police', 'Police Department', 5.00),
('ambulance', 'Emergency Medical Services', 0.00),
('mechanic', 'Mechanic', 0.00);

server.cfg#

Add the following to your server.cfg, ensuring the dependencies are started first:

ensure legacy-lib
ensure ox_lib
ensure oxmysql
ensure legacy-billing