# Configuration

```javascript
let Config = {};

Config.Framework = 'auto'; // auto, qbox, qb, esx, custom
Config.Phone = 'auto' // auto, npwd_qbx_mail, qb-phone, lb-phone, gksphone, yseries, jpr-phonesystem, roadphone, custom
Config.Inventory = 'auto' // auto, ox_inventory, qb-inventory, qs-inventory, core_inventory, tgiann-inventory, ps-inventory, custom
Config.Jail = 'auto' // auto, xt-prison, custom

Config.Command = 'doj'; // Command for opening the main UI
Config.Keybind = { // Keymap for opening the UI
    enabled: true,
    key: 'j' // Default key. Can be changed by each player
};

Config.Menus = { // Menu locations
    citizen: {
        coords: [-545.41, -203.76, 37.22], // Coordinates, seperated by a comma
        radius: 2, // The radius from which the menu is accessible
        keybind: 38, // The control ID which should open the menu: https://docs.fivem.net/docs/game-references/controls/#controls,
        ped: {
            enabled: true,
            model: 'a_m_y_business_03',
            heading: 215.0
        }
    },
    lawyer: {
        coords: [-516.57, -210.99, 37.17],
        radius: 2,
        keybind: 38,
        ped: {
            enabled: true,
            model: 'cs_solomon',
            heading: 118.24
        }
    },
};

Config.Job = { // DOJ Job options. Everything here should match your framework job configuration
    name: 'doj',
    grades: [ // All grade levels, starting from 0
        {
            role: 'lawyer',
            isChiefJudge: false // Whether the grade has access to the 'requests' menu and can edit every case. Also has access to framework-specific features like bossmenu.
        },
        {
            role: 'prosecutor',
            isChiefJudge: false // Whether the grade has access to the 'requests' menu and can edit every case. Also has access to framework-specific features like bossmenu.
        },
        {
            role: 'judge',
            isChiefJudge: false // Whether the grade has access to the 'requests' menu and can edit every case. Also has access to framework-specific features like bossmenu.
        },
        {
            role: 'judge',
            isChiefJudge: true // Whether the grade has access to the 'requests' menu and can edit every case. Also has access to framework-specific features like bossmenu.
        },
    ],
}

Config.Fees = {
    fileCase: 100, // Set to 0 to remove fee
    losingParty: 500 // If a criminal case - the prosecutor or convicted. If a civilian case - the losing party.
}

// These are triggered immediately after the case is closed:
Config.AutoFine = true // Automatically fine the defendant of a criminal case if convicted (found guilty).
Config.AutoJail = true // Automatically send the player to jail if found guilty.
Config.AutoTransfer = true // Automatically transfer the settle amount of a civilian case from the losing party to the winning party.

Config.Evidence = {
    slots: 50,
    weight: 100000,
}

// #################################
//                                 #
//         PHONE INTEGRATION       # 
//                                 # 
// #################################

if (Config.Phone === 'auto') Config.Phone = detectPhone();

function detectPhone() {
    if (GetResourceState('qb-phone') === 'started') return 'qb-phone';
    if (GetResourceState('npwd_qbx_mail') === 'started') return 'npwd_qbx_mail';
    if (GetResourceState('lb-phone') === 'started') return 'lb-phone';
    if (GetResourceState('gksphone') === 'started') return 'gksphone';
    if (GetResourceState('yseries') === 'started') return 'yseries';
    if (GetResourceState('jpr-phonesystem') === 'started') return 'jpr-phonesystem';
    if (GetResourceState('roadphone') === 'started') return 'roadphone';
    return 'custom';
}

// These functions are triggered on the server
Config.SendMail = {
    'qb-phone': (cid, sender, subject, message) => {
        exports['qb-phone'].sendNewMailToOffline(cid, { sender, subject, message });
    },
    'npwd_qbx_mail': (cid, sender, subject, message) => {
        TriggerEvent('qb-phone:server:sendNewMailToOffline', cid, { sender, subject, message });
    },
    'lb-phone': (cid, sender, subject, message) => {
        const phoneNumber = exports["lb-phone"].GetEquippedPhoneNumber(cid);
        const email = exports["lb-phone"].GetEmailAddress(phoneNumber);
        exports["lb-phone"].SendMail({
            to: email,
            sender,
            subject,
            message
        })
    },
    'gksphone': (cid, sender, subject, message) => {
        exports["gksphone"].SendNewMailOffline(cid, {
            sender,
            subject,
            message
        });
    },
    'yseries': (cid, sender, subject, message) => {
        const phoneNumber = exports.yseries.GetPhoneNumberByIdentifier(cid);
        exports.yseries.SendMail({
            title: subject,
            sender,
            senderDisplayName: sender,
            content: message,
        }, 'phoneNumber', phoneNumber);
    },
    'jpr-phonesystem': (cid, sender, subject, message) => {
        exports['jpr-phonesystem'].sendNewMailToOffline(cid, {
            sender,
            subject,
            message,
            button: {}
        });
    },
    'roadphone': (cid, sender, subject, message) => {
        exports['roadphone'].sendMailOffline(cid, {
            sender,
            subject,
            message
        });
    },
    'custom': (cid, sender, subject, message) => {},
}

// #################################
//                                 #
//      INVENTORY INTEGRATION      #
//                                 #
// #################################

if (Config.Inventory === 'auto') Config.Inventory = detectInventory();

function detectInventory() {
    if (GetResourceState('ox_inventory') === 'started') return 'ox_inventory';
    if (GetResourceState('qb-inventory') === 'started') return 'qb-inventory';
    if (GetResourceState('qs-inventory') === 'started') return 'qs-inventory';
    if (GetResourceState('core_inventory') === 'started') return 'core_inventory';
    if (GetResourceState('codem-inventory') === 'started') return 'codem-inventory';
    if (GetResourceState('tgiann-inventory') === 'started') return 'tgiann-inventory';
    if (GetResourceState('ps-inventory') === 'started') return 'ps-inventory';
    return 'custom';
}

// These functions are triggered on the server
Config.OpenEvidence = {
    'ox_inventory': (src, caseId) => {
        const invId = `doj_evidence:${caseId}`;
        exports.ox_inventory.RegisterStash(invId, `D.O.J Evidence - Case #${caseId}`, Config.Evidence.slots, Config.Evidence.weight);
        exports.ox_inventory.forceOpenInventory(src, 'stash', invId);
    },
    'qb-inventory': (src, caseId) => {
        const invId = `doj_evidence:${caseId}`;
        exports['qb-inventory'].CreateInventory(invId, {
            label: `D.O.J Evidence - Case #${caseId}`,
            maxweight: Config.Evidence.weight,
            slots: Config.Evidence.slots
        });
        exports['qb-inventory'].OpenInventory(src, invId);
    },
    'qs-inventory': (src, caseId) => {
        const invId = `doj_evidence:${caseId}`;
        exports['qs-inventory'].RegisterStash(src, invId, Config.Evidence.slots, Config.Evidence.weight) 
    },
    'core_inventory': (src, caseId) => {
        const invId = `doj_evidence:${caseId}`;
        exports.core_inventory.openInventory(src, invId, 'stash', null, null, true, null, false);
    },
    'tgiann-inventory': (src, caseId) => {
        const invId = `doj_evidence:${caseId}`;
        exports["tgiann-inventory"].RegisterStash(invId, `D.O.J Evidence - Case #${caseId}`, Config.Evidence.slots, Config.Evidence.weight);
        exports["tgiann-inventory"].ForceOpenInventory(src, 'stash', invId);
    },
    'ps-inventory': (src, caseId) => {
        const invId = `doj_evidence:${caseId}`;
        exports['ps-inventory'].OpenInventory('stash', invId, {
            maxweight: Config.Evidence.weight,
            slots: Config.Evidence.slots
        }, src);
    },
}

// #################################
//                                 #
//         JAIL INTEGRATION        #
//                                 #
// #################################

if (Config.Jail === 'auto') Config.Jail = detectJail();

function detectJail() {
    if (GetResourceState('xt-prison') === 'started') return 'xt-prison';
    return 'custom';
}

Config.JailPlayer = {
    'xt-prison': (src, timeInMins) => {
        oxTriggerClientCallback('xt-prison:client:enterJail', src, timeInMins);
    },
    'custom': (src, timeInMins) => {}
}
```

<details>

<summary>Language configuration</summary>

```javascript
let Lang = {};

Lang.CommandSuggestion = 'Open the D.O.J management system';

Lang.Menus = {
    citizen: {
        main: {
            text_ui: '[E] - Open Citizens Menu',
            title: 'Citizens Menu',
            case_details: {
                title: 'View Case Details',
                description: 'Check your own case\'s status or search a public case'
            },
            schedule_appointment: {
                title: 'Schedule a Lawyer Appointment',
                description: 'Send a request for a meeting with your preferred lawyer'
            },
            file_case: {
                title: 'File a New Case',
                description: 'Open a new case against someone bad'
            },
        },
        case_details: {
            title: 'View Case Details',
            my_cases: {
                title: 'My Cases',
                description: 'View details about your current or past cases'
            },
            search_case: {
                title: 'Search Case',
                description: 'View details about a public case by case ID'
            }
        },
        my_cases: {
            title: 'My Cases (%s)',
            format: {
                title: 'Case #%s',
                description: 'Status: %s'
            }
        }
    },
    lawyer: {
        main: {
            text_ui: '[E] - Open Lawyers Menu',
            title: 'Lawyers Menu',
            appointments: {
                title: 'Appointment Requests',
                description: 'View and respond to requests for scheduled appointments.'
            }
        },
        appointments: {
            title: 'Appointment Requests (%s)',
            format: {
                title: '%s',
                description: 'Requested %s'
            }
        },
        appointment: {
            title: 'Appointment Request',
            reason: {
                title: 'Reason for the appointment',
                description: '%s'
            },
            meeting_time: {
                title: 'Preferred meeting time',
                description: '%s'
            },
            respond: {
                title: 'Respond',
                description: 'The person will receive an email and the request will be deleted'
            }
        }
    }
}

Lang.Inputs = {
    search_case: {
        title: 'Search Case',
        case_id_input: {
            title: 'Case ID',
            description: 'Enter the case ID without a #'
        }
    },
    schedule_appointment: {
        title: 'Schedule an Appointment',
        reason: {
            title: 'Reason',
            description: 'Enter the details and the reason for the appointment'
        },
        meeting_date: {
            title: 'Meeting Date',
            description: 'Choose your preferred meeting date',
        },
        meeting_time: {
            title: 'Meeting Time',
            description: 'Enter a convenient time for the appointment'
        },
        lawyer: {
            title: 'Lawyer',
            description: 'Select a lawyer you\'d like to schedule the meeting with'
        }
    },
    file_case: {
        title: 'File A Case',
        case_type: {
            title: 'Case Type',
            description: 'Choose a case type from the ones available',
            criminal: 'Criminal',
            civilian: 'Civilian'
        },
        defendant_cid: {
            title: 'Defendant\'s CID',
            description: 'Enter the other party\'s citizen ID'
        },
        complainant_cid: {
            title: 'Complainant\'s CID',
            description: 'Lawyers only - if you enter a value here, you will be automatically assigned to the case as the complainant\'s lawyer. Leave empty to file a case as a complainant.'
        },
        description: {
            title: 'Description',
            description: 'Describe your case or enter important details'
        }
    },
    respond_appointment: {
        title: 'Respond to an Appointment',
        reply: {
            title: 'Reply',
            description: 'Enter details about the appointment, such as final meeting time'
        }
    }
}

Lang.Errors = {
    operation_failed: 'Operation failed: Internal server error',
    no_data: 'No data returned!',
    invalid_id: 'Invalid Case ID!',
    invalid_fields: 'One or more fields are invalid!',
    invalid_appointment_date: 'You can\'t schedule an appointment in the past!',
    no_permission: 'You are not authorized for this!',
    invalid_cid: {
        basic: 'Citizen ID is invalid or not found!',
        format: '%s citizen ID invalid or not found!',
        defendant: 'Defendant',
        complainant: 'Complainant',
    },
    no_self_case: 'You can\'t open a case against yourself!',
    no_available_lawyers: 'There are no available lawyers at this time.',
    already_scheduled: 'You already have a scheduled appointment with this lawyer!',
    no_self_appointment: 'You can\'t schedule an appointment with yourself!',
    case_not_found: 'Case not found!',
    appointment_not_found: 'Appointment not found!',
    judge_not_found: 'Judge not found!',
    person_already_present: 'The person you\'re trying to add is already part of the case!',
    no_complainant_lawyer: 'You can\'t add a complainant\'s lawyer to this case!',
    person_not_found: 'The person you\'re trying to remove does not exist!',
    verdict_not_found: 'Verdict not found!',
    decision_not_found: 'Decision not found!',
    mails_not_sent: 'Mails could not be sent due to case information not present.'
}

Lang.Messages = {
    case_created: {
        title: 'Successfully filed a new case.',
        description: 'ID: %s'
    },
    appointment_created: {
        title: 'Successfully created an appointment request!',
        description: 'Expect an email response from the lawyer.'
    },
    no_cases: 'You don\'t have any cases.',
    no_appointments: 'You don\'t have any active appointment requests.',
    responded_appointment: 'Successfully responded to the appointment!',
}

Lang.Dialogs = {
    file_case_confirm: {
        title: 'Are you sure?',
        description: 'There is a fee of **$%s** for filing cases.',
        confirm: 'File Case - $%s'
    }
}

Lang.FeeReasons = {
    fileCase: 'Filing a DOJ case',
    losingParty: 'Lost a DOJ case',
    convictionFine: 'Conviction fine',
    settleAmount: 'Settle amount from a DOJ case'
}

Lang.Mails = {
    sender: 'DOJ Delivery System',
    new_appointment: {
        subject: 'New Scheduled Appointment Request From <strong>%s</strong>',
        message: 'You have a new request for an appointment. Here are the details:<br/>Name: <strong>%s</strong><br/>Date & Time: <strong>%s</strong><br/>Reason: <strong>%s</strong><br/>You can respond to the request via the menu.'
    },
    appointment_reply: {
        subject: 'Re: Scheduled appointment request',
        message: 'You are receiving this email because you\'ve recently scheduled an appointment with the lawyer <strong>%s</strong>. Here is their response:<br/><br/><strong>%s</strong><br/><br/>Thank you for using our services.'
    },
    case_created_defendant: {
        subject: 'New case against you has been filed',
        message: 'You are receiving this email because a case against you has been filed. Here are the details:<br/>Case ID: <strong>#%s</strong><br/>Complainant: <strong>%s</strong><br/>Details: <br/><br/><strong>%s</strong><br/><br/>Please note, you will receive an additional email when the case gets approved or rejected. No further action from you is required at this time.',
        prosecutor: '[Prosecutor]'
    },
    case_created_complainant: {
        subject: 'New case by %s has been filed',
        message: 'You are receiving this email because your lawyer has filed a case on your behalf. Here are the details:<br/>Case ID: <strong>#%s</strong><br/>Complainant: <strong>%s</strong><br/>Defendant: <strong>%s</strong><br/>Details: <br/><br/><strong>%s</strong><br/><br/>Please note, you will receive an additional email when the case gets approved or rejected. No further action from you is required at this time.'
    },
    case_approved: {
        subject: 'Case #%s has been approved',
        message: 'You are receiving this email because a case you are a part of has been approved. Expect another email stating the next court session date.'
    },
    case_rejected: {
        subject: 'Case #%s has been rejected',
        message: 'We are informing you that a case you are a part of has been rejected. No further action from you is required.'
    },
    case_assigned: {
        subject: 'You have been assigned to case #%s',
        message: 'Here are the details:<br/>Case ID: <strong>#%s</strong><br/>Type: <strong>%s</strong><br/>Complainant: <strong>%s</strong><br/>Complainant\'s Lawyer: <strong>%s</strong><br/>Defendant: <strong>%s</strong><br/>Details: <br/><br/><strong>%s</strong><br/><br/>You have been assigned by Chief Judge <strong>%s</strong>'
    },
    added_to_case: {
        subject: 'You have been added to case #%s',
        message: 'You are receiving this email because the judge of a case has added you to it.<br/>Your role is: <strong>%s</strong>',
        defendantLawyer: 'Defendant\'s Lawyer',
        complainantLawyer: 'Complainant\'s Lawyer',
        witness: 'Witness'
    },
    next_session_changed: {
        subject: 'Next session for case #%s',
        message: 'The next court session has been scheduled for:<br/><strong>%s</strong><br/>Please make sure you attend the court on this date.'
    },
    next_session_canceled: {
        subject: 'Session for case #%s canceled',
        message: 'The court session that was previously scheduled for <strong>%s</strong> has been canceled. Please expect a new email about the next session. No further action from you is required at this time.'
    }
}
```

</details>


---

# Agent Instructions: 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://docs.bkscripts.com/scripts/bk_doj/configuration.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.
