mirror of
https://origin.cursor.com/mrdevmx/panels.git
synced 2026-10-09 14:53:18 +00:00
Implement fn_company_list, fn_company_get, fn_company_get_by_code, fn_company_create, fn_company_update, and fn_next_company_code with shared validation helpers mirroring api/companies.ts logic. Uses RPC envelope helpers from 006-rpc-infra.sql with detailed Spanish error messages and GRANT EXECUTE for panels_core_app. Co-authored-by: alberto.martinez <alberto.martinez@mrdev.mx>
639 lines
22 KiB
PL/PgSQL
639 lines
22 KiB
PL/PgSQL
--liquibase formatted sql
|
|
-- PANELS · core · RPC empresas (CRUD)
|
|
|
|
--changeset panel:core-008a-company-helpers endDelimiter:; splitStatements:true
|
|
CREATE OR REPLACE FUNCTION core._company_trim_text(p_value text)
|
|
RETURNS text
|
|
LANGUAGE sql
|
|
IMMUTABLE
|
|
AS $$
|
|
SELECT btrim(COALESCE(p_value, ''));
|
|
$$;
|
|
|
|
CREATE OR REPLACE FUNCTION core._company_norm_code(p_value text)
|
|
RETURNS text
|
|
LANGUAGE sql
|
|
IMMUTABLE
|
|
AS $$
|
|
SELECT upper(regexp_replace(btrim(COALESCE(p_value, '')), '\s+', '', 'g'));
|
|
$$;
|
|
|
|
CREATE OR REPLACE FUNCTION core._company_norm_rfc(p_value text)
|
|
RETURNS text
|
|
LANGUAGE sql
|
|
IMMUTABLE
|
|
AS $$
|
|
SELECT upper(regexp_replace(btrim(COALESCE(p_value, '')), '\s+', '', 'g'));
|
|
$$;
|
|
|
|
CREATE OR REPLACE FUNCTION core._company_code_from_name(p_name text)
|
|
RETURNS text
|
|
LANGUAGE sql
|
|
IMMUTABLE
|
|
AS $$
|
|
SELECT COALESCE(
|
|
NULLIF(
|
|
left(
|
|
upper(
|
|
regexp_replace(
|
|
translate(
|
|
COALESCE(p_name, ''),
|
|
'áàäâãåéèëêíìïîóòöôõúùüûñÁÀÄÂÃÅÉÈËÊÍÌÏÎÓÒÖÔÕÚÙÜÛÑ',
|
|
'aaaaaaeeeeiiiiooooouuuunAAAAAAEEEEIIIIOOOOOUUUUN'
|
|
),
|
|
'[^A-Z0-9]+',
|
|
'',
|
|
'g'
|
|
)
|
|
),
|
|
12
|
|
),
|
|
''
|
|
),
|
|
'EMP'
|
|
);
|
|
$$;
|
|
|
|
CREATE OR REPLACE FUNCTION core._company_validate_code(p_code text)
|
|
RETURNS text
|
|
LANGUAGE plpgsql
|
|
IMMUTABLE
|
|
AS $$
|
|
BEGIN
|
|
IF p_code IS NULL OR p_code = '' THEN
|
|
RETURN 'Código de 2 a 16 caracteres (letras, números, _ o -)';
|
|
END IF;
|
|
IF p_code !~ '^[A-Z0-9][A-Z0-9_-]{1,15}$' THEN
|
|
RETURN 'Código de 2 a 16 caracteres (letras, números, _ o -)';
|
|
END IF;
|
|
RETURN NULL;
|
|
END;
|
|
$$;
|
|
|
|
CREATE OR REPLACE FUNCTION core._company_validate_profile(
|
|
p_payload jsonb,
|
|
p_require_legal boolean DEFAULT false
|
|
)
|
|
RETURNS text
|
|
LANGUAGE plpgsql
|
|
IMMUTABLE
|
|
AS $$
|
|
DECLARE
|
|
v_rfc text := core._company_norm_rfc(p_payload->>'rfc');
|
|
v_clase text := upper(core._company_trim_text(p_payload->>'clase_riesgo'));
|
|
BEGIN
|
|
IF v_rfc <> '' AND v_rfc !~ '^[A-ZÑ&]{3,4}\d{6}[A-Z0-9]{3}$' THEN
|
|
RETURN 'RFC inválido (formato mexicano de 12 o 13 caracteres)';
|
|
END IF;
|
|
IF p_require_legal THEN
|
|
IF core._company_trim_text(p_payload->>'razon_social') = ''
|
|
AND core._company_trim_text(p_payload->>'name') = ''
|
|
AND core._company_trim_text(p_payload->>'nombre_comercial') = '' THEN
|
|
RETURN 'Indique razón social o nombre comercial';
|
|
END IF;
|
|
END IF;
|
|
IF v_clase <> '' AND v_clase NOT IN ('I', 'II', 'III', 'IV', 'V') THEN
|
|
RETURN 'Clase de riesgo IMSS debe ser I, II, III, IV o V';
|
|
END IF;
|
|
RETURN NULL;
|
|
END;
|
|
$$;
|
|
|
|
CREATE OR REPLACE FUNCTION core._company_normalize_profile(
|
|
p_payload jsonb,
|
|
p_fallback_name text DEFAULT ''
|
|
)
|
|
RETURNS jsonb
|
|
LANGUAGE plpgsql
|
|
IMMUTABLE
|
|
AS $$
|
|
DECLARE
|
|
v_nombre_comercial text;
|
|
v_razon_social text;
|
|
v_name text;
|
|
BEGIN
|
|
v_nombre_comercial := COALESCE(
|
|
NULLIF(core._company_trim_text(p_payload->>'nombre_comercial'), ''),
|
|
NULLIF(core._company_trim_text(p_payload->>'name'), ''),
|
|
p_fallback_name
|
|
);
|
|
v_razon_social := COALESCE(
|
|
NULLIF(core._company_trim_text(p_payload->>'razon_social'), ''),
|
|
NULLIF(v_nombre_comercial, ''),
|
|
p_fallback_name
|
|
);
|
|
v_name := COALESCE(
|
|
NULLIF(core._company_trim_text(p_payload->>'name'), ''),
|
|
NULLIF(v_nombre_comercial, ''),
|
|
NULLIF(v_razon_social, ''),
|
|
p_fallback_name
|
|
);
|
|
RETURN jsonb_build_object(
|
|
'name', v_name,
|
|
'nombre_comercial', v_nombre_comercial,
|
|
'razon_social', v_razon_social,
|
|
'rfc', core._company_norm_rfc(p_payload->>'rfc'),
|
|
'regimen_fiscal', core._company_trim_text(p_payload->>'regimen_fiscal'),
|
|
'registro_patronal', upper(core._company_trim_text(p_payload->>'registro_patronal')),
|
|
'clase_riesgo', upper(core._company_trim_text(p_payload->>'clase_riesgo')),
|
|
'domicilio_fiscal', core._company_trim_text(p_payload->>'domicilio_fiscal'),
|
|
'codigo_postal', core._company_trim_text(p_payload->>'codigo_postal'),
|
|
'ciudad', core._company_trim_text(p_payload->>'ciudad'),
|
|
'estado', core._company_trim_text(p_payload->>'estado'),
|
|
'telefono', core._company_trim_text(p_payload->>'telefono'),
|
|
'email', lower(core._company_trim_text(p_payload->>'email')),
|
|
'representante_legal', core._company_trim_text(p_payload->>'representante_legal'),
|
|
'giro', core._company_trim_text(p_payload->>'giro')
|
|
);
|
|
END;
|
|
$$;
|
|
|
|
--changeset panel:core-008b-fn-company-list endDelimiter:; splitStatements:true
|
|
CREATE OR REPLACE FUNCTION core.fn_company_list(payload jsonb)
|
|
RETURNS jsonb
|
|
LANGUAGE plpgsql
|
|
SECURITY INVOKER
|
|
SET search_path = core
|
|
AS $$
|
|
DECLARE
|
|
v_tid integer := NULLIF(payload->>'tenant_id', '')::integer;
|
|
v_companies jsonb;
|
|
v_count integer;
|
|
BEGIN
|
|
SELECT COALESCE(
|
|
jsonb_agg(row_to_json(x)::jsonb ORDER BY
|
|
CASE x.kind WHEN 'principal' THEN 0 ELSE 1 END,
|
|
lower(x.name)),
|
|
'[]'::jsonb
|
|
),
|
|
COUNT(*)::integer
|
|
INTO v_companies, v_count
|
|
FROM (
|
|
SELECT c.*,
|
|
p.code AS parent_code,
|
|
p.name AS parent_name,
|
|
(SELECT COUNT(*) FROM workers w WHERE w.company_id = c.id) AS worker_count
|
|
FROM companies c
|
|
LEFT JOIN companies p ON p.id = c.parent_id
|
|
WHERE v_tid IS NULL OR c.tenant_id = v_tid
|
|
) x;
|
|
RETURN core.rpc_ok(
|
|
jsonb_build_object('companies', v_companies),
|
|
format('Listado de empresas: %s registro(s)%s',
|
|
v_count,
|
|
CASE WHEN v_tid IS NOT NULL THEN format(' para tenant_id=%s', v_tid) ELSE '' END),
|
|
jsonb_build_object('fn', 'fn_company_list', 'tenant_id', v_tid, 'count', v_count)
|
|
);
|
|
EXCEPTION WHEN OTHERS THEN
|
|
RETURN core.rpc_from_exception('fn_company_list', SQLSTATE, SQLERRM);
|
|
END;
|
|
$$;
|
|
|
|
--changeset panel:core-008c-fn-company-get endDelimiter:; splitStatements:true
|
|
CREATE OR REPLACE FUNCTION core.fn_company_get(payload jsonb)
|
|
RETURNS jsonb
|
|
LANGUAGE plpgsql
|
|
SECURITY INVOKER
|
|
SET search_path = core
|
|
AS $$
|
|
DECLARE
|
|
v_id bigint := NULLIF(payload->>'id', '')::bigint;
|
|
v_tid integer := NULLIF(payload->>'tenant_id', '')::integer;
|
|
v_company jsonb;
|
|
BEGIN
|
|
IF v_id IS NULL THEN
|
|
RETURN core.rpc_err(
|
|
'VALIDATION',
|
|
'fn_company_get: id es obligatorio para consultar una empresa',
|
|
jsonb_build_object('fn', 'fn_company_get', 'field', 'id')
|
|
);
|
|
END IF;
|
|
SELECT to_jsonb(c) INTO v_company
|
|
FROM companies c
|
|
WHERE c.id = v_id
|
|
AND (v_tid IS NULL OR c.tenant_id IS NULL OR c.tenant_id = v_tid);
|
|
IF v_company IS NULL THEN
|
|
RETURN core.rpc_err(
|
|
'NOT_FOUND',
|
|
format('fn_company_get: empresa id=%s no encontrada%s', v_id,
|
|
CASE WHEN v_tid IS NOT NULL THEN format(' en tenant_id=%s', v_tid) ELSE '' END),
|
|
jsonb_build_object('fn', 'fn_company_get', 'id', v_id, 'tenant_id', v_tid)
|
|
);
|
|
END IF;
|
|
RETURN core.rpc_ok(
|
|
jsonb_build_object('company', v_company),
|
|
format('Empresa id=%s cargada (%s)', v_id, v_company->>'code'),
|
|
jsonb_build_object('fn', 'fn_company_get', 'id', v_id)
|
|
);
|
|
EXCEPTION WHEN OTHERS THEN
|
|
RETURN core.rpc_from_exception('fn_company_get', SQLSTATE, SQLERRM);
|
|
END;
|
|
$$;
|
|
|
|
--changeset panel:core-008d-fn-company-get-by-code endDelimiter:; splitStatements:true
|
|
CREATE OR REPLACE FUNCTION core.fn_company_get_by_code(payload jsonb)
|
|
RETURNS jsonb
|
|
LANGUAGE plpgsql
|
|
SECURITY INVOKER
|
|
SET search_path = core
|
|
AS $$
|
|
DECLARE
|
|
v_code text := core._company_norm_code(payload->>'code');
|
|
v_company jsonb;
|
|
BEGIN
|
|
IF v_code = '' THEN
|
|
RETURN core.rpc_err(
|
|
'VALIDATION',
|
|
'fn_company_get_by_code: code es obligatorio para consultar una empresa',
|
|
jsonb_build_object('fn', 'fn_company_get_by_code', 'field', 'code')
|
|
);
|
|
END IF;
|
|
SELECT to_jsonb(c) INTO v_company
|
|
FROM companies c
|
|
WHERE c.code = v_code;
|
|
IF v_company IS NULL THEN
|
|
RETURN core.rpc_err(
|
|
'NOT_FOUND',
|
|
format('fn_company_get_by_code: empresa con código %s no encontrada', v_code),
|
|
jsonb_build_object('fn', 'fn_company_get_by_code', 'code', v_code)
|
|
);
|
|
END IF;
|
|
RETURN core.rpc_ok(
|
|
jsonb_build_object('company', v_company),
|
|
format('Empresa con código %s cargada (id=%s)', v_code, v_company->>'id'),
|
|
jsonb_build_object('fn', 'fn_company_get_by_code', 'code', v_code)
|
|
);
|
|
EXCEPTION WHEN OTHERS THEN
|
|
RETURN core.rpc_from_exception('fn_company_get_by_code', SQLSTATE, SQLERRM);
|
|
END;
|
|
$$;
|
|
|
|
--changeset panel:core-008e-fn-next-company-code endDelimiter:; splitStatements:true
|
|
CREATE OR REPLACE FUNCTION core.fn_next_company_code(payload jsonb)
|
|
RETURNS jsonb
|
|
LANGUAGE plpgsql
|
|
SECURITY INVOKER
|
|
SET search_path = core
|
|
AS $$
|
|
DECLARE
|
|
v_name text := core._company_trim_text(payload->>'name');
|
|
v_base text;
|
|
v_n integer;
|
|
v_code text;
|
|
BEGIN
|
|
IF v_name = '' THEN
|
|
RETURN core.rpc_err(
|
|
'VALIDATION',
|
|
'fn_next_company_code: name es obligatorio para generar un código de empresa',
|
|
jsonb_build_object('fn', 'fn_next_company_code', 'field', 'name')
|
|
);
|
|
END IF;
|
|
v_base := core._company_code_from_name(v_name);
|
|
IF NOT EXISTS (SELECT 1 FROM companies WHERE code = v_base) THEN
|
|
v_code := v_base;
|
|
ELSE
|
|
SELECT COALESCE(MAX(substring(code FROM 5)::integer), 0) + 1
|
|
INTO v_n
|
|
FROM companies
|
|
WHERE code ~ '^EMP-[0-9]{4}';
|
|
v_code := 'EMP-' || lpad(v_n::text, 4, '0');
|
|
END IF;
|
|
RETURN core.rpc_ok(
|
|
jsonb_build_object('code', v_code),
|
|
format('Código sugerido para "%s": %s', v_name, v_code),
|
|
jsonb_build_object('fn', 'fn_next_company_code', 'name', v_name, 'code', v_code)
|
|
);
|
|
EXCEPTION WHEN OTHERS THEN
|
|
RETURN core.rpc_from_exception('fn_next_company_code', SQLSTATE, SQLERRM);
|
|
END;
|
|
$$;
|
|
|
|
--changeset panel:core-008f-fn-company-create endDelimiter:; splitStatements:true
|
|
CREATE OR REPLACE FUNCTION core.fn_company_create(payload jsonb)
|
|
RETURNS jsonb
|
|
LANGUAGE plpgsql
|
|
SECURITY INVOKER
|
|
SET search_path = core
|
|
AS $$
|
|
DECLARE
|
|
v_tid integer := NULLIF(payload->>'tenant_id', '')::integer;
|
|
v_profile_err text;
|
|
v_profile jsonb;
|
|
v_principal companies%ROWTYPE;
|
|
v_parent_id bigint;
|
|
v_parent companies%ROWTYPE;
|
|
v_code text;
|
|
v_code_err text;
|
|
v_new_id bigint;
|
|
v_n integer;
|
|
v_company jsonb;
|
|
BEGIN
|
|
v_profile_err := core._company_validate_profile(payload, true);
|
|
IF v_profile_err IS NOT NULL THEN
|
|
RETURN core.rpc_err(
|
|
'VALIDATION',
|
|
format('fn_company_create: %s', v_profile_err),
|
|
jsonb_build_object('fn', 'fn_company_create', 'field', 'profile')
|
|
);
|
|
END IF;
|
|
|
|
v_profile := core._company_normalize_profile(payload, '');
|
|
IF core._company_trim_text(v_profile->>'name') = '' THEN
|
|
RETURN core.rpc_err(
|
|
'VALIDATION',
|
|
'fn_company_create: nombre de empresa obligatorio',
|
|
jsonb_build_object('fn', 'fn_company_create', 'field', 'name')
|
|
);
|
|
END IF;
|
|
|
|
IF v_tid IS NOT NULL THEN
|
|
SELECT * INTO v_principal
|
|
FROM companies
|
|
WHERE kind = 'principal' AND tenant_id = v_tid
|
|
ORDER BY id
|
|
LIMIT 1;
|
|
ELSE
|
|
SELECT * INTO v_principal
|
|
FROM companies
|
|
WHERE kind = 'principal'
|
|
ORDER BY id
|
|
LIMIT 1;
|
|
END IF;
|
|
IF NOT FOUND THEN
|
|
RETURN core.rpc_err(
|
|
'VALIDATION',
|
|
'fn_company_create: no hay empresa principal configurada en el tenant',
|
|
jsonb_build_object('fn', 'fn_company_create', 'tenant_id', v_tid)
|
|
);
|
|
END IF;
|
|
|
|
v_parent_id := COALESCE(NULLIF(payload->>'parent_id', '')::bigint, v_principal.id);
|
|
SELECT * INTO v_parent FROM companies WHERE id = v_parent_id;
|
|
IF NOT FOUND THEN
|
|
RETURN core.rpc_err(
|
|
'VALIDATION',
|
|
format('fn_company_create: empresa padre id=%s no encontrada', v_parent_id),
|
|
jsonb_build_object('fn', 'fn_company_create', 'parent_id', v_parent_id)
|
|
);
|
|
END IF;
|
|
IF v_tid IS NOT NULL AND v_parent.tenant_id IS NOT NULL AND v_parent.tenant_id <> v_tid THEN
|
|
RETURN core.rpc_err(
|
|
'VALIDATION',
|
|
format('fn_company_create: empresa padre id=%s pertenece a tenant_id=%s, distinto del solicitado (%s)',
|
|
v_parent_id, v_parent.tenant_id, v_tid),
|
|
jsonb_build_object('fn', 'fn_company_create', 'parent_id', v_parent_id, 'tenant_id', v_tid)
|
|
);
|
|
END IF;
|
|
|
|
v_code := core._company_norm_code(payload->>'code');
|
|
IF v_code = '' THEN
|
|
v_code := core._company_code_from_name(v_profile->>'name');
|
|
IF EXISTS (SELECT 1 FROM companies WHERE code = v_code) THEN
|
|
SELECT COALESCE(MAX(substring(code FROM 5)::integer), 0) + 1
|
|
INTO v_n
|
|
FROM companies
|
|
WHERE code ~ '^EMP-[0-9]{4}';
|
|
v_code := 'EMP-' || lpad(v_n::text, 4, '0');
|
|
END IF;
|
|
END IF;
|
|
v_code_err := core._company_validate_code(v_code);
|
|
IF v_code_err IS NOT NULL THEN
|
|
RETURN core.rpc_err(
|
|
'VALIDATION',
|
|
format('fn_company_create: %s (código=%s)', v_code_err, v_code),
|
|
jsonb_build_object('fn', 'fn_company_create', 'field', 'code', 'code', v_code)
|
|
);
|
|
END IF;
|
|
IF EXISTS (SELECT 1 FROM companies WHERE code = v_code) THEN
|
|
RETURN core.rpc_err(
|
|
'CONFLICT',
|
|
format('fn_company_create: ya existe una empresa con el código %s', v_code),
|
|
jsonb_build_object('fn', 'fn_company_create', 'code', v_code)
|
|
);
|
|
END IF;
|
|
|
|
INSERT INTO companies (
|
|
code, name, parent_id, kind, status, tenant_id,
|
|
registro_patronal, razon_social, nombre_comercial, rfc, regimen_fiscal, clase_riesgo,
|
|
domicilio_fiscal, codigo_postal, ciudad, estado, telefono, email, representante_legal, giro
|
|
) VALUES (
|
|
v_code,
|
|
v_profile->>'name',
|
|
v_parent.id,
|
|
'sub',
|
|
'activo',
|
|
COALESCE(v_tid, v_principal.tenant_id),
|
|
v_profile->>'registro_patronal',
|
|
v_profile->>'razon_social',
|
|
v_profile->>'nombre_comercial',
|
|
v_profile->>'rfc',
|
|
v_profile->>'regimen_fiscal',
|
|
v_profile->>'clase_riesgo',
|
|
v_profile->>'domicilio_fiscal',
|
|
v_profile->>'codigo_postal',
|
|
v_profile->>'ciudad',
|
|
v_profile->>'estado',
|
|
v_profile->>'telefono',
|
|
v_profile->>'email',
|
|
v_profile->>'representante_legal',
|
|
v_profile->>'giro'
|
|
)
|
|
RETURNING id INTO v_new_id;
|
|
|
|
SELECT to_jsonb(c) INTO v_company FROM companies c WHERE c.id = v_new_id;
|
|
RETURN core.rpc_created(
|
|
jsonb_build_object('company', v_company),
|
|
format('Subempresa creada: %s (%s), id=%s', v_company->>'name', v_code, v_new_id),
|
|
jsonb_build_object('fn', 'fn_company_create', 'id', v_new_id, 'code', v_code, 'parent_id', v_parent.id)
|
|
);
|
|
EXCEPTION
|
|
WHEN unique_violation THEN
|
|
RETURN core.rpc_err(
|
|
'CONFLICT',
|
|
format('fn_company_create: ya existe una empresa con el código %s', v_code),
|
|
jsonb_build_object('fn', 'fn_company_create', 'code', v_code)
|
|
);
|
|
WHEN OTHERS THEN
|
|
RETURN core.rpc_from_exception('fn_company_create', SQLSTATE, SQLERRM);
|
|
END;
|
|
$$;
|
|
|
|
--changeset panel:core-008g-fn-company-update endDelimiter:; splitStatements:true
|
|
CREATE OR REPLACE FUNCTION core.fn_company_update(payload jsonb)
|
|
RETURNS jsonb
|
|
LANGUAGE plpgsql
|
|
SECURITY INVOKER
|
|
SET search_path = core
|
|
AS $$
|
|
DECLARE
|
|
v_id bigint := NULLIF(payload->>'id', '')::bigint;
|
|
v_tid integer := NULLIF(payload->>'tenant_id', '')::integer;
|
|
v_current companies%ROWTYPE;
|
|
v_merged jsonb;
|
|
v_profile_err text;
|
|
v_profile jsonb;
|
|
v_code text;
|
|
v_code_err text;
|
|
v_status text;
|
|
v_clash_id bigint;
|
|
v_company jsonb;
|
|
BEGIN
|
|
IF v_id IS NULL THEN
|
|
RETURN core.rpc_err(
|
|
'VALIDATION',
|
|
'fn_company_update: id es obligatorio para actualizar una empresa',
|
|
jsonb_build_object('fn', 'fn_company_update', 'field', 'id')
|
|
);
|
|
END IF;
|
|
|
|
SELECT * INTO v_current FROM companies WHERE id = v_id;
|
|
IF NOT FOUND THEN
|
|
RETURN core.rpc_err(
|
|
'NOT_FOUND',
|
|
format('fn_company_update: empresa id=%s no encontrada', v_id),
|
|
jsonb_build_object('fn', 'fn_company_update', 'id', v_id, 'tenant_id', v_tid)
|
|
);
|
|
END IF;
|
|
IF v_tid IS NOT NULL AND v_current.tenant_id IS NOT NULL AND v_current.tenant_id <> v_tid THEN
|
|
RETURN core.rpc_err(
|
|
'NOT_FOUND',
|
|
format('fn_company_update: empresa id=%s no encontrada en tenant_id=%s', v_id, v_tid),
|
|
jsonb_build_object('fn', 'fn_company_update', 'id', v_id, 'tenant_id', v_tid)
|
|
);
|
|
END IF;
|
|
|
|
v_merged := jsonb_build_object(
|
|
'name', CASE WHEN payload ? 'name' THEN payload->>'name' ELSE v_current.name END,
|
|
'code', CASE WHEN payload ? 'code' THEN payload->>'code' ELSE v_current.code END,
|
|
'status', CASE WHEN payload ? 'status' THEN payload->>'status' ELSE v_current.status END,
|
|
'registro_patronal', CASE WHEN payload ? 'registro_patronal' THEN payload->>'registro_patronal' ELSE v_current.registro_patronal END,
|
|
'razon_social', CASE WHEN payload ? 'razon_social' THEN payload->>'razon_social' ELSE v_current.razon_social END,
|
|
'nombre_comercial', CASE WHEN payload ? 'nombre_comercial' THEN payload->>'nombre_comercial' ELSE v_current.nombre_comercial END,
|
|
'rfc', CASE WHEN payload ? 'rfc' THEN payload->>'rfc' ELSE v_current.rfc END,
|
|
'regimen_fiscal', CASE WHEN payload ? 'regimen_fiscal' THEN payload->>'regimen_fiscal' ELSE v_current.regimen_fiscal END,
|
|
'clase_riesgo', CASE WHEN payload ? 'clase_riesgo' THEN payload->>'clase_riesgo' ELSE v_current.clase_riesgo END,
|
|
'domicilio_fiscal', CASE WHEN payload ? 'domicilio_fiscal' THEN payload->>'domicilio_fiscal' ELSE v_current.domicilio_fiscal END,
|
|
'codigo_postal', CASE WHEN payload ? 'codigo_postal' THEN payload->>'codigo_postal' ELSE v_current.codigo_postal END,
|
|
'ciudad', CASE WHEN payload ? 'ciudad' THEN payload->>'ciudad' ELSE v_current.ciudad END,
|
|
'estado', CASE WHEN payload ? 'estado' THEN payload->>'estado' ELSE v_current.estado END,
|
|
'telefono', CASE WHEN payload ? 'telefono' THEN payload->>'telefono' ELSE v_current.telefono END,
|
|
'email', CASE WHEN payload ? 'email' THEN payload->>'email' ELSE v_current.email END,
|
|
'representante_legal', CASE WHEN payload ? 'representante_legal' THEN payload->>'representante_legal' ELSE v_current.representante_legal END,
|
|
'giro', CASE WHEN payload ? 'giro' THEN payload->>'giro' ELSE v_current.giro END
|
|
);
|
|
|
|
v_profile_err := core._company_validate_profile(v_merged, false);
|
|
IF v_profile_err IS NOT NULL THEN
|
|
RETURN core.rpc_err(
|
|
'VALIDATION',
|
|
format('fn_company_update: %s (id=%s)', v_profile_err, v_id),
|
|
jsonb_build_object('fn', 'fn_company_update', 'id', v_id, 'field', 'profile')
|
|
);
|
|
END IF;
|
|
|
|
v_profile := core._company_normalize_profile(v_merged, v_current.name);
|
|
IF core._company_trim_text(v_profile->>'name') = '' THEN
|
|
RETURN core.rpc_err(
|
|
'VALIDATION',
|
|
format('fn_company_update: nombre de empresa obligatorio (id=%s)', v_id),
|
|
jsonb_build_object('fn', 'fn_company_update', 'id', v_id, 'field', 'name')
|
|
);
|
|
END IF;
|
|
|
|
v_code := v_current.code;
|
|
IF payload ? 'code' THEN
|
|
v_code := core._company_norm_code(payload->>'code');
|
|
v_code_err := core._company_validate_code(v_code);
|
|
IF v_code_err IS NOT NULL THEN
|
|
RETURN core.rpc_err(
|
|
'VALIDATION',
|
|
format('fn_company_update: %s (id=%s, código=%s)', v_code_err, v_id, v_code),
|
|
jsonb_build_object('fn', 'fn_company_update', 'id', v_id, 'field', 'code', 'code', v_code)
|
|
);
|
|
END IF;
|
|
SELECT id INTO v_clash_id FROM companies WHERE code = v_code AND id <> v_id;
|
|
IF FOUND THEN
|
|
RETURN core.rpc_err(
|
|
'CONFLICT',
|
|
format('fn_company_update: ya existe otra empresa con el código %s (id=%s)', v_code, v_clash_id),
|
|
jsonb_build_object('fn', 'fn_company_update', 'id', v_id, 'code', v_code, 'conflict_id', v_clash_id)
|
|
);
|
|
END IF;
|
|
END IF;
|
|
|
|
v_status := v_current.status;
|
|
IF payload ? 'status' THEN
|
|
IF (payload->>'status') NOT IN ('activo', 'inactivo') THEN
|
|
RETURN core.rpc_err(
|
|
'VALIDATION',
|
|
format('fn_company_update: estatus debe ser activo o inactivo (recibido=%s, id=%s)',
|
|
payload->>'status', v_id),
|
|
jsonb_build_object('fn', 'fn_company_update', 'id', v_id, 'field', 'status', 'status', payload->>'status')
|
|
);
|
|
END IF;
|
|
IF v_current.kind = 'principal' AND payload->>'status' = 'inactivo' THEN
|
|
RETURN core.rpc_err(
|
|
'VALIDATION',
|
|
format('fn_company_update: la empresa principal id=%s no se puede inactivar', v_id),
|
|
jsonb_build_object('fn', 'fn_company_update', 'id', v_id, 'kind', v_current.kind)
|
|
);
|
|
END IF;
|
|
v_status := payload->>'status';
|
|
END IF;
|
|
|
|
UPDATE companies SET
|
|
name = v_profile->>'name',
|
|
code = v_code,
|
|
status = v_status,
|
|
registro_patronal = v_profile->>'registro_patronal',
|
|
razon_social = v_profile->>'razon_social',
|
|
nombre_comercial = v_profile->>'nombre_comercial',
|
|
rfc = v_profile->>'rfc',
|
|
regimen_fiscal = v_profile->>'regimen_fiscal',
|
|
clase_riesgo = v_profile->>'clase_riesgo',
|
|
domicilio_fiscal = v_profile->>'domicilio_fiscal',
|
|
codigo_postal = v_profile->>'codigo_postal',
|
|
ciudad = v_profile->>'ciudad',
|
|
estado = v_profile->>'estado',
|
|
telefono = v_profile->>'telefono',
|
|
email = v_profile->>'email',
|
|
representante_legal = v_profile->>'representante_legal',
|
|
giro = v_profile->>'giro'
|
|
WHERE id = v_id;
|
|
|
|
IF v_code <> v_current.code THEN
|
|
UPDATE workers SET hire_type = v_code WHERE company_id = v_id;
|
|
END IF;
|
|
|
|
SELECT to_jsonb(c) INTO v_company FROM companies c WHERE c.id = v_id;
|
|
RETURN core.rpc_ok(
|
|
jsonb_build_object('company', v_company),
|
|
format('Empresa id=%s actualizada (%s)', v_id, v_code),
|
|
jsonb_build_object('fn', 'fn_company_update', 'id', v_id, 'code', v_code)
|
|
);
|
|
EXCEPTION
|
|
WHEN unique_violation THEN
|
|
RETURN core.rpc_err(
|
|
'CONFLICT',
|
|
format('fn_company_update: ya existe una empresa con el código %s (id=%s)', v_code, v_id),
|
|
jsonb_build_object('fn', 'fn_company_update', 'id', v_id, 'code', v_code)
|
|
);
|
|
WHEN OTHERS THEN
|
|
RETURN core.rpc_from_exception('fn_company_update', SQLSTATE, SQLERRM);
|
|
END;
|
|
$$;
|
|
|
|
--changeset panel:core-008h-fn-companies-grants endDelimiter:; splitStatements:true
|
|
GRANT EXECUTE ON FUNCTION core._company_trim_text(text) TO panels_core_app;
|
|
GRANT EXECUTE ON FUNCTION core._company_norm_code(text) TO panels_core_app;
|
|
GRANT EXECUTE ON FUNCTION core._company_norm_rfc(text) TO panels_core_app;
|
|
GRANT EXECUTE ON FUNCTION core._company_code_from_name(text) TO panels_core_app;
|
|
GRANT EXECUTE ON FUNCTION core._company_validate_code(text) TO panels_core_app;
|
|
GRANT EXECUTE ON FUNCTION core._company_validate_profile(jsonb, boolean) TO panels_core_app;
|
|
GRANT EXECUTE ON FUNCTION core._company_normalize_profile(jsonb, text) TO panels_core_app;
|
|
GRANT EXECUTE ON FUNCTION core.fn_company_list(jsonb) TO panels_core_app;
|
|
GRANT EXECUTE ON FUNCTION core.fn_company_get(jsonb) TO panels_core_app;
|
|
GRANT EXECUTE ON FUNCTION core.fn_company_get_by_code(jsonb) TO panels_core_app;
|
|
GRANT EXECUTE ON FUNCTION core.fn_next_company_code(jsonb) TO panels_core_app;
|
|
GRANT EXECUTE ON FUNCTION core.fn_company_create(jsonb) TO panels_core_app;
|
|
GRANT EXECUTE ON FUNCTION core.fn_company_update(jsonb) TO panels_core_app;
|