first commit

This commit is contained in:
2026-03-05 13:07:40 +01:00
commit 64ba0721ee
25709 changed files with 4691006 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
<?php
namespace WPO\WC\UBL\Handlers;
use WPO\WC\UBL\Documents\Document;
use WPO\WC\UBL\Models\Order;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
abstract class Handler {
/** @var Document */
public $document;
public function __construct( Document $document ) {
$this->document = $document;
}
abstract public function handle( $data, $options = array() );
}

View File

@@ -0,0 +1,47 @@
<?php
namespace WPO\WC\UBL\Handlers\Ubl;
use WPO\WC\UBL\Handlers\UblHandler;
use WPO\WC\UBL\Models\Order;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class AdditionalDocumentReferenceHandler extends UblHandler {
public function handle( $data, $options = array() ) {
if ( $this->document->order_document && $this->document->order_document->exists() && $this->document->order_document->get_setting( 'include_encrypted_pdf', false, 'ubl' ) ) {
$additionalDocumentReference = array(
'name' => 'cac:AdditionalDocumentReference',
'value' => array(
array(
'name' => 'cbc:ID',
'value' => ! empty( $this->document->order_document->get_number() ) ? $this->document->order_document->get_number()->get_formatted() : '',
),
array(
'name' => 'cbc:DocumentType',
'value' => ! empty( $this->document->order_document->get_title() ) ? 'PDF '.$this->document->order_document->get_title() : '',
),
array(
'name' => 'cac:Attachment',
'value' => array(
'name' => 'cbc:EmbeddedDocumentBinaryObject',
'value' => ! empty( $this->document->order_document->get_pdf() ) ? base64_encode( $this->document->order_document->get_pdf() ) : '',
'attributes' => array(
'mimeCode' => 'application/pdf',
'filename' => ! empty( $this->document->order_document->get_filename() ) ? $this->document->order_document->get_filename() : '',
),
),
),
),
);
$data[] = apply_filters( 'wpo_wc_ubl_handle_AdditionalDocumentReference', $additionalDocumentReference, $data, $options, $this );
}
return $data;
}
}

View File

@@ -0,0 +1,282 @@
<?php
namespace WPO\WC\UBL\Handlers\Ubl;
use WPO\WC\UBL\Handlers\UblHandler;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class AddressHandler extends UblHandler {
public function handle( $data, $options = array() ) {
$root = isset( $options['root'] ) ? $options['root'] : 'AccountingSupplierParty';
// AccountingSupplierParty or AccountingCustomerParty
if ( 'AccountingSupplierParty' === $root ) {
return $this->return_supplier_party( $data, $options );
}
return $this->return_customer_party( $data, $options );
}
public function return_supplier_party( $data, $options = array() ) {
$supplierParty = array(
'name' => 'cac:AccountingSupplierParty',
'value' => array(
array(
'name' => 'cbc:CustomerAssignedAccountID',
'value' => '',
),
array(
'name' => 'cac:Party',
'value' => $this->return_supplier_party_details(),
),
),
);
$data[] = apply_filters( 'wpo_wc_ubl_handle_AccountingSupplierParty', $supplierParty, $data, $options, $this );
return $data;
}
public function return_supplier_party_details() {
$company = ! empty( $this->document->order_document ) ? $this->document->order_document->get_shop_name() : '';
$address = ! empty( $this->document->order_document ) ? $this->document->order_document->get_shop_address() : get_option( 'woocommerce_store_address' );
$vat_number = ! empty( $this->document->order_document ) ? $this->document->order_document->get_shop_vat_number() : '';
$coc_number = ! empty( $this->document->order_document ) ? $this->document->order_document->get_shop_coc_number() : '';
$supplierPartyDetails = array(
array(
'name' => 'cac:PartyName',
'value' => array(
'name' => 'cbc:Name',
'value' => $company,
),
),
array(
'name' => 'cac:PostalAddress',
'value' => array(
array(
'name' => 'cbc:StreetName',
'value' => get_option( 'woocommerce_store_address' ),
),
array(
'name' => 'cbc:CityName',
'value' => get_option( 'woocommerce_store_city' ),
),
array(
'name' => 'cbc:PostalZone',
'value' => get_option( 'woocommerce_store_postcode' ),
),
array(
'name' => 'cac:AddressLine',
'value' => array(
'name' => 'cbc:Line',
'value' => $address,
),
),
array(
'name' => 'cac:Country',
'value' => array(
'name' => 'cbc:IdentificationCode',
'value' => get_option( 'woocommerce_default_country' ),
'attributes' => array(
'listID' => 'ISO3166-1:Alpha2',
'listAgencyID' => '6',
),
),
),
),
),
);
if ( ! empty( $vat_number ) ) {
$supplierPartyDetails[] = array(
'name' => 'cac:PartyTaxScheme',
'value' => array(
array(
'name' => 'cbc:CompanyID',
'value' => $vat_number,
),
array(
'name' => 'cac:TaxScheme',
'value' => array(
array(
'name' => 'cbc:ID',
'value' => 'VAT',
'attributes' => array(
'schemeID' => 'UN/ECE 5153',
'schemeAgencyID' => '6',
),
),
),
),
),
);
}
$supplierPartyDetails[] = array(
'name' => 'cac:Contact',
'value' => array(
array(
'name' => 'cbc:ElectronicMail',
'value' => get_option( 'woocommerce_email_from_address' ),
),
),
);
if ( ! empty( $company ) && ! empty( $coc_number ) ) {
$supplierPartyDetails[] = array(
'name' => 'cac:PartyLegalEntity',
'value' => array(
array(
'name' => 'cbc:RegistrationName',
'value' => $company,
),
array(
'name' => 'cbc:CompanyID',
'value' => $coc_number,
'attributes' => array(
'schemeID' => '0106',
),
),
),
);
}
return $supplierPartyDetails;
}
public function return_customer_party( $data, $options = array() ) {
$vat_number = apply_filters( 'wpo_wc_ubl_vat_number', '', $this->document->order );
if ( empty( $vat_number ) ) {
// Try fetching VAT Number from meta
$vat_meta_keys = array(
'_vat_number', // WooCommerce EU VAT Number
'VAT Number', // WooCommerce EU VAT Compliance
'vat_number', // Aelia EU VAT Assistant
'_billing_vat_number', // WooCommerce EU VAT Number 2.3.21+
'_billing_eu_vat_number', // EU VAT Number for WooCommerce (WP Whale/former Algoritmika)
'yweu_billing_vat', // YITH WooCommerce EU VAT
'billing_vat', // German Market
'_billing_vat_id', // Germanized Pro
'_shipping_vat_id' // Germanized Pro (alternative)
);
foreach ( $vat_meta_keys as $meta_key ) {
if ( $vat_number = $this->document->order->get_meta( $meta_key ) ) {
break;
}
}
}
$customerPartyName = $customerPartyContactName = $this->document->order->get_formatted_billing_full_name();
$billing_company = $this->document->order->get_billing_company();
if ( ! empty( $billing_company ) ) {
// $customerPartyName = "{$billing_company} ({$customerPartyName})";
// we register customer name separately as Contact too,
// so we use the comapny name as the primary name
$customerPartyName = $billing_company;
}
$customerParty = array(
'name' => 'cac:AccountingCustomerParty',
'value' => array(
array(
'name' => 'cbc:CustomerAssignedAccountID',
'value' => '',
),
array(
'name' => 'cac:Party',
'value' => array(
array(
'name' => 'cac:PartyName',
'value' => array(
'name' => 'cbc:Name',
'value' => $customerPartyName,
),
),
array(
'name' => 'cac:PostalAddress',
'value' => array(
array(
'name' => 'cbc:StreetName',
'value' => $this->document->order->get_billing_address_1(),
),
array(
'name' => 'cbc:CityName',
'value' => $this->document->order->get_billing_city(),
),
array(
'name' => 'cbc:PostalZone',
'value' => $this->document->order->get_billing_postcode(),
),
array(
'name' => 'cac:AddressLine',
'value' => array(
'name' => 'cbc:Line',
'value' => $this->document->order->get_billing_address_1() .'<br/>'.$this->document->order->get_billing_address_2(),
),
),
array(
'name' => 'cac:Country',
'value' => array(
'name' => 'cbc:IdentificationCode',
'value' => $this->document->order->get_billing_country(),
'attributes' => array(
'listID' => 'ISO3166-1:Alpha2',
'listAgencyID' => '6',
),
),
),
),
),
array(
'name' => 'cac:PartyTaxScheme',
'value' => array(
array(
'name' => 'cbc:CompanyID',
'value' => $vat_number,
),
array(
'name' => 'cac:TaxScheme',
'value' => array(
array(
'name' => 'cbc:ID',
'value' => 'VAT',
'attributes' => array(
'schemeID' => 'UN/ECE 5153',
'schemeAgencyID' => '6',
),
),
),
),
),
),
array(
'name' => 'cac:Contact',
'value' => array(
array(
'name' => 'cbc:Name',
'value' => $customerPartyContactName,
),
array(
'name' => 'cbc:ElectronicMail',
'value' => $this->document->order->get_billing_email(),
),
),
),
),
),
),
);
$data[] = apply_filters( 'wpo_wc_ubl_handle_AccountingCustomerParty', $customerParty, $data, $options, $this );
return $data;
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace WPO\WC\UBL\Handlers\Ubl;
use WPO\WC\UBL\Handlers\UblHandler;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class AllowanceChargeHandler extends UblHandler {
public function handle( $data, $options = array() ) {
$allowanceCharge = array(
'name' => 'cac:AllowanceCharge',
'value' => array(),
);
$data[] = apply_filters( 'wpo_wc_ubl_handle_AllowanceCharge', $allowanceCharge, $data, $options, $this );
return $data;
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace WPO\WC\UBL\Handlers\Ubl;
use WPO\WC\UBL\Handlers\UblHandler;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class DeliveryHandler extends UblHandler {
public function handle( $data, $options = array() ) {
$delivery = array(
'name' => 'cac:Delivery',
'value' => array(),
);
$data[] = apply_filters( 'wpo_wc_ubl_handle_Delivery', $delivery, $data, $options, $this );
return $data;
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace WPO\WC\UBL\Handlers\Ubl;
use WPO\WC\UBL\Handlers\UblHandler;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class DocumentCurrencyCodeHandler extends UblHandler {
public function handle( $data, $options = array() ) {
$documentCurrencyCode = array(
'name' => 'cbc:DocumentCurrencyCode',
'value' => $this->document->order->get_currency(),
'attributes' => array(
'listID' => 'ISO4217',
'listAgencyID' => '6',
),
);
$data[] = apply_filters( 'wpo_wc_ubl_handle_DocumentCurrencyCode', $documentCurrencyCode, $data, $options, $this );
return $data;
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace WPO\WC\UBL\Handlers\Ubl;
use WPO\WC\UBL\Handlers\UblHandler;
use WPO\WC\UBL\Models\Order;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class IdHandler extends UblHandler {
public function handle( $data, $options = array() ) {
$ID = array(
'name' => 'cbc:ID',
'value' => $this->document->order_document->get_number()->get_formatted(),
);
$data[] = apply_filters( 'wpo_wc_ubl_handle_ID', $ID, $data, $options, $this );
return $data;
}
}

View File

@@ -0,0 +1,131 @@
<?php
namespace WPO\WC\UBL\Handlers\Ubl;
use WPO\WC\UBL\Handlers\UblHandler;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class InvoiceLineHandler extends UblHandler {
public function handle( $data, $options = array() ) {
$items = $this->document->order->get_items( array( 'line_item', 'fee', 'shipping' ) );
// Build the tax totals array
foreach ( $items as $item_id => $item ) {
$taxSubtotal = [];
$taxDataContainer = ( $item['type'] == 'line_item' ) ? 'line_tax_data' : 'taxes';
$taxDataKey = ( $item['type'] == 'line_item' ) ? 'subtotal' : 'total';
$lineTotalKey = ( $item['type'] == 'line_item' ) ? 'line_total' : 'total';
$line_tax_data = $item[ $taxDataContainer ];
foreach ( $line_tax_data[ $taxDataKey ] as $tax_id => $tax ) {
if ( ! is_numeric( $tax ) ) {
continue;
}
$taxOrderData = $this->document->order_tax_data[ $tax_id ];
$taxSubtotal[] = array(
'name' => 'cac:TaxSubtotal',
'value' => array(
array(
'name' => 'cbc:TaxableAmount',
'value' => round( $item[ $lineTotalKey ], 2 ),
'attributes' => array(
'currencyID' => $this->document->order->get_currency(),
),
),
array(
'name' => 'cbc:TaxAmount',
'value' => round( $tax, 2 ),
'attributes' => array(
'currencyID' => $this->document->order->get_currency(),
),
),
array(
'name' => 'cac:TaxCategory',
'value' => array(
array(
'name' => 'cbc:ID',
'value' => strtoupper( $taxOrderData['category'] ),
),
array(
'name' => 'cbc:Name',
'value' => $taxOrderData['name'],
),
array(
'name' => 'cbc:Percent',
'value' => round( $taxOrderData['percentage'], 2 ),
),
array(
'name' => 'cac:TaxScheme',
'value' => array(
array(
'name' => 'cbc:ID',
'value' => strtoupper( $taxOrderData['scheme'] ),
),
),
),
),
),
),
);
}
$invoiceLine = array(
'name' => 'cac:InvoiceLine',
'value' => array(
array(
'name' => 'cbc:ID',
'value' => $item_id,
),
array(
'name' => 'cbc:InvoicedQuantity',
'value' => $item->get_quantity(),
),
array(
'name' => 'cbc:LineExtensionAmount',
'value' => round( $item->get_total(), 2 ),
'attributes' => array(
'currencyID' => $this->document->order->get_currency(),
),
),
array(
'name' => 'cac:TaxTotal',
'value' => array(
array(
'name' => 'cbc:TaxAmount',
'value' => round( $item->get_total_tax(), 2),
'attributes' => array(
'currencyID' => $this->document->order->get_currency(),
),
),
$taxSubtotal,
),
),
array(
'name' => 'cac:Item',
'value' => array(
array(
'name' => 'cbc:Name',
'value' => $item->get_name(),
),
),
),
),
);
$data[] = apply_filters( 'wpo_wc_ubl_handle_InvoiceLine', $invoiceLine, $data, $options, $item, $this );
// Empty this array at the end of the loop per item, so data doesn't stack
$taxSubtotal = [];
}
return $data;
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace WPO\WC\UBL\Handlers\Ubl;
use WPO\WC\UBL\Handlers\UblHandler;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class InvoiceTypeCodeHandler extends UblHandler {
public function handle( $data, $options = array() ) {
$invoiceTypeCode = array(
'name' => 'cbc:InvoiceTypeCode',
'value' => '380',
'attributes' => array(
'listID' => 'UNCL1001',
'listAgencyID' => '6',
),
);
$data[] = apply_filters( 'wpo_wc_ubl_handle_InvoiceTypeCode', $invoiceTypeCode, $data, $options, $this );
return $data;
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace WPO\WC\UBL\Handlers\Ubl;
use WPO\WC\UBL\Handlers\UblHandler;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class IssueDateHandler extends UblHandler {
public function handle( $data, $options = array() ) {
$issueDate = array(
'name' => 'cbc:IssueDate',
'value' => $this->document->order_document->get_date()->date_i18n( 'Y-m-d' ),
);
$data[] = apply_filters( 'wpo_wc_ubl_handle_IssueDate', $issueDate, $data, $options, $this );
return $data;
}
}

View File

@@ -0,0 +1,57 @@
<?php
namespace WPO\WC\UBL\Handlers\Ubl;
use WPO\WC\UBL\Handlers\UblHandler;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class LegalMonetaryTotalHandler extends UblHandler {
public function handle( $data, $options = array() ) {
$total = $this->document->order->get_total();
$total_inc_tax = $total;
$total_exc_tax = $total - $this->document->order->get_total_tax();
$legalMonetaryTotal = array(
'name' => 'cac:LegalMonetaryTotal',
'value' => array(
array(
'name' => 'cbc:LineExtensionAmount',
'value' => $total_exc_tax,
'attributes' => array(
'currencyID' => $this->document->order->get_currency(),
),
),
array(
'name' => 'cbc:TaxExclusiveAmount',
'value' => $total_exc_tax,
'attributes' => array(
'currencyID' => $this->document->order->get_currency(),
),
),
array(
'name' => 'cbc:TaxInclusiveAmount',
'value' => $total_inc_tax,
'attributes' => array(
'currencyID' => $this->document->order->get_currency(),
),
),
array(
'name' => 'cbc:PayableAmount',
'value' => $total,
'attributes' => array(
'currencyID' => $this->document->order->get_currency(),
),
),
),
);
$data[] = apply_filters( 'wpo_wc_ubl_handle_LegalMonetaryTotal', $legalMonetaryTotal, $data, $options, $this );
return $data;
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace WPO\WC\UBL\Handlers\Ubl;
use WPO\WC\UBL\Handlers\UblHandler;
use WPO\WC\UBL\Models\Order;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class OrderReferenceHandler extends UblHandler {
public function handle( $data, $options = array() ) {
$orderReference = array(
'name' => 'cac:OrderReference',
'value' => array(
'name' => 'cbc:ID',
'value' => $this->document->order->get_id(),
),
);
$data[] = apply_filters( 'wpo_wc_ubl_handle_OrderReference', $orderReference, $data, $options, $this );
return $data;
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace WPO\WC\UBL\Handlers\Ubl;
use WPO\WC\UBL\Handlers\UblHandler;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class PaymentMeansHandler extends UblHandler {
public function handle( $data, $options = array() ) {
$payment_means = array(
'name' => 'cac:PaymentMeans',
'value' => array(),
);
$data[] = apply_filters( 'wpo_wc_ubl_handle_PaymentMeans', $payment_means, $data, $options, $this );
return $data;
}
}

View File

@@ -0,0 +1,29 @@
<?php
namespace WPO\WC\UBL\Handlers\Ubl;
use WPO\WC\UBL\Handlers\UblHandler;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class PaymentTermsHandler extends UblHandler {
public function handle( $data, $options = array() ) {
$paymentTerms = array(
'name' => 'cac:PaymentTerms',
'value' => array(
array(
'name' => 'cbc:Note',
'value' => '',
),
),
);
$data[] = apply_filters( 'wpo_wc_ubl_handle_PaymentTerms', $paymentTerms, $data, $options, $this );
return $data;
}
}

View File

@@ -0,0 +1,81 @@
<?php
namespace WPO\WC\UBL\Handlers\Ubl;
use WPO\WC\UBL\Handlers\UblHandler;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class TaxTotalHandler extends UblHandler {
public function handle( $data, $options = array() ) {
$formatted_tax_array = array_map( function( $item ) {
return array(
'name' => 'cac:TaxSubtotal',
'value' => array(
array(
'name' => 'cbc:TaxableAmount',
'value' => round( $item['total_ex'], 2 ),
'attributes' => array(
'currencyID' => $this->document->order->get_currency(),
),
),
array(
'name' => 'cbc:TaxAmount',
'value' => round( $item['total_tax'], 2 ),
'attributes' => array(
'currencyID' => $this->document->order->get_currency(),
),
),
array(
'name' => 'cac:TaxCategory',
'value' => array(
array(
'name' => 'cbc:ID',
'value' => strtoupper( $item['category'] ),
),
array(
'name' => 'cbc:Name',
'value' => $item['name'],
),
array(
'name' => 'cbc:Percent',
'value' => round( $item['percentage'], 1 ),
),
array(
'name' => 'cac:TaxScheme',
'value' => array(
array(
'name' => 'cbc:ID',
'value' => strtoupper( $item['scheme'] ),
),
),
),
),
),
),
);
}, $this->document->order_tax_data );
$array = array(
'name' => 'cac:TaxTotal',
'value' => array(
array(
'name' => 'cbc:TaxAmount',
'value' => round( $this->document->order->get_total_tax(), 2 ),
'attributes' => array(
'currencyID' => $this->document->order->get_currency(),
),
),
$formatted_tax_array
),
);
$data[] = apply_filters( 'wpo_wc_ubl_handle_TaxTotal', $array, $data, $options, $this );
return $data;
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace WPO\WC\UBL\Handlers\Ubl;
use WPO\WC\UBL\Handlers\UblHandler;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
class UblVersionIdHandler extends UblHandler {
public function handle( $data, $options = array() ) {
$UBLVersionID = array(
'name' => 'cbc:UBLVersionID',
'value' => '2.1',
);
$data[] = apply_filters( 'wpo_wc_ubl_handle_UBLVersionID', $UBLVersionID, $data, $options, $this );
return $data;
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace WPO\WC\UBL\Handlers;
use WPO\WC\UBL\Documents\Document;
use WPO\WC\UBL\Models\Order;
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
abstract class UblHandler extends Handler {
}