1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-08 12:12:48 +01:00

Fixes for tests

This commit is contained in:
David Bomba 2024-11-05 20:42:48 +11:00
parent d93ac9ae59
commit d2e3998467
10 changed files with 75 additions and 288 deletions

View File

@ -373,7 +373,12 @@ class BaseRule implements RuleInterface
default => $this->defaultForeign(),
};
return $this;
}
$this->taxByType($item);
return $this;
}

View File

@ -472,8 +472,6 @@ class InvoiceItemSum
$amount = $this->item->line_total;
}
//$amount = ($this->sub_total > 0) ? $this->item->line_total - ($this->invoice->discount * ($this->item->line_total / $this->sub_total)) : 0;
$item_tax_rate1_total = $this->calcAmountLineTax($this->item->tax_rate1, $amount);
$item_tax += $item_tax_rate1_total;

View File

@ -276,7 +276,7 @@ class InvoiceItemSumInclusive
$key = str_replace(' ', '', $tax_name.$tax_rate);
$group_tax = ['key' => $key, 'total' => $tax_total, 'tax_name' => $tax_name.' '.Number::formatValueNoTrailingZeroes(floatval($tax_rate), $this->client).'%', 'tax_id' => $tax_id, 'base_amoount' => $amount];
$group_tax = ['key' => $key, 'total' => $tax_total, 'tax_name' => $tax_name.' '.Number::formatValueNoTrailingZeroes(floatval($tax_rate), $this->client).'%', 'tax_id' => $tax_id, 'base_amount' => $amount];
$this->tax_collection->push(collect($group_tax));
}

View File

@ -367,7 +367,7 @@ class InvoiceSum
$tax_id = $values->first()['tax_id'] ?? '';
$this->tax_map[] = ['name' => $tax_name, 'total' => $total_line_tax, 'tax_id' => $tax_id, 'tax_rate' => $tax_rate, 'base_amount' => $base_amount];
$this->tax_map[] = ['name' => $tax_name, 'total' => $total_line_tax, 'tax_id' => $tax_id, 'tax_rate' => $tax_rate, 'base_amount' => round($base_amount,2)];
$this->total_taxes += $total_line_tax;
}

View File

@ -391,7 +391,7 @@ class InvoiceSumInclusive
$tax_id = $values->first()['tax_id'] ?? '';
$this->tax_map[] = ['name' => $tax_name, 'total' => $total_line_tax, 'tax_id' => $tax_id, 'tax_rate' => $tax_rate, 'base_amount' => $base_amount];
$this->tax_map[] = ['name' => $tax_name, 'total' => $total_line_tax, 'tax_id' => $tax_id, 'tax_rate' => $tax_rate, 'base_amount' => round($base_amount,2)];
$this->total_taxes += $total_line_tax;

View File

@ -154,6 +154,11 @@ class CompanyPresenter extends EntityPresenter
}
}
public function phone()
{
return $this->entity->settings->phone ?? ' ';
}
public function address1()
{
return $this->entity->settings->address1;

View File

@ -153,7 +153,7 @@ class Storecove
*/
public function sendJsonDocument(array $payload)
{
nlog($payload);
$uri = "document_submissions";
$r = $this->httpClient($uri, (HttpVerb::POST)->value, $payload, $this->getHeaders());
@ -163,6 +163,7 @@ class Storecove
return $r->json()['guid'];
}
nlog($payload);
nlog($r->body());
return false;

View File

@ -562,7 +562,6 @@ class Peppol extends AbstractService
$tea = new TaxExclusiveAmount();
$tea->currencyID = $this->invoice->client->currency()->code;
// $tea->amount = $this->invoice->uses_inclusive_taxes ? round($this->invoice->amount - $this->invoice->total_taxes, 2) : $taxable;
$tea->amount = round($this->invoice->amount - $this->invoice->total_taxes, 2);
$lmt->TaxExclusiveAmount = $tea;
@ -866,24 +865,6 @@ class Peppol extends AbstractService
return $lines;
}
// /**
// * calculateDiscountAmount
// *
// * Helper method to determine the discount amount to be used.
// *
// * @param mixed $item
// * @return float
// */
// private function calculateDiscountAmount($item): float
// {
// if ($item->is_amount_discount) {
// return $item->discount / $item->quantity; // Per unit discount amount
// }
// return ($item->cost / $item->quantity) * ($item->discount / 100);
// }
private function calculateTotalItemDiscountAmount($item):float
{
@ -895,29 +876,6 @@ class Peppol extends AbstractService
}
// /**
// * costWithDiscount
// *
// * Helper method to determine the cost INCLUDING discount
// *
// * @param mixed $item
// * @return float
// */
// private function costWithDiscount($item): float
// {
// $cost = $item->cost;
// if ($item->discount != 0) {
// if ($this->invoice->is_amount_discount) {
// $cost -= $item->discount / $item->quantity;
// } else {
// $cost -= $cost * $item->discount / 100;
// }
// }
// return $cost;
// }
/**
* calculateTaxMap
*
@ -987,169 +945,7 @@ class Peppol extends AbstractService
return $this;
}
/**
* getItemTaxes
*
* Builds a tax map for later use when
* collating taxes
*
* @param object $item
* @return array
// */
// private function getItemTaxes(object $item): array
// {
// $item_taxes = [];
// $adjusted_base_amount = $this->calculateAdjustedBaseAmount($item);
// // if(strlen($item->tax_name1 ?? '') > 1) {
// $tax_amount = new TaxAmount();
// $tax_amount->currencyID = $this->invoice->client->currency()->code;
// $tax_amount->amount = $this->invoice->uses_inclusive_taxes ? $this->calcInclusiveLineTax($item->tax_rate1, $adjusted_base_amount) : $this->calcAmountLineTax($item->tax_rate1, $adjusted_base_amount);
// $tax_subtotal = new TaxSubtotal();
// $tax_subtotal->TaxAmount = $tax_amount;
// $taxable_amount = new TaxableAmount();
// $taxable_amount->currencyID = $this->invoice->client->currency()->code;
// $taxable_amount->amount = $this->invoice->uses_inclusive_taxes ? $adjusted_base_amount - $tax_amount->amount : $adjusted_base_amount;
// $tax_subtotal->TaxableAmount = $taxable_amount;
// $tc = new TaxCategory();
// $id = new ID();
// $id->value = $this->getTaxType($item->tax_id);
// if(floatval($item->tax_rate1) === 0.0)
// $id->value = $this->resolveTaxExemptReason($item);
// $tc->ID = $id;
// $tc->Percent = (string)$item->tax_rate1;
// $ts = new TaxScheme();
// $id = new ID();
// $id->value = $this->standardizeTaxSchemeId($item->tax_name1);
// $jurisdiction = $this->getJurisdiction();
// $ts->JurisdictionRegionAddress[] = $jurisdiction;
// $ts->ID = $id;
// $tc->TaxScheme = $ts;
// $tax_subtotal->TaxCategory = $tc;
// $tax_total = new TaxTotal();
// $tax_total->TaxAmount = $tax_amount;
// $tax_total->TaxSubtotal[] = $tax_subtotal;
// $this->tax_map[] = [
// 'taxableAmount' => $taxable_amount->amount,
// 'taxAmount' => $tax_amount->amount,
// 'percentage' => $item->tax_rate1,
// ];
// $item_taxes[] = $tax_total;
// // }
// if(strlen($item->tax_name2 ?? '') > 1) {
// $tax_amount = new TaxAmount();
// $tax_amount->currencyID = $this->invoice->client->currency()->code;
// $tax_amount->amount = $this->invoice->uses_inclusive_taxes ? $this->calcInclusiveLineTax($item->tax_rate2, $item->line_total) : $this->calcAmountLineTax($item->tax_rate2, $item->line_total);
// $tax_subtotal = new TaxSubtotal();
// $tax_subtotal->TaxAmount = $tax_amount;
// $taxable_amount = new TaxableAmount();
// $taxable_amount->currencyID = $this->invoice->client->currency()->code;
// $taxable_amount->amount = $item->line_total;
// $tax_subtotal->TaxableAmount = $taxable_amount;
// $tc = new TaxCategory();
// $id = new ID();
// $id->value = $this->getTaxType($item->tax_id);
// $tc->ID = $id;
// $tc->Percent = (string)$item->tax_rate2;
// $ts = new TaxScheme();
// $id = new ID();
// $id->value = $this->standardizeTaxSchemeId($item->tax_name2);
// $jurisdiction = $this->getJurisdiction();
// $ts->JurisdictionRegionAddress[] = $jurisdiction;
// $ts->ID = $id;
// $tc->TaxScheme = $ts;
// $tax_subtotal->TaxCategory = $tc;
// $tax_total = new TaxTotal();
// $tax_total->TaxAmount = $tax_amount;
// $tax_total->TaxSubtotal[] = $tax_subtotal;
// $this->tax_map[] = [
// 'taxableAmount' => $taxable_amount->amount,
// 'taxAmount' => $tax_amount->amount,
// 'percentage' => $item->tax_rate2,
// ];
// $item_taxes[] = $tax_total;
// }
// if(strlen($item->tax_name3 ?? '') > 1) {
// $tax_amount = new TaxAmount();
// $tax_amount->currencyID = $this->invoice->client->currency()->code;
// $tax_amount->amount = $this->invoice->uses_inclusive_taxes ? $this->calcInclusiveLineTax($item->tax_rate3, $item->line_total) : $this->calcAmountLineTax($item->tax_rate3, $item->line_total);
// $tax_subtotal = new TaxSubtotal();
// $tax_subtotal->TaxAmount = $tax_amount;
// $taxable_amount = new TaxableAmount();
// $taxable_amount->currencyID = $this->invoice->client->currency()->code;
// $taxable_amount->amount = $item->line_total;
// $tax_subtotal->TaxableAmount = $taxable_amount;
// $tc = new TaxCategory();
// $id = new ID();
// $id->value = $this->getTaxType($item->tax_id);
// $tc->ID = $id;
// $tc->Percent = (string)$item->tax_rate3;
// $ts = new TaxScheme();
// $id = new ID();
// $id->value = $this->standardizeTaxSchemeId($item->tax_name3);
// $jurisdiction = $this->getJurisdiction();
// $ts->JurisdictionRegionAddress[] = $jurisdiction;
// $ts->ID = $id;
// $tc->TaxScheme = $ts;
// $tax_subtotal->TaxCategory = $tc;
// $tax_total = new TaxTotal();
// $tax_total->TaxAmount = $tax_amount;
// $tax_total->TaxSubtotal[] = $tax_subtotal;
// $this->tax_map[] = [
// 'taxableAmount' => $taxable_amount->amount,
// 'taxAmount' => $tax_amount->amount,
// 'percentage' => $item->tax_rate3,
// ];
// $item_taxes[] = $tax_total;
// }
// return $item_taxes;
// }
/**
* getAccountingSupplierParty
@ -1483,7 +1279,9 @@ class Peppol extends AbstractService
// Required: TaxableAmount (BT-116)
$taxable_amount = new TaxableAmount();
$taxable_amount->currencyID = $this->invoice->client->currency()->code;
$taxable_amount->amount = (string)round($this->invoice->amount - $this->invoice->total_taxes, 2);
$taxable_amount->amount = (string)round($this->invoice->amount,2);
nlog("0 tax taxable amount = ".$taxable_amount->amount);
$tax_subtotal->TaxableAmount = $taxable_amount;
@ -1503,11 +1301,6 @@ class Peppol extends AbstractService
$tax_category->ID = $category_id;
// Required: TaxCategory Rate (BT-119)
// if ($grouped_tax['tax_rate'] > 0) {
// $tax_category->Percent = (string)$grouped_tax['tax_rate'];
// }
// Required: TaxScheme (BG-23)
$tax_scheme = new TaxScheme();
$scheme_id = new ID();
@ -1516,7 +1309,6 @@ class Peppol extends AbstractService
$tax_category->TaxScheme = $tax_scheme;
$tax_subtotal->TaxCategory = $this->globalTaxCategories[0];
// $tax_subtotal->TaxCategory = $tax_category;
$tax_total->TaxSubtotal[] = $tax_subtotal;
@ -1526,7 +1318,7 @@ class Peppol extends AbstractService
}
foreach($taxes as $grouped_tax)
foreach($taxes as $key => $grouped_tax)
{
// Required: TaxAmount (BT-110)
$tax_amount = new TaxAmount();
@ -1541,8 +1333,10 @@ class Peppol extends AbstractService
$taxable_amount = new TaxableAmount();
$taxable_amount->currencyID = $this->invoice->client->currency()->code;
$taxable_amount->amount = (string)round($grouped_tax['base_amount'],2);
if(floatval($grouped_tax['total']) === 0.0)
$taxable_amount->amount = (string)round($this->invoice->amount, 2);
else
$taxable_amount->amount = (string)round($grouped_tax['base_amount'],2);
$tax_subtotal->TaxableAmount = $taxable_amount;
// Required: TaxAmount (BT-117)
@ -1658,61 +1452,4 @@ class Peppol extends AbstractService
return '0037';
}
/**
* calculateAdjustedBaseAmount
*
* Calculates the adjusted base amount for a line item considering invoice-level discounts
*
*/
private function calculateAdjustedBaseAmount(object $line_item)
{
$precision = $this->invoice->client->currency()->precision;
// 1. First calculate the raw line total
$line_total = round($line_item->quantity * $line_item->cost, $precision);
// 2. Apply line-level discount if any
if ($line_item->discount > 0) {
if ($line_item->is_amount_discount) {
$line_total = round($line_total - $line_item->discount, $precision);
} else {
$line_total = round($line_total * (1 - $line_item->discount / 100), $precision);
}
}
// 3. If no invoice-level discount, return now
if ($this->invoice->discount <= 0) {
return (string)$line_total;
}
// 4. Calculate total of all line items after their individual discounts
$invoice_subtotal = 0;
foreach ($this->invoice->line_items as $item) {
$item_total = round($item->quantity * $item->cost, $precision);
if ($item->discount > 0) {
if ($item->is_amount_discount) {
$item_total = round($item_total - $item->discount, $precision);
} else {
$item_total = round($item_total * (1 - $item->discount / 100), $precision);
}
}
$invoice_subtotal = round($invoice_subtotal + $item_total, $precision);
}
// 5. Calculate this line's portion of the invoice discount
if ($invoice_subtotal > 0) {
if ($this->invoice->is_amount_discount) {
$discount_portion = round(($line_total / $invoice_subtotal) * $this->invoice->discount, $precision);
} else {
$discount_portion = round($line_total * ($this->invoice->discount / 100), $precision);
}
$line_total = round($line_total - $discount_portion, $precision);
}
return (string)$line_total;
}
}

View File

@ -65,11 +65,13 @@ class ZugferdEDokument extends AbstractService
$this->xdocument = ZugferdDocumentBuilder::CreateNew($profile);
$user_or_company_phone = strlen($this->document->user->present()->phone()) > 3 ? $this->document->user->present()->phone() : $company->present()->phone;
$this->xdocument
->setDocumentSupplyChainEvent(date_create($this->document->date ?? now()->format('Y-m-d')))
->setDocumentSeller($company->getSetting('name'))
->setDocumentSellerAddress($company->getSetting("address1"), $company->getSetting("address2"), "", $company->getSetting("postal_code"), $company->getSetting("city"), $company->country()->iso_3166_2, $company->getSetting("state"))
->setDocumentSellerContact($this->document->user->present()->getFullName(), "", $this->document->user->present()->phone(), "", $this->document->user->email)
->setDocumentSellerContact($this->document->user->present()->getFullName(), "", $user_or_company_phone, "", $this->document->user->email)
->setDocumentSellerCommunication("EM", $this->document->user->email)
->setDocumentBuyer($client->present()->name(), $client->number)
->setDocumentBuyerAddress($client->address1, "", "", $client->postal_code, $client->city, $client->country->iso_3166_2, $client->state)

View File

@ -38,23 +38,19 @@ use InvoiceNinja\EInvoice\Models\Peppol\FinancialAccountType\PayeeFinancialAccou
use InvoiceNinja\EInvoice\Models\FatturaPA\FatturaElettronicaBodyType\FatturaElettronicaBody;
use InvoiceNinja\EInvoice\Models\FatturaPA\FatturaElettronicaHeaderType\FatturaElettronicaHeader;
/**
*
*/
class PeppolTest extends TestCase
{
use DatabaseTransactions;
use MockAccountData;
protected int $iterations = 1000;
protected function setUp(): void
{
parent::setUp();
$this->makeTestData();
// $this->markTestSkipped('prevent running in CI');
$this->withoutMiddleware(
ThrottleRequests::class
);
@ -145,6 +141,7 @@ class PeppolTest extends TestCase
]);
$items = $invoice->line_items;
foreach($items as &$item)
{
$item->tax_name2 = '';
@ -164,7 +161,6 @@ class PeppolTest extends TestCase
public function testWithChaosMonkey()
{
$scenarios = [
[
'company_vat' => 'DE923356489',
@ -268,8 +264,7 @@ class PeppolTest extends TestCase
$this->assertCount(0, $validator->getErrors());
}
for($x=0; $x<1000; $x++){
for($x=0; $x< $this->iterations; $x++){
$scenario = $scenarios[0];
@ -293,6 +288,10 @@ class PeppolTest extends TestCase
if (count($validator->getErrors()) > 0) {
nlog("index {$x}");
nlog($invoice->calc()->getTotalTaxes());
nlog($invoice->calc()->getTotal());
nlog($invoice->calc()->getSubtotal());
nlog($invoice->calc()->getTaxMap());
nlog($invoice->withoutRelations()->toArray());
nlog($p->toXml());
nlog($validator->getErrors());
@ -302,6 +301,46 @@ class PeppolTest extends TestCase
}
for ($x = 0; $x < $this->iterations; $x++) {
$scenario = end($scenarios);
$data = $this->setupTestData($scenario);
$invoice = $data['invoice'];
$invoice = $invoice->calc()->getInvoice();
$storecove = new Storecove();
$p = new Peppol($invoice);
$p->run();
try {
$processor = new \Saxon\SaxonProcessor();
} catch (\Throwable $e) {
$this->markTestSkipped('saxon not installed');
}
$validator = new \App\Services\EDocument\Standards\Validation\XsltDocumentValidator($p->toXml());
$validator->validate();
if (count($validator->getErrors()) > 0) {
nlog("De-De tax");
nlog("index {$x}");
nlog($invoice->calc()->getTotalTaxes());
nlog($invoice->calc()->getTotal());
nlog($invoice->calc()->getSubtotal());
nlog($invoice->calc()->getTaxMap());
nlog($invoice->withoutRelations()->toArray());
nlog($p->toXml());
nlog($validator->getErrors());
}
$this->assertCount(0, $validator->getErrors());
}
}