[ 'table' => 'sat_banco', 'key' => 'c_banco', 'value' => 'descripcion AS item', 'order_by' => 'descripcion', 'search_columns' => ['descripcion'], 'use_status' => true, 'limit' => 10 ], 'clave_prod_serv' => [ 'table' => 'sat_clave_prod_serv', 'key' => 'c_clave_prod_serv', 'value' => "CONCAT_WS(' - ', c_clave_prod_serv , descripcion) as item", 'search_type' => 'MATCH', 'search_columns' => ['c_clave_prod_serv_text', 'descripcion'], ], 'clave_unidad' => [ 'table' => 'sat_clave_unidad', 'key' => 'c_clave_unidad', 'value' => "CONCAT_WS(' - ', c_clave_unidad , nombre) as item", 'search_columns' => ['c_clave_unidad', 'nombre'], 'limit' => 20 ], 'deduccion' => [ 'table' => 'sat_deduccion', 'key' => 'c_deduccion', 'value' => "CONCAT_WS(' - ', c_deduccion , descripcion) as item", 'search_columns' => ['c_deduccion', 'descripcion'], 'limit' => 20 ], 'forma_pago' => [ 'table' => 'sat_forma_pago', 'key' => 'c_forma_pago', 'value' => "CONCAT_WS(' - ', c_forma_pago , descripcion) as item", 'search_columns' => ['c_forma_pago', 'descripcion'], 'limit' => 10 ], 'moneda' => [ 'table' => 'sat_moneda', 'key' => 'c_moneda', 'value' => "CONCAT_WS(' - ', c_moneda , descripcion) as item", 'order_by' => 'descripcion', 'search_columns' => ['c_moneda', 'descripcion'], 'limit' => 10 ], 'pais' => [ 'table' => 'sat_pais', 'key' => 'c_pais', 'value' => 'descripcion AS item', 'order_by' => 'descripcion', 'search_columns' => ['c_pais', 'descripcion'], 'limit' => 10 ], 'estado' => [ 'table' => 'sat_estado', 'key' => 'c_estado', 'value' => 'nombre_del_estado AS item', 'order_by' => 'nombre_del_estado', 'extra_conditions' => ['c_pais'], 'search_columns' => ['nombre_del_estado'], ], 'municipio' => [ 'table' => 'sat_municipio', 'key' => 'c_municipio', 'value' => 'descripcion AS item', 'order_by' => 'descripcion', 'extra_conditions' => ['c_estado'], 'search_columns' => ['descripcion'], ], 'localidad' => [ 'table' => 'sat_localidad', 'key' => 'c_localidad', 'value' => 'descripcion AS item', 'order_by' => 'descripcion', 'extra_conditions' => ['c_estado'], 'search_columns' => ['descripcion'], ], 'colonia' => [ 'table' => 'sat_colonia', 'joins' => [ [ 'table' => 'sat_codigo_postal', 'first' => 'sat_colonia.c_codigo_postal', 'second' => 'sat_codigo_postal.c_codigo_postal', ], ], 'key' => 'sat_colonia.c_colonia', 'value' => 'sat_colonia.nombre_del_asentamiento AS item', 'columns' => [ 'sat_colonia.c_codigo_postal', ], 'order_by' => 'sat_colonia.nombre_del_asentamiento', 'extra_conditions' => ['sat_codigo_postal.c_codigo_postal', 'sat_codigo_postal.c_estado', 'sat_codigo_postal.c_municipio', 'sat_colonia.c_colonia'], 'search_columns' => ['sat_colonia.nombre_del_asentamiento'], ], 'codigo_postal' => [ 'table' => 'sat_codigo_postal', 'joins' => [ [ 'table' => 'sat_localidad', 'first' => 'sat_codigo_postal.c_localidad', 'second' => 'sat_localidad.c_localidad', 'and' => ['sat_codigo_postal.c_estado = sat_localidad.c_estado'], 'type' => 'leftJoin', ], [ 'table' => 'sat_municipio', 'first' => 'sat_codigo_postal.c_municipio', 'second' => 'sat_municipio.c_municipio', 'and' => ['sat_codigo_postal.c_estado = sat_municipio.c_estado'], 'type' => 'leftJoin', ], [ 'table' => 'sat_estado', 'first' => 'sat_codigo_postal.c_estado', 'second' => 'sat_estado.c_estado', 'type' => 'leftJoin', ], ], 'key' => 'sat_codigo_postal.c_codigo_postal', 'columns' => [ 'sat_codigo_postal.c_estado', 'sat_estado.nombre_del_estado as estado', 'sat_codigo_postal.c_localidad', 'sat_localidad.descripcion as localidad', 'sat_codigo_postal.c_municipio', 'sat_municipio.descripcion as municipio', ], 'search_columns' => ['sat_codigo_postal.c_codigo_postal'], ], ]; protected $fixedCatalogs = [ 'exportacion' => [ 1 => 'No aplica', 2 => 'Definitiva con clave A1', 3 => 'Temporal', 4 => 'Definitiva con clave distinta a A1 o cuando no existe enajenación en términos del CFF' ], 'horas_extra' => [ '01' => 'Dobles', '02' => 'Triples', '03' => 'Simples' ], 'impuestos' => [ 1 => 'ISR', 2 => 'IVA', 3 => 'IEPS' ], 'incapacidad' => [ 1 => 'Riesgo de trabajo', 2 => 'Enfermedad en general', 3 => 'Maternidad', 4 => 'Licencia por cuidados médicos de hijos diagnosticados con cáncer' ], 'jornada' => [ '01' => 'Diurna', '02' => 'Nocturna', '03' => 'Mixta', '04' => 'Por hora', '05' => 'Reducida', '06' => 'Continuada', '07' => 'Partida', '08' => 'Por turnos', '99' => 'Otra Jornada' ], 'metodo_pago' => [ 'PUE' => 'Pago en una sola exhibición', 'PPD' => 'Pago en parcialidades o diferido' ], 'nomina' => [ 'O' => 'Nómina ordinaria', 'E' => 'Nómina extraordinaria' ], 'objeto_imp' => [ 1 => 'No objeto de impuesto.', 2 => 'Sí objeto de impuesto.', 3 => 'Sí objeto del impuesto y no obligado al desglose.', 4 => 'Sí objeto del impuesto y no causa impuesto.', 5 => 'Sí objeto del impuesto, IVA crédito PODEBI.' ], 'origen_recurso' => [ 'IP' => 'Ingresos propios', 'IF' => 'Ingresos federales', 'IM' => 'Ingresos mixtos' ], 'otro_pago' => [ 1 => 'Reintegro de ISR pagado en exceso', 2 => 'Subsidio para el empleo', 3 => 'Viáticos', 4 => 'Aplicación de saldo a favor por compensación anual', 5 => 'Reintegro de ISR retenido en exceso de ejercicio anterior', 6 => 'Alimentos en bienes', 7 => 'ISR ajustado por subsidio', 8 => 'Subsidio efectivamente entregado que no correspondía', 999 => 'Pagos distintos a los listados' ], 'periodicidad' => [ 1 => 'Diario', 2 => 'Semanal', 3 => 'Quincenal', 4 => 'Mensual', 5 => 'Bimestral' ], 'periodicidad_pago' => [ 1 => 'Diario', 2 => 'Semanal', 3 => 'Catorcenal', 4 => 'Quincenal', 5 => 'Mensual', 6 => 'Bimestral', 7 => 'Unidad obra', 8 => 'Comisión', 9 => 'Precio alzado', 10 => 'Decenal', 99 => 'Otra Periodicidad' ], 'riesgo_puesto' => [ '1' => 'Clase I', '2' => 'Clase II', '3' => 'Clase III', '4' => 'Clase IV', '5' => 'Clase V' ], 'tipo_comprobante' => [ 'I' => 'Ingreso', 'E' => 'Egreso', 'T' => 'Traslado', 'N' => 'Nómina', 'P' => 'Pago' ], 'tipo_factor' => [ 1 => 'Tasa', 2 => 'Cuota', 3 => 'Exento' ], 'tipo_relacion' => [ 1 => 'Nota de crédito de los documentos relacionados', 2 => 'Nota de débito de los documentos relacionados', 3 => 'Devolución de mercancía sobre facturas o traslados previos', 4 => 'Sustitución de los CFDI previos', 5 => 'Traslados de mercancías facturados previamente', 6 => 'Factura generada por los traslados previos', 7 => 'CFDI por aplicación de anticipo' ] ]; public function searchCatalog(string $catalog, string $searchTerm = '', array $options = []): array { // 1. Validar si es un catálogo fijo o uno definido en $this->catalogs if (isset($this->fixedCatalogs[$catalog])) { return $this->fixedCatalogs[$catalog]; } if (!isset($this->catalogs[$catalog])) { return []; } $config = $this->catalogs[$catalog]; // 2. Construye Query Builder base $query = DB::table($config['table']); // 3. Aplica joins if (!empty($config['joins'])) { foreach ($config['joins'] as $join) { $type = $join['type'] ?? 'join'; $query->{$type}($join['table'], function($joinObj) use ($join) { $joinObj->on($join['first'], '=', $join['second']); // Soporte para AND en ON, si está definidio if (!empty($join['and'])) { foreach ((array) $join['and'] as $andCondition) { // 'sat_codigo_postal.c_estado = sat_localidad.c_estado' $parts = explode('=', $andCondition); if (count($parts) === 2) { $left = trim($parts[0]); $right = trim($parts[1]); $joinObj->whereRaw("$left = $right"); } } } }); } } // 4. Construir la lista de columnas a seleccionar $selectFields = []; // - Si hay "columns", añádelas if (!empty($config['columns'])) { foreach ($config['columns'] as $col) { $selectFields[] = DB::raw($col); } } // - Si también tienes "key" y "value" (por ejemplo para select2), // añádelos (si no están ya en columns). if (!empty($config['key'])) { $selectFields[] = DB::raw($config['key']); } if (!empty($config['value'])) { $selectFields[] = DB::raw($config['value']); } // - Si al final no hay nada, por fallback selecciona todo (o lanza un error) if (empty($selectFields)) { $query->select('*'); } else { $query->select($selectFields); } // 5. Filtrado por status si aplica if (($config['use_status'] ?? false) === true) { $status = isset($options['status']) ? $options['status'] : (isset($config['status']) ? $config['status']: null); if ($status !== null) { $query->where('status', $status); } } // 6. Filtrar según extra_conditions (ahora puede incluir columnas de la tabla unida) if (isset($config['extra_conditions'])) { foreach ($config['extra_conditions'] as $field) { if (array_key_exists($field, $options)) { $query->where($field, $options[$field]); } } } // 7. Búsqueda if (!empty($searchTerm) && !empty($config['search_columns'])) { if (($config['search_type'] ?? 'LIKE') === 'MATCH') { // Ejemplo: MATCH..AGAINST $cols = implode(',', $config['search_columns']); $query->whereRaw("MATCH ($cols) AGAINST (? IN BOOLEAN MODE)", [$searchTerm]); } else { // Búsqueda por LIKE $query->where(function ($subQ) use ($config, $searchTerm) { foreach ($config['search_columns'] as $col) { $subQ->orWhere($col, 'LIKE', "%{$searchTerm}%"); } }); } } // 8. Ordenar resultados $orderBy = $options['order_by'] ?? $config['order_by'] ?? $config['key']; $orderDir = $options['order_dir'] ?? $config['order_dir'] ?? 'asc'; $query->orderBy($orderBy, $orderDir); // 9. Limitar $limit = array_key_exists('limit', $options) ? $options['limit'] : ($config['limit'] ?? 50); if ($limit !== null) { $query->limit($limit); } // Para ver la sentencia SQL (con placeholders ?) // dump($query->toSql()); dd($query->getBindings()); // 10. Revisar modo de respuesta $rawMode = ($config['rawMode'] ?? false) || ($options['rawMode'] ?? false); $firstRow = ($config['firstRow'] ?? false) || ($options['firstRow'] ?? false); $select2Mode = $options['select2Mode'] ?? false; // (a) Modo raw -> devolvemos tal cual if ($rawMode) { if($firstRow){ return (array) $query->first(); } return $query->get()->toArray(); } $shortKey = Str::afterLast($config['key'], '.'); // (b) Devuelve en formato "select2" o en un array if ($select2Mode) { $response = []; foreach ($query->get() as $row) { $response[] = [ 'id' => $row->{$shortKey}, 'text' => $row->item, ]; } return $response; } // (c) Por defecto, regresa "pluck" id => texto return $query->pluck('item', $shortKey)->toArray(); } }