first commit
This commit is contained in:
269
Livewire/Company/CompanyIndex.php
Normal file
269
Livewire/Company/CompanyIndex.php
Normal file
@ -0,0 +1,269 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyStoreManager\Livewire\Company;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Koneko\SatCatalogs\Models\Colonia;
|
||||
use Koneko\SatCatalogs\Models\Estado;
|
||||
use Koneko\SatCatalogs\Models\Localidad;
|
||||
use Koneko\SatCatalogs\Models\Municipio;
|
||||
use Koneko\SatCatalogs\Models\Pais;
|
||||
use Koneko\SatCatalogs\Models\RegimenFiscal;
|
||||
use Koneko\VuexyStoreManager\Models\Store;
|
||||
use Livewire\Component;
|
||||
|
||||
class CompanyIndex extends Component
|
||||
{
|
||||
public $btnSubmitText;
|
||||
public $mode;
|
||||
public $storeId;
|
||||
|
||||
public $code,
|
||||
$name,
|
||||
$description,
|
||||
$manager_id,
|
||||
$rfc,
|
||||
$nombre_fiscal,
|
||||
$c_regimen_fiscal,
|
||||
$domicilio_fiscal,
|
||||
$serie_ingresos,
|
||||
$serie_egresos,
|
||||
$serie_pagos,
|
||||
$c_codigo_postal,
|
||||
$c_pais,
|
||||
$c_estado,
|
||||
$c_localidad,
|
||||
$c_municipio,
|
||||
$c_colonia,
|
||||
$direccion,
|
||||
$num_ext,
|
||||
$num_int,
|
||||
$email,
|
||||
$tel,
|
||||
$tel2,
|
||||
$lat,
|
||||
$lng,
|
||||
$status,
|
||||
$show_on_website,
|
||||
$enable_ecommerce;
|
||||
|
||||
public $manager_id_options = [],
|
||||
$c_regimen_fiscal_options = [],
|
||||
$c_pais_options = [],
|
||||
$c_estado_options = [],
|
||||
$c_localidad_options = [],
|
||||
$c_municipio_options = [],
|
||||
$c_colonia_options = [];
|
||||
|
||||
protected $listeners = [
|
||||
'editStore' => 'loadStore',
|
||||
'confirmDeletionStore' => 'loadStoreForDeletion',
|
||||
];
|
||||
|
||||
|
||||
public function mount(String $mode = 'create', Store $store = null)
|
||||
{
|
||||
$this->mode = $mode;
|
||||
|
||||
$this->loadData($store);
|
||||
$this->loadOptions();
|
||||
}
|
||||
|
||||
private function loadData(Store $store)
|
||||
{
|
||||
switch($this->mode){
|
||||
case 'create':
|
||||
$this->btnSubmitText = 'Crear sucursal';
|
||||
|
||||
$this->c_pais = 'MEX';
|
||||
$this->status = true;
|
||||
break;
|
||||
|
||||
case 'edit':
|
||||
|
||||
$this->btnSubmitText = 'Guardar cambios';
|
||||
break;
|
||||
|
||||
case 'delete':
|
||||
$this->btnSubmitText = 'Eliminar sucursal';
|
||||
break;
|
||||
}
|
||||
|
||||
if($store){
|
||||
$this->storeId = $store->id;
|
||||
|
||||
$this->code = $store->code;
|
||||
$this->name = $store->name;
|
||||
$this->description = $store->description;
|
||||
$this->manager_id = $store->manager_id;
|
||||
$this->rfc = $store->rfc;
|
||||
$this->nombre_fiscal = $store->nombre_fiscal;
|
||||
$this->c_regimen_fiscal = $store->c_regimen_fiscal;
|
||||
$this->domicilio_fiscal = $store->domicilio_fiscal;
|
||||
$this->serie_ingresos = $store->serie_ingresos;
|
||||
$this->serie_egresos = $store->serie_egresos;
|
||||
$this->serie_pagos = $store->serie_pagos;
|
||||
$this->c_codigo_postal = $store->c_codigo_postal;
|
||||
$this->c_pais = $store->c_pais;
|
||||
$this->c_estado = $store->c_estado;
|
||||
$this->c_localidad = $store->c_localidad;
|
||||
$this->c_municipio = $store->c_municipio;
|
||||
$this->c_colonia = $store->c_colonia;
|
||||
$this->direccion = $store->direccion;
|
||||
$this->num_ext = $store->num_ext;
|
||||
$this->num_int = $store->num_int;
|
||||
$this->email = $store->email;
|
||||
$this->tel = $store->tel;
|
||||
$this->tel2 = $store->tel2;
|
||||
$this->lat = $store->lat;
|
||||
$this->lng = $store->lng;
|
||||
$this->status = $store->status;
|
||||
$this->show_on_website = $store->show_on_website;
|
||||
$this->enable_ecommerce = $store->enable_ecommerce;
|
||||
}
|
||||
}
|
||||
|
||||
private function loadOptions()
|
||||
{
|
||||
$this->manager_id_options = DB::table('users')
|
||||
->select('id', DB::raw("CONCAT(CONCAT_WS(' ', name, last_name), ' - ', email) as full_name"))
|
||||
//->where('is_user', 1)
|
||||
->orderBy('full_name')
|
||||
->pluck('full_name', 'id');
|
||||
|
||||
$this->c_regimen_fiscal_options = RegimenFiscal::selectList();
|
||||
$this->c_pais_options = Pais::selectList();
|
||||
|
||||
if($this->mode !== 'create'){
|
||||
$this->c_estado_options = ['' => 'Seleccione el estado'] + Estado::selectList($this->c_pais)->toArray();
|
||||
$this->c_localidad_options = ['' => 'Seleccione la localidad'] + Localidad::selectList($this->c_estado)->toArray();
|
||||
$this->c_municipio_options = ['' => 'Seleccione el municipio'] + Municipio::selectList($this->c_estado, $this->c_municipio)->toArray();
|
||||
$this->c_colonia_options = ['' => 'Seleccione la colonia'] + Colonia::selectList($this->c_codigo_postal, $this->c_colonia)->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
public function onSubmit()
|
||||
{
|
||||
if ($this->mode === 'delete') {
|
||||
return $this->delete();
|
||||
}
|
||||
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
private function save()
|
||||
{
|
||||
$validatedData = $this->validate([
|
||||
'code' => 'required|string|max:16',
|
||||
'name' => 'required|string|max:96',
|
||||
'description' => 'nullable|string|max:1024',
|
||||
|
||||
'manager_id' => 'nullable|exists:users,id',
|
||||
'rfc' => 'nullable|string|max:13',
|
||||
'nombre_fiscal' => 'nullable|string|max:255',
|
||||
'c_regimen_fiscal' => 'nullable|integer',
|
||||
'domicilio_fiscal' => 'nullable|integer',
|
||||
|
||||
'c_pais' => 'nullable|string|max:3',
|
||||
'c_estado' => 'nullable|string|max:3',
|
||||
'c_municipio' => 'nullable|integer',
|
||||
'c_localidad' => 'nullable|integer',
|
||||
'c_codigo_postal' => 'nullable|integer',
|
||||
'c_colonia' => 'nullable|integer',
|
||||
'direccion' => 'nullable|string|max:255',
|
||||
'num_ext' => 'nullable|string|max:50',
|
||||
'num_int' => 'nullable|string|max:50',
|
||||
'lat' => 'nullable|numeric',
|
||||
'lng' => 'nullable|numeric',
|
||||
|
||||
'email' => 'nullable|email|max:96',
|
||||
'tel' => 'nullable|string|max:15',
|
||||
'tel2' => 'nullable|string|max:15',
|
||||
|
||||
'status' => 'nullable|boolean',
|
||||
'show_on_website' => 'nullable|boolean',
|
||||
'enable_ecommerce' => 'nullable|boolean',
|
||||
]);
|
||||
|
||||
try {
|
||||
$store = Store::updateOrCreate(
|
||||
[ 'id' => $this->storeId ], // Si $this->storeId es null, creará un nuevo registro
|
||||
[
|
||||
'code' => $validatedData['code'],
|
||||
'name' => $validatedData['name'],
|
||||
'description' => $validatedData['description'] ?? null,
|
||||
|
||||
'manager_id' => $validatedData['manager_id'] ?? null,
|
||||
'rfc' => $validatedData['rfc'] ?? null,
|
||||
'nombre_fiscal' => $validatedData['nombre_fiscal'] ?? null,
|
||||
'c_regimen_fiscal' => $validatedData['c_regimen_fiscal'] ?? null,
|
||||
'domicilio_fiscal' => $validatedData['domicilio_fiscal'] ?? null,
|
||||
|
||||
'c_pais' => $validatedData['c_pais'] ?? null,
|
||||
'c_estado' => $validatedData['c_estado'] ?? null,
|
||||
'c_municipio' => $validatedData['c_municipio'] ?? null,
|
||||
'c_localidad' => $validatedData['c_localidad'] ?? null,
|
||||
'c_codigo_postal' => $validatedData['c_codigo_postal'] ?? null,
|
||||
'c_colonia' => $validatedData['c_colonia'] ?? null,
|
||||
'direccion' => $validatedData['direccion'] ?? null,
|
||||
'num_ext' => $validatedData['num_ext'] ?? null,
|
||||
'num_int' => $validatedData['num_int'] ?? null,
|
||||
'lat' => $validatedData['lat'] ?? null,
|
||||
'lng' => $validatedData['lng'] ?? null,
|
||||
|
||||
'email' => $validatedData['email'] ?? null,
|
||||
'tel' => $validatedData['tel'] ?? null,
|
||||
'tel2' => $validatedData['tel2'] ?? null,
|
||||
|
||||
'show_on_website' => (bool) $validatedData['show_on_website'],
|
||||
'enable_ecommerce' => (bool) $validatedData['enable_ecommerce'],
|
||||
'status' => (bool) $validatedData['status'],
|
||||
]
|
||||
);
|
||||
|
||||
session()->flash('success', 'Sucursal guardada correctamente.');
|
||||
|
||||
return redirect()->route('admin.store-manager.stores.index');
|
||||
|
||||
} catch (QueryException $e) {
|
||||
// Manejar un error específico de SQL/DB, por ejemplo duplicados, FK violation, etc.
|
||||
// O podrías capturar \Exception para cualquier error genérico
|
||||
session()->flash('error', 'Ocurrió un error al guardar la sucursal.');
|
||||
// Opcionalmente: loguear el error para depuración:
|
||||
\Log::error($e->getMessage());
|
||||
|
||||
// Si no haces return, el método continuará, podrías redirigir o quedarte en la misma página
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
if ($this->storeId) {
|
||||
try {
|
||||
Store::find($this->storeId)->delete();
|
||||
|
||||
session()->flash('warning', 'Sucursal eliminada correctamente.');
|
||||
|
||||
return redirect()->route('admin.store-manager.stores.index');
|
||||
|
||||
} catch (QueryException $e) {
|
||||
// Manejar un error específico de SQL/DB, por ejemplo duplicados, FK violation, etc.
|
||||
// O podrías capturar \Exception para cualquier error genérico
|
||||
session()->flash('error', 'Ocurrió un error al eliminar la sucursal.');
|
||||
// Opcionalmente: loguear el error para depuración:
|
||||
\Log::error($e->getMessage());
|
||||
|
||||
// Si no haces return, el método continuará, podrías redirigir o quedarte en la misma página
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('vuexy-store-manager::livewire.company.index');
|
||||
}
|
||||
|
||||
}
|
190
Livewire/Store/PostForm.php
Normal file
190
Livewire/Store/PostForm.php
Normal file
@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyStoreManager\Livewire\Stores;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Koneko\VuexyWarehouse\Models\Warehouse;
|
||||
use Livewire\Component;
|
||||
|
||||
class StoreForm extends Component
|
||||
{
|
||||
public $form_title;
|
||||
public $mode = 'create';
|
||||
|
||||
public $warehouseId,
|
||||
$store_id,
|
||||
$workcenter_id,
|
||||
$code,
|
||||
$name,
|
||||
$description,
|
||||
$is_active = true,
|
||||
$is_default,
|
||||
$confirm_delete;
|
||||
|
||||
public $store_options = [],
|
||||
$workcenter_options = [];
|
||||
|
||||
protected $listeners = [
|
||||
'editWarehouse' => 'loadWarehouse',
|
||||
'confirmDeleteWarehouse' => 'loadWarehouseForDeletion',
|
||||
];
|
||||
|
||||
|
||||
public function mount()
|
||||
{
|
||||
$this->loadOptions();
|
||||
$this->resetForm();
|
||||
}
|
||||
|
||||
private function loadOptions()
|
||||
{
|
||||
$this->store_options = DB::table('stores')
|
||||
->select('id', 'name')
|
||||
->orderBy('name')
|
||||
->pluck('name', 'id');
|
||||
|
||||
$this->workcenter_options = DB::table('store_work_centers')
|
||||
->select('id', 'name')
|
||||
->orderBy('name')
|
||||
->pluck('name', 'id');
|
||||
}
|
||||
|
||||
public function loadWarehouse($id)
|
||||
{
|
||||
$warehouse = Warehouse::find($id);
|
||||
|
||||
if ($warehouse) {
|
||||
$this->fill($warehouse->only(['id', 'store_id', 'workcenter_id', 'code', 'name', 'description', 'is_active', 'is_default']));
|
||||
$this->form_title = "Editar: $warehouse->name";
|
||||
$this->mode = 'edit';
|
||||
|
||||
$this->dispatch('on-edit-warehouse-modal');
|
||||
}
|
||||
}
|
||||
|
||||
public function loadWarehouseForDeletion($id)
|
||||
{
|
||||
$warehouse = Warehouse::find($id);
|
||||
|
||||
if ($warehouse) {
|
||||
$this->fill($warehouse->only(['id', 'store_id', 'workcenter_id', 'code', 'name', 'description', 'is_active', 'is_default']));
|
||||
$this->form_title = "Eliminar: $warehouse->name";
|
||||
$this->mode = 'delete';
|
||||
|
||||
$this->dispatch('on-delete-warehouse-modal');
|
||||
}
|
||||
}
|
||||
|
||||
public function editWarehouse($id)
|
||||
{
|
||||
$warehouse = Warehouse::find($id);
|
||||
|
||||
if ($warehouse) {
|
||||
$this->form_title = 'Editar: ' . $warehouse->name;
|
||||
$this->mode = 'edit';
|
||||
|
||||
$this->warehouseId = $warehouse->id;
|
||||
$this->store_id = $warehouse->store_id;
|
||||
$this->workcenter_id = $warehouse->workcenter_id;
|
||||
$this->code = $warehouse->code;
|
||||
$this->name = $warehouse->name;
|
||||
$this->description = $warehouse->description;
|
||||
$this->is_active = $warehouse->is_active;
|
||||
$this->is_default = $warehouse->is_default;
|
||||
|
||||
$this->dispatch('on-edit-warehouse-modal');
|
||||
}
|
||||
}
|
||||
|
||||
public function confirmDeleteWarehouse($id)
|
||||
{
|
||||
$warehouse = Warehouse::find($id);
|
||||
|
||||
if ($warehouse) {
|
||||
$this->form_title = 'Eliminar: ' . $warehouse->name;
|
||||
$this->mode = 'delete';
|
||||
|
||||
$this->warehouseId = $warehouse->id;
|
||||
$this->store_id = $warehouse->store_id;
|
||||
$this->workcenter_id = $warehouse->workcenter_id;
|
||||
$this->code = $warehouse->code;
|
||||
$this->name = $warehouse->name;
|
||||
$this->description = $warehouse->description;
|
||||
$this->is_active = $warehouse->is_active;
|
||||
$this->is_default = $warehouse->is_default;
|
||||
|
||||
$this->dispatch('on-delete-warehouse-modal');
|
||||
}
|
||||
}
|
||||
|
||||
public function onSubmit()
|
||||
{
|
||||
if ($this->mode === 'delete') {
|
||||
return $this->delete();
|
||||
}
|
||||
|
||||
return $this->save();
|
||||
}
|
||||
|
||||
private function save()
|
||||
{
|
||||
try {
|
||||
$validatedData = $this->validate([
|
||||
'store_id' => 'required',
|
||||
'code' => 'required|string|max:16',
|
||||
'name' => 'required|string|max:96',
|
||||
'description' => 'nullable|string|max:1024',
|
||||
]);
|
||||
} catch (\Illuminate\Validation\ValidationException $e) {
|
||||
$this->dispatch('on-failed-validation-warehouse-modal');
|
||||
$this->dispatch('warehouse-message', ['type' => 'danger', 'message' => 'Error en la validación']);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
Warehouse::updateOrCreate(
|
||||
['id' => $this->warehouseId],
|
||||
[
|
||||
'store_id' => $validatedData['store_id'],
|
||||
'workcenter_id' => $this->workcenter_id,
|
||||
'code' => $validatedData['code'],
|
||||
'name' => $validatedData['name'],
|
||||
'description' => $validatedData['description'] ?? null,
|
||||
'is_active' => (bool) $this->is_active,
|
||||
'is_default' => (bool) $this->is_default,
|
||||
]
|
||||
);
|
||||
|
||||
$this->dispatch('warehouse-message', ['type' => 'success', 'message' => 'Almacén guardado correctamente']);
|
||||
$this->dispatch('reload-warehouse-table');
|
||||
$this->dispatch('close-warehouse-modal');
|
||||
$this->resetForm();
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
if ($this->warehouseId) {
|
||||
Warehouse::find($this->warehouseId)->delete();
|
||||
|
||||
$this->dispatch('warehouse-message', ['type' => 'warning', 'message' => 'Almacén eliminado']);
|
||||
$this->dispatch('reload-warehouse-table');
|
||||
$this->dispatch('close-warehouse-modal');
|
||||
|
||||
$this->resetForm();
|
||||
}
|
||||
}
|
||||
|
||||
public function resetForm()
|
||||
{
|
||||
$this->reset(['warehouseId', 'store_id', 'workcenter_id', 'code', 'name', 'description', 'is_default', 'confirm_delete']);
|
||||
|
||||
$this->form_title = 'Agregar almacén';
|
||||
$this->mode = 'create';
|
||||
$this->is_active = true;
|
||||
}
|
||||
|
||||
public function render()
|
||||
{
|
||||
return view('vuexy-warehouse::livewire.stores.form');
|
||||
}
|
||||
|
||||
}
|
306
Livewire/Stores/StoreForm.php
Normal file
306
Livewire/Stores/StoreForm.php
Normal file
@ -0,0 +1,306 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyStoreManager\Livewire\Stores;
|
||||
|
||||
use Illuminate\Validation\Rule;
|
||||
use Koneko\VuexyAdmin\Models\User;
|
||||
use Koneko\VuexyAdmin\Livewire\Form\AbstractFormComponent;
|
||||
use Koneko\SatCatalogs\Models\{Colonia, Estado, Localidad, Municipio, Pais, RegimenFiscal};
|
||||
use Koneko\VuexyStoreManager\Models\Store;
|
||||
|
||||
/**
|
||||
* Class StoreForm
|
||||
*
|
||||
* Componente Livewire para manejar el formulario CRUD de sucursales en el sistema ERP.
|
||||
* Implementa la creación, edición y eliminación de sucursales con validaciones dinámicas.
|
||||
*/
|
||||
class StoreForm extends AbstractFormComponent
|
||||
{
|
||||
/**
|
||||
* Campos específicos del formulario.
|
||||
*/
|
||||
public $code, $name, $description, $manager_id, $rfc, $nombre_fiscal, $c_regimen_fiscal,
|
||||
$domicilio_fiscal, $serie_ingresos, $serie_egresos, $serie_pagos, $c_codigo_postal,
|
||||
$c_pais, $c_estado, $c_localidad, $c_municipio, $c_colonia, $direccion, $num_ext,
|
||||
$num_int, $email, $tel, $tel2, $lat, $lng, $show_on_website, $enable_ecommerce, $status;
|
||||
|
||||
|
||||
public $confirmDeletion = false;
|
||||
|
||||
/**
|
||||
* Listas de opciones para selects en el formulario.
|
||||
*/
|
||||
public $manager_id_options = [],
|
||||
$c_regimen_fiscal_options = [],
|
||||
$c_pais_options = [],
|
||||
$c_estado_options = [],
|
||||
$c_localidad_options = [],
|
||||
$c_municipio_options = [],
|
||||
$c_colonia_options = [];
|
||||
|
||||
/**
|
||||
* Montar el formulario e inicializar datos específicos.
|
||||
*
|
||||
* @param string $mode Modo del formulario: create, edit, delete.
|
||||
* @param Store|null $store El modelo Store si está en modo edición o eliminación.
|
||||
*/
|
||||
public function mount(string $mode = 'create', mixed $store = null): void
|
||||
{
|
||||
parent::mount($mode, $store->id ?? null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cargar opciones de formularios según el modo actual.
|
||||
*
|
||||
* @param string $mode
|
||||
*/
|
||||
private function loadOptions(string $mode): void
|
||||
{
|
||||
$this->manager_id_options = User::getUsersListWithInactive($this->manager_id, ['type' => 'user', 'status' => 1]);
|
||||
$this->c_regimen_fiscal_options = RegimenFiscal::selectList();
|
||||
$this->c_pais_options = Pais::selectList();
|
||||
$this->c_estado_options = Estado::selectList($this->c_pais)->toArray();
|
||||
|
||||
if ($mode !== 'create') {
|
||||
$this->c_localidad_options = Localidad::selectList($this->c_estado)->toArray();
|
||||
$this->c_municipio_options = Municipio::selectList($this->c_estado, $this->c_municipio)->toArray();
|
||||
$this->c_colonia_options = Colonia::selectList($this->c_codigo_postal, $this->c_colonia)->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
// ===================== MÉTODOS OBLIGATORIOS =====================
|
||||
|
||||
/**
|
||||
* Devuelve el modelo Eloquent asociado.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function model(): string
|
||||
{
|
||||
return Store::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reglas de validación dinámicas según el modo actual.
|
||||
*
|
||||
* @param string $mode
|
||||
* @return array
|
||||
*/
|
||||
protected function dynamicRules(string $mode): array
|
||||
{
|
||||
switch ($mode) {
|
||||
case 'create':
|
||||
case 'edit':
|
||||
return [
|
||||
'code' => [
|
||||
'required', 'string', 'alpha_num', 'max:16',
|
||||
Rule::unique('stores', 'code')->ignore($this->id)
|
||||
],
|
||||
'name' => 'required|string|max:96',
|
||||
'description' => 'nullable|string|max:1024',
|
||||
'manager_id' => 'nullable|exists:users,id',
|
||||
|
||||
// Información fiscal
|
||||
'rfc' => ['nullable', 'string', 'regex:/^([A-ZÑ&]{3,4})(\d{6})([A-Z\d]{3})$/i', 'max:13'],
|
||||
'nombre_fiscal' => 'nullable|string|max:255',
|
||||
'c_regimen_fiscal' => 'nullable|exists:sat_regimen_fiscal,c_regimen_fiscal',
|
||||
'domicilio_fiscal' => 'nullable|exists:sat_codigo_postal,c_codigo_postal',
|
||||
|
||||
// Ubicación
|
||||
'c_pais' => 'nullable|exists:sat_pais,c_pais|string|size:3',
|
||||
'c_estado' => 'nullable|exists:sat_estado,c_estado|string|min:2|max:3',
|
||||
'c_municipio' => 'nullable|exists:sat_municipio,c_municipio|integer',
|
||||
'c_localidad' => 'nullable|integer',
|
||||
'c_codigo_postal' => 'nullable|exists:sat_codigo_postal,c_codigo_postal|integer',
|
||||
'c_colonia' => 'nullable|exists:sat_colonia,c_colonia|integer',
|
||||
'direccion' => 'nullable|string|max:255',
|
||||
'num_ext' => 'nullable|string|max:50',
|
||||
'num_int' => 'nullable|string|max:50',
|
||||
'lat' => 'nullable|numeric|between:-90,90',
|
||||
'lng' => 'nullable|numeric|between:-180,180',
|
||||
|
||||
// Contacto
|
||||
'email' => ['nullable', 'email', 'required_if:enable_ecommerce,true'],
|
||||
'tel' => ['nullable', 'regex:/^[0-9\s\-\+\(\)]+$/', 'max:15'],
|
||||
'tel2' => ['nullable', 'regex:/^[0-9\s\-\+\(\)]+$/', 'max:15'],
|
||||
|
||||
// Configuración web y estado
|
||||
'show_on_website' => 'nullable|boolean',
|
||||
'enable_ecommerce' => 'nullable|boolean',
|
||||
'status' => 'nullable|boolean',
|
||||
];
|
||||
|
||||
case 'delete':
|
||||
return [
|
||||
'confirmDeletion' => 'accepted', // Asegura que el usuario confirme la eliminación
|
||||
];
|
||||
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inicializa los datos del formulario en función del modo.
|
||||
*
|
||||
* @param Store|null $store
|
||||
* @param string $mode
|
||||
*/
|
||||
protected function initializeFormData(mixed $store, string $mode): void
|
||||
{
|
||||
if ($store) {
|
||||
$this->code = $store->code;
|
||||
$this->name = $store->name;
|
||||
$this->description = $store->description;
|
||||
$this->manager_id = $store->manager_id;
|
||||
$this->rfc = $store->rfc;
|
||||
$this->nombre_fiscal = $store->nombre_fiscal;
|
||||
$this->c_regimen_fiscal = $store->c_regimen_fiscal;
|
||||
$this->domicilio_fiscal = $store->domicilio_fiscal;
|
||||
$this->c_pais = $store->c_pais;
|
||||
$this->c_estado = $store->c_estado;
|
||||
$this->c_municipio = $store->c_municipio;
|
||||
$this->c_localidad = $store->c_localidad;
|
||||
$this->c_codigo_postal = $store->c_codigo_postal;
|
||||
$this->c_colonia = $store->c_colonia;
|
||||
$this->direccion = $store->direccion;
|
||||
$this->num_ext = $store->num_ext;
|
||||
$this->num_int = $store->num_int;
|
||||
$this->lat = $store->lat;
|
||||
$this->lng = $store->lng;
|
||||
$this->email = $store->email;
|
||||
$this->tel = $store->tel;
|
||||
$this->tel2 = $store->tel2;
|
||||
$this->show_on_website = (bool) $store->show_on_website;
|
||||
$this->enable_ecommerce = (bool) $store->enable_ecommerce;
|
||||
$this->status = (bool) $store->status;
|
||||
|
||||
} else {
|
||||
$this->c_pais = 'MEX';
|
||||
$this->status = true;
|
||||
$this->show_on_website = false;
|
||||
$this->enable_ecommerce = false;
|
||||
}
|
||||
|
||||
$this->loadOptions($mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepara los datos validados para su almacenamiento.
|
||||
*
|
||||
* @param array $validatedData
|
||||
* @return array
|
||||
*/
|
||||
protected function prepareData(array $validatedData): array
|
||||
{
|
||||
return [
|
||||
'code' => $validatedData['code'],
|
||||
'name' => $validatedData['name'],
|
||||
'description' => strip_tags($validatedData['description']),
|
||||
'manager_id' => $validatedData['manager_id'],
|
||||
'rfc' => $validatedData['rfc'],
|
||||
'nombre_fiscal' => $validatedData['nombre_fiscal'],
|
||||
'c_regimen_fiscal' => $validatedData['c_regimen_fiscal'],
|
||||
'domicilio_fiscal' => $validatedData['domicilio_fiscal'],
|
||||
'c_codigo_postal' => $validatedData['c_codigo_postal'],
|
||||
'c_pais' => $validatedData['c_pais'],
|
||||
'c_estado' => $validatedData['c_estado'],
|
||||
'c_localidad' => $validatedData['c_localidad'],
|
||||
'c_municipio' => $validatedData['c_municipio'],
|
||||
'c_colonia' => $validatedData['c_colonia'],
|
||||
'direccion' => $validatedData['direccion'],
|
||||
'num_ext' => $validatedData['num_ext'],
|
||||
'num_int' => $validatedData['num_int'],
|
||||
'email' => $validatedData['email'],
|
||||
'tel' => $validatedData['tel'],
|
||||
'tel2' => $validatedData['tel2'],
|
||||
'lat' => $validatedData['lat'],
|
||||
'lng' => $validatedData['lng'],
|
||||
'status' => $validatedData['status'],
|
||||
'show_on_website' => $validatedData['show_on_website'],
|
||||
'enable_ecommerce' => $validatedData['enable_ecommerce'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Definición de los contenedores de notificación.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function targetNotifies(): array
|
||||
{
|
||||
return [
|
||||
"index" => "#bt-stores .notification-container",
|
||||
"form" => "#store-form .notification-container",
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Ruta de vista asociada al formulario.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View
|
||||
*/
|
||||
protected function viewPath(): string
|
||||
{
|
||||
return 'vuexy-store-manager::livewire.stores.form';
|
||||
}
|
||||
|
||||
// ===================== VALIDACIONES =====================
|
||||
|
||||
/**
|
||||
* Get custom attributes for validator errors.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'code' => 'código de sucursal',
|
||||
'name' => 'nombre de la sucursal',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the error messages for the defined validation rules.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'code.required' => 'El código de la sucursal es obligatorio.',
|
||||
'code.unique' => 'Este código ya está en uso por otra sucursal.',
|
||||
'name.required' => 'El nombre de la sucursal es obligatorio.',
|
||||
];
|
||||
}
|
||||
|
||||
// ===================== PREPARACIÓN DE DATOS =====================
|
||||
|
||||
// ===================== NOTIFICACIONES Y EVENTOS =====================
|
||||
|
||||
/**
|
||||
* Definición de los eventos del componente.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function dispatches(): array
|
||||
{
|
||||
return [
|
||||
'on-failed-validation' => 'on-failed-validation-store',
|
||||
'on-hydrate' => 'on-hydrate-store-modal',
|
||||
];
|
||||
}
|
||||
|
||||
// ===================== REDIRECCIÓN =====================
|
||||
|
||||
/**
|
||||
* Define la ruta de redirección tras guardar o eliminar.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getRedirectRoute(): string
|
||||
{
|
||||
return 'admin.store-manager.stores.index';
|
||||
}
|
||||
|
||||
}
|
230
Livewire/Stores/StoreIndex.php
Normal file
230
Livewire/Stores/StoreIndex.php
Normal file
@ -0,0 +1,230 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyStoreManager\Livewire\Stores;
|
||||
|
||||
use Koneko\VuexyAdmin\Livewire\Table\AbstractIndexComponent;
|
||||
use Koneko\VuexyStoreManager\Models\Store;
|
||||
|
||||
/**
|
||||
* Listado de Tiendas, extiende de la clase base AbstractIndexComponent
|
||||
* para reutilizar la lógica de configuración y renderizado de tablas.
|
||||
*/
|
||||
class StoreIndex extends AbstractIndexComponent
|
||||
{
|
||||
/**
|
||||
* Almacena rutas útiles para la funcionalidad de edición o eliminación.
|
||||
* (En tu caso, lo llenas en mount())
|
||||
*/
|
||||
public $routes = [];
|
||||
|
||||
/**
|
||||
* Método que define la clase o instancia del modelo a usar en este Index.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function model(): string
|
||||
{
|
||||
return Store::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retorna las columnas (header) de la tabla.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function columns(): array
|
||||
{
|
||||
return [
|
||||
'action' => 'Acciones',
|
||||
'code' => 'Código',
|
||||
'name' => 'Nombre de la tienda',
|
||||
'description' => 'Descripción',
|
||||
'manager_name' => 'Gerente',
|
||||
'pais' => 'País',
|
||||
'estado' => 'Estado',
|
||||
'localidad' => 'Localidad',
|
||||
'municipio' => 'Municipio',
|
||||
'codigo_postal' => 'Código Postal',
|
||||
'colonia' => 'Colonia',
|
||||
'direccion' => 'Dirección',
|
||||
'lat' => 'Latitud',
|
||||
'lng' => 'Longitud',
|
||||
'email' => 'Correo de la tienda',
|
||||
'tel' => 'Teléfono',
|
||||
'tel2' => 'Teléfono Alternativo',
|
||||
'rfc' => 'RFC',
|
||||
'nombre_fiscal' => 'Nombre Fiscal',
|
||||
'regimen_fiscal' => 'Régimen Fiscal',
|
||||
'domicilio_fiscal' => 'Domicilio Fiscal',
|
||||
'show_on_website' => 'Visible en Sitio Web',
|
||||
'enable_ecommerce' => 'eCommerce',
|
||||
'status' => 'Estatus',
|
||||
'created_at' => 'Creada',
|
||||
'updated_at' => 'Modificada',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retorna el formato (formatter) para cada columna (similar a 'bt_datatable.format').
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function format(): array
|
||||
{
|
||||
return [
|
||||
'action' => [
|
||||
'formatter' => 'storeActionFormatter',
|
||||
'onlyFormatter' => true,
|
||||
],
|
||||
'code' => [
|
||||
'formatter' => [
|
||||
'name' => 'dynamicBadgeFormatter',
|
||||
'params' => ['color' => 'secondary'],
|
||||
],
|
||||
'align' => 'center',
|
||||
'switchable' => false,
|
||||
],
|
||||
'name' => [
|
||||
'switchable' => false,
|
||||
],
|
||||
'description' => [
|
||||
'visible' => false,
|
||||
],
|
||||
'codigo_postal' => [
|
||||
'align' => 'center',
|
||||
'visible' => false,
|
||||
],
|
||||
'manager_name' => [
|
||||
'formatter' => 'managerFormatter',
|
||||
'visible' => true,
|
||||
],
|
||||
'pais' => [
|
||||
'align' => 'center',
|
||||
],
|
||||
'estado' => [
|
||||
'formatter' => 'textNowrapFormatter',
|
||||
'align' => 'center',
|
||||
],
|
||||
'localidad' => [
|
||||
'formatter' => 'textNowrapFormatter',
|
||||
'visible' => false,
|
||||
],
|
||||
'municipio' => [
|
||||
'formatter' => 'textNowrapFormatter',
|
||||
'visible' => false,
|
||||
],
|
||||
// la segunda definición de 'codigo_postal' la omites, pues ya está arriba
|
||||
'colonia' => [
|
||||
'formatter' => 'textNowrapFormatter',
|
||||
'visible' => false,
|
||||
],
|
||||
'direccion' => [
|
||||
'formatter' => 'direccionFormatter',
|
||||
'visible' => false,
|
||||
],
|
||||
'lat' => [
|
||||
'align' => 'center',
|
||||
'visible' => false,
|
||||
],
|
||||
'lng' => [
|
||||
'align' => 'center',
|
||||
'visible' => false,
|
||||
],
|
||||
'email' => [
|
||||
'visible' => true,
|
||||
'formatter' => 'emailFormatter',
|
||||
],
|
||||
'tel' => [
|
||||
'formatter' => 'telFormatter',
|
||||
],
|
||||
'tel2' => [
|
||||
'formatter' => 'telFormatter',
|
||||
'visible' => false,
|
||||
],
|
||||
'rfc' => [
|
||||
'align' => 'center',
|
||||
'visible' => false,
|
||||
],
|
||||
'nombre_fiscal' => [
|
||||
'formatter' => 'textNowrapFormatter',
|
||||
'visible' => false,
|
||||
],
|
||||
'regimen_fiscal' => [
|
||||
'visible' => false,
|
||||
],
|
||||
'domicilio_fiscal' => [
|
||||
'align' => 'center',
|
||||
'visible' => false,
|
||||
],
|
||||
'show_on_website' => [
|
||||
'formatter' => 'dynamicBooleanFormatter',
|
||||
'align' => 'center',
|
||||
],
|
||||
'enable_ecommerce' => [
|
||||
'formatter' => 'dynamicBooleanFormatter',
|
||||
'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,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sobrescribe la config base de la tabla para inyectar
|
||||
* tus valores (similar a 'bt_datatable').
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function bootstraptableConfig(): array
|
||||
{
|
||||
// Llamamos al padre y reemplazamos/ajustamos lo que necesitemos.
|
||||
return array_merge(parent::bootstraptableConfig(), [
|
||||
'sortName' => 'code',
|
||||
'exportFileName' => 'Tiendas',
|
||||
'showFullscreen' => false,
|
||||
'showPaginationSwitch'=> false,
|
||||
'showRefresh' => false,
|
||||
'pagination' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Montamos el componente (ajustando rutas o algo adicional),
|
||||
* y llamamos al parent::mount() para que se configure la tabla.
|
||||
*/
|
||||
public function mount(): void
|
||||
{
|
||||
parent::mount();
|
||||
|
||||
// Definimos las rutas específicas de este componente
|
||||
$this->routes = [
|
||||
'admin.store-manager.stores.edit' => route('admin.store-manager.stores.edit', ['store' => ':id']),
|
||||
'admin.store-manager.stores.delete' => route('admin.store-manager.stores.delete', ['store' => ':id']),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retorna la vista a renderizar por este componente.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function viewPath(): string
|
||||
{
|
||||
return 'vuexy-store-manager::livewire.stores.index';
|
||||
}
|
||||
}
|
211
Livewire/WorkCenters/WorkCenterIndex.php
Normal file
211
Livewire/WorkCenters/WorkCenterIndex.php
Normal file
@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyStoreManager\Livewire\WorkCenters;
|
||||
|
||||
use Koneko\VuexyAdmin\Livewire\Table\AbstractIndexComponent;
|
||||
use Koneko\VuexyStoreManager\Models\StoreWorkCenter;
|
||||
use Koneko\VuexyStoreManager\Services\StoreCatalogService;
|
||||
|
||||
/**
|
||||
* Index para Centros de Trabajo, extendiendo la clase base AbstractIndexComponent.
|
||||
*/
|
||||
class WorkCenterIndex extends AbstractIndexComponent
|
||||
{
|
||||
/**
|
||||
* Usado para filtrar (opcional) o cargar catálogos en la vista.
|
||||
*/
|
||||
public $store_id;
|
||||
|
||||
/**
|
||||
* Opciones de tiendas (por ejemplo, para un select de filtrado).
|
||||
*/
|
||||
public $storeOptions = [];
|
||||
|
||||
/**
|
||||
* Montamos (inicializamos) el componente y llamamos al mount() del padre
|
||||
* para configurar la tabla y setear $tagName, $singularName, $formId, etc.
|
||||
*/
|
||||
public function mount(): void
|
||||
{
|
||||
parent::mount();
|
||||
|
||||
// Ahora cargamos las opciones de tienda, usando el servicio necesario.
|
||||
$storeCatalogService = app(StoreCatalogService::class);
|
||||
$this->storeOptions = $storeCatalogService->searchCatalog('stores', '', ['limit' => -1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indica la clase (o instancia) de tu modelo.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function model(): string
|
||||
{
|
||||
// Retornamos la clase del modelo
|
||||
return StoreWorkCenter::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retorna las columnas (header) de tu tabla.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function columns(): array
|
||||
{
|
||||
return [
|
||||
'action' => 'Acciones',
|
||||
'stores_code' => 'Código de Tienda',
|
||||
'stores_name' => 'Nombre de la Tienda',
|
||||
'code' => 'Código del Centro',
|
||||
'name' => 'Nombre del Centro',
|
||||
'description' => 'Descripción',
|
||||
'manager_name' => 'Gerente',
|
||||
'tel' => 'Teléfono',
|
||||
'tel2' => 'Teléfono Alternativo',
|
||||
'codigo_postal' => 'Código Postal',
|
||||
'pais' => 'País',
|
||||
'estado' => 'Estado',
|
||||
'localidad' => 'Localidad',
|
||||
'municipio' => 'Municipio',
|
||||
'colonia' => 'Colonia',
|
||||
'direccion' => 'Dirección',
|
||||
'lat' => 'Latitud',
|
||||
'lng' => 'Longitud',
|
||||
'status' => 'Estatus',
|
||||
'created_at' => 'Creado',
|
||||
'updated_at' => 'Actualizado',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retorna el formato (formatter) de las columnas.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function format(): array
|
||||
{
|
||||
return [
|
||||
'action' => [
|
||||
'formatter' => 'workCenterActionFormatter',
|
||||
'onlyFormatter' => true,
|
||||
],
|
||||
'stores_code' => [
|
||||
'formatter' => [
|
||||
'name' => 'dynamicBadgeFormatter',
|
||||
'params' => ['color' => 'secondary'],
|
||||
],
|
||||
'align' => 'center',
|
||||
],
|
||||
'stores_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,
|
||||
],
|
||||
'lat' => [
|
||||
'align' => 'center',
|
||||
'visible' => false,
|
||||
],
|
||||
'lng' => [
|
||||
'align' => 'center',
|
||||
'visible' => false,
|
||||
],
|
||||
'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,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sobrescribe la config base para adaptarla al caso de los Centros de Trabajo.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function bootstraptableConfig(): array
|
||||
{
|
||||
// Llamamos al padre y luego ajustamos lo que necesitemos.
|
||||
return array_merge(parent::bootstraptableConfig(), [
|
||||
'sortName' => 'code',
|
||||
'exportFileName' => 'Centros de Trabajo',
|
||||
'showFullscreen' => false,
|
||||
'showPaginationSwitch'=> false,
|
||||
'showRefresh' => false,
|
||||
'pagination' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retorna la vista que se usará para renderizar este componente.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function viewPath(): string
|
||||
{
|
||||
return 'vuexy-store-manager::livewire.work-center.index';
|
||||
}
|
||||
}
|
202
Livewire/WorkCenters/WorkCenterOffcanvasForm.php
Normal file
202
Livewire/WorkCenters/WorkCenterOffcanvasForm.php
Normal file
@ -0,0 +1,202 @@
|
||||
<?php
|
||||
|
||||
namespace Koneko\VuexyStoreManager\Livewire\Workcenters;
|
||||
|
||||
use Illuminate\Validation\Rule;
|
||||
use Koneko\VuexyAdmin\Livewire\Form\AbstractFormOffCanvasComponent;
|
||||
use Koneko\VuexyContacts\Services\ContactCatalogService;
|
||||
use Koneko\VuexyStoreManager\Models\StoreWorkCenter;
|
||||
use Koneko\VuexyStoreManager\Services\StoreCatalogService;
|
||||
|
||||
/**
|
||||
* Class WorkCenterOffcanvasForm
|
||||
*
|
||||
* Componente Livewire para gestionar centros de trabajo.
|
||||
* Extiende las funcionalidades generales de AbstractFormOffCanvasComponent.
|
||||
*
|
||||
* @package Koneko\VuexyStoreManager\Livewire\Workcenters
|
||||
*/
|
||||
class WorkCenterOffcanvasForm extends AbstractFormOffCanvasComponent
|
||||
{
|
||||
/**
|
||||
* Campos específicos del centro de trabajo.
|
||||
*/
|
||||
public $store_id, $code, $name, $description, $manager_id, $tel, $tel2, $lat, $lng, $status;
|
||||
|
||||
/**
|
||||
* Listas de opciones para selects en el formulario.
|
||||
*/
|
||||
public $store_options = [],
|
||||
$manager_options = [];
|
||||
|
||||
/**
|
||||
* Eventos de escucha de Livewire.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $listeners = [
|
||||
'editWorkCenter' => 'loadFormModel',
|
||||
'confirmDeletionWorkCenter' => 'loadFormModelForDeletion',
|
||||
];
|
||||
|
||||
/**
|
||||
* Definición de tipos de datos que se deben castear.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
//
|
||||
'status' => 'boolean',
|
||||
];
|
||||
|
||||
/**
|
||||
* Devuelve el modelo relacionado con el formulario.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function model(): string
|
||||
{
|
||||
return StoreWorkCenter::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define los campos del formulario.
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
protected function fields(): array
|
||||
{
|
||||
return (new StoreWorkCenter())->getFillable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Valores por defecto para el formulario.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function defaults(): array
|
||||
{
|
||||
return [
|
||||
'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'],
|
||||
'code' => [
|
||||
'required', 'string', 'max:16',
|
||||
'regex:/^[a-zA-Z0-9_-]+$/', // Solo alfanuméricos, guiones y guiones bajos
|
||||
Rule::unique('store_work_centers', 'code')->ignore($this->id),
|
||||
],
|
||||
'name' => [
|
||||
'required', 'string', 'max:96',
|
||||
'regex:/^[a-zA-ZáéíóúÁÉÍÓÚñÑ0-9\s-]+$/', // Solo letras, números y espacios
|
||||
Rule::unique('store_work_centers')
|
||||
->where(fn ($query) => $query->where('store_id', $this->store_id))
|
||||
->ignore($this->id),
|
||||
],
|
||||
'description' => ['nullable', 'string', 'max:1024'],
|
||||
'manager_id' => ['nullable', 'integer', 'exists:users,id'],
|
||||
'tel' => ['nullable', 'regex:/^\+?[0-9()\s-]+$/', 'max:20'], // Permitir formatos internacionales
|
||||
'tel2' => ['nullable', 'regex:/^\+?[0-9()\s-]+$/', 'max:20'],
|
||||
'lat' => ['nullable', 'numeric', 'between:-90,90'],
|
||||
'lng' => ['nullable', 'numeric', 'between:-180,180'],
|
||||
'status' => ['nullable', 'boolean']
|
||||
];
|
||||
|
||||
case 'delete':
|
||||
return [
|
||||
'confirmDeletion' => 'accepted', // Confirma que el usuario acepta eliminar
|
||||
];
|
||||
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// ===================== VALIDACIONES =====================
|
||||
|
||||
/**
|
||||
* Get custom attributes for validator errors.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function attributes(): array
|
||||
{
|
||||
return [
|
||||
'store_id' => 'negocio',
|
||||
'code' => 'código del centro de trabajo',
|
||||
'name' => 'nombre del centro de trabajo',
|
||||
'tel' => 'teléfono',
|
||||
'tel2' => 'teléfono alternativo',
|
||||
'lat' => 'latitud',
|
||||
'lng' => 'longitud',
|
||||
'status' => 'estado',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the error messages for the defined validation rules.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function messages(): array
|
||||
{
|
||||
return [
|
||||
'store_id.required' => 'El centro de trabajo debe estar asociado a un negocio.',
|
||||
'code.required' => 'El código del centro de trabajo es obligatorio.',
|
||||
'code.unique' => 'Este código ya está en uso por otro centro de trabajo.',
|
||||
'name.required' => 'El nombre del centro de trabajo es obligatorio.',
|
||||
'name.unique' => 'Ya existe un centro de trabajo con este nombre en este negocio.',
|
||||
'name.regex' => 'El nombre solo puede contener letras, números, espacios y guiones.',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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-store-manager::livewire.work-center.form-offcanvas';
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user