card.php 86 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011
  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-2017 Alexandre Spangaro <aspangaro.dolibarr@gmail.com>
  12. * Copyright (C) 2014 Cédric Gross <c.gross@kreiz-it.fr>
  13. * Copyright (C) 2014-2015 Ferran Marcet <fmarcet@2byte.es>
  14. * Copyright (C) 2015 Jean-François Ferry <jfefe@aternatik.fr>
  15. * Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
  16. * Copyright (C) 2016 Charlie Benke <charlie@patas-monkey.com>
  17. * Copyright (C) 2016 Meziane Sof <virtualsof@yahoo.fr>
  18. *
  19. * This program is free software; you can redistribute it and/or modify
  20. * it under the terms of the GNU General Public License as published by
  21. * the Free Software Foundation; either version 3 of the License, or
  22. * (at your option) any later version.
  23. *
  24. * This program is distributed in the hope that it will be useful,
  25. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  27. * GNU General Public License for more details.
  28. *
  29. * You should have received a copy of the GNU General Public License
  30. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  31. */
  32. /**
  33. * \file htdocs/product/card.php
  34. * \ingroup product
  35. * \brief Page to show product
  36. */
  37. require '../main.inc.php';
  38. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
  39. require_once DOL_DOCUMENT_ROOT.'/core/class/canvas.class.php';
  40. require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
  41. require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php';
  42. require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
  43. require_once DOL_DOCUMENT_ROOT.'/core/class/genericobject.class.php';
  44. require_once DOL_DOCUMENT_ROOT.'/core/lib/product.lib.php';
  45. require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
  46. require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
  47. require_once DOL_DOCUMENT_ROOT.'/core/modules/product/modules_product.php';
  48. if (! empty($conf->propal->enabled)) require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
  49. if (! empty($conf->facture->enabled)) require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
  50. if (! empty($conf->commande->enabled)) require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
  51. if (! empty($conf->accounting->enabled)) require_once DOL_DOCUMENT_ROOT.'/core/lib/accounting.lib.php';
  52. if (! empty($conf->accounting->enabled)) require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php';
  53. if (! empty($conf->accounting->enabled)) require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php';
  54. $langs->load("products");
  55. $langs->load("other");
  56. if (! empty($conf->stock->enabled)) $langs->load("stocks");
  57. if (! empty($conf->facture->enabled)) $langs->load("bills");
  58. if (! empty($conf->productbatch->enabled)) $langs->load("productbatch");
  59. $mesg=''; $error=0; $errors=array();
  60. $refalreadyexists=0;
  61. $id=GETPOST('id', 'int');
  62. $ref=GETPOST('ref', 'alpha');
  63. $type=GETPOST('type','int');
  64. $action=(GETPOST('action','alpha') ? GETPOST('action','alpha') : 'view');
  65. $cancel=GETPOST('cancel');
  66. $confirm=GETPOST('confirm','alpha');
  67. $socid=GETPOST('socid','int');
  68. $duration_value = GETPOST('duration_value');
  69. $duration_unit = GETPOST('duration_unit');
  70. if (! empty($user->societe_id)) $socid=$user->societe_id;
  71. $object = new Product($db);
  72. $extrafields = new ExtraFields($db);
  73. // fetch optionals attributes and labels
  74. $extralabels=$extrafields->fetch_name_optionals_label($object->table_element);
  75. if ($id > 0 || ! empty($ref))
  76. {
  77. $result = $object->fetch($id, $ref);
  78. if (! empty($conf->product->enabled)) $upload_dir = $conf->product->multidir_output[$object->entity].'/'.get_exdir(0, 0, 0, 0, $object, 'product').dol_sanitizeFileName($object->ref);
  79. elseif (! empty($conf->service->enabled)) $upload_dir = $conf->service->multidir_output[$object->entity].'/'.get_exdir(0, 0, 0, 0, $object, 'product').dol_sanitizeFileName($object->ref);
  80. if (! empty($conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO)) // For backward compatiblity, we scan also old dirs
  81. {
  82. if (! empty($conf->product->enabled)) $upload_dirold = $conf->product->multidir_output[$object->entity].'/'.substr(substr("000".$object->id, -2),1,1).'/'.substr(substr("000".$object->id, -2),0,1).'/'.$object->id."/photos";
  83. else $upload_dirold = $conf->service->multidir_output[$object->entity].'/'.substr(substr("000".$object->id, -2),1,1).'/'.substr(substr("000".$object->id, -2),0,1).'/'.$object->id."/photos";
  84. }
  85. }
  86. $modulepart='product';
  87. // Get object canvas (By default, this is not defined, so standard usage of dolibarr)
  88. $canvas = !empty($object->canvas)?$object->canvas:GETPOST("canvas");
  89. $objcanvas=null;
  90. if (! empty($canvas))
  91. {
  92. require_once DOL_DOCUMENT_ROOT.'/core/class/canvas.class.php';
  93. $objcanvas = new Canvas($db,$action);
  94. $objcanvas->getCanvas('product','card',$canvas);
  95. }
  96. // Security check
  97. $fieldvalue = (! empty($id) ? $id : (! empty($ref) ? $ref : ''));
  98. $fieldtype = (! empty($ref) ? 'ref' : 'rowid');
  99. $result=restrictedArea($user,'produit|service',$fieldvalue,'product&product','','',$fieldtype,$objcanvas);
  100. // Initialize technical object to manage hooks of thirdparties. Note that conf->hooks_modules contains array array
  101. $hookmanager->initHooks(array('productcard','globalcard'));
  102. /*
  103. * Actions
  104. */
  105. if ($cancel) $action = '';
  106. $createbarcode=empty($conf->barcode->enabled)?0:1;
  107. if (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->barcode->creer_advance)) $createbarcode=0;
  108. $parameters=array('id'=>$id, 'ref'=>$ref, 'objcanvas'=>$objcanvas);
  109. $reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks
  110. if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
  111. if (empty($reshook))
  112. {
  113. // Type
  114. if ($action == 'setfk_product_type' && $user->rights->produit->creer)
  115. {
  116. $result = $object->setValueFrom('fk_product_type', GETPOST('fk_product_type'), '', null, 'text', '', $user, 'PRODUCT_MODIFY');
  117. header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
  118. exit;
  119. }
  120. // Actions to build doc
  121. $upload_dir = $conf->produit->dir_output;
  122. $permissioncreate = $user->rights->produit->creer;
  123. include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php';
  124. include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php';
  125. // Barcode type
  126. if ($action == 'setfk_barcode_type' && $createbarcode)
  127. {
  128. $result = $object->setValueFrom('fk_barcode_type', GETPOST('fk_barcode_type'), '', null, 'text', '', $user, 'PRODUCT_MODIFY');
  129. header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
  130. exit;
  131. }
  132. // Barcode value
  133. if ($action == 'setbarcode' && $createbarcode)
  134. {
  135. $result=$object->check_barcode(GETPOST('barcode'),GETPOST('barcode_type_code'));
  136. if ($result >= 0)
  137. {
  138. $result = $object->setValueFrom('barcode', GETPOST('barcode'));
  139. header("Location: ".$_SERVER['PHP_SELF']."?id=".$object->id);
  140. exit;
  141. }
  142. else
  143. {
  144. $langs->load("errors");
  145. if ($result == -1) $errors[] = 'ErrorBadBarCodeSyntax';
  146. else if ($result == -2) $errors[] = 'ErrorBarCodeRequired';
  147. else if ($result == -3) $errors[] = 'ErrorBarCodeAlreadyUsed';
  148. else $errors[] = 'FailedToValidateBarCode';
  149. $error++;
  150. setEventMessages($errors, null, 'errors');
  151. }
  152. }
  153. // Add a product or service
  154. if ($action == 'add' && ($user->rights->produit->creer || $user->rights->service->creer))
  155. {
  156. $error=0;
  157. if (! GETPOST('label'))
  158. {
  159. setEventMessages($langs->trans('ErrorFieldRequired',$langs->transnoentities('Label')), null, 'errors');
  160. $action = "create";
  161. $error++;
  162. }
  163. if (empty($ref))
  164. {
  165. setEventMessages($langs->trans('ErrorFieldRequired',$langs->transnoentities('Ref')), null, 'errors');
  166. $action = "create";
  167. $error++;
  168. }
  169. if (! empty($duration_value) && empty($duration_unit))
  170. {
  171. setEventMessages($langs->trans('ErrorFieldRequired',$langs->transnoentities('Unit')), null, 'errors');
  172. $action = "create";
  173. $error++;
  174. }
  175. if (! $error)
  176. {
  177. $units = GETPOST('units', 'int');
  178. $object->ref = $ref;
  179. $object->label = GETPOST('label');
  180. $object->price_base_type = GETPOST('price_base_type');
  181. if ($object->price_base_type == 'TTC')
  182. $object->price_ttc = GETPOST('price');
  183. else
  184. $object->price = GETPOST('price');
  185. if ($object->price_base_type == 'TTC')
  186. $object->price_min_ttc = GETPOST('price_min');
  187. else
  188. $object->price_min = GETPOST('price_min');
  189. $object->tva_tx = str_replace('*','',GETPOST('tva_tx'));
  190. $object->tva_npr = preg_match('/\*/',GETPOST('tva_tx'))?1:0;
  191. // local taxes.
  192. $object->localtax1_tx = get_localtax($object->tva_tx,1);
  193. $object->localtax2_tx = get_localtax($object->tva_tx,2);
  194. $object->type = $type;
  195. $object->status = GETPOST('statut');
  196. $object->status_buy = GETPOST('statut_buy');
  197. $object->status_batch = GETPOST('status_batch');
  198. $object->barcode_type = GETPOST('fk_barcode_type');
  199. $object->barcode = GETPOST('barcode');
  200. // Set barcode_type_xxx from barcode_type id
  201. $stdobject=new GenericObject($db);
  202. $stdobject->element='product';
  203. $stdobject->barcode_type=GETPOST('fk_barcode_type');
  204. $result=$stdobject->fetch_barcode();
  205. if ($result < 0)
  206. {
  207. $error++;
  208. $mesg='Failed to get bar code type information ';
  209. setEventMessages($mesg.$stdobject->error, $mesg.$stdobject->errors, 'errors');
  210. }
  211. $object->barcode_type_code = $stdobject->barcode_type_code;
  212. $object->barcode_type_coder = $stdobject->barcode_type_coder;
  213. $object->barcode_type_label = $stdobject->barcode_type_label;
  214. $object->description = dol_htmlcleanlastbr(GETPOST('desc'));
  215. $object->url = GETPOST('url');
  216. $object->note_private = dol_htmlcleanlastbr(GETPOST('note_private'));
  217. $object->note = $object->note_private; // deprecated
  218. $object->customcode = GETPOST('customcode');
  219. $object->country_id = GETPOST('country_id');
  220. $object->duration_value = $duration_value;
  221. $object->duration_unit = $duration_unit;
  222. $object->seuil_stock_alerte = GETPOST('seuil_stock_alerte')?GETPOST('seuil_stock_alerte'):0;
  223. $object->desiredstock = GETPOST('desiredstock')?GETPOST('desiredstock'):0;
  224. $object->canvas = GETPOST('canvas');
  225. $object->weight = GETPOST('weight');
  226. $object->weight_units = GETPOST('weight_units');
  227. $object->length = GETPOST('size');
  228. $object->length_units = GETPOST('size_units');
  229. $object->width = GETPOST('sizewidth');
  230. $object->height = GETPOST('sizeheight');
  231. $object->surface = GETPOST('surface');
  232. $object->surface_units = GETPOST('surface_units');
  233. $object->volume = GETPOST('volume');
  234. $object->volume_units = GETPOST('volume_units');
  235. $object->finished = GETPOST('finished');
  236. $object->fk_unit = GETPOST('units');
  237. $accountancy_code_sell = GETPOST('accountancy_code_sell');
  238. $accountancy_code_buy = GETPOST('accountancy_code_buy');
  239. if ($accountancy_code_sell <= 0) { $object->accountancy_code_sell = ''; } else { $object->accountancy_code_sell = $accountancy_code_sell; }
  240. if ($accountancy_code_buy <= 0) { $object->accountancy_code_buy = ''; } else { $object->accountancy_code_buy = $accountancy_code_buy; }
  241. // MultiPrix
  242. if (! empty($conf->global->PRODUIT_MULTIPRICES))
  243. {
  244. for($i=2;$i<=$conf->global->PRODUIT_MULTIPRICES_LIMIT;$i++)
  245. {
  246. if (isset($_POST["price_".$i]))
  247. {
  248. $object->multiprices["$i"] = price2num($_POST["price_".$i],'MU');
  249. $object->multiprices_base_type["$i"] = $_POST["multiprices_base_type_".$i];
  250. }
  251. else
  252. {
  253. $object->multiprices["$i"] = "";
  254. }
  255. }
  256. }
  257. // Fill array 'array_options' with data from add form
  258. $ret = $extrafields->setOptionalsFromPost($extralabels,$object);
  259. if ($ret < 0) $error++;
  260. if (! $error)
  261. {
  262. $id = $object->create($user);
  263. }
  264. if ($id > 0)
  265. {
  266. // Category association
  267. $categories = GETPOST('categories');
  268. $object->setCategories($categories);
  269. header("Location: ".$_SERVER['PHP_SELF']."?id=".$id);
  270. exit;
  271. }
  272. else
  273. {
  274. if (count($object->errors)) setEventMessages($object->error, $object->errors, 'errors');
  275. else setEventMessages($langs->trans($object->error), null, 'errors');
  276. $action = "create";
  277. }
  278. }
  279. }
  280. // Update a product or service
  281. if ($action == 'update' && ($user->rights->produit->creer || $user->rights->service->creer))
  282. {
  283. if (GETPOST('cancel'))
  284. {
  285. $action = '';
  286. }
  287. else
  288. {
  289. if ($object->id > 0)
  290. {
  291. $object->oldcopy= clone $object;
  292. $object->ref = $ref;
  293. $object->label = GETPOST('label');
  294. $object->description = dol_htmlcleanlastbr(GETPOST('desc'));
  295. $object->url = GETPOST('url');
  296. if (! empty($conf->global->MAIN_DISABLE_NOTES_TAB))
  297. {
  298. $object->note_private = dol_htmlcleanlastbr(GETPOST('note_private'));
  299. $object->note = $object->note_private;
  300. }
  301. $object->customcode = GETPOST('customcode');
  302. $object->country_id = GETPOST('country_id');
  303. $object->status = GETPOST('statut');
  304. $object->status_buy = GETPOST('statut_buy');
  305. $object->status_batch = GETPOST('status_batch');
  306. // removed from update view so GETPOST always empty
  307. /*
  308. $object->seuil_stock_alerte = GETPOST('seuil_stock_alerte');
  309. $object->desiredstock = GETPOST('desiredstock');
  310. */
  311. $object->duration_value = GETPOST('duration_value');
  312. $object->duration_unit = GETPOST('duration_unit');
  313. $object->canvas = GETPOST('canvas');
  314. $object->weight = GETPOST('weight');
  315. $object->weight_units = GETPOST('weight_units');
  316. $object->length = GETPOST('size');
  317. $object->length_units = GETPOST('size_units');
  318. $object->width = GETPOST('sizewidth');
  319. $object->height = GETPOST('sizeheight');
  320. $object->surface = GETPOST('surface');
  321. $object->surface_units = GETPOST('surface_units');
  322. $object->volume = GETPOST('volume');
  323. $object->volume_units = GETPOST('volume_units');
  324. $object->finished = GETPOST('finished');
  325. $units = GETPOST('units', 'int');
  326. if ($units > 0) {
  327. $object->fk_unit = $units;
  328. } else {
  329. $object->fk_unit = null;
  330. }
  331. $object->barcode_type = GETPOST('fk_barcode_type');
  332. $object->barcode = GETPOST('barcode');
  333. // Set barcode_type_xxx from barcode_type id
  334. $stdobject=new GenericObject($db);
  335. $stdobject->element='product';
  336. $stdobject->barcode_type=GETPOST('fk_barcode_type');
  337. $result=$stdobject->fetch_barcode();
  338. if ($result < 0)
  339. {
  340. $error++;
  341. $mesg='Failed to get bar code type information ';
  342. setEventMessages($mesg.$stdobject->error, $mesg.$stdobject->errors, 'errors');
  343. }
  344. $object->barcode_type_code = $stdobject->barcode_type_code;
  345. $object->barcode_type_coder = $stdobject->barcode_type_coder;
  346. $object->barcode_type_label = $stdobject->barcode_type_label;
  347. $accountancy_code_sell = GETPOST('accountancy_code_sell');
  348. $accountancy_code_buy = GETPOST('accountancy_code_buy');
  349. if ($accountancy_code_sell <= 0) { $object->accountancy_code_sell = ''; } else { $object->accountancy_code_sell = $accountancy_code_sell; }
  350. if ($accountancy_code_buy <= 0) { $object->accountancy_code_buy = ''; } else { $object->accountancy_code_buy = $accountancy_code_buy; }
  351. // Fill array 'array_options' with data from add form
  352. $ret = $extrafields->setOptionalsFromPost($extralabels,$object);
  353. if ($ret < 0) $error++;
  354. if (! $error && $object->check())
  355. {
  356. if ($object->update($object->id, $user) > 0)
  357. {
  358. // Category association
  359. $categories = GETPOST('categories');
  360. $object->setCategories($categories);
  361. $action = 'view';
  362. }
  363. else
  364. {
  365. if (count($object->errors)) setEventMessages($object->error, $object->errors, 'errors');
  366. else setEventMessages($langs->trans($object->error), null, 'errors');
  367. $action = 'edit';
  368. }
  369. }
  370. else
  371. {
  372. if (count($object->errors)) setEventMessages($object->error, $object->errors, 'errors');
  373. else setEventMessages($langs->trans("ErrorProductBadRefOrLabel"), null, 'errors');
  374. $action = 'edit';
  375. }
  376. }
  377. }
  378. }
  379. // Action clone object
  380. if ($action == 'confirm_clone' && $confirm != 'yes') { $action=''; }
  381. if ($action == 'confirm_clone' && $confirm == 'yes' && ($user->rights->produit->creer || $user->rights->service->creer))
  382. {
  383. if (! GETPOST('clone_content') && ! GETPOST('clone_prices') )
  384. {
  385. setEventMessages($langs->trans("NoCloneOptionsSpecified"), null, 'errors');
  386. }
  387. else
  388. {
  389. $db->begin();
  390. $originalId = $id;
  391. if ($object->id > 0)
  392. {
  393. $object->ref = GETPOST('clone_ref');
  394. $object->status = 0;
  395. $object->status_buy = 0;
  396. $object->id = null;
  397. $object->barcode = -1;
  398. if ($object->check())
  399. {
  400. $id = $object->create($user);
  401. if ($id > 0)
  402. {
  403. if (GETPOST('clone_composition'))
  404. {
  405. $result = $object->clone_associations($originalId, $id);
  406. if ($result < 1)
  407. {
  408. $db->rollback();
  409. setEventMessages($langs->trans('ErrorProductClone'), null, 'errors');
  410. header("Location: ".$_SERVER["PHP_SELF"]."?id=".$originalId);
  411. exit;
  412. }
  413. }
  414. // $object->clone_fournisseurs($originalId, $id);
  415. $db->commit();
  416. $db->close();
  417. header("Location: ".$_SERVER["PHP_SELF"]."?id=".$id);
  418. exit;
  419. }
  420. else
  421. {
  422. $id=$originalId;
  423. if ($object->error == 'ErrorProductAlreadyExists')
  424. {
  425. $db->rollback();
  426. $refalreadyexists++;
  427. $action = "";
  428. $mesg=$langs->trans("ErrorProductAlreadyExists",$object->ref);
  429. $mesg.=' <a href="'.$_SERVER["PHP_SELF"].'?ref='.$object->ref.'">'.$langs->trans("ShowCardHere").'</a>.';
  430. setEventMessages($mesg, null, 'errors');
  431. $object->fetch($id);
  432. }
  433. else
  434. {
  435. $db->rollback();
  436. if (count($object->errors))
  437. {
  438. setEventMessages($object->error, $object->errors, 'errors');
  439. dol_print_error($db,$object->errors);
  440. }
  441. else
  442. {
  443. setEventMessages($langs->trans($object->error), null, 'errors');
  444. dol_print_error($db,$object->error);
  445. }
  446. }
  447. }
  448. }
  449. }
  450. else
  451. {
  452. $db->rollback();
  453. dol_print_error($db,$object->error);
  454. }
  455. }
  456. }
  457. // Delete a product
  458. if ($action == 'confirm_delete' && $confirm != 'yes') { $action=''; }
  459. if ($action == 'confirm_delete' && $confirm == 'yes')
  460. {
  461. if (($object->type == Product::TYPE_PRODUCT && $user->rights->produit->supprimer) || ($object->type == Product::TYPE_SERVICE && $user->rights->service->supprimer))
  462. {
  463. $result = $object->delete(DolibarrApiAccess::$user);
  464. }
  465. if ($result > 0)
  466. {
  467. header('Location: '.DOL_URL_ROOT.'/product/list.php?type='.$object->type.'&delprod='.urlencode($object->ref));
  468. exit;
  469. }
  470. else
  471. {
  472. setEventMessages($langs->trans($object->error), null, 'errors');
  473. $reload = 0;
  474. $action='';
  475. }
  476. }
  477. // Add product into object
  478. if ($object->id > 0 && $action == 'addin')
  479. {
  480. $thirpdartyid =0 ;
  481. if (GETPOST('propalid') > 0)
  482. {
  483. $propal = new Propal($db);
  484. $result=$propal->fetch(GETPOST('propalid'));
  485. if ($result <= 0)
  486. {
  487. dol_print_error($db,$propal->error);
  488. exit;
  489. }
  490. $thirpdartyid = $propal->socid;
  491. }
  492. elseif (GETPOST('commandeid') > 0)
  493. {
  494. $commande = new Commande($db);
  495. $result=$commande->fetch(GETPOST('commandeid'));
  496. if ($result <= 0)
  497. {
  498. dol_print_error($db,$commande->error);
  499. exit;
  500. }
  501. $thirpdartyid = $commande->socid;
  502. }
  503. elseif (GETPOST('factureid') > 0)
  504. {
  505. $facture = new Facture($db);
  506. $result=$facture->fetch(GETPOST('factureid'));
  507. if ($result <= 0)
  508. {
  509. dol_print_error($db,$facture->error);
  510. exit;
  511. }
  512. $thirpdartyid = $facture->socid;
  513. }
  514. if ( $thirpdartyid > 0) {
  515. $soc = new Societe($db);
  516. $result = $soc->fetch($thirpdartyid);
  517. if ($result <= 0) {
  518. dol_print_error($db, $soc->error);
  519. exit;
  520. }
  521. $desc = $object->description;
  522. $tva_tx = get_default_tva($mysoc, $soc, $object->id);
  523. $tva_npr = get_default_npr($mysoc, $soc, $object->id);
  524. if (empty($tva_tx)) $tva_npr=0;
  525. $localtax1_tx = get_localtax($tva_tx, 1, $soc, $mysoc, $tva_npr);
  526. $localtax2_tx = get_localtax($tva_tx, 2, $soc, $mysoc, $tva_npr);
  527. $pu_ht = $object->price;
  528. $pu_ttc = $object->price_ttc;
  529. $price_base_type = $object->price_base_type;
  530. // If multiprice
  531. if ($conf->global->PRODUIT_MULTIPRICES && $soc->price_level) {
  532. $pu_ht = $object->multiprices[$soc->price_level];
  533. $pu_ttc = $object->multiprices_ttc[$soc->price_level];
  534. $price_base_type = $object->multiprices_base_type[$soc->price_level];
  535. } elseif (!empty($conf->global->PRODUIT_CUSTOMER_PRICES)) {
  536. require_once DOL_DOCUMENT_ROOT . '/product/class/productcustomerprice.class.php';
  537. $prodcustprice = new Productcustomerprice($db);
  538. $filter = array('t.fk_product' => $object->id, 't.fk_soc' => $soc->id);
  539. $result = $prodcustprice->fetch_all('', '', 0, 0, $filter);
  540. if ($result) {
  541. if (count($prodcustprice->lines) > 0) {
  542. $pu_ht = price($prodcustprice->lines [0]->price);
  543. $pu_ttc = price($prodcustprice->lines [0]->price_ttc);
  544. $price_base_type = $prodcustprice->lines [0]->price_base_type;
  545. $tva_tx = $prodcustprice->lines [0]->tva_tx;
  546. }
  547. }
  548. }
  549. $tmpvat = price2num(preg_replace('/\s*\(.*\)/', '', $tva_tx));
  550. $tmpprodvat = price2num(preg_replace('/\s*\(.*\)/', '', $prod->tva_tx));
  551. // On reevalue prix selon taux tva car taux tva transaction peut etre different
  552. // de ceux du produit par defaut (par exemple si pays different entre vendeur et acheteur).
  553. if ($tmpvat != $tmpprodvat) {
  554. if ($price_base_type != 'HT') {
  555. $pu_ht = price2num($pu_ttc / (1 + ($tmpvat / 100)), 'MU');
  556. } else {
  557. $pu_ttc = price2num($pu_ht * (1 + ($tmpvat / 100)), 'MU');
  558. }
  559. }
  560. if (GETPOST('propalid') > 0) {
  561. // Define cost price for margin calculation
  562. $buyprice=0;
  563. if (($result = $propal->defineBuyPrice($pu_ht, GETPOST('remise_percent'), $object->id)) < 0)
  564. {
  565. dol_syslog($langs->trans('FailedToGetCostPrice'));
  566. setEventMessage($langs->trans('FailedToGetCostPrice'), 'errors');
  567. }
  568. else
  569. {
  570. $buyprice = $result;
  571. }
  572. $result = $propal->addline(
  573. $desc,
  574. $pu_ht,
  575. GETPOST('qty'),
  576. $tva_tx,
  577. $localtax1_tx, // localtax1
  578. $localtax2_tx, // localtax2
  579. $object->id,
  580. GETPOST('remise_percent'),
  581. $price_base_type,
  582. $pu_ttc,
  583. 0,
  584. 0,
  585. -1,
  586. 0,
  587. 0,
  588. 0,
  589. $buyprice,
  590. '',
  591. '',
  592. '',
  593. 0,
  594. $object->fk_unit
  595. );
  596. if ($result > 0) {
  597. header("Location: " . DOL_URL_ROOT . "/comm/propal/card.php?id=" . $propal->id);
  598. return;
  599. }
  600. setEventMessages($langs->trans("ErrorUnknown") . ": $result", null, 'errors');
  601. } elseif (GETPOST('commandeid') > 0) {
  602. // Define cost price for margin calculation
  603. $buyprice=0;
  604. if (($result = $commande->defineBuyPrice($pu_ht, GETPOST('remise_percent'), $object->id)) < 0)
  605. {
  606. dol_syslog($langs->trans('FailedToGetCostPrice'));
  607. setEventMessage($langs->trans('FailedToGetCostPrice'), 'errors');
  608. }
  609. else
  610. {
  611. $buyprice = $result;
  612. }
  613. $result = $commande->addline(
  614. $desc,
  615. $pu_ht,
  616. GETPOST('qty'),
  617. $tva_tx,
  618. $localtax1_tx, // localtax1
  619. $localtax2_tx, // localtax2
  620. $object->id,
  621. GETPOST('remise_percent'),
  622. '',
  623. '',
  624. $price_base_type,
  625. $pu_ttc,
  626. '',
  627. '',
  628. 0,
  629. -1,
  630. 0,
  631. 0,
  632. null,
  633. $buyprice,
  634. '',
  635. 0,
  636. $object->fk_unit
  637. );
  638. if ($result > 0) {
  639. header("Location: " . DOL_URL_ROOT . "/commande/card.php?id=" . $commande->id);
  640. exit;
  641. }
  642. } elseif (GETPOST('factureid') > 0) {
  643. // Define cost price for margin calculation
  644. $buyprice=0;
  645. if (($result = $facture->defineBuyPrice($pu_ht, GETPOST('remise_percent'), $object->id)) < 0)
  646. {
  647. dol_syslog($langs->trans('FailedToGetCostPrice'));
  648. setEventMessage($langs->trans('FailedToGetCostPrice'), 'errors');
  649. }
  650. else
  651. {
  652. $buyprice = $result;
  653. }
  654. $result = $facture->addline(
  655. $desc,
  656. $pu_ht,
  657. GETPOST('qty'),
  658. $tva_tx,
  659. $localtax1_tx,
  660. $localtax2_tx,
  661. $object->id,
  662. GETPOST('remise_percent'),
  663. '',
  664. '',
  665. '',
  666. '',
  667. '',
  668. $price_base_type,
  669. $pu_ttc,
  670. Facture::TYPE_STANDARD,
  671. -1,
  672. 0,
  673. '',
  674. 0,
  675. 0,
  676. null,
  677. $buyprice,
  678. '',
  679. 0,
  680. 100,
  681. '',
  682. $object->fk_unit
  683. );
  684. if ($result > 0) {
  685. header("Location: " . DOL_URL_ROOT . "/compta/facture/card.php?facid=" . $facture->id);
  686. exit;
  687. }
  688. }
  689. }
  690. else {
  691. $action="";
  692. setEventMessages($langs->trans("WarningSelectOneDocument"), null, 'warnings');
  693. }
  694. }
  695. }
  696. /*
  697. * View
  698. */
  699. $title = $langs->trans('ProductServiceCard');
  700. $helpurl = '';
  701. $shortlabel = dol_trunc($object->label,16);
  702. if (GETPOST("type") == '0' || ($object->type == Product::TYPE_PRODUCT))
  703. {
  704. $title = $langs->trans('Product')." ". $shortlabel ." - ".$langs->trans('Card');
  705. $helpurl='EN:Module_Products|FR:Module_Produits|ES:M&oacute;dulo_Productos';
  706. }
  707. if (GETPOST("type") == '1' || ($object->type == Product::TYPE_SERVICE))
  708. {
  709. $title = $langs->trans('Service')." ". $shortlabel ." - ".$langs->trans('Card');
  710. $helpurl='EN:Module_Services_En|FR:Module_Services|ES:M&oacute;dulo_Servicios';
  711. }
  712. llxHeader('', $title, $helpurl);
  713. $form = new Form($db);
  714. $formfile = new FormFile($db);
  715. $formproduct = new FormProduct($db);
  716. if (! empty($conf->accounting->enabled)) $formaccounting = New FormAccounting($db);
  717. // Load object modBarCodeProduct
  718. $res=0;
  719. if (! empty($conf->barcode->enabled) && ! empty($conf->global->BARCODE_PRODUCT_ADDON_NUM))
  720. {
  721. $module=strtolower($conf->global->BARCODE_PRODUCT_ADDON_NUM);
  722. $dirbarcode=array_merge(array('/core/modules/barcode/'),$conf->modules_parts['barcode']);
  723. foreach ($dirbarcode as $dirroot)
  724. {
  725. $res=dol_include_once($dirroot.$module.'.php');
  726. if ($res) break;
  727. }
  728. if ($res > 0)
  729. {
  730. $modBarCodeProduct =new $module();
  731. }
  732. }
  733. if (is_object($objcanvas) && $objcanvas->displayCanvasExists($action))
  734. {
  735. // -----------------------------------------
  736. // When used with CANVAS
  737. // -----------------------------------------
  738. if (empty($object->error) && $id)
  739. {
  740. $object = new Product($db);
  741. $result=$object->fetch($id);
  742. if ($result <= 0) dol_print_error('',$object->error);
  743. }
  744. $objcanvas->assign_values($action, $object->id, $object->ref); // Set value for templates
  745. $objcanvas->display_canvas($action); // Show template
  746. }
  747. else
  748. {
  749. // -----------------------------------------
  750. // When used in standard mode
  751. // -----------------------------------------
  752. if ($action == 'create' && ($user->rights->produit->creer || $user->rights->service->creer))
  753. {
  754. //WYSIWYG Editor
  755. require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
  756. // Load object modCodeProduct
  757. $module=(! empty($conf->global->PRODUCT_CODEPRODUCT_ADDON)?$conf->global->PRODUCT_CODEPRODUCT_ADDON:'mod_codeproduct_leopard');
  758. if (substr($module, 0, 16) == 'mod_codeproduct_' && substr($module, -3) == 'php')
  759. {
  760. $module = substr($module, 0, dol_strlen($module)-4);
  761. }
  762. $result=dol_include_once('/core/modules/product/'.$module.'.php');
  763. if ($result > 0)
  764. {
  765. $modCodeProduct = new $module();
  766. }
  767. print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
  768. print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
  769. print '<input type="hidden" name="action" value="add">';
  770. print '<input type="hidden" name="type" value="'.$type.'">'."\n";
  771. if (! empty($modCodeProduct->code_auto))
  772. print '<input type="hidden" name="code_auto" value="1">';
  773. if (! empty($modBarCodeProduct->code_auto))
  774. print '<input type="hidden" name="barcode_auto" value="1">';
  775. if ($type==1) $title=$langs->trans("NewService");
  776. else $title=$langs->trans("NewProduct");
  777. $linkback="";
  778. print load_fiche_titre($title,$linkback,'title_products.png');
  779. dol_fiche_head('');
  780. print '<table class="border centpercent">';
  781. print '<tr>';
  782. $tmpcode='';
  783. if (! empty($modCodeProduct->code_auto)) $tmpcode=$modCodeProduct->getNextValue($object,$type);
  784. print '<td class="titlefieldcreate fieldrequired">'.$langs->trans("Ref").'</td><td colspan="3"><input name="ref" class="maxwidth200" maxlength="128" value="'.dol_escape_htmltag(GETPOST('ref')?GETPOST('ref'):$tmpcode).'">';
  785. if ($refalreadyexists)
  786. {
  787. print $langs->trans("RefAlreadyExists");
  788. }
  789. print '</td></tr>';
  790. // Label
  791. print '<tr><td class="fieldrequired">'.$langs->trans("Label").'</td><td colspan="3"><input name="label" class="minwidth300 maxwidth400onsmartphone" maxlength="255" value="'.dol_escape_htmltag(GETPOST('label')).'"></td></tr>';
  792. // On sell
  793. print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Sell").')</td><td colspan="3">';
  794. $statutarray=array('1' => $langs->trans("OnSell"), '0' => $langs->trans("NotOnSell"));
  795. print $form->selectarray('statut',$statutarray,GETPOST('statut'));
  796. print '</td></tr>';
  797. // To buy
  798. print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Buy").')</td><td colspan="3">';
  799. $statutarray=array('1' => $langs->trans("ProductStatusOnBuy"), '0' => $langs->trans("ProductStatusNotOnBuy"));
  800. print $form->selectarray('statut_buy',$statutarray,GETPOST('statut_buy'));
  801. print '</td></tr>';
  802. // Batch number management
  803. if (! empty($conf->productbatch->enabled))
  804. {
  805. print '<tr><td>'.$langs->trans("ManageLotSerial").'</td><td colspan="3">';
  806. $statutarray=array('0' => $langs->trans("ProductStatusNotOnBatch"), '1' => $langs->trans("ProductStatusOnBatch"));
  807. print $form->selectarray('status_batch',$statutarray,GETPOST('status_batch'));
  808. print '</td></tr>';
  809. }
  810. $showbarcode=empty($conf->barcode->enabled)?0:1;
  811. if (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->barcode->lire_advance)) $showbarcode=0;
  812. if ($showbarcode)
  813. {
  814. print '<tr><td>'.$langs->trans('BarcodeType').'</td><td>';
  815. if (isset($_POST['fk_barcode_type']))
  816. {
  817. $fk_barcode_type=GETPOST('fk_barcode_type');
  818. }
  819. else
  820. {
  821. if (empty($fk_barcode_type) && ! empty($conf->global->PRODUIT_DEFAULT_BARCODE_TYPE)) $fk_barcode_type = $conf->global->PRODUIT_DEFAULT_BARCODE_TYPE;
  822. }
  823. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formbarcode.class.php';
  824. $formbarcode = new FormBarCode($db);
  825. print $formbarcode->select_barcode_type($fk_barcode_type, 'fk_barcode_type', 1);
  826. print '</td><td>'.$langs->trans("BarcodeValue").'</td><td>';
  827. $tmpcode=isset($_POST['barcode'])?GETPOST('barcode'):$object->barcode;
  828. if (empty($tmpcode) && ! empty($modBarCodeProduct->code_auto)) $tmpcode=$modBarCodeProduct->getNextValue($object,$type);
  829. print '<input class="maxwidth100" type="text" name="barcode" value="'.dol_escape_htmltag($tmpcode).'">';
  830. print '</td></tr>';
  831. }
  832. // Description (used in invoice, propal...)
  833. print '<tr><td class="tdtop">'.$langs->trans("Description").'</td><td colspan="3">';
  834. $doleditor = new DolEditor('desc', GETPOST('desc'), '', 160, 'dolibarr_details', '', false, true, $conf->global->FCKEDITOR_ENABLE_PRODUCTDESC, ROWS_4, '90%');
  835. $doleditor->Create();
  836. print "</td></tr>";
  837. // Public URL
  838. print '<tr><td>'.$langs->trans("PublicUrl").'</td><td colspan="3">';
  839. print '<input type="text" name="url" class="quatrevingtpercent" value="'.GETPOST('url').'">';
  840. print '</td></tr>';
  841. // Stock min level
  842. if ($type != 1 && ! empty($conf->stock->enabled))
  843. {
  844. print '<tr><td>'.$langs->trans("StockLimit").'</td><td>';
  845. print '<input name="seuil_stock_alerte" class="maxwidth50" value="'.GETPOST('seuil_stock_alerte').'">';
  846. print '</td>';
  847. // Stock desired level
  848. print '<td>'.$langs->trans("DesiredStock").'</td><td>';
  849. print '<input name="desiredstock" class="maxwidth50" value="'.GETPOST('desiredstock').'">';
  850. print '</td></tr>';
  851. }
  852. else
  853. {
  854. print '<input name="seuil_stock_alerte" type="hidden" value="0">';
  855. print '<input name="desiredstock" type="hidden" value="0">';
  856. }
  857. // Nature
  858. if ($type != 1)
  859. {
  860. print '<tr><td>'.$langs->trans("Nature").'</td><td colspan="3">';
  861. $statutarray=array('1' => $langs->trans("Finished"), '0' => $langs->trans("RowMaterial"));
  862. print $form->selectarray('finished',$statutarray,GETPOST('finished'),1);
  863. print '</td></tr>';
  864. }
  865. // Duration
  866. if ($type == 1)
  867. {
  868. print '<tr><td>' . $langs->trans("Duration") . '</td><td colspan="3"><input name="duration_value" size="6" maxlength="5" value="' . $duration_value . '"> &nbsp;';
  869. print '<input name="duration_unit" type="radio" value="h">'.$langs->trans("Hour").'&nbsp;';
  870. print '<input name="duration_unit" type="radio" value="d">'.$langs->trans("Day").'&nbsp;';
  871. print '<input name="duration_unit" type="radio" value="w">'.$langs->trans("Week").'&nbsp;';
  872. print '<input name="duration_unit" type="radio" value="m">'.$langs->trans("Month").'&nbsp;';
  873. print '<input name="duration_unit" type="radio" value="y">'.$langs->trans("Year").'&nbsp;';
  874. print '</td></tr>';
  875. }
  876. if ($type != 1) // Le poids et le volume ne concerne que les produits et pas les services
  877. {
  878. // Weight
  879. print '<tr><td>'.$langs->trans("Weight").'</td><td colspan="3">';
  880. print '<input name="weight" size="4" value="'.GETPOST('weight').'">';
  881. print $formproduct->select_measuring_units("weight_units","weight");
  882. print '</td></tr>';
  883. // Length
  884. if (empty($conf->global->PRODUCT_DISABLE_SIZE))
  885. {
  886. print '<tr><td>'.$langs->trans("Length").' x '.$langs->trans("Width").' x '.$langs->trans("Height").'</td><td colspan="3">';
  887. print '<input name="size" size="4" value="'.GETPOST('size').'"> x ';
  888. print '<input name="sizewidth" size="4" value="'.GETPOST('sizewidth').'"> x ';
  889. print '<input name="sizeheight" size="4" value="'.GETPOST('sizeheight').'">';
  890. print $formproduct->select_measuring_units("size_units","size");
  891. print '</td></tr>';
  892. }
  893. if (empty($conf->global->PRODUCT_DISABLE_SURFACE))
  894. {
  895. // Surface
  896. print '<tr><td>'.$langs->trans("Surface").'</td><td colspan="3">';
  897. print '<input name="surface" size="4" value="'.GETPOST('surface').'">';
  898. print $formproduct->select_measuring_units("surface_units","surface");
  899. print '</td></tr>';
  900. }
  901. // Volume
  902. print '<tr><td>'.$langs->trans("Volume").'</td><td colspan="3">';
  903. print '<input name="volume" size="4" value="'.GETPOST('volume').'">';
  904. print $formproduct->select_measuring_units("volume_units","volume");
  905. print '</td></tr>';
  906. }
  907. // Units
  908. if($conf->global->PRODUCT_USE_UNITS)
  909. {
  910. print '<tr><td>'.$langs->trans('DefaultUnitToShow').'</td>';
  911. print '<td colspan="3">';
  912. print $form->selectUnits('','units');
  913. print '</td></tr>';
  914. }
  915. // Custom code
  916. if (empty($conf->global->PRODUCT_DISABLE_CUSTOM_INFO) && empty($type))
  917. {
  918. print '<tr><td>'.$langs->trans("CustomCode").'</td><td><input name="customcode" class="maxwidth100onsmartphone" value="'.GETPOST('customcode').'"></td>';
  919. // Origin country
  920. print '<td>'.$langs->trans("CountryOrigin").'</td><td>';
  921. print $form->select_country(GETPOST('country_id','int'),'country_id');
  922. if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
  923. print '</td></tr>';
  924. }
  925. // Other attributes
  926. $parameters=array('colspan' => 3);
  927. $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook
  928. if (empty($reshook) && ! empty($extrafields->attribute_label))
  929. {
  930. print $object->showOptionals($extrafields,'edit',$parameters);
  931. }
  932. // Note (private, no output on invoices, propales...)
  933. //if (! empty($conf->global->MAIN_DISABLE_NOTES_TAB)) available in create mode
  934. //{
  935. print '<tr><td class="tdtop">'.$langs->trans("NoteNotVisibleOnBill").'</td><td colspan="3">';
  936. // 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.
  937. $doleditor = new DolEditor('note_private', GETPOST('note_private'), '', 140, 'dolibarr_details', '', false, true, $conf->global->FCKEDITOR_ENABLE_PRODUCTDESC, ROWS_8, '90%');
  938. $doleditor->Create();
  939. print "</td></tr>";
  940. //}
  941. if($conf->categorie->enabled) {
  942. // Categories
  943. print '<tr><td>'.$langs->trans("Categories").'</td><td colspan="3">';
  944. $cate_arbo = $form->select_all_categories(Categorie::TYPE_PRODUCT, '', 'parent', 64, 0, 1);
  945. print $form->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, '', 0, '100%');
  946. print "</td></tr>";
  947. }
  948. print '</table>';
  949. print '<br>';
  950. if (! empty($conf->global->PRODUIT_MULTIPRICES))
  951. {
  952. // We do no show price array on create when multiprices enabled.
  953. // We must set them on prices tab.
  954. }
  955. else
  956. {
  957. print '<table class="border" width="100%">';
  958. // Price
  959. print '<tr><td class="titlefieldcreate">'.$langs->trans("SellingPrice").'</td>';
  960. print '<td><input name="price" class="maxwidth50" value="'.$object->price.'">';
  961. print $form->selectPriceBaseType($object->price_base_type, "price_base_type");
  962. print '</td></tr>';
  963. // Min price
  964. print '<tr><td>'.$langs->trans("MinPrice").'</td>';
  965. print '<td><input name="price_min" class="maxwidth50" value="'.$object->price_min.'">';
  966. print '</td></tr>';
  967. // VAT
  968. print '<tr><td>'.$langs->trans("VATRate").'</td><td>';
  969. print $form->load_tva("tva_tx",-1,$mysoc,'');
  970. print '</td></tr>';
  971. print '</table>';
  972. print '<br>';
  973. }
  974. // Accountancy codes
  975. print '<table class="border" width="100%">';
  976. if (! empty($conf->accounting->enabled))
  977. {
  978. // Accountancy_code_sell
  979. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellCode").'</td>';
  980. print '<td>';
  981. print $formaccounting->select_account(GETPOST('accountancy_code_sell'), 'accountancy_code_sell', 1, null, 1, 1, '');
  982. print '</td></tr>';
  983. // Accountancy_code_buy
  984. print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
  985. print '<td>';
  986. print $formaccounting->select_account(GETPOST('accountancy_code_buy'), 'accountancy_code_buy', 1, null, 1, 1, '');
  987. print '</td></tr>';
  988. }
  989. else // For external software
  990. {
  991. // Accountancy_code_sell
  992. print '<tr><td class="titlefieldcreate">'.$langs->trans("ProductAccountancySellCode").'</td>';
  993. print '<td class="maxwidthonsmartphone"><input class="minwidth100" name="accountancy_code_sell" value="'.$object->accountancy_code_sell.'">';
  994. print '</td></tr>';
  995. // Accountancy_code_buy
  996. print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
  997. print '<td class="maxwidthonsmartphone"><input class="minwidth100" name="accountancy_code_buy" value="'.$object->accountancy_code_buy.'">';
  998. print '</td></tr>';
  999. }
  1000. print '</table>';
  1001. dol_fiche_end();
  1002. print '<div class="center">';
  1003. print '<input type="submit" class="button" value="' . $langs->trans("Create") . '">';
  1004. print ' &nbsp; &nbsp; ';
  1005. print '<input type="button" class="button" value="' . $langs->trans("Cancel") . '" onClick="javascript:history.go(-1)">';
  1006. print '</div>';
  1007. print '</form>';
  1008. }
  1009. /*
  1010. * Product card
  1011. */
  1012. else if ($object->id > 0)
  1013. {
  1014. // Fiche en mode edition
  1015. if ($action == 'edit' && ((($object->type == Product::TYPE_PRODUCT && $user->rights->produit->creer) || ($object->type == Product::TYPE_SERVICE && $user->rights->service->creer))))
  1016. {
  1017. //WYSIWYG Editor
  1018. require_once DOL_DOCUMENT_ROOT.'/core/class/doleditor.class.php';
  1019. $type = $langs->trans('Product');
  1020. if ($object->isService()) $type = $langs->trans('Service');
  1021. //print load_fiche_titre($langs->trans('Modify').' '.$type.' : '.(is_object($object->oldcopy)?$object->oldcopy->ref:$object->ref), "");
  1022. // Main official, simple, and not duplicated code
  1023. print '<form action="'.$_SERVER['PHP_SELF'].'?id='.$object->id.'" method="POST">'."\n";
  1024. print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
  1025. print '<input type="hidden" name="action" value="update">';
  1026. print '<input type="hidden" name="id" value="'.$object->id.'">';
  1027. print '<input type="hidden" name="canvas" value="'.$object->canvas.'">';
  1028. $head=product_prepare_head($object);
  1029. $titre=$langs->trans("CardProduct".$object->type);
  1030. $picto=($object->type== Product::TYPE_SERVICE?'service':'product');
  1031. dol_fiche_head($head, 'card', $titre, 0, $picto);
  1032. print '<table class="border allwidth">';
  1033. // Ref
  1034. print '<tr><td class="titlefield fieldrequired">'.$langs->trans("Ref").'</td><td colspan="3"><input name="ref" class="maxwidth200" maxlength="128" value="'.dol_escape_htmltag($object->ref).'"></td></tr>';
  1035. // Label
  1036. print '<tr><td class="fieldrequired">'.$langs->trans("Label").'</td><td colspan="3"><input name="label" class="minwidth300 maxwidth400onsmartphone" maxlength="255" value="'.dol_escape_htmltag($object->label).'"></td></tr>';
  1037. // Status To sell
  1038. print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Sell").')</td><td colspan="3">';
  1039. print '<select class="flat" name="statut">';
  1040. if ($object->status)
  1041. {
  1042. print '<option value="1" selected>'.$langs->trans("OnSell").'</option>';
  1043. print '<option value="0">'.$langs->trans("NotOnSell").'</option>';
  1044. }
  1045. else
  1046. {
  1047. print '<option value="1">'.$langs->trans("OnSell").'</option>';
  1048. print '<option value="0" selected>'.$langs->trans("NotOnSell").'</option>';
  1049. }
  1050. print '</select>';
  1051. print '</td></tr>';
  1052. // Status To Buy
  1053. print '<tr><td class="fieldrequired">'.$langs->trans("Status").' ('.$langs->trans("Buy").')</td><td colspan="3">';
  1054. print '<select class="flat" name="statut_buy">';
  1055. if ($object->status_buy)
  1056. {
  1057. print '<option value="1" selected>'.$langs->trans("ProductStatusOnBuy").'</option>';
  1058. print '<option value="0">'.$langs->trans("ProductStatusNotOnBuy").'</option>';
  1059. }
  1060. else
  1061. {
  1062. print '<option value="1">'.$langs->trans("ProductStatusOnBuy").'</option>';
  1063. print '<option value="0" selected>'.$langs->trans("ProductStatusNotOnBuy").'</option>';
  1064. }
  1065. print '</select>';
  1066. print '</td></tr>';
  1067. // Batch number managment
  1068. if ($conf->productbatch->enabled) {
  1069. print '<tr><td>'.$langs->trans("ManageLotSerial").'</td><td colspan="3">';
  1070. $statutarray=array('0' => $langs->trans("ProductStatusNotOnBatch"), '1' => $langs->trans("ProductStatusOnBatch"));
  1071. print $form->selectarray('status_batch',$statutarray,$object->status_batch);
  1072. print '</td></tr>';
  1073. }
  1074. // Barcode
  1075. $showbarcode=empty($conf->barcode->enabled)?0:1;
  1076. if (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->barcode->lire_advance)) $showbarcode=0;
  1077. if ($showbarcode)
  1078. {
  1079. print '<tr><td>'.$langs->trans('BarcodeType').'</td><td>';
  1080. if (isset($_POST['fk_barcode_type']))
  1081. {
  1082. $fk_barcode_type=GETPOST('fk_barcode_type');
  1083. }
  1084. else
  1085. {
  1086. $fk_barcode_type=$object->barcode_type;
  1087. if (empty($fk_barcode_type) && ! empty($conf->global->PRODUIT_DEFAULT_BARCODE_TYPE)) $fk_barcode_type = $conf->global->PRODUIT_DEFAULT_BARCODE_TYPE;
  1088. }
  1089. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formbarcode.class.php';
  1090. $formbarcode = new FormBarCode($db);
  1091. print $formbarcode->select_barcode_type($fk_barcode_type, 'fk_barcode_type', 1);
  1092. print '</td><td>'.$langs->trans("BarcodeValue").'</td><td>';
  1093. $tmpcode=isset($_POST['barcode'])?GETPOST('barcode'):$object->barcode;
  1094. if (empty($tmpcode) && ! empty($modBarCodeProduct->code_auto)) $tmpcode=$modBarCodeProduct->getNextValue($object,$type);
  1095. print '<input size="40" class="maxwidthonsmartphone" type="text" name="barcode" value="'.dol_escape_htmltag($tmpcode).'">';
  1096. print '</td></tr>';
  1097. }
  1098. // Description (used in invoice, propal...)
  1099. print '<tr><td class="tdtop">'.$langs->trans("Description").'</td><td colspan="3">';
  1100. // 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.
  1101. $doleditor = new DolEditor('desc', $object->description, '', 160, 'dolibarr_details', '', false, true, $conf->global->FCKEDITOR_ENABLE_PRODUCTDESC, ROWS_4, '90%');
  1102. $doleditor->Create();
  1103. print "</td></tr>";
  1104. print "\n";
  1105. // Public Url
  1106. print '<tr><td>'.$langs->trans("PublicUrl").'</td><td colspan="3">';
  1107. print '<input type="text" name="url" class="quatrevingtpercent" value="'.$object->url.'">';
  1108. print '</td></tr>';
  1109. // Stock
  1110. /*
  1111. if ($object->isProduct() && ! empty($conf->stock->enabled))
  1112. {
  1113. print "<tr>".'<td>'.$langs->trans("StockLimit").'</td><td>';
  1114. print '<input name="seuil_stock_alerte" size="4" value="'.$object->seuil_stock_alerte.'">';
  1115. print '</td>';
  1116. print '<td>'.$langs->trans("DesiredStock").'</td><td>';
  1117. print '<input name="desiredstock" size="4" value="'.$object->desiredstock.'">';
  1118. print '</td></tr>';
  1119. }
  1120. else
  1121. {
  1122. print '<input name="seuil_stock_alerte" type="hidden" value="'.$object->seuil_stock_alerte.'">';
  1123. print '<input name="desiredstock" type="hidden" value="'.$object->desiredstock.'">';
  1124. }*/
  1125. // Nature
  1126. if($object->type!= Product::TYPE_SERVICE)
  1127. {
  1128. print '<tr><td>'.$langs->trans("Nature").'</td><td colspan="3">';
  1129. $statutarray=array('-1'=>'&nbsp;', '1' => $langs->trans("Finished"), '0' => $langs->trans("RowMaterial"));
  1130. print $form->selectarray('finished',$statutarray,$object->finished);
  1131. print '</td></tr>';
  1132. }
  1133. if ($object->isService())
  1134. {
  1135. // Duration
  1136. print '<tr><td>'.$langs->trans("Duration").'</td><td colspan="3"><input name="duration_value" size="3" maxlength="5" value="'.$object->duration_value.'">';
  1137. print '&nbsp; ';
  1138. print '<input name="duration_unit" type="radio" value="h"'.($object->duration_unit=='h'?' checked':'').'>'.$langs->trans("Hour");
  1139. print '&nbsp; ';
  1140. print '<input name="duration_unit" type="radio" value="d"'.($object->duration_unit=='d'?' checked':'').'>'.$langs->trans("Day");
  1141. print '&nbsp; ';
  1142. print '<input name="duration_unit" type="radio" value="w"'.($object->duration_unit=='w'?' checked':'').'>'.$langs->trans("Week");
  1143. print '&nbsp; ';
  1144. print '<input name="duration_unit" type="radio" value="m"'.($object->duration_unit=='m'?' checked':'').'>'.$langs->trans("Month");
  1145. print '&nbsp; ';
  1146. print '<input name="duration_unit" type="radio" value="y"'.($object->duration_unit=='y'?' checked':'').'>'.$langs->trans("Year");
  1147. print '</td></tr>';
  1148. }
  1149. else
  1150. {
  1151. // Weight
  1152. print '<tr><td>'.$langs->trans("Weight").'</td><td colspan="3">';
  1153. print '<input name="weight" size="5" value="'.$object->weight.'"> ';
  1154. print $formproduct->select_measuring_units("weight_units", "weight", $object->weight_units);
  1155. print '</td></tr>';
  1156. if (empty($conf->global->PRODUCT_DISABLE_SIZE))
  1157. {
  1158. // Length
  1159. print '<tr><td>'.$langs->trans("Length").' x '.$langs->trans("Width").' x '.$langs->trans("Height").'</td><td colspan="3">';
  1160. print '<input name="size" size="5" value="'.$object->length.'">x';
  1161. print '<input name="sizewidth" size="5" value="'.$object->width.'">x';
  1162. print '<input name="sizeheight" size="5" value="'.$object->height.'"> ';
  1163. print $formproduct->select_measuring_units("size_units", "size", $object->length_units);
  1164. print '</td></tr>';
  1165. }
  1166. if (empty($conf->global->PRODUCT_DISABLE_SURFACE))
  1167. {
  1168. // Surface
  1169. print '<tr><td>'.$langs->trans("Surface").'</td><td colspan="3">';
  1170. print '<input name="surface" size="5" value="'.$object->surface.'"> ';
  1171. print $formproduct->select_measuring_units("surface_units", "surface", $object->surface_units);
  1172. print '</td></tr>';
  1173. }
  1174. if (empty($conf->global->PRODUCT_DISABLE_VOLUME))
  1175. {
  1176. // Volume
  1177. print '<tr><td>'.$langs->trans("Volume").'</td><td colspan="3">';
  1178. print '<input name="volume" size="5" value="'.$object->volume.'"> ';
  1179. print $formproduct->select_measuring_units("volume_units", "volume", $object->volume_units);
  1180. print '</td></tr>';
  1181. }
  1182. }
  1183. // Units
  1184. if($conf->global->PRODUCT_USE_UNITS)
  1185. {
  1186. print '<tr><td>'.$langs->trans('DefaultUnitToShow').'</td>';
  1187. print '<td colspan="3">';
  1188. print $form->selectUnits($object->fk_unit, 'units');
  1189. print '</td></tr>';
  1190. }
  1191. // Custom code
  1192. if (! $object->isService() && empty($conf->global->PRODUCT_DISABLE_CUSTOM_INFO))
  1193. {
  1194. print '<tr><td>'.$langs->trans("CustomCode").'</td><td><input name="customcode" class="maxwidth100onsmartphone" value="'.$object->customcode.'"></td>';
  1195. // Origin country
  1196. print '<td>'.$langs->trans("CountryOrigin").'</td><td>';
  1197. print $form->select_country($object->country_id, 'country_id', '', 0, 'minwidth100 maxwidthonsmartphone');
  1198. if ($user->admin) print info_admin($langs->trans("YouCanChangeValuesForThisListFromDictionarySetup"),1);
  1199. print '</td></tr>';
  1200. }
  1201. // Other attributes
  1202. $parameters=array('colspan' => ' colspan="2"');
  1203. $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook
  1204. if (empty($reshook) && ! empty($extrafields->attribute_label))
  1205. {
  1206. print $object->showOptionals($extrafields,'edit');
  1207. }
  1208. // Tags-Categories
  1209. if ($conf->categorie->enabled)
  1210. {
  1211. print '<tr><td class="tdtop">'.$langs->trans("Categories").'</td><td colspan="3">';
  1212. $cate_arbo = $form->select_all_categories(Categorie::TYPE_PRODUCT, '', 'parent', 64, 0, 1);
  1213. $c = new Categorie($db);
  1214. $cats = $c->containing($object->id,Categorie::TYPE_PRODUCT);
  1215. foreach($cats as $cat) {
  1216. $arrayselected[] = $cat->id;
  1217. }
  1218. print $form->multiselectarray('categories', $cate_arbo, $arrayselected, '', 0, '', 0, '100%');
  1219. print "</td></tr>";
  1220. }
  1221. // Note private
  1222. if (! empty($conf->global->MAIN_DISABLE_NOTES_TAB))
  1223. {
  1224. print '<tr><td class="tdtop">'.$langs->trans("NoteNotVisibleOnBill").'</td><td colspan="3">';
  1225. $doleditor = new DolEditor('note_private', $object->note_private, '', 140, 'dolibarr_notes', '', false, true, $conf->global->FCKEDITOR_ENABLE_PRODUCTDESC, ROWS_4, '90%');
  1226. $doleditor->Create();
  1227. print "</td></tr>";
  1228. }
  1229. print '</table>';
  1230. print '<br>';
  1231. print '<table class="border" width="100%">';
  1232. if (! empty($conf->accounting->enabled))
  1233. {
  1234. // Accountancy_code_sell
  1235. print '<tr><td class="titlefield">'.$langs->trans("ProductAccountancySellCode").'</td>';
  1236. print '<td>';
  1237. print $formaccounting->select_account($object->accountancy_code_sell, 'accountancy_code_sell', 1, '', 1, 1);
  1238. print '</td></tr>';
  1239. // Accountancy_code_buy
  1240. print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
  1241. print '<td>';
  1242. print $formaccounting->select_account($object->accountancy_code_buy, 'accountancy_code_buy', 1, '', 1, 1);
  1243. print '</td></tr>';
  1244. }
  1245. else // For external software
  1246. {
  1247. // Accountancy_code_sell
  1248. print '<tr><td class="titlefield">'.$langs->trans("ProductAccountancySellCode").'</td>';
  1249. print '<td><input name="accountancy_code_sell" class="maxwidth200" value="'.$object->accountancy_code_sell.'">';
  1250. print '</td></tr>';
  1251. // Accountancy_code_buy
  1252. print '<tr><td>'.$langs->trans("ProductAccountancyBuyCode").'</td>';
  1253. print '<td><input name="accountancy_code_buy" class="maxwidth200" value="'.$object->accountancy_code_buy.'">';
  1254. print '</td></tr>';
  1255. }
  1256. print '</table>';
  1257. dol_fiche_end();
  1258. print '<div class="center">';
  1259. print '<input type="submit" class="button" value="'.$langs->trans("Save").'">';
  1260. print '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
  1261. print '<input type="submit" class="button" name="cancel" value="'.$langs->trans("Cancel").'">';
  1262. print '</div>';
  1263. print '</form>';
  1264. }
  1265. // Fiche en mode visu
  1266. else
  1267. {
  1268. $showbarcode=empty($conf->barcode->enabled)?0:1;
  1269. if (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && empty($user->rights->barcode->lire_advance)) $showbarcode=0;
  1270. $head=product_prepare_head($object);
  1271. $titre=$langs->trans("CardProduct".$object->type);
  1272. $picto=($object->type== Product::TYPE_SERVICE?'service':'product');
  1273. dol_fiche_head($head, 'card', $titre, -1, $picto);
  1274. $linkback = '<a href="'.DOL_URL_ROOT.'/product/list.php?type='.$object->type.'">'.$langs->trans("BackToList").'</a>';
  1275. $object->next_prev_filter=" fk_product_type = ".$object->type;
  1276. dol_banner_tab($object, 'ref', $linkback, ($user->societe_id?0:1), 'ref');
  1277. print '<div class="fichecenter">';
  1278. print '<div class="fichehalfleft">';
  1279. print '<div class="underbanner clearboth"></div>';
  1280. print '<table class="border tableforfield" width="100%">';
  1281. // Type
  1282. if (! empty($conf->produit->enabled) && ! empty($conf->service->enabled))
  1283. {
  1284. // TODO change for compatibility with edit in place
  1285. $typeformat='select;0:'.$langs->trans("Product").',1:'.$langs->trans("Service");
  1286. print '<tr><td class="titlefield">'.$form->editfieldkey("Type",'fk_product_type',$object->type,$object,$user->rights->produit->creer||$user->rights->service->creer,$typeformat).'</td><td colspan="2">';
  1287. print $form->editfieldval("Type",'fk_product_type',$object->type,$object,$user->rights->produit->creer||$user->rights->service->creer,$typeformat);
  1288. print '</td></tr>';
  1289. }
  1290. if ($showbarcode)
  1291. {
  1292. // Barcode type
  1293. print '<tr><td class="nowrap">';
  1294. print '<table width="100%" class="nobordernopadding"><tr><td class="nowrap">';
  1295. print $langs->trans("BarcodeType");
  1296. print '</td>';
  1297. if (($action != 'editbarcodetype') && ! empty($user->rights->produit->creer) && $createbarcode) print '<td align="right"><a href="'.$_SERVER["PHP_SELF"].'?action=editbarcodetype&amp;id='.$object->id.'">'.img_edit($langs->trans('Edit'),1).'</a></td>';
  1298. print '</tr></table>';
  1299. print '</td><td colspan="2">';
  1300. if ($action == 'editbarcodetype' || $action == 'editbarcode')
  1301. {
  1302. require_once DOL_DOCUMENT_ROOT.'/core/class/html.formbarcode.class.php';
  1303. $formbarcode = new FormBarCode($db);
  1304. }
  1305. if ($action == 'editbarcodetype')
  1306. {
  1307. $formbarcode->form_barcode_type($_SERVER['PHP_SELF'].'?id='.$object->id,$object->barcode_type,'fk_barcode_type');
  1308. }
  1309. else
  1310. {
  1311. $object->fetch_barcode();
  1312. print $object->barcode_type_label?$object->barcode_type_label:($object->barcode?'<div class="warning">'.$langs->trans("SetDefaultBarcodeType").'<div>':'');
  1313. }
  1314. print '</td></tr>'."\n";
  1315. // Barcode value
  1316. print '<tr><td class="nowrap">';
  1317. print '<table width="100%" class="nobordernopadding"><tr><td class="nowrap">';
  1318. print $langs->trans("BarcodeValue");
  1319. print '</td>';
  1320. if (($action != 'editbarcode') && ! empty($user->rights->produit->creer) && $createbarcode) print '<td align="right"><a href="'.$_SERVER["PHP_SELF"].'?action=editbarcode&amp;id='.$object->id.'">'.img_edit($langs->trans('Edit'),1).'</a></td>';
  1321. print '</tr></table>';
  1322. print '</td><td colspan="2">';
  1323. if ($action == 'editbarcode')
  1324. {
  1325. $tmpcode=isset($_POST['barcode'])?GETPOST('barcode'):$object->barcode;
  1326. if (empty($tmpcode) && ! empty($modBarCodeProduct->code_auto)) $tmpcode=$modBarCodeProduct->getNextValue($object,$type);
  1327. print '<form method="post" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">';
  1328. print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
  1329. print '<input type="hidden" name="action" value="setbarcode">';
  1330. print '<input type="hidden" name="barcode_type_code" value="'.$object->barcode_type_code.'">';
  1331. print '<input size="40" class="maxwidthonsmartphone" type="text" name="barcode" value="'.$tmpcode.'">';
  1332. print '&nbsp;<input type="submit" class="button" value="'.$langs->trans("Modify").'">';
  1333. print '</form>';
  1334. }
  1335. else
  1336. {
  1337. print $object->barcode;
  1338. }
  1339. print '</td></tr>'."\n";
  1340. }
  1341. // Accountancy sell code
  1342. print '<tr><td class="nowrap">';
  1343. print $langs->trans("ProductAccountancySellCode");
  1344. print '</td><td colspan="2">';
  1345. if (! empty($conf->accounting->enabled))
  1346. {
  1347. $accountingaccount = new AccountingAccount($db);
  1348. $accountingaccount->fetch('',$object->accountancy_code_sell);
  1349. print $accountingaccount->getNomUrl(0,1,1,'',1);
  1350. } else {
  1351. print $object->accountancy_code_sell;
  1352. }
  1353. print '</td></tr>';
  1354. // Accountancy buy code
  1355. print '<tr><td class="nowrap">';
  1356. print $langs->trans("ProductAccountancyBuyCode");
  1357. print '</td><td colspan="2">';
  1358. if (! empty($conf->accounting->enabled))
  1359. {
  1360. $accountingaccount2 = new AccountingAccount($db);
  1361. $accountingaccount2->fetch('',$object->accountancy_code_buy);
  1362. print $accountingaccount2->getNomUrl(0,1,1,'',1);
  1363. } else {
  1364. print $object->accountancy_code_buy;
  1365. }
  1366. print '</td></tr>';
  1367. // Status (to sell)
  1368. /*
  1369. print '<tr><td>'.$langs->trans("Status").' ('.$langs->trans("Sell").')</td><td colspan="2">';
  1370. if (! empty($conf->use_javascript_ajax) && $user->rights->produit->creer && ! empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) {
  1371. print ajax_object_onoff($object, 'status', 'tosell', 'ProductStatusOnSell', 'ProductStatusNotOnSell');
  1372. } else {
  1373. print $object->getLibStatut(2,0);
  1374. }
  1375. print '</td></tr>';
  1376. // Status (to buy)
  1377. print '<tr><td>'.$langs->trans("Status").' ('.$langs->trans("Buy").')</td><td colspan="2">';
  1378. if (! empty($conf->use_javascript_ajax) && $user->rights->produit->creer && ! empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) {
  1379. print ajax_object_onoff($object, 'status_buy', 'tobuy', 'ProductStatusOnBuy', 'ProductStatusNotOnBuy');
  1380. } else {
  1381. print $object->getLibStatut(2,1);
  1382. }
  1383. print '</td></tr>';
  1384. */
  1385. // Batch number management (to batch)
  1386. if (! empty($conf->productbatch->enabled)) {
  1387. print '<tr><td>'.$langs->trans("ManageLotSerial").'</td><td colspan="2">';
  1388. if (! empty($conf->use_javascript_ajax) && $user->rights->produit->creer && ! empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) {
  1389. print ajax_object_onoff($object, 'status_batch', 'tobatch', 'ProductStatusOnBatch', 'ProductStatusNotOnBatch');
  1390. } else {
  1391. print $object->getLibStatut(0,2);
  1392. }
  1393. print '</td></tr>';
  1394. }
  1395. // Description
  1396. print '<tr><td class="tdtop">'.$langs->trans("Description").'</td><td colspan="2">'.(dol_textishtml($object->description)?$object->description:dol_nl2br($object->description,1,true)).'</td></tr>';
  1397. // Public URL
  1398. print '<tr><td>'.$langs->trans("PublicUrl").'</td><td colspan="2">';
  1399. print dol_print_url($object->url);
  1400. print '</td></tr>';
  1401. //Parent product.
  1402. if (!empty($conf->variants->enabled) && $object->isProduct()) {
  1403. $combination = new ProductCombination($db);
  1404. if ($combination->fetchByFkProductChild($object->id) > 0) {
  1405. $prodstatic = new Product($db);
  1406. $prodstatic->fetch($combination->fk_product_parent);
  1407. // Parent product
  1408. print '<tr><td>'.$langs->trans("ParentProduct").'</td><td colspan="2">';
  1409. print $prodstatic->getNomUrl(1);
  1410. print '</td></tr>';
  1411. }
  1412. }
  1413. print '</table>';
  1414. print '</div>';
  1415. print '<div class="fichehalfright"><div class="ficheaddleft">';
  1416. print '<div class="underbanner clearboth"></div>';
  1417. print '<table class="border tableforfield" width="100%">';
  1418. // Nature
  1419. if($object->type!= Product::TYPE_SERVICE)
  1420. {
  1421. print '<tr><td class="titlefield">'.$langs->trans("Nature").'</td><td colspan="2">';
  1422. print $object->getLibFinished();
  1423. print '</td></tr>';
  1424. }
  1425. if ($object->isService())
  1426. {
  1427. // Duration
  1428. print '<tr><td class="titlefield">'.$langs->trans("Duration").'</td><td colspan="2">'.$object->duration_value.'&nbsp;';
  1429. if ($object->duration_value > 1)
  1430. {
  1431. $dur=array("h"=>$langs->trans("Hours"),"d"=>$langs->trans("Days"),"w"=>$langs->trans("Weeks"),"m"=>$langs->trans("Months"),"y"=>$langs->trans("Years"));
  1432. }
  1433. else if ($object->duration_value > 0)
  1434. {
  1435. $dur=array("h"=>$langs->trans("Hour"),"d"=>$langs->trans("Day"),"w"=>$langs->trans("Week"),"m"=>$langs->trans("Month"),"y"=>$langs->trans("Year"));
  1436. }
  1437. print (! empty($object->duration_unit) && isset($dur[$object->duration_unit]) ? $langs->trans($dur[$object->duration_unit]) : '')."&nbsp;";
  1438. print '</td></tr>';
  1439. }
  1440. else
  1441. {
  1442. // Weight
  1443. print '<tr><td class="titlefield">'.$langs->trans("Weight").'</td><td colspan="2">';
  1444. if ($object->weight != '')
  1445. {
  1446. print $object->weight." ".measuring_units_string($object->weight_units,"weight");
  1447. }
  1448. else
  1449. {
  1450. print '&nbsp;';
  1451. }
  1452. print "</td></tr>\n";
  1453. if (empty($conf->global->PRODUCT_DISABLE_SIZE))
  1454. {
  1455. // Length
  1456. print '<tr><td>'.$langs->trans("Length").' x '.$langs->trans("Width").' x '.$langs->trans("Height").'</td><td colspan="2">';
  1457. if ($object->length != '' || $object->width != '' || $object->height != '')
  1458. {
  1459. print $object->length;
  1460. if ($object->width) print " x ".$object->width;
  1461. if ($object->height) print " x ".$object->height;
  1462. print ' '.measuring_units_string($object->length_units,"size");
  1463. }
  1464. else
  1465. {
  1466. print '&nbsp;';
  1467. }
  1468. print "</td></tr>\n";
  1469. }
  1470. if (empty($conf->global->PRODUCT_DISABLE_SURFACE))
  1471. {
  1472. // Surface
  1473. print '<tr><td>'.$langs->trans("Surface").'</td><td colspan="2">';
  1474. if ($object->surface != '')
  1475. {
  1476. print $object->surface." ".measuring_units_string($object->surface_units,"surface");
  1477. }
  1478. else
  1479. {
  1480. print '&nbsp;';
  1481. }
  1482. print "</td></tr>\n";
  1483. }
  1484. if (empty($conf->global->PRODUCT_DISABLE_VOLUME))
  1485. {
  1486. // Volume
  1487. print '<tr><td>'.$langs->trans("Volume").'</td><td colspan="2">';
  1488. if ($object->volume != '')
  1489. {
  1490. print $object->volume." ".measuring_units_string($object->volume_units,"volume");
  1491. }
  1492. else
  1493. {
  1494. print '&nbsp;';
  1495. }
  1496. print "</td></tr>\n";
  1497. }
  1498. }
  1499. // Unit
  1500. if (! empty($conf->global->PRODUCT_USE_UNITS))
  1501. {
  1502. $unit = $object->getLabelOfUnit();
  1503. print '<tr><td>'.$langs->trans('DefaultUnitToShow').'</td><td>';
  1504. if ($unit !== '') {
  1505. print $langs->trans($unit);
  1506. }
  1507. print '</td></tr>';
  1508. }
  1509. // Custom code
  1510. if (empty($conf->global->PRODUCT_DISABLE_CUSTOM_INFO))
  1511. {
  1512. print '<tr><td>'.$langs->trans("CustomCode").'</td><td colspan="2">'.$object->customcode.'</td>';
  1513. // Origin country code
  1514. print '<tr><td>'.$langs->trans("CountryOrigin").'</td><td colspan="2">'.getCountry($object->country_id,0,$db).'</td>';
  1515. }
  1516. // Other attributes
  1517. $parameters=array('colspan' => ' colspan="'.(2+(($showphoto||$showbarcode)?1:0)).'"');
  1518. $reshook=$hookmanager->executeHooks('formObjectOptions',$parameters,$object,$action); // Note that $action and $object may have been modified by hook
  1519. if (empty($reshook) && ! empty($extrafields->attribute_label))
  1520. {
  1521. print $object->showOptionals($extrafields);
  1522. }
  1523. // Categories
  1524. if($conf->categorie->enabled) {
  1525. print '<tr><td valign="middle">'.$langs->trans("Categories").'</td><td colspan="3">';
  1526. print $form->showCategories($object->id,'product',1);
  1527. print "</td></tr>";
  1528. }
  1529. // Note private
  1530. if (! empty($conf->global->MAIN_DISABLE_NOTES_TAB))
  1531. {
  1532. print '<!-- show Note --> '."\n";
  1533. print '<tr><td class="tdtop">'.$langs->trans("NotePrivate").'</td><td colspan="'.(2+(($showphoto||$showbarcode)?1:0)).'">'.(dol_textishtml($object->note_private)?$object->note_private:dol_nl2br($object->note_private,1,true)).'</td></tr>'."\n";
  1534. print '<!-- End show Note --> '."\n";
  1535. }
  1536. print "</table>\n";
  1537. print '</div>';
  1538. print '</div></div>';
  1539. print '<div style="clear:both"></div>';
  1540. dol_fiche_end();
  1541. }
  1542. }
  1543. else if ($action != 'create')
  1544. {
  1545. exit;
  1546. }
  1547. }
  1548. // Load object modCodeProduct
  1549. $module=(! empty($conf->global->PRODUCT_CODEPRODUCT_ADDON)?$conf->global->PRODUCT_CODEPRODUCT_ADDON:'mod_codeproduct_leopard');
  1550. if (substr($module, 0, 16) == 'mod_codeproduct_' && substr($module, -3) == 'php')
  1551. {
  1552. $module = substr($module, 0, dol_strlen($module)-4);
  1553. }
  1554. $result=dol_include_once('/core/modules/product/'.$module.'.php');
  1555. if ($result > 0)
  1556. {
  1557. $modCodeProduct = new $module();
  1558. }
  1559. $tmpcode='';
  1560. if (! empty($modCodeProduct->code_auto)) $tmpcode=$modCodeProduct->getNextValue($object,$object->type);
  1561. // Define confirmation messages
  1562. $formquestionclone=array(
  1563. 'text' => $langs->trans("ConfirmClone"),
  1564. array('type' => 'text', 'name' => 'clone_ref','label' => $langs->trans("NewRefForClone"), 'value' => empty($tmpcode) ? $langs->trans("CopyOf").' '.$object->ref : $tmpcode, 'size'=>24),
  1565. array('type' => 'checkbox', 'name' => 'clone_content','label' => $langs->trans("CloneContentProduct"), 'value' => 1),
  1566. array('type' => 'checkbox', 'name' => 'clone_prices', 'label' => $langs->trans("ClonePricesProduct").' ('.$langs->trans("FeatureNotYetAvailable").')', 'value' => 0, 'disabled' => true),
  1567. );
  1568. if (! empty($conf->global->PRODUIT_SOUSPRODUITS))
  1569. {
  1570. $formquestionclone[]=array('type' => 'checkbox', 'name' => 'clone_composition', 'label' => $langs->trans('CloneCompositionProduct'), 'value' => 1);
  1571. }
  1572. // Confirm delete product
  1573. if (($action == 'delete' && (empty($conf->use_javascript_ajax) || ! empty($conf->dol_use_jmobile))) // Output when action = clone if jmobile or no js
  1574. || (! empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile))) // Always output when not jmobile nor js
  1575. {
  1576. print $form->formconfirm("card.php?id=".$object->id,$langs->trans("DeleteProduct"),$langs->trans("ConfirmDeleteProduct"),"confirm_delete",'',0,"action-delete");
  1577. }
  1578. // Clone confirmation
  1579. if (($action == 'clone' && (empty($conf->use_javascript_ajax) || ! empty($conf->dol_use_jmobile))) // Output when action = clone if jmobile or no js
  1580. || (! empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile))) // Always output when not jmobile nor js
  1581. {
  1582. print $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id,$langs->trans('CloneProduct'),$langs->trans('ConfirmCloneProduct',$object->ref),'confirm_clone',$formquestionclone,'yes','action-clone',250,600);
  1583. }
  1584. /* ************************************************************************** */
  1585. /* */
  1586. /* Barre d'action */
  1587. /* */
  1588. /* ************************************************************************** */
  1589. if ($action != 'create' && $action != 'edit')
  1590. {
  1591. print "\n".'<div class="tabsAction">'."\n";
  1592. $parameters=array();
  1593. $reshook=$hookmanager->executeHooks('addMoreActionsButtons',$parameters,$object,$action); // Note that $action and $object may have been modified by hook
  1594. if (empty($reshook))
  1595. {
  1596. if (($object->type == Product::TYPE_PRODUCT && $user->rights->produit->creer ) ||
  1597. ($object->type == Product::TYPE_SERVICE && $user->rights->service->creer))
  1598. {
  1599. if (! isset($object->no_button_edit) || $object->no_button_edit <> 1) print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=edit&amp;id='.$object->id.'">'.$langs->trans("Modify").'</a></div>';
  1600. if (! isset($object->no_button_copy) || $object->no_button_copy <> 1)
  1601. {
  1602. if (! empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile))
  1603. {
  1604. print '<div class="inline-block divButAction"><span id="action-clone" class="butAction">'.$langs->trans('ToClone').'</span></div>'."\n";
  1605. }
  1606. else
  1607. {
  1608. print '<div class="inline-block divButAction"><a class="butAction" href="'.$_SERVER["PHP_SELF"].'?action=clone&amp;id='.$object->id.'">'.$langs->trans("ToClone").'</a></div>';
  1609. }
  1610. }
  1611. }
  1612. $object_is_used = $object->isObjectUsed($object->id);
  1613. if (($object->type == Product::TYPE_PRODUCT && $user->rights->produit->supprimer)
  1614. || ($object->type == Product::TYPE_SERVICE && $user->rights->service->supprimer))
  1615. {
  1616. if (empty($object_is_used) && (! isset($object->no_button_delete) || $object->no_button_delete <> 1))
  1617. {
  1618. if (! empty($conf->use_javascript_ajax) && empty($conf->dol_use_jmobile))
  1619. {
  1620. print '<div class="inline-block divButAction"><span id="action-delete" class="butActionDelete">'.$langs->trans('Delete').'</span></div>'."\n";
  1621. }
  1622. else
  1623. {
  1624. print '<div class="inline-block divButAction"><a class="butActionDelete" href="'.$_SERVER["PHP_SELF"].'?action=delete&amp;id='.$object->id.'">'.$langs->trans("Delete").'</a></div>';
  1625. }
  1626. }
  1627. else
  1628. {
  1629. print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="'.$langs->trans("ProductIsUsed").'">'.$langs->trans("Delete").'</a></div>';
  1630. }
  1631. }
  1632. else
  1633. {
  1634. print '<div class="inline-block divButAction"><a class="butActionRefused" href="#" title="'.$langs->trans("NotEnoughPermissions").'">'.$langs->trans("Delete").'</a></div>';
  1635. }
  1636. }
  1637. print "\n</div>\n";
  1638. }
  1639. /*
  1640. * All the "Add to" areas
  1641. */
  1642. if (! empty($conf->global->PRODUCT_ADD_FORM_ADD_TO) && $object->id && ($action == '' || $action == 'view') && $object->status)
  1643. {
  1644. //Variable used to check if any text is going to be printed
  1645. $html = '';
  1646. //print '<div class="fichecenter"><div class="fichehalfleft">';
  1647. // Propals
  1648. if (! empty($conf->propal->enabled) && $user->rights->propale->creer)
  1649. {
  1650. $propal = new Propal($db);
  1651. $langs->load("propal");
  1652. $otherprop = $propal->liste_array(2,1,0);
  1653. if (is_array($otherprop) && count($otherprop))
  1654. {
  1655. $html .= '<tr><td style="width: 200px;">';
  1656. $html .= $langs->trans("AddToDraftProposals").'</td><td>';
  1657. $html .= $form->selectarray("propalid", $otherprop, 0, 1);
  1658. $html .= '</td></tr>';
  1659. }
  1660. else
  1661. {
  1662. $html .= '<tr><td style="width: 200px;">';
  1663. $html .= $langs->trans("AddToDraftProposals").'</td><td>';
  1664. $html .= $langs->trans("NoDraftProposals");
  1665. $html .= '</td></tr>';
  1666. }
  1667. }
  1668. // Commande
  1669. if (! empty($conf->commande->enabled) && $user->rights->commande->creer)
  1670. {
  1671. $commande = new Commande($db);
  1672. $langs->load("orders");
  1673. $othercom = $commande->liste_array(2, 1, null);
  1674. if (is_array($othercom) && count($othercom))
  1675. {
  1676. $html .= '<tr><td style="width: 200px;">';
  1677. $html .= $langs->trans("AddToDraftOrders").'</td><td>';
  1678. $html .= $form->selectarray("commandeid", $othercom, 0, 1);
  1679. $html .= '</td></tr>';
  1680. }
  1681. else
  1682. {
  1683. $html .= '<tr><td style="width: 200px;">';
  1684. $html .= $langs->trans("AddToDraftOrders").'</td><td>';
  1685. $html .= $langs->trans("NoDraftOrders");
  1686. $html .= '</td></tr>';
  1687. }
  1688. }
  1689. // Factures
  1690. if (! empty($conf->facture->enabled) && $user->rights->facture->creer)
  1691. {
  1692. $invoice = new Facture($db);
  1693. $langs->load("bills");
  1694. $otherinvoice = $invoice->liste_array(2, 1, null);
  1695. if (is_array($otherinvoice) && count($otherinvoice))
  1696. {
  1697. $html .= '<tr><td style="width: 200px;">';
  1698. $html .= $langs->trans("AddToDraftInvoices").'</td><td>';
  1699. $html .= $form->selectarray("factureid", $otherinvoice, 0, 1);
  1700. $html .= '</td></tr>';
  1701. }
  1702. else
  1703. {
  1704. $html .= '<tr><td style="width: 200px;">';
  1705. $html .= $langs->trans("AddToDraftInvoices").'</td><td>';
  1706. $html .= $langs->trans("NoDraftInvoices");
  1707. $html .= '</td></tr>';
  1708. }
  1709. }
  1710. //If any text is going to be printed, then we show the table
  1711. if (!empty($html))
  1712. {
  1713. print '<form method="POST" action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'">';
  1714. print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
  1715. print '<input type="hidden" name="action" value="addin">';
  1716. print load_fiche_titre($langs->trans("AddToDraft"),'','');
  1717. dol_fiche_head('');
  1718. $html .= '<tr><td class="nowrap">'.$langs->trans("Quantity").' ';
  1719. $html .= '<input type="text" class="flat" name="qty" size="1" value="1"></td>';
  1720. $html .= '<td class="nowrap">'.$langs->trans("ReductionShort").'(%) ';
  1721. $html .= '<input type="text" class="flat" name="remise_percent" size="1" value="0">';
  1722. $html .= '</td></tr>';
  1723. print '<table width="100%" class="border">';
  1724. print $html;
  1725. print '</table>';
  1726. print '<div class="center">';
  1727. print '<input type="submit" class="button" value="'.$langs->trans("Add").'">';
  1728. print '</div>';
  1729. dol_fiche_end();
  1730. print '</form>';
  1731. }
  1732. }
  1733. /*
  1734. * Documents generes
  1735. */
  1736. if ($action != 'create' && $action != 'edit' && $action != 'delete')
  1737. {
  1738. print '<div class="fichecenter"><div class="fichehalfleft">';
  1739. print '<a name="builddoc"></a>'; // ancre
  1740. // Documents
  1741. $objectref = dol_sanitizeFileName($object->ref);
  1742. $relativepath = $comref . '/' . $objectref . '.pdf';
  1743. $filedir = $conf->produit->dir_output . '/' . $objectref;
  1744. $urlsource=$_SERVER["PHP_SELF"]."?id=".$object->id;
  1745. $genallowed=$user->rights->produit->creer;
  1746. $delallowed=$user->rights->produit->supprimer;
  1747. print $formfile->showdocuments($modulepart,$object->ref,$filedir,$urlsource,$genallowed,$delallowed,'',0,0,0,28,0,'',0,'',$object->default_lang, '', $object);
  1748. $somethingshown=$formfile->numoffiles;
  1749. print '</div><div class="fichehalfright"><div class="ficheaddleft">';
  1750. print '</div></div></div>';
  1751. }
  1752. llxFooter();
  1753. $db->close();