2
0
forked from Wavyzz/dolibarr
Files
dolibarr-fork/htdocs/intracommreport/class/intracommreport.class.php
Laurent Destailleur e9a3c37b89 Debug v17
2022-12-09 20:01:05 +01:00

503 lines
16 KiB
PHP

<?php
/* Copyright (C) 2015 ATM Consulting <support@atm-consulting.fr>
* Copyright (C) 2019-2020 Open-DSI <support@open-dsi.fr>
* Copyright (C) 2020 Frédéric France <frederic.france@netlogic.fr>
*
* This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
*/
/**
* \file htdocs/intracommreport/class/intracommreport.class.php
* \ingroup Intracomm report
* \brief File of class to manage intracomm report
*/
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
/**
* Class to manage intracomm report
*/
class IntracommReport extends CommonObject
{
/**
* @var string ID to identify managed object
*/
public $element = 'intracommreport';
/**
* @var string Name of table without prefix where object is stored
*/
public $table_element = 'intracommreport';
/**
* @var string Field with ID of parent key if this field has a parent
*/
public $fk_element = 'fk_intracommreport';
/**
* 0 = No test on entity, 1 = Test with field entity, 2 = Test with link by societe
* @var int
*/
public $ismultientitymanaged = 1;
public $picto = 'intracommreport';
public $label; // ref ???
public $period;
public $declaration;
/**
* @var string declaration number
*/
public $declaration_number;
public $type_declaration; // deb or des
/**
* DEB - Product
*/
const TYPE_DEB = 0;
/**
* DES - Service
*/
const TYPE_DES = 1;
public static $type = array(
'introduction'=>'Introduction',
'expedition'=>'Expédition'
);
/**
* Constructor
*
* @param DoliDB $db Database handle
*/
public function __construct(DoliDB $db)
{
$this->db = $db;
$this->exporttype = 'deb';
}
/**
* Function create
*
* @param User $user User
* @param int $notrigger notrigger
* @return int
*/
public function create($user, $notrigger = 0)
{
return 1;
}
/**
* Function fetch
*
* @param int $id object ID
* @return int
*/
public function fetch($id)
{
return 1;
}
/**
* Function delete
*
* @param int $id object ID
* @param User $user User
* @param int $notrigger notrigger
* @return int
*/
public function delete($id, $user, $notrigger = 0)
{
return 1;
}
/**
* Generate XML file
*
* @param int $mode O for create, R for regenerate (Look always 0 ment toujours 0 within the framework of XML exchanges according to documentation)
* @param string $type Declaration type by default - introduction or expedition (always 'expedition' for Des)
* @param string $period_reference Period of reference
* @return SimpleXMLElement|int
*/
public function getXML($mode = 'O', $type = 'introduction', $period_reference = '')
{
global $conf, $mysoc;
/**************Construction de quelques variables********************/
$party_id = substr(strtr($mysoc->tva_intra, array(' '=>'')), 0, 4).$mysoc->idprof2;
$declarant = substr($mysoc->managers, 0, 14);
$id_declaration = self::getDeclarationNumber($this->numero_declaration);
/********************************************************************/
/**************Construction du fichier XML***************************/
$e = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8" standalone="yes"?><INSTAT></INSTAT>');
$enveloppe = $e->addChild('Envelope');
$enveloppe->addChild('envelopeId', $conf->global->INTRACOMMREPORT_NUM_AGREMENT);
$date_time = $enveloppe->addChild('DateTime');
$date_time->addChild('date', date('Y-m-d'));
$date_time->addChild('time', date('H:i:s'));
$party = $enveloppe->addChild('Party');
$party->addAttribute('partyType', $conf->global->INTRACOMMREPORT_TYPE_ACTEUR);
$party->addAttribute('partyRole', $conf->global->INTRACOMMREPORT_ROLE_ACTEUR);
$party->addChild('partyId', $party_id);
$party->addChild('partyName', $declarant);
$enveloppe->addChild('softwareUsed', 'Dolibarr');
$declaration = $enveloppe->addChild('Declaration');
$declaration->addChild('declarationId', $id_declaration);
$declaration->addChild('referencePeriod', $period_reference);
if ($conf->global->INTRACOMMREPORT_TYPE_ACTEUR === 'PSI') {
$psiId = $party_id;
} else {
$psiId = 'NA';
}
$declaration->addChild('PSIId', $psiId);
$function = $declaration->addChild('Function');
$functionCode = $function->addChild('functionCode', $mode);
$declaration->addChild('declarationTypeCode', $conf->global->{'INTRACOMMREPORT_NIV_OBLIGATION_'.strtoupper($type)});
$declaration->addChild('flowCode', ($type == 'introduction' ? 'A' : 'D'));
$declaration->addChild('currencyCode', $conf->global->MAIN_MONNAIE);
/********************************************************************/
/**************Ajout des lignes de factures**************************/
$res = $this->addItemsFact($declaration, $type, $period_reference);
/********************************************************************/
$this->errors = array_unique($this->errors);
if (!empty($res)) {
return $e->asXML();
} else {
return 0;
}
}
/**
* Generate XMLDes file
*
* @param int $period_year Year of declaration
* @param int $period_month Month of declaration
* @param string $type_declaration Declaration type by default - introduction or expedition (always 'expedition' for Des)
* @return SimpleXMLElement|int
*/
public function getXMLDes($period_year, $period_month, $type_declaration = 'expedition')
{
global $mysoc;
$e = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8" ?><fichier_des></fichier_des>');
$declaration_des = $e->addChild('declaration_des');
$declaration_des->addChild('num_des', self::getDeclarationNumber($this->numero_declaration));
$declaration_des->addChild('num_tvaFr', $mysoc->tva_intra); // /^FR[a-Z0-9]{2}[0-9]{9}$/ // Doit faire 13 caractères
$declaration_des->addChild('mois_des', $period_month);
$declaration_des->addChild('an_des', $period_year);
/**************Ajout des lignes de factures**************************/
$res = $this->addItemsFact($declaration_des, $type_declaration, $period_year.'-'.$period_month, 'des');
/********************************************************************/
$this->errors = array_unique($this->errors);
if (!empty($res)) {
return $e->asXML();
} else {
return 0;
}
}
/**
* Add line from invoice
*
* @param SimpleXMLElement $declaration Reference declaration
* @param string $type Declaration type by default - introduction or expedition (always 'expedition' for Des)
* @param int $period_reference Reference period
* @param string $exporttype deb=DEB, des=DES
* @return int <0 if KO, >0 if OK
*/
public function addItemsFact(&$declaration, $type, $period_reference, $exporttype = 'deb')
{
global $conf;
require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
$sql = $this->getSQLFactLines($type, $period_reference, $exporttype);
$resql = $this->db->query($sql);
if ($resql) {
$i = 1;
if ($this->db->num_rows($resql) <= 0) {
$this->errors[] = 'No data for this period';
return 0;
}
if ($exporttype == 'deb' && $conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT > 0) {
$categ_fraisdeport = new Categorie($this->db);
$categ_fraisdeport->fetch($conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT);
$TLinesFraisDePort = array();
}
while ($res = $this->db->fetch_object($resql)) {
if ($exporttype == 'des') {
$this->addItemXMlDes($declaration, $res, $i);
} else {
if (empty($res->fk_pays)) {
// We don't stop the loop because we want to know all the third parties who don't have an informed country
$this->errors[] = 'Country not filled in for the third party <a href="'.dol_buildpath('/societe/soc.php', 1).'?socid='.$res->id_client.'">'.$res->nom.'</a>';
} else {
if ($conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT > 0 && $categ_fraisdeport->containsObject('product', $res->id_prod)) {
$TLinesFraisDePort[] = $res;
} else {
$this->addItemXMl($declaration, $res, $i, '');
}
}
}
$i++;
}
if (!empty($TLinesFraisDePort)) {
$this->addItemFraisDePort($declaration, $TLinesFraisDePort, $type, $categ_fraisdeport, $i);
}
if (count($this->errors) > 0) {
return 0;
}
}
return 1;
}
/**
* Add invoice line
*
* @param string $type Declaration type by default - introduction or expedition (always 'expedition' for Des)
* @param int $period_reference Reference declaration
* @param string $exporttype deb=DEB, des=DES
* @return string <0 if KO, >0 if OK
*/
public function getSQLFactLines($type, $period_reference, $exporttype = 'deb')
{
global $mysoc, $conf;
if ($type == 'expedition' || $exporttype == 'des') {
$sql = "SELECT f.ref as refinvoice, f.total_ht";
$table = 'facture';
$table_extraf = 'facture_extrafields';
$tabledet = 'facturedet';
$field_link = 'fk_facture';
} else { // Introduction
$sql = "SELECT f.ref_supplier as refinvoice, f.total_ht";
$table = 'facture_fourn';
$table_extraf = 'facture_fourn_extrafields';
$tabledet = 'facture_fourn_det';
$field_link = 'fk_facture_fourn';
}
$sql .= ", l.fk_product, l.qty
, p.weight, p.rowid as id_prod, p.customcode
, s.rowid as id_client, s.nom, s.zip, s.fk_pays, s.tva_intra
, c.code
, ext.mode_transport
FROM ".MAIN_DB_PREFIX.$tabledet." l
INNER JOIN ".MAIN_DB_PREFIX.$table." f ON (f.rowid = l.".$this->db->escape($field_link).")
LEFT JOIN ".MAIN_DB_PREFIX.$table_extraf." ext ON (ext.fk_object = f.rowid)
INNER JOIN ".MAIN_DB_PREFIX."product p ON (p.rowid = l.fk_product)
INNER JOIN ".MAIN_DB_PREFIX."societe s ON (s.rowid = f.fk_soc)
LEFT JOIN ".MAIN_DB_PREFIX."c_country c ON (c.rowid = s.fk_pays)
WHERE f.fk_statut > 0
AND l.product_type = ".($exporttype == "des" ? 1 : 0)."
AND f.entity = ".((int) $conf->entity)."
AND (s.fk_pays <> ".((int) $mysoc->country_id)." OR s.fk_pays IS NULL)
AND f.datef BETWEEN '".$this->db->escape($period_reference)."-01' AND '".$this->db->escape($period_reference)."-".date('t')."'";
return $sql;
}
/**
* Add item for DEB
*
* @param SimpleXMLElement $declaration Reference declaration
* @param Resource $res Result of request SQL
* @param int $i Line Id
* @param string $code_douane_spe Specific customs authorities code
* @return void
*/
public function addItemXMl(&$declaration, &$res, $i, $code_douane_spe = '')
{
$item = $declaration->addChild('Item');
$item->addChild('itemNumber', $i);
$cn8 = $item->addChild('CN8');
if (empty($code_douane_spe)) {
$code_douane = $res->customcode;
} else {
$code_douane = $code_douane_spe;
}
$cn8->addChild('CN8Code', $code_douane);
$item->addChild('MSConsDestCode', $res->code); // code iso pays client
$item->addChild('countryOfOriginCode', substr($res->zip, 0, 2)); // code iso pays d'origine
$item->addChild('netMass', round($res->weight * $res->qty)); // Poids du produit
$item->addChild('quantityInSU', $res->qty); // Quantité de produit dans la ligne
$item->addChild('invoicedAmount', round($res->total_ht)); // Montant total ht de la facture (entier attendu)
// $item->addChild('invoicedNumber', $res->refinvoice); // Numéro facture
if (!empty($res->tva_intra)) {
$item->addChild('partnerId', $res->tva_intra);
}
$item->addChild('statisticalProcedureCode', '11');
$nature_of_transaction = $item->addChild('NatureOfTransaction');
$nature_of_transaction->addChild('natureOfTransactionACode', 1);
$nature_of_transaction->addChild('natureOfTransactionBCode', 1);
$item->addChild('modeOfTransportCode', $res->mode_transport);
$item->addChild('regionCode', substr($res->zip, 0, 2));
}
/**
* Add item for DES
*
* @param SimpleXMLElement $declaration Reference declaration
* @param Resource $res Result of request SQL
* @param int $i Line Id
* @return void
*/
public function addItemXMlDes($declaration, &$res, $i)
{
$item = $declaration->addChild('ligne_des');
$item->addChild('numlin_des', $i);
$item->addChild('valeur', round($res->total_ht)); // Total amount excl. tax of the invoice (whole amount expected)
$item->addChild('partner_des', $res->tva_intra); // Represents the foreign customer's VAT number
}
/**
* This function adds an item by retrieving the customs code of the product with the highest amount in the invoice
*
* @param SimpleXMLElement $declaration Reference declaration
* @param array $TLinesFraisDePort Data of shipping costs line
* @param string $type Declaration type by default - introduction or expedition (always 'expedition' for Des)
* @param Categorie $categ_fraisdeport category of shipping costs
* @param int $i Line Id
* @return void
*/
public function addItemFraisDePort(&$declaration, &$TLinesFraisDePort, $type, &$categ_fraisdeport, $i)
{
global $conf;
if ($type == 'expedition') {
$table = 'facture';
$tabledet = 'facturedet';
$field_link = 'fk_facture';
$more_sql = 'f.ref';
} else { // Introduction
$table = 'facture_fourn';
$tabledet = 'facture_fourn_det';
$field_link = 'fk_facture_fourn';
$more_sql = 'f.ref_supplier';
}
foreach ($TLinesFraisDePort as $res) {
$sql = "SELECT p.customcode
FROM ".MAIN_DB_PREFIX.$tabledet." d
INNER JOIN ".MAIN_DB_PREFIX.$table." f ON (f.rowid = d.".$this->db->escape($field_link).")
INNER JOIN ".MAIN_DB_PREFIX."product p ON (p.rowid = d.fk_product)
WHERE d.fk_product IS NOT NULL
AND f.entity = ".((int) $conf->entity)."
AND ".$more_sql." = '".$this->db->escape($res->refinvoice)."'
AND d.total_ht =
(
SELECT MAX(d.total_ht)
FROM ".MAIN_DB_PREFIX.$tabledet." d
INNER JOIN ".MAIN_DB_PREFIX.$table." f ON (f.rowid = d.".$this->db->escape($field_link).")
WHERE d.fk_product IS NOT NULL
AND ".$more_sql." = '".$this->db->escape($res->refinvoice)."'
AND d.fk_product NOT IN
(
SELECT fk_product
FROM ".MAIN_DB_PREFIX."categorie_product
WHERE fk_categorie = ".((int) $categ_fraisdeport->id)."
)
)";
$resql = $this->db->query($sql);
$ress = $this->db->fetch_object($resql);
$this->addItemXMl($declaration, $res, $i, $ress->customcode);
$i++;
}
}
/**
* Return next reference of declaration not already used (or last reference)
*
* @return string free ref or last ref
*/
public function getNextDeclarationNumber()
{
$sql = "SELECT MAX(numero_declaration) as max_declaration_number FROM ".MAIN_DB_PREFIX.$this->table_element;
$sql .= " WHERE exporttype = '".$this->db->escape($this->exporttype)."'";
$resql = $this->db->query($sql);
if ($resql) {
$res = $this->db->fetch_object($resql);
}
return ($res->max_declaration_number + 1);
}
/**
* Verify declaration number. Positive integer of a maximum of 6 characters recommended by the documentation
*
* @param string $number Number to verify / convert
* @return string Number
*/
public static function getDeclarationNumber($number)
{
return str_pad($number, 6, 0, STR_PAD_LEFT);
}
/**
* Generate XML file
*
* @return void
*/
public function generateXMLFile()
{
$name = $this->periode.'.xml';
$fname = sys_get_temp_dir().'/'.$name;
$f = fopen($fname, 'w+');
fwrite($f, $this->content_xml);
fclose($f);
header('Content-Description: File Transfer');
header('Content-Type: application/xml');
header('Content-Disposition: attachment; filename="'.$name.'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: '.filesize($fname));
readfile($fname);
exit;
}
}