123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483 |
- <?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 <http://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';
- /**
- * @var string declaration number
- */
- public $declaration_number;
- /**
- * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
- * @var int
- */
- public $ismultientitymanaged = 1;
- /**
- * 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';
- }
- /**
- * Fonction create
- * @param User $user User
- * @param int $notrigger notrigger
- * @return int
- */
- public function create($user, $notrigger = 0)
- {
- return 1;
- }
- /**
- * Fonction fetch
- * @param int $id object ID
- * @return int
- */
- public function fetch($id)
- {
- return 1;
- }
- /**
- * Fonction 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.'.$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 = '.$conf->entity.'
- AND (s.fk_pays <> '.$mysoc->country_id.' OR s.fk_pays IS NULL)
- AND f.datef BETWEEN "'.$period_reference.'-01" AND "'.$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.'.$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 = '.$conf->entity.'
- AND '.$more_sql.' = "'.$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.'.$field_link.')
- WHERE d.fk_product IS NOT NULL
- AND '.$more_sql.' = "'.$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()
- {
- $resql = $this->db->query('SELECT MAX(numero_declaration) as max_declaration_number FROM '.MAIN_DB_PREFIX.$this->table_element." WHERE exporttype='".$this->db->escape($this->exporttype)."'");
- 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;
- }
- }
|