PageRenderTime 65ms CodeModel.GetById 26ms 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

Large files files are truncated, but you can click here to view the full file

  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= "SE…

Large files files are truncated, but you can click here to view the full file