Issues (2811)

public/htdocs/reception/card.php (4 issues)

1
<?php
2
3
/* Copyright (C) 2003-2008  Rodolphe Quiedeville        <[email protected]>
4
 * Copyright (C) 2005-2016	Laurent Destailleur		    <[email protected]>
5
 * Copyright (C) 2005		Simon TOSSER			    <[email protected]>
6
 * Copyright (C) 2005-2012	Regis Houssin			    <[email protected]>
7
 * Copyright (C) 2011-2017	Juanjo Menent			    <[email protected]>
8
 * Copyright (C) 2013       Florian Henry		  	    <[email protected]>
9
 * Copyright (C) 2013       Marcos García               <[email protected]>
10
 * Copyright (C) 2014		Cedric GROSS			    <[email protected]>
11
 * Copyright (C) 2014-2017	Francis Appels			    <[email protected]>
12
 * Copyright (C) 2015		Claudio Aschieri		    <[email protected]>
13
 * Copyright (C) 2016		Ferran Marcet			    <[email protected]>
14
 * Copyright (C) 2016		Yasser Carreón			    <[email protected]>
15
 * Copyright (C) 2018	    Quentin Vial-Gouteyron      <[email protected]>
16
 * Copyright (C) 2024		MDW							<[email protected]>
17
 * Copyright (C) 2024       Rafael San José             <[email protected]>
18
 *
19
 * This program is free software; you can redistribute it and/or modify
20
 * it under the terms of the GNU General Public License as published by
21
 * the Free Software Foundation; either version 3 of the License, or
22
 * (at your option) any later version.
23
 *
24
 * This program is distributed in the hope that it will be useful,
25
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
27
 * GNU General Public License for more details.
28
 *
29
 * You should have received a copy of the GNU General Public License
30
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
31
 */
32
33
use Dolibarr\Code\Comm\Classes\Propal;
34
use Dolibarr\Code\Commande\Classes\Commande;
35
use Dolibarr\Code\Core\Classes\DolEditor;
36
use Dolibarr\Code\Core\Classes\ExtraFields;
37
use Dolibarr\Code\Core\Classes\Form;
38
use Dolibarr\Code\Core\Classes\FormFile;
39
use Dolibarr\Code\Core\Classes\FormProjets;
40
use Dolibarr\Code\Core\Classes\Notify;
41
use Dolibarr\Code\Core\Classes\Translate;
42
use Dolibarr\Code\Fourn\Classes\CommandeFournisseur;
43
use Dolibarr\Code\Fourn\Classes\CommandeFournisseurDispatch;
44
use Dolibarr\Code\Fourn\Classes\CommandeFournisseurLigne;
45
use Dolibarr\Code\Product\Classes\Entrepot;
46
use Dolibarr\Code\Product\Classes\FormProduct;
47
use Dolibarr\Code\Product\Classes\Product;
48
use Dolibarr\Code\Product\Classes\Productlot;
49
use Dolibarr\Code\Projet\Classes\Project;
50
use Dolibarr\Code\Reception\Classes\ModelePdfReception;
51
use Dolibarr\Code\Reception\Classes\Reception;
52
use Dolibarr\Code\Societe\Classes\Societe;
53
use Dolibarr\Code\User\Classes\User;
54
use Dolibarr\Lib\ViewMain;
55
56
/**
57
 *  \file       htdocs/reception/card.php
58
 *  \ingroup    reception
59
 *  \brief      Card of a reception
60
 */
61
62
// Load Dolibarr environment
63
require constant('DOL_DOCUMENT_ROOT') . '/main.inc.php';
64
require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/product.lib.php';
65
require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/reception.lib.php';
66
if (isModEnabled("product") || isModEnabled("service")) {
67
}
68
if (isModEnabled("propal")) {
69
}
70
if (isModEnabled('productbatch')) {
71
}
72
if (isModEnabled('project')) {
73
    }
74
75
$langs->loadLangs(array("receptions", "companies", "bills", 'deliveries', 'orders', 'stocks', 'other', 'propal', 'sendings'));
76
77
if (isModEnabled('incoterm')) {
78
    $langs->load('incoterm');
79
}
80
if (isModEnabled('productbatch')) {
81
    $langs->load('productbatch');
82
}
83
84
$origin = GETPOST('origin', 'alpha') ? GETPOST('origin', 'alpha') : 'reception'; // Example: commande, propal
85
$origin_id = GETPOSTINT('id') ? GETPOSTINT('id') : '';
86
$id = $origin_id;
87
if (empty($origin_id)) {
88
    $origin_id  = GETPOSTINT('origin_id'); // Id of order or propal
89
}
90
if (empty($origin_id)) {
91
    $origin_id  = GETPOSTINT('object_id'); // Id of order or propal
92
}
93
if (empty($origin_id)) {
94
    $origin_id  = GETPOSTINT('originid'); // Id of order or propal
95
}
96
$ref = GETPOST('ref', 'alpha');
97
$line_id = GETPOSTINT('lineid') ? GETPOSTINT('lineid') : 0;
98
$facid = GETPOSTINT('facid');
99
100
$action = GETPOST('action', 'alpha');
101
//Select mail models is same action as presend
102
if (GETPOST('modelselected')) {
103
    $action = 'presend';
104
}
105
$confirm = GETPOST('confirm', 'alpha');
106
$cancel = GETPOST('cancel', 'alpha');
107
$backtopage = GETPOST('backtopage', 'alpha');
108
$backtopageforcancel = GETPOST('backtopageforcancel', 'alpha');
109
110
//PDF
111
$hidedetails = (GETPOSTINT('hidedetails') ? GETPOSTINT('hidedetails') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DETAILS') ? 1 : 0));
112
$hidedesc = (GETPOSTINT('hidedesc') ? GETPOSTINT('hidedesc') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_DESC') ? 1 : 0));
113
$hideref = (GETPOSTINT('hideref') ? GETPOSTINT('hideref') : (getDolGlobalString('MAIN_GENERATE_DOCUMENTS_HIDE_REF') ? 1 : 0));
114
115
$object = new Reception($db);
116
$objectorder = new CommandeFournisseur($db);
117
$extrafields = new ExtraFields($db);
118
119
// fetch optionals attributes and labels
120
$extrafields->fetch_name_optionals_label($object->table_element);
121
$extrafields->fetch_name_optionals_label($object->table_element_line);
122
$extrafields->fetch_name_optionals_label($objectorder->table_element_line);
123
124
// Load object. Make an object->fetch
125
include DOL_DOCUMENT_ROOT . '/core/actions_fetchobject.inc.php'; // Must be include, not include_once
126
127
// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
128
$hookmanager->initHooks(array('receptioncard', 'globalcard'));
129
130
$date_delivery = dol_mktime(GETPOSTINT('date_deliveryhour'), GETPOSTINT('date_deliverymin'), 0, GETPOSTINT('date_deliverymonth'), GETPOSTINT('date_deliveryday'), GETPOSTINT('date_deliveryyear'));
131
132
if ($id > 0 || !empty($ref)) {
133
    $object->fetch($id, $ref);
134
    $object->fetch_thirdparty();
135
136
    $typeobject = '';
137
    if (!empty($object->origin)) {
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$origin has been deprecated: Use $origin_type and $origin_id instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

137
    if (!empty(/** @scrutinizer ignore-deprecated */ $object->origin)) {

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
138
        $origin = $object->origin;
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$origin has been deprecated: Use $origin_type and $origin_id instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

138
        $origin = /** @scrutinizer ignore-deprecated */ $object->origin;

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
139
        $typeobject = $object->origin;
0 ignored issues
show
Deprecated Code introduced by
The property Dolibarr\Core\Base\CommonObject::$origin has been deprecated: Use $origin_type and $origin_id instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

139
        $typeobject = /** @scrutinizer ignore-deprecated */ $object->origin;

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
140
141
        $object->fetch_origin();
142
    }
143
144
    // Set $origin_id and $objectsrc
145
    if (($origin == 'order_supplier' || $origin == 'supplier_order') && is_object($object->origin_object) && isModEnabled("supplier_order")) {
146
        $origin_id = $object->origin_object->id;
147
        $objectsrc = $object->origin_object;
148
    }
149
}
150
151
// Security check
152
$socid = '';
153
if ($user->socid) {
154
    $socid = $user->socid;
155
}
156
157
// TODO Test on reception module on only
158
if (isModEnabled("reception") || $origin == 'reception' || empty($origin)) {
159
    $result = restrictedArea($user, 'reception', $object->id);
160
} else {
161
    // We do not use the reception module, so we test permission on the supplier orders
162
    if ($origin == 'supplierorder' || $origin == 'order_supplier') {
163
        $result = restrictedArea($user, 'fournisseur', $origin_id, 'commande_fournisseur', 'commande');
164
    } elseif (!$user->hasRight($origin, 'lire') && !$user->hasRight($origin, 'read')) {
165
        accessforbidden();
166
    }
167
}
168
169
if (isModEnabled("reception")) {
170
    $permissiontoread = $user->hasRight('reception', 'lire');
171
    $permissiontoadd = $user->hasRight('reception', 'creer');
172
    $permissiondellink = $user->hasRight('reception', 'creer'); // Used by the include of actions_dellink.inc.php
173
    $permissiontovalidate = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('reception', 'creer')) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('reception', 'reception_advance', 'validate')));
174
    $permissiontodelete = $user->hasRight('reception', 'supprimer');
175
} else {
176
    $permissiontoread = $user->hasRight('fournisseur', 'commande', 'receptionner');
177
    $permissiontoadd = $user->hasRight('fournisseur', 'commande', 'receptionner');
178
    $permissiondellink = $user->hasRight('fournisseur', 'commande', 'receptionner'); // Used by the include of actions_dellink.inc.php
179
    $permissiontovalidate = ((!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('fournisseur', 'commande', 'receptionner')) || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('fournisseur', 'commande_advance', 'check')));
180
    $permissiontodelete = $user->hasRight('fournisseur', 'commande', 'receptionner');
181
}
182
183
184
/*
185
 * Actions
186
 */
187
188
$parameters = array();
189
$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
190
if ($reshook < 0) {
191
    setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
192
}
193
194
if (empty($reshook)) {
195
    /*
196
    $backurlforlist = DOL_URL_ROOT.'/reception/list.php';
197
198
    if (empty($backtopage) || ($cancel && empty($id))) {
199
        if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) {
200
             if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) {
201
                 $backtopage = $backurlforlist;
202
             } else {
203
                 $backtopage = dol_buildpath('/mymodule/myobject_card.php', 1).'?id='.((!empty($id) && $id > 0) ? $id : '__ID__');
204
             }
205
        }
206
    }
207
    */
208
209
    if ($cancel) {
210
        if (!empty($backtopageforcancel)) {
211
            header("Location: " . $backtopageforcancel);
212
            exit;
213
        } elseif (!empty($backtopage)) {
214
            header("Location: " . $backtopage);
215
            exit;
216
        }
217
218
        $action = '';
219
    }
220
221
    include DOL_DOCUMENT_ROOT . '/core/actions_dellink.inc.php'; // Must be include, not include_once
222
223
    // Reopen
224
    if ($action == 'reopen' && $permissiontoadd) {
225
        $result = $object->reOpen();
226
    }
227
228
    // Confirm back to draft status
229
    if ($action == 'modif' && $permissiontoadd) {
230
        $result = $object->setDraft($user);
231
        if ($result >= 0) {
232
            // Define output language
233
            if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
234
                $outputlangs = $langs;
235
                $newlang = '';
236
                if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
237
                    $newlang = GETPOST('lang_id', 'aZ09');
238
                }
239
                if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
240
                    $newlang = $object->thirdparty->default_lang;
241
                }
242
                if (!empty($newlang)) {
243
                    $outputlangs = new Translate("", $conf);
244
                    $outputlangs->setDefaultLang($newlang);
245
                }
246
                $model = $object->model_pdf;
247
                $ret = $object->fetch($id); // Reload to get new records
248
                $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
249
            }
250
        } else {
251
            setEventMessages($object->error, $object->errors, 'errors');
252
        }
253
    }
254
255
    // Set incoterm
256
    if ($action == 'set_incoterms' && isModEnabled('incoterm') && $permissiontoadd) {
257
        $result = $object->setIncoterms(GETPOSTINT('incoterm_id'), GETPOSTINT('location_incoterms'));
258
    }
259
260
    if ($action == 'setref_supplier' && $permissiontoadd) {
261
        if ($result < 0) {
262
            setEventMessages($object->error, $object->errors, 'errors');
263
        }
264
265
        $result = $object->setValueFrom('ref_supplier', GETPOST('ref_supplier', 'alpha'), '', null, 'text', '', $user, 'RECEPTION_MODIFY');
266
        if ($result < 0) {
267
            setEventMessages($object->error, $object->errors, 'errors');
268
            $action = 'editref_supplier';
269
        } else {
270
            header("Location: " . $_SERVER['PHP_SELF'] . "?id=" . $object->id);
271
            exit;
272
        }
273
    }
274
275
    if ($action == 'update_extras' && $permissiontoadd) {
276
        $object->oldcopy = dol_clone($object, 2);
277
278
        // Fill array 'array_options' with data from update form
279
        $ret = $extrafields->setOptionalsFromPost(null, $object, GETPOST('attribute', 'restricthtml'));
280
        if ($ret < 0) {
281
            $error++;
282
        }
283
284
        if (!$error) {
285
            // Actions on extra fields
286
            $result = $object->insertExtraFields('RECEPTION_MODIFY');
287
            if ($result < 0) {
288
                setEventMessages($object->error, $object->errors, 'errors');
289
                $error++;
290
            }
291
        }
292
293
        if ($error) {
294
            $action = 'edit_extras';
295
        }
296
    }
297
298
    // Create reception
299
    if ($action == 'add' && $permissiontoadd) {
300
        $error = 0;
301
        $predef = '';
302
303
        $db->begin();
304
305
        $object->note = GETPOST('note', 'alpha');
306
        $object->origin = $origin;
307
        $object->origin_id = $origin_id;
308
        $object->fk_project = GETPOSTINT('projectid');
309
        $object->weight = GETPOSTINT('weight') == '' ? null : GETPOSTINT('weight');
310
        $object->trueHeight = GETPOSTINT('trueHeight') == '' ? null : GETPOSTINT('trueHeight');
311
        $object->trueWidth = GETPOSTINT('trueWidth') == '' ? null : GETPOSTINT('trueWidth');
312
        $object->trueDepth = GETPOSTINT('trueDepth') == '' ? null : GETPOSTINT('trueDepth');
313
        $object->size_units = GETPOSTINT('size_units');
314
        $object->weight_units = GETPOSTINT('weight_units');
315
316
        // On va boucler sur chaque ligne du document d'origine pour completer object reception
317
        // avec info diverses + qte a livrer
318
319
        if ($object->origin == "supplierorder") {
320
            $classname = 'CommandeFournisseur';
321
        } else {
322
            $classname = ucfirst($object->origin);
323
        }
324
        $objectsrc = new $classname($db);
325
        $objectsrc->fetch($object->origin_id);
326
327
        $object->socid = $objectsrc->socid;
328
        $object->ref_supplier = GETPOST('ref_supplier', 'alpha');
329
        $object->model_pdf = GETPOST('model');
330
        $object->date_delivery = $date_delivery; // Date delivery planned
331
        $object->fk_delivery_address = $objectsrc->fk_delivery_address;
332
        $object->shipping_method_id = GETPOSTINT('shipping_method_id');
333
        $object->tracking_number = GETPOST('tracking_number', 'alpha');
334
        $object->note_private = GETPOST('note_private', 'restricthtml');
335
        $object->note_public = GETPOST('note_public', 'restricthtml');
336
        $object->fk_incoterms = GETPOSTINT('incoterm_id');
337
        $object->location_incoterms = GETPOST('location_incoterms', 'alpha');
338
339
        $batch_line = array();
340
        $stockLine = array();
341
        $array_options = array();
342
343
        $totalqty = 0;
344
345
        $num = 0;
346
        foreach ($_POST as $key => $value) {
347
            // without batch module enabled
348
349
            if (strpos($key, 'qtyasked') !== false) {
350
                $num++;
351
            }
352
        }
353
354
        // Loop lines to calculate $totalqty
355
        for ($i = 1; $i <= $num; $i++) {
356
            $idl = "idl" . $i;    // id line source
357
358
            //$sub_qty = array();
359
            //$subtotalqty = 0;
360
361
            //$j = 0;
362
            //$batch = "batchl".$i."_0";
363
            //$stockLocation = "ent1".$i."_0";
364
            $qty = "qtyl" . $i;   // qty
365
366
            //reception line for product with no batch management and no multiple stock location
367
            if (GETPOST($qty, 'alpha') > 0) {
368
                $totalqty += price2num(GETPOST($qty, 'alpha'), 'MS');
369
            }
370
371
            // Extrafields
372
            $array_options[$i] = $extrafields->getOptionalsFromPost($object->table_element_line, $i);
373
        }
374
375
376
        if ($totalqty > 0) {  // There is at least one thing to ship
377
            for ($i = 1; $i <= $num; $i++) {
378
                $idl = "idl" . $i;    // id line source
379
                $lineToTest = '';
380
                $lineId = GETPOSTINT($idl);
381
                foreach ($objectsrc->lines as $linesrc) {
382
                    if ($linesrc->id == $lineId) {
383
                        $lineToTest = $linesrc;
384
                        break;
385
                    }
386
                }
387
                if (empty($lineToTest)) {
388
                    continue;
389
                }
390
                $qty = "qtyl" . $i;
391
                $comment = "comment" . $i;
392
                // EATBY <-> DLUO and SELLBY <-> DLC, see productbatch.class.php
393
                $eatby = "dluo" . $i;
394
                $sellby = "dlc" . $i;
395
                $batch = "batch" . $i;
396
                $cost_price = "cost_price" . $i;
397
398
                //var_dump(GETPOST("productl".$i, 'int').' '.GETPOST('entl'.$i, 'int').' '.GETPOST($idl, 'int').' '.GETPOST($qty, 'int').' '.GETPOST($batch, 'alpha'));
399
400
                //if (GETPOST($qty, 'int') > 0 || (GETPOST($qty, 'int') == 0 && getDolGlobalString('RECEPTION_GETS_ALL_ORDER_PRODUCTS')) || (GETPOST($qty, 'int') < 0 && getDolGlobalString('RECEPTION_ALLOW_NEGATIVE_QTY'))) {
401
                if (GETPOSTINT($qty) > 0 || (GETPOSTINT($qty) == 0 && getDolGlobalString('RECEPTION_GETS_ALL_ORDER_PRODUCTS'))) {
402
                    $ent = "entl" . $i;
403
                    $idl = "idl" . $i;
404
405
                    $entrepot_id = is_numeric(GETPOST($ent)) ? GETPOSTINT($ent) : GETPOSTINT('entrepot_id');
406
407
                    /*
408
                    if (!empty($lineToTest)) {
409
                        $fk_product = $lineToTest->fk_product;
410
                    } else {
411
                        $fk_product = $linesrc->fk_product;
412
                    }*/
413
                    $fk_product = GETPOSTINT("productl" . $i);
414
415
                    if ($entrepot_id < 0) {
416
                        $entrepot_id = '';
417
                    }
418
                    if (!($fk_product > 0) && !getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
419
                        $entrepot_id = 0;
420
                    }
421
422
                    $eatby = GETPOST($eatby, 'alpha');
423
                    $sellby = GETPOST($sellby, 'alpha');
424
                    $eatbydate = str_replace('/', '-', $eatby);
425
                    $sellbydate = str_replace('/', '-', $sellby);
426
427
                    if (getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION') || getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION_CLOSE')) {
428
                        $ret = $object->addline($entrepot_id, GETPOSTINT($idl), price2num(GETPOST($qty), 'MS'), $array_options[$i], GETPOST($comment), strtotime($eatbydate), strtotime($sellbydate), GETPOST($batch), GETPOSTFLOAT($cost_price, 'MU'));
429
                    } else {
430
                        $ret = $object->addline($entrepot_id, GETPOSTINT($idl), price2num(GETPOST($qty), 'MS'), $array_options[$i], GETPOST($comment), strtotime($eatbydate), strtotime($sellbydate), GETPOST($batch));
431
                    }
432
                    if ($ret < 0) {
433
                        setEventMessages($object->error, $object->errors, 'errors');
434
                        $error++;
435
                    }
436
                }
437
            }
438
439
            // Fill array 'array_options' with data from add form
440
            $ret = $extrafields->setOptionalsFromPost(null, $object);
441
            if ($ret < 0) {
442
                $error++;
443
            }
444
            if (!$error) {
445
                $ret = $object->create($user); // This create reception (like Odoo picking) and line of receptions. Stock movement will when validating reception.
446
447
                if ($ret <= 0) {
448
                    setEventMessages($object->error, $object->errors, 'errors');
449
                    $error++;
450
                }
451
            }
452
        } else {
453
            setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("QtyToReceive") . '/' . $langs->transnoentitiesnoconv("Warehouse")), null, 'errors');
454
            $error++;
455
        }
456
457
        if (!$error) {
458
            $db->commit();
459
            header("Location: card.php?id=" . $object->id);
460
            exit;
461
        } else {
462
            $db->rollback();
463
            //$_GET["commande_id"] = GETPOSTINT('commande_id');
464
            $action = 'create';
465
        }
466
    } elseif ($action == 'confirm_valid' && $confirm == 'yes' && $permissiontovalidate) {
467
        $object->fetch_thirdparty();
468
469
        $result = $object->valid($user);
470
471
        if ($result < 0) {
472
            $langs->load("errors");
473
            setEventMessages($langs->trans($object->error), null, 'errors');
474
        } else {
475
            // Define output language
476
            if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
477
                $outputlangs = $langs;
478
                $newlang = '';
479
                if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
480
                    $newlang = GETPOST('lang_id', 'aZ09');
481
                }
482
                if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
483
                    $newlang = $object->thirdparty->default_lang;
484
                }
485
                if (!empty($newlang)) {
486
                    $outputlangs = new Translate("", $conf);
487
                    $outputlangs->setDefaultLang($newlang);
488
                }
489
                $model = $object->model_pdf;
490
                $ret = $object->fetch($id); // Reload to get new records
491
492
                $result = $object->generateDocument($model, $outputlangs, $hidedetails, $hidedesc, $hideref);
493
                if ($result < 0) {
494
                    dol_print_error($db, $result);
495
                }
496
            }
497
        }
498
    } elseif ($action == 'confirm_delete' && $confirm == 'yes' && $permissiontodelete) {
499
        $result = $object->delete($user);
500
        if ($result > 0) {
501
            header("Location: " . constant('BASE_URL') . '/reception/index.php');
502
            exit;
503
        } else {
504
            setEventMessages($object->error, $object->errors, 'errors');
505
        }
506
507
        // TODO add alternative status
508
        /*} elseif ($action == 'reopen' && (!empty($user->rights->reception->creer) || !empty($user->rights->reception->reception_advance->validate))) {
509
            $result = $object->setStatut(0);
510
            if ($result < 0) {
511
                setEventMessages($object->error, $object->errors, 'errors');
512
        }*/
513
    } elseif ($action == 'setdate_livraison' && $permissiontoadd) {
514
        $datedelivery = dol_mktime(GETPOSTINT('liv_hour'), GETPOSTINT('liv_min'), 0, GETPOSTINT('liv_month'), GETPOSTINT('liv_day'), GETPOSTINT('liv_year'));
515
516
        $object->fetch($id);
517
        $result = $object->setDeliveryDate($user, $datedelivery);
518
        if ($result < 0) {
519
            setEventMessages($object->error, $object->errors, 'errors');
520
        }
521
    } elseif (
522
        ($action == 'settracking_number' || $action == 'settracking_url'
523
        || $action == 'settrueWeight'
524
        || $action == 'settrueWidth'
525
        || $action == 'settrueHeight'
526
        || $action == 'settrueDepth'
527
        || $action == 'setshipping_method_id') && $permissiontoadd
528
    ) {
529
        // Action update
530
        $error = 0;
531
532
        if ($action == 'settracking_number') {
533
            $object->tracking_number = trim(GETPOST('tracking_number', 'alpha'));
534
        }
535
        if ($action == 'settracking_url') {
536
            $object->tracking_url = trim(GETPOST('tracking_url', 'restricthtml'));
537
        }
538
        if ($action == 'settrueWeight') {
539
            $object->trueWeight = GETPOSTINT('trueWeight');
540
            $object->weight_units = GETPOSTINT('weight_units');
541
        }
542
        if ($action == 'settrueWidth') {
543
            $object->trueWidth = GETPOSTINT('trueWidth');
544
        }
545
        if ($action == 'settrueHeight') {
546
            $object->trueHeight = GETPOSTINT('trueHeight');
547
            $object->size_units = GETPOSTINT('size_units');
548
        }
549
        if ($action == 'settrueDepth') {
550
            $object->trueDepth = GETPOSTINT('trueDepth');
551
        }
552
        if ($action == 'setshipping_method_id') {
553
            $object->shipping_method_id = GETPOSTINT('shipping_method_id');
554
        }
555
556
        if (!$error) {
557
            if ($object->update($user) >= 0) {
558
                header("Location: card.php?id=" . $object->id);
559
                exit;
560
            }
561
            setEventMessages($object->error, $object->errors, 'errors');
562
        }
563
564
        $action = "";
565
    } elseif ($action == 'builddoc' && $permissiontoread) {
566
        // Build document
567
        // En get ou en post
568
        // Save last template used to generate document
569
        if (GETPOST('model')) {
570
            $object->setDocModel($user, GETPOST('model', 'alpha'));
571
        }
572
573
        // Define output language
574
        $outputlangs = $langs;
575
        $newlang = '';
576
        if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
577
            $newlang = GETPOST('lang_id', 'aZ09');
578
        }
579
        if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
580
            $newlang = $reception->thirdparty->default_lang;
581
        }
582
        if (!empty($newlang)) {
583
            $outputlangs = new Translate("", $conf);
584
            $outputlangs->setDefaultLang($newlang);
585
        }
586
        $result = $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
587
        if ($result <= 0) {
588
            setEventMessages($object->error, $object->errors, 'errors');
589
            $action = '';
590
        }
591
    } elseif ($action == 'remove_file' && $permissiontoadd) {
592
        // Delete file in doc form
593
        require_once constant('DOL_DOCUMENT_ROOT') . '/core/lib/files.lib.php';
594
595
        $upload_dir = $conf->reception->dir_output;
596
        $file = $upload_dir . '/' . GETPOST('file');
597
        $ret = dol_delete_file($file, 0, 0, 0, $object);
598
        if ($ret) {
599
            setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs');
600
        } else {
601
            setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors');
602
        }
603
    } elseif ($action == 'classifybilled' && $permissiontoadd) {
604
        $result = $object->setBilled();
605
        if ($result >= 0) {
606
            header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id);
607
            exit();
608
        } else {
609
            setEventMessages($object->error, $object->errors, 'errors');
610
            $action = '';
611
        }
612
    } elseif ($action == 'classifyclosed' && $permissiontoread) {
613
        $result = $object->setClosed();
614
        if ($result >= 0) {
615
            header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id);
616
            exit();
617
        } else {
618
            setEventMessages($object->error, $object->errors, 'errors');
619
            $action = '';
620
        }
621
    } elseif ($action == 'deleteline' && !empty($line_id) && $permissiontoread) {
622
        // delete a line
623
        $lines = $object->lines;
624
        $line = new CommandeFournisseurDispatch($db);
625
626
        $num_prod = count($lines);
627
        for ($i = 0; $i < $num_prod; $i++) {
628
            if ($lines[$i]->id == $line_id) {
629
                // delete single warehouse line
630
                $line->id = $line_id;
631
                if (!$error && $line->delete($user) < 0) {
632
                    $error++;
633
                }
634
            }
635
            unset($_POST["lineid"]);
636
        }
637
638
        if (!$error) {
639
            header('Location: ' . $_SERVER["PHP_SELF"] . '?id=' . $object->id);
640
            exit();
641
        } else {
642
            setEventMessages($line->error, $line->errors, 'errors');
643
        }
644
    } elseif ($action == 'updateline' && GETPOST('save') && $permissiontoadd) {
645
        // Update a line
646
        // Clean parameters
647
        $qty = 0;
648
        $entrepot_id = 0;
649
        $batch_id = 0;
650
651
        $lines = $object->lines;
652
        $num_prod = count($lines);
653
        for ($i = 0; $i < $num_prod; $i++) {
654
            if ($lines[$i]->id == $line_id) {  // we have found line to update
655
                $line = new CommandeFournisseurDispatch($db);
656
                $line->fetch($line_id);
657
                // Extrafields Lines
658
                $extrafields->fetch_name_optionals_label($object->table_element_line);
659
                $line->array_options = $extrafields->getOptionalsFromPost($object->table_element_line);
0 ignored issues
show
Documentation Bug introduced by
It seems like $extrafields->getOptiona...ct->table_element_line) can also be of type integer. However, the property $array_options is declared as type array<string,mixed>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
660
661
662
                $line->fk_product = $lines[$i]->fk_product;
663
664
665
                if ($lines[$i]->fk_product > 0) {
666
                    // single warehouse reception line
667
                    $stockLocation = "entl" . $line_id;
668
                    $qty = "qtyl" . $line_id;
669
                    $comment = "comment" . $line_id;
670
671
672
                    $line->id = $line_id;
673
                    $line->fk_entrepot = GETPOSTINT($stockLocation);
674
                    $line->qty = GETPOSTINT($qty);
675
                    $line->comment = GETPOST($comment, 'alpha');
676
677
                    if (isModEnabled('productbatch')) {
678
                        $batch = "batch" . $line_id;
679
                        $dlc = "dlc" . $line_id;
680
                        $dluo = "dluo" . $line_id;
681
                        // EATBY <-> DLUO
682
                        $eatby = GETPOST($dluo, 'alpha');
683
                        $eatbydate = str_replace('/', '-', $eatby);
684
                        // SELLBY <-> DLC
685
                        $sellby = GETPOST($dlc, 'alpha');
686
                        $sellbydate = str_replace('/', '-', $sellby);
687
                        $line->batch = GETPOST($batch, 'alpha');
688
                        $line->eatby = strtotime($eatbydate);
689
                        $line->sellby = strtotime($sellbydate);
690
                    }
691
692
                    if ($line->update($user) < 0) {
693
                        setEventMessages($line->error, $line->errors, 'errors');
694
                        $error++;
695
                    }
696
                } else { // Product no predefined
697
                    $qty = "qtyl" . $line_id;
698
                    $line->id = $line_id;
699
                    $line->qty = GETPOSTINT($qty);
700
                    $line->fk_entrepot = 0;
701
                    if ($line->update($user) < 0) {
702
                        setEventMessages($line->error, $line->errors, 'errors');
703
                        $error++;
704
                    }
705
                    unset($_POST[$qty]);
706
                }
707
            }
708
        }
709
710
        unset($_POST["lineid"]);
711
712
        if (!$error) {
713
            if (!getDolGlobalString('MAIN_DISABLE_PDF_AUTOUPDATE')) {
714
                // Define output language
715
                $outputlangs = $langs;
716
                $newlang = '';
717
                if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang) && GETPOST('lang_id', 'aZ09')) {
718
                    $newlang = GETPOST('lang_id', 'aZ09');
719
                }
720
                if (getDolGlobalInt('MAIN_MULTILANGS') && empty($newlang)) {
721
                    $newlang = $object->thirdparty->default_lang;
722
                }
723
                if (!empty($newlang)) {
724
                    $outputlangs = new Translate("", $conf);
725
                    $outputlangs->setDefaultLang($newlang);
726
                }
727
728
                $ret = $object->fetch($object->id); // Reload to get new records
729
                $object->generateDocument($object->model_pdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
730
            }
731
        } else {
732
            header('Location: ' . $_SERVER['PHP_SELF'] . '?id=' . $object->id); // To reshow the record we edit
733
            exit();
734
        }
735
    } elseif ($action == 'updateline' && $permissiontoadd && GETPOST('cancel', 'alpha') == $langs->trans("Cancel")) {
736
        header('Location: ' . $_SERVER['PHP_SELF'] . '?id=' . $object->id); // To reshow the record we edit
737
        exit();
738
    }
739
740
    include DOL_DOCUMENT_ROOT . '/core/actions_printing.inc.php';
741
742
    // Actions to send emails
743
    if (empty($id)) {
744
        $id = $facid;
745
    }
746
    $triggersendname = 'RECEPTION_SENTBYMAIL';
747
    $paramname = 'id';
748
    $mode = 'emailfromreception';
749
    $autocopy = 'MAIN_MAIL_AUTOCOPY_RECEPTION_TO';
750
    $trackid = 'rec' . $object->id;
751
    include DOL_DOCUMENT_ROOT . '/core/actions_sendmails.inc.php';
752
}
753
754
755
/*
756
 * View
757
 */
758
759
$title = $object->ref . ' - ' . $langs->trans('Reception');
760
761
ViewMain::llxHeader('', $title, 'Reception', '', 0, 0, '', '', '', 'mod-reception page-card');
762
763
$form = new Form($db);
764
$formfile = new FormFile($db);
765
$formproduct = new FormProduct($db);
766
if (isModEnabled('project')) {
767
    $formproject = new FormProjets($db);
768
}
769
770
$product_static = new Product($db);
771
$reception_static = new Reception($db);
772
$warehousestatic = new Entrepot($db);
773
774
if ($action == 'create2') {
775
    print load_fiche_titre($langs->trans("CreateReception"), '', 'dollyrevert');
776
777
    print '<br>' . $langs->trans("ReceptionCreationIsDoneFromOrder");
778
    $action = '';
779
    $id = '';
780
    $ref = '';
781
}
782
783
// Mode creation.
784
if ($action == 'create') {
785
    $recept = new Reception($db);
786
787
    print load_fiche_titre($langs->trans("CreateReception"));
788
    if (!$origin) {
789
        setEventMessages($langs->trans("ErrorBadParameters"), null, 'errors');
790
    }
791
792
    if ($origin) {
793
        if ($origin == 'supplierorder') {
794
            $classname = 'CommandeFournisseur';
795
        } else {
796
            $classname = ucfirst($origin);
797
        }
798
799
        $objectsrc = new $classname($db);
800
        if ($objectsrc->fetch($origin_id)) {    // This include the fetch_lines
801
            $soc = new Societe($db);
802
            $soc->fetch($objectsrc->socid);
803
804
            $author = new User($db);
805
            $author->fetch($objectsrc->user_author_id);
806
807
            if (isModEnabled('stock')) {
808
                $entrepot = new Entrepot($db);
809
            }
810
811
            print '<form action="' . $_SERVER["PHP_SELF"] . '" method="post">';
812
            print '<input type="hidden" name="token" value="' . newToken() . '">';
813
            print '<input type="hidden" name="action" value="add">';
814
            print '<input type="hidden" name="origin" value="' . $origin . '">';
815
            print '<input type="hidden" name="origin_id" value="' . $objectsrc->id . '">';
816
            print '<input type="hidden" name="backtopageforcancel" value="' . $backtopageforcancel . '">';
817
            print '<input type="hidden" name="backtopage" value="' . $backtopage . '">';
818
            if (GETPOSTINT('entrepot_id')) {
819
                print '<input type="hidden" name="entrepot_id" value="' . GETPOSTINT('entrepot_id') . '">';
820
            }
821
822
            print dol_get_fiche_head();
823
824
            print '<table class="border centpercent">';
825
826
            // Ref
827
            print '<tr><td class="titlefieldcreate fieldrequired">';
828
            if ($origin == 'supplierorder' && isModEnabled("supplier_order")) {
829
                print $langs->trans("RefOrder") . '</td><td colspan="3"><a href="' . constant('BASE_URL') . '/fourn/commande/card.php?id=' . $objectsrc->id . '">' . img_object($langs->trans("ShowOrder"), 'order') . ' ' . $objectsrc->ref;
830
            }
831
            if ($origin == 'propal' && isModEnabled("propal")) {
832
                print $langs->trans("RefProposal") . '</td><td colspan="3"><a href="' . constant('BASE_URL') . '/comm/card.php?id=' . $objectsrc->id . '">' . img_object($langs->trans("ShowProposal"), 'propal') . ' ' . $objectsrc->ref;
833
            }
834
            print '</a></td>';
835
            print "</tr>\n";
836
837
            // Ref client
838
            print '<tr><td>';
839
            if ($origin == 'supplier_order') {
840
                print $langs->trans('SupplierOrder');
841
            } else {
842
                print $langs->trans('RefSupplier');
843
            }
844
            print '</td><td colspan="3">';
845
            print '<input type="text" name="ref_supplier" value="' . $objectsrc->ref_supplier . '" />';
846
            print '</td>';
847
            print '</tr>';
848
849
            // Tiers
850
            print '<tr><td class="titlefieldcreate fieldrequired">' . $langs->trans('Company') . '</td>';
851
            print '<td colspan="3">' . $soc->getNomUrl(1) . '</td>';
852
            print '</tr>';
853
854
            // Project
855
            if (isModEnabled('project')) {
856
                $projectid = GETPOSTINT('projectid') ? GETPOSTINT('projectid') : 0;
857
                if (empty($projectid) && !empty($objectsrc->fk_project)) {
858
                    $projectid = $objectsrc->fk_project;
859
                }
860
                if ($origin == 'project') {
861
                    $projectid = ($originid ? $originid : 0);
862
                }
863
864
                $langs->load("projects");
865
                print '<tr>';
866
                print '<td>' . $langs->trans("Project") . '</td><td colspan="2">';
867
                print img_picto('', 'project', 'class="paddingright"');
868
                print $formproject->select_projects((!getDolGlobalString('PROJECT_CAN_ALWAYS_LINK_TO_ALL_SUPPLIERS') ? $soc->id : -1), $projectid, 'projectid', 0, 0, 1, 0, 1, 0, 0, '', 1, 0, 'maxwidth500');
869
                print ' &nbsp; <a href="' . constant('BASE_URL') . '/projet/card.php?socid=' . $soc->id . '&action=create&status=1&backtopage=' . $_SERVER["PHP_SELF"] . ('?action=create&socid=' . $soc->id) . '"><span class="fa fa-plus-circle valignmiddle" title="' . $langs->trans("AddProject") . '"></span></a>';
870
                print '</td>';
871
                print '</tr>';
872
            }
873
874
            // Date delivery planned
875
            print '<tr><td>' . $langs->trans("DateDeliveryPlanned") . '</td>';
876
            print '<td colspan="3">';
877
            $date_delivery = ($date_delivery ? $date_delivery : $objectsrc->delivery_date); // $date_delivery comes from GETPOST
878
            print $form->selectDate($date_delivery ? $date_delivery : -1, 'date_delivery', 1, 1, 1);
879
            print "</td>\n";
880
            print '</tr>';
881
882
            // Note Public
883
            print '<tr><td>' . $langs->trans("NotePublic") . '</td>';
884
            print '<td colspan="3">';
885
            $doleditor = new DolEditor('note_public', $objectsrc->note_public, '', 60, 'dolibarr_notes', 'In', 0, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PUBLIC') ? 0 : 1, ROWS_3, '90%');
886
            print $doleditor->Create(1);
887
            print "</td></tr>";
888
889
            // Note Private
890
            if ($objectsrc->note_private && !$user->socid) {
891
                print '<tr><td>' . $langs->trans("NotePrivate") . '</td>';
892
                print '<td colspan="3">';
893
                $doleditor = new DolEditor('note_private', $objectsrc->note_private, '', 60, 'dolibarr_notes', 'In', 0, false, !getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE') ? 0 : 1, ROWS_3, '90%');
894
                print $doleditor->Create(1);
895
                print "</td></tr>";
896
            }
897
898
            // Weight
899
            print '<tr><td>';
900
            print $langs->trans("Weight");
901
            print '</td><td colspan="3"><input name="weight" size="4" value="' . GETPOSTINT('weight') . '"> ';
902
            $text = $formproduct->selectMeasuringUnits("weight_units", "weight", GETPOSTINT('weight_units'), 0, 2);
903
            $htmltext = $langs->trans("KeepEmptyForAutoCalculation");
904
            print $form->textwithpicto($text, $htmltext);
905
            print '</td></tr>';
906
            // Dim
907
            print '<tr><td>';
908
            print $langs->trans("Width") . ' x ' . $langs->trans("Height") . ' x ' . $langs->trans("Depth");
909
            print ' </td><td colspan="3"><input name="trueWidth" size="4" value="' . GETPOSTINT('trueWidth') . '">';
910
            print ' x <input name="trueHeight" size="4" value="' . GETPOSTINT('trueHeight') . '">';
911
            print ' x <input name="trueDepth" size="4" value="' . GETPOSTINT('trueDepth') . '">';
912
            print ' ';
913
            $text = $formproduct->selectMeasuringUnits("size_units", "size", GETPOSTINT('size_units'), 0, 2);
914
            $htmltext = $langs->trans("KeepEmptyForAutoCalculation");
915
            print $form->textwithpicto($text, $htmltext);
916
            print '</td></tr>';
917
918
            // Delivery method
919
            print "<tr><td>" . $langs->trans("ReceptionMethod") . "</td>";
920
            print '<td colspan="3">';
921
            $recept->fetch_delivery_methods();
922
            print $form->selectarray("shipping_method_id", $recept->meths, GETPOSTINT('shipping_method_id'), 1, 0, 0, "", 1);
923
            if ($user->admin) {
924
                print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
925
            }
926
            print "</td></tr>\n";
927
928
            // Tracking number
929
            print "<tr><td>" . $langs->trans("TrackingNumber") . "</td>";
930
            print '<td colspan="3">';
931
            print '<input name="tracking_number" size="20" value="' . GETPOST('tracking_number', 'alpha') . '">';
932
            print "</td></tr>\n";
933
934
            // Other attributes
935
            $parameters = array('objectsrc' => $objectsrc, 'colspan' => ' colspan="3"', 'cols' => '3', 'socid' => $socid);
936
            $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $recept, $action); // Note that $action and $objectsrc may have been modified by hook
937
            print $hookmanager->resPrint;
938
939
            // Here $object can be of an object Reception
940
            $extrafields->fetch_name_optionals_label($object->table_element);
941
            if (empty($reshook) && !empty($extrafields->attributes[$object->table_element]['label'])) {
942
                // copy from order
943
                if ($objectsrc->fetch_optionals() > 0) {
944
                    $recept->array_options = array_merge($recept->array_options, $objectsrc->array_options);
945
                }
946
                print $recept->showOptionals($extrafields, 'create', $parameters);
947
            }
948
949
            // Incoterms
950
            if (isModEnabled('incoterm')) {
951
                print '<tr>';
952
                print '<td><label for="incoterm_id">' . $form->textwithpicto($langs->trans("IncotermLabel"), $objectsrc->label_incoterms, 1) . '</label></td>';
953
                print '<td colspan="3" class="maxwidthonsmartphone">';
954
                print $form->select_incoterms((!empty($objectsrc->fk_incoterms) ? $objectsrc->fk_incoterms : ''), (!empty($objectsrc->location_incoterms) ? $objectsrc->location_incoterms : ''));
955
                print '</td></tr>';
956
            }
957
958
            // Document model
959
            $list = ModelePdfReception::liste_modeles($db);
960
961
            if (count($list) > 1) {
962
                print "<tr><td>" . $langs->trans("DefaultModel") . "</td>";
963
                print '<td colspan="3">';
964
                print $form->selectarray('model', $list, $conf->global->RECEPTION_ADDON_PDF);
965
                print "</td></tr>\n";
966
            }
967
968
            print "</table>";
969
970
            print dol_get_fiche_end();
971
972
            // Number of lines show on the reception card
973
            $numAsked = 0;
974
975
            /**
976
             * @var array $suffix2numAsked map HTTP query parameter suffixes (like '1_0') to line indices so that
977
             *                             extrafields from HTTP query can be assigned to the correct dispatch line
978
            */
979
            $suffix2numAsked = array();
980
            $dispatchLines = array();
981
982
            foreach ($_POST as $key => $value) {
983
                // If create form is coming from the button "Create Reception" of previous page
984
985
                // without batch module enabled or product with no lot/serial
986
                $reg = array();
987
                if (preg_match('/^product_([0-9]+)_([0-9]+)$/i', $key, $reg)) {
988
                    $numAsked++;
989
                    $paramSuffix = $reg[1] . '_' . $reg[2];
990
                    $suffix2numAsked[$paramSuffix] = $numAsked;
991
992
                    // $numline=$reg[2] + 1; // line of product
993
                    $numline = $numAsked;
994
995
                    $prod = "product_" . $paramSuffix;
996
                    $qty = "qty_" . $paramSuffix;
997
                    $ent = "entrepot_" . $paramSuffix;
998
                    $pu = "pu_" . $paramSuffix; // This is unit price including discount
999
                    $fk_commandefourndet = "fk_commandefourndet_" . $paramSuffix;
1000
                    $dispatchLines[$numAsked] = array('paramSuffix' => $paramSuffix, 'prod' => GETPOSTINT($prod), 'qty' => price2num(GETPOST($qty), 'MS'), 'ent' => GETPOSTINT($ent), 'pu' => price2num(GETPOST($pu), 'MU'), 'comment' => GETPOST('comment'), 'fk_commandefourndet' => GETPOSTINT($fk_commandefourndet));
1001
                }
1002
1003
                // with batch module enabled and product with lot/serial
1004
                if (preg_match('/^product_batch_([0-9]+)_([0-9]+)$/i', $key, $reg)) {
1005
                    $numAsked++;
1006
                    $paramSuffix = $reg[1] . '_' . $reg[2];
1007
                    $suffix2numAsked[$paramSuffix] = $numAsked;
1008
1009
                    // eat-by date dispatch
1010
                    // $numline=$reg[2] + 1; // line of product
1011
                    $numline = $numAsked;
1012
1013
                    $prod = 'product_batch_' . $paramSuffix;
1014
                    $qty = 'qty_' . $paramSuffix;
1015
                    $ent = 'entrepot_' . $paramSuffix;
1016
                    $pu = 'pu_' . $paramSuffix;
1017
                    $lot = 'lot_number_' . $paramSuffix;
1018
                    $dDLUO = dol_mktime(12, 0, 0, GETPOSTINT('dluo_' . $paramSuffix . 'month'), GETPOSTINT('dluo_' . $paramSuffix . 'day'), GETPOSTINT('dluo_' . $paramSuffix . 'year'));
1019
                    $dDLC = dol_mktime(12, 0, 0, GETPOSTINT('dlc_' . $paramSuffix . 'month'), GETPOSTINT('dlc_' . $paramSuffix . 'day'), GETPOSTINT('dlc_' . $paramSuffix . 'year'));
1020
                    $fk_commandefourndet = 'fk_commandefourndet_' . $paramSuffix;
1021
                    $dispatchLines[$numAsked] = array('paramSuffix' => $paramSuffix, 'prod' => GETPOSTINT($prod), 'qty' => price2num(GETPOST($qty), 'MS'), 'ent' => GETPOSTINT($ent), 'pu' => price2num(GETPOST($pu), 'MU'), 'comment' => GETPOST('comment'), 'fk_commandefourndet' => GETPOSTINT($fk_commandefourndet), 'DLC' => $dDLC, 'DLUO' => $dDLUO, 'lot' => GETPOST($lot));
1022
                }
1023
1024
                // If create form is coming from same page, it means that post was sent but an error occurred
1025
                if (preg_match('/^productl([0-9]+)$/i', $key, $reg)) {
1026
                    $numAsked++;
1027
                    $paramSuffix = $reg[1];
1028
                    $suffix2numAsked[$paramSuffix] = $numAsked;
1029
1030
                    // eat-by date dispatch
1031
                    // $numline=$reg[2] + 1; // line of product
1032
                    $numline = $numAsked;
1033
1034
                    $prod = 'productid' . $paramSuffix;
1035
                    $comment = 'comment' . $paramSuffix;
1036
                    $qty = 'qtyl' . $paramSuffix;
1037
                    $ent = 'entl' . $paramSuffix;
1038
                    $pu = 'pul' . $paramSuffix;
1039
                    $lot = 'batch' . $paramSuffix;
1040
                    $dDLUO = dol_mktime(12, 0, 0, GETPOSTINT('dluo' . $paramSuffix . 'month'), GETPOSTINT('dluo' . $paramSuffix . 'day'), GETPOSTINT('dluo' . $paramSuffix . 'year'));
1041
                    $dDLC = dol_mktime(12, 0, 0, GETPOSTINT('dlc' . $paramSuffix . 'month'), GETPOSTINT('dlc' . $paramSuffix . 'day'), GETPOSTINT('dlc' . $paramSuffix . 'year'));
1042
                    $fk_commandefourndet = 'fk_commandefournisseurdet' . $paramSuffix;
1043
                    $dispatchLines[$numAsked] = array('prod' => GETPOSTINT($prod), 'qty' => price2num(GETPOST($qty), 'MS'), 'ent' => GETPOSTINT($ent), 'pu' => price2num(GETPOST($pu), 'MU'), 'comment' => GETPOST($comment), 'fk_commandefourndet' => GETPOSTINT($fk_commandefourndet), 'DLC' => $dDLC, 'DLUO' => $dDLUO, 'lot' => GETPOSTINT($lot));
1044
                }
1045
            }
1046
1047
            // If extrafield values are passed in the HTTP query, assign them to the correct dispatch line
1048
            // Note that if an extrafield with the same name exists in the origin supplier order line, the value
1049
            // from the HTTP query will be ignored
1050
            foreach ($suffix2numAsked as $suffix => $n) {
1051
                $dispatchLines[$n]['array_options'] = $extrafields->getOptionalsFromPost('receptiondet_batch', '_' . $suffix, '');
1052
            }
1053
1054
            print '<script type="text/javascript">
1055
            jQuery(document).ready(function() {
1056
	            jQuery("#autofill").click(function(event) {
1057
					event.preventDefault();';
1058
            $i = 1;
1059
            while ($i <= $numAsked) {
1060
                print 'jQuery("#qtyl' . $i . '").val(jQuery("#qtyasked' . $i . '").val() - jQuery("#qtydelivered' . $i . '").val());' . "\n";
1061
                $i++;
1062
            }
1063
            print '});
1064
	            jQuery("#autoreset").click(function(event) {
1065
					event.preventDefault();';
1066
            $i = 1;
1067
            while ($i <= $numAsked) {
1068
                print 'jQuery("#qtyl' . $i . '").val(0);' . "\n";
1069
                $i++;
1070
            }
1071
            print '});
1072
        	});
1073
            </script>';
1074
1075
            print '<br>';
1076
1077
            print '<table class="noborder centpercent">';
1078
1079
            // Load receptions already done for same order
1080
            $objectsrc->loadReceptions();
1081
1082
            if ($numAsked) {
1083
                print '<tr class="liste_titre">';
1084
                print '<td>' . $langs->trans("Description") . '</td>';
1085
                print '<td>' . $langs->trans("Comment") . '</td>';
1086
                print '<td class="center">' . $langs->trans("QtyOrdered") . '</td>';
1087
                print '<td class="center">' . $langs->trans("QtyReceived") . '</td>';
1088
                print '<td class="center">' . $langs->trans("QtyToReceive");
1089
                if (getDolGlobalInt('STOCK_CALCULATE_ON_RECEPTION') || getDolGlobalInt('STOCK_CALCULATE_ON_RECEPTION_CLOSE')) {
1090
                    print '<td>' . $langs->trans("BuyingPrice") . '</td>';
1091
                }
1092
                if (!isModEnabled('productbatch')) {
1093
                    print ' <br><center><a href="#" id="autofill"><span class="fas fa-fill pictofixedwidth" style=""></span> ' . $langs->trans("Fill") . '</a>';
1094
                    print ' &nbsp; &nbsp; <a href="#" id="autoreset"><span class="fas fa-eraser pictofixedwidth" style=""></span>' . $langs->trans("Reset") . '</a></center><br>';
1095
                }
1096
                print '</td>';
1097
                if (isModEnabled('stock')) {
1098
                    print '<td class="left">' . $langs->trans("Warehouse") . ' (' . $langs->trans("Stock") . ')</td>';
1099
                }
1100
                if (isModEnabled('productbatch')) {
1101
                    print '<td class="left">' . $langs->trans("batch_number") . '</td>';
1102
                    if (!getDolGlobalInt('PRODUCT_DISABLE_SELLBY')) {
1103
                        print '<td class="left">' . $langs->trans("SellByDate") . '</td>';
1104
                    }
1105
                    if (!getDolGlobalInt('PRODUCT_DISABLE_EATBY')) {
1106
                        print '<td class="left">' . $langs->trans("EatByDate") . '</td>';
1107
                    }
1108
                }
1109
                print "</tr>\n";
1110
            }
1111
1112
            // $objectsrc->lines contains the line of the purchase order
1113
            // $dispatchLines is list of lines with dispatching detail (with product, qty and warehouse). One purchase order line may have n of this dispatch lines.
1114
1115
            $arrayofpurchaselinealreadyoutput = array();
1116
1117
            // $_POST contains fk_commandefourndet_X_Y    where Y is num of product line and X is number of split lines
1118
            $indiceAsked = 1;
1119
            while ($indiceAsked <= $numAsked) { // Loop on $dispatchLines. Warning: $dispatchLines must be sorted by fk_commandefourndet (it is a regroupment key on output)
1120
                $product = new Product($db);
1121
1122
                // We search the purchase order line that is linked to the dispatchLines
1123
                foreach ($objectsrc->lines as $supplierLine) {
1124
                    if ($dispatchLines[$indiceAsked]['fk_commandefourndet'] == $supplierLine->id) {
1125
                        $line = $supplierLine;
1126
                        break;
1127
                    }
1128
                }
1129
1130
                // Show product and description
1131
                $type = $line->product_type ? $line->product_type : $line->fk_product_type;
1132
                // Try to enhance type detection using date_start and date_end for free lines where type
1133
                // was not saved.
1134
                if (!empty($line->date_start)) {
1135
                    $type = 1;
1136
                }
1137
                if (!empty($line->date_end)) {
1138
                    $type = 1;
1139
                }
1140
1141
                print '<!-- line fk_commandefourndet=' . $line->id . ' for product=' . $line->fk_product . ' -->' . "\n";
1142
                print '<tr class="oddeven">' . "\n";
1143
1144
                // Product label
1145
                if ($line->fk_product > 0) {  // If predefined product
1146
                    $product->fetch($line->fk_product);
1147
                    $product->load_stock('warehouseopen'); // Load all $product->stock_warehouse[idwarehouse]->detail_batch
1148
                    //var_dump($product->stock_warehouse[1]);
1149
                    //var_dump($dispatchLines[$indiceAsked]);
1150
1151
                    print '<td>';
1152
                    print '<a name="' . $line->id . '"></a>'; // ancre pour retourner sur la ligne
1153
1154
                    print '<input type="hidden" name="productl' . $indiceAsked . '" value="' . $line->fk_product . '">';
1155
1156
                    if (! array_key_exists($line->id, $arrayofpurchaselinealreadyoutput)) { // Add test to avoid to show qty twice
1157
                        print '<input type="hidden" name="productid' . $indiceAsked . '" value="' . $line->fk_product . '">';
1158
1159
                        // Show product and description
1160
                        $product_static = $product;
1161
1162
                        $text = $product_static->getNomUrl(1);
1163
                        $text .= ' - ' . (!empty($line->label) ? $line->label : $line->product_label);
1164
                        $description = (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE') ? '' : dol_htmlentitiesbr($line->desc));
1165
                        print $form->textwithtooltip($text, $description, 3, '', '', $i);
1166
1167
                        // Show range
1168
                        print_date_range($db->jdate($line->date_start), $db->jdate($line->date_end));
1169
1170
                        // Add description in form
1171
                        if (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE')) {
1172
                            print ($line->desc && $line->desc != $line->product_label) ? '<br>' . dol_htmlentitiesbr($line->desc) : '';
1173
                        }
1174
                    }
1175
                    print '</td>';
1176
                } else {
1177
                    print "<td>";
1178
                    if (! array_key_exists($line->id, $arrayofpurchaselinealreadyoutput)) { // Add test to avoid to show qty twice
1179
                        if ($type == 1) {
1180
                            $text = img_object($langs->trans('Service'), 'service');
1181
                        } else {
1182
                            $text = img_object($langs->trans('Product'), 'product');
1183
                        }
1184
1185
                        if (!empty($line->label)) {
1186
                            $text .= ' <strong>' . $line->label . '</strong>';
1187
                            print $form->textwithtooltip($text, $line->desc, 3, '', '', $i);
1188
                        } else {
1189
                            print $text . ' ' . nl2br($line->desc);
1190
                        }
1191
1192
                        // Show range
1193
                        print_date_range($db->jdate($line->date_start), $db->jdate($line->date_end));
1194
                    }
1195
                    print "</td>\n";
1196
                }
1197
1198
                // Comment
1199
                //$defaultcomment = 'Line create from order line id '.$line->id;
1200
                $defaultcomment = $dispatchLines[$indiceAsked]['comment'];
1201
                print '<td>';
1202
                print '<input type="text" class="maxwidth100" name="comment' . $indiceAsked . '" value="' . $defaultcomment . '">';
1203
                print '</td>';
1204
1205
                // Qty in source purchase order line
1206
                print '<td class="center">';
1207
                if (! array_key_exists($line->id, $arrayofpurchaselinealreadyoutput)) { // Add test to avoid to show qty twice
1208
                    print $line->qty;
1209
                }
1210
                print '<input type="hidden" name="fk_commandefournisseurdet' . $indiceAsked . '" value="' . $line->id . '">';
1211
                print '<input type="hidden" name="pul' . $indiceAsked . '" value="' . $line->pu_ht . '">';
1212
                print '<input name="qtyasked' . $indiceAsked . '" id="qtyasked' . $indiceAsked . '" type="hidden" value="' . $line->qty . '">';
1213
                print '</td>';
1214
                $qtyProdCom = $line->qty;
1215
1216
                // Qty already received
1217
                print '<td class="center">';
1218
                $quantityDelivered = $objectsrc->receptions[$line->id];
1219
                if (! array_key_exists($line->id, $arrayofpurchaselinealreadyoutput)) { // Add test to avoid to show qty twice
1220
                    print $quantityDelivered;
1221
                }
1222
                print '<input name="qtydelivered' . $indiceAsked . '" id="qtydelivered' . $indiceAsked . '" type="hidden" value="' . $quantityDelivered . '">';
1223
                print '</td>';
1224
1225
1226
                if ($line->product_type == 1 && !getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
1227
                    $quantityToBeDelivered = 0;
1228
                } else {
1229
                    $quantityToBeDelivered = $dispatchLines[$indiceAsked]['qty'];
1230
                }
1231
                $warehouse_id = $dispatchLines[$indiceAsked]['ent'];
1232
1233
1234
                $warehouseObject = null;
1235
                if (isModEnabled('stock')) {
1236
                    // If warehouse was already selected or if product is not a predefined, we go into this part with no multiwarehouse selection
1237
                    print '<!-- Case warehouse already known or product not a predefined product -->';
1238
                    if (array_key_exists($dispatchLines[$indiceAsked]['ent'], $product->stock_warehouse)) {
1239
                        $stock = +$product->stock_warehouse[$dispatchLines[$indiceAsked]['ent']]->real; // Convert to number
1240
                    }
1241
                    $deliverableQty = $dispatchLines[$indiceAsked]['qty'];
1242
                    $cost_price = $dispatchLines[$indiceAsked]['pu'];
1243
1244
                    // Quantity to send
1245
                    print '<td class="center">';
1246
                    if ($line->product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
1247
                        if (GETPOSTINT('qtyl' . $indiceAsked)) {
1248
                            $defaultqty = GETPOSTINT('qtyl' . $indiceAsked);
1249
                        }
1250
                        print '<input name="idl' . $indiceAsked . '" type="hidden" value="' . $line->id . '">';
1251
                        print '<input class="right" name="qtyl' . $indiceAsked . '" id="qtyl' . $indiceAsked . '" type="text" size="4" value="' . $deliverableQty . '">';
1252
                    } else {
1253
                        print $langs->trans("NA");
1254
                    }
1255
                    print '</td>';
1256
1257
                    if (getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION') || getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION_CLOSE')) {
1258
                        print '<td>';
1259
                        print '<input class="width75 right" name="cost_price' . $indiceAsked . '" id="cost_price' . $indiceAsked . '" value="' . $cost_price . '">';
1260
                        print '</td>';
1261
                    }
1262
1263
                    // Stock
1264
                    if (isModEnabled('stock')) {
1265
                        print '<td class="left">';
1266
                        if ($line->product_type == Product::TYPE_PRODUCT || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {   // Type of product need stock change ?
1267
                            // Show warehouse combo list
1268
                            $ent = "entl" . $indiceAsked;
1269
                            $idl = "idl" . $indiceAsked;
1270
                            $tmpentrepot_id = is_numeric(GETPOST($ent)) ? GETPOSTINT($ent) : $warehouse_id;
1271
                            if ($line->fk_product > 0) {
1272
                                print '<!-- Show warehouse selection -->';
1273
                                print $formproduct->selectWarehouses($tmpentrepot_id, 'entl' . $indiceAsked, '', 0, 0, $line->fk_product, '', 1);
1274
                            }
1275
                        } else {
1276
                            print $langs->trans("Service");
1277
                        }
1278
                        print '</td>';
1279
                    }
1280
1281
                    if (isModEnabled('productbatch')) {
1282
                        if (!empty($product->status_batch)) {
1283
                            print '<td><input name="batch' . $indiceAsked . '" value="' . $dispatchLines[$indiceAsked]['lot'] . '"></td>';
1284
                            if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
1285
                                print '<td class="nowraponall">';
1286
                                print $form->selectDate($dispatchLines[$indiceAsked]['DLC'], 'dlc' . $indiceAsked, 0, 0, 1, "");
1287
                                print '</td>';
1288
                            }
1289
                            if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
1290
                                print '<td class="nowraponall">';
1291
                                print $form->selectDate($dispatchLines[$indiceAsked]['DLUO'], 'dluo' . $indiceAsked, 0, 0, 1, "");
1292
                                print '</td>';
1293
                            }
1294
                        } else {
1295
                            print '<td colspan="3"></td>';
1296
                        }
1297
                    }
1298
                }
1299
1300
                $arrayofpurchaselinealreadyoutput[$line->id] = $line->id;
1301
1302
                print "</tr>\n";
1303
1304
                // Display lines for extrafields of the Reception line
1305
                // $line is a 'CommandeFournisseurLigne', $dispatchLines contains values of Reception lines so properties of CommandeFournisseurDispatch
1306
                if (!empty($extrafields)) {
1307
                    $colspan = 5;
1308
                    if (isModEnabled('productbatch')) {
1309
                        $colspan += 2;
1310
                        if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
1311
                            $colspan += 1;
1312
                        }
1313
                        if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
1314
                            $colspan += 1;
1315
                        }
1316
                    }
1317
                    $recLine = new CommandeFournisseurDispatch($db);
1318
1319
                    $srcLine = new CommandeFournisseurLigne($db);
1320
                    $srcLine->id = $line->id;
1321
                    $srcLine->fetch_optionals(); // fetch extrafields also available in orderline
1322
1323
                    if (empty($recLine->array_options) && !empty($dispatchLines[$indiceAsked]['array_options'])) {
1324
                        $recLine->array_options = $dispatchLines[$indiceAsked]['array_options'];
1325
                    }
1326
                    $recLine->array_options = array_merge($recLine->array_options, $srcLine->array_options);
1327
1328
                    print $recLine->showOptionals($extrafields, 'edit', array('style' => 'class="oddeven"', 'colspan' => $colspan), $indiceAsked, '', 1);
1329
                }
1330
1331
                $indiceAsked++;
1332
            }
1333
1334
            print "</table>";
1335
1336
            print '<br>';
1337
1338
            print $form->buttonsSaveCancel("Create");
1339
1340
            print '</form>';
1341
1342
            print '<br>';
1343
        } else {
1344
            dol_print_error($db);
1345
        }
1346
    }
1347
} elseif ($id || $ref) {
1348
    /* *************************************************************************** */
1349
    /*                                                                             */
1350
    /* Edit and view mode                                                          */
1351
    /*                                                                             */
1352
    /* *************************************************************************** */
1353
    $lines = $object->lines;
1354
1355
    $num_prod = count($lines);
1356
    $indiceAsked = 0;
1357
1358
    if ($object->id <= 0) {
1359
        print $langs->trans("NoRecordFound");
1360
        ViewMain::llxFooter();
1361
        exit;
1362
    }
1363
1364
    if (!empty($object->origin) && $object->origin_id > 0) {
1365
        $object->origin = 'CommandeFournisseur';
1366
        $typeobject = $object->origin;
1367
        $origin = $object->origin;
1368
        $origin_id = $object->origin_id;
1369
        $object->fetch_origin(); // Load property $object->origin_object, $object->commande, $object->propal, ...
1370
    }
1371
1372
    $soc = new Societe($db);
1373
    $soc->fetch($object->socid);
1374
1375
    $res = $object->fetch_optionals();
1376
1377
    $head = reception_prepare_head($object);
1378
    print dol_get_fiche_head($head, 'reception', $langs->trans("Reception"), -1, 'dollyrevert');
1379
1380
    $formconfirm = '';
1381
1382
    // Confirm deletion
1383
    if ($action == 'delete') {
1384
        $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'] . '?id=' . $object->id, $langs->trans('DeleteReception'), $langs->trans("ConfirmDeleteReception", $object->ref), 'confirm_delete', '', 0, 1);
1385
    }
1386
1387
    // Confirmation validation
1388
    if ($action == 'valid') {
1389
        $objectref = substr($object->ref, 1, 4);
1390
        if ($objectref == 'PROV') {
1391
            $numref = $object->getNextNumRef($soc);
1392
        } else {
1393
            $numref = $object->ref;
1394
        }
1395
1396
        $text = $langs->trans("ConfirmValidateReception", $numref);
1397
        if (getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION')) {
1398
            $text .= '<br>' . img_picto('', 'movement', 'class="pictofixedwidth"') . $langs->trans("StockMovementWillBeRecorded") . '.';
1399
        } elseif (getDolGlobalString('STOCK_CALCULATE_ON_RECEPTION_CLOSE')) {
1400
            $text .= '<br>' . img_picto('', 'movement', 'class="pictofixedwidth"') . $langs->trans("StockMovementNotYetRecorded") . '.';
1401
        }
1402
1403
        if (isModEnabled('notification')) {
1404
            $notify = new Notify($db);
1405
            $text .= '<br>';
1406
            $text .= $notify->confirmMessage('RECEPTION_VALIDATE', $object->socid, $object);
1407
        }
1408
1409
        $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'] . '?id=' . $object->id, $langs->trans('ValidateReception'), $text, 'confirm_valid', '', 0, 1, 250);
1410
    }
1411
1412
    // Confirm cancellation
1413
    if ($action == 'annuler') {
1414
        $formconfirm = $form->formconfirm($_SERVER['PHP_SELF'] . '?id=' . $object->id, $langs->trans('CancelReception'), $langs->trans("ConfirmCancelReception", $object->ref), 'confirm_cancel', '', 0, 1);
1415
    }
1416
1417
    if (!$formconfirm) {
1418
        $parameters = array('formConfirm' => $formconfirm);
1419
        $reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1420
        if (empty($reshook)) {
1421
            $formconfirm .= $hookmanager->resPrint;
1422
        } elseif ($reshook > 0) {
1423
            $formconfirm = $hookmanager->resPrint;
1424
        }
1425
    }
1426
1427
    // Print form confirm
1428
    print $formconfirm;
1429
1430
1431
    // Calculate totalWeight and totalVolume for all products
1432
    // by adding weight and volume of each product line.
1433
    $tmparray = $object->getTotalWeightVolume();
1434
    $totalWeight = $tmparray['weight'];
1435
    $totalVolume = $tmparray['volume'];
1436
1437
1438
    if ($typeobject == 'commande' && $object->origin_object->id && isModEnabled('order')) {
1439
        $objectsrc = new Commande($db);
1440
        $objectsrc->fetch($object->origin_object->id);
1441
    }
1442
    if ($typeobject == 'propal' && $object->origin_object->id && isModEnabled("propal")) {
1443
        $objectsrc = new Propal($db);
1444
        $objectsrc->fetch($object->origin_object->id);
1445
    }
1446
    if ($typeobject == 'CommandeFournisseur' && $object->origin_object->id && isModEnabled("supplier_order")) {
1447
        $objectsrc = new CommandeFournisseur($db);
1448
        $objectsrc->fetch($object->origin_object->id);
1449
    }
1450
    // Reception card
1451
    $linkback = '<a href="' . constant('BASE_URL') . '/reception/list.php?restore_lastsearch_values=1' . (!empty($socid) ? '&socid=' . $socid : '') . '">' . $langs->trans("BackToList") . '</a>';
1452
    $morehtmlref = '<div class="refidno">';
1453
    // Ref customer reception
1454
1455
    $morehtmlref .= $form->editfieldkey("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $user->hasRight('reception', 'creer'), 'string', '', 0, 1);
1456
    $morehtmlref .= $form->editfieldval("RefSupplier", 'ref_supplier', $object->ref_supplier, $object, $user->hasRight('reception', 'creer'), 'string', '', null, null, '', 1);
1457
1458
    // Thirdparty
1459
    $morehtmlref .= '<br>' . $object->thirdparty->getNomUrl(1);
1460
    // Project
1461
    if (isModEnabled('project')) {
1462
        $langs->load("projects");
1463
        $morehtmlref .= '<br>';
1464
        if (0) {    // Do not change on reception
1465
            $morehtmlref .= img_picto($langs->trans("Project"), 'project', 'class="pictofixedwidth"');
1466
            if ($action != 'classify' && $permissiontoadd) {
1467
                $morehtmlref .= '<a class="editfielda" href="' . $_SERVER['PHP_SELF'] . '?action=classify&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->transnoentitiesnoconv('SetProject')) . '</a> ';
1468
            }
1469
            $morehtmlref .= $form->form_project($_SERVER['PHP_SELF'] . '?id=' . $object->id, (!getDolGlobalString('PROJECT_CAN_ALWAYS_LINK_TO_ALL_SUPPLIERS') ? $object->socid : -1), $object->fk_project, ($action == 'classify' ? 'projectid' : 'none'), 0, 0, 0, 1, '', 'maxwidth300');
1470
        } else {
1471
            if (!empty($objectsrc) && !empty($objectsrc->fk_project)) {
1472
                $proj = new Project($db);
1473
                $proj->fetch($objectsrc->fk_project);
1474
                $morehtmlref .= $proj->getNomUrl(1);
1475
                if ($proj->title) {
1476
                    $morehtmlref .= '<span class="opacitymedium"> - ' . dol_escape_htmltag($proj->title) . '</span>';
1477
                }
1478
            }
1479
        }
1480
    }
1481
    $morehtmlref .= '</div>';
1482
1483
    dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
1484
1485
1486
    print '<div class="fichecenter">';
1487
    print '<div class="fichehalfleft">';
1488
    print '<div class="underbanner clearboth"></div>';
1489
1490
    print '<table class="border centpercent tableforfield">';
1491
1492
    // Linked documents
1493
    if ($typeobject == 'commande' && $object->origin_object->id && isModEnabled('order')) {
1494
        print '<tr><td>';
1495
        print $langs->trans("RefOrder") . '</td>';
1496
        print '<td colspan="3">';
1497
        print $objectsrc->getNomUrl(1, 'commande');
1498
        print "</td>\n";
1499
        print '</tr>';
1500
    }
1501
    if ($typeobject == 'propal' && $object->origin_object->id && isModEnabled("propal")) {
1502
        print '<tr><td>';
1503
        print $langs->trans("RefProposal") . '</td>';
1504
        print '<td colspan="3">';
1505
        print $objectsrc->getNomUrl(1, 'reception');
1506
        print "</td>\n";
1507
        print '</tr>';
1508
    }
1509
    if ($typeobject == 'CommandeFournisseur' && $object->origin_object->id && isModEnabled("propal")) {
1510
        print '<tr><td>';
1511
        print $langs->trans("SupplierOrder") . '</td>';
1512
        print '<td colspan="3">';
1513
        print $objectsrc->getNomUrl(1, 'reception');
1514
        print "</td>\n";
1515
        print '</tr>';
1516
    }
1517
1518
    // Date creation
1519
    print '<tr><td class="titlefield">' . $langs->trans("DateCreation") . '</td>';
1520
    print '<td colspan="3">' . dol_print_date($object->date_creation, "dayhour", "tzuserrel") . "</td>\n";
1521
    print '</tr>';
1522
1523
    // Delivery date planned
1524
    print '<tr><td height="10">';
1525
    print '<table class="nobordernopadding" width="100%"><tr><td>';
1526
    print $langs->trans('DateDeliveryPlanned');
1527
    print '</td>';
1528
1529
    if ($action != 'editdate_livraison' && $permissiontoadd) {
1530
        print '<td class="right"><a class="editfielda" href="' . $_SERVER["PHP_SELF"] . '?action=editdate_livraison&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->trans('SetDeliveryDate'), 1) . '</a></td>';
1531
    }
1532
    print '</tr></table>';
1533
    print '</td><td colspan="2">';
1534
    if ($action == 'editdate_livraison') {
1535
        print '<form name="setdate_livraison" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="post">';
1536
        print '<input type="hidden" name="token" value="' . newToken() . '">';
1537
        print '<input type="hidden" name="action" value="setdate_livraison">';
1538
        print $form->selectDate($object->date_delivery ? $object->date_delivery : -1, 'liv_', 1, 1, 0, "setdate_livraison", 1, 0);
1539
        print '<input type="submit" class="button button-edit" value="' . $langs->trans('Modify') . '">';
1540
        print '</form>';
1541
    } else {
1542
        print $object->date_delivery ? dol_print_date($object->date_delivery, 'dayhour') : '&nbsp;';
1543
    }
1544
    print '</td>';
1545
    print '</tr>';
1546
1547
    // Weight
1548
    print '<tr><td>';
1549
    print $form->editfieldkey("Weight", 'trueWeight', $object->trueWeight, $object, $user->hasRight('reception', 'creer'));
1550
    print '</td><td colspan="3">';
1551
1552
    if ($action == 'edittrueWeight') {
1553
        print '<form name="settrueweight" action="' . $_SERVER["PHP_SELF"] . '" method="post">';
1554
        print '<input name="action" value="settrueWeight" type="hidden">';
1555
        print '<input name="id" value="' . $object->id . '" type="hidden">';
1556
        print '<input type="hidden" name="token" value="' . newToken() . '">';
1557
        print '<input id="trueWeight" name="trueWeight" value="' . $object->trueWeight . '" type="text">';
1558
        print $formproduct->selectMeasuringUnits("weight_units", "weight", $object->weight_units, 0, 2);
1559
        print ' <input class="button" name="modify" value="' . $langs->trans("Modify") . '" type="submit">';
1560
        print ' <input class="button button-cancel" name="cancel" value="' . $langs->trans("Cancel") . '" type="submit">';
1561
        print '</form>';
1562
    } else {
1563
        print $object->trueWeight;
1564
        print ($object->trueWeight && $object->weight_units != '') ? ' ' . measuringUnitString(0, "weight", $object->weight_units) : '';
1565
    }
1566
1567
    // Calculated
1568
    if ($totalWeight > 0) {
1569
        if (!empty($object->trueWeight)) {
1570
            print ' (' . $langs->trans("SumOfProductWeights") . ': ';
1571
        }
1572
        print showDimensionInBestUnit($totalWeight, 0, "weight", $langs, isset($conf->global->MAIN_WEIGHT_DEFAULT_ROUND) ? $conf->global->MAIN_WEIGHT_DEFAULT_ROUND : -1, isset($conf->global->MAIN_WEIGHT_DEFAULT_UNIT) ? $conf->global->MAIN_WEIGHT_DEFAULT_UNIT : 'no');
1573
        if (!empty($object->trueWeight)) {
1574
            print ')';
1575
        }
1576
    }
1577
    print '</td></tr>';
1578
1579
    // Width
1580
    print '<tr><td>' . $form->editfieldkey("Width", 'trueWidth', $object->trueWidth, $object, $user->hasRight('reception', 'creer')) . '</td><td colspan="3">';
1581
    print $form->editfieldval("Width", 'trueWidth', $object->trueWidth, $object, $user->hasRight('reception', 'creer'));
1582
    print ($object->trueWidth && $object->width_units != '') ? ' ' . measuringUnitString(0, "size", $object->width_units) : '';
1583
    print '</td></tr>';
1584
1585
    // Height
1586
    print '<tr><td>' . $form->editfieldkey("Height", 'trueHeight', $object->trueHeight, $object, $user->hasRight('reception', 'creer')) . '</td><td colspan="3">';
1587
    if ($action == 'edittrueHeight') {
1588
        print '<form name="settrueHeight" action="' . $_SERVER["PHP_SELF"] . '" method="post">';
1589
        print '<input name="action" value="settrueHeight" type="hidden">';
1590
        print '<input name="id" value="' . $object->id . '" type="hidden">';
1591
        print '<input type="hidden" name="token" value="' . newToken() . '">';
1592
        print '<input id="trueHeight" name="trueHeight" value="' . $object->trueHeight . '" type="text">';
1593
        print $formproduct->selectMeasuringUnits("size_units", "size", $object->size_units, 0, 2);
1594
        print ' <input class="button" name="modify" value="' . $langs->trans("Modify") . '" type="submit">';
1595
        print ' <input class="button button-cancel" name="cancel" value="' . $langs->trans("Cancel") . '" type="submit">';
1596
        print '</form>';
1597
    } else {
1598
        print $object->trueHeight;
1599
        print ($object->trueHeight && $object->height_units != '') ? ' ' . measuringUnitString(0, "size", $object->height_units) : '';
1600
    }
1601
1602
    print '</td></tr>';
1603
1604
    // Depth
1605
    print '<tr><td>' . $form->editfieldkey("Depth", 'trueDepth', $object->trueDepth, $object, $user->hasRight('reception', 'creer')) . '</td><td colspan="3">';
1606
    print $form->editfieldval("Depth", 'trueDepth', $object->trueDepth, $object, $user->hasRight('reception', 'creer'));
1607
    print ($object->trueDepth && $object->depth_units != '') ? ' ' . measuringUnitString(0, "size", $object->depth_units) : '';
1608
    print '</td></tr>';
1609
1610
    // Volume
1611
    print '<tr><td>';
1612
    print $langs->trans("Volume");
1613
    print '</td>';
1614
    print '<td colspan="3">';
1615
    $calculatedVolume = 0;
1616
    $volumeUnit = 0;
1617
    if ($object->trueWidth && $object->trueHeight && $object->trueDepth) {
1618
        $calculatedVolume = ($object->trueWidth * $object->trueHeight * $object->trueDepth);
1619
        $volumeUnit = $object->size_units * 3;
1620
    }
1621
    // If reception volume not defined we use sum of products
1622
    if ($calculatedVolume > 0) {
1623
        if ($volumeUnit < 50) {
1624
            print showDimensionInBestUnit($calculatedVolume, $volumeUnit, "volume", $langs, isset($conf->global->MAIN_VOLUME_DEFAULT_ROUND) ? $conf->global->MAIN_VOLUME_DEFAULT_ROUND : -1, isset($conf->global->MAIN_VOLUME_DEFAULT_UNIT) ? $conf->global->MAIN_VOLUME_DEFAULT_UNIT : 'no');
1625
        } else {
1626
            print $calculatedVolume . ' ' . measuringUnitString(0, "volume", $volumeUnit);
1627
        }
1628
    }
1629
    if ($totalVolume > 0) {
1630
        if ($calculatedVolume) {
1631
            print ' (' . $langs->trans("SumOfProductVolumes") . ': ';
1632
        }
1633
        print showDimensionInBestUnit($totalVolume, 0, "volume", $langs, isset($conf->global->MAIN_VOLUME_DEFAULT_ROUND) ? $conf->global->MAIN_VOLUME_DEFAULT_ROUND : -1, isset($conf->global->MAIN_VOLUME_DEFAULT_UNIT) ? $conf->global->MAIN_VOLUME_DEFAULT_UNIT : 'no');
1634
        //if (empty($calculatedVolume)) print ' ('.$langs->trans("Calculated").')';
1635
        if ($calculatedVolume) {
1636
            print ')';
1637
        }
1638
    }
1639
    print "</td>\n";
1640
    print '</tr>';
1641
1642
    // Other attributes
1643
    $cols = 2;
1644
1645
    include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php';
1646
1647
    print '</table>';
1648
1649
    print '</div>';
1650
    print '<div class="fichehalfright">';
1651
    print '<div class="underbanner clearboth"></div>';
1652
1653
    print '<table class="border centpercent tableforfield">';
1654
1655
    // Reception method
1656
    print '<tr><td height="10">';
1657
    print '<table class="nobordernopadding centpercent"><tr><td>';
1658
    print $langs->trans('ReceptionMethod');
1659
    print '</td>';
1660
1661
    if ($action != 'editshipping_method_id' && $permissiontoadd) {
1662
        print '<td class="right"><a class="editfielda" href="' . $_SERVER["PHP_SELF"] . '?action=editshipping_method_id&token=' . newToken() . '&id=' . $object->id . '">' . img_edit($langs->trans('SetReceptionMethod'), 1) . '</a></td>';
1663
    }
1664
    print '</tr></table>';
1665
    print '</td><td colspan="2">';
1666
    if ($action == 'editshipping_method_id') {
1667
        print '<form name="setshipping_method_id" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '" method="post">';
1668
        print '<input type="hidden" name="token" value="' . newToken() . '">';
1669
        print '<input type="hidden" name="action" value="setshipping_method_id">';
1670
        $object->fetch_delivery_methods();
1671
        print $form->selectarray("shipping_method_id", $object->meths, $object->shipping_method_id, 1, 0, 0, "", 1);
1672
        if ($user->admin) {
1673
            print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1674
        }
1675
        print '<input type="submit" class="button button-edit" value="' . $langs->trans('Modify') . '">';
1676
        print '</form>';
1677
    } else {
1678
        if ($object->shipping_method_id > 0) {
1679
            // Get code using getLabelFromKey
1680
            $code = $langs->getLabelFromKey($db, $object->shipping_method_id, 'c_shipment_mode', 'rowid', 'code');
1681
            print $langs->trans("SendingMethod" . strtoupper($code));
1682
        }
1683
    }
1684
    print '</td>';
1685
    print '</tr>';
1686
1687
    // Tracking Number
1688
    print '<tr><td class="titlefield">' . $form->editfieldkey("TrackingNumber", 'tracking_number', $object->tracking_number, $object, $user->hasRight('reception', 'creer')) . '</td><td colspan="3">';
1689
    print $form->editfieldval("TrackingNumber", 'tracking_number', $object->tracking_url, $object, $user->hasRight('reception', 'creer'), 'safehtmlstring', $object->tracking_number);
1690
    print '</td></tr>';
1691
1692
    // Incoterms
1693
    if (isModEnabled('incoterm')) {
1694
        print '<tr><td>';
1695
        print '<table width="100%" class="nobordernopadding"><tr><td>';
1696
        print $langs->trans('IncotermLabel');
1697
        print '<td><td class="right">';
1698
        if ($user->hasRight('reception', 'creer')) {
1699
            print '<a class="editfielda" href="' . constant('BASE_URL') . '/reception/card.php?id=' . $object->id . '&action=editincoterm&token=' . newToken() . '">' . img_edit() . '</a>';
1700
        } else {
1701
            print '&nbsp;';
1702
        }
1703
        print '</td></tr></table>';
1704
        print '</td>';
1705
        print '<td colspan="3">';
1706
        if ($action != 'editincoterm') {
1707
            print $form->textwithpicto($object->display_incoterms(), $object->label_incoterms, 1);
1708
        } else {
1709
            print $form->select_incoterms((!empty($object->fk_incoterms) ? $object->fk_incoterms : ''), (!empty($object->location_incoterms) ? $object->location_incoterms : ''), $_SERVER['PHP_SELF'] . '?id=' . $object->id);
1710
        }
1711
        print '</td></tr>';
1712
    }
1713
1714
    print "</table>";
1715
1716
    print '</div>';
1717
    print '</div>';
1718
1719
    print '<div class="clearboth"></div>';
1720
1721
1722
    // Lines of products
1723
    if ($action == 'editline') {
1724
        print '<form name="updateline" id="updateline" action="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&amp;lineid=' . $line_id . '" method="POST">
1725
		<input type="hidden" name="token" value="' . newToken() . '">
1726
		<input type="hidden" name="action" value="updateline">
1727
		<input type="hidden" name="mode" value="">
1728
		<input type="hidden" name="id" value="' . $object->id . '">';
1729
    }
1730
    print '<br><br>';
1731
1732
    print '<div class="div-table-responsive-no-min">';
1733
    print '<table id="tablelines" class="noborder centpercent">';
1734
    print '<thead>';
1735
    print '<tr class="liste_titre">';
1736
    // #
1737
    if (getDolGlobalString('MAIN_VIEW_LINE_NUMBER')) {
1738
        print '<td width="5" class="center">&nbsp;</td>';
1739
    }
1740
    // Product/Service
1741
    print '<td>' . $langs->trans("Products") . '</td>';
1742
    // Comment
1743
    print '<td>' . $langs->trans("Comment") . '</td>';
1744
    // Qty
1745
    print '<td class="center">' . $langs->trans("QtyOrdered") . '</td>';
1746
    if ($origin && $origin_id > 0) {
1747
        print '<td class="center">' . $langs->trans("QtyInOtherReceptions") . '</td>';
1748
    }
1749
    if ($action == 'editline') {
1750
        $editColspan = 3;
1751
        if (!isModEnabled('stock')) {
1752
            $editColspan--;
1753
        }
1754
        if (empty($conf->productbatch->enabled)) {
1755
            $editColspan--;
1756
        }
1757
        print '<td class="center" colspan="' . $editColspan . '">';
1758
        if ($object->statut <= 1) {
1759
            print $langs->trans("QtyToReceive") . ' - ';
1760
        } else {
1761
            print $langs->trans("QtyReceived") . ' - ';
1762
        }
1763
        if (isModEnabled('stock')) {
1764
            print $langs->trans("WarehouseTarget") . ' - ';
1765
        }
1766
        if (isModEnabled('productbatch')) {
1767
            print $langs->trans("Batch");
1768
        }
1769
        print '</td>';
1770
    } else {
1771
        $statusreceived = $object::STATUS_CLOSED;
1772
        if (getDolGlobalInt("STOCK_CALCULATE_ON_RECEPTION")) {
1773
            $statusreceived = $object::STATUS_VALIDATED;
1774
        }
1775
        if (getDolGlobalInt("STOCK_CALCULATE_ON_RECEPTION_CLOSE")) {
1776
            $statusreceived = $object::STATUS_CLOSED;
1777
        }
1778
        if ($object->statut < $statusreceived) {
1779
            print '<td class="center">' . $langs->trans("QtyToReceive") . '</td>';
1780
        } else {
1781
            print '<td class="center">' . $langs->trans("QtyReceived") . '</td>';
1782
        }
1783
        if (isModEnabled('stock')) {
1784
            print '<td class="left">' . $langs->trans("WarehouseTarget") . '</td>';
1785
        }
1786
1787
        if (isModEnabled('productbatch')) {
1788
            print '<td class="left">' . $langs->trans("Batch") . '</td>';
1789
        }
1790
    }
1791
    print '<td class="center">' . $langs->trans("CalculatedWeight") . '</td>';
1792
    print '<td class="center">' . $langs->trans("CalculatedVolume") . '</td>';
1793
    //print '<td class="center">'.$langs->trans("Size").'</td>';
1794
    if ($object->statut == 0) {
1795
        print '<td class="linecoledit"></td>';
1796
        print '<td class="linecoldelete" width="10"></td>';
1797
    }
1798
    print "</tr>\n";
1799
    print '</thead>';
1800
1801
    $var = false;
1802
1803
    if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
1804
        $object->fetch_thirdparty();
1805
        $outputlangs = $langs;
1806
        $newlang = '';
1807
        if (empty($newlang) && GETPOST('lang_id', 'aZ09')) {
1808
            $newlang = GETPOST('lang_id', 'aZ09');
1809
        }
1810
        if (empty($newlang)) {
1811
            $newlang = $object->thirdparty->default_lang;
1812
        }
1813
        if (!empty($newlang)) {
1814
            $outputlangs = new Translate("", $conf);
1815
            $outputlangs->setDefaultLang($newlang);
1816
        }
1817
    }
1818
1819
    // Get list of products already sent for same source object into $alreadysent
1820
    $alreadysent = array();
1821
1822
    $origin = 'commande_fournisseur';
1823
1824
    if ($origin && $origin_id > 0) {
1825
        $sql = "SELECT obj.rowid, obj.fk_product, obj.label, obj.description, obj.product_type as fk_product_type, obj.qty as qty_asked, obj.date_start, obj.date_end";
1826
        $sql .= ", ed.rowid as receptionline_id, ed.qty, ed.fk_reception as reception_id,  ed.fk_entrepot";
1827
        $sql .= ", e.rowid as reception_id, e.ref as reception_ref, e.date_creation, e.date_valid, e.date_delivery, e.date_reception";
1828
        //if (getDolGlobalInt('MAIN_SUBMODULE_DELIVERY')) $sql .= ", l.rowid as livraison_id, l.ref as livraison_ref, l.date_delivery, ld.qty as qty_received";
1829
        $sql .= ', p.label as product_label, p.ref, p.fk_product_type, p.rowid as prodid, p.tobatch as product_tobatch';
1830
        $sql .= ', p.description as product_desc';
1831
        $sql .= " FROM " . MAIN_DB_PREFIX . "receptiondet_batch as ed";
1832
        $sql .= ", " . MAIN_DB_PREFIX . "reception as e";
1833
        $sql .= ", " . MAIN_DB_PREFIX . $origin . "det as obj";
1834
        //if (getDolGlobalInt('MAIN_SUBMODULE_DELIVERY')) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."delivery as l ON l.fk_reception = e.rowid LEFT JOIN ".MAIN_DB_PREFIX."deliverydet as ld ON ld.fk_delivery = l.rowid  AND obj.rowid = ld.fk_origin_line";
1835
        $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "product as p ON obj.fk_product = p.rowid";
1836
        $sql .= " WHERE e.entity IN (" . getEntity('reception') . ")";
1837
        $sql .= " AND obj.fk_commande = " . ((int) $origin_id);
1838
        $sql .= " AND obj.rowid = ed.fk_elementdet";
1839
        $sql .= " AND ed.fk_reception = e.rowid";
1840
        $sql .= " AND ed.fk_reception !=" . ((int) $object->id);
1841
        //if ($filter) $sql.= $filter;
1842
        $sql .= " ORDER BY obj.fk_product";
1843
1844
        dol_syslog("get list of reception lines", LOG_DEBUG);
1845
        $resql = $db->query($sql);
1846
        if ($resql) {
1847
            $num = $db->num_rows($resql);
1848
            $i = 0;
1849
1850
            while ($i < $num) {
1851
                $obj = $db->fetch_object($resql);
1852
                if ($obj) {
1853
                    // $obj->rowid is rowid in $origin."det" table
1854
                    $alreadysent[$obj->rowid][$obj->receptionline_id] = array('reception_ref' => $obj->reception_ref, 'reception_id' => $obj->reception_id, 'warehouse' => $obj->fk_entrepot, 'qty' => $obj->qty, 'date_valid' => $obj->date_valid, 'date_delivery' => $obj->date_delivery);
1855
                }
1856
                $i++;
1857
            }
1858
        }
1859
        //var_dump($alreadysent);
1860
    }
1861
1862
    $arrayofpurchaselinealreadyoutput = array();
1863
1864
    // Loop on each product to send/sent. Warning: $lines must be sorted by ->fk_commandefourndet (it is a regroupment key on output)
1865
    print '<tbody>';
1866
    for ($i = 0; $i < $num_prod; $i++) {
1867
        print '<!-- origin line id = ' . (!empty($lines[$i]->origin_line_id) ? $lines[$i]->origin_line_id : 0) . ' -->'; // id of order line
1868
        print '<tr class="oddeven" id="row-' . $lines[$i]->id . '" data-id="' . $lines[$i]->id . '" data-element="' . $lines[$i]->element . '">';
1869
1870
        // #
1871
        if (getDolGlobalString('MAIN_VIEW_LINE_NUMBER')) {
1872
            print '<td class="center">' . ($i + 1) . '</td>';
1873
        }
1874
1875
        // Predefined product or service
1876
        if ($lines[$i]->fk_product > 0) {
1877
            // Define output language
1878
            if (getDolGlobalInt('MAIN_MULTILANGS') && getDolGlobalString('PRODUIT_TEXTS_IN_THIRDPARTY_LANGUAGE')) {
1879
                $prod = new Product($db);
1880
                $prod->fetch($lines[$i]->fk_product);
1881
                $label = (!empty($prod->multilangs[$outputlangs->defaultlang]["label"])) ? $prod->multilangs[$outputlangs->defaultlang]["label"] : $lines[$i]->product->label;
1882
            } else {
1883
                $label = (!empty($lines[$i]->product->label) ? $lines[$i]->product->label : $lines[$i]->product->product_label);
1884
            }
1885
1886
            print '<td class="linecoldescription">';
1887
            if (!array_key_exists($lines[$i]->fk_commandefourndet, $arrayofpurchaselinealreadyoutput)) {
1888
                $text = $lines[$i]->product->getNomUrl(1);
1889
                $text .= ' - ' . $label;
1890
                $description = (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE') ? '' : dol_htmlentitiesbr($lines[$i]->product->description));
1891
                print $form->textwithtooltip($text, $description, 3, '', '', $i);
1892
                print_date_range(!empty($lines[$i]->date_start) ? $lines[$i]->date_start : 0, !empty($lines[$i]->date_end) ? $lines[$i]->date_end : 0);
1893
                if (getDolGlobalInt('PRODUIT_DESC_IN_FORM_ACCORDING_TO_DEVICE')) {
1894
                    print (!empty($lines[$i]->product->description) && $lines[$i]->description != $lines[$i]->product->description) ? '<br>' . dol_htmlentitiesbr($lines[$i]->description) : '';
1895
                }
1896
            }
1897
            print "</td>\n";
1898
        } else {
1899
            print '<td class="linecoldescription">';
1900
            if (!array_key_exists($lines[$i]->fk_commandefourndet, $arrayofpurchaselinealreadyoutput)) {
1901
                if ($lines[$i]->product_type == Product::TYPE_SERVICE) {
1902
                    $text = img_object($langs->trans('Service'), 'service');
1903
                } else {
1904
                    $text = img_object($langs->trans('Product'), 'product');
1905
                }
1906
1907
                if (!empty($lines[$i]->label)) {
1908
                    $text .= ' <strong>' . $lines[$i]->label . '</strong>';
1909
                    print $form->textwithtooltip($text, $lines[$i]->description, 3, '', '', $i);
1910
                } else {
1911
                    print $text . ' ' . nl2br($lines[$i]->description);
1912
                }
1913
1914
                print_date_range($lines[$i]->date_start, $lines[$i]->date_end);
1915
            }
1916
            print "</td>\n";
1917
        }
1918
1919
        if ($action == 'editline' && $lines[$i]->id == $line_id) {
1920
            print '<td><input name="comment' . $line_id . '" id="comment' . $line_id . '" value="' . dol_escape_htmltag($lines[$i]->comment) . '"></td>';
1921
        } else {
1922
            print '<td style="white-space: pre-wrap; max-width: 200px;">' . dol_escape_htmltag($lines[$i]->comment) . '</td>';
1923
        }
1924
1925
1926
        // Qty ordered
1927
        print '<td class="center linecolqty">';
1928
        if (!array_key_exists($lines[$i]->fk_commandefourndet, $arrayofpurchaselinealreadyoutput)) {
1929
            print $lines[$i]->qty_asked;
1930
        }
1931
        print '</td>';
1932
1933
        // Qty in other receptions (with reception and warehouse used)
1934
        if ($origin && $origin_id > 0) {
1935
            print '<td class="center nowrap linecolqtyinotherreceptions">';
1936
            $htmltooltip = '';
1937
            $qtyalreadyreceived = 0;
1938
            if (!array_key_exists($lines[$i]->fk_commandefourndet, $arrayofpurchaselinealreadyoutput)) {
1939
                foreach ($alreadysent as $key => $val) {
1940
                    if ($lines[$i]->fk_commandefourndet == $key) {
1941
                        $j = 0;
1942
                        foreach ($val as $receptionline_id => $receptionline_var) {
1943
                            if ($receptionline_var['reception_id'] == $lines[$i]->fk_reception) {
1944
                                continue; // We want to show only "other receptions"
1945
                            }
1946
1947
                            $j++;
1948
                            if ($j > 1) {
1949
                                $htmltooltip .= '<br>';
1950
                            }
1951
                            $reception_static->fetch($receptionline_var['reception_id']);
1952
                            $htmltooltip .= $reception_static->getNomUrl(1, 0, 0, 0, 1);
1953
                            $htmltooltip .= ' - ' . $receptionline_var['qty'];
1954
1955
                            $htmltext = $langs->trans("DateValidation") . ' : ' . (empty($receptionline_var['date_valid']) ? $langs->trans("Draft") : dol_print_date($receptionline_var['date_valid'], 'dayhour'));
1956
                            if (isModEnabled('stock') && $receptionline_var['warehouse'] > 0) {
1957
                                $warehousestatic->fetch($receptionline_var['warehouse']);
1958
                                $htmltext .= '<br>' . $langs->trans("From") . ' : ' . $warehousestatic->getNomUrl(1, '', 0, 1);
1959
                            }
1960
                            $htmltooltip .= ' ' . $form->textwithpicto('', $htmltext, 1);
1961
1962
                            $qtyalreadyreceived += $receptionline_var['qty'];
1963
                        }
1964
                        if ($j) {
1965
                            $htmltooltip = $langs->trans("QtyInOtherReceptions") . '...<br><br>' . $htmltooltip . '<br><input type="submit" name="dummyhiddenbuttontogetfocus" style="display:none" autofocus>';
1966
                        }
1967
                    }
1968
                }
1969
            }
1970
            print $form->textwithpicto($qtyalreadyreceived, $htmltooltip, 1, 'info', '', 0, 3, 'tooltip' . $lines[$i]->id);
1971
            print '</td>';
1972
        }
1973
1974
        if ($action == 'editline' && $lines[$i]->id == $line_id) {
1975
            // edit mode
1976
            print '<td colspan="' . $editColspan . '" class="center"><table class="nobordernopadding">';
1977
            if (isModEnabled('stock')) {
1978
                if ($lines[$i]->fk_product > 0) {
1979
                    print '<!-- case edit 1 -->';
1980
                    print '<tr>';
1981
                    // Qty to receive or received
1982
                    print '<td><input name="qtyl' . $line_id . '" id="qtyl' . $line_id . '" type="text" size="4" value="' . $lines[$i]->qty . '"></td>';
1983
                    // Warehouse source
1984
                    print '<td>' . $formproduct->selectWarehouses($lines[$i]->fk_entrepot, 'entl' . $line_id, '', 1, 0, $lines[$i]->fk_product, '', 1) . '</td>';
1985
                    // Batch number management
1986
                    if ($conf->productbatch->enabled && !empty($lines[$i]->product->status_batch)) {
1987
                        print '<td class="nowraponall left"><input name="batch' . $line_id . '" id="batch' . $line_id . '" type="text" value="' . $lines[$i]->batch . '"><br>';
1988
                        if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
1989
                            print $langs->trans('SellByDate') . ' : ';
1990
                            print $form->selectDate($lines[$i]->sellby, 'dlc' . $line_id, 0, 0, 1, "") . '</br>';
1991
                        }
1992
                        if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
1993
                            print $langs->trans('EatByDate') . ' : ';
1994
                            print $form->selectDate($lines[$i]->eatby, 'dluo' . $line_id, 0, 0, 1, "");
1995
                        }
1996
                        print '</td>';
1997
                    }
1998
                    print '</tr>';
1999
                } else {
2000
                    print '<!-- case edit 2 -->';
2001
                    print '<tr>';
2002
                    // Qty to receive or received
2003
                    print '<td><input name="qtyl' . $line_id . '" id="qtyl' . $line_id . '" type="text" size="4" value="' . $lines[$i]->qty . '"></td>';
2004
                    // Warehouse source
2005
                    print '<td></td>';
2006
                    // Batch number management
2007
                    print '<td></td>';
2008
                    print '</tr>';
2009
                }
2010
            }
2011
            print '</table></td>';
2012
        } else {
2013
            // Qty to receive or received
2014
            print '<td class="center linecolqtytoreceive">' . $lines[$i]->qty . '</td>';
2015
2016
            // Warehouse source
2017
            if (isModEnabled('stock')) {
2018
                if ($lines[$i]->fk_entrepot > 0) {
2019
                    $entrepot = new Entrepot($db);
2020
                    $entrepot->fetch($lines[$i]->fk_entrepot);
2021
2022
                    print '<td class="left tdoverflowmax150" title="' . dol_escape_htmltag($entrepot->label) . '">';
2023
                    print $entrepot->getNomUrl(1);
2024
                    print '</td>';
2025
                } else {
2026
                    print '<td></td>';
2027
                }
2028
            }
2029
2030
            // Batch number management
2031
            if (isModEnabled('productbatch')) {
2032
                if (isset($lines[$i]->batch)) {
2033
                    print '<!-- Detail of lot -->';
2034
                    print '<td class="linecolbatch nowrap">';
2035
                    $detail = $langs->trans("NA");
2036
                    if ($lines[$i]->product->status_batch > 0 && $lines[$i]->fk_product > 0) {
2037
                        $productlot = new Productlot($db);
2038
                        $reslot = $productlot->fetch(0, $lines[$i]->fk_product, $lines[$i]->batch);
2039
                        if ($reslot > 0) {
2040
                            $detail = $productlot->getNomUrl(1);
2041
                        } else {
2042
                            // lot is not created and info is only in reception lines
2043
                            $batchinfo = $langs->trans("Batch") . ': ' . $lines[$i]->batch;
2044
                            if (!getDolGlobalString('PRODUCT_DISABLE_SELLBY')) {
2045
                                $batchinfo .= ' - ' . $langs->trans("SellByDate") . ': ' . dol_print_date($lines[$i]->sellby, "day");
2046
                            }
2047
                            if (!getDolGlobalString('PRODUCT_DISABLE_EATBY')) {
2048
                                $batchinfo .= ' - ' . $langs->trans("EatByDate") . ': ' . dol_print_date($lines[$i]->eatby, "day");
2049
                            }
2050
                            $detail = $form->textwithtooltip(img_picto('', 'object_barcode') . ' ' . $langs->trans("DetailBatchNumber"), $batchinfo);
2051
                        }
2052
                    }
2053
                    print $detail . '</td>';
2054
                } else {
2055
                    print '<td></td>';
2056
                }
2057
            }
2058
        }
2059
2060
        // Weight
2061
        print '<td class="center linecolweight">';
2062
        if (!empty($lines[$i]->fk_product_type) && $lines[$i]->fk_product_type == Product::TYPE_PRODUCT) {
2063
            print $lines[$i]->product->weight * $lines[$i]->qty . ' ' . measuringUnitString(0, "weight", $lines[$i]->product->weight_units);
2064
        } else {
2065
            print '&nbsp;';
2066
        }
2067
        print '</td>';
2068
2069
        // Volume
2070
        print '<td class="center linecolvolume">';
2071
        if (!empty($lines[$i]->fk_product_type) && $lines[$i]->fk_product_type == Product::TYPE_PRODUCT) {
2072
            print $lines[$i]->product->volume * $lines[$i]->qty . ' ' . measuringUnitString(0, "volume", $lines[$i]->product->volume_units);
2073
        } else {
2074
            print '&nbsp;';
2075
        }
2076
        print '</td>';
2077
2078
2079
        if ($action == 'editline' && $lines[$i]->id == $line_id) {
2080
            print '<td class="center valignmiddle" colspan="2">';
2081
            print '<input type="submit" class="button small button-save" id="savelinebutton marginbottomonly" name="save" value="' . $langs->trans("Save") . '"><br>';
2082
            print '<input type="submit" class="button small button-cancel" id="cancellinebutton" name="cancel" value="' . $langs->trans("Cancel") . '"><br>';
2083
            print '</td>';
2084
        } elseif ($object->statut == Reception::STATUS_DRAFT) {
2085
            // edit-delete buttons
2086
            print '<td class="linecoledit center">';
2087
            print '<a class="editfielda" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=editline&token=' . newToken() . '&lineid=' . $lines[$i]->id . '">' . img_edit() . '</a>';
2088
            print '</td>';
2089
            print '<td class="linecoldelete" width="10">';
2090
            print '<a class="reposition" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=deleteline&token=' . newToken() . '&lineid=' . $lines[$i]->id . '">' . img_delete() . '</a>';
2091
            print '</td>';
2092
2093
            // Display lines extrafields
2094
            if (!empty($rowExtrafieldsStart)) {
2095
                print $rowExtrafieldsStart;
2096
                print $rowExtrafieldsView;
2097
                print $rowEnd;
2098
            }
2099
        }
2100
        print "</tr>";
2101
2102
        $arrayofpurchaselinealreadyoutput[$lines[$i]->fk_commandefourndet] = $lines[$i]->fk_commandefourndet;
2103
2104
        // Display lines extrafields
2105
        $extralabelslines = $extrafields->attributes[$lines[$i]->table_element];
2106
        if (!empty($extralabelslines) && is_array($extralabelslines) && count($extralabelslines) > 0) {
2107
            $colspan = 8;
2108
            if (isModEnabled('stock')) {
2109
                $colspan++;
2110
            }
2111
            if (isModEnabled('productbatch')) {
2112
                $colspan++;
2113
            }
2114
2115
            $line = new CommandeFournisseurDispatch($db);
2116
            $line->id = $lines[$i]->id;
2117
            $line->fetch_optionals();
2118
2119
            if ($action == 'editline' && $lines[$i]->id == $line_id) {
2120
                print $line->showOptionals($extrafields, 'edit', array('colspan' => $colspan), '');
2121
            } else {
2122
                print $line->showOptionals($extrafields, 'view', array('colspan' => $colspan), '');
2123
            }
2124
        }
2125
    }
2126
    print '</tbody>';
2127
2128
    // TODO Show also lines ordered but not delivered
2129
2130
    print "</table>\n";
2131
    print '</div>';
2132
2133
2134
    print dol_get_fiche_end();
2135
2136
2137
    $object->fetchObjectLinked($object->id, $object->element);
2138
2139
2140
    /*
2141
     *    Boutons actions
2142
     */
2143
2144
    if (($user->socid == 0) && ($action != 'presend')) {
2145
        print '<div class="tabsAction">';
2146
2147
        $parameters = array();
2148
        $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2149
        if (empty($reshook)) {
2150
            if ($object->statut == Reception::STATUS_DRAFT && $num_prod > 0) {
2151
                if (
2152
                    (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('reception', 'creer'))
2153
                    || (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && $user->hasRight('reception', 'reception_advance', 'validate'))
2154
                ) {
2155
                    print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=valid&token=' . newToken() . '">' . $langs->trans("Validate") . '</a>';
2156
                } else {
2157
                    print '<a class="butActionRefused" href="#" title="' . $langs->trans("NotAllowed") . '">' . $langs->trans("Validate") . '</a>';
2158
                }
2159
            }
2160
            // Back to draft
2161
            if ($object->statut == Reception::STATUS_VALIDATED && $user->hasRight('reception', 'creer')) {
2162
                print '<div class="inline-block divButAction"><a class="butAction" href="card.php?id=' . $object->id . '&action=modif&token=' . newToken() . '">' . $langs->trans('SetToDraft') . '</a></div>';
2163
            }
2164
2165
            // TODO add alternative status
2166
            // 0=draft, 1=validated, 2=billed, we miss a status "delivered" (only available on order)
2167
            if ($object->statut == Reception::STATUS_CLOSED && $user->hasRight('reception', 'creer')) {
2168
                print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=reopen&token=' . newToken() . '">' . $langs->trans("ReOpen") . '</a>';
2169
            }
2170
2171
            // Send
2172
            if (empty($user->socid)) {
2173
                if ($object->statut > 0) {
2174
                    if (!getDolGlobalString('MAIN_USE_ADVANCED_PERMS') || $user->hasRight('reception', 'reception_advance', 'send')) {
2175
                        print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=presend&mode=init#formmailbeforetitle">' . $langs->trans('SendByMail') . '</a>';
2176
                    } else {
2177
                        print '<a class="butActionRefused" href="#">' . $langs->trans('SendByMail') . '</a>';
2178
                    }
2179
                }
2180
            }
2181
2182
            // Create bill
2183
            if (isModEnabled("supplier_invoice") && ($object->statut == Reception::STATUS_VALIDATED || $object->statut == Reception::STATUS_CLOSED)) {
2184
                if ($user->hasRight('fournisseur', 'facture', 'creer') || $user->hasRight('supplier_invoice', 'creer')) {
2185
                    if (getDolGlobalString('WORKFLOW_BILL_ON_RECEPTION') !== '0') {
2186
                        print '<a class="butAction" href="' . constant('BASE_URL') . '/fourn/facture/card.php?action=create&amp;origin=' . $object->element . '&amp;originid=' . $object->id . '&amp;socid=' . $object->socid . '">' . $langs->trans("CreateBill") . '</a>';
2187
                    }
2188
                }
2189
            }
2190
2191
2192
            // Set Billed and Closed
2193
            if ($object->statut == Reception::STATUS_VALIDATED) {
2194
                if ($user->hasRight('reception', 'creer') && $object->statut > 0) {
2195
                    if (!$object->billed && getDolGlobalString('WORKFLOW_BILL_ON_RECEPTION') !== '0') {
2196
                        print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=classifybilled&token=' . newToken() . '">' . $langs->trans('ClassifyBilled') . '</a>';
2197
                    }
2198
                    print '<a class="butAction" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=classifyclosed&token=' . newToken() . '">' . $langs->trans("Close") . '</a>';
2199
                }
2200
            }
2201
2202
            if ($user->hasRight('reception', 'supprimer')) {
2203
                print '<a class="butActionDelete" href="' . $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=delete&token=' . newToken() . '">' . $langs->trans("Delete") . '</a>';
2204
            }
2205
        }
2206
2207
        print '</div>';
2208
    }
2209
2210
2211
    /*
2212
     * Documents generated
2213
     */
2214
2215
    if ($action != 'presend' && $action != 'editline') {
2216
        print '<div class="fichecenter"><div class="fichehalfleft">';
2217
2218
        $objectref = dol_sanitizeFileName($object->ref);
2219
        $filedir = $conf->reception->dir_output . "/" . $objectref;
2220
2221
        $urlsource = $_SERVER["PHP_SELF"] . "?id=" . $object->id;
2222
2223
        $genallowed = $user->hasRight('reception', 'lire');
2224
        $delallowed = $user->hasRight('reception', 'creer');
2225
2226
        print $formfile->showdocuments('reception', $objectref, $filedir, $urlsource, $genallowed, $delallowed, $object->model_pdf, 1, 0, 0, 28, 0, '', '', '', $soc->default_lang);
2227
2228
        // Show links to link elements
2229
        //$linktoelem = $form->showLinkToObjectBlock($object, null, array('order'));
2230
        $somethingshown = $form->showLinkedObjectBlock($object, '');
2231
2232
        print '</div><div class="fichehalfright">';
2233
2234
        print '</div></div>';
2235
    }
2236
2237
    // Presend form
2238
    $modelmail = 'shipping_send';
2239
    $defaulttopic = 'SendReceptionRef';
2240
    $diroutput = $conf->reception->dir_output;
2241
    $trackid = 'rec' . $object->id;
2242
2243
    include DOL_DOCUMENT_ROOT . '/core/tpl/card_presend.tpl.php';
2244
}
2245
2246
2247
ViewMain::llxFooter();
2248
2249
$db->close();
2250