up
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
namespace App\Observers;
|
||||
|
||||
use App\Models\Compra;
|
||||
use App\Models\Producto;
|
||||
use App\Models\ProductVariant;
|
||||
use App\Models\Bodega;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class CompraObserver
|
||||
{
|
||||
/**
|
||||
* Handle the Compra "created" event.
|
||||
*/
|
||||
public function created(Compra $compra): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Compra "updated" event.
|
||||
*/
|
||||
public function updated(Compra $compra): void
|
||||
{
|
||||
// Solo procesar cuando el estado cambie a 'Recibida'
|
||||
if ($compra->isDirty('estado') && $compra->estado === 'Recibida') {
|
||||
Log::info("Procesando compra recibida", [
|
||||
'compra_id' => $compra->id,
|
||||
'detalles_count' => $compra->detalles->count()
|
||||
]);
|
||||
|
||||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
foreach ($compra->detalles as $detalle) {
|
||||
Log::info("Procesando detalle de compra", [
|
||||
'detalle_id' => $detalle->id,
|
||||
'producto_id' => $detalle->producto_id,
|
||||
'variante_id' => $detalle->variante_id,
|
||||
'bodega_id' => $detalle->bodega_id,
|
||||
'cantidad' => $detalle->cantidad
|
||||
]);
|
||||
|
||||
if ($detalle->variante_id) {
|
||||
// Manejo para variantes
|
||||
$variante = ProductVariant::find($detalle->variante_id);
|
||||
if ($variante && $detalle->bodega_id) {
|
||||
// Actualizar stock en bodega para la variante
|
||||
$existeRelacion = $variante->bodegas()
|
||||
->where('bodega_id', $detalle->bodega_id)
|
||||
->exists();
|
||||
|
||||
if ($existeRelacion) {
|
||||
// Incrementar stock existente
|
||||
$pivotData = $variante->bodegas()
|
||||
->where('bodega_id', $detalle->bodega_id)
|
||||
->first();
|
||||
|
||||
$nuevoStock = $pivotData->pivot->stock + $detalle->cantidad;
|
||||
|
||||
$variante->bodegas()->updateExistingPivot($detalle->bodega_id, [
|
||||
'stock' => $nuevoStock
|
||||
]);
|
||||
} else {
|
||||
// Crear nueva relación con stock
|
||||
$variante->bodegas()->attach($detalle->bodega_id, [
|
||||
'stock' => $detalle->cantidad
|
||||
]);
|
||||
}
|
||||
|
||||
Log::info("Stock actualizado para variante en bodega", [
|
||||
'variante_id' => $variante->id,
|
||||
'bodega_id' => $detalle->bodega_id,
|
||||
'cantidad_agregada' => $detalle->cantidad
|
||||
]);
|
||||
} else {
|
||||
// Fallback: incrementar stock directo de la variante si no hay bodega especificada
|
||||
ProductVariant::where('id', $detalle->variante_id)
|
||||
->increment('stock', $detalle->cantidad);
|
||||
|
||||
Log::info("Stock incrementado directamente en variante (sin bodega)", [
|
||||
'variante_id' => $detalle->variante_id,
|
||||
'cantidad' => $detalle->cantidad
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
// Manejo para productos sin variantes
|
||||
$producto = Producto::find($detalle->producto_id);
|
||||
if ($producto && $detalle->bodega_id) {
|
||||
// Actualizar stock en bodega para el producto
|
||||
$existeRelacion = $producto->bodegas()
|
||||
->where('bodega_id', $detalle->bodega_id)
|
||||
->exists();
|
||||
|
||||
if ($existeRelacion) {
|
||||
// Incrementar stock existente
|
||||
$pivotData = $producto->bodegas()
|
||||
->where('bodega_id', $detalle->bodega_id)
|
||||
->first();
|
||||
|
||||
$nuevoStock = $pivotData->pivot->stock + $detalle->cantidad;
|
||||
|
||||
$producto->bodegas()->updateExistingPivot($detalle->bodega_id, [
|
||||
'stock' => $nuevoStock
|
||||
]);
|
||||
} else {
|
||||
// Crear nueva relación con stock
|
||||
$producto->bodegas()->attach($detalle->bodega_id, [
|
||||
'stock' => $detalle->cantidad
|
||||
]);
|
||||
}
|
||||
|
||||
Log::info("Stock actualizado para producto en bodega", [
|
||||
'producto_id' => $producto->id,
|
||||
'bodega_id' => $detalle->bodega_id,
|
||||
'cantidad_agregada' => $detalle->cantidad
|
||||
]);
|
||||
} else {
|
||||
// Fallback: incrementar stock directo del producto si no hay bodega especificada
|
||||
Producto::where('id', $detalle->producto_id)
|
||||
->increment('stock', $detalle->cantidad);
|
||||
|
||||
Log::info("Stock incrementado directamente en producto (sin bodega)", [
|
||||
'producto_id' => $detalle->producto_id,
|
||||
'cantidad' => $detalle->cantidad
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
Log::info("Compra procesada exitosamente", ['compra_id' => $compra->id]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
Log::error("Error al procesar compra recibida", [
|
||||
'compra_id' => $compra->id,
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString()
|
||||
]);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Compra "deleted" event.
|
||||
*/
|
||||
public function deleted(Compra $compra): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Compra "restored" event.
|
||||
*/
|
||||
public function restored(Compra $compra): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the Compra "force deleted" event.
|
||||
*/
|
||||
public function forceDeleted(Compra $compra): void
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Observers;
|
||||
|
||||
use App\Models\DetalleCompra;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class DetalleCompraObserver
|
||||
{
|
||||
/**
|
||||
* Handle the DetalleCompra "saving" event.
|
||||
*/
|
||||
public function saving(DetalleCompra $detalle): void
|
||||
{
|
||||
// Guardar snapshot del producto si existe y no hay snapshot previo
|
||||
if ($detalle->producto && empty($detalle->producto_nombre_snapshot)) {
|
||||
$detalle->producto_nombre_snapshot = $detalle->producto->nombre;
|
||||
|
||||
Log::info("Snapshot de producto guardado", [
|
||||
'detalle_id' => $detalle->id,
|
||||
'producto_id' => $detalle->producto_id,
|
||||
'producto_nombre' => $detalle->producto_nombre_snapshot
|
||||
]);
|
||||
}
|
||||
|
||||
// Guardar snapshot de variante si existe y no hay snapshot previo
|
||||
if ($detalle->variante && empty($detalle->variante_info_snapshot)) {
|
||||
// Validación defensiva para evitar error "name" on null
|
||||
$colorName = $detalle->variante->color ? $detalle->variante->color->name : 'Sin color';
|
||||
$sizeName = $detalle->variante->size ? $detalle->variante->size->name : 'Sin talla';
|
||||
|
||||
$detalle->variante_info_snapshot = $colorName . ' / ' . $sizeName;
|
||||
|
||||
Log::info("Snapshot de variante guardado", [
|
||||
'detalle_id' => $detalle->id,
|
||||
'variante_id' => $detalle->variante_id,
|
||||
'variante_info' => $detalle->variante_info_snapshot
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace App\Observers;
|
||||
|
||||
use App\Models\ProductVariant;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class ProductVariantObserver
|
||||
{
|
||||
/**
|
||||
* Handle the ProductVariant "created" event.
|
||||
*/
|
||||
public function created(ProductVariant $variant): void
|
||||
{
|
||||
$producto = $variant->producto;
|
||||
|
||||
Log::info("Variante creada para producto", [
|
||||
'variante_id' => $variant->id,
|
||||
'producto_id' => $producto->id,
|
||||
'producto_nombre' => $producto->nombre,
|
||||
'stock_producto_anterior' => $producto->stock
|
||||
]);
|
||||
|
||||
// Si este producto ahora tiene variantes y tenía stock directo, limpiar el stock principal
|
||||
if ($producto->stock > 0) {
|
||||
// Obtener el stock anterior para potencial transferencia
|
||||
$stockAnterior = $producto->stock;
|
||||
|
||||
// Limpiar el stock del producto principal
|
||||
$producto->update(['stock' => 0]);
|
||||
|
||||
Log::info("Stock del producto principal limpiado debido a creación de variantes", [
|
||||
'producto_id' => $producto->id,
|
||||
'stock_anterior' => $stockAnterior,
|
||||
'stock_nuevo' => 0
|
||||
]);
|
||||
|
||||
// Opcionalmente, podrías transferir el stock anterior a la nueva variante
|
||||
// o a una bodega específica, pero por ahora solo lo eliminamos
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the ProductVariant "deleting" event.
|
||||
*/
|
||||
public function deleting(ProductVariant $variant): void
|
||||
{
|
||||
$producto = $variant->producto;
|
||||
|
||||
// Verificar si esta es la última variante
|
||||
$variantesRestantes = $producto->variants()->where('id', '!=', $variant->id)->count();
|
||||
|
||||
Log::info("Eliminando variante", [
|
||||
'variante_id' => $variant->id,
|
||||
'producto_id' => $producto->id,
|
||||
'variantes_restantes' => $variantesRestantes
|
||||
]);
|
||||
|
||||
// Si esta era la última variante, el producto vuelve a poder tener stock directo
|
||||
if ($variantesRestantes === 0) {
|
||||
Log::info("Última variante eliminada - producto puede volver a tener stock directo", [
|
||||
'producto_id' => $producto->id
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Observers;
|
||||
|
||||
use App\Models\Producto;
|
||||
use App\Models\User;
|
||||
use App\Notifications\StockMinimoNotificacion;
|
||||
use App\Mail\AlertaStockMail;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class ProductoObserver
|
||||
{
|
||||
public function saved(Producto $producto): void
|
||||
{
|
||||
// Solo verificar si no es un producto recién creado
|
||||
if ($producto->wasRecentlyCreated) {
|
||||
return;
|
||||
}
|
||||
|
||||
$stockActual = $producto->getStockEfectivo();
|
||||
|
||||
$alertaStockMinimo = collect();
|
||||
$alertaStockMaximo = collect();
|
||||
|
||||
// Verificar stock mínimo
|
||||
if ($stockActual <= $producto->stock_minimo && $producto->stock_minimo > 0) {
|
||||
$alertaStockMinimo->push($producto);
|
||||
Log::info("Stock mínimo alcanzado para producto: {$producto->nombre} (Stock: {$stockActual})");
|
||||
}
|
||||
|
||||
// Verificar stock máximo
|
||||
if ($producto->stock_maximo && $stockActual > $producto->stock_maximo) {
|
||||
$alertaStockMaximo->push($producto);
|
||||
Log::info("Stock máximo excedido para producto: {$producto->nombre} (Stock: {$stockActual})");
|
||||
}
|
||||
|
||||
// Enviar alertas si hay productos que requieren atención
|
||||
if ($alertaStockMinimo->isNotEmpty() || $alertaStockMaximo->isNotEmpty()) {
|
||||
$this->enviarAlertasStock($alertaStockMinimo, $alertaStockMaximo);
|
||||
}
|
||||
}
|
||||
|
||||
private function enviarAlertasStock($productosStockMinimo, $productosStockMaximo)
|
||||
{
|
||||
// Obtener todos los usuarios con el rol 'Administrador'
|
||||
$administradores = User::role('Administrador')->get();
|
||||
|
||||
if ($administradores->isEmpty()) {
|
||||
Log::warning('No se encontraron usuarios con el rol Administrador para enviar alertas de stock.');
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($administradores as $admin) {
|
||||
try {
|
||||
// Enviar usando el nuevo sistema de alertas
|
||||
Mail::to($admin->email)->send(new AlertaStockMail(
|
||||
$productosStockMinimo,
|
||||
$productosStockMaximo,
|
||||
$admin->email
|
||||
));
|
||||
|
||||
Log::info("Alerta de stock enviada a: {$admin->email}");
|
||||
} catch (\Exception $e) {
|
||||
Log::error("Error al enviar alerta de stock a {$admin->email}: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user