Блог

PDF/A и Factur-X объяснены инженерам (без юридического жаргона)

Что профили PDF/A реально ограничивают, почему Factur-X становится обязательным в ЕС в 2026, и наименьший практический pipeline для соответствия из JSON-renderer.

Если вы инженер, которому только что сказали «счета должны быть PDF/A-3 с Factur-X к следующему кварталу», и ваш единственный контекст в том, что кто-то из юридического отдела произнёс эти слова, этот пост для вас.

Срезаем тон документов стандартизации и объясняем, что эти профили реально ограничивают, почему правительства начали их обязывать, и наименьший практический pipeline для эмиссии compliant PDF из renderer-а структурированных данных.

PDF/A в двух абзацах

PDF — гибкий формат. Слишком гибкий — та же спецификация PDF позволяет встраивать JavaScript, ссылаться на внешние ресурсы, которые могут не существовать через 50 лет, шифровать содержимое обратимой криптографией, ссылаться на внешние шрифты, и сотню других вещей, делающих документ не-самодостаточным.

PDF/A («A» от Archival) — профиль PDF, запрещающий части, которые мешали бы документу рендериться идентично через 50 лет. Высокоуровневые правила:

  • Все шрифты должны быть встроены.
  • Никакого JavaScript, внешних ссылок, аудио/видео.
  • Никакого шифрования.
  • Вся прозрачность должна быть сплющена или поддерживаться версией профиля.
  • Цвета должны быть аппаратно-независимыми (требуется ICC-профиль).
  • Всё содержимое должно быть в файле — никаких ссылок, зависящих от сети.

Существует несколько версий, каждая добавляет толерантность к более новым функциям:

Профиль Год Что добавляет
PDF/A-1b 2005 Изначальный baseline — самый строгий
PDF/A-2b 2011 Разрешает JPEG2000, прозрачность, слои
PDF/A-3b 2012 Разрешает произвольные вложения файлов (фундамент Factur-X)
PDF/A-4 2020 База ISO 32000-2 (PDF 2.0), упрощённые уровни соответствия

Суффикс «b» означает «basic» соответствие (визуальная верность). Также есть варианты «u» (Unicode-mapped) и «a» (accessibility-tagged) — для большинства workflow-ов счёт/чек, «b» — то, что вам нужно, потому что налоговое архивирование заботится о визуальной воспроизводимости, а не семантике для screen reader.

Практический вывод: если ваш renderer говорит, что поддерживает PDF/A-3b, это должен быть единственный config-флаг ({ profile: "PDF/A-3b" } или эквивалент). Если приходится запускать второй инструмент (Ghostscript, qpdf, Acrobat) для конвертации потом, это пробел в workflow для учёта в ваших ops.

Почему PDF/A-3 особенно важен: он носитель электронных счетов

PDF/A-3 добавил одну способность, которая оказалась мир-меняющей: произвольные вложения файлов внутри PDF.

Звучит скучно. Это не так. Это вся техническая основа мандатов электронных счетов, разворачивающихся по Европе прямо сейчас.

Архитектура: единственный файл PDF, который одновременно

  1. Человеко-читаемый счёт (визуальный layout, итоги, брендинг) — часть, которую читает человек.
  2. Машинно-читаемый XML-счёт — часть, которую парсит софт налоговой инстанции.

Оба внутри одного файла, оба представляют тот же счёт, и обёртка PDF/A-3 гарантирует, что файл будет parseable десятилетиями.

Два главных XML-формата:

  • Factur-X (Франция) — XML-профиль на основе UN/CEFACT Cross Industry Invoice
  • ZUGFeRD (Германия) — по сути идентичен Factur-X (две стандарта технически слились в 2018)
  • EN 16931 — европейская норма, которой соответствуют обе реализации

Для большинства workflow-ов «Factur-X» и «ZUGFeRD» — взаимозаменяемые термины — делят схему, делят механизм встраивания, и единственный PDF, compliant с одним, обычно compliant с другим.

Что обязательно, где, когда

Неисчерпывающий снимок для инженеров, планирующих rollout-ы Q2/Q3 2026:

Страна Статус Требуемый формат
Германия B2B обязателен для приёма с 2025-01-01; эмиссия с 2027 EN 16931 (ZUGFeRD / Factur-X / XRechnung)
Франция Эмиссия обязательна для крупных предприятий 2026-09; МСП 2027-09 Factur-X через Chorus Pro
Италия B2B обязателен с 2019 FatturaPA через SDI
Польша Обязателен с 2024-07 KSeF
Испания Обязателен с 2026 (B2B) Facturae через FACe
Бельгия Обязателен с 2026-01 Peppol BIS 3

Паттерн: каждое государство-член ЕС реализует какой-то вариант EN 16931-compliant электронного счёт-фактуры на timeline 2024–2027. Если ваши клиенты работают в любом из этих рынков, ваш PDF-генератор должен будет эмитировать прикреплённый XML рядом с визуальным счётом.

Наименьший практический pipeline

Забудьте, что предписывают документы стандартизации. Вот вид инженера:

   ┌─────────────────────┐
   │  Данные счёта       │  (уже JSON-объект где-то)
   └─────────┬───────────┘


   ┌─────────────────────┐
   │ Построить XML       │  (детерминистичный mapping; проверенные libs существуют)
   │      EN 16931       │
   └─────────┬───────────┘


   ┌─────────────────────┐
   │ Рендерить PDF/A-3b  │
   │ + прикрепить XML    │  (один API-вызов к gPdf — или два шага в других)
   └─────────┬───────────┘


   ┌─────────────────────┐
   │  Передать в         │
   │  Chorus Pro / SDI / │
   │  Peppol / etc       │
   └─────────────────────┘

Два нетривиальных шага:

Шаг 1: построить XML

Это раздражает, но механически. Вы маппите данные счёта (строки, налоги, итоги, стороны) на имена полей XML EN 16931. Несколько Java/Node/Python библиотек делают это за вас — ищите «factur-x library» в вашем языке. Не пишите с нуля, если вы действительно не наслаждаетесь спецификациями XML-схем.

Шаг 2: рендерить PDF/A-3 и прикрепить XML

Здесь имеет значение выбор renderer-а.

Без встроенной поддержки: вы рендерите обычный PDF, затем post-обрабатываете инструментом, который конвертирует в PDF/A-3 и прикрепляет XML как встроенный файл. Распространённые стеки: Ghostscript + qpdf, или платный инструмент типа Aspose. Два дополнительных шага, две дополнительные точки отказа, и нужно убедиться, что post-обработка не сдвигает визуальный layout.

Со встроенной поддержкой (подход gPdf): один вызов.

curl -X POST https://api.gpdf.com/api/v1/e-invoice/render \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "settings": {
      "profile": "pdfa-3b",
      "e_invoice": {
        "standard": "factur_x",
        "profile": "en16931",
        "document_type": "invoice",
        "xml": {
          "format": "cii",
          "encoding": "utf8",
          "content": "<rsm:CrossIndustryInvoice>...</rsm:CrossIndustryInvoice>"
        }
      }
    },
    "pages": [{ "size": "a4", "elements": [...] }]
  }' \
  --output invoice-with-einvoice.pdf

Это весь pipeline. Renderer эмитирует PDF/A-3b, прикрепляет ваш XML как factur-x.xml (или zugferd-invoice.xml, оба распознаются каждым потребителем) и возвращает байты.

Распространённые ловушки

Несколько вещей, которые люди узнают тяжёлым путём:

«PDF/A» и «со шрифтами compliant PDF/A» — не одно и то же

PDF/A-3 файл требует, чтобы все шрифты были встроены с полным покрытием используемых глифов. Если в счёте имя иностранного клиента, и renderer падает на шрифт, который не полностью встраиваемый, инструменты валидации отклонят его. Проверьте, встраивает ли ваш renderer CJK-шрифты в режиме PDF/A — многие не делают этого по умолчанию.

Визуальное + XML должны совпадать

XML-счёт и визуальный счёт должны представлять тот же счёт. Налоговые аудиторы будут diff их. Если ваш код эмитирует XML с total: 119,00, а визуальный PDF показывает Итого: 120,00 (из-за бага округления или устаревшего шаблона), у вас расхождение по налогам в файлах. Генерируйте оба из того же source-of-truth, идеально в том же code path.

Уровни «профиля» в EN 16931

Factur-X имеет профили: MINIMUM, BASIC, EN 16931, EXTENDED. Различаются по тому, сколько данных в XML. Используйте BASIC, если ваш клиент специально не требует больше — покрывает налоговые коды, строки, стороны, итоги, что достаточно для ~95% B2B-счёт-фактур.

Валидация перед отправкой

Всегда валидируйте сгенерированный PDF против PDF/A-валидатора (veraPDF — open-source стандарт) и валидируйте XML против схемы EN 16931 перед отправкой в tax authority. Неудачные отправки в Chorus Pro / SDI считаются против ваших reliability metrics у regulator.

TL;DR

PDF/A — профиль самосодержащегося документа. PDF/A-3 позволяет прикреплять файлы. Factur-X / ZUGFeRD — это «XML EN 16931, прикреплённый внутри PDF/A-3». Мандаты электронного счёт-фактуры по ЕС делают эту комбинацию де-факто B2B-форматом счёта 2025–2027.

Если ваш renderer обращается с PDF/A-3 + Factur-X как с единственным config-флагом, миграция механическая. Если нет, вы строите multi-step ops pipeline. /api/v1/e-invoice/render от gPdf — single-flag версия — API-справочник имеет полную схему, или попробуйте sample-render в Playground.