From 1d604b359094b380eb3c240d5c702da5db60e9c7 Mon Sep 17 00:00:00 2001 From: Stanislav Kutasevits Date: Mon, 1 Jun 2026 17:10:23 +0300 Subject: [PATCH 1/4] OS-245 adding P-number lookup --- CHANGELOG.md | 2 + src/LookupResult/CompanyLookupResult.php | 56 +++++-- .../os2web/DataLookup/DatafordelerCVR.php | 17 -- .../os2web/DataLookup/DatafordelerPNumber.php | 158 ++++++++++++++---- 4 files changed, 165 insertions(+), 68 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac9bf52..12a3224 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +* Adding Datafordeler P-number lookup + ## [3.2.0] - 2026-05-29 * [PR-32](https://github.com/OS2web/os2web_datalookup/pull/32) diff --git a/src/LookupResult/CompanyLookupResult.php b/src/LookupResult/CompanyLookupResult.php index 1ab4ef0..0daf997 100644 --- a/src/LookupResult/CompanyLookupResult.php +++ b/src/LookupResult/CompanyLookupResult.php @@ -39,6 +39,13 @@ class CompanyLookupResult { */ protected string $cvr; + /** + * The P-Number number. + * + * @var string + */ + protected string $pNumber; + /** * Company name. * @@ -95,13 +102,6 @@ class CompanyLookupResult { */ protected string $municipalityCode; - /** - * Address of the person. - * - * @var string - */ - protected string $address; - /** * Check the state of successful. * @@ -162,6 +162,24 @@ public function setCvr(string $cpr): void { $this->cvr = $cpr; } + /** + * Get P-Number number. + * + * @return string + */ + public function getPNumber(): string { + return $this->pNumber; + } + + /** + * Set P-Number number. + * + * @param string $pNumber + */ + public function setPNumber(string $pNumber): void { + $this->pNumber = $pNumber; + } + /** * Get name. * @@ -329,17 +347,21 @@ public function setMunicipalityCode(string $municipalityCode): void { * The address. */ public function getAddress(): string { - return $this->address; - } + $address = $this->getStreet(); + if ($this->getHouseNr()) { + $address .= ' ' . $this->getHouseNr(); + } + if ($this->getFloor()) { + $address .= ' ' . $this->getFloor(); + } + if ($this->getApartmentNr()) { + $address .= ' ' . $this->getApartmentNr(); + } + if ($this->getPostalCode() && $this->getCity()) { + $address .= ', ' . $this->getPostalCode() . ' ' . $this->getCity(); + } - /** - * Set address. - * - * @param string $address - * The address to set. - */ - public function setAddress(string $address): void { - $this->address = $address; + return $address; } /** diff --git a/src/Plugin/os2web/DataLookup/DatafordelerCVR.php b/src/Plugin/os2web/DataLookup/DatafordelerCVR.php index 81c429e..ac463b0 100644 --- a/src/Plugin/os2web/DataLookup/DatafordelerCVR.php +++ b/src/Plugin/os2web/DataLookup/DatafordelerCVR.php @@ -127,23 +127,6 @@ public function lookup(string $param): CompanyLookupResult { $city = $address->CVRAdresse_postdistrikt ?? $cvrResult->getPostalCode(); $cvrResult->setCity($city); $cvrResult->setMunicipalityCode($address->CVRAdresse_kommunekode ?? ''); - - // Composing full address in one line. - $address = $cvrResult->getStreet(); - if ($cvrResult->getHouseNr()) { - $address .= ' ' . $cvrResult->getHouseNr(); - } - if ($cvrResult->getFloor()) { - $address .= ' ' . $cvrResult->getFloor(); - } - if ($cvrResult->getApartmentNr()) { - $address .= ' ' . $cvrResult->getApartmentNr(); - } - if ($cvrResult->getPostalCode() && $cvrResult->getCity()) { - $address .= ', ' . $cvrResult->getPostalCode() . ' ' . $cvrResult->getCity(); - } - - $cvrResult->setAddress($address); } } else { diff --git a/src/Plugin/os2web/DataLookup/DatafordelerPNumber.php b/src/Plugin/os2web/DataLookup/DatafordelerPNumber.php index 23cf94e..00443aa 100644 --- a/src/Plugin/os2web/DataLookup/DatafordelerPNumber.php +++ b/src/Plugin/os2web/DataLookup/DatafordelerPNumber.php @@ -6,7 +6,9 @@ use Drupal\Core\Messenger\MessengerInterface; use Drupal\Core\Render\Markup; use Drupal\os2web_datalookup\LookupResult\CompanyLookupResult; -use GuzzleHttp\Exception\ClientException; +use GuzzleHttp\Client; +use GuzzleHttp\Exception\GuzzleException; +use Psr\Http\Message\ResponseInterface; /** * Defines a plugin for DatafordelerPNumber. @@ -17,14 +19,22 @@ * group = "pnumber_lookup" * ) */ -class DatafordelerPNumber extends DatafordelerBase implements DataLookupCompanyInterface { +class DatafordelerPNumber extends DataLookupBase implements DataLookupCompanyInterface { + + /** + * Http client. + * + * @var \GuzzleHttp\Client + */ + protected Client $httpClient; /** * {@inheritdoc} */ public function defaultConfiguration(): array { return [ - 'webserviceurl_live' => 'https://s5-certservices.datafordeler.dk/CVR/HentCVRData/1/REST/', + 'webserviceurl_live' => 'https://graphql.datafordeler.dk/flexibleCurrent/v1', + 'api_key' => '', ] + parent::defaultConfiguration(); } @@ -32,7 +42,18 @@ public function defaultConfiguration(): array { * {@inheritdoc} */ public function buildConfigurationForm(array $form, FormStateInterface $form_state): array { - $form = parent::buildConfigurationForm($form, $form_state); + $form['webserviceurl_live'] = [ + '#type' => 'textfield', + '#title' => $this->t('Webservice URL (LIVE)'), + '#description' => $this->t('Live URL against which to make the request, e.g. https://graphql.datafordeler.dk/flexibleCurrent/v1'), + '#default_value' => $this->configuration['webserviceurl_live'], + ]; + + $form['api_key'] = [ + '#type' => 'textfield', + '#title' => $this->t('API Key'), + '#default_value' => $this->configuration['api_key'], + ]; $form['test_pnumber'] = [ '#type' => 'textfield', @@ -46,7 +67,12 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta * {@inheritdoc} */ public function submitConfigurationForm(array &$form, FormStateInterface $form_state): void { - parent::submitConfigurationForm($form, $form_state); + $keys = array_keys($this->defaultConfiguration()); + $configuration = $this->getConfiguration(); + foreach ($keys as $key) { + $configuration[$key] = $form_state->getValue($key); + } + $this->setConfiguration($configuration); if (!empty($form_state->getValue('test_pnumber'))) { $lookupResult = $this->lookup($form_state->getValue('test_pnumber')); @@ -64,52 +90,116 @@ public function submitConfigurationForm(array &$form, FormStateInterface $form_s */ public function lookup(string $param): CompanyLookupResult { try { - $msg = sprintf('Hent produktionsenhed med PNummer: %s', $param); + if (!preg_match('/^\d{10}$/', $param)) { + throw new \InvalidArgumentException('P-number must be exactly 10 digits.'); + } + + $msg = sprintf('Hent virksomhed med PNummer: %s', $param); $this->auditLogger->info('DataLookup', $msg); - $response = $this->getResponse('hentProduktionsenhedMedPNummer', ['query' => ['ppNummer' => $param]]); + $response = $this->executeQuery($param); $result = json_decode((string) $response->getBody()); } - catch (ClientException $e) { - $msg = sprintf('Hent produktionsenhed med PNummer (%s): %s', $param, $e->getMessage()); + catch (GuzzleException | \InvalidArgumentException $e) { + $msg = sprintf('Hent virksomhed med PNummer (%s): %s', $param, $e->getMessage()); $this->auditLogger->error('DataLookup', $msg); $result = $e->getMessage(); } - $cvrResult = new CompanyLookupResult(); - if ($result && isset($result->produktionsenhed) && !empty((array) $result->produktionsenhed)) { - $cvrResult->setSuccessful(); - $cvrResult->setCvr($result->produktionsenhed->tilknyttetVirksomhedsCVRNummer ?? ''); + $companyLookupResult = new CompanyLookupResult(); + if ($result && isset($result->data->CVR_Produktionsenhed->nodes) && !empty($result->data->CVR_Produktionsenhed->nodes)) { + $companyGraph = $result->data->CVR_Produktionsenhed->nodes[0]->id_CVR_CVREnhed_id_ref->nodes[0]; - if ($result->produktionsenhedsnavn) { - $cvrResult->setName($result->produktionsenhedsnavn->vaerdi); + if ($result->data->CVR_Produktionsenhed->nodes[0]->tilknyttetVirksomhedsCVRNummer) { + $companyLookupResult->setCvr($result->data->CVR_Produktionsenhed->nodes[0]->tilknyttetVirksomhedsCVRNummer); } - if ($result->beliggenhedsadresse) { - $address = $result->beliggenhedsadresse; - - $cvrResult->setStreet($address->CVRAdresse_vejnavn ?? ''); - $cvrResult->setHouseNr($address->CVRAdresse_husnummerFra ?? ''); - $cvrResult->setFloor($address->CVRAdresse_etagebetegnelse ?? ''); - $cvrResult->setApartmentNr($address->CVRAdresse_doerbetegnelse ?? ''); - $cvrResult->setPostalCode($address->CVRAdresse_postnummer ?? ''); - $city = implode(' ', array_filter([ - $address->CVRAdresse_postdistrikt ?? NULL, - $cvrResult->getPostalCode() ?? NULL, - ])); - $cvrResult->setCity($city); - $cvrResult->setMunicipalityCode($address->CVRAdresse_kommunekode ?? ''); - $address = $cvrResult->getStreet() . ' ' . $cvrResult->getHouseNr() . ' ' . $cvrResult->getFloor() . $cvrResult->getApartmentNr(); - $cvrResult->setAddress(trim($address)); + $companyLookupResult->setSuccessful(); + $companyLookupResult->setPNumber($param); + + if ($companyGraph->id_CVR_Navn_CVREnhedsId_ref) { + $companyLookupResult->setName($companyGraph->id_CVR_Navn_CVREnhedsId_ref->vaerdi); + } + + if ($companyGraph->id_CVR_Adressering_CVREnhedsId_ref) { + $address = $companyGraph->id_CVR_Adressering_CVREnhedsId_ref->nodes[0]; + + $companyLookupResult->setStreet($address->CVRAdresse_vejnavn ?? ''); + $companyLookupResult->setHouseNr($address->CVRAdresse_husnummerFra ?? ''); + $companyLookupResult->setFloor($address->CVRAdresse_etagebetegnelse ?? ''); + $companyLookupResult->setApartmentNr($address->CVRAdresse_doerbetegnelse ?? ''); + $companyLookupResult->setPostalCode($address->CVRAdresse_postnummer ?? ''); + $city = $address->CVRAdresse_postdistrikt ?? $companyLookupResult->getPostalCode(); + $companyLookupResult->setCity($city); + $companyLookupResult->setMunicipalityCode($address->CVRAdresse_kommunekode ?? ''); } } else { - $cvrResult->setSuccessful(FALSE); + $companyLookupResult->setSuccessful(FALSE); if (is_string($result)) { - $cvrResult->setErrorMessage($result); + $companyLookupResult->setErrorMessage($result); } } - return $cvrResult; + return $companyLookupResult; } + /** + * Executes the GraphQL lookup request for a specific P-number number. + * + * Builds the GraphQL payload and sends it to the configured Datafordeler + * endpoint using the shared HTTP request flow from the parent class. + * + * @param string $pNumber + * The P-Number number to look up. + * + * @return \Psr\Http\Message\ResponseInterface + * The raw HTTP response from the GraphQL endpoint. + * + * @throws \GuzzleHttp\Exception\GuzzleException + */ + private function executeQuery($pNumber): ResponseInterface { + $this->httpClient = new Client(); + + // Setting date to TODAY 00:00:00, so that we are always getting up-to-date + // information. + $virkningstid = (new \DateTimeImmutable('today', new \DateTimeZone('UTC'))) + ->format('Y-m-d\T00:00:00\Z'); + + $query = <<configuration['webserviceurl_live']; + + return $this->httpClient->post($webserviceUrl, [ + 'query' => [ + 'apiKey' => $this->configuration['api_key'], + ], + 'json' => [ + 'query' => $query, + ], + ]); + } } From 2076f3d778dcd432f9ed14f3eabb62d1b5ef02b1 Mon Sep 17 00:00:00 2001 From: Stanislav Kutasevits Date: Mon, 1 Jun 2026 17:16:36 +0300 Subject: [PATCH 2/4] OS-245 phpcs fixes --- src/LookupResult/CompanyLookupResult.php | 4 ++-- src/Plugin/os2web/DataLookup/DatafordelerPNumber.php | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/LookupResult/CompanyLookupResult.php b/src/LookupResult/CompanyLookupResult.php index 0daf997..581d6fc 100644 --- a/src/LookupResult/CompanyLookupResult.php +++ b/src/LookupResult/CompanyLookupResult.php @@ -167,7 +167,7 @@ public function setCvr(string $cpr): void { * * @return string */ - public function getPNumber(): string { + public function getPnumber(): string { return $this->pNumber; } @@ -176,7 +176,7 @@ public function getPNumber(): string { * * @param string $pNumber */ - public function setPNumber(string $pNumber): void { + public function setPnumber(string $pNumber): void { $this->pNumber = $pNumber; } diff --git a/src/Plugin/os2web/DataLookup/DatafordelerPNumber.php b/src/Plugin/os2web/DataLookup/DatafordelerPNumber.php index 00443aa..ba1ac2f 100644 --- a/src/Plugin/os2web/DataLookup/DatafordelerPNumber.php +++ b/src/Plugin/os2web/DataLookup/DatafordelerPNumber.php @@ -114,7 +114,7 @@ public function lookup(string $param): CompanyLookupResult { } $companyLookupResult->setSuccessful(); - $companyLookupResult->setPNumber($param); + $companyLookupResult->setPnumber($param); if ($companyGraph->id_CVR_Navn_CVREnhedsId_ref) { $companyLookupResult->setName($companyGraph->id_CVR_Navn_CVREnhedsId_ref->vaerdi); @@ -202,4 +202,5 @@ private function executeQuery($pNumber): ResponseInterface { ], ]); } + } From 73e9a4820e49cacfac7899731943a4021fc3ba5b Mon Sep 17 00:00:00 2001 From: Stanislav Kutasevits Date: Mon, 1 Jun 2026 17:18:53 +0300 Subject: [PATCH 3/4] OS-245 phpcs fixes --- src/LookupResult/CompanyLookupResult.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/LookupResult/CompanyLookupResult.php b/src/LookupResult/CompanyLookupResult.php index 581d6fc..4ff6ff2 100644 --- a/src/LookupResult/CompanyLookupResult.php +++ b/src/LookupResult/CompanyLookupResult.php @@ -166,6 +166,7 @@ public function setCvr(string $cpr): void { * Get P-Number number. * * @return string + * P-Number. */ public function getPnumber(): string { return $this->pNumber; @@ -175,6 +176,7 @@ public function getPnumber(): string { * Set P-Number number. * * @param string $pNumber + * P-Number. */ public function setPnumber(string $pNumber): void { $this->pNumber = $pNumber; From 2c6bf38bfa2b9f18b9c3b8b3982f999725194579 Mon Sep 17 00:00:00 2001 From: Stanislav Kutasevits Date: Tue, 2 Jun 2026 10:07:40 +0300 Subject: [PATCH 4/4] OS-245 address getting fix --- src/LookupResult/CompanyLookupResult.php | 28 +++++++++++++++--------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/LookupResult/CompanyLookupResult.php b/src/LookupResult/CompanyLookupResult.php index 4ff6ff2..e021c8d 100644 --- a/src/LookupResult/CompanyLookupResult.php +++ b/src/LookupResult/CompanyLookupResult.php @@ -37,70 +37,70 @@ class CompanyLookupResult { * * @var string */ - protected string $cvr; + protected string $cvr = ''; /** * The P-Number number. * * @var string */ - protected string $pNumber; + protected string $pNumber = ''; /** * Company name. * * @var string */ - protected string $name; + protected string $name = ''; /** * Street of the person. * * @var string */ - protected string $street; + protected string $street = ''; /** * Street house number of the person. * * @var string */ - protected string $houseNr; + protected string $houseNr = ''; /** * Floor number of the person. * * @var string */ - protected string $floor; + protected string $floor = ''; /** * Apartment number of the person. * * @var string */ - protected string $apartmentNr; + protected string $apartmentNr = ''; /** * Postal code of the person. * * @var string */ - protected string $postalCode; + protected string $postalCode = ''; /** * City of the person. * * @var string */ - protected string $city; + protected string $city = ''; /** * Municipality code of the person. * * @var string */ - protected string $municipalityCode; + protected string $municipalityCode = ''; /** * Check the state of successful. @@ -376,6 +376,14 @@ public function getAddress(): string { * The field value or the empty string if the field does not exist. */ public function getFieldValue(string $field): mixed { + $calculatedFields = [ + $this::ADDRESS => fn() => $this->getAddress(), + ]; + + if (isset($calculatedFields[$field])) { + return $calculatedFields[$field](); + } + if (property_exists($this, $field) && isset($this->{$field})) { return $this->{$field}; }