mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-08 20:22:42 +01:00
Storecove
This commit is contained in:
parent
5698c59322
commit
ed9dd868b4
@ -56,10 +56,22 @@ class Storecove
|
||||
|
||||
public Mutator $mutator;
|
||||
|
||||
public StorecoveAdapter $adapter;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->router = new StorecoveRouter();
|
||||
$this->mutator = new Mutator($this);
|
||||
$this->adapter = new StorecoveAdapter($this);
|
||||
}
|
||||
|
||||
public function build($peppol_model): self
|
||||
{
|
||||
$this->adapter
|
||||
->transform($peppol_model)
|
||||
->decorate()
|
||||
->validate();
|
||||
}
|
||||
|
||||
/**
|
||||
|
133
app/Services/EDocument/Gateway/Storecove/StorecoveAdapter.php
Normal file
133
app/Services/EDocument/Gateway/Storecove/StorecoveAdapter.php
Normal file
@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\EDocument\Gateway\Storecove;
|
||||
|
||||
use App\Services\EDocument\Gateway\Storecove\Models\Invoice;
|
||||
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 App\Services\EDocument\Gateway\Transformers\StorecoveTransformer;
|
||||
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 Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
|
||||
|
||||
class StorecoveAdapter
|
||||
{
|
||||
|
||||
public function __construct(public Storecove $storecove){}
|
||||
|
||||
private Invoice $storecove_invoice;
|
||||
|
||||
private array $errors = [];
|
||||
|
||||
private bool $valid_document = true;
|
||||
|
||||
public function transform($invoice): self
|
||||
{
|
||||
|
||||
$context = [
|
||||
DateTimeNormalizer::FORMAT_KEY => 'Y-m-d',
|
||||
AbstractObjectNormalizer::SKIP_NULL_VALUES => true,
|
||||
];
|
||||
|
||||
$serializer = $this->getSerializer();
|
||||
|
||||
/** @var Invoice $storecove_invoice */
|
||||
$this->storecove_invoice = $serializer->deserialize($invoice, Invoice::class, 'json', $context);
|
||||
|
||||
return $this;
|
||||
|
||||
}
|
||||
|
||||
public function decorate(): self
|
||||
{
|
||||
//set all taxmap countries
|
||||
|
||||
//configure identifiers
|
||||
|
||||
//set additional identifier if required (ie de => FR with FR vat)
|
||||
}
|
||||
|
||||
public function validate(): self
|
||||
{
|
||||
return $this->valid_document;
|
||||
}
|
||||
|
||||
public function getInvoice(): StorecoveInvoice
|
||||
{
|
||||
return $this->storecove_invoice;
|
||||
}
|
||||
|
||||
public function getErrors(): array
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
private function addError(string $error): self
|
||||
{
|
||||
$this->errors[] = $error;
|
||||
}
|
||||
|
||||
private function getSerializer()
|
||||
{
|
||||
|
||||
$phpDocExtractor = new PhpDocExtractor();
|
||||
$reflectionExtractor = new ReflectionExtractor();
|
||||
// list of PropertyListExtractorInterface (any iterable)
|
||||
$typeExtractors = [$reflectionExtractor,$phpDocExtractor];
|
||||
// list of PropertyDescriptionExtractorInterface (any iterable)
|
||||
$descriptionExtractors = [$phpDocExtractor];
|
||||
// list of PropertyAccessExtractorInterface (any iterable)
|
||||
$propertyInitializableExtractors = [$reflectionExtractor];
|
||||
$propertyInfo = new PropertyInfoExtractor(
|
||||
$propertyInitializableExtractors,
|
||||
$descriptionExtractors,
|
||||
$typeExtractors,
|
||||
);
|
||||
$xml_encoder = new XmlEncoder(['xml_format_output' => true, 'remove_empty_tags' => true,]);
|
||||
$json_encoder = new JsonEncoder();
|
||||
|
||||
$classMetadataFactory = new ClassMetadataFactory(new AttributeLoader());
|
||||
$metadataAwareNameConverter = new MetadataAwareNameConverter($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter());
|
||||
|
||||
$normalizer = new ObjectNormalizer($classMetadataFactory, $metadataAwareNameConverter, null, $propertyInfo);
|
||||
|
||||
$normalizers = [new DateTimeNormalizer(), $normalizer, new ArrayDenormalizer()];
|
||||
$encoders = [$xml_encoder, $json_encoder];
|
||||
$serializer = new Serializer($normalizers, $encoders);
|
||||
|
||||
|
||||
|
||||
return $serializer;
|
||||
}
|
||||
|
||||
private function removeEmptyValues(array $array): array
|
||||
{
|
||||
foreach ($array as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
$array[$key] = $this->removeEmptyValues($value);
|
||||
if (empty($array[$key])) {
|
||||
unset($array[$key]);
|
||||
}
|
||||
} elseif ($value === null || $value === '') {
|
||||
unset($array[$key]);
|
||||
}
|
||||
}
|
||||
// nlog($array);
|
||||
return $array;
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ use App\Services\EDocument\Gateway\Storecove\Models\AllowanceCharges;
|
||||
use App\Services\EDocument\Gateway\Storecove\Models\AccountingCustomerParty;
|
||||
use App\Services\EDocument\Gateway\Storecove\Models\AccountingSupplierParty;
|
||||
use App\Services\EDocument\Gateway\Storecove\Models\Invoice as StorecoveInvoice;
|
||||
use App\Services\EDocument\Gateway\Storecove\Storecove;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class StorecoveTransformer implements TransformerInterface
|
||||
@ -27,17 +28,27 @@ class StorecoveTransformer implements TransformerInterface
|
||||
|
||||
private array $tax_map = [];
|
||||
|
||||
public function setInvoice($s_invoice): self
|
||||
{
|
||||
$this->s_invoice = $s_invoice;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getInvoice($s_invoice): StorecoveInvoice
|
||||
{
|
||||
return $this->s_invoice;
|
||||
}
|
||||
|
||||
public function createNewStorecoveInvoice(): self
|
||||
{
|
||||
$this->s_invoice = (new \ReflectionClass(StorecoveInvoice::class))->newInstanceWithoutConstructor();
|
||||
}
|
||||
|
||||
//$invoice = inbound peppol
|
||||
public function transform(mixed $invoice)
|
||||
{
|
||||
|
||||
$this->s_invoice = (new \ReflectionClass(StorecoveInvoice::class))->newInstanceWithoutConstructor();
|
||||
|
||||
// $this->s_invoice->setDocumentCurrency($invoice->DocumentCurrencyCode ?? '');
|
||||
// $this->s_invoice->setInvoiceNumber($invoice->ID ?? '');
|
||||
// $this->s_invoice->setIssueDate($invoice->IssueDate->format('Y-m-d'));
|
||||
$this->s_invoice->setTaxPointDate($invoice->IssueDate->format('Y-m-d'));
|
||||
$this->s_invoice->setDueDate($invoice->DueDate->format('Y-m-d') ?? '');
|
||||
// $this->s_invoice->setNote($invoice->Note ?? '');
|
||||
|
||||
// Only use this if we are billing for services between a period.
|
||||
if (isset($invoice->InvoicePeriod[0]) &&
|
||||
@ -46,42 +57,18 @@ class StorecoveTransformer implements TransformerInterface
|
||||
$this->s_invoice->setInvoicePeriod("{$invoice->InvoicePeriod[0]->StartDate->format('Y-m-d')} - {$invoice->InvoicePeriod[0]->EndDate->format('Y-m-d')}");
|
||||
}
|
||||
|
||||
// $supplier_contact = new Contact(
|
||||
// email: $invoice->AccountingSupplierParty->Party->Contact->ElectronicMail,
|
||||
// firstName: $invoice->AccountingSupplierParty->Party->Contact->Name ?? null,
|
||||
// phone: $invoice->AccountingSupplierParty->Party->Contact->Telephone ?? null,
|
||||
// );
|
||||
|
||||
// $supplier_party = new Party(contact: $supplier_contact);
|
||||
// $asp = new AccountingSupplierParty($supplier_party);
|
||||
// $this->s_invoice->setAccountingSupplierParty($asp);
|
||||
|
||||
$lines = [];
|
||||
|
||||
// foreach($invoice->InvoiceLine as $peppolLine)
|
||||
// {
|
||||
foreach($invoice->InvoiceLine as $peppolLine)
|
||||
{
|
||||
|
||||
// $line = (new \ReflectionClass(InvoiceLines::class))->newInstanceWithoutConstructor();
|
||||
|
||||
// // Basic line details
|
||||
// $line->setLineId($peppolLine->ID->value);
|
||||
// $line->setQuantity((int)$peppolLine->InvoicedQuantity->amount);
|
||||
// $line->setItemPrice((float)$peppolLine->Price->PriceAmount->amount);
|
||||
// $line->setAmountExcludingVat((float)$peppolLine->LineExtensionAmount->amount);
|
||||
|
||||
// // Item details
|
||||
// $line->setName($peppolLine->Item->Name);
|
||||
// $line->setDescription($peppolLine->Item->Description);
|
||||
|
||||
// // Tax handling
|
||||
// if(isset($peppolLine->Item->ClassifiedTaxCategory) && is_array($peppolLine->Item->ClassifiedTaxCategory)){
|
||||
// foreach($peppolLine->Item->ClassifiedTaxCategory as $ctc)
|
||||
// {
|
||||
// $this->setTaxMap($ctc, $peppolLine, $invoice);
|
||||
// $tax = new Tax((float)$ctc->Percent, $this->resolveJurisdication($ctc, $invoice));
|
||||
// $line->setTax($tax);
|
||||
// }
|
||||
// }
|
||||
// Tax handling
|
||||
if(isset($peppolLine->Item->ClassifiedTaxCategory) && is_array($peppolLine->Item->ClassifiedTaxCategory)){
|
||||
foreach($peppolLine->Item->ClassifiedTaxCategory as $ctc)
|
||||
{
|
||||
$this->setTaxMap($ctc, $peppolLine, $invoice);
|
||||
}
|
||||
}
|
||||
|
||||
// //discounts
|
||||
// if(isset($peppolLine->Price->AllowanceCharge) && is_array($peppolLine->Price->AllowanceCharge)){
|
||||
@ -103,42 +90,31 @@ class StorecoveTransformer implements TransformerInterface
|
||||
|
||||
// $this->s_invoice->invoiceLines = $lines;
|
||||
|
||||
// //invoice level discounts + surcharges
|
||||
// if(isset($peppolLine->AllowanceCharge) && is_array($peppolLine->AllowanceCharge)){
|
||||
|
||||
// foreach ($peppolLine->AllowanceCharge as $allowance)
|
||||
// {
|
||||
|
||||
// $reason = $allowance->ChargeIndicator ? ctrans('texts.fee') : ctrans('texts.discount');
|
||||
// $amount = $allowance->Amount->amount;
|
||||
}
|
||||
|
||||
// $ac = new AllowanceCharges(reason: $reason, amountExcludingTax: $amount);
|
||||
// $this->s_invoice->addAllowanceCharge($ac); //todo handle surcharge taxes
|
||||
$sub_taxes = collect($this->tax_map)
|
||||
->groupBy('percentage')
|
||||
->map(function ($group) {
|
||||
|
||||
// }
|
||||
// }
|
||||
return new TaxSubtotals(
|
||||
taxable_amount: $group->sum('taxableAmount'),
|
||||
tax_amount: $group->sum('taxAmount'),
|
||||
percentage: $group->first()['percentage'],
|
||||
country: $group->first()['country'],
|
||||
category: null
|
||||
);
|
||||
|
||||
|
||||
// collect($this->tax_map)
|
||||
// ->groupBy('percentage')
|
||||
// ->each(function ($group) {
|
||||
})->toArray();
|
||||
|
||||
// $taxSubtotals = new TaxSubtotals(
|
||||
// taxableAmount: $group->sum('taxableAmount'),
|
||||
// taxAmount: $group->sum('taxAmount'),
|
||||
// percentage: $group->first()['percentage'],
|
||||
// country: $group->first()['country']
|
||||
// );
|
||||
|
||||
// $this->s_invoice->addTaxSubtotals($taxSubtotals);
|
||||
|
||||
|
||||
// });
|
||||
|
||||
$this->s_invoice->setTaxSubtotals($sub_taxes);
|
||||
|
||||
|
||||
// $this->s_invoice->setAmountIncludingVat($invoice->LegalMonetaryTotal->TaxInclusiveAmount->amount);
|
||||
// $this->s_invoice->setPrepaidAmount(0);
|
||||
|
||||
// return $this->s_invoice;
|
||||
return $this->s_invoice;
|
||||
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ class SendEDocument implements ShouldQueue
|
||||
use Queueable;
|
||||
use SerializesModels;
|
||||
|
||||
public $tries = 2;
|
||||
public $tries = 5;
|
||||
|
||||
public $deleteWhenMissingModels = true;
|
||||
|
||||
@ -42,10 +42,10 @@ class SendEDocument implements ShouldQueue
|
||||
|
||||
public function backoff()
|
||||
{
|
||||
return [rand(5, 29), rand(30, 59)];
|
||||
return [rand(5, 29), rand(30, 59), rand(240, 360), 3600, 7200];
|
||||
}
|
||||
|
||||
public function handle()
|
||||
public function handle(Storecove $storecove)
|
||||
{
|
||||
MultiDB::setDB($this->db);
|
||||
|
||||
@ -55,20 +55,21 @@ class SendEDocument implements ShouldQueue
|
||||
{
|
||||
|
||||
$p = new Peppol($model);
|
||||
|
||||
$p->run();
|
||||
$xml = $p->toXml();
|
||||
$identifiers = $p->getStorecoveMeta();
|
||||
|
||||
$payload = [
|
||||
'legal_entity_id' => $model->company->legal_entity_id,
|
||||
'document' => base64_encode($xml),
|
||||
'tenant_id' => $model->company->company_key,
|
||||
'identifiers' => $identifiers,
|
||||
'e_invoicing_token' => $model->company->e_invoicing_token,
|
||||
$result = $storecove->build($model);
|
||||
|
||||
// include whitelabel key.
|
||||
];
|
||||
// $xml = $p->toXml();
|
||||
// $identifiers = $p->getStorecoveMeta();
|
||||
|
||||
// $payload = [
|
||||
// 'legal_entity_id' => $model->company->legal_entity_id,
|
||||
// 'document' => base64_encode($xml),
|
||||
// 'tenant_id' => $model->company->company_key,
|
||||
// 'identifiers' => $identifiers,
|
||||
// // 'e_invoicing_token' => $model->company->e_invoicing_token,
|
||||
// // include whitelabel key.
|
||||
// ];
|
||||
|
||||
$r = Http::withHeaders($this->getHeaders())
|
||||
->post(config('ninja.hosted_ninja_url')."/api/einvoice/submission", $payload);
|
||||
|
@ -209,6 +209,7 @@ class Peppol extends AbstractService
|
||||
|
||||
$this->setOrderReference()->setTaxBreakdown();
|
||||
|
||||
//isolate this class to only peppol changes
|
||||
$this->p_invoice = $this->gateway
|
||||
->mutator
|
||||
->senderSpecificLevelMutators()
|
||||
|
@ -141,34 +141,34 @@ class StorecoveTest extends TestCase
|
||||
}
|
||||
|
||||
|
||||
// public function testNormalizingToStorecove()
|
||||
// {
|
||||
public function testNormalizingToStorecove()
|
||||
{
|
||||
|
||||
// $e_invoice = new \InvoiceNinja\EInvoice\Models\Peppol\Invoice();
|
||||
$e_invoice = new \InvoiceNinja\EInvoice\Models\Peppol\Invoice();
|
||||
|
||||
// $invoice = $this->createATData();
|
||||
$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;
|
||||
// }
|
||||
$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;
|
||||
$invoice->e_invoice = $e_invoice;
|
||||
|
||||
// $p = new Peppol($invoice);
|
||||
// $p->run();
|
||||
// $peppolInvoice = $p->getInvoice();
|
||||
$p = new Peppol($invoice);
|
||||
$p->run();
|
||||
$peppolInvoice = $p->getInvoice();
|
||||
|
||||
|
||||
// $s_transformer = new StorecoveTransformer();
|
||||
// $s_transformer->transform($peppolInvoice);
|
||||
$s_transformer = new StorecoveTransformer();
|
||||
$s_transformer->transform($peppolInvoice);
|
||||
|
||||
// $json = $s_transformer->toJson();
|
||||
$json = $s_transformer->toJson();
|
||||
|
||||
// $this->assertJson($json);
|
||||
$this->assertJson($json);
|
||||
|
||||
// nlog($json);
|
||||
// }
|
||||
nlog($json);
|
||||
}
|
||||
|
||||
// public function testStorecoveTransformer()
|
||||
// {
|
||||
|
Loading…
Reference in New Issue
Block a user