1
0
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:
David Bomba 2024-10-28 15:47:57 +11:00
parent f44180ee24
commit 75078de048
6 changed files with 317 additions and 404 deletions

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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();
}

View File

@ -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;