PageRenderTime 57ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/htdocs/core/class/abstractinvoice.class.php

https://bitbucket.org/speedealing/speedealing
PHP | 560 lines | 410 code | 81 blank | 69 comment | 42 complexity | 4e5514f70d24520485820f224c65a84c MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, GPL-3.0, MIT
  1. <?php
  2. require_once DOL_DOCUMENT_ROOT . '/core/class/nosqlDocument.class.php';
  3. class AbstractInvoice extends nosqlDocument {
  4. var $lines = array();
  5. public function load($id) {
  6. $res = parent::load($id);
  7. // Attribuer un id à chaque ligne
  8. for ($i = 0; $i < count($this->lines); $i++) {
  9. $this->lines[$i]->id = $i + 1;
  10. }
  11. return $res;
  12. }
  13. public function record() {
  14. // ne pas sauvegarder l'id des lignes
  15. for ($i = 0; $i < count($this->lines); $i++)
  16. $this->lines[$i]->id = null;
  17. return parent::record();
  18. }
  19. /**
  20. * Update a line in database
  21. *
  22. * @param int $rowid Id of line to update
  23. * @return int < 0 if KO, > 0 if OK
  24. */
  25. function updateline($lineid, $line) {
  26. global $conf;
  27. $this->lines[$lineid] = new stdClass();
  28. foreach (get_object_vars($line) as $key => $aRow)
  29. $this->lines[$lineid]->$key = $aRow;
  30. $this->lines = array_merge($this->lines);
  31. $this->update_price();
  32. return 1;
  33. }
  34. /**
  35. * Delete an order line
  36. *
  37. * @param int $lineid Id of line to delete
  38. * @return int >0 if OK, 0 if nothing to do, <0 if KO
  39. */
  40. function deleteline($lineid) {
  41. global $user;
  42. if ($this->Status == "DRAFT") {
  43. unset($this->lines[$lineid - 1]);
  44. $this->lines = array_merge($this->lines);
  45. $this->update_price(1);
  46. return 1;
  47. } else {
  48. return -2;
  49. }
  50. }
  51. function update_price($exclspec = 0, $roundingadjust = -1, $nodatabaseupdate = 0) {
  52. $this->total_ht = 0;
  53. $this->total_localtax1 = 0;
  54. $this->total_localtax2 = 0;
  55. $this->total_tva = 0;
  56. $this->total_ttc = 0;
  57. foreach ($this->lines as $line) {
  58. $this->total_ht += $line->total_ht;
  59. $this->total_localtax1 += $line->total_localtax1;
  60. $this->total_localtax2 += $line->totaltaxt1;
  61. $this->total_tva += $line->total_tva;
  62. $this->total_ttc += $line->total_ttc;
  63. }
  64. return 1;
  65. }
  66. /**
  67. * For menu Add/Remove a datatable
  68. *
  69. * @param $ref_css name of #list
  70. * @return string
  71. */
  72. public function datatablesEditLine($ref_css, $title = "") {
  73. global $langs, $user;
  74. $class = strtolower(get_class($this));
  75. if (!$user->rights->$class->edit && !$user->rights->$class->creer)
  76. return null;
  77. if (count($this->fk_extrafields->createLine)) {
  78. print '<form id="' . $ref_css . '_formAddNewRow" class="block" title="' . $title . '">';
  79. //print '<input type="hidden" name="token" value="' . $_SESSION['newtoken'] . '">';
  80. print '<input type="hidden" name="json" id="json" value="addline" />';
  81. print '<input type="hidden" name="fk_invoice" id="fk_invoice" value="' . $this->id . '" />';
  82. print '<input type="hidden" name="class" id="class" value="' . get_class($this) . '" />';
  83. foreach ($this->fk_extrafields->createLine as $aRow) {
  84. print '<p class="button-height block-label">';
  85. $label = $langs->trans($this->fk_extrafields->fields->$aRow->label);
  86. if (empty($label))
  87. $label = $langs->trans($aRow);
  88. print '<label for = "' . $aRow . '" class="label">' . $label . '</label>';
  89. print $this->select_fk_extrafields($aRow, $aRow, null, true, 40, "full-width");
  90. print '</p>';
  91. }
  92. print '</form>';
  93. if ($user->rights->$class->edit || $user->rights->$class->creer) {
  94. //print '<button id="' . $ref_css . '_btnAddNewRow">' . $langs->trans("Add") . '</button> ';
  95. $head[0] = new stdClass();
  96. $head[0]->title = $langs->trans("Add");
  97. $head[0]->id = $ref_css . '_btnAddNewRow';
  98. $head[0]->href = "#";
  99. $head[0]->icon = "icon-pencil";
  100. $head[0]->onclick = "return false;";
  101. }
  102. }
  103. /* if ($user->rights->$class->delete)
  104. print '<button id="' . $ref_css . '_btnDeleteRow">' . $langs->trans("Delete") . '</button>'; */
  105. //print '<p class="button-height "></p>';
  106. return $head;
  107. }
  108. public function showLines() {
  109. global $langs;
  110. global $conf;
  111. require_once(DOL_DOCUMENT_ROOT . '/product/class/product.class.php');
  112. switch (get_class($this)) {
  113. case 'Commande':
  114. $title = $langs->trans('OrderLines');
  115. $url = 'commande/fiche.php';
  116. break;
  117. case 'Propal':
  118. $title = $langs->trans('PropalLines');
  119. $url = 'propal/fiche.php';
  120. break;
  121. case 'Facture':
  122. $title = $langs->trans('FactureLines');
  123. $url = 'facture/fiche.php';
  124. break;
  125. }
  126. //print start_box(, "twelve", $object->fk_extrafields->ico, false);
  127. //print show_title($title);
  128. $head = $this->datatablesEditLine("listlines", $langs->trans("Lines"));
  129. print start_box($title, "icon-bag", $head);
  130. $i = 0;
  131. print '<table class="display dt_act" id="listlines" >';
  132. // Ligne des titres
  133. print'<thead>';
  134. print'<tr>';
  135. print'<th>';
  136. print'</th>';
  137. $obj->aoColumns[$i] = new stdClass();
  138. $obj->aoColumns[$i]->mDataProp = "_id";
  139. $obj->aoColumns[$i]->bUseRendered = false;
  140. $obj->aoColumns[$i]->bSearchable = false;
  141. $obj->aoColumns[$i]->bVisible = false;
  142. $i++;
  143. print'<th class="essential">';
  144. print $langs->trans("Group");
  145. print'</th>';
  146. $obj->aoColumns[$i] = new stdClass();
  147. $obj->aoColumns[$i]->mDataProp = "group";
  148. $obj->aoColumns[$i]->sDefaultContent = "";
  149. $obj->aoColumns[$i]->bVisible = false;
  150. $i++;
  151. print'<th class="essential">';
  152. $product = new Product($this->db);
  153. print $langs->trans("Product");
  154. print'</th>';
  155. $obj->aoColumns[$i] = new stdClass();
  156. $obj->aoColumns[$i]->mDataProp = "product.label";
  157. $obj->aoColumns[$i]->bUseRendered = false;
  158. $obj->aoColumns[$i]->bSearchable = true;
  159. $obj->aoColumns[$i]->sDefaultContent = "";
  160. $obj->aoColumns[$i]->fnRender = $product->datatablesFnRender("product.label", "url", array("id" => "product.id", "title" => "product.ref"));
  161. $i++;
  162. print'<th class="essential">';
  163. print $langs->trans("Description");
  164. print'</th>';
  165. $obj->aoColumns[$i] = new stdClass();
  166. $obj->aoColumns[$i]->mDataProp = "description";
  167. $obj->aoColumns[$i]->bUseRendered = false;
  168. $obj->aoColumns[$i]->bSearchable = true;
  169. $obj->aoColumns[$i]->editable = true;
  170. $obj->aoColumns[$i]->sDefaultContent = "";
  171. $i++;
  172. print'<th class="essential">';
  173. print $langs->trans("VAT");
  174. print'</th>';
  175. $obj->aoColumns[$i] = new stdClass();
  176. $obj->aoColumns[$i]->mDataProp = "tva_tx";
  177. $obj->aoColumns[$i]->bUseRendered = false;
  178. $obj->aoColumns[$i]->bSearchable = true;
  179. $obj->aoColumns[$i]->editable = true;
  180. $obj->aoColumns[$i]->sDefaultContent = 0;
  181. $i++;
  182. print'<th class="essential">';
  183. print $langs->trans("PriceUHT");
  184. print'</th>';
  185. $obj->aoColumns[$i] = new stdClass();
  186. $obj->aoColumns[$i]->mDataProp = "pu_ht";
  187. $obj->aoColumns[$i]->bUseRendered = false;
  188. $obj->aoColumns[$i]->bSearchable = true;
  189. $obj->aoColumns[$i]->editable = true;
  190. $obj->aoColumns[$i]->fnRender = $this->datatablesFnRender("pu_ht", "price");
  191. $obj->aoColumns[$i]->sDefaultContent = 0;
  192. $i++;
  193. print'<th class="essential">';
  194. print $langs->trans("Qty");
  195. print'</th>';
  196. $obj->aoColumns[$i] = new stdClass();
  197. $obj->aoColumns[$i]->mDataProp = "qty";
  198. $obj->aoColumns[$i]->bUseRendered = false;
  199. $obj->aoColumns[$i]->bSearchable = true;
  200. $obj->aoColumns[$i]->editable = true;
  201. $obj->aoColumns[$i]->sDefaultContent = 0;
  202. $i++;
  203. print'<th class="essential">';
  204. print $langs->trans("ReductionShort");
  205. print'</th>';
  206. $obj->aoColumns[$i] = new stdClass();
  207. $obj->aoColumns[$i]->mDataProp = "remise";
  208. $obj->aoColumns[$i]->bUseRendered = false;
  209. $obj->aoColumns[$i]->bSearchable = true;
  210. $obj->aoColumns[$i]->editable = true;
  211. $obj->aoColumns[$i]->sDefaultContent = "0";
  212. $i++;
  213. print'<th class="essential">';
  214. print $langs->trans("TotalHTShort");
  215. print'</th>';
  216. $obj->aoColumns[$i] = new stdClass();
  217. $obj->aoColumns[$i]->mDataProp = "total_ht";
  218. $obj->aoColumns[$i]->bUseRendered = false;
  219. $obj->aoColumns[$i]->bSearchable = true;
  220. $obj->aoColumns[$i]->editable = true;
  221. $obj->aoColumns[$i]->fnRender = $this->datatablesFnRender("total_ht", "price");
  222. $obj->aoColumns[$i]->sDefaultContent = 0;
  223. $i++;
  224. print'<th class="essential">';
  225. print $langs->trans('Action');
  226. print'</th>';
  227. $obj->aoColumns[$i] = new stdClass();
  228. $obj->aoColumns[$i]->mDataProp = "";
  229. $obj->aoColumns[$i]->sClass = "center content_actions";
  230. $obj->aoColumns[$i]->sWidth = "60px";
  231. $obj->aoColumns[$i]->bSortable = false;
  232. $obj->aoColumns[$i]->sDefaultContent = "";
  233. $obj->aoColumns[$i]->fnRender = 'function(obj) {
  234. var ar = [];
  235. ar[ar.length] = "<a href=\"\"";
  236. ar[ar.length] = " class=\"delEnqBtn\" title=\"' . $langs->trans("Delete") . '\"><img src=\"' . DOL_URL_ROOT . '/theme/' . $conf->theme . '/img/delete.png\" alt=\"\" /></a>";
  237. var str = ar.join("");
  238. return str;
  239. }';
  240. print'</tr>';
  241. print'</thead>';
  242. print'<tfoot>';
  243. print'</tfoot>';
  244. print'<tbody>';
  245. print'</tbody>';
  246. print "</table>";
  247. $obj->fnDrawCallback = "function(oSettings){
  248. if ( oSettings.aiDisplay.length == 0 )
  249. {
  250. return;
  251. }
  252. var nTrs = jQuery('#listlines tbody tr');
  253. var iColspan = nTrs[0].getElementsByTagName('td').length;
  254. var sLastGroup = '';
  255. for ( var i=0 ; i<nTrs.length ; i++ )
  256. {
  257. var iDisplayIndex = oSettings._iDisplayStart + i;
  258. var sGroup = oSettings.aoData[ oSettings.aiDisplay[iDisplayIndex] ]._aData['group'];
  259. if (sGroup!=null && sGroup!='' && sGroup != sLastGroup)
  260. {
  261. var nGroup = document.createElement('tr');
  262. var nCell = document.createElement('td');
  263. nCell.colSpan = iColspan;
  264. nCell.className = 'group';
  265. nCell.innerHTML = sGroup;
  266. nGroup.appendChild( nCell );
  267. nTrs[i].parentNode.insertBefore( nGroup, nTrs[i] );
  268. sLastGroup = sGroup;
  269. }
  270. }
  271. }";
  272. $obj->aaSorting = array(array(1, 'asc'));
  273. //$obj->bServerSide = true;
  274. //if ($all) {
  275. // if ($type == "DONE")
  276. // $obj->sAjaxSource = "core/ajax/listdatatables.php?json=actionsDONE&class=" . get_class($object);
  277. // else
  278. // $obj->sAjaxSource = "core/ajax/listdatatables.php?json=actionsTODO&class=" . get_class($object);
  279. //} else {
  280. // if ($type == "DONE")
  281. // $obj->sAjaxSource = $_SERVER["PHP_SELF"] . "?json=listDONEByUser";
  282. // else
  283. // $obj->sAjaxSource = $_SERVER["PHP_SELF"] . "?json=listTODOByUser";
  284. //
  285. //}
  286. $obj->sAjaxSource = $_SERVER["PHP_SELF"] . "?json=lines&id=" . $this->id;
  287. $this->datatablesCreate($obj, "listlines", true, true);
  288. print end_box();
  289. }
  290. /**
  291. * return div with total table
  292. *
  293. * @return @string
  294. */
  295. function showAmounts() {
  296. global $conf, $user, $langs;
  297. $out = start_box($langs->trans("Summary"), "icon-bag");
  298. //$out.= '<legend class="anthracite large"><div class="no-margin-bottom left-icon icon-bag">' . $langs->trans("Summary") . '</div></legend>';
  299. $out.= '<table class="simple-table responsive-table" id="table-amount">
  300. <!--
  301. <thead>
  302. <tr>
  303. <th scope="col"><div class="no-margin-bottom red left-icon icon-bag"><h4 class="no-margin-bottom">' . $langs->trans("Summary") . '</h4></div></th>
  304. <th scope="col" width="40%"></th>
  305. <th scope="col" width="15%" class="hide-on-mobile-portrait"></th>
  306. </tr>
  307. </thead>
  308. -->
  309. <tbody>';
  310. foreach ($this->fk_extrafields->amountsBox as $aRow) {
  311. $out.= '<tr>
  312. <th scope="row">';
  313. if (isset($this->fk_extrafields->fields->$aRow->icon))
  314. $out.= '<span class="left-icon ' . $this->fk_extrafields->fields->$aRow->icon . '">' . $langs->trans($this->fk_extrafields->fields->$aRow->label) . '</span>';
  315. else
  316. $out.= $langs->trans($this->fk_extrafields->fields->$aRow->label);
  317. $out.= '</th>
  318. <td align="right">';
  319. if (isset($this->fk_extrafields->fields->$aRow->cssClass))
  320. $out.= '<span class="' . $this->fk_extrafields->fields->$aRow->cssClass . '">';
  321. if ($this->fk_extrafields->fields->$aRow->price)
  322. $out.= price(price2num($this->$aRow, 'MT'));
  323. else
  324. $out.= $this->$aRow;
  325. if (isset($this->fk_extrafields->fields->$aRow->cssClass))
  326. $out.= '</span>';
  327. $out.='</td>
  328. <td>';
  329. if ($this->fk_extrafields->fields->$aRow->mode == "absolute")
  330. $out.= $langs->trans('Currency' . $conf->currency);
  331. else
  332. $out.= "%";
  333. $out.='</td>
  334. </tr>';
  335. }
  336. $out.='</tbody></table>';
  337. $out.=end_box();
  338. return $out;
  339. }
  340. /**
  341. * return address bloc
  342. *
  343. * @return @string
  344. */
  345. function showAddresses() {
  346. global $conf, $user, $langs;
  347. //$out = start_box($langs->trans("ContactsAddresses"), "icon-bag");
  348. $out.= '<div class="standard-tabs">';
  349. // Tabs
  350. $out.= '<ul class="tabs">';
  351. $out.= '<li class="active"><a href="#tab-1">' . $langs->trans('DeliveryAddress') . '</a></li>';
  352. $out.= '<li><a href="#tab-2">' . $langs->trans('BillingAddress') . '</a></li>';
  353. $out.= '</ul>';
  354. // Contents
  355. $out.= '<div class="tabs-content">';
  356. $out.= '<div id="tab-1" class="with-padding">';
  357. $out.= '<br><br><br><br>Delivery address content<br><br><br><br>';
  358. $out.= '</div>';
  359. $out.= '<div id="tab-2" class="with-padding">';
  360. $out.= '<br><br><br><<br>Billing address content<br><br><br><br>';
  361. $out.= '</div>';
  362. $out.= '</div>';
  363. $out.= '</div>';
  364. //$out.= end_box();
  365. return $out;
  366. }
  367. }
  368. class Line {
  369. var $rowid;
  370. var $desc;
  371. var $pu;
  372. var $qty;
  373. var $remise_percent;
  374. var $tva_tx;
  375. var $price_base_type = 'HT';
  376. var $info_bits = 0;
  377. var $date_start = '';
  378. var $date_end = '';
  379. var $type = 0;
  380. var $fk_parent_line = 0;
  381. var $skip_update_total = 0;
  382. var $fk_fournprice = null;
  383. var $pa_ht = 0;
  384. var $label = '';
  385. var $group = '';
  386. function __construct() {
  387. //TODO Load extrafields
  388. }
  389. function load($line) {
  390. if (is_object($line))
  391. foreach ($line as $key => $row)
  392. $this->$key = $row;
  393. }
  394. function verify() {
  395. // Clean parameters
  396. if (empty($this->qty))
  397. $this->qty = 0;
  398. if (empty($this->info_bits))
  399. $this->info_bits = 0;
  400. if (empty($this->tva_tx))
  401. $this->tva_tx = 0;
  402. if (empty($this->remise))
  403. $this->remise = 0;
  404. if (empty($this->remise_percent))
  405. $this->remise_percent = 0;
  406. $this->remise_percent = price2num($this->remise_percent);
  407. $this->qty = price2num($this->qty);
  408. if ($this->price_base_type == 'HT')
  409. $this->pu = price2num($this->pu_ht);
  410. else
  411. $this->pu = price2num($this->pu_ttc);
  412. $this->pa_ht = price2num($this->pa_ht);
  413. $this->tva_tx = price2num($this->tva_tx);
  414. // Calcul du total TTC et de la TVA pour la ligne a partir de
  415. // qty, pu, remise_percent et tva_tx
  416. // TRES IMPORTANT: C'est au moment de l'insertion ligne qu'on doit stocker
  417. // la part ht, tva et ttc, et ce au niveau de la ligne qui a son propre taux tva.
  418. $this->calcul_price_total();
  419. return 1;
  420. }
  421. function calcul_price_total() {
  422. global $conf, $mysoc;
  423. // initialize total (may be HT or TTC depending on price_base_type)
  424. $tot_sans_remise = $this->pu * $this->qty;
  425. $tot_avec_remise_ligne = $tot_sans_remise * (1 - ($this->remise_percent_ligne / 100));
  426. $tot_avec_remise = $tot_avec_remise_ligne * (1 - ($this->remise_percent_global / 100));
  427. // initialize result
  428. $this->total_tva = 0;
  429. $this->total_ttc = 0;
  430. if ($this->price_base_type == 'HT') {
  431. // We work to define prices using the price without tax
  432. $this->total_ht_without_discount = $tot_sans_remise;
  433. $this->total_ttc_without_discount = $tot_sans_remise * (1 + ( (($this->info_bits & 1) ? 0 : $this->tva_tx) / 100)); // Selon TVA NPR ou non
  434. $result8bis = $tot_sans_remise * (1 + ( $this->tva_tx / 100)); // Si TVA consideree normale (non NPR)
  435. $this->total_vat_without_discount = $result8bis - ($this->total_ht_without_discount);
  436. $this->total_ht = $tot_avec_remise;
  437. $this->total_ttc = $tot_avec_remise * (1 + ( (($this->info_bits & 1) ? 0 : $this->tva_tx) / 100)); // Selon TVA NPR ou non
  438. $result2bis = $tot_avec_remise * (1 + ( $this->tva_tx / 100)); // Si TVA consideree normale (non NPR)
  439. $this->total_tva = $result2bis - ($this->total_ht); // Total VAT = TTC - (HT + localtax)
  440. $this->pu_ht = $this->pu;
  441. $this->pu_ttc = $this->pu * (1 + ((($this->info_bits & 1) ? 0 : $this->tva_tx) / 100)); // Selon TVA NPR ou non
  442. $result5bis = $this->pu * (1 + ($this->tva_tx / 100)); // Si TVA consideree normale (non NPR)
  443. $this->pu_tva = $result5bis - ($this->pu_ht);
  444. } else {
  445. // We work to define prices using the price with tax
  446. $this->total_ttc_without_discount = $tot_sans_remise;
  447. $this->total_ht_without_discount = $tot_sans_remise / (1 + ((($this->info_bits & 1) ? 0 : $this->tva_tx) / 100)); // Selon TVA NPR ou non
  448. $result6bis = $tot_sans_remise / (1 + ($this->tva_tx / 100)); // Si TVA consideree normale (non NPR)
  449. $this->total_vat_without_discount = $this->total_ttc_without_discount - ($result6bis );
  450. $this->total_ttc = $tot_avec_remise;
  451. $this->total_ht = $tot_avec_remise / (1 + ((($this->info_bits & 1) ? 0 : $this->tva_tx) / 100)); // Selon TVA NPR ou non
  452. $result0bis = $tot_avec_remise / (1 + ($this->tva_tx / 100)); // Si TVA consideree normale (non NPR)
  453. $this->total_tva = $this->total_ttc - ($result0bis ); // Total VAT = TTC - HT
  454. $this->pu_ttc = $this->pu;
  455. $this->pu_ht = $this->pu / (1 + ((($this->info_bits & 1) ? 0 : $this->tva_tx) / 100)); // Selon TVA NPR ou non
  456. $result3bis = $this->pu / (1 + ($this->tva_tx / 100)); // Si TVA consideree normale (non NPR)
  457. $this->pu_tva = $this->pu_ttc - $result3bis;
  458. }
  459. //If price is 'TTC' we need to have the totals without VAT for a correct calculation
  460. if ($this->price_base_type == 'TTC') {
  461. $tot_sans_remise = $tot_sans_remise / (1 + ($this->tva_tx / 100));
  462. $tot_avec_remise = $tot_avec_remise / (1 + ($this->tva_tx / 100));
  463. }
  464. // If rounding is not using base 10 (rare)
  465. if (!empty($conf->global->MAIN_ROUNDING_RULE_TOT)) {
  466. if ($this->price_base_type == 'HT') {
  467. $this->total_ht = round($this->total_ht / $conf->global->MAIN_ROUNDING_RULE_TOT, 0) * $conf->global->MAIN_ROUNDING_RULE_TOT;
  468. $this->total_tva = round($this->total_tva / $conf->global->MAIN_ROUNDING_RULE_TOT, 0) * $conf->global->MAIN_ROUNDING_RULE_TOT;
  469. $this->total_ttc = price2num($this->total_ht + $this->total_tva, 'MT');
  470. } else {
  471. $this->total_tva = round($this->total_tva / $conf->global->MAIN_ROUNDING_RULE_TOT, 0) * $conf->global->MAIN_ROUNDING_RULE_TOT;
  472. $this->total_ttc = round($this->total_ttc / $conf->global->MAIN_ROUNDING_RULE_TOT, 0) * $conf->global->MAIN_ROUNDING_RULE_TOT;
  473. $this->total_ht = price2num($this->total_ttc - $this->total_ht, 'MT');
  474. }
  475. }
  476. //print "Price.lib::calcul_price_total ".$this->total_ht."-".$this->total_tva."-".$this->total_ttc
  477. }
  478. }
  479. ?>