esofitec. CoreDocs

esofitec. CoreDocs

Listados de impresión

Plantillas y ejemplos

Esqueletos listos para copiar al diseñador de listados y rellenar. El porqué de cada pieza está en el artículo de listados de impresión.

Consulta primaria de un listado de documento#

La estructura mínima: el ID del documento como parámetro runtime, [CondicionesListado] al final del WHERE y un único ORDER BY por la clave del documento. El ejemplo es para factura de venta — para otro documento, cambia las tablas y el parámetro de ID.

SELECT
    Cabecera.SERIE,
    Cabecera.NUMDOC,
    Cabecera.FECHA,
    Lineas.CODART,
    Lineas.DESCLIN,
    Lineas.UNIDADES,
    Lineas.PRCMONEDA,
    Lineas.BRUTOMONEDA
    -- añade aquí tus columnas; toda columna calculada, con CAST a tipo de longitud explícita
FROM CABEFACV Cabecera WITH (NOLOCK)
INNER JOIN LINEFACT Lineas WITH (NOLOCK) ON Lineas.IDFACV = Cabecera.IDFACV
WHERE Cabecera.IDFACV = :IdFacV
  AND [CondicionesListado,Sysname,1=1]
ORDER BY Cabecera.IDFACV

Texto según el idioma del documento#

CASE Cabecera.CODIDIOMA
    WHEN 'CAT' THEN 'Text en català'
    WHEN 'CAS' THEN 'Texto en castellano'
    ELSE 'Text in English'
END

Textos legales por empresa emisora e idioma#

Cuando los textos son largos (cláusulas RGPD, datos registrales) y hay varias empresas emisoras en el mismo listado — un grupo que factura con varias sociedades —, los CASE se quedan cortos. El patrón es cargar una tabla variable indexada por NIF de la empresa emisora + idioma y cruzarla con la cabecera. Cada empresa lleva sus variantes de idioma, con NULL como fila de respaldo (normalmente, el inglés):

DECLARE @Temp_lopd TABLE (
    CodIdioma         VARCHAR(20),
    NifEmpresa        VARCHAR(20),
    NombreYDireccion  VARCHAR(500),
    RegistroMercantil VARCHAR(500),
    TextoLopd         VARCHAR(2500));

INSERT INTO @Temp_lopd (NifEmpresa, CodIdioma, NombreYDireccion, RegistroMercantil, TextoLopd) VALUES ('B00000000', 'CAT',
    'EMPRESA EXEMPLE, S.L.' + CHAR(13) + CHAR(10) + 'N.I.F. B00000000' + CHAR(13) + CHAR(10) + 'Adreça - CP Ciutat',
    'Inscrita en el R.M. de ..., vol. ..., foli ..., full ..., inscripció ...',
    'Text legal RGPD en català.');
INSERT INTO @Temp_lopd (NifEmpresa, CodIdioma, NombreYDireccion, RegistroMercantil, TextoLopd) VALUES ('B00000000', 'CAS',
    'EMPRESA EJEMPLO, S.L.' + CHAR(13) + CHAR(10) + 'N.I.F. B00000000' + CHAR(13) + CHAR(10) + 'Dirección - CP Ciudad',
    'Inscrita en el R.M. de ..., tomo ..., folio ..., hoja ..., inscripción ...',
    'Texto legal RGPD en castellano.');
INSERT INTO @Temp_lopd (NifEmpresa, CodIdioma, NombreYDireccion, RegistroMercantil, TextoLopd) VALUES ('B00000000', NULL,
    'EMPRESA EJEMPLO, S.L.' + CHAR(13) + CHAR(10) + 'N.I.F. B00000000' + CHAR(13) + CHAR(10) + 'Address - ZIP City',
    'Registered in ...',
    'RGPD legal text in English.');

-- se repiten los tres INSERT por cada empresa emisora del grupo

SELECT
    ...,
    Lopd.NombreYDireccion,
    Lopd.RegistroMercantil,
    Lopd.TextoLopd
FROM CABEFACV Cabecera WITH (NOLOCK)
...
LEFT JOIN @Temp_lopd Lopd
  ON Cabecera.CODIDIOMA = Lopd.CodIdioma
 AND DatosEmp.NIFEMP = Lopd.NifEmpresa

Si el grupo incorpora una empresa nueva, hay que darla de alta con sus tres variantes — si falta alguna, los documentos de esa empresa saldrán sin texto legal en ese idioma.

Concatenar filas en una cadena (seguro para el motor de informes)#

Concatena valores relacionados en una sola columna. Las dos precauciones que ya trae puestas son las que evitan los errores del motor de informes — sin ORDER BY en la subconsulta anidada, y CAST final a una longitud explícita en lugar de dejar el VARCHAR(MAX) que produce FOR XML PATH.

CAST(STUFF((
    SELECT ', ' + Hijas.DESCLIN
    FROM LINEFACT Hijas WITH (NOLOCK)
    WHERE Hijas.IDFACV = Cabecera.IDFACV
    FOR XML PATH('')
), 1, 2, '') AS VARCHAR(2000))

Subconsulta de rectificativas compatible con el SII#

La función interna de a3ERP DetalleRectificativa('V') identifica las facturas rectificadas como TipoContable/Serie/NumDoc; para el SII, en cambio, el identificador de una factura es Serie/NumDoc. Si al cliente le aplica el SII, esta subconsulta sustituye a la función y monta el texto con el formato correcto. Cubre los dos tipos de rectificativa — por facturas concretas y por periodo — y solo devuelve fila cuando la factura es rectificativa:

-- Solo devuelve fila cuando la factura es rectificativa (RECTIFICATIVA = 'T').
SELECT
    Cabecera.IdFacV,
    CAST(Cabecera.MotivoRectificacion AS VARCHAR(500)) AS MotivoRectificacion,
    -- CAST final a VARCHAR acotado obligatorio. La concatenacion y el .value
    -- producen VARCHAR(MAX), tipo que el dataset de a3ERP no sabe mapear.
    CAST(CASE
        WHEN Cabecera.TIPORECTIFICATIVA = 'PERIODO' THEN
            CASE Cabecera.CodIdioma
                WHEN 'CAT' THEN 'Rectificació del període '
                WHEN 'CAS' THEN 'Rectificación del periodo '
                ELSE 'Rectification of period '
            END
            + CONVERT(VARCHAR(10), Cabecera.FECHAINIRECTIFICATIVA, 103)
            + ' - '
            + CONVERT(VARCHAR(10), Cabecera.FECHAFINRECTIFICATIVA, 103)
        ELSE
            CASE Cabecera.CodIdioma
                WHEN 'CAT' THEN 'Rectificació de les factures: '
                WHEN 'CAS' THEN 'Rectificación de las facturas: '
                ELSE 'Rectification of invoices: '
            END
            + ISNULL(
                STUFF((
                    SELECT ', '
                           + LTRIM(ISNULL(Origen.Serie, ''))
                           + '/'
                           + CAST(CAST(Origen.NumDoc AS BIGINT) AS VARCHAR(30))
                    FROM CABEFACV Origen WITH (NOLOCK)
                    WHERE Origen.IdFacV IN (
                        SELECT Detalle.IDFACORIGEN
                        FROM __DETALLERECTIFICADAS_VENTAS Detalle WITH (NOLOCK)
                        WHERE Detalle.IDFACRECTIFICATIVA = Cabecera.IdFacV
                    )
                    -- Sin ordenar dentro del FOR XML; el orden queda el natural por IdFacV.
                    FOR XML PATH(''), TYPE
                ).value('.', 'VARCHAR(MAX)'), 1, 2, ''),
                '')
    END AS VARCHAR(2000)) AS TextoRectificacion
FROM CABEFACV Cabecera WITH (NOLOCK)
WHERE Cabecera.IdFacV = :IdFacV
  AND Cabecera.RECTIFICATIVA = 'T'
ORDER BY Cabecera.IdFacV

Esta plantilla es además un buen repaso de las reglas del artículo, todas aplicadas a la vez: parámetro runtime :IdFacV, CAST a longitud explícita en cada columna calculada, concatenación sin ORDER BY anidado, ORDER BY final por la clave del documento y comentarios sin dos puntos. Y un matiz que se ve en los literales ('Rectificación de las facturas: '): los dos puntos dentro de cadenas de texto no dan problema — la restricción es en los comentarios.

Al adaptar las plantillas

Nada de : ni [...] en los comentarios, y cuidado con escribir las palabras ORDER BY en uno — las tres trampas están explicadas en el artículo.