card.php 117 KB

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