Files
pos_heidiver/app/Models/ProcesoAcabado.php
T
2026-02-09 15:09:15 -05:00

147 lines
5.0 KiB
PHP

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
class ProcesoAcabado extends Model
{
protected $fillable = [
'orden_produccion_id',
'tipo_proceso',
'proveedor_id',
'distribucion_proveedores',
'responsable_interno',
'cantidad_enviada',
'cantidad_recibida',
'fecha_envio',
'fecha_recepcion',
'terminada',
'observaciones',
];
protected $casts = [
'distribucion_proveedores' => 'array',
'terminada' => 'boolean',
'fecha_envio' => 'date',
'fecha_recepcion' => 'date',
];
/* Relaciones */
public function ordenProduccion()
{
return $this->belongsTo(OrdenProduccion::class);
}
public function proveedor()
{
return $this->belongsTo(Proveedor::class);
}
/* Recepciones polimórficas */
public function recepciones()
{
return $this->morphMany(\App\Models\Recepcion::class, 'referencia');
}
public function cobros()
{
return $this->morphMany(\App\Models\Cobro::class, 'referencia');
}
public function ajustes()
{
return $this->morphMany(\App\Models\Ajuste::class, 'referencia');
}
// Total recibido calculado desde recepciones (fuente de verdad)
// Menos reprocesos (permiten re-recepción)
public function getRecibidoTotalAttribute()
{
$recepciones = (int) $this->recepciones()->sum(DB::raw('cantidad - COALESCE(prendas_defectuosas, 0)'));
$reprocesos = (int) $this->ajustes()->where('tipo', 'reproceso')->sum('cantidad');
return max(0, $recepciones - $reprocesos);
}
// Total de pérdidas registradas en las recepciones
public function getPerdidasTotalAttribute()
{
return (int) $this->recepciones()->sum('prendas_defectuosas');
}
public function getCobrosTotalAttribute()
{
return (float) $this->cobros()->sum('valor');
}
// Cuantas faltan por recibir
public function getFaltantesAttribute()
{
$enviada = (int)($this->cantidad_enviada ?? 0);
$recepciones = (int) $this->recepciones()->sum(DB::raw('cantidad - COALESCE(prendas_defectuosas, 0)'));
$reprocesos = (int) $this->ajustes()->where('tipo', 'reproceso')->sum('cantidad');
// Lo que puede recibir = enviadas - recepciones + reprocesos (reprocesos permiten re-recepción)
return max(0, $enviada - $recepciones + $reprocesos);
}
// Estado de recepción (Parcial / Completado)
public function getEstadoRecepcionAttribute()
{
$faltan = $this->faltantes ?? 0;
if (($this->cantidad_enviada ?? 0) <= 0) {
return 'Sin envío';
}
return $faltan > 0 ? 'Parcial' : 'Completado';
}
/* Lógica de negocio */
protected static function booted()
{
static::saving(function ($acabado) {
// Fecha de envío por defecto
if (! $acabado->fecha_envio) {
$acabado->fecha_envio = now();
}
// Validación: cantidad_enviada no puede exceder lo enviado desde Tintorería (cantidad recibida allí)
if ($acabado->cantidad_enviada !== null && $acabado->orden_produccion_id) {
$sumTint = \App\Models\Tintoreria::where('orden_produccion_id', $acabado->orden_produccion_id)->sum('cantidad_recibida');
if ($sumTint && $acabado->cantidad_enviada > $sumTint) {
throw \Illuminate\Validation\ValidationException::withMessages([
'cantidad_enviada' => 'La cantidad enviada no puede exceder lo recibido en Tintorería (' . $sumTint . ').',
]);
}
}
});
// Al guardar recepciones, avanzar estado de la OP
static::saved(function ($acabado) {
// Verificar si el proceso está completado (todas las prendas recibidas)
$faltantes = $acabado->faltantes ?? 0;
if ($faltantes === 0 && ($acabado->cantidad_enviada ?? 0) > 0) {
// Avanzar la OP al completar este proceso
$acabado->ordenProduccion?->avanzarEstado();
// Validar si ya no quedan procesos pendientes
$pendientes = self::where('orden_produccion_id', $acabado->orden_produccion_id)
->where(function($q) {
$q->whereNull('cantidad_enviada')
->orWhereRaw('cantidad_enviada > 0 AND (SELECT COALESCE(SUM(cantidad - COALESCE(prendas_defectuosas, 0)), 0) FROM recepciones WHERE referencia_type = ? AND referencia_id = proceso_acabados.id) < cantidad_enviada', [self::class]);
})
->exists();
if (!$pendientes) {
// Intentar finalizar la OP solo si está completada según la lógica centralizada
$acabado->ordenProduccion?->tryFinalize();
}
}
});
}
}