up
This commit is contained in:
@@ -74,6 +74,39 @@ class InventarioPrendaResource extends Resource
|
||||
->required(),
|
||||
])
|
||||
->columns(2),
|
||||
|
||||
Section::make('Distribución')
|
||||
->schema([
|
||||
\Filament\Forms\Components\Repeater::make('distribuciones')
|
||||
->label('Distribuciones por bodega / color / talla')
|
||||
->schema([
|
||||
Select::make('bodega_id')
|
||||
->label('Bodega')
|
||||
->relationship('bodega', 'nombre')
|
||||
->required(),
|
||||
|
||||
Select::make('color_id')
|
||||
->label('Color')
|
||||
->relationship('color', 'nombre')
|
||||
->nullable(),
|
||||
|
||||
Select::make('size_id')
|
||||
->label('Talla')
|
||||
->relationship('size', 'nombre')
|
||||
->nullable(),
|
||||
|
||||
TextInput::make('cantidad')
|
||||
->label('Cantidad')
|
||||
->numeric()
|
||||
->required()
|
||||
->minValue(1),
|
||||
])
|
||||
->columns(1)
|
||||
->dehydrated(false)
|
||||
->minItems(0)
|
||||
->helpMessage('Agrega una o varias filas para distribuir la cantidad terminada entre bodegas/variantes.'),
|
||||
])
|
||||
->columns(1),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -118,7 +151,7 @@ class InventarioPrendaResource extends Resource
|
||||
public static function getRelations(): array
|
||||
{
|
||||
return [
|
||||
//
|
||||
RelationManagers\DistribucionesRelationManager::class,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,137 @@ use App\Filament\Resources\InventarioPrendaResource;
|
||||
use Filament\Actions;
|
||||
use Filament\Resources\Pages\CreateRecord;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use App\Models\ProductVariant;
|
||||
use App\Models\InventarioPrendaDistribucion;
|
||||
|
||||
class CreateInventarioPrenda extends CreateRecord
|
||||
{
|
||||
protected static string $resource = InventarioPrendaResource::class;
|
||||
|
||||
protected function handleRecordCreation(array $data): \Illuminate\Database\Eloquent\Model
|
||||
{
|
||||
$distribuciones = $data['distribuciones'] ?? [];
|
||||
$cantidadTerminada = $data['cantidad_terminada'] ?? 0;
|
||||
|
||||
// Validación: la suma de las distribuciones no puede exceder la cantidad terminada
|
||||
$sum = 0;
|
||||
foreach ($distribuciones as $d) {
|
||||
$sum += intval($d['cantidad'] ?? 0);
|
||||
}
|
||||
|
||||
if ($sum > $cantidadTerminada) {
|
||||
throw ValidationException::withMessages(['distribuciones' => 'La suma de las cantidades asignadas excede la cantidad terminada.']);
|
||||
}
|
||||
|
||||
// Remover distribuciones del payload antes de crear el registro principal
|
||||
unset($data['distribuciones']);
|
||||
|
||||
$record = parent::handleRecordCreation($data);
|
||||
|
||||
// Procesar distribuciones y actualizar stock en bodegas
|
||||
foreach ($distribuciones as $d) {
|
||||
$cantidad = intval($d['cantidad'] ?? 0);
|
||||
if ($cantidad <= 0) continue;
|
||||
|
||||
// Crear registro de distribución
|
||||
$created = InventarioPrendaDistribucion::create([
|
||||
'inventario_prenda_id' => $record->id,
|
||||
'bodega_id' => $d['bodega_id'] ?? null,
|
||||
'color_id' => $d['color_id'] ?? null,
|
||||
'size_id' => $d['size_id'] ?? null,
|
||||
'cantidad' => $cantidad,
|
||||
]);
|
||||
|
||||
// Actualizar stock en bodegas
|
||||
$bodegaId = $d['bodega_id'] ?? null;
|
||||
|
||||
// Si tiene color y talla -> variante
|
||||
if (!empty($d['color_id']) && !empty($d['size_id'])) {
|
||||
$productoId = $record->producto_id ?? ($record->ordenProduccion->producto_id ?? null);
|
||||
|
||||
// Si no hay producto, intentar obtener por OP
|
||||
if (! $productoId && $record->ordenProduccion) {
|
||||
$productoId = $record->ordenProduccion->producto_id;
|
||||
}
|
||||
|
||||
if ($productoId) {
|
||||
$variant = ProductVariant::firstOrCreate(
|
||||
[
|
||||
'producto_id' => $productoId,
|
||||
'color_id' => $d['color_id'],
|
||||
'size_id' => $d['size_id'],
|
||||
],
|
||||
[
|
||||
'stock' => 0,
|
||||
'sku' => null,
|
||||
'barcode' => null,
|
||||
]
|
||||
);
|
||||
|
||||
$existing = DB::table('variante_bodega')
|
||||
->where('variante_id', $variant->id)
|
||||
->where('bodega_id', $bodegaId)
|
||||
->first();
|
||||
|
||||
if ($existing) {
|
||||
DB::table('variante_bodega')
|
||||
->where('variante_id', $variant->id)
|
||||
->where('bodega_id', $bodegaId)
|
||||
->update([
|
||||
'stock' => ($existing->stock ?? 0) + $cantidad,
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
} else {
|
||||
DB::table('variante_bodega')->insert([
|
||||
'variante_id' => $variant->id,
|
||||
'bodega_id' => $bodegaId,
|
||||
'stock' => $cantidad,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
// También incrementar stock total de la variante
|
||||
$variant->increment('stock', $cantidad);
|
||||
}
|
||||
} else {
|
||||
// Producto a nivel general
|
||||
$productoId = $record->producto_id ?? ($record->ordenProduccion->producto_id ?? null);
|
||||
if ($productoId) {
|
||||
$existing = DB::table('producto_bodega')
|
||||
->where('producto_id', $productoId)
|
||||
->where('bodega_id', $bodegaId)
|
||||
->first();
|
||||
|
||||
if ($existing) {
|
||||
DB::table('producto_bodega')
|
||||
->where('producto_id', $productoId)
|
||||
->where('bodega_id', $bodegaId)
|
||||
->update([
|
||||
'stock' => ($existing->stock ?? 0) + $cantidad,
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
} else {
|
||||
DB::table('producto_bodega')->insert([
|
||||
'producto_id' => $productoId,
|
||||
'bodega_id' => $bodegaId,
|
||||
'stock' => $cantidad,
|
||||
'created_at' => now(),
|
||||
'updated_at' => now(),
|
||||
]);
|
||||
}
|
||||
|
||||
// Incrementar stock total del producto si no tiene variantes
|
||||
$prod = \App\Models\Producto::find($productoId);
|
||||
if ($prod && ! $prod->variants()->exists()) {
|
||||
$prod->increment('stock', $cantidad);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $record;
|
||||
}
|
||||
}
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Resources\InventarioPrendaResource\RelationManagers;
|
||||
|
||||
use Filament\Resources\RelationManagers\RelationManager;
|
||||
use Filament\Tables;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
class DistribucionesRelationManager extends RelationManager
|
||||
{
|
||||
protected static string $relationship = 'distribuciones';
|
||||
|
||||
protected static ?string $recordTitleAttribute = 'id';
|
||||
|
||||
public function form(Form $form): Form
|
||||
{
|
||||
return $form->schema([
|
||||
Forms\Components\Select::make('bodega_id')->relationship('bodega', 'nombre')->required(),
|
||||
Forms\Components\Select::make('color_id')->relationship('color', 'nombre')->nullable(),
|
||||
Forms\Components\Select::make('size_id')->relationship('size', 'nombre')->nullable(),
|
||||
Forms\Components\TextInput::make('cantidad')->numeric()->required()->minValue(1),
|
||||
]);
|
||||
}
|
||||
|
||||
public function table(Table $table): Table
|
||||
{
|
||||
return $table->columns([
|
||||
Tables\Columns\TextColumn::make('bodega.nombre')->label('Bodega'),
|
||||
Tables\Columns\TextColumn::make('color.nombre')->label('Color'),
|
||||
Tables\Columns\TextColumn::make('size.nombre')->label('Talla'),
|
||||
Tables\Columns\TextColumn::make('cantidad'),
|
||||
Tables\Columns\TextColumn::make('created_at')->label('Creado')->dateTime(),
|
||||
])->filters([
|
||||
//
|
||||
])->headerActions([
|
||||
Tables\Actions\CreateAction::make(),
|
||||
])->actions([
|
||||
Tables\Actions\EditAction::make(),
|
||||
Tables\Actions\DeleteAction::make(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -34,13 +34,10 @@ class TelaResource extends Resource
|
||||
|
||||
TextInput::make('codigo')->required()->unique(ignoreRecord: true),
|
||||
|
||||
Select::make('tipo')
|
||||
->options([
|
||||
'algodon' => 'Algodón',
|
||||
'poliester' => 'Poliéster',
|
||||
'denim' => 'Denim',
|
||||
])
|
||||
->required(),
|
||||
TextInput::make('tipo')
|
||||
->label('Tipo de tela')
|
||||
->required()
|
||||
->helperText('Ej: Algodón, Poliéster, Denim'),
|
||||
|
||||
FileUpload::make('foto')->image()->directory('telas')->disk('public')->visibility('public')->maxSize(1024)->imageEditor()->imageEditorAspectRatios(['16:9','4:3','1:1'])->helperText('Selecciona una imagen de la tela (máx. 1MB)')->acceptedFileTypes(['image/jpeg', 'image/png', 'image/webp'])->downloadable()->openable()->nullable()
|
||||
,
|
||||
|
||||
@@ -25,6 +25,11 @@ class InventarioPrenda extends Model
|
||||
return $this->belongsTo(\App\Models\Producto::class, 'producto_id');
|
||||
}
|
||||
|
||||
public function distribuciones()
|
||||
{
|
||||
return $this->hasMany(\App\Models\InventarioPrendaDistribucion::class, 'inventario_prenda_id');
|
||||
}
|
||||
|
||||
protected static function booted()
|
||||
{
|
||||
static::creating(function ($inventario) {
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class InventarioPrendaDistribucion extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'inventario_prenda_distribuciones';
|
||||
|
||||
protected $fillable = [
|
||||
'inventario_prenda_id',
|
||||
'bodega_id',
|
||||
'color_id',
|
||||
'size_id',
|
||||
'cantidad',
|
||||
];
|
||||
|
||||
public function inventarioPrenda()
|
||||
{
|
||||
return $this->belongsTo(InventarioPrenda::class);
|
||||
}
|
||||
|
||||
public function bodega()
|
||||
{
|
||||
return $this->belongsTo(Bodega::class);
|
||||
}
|
||||
|
||||
public function color()
|
||||
{
|
||||
return $this->belongsTo(Color::class);
|
||||
}
|
||||
|
||||
public function size()
|
||||
{
|
||||
return $this->belongsTo(Size::class);
|
||||
}
|
||||
|
||||
protected static function booted()
|
||||
{
|
||||
// Al crear una distribución, incrementar stock
|
||||
static::created(function ($dist) {
|
||||
$cantidad = $dist->cantidad ?? 0;
|
||||
if ($cantidad <= 0) return;
|
||||
|
||||
$bodegaId = $dist->bodega_id;
|
||||
|
||||
if ($dist->color_id && $dist->size_id) {
|
||||
// Variante
|
||||
$variant = \App\Models\ProductVariant::firstOrCreate([
|
||||
'producto_id' => $dist->inventarioPrenda->producto_id ?? ($dist->inventarioPrenda->ordenProduccion->producto_id ?? null),
|
||||
'color_id' => $dist->color_id,
|
||||
'size_id' => $dist->size_id,
|
||||
], ['stock' => 0, 'sku' => 'AUTO-'.uniqid(), 'barcode' => '']);
|
||||
|
||||
$existing = \DB::table('variante_bodega')
|
||||
->where('variante_id', $variant->id)
|
||||
->where('bodega_id', $bodegaId)
|
||||
->first();
|
||||
|
||||
if ($existing) {
|
||||
\DB::table('variante_bodega')
|
||||
->where('variante_id', $variant->id)
|
||||
->where('bodega_id', $bodegaId)
|
||||
->update(['stock' => ($existing->stock ?? 0) + $cantidad, 'updated_at' => now()]);
|
||||
} else {
|
||||
\DB::table('variante_bodega')->insert(['variante_id' => $variant->id, 'bodega_id' => $bodegaId, 'stock' => $cantidad, 'created_at' => now(), 'updated_at' => now()]);
|
||||
}
|
||||
|
||||
$variant->increment('stock', $cantidad);
|
||||
} else {
|
||||
// Producto
|
||||
$productoId = $dist->inventarioPrenda->producto_id ?? ($dist->inventarioPrenda->ordenProduccion->producto_id ?? null);
|
||||
if ($productoId) {
|
||||
$existing = \DB::table('producto_bodega')->where('producto_id', $productoId)->where('bodega_id', $bodegaId)->first();
|
||||
if ($existing) {
|
||||
\DB::table('producto_bodega')->where('producto_id', $productoId)->where('bodega_id', $bodegaId)->update(['stock' => ($existing->stock ?? 0) + $cantidad, 'updated_at' => now()]);
|
||||
} else {
|
||||
\DB::table('producto_bodega')->insert(['producto_id' => $productoId, 'bodega_id' => $bodegaId, 'stock' => $cantidad, 'created_at' => now(), 'updated_at' => now()]);
|
||||
}
|
||||
|
||||
$prod = \App\Models\Producto::find($productoId);
|
||||
if ($prod && ! $prod->variants()->exists()) {
|
||||
$prod->increment('stock', $cantidad);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Al actualizar, ajustar la diferencia
|
||||
static::updated(function ($dist) {
|
||||
$original = $dist->getOriginal();
|
||||
$oldCantidad = intval($original['cantidad'] ?? 0);
|
||||
$newCantidad = intval($dist->cantidad ?? 0);
|
||||
$delta = $newCantidad - $oldCantidad;
|
||||
if ($delta == 0) return;
|
||||
|
||||
$bodegaId = $dist->bodega_id;
|
||||
|
||||
if ($dist->color_id && $dist->size_id) {
|
||||
$variant = \App\Models\ProductVariant::firstOrCreate([
|
||||
'producto_id' => $dist->inventarioPrenda->producto_id ?? ($dist->inventarioPrenda->ordenProduccion->producto_id ?? null),
|
||||
'color_id' => $dist->color_id,
|
||||
'size_id' => $dist->size_id,
|
||||
], ['stock' => 0, 'sku' => 'AUTO-'.uniqid(), 'barcode' => '']);
|
||||
|
||||
$existing = \DB::table('variante_bodega')->where('variante_id', $variant->id)->where('bodega_id', $bodegaId)->first();
|
||||
if ($existing) {
|
||||
\DB::table('variante_bodega')->where('variante_id', $variant->id)->where('bodega_id', $bodegaId)->update(['stock' => ($existing->stock ?? 0) + $delta, 'updated_at' => now()]);
|
||||
} else {
|
||||
\DB::table('variante_bodega')->insert(['variante_id' => $variant->id, 'bodega_id' => $bodegaId, 'stock' => max(0, $delta), 'created_at' => now(), 'updated_at' => now()]);
|
||||
}
|
||||
|
||||
$variant->increment('stock', $delta);
|
||||
} else {
|
||||
$productoId = $dist->inventarioPrenda->producto_id ?? ($dist->inventarioPrenda->ordenProduccion->producto_id ?? null);
|
||||
if ($productoId) {
|
||||
$existing = \DB::table('producto_bodega')->where('producto_id', $productoId)->where('bodega_id', $bodegaId)->first();
|
||||
if ($existing) {
|
||||
\DB::table('producto_bodega')->where('producto_id', $productoId)->where('bodega_id', $bodegaId)->update(['stock' => ($existing->stock ?? 0) + $delta, 'updated_at' => now()]);
|
||||
} else {
|
||||
\DB::table('producto_bodega')->insert(['producto_id' => $productoId, 'bodega_id' => $bodegaId, 'stock' => max(0, $delta), 'created_at' => now(), 'updated_at' => now()]);
|
||||
}
|
||||
|
||||
$prod = \App\Models\Producto::find($productoId);
|
||||
if ($prod && ! $prod->variants()->exists()) {
|
||||
$prod->increment('stock', $delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Al eliminar, restar la cantidad
|
||||
static::deleted(function ($dist) {
|
||||
$cantidad = $dist->cantidad ?? 0;
|
||||
if ($cantidad <= 0) return;
|
||||
|
||||
$bodegaId = $dist->bodega_id;
|
||||
|
||||
if ($dist->color_id && $dist->size_id) {
|
||||
$variant = \App\Models\ProductVariant::where('color_id', $dist->color_id)->where('size_id', $dist->size_id)->first();
|
||||
if ($variant) {
|
||||
$existing = \DB::table('variante_bodega')->where('variante_id', $variant->id)->where('bodega_id', $bodegaId)->first();
|
||||
if ($existing) {
|
||||
$newStock = max(0, ($existing->stock ?? 0) - $cantidad);
|
||||
\DB::table('variante_bodega')->where('variante_id', $variant->id)->where('bodega_id', $bodegaId)->update(['stock' => $newStock, 'updated_at' => now()]);
|
||||
}
|
||||
|
||||
$variant->decrement('stock', $cantidad);
|
||||
}
|
||||
} else {
|
||||
$productoId = $dist->inventarioPrenda->producto_id ?? ($dist->inventarioPrenda->ordenProduccion->producto_id ?? null);
|
||||
if ($productoId) {
|
||||
$existing = \DB::table('producto_bodega')->where('producto_id', $productoId)->where('bodega_id', $bodegaId)->first();
|
||||
if ($existing) {
|
||||
$newStock = max(0, ($existing->stock ?? 0) - $cantidad);
|
||||
\DB::table('producto_bodega')->where('producto_id', $productoId)->where('bodega_id', $bodegaId)->update(['stock' => $newStock, 'updated_at' => now()]);
|
||||
}
|
||||
|
||||
$prod = \App\Models\Producto::find($productoId);
|
||||
if ($prod && ! $prod->variants()->exists()) {
|
||||
$prod->decrement('stock', $cantidad);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user