Skip to content
Closed
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
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,45 @@ if ($aeatResponse->status === ResponseStatus::Correct) {
}
```

## Remisión Voluntaria (Voluntary Discontinuation)

La librería también soporta la funcionalidad de **Remisión Voluntaria** que permite notificar a la AEAT cuando una empresa decide dejar de usar VERI*FACTU.

### Ejemplo de uso de Remisión Voluntaria

```php
<?php
use josemmo\Verifactu\Models\Records\VoluntaryDiscontinuation;
use josemmo\Verifactu\Services\AeatClient;

// Configura el cliente con la remisión voluntaria
$client = new AeatClient($system, $taxpayer, null);
$client->setCertificate(__DIR__ . '/certificado.pfx', 'contraseña');
$client->setProduction(false);

// Crea una remisión voluntaria
$client->setVoluntaryDiscontinuation(
new VoluntaryDiscontinuation(
new DateTimeImmutable('2025-12-31') // Debe ser a finales del año contable
)
);

// Envía la remisión (no se requieren registros de facturación)
$res = $client->send([])->wait();
echo $res->asXML() . "\n";
```

### Parámetros de Remisión Voluntaria

- **`endDate`**: Fecha en la que la empresa dejará de usar VERI*FACTU. **Debe ser a finales del año contable actual** según indica la AEAT.
- **`incident`**: Indica si la razón de la remisión es una incidencia (`true`) o es voluntaria (`false`).

### Notas importantes

- La remisión voluntaria debe enviarse **antes** de la fecha de fin especificada
- Una vez llega la fecha de remisión, el SIF no debería de volver a enviar facturas a VERI*FACTU a no ser que el cliente vuelva a activarlo de forma voluntaria.
- La fecha de fin debe ser a finales del año contable actual (31 de diciembre)

## Exención de responsabilidad
Esta librería se proporciona sin una declaración responsable al no ser un Sistema Informático de Facturación (SIF).
Verifactu-PHP es una herramienta para crear SIFs, es tu responsabilidad auditar su código y usarlo de acuerdo a la normativa vigente.
Expand Down
47 changes: 47 additions & 0 deletions src/Models/Records/VoluntaryDiscontinuation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?php
namespace josemmo\Verifactu\Models\Records;

use DateTimeImmutable;
use josemmo\Verifactu\Models\Model;
use Symfony\Component\Validator\Constraints as Assert;

/**
* Remisión Voluntaria VERI*FACTU
*
* @field Caberecera/RemisionVoluntaria/FechaFinVeriFactu
* @field Caberecera/RemisionVoluntaria/Incidencia
*/
class VoluntaryDiscontinuation extends Model {
/**
* Class constructor
*
* @param DateTimeImmutable|null $endDate When the company will stop using VERI*FACTU. As the AEAT says, this date should be at the end of the year.
* @param bool|null $incident Whether the reason of the voluntary discontinuation is an incident or not (Default: false)
*/
public function __construct(
?DateTimeImmutable $endDate = null,
?bool $incident = false,
) {
if ($endDate !== null) {
$this->endDate = $endDate;
}
if ($incident !== null) {
$this->incident = $incident;
}
}

/**
* Fecha fin de VERI*FACTU. Debe ser a finales del año contable actual.
*
* @field Caberecera/RemisionVoluntaria/FechaFinVeriFactu
*/
public ?DateTimeImmutable $endDate = null;

/**
* Incidencia
*
* @field Caberecera/RemisionVoluntaria/Incidencia
*/
#[Assert\Type('boolean')]
public bool $incident = false;
}
21 changes: 20 additions & 1 deletion src/Services/AeatClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use josemmo\Verifactu\Models\Records\FiscalIdentifier;
use josemmo\Verifactu\Models\Records\Record;
use josemmo\Verifactu\Models\Records\RegistrationRecord;
use josemmo\Verifactu\Models\Records\VoluntaryDiscontinuation;
use josemmo\Verifactu\Models\Responses\AeatResponse;
use Psr\Http\Client\ClientExceptionInterface;
use Psr\Http\Message\ResponseInterface;
Expand All @@ -31,6 +32,7 @@ class AeatClient {
private ?string $certificatePath = null;
private ?string $certificatePassword = null;
private ?FiscalIdentifier $representative = null;
private ?VoluntaryDiscontinuation $voluntaryDiscontinuation = null;
private bool $isProduction = true;
private bool $isEntitySeal = false;

Expand All @@ -44,7 +46,7 @@ class AeatClient {
public function __construct(
ComputerSystem $system,
FiscalIdentifier $taxpayer,
?Client $httpClient = null,
?Client $httpClient = null
) {
$this->system = $system;
$this->taxpayer = $taxpayer;
Expand Down Expand Up @@ -96,6 +98,18 @@ public function setProduction(bool $production): static {
return $this;
}

/**
* Set voluntary discontinuation
*
* @param VoluntaryDiscontinuation|null $voluntaryDiscontinuation Sends the date of which the company will stop using VERI*FACTU.
*
* @return $this This instance
*/
public function setVoluntaryDiscontinuation(?VoluntaryDiscontinuation $voluntaryDiscontinuation): static {
$this->voluntaryDiscontinuation = $voluntaryDiscontinuation;
return $this;
}

/**
* Set entity seal
*
Expand Down Expand Up @@ -138,6 +152,11 @@ public function send(array $records): PromiseInterface { /** @phpstan-ignore gen
$representanteElement->add('sum1:NombreRazon', $this->representative->name);
$representanteElement->add('sum1:NIF', $this->representative->nif);
}
if ($this->voluntaryDiscontinuation !== null && $this->voluntaryDiscontinuation->endDate !== null) {
$remisionVoluntariaElement = $cabeceraElement->add('sum1:RemisionVoluntaria');
$remisionVoluntariaElement->add('sum1:FechaFinVeriFactu', $this->voluntaryDiscontinuation->endDate->format('d-m-Y'));
$remisionVoluntariaElement->add('sum1:Incidencia', $this->voluntaryDiscontinuation->incident ? 'S' : 'N');
}

// Add registration records
foreach ($records as $record) {
Expand Down