laravel-vuexy-warehouse/database/migrations/2024_12_16_111823_create_warehouse_tables.php

194 lines
9.1 KiB
PHP
Raw Normal View History

2025-03-05 20:44:45 -06:00
<?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::create('warehouses', function (Blueprint $table) {
$table->smallIncrements('id');
$table->unsignedSmallInteger('store_id')->index(); // Relación con sucursal
$table->unsignedSmallInteger('work_center_id')->nullable()->index();
$table->string('code', 16)->unique();
$table->string('name', 96)->index();
$table->mediumText('description')->nullable();
$table->unsignedMediumInteger('manager_id')->nullable()->index(); // sat_codigo_postal.
$table->string('tel')->nullable();
$table->string('tel2')->nullable();
$table->unsignedTinyInteger('priority')->nullable();
$table->boolean('status')->default(true)->index();
$table->timestamps();
// Indices
$table->unique(['store_id', 'name']);
$table->foreign('store_id')->references('id')->on('stores')->onDelete('cascade');
$table->foreign('work_center_id')->references('id')->on('store_work_centers')->onDelete('cascade');
$table->foreign('manager_id')->references('id')->on('users')->onUpdate('restrict')->onDelete('restrict');
});
Schema::create('warehouse_movements', function (Blueprint $table) {
$table->mediumIncrements('id');
$table->unsignedSmallInteger('store_id')->index();
$table->unsignedSmallInteger('warehouse_id')->index(); // Almacén involucrado
// Tipo de ajuste (ajuste de inventario o traspaso)
$table->unsignedTinyInteger('movement_type')->index(); // Tipo de movimiento: ajuste o traspaso
$table->unsignedMediumInteger('movement_id')->nullable(); // UID específico por sucursal
$table->unsignedMediumInteger('created_by')->index(); // Usuario que registró el movimiento
$table->unsignedMediumInteger('approved_by')->nullable()->index(); // Usuario que autorizó el movimiento
// Cantidad ajustada
$table->decimal('adjusted_quantity', 13, 6); // Cantidad ajustada para el ajuste o transferencia
// Costo asociado
$table->decimal('cost', 9, 2)->unsigned()->default(0); // Costo de la operación
// Notas sobre el ajuste
$table->mediumText('notes')->nullable(); // Notas adicionales
// Campos para el traspaso
$table->unsignedSmallInteger('to_warehouse_id')->nullable()->index(); // Almacén de destino (solo para traspasos)
$table->unsignedTinyInteger('status')->index(); // Estatus de la orden ('pending', 'approved', 'received', 'cancelled')
$table->softDeletes();
$table->timestamps();
// Claves foráneas
$table->foreign('store_id')->references('id')->on('stores')->onDelete('restrict');
$table->foreign('warehouse_id')->references('id')->on('warehouses')->onDelete('restrict');
$table->foreign('to_warehouse_id')->references('id')->on('warehouses')->onDelete('restrict');
$table->foreign('created_by')->references('id')->on('users')->onDelete('restrict');
$table->foreign('approved_by')->references('id')->on('users')->onDelete('restrict');
});
Schema::create('lot_numbers', function (Blueprint $table) {
$table->mediumIncrements('id');
$table->unsignedMediumInteger('product_id')->index();
$table->unsignedSmallInteger('store_id')->index();
$table->unsignedSmallInteger('warehouse_id')->index();
$table->string('lot_number', 50)->unique()->comment('Número único del lote');
$table->date('production_date')->nullable();
$table->date('expiry_date')->nullable();
$table->decimal('initial_quantity', 13, 6)->unsigned()->default(0);
$table->decimal('remaining_quantity', 13, 6)->unsigned()->default(0);
$table->decimal('cost', 9, 2)->unsigned()->default(0);
$table->timestamps();
$table->foreign('product_id')->references('id')->on('products')->onDelete('restrict');
$table->foreign('store_id')->references('id')->on('stores')->onDelete('restrict');
$table->foreign('warehouse_id')->references('id')->on('warehouses')->onDelete('restrict');
});
Schema::create('inventory_stock_levels', function (Blueprint $table) {
$table->mediumIncrements('id');
$table->unsignedMediumInteger('product_id')->index();
$table->unsignedSmallInteger('store_id')->nullable()->index();
$table->unsignedSmallInteger('warehouse_id')->index();
$table->decimal('quantity', 13, 6)->unsigned()->comment('Stock total disponible en el almacén');
// Stock separado por área
$table->decimal('pos_stock', 13, 6)->unsigned()->default(0)->comment('Stock destinado a ventas en POS');
$table->decimal('ecommerce_stock', 13, 6)->unsigned()->default(0)->comment('Stock destinado a eCommerce');
$table->decimal('purchase_reserved_stock', 13, 6)->unsigned()->default(0)->comment('Stock reservado para órdenes de compra');
$table->decimal('asset_stock', 13, 6)->unsigned()->default(0)->comment('Stock reservado para uso interno');
// Alertas de Stock mínimo y máximo
$table->unsignedTinyInteger('alert_minimum_stock')->nullable()->index();
$table->decimal('minimum_stock', 13, 6)->unsigned()->nullable();
$table->unsignedTinyInteger('alert_maximum_stock')->nullable()->index();
$table->decimal('maximum_stock', 13, 6)->unsigned()->nullable();
// Costos asociados
$table->decimal('last_cost', 9, 2)->unsigned()->default(0); // Último costo registrado
$table->decimal('average_cost', 9, 2)->unsigned()->default(0); // Costo promedio ponderado
$table->decimal('total_last_cost', 11, 2)->unsigned()->default(0); // Costo total último costo registrado
$table->decimal('total_average_cost', 11, 2)->unsigned()->default(0); // Costo total promedio ponderado
$table->decimal('total_identified_cost', 11, 2)->unsigned()->default(0); // Costo total identificado
$table->unsignedTinyInteger('costing_method')->index(); // Método de costeo: 'average', 'last', 'identified'
$table->timestamps();
$table->unique(['warehouse_id', 'product_id']);
$table->foreign('product_id')->references('id')->on('products')->onDelete('restrict');
$table->foreign('store_id')->references('id')->on('stores')->onDelete('restrict');
$table->foreign('warehouse_id')->references('id')->on('warehouses')->onDelete('restrict');
});
Schema::create('inventory_movements', function (Blueprint $table) {
$table->integerIncrements('id');
$table->unsignedMediumInteger('product_id')->index();
$table->unsignedSmallInteger('store_id')->index();
$table->unsignedSmallInteger('warehouse_id')->index();
$table->enum('movement_type', ['in', 'out'])->index(); // Tipo de movimiento (entrada/salida)
$table->decimal('quantity', 13, 6)->unsigned();
$table->decimal('cost', 9, 2)->unsigned(); // Costo asociado a la transacción
$table->decimal('cost_before', 9, 2)->unsigned()->nullable();
$table->decimal('cost_after', 9, 2)->unsigned()->nullable();
$table->enum('cost_type', ['average', 'last', 'specific'])->default('last');
$table->text('notes')->nullable(); // Notas sobre el movimiento
// Define el campo para la relación polimórfica manualmente
$table->unsignedMediumInteger('transactionable_id')->index();
$table->string('transactionable_type')->index();
$table->unsignedMediumInteger('created_by')->index(); // Usuario que registró el movimiento
$table->timestamps();
// Agrega el índice con un nombre específico para evitar el problema de longitud
$table->index(['transactionable_type', 'transactionable_id'], 'inventory_movements_transactionable_index');
$table->foreign('product_id')->references('id')->on('products')->onDelete('restrict');
$table->foreign('store_id')->references('id')->on('stores')->onDelete('restrict');
$table->foreign('warehouse_id')->references('id')->on('warehouses')->onDelete('restrict');
$table->foreign('created_by')->references('id')->on('users')->onDelete('restrict');
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('warehouses');
Schema::dropIfExists('warehouse_movements');
Schema::dropIfExists('lot_numbers');
Schema::dropIfExists('inventory_stock_levels');
Schema::dropIfExists('inventory_movements');
}
};