dolibarr 22.0.5
card.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2001-2007 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2016 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005 Eric Seigne <eric.seigne@ryxeo.com>
5 * Copyright (C) 2005-2015 Regis Houssin <regis.houssin@capnetworks.com>
6 * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
7 * Copyright (C) 2006 Auguria SARL <info@auguria.org>
8 * Copyright (C) 2010-2015 Juanjo Menent <jmenent@2byte.es>
9 * Copyright (C) 2013-2016 Marcos García <marcosgdf@gmail.com>
10 * Copyright (C) 2012-2013 Cédric Salvador <csalvador@gpcsolutions.fr>
11 * Copyright (C) 2011-2023 Alexandre Spangaro <alexandre@inovea-conseil.com>
12 * Copyright (C) 2014 Cédric Gross <c.gross@kreiz-it.fr>
13 * Copyright (C) 2014-2015 Ferran Marcet <fmarcet@2byte.es>
14 * Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
15 * Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
16 * Copyright (C) 2016-2022 Charlene Benke <charlene@patas-monkey.com>
17 * Copyright (C) 2016 Meziane Sof <virtualsof@yahoo.fr>
18 * Copyright (C) 2017 Josep Lluís Amador <joseplluis@lliuretic.cat>
19 * Copyright (C) 2019-2024 Frédéric France <frederic.france@free.fr>
20 * Copyright (C) 2019-2020 Thibault FOUCART <support@ptibogxiv.net>
21 * Copyright (C) 2020 Pierre Ardoin <mapiolca@me.com>
22 * Copyright (C) 2022 Vincent de Grandpré <vincent@de-grandpre.quebec>
23 * Copyright (C) 2024-2025 MDW <mdeweerd@users.noreply.github.com>
24 *
25 * This program is free software; you can redistribute it and/or modify
26 * it under the terms of the GNU General Public License as published by
27 * the Free Software Foundation; either version 3 of the License, or
28 * (at your option) any later version.
29 *
30 * This program is distributed in the hope that it will be useful,
31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 * GNU General Public License for more details.
34 *
35 * You should have received a copy of the GNU General Public License
36 * along with this program. If not, see <https://www.gnu.org/licenses/>.
37 */
38
46// Load Dolibarr environment
47require '../main.inc.php';
48require_once DOL_DOCUMENT_ROOT.'/core/class/canvas.class.php';
49require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
50require_once DOL_DOCUMENT_ROOT.'/core/class/genericobject.class.php';
51require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
52require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
53require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
54require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
55require_once DOL_DOCUMENT_ROOT.'/core/modules/product/modules_product.class.php';
56require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
57require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
58require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
67if (isModEnabled('propal')) {
68 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
69}
70if (isModEnabled('invoice')) {
71 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
72}
73if (isModEnabled('order')) {
74 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
75}
76if (isModEnabled('accounting')) {
77 require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
78 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
79 require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
80}
81if (isModEnabled('bom')) {
82 require_once DOL_DOCUMENT_ROOT.'/bom/class/bom.class.php';
83 $langs->load("mrp");
84}
85if (isModEnabled('workstation')) {
86 require_once DOL_DOCUMENT_ROOT.'/workstation/class/workstation.class.php';
87}
88
89// Load translation files required by the page
90$langs->loadLangs(array('products', 'other'));
91if (isModEnabled('stock')) {
92 $langs->load("stocks");
93}
94if (isModEnabled('invoice')) {
95 $langs->load("bills");
96}
97if (isModEnabled('productbatch')) {
98 $langs->load("productbatch");
99}
100
101$backtopageforcancel = GETPOST('backtopageforcancel');
102
103$mesg = '';
104$error = 0;
105$errors = array();
106
107$refalreadyexists = 0;
108$formbarcode = null;
109
110// Get parameters
111$id = GETPOSTINT('id');
112if (getDolGlobalString('MAIN_SECURITY_ALLOW_UNSECURED_REF_LABELS')) {
113 $ref = (GETPOSTISSET('ref') ? GETPOST('ref', 'nohtml') : null);
114} else {
115 $ref = (GETPOSTISSET('ref') ? GETPOST('ref', 'alpha') : null);
116}
117$type = (GETPOSTISSET('type') ? GETPOSTINT('type') : Product::TYPE_PRODUCT);
118$action = (GETPOST('action', 'alpha') ? GETPOST('action', 'alpha') : 'view');
119$cancel = GETPOST('cancel', 'alpha');
120$backtopage = GETPOST('backtopage', 'alpha');
121$confirm = GETPOST('confirm', 'alpha');
122$socid = GETPOSTINT('socid');
123$duration_value = GETPOST('duration_value'); // duration value can be an empty string
124$duration_unit = GETPOST('duration_unit', 'alpha');
125
126$accountancy_code_sell = GETPOST('accountancy_code_sell', 'alpha');
127$accountancy_code_sell_intra = GETPOST('accountancy_code_sell_intra', 'alpha');
128$accountancy_code_sell_export = GETPOST('accountancy_code_sell_export', 'alpha');
129$accountancy_code_buy = GETPOST('accountancy_code_buy', 'alpha');
130$accountancy_code_buy_intra = GETPOST('accountancy_code_buy_intra', 'alpha');
131$accountancy_code_buy_export = GETPOST('accountancy_code_buy_export', 'alpha');
132
133$checkmandatory = GETPOST('accountancy_code_buy_export', 'alpha');
134
135// by default 'alphanohtml' (better security); hidden conf MAIN_SECURITY_ALLOW_UNSECURED_LABELS_WITH_HTML allows basic html
136if (getDolGlobalString('MAIN_SECURITY_ALLOW_UNSECURED_REF_LABELS')) {
137 $label_security_check = 'nohtml';
138} else {
139 $label_security_check = !getDolGlobalString('MAIN_SECURITY_ALLOW_UNSECURED_LABELS_WITH_HTML') ? 'alphanohtml' : 'restricthtml';
140}
141
142if (!empty($user->socid)) {
143 $socid = $user->socid;
144}
145
146// Load object modCodeProduct
147$module = getDolGlobalString('PRODUCT_CODEPRODUCT_ADDON', 'mod_codeproduct_leopard');
148if (substr($module, 0, 16) == 'mod_codeproduct_' && substr($module, -3) == 'php') {
149 $module = substr($module, 0, dol_strlen($module) - 4);
150}
151$result = dol_include_once('/core/modules/product/'.$module.'.php');
152if ($result > 0) {
153 $modCodeProduct = new $module();
154}
155
156$object = new Product($db);
157$object->type = $type; // so test later to fill $usercancxxx is correct
158$extrafields = new ExtraFields($db);
159
160// fetch optionals attributes and labels
161$extrafields->fetch_name_optionals_label($object->table_element);
162
163if ($id > 0 || !empty($ref)) {
164 $result = $object->fetch($id, (string) $ref);
165 if ($result < 0) {
166 dol_print_error($db, $object->error, $object->errors);
167 }
168 $entity = (empty($object->entity) ? $conf->entity : $object->entity);
169 if (isModEnabled("product")) {
170 $upload_dir = $conf->product->multidir_output[$entity].'/'.get_exdir(0, 0, 0, 0, $object, 'product').dol_sanitizeFileName($object->ref);
171 } elseif (isModEnabled("service")) {
172 $upload_dir = $conf->service->multidir_output[$entity].'/'.get_exdir(0, 0, 0, 0, $object, 'product').dol_sanitizeFileName($object->ref);
173 }
174
175 if (getDolGlobalInt('PRODUCT_USE_OLD_PATH_FOR_PHOTO')) { // For backward compatibility, we scan also old dirs
176 if (isModEnabled("product")) {
177 $upload_dirold = $conf->product->multidir_output[$entity].'/'.substr(substr("000".$object->id, -2), 1, 1).'/'.substr(substr("000".$object->id, -2), 0, 1).'/'.$object->id."/photos";
178 } else {
179 $upload_dirold = $conf->service->multidir_output[$entity].'/'.substr(substr("000".$object->id, -2), 1, 1).'/'.substr(substr("000".$object->id, -2), 0, 1).'/'.$object->id."/photos";
180 }
181 }
182}
183
184$modulepart = 'product';
185
186// Get object canvas (By default, this is not defined, so standard usage of dolibarr)
187$canvas = !empty($object->canvas) ? $object->canvas : GETPOST("canvas");
188$objcanvas = null;
189if (!empty($canvas)) {
190 require_once DOL_DOCUMENT_ROOT.'/core/class/canvas.class.php';
191 $objcanvas = new Canvas($db, $action);
192 $objcanvas->getCanvas('product', 'card', $canvas);
193}
194
195// Security check
196$fieldvalue = (!empty($id) ? $id : (!empty($ref) ? $ref : ''));
197$fieldtype = (!empty($id) ? 'rowid' : 'ref');
198
199// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context
200$hookmanager->initHooks(array('productcard', 'globalcard'));
201
202if ($object->id > 0) {
203 if ($object->type == $object::TYPE_PRODUCT) {
204 restrictedArea($user, 'produit', $object->id, 'product&product', '', '');
205 }
206 if ($object->type == $object::TYPE_SERVICE) {
207 restrictedArea($user, 'service', $object->id, 'product&product', '', '');
208 }
209} else {
210 restrictedArea($user, 'produit|service', 0, 'product&product', '', '', $fieldtype);
211}
212
213// Permissions
214$usercanread = (($object->type == Product::TYPE_PRODUCT && $user->hasRight('produit', 'lire')) || ($object->type == Product::TYPE_SERVICE && $user->hasRight('service', 'lire')));
215$usercancreate = (($object->type == Product::TYPE_PRODUCT && $user->hasRight('produit', 'creer')) || ($object->type == Product::TYPE_SERVICE && $user->hasRight('service', 'creer')));
216$usercandelete = (($object->type == Product::TYPE_PRODUCT && $user->hasRight('produit', 'supprimer')) || ($object->type == Product::TYPE_SERVICE && $user->hasRight('service', 'supprimer')));
217$permissiontoeditextra = $usercancreate;
218if (GETPOST('attribute', 'aZ09') && isset($extrafields->attributes[$object->table_element]['perms'][GETPOST('attribute', 'aZ09')])) {
219 // For action 'update_extras', is there a specific permission set for the attribute to update
220 $permissiontoeditextra = dol_eval((string) $extrafields->attributes[$object->table_element]['perms'][GETPOST('attribute', 'aZ09')]);
221}
222
223
224/*
225 * Actions
226 */
227
228if ($cancel) {
229 $action = '';
230}
231
232$createbarcode = isModEnabled('barcode');
233if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('barcode', 'creer_advance')) {
234 $createbarcode = 0;
235}
236
237$parameters = array('id' => $id, 'ref' => $ref, 'objcanvas' => $objcanvas);
238$reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
239if ($reshook < 0) {
240 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
241}
242
243if (empty($reshook)) {
244 $backurlforlist = DOL_URL_ROOT.'/product/list.php?type='.$type;
245
246 if (empty($backtopage) || ($cancel && empty($id))) {
247 if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) {
248 if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) {
249 $backtopage = $backurlforlist;
250 } else {
251 $backtopage = DOL_URL_ROOT.'/product/card.php?id='.((!empty($id) && $id > 0) ? $id : '__ID__');
252 }
253 }
254 }
255
256 if ($cancel) {
257 if (!empty($backtopageforcancel)) {
258 header("Location: ".$backtopageforcancel);
259 exit;
260 } elseif (!empty($backtopage)) {
261 header("Location: ".$backtopage);
262 exit;
263 }
264 $action = '';
265 }
266 // merge products
267 if ($action == 'confirm_merge' && $confirm == 'yes' && $user->hasRight('societe', 'creer')) {
268 $error = 0;
269 $productOriginId = GETPOSTINT('product_origin');
270 $productOrigin = new Product($db);
271
272 if ($productOriginId <= 0) {
273 $langs->load('errors');
274 setEventMessages($langs->trans('ErrorProductIdIsMandatory', $langs->transnoentitiesnoconv('MergeOriginProduct')), null, 'errors');
275 } else {
276 if (!$error && $productOrigin->fetch($productOriginId) < 1) {
277 setEventMessages($langs->trans('ErrorRecordNotFound'), null, 'errors');
278 $error++;
279 }
280
281 if (!$error) {
282 // TODO Move the merge function into class of object.
283 $db->begin();
284
285 // Recopy some data
286 $listofproperties = array(
287 'ref',
288 'ref_ext',
289 'label',
290 'description',
291 'url',
292 'barcode',
293 'fk_barcode_type',
294 'import_key',
295 'mandatory_period',
296 'accountancy_code_buy',
297 'accountancy_code_buy_intra',
298 'accountancy_code_buy_export',
299 'accountancy_code_sell',
300 'accountancy_code_sell_intra',
301 'accountancy_code_sell_export'
302 );
303 foreach ($listofproperties as $property) {
304 if (empty($object->$property)) {
305 $object->$property = $productOrigin->$property;
306 }
307 }
308 // Concat some data
309 $listofproperties = array(
310 'note_public', 'note_private'
311 );
312 foreach ($listofproperties as $property) {
313 $object->$property = dol_concatdesc($object->$property, $productOrigin->$property);
314 }
315
316 // Merge extrafields
317 if (is_array($productOrigin->array_options)) {
318 foreach ($productOrigin->array_options as $key => $val) {
319 if (empty($object->array_options[$key])) {
320 $object->array_options[$key] = $val;
321 }
322 }
323 }
324
325 // Merge categories
326 $static_cat = new Categorie($db);
327 $custcats_ori = $static_cat->containing($productOrigin->id, 'product', 'id');
328 $custcats = $static_cat->containing($object->id, 'product', 'id');
329 $custcats = array_merge($custcats, $custcats_ori);
330 $object->setCategories($custcats);
331
332 // If product has a new code that is same than origin, we clean origin code to avoid duplicate key from database unique keys.
333 if ($productOrigin->barcode == $object->barcode) {
334 dol_syslog("We clean customer and supplier code so we will be able to make the update of target");
335 $productOrigin->barcode = '';
336 //$productOrigin->update($productOrigin->id, $user, 0, 'merge');
337 }
338
339 // Update
340 $result = $object->update($object->id, $user, 0, 'merge');
341 if ($result <= 0) {
342 setEventMessages($object->error, $object->errors, 'errors');
343 $error++;
344 }
345
346 // Move links
347 if (!$error) {
348 // TODO add this functionality into the api_products.class.php
349 // TODO Mutualise the list into object product.class.php
350 $objects = array(
351 'ActionComm' => '/comm/action/class/actioncomm.class.php',
352 'Bom' => '/bom/class/bom.class.php',
353 // do not use Categorie, it cause foreign key error, merge is done before
354 //'Categorie' => '/categories/class/categorie.class.php',
355 'Commande' => '/commande/class/commande.class.php',
356 'CommandeFournisseur' => '/fourn/class/fournisseur.commande.class.php',
357 'Contrat' => '/contrat/class/contrat.class.php',
358 'Delivery' => '/delivery/class/delivery.class.php',
359 'Facture' => '/compta/facture/class/facture.class.php',
360 'FactureFournisseur' => '/fourn/class/fournisseur.facture.class.php',
361 'FactureRec' => '/compta/facture/class/facture-rec.class.php',
362 'FichinterRec' => '/fichinter/class/fichinterrec.class.php',
363 'ProductFournisseur' => '/fourn/class/fournisseur.product.class.php',
364 'Propal' => '/comm/propal/class/propal.class.php',
365 'Reception' => '/reception/class/reception.class.php',
366 'SupplierProposal' => '/supplier_proposal/class/supplier_proposal.class.php',
367 );
368
369 // First, all core objects must update their tables
370 foreach ($objects as $object_name => $object_file) {
371 require_once DOL_DOCUMENT_ROOT.$object_file;
372
373 if (!$error && !$object_name::replaceProduct($db, $productOrigin->id, $object->id)) {
374 $error++;
375 setEventMessages($db->lasterror(), null, 'errors');
376 break;
377 }
378 }
379 }
380
381 // External modules should update their ones too
382 if (!$error) {
383 $parameters = array('soc_origin' => $productOrigin->id, 'soc_dest' => $object->id);
384 $reshook = $hookmanager->executeHooks(
385 'replaceProduct',
386 $parameters,
387 $object,
388 $action
389 );
390
391 if ($reshook < 0) {
392 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
393 $error++;
394 }
395 }
396
397
398 if (!$error) {
399 $object->context = array(
400 'merge' => 1,
401 'mergefromid' => $productOrigin->id,
402 );
403
404 // Call trigger
405 $result = $object->call_trigger('PRODUCT_MODIFY', $user);
406 if ($result < 0) {
407 setEventMessages($object->error, $object->errors, 'errors');
408 $error++;
409 }
410 // End call triggers
411 }
412
413 if (!$error) {
414 // Move files from the dir of the product being deleted into the dir of the product kept.
415 // This must happen on success only, and before the deletion: the filesystem is not part
416 // of the transaction, so moving the files on the failing path stripped the origin product
417 // of its documents while the database was rolled back, and Product::delete() removes the
418 // directory of the product, so a move placed after it finds nothing left to move.
419 if (!empty($conf->product->multidir_output[$productOrigin->entity])) {
420 $srcdir = $conf->product->multidir_output[$productOrigin->entity]."/".$productOrigin->ref;
421 $destdir = $conf->product->multidir_output[$object->entity]."/".$object->ref;
422
423 if (dol_is_dir($srcdir)) {
424 $dirlist = dol_dir_list($srcdir, 'files', 1);
425 foreach ($dirlist as $filetomove) {
426 $destfile = $destdir.'/'.$filetomove['relativename'];
427 //var_dump('Move file '.$filetomove['relativename'].' into '.$destfile);
428 dol_move($filetomove['fullname'], $destfile, '0', 0, 0, 1);
429 }
430 //exit;
431 }
432 }
433
434 // Delete the product
435 if ($productOrigin->delete($user) < 1) {
436 $error++;
437 }
438 }
439
440 if (!$error) {
441 setEventMessages($langs->trans('ProductsMergeSuccess'), null, 'mesgs');
442 $db->commit();
443 } else {
444 $langs->load("errors");
445 setEventMessages($langs->trans('ErrorsProductsMerge'), null, 'errors');
446 $db->rollback();
447 }
448 }
449 }
450 }
451
452 // Type
453 if ($action == 'setfk_product_type' && $usercancreate) {
454 $result = $object->setValueFrom('fk_product_type', GETPOST('fk_product_type'), '', null, 'text', '', $user, 'PRODUCT_MODIFY');
455 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
456 exit;
457 }
458
459 // Actions to build doc
460 $upload_dir = $conf->product->dir_output;
461 $permissiontoadd = $usercancreate;
462 include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
463
464 include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
465
466 // Barcode type
467 if ($action == 'setfk_barcode_type' && $usercancreate) {
468 $result = $object->setValueFrom('fk_barcode_type', GETPOST('fk_barcode_type'), '', null, 'text', '', $user, 'PRODUCT_MODIFY');
469 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
470 exit;
471 }
472
473 // Barcode value
474 if ($action == 'setbarcode' && $usercancreate) {
475 $result = $object->check_barcode(GETPOST('barcode'), GETPOST('barcode_type_code'));
476
477 if ($result >= 0) {
478 $result = $object->setValueFrom('barcode', GETPOST('barcode'), '', null, 'text', '', $user, 'PRODUCT_MODIFY');
479 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
480 exit;
481 } else {
482 $langs->load("errors");
483 if ($result == -1) {
484 $errors[] = 'ErrorBadBarCodeSyntax';
485 } elseif ($result == -2) {
486 $errors[] = 'ErrorBarCodeRequired';
487 } elseif ($result == -3) {
488 $errors[] = 'ErrorBarCodeAlreadyUsed';
489 } else {
490 $errors[] = 'FailedToValidateBarCode';
491 }
492
493 $error++;
494 setEventMessages('', $errors, 'errors');
495 }
496 }
497
498 // Quick edit for extrafields
499 if ($action == 'update_extras' && $permissiontoeditextra) {
500 // we may use oldcopy->hasBatch( in triggers so keep 1
501 $object->oldcopy = dol_clone($object, 1); // @phan-suppress-current-line PhanTypeMismatchProperty
502
503 $attribute_name = GETPOST('attribute', 'aZ09');
504
505 // Fill array 'array_options' with data from update form
506 $ret = $extrafields->setOptionalsFromPost(null, $object, $attribute_name);
507 if ($ret < 0) {
508 $error++;
509 }
510
511 if (!$error) {
512 $result = $object->updateExtraField($attribute_name, 'PRODUCT_MODIFY');
513 if ($result < 0) {
514 setEventMessages($object->error, $object->errors, 'errors');
515 $error++;
516 }
517 }
518
519 if ($error) {
520 $action = 'edit_extras';
521 }
522 }
523
524 // Add a product or service
525 if ($action == 'add' && $usercancreate) {
526 $error = 0;
527
528 if (!GETPOST('label', $label_security_check)) {
529 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentities('Label')), null, 'errors');
530 $action = "create";
531 $error++;
532 }
533 if (empty($ref)) {
534 if (!getDolGlobalString('PRODUCT_GENERATE_REF_AFTER_FORM')) {
535 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentities('ProductRef')), null, 'errors');
536 $action = "create";
537 $error++;
538 }
539 }
540 if (!empty($duration_value) && empty($duration_unit)) {
541 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentities('Unit')), null, 'errors');
542 $action = "create";
543 $error++;
544 }
545 $stockable_product = (int) ($type == 0 || ($type == 1 && getDolGlobalInt('STOCK_SUPPORTS_SERVICES')));
546 if (GETPOST('status_batch') && $stockable_product == 0 && isModEnabled('stock') && isModEnabled('productbatch')) {
547 setEventMessages($langs->trans('ErrorBatchesNeedStockManagement'), null, 'errors');
548 $action = "create";
549 $error++;
550 }
551
552 if (!$error) {
553 $units = GETPOSTINT('units');
554
555 $object->entity = $conf->entity;
556 $object->ref = (string) $ref;
557 $object->label = GETPOST('label', $label_security_check);
558 $object->price_base_type = GETPOST('price_base_type', 'aZ09');
559 $object->mandatory_period = empty(GETPOST("mandatoryperiod", 'alpha')) ? 0 : 1;
560 if ($object->price_base_type == 'TTC') {
561 $object->price_ttc = GETPOSTFLOAT('price');
562 } else {
563 $object->price = GETPOSTFLOAT('price');
564 }
565 if ($object->price_base_type == 'TTC') {
566 $object->price_min_ttc = GETPOSTFLOAT('price_min');
567 } else {
568 $object->price_min = GETPOSTFLOAT('price_min');
569 }
570
571 $tva_tx_txt = GETPOST('tva_tx', 'alpha'); // tva_tx can be '8.5' or '8.5*' or '8.5 (XXX)' or '8.5* (XXX)'
572
573 // We must define tva_tx, npr and local taxes
574 $vatratecode = '';
575 $tva_tx = preg_replace('/[^0-9\.].*$/', '', $tva_tx_txt); // keep remove all after the numbers and dot
576 $npr = preg_match('/\*/', $tva_tx_txt) ? 1 : 0;
577 $localtax1 = 0;
578 $localtax2 = 0;
579 $localtax1_type = '0';
580 $localtax2_type = '0';
581 // If value contains the unique code of vat line (new recommended method), we use it to find npr and local taxes
582 $reg = array();
583 if (preg_match('/\‍((.*)\‍)/', $tva_tx_txt, $reg)) {
584 // We look into database using code (we can't use get_localtax() because it depends on buyer that is not known). Same in update price.
585 $vatratecode = $reg[1];
586 // Get record from code
587 $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
588 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
589 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'";
590 $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1";
591 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
592 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
593 $resql = $db->query($sql);
594 if ($resql) {
595 $obj = $db->fetch_object($resql);
596 $npr = $obj->recuperableonly;
597 $localtax1 = $obj->localtax1;
598 $localtax2 = $obj->localtax2;
599 $localtax1_type = $obj->localtax1_type;
600 $localtax2_type = $obj->localtax2_type;
601 }
602 }
603
604 $object->default_vat_code = $vatratecode;
605 $object->tva_tx = $tva_tx;
606 $object->tva_npr = $npr;
607 $object->localtax1_tx = $localtax1;
608 $object->localtax2_tx = $localtax2;
609 $object->localtax1_type = $localtax1_type;
610 $object->localtax2_type = $localtax2_type;
611
612 $object->type = $type;
613 $object->status = GETPOSTINT('statut');
614 $object->status_buy = GETPOSTINT('statut_buy');
615 $object->status_batch = GETPOSTINT('status_batch');
616 $object->sell_or_eat_by_mandatory = GETPOSTINT('sell_or_eat_by_mandatory');
617 $object->batch_mask = GETPOST('batch_mask');
618
619 $object->barcode_type = GETPOSTINT('fk_barcode_type');
620 $object->barcode = GETPOST('barcode');
621 // Set barcode_type_xxx from barcode_type id
622 $stdobject = new GenericObject($db);
623 $stdobject->element = 'product';
624 $stdobject->barcode_type = GETPOSTINT('fk_barcode_type');
625 $result = $stdobject->fetchBarCode();
626 if ($result < 0) {
627 $error++;
628 $mesg = 'Failed to get bar code type information ';
629 setEventMessages($mesg.$stdobject->error, $stdobject->errors, 'errors');
630 }
631 $object->barcode_type_code = $stdobject->barcode_type_code;
632 $object->barcode_type_coder = $stdobject->barcode_type_coder;
633 $object->barcode_type_label = $stdobject->barcode_type_label;
634
635 $object->description = dol_htmlcleanlastbr(GETPOST('desc', 'restricthtml'));
636 $object->url = GETPOST('url');
637 $object->note_private = dol_htmlcleanlastbr(GETPOST('note_private', 'restricthtml'));
638 $object->note = $object->note_private; // deprecated
639 $object->customcode = GETPOST('customcode', 'alphanohtml');
640 $object->country_id = GETPOSTINT('country_id');
641 $object->state_id = GETPOSTINT('state_id');
642 $object->lifetime = GETPOSTINT('lifetime');
643 $object->qc_frequency = GETPOSTINT('qc_frequency');
644 $object->duration_value = $duration_value;
645 $object->duration_unit = $duration_unit;
646 $object->fk_default_warehouse = GETPOSTINT('fk_default_warehouse');
647 $object->fk_default_workstation = GETPOSTINT('fk_default_workstation');
648 $object->seuil_stock_alerte = GETPOST('seuil_stock_alerte') ? GETPOST('seuil_stock_alerte') : 0;
649 $object->desiredstock = GETPOST('desiredstock') ? GETPOST('desiredstock') : 0;
650 $object->canvas = GETPOST('canvas');
651 $object->net_measure = GETPOST('net_measure');
652 $object->net_measure_units = GETPOST('net_measure_units') === '' ? null : GETPOSTINT('net_measure_units'); // This is not the fk_unit but the power of unit
653 $object->weight = GETPOST('weight');
654 $object->weight_units = GETPOST('weight_units'); // This is not the fk_unit but the power of unit
655 $object->length = GETPOST('size');
656 $object->length_units = GETPOST('size_units'); // This is not the fk_unit but the power of unit
657 $object->width = GETPOST('sizewidth');
658 $object->height = GETPOST('sizeheight');
659 $object->surface = GETPOST('surface');
660 $object->surface_units = GETPOST('surface_units'); // This is not the fk_unit but the power of unit
661 $object->volume = GETPOST('volume');
662 $object->volume_units = GETPOST('volume_units'); // This is not the fk_unit but the power of unit
663 $finished = GETPOSTINT('finished');
664 if ($finished >= 0) {
665 $object->finished = $finished;
666 } else {
667 $object->finished = null;
668 }
669
670 $units = GETPOSTINT('units');
671 if ($units > 0) {
672 $object->fk_unit = $units;
673 } else {
674 $object->fk_unit = null;
675 }
676
677 $object->stockable_product = $stockable_product;
678
679 $accountancy_code_sell = GETPOST('accountancy_code_sell', 'alpha');
680 $accountancy_code_sell_intra = GETPOST('accountancy_code_sell_intra', 'alpha');
681 $accountancy_code_sell_export = GETPOST('accountancy_code_sell_export', 'alpha');
682 $accountancy_code_buy = GETPOST('accountancy_code_buy', 'alpha');
683 $accountancy_code_buy_intra = GETPOST('accountancy_code_buy_intra', 'alpha');
684 $accountancy_code_buy_export = GETPOST('accountancy_code_buy_export', 'alpha');
685
686 if (empty($accountancy_code_sell) || $accountancy_code_sell == '-1') {
687 $object->accountancy_code_sell = '';
688 } else {
689 $object->accountancy_code_sell = $accountancy_code_sell;
690 }
691 if (empty($accountancy_code_sell_intra) || $accountancy_code_sell_intra == '-1') {
692 $object->accountancy_code_sell_intra = '';
693 } else {
694 $object->accountancy_code_sell_intra = $accountancy_code_sell_intra;
695 }
696 if (empty($accountancy_code_sell_export) || $accountancy_code_sell_export == '-1') {
697 $object->accountancy_code_sell_export = '';
698 } else {
699 $object->accountancy_code_sell_export = $accountancy_code_sell_export;
700 }
701 if (empty($accountancy_code_buy) || $accountancy_code_buy == '-1') {
702 $object->accountancy_code_buy = '';
703 } else {
704 $object->accountancy_code_buy = $accountancy_code_buy;
705 }
706 if (empty($accountancy_code_buy_intra) || $accountancy_code_buy_intra == '-1') {
707 $object->accountancy_code_buy_intra = '';
708 } else {
709 $object->accountancy_code_buy_intra = $accountancy_code_buy_intra;
710 }
711 if (empty($accountancy_code_buy_export) || $accountancy_code_buy_export == '-1') {
712 $object->accountancy_code_buy_export = '';
713 } else {
714 $object->accountancy_code_buy_export = $accountancy_code_buy_export;
715 }
716
717 // MultiPrix
718 if (getDolGlobalString('PRODUIT_MULTIPRICES')) {
719 $produit_multiprices_limit = getDolGlobalString('PRODUIT_MULTIPRICES_LIMIT');
720 for ($i = 2; $i <= $produit_multiprices_limit; $i++) {
721 if (GETPOSTISSET("price_".$i)) {
722 $object->multiprices["$i"] = price2num(GETPOST("price_".$i), 'MU');
723 $object->multiprices_base_type["$i"] = GETPOST("multiprices_base_type_".$i);
724 } else {
725 $object->multiprices["$i"] = "";
726 }
727 }
728 }
729
730 // Fill array 'array_options' with data from add form
731 $ret = $extrafields->setOptionalsFromPost(null, $object);
732 if ($ret < 0) {
733 $error++;
734 }
735
736 if (!$ref && getDolGlobalString('PRODUCT_GENERATE_REF_AFTER_FORM')) {
737 // Generate ref...
738 '@phan-var ModeleProductCode $modCodeProduct';
739 $ref = $modCodeProduct->getNextValue($object, $type);
740 }
741
742 if (!$error) {
743 $id = $object->create($user);
744 }
745
746 if ($id > 0) {
747 // Category association
748 $categories = GETPOST('categories', 'array');
749 $object->setCategories($categories);
750
751 if (!empty($backtopage)) {
752 $backtopage = preg_replace('/__ID__/', (string) $object->id, $backtopage); // New method to autoselect parent project after a New on another form object creation
753 $backtopage = preg_replace('/--IDFORBACKTOPAGE--/', (string) $object->id, $backtopage); // New method to autoselect parent after a New on another form object creation
754 if (preg_match('/\?/', $backtopage)) {
755 $backtopage .= '&productid='.$object->id; // Old method
756 }
757
758 header("Location: ".$backtopage);
759 exit;
760 } else {
761 header("Location: ".$_SERVER['PHP_SELF']."?id=".$id);
762 exit;
763 }
764 } else {
765 if (count($object->errors)) {
766 setEventMessages($object->error, $object->errors, 'errors');
767 } else {
768 if ($object->error == 'ErrorProductAlreadyExists') {
769 // allow to hook on ErrorProductAlreadyExists in any module
770 $reshook = $hookmanager->executeHooks('onProductAlreadyExists', $parameters, $object, $action);
771 if ($reshook < 0) {
772 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
773 }
774 if ($object->error) {
775 // check again to prevent translation issue,
776 // as error may have been cleared in hook function
777 setEventMessages($langs->trans($object->error), null, 'errors');
778 }
779 } else {
780 setEventMessages($langs->trans($object->error), null, 'errors');
781 }
782 }
783 $action = "create";
784 }
785 }
786 }
787
788 // Update a product or service
789 if ($action == 'update' && $usercancreate) {
790 if (GETPOST('cancel', 'alpha')) {
791 $action = '';
792 } else {
793 if ($object->id > 0) {
794 // Need dol_clone methode 1 (same object class) because update product use hasbatch() method on oldcopy
795 $object->oldcopy = dol_clone($object, 1); // @phan-suppress-current-line PhanTypeMismatchProperty
796
797 if (!getDolGlobalString('PRODUCT_GENERATE_REF_AFTER_FORM')) {
798 $object->ref = (string) $ref;
799 }
800 $object->label = GETPOST('label', $label_security_check);
801
802 $desc = dol_htmlcleanlastbr(preg_replace('/&nbsp;$/', '', GETPOST('desc', 'restricthtml')));
803 $object->description = $desc;
804
805 $object->url = GETPOST('url');
806 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
807 $object->note_private = dol_htmlcleanlastbr(GETPOST('note_private', 'restricthtml'));
808 $object->note = $object->note_private;
809 }
810 $object->customcode = GETPOST('customcode', 'alpha');
811 $object->country_id = GETPOSTINT('country_id');
812 $object->state_id = GETPOSTINT('state_id');
813 $object->lifetime = GETPOSTINT('lifetime');
814 $object->qc_frequency = GETPOSTINT('qc_frequency');
815 $object->status = GETPOSTINT('statut');
816 $object->status_buy = GETPOSTINT('statut_buy');
817 $object->status_batch = GETPOSTINT('status_batch');
818 $object->sell_or_eat_by_mandatory = GETPOSTINT('sell_or_eat_by_mandatory');
819 $object->batch_mask = GETPOST('batch_mask', 'alpha');
820 $object->fk_default_warehouse = GETPOSTINT('fk_default_warehouse');
821 $object->fk_default_workstation = GETPOSTINT('fk_default_workstation');
822 // removed from update view so GETPOST always empty
823 /*
824 $object->seuil_stock_alerte = GETPOST('seuil_stock_alerte');
825 $object->desiredstock = GETPOST('desiredstock');
826 */
827 $object->duration_value = GETPOST('duration_value');
828 $object->duration_unit = GETPOST('duration_unit', 'alpha');
829
830 $object->canvas = GETPOST('canvas');
831 $object->net_measure = GETPOST('net_measure');
832 $object->net_measure_units = GETPOST('net_measure_units') === '' ? null : GETPOSTINT('net_measure_units'); // This is not the fk_unit but the power of unit
833 $object->weight = GETPOST('weight');
834 $object->weight_units = GETPOST('weight_units'); // This is not the fk_unit but the power of unit
835 $object->length = GETPOST('size');
836 $object->length_units = GETPOST('size_units'); // This is not the fk_unit but the power of unit
837 $object->width = GETPOST('sizewidth');
838 $object->height = GETPOST('sizeheight');
839
840 $object->surface = GETPOST('surface');
841 $object->surface_units = GETPOST('surface_units'); // This is not the fk_unit but the power of unit
842 $object->volume = GETPOST('volume');
843 $object->volume_units = GETPOST('volume_units'); // This is not the fk_unit but the power of unit
844
845 $finished = GETPOSTINT('finished');
846 if ($finished >= 0) {
847 $object->finished = $finished;
848 } else {
849 $object->finished = null;
850 }
851
852 $fk_default_bom = GETPOSTINT('fk_default_bom');
853 if ($fk_default_bom >= 0) {
854 $object->fk_default_bom = $fk_default_bom;
855 } else {
856 $object->fk_default_bom = 0;
857 }
858
859 // managed_in_stock
860 $object->stockable_product = (int) GETPOSTISSET('stockable_product');
861 if ($object->status_batch > 0 && $object->stockable_product == 0 && isModEnabled('stock') && isModEnabled('productbatch')) {
862 $object->stockable_product = 1;
863 setEventMessages($langs->trans('ForceBatchesNeedStockManagement'), null, 'warnings');
864 }
865
866 $units = GETPOSTINT('units');
867 if ($units > 0) {
868 $object->fk_unit = $units;
869 } else {
870 $object->fk_unit = null;
871 }
872
873 $object->barcode_type = GETPOSTINT('fk_barcode_type');
874 $object->barcode = GETPOST('barcode');
875 // Set barcode_type_xxx from barcode_type id
876 $stdobject = new GenericObject($db);
877 $stdobject->element = 'product';
878 $stdobject->barcode_type = GETPOSTINT('fk_barcode_type');
879 $result = $stdobject->fetchBarCode();
880 if ($result < 0) {
881 $error++;
882 $mesg = 'Failed to get bar code type information ';
883 setEventMessages($mesg.$stdobject->error, $stdobject->errors, 'errors');
884 }
885 $object->barcode_type_code = $stdobject->barcode_type_code;
886 $object->barcode_type_coder = $stdobject->barcode_type_coder;
887 $object->barcode_type_label = $stdobject->barcode_type_label;
888
889 $accountancy_code_sell = GETPOST('accountancy_code_sell', 'alpha');
890 $accountancy_code_sell_intra = GETPOST('accountancy_code_sell_intra', 'alpha');
891 $accountancy_code_sell_export = GETPOST('accountancy_code_sell_export', 'alpha');
892 $accountancy_code_buy = GETPOST('accountancy_code_buy', 'alpha');
893 $accountancy_code_buy_intra = GETPOST('accountancy_code_buy_intra', 'alpha');
894 $accountancy_code_buy_export = GETPOST('accountancy_code_buy_export', 'alpha');
895 $checkmandatory = GETPOST('mandatoryperiod', 'alpha');
896 if (empty($accountancy_code_sell) || $accountancy_code_sell == '-1') {
897 $object->accountancy_code_sell = '';
898 } else {
899 $object->accountancy_code_sell = $accountancy_code_sell;
900 }
901 if (empty($accountancy_code_sell_intra) || $accountancy_code_sell_intra == '-1') {
902 $object->accountancy_code_sell_intra = '';
903 } else {
904 $object->accountancy_code_sell_intra = $accountancy_code_sell_intra;
905 }
906 if (empty($accountancy_code_sell_export) || $accountancy_code_sell_export == '-1') {
907 $object->accountancy_code_sell_export = '';
908 } else {
909 $object->accountancy_code_sell_export = $accountancy_code_sell_export;
910 }
911 if (empty($accountancy_code_buy) || $accountancy_code_buy == '-1') {
912 $object->accountancy_code_buy = '';
913 } else {
914 $object->accountancy_code_buy = $accountancy_code_buy;
915 }
916 if (empty($accountancy_code_buy_intra) || $accountancy_code_buy_intra == '-1') {
917 $object->accountancy_code_buy_intra = '';
918 } else {
919 $object->accountancy_code_buy_intra = $accountancy_code_buy_intra;
920 }
921 if (empty($accountancy_code_buy_export) || $accountancy_code_buy_export == '-1') {
922 $object->accountancy_code_buy_export = '';
923 } else {
924 $object->accountancy_code_buy_export = $accountancy_code_buy_export;
925 }
926 if ($object->isService()) {
927 $object->mandatory_period = (!empty($checkmandatory)) ? 1 : 0 ;
928 }
929
930
931 // Fill array 'array_options' with data from add form
932 $ret = $extrafields->setOptionalsFromPost(null, $object, '@GETPOSTISSET');
933 if ($ret < 0) {
934 $error++;
935 }
936
937 if (!$error && $object->check()) {
938 if ($object->update($object->id, $user) > 0) {
939 // Category association
940 $categories = GETPOST('categories', 'array');
941 $object->setCategories($categories);
942
943 $action = 'view';
944 } else {
945 if (count($object->errors)) {
946 setEventMessages($object->error, $object->errors, 'errors');
947 } else {
948 setEventMessages($langs->trans($object->error), null, 'errors');
949 }
950 $action = 'edit';
951 }
952 } else {
953 if (count($object->errors)) {
954 setEventMessages($object->error, $object->errors, 'errors');
955 } else {
956 setEventMessages($langs->trans("ErrorProductBadRefOrLabel"), null, 'errors');
957 }
958 $action = 'edit';
959 }
960 }
961 }
962 }
963
964 // Action clone object
965 if ($action == 'confirm_clone' && $confirm != 'yes') { // Test on permission not required
966 $action = '';
967 }
968 if ($action == 'confirm_clone' && $confirm == 'yes' && $usercancreate) {
969 if (!GETPOST('clone_content') && !GETPOST('clone_prices')) {
970 setEventMessages($langs->trans("NoCloneOptionsSpecified"), null, 'errors');
971 } else {
972 if ($object->id > 0) {
973 $error = 0;
974 // We clone object to avoid to denaturate loaded object when setting some properties for clone or if createFromClone modifies the object.
975 // We use native clone to keep this->db valid and allow to use later all the methods of object.
976 $clone = dol_clone($object, 1);
977
978 $clone->id = 0;
979 $clone->ref = GETPOST('clone_ref', 'alphanohtml');
980 $clone->status = 0;
981 $clone->status_buy = 0;
982 $clone->barcode = -1;
983
984 if ($clone->check()) {
985 $db->begin();
986
987 $clone->context['createfromclone'] = 'createfromclone';
988 $id = $clone->create($user);
989 if ($id > 0) {
990 if (GETPOST('clone_composition')) {
991 $result = $clone->clone_associations($object->id, $id);
992 if ($result < 1) {
993 setEventMessages($langs->trans('ErrorProductClone'), null, 'errors');
994 setEventMessages($clone->error, $clone->errors, 'errors');
995 $error++;
996 }
997 }
998
999 if (!$error && GETPOST('clone_categories')) {
1000 $result = $clone->cloneCategories($object->id, $id);
1001 if ($result < 1) {
1002 setEventMessages($langs->trans('ErrorProductClone'), null, 'errors');
1003 setEventMessages($clone->error, $clone->errors, 'errors');
1004 $error++;
1005 }
1006 }
1007
1008 if (!$error && GETPOST('clone_prices')) {
1009 $result = $clone->clone_price($object->id, $id);
1010 if ($result < 1) {
1011 setEventMessages($langs->trans('ErrorProductClone'), null, 'errors');
1012 setEventMessages($clone->error, $clone->errors, 'errors');
1013 $error++;
1014 }
1015 }
1016
1017 if (!$error && isModEnabled('bom') && $user->hasRight('bom', 'write')) {
1018 $defbomidac = 0; // to avoid cloning same BOM twice
1019 if (GETPOST('clone_defbom') && $object->fk_default_bom > 0) {
1020 $bomstatic = new BOM($db);
1021 $bomclone = $bomstatic->createFromClone($user, $object->fk_default_bom);
1022 if ((int) $bomclone < 0) {
1023 setEventMessages($langs->trans('ErrorProductClone').' : '.$langs->trans('ErrorProductCloneBom'), null, 'warnings');
1024 } else {
1025 $defbomidac = $object->fk_default_bom;
1026 $clone->fk_default_bom = $bomclone->id;
1027 $clone->update($id, $user);
1028 $bomclone->fk_product = $id;
1029 $bomclone->label = $langs->trans('BOMofRef', $clone->ref);
1030 $bomclone->update($user);
1031 $bomclone->validate($user);
1032 }
1033 }
1034 if (GETPOST('clone_otherboms')) {
1035 $bomstatic = new BOM($db);
1036 $bomlist = $bomstatic->fetchAll("", "", 0, 0, 'fk_product:=:'.(int) $object->id);
1037 if (is_array($bomlist)) {
1038 foreach ($bomlist as $bom2clone) {
1039 if ($bom2clone->id != $defbomidac) { // to avoid cloning same BOM twice
1040 $bomclone = $bomstatic->createFromClone($user, $bom2clone->id);
1041 if ((int) $bomclone < 0) {
1042 setEventMessages($langs->trans('ErrorProductClone').' : '.$langs->trans('ErrorProductCloneBom'), null, 'warnings');
1043 } else {
1044 $bomclone->fk_product = $id;
1045 $bomclone->label = $langs->trans('BOMofRef', $clone->ref);
1046 $bomclone->update($user);
1047 $bomclone->validate($user);
1048 }
1049 }
1050 }
1051 }
1052 }
1053 }
1054 // $clone->clone_fournisseurs($object->id, $id);
1055 } else {
1056 if ($clone->error == 'ErrorProductAlreadyExists') {
1057 $refalreadyexists++;
1058 $action = "";
1059
1060 $mesg = $langs->trans("ErrorProductAlreadyExists", $clone->ref);
1061 $mesg .= ' <a href="' . $_SERVER["PHP_SELF"] . '?ref=' . $clone->ref . '">' . $langs->trans("ShowCardHere") . '</a>.';
1062 setEventMessages($mesg, null, 'errors');
1063 } else {
1064 setEventMessages(empty($clone->error) ? '' : $langs->trans($clone->error), $clone->errors, 'errors');
1065 }
1066 $error++;
1067 }
1068
1069 unset($clone->context['createfromclone']);
1070
1071 if ($error) {
1072 $db->rollback();
1073 } else {
1074 $db->commit();
1075 $db->close();
1076 header("Location: " . $_SERVER["PHP_SELF"] . "?id=" . $id);
1077 exit;
1078 }
1079 } else {
1080 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("NewRefForClone")), null, 'errors');
1081 }
1082 } else {
1083 dol_print_error($db, $object->error, $object->errors);
1084 }
1085 }
1086 $action = 'clone';
1087 }
1088
1089 // Delete a product
1090 if ($action == 'confirm_delete' && $confirm != 'yes') { // Test on permission not required
1091 $action = '';
1092 }
1093 if ($action == 'confirm_delete' && $confirm == 'yes' && $usercandelete) {
1094 $result = $object->delete($user);
1095
1096 if ($result > 0) {
1097 header('Location: '.DOL_URL_ROOT.'/product/list.php?type='.$object->type.'&delprod='.urlencode($object->ref));
1098 exit;
1099 } else {
1100 setEventMessages($langs->trans($object->error), null, 'errors');
1101 $reload = 0;
1102 $action = '';
1103 }
1104 }
1105
1106
1107 // Add product into object (when PRODUCT_ADD_FORM_ADD_TO is set)
1108 if ($object->id > 0 && $action == 'addin') { // Test on permission not required here. it is done later according to object.
1109 $thirdpartyid = 0;
1110 $permissiontoaddline = false;
1111 $propal = null;
1112 $facture = null;
1113 $commande = null;
1114
1115 // Get object and test permission
1116 if (GETPOSTINT('propalid') > 0) {
1117 $propal = new Propal($db);
1118 $result = $propal->fetch(GETPOSTINT('propalid'));
1119 if ($result <= 0) {
1120 dol_print_error($db, $propal->error);
1121 exit;
1122 }
1123 $thirdpartyid = $propal->socid;
1124 $permissiontoaddline = $user->hasRight('propal', 'creer');
1125 } elseif (GETPOSTINT('commandeid') > 0) {
1126 $commande = new Commande($db);
1127 $result = $commande->fetch(GETPOSTINT('commandeid'));
1128 if ($result <= 0) {
1129 dol_print_error($db, $commande->error);
1130 exit;
1131 }
1132 $thirdpartyid = $commande->socid;
1133 $permissiontoaddline = $user->hasRight('commande', 'creer');
1134 } elseif (GETPOSTINT('factureid') > 0) {
1135 $facture = new Facture($db);
1136 $result = $facture->fetch(GETPOSTINT('factureid'));
1137 if ($result <= 0) {
1138 dol_print_error($db, $facture->error);
1139 exit;
1140 }
1141 $thirdpartyid = $facture->socid;
1142 $permissiontoaddline = $user->hasRight('facture', 'creer');
1143 }
1144
1145 if ($thirdpartyid > 0) {
1146 $soc = new Societe($db);
1147 $result = $soc->fetch($thirdpartyid);
1148 if ($result <= 0) {
1149 dol_print_error($db, $soc->error);
1150 exit;
1151 }
1152
1153 $desc = $object->description;
1154
1155 $tva_tx = get_default_tva($mysoc, $soc, $object->id);
1156 $tva_npr = get_default_npr($mysoc, $soc, $object->id);
1157 if (empty($tva_tx)) {
1158 $tva_npr = 0;
1159 }
1160 $localtax1_tx = get_localtax($tva_tx, 1, $soc, $mysoc, $tva_npr);
1161 $localtax2_tx = get_localtax($tva_tx, 2, $soc, $mysoc, $tva_npr);
1162
1163 $pu_ht = $object->price;
1164 $pu_ttc = $object->price_ttc;
1165 $price_base_type = $object->price_base_type;
1166
1167 // If multiprice
1168 if (getDolGlobalString('PRODUIT_MULTIPRICES') && $soc->price_level) {
1169 $pu_ht = $object->multiprices[$soc->price_level];
1170 $pu_ttc = $object->multiprices_ttc[$soc->price_level];
1171 $price_base_type = $object->multiprices_base_type[$soc->price_level];
1172 } elseif (getDolGlobalString('PRODUIT_CUSTOMER_PRICES')) {
1173 require_once DOL_DOCUMENT_ROOT.'/product/class/productcustomerprice.class.php';
1174
1175 $prodcustprice = new ProductCustomerPrice($db);
1176
1177 $filter = array('t.fk_product' => (string) $object->id, 't.fk_soc' => (string) $soc->id);
1178
1179 $result = $prodcustprice->fetchAll('', '', 0, 0, $filter);
1180 if ($result) {
1181 if (count($prodcustprice->lines) > 0) {
1182 $date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours
1183 foreach ($prodcustprice->lines as $k => $custprice_line) {
1184 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
1185 $pu_ht = price($custprice_line->price);
1186 $pu_ttc = price($custprice_line->price_ttc);
1187 $price_base_type = $custprice_line->price_base_type;
1188 $tva_tx = $custprice_line->tva_tx;
1189 break;
1190 }
1191 }
1192 }
1193 }
1194 }
1195
1196 $tmpvat = price2num(preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx));
1197 $tmpprodvat = price2num(preg_replace('/\s*\‍(.*\‍)/', '', $object->tva_tx));
1198
1199 // On reevalue prix selon taux tva car taux tva transaction peut etre different
1200 // de ceux du produit par default (par example si pays different entre vendeur et acheteur).
1201 if ($tmpvat != $tmpprodvat) {
1202 if ($price_base_type != 'HT') {
1203 $pu_ht = price2num($pu_ttc / (1 + ((float) $tmpvat / 100)), 'MU');
1204 } else {
1205 $pu_ttc = price2num($pu_ht * (1 + ((float) $tmpvat / 100)), 'MU');
1206 }
1207 }
1208
1209 if (GETPOSTINT('propalid') > 0 && $permissiontoaddline && is_object($propal)) {
1210 // Define cost price for margin calculation
1211 $buyprice = 0;
1212 if (($result = $propal->defineBuyPrice($pu_ht, (float) price2num(GETPOST('remise_percent'), '', 2), $object->id)) < 0) {
1213 dol_syslog($langs->trans('FailedToGetCostPrice'));
1214 setEventMessages($langs->trans('FailedToGetCostPrice'), null, 'errors');
1215 } else {
1216 $buyprice = $result;
1217 }
1218
1219 $result = $propal->addline(
1220 $desc,
1221 $pu_ht,
1222 (float) price2num(GETPOST('qty'), 'MS'),
1223 $tva_tx,
1224 $localtax1_tx, // localtax1
1225 $localtax2_tx, // localtax2
1226 $object->id,
1227 (float) price2num(GETPOST('remise_percent'), '', 2),
1228 $price_base_type,
1229 $pu_ttc,
1230 0,
1231 0,
1232 -1,
1233 0,
1234 0,
1235 0,
1236 $buyprice,
1237 '',
1238 '',
1239 '',
1240 array(),
1241 $object->fk_unit
1242 );
1243 if ($result > 0) {
1244 header("Location: ".DOL_URL_ROOT."/comm/propal/card.php?id=".$propal->id);
1245 return;
1246 }
1247
1248 setEventMessages($langs->trans("ErrorUnknown").": $result", null, 'errors');
1249 } elseif (GETPOST('commandeid') > 0 && $permissiontoaddline && is_object($commande)) {
1250 // Define cost price for margin calculation
1251 $buyprice = 0;
1252 if (($result = $commande->defineBuyPrice($pu_ht, (float) price2num(GETPOST('remise_percent'), '', 2), $object->id)) < 0) {
1253 dol_syslog($langs->trans('FailedToGetCostPrice'));
1254 setEventMessages($langs->trans('FailedToGetCostPrice'), null, 'errors');
1255 } else {
1256 $buyprice = $result;
1257 }
1258
1259 $result = $commande->addline(
1260 $desc,
1261 (float) $pu_ht,
1262 (float) price2num(GETPOST('qty'), 'MS'),
1263 $tva_tx,
1264 $localtax1_tx, // localtax1
1265 $localtax2_tx, // localtax2
1266 $object->id,
1267 (float) price2num(GETPOST('remise_percent'), '', 2),
1268 0,
1269 0,
1270 $price_base_type,
1271 $pu_ttc,
1272 '',
1273 '',
1274 0,
1275 -1,
1276 0,
1277 0,
1278 0,
1279 $buyprice,
1280 '',
1281 array(),
1282 $object->fk_unit
1283 );
1284
1285 if ($result > 0) {
1286 header("Location: ".DOL_URL_ROOT."/commande/card.php?id=".urlencode((string) ($commande->id)));
1287 exit;
1288 }
1289
1290 setEventMessages($langs->trans("ErrorUnknown").": $result", null, 'errors');
1291 } elseif (GETPOST('factureid') > 0 && $permissiontoaddline && is_object($facture)) {
1292 // Define cost price for margin calculation
1293 $buyprice = 0;
1294 if (($result = $facture->defineBuyPrice($pu_ht, (float) price2num(GETPOST('remise_percent'), '', 2), $object->id)) < 0) {
1295 dol_syslog($langs->trans('FailedToGetCostPrice'));
1296 setEventMessages($langs->trans('FailedToGetCostPrice'), null, 'errors');
1297 } else {
1298 $buyprice = $result;
1299 }
1300
1301 $result = $facture->addline(
1302 $desc,
1303 (float) $pu_ht,
1304 (float) price2num(GETPOST('qty'), 'MS'),
1305 $tva_tx,
1306 $localtax1_tx,
1307 $localtax2_tx,
1308 $object->id,
1309 (float) price2num(GETPOST('remise_percent'), '', 2),
1310 '',
1311 '',
1312 0,
1313 0,
1314 0,
1315 $price_base_type,
1316 $pu_ttc,
1318 -1,
1319 0,
1320 '',
1321 0,
1322 0,
1323 0,
1324 $buyprice,
1325 '',
1326 array(),
1327 100,
1328 0,
1329 $object->fk_unit
1330 );
1331
1332 if ($result > 0) {
1333 header("Location: ".DOL_URL_ROOT."/compta/facture/card.php?facid=".$facture->id);
1334 exit;
1335 }
1336
1337 setEventMessages($langs->trans("ErrorUnknown").": $result", null, 'errors');
1338 }
1339 } else {
1340 $action = "";
1341 setEventMessages($langs->trans("WarningSelectOneDocument"), null, 'warnings');
1342 }
1343 }
1344
1345 // Actions to send emails
1346 $triggersendname = 'PRODUCT_SENTBYMAIL';
1347 $paramname = 'id';
1348 $autocopy = 'MAIN_MAIL_AUTOCOPY_PRODUCT_TO';
1349 $trackid = 'prod'.$object->id;
1350 include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php';
1351}
1352
1353
1354
1355/*
1356 * View
1357 */
1358
1359$form = new Form($db);
1360$formfile = new FormFile($db);
1361$formproduct = new FormProduct($db);
1362$formcompany = new FormCompany($db);
1363if (isModEnabled('accounting')) {
1364 $formaccounting = new FormAccounting($db);
1365}
1366$sellOrEatByMandatoryList = null;
1367if (isModEnabled('productbatch')) {
1368 $sellOrEatByMandatoryList = Product::getSellOrEatByMandatoryList();
1369
1370 $disableSellBy = getDolGlobalString('PRODUCT_DISABLE_SELLBY');
1371 $disableEatBy = getDolGlobalString('PRODUCT_DISABLE_EATBY');
1372
1373 if ($disableSellBy) {
1374 unset($sellOrEatByMandatoryList[Product::SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY]);
1375 unset($sellOrEatByMandatoryList[Product::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT]);
1376 }
1377 if ($disableEatBy) {
1378 unset($sellOrEatByMandatoryList[Product::SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY]);
1379 unset($sellOrEatByMandatoryList[Product::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT]);
1380 }
1381}
1382
1383$title = $langs->trans('ProductServiceCard');
1384
1385$help_url = '';
1386$shortlabel = dol_trunc($object->label, 16);
1387if (GETPOST("type") == '0' || ($object->type == Product::TYPE_PRODUCT)) {
1388 if ($action == 'create') {
1389 $title = $langs->trans("NewProduct");
1390 } else {
1391 $title = $langs->trans('Product')." ".$shortlabel." - ".$langs->trans('Card');
1392 $help_url = 'EN:Module_Products|FR:Module_Produits|ES:M&oacute;dulo_Productos|DE:Modul_Produkte';
1393 }
1394}
1395if (GETPOST("type") == '1' || ($object->type == Product::TYPE_SERVICE)) {
1396 if ($action == 'create') {
1397 $title = $langs->trans("NewService");
1398 } else {
1399 $title = $langs->trans('Service')." ".$shortlabel." - ".$langs->trans('Card');
1400 $help_url = 'EN:Module_Services_En|FR:Module_Services|ES:M&oacute;dulo_Servicios|DE:Modul_Leistungen';
1401 }
1402}
1403
1404llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-product page-card');
1405
1406// Load object modBarCodeProduct
1407$res = 0;
1408$modBarCodeProduct = null;
1409if (isModEnabled('barcode') && getDolGlobalString('BARCODE_PRODUCT_ADDON_NUM')) {
1410 $module = strtolower(getDolGlobalString('BARCODE_PRODUCT_ADDON_NUM'));
1411 $dirbarcode = array_merge(array('/core/modules/barcode/'), $conf->modules_parts['barcode']);
1412 foreach ($dirbarcode as $dirroot) {
1413 $res = dol_include_once($dirroot.$module.'.php');
1414 if ($res) {
1415 break;
1416 }
1417 }
1418 if ($res > 0) {
1419 $modBarCodeProduct = new $module();
1420 '@phan-var-force ModeleNumRefBarCode $modBarCodeProduct';
1421 }
1422}
1423
1424$canvasdisplayaction = $action;
1425if (in_array($canvasdisplayaction, array('merge', 'confirm_merge'))) {
1426 $canvasdisplayaction = 'view';
1427}
1428
1429if (is_object($objcanvas) && $objcanvas->displayCanvasExists($canvasdisplayaction)) {
1430 // -----------------------------------------
1431 // When used with CANVAS
1432 // -----------------------------------------
1433 $objcanvas->assign_values($canvasdisplayaction, $object->id, $object->ref); // Set value for templates
1434 $objcanvas->display_canvas($canvasdisplayaction); // Show template
1435} else {
1436 // -----------------------------------------
1437 // When used in standard mode
1438 // -----------------------------------------
1439 if ($action == 'create' && $usercancreate) {
1440 //WYSIWYG Editor
1441 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1442
1443 if (!empty($conf->use_javascript_ajax)) {
1444 print '<script type="text/javascript">';
1445 print '$(document).ready(function () {
1446 $("#selectcountry_id").change(function() {
1447 console.log("selectcountry_id change");
1448 document.formprod.action.value="create";
1449 document.formprod.submit();
1450 });
1451 });';
1452 print '</script>'."\n";
1453 }
1454
1455 // Load object modCodeProduct
1456 $module = getDolGlobalString('PRODUCT_CODEPRODUCT_ADDON', 'mod_codeproduct_leopard');
1457 if (substr($module, 0, 16) == 'mod_codeproduct_' && substr($module, -3) == 'php') {
1458 $module = substr($module, 0, dol_strlen($module) - 4);
1459 }
1460 $result = dol_include_once('/core/modules/product/'.$module.'.php');
1461 if ($result > 0) {
1462 $modCodeProduct = new $module();
1463 }
1464
1465 dol_set_focus('input[name="ref"]');
1466
1467 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formprod">';
1468 print '<input type="hidden" name="token" value="'.newToken().'">';
1469 print '<input type="hidden" name="action" value="add">';
1470 print '<input type="hidden" name="type" value="'.$type.'">'."\n";
1471 if (!empty($modCodeProduct->code_auto)) {
1472 print '<input type="hidden" name="code_auto" value="1">';
1473 }
1474 if (!empty($modBarCodeProduct->code_auto)) {
1475 print '<input type="hidden" name="barcode_auto" value="1">';
1476 }
1477 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
1478
1479 if ($type == 1) {
1480 $picto = 'service';
1481 $title = $langs->trans("NewService");
1482 } else {
1483 $picto = 'product';
1484 $title = $langs->trans("NewProduct");
1485 }
1486 $linkback = "";
1487 print load_fiche_titre($title, $linkback, $picto);
1488
1489 // We set country_id, country_code and country for the selected country
1490 $object->country_id = GETPOSTISSET('country_id') ? GETPOSTINT('country_id') : null;
1491 if ($object->country_id > 0) {
1492 $tmparray = getCountry($object->country_id, 'all');
1493 $object->country_code = $tmparray['code'];
1494 $object->country = $tmparray['label'];
1495 }
1496
1497 print dol_get_fiche_head();
1498
1499 // Call Hook tabContentCreateProduct
1500 $parameters = array();
1501 // Note that $action and $object may be modified by hook
1502 $reshook = $hookmanager->executeHooks('tabContentCreateProduct', $parameters, $object, $action);
1503 if (empty($reshook)) {
1504 print '<table class="border centpercent">';
1505
1506 if (!getDolGlobalString('PRODUCT_GENERATE_REF_AFTER_FORM')) {
1507 print '<tr>';
1508 $tmpcode = '';
1509 if (!empty($modCodeProduct->code_auto)) {
1510 $tmpcode = $modCodeProduct->getNextValue($object, $type);
1511 }
1512 print '<td class="titlefieldcreate fieldrequired">'.$langs->trans("ProductRef").'</td><td><input id="ref" name="ref" class="maxwidth200" maxlength="128" value="'.dol_escape_htmltag(GETPOSTISSET('ref') ? GETPOST('ref', 'alphanohtml') : $tmpcode).'">';
1513 if ($refalreadyexists) {
1514 print $langs->trans("RefAlreadyExists");
1515 }
1516 print '</td></tr>';
1517 }
1518
1519 // Label
1520 print '<tr><td class="fieldrequired">'.$langs->trans("Label").'</td><td><input id="label" name="label" class="minwidth300 maxwidth400onsmartphone" maxlength="255" value="'.dol_escape_htmltag(GETPOST('label', $label_security_check)).'"></td></tr>';
1521
1522 // On sell
1523 print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Sell").')</td><td>';
1524 $statutarray = array('1' => $langs->trans("OnSell"), '0' => $langs->trans("NotOnSell"));
1525 print $form->selectarray('statut', $statutarray, GETPOST('statut'));
1526 print '</td></tr>';
1527
1528 // To buy
1529 print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Buy").')</td><td>';
1530 $statutarray = array('1' => $langs->trans("ProductStatusOnBuy"), '0' => $langs->trans("ProductStatusNotOnBuy"));
1531 print $form->selectarray('statut_buy', $statutarray, GETPOST('statut_buy'));
1532 print '</td></tr>';
1533
1534 // Batch number management
1535 if (isModEnabled('productbatch')) {
1536 print '<tr><td>'.$langs->trans("ManageLotSerial").'</td><td>';
1537 $statutarray = array('0' => $langs->trans("ProductStatusNotOnBatch"), '1' => $langs->trans("ProductStatusOnBatch"), '2' => $langs->trans("ProductStatusOnSerial"));
1538 print $form->selectarray('status_batch', $statutarray, GETPOSTINT('status_batch'));
1539 print '</td></tr>';
1540 // Product specific batch number management
1541 $status_batch = GETPOSTINT('status_batch');
1542 if ($status_batch !== '0') {
1543 $langs->load("admin");
1544 $tooltip = $langs->trans("GenericMaskCodes", $langs->transnoentities("Batch"), $langs->transnoentities("Batch"));
1545 $tooltip .= $langs->trans("GenericMaskCodes1");
1546 $tooltip .= '<br>'.$langs->trans("GenericMaskCodes2");
1547 $tooltip .= '<br>'.$langs->trans("GenericMaskCodes3");
1548 $tooltip .= '<br>'.$langs->trans("GenericMaskCodes4a", $langs->transnoentities("Batch"), $langs->transnoentities("Batch"));
1549 $tooltip .= '<br>'.$langs->trans("GenericMaskCodes5");
1550 //$tooltip .= '<br>'.$langs->trans("GenericMaskCodes5b");
1551
1552 if ((getDolGlobalString('PRODUCTBATCH_LOT_ADDON') == 'mod_lot_advanced')
1553 || (getDolGlobalString('PRODUCTBATCH_SN_ADDON') == 'mod_sn_advanced')) {
1554 print '<tr><td id="mask_option">'.$langs->trans("ManageLotMask").'</td>';
1555 $inherited_mask_lot = getDolGlobalString('LOT_ADVANCED_MASK');
1556 $inherited_mask_sn = getDolGlobalString('SN_ADVANCED_MASK');
1557 print '<td id="field_mask">';
1558 print $form->textwithpicto('<input type="text" class="flat minwidth175" name="batch_mask" id="batch_mask_input">', $tooltip, 1, 'help');
1559 print '<script type="text/javascript">
1560 $(document).ready(function() {
1561 $("#field_mask, #mask_option").addClass("hideobject");
1562 $("#status_batch").on("change", function () {
1563 console.log("We change batch status");
1564 var optionSelected = $("option:selected", this);
1565 var valueSelected = this.value;
1566 $("#field_mask, #mask_option").addClass("hideobject");
1567 ';
1568 if (getDolGlobalString('PRODUCTBATCH_LOT_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_LOT_ADDON') == 'mod_lot_advanced') {
1569 print '
1570 if (this.value == 1) {
1571 $("#field_mask, #mask_option").toggleClass("hideobject");
1572 $("#batch_mask_input").val("'.$inherited_mask_lot.'");
1573 }
1574 ';
1575 }
1576 if (getDolGlobalString('PRODUCTBATCH_SN_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_SN_ADDON') == 'mod_sn_advanced') {
1577 print '
1578 if (this.value == 2) {
1579 $("#field_mask, #mask_option").toggleClass("hideobject");
1580 $("#batch_mask_input").val("'.$inherited_mask_sn.'");
1581 }
1582 ';
1583 }
1584 print '
1585 })
1586 })
1587 </script>';
1588 print '</td></tr>';
1589 }
1590 }
1591
1592 // SellBy / EatBy mandatory list
1593 if (!empty($sellOrEatByMandatoryList)) {
1594 print '<tr><td>'.$langs->trans('BatchSellOrEatByMandatoryList', $langs->transnoentities('SellByDate'), $langs->transnoentities('EatByDate')).'</td><td>';
1595 print $form->selectarray('sell_or_eat_by_mandatory', $sellOrEatByMandatoryList, GETPOSTINT('sell_or_eat_by_mandatory'));
1596 print '</td></tr>';
1597 }
1598 }
1599
1600 $showbarcode = isModEnabled('barcode');
1601 if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('barcode', 'lire_advance')) {
1602 $showbarcode = 0;
1603 }
1604
1605 if ($showbarcode && is_object($modBarCodeProduct)) {
1606 //var_dump($modBarCodeProduct); exit;
1607
1608 print '<tr><td>'.$langs->trans('BarcodeType').'</td><td>';
1609 if (GETPOSTISSET('fk_barcode_type')) {
1610 $fk_barcode_type = GETPOST('fk_barcode_type') ? GETPOST('fk_barcode_type') : 0;
1611 } else {
1612 if (empty($fk_barcode_type) && getDolGlobalString('PRODUIT_DEFAULT_BARCODE_TYPE')) {
1613 $fk_barcode_type = getDolGlobalInt("PRODUIT_DEFAULT_BARCODE_TYPE");
1614 } else {
1615 $fk_barcode_type = 0;
1616 }
1617 }
1618 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formbarcode.class.php';
1619 $formbarcode = new FormBarCode($db);
1620 print $formbarcode->selectBarcodeType($fk_barcode_type, 'fk_barcode_type', 1);
1621 print '</td>';
1622 print '</tr>';
1623
1624 print '<tr>';
1625 print '<td'.($modBarCodeProduct->code_null ? '' : ' class="fieldrequired"').'>'.$langs->trans("BarcodeValue").'</td><td>';
1626 $tmpcode = GETPOSTISSET('barcode') ? GETPOST('barcode') : $object->barcode;
1627 if (empty($tmpcode) && !empty($modBarCodeProduct->code_auto)) {
1628 $tmpcode = $modBarCodeProduct->getNextValue($object, $fk_barcode_type);
1629 }
1630 print img_picto('', 'barcode', 'class="pictofixedwidth"');
1631 print '<input class="maxwidth150" type="text" name="barcode" value="'.dol_escape_htmltag($tmpcode).'">';
1632 print '</td></tr>';
1633 }
1634
1635 // Description (used in invoice, propal...)
1636 print '<tr><td class="tdtop">'.$langs->trans("Description").'</td><td>';
1637 $doleditor = new DolEditor('desc', GETPOST('desc', 'restricthtml'), '', 160, 'dolibarr_details', '', false, true, getDolGlobalString('FCKEDITOR_ENABLE_DETAILS'), ROWS_4, '90%');
1638 $doleditor->Create();
1639 print "</td></tr>";
1640
1641 if (!getDolGlobalString('PRODUCT_DISABLE_PUBLIC_URL')) {
1642 // Public URL
1643 print '<tr><td>'.$langs->trans("PublicUrl").'</td><td>';
1644 print img_picto('', 'globe', 'class="pictofixedwidth"');
1645 print '<input type="text" name="url" class="quatrevingtpercent" value="'.GETPOST('url').'">';
1646 print '</td></tr>';
1647 }
1648
1649 if (($type != 1 || getDolGlobalInt('STOCK_SUPPORTS_SERVICES')) && isModEnabled('stock')) {
1650 // Default warehouse
1651 print '<tr><td>'.$langs->trans("DefaultWarehouse").'</td><td>';
1652 print img_picto($langs->trans("DefaultWarehouse"), 'stock', 'class="pictofixedwidth"');
1653 print $formproduct->selectWarehouses(GETPOSTINT('fk_default_warehouse'), 'fk_default_warehouse', 'warehouseopen', 1, 0, 0, '', 0, 0, array(), 'minwidth300 widthcentpercentminusxx maxwidth500');
1654 print ' <a href="'.DOL_URL_ROOT.'/product/stock/card.php?action=create&token='.newToken().'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?&action=create&type='.GETPOSTINT('type')).'">';
1655 print '<span class="fa fa-plus-circle valignmiddle paddingleft" title="'.$langs->trans("AddWarehouse").'"></span>';
1656 print '</a>';
1657
1658 print '</td>';
1659 print '</tr>';
1660
1661 if (!getDolGlobalString('PRODUCT_DISABLE_STOCK_LEVELS')) {
1662 // Stock min level
1663 print '<tr><td>'.$form->textwithpicto($langs->trans("StockLimit"), $langs->trans("StockLimitDesc"), 1).'</td><td>';
1664 print '<input name="seuil_stock_alerte" class="maxwidth50" value="'.GETPOST('seuil_stock_alerte').'">';
1665 print '</td>';
1666 print '</tr>';
1667
1668 // Stock desired level
1669 print '<tr><td>'.$form->textwithpicto($langs->trans("DesiredStock"), $langs->trans("DesiredStockDesc"), 1).'</td><td>';
1670 print '<input name="desiredstock" class="maxwidth50" value="'.GETPOST('desiredstock').'">';
1671 print '</td></tr>';
1672 }
1673 } else {
1674 if (!getDolGlobalString('PRODUCT_DISABLE_STOCK_LEVELS')) {
1675 print '<input name="seuil_stock_alerte" type="hidden" value="0">';
1676 print '<input name="desiredstock" type="hidden" value="0">';
1677 }
1678 }
1679
1680 if ($type == $object::TYPE_SERVICE && isModEnabled("workstation")) {
1681 // Default workstation
1682 print '<tr><td>'.$langs->trans("DefaultWorkstation").'</td><td>';
1683 print img_picto($langs->trans("DefaultWorkstation"), 'workstation', 'class="pictofixedwidth"');
1684 print $formproduct->selectWorkstations((GETPOSTISSET('fk_default_workstation') ? GETPOSTINT('fk_default_workstation') : ''), 'fk_default_workstation', 1);
1685 print '</td></tr>';
1686 }
1687
1688 // Duration
1689 if ($type == 1) {
1690 print '<tr><td>'.$langs->trans("Duration").'</td><td>';
1691 print img_picto('', 'clock', 'class="pictofixedwidth"');
1692 print '<input name="duration_value" class="width50" value="'.(GETPOSTISSET('duration_value') ? GETPOST('duration_value') : '').'">';
1693 print $formproduct->selectMeasuringUnits("duration_unit", "time", (GETPOSTISSET('duration_unit') ? GETPOST('duration_unit', 'alpha') : 'h'), 0, 1);
1694
1695 // Mandatory period
1696 if ($object->duration_value > 0) {
1697 print ' &nbsp; &nbsp; ';
1698 }
1699 print '<input type="checkbox" class="marginleftonly valignmiddle" id="mandatoryperiod" name="mandatoryperiod"'.(GETPOSTISSET('mandatoryperiod') ? ' checked="checked"' : '').'>';
1700 print '<label for="mandatoryperiod">';
1701 $htmltooltip = $langs->trans("mandatoryHelper");
1702 if (!getDolGlobalString('SERVICE_STRICT_MANDATORY_PERIOD')) {
1703 $htmltooltip .= '<br>'.$langs->trans("mandatoryHelper2");
1704 }
1705 print $form->textwithpicto($langs->trans("mandatoryperiod"), $htmltooltip, 1, 'info');
1706 print '</label>';
1707
1708 print '</td></tr>';
1709 }
1710
1711 if ($type != 1) { // Nature, Weight and volume only applies to products and not to services
1712 if (!getDolGlobalString('PRODUCT_DISABLE_NATURE')) {
1713 // Nature
1714 print '<tr><td>'.$form->textwithpicto($langs->trans("NatureOfProductShort"), $langs->trans("NatureOfProductDesc")).'</td><td>';
1715 print $formproduct->selectProductNature('finished', (GETPOST('finished') ? GETPOST('finished') : (string) $object->finished));
1716 print '</td></tr>';
1717 }
1718 }
1719
1720 if ($type != 1) {
1721 if (!getDolGlobalString('PRODUCT_DISABLE_WEIGHT')) {
1722 // Brut Weight
1723 print '<tr><td>'.$langs->trans("Weight").'</td><td>';
1724 print img_picto('', 'fa-balance-scale', 'class="pictofixedwidth"');
1725 print '<input name="weight" size="4" value="'.GETPOST('weight').'">';
1726 print $formproduct->selectMeasuringUnits("weight_units", "weight", GETPOSTISSET('weight_units') ? GETPOST('weight_units', 'alpha') : (GETPOST('weight_units', 'alpha') ?: getDolGlobalString('MAIN_WEIGHT_DEFAULT_UNIT', 0)), 0, 2);
1727 print '</td></tr>';
1728 }
1729
1730 // Brut Length
1731 if (!getDolGlobalString('PRODUCT_DISABLE_SIZE')) {
1732 print '<tr><td>'.$langs->trans("Length").' x '.$langs->trans("Width").' x '.$langs->trans("Height").'</td><td>';
1733 print img_picto('', 'fa-ruler', 'class="pictofixedwidth"');
1734 print '<input name="size" class="width50" value="'.GETPOST('size').'"> x ';
1735 print '<input name="sizewidth" class="width50" value="'.GETPOST('sizewidth').'"> x ';
1736 print '<input name="sizeheight" class="width50" value="'.GETPOST('sizeheight').'">';
1737 print $formproduct->selectMeasuringUnits("size_units", "size", GETPOSTISSET('size_units') ? GETPOST('size_units', 'alpha') : (GETPOST('size_units', 'alpha') ?: '0'), 0, 2);
1738 print '</td></tr>';
1739 }
1740 if (!getDolGlobalString('PRODUCT_DISABLE_SURFACE')) {
1741 // Brut Surface
1742 print '<tr><td>'.$langs->trans("Surface").'</td><td>';
1743 print '<input name="surface" size="4" value="'.GETPOST('surface').'">';
1744 print $formproduct->selectMeasuringUnits("surface_units", "surface", GETPOSTISSET('surface_units') ? GETPOST('surface_units', 'alpha') : (GETPOST('surface_units', 'alpha') ?: '0'), 0, 2);
1745 print '</td></tr>';
1746 }
1747 if (!getDolGlobalString('PRODUCT_DISABLE_VOLUME')) {
1748 // Brut Volume
1749 print '<tr><td>'.$langs->trans("Volume").'</td><td>';
1750 print '<input name="volume" size="4" value="'.GETPOST('volume').'">';
1751 print $formproduct->selectMeasuringUnits("volume_units", "volume", GETPOSTISSET('volume_units') ? GETPOST('volume_units', 'alpha') : (GETPOST('volume_units', 'alpha') ?: '0'), 0, 2);
1752 print '</td></tr>';
1753 }
1754
1755 if (getDolGlobalString('PRODUCT_ADD_NET_MEASURE')) {
1756 // Net Measure
1757 print '<tr><td>'.$langs->trans("NetMeasure").'</td><td>';
1758 print '<input name="net_measure" size="4" value="'.GETPOST('net_measure').'">';
1759 print $formproduct->selectMeasuringUnits("net_measure_units", '', GETPOSTISSET('net_measure_units') ? GETPOST('net_measure_units', 'alpha') : (GETPOST('net_measure_units', 'alpha') ?: getDolGlobalString('MAIN_WEIGHT_DEFAULT_UNIT', 0)), 0, 0);
1760 print '</td></tr>';
1761 }
1762 }
1763
1764 // Units
1765 if (getDolGlobalString('PRODUCT_USE_UNITS')) {
1766 print '<tr><td>'.$langs->trans('DefaultUnitToShow').'</td>';
1767 print '<td>';
1768 print $form->selectUnits(GETPOSTISSET('units') ? GETPOST('units', 'alpha') : (GETPOST('units', 'alpha') ?: '0'), 'units');
1769 print '</td></tr>';
1770 }
1771
1772 // Custom code
1773 if (!getDolGlobalString('PRODUCT_DISABLE_CUSTOMS_INFO') && empty($type)) {
1774 print '<tr><td class="wordbreak">'.$form->textwithpicto($langs->trans("CustomsCode"), $langs->trans("CustomsCodeHelp")).'</td><td><input name="customcode" class="maxwidth100onsmartphone" value="'.GETPOST('customcode').'"></td></tr>';
1775
1776 // Origin country
1777 print '<tr><td>'.$langs->trans("CountryOrigin").'</td>';
1778 print '<td>';
1779 print img_picto('', 'globe-americas', 'class="pictofixedwidth"');
1780 print $form->select_country((GETPOSTISSET('country_id') ? GETPOST('country_id') : $object->country_id), 'country_id', '', 0, 'minwidth300 widthcentpercentminusx maxwidth500');
1781 if ($user->admin) {
1782 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1783 }
1784 print '</td></tr>';
1785
1786 // State
1787 if (!getDolGlobalString('PRODUCT_DISABLE_STATE')) {
1788 print '<tr>';
1789 if (getDolGlobalString('MAIN_SHOW_REGION_IN_STATE_SELECT') && (getDolGlobalInt('MAIN_SHOW_REGION_IN_STATE_SELECT') == 1 || getDolGlobalInt('MAIN_SHOW_REGION_IN_STATE_SELECT') == 2)) {
1790 print '<td>'.$form->editfieldkey('RegionStateOrigin', 'state_id', '', $object, 0).'</td><td>';
1791 } else {
1792 print '<td>'.$form->editfieldkey('StateOrigin', 'state_id', '', $object, 0).'</td><td>';
1793 }
1794
1795 print img_picto('', 'state', 'class="pictofixedwidth"');
1796 print $formcompany->select_state($object->state_id, $object->country_code);
1797 print '</tr>';
1798 }
1799 }
1800
1801 // Quality control
1802 if (getDolGlobalString('PRODUCT_LOT_ENABLE_QUALITY_CONTROL')) {
1803 print '<tr><td>'.$langs->trans("LifeTime").'</td><td><input name="lifetime" class="maxwidth50" value="'.GETPOST('lifetime').'"></td></tr>';
1804 print '<tr><td>'.$langs->trans("QCFrequency").'</td><td><input name="qc_frequency" class="maxwidth50" value="'.GETPOST('qc_frequency').'"></td></tr>';
1805 }
1806
1807 // Other attributes
1808 $parameters = array('colspan' => ' colspan="2"', 'cols' => 2);
1809 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1810 print $hookmanager->resPrint;
1811 if (empty($reshook)) {
1812 print $object->showOptionals($extrafields, 'create', $parameters);
1813 }
1814
1815 // Note (private, no output on invoices, propales...)
1816 print '<tr><td class="tdtop">'.$langs->trans("NoteNotVisibleOnBill").'</td><td>';
1817
1818 // We use dolibarr_details as type of DolEditor here, because we must not accept images as description is included into PDF and not accepted by TCPDF.
1819 $doleditor = new DolEditor('note_private', GETPOST('note_private', 'restricthtml'), '', 140, 'dolibarr_details', '', false, true, getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE'), ROWS_8, '90%');
1820 $doleditor->Create();
1821
1822 print "</td></tr>";
1823
1824 if (isModEnabled('category')) {
1825 // Categories
1826 print '<tr><td>'.$langs->trans("Categories").'</td><td>';
1827 print $form->selectCategories(Categorie::TYPE_PRODUCT, 'categories', $object);
1828 print "</td></tr>";
1829 }
1830
1831 print '</table>';
1832
1833 print '<hr>';
1834
1835 if (!getDolGlobalString('PRODUCT_DISABLE_PRICES')) {
1836 if (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
1837 // We do no show price array on create when multiprices enabled.
1838 // We must set them on prices tab.
1839 print '<table class="border centpercent">';
1840 // VAT
1841 print '<tr><td class="titlefieldcreate">'.$langs->trans("VATRate").'</td><td>';
1842 $defaultva = get_default_tva($mysoc, $mysoc);
1843 print $form->load_tva("tva_tx", $defaultva, $mysoc, $mysoc, 0, 0, '', false, 1);
1844 print ajax_combobox("tva_tx");
1845 print '</td></tr>';
1846
1847 print '</table>';
1848
1849 print '<br>';
1850 } else {
1851 print '<table class="border centpercent">';
1852
1853 // Price
1854 print '<tr><td class="titlefieldcreate">'.$langs->trans("SellingPrice").'</td>';
1855 print '<td><input name="price" class="maxwidth50" value="'.$object->price.'">';
1856 print $form->selectPriceBaseType(getDolGlobalString('PRODUCT_PRICE_BASE_TYPE'), "price_base_type");
1857 print ajax_combobox("select_price_base_type");
1858 print '</td></tr>';
1859
1860 // Min price
1861 print '<tr><td>'.$langs->trans("MinPrice").'</td>';
1862 print '<td><input name="price_min" class="maxwidth50" value="'.$object->price_min.'">';
1863 print '</td></tr>';
1864
1865 // VAT
1866 print '<tr><td>'.$langs->trans("VATRate").'</td><td>';
1867 $defaultva = get_default_tva($mysoc, $mysoc);
1868 print $form->load_tva("tva_tx", $defaultva, $mysoc, $mysoc, 0, 0, '', false, 1);
1869 print ajax_combobox("tva_tx");
1870 print '</td></tr>';
1871
1872 print '</table>';
1873
1874 print '<br>';
1875 }
1876 }
1877
1878 // Accountancy codes
1879 print '<!-- accountancy codes -->'."\n";
1880 print '<table class="border centpercent">';
1881
1882 if (!getDolGlobalString('PRODUCT_DISABLE_ACCOUNTING')) {
1883 if (isModEnabled('accounting')) {
1885 // Accountancy_code_sell
1886 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellCode").'</td>';
1887 print '<td>';
1888 if ($type == 0) {
1889 $accountancy_code_sell = (GETPOSTISSET('accountancy_code_sell') ? GETPOST('accountancy_code_sell', 'alpha') : getDolGlobalString("ACCOUNTING_PRODUCT_SOLD_ACCOUNT"));
1890 } else {
1891 $accountancy_code_sell = (GETPOSTISSET('accountancy_code_sell') ? GETPOST('accountancy_code_sell', 'alpha') : getDolGlobalString("ACCOUNTING_SERVICE_SOLD_ACCOUNT"));
1892 }
1893 print $formaccounting->select_account($accountancy_code_sell, 'accountancy_code_sell', 1, array(), 1, 1, 'minwidth150 maxwidth300', '1');
1894 print '</td></tr>';
1895
1896 // Accountancy_code_sell_intra
1897 if ($mysoc->isInEEC()) {
1898 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellIntraCode").'</td>';
1899 print '<td>';
1900 if ($type == 0) {
1901 $accountancy_code_sell_intra = (GETPOSTISSET('accountancy_code_sell_intra') ? GETPOST('accountancy_code_sell_intra', 'alpha') : getDolGlobalString("ACCOUNTING_PRODUCT_SOLD_INTRA_ACCOUNT"));
1902 } else {
1903 $accountancy_code_sell_intra = (GETPOSTISSET('accountancy_code_sell_intra') ? GETPOST('accountancy_code_sell_intra', 'alpha') : getDolGlobalString("ACCOUNTING_SERVICE_SOLD_INTRA_ACCOUNT"));
1904 }
1905 print $formaccounting->select_account($accountancy_code_sell_intra, 'accountancy_code_sell_intra', 1, array(), 1, 1, 'minwidth150 maxwidth300', '1');
1906 print '</td></tr>';
1907 }
1908
1909 // Accountancy_code_sell_export
1910 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellExportCode").'</td>';
1911 print '<td>';
1912 if ($type == 0) {
1913 $accountancy_code_sell_export = (GETPOST('accountancy_code_sell_export') ? GETPOST('accountancy_code_sell_export', 'alpha') : getDolGlobalString("ACCOUNTING_PRODUCT_SOLD_EXPORT_ACCOUNT"));
1914 } else {
1915 $accountancy_code_sell_export = (GETPOST('accountancy_code_sell_export') ? GETPOST('accountancy_code_sell_export', 'alpha') : getDolGlobalString("ACCOUNTING_SERVICE_SOLD_EXPORT_ACCOUNT"));
1916 }
1917 print $formaccounting->select_account($accountancy_code_sell_export, 'accountancy_code_sell_export', 1, array(), 1, 1, 'minwidth150 maxwidth300', '1');
1918 print '</td></tr>';
1919
1920 // Accountancy_code_buy
1921 print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
1922 print '<td>';
1923 if ($type == 0) {
1924 $accountancy_code_buy = (GETPOST('accountancy_code_buy', 'alpha') ? (GETPOST('accountancy_code_buy', 'alpha')) : getDolGlobalString("ACCOUNTING_PRODUCT_BUY_ACCOUNT"));
1925 } else {
1926 $accountancy_code_buy = (GETPOST('accountancy_code_buy', 'alpha') ? (GETPOST('accountancy_code_buy', 'alpha')) : getDolGlobalString("ACCOUNTING_SERVICE_BUY_ACCOUNT"));
1927 }
1928 print $formaccounting->select_account($accountancy_code_buy, 'accountancy_code_buy', 1, array(), 1, 1, 'minwidth150 maxwidth300', '1');
1929 print '</td></tr>';
1930
1931 // Accountancy_code_buy_intra
1932 if ($mysoc->isInEEC()) {
1933 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyIntraCode").'</td>';
1934 print '<td>';
1935 if ($type == 0) {
1936 $accountancy_code_buy_intra = (GETPOSTISSET('accountancy_code_buy_intra') ? GETPOST('accountancy_code_buy_intra', 'alpha') : getDolGlobalString("ACCOUNTING_PRODUCT_BUY_INTRA_ACCOUNT"));
1937 } else {
1938 $accountancy_code_buy_intra = (GETPOSTISSET('accountancy_code_buy_intra') ? GETPOST('accountancy_code_buy_intra', 'alpha') : getDolGlobalString("ACCOUNTING_SERVICE_BUY_INTRA_ACCOUNT"));
1939 }
1940 print $formaccounting->select_account($accountancy_code_buy_intra, 'accountancy_code_buy_intra', 1, array(), 1, 1, 'minwidth150 maxwidth300', '1');
1941 print '</td></tr>';
1942 }
1943
1944 // Accountancy_code_buy_export
1945 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyExportCode").'</td>';
1946 print '<td>';
1947 if ($type == 0) {
1948 $accountancy_code_buy_export = (GETPOST('accountancy_code_buy_export') ? GETPOST('accountancy_code_buy_export', 'alpha') : getDolGlobalString("ACCOUNTING_PRODUCT_BUY_EXPORT_ACCOUNT"));
1949 } else {
1950 $accountancy_code_buy_export = (GETPOST('accountancy_code_buy_export') ? GETPOST('accountancy_code_buy_export', 'alpha') : getDolGlobalString("ACCOUNTING_SERVICE_BUY_EXPORT_ACCOUNT"));
1951 }
1952 print $formaccounting->select_account($accountancy_code_buy_export, 'accountancy_code_buy_export', 1, array(), 1, 1, 'minwidth150 maxwidth300', '1');
1953 print '</td></tr>';
1954 } else {// For external software
1955 if (!empty($accountancy_code_sell)) {
1956 $object->accountancy_code_sell = $accountancy_code_sell;
1957 }
1958 if (!empty($accountancy_code_sell_intra)) {
1959 $object->accountancy_code_sell_intra = $accountancy_code_sell_intra;
1960 }
1961 if (!empty($accountancy_code_sell_export)) {
1962 $object->accountancy_code_sell_export = $accountancy_code_sell_export;
1963 }
1964 if (!empty($accountancy_code_buy)) {
1965 $object->accountancy_code_buy = $accountancy_code_buy;
1966 }
1967 if (!empty($accountancy_code_buy_intra)) {
1968 $object->accountancy_code_buy_intra = $accountancy_code_buy_intra;
1969 }
1970 if (!empty($accountancy_code_buy_export)) {
1971 $object->accountancy_code_buy_export = $accountancy_code_buy_export;
1972 }
1973
1974 // Accountancy_code_sell
1975 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellCode").'</td>';
1976 print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_sell" value="'.$object->accountancy_code_sell.'">';
1977 print '</td></tr>';
1978
1979 // Accountancy_code_sell_intra
1980 if ($mysoc->isInEEC()) {
1981 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellIntraCode").'</td>';
1982 print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_sell_intra" value="'.$object->accountancy_code_sell_intra.'">';
1983 print '</td></tr>';
1984 }
1985
1986 // Accountancy_code_sell_export
1987 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellExportCode").'</td>';
1988 print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_sell_export" value="'.$object->accountancy_code_sell_export.'">';
1989 print '</td></tr>';
1990
1991 // Accountancy_code_buy
1992 print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
1993 print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_buy" value="'.$object->accountancy_code_buy.'">';
1994 print '</td></tr>';
1995
1996 // Accountancy_code_buy_intra
1997 if ($mysoc->isInEEC()) {
1998 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyIntraCode").'</td>';
1999 print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_buy_intra" value="'.$object->accountancy_code_buy_intra.'">';
2000 print '</td></tr>';
2001 }
2002
2003 // Accountancy_code_buy_export
2004 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyExportCode").'</td>';
2005 print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_buy_export" value="'.$object->accountancy_code_buy_export.'">';
2006 print '</td></tr>';
2007 }
2008 }
2009 print '</table>';
2010 }
2011
2012 print dol_get_fiche_end();
2013
2014 print $form->buttonsSaveCancel("Create");
2015
2016 print '</form>';
2017 } elseif ($object->id > 0) {
2018 /*
2019 * Product card
2020 */
2021
2022 // Card in edit mode
2023 if ($action == 'edit' && $usercancreate) {
2024 //WYSIWYG Editor
2025 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
2026
2027 if (!empty($conf->use_javascript_ajax)) {
2028 print '<script type="text/javascript">';
2029 print '$(document).ready(function () {
2030 $("#selectcountry_id").change(function () {
2031 document.formprod.action.value="edit";
2032 document.formprod.submit();
2033 });
2034 });';
2035 print '</script>'."\n";
2036 }
2037
2038 // We set country_id, country_code and country for the selected country
2039 $object->country_id = GETPOST('country_id') ? GETPOST('country_id') : $object->country_id;
2040 if ($object->country_id) {
2041 $tmparray = getCountry($object->country_id, 'all');
2042 $object->country_code = $tmparray['code'];
2043 $object->country = $tmparray['label'];
2044 }
2045
2046 $type = $langs->trans('Product');
2047 if ($object->isService()) {
2048 $type = $langs->trans('Service');
2049 }
2050 // print load_fiche_titre($langs->trans('Modify').' '.$type.' : '.(is_object($object->oldcopy)?$object->oldcopy->ref:$object->ref), "");
2051
2052 // Main official, simple, and not duplicated code
2053 print '<form action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'" method="POST" name="formprod">'."\n";
2054 print '<input type="hidden" name="token" value="'.newToken().'">';
2055 print '<input type="hidden" name="action" value="update">';
2056 print '<input type="hidden" name="id" value="'.$object->id.'">';
2057 print '<input type="hidden" name="canvas" value="'.$object->canvas.'">';
2058
2060 $titre = $langs->trans("CardProduct".$object->type);
2061 $picto = ($object->type == Product::TYPE_SERVICE ? 'service' : 'product');
2062 print dol_get_fiche_head($head, 'card', $titre, 0, $picto, 0, '', '', 0, '', 1);
2063
2064 // Call Hook tabContentEditProduct
2065 $parameters = array();
2066 // Note that $action and $object may be modified by hook
2067 $reshook = $hookmanager->executeHooks('tabContentEditProduct', $parameters, $object, $action);
2068
2069 if (empty($reshook)) {
2070 print '<table class="border allwidth">';
2071
2072 // Ref
2073 if (!getDolGlobalString('MAIN_PRODUCT_REF_NOT_EDITABLE')) {
2074 print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans("Ref").'</td><td colspan="3"><input name="ref" class="maxwidth200" maxlength="128" value="'.dol_escape_htmltag(GETPOSTISSET('ref') ? GETPOST('ref') : $object->ref).'"></td></tr>';
2075 } else {
2076 print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans("Ref").'</td><td colspan="3"><input name="ref" class="maxwidth200" maxlength="128" value="'.dol_escape_htmltag($object->ref).'" readonly="true"></td></tr>';
2077 }
2078
2079 // Label
2080 print '<tr><td class="fieldrequired">'.$langs->trans("Label").'</td><td colspan="3"><input name="label" class="minwidth300 maxwidth400onsmartphone" maxlength="255" value="'.dol_escape_htmltag(GETPOSTISSET('label') ? GETPOST('label') : $object->label).'"></td></tr>';
2081
2082 // Status To sell
2083 print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Sell").')</td><td colspan="3">';
2084 print '<select class="flat" name="statut">';
2085 if ((GETPOSTISSET('statut') && GETPOST('statut')) || (!GETPOSTISSET('statut') && $object->status)) {
2086 print '<option value="1" selected>'.$langs->trans("OnSell").'</option>';
2087 print '<option value="0">'.$langs->trans("NotOnSell").'</option>';
2088 } else {
2089 print '<option value="1">'.$langs->trans("OnSell").'</option>';
2090 print '<option value="0" selected>'.$langs->trans("NotOnSell").'</option>';
2091 }
2092 print '</select>';
2093 print '</td></tr>';
2094
2095 // Status To Buy
2096 print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Buy").')</td><td colspan="3">';
2097 print '<select class="flat" name="statut_buy">';
2098 if ((GETPOSTISSET('statut_buy') && GETPOST('statut_buy')) || (!GETPOSTISSET('statut_buy') && $object->status_buy)) {
2099 print '<option value="1" selected>'.$langs->trans("ProductStatusOnBuy").'</option>';
2100 print '<option value="0">'.$langs->trans("ProductStatusNotOnBuy").'</option>';
2101 } else {
2102 print '<option value="1">'.$langs->trans("ProductStatusOnBuy").'</option>';
2103 print '<option value="0" selected>'.$langs->trans("ProductStatusNotOnBuy").'</option>';
2104 }
2105 print '</select>';
2106 print '</td></tr>';
2107
2108 // Batch number management
2109 if (isModEnabled('productbatch')) {
2110 if ($object->isProduct() || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
2111 print '<tr><td>'.$langs->trans("ManageLotSerial").'</td><td>';
2112 $statutarray = array('0' => $langs->trans("ProductStatusNotOnBatch"), '1' => $langs->trans("ProductStatusOnBatch"), '2' => $langs->trans("ProductStatusOnSerial"));
2113
2114 print $form->selectarray('status_batch', $statutarray, GETPOSTISSET('status_batch') ? GETPOSTINT('status_batch') : $object->status_batch);
2115
2116 print '<span id="statusBatchWarning" class="warning" style="display: none;">';
2117 print img_warning().'&nbsp;'.$langs->trans("WarningConvertFromBatchToSerial").'</span>';
2118
2119 print '<span id="statusBatchMouvToGlobal" class="warning" style="display: none;">';
2120 print img_warning().'&nbsp;'.$langs->trans("WarningTransferBatchStockMouvToGlobal").'</span>';
2121
2122 if ($object->status_batch) {
2123 // Display message to make user know that all batch will be move into global stock
2124 print '<script type="text/javascript">
2125 $(document).ready(function() {
2126 console.log($("#statusBatchWarning"))
2127 $("#status_batch").on("change", function() {
2128 if ($("#status_batch")[0].value == 0) {
2129 $("#statusBatchMouvToGlobal").show()
2130 } else {
2131 $("#statusBatchMouvToGlobal").hide()
2132 }
2133 })
2134 })</script>';
2135
2136 // Display message to explain that if the product currently have a quantity higher or equal to 2, switching to this choice means we will still have a product with different objects of the same batch (while we want a unique serial number)
2137 if ($object->status_batch == 1) {
2138 print '<script type="text/javascript">
2139 $(document).ready(function() {
2140 console.log($("#statusBatchWarning"))
2141 $("#status_batch").on("change", function() {
2142 if ($("#status_batch")[0].value == 2) {
2143 $("#statusBatchWarning").show()
2144 } else {
2145 $("#statusBatchWarning").hide()
2146 }
2147 })
2148 })</script>';
2149 }
2150 }
2151
2152 print '</td></tr>';
2153 if (!empty($object->status_batch) || !empty($conf->use_javascript_ajax)) {
2154 $langs->load("admin");
2155 $tooltip = $langs->trans("GenericMaskCodes", $langs->transnoentities("Batch"), $langs->transnoentities("Batch"));
2156 $tooltip .= '<br>'.$langs->trans("GenericMaskCodes2");
2157 $tooltip .= '<br>'.$langs->trans("GenericMaskCodes3");
2158 $tooltip .= '<br>'.$langs->trans("GenericMaskCodes4a", $langs->transnoentities("Batch"), $langs->transnoentities("Batch"));
2159 $tooltip .= '<br>'.$langs->trans("GenericMaskCodes5");
2160 //$tooltip .= '<br>'.$langs->trans("GenericMaskCodes5b");
2161
2162 print '<tr><td id="mask_option">'.$langs->trans("ManageLotMask").'</td>';
2163 $mask = '';
2164 if ($object->status_batch == '1' && getDolGlobalString('PRODUCTBATCH_LOT_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_LOT_ADDON') == 'mod_lot_advanced') {
2165 $mask = !empty($object->batch_mask) ? $object->batch_mask : getDolGlobalString('LOT_ADVANCED_MASK');
2166 }
2167 if ($object->status_batch == '2' && getDolGlobalString('PRODUCTBATCH_SN_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_SN_ADDON') == 'mod_sn_advanced') {
2168 $mask = !empty($object->batch_mask) ? $object->batch_mask : getDolGlobalString('SN_ADVANCED_MASK');
2169 }
2170 $inherited_mask_lot = getDolGlobalString('LOT_ADVANCED_MASK');
2171 $inherited_mask_sn = getDolGlobalString('SN_ADVANCED_MASK');
2172 print '<td id="field_mask">';
2173 print $form->textwithpicto('<input type="text" class="flat minwidth175" name="batch_mask" id="batch_mask_input" value="'.$mask.'">', $tooltip, 1, 'help');
2174 // Add javascript to sho/hide field for custom mask
2175 if (!empty($conf->use_javascript_ajax)) {
2176 print '<script type="text/javascript">
2177 $(document).ready(function() {
2178 $("#field_mask").parent().addClass("hideobject");
2179 var preselect = document.getElementById("status_batch");';
2180 if (getDolGlobalString('PRODUCTBATCH_SN_USE_PRODUCT_MASKS')) {
2181 print 'if (preselect.value == "2") {
2182 $("#field_mask").parent().removeClass("hideobject");
2183 }';
2184 }
2185 if (getDolGlobalString('PRODUCTBATCH_LOT_USE_PRODUCT_MASKS')) {
2186 print 'if (preselect.value == "1") {
2187 $("#field_mask").parent().removeClass("hideobject");
2188 }';
2189 }
2190 print '$("#status_batch").on("change", function () {
2191 var optionSelected = $("option:selected", this);
2192 var valueSelected = this.value;
2193 $("#field_mask").parent().addClass("hideobject");
2194 ';
2195 if (getDolGlobalString('PRODUCTBATCH_LOT_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_LOT_ADDON') == 'mod_lot_advanced') {
2196 print '
2197 if (this.value == 1) {
2198 $("#field_mask").parent().removeClass("hideobject");
2199 $("#batch_mask_input").val("'.$inherited_mask_lot.'");
2200 }
2201 ';
2202 }
2203 if (getDolGlobalString('PRODUCTBATCH_SN_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_SN_ADDON') == 'mod_sn_advanced') {
2204 print '
2205 if (this.value == 2) {
2206 $("#field_mask").parent().removeClass("hideobject");
2207 $("#batch_mask_input").val("'.$inherited_mask_sn.'");
2208 }
2209 ';
2210 }
2211 print '
2212 })
2213 })
2214 </script>';
2215 }
2216 print '</td></tr>';
2217 }
2218 }
2219
2220 // SellBy / EatBy mandatory list
2221 if (!empty($sellOrEatByMandatoryList)) {
2222 if (GETPOSTISSET('sell_or_eat_by_mandatory')) {
2223 $sellOrEatByMandatorySelectedId = GETPOSTINT('sell_or_eat_by_mandatory');
2224 } else {
2225 $sellOrEatByMandatorySelectedId = $object->sell_or_eat_by_mandatory;
2226 }
2227 print '<tr><td>'.$langs->trans('BatchSellOrEatByMandatoryList', $langs->transnoentities('SellByDate'), $langs->transnoentities('EatByDate')).'</td><td>';
2228 print $form->selectarray('sell_or_eat_by_mandatory', $sellOrEatByMandatoryList, $sellOrEatByMandatorySelectedId);
2229 print '</td></tr>';
2230 }
2231 }
2232
2233 // Barcode
2234 $showbarcode = isModEnabled('barcode');
2235 if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('barcode', 'lire_advance')) {
2236 $showbarcode = 0;
2237 }
2238
2239 if ($showbarcode) {
2240 print '<tr><td>'.$langs->trans('BarcodeType').'</td><td>';
2241 if (GETPOSTISSET('fk_barcode_type')) {
2242 $fk_barcode_type = GETPOST('fk_barcode_type');
2243 } else {
2244 $fk_barcode_type = $object->barcode_type;
2245 if (empty($fk_barcode_type) && getDolGlobalString('PRODUIT_DEFAULT_BARCODE_TYPE')) {
2246 $fk_barcode_type = getDolGlobalString('PRODUIT_DEFAULT_BARCODE_TYPE');
2247 }
2248 }
2249 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formbarcode.class.php';
2250 $formbarcode = new FormBarCode($db);
2251 print $formbarcode->selectBarcodeType($fk_barcode_type, 'fk_barcode_type', 1);
2252 print '</td></tr>';
2253 print '<tr><td>'.$langs->trans("BarcodeValue").'</td><td>';
2254 $tmpcode = GETPOSTISSET('barcode') ? GETPOST('barcode') : $object->barcode;
2255 if (empty($tmpcode) && !empty($modBarCodeProduct->code_auto)) {
2256 $tmpcode = $modBarCodeProduct->getNextValue($object, $fk_barcode_type);
2257 }
2258 print '<input class="maxwidth150 maxwidthonsmartphone" type="text" name="barcode" value="'.dol_escape_htmltag($tmpcode).'">';
2259 print '</td></tr>';
2260 }
2261
2262 // Description (used in invoice, propal...)
2263 print '<tr><td class="tdtop">'.$langs->trans("Description").'</td><td>';
2264
2265 // We use dolibarr_details as type of DolEditor here, because we must not accept images, as description is included into PDF and external links are not accepted by TCPDF.
2266 $doleditor = new DolEditor('desc', GETPOSTISSET('desc') ? GETPOST('desc', 'restricthtml') : $object->description, '', 160, 'dolibarr_details', '', false, true, getDolGlobalInt('FCKEDITOR_ENABLE_DETAILS'), ROWS_4, '90%');
2267 $doleditor->Create();
2268
2269 print "</td></tr>";
2270 print "\n";
2271
2272 // Public Url
2273 if (!getDolGlobalString('PRODUCT_DISABLE_PUBLIC_URL')) {
2274 print '<tr><td>'.$langs->trans("PublicUrl").'</td><td>';
2275 print img_picto('', 'globe', 'class="pictofixedwidth"');
2276 print '<input type="text" name="url" class="maxwidth500 widthcentpercentminusx" value="'.(GETPOSTISSET('url') ? GETPOST('url') : $object->url).'">';
2277 print '</td></tr>';
2278 }
2279
2280 // Stock
2281 if (($object->isProduct() || getDolGlobalInt('STOCK_SUPPORTS_SERVICES')) && isModEnabled('stock')) {
2282 if (isModEnabled('productbatch') && $object->hasbatch()) {
2283 print '<tr><td><input type="hidden" id="stockable_product" name="stockable_product" value="on" /></td><td></td></tr>';
2284 } else {
2285 print '<tr><td><label for="stockable_product">' . $langs->trans("StockableProduct") . '</label></td>';
2286 $checked = empty($object->stockable_product) ? "" : "checked";
2287 print '<td><input type="checkbox" id="stockable_product" name="stockable_product" '. $checked . ' /></td></tr>';
2288 }
2289
2290 // Default warehouse
2291 print '<tr class="showifstockable'.(empty($object->stockable_product) ? ' hidden' : '').'"><td>'.$langs->trans("DefaultWarehouse").'</td><td>';
2292 print img_picto($langs->trans("DefaultWarehouse"), 'stock', 'class="pictofixedwidth"');
2293 print $formproduct->selectWarehouses((GETPOSTISSET('fk_default_warehouse') ? GETPOST('fk_default_warehouse') : $object->fk_default_warehouse), 'fk_default_warehouse', 'warehouseopen', 1, 0, 0, '', 0, 0, array(), 'minwidth200 maxwidth500 widthcentpercentminusxx');
2294 print ' <a href="'.DOL_URL_ROOT.'/product/stock/card.php?action=create&amp;backtopage='.urlencode($_SERVER['PHP_SELF'].'?action=edit&id='.((int) $object->id)).'">';
2295 print '<span class="fa fa-plus-circle valignmiddle paddingleft" title="'.$langs->trans("AddWarehouse").'"></span></a>';
2296 print '</td></tr>';
2297
2298 /*
2299 print "<tr>".'<td>'.$langs->trans("StockLimit").'</td><td>';
2300 print '<input name="seuil_stock_alerte" size="4" value="'.$object->seuil_stock_alerte.'">';
2301 print '</td>';
2302
2303 print '<td>'.$langs->trans("DesiredStock").'</td><td>';
2304 print '<input name="desiredstock" size="4" value="'.$object->desiredstock.'">';
2305 print '</td></tr>';
2306 */
2307 }
2308
2309 if ($object->isService() && isModEnabled('workstation')) {
2310 // Default workstation
2311 print '<tr><td>'.$langs->trans("DefaultWorkstation").'</td><td>';
2312 print img_picto($langs->trans("DefaultWorkstation"), 'workstation', 'class="pictofixedwidth"');
2313 print $formproduct->selectWorkstations($object->fk_default_workstation, 'fk_default_workstation', 1);
2314 print '</td></tr>';
2315 }
2316
2317 /*
2318 else
2319 {
2320 print '<input name="seuil_stock_alerte" type="hidden" value="'.$object->seuil_stock_alerte.'">';
2321 print '<input name="desiredstock" type="hidden" value="'.$object->desiredstock.'">';
2322 }*/
2323
2324 if ($object->isService()) {
2325 // Duration
2326 print '<tr><td>'.$langs->trans("Duration").'</td><td>';
2327 print '<input name="duration_value" class="width50" value="'.($object->duration_value ? $object->duration_value : '').'"> ';
2328
2329 print $formproduct->selectMeasuringUnits("duration_unit", "time", ($object->duration_unit ? $object->duration_unit : 'h'), 0, 1);
2330
2331 // Mandatory period
2332 //if ($object->duration_value > 0) {
2333 print ' &nbsp; &nbsp; ';
2334 //}
2335 print '<input type="checkbox" class="valignmiddle" id="mandatoryperiod" name="mandatoryperiod"'.($object->mandatory_period == 1 ? ' checked="checked"' : '').'>';
2336 print '<label for="mandatoryperiod">';
2337 $htmltooltip = $langs->trans("mandatoryHelper");
2338 if (!getDolGlobalString('SERVICE_STRICT_MANDATORY_PERIOD')) {
2339 $htmltooltip .= '<br>'.$langs->trans("mandatoryHelper2");
2340 }
2341 print $form->textwithpicto($langs->trans("mandatoryperiod"), $htmltooltip, 1, 'info');
2342 print '</label>';
2343
2344 print '</td></tr>';
2345 } else {
2346 if (!getDolGlobalString('PRODUCT_DISABLE_NATURE')) {
2347 // Nature
2348 print '<tr><td>'.$form->textwithpicto($langs->trans("NatureOfProductShort"), $langs->trans("NatureOfProductDesc")).'</td><td>';
2349 print $formproduct->selectProductNature('finished', (GETPOSTISSET('finished') ? GETPOST('finished') : $object->finished));
2350 print '</td></tr>';
2351 }
2352 }
2353
2354 if (!$object->isService() && isModEnabled('bom')) {
2355 print '<tr><td>'.$form->textwithpicto($langs->trans("DefaultBOM"), $langs->trans("DefaultBOMDesc", $langs->transnoentitiesnoconv("Finished"))).'</td><td>';
2356 $bomkey = "Bom:bom/class/bom.class.php:0:(t.status:=:1) AND (t.fk_product:=:".((int) $object->id).')';
2357 print img_picto($langs->trans("DefaultBOM"), 'bom', 'class="pictofixedwidth"');
2358 print $form->selectForForms($bomkey, 'fk_default_bom', (GETPOSTISSET('fk_default_bom') ? GETPOST('fk_default_bom') : $object->fk_default_bom), 1);
2359 print '</td></tr>';
2360 }
2361
2362 if (!$object->isService()) {
2363 if (!getDolGlobalString('PRODUCT_DISABLE_WEIGHT')) {
2364 // Brut Weight
2365 print '<tr><td>'.$langs->trans("Weight").'</td><td>';
2366 print '<input name="weight" size="5" value="'.(GETPOSTISSET('weight') ? GETPOST('weight') : $object->weight).'"> ';
2367 print $formproduct->selectMeasuringUnits("weight_units", "weight", GETPOSTISSET('weight_units') ? GETPOST('weight_units') : (int) $object->weight_units, 0, 2);
2368 print '</td></tr>';
2369 }
2370
2371 if (!getDolGlobalString('PRODUCT_DISABLE_SIZE')) {
2372 // Brut Length
2373 print '<tr><td>'.$langs->trans("Length").' x '.$langs->trans("Width").' x '.$langs->trans("Height").'</td><td>';
2374 print '<input name="size" size="5" value="'.(GETPOSTISSET('size') ? GETPOST('size') : $object->length).'">x';
2375 print '<input name="sizewidth" size="5" value="'.(GETPOSTISSET('sizewidth') ? GETPOST('sizewidth') : $object->width).'">x';
2376 print '<input name="sizeheight" size="5" value="'.(GETPOSTISSET('sizeheight') ? GETPOST('sizeheight') : $object->height).'"> ';
2377 print $formproduct->selectMeasuringUnits("size_units", "size", GETPOSTISSET('size_units') ? GETPOST('size_units') : (int) $object->length_units, 0, 2);
2378 print '</td></tr>';
2379 }
2380 if (!getDolGlobalString('PRODUCT_DISABLE_SURFACE')) {
2381 // Brut Surface
2382 print '<tr><td>'.$langs->trans("Surface").'</td><td>';
2383 print '<input name="surface" size="5" value="'.(GETPOSTISSET('surface') ? GETPOST('surface') : $object->surface).'"> ';
2384 print $formproduct->selectMeasuringUnits("surface_units", "surface", GETPOSTISSET('surface_units') ? GETPOST('surface_units') : (int) $object->surface_units, 0, 2);
2385 print '</td></tr>';
2386 }
2387 if (!getDolGlobalString('PRODUCT_DISABLE_VOLUME')) {
2388 // Brut Volume
2389 print '<tr><td>'.$langs->trans("Volume").'</td><td>';
2390 print '<input name="volume" size="5" value="'.(GETPOSTISSET('volume') ? GETPOST('volume') : $object->volume).'"> ';
2391 print $formproduct->selectMeasuringUnits("volume_units", "volume", GETPOSTISSET('volume_units') ? GETPOST('volume_units') : (int) $object->volume_units, 0, 2);
2392 print '</td></tr>';
2393 }
2394
2395 if (getDolGlobalString('PRODUCT_ADD_NET_MEASURE')) {
2396 // Net Measure
2397 print '<tr><td>'.$langs->trans("NetMeasure").'</td><td>';
2398 print '<input name="net_measure" size="5" value="'.(GETPOSTISSET('net_measure') ? GETPOST('net_measure') : $object->net_measure).'"> ';
2399 print $formproduct->selectMeasuringUnits("net_measure_units", "", GETPOSTISSET('net_measure_units') ? GETPOST('net_measure_units') : (int) $object->net_measure_units, 0, 0);
2400 print '</td></tr>';
2401 }
2402 }
2403 // Units
2404 if (getDolGlobalString('PRODUCT_USE_UNITS')) {
2405 print '<tr><td>'.$langs->trans('DefaultUnitToShow').'</td>';
2406 print '<td>';
2407 print $form->selectUnits($object->fk_unit, 'units');
2408 print '</td></tr>';
2409 }
2410
2411 // Customs code
2412 if (!$object->isService() && !getDolGlobalString('PRODUCT_DISABLE_CUSTOMS_INFO')) {
2413 print '<tr><td class="wordbreak">'.$form->textwithpicto($langs->trans("CustomsCode"), $langs->trans("CustomsCodeHelp")).'</td><td><input name="customcode" class="maxwidth100onsmartphone" value="'.(GETPOSTISSET('customcode') ? GETPOST('customcode') : $object->customcode).'"></td></tr>';
2414 // Origin country
2415 print '<tr><td>'.$langs->trans("CountryOrigin").'</td>';
2416 print '<td>';
2417 print img_picto('', 'globe-americas', 'class="paddingrightonly"');
2418 print $form->select_country((string) (GETPOSTISSET('country_id') ? GETPOSTINT('country_id') : $object->country_id), 'country_id', '', 0, 'minwidth100 maxwidthonsmartphone');
2419 if ($user->admin) {
2420 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
2421 }
2422 print '</td></tr>';
2423
2424 // State
2425 if (!getDolGlobalString('PRODUCT_DISABLE_STATE')) {
2426 print '<tr>';
2427 if (getDolGlobalString('MAIN_SHOW_REGION_IN_STATE_SELECT') && (getDolGlobalInt('MAIN_SHOW_REGION_IN_STATE_SELECT') == 1 || getDolGlobalInt('MAIN_SHOW_REGION_IN_STATE_SELECT') == 2)) {
2428 print '<td>'.$form->editfieldkey('RegionStateOrigin', 'state_id', '', $object, 0).'</td><td>';
2429 } else {
2430 print '<td>'.$form->editfieldkey('StateOrigin', 'state_id', '', $object, 0).'</td><td>';
2431 }
2432
2433 print img_picto('', 'state', 'class="pictofixedwidth"');
2434 print $formcompany->select_state(GETPOSTISSET('state_id') ? GETPOSTINT('state_id') : $object->state_id, $object->country_code);
2435 print '</td>';
2436 print '</tr>';
2437 }
2438 }
2439
2440 // Quality control
2441 if (getDolGlobalString('PRODUCT_LOT_ENABLE_QUALITY_CONTROL')) {
2442 print '<tr><td>'.$langs->trans("LifeTime").'</td><td><input name="lifetime" class="maxwidth100onsmartphone" value="'.$object->lifetime.'"></td></tr>';
2443 print '<tr><td>'.$langs->trans("QCFrequency").'</td><td><input name="qc_frequency" class="maxwidth100onsmartphone" value="'.$object->qc_frequency.'"></td></tr>';
2444 }
2445
2446 // Other attributes
2447 $parameters = array('colspan' => ' colspan="2"', 'cols' => 2);
2448 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2449 print $hookmanager->resPrint;
2450 if (empty($reshook)) {
2451 print $object->showOptionals($extrafields, 'edit', $parameters);
2452 }
2453
2454 // Tags-Categories
2455 if (isModEnabled('category')) {
2456 print '<tr><td>'.$langs->trans("Categories").'</td><td>';
2457 print $form->selectCategories(Categorie::TYPE_PRODUCT, 'categories', $object);
2458 print "</td></tr>";
2459 }
2460
2461 // Note private
2462 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
2463 print '<tr><td class="tdtop">'.$langs->trans("NoteNotVisibleOnBill").'</td><td>';
2464
2465 $doleditor = new DolEditor('note_private', $object->note_private, '', 140, 'dolibarr_notes', '', false, true, getDolGlobalInt('FCKEDITOR_ENABLE_NOTE_PRIVATE'), ROWS_4, '90%');
2466 $doleditor->Create();
2467
2468 print "</td></tr>";
2469 }
2470
2471 print '</table>';
2472
2473 if (!getDolGlobalString('PRODUCT_DISABLE_ACCOUNTING')) {
2474 print '<hr>';
2475
2476 print '<table class="border centpercent">';
2477
2478 if (isModEnabled('accounting')) {
2480 // Accountancy_code_sell
2481 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellCode").'</td>';
2482 print '<td>';
2483 print $formaccounting->select_account((GETPOSTISSET('accountancy_code_sell') ? GETPOST('accountancy_code_sell') : $object->accountancy_code_sell), 'accountancy_code_sell', 1, array(), 1, 1, 'minwidth150 maxwidth300');
2484 print '</td></tr>';
2485
2486 // Accountancy_code_sell_intra
2487 if ($mysoc->isInEEC()) {
2488 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellIntraCode").'</td>';
2489 print '<td>';
2490 print $formaccounting->select_account((GETPOSTISSET('accountancy_code_sell_intra') ? GETPOST('accountancy_code_sell_intra') : $object->accountancy_code_sell_intra), 'accountancy_code_sell_intra', 1, array(), 1, 1, 'minwidth150 maxwidth300');
2491 print '</td></tr>';
2492 }
2493
2494 // Accountancy_code_sell_export
2495 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellExportCode").'</td>';
2496 print '<td>';
2497 print $formaccounting->select_account((GETPOSTISSET('accountancy_code_sell_export') ? GETPOST('accountancy_code_sell_export') : $object->accountancy_code_sell_export), 'accountancy_code_sell_export', 1, array(), 1, 1, 'minwidth150 maxwidth300');
2498 print '</td></tr>';
2499
2500 // Accountancy_code_buy
2501 print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
2502 print '<td>';
2503 print $formaccounting->select_account((GETPOSTISSET('accountancy_code_buy') ? GETPOST('accountancy_code_buy') : $object->accountancy_code_buy), 'accountancy_code_buy', 1, array(), 1, 1, 'minwidth150 maxwidth300');
2504 print '</td></tr>';
2505
2506 // Accountancy_code_buy_intra
2507 if ($mysoc->isInEEC()) {
2508 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyIntraCode").'</td>';
2509 print '<td>';
2510 print $formaccounting->select_account((GETPOSTISSET('accountancy_code_buy_intra') ? GETPOST('accountancy_code_buy_intra') : $object->accountancy_code_buy_intra), 'accountancy_code_buy_intra', 1, array(), 1, 1, 'minwidth150 maxwidth300');
2511 print '</td></tr>';
2512 }
2513
2514 // Accountancy_code_buy_export
2515 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyExportCode").'</td>';
2516 print '<td>';
2517 print $formaccounting->select_account((GETPOSTISSET('accountancy_code_buy_export') ? GETPOST('accountancy_code_buy_export') : $object->accountancy_code_buy_export), 'accountancy_code_buy_export', 1, array(), 1, 1, 'minwidth150 maxwidth300');
2518 print '</td></tr>';
2519 } else {
2520 // For external software
2521 // Accountancy_code_sell
2522 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellCode").'</td>';
2523 print '<td><input name="accountancy_code_sell" class="maxwidth200" value="'.(GETPOSTISSET('accountancy_code_sell') ? GETPOST('accountancy_code_sell') : $object->accountancy_code_sell).'">';
2524 print '</td></tr>';
2525
2526 // Accountancy_code_sell_intra
2527 if ($mysoc->isInEEC()) {
2528 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellIntraCode").'</td>';
2529 print '<td><input name="accountancy_code_sell_intra" class="maxwidth200" value="'.(GETPOSTISSET('accountancy_code_sell_intra') ? GETPOST('accountancy_code_sell_intra') : $object->accountancy_code_sell_intra).'">';
2530 print '</td></tr>';
2531 }
2532
2533 // Accountancy_code_sell_export
2534 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellExportCode").'</td>';
2535 print '<td><input name="accountancy_code_sell_export" class="maxwidth200" value="'.(GETPOSTISSET('accountancy_code_sell_export') ? GETPOST('accountancy_code_sell_export') : $object->accountancy_code_sell_export).'">';
2536 print '</td></tr>';
2537
2538 // Accountancy_code_buy
2539 print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
2540 print '<td><input name="accountancy_code_buy" class="maxwidth200" value="'.(GETPOSTISSET('accountancy_code_buy') ? GETPOST('accountancy_code_buy') : $object->accountancy_code_buy).'">';
2541 print '</td></tr>';
2542
2543 // Accountancy_code_buy_intra
2544 if ($mysoc->isInEEC()) {
2545 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyIntraCode").'</td>';
2546 print '<td><input name="accountancy_code_buy_intra" class="maxwidth200" value="'.(GETPOSTISSET('accountancy_code_buy_intra') ? GETPOST('accountancy_code_buy_intra') : $object->accountancy_code_buy_intra).'">';
2547 print '</td></tr>';
2548 }
2549
2550 // Accountancy_code_buy_export
2551 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyExportCode").'</td>';
2552 print '<td><input name="accountancy_code_buy_export" class="maxwidth200" value="'.(GETPOSTISSET('accountancy_code_buy_export') ? GETPOST('accountancy_code_buy_export') : $object->accountancy_code_buy_export).'">';
2553 print '</td></tr>';
2554 }
2555
2556 print '</table>';
2557 }
2558 }
2559
2560 print '<script>';
2561 print '$(document).ready(function() {
2562 $("#stockable_product").change(function() {
2563 $(".showifstockable").toggle(this.checked);
2564 });
2565 });';
2566
2567 print '</script>';
2568
2569
2570 print dol_get_fiche_end();
2571
2572 print $form->buttonsSaveCancel();
2573
2574 print '</form>';
2575 } else {
2576 // Card in view mode
2577
2578 $showbarcode = isModEnabled('barcode');
2579 if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('barcode', 'lire_advance')) {
2580 $showbarcode = 0;
2581 }
2582
2584 $titre = $langs->trans("CardProduct".$object->type);
2585 $picto = ($object->type == Product::TYPE_SERVICE ? 'service' : 'product');
2586
2587 print dol_get_fiche_head($head, 'card', $titre, -1, $picto, 0, '', '', 0, '', 1);
2588
2589 $linkback = '<a href="'.DOL_URL_ROOT.'/product/list.php?restore_lastsearch_values=1&type='.$object->type.'">'.$langs->trans("BackToList").'</a>';
2590 $object->next_prev_filter = "(te.fk_product_type:=:".((int) $object->type).")";
2591
2592 $shownav = 1;
2593 if ($user->socid && !in_array('product', explode(',', getDolGlobalString('MAIN_MODULES_FOR_EXTERNAL')))) {
2594 $shownav = 0;
2595 }
2596
2597 dol_banner_tab($object, 'ref', $linkback, $shownav, 'ref');
2598
2599 // Call Hook tabContentViewProduct
2600 $parameters = array();
2601 // Note that $action and $object may be modified by hook
2602 $reshook = $hookmanager->executeHooks('tabContentViewProduct', $parameters, $object, $action);
2603 if (empty($reshook)) {
2604 print '<div class="fichecenter">';
2605 print '<div class="fichehalfleft">';
2606
2607 print '<div class="underbanner clearboth"></div>';
2608 print '<table class="border tableforfield centpercent">';
2609
2610 // Type
2611 if (isModEnabled("product") && isModEnabled("service")) {
2612 $typeformat = 'select;0:'.$langs->trans("Product").',1:'.$langs->trans("Service");
2613 print '<tr><td class="titlefield">';
2614 print (!getDolGlobalString('PRODUCT_DENY_CHANGE_PRODUCT_TYPE')) ? $form->editfieldkey("Type", 'fk_product_type', (string) $object->type, $object, (int) $usercancreate, $typeformat) : $langs->trans('Type');
2615 print '</td><td>';
2616 print $form->editfieldval("Type", 'fk_product_type', $object->type, $object, $usercancreate, $typeformat);
2617 print '</td></tr>';
2618 }
2619
2620 if ($showbarcode) {
2621 // Barcode type
2622 print '<tr><td class="nowrap">';
2623 print '<table width="100%" class="nobordernopadding"><tr><td class="nowrap">';
2624 print $langs->trans("BarcodeType");
2625 print '</td>';
2626 if (($action != 'editbarcodetype') && $usercancreate && $createbarcode) {
2627 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editbarcodetype&id='.$object->id.'&token='.newToken().'">'.img_edit($langs->trans('Edit'), 1).'</a></td>';
2628 }
2629 print '</tr></table>';
2630 print '</td><td>';
2631 if ($action == 'editbarcodetype' || $action == 'editbarcode') {
2632 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formbarcode.class.php';
2633 $formbarcode = new FormBarCode($db);
2634 }
2635
2636 $fk_barcode_type = '';
2637 if ($action == 'editbarcodetype' && is_object($formbarcode)) {
2638 print $formbarcode->formBarcodeType($_SERVER['PHP_SELF'].'?id='.$object->id, $object->barcode_type, 'fk_barcode_type');
2639 $fk_barcode_type = $object->barcode_type;
2640 } else {
2641 $object->fetchBarCode();
2642 $fk_barcode_type = $object->barcode_type;
2643 print $object->barcode_type_label ? $object->barcode_type_label : ($object->barcode ? '<div class="warning">'.$langs->trans("SetDefaultBarcodeType").'<div>' : '');
2644 }
2645 print '</td></tr>'."\n";
2646
2647 // Barcode value
2648 print '<tr><td class="nowrap">';
2649 print '<table width="100%" class="nobordernopadding"><tr><td class="nowrap">';
2650 print $langs->trans("BarcodeValue");
2651 print '</td>';
2652 if (($action != 'editbarcode') && $usercancreate && $createbarcode) {
2653 print '<td class="right"><a class="editfielda" href="'.$_SERVER["PHP_SELF"].'?action=editbarcode&id='.$object->id.'&token='.newToken().'">'.img_edit($langs->trans('Edit'), 1).'</a></td>';
2654 }
2655 print '</tr></table>';
2656 print '</td><td class="wordbreak">';
2657 if ($action == 'editbarcode') {
2658 $tmpcode = GETPOSTISSET('barcode') ? GETPOST('barcode') : $object->barcode;
2659 if (empty($tmpcode) && !empty($modBarCodeProduct->code_auto)) {
2660 $tmpcode = $modBarCodeProduct->getNextValue($object, (string) $fk_barcode_type);
2661 }
2662
2663 print '<form method="post" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">';
2664 print '<input type="hidden" name="token" value="'.newToken().'">';
2665 print '<input type="hidden" name="action" value="setbarcode">';
2666 print '<input type="hidden" name="barcode_type_code" value="'.$object->barcode_type_code.'">';
2667 print '<input class="width300" class="maxwidthonsmartphone" type="text" name="barcode" value="'.$tmpcode.'">';
2668 print '&nbsp;<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
2669 print '</form>';
2670 } else {
2672 }
2673 print '</td></tr>'."\n";
2674 }
2675
2676 // Batch number management (to batch)
2677 if (isModEnabled('productbatch')) {
2678 if ($object->isProduct() || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
2679 print '<tr><td>'.$langs->trans("ManageLotSerial").'</td><td>';
2680 print $object->getLibStatut(0, 2);
2681 print '</td></tr>';
2682 if ((($object->status_batch == '1' && getDolGlobalString('PRODUCTBATCH_LOT_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_LOT_ADDON') == 'mod_lot_advanced')
2683 || ($object->status_batch == '2' && getDolGlobalString('PRODUCTBATCH_SN_ADDON') == 'mod_sn_advanced' && getDolGlobalString('PRODUCTBATCH_SN_USE_PRODUCT_MASKS')))) {
2684 print '<tr><td>'.$langs->trans("ManageLotMask").'</td><td>';
2685 print $object->batch_mask;
2686 print '</td></tr>';
2687 }
2688 }
2689
2690 print '<tr><td>'.$langs->trans('BatchSellOrEatByMandatoryList', $langs->transnoentities('SellByDate'), $langs->transnoentities('EatByDate')).'</td><td>';
2691 print $object->getSellOrEatByMandatoryLabel();
2692 print '</td></tr>';
2693 }
2694
2695 if (!getDolGlobalString('PRODUCT_DISABLE_ACCOUNTING')) {
2696 // Accountancy sell code
2697 print '<tr><td class="nowrap">';
2698 print $langs->trans("ProductAccountancySellCode");
2699 print '</td><td>';
2700 if (isModEnabled('accounting')) {
2701 if (!empty($object->accountancy_code_sell)) {
2702 $accountingaccount = new AccountingAccount($db);
2703 $accountingaccount->fetch(0, $object->accountancy_code_sell, 1);
2704
2705 print $accountingaccount->getNomUrl(0, 1, 1, '', 1);
2706 }
2707 } else {
2708 print $object->accountancy_code_sell;
2709 }
2710 print '</td></tr>';
2711
2712 // Accountancy sell code intra-community
2713 if ($mysoc->isInEEC()) {
2714 print '<tr><td class="nowrap">';
2715 print $langs->trans("ProductAccountancySellIntraCode");
2716 print '</td><td>';
2717 if (isModEnabled('accounting')) {
2718 if (!empty($object->accountancy_code_sell_intra)) {
2719 $accountingaccount2 = new AccountingAccount($db);
2720 $accountingaccount2->fetch(0, $object->accountancy_code_sell_intra, 1);
2721
2722 print $accountingaccount2->getNomUrl(0, 1, 1, '', 1);
2723 }
2724 } else {
2725 print $object->accountancy_code_sell_intra;
2726 }
2727 print '</td></tr>';
2728 }
2729
2730 // Accountancy sell code export
2731 print '<tr><td class="nowrap">';
2732 print $langs->trans("ProductAccountancySellExportCode");
2733 print '</td><td>';
2734 if (isModEnabled('accounting')) {
2735 if (!empty($object->accountancy_code_sell_export)) {
2736 $accountingaccount3 = new AccountingAccount($db);
2737 $accountingaccount3->fetch(0, $object->accountancy_code_sell_export, 1);
2738
2739 print $accountingaccount3->getNomUrl(0, 1, 1, '', 1);
2740 }
2741 } else {
2742 print $object->accountancy_code_sell_export;
2743 }
2744 print '</td></tr>';
2745
2746 // Accountancy buy code
2747 print '<tr><td class="nowrap">';
2748 print $langs->trans("ProductAccountancyBuyCode");
2749 print '</td><td>';
2750 if (isModEnabled('accounting')) {
2751 if (!empty($object->accountancy_code_buy)) {
2752 $accountingaccount4 = new AccountingAccount($db);
2753 $accountingaccount4->fetch(0, $object->accountancy_code_buy, 1);
2754
2755 print $accountingaccount4->getNomUrl(0, 1, 1, '', 1);
2756 }
2757 } else {
2758 print $object->accountancy_code_buy;
2759 }
2760 print '</td></tr>';
2761
2762 // Accountancy buy code intra-community
2763 if ($mysoc->isInEEC()) {
2764 print '<tr><td class="nowrap">';
2765 print $langs->trans("ProductAccountancyBuyIntraCode");
2766 print '</td><td>';
2767 if (isModEnabled('accounting')) {
2768 if (!empty($object->accountancy_code_buy_intra)) {
2769 $accountingaccount5 = new AccountingAccount($db);
2770 $accountingaccount5->fetch(0, $object->accountancy_code_buy_intra, 1);
2771
2772 print $accountingaccount5->getNomUrl(0, 1, 1, '', 1);
2773 }
2774 } else {
2775 print $object->accountancy_code_buy_intra;
2776 }
2777 print '</td></tr>';
2778 }
2779
2780 // Accountancy buy code export
2781 print '<tr><td class="nowrap">';
2782 print $langs->trans("ProductAccountancyBuyExportCode");
2783 print '</td><td>';
2784 if (isModEnabled('accounting')) {
2785 if (!empty($object->accountancy_code_buy_export)) {
2786 $accountingaccount6 = new AccountingAccount($db);
2787 $accountingaccount6->fetch(0, $object->accountancy_code_buy_export, 1);
2788
2789 print $accountingaccount6->getNomUrl(0, 1, 1, '', 1);
2790 }
2791 } else {
2792 print $object->accountancy_code_buy_export;
2793 }
2794 print '</td></tr>';
2795 }
2796
2797 // Description
2798 print '<tr><td class="tdtop">'.$langs->trans("Description").'</td>';
2799 print '<td class="wordbreakimp wrapimp"><div class="longmessagecut">'.(dol_textishtml($object->description) ? $object->description : dol_nl2br($object->description, 1, true)).'</div></td></tr>';
2800
2801 // Public URL
2802 if (!getDolGlobalString('PRODUCT_DISABLE_PUBLIC_URL')) {
2803 print '<tr><td>'.$langs->trans("PublicUrl").'</td><td>';
2804 print dol_print_url($object->url, '_blank', 128);
2805 print '</td></tr>';
2806 }
2807
2808 // Stockable product / default warehouse
2809 if (($object->isProduct() || getDolGlobalInt('STOCK_SUPPORTS_SERVICES')) && isModEnabled('stock')) {
2810 print '<tr><td>' . $form->textwithpicto($langs->trans("StockableProduct"), $langs->trans('StockableProductDescription')) . '</td>';
2811 print '<td><input type="checkbox" readonly disabled '.($object->stockable_product == 1 ? 'checked' : '').'></td></tr>';
2812
2813 if ($object->isStockManaged()) {
2814 $warehouse = new Entrepot($db);
2815 $warehouse->fetch($object->fk_default_warehouse);
2816
2817 print '<tr><td>'.$langs->trans("DefaultWarehouse").'</td><td>';
2818 print(!empty($warehouse->id) ? $warehouse->getNomUrl(1) : '');
2819 print '</td>';
2820 }
2821 }
2822
2823 if ($object->isService() && isModEnabled('workstation')) {
2824 $workstation = new Workstation($db);
2825 $res = $workstation->fetch($object->fk_default_workstation);
2826
2827 print '<tr><td>'.$langs->trans("DefaultWorkstation").'</td><td>';
2828 print(!empty($workstation->id) ? $workstation->getNomUrl(1) : '');
2829 print '</td>';
2830 }
2831
2832 // Parent product.
2833 if (isModEnabled('variants') && ($object->isProduct() || $object->isService())) {
2834 $combination = new ProductCombination($db);
2835
2836 if ($combination->fetchByFkProductChild($object->id) > 0) {
2837 $prodstatic = new Product($db);
2838 $prodstatic->fetch($combination->fk_product_parent);
2839
2840 // Parent product
2841 print '<tr><td>'.$langs->trans("ParentProduct").'</td><td>';
2842 print $prodstatic->getNomUrl(1);
2843 print '</td></tr>';
2844 }
2845 }
2846
2847 print '</table>';
2848
2849 print '</div>';
2850 print '<div class="fichehalfright">';
2851 print '<div class="underbanner clearboth"></div>';
2852
2853 print '<table class="border tableforfield centpercent">';
2854
2855 if ($object->isService()) {
2856 // Duration
2857 require_once DOL_DOCUMENT_ROOT.'/core/class/cunits.class.php';
2858 $measuringUnits = new CUnits($db);
2859 $durations = [];
2860 $plural = '';
2861 if ($object->duration_value > 1) {
2862 $plural = 's';
2863 }
2864 $result = $measuringUnits->fetchAll('', 'scale', 0, 0, ['t.active' => 1, 't.unit_type' => 'time']);
2865 if ($result !== -1) {
2866 foreach ($measuringUnits->records as $record) {
2867 $durations[$record->short_label] = dol_ucfirst($record->label) . $plural;
2868 }
2869 }
2870 print '<tr><td class="titlefieldmiddle">'.$langs->trans("Duration").'</td><td>';
2871 if ($object->duration_value) {
2872 print $object->duration_value;
2873 print(!empty($object->duration_unit) && isset($durations[$object->duration_unit]) ? "&nbsp; ".$langs->trans($durations[$object->duration_unit])."&nbsp;" : '');
2874 }
2875
2876 // Mandatory period
2877 $htmltooltip = $langs->trans("mandatoryHelper");
2878 if (!getDolGlobalString('SERVICE_STRICT_MANDATORY_PERIOD')) {
2879 $htmltooltip .= '<br>'.$langs->trans("mandatoryHelper2");
2880 }
2881 if ($object->duration_value > 0) {
2882 print ' &nbsp; &nbsp; ';
2883 }
2884 print '<input type="checkbox" class="valignmiddle" name="mandatoryperiod"'.($object->mandatory_period == 1 ? ' checked="checked"' : '').' disabled>';
2885 print $form->textwithpicto($langs->trans("mandatoryperiod"), $htmltooltip, 1, 'info');
2886
2887 print '</td></tr>';
2888 } else {
2889 if (!getDolGlobalString('PRODUCT_DISABLE_NATURE')) {
2890 // Nature
2891 print '<tr><td class="titlefieldmiddle">'.$form->textwithpicto($langs->trans("NatureOfProductShort"), $langs->trans("NatureOfProductDesc")).'</td><td>';
2892 print $object->getLibFinished();
2893 print '</td></tr>';
2894 }
2895 }
2896
2897 if (!$object->isService() && isModEnabled('bom') && $object->finished) {
2898 print '<tr><td class="titlefieldmiddle">'.$form->textwithpicto($langs->trans("DefaultBOM"), $langs->trans("DefaultBOMDesc", $langs->transnoentitiesnoconv("Finished"))).'</td><td>';
2899 if ($object->fk_default_bom) {
2900 $bom_static = new BOM($db);
2901 $bom_static->fetch($object->fk_default_bom);
2902 print $bom_static->getNomUrl(1);
2903 }
2904 print '</td></tr>';
2905 }
2906
2907 if (!$object->isService()) {
2908 // Brut Weight
2909 if (!getDolGlobalString('PRODUCT_DISABLE_WEIGHT')) {
2910 print '<tr><td class="titlefieldmiddle">'.$langs->trans("Weight").'</td><td>';
2911 if ($object->weight != '') {
2912 print $object->weight." ".measuringUnitString(0, "weight", $object->weight_units);
2913 } else {
2914 print '&nbsp;';
2915 }
2916 print "</td></tr>\n";
2917 }
2918
2919 if (!getDolGlobalString('PRODUCT_DISABLE_SIZE')) {
2920 // Brut Length
2921 print '<tr><td>'.$langs->trans("Length").' x '.$langs->trans("Width").' x '.$langs->trans("Height").'</td><td>';
2922 if ($object->length != '' || $object->width != '' || $object->height != '') {
2923 print $object->length;
2924 if ($object->width) {
2925 print " x ".$object->width;
2926 }
2927 if ($object->height) {
2928 print " x ".$object->height;
2929 }
2930 print ' '.measuringUnitString(0, "size", $object->length_units);
2931 } else {
2932 print '&nbsp;';
2933 }
2934 print "</td></tr>\n";
2935 }
2936 if (!getDolGlobalString('PRODUCT_DISABLE_SURFACE') || !getDolGlobalString('PRODUCT_DISABLE_VOLUME')) {
2937 // Brut Surface / Volume
2938 print '<tr><td>';
2939 print (getDolGlobalString('PRODUCT_DISABLE_SURFACE') ? '' : $langs->trans("Surface"));
2940 print (!getDolGlobalString('PRODUCT_DISABLE_SURFACE') && !getDolGlobalString('PRODUCT_DISABLE_VOLUME')) ? ' / ' : '';
2941 print (getDolGlobalString('PRODUCT_DISABLE_VOLUME') ? '' : $langs->trans("Volume")).'</td><td>';
2942 if (!getDolGlobalString('PRODUCT_DISABLE_SURFACE') && $object->surface != '') {
2943 print $object->surface." ".measuringUnitString(0, "surface", $object->surface_units);
2944 }
2945 print (!getDolGlobalString('PRODUCT_DISABLE_SURFACE') && !getDolGlobalString('PRODUCT_DISABLE_VOLUME') && $object->surface && $object->volume) ? ' / ' : '';
2946 if (!getDolGlobalString('PRODUCT_DISABLE_VOLUME') && $object->volume != '') {
2947 print $object->volume." ".measuringUnitString(0, "volume", $object->volume_units);
2948 }
2949 print "</td></tr>\n";
2950 }
2951
2952 if (getDolGlobalString('PRODUCT_ADD_NET_MEASURE')) {
2953 // Net Measure
2954 print '<tr><td class="titlefieldmiddle">'.$langs->trans("NetMeasure").'</td><td>';
2955 if ($object->net_measure != '') {
2956 print $object->net_measure." ".measuringUnitString((int) $object->net_measure_units);
2957 } else {
2958 print '&nbsp;';
2959 }
2960 print '</td></tr>';
2961 }
2962 }
2963
2964 // Unit
2965 if (getDolGlobalString('PRODUCT_USE_UNITS')) {
2966 $unit = $object->getLabelOfUnit('long', $langs);
2967
2968 print '<tr><td>'.$langs->trans('DefaultUnitToShow').'</td><td>';
2969 print $unit;
2970 print '</td></tr>';
2971 }
2972
2973 // Custom code
2974 if (!$object->isService() && !getDolGlobalString('PRODUCT_DISABLE_CUSTOMS_INFO')) {
2975 print '<tr><td>'.$form->textwithpicto($langs->trans("CustomsCode"), $langs->trans("CustomsCodeHelp")).'</td><td>'.dolPrintHTML($object->customcode).'</td></tr>';
2976
2977 // Origin country code
2978 print '<tr><td>'.$langs->trans("Origin").'</td><td>'.getCountry($object->country_id, '', $db);
2979 if (!empty($object->state_id)) {
2980 print ' - '.getState($object->state_id, '0', $db);
2981 }
2982 print '</td></tr>';
2983 }
2984
2985 // Quality Control
2986 if (getDolGlobalString('PRODUCT_LOT_ENABLE_QUALITY_CONTROL')) {
2987 print '<tr><td>'.$langs->trans("LifeTime").'</td><td>'.$object->lifetime.'</td></tr>';
2988 print '<tr><td>'.$langs->trans("QCFrequency").'</td><td>'.$object->qc_frequency.'</td></tr>';
2989 }
2990
2991 // Other attributes
2992 $parameters = array();
2993 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
2994
2995 // Categories
2996 if (isModEnabled('category')) {
2997 print '<tr><td class="valignmiddle">'.$langs->trans("Categories").'</td><td>';
2998 print $form->showCategories($object->id, Categorie::TYPE_PRODUCT, 1);
2999 print "</td></tr>";
3000 }
3001
3002 // Note private
3003 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
3004 print '<!-- show Note --> '."\n";
3005 print '<tr><td class="tdtop">'.$langs->trans("NotePrivate").'</td><td>'.(dol_textishtml($object->note_private) ? $object->note_private : dol_nl2br($object->note_private, 1, true)).'</td></tr>'."\n";
3006 print '<!-- End show Note --> '."\n";
3007 }
3008
3009 print "</table>\n";
3010 print '</div>';
3011
3012 print '</div>';
3013 print '<div class="clearboth"></div>';
3014 }
3015
3016 print dol_get_fiche_end();
3017 }
3018 } elseif ($action != 'create') {
3019 exit;
3020 }
3021}
3022
3023$tmpcode = '';
3024if (!empty($modCodeProduct->code_auto)) {
3025 $tmpcode = $modCodeProduct->getNextValue($object, $object->type);
3026}
3027
3028$formconfirm = '';
3029
3030// Confirm delete product
3031if (($action == 'delete' && (empty($conf->use_javascript_ajax) || !empty($conf->dol_use_jmobile))) // Output when action = clone if jmobile or no js
3032 || (!empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile))) { // Always output when not jmobile nor js
3033 $formconfirm = $form->formconfirm("card.php?id=".$object->id, $langs->trans("DeleteProduct"), $langs->trans("ConfirmDeleteProduct"), "confirm_delete", '', 0, "action-delete");
3034}
3035if ($action == 'merge') {
3036 $formquestion = array(
3037 array(
3038 'name' => 'product_origin',
3039 'label' => $langs->trans('MergeOriginProduct'),
3040 'type' => 'other',
3041 'value' => $form->select_produits(0, 'product_origin', '', 0, 0, 1, 2, '', 1, array(), 0, 1, 0, 'minwidth200', 0, '', null, 1),
3042 )
3043 );
3044 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id, $langs->trans("MergeProducts"), $langs->trans("ConfirmMergeProducts"), "confirm_merge", $formquestion, 'no', 1, 250);
3045}
3046
3047// Clone confirmation
3048if (($action == 'clone' && (empty($conf->use_javascript_ajax) || !empty($conf->dol_use_jmobile))) // Output when action = clone if jmobile or no js
3049 || (!empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile))) { // Always output when not jmobile nor js
3050 // Define confirmation messages
3051 $formquestionclone = array(
3052 'text' => $langs->trans("ConfirmClone"),
3053 0 => array('type' => 'text', 'name' => 'clone_ref', 'label' => $langs->trans("NewRefForClone"), 'value' => empty($tmpcode) ? $langs->trans("CopyOf").' '.$object->ref : $tmpcode, 'morecss' => 'width150'),
3054 1 => array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneContentProduct"), 'value' => 1),
3055 2 => array('type' => 'checkbox', 'name' => 'clone_categories', 'label' => $langs->trans("CloneCategoriesProduct"), 'value' => 1),
3056 );
3057 if (getDolGlobalString('PRODUIT_MULTIPRICES')) {
3058 $formquestionclone[] = array('type' => 'checkbox', 'name' => 'clone_prices', 'label' => $langs->trans("ClonePricesProduct").' ('.$langs->trans("CustomerPrices").')', 'value' => 0);
3059 }
3060 if (getDolGlobalString('PRODUIT_SOUSPRODUITS')) {
3061 $formquestionclone[] = array('type' => 'checkbox', 'name' => 'clone_composition', 'label' => $langs->trans('CloneCompositionProduct'), 'value' => 1);
3062 }
3063 if (isModEnabled('bom') && $user->hasRight('bom', 'write')) {
3064 if ($object->fk_default_bom > 0) {
3065 $formquestionclone[] = array('type' => 'checkbox', 'name' => 'clone_defbom', 'label' => $langs->trans("CloneDefBomProduct"), 'value' => getDolGlobalInt('BOM_CLONE_DEFBOM'));
3066 }
3067 $bomstatic = new BOM($db);
3068 $bomlist = $bomstatic->fetchAll("", "", 0, 0, 'fk_product:=:'.(int) $object->id);
3069 if (is_array($bomlist) && count($bomlist) > 0) {
3070 $formquestionclone[] = array('type' => 'checkbox', 'name' => 'clone_otherboms', 'label' => $langs->trans("CloneOtherBomsProduct"), 'value' => 0);
3071 }
3072 }
3073 $formconfirm .= $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id, $langs->trans('ToClone'), $langs->trans('ConfirmCloneProduct', $object->ref), 'confirm_clone', $formquestionclone, 'yes', 'action-clone', 350, 600);
3074}
3075
3076// Call Hook formConfirm
3077$parameters = array('formConfirm' => $formconfirm, 'object' => $object);
3078$reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3079if (empty($reshook)) {
3080 $formconfirm .= $hookmanager->resPrint;
3081} elseif ($reshook > 0) {
3082 $formconfirm = $hookmanager->resPrint;
3083}
3084
3085// Print form confirm
3086print $formconfirm;
3087
3088/*
3089 * Action bar
3090 */
3091if ($action != 'create' && $action != 'edit') {
3092 $cloneProductUrl = $_SERVER["PHP_SELF"].'?action=clone&token='.newToken();
3093 $cloneButtonId = 'action-clone-no-ajax';
3094
3095 print "\n".'<div class="tabsAction">'."\n";
3096
3097 $parameters = array();
3098 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3099 if (empty($reshook)) {
3100 if ($usercancreate) {
3101 if (!isset($hookmanager->resArray['no_button_edit']) || $hookmanager->resArray['no_button_edit'] != 1) {
3102 print dolGetButtonAction('', $langs->trans('Modify'), 'default', $_SERVER["PHP_SELF"].'?action=edit&token='.newToken().'&id='.$object->id, '', $usercancreate);
3103 }
3104
3105 //Send
3106 print dolGetButtonAction('', $langs->trans('SendMail'), 'default', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=presend&mode=init&token=' . newToken() . '#formmailbeforetitle');
3107
3108 if (!isset($hookmanager->resArray['no_button_copy']) || $hookmanager->resArray['no_button_copy'] != 1) {
3109 if (!empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile)) {
3110 $cloneProductUrl = '';
3111 $cloneButtonId = 'action-clone';
3112 }
3113 print dolGetButtonAction($langs->trans('ToClone'), '', 'default', $cloneProductUrl, $cloneButtonId, $usercancreate);
3114 }
3115 }
3116 $object_is_used = $object->isObjectUsed($object->id);
3117
3118 if ($usercandelete) {
3119 if (empty($object_is_used)) {
3120 if (!isset($hookmanager->resArray['no_button_delete']) || $hookmanager->resArray['no_button_delete'] != 1) {
3121 if (!empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile)) {
3122 print dolGetButtonAction($langs->trans('Delete'), '', 'delete', '#', 'action-delete', true);
3123 } else {
3124 print dolGetButtonAction('', $langs->trans('Delete'), 'delete', $_SERVER["PHP_SELF"].'?action=delete&token='.newToken().'&id='.$object->id, '');
3125 }
3126 }
3127 } else {
3128 print dolGetButtonAction($langs->trans("ProductIsUsed"), $langs->trans('Delete'), 'delete', '#', '', false);
3129 }
3130 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') > 1) {
3131 print '<a class="butActionDelete" href="card.php?action=merge&id='.$object->id.'" title="'.dol_escape_htmltag($langs->trans("MergeProducts")).'">'.$langs->trans('Merge').'</a>'."\n";
3132 }
3133 } else {
3134 print dolGetButtonAction($langs->trans("NotEnoughPermissions"), $langs->trans('Delete'), 'delete', '#', '', false);
3135 }
3136 }
3137
3138 print "\n</div>\n";
3139}
3140
3141
3142/*
3143 * All the "Add to" areas if PRODUCT_ADD_FORM_ADD_TO is set
3144 */
3145
3146if (getDolGlobalString('PRODUCT_ADD_FORM_ADD_TO') && $object->id && ($action == '' || $action == 'view') && $object->status) {
3147 //Variable used to check if any text is going to be printed
3148 $html = '';
3149 //print '<div class="fichecenter"><div class="fichehalfleft">';
3150
3151 // Propals
3152 if (isModEnabled("propal") && $user->hasRight('propal', 'creer')) {
3153 $propal = new Propal($db);
3154
3155 $langs->load("propal");
3156
3157 $otherprop = $propal->liste_array(2, 1, 0);
3158
3159 if (is_array($otherprop) && count($otherprop)) {
3160 $html .= '<tr><td style="width: 200px;">';
3161 $html .= $langs->trans("AddToDraftProposals").'</td><td>';
3162 $html .= $form->selectarray("propalid", $otherprop, 0, 1);
3163 $html .= '</td></tr>';
3164 } else {
3165 $html .= '<tr><td style="width: 200px;">';
3166 $html .= $langs->trans("AddToDraftProposals").'</td><td>';
3167 $html .= $langs->trans("NoDraftProposals");
3168 $html .= '</td></tr>';
3169 }
3170 }
3171
3172 // Commande
3173 if (isModEnabled('order') && $user->hasRight('commande', 'creer')) {
3174 $commande = new Commande($db);
3175
3176 $langs->load("orders");
3177
3178 $othercom = $commande->liste_array(2, 1, null);
3179 if (is_array($othercom) && count($othercom)) {
3180 $html .= '<tr><td style="width: 200px;">';
3181 $html .= $langs->trans("AddToDraftOrders").'</td><td>';
3182 $html .= $form->selectarray("commandeid", $othercom, 0, 1);
3183 $html .= '</td></tr>';
3184 } else {
3185 $html .= '<tr><td style="width: 200px;">';
3186 $html .= $langs->trans("AddToDraftOrders").'</td><td>';
3187 $html .= $langs->trans("NoDraftOrders");
3188 $html .= '</td></tr>';
3189 }
3190 }
3191
3192 // Factures
3193 if (isModEnabled('invoice') && $user->hasRight('facture', 'creer')) {
3194 $invoice = new Facture($db);
3195
3196 $langs->load("bills");
3197
3198 $otherinvoice = $invoice->liste_array(2, 1, null);
3199 if (is_array($otherinvoice) && count($otherinvoice)) {
3200 $html .= '<tr><td style="width: 200px;">';
3201 $html .= $langs->trans("AddToDraftInvoices").'</td><td>';
3202 $html .= $form->selectarray("factureid", $otherinvoice, 0, 1);
3203 $html .= '</td></tr>';
3204 } else {
3205 $html .= '<tr><td style="width: 200px;">';
3206 $html .= $langs->trans("AddToDraftInvoices").'</td><td>';
3207 $html .= $langs->trans("NoDraftInvoices");
3208 $html .= '</td></tr>';
3209 }
3210 }
3211
3212 // If any text is going to be printed, then we show the table
3213 if (!empty($html)) {
3214 print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">';
3215 print '<input type="hidden" name="token" value="'.newToken().'">';
3216 print '<input type="hidden" name="action" value="addin">';
3217
3218 print load_fiche_titre($langs->trans("AddToDraft"), '', '');
3219
3220 print dol_get_fiche_head();
3221
3222 $html .= '<tr><td class="nowrap">'.$langs->trans("Quantity").' ';
3223 $html .= '<input type="text" class="flat" name="qty" size="1" value="1"></td>';
3224 $html .= '<td class="nowrap">'.$langs->trans("ReductionShort").'(%) ';
3225 $html .= '<input type="text" class="flat" name="remise_percent" size="1" value="0">';
3226 $html .= '</td></tr>';
3227
3228 print '<table class="centpercent border">';
3229 print $html;
3230 print '</table>';
3231
3232 print '<div class="center">';
3233 print '<input type="submit" class="button button-add" value="'.$langs->trans("Add").'">';
3234 print '</div>';
3235
3236 print dol_get_fiche_end();
3237
3238 print '</form>';
3239 }
3240}
3241
3242
3243/*
3244 * Generated documents
3245 */
3246
3247if (GETPOST('modelselected')) {
3248 $action = 'presend';
3249}
3250
3251if ($action != 'create' && $action != 'edit' && $action != 'delete') {
3252 print '<div class="fichecenter"><div class="fichehalfleft">';
3253 print '<a name="builddoc"></a>'; // ancre
3254
3255 // Documents
3256 $objectref = dol_sanitizeFileName($object->ref);
3257 if (!empty($conf->product->multidir_output[$object->entity])) {
3258 $filedir = $conf->product->multidir_output[$object->entity].'/'.$objectref; //Check repertories of current entities
3259 } else {
3260 $filedir = $conf->product->dir_output.'/'.$objectref;
3261 }
3262 $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
3263 $genallowed = $usercanread;
3264 $delallowed = $usercancreate;
3265
3266 print $formfile->showdocuments($modulepart, $object->ref, $filedir, $urlsource, (int) $genallowed, (int) $delallowed, '', 0, 0, 0, 28, 0, '', '', '', $langs->getDefaultLang(), '', $object);
3267 $somethingshown = $formfile->numoffiles;
3268
3269 print '</div><div class="fichehalfright">';
3270
3271 $MAXEVENT = 10;
3272 $morehtmlcenter = '<div class="nowraponall">';
3273 $morehtmlcenter .= dolGetButtonTitle($langs->trans('FullConversation'), '', 'fa fa-comments imgforviewmode', DOL_URL_ROOT.'/product/messaging.php?id='.$object->id);
3274 $morehtmlcenter .= dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/product/agenda.php?id='.$object->id);
3275 $morehtmlcenter .= '</div>';
3276
3277 // List of actions on element
3278 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
3279 $formactions = new FormActions($db);
3280 $somethingshown = $formactions->showactions($object, 'product', 0, 1, '', $MAXEVENT, '', $morehtmlcenter); // Show all action for product
3281
3282 print '</div></div>';
3283
3284 // Presend form
3285 $modelmail = 'product_send';
3286 $defaulttopic = $object->label;
3287 $diroutput = $conf->product->multidir_output[$object->entity];
3288 $trackid = 'prod' . $object->id;
3289
3290 include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
3291}
3292
3293// End of page
3294llxFooter();
3295$db->close();
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:48
if( $user->socid > 0) if(! $user->hasRight('accounting', 'chartofaccount')) $object
Definition card.php:67
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='')
Convert a html select field into an ajax combobox.
Definition ajax.lib.php:475
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:91
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:73
$object ref
Definition info.php:90
Class to manage accounting accounts.
Class for BOM.
Definition bom.class.php:42
Class of dictionary type of thirdparty (used by imports)
Class to manage canvas.
Class to manage categories.
Class to manage customers orders.
Class to manage a WYSIWYG editor.
Class to manage warehouses.
Class to manage standard extra fields.
Class to manage invoices.
const TYPE_STANDARD
Standard invoice.
Class to manage generation of HTML components for accounting management.
Class to manage building of HTML components.
Class to manage barcode HTML.
Class to build HTML component for third parties management Only common components are here.
Class to offer components to list and upload files.
Class to manage generation of HTML components Only common components must be here.
Class with static methods for building HTML components related to products Only components common to ...
Class of a generic business object.
Class ProductCombination Used to represent the relation between a product and one of its variants.
File of class to manage predefined price products or services by customer.
Class to manage products or services.
const TYPE_PRODUCT
Regular product.
static getSellOrEatByMandatoryList()
Get the array of labels of Sell by or Eat by all mandatory flags for each status.
const TYPE_SERVICE
Service.
Class to manage proposals.
Class to manage third parties objects (customers, suppliers, prospects...)
Class for Workstation.
getCountry($searchkey, $withcode='', $dbtouse=null, $outputlangs=null, $entconv=1, $searchlabel='')
Return country label, code or id from an id, code or label.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
dol_move($srcfile, $destfile, $newmask='0', $overwriteifexists=1, $testvirus=0, $indexdatabase=1, $moreinfo=array(), $entity=0)
Move a file into another name.
dol_dir_list($utf8_path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0, $nbsecondsold=0)
Scan a directory and return a list of files/directories.
Definition files.lib.php:63
dol_is_dir($folder)
Test if filename is a directory.
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='')
Load a title with picto.
setEventMessages($mesg, $mesgs, $style='mesgs', $messagekey='', $noduplicate=0, $attop=0)
Set event messages in dol_events session object.
dol_ucfirst($string, $encoding="UTF-8")
Convert first character of the first word of a string to upper.
showValueWithClipboardCPButton($valuetocopy, $showonlyonhover=1, $texttoshow='')
Create a button to copy $valuetocopy in the clipboard (for copy and paste feature).
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
img_warning($titlealt='default', $moreatt='', $morecss='pictowarning')
Show warning logo.
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
dolPrintHTML($s, $allowiframe=0)
Return a string (that can be on several lines) ready to be output on a HTML page.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
dolGetButtonTitle($label, $helpText='', $iconClass='fa fa-file', $url='', $id='', $status=1, $params=array())
Function dolGetButtonTitle : this kind of buttons are used in title in list.
dol_get_fiche_end($notab=0)
Return tab footer of a card.
dol_eval($s, $returnvalue=1, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
dol_nl2br($stringtoencode, $nl2brmode=0, $forxml=false)
Replace CRLF in string with a HTML BR tag.
dol_print_url($url, $target='_blank', $max=32, $withpicto=0, $morecss='')
Show Url link.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_now($mode='auto')
Return date for now.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
if(!function_exists( 'dol_getprefix')) dol_include_once($relpath, $classname='')
Make an include_once using default root and alternate root if it fails.
dol_set_focus($selector)
Set focus onto field with selector (similar behaviour of 'autofocus' HTML5 tag)
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dolGetButtonAction($label, $text='', $actionType='default', $url='', $id='', $userRight=1, $params=array())
Function dolGetButtonAction.
dol_htmlcleanlastbr($stringtodecode)
This function remove all ending and br at end.
get_default_npr(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that returns whether VAT must be recoverable collected VAT (e.g.: VAT NPR in France)
dol_concatdesc($text1, $text2, $forxml=false, $invert=false)
Concat 2 descriptions with a new line between them (second operand after first one with appropriate n...
dol_textishtml($msg, $option=0)
Return if a text is a html content.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
GETPOSTFLOAT($paramname, $rounding='')
Return the value of a $_GET or $_POST supervariable, converted into float.
dol_clone($object, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_trunc($string, $size=40, $trunc='right', $stringencoding='UTF-8', $nodot=0, $display=0)
Truncate a string to a particular length adding '…' if string larger than length.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0)
Clean a string to use it as a file name.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
info_admin($text, $infoonimgalt=0, $nodiv=0, $admin='1', $morecss='hideonsmartphone', $textfordropdown='', $picto='')
Show information in HTML for admin users or standard users.
img_edit($titlealt='default', $float=0, $other='')
Show logo edit/modify fiche.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_localtax($vatrate, $local, $thirdparty_buyer=null, $thirdparty_seller=null, $vatnpr=0)
Return localtax rate for a particular vat, when selling a product with vat $vatrate,...
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
measuringUnitString($unitid, $measuring_style='', $unitscale=null, $use_short_label=0, $outputlangs=null)
Return translation label of a unit key.
product_prepare_head($object)
Prepare array with list of tabs.
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.