diff --git a/Modules/Core/Tests/AbstractAdminPanelTestCase.php b/Modules/Core/Tests/AbstractAdminPanelTestCase.php
index d25a806d6..4340275b2 100644
--- a/Modules/Core/Tests/AbstractAdminPanelTestCase.php
+++ b/Modules/Core/Tests/AbstractAdminPanelTestCase.php
@@ -9,6 +9,7 @@
abstract class AbstractAdminPanelTestCase extends BaseTestCase
{
+ use CreatesApplication;
use RefreshDatabase;
protected ?User $superAdmin;
diff --git a/Modules/Core/Tests/AbstractCompanyPanelTestCase.php b/Modules/Core/Tests/AbstractCompanyPanelTestCase.php
index 3c18f2129..dfef9d82e 100644
--- a/Modules/Core/Tests/AbstractCompanyPanelTestCase.php
+++ b/Modules/Core/Tests/AbstractCompanyPanelTestCase.php
@@ -11,6 +11,7 @@
abstract class AbstractCompanyPanelTestCase extends BaseTestCase
{
+ use CreatesApplication;
use RefreshDatabase;
protected User $user;
diff --git a/Modules/Core/Tests/Unit/DateFieldAutoPopulationTest.php b/Modules/Core/Tests/Unit/DateFieldAutoPopulationTest.php
index 8d3fd221c..94f53bb65 100644
--- a/Modules/Core/Tests/Unit/DateFieldAutoPopulationTest.php
+++ b/Modules/Core/Tests/Unit/DateFieldAutoPopulationTest.php
@@ -25,25 +25,18 @@ class DateFieldAutoPopulationTest extends AbstractCompanyPanelTestCase
use RefreshDatabase;
use WithFaker;
- protected User $user;
-
- protected Company $company;
-
protected function setUp(): void
{
parent::setUp();
- $this->user = User::factory()->create(); /* @var User $user */
- $this->company = Company::factory()->create(); /* @var Company $company */
- $this->user->companies()->attach($this->company);
+ // Parent already creates $this->user and $this->company
+ // No need to create them again
}
#[Test]
#[Group('date-auto-population')]
public function it_auto_populates_invoice_date_fields_on_create_form(): void
{
- $this->markTestIncomplete();
-
/* arrange */
$customer = Relation::factory()->for($this->company)->customer()->create();
$documentGroup = Numbering::factory()->for($this->company)->create();
@@ -82,8 +75,6 @@ public function it_auto_populates_invoice_date_fields_on_create_form(): void
#[Group('date-auto-population')]
public function it_auto_populates_task_date_fields_on_create_form(): void
{
- $this->markTestIncomplete();
-
/* arrange */
$project = Project::factory()->for($this->company)->create();
$expectedDate = Carbon::now();
@@ -110,8 +101,6 @@ public function it_auto_populates_task_date_fields_on_create_form(): void
#[Group('date-auto-population')]
public function it_auto_populates_quote_date_fields_on_create_form(): void
{
- $this->markTestIncomplete();
-
/* arrange */
$customer = Relation::factory()->for($this->company)->customer()->create();
$documentGroup = Numbering::factory()->for($this->company)->create();
@@ -139,8 +128,6 @@ public function it_auto_populates_quote_date_fields_on_create_form(): void
#[Group('date-auto-population')]
public function it_auto_populates_payment_date_fields_on_create_form(): void
{
- $this->markTestIncomplete();
-
/* arrange */
$invoice = Invoice::factory()->for($this->company)->create();
$expectedDate = Carbon::now();
@@ -168,8 +155,6 @@ public function it_auto_populates_payment_date_fields_on_create_form(): void
#[Group('edge-cases')]
public function it_handles_timezone_differences_correctly(): void
{
- $this->markTestIncomplete();
-
/* arrange */
$originalTimezone = config('app.timezone');
config(['app.timezone' => 'America/New_York']);
@@ -202,8 +187,6 @@ public function it_handles_timezone_differences_correctly(): void
#[Group('edge-cases')]
public function it_handles_multiple_date_fields_consistently(): void
{
- $this->markTestIncomplete();
-
/* arrange */
$customer = Relation::factory()->for($this->company)->customer()->create();
$documentGroup = Numbering::factory()->for($this->company)->create();
@@ -243,8 +226,6 @@ public function it_handles_multiple_date_fields_consistently(): void
#[Group('edge-cases')]
public function it_handles_date_field_auto_population_during_high_load(): void
{
- $this->markTestIncomplete();
-
/* arrange */
$customer = Relation::factory()->for($this->company)->customer()->create();
$documentGroup = Numbering::factory()->for($this->company)->create();
@@ -278,8 +259,6 @@ public function it_handles_date_field_auto_population_during_high_load(): void
#[Group('edge-cases')]
public function it_maintains_date_precision_across_different_formats(): void
{
- $this->markTestIncomplete();
-
/* arrange */
$customer = Relation::factory()->for($this->company)->customer()->create();
$documentGroup = Numbering::factory()->for($this->company)->create();
@@ -318,8 +297,6 @@ public function it_maintains_date_precision_across_different_formats(): void
#[Group('edge-cases')]
public function it_handles_date_auto_population_with_invalid_session_data(): void
{
- $this->markTestIncomplete();
-
/* arrange */
$customer = Relation::factory()->for($this->company)->customer()->create();
$documentGroup = Numbering::factory()->for($this->company)->create();
@@ -350,8 +327,6 @@ public function it_handles_date_auto_population_with_invalid_session_data(): voi
#[Group('date-auto-population')]
public function it_filters_numberings_by_current_company_id(): void
{
- $this->markTestIncomplete();
-
/* arrange */
$otherCompany = Company::factory()->create();
$currentCompanyDocGroup = Numbering::factory()->for($this->company)->create(['name' => 'Current Company Group']);
diff --git a/Modules/Core/Tests/Unit/Observers/CompanyObserverTest.php b/Modules/Core/Tests/Unit/Observers/CompanyObserverTest.php
index 761f1c0da..de55da845 100644
--- a/Modules/Core/Tests/Unit/Observers/CompanyObserverTest.php
+++ b/Modules/Core/Tests/Unit/Observers/CompanyObserverTest.php
@@ -16,13 +16,15 @@ class CompanyObserverTest extends AbstractTestCase
#[Group('unit')]
public function it_bootstraps_default_data_when_company_is_created(): void
{
- $this->markTestIncomplete('This test has not been implemented yet.');
+ /* Arrange */
+ /* Act */
$company = Company::create([
'search_code' => 'IVPLV2',
'name' => 'InvoicePlane Corporation',
'slug' => 'invoiceplane-corporation',
]);
+ /* Assert */
$this->assertDatabaseHas('email_templates', [
'company_id' => $company->id,
]);
diff --git a/Modules/Invoices/Http/Clients/ApiClient.php b/Modules/Invoices/Http/Clients/ApiClient.php
index 6d8618754..9add2e7ea 100644
--- a/Modules/Invoices/Http/Clients/ApiClient.php
+++ b/Modules/Invoices/Http/Clients/ApiClient.php
@@ -24,10 +24,8 @@ class ApiClient
*
* @return Response
*/
- public function request(RequestMethod|string $method, string $uri, array $options = []): Response
+ public function request(RequestMethod $method, string $uri, array $options = []): Response
{
- $methodString = $method instanceof RequestMethod ? $method->value : mb_strtolower($method);
-
$client = Http::timeout($options['timeout'] ?? 30);
$client = $this->applyAuth($client, $options);
@@ -37,8 +35,8 @@ public function request(RequestMethod|string $method, string $uri, array $option
$client = $client->withHeaders($options['headers']);
}
- return $client
- ->{$methodString}($uri, $options['payload'] ?? [])
+ return $clients
+ ->{$method->value}($uri, $options['payload'] ?? [])
->throw();
}
@@ -55,7 +53,6 @@ private function applyAuth(PendingRequest $client, array $options): PendingReque
$authType = match (true) {
isset($options['bearer']) => 'bearer',
isset($options['auth']) && is_array($options['auth']) && count($options['auth']) >= 2 => 'basic',
- isset($options['digest']) && is_array($options['digest']) && count($options['digest']) >= 2 => 'digest',
default => null
};
diff --git a/Modules/Invoices/Peppol/Enums/PeppolDocumentFormat.php b/Modules/Invoices/Peppol/Enums/PeppolDocumentFormat.php
index d72232727..43386d570 100644
--- a/Modules/Invoices/Peppol/Enums/PeppolDocumentFormat.php
+++ b/Modules/Invoices/Peppol/Enums/PeppolDocumentFormat.php
@@ -125,11 +125,11 @@ public static function formatsForCountry(?string $countryCode): array
return match ($country) {
'ES' => [self::FACTURAE_32, self::UBL_21, self::PEPPOL_BIS_30],
'IT' => [self::FATTURAPA_12, self::UBL_21, self::PEPPOL_BIS_30],
- 'FR' => [self::FACTURX_10, self::CII, self::UBL_21, self::PEPPOL_BIS_30],
+ 'FR' => [self::FACTURX_10, self::FACTURX, self::CII, self::UBL_21, self::PEPPOL_BIS_30],
'DE' => [self::ZUGFERD_20, self::ZUGFERD_10, self::CII, self::UBL_21, self::PEPPOL_BIS_30],
'AT' => [self::CII, self::UBL_21, self::PEPPOL_BIS_30],
'DK' => [self::OIOUBL, self::UBL_21, self::PEPPOL_BIS_30],
- 'NO' => [self::EHF, self::UBL_21, self::PEPPOL_BIS_30],
+ 'NO' => [self::EHF_30, self::EHF, self::UBL_21, self::PEPPOL_BIS_30],
default => [self::PEPPOL_BIS_30, self::UBL_21, self::CII],
};
}
@@ -153,6 +153,8 @@ public function label(): string
self::OIOUBL => 'OIOUBL (Denmark)',
self::EHF => 'EHF (Norway)',
self::PEPPOL_BIS_30 => 'PEPPOL BIS Billing 3.0',
+ self::EHF_30 => 'EHF 3.0 (Norway)',
+ self::FACTURX => 'Factur-X (France/Germany)',
};
}
@@ -175,6 +177,8 @@ public function description(): string
self::OIOUBL => 'Danish UBL-based format with national extensions.',
self::EHF => 'Norwegian UBL-based format used in public procurement.',
self::PEPPOL_BIS_30 => 'Pan-European Public Procurement Online standard.',
+ self::EHF_30 => 'Norwegian EHF 3.0 format for Peppol network.',
+ self::FACTURX => 'Hybrid PDF/A-3 format with embedded XML. Used in France and Germany.',
};
}
diff --git a/Modules/Invoices/Peppol/FormatHandlers/BaseFormatHandler.php b/Modules/Invoices/Peppol/FormatHandlers/BaseFormatHandler.php
index d409a6680..586d11750 100644
--- a/Modules/Invoices/Peppol/FormatHandlers/BaseFormatHandler.php
+++ b/Modules/Invoices/Peppol/FormatHandlers/BaseFormatHandler.php
@@ -54,7 +54,7 @@ public function getFormat(): PeppolDocumentFormat
public function supports(Invoice $invoice): bool
{
// Check if customer's country matches format requirements
- $customerCountry = $invoice->customer->country_code ?? null;
+ $customerCountry = $invoice->customer?->country_code ?? null;
// Mandatory formats must be used for their countries
if ($this->format->isMandatoryFor($customerCountry)) {
@@ -144,7 +144,7 @@ protected function getCurrencyCode(Invoice $invoice, ...$args): string
*/
protected function getEndpointScheme(Invoice $invoice): PeppolEndpointScheme
{
- $countryCode = $invoice->customer->country_code ?? null;
+ $countryCode = $invoice->customer?->country_code ?? null;
return PeppolEndpointScheme::forCountry($countryCode);
}
diff --git a/Modules/Invoices/Peppol/FormatHandlers/EhfHandler.php b/Modules/Invoices/Peppol/FormatHandlers/EhfHandler.php
index 8a2532ab1..3325da31e 100644
--- a/Modules/Invoices/Peppol/FormatHandlers/EhfHandler.php
+++ b/Modules/Invoices/Peppol/FormatHandlers/EhfHandler.php
@@ -177,38 +177,38 @@ protected function buildCustomerParty(Invoice $invoice, $endpointScheme): array
return [
'party' => [
'endpoint_id' => [
- 'value' => $customer->peppol_id ?? '',
+ 'value' => $customer?->peppol_id ?? '',
'scheme_id' => $endpointScheme->value,
],
'party_identification' => [
'id' => [
- 'value' => $customer->organization_number ?? $customer->peppol_id ?? '',
+ 'value' => $customer?->organization_number ?? $customer?->peppol_id ?? '',
'scheme_id' => 'NO:ORGNR',
],
],
'party_name' => [
- 'name' => $customer->company_name ?? $customer->customer_name,
+ 'name' => $customer?->company_name ?? $customer?->customer_name,
],
'postal_address' => [
- 'street_name' => $customer->street1 ?? '',
- 'additional_street_name' => $customer->street2 ?? '',
- 'city_name' => $customer->city ?? '',
- 'postal_zone' => $customer->zip ?? '',
+ 'street_name' => $customer?->street1 ?? '',
+ 'additional_street_name' => $customer?->street2 ?? '',
+ 'city_name' => $customer?->city ?? '',
+ 'postal_zone' => $customer?->zip ?? '',
'country' => [
- 'identification_code' => $customer->country_code ?? 'NO',
+ 'identification_code' => $customer?->country_code ?? 'NO',
],
],
'party_legal_entity' => [
- 'registration_name' => $customer->company_name ?? $customer->customer_name,
+ 'registration_name' => $customer?->company_name ?? $customer?->customer_name,
'company_id' => [
- 'value' => $customer->organization_number ?? $customer->peppol_id ?? '',
+ 'value' => $customer?->organization_number ?? $customer?->peppol_id ?? '',
'scheme_id' => 'NO:ORGNR',
],
],
'contact' => [
- 'name' => $customer->contact_name ?? '',
- 'telephone' => $customer->contact_phone ?? '',
- 'electronic_mail' => $customer->contact_email ?? '',
+ 'name' => $customer?->contact_name ?? '',
+ 'telephone' => $customer?->contact_phone ?? '',
+ 'electronic_mail' => $customer?->contact_email ?? '',
],
],
];
@@ -229,11 +229,11 @@ protected function buildDelivery(Invoice $invoice): array
'actual_delivery_date' => $invoice->invoiced_at->format('Y-m-d'),
'delivery_location' => [
'address' => [
- 'street_name' => $invoice->customer->street1 ?? '',
- 'city_name' => $invoice->customer->city ?? '',
- 'postal_zone' => $invoice->customer->zip ?? '',
+ 'street_name' => $invoice->customer?->street1 ?? '',
+ 'city_name' => $invoice->customer?->city ?? '',
+ 'postal_zone' => $invoice->customer?->zip ?? '',
'country' => [
- 'identification_code' => $invoice->customer->country_code ?? 'NO',
+ 'identification_code' => $invoice->customer?->country_code ?? 'NO',
],
],
],
@@ -460,7 +460,7 @@ protected function validateFormatSpecific(Invoice $invoice): array
}
// Customer must have organization number or Peppol ID
- if ( ! $invoice->customer->organization_number && ! $invoice->customer->peppol_id) {
+ if ( ! $invoice->customer?->organization_number && ! $invoice->customer?->peppol_id) {
$errors[] = 'Customer organization number or Peppol ID is required for EHF format';
}
@@ -477,7 +477,7 @@ protected function validateFormatSpecific(Invoice $invoice): array
protected function getBuyerReference(Invoice $invoice): string
{
// EHF requires buyer reference for routing
- return $invoice->customer->reference ?? $invoice->reference ?? '';
+ return $invoice->customer?->reference ?? $invoice->reference ?? '';
}
/**
diff --git a/Modules/Invoices/Peppol/FormatHandlers/FatturaPaHandler.php b/Modules/Invoices/Peppol/FormatHandlers/FatturaPaHandler.php
index 1b6dff695..317f12cfd 100644
--- a/Modules/Invoices/Peppol/FormatHandlers/FatturaPaHandler.php
+++ b/Modules/Invoices/Peppol/FormatHandlers/FatturaPaHandler.php
@@ -94,7 +94,7 @@ protected function buildTransmissionData(Invoice $invoice): array
],
'ProgressivoInvio' => $invoice->invoice_number,
'FormatoTrasmissione' => 'FPR12', // FatturaPA 1.2 format
- 'CodiceDestinatario' => $invoice->customer->peppol_id ?? '0000000',
+ 'CodiceDestinatario' => $invoice->customer?->peppol_id ?? '0000000',
];
}
@@ -158,16 +158,16 @@ protected function buildCustomerData(Invoice $invoice): array
return [
'DatiAnagrafici' => [
- 'CodiceFiscale' => $customer->tax_code ?? '',
+ 'CodiceFiscale' => $customer?->tax_code ?? '',
'Anagrafica' => [
- 'Denominazione' => $customer->company_name ?? $customer->customer_name,
+ 'Denominazione' => $customer?->company_name ?? $customer?->customer_name,
],
],
'Sede' => [
- 'Indirizzo' => $customer->street1 ?? '',
- 'CAP' => $customer->zip ?? '',
- 'Comune' => $customer->city ?? '',
- 'Nazione' => $customer->country_code ?? 'IT',
+ 'Indirizzo' => $customer?->street1 ?? '',
+ 'CAP' => $customer?->zip ?? '',
+ 'Comune' => $customer?->city ?? '',
+ 'Nazione' => $customer?->country_code ?? 'IT',
],
];
}
@@ -337,7 +337,7 @@ protected function validateFormatSpecific(Invoice $invoice): array
}
// Customer must be in Italy or have Italian tax code for mandatory usage
- if ($invoice->customer->country_code === 'IT' && ! $invoice->customer->tax_code) {
+ if ($invoice->customer?->country_code === 'IT' && ! $invoice->customer?->tax_code) {
$errors[] = 'Customer tax code (Codice Fiscale) is required for Italian customers in FatturaPA format';
}
diff --git a/Modules/Invoices/Peppol/FormatHandlers/OioublHandler.php b/Modules/Invoices/Peppol/FormatHandlers/OioublHandler.php
index 9acf752bc..d14ce6fa7 100644
--- a/Modules/Invoices/Peppol/FormatHandlers/OioublHandler.php
+++ b/Modules/Invoices/Peppol/FormatHandlers/OioublHandler.php
@@ -168,34 +168,34 @@ protected function buildCustomerParty(Invoice $invoice, $endpointScheme): array
return [
'party' => [
'endpoint_id' => [
- 'value' => $customer->peppol_id ?? '',
+ 'value' => $customer?->peppol_id ?? '',
'scheme_id' => $endpointScheme->value,
],
'party_identification' => [
'id' => [
- 'value' => $customer->peppol_id ?? '',
+ 'value' => $customer?->peppol_id ?? '',
'scheme_id' => 'DK:CVR',
],
],
'party_name' => [
- 'name' => $customer->company_name ?? $customer->customer_name,
+ 'name' => $customer?->company_name ?? $customer?->customer_name,
],
'postal_address' => [
- 'street_name' => $customer->street1 ?? '',
- 'additional_street_name' => $customer->street2 ?? '',
- 'city_name' => $customer->city ?? '',
- 'postal_zone' => $customer->zip ?? '',
+ 'street_name' => $customer?->street1 ?? '',
+ 'additional_street_name' => $customer?->street2 ?? '',
+ 'city_name' => $customer?->city ?? '',
+ 'postal_zone' => $customer?->zip ?? '',
'country' => [
- 'identification_code' => $customer->country_code ?? 'DK',
+ 'identification_code' => $customer?->country_code ?? 'DK',
],
],
'party_legal_entity' => [
- 'registration_name' => $customer->company_name ?? $customer->customer_name,
+ 'registration_name' => $customer?->company_name ?? $customer?->customer_name,
],
'contact' => [
- 'name' => $customer->contact_name ?? '',
- 'telephone' => $customer->contact_phone ?? '',
- 'electronic_mail' => $customer->contact_email ?? '',
+ 'name' => $customer?->contact_name ?? '',
+ 'telephone' => $customer?->contact_phone ?? '',
+ 'electronic_mail' => $customer?->contact_email ?? '',
],
],
];
@@ -426,7 +426,7 @@ protected function validateFormatSpecific(Invoice $invoice): array
}
// Customer must have Peppol ID for OIOUBL
- if ( ! $invoice->customer->peppol_id) {
+ if ( ! $invoice->customer?->peppol_id) {
$errors[] = 'Customer Peppol ID (CVR) is required for OIOUBL format';
}
diff --git a/Modules/Invoices/Peppol/FormatHandlers/PeppolBisHandler.php b/Modules/Invoices/Peppol/FormatHandlers/PeppolBisHandler.php
index 0d1ae5613..191a41e20 100644
--- a/Modules/Invoices/Peppol/FormatHandlers/PeppolBisHandler.php
+++ b/Modules/Invoices/Peppol/FormatHandlers/PeppolBisHandler.php
@@ -80,18 +80,18 @@ public function transform(Invoice $invoice, array $options = []): array
'accounting_customer_party' => [
'party' => [
'endpoint_id' => [
- 'value' => $customer->peppol_id,
+ 'value' => $customer?->peppol_id,
'scheme_id' => $endpointScheme->value,
],
'party_name' => [
- 'name' => $customer->company_name ?? $customer->customer_name,
+ 'name' => $customer?->company_name ?? $customer?->customer_name,
],
'postal_address' => [
- 'street_name' => $customer->street1,
- 'city_name' => $customer->city,
- 'postal_zone' => $customer->zip,
+ 'street_name' => $customer?->street1,
+ 'city_name' => $customer?->city,
+ 'postal_zone' => $customer?->zip,
'country' => [
- 'identification_code' => $customer->country_code,
+ 'identification_code' => $customer?->country_code,
],
],
],
@@ -164,7 +164,7 @@ protected function validateFormatSpecific(Invoice $invoice): array
$errors = [];
// PEPPOL BIS specific validation
- if ( ! $invoice->customer->peppol_id) {
+ if ( ! $invoice->customer?->peppol_id) {
$errors[] = 'Customer must have a Peppol ID for PEPPOL BIS format';
}
diff --git a/Modules/Invoices/Peppol/FormatHandlers/UblHandler.php b/Modules/Invoices/Peppol/FormatHandlers/UblHandler.php
index e76dcd204..04d909876 100644
--- a/Modules/Invoices/Peppol/FormatHandlers/UblHandler.php
+++ b/Modules/Invoices/Peppol/FormatHandlers/UblHandler.php
@@ -78,7 +78,7 @@ protected function validateFormatSpecific(Invoice $invoice): array
$errors = [];
// UBL requires certain fields
- if ( ! $invoice->customer->peppol_id && config('invoices.peppol.validation.require_customer_peppol_id')) {
+ if ( ! $invoice->customer?->peppol_id && config('invoices.peppol.validation.require_customer_peppol_id')) {
$errors[] = 'Customer Peppol ID is required for UBL format';
}
diff --git a/Modules/ReportBuilder/DTOs/GridPositionDTO.php b/Modules/ReportBuilder/DTOs/GridPositionDTO.php
index 624ea9355..965c0aa89 100644
--- a/Modules/ReportBuilder/DTOs/GridPositionDTO.php
+++ b/Modules/ReportBuilder/DTOs/GridPositionDTO.php
@@ -33,7 +33,33 @@ class GridPositionDTO
//region Constructor
- public function __construct(int $x, int $y, int $width, int $height)
+ /**
+ * GridPositionDTO constructor.
+ *
+ * No-arg constructor following DTO guidelines.
+ * Use setters or static factory methods to populate the DTO.
+ */
+ public function __construct()
+ {
+ $this->x = 0;
+ $this->y = 0;
+ $this->width = 0;
+ $this->height = 0;
+ }
+
+ /**
+ * Static factory method to create a GridPositionDTO with all values.
+ *
+ * @param int $x X coordinate
+ * @param int $y Y coordinate
+ * @param int $width Width
+ * @param int $height Height
+ *
+ * @return self
+ *
+ * @throws InvalidArgumentException
+ */
+ public static function create(int $x, int $y, int $width, int $height): self
{
if ($x < 0 || $y < 0) {
throw new InvalidArgumentException('x and y must be >= 0');
@@ -41,10 +67,14 @@ public function __construct(int $x, int $y, int $width, int $height)
if ($width <= 0 || $height <= 0) {
throw new InvalidArgumentException('width and height must be > 0');
}
- $this->x = $x;
- $this->y = $y;
- $this->width = $width;
- $this->height = $height;
+
+ $dto = new self();
+ $dto->x = $x;
+ $dto->y = $y;
+ $dto->width = $width;
+ $dto->height = $height;
+
+ return $dto;
}
//endregion
diff --git a/Modules/ReportBuilder/Services/GridSnapperService.php b/Modules/ReportBuilder/Services/GridSnapperService.php
index caf4f3855..fce2a63dd 100644
--- a/Modules/ReportBuilder/Services/GridSnapperService.php
+++ b/Modules/ReportBuilder/Services/GridSnapperService.php
@@ -29,7 +29,7 @@ public function snap(GridPositionDTO $position): GridPositionDTO
$width = max(1, min($position->getWidth(), $this->gridSize - $position->getX()));
$height = max(1, $position->getHeight());
- return new GridPositionDTO($x, $y, $width, $height);
+ return GridPositionDTO::create($x, $y, $width, $height);
}
/**
diff --git a/Modules/ReportBuilder/Services/ReportTemplateService.php b/Modules/ReportBuilder/Services/ReportTemplateService.php
index 8a0581f00..cf158842c 100644
--- a/Modules/ReportBuilder/Services/ReportTemplateService.php
+++ b/Modules/ReportBuilder/Services/ReportTemplateService.php
@@ -252,7 +252,7 @@ public function validateBlocks(array $blocks): void
throw new InvalidArgumentException("Block at index {$index} must have a 'config' array");
}
- $positionDTO = new GridPositionDTO(
+ $positionDTO = GridPositionDTO::create(
$position['x'],
$position['y'],
$position['width'],
@@ -387,7 +387,7 @@ private function createSystemBlock(
string $label,
string $dataSource
): BlockDTO {
- $position = new GridPositionDTO($x, $y, $width, $height);
+ $position = GridPositionDTO::create($x, $y, $width, $height);
$block = new BlockDTO();
$block->setId($id)
diff --git a/Modules/ReportBuilder/Tests/Unit/BlockDTOTest.php b/Modules/ReportBuilder/Tests/Unit/BlockDTOTest.php
index 7b2c19a0b..ffc92fa59 100644
--- a/Modules/ReportBuilder/Tests/Unit/BlockDTOTest.php
+++ b/Modules/ReportBuilder/Tests/Unit/BlockDTOTest.php
@@ -44,10 +44,9 @@ public function it_can_set_and_get_position(): void
{
/* arrange */
$position = new GridPositionDTO();
-
- /* act */
$position->setX(0)->setY(0)->setWidth(6)->setHeight(4);
+ /* act */
$dto = new BlockDTO();
$dto->setPosition($position);
@@ -64,7 +63,11 @@ public function it_can_set_and_get_position(): void
public function it_can_set_and_get_config(): void
{
/* arrange */
- // No setup needed
+ $config = ['show_vat_id' => true];
+
+ /* act */
+ $dto = new BlockDTO();
+ $dto->setConfig($config);
/* assert */
$this->assertEquals($config, $dto->getConfig());
@@ -75,7 +78,10 @@ public function it_can_set_and_get_config(): void
public function it_can_set_and_get_label(): void
{
/* arrange */
- // No setup needed
+ $dto = new BlockDTO();
+
+ /* act */
+ $dto->setLabel('Company Header');
/* assert */
$this->assertEquals('Company Header', $dto->getLabel());
@@ -86,7 +92,10 @@ public function it_can_set_and_get_label(): void
public function it_can_set_label_to_null(): void
{
/* arrange */
- // No setup needed
+ $dto = new BlockDTO();
+
+ /* act */
+ $dto->setLabel(null);
/* assert */
$this->assertNull($dto->getLabel());
@@ -97,7 +106,10 @@ public function it_can_set_label_to_null(): void
public function it_can_set_and_get_is_cloneable(): void
{
/* arrange */
- // No setup needed
+ $dto = new BlockDTO();
+
+ /* act */
+ $dto->setIsCloneable(true);
/* assert */
$this->assertTrue($dto->getIsCloneable());
@@ -110,7 +122,10 @@ public function it_can_set_and_get_is_cloneable(): void
public function it_can_set_and_get_data_source(): void
{
/* arrange */
- // No setup needed
+ $dto = new BlockDTO();
+
+ /* act */
+ $dto->setDataSource('company');
/* assert */
$this->assertEquals('company', $dto->getDataSource());
@@ -121,7 +136,10 @@ public function it_can_set_and_get_data_source(): void
public function it_can_set_data_source_to_null(): void
{
/* arrange */
- // No setup needed
+ $dto = new BlockDTO();
+
+ /* act */
+ $dto->setDataSource(null);
/* assert */
$this->assertNull($dto->getDataSource());
@@ -132,7 +150,10 @@ public function it_can_set_data_source_to_null(): void
public function it_can_set_and_get_is_cloned(): void
{
/* arrange */
- // No setup needed
+ $dto = new BlockDTO();
+
+ /* act */
+ $dto->setIsCloned(true);
/* assert */
$this->assertTrue($dto->getIsCloned());
@@ -145,7 +166,10 @@ public function it_can_set_and_get_is_cloned(): void
public function it_can_set_and_get_cloned_from(): void
{
/* arrange */
- // No setup needed
+ $dto = new BlockDTO();
+
+ /* act */
+ $dto->setClonedFrom('block_original');
/* assert */
$this->assertEquals('block_original', $dto->getClonedFrom());
@@ -156,7 +180,10 @@ public function it_can_set_and_get_cloned_from(): void
public function it_can_set_cloned_from_to_null(): void
{
/* arrange */
- // No setup needed
+ $dto = new BlockDTO();
+
+ /* act */
+ $dto->setClonedFrom(null);
/* assert */
$this->assertNull($dto->getClonedFrom());
@@ -168,12 +195,10 @@ public function it_can_create_system_block(): void
{
/* arrange */
$position = new GridPositionDTO();
-
- /* act */
$position->setX(0)->setY(0)->setWidth(6)->setHeight(4);
-
$config = ['show_vat_id' => true];
+ /* act */
$dto = BlockDTO::system('header_company', $position, $config);
/* assert */
@@ -191,10 +216,9 @@ public function it_can_create_cloned_block(): void
{
/* arrange */
$position = new GridPositionDTO();
-
- /* act */
$position->setX(0)->setY(0)->setWidth(6)->setHeight(4);
+ /* act */
$original = new BlockDTO();
$original->setId('block_original')
->setType('header_company')
diff --git a/Modules/ReportBuilder/Transformers/BlockTransformer.php b/Modules/ReportBuilder/Transformers/BlockTransformer.php
index 989a683c0..3d8726b50 100644
--- a/Modules/ReportBuilder/Transformers/BlockTransformer.php
+++ b/Modules/ReportBuilder/Transformers/BlockTransformer.php
@@ -45,7 +45,7 @@ class BlockTransformer
public static function toDTO(array $blockData): BlockDTO
{
$positionData = $blockData['position'] ?? [];
- $position = new GridPositionDTO(
+ $position = GridPositionDTO::create(
$positionData['x'] ?? 0,
$positionData['y'] ?? 0,
$positionData['width'] ?? 1,
diff --git a/phpunit.xml b/phpunit.xml
index 041fb3f13..c52013c61 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -26,13 +26,8 @@
-
-
-
-
-
-
-
+
+