Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
19 changes: 19 additions & 0 deletions modules/os2forms_digital_post/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).

Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand All @@ -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' }
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

namespace Drupal\os2forms_digital_post\EventSubscriber;

use Drupal\entity_print\Event\PrintEvents;
use Drupal\entity_print\Event\PrintHtmlAlterEvent;
use Drupal\webform\WebformSubmissionInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RequestStack;

/**
* Used to alter the generated PDF to align with digital post requirements.
*/
final class Os2formsDigitalPostSubscriber implements EventSubscriberInterface {

public function __construct(private readonly RequestStack $requestStack) {
}

/**
* Post render entity_print event.
*
* Injects an envelope-window element containing address information.
*/
public function onPrintRender(PrintHtmlAlterEvent $event): void {
$html = &$event->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 = <<<HTML
<div class="envelope-window" id="envelope-window-digital-post">
<div class="envelope-window-recipient-section" id="envelope-window-recipient-section-digital-post">
$name</br>
$address</br>
$zipAndCity
</div>
</div>
HTML;
$html = preg_replace('@<body[^>]*>@', '${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 {

Check failure on line 67 in modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php

View workflow job for this annotation

GitHub Actions / PHP code analysis

Method Drupal\os2forms_digital_post\EventSubscriber\Os2formsDigitalPostSubscriber::setDigitalPostContext() has parameter $digitalPostContext with no value type specified in iterable type array.
$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 {

Check failure on line 75 in modules/os2forms_digital_post/src/EventSubscriber/Os2formsDigitalPostSubscriber.php

View workflow job for this annotation

GitHub Actions / PHP code analysis

Method Drupal\os2forms_digital_post\EventSubscriber\Os2formsDigitalPostSubscriber::getDigitalPostContext() return type has no value type specified in iterable type 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();
}

}
35 changes: 35 additions & 0 deletions modules/os2forms_digital_post/src/Helper/WebformHelperSF1601.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -62,6 +65,7 @@
#[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');
Expand Down Expand Up @@ -152,6 +156,10 @@
$recipientIdentifierType = 'CPR';
}

$digitalPostAddressData = $this->getAddressForDigitalPost($lookupResult);

$this->digitalPostSubscriber->setDigitalPostContext($submission, $digitalPostAddressData);

$senderSettings = $this->settings->getSender();
$messageOptions = [
self::RECIPIENT_IDENTIFIER_TYPE => $recipientIdentifierType,
Expand Down Expand Up @@ -342,4 +350,31 @@
$this->beskedfordelerHelper->deleteMessages($webformSubmissions);
}

/**
* Gets lookup results addresses in the format needed for SF1601.
*/
private function getAddressForDigitalPost(CprLookupResult|CompanyLookupResult $lookupResult): array {

Check failure on line 356 in modules/os2forms_digital_post/src/Helper/WebformHelperSF1601.php

View workflow job for this annotation

GitHub Actions / PHP code analysis

Method Drupal\os2forms_digital_post\Helper\WebformHelperSF1601::getAddressForDigitalPost() return type has no value type specified in iterable type 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,
];
}

}
Loading