Merge branch '250826-e-einvoice' into unstable
* 250826-e-einvoice: (29 commits) Update VENDOR : remove useless Factur-X norme 3 (May 15th, 2025) E-INVOICE : if upload an XML file than the embedded document will be saved separately, if there is no embedded document a standard document with info from XML will be generated E-INVOICE , when loading a XML , the file is splitted into a PDF and XML XMLInvoiceReader : extract information from XML E-INVOICE : corrige PriceAmount E-INVOICE : show the XML to download Database: upload file function E-INVOICE : export XML if exists from ledger_detail_bottom E-INVOICE : create standard invoice if not convert E-INVOICE: small bugs UBL21 E-INVOICE: negative amount e-invoice : add communication , bank and buyer reference e-invoice : display errors if cannot be created Typo : space quantity PHPUNIT : adapt 12.3 E-INVOICE: check data before generating E-INVOICE: add missing for Belgium : BuyerReference and Due_Date E-INVOICE: add code quantity E-INVOICE : add AdditionalDocument XMLInvoice adapt currency ...
This commit is contained in:
commit
9898434767
169 changed files with 3614 additions and 15659 deletions
137
include/XMLDocument/Error_Message.php
Normal file
137
include/XMLDocument/Error_Message.php
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
<?php
|
||||
|
||||
namespace Noalyss\XMLDocument;
|
||||
|
||||
/*
|
||||
* This file is part of NOALYSS.
|
||||
*
|
||||
* NOALYSS is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* NOALYSS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with NOALYSS; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
// Copyright Author Dany De Bontridder danydb@aevalys.eu 22/10/23
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Give the error message thanks the code for FacturX and UBL21
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @brief Give the error message thanks the code for FacturX and UBL21
|
||||
*
|
||||
property $a_error (double array)
|
||||
keys :
|
||||
- general ,
|
||||
- customer,
|
||||
- ATTR_DEF_NAME=>'CUST_NAME'
|
||||
- ATTR_DEF_ADRESS=>'CUST_ADDR'
|
||||
- ATTR_DEF_POSTCODE=>'CUST_POSTCD'
|
||||
- ATTR_DEF_CITY=>'CUST_CITY'
|
||||
- ATTR_DEF_COUNTRY_CODE=>'CUST_CDCOUNTRY'
|
||||
- ATTR_DEF_NUMTVA=>'CUST_VAT'
|
||||
- ATTR_DEF_PEPPOLID=>'CUST_PEPPOLID'
|
||||
- company,
|
||||
- "INVOICE_EMAIL_COMPANY" company's email
|
||||
- 'INVOICE_CONTACT_NAME' contact name
|
||||
- 'COMPANY_LEGAL_ENTITY' legal form of company
|
||||
- 'COMPANY_LEGAL_REGISTRATION' full name
|
||||
- 'COMPANY_BANK_IBAN' IBAN bank account
|
||||
- 'COMPANY_BANK_BIC' BIC bank account
|
||||
- 'COMPANY_UBL_ID' PEPPOL id
|
||||
- 'MY_COUNTRY_CODE' country code (normally BE)
|
||||
- 'MY_NAME' short company name
|
||||
- 'MY_STREET' address
|
||||
- 'MY_CITY' address
|
||||
- 'MY_TVA' VAT number
|
||||
*
|
||||
*/
|
||||
class Error_Message
|
||||
{
|
||||
|
||||
private $a_error;
|
||||
private $a_message_company;
|
||||
private $a_message_customer;
|
||||
|
||||
/**
|
||||
* @brief constructo
|
||||
* @param $a_error (double array)
|
||||
*/
|
||||
public function __construct($a_error)
|
||||
{
|
||||
$this->a_error = $a_error;
|
||||
$this->a_message_company = array(
|
||||
"INVOICE_EMAIL_COMPANY" => _("L'email de la société ")
|
||||
, 'INVOICE_CONTACT_NAME' => _("Nom du contact")
|
||||
, 'COMPANY_LEGAL_ENTITY' => _("Type de société (SRL,ASBL,...)")
|
||||
, 'COMPANY_LEGAL_REGISTRATION' => _("Nom complet de la société")
|
||||
, 'COMPANY_BANK_IBAN' => _("Compte en banque (IBAN) de la société")
|
||||
, 'COMPANY_BANK_BIC' => _("Code BIC de compte en banque")
|
||||
, 'COMPANY_UBL_ID' => _("Identifiant PEPPOL")
|
||||
, 'MY_COUNTRY_CODE' => _('Code Pays')
|
||||
, 'MY_NAME' => _("Nom de la société")
|
||||
, '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")
|
||||
, 'street' => _("Adresse")
|
||||
, 'postalzone' => _("Code postal")
|
||||
, 'city' => _("Ville")
|
||||
, 'country'=>_("Code pays")
|
||||
, 'customer_id' => _("Numéro de TVA")
|
||||
, 'endpoint_id' => _('Identifiant PEPPOL')
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public function get_a_error()
|
||||
{
|
||||
return $this->a_error;
|
||||
}
|
||||
|
||||
public function set_a_error($a_error)
|
||||
{
|
||||
$this->a_error = $a_error;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief returns the text of an error
|
||||
* @param $code (string or number)
|
||||
* @param $type (string) customer , general or company
|
||||
*/
|
||||
function get_message_error($code, $type)
|
||||
{
|
||||
if ($type == "customer")
|
||||
{
|
||||
$a_error = $this->a_error['customer'];
|
||||
$a_message = $this->a_message_customer;
|
||||
} else if ($type == "company")
|
||||
{
|
||||
$a_error = $this->a_error['company'];
|
||||
$a_message = $this->a_message_company;
|
||||
} else
|
||||
{
|
||||
throw new \Exception("EM116: unknow type");
|
||||
}
|
||||
|
||||
return $a_message[$code];
|
||||
}
|
||||
}
|
||||
|
|
@ -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']
|
||||
);
|
||||
|
||||
$invoice->setCurrencyCode('EUR');
|
||||
$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
|
||||
//------------------------------------------------
|
||||
|
||||
$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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -23,12 +23,14 @@ namespace Noalyss\XMLDocument;
|
|||
|
||||
/**
|
||||
* @file
|
||||
* @brief answer to an inplace object
|
||||
* @brief UBL2.1 Belgique
|
||||
* - $pdf_filename PDF file to insert into XML, it is the file on the filesystem
|
||||
*/
|
||||
/**
|
||||
* @class
|
||||
* @brief UBL2.1 Belgique
|
||||
* @note Doit contenir le PDF
|
||||
* @note Doit contenir le PDF.
|
||||
* - $pdf_filename PDF file to insert into XML, it is the file on the filesystem
|
||||
@code
|
||||
<cac:Attachment>
|
||||
<cbc:EmbeddedDocumentBinaryObject mimeCode="application/pdf" filename="facture.pdf" encodingCode="Base64">
|
||||
|
|
@ -52,32 +54,37 @@ class InvoiceUBL21 extends XMLInvoice {
|
|||
, 'MY_STREET'
|
||||
, 'MY_CITY'
|
||||
, 'MY_TVA'
|
||||
, 'INVOICE_EMAIL_COMPANY'
|
||||
];
|
||||
protected $pdf_filename; //!< PDF file to insert into XML
|
||||
protected $pdf_filename; //!< PDF file to insert into XML,
|
||||
// it is the file on the filesystem
|
||||
public function get_pdf_filename() {
|
||||
return $this->pdf_filename;
|
||||
}
|
||||
|
||||
public function set_pdf_filename($pdf_filename) {
|
||||
$this->pdf_filename = $pdf_filename;
|
||||
return $this;
|
||||
/**
|
||||
* @brief display_error display a warning with all error
|
||||
*/
|
||||
function display_error()
|
||||
{
|
||||
$a_error=$this->verify();
|
||||
include NOALYSS_TEMPLATE."/invoiceUBL21-display_error.php";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief check that mandatory info are saved in the DB for company (seller)
|
||||
* @param $a_error (array) array of errors, empty if nothing found
|
||||
*/
|
||||
function check_company_data(&$a_error) {
|
||||
function check_company_data() {
|
||||
// var $a_error (array) contains the errors for the company
|
||||
$a_error=array();
|
||||
$company = $this->load_noalyss_parameter();
|
||||
foreach (InvoiceUBL21::EXTRA_PARAMETER as $item) {
|
||||
if (!isset($company[$item]) || $company[$item] == '') {
|
||||
if (!isset($company[$item]) || trim($company[$item]) == '') {
|
||||
$a_error[]=$item;
|
||||
}
|
||||
}
|
||||
if (count($a_error) == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return $a_error;
|
||||
}
|
||||
/**
|
||||
* @brief check that mandatory info are saved in the DB for customer
|
||||
|
|
@ -85,26 +92,26 @@ class InvoiceUBL21 extends XMLInvoice {
|
|||
* @param $a_error (array) array of errors, empty if nothing found
|
||||
* @todo : country code au lieu de country !!
|
||||
*/
|
||||
function check_customer_data($customer_id,&$a_error){
|
||||
$card=new \Fiche($this->cn,$customer_id);
|
||||
$a_needed=[ATTR_DEF_NAME=>_("Nom")
|
||||
,ATTR_DEF_ADRESS=>_("Adresse")
|
||||
,ATTR_DEF_POSTCODE=>_("Code postal")
|
||||
,ATTR_DEF_CITY=>_("Localité")
|
||||
,ATTR_DEF_COUNTRY_CODE=>_("Code pays")
|
||||
,ATTR_DEF_NUMTVA=>_("Numéro de TVA")
|
||||
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 (\noalyss_trim($card->get_attribute($item))=="") {
|
||||
printf (_("ATTENTION donnée manquante dans la fiche client [%s]"),$value);
|
||||
}
|
||||
if ( $this->data['customer'][$value]=="") {
|
||||
$a_error[]=$value;
|
||||
}
|
||||
}
|
||||
if (count($a_error) == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
return $a_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief transform an operation ($jr_id) into an array, which contains
|
||||
* needed information for making an e-invoice
|
||||
|
|
@ -113,61 +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);
|
||||
// subtotal for VAT
|
||||
var_dump($VAT_SubTotal);
|
||||
$n = \Noalyss\Invoicing\Utility::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
|
||||
|
|
@ -178,7 +135,8 @@ class InvoiceUBL21 extends XMLInvoice {
|
|||
$customer=$this->createElement('cac:AccountingCustomerParty');
|
||||
$customer_party=$customer->appendChild($this->createElement('cac:Party'));
|
||||
///@todo EndPointID doit être dans les paramètres (voir upgrade.sql)
|
||||
$customer_party->appendChild($this->createElement('cbc:EndpointID',"ERROR"))->setAttribute('schemeID', 9956);
|
||||
$customer_party->appendChild($this->createElement('cbc:EndpointID',$this->data['customer']['endpoint_id']))
|
||||
->setAttribute('schemeID', 9925);
|
||||
$party_name=$this->createElement('cac:PartyName');
|
||||
$party_name->appendChild($this->createElement("cbc:Name", $this->data['customer']['name']));
|
||||
$customer_party->appendChild($party_name);
|
||||
|
|
@ -187,9 +145,10 @@ class InvoiceUBL21 extends XMLInvoice {
|
|||
$postal_address->appendChild($this->createElement("cbc:CityName", $this->data['customer']['city']));
|
||||
$postal_address->appendChild($this->createElement("cbc:PostalZone", $this->data['customer']['postalzone']));
|
||||
///@todo customer = countryCode doit être dans les paramètres (voir upgrade.sql)
|
||||
$country_code ="ERROR";
|
||||
$country_code =$this->data['customer']['country'];
|
||||
$country=$postal_address->appendChild($this->createElement("cac:Country"));
|
||||
$country->appendChild($this->createElement('cbc:IdentificationCode',$country_code??"ERROR:COUNTRY_CODE"));
|
||||
|
||||
$country->appendChild($this->createElement('cbc:IdentificationCode',$country_code));
|
||||
$postal_address->appendChild($country);
|
||||
|
||||
// Tax Schem
|
||||
|
|
@ -231,16 +190,16 @@ class InvoiceUBL21 extends XMLInvoice {
|
|||
*/
|
||||
function build_paymentInfo()
|
||||
{
|
||||
$company = $this->load_noalyss_parameter();
|
||||
$payment=$this->createElement("cac:PaymentMeans");
|
||||
$payment->appendChild($this->createElement('cbc:PaymentMeansCode',30));
|
||||
///@note cbc:PaymentID est la communication lors du paiement
|
||||
$payment->appendChild($this->createElement('cbc:PaymentID',$this->data["id"]));
|
||||
$payment->appendChild($this->createElement('cbc:PaymentID',$this->data["info"]['communication']));
|
||||
$f=$this->createElement ('cac:PayeeFinancialAccount');
|
||||
///@todo customer = IBAN doit être dans les paramètres (voir upgrade.sql)
|
||||
$f->appendChild($this->createElement("cbc:ID", "ERROR:IBAN"));
|
||||
$f->appendChild($this->createElement("cbc:ID",$company['COMPANY_BANK_IBAN']));
|
||||
$g=$this->createElement("cac:FinancialInstitutionBranch");
|
||||
///@todo customer = BIC doit être dans les paramètres (voir upgrade.sql)
|
||||
$g->appendChild($this->createElement("cbc:ID", "ERROR:BIC"));
|
||||
$g->appendChild($this->createElement("cbc:ID", $company['COMPANY_BANK_BIC']));
|
||||
$f->appendChild($g);
|
||||
|
||||
$payment->appendChild($f);
|
||||
|
|
@ -255,7 +214,7 @@ class InvoiceUBL21 extends XMLInvoice {
|
|||
|
||||
$supplier=$this->createElement('cac:AccountingSupplierParty');
|
||||
$supplier_party=$supplier->appendChild($this->createElement('cac:Party'));
|
||||
$supplier_party->appendChild($this->createElement('cbc:EndpointID',$company['COMPANY_UBL_ID']??"ERROR"))->setAttribute('schemeID', 9956);
|
||||
$supplier_party->appendChild($this->createElement('cbc:EndpointID',$company['COMPANY_UBL_ID']))->setAttribute('schemeID', 9925);
|
||||
$party_name=$this->createElement('cac:PartyName');
|
||||
$party_name->appendChild($this->createElement('cbc:Name', $this->data['supplier']['name']));
|
||||
$supplier_party->appendChild($party_name);
|
||||
|
|
@ -325,20 +284,24 @@ class InvoiceUBL21 extends XMLInvoice {
|
|||
function build_taxTotal()
|
||||
{
|
||||
$taxTotal=$this->createElement("cac:TaxTotal");
|
||||
$taxTotal->appendChild($this->createElement('cbc:TaxAmount',$this->data['TaxAmount']))
|
||||
->setAttribute("currencyID","EUR");
|
||||
$taxTotal->appendChild($this->createElement('cbc:TaxAmount',sprintf("%.2f",$this->data['TaxAmount'])))
|
||||
->setAttribute("currencyID",$this->data['currency']);
|
||||
// for subTotal
|
||||
$subTotal=$this->data['subTotalVAT'];
|
||||
$nb_sub=count($subTotal);
|
||||
for ($i=0;$i<$nb_sub;$i++) {
|
||||
$subTotalXML=$this->createElement("cac:TaxSubtotal");
|
||||
$subTotalXML->appendChild($this->createElement('cbc:TaxableAmount',$subTotal[$i]['amount']))
|
||||
->setAttribute("currencyID","EUR");
|
||||
$subTotalXML->appendChild($this->createElement('cbc:TaxAmount',$subTotal[$i]['vat']))
|
||||
->setAttribute("currencyID","EUR");
|
||||
$subTotalXML->appendChild($this->createElement('cbc:TaxableAmount',sprintf("%.2f",$subTotal[$i]['amount'])))
|
||||
->setAttribute("currencyID", $this->data['currency']);
|
||||
$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"));
|
||||
$taxCategory->appendChild($this->createElement("cbc:Percent",$subTotal[$i]['percent']));
|
||||
/**
|
||||
* @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"));
|
||||
$taxCategory->appendChild($taxScheme);
|
||||
|
|
@ -363,14 +326,14 @@ class InvoiceUBL21 extends XMLInvoice {
|
|||
function build_legalMonetaryTotal()
|
||||
{
|
||||
$result=$this->createElement('cac:LegalMonetaryTotal' );
|
||||
$result->appendChild($this->createElement("cbc:LineExtensionAmount",$this->data['LineExtensionAmount']))
|
||||
->setAttribute("currencyID","EUR");
|
||||
$result->appendChild($this->createElement("cbc:TaxExclusiveAmount",$this->data['TaxExclusiveAmount']))
|
||||
->setAttribute("currencyID","EUR");
|
||||
$result->appendChild($this->createElement("cbc:TaxInclusiveAmount",$this->data['TaxInclusiveAmount']))
|
||||
->setAttribute("currencyID","EUR");
|
||||
$result->appendChild($this->createElement("cbc:PayableAmount",$this->data['PayableAmount']))
|
||||
->setAttribute("currencyID","EUR");
|
||||
$result->appendChild($this->createElement("cbc:LineExtensionAmount",sprintf("%.2f",$this->data['LineExtensionAmount'])))
|
||||
->setAttribute("currencyID",$this->data['currency']);
|
||||
$result->appendChild($this->createElement("cbc:TaxExclusiveAmount",sprintf("%.2f",$this->data['TaxExclusiveAmount'])))
|
||||
->setAttribute("currencyID",$this->data['currency']);
|
||||
$result->appendChild($this->createElement("cbc:TaxInclusiveAmount",sprintf("%.2f",$this->data['TaxInclusiveAmount'])))
|
||||
->setAttribute("currencyID", $this->data['currency'] );
|
||||
$result->appendChild($this->createElement("cbc:PayableAmount",sprintf("%.2f",$this->data['PayableAmount'])))
|
||||
->setAttribute("currencyID", $this->data['currency'] );
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
|
@ -404,30 +367,35 @@ class InvoiceUBL21 extends XMLInvoice {
|
|||
|
||||
$result=$this->createElement('cac:InvoiceLine');
|
||||
$row=$this->data["operation"][$i];
|
||||
$amount=sprintf("%.2f",$row['price']);
|
||||
|
||||
$result->appendChild($this->createElement("cbc:ID", $i));
|
||||
///@todo , les unités de quantités devraient être ajoutés à NOALYSS
|
||||
/// il faut adapter les fiches
|
||||
$amount=sprintf("%.2f",$row['price']);
|
||||
$result->appendChild(
|
||||
$this->createElement("cbc:InvoicedQuantity", $row['quantity']))
|
||||
->setAttribute("unitCode", "EA");
|
||||
$result->appendChild($this->createElement("cbc:LineExtensionAmount", $row['price']))
|
||||
->setAttribute("currencyID","EUR");
|
||||
$this->createElement("cbc:InvoicedQuantity", sprintf("%.2f",$row['quantity'])))
|
||||
->setAttribute("unitCode", $row["code_quantity"]);
|
||||
$result->appendChild($this->createElement("cbc:LineExtensionAmount", $amount))
|
||||
->setAttribute("currencyID",$this->data['currency']);
|
||||
|
||||
// ITEM
|
||||
$item=$this->createElement("cac:Item");
|
||||
$card=new \Fiche($this->cn,$row['card_id']);
|
||||
$item->appendChild($this->createElement("cbc:Name", $card->get_attribute(ATTR_DEF_NAME)));
|
||||
$item->appendChild($this->createElement("cbc:Description",$row['name']));
|
||||
$item->appendChild($this->createElement("cbc:Name", $row['qcode']));
|
||||
$classifiedTaxCat=$this->createElement("cac:ClassifiedTaxCategory");
|
||||
///@todo cbc:ID S = standard rate et que se passe-t'il pour l'autoliquidation ???
|
||||
/// Il faut ajouter dans TVA_RATE , un code pour la TVA,
|
||||
$classifiedTaxCat->appendChild($this->createElement("cbc:ID", "S"));
|
||||
$classifiedTaxCat->appendChild($this->createElement("cbc:Percent", $row['vat_percent']));
|
||||
|
||||
//cbc:ID S = standard rate
|
||||
/// see TVA_RATE.TVA_PEPPOL_CODE & C0TVA
|
||||
$classifiedTaxCat->appendChild($this->createElement("cbc:ID", $row['vat_code']));
|
||||
$classifiedTaxCat->appendChild($this->createElement("cbc:Percent", sprintf("%.2f",$row['vat_percent'])));
|
||||
|
||||
$tax_scheme=$this->createElement('cac:TaxScheme');
|
||||
$tax_scheme->appendChild($this->createElement("cbc:ID", "VAT"));
|
||||
$classifiedTaxCat->appendChild($tax_scheme);
|
||||
$item->appendChild($classifiedTaxCat);
|
||||
$result->appendChild($item);
|
||||
$price=$result->appendChild($this->createElement("cac:Price"));
|
||||
$price->appendChild($this->createElement("cbc:PriceAmount", $row['price']))
|
||||
->setAttribute("currencyID","EUR");
|
||||
$price->appendChild($this->createElement("cbc:PriceAmount",sprintf("%.2f",abs($row['price_unit']))))
|
||||
->setAttribute("currencyID",$this->data['currency']);
|
||||
$result->appendChild($price);
|
||||
|
||||
return $result;
|
||||
|
|
@ -435,10 +403,10 @@ class InvoiceUBL21 extends XMLInvoice {
|
|||
}
|
||||
/**
|
||||
* @brief Insert a PDF in the XML
|
||||
* the document type is not due for BELGIUM
|
||||
@code
|
||||
<cac:AdditionalDocumentReference>
|
||||
<cbc:ID>P01</cbc:ID>
|
||||
<cbc:DocumentType>InvoicePDF</cbc:DocumentType>
|
||||
<cbc:DocumentDescription>Facture PDF</cbc:DocumentDescription>
|
||||
<cac:Attachment>
|
||||
<cbc:EmbeddedDocumentBinaryObject
|
||||
|
|
@ -449,7 +417,6 @@ class InvoiceUBL21 extends XMLInvoice {
|
|||
<!-- OU -->
|
||||
<cac:AdditionalDocumentReference>
|
||||
<cbc:ID>REF_ODT_001</cbc:ID>
|
||||
<cbc:DocumentType>OpenDocument</cbc:DocumentType>
|
||||
<cbc:DocumentDescription>Fichier OpenDocument</cbc:DocumentDescription>
|
||||
<cac:Attachment>
|
||||
<cbc:EmbeddedDocumentBinaryObject
|
||||
|
|
@ -465,14 +432,31 @@ class InvoiceUBL21 extends XMLInvoice {
|
|||
function build_Invoice():\DOMElement
|
||||
{
|
||||
if ( $this->pdf_filename == "") return null;
|
||||
$result=$this->createElement("AdditionalDocumentReference");
|
||||
/** $pdf_filename = 'chemin/vers/votre/fichier.pdf';*/
|
||||
|
||||
static $i=0;
|
||||
$i++;
|
||||
if ( $this->pdf_filename == null ) {
|
||||
return null;
|
||||
}
|
||||
// Lire le fichier PDF
|
||||
// $pdfContent = file_get_contents($pdfPath);
|
||||
$pdfContent = file_get_contents( $this->pdf_filename );
|
||||
|
||||
// Encoder le PDF en base64
|
||||
// $base64Pdf = base64_encode($pdfContent);
|
||||
$result=$this->createElement("cac:AdditionalDocumentReference");
|
||||
$id=$this->createElement("cbc:ID",$i);
|
||||
$document_description=$this->createElement("cbc:DocumentDescription"
|
||||
, $this->data['description']);
|
||||
|
||||
// PDF in base64
|
||||
$base64Pdf = base64_encode($pdfContent);
|
||||
$embeddedDocument=$this->createElement("cbc:EmbeddedDocumentBinaryObject",$base64Pdf);
|
||||
$embeddedDocument->setAttribute("mimeCode", "application/pdf");
|
||||
$embeddedDocument->setAttribute("filename", "facture.pdf");
|
||||
$attachment=$this->createElement("cac:Attachment");
|
||||
$attachment->appendChild($embeddedDocument);
|
||||
|
||||
$result->appendChild($id);
|
||||
$result->appendChild($document_description);
|
||||
$result->appendChild($attachment);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
|
@ -496,12 +480,14 @@ class InvoiceUBL21 extends XMLInvoice {
|
|||
|
||||
$root->appendChild($this->createElement('cbc:ID',$this->data['id']));
|
||||
$root->appendChild($this->createElement('cbc:IssueDate',$this->data['issue_date']));
|
||||
if ($this->data ['due_date'] != '') {
|
||||
$root->appendChild($this->createElement('cbc:DueDate',$this->data['due_date']));
|
||||
if ($this->data ['due_date'] == '')
|
||||
{
|
||||
$this->data ['due_date']=$this->data['issue_date'];
|
||||
}
|
||||
$root->appendChild($this->createElement('cbc:DueDate',$this->data['due_date']));
|
||||
$root->appendChild($this->createElement('cbc:InvoiceTypeCode',380));
|
||||
$root->appendChild($this->createElement('cbc:DocumentCurrencyCode','EUR'));
|
||||
|
||||
$root->appendChild($this->createElement('cbc:DocumentCurrencyCode',$this->data['currency']));
|
||||
$root->appendChild($this->createElement('cbc:BuyerReference',$this->data['info']['order']));
|
||||
/**
|
||||
* insert PDF in the XML
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
namespace Noalyss\XMLDocument;
|
||||
|
||||
use Noalyss\Utility;
|
||||
//use Noalyss\Utility;
|
||||
/*
|
||||
* This file is part of NOALYSS.
|
||||
*
|
||||
|
|
@ -57,6 +57,9 @@ use Noalyss\Utility;
|
|||
)
|
||||
|
||||
[currency] => 0
|
||||
[info] => Array
|
||||
[order] = order reference
|
||||
[communication] = communication added to the invoice
|
||||
[operation] => Array
|
||||
(
|
||||
[0] => Array
|
||||
|
|
@ -67,6 +70,8 @@ use Noalyss\Utility;
|
|||
[vat] => 2.1000
|
||||
[vat_id] => 1
|
||||
[vat_reversed] => 0.0000
|
||||
[code_quantity]=> EA
|
||||
[vat_code]=> Code VAT for PEPPOL (S,K,...)
|
||||
)
|
||||
|
||||
[1] => Array
|
||||
|
|
@ -77,6 +82,8 @@ use Noalyss\Utility;
|
|||
[vat] => 17.5200
|
||||
[vat_id] => 1
|
||||
[vat_reversed] => 0.0000
|
||||
[code_quantity]=> EA
|
||||
[vat_code]=> Code VAT for PEPPOL (S,K,...)
|
||||
)
|
||||
|
||||
[2] => Array
|
||||
|
|
@ -87,6 +94,8 @@ use Noalyss\Utility;
|
|||
[vat] => 15.1200
|
||||
[vat_id] => 5
|
||||
[vat_reversed] => 15.1200
|
||||
[code_quantity]=> EA
|
||||
[vat_code]=> Code VAT for PEPPOL (S,K,...)
|
||||
)
|
||||
|
||||
)
|
||||
|
|
@ -100,7 +109,8 @@ use Noalyss\Utility;
|
|||
abstract class XMLInvoice extends \DOMDocument
|
||||
{
|
||||
protected $cn; //!< Database conx , current folder
|
||||
protected $data; //! $data Array data retrieve from DB
|
||||
protected $data; //! $data (Array) data retrieve from DB
|
||||
protected $jr_id; //! $jr_id (int) is JRN.JR_ID
|
||||
function __construct(\Database $conx)
|
||||
{
|
||||
parent::__construct("1.0", "UTF-8");
|
||||
|
|
@ -154,71 +164,149 @@ abstract class XMLInvoice extends \DOMDocument
|
|||
function build_data($jr_id):array
|
||||
{
|
||||
global $g_parameter;
|
||||
$this->jr_id=$jr_id;
|
||||
$operation = new \Acc_Sold($this->cn,$jr_id);
|
||||
|
||||
$operation->get();
|
||||
$result=array();
|
||||
$result["id"]= $operation->det->jr_pj_number;
|
||||
$result["issue_date"]=$operation->det->jr_date;
|
||||
$result["due_date"]=$operation->det->jr_ech;
|
||||
$result["due_date"]=($operation->det->jr_ech=="")?$operation->det->jr_date:$operation->det->jr_ech;
|
||||
// supplier
|
||||
$result['supplier']=array();
|
||||
$result['supplier']['name']=$g_parameter->MY_NAME;
|
||||
$result['supplier']['street']=$g_parameter->MY_STREET;
|
||||
$result['supplier']['postalzone']=$g_parameter->MY_POSTCODE;
|
||||
$result['supplier']['city']=$g_parameter->MY_CITY;
|
||||
$result['supplier']['country']=$g_parameter->MY_COUNTRY;
|
||||
$result['supplier']['supplier_id']=$g_parameter->MY_TVA;
|
||||
// official name of the company
|
||||
$result['supplier']['registration_name']=$g_parameter->MY_NAME;
|
||||
// official ID , like VAT
|
||||
$result['supplier']['supplier_id']=str_replace([" ",".","-","/"],"" ,$g_parameter->MY_TVA);
|
||||
//@todo
|
||||
//Autre parametre comme email dans Parameter_Extra_SQL
|
||||
//
|
||||
//
|
||||
// == $result['supplier']['supplier_email']=$g_parameter->;
|
||||
//@todo TESTER S'IL Y A QQ'CHOSE DE VENDU !
|
||||
$result['supplier']=$this->fill_supplier();
|
||||
|
||||
|
||||
//customer
|
||||
$customer=new \Fiche($this->cn,$operation->det->array[0]['qs_client']);
|
||||
$result['customer']=array();
|
||||
$result['customer']['card_id']=$operation->det->array[0]['qs_client'];
|
||||
$result['customer']['name']=$customer->get_attribute(ATTR_DEF_NAME);
|
||||
$result['customer']['street']=$customer->get_attribute(ATTR_DEF_ADRESS);
|
||||
$result['customer']['postalzone']=$customer->get_attribute(ATTR_DEF_POSTCODE);
|
||||
$result['customer']['city']=$customer->get_attribute(ATTR_DEF_CITY);
|
||||
$result['customer']=$this->fill_customer($operation->det->array[0]['qs_client']);
|
||||
|
||||
// find country_code of this card
|
||||
// currency
|
||||
$result['currency']=$this->cn->get_value("select cr_code_iso from currency where id=$1"
|
||||
,array($operation->det->currency_id));
|
||||
|
||||
$result['customer']['country']=$customer->get_attribute(ATTR_DEF_COUNTRY);
|
||||
// document description
|
||||
$result['description']=$operation->det->jr_comment;
|
||||
|
||||
$result['customer']['customer_id']=str_replace([" ",".","-","/"],"" ,$customer->get_attribute(ATTR_DEF_NUMTVA));
|
||||
// official name of the company
|
||||
$result['customer']['registration_name']=$customer->get_attribute(ATTR_DEF_NAME);
|
||||
// official ID , like VAT
|
||||
$result['customer']['customer_id']=$customer->get_attribute(ATTR_DEF_NUMTVA);
|
||||
// +++TODO+++ adapt for all currency
|
||||
// currency must be EURO !
|
||||
$result['currency']=$operation->det->currency_id;
|
||||
// goods and services
|
||||
$result['operation']=array();
|
||||
|
||||
$nb_operation= count($operation->det->array);
|
||||
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'];
|
||||
$result['operation'][$i]['price']=$operation->det->array[$i]['qs_price'];
|
||||
$result['operation'][$i]['vat']=$operation->det->array[$i]['qs_vat'];
|
||||
$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->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
|
||||
if ($operation->det->currency_id == 0 ) {
|
||||
$result['operation'][$i]['price']=$operation->det->array[$i]['qs_price'];
|
||||
$result['operation'][$i]['price_unit']=$operation->det->array[$i]['qs_unit'];
|
||||
$result['operation'][$i]['vat']=$operation->det->array[$i]['qs_vat'];
|
||||
} else {
|
||||
$result['operation'][$i]['price']=$operation->det->array[$i]['oc_amount'];
|
||||
$result['operation'][$i]['price_unit']=bcdiv(
|
||||
$operation->det->array[$i]['oc_amount'],
|
||||
$operation->det->array[$i]['qs_quantite'],
|
||||
2);
|
||||
$result['operation'][$i]['vat']=$operation->det->array[$i]['oc_vat_amount'];
|
||||
|
||||
}
|
||||
$result['operation'][$i]['vat_id']=$operation->det->array[$i]['qs_vat_code'];
|
||||
// // tva code for PEPPOL
|
||||
$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['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'];
|
||||
}
|
||||
print_r($result);
|
||||
//------------------------------------------------
|
||||
// retrieve order and comment
|
||||
//------------------------------------------------
|
||||
$a_row=$this->cn->get_array("select id_type,ji_value from jrn_info where jr_id=$1"
|
||||
,[$jr_id]);
|
||||
$nb_row = count($a_row);
|
||||
$result['info']=[];
|
||||
$result['info']['order']='NA';
|
||||
$result['info']['communication']='';
|
||||
for($i=0;$i<$nb_row;$i++) {
|
||||
switch ($a_row[$i]['id_type']) {
|
||||
case 'BON_COMMANDE':
|
||||
$result['info']['order']=$a_row[$i]['ji_value'];
|
||||
break;
|
||||
case 'OTHER':
|
||||
$result['info']['communication']=$a_row[$i]['ji_value'];
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
$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
|
||||
* @return array
|
||||
* @return array keys : pe_code,pe_value
|
||||
*/
|
||||
function load_noalyss_parameter()
|
||||
{
|
||||
|
|
@ -238,19 +326,218 @@ abstract class XMLInvoice extends \DOMDocument
|
|||
abstract function make_xml($jr_id);
|
||||
/**
|
||||
* @brief check that mandatory info are saved in the DB for company (seller)
|
||||
* @param $a_error (array) array of errors, empty if nothing found
|
||||
*/
|
||||
abstract function check_company_data(&$a_error) ;
|
||||
abstract function check_company_data() ;
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
abstract function check_customer_data($customer_id,&$a_error) ;
|
||||
abstract function check_customer_data($customer_id) ;
|
||||
/**
|
||||
* @brief create the invoice in the right format, with PDF if any
|
||||
* @param $operation_id (int) JRN.JR_ID
|
||||
* @return string : XML or PDF format
|
||||
*/
|
||||
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
|
||||
* - FacturX => FACTURXFR
|
||||
* @returns null MY_INVOICE_FORMAT is BASIC
|
||||
*/
|
||||
static function build_xmlinvoice(\Database $conx) {
|
||||
global $g_parameter;
|
||||
if ($g_parameter->MY_INVOICE_FORMAT == 'UBL21BEL') {
|
||||
return new \Noalyss\XMLDocument\InvoiceUBL21($conx);
|
||||
}
|
||||
if ($g_parameter->MY_INVOICE_FORMAT == 'FACTURXFR') {
|
||||
return new \Noalyss\XMLDocument\FacturX($conx);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check that all the data are correct
|
||||
* @returns null : no errors, string separated with comma of error code
|
||||
* @see get_message_error
|
||||
*/
|
||||
public function verify()
|
||||
{
|
||||
// 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
|
||||
* @return array keys :
|
||||
* - name
|
||||
* - ,street
|
||||
* - ,postalzone
|
||||
* - ,city
|
||||
* - ,country
|
||||
* - ,customer_id => VAT Number
|
||||
* - , registration_name,
|
||||
* - card_id
|
||||
*/
|
||||
function fill_customer($card_id):array
|
||||
{
|
||||
$customer =new \Fiche($this->cn,$card_id);
|
||||
$result=array();
|
||||
$result['card_id']=$card_id;
|
||||
$result['name']=$customer->get_attribute(ATTR_DEF_NAME,0);
|
||||
$result['street']=$customer->get_attribute(ATTR_DEF_ADRESS,0);
|
||||
$result['postalzone']=$customer->get_attribute(ATTR_DEF_POSTCODE,0);
|
||||
$result['city']=$customer->get_attribute(ATTR_DEF_CITY,0);
|
||||
|
||||
// find country_code of this card
|
||||
$result['country']=$customer->get_attribute(ATTR_DEF_COUNTRY_CODE,0);
|
||||
|
||||
// official ID , like VAT
|
||||
$result['customer_id']=str_replace([" ",".","-","/"],"" ,$customer->get_attribute(ATTR_DEF_NUMTVA,0));
|
||||
// official name of the company
|
||||
$result['registration_name']=$customer->get_attribute(ATTR_DEF_NAME,0);
|
||||
$result['endpoint_id']=$customer->get_attribute(ATTR_DEF_PEPPOLID,0);
|
||||
return $result;
|
||||
}
|
||||
/**
|
||||
* @brief complete $this->data from $g_parameter (global variable) for
|
||||
* Noalyss_Folder_Parameter
|
||||
* @return array keys :
|
||||
* - name
|
||||
* - ,street
|
||||
* - ,postalzone
|
||||
* - ,city
|
||||
* - ,country
|
||||
* - supplier_id => VAT Number
|
||||
* - registration_name,
|
||||
*
|
||||
*/
|
||||
function fill_supplier():array
|
||||
{
|
||||
$a_parameter=$this->load_noalyss_parameter();
|
||||
$result=array();
|
||||
$result['name']=$a_parameter['MY_NAME'];
|
||||
$result['street']=$a_parameter['MY_STREET'];
|
||||
$result['postalzone']=$a_parameter['MY_POSTCODE'];
|
||||
$result['city']=$a_parameter['MY_CITY'];
|
||||
$result['country']=$a_parameter['MY_COUNTRY'];
|
||||
// official name of the company
|
||||
$result['registration_name']=$a_parameter['MY_NAME'];
|
||||
// official ID , like VAT
|
||||
$result['supplier_id']=str_replace([" ",".","-","/"],"" ,$a_parameter['MY_TVA']);
|
||||
$result['COUNTRY_CODE']=$a_parameter['COUNTRY_CODE']??"";
|
||||
$result['COMPANY_LEGAL_REGISTRATION']=$a_parameter['COMPANY_LEGAL_REGISTRATION']??"";
|
||||
$result['COMPANY_LEGAL_ENTITY']=$a_parameter['COMPANY_LEGAL_ENTITY']??"";
|
||||
$result['INVOICE_CONTACT_NAME']=$a_parameter['INVOICE_CONTACT_NAME']??"";
|
||||
$result['INVOICE_EMAIL_COMPANY']=$a_parameter['INVOICE_EMAIL_COMPANY']??"";
|
||||
$result['COMPANY_UBL_ID']=$a_parameter['COMPANY_UBL_ID']??"";
|
||||
return $result;
|
||||
}
|
||||
/**
|
||||
* @brief build operation from array
|
||||
* key :
|
||||
* - [e_march0] => Quick code of the item
|
||||
- [e_march0_label] => Label of item
|
||||
- [e_march0_price] => Unit Price
|
||||
- [e_quant0] => Quantity
|
||||
- [htva_march0] => Price w/0 VAT
|
||||
- [e_march0_tva_id] => Code VAT
|
||||
- [e_march0_tva_amount] => Amount VAT
|
||||
- [tva_march0] => Amount VAT (duplicate -> to remove)
|
||||
- [tvac_march0] => Total Amount Tax included
|
||||
* @param type $a_array
|
||||
* @return type
|
||||
*/
|
||||
function fill_operation_from_array($a_array)
|
||||
{
|
||||
$result=array();
|
||||
$http=new \HttpInput();
|
||||
$http->set_array($a_array);
|
||||
|
||||
$nb_item=$http->get_value("nb_item");
|
||||
for ($i=0;$i<$nb_item;$i++)
|
||||
{
|
||||
if ( $http->get_value("e_march{$i}_tva_id") == "")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$operation=array();
|
||||
$card=\Fiche::from_qcode($this->cn,trim($http->get_value("e_march{$i}")));
|
||||
$operation['card_id']=$card->id;
|
||||
$operation['quantity']=$http->get_value("e_quant{$i}");
|
||||
$operation['price']=$http->get_value("e_march{$i}_price");
|
||||
$operation['vat']=$http->get_value("tvac_march{$i}");
|
||||
$tva= \Acc_Tva::build($this->cn, $http->get_value("e_march{$i}_tva_id"));
|
||||
$operation['vat_id']=$tva->tva_id;
|
||||
$operation['vat_reversed']=($tva->tva_both_side==1)?$operation['vat']:0;
|
||||
$operation['vat_code']=$tva->tva_peppol_code;
|
||||
|
||||
$operation['code_quantity']=$card->get_attribute(ATTR_DEF_QUANTITY_TYPE,0);
|
||||
$operation['code_quantity']=($operation['code_quantity']=="")?"EA":$operation['code_quantity'];
|
||||
$result[$i]=$operation;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
540
include/XMLDocument/xmlinvoice_reader.class.php
Normal file
540
include/XMLDocument/xmlinvoice_reader.class.php
Normal file
|
|
@ -0,0 +1,540 @@
|
|||
<?php
|
||||
|
||||
namespace Noalyss\XMLDocument;
|
||||
|
||||
/*
|
||||
* This file is part of NOALYSS.
|
||||
*
|
||||
* NOALYSS is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* NOALYSS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with NOALYSS; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
// Copyright Author Dany De Bontridder danydb@aevalys.eu 22/10/23
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief extract information from UBL21
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Get information from an XML
|
||||
* Exception code :
|
||||
* - 55 : XML Invalid
|
||||
* - 62 : filename don't exist
|
||||
*/
|
||||
class XMLInvoice_Reader
|
||||
{
|
||||
|
||||
protected \DOMDocument $domDocument;
|
||||
protected readonly \DOMXPath $xpath;
|
||||
|
||||
public function __construct(\DOMDocument $domDocument)
|
||||
{
|
||||
$this->domDocument = $domDocument;
|
||||
$this->xpath = new \DOMXPath($this->domDocument);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return \DOMDocument
|
||||
*/
|
||||
public function get_domDocument(): \DOMDocument
|
||||
{
|
||||
return $this->domDocument;
|
||||
}
|
||||
|
||||
public function get_xpath(): \DOMXPath
|
||||
{
|
||||
return $this->xpath;
|
||||
}
|
||||
|
||||
public function set_domDocument($domDocument)
|
||||
{
|
||||
$this->domDocument = $domDocument;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build an XMLInvoice_Reader object from an XML string
|
||||
* @param $string (string) XML
|
||||
* @return \Noalyss\XMLDocument\XMLInvoice_Reader
|
||||
* @throws \Exception if xml not valid
|
||||
*/
|
||||
static function build_from_string($string)
|
||||
{
|
||||
$dm = new \DOMDocument();
|
||||
if ($dm->loadXML($string) != false)
|
||||
{
|
||||
return new XMLInvoice_Reader($dm);
|
||||
} else
|
||||
{
|
||||
throw new \Exception("XR55: not a valid XML");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build an XMLInvoice_Reader object from an XML file
|
||||
* @param $filename (string) file and path to the file
|
||||
* @return \Noalyss\XMLDocument\XMLInvoice_Reader
|
||||
* @throws \Exception if xml not valid
|
||||
*/
|
||||
static function build_from_file($filename)
|
||||
{
|
||||
if (!file_exists($filename))
|
||||
{
|
||||
throw new \Exception("XR62: file not found $filename", 62);
|
||||
}
|
||||
$dm = new \DOMDocument();
|
||||
if ($dm->load($filename) != false)
|
||||
{
|
||||
return new XMLInvoice_Reader($dm);
|
||||
} else
|
||||
{
|
||||
throw new \Exception("XR55: not a valid XML", 55);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief execute a XPATH query of the DOMDocument and return the result
|
||||
* or null if nothing found
|
||||
* @param $query (string) valid XPath Query
|
||||
* @return null or DOMNodeList or DOMElement
|
||||
*/
|
||||
public function get_node($query)
|
||||
{
|
||||
if ($this->xpath->query($query)->length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return $this->xpath->query($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief returns the embedded document in an array (keys : filecontent (BYTES),mimecode , filename)
|
||||
* or false if there is no document
|
||||
* @return bool|array keys : filecontent (BYTES),mimecode , filename)
|
||||
* or false if there is no document
|
||||
* @throws \Exception if there are several documents
|
||||
*
|
||||
*/
|
||||
public function get_embedded_document()
|
||||
{
|
||||
if (($node = $this->get_node("//cac:AdditionalDocumentReference")) == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ($node->length > 1)
|
||||
{
|
||||
throw new \Exception("XR110 Too many documents found", 110);
|
||||
}
|
||||
///@var DOMNodeList $data //cac:AdditionalDocumentReference[1]/cac:Attachment[1]/cbc:EmbeddedDocumentBinaryObject[1]
|
||||
if (
|
||||
($data = $this->get_node("//cac:AdditionalDocumentReference[1]/cac:Attachment[1]/cbc:EmbeddedDocumentBinaryObject[1]")) == null
|
||||
)
|
||||
{
|
||||
|
||||
throw new \Exception("X116 Document corrupted", 116);
|
||||
}
|
||||
$filecontent = base64_decode($data->item(0)->nodeValue);
|
||||
$mimecode = $data->item(0)->getAttribute("mimeCode");
|
||||
$filename = $data->item(0)->getAttribute("filename");
|
||||
return array("filecontent" => $filecontent,
|
||||
"mimecode" => $mimecode,
|
||||
"filename" => $filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the node value
|
||||
* @param $query (string) valid XPath query
|
||||
* @param $ix (int) the item number
|
||||
* @return string
|
||||
*/
|
||||
function get_node_value($query, $ix = 0)
|
||||
{
|
||||
return $this->get_node($query)?->item($ix)?->nodeValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the customer info from XML
|
||||
* @return array
|
||||
*/
|
||||
function get_customer(): array
|
||||
{
|
||||
$result = [];
|
||||
$result['ID'] = $this->get_node_value("//cac:AccountingCustomerParty[1]/cac:Party[1]/cbc:EndpointID[1]");
|
||||
$result['name'] = $this->get_node_value('//cac:AccountingCustomerParty[1]/cac:Party[1]/cac:PartyName[1]/cbc:Name[1]');
|
||||
$result['street'] = $this->get_node_value('//cac:AccountingCustomerParty[1]/cac:Party[1]/cac:PostalAddress[1]/cbc:StreetName[1]');
|
||||
$result['city'] = $this->get_node_value('//cac:AccountingCustomerParty[1]/cac:Party[1]/cac:PostalAddress[1]/cbc:CityName[1]');
|
||||
$result['postcode'] = $this->get_node_value('//cac:AccountingCustomerParty[1]/cac:Party[1]/cac:PostalAddress[1]/cbc:PostalZone[1]');
|
||||
$result['country_code'] = $this->get_node_value("//cac:AccountingCustomerParty[1]/cac:Party[1]/cac:PostalAddress[1]/cac:Country[1]/cbc:IdentificationCode[1]");
|
||||
$result['company_id'] = $this->get_node_value("//cac:AccountingCustomerParty[1]/cac:Party[1]/cac:PartyTaxScheme[1]/cbc:CompanyID[1]");
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the supplier info from XML
|
||||
* @return array
|
||||
*/
|
||||
function get_supplier(): array
|
||||
{
|
||||
$result = [];
|
||||
$result['ID'] = $this->get_node_value("//cac:AccountingSupplierParty[1]/cac:Party[1]/cbc:EndpointID[1]");
|
||||
$result['name'] = $this->get_node_value("//cac:AccountingSupplierParty[1]/cac:Party[1]/cac:PartyName[1]/cbc:Name[1]");
|
||||
$result['street'] = $this->get_node_value("//cac:AccountingSupplierParty[1]/cac:Party[1]/cac:PostalAddress[1]/cbc:StreetName[1]");
|
||||
$result['city'] = $this->get_node_value("//cac:AccountingSupplierParty[1]/cac:Party[1]/cac:PostalAddress[1]/cbc:CityName[1]");
|
||||
$result['postcode'] = $this->get_node_value("//cac:AccountingSupplierParty[1]/cac:Party[1]/cac:PostalAddress[1]/cbc:PostalZone[1]");
|
||||
$result['country_code'] = $this->get_node_value("//cac:AccountingSupplierParty[1]/cac:Party[1]/cac:PostalAddress[1]/cac:Country[1]/cbc:IdentificationCode[1]");
|
||||
$result['company_id'] = $this->get_node_value("//cac:AccountingSupplierParty[1]/cac:Party[1]/cac:PartyTaxScheme[1]/cbc:CompanyID[1]");
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the Taxes info from XML
|
||||
* @return array
|
||||
*/
|
||||
function get_taxes(): array
|
||||
{
|
||||
$result = [];
|
||||
$node = $this->get_node("//cac:TaxTotal/cac:TaxSubtotal");
|
||||
|
||||
for ($e = 0; $e < $node->length; $e++)
|
||||
{
|
||||
$row = [];
|
||||
$xml = simplexml_import_dom($node->item($e));
|
||||
// /Invoice/cac:TaxTotal[1]/cac:TaxSubtotal[1]/cbc:TaxableAmount[1]
|
||||
|
||||
$row ['taxable_amount'] = $xml->xpath("//cbc:TaxableAmount")[$e] . "";
|
||||
$row ['tax'] = $xml->xpath("//cbc:TaxAmount")[$e] . "";
|
||||
$row ['tax_id'] = $xml->xpath("//cac:TaxCategory/cbc:ID")[$e] . "";
|
||||
$row ['tax_percent'] = $xml->xpath("//cac:TaxCategory/cbc:Percent")[$e] . "";
|
||||
// $row ['name'] =$xml->xpath("//cac:InvoiceLine/cac:Item/cbc:Name")[$e]."<br>";
|
||||
/**
|
||||
* @TODODNY
|
||||
* Implémenter les allowances
|
||||
*/
|
||||
$result[] = $row;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief retrieve InvoiceLines
|
||||
* @TODO XMLInvoice_Reader->get_invoiceLine * Implémenter les allowances
|
||||
*/
|
||||
function get_invoiceLine(): array
|
||||
{
|
||||
$result = [];
|
||||
$node = $this->get_node("//cac:InvoiceLine");
|
||||
for ($e = 0; $e < $node->length; $e++)
|
||||
{
|
||||
$row = [];
|
||||
$xml = simplexml_import_dom($node->item($e));
|
||||
//var_dump($xml->asXML());
|
||||
$row ['quantity'] = $this->get_node_value("//cbc:InvoicedQuantity", $e);
|
||||
$row ['amount'] = $this->get_node_value("//cbc:LineExtensionAmount", $e);
|
||||
$row ['description'] = $this->get_node_value("//cac:Item/cbc:Description", $e);
|
||||
$row ['name'] = $this->get_node_value("//cac:InvoiceLine/cac:Item/cbc:Name", $e);
|
||||
$row ['unit_price'] = $this->get_node_value("//cac:InvoiceLine/cac:Price/cbc:PriceAmount", $e);
|
||||
$row ['tva_id'] = $this->get_node_value("//cac:InvoiceLine/cac:Item/cac:ClassifiedTaxCategory/cbc:ID", $e);
|
||||
$row ['tva_percent'] = $this->get_node_value("//cac:InvoiceLine/cac:Item/cac:ClassifiedTaxCategory/cbc:Percent", $e);
|
||||
|
||||
$result[] = $row;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the Payment Means info from XML
|
||||
* @return array
|
||||
*/
|
||||
function get_payment_mean(): array
|
||||
{
|
||||
$result = [];
|
||||
$result['payment_code'] = $this->get_node_value("//cac:PaymentMeans[1]/cbc:PaymentMeansCode[1]");
|
||||
$result['label'] = $this->get_node_value("//cac:PaymentMeans[1]/cbc:PaymentID[1]");
|
||||
$result['iban'] = $this->get_node_value("//cac:PaymentMeans[1]/cac:PayeeFinancialAccount[1]/cbc:ID[1]");
|
||||
$result['bic'] = $this->get_node_value("//cac:PaymentMeans[1]/cac:PayeeFinancialAccount[1]/cac:FinancialInstitutionBranch[1]/cbc:ID[1]");
|
||||
$result['note'] = [];
|
||||
$note = $this->get_node("//cac:PaymentTerms/cbc:Note");
|
||||
if ($note != null)
|
||||
{
|
||||
$a = $note->length;
|
||||
for ($i = 0; $i < $a; $i++)
|
||||
{
|
||||
$result['note'][] = $note->item(0)->nodeValue;
|
||||
}
|
||||
}
|
||||
/**
|
||||
<cac:PaymentTerms>
|
||||
<cbc:Note> In geval van betaling binnen 14 dagen is 2% (52.00€) betalingskorting van
|
||||
toepassing en het te betalen bedrag = 3053.68€
|
||||
En cas de paiement dans les 14 jours, l'escompte conditionnel de 2% (52.00€) est appliqué et le montant payable = 3053.68€
|
||||
In case of payment within 14 days, 2% (52.00€) conditional cash/payment discount applies and the payable amount = 3053.68€
|
||||
</cbc:Note>
|
||||
</cac:PaymentTerms>
|
||||
*/
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the node value from simpleXML
|
||||
* @param $xml (\SimpleXMLElement) fragment of XML dom
|
||||
* @param $query (string) XPath query
|
||||
* @return string
|
||||
*/
|
||||
protected function get_simple_xml_value(\SimpleXMLElement $xml, $query): string
|
||||
{
|
||||
$x = $xml->xpath($query);
|
||||
$result = (count($x) == 0) ? "" : $x[0];
|
||||
return (string) $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the amount summary info from XML
|
||||
* @return array
|
||||
*/
|
||||
function get_amount_summary(): array
|
||||
{
|
||||
$result = [];
|
||||
$node = $this->get_node("//cac:LegalMonetaryTotal");
|
||||
$xml = simplexml_import_dom($node->item(0));
|
||||
$result['LineExtensionAmount'] = $this->get_simple_xml_value($xml, "cbc:LineExtensionAmount");
|
||||
$result['TaxExclusiveAmount'] = $this->get_simple_xml_value($xml, "cbc:TaxExclusiveAmount");
|
||||
$result['TaxInclusiveAmount'] = $this->get_simple_xml_value($xml, "cbc:TaxInclusiveAmount");
|
||||
$result['PayableAmount'] = $this->get_simple_xml_value($xml, "cbc:PayableAmount");
|
||||
$result['AllowanceTotalAmount'] = $this->get_simple_xml_value($xml, "cbc:AllowanceTotalAmount");
|
||||
$result['AllowanceTotalAmount'] = ($result['AllowanceTotalAmount'] == "") ? 0 : $result['AllowanceTotalAmount'];
|
||||
$result['ChargeTotalAmount'] = $this->get_simple_xml_value($xml, "cbc:ChargeTotalAmount");
|
||||
$result['ChargeTotalAmount'] = ($result['ChargeTotalAmount'] == "") ? 0 : $result['ChargeTotalAmount'];
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief get the customer info from XML
|
||||
* @return array
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
@code
|
||||
<cac:AllowanceCharge>
|
||||
<cbc:ChargeIndicator>false</cbc:ChargeIndicator>
|
||||
<cbc:AllowanceChargeReasonCode>64</cbc:AllowanceChargeReasonCode>
|
||||
<cbc:AllowanceChargeReason>Conditional cash/payment discount | Korting contant | Escompte Conditionnel 2%</cbc:AllowanceChargeReason>
|
||||
<cbc:Amount currencyID="EUR">4.00</cbc:Amount>
|
||||
<cac:TaxCategory>
|
||||
<cbc:ID>S</cbc:ID>
|
||||
<cbc:Percent>6.00</cbc:Percent>
|
||||
<cac:TaxScheme>
|
||||
<cbc:ID>VAT</cbc:ID>
|
||||
</cac:TaxScheme>
|
||||
</cac:TaxCategory>
|
||||
</cac:AllowanceCharge>
|
||||
@encode
|
||||
*/
|
||||
function get_allowance(): array
|
||||
{
|
||||
$result = [];
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return array
|
||||
* @TODODNY
|
||||
* Implémenter les allowances
|
||||
*/
|
||||
function get_info(): array
|
||||
{
|
||||
$result = [];
|
||||
$result['id'] = $this->get_node_value('cbc:ID');
|
||||
$result['IssueDate'] = $this->get_node_value('cbc:IssueDate');
|
||||
$result['DueDate'] = $this->get_node_value('cbc:DueDate');
|
||||
$result['InvoiceTypeCode'] = $this->get_node_value('cbc:InvoiceTypeCode');
|
||||
$result['DocumentCurrencyCode'] = $this->get_node_value('cbc:DocumentCurrencyCode');
|
||||
$result['BuyerReference'] = $this->get_node_value('cbc:BuyerReference');
|
||||
$result['ActualDeliveryDate'] = $this->get_node_value('//cac:Delivery[1]/cbc:ActualDeliveryDate[1]');
|
||||
/*
|
||||
<cac:Delivery>
|
||||
<cbc:ActualDeliveryDate>2018-07-01</cbc:ActualDeliveryDate>
|
||||
</cac:Delivery>
|
||||
*/
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief make a PDF with the information from XMLInvoice
|
||||
* @param \Database $cn
|
||||
* @returns \PDF
|
||||
*/
|
||||
public function to_pdf(\Database $cn): \PDF
|
||||
{
|
||||
$pdf = new \PDF($cn);
|
||||
$result = $this->get_info();
|
||||
|
||||
$pdf->setDossierInfo(_(" id ")." ".$result['id']);
|
||||
$pdf->AliasNbPages();
|
||||
$pdf->setAuthor("Noalyss");
|
||||
$pdf->AddPage();
|
||||
// 180 mm large
|
||||
$pdf->setFont("DejaVu", "B", 12);
|
||||
$pdf->write_cell(60, 4, _("Information facture"));
|
||||
$pdf->line_new(10);
|
||||
$pdf->setFont("DejaVu", "", 7);
|
||||
$pdf->write(4, sprintf(_("Document ID %s"), $result['id']));
|
||||
$pdf->ln();
|
||||
$pdf->write(4, sprintf(_("Date facture %s"), $result['IssueDate']));
|
||||
$pdf->ln();
|
||||
$pdf->write(4, sprintf(_("Date échéance %s"), $result['DueDate']));
|
||||
$pdf->ln();
|
||||
$pdf->write(4, sprintf(_("Code facture %s"), $result['InvoiceTypeCode']));
|
||||
$pdf->ln();
|
||||
$pdf->write(4, sprintf(_("Devise docuemnt %s"), $result['DocumentCurrencyCode']));
|
||||
$pdf->ln();
|
||||
$pdf->write(4, sprintf(_("Référence client %s"), $result['BuyerReference']));
|
||||
$pdf->ln();
|
||||
$pdf->write(4, sprintf(_("Date Livraison %s"), $result['ActualDeliveryDate']));
|
||||
$pdf->ln(10);
|
||||
|
||||
$pdf->setFont("DejaVu", "B", 12);
|
||||
$pdf->write_cell(60, 4, _("Fournisseur"));
|
||||
$pdf->line_new(12);
|
||||
$supplier = $this->get_supplier();
|
||||
$pdf->setFont("DejaVu", "", 7);
|
||||
$pdf->write_cell(60, 4, $supplier['name']);
|
||||
$pdf->write_cell(60, 4, $supplier['company_id']);
|
||||
$pdf->write_cell(60, 4, $supplier['ID']);
|
||||
$pdf->line_new();
|
||||
$pdf->write_cell(60, 4, $supplier['street']);
|
||||
$pdf->write_cell(30, 4, $supplier['postcode']);
|
||||
$pdf->write_cell(60, 4, $supplier['city']);
|
||||
$pdf->write_cell(20, 4, $supplier['country_code']);
|
||||
$pdf->line_new(10);
|
||||
|
||||
$customer = $this->get_customer();
|
||||
$pdf->setFont("DejaVu", "B", 12);
|
||||
$pdf->write_cell(60, 4, _("Client"));
|
||||
$pdf->line_new(10);
|
||||
$pdf->setFont("DejaVu", "", 7);
|
||||
$pdf->write_cell(60, 4, $customer['name']);
|
||||
$pdf->write_cell(60, 4, $customer['company_id']);
|
||||
$pdf->write_cell(60, 4, $customer['ID']);
|
||||
$pdf->line_new();
|
||||
$pdf->write_cell(60, 4, $customer['street']);
|
||||
$pdf->write_cell(40, 4, $customer['postcode']);
|
||||
$pdf->write_cell(60, 4, $customer['city']);
|
||||
$pdf->write_cell(20, 4, $customer['country_code']);
|
||||
$pdf->line_new(10);
|
||||
|
||||
$pdf->setFont("DejaVu", "B", 12);
|
||||
$pdf->write_cell(60, 4, _("Articles"));
|
||||
$pdf->line_new(10);
|
||||
$pdf->setFont("DejaVu", "", 7);
|
||||
$result = $this->get_invoiceLine();
|
||||
$pdf->write_cell(50, 4, _("Code"), border: 'B');
|
||||
$pdf->write_cell(50, 4, _("Description"), border: 'B');
|
||||
$pdf->write_cell(30, 4, _("TVA"), border: 'B', align: 'R');
|
||||
$pdf->write_cell(25, 4, _("Quantité"), border: 'B', align: 'R');
|
||||
$pdf->write_cell(25, 4, _("Montant HT"), border: 'B', align: 'R');
|
||||
$pdf->line_new();
|
||||
|
||||
$nb_inline = count($result);
|
||||
for ($i = 0; $i < $nb_inline; $i++)
|
||||
{
|
||||
$pdf->write_cell(50, 4, $result[$i]['name']);
|
||||
$pdf->write_cell(50, 4, $result[$i]['description']);
|
||||
$pdf->write_cell(25, 4, $result[$i]['tva_percent'], align: 'R');
|
||||
$pdf->write_cell(5, 4, $result[$i]['tva_id']);
|
||||
$pdf->write_cell(25, 4, $result[$i]['quantity'], align: 'R');
|
||||
$pdf->write_cell(25, 4, $result[$i]['amount'], align: 'R');
|
||||
$pdf->line_new();
|
||||
}
|
||||
$pdf->line_new(10);
|
||||
|
||||
$pdf->setFont("DejaVu", "B", 12);
|
||||
$pdf->write_cell(60, 4, _("Totaux"));
|
||||
$pdf->line_new(10);
|
||||
$pdf->setFont("DejaVu", "", 7);
|
||||
$result = $this->get_amount_summary();
|
||||
// @TODO DNY : Qu'est-ce que LineExtension Amount ??
|
||||
$pdf->write_cell(50, 4, _("Base taxe"));
|
||||
$pdf->write_cell(50, 4, $result['LineExtensionAmount']);
|
||||
$pdf->line_new();
|
||||
$pdf->write_cell(50, 4, _("Total Hors Taxe"));
|
||||
$pdf->write_cell(50, 4, $result['TaxExclusiveAmount']);
|
||||
$pdf->line_new();
|
||||
$pdf->write_cell(50, 4, _("Total avec Taxe"));
|
||||
$pdf->write_cell(50, 4, $result['TaxInclusiveAmount']);
|
||||
$pdf->line_new();
|
||||
$pdf->write_cell(50, 4, _("Total à payer"));
|
||||
$pdf->write_cell(50, 4, $result['PayableAmount']);
|
||||
$pdf->line_new();
|
||||
$pdf->write_cell(50, 4, _("Total réduction"));
|
||||
$pdf->write_cell(50, 4, $result['AllowanceTotalAmount']);
|
||||
$pdf->line_new();
|
||||
$pdf->write_cell(50, 4, _("Total charge"));
|
||||
$pdf->write_cell(50, 4, $result['ChargeTotalAmount']);
|
||||
$pdf->line_new();
|
||||
|
||||
$pdf->line_new(10);
|
||||
$pdf->setFont("DejaVu", "B", 12);
|
||||
$pdf->write_cell(60, 4, _("TVA"));
|
||||
$pdf->line_new(10);
|
||||
$pdf->setFont("DejaVu", "", 7);
|
||||
$result = $this->get_taxes();
|
||||
$pdf->write_cell(25, 4, _("% Taxe"), align: 'R', border: 'B');
|
||||
$pdf->write_cell(5, 4, _("Code taxe"), border: 'B');
|
||||
$pdf->write_cell(50, 4, _("Base"), align: 'R', border: 'B');
|
||||
$pdf->write_cell(50, 4, _("Taxe"), align: 'R', border: 'B');
|
||||
$pdf->line_new();
|
||||
$nb_inline = count($result);
|
||||
for ($i = 0; $i < $nb_inline; $i++)
|
||||
{
|
||||
$pdf->write_cell(25, 4, $result[$i]['tax_percent'], align: 'R');
|
||||
$pdf->write_cell(5, 4, $result[$i]['tax_id']);
|
||||
$pdf->write_cell(50, 4, $result[$i]['taxable_amount'], align: 'R');
|
||||
$pdf->write_cell(50, 4, $result[$i]['tax'], align: 'R');
|
||||
|
||||
$pdf->line_new();
|
||||
}
|
||||
$pdf->line_new(10);
|
||||
$pdf->setFont("DejaVu", "B", 12);
|
||||
$pdf->write_cell(60, 4, _("Paiement"));
|
||||
$pdf->line_new(10);
|
||||
$pdf->setFont("DejaVu", "", 7);
|
||||
$result = $this->get_payment_mean();
|
||||
$pdf->write_cell(50, 4, _("Code"));
|
||||
$pdf->write_cell(50, 4, $result['payment_code']);
|
||||
$pdf->line_new();
|
||||
$pdf->write_cell(50, 4, _("IBAN"));
|
||||
$pdf->write_cell(50, 4, $result['iban']);
|
||||
$pdf->line_new();
|
||||
$pdf->write_cell(50, 4, _("BIC"));
|
||||
$pdf->write_cell(50, 4, $result['bic']);
|
||||
$pdf->line_new();
|
||||
$pdf->write_cell(50, 4, _("Communication"));
|
||||
$pdf->write_cell(50, 4, $result['label']);
|
||||
$pdf->line_new();
|
||||
$nb_note = count($result['note']);
|
||||
for ($i = 0; $i < $nb_note; $i++)
|
||||
{
|
||||
$pdf->write_cell(40, 4, _("note") . " " . $i);
|
||||
$pdf->write_multi(140, 4, str_replace(["\n","\r","\t"]," ",$result['note'][$i]));
|
||||
$pdf->line_new();
|
||||
}
|
||||
return $pdf;
|
||||
}
|
||||
}
|
||||
|
|
@ -256,6 +256,11 @@ switch ($action) {
|
|||
$filename = mb_substr($obj->det->jr_pj_name, 0, 60);
|
||||
}
|
||||
echo HtmlInput::show_receipt_document($jr_id, h($filename));
|
||||
// if using the XML Belgian format, add a tab for showing it
|
||||
$acc_document=new Acc_Document($cn,$jr_id);
|
||||
echo '<span style="margin-left:5rem">'.
|
||||
$acc_document->link_download_xml()
|
||||
.'</span>';
|
||||
echo $x;
|
||||
echo '<p id="receipt_info_id" style="display:inline" ></p>';
|
||||
echo '</div>';
|
||||
|
|
@ -268,9 +273,8 @@ switch ($action) {
|
|||
case 'loadfile':
|
||||
if ($access == 'W' && isset ($_FILES)) {
|
||||
$cn->start();
|
||||
// remove the file
|
||||
$grpt = $cn->get_value('select jr_grpt_id from jrn where jr_id=$1', array($jr_id));
|
||||
$cn->save_receipt($grpt);
|
||||
$acc_document=new \Acc_Document($cn,$jr_id);
|
||||
$acc_document->save_receipt();
|
||||
$cn->commit();
|
||||
// Show a link to the new file
|
||||
$op->get();
|
||||
|
|
@ -290,7 +294,13 @@ switch ($action) {
|
|||
$filename = $obj->det->jr_pj_name;
|
||||
echo HtmlInput::show_receipt_document($jr_id, h($filename));
|
||||
echo $x;
|
||||
|
||||
// if using the XML Belgian format, add a tab for showing it
|
||||
$acc_document=new Acc_Document($cn,$jr_id);
|
||||
echo '<span style="margin-left:5rem">'.
|
||||
$acc_document->link_download_xml()
|
||||
.'</span>';
|
||||
echo '<p id="receipt_info_id" style="display:inline" ></p>';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
echo '</body></html>';
|
||||
}
|
||||
|
|
@ -325,12 +335,21 @@ switch ($action) {
|
|||
$old_oid = $r['jr_pj'];
|
||||
if (strlen($old_oid) != 0) {
|
||||
// check if this pj is used somewhere else
|
||||
$c = $cn->count_sql("select * from jrn where jr_pj=" . $old_oid);
|
||||
$c = $cn->get_value("select count(*) from jrn where jr_pj=$1",
|
||||
[$old_oid]);
|
||||
|
||||
if ($c == 1)
|
||||
$cn->lo_unlink($old_oid);
|
||||
}
|
||||
|
||||
$cn->exec_sql("update jrn set jr_pj=null, jr_pj_name=null, " .
|
||||
"jr_pj_type=null where jr_id=$1", array($jr_id));
|
||||
|
||||
if ( ($oid_xml = $cn->get_value("select jr_document_xml from jrn where jr_id = $1",[$jr_id])) != "")
|
||||
{
|
||||
$cn->exec_sql("update jrn set jr_document_xml=null where jr_id=$1", array($jr_id));
|
||||
$cn->lo_unlink($oid_xml);
|
||||
}
|
||||
}
|
||||
}
|
||||
echo '</div>';
|
||||
|
|
|
|||
387
include/class/acc_document.class.php
Normal file
387
include/class/acc_document.class.php
Normal file
|
|
@ -0,0 +1,387 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of NOALYSS.
|
||||
*
|
||||
* NOALYSS is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* NOALYSS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with NOALYSS; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
// Copyright Author Dany De Bontridder danydb@aevalys.eu 28/08/25
|
||||
use Noalyss\XMLDocument\XMLInvoice_Reader;
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Document used in accountancy : invoice , credit note, ...It is
|
||||
* a specialization of Document used in Follow-UP
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @brief Document used in accountancy : invoice , credit note, ... It is
|
||||
* a specialization of Document used in Follow-UP.
|
||||
* property :
|
||||
* - d_id JRN.JR_ID
|
||||
* - d_name name Receipt number
|
||||
- d_description Comment of the operation
|
||||
- d_mimetype mimetype of the document JRN.JR_PJ_TYPE
|
||||
- d_filename filename JRN.JR_PJ_NAME
|
||||
- document_xml oid of the XML invoice (including PDF) JRN.JR_DOCUMENT_XML
|
||||
- d_lob = JRN.JR_PJ
|
||||
*
|
||||
*/
|
||||
class Acc_Document extends Document {
|
||||
private $document_xml; ///< $document_xml (oid) XML document e-invoice
|
||||
|
||||
public function get_document_xml() {
|
||||
return $this->document_xml;
|
||||
}
|
||||
|
||||
public function set_document_xml($document_xml) {
|
||||
$this->document_xml = $document_xml;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
* @param $cn \Database
|
||||
* @param $jr_id (int) JRN.JRID will be in d_id
|
||||
*/
|
||||
function __construct($cn, $jr_id=0)
|
||||
{
|
||||
$this->db=$cn;
|
||||
$this->set_id($jr_id);
|
||||
// counter for MARCH_NEXT
|
||||
$this->counter=0;
|
||||
|
||||
}
|
||||
/**
|
||||
* @brief set_id fill up d_filename, d_mimetype,d_lob,d_description,jr_pj_number
|
||||
*/
|
||||
function set_id($jr_id) {
|
||||
$this->d_id=$jr_id;
|
||||
if ( $jr_id == 0 ){
|
||||
return $this;
|
||||
}
|
||||
$row = $this->db->get_row("select jr_comment
|
||||
,jr_pj
|
||||
,jr_pj_name
|
||||
,jr_pj_type
|
||||
,jr_pj_number
|
||||
,jr_document_xml
|
||||
from jrn
|
||||
where
|
||||
jr_id=$1", [$this->d_id]);
|
||||
if ( empty ($row)) {
|
||||
return $this;
|
||||
}
|
||||
$this->d_name=$row['jr_pj_number'];
|
||||
$this->d_description=$row['jr_comment'];
|
||||
$this->d_mimetype=$row['jr_pj_type'];
|
||||
$this->d_filename=$row['jr_pj_name'];
|
||||
$this->d_lob=$row['jr_pj'];
|
||||
$this->document_xml=$row['jr_document_xml'];
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* @brief save the file into DB, will create a large object if there
|
||||
* is no document to replace. It will change the d_filename, d_mimetype
|
||||
*
|
||||
* @param $d_filename (string) full path to the file to load into DB
|
||||
*
|
||||
* @returns false if d_id = 0 or the file doesn't exist, true for success
|
||||
*/
|
||||
function update($filename) {
|
||||
if ($this->d_id == 0) return false;
|
||||
if ( ! file_exists($filename)) return false;
|
||||
$this->db->start();
|
||||
$this->d_mimetype= mime_content_type($filename);
|
||||
$this->d_filename= basename($filename);
|
||||
if ( $this->d_lob == "") {
|
||||
$this->db->lo_unlink($this->d_lob);
|
||||
}
|
||||
|
||||
$this->d_lob=$this->db->lo_import($filename);
|
||||
$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]
|
||||
);
|
||||
$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
|
||||
*/
|
||||
function update_document_xml($oid){
|
||||
$this->db->exec_sql("update jrn set jr_document_xml=$1 where
|
||||
jr_id=$2",[
|
||||
$oid,
|
||||
$this->d_id
|
||||
]);
|
||||
|
||||
}
|
||||
/**
|
||||
* @brief create the invoice and saved it as attachment to the
|
||||
* operation,
|
||||
* @param $p_array is normally the $_POST
|
||||
@verbatim
|
||||
Array
|
||||
(
|
||||
[ledger_type] => VEN
|
||||
[gDossier] => x
|
||||
[nb_item] => 1 (number of item used to numerate e_marchX, e_quantX ,...)
|
||||
[p_jrn] => 2
|
||||
[p_jrn_predef] => 2
|
||||
[jrn_type] => VEN or ACH
|
||||
[e_date] => 10.06.2025 (date)
|
||||
[e_ech] => limite date
|
||||
[e_client] => CLIENT
|
||||
[e_pj] => 25.827
|
||||
[e_pj_suggest] => 25.827
|
||||
[e_comm] => E-INVOICE
|
||||
[p_currency_code] => 0
|
||||
[p_currency_rate] => 1 (rate if 1 for EURO)
|
||||
[jrn_note_input] =>
|
||||
[e_march0] => 7DVINV
|
||||
[e_march0_label] => Label of the operation
|
||||
[e_march0_price] => 10.0000
|
||||
[e_quant0] => 1.0000
|
||||
[htva_march0] => 10
|
||||
[e_march0_tva_id] => 1
|
||||
[e_march0_tva_amount] => 2.1
|
||||
[tva_march0] => 2.1
|
||||
[tvac_march0] => 12.1
|
||||
...
|
||||
[mp_date] => (dd.mm.yyyy date of payment)
|
||||
[acompte] => 0 (amount to deduce as advance payment)
|
||||
[e_comm_paiement] => (string : comment of the payment)
|
||||
[e_mp] => 0 (method of payment it is the XX in e_mp_qcode_XX)
|
||||
[e_mp_qcode_16] => Banque 1
|
||||
[e_mp_qcode_17] => Banque 2
|
||||
[view_invoice] => Enregistrer
|
||||
[gen_doc] => int DOCUMENT_MODELE.MD_ID , document template to use
|
||||
)
|
||||
* @endverbatim
|
||||
* @todo rewrite code : remove extract and +SQL value
|
||||
* @returns void
|
||||
*/
|
||||
function create_document($internal, $p_array) {
|
||||
$this->f_id = $p_array['e_client'];
|
||||
// var md_id (int) DOCUMENT_MODELE.MD_ID
|
||||
$this->md_id = $p_array['gen_doc'];
|
||||
// var ag_id == 0 fake follow-up
|
||||
$this->ag_id = 0;
|
||||
// var e_pj (string) receipt nb
|
||||
$p_array['e_pj'] = $this->db->get_value("select jr_pj_number from jrn where jr_id=$1"
|
||||
, [$this->d_id]);
|
||||
$filename = "";
|
||||
// generate the document and set d_lob,d_mimetype,
|
||||
$this->generate($p_array, $p_array['e_pj']);
|
||||
|
||||
// Move the document to accountancy (table JRN),
|
||||
$this->moveDocumentACC($internal);
|
||||
|
||||
// Update the comment with invoice number, if the comment is empty
|
||||
if (!isset($p_array['e_comm']) || noalyss_strlentrim($p_array['e_comm']) == 0) {
|
||||
$sql = "update jrn set jr_comment=' document " . $this->d_number . "' where jr_internal=$1";
|
||||
$this->db->exec_sql($sql, [$internal]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief export the file to the file system and complet $this->d_mimetype, d_filename and
|
||||
* @param $destination_file (string) full path to document
|
||||
* @return bool false for failure and string (the full path_name) for success
|
||||
*/
|
||||
function export_file($destination_file) {
|
||||
|
||||
if (empty($this->d_filename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->db->start();
|
||||
if ($this->db->lo_export($this->d_lob, $destination_file) == false) {
|
||||
record_log("ACD122. cannot export");
|
||||
$this->db->commit();
|
||||
return false;
|
||||
}
|
||||
$this->db->commit();
|
||||
|
||||
return $destination_file;
|
||||
}
|
||||
/**
|
||||
* \brief Save a "piece justificative" , the name must be a receipt. If it
|
||||
* is a XML document, split it into 2 parts : PDF and XML
|
||||
* the PDF be stored in JR_PJ and the XML into JR_DOCUMENT_XML
|
||||
*
|
||||
*
|
||||
* \return $oid of the lob file if success null if a error occurs
|
||||
*
|
||||
*/
|
||||
function save_receipt()
|
||||
{
|
||||
$this->db->start();
|
||||
/**
|
||||
* pj is the $_FILES key
|
||||
*/
|
||||
$a_file= $this->db->upload('pj',only_oid:false);
|
||||
if ($a_file == false) {
|
||||
return false;
|
||||
}
|
||||
$oid=$a_file['oid'];
|
||||
// Remove old document if any
|
||||
$old_oid = $this->db->get_value("select jr_pj from jrn where jr_id=$1"
|
||||
,[$this->d_id]);
|
||||
|
||||
if ( $old_oid != "")
|
||||
{
|
||||
$this->db->lo_unlink( $old_oid);
|
||||
}
|
||||
|
||||
// if there is a e-invoice in XML
|
||||
if ( $_FILES['pj']['type'] == 'text/xml'
|
||||
|| $_FILES['pj']['type'] == 'application/xml'
|
||||
)
|
||||
{
|
||||
// save the XML
|
||||
$this->db->exec_sql("update jrn set jr_document_xml = $1
|
||||
where
|
||||
jr_id=$2",
|
||||
[$oid,$this->d_id]);
|
||||
|
||||
$xmlreader= XMLInvoice_Reader::build_from_file($a_file['filename']);
|
||||
|
||||
//@var $embedded_file (array) keys = filecontent: binary data
|
||||
//,mimecode mimetype and filename (string)
|
||||
try
|
||||
{
|
||||
$embedded_file=$xmlreader->get_embedded_document();
|
||||
if ($embedded_file == false)
|
||||
{
|
||||
$embedded_file=array();
|
||||
// create a PDF with standard information
|
||||
$pdf=$xmlreader->to_pdf($this->db);
|
||||
$file_oid=$this->db->lo_write($pdf->Output("S"));
|
||||
$embedded_file['filename']="invoice.pdf";
|
||||
$embedded_file['mimecode']="application/pdf";
|
||||
}
|
||||
else
|
||||
{
|
||||
$file_oid=$this->db->lo_write($embedded_file['filecontent']);
|
||||
if ( $file_oid == false )
|
||||
{
|
||||
// create a PDF with standard information
|
||||
$pdf=$xmlreader->to_pdf($this->db);
|
||||
$file_oid=$this->db->lo_write($pdf->Output("S"));
|
||||
}
|
||||
}
|
||||
//@var $file_oid OID of the large object saved in DB
|
||||
|
||||
|
||||
$this->d_name=$embedded_file['filename'];
|
||||
$this->d_description=$embedded_file['filename'];
|
||||
$this->d_lob=$file_oid;
|
||||
$this->d_mimetype=$embedded_file['mimecode'];
|
||||
// save extracted document into DB
|
||||
$this->db->exec_sql("update jrn set jr_pj=$1 , jr_pj_name=$2,
|
||||
jr_pj_type=$3 where jr_id=$4",
|
||||
array(
|
||||
$this->d_lob
|
||||
, $this->d_name
|
||||
, $this->d_description
|
||||
, $this->d_id
|
||||
)
|
||||
);
|
||||
return $file_oid;
|
||||
} catch (\Exception $e ) {
|
||||
\record_log($e);
|
||||
// if exception is not too many document or document corrupted
|
||||
// then rethrow the exception
|
||||
if ( !in_array(e->getCode(),[110,116]) )
|
||||
{
|
||||
throw new \Exception("X281 ",281,$e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// save new document
|
||||
$this->db->exec_sql("update jrn set jr_pj=$1 , jr_pj_name=$2,
|
||||
jr_pj_type=$3 where jr_id=$4",
|
||||
array(
|
||||
$oid
|
||||
, $_FILES['pj']['name']
|
||||
, $_FILES['pj']['type']
|
||||
, $this->d_id
|
||||
)
|
||||
);
|
||||
$this->d_name=$_FILES['pj']['name'];
|
||||
$this->d_description=$_FILES['pj']['name'];
|
||||
$this->d_lob=$oid;
|
||||
$this->d_mimetype=$_FILES['pj']['type'];
|
||||
$this->db->commit();
|
||||
|
||||
return $oid;
|
||||
}
|
||||
/**
|
||||
* @brief return a string with a link download XML or an empty string
|
||||
* if there is no XML to download
|
||||
*/
|
||||
function link_download_xml():string
|
||||
{
|
||||
$xml_oid=$this->db->get_value("select jr_document_xml from jrn where jr_id=$1",
|
||||
[$this->d_id]);
|
||||
if ($xml_oid == "") { return "";}
|
||||
$url= "export.php?".http_build_query(
|
||||
[
|
||||
"gDossier"=>\Dossier::id(),
|
||||
"jr_id"=>$this->d_id,
|
||||
"act"=>'RAW:xml-invoice'
|
||||
]);
|
||||
$r = sprintf('<a class="mtitle line" href="%s">',$url);
|
||||
$r .= _("XML")
|
||||
.'<i class="icon-download">'
|
||||
.'</i>'
|
||||
.'</a>';
|
||||
return $r;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1610,6 +1610,7 @@ class Acc_Ledger extends jrn_def_sql
|
|||
$acc_end->currency_rate=$currency_rate;
|
||||
$acc_end->currency_rate_ref=$currency_rate_ref->get_rate();
|
||||
|
||||
// @var $jr_id (int) JRN.JR_ID
|
||||
$jr_id=$acc_end->insert_jrn();
|
||||
|
||||
$this->jr_id=$jr_id;
|
||||
|
|
@ -1651,7 +1652,8 @@ class Acc_Ledger extends jrn_def_sql
|
|||
*/
|
||||
if (isset($_FILES["pj"]))
|
||||
{
|
||||
$this->db->save_receipt($seq);
|
||||
$acc_document=new Acc_Document($this->db, $jr_id);
|
||||
$acc_document->save_receipt();
|
||||
}
|
||||
/*----------------------------------------------
|
||||
* Save the note
|
||||
|
|
@ -1973,31 +1975,22 @@ class Acc_Ledger extends jrn_def_sql
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief create the invoice and saved it as attachment to the
|
||||
* operation,
|
||||
* @brief alias for Acc_Document->create_document
|
||||
* @param $internal is the internal code
|
||||
* @param $p_array is normally the $_POST
|
||||
* @todo rewrite code : remove extract and +SQL value
|
||||
* \return a string
|
||||
@see Acc_Document::create_document
|
||||
* @return a string
|
||||
*/
|
||||
function create_document($internal, $p_array)
|
||||
{
|
||||
$doc=new Document($this->db);
|
||||
$doc->f_id=$p_array['e_client'];
|
||||
$doc->md_id=$p_array['gen_doc'];
|
||||
$doc->ag_id=0;
|
||||
$p_array['e_pj']=$this->pj;
|
||||
$filename="";
|
||||
$doc->Generate($p_array, $p_array['e_pj']);
|
||||
// Move the document to the jrn
|
||||
$doc->moveDocumentPj($internal);
|
||||
// Update the comment with invoice number, if the comment is empty
|
||||
if (!isset($p_array['e_comm'])||noalyss_strlentrim($p_array['e_comm'])==0)
|
||||
{
|
||||
$sql="update jrn set jr_comment=' document ".$doc->d_number."' where jr_internal=$1";
|
||||
$this->db->exec_sql($sql,[$internal]);
|
||||
$id=$this->db->get_value('select jr_id from jrn where jr_internal=$1',
|
||||
[$internal]);
|
||||
if ( $id == "") {
|
||||
return;
|
||||
}
|
||||
return h($doc->d_name.' ('.$doc->d_filename.')');
|
||||
$acc_document=new Acc_Document($this->db,$id);
|
||||
$acc_document->create_document($internal,$p_array);
|
||||
return h($acc_document->d_name.' ('.$acc_document->d_filename.')');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -983,6 +983,7 @@ class Acc_Ledger_Fin extends Acc_Ledger
|
|||
throw new Exception (_("Erreur de balance"),EXC_BALANCE);
|
||||
|
||||
// $acc_operation->update_receipt();
|
||||
$this->jr_id=&$jr_id;
|
||||
$this->db->exec_sql('update jrn set jr_pj_number=$1 where jr_id=$2', array($acc_operation->pj, $jr_id));
|
||||
$internal=$this->compute_internal_code($seq);
|
||||
|
||||
|
|
@ -1073,21 +1074,18 @@ class Acc_Ledger_Fin extends Acc_Ledger
|
|||
$class=($i%2==0)?' class="even" ':' class="odd" ';
|
||||
$ret.=tr($row, $class);
|
||||
|
||||
if ($i==0)
|
||||
if ($i==0 && isset($_FILES['pj']) )
|
||||
{
|
||||
// first record we upload the files and
|
||||
// keep variable to update other row of jrn
|
||||
if (isset($_FILES['pj']))
|
||||
$oid=$this->db->save_receipt($seq);
|
||||
$acc_document=new Acc_Document($this->db,$jr_id);
|
||||
$oid=$acc_document->save_receipt();
|
||||
}
|
||||
else
|
||||
elseif ($oid != 0 )
|
||||
{
|
||||
if ($oid!=0)
|
||||
{
|
||||
$this->db->exec_sql("update jrn set jr_pj=$1 , jr_pj_name=$2,
|
||||
jr_pj_type=$3 where jr_grpt_id=$4",
|
||||
array($oid, $_FILES['pj']['name'], $_FILES['pj']['type'], $seq));
|
||||
}
|
||||
$this->db->exec_sql("update jrn set jr_pj=$1 , jr_pj_name=$2,
|
||||
jr_pj_type=$3 where jr_grpt_id=$4",
|
||||
array($oid, $_FILES['pj']['name'], $_FILES['pj']['type'], $seq));
|
||||
}
|
||||
} // for nbitem
|
||||
// increment pj
|
||||
|
|
|
|||
|
|
@ -29,9 +29,86 @@ require_once NOALYSS_INCLUDE.'/lib/ac_common.php';
|
|||
|
||||
/*!
|
||||
* \class Acc_Ledger_Purchase
|
||||
* \brief Handle the ledger of purchase,
|
||||
*
|
||||
*
|
||||
** @brief : input, confirm and save new operations in edger of purchase
|
||||
the $_POST data is an array with these keys
|
||||
@code
|
||||
Array
|
||||
(
|
||||
|
||||
// =====================
|
||||
// ANALYTIC PART
|
||||
// =====================
|
||||
[pa_id] => Array
|
||||
(
|
||||
[0] => 1
|
||||
)
|
||||
|
||||
[op] => Array
|
||||
(
|
||||
[0] => 0
|
||||
)
|
||||
|
||||
[amount_t0] => 10
|
||||
[hplan] => Array
|
||||
(
|
||||
[0] => Array
|
||||
(
|
||||
[0] => -1
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
[val] => Array
|
||||
(
|
||||
[0] => Array
|
||||
(
|
||||
[0] => 10
|
||||
)
|
||||
|
||||
)
|
||||
// =====================
|
||||
// SALES DATA
|
||||
// =====================
|
||||
|
||||
[e_client] => QuickCode supplier
|
||||
[nb_item] => number of items (lines of invoice)
|
||||
[p_jrn] => JRN_DEF.JRN_DEF_ID id of the ledger
|
||||
[jrn_note_input] => Note JRN_NOTE.N_TEXT
|
||||
[mt] => 1759130008.8134
|
||||
[p_currency_rate] => Currency Rate
|
||||
[p_currency_code] => Currency Code
|
||||
[e_comm] => Description of invoice
|
||||
[e_date] => date invoice
|
||||
[e_ech] => limit date
|
||||
[e_pj] => Receipt number
|
||||
[e_pj_suggest] => suggested receipt number
|
||||
[e_mp] => payment means (
|
||||
[jrn_type] => Type of ledger (always ACH)
|
||||
//---------------------------------------------
|
||||
// For each invoice line
|
||||
//---------------------------------------------
|
||||
[e_march0] => QuickCode of the item
|
||||
[e_march0_label] => label
|
||||
[e_march0_price] => unit price
|
||||
[e_march0_tva_id] => VAT ID
|
||||
[e_march0_tva_amount] => amount of VAT
|
||||
[e_quant0] => quantity of item
|
||||
//========================
|
||||
// MISC
|
||||
//========================
|
||||
[repo] => 1 (repository)
|
||||
[gen_invoice] => on (it is asked to generate an invoice
|
||||
[gen_doc] => Document template id
|
||||
[bon_comm] => JRN_INFO.
|
||||
[other_info] = JRN_INFO.>
|
||||
[opd_name] => Name of operation template
|
||||
[od_description] => Description of operation template
|
||||
[reverse_date] => if reverse is asked
|
||||
[ext_label] => Label for revese operation
|
||||
[jr_optype] => Type of operation NOR:Normal,, EXT; reverse, ..
|
||||
)
|
||||
@endcode
|
||||
|
||||
*/
|
||||
class Acc_Ledger_Purchase extends Acc_Ledger
|
||||
{
|
||||
|
|
@ -978,7 +1055,9 @@ class Acc_Ledger_Purchase extends Acc_Ledger
|
|||
if ( isset ($_FILES))
|
||||
{
|
||||
if ( sizeof($_FILES) != 0 )
|
||||
$this->db->save_receipt($seq);
|
||||
$acc_document=new \Acc_Document($this->db, $this->jr_id);
|
||||
$acc_document->save_receipt();
|
||||
$this->doc=HtmlInput::show_receipt_document($this->jr_id,h($_FILES['pj']['name']));
|
||||
}
|
||||
$str_file="";
|
||||
/* Generate an document and save it into the database (Note de frais only)
|
||||
|
|
|
|||
|
|
@ -28,9 +28,87 @@ require_once NOALYSS_INCLUDE.'/lib/user_common.php';
|
|||
require_once NOALYSS_INCLUDE.'/lib/ac_common.php';
|
||||
|
||||
/*!
|
||||
* \brief Handle the ledger of sold,
|
||||
*
|
||||
* @exception throw an exception is something is wrong
|
||||
* @class Acc_Ledger_Sale
|
||||
* @brief : input, confirm and save new operations in edger of sales
|
||||
the $_POST data is an array with these keys
|
||||
@code
|
||||
Array
|
||||
(
|
||||
|
||||
// =====================
|
||||
// ANALYTIC PART
|
||||
// =====================
|
||||
[pa_id] => Array
|
||||
(
|
||||
[0] => 1
|
||||
)
|
||||
|
||||
[op] => Array
|
||||
(
|
||||
[0] => 0
|
||||
)
|
||||
|
||||
[amount_t0] => 10
|
||||
[hplan] => Array
|
||||
(
|
||||
[0] => Array
|
||||
(
|
||||
[0] => -1
|
||||
)
|
||||
|
||||
)
|
||||
|
||||
[val] => Array
|
||||
(
|
||||
[0] => Array
|
||||
(
|
||||
[0] => 10
|
||||
)
|
||||
|
||||
)
|
||||
// =====================
|
||||
// SALES DATA
|
||||
// =====================
|
||||
|
||||
[e_client] => QuickCode customer
|
||||
[nb_item] => number of items (lines of invoice)
|
||||
[p_jrn] => JRN_DEF.JRN_DEF_ID id of the ledger
|
||||
[jrn_note_input] => Note JRN_NOTE.N_TEXT
|
||||
[mt] => 1759130008.8134
|
||||
[p_currency_rate] => Currency Rate
|
||||
[p_currency_code] => Currency Code
|
||||
[e_comm] => Description of invoice
|
||||
[e_date] => date invoice
|
||||
[e_ech] => limit date
|
||||
[e_pj] => Receipt number
|
||||
[e_pj_suggest] => suggested receipt number
|
||||
[e_mp] => payment means (
|
||||
[jrn_type] => Type of ledger (always VEN)
|
||||
//---------------------------------------------
|
||||
// For each invoice line
|
||||
//---------------------------------------------
|
||||
[e_march0] => QuickCode of the item
|
||||
[e_march0_label] => label
|
||||
[e_march0_price] => unit price
|
||||
[e_march0_tva_id] => VAT ID
|
||||
[e_march0_tva_amount] => amount of VAT
|
||||
[e_quant0] => quantity of item
|
||||
//========================
|
||||
// MISC
|
||||
//========================
|
||||
[repo] => 1 (repository)
|
||||
[gen_invoice] => on (it is asked to generate an invoice
|
||||
[gen_doc] => Document template id
|
||||
[bon_comm] => JRN_INFO.
|
||||
[other_info] = JRN_INFO.>
|
||||
[opd_name] => Name of operation template
|
||||
[od_description] => Description of operation template
|
||||
[reverse_date] => if reverse is asked
|
||||
[ext_label] => Label for revese operation
|
||||
[jr_optype] => Type of operation NOR:Normal,, EXT; reverse, ..
|
||||
)
|
||||
@endcode
|
||||
|
||||
*/
|
||||
|
||||
class Acc_Ledger_Sale extends Acc_Ledger {
|
||||
|
|
@ -698,17 +776,7 @@ class Acc_Ledger_Sale extends Acc_Ledger {
|
|||
where j_id in (select j_id from jrnx where j_grpt=$2)'
|
||||
, array($internal, $seq));
|
||||
|
||||
/* Save the attachment or generate doc */
|
||||
if (isset($_FILES['pj'])) {
|
||||
if (noalyss_strlentrim($_FILES['pj']['name']) != 0)
|
||||
$this->db->save_receipt($seq);
|
||||
else
|
||||
/* Generate an invoice and save it into the database */
|
||||
if (isset($_POST['gen_invoice'])) {
|
||||
$file = $this->create_document($internal, $p_array);
|
||||
$this->doc=HtmlInput::show_receipt_document($this->jr_id,h($file));
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// Save the payer
|
||||
//----------------------------------------
|
||||
|
|
@ -932,6 +1000,7 @@ class Acc_Ledger_Sale extends Acc_Ledger {
|
|||
$r.='<td>' . _('Numéro Pièce') .$span.'</td><td>'. hb($this->pj) . '</td>';
|
||||
}
|
||||
}
|
||||
$e_comm=($e_comm == "")?_('Facture')." $e_pj":$e_comm;
|
||||
$r.='</tr>';
|
||||
$r.='<tr>';
|
||||
$r.='<td> ' . _('Date') . '</td><td> ' . hb($e_date) . '</td>';
|
||||
|
|
@ -954,7 +1023,7 @@ class Acc_Ledger_Sale extends Acc_Ledger {
|
|||
$r.='</tr>';
|
||||
|
||||
$r.='<tr>';
|
||||
$r.='<td> ' . _('Client') . '</td><td> ' . hb($e_client . ':' . $client_name) . '</td>';
|
||||
$r.='<td> ' . _('Client') . '</td><td> ' . HtmlInput::card_detail($e_client).":".hb( $client_name) . '</td>';
|
||||
$r.='</tr>';
|
||||
$r.='</table>';
|
||||
$r.='<pre>'._('Note').' '.h($p_array['jrn_note_input']).'</pre>';
|
||||
|
|
@ -1296,7 +1365,8 @@ EOF;
|
|||
return $r;
|
||||
}
|
||||
|
||||
/*!\brief the function extra info allows to
|
||||
/*!
|
||||
* \brief the function extra info allows to
|
||||
* - add a attachment
|
||||
* - generate an invoice
|
||||
* - insert extra info
|
||||
|
|
@ -1304,31 +1374,35 @@ EOF;
|
|||
*/
|
||||
|
||||
public function extra_info() {
|
||||
$r = '<div id="facturation_div_id" style="height:185px;height:10rem">';
|
||||
$r = '<div id="facturation_div_id" style="display:flex;height:185px;height:10rem">';
|
||||
// check for upload piece
|
||||
$file = new IFile();
|
||||
$file->table = 0;
|
||||
$file->setAlertOnSize(true);
|
||||
$r.='<p class="decale">';
|
||||
|
||||
// add a receipt
|
||||
$r.=_("Ajoutez une pièce justificative ");
|
||||
$r.=$file->input("pj", "");
|
||||
|
||||
if ($this->db->count_sql("select md_id,md_name from document_modele where md_affect='VEN' ") > 0) {
|
||||
|
||||
|
||||
$r.=_('ou générer une facture') . ' <input type="checkbox" name="gen_invoice" CHECKED>';
|
||||
// We propose to generate the invoice and some template
|
||||
$doc_gen = new ISelect();
|
||||
$doc_gen->name = "gen_doc";
|
||||
$doc_gen->value = $this->db->make_array(
|
||||
"select md_id,md_name " .
|
||||
" from document_modele where md_affect='VEN' order by 2");
|
||||
$r.=$doc_gen->input() . '<br>';
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
// Propose to generate an invoice
|
||||
//------------------------------------------------
|
||||
$r.=_('ou générer une facture') . ' <input type="checkbox" name="gen_invoice" CHECKED>';
|
||||
// We propose to generate the invoice and some template
|
||||
$doc_gen = new ISelect();
|
||||
$doc_gen->name = "gen_doc";
|
||||
$doc_gen->value = $this->db->make_array(
|
||||
"select md_id,md_name " .
|
||||
" from document_modele where md_affect='VEN' ".
|
||||
" union select -2,'"._("0 - Facture PDF Standard")."' ".
|
||||
" order by 2");
|
||||
$r.=$doc_gen->input() . '<br>';
|
||||
|
||||
$r.='<br>';
|
||||
$obj = new IText();
|
||||
$r.=_('Numero de bon de commande : ') . $obj->input('bon_comm') . '<br>';
|
||||
$r.=_('Communication ou autre information : ') . $obj->input('other_info') . '<br>';
|
||||
$r.=_('Numero de bon de commande') . $obj->input('bon_comm') . '<br>';
|
||||
$r.=_('Communication') . $obj->input('other_info') . '<br>';
|
||||
$r.='</p>';
|
||||
$r.='</div>';
|
||||
return $r;
|
||||
|
|
|
|||
|
|
@ -91,9 +91,9 @@ class Acc_Operation
|
|||
jr_id {$this->jr_id}
|
||||
jr_optype {$this->jr_optype}
|
||||
amount {$this->amount}
|
||||
currency_rate {$this->amount}
|
||||
currency_rate_ref {$this->amount}
|
||||
currency_id {$this->amount}
|
||||
currency_rate {$this->currency_rate}
|
||||
currency_rate_ref {$this->currency_rate_ref}
|
||||
currency_id {$this->currency_id}
|
||||
]
|
||||
EOF;
|
||||
return $r;
|
||||
|
|
@ -1031,11 +1031,43 @@ EOF;
|
|||
/**
|
||||
* @class Acc_Detail
|
||||
* @brief Contains the detail of an operation Acc_Operation
|
||||
* propery :
|
||||
* - $det
|
||||
- jr_id PKfrom table JRN
|
||||
- jr_def_id id of the ledger (FK to - _DEF- _DEF_ID)from table JRN
|
||||
- jr_montant AMOUNT of the operationfrom table JRN
|
||||
- jr_comment COMMENT from table JRN
|
||||
- jr_date DATEfrom table JRN
|
||||
- jr_grpt_id CODE to group - X rowsfrom table JRN
|
||||
- jr_internal INTERNAL CODEfrom table JRN
|
||||
- jr_tech_date DATE OF CHANGEfrom table JRN
|
||||
- jr_tech_per FK TO PARAM_PERIODEP_IDfrom table JRN
|
||||
- jrn_ech from table JRN
|
||||
- jr_ech DATE LIMIT OF PAYMENTfrom table JRN
|
||||
- jr_rapt from table JRN
|
||||
- jr_echfrom table JRN
|
||||
- jr_validfrom table JRN
|
||||
- jr_opid from table JRN
|
||||
- jr_c_opidfrom table JRN
|
||||
- jr_pj OID OF THE DOCUMENTfrom table JRN
|
||||
- jr_pj_name NAME OF THE DOCUMENTfrom table JRN
|
||||
- jr_pj_typefrom table JRN
|
||||
- jr_pj_number RECEIPT NBfrom table JRN
|
||||
- jr_mt INTERNAL CODEfrom table JRN
|
||||
- jr_raptfrom table JRN
|
||||
- jr_date_paid DATE OF PAYMENTfrom table JRN
|
||||
- jr_optype TYPE OF OPERATION NOR = NORMAL OPE=OPENING EXT=EXTOURNEfrom table JRN
|
||||
- currency_id FK TO CURRENCYIDfrom table JRN
|
||||
- currency_rate amountfrom table JRN
|
||||
- currency_rate_ref amount in CURRENT_HISTORYCH_VALUEfrom table JRN
|
||||
* - note from table JRN_NOTE
|
||||
- $jr_id JRN.JR_ID
|
||||
- $info
|
||||
*/
|
||||
class Acc_Detail extends Acc_Operation
|
||||
{
|
||||
public $det;
|
||||
public $jr_id;
|
||||
public $det;//!< Object with columns from JRN
|
||||
public $jr_id;//! $jr_id (int) JRN.JR_ID
|
||||
public $info;
|
||||
|
||||
function __construct($p_cn,$p_jrid=0)
|
||||
|
|
@ -1050,10 +1082,34 @@ class Acc_Detail extends Acc_Operation
|
|||
*/
|
||||
function get()
|
||||
{
|
||||
$sql="SELECT jr_id, jr_def_id, jr_montant, jr_comment, jr_date, jr_grpt_id,
|
||||
jr_internal, jr_tech_date, jr_tech_per, jrn_ech, jr_ech, jr_rapt,jr_ech,
|
||||
jr_valid, jr_opid, jr_c_opid, jr_pj, jr_pj_name, jr_pj_type,
|
||||
jr_pj_number, jr_mt,jr_rapt,jr_date_paid,jr_optype,currency_id,currency_rate,currency_rate_ref
|
||||
$sql="SELECT jr_id
|
||||
, jr_def_id
|
||||
, jr_montant
|
||||
, jr_comment
|
||||
, jr_date
|
||||
, jr_grpt_id
|
||||
, jr_internal
|
||||
, jr_tech_date
|
||||
, jr_tech_per
|
||||
, jrn_ech
|
||||
, jr_ech
|
||||
, jr_rapt
|
||||
,jr_ech
|
||||
, jr_valid
|
||||
, jr_opid
|
||||
, jr_c_opid
|
||||
, jr_pj
|
||||
, jr_pj_name
|
||||
, jr_pj_type,
|
||||
jr_pj_number
|
||||
, jr_mt
|
||||
,jr_rapt
|
||||
,jr_date_paid
|
||||
,jr_optype
|
||||
,currency_id
|
||||
,currency_rate
|
||||
,currency_rate_ref
|
||||
,jr_document_xml
|
||||
FROM jrn where jr_id=$1";
|
||||
$array=$this->db->get_array($sql,array($this->jr_id));
|
||||
if ( count($array) == 0 ) throw new Exception('Aucune ligne trouvée');
|
||||
|
|
@ -1363,4 +1419,5 @@ class Acc_Fin extends Acc_Detail
|
|||
return $array;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,9 @@
|
|||
"label"=>"tva_label",
|
||||
"rate"=>"tva_rate",
|
||||
"comment"=>"tva_comment",
|
||||
"account"=>"tva_poste");
|
||||
"account"=>"tva_poste"
|
||||
tva_peppol_code
|
||||
* );
|
||||
|
||||
*/
|
||||
class Acc_Tva
|
||||
|
|
@ -42,7 +44,9 @@ class Acc_Tva
|
|||
"account"=>"tva_poste",
|
||||
"both_side"=>'tva_both_side',
|
||||
'tva_reverse_account'=>'tva_reverse_account',
|
||||
'tva_code'=>'tva_code');
|
||||
'tva_code'=>'tva_code',
|
||||
"tva_peppol_code"=>"tva_peppol_code"
|
||||
);
|
||||
public $tva_id,
|
||||
$tva_label,
|
||||
$tva_rate,
|
||||
|
|
@ -50,16 +54,18 @@ class Acc_Tva
|
|||
$tva_poste,
|
||||
$tva_both_side,
|
||||
$tva_code,
|
||||
$tva_reverse_account;
|
||||
$tva_reverse_account,
|
||||
$tva_peppol_code
|
||||
;
|
||||
|
||||
private $cn; //!< Database connection
|
||||
|
||||
private Tva_Rate_SQL $tva_rate_sql;
|
||||
|
||||
function __construct ($p_init,$p_tva_id=-1)
|
||||
function __construct (Database $cn,$p_tva_id=-1)
|
||||
{
|
||||
$this->cn=$p_init;
|
||||
$this->tva_rate_sql=new Tva_Rate_SQL($p_init,$p_tva_id);
|
||||
$this->cn=$cn;
|
||||
$this->tva_rate_sql=new Tva_Rate_SQL($cn,$p_tva_id);
|
||||
$this->tva_id=$p_tva_id;
|
||||
$this->tva_label=&$this->tva_rate_sql->tva_label;
|
||||
$this->tva_rate=&$this->tva_rate_sql->tva_rate;
|
||||
|
|
@ -68,6 +74,7 @@ class Acc_Tva
|
|||
$this->tva_both_side=&$this->tva_rate_sql->tva_both_side;
|
||||
$this->tva_code=&$this->tva_rate_sql->tva_code;
|
||||
$this->tva_reverse_account=&$this->tva_rate_sql->tva_reverse_account;
|
||||
$this->tva_peppol_code=&$this->tva_rate_sql->tva_peppol_code;
|
||||
|
||||
}
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -699,4 +699,18 @@ class Card_Property
|
|||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* @brief returns the property value of a card without creating a card
|
||||
* @param \Database $conx
|
||||
* @param $card_id (int) FICHE.F_ID
|
||||
* @param $property_id (int) ad_value
|
||||
* @return string or false if nothing was found
|
||||
*/
|
||||
static function get_attribute(\Database $conx, $card_id,$property_id)
|
||||
{
|
||||
$r=$conx->get_value("select ad_value from fiche_detail where
|
||||
ad_id = $1 and f_id=$2",[$property_id,$card_id]);
|
||||
if ( $conx->count() == 0) { return false;}
|
||||
return $r;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,34 +81,6 @@ class Database extends DatabaseCore
|
|||
. ",dbname = ".$this->get_dbname()
|
||||
. "]";
|
||||
}
|
||||
/***
|
||||
* \brief Save a "piece justificative" , the name must be pj
|
||||
*
|
||||
* \param $seq jr_grpt_id
|
||||
* \return $oid of the lob file if success
|
||||
* null if a error occurs
|
||||
*
|
||||
*/
|
||||
function save_receipt($seq)
|
||||
{
|
||||
$oid = $this->upload('pj');
|
||||
if ($oid == false) {
|
||||
return false;
|
||||
}
|
||||
// Remove old document
|
||||
$ret = $this->exec_sql("select jr_pj from jrn where jr_grpt_id=$seq");
|
||||
if (pg_num_rows($ret) != 0) {
|
||||
$r = pg_fetch_array($ret, 0);
|
||||
$old_oid = $r['jr_pj'];
|
||||
if (strlen($old_oid??"") != 0)
|
||||
$this->lo_unlink( $old_oid);
|
||||
}
|
||||
// Load new document
|
||||
$this->exec_sql("update jrn set jr_pj=$1 , jr_pj_name=$2,
|
||||
jr_pj_type=$3 where jr_grpt_id=$4",
|
||||
array($oid, $_FILES['pj']['name'], $_FILES['pj']['type'], $seq));
|
||||
return $oid;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get version of a database, the content of the
|
||||
|
|
|
|||
|
|
@ -19,10 +19,14 @@
|
|||
*/
|
||||
// Copyright Author Dany De Bontridder danydb@aevalys.eu
|
||||
|
||||
/*! \file
|
||||
/*!
|
||||
* \file
|
||||
* \brief Class Document corresponds to the table document
|
||||
*/
|
||||
/*! \brief Class Document corresponds to the table document
|
||||
/*!
|
||||
* \class
|
||||
* \brief
|
||||
* Class Document corresponds to the table DOCUMENT
|
||||
*/
|
||||
|
||||
class Document
|
||||
|
|
@ -38,7 +42,7 @@ class Document
|
|||
var $d_number; /*!< $d_number number of the document */
|
||||
var $md_id; /*!< $md_id document's template */
|
||||
var $f_id; /*!< fiche.f_id */
|
||||
private $counter; /*!< counter for the items ( goods ) */
|
||||
protected $counter; /*!< counter for the items ( goods ) */
|
||||
var $d_name; /*!< document name */
|
||||
var $md_type ; /*!< Type of document */
|
||||
/*!
|
||||
|
|
@ -54,6 +58,24 @@ class Document
|
|||
// counter for MARCH_NEXT
|
||||
$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
|
||||
|
|
@ -105,16 +127,20 @@ class Document
|
|||
/*!
|
||||
* \brief Generate the document, Call $this-\>replace to replace
|
||||
* tag by value
|
||||
* @param p_array contains the data normally it is the $_POST
|
||||
* @param $p_filename contains the new filename
|
||||
* @param p_array contains the data normally it is the $_POST (see Acc_Ledger_Sale or
|
||||
* Acc_Ledger_Purchase)
|
||||
* @see Acc_Ledger_Sale
|
||||
* @see Acc_Ledger_Purchase
|
||||
* @param $p_filename contains the new filename, if not given the filename will be generated
|
||||
* \return an string : the url where the generated doc can be found, the name
|
||||
* of the file and his mimetype
|
||||
*/
|
||||
|
||||
function generate($p_array, $p_filename="")
|
||||
{
|
||||
|
||||
try {
|
||||
// create a temp directory in /tmp to unpack file and to parse it
|
||||
///@var $dirname (string) temp directory in /tmp to unpack file and to parse it
|
||||
$dirname=tempnam($_ENV['TMP'], 'doc_');
|
||||
if ($dirname == false) {
|
||||
throw new Exception ('DC117 cannot create tmp file',5000);
|
||||
|
|
@ -124,6 +150,31 @@ class Document
|
|||
if ( mkdir($dirname) == false ) {
|
||||
throw new Exception ("DC121 cannot create $dirname directory",5000);
|
||||
}
|
||||
/**
|
||||
* md_id == -2 is the standard PDF invoice, you don't parse or compute
|
||||
* it
|
||||
*/
|
||||
if ( $this->md_id == -2)
|
||||
{
|
||||
$file_to_parse=str_replace(
|
||||
array('/', '*', '<', '>', ';', ',', '\\', '.', ':', '(', ')', ' ', '[', ']')
|
||||
, "-"
|
||||
, "inv-std-".$p_array['e_pj'].".pdf");
|
||||
|
||||
$this->d_number=$this->db->get_next_seq("seq_doc_type_stdinv");
|
||||
$this->d_filename=$file_to_parse;
|
||||
$this->d_mimetype="application/pdf";
|
||||
$this->d_name=$file_to_parse;
|
||||
$standard_invoice=new \Noalyss\Invoice_PDF($this->db,$dirname,$file_to_parse);
|
||||
$standard_invoice->set_data($p_array);
|
||||
$standard_invoice->export();
|
||||
$this->saveGenerated($dirname.DIRECTORY_SEPARATOR.$file_to_parse);
|
||||
// Invoice
|
||||
$href=http_build_query(array('gDossier'=>Dossier::id(), "d_id"=>$this->d_id, 'act'=>'RAW:document'));
|
||||
$ret='<A class="mtitle" HREF="export.php?'.$href.'">'._('Document').'</A>';
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// Retrieve the lob and save it into $dirname
|
||||
$this->db->start();
|
||||
$dm_info="select md_name,md_type,md_lob,md_filename,md_mimetype
|
||||
|
|
@ -145,7 +196,8 @@ class Document
|
|||
record_log(sprintf('DOCUMENT.GENERATE.D1 , export failed %s %s',$dirname, $filename));
|
||||
throw new Exception(sprintf(_("Export a échoué pour %s"), $filename));
|
||||
}
|
||||
|
||||
// $type (letter) type of document : OOo for openoffice otherwise n , with OOo the file
|
||||
// is a ZIP XML
|
||||
$type="n";
|
||||
// if the doc is a OOo, we need to unzip it first
|
||||
// and the name of the file to change is always content.xml
|
||||
|
|
@ -247,7 +299,7 @@ class Document
|
|||
{
|
||||
if (mkdir($temp_dir)==false)
|
||||
{
|
||||
$msg=sprintf("D221."._("Ne peut pas créer le répertoire %s", $temp_dir));
|
||||
$msg=sprintf("D221."._("Ne peut pas créer le répertoire %s"), $temp_dir);
|
||||
record_log("D221".$msg);
|
||||
throw new Exception($msg);
|
||||
}
|
||||
|
|
@ -332,10 +384,9 @@ class Document
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Save the generated Document
|
||||
* \brief insert the generated Document into the database, update the $this->d_id
|
||||
* that is the PK of document. and load the PDF into the database.
|
||||
* \param $p_file is the generated file
|
||||
*
|
||||
*
|
||||
* \return 0 if no error otherwise 1
|
||||
*/
|
||||
|
||||
|
|
@ -716,22 +767,22 @@ class Document
|
|||
$p_tag=noalyss_str_replace('=', '', $p_tag);
|
||||
$r="Tag inconnu";
|
||||
static $aComment=NULL;
|
||||
static $counter_comment=1; /* <! counter for the comment , skip the first one which is the descrition */
|
||||
static $counter_comment=1; /*<! counter for the comment , skip the first one which is the descrition */
|
||||
|
||||
static $aRelatedAction=NULL;
|
||||
static $counter_related_action=0; /* <! counter for the related action */
|
||||
static $counter_related_action=0; /*<! counter for the related action */
|
||||
|
||||
static $aRelatedOperation=NULL;
|
||||
static $counter_related_operation=0; /* <! counter for the related operation */
|
||||
static $counter_related_operation=0; /*<! counter for the related operation */
|
||||
|
||||
static $aFileAttached=NULL;
|
||||
static $counter_file=0; /* <! counter for the file */
|
||||
static $counter_file=0; /*<! counter for the file */
|
||||
|
||||
static $aOtherCard=NULL;
|
||||
static $counter_other_card=0; /* <! counter for the other card */
|
||||
static $counter_other_card=0; /*<! counter for the other card */
|
||||
|
||||
static $aTag=NULL;
|
||||
static $counter_tag=0; /* <! counter for the tags */
|
||||
static $counter_tag=0; /*<! counter for the tags */
|
||||
|
||||
static $aParameterExtra=NULL; // Extra parameter for the company
|
||||
switch ($p_tag)
|
||||
|
|
@ -1769,14 +1820,11 @@ class Document
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Move a document from the table document into the concerned row
|
||||
* \brief Move a document from the table document into the concerned operation
|
||||
* the document is not copied : it is only a link
|
||||
*
|
||||
* \param $p_internal internal code
|
||||
*
|
||||
*/
|
||||
|
||||
function moveDocumentPj($p_internal)
|
||||
function moveDocumentACC($p_internal)
|
||||
{
|
||||
$sql="update jrn set jr_pj=$1,jr_pj_name=$2,jr_pj_type=$3 where jr_internal=$4";
|
||||
|
||||
|
|
@ -1836,7 +1884,7 @@ class Document
|
|||
}
|
||||
|
||||
/**
|
||||
* replace a pattern with a value in the buffer , handle the change for OOo type file and amount
|
||||
* @brief replace a pattern with a value in the buffer , handle the change for OOo type file and amount
|
||||
*
|
||||
* @param string $p_buffer
|
||||
* @param string $_pattern
|
||||
|
|
@ -1890,14 +1938,14 @@ class Document
|
|||
function export_file($p_destination_file)
|
||||
{
|
||||
if ($this->d_id==0) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
$this->db->start();
|
||||
$ret=$this->db->exec_sql(
|
||||
"select d_id,d_lob,d_filename,d_mimetype from document where d_id=$1", [$this->d_id]);
|
||||
if (Database::num_row($ret)==0)
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
$row=Database::fetch_array($ret, 0);
|
||||
//the document is saved into file $tmp
|
||||
|
|
@ -1916,15 +1964,14 @@ class Document
|
|||
}
|
||||
/**
|
||||
* @brief transform the current Document to a PDF, returns the full path of the PDF from the TMP folder
|
||||
* if the file IS a pdf , then export it and return the path to the file.
|
||||
*
|
||||
* @todo replace use of unoconv with a PHP lib to convert into PDF
|
||||
* @return string full path to the PDF file
|
||||
*/
|
||||
function transform2pdf()
|
||||
{
|
||||
if (GENERATE_PDF == 'NO' ) {
|
||||
\record_log(__FILE__."D1857 PDF not available");
|
||||
throw new \Exception("Cannot not transform to PDF",5000);
|
||||
}
|
||||
// Extract from public.document
|
||||
// Extract from public.document
|
||||
$dirname=tempnam($_ENV['TMP'],"document");
|
||||
|
||||
if ( $dirname == false ) {
|
||||
|
|
@ -1935,6 +1982,16 @@ class Document
|
|||
if ( mkdir($dirname) == false ) {
|
||||
throw new Exception("D1868.cannot create tmp directory",5000);
|
||||
}
|
||||
if ( $this->d_mimetype == "application/pdf") {
|
||||
$destination_file=$dirname."/".$this->d_filename;
|
||||
$this->export_file($destination_file);
|
||||
return $dirname."/".$destination_file;
|
||||
return;
|
||||
}
|
||||
if (GENERATE_PDF == 'NO' ) {
|
||||
\record_log(__FILE__."D1857 PDF not available");
|
||||
throw new \Exception("Cannot not transform to PDF",5000);
|
||||
}
|
||||
|
||||
$destination_file=$dirname."/".$this->d_filename;
|
||||
$this->export_file($destination_file);
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@ class Fiche
|
|||
* @param int $p_ad_id AD_ID from attr_def.ad_id
|
||||
* @param int $p_return 1 return NOTFOUND otherwise an empty string
|
||||
* @see constant.php
|
||||
* @return string
|
||||
* @return string
|
||||
* @note reread data from database and so it reset previous unsaved change
|
||||
*/
|
||||
function get_attribute($p_ad_id,$p_return=1)
|
||||
|
|
@ -1345,16 +1345,17 @@ class Fiche
|
|||
bcscale(4);
|
||||
$gDossier=dossier::id();
|
||||
$p_search=sql_string($p_search);
|
||||
$script=$_SERVER['PHP_SELF'];
|
||||
$script=$_SERVER['PHP_SELF']??"";
|
||||
// Creation of the nav bar
|
||||
// Get the max numberRow
|
||||
$filter_amount='';
|
||||
global $g_user;
|
||||
|
||||
$filter_year=" j_tech_per in (select p_id from parm_periode ".
|
||||
"where p_exercice='".$g_user->get_exercice()."')";
|
||||
|
||||
if ( $p_amount) $filter_amount=' and f_id in (select f_id from jrnx where '.$filter_year.')';
|
||||
if ($p_amount) {
|
||||
$filter_amount = ' and f_id in (select f_id from jrnx where ' . $filter_year . ')';
|
||||
}
|
||||
|
||||
$all_tiers=$this->count_by_modele($this->fiche_def_ref,"",$p_sql.$filter_amount);
|
||||
// Get offset and page variable
|
||||
|
|
@ -1495,21 +1496,23 @@ class Fiche
|
|||
return $this->fiche_def;
|
||||
}
|
||||
/*!
|
||||
***************************************************
|
||||
* \brief Check if a fiche is used by a jrn
|
||||
* \brief Check if a card can be used and then belong tp a specific ledger, it the card
|
||||
*
|
||||
* return 1 if the fiche is in the range otherwise 0, the quick_code
|
||||
* or the id must be set
|
||||
*
|
||||
*
|
||||
* \param $p_jrn journal_id
|
||||
* \param $p_type : deb or cred default empty
|
||||
* \param $jrn_def_id journal_id (JRN.JRN_DEF_ID)
|
||||
* \param $side : deb or cred , default empty = both
|
||||
*
|
||||
* \return 1 if the fiche is in the range otherwise < 1
|
||||
* -1 the card doesn't exist
|
||||
* -2 the ledger has no card to check
|
||||
* \return 1 if the card belongs to the ledger,
|
||||
* 0 the card doesn't belong,
|
||||
* -1 the card doesn't exist,
|
||||
* -2 the ledger has no card to check,
|
||||
* -3 there is no category of card for this ledger
|
||||
*
|
||||
*/
|
||||
function belong_ledger($p_jrn,$p_type="")
|
||||
function belong_ledger($jrn_def_id,$side="")
|
||||
{
|
||||
// check if we have a quick_code or a f_id
|
||||
if (($this->quick_code==null || $this->quick_code == "" )
|
||||
|
|
@ -1519,41 +1522,38 @@ class Fiche
|
|||
}
|
||||
|
||||
//retrieve the quick_code
|
||||
if ( $this->quick_code=="")
|
||||
$this->quick_code=$this->get_quick_code();
|
||||
|
||||
|
||||
if ( $this->quick_code==null)
|
||||
return -1;
|
||||
|
||||
if ( $this->id == 0 )
|
||||
if ( $this->get_by_qcode(null,false) == 1)
|
||||
return -1;
|
||||
|
||||
$get="";
|
||||
if ( $p_type == 'deb' )
|
||||
{
|
||||
$get='jrn_def_fiche_deb';
|
||||
}elseif ( $p_type == 'cred' )
|
||||
{
|
||||
$get='jrn_def_fiche_cred';
|
||||
if ($this->quick_code == "") {
|
||||
$this->quick_code = $this->get_quick_code();
|
||||
}
|
||||
if ( $get != "" )
|
||||
|
||||
|
||||
if ($this->quick_code == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ($this->id == 0 && $this->get_by_qcode(null, false) == 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( $side == 'deb' )
|
||||
{
|
||||
$Res=$this->cn->exec_sql("select $get as fiche from jrn_def where jrn_def_id=$p_jrn");
|
||||
$Res=$this->cn->exec_sql("select jrn_def_fiche_deb as fiche from jrn_def where jrn_def_id=$1",[$jrn_def_id]);
|
||||
}elseif ( $side == 'cred' )
|
||||
{
|
||||
$Res=$this->cn->exec_sql("select jrn_def_fiche_cred as fiche from jrn_def where jrn_def_id=$1",[$jrn_def_id]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get all the fiche type (deb and cred)
|
||||
$Res=$this->cn->exec_sql(" select jrn_def_fiche_cred as fiche
|
||||
from jrn_def where jrn_def_id=$p_jrn
|
||||
from jrn_def where jrn_def_id=$1
|
||||
union
|
||||
select jrn_def_fiche_deb
|
||||
from jrn_def where jrn_def_id=$p_jrn"
|
||||
from jrn_def where jrn_def_id=$1",
|
||||
[$jrn_def_id]
|
||||
);
|
||||
}
|
||||
$Max=Database::num_row($Res);
|
||||
if ( $Max==0)
|
||||
if ( Database::num_row($Res)==0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
|
@ -1582,11 +1582,11 @@ class Fiche
|
|||
fd_id in (".$str_list.") and f_id= ".$this->id;
|
||||
|
||||
$Res=$this->cn->exec_sql($sql);
|
||||
$Max=Database::num_row($Res);
|
||||
if ($Max==0 )
|
||||
if (Database::num_row($Res) == 0) {
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
return 1;
|
||||
|
||||
}
|
||||
/*!
|
||||
* \brief get all the card from a categorie
|
||||
|
|
@ -1968,12 +1968,12 @@ class Fiche
|
|||
}
|
||||
/**
|
||||
* @brief create a card from a qcode and returns a card
|
||||
* @param string $p_qcode qcode of the card
|
||||
* @param $cn Database cnx
|
||||
* @param $p_qcode (string) qcode of the card
|
||||
*/
|
||||
static function from_qcode($p_qcode)
|
||||
static function from_qcode(Database $cn,string $p_qcode)
|
||||
{
|
||||
$cn=Dossier::connect();
|
||||
$card=new Card($cn);
|
||||
$card=new Fiche($cn);
|
||||
$card->get_by_qcode($p_qcode);
|
||||
return $card;
|
||||
}
|
||||
|
|
|
|||
332
include/class/invoice_pdf.class.php
Normal file
332
include/class/invoice_pdf.class.php
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
<?php
|
||||
|
||||
namespace Noalyss;
|
||||
|
||||
/*
|
||||
* This file is part of NOALYSS.
|
||||
*
|
||||
* NOALYSS is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* NOALYSS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with NOALYSS; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
// Copyright Author Dany De Bontridder danydb@aevalys.eu 22/10/23
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief create a standard invoice
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class Invoice PDF
|
||||
* @brief create a standard invoice
|
||||
*/
|
||||
class Invoice_PDF extends \PDF
|
||||
{
|
||||
|
||||
private $data; //!< $data (array) see Acc_Ledger_Purchases
|
||||
|
||||
function __construct(
|
||||
\Database $cn
|
||||
, private $dirname //!< folder where to save file
|
||||
, private $filename //!< filename to use
|
||||
)
|
||||
{
|
||||
parent::__construct($cn);
|
||||
}
|
||||
|
||||
public function get_dirname()
|
||||
{
|
||||
return $this->dirname;
|
||||
}
|
||||
|
||||
public function get_filename()
|
||||
{
|
||||
return $this->filename;
|
||||
}
|
||||
|
||||
public function set_dirname($dirname)
|
||||
{
|
||||
$this->dirname = $dirname;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function set_filename($filename)
|
||||
{
|
||||
$this->filename = $filename;
|
||||
return $this;
|
||||
}
|
||||
|
||||
function set_data($array)
|
||||
{
|
||||
$this->data = $array;
|
||||
return $this;
|
||||
}
|
||||
|
||||
function get_data()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
function footer()
|
||||
{
|
||||
//Position at 1 cm from bottom
|
||||
$this->SetY(-10);
|
||||
//Arial italic 8
|
||||
$this->SetFont('Arial', '', 8);
|
||||
//Page number
|
||||
parent::Cell(0, 8, " Page " . $this->PageNo() . '/{nb}', 0, 0, 'C');
|
||||
parent::Ln(3);
|
||||
}
|
||||
|
||||
function header()
|
||||
{
|
||||
global $g_parameter;
|
||||
$this->setY(15);
|
||||
$this->SetFont('DejaVu', '', 6);
|
||||
$colsize = 90;
|
||||
$this->write_multi($colsize, 3, $g_parameter->MY_NAME);
|
||||
$this->write_multi($colsize, 3, $this->data['e_date'], border: '', align: 'R');
|
||||
$this->line_new();
|
||||
$this->write_multi($colsize, 3,
|
||||
sprintf("%s %s "
|
||||
, $g_parameter->MY_STREET
|
||||
, $g_parameter->MY_NUMBER));
|
||||
$this->line_new();
|
||||
$this->write_multi($colsize, 3, $g_parameter->MY_POSTCODE
|
||||
. " " . $g_parameter->MY_CITY
|
||||
. " " . $g_parameter->MY_COUNTRY
|
||||
);
|
||||
$this->line_new();
|
||||
$this->write_multi($colsize, 3, $g_parameter->MY_TVA);
|
||||
$this->line_new();
|
||||
|
||||
$email_company = $this->cn->get_value("select pe_value from parameter_extra where pe_code=$1",
|
||||
['INVOICE_EMAIL_COMPANY']);
|
||||
$site = $this->cn->get_value("select pe_value from parameter_extra where pe_code=$1",
|
||||
['WEB_COMPANY']);
|
||||
// for FRANCE , the SIREN and SIRET must be given
|
||||
$siren = $this->cn->get_value("select pe_value from parameter_extra where pe_code=$1",
|
||||
['SIREN']);
|
||||
$siret = $this->cn->get_value("select pe_value from parameter_extra where pe_code=$1",
|
||||
['SIRET']);
|
||||
$iban = $this->cn->get_value("select pe_value from parameter_extra where pe_code=$1",
|
||||
['COMPANY_BANK_IBAN']);
|
||||
$bic = $this->cn->get_value("select pe_value from parameter_extra where pe_code=$1",
|
||||
['COMPANY_BANK_BIC']);
|
||||
|
||||
if ($siret != "")
|
||||
{
|
||||
$this->write_multi($colsize, 3, "SIRET $siret");
|
||||
$this->line_new();
|
||||
}
|
||||
if ($siren != "")
|
||||
{
|
||||
$this->write_multi($colsize, 3, "SIREN $siren");
|
||||
$this->line_new();
|
||||
}
|
||||
if ($iban != "")
|
||||
{
|
||||
$this->write_multi($colsize, 3, "IBAN $iban BIC $bic");
|
||||
$this->line_new();
|
||||
}
|
||||
if ($g_parameter->MY_PHONE != "")
|
||||
{
|
||||
$this->write_multi($colsize, 3, sprintf(_("Tel %s "),
|
||||
$g_parameter->MY_PHONE
|
||||
));
|
||||
$this->line_new();
|
||||
}
|
||||
if ($email_company != "")
|
||||
{
|
||||
$this->write_multi($colsize, 3, sprintf(_("email %s "),
|
||||
$email_company));
|
||||
$this->line_new();
|
||||
}
|
||||
if ($site != "")
|
||||
{
|
||||
$this->write_multi($colsize, 3, sprintf(_("site %s"),
|
||||
$site
|
||||
));
|
||||
$this->line_new();
|
||||
}
|
||||
$this->setFont("DejaVu", 'B', 14);
|
||||
$this->write_multi(40, 10, "");
|
||||
$this->write_multi(100, 10, _("Facture") . " " . $this->data['e_pj'], border: 1, align: 'C');
|
||||
$this->write_multi(40, 10, "");
|
||||
$this->line_new(10);
|
||||
$this->ln(5);
|
||||
}
|
||||
|
||||
//!
|
||||
//@brief make the invoice
|
||||
function export()
|
||||
{
|
||||
$this->SetAuthor('NOALYSS');
|
||||
$this->AliasNbPages();
|
||||
$this->AddPage();
|
||||
$this->SetAutoPageBreak(true, $this->bMargin*1);
|
||||
$this->setTitle($this->filename, true);
|
||||
// $customer (Fiche) retrieve card of the customer
|
||||
$customer = new \Fiche($this->cn);
|
||||
$customer->get_by_qcode(trim($this->data['e_client']));
|
||||
|
||||
$this->setFont("DejaVu", '', 7);
|
||||
$this->write_cell(50, 4, "");
|
||||
$this->write_cell(60, 4, sprintf(_("Echéance %s"), $this->data['e_ech']));
|
||||
$this->line_new();
|
||||
$this->write_cell(50, 4, "");
|
||||
$this->write_cell(100, 4, _("Client"), 'B', 'R');
|
||||
$this->line_new();
|
||||
$this->write_cell(50, 4, "");
|
||||
$this->write_cell(110, 4, $customer->get_attribute(ATTR_DEF_NAME)
|
||||
. " " . $customer->get_attribute(ATTR_DEF_FIRST_NAME, 0));
|
||||
$this->line_new();
|
||||
$this->write_cell(50, 4, "");
|
||||
$this->write_cell(110, 4, $customer->get_attribute(ATTR_DEF_ADRESS, 0));
|
||||
$this->line_new();
|
||||
$this->write_cell(50, 4, "");
|
||||
$this->write_cell(110, 4, $customer->get_attribute(ATTR_DEF_POSTCODE, 0)
|
||||
. " " . $customer->get_attribute(ATTR_DEF_CITY, 0)
|
||||
);
|
||||
$this->line_new();
|
||||
$this->write_cell(50, 4, "");
|
||||
$this->write_cell(110, 4, $customer->get_attribute(ATTR_DEF_COUNTRY, 0));
|
||||
$this->line_new();
|
||||
$this->write_cell(50, 4, "");
|
||||
$this->write_cell(110, 4, $customer->get_attribute(ATTR_DEF_NUMTVA, 0));
|
||||
$this->line_new();
|
||||
$a_tva_amount = [];
|
||||
$a_tva_code = [];
|
||||
$col = array(
|
||||
"quick_code" => 30,
|
||||
"label" => 80,
|
||||
"quantity" => 25,
|
||||
"price" => 25,
|
||||
"vat_code" => 20
|
||||
);
|
||||
$this->SetFont("DejaVu", "B", 12);
|
||||
$this->write_multi(50, 20, "");
|
||||
$this->write_multi(50, 20, _("Détails"));
|
||||
$this->line_new();
|
||||
$this->SetFont("DejaVuCond", "", 7);
|
||||
$currency = new \Acc_Currency($this->cn, $this->data['p_currency_code']);
|
||||
$this->write_multi(60, 4, sprintf(_("Les montants sont en %s taux %s")
|
||||
, $currency->get_code()
|
||||
, $this->data['p_currency_rate']));
|
||||
$this->line_new(4);
|
||||
if ($this->data["bon_comm"] != "")
|
||||
{
|
||||
$this->write_multi(120, 4, sprintf(_("Bon de commande / référence %s")
|
||||
, $this->data["bon_comm"]));
|
||||
$this->line_new(4);
|
||||
}
|
||||
$this->line_new(4);
|
||||
$this->SetFont("DejaVu", "", 7);
|
||||
$this->write_multi($col['quick_code'], 4, _("Article"), 1);
|
||||
$this->write_multi($col['label'], 4, _("Description"), 1);
|
||||
$this->write_multi($col['quantity'], 4, _("Quantité"), 1);
|
||||
$this->write_multi($col['price'], 4, _("Prix"), 1);
|
||||
$this->write_multi($col['vat_code'], 4, _("TVA"), 1);
|
||||
$this->line_new();
|
||||
///@var $tot_amount (float) total amount without VAT
|
||||
///@var $tot_vat (float) total VAT
|
||||
///@var $line (int) line printed
|
||||
$tot_amount = $tot_vat = $line =0;
|
||||
for ($i = 0; $i < $this->data['nb_item']; $i++)
|
||||
{
|
||||
$item = new \Fiche($this->cn);
|
||||
if (!isset($this->data['e_march' . $i]) || $this->data['e_march' . $i] == "")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$line++;
|
||||
$item->get_by_qcode(trim($this->data['e_march' . $i]));
|
||||
$fill = $this->is_fill($line);
|
||||
$this->write_multi($col['quick_code'], 4, $item->get_attribute(ATTR_DEF_QUICKCODE),'','',$fill);
|
||||
$this->write_multi($col['label'], 4, $this->data['e_march' . $i . '_label'],fill:$fill);
|
||||
$this->write_multi($col['quantity'], 4, nbm($this->data['e_quant' . $i]), '', 'R',fill:$fill);
|
||||
$this->write_multi($col['price'], 4, nbm($this->data['e_march' . $i . '_price']), '', 'R',fill:$fill);
|
||||
$this->write_multi($col['vat_code'], 4, $this->data['e_march' . $i . '_tva_id'], '', 'C',fill:$fill);
|
||||
$x = $this->data['e_march' . $i . '_tva_id'];
|
||||
if (!isset($a_tva_amount[$x]))
|
||||
{
|
||||
$a_tva_amount[$x] = 0;
|
||||
}
|
||||
$a_tva_amount[$x] = bcadd($a_tva_amount[$x], $this->data["e_march" . $i . "_tva_amount"], 2);
|
||||
$tot_amount = bcadd($tot_amount
|
||||
, bcmul($this->data['e_march' . $i . '_price']
|
||||
, $this->data['e_quant' . $i]
|
||||
, 2
|
||||
)
|
||||
, 2);
|
||||
$tot_vat = bcadd($tot_vat
|
||||
, $this->data['e_march' . $i . '_tva_amount']
|
||||
, 2);
|
||||
$this->line_new(4);
|
||||
if ($this->GetY()>250) {
|
||||
$this->AddPage();
|
||||
}
|
||||
}
|
||||
$this->line_new(10);
|
||||
$this->SetFont("DejaVu", "B", 9);
|
||||
$this->write_multi(30, 4, _("TVA"));
|
||||
$this->line_new(5);
|
||||
$this->SetFont("DejaVu", "", 7);
|
||||
foreach ($a_tva_amount as $tva_id => $tva_amount)
|
||||
{
|
||||
$tva = \Acc_Tva::build($this->cn, $tva_id);
|
||||
$this->write_multi(20, 4, "");
|
||||
$this->write_multi(80, 4, $tva->tva_id
|
||||
. " / " . $tva->tva_code
|
||||
. " / " . $tva->tva_label
|
||||
. " / " . $tva->tva_rate * 100
|
||||
);
|
||||
|
||||
$this->write_multi(50, 4, $tva_amount);
|
||||
$this->line_new();
|
||||
}
|
||||
$this->ln(20);
|
||||
$this->SetFont("DejaVu", "B", 9);
|
||||
$this->write_multi(30, 4, _("TOTAUX"));
|
||||
$this->line_new();
|
||||
$this->SetFont("DejaVu", "", 7);
|
||||
$this->write_multi(60, 4, _("Total Hors TVA "));
|
||||
$this->write_multi(60, 4, nbm($tot_amount), '', 'R');
|
||||
$this->line_new();
|
||||
$this->write_multi(60, 4, _("Total TVA "));
|
||||
$this->write_multi(60, 4, nbm($tot_vat), '', 'R');
|
||||
$this->line_new();
|
||||
$this->write_multi(60, 4, _("Total "));
|
||||
$this->write_multi(60, 4, nbm(bcadd($tot_amount, $tot_vat, 2),2), '', 'R');
|
||||
$this->line_new();
|
||||
$iban = $this->cn->get_value("select pe_value from parameter_extra where pe_code=$1",
|
||||
['COMPANY_BANK_IBAN']);
|
||||
if ($this->data['e_ech'] != "" && $iban != "")
|
||||
{
|
||||
$info = ($this->data["other_info"] == "") ? $this->data["e_pj"] : $this->data["other_info"];
|
||||
$bic = $this->cn->get_value("select pe_value from parameter_extra where pe_code=$1",
|
||||
['COMPANY_BANK_IBAN']);
|
||||
$this->write_multi(150, 4,
|
||||
sprintf(_("Paiement avant le %s sur le compte %s (BIC %s) avec comme message %s"),
|
||||
$this->data['e_ech']
|
||||
, $iban
|
||||
, $bic
|
||||
, $this->data["other_info"]
|
||||
)
|
||||
);
|
||||
$this->line_new();
|
||||
}
|
||||
$this->Output($this->dirname . DIRECTORY_SEPARATOR . $this->filename, "F");
|
||||
}
|
||||
}
|
||||
|
|
@ -227,10 +227,10 @@ select sum(signed_amount) delta,sum(debit) debit,sum(credit) credit from saldo_d
|
|||
$ledger->save($oe_data);
|
||||
$oe_result=_("Détail opération");
|
||||
$oe_result.=sprintf('<a class="detail" style="display:inline" href="javascript:modifyOperation(%d,%d)">%s</a><hr>',
|
||||
$ledger->jr_id, dossier::id(), $ledger->internal);
|
||||
$ledger->jr_id, dossier::id(), $ledger->jr_internal);
|
||||
|
||||
$cn->exec_sql("update operation_exercice set oe_transfer_date=to_timestamp($1,'DD.MM.YY HH24:MI') , jr_internal=$2 where oe_id=$3",
|
||||
[date('d.m.Y H:i'),$ledger->internal,$this->operation_exercice_sql->oe_id]);
|
||||
[date('d.m.Y H:i'),$ledger->jr_internal,$this->operation_exercice_sql->oe_id]);
|
||||
|
||||
$cn->commit();
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -191,13 +191,13 @@ class Tva_Rate_MTable extends Manage_Table_SQL
|
|||
$text->selected=$value;
|
||||
$text->transform(array(
|
||||
null=>_('-')
|
||||
,"S"=>_('Taux standard')
|
||||
,'AE'=>_('Autoliquidate mais pas INTRACOMM.')
|
||||
,'Z'=>_("TVA à 0%")
|
||||
,'K'=>_('Autoliquidation INTRACOMM.')
|
||||
,'G'=>_('TVA exempt pour export hors Europe')
|
||||
,'O'=>_('TVA Hors périmètre application')
|
||||
,'E'=>_('Exempté de TVA')
|
||||
,"S"=>_('S Taux standard')
|
||||
,'AE'=>_('AE Autoliquidate mais pas INTRACOMM.')
|
||||
,'Z'=>_("Z TVA à 0%")
|
||||
,'K'=>_('K Autoliquidation INTRACOMM.')
|
||||
,'G'=>_('G TVA exempt pour export hors Europe')
|
||||
,'O'=>_('O TVA Hors périmètre application')
|
||||
,'E'=>_('E Exempté de TVA')
|
||||
));
|
||||
echo $text->input();
|
||||
}elseif ($key == "tva_id") {
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ if (!isset($_POST['summary']) && !isset($_POST['save'])) {
|
|||
echo _("Détail opération");
|
||||
echo " ";
|
||||
printf('<a class="detail" style="display:inline" href="javascript:modifyOperation(%d,%d)">%s</a><hr>',
|
||||
$jr_id, dossier::id(), $ledger->internal);
|
||||
$jr_id, dossier::id(), $ledger->jr_internal);
|
||||
echo '</div>';
|
||||
|
||||
// show feedback
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ $http=new HttpInput();
|
|||
$strac=$http->request('ac');
|
||||
$ac="ac=".$strac;
|
||||
$p_msg="";
|
||||
$post_jrn=$http->post("p_jrn", "string","");
|
||||
//@var $post_jrn (int) Ledger id JRN_DEF.JRN_DEF_ID
|
||||
$post_jrn=$http->post("p_jrn", "number","");
|
||||
//----------------------------------------------------------------------
|
||||
// Encode a new invoice
|
||||
// empty form for encoding
|
||||
|
|
@ -65,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))
|
||||
{
|
||||
|
|
@ -79,6 +83,28 @@ if ( isset ($_POST['view_invoice'] ) )
|
|||
echo '<form class="print" enctype="multipart/form-data" method="post">';
|
||||
echo dossier::hidden();
|
||||
echo $Ledger->confirm($_POST );
|
||||
//----------------------------------------------------
|
||||
// Check that INVOICE can be generated
|
||||
// for e-invoice only
|
||||
//----------------------------------------------------
|
||||
if ($g_parameter->MY_INVOICE_FORMAT != 'BASIC')
|
||||
{
|
||||
$xmldocument= \Noalyss\XMLDocument\XMLInvoice::build_xmlinvoice($cn);
|
||||
$array=[];
|
||||
$array['supplier']=$xmldocument->fill_supplier();
|
||||
$customer=Fiche::from_qcode($cn,trim($http->post("e_client")));
|
||||
|
||||
$array['customer']=$xmldocument->fill_customer($customer->id);
|
||||
$array['operation']=$xmldocument->fill_operation_from_array($_POST);
|
||||
$array['due_date']=$http->post("e_ech");
|
||||
if ( $array['due_date'] == '')
|
||||
{
|
||||
$array['due_date']=$http->post("e_date");
|
||||
}
|
||||
$xmldocument->set_data($array);
|
||||
$xmldocument->display_error();
|
||||
}
|
||||
|
||||
echo HtmlInput::hidden('ac',$strac);
|
||||
$Ledger->input_extra_info();
|
||||
echo HtmlInput::submit("record", _("Enregistrement"), 'onClick="return verify_ca(\'\');"');
|
||||
|
|
@ -121,10 +147,113 @@ if ( isset($_POST['record']) )
|
|||
else
|
||||
echo '<div class="content">';
|
||||
|
||||
$Ledger=new Acc_Ledger_Sale($cn,$_POST['p_jrn']);
|
||||
$Ledger=new Acc_Ledger_Sale($cn,$post_jrn);
|
||||
try {
|
||||
$internal=$Ledger->insert($_POST);
|
||||
|
||||
// var $receipt (string) contains the name of the file name of
|
||||
// the invoice (document created), if empty there
|
||||
// is no invoice
|
||||
|
||||
$receipt='';
|
||||
//-------------------------------------------------------
|
||||
// Generate a XLM invoice
|
||||
// if a document has been created create the XML file
|
||||
//-------------------------------------------------------
|
||||
///@var $flag_invoice (int) error for invoice generating.
|
||||
/// 0 = nothing no invoice created
|
||||
/// 1 = cannot create e-invoice
|
||||
/// 2 = create e-invoice requested
|
||||
|
||||
$flag_invoice=0;
|
||||
/* Save the attachment or generate doc */
|
||||
if (isset($_FILES['pj']) && noalyss_strlentrim($_FILES['pj']['name']) != 0)
|
||||
{
|
||||
$acc_document=new Acc_Document($cn,$Ledger->jr_id);
|
||||
$acc_document->save_receipt();
|
||||
$receipt= HtmlInput::show_receipt_document($Ledger->jr_id
|
||||
,h($_FILES['pj']['name']));
|
||||
}
|
||||
else
|
||||
/* Generate an invoice and save it into the database */
|
||||
if (isset($_POST['gen_invoice']))
|
||||
{
|
||||
//@var $invoice_template (int) get the invoice number DOCUMENT_MODELE.MD_ID
|
||||
$invoice_template=$http->post("gen_doc","number");
|
||||
// generate an invoice
|
||||
$file = $Ledger->create_document($internal, $_POST);
|
||||
$receipt= HtmlInput::show_receipt_document($Ledger->jr_id
|
||||
,h($file));
|
||||
$acc_document=new Acc_Document($cn,$Ledger->jr_id);
|
||||
|
||||
/**
|
||||
* @todo si Client non belge ou pas de n° de tva alors pas de e-facture
|
||||
*/
|
||||
if ($g_parameter->MY_INVOICE_FORMAT != 'BASIC' && ! empty($acc_document->d_filename ))
|
||||
{
|
||||
$flag_invoice=2;
|
||||
$xmldocument= \Noalyss\XMLDocument\XMLInvoice::build_xmlinvoice($cn);
|
||||
$xmldocument->build_data($Ledger->jr_id);
|
||||
$code_error = $xmldocument->verify() ;
|
||||
// check that all the sub arrays are empty
|
||||
if ( ! empty( array_filter($code_error,function($a){ if (!empty($a)) return true; })))
|
||||
{
|
||||
$xmldocument->display_error();
|
||||
$flag_invoice=1;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------
|
||||
// flag_invoice == 2 , generate an e-invoice
|
||||
//------------------------------------------------
|
||||
if ( $flag_invoice == 2 )
|
||||
{
|
||||
$pdf_filename=$acc_document->d_filename;
|
||||
if ( $acc_document->d_mimetype != 'application/pdf')
|
||||
{
|
||||
$pdf_filename=$acc_document->transform2pdf();
|
||||
|
||||
// save PDF In db
|
||||
$acc_document->update($pdf_filename);
|
||||
}else{
|
||||
$pdf_filename=$_ENV['TMP']."/".$pdf_filename;
|
||||
$acc_document->export_file($pdf_filename);
|
||||
}
|
||||
// make the PDF
|
||||
$xmldocument->set_pdf_filename($pdf_filename);
|
||||
|
||||
// make the XML + PDF
|
||||
$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";
|
||||
file_put_contents($uniq, $xml);
|
||||
chmod ($uniq,774);
|
||||
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');
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
if ( $e->getCode()==EXC_BALANCE)
|
||||
|
|
@ -144,14 +273,17 @@ if ( isset($_POST['record']) )
|
|||
}
|
||||
|
||||
/* Show button */
|
||||
echo '<h1> Enregistrement </h1>';
|
||||
|
||||
echo '<h1>'._("Enregistré").'</h1>';
|
||||
if ($flag_invoice == 1) {
|
||||
echo_warning(_("Impossible de générer facture électronique") );
|
||||
$xmldocument->display_error();
|
||||
}
|
||||
echo $Ledger->confirm($_POST,true);
|
||||
/* Show link for Invoice */
|
||||
if (isset ($Ledger->doc) )
|
||||
if ($receipt != "")
|
||||
{
|
||||
echo '<h2 class="h-section">'._('Document').' </h2>';
|
||||
echo $Ledger->doc;
|
||||
echo $receipt;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -224,8 +224,8 @@ define("ATTR_DEF_BQ_NO", 3);
|
|||
define("ATTR_DEF_BQ_NAME", 4);
|
||||
define("ATTR_DEF_PRIX_ACHAT", 7);
|
||||
define("ATTR_DEF_PRIX_VENTE", 6);
|
||||
define("ATTR_DEF_TVA", 2);
|
||||
define("ATTR_DEF_NUMTVA", 13);
|
||||
define("ATTR_DEF_TVA", 2); // usable VAT for goods and services
|
||||
define("ATTR_DEF_NUMTVA", 13); // number of VAT
|
||||
define("ATTR_DEF_ADRESS", 14);
|
||||
define("ATTR_DEF_POSTCODE", 15);
|
||||
define("ATTR_DEF_COUNTRY", 16);
|
||||
|
|
@ -427,7 +427,13 @@ function noalyss_class_autoloader($class)
|
|||
'noalyss\file_cache'=>"lib/file_cache.class.php",
|
||||
"pdfland"=>"class/pdf_land.class.php",
|
||||
"noalyss\widget\widget"=>"widget/widget.php",
|
||||
"noalyss\otp"=>"lib/otp.class.php"
|
||||
"noalyss\otp"=>"lib/otp.class.php",
|
||||
'noalyss\xmldocument\xmlinvoice'=>'XMLDocument/XMLInvoice.php',
|
||||
'noalyss\xmldocument\facturx'=>'XMLDocument/FacturX.php',
|
||||
'noalyss\xmldocument\invoiceubl21'=>'XMLDocument/InvoiceUBL21.php',
|
||||
'noalyss\xmldocument\error_message'=>'XMLDocument/Error_Message.php',
|
||||
"noalyss\invoice_pdf"=>"class/invoice_pdf.class.php",
|
||||
'noalyss\xmldocument\xmlinvoice_reader'=>'XMLDocument/xmlinvoice_reader.class.php'
|
||||
);
|
||||
if (isset ($aClass[$class])) {
|
||||
require_once NOALYSS_INCLUDE . "/" . $aClass[$class];
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ try
|
|||
}
|
||||
catch (Exception $exc)
|
||||
{
|
||||
error_log($exc->getTraceAsString());
|
||||
record_log($exc);
|
||||
return;
|
||||
}
|
||||
$cn=Dossier::connect();
|
||||
|
|
|
|||
122
include/export/export_xml-invoice.php
Normal file
122
include/export/export_xml-invoice.php
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of NOALYSS.
|
||||
*
|
||||
* NOALYSS is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* NOALYSS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with NOALYSS; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
// Copyright Author Dany De Bontridder danydb@aevalys.eu 22/10/23
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief export the XML invoice from JRN.JR_DOCUMENT_XML
|
||||
*/
|
||||
if ( ! defined ('ALLOWED')) die (_('Non autorisé'));
|
||||
|
||||
$http=new HttpInput();
|
||||
|
||||
try
|
||||
{
|
||||
$jr_id=$http->get('jr_id',"number");
|
||||
}
|
||||
catch (Exception $exc)
|
||||
{
|
||||
record_log($exc);
|
||||
return;
|
||||
}
|
||||
|
||||
$cn=Dossier::connect();
|
||||
|
||||
$r=$cn->exec_sql("select jr_def_id from jrn where jr_id=$1",array($jr_id));
|
||||
|
||||
if ( Database::num_row($r) == 0 )
|
||||
{
|
||||
echo_error("Invalid operation id jr_id=$jr_id");
|
||||
exit;
|
||||
}
|
||||
$a=Database::fetch_array($r,0);
|
||||
$jrn=$a['jr_def_id'];
|
||||
global $g_user;
|
||||
if ($g_user->check_jrn($jrn) == 'X' )
|
||||
{
|
||||
/* Cannot Access */
|
||||
NoAccess();
|
||||
exit -1;
|
||||
}
|
||||
|
||||
$ret=$cn->exec_sql("select jr_pj_name,jr_pj_number ,jr_document_xml from jrn where jr_id=$1",
|
||||
array($jr_id));
|
||||
|
||||
if ( Database::num_row ($ret) == 0 )
|
||||
return;
|
||||
|
||||
$row=Database::fetch_array($ret,0);
|
||||
|
||||
if ( $row['jr_document_xml']==null )
|
||||
{
|
||||
ini_set('zlib.output_compression','Off');
|
||||
header("Pragma: public");
|
||||
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
|
||||
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
|
||||
header("Cache-Control: must-revalidate");
|
||||
header('Content-type: '.'text/plain');
|
||||
header('Content-Disposition: attachment;filename=vide.txt',FALSE);
|
||||
header("Accept-Ranges: bytes");
|
||||
echo "******************";
|
||||
echo _("Fichier effacé");
|
||||
echo "******************";
|
||||
exit();
|
||||
}
|
||||
$tmp=tempnam($_ENV['TMP'],'document_');
|
||||
|
||||
$new_name=$row['jr_pj_name'];
|
||||
$receipt_number=clean_filename($row['jr_pj_number']);
|
||||
$receipt_number=noalyss_str_replace('.','-',$receipt_number);
|
||||
if ( ! empty($receipt_number) && strpos($new_name,$receipt_number) === false ) {
|
||||
|
||||
$new_name=$receipt_number.'-'.$new_name;
|
||||
}
|
||||
// replace extension by xml (normally a PDF)
|
||||
//@var $pos_ext (int) where is the last dot
|
||||
$pos_ext=strrpos($new_name,'.');
|
||||
if ( $pos_ext == 0)
|
||||
{
|
||||
// there is no extension
|
||||
$new_name.='.xml';
|
||||
}else {
|
||||
$new_name=substr_replace($new_name,'.xml',$pos_ext);
|
||||
}
|
||||
$cn->start();
|
||||
|
||||
$cn->lo_export($row['jr_document_xml'],$tmp);
|
||||
$cn->commit();
|
||||
|
||||
ini_set('zlib.output_compression','Off');
|
||||
header("Pragma: public");
|
||||
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
|
||||
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
|
||||
header("Cache-Control: must-revalidate");
|
||||
header('Content-type: application/xml');
|
||||
header('Content-Disposition: attachment;filename="'.$new_name.'"',FALSE);
|
||||
header("Accept-Ranges: bytes");
|
||||
|
||||
$file=fopen($tmp,'r');
|
||||
while ( !feof ($file) )
|
||||
echo fread($file,8192);
|
||||
|
||||
fclose($file);
|
||||
|
||||
unlink ($tmp);
|
||||
|
|
@ -1877,3 +1877,20 @@ function guidv4($data = null) {
|
|||
// Output the 36 character UUID.
|
||||
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
|
||||
}
|
||||
/**
|
||||
* @brief retrieve the index for the key percent, returns -1 if nothing found
|
||||
* @param $array (array) SubTotal
|
||||
* @param $key (string) name of the key
|
||||
* @param $value (string) value to look for
|
||||
* @return int
|
||||
*/
|
||||
function find_idx($array,$key,$value) {
|
||||
if ( count($array) == 0 ) { return -1; }
|
||||
$nb_array=count($array);
|
||||
for($i=0;$i <$nb_array;$i++) {
|
||||
if ($array[$i][$key] == $value) {
|
||||
return $i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -718,27 +718,39 @@ class DatabaseCore
|
|||
}
|
||||
|
||||
/***
|
||||
* \brief Save a document into the database , it just puts the file in the database
|
||||
* \brief Save one or several documents into the database , it just puts the file in the database
|
||||
* and returns the corresponding OID , the mimetype , size ... of the document
|
||||
* must be set in the calling function.
|
||||
*
|
||||
* \param name of the variable in $_FILES
|
||||
* \param $only_oid (bool) (default :true) false : return filename and oid in an array , true only OID,
|
||||
* \return $oid of the lob file if success
|
||||
* false if a error occurs or if there is no file to upload
|
||||
* array(oid, filename) if $only_oid is true
|
||||
*
|
||||
*/
|
||||
|
||||
function upload($p_name)
|
||||
function upload($p_name,$only_oid = false)
|
||||
{
|
||||
|
||||
//var $a : 0 we're in a transaction, 1 we are not in a transaction
|
||||
$a=0;
|
||||
if ( $this->status() !== PGSQL_TRANSACTION_INTRANS ) {
|
||||
$a=1;
|
||||
$this->start();
|
||||
}
|
||||
|
||||
/* there is no file to upload */
|
||||
if ($_FILES[$p_name]["error"] == UPLOAD_ERR_NO_FILE) {
|
||||
\record_log("DC759: error upload file".var_export($_FILES, true));
|
||||
if ( $a==1) { $this->rollback(); }
|
||||
return false;
|
||||
}
|
||||
|
||||
$new_name = tempnam($_ENV['TMP'], $p_name);
|
||||
if ($_FILES[$p_name]["error"] > 0) {
|
||||
print_r($_FILES);
|
||||
echo_error(__FILE__ . ":" . __LINE__ . "Error: " . $_FILES[$p_name]["error"]);
|
||||
\record_log("DC740: error upload file".var_export($_FILES, true));
|
||||
if ( $a==1) { $this->rollback(); }
|
||||
return false;
|
||||
}
|
||||
if (strlen($_FILES[$p_name]['tmp_name']) != 0) {
|
||||
|
|
@ -746,19 +758,101 @@ class DatabaseCore
|
|||
// echo "Image saved";
|
||||
$oid = pg_lo_import($this->db, $new_name);
|
||||
if ($oid == false) {
|
||||
echo_error(__FILE__, __LINE__, "cannot upload document");
|
||||
\record_log("DC747: error upload file".var_export($_FILES, true). "SQL MESSAGE". pg_last_error($this->db));
|
||||
$this->rollback();
|
||||
return false;
|
||||
}
|
||||
return $oid;
|
||||
if ( $a == 1 ) { $this->commit(); }
|
||||
if ($only_oid ){
|
||||
return $oid;
|
||||
}else {
|
||||
return ["oid"=>$oid,'filename'=>$new_name];
|
||||
}
|
||||
} else {
|
||||
echo "<H1>Error</H1>";
|
||||
\record_log("DC754: move_uploaded fails".var_export($_FILES, true));
|
||||
$this->rollback();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
\record_log("DC576: Files error names empty".var_export($_FILES, true));
|
||||
if ( $a == 1) { $this->commit(); }
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @brief large_object writee: create a Large object if oid is not given
|
||||
* with data content in a binaray
|
||||
* @param $binary_data (raw data) binary
|
||||
* @returns $oid of the LO, false if it fails
|
||||
*/
|
||||
function lo_write($binary_data)
|
||||
{
|
||||
//var $a : 0 where in a transaction, 1 we are not in a transaction
|
||||
$a=0;
|
||||
if ( $this->status() !== PGSQL_TRANSACTION_INTRANS ) {
|
||||
$a=1;
|
||||
$this->start();
|
||||
}
|
||||
|
||||
$oid= pg_lo_create($this->db);
|
||||
|
||||
if ( ($handle=pg_lo_open($this->db,$oid,"w")) == false ) { return false ;}
|
||||
pg_lo_write($handle, $binary_data);
|
||||
pg_lo_close($handle);
|
||||
if ( $a==1) { $this->commit(); }
|
||||
return $oid;
|
||||
|
||||
}
|
||||
/**
|
||||
* @brief read a Large object with data content in a binary
|
||||
* @param $oid (int8) oid of the large object
|
||||
* @returns $binary_data (raw data) binary
|
||||
*/
|
||||
function lo_read($oid)
|
||||
{
|
||||
//var $a : 0 where in a transaction, 1 we are not in a transaction
|
||||
$a=0;
|
||||
if ( $this->status() !== PGSQL_TRANSACTION_INTRANS ) {
|
||||
$a=1;
|
||||
$this->start();
|
||||
}
|
||||
|
||||
$handle=pg_lo_open($this->db,$oid,"r");
|
||||
if ( $handle == false ) { return false ;}
|
||||
// set position end of the LO
|
||||
pg_lo_seek($handle, 0, PGSQL_SEEK_END);
|
||||
// get the size
|
||||
$size= pg_lo_tell($handle);
|
||||
// set position to start
|
||||
pg_lo_seek($handle, 0, PGSQL_SEEK_SET);
|
||||
// read the comùplete LOB
|
||||
$binary_data = pg_lo_read($handle,$size );
|
||||
pg_lo_close($handle);
|
||||
if ( $a==1) { $this->commit(); }
|
||||
return $binary_data;
|
||||
}
|
||||
/**
|
||||
* @brief replace a Large object with data content in a binary
|
||||
* @param $oid (int8) oid of the large object
|
||||
* @param $binary_data (raw data) binary
|
||||
* @returns $oid of the LO, false if it fails
|
||||
*/
|
||||
function lo_replace($binary_data, $oid) {
|
||||
$a = 0;
|
||||
if ($this->status() !== PGSQL_TRANSACTION_INTRANS) {
|
||||
$a = 1;
|
||||
$this->start();
|
||||
}
|
||||
$handle = pg_lo_open($this->db, $oid, "w");
|
||||
if ( $handle == false ) { return false ;}
|
||||
pg_lo_truncate($handle, 0);
|
||||
pg_lo_write($handle, $binary_data);
|
||||
pg_lo_close($handle);
|
||||
if ($a == 1) {
|
||||
$this->commit();
|
||||
}
|
||||
return $oid;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief wrapper for the function pg_num_rows
|
||||
|
|
@ -823,7 +917,7 @@ class DatabaseCore
|
|||
/**
|
||||
* \brief wrapper for the function pg_lo_unlink
|
||||
* \param $p_oid is the of oid
|
||||
* \return return the result of the operation
|
||||
* \return return the result of the operation : false == fails
|
||||
*/
|
||||
|
||||
function lo_unlink($p_oid)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
* @brief show the common parts of operation details
|
||||
*
|
||||
* Variables : $div = popup or box (det[0-9]
|
||||
*
|
||||
*@var $obj = Acc_Operation
|
||||
*/
|
||||
bcscale(2);
|
||||
\Noalyss\Dbg::echo_file(__FILE__);
|
||||
|
|
@ -44,13 +44,18 @@ $a_tab['linked_operation_div']=array('id'=>'linked_operation_div'.$div,'label'=>
|
|||
$a_tab['document_operation_div']=array('id'=>'document_operation_div'.$div,'label'=>_('Document').'('.$nb_document.')','display'=>'block');
|
||||
$a_tab['linked_action_div']=array('id'=>'linked_action_div'.$div,'label'=>_('Actions Gestion').'('.count($a_followup).')','display'=>'none');
|
||||
$a_tab['analytic_div']=array('id'=>'analytic_div'.$div,'label'=>_('Comptabilité Analytique'),'display'=>'none');
|
||||
//var $g_parameter \Noalyss_Parameter_Folder
|
||||
global $g_parameter;
|
||||
|
||||
|
||||
|
||||
// show tabs
|
||||
if ( $div != "popup") :
|
||||
$a_tab['document_operation_div']['display']='block';
|
||||
$tabs=array_column($a_tab,"id");
|
||||
|
||||
?>
|
||||
<input type="hidden" id="<?=$div?>tab" value="<?=join(",",$tabs)?>">
|
||||
<ul class="tabs">
|
||||
<?php foreach ($a_tab as $idx=>$a_value): ?>
|
||||
<?php
|
||||
|
|
@ -58,7 +63,7 @@ if ( $div != "popup") :
|
|||
?>
|
||||
<li class="<?php echo $class?>">
|
||||
<?php $div_tab_id=$a_value['id'];?>
|
||||
<a href="javascript:void(0)" onclick="unselect_other_tab(this.parentNode.parentNode);var tab=Array('writing_div<?php echo $div?>','info_operation_div<?php echo $div?>','linked_operation_div<?php echo $div?>','document_operation_div<?php echo $div?>','linked_action_div<?php echo $div?>','analytic_div<?php echo $div?>');this.parentNode.className='tabs_selected' ;show_tabs(tab,'<?php echo $div_tab_id; ?>');"><?php echo _($a_value['label'])?></a>
|
||||
<a href="javascript:void(0)" onclick="unselect_other_tab(this.parentNode.parentNode);this.parentNode.className='tabs_selected' ;show_tabs($F('<?=$div?>tab').split(','),'<?php echo $div_tab_id; ?>');"><?php echo _($a_value['label'])?></a>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
|
|
@ -317,9 +322,7 @@ require_once NOALYSS_TEMPLATE.'/ledger_detail_file.php';
|
|||
</span>
|
||||
<?php endif;?>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<?php
|
||||
<?php
|
||||
echo '<p style="text-align:center">';
|
||||
|
||||
if ( $div != 'popup' ) {
|
||||
|
|
@ -408,4 +411,4 @@ echo '</form>';
|
|||
}else {
|
||||
echo '</p>';
|
||||
}
|
||||
?>
|
||||
|
||||
|
|
|
|||
124
include/template/xmlinvoice-display_error.php
Normal file
124
include/template/xmlinvoice-display_error.php
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of NOALYSS.
|
||||
*
|
||||
* NOALYSS is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* NOALYSS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with NOALYSS; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
// Copyright Author Dany De Bontridder danydb@aevalys.eu 22/10/23
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief display errors for generating e-invoices, called from
|
||||
* invoiceUBL21-display-error.php
|
||||
*/
|
||||
///@var $a_vat_error (array) contains error for VAT
|
||||
$a_vat_error=$this->check_VAT();
|
||||
|
||||
///@var $total_error (int) total of errors found in e-invoice
|
||||
$total_error=count ($a_error['general'])
|
||||
+ count($a_error['operation'])
|
||||
+ count($a_error['customer'])
|
||||
+ count($a_error['company'])
|
||||
+count($a_vat_error);
|
||||
|
||||
if ( $total_error == 0 ) :
|
||||
return;
|
||||
endif;
|
||||
$error_message=new \Noalyss\XMLDocument\Error_Message($a_error);
|
||||
?>
|
||||
<button onclick="$('invoice_error_popover').show();return false" class="button bt-error "><i class="icon-attention"></i> <?=_("Erreurs Facture électronique {$total_error}")?></button>
|
||||
<div style="display:none" id="invoice_error_popover">
|
||||
<?php
|
||||
echo HtmlInput::title_box(_("Erreurs"), "invoice_error_popover","hide");
|
||||
//----------------------------------------------------------------------------
|
||||
// company
|
||||
//----------------------------------------------------------------------------
|
||||
$nb_error=count($a_error['company']);
|
||||
for ($i=0;$i<$nb_error;$i++):
|
||||
?>
|
||||
|
||||
<?php if ($i == 0 ):?>
|
||||
<h3><?=_("Société")?></h3>
|
||||
<p class="text-muted">
|
||||
<?=_("A corriger dans COMPANY")?>
|
||||
</p>
|
||||
<ol>
|
||||
<?php endif;?>
|
||||
<li class="notice-item">
|
||||
<?=$error_message->get_message_error(code:$a_error['company'][$i],type:'company')?>
|
||||
</li>
|
||||
|
||||
<?php
|
||||
endfor;
|
||||
if ( $nb_error!=0) print '</ol>';
|
||||
?>
|
||||
<?php
|
||||
//----------------------------------------------------------------------------
|
||||
// Customer
|
||||
//----------------------------------------------------------------------------
|
||||
$nb_error=count($a_error['customer']);
|
||||
for ($i=0;$i<$nb_error;$i++):
|
||||
?>
|
||||
<?php if ($i == 0) :?>
|
||||
<h3><?=_("Client")?></h3>
|
||||
<p class="text-muted">
|
||||
<?=_("A corriger dans la fiche")?>
|
||||
</p>
|
||||
<p>
|
||||
<?php
|
||||
$card=new \Fiche ($this->cn,$this->data['customer']['card_id']);
|
||||
echo \HtmlInput::card_detail($card->get_attribute(ATTR_DEF_QUICKCODE)
|
||||
,$card->get_attribute(ATTR_DEF_NAME));
|
||||
?>
|
||||
</p>
|
||||
<ol>
|
||||
<?php endif;?>
|
||||
|
||||
<li class="notice-item">
|
||||
<?=$error_message->get_message_error(code:$a_error['customer'][$i],type:'customer')?>
|
||||
</li>
|
||||
|
||||
<?php
|
||||
endfor;
|
||||
if ( $nb_error!=0) print '</ol>';
|
||||
?>
|
||||
<?php
|
||||
//----------------------------------------------------------------------------
|
||||
// Item VAT
|
||||
//----------------------------------------------------------------------------
|
||||
$a_vat_error=$this->check_VAT();
|
||||
$nb_error=count($a_vat_error);
|
||||
for ($i=0;$i<$nb_error;$i++):
|
||||
?>
|
||||
<?php if ($i == 0) :?>
|
||||
<h3><?=_("TVA")?></h3>
|
||||
<p class="text-muted">
|
||||
<?=_("A corriger dans la configuration TVA (C0TVA)")?>
|
||||
</p>
|
||||
<ol>
|
||||
<?php endif;?>
|
||||
<li class="notice-item">
|
||||
<?=$a_vat_error[$i]?>
|
||||
</li>
|
||||
|
||||
<?php
|
||||
endfor;
|
||||
if ( $nb_error!=0) print '</ol>';
|
||||
?>
|
||||
<button onclick="$('invoice_error_popover').hide();return false" class="button"><?=_("Fermer")?></button>
|
||||
|
||||
</div>
|
||||
Loading…
Add table
Add a link
Reference in a new issue