dolibarr 20.0.0
intracommreport.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2015 ATM Consulting <support@atm-consulting.fr>
3 * Copyright (C) 2019-2020 Open-DSI <support@open-dsi.fr>
4 * Copyright (C) 2020-2024 Frédéric France <frederic.france@free.fr>
5 * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
28require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
29
30
35{
39 public $element = 'intracommreport';
40
44 public $table_element = 'intracommreport';
45
49 public $fk_element = 'fk_intracommreport';
50
51 public $picto = 'intracommreport';
52
56 public $label;
57
58 public $period;
59
60 public $declaration;
61
65 public $declaration_number;
66
70 public $exporttype; // deb or des
71
75 public $type_declaration; // 'introduction' or 'expedition'
76 public $numero_declaration;
77
78
82 const TYPE_DEB = 0;
83
87 const TYPE_DES = 1;
88
89 public static $type = array(
90 'introduction' => 'Introduction',
91 'expedition' => 'Expédition'
92 );
93
94
100 public function __construct(DoliDB $db)
101 {
102 $this->db = $db;
103
104 $this->ismultientitymanaged = 1;
105 $this->exporttype = 'deb';
106 }
107
115 public function create($user, $notrigger = 0)
116 {
117 return 1;
118 }
119
126 public function fetch($id)
127 {
128 return 1;
129 }
130
138 public function delete($user, $notrigger = 0)
139 {
140 return 1;
141 }
142
151 public function getXML($mode = 'O', $type = 'introduction', $period_reference = '')
152 {
153 global $conf, $mysoc;
154
155 /**************Construction de quelques variables********************/
156 $party_id = substr(strtr($mysoc->tva_intra, array(' ' => '')), 0, 4).$mysoc->idprof2;
157 $declarant = substr($mysoc->managers, 0, 14);
158 $id_declaration = self::getDeclarationNumber($this->numero_declaration);
159 /********************************************************************/
160
161 /**************Construction du fichier XML***************************/
162 $e = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8" standalone="yes"?><INSTAT></INSTAT>');
163
164 $envelope = $e->addChild('Envelope');
165 $envelope->addChild('envelopeId', $conf->global->INTRACOMMREPORT_NUM_AGREMENT);
166 $date_time = $envelope->addChild('DateTime');
167 $date_time->addChild('date', date('Y-m-d'));
168 $date_time->addChild('time', date('H:i:s'));
169 $party = $envelope->addChild('Party');
170 $party->addAttribute('partyType', $conf->global->INTRACOMMREPORT_TYPE_ACTEUR);
171 $party->addAttribute('partyRole', $conf->global->INTRACOMMREPORT_ROLE_ACTEUR);
172 $party->addChild('partyId', $party_id);
173 $party->addChild('partyName', $declarant);
174 $envelope->addChild('softwareUsed', 'Dolibarr');
175 $declaration = $envelope->addChild('Declaration');
176 $declaration->addChild('declarationId', $id_declaration);
177 $declaration->addChild('referencePeriod', $period_reference);
178 if (getDolGlobalString('INTRACOMMREPORT_TYPE_ACTEUR') === 'PSI') {
179 $psiId = $party_id;
180 } else {
181 $psiId = 'NA';
182 }
183 $declaration->addChild('PSIId', $psiId);
184 $function = $declaration->addChild('Function');
185 $functionCode = $function->addChild('functionCode', $mode);
186 $declaration->addChild('declarationTypeCode', getDolGlobalString('INTRACOMMREPORT_NIV_OBLIGATION_'.strtoupper($type)));
187 $declaration->addChild('flowCode', ($type == 'introduction' ? 'A' : 'D'));
188 $declaration->addChild('currencyCode', $conf->global->MAIN_MONNAIE);
189 /********************************************************************/
190
191 /**************Ajout des lignes de factures**************************/
192 $res = $this->addItemsFact($declaration, $type, $period_reference);
193 /********************************************************************/
194
195 $this->errors = array_unique($this->errors);
196
197 if (!empty($res)) {
198 return $e->asXML();
199 } else {
200 return false;
201 }
202 }
203
212 public function getXMLDes($period_year, $period_month, $type_declaration = 'expedition')
213 {
214 global $mysoc;
215
216 $e = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8" ?><fichier_des></fichier_des>');
217
218 $declaration_des = $e->addChild('declaration_des');
219 $declaration_des->addChild('num_des', self::getDeclarationNumber($this->numero_declaration));
220 $declaration_des->addChild('num_tvaFr', $mysoc->tva_intra); // /^FR[a-Z0-9]{2}[0-9]{9}$/ // Doit faire 13 caractères
221 $declaration_des->addChild('mois_des', (string) $period_month);
222 $declaration_des->addChild('an_des', (string) $period_year);
223
224 // Add invoice lines
225 $res = $this->addItemsFact($declaration_des, $type_declaration, $period_year.'-'.$period_month, 'des');
226
227 $this->errors = array_unique($this->errors);
228
229 if (!empty($res)) {
230 return $e->asXML();
231 } else {
232 return false;
233 }
234 }
235
245 public function addItemsFact(&$declaration, $type, $period_reference, $exporttype = 'deb')
246 {
247 global $conf;
248
249 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
250
251 $sql = $this->getSQLFactLines($type, $period_reference, $exporttype);
252
253 $resql = $this->db->query($sql);
254
255 if ($resql) {
256 $i = 1;
257
258 if ($this->db->num_rows($resql) <= 0) {
259 $this->errors[] = 'No data for this period';
260 return 0;
261 }
262
263 if ($exporttype == 'deb' && getDolGlobalInt('INTRACOMMREPORT_CATEG_FRAISDEPORT') > 0) {
264 $categ_fraisdeport = new Categorie($this->db);
265 $categ_fraisdeport->fetch(getDolGlobalString('INTRACOMMREPORT_CATEG_FRAISDEPORT'));
266 $TLinesFraisDePort = array();
267 }
268
269 while ($res = $this->db->fetch_object($resql)) {
270 if ($exporttype == 'des') {
271 $this->addItemXMlDes($declaration, $res, $i);
272 } else {
273 if (empty($res->fk_pays)) {
274 // We don't stop the loop because we want to know all the third parties who don't have an informed country
275 $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>';
276 } else {
277 if (getDolGlobalInt('INTRACOMMREPORT_CATEG_FRAISDEPORT') > 0 && $categ_fraisdeport->containsObject('product', $res->id_prod)) {
278 $TLinesFraisDePort[] = $res;
279 } else {
280 $this->addItemXMl($declaration, $res, $i, '');
281 }
282 }
283 }
284
285 $i++;
286 }
287
288 if (!empty($TLinesFraisDePort)) {
289 $this->addItemFraisDePort($declaration, $TLinesFraisDePort, $type, $categ_fraisdeport, $i);
290 }
291
292 if (count($this->errors) > 0) {
293 return 0;
294 }
295 }
296
297 return 1;
298 }
299
308 public function getSQLFactLines($type, $period_reference, $exporttype = 'deb')
309 {
310 global $mysoc, $conf;
311
312 if ($type == 'expedition' || $exporttype == 'des') {
313 $sql = "SELECT f.ref as refinvoice, f.total_ht";
314 $table = 'facture';
315 $table_extraf = 'facture_extrafields';
316 $tabledet = 'facturedet';
317 $field_link = 'fk_facture';
318 } else { // Introduction
319 $sql = "SELECT f.ref_supplier as refinvoice, f.total_ht";
320 $table = 'facture_fourn';
321 $table_extraf = 'facture_fourn_extrafields';
322 $tabledet = 'facture_fourn_det';
323 $field_link = 'fk_facture_fourn';
324 }
325 $sql .= ", l.fk_product, l.qty
326 , p.weight, p.rowid as id_prod, p.customcode
327 , s.rowid as id_client, s.nom, s.zip, s.fk_pays, s.tva_intra
328 , c.code
329 , ext.mode_transport
330 FROM ".MAIN_DB_PREFIX.$tabledet." l
331 INNER JOIN ".MAIN_DB_PREFIX.$table." f ON (f.rowid = l.".$this->db->escape($field_link).")
332 LEFT JOIN ".MAIN_DB_PREFIX.$table_extraf." ext ON (ext.fk_object = f.rowid)
333 INNER JOIN ".MAIN_DB_PREFIX."product p ON (p.rowid = l.fk_product)
334 INNER JOIN ".MAIN_DB_PREFIX."societe s ON (s.rowid = f.fk_soc)
335 LEFT JOIN ".MAIN_DB_PREFIX."c_country c ON (c.rowid = s.fk_pays)
336 WHERE f.fk_statut > 0
337 AND l.product_type = ".($exporttype == "des" ? 1 : 0)."
338 AND f.entity = ".((int) $conf->entity)."
339 AND (s.fk_pays <> ".((int) $mysoc->country_id)." OR s.fk_pays IS NULL)
340 AND f.datef BETWEEN '".$this->db->escape($period_reference)."-01' AND '".$this->db->escape($period_reference)."-".date('t')."'";
341
342 return $sql;
343 }
344
354 public function addItemXMl(&$declaration, &$res, $i, $code_douane_spe = '')
355 {
356 $item = $declaration->addChild('Item');
357 $item->addChild('itemNumber', (string) $i);
358 $cn8 = $item->addChild('CN8');
359 if (empty($code_douane_spe)) {
360 $code_douane = $res->customcode;
361 } else {
362 $code_douane = $code_douane_spe;
363 }
364 $cn8->addChild('CN8Code', $code_douane);
365 $item->addChild('MSConsDestCode', $res->code); // code iso pays client
366 $item->addChild('countryOfOriginCode', substr($res->zip, 0, 2)); // code iso pays d'origine
367 $item->addChild('netMass', (string) round($res->weight * $res->qty)); // Poids du produit
368 $item->addChild('quantityInSU', (string) $res->qty); // Quantité de produit dans la ligne
369 $item->addChild('invoicedAmount', (string) round($res->total_ht)); // Montant total ht de la facture (entier attendu)
370 // $item->addChild('invoicedNumber', $res->refinvoice); // Numéro facture
371 if (!empty($res->tva_intra)) {
372 $item->addChild('partnerId', $res->tva_intra);
373 }
374 $item->addChild('statisticalProcedureCode', '11');
375 $nature_of_transaction = $item->addChild('NatureOfTransaction');
376 $nature_of_transaction->addChild('natureOfTransactionACode', '1');
377 $nature_of_transaction->addChild('natureOfTransactionBCode', '1');
378 $item->addChild('modeOfTransportCode', $res->mode_transport);
379 $item->addChild('regionCode', substr($res->zip, 0, 2));
380 }
381
390 public function addItemXMlDes($declaration, &$res, $i)
391 {
392 $item = $declaration->addChild('ligne_des');
393 $item->addChild('numlin_des', (string) $i);
394 $item->addChild('valeur', (string) round($res->total_ht)); // Total amount excl. tax of the invoice (whole amount expected)
395 $item->addChild('partner_des', $res->tva_intra); // Represents the foreign customer's VAT number
396 }
397
408 public function addItemFraisDePort(&$declaration, &$TLinesFraisDePort, $type, &$categ_fraisdeport, $i)
409 {
410 global $conf;
411
412 if ($type == 'expedition') {
413 $table = 'facture';
414 $tabledet = 'facturedet';
415 $field_link = 'fk_facture';
416 $more_sql = 'f.ref';
417 } else { // Introduction
418 $table = 'facture_fourn';
419 $tabledet = 'facture_fourn_det';
420 $field_link = 'fk_facture_fourn';
421 $more_sql = 'f.ref_supplier';
422 }
423
424 foreach ($TLinesFraisDePort as $res) {
425 $sql = "SELECT p.customcode
426 FROM ".MAIN_DB_PREFIX.$tabledet." d
427 INNER JOIN ".MAIN_DB_PREFIX.$table." f ON (f.rowid = d.".$this->db->escape($field_link).")
428 INNER JOIN ".MAIN_DB_PREFIX."product p ON (p.rowid = d.fk_product)
429 WHERE d.fk_product IS NOT NULL
430 AND f.entity = ".((int) $conf->entity)."
431 AND ".$more_sql." = '".$this->db->escape($res->refinvoice)."'
432 AND d.total_ht =
433 (
434 SELECT MAX(d.total_ht)
435 FROM ".MAIN_DB_PREFIX.$tabledet." d
436 INNER JOIN ".MAIN_DB_PREFIX.$table." f ON (f.rowid = d.".$this->db->escape($field_link).")
437 WHERE d.fk_product IS NOT NULL
438 AND ".$more_sql." = '".$this->db->escape($res->refinvoice)."'
439 AND d.fk_product NOT IN
440 (
441 SELECT fk_product
442 FROM ".MAIN_DB_PREFIX."categorie_product
443 WHERE fk_categorie = ".((int) $categ_fraisdeport->id)."
444 )
445 )";
446
447 $resql = $this->db->query($sql);
448 $ress = $this->db->fetch_object($resql);
449
450 $this->addItemXMl($declaration, $res, $i, $ress->customcode);
451
452 $i++;
453 }
454 }
455
461 public function getNextDeclarationNumber()
462 {
463 $sql = "SELECT MAX(numero_declaration) as max_declaration_number";
464 $sql .= " FROM ".MAIN_DB_PREFIX.$this->table_element;
465 $sql .= " WHERE exporttype = '".$this->db->escape($this->exporttype)."'";
466 $resql = $this->db->query($sql);
467 if ($resql) {
468 $res = $this->db->fetch_object($resql);
469 }
470
471 return (string) ($res->max_declaration_number + 1);
472 }
473
480 public static function getDeclarationNumber($number)
481 {
482 return str_pad($number, 6, '0', STR_PAD_LEFT);
483 }
484
491 public function generateXMLFile($content_xml)
492 {
493 $name = $this->period.'.xml';
494
495 // TODO Must be stored into a dolibarr temp directory
496 $fname = sys_get_temp_dir().'/'.$name;
497
498 $f = fopen($fname, 'w+');
499 fwrite($f, $content_xml);
500 fclose($f);
501
502 header('Content-Description: File Transfer');
503 header('Content-Type: application/xml');
504 header('Content-Disposition: attachment; filename="'.$name.'"');
505 header('Expires: 0');
506 header('Cache-Control: must-revalidate');
507 header('Pragma: public');
508 header('Content-Length: '.filesize($fname));
509
510 readfile($fname);
511 exit;
512 }
513}
Class to manage categories.
Parent class of all other business classes (invoices, contracts, proposals, orders,...
Class to manage Dolibarr database access.
Class to manage intracomm report.
static getDeclarationNumber($number)
Verify declaration number.
addItemsFact(&$declaration, $type, $period_reference, $exporttype='deb')
Add line from invoice.
fetch($id)
Function fetch.
const TYPE_DEB
DEB - Product.
const TYPE_DES
DES - Service.
__construct(DoliDB $db)
Constructor.
addItemXMl(&$declaration, &$res, $i, $code_douane_spe='')
Add item for DEB.
getXML($mode='O', $type='introduction', $period_reference='')
Generate XML file.
addItemXMlDes($declaration, &$res, $i)
Add item for DES.
addItemFraisDePort(&$declaration, &$TLinesFraisDePort, $type, &$categ_fraisdeport, $i)
This function adds an item by retrieving the customs code of the product with the highest amount in t...
getNextDeclarationNumber()
Return next reference of declaration not already used (or last reference)
getSQLFactLines($type, $period_reference, $exporttype='deb')
Add invoice line.
generateXMLFile($content_xml)
Generate XML file.
create($user, $notrigger=0)
Function create.
getXMLDes($period_year, $period_month, $type_declaration='expedition')
Generate XMLDes file.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.