feat: corrección al apartado de inventario, productos que no tiene numero de serie
This commit is contained in:
parent
b9e694f6ca
commit
91f27c4e4a
@ -25,6 +25,7 @@ public function rules(): array
|
||||
'barcode' => ['nullable', 'string', 'unique:inventories,barcode'],
|
||||
'category_id' => ['required', 'exists:categories,id'],
|
||||
'stock' => ['nullable', 'integer', 'min:0'],
|
||||
'track_serials' => ['nullable', 'boolean'],
|
||||
|
||||
// Campos de Price
|
||||
'cost' => ['required', 'numeric', 'min:0'],
|
||||
|
||||
@ -27,6 +27,7 @@ public function rules(): array
|
||||
'barcode' => ['nullable', 'string', 'unique:inventories,barcode,' . $inventoryId],
|
||||
'category_id' => ['nullable', 'exists:categories,id'],
|
||||
'stock' => ['nullable', 'integer', 'min:0'],
|
||||
'track_serials' => ['nullable', 'boolean'],
|
||||
|
||||
// Campos de Price
|
||||
'cost' => ['nullable', 'numeric', 'min:0'],
|
||||
|
||||
@ -21,11 +21,13 @@ class Inventory extends Model
|
||||
'sku',
|
||||
'barcode',
|
||||
'stock',
|
||||
'track_serials',
|
||||
'is_active',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'is_active' => 'boolean',
|
||||
'track_serials' => 'boolean',
|
||||
];
|
||||
|
||||
protected $appends = ['has_serials'];
|
||||
@ -67,8 +69,10 @@ public function getAvailableStockAttribute(): int
|
||||
*/
|
||||
public function syncStock(): void
|
||||
{
|
||||
if($this->track_serials) {
|
||||
$this->update(['stock' => $this->getAvailableStockAttribute()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function getHasSerialsAttribute(): bool
|
||||
{
|
||||
|
||||
@ -15,6 +15,7 @@ public function createProduct(array $data)
|
||||
'barcode' => $data['barcode'] ?? null,
|
||||
'category_id' => $data['category_id'],
|
||||
'stock' => $data['stock'] ?? 0,
|
||||
'track_serials' => $data['track_serials'] ?? false,
|
||||
]);
|
||||
|
||||
$price = Price::create([
|
||||
@ -38,6 +39,7 @@ public function updateProduct(Inventory $inventory, array $data)
|
||||
'barcode' => $data['barcode'] ?? null,
|
||||
'category_id' => $data['category_id'] ?? null,
|
||||
'stock' => $data['stock'] ?? null,
|
||||
'track_serials' => $data['track_serials'] ?? null,
|
||||
], fn($value) => $value !== null);
|
||||
|
||||
if (!empty($inventoryData)) {
|
||||
|
||||
@ -93,6 +93,20 @@ public function createReturn(array $data): Returns
|
||||
'subtotal' => $saleDetail->unit_price * $item['quantity_returned'],
|
||||
]);
|
||||
|
||||
|
||||
$inventory = $saleDetail->inventory;
|
||||
|
||||
if ($inventory->track_serials) {
|
||||
// Validación de cantidad de seriales
|
||||
if (isset($item['serial_numbers']) && is_array($item['serial_numbers'])) {
|
||||
if (count($item['serial_numbers']) != $item['quantity_returned']) {
|
||||
throw new \Exception(
|
||||
"La cantidad de seriales proporcionados no coincide con la cantidad a devolver " .
|
||||
"para {$saleDetail->product_name}."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Gestionar seriales
|
||||
if (isset($item['serial_numbers']) && is_array($item['serial_numbers'])) {
|
||||
// Seriales específicos proporcionados
|
||||
@ -135,6 +149,9 @@ public function createReturn(array $data): Returns
|
||||
|
||||
// Sincronizar el stock del inventario
|
||||
$saleDetail->inventory->syncStock();
|
||||
} else {
|
||||
$inventory->increment('stock', $item['quantity_returned']);
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Retornar con relaciones cargadas
|
||||
@ -155,6 +172,7 @@ public function cancelReturn(Returns $return): Returns
|
||||
return DB::transaction(function () use ($return) {
|
||||
// Restaurar seriales a estado vendido
|
||||
foreach ($return->details as $detail) {
|
||||
if(!$detail->inventory->track_serials) {
|
||||
$serials = InventorySerial::where('return_detail_id', $detail->id)->get();
|
||||
|
||||
foreach ($serials as $serial) {
|
||||
@ -164,9 +182,12 @@ public function cancelReturn(Returns $return): Returns
|
||||
'return_detail_id' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
// Sincronizar stock
|
||||
$detail->inventory->syncStock();
|
||||
} else {
|
||||
// Restaurar stock numérico
|
||||
$detail->inventory->increment('stock', $detail->quantity_returned);
|
||||
}
|
||||
}
|
||||
|
||||
// Eliminar la devolución (soft delete)
|
||||
@ -194,15 +215,17 @@ public function getReturnableItems(Sale $sale): array
|
||||
$maxReturnable = $detail->quantity - $alreadyReturned;
|
||||
|
||||
if ($maxReturnable > 0) {
|
||||
$availableSerials = [];
|
||||
if ($detail->inventory->track_serials) {
|
||||
// Obtener seriales vendidos que aún no han sido devueltos
|
||||
$availableSerials = InventorySerial::where('sale_detail_id', $detail->id)
|
||||
->where('status', 'vendido')
|
||||
->get()
|
||||
->map(fn ($serial) => [
|
||||
->map(fn($serial) => [
|
||||
'serial_number' => $serial->serial_number,
|
||||
'status' => $serial->status,
|
||||
]);
|
||||
|
||||
}
|
||||
$returnableItems[] = [
|
||||
'sale_detail_id' => $detail->id,
|
||||
'inventory_id' => $detail->inventory_id,
|
||||
|
||||
@ -55,7 +55,7 @@ public function createSale(array $data)
|
||||
// Obtener el inventario
|
||||
$inventory = Inventory::find($item['inventory_id']);
|
||||
|
||||
if ($inventory) {
|
||||
if ($inventory->track_serials) {
|
||||
// Si se proporcionaron números de serie específicos
|
||||
if (isset($item['serial_numbers']) && is_array($item['serial_numbers'])) {
|
||||
foreach ($item['serial_numbers'] as $serialNumber) {
|
||||
@ -88,6 +88,12 @@ public function createSale(array $data)
|
||||
|
||||
// Sincronizar el stock
|
||||
$inventory->syncStock();
|
||||
} else {
|
||||
if ($inventory->stock < $item['quantity']) {
|
||||
throw new \Exception("Stock insuficiente para {$item['product_name']}");
|
||||
}
|
||||
|
||||
$inventory->decrement('stock', $item['quantity']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,14 +121,17 @@ public function cancelSale(Sale $sale)
|
||||
|
||||
// Restaurar seriales a disponible
|
||||
foreach ($sale->details as $detail) {
|
||||
if ($detail->inventory->track_serials) {
|
||||
// Restaurar seriales
|
||||
$serials = InventorySerial::where('sale_detail_id', $detail->id)->get();
|
||||
|
||||
foreach ($serials as $serial) {
|
||||
$serial->markAsAvailable();
|
||||
}
|
||||
|
||||
// Sincronizar stock
|
||||
$detail->inventory->syncStock();
|
||||
} else {
|
||||
// Restaurar stock numérico
|
||||
$detail->inventory->increment('stock', $detail->quantity);
|
||||
}
|
||||
}
|
||||
|
||||
// Marcar venta como cancelada
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('inventories', function (Blueprint $table) {
|
||||
$table->boolean('track_serials')->default(false)->after('stock');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('inventories', function (Blueprint $table) {
|
||||
$table->dropColumn('track_serials');
|
||||
});
|
||||
}
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user