Passed
Branch develop (30d2c8)
by
unknown
26:49
created

IntracommReport::create()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/* Copyright (C) 2015       ATM Consulting          <[email protected]>
3
 * Copyright (C) 2019-2020  Open-DSI                <[email protected]>
4
 * Copyright (C) 2020       Frédéric France         <[email protected]>
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 3 of the License, or
9
 * (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18
 */
19
20
/**
21
 *  \file       htdocs/intracommreport/class/intracommreport.class.php
22
 *  \ingroup    Intracomm report
23
 *  \brief      File of class to manage intracomm report
24
 */
25
require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php';
26
27
/**
28
 * Class to manage intracomm report
29
 */
30
class IntracommReport extends CommonObject
31
{
32
	/**
33
	 * @var string ID to identify managed object
34
	 */
35
	public $element = 'intracommreport';
36
37
	/**
38
	 * @var string Name of table without prefix where object is stored
39
	 */
40
	public $table_element = 'intracommreport';
41
42
	/**
43
	 * @var string Field with ID of parent key if this field has a parent
44
	 */
45
	public $fk_element = 'fk_intracommreport';
46
47
	/**
48
	 * @var string declaration number
49
	 */
50
	public $declaration_number;
51
52
	/**
53
	 * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
54
	 * @var int
55
	 */
56
	public $ismultientitymanaged = 1;
57
58
	/**
59
	 * DEB - Product
60
	 */
61
	const TYPE_DEB = 0;
62
63
	/**
64
	 * DES - Service
65
	 */
66
	const TYPE_DES = 1;
67
68
	public static $type = array(
69
		'introduction'=>'Introduction',
70
		'expedition'=>'Expédition'
71
	);
72
73
	/**
74
	 * Constructor
75
	 *
76
	 * @param DoliDB $db Database handle
77
	 */
78
	public function __construct(DoliDB $db)
79
	{
80
		$this->db = $db;
81
		$this->exporttype = 'deb';
82
	}
83
84
	/**
85
	 * Fonction create
86
	 * @param 	User 	$user 		User
87
	 * @param 	int 	$notrigger 	notrigger
88
	 * @return 	int
89
	 */
90
	public function create($user, $notrigger = 0)
91
	{
92
		return 1;
93
	}
94
95
	/**
96
	 * Fonction fetch
97
	 * @param 	int 	$id 	object ID
98
	 * @return 	int
99
	 */
100
	public function fetch($id)
101
	{
102
		return 1;
103
	}
104
105
	/**
106
	 * Fonction delete
107
	 * @param 	int 	$id 		object ID
108
	 * @param 	User 	$user 		User
109
	 * @param 	int 	$notrigger 	notrigger
110
	 * @return 	int
111
	 */
112
	public function delete($id, $user, $notrigger = 0)
113
	{
114
		return 1;
115
	}
116
117
	/**
118
	 * Generate XML file
119
	 *
120
	 * @param int			$mode 				O for create, R for regenerate (Look always 0 ment toujours 0 within the framework of XML exchanges according to documentation)
121
	 * @param string		$type 				Declaration type by default - introduction or expedition (always 'expedition' for Des)
122
	 * @param string		$period_reference	Period of reference
123
	 * @return SimpleXMLElement|int
124
	 */
125
	public function getXML($mode = 'O', $type = 'introduction', $period_reference = '')
126
	{
127
128
		global $conf, $mysoc;
129
130
		/**************Construction de quelques variables********************/
131
		$party_id = substr(strtr($mysoc->tva_intra, array(' '=>'')), 0, 4).$mysoc->idprof2;
132
		$declarant = substr($mysoc->managers, 0, 14);
133
		$id_declaration = self::getDeclarationNumber($this->numero_declaration);
0 ignored issues
show
Bug Best Practice introduced by
The property numero_declaration does not exist on IntracommReport. Did you maybe forget to declare it?
Loading history...
134
		/********************************************************************/
135
136
		/**************Construction du fichier XML***************************/
137
		$e = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8" standalone="yes"?><INSTAT></INSTAT>');
138
139
		$enveloppe = $e->addChild('Envelope');
140
		$enveloppe->addChild('envelopeId', $conf->global->INTRACOMMREPORT_NUM_AGREMENT);
141
		$date_time = $enveloppe->addChild('DateTime');
142
		$date_time->addChild('date', date('Y-m-d'));
143
		$date_time->addChild('time', date('H:i:s'));
144
		$party = $enveloppe->addChild('Party');
145
		$party->addAttribute('partyType', $conf->global->INTRACOMMREPORT_TYPE_ACTEUR);
146
		$party->addAttribute('partyRole', $conf->global->INTRACOMMREPORT_ROLE_ACTEUR);
147
		$party->addChild('partyId', $party_id);
148
		$party->addChild('partyName', $declarant);
149
		$enveloppe->addChild('softwareUsed', 'Dolibarr');
150
		$declaration = $enveloppe->addChild('Declaration');
151
		$declaration->addChild('declarationId', $id_declaration);
152
		$declaration->addChild('referencePeriod', $period_reference);
153
		if ($conf->global->INTRACOMMREPORT_TYPE_ACTEUR === 'PSI') {
154
			$psiId = $party_id;
155
		} else {
156
			$psiId = 'NA';
157
		}
158
		$declaration->addChild('PSIId', $psiId);
159
		$function = $declaration->addChild('Function');
160
		$functionCode = $function->addChild('functionCode', $mode);
161
		$declaration->addChild('declarationTypeCode', $conf->global->{'INTRACOMMREPORT_NIV_OBLIGATION_'.strtoupper($type)});
162
		$declaration->addChild('flowCode', ($type == 'introduction' ? 'A' : 'D'));
163
		$declaration->addChild('currencyCode', $conf->global->MAIN_MONNAIE);
164
		/********************************************************************/
165
166
		/**************Ajout des lignes de factures**************************/
167
		$res = $this->addItemsFact($declaration, $type, $period_reference);
168
		/********************************************************************/
169
170
		$this->errors = array_unique($this->errors);
171
172
		if (!empty($res)) {
173
			return $e->asXML();
174
		} else {
175
			return 0;
176
		}
177
	}
178
179
	/**
180
	 * Generate XMLDes file
181
	 *
182
	 * @param int		$period_year		Year of declaration
183
	 * @param int		$period_month		Month of declaration
184
	 * @param string	$type_declaration	Declaration type by default - introduction or expedition (always 'expedition' for Des)
185
	 * @return SimpleXMLElement|int
186
	 */
187
	public function getXMLDes($period_year, $period_month, $type_declaration = 'expedition')
188
	{
189
		global $mysoc;
190
191
		$e = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8" ?><fichier_des></fichier_des>');
192
193
		$declaration_des = $e->addChild('declaration_des');
194
		$declaration_des->addChild('num_des', self::getDeclarationNumber($this->numero_declaration));
0 ignored issues
show
Bug Best Practice introduced by
The property numero_declaration does not exist on IntracommReport. Did you maybe forget to declare it?
Loading history...
195
		$declaration_des->addChild('num_tvaFr', $mysoc->tva_intra); // /^FR[a-Z0-9]{2}[0-9]{9}$/  // Doit faire 13 caractères
196
		$declaration_des->addChild('mois_des', $period_month);
197
		$declaration_des->addChild('an_des', $period_year);
198
199
		/**************Ajout des lignes de factures**************************/
200
		$res = $this->addItemsFact($declaration_des, $type_declaration, $period_year.'-'.$period_month, 'des');
201
		/********************************************************************/
202
203
		$this->errors = array_unique($this->errors);
204
205
		if (!empty($res)) {
206
			return $e->asXML();
207
		} else {
208
			return 0;
209
		}
210
	}
211
212
	/**
213
	 *  Add line from invoice
214
	 *
215
	 *  @param	SimpleXMLElement	$declaration		Reference declaration
216
	 *  @param	string				$type				Declaration type by default - introduction or expedition (always 'expedition' for Des)
217
	 *  @param	int					$period_reference	Reference period
218
	 *  @param	string				$exporttype	    	deb=DEB, des=DES
219
	 *  @return	int       			  					<0 if KO, >0 if OK
220
	 */
221
	public function addItemsFact(&$declaration, $type, $period_reference, $exporttype = 'deb')
222
	{
223
		global $conf;
224
225
		require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
226
227
		$sql = $this->getSQLFactLines($type, $period_reference, $exporttype);
228
229
		$resql = $this->db->query($sql);
230
231
		if ($resql) {
232
			$i = 1;
233
234
			if (empty($resql->num_rows)) {
235
				$this->errors[] = 'No data for this period';
236
				return 0;
237
			}
238
239
			if ($exporttype == 'deb' && $conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT > 0) {
240
				$categ_fraisdeport = new Categorie($this->db);
241
				$categ_fraisdeport->fetch($conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT);
242
				$TLinesFraisDePort = array();
243
			}
244
245
			while ($res = $this->db->fetch_object($resql)) {
246
				if ($exporttype == 'des') {
247
					$this->addItemXMlDes($declaration, $res, $i);
248
				} else {
249
					if (empty($res->fk_pays)) {
250
						// We don't stop the loop because we want to know all the third parties who don't have an informed country
251
						$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>';
252
					} else {
253
						if ($conf->global->INTRACOMMREPORT_CATEG_FRAISDEPORT > 0 && $categ_fraisdeport->containsObject('product', $res->id_prod)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $categ_fraisdeport does not seem to be defined for all execution paths leading up to this point.
Loading history...
254
							$TLinesFraisDePort[] = $res;
255
						} else {
256
							$this->addItemXMl($declaration, $res, $i, '');
257
						}
258
					}
259
				}
260
261
				$i++;
262
			}
263
264
			if (!empty($TLinesFraisDePort)) {
265
				$this->addItemFraisDePort($declaration, $TLinesFraisDePort, $type, $categ_fraisdeport, $i);
266
			}
267
268
			if (count($this->errors) > 0) {
269
				return 0;
270
			}
271
		}
272
273
		return 1;
274
	}
275
276
	/**
277
	 *  Add invoice line
278
	 *
279
	 *  @param      string	$type				Declaration type by default - introduction or expedition (always 'expedition' for Des)
280
	 *  @param      int		$period_reference	Reference declaration
281
	 *  @param      string	$exporttype	    	deb=DEB, des=DES
282
	 *  @return     string       			  		<0 if KO, >0 if OK
283
	 */
284
	public function getSQLFactLines($type, $period_reference, $exporttype = 'deb')
285
	{
286
		global $mysoc, $conf;
287
288
		if ($type == 'expedition' || $exporttype == 'des') {
289
			$sql = 'SELECT f.ref as refinvoice, f.total as total_ht';
290
			$table = 'facture';
291
			$table_extraf = 'facture_extrafields';
292
			$tabledet = 'facturedet';
293
			$field_link = 'fk_facture';
294
		} else { // Introduction
295
			$sql = 'SELECT f.ref_supplier as refinvoice, f.total_ht';
296
			$table = 'facture_fourn';
297
			$table_extraf = 'facture_fourn_extrafields';
298
			$tabledet = 'facture_fourn_det';
299
			$field_link = 'fk_facture_fourn';
300
		}
301
		$sql .= ', l.fk_product, l.qty
302
				, p.weight, p.rowid as id_prod, p.customcode
303
				, s.rowid as id_client, s.nom, s.zip, s.fk_pays, s.tva_intra
304
				, c.code
305
				, ext.mode_transport
306
				FROM '.MAIN_DB_PREFIX.$tabledet.' l
307
				INNER JOIN '.MAIN_DB_PREFIX.$table.' f ON (f.rowid = l.'.$field_link.')
308
				LEFT JOIN '.MAIN_DB_PREFIX.$table_extraf.' ext ON (ext.fk_object = f.rowid)
309
				INNER JOIN '.MAIN_DB_PREFIX.'product p ON (p.rowid = l.fk_product)
310
				INNER JOIN '.MAIN_DB_PREFIX.'societe s ON (s.rowid = f.fk_soc)
311
				LEFT JOIN '.MAIN_DB_PREFIX.'c_country c ON (c.rowid = s.fk_pays)
312
				WHERE f.fk_statut > 0
313
				AND l.product_type = '.($exporttype == 'des' ? 1 : 0).'
314
				AND f.entity = '.$conf->entity.'
315
				AND (s.fk_pays <> '.$mysoc->country_id.' OR s.fk_pays IS NULL)
316
				AND f.datef BETWEEN "'.$period_reference.'-01" AND "'.$period_reference.'-'.date('t').'"';
317
318
		return $sql;
319
	}
320
321
	/**
322
	 *	Add item for DEB
323
	 *
324
	 * 	@param	SimpleXMLElement	$declaration		Reference declaration
325
	 * 	@param	Resource			$res				Result of request SQL
326
	 *  @param	int					$i					Line Id
327
	 * 	@param	string				$code_douane_spe	Specific customs authorities code
328
	 *  @return	void
329
	 */
330
	public function addItemXMl(&$declaration, &$res, $i, $code_douane_spe = '')
331
	{
332
		$item = $declaration->addChild('Item');
333
		$item->addChild('itemNumber', $i);
334
		$cn8 = $item->addChild('CN8');
335
		if (empty($code_douane_spe)) {
336
			$code_douane = $res->customcode;
337
		} else {
338
			$code_douane = $code_douane_spe;
339
		}
340
		$cn8->addChild('CN8Code', $code_douane);
341
		$item->addChild('MSConsDestCode', $res->code); // code iso pays client
342
		$item->addChild('countryOfOriginCode', substr($res->zip, 0, 2)); // code iso pays d'origine
343
		$item->addChild('netMass', round($res->weight * $res->qty)); // Poids du produit
344
		$item->addChild('quantityInSU', $res->qty); // Quantité de produit dans la ligne
345
		$item->addChild('invoicedAmount', round($res->total_ht)); // Montant total ht de la facture (entier attendu)
346
		// $item->addChild('invoicedNumber', $res->refinvoice); // Numéro facture
347
		if (!empty($res->tva_intra)) {
348
			$item->addChild('partnerId', $res->tva_intra);
349
		}
350
		$item->addChild('statisticalProcedureCode', '11');
351
		$nature_of_transaction = $item->addChild('NatureOfTransaction');
352
		$nature_of_transaction->addChild('natureOfTransactionACode', 1);
353
		$nature_of_transaction->addChild('natureOfTransactionBCode', 1);
354
		$item->addChild('modeOfTransportCode', $res->mode_transport);
355
		$item->addChild('regionCode', substr($res->zip, 0, 2));
356
	}
357
358
	/**
359
	 *	Add item for DES
360
	 *
361
	 * 	@param	SimpleXMLElement	$declaration		Reference declaration
362
	 * 	@param	Resource				$res				Result of request SQL
363
	 *  @param	int					$i					Line Id
364
	 *  @return	void
365
	 */
366
	public function addItemXMlDes($declaration, &$res, $i)
367
	{
368
		$item = $declaration->addChild('ligne_des');
369
		$item->addChild('numlin_des', $i);
370
		$item->addChild('valeur', round($res->total_ht)); // Total amount excl. tax of the invoice (whole amount expected)
371
		$item->addChild('partner_des', $res->tva_intra); // Represents the foreign customer's VAT number
372
	}
373
374
	/**
375
	 *	This function adds an item by retrieving the customs code of the product with the highest amount in the invoice
376
	 *
377
	 * 	@param	SimpleXMLElement	$declaration		Reference declaration
378
	 * 	@param	array				$TLinesFraisDePort	Data of shipping costs line
379
	 *  @param	string	    		$type				Declaration type by default - introduction or expedition (always 'expedition' for Des)
380
	 *  @param	Categorie			$categ_fraisdeport	category of shipping costs
381
	 *  @param	int		    		$i					Line Id
382
	 *  @return	void
383
	 */
384
	public function addItemFraisDePort(&$declaration, &$TLinesFraisDePort, $type, &$categ_fraisdeport, $i)
385
	{
386
387
		global $conf;
388
389
		if ($type == 'expedition') {
390
			$table = 'facture';
391
			$tabledet = 'facturedet';
392
			$field_link = 'fk_facture';
393
			$more_sql = 'f.ref';
394
		} else { // Introduction
395
			$table = 'facture_fourn';
396
			$tabledet = 'facture_fourn_det';
397
			$field_link = 'fk_facture_fourn';
398
			$more_sql = 'f.ref_supplier';
399
		}
400
401
		foreach ($TLinesFraisDePort as $res) {
402
			$sql = 'SELECT p.customcode
403
					FROM '.MAIN_DB_PREFIX.$tabledet.' d
404
					INNER JOIN '.MAIN_DB_PREFIX.$table.' f ON (f.rowid = d.'.$field_link.')
405
					INNER JOIN '.MAIN_DB_PREFIX.'product p ON (p.rowid = d.fk_product)
406
					WHERE d.fk_product IS NOT NULL
407
					AND f.entity = '.$conf->entity.'
408
					AND '.$more_sql.' = "'.$res->refinvoice.'"
409
					AND d.total_ht =
410
					(
411
						SELECT MAX(d.total_ht)
412
						FROM '.MAIN_DB_PREFIX.$tabledet.' d
413
						INNER JOIN '.MAIN_DB_PREFIX.$table.' f ON (f.rowid = d.'.$field_link.')
414
						WHERE d.fk_product IS NOT NULL
415
						AND '.$more_sql.' = "'.$res->refinvoice.'"
416
						AND d.fk_product NOT IN
417
						(
418
							SELECT fk_product
419
							FROM '.MAIN_DB_PREFIX.'categorie_product
420
							WHERE fk_categorie = '.$categ_fraisdeport->id.'
421
						)
422
					)';
423
424
			$resql = $this->db->query($sql);
425
			$ress = $this->db->fetch_object($resql);
426
427
			$this->addItemXMl($declaration, $res, $i, $ress->customcode);
428
429
			$i++;
430
		}
431
	}
432
433
	/**
434
	 *	Return next reference of declaration not already used (or last reference)
435
	 *
436
	 *	@return    string					free ref or last ref
437
	 */
438
	public function getNextDeclarationNumber()
439
	{
440
		$resql = $this->db->query('SELECT MAX(numero_declaration) as max_declaration_number FROM '.MAIN_DB_PREFIX.$this->table_element.' WHERE exporttype="'.$this->exporttype.'"');
441
		if ($resql) {
442
			$res = $this->db->fetch_object($resql);
443
		}
444
445
		return ($res->max_declaration_number + 1);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $res does not seem to be defined for all execution paths leading up to this point.
Loading history...
446
	}
447
448
	/**
449
	 *	Verify declaration number. Positive integer of a maximum of 6 characters recommended by the documentation
450
	 *
451
	 *	@param     	string		$number		Number to verify / convert
452
	 *	@return		string 				Number
453
	 */
454
	public static function getDeclarationNumber($number)
455
	{
456
		return str_pad($number, 6, 0, STR_PAD_LEFT);
457
	}
458
459
	/**
460
	 *	Generate XML file
461
	 *
462
	 *	@return		void
463
	 */
464
	public function generateXMLFile()
465
	{
466
467
		$name = $this->periode.'.xml';
0 ignored issues
show
Bug Best Practice introduced by
The property periode does not exist on IntracommReport. Did you maybe forget to declare it?
Loading history...
468
		$fname = sys_get_temp_dir().'/'.$name;
469
		$f = fopen($fname, 'w+');
470
		fwrite($f, $this->content_xml);
0 ignored issues
show
Bug introduced by
The property content_xml does not exist on IntracommReport. Did you mean context?
Loading history...
471
		fclose($f);
472
473
		header('Content-Description: File Transfer');
474
		header('Content-Type: application/xml');
475
		header('Content-Disposition: attachment; filename="'.$name.'"');
476
		header('Expires: 0');
477
		header('Cache-Control: must-revalidate');
478
		header('Pragma: public');
479
		header('Content-Length: '.filesize($fname));
480
		readfile($fname);
481
		exit;
482
	}
483
}
484