feat: cuentas por cobrar usa listado de clientes en vez de entidades contables
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
daf0b2c2a1
commit
6e281dfbda
@@ -61,8 +61,10 @@ func (Transaccion) TableName() string { return "contab_transacciones" }
|
|||||||
|
|
||||||
type CuentaCobro struct {
|
type CuentaCobro struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
EntidadID uint `json:"entidad_id" gorm:"column:entidad_id;index;not null"`
|
ClienteID uint `json:"cliente_id" gorm:"column:cliente_id;index;not null"`
|
||||||
Entidad Entidad `json:"entidad" gorm:"foreignKey:EntidadID"`
|
Cliente Cliente `json:"cliente" gorm:"foreignKey:ClienteID"`
|
||||||
|
EntidadID *uint `json:"entidad_id" gorm:"column:entidad_id;index"`
|
||||||
|
Entidad *Entidad `json:"entidad" gorm:"foreignKey:EntidadID"`
|
||||||
Fecha time.Time `json:"fecha" gorm:"column:fecha;not null"`
|
Fecha time.Time `json:"fecha" gorm:"column:fecha;not null"`
|
||||||
Descripcion string `json:"descripcion" gorm:"column:descripcion;type:text"`
|
Descripcion string `json:"descripcion" gorm:"column:descripcion;type:text"`
|
||||||
Valor float64 `json:"valor" gorm:"column:valor;not null"`
|
Valor float64 `json:"valor" gorm:"column:valor;not null"`
|
||||||
@@ -260,11 +262,11 @@ func DeleteTransaccion(id uint) error {
|
|||||||
func GetAllCuentasCobro(limit, offset int, search string, estado string) ([]CuentaCobro, int64, error) {
|
func GetAllCuentasCobro(limit, offset int, search string, estado string) ([]CuentaCobro, int64, error) {
|
||||||
var items []CuentaCobro
|
var items []CuentaCobro
|
||||||
var total int64
|
var total int64
|
||||||
db := app.Http.Database.DB.Model(&CuentaCobro{}).Preload("Entidad").Preload("Transaccion")
|
db := app.Http.Database.DB.Model(&CuentaCobro{}).Preload("Cliente").Preload("Entidad").Preload("Transaccion")
|
||||||
if search != "" {
|
if search != "" {
|
||||||
db = db.Joins("JOIN contab_entidades ON contab_entidades.id = contab_cuentas_cobro.entidad_id").
|
db = db.Joins("JOIN clientes ON clientes.id = contab_cuentas_cobro.cliente_id").
|
||||||
Where("contab_entidades.nombre ILIKE ? OR contab_cuentas_cobro.descripcion ILIKE ?",
|
Where("clientes.nombre ILIKE ? OR clientes.empresa ILIKE ? OR contab_cuentas_cobro.descripcion ILIKE ?",
|
||||||
"%"+search+"%", "%"+search+"%")
|
"%"+search+"%", "%"+search+"%", "%"+search+"%")
|
||||||
}
|
}
|
||||||
if estado != "" {
|
if estado != "" {
|
||||||
db = db.Where("contab_cuentas_cobro.estado = ?", estado)
|
db = db.Where("contab_cuentas_cobro.estado = ?", estado)
|
||||||
@@ -463,10 +465,7 @@ func CreateCuentaCobro(cc *CuentaCobro) error {
|
|||||||
|
|
||||||
func UpdateCuentaCobro(cc *CuentaCobro) error {
|
func UpdateCuentaCobro(cc *CuentaCobro) error {
|
||||||
return app.Http.Database.DB.Model(&CuentaCobro{}).Where("id = ?", cc.ID).Updates(map[string]interface{}{
|
return app.Http.Database.DB.Model(&CuentaCobro{}).Where("id = ?", cc.ID).Updates(map[string]interface{}{
|
||||||
"entidad_id": cc.EntidadID,
|
"cliente_id": cc.ClienteID,
|
||||||
"fecha": cc.Fecha,
|
|
||||||
"descripcion": cc.Descripcion,
|
|
||||||
"valor": cc.Valor,
|
|
||||||
"estado": cc.Estado,
|
"estado": cc.Estado,
|
||||||
"fecha_vencimiento": cc.FechaVencimiento,
|
"fecha_vencimiento": cc.FechaVencimiento,
|
||||||
"fecha_pago": cc.FechaPago,
|
"fecha_pago": cc.FechaPago,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
<thead class="bg-slate-50 text-slate-500 text-xs uppercase tracking-wide">
|
<thead class="bg-slate-50 text-slate-500 text-xs uppercase tracking-wide">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="px-4 py-3 text-left">Fecha</th>
|
<th class="px-4 py-3 text-left">Fecha</th>
|
||||||
<th class="px-4 py-3 text-left">Entidad</th>
|
<th class="px-4 py-3 text-left">Cliente</th>
|
||||||
<th class="px-4 py-3 text-left">Descripción</th>
|
<th class="px-4 py-3 text-left">Descripción</th>
|
||||||
<th class="px-4 py-3 text-right">Valor</th>
|
<th class="px-4 py-3 text-right">Valor</th>
|
||||||
<th class="px-4 py-3 text-left">Vence</th>
|
<th class="px-4 py-3 text-left">Vence</th>
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
<template x-for="c in items" :key="c.ID">
|
<template x-for="c in items" :key="c.ID">
|
||||||
<tr class="hover:bg-slate-50">
|
<tr class="hover:bg-slate-50">
|
||||||
<td class="px-4 py-3 text-xs text-slate-500" x-text="formatDate(c.fecha)"></td>
|
<td class="px-4 py-3 text-xs text-slate-500" x-text="formatDate(c.fecha)"></td>
|
||||||
<td class="px-4 py-3 text-slate-700 font-medium" x-text="c.entidad?.nombre||'-'"></td>
|
<td class="px-4 py-3 text-slate-700 font-medium" x-text="c.cliente?.nombre||'-'"></td>
|
||||||
<td class="px-4 py-3 text-slate-600" x-text="c.descripcion"></td>
|
<td class="px-4 py-3 text-slate-600" x-text="c.descripcion"></td>
|
||||||
<td class="px-4 py-3 text-right font-semibold text-amber-600" x-text="formatoCOP(c.valor)"></td>
|
<td class="px-4 py-3 text-right font-semibold text-amber-600" x-text="formatoCOP(c.valor)"></td>
|
||||||
<td class="px-4 py-3 text-xs text-slate-500" x-text="formatDate(c.fecha_vencimiento)"></td>
|
<td class="px-4 py-3 text-xs text-slate-500" x-text="formatDate(c.fecha_vencimiento)"></td>
|
||||||
@@ -80,11 +80,11 @@
|
|||||||
<form @submit.prevent="save()">
|
<form @submit.prevent="save()">
|
||||||
<div class="grid grid-cols-2 gap-4">
|
<div class="grid grid-cols-2 gap-4">
|
||||||
<div class="col-span-2">
|
<div class="col-span-2">
|
||||||
<label class="label">Entidad (quien debe)</label>
|
<label class="label">Cliente (quien debe)</label>
|
||||||
<select x-model.number="form.entidad_id" class="input-field w-full" required>
|
<select x-model.number="form.cliente_id" class="input-field w-full" required>
|
||||||
<option value="">Seleccionar...</option>
|
<option value="">Seleccionar...</option>
|
||||||
<template x-for="e in entidades" :key="e.ID">
|
<template x-for="cl in clientes" :key="cl.ID">
|
||||||
<option :value="e.ID" x-text="e.nombre"></option>
|
<option :value="cl.ID" x-text="cl.nombre + (cl.empresa ? ' — ' + cl.empresa : '')"></option>
|
||||||
</template>
|
</template>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@@ -149,10 +149,10 @@
|
|||||||
<script>
|
<script>
|
||||||
function cobroApp() {
|
function cobroApp() {
|
||||||
return {
|
return {
|
||||||
items:[], entidades:[], total:0, totalPages:1, page:1, search:'', filtroEstado:'',
|
items:[], clientes:[], total:0, totalPages:1, page:1, search:'', filtroEstado:'',
|
||||||
loading:false, saving:false, showModal:false, showDelete:false, showPagarModal:false,
|
loading:false, saving:false, showModal:false, showDelete:false, showPagarModal:false,
|
||||||
deleteId:null, pagarId:null, pagoFecha:'', error:'',
|
deleteId:null, pagarId:null, pagoFecha:'', error:'',
|
||||||
form:{ entidad_id:'', descripcion:'', valor:0, fecha:'', fecha_vencimiento:'', notas:'' },
|
form:{ cliente_id:'', descripcion:'', valor:0, fecha:'', fecha_vencimiento:'', notas:'' },
|
||||||
|
|
||||||
async init(){ await this.load(); },
|
async init(){ await this.load(); },
|
||||||
|
|
||||||
@@ -163,12 +163,12 @@ function cobroApp() {
|
|||||||
if(this.filtroEstado) params.set('estado',this.filtroEstado);
|
if(this.filtroEstado) params.set('estado',this.filtroEstado);
|
||||||
const r=await axios.get('/app/contabilidad/cuentas-cobro/list?'+params.toString());
|
const r=await axios.get('/app/contabilidad/cuentas-cobro/list?'+params.toString());
|
||||||
this.items=r.data.items; this.total=r.data.total; this.totalPages=r.data.totalPages;
|
this.items=r.data.items; this.total=r.data.total; this.totalPages=r.data.totalPages;
|
||||||
const er=await axios.get('/app/contabilidad/entidades/select');
|
const er=await axios.get('/app/api/clientes/select');
|
||||||
this.entidades=er.data;
|
this.clientes=er.data;
|
||||||
} finally{ this.loading=false; }
|
} finally{ this.loading=false; }
|
||||||
},
|
},
|
||||||
|
|
||||||
openCreate(){ this.editId=null; this.error=''; this.form={entidad_id:'',descripcion:'',valor:0,fecha:'',fecha_vencimiento:'',notas:''}; this.showModal=true; },
|
openCreate(){ this.editId=null; this.error=''; this.form={cliente_id:'',descripcion:'',valor:0,fecha:'',fecha_vencimiento:'',notas:''}; this.showModal=true; },
|
||||||
async save(){
|
async save(){
|
||||||
this.saving=true; this.error='';
|
this.saving=true; this.error='';
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<thead class="bg-slate-50 text-slate-500 text-xs uppercase tracking-wide">
|
<thead class="bg-slate-50 text-slate-500 text-xs uppercase tracking-wide">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="px-4 py-3 text-left">Fecha</th>
|
<th class="px-4 py-3 text-left">Fecha</th>
|
||||||
<th class="px-4 py-3 text-left">Entidad</th>
|
<th class="px-4 py-3 text-left">Cliente</th>
|
||||||
<th class="px-4 py-3 text-left">Descripción</th>
|
<th class="px-4 py-3 text-left">Descripción</th>
|
||||||
<th class="px-4 py-3 text-right">Valor</th>
|
<th class="px-4 py-3 text-right">Valor</th>
|
||||||
<th class="px-4 py-3 text-left">Vence</th>
|
<th class="px-4 py-3 text-left">Vence</th>
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
<template x-for="c in items" :key="c.ID">
|
<template x-for="c in items" :key="c.ID">
|
||||||
<tr class="hover:bg-slate-50">
|
<tr class="hover:bg-slate-50">
|
||||||
<td class="px-4 py-3 text-xs text-slate-500" x-text="formatDate(c.fecha)"></td>
|
<td class="px-4 py-3 text-xs text-slate-500" x-text="formatDate(c.fecha)"></td>
|
||||||
<td class="px-4 py-3 text-slate-700 font-medium" x-text="c.entidad?.nombre||'-'"></td>
|
<td class="px-4 py-3 text-slate-700 font-medium" x-text="c.cliente?.nombre||'-'"></td>
|
||||||
<td class="px-4 py-3 text-slate-600" x-text="c.descripcion"></td>
|
<td class="px-4 py-3 text-slate-600" x-text="c.descripcion"></td>
|
||||||
<td class="px-4 py-3 text-right font-semibold text-amber-600" x-text="formatoCOP(c.valor)"></td>
|
<td class="px-4 py-3 text-right font-semibold text-amber-600" x-text="formatoCOP(c.valor)"></td>
|
||||||
<td class="px-4 py-3 text-xs text-slate-500" x-text="formatDate(c.fecha_vencimiento)"></td>
|
<td class="px-4 py-3 text-xs text-slate-500" x-text="formatDate(c.fecha_vencimiento)"></td>
|
||||||
@@ -73,11 +73,11 @@
|
|||||||
<form @submit.prevent="save()">
|
<form @submit.prevent="save()">
|
||||||
<div class="grid grid-cols-2 gap-3">
|
<div class="grid grid-cols-2 gap-3">
|
||||||
<div class="col-span-2">
|
<div class="col-span-2">
|
||||||
<label class="label">Entidad (quien debe)</label>
|
<label class="label">Cliente (quien debe)</label>
|
||||||
<select x-model.number="form.entidad_id" class="input-field w-full" required>
|
<select x-model.number="form.cliente_id" class="input-field w-full" required>
|
||||||
<option value="">Seleccionar...</option>
|
<option value="">Seleccionar...</option>
|
||||||
<template x-for="e in entidades" :key="e.ID">
|
<template x-for="cl in clientes" :key="cl.ID">
|
||||||
<option :value="e.ID" x-text="e.nombre"></option>
|
<option :value="cl.ID" x-text="cl.nombre + (cl.empresa ? ' — ' + cl.empresa : '')"></option>
|
||||||
</template>
|
</template>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@@ -141,10 +141,10 @@
|
|||||||
<script>
|
<script>
|
||||||
function cobroApp() {
|
function cobroApp() {
|
||||||
return {
|
return {
|
||||||
items:[], entidades:[], total:0, totalPages:1, page:1, search:'', filtroEstado:'',
|
items:[], clientes:[], total:0, totalPages:1, page:1, search:'', filtroEstado:'',
|
||||||
loading:false, saving:false, showModal:false, showDelete:false, showPagarModal:false,
|
loading:false, saving:false, showModal:false, showDelete:false, showPagarModal:false,
|
||||||
deleteId:null, pagarId:null, pagoFecha:'', error:'',
|
deleteId:null, pagarId:null, pagoFecha:'', error:'',
|
||||||
form:{ entidad_id:'', descripcion:'', valor:0, fecha:'', fecha_vencimiento:'', notas:'' },
|
form:{ cliente_id:'', descripcion:'', valor:0, fecha:'', fecha_vencimiento:'', notas:'' },
|
||||||
|
|
||||||
async init(){ await this.load(); },
|
async init(){ await this.load(); },
|
||||||
|
|
||||||
@@ -155,12 +155,12 @@ function cobroApp() {
|
|||||||
if(this.filtroEstado) params.set('estado',this.filtroEstado);
|
if(this.filtroEstado) params.set('estado',this.filtroEstado);
|
||||||
const r=await axios.get('/app/contabilidad/cuentas-cobro/list?'+params.toString());
|
const r=await axios.get('/app/contabilidad/cuentas-cobro/list?'+params.toString());
|
||||||
this.items=r.data.items; this.total=r.data.total; this.totalPages=r.data.totalPages;
|
this.items=r.data.items; this.total=r.data.total; this.totalPages=r.data.totalPages;
|
||||||
const er=await axios.get('/app/contabilidad/entidades/select');
|
const er=await axios.get('/app/api/clientes/select');
|
||||||
this.entidades=er.data;
|
this.clientes=er.data;
|
||||||
} finally{ this.loading=false; }
|
} finally{ this.loading=false; }
|
||||||
},
|
},
|
||||||
|
|
||||||
openCreate(){ this.editId=null; this.error=''; this.form={entidad_id:'',descripcion:'',valor:0,fecha:'',fecha_vencimiento:'',notas:''}; this.showModal=true; },
|
openCreate(){ this.editId=null; this.error=''; this.form={cliente_id:'',descripcion:'',valor:0,fecha:'',fecha_vencimiento:'',notas:''}; this.showModal=true; },
|
||||||
async save(){
|
async save(){
|
||||||
this.saving=true; this.error='';
|
this.saving=true; this.error='';
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -408,7 +408,7 @@ func GetCuentasCobro(c *fiber.Ctx) error {
|
|||||||
|
|
||||||
func CreateCuentaCobro(c *fiber.Ctx) error {
|
func CreateCuentaCobro(c *fiber.Ctx) error {
|
||||||
type Req struct {
|
type Req struct {
|
||||||
EntidadID uint `json:"entidad_id"`
|
ClienteID uint `json:"cliente_id"`
|
||||||
Fecha string `json:"fecha"`
|
Fecha string `json:"fecha"`
|
||||||
Descripcion string `json:"descripcion"`
|
Descripcion string `json:"descripcion"`
|
||||||
Valor float64 `json:"valor"`
|
Valor float64 `json:"valor"`
|
||||||
@@ -419,11 +419,11 @@ func CreateCuentaCobro(c *fiber.Ctx) error {
|
|||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
return c.Status(400).JSON(fiber.Map{"error": err.Error()})
|
return c.Status(400).JSON(fiber.Map{"error": err.Error()})
|
||||||
}
|
}
|
||||||
if req.EntidadID == 0 {
|
if req.ClienteID == 0 {
|
||||||
return c.Status(400).JSON(fiber.Map{"error": "entidad_id es requerido"})
|
return c.Status(400).JSON(fiber.Map{"error": "cliente_id es requerido"})
|
||||||
}
|
}
|
||||||
cc := &models.CuentaCobro{
|
cc := &models.CuentaCobro{
|
||||||
EntidadID: req.EntidadID,
|
ClienteID: req.ClienteID,
|
||||||
Descripcion: req.Descripcion,
|
Descripcion: req.Descripcion,
|
||||||
Valor: req.Valor,
|
Valor: req.Valor,
|
||||||
Estado: "pendiente",
|
Estado: "pendiente",
|
||||||
|
|||||||
Reference in New Issue
Block a user