# US-MGN010-004: Registrar Asientos Contables

## Identificacion

| Campo | Valor |
|-------|-------|
| **ID** | US-MGN010-004 |
| **Modulo** | MGN-010 Financial |
| **Sprint** | Sprint 7 |
| **Prioridad** | P0 - Critica |
| **Story Points** | 13 |
| **Estado** | Ready |
| **RF Relacionado** | RF-FIN-004 |
| **Fecha** | 2025-12-05 |

---

## Historia de Usuario

**Como** contador
**Quiero** registrar asientos contables con multiples lineas
**Para** afectar los saldos de cuentas y mantener la contabilidad al dia

---

## Descripcion

El sistema permite registrar asientos contables (journal entries) con multiples lineas de cargo y abono. Valida que el asiento este cuadrado, la fecha en periodo abierto y las cuentas sean de detalle. Soporta multi-moneda y centros de costo.

### Contexto

- Partida doble (Debe = Haber)
- Validacion de periodo abierto
- Numeracion automatica
- Mayorizar (post) afecta saldos

---

## Criterios de Aceptacion

### Escenario 1: Crear asiento en borrador

```gherkin
Given usuario con permiso contable
When crea POST /api/v1/financial/journal
  | entryDate | "2025-12-05" |
  | description | "Registro de venta" |
  | lines | [{ accountId, debit/credit }, ...] |
Then el asiento se crea con status = "draft"
  And aun no afecta saldos de cuentas
```

### Escenario 2: Validar asiento cuadrado

```gherkin
Given asiento con total Debe = 11,600
  And total Haber = 10,000
When intenta contabilizar
Then el sistema rechaza con error
  And indica "Asiento descuadrado: Debe=11,600, Haber=10,000"
```

### Escenario 3: Contabilizar asiento (post)

```gherkin
Given asiento en borrador cuadrado
When ejecuta POST /api/v1/financial/journal/{id}/post
Then el asiento cambia a status = "posted"
  And se genera numero automatico
  And se actualizan saldos de cuentas afectadas
```

### Escenario 4: Numeracion automatica

```gherkin
Given configuracion de numeracion:
  | prefix | "POL" |
  | yearFormat | "YYYY" |
  | sequenceLength | 6 |
When contabiliza asiento
Then recibe numero "POL-2025-000001"
```

### Escenario 5: Fecha en periodo cerrado

```gherkin
Given periodo Noviembre cerrado
When crea asiento con fecha "2025-11-15"
Then el sistema rechaza
  And indica "Periodo cerrado para esta fecha"
```

### Escenario 6: Asiento multi-moneda

```gherkin
Given asiento con linea en USD
When registra la linea:
  | amount | 1000 USD |
  | exchangeRate | 17.50 |
Then se guarda:
  | debit | 1000 (moneda original) |
  | debitBase | 17500 (moneda base MXN) |
```

### Escenario 7: Reversar asiento

```gherkin
Given asiento contabilizado
When ejecuta POST /api/v1/financial/journal/{id}/reverse
  | reversalDate | "2025-12-06" |
  | reason | "Error en monto" |
Then se crea nuevo asiento con lineas invertidas
  And el original cambia a status = "reversed"
  And los saldos vuelven a estado anterior
```

### Escenario 8: Asiento con centro de costo

```gherkin
Given asiento de gasto
When registra linea con:
  | accountId | Gastos Administrativos |
  | costCenterId | Centro Norte |
Then el movimiento queda asociado al centro de costo
  And reportes por CC muestran el monto
```

### Escenario 9: Consultar libro diario

```gherkin
Given asientos contabilizados
When consulta GET /api/v1/financial/journal?periodId=uuid
Then retorna lista de asientos:
  | entryNumber, entryDate, description, totalDebit, linesCount |
```

### Escenario 10: Ver detalle de asiento

```gherkin
Given asiento existente
When consulta GET /api/v1/financial/journal/{id}
Then retorna asiento con todas sus lineas:
  | lineNumber, account, debit, credit, description |
```

---

## Mockup / Wireframe

```
+------------------------------------------------------------------+
|  LIBRO DIARIO                                    [+ Nuevo Asiento] |
+------------------------------------------------------------------+
| [Periodo: Diciembre 2025 v]  [Estado: Todos v]  [Buscar...]       |
+------------------------------------------------------------------+

| NUMERO        | FECHA      | CONCEPTO             | DEBE      | LINEAS |
+------------------------------------------------------------------+
| POL-2025-001245| 2025-12-05 | Pago a proveedor XYZ | $10,000   | 3     |
| POL-2025-001244| 2025-12-05 | Registro de venta    | $11,600   | 3     |
| POL-2025-001243| 2025-12-04 | Nomina quincenal     | $85,000   | 15    |
| POL-2025-001242| 2025-12-04 | Compra de inventario | $45,000   | 2     |
+------------------------------------------------------------------+
                                              [< Anterior] [1] [Siguiente >]

+------------------------------------------------------------------+
|  NUEVO ASIENTO CONTABLE                                           |
+------------------------------------------------------------------+
| Fecha*                           | Concepto/Glosa*                |
| [2025-12-05] [📅]                | [Registro de venta #1234     ] |
+------------------------------------------------------------------+
| Referencia                       | Fuente                         |
| [FAC-2025-1234            ]     | [Factura v]                    |
+------------------------------------------------------------------+

LINEAS
+------------------------------------------------------------------+
| # | CUENTA            | DESCRIPCION      | DEBE     | HABER     |
+------------------------------------------------------------------+
| 1 | [1.1.02.001 Clien | [Cliente ABC   ] | [11,600] | [       ] |
| 2 | [4.1.01.001 Ingre | [Venta servici ] | [      ] | [10,000 ] |
| 3 | [2.1.05.001 IVA x | [IVA 16%       ] | [      ] | [1,600  ] |
+------------------------------------------------------------------+
                                 [+ Agregar Linea]
+------------------------------------------------------------------+
| TOTALES                                     | $11,600  | $11,600  |
| DIFERENCIA                                  |        $0.00 ✓      |
+------------------------------------------------------------------+

                   [Cancelar]  [Guardar Borrador]  [=== Contabilizar ===]

Modal: Detalle de Asiento
+------------------------------------------------------------------+
| ASIENTO: POL-2025-001244                                    [X]  |
+------------------------------------------------------------------+
| Numero: POL-2025-001244                                          |
| Fecha: 05 de Diciembre de 2025                                   |
| Concepto: Registro de venta #1234                                |
| Estado: ✓ Contabilizado                                          |
| Contabilizado por: Juan Contador - 2025-12-05 10:30              |
|                                                                   |
| LINEAS                                                            |
+------------------------------------------------------------------+
| CUENTA                    | DESCRIPCION    | DEBE     | HABER    |
+------------------------------------------------------------------+
| 1.1.02.001 Clientes Nac.  | Cliente ABC    | $11,600  |          |
| 4.1.01.001 Ingresos Venta | Venta servic.  |          | $10,000  |
| 2.1.05.001 IVA por Pagar  | IVA 16%        |          | $1,600   |
+------------------------------------------------------------------+
| TOTALES                                    | $11,600  | $11,600  |
+------------------------------------------------------------------+
|                                                                   |
|                              [Imprimir]  [=== Reversar ===]      |
+------------------------------------------------------------------+
```

---

## Notas Tecnicas

### API Endpoints

| Metodo | Path | Descripcion |
|--------|------|-------------|
| GET | /financial/journal | Listar asientos |
| POST | /financial/journal | Crear asiento |
| GET | /financial/journal/:id | Detalle de asiento |
| PUT | /financial/journal/:id | Actualizar borrador |
| DELETE | /financial/journal/:id | Eliminar borrador |
| POST | /financial/journal/:id/post | Contabilizar |
| POST | /financial/journal/:id/reverse | Reversar |

### Validaciones

| Validacion | Descripcion |
|------------|-------------|
| entry_balanced | Debe = Haber (tolerancia 0.01) |
| date_in_open_period | Fecha en periodo abierto |
| accounts_are_detail | Solo cuentas de detalle |
| accounts_active | Cuentas activas |
| amounts_positive | Montos positivos |
| valid_exchange_rate | TC valido para fecha |

### Mayorizar

```typescript
async function postEntry(entryId: UUID): Promise<PostResult> {
  const entry = await this.getEntry(entryId);

  // Validar
  const validation = this.validate(entry);
  if (!validation.isValid) throw new ValidationError(validation.errors);

  // Generar numero
  const entryNumber = await this.generateNumber(entry.entryDate);

  // Actualizar saldos (en transaccion)
  await this.db.transaction(async (tx) => {
    for (const line of entry.lines) {
      await this.updateAccountBalance(tx, line);
    }
    await this.markAsPosted(tx, entry, entryNumber);
  });

  return { entryNumber, postedAt: new Date() };
}
```

---

## Definicion de Done

- [ ] CRUD de asientos
- [ ] Validacion de cuadre
- [ ] Validacion de periodo abierto
- [ ] Numeracion automatica
- [ ] Mayorizar asiento
- [ ] Reversar asiento
- [ ] Soporte multi-moneda
- [ ] Centros de costo
- [ ] Tests unitarios
- [ ] Documentacion Swagger

---

## Dependencias

### Requiere

| Item | Descripcion |
|------|-------------|
| US-MGN010-001 | Plan de cuentas |
| US-MGN010-002 | Monedas y TC |
| US-MGN010-003 | Periodos (validacion) |
| Tabla journal_entries | Asientos |
| Tabla journal_lines | Lineas |

### Bloquea

| Item | Descripcion |
|------|-------------|
| Reportes contables | Balance, Libro Mayor |
| Modulos de negocio | Generan asientos |

---

## Historial

| Version | Fecha | Autor | Cambios |
|---------|-------|-------|---------|
| 1.0 | 2025-12-05 | Requirements-Analyst | Creacion inicial |
