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 // Delete the product
415 if ($productOrigin->delete($user) < 1) {
416 $error++;
417 }
418 }
419
420 if ($error) {
421 // Move files from the dir of the third party to delete into the dir of the third party to keep
422 if (!empty($conf->product->multidir_output[$productOrigin->entity])) {
423 $srcdir = $conf->product->multidir_output[$productOrigin->entity]."/".$productOrigin->ref;
424 $destdir = $conf->product->multidir_output[$object->entity]."/".$object->ref;
425
426 if (dol_is_dir($srcdir)) {
427 $dirlist = dol_dir_list($srcdir, 'files', 1);
428 foreach ($dirlist as $filetomove) {
429 $destfile = $destdir.'/'.$filetomove['relativename'];
430 //var_dump('Move file '.$filetomove['relativename'].' into '.$destfile);
431 dol_move($filetomove['fullname'], $destfile, '0', 0, 0, 1);
432 }
433 //exit;
434 }
435 }
436 }
437
438 if (!$error) {
439 setEventMessages($langs->trans('ProductsMergeSuccess'), null, 'mesgs');
440 $db->commit();
441 } else {
442 $langs->load("errors");
443 setEventMessages($langs->trans('ErrorsProductsMerge'), null, 'errors');
444 $db->rollback();
445 }
446 }
447 }
448 }
449
450 // Type
451 if ($action == 'setfk_product_type' && $usercancreate) {
452 $result = $object->setValueFrom('fk_product_type', GETPOST('fk_product_type'), '', null, 'text', '', $user, 'PRODUCT_MODIFY');
453 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
454 exit;
455 }
456
457 // Actions to build doc
458 $upload_dir = $conf->product->dir_output;
459 $permissiontoadd = $usercancreate;
460 include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
461
462 include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
463
464 // Barcode type
465 if ($action == 'setfk_barcode_type' && $usercancreate) {
466 $result = $object->setValueFrom('fk_barcode_type', GETPOST('fk_barcode_type'), '', null, 'text', '', $user, 'PRODUCT_MODIFY');
467 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
468 exit;
469 }
470
471 // Barcode value
472 if ($action == 'setbarcode' && $usercancreate) {
473 $result = $object->check_barcode(GETPOST('barcode'), GETPOST('barcode_type_code'));
474
475 if ($result >= 0) {
476 $result = $object->setValueFrom('barcode', GETPOST('barcode'), '', null, 'text', '', $user, 'PRODUCT_MODIFY');
477 header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
478 exit;
479 } else {
480 $langs->load("errors");
481 if ($result == -1) {
482 $errors[] = 'ErrorBadBarCodeSyntax';
483 } elseif ($result == -2) {
484 $errors[] = 'ErrorBarCodeRequired';
485 } elseif ($result == -3) {
486 $errors[] = 'ErrorBarCodeAlreadyUsed';
487 } else {
488 $errors[] = 'FailedToValidateBarCode';
489 }
490
491 $error++;
492 setEventMessages('', $errors, 'errors');
493 }
494 }
495
496 // Quick edit for extrafields
497 if ($action == 'update_extras' && $permissiontoeditextra) {
498 // we may use oldcopy->hasBatch( in triggers so keep 1
499 $object->oldcopy = dol_clone($object, 1); // @phan-suppress-current-line PhanTypeMismatchProperty
500
501 $attribute_name = GETPOST('attribute', 'aZ09');
502
503 // Fill array 'array_options' with data from update form
504 $ret = $extrafields->setOptionalsFromPost(null, $object, $attribute_name);
505 if ($ret < 0) {
506 $error++;
507 }
508
509 if (!$error) {
510 $result = $object->updateExtraField($attribute_name, 'PRODUCT_MODIFY');
511 if ($result < 0) {
512 setEventMessages($object->error, $object->errors, 'errors');
513 $error++;
514 }
515 }
516
517 if ($error) {
518 $action = 'edit_extras';
519 }
520 }
521
522 // Add a product or service
523 if ($action == 'add' && $usercancreate) {
524 $error = 0;
525
526 if (!GETPOST('label', $label_security_check)) {
527 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentities('Label')), null, 'errors');
528 $action = "create";
529 $error++;
530 }
531 if (empty($ref)) {
532 if (!getDolGlobalString('PRODUCT_GENERATE_REF_AFTER_FORM')) {
533 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentities('ProductRef')), null, 'errors');
534 $action = "create";
535 $error++;
536 }
537 }
538 if (!empty($duration_value) && empty($duration_unit)) {
539 setEventMessages($langs->trans('ErrorFieldRequired', $langs->transnoentities('Unit')), null, 'errors');
540 $action = "create";
541 $error++;
542 }
543 $stockable_product = (int) ($type == 0 || ($type == 1 && getDolGlobalInt('STOCK_SUPPORTS_SERVICES')));
544 if (GETPOST('status_batch') && $stockable_product == 0 && isModEnabled('stock') && isModEnabled('productbatch')) {
545 setEventMessages($langs->trans('ErrorBatchesNeedStockManagement'), null, 'errors');
546 $action = "create";
547 $error++;
548 }
549
550 if (!$error) {
551 $units = GETPOSTINT('units');
552
553 $object->entity = $conf->entity;
554 $object->ref = (string) $ref;
555 $object->label = GETPOST('label', $label_security_check);
556 $object->price_base_type = GETPOST('price_base_type', 'aZ09');
557 $object->mandatory_period = empty(GETPOST("mandatoryperiod", 'alpha')) ? 0 : 1;
558 if ($object->price_base_type == 'TTC') {
559 $object->price_ttc = GETPOSTFLOAT('price');
560 } else {
561 $object->price = GETPOSTFLOAT('price');
562 }
563 if ($object->price_base_type == 'TTC') {
564 $object->price_min_ttc = GETPOSTFLOAT('price_min');
565 } else {
566 $object->price_min = GETPOSTFLOAT('price_min');
567 }
568
569 $tva_tx_txt = GETPOST('tva_tx', 'alpha'); // tva_tx can be '8.5' or '8.5*' or '8.5 (XXX)' or '8.5* (XXX)'
570
571 // We must define tva_tx, npr and local taxes
572 $vatratecode = '';
573 $tva_tx = preg_replace('/[^0-9\.].*$/', '', $tva_tx_txt); // keep remove all after the numbers and dot
574 $npr = preg_match('/\*/', $tva_tx_txt) ? 1 : 0;
575 $localtax1 = 0;
576 $localtax2 = 0;
577 $localtax1_type = '0';
578 $localtax2_type = '0';
579 // If value contains the unique code of vat line (new recommended method), we use it to find npr and local taxes
580 $reg = array();
581 if (preg_match('/\‍((.*)\‍)/', $tva_tx_txt, $reg)) {
582 // 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.
583 $vatratecode = $reg[1];
584 // Get record from code
585 $sql = "SELECT t.rowid, t.code, t.recuperableonly, t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
586 $sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
587 $sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($mysoc->country_code)."'";
588 $sql .= " AND t.taux = ".((float) $tva_tx)." AND t.active = 1";
589 $sql .= " AND t.code = '".$db->escape($vatratecode)."'";
590 $sql .= " AND t.entity IN (".getEntity('c_tva').")";
591 $resql = $db->query($sql);
592 if ($resql) {
593 $obj = $db->fetch_object($resql);
594 $npr = $obj->recuperableonly;
595 $localtax1 = $obj->localtax1;
596 $localtax2 = $obj->localtax2;
597 $localtax1_type = $obj->localtax1_type;
598 $localtax2_type = $obj->localtax2_type;
599 }
600 }
601
602 $object->default_vat_code = $vatratecode;
603 $object->tva_tx = $tva_tx;
604 $object->tva_npr = $npr;
605 $object->localtax1_tx = $localtax1;
606 $object->localtax2_tx = $localtax2;
607 $object->localtax1_type = $localtax1_type;
608 $object->localtax2_type = $localtax2_type;
609
610 $object->type = $type;
611 $object->status = GETPOSTINT('statut');
612 $object->status_buy = GETPOSTINT('statut_buy');
613 $object->status_batch = GETPOSTINT('status_batch');
614 $object->sell_or_eat_by_mandatory = GETPOSTINT('sell_or_eat_by_mandatory');
615 $object->batch_mask = GETPOST('batch_mask');
616
617 $object->barcode_type = GETPOSTINT('fk_barcode_type');
618 $object->barcode = GETPOST('barcode');
619 // Set barcode_type_xxx from barcode_type id
620 $stdobject = new GenericObject($db);
621 $stdobject->element = 'product';
622 $stdobject->barcode_type = GETPOSTINT('fk_barcode_type');
623 $result = $stdobject->fetchBarCode();
624 if ($result < 0) {
625 $error++;
626 $mesg = 'Failed to get bar code type information ';
627 setEventMessages($mesg.$stdobject->error, $stdobject->errors, 'errors');
628 }
629 $object->barcode_type_code = $stdobject->barcode_type_code;
630 $object->barcode_type_coder = $stdobject->barcode_type_coder;
631 $object->barcode_type_label = $stdobject->barcode_type_label;
632
633 $object->description = dol_htmlcleanlastbr(GETPOST('desc', 'restricthtml'));
634 $object->url = GETPOST('url');
635 $object->note_private = dol_htmlcleanlastbr(GETPOST('note_private', 'restricthtml'));
636 $object->note = $object->note_private; // deprecated
637 $object->customcode = GETPOST('customcode', 'alphanohtml');
638 $object->country_id = GETPOSTINT('country_id');
639 $object->state_id = GETPOSTINT('state_id');
640 $object->lifetime = GETPOSTINT('lifetime');
641 $object->qc_frequency = GETPOSTINT('qc_frequency');
642 $object->duration_value = $duration_value;
643 $object->duration_unit = $duration_unit;
644 $object->fk_default_warehouse = GETPOSTINT('fk_default_warehouse');
645 $object->fk_default_workstation = GETPOSTINT('fk_default_workstation');
646 $object->seuil_stock_alerte = GETPOST('seuil_stock_alerte') ? GETPOST('seuil_stock_alerte') : 0;
647 $object->desiredstock = GETPOST('desiredstock') ? GETPOST('desiredstock') : 0;
648 $object->canvas = GETPOST('canvas');
649 $object->net_measure = GETPOST('net_measure');
650 $object->net_measure_units = GETPOST('net_measure_units') === '' ? null : GETPOSTINT('net_measure_units'); // This is not the fk_unit but the power of unit
651 $object->weight = GETPOST('weight');
652 $object->weight_units = GETPOST('weight_units'); // This is not the fk_unit but the power of unit
653 $object->length = GETPOST('size');
654 $object->length_units = GETPOST('size_units'); // This is not the fk_unit but the power of unit
655 $object->width = GETPOST('sizewidth');
656 $object->height = GETPOST('sizeheight');
657 $object->surface = GETPOST('surface');
658 $object->surface_units = GETPOST('surface_units'); // This is not the fk_unit but the power of unit
659 $object->volume = GETPOST('volume');
660 $object->volume_units = GETPOST('volume_units'); // This is not the fk_unit but the power of unit
661 $finished = GETPOSTINT('finished');
662 if ($finished >= 0) {
663 $object->finished = $finished;
664 } else {
665 $object->finished = null;
666 }
667
668 $units = GETPOSTINT('units');
669 if ($units > 0) {
670 $object->fk_unit = $units;
671 } else {
672 $object->fk_unit = null;
673 }
674
675 $object->stockable_product = $stockable_product;
676
677 $accountancy_code_sell = GETPOST('accountancy_code_sell', 'alpha');
678 $accountancy_code_sell_intra = GETPOST('accountancy_code_sell_intra', 'alpha');
679 $accountancy_code_sell_export = GETPOST('accountancy_code_sell_export', 'alpha');
680 $accountancy_code_buy = GETPOST('accountancy_code_buy', 'alpha');
681 $accountancy_code_buy_intra = GETPOST('accountancy_code_buy_intra', 'alpha');
682 $accountancy_code_buy_export = GETPOST('accountancy_code_buy_export', 'alpha');
683
684 if (empty($accountancy_code_sell) || $accountancy_code_sell == '-1') {
685 $object->accountancy_code_sell = '';
686 } else {
687 $object->accountancy_code_sell = $accountancy_code_sell;
688 }
689 if (empty($accountancy_code_sell_intra) || $accountancy_code_sell_intra == '-1') {
690 $object->accountancy_code_sell_intra = '';
691 } else {
692 $object->accountancy_code_sell_intra = $accountancy_code_sell_intra;
693 }
694 if (empty($accountancy_code_sell_export) || $accountancy_code_sell_export == '-1') {
695 $object->accountancy_code_sell_export = '';
696 } else {
697 $object->accountancy_code_sell_export = $accountancy_code_sell_export;
698 }
699 if (empty($accountancy_code_buy) || $accountancy_code_buy == '-1') {
700 $object->accountancy_code_buy = '';
701 } else {
702 $object->accountancy_code_buy = $accountancy_code_buy;
703 }
704 if (empty($accountancy_code_buy_intra) || $accountancy_code_buy_intra == '-1') {
705 $object->accountancy_code_buy_intra = '';
706 } else {
707 $object->accountancy_code_buy_intra = $accountancy_code_buy_intra;
708 }
709 if (empty($accountancy_code_buy_export) || $accountancy_code_buy_export == '-1') {
710 $object->accountancy_code_buy_export = '';
711 } else {
712 $object->accountancy_code_buy_export = $accountancy_code_buy_export;
713 }
714
715 // MultiPrix
716 if (getDolGlobalString('PRODUIT_MULTIPRICES')) {
717 $produit_multiprices_limit = getDolGlobalString('PRODUIT_MULTIPRICES_LIMIT');
718 for ($i = 2; $i <= $produit_multiprices_limit; $i++) {
719 if (GETPOSTISSET("price_".$i)) {
720 $object->multiprices["$i"] = price2num(GETPOST("price_".$i), 'MU');
721 $object->multiprices_base_type["$i"] = GETPOST("multiprices_base_type_".$i);
722 } else {
723 $object->multiprices["$i"] = "";
724 }
725 }
726 }
727
728 // Fill array 'array_options' with data from add form
729 $ret = $extrafields->setOptionalsFromPost(null, $object);
730 if ($ret < 0) {
731 $error++;
732 }
733
734 if (!$ref && getDolGlobalString('PRODUCT_GENERATE_REF_AFTER_FORM')) {
735 // Generate ref...
736 '@phan-var ModeleProductCode $modCodeProduct';
737 $ref = $modCodeProduct->getNextValue($object, $type);
738 }
739
740 if (!$error) {
741 $id = $object->create($user);
742 }
743
744 if ($id > 0) {
745 // Category association
746 $categories = GETPOST('categories', 'array');
747 $object->setCategories($categories);
748
749 if (!empty($backtopage)) {
750 $backtopage = preg_replace('/__ID__/', (string) $object->id, $backtopage); // New method to autoselect parent project after a New on another form object creation
751 $backtopage = preg_replace('/--IDFORBACKTOPAGE--/', (string) $object->id, $backtopage); // New method to autoselect parent after a New on another form object creation
752 if (preg_match('/\?/', $backtopage)) {
753 $backtopage .= '&productid='.$object->id; // Old method
754 }
755
756 header("Location: ".$backtopage);
757 exit;
758 } else {
759 header("Location: ".$_SERVER['PHP_SELF']."?id=".$id);
760 exit;
761 }
762 } else {
763 if (count($object->errors)) {
764 setEventMessages($object->error, $object->errors, 'errors');
765 } else {
766 if ($object->error == 'ErrorProductAlreadyExists') {
767 // allow to hook on ErrorProductAlreadyExists in any module
768 $reshook = $hookmanager->executeHooks('onProductAlreadyExists', $parameters, $object, $action);
769 if ($reshook < 0) {
770 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
771 }
772 if ($object->error) {
773 // check again to prevent translation issue,
774 // as error may have been cleared in hook function
775 setEventMessages($langs->trans($object->error), null, 'errors');
776 }
777 } else {
778 setEventMessages($langs->trans($object->error), null, 'errors');
779 }
780 }
781 $action = "create";
782 }
783 }
784 }
785
786 // Update a product or service
787 if ($action == 'update' && $usercancreate) {
788 if (GETPOST('cancel', 'alpha')) {
789 $action = '';
790 } else {
791 if ($object->id > 0) {
792 // Need dol_clone methode 1 (same object class) because update product use hasbatch() method on oldcopy
793 $object->oldcopy = dol_clone($object, 1); // @phan-suppress-current-line PhanTypeMismatchProperty
794
795 if (!getDolGlobalString('PRODUCT_GENERATE_REF_AFTER_FORM')) {
796 $object->ref = (string) $ref;
797 }
798 $object->label = GETPOST('label', $label_security_check);
799
800 $desc = dol_htmlcleanlastbr(preg_replace('/&nbsp;$/', '', GETPOST('desc', 'restricthtml')));
801 $object->description = $desc;
802
803 $object->url = GETPOST('url');
804 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
805 $object->note_private = dol_htmlcleanlastbr(GETPOST('note_private', 'restricthtml'));
806 $object->note = $object->note_private;
807 }
808 $object->customcode = GETPOST('customcode', 'alpha');
809 $object->country_id = GETPOSTINT('country_id');
810 $object->state_id = GETPOSTINT('state_id');
811 $object->lifetime = GETPOSTINT('lifetime');
812 $object->qc_frequency = GETPOSTINT('qc_frequency');
813 $object->status = GETPOSTINT('statut');
814 $object->status_buy = GETPOSTINT('statut_buy');
815 $object->status_batch = GETPOSTINT('status_batch');
816 $object->sell_or_eat_by_mandatory = GETPOSTINT('sell_or_eat_by_mandatory');
817 $object->batch_mask = GETPOST('batch_mask', 'alpha');
818 $object->fk_default_warehouse = GETPOSTINT('fk_default_warehouse');
819 $object->fk_default_workstation = GETPOSTINT('fk_default_workstation');
820 // removed from update view so GETPOST always empty
821 /*
822 $object->seuil_stock_alerte = GETPOST('seuil_stock_alerte');
823 $object->desiredstock = GETPOST('desiredstock');
824 */
825 $object->duration_value = GETPOST('duration_value');
826 $object->duration_unit = GETPOST('duration_unit', 'alpha');
827
828 $object->canvas = GETPOST('canvas');
829 $object->net_measure = GETPOST('net_measure');
830 $object->net_measure_units = GETPOST('net_measure_units') === '' ? null : GETPOSTINT('net_measure_units'); // This is not the fk_unit but the power of unit
831 $object->weight = GETPOST('weight');
832 $object->weight_units = GETPOST('weight_units'); // This is not the fk_unit but the power of unit
833 $object->length = GETPOST('size');
834 $object->length_units = GETPOST('size_units'); // This is not the fk_unit but the power of unit
835 $object->width = GETPOST('sizewidth');
836 $object->height = GETPOST('sizeheight');
837
838 $object->surface = GETPOST('surface');
839 $object->surface_units = GETPOST('surface_units'); // This is not the fk_unit but the power of unit
840 $object->volume = GETPOST('volume');
841 $object->volume_units = GETPOST('volume_units'); // This is not the fk_unit but the power of unit
842
843 $finished = GETPOSTINT('finished');
844 if ($finished >= 0) {
845 $object->finished = $finished;
846 } else {
847 $object->finished = null;
848 }
849
850 $fk_default_bom = GETPOSTINT('fk_default_bom');
851 if ($fk_default_bom >= 0) {
852 $object->fk_default_bom = $fk_default_bom;
853 } else {
854 $object->fk_default_bom = 0;
855 }
856
857 // managed_in_stock
858 $object->stockable_product = (int) GETPOSTISSET('stockable_product');
859 if ($object->status_batch > 0 && $object->stockable_product == 0 && isModEnabled('stock') && isModEnabled('productbatch')) {
860 $object->stockable_product = 1;
861 setEventMessages($langs->trans('ForceBatchesNeedStockManagement'), null, 'warnings');
862 }
863
864 $units = GETPOSTINT('units');
865 if ($units > 0) {
866 $object->fk_unit = $units;
867 } else {
868 $object->fk_unit = null;
869 }
870
871 $object->barcode_type = GETPOSTINT('fk_barcode_type');
872 $object->barcode = GETPOST('barcode');
873 // Set barcode_type_xxx from barcode_type id
874 $stdobject = new GenericObject($db);
875 $stdobject->element = 'product';
876 $stdobject->barcode_type = GETPOSTINT('fk_barcode_type');
877 $result = $stdobject->fetchBarCode();
878 if ($result < 0) {
879 $error++;
880 $mesg = 'Failed to get bar code type information ';
881 setEventMessages($mesg.$stdobject->error, $stdobject->errors, 'errors');
882 }
883 $object->barcode_type_code = $stdobject->barcode_type_code;
884 $object->barcode_type_coder = $stdobject->barcode_type_coder;
885 $object->barcode_type_label = $stdobject->barcode_type_label;
886
887 $accountancy_code_sell = GETPOST('accountancy_code_sell', 'alpha');
888 $accountancy_code_sell_intra = GETPOST('accountancy_code_sell_intra', 'alpha');
889 $accountancy_code_sell_export = GETPOST('accountancy_code_sell_export', 'alpha');
890 $accountancy_code_buy = GETPOST('accountancy_code_buy', 'alpha');
891 $accountancy_code_buy_intra = GETPOST('accountancy_code_buy_intra', 'alpha');
892 $accountancy_code_buy_export = GETPOST('accountancy_code_buy_export', 'alpha');
893 $checkmandatory = GETPOST('mandatoryperiod', 'alpha');
894 if (empty($accountancy_code_sell) || $accountancy_code_sell == '-1') {
895 $object->accountancy_code_sell = '';
896 } else {
897 $object->accountancy_code_sell = $accountancy_code_sell;
898 }
899 if (empty($accountancy_code_sell_intra) || $accountancy_code_sell_intra == '-1') {
900 $object->accountancy_code_sell_intra = '';
901 } else {
902 $object->accountancy_code_sell_intra = $accountancy_code_sell_intra;
903 }
904 if (empty($accountancy_code_sell_export) || $accountancy_code_sell_export == '-1') {
905 $object->accountancy_code_sell_export = '';
906 } else {
907 $object->accountancy_code_sell_export = $accountancy_code_sell_export;
908 }
909 if (empty($accountancy_code_buy) || $accountancy_code_buy == '-1') {
910 $object->accountancy_code_buy = '';
911 } else {
912 $object->accountancy_code_buy = $accountancy_code_buy;
913 }
914 if (empty($accountancy_code_buy_intra) || $accountancy_code_buy_intra == '-1') {
915 $object->accountancy_code_buy_intra = '';
916 } else {
917 $object->accountancy_code_buy_intra = $accountancy_code_buy_intra;
918 }
919 if (empty($accountancy_code_buy_export) || $accountancy_code_buy_export == '-1') {
920 $object->accountancy_code_buy_export = '';
921 } else {
922 $object->accountancy_code_buy_export = $accountancy_code_buy_export;
923 }
924 if ($object->isService()) {
925 $object->mandatory_period = (!empty($checkmandatory)) ? 1 : 0 ;
926 }
927
928
929 // Fill array 'array_options' with data from add form
930 $ret = $extrafields->setOptionalsFromPost(null, $object, '@GETPOSTISSET');
931 if ($ret < 0) {
932 $error++;
933 }
934
935 if (!$error && $object->check()) {
936 if ($object->update($object->id, $user) > 0) {
937 // Category association
938 $categories = GETPOST('categories', 'array');
939 $object->setCategories($categories);
940
941 $action = 'view';
942 } else {
943 if (count($object->errors)) {
944 setEventMessages($object->error, $object->errors, 'errors');
945 } else {
946 setEventMessages($langs->trans($object->error), null, 'errors');
947 }
948 $action = 'edit';
949 }
950 } else {
951 if (count($object->errors)) {
952 setEventMessages($object->error, $object->errors, 'errors');
953 } else {
954 setEventMessages($langs->trans("ErrorProductBadRefOrLabel"), null, 'errors');
955 }
956 $action = 'edit';
957 }
958 }
959 }
960 }
961
962 // Action clone object
963 if ($action == 'confirm_clone' && $confirm != 'yes') { // Test on permission not required
964 $action = '';
965 }
966 if ($action == 'confirm_clone' && $confirm == 'yes' && $usercancreate) {
967 if (!GETPOST('clone_content') && !GETPOST('clone_prices')) {
968 setEventMessages($langs->trans("NoCloneOptionsSpecified"), null, 'errors');
969 } else {
970 if ($object->id > 0) {
971 $error = 0;
972 // We clone object to avoid to denaturate loaded object when setting some properties for clone or if createFromClone modifies the object.
973 // We use native clone to keep this->db valid and allow to use later all the methods of object.
974 $clone = dol_clone($object, 1);
975
976 $clone->id = 0;
977 $clone->ref = GETPOST('clone_ref', 'alphanohtml');
978 $clone->status = 0;
979 $clone->status_buy = 0;
980 $clone->barcode = -1;
981
982 if ($clone->check()) {
983 $db->begin();
984
985 $clone->context['createfromclone'] = 'createfromclone';
986 $id = $clone->create($user);
987 if ($id > 0) {
988 if (GETPOST('clone_composition')) {
989 $result = $clone->clone_associations($object->id, $id);
990 if ($result < 1) {
991 setEventMessages($langs->trans('ErrorProductClone'), null, 'errors');
992 setEventMessages($clone->error, $clone->errors, 'errors');
993 $error++;
994 }
995 }
996
997 if (!$error && GETPOST('clone_categories')) {
998 $result = $clone->cloneCategories($object->id, $id);
999 if ($result < 1) {
1000 setEventMessages($langs->trans('ErrorProductClone'), null, 'errors');
1001 setEventMessages($clone->error, $clone->errors, 'errors');
1002 $error++;
1003 }
1004 }
1005
1006 if (!$error && GETPOST('clone_prices')) {
1007 $result = $clone->clone_price($object->id, $id);
1008 if ($result < 1) {
1009 setEventMessages($langs->trans('ErrorProductClone'), null, 'errors');
1010 setEventMessages($clone->error, $clone->errors, 'errors');
1011 $error++;
1012 }
1013 }
1014
1015 if (!$error && isModEnabled('bom') && $user->hasRight('bom', 'write')) {
1016 $defbomidac = 0; // to avoid cloning same BOM twice
1017 if (GETPOST('clone_defbom') && $object->fk_default_bom > 0) {
1018 $bomstatic = new BOM($db);
1019 $bomclone = $bomstatic->createFromClone($user, $object->fk_default_bom);
1020 if ((int) $bomclone < 0) {
1021 setEventMessages($langs->trans('ErrorProductClone').' : '.$langs->trans('ErrorProductCloneBom'), null, 'warnings');
1022 } else {
1023 $defbomidac = $object->fk_default_bom;
1024 $clone->fk_default_bom = $bomclone->id;
1025 $clone->update($id, $user);
1026 $bomclone->fk_product = $id;
1027 $bomclone->label = $langs->trans('BOMofRef', $clone->ref);
1028 $bomclone->update($user);
1029 $bomclone->validate($user);
1030 }
1031 }
1032 if (GETPOST('clone_otherboms')) {
1033 $bomstatic = new BOM($db);
1034 $bomlist = $bomstatic->fetchAll("", "", 0, 0, 'fk_product:=:'.(int) $object->id);
1035 if (is_array($bomlist)) {
1036 foreach ($bomlist as $bom2clone) {
1037 if ($bom2clone->id != $defbomidac) { // to avoid cloning same BOM twice
1038 $bomclone = $bomstatic->createFromClone($user, $bom2clone->id);
1039 if ((int) $bomclone < 0) {
1040 setEventMessages($langs->trans('ErrorProductClone').' : '.$langs->trans('ErrorProductCloneBom'), null, 'warnings');
1041 } else {
1042 $bomclone->fk_product = $id;
1043 $bomclone->label = $langs->trans('BOMofRef', $clone->ref);
1044 $bomclone->update($user);
1045 $bomclone->validate($user);
1046 }
1047 }
1048 }
1049 }
1050 }
1051 }
1052 // $clone->clone_fournisseurs($object->id, $id);
1053 } else {
1054 if ($clone->error == 'ErrorProductAlreadyExists') {
1055 $refalreadyexists++;
1056 $action = "";
1057
1058 $mesg = $langs->trans("ErrorProductAlreadyExists", $clone->ref);
1059 $mesg .= ' <a href="' . $_SERVER["PHP_SELF"] . '?ref=' . $clone->ref . '">' . $langs->trans("ShowCardHere") . '</a>.';
1060 setEventMessages($mesg, null, 'errors');
1061 } else {
1062 setEventMessages(empty($clone->error) ? '' : $langs->trans($clone->error), $clone->errors, 'errors');
1063 }
1064 $error++;
1065 }
1066
1067 unset($clone->context['createfromclone']);
1068
1069 if ($error) {
1070 $db->rollback();
1071 } else {
1072 $db->commit();
1073 $db->close();
1074 header("Location: " . $_SERVER["PHP_SELF"] . "?id=" . $id);
1075 exit;
1076 }
1077 } else {
1078 setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("NewRefForClone")), null, 'errors');
1079 }
1080 } else {
1081 dol_print_error($db, $object->error, $object->errors);
1082 }
1083 }
1084 $action = 'clone';
1085 }
1086
1087 // Delete a product
1088 if ($action == 'confirm_delete' && $confirm != 'yes') { // Test on permission not required
1089 $action = '';
1090 }
1091 if ($action == 'confirm_delete' && $confirm == 'yes' && $usercandelete) {
1092 $result = $object->delete($user);
1093
1094 if ($result > 0) {
1095 header('Location: '.DOL_URL_ROOT.'/product/list.php?type='.$object->type.'&delprod='.urlencode($object->ref));
1096 exit;
1097 } else {
1098 setEventMessages($langs->trans($object->error), null, 'errors');
1099 $reload = 0;
1100 $action = '';
1101 }
1102 }
1103
1104
1105 // Add product into object (when PRODUCT_ADD_FORM_ADD_TO is set)
1106 if ($object->id > 0 && $action == 'addin') { // Test on permission not required here. it is done later according to object.
1107 $thirdpartyid = 0;
1108 $permissiontoaddline = false;
1109 $propal = null;
1110 $facture = null;
1111 $commande = null;
1112
1113 // Get object and test permission
1114 if (GETPOSTINT('propalid') > 0) {
1115 $propal = new Propal($db);
1116 $result = $propal->fetch(GETPOSTINT('propalid'));
1117 if ($result <= 0) {
1118 dol_print_error($db, $propal->error);
1119 exit;
1120 }
1121 $thirdpartyid = $propal->socid;
1122 $permissiontoaddline = $user->hasRight('propal', 'creer');
1123 } elseif (GETPOSTINT('commandeid') > 0) {
1124 $commande = new Commande($db);
1125 $result = $commande->fetch(GETPOSTINT('commandeid'));
1126 if ($result <= 0) {
1127 dol_print_error($db, $commande->error);
1128 exit;
1129 }
1130 $thirdpartyid = $commande->socid;
1131 $permissiontoaddline = $user->hasRight('commande', 'creer');
1132 } elseif (GETPOSTINT('factureid') > 0) {
1133 $facture = new Facture($db);
1134 $result = $facture->fetch(GETPOSTINT('factureid'));
1135 if ($result <= 0) {
1136 dol_print_error($db, $facture->error);
1137 exit;
1138 }
1139 $thirdpartyid = $facture->socid;
1140 $permissiontoaddline = $user->hasRight('facture', 'creer');
1141 }
1142
1143 if ($thirdpartyid > 0) {
1144 $soc = new Societe($db);
1145 $result = $soc->fetch($thirdpartyid);
1146 if ($result <= 0) {
1147 dol_print_error($db, $soc->error);
1148 exit;
1149 }
1150
1151 $desc = $object->description;
1152
1153 $tva_tx = get_default_tva($mysoc, $soc, $object->id);
1154 $tva_npr = get_default_npr($mysoc, $soc, $object->id);
1155 if (empty($tva_tx)) {
1156 $tva_npr = 0;
1157 }
1158 $localtax1_tx = get_localtax($tva_tx, 1, $soc, $mysoc, $tva_npr);
1159 $localtax2_tx = get_localtax($tva_tx, 2, $soc, $mysoc, $tva_npr);
1160
1161 $pu_ht = $object->price;
1162 $pu_ttc = $object->price_ttc;
1163 $price_base_type = $object->price_base_type;
1164
1165 // If multiprice
1166 if (getDolGlobalString('PRODUIT_MULTIPRICES') && $soc->price_level) {
1167 $pu_ht = $object->multiprices[$soc->price_level];
1168 $pu_ttc = $object->multiprices_ttc[$soc->price_level];
1169 $price_base_type = $object->multiprices_base_type[$soc->price_level];
1170 } elseif (getDolGlobalString('PRODUIT_CUSTOMER_PRICES')) {
1171 require_once DOL_DOCUMENT_ROOT.'/product/class/productcustomerprice.class.php';
1172
1173 $prodcustprice = new ProductCustomerPrice($db);
1174
1175 $filter = array('t.fk_product' => (string) $object->id, 't.fk_soc' => (string) $soc->id);
1176
1177 $result = $prodcustprice->fetchAll('', '', 0, 0, $filter);
1178 if ($result) {
1179 if (count($prodcustprice->lines) > 0) {
1180 $date_now = (int) floor(dol_now() / 86400) * 86400; // date without hours
1181 foreach ($prodcustprice->lines as $k => $custprice_line) {
1182 if ($custprice_line->date_begin <= $date_now && (empty($custprice_line->date_end) || $date_now <= $custprice_line->date_end)) {
1183 $pu_ht = price($custprice_line->price);
1184 $pu_ttc = price($custprice_line->price_ttc);
1185 $price_base_type = $custprice_line->price_base_type;
1186 $tva_tx = $custprice_line->tva_tx;
1187 break;
1188 }
1189 }
1190 }
1191 }
1192 }
1193
1194 $tmpvat = price2num(preg_replace('/\s*\‍(.*\‍)/', '', $tva_tx));
1195 $tmpprodvat = price2num(preg_replace('/\s*\‍(.*\‍)/', '', $object->tva_tx));
1196
1197 // On reevalue prix selon taux tva car taux tva transaction peut etre different
1198 // de ceux du produit par default (par example si pays different entre vendeur et acheteur).
1199 if ($tmpvat != $tmpprodvat) {
1200 if ($price_base_type != 'HT') {
1201 $pu_ht = price2num($pu_ttc / (1 + ((float) $tmpvat / 100)), 'MU');
1202 } else {
1203 $pu_ttc = price2num($pu_ht * (1 + ((float) $tmpvat / 100)), 'MU');
1204 }
1205 }
1206
1207 if (GETPOSTINT('propalid') > 0 && $permissiontoaddline && is_object($propal)) {
1208 // Define cost price for margin calculation
1209 $buyprice = 0;
1210 if (($result = $propal->defineBuyPrice($pu_ht, (float) price2num(GETPOST('remise_percent'), '', 2), $object->id)) < 0) {
1211 dol_syslog($langs->trans('FailedToGetCostPrice'));
1212 setEventMessages($langs->trans('FailedToGetCostPrice'), null, 'errors');
1213 } else {
1214 $buyprice = $result;
1215 }
1216
1217 $result = $propal->addline(
1218 $desc,
1219 $pu_ht,
1220 (float) price2num(GETPOST('qty'), 'MS'),
1221 $tva_tx,
1222 $localtax1_tx, // localtax1
1223 $localtax2_tx, // localtax2
1224 $object->id,
1225 (float) price2num(GETPOST('remise_percent'), '', 2),
1226 $price_base_type,
1227 $pu_ttc,
1228 0,
1229 0,
1230 -1,
1231 0,
1232 0,
1233 0,
1234 $buyprice,
1235 '',
1236 '',
1237 '',
1238 array(),
1239 $object->fk_unit
1240 );
1241 if ($result > 0) {
1242 header("Location: ".DOL_URL_ROOT."/comm/propal/card.php?id=".$propal->id);
1243 return;
1244 }
1245
1246 setEventMessages($langs->trans("ErrorUnknown").": $result", null, 'errors');
1247 } elseif (GETPOST('commandeid') > 0 && $permissiontoaddline && is_object($commande)) {
1248 // Define cost price for margin calculation
1249 $buyprice = 0;
1250 if (($result = $commande->defineBuyPrice($pu_ht, (float) price2num(GETPOST('remise_percent'), '', 2), $object->id)) < 0) {
1251 dol_syslog($langs->trans('FailedToGetCostPrice'));
1252 setEventMessages($langs->trans('FailedToGetCostPrice'), null, 'errors');
1253 } else {
1254 $buyprice = $result;
1255 }
1256
1257 $result = $commande->addline(
1258 $desc,
1259 (float) $pu_ht,
1260 (float) price2num(GETPOST('qty'), 'MS'),
1261 $tva_tx,
1262 $localtax1_tx, // localtax1
1263 $localtax2_tx, // localtax2
1264 $object->id,
1265 (float) price2num(GETPOST('remise_percent'), '', 2),
1266 0,
1267 0,
1268 $price_base_type,
1269 $pu_ttc,
1270 '',
1271 '',
1272 0,
1273 -1,
1274 0,
1275 0,
1276 0,
1277 $buyprice,
1278 '',
1279 array(),
1280 $object->fk_unit
1281 );
1282
1283 if ($result > 0) {
1284 header("Location: ".DOL_URL_ROOT."/commande/card.php?id=".urlencode((string) ($commande->id)));
1285 exit;
1286 }
1287
1288 setEventMessages($langs->trans("ErrorUnknown").": $result", null, 'errors');
1289 } elseif (GETPOST('factureid') > 0 && $permissiontoaddline && is_object($facture)) {
1290 // Define cost price for margin calculation
1291 $buyprice = 0;
1292 if (($result = $facture->defineBuyPrice($pu_ht, (float) price2num(GETPOST('remise_percent'), '', 2), $object->id)) < 0) {
1293 dol_syslog($langs->trans('FailedToGetCostPrice'));
1294 setEventMessages($langs->trans('FailedToGetCostPrice'), null, 'errors');
1295 } else {
1296 $buyprice = $result;
1297 }
1298
1299 $result = $facture->addline(
1300 $desc,
1301 (float) $pu_ht,
1302 (float) price2num(GETPOST('qty'), 'MS'),
1303 $tva_tx,
1304 $localtax1_tx,
1305 $localtax2_tx,
1306 $object->id,
1307 (float) price2num(GETPOST('remise_percent'), '', 2),
1308 '',
1309 '',
1310 0,
1311 0,
1312 0,
1313 $price_base_type,
1314 $pu_ttc,
1316 -1,
1317 0,
1318 '',
1319 0,
1320 0,
1321 0,
1322 $buyprice,
1323 '',
1324 array(),
1325 100,
1326 0,
1327 $object->fk_unit
1328 );
1329
1330 if ($result > 0) {
1331 header("Location: ".DOL_URL_ROOT."/compta/facture/card.php?facid=".$facture->id);
1332 exit;
1333 }
1334
1335 setEventMessages($langs->trans("ErrorUnknown").": $result", null, 'errors');
1336 }
1337 } else {
1338 $action = "";
1339 setEventMessages($langs->trans("WarningSelectOneDocument"), null, 'warnings');
1340 }
1341 }
1342
1343 // Actions to send emails
1344 $triggersendname = 'PRODUCT_SENTBYMAIL';
1345 $paramname = 'id';
1346 $autocopy = 'MAIN_MAIL_AUTOCOPY_PRODUCT_TO';
1347 $trackid = 'prod'.$object->id;
1348 include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php';
1349}
1350
1351
1352
1353/*
1354 * View
1355 */
1356
1357$form = new Form($db);
1358$formfile = new FormFile($db);
1359$formproduct = new FormProduct($db);
1360$formcompany = new FormCompany($db);
1361if (isModEnabled('accounting')) {
1362 $formaccounting = new FormAccounting($db);
1363}
1364$sellOrEatByMandatoryList = null;
1365if (isModEnabled('productbatch')) {
1366 $sellOrEatByMandatoryList = Product::getSellOrEatByMandatoryList();
1367
1368 $disableSellBy = getDolGlobalString('PRODUCT_DISABLE_SELLBY');
1369 $disableEatBy = getDolGlobalString('PRODUCT_DISABLE_EATBY');
1370
1371 if ($disableSellBy) {
1372 unset($sellOrEatByMandatoryList[Product::SELL_OR_EAT_BY_MANDATORY_ID_SELL_BY]);
1373 unset($sellOrEatByMandatoryList[Product::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT]);
1374 }
1375 if ($disableEatBy) {
1376 unset($sellOrEatByMandatoryList[Product::SELL_OR_EAT_BY_MANDATORY_ID_EAT_BY]);
1377 unset($sellOrEatByMandatoryList[Product::SELL_OR_EAT_BY_MANDATORY_ID_SELL_AND_EAT]);
1378 }
1379}
1380
1381$title = $langs->trans('ProductServiceCard');
1382
1383$help_url = '';
1384$shortlabel = dol_trunc($object->label, 16);
1385if (GETPOST("type") == '0' || ($object->type == Product::TYPE_PRODUCT)) {
1386 if ($action == 'create') {
1387 $title = $langs->trans("NewProduct");
1388 } else {
1389 $title = $langs->trans('Product')." ".$shortlabel." - ".$langs->trans('Card');
1390 $help_url = 'EN:Module_Products|FR:Module_Produits|ES:M&oacute;dulo_Productos|DE:Modul_Produkte';
1391 }
1392}
1393if (GETPOST("type") == '1' || ($object->type == Product::TYPE_SERVICE)) {
1394 if ($action == 'create') {
1395 $title = $langs->trans("NewService");
1396 } else {
1397 $title = $langs->trans('Service')." ".$shortlabel." - ".$langs->trans('Card');
1398 $help_url = 'EN:Module_Services_En|FR:Module_Services|ES:M&oacute;dulo_Servicios|DE:Modul_Leistungen';
1399 }
1400}
1401
1402llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-product page-card');
1403
1404// Load object modBarCodeProduct
1405$res = 0;
1406$modBarCodeProduct = null;
1407if (isModEnabled('barcode') && getDolGlobalString('BARCODE_PRODUCT_ADDON_NUM')) {
1408 $module = strtolower(getDolGlobalString('BARCODE_PRODUCT_ADDON_NUM'));
1409 $dirbarcode = array_merge(array('/core/modules/barcode/'), $conf->modules_parts['barcode']);
1410 foreach ($dirbarcode as $dirroot) {
1411 $res = dol_include_once($dirroot.$module.'.php');
1412 if ($res) {
1413 break;
1414 }
1415 }
1416 if ($res > 0) {
1417 $modBarCodeProduct = new $module();
1418 '@phan-var-force ModeleNumRefBarCode $modBarCodeProduct';
1419 }
1420}
1421
1422$canvasdisplayaction = $action;
1423if (in_array($canvasdisplayaction, array('merge', 'confirm_merge'))) {
1424 $canvasdisplayaction = 'view';
1425}
1426
1427if (is_object($objcanvas) && $objcanvas->displayCanvasExists($canvasdisplayaction)) {
1428 // -----------------------------------------
1429 // When used with CANVAS
1430 // -----------------------------------------
1431 $objcanvas->assign_values($canvasdisplayaction, $object->id, $object->ref); // Set value for templates
1432 $objcanvas->display_canvas($canvasdisplayaction); // Show template
1433} else {
1434 // -----------------------------------------
1435 // When used in standard mode
1436 // -----------------------------------------
1437 if ($action == 'create' && $usercancreate) {
1438 //WYSIWYG Editor
1439 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
1440
1441 if (!empty($conf->use_javascript_ajax)) {
1442 print '<script type="text/javascript">';
1443 print '$(document).ready(function () {
1444 $("#selectcountry_id").change(function() {
1445 console.log("selectcountry_id change");
1446 document.formprod.action.value="create";
1447 document.formprod.submit();
1448 });
1449 });';
1450 print '</script>'."\n";
1451 }
1452
1453 // Load object modCodeProduct
1454 $module = getDolGlobalString('PRODUCT_CODEPRODUCT_ADDON', 'mod_codeproduct_leopard');
1455 if (substr($module, 0, 16) == 'mod_codeproduct_' && substr($module, -3) == 'php') {
1456 $module = substr($module, 0, dol_strlen($module) - 4);
1457 }
1458 $result = dol_include_once('/core/modules/product/'.$module.'.php');
1459 if ($result > 0) {
1460 $modCodeProduct = new $module();
1461 }
1462
1463 dol_set_focus('input[name="ref"]');
1464
1465 print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST" name="formprod">';
1466 print '<input type="hidden" name="token" value="'.newToken().'">';
1467 print '<input type="hidden" name="action" value="add">';
1468 print '<input type="hidden" name="type" value="'.$type.'">'."\n";
1469 if (!empty($modCodeProduct->code_auto)) {
1470 print '<input type="hidden" name="code_auto" value="1">';
1471 }
1472 if (!empty($modBarCodeProduct->code_auto)) {
1473 print '<input type="hidden" name="barcode_auto" value="1">';
1474 }
1475 print '<input type="hidden" name="backtopage" value="'.$backtopage.'">';
1476
1477 if ($type == 1) {
1478 $picto = 'service';
1479 $title = $langs->trans("NewService");
1480 } else {
1481 $picto = 'product';
1482 $title = $langs->trans("NewProduct");
1483 }
1484 $linkback = "";
1485 print load_fiche_titre($title, $linkback, $picto);
1486
1487 // We set country_id, country_code and country for the selected country
1488 $object->country_id = GETPOSTISSET('country_id') ? GETPOSTINT('country_id') : null;
1489 if ($object->country_id > 0) {
1490 $tmparray = getCountry($object->country_id, 'all');
1491 $object->country_code = $tmparray['code'];
1492 $object->country = $tmparray['label'];
1493 }
1494
1495 print dol_get_fiche_head();
1496
1497 // Call Hook tabContentCreateProduct
1498 $parameters = array();
1499 // Note that $action and $object may be modified by hook
1500 $reshook = $hookmanager->executeHooks('tabContentCreateProduct', $parameters, $object, $action);
1501 if (empty($reshook)) {
1502 print '<table class="border centpercent">';
1503
1504 if (!getDolGlobalString('PRODUCT_GENERATE_REF_AFTER_FORM')) {
1505 print '<tr>';
1506 $tmpcode = '';
1507 if (!empty($modCodeProduct->code_auto)) {
1508 $tmpcode = $modCodeProduct->getNextValue($object, $type);
1509 }
1510 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).'">';
1511 if ($refalreadyexists) {
1512 print $langs->trans("RefAlreadyExists");
1513 }
1514 print '</td></tr>';
1515 }
1516
1517 // Label
1518 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>';
1519
1520 // On sell
1521 print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Sell").')</td><td>';
1522 $statutarray = array('1' => $langs->trans("OnSell"), '0' => $langs->trans("NotOnSell"));
1523 print $form->selectarray('statut', $statutarray, GETPOST('statut'));
1524 print '</td></tr>';
1525
1526 // To buy
1527 print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Buy").')</td><td>';
1528 $statutarray = array('1' => $langs->trans("ProductStatusOnBuy"), '0' => $langs->trans("ProductStatusNotOnBuy"));
1529 print $form->selectarray('statut_buy', $statutarray, GETPOST('statut_buy'));
1530 print '</td></tr>';
1531
1532 // Batch number management
1533 if (isModEnabled('productbatch')) {
1534 print '<tr><td>'.$langs->trans("ManageLotSerial").'</td><td>';
1535 $statutarray = array('0' => $langs->trans("ProductStatusNotOnBatch"), '1' => $langs->trans("ProductStatusOnBatch"), '2' => $langs->trans("ProductStatusOnSerial"));
1536 print $form->selectarray('status_batch', $statutarray, GETPOSTINT('status_batch'));
1537 print '</td></tr>';
1538 // Product specific batch number management
1539 $status_batch = GETPOSTINT('status_batch');
1540 if ($status_batch !== '0') {
1541 $langs->load("admin");
1542 $tooltip = $langs->trans("GenericMaskCodes", $langs->transnoentities("Batch"), $langs->transnoentities("Batch"));
1543 $tooltip .= $langs->trans("GenericMaskCodes1");
1544 $tooltip .= '<br>'.$langs->trans("GenericMaskCodes2");
1545 $tooltip .= '<br>'.$langs->trans("GenericMaskCodes3");
1546 $tooltip .= '<br>'.$langs->trans("GenericMaskCodes4a", $langs->transnoentities("Batch"), $langs->transnoentities("Batch"));
1547 $tooltip .= '<br>'.$langs->trans("GenericMaskCodes5");
1548 //$tooltip .= '<br>'.$langs->trans("GenericMaskCodes5b");
1549
1550 if ((getDolGlobalString('PRODUCTBATCH_LOT_ADDON') == 'mod_lot_advanced')
1551 || (getDolGlobalString('PRODUCTBATCH_SN_ADDON') == 'mod_sn_advanced')) {
1552 print '<tr><td id="mask_option">'.$langs->trans("ManageLotMask").'</td>';
1553 $inherited_mask_lot = getDolGlobalString('LOT_ADVANCED_MASK');
1554 $inherited_mask_sn = getDolGlobalString('SN_ADVANCED_MASK');
1555 print '<td id="field_mask">';
1556 print $form->textwithpicto('<input type="text" class="flat minwidth175" name="batch_mask" id="batch_mask_input">', $tooltip, 1, 'help');
1557 print '<script type="text/javascript">
1558 $(document).ready(function() {
1559 $("#field_mask, #mask_option").addClass("hideobject");
1560 $("#status_batch").on("change", function () {
1561 console.log("We change batch status");
1562 var optionSelected = $("option:selected", this);
1563 var valueSelected = this.value;
1564 $("#field_mask, #mask_option").addClass("hideobject");
1565 ';
1566 if (getDolGlobalString('PRODUCTBATCH_LOT_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_LOT_ADDON') == 'mod_lot_advanced') {
1567 print '
1568 if (this.value == 1) {
1569 $("#field_mask, #mask_option").toggleClass("hideobject");
1570 $("#batch_mask_input").val("'.$inherited_mask_lot.'");
1571 }
1572 ';
1573 }
1574 if (getDolGlobalString('PRODUCTBATCH_SN_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_SN_ADDON') == 'mod_sn_advanced') {
1575 print '
1576 if (this.value == 2) {
1577 $("#field_mask, #mask_option").toggleClass("hideobject");
1578 $("#batch_mask_input").val("'.$inherited_mask_sn.'");
1579 }
1580 ';
1581 }
1582 print '
1583 })
1584 })
1585 </script>';
1586 print '</td></tr>';
1587 }
1588 }
1589
1590 // SellBy / EatBy mandatory list
1591 if (!empty($sellOrEatByMandatoryList)) {
1592 print '<tr><td>'.$langs->trans('BatchSellOrEatByMandatoryList', $langs->transnoentities('SellByDate'), $langs->transnoentities('EatByDate')).'</td><td>';
1593 print $form->selectarray('sell_or_eat_by_mandatory', $sellOrEatByMandatoryList, GETPOSTINT('sell_or_eat_by_mandatory'));
1594 print '</td></tr>';
1595 }
1596 }
1597
1598 $showbarcode = isModEnabled('barcode');
1599 if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('barcode', 'lire_advance')) {
1600 $showbarcode = 0;
1601 }
1602
1603 if ($showbarcode && is_object($modBarCodeProduct)) {
1604 //var_dump($modBarCodeProduct); exit;
1605
1606 print '<tr><td>'.$langs->trans('BarcodeType').'</td><td>';
1607 if (GETPOSTISSET('fk_barcode_type')) {
1608 $fk_barcode_type = GETPOST('fk_barcode_type') ? GETPOST('fk_barcode_type') : 0;
1609 } else {
1610 if (empty($fk_barcode_type) && getDolGlobalString('PRODUIT_DEFAULT_BARCODE_TYPE')) {
1611 $fk_barcode_type = getDolGlobalInt("PRODUIT_DEFAULT_BARCODE_TYPE");
1612 } else {
1613 $fk_barcode_type = 0;
1614 }
1615 }
1616 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formbarcode.class.php';
1617 $formbarcode = new FormBarCode($db);
1618 print $formbarcode->selectBarcodeType($fk_barcode_type, 'fk_barcode_type', 1);
1619 print '</td>';
1620 print '</tr>';
1621
1622 print '<tr>';
1623 print '<td'.($modBarCodeProduct->code_null ? '' : ' class="fieldrequired"').'>'.$langs->trans("BarcodeValue").'</td><td>';
1624 $tmpcode = GETPOSTISSET('barcode') ? GETPOST('barcode') : $object->barcode;
1625 if (empty($tmpcode) && !empty($modBarCodeProduct->code_auto)) {
1626 $tmpcode = $modBarCodeProduct->getNextValue($object, $fk_barcode_type);
1627 }
1628 print img_picto('', 'barcode', 'class="pictofixedwidth"');
1629 print '<input class="maxwidth150" type="text" name="barcode" value="'.dol_escape_htmltag($tmpcode).'">';
1630 print '</td></tr>';
1631 }
1632
1633 // Description (used in invoice, propal...)
1634 print '<tr><td class="tdtop">'.$langs->trans("Description").'</td><td>';
1635 $doleditor = new DolEditor('desc', GETPOST('desc', 'restricthtml'), '', 160, 'dolibarr_details', '', false, true, getDolGlobalString('FCKEDITOR_ENABLE_DETAILS'), ROWS_4, '90%');
1636 $doleditor->Create();
1637 print "</td></tr>";
1638
1639 if (!getDolGlobalString('PRODUCT_DISABLE_PUBLIC_URL')) {
1640 // Public URL
1641 print '<tr><td>'.$langs->trans("PublicUrl").'</td><td>';
1642 print img_picto('', 'globe', 'class="pictofixedwidth"');
1643 print '<input type="text" name="url" class="quatrevingtpercent" value="'.GETPOST('url').'">';
1644 print '</td></tr>';
1645 }
1646
1647 if (($type != 1 || getDolGlobalInt('STOCK_SUPPORTS_SERVICES')) && isModEnabled('stock')) {
1648 // Default warehouse
1649 print '<tr><td>'.$langs->trans("DefaultWarehouse").'</td><td>';
1650 print img_picto($langs->trans("DefaultWarehouse"), 'stock', 'class="pictofixedwidth"');
1651 print $formproduct->selectWarehouses(GETPOSTINT('fk_default_warehouse'), 'fk_default_warehouse', 'warehouseopen', 1, 0, 0, '', 0, 0, array(), 'minwidth300 widthcentpercentminusxx maxwidth500');
1652 print ' <a href="'.DOL_URL_ROOT.'/product/stock/card.php?action=create&token='.newToken().'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?&action=create&type='.GETPOSTINT('type')).'">';
1653 print '<span class="fa fa-plus-circle valignmiddle paddingleft" title="'.$langs->trans("AddWarehouse").'"></span>';
1654 print '</a>';
1655
1656 print '</td>';
1657 print '</tr>';
1658
1659 if (!getDolGlobalString('PRODUCT_DISABLE_STOCK_LEVELS')) {
1660 // Stock min level
1661 print '<tr><td>'.$form->textwithpicto($langs->trans("StockLimit"), $langs->trans("StockLimitDesc"), 1).'</td><td>';
1662 print '<input name="seuil_stock_alerte" class="maxwidth50" value="'.GETPOST('seuil_stock_alerte').'">';
1663 print '</td>';
1664 print '</tr>';
1665
1666 // Stock desired level
1667 print '<tr><td>'.$form->textwithpicto($langs->trans("DesiredStock"), $langs->trans("DesiredStockDesc"), 1).'</td><td>';
1668 print '<input name="desiredstock" class="maxwidth50" value="'.GETPOST('desiredstock').'">';
1669 print '</td></tr>';
1670 }
1671 } else {
1672 if (!getDolGlobalString('PRODUCT_DISABLE_STOCK_LEVELS')) {
1673 print '<input name="seuil_stock_alerte" type="hidden" value="0">';
1674 print '<input name="desiredstock" type="hidden" value="0">';
1675 }
1676 }
1677
1678 if ($type == $object::TYPE_SERVICE && isModEnabled("workstation")) {
1679 // Default workstation
1680 print '<tr><td>'.$langs->trans("DefaultWorkstation").'</td><td>';
1681 print img_picto($langs->trans("DefaultWorkstation"), 'workstation', 'class="pictofixedwidth"');
1682 print $formproduct->selectWorkstations((GETPOSTISSET('fk_default_workstation') ? GETPOSTINT('fk_default_workstation') : ''), 'fk_default_workstation', 1);
1683 print '</td></tr>';
1684 }
1685
1686 // Duration
1687 if ($type == 1) {
1688 print '<tr><td>'.$langs->trans("Duration").'</td><td>';
1689 print img_picto('', 'clock', 'class="pictofixedwidth"');
1690 print '<input name="duration_value" class="width50" value="'.(GETPOSTISSET('duration_value') ? GETPOST('duration_value') : '').'">';
1691 print $formproduct->selectMeasuringUnits("duration_unit", "time", (GETPOSTISSET('duration_unit') ? GETPOST('duration_unit', 'alpha') : 'h'), 0, 1);
1692
1693 // Mandatory period
1694 if ($object->duration_value > 0) {
1695 print ' &nbsp; &nbsp; ';
1696 }
1697 print '<input type="checkbox" class="marginleftonly valignmiddle" id="mandatoryperiod" name="mandatoryperiod"'.(GETPOSTISSET('mandatoryperiod') ? ' checked="checked"' : '').'>';
1698 print '<label for="mandatoryperiod">';
1699 $htmltooltip = $langs->trans("mandatoryHelper");
1700 if (!getDolGlobalString('SERVICE_STRICT_MANDATORY_PERIOD')) {
1701 $htmltooltip .= '<br>'.$langs->trans("mandatoryHelper2");
1702 }
1703 print $form->textwithpicto($langs->trans("mandatoryperiod"), $htmltooltip, 1, 'info');
1704 print '</label>';
1705
1706 print '</td></tr>';
1707 }
1708
1709 if ($type != 1) { // Nature, Weight and volume only applies to products and not to services
1710 if (!getDolGlobalString('PRODUCT_DISABLE_NATURE')) {
1711 // Nature
1712 print '<tr><td>'.$form->textwithpicto($langs->trans("NatureOfProductShort"), $langs->trans("NatureOfProductDesc")).'</td><td>';
1713 print $formproduct->selectProductNature('finished', (GETPOST('finished') ? GETPOST('finished') : (string) $object->finished));
1714 print '</td></tr>';
1715 }
1716 }
1717
1718 if ($type != 1) {
1719 if (!getDolGlobalString('PRODUCT_DISABLE_WEIGHT')) {
1720 // Brut Weight
1721 print '<tr><td>'.$langs->trans("Weight").'</td><td>';
1722 print img_picto('', 'fa-balance-scale', 'class="pictofixedwidth"');
1723 print '<input name="weight" size="4" value="'.GETPOST('weight').'">';
1724 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);
1725 print '</td></tr>';
1726 }
1727
1728 // Brut Length
1729 if (!getDolGlobalString('PRODUCT_DISABLE_SIZE')) {
1730 print '<tr><td>'.$langs->trans("Length").' x '.$langs->trans("Width").' x '.$langs->trans("Height").'</td><td>';
1731 print img_picto('', 'fa-ruler', 'class="pictofixedwidth"');
1732 print '<input name="size" class="width50" value="'.GETPOST('size').'"> x ';
1733 print '<input name="sizewidth" class="width50" value="'.GETPOST('sizewidth').'"> x ';
1734 print '<input name="sizeheight" class="width50" value="'.GETPOST('sizeheight').'">';
1735 print $formproduct->selectMeasuringUnits("size_units", "size", GETPOSTISSET('size_units') ? GETPOST('size_units', 'alpha') : (GETPOST('size_units', 'alpha') ?: '0'), 0, 2);
1736 print '</td></tr>';
1737 }
1738 if (!getDolGlobalString('PRODUCT_DISABLE_SURFACE')) {
1739 // Brut Surface
1740 print '<tr><td>'.$langs->trans("Surface").'</td><td>';
1741 print '<input name="surface" size="4" value="'.GETPOST('surface').'">';
1742 print $formproduct->selectMeasuringUnits("surface_units", "surface", GETPOSTISSET('surface_units') ? GETPOST('surface_units', 'alpha') : (GETPOST('surface_units', 'alpha') ?: '0'), 0, 2);
1743 print '</td></tr>';
1744 }
1745 if (!getDolGlobalString('PRODUCT_DISABLE_VOLUME')) {
1746 // Brut Volume
1747 print '<tr><td>'.$langs->trans("Volume").'</td><td>';
1748 print '<input name="volume" size="4" value="'.GETPOST('volume').'">';
1749 print $formproduct->selectMeasuringUnits("volume_units", "volume", GETPOSTISSET('volume_units') ? GETPOST('volume_units', 'alpha') : (GETPOST('volume_units', 'alpha') ?: '0'), 0, 2);
1750 print '</td></tr>';
1751 }
1752
1753 if (getDolGlobalString('PRODUCT_ADD_NET_MEASURE')) {
1754 // Net Measure
1755 print '<tr><td>'.$langs->trans("NetMeasure").'</td><td>';
1756 print '<input name="net_measure" size="4" value="'.GETPOST('net_measure').'">';
1757 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);
1758 print '</td></tr>';
1759 }
1760 }
1761
1762 // Units
1763 if (getDolGlobalString('PRODUCT_USE_UNITS')) {
1764 print '<tr><td>'.$langs->trans('DefaultUnitToShow').'</td>';
1765 print '<td>';
1766 print $form->selectUnits(GETPOSTISSET('units') ? GETPOST('units', 'alpha') : (GETPOST('units', 'alpha') ?: '0'), 'units');
1767 print '</td></tr>';
1768 }
1769
1770 // Custom code
1771 if (!getDolGlobalString('PRODUCT_DISABLE_CUSTOMS_INFO') && empty($type)) {
1772 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>';
1773
1774 // Origin country
1775 print '<tr><td>'.$langs->trans("CountryOrigin").'</td>';
1776 print '<td>';
1777 print img_picto('', 'globe-americas', 'class="pictofixedwidth"');
1778 print $form->select_country((GETPOSTISSET('country_id') ? GETPOST('country_id') : $object->country_id), 'country_id', '', 0, 'minwidth300 widthcentpercentminusx maxwidth500');
1779 if ($user->admin) {
1780 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
1781 }
1782 print '</td></tr>';
1783
1784 // State
1785 if (!getDolGlobalString('PRODUCT_DISABLE_STATE')) {
1786 print '<tr>';
1787 if (getDolGlobalString('MAIN_SHOW_REGION_IN_STATE_SELECT') && (getDolGlobalInt('MAIN_SHOW_REGION_IN_STATE_SELECT') == 1 || getDolGlobalInt('MAIN_SHOW_REGION_IN_STATE_SELECT') == 2)) {
1788 print '<td>'.$form->editfieldkey('RegionStateOrigin', 'state_id', '', $object, 0).'</td><td>';
1789 } else {
1790 print '<td>'.$form->editfieldkey('StateOrigin', 'state_id', '', $object, 0).'</td><td>';
1791 }
1792
1793 print img_picto('', 'state', 'class="pictofixedwidth"');
1794 print $formcompany->select_state($object->state_id, $object->country_code);
1795 print '</tr>';
1796 }
1797 }
1798
1799 // Quality control
1800 if (getDolGlobalString('PRODUCT_LOT_ENABLE_QUALITY_CONTROL')) {
1801 print '<tr><td>'.$langs->trans("LifeTime").'</td><td><input name="lifetime" class="maxwidth50" value="'.GETPOST('lifetime').'"></td></tr>';
1802 print '<tr><td>'.$langs->trans("QCFrequency").'</td><td><input name="qc_frequency" class="maxwidth50" value="'.GETPOST('qc_frequency').'"></td></tr>';
1803 }
1804
1805 // Other attributes
1806 $parameters = array('colspan' => ' colspan="2"', 'cols' => 2);
1807 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1808 print $hookmanager->resPrint;
1809 if (empty($reshook)) {
1810 print $object->showOptionals($extrafields, 'create', $parameters);
1811 }
1812
1813 // Note (private, no output on invoices, propales...)
1814 print '<tr><td class="tdtop">'.$langs->trans("NoteNotVisibleOnBill").'</td><td>';
1815
1816 // 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.
1817 $doleditor = new DolEditor('note_private', GETPOST('note_private', 'restricthtml'), '', 140, 'dolibarr_details', '', false, true, getDolGlobalString('FCKEDITOR_ENABLE_NOTE_PRIVATE'), ROWS_8, '90%');
1818 $doleditor->Create();
1819
1820 print "</td></tr>";
1821
1822 if (isModEnabled('category')) {
1823 // Categories
1824 print '<tr><td>'.$langs->trans("Categories").'</td><td>';
1825 print $form->selectCategories(Categorie::TYPE_PRODUCT, 'categories', $object);
1826 print "</td></tr>";
1827 }
1828
1829 print '</table>';
1830
1831 print '<hr>';
1832
1833 if (!getDolGlobalString('PRODUCT_DISABLE_PRICES')) {
1834 if (getDolGlobalString('PRODUIT_MULTIPRICES') || getDolGlobalString('PRODUIT_CUSTOMER_PRICES_AND_MULTIPRICES')) {
1835 // We do no show price array on create when multiprices enabled.
1836 // We must set them on prices tab.
1837 print '<table class="border centpercent">';
1838 // VAT
1839 print '<tr><td class="titlefieldcreate">'.$langs->trans("VATRate").'</td><td>';
1840 $defaultva = get_default_tva($mysoc, $mysoc);
1841 print $form->load_tva("tva_tx", $defaultva, $mysoc, $mysoc, 0, 0, '', false, 1);
1842 print ajax_combobox("tva_tx");
1843 print '</td></tr>';
1844
1845 print '</table>';
1846
1847 print '<br>';
1848 } else {
1849 print '<table class="border centpercent">';
1850
1851 // Price
1852 print '<tr><td class="titlefieldcreate">'.$langs->trans("SellingPrice").'</td>';
1853 print '<td><input name="price" class="maxwidth50" value="'.$object->price.'">';
1854 print $form->selectPriceBaseType(getDolGlobalString('PRODUCT_PRICE_BASE_TYPE'), "price_base_type");
1855 print ajax_combobox("select_price_base_type");
1856 print '</td></tr>';
1857
1858 // Min price
1859 print '<tr><td>'.$langs->trans("MinPrice").'</td>';
1860 print '<td><input name="price_min" class="maxwidth50" value="'.$object->price_min.'">';
1861 print '</td></tr>';
1862
1863 // VAT
1864 print '<tr><td>'.$langs->trans("VATRate").'</td><td>';
1865 $defaultva = get_default_tva($mysoc, $mysoc);
1866 print $form->load_tva("tva_tx", $defaultva, $mysoc, $mysoc, 0, 0, '', false, 1);
1867 print ajax_combobox("tva_tx");
1868 print '</td></tr>';
1869
1870 print '</table>';
1871
1872 print '<br>';
1873 }
1874 }
1875
1876 // Accountancy codes
1877 print '<!-- accountancy codes -->'."\n";
1878 print '<table class="border centpercent">';
1879
1880 if (!getDolGlobalString('PRODUCT_DISABLE_ACCOUNTING')) {
1881 if (isModEnabled('accounting')) {
1883 // Accountancy_code_sell
1884 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellCode").'</td>';
1885 print '<td>';
1886 if ($type == 0) {
1887 $accountancy_code_sell = (GETPOSTISSET('accountancy_code_sell') ? GETPOST('accountancy_code_sell', 'alpha') : getDolGlobalString("ACCOUNTING_PRODUCT_SOLD_ACCOUNT"));
1888 } else {
1889 $accountancy_code_sell = (GETPOSTISSET('accountancy_code_sell') ? GETPOST('accountancy_code_sell', 'alpha') : getDolGlobalString("ACCOUNTING_SERVICE_SOLD_ACCOUNT"));
1890 }
1891 print $formaccounting->select_account($accountancy_code_sell, 'accountancy_code_sell', 1, array(), 1, 1, 'minwidth150 maxwidth300', '1');
1892 print '</td></tr>';
1893
1894 // Accountancy_code_sell_intra
1895 if ($mysoc->isInEEC()) {
1896 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellIntraCode").'</td>';
1897 print '<td>';
1898 if ($type == 0) {
1899 $accountancy_code_sell_intra = (GETPOSTISSET('accountancy_code_sell_intra') ? GETPOST('accountancy_code_sell_intra', 'alpha') : getDolGlobalString("ACCOUNTING_PRODUCT_SOLD_INTRA_ACCOUNT"));
1900 } else {
1901 $accountancy_code_sell_intra = (GETPOSTISSET('accountancy_code_sell_intra') ? GETPOST('accountancy_code_sell_intra', 'alpha') : getDolGlobalString("ACCOUNTING_SERVICE_SOLD_INTRA_ACCOUNT"));
1902 }
1903 print $formaccounting->select_account($accountancy_code_sell_intra, 'accountancy_code_sell_intra', 1, array(), 1, 1, 'minwidth150 maxwidth300', '1');
1904 print '</td></tr>';
1905 }
1906
1907 // Accountancy_code_sell_export
1908 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellExportCode").'</td>';
1909 print '<td>';
1910 if ($type == 0) {
1911 $accountancy_code_sell_export = (GETPOST('accountancy_code_sell_export') ? GETPOST('accountancy_code_sell_export', 'alpha') : getDolGlobalString("ACCOUNTING_PRODUCT_SOLD_EXPORT_ACCOUNT"));
1912 } else {
1913 $accountancy_code_sell_export = (GETPOST('accountancy_code_sell_export') ? GETPOST('accountancy_code_sell_export', 'alpha') : getDolGlobalString("ACCOUNTING_SERVICE_SOLD_EXPORT_ACCOUNT"));
1914 }
1915 print $formaccounting->select_account($accountancy_code_sell_export, 'accountancy_code_sell_export', 1, array(), 1, 1, 'minwidth150 maxwidth300', '1');
1916 print '</td></tr>';
1917
1918 // Accountancy_code_buy
1919 print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
1920 print '<td>';
1921 if ($type == 0) {
1922 $accountancy_code_buy = (GETPOST('accountancy_code_buy', 'alpha') ? (GETPOST('accountancy_code_buy', 'alpha')) : getDolGlobalString("ACCOUNTING_PRODUCT_BUY_ACCOUNT"));
1923 } else {
1924 $accountancy_code_buy = (GETPOST('accountancy_code_buy', 'alpha') ? (GETPOST('accountancy_code_buy', 'alpha')) : getDolGlobalString("ACCOUNTING_SERVICE_BUY_ACCOUNT"));
1925 }
1926 print $formaccounting->select_account($accountancy_code_buy, 'accountancy_code_buy', 1, array(), 1, 1, 'minwidth150 maxwidth300', '1');
1927 print '</td></tr>';
1928
1929 // Accountancy_code_buy_intra
1930 if ($mysoc->isInEEC()) {
1931 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyIntraCode").'</td>';
1932 print '<td>';
1933 if ($type == 0) {
1934 $accountancy_code_buy_intra = (GETPOSTISSET('accountancy_code_buy_intra') ? GETPOST('accountancy_code_buy_intra', 'alpha') : getDolGlobalString("ACCOUNTING_PRODUCT_BUY_INTRA_ACCOUNT"));
1935 } else {
1936 $accountancy_code_buy_intra = (GETPOSTISSET('accountancy_code_buy_intra') ? GETPOST('accountancy_code_buy_intra', 'alpha') : getDolGlobalString("ACCOUNTING_SERVICE_BUY_INTRA_ACCOUNT"));
1937 }
1938 print $formaccounting->select_account($accountancy_code_buy_intra, 'accountancy_code_buy_intra', 1, array(), 1, 1, 'minwidth150 maxwidth300', '1');
1939 print '</td></tr>';
1940 }
1941
1942 // Accountancy_code_buy_export
1943 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyExportCode").'</td>';
1944 print '<td>';
1945 if ($type == 0) {
1946 $accountancy_code_buy_export = (GETPOST('accountancy_code_buy_export') ? GETPOST('accountancy_code_buy_export', 'alpha') : getDolGlobalString("ACCOUNTING_PRODUCT_BUY_EXPORT_ACCOUNT"));
1947 } else {
1948 $accountancy_code_buy_export = (GETPOST('accountancy_code_buy_export') ? GETPOST('accountancy_code_buy_export', 'alpha') : getDolGlobalString("ACCOUNTING_SERVICE_BUY_EXPORT_ACCOUNT"));
1949 }
1950 print $formaccounting->select_account($accountancy_code_buy_export, 'accountancy_code_buy_export', 1, array(), 1, 1, 'minwidth150 maxwidth300', '1');
1951 print '</td></tr>';
1952 } else {// For external software
1953 if (!empty($accountancy_code_sell)) {
1954 $object->accountancy_code_sell = $accountancy_code_sell;
1955 }
1956 if (!empty($accountancy_code_sell_intra)) {
1957 $object->accountancy_code_sell_intra = $accountancy_code_sell_intra;
1958 }
1959 if (!empty($accountancy_code_sell_export)) {
1960 $object->accountancy_code_sell_export = $accountancy_code_sell_export;
1961 }
1962 if (!empty($accountancy_code_buy)) {
1963 $object->accountancy_code_buy = $accountancy_code_buy;
1964 }
1965 if (!empty($accountancy_code_buy_intra)) {
1966 $object->accountancy_code_buy_intra = $accountancy_code_buy_intra;
1967 }
1968 if (!empty($accountancy_code_buy_export)) {
1969 $object->accountancy_code_buy_export = $accountancy_code_buy_export;
1970 }
1971
1972 // Accountancy_code_sell
1973 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellCode").'</td>';
1974 print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_sell" value="'.$object->accountancy_code_sell.'">';
1975 print '</td></tr>';
1976
1977 // Accountancy_code_sell_intra
1978 if ($mysoc->isInEEC()) {
1979 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellIntraCode").'</td>';
1980 print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_sell_intra" value="'.$object->accountancy_code_sell_intra.'">';
1981 print '</td></tr>';
1982 }
1983
1984 // Accountancy_code_sell_export
1985 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellExportCode").'</td>';
1986 print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_sell_export" value="'.$object->accountancy_code_sell_export.'">';
1987 print '</td></tr>';
1988
1989 // Accountancy_code_buy
1990 print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
1991 print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_buy" value="'.$object->accountancy_code_buy.'">';
1992 print '</td></tr>';
1993
1994 // Accountancy_code_buy_intra
1995 if ($mysoc->isInEEC()) {
1996 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyIntraCode").'</td>';
1997 print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_buy_intra" value="'.$object->accountancy_code_buy_intra.'">';
1998 print '</td></tr>';
1999 }
2000
2001 // Accountancy_code_buy_export
2002 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyExportCode").'</td>';
2003 print '<td class="maxwidthonsmartphone"><input class="minwidth150" name="accountancy_code_buy_export" value="'.$object->accountancy_code_buy_export.'">';
2004 print '</td></tr>';
2005 }
2006 }
2007 print '</table>';
2008 }
2009
2010 print dol_get_fiche_end();
2011
2012 print $form->buttonsSaveCancel("Create");
2013
2014 print '</form>';
2015 } elseif ($object->id > 0) {
2016 /*
2017 * Product card
2018 */
2019
2020 // Card in edit mode
2021 if ($action == 'edit' && $usercancreate) {
2022 //WYSIWYG Editor
2023 require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
2024
2025 if (!empty($conf->use_javascript_ajax)) {
2026 print '<script type="text/javascript">';
2027 print '$(document).ready(function () {
2028 $("#selectcountry_id").change(function () {
2029 document.formprod.action.value="edit";
2030 document.formprod.submit();
2031 });
2032 });';
2033 print '</script>'."\n";
2034 }
2035
2036 // We set country_id, country_code and country for the selected country
2037 $object->country_id = GETPOST('country_id') ? GETPOST('country_id') : $object->country_id;
2038 if ($object->country_id) {
2039 $tmparray = getCountry($object->country_id, 'all');
2040 $object->country_code = $tmparray['code'];
2041 $object->country = $tmparray['label'];
2042 }
2043
2044 $type = $langs->trans('Product');
2045 if ($object->isService()) {
2046 $type = $langs->trans('Service');
2047 }
2048 // print load_fiche_titre($langs->trans('Modify').' '.$type.' : '.(is_object($object->oldcopy)?$object->oldcopy->ref:$object->ref), "");
2049
2050 // Main official, simple, and not duplicated code
2051 print '<form action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'" method="POST" name="formprod">'."\n";
2052 print '<input type="hidden" name="token" value="'.newToken().'">';
2053 print '<input type="hidden" name="action" value="update">';
2054 print '<input type="hidden" name="id" value="'.$object->id.'">';
2055 print '<input type="hidden" name="canvas" value="'.$object->canvas.'">';
2056
2058 $titre = $langs->trans("CardProduct".$object->type);
2059 $picto = ($object->type == Product::TYPE_SERVICE ? 'service' : 'product');
2060 print dol_get_fiche_head($head, 'card', $titre, 0, $picto, 0, '', '', 0, '', 1);
2061
2062 // Call Hook tabContentEditProduct
2063 $parameters = array();
2064 // Note that $action and $object may be modified by hook
2065 $reshook = $hookmanager->executeHooks('tabContentEditProduct', $parameters, $object, $action);
2066
2067 if (empty($reshook)) {
2068 print '<table class="border allwidth">';
2069
2070 // Ref
2071 if (!getDolGlobalString('MAIN_PRODUCT_REF_NOT_EDITABLE')) {
2072 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>';
2073 } else {
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($object->ref).'" readonly="true"></td></tr>';
2075 }
2076
2077 // Label
2078 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>';
2079
2080 // Status To sell
2081 print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Sell").')</td><td colspan="3">';
2082 print '<select class="flat" name="statut">';
2083 if ((GETPOSTISSET('statut') && GETPOST('statut')) || (!GETPOSTISSET('statut') && $object->status)) {
2084 print '<option value="1" selected>'.$langs->trans("OnSell").'</option>';
2085 print '<option value="0">'.$langs->trans("NotOnSell").'</option>';
2086 } else {
2087 print '<option value="1">'.$langs->trans("OnSell").'</option>';
2088 print '<option value="0" selected>'.$langs->trans("NotOnSell").'</option>';
2089 }
2090 print '</select>';
2091 print '</td></tr>';
2092
2093 // Status To Buy
2094 print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Buy").')</td><td colspan="3">';
2095 print '<select class="flat" name="statut_buy">';
2096 if ((GETPOSTISSET('statut_buy') && GETPOST('statut_buy')) || (!GETPOSTISSET('statut_buy') && $object->status_buy)) {
2097 print '<option value="1" selected>'.$langs->trans("ProductStatusOnBuy").'</option>';
2098 print '<option value="0">'.$langs->trans("ProductStatusNotOnBuy").'</option>';
2099 } else {
2100 print '<option value="1">'.$langs->trans("ProductStatusOnBuy").'</option>';
2101 print '<option value="0" selected>'.$langs->trans("ProductStatusNotOnBuy").'</option>';
2102 }
2103 print '</select>';
2104 print '</td></tr>';
2105
2106 // Batch number management
2107 if (isModEnabled('productbatch')) {
2108 if ($object->isProduct() || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
2109 print '<tr><td>'.$langs->trans("ManageLotSerial").'</td><td>';
2110 $statutarray = array('0' => $langs->trans("ProductStatusNotOnBatch"), '1' => $langs->trans("ProductStatusOnBatch"), '2' => $langs->trans("ProductStatusOnSerial"));
2111
2112 print $form->selectarray('status_batch', $statutarray, GETPOSTISSET('status_batch') ? GETPOSTINT('status_batch') : $object->status_batch);
2113
2114 print '<span id="statusBatchWarning" class="warning" style="display: none;">';
2115 print img_warning().'&nbsp;'.$langs->trans("WarningConvertFromBatchToSerial").'</span>';
2116
2117 print '<span id="statusBatchMouvToGlobal" class="warning" style="display: none;">';
2118 print img_warning().'&nbsp;'.$langs->trans("WarningTransferBatchStockMouvToGlobal").'</span>';
2119
2120 if ($object->status_batch) {
2121 // Display message to make user know that all batch will be move into global stock
2122 print '<script type="text/javascript">
2123 $(document).ready(function() {
2124 console.log($("#statusBatchWarning"))
2125 $("#status_batch").on("change", function() {
2126 if ($("#status_batch")[0].value == 0) {
2127 $("#statusBatchMouvToGlobal").show()
2128 } else {
2129 $("#statusBatchMouvToGlobal").hide()
2130 }
2131 })
2132 })</script>';
2133
2134 // 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)
2135 if ($object->status_batch == 1) {
2136 print '<script type="text/javascript">
2137 $(document).ready(function() {
2138 console.log($("#statusBatchWarning"))
2139 $("#status_batch").on("change", function() {
2140 if ($("#status_batch")[0].value == 2) {
2141 $("#statusBatchWarning").show()
2142 } else {
2143 $("#statusBatchWarning").hide()
2144 }
2145 })
2146 })</script>';
2147 }
2148 }
2149
2150 print '</td></tr>';
2151 if (!empty($object->status_batch) || !empty($conf->use_javascript_ajax)) {
2152 $langs->load("admin");
2153 $tooltip = $langs->trans("GenericMaskCodes", $langs->transnoentities("Batch"), $langs->transnoentities("Batch"));
2154 $tooltip .= '<br>'.$langs->trans("GenericMaskCodes2");
2155 $tooltip .= '<br>'.$langs->trans("GenericMaskCodes3");
2156 $tooltip .= '<br>'.$langs->trans("GenericMaskCodes4a", $langs->transnoentities("Batch"), $langs->transnoentities("Batch"));
2157 $tooltip .= '<br>'.$langs->trans("GenericMaskCodes5");
2158 //$tooltip .= '<br>'.$langs->trans("GenericMaskCodes5b");
2159
2160 print '<tr><td id="mask_option">'.$langs->trans("ManageLotMask").'</td>';
2161 $mask = '';
2162 if ($object->status_batch == '1' && getDolGlobalString('PRODUCTBATCH_LOT_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_LOT_ADDON') == 'mod_lot_advanced') {
2163 $mask = !empty($object->batch_mask) ? $object->batch_mask : getDolGlobalString('LOT_ADVANCED_MASK');
2164 }
2165 if ($object->status_batch == '2' && getDolGlobalString('PRODUCTBATCH_SN_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_SN_ADDON') == 'mod_sn_advanced') {
2166 $mask = !empty($object->batch_mask) ? $object->batch_mask : getDolGlobalString('SN_ADVANCED_MASK');
2167 }
2168 $inherited_mask_lot = getDolGlobalString('LOT_ADVANCED_MASK');
2169 $inherited_mask_sn = getDolGlobalString('SN_ADVANCED_MASK');
2170 print '<td id="field_mask">';
2171 print $form->textwithpicto('<input type="text" class="flat minwidth175" name="batch_mask" id="batch_mask_input" value="'.$mask.'">', $tooltip, 1, 'help');
2172 // Add javascript to sho/hide field for custom mask
2173 if (!empty($conf->use_javascript_ajax)) {
2174 print '<script type="text/javascript">
2175 $(document).ready(function() {
2176 $("#field_mask").parent().addClass("hideobject");
2177 var preselect = document.getElementById("status_batch");';
2178 if (getDolGlobalString('PRODUCTBATCH_SN_USE_PRODUCT_MASKS')) {
2179 print 'if (preselect.value == "2") {
2180 $("#field_mask").parent().removeClass("hideobject");
2181 }';
2182 }
2183 if (getDolGlobalString('PRODUCTBATCH_LOT_USE_PRODUCT_MASKS')) {
2184 print 'if (preselect.value == "1") {
2185 $("#field_mask").parent().removeClass("hideobject");
2186 }';
2187 }
2188 print '$("#status_batch").on("change", function () {
2189 var optionSelected = $("option:selected", this);
2190 var valueSelected = this.value;
2191 $("#field_mask").parent().addClass("hideobject");
2192 ';
2193 if (getDolGlobalString('PRODUCTBATCH_LOT_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_LOT_ADDON') == 'mod_lot_advanced') {
2194 print '
2195 if (this.value == 1) {
2196 $("#field_mask").parent().removeClass("hideobject");
2197 $("#batch_mask_input").val("'.$inherited_mask_lot.'");
2198 }
2199 ';
2200 }
2201 if (getDolGlobalString('PRODUCTBATCH_SN_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_SN_ADDON') == 'mod_sn_advanced') {
2202 print '
2203 if (this.value == 2) {
2204 $("#field_mask").parent().removeClass("hideobject");
2205 $("#batch_mask_input").val("'.$inherited_mask_sn.'");
2206 }
2207 ';
2208 }
2209 print '
2210 })
2211 })
2212 </script>';
2213 }
2214 print '</td></tr>';
2215 }
2216 }
2217
2218 // SellBy / EatBy mandatory list
2219 if (!empty($sellOrEatByMandatoryList)) {
2220 if (GETPOSTISSET('sell_or_eat_by_mandatory')) {
2221 $sellOrEatByMandatorySelectedId = GETPOSTINT('sell_or_eat_by_mandatory');
2222 } else {
2223 $sellOrEatByMandatorySelectedId = $object->sell_or_eat_by_mandatory;
2224 }
2225 print '<tr><td>'.$langs->trans('BatchSellOrEatByMandatoryList', $langs->transnoentities('SellByDate'), $langs->transnoentities('EatByDate')).'</td><td>';
2226 print $form->selectarray('sell_or_eat_by_mandatory', $sellOrEatByMandatoryList, $sellOrEatByMandatorySelectedId);
2227 print '</td></tr>';
2228 }
2229 }
2230
2231 // Barcode
2232 $showbarcode = isModEnabled('barcode');
2233 if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('barcode', 'lire_advance')) {
2234 $showbarcode = 0;
2235 }
2236
2237 if ($showbarcode) {
2238 print '<tr><td>'.$langs->trans('BarcodeType').'</td><td>';
2239 if (GETPOSTISSET('fk_barcode_type')) {
2240 $fk_barcode_type = GETPOST('fk_barcode_type');
2241 } else {
2242 $fk_barcode_type = $object->barcode_type;
2243 if (empty($fk_barcode_type) && getDolGlobalString('PRODUIT_DEFAULT_BARCODE_TYPE')) {
2244 $fk_barcode_type = getDolGlobalString('PRODUIT_DEFAULT_BARCODE_TYPE');
2245 }
2246 }
2247 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formbarcode.class.php';
2248 $formbarcode = new FormBarCode($db);
2249 print $formbarcode->selectBarcodeType($fk_barcode_type, 'fk_barcode_type', 1);
2250 print '</td></tr>';
2251 print '<tr><td>'.$langs->trans("BarcodeValue").'</td><td>';
2252 $tmpcode = GETPOSTISSET('barcode') ? GETPOST('barcode') : $object->barcode;
2253 if (empty($tmpcode) && !empty($modBarCodeProduct->code_auto)) {
2254 $tmpcode = $modBarCodeProduct->getNextValue($object, $fk_barcode_type);
2255 }
2256 print '<input class="maxwidth150 maxwidthonsmartphone" type="text" name="barcode" value="'.dol_escape_htmltag($tmpcode).'">';
2257 print '</td></tr>';
2258 }
2259
2260 // Description (used in invoice, propal...)
2261 print '<tr><td class="tdtop">'.$langs->trans("Description").'</td><td>';
2262
2263 // 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.
2264 $doleditor = new DolEditor('desc', GETPOSTISSET('desc') ? GETPOST('desc', 'restricthtml') : $object->description, '', 160, 'dolibarr_details', '', false, true, getDolGlobalInt('FCKEDITOR_ENABLE_DETAILS'), ROWS_4, '90%');
2265 $doleditor->Create();
2266
2267 print "</td></tr>";
2268 print "\n";
2269
2270 // Public Url
2271 if (!getDolGlobalString('PRODUCT_DISABLE_PUBLIC_URL')) {
2272 print '<tr><td>'.$langs->trans("PublicUrl").'</td><td>';
2273 print img_picto('', 'globe', 'class="pictofixedwidth"');
2274 print '<input type="text" name="url" class="maxwidth500 widthcentpercentminusx" value="'.(GETPOSTISSET('url') ? GETPOST('url') : $object->url).'">';
2275 print '</td></tr>';
2276 }
2277
2278 // Stock
2279 if (($object->isProduct() || getDolGlobalInt('STOCK_SUPPORTS_SERVICES')) && isModEnabled('stock')) {
2280 if (isModEnabled('productbatch') && $object->hasbatch()) {
2281 print '<tr><td><input type="hidden" id="stockable_product" name="stockable_product" value="on" /></td><td></td></tr>';
2282 } else {
2283 print '<tr><td><label for="stockable_product">' . $langs->trans("StockableProduct") . '</label></td>';
2284 $checked = empty($object->stockable_product) ? "" : "checked";
2285 print '<td><input type="checkbox" id="stockable_product" name="stockable_product" '. $checked . ' /></td></tr>';
2286 }
2287
2288 // Default warehouse
2289 print '<tr class="showifstockable'.(empty($object->stockable_product) ? ' hidden' : '').'"><td>'.$langs->trans("DefaultWarehouse").'</td><td>';
2290 print img_picto($langs->trans("DefaultWarehouse"), 'stock', 'class="pictofixedwidth"');
2291 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');
2292 print ' <a href="'.DOL_URL_ROOT.'/product/stock/card.php?action=create&amp;backtopage='.urlencode($_SERVER['PHP_SELF'].'?action=edit&id='.((int) $object->id)).'">';
2293 print '<span class="fa fa-plus-circle valignmiddle paddingleft" title="'.$langs->trans("AddWarehouse").'"></span></a>';
2294 print '</td></tr>';
2295
2296 /*
2297 print "<tr>".'<td>'.$langs->trans("StockLimit").'</td><td>';
2298 print '<input name="seuil_stock_alerte" size="4" value="'.$object->seuil_stock_alerte.'">';
2299 print '</td>';
2300
2301 print '<td>'.$langs->trans("DesiredStock").'</td><td>';
2302 print '<input name="desiredstock" size="4" value="'.$object->desiredstock.'">';
2303 print '</td></tr>';
2304 */
2305 }
2306
2307 if ($object->isService() && isModEnabled('workstation')) {
2308 // Default workstation
2309 print '<tr><td>'.$langs->trans("DefaultWorkstation").'</td><td>';
2310 print img_picto($langs->trans("DefaultWorkstation"), 'workstation', 'class="pictofixedwidth"');
2311 print $formproduct->selectWorkstations($object->fk_default_workstation, 'fk_default_workstation', 1);
2312 print '</td></tr>';
2313 }
2314
2315 /*
2316 else
2317 {
2318 print '<input name="seuil_stock_alerte" type="hidden" value="'.$object->seuil_stock_alerte.'">';
2319 print '<input name="desiredstock" type="hidden" value="'.$object->desiredstock.'">';
2320 }*/
2321
2322 if ($object->isService()) {
2323 // Duration
2324 print '<tr><td>'.$langs->trans("Duration").'</td><td>';
2325 print '<input name="duration_value" class="width50" value="'.($object->duration_value ? $object->duration_value : '').'"> ';
2326
2327 print $formproduct->selectMeasuringUnits("duration_unit", "time", ($object->duration_unit ? $object->duration_unit : 'h'), 0, 1);
2328
2329 // Mandatory period
2330 //if ($object->duration_value > 0) {
2331 print ' &nbsp; &nbsp; ';
2332 //}
2333 print '<input type="checkbox" class="valignmiddle" id="mandatoryperiod" name="mandatoryperiod"'.($object->mandatory_period == 1 ? ' checked="checked"' : '').'>';
2334 print '<label for="mandatoryperiod">';
2335 $htmltooltip = $langs->trans("mandatoryHelper");
2336 if (!getDolGlobalString('SERVICE_STRICT_MANDATORY_PERIOD')) {
2337 $htmltooltip .= '<br>'.$langs->trans("mandatoryHelper2");
2338 }
2339 print $form->textwithpicto($langs->trans("mandatoryperiod"), $htmltooltip, 1, 'info');
2340 print '</label>';
2341
2342 print '</td></tr>';
2343 } else {
2344 if (!getDolGlobalString('PRODUCT_DISABLE_NATURE')) {
2345 // Nature
2346 print '<tr><td>'.$form->textwithpicto($langs->trans("NatureOfProductShort"), $langs->trans("NatureOfProductDesc")).'</td><td>';
2347 print $formproduct->selectProductNature('finished', (GETPOSTISSET('finished') ? GETPOST('finished') : $object->finished));
2348 print '</td></tr>';
2349 }
2350 }
2351
2352 if (!$object->isService() && isModEnabled('bom')) {
2353 print '<tr><td>'.$form->textwithpicto($langs->trans("DefaultBOM"), $langs->trans("DefaultBOMDesc", $langs->transnoentitiesnoconv("Finished"))).'</td><td>';
2354 $bomkey = "Bom:bom/class/bom.class.php:0:(t.status:=:1) AND (t.fk_product:=:".((int) $object->id).')';
2355 print img_picto($langs->trans("DefaultBOM"), 'bom', 'class="pictofixedwidth"');
2356 print $form->selectForForms($bomkey, 'fk_default_bom', (GETPOSTISSET('fk_default_bom') ? GETPOST('fk_default_bom') : $object->fk_default_bom), 1);
2357 print '</td></tr>';
2358 }
2359
2360 if (!$object->isService()) {
2361 if (!getDolGlobalString('PRODUCT_DISABLE_WEIGHT')) {
2362 // Brut Weight
2363 print '<tr><td>'.$langs->trans("Weight").'</td><td>';
2364 print '<input name="weight" size="5" value="'.(GETPOSTISSET('weight') ? GETPOST('weight') : $object->weight).'"> ';
2365 print $formproduct->selectMeasuringUnits("weight_units", "weight", GETPOSTISSET('weight_units') ? GETPOST('weight_units') : (int) $object->weight_units, 0, 2);
2366 print '</td></tr>';
2367 }
2368
2369 if (!getDolGlobalString('PRODUCT_DISABLE_SIZE')) {
2370 // Brut Length
2371 print '<tr><td>'.$langs->trans("Length").' x '.$langs->trans("Width").' x '.$langs->trans("Height").'</td><td>';
2372 print '<input name="size" size="5" value="'.(GETPOSTISSET('size') ? GETPOST('size') : $object->length).'">x';
2373 print '<input name="sizewidth" size="5" value="'.(GETPOSTISSET('sizewidth') ? GETPOST('sizewidth') : $object->width).'">x';
2374 print '<input name="sizeheight" size="5" value="'.(GETPOSTISSET('sizeheight') ? GETPOST('sizeheight') : $object->height).'"> ';
2375 print $formproduct->selectMeasuringUnits("size_units", "size", GETPOSTISSET('size_units') ? GETPOST('size_units') : (int) $object->length_units, 0, 2);
2376 print '</td></tr>';
2377 }
2378 if (!getDolGlobalString('PRODUCT_DISABLE_SURFACE')) {
2379 // Brut Surface
2380 print '<tr><td>'.$langs->trans("Surface").'</td><td>';
2381 print '<input name="surface" size="5" value="'.(GETPOSTISSET('surface') ? GETPOST('surface') : $object->surface).'"> ';
2382 print $formproduct->selectMeasuringUnits("surface_units", "surface", GETPOSTISSET('surface_units') ? GETPOST('surface_units') : (int) $object->surface_units, 0, 2);
2383 print '</td></tr>';
2384 }
2385 if (!getDolGlobalString('PRODUCT_DISABLE_VOLUME')) {
2386 // Brut Volume
2387 print '<tr><td>'.$langs->trans("Volume").'</td><td>';
2388 print '<input name="volume" size="5" value="'.(GETPOSTISSET('volume') ? GETPOST('volume') : $object->volume).'"> ';
2389 print $formproduct->selectMeasuringUnits("volume_units", "volume", GETPOSTISSET('volume_units') ? GETPOST('volume_units') : (int) $object->volume_units, 0, 2);
2390 print '</td></tr>';
2391 }
2392
2393 if (getDolGlobalString('PRODUCT_ADD_NET_MEASURE')) {
2394 // Net Measure
2395 print '<tr><td>'.$langs->trans("NetMeasure").'</td><td>';
2396 print '<input name="net_measure" size="5" value="'.(GETPOSTISSET('net_measure') ? GETPOST('net_measure') : $object->net_measure).'"> ';
2397 print $formproduct->selectMeasuringUnits("net_measure_units", "", GETPOSTISSET('net_measure_units') ? GETPOST('net_measure_units') : (int) $object->net_measure_units, 0, 0);
2398 print '</td></tr>';
2399 }
2400 }
2401 // Units
2402 if (getDolGlobalString('PRODUCT_USE_UNITS')) {
2403 print '<tr><td>'.$langs->trans('DefaultUnitToShow').'</td>';
2404 print '<td>';
2405 print $form->selectUnits($object->fk_unit, 'units');
2406 print '</td></tr>';
2407 }
2408
2409 // Customs code
2410 if (!$object->isService() && !getDolGlobalString('PRODUCT_DISABLE_CUSTOMS_INFO')) {
2411 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>';
2412 // Origin country
2413 print '<tr><td>'.$langs->trans("CountryOrigin").'</td>';
2414 print '<td>';
2415 print img_picto('', 'globe-americas', 'class="paddingrightonly"');
2416 print $form->select_country((string) (GETPOSTISSET('country_id') ? GETPOSTINT('country_id') : $object->country_id), 'country_id', '', 0, 'minwidth100 maxwidthonsmartphone');
2417 if ($user->admin) {
2418 print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"), 1);
2419 }
2420 print '</td></tr>';
2421
2422 // State
2423 if (!getDolGlobalString('PRODUCT_DISABLE_STATE')) {
2424 print '<tr>';
2425 if (getDolGlobalString('MAIN_SHOW_REGION_IN_STATE_SELECT') && (getDolGlobalInt('MAIN_SHOW_REGION_IN_STATE_SELECT') == 1 || getDolGlobalInt('MAIN_SHOW_REGION_IN_STATE_SELECT') == 2)) {
2426 print '<td>'.$form->editfieldkey('RegionStateOrigin', 'state_id', '', $object, 0).'</td><td>';
2427 } else {
2428 print '<td>'.$form->editfieldkey('StateOrigin', 'state_id', '', $object, 0).'</td><td>';
2429 }
2430
2431 print img_picto('', 'state', 'class="pictofixedwidth"');
2432 print $formcompany->select_state(GETPOSTISSET('state_id') ? GETPOSTINT('state_id') : $object->state_id, $object->country_code);
2433 print '</td>';
2434 print '</tr>';
2435 }
2436 }
2437
2438 // Quality control
2439 if (getDolGlobalString('PRODUCT_LOT_ENABLE_QUALITY_CONTROL')) {
2440 print '<tr><td>'.$langs->trans("LifeTime").'</td><td><input name="lifetime" class="maxwidth100onsmartphone" value="'.$object->lifetime.'"></td></tr>';
2441 print '<tr><td>'.$langs->trans("QCFrequency").'</td><td><input name="qc_frequency" class="maxwidth100onsmartphone" value="'.$object->qc_frequency.'"></td></tr>';
2442 }
2443
2444 // Other attributes
2445 $parameters = array('colspan' => ' colspan="2"', 'cols' => 2);
2446 $reshook = $hookmanager->executeHooks('formObjectOptions', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
2447 print $hookmanager->resPrint;
2448 if (empty($reshook)) {
2449 print $object->showOptionals($extrafields, 'edit', $parameters);
2450 }
2451
2452 // Tags-Categories
2453 if (isModEnabled('category')) {
2454 print '<tr><td>'.$langs->trans("Categories").'</td><td>';
2455 print $form->selectCategories(Categorie::TYPE_PRODUCT, 'categories', $object);
2456 print "</td></tr>";
2457 }
2458
2459 // Note private
2460 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
2461 print '<tr><td class="tdtop">'.$langs->trans("NoteNotVisibleOnBill").'</td><td>';
2462
2463 $doleditor = new DolEditor('note_private', $object->note_private, '', 140, 'dolibarr_notes', '', false, true, getDolGlobalInt('FCKEDITOR_ENABLE_NOTE_PRIVATE'), ROWS_4, '90%');
2464 $doleditor->Create();
2465
2466 print "</td></tr>";
2467 }
2468
2469 print '</table>';
2470
2471 if (!getDolGlobalString('PRODUCT_DISABLE_ACCOUNTING')) {
2472 print '<hr>';
2473
2474 print '<table class="border centpercent">';
2475
2476 if (isModEnabled('accounting')) {
2478 // Accountancy_code_sell
2479 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellCode").'</td>';
2480 print '<td>';
2481 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');
2482 print '</td></tr>';
2483
2484 // Accountancy_code_sell_intra
2485 if ($mysoc->isInEEC()) {
2486 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellIntraCode").'</td>';
2487 print '<td>';
2488 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');
2489 print '</td></tr>';
2490 }
2491
2492 // Accountancy_code_sell_export
2493 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellExportCode").'</td>';
2494 print '<td>';
2495 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');
2496 print '</td></tr>';
2497
2498 // Accountancy_code_buy
2499 print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
2500 print '<td>';
2501 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');
2502 print '</td></tr>';
2503
2504 // Accountancy_code_buy_intra
2505 if ($mysoc->isInEEC()) {
2506 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyIntraCode").'</td>';
2507 print '<td>';
2508 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');
2509 print '</td></tr>';
2510 }
2511
2512 // Accountancy_code_buy_export
2513 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyExportCode").'</td>';
2514 print '<td>';
2515 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');
2516 print '</td></tr>';
2517 } else {
2518 // For external software
2519 // Accountancy_code_sell
2520 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellCode").'</td>';
2521 print '<td><input name="accountancy_code_sell" class="maxwidth200" value="'.(GETPOSTISSET('accountancy_code_sell') ? GETPOST('accountancy_code_sell') : $object->accountancy_code_sell).'">';
2522 print '</td></tr>';
2523
2524 // Accountancy_code_sell_intra
2525 if ($mysoc->isInEEC()) {
2526 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellIntraCode").'</td>';
2527 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).'">';
2528 print '</td></tr>';
2529 }
2530
2531 // Accountancy_code_sell_export
2532 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellExportCode").'</td>';
2533 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).'">';
2534 print '</td></tr>';
2535
2536 // Accountancy_code_buy
2537 print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
2538 print '<td><input name="accountancy_code_buy" class="maxwidth200" value="'.(GETPOSTISSET('accountancy_code_buy') ? GETPOST('accountancy_code_buy') : $object->accountancy_code_buy).'">';
2539 print '</td></tr>';
2540
2541 // Accountancy_code_buy_intra
2542 if ($mysoc->isInEEC()) {
2543 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyIntraCode").'</td>';
2544 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).'">';
2545 print '</td></tr>';
2546 }
2547
2548 // Accountancy_code_buy_export
2549 print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancyBuyExportCode").'</td>';
2550 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).'">';
2551 print '</td></tr>';
2552 }
2553
2554 print '</table>';
2555 }
2556 }
2557
2558 print '<script>';
2559 print '$(document).ready(function() {
2560 $("#stockable_product").change(function() {
2561 $(".showifstockable").toggle(this.checked);
2562 });
2563 });';
2564
2565 print '</script>';
2566
2567
2568 print dol_get_fiche_end();
2569
2570 print $form->buttonsSaveCancel();
2571
2572 print '</form>';
2573 } else {
2574 // Card in view mode
2575
2576 $showbarcode = isModEnabled('barcode');
2577 if (getDolGlobalString('MAIN_USE_ADVANCED_PERMS') && !$user->hasRight('barcode', 'lire_advance')) {
2578 $showbarcode = 0;
2579 }
2580
2582 $titre = $langs->trans("CardProduct".$object->type);
2583 $picto = ($object->type == Product::TYPE_SERVICE ? 'service' : 'product');
2584
2585 print dol_get_fiche_head($head, 'card', $titre, -1, $picto, 0, '', '', 0, '', 1);
2586
2587 $linkback = '<a href="'.DOL_URL_ROOT.'/product/list.php?restore_lastsearch_values=1&type='.$object->type.'">'.$langs->trans("BackToList").'</a>';
2588 $object->next_prev_filter = "(te.fk_product_type:=:".((int) $object->type).")";
2589
2590 $shownav = 1;
2591 if ($user->socid && !in_array('product', explode(',', getDolGlobalString('MAIN_MODULES_FOR_EXTERNAL')))) {
2592 $shownav = 0;
2593 }
2594
2595 dol_banner_tab($object, 'ref', $linkback, $shownav, 'ref');
2596
2597 // Call Hook tabContentViewProduct
2598 $parameters = array();
2599 // Note that $action and $object may be modified by hook
2600 $reshook = $hookmanager->executeHooks('tabContentViewProduct', $parameters, $object, $action);
2601 if (empty($reshook)) {
2602 print '<div class="fichecenter">';
2603 print '<div class="fichehalfleft">';
2604
2605 print '<div class="underbanner clearboth"></div>';
2606 print '<table class="border tableforfield centpercent">';
2607
2608 // Type
2609 if (isModEnabled("product") && isModEnabled("service")) {
2610 $typeformat = 'select;0:'.$langs->trans("Product").',1:'.$langs->trans("Service");
2611 print '<tr><td class="titlefield">';
2612 print (!getDolGlobalString('PRODUCT_DENY_CHANGE_PRODUCT_TYPE')) ? $form->editfieldkey("Type", 'fk_product_type', (string) $object->type, $object, (int) $usercancreate, $typeformat) : $langs->trans('Type');
2613 print '</td><td>';
2614 print $form->editfieldval("Type", 'fk_product_type', $object->type, $object, $usercancreate, $typeformat);
2615 print '</td></tr>';
2616 }
2617
2618 if ($showbarcode) {
2619 // Barcode type
2620 print '<tr><td class="nowrap">';
2621 print '<table width="100%" class="nobordernopadding"><tr><td class="nowrap">';
2622 print $langs->trans("BarcodeType");
2623 print '</td>';
2624 if (($action != 'editbarcodetype') && $usercancreate && $createbarcode) {
2625 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>';
2626 }
2627 print '</tr></table>';
2628 print '</td><td>';
2629 if ($action == 'editbarcodetype' || $action == 'editbarcode') {
2630 require_once DOL_DOCUMENT_ROOT.'/core/class/html.formbarcode.class.php';
2631 $formbarcode = new FormBarCode($db);
2632 }
2633
2634 $fk_barcode_type = '';
2635 if ($action == 'editbarcodetype' && is_object($formbarcode)) {
2636 print $formbarcode->formBarcodeType($_SERVER['PHP_SELF'].'?id='.$object->id, $object->barcode_type, 'fk_barcode_type');
2637 $fk_barcode_type = $object->barcode_type;
2638 } else {
2639 $object->fetchBarCode();
2640 $fk_barcode_type = $object->barcode_type;
2641 print $object->barcode_type_label ? $object->barcode_type_label : ($object->barcode ? '<div class="warning">'.$langs->trans("SetDefaultBarcodeType").'<div>' : '');
2642 }
2643 print '</td></tr>'."\n";
2644
2645 // Barcode value
2646 print '<tr><td class="nowrap">';
2647 print '<table width="100%" class="nobordernopadding"><tr><td class="nowrap">';
2648 print $langs->trans("BarcodeValue");
2649 print '</td>';
2650 if (($action != 'editbarcode') && $usercancreate && $createbarcode) {
2651 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>';
2652 }
2653 print '</tr></table>';
2654 print '</td><td class="wordbreak">';
2655 if ($action == 'editbarcode') {
2656 $tmpcode = GETPOSTISSET('barcode') ? GETPOST('barcode') : $object->barcode;
2657 if (empty($tmpcode) && !empty($modBarCodeProduct->code_auto)) {
2658 $tmpcode = $modBarCodeProduct->getNextValue($object, (string) $fk_barcode_type);
2659 }
2660
2661 print '<form method="post" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">';
2662 print '<input type="hidden" name="token" value="'.newToken().'">';
2663 print '<input type="hidden" name="action" value="setbarcode">';
2664 print '<input type="hidden" name="barcode_type_code" value="'.$object->barcode_type_code.'">';
2665 print '<input class="width300" class="maxwidthonsmartphone" type="text" name="barcode" value="'.$tmpcode.'">';
2666 print '&nbsp;<input type="submit" class="button smallpaddingimp" value="'.$langs->trans("Modify").'">';
2667 print '</form>';
2668 } else {
2670 }
2671 print '</td></tr>'."\n";
2672 }
2673
2674 // Batch number management (to batch)
2675 if (isModEnabled('productbatch')) {
2676 if ($object->isProduct() || getDolGlobalString('STOCK_SUPPORTS_SERVICES')) {
2677 print '<tr><td>'.$langs->trans("ManageLotSerial").'</td><td>';
2678 print $object->getLibStatut(0, 2);
2679 print '</td></tr>';
2680 if ((($object->status_batch == '1' && getDolGlobalString('PRODUCTBATCH_LOT_USE_PRODUCT_MASKS') && getDolGlobalString('PRODUCTBATCH_LOT_ADDON') == 'mod_lot_advanced')
2681 || ($object->status_batch == '2' && getDolGlobalString('PRODUCTBATCH_SN_ADDON') == 'mod_sn_advanced' && getDolGlobalString('PRODUCTBATCH_SN_USE_PRODUCT_MASKS')))) {
2682 print '<tr><td>'.$langs->trans("ManageLotMask").'</td><td>';
2683 print $object->batch_mask;
2684 print '</td></tr>';
2685 }
2686 }
2687
2688 print '<tr><td>'.$langs->trans('BatchSellOrEatByMandatoryList', $langs->transnoentities('SellByDate'), $langs->transnoentities('EatByDate')).'</td><td>';
2689 print $object->getSellOrEatByMandatoryLabel();
2690 print '</td></tr>';
2691 }
2692
2693 if (!getDolGlobalString('PRODUCT_DISABLE_ACCOUNTING')) {
2694 // Accountancy sell code
2695 print '<tr><td class="nowrap">';
2696 print $langs->trans("ProductAccountancySellCode");
2697 print '</td><td>';
2698 if (isModEnabled('accounting')) {
2699 if (!empty($object->accountancy_code_sell)) {
2700 $accountingaccount = new AccountingAccount($db);
2701 $accountingaccount->fetch(0, $object->accountancy_code_sell, 1);
2702
2703 print $accountingaccount->getNomUrl(0, 1, 1, '', 1);
2704 }
2705 } else {
2706 print $object->accountancy_code_sell;
2707 }
2708 print '</td></tr>';
2709
2710 // Accountancy sell code intra-community
2711 if ($mysoc->isInEEC()) {
2712 print '<tr><td class="nowrap">';
2713 print $langs->trans("ProductAccountancySellIntraCode");
2714 print '</td><td>';
2715 if (isModEnabled('accounting')) {
2716 if (!empty($object->accountancy_code_sell_intra)) {
2717 $accountingaccount2 = new AccountingAccount($db);
2718 $accountingaccount2->fetch(0, $object->accountancy_code_sell_intra, 1);
2719
2720 print $accountingaccount2->getNomUrl(0, 1, 1, '', 1);
2721 }
2722 } else {
2723 print $object->accountancy_code_sell_intra;
2724 }
2725 print '</td></tr>';
2726 }
2727
2728 // Accountancy sell code export
2729 print '<tr><td class="nowrap">';
2730 print $langs->trans("ProductAccountancySellExportCode");
2731 print '</td><td>';
2732 if (isModEnabled('accounting')) {
2733 if (!empty($object->accountancy_code_sell_export)) {
2734 $accountingaccount3 = new AccountingAccount($db);
2735 $accountingaccount3->fetch(0, $object->accountancy_code_sell_export, 1);
2736
2737 print $accountingaccount3->getNomUrl(0, 1, 1, '', 1);
2738 }
2739 } else {
2740 print $object->accountancy_code_sell_export;
2741 }
2742 print '</td></tr>';
2743
2744 // Accountancy buy code
2745 print '<tr><td class="nowrap">';
2746 print $langs->trans("ProductAccountancyBuyCode");
2747 print '</td><td>';
2748 if (isModEnabled('accounting')) {
2749 if (!empty($object->accountancy_code_buy)) {
2750 $accountingaccount4 = new AccountingAccount($db);
2751 $accountingaccount4->fetch(0, $object->accountancy_code_buy, 1);
2752
2753 print $accountingaccount4->getNomUrl(0, 1, 1, '', 1);
2754 }
2755 } else {
2756 print $object->accountancy_code_buy;
2757 }
2758 print '</td></tr>';
2759
2760 // Accountancy buy code intra-community
2761 if ($mysoc->isInEEC()) {
2762 print '<tr><td class="nowrap">';
2763 print $langs->trans("ProductAccountancyBuyIntraCode");
2764 print '</td><td>';
2765 if (isModEnabled('accounting')) {
2766 if (!empty($object->accountancy_code_buy_intra)) {
2767 $accountingaccount5 = new AccountingAccount($db);
2768 $accountingaccount5->fetch(0, $object->accountancy_code_buy_intra, 1);
2769
2770 print $accountingaccount5->getNomUrl(0, 1, 1, '', 1);
2771 }
2772 } else {
2773 print $object->accountancy_code_buy_intra;
2774 }
2775 print '</td></tr>';
2776 }
2777
2778 // Accountancy buy code export
2779 print '<tr><td class="nowrap">';
2780 print $langs->trans("ProductAccountancyBuyExportCode");
2781 print '</td><td>';
2782 if (isModEnabled('accounting')) {
2783 if (!empty($object->accountancy_code_buy_export)) {
2784 $accountingaccount6 = new AccountingAccount($db);
2785 $accountingaccount6->fetch(0, $object->accountancy_code_buy_export, 1);
2786
2787 print $accountingaccount6->getNomUrl(0, 1, 1, '', 1);
2788 }
2789 } else {
2790 print $object->accountancy_code_buy_export;
2791 }
2792 print '</td></tr>';
2793 }
2794
2795 // Description
2796 print '<tr><td class="tdtop">'.$langs->trans("Description").'</td>';
2797 print '<td class="wordbreakimp wrapimp"><div class="longmessagecut">'.(dol_textishtml($object->description) ? $object->description : dol_nl2br($object->description, 1, true)).'</div></td></tr>';
2798
2799 // Public URL
2800 if (!getDolGlobalString('PRODUCT_DISABLE_PUBLIC_URL')) {
2801 print '<tr><td>'.$langs->trans("PublicUrl").'</td><td>';
2802 print dol_print_url($object->url, '_blank', 128);
2803 print '</td></tr>';
2804 }
2805
2806 // Stockable product / default warehouse
2807 if (($object->isProduct() || getDolGlobalInt('STOCK_SUPPORTS_SERVICES')) && isModEnabled('stock')) {
2808 print '<tr><td>' . $form->textwithpicto($langs->trans("StockableProduct"), $langs->trans('StockableProductDescription')) . '</td>';
2809 print '<td><input type="checkbox" readonly disabled '.($object->stockable_product == 1 ? 'checked' : '').'></td></tr>';
2810
2811 if ($object->isStockManaged()) {
2812 $warehouse = new Entrepot($db);
2813 $warehouse->fetch($object->fk_default_warehouse);
2814
2815 print '<tr><td>'.$langs->trans("DefaultWarehouse").'</td><td>';
2816 print(!empty($warehouse->id) ? $warehouse->getNomUrl(1) : '');
2817 print '</td>';
2818 }
2819 }
2820
2821 if ($object->isService() && isModEnabled('workstation')) {
2822 $workstation = new Workstation($db);
2823 $res = $workstation->fetch($object->fk_default_workstation);
2824
2825 print '<tr><td>'.$langs->trans("DefaultWorkstation").'</td><td>';
2826 print(!empty($workstation->id) ? $workstation->getNomUrl(1) : '');
2827 print '</td>';
2828 }
2829
2830 // Parent product.
2831 if (isModEnabled('variants') && ($object->isProduct() || $object->isService())) {
2832 $combination = new ProductCombination($db);
2833
2834 if ($combination->fetchByFkProductChild($object->id) > 0) {
2835 $prodstatic = new Product($db);
2836 $prodstatic->fetch($combination->fk_product_parent);
2837
2838 // Parent product
2839 print '<tr><td>'.$langs->trans("ParentProduct").'</td><td>';
2840 print $prodstatic->getNomUrl(1);
2841 print '</td></tr>';
2842 }
2843 }
2844
2845 print '</table>';
2846
2847 print '</div>';
2848 print '<div class="fichehalfright">';
2849 print '<div class="underbanner clearboth"></div>';
2850
2851 print '<table class="border tableforfield centpercent">';
2852
2853 if ($object->isService()) {
2854 // Duration
2855 require_once DOL_DOCUMENT_ROOT.'/core/class/cunits.class.php';
2856 $measuringUnits = new CUnits($db);
2857 $durations = [];
2858 $plural = '';
2859 if ($object->duration_value > 1) {
2860 $plural = 's';
2861 }
2862 $result = $measuringUnits->fetchAll('', 'scale', 0, 0, ['t.active' => 1, 't.unit_type' => 'time']);
2863 if ($result !== -1) {
2864 foreach ($measuringUnits->records as $record) {
2865 $durations[$record->short_label] = dol_ucfirst($record->label) . $plural;
2866 }
2867 }
2868 print '<tr><td class="titlefieldmiddle">'.$langs->trans("Duration").'</td><td>';
2869 if ($object->duration_value) {
2870 print $object->duration_value;
2871 print(!empty($object->duration_unit) && isset($durations[$object->duration_unit]) ? "&nbsp; ".$langs->trans($durations[$object->duration_unit])."&nbsp;" : '');
2872 }
2873
2874 // Mandatory period
2875 $htmltooltip = $langs->trans("mandatoryHelper");
2876 if (!getDolGlobalString('SERVICE_STRICT_MANDATORY_PERIOD')) {
2877 $htmltooltip .= '<br>'.$langs->trans("mandatoryHelper2");
2878 }
2879 if ($object->duration_value > 0) {
2880 print ' &nbsp; &nbsp; ';
2881 }
2882 print '<input type="checkbox" class="valignmiddle" name="mandatoryperiod"'.($object->mandatory_period == 1 ? ' checked="checked"' : '').' disabled>';
2883 print $form->textwithpicto($langs->trans("mandatoryperiod"), $htmltooltip, 1, 'info');
2884
2885 print '</td></tr>';
2886 } else {
2887 if (!getDolGlobalString('PRODUCT_DISABLE_NATURE')) {
2888 // Nature
2889 print '<tr><td class="titlefieldmiddle">'.$form->textwithpicto($langs->trans("NatureOfProductShort"), $langs->trans("NatureOfProductDesc")).'</td><td>';
2890 print $object->getLibFinished();
2891 print '</td></tr>';
2892 }
2893 }
2894
2895 if (!$object->isService() && isModEnabled('bom') && $object->finished) {
2896 print '<tr><td class="titlefieldmiddle">'.$form->textwithpicto($langs->trans("DefaultBOM"), $langs->trans("DefaultBOMDesc", $langs->transnoentitiesnoconv("Finished"))).'</td><td>';
2897 if ($object->fk_default_bom) {
2898 $bom_static = new BOM($db);
2899 $bom_static->fetch($object->fk_default_bom);
2900 print $bom_static->getNomUrl(1);
2901 }
2902 print '</td></tr>';
2903 }
2904
2905 if (!$object->isService()) {
2906 // Brut Weight
2907 if (!getDolGlobalString('PRODUCT_DISABLE_WEIGHT')) {
2908 print '<tr><td class="titlefieldmiddle">'.$langs->trans("Weight").'</td><td>';
2909 if ($object->weight != '') {
2910 print $object->weight." ".measuringUnitString(0, "weight", $object->weight_units);
2911 } else {
2912 print '&nbsp;';
2913 }
2914 print "</td></tr>\n";
2915 }
2916
2917 if (!getDolGlobalString('PRODUCT_DISABLE_SIZE')) {
2918 // Brut Length
2919 print '<tr><td>'.$langs->trans("Length").' x '.$langs->trans("Width").' x '.$langs->trans("Height").'</td><td>';
2920 if ($object->length != '' || $object->width != '' || $object->height != '') {
2921 print $object->length;
2922 if ($object->width) {
2923 print " x ".$object->width;
2924 }
2925 if ($object->height) {
2926 print " x ".$object->height;
2927 }
2928 print ' '.measuringUnitString(0, "size", $object->length_units);
2929 } else {
2930 print '&nbsp;';
2931 }
2932 print "</td></tr>\n";
2933 }
2934 if (!getDolGlobalString('PRODUCT_DISABLE_SURFACE') || !getDolGlobalString('PRODUCT_DISABLE_VOLUME')) {
2935 // Brut Surface / Volume
2936 print '<tr><td>';
2937 print (getDolGlobalString('PRODUCT_DISABLE_SURFACE') ? '' : $langs->trans("Surface"));
2938 print (!getDolGlobalString('PRODUCT_DISABLE_SURFACE') && !getDolGlobalString('PRODUCT_DISABLE_VOLUME')) ? ' / ' : '';
2939 print (getDolGlobalString('PRODUCT_DISABLE_VOLUME') ? '' : $langs->trans("Volume")).'</td><td>';
2940 if (!getDolGlobalString('PRODUCT_DISABLE_SURFACE') && $object->surface != '') {
2941 print $object->surface." ".measuringUnitString(0, "surface", $object->surface_units);
2942 }
2943 print (!getDolGlobalString('PRODUCT_DISABLE_SURFACE') && !getDolGlobalString('PRODUCT_DISABLE_VOLUME') && $object->surface && $object->volume) ? ' / ' : '';
2944 if (!getDolGlobalString('PRODUCT_DISABLE_VOLUME') && $object->volume != '') {
2945 print $object->volume." ".measuringUnitString(0, "volume", $object->volume_units);
2946 }
2947 print "</td></tr>\n";
2948 }
2949
2950 if (getDolGlobalString('PRODUCT_ADD_NET_MEASURE')) {
2951 // Net Measure
2952 print '<tr><td class="titlefieldmiddle">'.$langs->trans("NetMeasure").'</td><td>';
2953 if ($object->net_measure != '') {
2954 print $object->net_measure." ".measuringUnitString((int) $object->net_measure_units);
2955 } else {
2956 print '&nbsp;';
2957 }
2958 print '</td></tr>';
2959 }
2960 }
2961
2962 // Unit
2963 if (getDolGlobalString('PRODUCT_USE_UNITS')) {
2964 $unit = $object->getLabelOfUnit('long', $langs);
2965
2966 print '<tr><td>'.$langs->trans('DefaultUnitToShow').'</td><td>';
2967 print $unit;
2968 print '</td></tr>';
2969 }
2970
2971 // Custom code
2972 if (!$object->isService() && !getDolGlobalString('PRODUCT_DISABLE_CUSTOMS_INFO')) {
2973 print '<tr><td>'.$form->textwithpicto($langs->trans("CustomsCode"), $langs->trans("CustomsCodeHelp")).'</td><td>'.dolPrintHTML($object->customcode).'</td></tr>';
2974
2975 // Origin country code
2976 print '<tr><td>'.$langs->trans("Origin").'</td><td>'.getCountry($object->country_id, '', $db);
2977 if (!empty($object->state_id)) {
2978 print ' - '.getState($object->state_id, '0', $db);
2979 }
2980 print '</td></tr>';
2981 }
2982
2983 // Quality Control
2984 if (getDolGlobalString('PRODUCT_LOT_ENABLE_QUALITY_CONTROL')) {
2985 print '<tr><td>'.$langs->trans("LifeTime").'</td><td>'.$object->lifetime.'</td></tr>';
2986 print '<tr><td>'.$langs->trans("QCFrequency").'</td><td>'.$object->qc_frequency.'</td></tr>';
2987 }
2988
2989 // Other attributes
2990 $parameters = array();
2991 include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
2992
2993 // Categories
2994 if (isModEnabled('category')) {
2995 print '<tr><td class="valignmiddle">'.$langs->trans("Categories").'</td><td>';
2996 print $form->showCategories($object->id, Categorie::TYPE_PRODUCT, 1);
2997 print "</td></tr>";
2998 }
2999
3000 // Note private
3001 if (getDolGlobalString('MAIN_DISABLE_NOTES_TAB')) {
3002 print '<!-- show Note --> '."\n";
3003 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";
3004 print '<!-- End show Note --> '."\n";
3005 }
3006
3007 print "</table>\n";
3008 print '</div>';
3009
3010 print '</div>';
3011 print '<div class="clearboth"></div>';
3012 }
3013
3014 print dol_get_fiche_end();
3015 }
3016 } elseif ($action != 'create') {
3017 exit;
3018 }
3019}
3020
3021$tmpcode = '';
3022if (!empty($modCodeProduct->code_auto)) {
3023 $tmpcode = $modCodeProduct->getNextValue($object, $object->type);
3024}
3025
3026$formconfirm = '';
3027
3028// Confirm delete product
3029if (($action == 'delete' && (empty($conf->use_javascript_ajax) || !empty($conf->dol_use_jmobile))) // Output when action = clone if jmobile or no js
3030 || (!empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile))) { // Always output when not jmobile nor js
3031 $formconfirm = $form->formconfirm("card.php?id=".$object->id, $langs->trans("DeleteProduct"), $langs->trans("ConfirmDeleteProduct"), "confirm_delete", '', 0, "action-delete");
3032}
3033if ($action == 'merge') {
3034 $formquestion = array(
3035 array(
3036 'name' => 'product_origin',
3037 'label' => $langs->trans('MergeOriginProduct'),
3038 'type' => 'other',
3039 'value' => $form->select_produits(0, 'product_origin', '', 0, 0, 1, 2, '', 1, array(), 0, 1, 0, 'minwidth200', 0, '', null, 1),
3040 )
3041 );
3042 $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id, $langs->trans("MergeProducts"), $langs->trans("ConfirmMergeProducts"), "confirm_merge", $formquestion, 'no', 1, 250);
3043}
3044
3045// Clone confirmation
3046if (($action == 'clone' && (empty($conf->use_javascript_ajax) || !empty($conf->dol_use_jmobile))) // Output when action = clone if jmobile or no js
3047 || (!empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile))) { // Always output when not jmobile nor js
3048 // Define confirmation messages
3049 $formquestionclone = array(
3050 'text' => $langs->trans("ConfirmClone"),
3051 0 => array('type' => 'text', 'name' => 'clone_ref', 'label' => $langs->trans("NewRefForClone"), 'value' => empty($tmpcode) ? $langs->trans("CopyOf").' '.$object->ref : $tmpcode, 'morecss' => 'width150'),
3052 1 => array('type' => 'checkbox', 'name' => 'clone_content', 'label' => $langs->trans("CloneContentProduct"), 'value' => 1),
3053 2 => array('type' => 'checkbox', 'name' => 'clone_categories', 'label' => $langs->trans("CloneCategoriesProduct"), 'value' => 1),
3054 );
3055 if (getDolGlobalString('PRODUIT_MULTIPRICES')) {
3056 $formquestionclone[] = array('type' => 'checkbox', 'name' => 'clone_prices', 'label' => $langs->trans("ClonePricesProduct").' ('.$langs->trans("CustomerPrices").')', 'value' => 0);
3057 }
3058 if (getDolGlobalString('PRODUIT_SOUSPRODUITS')) {
3059 $formquestionclone[] = array('type' => 'checkbox', 'name' => 'clone_composition', 'label' => $langs->trans('CloneCompositionProduct'), 'value' => 1);
3060 }
3061 if (isModEnabled('bom') && $user->hasRight('bom', 'write')) {
3062 if ($object->fk_default_bom > 0) {
3063 $formquestionclone[] = array('type' => 'checkbox', 'name' => 'clone_defbom', 'label' => $langs->trans("CloneDefBomProduct"), 'value' => getDolGlobalInt('BOM_CLONE_DEFBOM'));
3064 }
3065 $bomstatic = new BOM($db);
3066 $bomlist = $bomstatic->fetchAll("", "", 0, 0, 'fk_product:=:'.(int) $object->id);
3067 if (is_array($bomlist) && count($bomlist) > 0) {
3068 $formquestionclone[] = array('type' => 'checkbox', 'name' => 'clone_otherboms', 'label' => $langs->trans("CloneOtherBomsProduct"), 'value' => 0);
3069 }
3070 }
3071 $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);
3072}
3073
3074// Call Hook formConfirm
3075$parameters = array('formConfirm' => $formconfirm, 'object' => $object);
3076$reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3077if (empty($reshook)) {
3078 $formconfirm .= $hookmanager->resPrint;
3079} elseif ($reshook > 0) {
3080 $formconfirm = $hookmanager->resPrint;
3081}
3082
3083// Print form confirm
3084print $formconfirm;
3085
3086/*
3087 * Action bar
3088 */
3089if ($action != 'create' && $action != 'edit') {
3090 $cloneProductUrl = $_SERVER["PHP_SELF"].'?action=clone&token='.newToken();
3091 $cloneButtonId = 'action-clone-no-ajax';
3092
3093 print "\n".'<div class="tabsAction">'."\n";
3094
3095 $parameters = array();
3096 $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
3097 if (empty($reshook)) {
3098 if ($usercancreate) {
3099 if (!isset($hookmanager->resArray['no_button_edit']) || $hookmanager->resArray['no_button_edit'] != 1) {
3100 print dolGetButtonAction('', $langs->trans('Modify'), 'default', $_SERVER["PHP_SELF"].'?action=edit&token='.newToken().'&id='.$object->id, '', $usercancreate);
3101 }
3102
3103 //Send
3104 print dolGetButtonAction('', $langs->trans('SendMail'), 'default', $_SERVER["PHP_SELF"] . '?id=' . $object->id . '&action=presend&mode=init&token=' . newToken() . '#formmailbeforetitle');
3105
3106 if (!isset($hookmanager->resArray['no_button_copy']) || $hookmanager->resArray['no_button_copy'] != 1) {
3107 if (!empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile)) {
3108 $cloneProductUrl = '';
3109 $cloneButtonId = 'action-clone';
3110 }
3111 print dolGetButtonAction($langs->trans('ToClone'), '', 'default', $cloneProductUrl, $cloneButtonId, $usercancreate);
3112 }
3113 }
3114 $object_is_used = $object->isObjectUsed($object->id);
3115
3116 if ($usercandelete) {
3117 if (empty($object_is_used)) {
3118 if (!isset($hookmanager->resArray['no_button_delete']) || $hookmanager->resArray['no_button_delete'] != 1) {
3119 if (!empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile)) {
3120 print dolGetButtonAction($langs->trans('Delete'), '', 'delete', '#', 'action-delete', true);
3121 } else {
3122 print dolGetButtonAction('', $langs->trans('Delete'), 'delete', $_SERVER["PHP_SELF"].'?action=delete&token='.newToken().'&id='.$object->id, '');
3123 }
3124 }
3125 } else {
3126 print dolGetButtonAction($langs->trans("ProductIsUsed"), $langs->trans('Delete'), 'delete', '#', '', false);
3127 }
3128 if (getDolGlobalInt('MAIN_FEATURES_LEVEL') > 1) {
3129 print '<a class="butActionDelete" href="card.php?action=merge&id='.$object->id.'" title="'.dol_escape_htmltag($langs->trans("MergeProducts")).'">'.$langs->trans('Merge').'</a>'."\n";
3130 }
3131 } else {
3132 print dolGetButtonAction($langs->trans("NotEnoughPermissions"), $langs->trans('Delete'), 'delete', '#', '', false);
3133 }
3134 }
3135
3136 print "\n</div>\n";
3137}
3138
3139
3140/*
3141 * All the "Add to" areas if PRODUCT_ADD_FORM_ADD_TO is set
3142 */
3143
3144if (getDolGlobalString('PRODUCT_ADD_FORM_ADD_TO') && $object->id && ($action == '' || $action == 'view') && $object->status) {
3145 //Variable used to check if any text is going to be printed
3146 $html = '';
3147 //print '<div class="fichecenter"><div class="fichehalfleft">';
3148
3149 // Propals
3150 if (isModEnabled("propal") && $user->hasRight('propal', 'creer')) {
3151 $propal = new Propal($db);
3152
3153 $langs->load("propal");
3154
3155 $otherprop = $propal->liste_array(2, 1, 0);
3156
3157 if (is_array($otherprop) && count($otherprop)) {
3158 $html .= '<tr><td style="width: 200px;">';
3159 $html .= $langs->trans("AddToDraftProposals").'</td><td>';
3160 $html .= $form->selectarray("propalid", $otherprop, 0, 1);
3161 $html .= '</td></tr>';
3162 } else {
3163 $html .= '<tr><td style="width: 200px;">';
3164 $html .= $langs->trans("AddToDraftProposals").'</td><td>';
3165 $html .= $langs->trans("NoDraftProposals");
3166 $html .= '</td></tr>';
3167 }
3168 }
3169
3170 // Commande
3171 if (isModEnabled('order') && $user->hasRight('commande', 'creer')) {
3172 $commande = new Commande($db);
3173
3174 $langs->load("orders");
3175
3176 $othercom = $commande->liste_array(2, 1, null);
3177 if (is_array($othercom) && count($othercom)) {
3178 $html .= '<tr><td style="width: 200px;">';
3179 $html .= $langs->trans("AddToDraftOrders").'</td><td>';
3180 $html .= $form->selectarray("commandeid", $othercom, 0, 1);
3181 $html .= '</td></tr>';
3182 } else {
3183 $html .= '<tr><td style="width: 200px;">';
3184 $html .= $langs->trans("AddToDraftOrders").'</td><td>';
3185 $html .= $langs->trans("NoDraftOrders");
3186 $html .= '</td></tr>';
3187 }
3188 }
3189
3190 // Factures
3191 if (isModEnabled('invoice') && $user->hasRight('facture', 'creer')) {
3192 $invoice = new Facture($db);
3193
3194 $langs->load("bills");
3195
3196 $otherinvoice = $invoice->liste_array(2, 1, null);
3197 if (is_array($otherinvoice) && count($otherinvoice)) {
3198 $html .= '<tr><td style="width: 200px;">';
3199 $html .= $langs->trans("AddToDraftInvoices").'</td><td>';
3200 $html .= $form->selectarray("factureid", $otherinvoice, 0, 1);
3201 $html .= '</td></tr>';
3202 } else {
3203 $html .= '<tr><td style="width: 200px;">';
3204 $html .= $langs->trans("AddToDraftInvoices").'</td><td>';
3205 $html .= $langs->trans("NoDraftInvoices");
3206 $html .= '</td></tr>';
3207 }
3208 }
3209
3210 // If any text is going to be printed, then we show the table
3211 if (!empty($html)) {
3212 print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">';
3213 print '<input type="hidden" name="token" value="'.newToken().'">';
3214 print '<input type="hidden" name="action" value="addin">';
3215
3216 print load_fiche_titre($langs->trans("AddToDraft"), '', '');
3217
3218 print dol_get_fiche_head();
3219
3220 $html .= '<tr><td class="nowrap">'.$langs->trans("Quantity").' ';
3221 $html .= '<input type="text" class="flat" name="qty" size="1" value="1"></td>';
3222 $html .= '<td class="nowrap">'.$langs->trans("ReductionShort").'(%) ';
3223 $html .= '<input type="text" class="flat" name="remise_percent" size="1" value="0">';
3224 $html .= '</td></tr>';
3225
3226 print '<table class="centpercent border">';
3227 print $html;
3228 print '</table>';
3229
3230 print '<div class="center">';
3231 print '<input type="submit" class="button button-add" value="'.$langs->trans("Add").'">';
3232 print '</div>';
3233
3234 print dol_get_fiche_end();
3235
3236 print '</form>';
3237 }
3238}
3239
3240
3241/*
3242 * Generated documents
3243 */
3244
3245if (GETPOST('modelselected')) {
3246 $action = 'presend';
3247}
3248
3249if ($action != 'create' && $action != 'edit' && $action != 'delete') {
3250 print '<div class="fichecenter"><div class="fichehalfleft">';
3251 print '<a name="builddoc"></a>'; // ancre
3252
3253 // Documents
3254 $objectref = dol_sanitizeFileName($object->ref);
3255 if (!empty($conf->product->multidir_output[$object->entity])) {
3256 $filedir = $conf->product->multidir_output[$object->entity].'/'.$objectref; //Check repertories of current entities
3257 } else {
3258 $filedir = $conf->product->dir_output.'/'.$objectref;
3259 }
3260 $urlsource = $_SERVER["PHP_SELF"]."?id=".$object->id;
3261 $genallowed = $usercanread;
3262 $delallowed = $usercancreate;
3263
3264 print $formfile->showdocuments($modulepart, $object->ref, $filedir, $urlsource, (int) $genallowed, (int) $delallowed, '', 0, 0, 0, 28, 0, '', '', '', $langs->getDefaultLang(), '', $object);
3265 $somethingshown = $formfile->numoffiles;
3266
3267 print '</div><div class="fichehalfright">';
3268
3269 $MAXEVENT = 10;
3270 $morehtmlcenter = '<div class="nowraponall">';
3271 $morehtmlcenter .= dolGetButtonTitle($langs->trans('FullConversation'), '', 'fa fa-comments imgforviewmode', DOL_URL_ROOT.'/product/messaging.php?id='.$object->id);
3272 $morehtmlcenter .= dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-bars imgforviewmode', DOL_URL_ROOT.'/product/agenda.php?id='.$object->id);
3273 $morehtmlcenter .= '</div>';
3274
3275 // List of actions on element
3276 include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php';
3277 $formactions = new FormActions($db);
3278 $somethingshown = $formactions->showactions($object, 'product', 0, 1, '', $MAXEVENT, '', $morehtmlcenter); // Show all action for product
3279
3280 print '</div></div>';
3281
3282 // Presend form
3283 $modelmail = 'product_send';
3284 $defaulttopic = $object->label;
3285 $diroutput = $conf->product->multidir_output[$object->entity];
3286 $trackid = 'prod' . $object->id;
3287
3288 include DOL_DOCUMENT_ROOT.'/core/tpl/card_presend.tpl.php';
3289}
3290
3291// End of page
3292llxFooter();
3293$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.