up
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use App\Models\ProductVariant;
|
||||
|
||||
class Bodega extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'nombre',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
];
|
||||
|
||||
/**
|
||||
* Relación many‑to‑many con productos.
|
||||
*/
|
||||
public function productos(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Producto::class, 'producto_bodega')
|
||||
->withPivot('stock')
|
||||
->withTimestamps();
|
||||
}
|
||||
|
||||
/**
|
||||
* Relación many-to-many con variantes.
|
||||
*/
|
||||
public function variantes(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(ProductVariant::class, 'variante_bodega', 'bodega_id', 'variante_id')
|
||||
->withPivot('stock')
|
||||
->withTimestamps();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener el stock total de todos los productos en esta bodega.
|
||||
*/
|
||||
public function getStockTotalAttribute(): int
|
||||
{
|
||||
return $this->productos()->sum('producto_bodega.stock');
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener el stock de un producto específico en esta bodega.
|
||||
*/
|
||||
public function getStockProducto(int $productoId): int
|
||||
{
|
||||
$producto = $this->productos()->where('producto_id', $productoId)->first();
|
||||
return $producto ? $producto->pivot->stock : 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Caja extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'monto_inicial',
|
||||
'monto_final',
|
||||
'fecha_apertura',
|
||||
'fecha_cierre',
|
||||
'estado',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
'monto_inicial' => 'decimal:2',
|
||||
'monto_final' => 'decimal:2',
|
||||
'fecha_apertura' => 'datetime',
|
||||
'fecha_cierre' => 'datetime',
|
||||
];
|
||||
|
||||
public function movimientoscaja()
|
||||
{
|
||||
return $this->hasMany(MovimientoCaja::class);
|
||||
}
|
||||
// Método para calcular el monto final
|
||||
public function calcularMontoFinal()
|
||||
{
|
||||
$ingresos = $this->movimientoscaja()->where('tipo', 'Ingreso')->sum('monto');
|
||||
$egresos = $this->movimientoscaja()->where('tipo', 'Egreso')->sum('monto');
|
||||
return $this->monto_inicial + $ingresos - $egresos;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Categoria extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'nombre',
|
||||
'descripcion',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Cliente extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'nombre',
|
||||
'correo',
|
||||
'telefono',
|
||||
'numero_documento',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Color extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'hex_code',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Compra extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'fecha',
|
||||
'proveedor_id',
|
||||
'total',
|
||||
'estado',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
'fecha' => 'datetime',
|
||||
'proveedor_id' => 'integer',
|
||||
'total' => 'decimal:2',
|
||||
];
|
||||
|
||||
public function proveedor(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Proveedor::class);
|
||||
}
|
||||
|
||||
public function detalles()
|
||||
{
|
||||
return $this->hasMany(DetalleCompra::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Boot del modelo para eventos
|
||||
*/
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
// Al eliminar una compra, eliminar sus detalles
|
||||
static::deleting(function ($compra) {
|
||||
$compra->detalles()->delete();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class DetalleCompra extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'compra_id',
|
||||
'producto_id',
|
||||
'variante_id',
|
||||
'bodega_id',
|
||||
'cantidad',
|
||||
'precio_unitario',
|
||||
'subtotal',
|
||||
'producto_nombre_snapshot',
|
||||
'variante_info_snapshot',
|
||||
'DetalleCompra',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
'compra_id' => 'integer',
|
||||
'producto_id' => 'integer',
|
||||
'variante_id' => 'integer',
|
||||
'bodega_id' => 'integer',
|
||||
'cantidad'=> 'integer',
|
||||
'precio_unitario' => 'decimal:2',
|
||||
'subtotal' => 'decimal:2',
|
||||
];
|
||||
|
||||
public function compra(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Compra::class);
|
||||
}
|
||||
|
||||
public function producto(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Producto::class)->withDefault();
|
||||
}
|
||||
|
||||
public function variante():BelongsTo
|
||||
{
|
||||
return $this->belongsTo(ProductVariant::class)->withDefault();
|
||||
}
|
||||
|
||||
public function bodega(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Bodega::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene el nombre del producto, usando snapshot si el producto fue eliminado
|
||||
*/
|
||||
public function getProductoNombreAttribute(): string
|
||||
{
|
||||
if ($this->producto) {
|
||||
return $this->producto->nombre;
|
||||
}
|
||||
|
||||
return $this->producto_nombre_snapshot ?? 'Producto eliminado';
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene la información de la variante, usando snapshot si la variante fue eliminada
|
||||
*/
|
||||
public function getVarianteInfoAttribute(): ?string
|
||||
{
|
||||
if ($this->variante) {
|
||||
// Validación defensiva para evitar error "name" on null
|
||||
$colorName = $this->variante->color ? $this->variante->color->name : 'Sin color';
|
||||
$sizeName = $this->variante->size ? $this->variante->size->name : 'Sin talla';
|
||||
|
||||
return $colorName . ' / ' . $sizeName;
|
||||
}
|
||||
|
||||
return $this->variante_info_snapshot;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class DetalleVenta extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'venta_id',
|
||||
'producto_id',
|
||||
'variante_id', // <-- agregar aquí
|
||||
'bodega_id', // <-- agregar campo bodega
|
||||
'cantidad',
|
||||
'precio_unitario',
|
||||
'subtotal',
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
'venta_id' => 'integer',
|
||||
'producto_id' => 'integer',
|
||||
'precio_unitario' => 'decimal:2',
|
||||
'subtotal' => 'decimal:2',
|
||||
];
|
||||
|
||||
public function venta(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Venta::class);
|
||||
}
|
||||
|
||||
public function producto(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Producto::class);
|
||||
}
|
||||
|
||||
|
||||
public function variante(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(ProductVariant::class);
|
||||
}
|
||||
|
||||
public function bodega(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Bodega::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Inventario extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'producto_id',
|
||||
'stock_actual',
|
||||
'stock_minimo',
|
||||
'ubicacion',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
'producto_id' => 'integer',
|
||||
];
|
||||
|
||||
public function producto(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Producto::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class MovimientoCaja extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'caja_id',
|
||||
'tipo',
|
||||
'monto',
|
||||
'descripcion',
|
||||
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
'caja_id' => 'integer',
|
||||
'monto' => 'decimal:2',
|
||||
];
|
||||
|
||||
public function caja(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Caja::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Spatie\Permission\Traits\HasRoles;
|
||||
|
||||
class Permission extends Model
|
||||
{
|
||||
use HasFactory, HasRoles;
|
||||
|
||||
protected $fillable = ['name', 'guard_name'];
|
||||
|
||||
protected $attributes = [
|
||||
'guard_name' => 'web', // Establece el valor predeterminado
|
||||
];
|
||||
|
||||
public function roles()
|
||||
{
|
||||
return $this->belongsToMany(Role::class, 'role_has_permissions');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
|
||||
class ProductVariant extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'producto_id',
|
||||
'color_id',
|
||||
'size_id',
|
||||
'stock',
|
||||
'sku',
|
||||
'barcode'
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
];
|
||||
|
||||
public function producto(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Producto::class);
|
||||
}
|
||||
|
||||
public function color(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Color::class);
|
||||
}
|
||||
|
||||
public function size(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Size::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Relación many-to-many con bodegas
|
||||
*/
|
||||
public function bodegas(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Bodega::class, 'variante_bodega', 'variante_id', 'bodega_id')
|
||||
->withPivot('stock')
|
||||
->withTimestamps();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener el stock total de la variante en todas las bodegas
|
||||
*/
|
||||
public function getStockTotalBodegas(): int
|
||||
{
|
||||
try {
|
||||
return $this->bodegas()->sum('variante_bodega.stock');
|
||||
} catch (\Exception $e) {
|
||||
// En caso de error, retornar 0
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener el stock efectivo de la variante (considerando bodegas si existen)
|
||||
*/
|
||||
public function getStockEfectivo(): int
|
||||
{
|
||||
try {
|
||||
// Si tiene distribución en bodegas, usar ese stock
|
||||
if ($this->bodegas()->exists()) {
|
||||
return $this->getStockTotalBodegas();
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// En caso de error (tabla no existe, etc.), usar stock directo
|
||||
// Esto puede ocurrir durante migraciones o configuración inicial
|
||||
}
|
||||
|
||||
// Stock directo de la variante
|
||||
return $this->stock;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Filament\Actions\Concerns\BelongsToGroup;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
|
||||
class Producto extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'nombre',
|
||||
'descripcion',
|
||||
'codigo_barras',
|
||||
'precio_compra',
|
||||
'precio_venta',
|
||||
'stock',
|
||||
'categoria_id',
|
||||
'estado',
|
||||
'imagen',
|
||||
'stock_minimo',
|
||||
'stock_maximo',
|
||||
'unidad_medida'
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
'estado' => 'boolean',
|
||||
];
|
||||
|
||||
public function variants(): HasMany
|
||||
{
|
||||
return $this->hasMany(ProductVariant::class);
|
||||
}
|
||||
public function categoria(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Categoria::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Relación many-to-many con bodegas
|
||||
*/
|
||||
public function bodegas(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Bodega::class, 'producto_bodega')
|
||||
->withPivot('stock')
|
||||
->withTimestamps();
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene las unidades de medida disponibles
|
||||
*/
|
||||
public static function getUnidadesMedida(): array
|
||||
{
|
||||
return [
|
||||
'unidad' => 'Unidad (1)',
|
||||
'docena' => 'Docena (12)',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene el factor de conversión para una unidad de medida
|
||||
*/
|
||||
public static function getFactorConversion(string $unidad): int
|
||||
{
|
||||
$factores = [
|
||||
'unidad' => 1,
|
||||
'docena' => 12,
|
||||
];
|
||||
|
||||
return $factores[$unidad] ?? 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convierte una cantidad en la unidad especificada a unidades individuales
|
||||
*/
|
||||
public static function convertirAUnidades(float $cantidad, string $unidad): int
|
||||
{
|
||||
return (int) ($cantidad * self::getFactorConversion($unidad));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convierte unidades individuales a la unidad de medida especificada
|
||||
*/
|
||||
public static function convertirDesdeUnidades(int $unidades, string $unidad): float
|
||||
{
|
||||
$factor = self::getFactorConversion($unidad);
|
||||
return $factor > 1 ? round($unidades / $factor, 2) : $unidades;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene el stock en la unidad de medida configurada
|
||||
*/
|
||||
public function getStockEnUnidadMedida(): float
|
||||
{
|
||||
$stockTotal = $this->variants()->exists()
|
||||
? $this->variants()->sum('stock')
|
||||
: $this->stock;
|
||||
|
||||
return self::convertirDesdeUnidades($stockTotal, $this->unidad_medida ?? 'unidad');
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtiene el nombre de la unidad de medida
|
||||
*/
|
||||
public function getNombreUnidadMedida(): string
|
||||
{
|
||||
$unidades = self::getUnidadesMedida();
|
||||
return $unidades[$this->unidad_medida ?? 'unidad'] ?? 'Unidad (1)';
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener el stock total en todas las bodegas
|
||||
*/
|
||||
public function getStockTotalBodegas(): int
|
||||
{
|
||||
return $this->bodegas()->sum('producto_bodega.stock');
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener el stock en una bodega específica
|
||||
*/
|
||||
public function getStockEnBodega(int $bodegaId): int
|
||||
{
|
||||
$bodega = $this->bodegas()->where('bodega_id', $bodegaId)->first();
|
||||
return $bodega ? $bodega->pivot->stock : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener el stock total en una bodega específica (considerando variantes)
|
||||
*/
|
||||
public function getStockTotalEnBodega(int $bodegaId): int
|
||||
{
|
||||
if ($this->variants()->exists()) {
|
||||
$stockVariantes = 0;
|
||||
foreach ($this->variants as $variante) {
|
||||
$bodegaVariante = $variante->bodegas()->where('bodega_id', $bodegaId)->first();
|
||||
if ($bodegaVariante) {
|
||||
$stockVariantes += $bodegaVariante->pivot->stock;
|
||||
}
|
||||
}
|
||||
return $stockVariantes;
|
||||
} else {
|
||||
return $this->getStockEnBodega($bodegaId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Distribuir stock total entre bodegas
|
||||
*/
|
||||
public function distribuirStock(array $distribucion): void
|
||||
{
|
||||
foreach ($distribucion as $bodegaId => $stock) {
|
||||
$this->bodegas()->syncWithoutDetaching([
|
||||
$bodegaId => ['stock' => $stock]
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtener el stock efectivo (considerando bodegas Y variantes correctamente)
|
||||
*/
|
||||
public function getStockEfectivo(): int
|
||||
{
|
||||
// Si tiene variantes, el stock se calcula desde las variantes
|
||||
if ($this->variants()->exists()) {
|
||||
$stockVariantes = 0;
|
||||
|
||||
foreach ($this->variants as $variante) {
|
||||
$stockVariantes += $variante->getStockEfectivo();
|
||||
}
|
||||
|
||||
return $stockVariantes;
|
||||
} else {
|
||||
// Para productos sin variantes
|
||||
if ($this->bodegas()->exists()) {
|
||||
return $this->getStockTotalBodegas();
|
||||
} else {
|
||||
return $this->stock;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor para código de barras dinámico
|
||||
*/
|
||||
public function getCodigoBarrasAttribute($value)
|
||||
{
|
||||
// Si el producto tiene variantes, el código de barras es NULL
|
||||
if ($this->variants()->exists()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Si NO tiene variantes, usa su código de barras propio
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accessor para stock dinámico
|
||||
* Si el producto tiene variantes, el stock directo debe ser 0
|
||||
*/
|
||||
public function getStockAttribute($value)
|
||||
{
|
||||
// Si el producto tiene variantes, el stock directo debe ser 0
|
||||
if ($this->variants()->exists()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Si NO tiene variantes, devuelve el stock real
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mutator para stock - evita que se asigne stock directo si hay variantes
|
||||
*/
|
||||
public function setStockAttribute($value)
|
||||
{
|
||||
// Si el producto ya tiene variantes, no permitir stock directo
|
||||
if ($this->exists && $this->variants()->exists()) {
|
||||
$this->attributes['stock'] = 0;
|
||||
} else {
|
||||
$this->attributes['stock'] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Relación con detalles de compra
|
||||
*/
|
||||
public function detalleCompras(): HasMany
|
||||
{
|
||||
return $this->hasMany(DetalleCompra::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Relación con detalles de venta
|
||||
*/
|
||||
public function detalleVentas(): HasMany
|
||||
{
|
||||
return $this->hasMany(DetalleVenta::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Proveedor extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'nombre',
|
||||
'contacto',
|
||||
'telefono',
|
||||
'correo',
|
||||
'direccion',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Spatie\Permission\Models\Role as SpatieRole;
|
||||
|
||||
class Role extends SpatieRole
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'guard_name', // Necesario para Spatie Permissions
|
||||
'description',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the users that belong to the role.
|
||||
*/
|
||||
public function users(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(User::class, 'model_has_roles', 'role_id', 'model_id');
|
||||
}
|
||||
public function permissions(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Permission::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Setting extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'logo',
|
||||
'description',
|
||||
'primary_color',
|
||||
'secondary_color',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
'created_at' => 'timestamp',
|
||||
'updated_at' => 'timestamp',
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Size extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class TransferenciaBodega extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'transferencias_bodega';
|
||||
|
||||
protected $fillable = [
|
||||
'producto_id',
|
||||
'variante_id',
|
||||
'bodega_origen_id',
|
||||
'bodega_destino_id',
|
||||
'cantidad',
|
||||
'motivo',
|
||||
'usuario_id',
|
||||
'fecha_transferencia',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'fecha_transferencia' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
* Relación con el producto
|
||||
*/
|
||||
public function producto(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Producto::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Relación con la variante (opcional)
|
||||
*/
|
||||
public function variante(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(ProductVariant::class, 'variante_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Relación con la bodega de origen
|
||||
*/
|
||||
public function bodegaOrigen(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Bodega::class, 'bodega_origen_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Relación con la bodega de destino
|
||||
*/
|
||||
public function bodegaDestino(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Bodega::class, 'bodega_destino_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Relación con el usuario que realizó la transferencia
|
||||
*/
|
||||
public function usuario(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'usuario_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Spatie\Permission\Traits\HasRoles;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasApiTokens, HasFactory, Notifiable, HasRoles;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'email',
|
||||
'password',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be hidden for serialization.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $hidden = [
|
||||
'password',
|
||||
'remember_token',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'email_verified_at' => 'datetime',
|
||||
'password' => 'hashed', // Laravel 10+ soporta casting a hashed
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the roles associated with the user.
|
||||
*/
|
||||
public function roles(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Role::class);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class Venta extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'cliente_id',
|
||||
'total',
|
||||
'tipo_pago',
|
||||
'estado',
|
||||
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'integer',
|
||||
'fecha' => 'datetime',
|
||||
'cliente_id' => 'integer',
|
||||
'total' => 'decimal:2',
|
||||
];
|
||||
|
||||
public function cliente(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Cliente::class);
|
||||
}
|
||||
|
||||
public function detalles(): HasMany
|
||||
{
|
||||
return $this->hasMany(DetalleVenta::class);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user