-- LA MARCA DEL NEGOCIO VIAJA CON CADA DOCUMENTO. El modelo de factura (logo,
-- color, mensaje del pie) vive en la Estacion del negocio; para que el PDF que
-- la imprenta manda por correo salga con esa cara, la marca acompaña la
-- emision y queda guardada JUNTO al documento (no adentro: el documento
-- sellado no se toca). Congelada a proposito: la factura de marzo conserva la
-- cara que tenia en marzo aunque el negocio cambie el logo en junio.

alter table fiscal.documentos add column if not exists marca jsonb;

-- La cadena de emision gana p_marca (opcional). Cambia la firma: fuera las
-- viejas para no dejar dobles que confundan las llamadas.
drop function if exists public.fn_emitir_documento(text, text, text, text, bigint, text, timestamptz, numeric, numeric, numeric, jsonb, text);
drop function if exists fiscal.emitir_con_llave(text, text, text, text, bigint, text, timestamptz, numeric, numeric, numeric, jsonb, text);
drop function if exists fiscal.recibir_documento(text, text, text, bigint, text, timestamptz, numeric, numeric, numeric, jsonb);
-- Y las firmas nuevas, por si la migracion se corre dos veces.
drop function if exists public.fn_emitir_documento(text, text, text, text, bigint, text, timestamptz, numeric, numeric, numeric, jsonb, text, jsonb);
drop function if exists fiscal.emitir_con_llave(text, text, text, text, bigint, text, timestamptz, numeric, numeric, numeric, jsonb, text, jsonb);
drop function if exists fiscal.recibir_documento(text, text, text, bigint, text, timestamptz, numeric, numeric, numeric, jsonb, jsonb);

create function fiscal.recibir_documento(
  p_rif text, p_serie text, p_tipo text, p_numero_documento bigint, p_hash text,
  p_fecha timestamptz, p_base_bs numeric, p_iva_bs numeric, p_total_bs numeric,
  p_documento jsonb, p_marca jsonb default null
) returns table(
  numero_control bigint, token text, ya_estaba boolean,
  fecha_asignacion timestamptz, rango_desde bigint, rango_hasta bigint,
  imprenta_rif text, imprenta_razon_social text,
  imprenta_providencia text, imprenta_providencia_fecha date
)
language plpgsql
security definer
set search_path to 'fiscal', 'public', 'extensions'
as $$
declare
  v_emisor uuid; v_control bigint; v_token text; v_fecha timestamptz;
  v_desde bigint; v_hasta bigint;
  v_imp_rif text; v_imp_razon text; v_imp_prov text; v_imp_prov_fecha date;
  v_existia boolean := false;
begin
  select e.id into v_emisor from fiscal.emisores e
   where e.rif = public.fn_rif_normalizado(p_rif) and e.activo;
  if v_emisor is null then
    raise exception 'Ese RIF no esta autorizado a emitir por esta imprenta';
  end if;

  -- Art. 29 num. 2: no se asignan numeros de control a quien no acredita RIF
  -- vigente. El texto evita a proposito las palabras que la cola de la
  -- Estacion trata como rechazo definitivo.
  if exists (select 1 from fiscal.emisores e
              where e.id = v_emisor and e.rif_vence is not null
                and e.rif_vence < current_date) then
    raise exception 'El comprobante de RIF de este emisor esta vencido. Consigne ante la imprenta el comprobante renovado para seguir emitiendo.';
  end if;

  -- Reintento del cliente: mismo hash, mismo numero, fecha de asignacion
  -- original. La marca guardada tampoco se pisa en el reintento.
  select d.numero_control, d.token, d.recibido_en into v_control, v_token, v_fecha
    from fiscal.documentos d
   where d.emisor_id = v_emisor and d.hash_documento = p_hash;
  if found then
    v_existia := true;
  else
    v_control := fiscal.asignar_control(v_emisor, p_serie);
    v_token := encode(extensions.gen_random_bytes(16), 'hex');
    v_fecha := now();
    insert into fiscal.documentos (
      emisor_id, serie, tipo, numero_documento, numero_control, token,
      hash_documento, fecha_emision, base_bs, iva_bs, total_bs, documento, marca
    ) values (
      v_emisor, p_serie, p_tipo, p_numero_documento, v_control, v_token,
      p_hash, p_fecha, p_base_bs, p_iva_bs, p_total_bs, p_documento, p_marca
    );
  end if;

  select r.desde, r.hasta into v_desde, v_hasta
    from fiscal.rangos_emisor r
   where r.emisor_id = v_emisor and not r.anulado
     and v_control between r.desde and r.hasta
   order by r.desde
   limit 1;

  select i.rif, i.razon_social, i.providencia, i.providencia_fecha
    into v_imp_rif, v_imp_razon, v_imp_prov, v_imp_prov_fecha
    from fiscal.imprenta i
   limit 1;

  return query select v_control, v_token, v_existia, v_fecha, v_desde, v_hasta,
                      v_imp_rif, v_imp_razon, v_imp_prov, v_imp_prov_fecha;
end;
$$;

create function fiscal.emitir_con_llave(
  p_llave text, p_rif text, p_serie text, p_tipo text, p_numero_documento bigint,
  p_hash text, p_fecha timestamptz, p_base_bs numeric, p_iva_bs numeric,
  p_total_bs numeric, p_documento jsonb, p_desde text default null,
  p_marca jsonb default null
) returns table(
  numero_control bigint, token text, ya_estaba boolean,
  fecha_asignacion timestamptz, rango_desde bigint, rango_hasta bigint,
  imprenta_rif text, imprenta_razon_social text,
  imprenta_providencia text, imprenta_providencia_fecha date
)
language plpgsql
security definer
set search_path to 'fiscal', 'public', 'extensions'
as $$
declare v_emisor uuid;
begin
  v_emisor := fiscal.autenticar(p_llave, p_rif, coalesce(p_desde, 'emision'));
  insert into fiscal.intentos (quien, entro, motivo, desde, tipo, grupo)
  values (p_rif, true, 'emision', p_desde, 'estacion', fiscal.grupo_de(p_desde));

  return query select * from fiscal.recibir_documento(
    p_rif, p_serie, p_tipo, p_numero_documento, p_hash, p_fecha,
    p_base_bs, p_iva_bs, p_total_bs, p_documento, p_marca
  );
end;
$$;

create function public.fn_emitir_documento(
  p_llave text, p_rif text, p_serie text, p_tipo text, p_numero_documento bigint,
  p_hash text, p_fecha timestamptz, p_base_bs numeric, p_iva_bs numeric,
  p_total_bs numeric, p_documento jsonb, p_desde text default null,
  p_marca jsonb default null
) returns table(
  numero_control bigint, token text, ya_estaba boolean,
  fecha_asignacion timestamptz, rango_desde bigint, rango_hasta bigint,
  imprenta_rif text, imprenta_razon_social text,
  imprenta_providencia text, imprenta_providencia_fecha date
)
language sql
security definer
set search_path to 'public', 'fiscal'
as $$
  select * from fiscal.emitir_con_llave(p_llave, p_rif, p_serie, p_tipo, p_numero_documento,
                                        p_hash, p_fecha, p_base_bs, p_iva_bs, p_total_bs,
                                        p_documento, p_desde, p_marca);
$$;

revoke all on function public.fn_emitir_documento(text, text, text, text, bigint, text, timestamptz, numeric, numeric, numeric, jsonb, text, jsonb) from public, anon, authenticated;
grant execute on function public.fn_emitir_documento(text, text, text, text, bigint, text, timestamptz, numeric, numeric, numeric, jsonb, text, jsonb) to service_role;

-- El correo de la factura necesita el documento completo y la marca para armar
-- el PDF con la cara del negocio.
create or replace function public.fn_correos_factura_pendientes(p_limite integer default 5)
returns jsonb
language sql
security definer
set search_path to 'fiscal', 'public'
as $$
  select coalesce(jsonb_agg(fila), '[]'::jsonb) from (
    select jsonb_build_object(
      'id', c.id,
      'para', c.para,
      'token', c.token,
      'negocio', e.razon_social,
      'rif', e.rif,
      'domicilio', e.domicilio_fiscal,
      'numero', d.numero_documento,
      'serie', d.serie,
      'control', d.numero_control,
      'fecha', d.fecha_emision,
      'fecha_asignacion', d.recibido_en,
      'total_bs', d.total_bs,
      'documento', d.documento,
      'marca', d.marca,
      'imprenta', (select jsonb_build_object(
                     'rif', i.rif, 'razon_social', i.razon_social,
                     'providencia', i.providencia, 'providencia_fecha', i.providencia_fecha)
                     from fiscal.imprenta i limit 1),
      'intentos', c.intentos
    ) as fila
    from fiscal.correos_factura c
    join fiscal.emisores e on e.id = c.emisor_id
    left join fiscal.documentos d on d.token = c.token
    where c.estado = 'pendiente' and c.intentos < 5
    order by c.creado_en
    limit greatest(1, least(coalesce(p_limite, 5), 20))
  ) t;
$$;

notify pgrst, 'reload schema';
