Overview
TechCore Mini ERP contains 12 core entities organized into functional modules. Each entity is implemented as both a SQL Server table and a corresponding C# Entity Framework model.User Management
rol
Defines user roles and permission levels in the system. Table Name:rolPrimary Key:
id (INT, IDENTITY)Entity Framework Model:
Rol
| Column | Type | Nullable | Default | Description |
|---|---|---|---|---|
| id | INT | No | IDENTITY | Unique role identifier |
| nombreRol | VARCHAR(100) | No | - | Role name (e.g., “Administrador”, “Vendedor”) |
| habilitado | BIT | No | 1 | Whether the role is active |
IDX_rol_habilitadoonhabilitado
- One-to-Many with
users
users
Stores system user accounts with authentication credentials. Table Name:usersPrimary Key:
id (INT, IDENTITY)Entity Framework Model:
User
| Column | Type | Nullable | Default | Description |
|---|---|---|---|---|
| id | INT | No | IDENTITY | Unique user identifier |
| code | VARCHAR(10) | No | - | User code (unique, e.g., “USR-001”) |
| nombre | VARCHAR(200) | No | - | Full name |
| username | VARCHAR(100) | No | - | Login username (unique) |
| pwd | VARCHAR(MAX) | No | - | Hashed password |
| phone | VARCHAR(15) | Yes | NULL | Contact phone number |
| idrol | INT | No | - | Foreign key to rol |
| VARCHAR(200) | Yes | NULL | Email address | |
| created_date | DATETIME | No | GETDATE() | Account creation timestamp |
IDX_users_code(UNIQUE) oncodeUQ__users__F3DBC572(UNIQUE) onusernameIDX_users_idrolonidrolIDX_users_emailonemail
- Many-to-One with
rol(idrol → rol.id) - One-to-Many with
ventas(sales created by user) - One-to-Many with
compras(purchases created by user)
Master Data
categoria
Product categories for inventory organization. Table Name:categoriaPrimary Key:
codCategoria (INT, IDENTITY)Entity Framework Model:
Categorium
| Column | Type | Nullable | Default | Description |
|---|---|---|---|---|
| codCategoria | INT | No | IDENTITY | Unique category identifier |
| codigo | VARCHAR(20) | No | - | Category code (unique, e.g., “CAT-001”) |
| nombre | VARCHAR(150) | No | - | Category name |
| descripcion | VARCHAR(300) | Yes | NULL | Category description |
| estado | BIT | No | 1 | Active/inactive status |
| created_date | DATETIME | No | GETDATE() | Creation timestamp |
IDX_categoria_codigo(UNIQUE) oncodigoIDX_categoria_nombreonnombreIDX_categoria_estadoonestado
- One-to-Many with
productos
clientes
Customer master data. Table Name:clientesPrimary Key:
codclien (VARCHAR(50))Entity Framework Model:
Cliente
| Column | Type | Nullable | Default | Description |
|---|---|---|---|---|
| codclien | VARCHAR(50) | No | - | Customer code (e.g., “CUST-001”) |
| nombre | VARCHAR(200) | No | - | Customer name |
| telefono | VARCHAR(15) | Yes | NULL | Phone number |
| VARCHAR(200) | Yes | NULL | Email address | |
| direccion | VARCHAR(300) | Yes | NULL | Physical address |
| estado | BIT | No | 1 | Active/inactive status |
| created_date | DATETIME | No | GETDATE() | Registration date |
IDX_clientes_nombreonnombreIDX_clientes_estadoonestadoIDX_clientes_emailonemail
- One-to-Many with
ventas
proveedores
Supplier/vendor master data. Table Name:proveedoresPrimary Key:
codprovee (VARCHAR(50))Entity Framework Model:
Proveedore
| Column | Type | Nullable | Default | Description |
|---|---|---|---|---|
| codprovee | VARCHAR(50) | No | - | Supplier code (e.g., “SUPP-001”) |
| nombre | VARCHAR(200) | No | - | Supplier name |
| telefono | VARCHAR(15) | Yes | NULL | Phone number |
| VARCHAR(200) | Yes | NULL | Email address | |
| direccion | VARCHAR(300) | Yes | NULL | Physical address |
| estado | INT | No | 1 | Active/inactive status |
| created_date | DATETIME | No | GETDATE() | Registration date |
IDX_proveedores_nombreonnombreIDX_proveedores_estadoonestado
- One-to-Many with
compras
The
estado field uses INT type for suppliers but BIT type for customers, indicating a potential schema evolution where suppliers may support multiple states beyond active/inactive.productos
Product catalog with inventory tracking. Table Name:productosPrimary Key:
codprod (VARCHAR(50))Entity Framework Model:
Producto
| Column | Type | Nullable | Default | Description |
|---|---|---|---|---|
| codprod | VARCHAR(50) | No | - | Product code/SKU |
| codCategoria | INT | Yes | NULL | Foreign key to categoria |
| descripcion | VARCHAR(500) | Yes | NULL | Product description |
| precioCompra | DECIMAL(18,2) | No | - | Purchase price (cost) |
| precioVenta | DECIMAL(18,2) | No | - | Selling price |
| stock | INT | No | 0 | Current inventory quantity |
| stockMinimo | INT | No | 5 | Minimum stock threshold for reorder alerts |
| estado | BIT | No | 1 | Active/inactive status |
| created_date | DATETIME | No | GETDATE() | Creation timestamp |
IDX_productos_descripcionondescripcionIDX_productos_idcategoriaoncodCategoriaIDX_productos_estadoonestadoIDX_productos_stock(COMPOSITE) on(stock, stockMinimo)- optimized for low stock queries
- Many-to-One with
categoria(codCategoria → categoria.codCategoria) - One-to-Many with
ventasDetalle - One-to-Many with
comprasDetalle
- Stock is automatically decreased by the
TR_DisminuirStocktrigger when sales are created - The composite index on stock fields enables efficient queries like:
WHERE stock <= stockMinimo
Sales Module
ventas
Sales order header information. Table Name:ventasPrimary Key:
norden (VARCHAR(50))Entity Framework Model:
Venta
| Column | Type | Nullable | Default | Description |
|---|---|---|---|---|
| norden | VARCHAR(50) | No | - | Order number (e.g., “V-2024-0001”) |
| ordenN | INT | No | - | Sequential order number |
| codclien | VARCHAR(50) | No | - | Customer code (FK to clientes) |
| codvend | INT | No | - | Salesperson user ID (FK to users) |
| fecha | DATETIME | No | GETDATE() | Order date |
| subtotal | DECIMAL(18,2) | No | - | Subtotal before tax |
| iva | DECIMAL(18,2) | No | - | Tax amount |
| total | DECIMAL(18,2) | No | - | Total amount including tax |
| tipoPago | VARCHAR(20) | No | ’CONTADO’ | Payment type: ‘CONTADO’ (cash) or ‘CREDITO’ (credit) |
| meses | INT | Yes | NULL | Number of installment months (for credit sales) |
| tasaInteres | DECIMAL(5,2) | No | 0 | Interest rate percentage |
| saldo | DECIMAL(18,2) | No | - | Outstanding balance |
| nula | BIT | No | 0 | Whether the sale is voided (0=valid, 1=voided) |
| estado | BIT | No | 1 | Active status |
IDX_ventas_codclienoncodclienIDX_ventas_codvendoncodvendIDX_ventas_fechaonfechaIDX_ventas_tipoPagoontipoPagoIDX_ventas_nula(FILTERED) onnula WHERE nula = 0- optimized for active sales queries
- Many-to-One with
clientes(codclien → clientes.codclien) - Many-to-One with
users(codvend → users.id) - One-to-Many with
ventasDetalle(CASCADE DELETE) - One-to-Many with
planPagos(CASCADE DELETE) - One-to-Many with
abonosVentas(CASCADE DELETE)
- For cash sales (
tipoPago = 'CONTADO'):saldoshould equal 0,mesesis NULL - For credit sales (
tipoPago = 'CREDITO'):saldostarts attotaland decreases as payments are made - Voided sales (
nula = 1) don’t affect inventory or reports
ventasDetalle
Sales order line items. Table Name:ventasDetallePrimary Key:
id (INT, IDENTITY)Entity Framework Model:
VentasDetalleTrigger:
TR_DisminuirStock
| Column | Type | Nullable | Default | Description |
|---|---|---|---|---|
| id | INT | No | IDENTITY | Unique line item identifier |
| norden | VARCHAR(50) | No | - | Order number (FK to ventas) |
| codprod | VARCHAR(50) | No | - | Product code (FK to productos) |
| cantidad | INT | No | - | Quantity sold |
| pventa | DECIMAL(18,2) | No | - | Unit price |
| subtotal | DECIMAL(18,2) | No | - | Line total (cantidad × pventa) |
IDX_ventasDetalle_nordenonnordenIDX_ventasDetalle_codprodoncodprod
- Many-to-One with
ventas(norden → ventas.norden, CASCADE DELETE) - Many-to-One with
productos(codprod → productos.codprod)
TR_DisminuirStock: Automatically decreases product stock when line items are inserted (only for non-voided sales)
planPagos
Installment payment schedule for credit sales. Table Name:planPagosPrimary Key:
id (INT, IDENTITY)Entity Framework Model:
PlanPago
| Column | Type | Nullable | Default | Description |
|---|---|---|---|---|
| id | INT | No | IDENTITY | Unique installment identifier |
| norden | VARCHAR(50) | No | - | Order number (FK to ventas) |
| numeroCuota | INT | No | - | Installment number (1, 2, 3…) |
| fechaVencimiento | DATE | No | - | Due date |
| montoCuota | DECIMAL(18,2) | No | - | Installment amount |
| pagada | BIT | No | 0 | Payment status (0=pending, 1=paid) |
IDX_planPagos_nordenonnordenIDX_planPagos_fechaVencimientoonfechaVencimientoIDX_planPagos_pagada(FILTERED) onpagada WHERE pagada = 0- optimized for pending payment queries
- Many-to-One with
ventas(norden → ventas.norden, CASCADE DELETE)
vw_CuotasVencidas: Shows overdue installments with late feesvw_CuotasPorVencer: Shows upcoming installments
abonosVentas
Payment transactions for credit sales. Table Name:abonosVentasPrimary Key:
id (INT, IDENTITY)Entity Framework Model:
AbonosVentaTrigger:
TR_ActualizarSaldo
| Column | Type | Nullable | Default | Description |
|---|---|---|---|---|
| id | INT | No | IDENTITY | Unique payment identifier |
| norden | VARCHAR(50) | No | - | Order number (FK to ventas) |
| fecha | DATETIME | No | GETDATE() | Payment date |
| monto | DECIMAL(18,2) | No | - | Payment amount |
| numeroCuota | INT | No | - | Installment number being paid |
IDX_abonosVentas_nordenonnordenIDX_abonosVentas_fechaonfecha
- Many-to-One with
ventas(norden → ventas.norden, CASCADE DELETE)
TR_ActualizarSaldo: Automatically updatesventas.saldoand marks the correspondingplanPagosrecord as paid
Purchases Module
compras
Purchase order header information. Table Name:comprasPrimary Key:
norden (VARCHAR(50))Entity Framework Model:
Compra
| Column | Type | Nullable | Default | Description |
|---|---|---|---|---|
| norden | VARCHAR(50) | No | - | Purchase order number |
| ordenN | INT | No | - | Sequential order number |
| codprov | VARCHAR(50) | No | - | Supplier code (FK to proveedores) |
| codusu | INT | No | - | User who created the PO (FK to users) |
| fecha | DATETIME | No | GETDATE() | Order date |
| subtotal | DECIMAL(18,2) | No | - | Subtotal before tax |
| iva | DECIMAL(18,2) | No | - | Tax amount |
| total | DECIMAL(18,2) | No | - | Total amount |
| estado | INT | No | 1 | Order status |
IDX_compras_codprovoncodprovIDX_compras_codusuoncodusuIDX_compras_fechaonfechaIDX_compras_estadoonestado
- Many-to-One with
proveedores(codprov → proveedores.codprovee) - Many-to-One with
users(codusu → users.id) - One-to-Many with
comprasDetalle(CASCADE DELETE)
comprasDetalle
Purchase order line items. Table Name:comprasDetallePrimary Key:
id (INT, IDENTITY)Entity Framework Model:
ComprasDetalle
| Column | Type | Nullable | Default | Description |
|---|---|---|---|---|
| id | INT | No | IDENTITY | Unique line item identifier |
| norden | VARCHAR(50) | No | - | Order number (FK to compras) |
| codprod | VARCHAR(50) | No | - | Product code (FK to productos) |
| cantidad | INT | No | - | Quantity purchased |
| precio | DECIMAL(18,2) | No | - | Unit cost |
| subtotal | DECIMAL(18,2) | No | - | Line total (cantidad × precio) |
IDX_comprasDetalle_nordenonnordenIDX_comprasDetalle_codprodoncodprod
- Many-to-One with
compras(norden → compras.norden, CASCADE DELETE) - Many-to-One with
productos(codprod → productos.codprod)
Unlike sales, purchases do not automatically increase inventory via triggers. Inventory increases must be handled programmatically in the application layer after receiving goods.
Database Views
Three read-only views provide business intelligence for credit management.vw_CuotasVencidas
Shows overdue installments with calculated late fees. Entity Framework Model:VwCuotasVencida
| Column | Type | Description |
|---|---|---|
| norden | VARCHAR(50) | Order number |
| cliente | VARCHAR(200) | Customer name |
| numeroCuota | INT | Installment number |
| fechaVencimiento | DATE | Original due date |
| montoCuota | DECIMAL(18,2) | Installment amount |
| diasAtraso | INT | Days overdue |
| moraCalculada | NUMERIC(32,4) | Late fee (2% daily interest) |
vw_CuotasPorVencer
Shows upcoming installments that haven’t reached their due date. Entity Framework Model:VwCuotasPorVencer
| Column | Type | Description |
|---|---|---|
| norden | VARCHAR(50) | Order number |
| cliente | VARCHAR(200) | Customer name |
| numeroCuota | INT | Installment number |
| fechaVencimiento | DATE | Due date |
| montoCuota | DECIMAL(18,2) | Installment amount |
vw_EstadoCuenta
Provides account statement summary for credit sales. Entity Framework Model:VwEstadoCuentum
| Column | Type | Description |
|---|---|---|
| norden | VARCHAR(50) | Order number |
| cliente | VARCHAR(200) | Customer name |
| total | DECIMAL(18,2) | Original total amount |
| saldo | DECIMAL(18,2) | Current outstanding balance |
| meses | INT | Number of installments |
| totalAbonado | DECIMAL(38,2) | Sum of all payments made |
Entity Framework DbContext
All entities are registered in theTechCoreContext class:
OnModelCreating() method at TechCore/Datos/TechCoreContext.cs:45.
Common Query Patterns
Get Products Below Minimum Stock
Get Customer Account Balance
Get Overdue Payments
Get Sales with Details
Data Migration Considerations
Foreign Key Constraints Order
When populating tables, follow this order to respect foreign key constraints:rolusers(depends on rol)categoriaproductos(depends on categoria)clientesproveedoresventas(depends on users, clientes)ventasDetalle(depends on ventas, productos)compras(depends on users, proveedores)comprasDetalle(depends on compras, productos)planPagos(depends on ventas)abonosVentas(depends on ventas)
Cascade Deletes
These relationships will automatically delete child records:- Deleting
ventas→ deletesventasDetalle,planPagos,abonosVentas - Deleting
compras→ deletescomprasDetalle
Non-Cascade Deletes
These relationships require manual cleanup or will prevent deletion:categoriawith existingproductosproductoswith existingventasDetalleorcomprasDetalleclienteswith existingventasproveedoreswith existingcomprasrolwith existingusersuserswith existingventasorcompras
Next Steps
Database Setup
Install and configure the database
Database Overview
Learn about database architecture and design