From 06dbf8e2a7325f33c3bc78c03334f28181d1690b Mon Sep 17 00:00:00 2001 From: Arturo Corro Date: Wed, 5 Mar 2025 20:44:45 -0600 Subject: [PATCH] first commit --- .editorconfig | 18 + .gitattributes | 38 ++ .gitignore | 10 + .prettierignore | 16 + .prettierrc.json | 29 + CHANGELOG.md | 39 ++ CONTRIBUTING.md | 9 + Http/Controllers/InventoryItemController.php | 65 +++ .../InventoryMovementController.php | 65 +++ Http/Controllers/InventoryStockController.php | 65 +++ Http/Controllers/MaterialController.php | 65 +++ Http/Controllers/ProductCatalogController.php | 65 +++ .../ProductCategorieController.php | 65 +++ Http/Controllers/ProductController.php | 65 +++ Http/Controllers/ProductReceiptController.php | 65 +++ Http/Controllers/WarehouseController.php | 133 +++++ .../WarehouseMovementController.php | 66 +++ .../WarehouseTransferController.php | 65 +++ LICENSE | 9 + .../InventoryItems/InventoryItemsIndex.php | 109 ++++ .../InventoryMovementsIndex.php | 109 ++++ .../InventoryStock/InventoryStockIndex.php | 109 ++++ Livewire/Materials/MaterialsIndex.php | 109 ++++ .../ProductCatalogs/ProductCatalogsIndex.php | 109 ++++ .../ProductCategoriesIndex.php | 109 ++++ .../ProductReceipts/ProductReceiptsIndex.php | 109 ++++ Livewire/Products/ProductsIndex.php | 109 ++++ .../PurchaseOrders/PurchaseOrdersIndex.php | 109 ++++ .../WarehouseMovementsIndex.php | 109 ++++ .../WarehouseTransfersIndex.php | 109 ++++ Livewire/Warehouses/WarehouseIndex.php | 221 ++++++++ .../Warehouses/WarehouseOffcanvasForm.php | 219 ++++++++ Models/Currency.php | 19 + Models/FixedAsset.php | 20 + Models/InventoryMovement.php | 84 +++ Models/InventoryStockLevel.php | 62 +++ Models/LotNumber.php | 62 +++ Models/Product.php | 134 +++++ Models/ProductCategory.php | 68 +++ Models/ProductProperty.php | 29 + Models/ProductPropertyValue.php | 39 ++ Models/Warehouse.php | 94 ++++ Models/WarehouseMovement.php | 80 +++ Providers/VuexyWarehouseServiceProvider.php | 63 +++ README.md | 133 +++++ Services/WarehouseCatalogService.php | 98 ++++ composer.json | 36 ++ ...091520_create_product_categories_table.php | 84 +++ ...24_12_16_092473_create_products_tables.php | 149 +++++ ...4_12_16_111823_create_warehouse_tables.php | 193 +++++++ .../js/bootstrap-table/warehouseFormatters.js | 17 + .../views/inventory-items/index.blade.php | 21 + .../views/inventory-movements/index.blade.php | 21 + .../views/inventory-stock/index.blade.php | 21 + .../inventory-items-index.blade.php | 516 ++++++++++++++++++ .../inventory-movements-index.blade.php | 516 ++++++++++++++++++ .../inventory-stock-index.blade.php | 516 ++++++++++++++++++ .../materials/materials-index.blade.php | 516 ++++++++++++++++++ .../product-catalogs-index.blade.php | 516 ++++++++++++++++++ .../product-categories-index.blade.php | 516 ++++++++++++++++++ .../product-receipts-index.blade.php | 516 ++++++++++++++++++ .../products/products-index.blade.php | 516 ++++++++++++++++++ .../warehouse-movements-index.blade.php | 516 ++++++++++++++++++ .../warehouse-transfers-index.blade.php | 516 ++++++++++++++++++ .../warehouses/form-offcanvas.blade.php | 132 +++++ .../views/livewire/warehouses/index.blade.php | 12 + resources/views/materials/index.blade.php | 21 + .../views/product-categories/index.blade.php | 21 + .../views/product-receipts/index.blade.php | 21 + resources/views/products/index.blade.php | 21 + .../views/warehouse-movements/index.blade.php | 21 + .../views/warehouse-transfers/index.blade.php | 21 + resources/views/warehouses/index.blade.php | 24 + routes/admin.php | 109 ++++ 74 files changed, 9681 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .prettierignore create mode 100644 .prettierrc.json create mode 100644 CHANGELOG.md create mode 100644 CONTRIBUTING.md create mode 100644 Http/Controllers/InventoryItemController.php create mode 100644 Http/Controllers/InventoryMovementController.php create mode 100644 Http/Controllers/InventoryStockController.php create mode 100644 Http/Controllers/MaterialController.php create mode 100644 Http/Controllers/ProductCatalogController.php create mode 100644 Http/Controllers/ProductCategorieController.php create mode 100644 Http/Controllers/ProductController.php create mode 100644 Http/Controllers/ProductReceiptController.php create mode 100644 Http/Controllers/WarehouseController.php create mode 100644 Http/Controllers/WarehouseMovementController.php create mode 100644 Http/Controllers/WarehouseTransferController.php create mode 100644 LICENSE create mode 100644 Livewire/InventoryItems/InventoryItemsIndex.php create mode 100644 Livewire/InventoryMovements/InventoryMovementsIndex.php create mode 100644 Livewire/InventoryStock/InventoryStockIndex.php create mode 100644 Livewire/Materials/MaterialsIndex.php create mode 100644 Livewire/ProductCatalogs/ProductCatalogsIndex.php create mode 100644 Livewire/ProductCategories/ProductCategoriesIndex.php create mode 100644 Livewire/ProductReceipts/ProductReceiptsIndex.php create mode 100644 Livewire/Products/ProductsIndex.php create mode 100644 Livewire/PurchaseOrders/PurchaseOrdersIndex.php create mode 100644 Livewire/WarehouseMovements/WarehouseMovementsIndex.php create mode 100644 Livewire/WarehouseTransfers/WarehouseTransfersIndex.php create mode 100644 Livewire/Warehouses/WarehouseIndex.php create mode 100644 Livewire/Warehouses/WarehouseOffcanvasForm.php create mode 100644 Models/Currency.php create mode 100644 Models/FixedAsset.php create mode 100644 Models/InventoryMovement.php create mode 100644 Models/InventoryStockLevel.php create mode 100644 Models/LotNumber.php create mode 100644 Models/Product.php create mode 100644 Models/ProductCategory.php create mode 100644 Models/ProductProperty.php create mode 100644 Models/ProductPropertyValue.php create mode 100644 Models/Warehouse.php create mode 100644 Models/WarehouseMovement.php create mode 100644 Providers/VuexyWarehouseServiceProvider.php create mode 100644 README.md create mode 100644 Services/WarehouseCatalogService.php create mode 100644 composer.json create mode 100644 database/migrations/2024_12_16_091520_create_product_categories_table.php create mode 100644 database/migrations/2024_12_16_092473_create_products_tables.php create mode 100644 database/migrations/2024_12_16_111823_create_warehouse_tables.php create mode 100644 resources/assets/js/bootstrap-table/warehouseFormatters.js create mode 100644 resources/views/inventory-items/index.blade.php create mode 100644 resources/views/inventory-movements/index.blade.php create mode 100644 resources/views/inventory-stock/index.blade.php create mode 100644 resources/views/livewire/inventory-items/inventory-items-index.blade.php create mode 100644 resources/views/livewire/inventory-movements/inventory-movements-index.blade.php create mode 100644 resources/views/livewire/inventory-stock/inventory-stock-index.blade.php create mode 100644 resources/views/livewire/materials/materials-index.blade.php create mode 100644 resources/views/livewire/product-catalogs/product-catalogs-index.blade.php create mode 100644 resources/views/livewire/product-categories/product-categories-index.blade.php create mode 100644 resources/views/livewire/product-receipts/product-receipts-index.blade.php create mode 100644 resources/views/livewire/products/products-index.blade.php create mode 100644 resources/views/livewire/warehouse-movements/warehouse-movements-index.blade.php create mode 100644 resources/views/livewire/warehouse-transfers/warehouse-transfers-index.blade.php create mode 100644 resources/views/livewire/warehouses/form-offcanvas.blade.php create mode 100644 resources/views/livewire/warehouses/index.blade.php create mode 100644 resources/views/materials/index.blade.php create mode 100644 resources/views/product-categories/index.blade.php create mode 100644 resources/views/product-receipts/index.blade.php create mode 100644 resources/views/products/index.blade.php create mode 100644 resources/views/warehouse-movements/index.blade.php create mode 100644 resources/views/warehouse-transfers/index.blade.php create mode 100644 resources/views/warehouses/index.blade.php create mode 100644 routes/admin.php diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8f0de65 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.{yml,yaml}] +indent_size = 2 + +[docker-compose.yml] +indent_size = 4 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..7333620 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,38 @@ +* text=auto eol=lf + +*.blade.php diff=html +*.css diff=css +*.html diff=html +*.md diff=markdown +*.php diff=php + +/.github export-ignore +CHANGELOG.md export-ignore +.styleci.yml export-ignore + +# Ignorar archivos de configuración y herramientas de desarrollo +.editorconfig export-ignore +.prettierrc.json export-ignore +.prettierignore export-ignore +.eslintrc.json export-ignore + +# Ignorar node_modules y dependencias locales +node_modules/ export-ignore +vendor/ export-ignore + +# Ignorar archivos de build +npm-debug.log export-ignore + +# Ignorar carpetas de logs y caché +storage/logs/ export-ignore +storage/framework/ export-ignore + +# Ignorar carpetas de compilación de frontend +public/build/ export-ignore +dist/ export-ignore + +# Ignorar archivos de CI/CD +.github/ export-ignore +.gitlab-ci.yml export-ignore +.vscode/ export-ignore +.idea/ export-ignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d07bec2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +/node_modules +/vendor +/.vscode +/.nova +/.fleet +/.phpactor.json +/.phpunit.cache +/.phpunit.result.cache +/.zed +/.idea diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..5d3dfee --- /dev/null +++ b/.prettierignore @@ -0,0 +1,16 @@ +# Dependencias de Composer y Node.js +/vendor/ +/node_modules/ + +# Caché y logs +/storage/ +*.log +*.cache + +# Archivos del sistema +.DS_Store +Thumbs.db + +# Configuración de editores +.idea/ +.vscode/ diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..5f11c9c --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,29 @@ +{ + "arrowParens": "avoid", + "bracketSpacing": true, + "bracketSameLine": true, + "htmlWhitespaceSensitivity": "css", + "insertPragma": false, + "jsxSingleQuote": true, + "printWidth": 120, + "proseWrap": "preserve", + "quoteProps": "as-needed", + "requirePragma": false, + "semi": true, + "singleQuote": true, + "tabWidth": 4, + "trailingComma": "none", + "useTabs": false, + "endOfLine": "lf", + "embeddedLanguageFormatting": "auto", + "overrides": [ + { + "files": [ + "resources/assets/**/*.js" + ], + "options": { + "semi": false + } + } + ] +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..93a240e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,39 @@ +# 📜 CHANGELOG - Laravel Vuexy Warehouse + +Este documento sigue el formato [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## [0.1.0] - ALPHA - 2024-03-05 + +### ✨ Added (Agregado) +- 🚀 Primera versión alpha de la librería. +- 🔹 Implementación inicial de [funcionalidad clave 1]. +- 🔹 Integración con [dependencia o servicio principal]. +- 🔹 Soporte para [Laravel/Vuexy Admin, si aplica]. + +### 🛠 Changed (Modificado) +- 🔄 Optimización de [código o estructura interna]. + +### 🐛 Fixed (Correcciones) +- 🐞 Correcciones iniciales en [migraciones, modelos, servicios, etc.]. + +--- + +## 📅 Próximos Cambios Planeados +- 📊 **Mejoras en [feature futuro]**. +- 🏪 **Compatibilidad con [Laravel 11, Vuexy, etc.]**. +- 📍 **Integración con [API o funcionalidad esperada]**. + +--- + +**📌 Nota:** Esta es una versión **ALPHA**, aún en desarrollo. + +--- + +## 🔄 Sincronización de Cambios +Este `CHANGELOG.md` se actualiza primero en nuestro repositorio principal en **[Tea - Koneko Git](https://git.koneko.mx/koneko/laravel-vuexy-warehouse)** y luego se refleja en GitHub. +Los cambios recientes pueden verse antes en **Tea** que en **GitHub** debido a la sincronización automática. + +--- + +📅 Última actualización: **2024-03-05**. + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..b2ac5f9 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,9 @@ +## 🔐 Acceso al Repositorio Privado + +Nuestro servidor Git en **Tea** tiene un registro cerrado. Para contribuir: + +1. Abre un **Issue** en [GitHub](https://github.com/koneko-mx/laravel-vuexy-warehouse/issues) indicando tu interés en contribuir. +2. Alternativamente, envía un correo a **contacto@koneko.mx** solicitando acceso. +3. Una vez aprobado, recibirás una invitación para registrarte y clonar el repositorio. + +Si solo necesitas acceso de lectura, puedes clonar la versión pública en **GitHub**. diff --git a/Http/Controllers/InventoryItemController.php b/Http/Controllers/InventoryItemController.php new file mode 100644 index 0000000..8d0ef2d --- /dev/null +++ b/Http/Controllers/InventoryItemController.php @@ -0,0 +1,65 @@ +ajax()) { + $bootstrapTableIndexConfig = [ + 'table' => 'warehouses', + 'columns' => [ + 'warehouses.id', + 'stores.code AS store_code', + 'stores.name AS store_name', + 'store_work_centers.code AS work_center_code', + 'store_work_centers.name AS work_center_name', + 'warehouses.code', + 'warehouses.name', + 'warehouses.description', + DB::raw("CONCAT_WS(' ', users.name, users.last_name) AS manager_name"), + 'users.email AS manager_email', + 'warehouses.tel', + 'warehouses.tel2', + 'sat_pais.descripcion AS pais', + 'sat_estado.nombre_del_estado AS estado', + 'sat_localidad.descripcion AS localidad', + 'sat_municipio.descripcion AS municipio', + 'sat_colonia.nombre_del_asentamiento AS colonia', + DB::raw("CONCAT_WS(' ', COALESCE(stores.direccion, ''), COALESCE(stores.num_ext, ''), IF(stores.num_int IS NOT NULL, CONCAT('Int ', stores.num_int), '')) AS direccion"), + 'warehouses.priority', + 'warehouses.status', + 'warehouses.created_at', + 'warehouses.updated_at', + ], + 'joins' => [ + [ + 'table' => 'stores', + 'first' => 'warehouses.store_id', + 'second' => 'stores.id', + 'type' => 'join', + ], + [ + 'table' => 'store_work_centers', + 'first' => 'warehouses.work_center_id', + 'second' => 'store_work_centers.id', + 'type' => 'leftJoin', + ], + [ + 'table' => 'users', + 'first' => 'warehouses.manager_id', + 'second' => 'users.id', + 'type' => 'leftJoin', + ], + [ + 'table' => 'sat_pais', + 'first' => 'stores.c_pais', + 'second' => 'sat_pais.c_pais', + 'type' => 'leftJoin', + ], + [ + 'table' => 'sat_estado', + 'first' => 'stores.c_estado', + 'second' => 'sat_estado.c_estado', + 'and' => [ + 'stores.c_pais = sat_estado.c_pais', + ], + 'type' => 'leftJoin', + ], + [ + 'table' => 'sat_localidad', + 'first' => 'stores.c_localidad', + 'second' => 'sat_localidad.c_localidad', + 'and' => [ + 'stores.c_estado = sat_localidad.c_estado', + ], + 'type' => 'leftJoin', + ], + [ + 'table' => 'sat_municipio', + 'first' => 'stores.c_municipio', + 'second' => 'sat_municipio.c_municipio', + 'and' => [ + 'stores.c_estado = sat_municipio.c_estado', + ], + 'type' => 'leftJoin', + ], + [ + 'table' => 'sat_colonia', + 'first' => 'stores.c_colonia', + 'second' => 'sat_colonia.c_colonia', + 'and' => [ + 'stores.c_codigo_postal = sat_colonia.c_codigo_postal', + ], + 'type' => 'leftJoin', + ], + ], + 'filters' => [ + 'search' => [ + 'warehouses.code', + 'warehouses.name', + 'stores.name', + 'store_work_centers.name', + ], + ], + 'sort_column' => 'warehouses.name', // Columna por defecto para ordenamiento + 'default_sort_order' => 'asc', // Orden por defecto + ]; + + return (new GenericQueryBuilder($request, $bootstrapTableIndexConfig))->getJson(); + } + + return view('vuexy-warehouse::warehouses.index'); + } + + /** + * Display the specified resource. + */ + public function show(Warehouse $warehouse) + { + // + } + +} diff --git a/Http/Controllers/WarehouseMovementController.php b/Http/Controllers/WarehouseMovementController.php new file mode 100644 index 0000000..242bc95 --- /dev/null +++ b/Http/Controllers/WarehouseMovementController.php @@ -0,0 +1,66 @@ +tipo_persona_options = [ + User::TIPO_RFC_FISICA => User::$tipoRfcList[User::TIPO_RFC_FISICA], + User::TIPO_RFC_MORAL => User::$tipoRfcList[User::TIPO_RFC_MORAL], + User::TIPO_RFC_PUBLICO => User::$tipoRfcList[User::TIPO_RFC_PUBLICO], + ]; + + $this->estado_options = DB::table('sat_estado') + ->select('sat_estado.c_estado', 'sat_estado.nombre_del_estado') + ->join('sat_codigo_postal', 'sat_estado.c_estado', '=', 'sat_codigo_postal.c_estado') + ->join('users', 'users.domicilio_fiscal', '=', 'sat_codigo_postal.c_codigo_postal') + ->distinct() + ->orderBy('sat_estado.c_estado') + ->pluck('sat_estado.nombre_del_estado', 'sat_estado.c_estado'); + + + $this->status_options = $this->status_list = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + //$this->status = User::STATUS_ENABLED; + $this->status_list_class = User::$statusListClass; + + $this->statuses = [ + User::STATUS_ENABLED => ['title' => 'Activo', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_ENABLED]], + User::STATUS_DISABLED => ['title' => 'Deshabilitado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_DISABLED]], + User::STATUS_REMOVED => ['title' => 'Eliminado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_REMOVED]], + ]; + + $roles = Role::whereNotIn('name', ['Patient', 'Doctor'])->get(); + + $this->roles_html_select = ""; + + $this->status_options = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + $this->uso_cfdi_options = UsoCfdi::selectList(); + $this->regimen_fiscal_options = RegimenFiscal::selectList(); + } + + + + + public function render() + { + return view('vuexy-warehouse::livewire.inventory-items.inventory-items-index'); + } + +} diff --git a/Livewire/InventoryMovements/InventoryMovementsIndex.php b/Livewire/InventoryMovements/InventoryMovementsIndex.php new file mode 100644 index 0000000..a3d4a3e --- /dev/null +++ b/Livewire/InventoryMovements/InventoryMovementsIndex.php @@ -0,0 +1,109 @@ +tipo_persona_options = [ + User::TIPO_RFC_FISICA => User::$tipoRfcList[User::TIPO_RFC_FISICA], + User::TIPO_RFC_MORAL => User::$tipoRfcList[User::TIPO_RFC_MORAL], + User::TIPO_RFC_PUBLICO => User::$tipoRfcList[User::TIPO_RFC_PUBLICO], + ]; + + $this->estado_options = DB::table('sat_estado') + ->select('sat_estado.c_estado', 'sat_estado.nombre_del_estado') + ->join('sat_codigo_postal', 'sat_estado.c_estado', '=', 'sat_codigo_postal.c_estado') + ->join('users', 'users.domicilio_fiscal', '=', 'sat_codigo_postal.c_codigo_postal') + ->distinct() + ->orderBy('sat_estado.c_estado') + ->pluck('sat_estado.nombre_del_estado', 'sat_estado.c_estado'); + + + $this->status_options = $this->status_list = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + //$this->status = User::STATUS_ENABLED; + $this->status_list_class = User::$statusListClass; + + $this->statuses = [ + User::STATUS_ENABLED => ['title' => 'Activo', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_ENABLED]], + User::STATUS_DISABLED => ['title' => 'Deshabilitado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_DISABLED]], + User::STATUS_REMOVED => ['title' => 'Eliminado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_REMOVED]], + ]; + + $roles = Role::whereNotIn('name', ['Patient', 'Doctor'])->get(); + + $this->roles_html_select = ""; + + $this->status_options = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + $this->uso_cfdi_options = UsoCfdi::selectList(); + $this->regimen_fiscal_options = RegimenFiscal::selectList(); + } + + + + + public function render() + { + return view('vuexy-warehouse::livewire.inventory-movements.inventory-movements-index'); + } + +} diff --git a/Livewire/InventoryStock/InventoryStockIndex.php b/Livewire/InventoryStock/InventoryStockIndex.php new file mode 100644 index 0000000..dab768a --- /dev/null +++ b/Livewire/InventoryStock/InventoryStockIndex.php @@ -0,0 +1,109 @@ +tipo_persona_options = [ + User::TIPO_RFC_FISICA => User::$tipoRfcList[User::TIPO_RFC_FISICA], + User::TIPO_RFC_MORAL => User::$tipoRfcList[User::TIPO_RFC_MORAL], + User::TIPO_RFC_PUBLICO => User::$tipoRfcList[User::TIPO_RFC_PUBLICO], + ]; + + $this->estado_options = DB::table('sat_estado') + ->select('sat_estado.c_estado', 'sat_estado.nombre_del_estado') + ->join('sat_codigo_postal', 'sat_estado.c_estado', '=', 'sat_codigo_postal.c_estado') + ->join('users', 'users.domicilio_fiscal', '=', 'sat_codigo_postal.c_codigo_postal') + ->distinct() + ->orderBy('sat_estado.c_estado') + ->pluck('sat_estado.nombre_del_estado', 'sat_estado.c_estado'); + + + $this->status_options = $this->status_list = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + //$this->status = User::STATUS_ENABLED; + $this->status_list_class = User::$statusListClass; + + $this->statuses = [ + User::STATUS_ENABLED => ['title' => 'Activo', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_ENABLED]], + User::STATUS_DISABLED => ['title' => 'Deshabilitado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_DISABLED]], + User::STATUS_REMOVED => ['title' => 'Eliminado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_REMOVED]], + ]; + + $roles = Role::whereNotIn('name', ['Patient', 'Doctor'])->get(); + + $this->roles_html_select = ""; + + $this->status_options = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + $this->uso_cfdi_options = UsoCfdi::selectList(); + $this->regimen_fiscal_options = RegimenFiscal::selectList(); + } + + + + + public function render() + { + return view('vuexy-warehouse::livewire.inventory-stock.inventory-stock-index'); + } + +} diff --git a/Livewire/Materials/MaterialsIndex.php b/Livewire/Materials/MaterialsIndex.php new file mode 100644 index 0000000..519bd56 --- /dev/null +++ b/Livewire/Materials/MaterialsIndex.php @@ -0,0 +1,109 @@ +tipo_persona_options = [ + User::TIPO_RFC_FISICA => User::$tipoRfcList[User::TIPO_RFC_FISICA], + User::TIPO_RFC_MORAL => User::$tipoRfcList[User::TIPO_RFC_MORAL], + User::TIPO_RFC_PUBLICO => User::$tipoRfcList[User::TIPO_RFC_PUBLICO], + ]; + + $this->estado_options = DB::table('sat_estado') + ->select('sat_estado.c_estado', 'sat_estado.nombre_del_estado') + ->join('sat_codigo_postal', 'sat_estado.c_estado', '=', 'sat_codigo_postal.c_estado') + ->join('users', 'users.domicilio_fiscal', '=', 'sat_codigo_postal.c_codigo_postal') + ->distinct() + ->orderBy('sat_estado.c_estado') + ->pluck('sat_estado.nombre_del_estado', 'sat_estado.c_estado'); + + + $this->status_options = $this->status_list = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + //$this->status = User::STATUS_ENABLED; + $this->status_list_class = User::$statusListClass; + + $this->statuses = [ + User::STATUS_ENABLED => ['title' => 'Activo', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_ENABLED]], + User::STATUS_DISABLED => ['title' => 'Deshabilitado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_DISABLED]], + User::STATUS_REMOVED => ['title' => 'Eliminado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_REMOVED]], + ]; + + $roles = Role::whereNotIn('name', ['Patient', 'Doctor'])->get(); + + $this->roles_html_select = ""; + + $this->status_options = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + $this->uso_cfdi_options = UsoCfdi::selectList(); + $this->regimen_fiscal_options = RegimenFiscal::selectList(); + } + + + + + public function render() + { + return view('vuexy-warehouse::livewire.materials.materials-index'); + } + +} diff --git a/Livewire/ProductCatalogs/ProductCatalogsIndex.php b/Livewire/ProductCatalogs/ProductCatalogsIndex.php new file mode 100644 index 0000000..1642d11 --- /dev/null +++ b/Livewire/ProductCatalogs/ProductCatalogsIndex.php @@ -0,0 +1,109 @@ +tipo_persona_options = [ + User::TIPO_RFC_FISICA => User::$tipoRfcList[User::TIPO_RFC_FISICA], + User::TIPO_RFC_MORAL => User::$tipoRfcList[User::TIPO_RFC_MORAL], + User::TIPO_RFC_PUBLICO => User::$tipoRfcList[User::TIPO_RFC_PUBLICO], + ]; + + $this->estado_options = DB::table('sat_estado') + ->select('sat_estado.c_estado', 'sat_estado.nombre_del_estado') + ->join('sat_codigo_postal', 'sat_estado.c_estado', '=', 'sat_codigo_postal.c_estado') + ->join('users', 'users.domicilio_fiscal', '=', 'sat_codigo_postal.c_codigo_postal') + ->distinct() + ->orderBy('sat_estado.c_estado') + ->pluck('sat_estado.nombre_del_estado', 'sat_estado.c_estado'); + + + $this->status_options = $this->status_list = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + //$this->status = User::STATUS_ENABLED; + $this->status_list_class = User::$statusListClass; + + $this->statuses = [ + User::STATUS_ENABLED => ['title' => 'Activo', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_ENABLED]], + User::STATUS_DISABLED => ['title' => 'Deshabilitado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_DISABLED]], + User::STATUS_REMOVED => ['title' => 'Eliminado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_REMOVED]], + ]; + + $roles = Role::whereNotIn('name', ['Patient', 'Doctor'])->get(); + + $this->roles_html_select = ""; + + $this->status_options = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + $this->uso_cfdi_options = UsoCfdi::selectList(); + $this->regimen_fiscal_options = RegimenFiscal::selectList(); + } + + + + + public function render() + { + return view('vuexy-warehouse::livewire.product-catalogs.product-catalogs-index'); + } + +} diff --git a/Livewire/ProductCategories/ProductCategoriesIndex.php b/Livewire/ProductCategories/ProductCategoriesIndex.php new file mode 100644 index 0000000..d87de06 --- /dev/null +++ b/Livewire/ProductCategories/ProductCategoriesIndex.php @@ -0,0 +1,109 @@ +tipo_persona_options = [ + User::TIPO_RFC_FISICA => User::$tipoRfcList[User::TIPO_RFC_FISICA], + User::TIPO_RFC_MORAL => User::$tipoRfcList[User::TIPO_RFC_MORAL], + User::TIPO_RFC_PUBLICO => User::$tipoRfcList[User::TIPO_RFC_PUBLICO], + ]; + + $this->estado_options = DB::table('sat_estado') + ->select('sat_estado.c_estado', 'sat_estado.nombre_del_estado') + ->join('sat_codigo_postal', 'sat_estado.c_estado', '=', 'sat_codigo_postal.c_estado') + ->join('users', 'users.domicilio_fiscal', '=', 'sat_codigo_postal.c_codigo_postal') + ->distinct() + ->orderBy('sat_estado.c_estado') + ->pluck('sat_estado.nombre_del_estado', 'sat_estado.c_estado'); + + + $this->status_options = $this->status_list = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + //$this->status = User::STATUS_ENABLED; + $this->status_list_class = User::$statusListClass; + + $this->statuses = [ + User::STATUS_ENABLED => ['title' => 'Activo', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_ENABLED]], + User::STATUS_DISABLED => ['title' => 'Deshabilitado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_DISABLED]], + User::STATUS_REMOVED => ['title' => 'Eliminado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_REMOVED]], + ]; + + $roles = Role::whereNotIn('name', ['Patient', 'Doctor'])->get(); + + $this->roles_html_select = ""; + + $this->status_options = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + $this->uso_cfdi_options = UsoCfdi::selectList(); + $this->regimen_fiscal_options = RegimenFiscal::selectList(); + } + + + + + public function render() + { + return view('vuexy-warehouse::livewire.product-categories.product-categories-index'); + } + +} diff --git a/Livewire/ProductReceipts/ProductReceiptsIndex.php b/Livewire/ProductReceipts/ProductReceiptsIndex.php new file mode 100644 index 0000000..1c2000e --- /dev/null +++ b/Livewire/ProductReceipts/ProductReceiptsIndex.php @@ -0,0 +1,109 @@ +tipo_persona_options = [ + User::TIPO_RFC_FISICA => User::$tipoRfcList[User::TIPO_RFC_FISICA], + User::TIPO_RFC_MORAL => User::$tipoRfcList[User::TIPO_RFC_MORAL], + User::TIPO_RFC_PUBLICO => User::$tipoRfcList[User::TIPO_RFC_PUBLICO], + ]; + + $this->estado_options = DB::table('sat_estado') + ->select('sat_estado.c_estado', 'sat_estado.nombre_del_estado') + ->join('sat_codigo_postal', 'sat_estado.c_estado', '=', 'sat_codigo_postal.c_estado') + ->join('users', 'users.domicilio_fiscal', '=', 'sat_codigo_postal.c_codigo_postal') + ->distinct() + ->orderBy('sat_estado.c_estado') + ->pluck('sat_estado.nombre_del_estado', 'sat_estado.c_estado'); + + + $this->status_options = $this->status_list = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + //$this->status = User::STATUS_ENABLED; + $this->status_list_class = User::$statusListClass; + + $this->statuses = [ + User::STATUS_ENABLED => ['title' => 'Activo', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_ENABLED]], + User::STATUS_DISABLED => ['title' => 'Deshabilitado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_DISABLED]], + User::STATUS_REMOVED => ['title' => 'Eliminado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_REMOVED]], + ]; + + $roles = Role::whereNotIn('name', ['Patient', 'Doctor'])->get(); + + $this->roles_html_select = ""; + + $this->status_options = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + $this->uso_cfdi_options = UsoCfdi::selectList(); + $this->regimen_fiscal_options = RegimenFiscal::selectList(); + } + + + + + public function render() + { + return view('vuexy-warehouse::livewire.product-receipts.product-receipts-index'); + } + +} diff --git a/Livewire/Products/ProductsIndex.php b/Livewire/Products/ProductsIndex.php new file mode 100644 index 0000000..5356aa2 --- /dev/null +++ b/Livewire/Products/ProductsIndex.php @@ -0,0 +1,109 @@ +tipo_persona_options = [ + User::TIPO_RFC_FISICA => User::$tipoRfcList[User::TIPO_RFC_FISICA], + User::TIPO_RFC_MORAL => User::$tipoRfcList[User::TIPO_RFC_MORAL], + User::TIPO_RFC_PUBLICO => User::$tipoRfcList[User::TIPO_RFC_PUBLICO], + ]; + + $this->estado_options = DB::table('sat_estado') + ->select('sat_estado.c_estado', 'sat_estado.nombre_del_estado') + ->join('sat_codigo_postal', 'sat_estado.c_estado', '=', 'sat_codigo_postal.c_estado') + ->join('users', 'users.domicilio_fiscal', '=', 'sat_codigo_postal.c_codigo_postal') + ->distinct() + ->orderBy('sat_estado.c_estado') + ->pluck('sat_estado.nombre_del_estado', 'sat_estado.c_estado'); + + + $this->status_options = $this->status_list = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + //$this->status = User::STATUS_ENABLED; + $this->status_list_class = User::$statusListClass; + + $this->statuses = [ + User::STATUS_ENABLED => ['title' => 'Activo', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_ENABLED]], + User::STATUS_DISABLED => ['title' => 'Deshabilitado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_DISABLED]], + User::STATUS_REMOVED => ['title' => 'Eliminado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_REMOVED]], + ]; + + $roles = Role::whereNotIn('name', ['Patient', 'Doctor'])->get(); + + $this->roles_html_select = ""; + + $this->status_options = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + $this->uso_cfdi_options = UsoCfdi::selectList(); + $this->regimen_fiscal_options = RegimenFiscal::selectList(); + } + + + + + public function render() + { + return view('vuexy-warehouse::livewire.products.products-index'); + } + +} diff --git a/Livewire/PurchaseOrders/PurchaseOrdersIndex.php b/Livewire/PurchaseOrders/PurchaseOrdersIndex.php new file mode 100644 index 0000000..c44de8f --- /dev/null +++ b/Livewire/PurchaseOrders/PurchaseOrdersIndex.php @@ -0,0 +1,109 @@ +tipo_persona_options = [ + User::TIPO_RFC_FISICA => User::$tipoRfcList[User::TIPO_RFC_FISICA], + User::TIPO_RFC_MORAL => User::$tipoRfcList[User::TIPO_RFC_MORAL], + User::TIPO_RFC_PUBLICO => User::$tipoRfcList[User::TIPO_RFC_PUBLICO], + ]; + + $this->estado_options = DB::table('sat_estado') + ->select('sat_estado.c_estado', 'sat_estado.nombre_del_estado') + ->join('sat_codigo_postal', 'sat_estado.c_estado', '=', 'sat_codigo_postal.c_estado') + ->join('users', 'users.domicilio_fiscal', '=', 'sat_codigo_postal.c_codigo_postal') + ->distinct() + ->orderBy('sat_estado.c_estado') + ->pluck('sat_estado.nombre_del_estado', 'sat_estado.c_estado'); + + + $this->status_options = $this->status_list = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + //$this->status = User::STATUS_ENABLED; + $this->status_list_class = User::$statusListClass; + + $this->statuses = [ + User::STATUS_ENABLED => ['title' => 'Activo', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_ENABLED]], + User::STATUS_DISABLED => ['title' => 'Deshabilitado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_DISABLED]], + User::STATUS_REMOVED => ['title' => 'Eliminado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_REMOVED]], + ]; + + $roles = Role::whereNotIn('name', ['Patient', 'Doctor'])->get(); + + $this->roles_html_select = ""; + + $this->status_options = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + $this->uso_cfdi_options = UsoCfdi::selectList(); + $this->regimen_fiscal_options = RegimenFiscal::selectList(); + } + + + + + public function render() + { + return view('vuexy-warehouse::livewire.purchase-orders.purchase-orders-index'); + } + +} diff --git a/Livewire/WarehouseMovements/WarehouseMovementsIndex.php b/Livewire/WarehouseMovements/WarehouseMovementsIndex.php new file mode 100644 index 0000000..018a218 --- /dev/null +++ b/Livewire/WarehouseMovements/WarehouseMovementsIndex.php @@ -0,0 +1,109 @@ +tipo_persona_options = [ + User::TIPO_RFC_FISICA => User::$tipoRfcList[User::TIPO_RFC_FISICA], + User::TIPO_RFC_MORAL => User::$tipoRfcList[User::TIPO_RFC_MORAL], + User::TIPO_RFC_PUBLICO => User::$tipoRfcList[User::TIPO_RFC_PUBLICO], + ]; + + $this->estado_options = DB::table('sat_estado') + ->select('sat_estado.c_estado', 'sat_estado.nombre_del_estado') + ->join('sat_codigo_postal', 'sat_estado.c_estado', '=', 'sat_codigo_postal.c_estado') + ->join('users', 'users.domicilio_fiscal', '=', 'sat_codigo_postal.c_codigo_postal') + ->distinct() + ->orderBy('sat_estado.c_estado') + ->pluck('sat_estado.nombre_del_estado', 'sat_estado.c_estado'); + + + $this->status_options = $this->status_list = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + //$this->status = User::STATUS_ENABLED; + $this->status_list_class = User::$statusListClass; + + $this->statuses = [ + User::STATUS_ENABLED => ['title' => 'Activo', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_ENABLED]], + User::STATUS_DISABLED => ['title' => 'Deshabilitado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_DISABLED]], + User::STATUS_REMOVED => ['title' => 'Eliminado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_REMOVED]], + ]; + + $roles = Role::whereNotIn('name', ['Patient', 'Doctor'])->get(); + + $this->roles_html_select = ""; + + $this->status_options = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + $this->uso_cfdi_options = UsoCfdi::selectList(); + $this->regimen_fiscal_options = RegimenFiscal::selectList(); + } + + + + + public function render() + { + return view('vuexy-warehouse::livewire.warehouse-movements.warehouse-movements-index'); + } + +} diff --git a/Livewire/WarehouseTransfers/WarehouseTransfersIndex.php b/Livewire/WarehouseTransfers/WarehouseTransfersIndex.php new file mode 100644 index 0000000..a4adea6 --- /dev/null +++ b/Livewire/WarehouseTransfers/WarehouseTransfersIndex.php @@ -0,0 +1,109 @@ +tipo_persona_options = [ + User::TIPO_RFC_FISICA => User::$tipoRfcList[User::TIPO_RFC_FISICA], + User::TIPO_RFC_MORAL => User::$tipoRfcList[User::TIPO_RFC_MORAL], + User::TIPO_RFC_PUBLICO => User::$tipoRfcList[User::TIPO_RFC_PUBLICO], + ]; + + $this->estado_options = DB::table('sat_estado') + ->select('sat_estado.c_estado', 'sat_estado.nombre_del_estado') + ->join('sat_codigo_postal', 'sat_estado.c_estado', '=', 'sat_codigo_postal.c_estado') + ->join('users', 'users.domicilio_fiscal', '=', 'sat_codigo_postal.c_codigo_postal') + ->distinct() + ->orderBy('sat_estado.c_estado') + ->pluck('sat_estado.nombre_del_estado', 'sat_estado.c_estado'); + + + $this->status_options = $this->status_list = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + //$this->status = User::STATUS_ENABLED; + $this->status_list_class = User::$statusListClass; + + $this->statuses = [ + User::STATUS_ENABLED => ['title' => 'Activo', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_ENABLED]], + User::STATUS_DISABLED => ['title' => 'Deshabilitado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_DISABLED]], + User::STATUS_REMOVED => ['title' => 'Eliminado', 'class' => 'badge bg-label-' . User::$statusListClass[User::STATUS_REMOVED]], + ]; + + $roles = Role::whereNotIn('name', ['Patient', 'Doctor'])->get(); + + $this->roles_html_select = ""; + + $this->status_options = [ + User::STATUS_ENABLED => User::$statusList[User::STATUS_ENABLED], + User::STATUS_DISABLED => User::$statusList[User::STATUS_DISABLED], + ]; + + $this->uso_cfdi_options = UsoCfdi::selectList(); + $this->regimen_fiscal_options = RegimenFiscal::selectList(); + } + + + + + public function render() + { + return view('vuexy-warehouse::livewire.warehouse-transfers.warehouse-transfers-index'); + } + +} diff --git a/Livewire/Warehouses/WarehouseIndex.php b/Livewire/Warehouses/WarehouseIndex.php new file mode 100644 index 0000000..91391b4 --- /dev/null +++ b/Livewire/Warehouses/WarehouseIndex.php @@ -0,0 +1,221 @@ + 'Acciones', + 'store_code' => 'Código de Tienda', + 'store_name' => 'Nombre de la Tienda', + 'work_center_code' => 'Código del Centro de Trabajo', + 'work_center_name' => 'Nombre del Centro de Trabajo', + 'code' => 'Código de Almacén', + 'name' => 'Nombre del Almacén', + 'description' => 'Descripción', + 'manager_name' => 'Encargado', + 'pais' => 'País', + 'estado' => 'Estado', + 'localidad' => 'Localidad', + 'municipio' => 'Municipio', + 'codigo_postal' => 'Código Postal', + 'colonia' => 'Colonia', + 'direccion' => 'Dirección', + 'tel' => 'Teléfono', + 'tel2' => 'Teléfono Alternativo', + 'priority' => 'Prioridad', + 'status' => 'Estatus', + 'created_at' => 'Fecha de Creación', + 'updated_at' => 'Última Actualización', + ]; + } + + /** + * Define los formatos de cada columna (se inyectará en $bt_datatable['format']). + * + * @return array + */ + protected function format(): array + { + return [ + 'action' => [ + 'formatter' => 'warehouseActionFormatter', + 'onlyFormatter' => true, + ], + 'store_code' => [ + 'formatter' => [ + 'name' => 'dynamicBadgeFormatter', + 'params' => ['color' => 'secondary'] + ], + 'align' => 'center', + 'visible' => false, + ], + 'work_center_code' => [ + 'formatter' => [ + 'name' => 'dynamicBadgeFormatter', + 'params' => ['color' => 'secondary'] + ], + 'align' => 'center', + 'visible' => false, + ], + 'work_center_name' => [ + 'visible' => false, + ], + 'code' => [ + 'formatter' => [ + 'name' => 'dynamicBadgeFormatter', + 'params' => ['color' => 'secondary'], + ], + 'align' => 'center', + 'switchable' => false, + ], + 'name' => [ + 'switchable' => false, + ], + 'description' => [ + 'visible' => false, + ], + 'manager_name' => [ + 'formatter' => 'managerFormatter', + ], + 'tel' => [ + 'formatter' => 'telFormatter', + 'align' => 'center', + ], + 'tel2' => [ + 'formatter' => 'telFormatter', + 'align' => 'center', + 'visible' => false, + ], + 'pais' => [ + 'align' => 'center', + 'visible' => false, + ], + 'estado' => [ + 'formatter' => 'textNowrapFormatter', + 'visible' => false, + ], + 'localidad' => [ + 'formatter' => 'textNowrapFormatter', + 'visible' => false, + ], + 'municipio' => [ + 'formatter' => 'textNowrapFormatter', + 'visible' => false, + ], + 'codigo_postal' => [ + 'align' => 'center', + 'visible' => false, + ], + 'colonia' => [ + 'formatter' => 'textNowrapFormatter', + 'visible' => false, + ], + 'direccion' => [ + 'formatter' => 'direccionFormatter', + 'visible' => false, + ], + 'priority' => [ + 'formatter' => 'numberFormatter', + 'align' => 'center', + ], + 'status' => [ + 'formatter' => [ + 'name' => 'dynamicBooleanFormatter', + 'params' => ['tag' => 'activo'] + ], + 'align' => 'center', + ], + 'created_at' => [ + 'formatter' => 'textNowrapFormatter', + 'align' => 'center', + 'visible' => false, + ], + 'updated_at' => [ + 'formatter' => 'textNowrapFormatter', + 'align' => 'center', + 'visible' => false, + ], + ]; + } + + /** + * Retorna la configuración base (común) para la tabla Bootstrap Table. + * + * @return array + */ + protected function bootstraptableConfig(): array + { + return [ + 'sortName' => 'code', + 'exportFileName' => 'Almacenes', + 'showFullscreen' => false, + 'showPaginationSwitch' => false, + 'showRefresh' => false, + 'pagination' => false, + ]; + } + + /** + * Retorna la ruta de la vista Blade. + * + * @return string + */ + protected function viewPath(): string + { + // La vista que ya tienes creada para WarehouseIndex + return 'vuexy-warehouse::livewire.warehouses.index'; + } + + /** + * Métodos que necesites sobreescribir o extender. + */ + public function mount(): void + { + parent::mount(); + + // Cargar opciones de tienda, por ejemplo: + $storeCatalogService = app(StoreCatalogService::class); + $this->storeOptions = $storeCatalogService->searchCatalog('stores', '', ['limit' => -1]); + } + + /** + * Puedes agregar lógica de filtrado específica para warehouses, + * si lo requieres, sobrescribiendo el método applyFilters del padre. + */ + protected function applyFilters($criteria = []) + { + $query = parent::applyFilters($criteria); + + // Ejemplo de aplicar filtro por store_id + if ($this->store_id) { + $query->where('store_id', $this->store_id); + } + + return $query; + } +} diff --git a/Livewire/Warehouses/WarehouseOffcanvasForm.php b/Livewire/Warehouses/WarehouseOffcanvasForm.php new file mode 100644 index 0000000..d4156cc --- /dev/null +++ b/Livewire/Warehouses/WarehouseOffcanvasForm.php @@ -0,0 +1,219 @@ + 'loadFormModel', + 'confirmDeletionWarehouse' => 'loadFormModelForDeletion', + ]; + + /** + * Definición de tipos de datos que se deben castear. + * + * @var array + */ + protected $casts = [ + 'status' => 'boolean', + ]; + + /** + * Define el modelo Eloquent asociado con el formulario. + * + * @return string + */ + protected function model(): string + { + return Warehouse::class; + } + + /** + * Define los campos del formulario. + * + * @return array + */ + protected function fields(): array + { + return (new Warehouse())->getFillable(); + } + + /** + * Valores por defecto para el formulario. + * + * @return array + */ + protected function defaults(): array + { + return [ + 'priority' => 0, + 'status' => true, + ]; + } + + /** + * Campo que se debe enfocar cuando se abra el formulario. + * + * @return string + */ + protected function focusOnOpen(): string + { + return 'code'; + } + + /** + * Define reglas de validación dinámicas basadas en el modo actual. + * + * @param string $mode El modo actual del formulario ('create', 'edit', 'delete'). + * @return array + */ + protected function dynamicRules(string $mode): array + { + switch ($mode) { + case 'create': + case 'edit': + return [ + 'store_id' => ['required', 'integer', 'exists:stores,id'], + 'work_center_id' => ['nullable', 'integer', 'exists:store_work_centers,id'], + 'code' => ['required', 'string', 'max:16', Rule::unique('warehouses', 'code')->ignore($this->id)], + 'name' => ['required', 'string', 'max:96'], + 'description' => ['nullable', 'string', 'max:1024'], + 'manager_id' => ['nullable', 'integer', 'exists:users,id'], + 'tel' => ['nullable', 'regex:/^[0-9+\-\s]+$/', 'max:20'], + 'tel2' => ['nullable', 'regex:/^[0-9+\-\s]+$/', 'max:20'], + 'priority' => ['nullable', 'numeric', 'between:0,99'], + 'status' => ['nullable', 'boolean'], + ]; + + case 'delete': + return [ + 'confirmDeletion' => 'accepted', // Asegura que el usuario confirme la eliminación + ]; + + default: + return []; + } + } + + // ===================== VALIDACIONES ===================== + + /** + * Get custom attributes for validator errors. + * + * @return array + */ + protected function attributes(): array + { + return [ + 'code' => 'código de almacén', + 'name' => 'nombre del almacén', + ]; + } + + /** + * Get the error messages for the defined validation rules. + * + * @return array + */ + protected function messages(): array + { + return [ + 'store_id.required' => 'El almacén debe estar asociado a un negocio.', + 'code.required' => 'El código del almacén es obligatorio.', + 'code.unique' => 'Este código ya está en uso por otro almacén.', + 'name.required' => 'El nombre del almacén es obligatorio.', + ]; + } + + /** + * Carga el formulario con datos del almacén y actualiza las opciones dinámicas. + * + * @param int $id + */ + public function loadFormModel($id): void + { + parent::loadFormModel($id); + + $this->work_center_options = $this->store_id + ? DB::table('store_work_centers') + ->where('store_id', $this->store_id) + ->pluck('name', 'id') + ->toArray() + : []; + } + + /** + * Carga el formulario para eliminar un almacén, actualizando las opciones necesarias. + * + * @param int $id + */ + public function loadFormModelForDeletion($id): void + { + parent::loadFormModelForDeletion($id); + + $this->work_center_options = DB::table('store_work_centers') + ->where('store_id', $this->store_id) + ->pluck('name', 'id') + ->toArray(); + } + + /** + * Define las opciones de los selectores desplegables. + * + * @return array + */ + protected function options(): array + { + $storeCatalogService = app(StoreCatalogService::class); + $contactCatalogService = app(ContactCatalogService::class); + + return [ + 'store_options' => $storeCatalogService->searchCatalog('stores', '', ['limit' => -1]), + 'manager_options' => $contactCatalogService->searchCatalog('users', '', ['limit' => -1]), + ]; + } + + /** + * Ruta de la vista asociada con este formulario. + * + * @return string + */ + protected function viewPath(): string + { + return 'vuexy-warehouse::livewire.warehouses.form-offcanvas'; + } +} diff --git a/Models/Currency.php b/Models/Currency.php new file mode 100644 index 0000000..96dcc6e --- /dev/null +++ b/Models/Currency.php @@ -0,0 +1,19 @@ + 'decimal:6', + 'status' => 'boolean' + ]; +} diff --git a/Models/FixedAsset.php b/Models/FixedAsset.php new file mode 100644 index 0000000..446a134 --- /dev/null +++ b/Models/FixedAsset.php @@ -0,0 +1,20 @@ + 'date', + 'value' => 'decimal:2', + 'status' => 'boolean' + ]; +} diff --git a/Models/InventoryMovement.php b/Models/InventoryMovement.php new file mode 100644 index 0000000..e0c4cf8 --- /dev/null +++ b/Models/InventoryMovement.php @@ -0,0 +1,84 @@ + 'decimal:6', + 'cost' => 'decimal:2', + 'cost_before' => 'decimal:2', + 'cost_after' => 'decimal:2', + 'cost_type' => 'string', + ]; + + /** + * Relación con el producto. + */ + public function product(): BelongsTo + { + return $this->belongsTo(Product::class, 'product_id'); + } + + /** + * Relación con la sucursal. + */ + public function store(): BelongsTo + { + return $this->belongsTo(Store::class, 'store_id'); + } + + /** + * Relación con el almacén. + */ + public function warehouse(): BelongsTo + { + return $this->belongsTo(Warehouse::class, 'warehouse_id'); + } + + /** + * Relación con el usuario que creó el movimiento. + */ + public function createdBy(): BelongsTo + { + return $this->belongsTo(User::class, 'created_by'); + } + + /** + * Relación polimórfica para vincular diferentes transacciones. + */ + public function transactionable(): MorphTo + { + return $this->morphTo(); + } +} diff --git a/Models/InventoryStockLevel.php b/Models/InventoryStockLevel.php new file mode 100644 index 0000000..56a5939 --- /dev/null +++ b/Models/InventoryStockLevel.php @@ -0,0 +1,62 @@ + 'decimal:6', + 'pos_stock' => 'decimal:6', + 'ecommerce_stock' => 'decimal:6', + 'purchase_reserved_stock' => 'decimal:6', + 'asset_stock' => 'decimal:6', + 'last_cost' => 'decimal:2', + 'average_cost' => 'decimal:2', + 'total_last_cost' => 'decimal:2', + 'total_average_cost' => 'decimal:2', + 'total_identified_cost' => 'decimal:2', + 'costing_method' => 'integer', + ]; + + /** + * Verificar que el stock en áreas no supere el stock total + */ + public static function boot() + { + parent::boot(); + + static::saving(function ($inventory) { + $totalReserved = $inventory->pos_stock + $inventory->ecommerce_stock + $inventory->purchase_reserved_stock + $inventory->asset_stock; + if ($totalReserved > $inventory->quantity) { + throw new \Exception("Error: El stock reservado no puede ser mayor al stock total."); + } + }); + } + + public function product() + { + return $this->belongsTo(Product::class, 'product_id'); + } + + public function store(): BelongsTo + { + return $this->belongsTo(Store::class, 'store_id'); + } + + public function warehouse() + { + return $this->belongsTo(Warehouse::class, 'warehouse_id'); + } +} diff --git a/Models/LotNumber.php b/Models/LotNumber.php new file mode 100644 index 0000000..b697e3b --- /dev/null +++ b/Models/LotNumber.php @@ -0,0 +1,62 @@ + 'date', + 'expiry_date' => 'date', + 'initial_quantity' => 'decimal:6', + 'remaining_quantity' => 'decimal:6', + 'cost' => 'decimal:2', + ]; + + /** + * Relación con el producto. + */ + public function product(): BelongsTo + { + return $this->belongsTo(Product::class, 'product_id'); + } + + /** + * Relación con la sucursal. + */ + public function store(): BelongsTo + { + return $this->belongsTo(Store::class, 'store_id'); + } + + /** + * Relación con el almacén. + */ + public function warehouse(): BelongsTo + { + return $this->belongsTo(Warehouse::class, 'warehouse_id'); + } +} diff --git a/Models/Product.php b/Models/Product.php new file mode 100644 index 0000000..7a312d4 --- /dev/null +++ b/Models/Product.php @@ -0,0 +1,134 @@ + 'boolean', + 'available_in_ecommerce' => 'boolean', + 'available_in_purchases' => 'boolean', + 'available_in_maanufacturing' => 'boolean', + 'available_in_quality' => 'boolean', + 'available_in_assets' => 'boolean', + 'costo' => 'decimal:2', + 'traslados' => 'decimal:6', + 'retenciones' => 'decimal:6', + 'minimum_unit' => 'decimal:6', + 'minimum_stock' => 'decimal:6', + 'maximum_stock' => 'decimal:6', + 'data_lot_enable' => 'boolean', + 'data_lot_require' => 'boolean', + 'data_series_enable' => 'boolean', + 'data_series_require' => 'boolean', + 'data_expiration_enable' => 'boolean', + 'data_expiration_require' => 'boolean', + 'data_warranty_enable' => 'boolean', + 'data_best_before_enable' => 'boolean', + 'data_best_before_require' => 'boolean', + 'data_observations_enable' => 'boolean', + 'affects_inventory' => 'boolean', + 'alert_minimum_stock' => 'boolean', + 'alert_maximum_stock' => 'boolean', + ]; + + /** + * Relación con la categoría del producto. + */ + public function category(): BelongsTo + { + return $this->belongsTo(ProductCategory::class, 'category_id'); + } + + /** + * Relación con la moneda. + */ + public function currency(): BelongsTo + { + return $this->belongsTo(Currency::class, 'c_moneda', 'c_currency'); + } + + /** + * Relación con la clave unidad SAT. + */ + public function claveUnidad(): BelongsTo + { + return $this->belongsTo(ClaveUnidad::class, 'c_clave_unidad', 'c_clave_unidad'); + } + + /** + * Relación con la clave de producto/servicio SAT. + */ + public function claveProdServ(): BelongsTo + { + return $this->belongsTo(ClaveProdServ::class, 'c_clave_prod_serv', 'c_clave_prod_serv'); + } + + /** + * Relación con el usuario que creó el producto. + */ + public function createdBy(): BelongsTo + { + return $this->belongsTo(User::class, 'created_by'); + } +} diff --git a/Models/ProductCategory.php b/Models/ProductCategory.php new file mode 100644 index 0000000..70cc7e7 --- /dev/null +++ b/Models/ProductCategory.php @@ -0,0 +1,68 @@ + 'boolean', + 'show_in_purchases' => 'boolean', + 'show_in_ecommerce' => 'boolean', + 'show_in_manufacturing' => 'boolean', + 'show_in_quality' => 'boolean', + 'show_in_assets' => 'boolean', + 'order' => 'integer', + ]; + + /** + * Relación con la categoría padre. + */ + public function parent(): BelongsTo + { + return $this->belongsTo(ProductCategory::class, 'parent_id'); + } + + /** + * Relación con categorías hijas. + */ + public function children(): HasMany + { + return $this->hasMany(ProductCategory::class, 'parent_id'); + } + + /** + * Relación con productos. + */ + public function products(): HasMany + { + return $this->hasMany(Product::class, 'category_id'); + } +} diff --git a/Models/ProductProperty.php b/Models/ProductProperty.php new file mode 100644 index 0000000..9b57fea --- /dev/null +++ b/Models/ProductProperty.php @@ -0,0 +1,29 @@ +hasMany(ProductPropertyValue::class, 'property_id'); + } +} diff --git a/Models/ProductPropertyValue.php b/Models/ProductPropertyValue.php new file mode 100644 index 0000000..b7174aa --- /dev/null +++ b/Models/ProductPropertyValue.php @@ -0,0 +1,39 @@ +belongsTo(Product::class, 'product_id'); + } + + /** + * Relación con la propiedad del producto. + */ + public function property(): BelongsTo + { + return $this->belongsTo(ProductProperty::class, 'property_id'); + } +} diff --git a/Models/Warehouse.php b/Models/Warehouse.php new file mode 100644 index 0000000..74c7014 --- /dev/null +++ b/Models/Warehouse.php @@ -0,0 +1,94 @@ + 'integer', + 'status' => 'boolean', + ]; + + /** + * Nombre de la etiqueta para generar Componentes + * + * @var string + */ + public $tagName = 'Warehouse'; + + /** + * Nombre de la columna que contiee el nombre del registro + * + * @var string + */ + public $columnNameLabel = 'name'; + + /** + * Nombre singular del registro. + * + * @var string + */ + public $singularName = 'almacén'; + + /** + * Nombre plural del registro. + * + * @var string + */ + public $pluralName = 'almacenes'; + + /** + * Relación con la sucursal a la que pertenece el almacén. + */ + public function store(): BelongsTo + { + return $this->belongsTo(Store::class, 'store_id'); + } + + /** + * Relación con el usuario que gestiona el centro de trabajo. + */ + public function manager(): BelongsTo + { + return $this->belongsTo(User::class, 'manager_id'); + } + + /** + * Relación con la sucursal a la que pertenece el almacén. + */ + public function workcenter(): BelongsTo + { + return $this->belongsTo(StoreWorkCenter::class, 'work_center_id'); + } + + /** + * Relación con los movimientos de inventario del almacén. + */ + public function movements(): HasMany + { + return $this->hasMany(WarehouseMovement::class, 'warehouse_id'); + } +} diff --git a/Models/WarehouseMovement.php b/Models/WarehouseMovement.php new file mode 100644 index 0000000..a83e513 --- /dev/null +++ b/Models/WarehouseMovement.php @@ -0,0 +1,80 @@ + 'decimal:6', + 'cost' => 'decimal:2', + 'status' => 'integer', + ]; + + /** + * Relación con la sucursal donde ocurrió el movimiento. + */ + public function store(): BelongsTo + { + return $this->belongsTo(Store::class, 'store_id'); + } + + /** + * Relación con el almacén de origen del movimiento. + */ + public function warehouse(): BelongsTo + { + return $this->belongsTo(Warehouse::class, 'warehouse_id'); + } + + /** + * Relación con el almacén de destino (si aplica). + */ + public function toWarehouse(): BelongsTo + { + return $this->belongsTo(Warehouse::class, 'to_warehouse_id'); + } + + /** + * Relación con el usuario que creó el movimiento. + */ + public function createdBy(): BelongsTo + { + return $this->belongsTo(User::class, 'created_by'); + } + + /** + * Relación con el usuario que aprobó el movimiento (si aplica). + */ + public function approvedBy(): BelongsTo + { + return $this->belongsTo(User::class, 'approved_by'); + } +} diff --git a/Providers/VuexyWarehouseServiceProvider.php b/Providers/VuexyWarehouseServiceProvider.php new file mode 100644 index 0000000..d9876f9 --- /dev/null +++ b/Providers/VuexyWarehouseServiceProvider.php @@ -0,0 +1,63 @@ +loadRoutesFrom(__DIR__.'/../routes/admin.php'); + + + // Cargar vistas del paquete + $this->loadViewsFrom(__DIR__.'/../resources/views', 'vuexy-warehouse'); + + + // Register the migrations + $this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); + + + // Registrar Livewire Components + $components = [ + 'warehouse-index' => WarehouseIndex::class, + 'warehouse-offcanvas-form' => WarehouseOffcanvasForm::class, + 'product-index' => ProductIndex::class, + 'product-form' => ProductForm::class, + 'product-property-index' => ProductPropertyIndex::class, + 'product-property-offcanvas-form' => ProductPropertyOffcanvasForm::class, + 'product-category-index' => ProductCategoryIndex::class, + 'product-receipts-index' => ProductReceiptsIndex::class, + 'product-receipts-form' => ProductReceiptsForm::class, + 'inventory-index' => InventoryIndex::class, + 'inventory-movements-index' => InventoryMovementsIndex::class, + 'inventory-movements-form' => InventoryMovementsForm::class, + 'warehouse-transfer-index' => WarehouseTransferIndex::class, + 'warehouse-transfer-form' => WarehouseTransferForm::class, + ]; + + foreach ($components as $alias => $component) { + Livewire::component($alias, $component); + } + + + // Registrar auditoría en usuarios + //User::observe(AuditableObserver::class); + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..aaafd8e --- /dev/null +++ b/README.md @@ -0,0 +1,133 @@ +# 🎨 Laravel Vuexy Warehouse - Vuexy Admin + +

+ Koneko Soluciones Tecnológicas Logo +

+

+ Sitio Web + Latest Stable Version + License + Servidor Git + Build Status + Issues +

+ +--- + +## 📌 Descripción + +**Laravel Vuexy Warehouse** es un módulo diseñado para **Laravel Vuexy Admin**, proporcionando [breve descripción de la funcionalidad]. + +### ✨ Características: +- 🔹 Integración completa con Vuexy Admin. +- 🔹 Funcionalidad clave 1. +- 🔹 Funcionalidad clave 2. + +--- + +## 📦 Instalación + +Instalar vía **Composer**: + +```bash +composer require koneko/laravel-vuexy-warehouse +``` + +Publicar archivos de configuración y migraciones (si aplica): + +```bash +php artisan vendor:publish --tag=laravel-vuexy-warehouse-config +php artisan migrate +``` + +--- + +## 🚀 Uso básico + +```php +use Koneko\NombreLibreria\Models\Model; + +$model = Model::create([ + 'campo1' => 'Valor', + 'campo2' => 'Otro valor', +]); +``` + +--- + +## 📚 Configuración adicional + +Si necesitas personalizar la configuración del módulo, publica el archivo de configuración: + +```bash +php artisan vendor:publish --tag=laravel-vuexy-warehouse-config +``` + +Esto generará `config/nombre_libreria.php`, donde puedes modificar valores predeterminados. + +--- + +## 🛠 Dependencias + +Este paquete requiere las siguientes dependencias: +- Laravel 11 +- `koneko/laravel-vuexy-warehouse` +- Dependencias específicas de la librería + +--- + +## 📦 Publicación de Assets y Configuraciones + +Para publicar configuraciones y seeders: + +```bash +php artisan vendor:publish --tag=laravel-vuexy-warehouse-config +php artisan vendor:publish --tag=laravel-vuexy-warehouse-seeders +php artisan migrate --seed +``` + +Para publicar imágenes del tema: + +```bash +php artisan vendor:publish --tag=laravel-vuexy-warehouse-images +``` + +--- + +## 🛠 Pruebas + +Ejecuta los tests con: + +```bash +php artisan test +``` + +--- + +## 🌍 Repositorio Principal y Sincronización + +Este repositorio es una **copia sincronizada** del repositorio principal alojado en **[Tea - Koneko Git](https://git.koneko.mx/koneko/laravel-vuexy-warehouse)**. + +### 🔄 Sincronización con GitHub +- **Repositorio Principal:** [git.koneko.mx](https://git.koneko.mx/koneko/laravel-vuexy-warehouse) +- **Repositorio en GitHub:** [github.com/koneko/laravel-vuexy-warehouse](https://github.com/koneko/laravel-vuexy-warehouse) +- **Los cambios pueden reflejarse primero en Tea antes de GitHub.** + +### 🤝 Contribuciones +Si deseas contribuir: +1. Puedes abrir un **Issue** en [GitHub Issues](https://github.com/koneko/laravel-vuexy-warehouse/issues). +2. Para Pull Requests, **preferimos contribuciones en Tea**. Contacta a `admin@koneko.mx` para solicitar acceso. + +⚠️ **Nota:** Algunos cambios pueden tardar en reflejarse en GitHub, ya que este repositorio se actualiza automáticamente desde Tea. + +--- + +## 🏅 Licencia + +Este paquete es de código abierto bajo la licencia [MIT](LICENSE). + +--- + +

+ Hecho con ❤️ por Koneko Soluciones Tecnológicas +

diff --git a/Services/WarehouseCatalogService.php b/Services/WarehouseCatalogService.php new file mode 100644 index 0000000..e6075a2 --- /dev/null +++ b/Services/WarehouseCatalogService.php @@ -0,0 +1,98 @@ + [ + 'table' => 'warehouses', + 'key' => 'id', + 'value' => "CONCAT(code, ' - ', name) as item", + 'search_columns' => ['code', 'name'], + 'order_by' => 'name', + 'limit' => 15, + ], + 'store_warehouses' => [ + 'table' => 'warehouses', + 'key' => 'id', + 'value' => "CONCAT(code, ' - ', name) as item", + 'search_columns' => ['code', 'name'], + 'extra_conditions' => ['store_id'], + 'order_by' => 'name', + 'limit' => 15, + ], + 'product_categories' => [ + 'table' => 'product_categories', + 'key' => 'id', + 'value' => "CONCAT(name, ' - ', slug) as item", + 'search_columns' => ['name', 'slug'], + 'order_by' => 'name', + 'limit' => 20, + ], + 'products' => [ + 'table' => 'products', + 'key' => 'id', + 'value' => "CONCAT(no_identificacion, ' - ', descripcion) as item", + 'search_columns' => ['no_identificacion', 'descripcion'], + 'order_by' => 'descripcion', + 'limit' => 20, + ], + 'inventory_levels' => [ + 'table' => 'inventory_stock_levels', + 'key' => 'id', + 'value' => "CONCAT(product_id, ' - ', quantity) as item", + 'search_columns' => ['product_id', 'quantity'], + 'extra_conditions' => ['warehouse_id'], + 'order_by' => 'quantity', + 'limit' => 10, + ], + ]; + + /** + * Busca registros en los catálogos del módulo de almacenes. + * + * @param string $catalog + * @param string|null $searchTerm + * @param array $options + * @return array + */ + public function searchCatalog(string $catalog, ?string $searchTerm = '', array $options = []): array + { + if (!isset($this->catalogs[$catalog])) { + return []; + } + + $config = $this->catalogs[$catalog]; + $query = DB::table($config['table']); + + // Selección de columnas + $query->selectRaw("{$config['key']}, {$config['value']}"); + + // Aplicar condiciones extra + if (!empty($config['extra_conditions'])) { + foreach ($config['extra_conditions'] as $column => $value) { + if (isset($options[$column])) { + $query->where($column, $options[$column]); + } + } + } + + // Búsqueda + if ($searchTerm) { + $query->where(function ($subQ) use ($config, $searchTerm) { + foreach ($config['search_columns'] as $column) { + $subQ->orWhere($column, 'LIKE', "%{$searchTerm}%"); + } + }); + } + + // Orden y límite + $query->orderBy($config['order_by'] ?? $config['key'], 'asc'); + $query->limit($options['limit'] ?? $config['limit'] ?? 20); + + return $query->pluck('item', $config['key'])->toArray(); + } +} diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..f753145 --- /dev/null +++ b/composer.json @@ -0,0 +1,36 @@ +{ + "name": "koneko/laravel-vuexy-warehouse", + "description": "Laravel Vuexy Warehouse, un modulo administrativo de almacenes optimizado para México.", + "keywords": ["laravel", "koneko", "framework", "vuexy", "warehouse", "admin", "mexico"], + "type": "library", + "license": "MIT", + "require": { + "php": "^8.2", + "koneko/laravel-vuexy-store-manager": "@dev", + "laravel/framework": "^11.31" + }, + "autoload": { + "psr-4": { + "Koneko\\VuexyWarehouse\\": "" + } + }, + "extra": { + "laravel": { + "providers": [ + "Koneko\\VuexyWarehouse\\Providers\\VuexyWarehouseServiceProvider" + ] + } + }, + "authors": [ + { + "name": "Arturo Corro Pacheco", + "email": "arturo@koneko.mx" + } + ], + "support": { + "source": "https://github.com/koneko-mx/laravel-vuexy-warehouse", + "issues": "https://github.com/koneko-mx/laravel-vuexy-warehouse/issues" + }, + "minimum-stability": "dev", + "prefer-stable": true +} diff --git a/database/migrations/2024_12_16_091520_create_product_categories_table.php b/database/migrations/2024_12_16_091520_create_product_categories_table.php new file mode 100644 index 0000000..42d8e1c --- /dev/null +++ b/database/migrations/2024_12_16_091520_create_product_categories_table.php @@ -0,0 +1,84 @@ +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'); + } +}; diff --git a/database/migrations/2024_12_16_092473_create_products_tables.php b/database/migrations/2024_12_16_092473_create_products_tables.php new file mode 100644 index 0000000..5843cc1 --- /dev/null +++ b/database/migrations/2024_12_16_092473_create_products_tables.php @@ -0,0 +1,149 @@ +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'); + } +}; diff --git a/database/migrations/2024_12_16_111823_create_warehouse_tables.php b/database/migrations/2024_12_16_111823_create_warehouse_tables.php new file mode 100644 index 0000000..0d84ae3 --- /dev/null +++ b/database/migrations/2024_12_16_111823_create_warehouse_tables.php @@ -0,0 +1,193 @@ +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'); + } +}; diff --git a/resources/assets/js/bootstrap-table/warehouseFormatters.js b/resources/assets/js/bootstrap-table/warehouseFormatters.js new file mode 100644 index 0000000..d3df94f --- /dev/null +++ b/resources/assets/js/bootstrap-table/warehouseFormatters.js @@ -0,0 +1,17 @@ +import {routes} from '../../../../../laravel-vuexy-admin/resources/assets/js/bootstrap-table/globalConfig.js'; + +export const warehouseActionFormatter = (value, row, index) => { + if (!row.id) return ''; + + return ` + `.trim(); +}; + + diff --git a/resources/views/inventory-items/index.blade.php b/resources/views/inventory-items/index.blade.php new file mode 100644 index 0000000..32837b4 --- /dev/null +++ b/resources/views/inventory-items/index.blade.php @@ -0,0 +1,21 @@ +@extends('vuexy-admin::layouts.vuexy.layoutMaster') + +@section('title', 'Almacenes') + +@section('vendor-style') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/bootstrap-table/bootstrap-table.scss', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/bootstrap-icons.scss', + ]) +@endsection + +@push('page-script') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/bootstrap-table/bootstrapTableManager.js', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/forms/formConvasHelper.js', + ]) +@endpush + +@section('content') + @livewire('warehouse-index') +@endsection diff --git a/resources/views/inventory-movements/index.blade.php b/resources/views/inventory-movements/index.blade.php new file mode 100644 index 0000000..a5a73db --- /dev/null +++ b/resources/views/inventory-movements/index.blade.php @@ -0,0 +1,21 @@ +@extends('vuexy-admin::layouts.vuexy.layoutMaster') + +@section('title', 'Movimientos de almacenes') + +@section('vendor-style') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/bootstrap-table/bootstrap-table.scss', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/bootstrap-icons.scss', + ]) +@endsection + +@push('page-script') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/bootstrap-table/bootstrapTableManager.js', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/forms/formConvasHelper.js', + ]) +@endpush + +@section('content') + @livewire('inventory-movements-index') +@endsection diff --git a/resources/views/inventory-stock/index.blade.php b/resources/views/inventory-stock/index.blade.php new file mode 100644 index 0000000..58af6ba --- /dev/null +++ b/resources/views/inventory-stock/index.blade.php @@ -0,0 +1,21 @@ +@extends('vuexy-admin::layouts.vuexy.layoutMaster') + +@section('title', 'Stock de inventario') + +@section('vendor-style') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/bootstrap-table/bootstrap-table.scss', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/bootstrap-icons.scss', + ]) +@endsection + +@push('page-script') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/bootstrap-table/bootstrapTableManager.js', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/forms/formConvasHelper.js', + ]) +@endpush + +@section('content') + @livewire('inventory-stock-index') +@endsection diff --git a/resources/views/livewire/inventory-items/inventory-items-index.blade.php b/resources/views/livewire/inventory-items/inventory-items-index.blade.php new file mode 100644 index 0000000..59be0f4 --- /dev/null +++ b/resources/views/livewire/inventory-items/inventory-items-index.blade.php @@ -0,0 +1,516 @@ +
+
+
+
+
+
+ +
+ +
+ +
+ +
+
+
+
+
+ +@push('page-script') + +@endpush diff --git a/resources/views/livewire/inventory-movements/inventory-movements-index.blade.php b/resources/views/livewire/inventory-movements/inventory-movements-index.blade.php new file mode 100644 index 0000000..59be0f4 --- /dev/null +++ b/resources/views/livewire/inventory-movements/inventory-movements-index.blade.php @@ -0,0 +1,516 @@ +
+
+
+
+
+
+ +
+ +
+ +
+ +
+
+
+
+
+ +@push('page-script') + +@endpush diff --git a/resources/views/livewire/inventory-stock/inventory-stock-index.blade.php b/resources/views/livewire/inventory-stock/inventory-stock-index.blade.php new file mode 100644 index 0000000..59be0f4 --- /dev/null +++ b/resources/views/livewire/inventory-stock/inventory-stock-index.blade.php @@ -0,0 +1,516 @@ +
+
+
+
+
+
+ +
+ +
+ +
+ +
+
+
+
+
+ +@push('page-script') + +@endpush diff --git a/resources/views/livewire/materials/materials-index.blade.php b/resources/views/livewire/materials/materials-index.blade.php new file mode 100644 index 0000000..59be0f4 --- /dev/null +++ b/resources/views/livewire/materials/materials-index.blade.php @@ -0,0 +1,516 @@ +
+
+
+
+
+
+ +
+ +
+ +
+ +
+
+
+
+
+ +@push('page-script') + +@endpush diff --git a/resources/views/livewire/product-catalogs/product-catalogs-index.blade.php b/resources/views/livewire/product-catalogs/product-catalogs-index.blade.php new file mode 100644 index 0000000..59be0f4 --- /dev/null +++ b/resources/views/livewire/product-catalogs/product-catalogs-index.blade.php @@ -0,0 +1,516 @@ +
+
+
+
+
+
+ +
+ +
+ +
+ +
+
+
+
+
+ +@push('page-script') + +@endpush diff --git a/resources/views/livewire/product-categories/product-categories-index.blade.php b/resources/views/livewire/product-categories/product-categories-index.blade.php new file mode 100644 index 0000000..59be0f4 --- /dev/null +++ b/resources/views/livewire/product-categories/product-categories-index.blade.php @@ -0,0 +1,516 @@ +
+
+
+
+
+
+ +
+ +
+ +
+ +
+
+
+
+
+ +@push('page-script') + +@endpush diff --git a/resources/views/livewire/product-receipts/product-receipts-index.blade.php b/resources/views/livewire/product-receipts/product-receipts-index.blade.php new file mode 100644 index 0000000..59be0f4 --- /dev/null +++ b/resources/views/livewire/product-receipts/product-receipts-index.blade.php @@ -0,0 +1,516 @@ +
+
+
+
+
+
+ +
+ +
+ +
+ +
+
+
+
+
+ +@push('page-script') + +@endpush diff --git a/resources/views/livewire/products/products-index.blade.php b/resources/views/livewire/products/products-index.blade.php new file mode 100644 index 0000000..59be0f4 --- /dev/null +++ b/resources/views/livewire/products/products-index.blade.php @@ -0,0 +1,516 @@ +
+
+
+
+
+
+ +
+ +
+ +
+ +
+
+
+
+
+ +@push('page-script') + +@endpush diff --git a/resources/views/livewire/warehouse-movements/warehouse-movements-index.blade.php b/resources/views/livewire/warehouse-movements/warehouse-movements-index.blade.php new file mode 100644 index 0000000..59be0f4 --- /dev/null +++ b/resources/views/livewire/warehouse-movements/warehouse-movements-index.blade.php @@ -0,0 +1,516 @@ +
+
+
+
+
+
+ +
+ +
+ +
+ +
+
+
+
+
+ +@push('page-script') + +@endpush diff --git a/resources/views/livewire/warehouse-transfers/warehouse-transfers-index.blade.php b/resources/views/livewire/warehouse-transfers/warehouse-transfers-index.blade.php new file mode 100644 index 0000000..59be0f4 --- /dev/null +++ b/resources/views/livewire/warehouse-transfers/warehouse-transfers-index.blade.php @@ -0,0 +1,516 @@ +
+
+
+
+
+
+ +
+ +
+ +
+ +
+
+
+
+
+ +@push('page-script') + +@endpush diff --git a/resources/views/livewire/warehouses/form-offcanvas.blade.php b/resources/views/livewire/warehouses/form-offcanvas.blade.php new file mode 100644 index 0000000..627969a --- /dev/null +++ b/resources/views/livewire/warehouses/form-offcanvas.blade.php @@ -0,0 +1,132 @@ +
+ + + + + + {{-- Selección de Sucursal --}} + + + + {{-- Identificación y Configuración --}} +
+ +
+ {{-- Código y Prioridad --}} +
+
+ + +
+ {{-- Detalles del Almacén --}} + + + {{-- Información de Contacto --}} +
+
+ + +
+ {{-- Configuración Adicional --}} +
+ +
+
+
+ +@push('page-script') + +@endpush diff --git a/resources/views/livewire/warehouses/index.blade.php b/resources/views/livewire/warehouses/index.blade.php new file mode 100644 index 0000000..c0c1a3f --- /dev/null +++ b/resources/views/livewire/warehouses/index.blade.php @@ -0,0 +1,12 @@ + + +
+ +
+ @if(count($storeOptions) > 1) +
+ +
+ @endif +
+
diff --git a/resources/views/materials/index.blade.php b/resources/views/materials/index.blade.php new file mode 100644 index 0000000..5732f46 --- /dev/null +++ b/resources/views/materials/index.blade.php @@ -0,0 +1,21 @@ +@extends('vuexy-admin::layouts.vuexy.layoutMaster') + +@section('title', 'Materiales') + +@section('vendor-style') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/bootstrap-table/bootstrap-table.scss', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/bootstrap-icons.scss', + ]) +@endsection + +@push('page-script') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/bootstrap-table/bootstrapTableManager.js', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/forms/formConvasHelper.js', + ]) +@endpush + +@section('content') + @livewire('materials-index') +@endsection diff --git a/resources/views/product-categories/index.blade.php b/resources/views/product-categories/index.blade.php new file mode 100644 index 0000000..af35cd5 --- /dev/null +++ b/resources/views/product-categories/index.blade.php @@ -0,0 +1,21 @@ +@extends('vuexy-admin::layouts.vuexy.layoutMaster') + +@section('title', 'Categorias de productos') + +@section('vendor-style') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/bootstrap-table/bootstrap-table.scss', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/bootstrap-icons.scss', + ]) +@endsection + +@push('page-script') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/bootstrap-table/bootstrapTableManager.js', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/forms/formConvasHelper.js', + ]) +@endpush + +@section('content') + @livewire('product-categories-index') +@endsection diff --git a/resources/views/product-receipts/index.blade.php b/resources/views/product-receipts/index.blade.php new file mode 100644 index 0000000..68acef7 --- /dev/null +++ b/resources/views/product-receipts/index.blade.php @@ -0,0 +1,21 @@ +@extends('vuexy-admin::layouts.vuexy.layoutMaster') + +@section('title', 'Recepción de productos') + +@section('vendor-style') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/bootstrap-table/bootstrap-table.scss', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/bootstrap-icons.scss', + ]) +@endsection + +@push('page-script') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/bootstrap-table/bootstrapTableManager.js', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/forms/formConvasHelper.js', + ]) +@endpush + +@section('content') + @livewire('product-receipts-index') +@endsection diff --git a/resources/views/products/index.blade.php b/resources/views/products/index.blade.php new file mode 100644 index 0000000..1583322 --- /dev/null +++ b/resources/views/products/index.blade.php @@ -0,0 +1,21 @@ +@extends('vuexy-admin::layouts.vuexy.layoutMaster') + +@section('title', 'Productos') + +@section('vendor-style') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/bootstrap-table/bootstrap-table.scss', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/bootstrap-icons.scss', + ]) +@endsection + +@push('page-script') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/bootstrap-table/bootstrapTableManager.js', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/forms/formConvasHelper.js', + ]) +@endpush + +@section('content') + @livewire('products-index') +@endsection diff --git a/resources/views/warehouse-movements/index.blade.php b/resources/views/warehouse-movements/index.blade.php new file mode 100644 index 0000000..78cb4eb --- /dev/null +++ b/resources/views/warehouse-movements/index.blade.php @@ -0,0 +1,21 @@ +@extends('vuexy-admin::layouts.vuexy.layoutMaster') + +@section('title', 'Mantenimientos de almacenes') + +@section('vendor-style') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/bootstrap-table/bootstrap-table.scss', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/bootstrap-icons.scss', + ]) +@endsection + +@push('page-script') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/bootstrap-table/bootstrapTableManager.js', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/forms/formConvasHelper.js', + ]) +@endpush + +@section('content') + @livewire('warehouse-movements-index') +@endsection diff --git a/resources/views/warehouse-transfers/index.blade.php b/resources/views/warehouse-transfers/index.blade.php new file mode 100644 index 0000000..3085ddf --- /dev/null +++ b/resources/views/warehouse-transfers/index.blade.php @@ -0,0 +1,21 @@ +@extends('vuexy-admin::layouts.vuexy.layoutMaster') + +@section('title', 'Transferencias de Almacenes') + +@section('vendor-style') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/bootstrap-table/bootstrap-table.scss', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/bootstrap-icons.scss', + ]) +@endsection + +@push('page-script') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/bootstrap-table/bootstrapTableManager.js', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/forms/formConvasHelper.js', + ]) +@endpush + +@section('content') + @livewire('warehouse-transfers-index') +@endsection diff --git a/resources/views/warehouses/index.blade.php b/resources/views/warehouses/index.blade.php new file mode 100644 index 0000000..df8f65b --- /dev/null +++ b/resources/views/warehouses/index.blade.php @@ -0,0 +1,24 @@ +@extends('vuexy-admin::layouts.vuexy.layoutMaster') + +@section('title', 'Almacenes') + +@section('vendor-style') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/select2/select2.scss', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/bootstrap-table/bootstrap-table.scss', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/fonts/bootstrap-icons.scss', + ]) +@endsection + +@push('page-script') + @vite([ + 'vendor/koneko/laravel-vuexy-admin/resources/assets/vendor/libs/select2/select2.js', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/bootstrap-table/bootstrapTableManager.js', + 'vendor/koneko/laravel-vuexy-admin/resources/assets/js/forms/formConvasHelper.js', + ]) +@endpush + +@section('content') + @livewire('warehouse-index') + @livewire('warehouse-offcanvas-form') +@endsection diff --git a/routes/admin.php b/routes/admin.php new file mode 100644 index 0000000..3c1c421 --- /dev/null +++ b/routes/admin.php @@ -0,0 +1,109 @@ +name('admin.inventory.')->middleware(['web', 'auth', 'admin'])->group(function () { + Route::controller(ProductCategorieController::class)->prefix('categorias')->name('product-categories.')->group(function () { + Route::get('/', 'index')->name('index'); // Listar + Route::get('create', 'create')->name('create'); // Formulario de creación + Route::post('/', 'categorie')->name('store'); // Guardar + Route::get('{categorie}', 'show')->name('show'); // Ver + Route::get('{categorie}/edit', 'edit')->name('edit'); // Formulario de edición + Route::put('{categorie}', 'update')->name('update'); // Actualizar + Route::delete('{categorie}', 'destroy')->name('destroy'); // Eliminar + }); + + Route::controller(ProductCatalogController::class)->prefix('catalogos')->name('product-catalogs.')->group(function () { + Route::get('/', 'index')->name('index'); // Listar + Route::get('create', 'create')->name('create'); // Formulario de creación + Route::post('/', 'catalog')->name('store'); // Guardar + Route::get('{catalog}', 'show')->name('show'); // Ver + Route::get('{catalog}/edit', 'edit')->name('edit'); // Formulario de edición + Route::put('{catalog}', 'update')->name('update'); // Actualizar + Route::delete('{catalog}', 'destroy')->name('destroy'); // Eliminar + }); + + Route::controller(ProductController::class)->prefix('productos')->name('products.')->group(function () { + Route::get('/', 'index')->name('index'); // Listar + Route::get('create', 'create')->name('create'); // Formulario de creación + Route::post('/', 'product')->name('store'); // Guardar + Route::get('{product}', 'show')->name('show'); // Ver + Route::get('{product}/edit', 'edit')->name('edit'); // Formulario de edición + Route::put('{product}', 'update')->name('update'); // Actualizar + Route::delete('{product}', 'destroy')->name('destroy'); // Eliminar + }); +}); + +Route::prefix('admin/inventario-y-logistica')->name('admin.inventory.')->middleware(['web', 'auth', 'admin'])->group(function () { + Route::controller(ProductReceiptController::class)->prefix('recepcion-de-productos')->name('reception.')->group(function () {; + Route::get('/', 'index')->name('index'); // Listar + Route::get('create', 'create')->name('create'); // Formulario de creación + Route::post('/', 'reception')->name('store'); // Guardar + Route::get('{reception}', 'show')->name('show'); // Ver + Route::get('{reception}/edit', 'edit')->name('edit'); // Formulario de edición + Route::put('{reception}', 'update')->name('update'); // Actualizar + Route::delete('{reception}', 'destroy')->name('destroy'); // Eliminar + }); + + Route::controller(MaterialController::class)->prefix('gestion-de-insumos')->name('materials.')->group(function () {; + Route::get('/', 'index')->name('index'); // Listar + Route::get('create', 'create')->name('create'); // Formulario de creación + Route::post('/', 'materials')->name('store'); // Guardar + Route::get('{materials}', 'show')->name('show'); // Ver + Route::get('{materials}/edit', 'edit')->name('edit'); // Formulario de edición + Route::put('{materials}', 'update')->name('update'); // Actualizar + Route::delete('{materials}', 'destroy')->name('destroy'); // Eliminar + }); + + Route::controller(WarehouseController::class)->prefix('almacenes')->name('warehouse.')->group(function () {; + Route::get('/', 'index')->name('index'); // Listar + Route::get('create', 'create')->name('create'); // Formulario de creación + Route::post('/', 'warehouse')->name('store'); // Guardar + Route::get('{warehouse}', 'show')->name('show'); // Ver + Route::get('{warehouse}/edit', 'edit')->name('edit'); // Formulario de edición + Route::put('{warehouse}', 'update')->name('update'); // Actualizar + Route::delete('{warehouse}', 'destroy')->name('destroy'); // Eliminar + }); + + Route::controller(InventoryStockController::class)->prefix('stock-de-inventario')->name('stock.')->group(function () {; + Route::get('/', 'index')->name('index'); // Listar + Route::get('create', 'create')->name('create'); // Formulario de creación + Route::post('/', 'stock')->name('store'); // Guardar + Route::get('{stock}', 'show')->name('show'); // Ver + Route::get('{stock}/edit', 'edit')->name('edit'); // Formulario de edición + Route::put('{stock}', 'update')->name('update'); // Actualizar + Route::delete('{stock}', 'destroy')->name('destroy'); // Eliminar + }); + + Route::controller(InventoryMovementController::class)->prefix('movimientos-de-inventario')->name('movements.')->group(function () {; + Route::get('/', 'index')->name('index'); // Listar + Route::get('create', 'create')->name('create'); // Formulario de creación + Route::post('/', 'movements')->name('store'); // Guardar + Route::get('{movements}', 'show')->name('show'); // Ver + Route::get('{movements}/edit', 'edit')->name('edit'); // Formulario de edición + Route::put('{movements}', 'update')->name('update'); // Actualizar + Route::delete('{movements}', 'destroy')->name('destroy'); // Eliminar + }); + + Route::controller(WarehouseTransferController::class)->prefix('transferencias-entre-almacenes')->name('transfers.')->group(function () {; + Route::get('/', 'index')->name('index'); // Listar + Route::get('create', 'create')->name('create'); // Formulario de creación + Route::post('/', 'transfers')->name('store'); // Guardar + Route::get('{transfers}', 'show')->name('show'); // Ver + Route::get('{transfers}/edit', 'edit')->name('edit'); // Formulario de edición + Route::put('{transfers}', 'update')->name('update'); // Actualizar + Route::delete('{transfers}', 'destroy')->name('destroy'); // Eliminar + }); + +});