Passed
Branch develop (5ec324)
by
unknown
37:40
created

Shipments::get()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 17
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 9
c 0
b 0
f 0
nc 4
nop 1
dl 0
loc 17
rs 9.9666
1
<?php
2
/* Copyright (C) 2015       Jean-François Ferry     <[email protected]>
3
 * Copyright (C) 2016       Laurent Destailleur     <[email protected]>
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 3 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17
 */
18
19
 use Luracast\Restler\RestException;
20
21
 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
22
23
/**
24
 * API class for shipments
25
 *
26
 * @access protected
27
 * @class  DolibarrApiAccess {@requires user,external}
28
 */
29
class Shipments extends DolibarrApi
30
{
31
32
	/**
33
	 * @var array   $FIELDS     Mandatory fields, checked when create and update object
34
	 */
35
	public static $FIELDS = array(
36
		'socid',
37
		'origin_id',
38
		'origin_type',
39
	);
40
41
	/**
42
	 * @var Expedition $shipment {@type Expedition}
43
	 */
44
	public $shipment;
45
46
	/**
47
	 * Constructor
48
	 */
49
	public function __construct()
50
	{
51
		global $db, $conf;
52
		$this->db = $db;
53
		$this->shipment = new Expedition($this->db);
54
	}
55
56
	/**
57
	 * Get properties of a shipment object
58
	 *
59
	 * Return an array with shipment informations
60
	 *
61
	 * @param       int         $id         ID of shipment
62
	 * @return 	array|mixed data without useless information
63
	 *
64
	 * @throws 	RestException
65
	 */
66
	public function get($id)
67
	{
68
		if (!DolibarrApiAccess::$user->rights->expedition->lire) {
69
			throw new RestException(401);
70
		}
71
72
		$result = $this->shipment->fetch($id);
73
		if (!$result) {
74
			throw new RestException(404, 'Shipment not found');
75
		}
76
77
		if (!DolibarrApi::_checkAccessToResource('expedition', $this->shipment->id)) {
78
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
79
		}
80
81
		$this->shipment->fetchObjectLinked();
82
		return $this->_cleanObjectDatas($this->shipment);
83
	}
84
85
86
87
	/**
88
	 * List shipments
89
	 *
90
	 * Get a list of shipments
91
	 *
92
	 * @param string	       $sortfield	        Sort field
93
	 * @param string	       $sortorder	        Sort order
94
	 * @param int		       $limit		        Limit for list
95
	 * @param int		       $page		        Page number
96
	 * @param string   	       $thirdparty_ids	    Thirdparty ids to filter shipments of (example '1' or '1,2,3') {@pattern /^[0-9,]*$/i}
97
	 * @param string           $sqlfilters          Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
98
	 * @return  array                               Array of shipment objects
99
	 *
100
	 * @throws RestException
101
	 */
102
	public function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 100, $page = 0, $thirdparty_ids = '', $sqlfilters = '')
103
	{
104
		global $db, $conf;
105
106
		if (!DolibarrApiAccess::$user->rights->expedition->lire) {
107
			throw new RestException(401);
108
		}
109
110
		$obj_ret = array();
111
112
		// case of external user, $thirdparty_ids param is ignored and replaced by user's socid
113
		$socids = DolibarrApiAccess::$user->socid ? DolibarrApiAccess::$user->socid : $thirdparty_ids;
114
115
		// If the internal user must only see his customers, force searching by him
116
		$search_sale = 0;
117
		if (!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) {
118
			$search_sale = DolibarrApiAccess::$user->id;
119
		}
120
121
		$sql = "SELECT t.rowid";
122
		if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) {
123
			$sql .= ", sc.fk_soc, sc.fk_user"; // We need these fields in order to filter by sale (including the case where the user can only see his prospects)
124
		}
125
		$sql .= " FROM ".MAIN_DB_PREFIX."expedition as t";
126
127
		if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) {
128
			$sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale
129
		}
130
131
		$sql .= ' WHERE t.entity IN ('.getEntity('expedition').')';
132
		if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) {
133
			$sql .= " AND t.fk_soc = sc.fk_soc";
134
		}
135
		if ($socids) {
136
			$sql .= " AND t.fk_soc IN (".$this->db->sanitize($socids).")";
137
		}
138
		if ($search_sale > 0) {
139
			$sql .= " AND t.rowid = sc.fk_soc"; // Join for the needed table to filter by sale
140
		}
141
		// Insert sale filter
142
		if ($search_sale > 0) {
143
			$sql .= " AND sc.fk_user = ".((int) $search_sale);
144
		}
145
		// Add sql filters
146
		if ($sqlfilters) {
147
			if (!DolibarrApi::_checkFilters($sqlfilters)) {
148
				throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters);
149
			}
150
			$regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)';
151
			$sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
152
		}
153
154
		$sql .= $this->db->order($sortfield, $sortorder);
155
		if ($limit) {
156
			if ($page < 0) {
157
				$page = 0;
158
			}
159
			$offset = $limit * $page;
160
161
			$sql .= $this->db->plimit($limit + 1, $offset);
162
		}
163
164
		dol_syslog("API Rest request");
165
		$result = $this->db->query($sql);
166
167
		if ($result) {
168
			$num = $this->db->num_rows($result);
169
			$min = min($num, ($limit <= 0 ? $num : $limit));
170
			$i = 0;
171
			while ($i < $min) {
172
				$obj = $this->db->fetch_object($result);
173
				$shipment_static = new Expedition($this->db);
174
				if ($shipment_static->fetch($obj->rowid)) {
175
					$obj_ret[] = $this->_cleanObjectDatas($shipment_static);
176
				}
177
				$i++;
178
			}
179
		} else {
180
			throw new RestException(503, 'Error when retrieve commande list : '.$this->db->lasterror());
181
		}
182
		if (!count($obj_ret)) {
183
			throw new RestException(404, 'No shipment found');
184
		}
185
		return $obj_ret;
186
	}
187
188
	/**
189
	 * Create shipment object
190
	 *
191
	 * @param   array   $request_data   Request data
192
	 * @return  int     ID of shipment
193
	 */
194
	public function post($request_data = null)
195
	{
196
		if (!DolibarrApiAccess::$user->rights->expedition->creer) {
197
			throw new RestException(401, "Insuffisant rights");
198
		}
199
		// Check mandatory fields
200
		$result = $this->_validate($request_data);
201
202
		foreach ($request_data as $field => $value) {
203
			$this->shipment->$field = $value;
204
		}
205
		if (isset($request_data["lines"])) {
206
			$lines = array();
207
			foreach ($request_data["lines"] as $line) {
208
				array_push($lines, (object) $line);
209
			}
210
			$this->shipment->lines = $lines;
211
		}
212
213
		if ($this->shipment->create(DolibarrApiAccess::$user) < 0) {
214
			throw new RestException(500, "Error creating shipment", array_merge(array($this->shipment->error), $this->shipment->errors));
215
		}
216
217
		return $this->shipment->id;
218
	}
219
220
	// /**
221
	//  * Get lines of an shipment
222
	//  *
223
	//  * @param int   $id             Id of shipment
224
	//  *
225
	//  * @url	GET {id}/lines
226
	//  *
227
	//  * @return int
228
	//  */
229
	/*
230
	public function getLines($id)
231
	{
232
		if(! DolibarrApiAccess::$user->rights->expedition->lire) {
233
			throw new RestException(401);
234
		}
235
236
		$result = $this->shipment->fetch($id);
237
		if( ! $result ) {
238
			throw new RestException(404, 'Shipment not found');
239
		}
240
241
		if( ! DolibarrApi::_checkAccessToResource('expedition',$this->shipment->id)) {
242
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
243
		}
244
		$this->shipment->getLinesArray();
245
		$result = array();
246
		foreach ($this->shipment->lines as $line) {
247
			array_push($result,$this->_cleanObjectDatas($line));
248
		}
249
		return $result;
250
	}
251
	*/
252
253
	// /**
254
	//  * Add a line to given shipment
255
	//  *
256
	//  * @param int   $id             Id of shipment to update
257
	//  * @param array $request_data   ShipmentLine data
258
	//  *
259
	//  * @url	POST {id}/lines
260
	//  *
261
	//  * @return int
262
	//  */
263
	/*
264
	public function postLine($id, $request_data = null)
265
	{
266
		if(! DolibarrApiAccess::$user->rights->expedition->creer) {
267
			throw new RestException(401);
268
		}
269
270
		$result = $this->shipment->fetch($id);
271
		if ( ! $result ) {
272
			throw new RestException(404, 'Shipment not found');
273
		}
274
275
		if( ! DolibarrApi::_checkAccessToResource('expedition',$this->shipment->id)) {
276
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
277
		}
278
279
		$request_data = (object) $request_data;
280
281
		$request_data->desc = checkVal($request_data->desc, 'restricthtml');
282
		$request_data->label = checkVal($request_data->label);
283
284
		$updateRes = $this->shipment->addline(
285
						$request_data->desc,
286
						$request_data->subprice,
287
						$request_data->qty,
288
						$request_data->tva_tx,
289
						$request_data->localtax1_tx,
290
						$request_data->localtax2_tx,
291
						$request_data->fk_product,
292
						$request_data->remise_percent,
293
						$request_data->info_bits,
294
						$request_data->fk_remise_except,
295
						'HT',
296
						0,
297
						$request_data->date_start,
298
						$request_data->date_end,
299
						$request_data->product_type,
300
						$request_data->rang,
301
						$request_data->special_code,
302
						$fk_parent_line,
303
						$request_data->fk_fournprice,
304
						$request_data->pa_ht,
305
						$request_data->label,
306
						$request_data->array_options,
307
						$request_data->fk_unit,
308
						$request_data->origin,
309
						$request_data->origin_id,
310
						$request_data->multicurrency_subprice
311
		);
312
313
		if ($updateRes > 0) {
314
			return $updateRes;
315
316
		}
317
		return false;
318
	}*/
319
320
	// /**
321
	//  * Update a line to given shipment
322
	//  *
323
	//  * @param int   $id             Id of shipment to update
324
	//  * @param int   $lineid         Id of line to update
325
	//  * @param array $request_data   ShipmentLine data
326
	//  *
327
	//  * @url	PUT {id}/lines/{lineid}
328
	//  *
329
	//  * @return object
330
	//  */
331
	/*
332
	public function putLine($id, $lineid, $request_data = null)
333
	{
334
		if (! DolibarrApiAccess::$user->rights->expedition->creer) {
335
			throw new RestException(401);
336
		}
337
338
		$result = $this->shipment->fetch($id);
339
		if ( ! $result ) {
340
			throw new RestException(404, 'Shipment not found');
341
		}
342
343
		if( ! DolibarrApi::_checkAccessToResource('expedition',$this->shipment->id)) {
344
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
345
		}
346
347
		$request_data = (object) $request_data;
348
349
		$request_data->desc = checkVal($request_data->desc, 'restricthtml');
350
		$request_data->label = checkVal($request_data->label);
351
352
		$updateRes = $this->shipment->updateline(
353
						$lineid,
354
						$request_data->desc,
355
						$request_data->subprice,
356
						$request_data->qty,
357
						$request_data->remise_percent,
358
						$request_data->tva_tx,
359
						$request_data->localtax1_tx,
360
						$request_data->localtax2_tx,
361
						'HT',
362
						$request_data->info_bits,
363
						$request_data->date_start,
364
						$request_data->date_end,
365
						$request_data->product_type,
366
						$request_data->fk_parent_line,
367
						0,
368
						$request_data->fk_fournprice,
369
						$request_data->pa_ht,
370
						$request_data->label,
371
						$request_data->special_code,
372
						$request_data->array_options,
373
						$request_data->fk_unit,
374
						$request_data->multicurrency_subprice
375
		);
376
377
		if ($updateRes > 0) {
378
			$result = $this->get($id);
379
			unset($result->line);
380
			return $this->_cleanObjectDatas($result);
381
		}
382
		return false;
383
	}*/
384
385
	/**
386
	 * Delete a line to given shipment
387
	 *
388
	 *
389
	 * @param int   $id             Id of shipment to update
390
	 * @param int   $lineid         Id of line to delete
391
	 *
392
	 * @url	DELETE {id}/lines/{lineid}
393
	 *
394
	 * @return int
395
	 *
396
	 * @throws RestException 401
397
	 * @throws RestException 404
398
	 */
399
	public function deleteLine($id, $lineid)
400
	{
401
		if (!DolibarrApiAccess::$user->rights->expedition->creer) {
402
			throw new RestException(401);
403
		}
404
405
		$result = $this->shipment->fetch($id);
406
		if (!$result) {
407
			throw new RestException(404, 'Shipment not found');
408
		}
409
410
		if (!DolibarrApi::_checkAccessToResource('expedition', $this->shipment->id)) {
411
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
412
		}
413
414
		// TODO Check the lineid $lineid is a line of ojbect
415
416
		$updateRes = $this->shipment->deleteline(DolibarrApiAccess::$user, $lineid);
417
		if ($updateRes > 0) {
418
			return $this->get($id);
419
		} else {
420
			throw new RestException(405, $this->shipment->error);
421
		}
422
	}
423
424
	/**
425
	 * Update shipment general fields (won't touch lines of shipment)
426
	 *
427
	 * @param int   $id             Id of shipment to update
428
	 * @param array $request_data   Datas
429
	 *
430
	 * @return int
431
	 */
432
	public function put($id, $request_data = null)
433
	{
434
		if (!DolibarrApiAccess::$user->rights->expedition->creer) {
435
			throw new RestException(401);
436
		}
437
438
		$result = $this->shipment->fetch($id);
439
		if (!$result) {
440
			throw new RestException(404, 'Shipment not found');
441
		}
442
443
		if (!DolibarrApi::_checkAccessToResource('expedition', $this->shipment->id)) {
444
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
445
		}
446
		foreach ($request_data as $field => $value) {
447
			if ($field == 'id') {
448
				continue;
449
			}
450
			$this->shipment->$field = $value;
451
		}
452
453
		if ($this->shipment->update(DolibarrApiAccess::$user) > 0) {
454
			return $this->get($id);
455
		} else {
456
			throw new RestException(500, $this->shipment->error);
457
		}
458
	}
459
460
	/**
461
	 * Delete shipment
462
	 *
463
	 * @param   int     $id         Shipment ID
464
	 *
465
	 * @return  array
466
	 */
467
	public function delete($id)
468
	{
469
		if (!DolibarrApiAccess::$user->rights->expedition->supprimer) {
470
			throw new RestException(401);
471
		}
472
		$result = $this->shipment->fetch($id);
473
		if (!$result) {
474
			throw new RestException(404, 'Shipment not found');
475
		}
476
477
		if (!DolibarrApi::_checkAccessToResource('expedition', $this->shipment->id)) {
478
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
479
		}
480
481
		if (!$this->shipment->delete(DolibarrApiAccess::$user)) {
482
			throw new RestException(500, 'Error when deleting shipment : '.$this->shipment->error);
483
		}
484
485
		return array(
486
			'success' => array(
487
				'code' => 200,
488
				'message' => 'Shipment deleted'
489
			)
490
		);
491
	}
492
493
	/**
494
	 * Validate a shipment
495
	 *
496
	 * This may record stock movements if module stock is enabled and option to
497
	 * decrease stock on shipment is on.
498
	 *
499
	 * @param   int $id             Shipment ID
500
	 * @param   int $notrigger      1=Does not execute triggers, 0= execute triggers
501
	 *
502
	 * @url POST    {id}/validate
503
	 *
504
	 * @return  array
505
	 * \todo An error 403 is returned if the request has an empty body.
506
	 * Error message: "Forbidden: Content type `text/plain` is not supported."
507
	 * Workaround: send this in the body
508
	 * {
509
	 *   "notrigger": 0
510
	 * }
511
	 */
512
	public function validate($id, $notrigger = 0)
513
	{
514
		if (!DolibarrApiAccess::$user->rights->expedition->creer) {
515
			throw new RestException(401);
516
		}
517
		$result = $this->shipment->fetch($id);
518
		if (!$result) {
519
			throw new RestException(404, 'Shipment not found');
520
		}
521
522
		if (!DolibarrApi::_checkAccessToResource('expedition', $this->shipment->id)) {
523
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
524
		}
525
526
		$result = $this->shipment->valid(DolibarrApiAccess::$user, $notrigger);
527
		if ($result == 0) {
528
			throw new RestException(304, 'Error nothing done. May be object is already validated');
529
		}
530
		if ($result < 0) {
531
			throw new RestException(500, 'Error when validating Shipment: '.$this->shipment->error);
532
		}
533
534
		// Reload shipment
535
		$result = $this->shipment->fetch($id);
536
537
		$this->shipment->fetchObjectLinked();
538
		return $this->_cleanObjectDatas($this->shipment);
539
	}
540
541
542
	// /**
543
	//  *  Classify the shipment as invoiced
544
	//  *
545
	//  * @param int   $id           Id of the shipment
546
	//  *
547
	//  * @url     POST {id}/setinvoiced
548
	//  *
549
	//  * @return int
550
	//  *
551
	//  * @throws RestException 400
552
	//  * @throws RestException 401
553
	//  * @throws RestException 404
554
	//  * @throws RestException 405
555
	//  */
556
	 /*
557
	public function setinvoiced($id)
558
	{
559
560
		if(! DolibarrApiAccess::$user->rights->expedition->creer) {
561
				throw new RestException(401);
562
		}
563
		if(empty($id)) {
564
				throw new RestException(400, 'Shipment ID is mandatory');
565
		}
566
		$result = $this->shipment->fetch($id);
567
		if( ! $result ) {
568
				throw new RestException(404, 'Shipment not found');
569
		}
570
571
		$result = $this->shipment->classifyBilled(DolibarrApiAccess::$user);
572
		if( $result < 0) {
573
				throw new RestException(400, $this->shipment->error);
574
		}
575
		return $result;
576
	}
577
	*/
578
579
580
	//  /**
581
	//  * Create a shipment using an existing order.
582
	//  *
583
	//  * @param int   $orderid       Id of the order
584
	//  *
585
	//  * @url     POST /createfromorder/{orderid}
586
	//  *
587
	//  * @return int
588
	//  * @throws RestException 400
589
	//  * @throws RestException 401
590
	//  * @throws RestException 404
591
	//  * @throws RestException 405
592
	//  */
593
	/*
594
	public function createShipmentFromOrder($orderid)
595
	{
596
597
		require_once DOL_DOCUMENT_ROOT . '/commande/class/commande.class.php';
598
599
		if(! DolibarrApiAccess::$user->rights->expedition->lire) {
600
				throw new RestException(401);
601
		}
602
		if(! DolibarrApiAccess::$user->rights->expedition->creer) {
603
				throw new RestException(401);
604
		}
605
		if(empty($proposalid)) {
606
				throw new RestException(400, 'Order ID is mandatory');
607
		}
608
609
		$order = new Commande($this->db);
610
		$result = $order->fetch($proposalid);
611
		if( ! $result ) {
612
				throw new RestException(404, 'Order not found');
613
		}
614
615
		$result = $this->shipment->createFromOrder($order, DolibarrApiAccess::$user);
616
		if( $result < 0) {
617
				throw new RestException(405, $this->shipment->error);
618
		}
619
		$this->shipment->fetchObjectLinked();
620
		return $this->_cleanObjectDatas($this->shipment);
621
	}
622
	*/
623
624
	/**
625
	* Close a shipment (Classify it as "Delivered")
626
	*
627
	* @param   int     $id             Expedition ID
628
	* @param   int     $notrigger      Disabled triggers
629
	*
630
	* @url POST    {id}/close
631
	*
632
	* @return  int
633
	*/
634
	public function close($id, $notrigger = 0)
635
	{
636
		if (!DolibarrApiAccess::$user->rights->expedition->creer) {
637
			throw new RestException(401);
638
		}
639
640
		$result = $this->shipment->fetch($id);
641
		if (!$result) {
642
			throw new RestException(404, 'Shipment not found');
643
		}
644
645
		if (!DolibarrApi::_checkAccessToResource('expedition', $this->commande->id)) {
0 ignored issues
show
Bug Best Practice introduced by
The property commande does not exist on Shipments. Did you maybe forget to declare it?
Loading history...
646
			throw new RestException(401, 'Access not allowed for login '.DolibarrApiAccess::$user->login);
647
		}
648
649
		$result = $this->shipment->setClosed();
650
		if ($result == 0) {
651
			throw new RestException(304, 'Error nothing done. May be object is already closed');
652
		}
653
		if ($result < 0) {
654
			throw new RestException(500, 'Error when closing Order: '.$this->commande->error);
655
		}
656
657
		// Reload shipment
658
		$result = $this->shipment->fetch($id);
659
660
		$this->shipment->fetchObjectLinked();
661
662
		return $this->_cleanObjectDatas($this->shipment);
663
	}
664
665
	// phpcs:disable PEAR.NamingConventions.ValidFunctionName.PublicUnderscore
666
	/**
667
	 * Clean sensible object datas
668
	 *
669
	 * @param   Object  $object     Object to clean
670
	 * @return  Object              Object with cleaned properties
671
	 */
672
	protected function _cleanObjectDatas($object)
673
	{
674
		// phpcs:enable
675
		$object = parent::_cleanObjectDatas($object);
676
677
		unset($object->thirdparty); // id already returned
678
679
		unset($object->note);
680
		unset($object->address);
681
		unset($object->barcode_type);
682
		unset($object->barcode_type_code);
683
		unset($object->barcode_type_label);
684
		unset($object->barcode_type_coder);
685
686
		if (!empty($object->lines) && is_array($object->lines)) {
687
			foreach ($object->lines as $line) {
688
				unset($line->tva_tx);
689
				unset($line->vat_src_code);
690
				unset($line->total_ht);
691
				unset($line->total_ttc);
692
				unset($line->total_tva);
693
				unset($line->total_localtax1);
694
				unset($line->total_localtax2);
695
				unset($line->remise_percent);
696
			}
697
		}
698
699
		return $object;
700
	}
701
702
	/**
703
	 * Validate fields before create or update object
704
	 *
705
	 * @param   array           $data   Array with data to verify
706
	 * @return  array
707
	 * @throws  RestException
708
	 */
709
	private function _validate($data)
710
	{
711
		$shipment = array();
712
		foreach (Shipments::$FIELDS as $field) {
713
			if (!isset($data[$field])) {
714
				throw new RestException(400, "$field field missing");
715
			}
716
			$shipment[$field] = $data[$field];
717
		}
718
		return $shipment;
719
	}
720
}
721