Files
opensourcepos/app/Libraries/Email_lib.php
jekkos e6b288c291 Add Peppol (UBL) invoice support for Phase 1
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
2026-04-02 19:57:20 +02:00

119 lines
3.3 KiB
PHP

<?php
namespace app\Libraries;
use CodeIgniter\Email\Email;
use CodeIgniter\Encryption\Encryption;
use CodeIgniter\Encryption\EncrypterInterface;
use CodeIgniter\Encryption\Exceptions\EncryptionException;
use Config\OSPOS;
use Config\Services;
/**
* Email library
*
* Library with utilities to configure and send emails
*/
class Email_lib
{
private Email $email;
private array $config;
public function __construct()
{
$this->email = new Email();
$this->config = config(OSPOS::class)->settings;
$encrypter = Services::encrypter();
$smtp_pass = $this->config['smtp_pass'];
if (!empty($smtp_pass) && check_encryption()) {
try {
$smtp_pass = $encrypter->decrypt($smtp_pass);
} catch (\EncryptionException $e) {
// Decryption failed, use the original value
log_message('error', 'SMTP password decryption failed: ' . $e->getMessage());
$smtp_pass = '';
}
}
$email_config = [
'mailType' => 'html',
'userAgent' => 'OSPOS',
'validate' => true,
'protocol' => $this->config['protocol'],
'mailPath' => $this->config['mailpath'],
'SMTPHost' => $this->config['smtp_host'],
'SMTPUser' => $this->config['smtp_user'],
'SMTPPass' => $smtp_pass,
'SMTPPort' => (int)$this->config['smtp_port'],
'SMTPTimeout' => (int)$this->config['smtp_timeout'],
'SMTPCrypto' => $this->config['smtp_crypto']
];
$this->email->initialize($email_config);
}
/**
* Email sending function
* Example of use: $response = sendEmail('john@doe.com', 'Hello', 'This is a message', $filename);
*/
public function sendEmail(string $to, string $subject, string $message, ?string $attachment = null): bool
{
$email = $this->email;
$email->setFrom($this->config['email'], $this->config['company']);
$email->setTo($to);
$email->setSubject($subject);
$email->setMessage($message);
if (!empty($attachment)) {
$email->attach($attachment);
$email->setAttachmentCID($attachment);
}
$result = $email->send();
if (!$result) {
log_message('error', $email->printDebugger());
}
return $result;
}
/**
* Send email with multiple attachments
*
* @param string $to
* @param string $subject
* @param string $message
* @param array $attachments
* @return bool
*/
public function sendMultipleAttachments(string $to, string $subject, string $message, array $attachments): bool
{
$email = $this->email;
$email->setFrom($this->config['email'], $this->config['company']);
$email->setTo($to);
$email->setSubject($subject);
$email->setMessage($message);
foreach ($attachments as $attachment) {
if (!empty($attachment) && file_exists($attachment)) {
$email->attach($attachment);
}
}
$result = $email->send();
if (!$result) {
log_message('error', $email->printDebugger());
}
return $result;
}
}