307 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			307 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?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';
 | |
|     }
 | |
| 
 | |
| }
 |