PageRenderTime 32ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/htdocs/comm/propal/class/propal.class.php

https://github.com/asterix14/dolibarr
PHP | 2773 lines | 2011 code | 317 blank | 445 comment | 279 complexity | 9f13ce5d6a3d7c4234fcb96e14a7f039 MD5 | raw file
Possible License(s): LGPL-2.0
  1. <?php
  2. /* Copyright (C) 2002-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2004 Eric Seigne <eric.seigne@ryxeo.com>
  4. * Copyright (C) 2004-2011 Laurent Destailleur <eldy@users.sourceforge.net>
  5. * Copyright (C) 2005 Marc Barilley / Ocebo <marc@ocebo.com>
  6. * Copyright (C) 2005-2011 Regis Houssin <regis@dolibarr.fr>
  7. * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
  8. * Copyright (C) 2008 Raphael Bertrand (Resultic) <raphael.bertrand@resultic.fr>
  9. * Copyright (C) 2010-2011 Juanjo Menent <jmenent@2byte.es>
  10. * Copyright (C) 2010-2011 Philippe Grand <philippe.grand@atoo-net.com>
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License as published by
  14. * the Free Software Foundation; either version 2 of the License, or
  15. * (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  24. */
  25. /**
  26. * \file htdocs/comm/propal/class/propal.class.php
  27. * \brief Fichier de la classe des propales
  28. * \author Rodolphe Qiedeville
  29. * \author Eric Seigne
  30. * \author Laurent Destailleur
  31. */
  32. require_once(DOL_DOCUMENT_ROOT ."/core/class/commonobject.class.php");
  33. require_once(DOL_DOCUMENT_ROOT ."/product/class/product.class.php");
  34. require_once(DOL_DOCUMENT_ROOT ."/contact/class/contact.class.php");
  35. /**
  36. * \class Propal
  37. * \brief Classe permettant la gestion des propales
  38. */
  39. class Propal extends CommonObject
  40. {
  41. public $element='propal';
  42. public $table_element='propal';
  43. public $table_element_line='propaldet';
  44. public $fk_element='fk_propal';
  45. protected $ismultientitymanaged = 1; // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
  46. var $id;
  47. var $socid; // Id client
  48. var $client; // Objet societe client (a charger par fetch_client)
  49. var $contactid;
  50. var $fk_project;
  51. var $author;
  52. var $ref;
  53. var $ref_client;
  54. var $statut; // 0 (draft), 1 (validated), 2 (signed), 3 (not signed), 4 (billed)
  55. var $datec; // Date of creation
  56. var $datev; // Date of validation
  57. var $date; // Date of proposal
  58. var $datep; // Same than date
  59. var $date_livraison;
  60. var $fin_validite;
  61. var $user_author_id;
  62. var $user_valid_id;
  63. var $user_close_id;
  64. var $total_ht; // Total net of tax
  65. var $total_tva; // Total VAT
  66. var $total_localtax1; // Total Local Taxes 1
  67. var $total_localtax2; // Total Local Taxes 2
  68. var $total_ttc; // Total with tax
  69. var $price; // deprecated (for compatibility)
  70. var $tva; // deprecated (for compatibility)
  71. var $total; // deprecated (for compatibility)
  72. var $cond_reglement_id;
  73. var $cond_reglement_code;
  74. var $mode_reglement_id;
  75. var $mode_reglement_code;
  76. var $remise;
  77. var $remise_percent;
  78. var $remise_absolue;
  79. var $note;
  80. var $note_public;
  81. var $fk_delivery_address; // deprecated (for compatibility)
  82. var $fk_address;
  83. var $address_type;
  84. var $adresse;
  85. var $availability_id;
  86. var $availability_code;
  87. var $demand_reason_id;
  88. var $demand_reason_code;
  89. var $products=array();
  90. var $lines = array();
  91. var $line;
  92. var $origin;
  93. var $origin_id;
  94. var $labelstatut=array();
  95. var $labelstatut_short=array();
  96. // Pour board
  97. var $nbtodo;
  98. var $nbtodolate;
  99. var $specimen;
  100. /**
  101. * \brief Constructeur
  102. * \param DB Database handler
  103. * \param socid Id third party
  104. * \param propalid Id proposal
  105. */
  106. function Propal($DB, $socid="", $propalid=0)
  107. {
  108. global $conf,$langs;
  109. $this->db = $DB ;
  110. $this->socid = $socid;
  111. $this->id = $propalid;
  112. $this->products = array();
  113. $this->remise = 0;
  114. $this->remise_percent = 0;
  115. $this->remise_absolue = 0;
  116. $this->duree_validite=$conf->global->PROPALE_VALIDITY_DURATION;
  117. $langs->load("propal");
  118. $this->labelstatut[0]=($conf->global->PROPAL_STATUS_DRAFT_LABEL ? $conf->global->PROPAL_STATUS_DRAFT_LABEL : $langs->trans("PropalStatusDraft"));
  119. $this->labelstatut[1]=($conf->global->PROPAL_STATUS_VALIDATED_LABEL ? $conf->global->PROPAL_STATUS_VALIDATED_LABEL : $langs->trans("PropalStatusValidated"));
  120. $this->labelstatut[2]=($conf->global->PROPAL_STATUS_SIGNED_LABEL ? $conf->global->PROPAL_STATUS_SIGNED_LABEL : $langs->trans("PropalStatusSigned"));
  121. $this->labelstatut[3]=($conf->global->PROPAL_STATUS_NOTSIGNED_LABEL ? $conf->global->PROPAL_STATUS_NOTSIGNED_LABEL : $langs->trans("PropalStatusNotSigned"));
  122. $this->labelstatut[4]=($conf->global->PROPAL_STATUS_BILLED_LABEL ? $conf->global->PROPAL_STATUS_BILLED_LABEL : $langs->trans("PropalStatusBilled"));
  123. $this->labelstatut_short[0]=($conf->global->PROPAL_STATUS_DRAFTSHORT_LABEL ? $conf->global->PROPAL_STATUS_DRAFTSHORT_LABEL : $langs->trans("PropalStatusDraftShort"));
  124. $this->labelstatut_short[1]=($conf->global->PROPAL_STATUS_VALIDATEDSHORT_LABEL ? $conf->global->PROPAL_STATUS_VALIDATEDSHORT_LABEL : $langs->trans("Opened"));
  125. $this->labelstatut_short[2]=($conf->global->PROPAL_STATUS_SIGNEDSHORT_LABEL ? $conf->global->PROPAL_STATUS_SIGNEDSHORT_LABEL : $langs->trans("PropalStatusSignedShort"));
  126. $this->labelstatut_short[3]=($conf->global->PROPAL_STATUS_NOTSIGNEDSHORT_LABEL ? $conf->global->PROPAL_STATUS_NOTSIGNEDSHORT_LABEL : $langs->trans("PropalStatusNotSignedShort"));
  127. $this->labelstatut_short[4]=($conf->global->PROPAL_STATUS_BILLEDSHORT_LABEL ? $conf->global->PROPAL_STATUS_BILLEDSHORT_LABEL : $langs->trans("PropalStatusBilledShort"));
  128. }
  129. /**
  130. * Add line into array products
  131. * $this->client doit etre charge
  132. * @param idproduct Id du produit a ajouter
  133. * @param qty Quantity
  134. * @param remise_percent Remise relative effectuee sur le produit
  135. * TODO Remplacer les appels a cette fonction par generation objet Ligne
  136. * insere dans tableau $this->products
  137. */
  138. function add_product($idproduct, $qty, $remise_percent=0)
  139. {
  140. global $conf, $mysoc;
  141. if (! $qty) $qty = 1;
  142. dol_syslog("Propal::add_product $idproduct, $qty, $remise_percent");
  143. if ($idproduct > 0)
  144. {
  145. $prod=new Product($this->db);
  146. $prod->fetch($idproduct);
  147. $productdesc = $prod->description;
  148. $tva_tx = get_default_tva($mysoc,$this->client,$prod->id);
  149. // local taxes
  150. $localtax1_tx = get_default_localtax($mysoc,$this->client,1,$prod->tva_tx);
  151. $localtax2_tx = get_default_localtax($mysoc,$this->client,2,$prod->tva_tx);
  152. // multiprix
  153. if($conf->global->PRODUIT_MULTIPRICES && $this->client->price_level)
  154. {
  155. $price = $prod->multiprices[$this->client->price_level];
  156. }
  157. else
  158. {
  159. $price = $prod->price;
  160. }
  161. $line = new PropaleLigne($this->db);
  162. $line->fk_product=$idproduct;
  163. $line->desc=$productdesc;
  164. $line->qty=$qty;
  165. $line->subprice=$price;
  166. $line->remise_percent=$remise_percent;
  167. $line->tva_tx=$tva_tx;
  168. $this->products[]=$line;
  169. }
  170. }
  171. /**
  172. * \brief Ajout d'une ligne remise fixe dans la proposition, en base
  173. * \param idremise Id de la remise fixe
  174. * \return int >0 si ok, <0 si ko
  175. */
  176. function insert_discount($idremise)
  177. {
  178. global $langs;
  179. include_once(DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php');
  180. include_once(DOL_DOCUMENT_ROOT.'/core/class/discount.class.php');
  181. $this->db->begin();
  182. $remise=new DiscountAbsolute($this->db);
  183. $result=$remise->fetch($idremise);
  184. if ($result > 0)
  185. {
  186. if ($remise->fk_facture) // Protection against multiple submission
  187. {
  188. $this->error=$langs->trans("ErrorDiscountAlreadyUsed");
  189. $this->db->rollback();
  190. return -5;
  191. }
  192. $propalligne=new PropaleLigne($this->db);
  193. $propalligne->fk_propal=$this->id;
  194. $propalligne->fk_remise_except=$remise->id;
  195. $propalligne->desc=$remise->description; // Description ligne
  196. $propalligne->tva_tx=$remise->tva_tx;
  197. $propalligne->subprice=-$remise->amount_ht;
  198. $propalligne->fk_product=0; // Id produit predefini
  199. $propalligne->qty=1;
  200. $propalligne->remise=0;
  201. $propalligne->remise_percent=0;
  202. $propalligne->rang=-1;
  203. $propalligne->info_bits=2;
  204. // TODO deprecated
  205. $propalligne->price=-$remise->amount_ht;
  206. $propalligne->total_ht = -$remise->amount_ht;
  207. $propalligne->total_tva = -$remise->amount_tva;
  208. $propalligne->total_ttc = -$remise->amount_ttc;
  209. $result=$propalligne->insert();
  210. if ($result > 0)
  211. {
  212. $result=$this->update_price(1);
  213. if ($result > 0)
  214. {
  215. $this->db->commit();
  216. return 1;
  217. }
  218. else
  219. {
  220. $this->db->rollback();
  221. return -1;
  222. }
  223. }
  224. else
  225. {
  226. $this->error=$propalligne->error;
  227. $this->db->rollback();
  228. return -2;
  229. }
  230. }
  231. else
  232. {
  233. $this->db->rollback();
  234. return -2;
  235. }
  236. }
  237. /**
  238. * Add a proposal line into database (linked to product/service or not)
  239. * Les parametres sont deja cense etre juste et avec valeurs finales a l'appel
  240. * de cette methode. Aussi, pour le taux tva, il doit deja avoir ete defini
  241. * par l'appelant par la methode get_default_tva(societe_vendeuse,societe_acheteuse,'',produit)
  242. * et le desc doit deja avoir la bonne valeur (a l'appelant de gerer le multilangue)
  243. *
  244. * @param propalid Id de la propale
  245. * @param desc Description de la ligne
  246. * @param pu_ht Prix unitaire
  247. * @param qty Quantite
  248. * @param txtva Taux de tva
  249. * @param txlocaltax1 Local tax 1 rate
  250. * @param txlocaltax2 Local tax 2 rate
  251. * @param fk_product Id du produit/service predefini
  252. * @param remise_percent Pourcentage de remise de la ligne
  253. * @param price_base_type HT or TTC
  254. * @param pu_ttc Prix unitaire TTC
  255. * @param info_bits Bits de type de lignes
  256. * @param type Type of line (product, service)
  257. * @param rang Position of line
  258. * @param special_code Special code
  259. * @param fk_parent_line Id of parent line
  260. * @return int >0 if OK, <0 if KO
  261. * @see add_product
  262. */
  263. function addline($propalid, $desc, $pu_ht, $qty, $txtva, $txlocaltax1=0, $txlocaltax2=0, $fk_product=0, $remise_percent=0, $price_base_type='HT', $pu_ttc=0, $info_bits=0, $type=0, $rang=-1, $special_code=0, $fk_parent_line=0)
  264. {
  265. global $conf;
  266. dol_syslog("Propal::Addline propalid=$propalid, desc=$desc, pu_ht=$pu_ht, qty=$qty, txtva=$txtva, fk_product=$fk_product, remise_except=$remise_percent, price_base_type=$price_base_type, pu_ttc=$pu_ttc, info_bits=$info_bits, type=$type");
  267. include_once(DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php');
  268. // Clean parameters
  269. if (empty($remise_percent)) $remise_percent=0;
  270. if (empty($qty)) $qty=0;
  271. if (empty($info_bits)) $info_bits=0;
  272. if (empty($rang)) $rang=0;
  273. if (empty($fk_parent_line) || $fk_parent_line < 0) $fk_parent_line=0;
  274. $remise_percent=price2num($remise_percent);
  275. $qty=price2num($qty);
  276. $pu_ht=price2num($pu_ht);
  277. $pu_ttc=price2num($pu_ttc);
  278. $txtva=price2num($txtva);
  279. $txlocaltax1=price2num($txlocaltax1);
  280. $txlocaltax2=price2num($txlocaltax2);
  281. if ($price_base_type=='HT')
  282. {
  283. $pu=$pu_ht;
  284. }
  285. else
  286. {
  287. $pu=$pu_ttc;
  288. }
  289. // Check parameters
  290. if ($type < 0) return -1;
  291. if ($this->statut == 0)
  292. {
  293. $this->db->begin();
  294. // Calcul du total TTC et de la TVA pour la ligne a partir de
  295. // qty, pu, remise_percent et txtva
  296. // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
  297. // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
  298. $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits);
  299. $total_ht = $tabprice[0];
  300. $total_tva = $tabprice[1];
  301. $total_ttc = $tabprice[2];
  302. $total_localtax1 = $tabprice[9];
  303. $total_localtax2 = $tabprice[10];
  304. // Rang to use
  305. $rangtouse = $rang;
  306. if ($rangtouse == -1)
  307. {
  308. $rangmax = $this->line_max($fk_parent_line);
  309. $rangtouse = $rangmax + 1;
  310. }
  311. // TODO A virer
  312. // Anciens indicateurs: $price, $remise (a ne plus utiliser)
  313. $price = $pu;
  314. $remise = 0;
  315. if ($remise_percent > 0)
  316. {
  317. $remise = round(($pu * $remise_percent / 100), 2);
  318. $price = $pu - $remise;
  319. }
  320. // Insert line
  321. $this->line=new PropaleLigne($this->db);
  322. $this->line->fk_propal=$propalid;
  323. $this->line->desc=$desc;
  324. $this->line->qty=$qty;
  325. $this->line->tva_tx=$txtva;
  326. $this->line->localtax1_tx=$txlocaltax1;
  327. $this->line->localtax2_tx=$txlocaltax2;
  328. $this->line->fk_product=$fk_product;
  329. $this->line->remise_percent=$remise_percent;
  330. $this->line->subprice=$pu_ht;
  331. $this->line->rang=$rangtouse;
  332. $this->line->info_bits=$info_bits;
  333. $this->line->fk_remise_except=$fk_remise_except;
  334. $this->line->total_ht=$total_ht;
  335. $this->line->total_tva=$total_tva;
  336. $this->line->total_localtax1=$total_localtax1;
  337. $this->line->total_localtax2=$total_localtax2;
  338. $this->line->total_ttc=$total_ttc;
  339. $this->line->product_type=$type;
  340. $this->line->special_code=$special_code;
  341. $this->line->fk_parent_line=$fk_parent_line;
  342. // Mise en option de la ligne
  343. //if ($conf->global->PROPALE_USE_OPTION_LINE && !$qty) $ligne->special_code=3;
  344. if (empty($qty) && empty($special_code)) $this->line->special_code=3;
  345. // TODO deprecated
  346. $this->line->price=$price;
  347. $this->line->remise=$remise;
  348. $result=$this->line->insert();
  349. if ($result > 0)
  350. {
  351. // Reorder if child line
  352. if (! empty($fk_parent_line)) $this->line_order(true,'DESC');
  353. // Mise a jour informations denormalisees au niveau de la propale meme
  354. $result=$this->update_price(1);
  355. if ($result > 0)
  356. {
  357. $this->db->commit();
  358. return $this->line->rowid;
  359. }
  360. else
  361. {
  362. $this->error=$this->db->error();
  363. dol_syslog("Error sql=$sql, error=".$this->error,LOG_ERR);
  364. $this->db->rollback();
  365. return -1;
  366. }
  367. }
  368. else
  369. {
  370. $this->error=$this->line->error;
  371. $this->db->rollback();
  372. return -2;
  373. }
  374. }
  375. }
  376. /**
  377. * Update a proposal line
  378. *
  379. * @param rowid Id de la ligne
  380. * @param pu Prix unitaire (HT ou TTC selon price_base_type)
  381. * @param qty Quantity
  382. * @param remise_percent Remise effectuee sur le produit
  383. * @param txtva Taux de TVA
  384. * @param txlocaltax1 Local tax 1 rate
  385. * @param txlocaltax2 Local tax 2 rate
  386. * @param desc Description
  387. * @param price_base_type HT ou TTC
  388. * @param info_bits Miscellanous informations
  389. * @param special_code Set special code ('' = we don't change it)
  390. * @param fk_parent_line Id of line parent
  391. * @param skip_update_total Skip update total
  392. * @return int 0 if OK, <0 if KO
  393. */
  394. function updateline($rowid, $pu, $qty, $remise_percent=0, $txtva, $txlocaltax1=0, $txlocaltax2=0, $desc='', $price_base_type='HT', $info_bits=0, $special_code=0, $fk_parent_line=0, $skip_update_total=0)
  395. {
  396. global $conf,$user,$langs;
  397. dol_syslog("Propal::UpdateLine $rowid, $pu, $qty, $remise_percent, $txtva, $desc, $price_base_type, $info_bits");
  398. include_once(DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php');
  399. // Clean parameters
  400. $remise_percent=price2num($remise_percent);
  401. $qty=price2num($qty);
  402. $pu = price2num($pu);
  403. $txtva = price2num($txtva);
  404. $txlocaltax1=price2num($txlocaltax1);
  405. $txlocaltax2=price2num($txlocaltax2);
  406. if (empty($qty) && empty($special_code)) $special_code=3; // Set option tag
  407. if (! empty($qty) && $special_code == 3) $special_code=0; // Remove option tag
  408. if ($this->statut == 0)
  409. {
  410. $this->db->begin();
  411. // Calcul du total TTC et de la TVA pour la ligne a partir de
  412. // qty, pu, remise_percent et txtva
  413. // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
  414. // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
  415. $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits);
  416. $total_ht = $tabprice[0];
  417. $total_tva = $tabprice[1];
  418. $total_ttc = $tabprice[2];
  419. $total_localtax1 = $tabprice[9];
  420. $total_localtax2 = $tabprice[10];
  421. // Anciens indicateurs: $price, $remise (a ne plus utiliser)
  422. $price = $pu;
  423. if ($remise_percent > 0)
  424. {
  425. $remise = round(($pu * $remise_percent / 100), 2);
  426. $price = $pu - $remise;
  427. }
  428. // Update line
  429. $this->line=new PropaleLigne($this->db);
  430. // Stock previous line records
  431. $staticline=new PropaleLigne($this->db);
  432. $staticline->fetch($rowid);
  433. $this->line->oldline = $staticline;
  434. // Reorder if fk_parent_line change
  435. if (! empty($fk_parent_line) && ! empty($staticline->fk_parent_line) && $fk_parent_line != $staticline->fk_parent_line)
  436. {
  437. $rangmax = $this->line_max($fk_parent_line);
  438. $this->line->rang = $rangmax + 1;
  439. }
  440. $this->line->rowid = $rowid;
  441. $this->line->desc = $desc;
  442. $this->line->qty = $qty;
  443. $this->line->tva_tx = $txtva;
  444. $this->line->localtax1_tx = $txlocaltax1;
  445. $this->line->localtax2_tx = $txlocaltax2;
  446. $this->line->remise_percent = $remise_percent;
  447. $this->line->subprice = $pu;
  448. $this->line->info_bits = $info_bits;
  449. $this->line->total_ht = $total_ht;
  450. $this->line->total_tva = $total_tva;
  451. $this->line->total_localtax1 = $total_localtax1;
  452. $this->line->total_localtax2 = $total_localtax2;
  453. $this->line->total_ttc = $total_ttc;
  454. $this->line->special_code = $special_code;
  455. $this->line->fk_parent_line = $fk_parent_line;
  456. $this->line->skip_update_total = $skip_update_total;
  457. // TODO deprecated
  458. $this->line->price=$price;
  459. $this->line->remise=$remise;
  460. $result=$this->line->update();
  461. if ($result > 0)
  462. {
  463. // Reorder if child line
  464. if (! empty($fk_parent_line)) $this->line_order(true,'DESC');
  465. $this->update_price(1);
  466. $this->fk_propal = $this->id;
  467. $this->rowid = $rowid;
  468. $this->db->commit();
  469. return $result;
  470. }
  471. else
  472. {
  473. $this->error=$this->db->error();
  474. $this->db->rollback();
  475. dol_syslog("Propal::UpdateLine Error=".$this->error, LOG_ERR);
  476. return -1;
  477. }
  478. }
  479. else
  480. {
  481. dol_syslog("Propal::UpdateLigne Erreur -2 Propal en mode incompatible pour cette action");
  482. return -2;
  483. }
  484. }
  485. /**
  486. * Supprime une ligne de detail
  487. *
  488. * @param int $lineid Id of line to delete
  489. * @return int >0 if OK, <0 if KO
  490. */
  491. function deleteline($lineid)
  492. {
  493. if ($this->statut == 0)
  494. {
  495. $line=new PropaleLigne($this->db);
  496. // For triggers
  497. $line->fetch($lineid);
  498. if ($line->delete() > 0)
  499. {
  500. $this->update_price(1);
  501. return 1;
  502. }
  503. else
  504. {
  505. return -1;
  506. }
  507. }
  508. else
  509. {
  510. return -2;
  511. }
  512. }
  513. /**
  514. * Create commercial proposal into database
  515. * this->ref can be set or empty. If empty, we will use "(PROVid)"
  516. *
  517. * @param User $user User that create
  518. * @param int $notrigger Disable trigger
  519. * @return int <0 if KO, >=0 if OK
  520. */
  521. function create($user='', $notrigger=0)
  522. {
  523. global $langs,$conf,$mysoc;
  524. $error=0;
  525. $now=dol_now();
  526. // Clean parameters
  527. $this->fin_validite = $this->datep + ($this->duree_validite * 24 * 3600);
  528. if (empty($this->availability_id)) $this->availability_id=0;
  529. if (empty($this->demand_reason_id)) $this->demand_reason_id=0;
  530. dol_syslog("Propal::Create");
  531. // Check parameters
  532. $soc = new Societe($this->db);
  533. $result=$soc->fetch($this->socid);
  534. if ($result < 0)
  535. {
  536. $this->error="Failed to fetch company";
  537. dol_syslog("Propal::create ".$this->error, LOG_ERR);
  538. return -3;
  539. }
  540. if (! empty($this->ref))
  541. {
  542. $result=$this->verifyNumRef(); // Check ref is not yet used
  543. }
  544. $this->db->begin();
  545. $this->fetch_thirdparty();
  546. // Insert into database
  547. $sql = "INSERT INTO ".MAIN_DB_PREFIX."propal (";
  548. $sql.= "fk_soc";
  549. $sql.= ", price";
  550. $sql.= ", remise";
  551. $sql.= ", remise_percent";
  552. $sql.= ", remise_absolue";
  553. $sql.= ", tva";
  554. $sql.= ", total";
  555. $sql.= ", datep";
  556. $sql.= ", datec";
  557. $sql.= ", ref";
  558. $sql.= ", fk_user_author";
  559. $sql.= ", note";
  560. $sql.= ", note_public";
  561. $sql.= ", model_pdf";
  562. $sql.= ", fin_validite";
  563. $sql.= ", fk_cond_reglement";
  564. $sql.= ", fk_mode_reglement";
  565. $sql.= ", ref_client";
  566. $sql.= ", date_livraison";
  567. $sql.= ", fk_availability";
  568. $sql.= ", fk_demand_reason";
  569. $sql.= ", entity";
  570. $sql.= ") ";
  571. $sql.= " VALUES (";
  572. $sql.= $this->socid;
  573. $sql.= ", 0";
  574. $sql.= ", ".$this->remise;
  575. $sql.= ", ".($this->remise_percent?$this->remise_percent:'null');
  576. $sql.= ", ".($this->remise_absolue?$this->remise_absolue:'null');
  577. $sql.= ", 0";
  578. $sql.= ", 0";
  579. $sql.= ", '".$this->db->idate($this->datep)."'";
  580. $sql.= ", '".$this->db->idate($now)."'";
  581. $sql.= ", '(PROV)'";
  582. $sql.= ", ".($user->id > 0 ? "'".$user->id."'":"null");
  583. $sql.= ", '".$this->db->escape($this->note)."'";
  584. $sql.= ", '".$this->db->escape($this->note_public)."'";
  585. $sql.= ", '".$this->modelpdf."'";
  586. $sql.= ", '".$this->db->idate($this->fin_validite)."'";
  587. $sql.= ", ".$this->cond_reglement_id;
  588. $sql.= ", ".$this->mode_reglement_id;
  589. $sql.= ", '".$this->db->escape($this->ref_client)."'";
  590. $sql.= ", ".($this->date_livraison!=''?"'".$this->db->idate($this->date_livraison)."'":'null');
  591. $sql.= ", ".$this->availability_id;
  592. $sql.= ", ".$this->demand_reason_id;
  593. $sql.= ", ".$conf->entity;
  594. $sql.= ")";
  595. dol_syslog("Propal::create sql=".$sql, LOG_DEBUG);
  596. $resql=$this->db->query($sql);
  597. if ($resql)
  598. {
  599. $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."propal");
  600. if ($this->id)
  601. {
  602. if (empty($this->ref)) $this->ref='(PROV'.$this->id.')';
  603. $sql = 'UPDATE '.MAIN_DB_PREFIX."propal SET ref='".$this->ref."' WHERE rowid=".$this->id;
  604. dol_syslog("Propal::create sql=".$sql);
  605. $resql=$this->db->query($sql);
  606. if (! $resql) $error++;
  607. /*
  608. * Insertion du detail des produits dans la base
  609. */
  610. if (! $error)
  611. {
  612. $fk_parent_line=0;
  613. $num=count($this->lines);
  614. for ($i=0;$i<$num;$i++)
  615. {
  616. // Reset fk_parent_line for no child products and special product
  617. if (($this->lines[$i]->product_type != 9 && empty($this->lines[$i]->fk_parent_line)) || $this->lines[$i]->product_type == 9) {
  618. $fk_parent_line = 0;
  619. }
  620. $result = $this->addline(
  621. $this->id,
  622. $this->lines[$i]->desc,
  623. $this->lines[$i]->subprice,
  624. $this->lines[$i]->qty,
  625. $this->lines[$i]->tva_tx,
  626. $this->lines[$i]->localtax1_tx,
  627. $this->lines[$i]->localtax2_tx,
  628. $this->lines[$i]->fk_product,
  629. $this->lines[$i]->remise_percent,
  630. 'HT',
  631. 0,
  632. 0,
  633. $this->lines[$i]->product_type,
  634. $this->lines[$i]->rang,
  635. $this->lines[$i]->special_code,
  636. $fk_parent_line
  637. );
  638. if ($result < 0)
  639. {
  640. $error++;
  641. $this->error=$this->db->error;
  642. dol_print_error($this->db);
  643. break;
  644. }
  645. // Defined the new fk_parent_line
  646. if ($result > 0 && $this->lines[$i]->product_type == 9) {
  647. $fk_parent_line = $result;
  648. }
  649. }
  650. }
  651. // Add linked object
  652. if (! $error && $this->origin && $this->origin_id)
  653. {
  654. $ret = $this->add_object_linked();
  655. if (! $ret) dol_print_error($this->db);
  656. }
  657. // Affectation au projet
  658. if (! $error && $this->fk_project)
  659. {
  660. $sql = "UPDATE ".MAIN_DB_PREFIX."propal";
  661. $sql.= " SET fk_projet=".$this->fk_project;
  662. $sql.= " WHERE ref='".$this->ref."'";
  663. $sql.= " AND entity = ".$conf->entity;
  664. $result=$this->db->query($sql);
  665. }
  666. // Set delivery address
  667. if (! $error && $this->fk_delivery_address)
  668. {
  669. $sql = "UPDATE ".MAIN_DB_PREFIX."propal";
  670. $sql.= " SET fk_adresse_livraison = ".$this->fk_delivery_address;
  671. $sql.= " WHERE ref = '".$this->ref."'";
  672. $sql.= " AND entity = ".$conf->entity;
  673. $result=$this->db->query($sql);
  674. }
  675. if (! $error)
  676. {
  677. // Mise a jour infos denormalisees
  678. $resql=$this->update_price(1);
  679. if ($resql)
  680. {
  681. if (! $notrigger)
  682. {
  683. // Appel des triggers
  684. include_once(DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php");
  685. $interface=new Interfaces($this->db);
  686. $result=$interface->run_triggers('PROPAL_CREATE',$this,$user,$langs,$conf);
  687. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  688. // Fin appel triggers
  689. }
  690. }
  691. else
  692. {
  693. $error++;
  694. }
  695. }
  696. }
  697. else
  698. {
  699. $error++;
  700. }
  701. if (! $error)
  702. {
  703. $this->db->commit();
  704. dol_syslog("Propal::Create done id=".$this->id);
  705. return $this->id;
  706. }
  707. else
  708. {
  709. $this->error=$this->db->error();
  710. dol_syslog("Propal::Create -2 ".$this->error, LOG_ERR);
  711. $this->db->rollback();
  712. return -2;
  713. }
  714. }
  715. else
  716. {
  717. $this->error=$this->db->error();
  718. dol_syslog("Propal::Create -1 ".$this->error, LOG_ERR);
  719. $this->db->rollback();
  720. return -1;
  721. }
  722. }
  723. /**
  724. * \brief Insert en base un objet propal completement definie par ses donnees membres (resultant d'une copie par exemple).
  725. * \return int l'id du nouvel objet propal en base si ok, <0 si ko
  726. * \see create
  727. */
  728. function create_from($user)
  729. {
  730. $this->products=$this->lines;
  731. return $this->create();
  732. }
  733. /**
  734. * Load an object from its id and create a new one in database
  735. *
  736. * @param int $fromid Id of object to clone
  737. * @param int $invertdetail Reverse sign of amounts for lines
  738. * @param int $socid Id of thirdparty
  739. * @param HookManager $hookmanager Hook manager instance
  740. * @return int New id of clone
  741. */
  742. function createFromClone($fromid,$invertdetail=0,$socid=0,$hookmanager=false)
  743. {
  744. global $user,$langs,$conf;
  745. $error=0;
  746. $now=dol_now();
  747. $object=new Propal($this->db);
  748. $this->db->begin();
  749. // Load source object
  750. $object->fetch($fromid);
  751. $objFrom = $object;
  752. $objsoc=new Societe($this->db);
  753. // Change socid if needed
  754. if (! empty($socid) && $socid != $object->socid)
  755. {
  756. if ($objsoc->fetch($socid)>0)
  757. {
  758. $object->socid = $objsoc->id;
  759. $object->cond_reglement_id = (! empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0);
  760. $object->mode_reglement_id = (! empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0);
  761. $object->fk_project = '';
  762. $object->fk_delivery_address = '';
  763. }
  764. // TODO Change product price if multi-prices
  765. }
  766. else
  767. {
  768. $objsoc->fetch($object->socid);
  769. }
  770. $object->id=0;
  771. $object->statut=0;
  772. $objsoc->fetch($object->socid);
  773. if (empty($conf->global->PROPALE_ADDON) || ! is_readable(DOL_DOCUMENT_ROOT ."/core/modules/propale/".$conf->global->PROPALE_ADDON.".php"))
  774. {
  775. $this->error='ErrorSetupNotComplete';
  776. return -1;
  777. }
  778. // Clear fields
  779. $object->user_author = $user->id;
  780. $object->user_valid = '';
  781. $object->date = '';
  782. $object->datep = $now;
  783. $object->fin_validite = $object->datep + ($this->duree_validite * 24 * 3600);
  784. $object->ref_client = '';
  785. // Set ref
  786. require_once(DOL_DOCUMENT_ROOT ."/core/modules/propale/".$conf->global->PROPALE_ADDON.".php");
  787. $obj = $conf->global->PROPALE_ADDON;
  788. $modPropale = new $obj;
  789. $object->ref = $modPropale->getNextValue($objsoc,$object);
  790. // Create clone
  791. $result=$object->create($user);
  792. // Other options
  793. if ($result < 0)
  794. {
  795. $this->error=$object->error;
  796. $error++;
  797. }
  798. if (! $error)
  799. {
  800. // Hook of thirdparty module
  801. if (is_object($hookmanager))
  802. {
  803. $parameters=array('objFrom'=>$objFrom);
  804. $action='';
  805. $reshook=$hookmanager->executeHooks('createfrom',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks
  806. if ($reshook < 0) $error++;
  807. }
  808. // Appel des triggers
  809. include_once(DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php");
  810. $interface=new Interfaces($this->db);
  811. $result=$interface->run_triggers('PROPAL_CLONE',$object,$user,$langs,$conf);
  812. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  813. // Fin appel triggers
  814. }
  815. // End
  816. if (! $error)
  817. {
  818. $this->db->commit();
  819. return $object->id;
  820. }
  821. else
  822. {
  823. $this->db->rollback();
  824. return -1;
  825. }
  826. }
  827. /**
  828. * \brief Load a proposal from database and its ligne array
  829. * \param rowid id of object to load
  830. * \param ref Ref of proposal
  831. * \return int >0 if OK, <0 if KO
  832. */
  833. function fetch($rowid,$ref='')
  834. {
  835. global $conf;
  836. $sql = "SELECT p.rowid,ref,remise,remise_percent,remise_absolue,fk_soc";
  837. $sql.= ", total, tva, localtax1, localtax2, total_ht";
  838. $sql.= ", datec";
  839. $sql.= ", date_valid as datev";
  840. $sql.= ", datep as dp";
  841. $sql.= ", fin_validite as dfv";
  842. $sql.= ", date_livraison as date_livraison";
  843. $sql.= ", ca.code as availability_code, ca.label as availability";
  844. $sql.= ", dr.code as demand_reason_code, dr.label as demand_reason";
  845. $sql.= ", model_pdf, ref_client";
  846. $sql.= ", note, note_public";
  847. $sql.= ", fk_projet, fk_statut";
  848. $sql.= ", fk_user_author, fk_user_valid, fk_user_cloture";
  849. $sql.= ", fk_adresse_livraison";
  850. $sql.= ", p.fk_availability";
  851. $sql.= ", p.fk_demand_reason";
  852. $sql.= ", p.fk_cond_reglement";
  853. $sql.= ", p.fk_mode_reglement";
  854. $sql.= ", c.label as statut_label";
  855. $sql.= ", cr.code as cond_reglement_code, cr.libelle as cond_reglement, cr.libelle_facture as cond_reglement_libelle_doc";
  856. $sql.= ", cp.code as mode_reglement_code, cp.libelle as mode_reglement";
  857. $sql.= " FROM ".MAIN_DB_PREFIX."c_propalst as c, ".MAIN_DB_PREFIX."propal as p";
  858. $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as cp ON p.fk_mode_reglement = cp.id';
  859. $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as cr ON p.fk_cond_reglement = cr.rowid';
  860. $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_availability as ca ON p.fk_availability = ca.rowid';
  861. $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_input_reason as dr ON p.fk_demand_reason = dr.rowid';
  862. $sql.= " WHERE p.fk_statut = c.id";
  863. $sql.= " AND p.entity = ".$conf->entity;
  864. if ($ref) $sql.= " AND p.ref='".$ref."'";
  865. else $sql.= " AND p.rowid=".$rowid;
  866. dol_syslog("Propal::fecth sql=".$sql, LOG_DEBUG);
  867. $resql=$this->db->query($sql);
  868. if ($resql)
  869. {
  870. if ($this->db->num_rows($resql))
  871. {
  872. $obj = $this->db->fetch_object($resql);
  873. $this->id = $obj->rowid;
  874. $this->ref = $obj->ref;
  875. $this->ref_client = $obj->ref_client;
  876. $this->remise = $obj->remise;
  877. $this->remise_percent = $obj->remise_percent;
  878. $this->remise_absolue = $obj->remise_absolue;
  879. $this->total = $obj->total; // TODO obsolete
  880. $this->total_ht = $obj->total_ht;
  881. $this->total_tva = $obj->tva;
  882. $this->total_localtax1 = $obj->localtax1;
  883. $this->total_localtax2 = $obj->localtax2;
  884. $this->total_ttc = $obj->total;
  885. $this->socid = $obj->fk_soc;
  886. $this->fk_project = $obj->fk_projet;
  887. $this->modelpdf = $obj->model_pdf;
  888. $this->note = $obj->note;
  889. $this->note_public = $obj->note_public;
  890. $this->statut = $obj->fk_statut;
  891. $this->statut_libelle = $obj->statut_label;
  892. $this->datec = $this->db->jdate($obj->datec);
  893. $this->datev = $this->db->jdate($obj->datev);
  894. $this->date = $this->db->jdate($obj->dp); // Proposal date
  895. $this->datep = $this->db->jdate($obj->dp);
  896. $this->fin_validite = $this->db->jdate($obj->dfv);
  897. $this->date_livraison = $this->db->jdate($obj->date_livraison);
  898. $this->availability_id = $obj->fk_availability;
  899. $this->availability_code = $obj->availability_code;
  900. $this->availability = $obj->availability;
  901. $this->demand_reason_id = $obj->fk_demand_reason;
  902. $this->demand_reason_code = $obj->demand_reason_code;
  903. $this->demand_reason = $obj->demand_reason;
  904. $this->fk_delivery_address = $obj->fk_adresse_livraison; // TODO obsolete
  905. $this->fk_address = $obj->fk_adresse_livraison;
  906. $this->mode_reglement_id = $obj->fk_mode_reglement;
  907. $this->mode_reglement_code = $obj->mode_reglement_code;
  908. $this->mode_reglement = $obj->mode_reglement;
  909. $this->cond_reglement_id = $obj->fk_cond_reglement;
  910. $this->cond_reglement_code = $obj->cond_reglement_code;
  911. $this->cond_reglement = $obj->cond_reglement;
  912. $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc;
  913. $this->user_author_id = $obj->fk_user_author;
  914. $this->user_valid_id = $obj->fk_user_valid;
  915. $this->user_close_id = $obj->fk_user_cloture;
  916. if ($obj->fk_statut == 0)
  917. {
  918. $this->brouillon = 1;
  919. }
  920. $this->db->free($resql);
  921. $this->lines = array();
  922. /*
  923. * Lignes propales liees a un produit ou non
  924. */
  925. $sql = "SELECT d.rowid, d.fk_propal, d.fk_parent_line, d.description, d.price, d.tva_tx, d.localtax1_tx, d.localtax2_tx, d.qty, d.fk_remise_except, d.remise_percent, d.subprice, d.fk_product,";
  926. $sql.= " d.info_bits, d.total_ht, d.total_tva, d.total_localtax1, d.total_localtax2, d.total_ttc, d.marge_tx, d.marque_tx, d.special_code, d.rang, d.product_type,";
  927. $sql.= ' p.ref as product_ref, p.description as product_desc, p.fk_product_type, p.label as product_label';
  928. $sql.= " FROM ".MAIN_DB_PREFIX."propaldet as d";
  929. $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON d.fk_product = p.rowid";
  930. $sql.= " WHERE d.fk_propal = ".$this->id;
  931. $sql.= " ORDER by d.rang";
  932. $result = $this->db->query($sql);
  933. if ($result)
  934. {
  935. $num = $this->db->num_rows($result);
  936. $i = 0;
  937. while ($i < $num)
  938. {
  939. $objp = $this->db->fetch_object($result);
  940. $line = new PropaleLigne($this->db);
  941. $line->rowid = $objp->rowid;
  942. $line->fk_propal = $objp->fk_propal;
  943. $line->fk_parent_line = $objp->fk_parent_line;
  944. $line->product_type = $objp->product_type;
  945. $line->desc = $objp->description; // Description ligne
  946. $line->qty = $objp->qty;
  947. $line->tva_tx = $objp->tva_tx;
  948. $line->localtax1_tx = $objp->localtax1_tx;
  949. $line->localtax2_tx = $objp->localtax2_tx;
  950. $line->subprice = $objp->subprice;
  951. $line->fk_remise_except = $objp->fk_remise_except;
  952. $line->remise_percent = $objp->remise_percent;
  953. $line->price = $objp->price; // TODO deprecated
  954. $line->info_bits = $objp->info_bits;
  955. $line->total_ht = $objp->total_ht;
  956. $line->total_tva = $objp->total_tva;
  957. $line->total_localtax1 = $objp->total_localtax1;
  958. $line->total_localtax2 = $objp->total_localtax2;
  959. $line->total_ttc = $objp->total_ttc;
  960. $line->marge_tx = $objp->marge_tx;
  961. $line->marque_tx = $objp->marque_tx;
  962. $line->special_code = $objp->special_code;
  963. $line->rang = $objp->rang;
  964. $line->fk_product = $objp->fk_product;
  965. $line->ref = $objp->product_ref; // TODO deprecated
  966. $line->product_ref = $objp->product_ref;
  967. $line->libelle = $objp->product_label; // TODO deprecated
  968. $line->label = $objp->product_label; // TODO deprecated
  969. $line->product_label = $objp->product_label;
  970. $line->product_desc = $objp->product_desc; // Description produit
  971. $line->fk_product_type = $objp->fk_product_type;
  972. $this->lines[$i] = $line;
  973. //dol_syslog("1 ".$line->fk_product);
  974. //print "xx $i ".$this->lines[$i]->fk_product;
  975. $i++;
  976. }
  977. $this->db->free($result);
  978. }
  979. else
  980. {
  981. $this->error=$this->db->error();
  982. dol_syslog("Propal::Fetch Error ".$this->error, LOG_ERR);
  983. return -1;
  984. }
  985. return 1;
  986. }
  987. $this->error="Record Not Found";
  988. return 0;
  989. }
  990. else
  991. {
  992. $this->error=$this->db->error();
  993. dol_syslog("Propal::Fetch Error ".$this->error, LOG_ERR);
  994. return -1;
  995. }
  996. }
  997. /**
  998. * Set status to validated
  999. *
  1000. * @param User $user Object user that validate
  1001. * @return int <0 if KO, >=0 if OK
  1002. */
  1003. function valid($user, $notrigger=0)
  1004. {
  1005. global $conf,$langs;
  1006. $now=dol_now();
  1007. if ($user->rights->propale->valider)
  1008. {
  1009. $this->db->begin();
  1010. $sql = "UPDATE ".MAIN_DB_PREFIX."propal";
  1011. $sql.= " SET fk_statut = 1, date_valid='".$this->db->idate($now)."', fk_user_valid=".$user->id;
  1012. $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
  1013. dol_syslog(get_class($this).'::valid sql='.$sql);
  1014. if ($this->db->query($sql))
  1015. {
  1016. if (! $notrigger)
  1017. {
  1018. // Appel des triggers
  1019. include_once(DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php");
  1020. $interface=new Interfaces($this->db);
  1021. $result=$interface->run_triggers('PROPAL_VALIDATE',$this,$user,$langs,$conf);
  1022. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  1023. // Fin appel triggers
  1024. }
  1025. if (! $error)
  1026. {
  1027. $this->brouillon=0;
  1028. $this->statut = 1;
  1029. $this->user_valid_id=$user->id;
  1030. $this->datev=$now;
  1031. $this->db->commit();
  1032. return 1;
  1033. }
  1034. else
  1035. {
  1036. $this->db->rollback();
  1037. return -2;
  1038. }
  1039. }
  1040. else
  1041. {
  1042. $this->db->rollback();
  1043. return -1;
  1044. }
  1045. }
  1046. }
  1047. /**
  1048. * Define proposal date
  1049. *
  1050. * @param User $user Object user that modify
  1051. * @param timestamp $date Date
  1052. * @return int <0 if KO, >0 if OK
  1053. */
  1054. function set_date($user, $date)
  1055. {
  1056. if ($user->rights->propale->creer)
  1057. {
  1058. $sql = "UPDATE ".MAIN_DB_PREFIX."propal SET datep = ".$this->db->idate($date);
  1059. $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
  1060. dol_syslog(get_class($this)."::set_date sql=".$sql);
  1061. if ($this->db->query($sql) )
  1062. {
  1063. $this->date = $date;
  1064. $this->datep = $date;
  1065. return 1;
  1066. }
  1067. else
  1068. {
  1069. $this->error=$this->db->lasterror();
  1070. dol_syslog(get_class($this)."::set_date ".$this->error, LOG_ERR);
  1071. return -1;
  1072. }
  1073. }
  1074. }
  1075. /**
  1076. * \brief Define end validity date
  1077. * \param user Object user that modify
  1078. * \param date_fin_validite End of validity date
  1079. * \return int <0 if KO, >0 if OK
  1080. */
  1081. function set_echeance($user, $date_fin_validite)
  1082. {
  1083. if ($user->rights->propale->creer)
  1084. {
  1085. $sql = "UPDATE ".MAIN_DB_PREFIX."propal SET fin_validite = ".$this->db->idate($date_fin_validite);
  1086. $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
  1087. if ($this->db->query($sql) )
  1088. {
  1089. $this->fin_validite = $date_fin_validite;
  1090. return 1;
  1091. }
  1092. else
  1093. {
  1094. $this->error=$this->db->error();
  1095. dol_syslog("Propal::set_echeance Erreur SQL".$this->error, LOG_ERR);
  1096. return -1;
  1097. }
  1098. }
  1099. }
  1100. /**
  1101. * \brief Set delivery date
  1102. * \param user Objet utilisateur qui modifie
  1103. * \param date_livraison date de livraison
  1104. * \return int <0 si ko, >0 si ok
  1105. */
  1106. function set_date_livraison($user, $date_livraison)
  1107. {
  1108. if ($user->rights->propale->creer)
  1109. {
  1110. $sql = "UPDATE ".MAIN_DB_PREFIX."propal ";
  1111. $sql.= " SET date_livraison = ".($date_livraison!=''?$this->db->idate($date_livraison):'null');
  1112. $sql.= " WHERE rowid = ".$this->id;
  1113. if ($this->db->query($sql))
  1114. {
  1115. $this->date_livraison = $date_livraison;
  1116. return 1;
  1117. }
  1118. else
  1119. {
  1120. $this->error=$this->db->error();
  1121. dol_syslog("Propal::set_date_livraison Erreur SQL");
  1122. return -1;
  1123. }
  1124. }
  1125. }
  1126. /**
  1127. * \brief Define delivery address
  1128. * \param user Objet utilisateur qui modifie
  1129. * \param fk_address Delivery address id
  1130. * \return int <0 si ko, >0 si ok
  1131. */
  1132. function set_adresse_livraison($user, $fk_address)
  1133. {
  1134. if ($user->rights->propale->creer)
  1135. {
  1136. $sql = "UPDATE ".MAIN_DB_PREFIX."propal SET fk_adresse_livraison = '".$fk_address."'";
  1137. $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
  1138. if ($this->db->query($sql) )
  1139. {
  1140. $this->fk_delivery_address = $fk_address;
  1141. return 1;
  1142. }
  1143. else
  1144. {
  1145. $this->error=$this->db->error();
  1146. dol_syslog("Propal::set_adresse_livraison Erreur SQL");
  1147. return -1;
  1148. }
  1149. }
  1150. }
  1151. /**
  1152. * Set delivery
  1153. *
  1154. * @param User $user Objet utilisateur qui modifie
  1155. * @param int $id Availability id
  1156. * @return int <0 if KO, >0 if OK
  1157. */
  1158. function set_availability($user, $id)
  1159. {
  1160. if ($user->rights->propale->creer)
  1161. {
  1162. $sql = "UPDATE ".MAIN_DB_PREFIX."propal ";
  1163. $sql.= " SET fk_availability = '".$id."'";
  1164. $sql.= " WHERE rowid = ".$this->id;
  1165. if ($this->db->query($sql))
  1166. {
  1167. $this->fk_availability = $id;
  1168. return 1;
  1169. }
  1170. else
  1171. {
  1172. $this->error=$this->db->error();
  1173. dol_syslog("Propal::set_availability Erreur SQL");
  1174. return -1;
  1175. }
  1176. }
  1177. }
  1178. /**
  1179. * Set source of demand
  1180. *
  1181. * @param User $user Objet utilisateur qui modifie
  1182. * @param int $id Input reason id
  1183. * @return int <0 if KO, >0 if OK
  1184. */
  1185. function set_demand_reason($user, $id)
  1186. {
  1187. if ($user->rights->propale->creer)
  1188. {
  1189. $sql = "UPDATE ".MAIN_DB_PREFIX."propal ";
  1190. $sql.= " SET fk_demand_reason = '".$id."'";
  1191. $sql.= " WHERE rowid = ".$this->id;
  1192. if ($this->db->query($sql))
  1193. {
  1194. $this->fk_demand_reason = $id;
  1195. return 1;
  1196. }
  1197. else
  1198. {
  1199. $this->error=$this->db->error();
  1200. dol_syslog("Propal::set_demand_reason Erreur SQL");
  1201. return -1;
  1202. }
  1203. }
  1204. }
  1205. /**
  1206. * Positionne numero reference client
  1207. *
  1208. * @param user Utilisateur qui modifie
  1209. * @param ref_client Reference client
  1210. * @return int <0 si ko, >0 si ok
  1211. */
  1212. function set_ref_client($user, $ref_client)
  1213. {
  1214. if ($user->rights->propale->creer)
  1215. {
  1216. dol_syslog('Propale::set_ref_client this->id='.$this->id.', ref_client='.$ref_client);
  1217. $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal SET ref_client = '.(empty($ref_client) ? 'NULL' : '\''.$this->db->escape($ref_client).'\'');
  1218. $sql.= ' WHERE rowid = '.$this->id;
  1219. if ($this->db->query($sql) )
  1220. {
  1221. $this->ref_client = $ref_client;
  1222. return 1;
  1223. }
  1224. else
  1225. {
  1226. $this->error=$this->db->error();
  1227. dol_syslog('Propale::set_ref_client Erreur '.$this->error.' - '.$sql);
  1228. return -2;
  1229. }
  1230. }
  1231. else
  1232. {
  1233. return -1;
  1234. }
  1235. }
  1236. /**
  1237. * \brief Definit une remise globale relative sur la proposition
  1238. * \param user Objet utilisateur qui modifie
  1239. * \param remise Montant remise
  1240. * \return int <0 si ko, >0 si ok
  1241. */
  1242. function set_remise_percent($user, $remise)
  1243. {
  1244. $remise=trim($remise)?trim($remise):0;
  1245. if ($user->rights->propale->creer)
  1246. {
  1247. $remise = price2num($remise);
  1248. $sql = "UPDATE ".MAIN_DB_PREFIX."propal SET remise_percent = ".$remise;
  1249. $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
  1250. if ($this->db->query($sql) )
  1251. {
  1252. $this->remise_percent = $remise;
  1253. $this->update_price(1);
  1254. return 1;
  1255. }
  1256. else
  1257. {
  1258. $this->error=$this->db->error();
  1259. dol_syslog("Propal::set_remise_percent Error sql=$sql");
  1260. return -1;
  1261. }
  1262. }
  1263. }
  1264. /**
  1265. * \brief Definit une remise globale absolue sur la proposition
  1266. * \param user Objet utilisateur qui modifie
  1267. * \param remise Montant remise
  1268. * \return int <0 si ko, >0 si ok
  1269. */
  1270. function set_remise_absolue($user, $remise)
  1271. {
  1272. $remise=trim($remise)?trim($remise):0;
  1273. if ($user->rights->propale->creer)
  1274. {
  1275. $remise = price2num($remise);
  1276. $sql = "UPDATE ".MAIN_DB_PREFIX."propal ";
  1277. $sql.= " SET remise_absolue = ".$remise;
  1278. $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
  1279. if ($this->db->query($sql) )
  1280. {
  1281. $this->remise_absolue = $remise;
  1282. $this->update_price(1);
  1283. return 1;
  1284. }
  1285. else
  1286. {
  1287. $this->error=$this->db->error();
  1288. dol_syslog("Propal::set_remise_absolue Error sql=$sql");
  1289. return -1;
  1290. }
  1291. }
  1292. }
  1293. /**
  1294. * \brief Cloture de la proposition commerciale
  1295. * \param user Utilisateur qui cloture
  1296. * \param statut Statut
  1297. * \param note Commentaire
  1298. * \return int <0 si ko, >0 si ok
  1299. */
  1300. function cloture($user, $statut, $note)
  1301. {
  1302. global $langs,$conf;
  1303. $this->statut = $statut;
  1304. $this->db->begin();
  1305. $sql = "UPDATE ".MAIN_DB_PREFIX."propal";
  1306. $sql.= " SET fk_statut = ".$statut.", note = '".$this->db->escape($note)."', date_cloture=".$this->db->idate(mktime()).", fk_user_cloture=".$user->id;
  1307. $sql.= " WHERE rowid = ".$this->id;
  1308. $resql=$this->db->query($sql);
  1309. if ($resql)
  1310. {
  1311. if ($statut == 2)
  1312. {
  1313. // Classe la societe rattachee comme client
  1314. $soc=new Societe($this->db);
  1315. $soc->id = $this->socid;
  1316. $result=$soc->set_as_client();
  1317. if ($result < 0)
  1318. {
  1319. $this->error=$this->db->error();
  1320. $this->db->rollback();
  1321. return -2;
  1322. }
  1323. // Appel des triggers
  1324. include_once(DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php");
  1325. $interface=new Interfaces($this->db);
  1326. $result=$interface->run_triggers('PROPAL_CLOSE_SIGNED',$this,$user,$langs,$conf);
  1327. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  1328. // Fin appel triggers
  1329. }
  1330. else
  1331. {
  1332. // Appel des triggers
  1333. include_once(DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php");
  1334. $interface=new Interfaces($this->db);
  1335. $result=$interface->run_triggers('PROPAL_CLOSE_REFUSED',$this,$user,$langs,$conf);
  1336. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  1337. // Fin appel triggers
  1338. }
  1339. $this->db->commit();
  1340. return 1;
  1341. }
  1342. else
  1343. {
  1344. $this->error=$this->db->error();
  1345. $this->db->rollback();
  1346. return -1;
  1347. }
  1348. }
  1349. /**
  1350. * \brief Classe la propale comme facturee
  1351. * \return int <0 si ko, >0 si ok
  1352. */
  1353. function classer_facturee()
  1354. {
  1355. $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal SET fk_statut = 4';
  1356. $sql .= ' WHERE rowid = '.$this->id.' AND fk_statut > 0 ;';
  1357. if ($this->db->query($sql) )
  1358. {
  1359. return 1;
  1360. }
  1361. else
  1362. {
  1363. dol_print_error($this->db);
  1364. }
  1365. }
  1366. /**
  1367. * Set draft status
  1368. *
  1369. * @param User $user Object user that modify
  1370. * @return int <0 if KO, >0 if OK
  1371. */
  1372. function set_draft($user)
  1373. {
  1374. global $conf,$langs;
  1375. $sql = "UPDATE ".MAIN_DB_PREFIX."propal SET fk_statut = 0";
  1376. $sql.= " WHERE rowid = ".$this->id;
  1377. if ($this->db->query($sql))
  1378. {
  1379. return 1;
  1380. }
  1381. else
  1382. {
  1383. return -1;
  1384. }
  1385. }
  1386. /**
  1387. * Return list of proposal (eventually filtered on user) into an array
  1388. *
  1389. * @param shortlist 0=Return array[id]=ref, 1=Return array[](id=>id,ref=>ref)
  1390. * @param draft 0=not draft, 1=draft
  1391. * @param notcurrentuser 0=current user, 1=not current user
  1392. * @param socid Id third pary
  1393. * @param limit For pagination
  1394. * @param offset For pagination
  1395. * @param sortfield Sort criteria
  1396. * @param sortorder Sort order
  1397. * @return int -1 if KO, array with result if OK
  1398. */
  1399. function liste_array($shortlist=0, $draft=0, $notcurrentuser=0, $socid=0, $limit=0, $offset=0, $sortfield='p.datep', $sortorder='DESC')
  1400. {
  1401. global $conf,$user;
  1402. $ga = array();
  1403. $sql = "SELECT s.nom, s.rowid, p.rowid as propalid, p.fk_statut, p.total_ht, p.ref, p.remise, ";
  1404. $sql.= " p.datep as dp, p.fin_validite as datelimite";
  1405. $sql.= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."propal as p, ".MAIN_DB_PREFIX."c_propalst as c";
  1406. $sql.= " WHERE p.entity = ".$conf->entity;
  1407. $sql.= " AND p.fk_soc = s.rowid";
  1408. $sql.= " AND p.fk_statut = c.id";
  1409. if ($socid) $sql.= " AND s.rowid = ".$socid;
  1410. if ($draft) $sql.= " AND p.fk_statut = 0";
  1411. if ($notcurrentuser) $sql.= " AND p.fk_user_author <> ".$user->id;
  1412. $sql.= $this->db->order($sortfield,$sortorder);
  1413. $sql.= $this->db->plimit($limit,$offset);
  1414. $result=$this->db->query($sql);
  1415. if ($result)
  1416. {
  1417. $num = $this->db->num_rows($result);
  1418. if ($num)
  1419. {
  1420. $i = 0;
  1421. while ($i < $num)
  1422. {
  1423. $obj = $this->db->fetch_object($result);
  1424. if ($shortlist)
  1425. {
  1426. $ga[$obj->propalid] = $obj->ref;
  1427. }
  1428. else
  1429. {
  1430. $ga[$i]['id'] = $obj->propalid;
  1431. $ga[$i]['ref'] = $obj->ref;
  1432. }
  1433. $i++;
  1434. }
  1435. }
  1436. return $ga;
  1437. }
  1438. else
  1439. {
  1440. dol_print_error($this->db);
  1441. return -1;
  1442. }
  1443. }
  1444. /**
  1445. * Renvoie un tableau contenant les numeros de factures associees
  1446. *
  1447. * @return array Tableau des id de factures
  1448. */
  1449. function getInvoiceArrayList()
  1450. {
  1451. return $this->InvoiceArrayList($this->id);
  1452. }
  1453. /**
  1454. * Renvoie un tableau contenant les id et ref des factures associees
  1455. *
  1456. * @param int $id Id propal
  1457. * @return array Array of invoices id
  1458. */
  1459. function InvoiceArrayList($id)
  1460. {
  1461. $ga = array();
  1462. $linkedInvoices = array();
  1463. $this->fetchObjectLinked($id,$this->element);
  1464. foreach($this->linkedObjectsIds as $objecttype => $objectid)
  1465. {
  1466. $numi=count($objectid);
  1467. for ($i=0;$i<$numi;$i++)
  1468. {
  1469. // Cas des factures liees directement
  1470. if ($objecttype == 'facture')
  1471. {
  1472. $linkedInvoices[] = $objectid[$i];
  1473. }
  1474. // Cas des factures liees via la commande
  1475. else
  1476. {
  1477. $this->fetchObjectLinked($objectid[$i],$objecttype);
  1478. foreach($this->linkedObjectsIds as $subobjecttype => $subobjectid)
  1479. {
  1480. $numj=count($subobjectid);
  1481. for ($j=0;$j<$numj;$j++)
  1482. {
  1483. $linkedInvoices[] = $subobjectid[$j];
  1484. }
  1485. }
  1486. }
  1487. }
  1488. }
  1489. if (count($linkedInvoices) > 0)
  1490. {
  1491. $sql= "SELECT rowid as facid, facnumber, total, datef as df, fk_user_author, fk_statut, paye";
  1492. $sql.= " FROM ".MAIN_DB_PREFIX."facture";
  1493. $sql.= " WHERE rowid IN (".implode(',',$linkedInvoices).")";
  1494. dol_syslog("Propal::InvoiceArrayList sql=".$sql);
  1495. $resql=$this->db->query($sql);
  1496. if ($resql)
  1497. {
  1498. $tab_sqlobj=array();
  1499. $nump = $this->db->num_rows($resql);
  1500. for ($i = 0;$i < $nump;$i++)
  1501. {
  1502. $sqlobj = $this->db->fetch_object($resql);
  1503. $tab_sqlobj[] = $sqlobj;
  1504. }
  1505. $this->db->free($resql);
  1506. $nump = count($tab_sqlobj);
  1507. if ($nump)
  1508. {
  1509. $i = 0;
  1510. while ($i < $nump)
  1511. {
  1512. $obj = array_shift($tab_sqlobj);
  1513. $ga[$i] = $obj;
  1514. $i++;
  1515. }
  1516. }
  1517. return $ga;
  1518. }
  1519. else
  1520. {
  1521. return -1;
  1522. }
  1523. }
  1524. else return $ga;
  1525. }
  1526. /**
  1527. * \brief Efface propal
  1528. * \param user Objet du user qui efface
  1529. */
  1530. function delete($user, $notrigger=0)
  1531. {
  1532. global $conf,$langs;
  1533. require_once(DOL_DOCUMENT_ROOT."/core/lib/files.lib.php");
  1534. $error=0;
  1535. $this->db->begin();
  1536. $sql = "DELETE FROM ".MAIN_DB_PREFIX."propaldet WHERE fk_propal = ".$this->id;
  1537. if ( $this->db->query($sql) )
  1538. {
  1539. $sql = "DELETE FROM ".MAIN_DB_PREFIX."propal WHERE rowid = ".$this->id;
  1540. if ( $this->db->query($sql) )
  1541. {
  1542. // Delete linked contacts
  1543. $res = $this->delete_linked_contact();
  1544. if ($res < 0)
  1545. {
  1546. $this->error='ErrorFailToDeleteLinkedContact';
  1547. $this->db->rollback();
  1548. return 0;
  1549. }
  1550. // We remove directory
  1551. $propalref = dol_sanitizeFileName($this->ref);
  1552. if ($conf->propale->dir_output)
  1553. {
  1554. $dir = $conf->propale->dir_output . "/" . $propalref ;
  1555. $file = $conf->propale->dir_output . "/" . $propalref . "/" . $propalref . ".pdf";
  1556. if (file_exists($file))
  1557. {
  1558. dol_delete_preview($this);
  1559. if (!dol_delete_file($file))
  1560. {
  1561. $this->error='ErrorFailToDeleteFile';
  1562. $this->db->rollback();
  1563. return 0;
  1564. }
  1565. }
  1566. if (file_exists($dir))
  1567. {
  1568. $res=@dol_delete_dir($dir);
  1569. if (! $res)
  1570. {
  1571. $this->error='ErrorFailToDeleteDir';
  1572. $this->db->rollback();
  1573. return 0;
  1574. }
  1575. }
  1576. }
  1577. if (! $notrigger)
  1578. {
  1579. // Call triggers
  1580. include_once(DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php");
  1581. $interface=new Interfaces($this->db);
  1582. $result=$interface->run_triggers('PROPAL_DELETE',$this,$user,$langs,$conf);
  1583. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  1584. // End call triggers
  1585. }
  1586. if (!$error)
  1587. {
  1588. dol_syslog("Suppression de la proposition $this->id par $user->id", LOG_DEBUG);
  1589. $this->db->commit();
  1590. return 1;
  1591. }
  1592. else
  1593. {
  1594. $this->db->rollback();
  1595. return 0;
  1596. }
  1597. }
  1598. else
  1599. {
  1600. $this->db->rollback();
  1601. return -2;
  1602. }
  1603. }
  1604. else
  1605. {
  1606. $this->db->rollback();
  1607. return -1;
  1608. }
  1609. }
  1610. /**
  1611. * Change les conditions de reglement de la facture
  1612. *
  1613. * @param cond_reglement_id Id de la nouvelle condition de reglement
  1614. * @return int >0 if OK, <0 if KO
  1615. */
  1616. function cond_reglement($cond_reglement_id)
  1617. {
  1618. dol_syslog('Propale::cond_reglement('.$cond_reglement_id.')');
  1619. if ($this->statut >= 0)
  1620. {
  1621. $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal';
  1622. $sql .= ' SET fk_cond_reglement = '.$cond_reglement_id;
  1623. $sql .= ' WHERE rowid='.$this->id;
  1624. if ( $this->db->query($sql) )
  1625. {
  1626. $this->cond_reglement_id = $cond_reglement_id;
  1627. return 1;
  1628. }
  1629. else
  1630. {
  1631. dol_syslog('Propale::cond_reglement Erreur '.$sql.' - '.$this->db->error());
  1632. $this->error=$this->db->error();
  1633. return -1;
  1634. }
  1635. }
  1636. else
  1637. {
  1638. dol_syslog('Propale::cond_reglement, etat propale incompatible');
  1639. $this->error='Etat propale incompatible '.$this->statut;
  1640. return -2;
  1641. }
  1642. }
  1643. /**
  1644. * Change le mode de reglement
  1645. *
  1646. * @param mode_reglement_id Id du nouveau mode
  1647. * @return int >0 if OK, <0 if KO
  1648. */
  1649. function mode_reglement($mode_reglement_id)
  1650. {
  1651. dol_syslog('Propale::mode_reglement('.$mode_reglement_id.')');
  1652. if ($this->statut >= 0)
  1653. {
  1654. $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal';
  1655. $sql .= ' SET fk_mode_reglement = '.$mode_reglement_id;
  1656. $sql .= ' WHERE rowid='.$this->id;
  1657. if ( $this->db->query($sql) )
  1658. {
  1659. $this->mode_reglement_id = $mode_reglement_id;
  1660. return 1;
  1661. }
  1662. else
  1663. {
  1664. dol_syslog('Propale::mode_reglement Erreur '.$sql.' - '.$this->db->error());
  1665. $this->error=$this->db->error();
  1666. return -1;
  1667. }
  1668. }
  1669. else
  1670. {
  1671. dol_syslog('Propale::mode_reglement, etat propale incompatible');
  1672. $this->error='Etat facture incompatible '.$this->statut;
  1673. return -2;
  1674. }
  1675. }
  1676. /**
  1677. * Change le delai de livraison
  1678. *
  1679. * @param availability_id Id du nouveau delai de livraison
  1680. * @return int >0 if OK, <0 if KO
  1681. */
  1682. function availability($availability_id)
  1683. {
  1684. dol_syslog('Propale::availability('.$availability_id.')');
  1685. if ($this->statut >= 0)
  1686. {
  1687. $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal';
  1688. $sql .= ' SET fk_availability = '.$availability_id;
  1689. $sql .= ' WHERE rowid='.$this->id;
  1690. if ( $this->db->query($sql) )
  1691. {
  1692. $this->availability_id = $availability_id;
  1693. return 1;
  1694. }
  1695. else
  1696. {
  1697. dol_syslog('Propale::availability Erreur '.$sql.' - '.$this->db->error());
  1698. $this->error=$this->db->error();
  1699. return -1;
  1700. }
  1701. }
  1702. else
  1703. {
  1704. dol_syslog('Propale::availability, etat propale incompatible');
  1705. $this->error='Etat propale incompatible '.$this->statut;
  1706. return -2;
  1707. }
  1708. }
  1709. /**
  1710. * \brief Change l'origine de la demande
  1711. * \param demand_reason_id Id de la nouvelle origine de demande
  1712. * \return int >0 si ok, <0 si ko
  1713. */
  1714. function demand_reason($demand_reason_id)
  1715. {
  1716. dol_syslog('Propale::demand_reason('.$demand_reason_id.')');
  1717. if ($this->statut >= 0)
  1718. {
  1719. $sql = 'UPDATE '.MAIN_DB_PREFIX.'propal';
  1720. $sql .= ' SET fk_demand_reason = '.$demand_reason_id;
  1721. $sql .= ' WHERE rowid='.$this->id;
  1722. if ( $this->db->query($sql) )
  1723. {
  1724. $this->demand_reason_id = $demand_reason_id;
  1725. return 1;
  1726. }
  1727. else
  1728. {
  1729. dol_syslog('Propale::demand_reason Erreur '.$sql.' - '.$this->db->error());
  1730. $this->error=$this->db->error();
  1731. return -1;
  1732. }
  1733. }
  1734. else
  1735. {
  1736. dol_syslog('Propale::demand_reason, etat propale incompatible');
  1737. $this->error='Etat propale incompatible '.$this->statut;
  1738. return -2;
  1739. }
  1740. }
  1741. /**
  1742. * \brief Information sur l'objet propal
  1743. * \param id id de la propale
  1744. */
  1745. function info($id)
  1746. {
  1747. $sql = "SELECT c.rowid, ";
  1748. $sql.= " c.datec, c.date_valid as datev, c.date_cloture as dateo,";
  1749. $sql.= " c.fk_user_author, c.fk_user_valid, c.fk_user_cloture";
  1750. $sql.= " FROM ".MAIN_DB_PREFIX."propal as c";
  1751. $sql.= " WHERE c.rowid = ".$id;
  1752. $result = $this->db->query($sql);
  1753. if ($result)
  1754. {
  1755. if ($this->db->num_rows($result))
  1756. {
  1757. $obj = $this->db->fetch_object($result);
  1758. $this->id = $obj->rowid;
  1759. $this->date_creation = $this->db->jdate($obj->datec);
  1760. $this->date_validation = $this->db->jdate($obj->datev);
  1761. $this->date_cloture = $this->db->jdate($obj->dateo);
  1762. $cuser = new User($this->db);
  1763. $cuser->fetch($obj->fk_user_author);
  1764. $this->user_creation = $cuser;
  1765. if ($obj->fk_user_valid)
  1766. {
  1767. $vuser = new User($this->db);
  1768. $vuser->fetch($obj->fk_user_valid);
  1769. $this->user_validation = $vuser;
  1770. }
  1771. if ($obj->fk_user_cloture)
  1772. {
  1773. $cluser = new User($this->db);
  1774. $cluser->fetch($obj->fk_user_cloture);
  1775. $this->user_cloture = $cluser;
  1776. }
  1777. }
  1778. $this->db->free($result);
  1779. }
  1780. else
  1781. {
  1782. dol_print_error($this->db);
  1783. }
  1784. }
  1785. /**
  1786. * Return label of status of proposal (draft, validated, ...)
  1787. * @param mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
  1788. * @return string Label
  1789. */
  1790. function getLibStatut($mode=0)
  1791. {
  1792. return $this->LibStatut($this->statut,$mode);
  1793. }
  1794. /**
  1795. * Return label of a status (draft, validated, ...)
  1796. * @param statut id statut
  1797. * @param mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
  1798. * @return string Label
  1799. */
  1800. function LibStatut($statut,$mode=1)
  1801. {
  1802. global $langs;
  1803. $langs->load("propal");
  1804. if ($mode == 0)
  1805. {
  1806. return $this->labelstatut[$statut];
  1807. }
  1808. if ($mode == 1)
  1809. {
  1810. return $this->labelstatut_short[$statut];
  1811. }
  1812. if ($mode == 2)
  1813. {
  1814. if ($statut==0) return img_picto($langs->trans('PropalStatusDraftShort'),'statut0').' '.$this->labelstatut_short[$statut];
  1815. if ($statut==1) return img_picto($langs->trans('PropalStatusOpenedShort'),'statut1').' '.$this->labelstatut_short[$statut];
  1816. if ($statut==2) return img_picto($langs->trans('PropalStatusSignedShort'),'statut3').' '.$this->labelstatut_short[$statut];
  1817. if ($statut==3) return img_picto($langs->trans('PropalStatusNotSignedShort'),'statut5').' '.$this->labelstatut_short[$statut];
  1818. if ($statut==4) return img_picto($langs->trans('PropalStatusBilledShort'),'statut6').' '.$this->labelstatut_short[$statut];
  1819. }
  1820. if ($mode == 3)
  1821. {
  1822. if ($statut==0) return img_picto($langs->trans('PropalStatusDraftShort'),'statut0');
  1823. if ($statut==1) return img_picto($langs->trans('PropalStatusOpenedShort'),'statut1');
  1824. if ($statut==2) return img_picto($langs->trans('PropalStatusSignedShort'),'statut3');
  1825. if ($statut==3) return img_picto($langs->trans('PropalStatusNotSignedShort'),'statut5');
  1826. if ($statut==4) return img_picto($langs->trans('PropalStatusBilledShort'),'statut6');
  1827. }
  1828. if ($mode == 4)
  1829. {
  1830. if ($statut==0) return img_picto($langs->trans('PropalStatusDraft'),'statut0').' '.$this->labelstatut[$statut];
  1831. if ($statut==1) return img_picto($langs->trans('PropalStatusOpened'),'statut1').' '.$this->labelstatut[$statut];
  1832. if ($statut==2) return img_picto($langs->trans('PropalStatusSigned'),'statut3').' '.$this->labelstatut[$statut];
  1833. if ($statut==3) return img_picto($langs->trans('PropalStatusNotSigned'),'statut5').' '.$this->labelstatut[$statut];
  1834. if ($statut==4) return img_picto($langs->trans('PropalStatusBilled'),'statut6').' '.$this->labelstatut[$statut];
  1835. }
  1836. if ($mode == 5)
  1837. {
  1838. if ($statut==0) return $this->labelstatut_short[$statut].' '.img_picto($langs->trans('PropalStatusDraftShort'),'statut0');
  1839. if ($statut==1) return $this->labelstatut_short[$statut].' '.img_picto($langs->trans('PropalStatusOpenedShort'),'statut1');
  1840. if ($statut==2) return $this->labelstatut_short[$statut].' '.img_picto($langs->trans('PropalStatusSignedShort'),'statut3');
  1841. if ($statut==3) return $this->labelstatut_short[$statut].' '.img_picto($langs->trans('PropalStatusNotSignedShort'),'statut5');
  1842. if ($statut==4) return $this->labelstatut_short[$statut].' '.img_picto($langs->trans('PropalStatusBilledShort'),'statut6');
  1843. }
  1844. }
  1845. /**
  1846. * Load indicators for dashboard (this->nbtodo and this->nbtodolate)
  1847. * @param user Objet user
  1848. * @param mode "opened" pour propal a fermer, "signed" pour propale a facturer
  1849. * @return int <0 if KO, >0 if OK
  1850. */
  1851. function load_board($user,$mode)
  1852. {
  1853. global $conf, $user;
  1854. $now=gmmktime();
  1855. $this->nbtodo=$this->nbtodolate=0;
  1856. $clause = " WHERE";
  1857. $sql = "SELECT p.rowid, p.ref, p.datec as datec, p.fin_validite as datefin";
  1858. $sql.= " FROM ".MAIN_DB_PREFIX."propal as p";
  1859. if (!$user->rights->societe->client->voir && !$user->societe_id)
  1860. {
  1861. $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON p.fk_soc = sc.fk_soc";
  1862. $sql.= " WHERE sc.fk_user = " .$user->id;
  1863. $clause = " AND";
  1864. }
  1865. $sql.= $clause." p.entity = ".$conf->entity;
  1866. if ($mode == 'opened') $sql.= " AND p.fk_statut = 1";
  1867. if ($mode == 'signed') $sql.= " AND p.fk_statut = 2";
  1868. if ($user->societe_id) $sql.= " AND p.fk_soc = ".$user->societe_id;
  1869. $resql=$this->db->query($sql);
  1870. if ($resql)
  1871. {
  1872. if ($mode == 'opened') $delay_warning=$conf->propal->cloture->warning_delay;
  1873. if ($mode == 'signed') $delay_warning=$conf->propal->facturation->warning_delay;
  1874. while ($obj=$this->db->fetch_object($resql))
  1875. {
  1876. $this->nbtodo++;
  1877. if ($mode == 'opened')
  1878. {
  1879. $datelimit = $this->db->jdate($obj->datefin);
  1880. if ($datelimit < ($now - $delay_warning))
  1881. {
  1882. $this->nbtodolate++;
  1883. }
  1884. }
  1885. // TODO Definir regle des propales a facturer en retard
  1886. // if ($mode == 'signed' && ! count($this->FactureListeArray($obj->rowid))) $this->nbtodolate++;
  1887. }
  1888. return 1;
  1889. }
  1890. else
  1891. {
  1892. $this->error=$this->db->error();
  1893. return -1;
  1894. }
  1895. }
  1896. /**
  1897. * Initialise an instance with random values.
  1898. * Used to build previews or test instances.
  1899. * id must be 0 if object instance is a specimen.
  1900. *
  1901. * @return void
  1902. */
  1903. function initAsSpecimen()
  1904. {
  1905. global $user,$langs,$conf;
  1906. // Charge tableau des produits prodids
  1907. $prodids = array();
  1908. $sql = "SELECT rowid";
  1909. $sql.= " FROM ".MAIN_DB_PREFIX."product";
  1910. $sql.= " WHERE entity = ".$conf->entity;
  1911. $resql = $this->db->query($sql);
  1912. if ($resql)
  1913. {
  1914. $num_prods = $this->db->num_rows($resql);
  1915. $i = 0;
  1916. while ($i < $num_prods)
  1917. {
  1918. $i++;
  1919. $row = $this->db->fetch_row($resql);
  1920. $prodids[$i] = $row[0];
  1921. }
  1922. }
  1923. // Initialise parametres
  1924. $this->id=0;
  1925. $this->ref = 'SPECIMEN';
  1926. $this->ref_client='NEMICEPS';
  1927. $this->specimen=1;
  1928. $this->socid = 1;
  1929. $this->date = time();
  1930. $this->fin_validite = $this->date+3600*24*30;
  1931. $this->cond_reglement_id = 1;
  1932. $this->cond_reglement_code = 'RECEP';
  1933. $this->mode_reglement_id = 7;
  1934. $this->mode_reglement_code = 'CHQ';
  1935. $this->availability_id = 1;
  1936. $this->availability_code = 'DSP';
  1937. $this->demand_reason_id = 1;
  1938. $this->demand_reason_code = 'SRC_00';
  1939. $this->note_public='This is a comment (public)';
  1940. $this->note='This is a comment (private)';
  1941. // Lines
  1942. $nbp = 5;
  1943. $xnbp = 0;
  1944. while ($xnbp < $nbp)
  1945. {
  1946. $line=new PropaleLigne($this->db);
  1947. $line->desc=$langs->trans("Description")." ".$xnbp;
  1948. $line->qty=1;
  1949. $line->subprice=100;
  1950. $line->price=100;
  1951. $line->tva_tx=19.6;
  1952. $line->localtax1_tx=0;
  1953. $line->localtax2_tx=0;
  1954. if ($xnbp == 2)
  1955. {
  1956. $line->total_ht=50;
  1957. $line->total_ttc=59.8;
  1958. $line->total_tva=9.8;
  1959. $line->remise_percent=50;
  1960. }
  1961. else
  1962. {
  1963. $line->total_ht=100;
  1964. $line->total_ttc=119.6;
  1965. $line->total_tva=19.6;
  1966. $line->remise_percent=00;
  1967. }
  1968. $prodid = rand(1, $num_prods);
  1969. $line->fk_product=$prodids[$prodid];
  1970. $this->lines[$xnbp]=$line;
  1971. $this->total_ht += $line->total_ht;
  1972. $this->total_tva += $line->total_tva;
  1973. $this->total_ttc += $line->total_ttc;
  1974. $xnbp++;
  1975. }
  1976. }
  1977. /**
  1978. * Charge indicateurs this->nb de tableau de bord
  1979. *
  1980. * @return int <0 si ko, >0 si ok
  1981. */
  1982. function load_state_board()
  1983. {
  1984. global $conf, $user;
  1985. $this->nb=array();
  1986. $clause = "WHERE";
  1987. $sql = "SELECT count(p.rowid) as nb";
  1988. $sql.= " FROM ".MAIN_DB_PREFIX."propal as p";
  1989. $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
  1990. if (!$user->rights->societe->client->voir && !$user->societe_id)
  1991. {
  1992. $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
  1993. $sql.= " WHERE sc.fk_user = " .$user->id;
  1994. $clause = "AND";
  1995. }
  1996. $sql.= " ".$clause." p.entity = ".$conf->entity;
  1997. $resql=$this->db->query($sql);
  1998. if ($resql)
  1999. {
  2000. while ($obj=$this->db->fetch_object($resql))
  2001. {
  2002. $this->nb["proposals"]=$obj->nb;
  2003. }
  2004. return 1;
  2005. }
  2006. else
  2007. {
  2008. dol_print_error($this->db);
  2009. $this->error=$this->db->error();
  2010. return -1;
  2011. }
  2012. }
  2013. /**
  2014. * Renvoie la reference de propale suivante non utilisee en fonction du module
  2015. * de numerotation actif defini dans PROPALE_ADDON
  2016. *
  2017. * @param Societe $soc Object thirdparty
  2018. * @return string Reference libre pour la propale
  2019. */
  2020. function getNextNumRef($soc)
  2021. {
  2022. global $conf, $db, $langs;
  2023. $langs->load("propal");
  2024. $dir = DOL_DOCUMENT_ROOT . "/core/modules/propale/";
  2025. if (! empty($conf->global->PROPALE_ADDON))
  2026. {
  2027. $file = $conf->global->PROPALE_ADDON.".php";
  2028. // Chargement de la classe de numerotation
  2029. $classname = $conf->global->PROPALE_ADDON;
  2030. require_once($dir.$file);
  2031. $obj = new $classname();
  2032. $numref = "";
  2033. $numref = $obj->getNextValue($soc,$this);
  2034. if ( $numref != "")
  2035. {
  2036. return $numref;
  2037. }
  2038. else
  2039. {
  2040. $this->error=$obj->error;
  2041. //dol_print_error($db,"Propale::getNextNumRef ".$obj->error);
  2042. return "";
  2043. }
  2044. }
  2045. else
  2046. {
  2047. $langs->load("errors");
  2048. print $langs->trans("Error")." ".$langs->trans("ErrorModuleSetupNotComplete");
  2049. return "";
  2050. }
  2051. }
  2052. /**
  2053. * Return clicable link of object (with eventually picto)
  2054. * @param withpicto Add picto into link
  2055. * @param option Where point the link
  2056. * @param get_params Parametres added to url
  2057. * @return string String with URL
  2058. */
  2059. function getNomUrl($withpicto=0,$option='', $get_params='')
  2060. {
  2061. global $langs;
  2062. $result='';
  2063. if($option == '')
  2064. {
  2065. $lien = '<a href="'.DOL_URL_ROOT.'/comm/propal.php?id='.$this->id. $get_params .'">';
  2066. }
  2067. if($option == 'compta') // deprecated
  2068. {
  2069. $lien = '<a href="'.DOL_URL_ROOT.'/comm/propal.php?id='.$this->id. $get_params .'">';
  2070. }
  2071. if($option == 'expedition')
  2072. {
  2073. $lien = '<a href="'.DOL_URL_ROOT.'/expedition/propal.php?id='.$this->id. $get_params .'">';
  2074. }
  2075. $lienfin='</a>';
  2076. $picto='propal';
  2077. $label=$langs->trans("ShowPropal").': '.$this->ref;
  2078. if ($withpicto) $result.=($lien.img_object($label,$picto).$lienfin);
  2079. if ($withpicto && $withpicto != 2) $result.=' ';
  2080. $result.=$lien.$this->ref.$lienfin;
  2081. return $result;
  2082. }
  2083. /**
  2084. * Return an array of propal lines
  2085. */
  2086. function getLinesArray()
  2087. {
  2088. $sql = 'SELECT pt.rowid, pt.description, pt.fk_product, pt.fk_remise_except,';
  2089. $sql.= ' pt.qty, pt.tva_tx, pt.remise_percent, pt.subprice, pt.info_bits,';
  2090. $sql.= ' pt.total_ht, pt.total_tva, pt.total_ttc, pt.marge_tx, pt.marque_tx, pt.pa_ht, pt.special_code,';
  2091. $sql.= ' pt.date_start, pt.date_end, pt.product_type, pt.rang,';
  2092. $sql.= ' p.label as product_label, p.ref, p.fk_product_type, p.rowid as prodid,';
  2093. $sql.= ' p.description as product_desc';
  2094. $sql.= ' FROM '.MAIN_DB_PREFIX.'propaldet as pt';
  2095. $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON pt.fk_product=p.rowid';
  2096. $sql.= ' WHERE pt.fk_propal = '.$this->id;
  2097. $sql.= ' ORDER BY pt.rang ASC, pt.rowid';
  2098. $resql = $this->db->query($sql);
  2099. if ($resql)
  2100. {
  2101. $num = $this->db->num_rows($resql);
  2102. $i = 0;
  2103. while ($i < $num)
  2104. {
  2105. $obj = $this->db->fetch_object($resql);
  2106. $this->lines[$i]->id = $obj->rowid;
  2107. $this->lines[$i]->description = $obj->description;
  2108. $this->lines[$i]->fk_product = $obj->fk_product;
  2109. $this->lines[$i]->ref = $obj->ref;
  2110. $this->lines[$i]->product_label = $obj->product_label;
  2111. $this->lines[$i]->product_desc = $obj->product_desc;
  2112. $this->lines[$i]->fk_product_type = $obj->fk_product_type; // deprecated
  2113. $this->lines[$i]->product_type = $obj->product_type;
  2114. $this->lines[$i]->qty = $obj->qty;
  2115. $this->lines[$i]->subprice = $obj->subprice;
  2116. $this->lines[$i]->pa_ht = $obj->pa_ht;
  2117. $this->lines[$i]->fk_remise_except = $obj->fk_remise_except;
  2118. $this->lines[$i]->remise_percent = $obj->remise_percent;
  2119. $this->lines[$i]->tva_tx = $obj->tva_tx;
  2120. $this->lines[$i]->info_bits = $obj->info_bits;
  2121. $this->lines[$i]->total_ht = $obj->total_ht;
  2122. $this->lines[$i]->total_tva = $obj->total_tva;
  2123. $this->lines[$i]->total_ttc = $obj->total_ttc;
  2124. $this->lines[$i]->marge_tx = $obj->marge_tx;
  2125. $this->lines[$i]->marque_tx = $obj->marque_tx;
  2126. $this->lines[$i]->special_code = $obj->special_code;
  2127. $this->lines[$i]->rang = $obj->rang;
  2128. $this->lines[$i]->date_start = $this->db->jdate($obj->date_start);
  2129. $this->lines[$i]->date_end = $this->db->jdate($obj->date_end);
  2130. $i++;
  2131. }
  2132. $this->db->free($resql);
  2133. return 1;
  2134. }
  2135. else
  2136. {
  2137. $this->error=$this->db->error();
  2138. dol_syslog("Error sql=$sql, error=".$this->error,LOG_ERR);
  2139. return -1;
  2140. }
  2141. }
  2142. }
  2143. /**
  2144. * \class PropaleLigne
  2145. * \brief Class to manage commercial proposal lines
  2146. */
  2147. class PropaleLigne
  2148. {
  2149. var $db;
  2150. var $error;
  2151. var $oldline;
  2152. // From llx_propaldet
  2153. var $rowid;
  2154. var $fk_propal;
  2155. var $fk_parent_line;
  2156. var $desc; // Description ligne
  2157. var $fk_product; // Id produit predefini
  2158. var $product_type = 0; // Type 0 = product, 1 = Service
  2159. var $qty;
  2160. var $tva_tx;
  2161. var $subprice;
  2162. var $remise_percent;
  2163. var $fk_remise_except;
  2164. var $rang = 0;
  2165. var $marge_tx;
  2166. var $marque_tx;
  2167. var $special_code; // Liste d'options non cumulabels:
  2168. // 1: frais de port
  2169. // 2: ecotaxe
  2170. // 3: ??
  2171. var $info_bits = 0; // Liste d'options cumulables:
  2172. // Bit 0: 0 si TVA normal - 1 si TVA NPR
  2173. // Bit 1: 0 ligne normale - 1 si ligne de remise fixe
  2174. var $total_ht; // Total HT de la ligne toute quantite et incluant la remise ligne
  2175. var $total_tva; // Total TVA de la ligne toute quantite et incluant la remise ligne
  2176. var $total_ttc; // Total TTC de la ligne toute quantite et incluant la remise ligne
  2177. // Ne plus utiliser
  2178. var $remise;
  2179. var $price;
  2180. // From llx_product
  2181. var $ref; // Reference produit
  2182. var $libelle; // Label produit
  2183. var $product_desc; // Description produit
  2184. var $localtax1_tx;
  2185. var $localtax2_tx;
  2186. var $total_localtax1;
  2187. var $total_localtax2;
  2188. var $skip_update_total; // Skip update price total for special lines
  2189. /**
  2190. * \brief Constructeur d'objets ligne de propal
  2191. * \param DB handler d'acces base de donnee
  2192. */
  2193. function PropaleLigne($DB)
  2194. {
  2195. $this->db= $DB;
  2196. }
  2197. /**
  2198. * \brief Recupere l'objet ligne de propal
  2199. * \param rowid id de la ligne de propal
  2200. */
  2201. function fetch($rowid)
  2202. {
  2203. $sql = 'SELECT pd.rowid, pd.fk_propal, pd.fk_parent_line, pd.fk_product, pd.description, pd.price, pd.qty, pd.tva_tx,';
  2204. $sql.= ' pd.remise, pd.remise_percent, pd.fk_remise_except, pd.subprice,';
  2205. $sql.= ' pd.info_bits, pd.total_ht, pd.total_tva, pd.total_ttc, pd.marge_tx, pd.marque_tx, pd.special_code, pd.rang,';
  2206. $sql.= ' p.ref as product_ref, p.label as product_libelle, p.description as product_desc';
  2207. $sql.= ' FROM '.MAIN_DB_PREFIX.'propaldet as pd';
  2208. $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON pd.fk_product = p.rowid';
  2209. $sql.= ' WHERE pd.rowid = '.$rowid;
  2210. $result = $this->db->query($sql);
  2211. if ($result)
  2212. {
  2213. $objp = $this->db->fetch_object($result);
  2214. $this->rowid = $objp->rowid;
  2215. $this->fk_propal = $objp->fk_propal;
  2216. $this->fk_parent_line = $objp->fk_parent_line;
  2217. $this->desc = $objp->description;
  2218. $this->qty = $objp->qty;
  2219. $this->price = $objp->price; // deprecated
  2220. $this->subprice = $objp->subprice;
  2221. $this->tva_tx = $objp->tva_tx;
  2222. $this->remise = $objp->remise;
  2223. $this->remise_percent = $objp->remise_percent;
  2224. $this->fk_remise_except = $objp->fk_remise_except;
  2225. $this->fk_product = $objp->fk_product;
  2226. $this->info_bits = $objp->info_bits;
  2227. $this->total_ht = $objp->total_ht;
  2228. $this->total_tva = $objp->total_tva;
  2229. $this->total_ttc = $objp->total_ttc;
  2230. $this->marge_tx = $objp->marge_tx;
  2231. $this->marque_tx = $objp->marque_tx;
  2232. $this->special_code = $objp->special_code;
  2233. $this->rang = $objp->rang;
  2234. $this->ref = $objp->product_ref; // deprecated
  2235. $this->product_ref = $objp->product_ref;
  2236. $this->libelle = $objp->product_libelle; // deprecated
  2237. $this->product_label = $objp->product_libelle;
  2238. $this->product_desc = $objp->product_desc;
  2239. $this->db->free($result);
  2240. }
  2241. else
  2242. {
  2243. dol_print_error($this->db);
  2244. }
  2245. }
  2246. /**
  2247. * \brief Insert object line propal in database
  2248. * \return int <0 if KO, >0 if OK
  2249. */
  2250. function insert($notrigger=0)
  2251. {
  2252. global $conf,$langs,$user;
  2253. dol_syslog("PropaleLigne::insert rang=".$this->rang);
  2254. // Clean parameters
  2255. if (empty($this->tva_tx)) $this->tva_tx=0;
  2256. if (empty($this->localtax1_tx)) $this->localtax1_tx=0;
  2257. if (empty($this->localtax2_tx)) $this->localtax2_tx=0;
  2258. if (empty($this->total_localtax1)) $this->total_localtax1=0;
  2259. if (empty($this->total_localtax2)) $this->total_localtax2=0;
  2260. if (empty($this->rang)) $this->rang=0;
  2261. if (empty($this->remise)) $this->remise=0;
  2262. if (empty($this->remise_percent)) $this->remise_percent=0;
  2263. if (empty($this->info_bits)) $this->info_bits=0;
  2264. if (empty($this->special_code)) $this->special_code=0;
  2265. if (empty($this->fk_parent_line)) $this->fk_parent_line=0;
  2266. // Check parameters
  2267. if ($this->product_type < 0) return -1;
  2268. $this->db->begin();
  2269. // Insert line into database
  2270. $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'propaldet';
  2271. $sql.= ' (fk_propal, fk_parent_line, description, fk_product, product_type, fk_remise_except, qty, tva_tx, localtax1_tx, localtax2_tx,';
  2272. $sql.= ' subprice, remise_percent, ';
  2273. $sql.= ' info_bits, ';
  2274. $sql.= ' total_ht, total_tva, total_localtax1, total_localtax2, total_ttc, special_code, rang, marge_tx, marque_tx)';
  2275. $sql.= " VALUES (".$this->fk_propal.",";
  2276. $sql.= " ".($this->fk_parent_line>0?"'".$this->fk_parent_line."'":"null").",";
  2277. $sql.= " '".$this->db->escape($this->desc)."',";
  2278. $sql.= " ".($this->fk_product?"'".$this->fk_product."'":"null").",";
  2279. $sql.= " '".$this->product_type."',";
  2280. $sql.= " ".($this->fk_remise_except?"'".$this->fk_remise_except."'":"null").",";
  2281. $sql.= " ".price2num($this->qty).",";
  2282. $sql.= " ".price2num($this->tva_tx).",";
  2283. $sql.= " ".price2num($this->localtax1_tx).",";
  2284. $sql.= " ".price2num($this->localtax2_tx).",";
  2285. $sql.= " ".($this->subprice?price2num($this->subprice):'null').",";
  2286. $sql.= " ".price2num($this->remise_percent).",";
  2287. $sql.= " '".$this->info_bits."',";
  2288. $sql.= " ".price2num($this->total_ht).",";
  2289. $sql.= " ".price2num($this->total_tva).",";
  2290. $sql.= " ".price2num($this->total_localtax1).",";
  2291. $sql.= " ".price2num($this->total_localtax2).",";
  2292. $sql.= " ".price2num($this->total_ttc).",";
  2293. $sql.= ' '.$this->special_code.',';
  2294. $sql.= ' '.$this->rang.',';
  2295. if (isset($this->marge_tx)) $sql.= ' '.$this->marge_tx.',';
  2296. else $sql.= ' null,';
  2297. if (isset($this->marque_tx)) $sql.= ' '.$this->marque_tx;
  2298. else $sql.= ' null';
  2299. $sql.= ')';
  2300. dol_syslog("PropaleLigne::insert sql=$sql");
  2301. $resql=$this->db->query($sql);
  2302. if ($resql)
  2303. {
  2304. $this->rang=$rangmax;
  2305. $this->rowid=$this->db->last_insert_id(MAIN_DB_PREFIX.'propaldet');
  2306. if (! $notrigger)
  2307. {
  2308. // Appel des triggers
  2309. include_once(DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php");
  2310. $interface=new Interfaces($this->db);
  2311. $result = $interface->run_triggers('LINEPROPAL_INSERT',$this,$user,$langs,$conf);
  2312. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  2313. // Fin appel triggers
  2314. }
  2315. $this->db->commit();
  2316. return 1;
  2317. }
  2318. else
  2319. {
  2320. $this->error=$this->db->error()." sql=".$sql;
  2321. dol_syslog("PropaleLigne::insert Error ".$this->error, LOG_ERR);
  2322. $this->db->rollback();
  2323. return -1;
  2324. }
  2325. }
  2326. /**
  2327. * Delete line in database
  2328. * @return int <0 si ko, >0 si ok
  2329. */
  2330. function delete()
  2331. {
  2332. global $conf,$langs,$user;
  2333. $this->db->begin();
  2334. $sql = "DELETE FROM ".MAIN_DB_PREFIX."propaldet WHERE rowid = ".$this->rowid;
  2335. dol_syslog("PropaleLigne::delete sql=".$sql, LOG_DEBUG);
  2336. if ($this->db->query($sql) )
  2337. {
  2338. // Appel des triggers
  2339. include_once(DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php");
  2340. $interface=new Interfaces($this->db);
  2341. $result = $interface->run_triggers('LINEPROPAL_DELETE',$this,$user,$langs,$conf);
  2342. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  2343. // Fin appel triggers
  2344. $this->db->commit();
  2345. return 1;
  2346. }
  2347. else
  2348. {
  2349. $this->error=$this->db->error()." sql=".$sql;
  2350. dol_syslog("PropaleLigne::delete Error ".$this->error, LOG_ERR);
  2351. $this->db->rollback();
  2352. return -1;
  2353. }
  2354. }
  2355. /**
  2356. * Mise a jour de l'objet ligne de propale en base
  2357. *
  2358. * @return int <0 si ko, >0 si ok
  2359. */
  2360. function update($notrigger=0)
  2361. {
  2362. global $conf,$langs,$user;
  2363. // Clean parameters
  2364. if (empty($this->tva_tx)) $this->tva_tx=0;
  2365. if (empty($this->localtax1_tx)) $this->localtax1_tx=0;
  2366. if (empty($this->localtax2_tx)) $this->localtax2_tx=0;
  2367. if (empty($this->total_localtax1)) $this->total_localtax1=0;
  2368. if (empty($this->total_localtax2)) $this->total_localtax2=0;
  2369. if (empty($this->marque_tx)) $this->marque_tx=0;
  2370. if (empty($this->marge_tx)) $this->marge_tx=0;
  2371. if (empty($this->remise)) $this->remise=0;
  2372. if (empty($this->remise_percent)) $this->remise_percent=0;
  2373. if (empty($this->info_bits)) $this->info_bits=0;
  2374. if (empty($this->special_code)) $this->special_code=0;
  2375. if (empty($this->fk_parent_line)) $this->fk_parent_line=0;
  2376. $this->db->begin();
  2377. // Mise a jour ligne en base
  2378. $sql = "UPDATE ".MAIN_DB_PREFIX."propaldet SET";
  2379. $sql.= " description='".$this->db->escape($this->desc)."'";
  2380. $sql.= " , tva_tx='".price2num($this->tva_tx)."'";
  2381. $sql.= " , localtax1_tx=".price2num($this->localtax1_tx);
  2382. $sql.= " , localtax2_tx=".price2num($this->localtax2_tx);
  2383. $sql.= " , qty='".price2num($this->qty)."'";
  2384. $sql.= " , subprice=".price2num($this->subprice)."";
  2385. $sql.= " , remise_percent=".price2num($this->remise_percent)."";
  2386. $sql.= " , price=".price2num($this->price).""; // TODO A virer
  2387. $sql.= " , remise=".price2num($this->remise).""; // TODO A virer
  2388. $sql.= " , info_bits='".$this->info_bits."'";
  2389. if (empty($this->skip_update_total))
  2390. {
  2391. $sql.= " , total_ht=".price2num($this->total_ht)."";
  2392. $sql.= " , total_tva=".price2num($this->total_tva)."";
  2393. $sql.= " , total_ttc=".price2num($this->total_ttc)."";
  2394. }
  2395. $sql.= " , marge_tx='".$this->marge_tx."'";
  2396. $sql.= " , marque_tx='".$this->marque_tx."'";
  2397. $sql.= " , info_bits=".$this->info_bits;
  2398. if (strlen($this->special_code)) $sql.= " , special_code=".$this->special_code;
  2399. $sql.= " , fk_parent_line=".($this->fk_parent_line>0?$this->fk_parent_line:"null");
  2400. if (! empty($this->rang)) $sql.= ", rang=".$this->rang;
  2401. $sql.= " WHERE rowid = ".$this->rowid;
  2402. dol_syslog(get_class($this)."::update sql=".$sql, LOG_DEBUG);
  2403. $resql=$this->db->query($sql);
  2404. if ($resql)
  2405. {
  2406. if (! $notrigger)
  2407. {
  2408. // Appel des triggers
  2409. include_once(DOL_DOCUMENT_ROOT . "/core/class/interfaces.class.php");
  2410. $interface=new Interfaces($this->db);
  2411. $result = $interface->run_triggers('LINEPROPAL_UPDATE',$this,$user,$langs,$conf);
  2412. if ($result < 0) { $error++; $this->errors=$interface->errors; }
  2413. // Fin appel triggers
  2414. }
  2415. $this->db->commit();
  2416. return 1;
  2417. }
  2418. else
  2419. {
  2420. $this->error=$this->db->error();
  2421. dol_syslog(get_class($this)."::update Error ".$this->error, LOG_ERR);
  2422. $this->db->rollback();
  2423. return -2;
  2424. }
  2425. }
  2426. /**
  2427. * \brief Mise a jour en base des champs total_xxx de ligne
  2428. * \remarks Utilise par migration
  2429. * \return int <0 si ko, >0 si ok
  2430. */
  2431. function update_total()
  2432. {
  2433. $this->db->begin();
  2434. // Mise a jour ligne en base
  2435. $sql = "UPDATE ".MAIN_DB_PREFIX."propaldet SET";
  2436. $sql.= " total_ht=".price2num($this->total_ht,'MT')."";
  2437. $sql.= ",total_tva=".price2num($this->total_tva,'MT')."";
  2438. $sql.= ",total_ttc=".price2num($this->total_ttc,'MT')."";
  2439. $sql.= " WHERE rowid = ".$this->rowid;
  2440. dol_syslog("PropaleLigne::update_total sql=$sql");
  2441. $resql=$this->db->query($sql);
  2442. if ($resql)
  2443. {
  2444. $this->db->commit();
  2445. return 1;
  2446. }
  2447. else
  2448. {
  2449. $this->error=$this->db->error();
  2450. dol_syslog("PropaleLigne::update_total Error ".$this->error, LOG_ERR);
  2451. $this->db->rollback();
  2452. return -2;
  2453. }
  2454. }
  2455. }
  2456. ?>