Fix customer registration duplicate recovery

This commit is contained in:
Jeppe Bundgaard
2026-06-11 12:04:56 +02:00
parent bdb1a0074b
commit d06c78119b
3 changed files with 241 additions and 56 deletions
+119 -23
View File
@@ -409,15 +409,7 @@ class authRoute
* Check if the cvr already exists
*/
$economic = new economic();
$economic_response = ($economic->customers->customers->search([
'corporateIdentificationNumber' => (string)$cvr,
], [
'skipPages' => 0,
'pageSize' => 1, // Since the limit is 1000, we need to set the page size to 1000.
])->collection);
if (!is_array($economic_response)) {
$economic_response = [];
}
$economic_response = $this->searchEconomicCustomersByCvr($economic, (string)$cvr);
$localUserExists = $this->localCustomerNumberExists($companyPhone);
$matchingEconomicCustomer = $this->findEconomicCustomerByNumber($economic_response, $companyPhone);
@@ -455,15 +447,37 @@ class authRoute
// Get the CVR company information used for the e-conomic customer payload.
$companyInformation = (new virkdata())->getCompanyInformation($cvr, '', []);
$name = (string)($companyInformation->name ?? '');
$result = $economic->createCustomer(
(int)$companyPhone,
$name,
(int)$cvr,
(string)$invoiceEmail,
(int)$companyPhone,
(int)$contactPhone,
$companyInformation,
);
try {
$result = $economic->createCustomer(
(int)$companyPhone,
$name,
(int)$cvr,
(string)$invoiceEmail,
(int)$companyPhone,
(int)$contactPhone,
$companyInformation,
);
} catch (Exception $exception) {
$recoveredCustomer = $this->recoverRegistrationAfterCreateFailure(
$economic,
(string)$cvr,
$companyPhone,
(string)$invoiceEmail,
$exception
);
if ($recoveredCustomer !== null) {
$response->success($recoveredCustomer, 200);
}
$this->logRegisterCvrIssue('AUTH_REGISTER_CVR_CREATE_FAILED', [
'phase' => 'create',
'cvr' => (string)$cvr,
'requestedCustomerNumber' => $companyPhone,
'message' => $exception->getMessage(),
]);
$response->error('Failed to create customer in e-conomic.', 502);
}
if (!isset($result->customerNumber) || !is_numeric($result->customerNumber)) {
$this->logRegisterCvrIssue('AUTH_REGISTER_CVR_INVALID_CREATE_RESPONSE', [
@@ -495,7 +509,7 @@ class authRoute
);
}
$this->bootstrapLocalCustomerOrFail($companyPhone);
$this->bootstrapLocalCustomerOrFail($companyPhone, $result);
$this->sendRegistrationWelcomeEmails($companyPhone, (string)$invoiceEmail);
$response->success($result, 201);
});
@@ -758,6 +772,61 @@ class authRoute
return count($rows) > 0;
}
private function searchEconomicCustomersByCvr(economic $economic, string $cvr): array
{
$economic_response = ($economic->customers->customers->search([
'corporateIdentificationNumber' => $cvr,
], [
'skipPages' => 0,
'pageSize' => 1,
])->collection);
return is_array($economic_response) ? $economic_response : [];
}
private function recoverRegistrationAfterCreateFailure(
economic $economic,
string $cvr,
int $customerNumber,
string $invoiceEmail,
Exception $exception
): ?object {
if (!$this->isRecoverableEconomicDuplicateError($exception)) {
return null;
}
try {
$economic_response = $this->searchEconomicCustomersByCvr($economic, $cvr);
} catch (Exception $searchException) {
$this->logRegisterCvrIssue('AUTH_REGISTER_CVR_CREATE_RECOVERY_SEARCH_FAILED', [
'phase' => 'create_recovery',
'cvr' => $cvr,
'requestedCustomerNumber' => $customerNumber,
'message' => $searchException->getMessage(),
]);
return null;
}
$matchingEconomicCustomer = $this->findEconomicCustomerByNumber($economic_response, $customerNumber);
if ($matchingEconomicCustomer === null || $this->localCustomerNumberExists($customerNumber)) {
return null;
}
$this->bootstrapLocalCustomerOrFail($customerNumber, $matchingEconomicCustomer);
$this->sendRegistrationWelcomeEmails($customerNumber, $invoiceEmail);
return $matchingEconomicCustomer;
}
private function isRecoverableEconomicDuplicateError(Exception $exception): bool
{
$message = strtolower($exception->getMessage());
return str_contains($message, 'already exists')
|| str_contains($message, 'already exist')
|| str_contains($message, 'duplicate');
}
private function findEconomicCustomerByNumber(array $customers, int $customerNumber): ?object
{
foreach ($customers as $customer) {
@@ -785,19 +854,46 @@ class authRoute
/**
* @throws Exception
*/
private function bootstrapLocalCustomerOrFail(int $customerNumber): users_o
private function bootstrapLocalCustomerOrFail(int $customerNumber, ?object $economicCustomer = null): users_o
{
global $response;
$customer = (new users_o())->getUserByCustomerNumber($customerNumber);
if (method_exists($customer, 'exists') && $customer->exists()) {
return $customer;
$customer = new users_o();
try {
$customer = $customer->getUserByCustomerNumber($customerNumber);
if (method_exists($customer, 'exists') && $customer->exists()) {
return $customer;
}
} catch (Exception $exception) {
$this->logRegisterCvrIssue('AUTH_REGISTER_CVR_LOCAL_BOOTSTRAP_LOOKUP_FAILED', [
'customerNumber' => $customerNumber,
'message' => $exception->getMessage(),
]);
}
if (
$economicCustomer !== null
&& $this->extractEconomicCustomerNumber($economicCustomer) === $customerNumber
&& method_exists($customer, 'importCustomerFromEconomicCustomerData')
) {
try {
$importedCustomer = $customer->importCustomerFromEconomicCustomerData($economicCustomer);
if (is_object($importedCustomer) && method_exists($importedCustomer, 'exists') && $importedCustomer->exists()) {
return $importedCustomer;
}
} catch (Exception $exception) {
$this->logRegisterCvrIssue('AUTH_REGISTER_CVR_LOCAL_SNAPSHOT_BOOTSTRAP_FAILED', [
'customerNumber' => $customerNumber,
'message' => $exception->getMessage(),
]);
}
}
$this->logRegisterCvrIssue('AUTH_REGISTER_CVR_LOCAL_BOOTSTRAP_FAILED', [
'customerNumber' => $customerNumber,
]);
$response->error('Customer was created in e-conomic but could not be imported locally.', 500);
throw new Exception('Customer was created in e-conomic but could not be imported locally.');
}
/**