Skip to content

Commit

Permalink
tweak(Sales UBL) add mor ubl allowance tests
Browse files Browse the repository at this point in the history
  • Loading branch information
paulmhh committed Dec 2, 2024
1 parent 173f418 commit fd74296
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 69 deletions.
174 changes: 151 additions & 23 deletions tests/tine20/Sales/Document/UblTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,42 +18,170 @@
class Sales_Document_UblTest extends Sales_Document_Abstract
{

public function testA(): void
protected function _createInvoice(array $positions, array $invoiceData = []): SMDI
{
$customer = $this->_createCustomer();
$product1 = $this->_createProduct();

/** @var SMDI $invoice */
$invoice = Sales_Controller_Document_Invoice::getInstance()->create(new SMDI([
$invoice = Sales_Controller_Document_Invoice::getInstance()->create(new SMDI(array_merge([
SMDI::FLD_CUSTOMER_ID => $customer,
SMDI::FLD_PAYMENT_TERMS => 10,
SMDI::FLD_INVOICE_STATUS => SMDI::STATUS_PROFORMA,
SMDI::FLD_DOCUMENT_DATE => Tinebase_DateTime::now(),
SMDI::FLD_BUYER_REFERENCE => 'buy ref',
SMDI::FLD_RECIPIENT_ID => $customer->{Sales_Model_Customer::FLD_DEBITORS}->getFirstRecord()->{Sales_Model_Debitor::FLD_BILLING}->getFirstRecord(),
SMDI::FLD_POSITIONS => [
new SMDPI([
SMDPI::FLD_TITLE => 'pos 1',
SMDPI::FLD_PRODUCT_ID => $product1->getId(),
SMDPI::FLD_QUANTITY => 1,
SMDPI::FLD_UNIT_PRICE => 1,
SMDPI::FLD_UNIT_PRICE_TYPE => Sales_Config::PRICE_TYPE_NET,
SMDPI::FLD_POSITION_DISCOUNT_TYPE => Sales_Config::INVOICE_DISCOUNT_SUM,
SMDPI::FLD_POSITION_DISCOUNT_SUM => 0.01
], true),
new SMDPI([
SMDPI::FLD_TITLE => 'pos 2',
SMDPI::FLD_PRODUCT_ID => $product1->getId(),
SMDPI::FLD_QUANTITY => 1,
SMDPI::FLD_UNIT_PRICE => 5,
SMDPI::FLD_UNIT_PRICE_TYPE => Sales_Config::PRICE_TYPE_NET,
], true)
],
]));
SMDI::FLD_POSITIONS => $positions,
], $invoiceData)));

return $invoice;
}

protected function _assertUblXml(SMDI $invoice, float $taxExclValue, float $taxInclValue): void
{
$this->assertNotNull($node = $invoice->attachments->find(fn(Tinebase_Model_Tree_Node $attachment) => str_ends_with($attachment->name, '-xrechnung.xml'), null));
//echo file_get_contents('tine20://' . Tinebase_FileSystem::getInstance()->getPathOfNode($node, true));
$xml = new SimpleXMLElement(file_get_contents('tine20://' . Tinebase_FileSystem::getInstance()->getPathOfNode($node, true)));
$xml->registerXPathNamespace('ubl', 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2');
$xml->registerXPathNamespace('cbc', 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2');
$xml->registerXPathNamespace('cac', 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2');
$this->assertIsArray($taxExclAmount = $xml->xpath('/ubl:Invoice/cac:LegalMonetaryTotal/cbc:TaxExclusiveAmount'));
$this->assertSame($taxExclValue, (float)$taxExclAmount[0]);
$this->assertIsArray($taxInclAmount = $xml->xpath('/ubl:Invoice/cac:LegalMonetaryTotal/cbc:TaxInclusiveAmount'));
$this->assertSame($taxInclValue, (float)$taxInclAmount[0]);
}

public function testPositionNetDiscount(): void
{
$product1 = $this->_createProduct();

$positions = [
new SMDPI([
SMDPI::FLD_TITLE => 'pos 1',
SMDPI::FLD_PRODUCT_ID => $product1->getId(),
SMDPI::FLD_QUANTITY => 1,
SMDPI::FLD_UNIT_PRICE => 1,
SMDPI::FLD_UNIT_PRICE_TYPE => Sales_Config::PRICE_TYPE_NET,
SMDPI::FLD_POSITION_DISCOUNT_TYPE => Sales_Config::INVOICE_DISCOUNT_SUM,
SMDPI::FLD_POSITION_DISCOUNT_SUM => 0.01
], true),
new SMDPI([
SMDPI::FLD_TITLE => 'pos 2',
SMDPI::FLD_PRODUCT_ID => $product1->getId(),
SMDPI::FLD_QUANTITY => 1,
SMDPI::FLD_UNIT_PRICE => 5,
SMDPI::FLD_UNIT_PRICE_TYPE => Sales_Config::PRICE_TYPE_NET,
SMDPI::FLD_POSITION_DISCOUNT_TYPE => Sales_Config::INVOICE_DISCOUNT_SUM,
SMDPI::FLD_POSITION_DISCOUNT_SUM => 0.1
], true)
];
$invoice = $this->_createInvoice($positions);
$invoice->{SMDI::FLD_INVOICE_STATUS} = SMDI::STATUS_BOOKED;
/** @var SMDI $invoice */
$invoice = Sales_Controller_Document_Invoice::getInstance()->update($invoice);
$this->_assertUblXml($invoice, 5.89, round(5.89 * (1 + Tinebase_Config::getInstance()->{Tinebase_Config::SALES_TAX} / 100), 2));
}

public function testPositionGrossDiscount(): void
{
$product1 = $this->_createProduct();

$invoice->toUbl();
$positions = [
new SMDPI([
SMDPI::FLD_TITLE => 'pos 1',
SMDPI::FLD_PRODUCT_ID => $product1->getId(),
SMDPI::FLD_QUANTITY => 1,
SMDPI::FLD_UNIT_PRICE => 1,
SMDPI::FLD_UNIT_PRICE_TYPE => Sales_Config::PRICE_TYPE_GROSS,
SMDPI::FLD_POSITION_DISCOUNT_TYPE => Sales_Config::INVOICE_DISCOUNT_SUM,
SMDPI::FLD_POSITION_DISCOUNT_SUM => 0.01
], true),
new SMDPI([
SMDPI::FLD_TITLE => 'pos 2',
SMDPI::FLD_PRODUCT_ID => $product1->getId(),
SMDPI::FLD_QUANTITY => 1,
SMDPI::FLD_UNIT_PRICE => 5,
SMDPI::FLD_UNIT_PRICE_TYPE => Sales_Config::PRICE_TYPE_GROSS,
SMDPI::FLD_POSITION_DISCOUNT_TYPE => Sales_Config::INVOICE_DISCOUNT_SUM,
SMDPI::FLD_POSITION_DISCOUNT_SUM => 0.1
], true)
];
$invoice = $this->_createInvoice($positions);
$invoice->{SMDI::FLD_INVOICE_STATUS} = SMDI::STATUS_BOOKED;
/** @var SMDI $invoice */
$invoice = Sales_Controller_Document_Invoice::getInstance()->update($invoice);
$this->_assertUblXml($invoice, round(5.89/(1 + Tinebase_Config::getInstance()->{Tinebase_Config::SALES_TAX} / 100), 2), 5.89);
}

public function testPositionGrossDiscountDocumentDiscount(): void
{
$product1 = $this->_createProduct();

$positions = [
new SMDPI([
SMDPI::FLD_TITLE => 'pos 1',
SMDPI::FLD_PRODUCT_ID => $product1->getId(),
SMDPI::FLD_QUANTITY => 1,
SMDPI::FLD_UNIT_PRICE => 1,
SMDPI::FLD_UNIT_PRICE_TYPE => Sales_Config::PRICE_TYPE_GROSS,
SMDPI::FLD_POSITION_DISCOUNT_TYPE => Sales_Config::INVOICE_DISCOUNT_SUM,
SMDPI::FLD_POSITION_DISCOUNT_SUM => 0.01
], true),
new SMDPI([
SMDPI::FLD_TITLE => 'pos 2',
SMDPI::FLD_PRODUCT_ID => $product1->getId(),
SMDPI::FLD_QUANTITY => 1,
SMDPI::FLD_UNIT_PRICE => 5,
SMDPI::FLD_UNIT_PRICE_TYPE => Sales_Config::PRICE_TYPE_GROSS,
SMDPI::FLD_POSITION_DISCOUNT_TYPE => Sales_Config::INVOICE_DISCOUNT_SUM,
SMDPI::FLD_POSITION_DISCOUNT_SUM => 0.01
], true)
];
$invoice = $this->_createInvoice($positions, [
SMDI::FLD_INVOICE_DISCOUNT_TYPE => Sales_Config::INVOICE_DISCOUNT_SUM,
SMDI::FLD_INVOICE_DISCOUNT_SUM => 0.01
]);
$invoice->{SMDI::FLD_INVOICE_STATUS} = SMDI::STATUS_BOOKED;
/** @var SMDI $invoice */
$invoice = Sales_Controller_Document_Invoice::getInstance()->update($invoice);
$this->_assertUblXml($invoice, round(5.97/(1 + Tinebase_Config::getInstance()->{Tinebase_Config::SALES_TAX} / 100)-0.01, 2), 5.97);
}

public function testPositionGrossDifferentTaxRates(): void
{
$product1 = $this->_createProduct();

$positions = [
new SMDPI([
SMDPI::FLD_TITLE => 'pos 1',
SMDPI::FLD_PRODUCT_ID => $product1->getId(),
SMDPI::FLD_QUANTITY => 1,
SMDPI::FLD_UNIT_PRICE => 10,
SMDPI::FLD_UNIT_PRICE_TYPE => Sales_Config::PRICE_TYPE_GROSS,
SMDPI::FLD_POSITION_DISCOUNT_TYPE => Sales_Config::INVOICE_DISCOUNT_SUM,
SMDPI::FLD_POSITION_DISCOUNT_SUM => 1.01
], true),
new SMDPI([
SMDPI::FLD_TITLE => 'pos 2',
SMDPI::FLD_PRODUCT_ID => $product1->getId(),
SMDPI::FLD_QUANTITY => 1,
SMDPI::FLD_UNIT_PRICE => 5,
SMDPI::FLD_UNIT_PRICE_TYPE => Sales_Config::PRICE_TYPE_GROSS,
SMDPI::FLD_POSITION_DISCOUNT_TYPE => Sales_Config::INVOICE_DISCOUNT_SUM,
SMDPI::FLD_POSITION_DISCOUNT_SUM => 0.5,
SMDPI::FLD_SALES_TAX_RATE => 7.0,
SMDPI::FLD_SALES_TAX => 4.5 - round(4.5/1.07, 2),
], true)
];
$invoice = $this->_createInvoice($positions, [
SMDI::FLD_INVOICE_DISCOUNT_TYPE => Sales_Config::INVOICE_DISCOUNT_SUM,
SMDI::FLD_INVOICE_DISCOUNT_SUM => 0.01
]);
$invoice->{SMDI::FLD_INVOICE_STATUS} = SMDI::STATUS_BOOKED;
/** @var SMDI $invoice */
$invoice = Sales_Controller_Document_Invoice::getInstance()->update($invoice);
$this->_assertUblXml($invoice,
round(8.99/(1 + Tinebase_Config::getInstance()->{Tinebase_Config::SALES_TAX} / 100), 2)
+ round(4.5/1.07, 2) - 0.01
, 13.48);
}
}
4 changes: 2 additions & 2 deletions tine20/Sales/Model/Document/Abstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -742,8 +742,8 @@ public function calculatePricesIncludingPositions()
{
/** @var Sales_Model_DocumentPosition_Abstract $position */
foreach ($this->{self::FLD_POSITIONS} ?? [] as $position) {
if ($this->{self::FLD_VAT_PROCEDURE} !== Sales_Config::VAT_PROCEDURE_TAXABLE
&& $position->{Sales_Model_DocumentPosition_Abstract::FLD_SALES_TAX_RATE}) {
if ($this->{self::FLD_VAT_PROCEDURE} && $this->{self::FLD_VAT_PROCEDURE} !== Sales_Config::VAT_PROCEDURE_TAXABLE
&& $position->{Sales_Model_DocumentPosition_Abstract::FLD_SALES_TAX_RATE}) {
$position->{Sales_Model_DocumentPosition_Abstract::FLD_SALES_TAX_RATE} = 0;
}
$position->computePrice();
Expand Down
Loading

0 comments on commit fd74296

Please sign in to comment.