-- ART. 7 DE LA PROVIDENCIA SNAT/2024/000102: la factura debe imprimir el rango
-- de numeros de control asignado (numeral 5), la fecha de asignacion del numero
-- de control (numeral 15) y la razon social, RIF y providencia de la imprenta
-- digital autorizada (numeral 14). Esos datos nacen en la imprenta, no en el
-- sistema del emisor: la respuesta de la emision ahora los devuelve para que la
-- Estacion (o el sistema del tercero que integra) los ponga en el documento.
--
-- Cambia el tipo de retorno de las tres funciones encadenadas, asi que van con
-- DROP previo (CREATE OR REPLACE no cambia un RETURNS TABLE). Los campos nuevos
-- son aditivos: el codigo desplegado que solo lee numero_control/token/ya_estaba
-- sigue funcionando igual.

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);

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
) 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;

  -- Reintento del cliente: mismo hash, mismo numero. La fecha de asignacion es
  -- la ORIGINAL (cuando de verdad se asigno), no la del 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
    ) 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
    );
  end if;

  -- El rango del que salio este numero de control (numeral 5 del art. 7).
  -- Vacio mientras el emisor trabaja con numeracion libre (modo paraguas).
  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;

  -- La identidad de la imprenta (numeral 14 del art. 7). Vacia mientras la
  -- imprenta no este dada de alta en su panel.
  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
) 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
  );
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
) 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);
$$;

-- Mismos permisos que tenia: solo el servicio la llama, nadie mas.
revoke all on function public.fn_emitir_documento(text, text, text, text, bigint, text, timestamptz, numeric, numeric, numeric, jsonb, text) from public, anon, authenticated;
grant execute on function public.fn_emitir_documento(text, text, text, text, bigint, text, timestamptz, numeric, numeric, numeric, jsonb, text) to service_role;

notify pgrst, 'reload schema';
