mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-08 20:22:42 +01:00
Updates for transforming PEPPOL => storecove
This commit is contained in:
parent
f44180ee24
commit
75078de048
@ -1,67 +1,57 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
|
||||
namespace App\Services\EDocument\Gateway\Storecove\Models;
|
||||
|
||||
use JsonSerializable;
|
||||
use Symfony\Component\Serializer\Annotation\SerializedName;
|
||||
use DateTime;
|
||||
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
|
||||
use Symfony\Component\Serializer\Attribute\Context;
|
||||
|
||||
class Invoice implements JsonSerializable
|
||||
class Invoice
|
||||
{
|
||||
#[SerializedName('taxSystem')]
|
||||
private string $taxSystem = 'tax_line_percentages';
|
||||
public string $taxSystem = 'tax_line_percentages';
|
||||
|
||||
#[SerializedName('documentCurrency')]
|
||||
private string $documentCurrency = '';
|
||||
public string $documentCurrency = '';
|
||||
|
||||
#[SerializedName('invoiceNumber')]
|
||||
private string $invoiceNumber = '';
|
||||
public string $invoiceNumber = '';
|
||||
|
||||
#[SerializedName('issueDate')]
|
||||
private DateTime $issueDate;
|
||||
public string $issueDate = '';
|
||||
|
||||
#[SerializedName('taxPointDate')]
|
||||
private ?DateTime $taxPointDate = null;
|
||||
public string $taxPointDate = '';
|
||||
|
||||
#[SerializedName('dueDate')]
|
||||
private DateTime $dueDate;
|
||||
public string $dueDate = '';
|
||||
|
||||
#[SerializedName('invoicePeriod')]
|
||||
private array $invoicePeriod = [];
|
||||
public string $invoicePeriod = '';
|
||||
|
||||
#[SerializedName('references')]
|
||||
private array $references = [];
|
||||
public array $references = [];
|
||||
|
||||
#[SerializedName('accountingCost')]
|
||||
private ?string $accountingCost = null;
|
||||
public ?string $accountingCost = null;
|
||||
|
||||
#[SerializedName('note')]
|
||||
private string $note = '';
|
||||
public string $note = '';
|
||||
|
||||
#[SerializedName('amountIncludingVat')]
|
||||
private float $amountIncludingVat = 0.0;
|
||||
public float $amountIncludingVat = 0.0;
|
||||
|
||||
#[SerializedName('prepaidAmount')]
|
||||
private ?float $prepaidAmount = null;
|
||||
public ?float $prepaidAmount = null;
|
||||
|
||||
#[SerializedName('accountingSupplierParty')]
|
||||
private array $accountingSupplierParty = [];
|
||||
public array $accountingSupplierParty = [];
|
||||
|
||||
#[SerializedName('accountingCustomerParty')]
|
||||
private array $accountingCustomerParty = [];
|
||||
public array $accountingCustomerParty = [];
|
||||
|
||||
#[SerializedName('paymentMeans')]
|
||||
private array $paymentMeans = [];
|
||||
public array $paymentMeans = [];
|
||||
|
||||
#[SerializedName('taxTotal')]
|
||||
private array $taxTotal = [];
|
||||
public array $taxTotal = [];
|
||||
|
||||
/**
|
||||
* @var InvoiceLines[]
|
||||
*/
|
||||
private array $invoiceLines = [];
|
||||
public array $invoiceLines = [];
|
||||
|
||||
// Getters and setters for all properties
|
||||
|
||||
public function setDocumentCurrency(string $documentCurrency): void
|
||||
{
|
||||
@ -73,99 +63,163 @@ class Invoice implements JsonSerializable
|
||||
$this->invoiceNumber = $invoiceNumber;
|
||||
}
|
||||
|
||||
public function setIssueDate(DateTime $issueDate): void
|
||||
public function setIssueDate($issueDate): void
|
||||
{
|
||||
$this->issueDate = $issueDate;
|
||||
}
|
||||
|
||||
public function setTaxPointDate(?DateTime $taxPointDate): void
|
||||
public function setTaxPointDate($taxPointDate): void
|
||||
{
|
||||
$this->taxPointDate = $taxPointDate;
|
||||
}
|
||||
|
||||
public function setDueDate(DateTime $dueDate): void
|
||||
public function setDueDate($dueDate): void
|
||||
{
|
||||
$this->dueDate = $dueDate;
|
||||
}
|
||||
|
||||
public function setInvoicePeriod(array $invoicePeriod): void
|
||||
public function setInvoicePeriod($invoicePeriod): void
|
||||
{
|
||||
$this->invoicePeriod = $invoicePeriod;
|
||||
}
|
||||
|
||||
public function setReferences(array $references): void
|
||||
public function setReferences( $references): void
|
||||
{
|
||||
$this->references = $references;
|
||||
}
|
||||
|
||||
public function setAccountingCost(?string $accountingCost): void
|
||||
public function setAccountingCost($accountingCost): void
|
||||
{
|
||||
$this->accountingCost = $accountingCost;
|
||||
}
|
||||
|
||||
public function setNote(string $note): void
|
||||
public function setNote($note): void
|
||||
{
|
||||
$this->note = $note;
|
||||
}
|
||||
|
||||
public function setAmountIncludingVat(float $amountIncludingVat): void
|
||||
public function setAmountIncludingVat ($amountIncludingVat): void
|
||||
{
|
||||
$this->amountIncludingVat = $amountIncludingVat;
|
||||
}
|
||||
|
||||
public function setPrepaidAmount(?float $prepaidAmount): void
|
||||
public function setPrepaidAmount( $prepaidAmount): void
|
||||
{
|
||||
$this->prepaidAmount = $prepaidAmount;
|
||||
}
|
||||
|
||||
public function setAccountingSupplierParty(array $accountingSupplierParty): void
|
||||
public function setAccountingSupplierParty( $accountingSupplierParty): void
|
||||
{
|
||||
$this->accountingSupplierParty = $accountingSupplierParty;
|
||||
}
|
||||
|
||||
public function setAccountingCustomerParty(array $accountingCustomerParty): void
|
||||
public function setAccountingCustomerParty( $accountingCustomerParty): void
|
||||
{
|
||||
$this->accountingCustomerParty = $accountingCustomerParty;
|
||||
}
|
||||
|
||||
public function setPaymentMeans(array $paymentMeans): void
|
||||
public function setPaymentMeans( $paymentMeans): void
|
||||
{
|
||||
$this->paymentMeans = $paymentMeans;
|
||||
}
|
||||
|
||||
public function setTaxTotal(array $taxTotal): void
|
||||
public function setTaxTotal( $taxTotal): void
|
||||
{
|
||||
$this->taxTotal = $taxTotal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InvoiceLines[] $invoiceLines
|
||||
*/
|
||||
public function setInvoiceLines(array $invoiceLines): void
|
||||
{
|
||||
$this->invoiceLines = $invoiceLines;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): mixed
|
||||
public function getInvoiceLines()
|
||||
{
|
||||
return [
|
||||
'taxSystem' => $this->taxSystem,
|
||||
'documentCurrency' => $this->documentCurrency,
|
||||
'invoiceNumber' => $this->invoiceNumber,
|
||||
'issueDate' => $this->issueDate->format('Y-m-d'),
|
||||
'taxPointDate' => $this->taxPointDate ? $this->taxPointDate->format('Y-m-d') : null,
|
||||
'dueDate' => $this->dueDate->format('Y-m-d'),
|
||||
'invoicePeriod' => $this->invoicePeriod,
|
||||
'references' => $this->references,
|
||||
'accountingCost' => $this->accountingCost,
|
||||
'note' => $this->note,
|
||||
'amountIncludingVat' => $this->amountIncludingVat,
|
||||
'prepaidAmount' => $this->prepaidAmount,
|
||||
'accountingSupplierParty' => $this->accountingSupplierParty,
|
||||
'accountingCustomerParty' => $this->accountingCustomerParty,
|
||||
'paymentMeans' => $this->paymentMeans,
|
||||
'taxTotal' => $this->taxTotal,
|
||||
'invoiceLines' => $this->invoiceLines,
|
||||
];
|
||||
return $this->invoiceLines;
|
||||
}
|
||||
|
||||
public function getTaxSystem(): string
|
||||
{
|
||||
return $this->taxSystem;
|
||||
}
|
||||
|
||||
public function getDocumentCurrency(): string
|
||||
{
|
||||
return $this->documentCurrency;
|
||||
}
|
||||
|
||||
public function getInvoiceNumber(): string
|
||||
{
|
||||
return $this->invoiceNumber;
|
||||
}
|
||||
|
||||
public function getIssueDate(): string
|
||||
{
|
||||
return $this->issueDate;
|
||||
}
|
||||
|
||||
public function getTaxPointDate(): string
|
||||
{
|
||||
return $this->taxPointDate;
|
||||
}
|
||||
|
||||
public function getDueDate(): string
|
||||
{
|
||||
return $this->dueDate;
|
||||
}
|
||||
|
||||
public function getInvoicePeriod(): string
|
||||
{
|
||||
return $this->invoicePeriod;
|
||||
}
|
||||
|
||||
public function getReferences(): array
|
||||
{
|
||||
return $this->references;
|
||||
}
|
||||
|
||||
public function getAccountingCost(): ?string
|
||||
{
|
||||
return $this->accountingCost;
|
||||
}
|
||||
|
||||
public function getNote(): string
|
||||
{
|
||||
return $this->note;
|
||||
}
|
||||
|
||||
public function getAmountIncludingVat(): float
|
||||
{
|
||||
return $this->amountIncludingVat;
|
||||
}
|
||||
|
||||
public function getPrepaidAmount(): ?float
|
||||
{
|
||||
return $this->prepaidAmount;
|
||||
}
|
||||
|
||||
public function getAccountingSupplierParty(): array
|
||||
{
|
||||
return $this->accountingSupplierParty;
|
||||
}
|
||||
|
||||
public function getAccountingCustomerParty(): array
|
||||
{
|
||||
return $this->accountingCustomerParty;
|
||||
}
|
||||
|
||||
public function getPaymentMeans(): array
|
||||
{
|
||||
return $this->paymentMeans;
|
||||
}
|
||||
|
||||
public function getTaxTotal(): array
|
||||
{
|
||||
return $this->taxTotal;
|
||||
}
|
||||
|
||||
public function setTaxSystem(string $taxSystem): void
|
||||
{
|
||||
$this->taxSystem = $taxSystem;
|
||||
}
|
||||
}
|
||||
|
@ -7,25 +7,18 @@ use Symfony\Component\Serializer\Annotation\SerializedName;
|
||||
|
||||
class InvoiceLines
|
||||
{
|
||||
#[SerializedName('ID.value')]
|
||||
public string $lineId = '';
|
||||
|
||||
#[SerializedName('LineExtensionAmount.amount')]
|
||||
public float $amountExcludingVat = 0.0;
|
||||
|
||||
#[SerializedName('Price.PriceAmount.amount')]
|
||||
public float $itemPrice = 0.0;
|
||||
|
||||
#[SerializedName('InvoicedQuantity')]
|
||||
public int $quantity = 0;
|
||||
|
||||
#[SerializedName('InvoicedQuantity.unitCode')]
|
||||
public string $quantityUnitCode = '';
|
||||
|
||||
#[SerializedName('Item.Name')]
|
||||
public string $name = '';
|
||||
|
||||
#[SerializedName('Item.Description')]
|
||||
public string $description = '';
|
||||
|
||||
public Tax $tax;
|
||||
|
@ -1,244 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\EDocument\Gateway\Storecove;
|
||||
|
||||
use App\Services\EDocument\Gateway\Storecove\Models\Tax;
|
||||
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
|
||||
use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader;
|
||||
use App\Services\EDocument\Gateway\Storecove\Models\InvoiceLines;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\Invoice as PeppolInvoice;
|
||||
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
|
||||
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
|
||||
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
|
||||
use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter;
|
||||
use App\Services\EDocument\Gateway\Storecove\Models\Invoice as StorecoveInvoice;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
|
||||
|
||||
class PeppolToStorecoveNormalizer implements DenormalizerInterface
|
||||
{
|
||||
private SerializerInterface $serializer;
|
||||
private ObjectNormalizer $objectNormalizer;
|
||||
|
||||
|
||||
public function __construct(SerializerInterface $serializer)
|
||||
{
|
||||
|
||||
|
||||
$this->serializer = $serializer;
|
||||
|
||||
$classMetadataFactory = new ClassMetadataFactory(new AttributeLoader());
|
||||
$metadataAwareNameConverter = new MetadataAwareNameConverter($classMetadataFactory);
|
||||
$this->objectNormalizer = new ObjectNormalizer($classMetadataFactory, $metadataAwareNameConverter);
|
||||
|
||||
}
|
||||
|
||||
public function denormalize(mixed $data, string $type, string $format = null, array $context = []): mixed
|
||||
{
|
||||
$peppolInvoice = $data;
|
||||
$storecoveInvoice = new StorecoveInvoice();
|
||||
|
||||
|
||||
$storecoveInvoice->setDocumentCurrency($peppolInvoice->DocumentCurrencyCode ?? '');
|
||||
$storecoveInvoice->setInvoiceNumber($peppolInvoice->ID ?? '');
|
||||
$storecoveInvoice->setIssueDate($peppolInvoice->IssueDate);
|
||||
$storecoveInvoice->setDueDate($peppolInvoice->DueDate);
|
||||
$storecoveInvoice->setNote($peppolInvoice->Note ?? '');
|
||||
$storecoveInvoice->setAmountIncludingVat((float)($peppolInvoice->LegalMonetaryTotal->TaxInclusiveAmount->amount ?? 0));
|
||||
|
||||
if (isset($peppolInvoice->InvoicePeriod[0])) {
|
||||
$storecoveInvoice->setInvoicePeriod([
|
||||
'startDate' => $peppolInvoice->InvoicePeriod[0]->StartDate,
|
||||
'endDate' => $peppolInvoice->InvoicePeriod[0]->EndDate,
|
||||
]);
|
||||
}
|
||||
|
||||
$storecoveInvoice->setReferences([
|
||||
'buyerReference' => $peppolInvoice->BuyerReference ?? '',
|
||||
'orderReference' => $peppolInvoice->OrderReference->ID->value ?? '',
|
||||
]);
|
||||
|
||||
if (isset($peppolInvoice->AccountingSupplierParty->Party)) {
|
||||
$supplier = $peppolInvoice->AccountingSupplierParty->Party;
|
||||
$storecoveInvoice->setAccountingSupplierParty([
|
||||
'name' => $supplier->PartyName[0]->Name ?? '',
|
||||
'vatNumber' => $supplier->PartyIdentification[0]->ID->value ?? '',
|
||||
'streetName' => $supplier->PostalAddress->StreetName ?? '',
|
||||
'cityName' => $supplier->PostalAddress->CityName ?? '',
|
||||
'postalZone' => $supplier->PostalAddress->PostalZone ?? '',
|
||||
'countryCode' => $supplier->PostalAddress->Country->IdentificationCode->value ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
if (isset($peppolInvoice->AccountingCustomerParty->Party)) {
|
||||
$customer = $peppolInvoice->AccountingCustomerParty->Party;
|
||||
$storecoveInvoice->setAccountingCustomerParty([
|
||||
'name' => $customer->PartyName[0]->Name ?? '',
|
||||
'vatNumber' => $customer->PartyIdentification[0]->ID->value ?? '',
|
||||
'streetName' => $customer->PostalAddress->StreetName ?? '',
|
||||
'cityName' => $customer->PostalAddress->CityName ?? '',
|
||||
'postalZone' => $customer->PostalAddress->PostalZone ?? '',
|
||||
'countryCode' => $customer->PostalAddress->Country->IdentificationCode->value ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
if (isset($peppolInvoice->PaymentMeans[0])) {
|
||||
$storecoveInvoice->setPaymentMeans([
|
||||
'paymentID' => $peppolInvoice->PaymentMeans[0]->PayeeFinancialAccount->ID->value ?? '',
|
||||
]);
|
||||
}
|
||||
|
||||
// Map tax total at invoice level
|
||||
$taxTotal = [];
|
||||
if (isset($peppolInvoice->InvoiceLine[0]->TaxTotal[0])) {
|
||||
$taxTotal[] = [
|
||||
'taxAmount' => (float)($peppolInvoice->InvoiceLine[0]->TaxTotal[0]->TaxAmount->amount ?? 0),
|
||||
'taxCurrency' => $peppolInvoice->DocumentCurrencyCode ?? '',
|
||||
];
|
||||
}
|
||||
$storecoveInvoice->setTaxTotal($taxTotal);
|
||||
|
||||
if (isset($peppolInvoice->InvoiceLine)) {
|
||||
$invoiceLines = [];
|
||||
foreach ($peppolInvoice->InvoiceLine as $line) {
|
||||
$invoiceLine = new InvoiceLines();
|
||||
$invoiceLine->setLineId($line->ID->value ?? '');
|
||||
$invoiceLine->setAmountExcludingVat((float)($line->LineExtensionAmount->amount ?? 0));
|
||||
$invoiceLine->setQuantity((float)($line->InvoicedQuantity ?? 0));
|
||||
$invoiceLine->setQuantityUnitCode(''); // Not present in the provided JSON
|
||||
$invoiceLine->setItemPrice((float)($line->Price->PriceAmount->amount ?? 0));
|
||||
$invoiceLine->setName($line->Item->Name ?? '');
|
||||
$invoiceLine->setDescription($line->Item->Description ?? '');
|
||||
|
||||
$tax = new Tax();
|
||||
if (isset($line->TaxTotal[0])) {
|
||||
$taxTotal = $line->TaxTotal[0];
|
||||
$tax->setTaxAmount((float)($taxTotal->TaxAmount->amount ?? 0));
|
||||
|
||||
if (isset($line->Item->ClassifiedTaxCategory[0])) {
|
||||
$taxCategory = $line->Item->ClassifiedTaxCategory[0];
|
||||
$tax->setTaxPercentage((float)($taxCategory->Percent ?? 0));
|
||||
$tax->setTaxCategory($taxCategory->ID->value ?? '');
|
||||
}
|
||||
|
||||
$tax->setTaxableAmount((float)($line->LineExtensionAmount->amount ?? 0));
|
||||
}
|
||||
$invoiceLine->setTax($tax);
|
||||
|
||||
$invoiceLines[] = $invoiceLine;
|
||||
}
|
||||
$storecoveInvoice->setInvoiceLines($invoiceLines);
|
||||
}
|
||||
|
||||
return $storecoveInvoice;
|
||||
|
||||
|
||||
}
|
||||
|
||||
private function validateStorecoveInvoice(StorecoveInvoice $invoice): void
|
||||
{
|
||||
$requiredFields = ['documentCurrency', 'invoiceNumber', 'issueDate', 'dueDate'];
|
||||
foreach ($requiredFields as $field) {
|
||||
if (empty($invoice->$field)) {
|
||||
throw new \InvalidArgumentException("Required field '$field' is missing or empty");
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($invoice->invoiceLines)) {
|
||||
throw new \InvalidArgumentException("Invoice must have at least one line item");
|
||||
}
|
||||
|
||||
// Add more validations as needed
|
||||
}
|
||||
|
||||
public function supportsDenormalization(mixed $data, string $type, string $format = null, array $context = []): bool
|
||||
{
|
||||
return $type === StorecoveInvoice::class && $data instanceof PeppolInvoice;
|
||||
}
|
||||
|
||||
public function getSupportedTypes(?string $format): array
|
||||
{
|
||||
return [
|
||||
StorecoveInvoice::class => true,
|
||||
];
|
||||
}
|
||||
|
||||
private function mapNestedProperties($object, array $nestedPaths): array
|
||||
{
|
||||
$result = [];
|
||||
foreach ($nestedPaths as $key => $path) {
|
||||
if (is_array($path)) {
|
||||
// Try multiple paths
|
||||
foreach ($path as $possiblePath) {
|
||||
$value = $this->getValueFromPath($object, $possiblePath);
|
||||
if ($value !== null) {
|
||||
$result[$key] = $value;
|
||||
nlog("Mapped nested property: $key", ['path' => $possiblePath, 'value' => $value]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isset($result[$key])) {
|
||||
nlog("Failed to map nested property: $key", ['paths' => $path]);
|
||||
}
|
||||
} else {
|
||||
$value = $this->getValueFromPath($object, $path);
|
||||
if ($value !== null) {
|
||||
$result[$key] = $value;
|
||||
nlog("Mapped nested property: $key", ['path' => $path, 'value' => $value]);
|
||||
} else {
|
||||
nlog("Failed to map nested property: $key", ['path' => $path]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function getValueFromPath($object, string $path)
|
||||
{
|
||||
$parts = explode('.', $path);
|
||||
$value = $object;
|
||||
foreach ($parts as $part) {
|
||||
if (preg_match('/(.+)\[(\d+)\]/', $part, $matches)) {
|
||||
$property = $matches[1];
|
||||
$index = $matches[2];
|
||||
$value = $value->$property[$index] ?? null;
|
||||
} else {
|
||||
$value = $value->$part ?? null;
|
||||
}
|
||||
if ($value === null) {
|
||||
nlog("Null value encountered in path: $path at part: $part");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return $value instanceof \DateTime ? $value->format('Y-m-d') : $value;
|
||||
}
|
||||
|
||||
private function castValue(string $property, $value)
|
||||
{
|
||||
try {
|
||||
$reflectionProperty = new \ReflectionProperty(StorecoveInvoice::class, $property);
|
||||
$type = $reflectionProperty->getType();
|
||||
|
||||
if ($type instanceof \ReflectionNamedType) {
|
||||
switch ($type->getName()) {
|
||||
case 'float':
|
||||
return (float) $value;
|
||||
case 'int':
|
||||
return (int) $value;
|
||||
case 'string':
|
||||
return (string) $value;
|
||||
case 'bool':
|
||||
return (bool) $value;
|
||||
case 'array':
|
||||
return (array) $value;
|
||||
default:
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
} catch (\ReflectionException $e) {
|
||||
nlog("Error casting value for property: $property", ['error' => $e->getMessage()]);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\EDocument\Gateway\Transformers;
|
||||
|
||||
use App\Services\EDocument\Gateway\Storecove\Models\Invoice as StorecoveInvoice;
|
||||
|
||||
class StorecoveTransformer implements TransformerInterface
|
||||
{
|
||||
private StorecoveInvoice $s_invoice;
|
||||
|
||||
public function transform(mixed $peppolInvoice)
|
||||
{
|
||||
|
||||
$this->s_invoice = new StorecoveInvoice();
|
||||
|
||||
$this->s_invoice->setDocumentCurrency($peppolInvoice->DocumentCurrencyCode ?? '');
|
||||
$this->s_invoice->setInvoiceNumber($peppolInvoice->ID ?? '');
|
||||
$this->s_invoice->setIssueDate($peppolInvoice->IssueDate->format('Y-m-d'));
|
||||
$this->s_invoice->setTaxPointDate($peppolInvoice->IssueDate->format('Y-m-d'));
|
||||
$this->s_invoice->setDueDate($peppolInvoice->DueDate->format('Y-m-d') ?? '');
|
||||
$this->s_invoice->setNote($peppolInvoice->Note ?? '');
|
||||
|
||||
// Only use this if we are billing for services between a period.
|
||||
if (isset($peppolInvoice->InvoicePeriod[0]) &&
|
||||
isset($peppolInvoice->InvoicePeriod[0]->StartDate) &&
|
||||
isset($peppolInvoice->InvoicePeriod[0]->EndDate)) {
|
||||
$this->s_invoice->setInvoicePeriod("{$peppolInvoice->InvoicePeriod[0]->StartDate} - {$peppolInvoice->InvoicePeriod[0]->EndDate}");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// $this->s_invoice->setReferences([
|
||||
// 'buyerReference' => $peppolInvoice->BuyerReference ?? '',
|
||||
// 'orderReference' => $peppolInvoice->OrderReference->ID->value ?? '',
|
||||
// ]);
|
||||
|
||||
// $this->s_invoice->setAmountIncludingVat((float)($peppolInvoice->LegalMonetaryTotal->TaxInclusiveAmount->amount ?? 0));
|
||||
// if (isset($peppolInvoice->AccountingSupplierParty->Party)) {
|
||||
// $supplier = $peppolInvoice->AccountingSupplierParty->Party;
|
||||
// $this->s_invoice->setAccountingSupplierParty([
|
||||
// 'name' => $supplier->PartyName[0]->Name ?? '',
|
||||
// 'vatNumber' => $supplier->PartyIdentification[0]->ID->value ?? '',
|
||||
// 'streetName' => $supplier->PostalAddress->StreetName ?? '',
|
||||
// 'cityName' => $supplier->PostalAddress->CityName ?? '',
|
||||
// 'postalZone' => $supplier->PostalAddress->PostalZone ?? '',
|
||||
// 'countryCode' => $supplier->PostalAddress->Country->IdentificationCode->value ?? '',
|
||||
// ]);
|
||||
// }
|
||||
|
||||
// if (isset($peppolInvoice->AccountingCustomerParty->Party)) {
|
||||
// $customer = $peppolInvoice->AccountingCustomerParty->Party;
|
||||
// $this->s_invoice->setAccountingCustomerParty([
|
||||
// 'name' => $customer->PartyName[0]->Name ?? '',
|
||||
// 'vatNumber' => $customer->PartyIdentification[0]->ID->value ?? '',
|
||||
// 'streetName' => $customer->PostalAddress->StreetName ?? '',
|
||||
// 'cityName' => $customer->PostalAddress->CityName ?? '',
|
||||
// 'postalZone' => $customer->PostalAddress->PostalZone ?? '',
|
||||
// 'countryCode' => $customer->PostalAddress->Country->IdentificationCode->value ?? '',
|
||||
// ]);
|
||||
// }
|
||||
|
||||
// if (isset($peppolInvoice->PaymentMeans[0])) {
|
||||
// $this->s_invoice->setPaymentMeans([
|
||||
// 'paymentID' => $peppolInvoice->PaymentMeans[0]->PayeeFinancialAccount->ID->value ?? '',
|
||||
// ]);
|
||||
// }
|
||||
|
||||
// // Map tax total at invoice level
|
||||
// $taxTotal = [];
|
||||
// if (isset($peppolInvoice->InvoiceLine[0]->TaxTotal[0])) {
|
||||
// $taxTotal[] = [
|
||||
// 'taxAmount' => (float)($peppolInvoice->InvoiceLine[0]->TaxTotal[0]->TaxAmount->amount ?? 0),
|
||||
// 'taxCurrency' => $peppolInvoice->DocumentCurrencyCode ?? '',
|
||||
// ];
|
||||
// }
|
||||
// $this->s_invoice->setTaxTotal($taxTotal);
|
||||
|
||||
// if (isset($peppolInvoice->InvoiceLine)) {
|
||||
// $invoiceLines = [];
|
||||
// foreach ($peppolInvoice->InvoiceLine as $line) {
|
||||
// $invoiceLine = new InvoiceLines();
|
||||
// $invoiceLine->setLineId($line->ID->value ?? '');
|
||||
// $invoiceLine->setAmountExcludingVat((float)($line->LineExtensionAmount->amount ?? 0));
|
||||
// $invoiceLine->setQuantity((float)($line->InvoicedQuantity ?? 0));
|
||||
// $invoiceLine->setQuantityUnitCode(''); // Not present in the provided JSON
|
||||
// $invoiceLine->setItemPrice((float)($line->Price->PriceAmount->amount ?? 0));
|
||||
// $invoiceLine->setName($line->Item->Name ?? '');
|
||||
// $invoiceLine->setDescription($line->Item->Description ?? '');
|
||||
|
||||
// $tax = new Tax();
|
||||
// if (isset($line->TaxTotal[0])) {
|
||||
// $taxTotal = $line->TaxTotal[0];
|
||||
// $tax->setTaxAmount((float)($taxTotal->TaxAmount->amount ?? 0));
|
||||
|
||||
// if (isset($line->Item->ClassifiedTaxCategory[0])) {
|
||||
// $taxCategory = $line->Item->ClassifiedTaxCategory[0];
|
||||
// $tax->setTaxPercentage((float)($taxCategory->Percent ?? 0));
|
||||
// $tax->setTaxCategory($taxCategory->ID->value ?? '');
|
||||
// }
|
||||
|
||||
// $tax->setTaxableAmount((float)($line->LineExtensionAmount->amount ?? 0));
|
||||
// }
|
||||
// $invoiceLine->setTax($tax);
|
||||
|
||||
// $invoiceLines[] = $invoiceLine;
|
||||
// }
|
||||
// $this->s_invoice->setInvoiceLines($invoiceLines);
|
||||
// }
|
||||
|
||||
// return $this->s_invoice;
|
||||
|
||||
}
|
||||
|
||||
public function getInvoice(): StorecoveInvoice
|
||||
{
|
||||
return $this->s_invoice;
|
||||
}
|
||||
|
||||
public function toJson(): string
|
||||
{
|
||||
return json_encode($this->s_invoice, JSON_PRETTY_PRINT);
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* Invoice Ninja (https://invoiceninja.com).
|
||||
*
|
||||
* @link https://github.com/invoiceninja/invoiceninja source repository
|
||||
*
|
||||
* @copyright Copyright (c) 2024. Invoice Ninja LLC (https://invoiceninja.com)
|
||||
*
|
||||
* @license https://www.elastic.co/licensing/elastic-license
|
||||
*/
|
||||
|
||||
|
||||
namespace App\Services\EDocument\Gateway\Transformers;
|
||||
|
||||
interface TransformerInterface
|
||||
{
|
||||
public function transform(mixed $peppolInvoice);
|
||||
|
||||
public function getInvoice();
|
||||
|
||||
public function toJson();
|
||||
}
|
@ -16,6 +16,7 @@ use App\Models\Client;
|
||||
use App\Models\Company;
|
||||
use App\Models\Invoice;
|
||||
use Tests\MockAccountData;
|
||||
use Illuminate\Support\Str;
|
||||
use App\Models\ClientContact;
|
||||
use App\DataMapper\InvoiceItem;
|
||||
use App\DataMapper\Tax\TaxModel;
|
||||
@ -23,19 +24,28 @@ use App\DataMapper\ClientSettings;
|
||||
use App\DataMapper\CompanySettings;
|
||||
use App\Services\EDocument\Standards\Peppol;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Serializer\Encoder\XmlEncoder;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\PaymentMeans;
|
||||
use Symfony\Component\Serializer\Encoder\JsonEncoder;
|
||||
use App\Services\EDocument\Gateway\Storecove\Storecove;
|
||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||||
use Symfony\Component\PropertyInfo\PropertyInfoExtractor;
|
||||
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
|
||||
|
||||
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
|
||||
|
||||
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
|
||||
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
|
||||
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
|
||||
use Symfony\Component\Serializer\Mapping\Loader\AttributeLoader;
|
||||
use InvoiceNinja\EInvoice\Models\Peppol\Invoice as PeppolInvoice;
|
||||
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
|
||||
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
|
||||
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
|
||||
|
||||
use App\Services\EDocument\Gateway\Storecove\PeppolToStorecoveNormalizer;
|
||||
|
||||
use Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter;
|
||||
use App\Services\EDocument\Gateway\Storecove\Models\Invoice as StorecoveInvoice;
|
||||
use App\Services\EDocument\Gateway\Transformers\StorecoveTransformer;
|
||||
|
||||
class StorecoveTest extends TestCase
|
||||
{
|
||||
@ -55,6 +65,36 @@ class StorecoveTest extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function testNormalizingToStorecove()
|
||||
{
|
||||
|
||||
$e_invoice = new \InvoiceNinja\EInvoice\Models\Peppol\Invoice();
|
||||
|
||||
$invoice = $this->createATData();
|
||||
|
||||
$stub = json_decode('{"Invoice":{"Note":"Nooo","PaymentMeans":[{"ID":{"value":"afdasfasdfasdfas"},"PayeeFinancialAccount":{"Name":"PFA-NAME","ID":{"value":"DE89370400440532013000"},"AliasName":"PFA-Alias","AccountTypeCode":{"value":"CHECKING"},"AccountFormatCode":{"value":"IBAN"},"CurrencyCode":{"value":"EUR"},"FinancialInstitutionBranch":{"ID":{"value":"DEUTDEMMXXX"},"Name":"Deutsche Bank"}}}]}}');
|
||||
foreach ($stub as $key => $value) {
|
||||
$e_invoice->{$key} = $value;
|
||||
}
|
||||
|
||||
$invoice->e_invoice = $e_invoice;
|
||||
|
||||
$p = new Peppol($invoice);
|
||||
$p->run();
|
||||
$peppolInvoice = $p->getInvoice();
|
||||
|
||||
|
||||
$s_transformer = new StorecoveTransformer();
|
||||
$s_transformer->transform($peppolInvoice);
|
||||
|
||||
$json = $s_transformer->toJson();
|
||||
|
||||
$this->assertJson($json);
|
||||
|
||||
nlog($json);
|
||||
}
|
||||
|
||||
public function testUnsetOfVatNumers()
|
||||
{
|
||||
|
||||
@ -1332,81 +1372,6 @@ class StorecoveTest extends TestCase
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function testNormalizingToStorecove()
|
||||
{
|
||||
|
||||
$e_invoice = new \InvoiceNinja\EInvoice\Models\Peppol\Invoice();
|
||||
|
||||
$invoice = $this->createATData();
|
||||
|
||||
$stub = json_decode('{"Invoice":{"Note":"Nooo","PaymentMeans":[{"ID":{"value":"afdasfasdfasdfas"},"PayeeFinancialAccount":{"Name":"PFA-NAME","ID":{"value":"DE89370400440532013000"},"AliasName":"PFA-Alias","AccountTypeCode":{"value":"CHECKING"},"AccountFormatCode":{"value":"IBAN"},"CurrencyCode":{"value":"EUR"},"FinancialInstitutionBranch":{"ID":{"value":"DEUTDEMMXXX"},"Name":"Deutsche Bank"}}}]}}');
|
||||
foreach ($stub as $key => $value) {
|
||||
$e_invoice->{$key} = $value;
|
||||
}
|
||||
|
||||
$invoice->e_invoice = $e_invoice;
|
||||
|
||||
|
||||
try {
|
||||
// Assuming $invoice is already defined or created earlier in your test
|
||||
$p = new Peppol($invoice);
|
||||
$p->run();
|
||||
$peppolInvoice = $p->getInvoice();
|
||||
|
||||
nlog("Peppol Invoice: " . json_encode($peppolInvoice, JSON_PRETTY_PRINT));
|
||||
|
||||
// Create the serializer with all necessary normalizers
|
||||
$classMetadataFactory = new ClassMetadataFactory(new AttributeLoader());
|
||||
$metadataAwareNameConverter = new MetadataAwareNameConverter($classMetadataFactory);
|
||||
$objectNormalizer = new ObjectNormalizer($classMetadataFactory, $metadataAwareNameConverter);
|
||||
|
||||
$encoders = [new JsonEncoder()];
|
||||
$normalizers = [
|
||||
new ArrayDenormalizer(),
|
||||
$objectNormalizer,
|
||||
new ObjectNormalizer(), // This is a fallback normalizer
|
||||
];
|
||||
$serializer = new Serializer($normalizers, $encoders);
|
||||
|
||||
// Create the PeppolToStorecoveNormalizer with the serializer
|
||||
$peppolToStorecoveNormalizer = new PeppolToStorecoveNormalizer($serializer);
|
||||
|
||||
// Denormalize the Peppol invoice to a Storecove invoice
|
||||
$storecoveInvoice = $peppolToStorecoveNormalizer->denormalize($peppolInvoice, StorecoveInvoice::class);
|
||||
|
||||
nlog("Storecove Invoice after denormalization: " . json_encode($storecoveInvoice, JSON_PRETTY_PRINT));
|
||||
|
||||
// Serialize the Storecove invoice to JSON
|
||||
$jsonOutput = $serializer->serialize($storecoveInvoice, 'json', [
|
||||
'json_encode_options' => JSON_PRETTY_PRINT
|
||||
]);
|
||||
|
||||
nlog("Final JSON output: " . $jsonOutput);
|
||||
|
||||
// Add assertions to verify the output
|
||||
$this->assertInstanceOf(StorecoveInvoice::class, $storecoveInvoice);
|
||||
$this->assertJson($jsonOutput);
|
||||
|
||||
// Add more specific assertions based on your expected output
|
||||
$decodedOutput = json_decode($jsonOutput, true);
|
||||
$this->assertArrayHasKey('documentCurrency', $decodedOutput);
|
||||
$this->assertArrayHasKey('invoiceNumber', $decodedOutput);
|
||||
$this->assertArrayHasKey('invoiceLines', $decodedOutput);
|
||||
$this->assertIsArray($decodedOutput['invoiceLines']);
|
||||
// Add more assertions as needed
|
||||
|
||||
} catch (\Exception $e) {
|
||||
nlog("Error occurred: " . $e->getMessage());
|
||||
nlog("Stack trace: " . $e->getTraceAsString());
|
||||
throw $e; // Re-throw the exception to fail the test
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function PestAtRules()
|
||||
{
|
||||
$this->routing_id = 293801;
|
||||
|
Loading…
Reference in New Issue
Block a user