Factur-X norme 3 (May 15th, 2025)

This commit is contained in:
sparkyx 2025-10-05 12:50:13 +02:00
parent 8039f3438a
commit fd21804f21
8 changed files with 361 additions and 202 deletions

View file

@ -85,7 +85,8 @@ class Error_Message
, 'MY_STREET' => _("Adresse de la société")
, 'MY_CITY' => _("Ville")
, 'MY_TVA' => _("Numéro de TVA")
// , 'SIREN'=> 'SIREN'
// , 'SIRET'=> 'SIRET'
);
$this->a_message_customer = array(
'name' => _("Nom")

View file

@ -19,15 +19,25 @@ namespace Noalyss\XMLDocument;
*/
// Copyright Author Dany De Bontridder danydb@aevalys.eu 22/10/23
use \Kinulab\Facturx\CrossIndustryInvoice as KINU_FX1;
use \Atgp\FacturX as FX_ATGP;
use horstoeko\zugferd\codelists\ZugferdCountryCodes;
use horstoeko\zugferd\codelists\ZugferdCurrencyCodes;
use horstoeko\zugferd\codelists\ZugferdElectronicAddressScheme;
use horstoeko\zugferd\codelists\ZugferdInvoiceType;
use horstoeko\zugferd\codelists\ZugferdReferenceCodeQualifiers;
use horstoeko\zugferd\codelists\ZugferdUnitCodes;
use horstoeko\zugferd\codelists\ZugferdVatCategoryCodes;
use horstoeko\zugferd\codelists\ZugferdVatTypeCodes;
use horstoeko\zugferd\ZugferdDocumentBuilder;
use horstoeko\zugferd\ZugferdProfiles;
/**
* @file
* @brief answer to an inplace object
*/
class FacturX extends XMLInvoice
{
const EXTRA_PARAMETER = ["INVOICE_EMAIL_COMPANY"
const EXTRA_PARAMETER = [
"INVOICE_EMAIL_COMPANY"
, 'INVOICE_CONTACT_NAME'
, 'COMPANY_LEGAL_ENTITY'
, 'COMPANY_LEGAL_REGISTRATION'
@ -40,38 +50,54 @@ class FacturX extends XMLInvoice
, 'MY_CITY'
, 'MY_COUNTRY_CODE'
, 'MY_TVA'
,'SIREN'
,'SIRET'
// ,'SIREN'
// ,'SIRET'
];
protected $pdf_filename;
function build_data($jr_id): array {
$result = parent::build_data($jr_id);
$customer=new \Fiche($this->cn,$result['customer']['card_id']);
$result['customer']['siren']=$customer->get_attribute(ATTR_DEF_SIREN);
$result['customer']['siret']=$customer->get_attribute(ATTR_DEF_SIRET);
return $result;
$this->data=parent::build_data($jr_id);
return $this->data;
}
/**
* @brief check that mandatory info are saved in the DB
* @param $a_error (array) array of errors, empty if nothing found
*/
function check_company_data(&$a_error) {
echo "not implemented";
return true;
function check_company_data()
{
$a_error=array();
$company = $this->load_noalyss_parameter();
foreach (FacturX::EXTRA_PARAMETER as $item) {
if (!isset($company[$item]) || trim($company[$item]) == '') {
$a_error[]=$item;
}
}
return $a_error;
}
/**
* @brief check that mandatory info are saved in the DB for customer
* @param $customer_id (int) card of the customer FICHE.F_ID
* @param $a_error (array) array of errors, empty if nothing found
*/
function check_customer_data($customer_id,&$a_error){
echo "not implemented";
return true;
function check_customer_data($customer_id){
$a_error=array();
$a_needed=[ATTR_DEF_NAME=>'name'
,ATTR_DEF_ADRESS=>'street'
,ATTR_DEF_POSTCODE=>'postalzone'
,ATTR_DEF_CITY=>'city'
,ATTR_DEF_COUNTRY_CODE=>'country'
,ATTR_DEF_NUMTVA=>'customer_id'
,ATTR_DEF_PEPPOLID=>'endpoint_id'
];
foreach ($a_needed as $item=>$value) {
if ( $this->data['customer'][$value]=="") {
$a_error[]=$value;
}
}
return $a_error;
}
/**
@ -83,53 +109,81 @@ class FacturX extends XMLInvoice
function make_xml($jr_id)
{
$this->data = $this->build_data($jr_id);
$invoice= new KINU_FX1\CrossIndustryInvoice(KINU_FX1\CrossIndustryInvoice::PROFILE_BASIC_WL);
$invoice->setInvoiceNumber($this->data['id']);
$invoice->setInvoiceType(KINU_FX1\CrossIndustryInvoice::INVOICE_TYPE_COMMERCIAL_INVOICE);
$invoice->setIssueDate(\DateTime::createFromFormat( 'Y-m-d',$this->data['issue_date']));
if ( $this->data['due_date'] !="") {
$invoice->setDueDate(\DateTime::createFromFormat( 'Y-m-d',$this->data['due_date']));
}else {
$due_date=\DateTime::createFromFormat( 'Y-m-d',$this->data['issue_date']);
$due_date->modify('+ 30 days');
$invoice->setDueDate($due_date);
}
$supplier=new KINU_FX1\LegalEntity();
$company = $this->load_noalyss_parameter();
$supplier->setName($company['MY_NAME']);
$supplier->setSiren($company['SIREN']);
$supplier->setSiret($company['SIRET']);
//$supplier->setSiren('999999');
$supplier->setVatIdentifier($company['MY_TVA']);
$supplier_addres=new KINU_FX1\Address();
$supplier_addres->setCityName($company['MY_CITY'])
->setCountryId($company['MY_COUNTRY_CODE'])
->setCityName($company['MY_CITY'])
->setLines($company['MY_STREET']);
$supplier->setAddress($supplier_addres);
$invoice->setPaymentInstruction(null);
$invoice->setPaymentMeansCode(0);
$invoice->setSeller($supplier);
$invoice->setBuyer(new KINU_FX1\LegalEntity);
$buyer=$invoice->getBuyer();
$buyer->setName($this->data['customer']['name']);
$buyer->setSiren($this->data['customer']['siren']);
$buyer->setSiret($this->data['customer']['siret']);
$buyer->setVatIdentifier($this->data['customer']['customer_id']);
$buyer->setAddress(new KINU_FX1\Address());
$address=$buyer->getAddress();
$address->setLines($this->data['customer']['street'])
->setCityName($this->data['customer']['city'])
->setZipCode($this->data['customer']['postalzone'])
->setCountryId($this->data['customer']['country']);
// var_dump($this->data);
$documentBuilder = ZugferdDocumentBuilder::createNew(ZugferdProfiles::PROFILE_XRECHNUNG_3);
$documentBuilder->setDocumentInformation(
$this->data['id']
,"380"
,\DateTime::createFromFormat( 'Y-m-d',$this->data["issue_date"])
, $this->data['currency']
);
$documentBuilder->addDocumentPaymentTerm(
sprintf("IBAN %s",$company['COMPANY_BANK_IBAN'])
,\DateTime::createFromFormat( 'Y-m-d',$this->data["due_date"])
, $this->data['info']['communication']
);
//------------------------------------------------
// SELLER
//------------------------------------------------
$documentBuilder->setDocumentSeller($company['MY_NAME'], );
$documentBuilder->addDocumentSellerGlobalId($company['SIREN'], '0009');
$documentBuilder->addDocumentSellerTaxNumber($company['MY_TVA']);
$documentBuilder->addDocumentSellerVATRegistrationNumber($company['MY_TVA']);
$documentBuilder->setDocumentSellerAddress(
$company['MY_STREET']
, '', ''
, $company['MY_POSTCODE']
, $company['MY_CITY']
,$company['MY_COUNTRY_CODE']);
$documentBuilder->setDocumentSellerCommunication(ZugferdElectronicAddressScheme::UNECE3155_EM
, $company["INVOICE_EMAIL_COMPANY"]);
//------------------------------------------------
// BUYER
//------------------------------------------------
$documentBuilder->setDocumentBuyer($this->data['customer']['name'], $this->data['customer']['customer_id']);
$documentBuilder->setDocumentBuyerAddress(
$this->data['customer']['street']
, ''
, ''
, $this->data['customer']['postalzone']
, $this->data['customer']['city']
, $this->data['customer']['country']
);
// $documentBuilder->setDocumentBuyerContact('H. Meier', 'Einkauf', '+49-333-4444444', '+49-333-5555555', 'hm@kunde.de');
// $documentBuilder->setDocumentBuyerCommunication(ZugferdElectronicAddressScheme::UNECE3155_EM, 'purchase@kunde.de');
$documentBuilder->setDocumentBuyerOrderReferencedDocument($this->data['info']['order']);
//------------------------------------------------
// Item & total
//------------------------------------------------
$invoice->setCurrencyCode('EUR');
$base=0;$vat=0;
$nb=count($this->data['operation']);
///@note : Pour l'autoliquidation le total TVA = 0
for ($i=0;$i < $nb;$i++) {
$documentBuilder->addNewPosition($i+1);
$documentBuilder->setDocumentPositionProductDetails($this->data['operation'][$i]['qcode']
,$this->data['operation'][$i]['name']
,$this->data['operation'][$i]['description']
);
$documentBuilder->setDocumentPositionNetPrice($this->data['operation'][$i]['price']);
$documentBuilder->setDocumentPositionQuantity($this->data['operation'][$i]['quantity']
,$this->data['operation'][$i]['code_quantity']
);
$documentBuilder->addDocumentPositionTax(
$this->data['operation'][$i]['vat_code']
, ZugferdVatTypeCodes::VALUE_ADDED_TAX
, bcmul($this->data['operation'][$i]['vat_rate'],100,2)
);
$documentBuilder->setDocumentPositionLineSummation($this->data['operation'][$i]['price']);
$base=bcadd($base,$this->data['operation'][$i]['price'],2);
$vat=bcadd($vat,$this->data['operation'][$i]['vat'],2);
$vat=bcsub($vat,$this->data['operation'][$i]['vat_reversed'],2);
@ -140,12 +194,40 @@ class FacturX extends XMLInvoice
* il faut alors un "reste" à payer.
* Pas de détail par articles ?
*/
$invoice->setTaxBasisTotalAmount($base);
$invoice->setTaxTotalAmount($vat);
$invoice->setGrandTotalAmount($tt);
$invoice->setDuePayableAmount($tt);
$xml = KINU_FX1\XmlWriter::write($invoice);
return $xml;
///@TODO DNY : ajouter les TVA par types ( addDocumentTax)
/// ainsi que la Somme des totaux (setDocumentSummation)
$subTotal=$this->data['subTotalVAT'];
$nb_sub=count($subTotal);
for ($i=0;$i<$nb_sub;$i++)
{
$documentBuilder->addDocumentTax(
$subTotal[$i]["vat_code"]
, ZugferdVatTypeCodes::VALUE_ADDED_TAX
,sprintf("%.2f",$subTotal[$i]['amount'])
, sprintf("%.2f",$subTotal[$i]['vat'])
, sprintf("%.2f",$subTotal[$i]['percent'])
);
}
$documentBuilder->setDocumentSummation(
sprintf("%.2f",$this->data['TaxInclusiveAmount'])
, sprintf("%.2f",$this->data['PayableAmount'])
, sprintf("%.2f",$this->data['TaxExclusiveAmount'])
, 0.0
, 0.0
, sprintf("%.2f",$this->data['LineExtensionAmount'])
, sprintf("%.2f",(bcsub($this->data['TaxInclusiveAmount'],
$this->data['TaxExclusiveAmount'],
2)
)
)
, 0
);
return $documentBuilder;
}
/**
* @brief create the invoice in the right format
@ -153,10 +235,14 @@ class FacturX extends XMLInvoice
* @return string PDF Invoice including the XML
*/
function create_invoice($operation_id) {
$xml = $this->make_xml($operation_id);
$facturx = new FX_ATGP\Facturx();
$invoice=$facturx->generateFacturxFromFiles($this->pdf_filename, $xml);
return $invoice;
$documentBuilder= $this->make_xml($operation_id);
$invoice = \horstoeko\zugferd\ZugferdDocumentPdfBuilder::fromPdfFile($documentBuilder, $this->pdf_filename);
$invoice->generateDocument();
$invoice->saveDocument($this->pdf_filename."-new.pdf");
return $invoice->downloadString();
}
}

View file

@ -70,40 +70,6 @@ class InvoiceUBL21 extends XMLInvoice {
include NOALYSS_TEMPLATE."/invoiceUBL21-display_error.php";
}
/**
* @brief check that all the data are correct
* @returns null : no errors, string separated with comma of error code
* @see get_message_error
* @see InvoiceUBL21::get_message_error()
*/
function verify()
{
// verify all VAT
///@var $a_error : array of error_code see check_company_error
$a_error = array();
$a_error['general'] = parent::verify();
$a_error['operation']=[];
// verify that all needed data in PARAMETER are valid
$a_error['company'] = $this->check_company_data();
$a_error['customer'] = $this->check_customer_data($this->data['customer']['card_id']);
return $a_error;
}
/**
* @brief set the PDF
* @param $pdf_filename (string) full path to the PDF
* @return $this
* @throws \Exception if the filename doesn't exist
*/
public function set_pdf_filename($pdf_filename) {
if ( !file_exists($pdf_filename)) {
throw new \Exception("AD65 $pdf_filename doesn't not exist");
}
$this->pdf_filename = $pdf_filename;
return $this;
}
/**
* @brief check that mandatory info are saved in the DB for company (seller)
@ -145,31 +111,7 @@ class InvoiceUBL21 extends XMLInvoice {
return $a_error;
}
/**
* @brief check that the VAT is using a PEPPOL Code
*/
function check_VAT()
{
$a_error=array();
$nb_operation=count($this->data['operation']);
for ($i=0;$i <$nb_operation;$i++)
{
if ( $this->data['operation'][$i]['vat_code'] == "" ) {
$card=new \Fiche(
$this->cn
,$this->data['operation'][$i]['card_id']
);
$tva= \Acc_Tva::build($this->cn, $this->data['operation'][$i]['vat_id']);
$a_error[]=sprintf(_("%s : %s code TVA pour PEPPOL non configuré code TVA [ %s %s ]")
, $i
, $card->get_quick_code()
,$tva->tva_id
,$tva->tva_code
);
}
}
return $a_error;
}
/**
* @brief transform an operation ($jr_id) into an array, which contains
* needed information for making an e-invoice
@ -178,60 +120,11 @@ class InvoiceUBL21 extends XMLInvoice {
* @param type $jr_id
* @see XMLInvoice::build_data
*/
function build_data($jr_id): array {
$result = parent::build_data($jr_id);
/**
* Compute totals VAT and AMOUNT
*/
$nb_operation = count($result['operation']);
function build_data($jr_id): array
{
/// block cac:LegalMonetaryTotal
$result['LineExtensionAmount']=0;
$result['TaxExclusiveAmount']=0;
$result['TaxInclusiveAmount']=0;
$result['PayableAmount']=0;
// block cac:TaxTotal
$result['TaxableAmount']=0;
$result['TaxAmount']=0;
// array for TaxSubtotal
$VAT_SubTotal=array();
$idx_subtotal=0;
bcscale(2);
// for each operation
$VAT_SubTotal=array();
for ($i=0;$i < $nb_operation;$i++) {
$acc_tva=\Acc_TVA::build($this->cn,$result['operation'][$i]['vat_id'] );
$percent = bcmul($acc_tva->tva_rate,100,2);
// subtotal for VAT
$n = find_idx($VAT_SubTotal,'percent',$percent);
if ($n == -1 ) {
$n=$idx_subtotal;
$VAT_SubTotal[$idx_subtotal]=array();
$VAT_SubTotal[$idx_subtotal]['percent']=$percent;
$VAT_SubTotal[$idx_subtotal]['amount']=$VAT_SubTotal[$idx_subtotal]['vat']=0;
$idx_subtotal++;
}
/**
* @todo Pour les intracomm , quel taux utilisé ? 0 ou 21%
*/
$VAT_SubTotal[$n]['amount']=bcadd($VAT_SubTotal[$n]['amount'],$result['operation'][$i]['price']);
$VAT_SubTotal[$n]['vat']=bcadd($VAT_SubTotal[$n]['vat'],$result['operation'][$i]['vat']);
$VAT_SubTotal[$n]['vat']=bcsub($VAT_SubTotal[$n]['vat'],$result['operation'][$i]['vat_reversed']);
$result['TaxableAmount']=bcadd( $result['TaxableAmount'],$result['operation'][$i]['price']);
$result['TaxAmount']=bcadd( $result['TaxAmount'],$result['operation'][$i]['vat']);
$result['TaxAmount']=bcsub( $result['TaxAmount'],$result['operation'][$i]['vat_reversed']);
$result['operation'][$i]['vat_percent']=$percent;
}
$result['subTotalVAT']=$VAT_SubTotal;
$result['LineExtensionAmount']= $result['TaxableAmount'];
$result['TaxExclusiveAmount']= $result['TaxableAmount'];
$result['TaxInclusiveAmount']=bcadd( $result['TaxableAmount'],$result['TaxAmount']);
$result['PayableAmount']=bcadd( $result['TaxableAmount'],$result['TaxAmount']);;
$this->data=$result;
return $result;
$this->data=parent::build_data($jr_id);
return $this->data;
}
/**
* @brief Information customer
@ -403,7 +296,11 @@ class InvoiceUBL21 extends XMLInvoice {
$subTotalXML->appendChild($this->createElement('cbc:TaxAmount',sprintf("%.2f",$subTotal[$i]['vat'])))
->setAttribute("currencyID",$this->data['currency']);
$taxCategory=$this->createElement("cac:TaxCategory");
$taxCategory->appendChild($this->createElement("cbc:ID","S"));
/**
* @TODO DNY
* Pas toujours S !?
*/
//$taxCategory->appendChild($this->createElement("cbc:ID",$subTotal[$i]['vat_code']));
$taxCategory->appendChild($this->createElement("cbc:Percent",sprintf("%.2f",$subTotal[$i]['percent'])));
$taxScheme=$this->createElement("cac:TaxScheme");
$taxScheme->appendChild($this->createElement("cbc:ID", "VAT"));
@ -482,9 +379,8 @@ class InvoiceUBL21 extends XMLInvoice {
// ITEM
$item=$this->createElement("cac:Item");
$card=new \Fiche($this->cn,$row['card_id']);
$item->appendChild($this->createElement("cbc:Description", $card->get_attribute(ATTR_DEF_NAME)));
$item->appendChild($this->createElement("cbc:Name", $card->get_attribute(ATTR_DEF_QUICKCODE)));
$item->appendChild($this->createElement("cbc:Description",$row['name']));
$item->appendChild($this->createElement("cbc:Name", $row['qcode']));
$classifiedTaxCat=$this->createElement("cac:ClassifiedTaxCategory");
//cbc:ID S = standard rate

View file

@ -193,9 +193,12 @@ abstract class XMLInvoice extends \DOMDocument
for ($i=0;$i < $nb_operation;$i++) {
$result['operation'][$i]['card_id']=$operation->det->array[$i]['qs_fiche'];
$result['operation'][$i]['quantity']=$operation->det->array[$i]['qs_quantite'];
$card=new \Fiche($this->cn,$operation->det->array[$i]['qs_fiche']);
$result['operation'][$i]['qcode']=$card->get_attribute(ATTR_DEF_QUICKCODE);
$result['operation'][$i]['name']=$card->get_attribute(ATTR_DEF_NAME);
$result['operation'][$i]['description']=$card->get_attribute(9);
// get the type of unity, if not found then it will be EA
$x= \Card_Property::get_attribute($this->cn,$operation->det->array[$i]['qs_fiche'], ATTR_DEF_QUANTITY_TYPE);
$x= $card->get_attribute(ATTR_DEF_QUANTITY_TYPE,0);
$result['operation'][$i]['code_quantity']=($x===false||$x=="")?"EA":$x;
// $operation->det->currency_id == 0 default currency of the folder
@ -214,9 +217,10 @@ abstract class XMLInvoice extends \DOMDocument
}
$result['operation'][$i]['vat_id']=$operation->det->array[$i]['qs_vat_code'];
// // tva code for PEPPOL
$x=$this->cn->get_value("select tva_peppol_code from tva_rate where tva_id=$1"
$x=$this->cn->get_row("select tva_peppol_code,tva_rate from tva_rate where tva_id=$1"
,[ $result['operation'][$i]['vat_id']]);
$result['operation'][$i]['vat_code']=($x=="")?"S":$x;
$result['operation'][$i]['vat_code']=($x['tva_peppol_code']=="")?"S":$x['tva_peppol_code'];
$result['operation'][$i]['vat_rate']=$x['tva_rate'];
$result['operation'][$i]['vat_reversed']=$operation->det->array[$i]['qs_vat_sided'];
}
@ -241,9 +245,64 @@ abstract class XMLInvoice extends \DOMDocument
}
}
$result['info']['communication']=($result['info']['communication']=="")?$result['id']:"";
/**
* Compute totals VAT and AMOUNT
*/
$nb_operation = count($result['operation']);
/// block cac:LegalMonetaryTotal
$result['LineExtensionAmount']=0;
$result['TaxExclusiveAmount']=0;
$result['TaxInclusiveAmount']=0;
$result['PayableAmount']=0;
// block cac:TaxTotal
$result['TaxableAmount']=0;
$result['TaxAmount']=0;
// array for TaxSubtotal
$VAT_SubTotal=array();
$idx_subtotal=0;
bcscale(2);
// for each operation
$VAT_SubTotal=array();
for ($i=0;$i < $nb_operation;$i++) {
$acc_tva=\Acc_TVA::build($this->cn,$result['operation'][$i]['vat_id'] );
$percent = bcmul($acc_tva->tva_rate,100,2);
$idx=sprintf("%s - %s",$percent,$result['operation'][$i]['vat_code'] );
// subtotal for VAT
$n = find_idx($VAT_SubTotal,'idx',$idx);
if ($n == -1 ) {
$n=$idx_subtotal;
$VAT_SubTotal[$idx_subtotal]=array();
$VAT_SubTotal[$idx_subtotal]['idx']=$idx;
$VAT_SubTotal[$idx_subtotal]['vat_code']=$result['operation'][$i]['vat_code'] ;
$VAT_SubTotal[$idx_subtotal]['percent']=$percent;
$VAT_SubTotal[$idx_subtotal]['amount']=$VAT_SubTotal[$idx_subtotal]['vat']=0;
$idx_subtotal++;
}
/**
* @todo Pour les intracomm , quel taux utilisé ? 0 ou 21%
*/
$VAT_SubTotal[$n]['amount']=bcadd($VAT_SubTotal[$n]['amount'],$result['operation'][$i]['price']);
$VAT_SubTotal[$n]['vat']=bcadd($VAT_SubTotal[$n]['vat'],$result['operation'][$i]['vat']);
$VAT_SubTotal[$n]['vat']=bcsub($VAT_SubTotal[$n]['vat'],$result['operation'][$i]['vat_reversed']);
$result['TaxableAmount']=bcadd( $result['TaxableAmount'],$result['operation'][$i]['price']);
$result['TaxAmount']=bcadd( $result['TaxAmount'],$result['operation'][$i]['vat']);
$result['TaxAmount']=bcsub( $result['TaxAmount'],$result['operation'][$i]['vat_reversed']);
$result['operation'][$i]['vat_percent']=$percent;
}
$result['subTotalVAT']=$VAT_SubTotal;
$result['LineExtensionAmount']= $result['TaxableAmount'];
$result['TaxExclusiveAmount']= $result['TaxableAmount'];
$result['TaxInclusiveAmount']=bcadd( $result['TaxableAmount'],$result['TaxAmount']);
$result['PayableAmount']=bcadd( $result['TaxableAmount'],$result['TaxAmount']);
return $result;
}
/**
* @brief make an array of parameter_extra where pe_code as key and pe_value
* as value
@ -281,6 +340,42 @@ abstract class XMLInvoice extends \DOMDocument
*/
abstract function create_invoice($operation_id) ;
/**
* @brief display_error display a warning with all error
*/
public function display_error()
{
$a_error=$this->verify();
include NOALYSS_TEMPLATE."/xmlinvoice-display_error.php";
}
/**
* @brief check that the VAT is using a PEPPOL Code
*/
function check_VAT()
{
$a_error=array();
$nb_operation=count($this->data['operation']);
for ($i=0;$i <$nb_operation;$i++)
{
if ( $this->data['operation'][$i]['vat_code'] == "" ) {
$card=new \Fiche(
$this->cn
,$this->data['operation'][$i]['card_id']
);
$tva= \Acc_Tva::build($this->cn, $this->data['operation'][$i]['vat_id']);
$a_error[]=sprintf(_("%s : %s code TVA pour PEPPOL non configuré code TVA [ %s %s ]")
, $i
, $card->get_quick_code()
,$tva->tva_id
,$tva->tva_code
);
}
}
return $a_error;
}
/**
* @brief thanks MY_INVOICE_FORMAT , create the corresponding object
* - UBL21BEL => InvoiceUBL21
@ -298,15 +393,26 @@ abstract class XMLInvoice extends \DOMDocument
return null;
}
/**
/**
* @brief check that all the data are correct
* @returns int 0 : no errors, int separated value
* @see InvoiceUBL21::get_message_error()
* @returns null : no errors, string separated with comma of error code
* @see get_message_error
*/
function verify()
public function verify()
{
return array();
// verify all VAT
///@var $a_error : array of error_code see check_company_error
$a_error = array();
$a_error['general'] = [];
$a_error['operation']=[];
// verify that all needed data in PARAMETER are valid
$a_error['company'] = $this->check_company_data();
$a_error['customer'] = $this->check_customer_data($this->data['customer']['card_id']);
return $a_error;
}
/**
* @brief retrieve data from customer and return it into an array
* @param $card_id (int) FICHE.F_ID
@ -419,4 +525,19 @@ abstract class XMLInvoice extends \DOMDocument
}
return $result;
}
/**
* @brief set the PDF
* @param $pdf_filename (string) full path to the PDF
* @return $this
* @throws \Exception if the filename doesn't exist
*/
public function set_pdf_filename($pdf_filename) {
if ( !file_exists($pdf_filename)) {
throw new \Exception("AD65 $pdf_filename doesn't not exist");
}
$this->pdf_filename = $pdf_filename;
return $this;
}
}

View file

@ -120,6 +120,32 @@ class Acc_Document extends Document {
$this->db->commit();
return true;
}
/**
* @brief for FACTURX we replace the PDF save in DB by this one, always
* a PDF (since it is a FACTURX document)
*/
function replace_receipt($new_oid)
{
if ($this->d_lob != "")
{
$this->db->lo_unlink($this->d_lob);
}
$this->d_lob=$new_oid;
$this->db->exec_sql("
update jrn
set
jr_pj = $1
,jr_pj_name =$2
,jr_pj_type =$3
where jr_id=$4
",
[$this->d_lob
,$this->d_filename
,$this->d_mimetype
,$this->d_id]
);
}
/**
* @brief save the Large Object $oid in the column JRN.JR_DOCUMENT_XML
* @param $oid( OID) PostgreSQL Object ID

View file

@ -59,6 +59,24 @@ class Document
$this->counter=0;
}
function __toString(): string
{
return "Document[db=" . $this->db
. ", d_id=" . $this->d_id
. ", ag_id=" . $this->ag_id
. ", d_mimetype=" . $this->d_mimetype
. ", d_filename=" . $this->d_filename
. ", d_lob=" . $this->d_lob
. ", d_description=" . $this->d_description
. ", d_number=" . $this->d_number
. ", md_id=" . $this->md_id
. ", f_id=" . $this->f_id
. ", counter=" . $this->counter
. ", d_name=" . $this->d_name
. ", md_type=" . $this->md_type
. "]";
}
/**
* @brief insert a minimal document and set the d_id
*/

View file

@ -66,6 +66,9 @@ if ( isset ($_POST['view_invoice'] ) )
$p_msg=$e->getMessage();
$correct=1;
}
//------------------------------------------------
// Confirm before saving
//------------------------------------------------
// if correct is not set it means it is correct
if ( ! isset($correct))
{
@ -219,7 +222,7 @@ if ( isset($_POST['record']) )
$xmldocument->set_pdf_filename($pdf_filename);
// make the XML + PDF
$xml=$xmldocument->make_xml($Ledger->jr_id);
$xml=$xmldocument->create_invoice($Ledger->jr_id);
if (DEBUGNOALYSS > 1) {
$mt=date ('ymd-Hi').'+'.$Ledger->jr_id;
$uniq= $_ENV['TMP']. DIRECTORY_SEPARATOR."$mt-e-invoice.xml";
@ -228,16 +231,24 @@ if ( isset($_POST['record']) )
echo \Noalyss\Dbg::echo_file("file save $uniq");
}
// FOR BELGIUM : XML and PDF will be store separately
// save XML string into the DB
$oid=$cn->lo_write($xml);
echo \Noalyss\Dbg::echo_var(1, "oid is $oid");
if ($oid == false) {
throw new Exception ('CV177 : cannot import e-invoice');
}
$acc_document->update_document_xml($oid);
if ( $g_parameter->MY_INVOICE_FORMAT == 'UBL21BEL')
{
$acc_document->update_document_xml($oid);
$receipt= HtmlInput::show_receipt_document($Ledger->jr_id,$acc_document->d_filename)
. $acc_document->link_download_xml();
}elseif ($g_parameter->MY_INVOICE_FORMAT=='FACTURXFR')
{
$acc_document->replace_receipt($oid);
$receipt= HtmlInput::show_receipt_document($Ledger->jr_id,$acc_document->d_filename);
}
$receipt= HtmlInput::show_receipt_document($Ledger->jr_id,$acc_document->d_filename)
. $acc_document->link_download_xml();
}
}