supplier_proposal.class.php 108 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063
  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 <marc@ocebo.com>
  6. * Copyright (C) 2005-2013 Regis Houssin <regis.houssin@capnetworks.com>
  7. * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
  8. * Copyright (C) 2008 Raphael Bertrand <raphael.bertrand@resultic.fr>
  9. * Copyright (C) 2010-2015 Juanjo Menent <jmenent@2byte.es>
  10. * Copyright (C) 2010-2011 Philippe Grand <philippe.grand@atoo-net.com>
  11. * Copyright (C) 2012-2014 Christophe Battarel <christophe.battarel@altairis.fr>
  12. * Copyright (C) 2013 Florian Henry <florian.henry@open-concept.pro>
  13. * Copyright (C) 2014 Marcos García <marcosgdf@gmail.com>
  14. *
  15. * This program is free software; you can redistribute it and/or modify
  16. * it under the terms of the GNU General Public License as published by
  17. * the Free Software Foundation; either version 3 of the License, or
  18. * (at your option) any later version.
  19. *
  20. * This program is distributed in the hope that it will be useful,
  21. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  23. * GNU General Public License for more details.
  24. *
  25. * You should have received a copy of the GNU General Public License
  26. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  27. */
  28. /**
  29. * \file htdocs/supplier_proposal/class/supplier_proposal.class.php
  30. * \brief File of class to manage supplier proposals
  31. */
  32. require_once DOL_DOCUMENT_ROOT .'/fourn/class/fournisseur.product.class.php';
  33. require_once DOL_DOCUMENT_ROOT .'/core/class/commonobject.class.php';
  34. require_once DOL_DOCUMENT_ROOT .'/product/class/product.class.php';
  35. require_once DOL_DOCUMENT_ROOT .'/contact/class/contact.class.php';
  36. require_once DOL_DOCUMENT_ROOT .'/margin/lib/margins.lib.php';
  37. require_once DOL_DOCUMENT_ROOT .'/multicurrency/class/multicurrency.class.php';
  38. /**
  39. * Class to manage price ask supplier
  40. */
  41. class SupplierProposal extends CommonObject
  42. {
  43. public $element='supplier_proposal';
  44. public $table_element='supplier_proposal';
  45. public $table_element_line='supplier_proposaldet';
  46. public $fk_element='fk_supplier_proposal';
  47. protected $ismultientitymanaged = 1; // 0=No test on entity, 1=Test with field entity, 2=Test with link by societe
  48. /**
  49. * {@inheritdoc}
  50. */
  51. protected $table_ref_field = 'ref';
  52. var $socid; // Id client
  53. /**
  54. * @deprecated
  55. * @see user_author_id
  56. */
  57. var $author;
  58. var $ref_fourn; //Reference saisie lors de l'ajout d'une ligne à la demande
  59. var $statut; // 0 (draft), 1 (validated), 2 (signed), 3 (not signed), 4 (processed/billed)
  60. var $date; // Date of proposal
  61. var $date_livraison;
  62. /**
  63. * @deprecated
  64. * @see date_creation
  65. */
  66. var $datec;
  67. /**
  68. * Creation date
  69. * @var int
  70. */
  71. public $date_creation;
  72. /**
  73. * @deprecated
  74. * @see date_validation
  75. */
  76. var $datev;
  77. /**
  78. * Validation date
  79. * @var int
  80. */
  81. public $date_validation;
  82. var $user_author_id;
  83. var $user_valid_id;
  84. var $user_close_id;
  85. /**
  86. * @deprecated
  87. * @see price_ht
  88. */
  89. var $price;
  90. /**
  91. * @deprecated
  92. * @see total_tva
  93. */
  94. var $tva;
  95. /**
  96. * @deprecated
  97. * @see total_ttc
  98. */
  99. var $total;
  100. var $cond_reglement_code;
  101. var $mode_reglement_code;
  102. var $remise;
  103. var $remise_percent;
  104. var $remise_absolue;
  105. var $products=array();
  106. var $extraparams=array();
  107. var $lines = array();
  108. var $line;
  109. var $labelstatut=array();
  110. var $labelstatut_short=array();
  111. var $nbtodo;
  112. var $nbtodolate;
  113. var $specimen;
  114. // Multicurrency
  115. var $fk_multicurrency;
  116. var $multicurrency_code;
  117. var $multicurrency_tx;
  118. var $multicurrency_total_ht;
  119. var $multicurrency_total_tva;
  120. var $multicurrency_total_ttc;
  121. /**
  122. * Draft status
  123. */
  124. const STATUS_DRAFT = 0;
  125. /**
  126. * Validated status
  127. */
  128. const STATUS_VALIDATED = 1;
  129. /**
  130. * Signed quote
  131. */
  132. const STATUS_SIGNED = 2;
  133. /**
  134. * Not signed quote
  135. */
  136. const STATUS_NOTSIGNED = 3;
  137. /**
  138. * Billed or processed quote
  139. */
  140. const STATUS_BILLED = 4;
  141. /**
  142. * Constructor
  143. *
  144. * @param DoliDB $db Database handler
  145. * @param int $socid Id third party
  146. * @param int $supplier_proposalid Id supplier_proposal
  147. */
  148. function __construct($db, $socid="", $supplier_proposalid=0)
  149. {
  150. global $conf,$langs;
  151. $this->db = $db;
  152. $this->socid = $socid;
  153. $this->id = $supplier_proposalid;
  154. $this->products = array();
  155. $this->remise = 0;
  156. $this->remise_percent = 0;
  157. $this->remise_absolue = 0;
  158. $langs->load("supplier_proposal");
  159. $this->labelstatut[0]=$langs->trans("SupplierProposalStatusDraft");
  160. $this->labelstatut[1]=$langs->trans("SupplierProposalStatusValidated");
  161. $this->labelstatut[2]=$langs->trans("SupplierProposalStatusSigned");
  162. $this->labelstatut[3]=$langs->trans("SupplierProposalStatusNotSigned");
  163. $this->labelstatut[4]=$langs->trans("SupplierProposalStatusClosed");
  164. $this->labelstatut_short[0]=$langs->trans("SupplierProposalStatusDraftShort");
  165. $this->labelstatut_short[1]=$langs->trans("Opened");
  166. $this->labelstatut_short[2]=$langs->trans("SupplierProposalStatusSignedShort");
  167. $this->labelstatut_short[3]=$langs->trans("SupplierProposalStatusNotSignedShort");
  168. $this->labelstatut_short[4]=$langs->trans("SupplierProposalStatusClosedShort");
  169. }
  170. /**
  171. * Add line into array products
  172. * $this->client doit etre charge
  173. *
  174. * @param int $idproduct Product Id to add
  175. * @param int $qty Quantity
  176. * @param int $remise_percent Discount effected on Product
  177. * @return int <0 if KO, >0 if OK
  178. *
  179. * TODO Remplacer les appels a cette fonction par generation objet Ligne
  180. * insere dans tableau $this->products
  181. */
  182. function add_product($idproduct, $qty, $remise_percent=0)
  183. {
  184. global $conf, $mysoc;
  185. if (! $qty) $qty = 1;
  186. dol_syslog(get_class($this)."::add_product $idproduct, $qty, $remise_percent");
  187. if ($idproduct > 0)
  188. {
  189. $prod=new Product($this->db);
  190. $prod->fetch($idproduct);
  191. $productdesc = $prod->description;
  192. $tva_tx = get_default_tva($mysoc,$this->thirdparty,$prod->id);
  193. $tva_npr = get_default_npr($mysoc,$this->thirdparty,$prod->id);
  194. if (empty($tva_tx)) $tva_npr=0;
  195. $localtax1_tx = get_localtax($tva_tx,1,$mysoc,$this->thirdparty,$tva_npr);
  196. $localtax2_tx = get_localtax($tva_tx,2,$mysoc,$this->thirdparty,$tva_npr);
  197. // multiprix
  198. if($conf->global->PRODUIT_MULTIPRICES && $this->thirdparty->price_level)
  199. {
  200. $price = $prod->multiprices[$this->thirdparty->price_level];
  201. }
  202. else
  203. {
  204. $price = $prod->price;
  205. }
  206. $line = new SupplierProposalLine($this->db);
  207. $line->fk_product=$idproduct;
  208. $line->desc=$productdesc;
  209. $line->qty=$qty;
  210. $line->subprice=$price;
  211. $line->remise_percent=$remise_percent;
  212. $line->tva_tx=$tva_tx;
  213. $this->lines[]=$line;
  214. }
  215. }
  216. /**
  217. * Adding line of fixed discount in the proposal in DB
  218. *
  219. * @param int $idremise Id of fixed discount
  220. * @return int >0 if OK, <0 if KO
  221. */
  222. function insert_discount($idremise)
  223. {
  224. global $langs;
  225. include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
  226. include_once DOL_DOCUMENT_ROOT.'/core/class/discount.class.php';
  227. $this->db->begin();
  228. $remise=new DiscountAbsolute($this->db);
  229. $result=$remise->fetch($idremise);
  230. if ($result > 0)
  231. {
  232. if ($remise->fk_facture) // Protection against multiple submission
  233. {
  234. $this->error=$langs->trans("ErrorDiscountAlreadyUsed");
  235. $this->db->rollback();
  236. return -5;
  237. }
  238. $supplier_proposalligne=new SupplierProposalLine($this->db);
  239. $supplier_proposalligne->fk_supplier_proposal=$this->id;
  240. $supplier_proposalligne->fk_remise_except=$remise->id;
  241. $supplier_proposalligne->desc=$remise->description; // Description ligne
  242. $supplier_proposalligne->tva_tx=$remise->tva_tx;
  243. $supplier_proposalligne->subprice=-$remise->amount_ht;
  244. $supplier_proposalligne->fk_product=0; // Id produit predefini
  245. $supplier_proposalligne->qty=1;
  246. $supplier_proposalligne->remise=0;
  247. $supplier_proposalligne->remise_percent=0;
  248. $supplier_proposalligne->rang=-1;
  249. $supplier_proposalligne->info_bits=2;
  250. // TODO deprecated
  251. $supplier_proposalligne->price=-$remise->amount_ht;
  252. $supplier_proposalligne->total_ht = -$remise->amount_ht;
  253. $supplier_proposalligne->total_tva = -$remise->amount_tva;
  254. $supplier_proposalligne->total_ttc = -$remise->amount_ttc;
  255. $result=$supplier_proposalligne->insert();
  256. if ($result > 0)
  257. {
  258. $result=$this->update_price(1);
  259. if ($result > 0)
  260. {
  261. $this->db->commit();
  262. return 1;
  263. }
  264. else
  265. {
  266. $this->db->rollback();
  267. return -1;
  268. }
  269. }
  270. else
  271. {
  272. $this->error=$supplier_proposalligne->error;
  273. $this->db->rollback();
  274. return -2;
  275. }
  276. }
  277. else
  278. {
  279. $this->db->rollback();
  280. return -2;
  281. }
  282. }
  283. /**
  284. * Add a proposal line into database (linked to product/service or not)
  285. * Les parametres sont deja cense etre juste et avec valeurs finales a l'appel
  286. * de cette methode. Aussi, pour le taux tva, il doit deja avoir ete defini
  287. * par l'appelant par la methode get_default_tva(societe_vendeuse,societe_acheteuse,'',produit)
  288. * et le desc doit deja avoir la bonne valeur (a l'appelant de gerer le multilangue)
  289. *
  290. * @param string $desc Description de la ligne
  291. * @param double $pu_ht Prix unitaire
  292. * @param double $qty Quantite
  293. * @param double $txtva Taux de tva
  294. * @param double $txlocaltax1 Local tax 1 rate
  295. * @param double $txlocaltax2 Local tax 2 rate
  296. * @param int $fk_product Id du produit/service predefini
  297. * @param double $remise_percent Pourcentage de remise de la ligne
  298. * @param string $price_base_type HT or TTC
  299. * @param double $pu_ttc Prix unitaire TTC
  300. * @param int $info_bits Bits de type de lignes
  301. * @param int $type Type of line (product, service)
  302. * @param int $rang Position of line
  303. * @param int $special_code Special code (also used by externals modules!)
  304. * @param int $fk_parent_line Id of parent line
  305. * @param int $fk_fournprice Id supplier price
  306. * @param int $pa_ht Buying price without tax
  307. * @param string $label ???
  308. * @param array $array_option extrafields array
  309. * @param string $ref_fourn Supplier price reference
  310. * @return int >0 if OK, <0 if KO
  311. *
  312. * @see add_product
  313. */
  314. function addline($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, $fk_fournprice=0, $pa_ht=0, $label='',$array_option=0, $ref_fourn='')
  315. {
  316. global $mysoc;
  317. dol_syslog(get_class($this)."::addline supplier_proposalid=$this->id, 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");
  318. include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
  319. // Clean parameters
  320. if (empty($remise_percent)) $remise_percent=0;
  321. if (empty($qty)) $qty=0;
  322. if (empty($info_bits)) $info_bits=0;
  323. if (empty($rang)) $rang=0;
  324. if (empty($fk_parent_line) || $fk_parent_line < 0) $fk_parent_line=0;
  325. $remise_percent=price2num($remise_percent);
  326. $qty=price2num($qty);
  327. $pu_ht=price2num($pu_ht);
  328. $pu_ttc=price2num($pu_ttc);
  329. $txtva=price2num($txtva);
  330. $txlocaltax1=price2num($txlocaltax1);
  331. $txlocaltax2=price2num($txlocaltax2);
  332. $pa_ht=price2num($pa_ht);
  333. if ($price_base_type=='HT')
  334. {
  335. $pu=$pu_ht;
  336. }
  337. else
  338. {
  339. $pu=$pu_ttc;
  340. }
  341. // Check parameters
  342. if ($type < 0) return -1;
  343. if ($this->statut == 0)
  344. {
  345. $this->db->begin();
  346. // Calcul du total TTC et de la TVA pour la ligne a partir de
  347. // qty, pu, remise_percent et txtva
  348. // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
  349. // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
  350. $localtaxes_type=getLocalTaxesFromRate($txtva,0,$this->thirdparty,$mysoc);
  351. $txtva = preg_replace('/\s*\(.*\)/','',$txtva); // Remove code into vatrate.
  352. $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $this->thirdparty, $localtaxes_type, 100, $this->multicurrency_tx);
  353. $total_ht = $tabprice[0];
  354. $total_tva = $tabprice[1];
  355. $total_ttc = $tabprice[2];
  356. $total_localtax1 = $tabprice[9];
  357. $total_localtax2 = $tabprice[10];
  358. // MultiCurrency
  359. $multicurrency_total_ht = $tabprice[16];
  360. $multicurrency_total_tva = $tabprice[17];
  361. $multicurrency_total_ttc = $tabprice[18];
  362. // Rang to use
  363. $rangtouse = $rang;
  364. if ($rangtouse == -1)
  365. {
  366. $rangmax = $this->line_max($fk_parent_line);
  367. $rangtouse = $rangmax + 1;
  368. }
  369. // TODO A virer
  370. // Anciens indicateurs: $price, $remise (a ne plus utiliser)
  371. $price = $pu;
  372. $remise = 0;
  373. if ($remise_percent > 0)
  374. {
  375. $remise = round(($pu * $remise_percent / 100), 2);
  376. $price = $pu - $remise;
  377. }
  378. // Insert line
  379. $this->line=new SupplierProposalLine($this->db);
  380. $this->line->fk_supplier_proposal=$this->id;
  381. $this->line->label=$label;
  382. $this->line->desc=$desc;
  383. $this->line->qty=$qty;
  384. $this->line->tva_tx=$txtva;
  385. $this->line->localtax1_tx=$txlocaltax1;
  386. $this->line->localtax2_tx=$txlocaltax2;
  387. $this->line->localtax1_type = $localtaxes_type[0];
  388. $this->line->localtax2_type = $localtaxes_type[2];
  389. $this->line->fk_product=$fk_product;
  390. $this->line->remise_percent=$remise_percent;
  391. $this->line->subprice=$pu_ht;
  392. $this->line->rang=$rangtouse;
  393. $this->line->info_bits=$info_bits;
  394. $this->line->total_ht=$total_ht;
  395. $this->line->total_tva=$total_tva;
  396. $this->line->total_localtax1=$total_localtax1;
  397. $this->line->total_localtax2=$total_localtax2;
  398. $this->line->total_ttc=$total_ttc;
  399. $this->line->product_type=$type;
  400. $this->line->special_code=$special_code;
  401. $this->line->fk_parent_line=$fk_parent_line;
  402. $this->line->ref_fourn = $this->db->escape($ref_fourn);
  403. // infos marge
  404. if (!empty($fk_product) && empty($fk_fournprice) && empty($pa_ht)) {
  405. // by external module, take lowest buying price
  406. include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
  407. $productFournisseur = new ProductFournisseur($this->db);
  408. $productFournisseur->find_min_price_product_fournisseur($fk_product);
  409. $this->line->fk_fournprice = $productFournisseur->product_fourn_price_id;
  410. } else {
  411. $this->line->fk_fournprice = $fk_fournprice;
  412. }
  413. $this->line->pa_ht = $pa_ht;
  414. // Multicurrency
  415. $this->line->fk_multicurrency = $this->fk_multicurrency;
  416. $this->line->multicurrency_code = $this->multicurrency_code;
  417. $this->line->multicurrency_subprice = price2num($pu_ht * $this->multicurrency_tx);
  418. $this->line->multicurrency_total_ht = $multicurrency_total_ht;
  419. $this->line->multicurrency_total_tva = $multicurrency_total_tva;
  420. $this->line->multicurrency_total_ttc = $multicurrency_total_ttc;
  421. // Mise en option de la ligne
  422. if (empty($qty) && empty($special_code)) $this->line->special_code=3;
  423. // TODO deprecated
  424. $this->line->price=$price;
  425. $this->line->remise=$remise;
  426. if (is_array($array_option) && count($array_option)>0) {
  427. $this->line->array_options=$array_option;
  428. }
  429. $result=$this->line->insert();
  430. if ($result > 0)
  431. {
  432. // Reorder if child line
  433. if (! empty($fk_parent_line)) $this->line_order(true,'DESC');
  434. // Mise a jour informations denormalisees au niveau de la propale meme
  435. $result=$this->update_price(1,'auto'); // This method is designed to add line from user input so total calculation must be done using 'auto' mode.
  436. if ($result > 0)
  437. {
  438. $this->db->commit();
  439. return $this->line->rowid;
  440. }
  441. else
  442. {
  443. $this->error=$this->db->error();
  444. $this->db->rollback();
  445. return -1;
  446. }
  447. }
  448. else
  449. {
  450. $this->error=$this->line->error;
  451. $this->db->rollback();
  452. return -2;
  453. }
  454. }
  455. }
  456. /**
  457. * Update a proposal line
  458. *
  459. * @param int $rowid Id de la ligne
  460. * @param double $pu Prix unitaire (HT ou TTC selon price_base_type)
  461. * @param double $qty Quantity
  462. * @param double $remise_percent Remise effectuee sur le produit
  463. * @param double $txtva Taux de TVA
  464. * @param double $txlocaltax1 Local tax 1 rate
  465. * @param double $txlocaltax2 Local tax 2 rate
  466. * @param string $desc Description
  467. * @param double $price_base_type HT ou TTC
  468. * @param int $info_bits Miscellaneous informations
  469. * @param int $special_code Special code (also used by externals modules!)
  470. * @param int $fk_parent_line Id of parent line (0 in most cases, used by modules adding sublevels into lines).
  471. * @param int $skip_update_total Keep fields total_xxx to 0 (used for special lines by some modules)
  472. * @param int $fk_fournprice Id of origin supplier price
  473. * @param int $pa_ht Price (without tax) of product when it was bought
  474. * @param string $label ???
  475. * @param int $type 0/1=Product/service
  476. * @param array $array_option extrafields array
  477. * @param string $ref_fourn Supplier price reference
  478. * @return int 0 if OK, <0 if KO
  479. */
  480. function updateline($rowid, $pu, $qty, $remise_percent, $txtva, $txlocaltax1=0, $txlocaltax2=0, $desc='', $price_base_type='HT', $info_bits=0, $special_code=0, $fk_parent_line=0, $skip_update_total=0, $fk_fournprice=0, $pa_ht=0, $label='', $type=0, $array_option=0, $ref_fourn='')
  481. {
  482. global $conf,$user,$langs, $mysoc;
  483. dol_syslog(get_class($this)."::updateLine $rowid, $pu, $qty, $remise_percent, $txtva, $desc, $price_base_type, $info_bits");
  484. include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php';
  485. // Clean parameters
  486. $remise_percent=price2num($remise_percent);
  487. $qty=price2num($qty);
  488. $pu = price2num($pu);
  489. $txtva = price2num($txtva);
  490. $txlocaltax1=price2num($txlocaltax1);
  491. $txlocaltax2=price2num($txlocaltax2);
  492. $pa_ht=price2num($pa_ht);
  493. if (empty($qty) && empty($special_code)) $special_code=3; // Set option tag
  494. if (! empty($qty) && $special_code == 3) $special_code=0; // Remove option tag
  495. if ($this->statut == 0)
  496. {
  497. $this->db->begin();
  498. // Calcul du total TTC et de la TVA pour la ligne a partir de
  499. // qty, pu, remise_percent et txtva
  500. // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
  501. // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
  502. $localtaxes_type=getLocalTaxesFromRate($txtva,0,$this->thirdparty,$mysoc);
  503. $txtva = preg_replace('/\s*\(.*\)/','',$txtva); // Remove code into vatrate.
  504. $tabprice=calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $type, $this->thirdparty, $localtaxes_type, 100, $this->multicurrency_tx);
  505. $total_ht = $tabprice[0];
  506. $total_tva = $tabprice[1];
  507. $total_ttc = $tabprice[2];
  508. $total_localtax1 = $tabprice[9];
  509. $total_localtax2 = $tabprice[10];
  510. // MultiCurrency
  511. $multicurrency_total_ht = $tabprice[16];
  512. $multicurrency_total_tva = $tabprice[17];
  513. $multicurrency_total_ttc = $tabprice[18];
  514. // Anciens indicateurs: $price, $remise (a ne plus utiliser)
  515. $price = $pu;
  516. if ($remise_percent > 0)
  517. {
  518. $remise = round(($pu * $remise_percent / 100), 2);
  519. $price = $pu - $remise;
  520. }
  521. // Update line
  522. $this->line=new SupplierProposalLine($this->db);
  523. // Stock previous line records
  524. $staticline=new SupplierProposalLine($this->db);
  525. $staticline->fetch($rowid);
  526. $this->line->oldline = $staticline;
  527. // Reorder if fk_parent_line change
  528. if (! empty($fk_parent_line) && ! empty($staticline->fk_parent_line) && $fk_parent_line != $staticline->fk_parent_line)
  529. {
  530. $rangmax = $this->line_max($fk_parent_line);
  531. $this->line->rang = $rangmax + 1;
  532. }
  533. $this->line->rowid = $rowid;
  534. $this->line->label = $label;
  535. $this->line->desc = $desc;
  536. $this->line->qty = $qty;
  537. $this->line->product_type = $type;
  538. $this->line->tva_tx = $txtva;
  539. $this->line->localtax1_tx = $txlocaltax1;
  540. $this->line->localtax2_tx = $txlocaltax2;
  541. $this->line->localtax1_type = $localtaxes_type[0];
  542. $this->line->localtax2_type = $localtaxes_type[2];
  543. $this->line->remise_percent = $remise_percent;
  544. $this->line->subprice = $pu;
  545. $this->line->info_bits = $info_bits;
  546. $this->line->total_ht = $total_ht;
  547. $this->line->total_tva = $total_tva;
  548. $this->line->total_localtax1 = $total_localtax1;
  549. $this->line->total_localtax2 = $total_localtax2;
  550. $this->line->total_ttc = $total_ttc;
  551. $this->line->special_code = $special_code;
  552. $this->line->fk_parent_line = $fk_parent_line;
  553. $this->line->skip_update_total = $skip_update_total;
  554. $this->line->ref_fourn = $ref_fourn;
  555. // infos marge
  556. if (!empty($fk_product) && empty($fk_fournprice) && empty($pa_ht)) {
  557. // by external module, take lowest buying price
  558. include_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php';
  559. $productFournisseur = new ProductFournisseur($this->db);
  560. $productFournisseur->find_min_price_product_fournisseur($fk_product);
  561. $this->line->fk_fournprice = $productFournisseur->product_fourn_price_id;
  562. } else {
  563. $this->line->fk_fournprice = $fk_fournprice;
  564. }
  565. $this->line->pa_ht = $pa_ht;
  566. // TODO deprecated
  567. $this->line->price=$price;
  568. $this->line->remise=$remise;
  569. if (is_array($array_option) && count($array_option)>0) {
  570. $this->line->array_options=$array_option;
  571. }
  572. // Multicurrency
  573. $this->line->multicurrency_subprice = price2num($pu * $this->multicurrency_tx);
  574. $this->line->multicurrency_total_ht = $multicurrency_total_ht;
  575. $this->line->multicurrency_total_tva = $multicurrency_total_tva;
  576. $this->line->multicurrency_total_ttc = $multicurrency_total_ttc;
  577. $result=$this->line->update();
  578. if ($result > 0)
  579. {
  580. // Reorder if child line
  581. if (! empty($fk_parent_line)) $this->line_order(true,'DESC');
  582. $this->update_price(1);
  583. $this->fk_supplier_proposal = $this->id;
  584. $this->rowid = $rowid;
  585. $this->db->commit();
  586. return $result;
  587. }
  588. else
  589. {
  590. $this->error=$this->db->error();
  591. $this->db->rollback();
  592. return -1;
  593. }
  594. }
  595. else
  596. {
  597. dol_syslog(get_class($this)."::updateline Erreur -2 SupplierProposal en mode incompatible pour cette action");
  598. return -2;
  599. }
  600. }
  601. /**
  602. * Delete detail line
  603. *
  604. * @param int $lineid Id of line to delete
  605. * @return int >0 if OK, <0 if KO
  606. */
  607. function deleteline($lineid)
  608. {
  609. if ($this->statut == 0)
  610. {
  611. $line=new SupplierProposalLine($this->db);
  612. // For triggers
  613. $line->fetch($lineid);
  614. if ($line->delete() > 0)
  615. {
  616. $this->update_price(1);
  617. return 1;
  618. }
  619. else
  620. {
  621. return -1;
  622. }
  623. }
  624. else
  625. {
  626. return -2;
  627. }
  628. }
  629. /**
  630. * Create commercial proposal into database
  631. * this->ref can be set or empty. If empty, we will use "(PROVid)"
  632. *
  633. * @param User $user User that create
  634. * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers
  635. * @return int <0 if KO, >=0 if OK
  636. */
  637. function create($user, $notrigger=0)
  638. {
  639. global $langs,$conf,$mysoc,$hookmanager;
  640. $error=0;
  641. $now=dol_now();
  642. dol_syslog(get_class($this)."::create");
  643. // Check parameters
  644. $result=$this->fetch_thirdparty();
  645. if ($result < 0)
  646. {
  647. $this->error="Failed to fetch company";
  648. dol_syslog(get_class($this)."::create ".$this->error, LOG_ERR);
  649. return -3;
  650. }
  651. // Check parameters
  652. if (! empty($this->ref)) // We check that ref is not already used
  653. {
  654. $result=self::isExistingObject($this->element, 0, $this->ref); // Check ref is not yet used
  655. if ($result > 0)
  656. {
  657. $this->error='ErrorRefAlreadyExists';
  658. dol_syslog(get_class($this)."::create ".$this->error,LOG_WARNING);
  659. $this->db->rollback();
  660. return -1;
  661. }
  662. }
  663. // Multicurrency
  664. if (!empty($this->multicurrency_code)) list($this->fk_multicurrency,$this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code);
  665. if (empty($this->fk_multicurrency))
  666. {
  667. $this->multicurrency_code = $conf->currency;
  668. $this->fk_multicurrency = 0;
  669. $this->multicurrency_tx = 1;
  670. }
  671. $this->db->begin();
  672. // Insert into database
  673. $sql = "INSERT INTO ".MAIN_DB_PREFIX."supplier_proposal (";
  674. $sql.= "fk_soc";
  675. $sql.= ", price";
  676. $sql.= ", remise";
  677. $sql.= ", remise_percent";
  678. $sql.= ", remise_absolue";
  679. $sql.= ", tva";
  680. $sql.= ", total";
  681. $sql.= ", datec";
  682. $sql.= ", ref";
  683. $sql.= ", fk_user_author";
  684. $sql.= ", note_private";
  685. $sql.= ", note_public";
  686. $sql.= ", model_pdf";
  687. $sql.= ", fk_cond_reglement";
  688. $sql.= ", fk_mode_reglement";
  689. $sql.= ", fk_account";
  690. $sql.= ", date_livraison";
  691. $sql.= ", fk_shipping_method";
  692. $sql.= ", fk_projet";
  693. $sql.= ", entity";
  694. $sql.= ", fk_multicurrency";
  695. $sql.= ", multicurrency_code";
  696. $sql.= ", multicurrency_tx";
  697. $sql.= ") ";
  698. $sql.= " VALUES (";
  699. $sql.= $this->socid;
  700. $sql.= ", 0";
  701. $sql.= ", ".$this->remise;
  702. $sql.= ", ".($this->remise_percent?$this->db->escape($this->remise_percent):'null');
  703. $sql.= ", ".($this->remise_absolue?$this->db->escape($this->remise_absolue):'null');
  704. $sql.= ", 0";
  705. $sql.= ", 0";
  706. $sql.= ", '".$this->db->idate($now)."'";
  707. $sql.= ", '(PROV)'";
  708. $sql.= ", ".($user->id > 0 ? "'".$user->id."'":"null");
  709. $sql.= ", '".$this->db->escape($this->note_private)."'";
  710. $sql.= ", '".$this->db->escape($this->note_public)."'";
  711. $sql.= ", '".$this->db->escape($this->modelpdf)."'";
  712. $sql.= ", ".$this->cond_reglement_id;
  713. $sql.= ", ".$this->mode_reglement_id;
  714. $sql.= ", ".($this->fk_account>0?$this->fk_account:'NULL');
  715. $sql.= ", ".($this->date_livraison!=''?"'".$this->db->idate($this->date_livraison)."'":"null");
  716. $sql.= ", ".($this->shipping_method_id>0?$this->shipping_method_id:'NULL');
  717. $sql.= ", ".($this->fk_project?$this->fk_project:"null");
  718. $sql.= ", ".$conf->entity;
  719. $sql.= ", ".(int) $this->fk_multicurrency;
  720. $sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
  721. $sql.= ", ".(double) $this->multicurrency_tx;
  722. $sql.= ")";
  723. dol_syslog(get_class($this)."::create", LOG_DEBUG);
  724. $resql=$this->db->query($sql);
  725. if ($resql)
  726. {
  727. $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."supplier_proposal");
  728. if ($this->id)
  729. {
  730. $this->ref='(PROV'.$this->id.')';
  731. $sql = 'UPDATE '.MAIN_DB_PREFIX."supplier_proposal SET ref='".$this->ref."' WHERE rowid=".$this->id;
  732. dol_syslog(get_class($this)."::create", LOG_DEBUG);
  733. $resql=$this->db->query($sql);
  734. if (! $resql) $error++;
  735. /*
  736. * Insertion du detail des produits dans la base
  737. */
  738. if (! $error)
  739. {
  740. $fk_parent_line=0;
  741. $num=count($this->lines);
  742. for ($i=0;$i<$num;$i++)
  743. {
  744. // Reset fk_parent_line for no child products and special product
  745. if (($this->lines[$i]->product_type != 9 && empty($this->lines[$i]->fk_parent_line)) || $this->lines[$i]->product_type == 9) {
  746. $fk_parent_line = 0;
  747. }
  748. $result = $this->addline(
  749. $this->lines[$i]->desc,
  750. $this->lines[$i]->subprice,
  751. $this->lines[$i]->qty,
  752. $this->lines[$i]->tva_tx,
  753. $this->lines[$i]->localtax1_tx,
  754. $this->lines[$i]->localtax2_tx,
  755. $this->lines[$i]->fk_product,
  756. $this->lines[$i]->remise_percent,
  757. 'HT',
  758. 0,
  759. 0,
  760. $this->lines[$i]->product_type,
  761. $this->lines[$i]->rang,
  762. $this->lines[$i]->special_code,
  763. $fk_parent_line,
  764. $this->lines[$i]->fk_fournprice,
  765. $this->lines[$i]->pa_ht,
  766. $this->lines[$i]->label,
  767. $this->lines[$i]->array_options,
  768. $this->lines[$i]->ref_fourn
  769. );
  770. if ($result < 0)
  771. {
  772. $error++;
  773. $this->error=$this->db->error;
  774. dol_print_error($this->db);
  775. break;
  776. }
  777. // Defined the new fk_parent_line
  778. if ($result > 0 && $this->lines[$i]->product_type == 9) {
  779. $fk_parent_line = $result;
  780. }
  781. }
  782. }
  783. // Add linked object
  784. if (! $error && $this->origin && $this->origin_id)
  785. {
  786. $ret = $this->add_object_linked();
  787. if (! $ret) dol_print_error($this->db);
  788. }
  789. if (! $error)
  790. {
  791. // Mise a jour infos denormalisees
  792. $resql=$this->update_price(1);
  793. if ($resql)
  794. {
  795. $action='update';
  796. // Actions on extra fields (by external module or standard code)
  797. $hookmanager->initHooks(array('supplier_proposaldao'));
  798. $parameters=array('socid'=>$this->id);
  799. $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks
  800. if (empty($reshook))
  801. {
  802. if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
  803. {
  804. $result=$this->insertExtraFields();
  805. if ($result < 0)
  806. {
  807. $error++;
  808. }
  809. }
  810. }
  811. else if ($reshook < 0) $error++;
  812. if (! $notrigger)
  813. {
  814. // Call trigger
  815. $result=$this->call_trigger('SUPPLIER_PROPOSAL_CREATE',$user);
  816. if ($result < 0) { $error++; }
  817. // End call triggers
  818. }
  819. }
  820. else
  821. {
  822. $this->error=$this->db->lasterror();
  823. $error++;
  824. }
  825. }
  826. }
  827. else
  828. {
  829. $this->error=$this->db->lasterror();
  830. $error++;
  831. }
  832. if (! $error)
  833. {
  834. $this->db->commit();
  835. dol_syslog(get_class($this)."::create done id=".$this->id);
  836. return $this->id;
  837. }
  838. else
  839. {
  840. $this->db->rollback();
  841. return -2;
  842. }
  843. }
  844. else
  845. {
  846. $this->error=$this->db->lasterror();
  847. $this->db->rollback();
  848. return -1;
  849. }
  850. }
  851. /**
  852. * Insert into DB a supplier_proposal object completely defined by its data members (ex, results from copy).
  853. *
  854. * @param User $user User that create
  855. * @return int Id of the new object if ok, <0 if ko
  856. * @see create
  857. */
  858. function create_from($user)
  859. {
  860. $this->products=$this->lines;
  861. return $this->create($user);
  862. }
  863. /**
  864. * Load an object from its id and create a new one in database
  865. *
  866. * @param int $socid Id of thirdparty
  867. * @return int New id of clone
  868. */
  869. function createFromClone($socid=0)
  870. {
  871. global $user,$langs,$conf,$hookmanager;
  872. $error=0;
  873. $now=dol_now();
  874. $this->db->begin();
  875. // get extrafields so they will be clone
  876. foreach($this->lines as $line)
  877. $line->fetch_optionals($line->rowid);
  878. // Load source object
  879. $objFrom = clone $this;
  880. $objsoc=new Societe($this->db);
  881. // Change socid if needed
  882. if (! empty($socid) && $socid != $this->socid)
  883. {
  884. if ($objsoc->fetch($socid) > 0)
  885. {
  886. $this->socid = $objsoc->id;
  887. $this->cond_reglement_id = (! empty($objsoc->cond_reglement_id) ? $objsoc->cond_reglement_id : 0);
  888. $this->mode_reglement_id = (! empty($objsoc->mode_reglement_id) ? $objsoc->mode_reglement_id : 0);
  889. $this->fk_project = '';
  890. }
  891. // TODO Change product price if multi-prices
  892. }
  893. else
  894. {
  895. $objsoc->fetch($this->socid);
  896. }
  897. $this->id=0;
  898. $this->statut=0;
  899. if (empty($conf->global->SUPPLIER_PROPOSAL_ADDON) || ! is_readable(DOL_DOCUMENT_ROOT ."/core/modules/supplier_proposal/".$conf->global->SUPPLIER_PROPOSAL_ADDON.".php"))
  900. {
  901. $this->error='ErrorSetupNotComplete';
  902. return -1;
  903. }
  904. // Clear fields
  905. $this->user_author = $user->id;
  906. $this->user_valid = '';
  907. $this->date = $now;
  908. // Set ref
  909. require_once DOL_DOCUMENT_ROOT ."/core/modules/supplier_proposal/".$conf->global->SUPPLIER_PROPOSAL_ADDON.'.php';
  910. $obj = $conf->global->SUPPLIER_PROPOSAL_ADDON;
  911. $modSupplierProposal = new $obj;
  912. $this->ref = $modSupplierProposal->getNextValue($objsoc,$this);
  913. // Create clone
  914. $result=$this->create($user);
  915. if ($result < 0) $error++;
  916. if (! $error)
  917. {
  918. // Hook of thirdparty module
  919. if (is_object($hookmanager))
  920. {
  921. $parameters=array('objFrom'=>$objFrom);
  922. $action='';
  923. $reshook=$hookmanager->executeHooks('createFrom',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks
  924. if ($reshook < 0) $error++;
  925. }
  926. // Call trigger
  927. $result=$this->call_trigger('SUPPLIER_PROPOSAL_CLONE',$user);
  928. if ($result < 0) { $error++; }
  929. // End call triggers
  930. }
  931. // End
  932. if (! $error)
  933. {
  934. $this->db->commit();
  935. return $this->id;
  936. }
  937. else
  938. {
  939. $this->db->rollback();
  940. return -1;
  941. }
  942. }
  943. /**
  944. * Load a proposal from database and its ligne array
  945. *
  946. * @param int $rowid id of object to load
  947. * @param string $ref Ref of proposal
  948. * @return int >0 if OK, <0 if KO
  949. */
  950. function fetch($rowid,$ref='')
  951. {
  952. global $conf;
  953. $sql = "SELECT p.rowid, p.ref, p.remise, p.remise_percent, p.remise_absolue, p.fk_soc";
  954. $sql.= ", p.total, p.tva, p.localtax1, p.localtax2, p.total_ht";
  955. $sql.= ", p.datec";
  956. $sql.= ", p.date_valid as datev";
  957. $sql.= ", p.date_livraison as date_livraison";
  958. $sql.= ", p.model_pdf, p.extraparams";
  959. $sql.= ", p.note_private, p.note_public";
  960. $sql.= ", p.fk_projet, p.fk_statut";
  961. $sql.= ", p.fk_user_author, p.fk_user_valid, p.fk_user_cloture";
  962. $sql.= ", p.fk_cond_reglement";
  963. $sql.= ", p.fk_mode_reglement";
  964. $sql.= ', p.fk_account';
  965. $sql.= ", p.fk_shipping_method";
  966. $sql.= ", p.fk_multicurrency, p.multicurrency_code, p.multicurrency_tx, p.multicurrency_total_ht, p.multicurrency_total_tva, p.multicurrency_total_ttc";
  967. $sql.= ", c.label as statut_label";
  968. $sql.= ", cr.code as cond_reglement_code, cr.libelle as cond_reglement, cr.libelle_facture as cond_reglement_libelle_doc";
  969. $sql.= ", cp.code as mode_reglement_code, cp.libelle as mode_reglement";
  970. $sql.= " FROM ".MAIN_DB_PREFIX."c_propalst as c, ".MAIN_DB_PREFIX."supplier_proposal as p";
  971. $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_paiement as cp ON p.fk_mode_reglement = cp.id';
  972. $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'c_payment_term as cr ON p.fk_cond_reglement = cr.rowid';
  973. $sql.= " WHERE p.fk_statut = c.id";
  974. $sql.= " AND p.entity = ".$conf->entity;
  975. if ($ref) $sql.= " AND p.ref='".$ref."'";
  976. else $sql.= " AND p.rowid=".$rowid;
  977. dol_syslog(get_class($this)."::fetch", LOG_DEBUG);
  978. $resql=$this->db->query($sql);
  979. if ($resql)
  980. {
  981. if ($this->db->num_rows($resql))
  982. {
  983. $obj = $this->db->fetch_object($resql);
  984. $this->id = $obj->rowid;
  985. $this->ref = $obj->ref;
  986. $this->remise = $obj->remise;
  987. $this->remise_percent = $obj->remise_percent;
  988. $this->remise_absolue = $obj->remise_absolue;
  989. $this->total = $obj->total; // TODO deprecated
  990. $this->total_ht = $obj->total_ht;
  991. $this->total_tva = $obj->tva;
  992. $this->total_localtax1 = $obj->localtax1;
  993. $this->total_localtax2 = $obj->localtax2;
  994. $this->total_ttc = $obj->total;
  995. $this->socid = $obj->fk_soc;
  996. $this->fk_project = $obj->fk_projet;
  997. $this->modelpdf = $obj->model_pdf;
  998. $this->note = $obj->note_private; // TODO deprecated
  999. $this->note_private = $obj->note_private;
  1000. $this->note_public = $obj->note_public;
  1001. $this->statut = $obj->fk_statut;
  1002. $this->statut_libelle = $obj->statut_label;
  1003. $this->datec = $this->db->jdate($obj->datec); // TODO deprecated
  1004. $this->datev = $this->db->jdate($obj->datev); // TODO deprecated
  1005. $this->date_creation = $this->db->jdate($obj->datec); //Creation date
  1006. $this->date_validation = $this->db->jdate($obj->datev); //Validation date
  1007. $this->date_livraison = $this->db->jdate($obj->date_livraison);
  1008. $this->shipping_method_id = ($obj->fk_shipping_method>0)?$obj->fk_shipping_method:null;
  1009. $this->mode_reglement_id = $obj->fk_mode_reglement;
  1010. $this->mode_reglement_code = $obj->mode_reglement_code;
  1011. $this->mode_reglement = $obj->mode_reglement;
  1012. $this->fk_account = ($obj->fk_account>0)?$obj->fk_account:null;
  1013. $this->cond_reglement_id = $obj->fk_cond_reglement;
  1014. $this->cond_reglement_code = $obj->cond_reglement_code;
  1015. $this->cond_reglement = $obj->cond_reglement;
  1016. $this->cond_reglement_doc = $obj->cond_reglement_libelle_doc;
  1017. $this->extraparams = (array) json_decode($obj->extraparams, true);
  1018. $this->user_author_id = $obj->fk_user_author;
  1019. $this->user_valid_id = $obj->fk_user_valid;
  1020. $this->user_close_id = $obj->fk_user_cloture;
  1021. // Multicurrency
  1022. $this->fk_multicurrency = $obj->fk_multicurrency;
  1023. $this->multicurrency_code = $obj->multicurrency_code;
  1024. $this->multicurrency_tx = $obj->multicurrency_tx;
  1025. $this->multicurrency_total_ht = $obj->multicurrency_total_ht;
  1026. $this->multicurrency_total_tva = $obj->multicurrency_total_tva;
  1027. $this->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
  1028. if ($obj->fk_statut == 0)
  1029. {
  1030. $this->brouillon = 1;
  1031. }
  1032. // Retreive all extrafield for invoice
  1033. // fetch optionals attributes and labels
  1034. require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
  1035. $extrafields=new ExtraFields($this->db);
  1036. $extralabels=$extrafields->fetch_name_optionals_label($this->table_element,true);
  1037. $this->fetch_optionals($this->id,$extralabels);
  1038. $this->db->free($resql);
  1039. $this->lines = array();
  1040. /*
  1041. * Lignes askprice liees a un produit ou non
  1042. */
  1043. $sql = "SELECT d.rowid, d.fk_supplier_proposal, d.fk_parent_line, d.label as custom_label, 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,";
  1044. $sql.= " d.info_bits, d.total_ht, d.total_tva, d.total_localtax1, d.total_localtax2, d.total_ttc, d.fk_product_fournisseur_price as fk_fournprice, d.buy_price_ht as pa_ht, d.special_code, d.rang, d.product_type,";
  1045. $sql.= ' p.ref as product_ref, p.description as product_desc, p.fk_product_type, p.label as product_label,';
  1046. $sql.= ' d.ref_fourn as ref_produit_fourn';
  1047. $sql.= ' ,d.fk_multicurrency, d.multicurrency_code, d.multicurrency_subprice, d.multicurrency_total_ht, d.multicurrency_total_tva, d.multicurrency_total_ttc';
  1048. $sql.= " FROM ".MAIN_DB_PREFIX."supplier_proposaldet as d";
  1049. $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."product as p ON d.fk_product = p.rowid";
  1050. $sql.= " WHERE d.fk_supplier_proposal = ".$this->id;
  1051. $sql.= " ORDER by d.rang";
  1052. $result = $this->db->query($sql);
  1053. if ($result)
  1054. {
  1055. $num = $this->db->num_rows($result);
  1056. $i = 0;
  1057. while ($i < $num)
  1058. {
  1059. $objp = $this->db->fetch_object($result);
  1060. $line = new SupplierProposalLine($this->db);
  1061. $line->rowid = $objp->rowid; // deprecated
  1062. $line->id = $objp->rowid;
  1063. $line->fk_supplier_proposal = $objp->fk_supplier_proposal;
  1064. $line->fk_parent_line = $objp->fk_parent_line;
  1065. $line->product_type = $objp->product_type;
  1066. $line->label = $objp->custom_label;
  1067. $line->desc = $objp->description; // Description ligne
  1068. $line->qty = $objp->qty;
  1069. $line->tva_tx = $objp->tva_tx;
  1070. $line->localtax1_tx = $objp->localtax1_tx;
  1071. $line->localtax2_tx = $objp->localtax2_tx;
  1072. $line->subprice = $objp->subprice;
  1073. $line->fk_remise_except = $objp->fk_remise_except;
  1074. $line->remise_percent = $objp->remise_percent;
  1075. $line->price = $objp->price; // TODO deprecated
  1076. $line->info_bits = $objp->info_bits;
  1077. $line->total_ht = $objp->total_ht;
  1078. $line->total_tva = $objp->total_tva;
  1079. $line->total_localtax1 = $objp->total_localtax1;
  1080. $line->total_localtax2 = $objp->total_localtax2;
  1081. $line->total_ttc = $objp->total_ttc;
  1082. $line->fk_fournprice = $objp->fk_fournprice;
  1083. $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $line->fk_fournprice, $objp->pa_ht);
  1084. $line->pa_ht = $marginInfos[0];
  1085. $line->marge_tx = $marginInfos[1];
  1086. $line->marque_tx = $marginInfos[2];
  1087. $line->special_code = $objp->special_code;
  1088. $line->rang = $objp->rang;
  1089. $line->fk_product = $objp->fk_product;
  1090. $line->ref = $objp->product_ref; // TODO deprecated
  1091. $line->product_ref = $objp->product_ref;
  1092. $line->libelle = $objp->product_label; // TODO deprecated
  1093. $line->product_label = $objp->product_label;
  1094. $line->product_desc = $objp->product_desc; // Description produit
  1095. $line->fk_product_type = $objp->fk_product_type;
  1096. $line->ref_fourn = $objp->ref_produit_fourn;
  1097. // Multicurrency
  1098. $line->fk_multicurrency = $objp->fk_multicurrency;
  1099. $line->multicurrency_code = $objp->multicurrency_code;
  1100. $line->multicurrency_subprice = $objp->multicurrency_subprice;
  1101. $line->multicurrency_total_ht = $objp->multicurrency_total_ht;
  1102. $line->multicurrency_total_tva = $objp->multicurrency_total_tva;
  1103. $line->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
  1104. $this->lines[$i] = $line;
  1105. $i++;
  1106. }
  1107. $this->db->free($result);
  1108. }
  1109. else
  1110. {
  1111. $this->error=$this->db->error();
  1112. return -1;
  1113. }
  1114. // Retreive all extrafield for askprice
  1115. // fetch optionals attributes and labels
  1116. require_once DOL_DOCUMENT_ROOT.'/core/class/extrafields.class.php';
  1117. $extrafields=new ExtraFields($this->db);
  1118. $extralabels=$extrafields->fetch_name_optionals_label($this->table_element,true);
  1119. $this->fetch_optionals($this->id,$extralabels);
  1120. return 1;
  1121. }
  1122. $this->error="Record Not Found";
  1123. return 0;
  1124. }
  1125. else
  1126. {
  1127. $this->error=$this->db->error();
  1128. return -1;
  1129. }
  1130. }
  1131. /**
  1132. * Update value of extrafields on the proposal
  1133. *
  1134. * @param User $user Object user that modify
  1135. * @return int <0 if ko, >0 if ok
  1136. */
  1137. function update_extrafields($user)
  1138. {
  1139. $action='update';
  1140. // Actions on extra fields (by external module or standard code)
  1141. $hookmanager->initHooks(array('supplier_proposaldao'));
  1142. $parameters=array('id'=>$this->id);
  1143. $reshook=$hookmanager->executeHooks('insertExtraFields',$parameters,$this,$action); // Note that $action and $object may have been modified by some hooks
  1144. if (empty($reshook))
  1145. {
  1146. if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
  1147. {
  1148. $result=$this->insertExtraFields();
  1149. if ($result < 0)
  1150. {
  1151. $error++;
  1152. }
  1153. }
  1154. }
  1155. else if ($reshook < 0) $error++;
  1156. if (!$error)
  1157. {
  1158. return 1;
  1159. }
  1160. else
  1161. {
  1162. return -1;
  1163. }
  1164. }
  1165. /**
  1166. * Set status to validated
  1167. *
  1168. * @param User $user Object user that validate
  1169. * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers
  1170. * @return int <0 if KO, >=0 if OK
  1171. */
  1172. function valid($user, $notrigger=0)
  1173. {
  1174. require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  1175. global $conf,$langs;
  1176. $error=0;
  1177. $now=dol_now();
  1178. if ((empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->supplier_proposal->creer))
  1179. || (! empty($conf->global->MAIN_USE_ADVANCED_PERMS) && ! empty($user->rights->supplier_proposal->validate_advance)))
  1180. {
  1181. $this->db->begin();
  1182. // Numbering module definition
  1183. $soc = new Societe($this->db);
  1184. $soc->fetch($this->socid);
  1185. // Define new ref
  1186. if (! $error && (preg_match('/^[\(]?PROV/i', $this->ref) || empty($this->ref))) // empty should not happened, but when it occurs, the test save life
  1187. {
  1188. $num = $this->getNextNumRef($soc);
  1189. }
  1190. else
  1191. {
  1192. $num = $this->ref;
  1193. }
  1194. $this->newref = $num;
  1195. $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal";
  1196. $sql.= " SET ref = '".$num."',";
  1197. $sql.= " fk_statut = 1, date_valid='".$this->db->idate($now)."', fk_user_valid=".$user->id;
  1198. $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
  1199. dol_syslog(get_class($this)."::valid", LOG_DEBUG);
  1200. $resql=$this->db->query($sql);
  1201. if (! $resql)
  1202. {
  1203. dol_print_error($this->db);
  1204. $error++;
  1205. }
  1206. // Trigger calls
  1207. if (! $error && ! $notrigger)
  1208. {
  1209. // Call trigger
  1210. $result=$this->call_trigger('SUPPLIER_PROPOSAL_VALIDATE',$user);
  1211. if ($result < 0) { $error++; }
  1212. // End call triggers
  1213. }
  1214. if (! $error)
  1215. {
  1216. $this->oldref = $this->ref;
  1217. // Rename directory if dir was a temporary ref
  1218. if (preg_match('/^[\(]?PROV/i', $this->ref))
  1219. {
  1220. // Rename of propal directory ($this->ref = old ref, $num = new ref)
  1221. // to not lose the linked files
  1222. $oldref = dol_sanitizeFileName($this->ref);
  1223. $newref = dol_sanitizeFileName($num);
  1224. $dirsource = $conf->supplier_proposal->dir_output.'/'.$oldref;
  1225. $dirdest = $conf->supplier_proposal->dir_output.'/'.$newref;
  1226. if (file_exists($dirsource))
  1227. {
  1228. dol_syslog(get_class($this)."::validate rename dir ".$dirsource." into ".$dirdest);
  1229. if (@rename($dirsource, $dirdest))
  1230. {
  1231. dol_syslog("Rename ok");
  1232. // Rename docs starting with $oldref with $newref
  1233. $listoffiles=dol_dir_list($conf->supplier_proposal->dir_output.'/'.$newref, 'files', 1, '^'.preg_quote($oldref,'/'));
  1234. foreach($listoffiles as $fileentry)
  1235. {
  1236. $dirsource=$fileentry['name'];
  1237. $dirdest=preg_replace('/^'.preg_quote($oldref,'/').'/',$newref, $dirsource);
  1238. $dirsource=$fileentry['path'].'/'.$dirsource;
  1239. $dirdest=$fileentry['path'].'/'.$dirdest;
  1240. @rename($dirsource, $dirdest);
  1241. }
  1242. }
  1243. }
  1244. }
  1245. $this->ref=$num;
  1246. $this->brouillon=0;
  1247. $this->statut = 1;
  1248. $this->user_valid_id=$user->id;
  1249. $this->datev=$now;
  1250. $this->db->commit();
  1251. return 1;
  1252. }
  1253. else
  1254. {
  1255. $this->db->rollback();
  1256. return -1;
  1257. }
  1258. }
  1259. }
  1260. /**
  1261. * Set delivery date
  1262. *
  1263. * @param User $user Object user that modify
  1264. * @param int $date_livraison Delivery date
  1265. * @return int <0 if ko, >0 if ok
  1266. */
  1267. function set_date_livraison($user, $date_livraison)
  1268. {
  1269. if (! empty($user->rights->supplier_proposal->creer))
  1270. {
  1271. $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal ";
  1272. $sql.= " SET date_livraison = ".($date_livraison!=''?"'".$this->db->idate($date_livraison)."'":'null');
  1273. $sql.= " WHERE rowid = ".$this->id;
  1274. if ($this->db->query($sql))
  1275. {
  1276. $this->date_livraison = $date_livraison;
  1277. return 1;
  1278. }
  1279. else
  1280. {
  1281. $this->error=$this->db->error();
  1282. dol_syslog(get_class($this)."::set_date_livraison Erreur SQL");
  1283. return -1;
  1284. }
  1285. }
  1286. }
  1287. /**
  1288. * Set an overall discount on the proposal
  1289. *
  1290. * @param User $user Object user that modify
  1291. * @param double $remise Amount discount
  1292. * @return int <0 if ko, >0 if ok
  1293. */
  1294. function set_remise_percent($user, $remise)
  1295. {
  1296. $remise=trim($remise)?trim($remise):0;
  1297. if (! empty($user->rights->supplier_proposal->creer))
  1298. {
  1299. $remise = price2num($remise);
  1300. $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal SET remise_percent = ".$remise;
  1301. $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
  1302. if ($this->db->query($sql) )
  1303. {
  1304. $this->remise_percent = $remise;
  1305. $this->update_price(1);
  1306. return 1;
  1307. }
  1308. else
  1309. {
  1310. $this->error=$this->db->error();
  1311. return -1;
  1312. }
  1313. }
  1314. }
  1315. /**
  1316. * Set an absolute overall discount on the proposal
  1317. *
  1318. * @param User $user Object user that modify
  1319. * @param double $remise Amount discount
  1320. * @return int <0 if ko, >0 if ok
  1321. */
  1322. function set_remise_absolue($user, $remise)
  1323. {
  1324. $remise=trim($remise)?trim($remise):0;
  1325. if (! empty($user->rights->supplier_proposal->creer))
  1326. {
  1327. $remise = price2num($remise);
  1328. $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal ";
  1329. $sql.= " SET remise_absolue = ".$remise;
  1330. $sql.= " WHERE rowid = ".$this->id." AND fk_statut = 0";
  1331. if ($this->db->query($sql) )
  1332. {
  1333. $this->remise_absolue = $remise;
  1334. $this->update_price(1);
  1335. return 1;
  1336. }
  1337. else
  1338. {
  1339. $this->error=$this->db->error();
  1340. return -1;
  1341. }
  1342. }
  1343. }
  1344. /**
  1345. * Reopen the commercial proposal
  1346. *
  1347. * @param User $user Object user that close
  1348. * @param int $statut Statut
  1349. * @param string $note Comment
  1350. * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers
  1351. * @return int <0 if KO, >0 if OK
  1352. */
  1353. function reopen($user, $statut, $note='', $notrigger=0)
  1354. {
  1355. global $langs,$conf;
  1356. $this->statut = $statut;
  1357. $error=0;
  1358. $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal";
  1359. $sql.= " SET fk_statut = ".$this->statut.",";
  1360. if (! empty($note)) $sql.= " note_private = '".$this->db->escape($note)."',";
  1361. $sql.= " date_cloture=NULL, fk_user_cloture=NULL";
  1362. $sql.= " WHERE rowid = ".$this->id;
  1363. $this->db->begin();
  1364. dol_syslog(get_class($this)."::reopen", LOG_DEBUG);
  1365. $resql = $this->db->query($sql);
  1366. if (! $resql) {
  1367. $error++; $this->errors[]="Error ".$this->db->lasterror();
  1368. }
  1369. if (! $error)
  1370. {
  1371. if (! $notrigger)
  1372. {
  1373. // Call trigger
  1374. $result=$this->call_trigger('SUPPLIER_PROPOSAL_REOPEN',$user);
  1375. if ($result < 0) { $error++; }
  1376. // End call triggers
  1377. }
  1378. }
  1379. // Commit or rollback
  1380. if ($error)
  1381. {
  1382. if (!empty($this->errors))
  1383. {
  1384. foreach($this->errors as $errmsg)
  1385. {
  1386. dol_syslog(get_class($this)."::update ".$errmsg, LOG_ERR);
  1387. $this->error.=($this->error?', '.$errmsg:$errmsg);
  1388. }
  1389. }
  1390. $this->db->rollback();
  1391. return -1*$error;
  1392. }
  1393. else
  1394. {
  1395. $this->db->commit();
  1396. return 1;
  1397. }
  1398. }
  1399. /**
  1400. * Close the askprice
  1401. *
  1402. * @param User $user Object user that close
  1403. * @param int $statut Statut
  1404. * @param string $note Comment
  1405. * @return int <0 if KO, >0 if OK
  1406. */
  1407. function cloture($user, $statut, $note)
  1408. {
  1409. global $langs,$conf;
  1410. $this->statut = $statut;
  1411. $error=0;
  1412. $now=dol_now();
  1413. $this->db->begin();
  1414. $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal";
  1415. $sql.= " SET fk_statut = ".$statut.", note_private = '".$this->db->escape($note)."', date_cloture='".$this->db->idate($now)."', fk_user_cloture=".$user->id;
  1416. $sql.= " WHERE rowid = ".$this->id;
  1417. $resql=$this->db->query($sql);
  1418. if ($resql)
  1419. {
  1420. $modelpdf=$conf->global->SUPPLIER_PROPOSAL_ADDON_PDF_ODT_CLOSED?$conf->global->SUPPLIER_PROPOSAL_ADDON_PDF_ODT_CLOSED:$this->modelpdf;
  1421. $trigger_name='SUPPLIER_PROPOSAL_CLOSE_REFUSED';
  1422. if ($statut == 2)
  1423. {
  1424. $trigger_name='SUPPLIER_PROPOSAL_CLOSE_SIGNED';
  1425. $modelpdf=$conf->global->SUPPLIER_PROPOSAL_ADDON_PDF_ODT_TOBILL?$conf->global->SUPPLIER_PROPOSAL_ADDON_PDF_ODT_TOBILL:$this->modelpdf;
  1426. // The connected company is classified as a client
  1427. $soc=new Societe($this->db);
  1428. $soc->id = $this->socid;
  1429. $result=$soc->set_as_client();
  1430. if ($result < 0)
  1431. {
  1432. $this->error=$this->db->error();
  1433. $this->db->rollback();
  1434. return -2;
  1435. }
  1436. else
  1437. {
  1438. if (! empty($conf->global->SUPPLIER_PROPOSAL_UPDATE_PRICE_ON_SUPPlIER_PROPOSAL)) // TODO This option was not tested correctly. Error if product ref does not exists
  1439. {
  1440. $result = $this->updateOrCreatePriceFournisseur($user);
  1441. }
  1442. }
  1443. }
  1444. if ($statut == 4)
  1445. {
  1446. $trigger_name='SUPPLIER_PROPOSAL_CLASSIFY_BILLED';
  1447. }
  1448. if (empty($conf->global->MAIN_DISABLE_PDF_AUTOUPDATE))
  1449. {
  1450. // Define output language
  1451. $outputlangs = $langs;
  1452. if (! empty($conf->global->MAIN_MULTILANGS))
  1453. {
  1454. $outputlangs = new Translate("",$conf);
  1455. $newlang=(GETPOST('lang_id') ? GETPOST('lang_id') : $this->thirdparty->default_lang);
  1456. $outputlangs->setDefaultLang($newlang);
  1457. }
  1458. //$ret=$object->fetch($id); // Reload to get new records
  1459. $this->generateDocument($modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref);
  1460. }
  1461. // Call trigger
  1462. $result=$this->call_trigger($trigger_name,$user);
  1463. if ($result < 0) { $error++; }
  1464. // End call triggers
  1465. if ( ! $error )
  1466. {
  1467. $this->db->commit();
  1468. return 1;
  1469. }
  1470. else
  1471. {
  1472. $this->db->rollback();
  1473. return -1;
  1474. }
  1475. }
  1476. else
  1477. {
  1478. $this->error=$this->db->lasterror();
  1479. $this->errors[]=$this->db->lasterror();
  1480. $this->db->rollback();
  1481. return -1;
  1482. }
  1483. }
  1484. /**
  1485. * Add or update supplier price according to result of proposal
  1486. *
  1487. * @param User $user Object user
  1488. * @return int > 0 if OK
  1489. */
  1490. function updateOrCreatePriceFournisseur($user)
  1491. {
  1492. $productsupplier = new ProductFournisseur($this->db);
  1493. dol_syslog(get_class($this)."::updateOrCreatePriceFournisseur", LOG_DEBUG);
  1494. foreach ($this->lines as $product)
  1495. {
  1496. if ($product->subprice <= 0) continue;
  1497. $idProductFourn = $productsupplier->find_min_price_product_fournisseur($product->fk_product, $product->qty);
  1498. $res = $productsupplier->fetch($idProductFourn);
  1499. if ($productsupplier->id) {
  1500. if ($productsupplier->fourn_qty == $product->qty) {
  1501. $this->updatePriceFournisseur($productsupplier->product_fourn_price_id, $product, $user);
  1502. } else {
  1503. $this->createPriceFournisseur($product, $user);
  1504. }
  1505. } else {
  1506. $this->createPriceFournisseur($product, $user);
  1507. }
  1508. }
  1509. return 1;
  1510. }
  1511. /**
  1512. * Upate ProductFournisseur
  1513. *
  1514. * @param int $idProductFournPrice id of llx_product_fournisseur_price
  1515. * @param int $product contain informations to update
  1516. * @param User $user Object user
  1517. * @return int <0 if KO, >0 if OK
  1518. */
  1519. function updatePriceFournisseur($idProductFournPrice, $product, $user) {
  1520. $price=price2num($product->subprice*$product->qty,'MU');
  1521. $unitPrice = price2num($product->subprice,'MU');
  1522. $sql = 'UPDATE '.MAIN_DB_PREFIX.'product_fournisseur_price SET '.(!empty($product->ref_fourn) ? 'ref_fourn = "'.$product->ref_fourn.'", ' : '').' price ='.$price.', unitprice ='.$unitPrice.' WHERE rowid = '.$idProductFournPrice;
  1523. $resql = $this->db->query($sql);
  1524. if (!$resql) {
  1525. $this->error=$this->db->error();
  1526. $this->db->rollback();
  1527. return -1;
  1528. }
  1529. }
  1530. /**
  1531. * Create ProductFournisseur
  1532. *
  1533. * @param Product $product Object Product
  1534. * @param User $user Object user
  1535. * @return int <0 if KO, >0 if OK
  1536. */
  1537. function createPriceFournisseur($product, $user) {
  1538. $price=price2num($product->subprice*$product->qty,'MU');
  1539. $qty=price2num($product->qty);
  1540. $unitPrice = price2num($product->subprice,'MU');
  1541. $now=dol_now();
  1542. $values = array(
  1543. "'".$this->db->idate($now)."'",
  1544. $product->fk_product,
  1545. $this->thirdparty->id,
  1546. "'".$product->ref_fourn."'",
  1547. $price,
  1548. $qty,
  1549. $unitPrice,
  1550. $product->tva_tx,
  1551. $user->id
  1552. );
  1553. $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'product_fournisseur_price ';
  1554. $sql .= '(datec, fk_product, fk_soc, ref_fourn, price, quantity, unitprice, tva_tx, fk_user) VALUES ('.implode(',', $values).')';
  1555. $resql = $this->db->query($sql);
  1556. if (!$resql) {
  1557. $this->error=$this->db->error();
  1558. $this->db->rollback();
  1559. return -1;
  1560. }
  1561. }
  1562. /**
  1563. * Set draft status
  1564. *
  1565. * @param User $user Object user that modify
  1566. * @return int <0 if KO, >0 if OK
  1567. */
  1568. function set_draft($user)
  1569. {
  1570. global $conf,$langs;
  1571. $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposal SET fk_statut = 0";
  1572. $sql.= " WHERE rowid = ".$this->id;
  1573. if ($this->db->query($sql))
  1574. {
  1575. $this->statut = 0;
  1576. $this->brouillon = 1;
  1577. return 1;
  1578. }
  1579. else
  1580. {
  1581. return -1;
  1582. }
  1583. }
  1584. /**
  1585. * Return list of askprice (eventually filtered on user) into an array
  1586. *
  1587. * @param int $shortlist 0=Return array[id]=ref, 1=Return array[](id=>id,ref=>ref,name=>name)
  1588. * @param int $draft 0=not draft, 1=draft
  1589. * @param int $notcurrentuser 0=all user, 1=not current user
  1590. * @param int $socid Id third pary
  1591. * @param int $limit For pagination
  1592. * @param int $offset For pagination
  1593. * @param string $sortfield Sort criteria
  1594. * @param string $sortorder Sort order
  1595. * @return int -1 if KO, array with result if OK
  1596. */
  1597. function liste_array($shortlist=0, $draft=0, $notcurrentuser=0, $socid=0, $limit=0, $offset=0, $sortfield='p.datec', $sortorder='DESC')
  1598. {
  1599. global $conf,$user;
  1600. $ga = array();
  1601. $sql = "SELECT s.rowid, s.nom as name, s.client,";
  1602. $sql.= " p.rowid as supplier_proposalid, p.fk_statut, p.total_ht, p.ref, p.remise, ";
  1603. $sql.= " p.datep as dp, p.fin_validite as datelimite";
  1604. if (! $user->rights->societe->client->voir && ! $socid) $sql .= ", sc.fk_soc, sc.fk_user";
  1605. $sql.= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."supplier_proposal as p, ".MAIN_DB_PREFIX."c_propalst as c";
  1606. if (! $user->rights->societe->client->voir && ! $socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
  1607. $sql.= " WHERE p.entity = ".$conf->entity;
  1608. $sql.= " AND p.fk_soc = s.rowid";
  1609. $sql.= " AND p.fk_statut = c.id";
  1610. if (! $user->rights->societe->client->voir && ! $socid) //restriction
  1611. {
  1612. $sql.= " AND s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id;
  1613. }
  1614. if ($socid) $sql.= " AND s.rowid = ".$socid;
  1615. if ($draft) $sql.= " AND p.fk_statut = 0";
  1616. if ($notcurrentuser > 0) $sql.= " AND p.fk_user_author <> ".$user->id;
  1617. $sql.= $this->db->order($sortfield,$sortorder);
  1618. $sql.= $this->db->plimit($limit,$offset);
  1619. $result=$this->db->query($sql);
  1620. if ($result)
  1621. {
  1622. $num = $this->db->num_rows($result);
  1623. if ($num)
  1624. {
  1625. $i = 0;
  1626. while ($i < $num)
  1627. {
  1628. $obj = $this->db->fetch_object($result);
  1629. if ($shortlist == 1)
  1630. {
  1631. $ga[$obj->supplier_proposalid] = $obj->ref;
  1632. }
  1633. else if ($shortlist == 2)
  1634. {
  1635. $ga[$obj->supplier_proposalid] = $obj->ref.' ('.$obj->name.')';
  1636. }
  1637. else
  1638. {
  1639. $ga[$i]['id'] = $obj->supplier_proposalid;
  1640. $ga[$i]['ref'] = $obj->ref;
  1641. $ga[$i]['name'] = $obj->name;
  1642. }
  1643. $i++;
  1644. }
  1645. }
  1646. return $ga;
  1647. }
  1648. else
  1649. {
  1650. dol_print_error($this->db);
  1651. return -1;
  1652. }
  1653. }
  1654. /**
  1655. * Delete askprice
  1656. *
  1657. * @param User $user Object user that delete
  1658. * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers
  1659. * @return int 1 if ok, otherwise if error
  1660. */
  1661. function delete($user, $notrigger=0)
  1662. {
  1663. global $conf,$langs;
  1664. require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
  1665. $error=0;
  1666. $this->db->begin();
  1667. if (! $notrigger)
  1668. {
  1669. // Call trigger
  1670. $result=$this->call_trigger('SUPPLIER_PROPOSAL_DELETE',$user);
  1671. if ($result < 0) { $error++; }
  1672. // End call triggers
  1673. }
  1674. if (! $error)
  1675. {
  1676. $sql = "DELETE FROM ".MAIN_DB_PREFIX."supplier_proposaldet WHERE fk_supplier_proposal = ".$this->id;
  1677. if ($this->db->query($sql))
  1678. {
  1679. $sql = "DELETE FROM ".MAIN_DB_PREFIX."supplier_proposal WHERE rowid = ".$this->id;
  1680. if ($this->db->query($sql))
  1681. {
  1682. // Delete linked object
  1683. $res = $this->deleteObjectLinked();
  1684. if ($res < 0) $error++;
  1685. if (! $error)
  1686. {
  1687. // We remove directory
  1688. $ref = dol_sanitizeFileName($this->ref);
  1689. if ($conf->supplier_proposal->dir_output && !empty($this->ref))
  1690. {
  1691. $dir = $conf->supplier_proposal->dir_output . "/" . $ref ;
  1692. $file = $dir . "/" . $ref . ".pdf";
  1693. if (file_exists($file))
  1694. {
  1695. dol_delete_preview($this);
  1696. if (! dol_delete_file($file,0,0,0,$this)) // For triggers
  1697. {
  1698. $this->error='ErrorFailToDeleteFile';
  1699. $this->errors=array('ErrorFailToDeleteFile');
  1700. $this->db->rollback();
  1701. return 0;
  1702. }
  1703. }
  1704. if (file_exists($dir))
  1705. {
  1706. $res=@dol_delete_dir_recursive($dir);
  1707. if (! $res)
  1708. {
  1709. $this->error='ErrorFailToDeleteDir';
  1710. $this->errors=array('ErrorFailToDeleteDir');
  1711. $this->db->rollback();
  1712. return 0;
  1713. }
  1714. }
  1715. }
  1716. }
  1717. // Removed extrafields
  1718. if (! $error)
  1719. {
  1720. if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
  1721. {
  1722. $result=$this->deleteExtraFields();
  1723. if ($result < 0)
  1724. {
  1725. $error++;
  1726. $errorflag=-4;
  1727. dol_syslog(get_class($this)."::delete erreur ".$errorflag." ".$this->error, LOG_ERR);
  1728. }
  1729. }
  1730. }
  1731. if (! $error)
  1732. {
  1733. dol_syslog(get_class($this)."::delete ".$this->id." by ".$user->id, LOG_DEBUG);
  1734. $this->db->commit();
  1735. return 1;
  1736. }
  1737. else
  1738. {
  1739. $this->error=$this->db->lasterror();
  1740. $this->db->rollback();
  1741. return 0;
  1742. }
  1743. }
  1744. else
  1745. {
  1746. $this->error=$this->db->lasterror();
  1747. $this->db->rollback();
  1748. return -3;
  1749. }
  1750. }
  1751. else
  1752. {
  1753. $this->error=$this->db->lasterror();
  1754. $this->db->rollback();
  1755. return -2;
  1756. }
  1757. }
  1758. else
  1759. {
  1760. $this->db->rollback();
  1761. return -1;
  1762. }
  1763. }
  1764. /**
  1765. * Object SupplierProposal Information
  1766. *
  1767. * @param int $id Proposal id
  1768. * @return void
  1769. */
  1770. function info($id)
  1771. {
  1772. $sql = "SELECT c.rowid, ";
  1773. $sql.= " c.datec, c.date_valid as datev, c.date_cloture as dateo,";
  1774. $sql.= " c.fk_user_author, c.fk_user_valid, c.fk_user_cloture";
  1775. $sql.= " FROM ".MAIN_DB_PREFIX."supplier_proposal as c";
  1776. $sql.= " WHERE c.rowid = ".$id;
  1777. $result = $this->db->query($sql);
  1778. if ($result)
  1779. {
  1780. if ($this->db->num_rows($result))
  1781. {
  1782. $obj = $this->db->fetch_object($result);
  1783. $this->id = $obj->rowid;
  1784. $this->date_creation = $this->db->jdate($obj->datec);
  1785. $this->date_validation = $this->db->jdate($obj->datev);
  1786. $this->date_cloture = $this->db->jdate($obj->dateo);
  1787. $cuser = new User($this->db);
  1788. $cuser->fetch($obj->fk_user_author);
  1789. $this->user_creation = $cuser;
  1790. if ($obj->fk_user_valid)
  1791. {
  1792. $vuser = new User($this->db);
  1793. $vuser->fetch($obj->fk_user_valid);
  1794. $this->user_validation = $vuser;
  1795. }
  1796. if ($obj->fk_user_cloture)
  1797. {
  1798. $cluser = new User($this->db);
  1799. $cluser->fetch($obj->fk_user_cloture);
  1800. $this->user_cloture = $cluser;
  1801. }
  1802. }
  1803. $this->db->free($result);
  1804. }
  1805. else
  1806. {
  1807. dol_print_error($this->db);
  1808. }
  1809. }
  1810. /**
  1811. * Return label of status of proposal (draft, validated, ...)
  1812. *
  1813. * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
  1814. * @return string Label
  1815. */
  1816. function getLibStatut($mode=0)
  1817. {
  1818. return $this->LibStatut($this->statut,$mode);
  1819. }
  1820. /**
  1821. * Return label of a status (draft, validated, ...)
  1822. *
  1823. * @param int $statut id statut
  1824. * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto
  1825. * @return string Label
  1826. */
  1827. function LibStatut($statut,$mode=1)
  1828. {
  1829. global $langs;
  1830. $langs->load("supplier_proposal");
  1831. if ($statut==0) $statuttrans='statut0';
  1832. if ($statut==1) $statuttrans='statut1';
  1833. if ($statut==2) $statuttrans='statut3';
  1834. if ($statut==3) $statuttrans='statut5';
  1835. if ($statut==4) $statuttrans='statut6';
  1836. if ($mode == 0) return $this->labelstatut[$statut];
  1837. if ($mode == 1) return $this->labelstatut_short[$statut];
  1838. if ($mode == 2) return img_picto($this->labelstatut_short[$statut], $statuttrans).' '.$this->labelstatut_short[$statut];
  1839. if ($mode == 3) return img_picto($this->labelstatut[$statut], $statuttrans);
  1840. if ($mode == 4) return img_picto($this->labelstatut[$statut],$statuttrans).' '.$this->labelstatut[$statut];
  1841. if ($mode == 5) return '<span class="hideonsmartphone">'.$this->labelstatut_short[$statut].' </span>'.img_picto($this->labelstatut_short[$statut],$statuttrans);
  1842. }
  1843. /**
  1844. * Load indicators for dashboard (this->nbtodo and this->nbtodolate)
  1845. *
  1846. * @param User $user Object user
  1847. * @param int $mode "opened" for askprice to close, "signed" for proposal to invoice
  1848. * @return int <0 if KO, >0 if OK
  1849. */
  1850. function load_board($user,$mode)
  1851. {
  1852. global $conf, $user, $langs;
  1853. $now=dol_now();
  1854. $this->nbtodo=$this->nbtodolate=0;
  1855. $clause = " WHERE";
  1856. $sql = "SELECT p.rowid, p.ref, p.datec as datec";
  1857. $sql.= " FROM ".MAIN_DB_PREFIX."supplier_proposal as p";
  1858. if (!$user->rights->societe->client->voir && !$user->societe_id)
  1859. {
  1860. $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON p.fk_soc = sc.fk_soc";
  1861. $sql.= " WHERE sc.fk_user = " .$user->id;
  1862. $clause = " AND";
  1863. }
  1864. $sql.= $clause." p.entity = ".$conf->entity;
  1865. if ($mode == 'opened') $sql.= " AND p.fk_statut = 1";
  1866. if ($mode == 'signed') $sql.= " AND p.fk_statut = 2";
  1867. if ($user->societe_id) $sql.= " AND p.fk_soc = ".$user->societe_id;
  1868. $resql=$this->db->query($sql);
  1869. if ($resql)
  1870. {
  1871. if ($mode == 'opened') {
  1872. $delay_warning=$conf->supplier_proposal->cloture->warning_delay;
  1873. $statut = self::STATUS_VALIDATED;
  1874. $label = $langs->trans("SupplierProposalsToClose");
  1875. }
  1876. if ($mode == 'signed') {
  1877. $delay_warning=$conf->supplier_proposal->facturation->warning_delay;
  1878. $statut = self::STATUS_SIGNED;
  1879. $label = $langs->trans("SupplierProposalsToProcess"); // May be billed or ordered
  1880. }
  1881. $response = new WorkboardResponse();
  1882. $response->warning_delay = $delay_warning/60/60/24;
  1883. $response->label = $label;
  1884. $response->url = DOL_URL_ROOT.'/supplier_proposal/list.php?viewstatut='.$statut;
  1885. $response->img = img_object($langs->trans("SupplierProposals"),"propal");
  1886. // This assignment in condition is not a bug. It allows walking the results.
  1887. while ($obj=$this->db->fetch_object($resql))
  1888. {
  1889. $response->nbtodo++;
  1890. if ($mode == 'opened')
  1891. {
  1892. $datelimit = $this->db->jdate($obj->datefin);
  1893. if ($datelimit < ($now - $delay_warning))
  1894. {
  1895. $response->nbtodolate++;
  1896. }
  1897. }
  1898. // TODO Definir regle des propales a facturer en retard
  1899. // if ($mode == 'signed' && ! count($this->FactureListeArray($obj->rowid))) $this->nbtodolate++;
  1900. }
  1901. return $response;
  1902. }
  1903. else
  1904. {
  1905. $this->error=$this->db->lasterror();
  1906. return -1;
  1907. }
  1908. }
  1909. /**
  1910. * Initialise an instance with random values.
  1911. * Used to build previews or test instances.
  1912. * id must be 0 if object instance is a specimen.
  1913. *
  1914. * @return void
  1915. */
  1916. function initAsSpecimen()
  1917. {
  1918. global $user,$langs,$conf;
  1919. // Load array of products prodids
  1920. $num_prods = 0;
  1921. $prodids = array();
  1922. $sql = "SELECT rowid";
  1923. $sql.= " FROM ".MAIN_DB_PREFIX."product";
  1924. $sql.= " WHERE entity IN (".getEntity('product', 1).")";
  1925. $resql = $this->db->query($sql);
  1926. if ($resql)
  1927. {
  1928. $num_prods = $this->db->num_rows($resql);
  1929. $i = 0;
  1930. while ($i < $num_prods)
  1931. {
  1932. $i++;
  1933. $row = $this->db->fetch_row($resql);
  1934. $prodids[$i] = $row[0];
  1935. }
  1936. }
  1937. // Initialise parametres
  1938. $this->id=0;
  1939. $this->ref = 'SPECIMEN';
  1940. $this->specimen=1;
  1941. $this->socid = 1;
  1942. $this->date = time();
  1943. $this->cond_reglement_id = 1;
  1944. $this->cond_reglement_code = 'RECEP';
  1945. $this->mode_reglement_id = 7;
  1946. $this->mode_reglement_code = 'CHQ';
  1947. $this->note_public='This is a comment (public)';
  1948. $this->note_private='This is a comment (private)';
  1949. // Lines
  1950. $nbp = 5;
  1951. $xnbp = 0;
  1952. while ($xnbp < $nbp)
  1953. {
  1954. $line=new SupplierProposalLine($this->db);
  1955. $line->desc=$langs->trans("Description")." ".$xnbp;
  1956. $line->qty=1;
  1957. $line->subprice=100;
  1958. $line->price=100;
  1959. $line->tva_tx=19.6;
  1960. $line->localtax1_tx=0;
  1961. $line->localtax2_tx=0;
  1962. if ($xnbp == 2)
  1963. {
  1964. $line->total_ht=50;
  1965. $line->total_ttc=59.8;
  1966. $line->total_tva=9.8;
  1967. $line->remise_percent=50;
  1968. }
  1969. else
  1970. {
  1971. $line->total_ht=100;
  1972. $line->total_ttc=119.6;
  1973. $line->total_tva=19.6;
  1974. $line->remise_percent=00;
  1975. }
  1976. if ($num_prods > 0)
  1977. {
  1978. $prodid = mt_rand(1, $num_prods);
  1979. $line->fk_product=$prodids[$prodid];
  1980. }
  1981. $this->lines[$xnbp]=$line;
  1982. $this->total_ht += $line->total_ht;
  1983. $this->total_tva += $line->total_tva;
  1984. $this->total_ttc += $line->total_ttc;
  1985. $xnbp++;
  1986. }
  1987. }
  1988. /**
  1989. * Charge indicateurs this->nb de tableau de bord
  1990. *
  1991. * @return int <0 if ko, >0 if ok
  1992. */
  1993. function load_state_board()
  1994. {
  1995. global $conf, $user;
  1996. $this->nb=array();
  1997. $clause = "WHERE";
  1998. $sql = "SELECT count(p.rowid) as nb";
  1999. $sql.= " FROM ".MAIN_DB_PREFIX."supplier_proposal as p";
  2000. $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON p.fk_soc = s.rowid";
  2001. if (!$user->rights->societe->client->voir && !$user->societe_id)
  2002. {
  2003. $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON s.rowid = sc.fk_soc";
  2004. $sql.= " WHERE sc.fk_user = " .$user->id;
  2005. $clause = "AND";
  2006. }
  2007. $sql.= " ".$clause." p.entity = ".$conf->entity;
  2008. $resql=$this->db->query($sql);
  2009. if ($resql)
  2010. {
  2011. // This assignment in condition is not a bug. It allows walking the results.
  2012. while ($obj=$this->db->fetch_object($resql))
  2013. {
  2014. $this->nb["askprice"]=$obj->nb;
  2015. }
  2016. $this->db->free($resql);
  2017. return 1;
  2018. }
  2019. else
  2020. {
  2021. dol_print_error($this->db);
  2022. $this->error=$this->db->lasterror();
  2023. return -1;
  2024. }
  2025. }
  2026. /**
  2027. * Returns the reference to the following non used Proposal used depending on the active numbering module
  2028. * defined into SUPPLIER_PROPOSAL_ADDON
  2029. *
  2030. * @param Societe $soc Object thirdparty
  2031. * @return string Reference libre pour la propale
  2032. */
  2033. function getNextNumRef($soc)
  2034. {
  2035. global $conf, $db, $langs;
  2036. $langs->load("supplier_proposal");
  2037. if (! empty($conf->global->SUPPLIER_PROPOSAL_ADDON))
  2038. {
  2039. $mybool=false;
  2040. $file = $conf->global->SUPPLIER_PROPOSAL_ADDON.".php";
  2041. $classname = $conf->global->SUPPLIER_PROPOSAL_ADDON;
  2042. // Include file with class
  2043. $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']);
  2044. foreach ($dirmodels as $reldir) {
  2045. $dir = dol_buildpath($reldir."core/modules/supplier_proposal/");
  2046. // Load file with numbering class (if found)
  2047. $mybool|=@include_once $dir.$file;
  2048. }
  2049. if (! $mybool)
  2050. {
  2051. dol_print_error('',"Failed to include file ".$file);
  2052. return '';
  2053. }
  2054. $obj = new $classname();
  2055. $numref = "";
  2056. $numref = $obj->getNextValue($soc,$this);
  2057. if ($numref != "")
  2058. {
  2059. return $numref;
  2060. }
  2061. else
  2062. {
  2063. $this->error=$obj->error;
  2064. return "";
  2065. }
  2066. }
  2067. else
  2068. {
  2069. $langs->load("errors");
  2070. print $langs->trans("Error")." ".$langs->trans("ErrorModuleSetupNotComplete");
  2071. return "";
  2072. }
  2073. }
  2074. /**
  2075. * Return clicable link of object (with eventually picto)
  2076. *
  2077. * @param int $withpicto Add picto into link
  2078. * @param string $option Where point the link ('compta', 'expedition', 'document', ...)
  2079. * @param string $get_params Parametres added to url
  2080. * @return string String with URL
  2081. */
  2082. function getNomUrl($withpicto=0,$option='', $get_params='')
  2083. {
  2084. global $langs;
  2085. $result='';
  2086. $label=$langs->trans("ShowSupplierProposal").': '.$this->ref;
  2087. $linkclose = '" title="'.dol_escape_htmltag($label, 1).'" class="classfortooltip">';
  2088. if ($option == '') {
  2089. $link = '<a href="'.DOL_URL_ROOT.'/supplier_proposal/card.php?id='.$this->id. $get_params .$linkclose;
  2090. }
  2091. if ($option == 'document') {
  2092. $link = '<a href="'.DOL_URL_ROOT.'/supplier_proposal/document.php?id='.$this->id. $get_params .$linkclose;
  2093. }
  2094. $linkend='</a>';
  2095. $picto='supplier_proposal';
  2096. if ($withpicto)
  2097. $result.=($link.img_object($label, $picto, 'class="classfortooltip"').$linkend);
  2098. if ($withpicto && $withpicto != 2)
  2099. $result.=' ';
  2100. $result.=$link.$this->ref.$linkend;
  2101. return $result;
  2102. }
  2103. /**
  2104. * Retrieve an array of supplier proposal lines
  2105. *
  2106. * @return int >0 if OK, <0 if KO
  2107. */
  2108. function getLinesArray()
  2109. {
  2110. // For other object, here we call fetch_lines. But fetch_lines does not exists on supplier proposal
  2111. $sql = 'SELECT pt.rowid, pt.label as custom_label, pt.description, pt.fk_product, pt.fk_remise_except,';
  2112. $sql.= ' pt.qty, pt.tva_tx, pt.remise_percent, pt.subprice, pt.info_bits,';
  2113. $sql.= ' pt.total_ht, pt.total_tva, pt.total_ttc, pt.fk_product_fournisseur_price as fk_fournprice, pt.buy_price_ht as pa_ht, pt.special_code, pt.localtax1_tx, pt.localtax2_tx,';
  2114. $sql.= ' pt.product_type, pt.rang, pt.fk_parent_line,';
  2115. $sql.= ' p.label as product_label, p.ref, p.fk_product_type, p.rowid as prodid,';
  2116. $sql.= ' p.description as product_desc, pt.ref_fourn as ref_produit_fourn';
  2117. $sql.= ' ,pt.fk_multicurrency, pt.multicurrency_code, pt.multicurrency_subprice, pt.multicurrency_total_ht, pt.multicurrency_total_tva, pt.multicurrency_total_ttc';
  2118. $sql.= ' FROM '.MAIN_DB_PREFIX.'supplier_proposaldet as pt';
  2119. $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON pt.fk_product=p.rowid';
  2120. $sql.= ' WHERE pt.fk_supplier_proposal = '.$this->id;
  2121. $sql.= ' ORDER BY pt.rang ASC, pt.rowid';
  2122. dol_syslog(get_class($this).'::getLinesArray', LOG_DEBUG);
  2123. $resql = $this->db->query($sql);
  2124. if ($resql)
  2125. {
  2126. $num = $this->db->num_rows($resql);
  2127. $i = 0;
  2128. while ($i < $num)
  2129. {
  2130. $obj = $this->db->fetch_object($resql);
  2131. $this->lines[$i] = new SupplierProposalLine($this->db);
  2132. $this->lines[$i]->id = $obj->rowid; // for backward compatibility
  2133. $this->lines[$i]->rowid = $obj->rowid;
  2134. $this->lines[$i]->label = $obj->custom_label;
  2135. $this->lines[$i]->description = $obj->description;
  2136. $this->lines[$i]->fk_product = $obj->fk_product;
  2137. $this->lines[$i]->ref = $obj->ref;
  2138. $this->lines[$i]->product_label = $obj->product_label;
  2139. $this->lines[$i]->product_desc = $obj->product_desc;
  2140. $this->lines[$i]->fk_product_type = $obj->fk_product_type; // deprecated
  2141. $this->lines[$i]->product_type = $obj->product_type;
  2142. $this->lines[$i]->qty = $obj->qty;
  2143. $this->lines[$i]->subprice = $obj->subprice;
  2144. $this->lines[$i]->fk_remise_except = $obj->fk_remise_except;
  2145. $this->lines[$i]->remise_percent = $obj->remise_percent;
  2146. $this->lines[$i]->tva_tx = $obj->tva_tx;
  2147. $this->lines[$i]->info_bits = $obj->info_bits;
  2148. $this->lines[$i]->total_ht = $obj->total_ht;
  2149. $this->lines[$i]->total_tva = $obj->total_tva;
  2150. $this->lines[$i]->total_ttc = $obj->total_ttc;
  2151. $this->lines[$i]->fk_fournprice = $obj->fk_fournprice;
  2152. $marginInfos = getMarginInfos($obj->subprice, $obj->remise_percent, $obj->tva_tx, $obj->localtax1_tx, $obj->localtax2_tx, $this->lines[$i]->fk_fournprice, $obj->pa_ht);
  2153. $this->lines[$i]->pa_ht = $marginInfos[0];
  2154. $this->lines[$i]->marge_tx = $marginInfos[1];
  2155. $this->lines[$i]->marque_tx = $marginInfos[2];
  2156. $this->lines[$i]->fk_parent_line = $obj->fk_parent_line;
  2157. $this->lines[$i]->special_code = $obj->special_code;
  2158. $this->lines[$i]->rang = $obj->rang;
  2159. $this->lines[$i]->ref_fourn = $obj->ref_produit_fourn;
  2160. // Multicurrency
  2161. $this->lines[$i]->fk_multicurrency = $obj->fk_multicurrency;
  2162. $this->lines[$i]->multicurrency_code = $obj->multicurrency_code;
  2163. $this->lines[$i]->multicurrency_subprice = $obj->multicurrency_subprice;
  2164. $this->lines[$i]->multicurrency_total_ht = $obj->multicurrency_total_ht;
  2165. $this->lines[$i]->multicurrency_total_tva = $obj->multicurrency_total_tva;
  2166. $this->lines[$i]->multicurrency_total_ttc = $obj->multicurrency_total_ttc;
  2167. $i++;
  2168. }
  2169. $this->db->free($resql);
  2170. return 1;
  2171. }
  2172. else
  2173. {
  2174. $this->error=$this->db->error();
  2175. return -1;
  2176. }
  2177. }
  2178. /**
  2179. * Create a document onto disk according to template module.
  2180. *
  2181. * @param string $modele Force model to use ('' to not force)
  2182. * @param Translate $outputlangs Object langs to use for output
  2183. * @param int $hidedetails Hide details of lines
  2184. * @param int $hidedesc Hide description
  2185. * @param int $hideref Hide ref
  2186. * @return int 0 if KO, 1 if OK
  2187. */
  2188. public function generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0)
  2189. {
  2190. global $conf,$user,$langs;
  2191. $langs->load("supplier_proposal");
  2192. // Positionne le modele sur le nom du modele a utiliser
  2193. if (! dol_strlen($modele))
  2194. {
  2195. if (! empty($conf->global->SUPPLIER_PROPOSAL_ADDON_PDF))
  2196. {
  2197. $modele = $conf->global->SUPPLIER_PROPOSAL_ADDON_PDF;
  2198. }
  2199. else
  2200. {
  2201. $modele = 'aurore';
  2202. }
  2203. }
  2204. $modelpath = "core/modules/supplier_proposal/doc/";
  2205. return $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref);
  2206. }
  2207. }
  2208. /**
  2209. * \class SupplierProposalLine
  2210. * \brief Class to manage supplier_proposal lines
  2211. */
  2212. class SupplierProposalLine extends CommonObject
  2213. {
  2214. var $db;
  2215. var $error;
  2216. public $element='supplier_proposaldet';
  2217. public $table_element='supplier_proposaldet';
  2218. var $oldline;
  2219. // From llx_supplier_proposaldet
  2220. var $rowid; // deprecated
  2221. var $id;
  2222. var $fk_supplier_proposal;
  2223. var $fk_parent_line;
  2224. var $desc; // Description ligne
  2225. var $fk_product; // Id produit predefini
  2226. /**
  2227. * @deprecated
  2228. * @see product_type
  2229. */
  2230. var $fk_product_type;
  2231. /**
  2232. * Product type
  2233. * @var int
  2234. * @see Product::TYPE_PRODUCT, Product::TYPE_SERVICE
  2235. */
  2236. public $product_type = Product::TYPE_PRODUCT;
  2237. var $qty;
  2238. var $tva_tx;
  2239. var $subprice;
  2240. var $remise_percent;
  2241. var $fk_remise_except;
  2242. var $rang = 0;
  2243. var $fk_fournprice;
  2244. var $pa_ht;
  2245. var $marge_tx;
  2246. var $marque_tx;
  2247. var $special_code; // Tag for special lines (exlusive tags)
  2248. // 1: frais de port
  2249. // 2: ecotaxe
  2250. // 3: option line (when qty = 0)
  2251. var $info_bits = 0; // Liste d'options cumulables:
  2252. // Bit 0: 0 si TVA normal - 1 si TVA NPR
  2253. // Bit 1: 0 ligne normale - 1 si ligne de remise fixe
  2254. var $total_ht; // Total HT de la ligne toute quantite et incluant la remise ligne
  2255. var $total_tva; // Total TVA de la ligne toute quantite et incluant la remise ligne
  2256. var $total_ttc; // Total TTC de la ligne toute quantite et incluant la remise ligne
  2257. /**
  2258. * @deprecated
  2259. * @see remise_percent, fk_remise_except
  2260. */
  2261. var $remise;
  2262. /**
  2263. * @deprecated
  2264. * @see subprice
  2265. */
  2266. var $price;
  2267. // From llx_product
  2268. /**
  2269. * @deprecated
  2270. * @see product_ref
  2271. */
  2272. var $ref;
  2273. /**
  2274. * Product reference
  2275. * @var string
  2276. */
  2277. public $product_ref;
  2278. /**
  2279. * @deprecated
  2280. * @see product_label
  2281. */
  2282. var $libelle;
  2283. /**
  2284. * Product label
  2285. * @var string
  2286. */
  2287. public $product_label;
  2288. /**
  2289. * Product description
  2290. * @var string
  2291. */
  2292. public $product_desc;
  2293. var $localtax1_tx; // Local tax 1
  2294. var $localtax2_tx; // Local tax 2
  2295. var $localtax1_type; // Local tax 1 type
  2296. var $localtax2_type; // Local tax 2 type
  2297. var $total_localtax1; // Line total local tax 1
  2298. var $total_localtax2; // Line total local tax 2
  2299. var $skip_update_total; // Skip update price total for special lines
  2300. var $ref_fourn;
  2301. // Multicurrency
  2302. var $fk_multicurrency;
  2303. var $multicurrency_code;
  2304. var $multicurrency_subprice;
  2305. var $multicurrency_total_ht;
  2306. var $multicurrency_total_tva;
  2307. var $multicurrency_total_ttc;
  2308. /**
  2309. * Class line Contructor
  2310. *
  2311. * @param DoliDB $db Database handler
  2312. */
  2313. function __construct($db)
  2314. {
  2315. $this->db= $db;
  2316. }
  2317. /**
  2318. * Retrieve the propal line object
  2319. *
  2320. * @param int $rowid Propal line id
  2321. * @return int <0 if KO, >0 if OK
  2322. */
  2323. function fetch($rowid)
  2324. {
  2325. $sql = 'SELECT pd.rowid, pd.fk_supplier_proposal, pd.fk_parent_line, pd.fk_product, pd.label as custom_label, pd.description, pd.price, pd.qty, pd.tva_tx,';
  2326. $sql.= ' pd.remise, pd.remise_percent, pd.fk_remise_except, pd.subprice,';
  2327. $sql.= ' pd.info_bits, pd.total_ht, pd.total_tva, pd.total_ttc, pd.fk_product_fournisseur_price as fk_fournprice, pd.buy_price_ht as pa_ht, pd.special_code, pd.rang,';
  2328. $sql.= ' pd.localtax1_tx, pd.localtax2_tx, pd.total_localtax1, pd.total_localtax2,';
  2329. $sql.= ' p.ref as product_ref, p.label as product_label, p.description as product_desc,';
  2330. $sql.= ' pd.product_type, pd.ref_fourn as ref_produit_fourn,';
  2331. $sql.= ' pd.fk_multicurrency, pd.multicurrency_code, pd.multicurrency_subprice, pd.multicurrency_total_ht, pd.multicurrency_total_tva, pd.multicurrency_total_ttc';
  2332. $sql.= ' FROM '.MAIN_DB_PREFIX.'supplier_proposaldet as pd';
  2333. $sql.= ' LEFT JOIN '.MAIN_DB_PREFIX.'product as p ON pd.fk_product = p.rowid';
  2334. $sql.= ' WHERE pd.rowid = '.$rowid;
  2335. $result = $this->db->query($sql);
  2336. if ($result)
  2337. {
  2338. $objp = $this->db->fetch_object($result);
  2339. $this->rowid = $objp->rowid; // deprecated
  2340. $this->id = $objp->rowid;
  2341. $this->fk_supplier_proposal = $objp->fk_supplier_proposal;
  2342. $this->fk_parent_line = $objp->fk_parent_line;
  2343. $this->label = $objp->custom_label;
  2344. $this->desc = $objp->description;
  2345. $this->qty = $objp->qty;
  2346. $this->price = $objp->price; // deprecated
  2347. $this->subprice = $objp->subprice;
  2348. $this->tva_tx = $objp->tva_tx;
  2349. $this->remise = $objp->remise;
  2350. $this->remise_percent = $objp->remise_percent;
  2351. $this->fk_remise_except = $objp->fk_remise_except;
  2352. $this->fk_product = $objp->fk_product;
  2353. $this->info_bits = $objp->info_bits;
  2354. $this->total_ht = $objp->total_ht;
  2355. $this->total_tva = $objp->total_tva;
  2356. $this->total_ttc = $objp->total_ttc;
  2357. $this->fk_fournprice = $objp->fk_fournprice;
  2358. $marginInfos = getMarginInfos($objp->subprice, $objp->remise_percent, $objp->tva_tx, $objp->localtax1_tx, $objp->localtax2_tx, $this->fk_fournprice, $objp->pa_ht);
  2359. $this->pa_ht = $marginInfos[0];
  2360. $this->marge_tx = $marginInfos[1];
  2361. $this->marque_tx = $marginInfos[2];
  2362. $this->special_code = $objp->special_code;
  2363. $this->product_type = $objp->product_type;
  2364. $this->rang = $objp->rang;
  2365. $this->ref = $objp->product_ref; // deprecated
  2366. $this->product_ref = $objp->product_ref;
  2367. $this->libelle = $objp->product_label; // deprecated
  2368. $this->product_label = $objp->product_label;
  2369. $this->product_desc = $objp->product_desc;
  2370. $this->ref_fourn = $objp->ref_produit_forun;
  2371. // Multicurrency
  2372. $this->fk_multicurrency = $objp->fk_multicurrency;
  2373. $this->multicurrency_code = $objp->multicurrency_code;
  2374. $this->multicurrency_subprice = $objp->multicurrency_subprice;
  2375. $this->multicurrency_total_ht = $objp->multicurrency_total_ht;
  2376. $this->multicurrency_total_tva = $objp->multicurrency_total_tva;
  2377. $this->multicurrency_total_ttc = $objp->multicurrency_total_ttc;
  2378. $this->db->free($result);
  2379. }
  2380. else
  2381. {
  2382. dol_print_error($this->db);
  2383. }
  2384. }
  2385. /**
  2386. * Insert object line propal in database
  2387. *
  2388. * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers
  2389. * @return int <0 if KO, >0 if OK
  2390. */
  2391. function insert($notrigger=0)
  2392. {
  2393. global $conf,$langs,$user;
  2394. $error=0;
  2395. dol_syslog(get_class($this)."::insert rang=".$this->rang);
  2396. // Clean parameters
  2397. if (empty($this->tva_tx)) $this->tva_tx=0;
  2398. if (empty($this->localtax1_tx)) $this->localtax1_tx=0;
  2399. if (empty($this->localtax2_tx)) $this->localtax2_tx=0;
  2400. if (empty($this->localtax1_type)) $this->localtax1_type=0;
  2401. if (empty($this->localtax2_type)) $this->localtax2_type=0;
  2402. if (empty($this->total_localtax1)) $this->total_localtax1=0;
  2403. if (empty($this->total_localtax2)) $this->total_localtax2=0;
  2404. if (empty($this->rang)) $this->rang=0;
  2405. if (empty($this->remise)) $this->remise=0;
  2406. if (empty($this->remise_percent)) $this->remise_percent=0;
  2407. if (empty($this->info_bits)) $this->info_bits=0;
  2408. if (empty($this->special_code)) $this->special_code=0;
  2409. if (empty($this->fk_parent_line)) $this->fk_parent_line=0;
  2410. if (empty($this->fk_fournprice)) $this->fk_fournprice=0;
  2411. if (empty($this->pa_ht)) $this->pa_ht=0;
  2412. // if buy price not defined, define buyprice as configured in margin admin
  2413. if ($this->pa_ht == 0)
  2414. {
  2415. if (($result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product)) < 0)
  2416. {
  2417. return $result;
  2418. }
  2419. else
  2420. {
  2421. $this->pa_ht = $result;
  2422. }
  2423. }
  2424. // Check parameters
  2425. if ($this->product_type < 0) return -1;
  2426. $this->db->begin();
  2427. // Insert line into database
  2428. $sql = 'INSERT INTO '.MAIN_DB_PREFIX.'supplier_proposaldet';
  2429. $sql.= ' (fk_supplier_proposal, fk_parent_line, label, description, fk_product, product_type,';
  2430. $sql.= ' fk_remise_except, qty, tva_tx, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type,';
  2431. $sql.= ' subprice, remise_percent, ';
  2432. $sql.= ' info_bits, ';
  2433. $sql.= ' total_ht, total_tva, total_localtax1, total_localtax2, total_ttc, fk_product_fournisseur_price, buy_price_ht, special_code, rang,';
  2434. $sql.= ' ref_fourn';
  2435. $sql.= ', fk_multicurrency, multicurrency_code, multicurrency_subprice, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc)';
  2436. $sql.= " VALUES (".$this->fk_supplier_proposal.",";
  2437. $sql.= " ".($this->fk_parent_line>0?"'".$this->fk_parent_line."'":"null").",";
  2438. $sql.= " ".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null").",";
  2439. $sql.= " '".$this->db->escape($this->desc)."',";
  2440. $sql.= " ".($this->fk_product?"'".$this->fk_product."'":"null").",";
  2441. $sql.= " '".$this->product_type."',";
  2442. $sql.= " ".($this->fk_remise_except?"'".$this->fk_remise_except."'":"null").",";
  2443. $sql.= " ".price2num($this->qty).",";
  2444. $sql.= " ".price2num($this->tva_tx).",";
  2445. $sql.= " ".price2num($this->localtax1_tx).",";
  2446. $sql.= " ".price2num($this->localtax2_tx).",";
  2447. $sql.= " '".$this->localtax1_type."',";
  2448. $sql.= " '".$this->localtax2_type."',";
  2449. $sql.= " ".($this->subprice?price2num($this->subprice):"null").",";
  2450. $sql.= " ".price2num($this->remise_percent).",";
  2451. $sql.= " ".(isset($this->info_bits)?"'".$this->info_bits."'":"null").",";
  2452. $sql.= " ".price2num($this->total_ht).",";
  2453. $sql.= " ".price2num($this->total_tva).",";
  2454. $sql.= " ".price2num($this->total_localtax1).",";
  2455. $sql.= " ".price2num($this->total_localtax2).",";
  2456. $sql.= " ".price2num($this->total_ttc).",";
  2457. $sql.= " ".(!empty($this->fk_fournprice)?"'".$this->fk_fournprice."'":"null").",";
  2458. $sql.= " ".(isset($this->pa_ht)?"'".price2num($this->pa_ht)."'":"null").",";
  2459. $sql.= ' '.$this->special_code.',';
  2460. $sql.= ' '.$this->rang.',';
  2461. $sql.= " '".$this->db->escape($this->ref_fourn)."'";
  2462. $sql.= ", ".($this->fk_multicurrency > 0?$this->fk_multicurrency:'null');
  2463. $sql.= ", '".$this->db->escape($this->multicurrency_code)."'";
  2464. $sql.= ", ".$this->multicurrency_subprice;
  2465. $sql.= ", ".$this->multicurrency_total_ht;
  2466. $sql.= ", ".$this->multicurrency_total_tva;
  2467. $sql.= ", ".$this->multicurrency_total_ttc;
  2468. $sql.= ')';
  2469. dol_syslog(get_class($this).'::insert', LOG_DEBUG);
  2470. $resql=$this->db->query($sql);
  2471. if ($resql)
  2472. {
  2473. $this->rowid=$this->db->last_insert_id(MAIN_DB_PREFIX.'supplier_proposaldet');
  2474. $this->id=$this->rowid;
  2475. if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
  2476. {
  2477. $result=$this->insertExtraFields();
  2478. if ($result < 0)
  2479. {
  2480. $error++;
  2481. }
  2482. }
  2483. if (! $notrigger)
  2484. {
  2485. // Call trigger
  2486. $result=$this->call_trigger('LINESUPPLIER_PROPOSAL_INSERT',$user);
  2487. if ($result < 0)
  2488. {
  2489. $this->db->rollback();
  2490. return -1;
  2491. }
  2492. // End call triggers
  2493. }
  2494. $this->db->commit();
  2495. return 1;
  2496. }
  2497. else
  2498. {
  2499. $this->error=$this->db->error()." sql=".$sql;
  2500. $this->db->rollback();
  2501. return -1;
  2502. }
  2503. }
  2504. /**
  2505. * Delete line in database
  2506. *
  2507. * @return int <0 if ko, >0 if ok
  2508. */
  2509. function delete()
  2510. {
  2511. global $conf,$langs,$user;
  2512. $error=0;
  2513. $this->db->begin();
  2514. $sql = "DELETE FROM ".MAIN_DB_PREFIX."supplier_proposaldet WHERE rowid = ".$this->rowid;
  2515. dol_syslog("SupplierProposalLine::delete", LOG_DEBUG);
  2516. if ($this->db->query($sql) )
  2517. {
  2518. // Remove extrafields
  2519. if ((! $error) && (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED))) // For avoid conflicts if trigger used
  2520. {
  2521. $this->id=$this->rowid;
  2522. $result=$this->deleteExtraFields();
  2523. if ($result < 0)
  2524. {
  2525. $error++;
  2526. dol_syslog(get_class($this)."::delete error -4 ".$this->error, LOG_ERR);
  2527. }
  2528. }
  2529. // Call trigger
  2530. $result=$this->call_trigger('LINESUPPLIER_PROPOSAL_DELETE',$user);
  2531. if ($result < 0)
  2532. {
  2533. $this->db->rollback();
  2534. return -1;
  2535. }
  2536. // End call triggers
  2537. $this->db->commit();
  2538. return 1;
  2539. }
  2540. else
  2541. {
  2542. $this->error=$this->db->error()." sql=".$sql;
  2543. $this->db->rollback();
  2544. return -1;
  2545. }
  2546. }
  2547. /**
  2548. * Update propal line object into DB
  2549. *
  2550. * @param int $notrigger 1=Does not execute triggers, 0= execuete triggers
  2551. * @return int <0 if ko, >0 if ok
  2552. */
  2553. function update($notrigger=0)
  2554. {
  2555. global $conf,$langs,$user;
  2556. $error=0;
  2557. // Clean parameters
  2558. if (empty($this->tva_tx)) $this->tva_tx=0;
  2559. if (empty($this->localtax1_tx)) $this->localtax1_tx=0;
  2560. if (empty($this->localtax2_tx)) $this->localtax2_tx=0;
  2561. if (empty($this->total_localtax1)) $this->total_localtax1=0;
  2562. if (empty($this->total_localtax2)) $this->total_localtax2=0;
  2563. if (empty($this->localtax1_type)) $this->localtax1_type=0;
  2564. if (empty($this->localtax2_type)) $this->localtax2_type=0;
  2565. if (empty($this->marque_tx)) $this->marque_tx=0;
  2566. if (empty($this->marge_tx)) $this->marge_tx=0;
  2567. if (empty($this->price)) $this->price=0; // TODO A virer
  2568. if (empty($this->remise)) $this->remise=0; // TODO A virer
  2569. if (empty($this->remise_percent)) $this->remise_percent=0;
  2570. if (empty($this->info_bits)) $this->info_bits=0;
  2571. if (empty($this->special_code)) $this->special_code=0;
  2572. if (empty($this->fk_parent_line)) $this->fk_parent_line=0;
  2573. if (empty($this->fk_fournprice)) $this->fk_fournprice=0;
  2574. if (empty($this->pa_ht)) $this->pa_ht=0;
  2575. // if buy price not defined, define buyprice as configured in margin admin
  2576. if ($this->pa_ht == 0)
  2577. {
  2578. if (($result = $this->defineBuyPrice($this->subprice, $this->remise_percent, $this->fk_product)) < 0)
  2579. {
  2580. return $result;
  2581. }
  2582. else
  2583. {
  2584. $this->pa_ht = $result;
  2585. }
  2586. }
  2587. $this->db->begin();
  2588. // Mise a jour ligne en base
  2589. $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposaldet SET";
  2590. $sql.= " description='".$this->db->escape($this->desc)."'";
  2591. $sql.= " , label=".(! empty($this->label)?"'".$this->db->escape($this->label)."'":"null");
  2592. $sql.= " , product_type=".$this->product_type;
  2593. $sql.= " , tva_tx='".price2num($this->tva_tx)."'";
  2594. $sql.= " , localtax1_tx=".price2num($this->localtax1_tx);
  2595. $sql.= " , localtax2_tx=".price2num($this->localtax2_tx);
  2596. $sql.= " , localtax1_type='".$this->localtax1_type."'";
  2597. $sql.= " , localtax2_type='".$this->localtax2_type."'";
  2598. $sql.= " , qty='".price2num($this->qty)."'";
  2599. $sql.= " , subprice=".price2num($this->subprice)."";
  2600. $sql.= " , remise_percent=".price2num($this->remise_percent)."";
  2601. $sql.= " , price=".price2num($this->price).""; // TODO A virer
  2602. $sql.= " , remise=".price2num($this->remise).""; // TODO A virer
  2603. $sql.= " , info_bits='".$this->info_bits."'";
  2604. if (empty($this->skip_update_total))
  2605. {
  2606. $sql.= " , total_ht=".price2num($this->total_ht)."";
  2607. $sql.= " , total_tva=".price2num($this->total_tva)."";
  2608. $sql.= " , total_ttc=".price2num($this->total_ttc)."";
  2609. $sql.= " , total_localtax1=".price2num($this->total_localtax1)."";
  2610. $sql.= " , total_localtax2=".price2num($this->total_localtax2)."";
  2611. }
  2612. $sql.= " , fk_product_fournisseur_price=".(! empty($this->fk_fournprice)?"'".$this->fk_fournprice."'":"null");
  2613. $sql.= " , buy_price_ht=".price2num($this->pa_ht);
  2614. if (strlen($this->special_code)) $sql.= " , special_code=".$this->special_code;
  2615. $sql.= " , fk_parent_line=".($this->fk_parent_line>0?$this->fk_parent_line:"null");
  2616. if (! empty($this->rang)) $sql.= ", rang=".$this->rang;
  2617. $sql.= " , ref_fourn=".(! empty($this->ref_fourn)?"'".$this->db->escape($this->ref_fourn)."'":"null");
  2618. // Multicurrency
  2619. $sql.= " , multicurrency_subprice=".price2num($this->multicurrency_subprice)."";
  2620. $sql.= " , multicurrency_total_ht=".price2num($this->multicurrency_total_ht)."";
  2621. $sql.= " , multicurrency_total_tva=".price2num($this->multicurrency_total_tva)."";
  2622. $sql.= " , multicurrency_total_ttc=".price2num($this->multicurrency_total_ttc)."";
  2623. $sql.= " WHERE rowid = ".$this->rowid;
  2624. dol_syslog(get_class($this)."::update", LOG_DEBUG);
  2625. $resql=$this->db->query($sql);
  2626. if ($resql)
  2627. {
  2628. if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used
  2629. {
  2630. $this->id=$this->rowid;
  2631. $result=$this->insertExtraFields();
  2632. if ($result < 0)
  2633. {
  2634. $error++;
  2635. }
  2636. }
  2637. if (! $notrigger)
  2638. {
  2639. // Call trigger
  2640. $result=$this->call_trigger('LINESUPPLIER_PROPOSAL_UPDATE',$user);
  2641. if ($result < 0)
  2642. {
  2643. $this->db->rollback();
  2644. return -1;
  2645. }
  2646. // End call triggers
  2647. }
  2648. $this->db->commit();
  2649. return 1;
  2650. }
  2651. else
  2652. {
  2653. $this->error=$this->db->error();
  2654. $this->db->rollback();
  2655. return -2;
  2656. }
  2657. }
  2658. /**
  2659. * Update DB line fields total_xxx
  2660. * Used by migration
  2661. *
  2662. * @return int <0 if ko, >0 if ok
  2663. */
  2664. function update_total()
  2665. {
  2666. $this->db->begin();
  2667. // Mise a jour ligne en base
  2668. $sql = "UPDATE ".MAIN_DB_PREFIX."supplier_proposaldet SET";
  2669. $sql.= " total_ht=".price2num($this->total_ht,'MT')."";
  2670. $sql.= ",total_tva=".price2num($this->total_tva,'MT')."";
  2671. $sql.= ",total_ttc=".price2num($this->total_ttc,'MT')."";
  2672. $sql.= " WHERE rowid = ".$this->rowid;
  2673. dol_syslog("SupplierProposalLine::update_total", LOG_DEBUG);
  2674. $resql=$this->db->query($sql);
  2675. if ($resql)
  2676. {
  2677. $this->db->commit();
  2678. return 1;
  2679. }
  2680. else
  2681. {
  2682. $this->error=$this->db->error();
  2683. $this->db->rollback();
  2684. return -2;
  2685. }
  2686. }
  2687. }