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