mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-04-03 06:44:27 -04:00
Implementation of UBL 2.1 invoice generation to comply with Belgium's 2026 Peppol mandate. Key changes: - Add num-num/ubl-invoice dependency via composer.json - Create Ubl_generator library to convert OSPOS sale data to UBL format - Create country_helper.php to map country names to ISO 3166-1 alpha-2 codes - Extend Email_lib to support multiple attachments for PDF+UBL emails - Add getUblInvoice() method in Sales controller for UBL download - Modify getSendPdf() to optionally attach UBL based on invoice_format config - Add database migration for invoice_format configuration (pdf_only/ubl_only/both) - Add UBL download button to invoice view - Add UBL download link to sales manage table - Add language keys for UBL-related UI elements Data mapping: - Company name/address -> Supplier Party - account_number -> Company VAT number - Customer address/country -> Customer Party with ISO country code - Customer tax_id -> Customer VAT number - Cart items -> InvoiceLines - Taxes -> TaxCategory and TaxTotal - Totals -> LegalMonetaryTotal Features: - Generate valid UBL 2.1 XML invoices - Download UBL from invoice view and manage table - Email with PDF, UBL, or both based on configuration - Support for multiple customer countries with ISO code mapping - Graceful handling of missing optional customer fields
103 lines
3.3 KiB
PHP
103 lines
3.3 KiB
PHP
<?php
|
|
|
|
namespace Tests\Libraries\InvoiceAttachment;
|
|
|
|
use CodeIgniter\Test\CIUnitTestCase;
|
|
use App\Libraries\InvoiceAttachment\UblAttachment;
|
|
|
|
class UblAttachmentTest extends CIUnitTestCase
|
|
{
|
|
private UblAttachment $attachment;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->attachment = new UblAttachment();
|
|
}
|
|
|
|
public function testGetFileExtensionReturnsXml(): void
|
|
{
|
|
$this->assertEquals('xml', $this->attachment->getFileExtension());
|
|
}
|
|
|
|
public function testGetEnabledConfigValuesReturnsCorrectArray(): void
|
|
{
|
|
$values = $this->attachment->getEnabledConfigValues();
|
|
|
|
$this->assertIsArray($values);
|
|
$this->assertContains('ubl_only', $values);
|
|
$this->assertContains('both', $values);
|
|
$this->assertCount(2, $values);
|
|
}
|
|
|
|
public function testIsApplicableForTypeReturnsTrueForInvoiceWithInvoiceNumber(): void
|
|
{
|
|
$saleData = ['invoice_number' => 'INV-001'];
|
|
|
|
$this->assertTrue($this->attachment->isApplicableForType('invoice', $saleData));
|
|
}
|
|
|
|
public function testIsApplicableForTypeReturnsTrueForTaxInvoiceWithInvoiceNumber(): void
|
|
{
|
|
$saleData = ['invoice_number' => 'INV-001'];
|
|
|
|
$this->assertTrue($this->attachment->isApplicableForType('tax_invoice', $saleData));
|
|
}
|
|
|
|
public function testIsApplicableForTypeReturnsFalseForInvoiceWithoutInvoiceNumber(): void
|
|
{
|
|
$saleData = ['invoice_number' => null];
|
|
|
|
$this->assertFalse($this->attachment->isApplicableForType('invoice', $saleData));
|
|
}
|
|
|
|
public function testIsApplicableForTypeReturnsFalseForInvoiceWithEmptyInvoiceNumber(): void
|
|
{
|
|
$saleData = ['invoice_number' => ''];
|
|
|
|
$this->assertFalse($this->attachment->isApplicableForType('invoice', $saleData));
|
|
}
|
|
|
|
public function testIsApplicableForTypeReturnsFalseForInvoiceWithoutInvoiceNumberKey(): void
|
|
{
|
|
$saleData = [];
|
|
|
|
$this->assertFalse($this->attachment->isApplicableForType('invoice', $saleData));
|
|
}
|
|
|
|
public function testIsApplicableForTypeReturnsFalseForQuoteEvenWithInvoiceNumber(): void
|
|
{
|
|
$saleData = ['invoice_number' => 'INV-001'];
|
|
|
|
$this->assertFalse($this->attachment->isApplicableForType('quote', $saleData));
|
|
}
|
|
|
|
public function testIsApplicableForTypeReturnsFalseForWorkOrderEvenWithInvoiceNumber(): void
|
|
{
|
|
$saleData = ['invoice_number' => 'INV-001'];
|
|
|
|
$this->assertFalse($this->attachment->isApplicableForType('work_order', $saleData));
|
|
}
|
|
|
|
public function testIsApplicableForTypeReturnsFalseForReceiptEvenWithInvoiceNumber(): void
|
|
{
|
|
$saleData = ['invoice_number' => 'INV-001'];
|
|
|
|
$this->assertFalse($this->attachment->isApplicableForType('receipt', $saleData));
|
|
}
|
|
|
|
public function testIsApplicableForTypeReturnsFalseForUnknownType(): void
|
|
{
|
|
$saleData = ['invoice_number' => 'INV-001'];
|
|
|
|
$this->assertFalse($this->attachment->isApplicableForType('unknown_type', $saleData));
|
|
}
|
|
|
|
public function testGenerateReturnsNullForMissingConfig(): void
|
|
{
|
|
// Without proper sale_data, generate should fail gracefully
|
|
$result = $this->attachment->generate([], 'invoice');
|
|
|
|
$this->assertNull($result);
|
|
}
|
|
} |