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'],
|
'barcode' => ['nullable', 'string', 'unique:inventories,barcode'],
|
||||||
'category_id' => ['required', 'exists:categories,id'],
|
'category_id' => ['required', 'exists:categories,id'],
|
||||||
'stock' => ['nullable', 'integer', 'min:0'],
|
'stock' => ['nullable', 'integer', 'min:0'],
|
||||||
|
'track_serials' => ['nullable', 'boolean'],
|
||||||
|
|
||||||
// Campos de Price
|
// Campos de Price
|
||||||
'cost' => ['required', 'numeric', 'min:0'],
|
'cost' => ['required', 'numeric', 'min:0'],
|
||||||
|
|||||||
@ -27,6 +27,7 @@ public function rules(): array
|
|||||||
'barcode' => ['nullable', 'string', 'unique:inventories,barcode,' . $inventoryId],
|
'barcode' => ['nullable', 'string', 'unique:inventories,barcode,' . $inventoryId],
|
||||||
'category_id' => ['nullable', 'exists:categories,id'],
|
'category_id' => ['nullable', 'exists:categories,id'],
|
||||||
'stock' => ['nullable', 'integer', 'min:0'],
|
'stock' => ['nullable', 'integer', 'min:0'],
|
||||||
|
'track_serials' => ['nullable', 'boolean'],
|
||||||
|
|
||||||
// Campos de Price
|
// Campos de Price
|
||||||
'cost' => ['nullable', 'numeric', 'min:0'],
|
'cost' => ['nullable', 'numeric', 'min:0'],
|
||||||
|
|||||||
@ -21,11 +21,13 @@ class Inventory extends Model
|
|||||||
'sku',
|
'sku',
|
||||||
'barcode',
|
'barcode',
|
||||||
'stock',
|
'stock',
|
||||||
|
'track_serials',
|
||||||
'is_active',
|
'is_active',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'is_active' => 'boolean',
|
'is_active' => 'boolean',
|
||||||
|
'track_serials' => 'boolean',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $appends = ['has_serials'];
|
protected $appends = ['has_serials'];
|
||||||
@ -67,8 +69,10 @@ public function getAvailableStockAttribute(): int
|
|||||||
*/
|
*/
|
||||||
public function syncStock(): void
|
public function syncStock(): void
|
||||||
{
|
{
|
||||||
|
if($this->track_serials) {
|
||||||
$this->update(['stock' => $this->getAvailableStockAttribute()]);
|
$this->update(['stock' => $this->getAvailableStockAttribute()]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function getHasSerialsAttribute(): bool
|
public function getHasSerialsAttribute(): bool
|
||||||
{
|
{
|
||||||
|
|||||||
@ -15,6 +15,7 @@ public function createProduct(array $data)
|
|||||||
'barcode' => $data['barcode'] ?? null,
|
'barcode' => $data['barcode'] ?? null,
|
||||||
'category_id' => $data['category_id'],
|
'category_id' => $data['category_id'],
|
||||||
'stock' => $data['stock'] ?? 0,
|
'stock' => $data['stock'] ?? 0,
|
||||||
|
'track_serials' => $data['track_serials'] ?? false,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$price = Price::create([
|
$price = Price::create([
|
||||||
@ -38,6 +39,7 @@ public function updateProduct(Inventory $inventory, array $data)
|
|||||||
'barcode' => $data['barcode'] ?? null,
|
'barcode' => $data['barcode'] ?? null,
|
||||||
'category_id' => $data['category_id'] ?? null,
|
'category_id' => $data['category_id'] ?? null,
|
||||||
'stock' => $data['stock'] ?? null,
|
'stock' => $data['stock'] ?? null,
|
||||||
|
'track_serials' => $data['track_serials'] ?? null,
|
||||||
], fn($value) => $value !== null);
|
], fn($value) => $value !== null);
|
||||||
|
|
||||||
if (!empty($inventoryData)) {
|
if (!empty($inventoryData)) {
|
||||||
|
|||||||
@ -93,6 +93,20 @@ public function createReturn(array $data): Returns
|
|||||||
'subtotal' => $saleDetail->unit_price * $item['quantity_returned'],
|
'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
|
// Gestionar seriales
|
||||||
if (isset($item['serial_numbers']) && is_array($item['serial_numbers'])) {
|
if (isset($item['serial_numbers']) && is_array($item['serial_numbers'])) {
|
||||||
// Seriales específicos proporcionados
|
// Seriales específicos proporcionados
|
||||||
@ -135,6 +149,9 @@ public function createReturn(array $data): Returns
|
|||||||
|
|
||||||
// Sincronizar el stock del inventario
|
// Sincronizar el stock del inventario
|
||||||
$saleDetail->inventory->syncStock();
|
$saleDetail->inventory->syncStock();
|
||||||
|
} else {
|
||||||
|
$inventory->increment('stock', $item['quantity_returned']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Retornar con relaciones cargadas
|
// 5. Retornar con relaciones cargadas
|
||||||
@ -155,6 +172,7 @@ public function cancelReturn(Returns $return): Returns
|
|||||||
return DB::transaction(function () use ($return) {
|
return DB::transaction(function () use ($return) {
|
||||||
// Restaurar seriales a estado vendido
|
// Restaurar seriales a estado vendido
|
||||||
foreach ($return->details as $detail) {
|
foreach ($return->details as $detail) {
|
||||||
|
if(!$detail->inventory->track_serials) {
|
||||||
$serials = InventorySerial::where('return_detail_id', $detail->id)->get();
|
$serials = InventorySerial::where('return_detail_id', $detail->id)->get();
|
||||||
|
|
||||||
foreach ($serials as $serial) {
|
foreach ($serials as $serial) {
|
||||||
@ -164,9 +182,12 @@ public function cancelReturn(Returns $return): Returns
|
|||||||
'return_detail_id' => null,
|
'return_detail_id' => null,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sincronizar stock
|
// Sincronizar stock
|
||||||
$detail->inventory->syncStock();
|
$detail->inventory->syncStock();
|
||||||
|
} else {
|
||||||
|
// Restaurar stock numérico
|
||||||
|
$detail->inventory->increment('stock', $detail->quantity_returned);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eliminar la devolución (soft delete)
|
// Eliminar la devolución (soft delete)
|
||||||
@ -194,6 +215,8 @@ public function getReturnableItems(Sale $sale): array
|
|||||||
$maxReturnable = $detail->quantity - $alreadyReturned;
|
$maxReturnable = $detail->quantity - $alreadyReturned;
|
||||||
|
|
||||||
if ($maxReturnable > 0) {
|
if ($maxReturnable > 0) {
|
||||||
|
$availableSerials = [];
|
||||||
|
if ($detail->inventory->track_serials) {
|
||||||
// Obtener seriales vendidos que aún no han sido devueltos
|
// Obtener seriales vendidos que aún no han sido devueltos
|
||||||
$availableSerials = InventorySerial::where('sale_detail_id', $detail->id)
|
$availableSerials = InventorySerial::where('sale_detail_id', $detail->id)
|
||||||
->where('status', 'vendido')
|
->where('status', 'vendido')
|
||||||
@ -202,7 +225,7 @@ public function getReturnableItems(Sale $sale): array
|
|||||||
'serial_number' => $serial->serial_number,
|
'serial_number' => $serial->serial_number,
|
||||||
'status' => $serial->status,
|
'status' => $serial->status,
|
||||||
]);
|
]);
|
||||||
|
}
|
||||||
$returnableItems[] = [
|
$returnableItems[] = [
|
||||||
'sale_detail_id' => $detail->id,
|
'sale_detail_id' => $detail->id,
|
||||||
'inventory_id' => $detail->inventory_id,
|
'inventory_id' => $detail->inventory_id,
|
||||||
|
|||||||
@ -55,7 +55,7 @@ public function createSale(array $data)
|
|||||||
// Obtener el inventario
|
// Obtener el inventario
|
||||||
$inventory = Inventory::find($item['inventory_id']);
|
$inventory = Inventory::find($item['inventory_id']);
|
||||||
|
|
||||||
if ($inventory) {
|
if ($inventory->track_serials) {
|
||||||
// Si se proporcionaron números de serie específicos
|
// Si se proporcionaron números de serie específicos
|
||||||
if (isset($item['serial_numbers']) && is_array($item['serial_numbers'])) {
|
if (isset($item['serial_numbers']) && is_array($item['serial_numbers'])) {
|
||||||
foreach ($item['serial_numbers'] as $serialNumber) {
|
foreach ($item['serial_numbers'] as $serialNumber) {
|
||||||
@ -88,6 +88,12 @@ public function createSale(array $data)
|
|||||||
|
|
||||||
// Sincronizar el stock
|
// Sincronizar el stock
|
||||||
$inventory->syncStock();
|
$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
|
// Restaurar seriales a disponible
|
||||||
foreach ($sale->details as $detail) {
|
foreach ($sale->details as $detail) {
|
||||||
|
if ($detail->inventory->track_serials) {
|
||||||
|
// Restaurar seriales
|
||||||
$serials = InventorySerial::where('sale_detail_id', $detail->id)->get();
|
$serials = InventorySerial::where('sale_detail_id', $detail->id)->get();
|
||||||
|
|
||||||
foreach ($serials as $serial) {
|
foreach ($serials as $serial) {
|
||||||
$serial->markAsAvailable();
|
$serial->markAsAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sincronizar stock
|
|
||||||
$detail->inventory->syncStock();
|
$detail->inventory->syncStock();
|
||||||
|
} else {
|
||||||
|
// Restaurar stock numérico
|
||||||
|
$detail->inventory->increment('stock', $detail->quantity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Marcar venta como cancelada
|
// 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