PHPackages                             numerar/contable - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. numerar/contable

ActiveLibrary[Database &amp; ORM](/categories/database)

numerar/contable
================

Numerar Contable — Motor contable de partida doble con PUC colombiano para Laravel.

v1.0.0(1mo ago)01MITBladePHP ^8.2

Since Jun 23Pushed 1mo agoCompare

[ Source](https://github.com/juan-rios-dev/numerar_contable)[ Packagist](https://packagist.org/packages/numerar/contable)[ RSS](/packages/numerar-contable/feed)WikiDiscussions main Synced 2w ago

READMEChangelogDependencies (7)Versions (4)Used By (0)

Numerar Contable
================

[](#numerar-contable)

Motor contable de **partida doble** para Laravel, diseñado sobre el **Plan Único de Cuentas (PUC) colombiano**. Se instala como paquete Composer en cualquier proyecto Laravel 11 o 12 y expone tanto una interfaz web Blade lista para usar como una API REST JSON completa.

Características principales
---------------------------

[](#características-principales)

- **Partida doble estricta** — los comprobantes solo se pueden contabilizar si débitos = créditos.
- **PUC colombiano precargado** — 9 clases de cuentas (Activo, Pasivo, Patrimonio, Ingresos, Gastos, Costos de Ventas, Costos de Producción, Cuentas de Orden Deudoras y Acreedoras) listas desde el primer `contable:install`. Opcionalmente carga el catálogo completo de **973 cuentas PUC** con `--with-puc`.
- **Catálogo de cuentas jerárquico** — árbol ilimitado de subcuentas auxiliares con naturaleza (débito/crédito) heredada de la clase.
- **Periodos y ejercicios fiscales** — apertura, cierre y reapertura de periodos; cierre de ejercicio con asiento de resultado automático.
- **Tipos y numeraciones de comprobante** — CI, CE, CD, CA, CO, NC, CIE con secuencias independientes por tipo.
- **Centros de costo** — asignables por línea de comprobante.
- **Terceros polimórficos** — cualquier modelo de tu aplicación puede actuar como tercero (proveedor, cliente, empleado, etc.) sin necesidad de duplicar datos.
- **UI Blade + API REST** — ambas capas pueden activarse de forma independiente.
- **Multi-tenancy opcional** — filtrado automático por `tenant_id` vía Global Scope; desactivado por defecto.
- **Autorización vía Gates** — el paquete no impone roles; tú defines quién puede entrar, registrar comprobantes, ver reportes o administrar el módulo.
- **Modelos intercambiables** — cualquier modelo del paquete puede reemplazarse por uno propio desde la configuración.
- **7 reportes contables** — Libro Diario, Mayor General, Balance de Comprobación, Estado de Situación Financiera, Estado de Resultados, Mayor por Tercero y Reporte por Centro de Costo.

Requisitos
----------

[](#requisitos)

DependenciaVersiónPHP^8.2Laravel^11.0 | ^12.0Alpine.js^3.x (CDN, incluido en la UI)Instalación
-----------

[](#instalación)

```
composer require numerar/contable
```

Ejecuta el comando de instalación:

```
php artisan contable:install
```

Esto publica `config/contable.php`, corre las migraciones y siembra las 9 clases PUC y los tipos de comprobante por defecto.

### Opciones del instalador

[](#opciones-del-instalador)

```
# Cargar el catálogo completo PUC (973 cuentas)
php artisan contable:install --with-puc

# Reinstalar desde cero (¡destructivo: elimina las tablas!)
php artisan contable:install --fresh

# Instalar sin datos iniciales
php artisan contable:install --no-seed
```

### Publicar recursos individualmente

[](#publicar-recursos-individualmente)

```
# Configuración
php artisan vendor:publish --tag=contable-config

# Migraciones
php artisan vendor:publish --tag=contable-migrations

# Vistas Blade (para personalizar la UI)
php artisan vendor:publish --tag=contable-views

# Assets CSS (se copia automáticamente con contable:install)
php artisan vendor:publish --tag=contable-assets --force
```

Configuración rápida
--------------------

[](#configuración-rápida)

El archivo `config/contable.php` cubre todas las opciones. Los ajustes más comunes:

### Middleware y prefijos de ruta

[](#middleware-y-prefijos-de-ruta)

```
'web_prefix'     => 'contabilidad',           // /contabilidad/...
'web_middleware' => ['web', 'auth'],           // añade auth para proteger la UI
'api_prefix'     => 'api/contabilidad',
'api_middleware' => ['api', 'auth:sanctum'],
```

### Activar/desactivar capas

[](#activardesactivar-capas)

```
'features' => [
    'web' => true,   // interfaz Blade
    'api' => true,   // API REST JSON
],
```

Autorización
------------

[](#autorización)

El paquete define cuatro gates. Si no los defines tú, **todos pasan** (modo desarrollo). En producción, decláralos en tu `AppServiceProvider`:

```
use Illuminate\Support\Facades\Gate;

Gate::define('contable.access',  fn($u) => $u->hasRole(['admin', 'contador']));
Gate::define('contable.entries', fn($u) => $u->hasRole(['admin', 'contador']));
Gate::define('contable.reports', fn($u) => $u->hasRole(['admin', 'contador', 'auditor']));
Gate::define('contable.admin',   fn($u) => $u->hasRole('admin'));
```

GateProtege`contable.access`Acceso general al módulo`contable.entries`Crear, editar y anular comprobantes`contable.reports`Ver reportes contables`contable.admin`Cerrar periodos, configurar ejerciciosMulti-tenancy
-------------

[](#multi-tenancy)

Desactivado por defecto. Para activarlo:

```
// config/contable.php
'tenancy' => [
    'enabled' => true,
    'column'  => 'tenant_id',
],
```

Registra el resolver en tu `AppServiceProvider::boot()`:

```
use Numerar\Contable\Facades\Contable;

Contable::resolveTenantUsing(fn() => auth()->user()?->company_id);
```

Todas las tablas tienen `tenant_id BIGINT DEFAULT 0`. El valor `0` actúa como centinela para modo single-tenant, evitando problemas con índices únicos en MySQL.

Terceros polimórficos
---------------------

[](#terceros-polimórficos)

Las líneas de comprobante aceptan cualquier modelo como tercero. Por defecto apunta al modelo `Tercero` del paquete; puedes agregar los tuyos:

```
// config/contable.php
'terceros' => [
    [
        'model'             => \App\Models\Proveedor::class,
        'label'             => 'Proveedores',
        'display_attribute' => 'razon_social',
        'search_attributes' => ['razon_social', 'nit'],
    ],
    [
        'model'             => \App\Models\Cliente::class,
        'label'             => 'Clientes',
        'display_attribute' => 'nombre',
        'search_attributes' => ['nombre', 'identificacion'],
    ],
],
```

El selector en la UI agrupa las opciones por tipo de modelo automáticamente.

Modelos intercambiables
-----------------------

[](#modelos-intercambiables)

Extiende cualquier modelo del paquete y regístralo en la config:

```
// app/Models/MiCuenta.php
class MiCuenta extends \Numerar\Contable\Models\Account
{
    // tus personalizaciones
}

// config/contable.php
'models' => [
    'account' => \App\Models\MiCuenta::class,
    // el resto sigue igual...
],
```

Crear comprobantes por código
-----------------------------

[](#crear-comprobantes-por-código)

Usa la fachada `Contable` o inyecta `EntryService` directamente. Todas las operaciones corren dentro de una transacción y lanzan excepciones tipadas ante cualquier violación de reglas contables.

### Requisito previo: periodo abierto

[](#requisito-previo-periodo-abierto)

El comprobante se asocia automáticamente al periodo contable cuya fecha de inicio/fin contenga `date`. Si el periodo no existe o está cerrado, se lanza `PeriodClosedException`.

```
use Numerar\Contable\Facades\Contable;

// Crear el periodo si aún no existe
Contable::createPeriod([
    'year'       => 2025,
    'month'      => 1,
    'start_date' => '2025-01-01',
    'end_date'   => '2025-01-31',
]);
```

### Registrar un comprobante

[](#registrar-un-comprobante)

```
$entry = Contable::createEntry([
    'entry_type'  => 'CI',          // código del tipo de comprobante
    'date'        => '2025-01-15',
    'description' => 'Venta de mercancía al contado',
    'created_by'  => auth()->id(),  // opcional

    'lines' => [
        [
            'account_id'  => 111,   // id de la cuenta Caja (1105)
            'debit'       => 1190000,
            'credit'      => 0,
            'description' => 'Recaudo en efectivo',
        ],
        [
            'account_id'  => 340,   // id de la cuenta IVA generado (240805)
            'debit'       => 0,
            'credit'      => 190000,
            'description' => 'IVA 19%',
        ],
        [
            'account_id'  => 210,   // id de la cuenta Ventas (4101)
            'debit'       => 0,
            'credit'      => 1000000,
            'description' => 'Venta mercancía',
            // opcional: tercero polimórfico
            'third_party_type' => \App\Models\Cliente::class,
            'third_party_id'   => 7,
            // opcional: centro de costo
            'cost_center_id'   => 2,
        ],
    ],
]);
// $entry->entry_number  → "CI-0001/2025"
// $entry->status        → EntryStatus::POSTED
```

El servicio valida que `sum(debit) === sum(credit)` antes de confirmar la transacción. Si no cuadra, lanza `UnbalancedEntryException`.

### Editar un comprobante

[](#editar-un-comprobante)

```
Contable::updateEntry($entry, [
    'description' => 'Descripción corregida',
    'lines'       => [...],   // reemplaza todas las líneas
]);
```

### Anular un comprobante

[](#anular-un-comprobante)

```
Contable::voidEntry($entry);
// o por id:
Contable::voidEntry(42);
```

Los comprobantes anulados quedan con `status = VOIDED` y no pueden editarse. Sus movimientos dejan de aparecer en reportes.

### Excepciones tipadas

[](#excepciones-tipadas)

ExcepciónCuándo se lanza`AccountingException`Regla de negocio general (cuenta inactiva, tipo de comprobante inexistente, etc.)`UnbalancedEntryException``sum(débitos) ≠ sum(créditos)``PeriodClosedException`El periodo contable está cerrado```
use Numerar\Contable\Exceptions\UnbalancedEntryException;
use Numerar\Contable\Exceptions\PeriodClosedException;

try {
    Contable::createEntry([...]);
} catch (PeriodClosedException $e) {
    // abrir el periodo primero
} catch (UnbalancedEntryException $e) {
    // $e->getMessage() incluye el valor de la diferencia
}
```

Reportes disponibles
--------------------

[](#reportes-disponibles)

ReporteRuta webEndpoint APILibro Diario`/accounting/reports/journal``GET /api/accounting/reports/journal`Mayor General`/accounting/reports/general-ledger``GET /api/accounting/reports/general-ledger`Mayor por Tercero`/accounting/reports/third-party-ledger``GET /api/accounting/reports/third-party-ledger`Balance de Comprobación`/accounting/reports/trial-balance``GET /api/accounting/reports/trial-balance`Estado de Situación Financiera`/accounting/reports/balance-sheet``GET /api/accounting/reports/balance-sheet`Estado de Resultados`/accounting/reports/income-statement``GET /api/accounting/reports/income-statement`Centro de Costo`/accounting/reports/cost-center``GET /api/accounting/reports/cost-center`> Las rutas usan el prefijo por defecto `accounting`. Cámbialo en `config/contable.php` → `web_prefix`.

API REST
--------

[](#api-rest)

Todos los recursos cuentan con endpoints JSON bajo el prefijo `api/accounting` (configurable). Ejemplo de rutas:

```
GET    /api/accounting/accounts
POST   /api/accounting/accounts
GET    /api/accounting/accounts/{id}
PUT    /api/accounting/accounts/{id}
DELETE /api/accounting/accounts/{id}

GET    /api/accounting/entries
POST   /api/accounting/entries
PATCH  /api/accounting/entries/{id}/void

GET    /api/accounting/periods
POST   /api/accounting/fiscal-years/{year}/close

```

Las respuestas siguen el formato de Laravel API Resources. Autenticación vía Sanctum por defecto (configurable).

Estructura del paquete
----------------------

[](#estructura-del-paquete)

```
src/
├── ContableServiceProvider.php
├── Console/Commands/InstallCommand.php
├── Database/Seeders/
│   ├── AccountClassSeeder.php      # 9 clases PUC
│   └── EntryTypeSeeder.php         # CI, CE, CD, CA, CO, NC, CIE
├── Enums/                          # AccountNature, AccountType, EntryStatus...
├── Exceptions/                     # UnbalancedEntry, PeriodClosed...
├── Facades/Contable.php
├── Http/
│   ├── Controllers/                # Controladores Blade
│   ├── Controllers/Api/            # Controladores JSON
│   ├── Requests/                   # Form Requests
│   └── Resources/                  # API Resources
├── Models/                         # 10 modelos Eloquent
├── Services/
│   ├── AccountingService.php       # Façade principal, tenant resolver
│   ├── EntryService.php            # Crear, editar, anular comprobantes
│   ├── FiscalYearService.php       # Cierre de ejercicio y resultado
│   └── ReportService.php           # 7 reportes contables
├── Traits/
│   ├── HasTenancy.php
│   └── HasAuditFields.php
├── database/migrations/            # 10 migraciones
└── helpers.php

```

Licencia
--------

[](#licencia)

MIT — © Alernal · [juan-rios-dev](https://github.com/juan-rios-dev)

###  Health Score

38

—

LowBetter than 83% of packages

Maintenance90

Actively maintained with recent releases

Popularity1

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity48

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

45d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/271b5db66a69b599976d6b16211ce3ddb186573756276d2dedc24dcfb1d06113?d=identicon)[juan-rios-dev](/maintainers/juan-rios-dev)

---

Top Contributors

[![juan-rios-dev](https://avatars.githubusercontent.com/u/279279753?v=4)](https://github.com/juan-rios-dev "juan-rios-dev (2 commits)")

---

Tags

laravelAccountingdouble entrycolombiapuccontabilidad

###  Code Quality

TestsPHPUnit

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/numerar-contable/health.svg)

```
[![Health](https://phpackages.com/badges/numerar-contable/health.svg)](https://phpackages.com/packages/numerar-contable)
```

###  Alternatives

[anourvalar/eloquent-serialize

Laravel Query Builder (Eloquent) serialization

11225.5M34](/packages/anourvalar-eloquent-serialize)[statamic-rad-pack/runway

Eloquently manage your database models in Statamic.

137236.2k8](/packages/statamic-rad-pack-runway)[langleyfoxall/xero-laravel

💸 Access the Xero accounting system using an Eloquent-like syntax

86245.1k](/packages/langleyfoxall-xero-laravel)[ecotone/laravel

Ecotone for Laravel — CQRS, Event Sourcing, Sagas, Durable Workflows, and Outbox on top of Laravel Queue, via PHP attributes.

21327.3k4](/packages/ecotone-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
