From 0d8224a6d389775fa5f0417efe9ff083ca5a57da Mon Sep 17 00:00:00 2001 From: jekuaitk Date: Fri, 6 Feb 2026 07:55:09 +0100 Subject: [PATCH 01/11] 288: Add address element to generated html during digital post --- modules/os2forms_digital_post/README.md | 19 ++++ ...arve_ej_til_kant_demo_ny_rudeplacering.pdf | Bin 0 -> 42079 bytes .../os2forms_digital_post.services.yml | 7 ++ .../Os2formsDigitalPostSubscriber.php | 99 ++++++++++++++++++ .../src/Helper/WebformHelperSF1601.php | 35 +++++++ 5 files changed, 160 insertions(+) create mode 100644 modules/os2forms_digital_post/docs/digst_a4_farve_ej_til_kant_demo_ny_rudeplacering.pdf create mode 100644 modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php diff --git a/modules/os2forms_digital_post/README.md b/modules/os2forms_digital_post/README.md index 999d87c7..e9591ff0 100644 --- a/modules/os2forms_digital_post/README.md +++ b/modules/os2forms_digital_post/README.md @@ -80,3 +80,22 @@ of recipients: ``` shell drush os2forms-digital-post:test:send --help ``` + +## Fjernprint (physical digital post) + +To comply with the address placement in the envelope window (kuvert-rude) an +[event subscriber](src/EventSubscriber/Os2formsDigitalPostSubscriber.php) is +used to inject an address information element into generated HTML before it is +converted to a PDF. + +We are only guaranteed to have the necessary information when in a digital +post context. For that reason, the injection of address information is only +done when in a digital post context. Note also that the information is only +injected – it is not styled. This allows flexibility across installations but +also means that it is up to individual installations to style it correctly. +This should be done in OS2Forms Attachment-templates, see +[Overwriting templates](https://github.com/OS2Forms/os2forms/tree/develop/modules/os2forms_attachment#overwriting-templates). + +To see the exact requirements for address placement, see +[digst_a4_farve_ej_til_kant_demo_ny_rudeplacering.pdf](docs/digst_a4_farve_ej_til_kant_demo_ny_rudeplacering.pdf). + diff --git a/modules/os2forms_digital_post/docs/digst_a4_farve_ej_til_kant_demo_ny_rudeplacering.pdf b/modules/os2forms_digital_post/docs/digst_a4_farve_ej_til_kant_demo_ny_rudeplacering.pdf new file mode 100644 index 0000000000000000000000000000000000000000..9f381c7a0246469067fa3d444e7f84614d3a95ef GIT binary patch literal 42079 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 gLnO2tD2G8X*n`UX2dtp+`Tzg` literal 0 HcmV?d00001 diff --git a/modules/os2forms_digital_post/os2forms_digital_post.services.yml b/modules/os2forms_digital_post/os2forms_digital_post.services.yml index 745b88d2..990e6020 100644 --- a/modules/os2forms_digital_post/os2forms_digital_post.services.yml +++ b/modules/os2forms_digital_post/os2forms_digital_post.services.yml @@ -52,6 +52,7 @@ services: - "@logger.channel.os2forms_digital_post" - "@logger.channel.os2forms_digital_post_submission" - "@Drupal\\os2forms_digital_post\\Helper\\DigitalPostHelper" + - "@Drupal\\os2forms_digital_post\\EventSubscriber\\Os2formsDigitalPostSubscriber" Drupal\os2forms_digital_post\Helper\SF1461Helper: @@ -69,3 +70,9 @@ services: - '@database' - '@Drupal\os2forms_digital_post\Helper\MeMoHelper' - '@logger.channel.os2forms_digital_post' + + Drupal\os2forms_digital_post\EventSubscriber\Os2formsDigitalPostSubscriber: + arguments: + - '@request_stack' + tags: + - { name: 'event_subscriber' } diff --git a/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php b/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php new file mode 100644 index 00000000..331e244e --- /dev/null +++ b/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php @@ -0,0 +1,99 @@ +getHtml(); + + // Only modify HTML if there is exactly one submission. + if (count($event->getEntities()) === 1) { + $submission = $event->getEntities()[0]; + if ($submission instanceof WebformSubmissionInterface) { + // Check whether generation is for digital post. + if ($digitalPostContext = $this->getDigitalPostContext($submission)) { + + $name = $digitalPostContext['name']; + $address = $digitalPostContext['address']; + $zipAndCity = $digitalPostContext['zipAndCity']; + + $addressHtml = << +
+ $name
+ $address
+ $zipAndCity +
+ +HTML; + $html = preg_replace('@]*>@', '${0}' . $addressHtml, $html); + $this->deleteDigitalPostContext($submission); + } + } + } + + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents(): array { + return [ + PrintEvents::POST_RENDER => ['onPrintRender'], + ]; + } + + /** + * Indicate Digital Post context in the current request. + */ + public function setDigitalPostContext(WebformSubmissionInterface $submission, array $digitalPostContext): void { + $key = $this->createSessionKeyFromSubmission($submission); + $this->requestStack->getCurrentRequest()->getSession()->set($key, $digitalPostContext); + } + + /** + * Check for Digital Post context in the current request. + */ + public function getDigitalPostContext(WebformSubmissionInterface $submission): array { + $key = $this->createSessionKeyFromSubmission($submission); + return $this->requestStack->getCurrentRequest()->getSession()->get($key, []); + } + + /** + * Delete Digital Post context from the current request. + */ + public function deleteDigitalPostContext(WebformSubmissionInterface $submission): bool { + $key = $this->createSessionKeyFromSubmission($submission); + return (bool) $this->requestStack->getCurrentRequest()->getSession()->remove($key); + } + + /** + * Create a session key from a submission that is unique to the submission. + */ + public function createSessionKeyFromSubmission(WebformSubmissionInterface $submission): string { + // Due to cloning of submission during attachment logic, we cannot use + // submission id or uuid. Webform serial, however, is copied along, so a + // combination of webform id and serial is used for uniqueness. + // @see \Drupal\os2forms_attachment\Element\AttachmentElement::overrideWebformSettings + return 'digital_post_context_' . $submission->getWebform()->id() . '_' . $submission->serial(); + } + +} diff --git a/modules/os2forms_digital_post/src/Helper/WebformHelperSF1601.php b/modules/os2forms_digital_post/src/Helper/WebformHelperSF1601.php index 60fae6a2..860e5e0d 100644 --- a/modules/os2forms_digital_post/src/Helper/WebformHelperSF1601.php +++ b/modules/os2forms_digital_post/src/Helper/WebformHelperSF1601.php @@ -2,12 +2,15 @@ namespace Drupal\os2forms_digital_post\Helper; +use Drupal\os2web_datalookup\LookupResult\CompanyLookupResult; +use Drupal\os2web_datalookup\LookupResult\CprLookupResult; use Drupal\Core\Entity\EntityStorageInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Logger\LoggerChannelInterface; use Drupal\advancedqueue\Entity\QueueInterface; use Drupal\advancedqueue\Job; use Drupal\advancedqueue\JobResult; +use Drupal\os2forms_digital_post\EventSubscriber\Os2formsDigitalPostSubscriber; use Drupal\os2forms_digital_post\Exception\InvalidRecipientIdentifierElementException; use Drupal\os2forms_digital_post\Exception\RuntimeException; use Drupal\os2forms_digital_post\Exception\SubmissionNotFoundException; @@ -62,6 +65,7 @@ public function __construct( #[Autowire(service: 'logger.channel.os2forms_digital_post_submission')] private readonly LoggerChannelInterface $submissionLogger, private readonly DigitalPostHelper $digitalPostHelper, + private readonly Os2formsDigitalPostSubscriber $digitalPostSubscriber, ) { $this->webformSubmissionStorage = $entityTypeManager->getStorage('webform_submission'); $this->queueStorage = $entityTypeManager->getStorage('advancedqueue_queue'); @@ -152,6 +156,10 @@ public function sendDigitalPost(WebformSubmissionInterface $submission, array $h $recipientIdentifierType = 'CPR'; } + $digitalPostAddressData = $this->getAddressForDigitalPost($lookupResult); + + $this->digitalPostSubscriber->setDigitalPostContext($submission, $digitalPostAddressData); + $senderSettings = $this->settings->getSender(); $messageOptions = [ self::RECIPIENT_IDENTIFIER_TYPE => $recipientIdentifierType, @@ -342,4 +350,31 @@ public function deleteMessages(array $webformSubmissions): void { $this->beskedfordelerHelper->deleteMessages($webformSubmissions); } + /** + * Gets lookup results addresses in the format needed for SF1601. + */ + private function getAddressForDigitalPost(CprLookupResult|CompanyLookupResult $lookupResult): array { + $name = $lookupResult->getName(); + + $address = $lookupResult->getStreet(); + + if ($lookupResult->getHouseNr()) { + $address .= ' ' . $lookupResult->getHouseNr(); + } + if ($lookupResult->getFloor()) { + $address .= ' ' . $lookupResult->getFloor(); + } + if ($lookupResult->getApartmentNr()) { + $address .= ' ' . $lookupResult->getApartmentNr(); + } + + $zipAndCity = $lookupResult->getPostalCode() . ' ' . $lookupResult->getCity(); + + return [ + 'name' => $name, + 'address' => $address, + 'zipAndCity' => $zipAndCity, + ]; + } + } From ba26c190b8f76cdf4fbf532f1b9214261b5684e7 Mon Sep 17 00:00:00 2001 From: jekuaitk Date: Fri, 6 Feb 2026 08:03:57 +0100 Subject: [PATCH 02/11] 288: Updated CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6f3e756..200bbc16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ before starting to add changes. Use example [placed in the end of the page](#exa ## [Unreleased] +- [PR-301](https://github.com/OS2Forms/os2forms/pull/301) + Add address information to Digital Post shipments to ensure "*fjernprint*" + can be sent. + ## [5.0.0] 2025-11-18 - [PR-192](https://github.com/OS2Forms/os2forms/pull/192) From e0815dc87fd152b6764e7bd2e5f3190a2201fdf1 Mon Sep 17 00:00:00 2001 From: jekuaitk Date: Tue, 10 Feb 2026 13:19:01 +0100 Subject: [PATCH 03/11] 288: Added comment to preg_replace --- .../src/EventSubscriber/Os2formsDigitalPostSubscriber.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php b/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php index 331e244e..eac2dafa 100644 --- a/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php +++ b/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php @@ -44,6 +44,8 @@ public function onPrintRender(PrintHtmlAlterEvent $event): void { HTML; + + // Insert address HTML immediately after body opening tag. $html = preg_replace('@]*>@', '${0}' . $addressHtml, $html); $this->deleteDigitalPostContext($submission); } From 1fca0a27d9b44f452ff42722f1a8b2b60d877ce8 Mon Sep 17 00:00:00 2001 From: jekuaitk Date: Tue, 10 Feb 2026 13:26:15 +0100 Subject: [PATCH 04/11] 288: Ensured required fields are set before accessing them --- .../src/EventSubscriber/Os2formsDigitalPostSubscriber.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php b/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php index eac2dafa..be19fa7b 100644 --- a/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php +++ b/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php @@ -30,6 +30,11 @@ public function onPrintRender(PrintHtmlAlterEvent $event): void { if ($submission instanceof WebformSubmissionInterface) { // Check whether generation is for digital post. if ($digitalPostContext = $this->getDigitalPostContext($submission)) { + // Check whether required fields are present. + if (!isset($digitalPostContext['name'], $digitalPostContext['address'], $digitalPostContext['zipAndCity'])) { + // Do nothing if they are not. + return; + } $name = $digitalPostContext['name']; $address = $digitalPostContext['address']; From d25ba3eb6569e7da49a628b407af9dd71bb9fe82 Mon Sep 17 00:00:00 2001 From: jekuaitk Date: Tue, 10 Feb 2026 15:41:16 +0100 Subject: [PATCH 05/11] 288: Switched to h-card and saving lookup result in session --- modules/os2forms_digital_post/README.md | 54 ++++++++++++ .../os2forms_digital_post.services.yml | 2 +- .../Os2formsDigitalPostSubscriber.php | 83 +++++++++++-------- .../src/Helper/WebformHelperSF1601.php | 31 +------ 4 files changed, 106 insertions(+), 64 deletions(-) diff --git a/modules/os2forms_digital_post/README.md b/modules/os2forms_digital_post/README.md index e9591ff0..9267cb5f 100644 --- a/modules/os2forms_digital_post/README.md +++ b/modules/os2forms_digital_post/README.md @@ -99,3 +99,57 @@ This should be done in OS2Forms Attachment-templates, see To see the exact requirements for address placement, see [digst_a4_farve_ej_til_kant_demo_ny_rudeplacering.pdf](docs/digst_a4_farve_ej_til_kant_demo_ny_rudeplacering.pdf). +The injected HTML is on the form: + +Without extended address information: + +```html +
+
+
Jeppe
+
Test vej HouseNr
+
2100 Copenhagen
+
+
+``` + +With extended address information: + +```html +
+
+
Jeppe
+
Test vej HouseNr Floor AppartmentNr
+
2100 Copenhagen
+
+
+``` + +Without c/o: + +```html + +
+
+
Jeppe
+
Test vej HouseNr Floor AppartmentNr
+
2100 Copenhagen
+
+
+``` + +With c/o: + +```html +
+
+
Jeppe
+
c/o Mikkel
+
Test vej HouseNr Floor AppartmentNr
+
2100 Copenhagen
+
+
+``` + + + diff --git a/modules/os2forms_digital_post/os2forms_digital_post.services.yml b/modules/os2forms_digital_post/os2forms_digital_post.services.yml index 990e6020..32fdb740 100644 --- a/modules/os2forms_digital_post/os2forms_digital_post.services.yml +++ b/modules/os2forms_digital_post/os2forms_digital_post.services.yml @@ -73,6 +73,6 @@ services: Drupal\os2forms_digital_post\EventSubscriber\Os2formsDigitalPostSubscriber: arguments: - - '@request_stack' + - '@session' tags: - { name: 'event_subscriber' } diff --git a/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php b/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php index be19fa7b..4fefcffa 100644 --- a/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php +++ b/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php @@ -4,16 +4,18 @@ use Drupal\entity_print\Event\PrintEvents; use Drupal\entity_print\Event\PrintHtmlAlterEvent; +use Drupal\os2web_datalookup\LookupResult\CompanyLookupResult; +use Drupal\os2web_datalookup\LookupResult\CprLookupResult; use Drupal\webform\WebformSubmissionInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpFoundation\Session\SessionInterface; /** * Used to alter the generated PDF to align with digital post requirements. */ final class Os2formsDigitalPostSubscriber implements EventSubscriberInterface { - public function __construct(private readonly RequestStack $requestStack) { + public function __construct(private readonly SessionInterface $session) { } /** @@ -29,30 +31,45 @@ public function onPrintRender(PrintHtmlAlterEvent $event): void { $submission = $event->getEntities()[0]; if ($submission instanceof WebformSubmissionInterface) { // Check whether generation is for digital post. - if ($digitalPostContext = $this->getDigitalPostContext($submission)) { - // Check whether required fields are present. - if (!isset($digitalPostContext['name'], $digitalPostContext['address'], $digitalPostContext['zipAndCity'])) { - // Do nothing if they are not. - return; + if ($lookupResult = $this->getDigitalPostContext($submission)) { + + // Combine address parts. + $streetAddress = $lookupResult->getStreet(); + + if ($lookupResult->getHouseNr()) { + $streetAddress .= ' ' . $lookupResult->getHouseNr(); } - $name = $digitalPostContext['name']; - $address = $digitalPostContext['address']; - $zipAndCity = $digitalPostContext['zipAndCity']; + $extendedAddress = ''; - $addressHtml = << -
- $name
- $address
- $zipAndCity -
- -HTML; + if ($lookupResult->getFloor()) { + $extendedAddress = $lookupResult->getFloor(); + } + if ($lookupResult->getApartmentNr()) { + $extendedAddress .= ' ' . $lookupResult->getApartmentNr(); + } + + // Generate address HTML. + $addressHtml = '
'; + $addressHtml .= '
' . htmlspecialchars($lookupResult->getName()) . '
'; + if ($lookupResult->getCoName()) { + $addressHtml .= '
c/o ' . htmlspecialchars($lookupResult->getCoName()) . '
'; + } + $addressHtml .= '
'; + $addressHtml .= '' . htmlspecialchars($streetAddress) . ''; + if (!empty($extendedAddress)) { + $addressHtml .= ' ' . htmlspecialchars($extendedAddress) . ''; + } + $addressHtml .= '
'; + $addressHtml .= '
'; + $addressHtml .= '' . htmlspecialchars($lookupResult->getPostalCode()) . ''; + $addressHtml .= ' ' . htmlspecialchars($lookupResult->getCity()) . ''; + $addressHtml .= '
'; + $addressHtml .= '
'; + $addressHtml .= '
'; // Insert address HTML immediately after body opening tag. $html = preg_replace('@]*>@', '${0}' . $addressHtml, $html); - $this->deleteDigitalPostContext($submission); } } } @@ -69,27 +86,27 @@ public static function getSubscribedEvents(): array { } /** - * Indicate Digital Post context in the current request. + * Indicate Digital Post context in the current session. */ - public function setDigitalPostContext(WebformSubmissionInterface $submission, array $digitalPostContext): void { + public function setDigitalPostContext(WebformSubmissionInterface $submission, CompanyLookupResult|CprLookupResult $lookupResult): void { $key = $this->createSessionKeyFromSubmission($submission); - $this->requestStack->getCurrentRequest()->getSession()->set($key, $digitalPostContext); + $this->session->set($key, $lookupResult); } /** - * Check for Digital Post context in the current request. + * Check for Digital Post context in the current session. */ - public function getDigitalPostContext(WebformSubmissionInterface $submission): array { + public function getDigitalPostContext(WebformSubmissionInterface $submission): CompanyLookupResult|CprLookupResult|null { $key = $this->createSessionKeyFromSubmission($submission); - return $this->requestStack->getCurrentRequest()->getSession()->get($key, []); - } - /** - * Delete Digital Post context from the current request. - */ - public function deleteDigitalPostContext(WebformSubmissionInterface $submission): bool { - $key = $this->createSessionKeyFromSubmission($submission); - return (bool) $this->requestStack->getCurrentRequest()->getSession()->remove($key); + $digitalPostContext = $this->session->get($key); + + // We only need/use it once, so just remove it after fetching it. + if ($digitalPostContext) { + $this->session->remove($key); + } + + return $digitalPostContext; } /** diff --git a/modules/os2forms_digital_post/src/Helper/WebformHelperSF1601.php b/modules/os2forms_digital_post/src/Helper/WebformHelperSF1601.php index 860e5e0d..e26e0b1b 100644 --- a/modules/os2forms_digital_post/src/Helper/WebformHelperSF1601.php +++ b/modules/os2forms_digital_post/src/Helper/WebformHelperSF1601.php @@ -156,9 +156,7 @@ public function sendDigitalPost(WebformSubmissionInterface $submission, array $h $recipientIdentifierType = 'CPR'; } - $digitalPostAddressData = $this->getAddressForDigitalPost($lookupResult); - - $this->digitalPostSubscriber->setDigitalPostContext($submission, $digitalPostAddressData); + $this->digitalPostSubscriber->setDigitalPostContext($submission, $lookupResult); $senderSettings = $this->settings->getSender(); $messageOptions = [ @@ -350,31 +348,4 @@ public function deleteMessages(array $webformSubmissions): void { $this->beskedfordelerHelper->deleteMessages($webformSubmissions); } - /** - * Gets lookup results addresses in the format needed for SF1601. - */ - private function getAddressForDigitalPost(CprLookupResult|CompanyLookupResult $lookupResult): array { - $name = $lookupResult->getName(); - - $address = $lookupResult->getStreet(); - - if ($lookupResult->getHouseNr()) { - $address .= ' ' . $lookupResult->getHouseNr(); - } - if ($lookupResult->getFloor()) { - $address .= ' ' . $lookupResult->getFloor(); - } - if ($lookupResult->getApartmentNr()) { - $address .= ' ' . $lookupResult->getApartmentNr(); - } - - $zipAndCity = $lookupResult->getPostalCode() . ' ' . $lookupResult->getCity(); - - return [ - 'name' => $name, - 'address' => $address, - 'zipAndCity' => $zipAndCity, - ]; - } - } From cfdd08f9e1e75f20b5560d611e30dadfc6bdde03 Mon Sep 17 00:00:00 2001 From: jekuaitk Date: Tue, 10 Feb 2026 16:11:07 +0100 Subject: [PATCH 06/11] 288: Updated README with injected html and example styling --- modules/os2forms_digital_post/README.md | 103 +++++++++++++++++++++--- 1 file changed, 92 insertions(+), 11 deletions(-) diff --git a/modules/os2forms_digital_post/README.md b/modules/os2forms_digital_post/README.md index 9267cb5f..805e94b4 100644 --- a/modules/os2forms_digital_post/README.md +++ b/modules/os2forms_digital_post/README.md @@ -99,11 +99,14 @@ This should be done in OS2Forms Attachment-templates, see To see the exact requirements for address placement, see [digst_a4_farve_ej_til_kant_demo_ny_rudeplacering.pdf](docs/digst_a4_farve_ej_til_kant_demo_ny_rudeplacering.pdf). -The injected HTML is on the form: +### The injected HTML -Without extended address information: +Variations of the injected HTML include extended addresses and c/o. + +Without extended address information or c/o: ```html +
Jeppe
@@ -113,32 +116,32 @@ Without extended address information:
``` -With extended address information: +With just an extended address: ```html
-
-
Jeppe
-
Test vej HouseNr Floor AppartmentNr
-
2100 Copenhagen
-
+
+
Jeppe
+
Test vej HouseNr Floor AppartmentNr
+
2100 Copenhagen
+
``` -Without c/o: +With just c/o: ```html
Jeppe
-
Test vej HouseNr Floor AppartmentNr
+
c/o Mikkel
Test vej HouseNr
2100 Copenhagen
``` -With c/o: +With extended address information and c/o: ```html
@@ -153,3 +156,81 @@ With c/o: +### Styling of the HTML + +The following SCSS can be used to style the injected HTML accordingly: + +```scss +$margin-top: 25mm; +// There is no exact measurement for margin right in the specifications +$margin-right: 10mm; +$margin-bottom: 20mm; +$margin-left: 17mm; +$page-width: 210mm; +$page-height: 297mm; +$envelope-window-height: 89mm; +$envelope-window-width: 115mm; +$recipient-window-height: 21mm; +$recipient-window-width: 59mm; + +@page { + size: A4; + margin: 0; +} + +html, body { + font-family:"DejaVu Sans",Helvetica,Arial,sans-serif; +} + +body { + margin-top: $margin-top; + margin-right: $margin-right; + margin-bottom: $margin-bottom; + margin-left: $margin-left; +} + +header { + position: fixed; + top: 0; + height: $margin-top; + width: calc($page-width - $margin-left - $margin-right); + font-size: 12px; +} + +footer { + position: fixed; + bottom: 0; + height: $margin-bottom; + width: calc($page-width - $margin-left - $margin-right); + font-size: 12px; +} + +// Style the envelope window that may be injected by Digital Post. +// Note that top/left is made from the assumption that @page has margin 0. +// @see \Drupal\os2forms_digital_post\EventSubscriber\Os2formsDigitalPostSubscriber:onPrintRender +#envelope-window-digital-post { + position: absolute; + top: $margin-top; + left: $margin-left; + height: $envelope-window-height; + width: $envelope-window-width; + background: white +} + +// If envelope window is present, move webform content down +// @see os2forms_digital_post +#envelope-window-digital-post ~ * .webform-entity-print-body { + margin-top: $envelope-window-height; +} + +#envelope-window-digital-post > div { + position: absolute; + top: 16mm; + left: 4mm; + font-size: 10px; + height: $recipient-window-height; + width: $recipient-window-width; +} + +// More custom styling... +``` From e3a719a48b9e96e0151b0c89966d54d3675d40b9 Mon Sep 17 00:00:00 2001 From: jekuaitk Date: Tue, 10 Feb 2026 16:17:59 +0100 Subject: [PATCH 07/11] 288: Cleaned up example styling --- modules/os2forms_digital_post/README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/modules/os2forms_digital_post/README.md b/modules/os2forms_digital_post/README.md index 805e94b4..16e83513 100644 --- a/modules/os2forms_digital_post/README.md +++ b/modules/os2forms_digital_post/README.md @@ -178,10 +178,6 @@ $recipient-window-width: 59mm; margin: 0; } -html, body { - font-family:"DejaVu Sans",Helvetica,Arial,sans-serif; -} - body { margin-top: $margin-top; margin-right: $margin-right; @@ -223,6 +219,7 @@ footer { margin-top: $envelope-window-height; } +// Style the h-card div #envelope-window-digital-post > div { position: absolute; top: 16mm; From fdaafd5ca437fd61bd9ffdded019750ed6fb4f9c Mon Sep 17 00:00:00 2001 From: Jeppe Kuhlmann Andersen <78410897+jekuaitk@users.noreply.github.com> Date: Mon, 16 Feb 2026 10:09:35 +0100 Subject: [PATCH 08/11] Update modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php Co-authored-by: Mikkel Ricky --- .../src/EventSubscriber/Os2formsDigitalPostSubscriber.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php b/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php index 4fefcffa..81ca5ef0 100644 --- a/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php +++ b/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php @@ -52,7 +52,7 @@ public function onPrintRender(PrintHtmlAlterEvent $event): void { // Generate address HTML. $addressHtml = '
'; $addressHtml .= '
' . htmlspecialchars($lookupResult->getName()) . '
'; - if ($lookupResult->getCoName()) { + if ($lookupResult instanceof CprLookupResult && $lookupResult->getCoName()) { $addressHtml .= '
c/o ' . htmlspecialchars($lookupResult->getCoName()) . '
'; } $addressHtml .= '
'; From a552bebc9fb7d6b1dc6265ff581a390ac54633fb Mon Sep 17 00:00:00 2001 From: Jeppe Kuhlmann Andersen <78410897+jekuaitk@users.noreply.github.com> Date: Mon, 16 Feb 2026 10:09:53 +0100 Subject: [PATCH 09/11] Update modules/os2forms_digital_post/README.md Co-authored-by: Mikkel Ricky --- modules/os2forms_digital_post/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/os2forms_digital_post/README.md b/modules/os2forms_digital_post/README.md index 16e83513..2c550502 100644 --- a/modules/os2forms_digital_post/README.md +++ b/modules/os2forms_digital_post/README.md @@ -85,7 +85,7 @@ drush os2forms-digital-post:test:send --help To comply with the address placement in the envelope window (kuvert-rude) an [event subscriber](src/EventSubscriber/Os2formsDigitalPostSubscriber.php) is -used to inject an address information element into generated HTML before it is +used to inject an address information element into the generated HTML before it is converted to a PDF. We are only guaranteed to have the necessary information when in a digital From 7ed8d8f43a6fea0be3605bf6f09f9230cab3a7d8 Mon Sep 17 00:00:00 2001 From: Jeppe Kuhlmann Andersen <78410897+jekuaitk@users.noreply.github.com> Date: Mon, 16 Feb 2026 10:10:05 +0100 Subject: [PATCH 10/11] Update modules/os2forms_digital_post/README.md Co-authored-by: Mikkel Ricky --- modules/os2forms_digital_post/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/os2forms_digital_post/README.md b/modules/os2forms_digital_post/README.md index 2c550502..851e6342 100644 --- a/modules/os2forms_digital_post/README.md +++ b/modules/os2forms_digital_post/README.md @@ -158,7 +158,7 @@ With extended address information and c/o: ### Styling of the HTML -The following SCSS can be used to style the injected HTML accordingly: +The following [SCSS](https://sass-lang.com/) can be used to style the injected HTML accordingly: ```scss $margin-top: 25mm; From 0c397392b8a4d8debbb89a06e5bd700dbd6416eb Mon Sep 17 00:00:00 2001 From: Jeppe Kuhlmann Andersen <78410897+jekuaitk@users.noreply.github.com> Date: Mon, 16 Feb 2026 10:26:03 +0100 Subject: [PATCH 11/11] Update modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php Co-authored-by: Mikkel Ricky --- .../src/EventSubscriber/Os2formsDigitalPostSubscriber.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php b/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php index 81ca5ef0..8c95f5c7 100644 --- a/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php +++ b/modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php @@ -53,7 +53,7 @@ public function onPrintRender(PrintHtmlAlterEvent $event): void { $addressHtml = '
'; $addressHtml .= '
' . htmlspecialchars($lookupResult->getName()) . '
'; if ($lookupResult instanceof CprLookupResult && $lookupResult->getCoName()) { - $addressHtml .= '
c/o ' . htmlspecialchars($lookupResult->getCoName()) . '
'; + $addressHtml .= '
c/o ' . htmlspecialchars($lookupResult->getCoName()) . '
'; } $addressHtml .= '
'; $addressHtml .= '' . htmlspecialchars($streetAddress) . '';