> For the complete documentation index, see [llms.txt](https://docs.realcity.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.realcity.dev/script-docs/rc-billing/configuracion.md).

# Configuración

## Referencia de configuración

Toda la configuración pública está en `config.lua`. El archivo se comparte entre cliente y servidor, por lo que no debes guardar secretos en él. Un webhook configurado aquí puede formar parte de los datos enviados al cliente por el sistema de recursos; utiliza una configuración privada de servidor si amplías el producto para manejar secretos.

### Resumen

| Opción                                 | Tipo           | Valor incluido        | Finalidad                   |
| -------------------------------------- | -------------- | --------------------- | --------------------------- |
| `Config.Locale`                        | `string`       | `'es'`                | Idioma predeterminado.      |
| `Config.AllowPersonalInvoices`         | `boolean`      | `true`                | Activa facturas personales. |
| `Config.CreateInvoicePermission`       | `string`       | `'rc-billing.create'` | ACE de creación personal.   |
| `Config.RequireAceForPersonalInvoices` | `boolean`      | `false`               | Obliga a comprobar el ACE.  |
| `Config.AdminAcePermission`            | `string`       | `'rc-billing.admin'`  | ACE administrativo.         |
| `Config.CompanyJobs`                   | `table`        | Ejemplos incluidos    | Empresas autorizadas.       |
| `Config.DefaultSocietyAccountPrefix`   | `string`       | `'society_'`          | Prefijo de cuentas.         |
| `Config.MaxInvoiceAmount`              | `number`       | `1000000`             | Máximo global por factura.  |
| `Config.HighValueInvoiceAmount`        | `number`       | `50000`               | Umbral de auditoría.        |
| `Config.InvoiceCategories`             | `table`        | 7 categorías          | Opciones de clasificación.  |
| `Config.DefaultDueDays`                | `number`       | `7`                   | Vencimiento predeterminado. |
| `Config.DuplicateWindowMinutes`        | `number`       | `5`                   | Ventana anti duplicados.    |
| `Config.DefaultCommission`             | `table`        | 10 %                  | Comisión empresarial base.  |
| `Config.PaymentAccount`                | `string`       | `'bank'`              | Cuenta del pagador.         |
| `Config.AllowPartialPayments`          | `boolean`      | `true`                | Permite abonos parciales.   |
| `Config.AllowPayAll`                   | `boolean`      | `true`                | Permite pagar todas.        |
| `Config.AuditLogs`                     | `boolean`      | `true`                | Auditoría SQL.              |
| `Config.DiscordWebhook`                | `string`       | `''`                  | Webhook opcional.           |
| `Config.OpenInvoiceCommand`            | `string`       | `'openinvoice'`       | Comando de facturas.        |
| `Config.OpenInvoiceKey`                | `string/false` | `'F6'`                | Keybind de facturas.        |
| `Config.OpenPosCommand`                | `string`       | `'openpos'`           | Comando POS.                |
| `Config.OpenPosKey`                    | `string/false` | `'F7'`                | Keybind POS.                |
| `Config.UseFrameworkPlayerNames`       | `boolean`      | `true`                | Usa nombre de personaje.    |
| `Config.DefaultMugshotUrl`             | `string`       | URL                   | Avatar de respaldo.         |

### Idioma

```lua
Config.Locale = 'es'
```

Se incluyen `es` y `en`. Hay dos grupos de traducciones:

* `locales/*.json`: textos Lua procesados por `ox_lib`.
* `web/src/locales/*.json`: textos fuente de la NUI.
* `web/public/*.json`: traducciones compiladas que FiveM sirve realmente.

Después de modificar traducciones web ejecuta `npm run build` dentro de `web`.

### Facturas personales y ACE

```lua
Config.AllowPersonalInvoices = true
Config.CreateInvoicePermission = 'rc-billing.create'
Config.RequireAceForPersonalInvoices = false
Config.AdminAcePermission = 'rc-billing.admin'
```

Comportamiento:

| AllowPersonal | RequireAce | Resultado                              |
| ------------- | ---------- | -------------------------------------- |
| `false`       | Cualquiera | Facturación personal desactivada.      |
| `true`        | `false`    | Todos los jugadores pueden crearla.    |
| `true`        | `true`     | Solo jugadores con el ACE configurado. |

`AdminAcePermission` protege las funciones administrativas del servidor. No uses un permiso genérico concedido a jugadores normales.

### Depuración

```lua
Config.Debug = {
    enabled = false,
    payments = true,
    invoices = true,
    nui = true
}
```

`enabled` es el interruptor global. Los otros campos activan o silencian áreas concretas. Déjalo en `false` en producción salvo durante una investigación: los logs pueden incluir importes, IDs de factura e identificadores internos.

### Empresas

Cada clave debe coincidir exactamente con el nombre interno del trabajo del framework:

```lua
Config.CompanyJobs = {
    ['mechanic'] = {
        label = 'Benny\'s Motorworks',
        minRank = 1,
        bossRank = 3,
        account = 'society_mechanic',
        logo = 'https://example.com/mechanic.png',
        maxInvoiceAmount = 50000,
        commission = {
            enabled = true,
            percent = 8,
            max = 2500
        },
        rankLimits = {
            [1] = 5000,
            [2] = 15000,
            [3] = 50000
        },
        templates = {
            {
                label = 'Revisión básica',
                description = 'Revisión mecánica básica',
                amount = 750,
                category = 'repair'
            }
        }
    }
}
```

#### Campos de empresa

| Campo              | Obligatorio | Descripción                            |
| ------------------ | ----------- | -------------------------------------- |
| `label`            | Sí          | Nombre mostrado en UI y recibos.       |
| `minRank`          | Sí          | Grado numérico mínimo para facturar.   |
| `bossRank`         | Sí          | Grado mínimo para acciones de jefe.    |
| `account`          | Recomendado | Nombre de la cuenta de sociedad.       |
| `logo`             | No          | URL HTTPS visible para clientes.       |
| `maxInvoiceAmount` | No          | Máximo de esta empresa.                |
| `commission`       | No          | Sustituye la comisión predeterminada.  |
| `rankLimits`       | No          | Máximo específico por grado exacto.    |
| `templates`        | No          | Conceptos predefinidos en la interfaz. |

#### Rangos

ESX suele entregar `job.grade` como número. QBCore/Qbox usan habitualmente `job.grade.level`. El bridge normaliza ambos.

El límite efectivo es el más restrictivo entre:

1. `Config.MaxInvoiceAmount`.
2. `company.maxInvoiceAmount`.
3. El valor aplicable en `company.rankLimits`.

No configures un `rankLimits` superior al máximo global esperando que lo amplíe.

#### Cuenta de sociedad

```lua
Config.DefaultSocietyAccountPrefix = 'society_'
```

Si una empresa no define `account`, se construye el nombre concatenando este prefijo y el trabajo. Para `police`, el resultado es `society_police`.

Comprueba cómo espera el identificador tu sistema bancario. Algunos recursos QB usan `police` y otros `society_police`; define `account` explícitamente para evitar ambigüedad.

### Límites e importes

```lua
Config.MaxInvoiceAmount = 1000000
Config.HighValueInvoiceAmount = 50000
```

* `MaxInvoiceAmount` bloquea valores superiores en el servidor.
* `HighValueInvoiceAmount` identifica operaciones importantes para auditoría.
* Los importes se redondean a dos decimales.
* Cero y números negativos se rechazan.

Usa límites razonables para la economía del servidor. Un límite de interfaz no sustituye la validación del servidor, que ya está incluida.

### Categorías

```lua
Config.InvoiceCategories = {
    { id = 'service', label = 'Servicio' },
    { id = 'fine', label = 'Multa' },
    { id = 'medical', label = 'Médico' },
    { id = 'repair', label = 'Reparación' },
    { id = 'sale', label = 'Venta' },
    { id = 'tax', label = 'Tasa' },
    { id = 'other', label = 'Otro' }
}
```

El `id` es persistente y debe mantenerse estable. `label` es presentación. Cuando una integración no especifica categoría se utiliza `service`.

### Vencimiento y duplicados

```lua
Config.DefaultDueDays = 7
Config.DuplicateWindowMinutes = 5
```

`DefaultDueDays` se usa cuando el formulario o export no aporta `dueDays`. Las facturas superadas pasan a `expired` mediante la tarea del servidor.

La protección de duplicados busca una factura reciente con mismo emisor, destinatario, fuente, importe y descripción en estado pendiente. Establece `DuplicateWindowMinutes = 0` para desactivarla.

### Comisiones

```lua
Config.DefaultCommission = {
    enabled = true,
    percent = 10,
    max = nil
}
```

La comisión está incluida en el total: el cliente paga exactamente el importe de la factura.

Para una factura empresarial de 1.000 con comisión del 10 %:

* Cliente paga: 1.000.
* Empleado recibe: 100.
* Sociedad recibe: 900.

`max` limita el valor monetario de la comisión, no el porcentaje. Una empresa puede sobrescribir toda la tabla mediante su campo `commission`. Las facturas personales no aplican comisión.

### Cuenta de pago

```lua
Config.PaymentAccount = 'bank'
```

Valores habituales:

* ESX: `bank` o `money`, según las cuentas disponibles.
* QBCore/Qbox: `bank`, `cash` o `money`; el bridge convierte `money` a `cash`.

Prueba saldo, retirada y devolución con el framework exacto antes de producción.

### Pagos parciales y pago agrupado

```lua
Config.AllowPartialPayments = true
Config.AllowPayAll = true
```

* `AllowPartialPayments` permite abonar una parte inferior al saldo pendiente.
* `AllowPayAll` habilita el flujo que suma y paga todas las facturas elegibles.

Cada abono crea una fila en `invoice_payments`. `paid_amount` acumula los pagos y la factura solo cambia a `paid` al completar `amount`.

### Auditoría y Discord

```lua
Config.AuditLogs = true
Config.DiscordWebhook = ''
Config.DiscordWebhookName = 'rc-billing'
```

La auditoría SQL escribe en `invoice_audit_logs`. El webhook vacío desactiva Discord. Si se configura, determinadas acciones críticas generan un embed.

No incluyas el webhook real en un paquete comercial, captura o repositorio público. Tras una filtración, revócalo desde Discord.

### Comandos y keybinds

```lua
Config.OpenInvoiceCommand = 'openinvoice'
Config.OpenInvoiceKey = 'F6'
Config.OpenPosCommand = 'openpos'
Config.OpenPosKey = 'F7'
```

Usa `false` o `nil` en una tecla para no registrar el keybind. Los comandos deben ser distintos y no incluir `/`.

FiveM guarda modificaciones de keybind por usuario; cambiar el valor predeterminado no reemplaza una asignación que el jugador ya personalizó.

### Nombres y avatar

```lua
Config.UseFrameworkPlayerNames = true
Config.DefaultMugshotUrl = 'https://example.com/default-avatar.png'
```

Con `UseFrameworkPlayerNames = true`, los recibos usan el nombre del personaje. En `false`, el bridge puede recurrir al nombre visible de FiveM según el framework.

La URL del avatar debe ser HTTPS, estable, pública y permitir carga desde Chromium Embedded Framework. Evita URLs temporales o con tokens.

### Configuración mínima de producción

Antes de publicar:

```lua
Config.Debug.enabled = false
Config.DiscordWebhook = '' -- Configúralo únicamente en la instalación privada.
Config.RequireAceForPersonalInvoices = true -- Recomendado si no todos deben facturar.
```

Elimina empresas de demostración que no existan en tu framework y reemplaza logos externos que no controles.
