423 lines
17 KiB
PL/PgSQL
423 lines
17 KiB
PL/PgSQL
-- =========================================================
|
||
-- TABLERO CDC - TARIFARIO FIJO WALMART CONNECT
|
||
-- Versión segura para producción.
|
||
--
|
||
-- Qué hace:
|
||
-- 1) Habilita la sección "wmc" en el catálogo dinámico existente.
|
||
-- 2) Inserta/actualiza las 12 piezas y montos del Excel Tarifario_XCDC_WMC.
|
||
-- 3) Mantiene intactos proyectos, costos históricos, links, listas, n8n y tarifas CDC existentes.
|
||
-- 4) Permite administrar el catálogo a usuarios activos con can_manage_internal_pricing = true.
|
||
-- 5) Protege las tarifas WMC de una futura desactivación masiva del sync del tarifario estándar.
|
||
--
|
||
-- Puede ejecutarse más de una vez: usa CREATE IF NOT EXISTS y UPSERT.
|
||
-- =========================================================
|
||
|
||
begin;
|
||
|
||
-- 1) Asegurar la tabla del catálogo dinámico.
|
||
create table if not exists public.tablero_cdc_tariff_catalog (
|
||
id text primary key,
|
||
catalog_item_id text not null,
|
||
section text not null,
|
||
category text not null default '',
|
||
service text not null default '',
|
||
notes text not null default '',
|
||
work_type_id text not null default 'reference',
|
||
work_type_label text not null default 'Referencia',
|
||
work_type_short_label text not null default 'Ref.',
|
||
hour_reference text not null default '',
|
||
level_id text not null default 'project',
|
||
level_label text not null default 'Precio único',
|
||
reference text not null default '',
|
||
reference_min numeric,
|
||
reference_max numeric,
|
||
level_hint text not null default '',
|
||
sort_order integer not null default 9999,
|
||
is_active boolean not null default true,
|
||
created_by uuid references auth.users(id),
|
||
updated_by uuid references auth.users(id),
|
||
created_at timestamptz not null default now(),
|
||
updated_at timestamptz not null default now()
|
||
);
|
||
|
||
-- Compatibilidad con instalaciones donde alguna columna todavía no exista.
|
||
alter table public.tablero_cdc_tariff_catalog
|
||
add column if not exists catalog_item_id text,
|
||
add column if not exists section text,
|
||
add column if not exists category text not null default '',
|
||
add column if not exists service text not null default '',
|
||
add column if not exists notes text not null default '',
|
||
add column if not exists work_type_id text not null default 'reference',
|
||
add column if not exists work_type_label text not null default 'Referencia',
|
||
add column if not exists work_type_short_label text not null default 'Ref.',
|
||
add column if not exists hour_reference text not null default '',
|
||
add column if not exists level_id text not null default 'project',
|
||
add column if not exists level_label text not null default 'Precio único',
|
||
add column if not exists reference text not null default '',
|
||
add column if not exists reference_min numeric,
|
||
add column if not exists reference_max numeric,
|
||
add column if not exists level_hint text not null default '',
|
||
add column if not exists sort_order integer not null default 9999,
|
||
add column if not exists is_active boolean not null default true,
|
||
add column if not exists created_by uuid references auth.users(id),
|
||
add column if not exists updated_by uuid references auth.users(id),
|
||
add column if not exists created_at timestamptz not null default now(),
|
||
add column if not exists updated_at timestamptz not null default now();
|
||
|
||
-- Completar valores obligatorios si la tabla venía de una versión antigua.
|
||
update public.tablero_cdc_tariff_catalog
|
||
set
|
||
catalog_item_id = coalesce(nullif(trim(catalog_item_id), ''), id),
|
||
section = case
|
||
when lower(trim(coalesce(section, ''))) in ('grafico', 'estrategia', 'wmc')
|
||
then lower(trim(section))
|
||
else 'grafico'
|
||
end
|
||
where catalog_item_id is null
|
||
or nullif(trim(catalog_item_id), '') is null
|
||
or section is null
|
||
or lower(trim(section)) not in ('grafico', 'estrategia', 'wmc');
|
||
|
||
alter table public.tablero_cdc_tariff_catalog
|
||
alter column catalog_item_id set not null,
|
||
alter column section set not null;
|
||
|
||
-- Reemplazar el check antiguo que solo permitía grafico/estrategia.
|
||
alter table public.tablero_cdc_tariff_catalog
|
||
drop constraint if exists tablero_cdc_tariff_catalog_section_check;
|
||
|
||
alter table public.tablero_cdc_tariff_catalog
|
||
add constraint tablero_cdc_tariff_catalog_section_check
|
||
check (section in ('grafico', 'estrategia', 'wmc'));
|
||
|
||
create index if not exists tablero_cdc_tariff_catalog_section_idx
|
||
on public.tablero_cdc_tariff_catalog(section, is_active, sort_order);
|
||
|
||
create index if not exists tablero_cdc_tariff_catalog_item_idx
|
||
on public.tablero_cdc_tariff_catalog(catalog_item_id);
|
||
|
||
-- 2) RLS: lectura para usuarios autenticados y escritura para quienes pueden tarifar.
|
||
alter table public.tablero_cdc_tariff_catalog enable row level security;
|
||
|
||
create or replace function public.tablero_cdc_current_user_can_manage_internal_pricing()
|
||
returns boolean
|
||
language sql
|
||
stable
|
||
security definer
|
||
set search_path = public
|
||
as $$
|
||
select exists (
|
||
select 1
|
||
from public.tablero_cdc_allowed_users u
|
||
where lower(trim(u.email)) = lower(trim(coalesce(auth.jwt() ->> 'email', '')))
|
||
and u.is_active = true
|
||
and u.can_manage_internal_pricing = true
|
||
);
|
||
$$;
|
||
|
||
grant execute on function public.tablero_cdc_current_user_can_manage_internal_pricing()
|
||
to authenticated;
|
||
|
||
drop policy if exists "tablero_cdc_tariff_catalog_select_authenticated"
|
||
on public.tablero_cdc_tariff_catalog;
|
||
drop policy if exists "tablero_cdc_tariff_catalog_insert_pricing_admins"
|
||
on public.tablero_cdc_tariff_catalog;
|
||
drop policy if exists "tablero_cdc_tariff_catalog_update_pricing_admins"
|
||
on public.tablero_cdc_tariff_catalog;
|
||
drop policy if exists "tablero_cdc_tariff_catalog_delete_pricing_admins"
|
||
on public.tablero_cdc_tariff_catalog;
|
||
|
||
create policy "tablero_cdc_tariff_catalog_select_authenticated"
|
||
on public.tablero_cdc_tariff_catalog
|
||
for select
|
||
to authenticated
|
||
using (true);
|
||
|
||
create policy "tablero_cdc_tariff_catalog_insert_pricing_admins"
|
||
on public.tablero_cdc_tariff_catalog
|
||
for insert
|
||
to authenticated
|
||
with check (public.tablero_cdc_current_user_can_manage_internal_pricing());
|
||
|
||
create policy "tablero_cdc_tariff_catalog_update_pricing_admins"
|
||
on public.tablero_cdc_tariff_catalog
|
||
for update
|
||
to authenticated
|
||
using (public.tablero_cdc_current_user_can_manage_internal_pricing())
|
||
with check (public.tablero_cdc_current_user_can_manage_internal_pricing());
|
||
|
||
-- No se recomienda borrar tarifas usadas históricamente; se deben desactivar.
|
||
create policy "tablero_cdc_tariff_catalog_delete_pricing_admins"
|
||
on public.tablero_cdc_tariff_catalog
|
||
for delete
|
||
to authenticated
|
||
using (public.tablero_cdc_current_user_can_manage_internal_pricing());
|
||
|
||
grant select, insert, update, delete
|
||
on public.tablero_cdc_tariff_catalog
|
||
to authenticated;
|
||
|
||
create or replace function public.set_tablero_cdc_tariff_catalog_updated_at()
|
||
returns trigger
|
||
language plpgsql
|
||
as $$
|
||
begin
|
||
new.updated_at = now();
|
||
new.updated_by = auth.uid();
|
||
|
||
if tg_op = 'INSERT' then
|
||
new.created_by = coalesce(new.created_by, auth.uid());
|
||
end if;
|
||
|
||
return new;
|
||
end;
|
||
$$;
|
||
|
||
drop trigger if exists trg_tablero_cdc_tariff_catalog_updated_at
|
||
on public.tablero_cdc_tariff_catalog;
|
||
|
||
create trigger trg_tablero_cdc_tariff_catalog_updated_at
|
||
before insert or update on public.tablero_cdc_tariff_catalog
|
||
for each row
|
||
execute function public.set_tablero_cdc_tariff_catalog_updated_at();
|
||
|
||
-- 3) Cargar las 12 piezas del Excel de Walmart Connect.
|
||
insert into public.tablero_cdc_tariff_catalog (
|
||
id,
|
||
catalog_item_id,
|
||
section,
|
||
category,
|
||
service,
|
||
notes,
|
||
work_type_id,
|
||
work_type_label,
|
||
work_type_short_label,
|
||
hour_reference,
|
||
level_id,
|
||
level_label,
|
||
reference,
|
||
reference_min,
|
||
reference_max,
|
||
level_hint,
|
||
sort_order,
|
||
is_active
|
||
)
|
||
values
|
||
(
|
||
'wmc-uniformes__wmc-fixed__fixed',
|
||
'wmc-uniformes',
|
||
'wmc',
|
||
'Walmart Connect',
|
||
'Uniformes',
|
||
'Uniforme completo para personal de impulso en piso (playera/top, jogger, falda, chaleco), con 4 variantes de diseño exploradas. Equivalencia CDC: Materiales de PDV estándar y otros materiales básicos > Uniformes. Incluye diseño en alta resolución y 3 rondas de cambios.',
|
||
'wmc_fixed', 'Tarifa fija WMC', 'WMC', '35 - 80',
|
||
'fixed', 'Precio fijo', '80 USD', 80, 80,
|
||
'Incluye diseño en alta resolución y 3 rondas de cambios.',
|
||
20001, true
|
||
),
|
||
(
|
||
'wmc-uniformes-supervisor__wmc-fixed__fixed',
|
||
'wmc-uniformes-supervisor',
|
||
'wmc',
|
||
'Walmart Connect',
|
||
'Uniformes – Supervisor',
|
||
'Uniforme para supervisor de piso (polo, chumpa/track jacket, camisa formal), con 3 variantes de diseño exploradas. Equivalencia CDC: Materiales de PDV estándar y otros materiales básicos > Uniformes. Incluye diseño en alta resolución y 3 rondas de cambios.',
|
||
'wmc_fixed', 'Tarifa fija WMC', 'WMC', '35 - 80',
|
||
'fixed', 'Precio fijo', '100 USD', 100, 100,
|
||
'Incluye diseño en alta resolución y 3 rondas de cambios.',
|
||
20002, true
|
||
),
|
||
(
|
||
'wmc-glorificador-mano__wmc-fixed__fixed',
|
||
'wmc-glorificador-mano',
|
||
'wmc',
|
||
'Walmart Connect',
|
||
'Glorificador de mano',
|
||
'Exhibidor portátil pequeño para presentar el producto: bandeja iluminada, aro LED, estuche o base acrílica. Equivalencia CDC: Stands, Muebles y Exhibidores > Estándar (Displays básicos). Incluye diseño 3D, troqueles y 3 rondas de cambios.',
|
||
'wmc_fixed', 'Tarifa fija WMC', 'WMC', '35 - 80',
|
||
'fixed', 'Precio fijo', '150 USD', 150, 150,
|
||
'Incluye diseño 3D, troqueles y 3 rondas de cambios.',
|
||
20003, true
|
||
),
|
||
(
|
||
'wmc-carritos-intervenidos__wmc-fixed__fixed',
|
||
'wmc-carritos-intervenidos',
|
||
'wmc',
|
||
'Walmart Connect',
|
||
'Carritos intervenidos',
|
||
'Vinil o calcomanía de marca aplicada a la canasta y al mango del carrito de compras. Equivalencia CDC: Materiales de PDV estándar y otros materiales básicos (análogo a Backings/Rompetráficos). Pieza análoga a material gráfico estándar aplicado sobre una superficie existente.',
|
||
'wmc_fixed', 'Tarifa fija WMC', 'WMC', '35 - 80',
|
||
'fixed', 'Precio fijo', '200 USD', 200, 200,
|
||
'Pieza análoga a material gráfico estándar aplicado sobre una superficie existente.',
|
||
20004, true
|
||
),
|
||
(
|
||
'wmc-dummies-exhibicion__wmc-fixed__fixed',
|
||
'wmc-dummies-exhibicion',
|
||
'wmc',
|
||
'Walmart Connect',
|
||
'Dummies de exhibición',
|
||
'Réplica escultórica a gran escala de pasta y cepillo dental como punto focal decorativo o táctil. Equivalencia CDC: Proyectos especiales > Diseño de muebles / proyectos con planos y troqueles desde cero. Requiere diseño estructural y visualización 3D; no es solo arte de impresión.',
|
||
'wmc_fixed', 'Tarifa fija WMC', 'WMC', '35 - 80',
|
||
'fixed', 'Precio fijo', '200 USD', 200, 200,
|
||
'Requiere diseño estructural y visualización 3D; no es solo arte de impresión.',
|
||
20005, true
|
||
),
|
||
(
|
||
'wmc-photobooth__wmc-fixed__fixed',
|
||
'wmc-photobooth',
|
||
'wmc',
|
||
'Walmart Connect',
|
||
'Photobooth',
|
||
'Estructura tipo arco con iluminación LED y espacio fotográfico de marca para activaciones. Equivalencia CDC: Proyectos especiales > Diseño de Stands Creativos para ferias o eventos. Estructura autoportante con iluminación, ambientación y 4 rondas de cambios.',
|
||
'wmc_fixed', 'Tarifa fija WMC', 'WMC', '35 - 80',
|
||
'fixed', 'Precio fijo', '200 USD', 200, 200,
|
||
'Estructura autoportante con iluminación, ambientación y 4 rondas de cambios.',
|
||
20006, true
|
||
),
|
||
(
|
||
'wmc-play-station__wmc-fixed__fixed',
|
||
'wmc-play-station',
|
||
'wmc',
|
||
'Walmart Connect',
|
||
'Play Station',
|
||
'Kiosco interactivo con pantalla táctil y mecánica de juego. Equivalencia CDC: Proyectos especiales > Diseño de muebles / proyectos especiales. Incluye diseño de mueble e interfaz gráfica; el desarrollo funcional del juego se cotiza aparte.',
|
||
'wmc_fixed', 'Tarifa fija WMC', 'WMC', '35 - 80',
|
||
'fixed', 'Precio fijo', '200 USD', 200, 200,
|
||
'Incluye diseño de mueble e interfaz gráfica; el desarrollo funcional del juego se cotiza aparte.',
|
||
20007, true
|
||
),
|
||
(
|
||
'wmc-isla-wm__wmc-fixed__fixed',
|
||
'wmc-isla-wm',
|
||
'wmc',
|
||
'Walmart Connect',
|
||
'Isla WM',
|
||
'Mueble isla completo multinivel con iluminación, gráficos y espacio de exhibición de la línea completa de producto. Equivalencia CDC: Proyectos especiales > Diseño de Stands Creativos para ferias o eventos. Mayor escala y complejidad estructural dentro del set de piezas.',
|
||
'wmc_fixed', 'Tarifa fija WMC', 'WMC', '35 - 80',
|
||
'fixed', 'Precio fijo', '150 USD', 150, 150,
|
||
'Mayor escala y complejidad estructural dentro del set de piezas.',
|
||
20008, true
|
||
),
|
||
(
|
||
'wmc-exhibicion-especial__wmc-fixed__fixed',
|
||
'wmc-exhibicion-especial',
|
||
'wmc',
|
||
'Walmart Connect',
|
||
'Exhibición Especial',
|
||
'Propuesta de muebles de exhibición. Equivalencia CDC: Proyectos especiales > Diseño de muebles con planos y troqueles desde cero. Costo de referencia por concepto; las variantes adicionales se cobran como adicionales.',
|
||
'wmc_fixed', 'Tarifa fija WMC', 'WMC', '35 - 80',
|
||
'fixed', 'Precio fijo', '250 USD', 250, 250,
|
||
'Costo de referencia por concepto; las variantes adicionales se cobran como adicionales.',
|
||
20009, true
|
||
),
|
||
(
|
||
'wmc-punta-gondola__wmc-fixed__fixed',
|
||
'wmc-punta-gondola',
|
||
'wmc',
|
||
'Walmart Connect',
|
||
'Punta de góndola',
|
||
'Cabecera de góndola personalizada con iluminación, gráficos y espacio para producto. Equivalencia CDC: Proyectos especiales > Diseño de muebles con planos y troqueles desde cero. Costo de referencia por concepto; las variantes adicionales se cobran como adicionales.',
|
||
'wmc_fixed', 'Tarifa fija WMC', 'WMC', '35 - 80',
|
||
'fixed', 'Precio fijo', '250 USD', 250, 250,
|
||
'Costo de referencia por concepto; las variantes adicionales se cobran como adicionales.',
|
||
20010, true
|
||
),
|
||
(
|
||
'wmc-estacion-prueba-producto__wmc-fixed__fixed',
|
||
'wmc-estacion-prueba-producto',
|
||
'wmc',
|
||
'Walmart Connect',
|
||
'Estación para prueba de producto',
|
||
'Carrito móvil con lavamanos funcional, grifo y desagüe para pruebas de producto en piso. Equivalencia CDC: Proyectos especiales > Diseño de Stands Creativos para ferias o eventos. La complejidad funcional puede requerir una cotización especial fuera del tarifario estándar.',
|
||
'wmc_fixed', 'Tarifa fija WMC', 'WMC', '35 - 80',
|
||
'fixed', 'Precio fijo', '200 USD', 200, 200,
|
||
'La complejidad funcional puede requerir una cotización especial fuera del tarifario estándar.',
|
||
20011, true
|
||
),
|
||
(
|
||
'wmc-arco-entrada__wmc-fixed__fixed',
|
||
'wmc-arco-entrada',
|
||
'wmc',
|
||
'Walmart Connect',
|
||
'Arco de entrada',
|
||
'Estructura de entrada de tienda a gran formato con iluminación, efecto de niebla y gráficos de marca. Equivalencia CDC: Proyectos especiales > Diseño de Stands Creativos para ferias o eventos. La instalación en sitio se cotiza aparte.',
|
||
'wmc_fixed', 'Tarifa fija WMC', 'WMC', '35 - 80',
|
||
'fixed', 'Precio fijo', '200 USD', 200, 200,
|
||
'La instalación en sitio se cotiza aparte.',
|
||
20012, true
|
||
)
|
||
on conflict (id) do update
|
||
set
|
||
catalog_item_id = excluded.catalog_item_id,
|
||
section = excluded.section,
|
||
category = excluded.category,
|
||
service = excluded.service,
|
||
notes = excluded.notes,
|
||
work_type_id = excluded.work_type_id,
|
||
work_type_label = excluded.work_type_label,
|
||
work_type_short_label = excluded.work_type_short_label,
|
||
hour_reference = excluded.hour_reference,
|
||
level_id = excluded.level_id,
|
||
level_label = excluded.level_label,
|
||
reference = excluded.reference,
|
||
reference_min = excluded.reference_min,
|
||
reference_max = excluded.reference_max,
|
||
level_hint = excluded.level_hint,
|
||
sort_order = excluded.sort_order,
|
||
is_active = true,
|
||
updated_at = now();
|
||
|
||
-- 4) Si el flujo estándar usa esta RPC para desactivar tarifas ausentes,
|
||
-- solo afectará grafico/estrategia y nunca apagará la sección WMC.
|
||
create or replace function public.tablero_cdc_deactivate_missing_tariffs(p_active_ids text[])
|
||
returns integer
|
||
language plpgsql
|
||
security definer
|
||
set search_path = public
|
||
as $$
|
||
declare
|
||
v_count integer;
|
||
begin
|
||
if p_active_ids is null or array_length(p_active_ids, 1) is null then
|
||
raise exception 'No se recibieron IDs activos. Se cancela la desactivación.';
|
||
end if;
|
||
|
||
if array_length(p_active_ids, 1) < 3 then
|
||
raise exception 'Se recibieron menos de 3 IDs activos. Se cancela la desactivación por seguridad.';
|
||
end if;
|
||
|
||
update public.tablero_cdc_tariff_catalog
|
||
set
|
||
is_active = false,
|
||
updated_at = now()
|
||
where section in ('grafico', 'estrategia')
|
||
and is_active = true
|
||
and not (id = any(p_active_ids));
|
||
|
||
get diagnostics v_count = row_count;
|
||
return v_count;
|
||
end;
|
||
$$;
|
||
|
||
grant execute on function public.tablero_cdc_deactivate_missing_tariffs(text[])
|
||
to authenticated, service_role;
|
||
|
||
commit;
|
||
|
||
-- Verificación final: deben aparecer 12 filas activas y un total de referencia de 2,180 USD.
|
||
select
|
||
count(*) as piezas_wmc_activas,
|
||
coalesce(sum(reference_min), 0)::numeric(12, 2) as suma_de_todas_las_piezas
|
||
from public.tablero_cdc_tariff_catalog
|
||
where section = 'wmc'
|
||
and is_active = true;
|
||
|
||
select
|
||
service as pieza,
|
||
reference_min::numeric(12, 2) as monto_fijo,
|
||
is_active
|
||
from public.tablero_cdc_tariff_catalog
|
||
where section = 'wmc'
|
||
order by sort_order, service;
|