first commit
This commit is contained in:
commit
06dbf8e2a7
18
.editorconfig
Normal file
18
.editorconfig
Normal file
@ -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
|
38
.gitattributes
vendored
Normal file
38
.gitattributes
vendored
Normal file
@ -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
|
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
/node_modules
|
||||
/vendor
|
||||
/.vscode
|
||||
/.nova
|
||||
/.fleet
|
||||
/.phpactor.json
|
||||
/.phpunit.cache
|
||||
/.phpunit.result.cache
|
||||
/.zed
|
||||
/.idea
|
16
.prettierignore
Normal file
16
.prettierignore
Normal file
@ -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/
|
29
.prettierrc.json
Normal file
29
.prettierrc.json
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
39
CHANGELOG.md
Normal file
39
CHANGELOG.md
Normal file
@ -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**.
|
||||
|
9
CONTRIBUTING.md
Normal file
9
CONTRIBUTING.md
Normal file
@ -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**.
|
65
Http/Controllers/InventoryItemController.php
Normal file
65
Http/Controllers/InventoryItemController.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class inventoryStockLevelController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('vuexy-warehouse::inventory-items.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
65
Http/Controllers/InventoryMovementController.php
Normal file
65
Http/Controllers/InventoryMovementController.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class InventoryMovementController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('vuexy-warehouse::inventory-movements.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
65
Http/Controllers/InventoryStockController.php
Normal file
65
Http/Controllers/InventoryStockController.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class InventoryStockController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('vuexy-warehouse::inventory-stock.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
65
Http/Controllers/MaterialController.php
Normal file
65
Http/Controllers/MaterialController.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class MaterialController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('vuexy-warehouse::materials.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
65
Http/Controllers/ProductCatalogController.php
Normal file
65
Http/Controllers/ProductCatalogController.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ProductCatalogController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('vuexy-warehouse::product-catalogs.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
65
Http/Controllers/ProductCategorieController.php
Normal file
65
Http/Controllers/ProductCategorieController.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ProductCategorieController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('vuexy-warehouse::product-categories.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
65
Http/Controllers/ProductController.php
Normal file
65
Http/Controllers/ProductController.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ProductController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('vuexy-warehouse::products.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
65
Http/Controllers/ProductReceiptController.php
Normal file
65
Http/Controllers/ProductReceiptController.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ProductReceiptController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('vuexy-warehouse::product-receipts.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
133
Http/Controllers/WarehouseController.php
Normal file
133
Http/Controllers/WarehouseController.php
Normal file
@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Koneko\VuexyAdmin\Queries\GenericQueryBuilder;
|
||||
use Koneko\SatCatalogs\Http\Controllers\SatCatalogController;
|
||||
use Koneko\VuexyWarehouse\Models\Warehouse;
|
||||
|
||||
class WarehouseController extends SatCatalogController
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
if ($request->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)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
}
|
66
Http/Controllers/WarehouseMovementController.php
Normal file
66
Http/Controllers/WarehouseMovementController.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\WarehouseMovement;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class WarehouseMovementController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('vuexy-warehouse::warehouse-movements.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(WarehouseMovement $warehouseMovement)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(WarehouseMovement $warehouseMovement)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, WarehouseMovement $warehouseMovement)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(WarehouseMovement $warehouseMovement)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
65
Http/Controllers/WarehouseTransferController.php
Normal file
65
Http/Controllers/WarehouseTransferController.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class WarehouseTransferController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('vuexy-warehouse::warehouse-transfers.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(string $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
9
LICENSE
Normal file
9
LICENSE
Normal file
@ -0,0 +1,9 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 koneko
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
109
Livewire/InventoryItems/InventoryItemsIndex.php
Normal file
109
Livewire/InventoryItems/InventoryItemsIndex.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Livewire\inventoryStockLevels;
|
||||
|
||||
use Koneko\SatCatalogs\Models\RegimenFiscal;
|
||||
use Koneko\SatCatalogs\Models\UsoCfdi;
|
||||
use Koneko\VuexyAdmin\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Component;
|
||||
|
||||
class inventoryStockLevelsIndex extends Component
|
||||
{
|
||||
public $tipo_persona_options, $estado_options, $status_options;
|
||||
public $status_list, $status_list_class;
|
||||
|
||||
public $userId,
|
||||
$name,
|
||||
$email,
|
||||
$cargo,
|
||||
$rfc,
|
||||
$nombre_fiscal,
|
||||
$c_regimen_fiscal,
|
||||
$domicilio_fiscal,
|
||||
$c_uso_cfdi,
|
||||
$roles,
|
||||
$password,
|
||||
$status,
|
||||
$is_prospect,
|
||||
$is_customer,
|
||||
$is_provider,
|
||||
$is_user;
|
||||
|
||||
public $statuses;
|
||||
|
||||
public $rows_roles = [];
|
||||
public $roles_options = [];
|
||||
|
||||
public $uso_cfdi_options = [];
|
||||
public $regimen_fiscal_options = [];
|
||||
|
||||
public $roles_html_select;
|
||||
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->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 = "<select id=\"UserRole\" class=\"form-select text-capitalize\"><option value=\"\"> Selecciona un rol </option>";
|
||||
|
||||
foreach ($roles as $role) {
|
||||
$this->rows_roles[$role->name] = "<span class=\"badge bg-label-" . $role->style . " mx-1\">" . $role->name . "</span>";
|
||||
|
||||
if (Auth::user()->hasRole('SuperAdmin') || $role->name != 'SuperAdmin') {
|
||||
$this->roles_html_select .= "<option value=\"" . $role->name . "\" class=\"text-capitalize\">" . $role->name . "</option>";
|
||||
$this->roles_options[$role->name] = $role->name;
|
||||
}
|
||||
}
|
||||
|
||||
$this->roles_html_select .= "</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');
|
||||
}
|
||||
|
||||
}
|
109
Livewire/InventoryMovements/InventoryMovementsIndex.php
Normal file
109
Livewire/InventoryMovements/InventoryMovementsIndex.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Livewire\InventoryMovements;
|
||||
|
||||
use Koneko\SatCatalogs\Models\RegimenFiscal;
|
||||
use Koneko\SatCatalogs\Models\UsoCfdi;
|
||||
use Koneko\VuexyAdmin\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Component;
|
||||
|
||||
class InventoryMovementsIndex extends Component
|
||||
{
|
||||
public $tipo_persona_options, $estado_options, $status_options;
|
||||
public $status_list, $status_list_class;
|
||||
|
||||
public $userId,
|
||||
$name,
|
||||
$email,
|
||||
$cargo,
|
||||
$rfc,
|
||||
$nombre_fiscal,
|
||||
$c_regimen_fiscal,
|
||||
$domicilio_fiscal,
|
||||
$c_uso_cfdi,
|
||||
$roles,
|
||||
$password,
|
||||
$status,
|
||||
$is_prospect,
|
||||
$is_customer,
|
||||
$is_provider,
|
||||
$is_user;
|
||||
|
||||
public $statuses;
|
||||
|
||||
public $rows_roles = [];
|
||||
public $roles_options = [];
|
||||
|
||||
public $uso_cfdi_options = [];
|
||||
public $regimen_fiscal_options = [];
|
||||
|
||||
public $roles_html_select;
|
||||
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->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 = "<select id=\"UserRole\" class=\"form-select text-capitalize\"><option value=\"\"> Selecciona un rol </option>";
|
||||
|
||||
foreach ($roles as $role) {
|
||||
$this->rows_roles[$role->name] = "<span class=\"badge bg-label-" . $role->style . " mx-1\">" . $role->name . "</span>";
|
||||
|
||||
if (Auth::user()->hasRole('SuperAdmin') || $role->name != 'SuperAdmin') {
|
||||
$this->roles_html_select .= "<option value=\"" . $role->name . "\" class=\"text-capitalize\">" . $role->name . "</option>";
|
||||
$this->roles_options[$role->name] = $role->name;
|
||||
}
|
||||
}
|
||||
|
||||
$this->roles_html_select .= "</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');
|
||||
}
|
||||
|
||||
}
|
109
Livewire/InventoryStock/InventoryStockIndex.php
Normal file
109
Livewire/InventoryStock/InventoryStockIndex.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Livewire\InventoryStock;
|
||||
|
||||
use Koneko\SatCatalogs\Models\RegimenFiscal;
|
||||
use Koneko\SatCatalogs\Models\UsoCfdi;
|
||||
use Koneko\VuexyAdmin\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Component;
|
||||
|
||||
class InventoryStockIndex extends Component
|
||||
{
|
||||
public $tipo_persona_options, $estado_options, $status_options;
|
||||
public $status_list, $status_list_class;
|
||||
|
||||
public $userId,
|
||||
$name,
|
||||
$email,
|
||||
$cargo,
|
||||
$rfc,
|
||||
$nombre_fiscal,
|
||||
$c_regimen_fiscal,
|
||||
$domicilio_fiscal,
|
||||
$c_uso_cfdi,
|
||||
$roles,
|
||||
$password,
|
||||
$status,
|
||||
$is_prospect,
|
||||
$is_customer,
|
||||
$is_provider,
|
||||
$is_user;
|
||||
|
||||
public $statuses;
|
||||
|
||||
public $rows_roles = [];
|
||||
public $roles_options = [];
|
||||
|
||||
public $uso_cfdi_options = [];
|
||||
public $regimen_fiscal_options = [];
|
||||
|
||||
public $roles_html_select;
|
||||
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->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 = "<select id=\"UserRole\" class=\"form-select text-capitalize\"><option value=\"\"> Selecciona un rol </option>";
|
||||
|
||||
foreach ($roles as $role) {
|
||||
$this->rows_roles[$role->name] = "<span class=\"badge bg-label-" . $role->style . " mx-1\">" . $role->name . "</span>";
|
||||
|
||||
if (Auth::user()->hasRole('SuperAdmin') || $role->name != 'SuperAdmin') {
|
||||
$this->roles_html_select .= "<option value=\"" . $role->name . "\" class=\"text-capitalize\">" . $role->name . "</option>";
|
||||
$this->roles_options[$role->name] = $role->name;
|
||||
}
|
||||
}
|
||||
|
||||
$this->roles_html_select .= "</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');
|
||||
}
|
||||
|
||||
}
|
109
Livewire/Materials/MaterialsIndex.php
Normal file
109
Livewire/Materials/MaterialsIndex.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Livewire\Materials;
|
||||
|
||||
use Koneko\SatCatalogs\Models\RegimenFiscal;
|
||||
use Koneko\SatCatalogs\Models\UsoCfdi;
|
||||
use Koneko\VuexyAdmin\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Component;
|
||||
|
||||
class MaterialsIndex extends Component
|
||||
{
|
||||
public $tipo_persona_options, $estado_options, $status_options;
|
||||
public $status_list, $status_list_class;
|
||||
|
||||
public $userId,
|
||||
$name,
|
||||
$email,
|
||||
$cargo,
|
||||
$rfc,
|
||||
$nombre_fiscal,
|
||||
$c_regimen_fiscal,
|
||||
$domicilio_fiscal,
|
||||
$c_uso_cfdi,
|
||||
$roles,
|
||||
$password,
|
||||
$status,
|
||||
$is_prospect,
|
||||
$is_customer,
|
||||
$is_provider,
|
||||
$is_user;
|
||||
|
||||
public $statuses;
|
||||
|
||||
public $rows_roles = [];
|
||||
public $roles_options = [];
|
||||
|
||||
public $uso_cfdi_options = [];
|
||||
public $regimen_fiscal_options = [];
|
||||
|
||||
public $roles_html_select;
|
||||
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->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 = "<select id=\"UserRole\" class=\"form-select text-capitalize\"><option value=\"\"> Selecciona un rol </option>";
|
||||
|
||||
foreach ($roles as $role) {
|
||||
$this->rows_roles[$role->name] = "<span class=\"badge bg-label-" . $role->style . " mx-1\">" . $role->name . "</span>";
|
||||
|
||||
if (Auth::user()->hasRole('SuperAdmin') || $role->name != 'SuperAdmin') {
|
||||
$this->roles_html_select .= "<option value=\"" . $role->name . "\" class=\"text-capitalize\">" . $role->name . "</option>";
|
||||
$this->roles_options[$role->name] = $role->name;
|
||||
}
|
||||
}
|
||||
|
||||
$this->roles_html_select .= "</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');
|
||||
}
|
||||
|
||||
}
|
109
Livewire/ProductCatalogs/ProductCatalogsIndex.php
Normal file
109
Livewire/ProductCatalogs/ProductCatalogsIndex.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Livewire\ProductCatalogs;
|
||||
|
||||
use Koneko\SatCatalogs\Models\RegimenFiscal;
|
||||
use Koneko\SatCatalogs\Models\UsoCfdi;
|
||||
use Koneko\VuexyAdmin\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Component;
|
||||
|
||||
class ProductCatalogsIndex extends Component
|
||||
{
|
||||
public $tipo_persona_options, $estado_options, $status_options;
|
||||
public $status_list, $status_list_class;
|
||||
|
||||
public $userId,
|
||||
$name,
|
||||
$email,
|
||||
$cargo,
|
||||
$rfc,
|
||||
$nombre_fiscal,
|
||||
$c_regimen_fiscal,
|
||||
$domicilio_fiscal,
|
||||
$c_uso_cfdi,
|
||||
$roles,
|
||||
$password,
|
||||
$status,
|
||||
$is_prospect,
|
||||
$is_customer,
|
||||
$is_provider,
|
||||
$is_user;
|
||||
|
||||
public $statuses;
|
||||
|
||||
public $rows_roles = [];
|
||||
public $roles_options = [];
|
||||
|
||||
public $uso_cfdi_options = [];
|
||||
public $regimen_fiscal_options = [];
|
||||
|
||||
public $roles_html_select;
|
||||
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->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 = "<select id=\"UserRole\" class=\"form-select text-capitalize\"><option value=\"\"> Selecciona un rol </option>";
|
||||
|
||||
foreach ($roles as $role) {
|
||||
$this->rows_roles[$role->name] = "<span class=\"badge bg-label-" . $role->style . " mx-1\">" . $role->name . "</span>";
|
||||
|
||||
if (Auth::user()->hasRole('SuperAdmin') || $role->name != 'SuperAdmin') {
|
||||
$this->roles_html_select .= "<option value=\"" . $role->name . "\" class=\"text-capitalize\">" . $role->name . "</option>";
|
||||
$this->roles_options[$role->name] = $role->name;
|
||||
}
|
||||
}
|
||||
|
||||
$this->roles_html_select .= "</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');
|
||||
}
|
||||
|
||||
}
|
109
Livewire/ProductCategories/ProductCategoriesIndex.php
Normal file
109
Livewire/ProductCategories/ProductCategoriesIndex.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Livewire\ProductCategories;
|
||||
|
||||
use Koneko\SatCatalogs\Models\RegimenFiscal;
|
||||
use Koneko\SatCatalogs\Models\UsoCfdi;
|
||||
use Koneko\VuexyAdmin\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Component;
|
||||
|
||||
class ProductCategoriesIndex extends Component
|
||||
{
|
||||
public $tipo_persona_options, $estado_options, $status_options;
|
||||
public $status_list, $status_list_class;
|
||||
|
||||
public $userId,
|
||||
$name,
|
||||
$email,
|
||||
$cargo,
|
||||
$rfc,
|
||||
$nombre_fiscal,
|
||||
$c_regimen_fiscal,
|
||||
$domicilio_fiscal,
|
||||
$c_uso_cfdi,
|
||||
$roles,
|
||||
$password,
|
||||
$status,
|
||||
$is_prospect,
|
||||
$is_customer,
|
||||
$is_provider,
|
||||
$is_user;
|
||||
|
||||
public $statuses;
|
||||
|
||||
public $rows_roles = [];
|
||||
public $roles_options = [];
|
||||
|
||||
public $uso_cfdi_options = [];
|
||||
public $regimen_fiscal_options = [];
|
||||
|
||||
public $roles_html_select;
|
||||
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->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 = "<select id=\"UserRole\" class=\"form-select text-capitalize\"><option value=\"\"> Selecciona un rol </option>";
|
||||
|
||||
foreach ($roles as $role) {
|
||||
$this->rows_roles[$role->name] = "<span class=\"badge bg-label-" . $role->style . " mx-1\">" . $role->name . "</span>";
|
||||
|
||||
if (Auth::user()->hasRole('SuperAdmin') || $role->name != 'SuperAdmin') {
|
||||
$this->roles_html_select .= "<option value=\"" . $role->name . "\" class=\"text-capitalize\">" . $role->name . "</option>";
|
||||
$this->roles_options[$role->name] = $role->name;
|
||||
}
|
||||
}
|
||||
|
||||
$this->roles_html_select .= "</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');
|
||||
}
|
||||
|
||||
}
|
109
Livewire/ProductReceipts/ProductReceiptsIndex.php
Normal file
109
Livewire/ProductReceipts/ProductReceiptsIndex.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Livewire\ProductReceipts;
|
||||
|
||||
use Koneko\SatCatalogs\Models\RegimenFiscal;
|
||||
use Koneko\SatCatalogs\Models\UsoCfdi;
|
||||
use Koneko\VuexyAdmin\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Component;
|
||||
|
||||
class ProductReceiptsIndex extends Component
|
||||
{
|
||||
public $tipo_persona_options, $estado_options, $status_options;
|
||||
public $status_list, $status_list_class;
|
||||
|
||||
public $userId,
|
||||
$name,
|
||||
$email,
|
||||
$cargo,
|
||||
$rfc,
|
||||
$nombre_fiscal,
|
||||
$c_regimen_fiscal,
|
||||
$domicilio_fiscal,
|
||||
$c_uso_cfdi,
|
||||
$roles,
|
||||
$password,
|
||||
$status,
|
||||
$is_prospect,
|
||||
$is_customer,
|
||||
$is_provider,
|
||||
$is_user;
|
||||
|
||||
public $statuses;
|
||||
|
||||
public $rows_roles = [];
|
||||
public $roles_options = [];
|
||||
|
||||
public $uso_cfdi_options = [];
|
||||
public $regimen_fiscal_options = [];
|
||||
|
||||
public $roles_html_select;
|
||||
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->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 = "<select id=\"UserRole\" class=\"form-select text-capitalize\"><option value=\"\"> Selecciona un rol </option>";
|
||||
|
||||
foreach ($roles as $role) {
|
||||
$this->rows_roles[$role->name] = "<span class=\"badge bg-label-" . $role->style . " mx-1\">" . $role->name . "</span>";
|
||||
|
||||
if (Auth::user()->hasRole('SuperAdmin') || $role->name != 'SuperAdmin') {
|
||||
$this->roles_html_select .= "<option value=\"" . $role->name . "\" class=\"text-capitalize\">" . $role->name . "</option>";
|
||||
$this->roles_options[$role->name] = $role->name;
|
||||
}
|
||||
}
|
||||
|
||||
$this->roles_html_select .= "</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');
|
||||
}
|
||||
|
||||
}
|
109
Livewire/Products/ProductsIndex.php
Normal file
109
Livewire/Products/ProductsIndex.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Livewire\Products;
|
||||
|
||||
use Koneko\SatCatalogs\Models\RegimenFiscal;
|
||||
use Koneko\SatCatalogs\Models\UsoCfdi;
|
||||
use Koneko\VuexyAdmin\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Component;
|
||||
|
||||
class ProductsIndex extends Component
|
||||
{
|
||||
public $tipo_persona_options, $estado_options, $status_options;
|
||||
public $status_list, $status_list_class;
|
||||
|
||||
public $userId,
|
||||
$name,
|
||||
$email,
|
||||
$cargo,
|
||||
$rfc,
|
||||
$nombre_fiscal,
|
||||
$c_regimen_fiscal,
|
||||
$domicilio_fiscal,
|
||||
$c_uso_cfdi,
|
||||
$roles,
|
||||
$password,
|
||||
$status,
|
||||
$is_prospect,
|
||||
$is_customer,
|
||||
$is_provider,
|
||||
$is_user;
|
||||
|
||||
public $statuses;
|
||||
|
||||
public $rows_roles = [];
|
||||
public $roles_options = [];
|
||||
|
||||
public $uso_cfdi_options = [];
|
||||
public $regimen_fiscal_options = [];
|
||||
|
||||
public $roles_html_select;
|
||||
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->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 = "<select id=\"UserRole\" class=\"form-select text-capitalize\"><option value=\"\"> Selecciona un rol </option>";
|
||||
|
||||
foreach ($roles as $role) {
|
||||
$this->rows_roles[$role->name] = "<span class=\"badge bg-label-" . $role->style . " mx-1\">" . $role->name . "</span>";
|
||||
|
||||
if (Auth::user()->hasRole('SuperAdmin') || $role->name != 'SuperAdmin') {
|
||||
$this->roles_html_select .= "<option value=\"" . $role->name . "\" class=\"text-capitalize\">" . $role->name . "</option>";
|
||||
$this->roles_options[$role->name] = $role->name;
|
||||
}
|
||||
}
|
||||
|
||||
$this->roles_html_select .= "</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');
|
||||
}
|
||||
|
||||
}
|
109
Livewire/PurchaseOrders/PurchaseOrdersIndex.php
Normal file
109
Livewire/PurchaseOrders/PurchaseOrdersIndex.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Livewire\PurchaseOrders;
|
||||
|
||||
use Koneko\SatCatalogs\Models\RegimenFiscal;
|
||||
use Koneko\SatCatalogs\Models\UsoCfdi;
|
||||
use Koneko\VuexyAdmin\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Component;
|
||||
|
||||
class PurchaseOrdersIndex extends Component
|
||||
{
|
||||
public $tipo_persona_options, $estado_options, $status_options;
|
||||
public $status_list, $status_list_class;
|
||||
|
||||
public $userId,
|
||||
$name,
|
||||
$email,
|
||||
$cargo,
|
||||
$rfc,
|
||||
$nombre_fiscal,
|
||||
$c_regimen_fiscal,
|
||||
$domicilio_fiscal,
|
||||
$c_uso_cfdi,
|
||||
$roles,
|
||||
$password,
|
||||
$status,
|
||||
$is_prospect,
|
||||
$is_customer,
|
||||
$is_provider,
|
||||
$is_user;
|
||||
|
||||
public $statuses;
|
||||
|
||||
public $rows_roles = [];
|
||||
public $roles_options = [];
|
||||
|
||||
public $uso_cfdi_options = [];
|
||||
public $regimen_fiscal_options = [];
|
||||
|
||||
public $roles_html_select;
|
||||
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->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 = "<select id=\"UserRole\" class=\"form-select text-capitalize\"><option value=\"\"> Selecciona un rol </option>";
|
||||
|
||||
foreach ($roles as $role) {
|
||||
$this->rows_roles[$role->name] = "<span class=\"badge bg-label-" . $role->style . " mx-1\">" . $role->name . "</span>";
|
||||
|
||||
if (Auth::user()->hasRole('SuperAdmin') || $role->name != 'SuperAdmin') {
|
||||
$this->roles_html_select .= "<option value=\"" . $role->name . "\" class=\"text-capitalize\">" . $role->name . "</option>";
|
||||
$this->roles_options[$role->name] = $role->name;
|
||||
}
|
||||
}
|
||||
|
||||
$this->roles_html_select .= "</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');
|
||||
}
|
||||
|
||||
}
|
109
Livewire/WarehouseMovements/WarehouseMovementsIndex.php
Normal file
109
Livewire/WarehouseMovements/WarehouseMovementsIndex.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Livewire\WarehouseMovements;
|
||||
|
||||
use Koneko\SatCatalogs\Models\RegimenFiscal;
|
||||
use Koneko\SatCatalogs\Models\UsoCfdi;
|
||||
use Koneko\VuexyAdmin\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Component;
|
||||
|
||||
class WarehouseMovementsIndex extends Component
|
||||
{
|
||||
public $tipo_persona_options, $estado_options, $status_options;
|
||||
public $status_list, $status_list_class;
|
||||
|
||||
public $userId,
|
||||
$name,
|
||||
$email,
|
||||
$cargo,
|
||||
$rfc,
|
||||
$nombre_fiscal,
|
||||
$c_regimen_fiscal,
|
||||
$domicilio_fiscal,
|
||||
$c_uso_cfdi,
|
||||
$roles,
|
||||
$password,
|
||||
$status,
|
||||
$is_prospect,
|
||||
$is_customer,
|
||||
$is_provider,
|
||||
$is_user;
|
||||
|
||||
public $statuses;
|
||||
|
||||
public $rows_roles = [];
|
||||
public $roles_options = [];
|
||||
|
||||
public $uso_cfdi_options = [];
|
||||
public $regimen_fiscal_options = [];
|
||||
|
||||
public $roles_html_select;
|
||||
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->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 = "<select id=\"UserRole\" class=\"form-select text-capitalize\"><option value=\"\"> Selecciona un rol </option>";
|
||||
|
||||
foreach ($roles as $role) {
|
||||
$this->rows_roles[$role->name] = "<span class=\"badge bg-label-" . $role->style . " mx-1\">" . $role->name . "</span>";
|
||||
|
||||
if (Auth::user()->hasRole('SuperAdmin') || $role->name != 'SuperAdmin') {
|
||||
$this->roles_html_select .= "<option value=\"" . $role->name . "\" class=\"text-capitalize\">" . $role->name . "</option>";
|
||||
$this->roles_options[$role->name] = $role->name;
|
||||
}
|
||||
}
|
||||
|
||||
$this->roles_html_select .= "</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');
|
||||
}
|
||||
|
||||
}
|
109
Livewire/WarehouseTransfers/WarehouseTransfersIndex.php
Normal file
109
Livewire/WarehouseTransfers/WarehouseTransfersIndex.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Livewire\WarehouseTransfers;
|
||||
|
||||
use Koneko\SatCatalogs\Models\RegimenFiscal;
|
||||
use Koneko\SatCatalogs\Models\UsoCfdi;
|
||||
use Koneko\VuexyAdmin\Models\User;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Spatie\Permission\Models\Role;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Livewire\Component;
|
||||
|
||||
class WarehouseTransfersIndex extends Component
|
||||
{
|
||||
public $tipo_persona_options, $estado_options, $status_options;
|
||||
public $status_list, $status_list_class;
|
||||
|
||||
public $userId,
|
||||
$name,
|
||||
$email,
|
||||
$cargo,
|
||||
$rfc,
|
||||
$nombre_fiscal,
|
||||
$c_regimen_fiscal,
|
||||
$domicilio_fiscal,
|
||||
$c_uso_cfdi,
|
||||
$roles,
|
||||
$password,
|
||||
$status,
|
||||
$is_prospect,
|
||||
$is_customer,
|
||||
$is_provider,
|
||||
$is_user;
|
||||
|
||||
public $statuses;
|
||||
|
||||
public $rows_roles = [];
|
||||
public $roles_options = [];
|
||||
|
||||
public $uso_cfdi_options = [];
|
||||
public $regimen_fiscal_options = [];
|
||||
|
||||
public $roles_html_select;
|
||||
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->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 = "<select id=\"UserRole\" class=\"form-select text-capitalize\"><option value=\"\"> Selecciona un rol </option>";
|
||||
|
||||
foreach ($roles as $role) {
|
||||
$this->rows_roles[$role->name] = "<span class=\"badge bg-label-" . $role->style . " mx-1\">" . $role->name . "</span>";
|
||||
|
||||
if (Auth::user()->hasRole('SuperAdmin') || $role->name != 'SuperAdmin') {
|
||||
$this->roles_html_select .= "<option value=\"" . $role->name . "\" class=\"text-capitalize\">" . $role->name . "</option>";
|
||||
$this->roles_options[$role->name] = $role->name;
|
||||
}
|
||||
}
|
||||
|
||||
$this->roles_html_select .= "</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');
|
||||
}
|
||||
|
||||
}
|
221
Livewire/Warehouses/WarehouseIndex.php
Normal file
221
Livewire/Warehouses/WarehouseIndex.php
Normal file
@ -0,0 +1,221 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Livewire\Warehouses;
|
||||
|
||||
use Koneko\VuexyAdmin\Livewire\Table\AbstractIndexComponent;
|
||||
use Koneko\VuexyWarehouse\Models\Warehouse;
|
||||
use Koneko\VuexyStoreManager\Services\StoreCatalogService;
|
||||
|
||||
class WarehouseIndex extends AbstractIndexComponent
|
||||
{
|
||||
public $store_id;
|
||||
public $storeOptions = [];
|
||||
|
||||
/**
|
||||
* Retorna la clase del modelo asociado.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function model(): string
|
||||
{
|
||||
return Warehouse::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configura el encabezado (header) de la tabla (las columnas).
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function columns(): array
|
||||
{
|
||||
return [
|
||||
'action' => '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;
|
||||
}
|
||||
}
|
219
Livewire/Warehouses/WarehouseOffcanvasForm.php
Normal file
219
Livewire/Warehouses/WarehouseOffcanvasForm.php
Normal file
@ -0,0 +1,219 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Livewire\Warehouses;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Koneko\VuexyAdmin\Livewire\Form\AbstractFormOffCanvasComponent;
|
||||
use Koneko\VuexyContacts\Services\ContactCatalogService;
|
||||
use Koneko\VuexyStoreManager\Services\StoreCatalogService;
|
||||
use Koneko\VuexyWarehouse\Models\Warehouse;
|
||||
|
||||
/**
|
||||
* Class WarehouseOffcanvasForm
|
||||
*
|
||||
* Componente Livewire para gestionar almacenes.
|
||||
* Extiende la clase AbstractFormOffCanvasComponent e implementa validaciones dinámicas,
|
||||
* manejo de formularios, eventos y actualizaciones en tiempo real.
|
||||
*
|
||||
* @package Koneko\VuexyWarehouse\Livewire\Warehouses
|
||||
*/
|
||||
class WarehouseOffcanvasForm extends AbstractFormOffCanvasComponent
|
||||
{
|
||||
/**
|
||||
* Propiedades del formulario relacionadas con el almacén.
|
||||
*/
|
||||
public $id, $store_id, $work_center_id, $code, $name, $description,
|
||||
$manager_id, $tel, $tel2, $priority, $status, $confirmDeletion;
|
||||
|
||||
/**
|
||||
* Listas de opciones para selects en el formulario.
|
||||
*/
|
||||
public $store_options = [],
|
||||
$work_center_options = [],
|
||||
$manager_options = [];
|
||||
|
||||
/**
|
||||
* Eventos de escucha de Livewire.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $listeners = [
|
||||
'editWarehouse' => '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<string, mixed>
|
||||
*/
|
||||
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<string, string>
|
||||
*/
|
||||
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<string, string>
|
||||
*/
|
||||
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';
|
||||
}
|
||||
}
|
19
Models/Currency.php
Normal file
19
Models/Currency.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Currency extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $fillable = ['code', 'name', 'symbol', 'exchange_rate', 'status'];
|
||||
|
||||
protected $casts = [
|
||||
'exchange_rate' => 'decimal:6',
|
||||
'status' => 'boolean'
|
||||
];
|
||||
}
|
20
Models/FixedAsset.php
Normal file
20
Models/FixedAsset.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class FixedAsset extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $fillable = ['name', 'description', 'acquisition_date', 'value', 'status'];
|
||||
|
||||
protected $casts = [
|
||||
'acquisition_date' => 'date',
|
||||
'value' => 'decimal:2',
|
||||
'status' => 'boolean'
|
||||
];
|
||||
}
|
84
Models/InventoryMovement.php
Normal file
84
Models/InventoryMovement.php
Normal file
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
use Koneko\VuexyStoreManager\Models\Store;
|
||||
use Koneko\VuexyAdmin\Models\User;
|
||||
|
||||
class InventoryMovement extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'inventory_movements';
|
||||
protected $primaryKey = 'id';
|
||||
public $incrementing = false;
|
||||
protected $keyType = 'integer';
|
||||
|
||||
protected $fillable = [
|
||||
'product_id',
|
||||
'store_id',
|
||||
'warehouse_id',
|
||||
'movement_type',
|
||||
'quantity',
|
||||
'cost',
|
||||
'cost_before',
|
||||
'cost_after',
|
||||
'cost_type',
|
||||
'notes',
|
||||
'transactionable_id',
|
||||
'transactionable_type',
|
||||
'created_by',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'quantity' => '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();
|
||||
}
|
||||
}
|
62
Models/InventoryStockLevel.php
Normal file
62
Models/InventoryStockLevel.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Koneko\VuexyStoreManager\Models\Store;
|
||||
|
||||
class InventoryStockLevel extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'product_id', 'store_id', 'warehouse_id', 'quantity',
|
||||
'pos_stock', 'ecommerce_stock', 'purchase_reserved_stock', 'asset_stock',
|
||||
'last_cost', 'average_cost', 'total_last_cost', 'total_average_cost', 'total_identified_cost',
|
||||
'costing_method'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'quantity' => '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');
|
||||
}
|
||||
}
|
62
Models/LotNumber.php
Normal file
62
Models/LotNumber.php
Normal file
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Koneko\VuexyStoreManager\Models\Store;
|
||||
|
||||
class LotNumber extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'lot_numbers';
|
||||
protected $primaryKey = 'id';
|
||||
public $incrementing = false;
|
||||
protected $keyType = 'mediumint';
|
||||
|
||||
protected $fillable = [
|
||||
'product_id',
|
||||
'store_id',
|
||||
'warehouse_id',
|
||||
'lot_number',
|
||||
'production_date',
|
||||
'expiry_date',
|
||||
'initial_quantity',
|
||||
'remaining_quantity',
|
||||
'cost',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'production_date' => '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');
|
||||
}
|
||||
}
|
134
Models/Product.php
Normal file
134
Models/Product.php
Normal file
@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Koneko\VuexyStoreManager\Models\Currency;
|
||||
use Koneko\SatCatalogs\Models\ClaveUnidad;
|
||||
use Koneko\SatCatalogs\Models\ClaveProdServ;
|
||||
use Koneko\VuexyAdmin\Models\User;
|
||||
|
||||
class Product extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'products';
|
||||
protected $primaryKey = 'id';
|
||||
public $incrementing = false;
|
||||
protected $keyType = 'mediumint';
|
||||
|
||||
protected $fillable = [
|
||||
'type',
|
||||
'category_id',
|
||||
'descripcion',
|
||||
'descripcion_completa',
|
||||
'no_identificacion',
|
||||
'slug',
|
||||
'available_in_pos',
|
||||
'available_in_purchases',
|
||||
'available_in_ecommerce',
|
||||
'available_in_purchases',
|
||||
'available_in_maanufacturing',
|
||||
'available_in_quality',
|
||||
'available_in_assets',
|
||||
'c_clave_unidad',
|
||||
'c_clave_prod_serv',
|
||||
'ean_code',
|
||||
'costo',
|
||||
'c_moneda',
|
||||
'c_objeto_imp',
|
||||
'impuestos',
|
||||
'traslados',
|
||||
'retenciones',
|
||||
'data_lot_enable',
|
||||
'data_lot_require',
|
||||
'data_series_enable',
|
||||
'data_series_require',
|
||||
'data_expiration_enable',
|
||||
'data_expiration_require',
|
||||
'data_warranty_enable',
|
||||
'warranty',
|
||||
'data_best_before_enable',
|
||||
'data_best_before_require',
|
||||
'data_observations_enable',
|
||||
'minimum_unit',
|
||||
'affects_inventory',
|
||||
'alert_minimum_stock',
|
||||
'alert_maximum_stock',
|
||||
'minimum_stock',
|
||||
'maximum_stock',
|
||||
'status',
|
||||
'created_by'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'available_in_pos',
|
||||
'available_in_purchases' => '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');
|
||||
}
|
||||
}
|
68
Models/ProductCategory.php
Normal file
68
Models/ProductCategory.php
Normal file
@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class ProductCategory extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'product_categories';
|
||||
protected $primaryKey = 'id';
|
||||
public $incrementing = false;
|
||||
protected $keyType = 'mediumint';
|
||||
|
||||
protected $fillable = [
|
||||
'parent_id',
|
||||
'parent_slug',
|
||||
'name',
|
||||
'slug',
|
||||
'icon',
|
||||
'description',
|
||||
'show_in_pos',
|
||||
'show_in_purchases',
|
||||
'show_in_ecommerce',
|
||||
'show_in_manufacturing',
|
||||
'show_in_quality',
|
||||
'show_in_assets',
|
||||
'order'
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'show_in_pos' => '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');
|
||||
}
|
||||
}
|
29
Models/ProductProperty.php
Normal file
29
Models/ProductProperty.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class ProductProperty extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'product_properties';
|
||||
protected $primaryKey = 'id';
|
||||
public $incrementing = false;
|
||||
protected $keyType = 'smallint';
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* Relación con los valores de propiedad asignados a productos.
|
||||
*/
|
||||
public function values(): HasMany
|
||||
{
|
||||
return $this->hasMany(ProductPropertyValue::class, 'property_id');
|
||||
}
|
||||
}
|
39
Models/ProductPropertyValue.php
Normal file
39
Models/ProductPropertyValue.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class ProductPropertyValue extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $table = 'product_property';
|
||||
protected $primaryKey = 'id';
|
||||
public $incrementing = false;
|
||||
protected $keyType = 'mediumint';
|
||||
|
||||
protected $fillable = [
|
||||
'product_id',
|
||||
'property_id',
|
||||
'value',
|
||||
];
|
||||
|
||||
/**
|
||||
* Relación con el producto.
|
||||
*/
|
||||
public function product(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Product::class, 'product_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Relación con la propiedad del producto.
|
||||
*/
|
||||
public function property(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(ProductProperty::class, 'property_id');
|
||||
}
|
||||
}
|
94
Models/Warehouse.php
Normal file
94
Models/Warehouse.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Koneko\VuexyAdmin\Models\User;
|
||||
use Koneko\VuexyStoreManager\Models\Store;
|
||||
use Koneko\VuexyStoreManager\Models\StoreWorkCenter;
|
||||
|
||||
class Warehouse extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'store_id',
|
||||
'work_center_id',
|
||||
'code',
|
||||
'name',
|
||||
'description',
|
||||
'manager_id',
|
||||
'tel',
|
||||
'tel2',
|
||||
'priority',
|
||||
'status',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'priority' => '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');
|
||||
}
|
||||
}
|
80
Models/WarehouseMovement.php
Normal file
80
Models/WarehouseMovement.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Koneko\VuexyStoreManager\Models\Store;
|
||||
use Koneko\VuexyAdmin\Models\User;
|
||||
|
||||
class WarehouseMovement extends Model
|
||||
{
|
||||
use HasFactory, SoftDeletes;
|
||||
|
||||
protected $table = 'warehouse_movements';
|
||||
protected $primaryKey = 'id';
|
||||
public $incrementing = false;
|
||||
protected $keyType = 'mediumint';
|
||||
|
||||
protected $fillable = [
|
||||
'store_id',
|
||||
'warehouse_id',
|
||||
'movement_type',
|
||||
'movement_id',
|
||||
'created_by',
|
||||
'approved_by',
|
||||
'adjusted_quantity',
|
||||
'cost',
|
||||
'notes',
|
||||
'to_warehouse_id',
|
||||
'status',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'adjusted_quantity' => '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');
|
||||
}
|
||||
}
|
63
Providers/VuexyWarehouseServiceProvider.php
Normal file
63
Providers/VuexyWarehouseServiceProvider.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
use Livewire\Livewire;
|
||||
use Koneko\VuexyWarehouse\Livewire\Warehouses\{WarehouseIndex,WarehouseOffcanvasForm};
|
||||
use OwenIt\Auditing\AuditableObserver;
|
||||
|
||||
class VuexyWarehouseServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register any application services.
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap any application services.
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
// Register the module's routes
|
||||
$this->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);
|
||||
}
|
||||
}
|
133
README.md
Normal file
133
README.md
Normal file
@ -0,0 +1,133 @@
|
||||
# 🎨 Laravel Vuexy Warehouse - Vuexy Admin
|
||||
|
||||
<p align="center">
|
||||
<a href="https://koneko.mx" target="_blank"> <img src="https://git.koneko.mx/Koneko-ST/koneko-st/raw/branch/main/logo-images/horizontal-05.png" width="400" alt="Koneko Soluciones Tecnológicas Logo"> </a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://koneko.mx"><img src="https://img.shields.io/badge/Website-koneko.mx-blue" alt="Sitio Web"></a>
|
||||
<a href="https://packagist.org/packages/koneko/laravel-vuexy-warehouse"><img src="https://img.shields.io/packagist/v/koneko/laravel-vuexy-warehouse" alt="Latest Stable Version"></a>
|
||||
<a href="https://packagist.org/packages/koneko/laravel-vuexy-warehouse"><img src="https://img.shields.io/packagist/l/koneko/laravel-vuexy-warehouse" alt="License"></a>
|
||||
<a href="https://git.koneko.mx/koneko"><img src="https://img.shields.io/badge/Git%20Server-Koneko%20Git-orange" alt="Servidor Git"></a>
|
||||
<a href="https://github.com/koneko-mx/laravel-vuexy-warehouse/actions/workflows/tests.yml"><img src="https://github.com/koneko-mx/laravel-vuexy-warehouse/actions/workflows/tests.yml/badge.svg" alt="Build Status"></a>
|
||||
<a href="https://github.com/koneko-mx/laravel-vuexy-warehouse/issues"><img src="https://img.shields.io/github/issues/koneko/laravel-vuexy-warehouse" alt="Issues"></a>
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
## 📌 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).
|
||||
|
||||
---
|
||||
|
||||
<p align="center">
|
||||
Hecho con ❤️ por <a href="https://koneko.mx">Koneko Soluciones Tecnológicas</a>
|
||||
</p>
|
98
Services/WarehouseCatalogService.php
Normal file
98
Services/WarehouseCatalogService.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyWarehouse\Services;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class WarehouseCatalogService
|
||||
{
|
||||
protected $catalogs = [
|
||||
'warehouses' => [
|
||||
'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();
|
||||
}
|
||||
}
|
36
composer.json
Normal file
36
composer.json
Normal file
@ -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
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('product_categories', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
|
||||
$table->unsignedMediumInteger('parent_id')->nullable()->index();
|
||||
$table->string('parent_slug')->nullable()->index();
|
||||
|
||||
$table->string('name')->index();
|
||||
$table->string('slug')->nullable()->index();
|
||||
$table->string('icon')->nullable();
|
||||
|
||||
$table->mediumText('description')->nullable();
|
||||
|
||||
$table->boolean('show_in_pos')->index();
|
||||
$table->boolean('show_in_purchases')->index();
|
||||
$table->boolean('show_in_ecommerce')->index();
|
||||
$table->boolean('show_in_manufacturing')->index();
|
||||
$table->boolean('show_in_quality')->index();
|
||||
$table->boolean('show_in_assets')->index();
|
||||
|
||||
$table->unsignedTinyInteger('priority')->nullable()->index();
|
||||
|
||||
// Aditoria
|
||||
$table->timestamps();
|
||||
|
||||
// Index
|
||||
$table->unique(['parent_id', 'slug']);
|
||||
|
||||
// Relaciones
|
||||
//$table->foreign('parent_id')->references('id')->on('product_categories')->onUpdate('restrict')->onDelete('cascade');
|
||||
});
|
||||
|
||||
DB::unprepared("CREATE TRIGGER before_delete_category
|
||||
BEFORE DELETE ON product_categories
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
-- Verificar si la categoría tiene hijos
|
||||
IF (SELECT COUNT(*) FROM product_categories WHERE parent_id = OLD.id) > 0 THEN
|
||||
-- Generar un error para evitar la eliminación
|
||||
SIGNAL SQLSTATE '45000'
|
||||
SET MESSAGE_TEXT = 'No se puede eliminar la categoría porque tiene categorías hijas.';
|
||||
END IF;
|
||||
END");
|
||||
|
||||
|
||||
Schema::create('category_properties', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
|
||||
$table->unsignedMediumInteger('category_id')->index();
|
||||
$table->unsignedSmallInteger('property_id')->index();
|
||||
|
||||
$table->boolean('is_required'); // Si es obligatorio en esta categoría
|
||||
$table->boolean('is_filterable'); // Si se puede usar en filtros
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('category_id')->references('id')->on('product_categories')->onUpdate('restrict')->onDelete('cascade');
|
||||
//$table->foreign('property_id')->references('id')->on('product_properties')->onUpdate('restrict')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('product_categories');
|
||||
DB::unprepared("DROP TRIGGER IF EXISTS before_delete_category");
|
||||
Schema::dropIfExists('category_properties');
|
||||
}
|
||||
};
|
149
database/migrations/2024_12_16_092473_create_products_tables.php
Normal file
149
database/migrations/2024_12_16_092473_create_products_tables.php
Normal file
@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('products', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
$table->unsignedTinyInteger('type')->index();
|
||||
|
||||
$table->unsignedMediumInteger('category_id')->index(); // product_categories.id
|
||||
|
||||
$table->string('descripcion')->fulltext();
|
||||
$table->mediumText('descripcion_completa')->nullable()->index();
|
||||
$table->string('no_identificacion', 40)->nullable()->unique();
|
||||
$table->string('slug')->nullable()->unique();
|
||||
|
||||
$table->boolean('available_in_pos')->index();
|
||||
$table->boolean('available_in_purchases')->index();
|
||||
$table->boolean('available_in_ecommerce')->index();
|
||||
$table->boolean('available_in_maanufacturing')->index();
|
||||
$table->boolean('available_in_quality')->index();
|
||||
$table->boolean('available_in_assets')->index();
|
||||
|
||||
$table->string('c_clave_unidad', 3)->nullable()->index(); // sat_clave_unidad.
|
||||
$table->unsignedInteger('c_clave_prod_serv')->nullable()->index(); // sat_clave_prod_serv.
|
||||
$table->unsignedBigInteger('ean_code')->nullable()->unique();
|
||||
|
||||
$table->decimal('costo', 9, 2)->unsigned()->nullable();
|
||||
$table->char('c_moneda', 3)->charset('ascii')->collation('ascii_general_ci')->nullable()->index();
|
||||
$table->unsignedTinyInteger('c_objeto_imp')->nullable()->index(); // sat_objeto_imp.
|
||||
$table->json('impuestos')->nullable();
|
||||
$table->decimal('traslados', 9, 6)->unsigned()->nullable();
|
||||
$table->decimal('retenciones', 9, 6)->unsigned()->nullable();
|
||||
|
||||
$table->unsignedTinyInteger('data_lot_enable')->nullable()->index();
|
||||
$table->unsignedTinyInteger('data_lot_require')->nullable()->index();
|
||||
$table->unsignedTinyInteger('data_series_enable')->nullable()->index();
|
||||
$table->unsignedTinyInteger('data_series_require')->nullable()->index();
|
||||
$table->unsignedTinyInteger('data_expiration_enable')->nullable()->index();
|
||||
$table->unsignedTinyInteger('data_expiration_require')->nullable()->index();
|
||||
$table->unsignedTinyInteger('data_warranty_enable')->nullable()->index();
|
||||
$table->unsignedMediumInteger('warranty')->nullable()->index();
|
||||
$table->unsignedTinyInteger('data_best_before_enable')->nullable()->index();
|
||||
$table->unsignedTinyInteger('data_best_before_require')->nullable()->index();
|
||||
$table->unsignedTinyInteger('data_observations_enable')->nullable()->index();
|
||||
|
||||
$table->decimal('minimum_unit', 7, 6)->unsigned()->nullable(); // Decimales soportados en la Unidad de Medida
|
||||
$table->unsignedTinyInteger('affects_inventory')->nullable()->index();
|
||||
|
||||
$table->unsignedTinyInteger('status')->index();
|
||||
|
||||
// Auditoría
|
||||
$table->unsignedMediumInteger('created_by')->nullable()->index(); // users.id
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('category_id')->references('id')->on('product_categories')->onUpdate('restrict')->onDelete('restrict');
|
||||
$table->foreign('c_moneda')->references('c_moneda')->on('sat_moneda')->onUpdate('restrict')->onDelete('restrict');
|
||||
$table->foreign('c_clave_unidad')->references('c_clave_unidad')->on('sat_clave_unidad')->onUpdate('restrict')->onDelete('restrict');
|
||||
$table->foreign('c_clave_prod_serv')->references('c_clave_prod_serv')->on('sat_clave_prod_serv')->onUpdate('restrict')->onDelete('restrict');
|
||||
$table->foreign('created_by')->references('id')->on('users')->onUpdate('restrict')->onDelete('restrict');
|
||||
});
|
||||
|
||||
Schema::create('product_properties', function (Blueprint $table) {
|
||||
$table->smallIncrements('id');
|
||||
|
||||
$table->string('name')->index(); // Ej: "Marca", "Potencia", "Color"
|
||||
$table->enum('type', ['text', 'number', 'boolean', 'select'])->default('text');
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('product_store_prices', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
|
||||
$table->unsignedMediumInteger('product_id')->index();
|
||||
$table->unsignedSmallInteger('store_id')->index();
|
||||
|
||||
$table->decimal('price', 9, 2)->unsigned()->default(0);
|
||||
$table->char('currency', 3)->charset('ascii')->collation('ascii_general_ci');
|
||||
|
||||
$table->boolean('is_discounted')->index();
|
||||
$table->decimal('discount_price', 9, 2)->unsigned()->nullable();
|
||||
$table->date('discount_start')->nullable();
|
||||
$table->date('discount_end')->nullable();
|
||||
|
||||
// Auditoría
|
||||
$table->timestamps();
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('product_id')->references('id')->on('products')->onUpdate('restrict')->onDelete('cascade');
|
||||
$table->foreign('store_id')->references('id')->on('stores')->onUpdate('restrict')->onDelete('cascade');
|
||||
});
|
||||
|
||||
Schema::create('product_property', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
|
||||
$table->unsignedMediumInteger('product_id')->index();
|
||||
$table->unsignedSmallInteger('property_id')->index();
|
||||
|
||||
$table->string('value')->index(); // Valor de la propiedad, ej: 'Intel', 'DDR4', '500W'
|
||||
|
||||
// Auditoria
|
||||
$table->timestamps();
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('product_id')->references('id')->on('products')->onUpdate('restrict')->onDelete('cascade');
|
||||
$table->foreign('property_id')->references('id')->on('product_properties')->onUpdate('restrict')->onDelete('cascade');
|
||||
});
|
||||
|
||||
Schema::create('product_property_values', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
|
||||
$table->unsignedMediumInteger('product_id')->index();
|
||||
$table->unsignedSmallInteger('property_id')->index();
|
||||
|
||||
$table->string('value_text')->nullable()->index();
|
||||
$table->decimal('value_number', 9, 2)->nullable();
|
||||
$table->boolean('value_boolean')->nullable();
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
// Relaciones
|
||||
$table->foreign('product_id')->references('id')->on('products')->onUpdate('restrict')->onDelete('cascade');
|
||||
$table->foreign('property_id')->references('id')->on('product_properties')->onUpdate('restrict')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('products');
|
||||
Schema::dropIfExists('product_properties');
|
||||
Schema::dropIfExists('product_store_prices');
|
||||
Schema::dropIfExists('product_property');
|
||||
Schema::dropIfExists('product_property_values');
|
||||
}
|
||||
};
|
@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('warehouses', function (Blueprint $table) {
|
||||
$table->smallIncrements('id');
|
||||
|
||||
$table->unsignedSmallInteger('store_id')->index(); // Relación con sucursal
|
||||
$table->unsignedSmallInteger('work_center_id')->nullable()->index();
|
||||
|
||||
$table->string('code', 16)->unique();
|
||||
$table->string('name', 96)->index();
|
||||
|
||||
$table->mediumText('description')->nullable();
|
||||
|
||||
$table->unsignedMediumInteger('manager_id')->nullable()->index(); // sat_codigo_postal.
|
||||
|
||||
$table->string('tel')->nullable();
|
||||
$table->string('tel2')->nullable();
|
||||
|
||||
$table->unsignedTinyInteger('priority')->nullable();
|
||||
|
||||
$table->boolean('status')->default(true)->index();
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
// Indices
|
||||
$table->unique(['store_id', 'name']);
|
||||
|
||||
$table->foreign('store_id')->references('id')->on('stores')->onDelete('cascade');
|
||||
$table->foreign('work_center_id')->references('id')->on('store_work_centers')->onDelete('cascade');
|
||||
$table->foreign('manager_id')->references('id')->on('users')->onUpdate('restrict')->onDelete('restrict');
|
||||
});
|
||||
|
||||
Schema::create('warehouse_movements', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
|
||||
$table->unsignedSmallInteger('store_id')->index();
|
||||
$table->unsignedSmallInteger('warehouse_id')->index(); // Almacén involucrado
|
||||
|
||||
// Tipo de ajuste (ajuste de inventario o traspaso)
|
||||
$table->unsignedTinyInteger('movement_type')->index(); // Tipo de movimiento: ajuste o traspaso
|
||||
$table->unsignedMediumInteger('movement_id')->nullable(); // UID específico por sucursal
|
||||
|
||||
$table->unsignedMediumInteger('created_by')->index(); // Usuario que registró el movimiento
|
||||
$table->unsignedMediumInteger('approved_by')->nullable()->index(); // Usuario que autorizó el movimiento
|
||||
|
||||
// Cantidad ajustada
|
||||
$table->decimal('adjusted_quantity', 13, 6); // Cantidad ajustada para el ajuste o transferencia
|
||||
|
||||
// Costo asociado
|
||||
$table->decimal('cost', 9, 2)->unsigned()->default(0); // Costo de la operación
|
||||
|
||||
// Notas sobre el ajuste
|
||||
$table->mediumText('notes')->nullable(); // Notas adicionales
|
||||
|
||||
// Campos para el traspaso
|
||||
$table->unsignedSmallInteger('to_warehouse_id')->nullable()->index(); // Almacén de destino (solo para traspasos)
|
||||
|
||||
$table->unsignedTinyInteger('status')->index(); // Estatus de la orden ('pending', 'approved', 'received', 'cancelled')
|
||||
|
||||
$table->softDeletes();
|
||||
$table->timestamps();
|
||||
|
||||
|
||||
// Claves foráneas
|
||||
$table->foreign('store_id')->references('id')->on('stores')->onDelete('restrict');
|
||||
$table->foreign('warehouse_id')->references('id')->on('warehouses')->onDelete('restrict');
|
||||
$table->foreign('to_warehouse_id')->references('id')->on('warehouses')->onDelete('restrict');
|
||||
$table->foreign('created_by')->references('id')->on('users')->onDelete('restrict');
|
||||
$table->foreign('approved_by')->references('id')->on('users')->onDelete('restrict');
|
||||
|
||||
});
|
||||
|
||||
Schema::create('lot_numbers', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
|
||||
$table->unsignedMediumInteger('product_id')->index();
|
||||
$table->unsignedSmallInteger('store_id')->index();
|
||||
$table->unsignedSmallInteger('warehouse_id')->index();
|
||||
|
||||
$table->string('lot_number', 50)->unique()->comment('Número único del lote');
|
||||
$table->date('production_date')->nullable();
|
||||
$table->date('expiry_date')->nullable();
|
||||
$table->decimal('initial_quantity', 13, 6)->unsigned()->default(0);
|
||||
$table->decimal('remaining_quantity', 13, 6)->unsigned()->default(0);
|
||||
$table->decimal('cost', 9, 2)->unsigned()->default(0);
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
$table->foreign('product_id')->references('id')->on('products')->onDelete('restrict');
|
||||
$table->foreign('store_id')->references('id')->on('stores')->onDelete('restrict');
|
||||
$table->foreign('warehouse_id')->references('id')->on('warehouses')->onDelete('restrict');
|
||||
});
|
||||
|
||||
Schema::create('inventory_stock_levels', function (Blueprint $table) {
|
||||
$table->mediumIncrements('id');
|
||||
|
||||
$table->unsignedMediumInteger('product_id')->index();
|
||||
$table->unsignedSmallInteger('store_id')->nullable()->index();
|
||||
$table->unsignedSmallInteger('warehouse_id')->index();
|
||||
|
||||
$table->decimal('quantity', 13, 6)->unsigned()->comment('Stock total disponible en el almacén');
|
||||
|
||||
// Stock separado por área
|
||||
$table->decimal('pos_stock', 13, 6)->unsigned()->default(0)->comment('Stock destinado a ventas en POS');
|
||||
$table->decimal('ecommerce_stock', 13, 6)->unsigned()->default(0)->comment('Stock destinado a eCommerce');
|
||||
$table->decimal('purchase_reserved_stock', 13, 6)->unsigned()->default(0)->comment('Stock reservado para órdenes de compra');
|
||||
$table->decimal('asset_stock', 13, 6)->unsigned()->default(0)->comment('Stock reservado para uso interno');
|
||||
|
||||
// Alertas de Stock mínimo y máximo
|
||||
$table->unsignedTinyInteger('alert_minimum_stock')->nullable()->index();
|
||||
$table->decimal('minimum_stock', 13, 6)->unsigned()->nullable();
|
||||
$table->unsignedTinyInteger('alert_maximum_stock')->nullable()->index();
|
||||
$table->decimal('maximum_stock', 13, 6)->unsigned()->nullable();
|
||||
|
||||
// Costos asociados
|
||||
$table->decimal('last_cost', 9, 2)->unsigned()->default(0); // Último costo registrado
|
||||
$table->decimal('average_cost', 9, 2)->unsigned()->default(0); // Costo promedio ponderado
|
||||
$table->decimal('total_last_cost', 11, 2)->unsigned()->default(0); // Costo total último costo registrado
|
||||
$table->decimal('total_average_cost', 11, 2)->unsigned()->default(0); // Costo total promedio ponderado
|
||||
$table->decimal('total_identified_cost', 11, 2)->unsigned()->default(0); // Costo total identificado
|
||||
|
||||
$table->unsignedTinyInteger('costing_method')->index(); // Método de costeo: 'average', 'last', 'identified'
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['warehouse_id', 'product_id']);
|
||||
|
||||
$table->foreign('product_id')->references('id')->on('products')->onDelete('restrict');
|
||||
$table->foreign('store_id')->references('id')->on('stores')->onDelete('restrict');
|
||||
$table->foreign('warehouse_id')->references('id')->on('warehouses')->onDelete('restrict');
|
||||
});
|
||||
|
||||
Schema::create('inventory_movements', function (Blueprint $table) {
|
||||
$table->integerIncrements('id');
|
||||
|
||||
$table->unsignedMediumInteger('product_id')->index();
|
||||
$table->unsignedSmallInteger('store_id')->index();
|
||||
$table->unsignedSmallInteger('warehouse_id')->index();
|
||||
|
||||
$table->enum('movement_type', ['in', 'out'])->index(); // Tipo de movimiento (entrada/salida)
|
||||
|
||||
$table->decimal('quantity', 13, 6)->unsigned();
|
||||
|
||||
$table->decimal('cost', 9, 2)->unsigned(); // Costo asociado a la transacción
|
||||
$table->decimal('cost_before', 9, 2)->unsigned()->nullable();
|
||||
$table->decimal('cost_after', 9, 2)->unsigned()->nullable();
|
||||
$table->enum('cost_type', ['average', 'last', 'specific'])->default('last');
|
||||
|
||||
$table->text('notes')->nullable(); // Notas sobre el movimiento
|
||||
|
||||
// Define el campo para la relación polimórfica manualmente
|
||||
$table->unsignedMediumInteger('transactionable_id')->index();
|
||||
$table->string('transactionable_type')->index();
|
||||
|
||||
$table->unsignedMediumInteger('created_by')->index(); // Usuario que registró el movimiento
|
||||
|
||||
$table->timestamps();
|
||||
|
||||
// Agrega el índice con un nombre específico para evitar el problema de longitud
|
||||
$table->index(['transactionable_type', 'transactionable_id'], 'inventory_movements_transactionable_index');
|
||||
|
||||
$table->foreign('product_id')->references('id')->on('products')->onDelete('restrict');
|
||||
$table->foreign('store_id')->references('id')->on('stores')->onDelete('restrict');
|
||||
$table->foreign('warehouse_id')->references('id')->on('warehouses')->onDelete('restrict');
|
||||
$table->foreign('created_by')->references('id')->on('users')->onDelete('restrict');
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('warehouses');
|
||||
Schema::dropIfExists('warehouse_movements');
|
||||
Schema::dropIfExists('lot_numbers');
|
||||
Schema::dropIfExists('inventory_stock_levels');
|
||||
Schema::dropIfExists('inventory_movements');
|
||||
}
|
||||
};
|
17
resources/assets/js/bootstrap-table/warehouseFormatters.js
Normal file
17
resources/assets/js/bootstrap-table/warehouseFormatters.js
Normal file
@ -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 `
|
||||
<div class="inline-flex space-x-2">
|
||||
<a href="javascript:;" title="Editar" class="mx-2" wire:click="dispatch('editWarehouse', {id:${row.id}})">
|
||||
<i class="ti ti-edit"></i>
|
||||
</a>
|
||||
<a href="javascript:;" title="Eliminar" class="mx-2" wire:click="dispatch('confirmDeletionWarehouse', {id:${row.id}})">
|
||||
<i class="ti ti-trash"></i>
|
||||
</a>
|
||||
</div>`.trim();
|
||||
};
|
||||
|
||||
|
21
resources/views/inventory-items/index.blade.php
Normal file
21
resources/views/inventory-items/index.blade.php
Normal file
@ -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
|
21
resources/views/inventory-movements/index.blade.php
Normal file
21
resources/views/inventory-movements/index.blade.php
Normal file
@ -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
|
21
resources/views/inventory-stock/index.blade.php
Normal file
21
resources/views/inventory-stock/index.blade.php
Normal file
@ -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
|
@ -0,0 +1,516 @@
|
||||
<section id="crm-warehouse-index">
|
||||
<div class="crm-warehouse-index alert-errors"></div>
|
||||
<div wire:ignore>
|
||||
<div class="query-filters" id="toolbar">
|
||||
<div class="d-flex flex-wrap">
|
||||
<div class="pt-1 pr-2 pb-1" style="min-width: 175px; max-width: 225px">
|
||||
<button data-bs-toggle='offcanvas' data-bs-target='#offcanvasUser' class="btn btn-primary waves-effect waves-light">Agregar almacén</button>
|
||||
</div>
|
||||
<button type="button" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#accordionFiltrado" aria-expanded="false" aria-controls="accordionFiltrado">
|
||||
Filtrado
|
||||
</button>
|
||||
<div class="px-2 pt-1">
|
||||
<button class="btn btn-label-secondary waves-effect py-3 btn-refresh" disabled><i class="fa-solid fa-rotate"></i></button>
|
||||
</div>
|
||||
<div class="pr-2" style="width: 60px;">
|
||||
<a href="javascript:void(0)" class="clear-filters">Limpiar Filtrado</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table id="bt-warehouses"></table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
const store_route = '{{ route('admin.core.users.store') }}',
|
||||
route_show = '{{ route('admin.inventory.warehouse.show', ['warehouse' => '~warehouse~']) }}',
|
||||
route_destroy = '{{ route('admin.inventory.warehouse.destroy', ['warehouse' => '~warehouse~']) }}',
|
||||
statusList = {!! json_encode($status_list) !!},
|
||||
statusIntCatalogCss = {!! json_encode($status_list_class) !!};
|
||||
|
||||
var btt_height;
|
||||
|
||||
|
||||
// BootstrapTable Petición AJAX
|
||||
function ajaxRequest(params) {
|
||||
let url = '{{ url()->current() }}' +
|
||||
'?' +
|
||||
$.param(params.data) +
|
||||
'&' +
|
||||
$('.query-filters :input').serialize();
|
||||
|
||||
$.get(url).then(function (res) {
|
||||
params.success(res)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// BootstrapTable Formatter
|
||||
function userAvatarFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex justify-content-start align-items-center user-name">',
|
||||
'<div class="avatar-wrapper">',
|
||||
'<div class="avatar avatar-sm me-4">' +
|
||||
'<img src="' + row.profile_photo_url + '" alt="Avatar" class="rounded-circle">' +
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<div class="d-flex flex-column">',
|
||||
'<a href="' + show_href + '" class="text-heading text-truncate"><span class="fw-medium">' + row.name + '</span></a>',
|
||||
'<small>' + row.email + '</small>',
|
||||
'</div>',
|
||||
'</div>',
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
function uidFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex align-items-center justify-content-center">',
|
||||
'<a href="' + show_href + '" class="whitespace-nowrap" title="Ver warehouseo"> ' + row.id + '</a>',
|
||||
@can('crm.warehouses.update')
|
||||
'<a href="javascript:;" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill dropdown-toggle hide-arrow" data-bs-toggle="dropdown"><i class="ti ti-dots-vertical ti-md"></i></a>',
|
||||
'<div class="dropdown-menu dropdown-menu-end m-0">',
|
||||
'<a href="javascript:deleteRow(' + row.id + ');" class="dropdown-item delete-record">Eliminar</a>',
|
||||
'</div>',
|
||||
@endcan
|
||||
'</div>'
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
// BootstrapTable Init
|
||||
function initTable(table) {
|
||||
$(table)
|
||||
.bootstrapTable('destroy')
|
||||
.bootstrapTable({
|
||||
height: btt_height,
|
||||
locale: 'es-MX',
|
||||
ajax: "ajaxRequest",
|
||||
toolbar: "#toolbar",
|
||||
search: true,
|
||||
showColumns: true,
|
||||
showColumnsToggleAll: true,
|
||||
showExport: true,
|
||||
showFullscreen: true,
|
||||
showPaginationSwitch: true,
|
||||
showRefresh: true,
|
||||
showToggle: true,
|
||||
clickToSelect: true,
|
||||
minimumCountColumns: 4,
|
||||
fixedColumns: true,
|
||||
fixedNumber: 1,
|
||||
idField: "id",
|
||||
pagination: true,
|
||||
pageList: [10, 25, 50, 100, 500],
|
||||
sidePagination: "server",
|
||||
exportTypes: ['csv', 'txt', 'excel'],
|
||||
exportOptions: {
|
||||
fileName: 'warehouseos',
|
||||
},
|
||||
sortName: 'users.id',
|
||||
sortOrder: 'desc',
|
||||
mobileResponsive: true,
|
||||
cookie: true,
|
||||
resizable: true,
|
||||
cookieIdTable:"crm-warehouse-index",
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'UID',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
sortName: 'users.id',
|
||||
switchable: false,
|
||||
formatter: uidFormatter
|
||||
},
|
||||
|
||||
{
|
||||
field: 'name',
|
||||
title: 'Nombre',
|
||||
formatter: userAvatarFormatter,
|
||||
},
|
||||
{
|
||||
field: 'email',
|
||||
title: 'Correo electrónico',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'tipo_persona',
|
||||
title: 'Tipo persona',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.tipoPersona,
|
||||
},
|
||||
{
|
||||
field: 'rfc',
|
||||
title: 'RFC',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'nombre_fiscal',
|
||||
title: 'Nombre fiscal',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'c_regimen_fiscal',
|
||||
title: 'Regimen fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.regimenFiscal,
|
||||
},
|
||||
{
|
||||
field: 'domicilio_fiscal',
|
||||
title: 'Domicilio fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'estado',
|
||||
title: 'Estado',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'municipio',
|
||||
title: 'Municipio',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'localidad',
|
||||
title: 'Localidad',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'c_uso_cfdi',
|
||||
title: 'Uso de CFDI',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.usoCfdi,
|
||||
},
|
||||
{
|
||||
field: 'cargo',
|
||||
title: 'Cargo',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
field: 'is_prospect',
|
||||
title: 'Es prospecto',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_customer',
|
||||
title: 'Es cliente',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_provider',
|
||||
title: 'Es proveedor',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_user',
|
||||
title: 'Es usuario',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'status',
|
||||
title: 'Estado',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.status,
|
||||
},
|
||||
{
|
||||
field: 'created_at',
|
||||
title: 'Creado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'created_by_name',
|
||||
title: 'Creado por',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
sortName: 'created_by_name',
|
||||
},
|
||||
{
|
||||
field: 'updated_at',
|
||||
title: 'Modificado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
function toggleSections() {
|
||||
const isProspect = $('#is_prospect').is(':checked');
|
||||
const isCustomer = $('#is_customer').is(':checked');
|
||||
const isProvider = $('#is_provider').is(':checked');
|
||||
const isUser = $('#is_user').is(':checked');
|
||||
|
||||
$('.div-sat').toggle(isCustomer || isProvider);
|
||||
$('.div-sat-customer').toggle(isCustomer);
|
||||
$('.div-user-auth').toggle(isCustomer || isUser);
|
||||
$('.div-roles').toggle(isUser);
|
||||
}
|
||||
|
||||
function toggleCheckboxes(status) {
|
||||
const isDisabled = status == 1;
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').prop('disabled', isDisabled);
|
||||
}
|
||||
|
||||
|
||||
load_js_form = () => {
|
||||
$('#userForm .select2')
|
||||
.each(function() {
|
||||
var $this = $(this)
|
||||
|
||||
$this.wrap('<div class="position-relative"></div>')
|
||||
|
||||
$this.select2({
|
||||
dropdownAutoWidth: true,
|
||||
width: '100%',
|
||||
dropdownParent: $this.parent()
|
||||
});
|
||||
});
|
||||
|
||||
// Evento para los checkboxes
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').on('change', toggleSections);
|
||||
|
||||
// Evento para el select de estado
|
||||
$('.div-status').on('change', 'select[name="status"]', function() {
|
||||
toggleCheckboxes($(this).val());
|
||||
});
|
||||
|
||||
|
||||
// Previo de imagenes
|
||||
document.getElementById("photo").addEventListener('change', updatePreviewImage);
|
||||
|
||||
|
||||
// Reset form
|
||||
$("#userForm")
|
||||
.on('reset', function(){
|
||||
var form = $("#userForm");
|
||||
|
||||
form.validate().resetForm();
|
||||
|
||||
setTimeout(function(){
|
||||
$('#roles').trigger('change');
|
||||
|
||||
toggleSections();
|
||||
}, 250)
|
||||
|
||||
$('#user-image').prop("src", "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
|
||||
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$('.pdf-dropzone-div').show();
|
||||
|
||||
$("#pdf-dropzone").removeAllFiles(true);
|
||||
});
|
||||
|
||||
|
||||
$("#userForm")
|
||||
.validate({
|
||||
errorClass: 'error',
|
||||
highlight: function(element, errorClass, validClass) {
|
||||
// Agrega la clase de error a la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').addClass('has-error');
|
||||
},
|
||||
unhighlight: function(element, errorClass, validClass) {
|
||||
// Elimina la clase de error de la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').removeClass('has-error');
|
||||
},
|
||||
errorPlacement: function(error, element) {
|
||||
// Controla dónde se colocan los mensajes de error
|
||||
error.appendTo(element.closest('.mb-3').find('.error-message'));
|
||||
},
|
||||
rules: {
|
||||
name: {
|
||||
required: true,
|
||||
minlength: 5
|
||||
},
|
||||
email: {
|
||||
required: true,
|
||||
email: true
|
||||
},
|
||||
password: {
|
||||
required: function(element) {
|
||||
return !$("#userForm input[name=id]").val() && ($('#is_user').is(':checked') || $('#is_customer').is(':checked'));
|
||||
},
|
||||
minlength: 6
|
||||
}
|
||||
},
|
||||
messages: {
|
||||
name: {
|
||||
required: "Por favor ingrese su nombre completo",
|
||||
minlength: "El nombre completo debe tener al menos 8 caracteres"
|
||||
},
|
||||
email: {
|
||||
required: "Por favor ingrese su correo electrónico",
|
||||
email: "El valor no es una dirección de correo válida"
|
||||
},
|
||||
password: {
|
||||
required: "La contraseña es obligatoria para nuevos usuarios",
|
||||
minlength: "La contraseña debe tener al menos 6 caracteres"
|
||||
}
|
||||
},
|
||||
submitHandler: function(form, event) {
|
||||
// Evita que el formulario se envíe automáticamente
|
||||
event.preventDefault();
|
||||
|
||||
var form = $("#userForm")[0],
|
||||
data = new FormData(form);
|
||||
|
||||
$('#userForm :input').prop('disabled', true);
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$.ajax({
|
||||
url: store_route,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
||||
},
|
||||
data: data,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
cache: false,
|
||||
timeout: 3000,
|
||||
success: function(data) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
if (data.errors) {
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + data.errors + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
} else {
|
||||
let $usersIndexAlert = $('.crm-warehouse-index.alert-errors');
|
||||
|
||||
$usersIndexAlert.html('<div class="alert alert-success alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' +
|
||||
'<p class="mb-0"><strong>' + data.success + '</strong></p>' +
|
||||
'</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
$('#userForm button[type=reset]').trigger('click');
|
||||
$('#toolbar .clear-filters').trigger('click');
|
||||
}
|
||||
},
|
||||
error: function(e) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + e.responseJSON.message + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Inicializar el estado al cargar la página
|
||||
toggleSections();
|
||||
toggleCheckboxes($('select[name="status"]').val());
|
||||
}
|
||||
|
||||
// Previo de imagen de perfil
|
||||
updatePreviewImage = (event) => {
|
||||
var file = event.target.files[0],
|
||||
reader = new FileReader();
|
||||
|
||||
reader.onload = event => {
|
||||
document.getElementById('user-image').setAttribute('src', event.target.result);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
$(document).ready(function() {
|
||||
var $table = $('#bt-warehouses'),
|
||||
$btnRefresh = $('#toolbar .btn-refresh'),
|
||||
$clearFilters = $('a.clear-filters');
|
||||
|
||||
var btt_rest_height = 220,
|
||||
btt_min_height = 600;
|
||||
|
||||
btt_height = (window.innerHeight - btt_rest_height) < btt_min_height?
|
||||
btt_height:
|
||||
window.innerHeight - btt_rest_height;
|
||||
|
||||
var offcanvasElement = document.getElementById('offcanvasUser'),
|
||||
offcanvasUser = new bootstrap.Offcanvas(offcanvasElement);
|
||||
|
||||
const refreshButton = document.querySelector('.btn-refresh');
|
||||
const inputs = document.querySelectorAll('#toolbar input, #toolbar select');
|
||||
|
||||
inputs.forEach(input => {
|
||||
input.addEventListener('change', () => {
|
||||
refreshButton.disabled = false;
|
||||
refreshButton.classList.remove('btn-label-secondary');
|
||||
refreshButton.classList.add('btn-label-success');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Button Refresh
|
||||
$btnRefresh
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('refresh');
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
// Button clear filters
|
||||
$clearFilters
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('resetSearch', ''); // Inicializa la búsqueda con cadena vacía
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
|
||||
initTable('#bt-warehouses'); // Una vez que todos los scripts estén cargados, inicializa Bootstrap Table
|
||||
|
||||
|
||||
load_js_form();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -0,0 +1,516 @@
|
||||
<section id="crm-warehouse-index">
|
||||
<div class="crm-warehouse-index alert-errors"></div>
|
||||
<div wire:ignore>
|
||||
<div class="query-filters" id="toolbar">
|
||||
<div class="d-flex flex-wrap">
|
||||
<div class="pt-1 pr-2 pb-1" style="min-width: 175px; max-width: 225px">
|
||||
<button data-bs-toggle='offcanvas' data-bs-target='#offcanvasUser' class="btn btn-primary waves-effect waves-light">Agregar almacén</button>
|
||||
</div>
|
||||
<button type="button" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#accordionFiltrado" aria-expanded="false" aria-controls="accordionFiltrado">
|
||||
Filtrado
|
||||
</button>
|
||||
<div class="px-2 pt-1">
|
||||
<button class="btn btn-label-secondary waves-effect py-3 btn-refresh" disabled><i class="fa-solid fa-rotate"></i></button>
|
||||
</div>
|
||||
<div class="pr-2" style="width: 60px;">
|
||||
<a href="javascript:void(0)" class="clear-filters">Limpiar Filtrado</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table id="bt-warehouses"></table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
const store_route = '{{ route('admin.core.users.store') }}',
|
||||
route_show = '{{ route('admin.inventory.warehouse.show', ['warehouse' => '~warehouse~']) }}',
|
||||
route_destroy = '{{ route('admin.inventory.warehouse.destroy', ['warehouse' => '~warehouse~']) }}',
|
||||
statusList = {!! json_encode($status_list) !!},
|
||||
statusIntCatalogCss = {!! json_encode($status_list_class) !!};
|
||||
|
||||
var btt_height;
|
||||
|
||||
|
||||
// BootstrapTable Petición AJAX
|
||||
function ajaxRequest(params) {
|
||||
let url = '{{ url()->current() }}' +
|
||||
'?' +
|
||||
$.param(params.data) +
|
||||
'&' +
|
||||
$('.query-filters :input').serialize();
|
||||
|
||||
$.get(url).then(function (res) {
|
||||
params.success(res)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// BootstrapTable Formatter
|
||||
function userAvatarFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex justify-content-start align-items-center user-name">',
|
||||
'<div class="avatar-wrapper">',
|
||||
'<div class="avatar avatar-sm me-4">' +
|
||||
'<img src="' + row.profile_photo_url + '" alt="Avatar" class="rounded-circle">' +
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<div class="d-flex flex-column">',
|
||||
'<a href="' + show_href + '" class="text-heading text-truncate"><span class="fw-medium">' + row.name + '</span></a>',
|
||||
'<small>' + row.email + '</small>',
|
||||
'</div>',
|
||||
'</div>',
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
function uidFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex align-items-center justify-content-center">',
|
||||
'<a href="' + show_href + '" class="whitespace-nowrap" title="Ver warehouseo"> ' + row.id + '</a>',
|
||||
@can('crm.warehouses.update')
|
||||
'<a href="javascript:;" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill dropdown-toggle hide-arrow" data-bs-toggle="dropdown"><i class="ti ti-dots-vertical ti-md"></i></a>',
|
||||
'<div class="dropdown-menu dropdown-menu-end m-0">',
|
||||
'<a href="javascript:deleteRow(' + row.id + ');" class="dropdown-item delete-record">Eliminar</a>',
|
||||
'</div>',
|
||||
@endcan
|
||||
'</div>'
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
// BootstrapTable Init
|
||||
function initTable(table) {
|
||||
$(table)
|
||||
.bootstrapTable('destroy')
|
||||
.bootstrapTable({
|
||||
height: btt_height,
|
||||
locale: 'es-MX',
|
||||
ajax: "ajaxRequest",
|
||||
toolbar: "#toolbar",
|
||||
search: true,
|
||||
showColumns: true,
|
||||
showColumnsToggleAll: true,
|
||||
showExport: true,
|
||||
showFullscreen: true,
|
||||
showPaginationSwitch: true,
|
||||
showRefresh: true,
|
||||
showToggle: true,
|
||||
clickToSelect: true,
|
||||
minimumCountColumns: 4,
|
||||
fixedColumns: true,
|
||||
fixedNumber: 1,
|
||||
idField: "id",
|
||||
pagination: true,
|
||||
pageList: [10, 25, 50, 100, 500],
|
||||
sidePagination: "server",
|
||||
exportTypes: ['csv', 'txt', 'excel'],
|
||||
exportOptions: {
|
||||
fileName: 'warehouseos',
|
||||
},
|
||||
sortName: 'users.id',
|
||||
sortOrder: 'desc',
|
||||
mobileResponsive: true,
|
||||
cookie: true,
|
||||
resizable: true,
|
||||
cookieIdTable:"crm-warehouse-index",
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'UID',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
sortName: 'users.id',
|
||||
switchable: false,
|
||||
formatter: uidFormatter
|
||||
},
|
||||
|
||||
{
|
||||
field: 'name',
|
||||
title: 'Nombre',
|
||||
formatter: userAvatarFormatter,
|
||||
},
|
||||
{
|
||||
field: 'email',
|
||||
title: 'Correo electrónico',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'tipo_persona',
|
||||
title: 'Tipo persona',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.tipoPersona,
|
||||
},
|
||||
{
|
||||
field: 'rfc',
|
||||
title: 'RFC',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'nombre_fiscal',
|
||||
title: 'Nombre fiscal',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'c_regimen_fiscal',
|
||||
title: 'Regimen fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.regimenFiscal,
|
||||
},
|
||||
{
|
||||
field: 'domicilio_fiscal',
|
||||
title: 'Domicilio fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'estado',
|
||||
title: 'Estado',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'municipio',
|
||||
title: 'Municipio',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'localidad',
|
||||
title: 'Localidad',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'c_uso_cfdi',
|
||||
title: 'Uso de CFDI',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.usoCfdi,
|
||||
},
|
||||
{
|
||||
field: 'cargo',
|
||||
title: 'Cargo',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
field: 'is_prospect',
|
||||
title: 'Es prospecto',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_customer',
|
||||
title: 'Es cliente',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_provider',
|
||||
title: 'Es proveedor',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_user',
|
||||
title: 'Es usuario',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'status',
|
||||
title: 'Estado',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.status,
|
||||
},
|
||||
{
|
||||
field: 'created_at',
|
||||
title: 'Creado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'created_by_name',
|
||||
title: 'Creado por',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
sortName: 'created_by_name',
|
||||
},
|
||||
{
|
||||
field: 'updated_at',
|
||||
title: 'Modificado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
function toggleSections() {
|
||||
const isProspect = $('#is_prospect').is(':checked');
|
||||
const isCustomer = $('#is_customer').is(':checked');
|
||||
const isProvider = $('#is_provider').is(':checked');
|
||||
const isUser = $('#is_user').is(':checked');
|
||||
|
||||
$('.div-sat').toggle(isCustomer || isProvider);
|
||||
$('.div-sat-customer').toggle(isCustomer);
|
||||
$('.div-user-auth').toggle(isCustomer || isUser);
|
||||
$('.div-roles').toggle(isUser);
|
||||
}
|
||||
|
||||
function toggleCheckboxes(status) {
|
||||
const isDisabled = status == 1;
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').prop('disabled', isDisabled);
|
||||
}
|
||||
|
||||
|
||||
load_js_form = () => {
|
||||
$('#userForm .select2')
|
||||
.each(function() {
|
||||
var $this = $(this)
|
||||
|
||||
$this.wrap('<div class="position-relative"></div>')
|
||||
|
||||
$this.select2({
|
||||
dropdownAutoWidth: true,
|
||||
width: '100%',
|
||||
dropdownParent: $this.parent()
|
||||
});
|
||||
});
|
||||
|
||||
// Evento para los checkboxes
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').on('change', toggleSections);
|
||||
|
||||
// Evento para el select de estado
|
||||
$('.div-status').on('change', 'select[name="status"]', function() {
|
||||
toggleCheckboxes($(this).val());
|
||||
});
|
||||
|
||||
|
||||
// Previo de imagenes
|
||||
document.getElementById("photo").addEventListener('change', updatePreviewImage);
|
||||
|
||||
|
||||
// Reset form
|
||||
$("#userForm")
|
||||
.on('reset', function(){
|
||||
var form = $("#userForm");
|
||||
|
||||
form.validate().resetForm();
|
||||
|
||||
setTimeout(function(){
|
||||
$('#roles').trigger('change');
|
||||
|
||||
toggleSections();
|
||||
}, 250)
|
||||
|
||||
$('#user-image').prop("src", "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
|
||||
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$('.pdf-dropzone-div').show();
|
||||
|
||||
$("#pdf-dropzone").removeAllFiles(true);
|
||||
});
|
||||
|
||||
|
||||
$("#userForm")
|
||||
.validate({
|
||||
errorClass: 'error',
|
||||
highlight: function(element, errorClass, validClass) {
|
||||
// Agrega la clase de error a la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').addClass('has-error');
|
||||
},
|
||||
unhighlight: function(element, errorClass, validClass) {
|
||||
// Elimina la clase de error de la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').removeClass('has-error');
|
||||
},
|
||||
errorPlacement: function(error, element) {
|
||||
// Controla dónde se colocan los mensajes de error
|
||||
error.appendTo(element.closest('.mb-3').find('.error-message'));
|
||||
},
|
||||
rules: {
|
||||
name: {
|
||||
required: true,
|
||||
minlength: 5
|
||||
},
|
||||
email: {
|
||||
required: true,
|
||||
email: true
|
||||
},
|
||||
password: {
|
||||
required: function(element) {
|
||||
return !$("#userForm input[name=id]").val() && ($('#is_user').is(':checked') || $('#is_customer').is(':checked'));
|
||||
},
|
||||
minlength: 6
|
||||
}
|
||||
},
|
||||
messages: {
|
||||
name: {
|
||||
required: "Por favor ingrese su nombre completo",
|
||||
minlength: "El nombre completo debe tener al menos 8 caracteres"
|
||||
},
|
||||
email: {
|
||||
required: "Por favor ingrese su correo electrónico",
|
||||
email: "El valor no es una dirección de correo válida"
|
||||
},
|
||||
password: {
|
||||
required: "La contraseña es obligatoria para nuevos usuarios",
|
||||
minlength: "La contraseña debe tener al menos 6 caracteres"
|
||||
}
|
||||
},
|
||||
submitHandler: function(form, event) {
|
||||
// Evita que el formulario se envíe automáticamente
|
||||
event.preventDefault();
|
||||
|
||||
var form = $("#userForm")[0],
|
||||
data = new FormData(form);
|
||||
|
||||
$('#userForm :input').prop('disabled', true);
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$.ajax({
|
||||
url: store_route,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
||||
},
|
||||
data: data,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
cache: false,
|
||||
timeout: 3000,
|
||||
success: function(data) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
if (data.errors) {
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + data.errors + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
} else {
|
||||
let $usersIndexAlert = $('.crm-warehouse-index.alert-errors');
|
||||
|
||||
$usersIndexAlert.html('<div class="alert alert-success alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' +
|
||||
'<p class="mb-0"><strong>' + data.success + '</strong></p>' +
|
||||
'</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
$('#userForm button[type=reset]').trigger('click');
|
||||
$('#toolbar .clear-filters').trigger('click');
|
||||
}
|
||||
},
|
||||
error: function(e) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + e.responseJSON.message + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Inicializar el estado al cargar la página
|
||||
toggleSections();
|
||||
toggleCheckboxes($('select[name="status"]').val());
|
||||
}
|
||||
|
||||
// Previo de imagen de perfil
|
||||
updatePreviewImage = (event) => {
|
||||
var file = event.target.files[0],
|
||||
reader = new FileReader();
|
||||
|
||||
reader.onload = event => {
|
||||
document.getElementById('user-image').setAttribute('src', event.target.result);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
$(document).ready(function() {
|
||||
var $table = $('#bt-warehouses'),
|
||||
$btnRefresh = $('#toolbar .btn-refresh'),
|
||||
$clearFilters = $('a.clear-filters');
|
||||
|
||||
var btt_rest_height = 220,
|
||||
btt_min_height = 600;
|
||||
|
||||
btt_height = (window.innerHeight - btt_rest_height) < btt_min_height?
|
||||
btt_height:
|
||||
window.innerHeight - btt_rest_height;
|
||||
|
||||
var offcanvasElement = document.getElementById('offcanvasUser'),
|
||||
offcanvasUser = new bootstrap.Offcanvas(offcanvasElement);
|
||||
|
||||
const refreshButton = document.querySelector('.btn-refresh');
|
||||
const inputs = document.querySelectorAll('#toolbar input, #toolbar select');
|
||||
|
||||
inputs.forEach(input => {
|
||||
input.addEventListener('change', () => {
|
||||
refreshButton.disabled = false;
|
||||
refreshButton.classList.remove('btn-label-secondary');
|
||||
refreshButton.classList.add('btn-label-success');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Button Refresh
|
||||
$btnRefresh
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('refresh');
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
// Button clear filters
|
||||
$clearFilters
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('resetSearch', ''); // Inicializa la búsqueda con cadena vacía
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
|
||||
initTable('#bt-warehouses'); // Una vez que todos los scripts estén cargados, inicializa Bootstrap Table
|
||||
|
||||
|
||||
load_js_form();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -0,0 +1,516 @@
|
||||
<section id="crm-warehouse-index">
|
||||
<div class="crm-warehouse-index alert-errors"></div>
|
||||
<div wire:ignore>
|
||||
<div class="query-filters" id="toolbar">
|
||||
<div class="d-flex flex-wrap">
|
||||
<div class="pt-1 pr-2 pb-1" style="min-width: 175px; max-width: 225px">
|
||||
<button data-bs-toggle='offcanvas' data-bs-target='#offcanvasUser' class="btn btn-primary waves-effect waves-light">Agregar almacén</button>
|
||||
</div>
|
||||
<button type="button" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#accordionFiltrado" aria-expanded="false" aria-controls="accordionFiltrado">
|
||||
Filtrado
|
||||
</button>
|
||||
<div class="px-2 pt-1">
|
||||
<button class="btn btn-label-secondary waves-effect py-3 btn-refresh" disabled><i class="fa-solid fa-rotate"></i></button>
|
||||
</div>
|
||||
<div class="pr-2" style="width: 60px;">
|
||||
<a href="javascript:void(0)" class="clear-filters">Limpiar Filtrado</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table id="bt-warehouses"></table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
const store_route = '{{ route('admin.core.users.store') }}',
|
||||
route_show = '{{ route('admin.inventory.warehouse.show', ['warehouse' => '~warehouse~']) }}',
|
||||
route_destroy = '{{ route('admin.inventory.warehouse.destroy', ['warehouse' => '~warehouse~']) }}',
|
||||
statusList = {!! json_encode($status_list) !!},
|
||||
statusIntCatalogCss = {!! json_encode($status_list_class) !!};
|
||||
|
||||
var btt_height;
|
||||
|
||||
|
||||
// BootstrapTable Petición AJAX
|
||||
function ajaxRequest(params) {
|
||||
let url = '{{ url()->current() }}' +
|
||||
'?' +
|
||||
$.param(params.data) +
|
||||
'&' +
|
||||
$('.query-filters :input').serialize();
|
||||
|
||||
$.get(url).then(function (res) {
|
||||
params.success(res)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// BootstrapTable Formatter
|
||||
function userAvatarFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex justify-content-start align-items-center user-name">',
|
||||
'<div class="avatar-wrapper">',
|
||||
'<div class="avatar avatar-sm me-4">' +
|
||||
'<img src="' + row.profile_photo_url + '" alt="Avatar" class="rounded-circle">' +
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<div class="d-flex flex-column">',
|
||||
'<a href="' + show_href + '" class="text-heading text-truncate"><span class="fw-medium">' + row.name + '</span></a>',
|
||||
'<small>' + row.email + '</small>',
|
||||
'</div>',
|
||||
'</div>',
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
function uidFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex align-items-center justify-content-center">',
|
||||
'<a href="' + show_href + '" class="whitespace-nowrap" title="Ver warehouseo"> ' + row.id + '</a>',
|
||||
@can('crm.warehouses.update')
|
||||
'<a href="javascript:;" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill dropdown-toggle hide-arrow" data-bs-toggle="dropdown"><i class="ti ti-dots-vertical ti-md"></i></a>',
|
||||
'<div class="dropdown-menu dropdown-menu-end m-0">',
|
||||
'<a href="javascript:deleteRow(' + row.id + ');" class="dropdown-item delete-record">Eliminar</a>',
|
||||
'</div>',
|
||||
@endcan
|
||||
'</div>'
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
// BootstrapTable Init
|
||||
function initTable(table) {
|
||||
$(table)
|
||||
.bootstrapTable('destroy')
|
||||
.bootstrapTable({
|
||||
height: btt_height,
|
||||
locale: 'es-MX',
|
||||
ajax: "ajaxRequest",
|
||||
toolbar: "#toolbar",
|
||||
search: true,
|
||||
showColumns: true,
|
||||
showColumnsToggleAll: true,
|
||||
showExport: true,
|
||||
showFullscreen: true,
|
||||
showPaginationSwitch: true,
|
||||
showRefresh: true,
|
||||
showToggle: true,
|
||||
clickToSelect: true,
|
||||
minimumCountColumns: 4,
|
||||
fixedColumns: true,
|
||||
fixedNumber: 1,
|
||||
idField: "id",
|
||||
pagination: true,
|
||||
pageList: [10, 25, 50, 100, 500],
|
||||
sidePagination: "server",
|
||||
exportTypes: ['csv', 'txt', 'excel'],
|
||||
exportOptions: {
|
||||
fileName: 'warehouseos',
|
||||
},
|
||||
sortName: 'users.id',
|
||||
sortOrder: 'desc',
|
||||
mobileResponsive: true,
|
||||
cookie: true,
|
||||
resizable: true,
|
||||
cookieIdTable:"crm-warehouse-index",
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'UID',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
sortName: 'users.id',
|
||||
switchable: false,
|
||||
formatter: uidFormatter
|
||||
},
|
||||
|
||||
{
|
||||
field: 'name',
|
||||
title: 'Nombre',
|
||||
formatter: userAvatarFormatter,
|
||||
},
|
||||
{
|
||||
field: 'email',
|
||||
title: 'Correo electrónico',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'tipo_persona',
|
||||
title: 'Tipo persona',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.tipoPersona,
|
||||
},
|
||||
{
|
||||
field: 'rfc',
|
||||
title: 'RFC',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'nombre_fiscal',
|
||||
title: 'Nombre fiscal',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'c_regimen_fiscal',
|
||||
title: 'Regimen fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.regimenFiscal,
|
||||
},
|
||||
{
|
||||
field: 'domicilio_fiscal',
|
||||
title: 'Domicilio fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'estado',
|
||||
title: 'Estado',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'municipio',
|
||||
title: 'Municipio',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'localidad',
|
||||
title: 'Localidad',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'c_uso_cfdi',
|
||||
title: 'Uso de CFDI',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.usoCfdi,
|
||||
},
|
||||
{
|
||||
field: 'cargo',
|
||||
title: 'Cargo',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
field: 'is_prospect',
|
||||
title: 'Es prospecto',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_customer',
|
||||
title: 'Es cliente',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_provider',
|
||||
title: 'Es proveedor',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_user',
|
||||
title: 'Es usuario',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'status',
|
||||
title: 'Estado',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.status,
|
||||
},
|
||||
{
|
||||
field: 'created_at',
|
||||
title: 'Creado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'created_by_name',
|
||||
title: 'Creado por',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
sortName: 'created_by_name',
|
||||
},
|
||||
{
|
||||
field: 'updated_at',
|
||||
title: 'Modificado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
function toggleSections() {
|
||||
const isProspect = $('#is_prospect').is(':checked');
|
||||
const isCustomer = $('#is_customer').is(':checked');
|
||||
const isProvider = $('#is_provider').is(':checked');
|
||||
const isUser = $('#is_user').is(':checked');
|
||||
|
||||
$('.div-sat').toggle(isCustomer || isProvider);
|
||||
$('.div-sat-customer').toggle(isCustomer);
|
||||
$('.div-user-auth').toggle(isCustomer || isUser);
|
||||
$('.div-roles').toggle(isUser);
|
||||
}
|
||||
|
||||
function toggleCheckboxes(status) {
|
||||
const isDisabled = status == 1;
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').prop('disabled', isDisabled);
|
||||
}
|
||||
|
||||
|
||||
load_js_form = () => {
|
||||
$('#userForm .select2')
|
||||
.each(function() {
|
||||
var $this = $(this)
|
||||
|
||||
$this.wrap('<div class="position-relative"></div>')
|
||||
|
||||
$this.select2({
|
||||
dropdownAutoWidth: true,
|
||||
width: '100%',
|
||||
dropdownParent: $this.parent()
|
||||
});
|
||||
});
|
||||
|
||||
// Evento para los checkboxes
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').on('change', toggleSections);
|
||||
|
||||
// Evento para el select de estado
|
||||
$('.div-status').on('change', 'select[name="status"]', function() {
|
||||
toggleCheckboxes($(this).val());
|
||||
});
|
||||
|
||||
|
||||
// Previo de imagenes
|
||||
document.getElementById("photo").addEventListener('change', updatePreviewImage);
|
||||
|
||||
|
||||
// Reset form
|
||||
$("#userForm")
|
||||
.on('reset', function(){
|
||||
var form = $("#userForm");
|
||||
|
||||
form.validate().resetForm();
|
||||
|
||||
setTimeout(function(){
|
||||
$('#roles').trigger('change');
|
||||
|
||||
toggleSections();
|
||||
}, 250)
|
||||
|
||||
$('#user-image').prop("src", "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
|
||||
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$('.pdf-dropzone-div').show();
|
||||
|
||||
$("#pdf-dropzone").removeAllFiles(true);
|
||||
});
|
||||
|
||||
|
||||
$("#userForm")
|
||||
.validate({
|
||||
errorClass: 'error',
|
||||
highlight: function(element, errorClass, validClass) {
|
||||
// Agrega la clase de error a la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').addClass('has-error');
|
||||
},
|
||||
unhighlight: function(element, errorClass, validClass) {
|
||||
// Elimina la clase de error de la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').removeClass('has-error');
|
||||
},
|
||||
errorPlacement: function(error, element) {
|
||||
// Controla dónde se colocan los mensajes de error
|
||||
error.appendTo(element.closest('.mb-3').find('.error-message'));
|
||||
},
|
||||
rules: {
|
||||
name: {
|
||||
required: true,
|
||||
minlength: 5
|
||||
},
|
||||
email: {
|
||||
required: true,
|
||||
email: true
|
||||
},
|
||||
password: {
|
||||
required: function(element) {
|
||||
return !$("#userForm input[name=id]").val() && ($('#is_user').is(':checked') || $('#is_customer').is(':checked'));
|
||||
},
|
||||
minlength: 6
|
||||
}
|
||||
},
|
||||
messages: {
|
||||
name: {
|
||||
required: "Por favor ingrese su nombre completo",
|
||||
minlength: "El nombre completo debe tener al menos 8 caracteres"
|
||||
},
|
||||
email: {
|
||||
required: "Por favor ingrese su correo electrónico",
|
||||
email: "El valor no es una dirección de correo válida"
|
||||
},
|
||||
password: {
|
||||
required: "La contraseña es obligatoria para nuevos usuarios",
|
||||
minlength: "La contraseña debe tener al menos 6 caracteres"
|
||||
}
|
||||
},
|
||||
submitHandler: function(form, event) {
|
||||
// Evita que el formulario se envíe automáticamente
|
||||
event.preventDefault();
|
||||
|
||||
var form = $("#userForm")[0],
|
||||
data = new FormData(form);
|
||||
|
||||
$('#userForm :input').prop('disabled', true);
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$.ajax({
|
||||
url: store_route,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
||||
},
|
||||
data: data,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
cache: false,
|
||||
timeout: 3000,
|
||||
success: function(data) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
if (data.errors) {
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + data.errors + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
} else {
|
||||
let $usersIndexAlert = $('.crm-warehouse-index.alert-errors');
|
||||
|
||||
$usersIndexAlert.html('<div class="alert alert-success alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' +
|
||||
'<p class="mb-0"><strong>' + data.success + '</strong></p>' +
|
||||
'</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
$('#userForm button[type=reset]').trigger('click');
|
||||
$('#toolbar .clear-filters').trigger('click');
|
||||
}
|
||||
},
|
||||
error: function(e) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + e.responseJSON.message + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Inicializar el estado al cargar la página
|
||||
toggleSections();
|
||||
toggleCheckboxes($('select[name="status"]').val());
|
||||
}
|
||||
|
||||
// Previo de imagen de perfil
|
||||
updatePreviewImage = (event) => {
|
||||
var file = event.target.files[0],
|
||||
reader = new FileReader();
|
||||
|
||||
reader.onload = event => {
|
||||
document.getElementById('user-image').setAttribute('src', event.target.result);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
$(document).ready(function() {
|
||||
var $table = $('#bt-warehouses'),
|
||||
$btnRefresh = $('#toolbar .btn-refresh'),
|
||||
$clearFilters = $('a.clear-filters');
|
||||
|
||||
var btt_rest_height = 220,
|
||||
btt_min_height = 600;
|
||||
|
||||
btt_height = (window.innerHeight - btt_rest_height) < btt_min_height?
|
||||
btt_height:
|
||||
window.innerHeight - btt_rest_height;
|
||||
|
||||
var offcanvasElement = document.getElementById('offcanvasUser'),
|
||||
offcanvasUser = new bootstrap.Offcanvas(offcanvasElement);
|
||||
|
||||
const refreshButton = document.querySelector('.btn-refresh');
|
||||
const inputs = document.querySelectorAll('#toolbar input, #toolbar select');
|
||||
|
||||
inputs.forEach(input => {
|
||||
input.addEventListener('change', () => {
|
||||
refreshButton.disabled = false;
|
||||
refreshButton.classList.remove('btn-label-secondary');
|
||||
refreshButton.classList.add('btn-label-success');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Button Refresh
|
||||
$btnRefresh
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('refresh');
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
// Button clear filters
|
||||
$clearFilters
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('resetSearch', ''); // Inicializa la búsqueda con cadena vacía
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
|
||||
initTable('#bt-warehouses'); // Una vez que todos los scripts estén cargados, inicializa Bootstrap Table
|
||||
|
||||
|
||||
load_js_form();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
516
resources/views/livewire/materials/materials-index.blade.php
Normal file
516
resources/views/livewire/materials/materials-index.blade.php
Normal file
@ -0,0 +1,516 @@
|
||||
<section id="crm-warehouse-index">
|
||||
<div class="crm-warehouse-index alert-errors"></div>
|
||||
<div wire:ignore>
|
||||
<div class="query-filters" id="toolbar">
|
||||
<div class="d-flex flex-wrap">
|
||||
<div class="pt-1 pr-2 pb-1" style="min-width: 175px; max-width: 225px">
|
||||
<button data-bs-toggle='offcanvas' data-bs-target='#offcanvasUser' class="btn btn-primary waves-effect waves-light">Agregar almacén</button>
|
||||
</div>
|
||||
<button type="button" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#accordionFiltrado" aria-expanded="false" aria-controls="accordionFiltrado">
|
||||
Filtrado
|
||||
</button>
|
||||
<div class="px-2 pt-1">
|
||||
<button class="btn btn-label-secondary waves-effect py-3 btn-refresh" disabled><i class="fa-solid fa-rotate"></i></button>
|
||||
</div>
|
||||
<div class="pr-2" style="width: 60px;">
|
||||
<a href="javascript:void(0)" class="clear-filters">Limpiar Filtrado</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table id="bt-warehouses"></table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
const store_route = '{{ route('admin.core.users.store') }}',
|
||||
route_show = '{{ route('admin.inventory.warehouse.show', ['warehouse' => '~warehouse~']) }}',
|
||||
route_destroy = '{{ route('admin.inventory.warehouse.destroy', ['warehouse' => '~warehouse~']) }}',
|
||||
statusList = {!! json_encode($status_list) !!},
|
||||
statusIntCatalogCss = {!! json_encode($status_list_class) !!};
|
||||
|
||||
var btt_height;
|
||||
|
||||
|
||||
// BootstrapTable Petición AJAX
|
||||
function ajaxRequest(params) {
|
||||
let url = '{{ url()->current() }}' +
|
||||
'?' +
|
||||
$.param(params.data) +
|
||||
'&' +
|
||||
$('.query-filters :input').serialize();
|
||||
|
||||
$.get(url).then(function (res) {
|
||||
params.success(res)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// BootstrapTable Formatter
|
||||
function userAvatarFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex justify-content-start align-items-center user-name">',
|
||||
'<div class="avatar-wrapper">',
|
||||
'<div class="avatar avatar-sm me-4">' +
|
||||
'<img src="' + row.profile_photo_url + '" alt="Avatar" class="rounded-circle">' +
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<div class="d-flex flex-column">',
|
||||
'<a href="' + show_href + '" class="text-heading text-truncate"><span class="fw-medium">' + row.name + '</span></a>',
|
||||
'<small>' + row.email + '</small>',
|
||||
'</div>',
|
||||
'</div>',
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
function uidFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex align-items-center justify-content-center">',
|
||||
'<a href="' + show_href + '" class="whitespace-nowrap" title="Ver warehouseo"> ' + row.id + '</a>',
|
||||
@can('crm.warehouses.update')
|
||||
'<a href="javascript:;" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill dropdown-toggle hide-arrow" data-bs-toggle="dropdown"><i class="ti ti-dots-vertical ti-md"></i></a>',
|
||||
'<div class="dropdown-menu dropdown-menu-end m-0">',
|
||||
'<a href="javascript:deleteRow(' + row.id + ');" class="dropdown-item delete-record">Eliminar</a>',
|
||||
'</div>',
|
||||
@endcan
|
||||
'</div>'
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
// BootstrapTable Init
|
||||
function initTable(table) {
|
||||
$(table)
|
||||
.bootstrapTable('destroy')
|
||||
.bootstrapTable({
|
||||
height: btt_height,
|
||||
locale: 'es-MX',
|
||||
ajax: "ajaxRequest",
|
||||
toolbar: "#toolbar",
|
||||
search: true,
|
||||
showColumns: true,
|
||||
showColumnsToggleAll: true,
|
||||
showExport: true,
|
||||
showFullscreen: true,
|
||||
showPaginationSwitch: true,
|
||||
showRefresh: true,
|
||||
showToggle: true,
|
||||
clickToSelect: true,
|
||||
minimumCountColumns: 4,
|
||||
fixedColumns: true,
|
||||
fixedNumber: 1,
|
||||
idField: "id",
|
||||
pagination: true,
|
||||
pageList: [10, 25, 50, 100, 500],
|
||||
sidePagination: "server",
|
||||
exportTypes: ['csv', 'txt', 'excel'],
|
||||
exportOptions: {
|
||||
fileName: 'warehouseos',
|
||||
},
|
||||
sortName: 'users.id',
|
||||
sortOrder: 'desc',
|
||||
mobileResponsive: true,
|
||||
cookie: true,
|
||||
resizable: true,
|
||||
cookieIdTable:"crm-warehouse-index",
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'UID',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
sortName: 'users.id',
|
||||
switchable: false,
|
||||
formatter: uidFormatter
|
||||
},
|
||||
|
||||
{
|
||||
field: 'name',
|
||||
title: 'Nombre',
|
||||
formatter: userAvatarFormatter,
|
||||
},
|
||||
{
|
||||
field: 'email',
|
||||
title: 'Correo electrónico',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'tipo_persona',
|
||||
title: 'Tipo persona',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.tipoPersona,
|
||||
},
|
||||
{
|
||||
field: 'rfc',
|
||||
title: 'RFC',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'nombre_fiscal',
|
||||
title: 'Nombre fiscal',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'c_regimen_fiscal',
|
||||
title: 'Regimen fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.regimenFiscal,
|
||||
},
|
||||
{
|
||||
field: 'domicilio_fiscal',
|
||||
title: 'Domicilio fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'estado',
|
||||
title: 'Estado',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'municipio',
|
||||
title: 'Municipio',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'localidad',
|
||||
title: 'Localidad',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'c_uso_cfdi',
|
||||
title: 'Uso de CFDI',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.usoCfdi,
|
||||
},
|
||||
{
|
||||
field: 'cargo',
|
||||
title: 'Cargo',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
field: 'is_prospect',
|
||||
title: 'Es prospecto',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_customer',
|
||||
title: 'Es cliente',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_provider',
|
||||
title: 'Es proveedor',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_user',
|
||||
title: 'Es usuario',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'status',
|
||||
title: 'Estado',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.status,
|
||||
},
|
||||
{
|
||||
field: 'created_at',
|
||||
title: 'Creado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'created_by_name',
|
||||
title: 'Creado por',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
sortName: 'created_by_name',
|
||||
},
|
||||
{
|
||||
field: 'updated_at',
|
||||
title: 'Modificado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
function toggleSections() {
|
||||
const isProspect = $('#is_prospect').is(':checked');
|
||||
const isCustomer = $('#is_customer').is(':checked');
|
||||
const isProvider = $('#is_provider').is(':checked');
|
||||
const isUser = $('#is_user').is(':checked');
|
||||
|
||||
$('.div-sat').toggle(isCustomer || isProvider);
|
||||
$('.div-sat-customer').toggle(isCustomer);
|
||||
$('.div-user-auth').toggle(isCustomer || isUser);
|
||||
$('.div-roles').toggle(isUser);
|
||||
}
|
||||
|
||||
function toggleCheckboxes(status) {
|
||||
const isDisabled = status == 1;
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').prop('disabled', isDisabled);
|
||||
}
|
||||
|
||||
|
||||
load_js_form = () => {
|
||||
$('#userForm .select2')
|
||||
.each(function() {
|
||||
var $this = $(this)
|
||||
|
||||
$this.wrap('<div class="position-relative"></div>')
|
||||
|
||||
$this.select2({
|
||||
dropdownAutoWidth: true,
|
||||
width: '100%',
|
||||
dropdownParent: $this.parent()
|
||||
});
|
||||
});
|
||||
|
||||
// Evento para los checkboxes
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').on('change', toggleSections);
|
||||
|
||||
// Evento para el select de estado
|
||||
$('.div-status').on('change', 'select[name="status"]', function() {
|
||||
toggleCheckboxes($(this).val());
|
||||
});
|
||||
|
||||
|
||||
// Previo de imagenes
|
||||
document.getElementById("photo").addEventListener('change', updatePreviewImage);
|
||||
|
||||
|
||||
// Reset form
|
||||
$("#userForm")
|
||||
.on('reset', function(){
|
||||
var form = $("#userForm");
|
||||
|
||||
form.validate().resetForm();
|
||||
|
||||
setTimeout(function(){
|
||||
$('#roles').trigger('change');
|
||||
|
||||
toggleSections();
|
||||
}, 250)
|
||||
|
||||
$('#user-image').prop("src", "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
|
||||
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$('.pdf-dropzone-div').show();
|
||||
|
||||
$("#pdf-dropzone").removeAllFiles(true);
|
||||
});
|
||||
|
||||
|
||||
$("#userForm")
|
||||
.validate({
|
||||
errorClass: 'error',
|
||||
highlight: function(element, errorClass, validClass) {
|
||||
// Agrega la clase de error a la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').addClass('has-error');
|
||||
},
|
||||
unhighlight: function(element, errorClass, validClass) {
|
||||
// Elimina la clase de error de la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').removeClass('has-error');
|
||||
},
|
||||
errorPlacement: function(error, element) {
|
||||
// Controla dónde se colocan los mensajes de error
|
||||
error.appendTo(element.closest('.mb-3').find('.error-message'));
|
||||
},
|
||||
rules: {
|
||||
name: {
|
||||
required: true,
|
||||
minlength: 5
|
||||
},
|
||||
email: {
|
||||
required: true,
|
||||
email: true
|
||||
},
|
||||
password: {
|
||||
required: function(element) {
|
||||
return !$("#userForm input[name=id]").val() && ($('#is_user').is(':checked') || $('#is_customer').is(':checked'));
|
||||
},
|
||||
minlength: 6
|
||||
}
|
||||
},
|
||||
messages: {
|
||||
name: {
|
||||
required: "Por favor ingrese su nombre completo",
|
||||
minlength: "El nombre completo debe tener al menos 8 caracteres"
|
||||
},
|
||||
email: {
|
||||
required: "Por favor ingrese su correo electrónico",
|
||||
email: "El valor no es una dirección de correo válida"
|
||||
},
|
||||
password: {
|
||||
required: "La contraseña es obligatoria para nuevos usuarios",
|
||||
minlength: "La contraseña debe tener al menos 6 caracteres"
|
||||
}
|
||||
},
|
||||
submitHandler: function(form, event) {
|
||||
// Evita que el formulario se envíe automáticamente
|
||||
event.preventDefault();
|
||||
|
||||
var form = $("#userForm")[0],
|
||||
data = new FormData(form);
|
||||
|
||||
$('#userForm :input').prop('disabled', true);
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$.ajax({
|
||||
url: store_route,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
||||
},
|
||||
data: data,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
cache: false,
|
||||
timeout: 3000,
|
||||
success: function(data) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
if (data.errors) {
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + data.errors + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
} else {
|
||||
let $usersIndexAlert = $('.crm-warehouse-index.alert-errors');
|
||||
|
||||
$usersIndexAlert.html('<div class="alert alert-success alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' +
|
||||
'<p class="mb-0"><strong>' + data.success + '</strong></p>' +
|
||||
'</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
$('#userForm button[type=reset]').trigger('click');
|
||||
$('#toolbar .clear-filters').trigger('click');
|
||||
}
|
||||
},
|
||||
error: function(e) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + e.responseJSON.message + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Inicializar el estado al cargar la página
|
||||
toggleSections();
|
||||
toggleCheckboxes($('select[name="status"]').val());
|
||||
}
|
||||
|
||||
// Previo de imagen de perfil
|
||||
updatePreviewImage = (event) => {
|
||||
var file = event.target.files[0],
|
||||
reader = new FileReader();
|
||||
|
||||
reader.onload = event => {
|
||||
document.getElementById('user-image').setAttribute('src', event.target.result);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
$(document).ready(function() {
|
||||
var $table = $('#bt-warehouses'),
|
||||
$btnRefresh = $('#toolbar .btn-refresh'),
|
||||
$clearFilters = $('a.clear-filters');
|
||||
|
||||
var btt_rest_height = 220,
|
||||
btt_min_height = 600;
|
||||
|
||||
btt_height = (window.innerHeight - btt_rest_height) < btt_min_height?
|
||||
btt_height:
|
||||
window.innerHeight - btt_rest_height;
|
||||
|
||||
var offcanvasElement = document.getElementById('offcanvasUser'),
|
||||
offcanvasUser = new bootstrap.Offcanvas(offcanvasElement);
|
||||
|
||||
const refreshButton = document.querySelector('.btn-refresh');
|
||||
const inputs = document.querySelectorAll('#toolbar input, #toolbar select');
|
||||
|
||||
inputs.forEach(input => {
|
||||
input.addEventListener('change', () => {
|
||||
refreshButton.disabled = false;
|
||||
refreshButton.classList.remove('btn-label-secondary');
|
||||
refreshButton.classList.add('btn-label-success');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Button Refresh
|
||||
$btnRefresh
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('refresh');
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
// Button clear filters
|
||||
$clearFilters
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('resetSearch', ''); // Inicializa la búsqueda con cadena vacía
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
|
||||
initTable('#bt-warehouses'); // Una vez que todos los scripts estén cargados, inicializa Bootstrap Table
|
||||
|
||||
|
||||
load_js_form();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -0,0 +1,516 @@
|
||||
<section id="crm-warehouse-index">
|
||||
<div class="crm-warehouse-index alert-errors"></div>
|
||||
<div wire:ignore>
|
||||
<div class="query-filters" id="toolbar">
|
||||
<div class="d-flex flex-wrap">
|
||||
<div class="pt-1 pr-2 pb-1" style="min-width: 175px; max-width: 225px">
|
||||
<button data-bs-toggle='offcanvas' data-bs-target='#offcanvasUser' class="btn btn-primary waves-effect waves-light">Agregar almacén</button>
|
||||
</div>
|
||||
<button type="button" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#accordionFiltrado" aria-expanded="false" aria-controls="accordionFiltrado">
|
||||
Filtrado
|
||||
</button>
|
||||
<div class="px-2 pt-1">
|
||||
<button class="btn btn-label-secondary waves-effect py-3 btn-refresh" disabled><i class="fa-solid fa-rotate"></i></button>
|
||||
</div>
|
||||
<div class="pr-2" style="width: 60px;">
|
||||
<a href="javascript:void(0)" class="clear-filters">Limpiar Filtrado</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table id="bt-warehouses"></table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
const store_route = '{{ route('admin.core.users.store') }}',
|
||||
route_show = '{{ route('admin.inventory.warehouse.show', ['warehouse' => '~warehouse~']) }}',
|
||||
route_destroy = '{{ route('admin.inventory.warehouse.destroy', ['warehouse' => '~warehouse~']) }}',
|
||||
statusList = {!! json_encode($status_list) !!},
|
||||
statusIntCatalogCss = {!! json_encode($status_list_class) !!};
|
||||
|
||||
var btt_height;
|
||||
|
||||
|
||||
// BootstrapTable Petición AJAX
|
||||
function ajaxRequest(params) {
|
||||
let url = '{{ url()->current() }}' +
|
||||
'?' +
|
||||
$.param(params.data) +
|
||||
'&' +
|
||||
$('.query-filters :input').serialize();
|
||||
|
||||
$.get(url).then(function (res) {
|
||||
params.success(res)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// BootstrapTable Formatter
|
||||
function userAvatarFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex justify-content-start align-items-center user-name">',
|
||||
'<div class="avatar-wrapper">',
|
||||
'<div class="avatar avatar-sm me-4">' +
|
||||
'<img src="' + row.profile_photo_url + '" alt="Avatar" class="rounded-circle">' +
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<div class="d-flex flex-column">',
|
||||
'<a href="' + show_href + '" class="text-heading text-truncate"><span class="fw-medium">' + row.name + '</span></a>',
|
||||
'<small>' + row.email + '</small>',
|
||||
'</div>',
|
||||
'</div>',
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
function uidFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex align-items-center justify-content-center">',
|
||||
'<a href="' + show_href + '" class="whitespace-nowrap" title="Ver warehouseo"> ' + row.id + '</a>',
|
||||
@can('crm.warehouses.update')
|
||||
'<a href="javascript:;" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill dropdown-toggle hide-arrow" data-bs-toggle="dropdown"><i class="ti ti-dots-vertical ti-md"></i></a>',
|
||||
'<div class="dropdown-menu dropdown-menu-end m-0">',
|
||||
'<a href="javascript:deleteRow(' + row.id + ');" class="dropdown-item delete-record">Eliminar</a>',
|
||||
'</div>',
|
||||
@endcan
|
||||
'</div>'
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
// BootstrapTable Init
|
||||
function initTable(table) {
|
||||
$(table)
|
||||
.bootstrapTable('destroy')
|
||||
.bootstrapTable({
|
||||
height: btt_height,
|
||||
locale: 'es-MX',
|
||||
ajax: "ajaxRequest",
|
||||
toolbar: "#toolbar",
|
||||
search: true,
|
||||
showColumns: true,
|
||||
showColumnsToggleAll: true,
|
||||
showExport: true,
|
||||
showFullscreen: true,
|
||||
showPaginationSwitch: true,
|
||||
showRefresh: true,
|
||||
showToggle: true,
|
||||
clickToSelect: true,
|
||||
minimumCountColumns: 4,
|
||||
fixedColumns: true,
|
||||
fixedNumber: 1,
|
||||
idField: "id",
|
||||
pagination: true,
|
||||
pageList: [10, 25, 50, 100, 500],
|
||||
sidePagination: "server",
|
||||
exportTypes: ['csv', 'txt', 'excel'],
|
||||
exportOptions: {
|
||||
fileName: 'warehouseos',
|
||||
},
|
||||
sortName: 'users.id',
|
||||
sortOrder: 'desc',
|
||||
mobileResponsive: true,
|
||||
cookie: true,
|
||||
resizable: true,
|
||||
cookieIdTable:"crm-warehouse-index",
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'UID',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
sortName: 'users.id',
|
||||
switchable: false,
|
||||
formatter: uidFormatter
|
||||
},
|
||||
|
||||
{
|
||||
field: 'name',
|
||||
title: 'Nombre',
|
||||
formatter: userAvatarFormatter,
|
||||
},
|
||||
{
|
||||
field: 'email',
|
||||
title: 'Correo electrónico',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'tipo_persona',
|
||||
title: 'Tipo persona',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.tipoPersona,
|
||||
},
|
||||
{
|
||||
field: 'rfc',
|
||||
title: 'RFC',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'nombre_fiscal',
|
||||
title: 'Nombre fiscal',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'c_regimen_fiscal',
|
||||
title: 'Regimen fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.regimenFiscal,
|
||||
},
|
||||
{
|
||||
field: 'domicilio_fiscal',
|
||||
title: 'Domicilio fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'estado',
|
||||
title: 'Estado',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'municipio',
|
||||
title: 'Municipio',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'localidad',
|
||||
title: 'Localidad',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'c_uso_cfdi',
|
||||
title: 'Uso de CFDI',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.usoCfdi,
|
||||
},
|
||||
{
|
||||
field: 'cargo',
|
||||
title: 'Cargo',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
field: 'is_prospect',
|
||||
title: 'Es prospecto',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_customer',
|
||||
title: 'Es cliente',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_provider',
|
||||
title: 'Es proveedor',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_user',
|
||||
title: 'Es usuario',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'status',
|
||||
title: 'Estado',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.status,
|
||||
},
|
||||
{
|
||||
field: 'created_at',
|
||||
title: 'Creado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'created_by_name',
|
||||
title: 'Creado por',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
sortName: 'created_by_name',
|
||||
},
|
||||
{
|
||||
field: 'updated_at',
|
||||
title: 'Modificado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
function toggleSections() {
|
||||
const isProspect = $('#is_prospect').is(':checked');
|
||||
const isCustomer = $('#is_customer').is(':checked');
|
||||
const isProvider = $('#is_provider').is(':checked');
|
||||
const isUser = $('#is_user').is(':checked');
|
||||
|
||||
$('.div-sat').toggle(isCustomer || isProvider);
|
||||
$('.div-sat-customer').toggle(isCustomer);
|
||||
$('.div-user-auth').toggle(isCustomer || isUser);
|
||||
$('.div-roles').toggle(isUser);
|
||||
}
|
||||
|
||||
function toggleCheckboxes(status) {
|
||||
const isDisabled = status == 1;
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').prop('disabled', isDisabled);
|
||||
}
|
||||
|
||||
|
||||
load_js_form = () => {
|
||||
$('#userForm .select2')
|
||||
.each(function() {
|
||||
var $this = $(this)
|
||||
|
||||
$this.wrap('<div class="position-relative"></div>')
|
||||
|
||||
$this.select2({
|
||||
dropdownAutoWidth: true,
|
||||
width: '100%',
|
||||
dropdownParent: $this.parent()
|
||||
});
|
||||
});
|
||||
|
||||
// Evento para los checkboxes
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').on('change', toggleSections);
|
||||
|
||||
// Evento para el select de estado
|
||||
$('.div-status').on('change', 'select[name="status"]', function() {
|
||||
toggleCheckboxes($(this).val());
|
||||
});
|
||||
|
||||
|
||||
// Previo de imagenes
|
||||
document.getElementById("photo").addEventListener('change', updatePreviewImage);
|
||||
|
||||
|
||||
// Reset form
|
||||
$("#userForm")
|
||||
.on('reset', function(){
|
||||
var form = $("#userForm");
|
||||
|
||||
form.validate().resetForm();
|
||||
|
||||
setTimeout(function(){
|
||||
$('#roles').trigger('change');
|
||||
|
||||
toggleSections();
|
||||
}, 250)
|
||||
|
||||
$('#user-image').prop("src", "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
|
||||
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$('.pdf-dropzone-div').show();
|
||||
|
||||
$("#pdf-dropzone").removeAllFiles(true);
|
||||
});
|
||||
|
||||
|
||||
$("#userForm")
|
||||
.validate({
|
||||
errorClass: 'error',
|
||||
highlight: function(element, errorClass, validClass) {
|
||||
// Agrega la clase de error a la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').addClass('has-error');
|
||||
},
|
||||
unhighlight: function(element, errorClass, validClass) {
|
||||
// Elimina la clase de error de la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').removeClass('has-error');
|
||||
},
|
||||
errorPlacement: function(error, element) {
|
||||
// Controla dónde se colocan los mensajes de error
|
||||
error.appendTo(element.closest('.mb-3').find('.error-message'));
|
||||
},
|
||||
rules: {
|
||||
name: {
|
||||
required: true,
|
||||
minlength: 5
|
||||
},
|
||||
email: {
|
||||
required: true,
|
||||
email: true
|
||||
},
|
||||
password: {
|
||||
required: function(element) {
|
||||
return !$("#userForm input[name=id]").val() && ($('#is_user').is(':checked') || $('#is_customer').is(':checked'));
|
||||
},
|
||||
minlength: 6
|
||||
}
|
||||
},
|
||||
messages: {
|
||||
name: {
|
||||
required: "Por favor ingrese su nombre completo",
|
||||
minlength: "El nombre completo debe tener al menos 8 caracteres"
|
||||
},
|
||||
email: {
|
||||
required: "Por favor ingrese su correo electrónico",
|
||||
email: "El valor no es una dirección de correo válida"
|
||||
},
|
||||
password: {
|
||||
required: "La contraseña es obligatoria para nuevos usuarios",
|
||||
minlength: "La contraseña debe tener al menos 6 caracteres"
|
||||
}
|
||||
},
|
||||
submitHandler: function(form, event) {
|
||||
// Evita que el formulario se envíe automáticamente
|
||||
event.preventDefault();
|
||||
|
||||
var form = $("#userForm")[0],
|
||||
data = new FormData(form);
|
||||
|
||||
$('#userForm :input').prop('disabled', true);
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$.ajax({
|
||||
url: store_route,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
||||
},
|
||||
data: data,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
cache: false,
|
||||
timeout: 3000,
|
||||
success: function(data) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
if (data.errors) {
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + data.errors + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
} else {
|
||||
let $usersIndexAlert = $('.crm-warehouse-index.alert-errors');
|
||||
|
||||
$usersIndexAlert.html('<div class="alert alert-success alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' +
|
||||
'<p class="mb-0"><strong>' + data.success + '</strong></p>' +
|
||||
'</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
$('#userForm button[type=reset]').trigger('click');
|
||||
$('#toolbar .clear-filters').trigger('click');
|
||||
}
|
||||
},
|
||||
error: function(e) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + e.responseJSON.message + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Inicializar el estado al cargar la página
|
||||
toggleSections();
|
||||
toggleCheckboxes($('select[name="status"]').val());
|
||||
}
|
||||
|
||||
// Previo de imagen de perfil
|
||||
updatePreviewImage = (event) => {
|
||||
var file = event.target.files[0],
|
||||
reader = new FileReader();
|
||||
|
||||
reader.onload = event => {
|
||||
document.getElementById('user-image').setAttribute('src', event.target.result);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
$(document).ready(function() {
|
||||
var $table = $('#bt-warehouses'),
|
||||
$btnRefresh = $('#toolbar .btn-refresh'),
|
||||
$clearFilters = $('a.clear-filters');
|
||||
|
||||
var btt_rest_height = 220,
|
||||
btt_min_height = 600;
|
||||
|
||||
btt_height = (window.innerHeight - btt_rest_height) < btt_min_height?
|
||||
btt_height:
|
||||
window.innerHeight - btt_rest_height;
|
||||
|
||||
var offcanvasElement = document.getElementById('offcanvasUser'),
|
||||
offcanvasUser = new bootstrap.Offcanvas(offcanvasElement);
|
||||
|
||||
const refreshButton = document.querySelector('.btn-refresh');
|
||||
const inputs = document.querySelectorAll('#toolbar input, #toolbar select');
|
||||
|
||||
inputs.forEach(input => {
|
||||
input.addEventListener('change', () => {
|
||||
refreshButton.disabled = false;
|
||||
refreshButton.classList.remove('btn-label-secondary');
|
||||
refreshButton.classList.add('btn-label-success');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Button Refresh
|
||||
$btnRefresh
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('refresh');
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
// Button clear filters
|
||||
$clearFilters
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('resetSearch', ''); // Inicializa la búsqueda con cadena vacía
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
|
||||
initTable('#bt-warehouses'); // Una vez que todos los scripts estén cargados, inicializa Bootstrap Table
|
||||
|
||||
|
||||
load_js_form();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -0,0 +1,516 @@
|
||||
<section id="crm-warehouse-index">
|
||||
<div class="crm-warehouse-index alert-errors"></div>
|
||||
<div wire:ignore>
|
||||
<div class="query-filters" id="toolbar">
|
||||
<div class="d-flex flex-wrap">
|
||||
<div class="pt-1 pr-2 pb-1" style="min-width: 175px; max-width: 225px">
|
||||
<button data-bs-toggle='offcanvas' data-bs-target='#offcanvasUser' class="btn btn-primary waves-effect waves-light">Agregar almacén</button>
|
||||
</div>
|
||||
<button type="button" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#accordionFiltrado" aria-expanded="false" aria-controls="accordionFiltrado">
|
||||
Filtrado
|
||||
</button>
|
||||
<div class="px-2 pt-1">
|
||||
<button class="btn btn-label-secondary waves-effect py-3 btn-refresh" disabled><i class="fa-solid fa-rotate"></i></button>
|
||||
</div>
|
||||
<div class="pr-2" style="width: 60px;">
|
||||
<a href="javascript:void(0)" class="clear-filters">Limpiar Filtrado</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table id="bt-warehouses"></table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
const store_route = '{{ route('admin.core.users.store') }}',
|
||||
route_show = '{{ route('admin.inventory.warehouse.show', ['warehouse' => '~warehouse~']) }}',
|
||||
route_destroy = '{{ route('admin.inventory.warehouse.destroy', ['warehouse' => '~warehouse~']) }}',
|
||||
statusList = {!! json_encode($status_list) !!},
|
||||
statusIntCatalogCss = {!! json_encode($status_list_class) !!};
|
||||
|
||||
var btt_height;
|
||||
|
||||
|
||||
// BootstrapTable Petición AJAX
|
||||
function ajaxRequest(params) {
|
||||
let url = '{{ url()->current() }}' +
|
||||
'?' +
|
||||
$.param(params.data) +
|
||||
'&' +
|
||||
$('.query-filters :input').serialize();
|
||||
|
||||
$.get(url).then(function (res) {
|
||||
params.success(res)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// BootstrapTable Formatter
|
||||
function userAvatarFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex justify-content-start align-items-center user-name">',
|
||||
'<div class="avatar-wrapper">',
|
||||
'<div class="avatar avatar-sm me-4">' +
|
||||
'<img src="' + row.profile_photo_url + '" alt="Avatar" class="rounded-circle">' +
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<div class="d-flex flex-column">',
|
||||
'<a href="' + show_href + '" class="text-heading text-truncate"><span class="fw-medium">' + row.name + '</span></a>',
|
||||
'<small>' + row.email + '</small>',
|
||||
'</div>',
|
||||
'</div>',
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
function uidFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex align-items-center justify-content-center">',
|
||||
'<a href="' + show_href + '" class="whitespace-nowrap" title="Ver warehouseo"> ' + row.id + '</a>',
|
||||
@can('crm.warehouses.update')
|
||||
'<a href="javascript:;" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill dropdown-toggle hide-arrow" data-bs-toggle="dropdown"><i class="ti ti-dots-vertical ti-md"></i></a>',
|
||||
'<div class="dropdown-menu dropdown-menu-end m-0">',
|
||||
'<a href="javascript:deleteRow(' + row.id + ');" class="dropdown-item delete-record">Eliminar</a>',
|
||||
'</div>',
|
||||
@endcan
|
||||
'</div>'
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
// BootstrapTable Init
|
||||
function initTable(table) {
|
||||
$(table)
|
||||
.bootstrapTable('destroy')
|
||||
.bootstrapTable({
|
||||
height: btt_height,
|
||||
locale: 'es-MX',
|
||||
ajax: "ajaxRequest",
|
||||
toolbar: "#toolbar",
|
||||
search: true,
|
||||
showColumns: true,
|
||||
showColumnsToggleAll: true,
|
||||
showExport: true,
|
||||
showFullscreen: true,
|
||||
showPaginationSwitch: true,
|
||||
showRefresh: true,
|
||||
showToggle: true,
|
||||
clickToSelect: true,
|
||||
minimumCountColumns: 4,
|
||||
fixedColumns: true,
|
||||
fixedNumber: 1,
|
||||
idField: "id",
|
||||
pagination: true,
|
||||
pageList: [10, 25, 50, 100, 500],
|
||||
sidePagination: "server",
|
||||
exportTypes: ['csv', 'txt', 'excel'],
|
||||
exportOptions: {
|
||||
fileName: 'warehouseos',
|
||||
},
|
||||
sortName: 'users.id',
|
||||
sortOrder: 'desc',
|
||||
mobileResponsive: true,
|
||||
cookie: true,
|
||||
resizable: true,
|
||||
cookieIdTable:"crm-warehouse-index",
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'UID',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
sortName: 'users.id',
|
||||
switchable: false,
|
||||
formatter: uidFormatter
|
||||
},
|
||||
|
||||
{
|
||||
field: 'name',
|
||||
title: 'Nombre',
|
||||
formatter: userAvatarFormatter,
|
||||
},
|
||||
{
|
||||
field: 'email',
|
||||
title: 'Correo electrónico',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'tipo_persona',
|
||||
title: 'Tipo persona',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.tipoPersona,
|
||||
},
|
||||
{
|
||||
field: 'rfc',
|
||||
title: 'RFC',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'nombre_fiscal',
|
||||
title: 'Nombre fiscal',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'c_regimen_fiscal',
|
||||
title: 'Regimen fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.regimenFiscal,
|
||||
},
|
||||
{
|
||||
field: 'domicilio_fiscal',
|
||||
title: 'Domicilio fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'estado',
|
||||
title: 'Estado',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'municipio',
|
||||
title: 'Municipio',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'localidad',
|
||||
title: 'Localidad',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'c_uso_cfdi',
|
||||
title: 'Uso de CFDI',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.usoCfdi,
|
||||
},
|
||||
{
|
||||
field: 'cargo',
|
||||
title: 'Cargo',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
field: 'is_prospect',
|
||||
title: 'Es prospecto',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_customer',
|
||||
title: 'Es cliente',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_provider',
|
||||
title: 'Es proveedor',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_user',
|
||||
title: 'Es usuario',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'status',
|
||||
title: 'Estado',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.status,
|
||||
},
|
||||
{
|
||||
field: 'created_at',
|
||||
title: 'Creado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'created_by_name',
|
||||
title: 'Creado por',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
sortName: 'created_by_name',
|
||||
},
|
||||
{
|
||||
field: 'updated_at',
|
||||
title: 'Modificado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
function toggleSections() {
|
||||
const isProspect = $('#is_prospect').is(':checked');
|
||||
const isCustomer = $('#is_customer').is(':checked');
|
||||
const isProvider = $('#is_provider').is(':checked');
|
||||
const isUser = $('#is_user').is(':checked');
|
||||
|
||||
$('.div-sat').toggle(isCustomer || isProvider);
|
||||
$('.div-sat-customer').toggle(isCustomer);
|
||||
$('.div-user-auth').toggle(isCustomer || isUser);
|
||||
$('.div-roles').toggle(isUser);
|
||||
}
|
||||
|
||||
function toggleCheckboxes(status) {
|
||||
const isDisabled = status == 1;
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').prop('disabled', isDisabled);
|
||||
}
|
||||
|
||||
|
||||
load_js_form = () => {
|
||||
$('#userForm .select2')
|
||||
.each(function() {
|
||||
var $this = $(this)
|
||||
|
||||
$this.wrap('<div class="position-relative"></div>')
|
||||
|
||||
$this.select2({
|
||||
dropdownAutoWidth: true,
|
||||
width: '100%',
|
||||
dropdownParent: $this.parent()
|
||||
});
|
||||
});
|
||||
|
||||
// Evento para los checkboxes
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').on('change', toggleSections);
|
||||
|
||||
// Evento para el select de estado
|
||||
$('.div-status').on('change', 'select[name="status"]', function() {
|
||||
toggleCheckboxes($(this).val());
|
||||
});
|
||||
|
||||
|
||||
// Previo de imagenes
|
||||
document.getElementById("photo").addEventListener('change', updatePreviewImage);
|
||||
|
||||
|
||||
// Reset form
|
||||
$("#userForm")
|
||||
.on('reset', function(){
|
||||
var form = $("#userForm");
|
||||
|
||||
form.validate().resetForm();
|
||||
|
||||
setTimeout(function(){
|
||||
$('#roles').trigger('change');
|
||||
|
||||
toggleSections();
|
||||
}, 250)
|
||||
|
||||
$('#user-image').prop("src", "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
|
||||
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$('.pdf-dropzone-div').show();
|
||||
|
||||
$("#pdf-dropzone").removeAllFiles(true);
|
||||
});
|
||||
|
||||
|
||||
$("#userForm")
|
||||
.validate({
|
||||
errorClass: 'error',
|
||||
highlight: function(element, errorClass, validClass) {
|
||||
// Agrega la clase de error a la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').addClass('has-error');
|
||||
},
|
||||
unhighlight: function(element, errorClass, validClass) {
|
||||
// Elimina la clase de error de la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').removeClass('has-error');
|
||||
},
|
||||
errorPlacement: function(error, element) {
|
||||
// Controla dónde se colocan los mensajes de error
|
||||
error.appendTo(element.closest('.mb-3').find('.error-message'));
|
||||
},
|
||||
rules: {
|
||||
name: {
|
||||
required: true,
|
||||
minlength: 5
|
||||
},
|
||||
email: {
|
||||
required: true,
|
||||
email: true
|
||||
},
|
||||
password: {
|
||||
required: function(element) {
|
||||
return !$("#userForm input[name=id]").val() && ($('#is_user').is(':checked') || $('#is_customer').is(':checked'));
|
||||
},
|
||||
minlength: 6
|
||||
}
|
||||
},
|
||||
messages: {
|
||||
name: {
|
||||
required: "Por favor ingrese su nombre completo",
|
||||
minlength: "El nombre completo debe tener al menos 8 caracteres"
|
||||
},
|
||||
email: {
|
||||
required: "Por favor ingrese su correo electrónico",
|
||||
email: "El valor no es una dirección de correo válida"
|
||||
},
|
||||
password: {
|
||||
required: "La contraseña es obligatoria para nuevos usuarios",
|
||||
minlength: "La contraseña debe tener al menos 6 caracteres"
|
||||
}
|
||||
},
|
||||
submitHandler: function(form, event) {
|
||||
// Evita que el formulario se envíe automáticamente
|
||||
event.preventDefault();
|
||||
|
||||
var form = $("#userForm")[0],
|
||||
data = new FormData(form);
|
||||
|
||||
$('#userForm :input').prop('disabled', true);
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$.ajax({
|
||||
url: store_route,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
||||
},
|
||||
data: data,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
cache: false,
|
||||
timeout: 3000,
|
||||
success: function(data) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
if (data.errors) {
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + data.errors + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
} else {
|
||||
let $usersIndexAlert = $('.crm-warehouse-index.alert-errors');
|
||||
|
||||
$usersIndexAlert.html('<div class="alert alert-success alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' +
|
||||
'<p class="mb-0"><strong>' + data.success + '</strong></p>' +
|
||||
'</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
$('#userForm button[type=reset]').trigger('click');
|
||||
$('#toolbar .clear-filters').trigger('click');
|
||||
}
|
||||
},
|
||||
error: function(e) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + e.responseJSON.message + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Inicializar el estado al cargar la página
|
||||
toggleSections();
|
||||
toggleCheckboxes($('select[name="status"]').val());
|
||||
}
|
||||
|
||||
// Previo de imagen de perfil
|
||||
updatePreviewImage = (event) => {
|
||||
var file = event.target.files[0],
|
||||
reader = new FileReader();
|
||||
|
||||
reader.onload = event => {
|
||||
document.getElementById('user-image').setAttribute('src', event.target.result);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
$(document).ready(function() {
|
||||
var $table = $('#bt-warehouses'),
|
||||
$btnRefresh = $('#toolbar .btn-refresh'),
|
||||
$clearFilters = $('a.clear-filters');
|
||||
|
||||
var btt_rest_height = 220,
|
||||
btt_min_height = 600;
|
||||
|
||||
btt_height = (window.innerHeight - btt_rest_height) < btt_min_height?
|
||||
btt_height:
|
||||
window.innerHeight - btt_rest_height;
|
||||
|
||||
var offcanvasElement = document.getElementById('offcanvasUser'),
|
||||
offcanvasUser = new bootstrap.Offcanvas(offcanvasElement);
|
||||
|
||||
const refreshButton = document.querySelector('.btn-refresh');
|
||||
const inputs = document.querySelectorAll('#toolbar input, #toolbar select');
|
||||
|
||||
inputs.forEach(input => {
|
||||
input.addEventListener('change', () => {
|
||||
refreshButton.disabled = false;
|
||||
refreshButton.classList.remove('btn-label-secondary');
|
||||
refreshButton.classList.add('btn-label-success');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Button Refresh
|
||||
$btnRefresh
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('refresh');
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
// Button clear filters
|
||||
$clearFilters
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('resetSearch', ''); // Inicializa la búsqueda con cadena vacía
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
|
||||
initTable('#bt-warehouses'); // Una vez que todos los scripts estén cargados, inicializa Bootstrap Table
|
||||
|
||||
|
||||
load_js_form();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -0,0 +1,516 @@
|
||||
<section id="crm-warehouse-index">
|
||||
<div class="crm-warehouse-index alert-errors"></div>
|
||||
<div wire:ignore>
|
||||
<div class="query-filters" id="toolbar">
|
||||
<div class="d-flex flex-wrap">
|
||||
<div class="pt-1 pr-2 pb-1" style="min-width: 175px; max-width: 225px">
|
||||
<button data-bs-toggle='offcanvas' data-bs-target='#offcanvasUser' class="btn btn-primary waves-effect waves-light">Agregar almacén</button>
|
||||
</div>
|
||||
<button type="button" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#accordionFiltrado" aria-expanded="false" aria-controls="accordionFiltrado">
|
||||
Filtrado
|
||||
</button>
|
||||
<div class="px-2 pt-1">
|
||||
<button class="btn btn-label-secondary waves-effect py-3 btn-refresh" disabled><i class="fa-solid fa-rotate"></i></button>
|
||||
</div>
|
||||
<div class="pr-2" style="width: 60px;">
|
||||
<a href="javascript:void(0)" class="clear-filters">Limpiar Filtrado</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table id="bt-warehouses"></table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
const store_route = '{{ route('admin.core.users.store') }}',
|
||||
route_show = '{{ route('admin.inventory.warehouse.show', ['warehouse' => '~warehouse~']) }}',
|
||||
route_destroy = '{{ route('admin.inventory.warehouse.destroy', ['warehouse' => '~warehouse~']) }}',
|
||||
statusList = {!! json_encode($status_list) !!},
|
||||
statusIntCatalogCss = {!! json_encode($status_list_class) !!};
|
||||
|
||||
var btt_height;
|
||||
|
||||
|
||||
// BootstrapTable Petición AJAX
|
||||
function ajaxRequest(params) {
|
||||
let url = '{{ url()->current() }}' +
|
||||
'?' +
|
||||
$.param(params.data) +
|
||||
'&' +
|
||||
$('.query-filters :input').serialize();
|
||||
|
||||
$.get(url).then(function (res) {
|
||||
params.success(res)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// BootstrapTable Formatter
|
||||
function userAvatarFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex justify-content-start align-items-center user-name">',
|
||||
'<div class="avatar-wrapper">',
|
||||
'<div class="avatar avatar-sm me-4">' +
|
||||
'<img src="' + row.profile_photo_url + '" alt="Avatar" class="rounded-circle">' +
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<div class="d-flex flex-column">',
|
||||
'<a href="' + show_href + '" class="text-heading text-truncate"><span class="fw-medium">' + row.name + '</span></a>',
|
||||
'<small>' + row.email + '</small>',
|
||||
'</div>',
|
||||
'</div>',
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
function uidFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex align-items-center justify-content-center">',
|
||||
'<a href="' + show_href + '" class="whitespace-nowrap" title="Ver warehouseo"> ' + row.id + '</a>',
|
||||
@can('crm.warehouses.update')
|
||||
'<a href="javascript:;" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill dropdown-toggle hide-arrow" data-bs-toggle="dropdown"><i class="ti ti-dots-vertical ti-md"></i></a>',
|
||||
'<div class="dropdown-menu dropdown-menu-end m-0">',
|
||||
'<a href="javascript:deleteRow(' + row.id + ');" class="dropdown-item delete-record">Eliminar</a>',
|
||||
'</div>',
|
||||
@endcan
|
||||
'</div>'
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
// BootstrapTable Init
|
||||
function initTable(table) {
|
||||
$(table)
|
||||
.bootstrapTable('destroy')
|
||||
.bootstrapTable({
|
||||
height: btt_height,
|
||||
locale: 'es-MX',
|
||||
ajax: "ajaxRequest",
|
||||
toolbar: "#toolbar",
|
||||
search: true,
|
||||
showColumns: true,
|
||||
showColumnsToggleAll: true,
|
||||
showExport: true,
|
||||
showFullscreen: true,
|
||||
showPaginationSwitch: true,
|
||||
showRefresh: true,
|
||||
showToggle: true,
|
||||
clickToSelect: true,
|
||||
minimumCountColumns: 4,
|
||||
fixedColumns: true,
|
||||
fixedNumber: 1,
|
||||
idField: "id",
|
||||
pagination: true,
|
||||
pageList: [10, 25, 50, 100, 500],
|
||||
sidePagination: "server",
|
||||
exportTypes: ['csv', 'txt', 'excel'],
|
||||
exportOptions: {
|
||||
fileName: 'warehouseos',
|
||||
},
|
||||
sortName: 'users.id',
|
||||
sortOrder: 'desc',
|
||||
mobileResponsive: true,
|
||||
cookie: true,
|
||||
resizable: true,
|
||||
cookieIdTable:"crm-warehouse-index",
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'UID',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
sortName: 'users.id',
|
||||
switchable: false,
|
||||
formatter: uidFormatter
|
||||
},
|
||||
|
||||
{
|
||||
field: 'name',
|
||||
title: 'Nombre',
|
||||
formatter: userAvatarFormatter,
|
||||
},
|
||||
{
|
||||
field: 'email',
|
||||
title: 'Correo electrónico',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'tipo_persona',
|
||||
title: 'Tipo persona',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.tipoPersona,
|
||||
},
|
||||
{
|
||||
field: 'rfc',
|
||||
title: 'RFC',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'nombre_fiscal',
|
||||
title: 'Nombre fiscal',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'c_regimen_fiscal',
|
||||
title: 'Regimen fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.regimenFiscal,
|
||||
},
|
||||
{
|
||||
field: 'domicilio_fiscal',
|
||||
title: 'Domicilio fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'estado',
|
||||
title: 'Estado',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'municipio',
|
||||
title: 'Municipio',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'localidad',
|
||||
title: 'Localidad',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'c_uso_cfdi',
|
||||
title: 'Uso de CFDI',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.usoCfdi,
|
||||
},
|
||||
{
|
||||
field: 'cargo',
|
||||
title: 'Cargo',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
field: 'is_prospect',
|
||||
title: 'Es prospecto',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_customer',
|
||||
title: 'Es cliente',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_provider',
|
||||
title: 'Es proveedor',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_user',
|
||||
title: 'Es usuario',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'status',
|
||||
title: 'Estado',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.status,
|
||||
},
|
||||
{
|
||||
field: 'created_at',
|
||||
title: 'Creado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'created_by_name',
|
||||
title: 'Creado por',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
sortName: 'created_by_name',
|
||||
},
|
||||
{
|
||||
field: 'updated_at',
|
||||
title: 'Modificado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
function toggleSections() {
|
||||
const isProspect = $('#is_prospect').is(':checked');
|
||||
const isCustomer = $('#is_customer').is(':checked');
|
||||
const isProvider = $('#is_provider').is(':checked');
|
||||
const isUser = $('#is_user').is(':checked');
|
||||
|
||||
$('.div-sat').toggle(isCustomer || isProvider);
|
||||
$('.div-sat-customer').toggle(isCustomer);
|
||||
$('.div-user-auth').toggle(isCustomer || isUser);
|
||||
$('.div-roles').toggle(isUser);
|
||||
}
|
||||
|
||||
function toggleCheckboxes(status) {
|
||||
const isDisabled = status == 1;
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').prop('disabled', isDisabled);
|
||||
}
|
||||
|
||||
|
||||
load_js_form = () => {
|
||||
$('#userForm .select2')
|
||||
.each(function() {
|
||||
var $this = $(this)
|
||||
|
||||
$this.wrap('<div class="position-relative"></div>')
|
||||
|
||||
$this.select2({
|
||||
dropdownAutoWidth: true,
|
||||
width: '100%',
|
||||
dropdownParent: $this.parent()
|
||||
});
|
||||
});
|
||||
|
||||
// Evento para los checkboxes
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').on('change', toggleSections);
|
||||
|
||||
// Evento para el select de estado
|
||||
$('.div-status').on('change', 'select[name="status"]', function() {
|
||||
toggleCheckboxes($(this).val());
|
||||
});
|
||||
|
||||
|
||||
// Previo de imagenes
|
||||
document.getElementById("photo").addEventListener('change', updatePreviewImage);
|
||||
|
||||
|
||||
// Reset form
|
||||
$("#userForm")
|
||||
.on('reset', function(){
|
||||
var form = $("#userForm");
|
||||
|
||||
form.validate().resetForm();
|
||||
|
||||
setTimeout(function(){
|
||||
$('#roles').trigger('change');
|
||||
|
||||
toggleSections();
|
||||
}, 250)
|
||||
|
||||
$('#user-image').prop("src", "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
|
||||
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$('.pdf-dropzone-div').show();
|
||||
|
||||
$("#pdf-dropzone").removeAllFiles(true);
|
||||
});
|
||||
|
||||
|
||||
$("#userForm")
|
||||
.validate({
|
||||
errorClass: 'error',
|
||||
highlight: function(element, errorClass, validClass) {
|
||||
// Agrega la clase de error a la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').addClass('has-error');
|
||||
},
|
||||
unhighlight: function(element, errorClass, validClass) {
|
||||
// Elimina la clase de error de la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').removeClass('has-error');
|
||||
},
|
||||
errorPlacement: function(error, element) {
|
||||
// Controla dónde se colocan los mensajes de error
|
||||
error.appendTo(element.closest('.mb-3').find('.error-message'));
|
||||
},
|
||||
rules: {
|
||||
name: {
|
||||
required: true,
|
||||
minlength: 5
|
||||
},
|
||||
email: {
|
||||
required: true,
|
||||
email: true
|
||||
},
|
||||
password: {
|
||||
required: function(element) {
|
||||
return !$("#userForm input[name=id]").val() && ($('#is_user').is(':checked') || $('#is_customer').is(':checked'));
|
||||
},
|
||||
minlength: 6
|
||||
}
|
||||
},
|
||||
messages: {
|
||||
name: {
|
||||
required: "Por favor ingrese su nombre completo",
|
||||
minlength: "El nombre completo debe tener al menos 8 caracteres"
|
||||
},
|
||||
email: {
|
||||
required: "Por favor ingrese su correo electrónico",
|
||||
email: "El valor no es una dirección de correo válida"
|
||||
},
|
||||
password: {
|
||||
required: "La contraseña es obligatoria para nuevos usuarios",
|
||||
minlength: "La contraseña debe tener al menos 6 caracteres"
|
||||
}
|
||||
},
|
||||
submitHandler: function(form, event) {
|
||||
// Evita que el formulario se envíe automáticamente
|
||||
event.preventDefault();
|
||||
|
||||
var form = $("#userForm")[0],
|
||||
data = new FormData(form);
|
||||
|
||||
$('#userForm :input').prop('disabled', true);
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$.ajax({
|
||||
url: store_route,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
||||
},
|
||||
data: data,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
cache: false,
|
||||
timeout: 3000,
|
||||
success: function(data) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
if (data.errors) {
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + data.errors + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
} else {
|
||||
let $usersIndexAlert = $('.crm-warehouse-index.alert-errors');
|
||||
|
||||
$usersIndexAlert.html('<div class="alert alert-success alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' +
|
||||
'<p class="mb-0"><strong>' + data.success + '</strong></p>' +
|
||||
'</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
$('#userForm button[type=reset]').trigger('click');
|
||||
$('#toolbar .clear-filters').trigger('click');
|
||||
}
|
||||
},
|
||||
error: function(e) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + e.responseJSON.message + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Inicializar el estado al cargar la página
|
||||
toggleSections();
|
||||
toggleCheckboxes($('select[name="status"]').val());
|
||||
}
|
||||
|
||||
// Previo de imagen de perfil
|
||||
updatePreviewImage = (event) => {
|
||||
var file = event.target.files[0],
|
||||
reader = new FileReader();
|
||||
|
||||
reader.onload = event => {
|
||||
document.getElementById('user-image').setAttribute('src', event.target.result);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
$(document).ready(function() {
|
||||
var $table = $('#bt-warehouses'),
|
||||
$btnRefresh = $('#toolbar .btn-refresh'),
|
||||
$clearFilters = $('a.clear-filters');
|
||||
|
||||
var btt_rest_height = 220,
|
||||
btt_min_height = 600;
|
||||
|
||||
btt_height = (window.innerHeight - btt_rest_height) < btt_min_height?
|
||||
btt_height:
|
||||
window.innerHeight - btt_rest_height;
|
||||
|
||||
var offcanvasElement = document.getElementById('offcanvasUser'),
|
||||
offcanvasUser = new bootstrap.Offcanvas(offcanvasElement);
|
||||
|
||||
const refreshButton = document.querySelector('.btn-refresh');
|
||||
const inputs = document.querySelectorAll('#toolbar input, #toolbar select');
|
||||
|
||||
inputs.forEach(input => {
|
||||
input.addEventListener('change', () => {
|
||||
refreshButton.disabled = false;
|
||||
refreshButton.classList.remove('btn-label-secondary');
|
||||
refreshButton.classList.add('btn-label-success');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Button Refresh
|
||||
$btnRefresh
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('refresh');
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
// Button clear filters
|
||||
$clearFilters
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('resetSearch', ''); // Inicializa la búsqueda con cadena vacía
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
|
||||
initTable('#bt-warehouses'); // Una vez que todos los scripts estén cargados, inicializa Bootstrap Table
|
||||
|
||||
|
||||
load_js_form();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
516
resources/views/livewire/products/products-index.blade.php
Normal file
516
resources/views/livewire/products/products-index.blade.php
Normal file
@ -0,0 +1,516 @@
|
||||
<section id="crm-warehouse-index">
|
||||
<div class="crm-warehouse-index alert-errors"></div>
|
||||
<div wire:ignore>
|
||||
<div class="query-filters" id="toolbar">
|
||||
<div class="d-flex flex-wrap">
|
||||
<div class="pt-1 pr-2 pb-1" style="min-width: 175px; max-width: 225px">
|
||||
<button data-bs-toggle='offcanvas' data-bs-target='#offcanvasUser' class="btn btn-primary waves-effect waves-light">Agregar almacén</button>
|
||||
</div>
|
||||
<button type="button" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#accordionFiltrado" aria-expanded="false" aria-controls="accordionFiltrado">
|
||||
Filtrado
|
||||
</button>
|
||||
<div class="px-2 pt-1">
|
||||
<button class="btn btn-label-secondary waves-effect py-3 btn-refresh" disabled><i class="fa-solid fa-rotate"></i></button>
|
||||
</div>
|
||||
<div class="pr-2" style="width: 60px;">
|
||||
<a href="javascript:void(0)" class="clear-filters">Limpiar Filtrado</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table id="bt-warehouses"></table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
const store_route = '{{ route('admin.core.users.store') }}',
|
||||
route_show = '{{ route('admin.inventory.warehouse.show', ['warehouse' => '~warehouse~']) }}',
|
||||
route_destroy = '{{ route('admin.inventory.warehouse.destroy', ['warehouse' => '~warehouse~']) }}',
|
||||
statusList = {!! json_encode($status_list) !!},
|
||||
statusIntCatalogCss = {!! json_encode($status_list_class) !!};
|
||||
|
||||
var btt_height;
|
||||
|
||||
|
||||
// BootstrapTable Petición AJAX
|
||||
function ajaxRequest(params) {
|
||||
let url = '{{ url()->current() }}' +
|
||||
'?' +
|
||||
$.param(params.data) +
|
||||
'&' +
|
||||
$('.query-filters :input').serialize();
|
||||
|
||||
$.get(url).then(function (res) {
|
||||
params.success(res)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// BootstrapTable Formatter
|
||||
function userAvatarFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex justify-content-start align-items-center user-name">',
|
||||
'<div class="avatar-wrapper">',
|
||||
'<div class="avatar avatar-sm me-4">' +
|
||||
'<img src="' + row.profile_photo_url + '" alt="Avatar" class="rounded-circle">' +
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<div class="d-flex flex-column">',
|
||||
'<a href="' + show_href + '" class="text-heading text-truncate"><span class="fw-medium">' + row.name + '</span></a>',
|
||||
'<small>' + row.email + '</small>',
|
||||
'</div>',
|
||||
'</div>',
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
function uidFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex align-items-center justify-content-center">',
|
||||
'<a href="' + show_href + '" class="whitespace-nowrap" title="Ver warehouseo"> ' + row.id + '</a>',
|
||||
@can('crm.warehouses.update')
|
||||
'<a href="javascript:;" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill dropdown-toggle hide-arrow" data-bs-toggle="dropdown"><i class="ti ti-dots-vertical ti-md"></i></a>',
|
||||
'<div class="dropdown-menu dropdown-menu-end m-0">',
|
||||
'<a href="javascript:deleteRow(' + row.id + ');" class="dropdown-item delete-record">Eliminar</a>',
|
||||
'</div>',
|
||||
@endcan
|
||||
'</div>'
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
// BootstrapTable Init
|
||||
function initTable(table) {
|
||||
$(table)
|
||||
.bootstrapTable('destroy')
|
||||
.bootstrapTable({
|
||||
height: btt_height,
|
||||
locale: 'es-MX',
|
||||
ajax: "ajaxRequest",
|
||||
toolbar: "#toolbar",
|
||||
search: true,
|
||||
showColumns: true,
|
||||
showColumnsToggleAll: true,
|
||||
showExport: true,
|
||||
showFullscreen: true,
|
||||
showPaginationSwitch: true,
|
||||
showRefresh: true,
|
||||
showToggle: true,
|
||||
clickToSelect: true,
|
||||
minimumCountColumns: 4,
|
||||
fixedColumns: true,
|
||||
fixedNumber: 1,
|
||||
idField: "id",
|
||||
pagination: true,
|
||||
pageList: [10, 25, 50, 100, 500],
|
||||
sidePagination: "server",
|
||||
exportTypes: ['csv', 'txt', 'excel'],
|
||||
exportOptions: {
|
||||
fileName: 'warehouseos',
|
||||
},
|
||||
sortName: 'users.id',
|
||||
sortOrder: 'desc',
|
||||
mobileResponsive: true,
|
||||
cookie: true,
|
||||
resizable: true,
|
||||
cookieIdTable:"crm-warehouse-index",
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'UID',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
sortName: 'users.id',
|
||||
switchable: false,
|
||||
formatter: uidFormatter
|
||||
},
|
||||
|
||||
{
|
||||
field: 'name',
|
||||
title: 'Nombre',
|
||||
formatter: userAvatarFormatter,
|
||||
},
|
||||
{
|
||||
field: 'email',
|
||||
title: 'Correo electrónico',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'tipo_persona',
|
||||
title: 'Tipo persona',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.tipoPersona,
|
||||
},
|
||||
{
|
||||
field: 'rfc',
|
||||
title: 'RFC',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'nombre_fiscal',
|
||||
title: 'Nombre fiscal',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'c_regimen_fiscal',
|
||||
title: 'Regimen fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.regimenFiscal,
|
||||
},
|
||||
{
|
||||
field: 'domicilio_fiscal',
|
||||
title: 'Domicilio fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'estado',
|
||||
title: 'Estado',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'municipio',
|
||||
title: 'Municipio',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'localidad',
|
||||
title: 'Localidad',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'c_uso_cfdi',
|
||||
title: 'Uso de CFDI',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.usoCfdi,
|
||||
},
|
||||
{
|
||||
field: 'cargo',
|
||||
title: 'Cargo',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
field: 'is_prospect',
|
||||
title: 'Es prospecto',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_customer',
|
||||
title: 'Es cliente',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_provider',
|
||||
title: 'Es proveedor',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_user',
|
||||
title: 'Es usuario',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'status',
|
||||
title: 'Estado',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.status,
|
||||
},
|
||||
{
|
||||
field: 'created_at',
|
||||
title: 'Creado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'created_by_name',
|
||||
title: 'Creado por',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
sortName: 'created_by_name',
|
||||
},
|
||||
{
|
||||
field: 'updated_at',
|
||||
title: 'Modificado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
function toggleSections() {
|
||||
const isProspect = $('#is_prospect').is(':checked');
|
||||
const isCustomer = $('#is_customer').is(':checked');
|
||||
const isProvider = $('#is_provider').is(':checked');
|
||||
const isUser = $('#is_user').is(':checked');
|
||||
|
||||
$('.div-sat').toggle(isCustomer || isProvider);
|
||||
$('.div-sat-customer').toggle(isCustomer);
|
||||
$('.div-user-auth').toggle(isCustomer || isUser);
|
||||
$('.div-roles').toggle(isUser);
|
||||
}
|
||||
|
||||
function toggleCheckboxes(status) {
|
||||
const isDisabled = status == 1;
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').prop('disabled', isDisabled);
|
||||
}
|
||||
|
||||
|
||||
load_js_form = () => {
|
||||
$('#userForm .select2')
|
||||
.each(function() {
|
||||
var $this = $(this)
|
||||
|
||||
$this.wrap('<div class="position-relative"></div>')
|
||||
|
||||
$this.select2({
|
||||
dropdownAutoWidth: true,
|
||||
width: '100%',
|
||||
dropdownParent: $this.parent()
|
||||
});
|
||||
});
|
||||
|
||||
// Evento para los checkboxes
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').on('change', toggleSections);
|
||||
|
||||
// Evento para el select de estado
|
||||
$('.div-status').on('change', 'select[name="status"]', function() {
|
||||
toggleCheckboxes($(this).val());
|
||||
});
|
||||
|
||||
|
||||
// Previo de imagenes
|
||||
document.getElementById("photo").addEventListener('change', updatePreviewImage);
|
||||
|
||||
|
||||
// Reset form
|
||||
$("#userForm")
|
||||
.on('reset', function(){
|
||||
var form = $("#userForm");
|
||||
|
||||
form.validate().resetForm();
|
||||
|
||||
setTimeout(function(){
|
||||
$('#roles').trigger('change');
|
||||
|
||||
toggleSections();
|
||||
}, 250)
|
||||
|
||||
$('#user-image').prop("src", "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
|
||||
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$('.pdf-dropzone-div').show();
|
||||
|
||||
$("#pdf-dropzone").removeAllFiles(true);
|
||||
});
|
||||
|
||||
|
||||
$("#userForm")
|
||||
.validate({
|
||||
errorClass: 'error',
|
||||
highlight: function(element, errorClass, validClass) {
|
||||
// Agrega la clase de error a la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').addClass('has-error');
|
||||
},
|
||||
unhighlight: function(element, errorClass, validClass) {
|
||||
// Elimina la clase de error de la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').removeClass('has-error');
|
||||
},
|
||||
errorPlacement: function(error, element) {
|
||||
// Controla dónde se colocan los mensajes de error
|
||||
error.appendTo(element.closest('.mb-3').find('.error-message'));
|
||||
},
|
||||
rules: {
|
||||
name: {
|
||||
required: true,
|
||||
minlength: 5
|
||||
},
|
||||
email: {
|
||||
required: true,
|
||||
email: true
|
||||
},
|
||||
password: {
|
||||
required: function(element) {
|
||||
return !$("#userForm input[name=id]").val() && ($('#is_user').is(':checked') || $('#is_customer').is(':checked'));
|
||||
},
|
||||
minlength: 6
|
||||
}
|
||||
},
|
||||
messages: {
|
||||
name: {
|
||||
required: "Por favor ingrese su nombre completo",
|
||||
minlength: "El nombre completo debe tener al menos 8 caracteres"
|
||||
},
|
||||
email: {
|
||||
required: "Por favor ingrese su correo electrónico",
|
||||
email: "El valor no es una dirección de correo válida"
|
||||
},
|
||||
password: {
|
||||
required: "La contraseña es obligatoria para nuevos usuarios",
|
||||
minlength: "La contraseña debe tener al menos 6 caracteres"
|
||||
}
|
||||
},
|
||||
submitHandler: function(form, event) {
|
||||
// Evita que el formulario se envíe automáticamente
|
||||
event.preventDefault();
|
||||
|
||||
var form = $("#userForm")[0],
|
||||
data = new FormData(form);
|
||||
|
||||
$('#userForm :input').prop('disabled', true);
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$.ajax({
|
||||
url: store_route,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
||||
},
|
||||
data: data,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
cache: false,
|
||||
timeout: 3000,
|
||||
success: function(data) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
if (data.errors) {
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + data.errors + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
} else {
|
||||
let $usersIndexAlert = $('.crm-warehouse-index.alert-errors');
|
||||
|
||||
$usersIndexAlert.html('<div class="alert alert-success alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' +
|
||||
'<p class="mb-0"><strong>' + data.success + '</strong></p>' +
|
||||
'</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
$('#userForm button[type=reset]').trigger('click');
|
||||
$('#toolbar .clear-filters').trigger('click');
|
||||
}
|
||||
},
|
||||
error: function(e) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + e.responseJSON.message + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Inicializar el estado al cargar la página
|
||||
toggleSections();
|
||||
toggleCheckboxes($('select[name="status"]').val());
|
||||
}
|
||||
|
||||
// Previo de imagen de perfil
|
||||
updatePreviewImage = (event) => {
|
||||
var file = event.target.files[0],
|
||||
reader = new FileReader();
|
||||
|
||||
reader.onload = event => {
|
||||
document.getElementById('user-image').setAttribute('src', event.target.result);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
$(document).ready(function() {
|
||||
var $table = $('#bt-warehouses'),
|
||||
$btnRefresh = $('#toolbar .btn-refresh'),
|
||||
$clearFilters = $('a.clear-filters');
|
||||
|
||||
var btt_rest_height = 220,
|
||||
btt_min_height = 600;
|
||||
|
||||
btt_height = (window.innerHeight - btt_rest_height) < btt_min_height?
|
||||
btt_height:
|
||||
window.innerHeight - btt_rest_height;
|
||||
|
||||
var offcanvasElement = document.getElementById('offcanvasUser'),
|
||||
offcanvasUser = new bootstrap.Offcanvas(offcanvasElement);
|
||||
|
||||
const refreshButton = document.querySelector('.btn-refresh');
|
||||
const inputs = document.querySelectorAll('#toolbar input, #toolbar select');
|
||||
|
||||
inputs.forEach(input => {
|
||||
input.addEventListener('change', () => {
|
||||
refreshButton.disabled = false;
|
||||
refreshButton.classList.remove('btn-label-secondary');
|
||||
refreshButton.classList.add('btn-label-success');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Button Refresh
|
||||
$btnRefresh
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('refresh');
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
// Button clear filters
|
||||
$clearFilters
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('resetSearch', ''); // Inicializa la búsqueda con cadena vacía
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
|
||||
initTable('#bt-warehouses'); // Una vez que todos los scripts estén cargados, inicializa Bootstrap Table
|
||||
|
||||
|
||||
load_js_form();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -0,0 +1,516 @@
|
||||
<section id="crm-warehouse-index">
|
||||
<div class="crm-warehouse-index alert-errors"></div>
|
||||
<div wire:ignore>
|
||||
<div class="query-filters" id="toolbar">
|
||||
<div class="d-flex flex-wrap">
|
||||
<div class="pt-1 pr-2 pb-1" style="min-width: 175px; max-width: 225px">
|
||||
<button data-bs-toggle='offcanvas' data-bs-target='#offcanvasUser' class="btn btn-primary waves-effect waves-light">Agregar almacén</button>
|
||||
</div>
|
||||
<button type="button" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#accordionFiltrado" aria-expanded="false" aria-controls="accordionFiltrado">
|
||||
Filtrado
|
||||
</button>
|
||||
<div class="px-2 pt-1">
|
||||
<button class="btn btn-label-secondary waves-effect py-3 btn-refresh" disabled><i class="fa-solid fa-rotate"></i></button>
|
||||
</div>
|
||||
<div class="pr-2" style="width: 60px;">
|
||||
<a href="javascript:void(0)" class="clear-filters">Limpiar Filtrado</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table id="bt-warehouses"></table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
const store_route = '{{ route('admin.core.users.store') }}',
|
||||
route_show = '{{ route('admin.inventory.warehouse.show', ['warehouse' => '~warehouse~']) }}',
|
||||
route_destroy = '{{ route('admin.inventory.warehouse.destroy', ['warehouse' => '~warehouse~']) }}',
|
||||
statusList = {!! json_encode($status_list) !!},
|
||||
statusIntCatalogCss = {!! json_encode($status_list_class) !!};
|
||||
|
||||
var btt_height;
|
||||
|
||||
|
||||
// BootstrapTable Petición AJAX
|
||||
function ajaxRequest(params) {
|
||||
let url = '{{ url()->current() }}' +
|
||||
'?' +
|
||||
$.param(params.data) +
|
||||
'&' +
|
||||
$('.query-filters :input').serialize();
|
||||
|
||||
$.get(url).then(function (res) {
|
||||
params.success(res)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// BootstrapTable Formatter
|
||||
function userAvatarFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex justify-content-start align-items-center user-name">',
|
||||
'<div class="avatar-wrapper">',
|
||||
'<div class="avatar avatar-sm me-4">' +
|
||||
'<img src="' + row.profile_photo_url + '" alt="Avatar" class="rounded-circle">' +
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<div class="d-flex flex-column">',
|
||||
'<a href="' + show_href + '" class="text-heading text-truncate"><span class="fw-medium">' + row.name + '</span></a>',
|
||||
'<small>' + row.email + '</small>',
|
||||
'</div>',
|
||||
'</div>',
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
function uidFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex align-items-center justify-content-center">',
|
||||
'<a href="' + show_href + '" class="whitespace-nowrap" title="Ver warehouseo"> ' + row.id + '</a>',
|
||||
@can('crm.warehouses.update')
|
||||
'<a href="javascript:;" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill dropdown-toggle hide-arrow" data-bs-toggle="dropdown"><i class="ti ti-dots-vertical ti-md"></i></a>',
|
||||
'<div class="dropdown-menu dropdown-menu-end m-0">',
|
||||
'<a href="javascript:deleteRow(' + row.id + ');" class="dropdown-item delete-record">Eliminar</a>',
|
||||
'</div>',
|
||||
@endcan
|
||||
'</div>'
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
// BootstrapTable Init
|
||||
function initTable(table) {
|
||||
$(table)
|
||||
.bootstrapTable('destroy')
|
||||
.bootstrapTable({
|
||||
height: btt_height,
|
||||
locale: 'es-MX',
|
||||
ajax: "ajaxRequest",
|
||||
toolbar: "#toolbar",
|
||||
search: true,
|
||||
showColumns: true,
|
||||
showColumnsToggleAll: true,
|
||||
showExport: true,
|
||||
showFullscreen: true,
|
||||
showPaginationSwitch: true,
|
||||
showRefresh: true,
|
||||
showToggle: true,
|
||||
clickToSelect: true,
|
||||
minimumCountColumns: 4,
|
||||
fixedColumns: true,
|
||||
fixedNumber: 1,
|
||||
idField: "id",
|
||||
pagination: true,
|
||||
pageList: [10, 25, 50, 100, 500],
|
||||
sidePagination: "server",
|
||||
exportTypes: ['csv', 'txt', 'excel'],
|
||||
exportOptions: {
|
||||
fileName: 'warehouseos',
|
||||
},
|
||||
sortName: 'users.id',
|
||||
sortOrder: 'desc',
|
||||
mobileResponsive: true,
|
||||
cookie: true,
|
||||
resizable: true,
|
||||
cookieIdTable:"crm-warehouse-index",
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'UID',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
sortName: 'users.id',
|
||||
switchable: false,
|
||||
formatter: uidFormatter
|
||||
},
|
||||
|
||||
{
|
||||
field: 'name',
|
||||
title: 'Nombre',
|
||||
formatter: userAvatarFormatter,
|
||||
},
|
||||
{
|
||||
field: 'email',
|
||||
title: 'Correo electrónico',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'tipo_persona',
|
||||
title: 'Tipo persona',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.tipoPersona,
|
||||
},
|
||||
{
|
||||
field: 'rfc',
|
||||
title: 'RFC',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'nombre_fiscal',
|
||||
title: 'Nombre fiscal',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'c_regimen_fiscal',
|
||||
title: 'Regimen fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.regimenFiscal,
|
||||
},
|
||||
{
|
||||
field: 'domicilio_fiscal',
|
||||
title: 'Domicilio fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'estado',
|
||||
title: 'Estado',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'municipio',
|
||||
title: 'Municipio',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'localidad',
|
||||
title: 'Localidad',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'c_uso_cfdi',
|
||||
title: 'Uso de CFDI',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.usoCfdi,
|
||||
},
|
||||
{
|
||||
field: 'cargo',
|
||||
title: 'Cargo',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
field: 'is_prospect',
|
||||
title: 'Es prospecto',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_customer',
|
||||
title: 'Es cliente',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_provider',
|
||||
title: 'Es proveedor',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_user',
|
||||
title: 'Es usuario',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'status',
|
||||
title: 'Estado',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.status,
|
||||
},
|
||||
{
|
||||
field: 'created_at',
|
||||
title: 'Creado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'created_by_name',
|
||||
title: 'Creado por',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
sortName: 'created_by_name',
|
||||
},
|
||||
{
|
||||
field: 'updated_at',
|
||||
title: 'Modificado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
function toggleSections() {
|
||||
const isProspect = $('#is_prospect').is(':checked');
|
||||
const isCustomer = $('#is_customer').is(':checked');
|
||||
const isProvider = $('#is_provider').is(':checked');
|
||||
const isUser = $('#is_user').is(':checked');
|
||||
|
||||
$('.div-sat').toggle(isCustomer || isProvider);
|
||||
$('.div-sat-customer').toggle(isCustomer);
|
||||
$('.div-user-auth').toggle(isCustomer || isUser);
|
||||
$('.div-roles').toggle(isUser);
|
||||
}
|
||||
|
||||
function toggleCheckboxes(status) {
|
||||
const isDisabled = status == 1;
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').prop('disabled', isDisabled);
|
||||
}
|
||||
|
||||
|
||||
load_js_form = () => {
|
||||
$('#userForm .select2')
|
||||
.each(function() {
|
||||
var $this = $(this)
|
||||
|
||||
$this.wrap('<div class="position-relative"></div>')
|
||||
|
||||
$this.select2({
|
||||
dropdownAutoWidth: true,
|
||||
width: '100%',
|
||||
dropdownParent: $this.parent()
|
||||
});
|
||||
});
|
||||
|
||||
// Evento para los checkboxes
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').on('change', toggleSections);
|
||||
|
||||
// Evento para el select de estado
|
||||
$('.div-status').on('change', 'select[name="status"]', function() {
|
||||
toggleCheckboxes($(this).val());
|
||||
});
|
||||
|
||||
|
||||
// Previo de imagenes
|
||||
document.getElementById("photo").addEventListener('change', updatePreviewImage);
|
||||
|
||||
|
||||
// Reset form
|
||||
$("#userForm")
|
||||
.on('reset', function(){
|
||||
var form = $("#userForm");
|
||||
|
||||
form.validate().resetForm();
|
||||
|
||||
setTimeout(function(){
|
||||
$('#roles').trigger('change');
|
||||
|
||||
toggleSections();
|
||||
}, 250)
|
||||
|
||||
$('#user-image').prop("src", "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
|
||||
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$('.pdf-dropzone-div').show();
|
||||
|
||||
$("#pdf-dropzone").removeAllFiles(true);
|
||||
});
|
||||
|
||||
|
||||
$("#userForm")
|
||||
.validate({
|
||||
errorClass: 'error',
|
||||
highlight: function(element, errorClass, validClass) {
|
||||
// Agrega la clase de error a la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').addClass('has-error');
|
||||
},
|
||||
unhighlight: function(element, errorClass, validClass) {
|
||||
// Elimina la clase de error de la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').removeClass('has-error');
|
||||
},
|
||||
errorPlacement: function(error, element) {
|
||||
// Controla dónde se colocan los mensajes de error
|
||||
error.appendTo(element.closest('.mb-3').find('.error-message'));
|
||||
},
|
||||
rules: {
|
||||
name: {
|
||||
required: true,
|
||||
minlength: 5
|
||||
},
|
||||
email: {
|
||||
required: true,
|
||||
email: true
|
||||
},
|
||||
password: {
|
||||
required: function(element) {
|
||||
return !$("#userForm input[name=id]").val() && ($('#is_user').is(':checked') || $('#is_customer').is(':checked'));
|
||||
},
|
||||
minlength: 6
|
||||
}
|
||||
},
|
||||
messages: {
|
||||
name: {
|
||||
required: "Por favor ingrese su nombre completo",
|
||||
minlength: "El nombre completo debe tener al menos 8 caracteres"
|
||||
},
|
||||
email: {
|
||||
required: "Por favor ingrese su correo electrónico",
|
||||
email: "El valor no es una dirección de correo válida"
|
||||
},
|
||||
password: {
|
||||
required: "La contraseña es obligatoria para nuevos usuarios",
|
||||
minlength: "La contraseña debe tener al menos 6 caracteres"
|
||||
}
|
||||
},
|
||||
submitHandler: function(form, event) {
|
||||
// Evita que el formulario se envíe automáticamente
|
||||
event.preventDefault();
|
||||
|
||||
var form = $("#userForm")[0],
|
||||
data = new FormData(form);
|
||||
|
||||
$('#userForm :input').prop('disabled', true);
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$.ajax({
|
||||
url: store_route,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
||||
},
|
||||
data: data,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
cache: false,
|
||||
timeout: 3000,
|
||||
success: function(data) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
if (data.errors) {
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + data.errors + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
} else {
|
||||
let $usersIndexAlert = $('.crm-warehouse-index.alert-errors');
|
||||
|
||||
$usersIndexAlert.html('<div class="alert alert-success alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' +
|
||||
'<p class="mb-0"><strong>' + data.success + '</strong></p>' +
|
||||
'</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
$('#userForm button[type=reset]').trigger('click');
|
||||
$('#toolbar .clear-filters').trigger('click');
|
||||
}
|
||||
},
|
||||
error: function(e) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + e.responseJSON.message + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Inicializar el estado al cargar la página
|
||||
toggleSections();
|
||||
toggleCheckboxes($('select[name="status"]').val());
|
||||
}
|
||||
|
||||
// Previo de imagen de perfil
|
||||
updatePreviewImage = (event) => {
|
||||
var file = event.target.files[0],
|
||||
reader = new FileReader();
|
||||
|
||||
reader.onload = event => {
|
||||
document.getElementById('user-image').setAttribute('src', event.target.result);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
$(document).ready(function() {
|
||||
var $table = $('#bt-warehouses'),
|
||||
$btnRefresh = $('#toolbar .btn-refresh'),
|
||||
$clearFilters = $('a.clear-filters');
|
||||
|
||||
var btt_rest_height = 220,
|
||||
btt_min_height = 600;
|
||||
|
||||
btt_height = (window.innerHeight - btt_rest_height) < btt_min_height?
|
||||
btt_height:
|
||||
window.innerHeight - btt_rest_height;
|
||||
|
||||
var offcanvasElement = document.getElementById('offcanvasUser'),
|
||||
offcanvasUser = new bootstrap.Offcanvas(offcanvasElement);
|
||||
|
||||
const refreshButton = document.querySelector('.btn-refresh');
|
||||
const inputs = document.querySelectorAll('#toolbar input, #toolbar select');
|
||||
|
||||
inputs.forEach(input => {
|
||||
input.addEventListener('change', () => {
|
||||
refreshButton.disabled = false;
|
||||
refreshButton.classList.remove('btn-label-secondary');
|
||||
refreshButton.classList.add('btn-label-success');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Button Refresh
|
||||
$btnRefresh
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('refresh');
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
// Button clear filters
|
||||
$clearFilters
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('resetSearch', ''); // Inicializa la búsqueda con cadena vacía
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
|
||||
initTable('#bt-warehouses'); // Una vez que todos los scripts estén cargados, inicializa Bootstrap Table
|
||||
|
||||
|
||||
load_js_form();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
@ -0,0 +1,516 @@
|
||||
<section id="crm-warehouse-index">
|
||||
<div class="crm-warehouse-index alert-errors"></div>
|
||||
<div wire:ignore>
|
||||
<div class="query-filters" id="toolbar">
|
||||
<div class="d-flex flex-wrap">
|
||||
<div class="pt-1 pr-2 pb-1" style="min-width: 175px; max-width: 225px">
|
||||
<button data-bs-toggle='offcanvas' data-bs-target='#offcanvasUser' class="btn btn-primary waves-effect waves-light">Agregar almacén</button>
|
||||
</div>
|
||||
<button type="button" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#accordionFiltrado" aria-expanded="false" aria-controls="accordionFiltrado">
|
||||
Filtrado
|
||||
</button>
|
||||
<div class="px-2 pt-1">
|
||||
<button class="btn btn-label-secondary waves-effect py-3 btn-refresh" disabled><i class="fa-solid fa-rotate"></i></button>
|
||||
</div>
|
||||
<div class="pr-2" style="width: 60px;">
|
||||
<a href="javascript:void(0)" class="clear-filters">Limpiar Filtrado</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<table id="bt-warehouses"></table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
const store_route = '{{ route('admin.core.users.store') }}',
|
||||
route_show = '{{ route('admin.inventory.warehouse.show', ['warehouse' => '~warehouse~']) }}',
|
||||
route_destroy = '{{ route('admin.inventory.warehouse.destroy', ['warehouse' => '~warehouse~']) }}',
|
||||
statusList = {!! json_encode($status_list) !!},
|
||||
statusIntCatalogCss = {!! json_encode($status_list_class) !!};
|
||||
|
||||
var btt_height;
|
||||
|
||||
|
||||
// BootstrapTable Petición AJAX
|
||||
function ajaxRequest(params) {
|
||||
let url = '{{ url()->current() }}' +
|
||||
'?' +
|
||||
$.param(params.data) +
|
||||
'&' +
|
||||
$('.query-filters :input').serialize();
|
||||
|
||||
$.get(url).then(function (res) {
|
||||
params.success(res)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// BootstrapTable Formatter
|
||||
function userAvatarFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex justify-content-start align-items-center user-name">',
|
||||
'<div class="avatar-wrapper">',
|
||||
'<div class="avatar avatar-sm me-4">' +
|
||||
'<img src="' + row.profile_photo_url + '" alt="Avatar" class="rounded-circle">' +
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<div class="d-flex flex-column">',
|
||||
'<a href="' + show_href + '" class="text-heading text-truncate"><span class="fw-medium">' + row.name + '</span></a>',
|
||||
'<small>' + row.email + '</small>',
|
||||
'</div>',
|
||||
'</div>',
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
function uidFormatter(value, row, index) {
|
||||
if(row.id){
|
||||
let show_href = route_show.replace('~warehouseo~', row.id);
|
||||
|
||||
return [
|
||||
'<div class="d-flex align-items-center justify-content-center">',
|
||||
'<a href="' + show_href + '" class="whitespace-nowrap" title="Ver warehouseo"> ' + row.id + '</a>',
|
||||
@can('crm.warehouses.update')
|
||||
'<a href="javascript:;" class="btn btn-icon btn-text-secondary waves-effect waves-light rounded-pill dropdown-toggle hide-arrow" data-bs-toggle="dropdown"><i class="ti ti-dots-vertical ti-md"></i></a>',
|
||||
'<div class="dropdown-menu dropdown-menu-end m-0">',
|
||||
'<a href="javascript:deleteRow(' + row.id + ');" class="dropdown-item delete-record">Eliminar</a>',
|
||||
'</div>',
|
||||
@endcan
|
||||
'</div>'
|
||||
].join('')
|
||||
}
|
||||
}
|
||||
|
||||
// BootstrapTable Init
|
||||
function initTable(table) {
|
||||
$(table)
|
||||
.bootstrapTable('destroy')
|
||||
.bootstrapTable({
|
||||
height: btt_height,
|
||||
locale: 'es-MX',
|
||||
ajax: "ajaxRequest",
|
||||
toolbar: "#toolbar",
|
||||
search: true,
|
||||
showColumns: true,
|
||||
showColumnsToggleAll: true,
|
||||
showExport: true,
|
||||
showFullscreen: true,
|
||||
showPaginationSwitch: true,
|
||||
showRefresh: true,
|
||||
showToggle: true,
|
||||
clickToSelect: true,
|
||||
minimumCountColumns: 4,
|
||||
fixedColumns: true,
|
||||
fixedNumber: 1,
|
||||
idField: "id",
|
||||
pagination: true,
|
||||
pageList: [10, 25, 50, 100, 500],
|
||||
sidePagination: "server",
|
||||
exportTypes: ['csv', 'txt', 'excel'],
|
||||
exportOptions: {
|
||||
fileName: 'warehouseos',
|
||||
},
|
||||
sortName: 'users.id',
|
||||
sortOrder: 'desc',
|
||||
mobileResponsive: true,
|
||||
cookie: true,
|
||||
resizable: true,
|
||||
cookieIdTable:"crm-warehouse-index",
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'UID',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
sortName: 'users.id',
|
||||
switchable: false,
|
||||
formatter: uidFormatter
|
||||
},
|
||||
|
||||
{
|
||||
field: 'name',
|
||||
title: 'Nombre',
|
||||
formatter: userAvatarFormatter,
|
||||
},
|
||||
{
|
||||
field: 'email',
|
||||
title: 'Correo electrónico',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'tipo_persona',
|
||||
title: 'Tipo persona',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.tipoPersona,
|
||||
},
|
||||
{
|
||||
field: 'rfc',
|
||||
title: 'RFC',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'nombre_fiscal',
|
||||
title: 'Nombre fiscal',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'c_regimen_fiscal',
|
||||
title: 'Regimen fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.regimenFiscal,
|
||||
},
|
||||
{
|
||||
field: 'domicilio_fiscal',
|
||||
title: 'Domicilio fiscal',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'estado',
|
||||
title: 'Estado',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'municipio',
|
||||
title: 'Municipio',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'localidad',
|
||||
title: 'Localidad',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'c_uso_cfdi',
|
||||
title: 'Uso de CFDI',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
formatter: window.btFormatter.usoCfdi,
|
||||
},
|
||||
{
|
||||
field: 'cargo',
|
||||
title: 'Cargo',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
field: 'is_prospect',
|
||||
title: 'Es prospecto',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_customer',
|
||||
title: 'Es cliente',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_provider',
|
||||
title: 'Es proveedor',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
{
|
||||
field: 'is_user',
|
||||
title: 'Es usuario',
|
||||
align: 'center',
|
||||
visible: false,
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.check,
|
||||
},
|
||||
|
||||
{
|
||||
field: 'status',
|
||||
title: 'Estado',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
formatter: window.btFormatter.status,
|
||||
},
|
||||
{
|
||||
field: 'created_at',
|
||||
title: 'Creado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
field: 'created_by_name',
|
||||
title: 'Creado por',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
sortName: 'created_by_name',
|
||||
},
|
||||
{
|
||||
field: 'updated_at',
|
||||
title: 'Modificado ',
|
||||
align: 'center',
|
||||
sortable: true,
|
||||
visible: false,
|
||||
},
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
function toggleSections() {
|
||||
const isProspect = $('#is_prospect').is(':checked');
|
||||
const isCustomer = $('#is_customer').is(':checked');
|
||||
const isProvider = $('#is_provider').is(':checked');
|
||||
const isUser = $('#is_user').is(':checked');
|
||||
|
||||
$('.div-sat').toggle(isCustomer || isProvider);
|
||||
$('.div-sat-customer').toggle(isCustomer);
|
||||
$('.div-user-auth').toggle(isCustomer || isUser);
|
||||
$('.div-roles').toggle(isUser);
|
||||
}
|
||||
|
||||
function toggleCheckboxes(status) {
|
||||
const isDisabled = status == 1;
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').prop('disabled', isDisabled);
|
||||
}
|
||||
|
||||
|
||||
load_js_form = () => {
|
||||
$('#userForm .select2')
|
||||
.each(function() {
|
||||
var $this = $(this)
|
||||
|
||||
$this.wrap('<div class="position-relative"></div>')
|
||||
|
||||
$this.select2({
|
||||
dropdownAutoWidth: true,
|
||||
width: '100%',
|
||||
dropdownParent: $this.parent()
|
||||
});
|
||||
});
|
||||
|
||||
// Evento para los checkboxes
|
||||
$('#is_prospect, #is_customer, #is_provider, #is_user').on('change', toggleSections);
|
||||
|
||||
// Evento para el select de estado
|
||||
$('.div-status').on('change', 'select[name="status"]', function() {
|
||||
toggleCheckboxes($(this).val());
|
||||
});
|
||||
|
||||
|
||||
// Previo de imagenes
|
||||
document.getElementById("photo").addEventListener('change', updatePreviewImage);
|
||||
|
||||
|
||||
// Reset form
|
||||
$("#userForm")
|
||||
.on('reset', function(){
|
||||
var form = $("#userForm");
|
||||
|
||||
form.validate().resetForm();
|
||||
|
||||
setTimeout(function(){
|
||||
$('#roles').trigger('change');
|
||||
|
||||
toggleSections();
|
||||
}, 250)
|
||||
|
||||
$('#user-image').prop("src", "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
|
||||
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$('.pdf-dropzone-div').show();
|
||||
|
||||
$("#pdf-dropzone").removeAllFiles(true);
|
||||
});
|
||||
|
||||
|
||||
$("#userForm")
|
||||
.validate({
|
||||
errorClass: 'error',
|
||||
highlight: function(element, errorClass, validClass) {
|
||||
// Agrega la clase de error a la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').addClass('has-error');
|
||||
},
|
||||
unhighlight: function(element, errorClass, validClass) {
|
||||
// Elimina la clase de error de la fila (contenedor del campo)
|
||||
$(element).closest('.mb-3').removeClass('has-error');
|
||||
},
|
||||
errorPlacement: function(error, element) {
|
||||
// Controla dónde se colocan los mensajes de error
|
||||
error.appendTo(element.closest('.mb-3').find('.error-message'));
|
||||
},
|
||||
rules: {
|
||||
name: {
|
||||
required: true,
|
||||
minlength: 5
|
||||
},
|
||||
email: {
|
||||
required: true,
|
||||
email: true
|
||||
},
|
||||
password: {
|
||||
required: function(element) {
|
||||
return !$("#userForm input[name=id]").val() && ($('#is_user').is(':checked') || $('#is_customer').is(':checked'));
|
||||
},
|
||||
minlength: 6
|
||||
}
|
||||
},
|
||||
messages: {
|
||||
name: {
|
||||
required: "Por favor ingrese su nombre completo",
|
||||
minlength: "El nombre completo debe tener al menos 8 caracteres"
|
||||
},
|
||||
email: {
|
||||
required: "Por favor ingrese su correo electrónico",
|
||||
email: "El valor no es una dirección de correo válida"
|
||||
},
|
||||
password: {
|
||||
required: "La contraseña es obligatoria para nuevos usuarios",
|
||||
minlength: "La contraseña debe tener al menos 6 caracteres"
|
||||
}
|
||||
},
|
||||
submitHandler: function(form, event) {
|
||||
// Evita que el formulario se envíe automáticamente
|
||||
event.preventDefault();
|
||||
|
||||
var form = $("#userForm")[0],
|
||||
data = new FormData(form);
|
||||
|
||||
$('#userForm :input').prop('disabled', true);
|
||||
$('#userForm .alert-errors').html('');
|
||||
|
||||
$.ajax({
|
||||
url: store_route,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
||||
},
|
||||
data: data,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
cache: false,
|
||||
timeout: 3000,
|
||||
success: function(data) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
if (data.errors) {
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + data.errors + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
} else {
|
||||
let $usersIndexAlert = $('.crm-warehouse-index.alert-errors');
|
||||
|
||||
$usersIndexAlert.html('<div class="alert alert-success alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' +
|
||||
'<p class="mb-0"><strong>' + data.success + '</strong></p>' +
|
||||
'</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
|
||||
$('#userForm button[type=reset]').trigger('click');
|
||||
$('#toolbar .clear-filters').trigger('click');
|
||||
}
|
||||
},
|
||||
error: function(e) {
|
||||
$('#userForm :input').prop('disabled', false);
|
||||
|
||||
$('#userForm .alert-errors').html('<div class="alert alert-danger alert-dismissible fade show" role="alert">' +
|
||||
'<div class="alert-body">' + e.responseJSON.message + '</div>' +
|
||||
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>' +
|
||||
'</div>');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Inicializar el estado al cargar la página
|
||||
toggleSections();
|
||||
toggleCheckboxes($('select[name="status"]').val());
|
||||
}
|
||||
|
||||
// Previo de imagen de perfil
|
||||
updatePreviewImage = (event) => {
|
||||
var file = event.target.files[0],
|
||||
reader = new FileReader();
|
||||
|
||||
reader.onload = event => {
|
||||
document.getElementById('user-image').setAttribute('src', event.target.result);
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
$(document).ready(function() {
|
||||
var $table = $('#bt-warehouses'),
|
||||
$btnRefresh = $('#toolbar .btn-refresh'),
|
||||
$clearFilters = $('a.clear-filters');
|
||||
|
||||
var btt_rest_height = 220,
|
||||
btt_min_height = 600;
|
||||
|
||||
btt_height = (window.innerHeight - btt_rest_height) < btt_min_height?
|
||||
btt_height:
|
||||
window.innerHeight - btt_rest_height;
|
||||
|
||||
var offcanvasElement = document.getElementById('offcanvasUser'),
|
||||
offcanvasUser = new bootstrap.Offcanvas(offcanvasElement);
|
||||
|
||||
const refreshButton = document.querySelector('.btn-refresh');
|
||||
const inputs = document.querySelectorAll('#toolbar input, #toolbar select');
|
||||
|
||||
inputs.forEach(input => {
|
||||
input.addEventListener('change', () => {
|
||||
refreshButton.disabled = false;
|
||||
refreshButton.classList.remove('btn-label-secondary');
|
||||
refreshButton.classList.add('btn-label-success');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Button Refresh
|
||||
$btnRefresh
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('refresh');
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
// Button clear filters
|
||||
$clearFilters
|
||||
.on('click', () => {
|
||||
$table.bootstrapTable('resetSearch', ''); // Inicializa la búsqueda con cadena vacía
|
||||
refreshButton.disabled = true;
|
||||
refreshButton.classList.remove('btn-label-success');
|
||||
refreshButton.classList.add('btn-label-secondary');
|
||||
});
|
||||
|
||||
|
||||
initTable('#bt-warehouses'); // Una vez que todos los scripts estén cargados, inicializa Bootstrap Table
|
||||
|
||||
|
||||
load_js_form();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
132
resources/views/livewire/warehouses/form-offcanvas.blade.php
Normal file
132
resources/views/livewire/warehouses/form-offcanvas.blade.php
Normal file
@ -0,0 +1,132 @@
|
||||
<div>
|
||||
<x-vuexy-admin::offcanvas.basic :id="$offcanvasId" :tag-name="$tagName">
|
||||
<x-vuexy-admin::form :id="$formId" :mode="$mode" wireSubmit="onSubmit">
|
||||
<x-slot name="actions">
|
||||
<x-vuexy-admin::button.offcanvas-buttons :mode="$mode" :tagName="$tagName" />
|
||||
</x-slot>
|
||||
{{-- Selección de Sucursal --}}
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="store_id" label="Sucursal" placeholder="Selecciona una sucursal" :options="$store_options" />
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="work_center_id" label="Área de trabajo" placeholder="Selecciona el área de trabajo" :options="$work_center_options" />
|
||||
|
||||
{{-- Identificación y Configuración --}}
|
||||
<div class="row">
|
||||
<x-vuexy-admin::form.select :uid="$uniqueId" model="manager_id" label="Gerente" placeholder="Selecciona el gerente" :options="$manager_options" class="select2 form-select" />
|
||||
</div>
|
||||
{{-- Código y Prioridad --}}
|
||||
<hr>
|
||||
<div class="row">
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="code" label="Código de almacén" icon="ti ti-tag" parentClass="col-md-8" autocomplete="off"/>
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="priority" label="Prioridad" type="number" max="99" parentClass="col-md-4" class="text-center" />
|
||||
</div>
|
||||
{{-- Detalles del Almacén --}}
|
||||
<x-vuexy-admin::form.input :uid="$uniqueId" model="name" label="Nombre del almacén" />
|
||||
<x-vuexy-admin::form.textarea :uid="$uniqueId" model="description" label="Descripción" placeholder="Ingresa una breve descripción del almacén" helperText="Describe el propósito y características del almacén." />
|
||||
{{-- Información de Contacto --}}
|
||||
<hr>
|
||||
<div class="row">
|
||||
<x-vuexy-admin::form.input type="tel" :uid="$uniqueId" model="tel" label="Teléfono" icon="ti ti-phone" phoneMode="national" />
|
||||
<x-vuexy-admin::form.input type="tel" :uid="$uniqueId" model="tel2" label="Teléfono 2" icon="ti ti-phone" phoneMode="national" />
|
||||
</div>
|
||||
{{-- Configuración Adicional --}}
|
||||
<hr>
|
||||
<x-vuexy-admin::form.checkbox :uid="$uniqueId" wire:model="status" label="Activo" switch switchType="square" size="lg" color="success" />
|
||||
</x-vuexy-admin::form>
|
||||
</x-vuexy-admin::offcanvas.basic>
|
||||
</div>
|
||||
|
||||
@push('page-script')
|
||||
<script>
|
||||
const csrf_token = "{{ csrf_token() }}";
|
||||
|
||||
const initializeContactForm = () => {
|
||||
// Inicializar Select2 sin jQuery
|
||||
const initializeSelect2 = () => {
|
||||
$("#manager_id_{{ $uniqueId }}")
|
||||
.select2({
|
||||
dropdownAutoWidth: true,
|
||||
width: '100%',
|
||||
dropdownParent: document.getElementById('warehouseForm')
|
||||
}).on('select2:clear', function (e) {
|
||||
@this.manager_id = null;
|
||||
}).on('select2:select', function (e) {
|
||||
@this.manager_id = e.params.data.id;
|
||||
});
|
||||
};
|
||||
|
||||
const storeIdElement = document.getElementById('store_id_{{ $uniqueId }}');
|
||||
const workCenterIdElement = document.getElementById('work_center_id_{{ $uniqueId }}');
|
||||
const managerIdElement = document.getElementById('manager_id_{{ $uniqueId }}');
|
||||
|
||||
// Evento de cambio en store_id
|
||||
storeIdElement.addEventListener('change', async function () {
|
||||
// Limpiar y deshabilitar el select
|
||||
workCenterIdElement.innerHTML = '<option value="">Selecciona el área de trabajo</option>';
|
||||
workCenterIdElement.disabled = true;
|
||||
|
||||
const storeIdValue = storeIdElement.value;
|
||||
|
||||
if (storeIdValue) {
|
||||
try {
|
||||
// Mostrar mensaje de carga
|
||||
workCenterIdElement.innerHTML = '<option value="">Cargando áreas de trabajo...</option>';
|
||||
|
||||
const response = await fetch("{{ route('admin.store-manager.work-centers.ajax') }}", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-TOKEN': csrf_token, // Agregar CSRF token
|
||||
},
|
||||
body: JSON.stringify({
|
||||
store_id: storeIdValue,
|
||||
responseType: 'keyValue',
|
||||
limit: -1 // Sin límite
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Error en la solicitud');
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result && typeof result === 'object' && Object.keys(result).length > 0) {
|
||||
// Limpiar y agregar nuevas opciones
|
||||
workCenterIdElement.innerHTML = '<option value="">Selecciona el área de trabajo</option>';
|
||||
Object.entries(result).forEach(([key, value]) => {
|
||||
workCenterIdElement.append(new Option(value, key, false, false));
|
||||
});
|
||||
|
||||
} else {
|
||||
// Si no hay datos disponibles
|
||||
workCenterIdElement.innerHTML = '<option value="">No hay áreas de trabajo disponibles</option>';
|
||||
}
|
||||
|
||||
// Habilitar el select después de completar la carga
|
||||
workCenterIdElement.disabled = false;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error al cargar los centros de trabajo:', error);
|
||||
|
||||
// En caso de error, mostrar mensaje por defecto
|
||||
workCenterIdElement.innerHTML = '<option value="">Selecciona el área de trabajo</option>';
|
||||
workCenterIdElement.disabled = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
// Inicializa los select2
|
||||
initializeSelect2();
|
||||
}, 1);
|
||||
}
|
||||
|
||||
// Evento para inicializar el formulario cuando se carga la página
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
var myOffcanvas = document.getElementById('{{ $offcanvasId }}')
|
||||
|
||||
myOffcanvas.addEventListener('show.bs.offcanvas', function () {
|
||||
initializeContactForm();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endpush
|
12
resources/views/livewire/warehouses/index.blade.php
Normal file
12
resources/views/livewire/warehouses/index.blade.php
Normal file
@ -0,0 +1,12 @@
|
||||
<x-vuexy-admin::table.bootstrap.manager :tagName="$tagName" :datatableConfig="$bt_datatable">
|
||||
<x-slot name="tools">
|
||||
<div class="mb-4 pr-2">
|
||||
<x-vuexy-admin::button.index-off-canvas :label="$singularName" :tagName="$tagName" />
|
||||
</div>
|
||||
@if(count($storeOptions) > 1)
|
||||
<div class="mb-4 pr-2 pt-1" style="max-width: 320px; min-width: 220px;">
|
||||
<x-vuexy-admin::form.select model="store_id" :options="$storeOptions" placeholder="[Sucursal]" size="sm" />
|
||||
</div>
|
||||
@endif
|
||||
</x-slot>
|
||||
</x-vuexy-admin::table.bootstrap.manager>
|
21
resources/views/materials/index.blade.php
Normal file
21
resources/views/materials/index.blade.php
Normal file
@ -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
|
21
resources/views/product-categories/index.blade.php
Normal file
21
resources/views/product-categories/index.blade.php
Normal file
@ -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
|
21
resources/views/product-receipts/index.blade.php
Normal file
21
resources/views/product-receipts/index.blade.php
Normal file
@ -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
|
21
resources/views/products/index.blade.php
Normal file
21
resources/views/products/index.blade.php
Normal file
@ -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
|
21
resources/views/warehouse-movements/index.blade.php
Normal file
21
resources/views/warehouse-movements/index.blade.php
Normal file
@ -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
|
21
resources/views/warehouse-transfers/index.blade.php
Normal file
21
resources/views/warehouse-transfers/index.blade.php
Normal file
@ -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
|
24
resources/views/warehouses/index.blade.php
Normal file
24
resources/views/warehouses/index.blade.php
Normal file
@ -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
|
109
routes/admin.php
Normal file
109
routes/admin.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
use Koneko\VuexyWarehouse\Http\Controllers\ProductCategorieController;
|
||||
use Koneko\VuexyWarehouse\Http\Controllers\ProductCatalogController;
|
||||
use Koneko\VuexyWarehouse\Http\Controllers\ProductController;
|
||||
use Koneko\VuexyWarehouse\Http\Controllers\ProductReceiptController;
|
||||
use Koneko\VuexyWarehouse\Http\Controllers\MaterialController;
|
||||
use Koneko\VuexyWarehouse\Http\Controllers\WarehouseController;
|
||||
use Koneko\VuexyWarehouse\Http\Controllers\InventoryStockController;
|
||||
use Koneko\VuexyWarehouse\Http\Controllers\InventoryMovementController;
|
||||
use Koneko\VuexyWarehouse\Http\Controllers\WarehouseTransferController;
|
||||
|
||||
// Grupo raíz para admin con middleware y prefijos comunes
|
||||
Route::prefix('admin/productos-y-servicios')->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
|
||||
});
|
||||
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user