Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@

return new class extends Migration
{
/**
* Add Peppol validation columns to the relations table.
*
* Adds nullable columns: `peppol_scheme` (string(50)) for Peppol endpoint scheme,
* `peppol_validation_status` (string(20)) for quick lookup of validation state,
* `peppol_validation_message` (text) for the last validation message, and
* `peppol_validated_at` (timestamp) for when the Peppol ID was last validated.
*/
public function up(): void
{
Schema::table('relations', function (Blueprint $table): void {
Expand All @@ -23,10 +31,15 @@ public function up(): void
});
}

/**
* Removes Peppol-related columns from the `relations` table.
*
* Drops the columns: `peppol_scheme`, `peppol_validation_status`, `peppol_validation_message`, and `peppol_validated_at`.
*/
public function down(): void
{
Schema::table('relations', function (Blueprint $table): void {
$table->dropColumn(['peppol_scheme', 'peppol_validation_status', 'peppol_validation_message', 'peppol_validated_at']);
});
}
};
};
16 changes: 14 additions & 2 deletions Modules/Clients/Models/Relation.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,21 @@ public function tasks(): HasMany
return $this->hasMany(Task::class, 'customer_id');
}

/**
* Define a one-to-many relationship to User models.
*
* @return HasMany The has-many relationship for User models.
*/
public function users(): HasMany
{
return $this->hasMany(User::class);
}

/**
* Get the Peppol validation history records for this relation.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany Collection of CustomerPeppolValidationHistory models related by `customer_id`.
*/
public function peppolValidationHistory(): HasMany
{
return $this->hasMany(CustomerPeppolValidationHistory::class, 'customer_id');
Expand All @@ -195,7 +205,9 @@ public function getCustomerEmailAttribute()
}*/

/**
* Check if customer has valid Peppol ID
* Determines whether the relation's Peppol ID has been validated and e-invoicing is enabled.
*
* @return bool `true` if e-invoicing is enabled, the Peppol validation status is `PeppolValidationStatus::VALID`, and `peppol_id` is not null; `false` otherwise.
*/
public function hasPeppolIdValidated(): bool
{
Expand Down Expand Up @@ -225,4 +237,4 @@ protected static function newFactory(): Factory
| Subqueries
|--------------------------------------------------------------------------
*/
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ class PollPeppolStatusCommand extends Command
protected $signature = 'peppol:poll-status';
protected $description = 'Poll Peppol provider for transmission status updates';

/**
* Triggers a background job to poll Peppol transmission statuses and reports the result.
*
* @return int Exit code: `self::SUCCESS` if the polling job was dispatched successfully, `self::FAILURE` if dispatch failed.
*/
public function handle(): int
{
$this->info('Starting Peppol status polling...');
Expand All @@ -32,4 +37,4 @@ public function handle(): int
return self::FAILURE;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ class RetryFailedPeppolTransmissionsCommand extends Command
protected $signature = 'peppol:retry-failed';
protected $description = 'Retry failed Peppol transmissions that are ready for retry';

/**
* Dispatches a job to retry failed Peppol transmissions and reports the outcome.
*
* Dispatches the RetryFailedTransmissions job; on success it emits informational output and returns a success exit code, on failure it emits an error message and returns a failure exit code.
*
* @return int self::SUCCESS if the job was dispatched successfully, self::FAILURE if an exception occurred while dispatching.
*/
public function handle(): int
{
$this->info('Starting retry of failed Peppol transmissions...');
Expand All @@ -32,4 +39,4 @@ public function handle(): int
return self::FAILURE;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@ class TestPeppolIntegrationCommand extends Command
protected $signature = 'peppol:test-integration {integration_id}';
protected $description = 'Test connection to a Peppol integration';

/**
* Execute the console command to test a Peppol integration's connection.
*
* Loads the PeppolIntegration identified by the `integration_id` command argument; if not found,
* outputs an error and returns failure. If found, invokes the PeppolManagementService to test
* the integration's connection, outputs the service message, and returns success on a successful
* test or failure otherwise.
*
* @param PeppolManagementService $service Service used to perform the connection test.
* @return int `self::SUCCESS` on a successful connection test, `self::FAILURE` otherwise.
*/
public function handle(PeppolManagementService $service): int
{
$integrationId = $this->argument('integration_id');
Expand All @@ -39,4 +50,4 @@ public function handle(PeppolManagementService $service): int
return self::FAILURE;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@

return new class extends Migration
{
/**
* Create the peppol_integrations table to store PEPPOL integration settings and connection test metadata.
*
* The table includes company association (foreign key to companies.id with cascade delete), provider identifier,
* encrypted API token, last test connection status/message/timestamp, an enabled flag, and indexes for
* (company_id, enabled) and provider_name.
*/
public function up(): void
{
Schema::create('peppol_integrations', function (Blueprint $table): void {
Expand All @@ -24,8 +31,11 @@ public function up(): void
});
}

/**
* Drop the `peppol_integrations` table if it exists.
*/
public function down(): void
{
Schema::dropIfExists('peppol_integrations');
}
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@

return new class extends Migration
{
/**
* Create the peppol_integration_config table and its schema.
*
* The table includes an auto-incrementing primary key `id`, `integration_id` (unsigned big integer),
* `config_key` (string up to 100 characters), and `config_value` (text). Adds a foreign key on
* `integration_id` referencing `peppol_integrations.id` with cascade on delete, and a composite index
* on (`integration_id`, `config_key`).
*/
public function up(): void
{
Schema::create('peppol_integration_config', function (Blueprint $table): void {
Expand All @@ -19,8 +27,13 @@ public function up(): void
});
}

/**
* Drop the `peppol_integration_config` table if it exists.
*
* Removes the database table created for storing Peppol integration configuration entries.
*/
public function down(): void
{
Schema::dropIfExists('peppol_integration_config');
}
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@

return new class extends Migration
{
/**
* Create the `peppol_transmissions` table with its columns, indexes, and foreign key constraints.
*
* The table stores transmission records for Peppol/UBL documents, including references to
* invoices, customers, and integrations; format and status metadata; retry and error tracking;
* idempotency and external provider identifiers; paths to stored files; and relevant timestamps.
*/
public function up(): void
{
Schema::create('peppol_transmissions', function (Blueprint $table): void {
Expand Down Expand Up @@ -39,8 +46,11 @@ public function up(): void
});
}

/**
* Reverses the migration by dropping the `peppol_transmissions` table if it exists.
*/
public function down(): void
{
Schema::dropIfExists('peppol_transmissions');
}
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@

return new class extends Migration
{
/**
* Create the peppol_transmission_responses database table.
*
* The table contains an auto-incrementing primary key `id`, an unsigned big integer
* `transmission_id` referencing `peppol_transmissions.id` with cascade on delete,
* a `response_key` string (maximum 100 characters), and a `response_value` text column.
* Also adds a composite index on (`transmission_id`, `response_key`).
*/
public function up(): void
{
Schema::create('peppol_transmission_responses', function (Blueprint $table): void {
Expand All @@ -19,8 +27,11 @@ public function up(): void
});
}

/**
* Reverts the migration by dropping the `peppol_transmission_responses` table if it exists.
*/
public function down(): void
{
Schema::dropIfExists('peppol_transmission_responses');
}
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@

return new class extends Migration
{
/**
* Create the customer_peppol_validation_history table to record Peppol identifier validation events for customers.
*
* The table stores customer, integration and user references, the Peppol scheme and identifier, validation status and message, timestamps, foreign key constraints, and indexes for efficient lookups.
*/
public function up(): void
{
Schema::create('customer_peppol_validation_history', function (Blueprint $table): void {
Expand All @@ -29,8 +34,13 @@ public function up(): void
});
}

/**
* Reverts the migration by removing the customer_peppol_validation_history table.
*
* Drops the table if it exists.
*/
public function down(): void
{
Schema::dropIfExists('customer_peppol_validation_history');
}
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@

return new class extends Migration
{
/**
* Create the customer_peppol_validation_responses table.
*
* The table contains an auto-incrementing primary key `id`, `validation_history_id` (unsigned big integer)
* referencing `customer_peppol_validation_history.id` with cascade on delete (constraint name `fk_peppol_validation_responses`),
* `response_key` (string, max 100), and `response_value` (text). An index on `validation_history_id` and `response_key`
* is created named `idx_validation_responses`.
*/
public function up(): void
{
Schema::create('customer_peppol_validation_responses', function (Blueprint $table): void {
Expand All @@ -20,8 +28,13 @@ public function up(): void
});
}

/**
* Remove the customer_peppol_validation_responses table from the database.
*
* Drops the table if it exists.
*/
public function down(): void
{
Schema::dropIfExists('customer_peppol_validation_responses');
}
};
};
17 changes: 16 additions & 1 deletion Modules/Invoices/Enums/PeppolConnectionStatus.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ enum PeppolConnectionStatus: string implements LabeledEnum
case SUCCESS = 'success';
case FAILED = 'failed';

/**
* Returns a human-readable label for the connection status.
*
* @return string The label for the enum case: 'Untested', 'Success', or 'Failed'.
*/
public function label(): string
{
return match ($this) {
Expand All @@ -22,6 +27,11 @@ public function label(): string
};
}

/**
* The display color name for the Peppol connection status.
*
* @return string The color name for the status: 'gray' for UNTESTED, 'green' for SUCCESS, 'red' for FAILED.
*/
public function color(): string
{
return match ($this) {
Expand All @@ -31,6 +41,11 @@ public function color(): string
};
}

/**
* Get the icon identifier associated with the current status.
*
* @return string The icon identifier corresponding to the enum case.
*/
public function icon(): string
{
return match ($this) {
Expand All @@ -39,4 +54,4 @@ public function icon(): string
self::FAILED => 'heroicon-o-x-circle',
};
}
}
}
17 changes: 16 additions & 1 deletion Modules/Invoices/Enums/PeppolErrorType.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ enum PeppolErrorType: string implements LabeledEnum
case PERMANENT = 'PERMANENT';
case UNKNOWN = 'UNKNOWN';

/**
* Get a human-readable label for the error type.
*
* @return string Human-readable label for the enum case.
*/
public function label(): string
{
return match ($this) {
Expand All @@ -22,6 +27,11 @@ public function label(): string
};
}

/**
* Gets the UI color identifier associated with this Peppol error type.
*
* @return string The color identifier: 'yellow' for TRANSIENT, 'red' for PERMANENT, 'gray' for UNKNOWN.
*/
public function color(): string
{
return match ($this) {
Expand All @@ -31,6 +41,11 @@ public function color(): string
};
}

/**
* Get the icon identifier corresponding to this error type.
*
* @return string The icon identifier for the enum case.
*/
public function icon(): string
{
return match ($this) {
Expand All @@ -39,4 +54,4 @@ public function icon(): string
self::UNKNOWN => 'heroicon-o-question-mark-circle',
};
}
}
}
Loading