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