first commit
This commit is contained in:
@ -0,0 +1,84 @@
|
||||
<?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('product_categories', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
|
||||
$table->unsignedMediumInteger('parent_id')->nullable()->index();
|
||||
$table->string('parent_slug')->nullable()->index();
|
||||
|
||||
$table->string('name')->index();
|
||||
$table->string('slug')->nullable()->index();
|
||||
$table->string('icon')->nullable();
|
||||
|
||||
$table->mediumText('description')->nullable();
|
||||
|
||||
$table->boolean('show_in_pos')->index();
|
||||
$table->boolean('show_in_purchases')->index();
|
||||
$table->boolean('show_in_ecommerce')->index();
|
||||
$table->boolean('show_in_manufacturing')->index();
|
||||
$table->boolean('show_in_quality')->index();
|
||||
$table->boolean('show_in_assets')->index();
|
||||
|
||||
$table->unsignedTinyInteger('priority')->nullable()->index();
|
||||
|
||||
// Aditoria
|
||||
$table->timestamps();
|
||||
|
||||
// Index
|
||||
$table->unique(['parent_id', 'slug']);
|
||||
|
||||
// Relaciones
|
||||
//$table->foreign('parent_id')->references('id')->on('product_categories')->onUpdate('restrict')->onDelete('cascade');
|
||||
});
|
||||
|
||||
DB::unprepared("CREATE TRIGGER before_delete_category
|
||||
BEFORE DELETE ON product_categories
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
-- Verificar si la categoría tiene hijos
|
||||
IF (SELECT COUNT(*) FROM product_categories WHERE parent_id = OLD.id) > 0 THEN
|
||||
-- Generar un error para evitar la eliminación
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = 'No se puede eliminar la categoría porque tiene categorías hijas.';
|
||||
END IF;
|
||||
END");
|
||||
|
||||
|
||||
Schema::create('category_properties', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
|
||||
$table->unsignedMediumInteger('category_id')->index();
|
||||
$table->unsignedSmallInteger('property_id')->index();
|
||||
|
||||
$table->boolean('is_required'); // Si es obligatorio en esta categoría
|
||||
$table->boolean('is_filterable'); // Si se puede usar en filtros
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('category_id')->references('id')->on('product_categories')->onUpdate('restrict')->onDelete('cascade');
|
||||
//$table->foreign('property_id')->references('id')->on('product_properties')->onUpdate('restrict')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('product_categories');
|
||||
DB::unprepared("DROP TRIGGER IF EXISTS before_delete_category");
|
||||
Schema::dropIfExists('category_properties');
|
||||
}
|
||||
};
|
149
database/migrations/2024_12_16_092473_create_products_tables.php
Normal file
149
database/migrations/2024_12_16_092473_create_products_tables.php
Normal file
@ -0,0 +1,149 @@
|
||||
<?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('products', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
$table->unsignedTinyInteger('type')->index();
|
||||
|
||||
$table->unsignedMediumInteger('category_id')->index(); // product_categories.id
|
||||
|
||||
$table->string('descripcion')->fulltext();
|
||||
$table->mediumText('descripcion_completa')->nullable()->index();
|
||||
$table->string('no_identificacion', 40)->nullable()->unique();
|
||||
$table->string('slug')->nullable()->unique();
|
||||
|
||||
$table->boolean('available_in_pos')->index();
|
||||
$table->boolean('available_in_purchases')->index();
|
||||
$table->boolean('available_in_ecommerce')->index();
|
||||
$table->boolean('available_in_maanufacturing')->index();
|
||||
$table->boolean('available_in_quality')->index();
|
||||
$table->boolean('available_in_assets')->index();
|
||||
|
||||
$table->string('c_clave_unidad', 3)->nullable()->index(); // sat_clave_unidad.
|
||||
$table->unsignedInteger('c_clave_prod_serv')->nullable()->index(); // sat_clave_prod_serv.
|
||||
$table->unsignedBigInteger('ean_code')->nullable()->unique();
|
||||
|
||||
$table->decimal('costo', 9, 2)->unsigned()->nullable();
|
||||
$table->char('c_moneda', 3)->charset('ascii')->collation('ascii_general_ci')->nullable()->index();
|
||||
$table->unsignedTinyInteger('c_objeto_imp')->nullable()->index(); // sat_objeto_imp.
|
||||
$table->json('impuestos')->nullable();
|
||||
$table->decimal('traslados', 9, 6)->unsigned()->nullable();
|
||||
$table->decimal('retenciones', 9, 6)->unsigned()->nullable();
|
||||
|
||||
$table->unsignedTinyInteger('data_lot_enable')->nullable()->index();
|
||||
$table->unsignedTinyInteger('data_lot_require')->nullable()->index();
|
||||
$table->unsignedTinyInteger('data_series_enable')->nullable()->index();
|
||||
$table->unsignedTinyInteger('data_series_require')->nullable()->index();
|
||||
$table->unsignedTinyInteger('data_expiration_enable')->nullable()->index();
|
||||
$table->unsignedTinyInteger('data_expiration_require')->nullable()->index();
|
||||
$table->unsignedTinyInteger('data_warranty_enable')->nullable()->index();
|
||||
$table->unsignedMediumInteger('warranty')->nullable()->index();
|
||||
$table->unsignedTinyInteger('data_best_before_enable')->nullable()->index();
|
||||
$table->unsignedTinyInteger('data_best_before_require')->nullable()->index();
|
||||
$table->unsignedTinyInteger('data_observations_enable')->nullable()->index();
|
||||
|
||||
$table->decimal('minimum_unit', 7, 6)->unsigned()->nullable(); // Decimales soportados en la Unidad de Medida
|
||||
$table->unsignedTinyInteger('affects_inventory')->nullable()->index();
|
||||
|
||||
$table->unsignedTinyInteger('status')->index();
|
||||
|
||||
// Auditoría
|
||||
$table->unsignedMediumInteger('created_by')->nullable()->index(); // users.id
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('category_id')->references('id')->on('product_categories')->onUpdate('restrict')->onDelete('restrict');
|
||||
$table->foreign('c_moneda')->references('c_moneda')->on('sat_moneda')->onUpdate('restrict')->onDelete('restrict');
|
||||
$table->foreign('c_clave_unidad')->references('c_clave_unidad')->on('sat_clave_unidad')->onUpdate('restrict')->onDelete('restrict');
|
||||
$table->foreign('c_clave_prod_serv')->references('c_clave_prod_serv')->on('sat_clave_prod_serv')->onUpdate('restrict')->onDelete('restrict');
|
||||
$table->foreign('created_by')->references('id')->on('users')->onUpdate('restrict')->onDelete('restrict');
|
||||
});
|
||||
|
||||
Schema::create('product_properties', function (Blueprint $table) {
|
||||
$table->smallIncrements('id');
|
||||
|
||||
$table->string('name')->index(); // Ej: "Marca", "Potencia", "Color"
|
||||
$table->enum('type', ['text', 'number', 'boolean', 'select'])->default('text');
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('product_store_prices', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
|
||||
$table->unsignedMediumInteger('product_id')->index();
|
||||
$table->unsignedSmallInteger('store_id')->index();
|
||||
|
||||
$table->decimal('price', 9, 2)->unsigned()->default(0);
|
||||
$table->char('currency', 3)->charset('ascii')->collation('ascii_general_ci');
|
||||
|
||||
$table->boolean('is_discounted')->index();
|
||||
$table->decimal('discount_price', 9, 2)->unsigned()->nullable();
|
||||
$table->date('discount_start')->nullable();
|
||||
$table->date('discount_end')->nullable();
|
||||
|
||||
// Auditoría
|
||||
$table->timestamps();
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('product_id')->references('id')->on('products')->onUpdate('restrict')->onDelete('cascade');
|
||||
$table->foreign('store_id')->references('id')->on('stores')->onUpdate('restrict')->onDelete('cascade');
|
||||
});
|
||||
|
||||
Schema::create('product_property', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
|
||||
$table->unsignedMediumInteger('product_id')->index();
|
||||
$table->unsignedSmallInteger('property_id')->index();
|
||||
|
||||
$table->string('value')->index(); // Valor de la propiedad, ej: 'Intel', 'DDR4', '500W'
|
||||
|
||||
// Auditoria
|
||||
$table->timestamps();
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('product_id')->references('id')->on('products')->onUpdate('restrict')->onDelete('cascade');
|
||||
$table->foreign('property_id')->references('id')->on('product_properties')->onUpdate('restrict')->onDelete('cascade');
|
||||
});
|
||||
|
||||
Schema::create('product_property_values', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
|
||||
$table->unsignedMediumInteger('product_id')->index();
|
||||
$table->unsignedSmallInteger('property_id')->index();
|
||||
|
||||
$table->string('value_text')->nullable()->index();
|
||||
$table->decimal('value_number', 9, 2)->nullable();
|
||||
$table->boolean('value_boolean')->nullable();
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('product_id')->references('id')->on('products')->onUpdate('restrict')->onDelete('cascade');
|
||||
$table->foreign('property_id')->references('id')->on('product_properties')->onUpdate('restrict')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('products');
|
||||
Schema::dropIfExists('product_properties');
|
||||
Schema::dropIfExists('product_store_prices');
|
||||
Schema::dropIfExists('product_property');
|
||||
Schema::dropIfExists('product_property_values');
|
||||
}
|
||||
};
|
@ -0,0 +1,193 @@
|
||||
<?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');
|
||||
}
|
||||
};
|
Reference in New Issue
Block a user