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