# Especificación: modo `autoconversion`

Cambio en el contrato de emisión de facturas. Los importes de la moneda contraria se
reciben ya calculados en lugar de derivarse por `tasacambio`.

---

## 1. Alcance

El emisor envía ambas monedas. El servicio deja de aplicar `tasacambio` sobre los
importes y los persiste tal como llegan.

Cambio **aditivo**: no se elimina ni se renombra ningún campo del contrato actual. Se
agrega un flag y los importes de la moneda contraria.

Retrocompatible: sin el flag, o con el flag en `false`, el comportamiento actual se
mantiene y los campos con sufijo se ignoran.

---

## 2. Convención de sufijos

`moneda` define la moneda primaria. Los campos sin sufijo son siempre importes en la
moneda primaria. El sufijo identifica la **moneda contraria**, no el tipo de moneda del
importe.

| `moneda` | Campos sin sufijo | Sufijo de la contraparte |
|---|---|---|
| `usd` | USD | `_bs` |
| `bs` | Bs | `_usd` |

Sus documentos van con `"moneda": "usd"` → el sufijo aplicable es `_bs` en todos los
casos.

---

## 3. Reglas de presencia

Los campos se validan por pares. Para cada concepto:

| `<concepto>` | `<concepto>_bs` | Resultado |
|---|---|---|
| presente | presente | válido |
| presente | ausente | rechazado |
| ausente | presente | rechazado |
| ausente | ausente | válido — el concepto no aplica |

Notas:

- `0` es un valor presente. `baser: 0` exige `baser_bs: 0`.
- Para omitir un concepto que no aplica, omitir ambos campos. Verificado con `baser`,
  `impuestor`, `basea` e `impuestoa`.
- La validación de consistencia aritmética se ejecuta sobre la moneda primaria. Los
  campos con sufijo no se recalculan ni se verifican; se persisten y se imprimen tal
  como llegan. Eliminar los campos sin sufijo invalida el documento.

---

## 4. Campos

### 4.1 Raíz

```json
"autoconversion": true
```

### 4.2 Cabecera

| Campo | Contraparte |
|---|---|
| `subtotal` | `subtotal_bs` |
| `descuento` | `descuento_bs` |
| `exento` | `exento_bs` |
| `baseg` | `baseg_bs` |
| `impuestog` | `impuestog_bs` |
| `baser` | `baser_bs` |
| `impuestor` | `impuestor_bs` |
| `basea` | `basea_bs` |
| `impuestoa` | `impuestoa_bs` |
| `baseigtf` | `baseigtf_bs` |
| `impuestoigtf` | `impuestoigtf_bs` |
| `total` | `total_bs` |

`tasag`, `tasar`, `tasaa`, `tasaigtf` y `tipo_descuento` no llevan contraparte.

### 4.3 `cuerpofactura[]`

| Campo | Contraparte |
|---|---|
| `precio` | `precio_bs` |
| `monto` | `monto_bs` |
| `descuento` | `descuento_bs` |
| `iva` | `iva_bs` |
| `monto_neto` | `monto_neto_bs` |

Sin contraparte: `cantidad`, `tasa`, `exento`, `codigo`, `descripcion`, `impuesto`,
`campo_1`.

### 4.4 `formasdepago[]`

| Campo | Contraparte |
|---|---|
| `valor` | `valor_bs` |

---

## 5. Cálculo de la contraparte

Derivar por línea, no por agregado. Convertir el precio unitario y reconstruir la
estructura con las mismas fórmulas de la moneda primaria:

```
precio_bs      = precio × tasacambio
monto_bs       = precio_bs × cantidad − descuento_bs
iva_bs         = monto_bs × tasa / 100
monto_neto_bs  = monto_bs + iva_bs

subtotal_bs    = Σ (precio_bs × cantidad)
baseg_bs       = Σ monto_bs de líneas gravadas
exento_bs      = Σ monto_bs de líneas exentas
impuestog_bs   = Σ iva_bs
total_bs       = subtotal_bs − descuento_bs + impuestog_bs + impuestoigtf_bs
```

Convertir los agregados directamente (`total_bs = total × tasacambio`) produce un
total que no coincide con la suma de las líneas convertidas, por acumulación de
redondeos.

**No redondear la contraparte.** Se persiste con la precisión recibida; el formato de
presentación se aplica en la emisión.

---

## 6. Ejemplo

Factura `0000000001`, `tasacambio: 737.8816`. Campos preexistentes sin modificación,
incluidos sus decimales.

### Cabecera

| Campo | Valor | Contraparte | Valor |
|---|---|---|---|
| `subtotal` | `1251.27` | `subtotal_bs` | `923289.109632` |
| `descuento` | `0` | `descuento_bs` | `0` |
| `exento` | `0` | `exento_bs` | `0` |
| `baseg` | `1251.270000498725` | `baseg_bs` | `923289.11` |
| `impuestog` | `200.20320333235034` | `impuestog_bs` | `147726.26` |
| `baser` | `0` | `baser_bs` | `0` |
| `impuestor` | `0` | `impuestor_bs` | `0` |
| `basea` | `0` | `basea_bs` | `0` |
| `impuestoa` | `0` | `impuestoa_bs` | `0` |
| `baseigtf` | `1451.473203831` | `baseigtf_bs` | `1071015.3699999445` |
| `impuestoigtf` | `43.5441946241` | `impuestoigtf_bs` | `32130.4599999423` |
| `total` | `1495.0173984552` | `total_bs` | `1103145.8299999605` |

### Líneas

| # | Campo | Valor | Contraparte | Valor |
|---|---|---|---|---|
| 1 | `precio` | `1000` | `precio_bs` | `737881.6` |
| 1 | `monto` | `1000` | `monto_bs` | `737881.6` |
| 1 | `descuento` | `0` | `descuento_bs` | `0` |
| 1 | `iva` | `160` | `iva_bs` | `118061.056` |
| 1 | `monto_neto` | `1160` | `monto_neto_bs` | `855942.656` |
| 2 | `precio` | `251.27` | `precio_bs` | `185407.509632` |
| 2 | `monto` | `251.27` | `monto_bs` | `185407.509632` |
| 2 | `descuento` | `0` | `descuento_bs` | `0` |
| 2 | `iva` | `40.2032` | `iva_bs` | `29665.20154112` |
| 2 | `monto_neto` | `291.4732` | `monto_neto_bs` | `215072.71117312` |

---

## 7. Respuestas de error

Falta de contraparte:

```json
{
  "success": false,
  "error": {
    "message": "Campo de conversion total_bs requerido en cabecera cuando autoconversion es true."
  }
}
```

| Patrón | Ubicación |
|---|---|
| `requerido en cabecera` | Raíz del documento |
| `requerido en cuerpofactura[n]` | Línea de detalle, índice base 0 |
| `requerido en formasdepago[n]` | Forma de pago, índice base 0 |
| `invalido ... se esperaba un valor numerico` | Campo no numérico, `null` o cadena vacía |

Eliminación de campos primarios — resultados verificados sobre la factura de
referencia:

| Campo eliminado | Respuesta |
|---|---|
| `total` | `Valor de TOTAL MAL CALCULADO!` |
| `subtotal` | `El subtotal es requerido.` |
| `baseg`, `impuestog` | `Valor de SUBTOTAL MAL CALCULADO!` |
| `baseigtf` | `Base IGTF es requerido` |
| `precio`, `monto` en líneas | `El valor de MONTO DE REGISTRO #01, MAL CALCULADO!` |

La validación de contrapartes se ejecuta antes del registro del documento. Un rechazo
por este motivo no consume numeración.

---

## 8. Checklist

- [ ] `"autoconversion": true` en la raíz
- [ ] Campos preexistentes sin modificación
- [ ] 12 contrapartes de cabecera, incluidos los conceptos en `0`
- [ ] 5 contrapartes por línea de `cuerpofactura`
- [ ] `valor_bs` por entrada de `formasdepago`
- [ ] Contraparte derivada por línea, no por agregado
- [ ] Sin redondeo previo al envío

---