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