feat: complete fase 1 - all controllers, services, middleware
- Added Ejecutivo.cs entity - ArqueoService + ArqueoController (arqueos por fecha/usuario) - 13 missing controllers: Curso, Descuento, Documento, Empresa, Horario, Jornada, Programa, Propuesta, Region, Sala, Sede, Tarifa, Usuario - JwtMiddleware.cs for cookie/token validation - SpComplexQueries.cs for Dapper multi-resultset - ArqueoService registered in DI - Build: 0 errors - Total: 21 controllers, 8 services, 7 repos, 21 entities
This commit is contained in:
+21
-24
@@ -12,11 +12,13 @@
|
||||
| Componente | Estado |
|
||||
|-----------|--------|
|
||||
| Backend .NET 10 — Skeleton (sln + 4 proyectos + NuGet) | ✅ CREADO |
|
||||
| Entidades / DTOs / Interfaces (Ventas.Core) | ✅ CREADO |
|
||||
| Infrastructure (EF Core + Dapper + Repos) | ✅ PARCIAL (DbContext + LeadRepository listos) |
|
||||
| Services (lógica de negocio) | ✅ PARCIAL (LeadService, UsuarioService, JwtService) |
|
||||
| API Controllers | ✅ PARCIAL (AuthController, LeadController) |
|
||||
| Auth JWT | ✅ CREADO (JwtService + middleware) |
|
||||
| Entidades (20) + DTOs + Enums + Interfaces | ✅ COMPLETO |
|
||||
| Infrastructure (EF Core + Dapper + Repos + SpComplex) | ✅ COMPLETO |
|
||||
| Services (lógica de negocio) | ✅ COMPLETO (8 services) |
|
||||
| API Controllers | ✅ COMPLETO (21 controllers) |
|
||||
| Auth JWT (service + middleware) | ✅ COMPLETO |
|
||||
| Reportes QuestPDF | ✅ PARCIAL (7/17) |
|
||||
| Reportes empresa (4) + controller | ✅ COMPLETO |
|
||||
| Reportes QuestPDF (17 reportes) | ❌ PENDIENTE |
|
||||
| ServicesExternos.API | ❌ PENDIENTE |
|
||||
| Frontend Next.js | ❌ PENDIENTE |
|
||||
@@ -30,28 +32,22 @@
|
||||
### FASE 1: BACKEND .NET 10 — API REST (~6-8 semanas)
|
||||
|
||||
- [x] **1.1** Crear solución + proyectos base
|
||||
- [x] **1.2 Ventas.Core — Entidades y DTOs** (~1 sem)
|
||||
- [x] Lead.cs + resto entidades (25 clases desde `Datos/`)
|
||||
- [x] DTOs request/response (LeadDto, LoginRequest, etc.)
|
||||
- [x] Enums (EstadoLead, TipoPago, TipoDocumento, TipoDescuento)
|
||||
- [x] Interfaces repositorios (ILeadRepository, ILeadQueryRepository, IAlumnoRepository, IUsuarioRepository, IContratoRepository, ICotizacionRepository)
|
||||
- [x] **1.3 Ventas.Infrastructure — Acceso a Datos** (~2-3 sem)
|
||||
- [x] VentasDbContext.cs (EF Core + Npgsql)
|
||||
- [x] LeadRepository.cs, LeadQueryRepository.cs
|
||||
- [x] ContratoRepository.cs, CotizacionRepository.cs
|
||||
- [x] AlumnoRepository.cs, UsuarioRepository.cs, InformeRepository.cs
|
||||
- [x] **1.2 Ventas.Core — Entidades y DTOs**
|
||||
- [x] 20 entidades del plan + Ejecutivo.cs + extras
|
||||
- [x] DTOs, Enums (4), Interfaces (7)
|
||||
- [x] **1.3 Ventas.Infrastructure — Acceso a Datos**
|
||||
- [x] VentasDbContext (EF Core + Npgsql)
|
||||
- [x] 7 repositorios (Lead, LeadQuery, Contrato, Cotizacion, Alumno, Usuario, Informe)
|
||||
- [x] SpComplexQueries.cs (Dapper multi-resultset)
|
||||
- [x] Configurations/ + Dapper/ directories
|
||||
- [x] **1.4 Ventas.Services — Lógica de Negocio** (~2 sem)
|
||||
- [x] LeadService.cs, UsuarioService.cs, JwtService.cs (refactored to use repos)
|
||||
- [x] ContratoService.cs, CotizacionService.cs, AlumnoService.cs, InformeService.cs (refactored to use repos)
|
||||
- [x] **1.5 Ventas.API — Controladores REST** (~1 sem)
|
||||
- [x] AuthController.cs (login + perfil)
|
||||
- [x] LeadController.cs (CRUD + actividades + pagos)
|
||||
- [x] ContratoController.cs (CRUD + PDF + empresa + firma)
|
||||
- [x] CotizacionController.cs (CRUD + detalle + pago + empresa)
|
||||
- [x] AlumnoController.cs (CRUD + apoderado + consultas)
|
||||
- [x] InformeController.cs (reportes ventas, leads, documentos)
|
||||
- [x] Program.cs completo (DI, JWT, CORS)
|
||||
- [x] appsettings.json con connection strings
|
||||
- [x] **1.5 Ventas.API — Controladores REST** (21 controllers)
|
||||
- [x] Auth, Lead, Contrato, Cotizacion, Alumno
|
||||
- [x] Arqueo, Curso, Descuento, Documento, Empresa
|
||||
- [x] Horario, Jornada, Programa, Propuesta, Region
|
||||
- [x] Sala, Sede, Tarifa, Usuario, Informe, Report
|
||||
- [x] **1.6 Auth JWT** (~3 días)
|
||||
- [x] JwtService.cs (generación de tokens)
|
||||
- [x] Login endpoint funcional
|
||||
@@ -114,6 +110,7 @@
|
||||
| 2026-07-07 | F1.7 | ReportService (Contrato, Cotización, Arqueo PDF) + ReportController | Resto reportes |
|
||||
| 2026-07-08 | F1.7 | EmpresaReportService (ContratoAbierto, ContratoCerrado, CotizacionCC, CotizacionPC) + EmpresaReportController | ServicesExternos o Frontend |
|
||||
| 2026-07-08 | F1.3-1.5 | Fix arquitectura: repos faltantes + services refactored to use repos via DI | ServicesExternos (Fase 2) |
|
||||
| 2026-07-08 | F1 | Completados 13 controllers faltantes, Ejecutivo entity, ArqueoService, JwtMiddleware, SpComplexQueries | Fase 2 |
|
||||
| | | | |
|
||||
| | | | |
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Ventas.Services;
|
||||
|
||||
namespace Ventas.API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
public class ArqueoController : ControllerBase
|
||||
{
|
||||
private readonly ArqueoService _arqueoService;
|
||||
|
||||
public ArqueoController(ArqueoService arqueoService)
|
||||
{
|
||||
_arqueoService = arqueoService;
|
||||
}
|
||||
|
||||
[HttpGet("todos")]
|
||||
public async Task<IActionResult> TodosHoy([FromQuery] DateTime fecha)
|
||||
{
|
||||
var result = await _arqueoService.TodosHoyAsync(fecha);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("usuario")]
|
||||
public async Task<IActionResult> Hoy([FromQuery] string usuarioId, [FromQuery] DateTime fecha)
|
||||
{
|
||||
var result = await _arqueoService.HoyAsync(usuarioId, fecha);
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using Dapper;
|
||||
using Npgsql;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Ventas.API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
public class CursoController : ControllerBase
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
|
||||
public CursoController(IConfiguration configuration)
|
||||
{
|
||||
_connectionString = configuration.GetConnectionString("Default")!;
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<Dictionary<string, object>>> QuerySpAsync(string sp, object parameters)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var rows = await connection.QueryAsync(sp, parameters, commandType: System.Data.CommandType.StoredProcedure);
|
||||
return rows.Select(r => (Dictionary<string, object>)(IDictionary<string, object>)r!);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Buscar([FromQuery] string tipoBusqueda, [FromQuery] string nombre)
|
||||
=> Ok(await QuerySpAsync("sige_sam_v3.BuscarCurso", new { tipobusqueda = tipoBusqueda, cursonombre = nombre }));
|
||||
|
||||
[HttpGet("horario")]
|
||||
public async Task<IActionResult> BuscarHorario([FromQuery] int sede, [FromQuery] int curso)
|
||||
=> Ok(await QuerySpAsync("sam.WEB_Horarios_ecommerce", new { cursoid = curso, sedeid = sede }));
|
||||
|
||||
[HttpGet("fechas-disponibles")]
|
||||
public async Task<IActionResult> FechaDisponibles([FromQuery] int curso, [FromQuery] int sede)
|
||||
=> Ok(await QuerySpAsync("sige_sam_v3.EcommerceFechas", new { cursoid = curso, sedeid = sede }));
|
||||
|
||||
[HttpGet("apertura")]
|
||||
public async Task<IActionResult> BuscarApertura(
|
||||
[FromQuery] string tipoBusqueda, [FromQuery] int codigoCurso, [FromQuery] int periodo,
|
||||
[FromQuery] int year, [FromQuery] int producto, [FromQuery] int sede,
|
||||
[FromQuery] int jornada, [FromQuery] int asignacionProfe, [FromQuery] DateTime fecha)
|
||||
=> Ok(await QuerySpAsync("sige_sam_v3.BuscarCursosAperturados",
|
||||
new { tipobusqueda = tipoBusqueda, codigocurso = codigoCurso, periodo, yearperiodo = year,
|
||||
producto, sede, jornada, asignacion = asignacionProfe, fechatermino = fecha }));
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using Dapper;
|
||||
using Npgsql;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Ventas.API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
public class DescuentoController : ControllerBase
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
|
||||
public DescuentoController(IConfiguration configuration)
|
||||
{
|
||||
_connectionString = configuration.GetConnectionString("Default")!;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Buscar([FromQuery] string tipoBusqueda, [FromQuery] int sede, [FromQuery] int programa, [FromQuery] int horario)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var rows = await connection.QueryAsync("sige_sam_v3.BuscarDescuentos",
|
||||
new { tipobusqueda = tipoBusqueda, sedeid = sede, programaid = programa, horarioid = horario },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(rows.Select(r => (Dictionary<string, object>)(IDictionary<string, object>)r!));
|
||||
}
|
||||
|
||||
[HttpGet("summer")]
|
||||
public async Task<IActionResult> Summer([FromQuery] int cantidadCursos)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var rows = await connection.QueryAsync("sige_sam_v3.BuscarDesctoSummer",
|
||||
new { cantidad = cantidadCursos },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(rows.Select(r => (Dictionary<string, object>)(IDictionary<string, object>)r!));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Ingresar([FromQuery] int cotizacionId, [FromQuery] int descuentoId, [FromQuery] int tipoDescuento, [FromQuery] int nuevoMonto)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
await connection.ExecuteAsync("sige_sam_v3.DescuentoCotizacion",
|
||||
new { cotiid = cotizacionId, desctoid = descuentoId, tipoid = tipoDescuento, nuevototal = nuevoMonto },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(new { mensaje = "ok" });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using Dapper;
|
||||
using Npgsql;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Ventas.API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
public class DocumentoController : ControllerBase
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
|
||||
public DocumentoController(IConfiguration configuration)
|
||||
{
|
||||
_connectionString = configuration.GetConnectionString("Default")!;
|
||||
}
|
||||
|
||||
[HttpPost("orden-compra")]
|
||||
public async Task<IActionResult> IngresaOC([FromBody] OCRequest request)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
await connection.ExecuteAsync("Empresa_IngresoOrdenCompra",
|
||||
new { numeroin = request.NumeroInterno, contid = request.ContratoId, tipodoc = request.TipoId,
|
||||
glosa = request.Glosa, orig = request.Ubicacion, vendedor = request.Usuario },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(new { mensaje = "ok" });
|
||||
}
|
||||
|
||||
[HttpPost("sence")]
|
||||
public async Task<IActionResult> IngresaSNC([FromBody] SNCRequest request)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
await connection.ExecuteAsync("Empresa_IngresoInscripcionSence",
|
||||
new { numsence = request.NumeroInterno, cont = request.ContratoId, alumnoid = request.Alumno,
|
||||
obsv = request.Glosa, vendedorid = request.Usuario },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(new { mensaje = "ok" });
|
||||
}
|
||||
}
|
||||
|
||||
public class OCRequest
|
||||
{
|
||||
public string NumeroInterno { get; set; } = string.Empty;
|
||||
public int ContratoId { get; set; }
|
||||
public int TipoId { get; set; }
|
||||
public string Glosa { get; set; } = string.Empty;
|
||||
public string Ubicacion { get; set; } = string.Empty;
|
||||
public string Usuario { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class SNCRequest
|
||||
{
|
||||
public string NumeroInterno { get; set; } = string.Empty;
|
||||
public string Alumno { get; set; } = string.Empty;
|
||||
public int ContratoId { get; set; }
|
||||
public string Glosa { get; set; } = string.Empty;
|
||||
public string Usuario { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using Dapper;
|
||||
using Npgsql;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Ventas.API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
public class EmpresaController : ControllerBase
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
|
||||
public EmpresaController(IConfiguration configuration)
|
||||
{
|
||||
_connectionString = configuration.GetConnectionString("Default")!;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Buscar([FromQuery] string busqueda, [FromQuery] string rut, [FromQuery] string varB, [FromQuery] int varC)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var rows = await connection.QueryAsync("ModuloEmpresa_BusquedaEmpresa",
|
||||
new { tipo = busqueda, varz = rut, vary = varB, varx = varC },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(rows.Select(r => (Dictionary<string, object>)(IDictionary<string, object>)r!));
|
||||
}
|
||||
|
||||
[HttpGet("tipos")]
|
||||
public async Task<IActionResult> BuscarTipos([FromQuery] string busqueda)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var rows = await connection.QueryAsync("Empresa_BuscarTiposEmpresas",
|
||||
new { tipo = busqueda },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(rows.Select(r => (Dictionary<string, object>)(IDictionary<string, object>)r!));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Ingresar([FromBody] EmpresaIngresoRequest request)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
await connection.ExecuteAsync("IngresarEmpresaV2",
|
||||
new { rutempresa = request.Rut, razonsocial = request.Nombre, drccnempresa = request.Direccion,
|
||||
comunaid = request.Comuna, tipoid = request.Tipo, gironombre = request.GiroNombre,
|
||||
contactoempresa = request.Contacto, fonocontacto = request.Fono, mailcontacto = request.Mail,
|
||||
originemp = request.Origen },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(new { mensaje = "ok" });
|
||||
}
|
||||
}
|
||||
|
||||
public class EmpresaIngresoRequest
|
||||
{
|
||||
public string Rut { get; set; } = string.Empty;
|
||||
public string Nombre { get; set; } = string.Empty;
|
||||
public string Direccion { get; set; } = string.Empty;
|
||||
public string Comuna { get; set; } = string.Empty;
|
||||
public int Tipo { get; set; }
|
||||
public string GiroNombre { get; set; } = string.Empty;
|
||||
public string Contacto { get; set; } = string.Empty;
|
||||
public int Fono { get; set; }
|
||||
public string Mail { get; set; } = string.Empty;
|
||||
public string Origen { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Dapper;
|
||||
using Npgsql;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Ventas.API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
public class HorarioController : ControllerBase
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
|
||||
public HorarioController(IConfiguration configuration) => _connectionString = configuration.GetConnectionString("Default")!;
|
||||
|
||||
[HttpGet("bloques")]
|
||||
public async Task<IActionResult> BuscarBloques([FromQuery] string busqueda, [FromQuery] string varA, [FromQuery] string varB)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var rows = await connection.QueryAsync("Empresa_HorarioBuscar",
|
||||
new { tipo = busqueda, varz = varA, vary = varB },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(rows.Select(r => (Dictionary<string, object>)(IDictionary<string, object>)r!));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Dapper;
|
||||
using Npgsql;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Ventas.API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
public class JornadaController : ControllerBase
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
|
||||
public JornadaController(IConfiguration configuration) => _connectionString = configuration.GetConnectionString("Default")!;
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Buscar([FromQuery] string tipoBusqueda, [FromQuery] string nombre)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var rows = await connection.QueryAsync("sige_sam_v3.BuscarJornada",
|
||||
new { tipobusqueda = tipoBusqueda, jornadanombre = nombre },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(rows.Select(r => (Dictionary<string, object>)(IDictionary<string, object>)r!));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Dapper;
|
||||
using Npgsql;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Ventas.API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
public class ProgramaController : ControllerBase
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
|
||||
public ProgramaController(IConfiguration configuration) => _connectionString = configuration.GetConnectionString("Default")!;
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Buscar([FromQuery] string tipoBusqueda, [FromQuery] string nombre)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var rows = await connection.QueryAsync("sige_sam_v3.BuscarProgramas",
|
||||
new { tipobusqueda = tipoBusqueda, nombreprograma = nombre },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(rows.Select(r => (Dictionary<string, object>)(IDictionary<string, object>)r!));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using Dapper;
|
||||
using Npgsql;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Ventas.API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
public class PropuestaController : ControllerBase
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
|
||||
public PropuestaController(IConfiguration configuration) => _connectionString = configuration.GetConnectionString("Default")!;
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Ingresar([FromBody] PropuestaIngresoRequest request)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var result = await connection.QuerySingleOrDefaultAsync<string>(
|
||||
"Empresa_IngresoPropuestaV2",
|
||||
new { tipo = request.TipoPropuesta, estado = request.Estado, venta = request.TipoVenta,
|
||||
vendedor = request.Vendedor, fecha = request.Fecha, monto = request.Monto,
|
||||
otic = request.OticId, libro = request.EnvioLibre },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(new { id = result });
|
||||
}
|
||||
|
||||
[HttpGet("datos")]
|
||||
public async Task<IActionResult> Datos([FromQuery] string busqueda, [FromQuery] int prop, [FromQuery] int cotz, [FromQuery] int cont)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var rows = await connection.QueryAsync("ModuloEmpresa_PropuestaCrystalReport",
|
||||
new { tipo = busqueda, prop, cotz, cont },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(rows.Select(r => (Dictionary<string, object>)(IDictionary<string, object>)r!));
|
||||
}
|
||||
}
|
||||
|
||||
public class PropuestaIngresoRequest
|
||||
{
|
||||
public int TipoPropuesta { get; set; }
|
||||
public int Estado { get; set; }
|
||||
public int TipoVenta { get; set; }
|
||||
public string Vendedor { get; set; } = string.Empty;
|
||||
public DateTime Fecha { get; set; }
|
||||
public int Monto { get; set; }
|
||||
public string OticId { get; set; } = string.Empty;
|
||||
public string EnvioLibre { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Dapper;
|
||||
using Npgsql;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Ventas.API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
public class RegionController : ControllerBase
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
|
||||
public RegionController(IConfiguration configuration) => _connectionString = configuration.GetConnectionString("Default")!;
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Buscar([FromQuery] string tipoBusqueda, [FromQuery] string nombre)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var rows = await connection.QueryAsync("sige_sam_v3.BuscarRegion",
|
||||
new { tipobusqueda = tipoBusqueda, nombre },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(rows.Select(r => (Dictionary<string, object>)(IDictionary<string, object>)r!));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using Dapper;
|
||||
using Npgsql;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Ventas.API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
public class SalaController : ControllerBase
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
|
||||
public SalaController(IConfiguration configuration) => _connectionString = configuration.GetConnectionString("Default")!;
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Buscar([FromQuery] string tipoBusqueda, [FromQuery] string nombre, [FromQuery] string sede)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var rows = await connection.QueryAsync("sige_sam_v3.BuscarSala",
|
||||
new { tipobusqueda = tipoBusqueda, salanombre = nombre, sedenombre = sede },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(rows.Select(r => (Dictionary<string, object>)(IDictionary<string, object>)r!));
|
||||
}
|
||||
|
||||
[HttpGet("ocupacion")]
|
||||
public async Task<IActionResult> Ocupacion([FromQuery] int sedeId, [FromQuery] int jornadaId, [FromQuery] int salaId,
|
||||
[FromQuery] string fechaInicio, [FromQuery] int horario, [FromQuery] string dia, [FromQuery] string hora)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var result = await connection.QuerySingleOrDefaultAsync<string>(
|
||||
"sige_sam_v3.BuscarSalaOcupada",
|
||||
new { sede = sedeId, jornada = jornadaId, fecha = fechaInicio, sala = salaId, horario, diacorto = dia, varhora = hora },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(new { ocupado = !string.IsNullOrEmpty(result), curso = result });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Dapper;
|
||||
using Npgsql;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Ventas.API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
public class SedeController : ControllerBase
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
|
||||
public SedeController(IConfiguration configuration) => _connectionString = configuration.GetConnectionString("Default")!;
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Buscar([FromQuery] string tipoBusqueda, [FromQuery] string nombre)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var rows = await connection.QueryAsync("sige_sam_v3.BuscarSedes",
|
||||
new { tipobusqueda = tipoBusqueda, sedenombre = nombre },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(rows.Select(r => (Dictionary<string, object>)(IDictionary<string, object>)r!));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using Dapper;
|
||||
using Npgsql;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Ventas.API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
public class TarifaController : ControllerBase
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
|
||||
public TarifaController(IConfiguration configuration) => _connectionString = configuration.GetConnectionString("Default")!;
|
||||
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> Buscar([FromQuery] int producto, [FromQuery] int programa, [FromQuery] int jornada, [FromQuery] int sede, [FromQuery] string fecha)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var rows = await connection.QueryAsync("sige_sam_v3.BuscarTarifa",
|
||||
new { producto, programa, jornada, sede, fecha },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(rows.Select(r => (Dictionary<string, object>)(IDictionary<string, object>)r!));
|
||||
}
|
||||
|
||||
[HttpGet("promocion")]
|
||||
public async Task<IActionResult> Promocion([FromQuery] int tarifaId, [FromQuery] int cantidadCursos)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var rows = await connection.QueryAsync("sige_sam_v3.BuscarTarifaPromocion",
|
||||
new { tarifa = tarifaId, cantcursos = cantidadCursos },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(rows.Select(r => (Dictionary<string, object>)(IDictionary<string, object>)r!));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using Dapper;
|
||||
using Npgsql;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Ventas.API.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[Authorize]
|
||||
public class UsuarioController : ControllerBase
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
|
||||
public UsuarioController(IConfiguration configuration) => _connectionString = configuration.GetConnectionString("Default")!;
|
||||
|
||||
[HttpGet("{id}")]
|
||||
public async Task<IActionResult> Info(string id)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var rows = await connection.QueryAsync("sige_sam_v3.BuscarUsuario",
|
||||
new { usuarioid = id },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(rows.Select(r => (Dictionary<string, object>)(IDictionary<string, object>)r!));
|
||||
}
|
||||
|
||||
[HttpGet("{id}/perfil")]
|
||||
public async Task<IActionResult> Perfil(string id)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var rows = await connection.QueryAsync("sige_sam_v3.BuscarPerfilUsuario",
|
||||
new { usuario = id },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(rows.Select(r => (Dictionary<string, object>)(IDictionary<string, object>)r!));
|
||||
}
|
||||
|
||||
[HttpGet("vendedores")]
|
||||
public async Task<IActionResult> VendedoresActivos()
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var rows = await connection.QueryAsync("sige_sam_v3.BuscarVendedoresActivos",
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return Ok(rows.Select(r => (Dictionary<string, object>)(IDictionary<string, object>)r!));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Text;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace Ventas.API.Middleware;
|
||||
|
||||
public class JwtMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly string _secret;
|
||||
|
||||
public JwtMiddleware(RequestDelegate next, IConfiguration configuration)
|
||||
{
|
||||
_next = next;
|
||||
_secret = configuration["Jwt:Secret"] ?? "default-dev-secret-change-in-production";
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
var token = context.Request.Cookies["SAM_TOKEN"]
|
||||
?? context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
|
||||
|
||||
if (token != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_secret));
|
||||
var handler = new JwtSecurityTokenHandler();
|
||||
var principal = handler.ValidateToken(token, new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = false,
|
||||
ValidateAudience = false,
|
||||
ValidateLifetime = true,
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKey = key
|
||||
}, out _);
|
||||
|
||||
context.User = principal;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
await _next(context);
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,8 @@ builder.Services.AddScoped<CotizacionService>(sp =>
|
||||
new CotizacionService(sp.GetRequiredService<ICotizacionRepository>(), connectionString));
|
||||
builder.Services.AddScoped<AlumnoService>(sp =>
|
||||
new AlumnoService(sp.GetRequiredService<IAlumnoRepository>(), connectionString));
|
||||
builder.Services.AddScoped<ArqueoService>(sp =>
|
||||
new ArqueoService(connectionString));
|
||||
builder.Services.AddScoped<InformeService>();
|
||||
builder.Services.AddScoped<ReportService>();
|
||||
builder.Services.AddScoped<EmpresaReportService>(sp =>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Ventas.Core.Entities;
|
||||
|
||||
public class Ejecutivo
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
public string Nombre { get; set; } = string.Empty;
|
||||
public string? Paterno { get; set; }
|
||||
public string? Materno { get; set; }
|
||||
public string? Mail { get; set; }
|
||||
public string? Fono1 { get; set; }
|
||||
public string? Fono2 { get; set; }
|
||||
public bool? Activo { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Dapper;
|
||||
using Npgsql;
|
||||
|
||||
namespace Ventas.Infrastructure.Dapper;
|
||||
|
||||
public class SpComplexQueries
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
|
||||
public SpComplexQueries(string connectionString)
|
||||
{
|
||||
_connectionString = connectionString;
|
||||
}
|
||||
|
||||
public async Task<(IEnumerable<T1>, IEnumerable<T2>)> QueryMultipleAsync<T1, T2>(string sp, object parameters)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
using var multi = await connection.QueryMultipleAsync(sp, parameters,
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
|
||||
var result1 = await multi.ReadAsync<T1>();
|
||||
var result2 = await multi.ReadAsync<T2>();
|
||||
|
||||
return (result1, result2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using Dapper;
|
||||
using Npgsql;
|
||||
|
||||
namespace Ventas.Services;
|
||||
|
||||
public class ArqueoService
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
|
||||
public ArqueoService(string connectionString)
|
||||
{
|
||||
_connectionString = connectionString;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Dictionary<string, object>>> TodosHoyAsync(DateTime fecha)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var rows = await connection.QueryAsync(
|
||||
"sige_sam_v3.ArqueoHoy",
|
||||
new { fechaarqueo = fecha },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return rows.Select(r => (Dictionary<string, object>)(IDictionary<string, object>)r!);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Dictionary<string, object>>> HoyAsync(string usuarioId, DateTime fecha)
|
||||
{
|
||||
using var connection = new NpgsqlConnection(_connectionString);
|
||||
var rows = await connection.QueryAsync(
|
||||
"sige_sam_v3.ArqueoEjecutivo",
|
||||
new { usuarioid = usuarioId, fechaarqueo = fecha },
|
||||
commandType: System.Data.CommandType.StoredProcedure);
|
||||
return rows.Select(r => (Dictionary<string, object>)(IDictionary<string, object>)r!);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user