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