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