Factur-X norme 3 (May 15th, 2025)
This commit is contained in:
parent
8039f3438a
commit
fd21804f21
8 changed files with 361 additions and 202 deletions
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue