server_productorservice.php 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143
  1. <?php
  2. /* Copyright (C) 2006-2016 Laurent Destailleur <eldy@users.sourceforge.net>
  3. * Copyright (C) 2012 JF FERRY <jfefe@aternatik.fr>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. * Path to WSDL is: http://localhost/dolibarr/webservices/server_productorservice.php?wsdl
  19. */
  20. /**
  21. * \file htdocs/webservices/server_productorservice.php
  22. * \brief File that is entry point to call Dolibarr WebServices
  23. */
  24. if (! defined("NOCSRFCHECK")) define("NOCSRFCHECK",'1');
  25. require '../master.inc.php';
  26. require_once NUSOAP_PATH.'/nusoap.php'; // Include SOAP
  27. require_once DOL_DOCUMENT_ROOT.'/core/lib/ws.lib.php';
  28. require_once DOL_DOCUMENT_ROOT.'/core/lib/functions.lib.php';
  29. require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
  30. require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
  31. require_once DOL_DOCUMENT_ROOT."/categories/class/categorie.class.php";
  32. require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
  33. dol_syslog("Call Dolibarr webservices interfaces");
  34. $langs->load("main");
  35. // Enable and test if module web services is enabled
  36. if (empty($conf->global->MAIN_MODULE_WEBSERVICES))
  37. {
  38. $langs->load("admin");
  39. dol_syslog("Call Dolibarr webservices interfaces with module webservices disabled");
  40. print $langs->trans("WarningModuleNotActive",'WebServices').'.<br><br>';
  41. print $langs->trans("ToActivateModule");
  42. exit;
  43. }
  44. // Create the soap Object
  45. $server = new nusoap_server();
  46. $server->soap_defencoding='UTF-8';
  47. $server->decode_utf8=false;
  48. $ns='http://www.dolibarr.org/ns/';
  49. $server->configureWSDL('WebServicesDolibarrProductOrService',$ns);
  50. $server->wsdl->schemaTargetNamespace=$ns;
  51. // Define WSDL Authentication object
  52. $server->wsdl->addComplexType(
  53. 'authentication',
  54. 'complexType',
  55. 'struct',
  56. 'all',
  57. '',
  58. array(
  59. 'dolibarrkey' => array('name'=>'dolibarrkey','type'=>'xsd:string'),
  60. 'sourceapplication' => array('name'=>'sourceapplication','type'=>'xsd:string'),
  61. 'login' => array('name'=>'login','type'=>'xsd:string'),
  62. 'password' => array('name'=>'password','type'=>'xsd:string'),
  63. 'entity' => array('name'=>'entity','type'=>'xsd:string')
  64. )
  65. );
  66. // Define WSDL Return object
  67. $server->wsdl->addComplexType(
  68. 'result',
  69. 'complexType',
  70. 'struct',
  71. 'all',
  72. '',
  73. array(
  74. 'result_code' => array('name'=>'result_code','type'=>'xsd:string'),
  75. 'result_label' => array('name'=>'result_label','type'=>'xsd:string')
  76. )
  77. );
  78. $productorservice_fields = array(
  79. 'id' => array('name'=>'id','type'=>'xsd:string'),
  80. 'ref' => array('name'=>'ref','type'=>'xsd:string'),
  81. 'ref_ext' => array('name'=>'ref_ext','type'=>'xsd:string'),
  82. 'type' => array('name'=>'type','type'=>'xsd:string'),
  83. 'label' => array('name'=>'label','type'=>'xsd:string'),
  84. 'description' => array('name'=>'description','type'=>'xsd:string'),
  85. 'date_creation' => array('name'=>'date_creation','type'=>'xsd:dateTime'),
  86. 'date_modification' => array('name'=>'date_modification','type'=>'xsd:dateTime'),
  87. 'note' => array('name'=>'note','type'=>'xsd:string'),
  88. 'status_tobuy' => array('name'=>'status_tobuy','type'=>'xsd:string'),
  89. 'status_tosell' => array('name'=>'status_tosell','type'=>'xsd:string'),
  90. 'barcode' => array('name'=>'barcode','type'=>'xsd:string'),
  91. 'barcode_type' => array('name'=>'barcode_type','type'=>'xsd:string'),
  92. 'country_id' => array('name'=>'country_id','type'=>'xsd:string'),
  93. 'country_code' => array('name'=>'country_code','type'=>'xsd:string'),
  94. 'customcode' => array('name'=>'customcode','type'=>'xsd:string'),
  95. 'price_net' => array('name'=>'price_net','type'=>'xsd:string'),
  96. 'price' => array('name'=>'price','type'=>'xsd:string'),
  97. 'price_min_net' => array('name'=>'price_min_net','type'=>'xsd:string'),
  98. 'price_min' => array('name'=>'price_min','type'=>'xsd:string'),
  99. 'price_base_type' => array('name'=>'price_base_type','type'=>'xsd:string'),
  100. 'vat_rate' => array('name'=>'vat_rate','type'=>'xsd:string'),
  101. 'vat_npr' => array('name'=>'vat_npr','type'=>'xsd:string'),
  102. 'localtax1_tx' => array('name'=>'localtax1_tx','type'=>'xsd:string'),
  103. 'localtax2_tx' => array('name'=>'localtax2_tx','type'=>'xsd:string'),
  104. 'stock_alert' => array('name'=>'stock_alert','type'=>'xsd:string'),
  105. 'stock_real' => array('name'=>'stock_real','type'=>'xsd:string'),
  106. 'stock_pmp' => array('name'=>'stock_pmp','type'=>'xsd:string'),
  107. 'warehouse_ref' => array('name'=>'warehouse_ref','type'=>'xsd:string'), // Used only for create or update to set which warehouse to use for stock correction if stock_real differs from database
  108. 'canvas' => array('name'=>'canvas','type'=>'xsd:string'),
  109. 'import_key' => array('name'=>'import_key','type'=>'xsd:string'),
  110. 'dir' => array('name'=>'dir','type'=>'xsd:string'),
  111. 'images' => array('name'=>'images','type'=>'tns:ImagesArray')
  112. );
  113. //Retreive all extrafield for product
  114. // fetch optionals attributes and labels
  115. $extrafields=new ExtraFields($db);
  116. $extralabels=$extrafields->fetch_name_optionals_label('product',true);
  117. $extrafield_array=null;
  118. if (is_array($extrafields) && count($extrafields) > 0) {
  119. $extrafield_array = array();
  120. }
  121. foreach($extrafields->attribute_label as $key=>$label)
  122. {
  123. $type =$extrafields->attribute_type[$key];
  124. if ($type=='date' || $type=='datetime') {$type='xsd:dateTime';}
  125. else {$type='xsd:string';}
  126. $extrafield_array['options_'.$key]=array('name'=>'options_'.$key,'type'=>$type);
  127. }
  128. if (is_array($extrafield_array)) $productorservice_fields=array_merge($productorservice_fields,$extrafield_array);
  129. // Define other specific objects
  130. $server->wsdl->addComplexType(
  131. 'product',
  132. 'complexType',
  133. 'struct',
  134. 'all',
  135. '',
  136. $productorservice_fields
  137. );
  138. /*
  139. * Image of product
  140. */
  141. $server->wsdl->addComplexType(
  142. 'ImagesArray',
  143. 'complexType',
  144. 'array',
  145. 'sequence',
  146. '',
  147. array(
  148. 'image' => array(
  149. 'name' => 'image',
  150. 'type' => 'tns:image',
  151. 'minOccurs' => '0',
  152. 'maxOccurs' => 'unbounded'
  153. )
  154. )
  155. );
  156. /*
  157. * An image
  158. */
  159. $server->wsdl->addComplexType(
  160. 'image',
  161. 'complexType',
  162. 'struct',
  163. 'all',
  164. '',
  165. array(
  166. 'photo' => array('name'=>'photo','type'=>'xsd:string'),
  167. 'photo_vignette' => array('name'=>'photo_vignette','type'=>'xsd:string'),
  168. 'imgWidth' => array('name'=>'imgWidth','type'=>'xsd:string'),
  169. 'imgHeight' => array('name'=>'imgHeight','type'=>'xsd:string')
  170. )
  171. );
  172. // Define other specific objects
  173. $server->wsdl->addComplexType(
  174. 'filterproduct',
  175. 'complexType',
  176. 'struct',
  177. 'all',
  178. '',
  179. array(
  180. //'limit' => array('name'=>'limit','type'=>'xsd:string'),
  181. 'type' => array('name'=>'type','type'=>'xsd:string'),
  182. 'status_tobuy' => array('name'=>'status_tobuy','type'=>'xsd:string'),
  183. 'status_tosell' => array('name'=>'status_tosell','type'=>'xsd:string'),
  184. )
  185. );
  186. $server->wsdl->addComplexType(
  187. 'ProductsArray2',
  188. 'complexType',
  189. 'array',
  190. 'sequence',
  191. '',
  192. array(
  193. 'product' => array(
  194. 'name' => 'product',
  195. 'type' => 'tns:product',
  196. 'minOccurs' => '0',
  197. 'maxOccurs' => 'unbounded'
  198. )
  199. )
  200. );
  201. // 5 styles: RPC/encoded, RPC/literal, Document/encoded (not WS-I compliant), Document/literal, Document/literal wrapped
  202. // Style merely dictates how to translate a WSDL binding to a SOAP message. Nothing more. You can use either style with any programming model.
  203. // http://www.ibm.com/developerworks/webservices/library/ws-whichwsdl/
  204. $styledoc='rpc'; // rpc/document (document is an extend into SOAP 1.0 to support unstructured messages)
  205. $styleuse='encoded'; // encoded/literal/literal wrapped
  206. // Better choice is document/literal wrapped but literal wrapped not supported by nusoap.
  207. // Register WSDL
  208. $server->register(
  209. 'getProductOrService',
  210. // Entry values
  211. array('authentication'=>'tns:authentication','id'=>'xsd:string','ref'=>'xsd:string','ref_ext'=>'xsd:string','lang'=>'xsd:string'),
  212. // Exit values
  213. array('result'=>'tns:result','product'=>'tns:product'),
  214. $ns,
  215. $ns.'#getProductOrService',
  216. $styledoc,
  217. $styleuse,
  218. 'WS to get product or service'
  219. );
  220. // Register WSDL
  221. $server->register(
  222. 'createProductOrService',
  223. // Entry values
  224. array('authentication'=>'tns:authentication','product'=>'tns:product'),
  225. // Exit values
  226. array('result'=>'tns:result','id'=>'xsd:string'),
  227. $ns,
  228. $ns.'#createProductOrService',
  229. $styledoc,
  230. $styleuse,
  231. 'WS to create a product or service'
  232. );
  233. // Register WSDL
  234. $server->register(
  235. 'updateProductOrService',
  236. // Entry values
  237. array('authentication'=>'tns:authentication','product'=>'tns:product'),
  238. // Exit values
  239. array('result'=>'tns:result','id'=>'xsd:string'),
  240. $ns,
  241. $ns.'#updateProductOrService',
  242. $styledoc,
  243. $styleuse,
  244. 'WS to update a product or service'
  245. );
  246. // Register WSDL
  247. $server->register(
  248. 'deleteProductOrService',
  249. // Entry values
  250. array('authentication'=>'tns:authentication','listofid'=>'xsd:string'),
  251. // Exit values
  252. array('result'=>'tns:result','nbdeleted'=>'xsd:int'),
  253. $ns,
  254. $ns.'#deleteProductOrService',
  255. $styledoc,
  256. $styleuse,
  257. 'WS to delete a product or service'
  258. );
  259. // Register WSDL
  260. $server->register(
  261. 'getListOfProductsOrServices',
  262. // Entry values
  263. array('authentication'=>'tns:authentication','filterproduct'=>'tns:filterproduct'),
  264. // Exit values
  265. array('result'=>'tns:result','products'=>'tns:ProductsArray2'),
  266. $ns,
  267. $ns.'#getListOfProductsOrServices',
  268. $styledoc,
  269. $styleuse,
  270. 'WS to get list of all products or services id and ref'
  271. );
  272. // Register WSDL
  273. $server->register(
  274. 'getProductsForCategory',
  275. // Entry values
  276. array('authentication'=>'tns:authentication','id'=>'xsd:string','lang'=>'xsd:string'),
  277. // Exit values
  278. array('result'=>'tns:result','products'=>'tns:ProductsArray2'),
  279. $ns,
  280. $ns.'#getProductsForCategory',
  281. $styledoc,
  282. $styleuse,
  283. 'WS to get list of all products or services for a category'
  284. );
  285. /**
  286. * Get produt or service
  287. *
  288. * @param array $authentication Array of authentication information
  289. * @param int $id Id of object
  290. * @param string $ref Ref of object
  291. * @param string $ref_ext Ref external of object
  292. * @param string $lang Lang to force
  293. * @return mixed
  294. */
  295. function getProductOrService($authentication,$id='',$ref='',$ref_ext='',$lang='')
  296. {
  297. global $db,$conf,$langs;
  298. dol_syslog("Function: getProductOrService login=".$authentication['login']." id=".$id." ref=".$ref." ref_ext=".$ref_ext);
  299. $langcode=($lang?$lang:(empty($conf->global->MAIN_LANG_DEFAULT)?'auto':$conf->global->MAIN_LANG_DEFAULT));
  300. $langs->setDefaultLang($langcode);
  301. if ($authentication['entity']) $conf->entity=$authentication['entity'];
  302. // Init and check authentication
  303. $objectresp=array();
  304. $errorcode='';$errorlabel='';
  305. $error=0;
  306. $fuser=check_authentication($authentication,$error,$errorcode,$errorlabel);
  307. // Check parameters
  308. if (! $error && (($id && $ref) || ($id && $ref_ext) || ($ref && $ref_ext)))
  309. {
  310. $error++;
  311. $errorcode='BAD_PARAMETERS'; $errorlabel="Parameter id, ref and ref_ext can't be both provided. You must choose one or other but not both.";
  312. }
  313. if (! $error)
  314. {
  315. $langcode=($lang?$lang:(empty($conf->global->MAIN_LANG_DEFAULT)?'auto':$conf->global->MAIN_LANG_DEFAULT));
  316. $langs->setDefaultLang($langcode);
  317. $fuser->getrights();
  318. if ($fuser->rights->produit->lire || $fuser->rights->service->lire)
  319. {
  320. $product=new Product($db);
  321. $result=$product->fetch($id,$ref,$ref_ext);
  322. if ($result > 0)
  323. {
  324. $product->load_stock();
  325. $dir = (!empty($conf->product->dir_output)?$conf->product->dir_output:$conf->service->dir_output);
  326. $pdir = get_exdir($product->id,2,0,0,$product,'product') . $product->ref . "/";
  327. $dir = $dir . '/'. $pdir;
  328. if (! empty($product->multilangs[$langs->defaultlang]["label"])) $product->label = $product->multilangs[$langs->defaultlang]["label"];
  329. if (! empty($product->multilangs[$langs->defaultlang]["description"])) $product->description = $product->multilangs[$langs->defaultlang]["description"];
  330. if (! empty($product->multilangs[$langs->defaultlang]["note"])) $product->note = $product->multilangs[$langs->defaultlang]["note"];
  331. $productorservice_result_fields = array(
  332. 'id' => $product->id,
  333. 'ref' => $product->ref,
  334. 'ref_ext' => $product->ref_ext,
  335. 'label' => $product->label,
  336. 'description' => $product->description,
  337. 'date_creation' => dol_print_date($product->date_creation,'dayhourrfc'),
  338. 'date_modification' => dol_print_date($product->date_modification,'dayhourrfc'),
  339. 'note' => $product->note,
  340. 'status_tosell' => $product->status,
  341. 'status_tobuy' => $product->status_buy,
  342. 'type' => $product->type,
  343. 'barcode' => $product->barcode,
  344. 'barcode_type' => $product->barcode_type,
  345. 'country_id' => $product->country_id>0?$product->country_id:'',
  346. 'country_code' => $product->country_code,
  347. 'custom_code' => $product->customcode,
  348. 'price_net' => $product->price,
  349. 'price' => $product->price_ttc,
  350. 'price_min_net' => $product->price_min,
  351. 'price_min' => $product->price_min_ttc,
  352. 'price_base_type' => $product->price_base_type,
  353. 'vat_rate' => $product->tva_tx,
  354. //! French VAT NPR
  355. 'vat_npr' => $product->tva_npr,
  356. //! Spanish local taxes
  357. 'localtax1_tx' => $product->localtax1_tx,
  358. 'localtax2_tx' => $product->localtax2_tx,
  359. 'stock_real' => $product->stock_reel,
  360. 'stock_virtual' => $product->stock_theorique,
  361. 'stock_alert' => $product->seuil_stock_alerte,
  362. 'pmp' => $product->pmp,
  363. 'import_key' => $product->import_key,
  364. 'dir' => $pdir,
  365. 'images' => $product->liste_photos($dir,$nbmax=10)
  366. );
  367. //Retreive all extrafield for thirdsparty
  368. // fetch optionals attributes and labels
  369. $extrafields=new ExtraFields($db);
  370. $extralabels=$extrafields->fetch_name_optionals_label('product',true);
  371. //Get extrafield values
  372. $product->fetch_optionals();
  373. foreach($extrafields->attribute_label as $key=>$label)
  374. {
  375. $productorservice_result_fields=array_merge($productorservice_result_fields,array('options_'.$key => $product->array_options['options_'.$key]));
  376. }
  377. // Create
  378. $objectresp = array(
  379. 'result'=>array('result_code'=>'OK', 'result_label'=>''),
  380. 'product'=>$productorservice_result_fields
  381. );
  382. }
  383. else
  384. {
  385. $error++;
  386. $errorcode='NOT_FOUND'; $errorlabel='Object not found for id='.$id.' nor ref='.$ref.' nor ref_ext='.$ref_ext;
  387. }
  388. }
  389. else
  390. {
  391. $error++;
  392. $errorcode='PERMISSION_DENIED'; $errorlabel='User does not have permission for this request';
  393. }
  394. }
  395. if ($error)
  396. {
  397. $objectresp = array('result'=>array('result_code' => $errorcode, 'result_label' => $errorlabel));
  398. }
  399. //var_dump($objectresp);exit;
  400. return $objectresp;
  401. }
  402. /**
  403. * Create an invoice
  404. *
  405. * @param array $authentication Array of authentication information
  406. * @param Product $product Product
  407. * @return array Array result
  408. */
  409. function createProductOrService($authentication,$product)
  410. {
  411. global $db,$conf,$langs;
  412. $now=dol_now();
  413. dol_syslog("Function: createProductOrService login=".$authentication['login']);
  414. if ($authentication['entity']) $conf->entity=$authentication['entity'];
  415. // Init and check authentication
  416. $objectresp=array();
  417. $errorcode='';$errorlabel='';
  418. $error=0;
  419. $fuser=check_authentication($authentication,$error,$errorcode,$errorlabel);
  420. // Check parameters
  421. if ($product['price_net'] > 0) $product['price_base_type']='HT';
  422. if ($product['price'] > 0) $product['price_base_type']='TTC';
  423. if ($product['price_net'] > 0 && $product['price'] > 0)
  424. {
  425. $error++; $errorcode='KO'; $errorlabel="You must choose between price or price_net to provide price.";
  426. }
  427. if ($product['barcode'] && !$product['barcode_type'])
  428. {
  429. $errror++; $errorcode='KO' ; $errorlabel="You must set a barcode type when setting a barcode.";
  430. }
  431. if (! $error)
  432. {
  433. include_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
  434. $newobject=new Product($db);
  435. $newobject->ref=$product['ref'];
  436. $newobject->ref_ext=$product['ref_ext'];
  437. $newobject->type=$product['type'];
  438. $newobject->libelle=$product['label']; // @deprecated
  439. $newobject->label=$product['label'];
  440. $newobject->description=$product['description'];
  441. $newobject->note=$product['note'];
  442. $newobject->status=$product['status_tosell'];
  443. $newobject->status_buy=$product['status_tobuy'];
  444. $newobject->price=$product['price_net'];
  445. $newobject->price_ttc=$product['price'];
  446. $newobject->tva_tx=$product['vat_rate'];
  447. $newobject->price_base_type=$product['price_base_type'];
  448. $newobject->date_creation=$now;
  449. if ($product['barcode'])
  450. {
  451. $newobject->barcode = $product['barcode'];
  452. $newobject->barcode_type = $product['barcode_type'];
  453. }
  454. $newobject->stock_reel=$product['stock_real'];
  455. $newobject->pmp=$product['pmp'];
  456. $newobject->seuil_stock_alert=$product['stock_alert'];
  457. $newobject->country_id=$product['country_id'];
  458. if ($product['country_code']) $newobject->country_id=getCountry($product['country_code'],3);
  459. $newobject->customcode=$product['customcode'];
  460. $newobject->canvas=$product['canvas'];
  461. /*foreach($product['lines'] as $line)
  462. {
  463. $newline=new FactureLigne($db);
  464. $newline->type=$line['type'];
  465. $newline->desc=$line['desc'];
  466. $newline->fk_product=$line['fk_product'];
  467. $newline->total_ht=$line['total_net'];
  468. $newline->total_vat=$line['total_vat'];
  469. $newline->total_ttc=$line['total'];
  470. $newline->vat=$line['vat_rate'];
  471. $newline->qty=$line['qty'];
  472. $newline->fk_product=$line['product_id'];
  473. }*/
  474. //var_dump($product['ref_ext']);
  475. //var_dump($product['lines'][0]['type']);
  476. $extrafields=new ExtraFields($db);
  477. $extralabels=$extrafields->fetch_name_optionals_label('product',true);
  478. foreach($extrafields->attribute_label as $key=>$label)
  479. {
  480. $key='options_'.$key;
  481. $newobject->array_options[$key]=$product[$key];
  482. }
  483. $db->begin();
  484. $result=$newobject->create($fuser,0);
  485. if ($result <= 0)
  486. {
  487. $error++;
  488. }
  489. if (! $error)
  490. {
  491. // Update stock if stock count is provided and differs from database after creation or update
  492. if (isset($product['stock_real']) && $product['stock_real'] != '' && ! empty($conf->global->stock->enabled))
  493. {
  494. include_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
  495. $savstockreal=$newobject->stock_reel;
  496. $newobject->load_stock('novirtual,nobatch'); // This overwrite ->stock_reel, surely 0 because we have just created product
  497. $getstockreal = $newobject->stock_reel;
  498. if ($savstockreal != $getstockreal)
  499. {
  500. $warehouse = new Entrepot($this->db);
  501. $warehouse->fetch(0, $product['warehouse_ref']);
  502. if ($warehouse->id > 0)
  503. {
  504. if (($savstockreal - $getstockreal) > 0)
  505. {
  506. $result=$newobject->correct_stock($fuser, $warehouse->id, ($savstockreal - $getstockreal), 0, 'Correction from external call (Web Service)', 0, 'WS'.dol_print_date($now,'dayhourlog'));
  507. }
  508. if (($savstockreal - $getstockreal) > 0)
  509. {
  510. $result=$newobject->correct_stock($fuser, $warehouse->id, ($savstockreal - $getstockreal), 1, 'Correction from external call (Web Service)', 0, 'WS'.dol_print_date($now,'dayhourlog'));
  511. }
  512. if ($result <= 0)
  513. {
  514. $error++;
  515. $newobject->error='You set a different value for stock, but correction of stock count (before='.$getstockreal.', after='.$savstockreal.') fails with error '.$newobject->error;
  516. }
  517. }
  518. else
  519. {
  520. $error++;
  521. $newobject->error='You set a different value for stock but we failed to find warehouse '.$product['warehouse_ref'].' to make correction.';
  522. }
  523. }
  524. }
  525. }
  526. if (! $error)
  527. {
  528. $db->commit();
  529. $objectresp=array('result'=>array('result_code'=>'OK', 'result_label'=>''),'id'=>$newobject->id,'ref'=>$newobject->ref);
  530. }
  531. else
  532. {
  533. $db->rollback();
  534. $error++;
  535. $errorcode='KO';
  536. $errorlabel=$newobject->error;
  537. }
  538. }
  539. if ($error)
  540. {
  541. $objectresp = array('result'=>array('result_code' => $errorcode, 'result_label' => $errorlabel));
  542. }
  543. return $objectresp;
  544. }
  545. /**
  546. * Update a product or service
  547. *
  548. * @param array $authentication Array of authentication information
  549. * @param Product $product Product
  550. * @return array Array result
  551. */
  552. function updateProductOrService($authentication,$product)
  553. {
  554. global $db,$conf,$langs;
  555. $now=dol_now();
  556. dol_syslog("Function: updateProductOrService login=".$authentication['login']);
  557. if ($authentication['entity']) $conf->entity=$authentication['entity'];
  558. // Init and check authentication
  559. $objectresp=array();
  560. $errorcode='';$errorlabel='';
  561. $error=0;
  562. $fuser=check_authentication($authentication,$error,$errorcode,$errorlabel);
  563. // Check parameters
  564. if ($product['price_net'] > 0) $product['price_base_type']='HT';
  565. if ($product['price'] > 0) $product['price_base_type']='TTC';
  566. if ($product['price_net'] > 0 && $product['price'] > 0)
  567. {
  568. $error++; $errorcode='KO'; $errorlabel="You must choose between price or price_net to provide price.";
  569. }
  570. if ($product['barcode'] && !$product['barcode_type'])
  571. {
  572. $errror++; $errorcode='KO' ; $errorlabel="You must set a barcode type when setting a barcode.";
  573. }
  574. if (! $error)
  575. {
  576. include_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
  577. $newobject=new Product($db);
  578. $newobject->fetch($product['id']);
  579. if (isset($product['ref'])) $newobject->ref=$product['ref'];
  580. if (isset($product['ref_ext'])) $newobject->ref_ext=$product['ref_ext'];
  581. $newobject->type=$product['type'];
  582. $newobject->libelle=$product['label']; // @deprecated
  583. $newobject->label=$product['label'];
  584. $newobject->description=$product['description'];
  585. $newobject->note=$product['note'];
  586. $newobject->status=$product['status_tosell'];
  587. $newobject->status_buy=$product['status_tobuy'];
  588. $newobject->price=$product['price_net'];
  589. $newobject->price_ttc=$product['price'];
  590. $newobject->tva_tx=$product['vat_rate'];
  591. $newobject->price_base_type=$product['price_base_type'];
  592. $newobject->date_creation=$now;
  593. if ($product['barcode'])
  594. {
  595. $newobject->barcode = $product['barcode'];
  596. $newobject->barcode_type = $product['barcode_type'];
  597. }
  598. $newobject->stock_reel=$product['stock_real'];
  599. $newobject->pmp=$product['pmp'];
  600. $newobject->seuil_stock_alert=$product['stock_alert'];
  601. $newobject->country_id=$product['country_id'];
  602. if ($product['country_code']) $newobject->country_id=getCountry($product['country_code'],3);
  603. $newobject->customcode=$product['customcode'];
  604. $newobject->canvas=$product['canvas'];
  605. /*foreach($product['lines'] as $line)
  606. {
  607. $newline=new FactureLigne($db);
  608. $newline->type=$line['type'];
  609. $newline->desc=$line['desc'];
  610. $newline->fk_product=$line['fk_product'];
  611. $newline->total_ht=$line['total_net'];
  612. $newline->total_vat=$line['total_vat'];
  613. $newline->total_ttc=$line['total'];
  614. $newline->vat=$line['vat_rate'];
  615. $newline->qty=$line['qty'];
  616. $newline->fk_product=$line['product_id'];
  617. }*/
  618. //var_dump($product['ref_ext']);
  619. //var_dump($product['lines'][0]['type']);
  620. $extrafields=new ExtraFields($db);
  621. $extralabels=$extrafields->fetch_name_optionals_label('product',true);
  622. foreach($extrafields->attribute_label as $key=>$label)
  623. {
  624. $key='options_'.$key;
  625. $newobject->array_options[$key]=$product[$key];
  626. }
  627. $db->begin();
  628. $result=$newobject->update($newobject->id,$fuser);
  629. if ($result <= 0)
  630. {
  631. $error++;
  632. }
  633. else
  634. {
  635. // Update stock if stock count is provided and differs from database after creation or update
  636. if (isset($product['stock_real']) && $product['stock_real'] != '' && ! empty($conf->global->stock->enabled))
  637. {
  638. include_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
  639. $savstockreal=$newobject->stock_reel;
  640. $newobject->load_stock('novirtual,nobatch'); // This overwrite ->stock_reel
  641. $getstockreal = $newobject->stock_reel;
  642. if ($savstockreal != $getstockreal)
  643. {
  644. $warehouse = new Entrepot($this->db);
  645. $warehouse->fetch(0, $product['warehouse_ref']);
  646. if ($warehouse->id > 0)
  647. {
  648. if (($savstockreal - $getstockreal) > 0)
  649. {
  650. $result=$newobject->correct_stock($fuser, $warehouse->id, ($savstockreal - $getstockreal), 0, 'Correction from external call (Web Service)', 0, 'WS'.dol_print_date($now,'dayhourlog'));
  651. }
  652. if (($savstockreal - $getstockreal) > 0)
  653. {
  654. $result=$newobject->correct_stock($fuser, $warehouse->id, ($savstockreal - $getstockreal), 1, 'Correction from external call (Web Service)', 0, 'WS'.dol_print_date($now,'dayhourlog'));
  655. }
  656. if ($result <= 0)
  657. {
  658. $error++;
  659. $newobject->error='You set a different value for stock, but correction of stock count (before='.$getstockreal.', after='.$savstockreal.') fails with error '.$newobject->error;
  660. }
  661. }
  662. else
  663. {
  664. $error++;
  665. $newobject->error='You set a different value for stock but we failed to find warehouse '.$product['warehouse_ref'].' to make correction.';
  666. }
  667. }
  668. }
  669. }
  670. if (! $error)
  671. {
  672. if ($newobject->price_base_type == 'HT')
  673. {
  674. $result=$newobject->updatePrice($newobject->price, $newobject->price_base_type,$fuser);
  675. if ($result <= 0)
  676. {
  677. $error++;
  678. }
  679. }
  680. elseif ($newobject->price_base_type == 'TTC')
  681. {
  682. $result=$newobject->updatePrice($newobject->price_ttc, $newobject->price_base_type);
  683. if ($result <= 0)
  684. {
  685. $error++;
  686. }
  687. }
  688. }
  689. if (! $error)
  690. {
  691. $db->commit();
  692. $objectresp=array('result'=>array('result_code'=>'OK', 'result_label'=>''),'id'=>$newobject->id,'ref'=>$newobject->ref);
  693. }
  694. else
  695. {
  696. $db->rollback();
  697. $error++;
  698. $errorcode='KO';
  699. $errorlabel=$newobject->error;
  700. }
  701. }
  702. if ($error)
  703. {
  704. $objectresp = array('result'=>array('result_code' => $errorcode, 'result_label' => $errorlabel));
  705. }
  706. return $objectresp;
  707. }
  708. /**
  709. * Delete a product or service
  710. *
  711. * @param array $authentication Array of authentication information
  712. * @param string $listofidstring List of id with comma
  713. * @return array Array result
  714. */
  715. function deleteProductOrService($authentication,$listofidstring)
  716. {
  717. global $db,$conf,$langs;
  718. $now=dol_now();
  719. dol_syslog("Function: deleteProductOrService login=".$authentication['login']);
  720. if ($authentication['entity']) $conf->entity=$authentication['entity'];
  721. // Init and check authentication
  722. $objectresp=array();
  723. $errorcode='';$errorlabel='';
  724. $error=0;
  725. $fuser=check_authentication($authentication,$error,$errorcode,$errorlabel);
  726. // User must be defined to user authenticated
  727. global $user;
  728. $user=$fuser;
  729. $listofid=explode(',',trim($listofidstring));
  730. $listofiddeleted=array();
  731. // Check parameters
  732. if (count($listofid) == 0 || empty($listofid[0]))
  733. {
  734. $error++; $errorcode='KO'; $errorlabel="List of Id of products or services to delete are required.";
  735. }
  736. if (! $error)
  737. {
  738. $firsterror='';
  739. $db->begin();
  740. foreach($listofid as $key => $id)
  741. {
  742. $newobject=new Product($db);
  743. $result=$newobject->fetch($id);
  744. if ($result == 0)
  745. {
  746. $error++;
  747. $firsterror='Product or service with id '.$id.' not found';
  748. break;
  749. }
  750. else
  751. {
  752. $result=$newobject->delete($user);
  753. if ($result <= 0)
  754. {
  755. $error++;
  756. $firsterror=$newobject->error;
  757. break;
  758. }
  759. $listofiddeleted[]=$id;
  760. }
  761. }
  762. if (! $error)
  763. {
  764. $db->commit();
  765. //$objectresp=array('result'=>array('result_code'=>'OK', 'result_label'=>''), 'listofid'=>$listofiddeleted);
  766. $objectresp=array('result'=>array('result_code'=>'OK', 'result_label'=>''), 'nbdeleted'=>count($listofiddeleted));
  767. }
  768. else
  769. {
  770. $db->rollback();
  771. $error++;
  772. $errorcode='KO';
  773. $errorlabel=$firsterror;
  774. }
  775. }
  776. if ($error)
  777. {
  778. //$objectresp = array('result'=>array('result_code' => $errorcode, 'result_label' => $errorlabel), 'listofid'=>$listofiddeleted);
  779. $objectresp = array('result'=>array('result_code' => $errorcode, 'result_label' => $errorlabel), 'nbdeleted'=>0);
  780. }
  781. else if (count($listofiddeleted) == 0)
  782. {
  783. //$objectresp=array('result'=>array('result_code'=>'NOT_FOUND', 'result_label'=>'No product or service with id '.join(',',$listofid).' found'), 'listofid'=>$listofiddeleted);
  784. $objectresp=array('result'=>array('result_code'=>'NOT_FOUND', 'result_label'=>'No product or service with id '.join(',',$listofid).' found'), 'nbdeleted'=>0);
  785. }
  786. return $objectresp;
  787. }
  788. /**
  789. * getListOfProductsOrServices
  790. *
  791. * @param array $authentication Array of authentication information
  792. * @param array $filterproduct Filter fields
  793. * @return array Array result
  794. */
  795. function getListOfProductsOrServices($authentication,$filterproduct)
  796. {
  797. global $db,$conf,$langs;
  798. $now=dol_now();
  799. dol_syslog("Function: getListOfProductsOrServices login=".$authentication['login']);
  800. if ($authentication['entity']) $conf->entity=$authentication['entity'];
  801. // Init and check authentication
  802. $objectresp=array();
  803. $arrayproducts=array();
  804. $errorcode='';$errorlabel='';
  805. $error=0;
  806. $fuser=check_authentication($authentication,$error,$errorcode,$errorlabel);
  807. // Check parameters
  808. if (! $error)
  809. {
  810. $sql ="SELECT rowid, ref, ref_ext";
  811. $sql.=" FROM ".MAIN_DB_PREFIX."product";
  812. $sql.=" WHERE entity=".$conf->entity;
  813. foreach($filterproduct as $key => $val)
  814. {
  815. if ($key == 'type' && $val >= 0) $sql.=" AND fk_product_type = ".$db->escape($val);
  816. if ($key == 'status_tosell') $sql.=" AND tosell = ".$db->escape($val);
  817. if ($key == 'status_tobuy') $sql.=" AND tobuy = ".$db->escape($val);
  818. }
  819. $resql=$db->query($sql);
  820. if ($resql)
  821. {
  822. $num=$db->num_rows($resql);
  823. $i=0;
  824. while ($i < $num)
  825. {
  826. $obj=$db->fetch_object($resql);
  827. $arrayproducts[]=array('id'=>$obj->rowid,'ref'=>$obj->ref,'ref_ext'=>$obj->ref_ext);
  828. $i++;
  829. }
  830. }
  831. else
  832. {
  833. $error++;
  834. $errorcode=$db->lasterrno();
  835. $errorlabel=$db->lasterror();
  836. }
  837. }
  838. if ($error)
  839. {
  840. $objectresp = array(
  841. 'result'=>array('result_code' => $errorcode, 'result_label' => $errorlabel),
  842. 'products'=>$arrayproducts
  843. );
  844. }
  845. else
  846. {
  847. $objectresp = array(
  848. 'result'=>array('result_code' => 'OK', 'result_label' => ''),
  849. 'products'=>$arrayproducts
  850. );
  851. }
  852. return $objectresp;
  853. }
  854. /**
  855. * Get list of products for a category
  856. *
  857. * @param array $authentication Array of authentication information
  858. * @param array $id Category id
  859. * @param $lang $lang Force lang
  860. * @return array Array result
  861. */
  862. function getProductsForCategory($authentication,$id,$lang='')
  863. {
  864. global $db,$conf,$langs;
  865. $langcode=($lang?$lang:(empty($conf->global->MAIN_LANG_DEFAULT)?'auto':$conf->global->MAIN_LANG_DEFAULT));
  866. $langs->setDefaultLang($langcode);
  867. dol_syslog("Function: getProductsForCategory login=".$authentication['login']." id=".$id);
  868. if ($authentication['entity']) $conf->entity=$authentication['entity'];
  869. $objectresp=array();
  870. $errorcode='';$errorlabel='';
  871. $error=0;
  872. $fuser=check_authentication($authentication,$error,$errorcode,$errorlabel);
  873. if (! $error && !$id)
  874. {
  875. $error++;
  876. $errorcode='BAD_PARAMETERS'; $errorlabel="Parameter id must be provided.";
  877. }
  878. if (! $error)
  879. {
  880. $langcode=($lang?$lang:(empty($conf->global->MAIN_LANG_DEFAULT)?'auto':$conf->global->MAIN_LANG_DEFAULT));
  881. $langs->setDefaultLang($langcode);
  882. $fuser->getrights();
  883. if ($fuser->rights->produit->lire)
  884. {
  885. $categorie=new Categorie($db);
  886. $result=$categorie->fetch($id);
  887. if ($result > 0)
  888. {
  889. $table = "product";
  890. $field = "product";
  891. $sql = "SELECT fk_".$field." FROM ".MAIN_DB_PREFIX."categorie_".$table;
  892. $sql .= " WHERE fk_categorie = ".$id;
  893. $sql .= " ORDER BY fk_".$field." ASC" ;
  894. dol_syslog("getProductsForCategory get id of product into category", LOG_DEBUG);
  895. $res = $db->query($sql);
  896. if ($res)
  897. {
  898. $iProduct = 0;
  899. while ($rec = $db->fetch_array($res))
  900. {
  901. $obj = new Product($db);
  902. $obj->fetch($rec['fk_'.$field]);
  903. if($obj->status > 0 )
  904. {
  905. $dir = (!empty($conf->product->dir_output)?$conf->product->dir_output:$conf->service->dir_output);
  906. $pdir = get_exdir($obj->id,2,0,0,$product,'product') . $obj->id ."/photos/";
  907. $dir = $dir . '/'. $pdir;
  908. $products[] = array(
  909. 'id' => $obj->id,
  910. 'ref' => $obj->ref,
  911. 'ref_ext' => $obj->ref_ext,
  912. 'label' => ! empty($obj->multilangs[$langs->defaultlang]["label"]) ? $obj->multilangs[$langs->defaultlang]["label"] : $obj->label,
  913. 'description' => ! empty($obj->multilangs[$langs->defaultlang]["description"]) ? $obj->multilangs[$langs->defaultlang]["description"] : $obj->description,
  914. 'date_creation' => dol_print_date($obj->date_creation,'dayhourrfc'),
  915. 'date_modification' => dol_print_date($obj->date_modification,'dayhourrfc'),
  916. 'note' => ! empty($obj->multilangs[$langs->defaultlang]["note"]) ? $obj->multilangs[$langs->defaultlang]["note"] : $obj->note,
  917. 'status_tosell' => $obj->status,
  918. 'status_tobuy' => $obj->status_buy,
  919. 'type' => $obj->type,
  920. 'barcode' => $obj->barcode,
  921. 'barcode_type' => $obj->barcode_type,
  922. 'country_id' => $obj->country_id>0?$obj->country_id:'',
  923. 'country_code' => $obj->country_code,
  924. 'custom_code' => $obj->customcode,
  925. 'price_net' => $obj->price,
  926. 'price' => $obj->price_ttc,
  927. 'vat_rate' => $obj->tva_tx,
  928. 'price_base_type' => $obj->price_base_type,
  929. 'stock_real' => $obj->stock_reel,
  930. 'stock_alert' => $obj->seuil_stock_alerte,
  931. 'pmp' => $obj->pmp,
  932. 'import_key' => $obj->import_key,
  933. 'dir' => $pdir,
  934. 'images' => $obj->liste_photos($dir,$nbmax=10)
  935. );
  936. //Retreive all extrafield for thirdsparty
  937. // fetch optionals attributes and labels
  938. $extrafields=new ExtraFields($db);
  939. $extralabels=$extrafields->fetch_name_optionals_label('product',true);
  940. //Get extrafield values
  941. $obj->fetch_optionals();
  942. foreach($extrafields->attribute_label as $key=>$label)
  943. {
  944. $products[$iProduct]=array_merge($products[$iProduct],array('options_'.$key => $obj->array_options['options_'.$key]));
  945. }
  946. $iProduct++;
  947. }
  948. }
  949. // Retour
  950. $objectresp = array(
  951. 'result'=>array('result_code'=>'OK', 'result_label'=>''),
  952. 'products'=> $products
  953. );
  954. }
  955. else
  956. {
  957. $errorcode='NORECORDS_FOR_ASSOCIATION'; $errorlabel='No products associated'.$sql;
  958. $objectresp = array('result'=>array('result_code' => $errorcode, 'result_label' => $errorlabel));
  959. dol_syslog("getProductsForCategory:: ".$c->error, LOG_DEBUG);
  960. }
  961. }
  962. else
  963. {
  964. $error++;
  965. $errorcode='NOT_FOUND'; $errorlabel='Object not found for id='.$id;
  966. }
  967. }
  968. else
  969. {
  970. $error++;
  971. $errorcode='PERMISSION_DENIED'; $errorlabel='User does not have permission for this request';
  972. }
  973. }
  974. if ($error)
  975. {
  976. $objectresp = array('result'=>array('result_code' => $errorcode, 'result_label' => $errorlabel));
  977. }
  978. return $objectresp;
  979. }
  980. // Return the results.
  981. $server->service(file_get_contents("php://input"));