price.lib.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. <?php
  2. /* Copyright (C) 2002-2006 Rodolphe Quiedeville <rodolphe@quiedeville.org>
  3. * Copyright (C) 2006-2008 Laurent Destailleur <eldy@users.sourceforge.net>
  4. * Copyright (C) 2010-2013 Juanjo Menent <jmenent@2byte.es>
  5. * Copyright (C) 2012 Christophe Battarel <christophe.battarel@altairis.fr>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. /**
  21. * \file htdocs/core/lib/price.lib.php
  22. * \brief Library with functions to calculate prices
  23. */
  24. /**
  25. * Calculate totals (net, vat, ...) of a line.
  26. * Value for localtaxX_type are '0' : local tax not applied
  27. * '1' : local tax apply on products and services without vat (vat is not applied for local tax calculation)
  28. * '2' : local tax apply on products and services before vat (vat is calculated on amount + localtax)
  29. * '3' : local tax apply on products without vat (vat is not applied for local tax calculation)
  30. * '4' : local tax apply on products before vat (vat is calculated on amount + localtax)
  31. * '5' : local tax apply on services without vat (vat is not applied for local tax calculation)
  32. * '6' : local tax apply on services before vat (vat is calculated on amount + localtax)
  33. * '7' : local tax is a fix amount applied on global invoice
  34. *
  35. * @param int $qty Quantity
  36. * @param float $pu Unit price (HT or TTC selon price_base_type)
  37. * @param float $remise_percent_ligne Discount for line
  38. * @param float $txtva 0=do not apply standard tax, Vat rate=apply
  39. * @param float $uselocaltax1_rate 0=do not use this localtax, >0=apply, -1=autodetect according to seller
  40. * @param float $uselocaltax2_rate 0=do not use this localtax, >0=apply, -1=autodetect according to seller
  41. * @param float $remise_percent_global 0
  42. * @param string $price_base_type HT=on calcule sur le HT, TTC=on calcule sur le TTC
  43. * @param int $info_bits Miscellaneous informations on line
  44. * @param int $type 0/1=Product/service
  45. * @param Societe $seller Thirdparty seller (we need $seller->country_id property). Provided only if seller is the supplier, otherwise $seller will be $mysoc.
  46. * @param array $localtaxes_array Array with localtaxes info (loaded by getLocalTaxesFromRate function).
  47. * @return result[ 0=total_ht,
  48. * 1=total_vat,
  49. * 2=total_ttc,
  50. * 3=pu_ht,
  51. * 4=pu_tva,
  52. * 5=pu_ttc,
  53. * 6=total_ht_without_discount,
  54. * 7=total_vat_without_discount,
  55. * 8=total_ttc_without_discount,
  56. * 9=amount tax1 for total_ht,
  57. * 10=amount tax2 for total_ht,
  58. * 11=amount tax1 for pu_ht,
  59. * 12=amount tax2 for pu_ht,
  60. * 13=not used???,
  61. * 14=amount tax1 for total_ht_without_discount,
  62. * 15=amount tax2 for total_ht_without_discount]
  63. */
  64. function calcul_price_total($qty, $pu, $remise_percent_ligne, $txtva, $uselocaltax1_rate, $uselocaltax2_rate, $remise_percent_global, $price_base_type, $info_bits, $type, $seller = '',$localtaxes_array='')
  65. {
  66. global $conf,$mysoc,$db;
  67. $result=array();
  68. // Clean parameters
  69. if (empty($txtva)) $txtva=0;
  70. if (empty($seller) || ! is_object($seller))
  71. {
  72. dol_syslog("calcul_price_total Warning: function is called with parameter seller that is missing", LOG_WARNING);
  73. if (! is_object($mysoc)) // mysoc may be not defined (during migration process)
  74. {
  75. $mysoc=new Societe($db);
  76. $mysoc->setMysoc($conf);
  77. }
  78. $seller=$mysoc; // If sell is done to a customer, $seller is not provided, we use $mysoc
  79. //var_dump($seller->country_id);exit;
  80. }
  81. if (empty($localtaxes_array) || ! is_array($localtaxes_array))
  82. {
  83. dol_syslog("calcul_price_total Warning: function is called with parameter localtaxes_array that is missing", LOG_WARNING);
  84. }
  85. // Too verbose. Enable for debug only
  86. //dol_syslog("calcul_price_total qty=".$qty." pu=".$pu." remiserpercent_ligne=".$remise_percent_ligne." txtva=".$txtva." uselocaltax1_rate=".$uselocaltax1_rate." uselocaltax2_rate=".$uselocaltax2_rate);
  87. $countryid=$seller->country_id;
  88. if ($uselocaltax1_rate < 0) $uselocaltax1_rate=$seller->localtax1_assuj;
  89. if ($uselocaltax2_rate < 0) $uselocaltax2_rate=$seller->localtax2_assuj;
  90. // Now we search localtaxes information ourself (rates and types).
  91. $localtax1_type=0;
  92. $localtax2_type=0;
  93. if (is_array($localtaxes_array))
  94. {
  95. $localtax1_type = $localtaxes_array[0];
  96. $localtax1_rate = $localtaxes_array[1];
  97. $localtax2_type = $localtaxes_array[2];
  98. $localtax2_rate = $localtaxes_array[3];
  99. }
  100. else
  101. {
  102. $sql = "SELECT taux, localtax1, localtax2, localtax1_type, localtax2_type";
  103. $sql.= " FROM ".MAIN_DB_PREFIX."c_tva as cv";
  104. $sql.= " WHERE cv.taux = ".$txtva;
  105. $sql.= " AND cv.fk_pays = ".$countryid;
  106. dol_syslog("calcul_price_total search vat information sql=".$sql);
  107. $resql = $db->query($sql);
  108. if ($resql)
  109. {
  110. $obj = $db->fetch_object($resql);
  111. if ($obj)
  112. {
  113. $localtax1_rate=$obj->localtax1;
  114. $localtax2_rate=$obj->localtax2;
  115. $localtax1_type=$obj->localtax1_type;
  116. $localtax2_type=$obj->localtax2_type;
  117. //var_dump($localtax1_rate.' '.$localtax2_rate.' '.$localtax1_type.' '.$localtax2_type);exit;
  118. }
  119. }
  120. else dol_print_error($db);
  121. }
  122. // initialize total (may be HT or TTC depending on price_base_type)
  123. $tot_sans_remise = $pu * $qty;
  124. $tot_avec_remise_ligne = $tot_sans_remise * (1 - ($remise_percent_ligne / 100));
  125. $tot_avec_remise = $tot_avec_remise_ligne * (1 - ($remise_percent_global / 100));
  126. // initialize result
  127. for ($i=0; $i <= 15; $i++) $result[$i] = 0;
  128. // if there's some localtax including vat, we calculate localtaxes (we will add later)
  129. $localtaxes = array(0,0,0);
  130. $apply_tax = false;
  131. switch($localtax1_type) {
  132. case '2': // localtax on product or service
  133. $apply_tax = true;
  134. break;
  135. case '4': // localtax on product
  136. if ($type == 0) $apply_tax = true;
  137. break;
  138. case '6': // localtax on service
  139. if ($type == 1) $apply_tax = true;
  140. break;
  141. }
  142. if ($uselocaltax1_rate && $apply_tax) {
  143. $result[14] = price2num(($tot_sans_remise * (1 + ( $localtax1_rate / 100))) - $tot_sans_remise, 'MT');
  144. $localtaxes[0] += $result[14];
  145. $result[9] = price2num(($tot_avec_remise * (1 + ( $localtax1_rate / 100))) - $tot_avec_remise, 'MT');
  146. $localtaxes[1] += $result[9];
  147. $result[11] = price2num(($pu * (1 + ( $localtax1_rate / 100))) - $pu, 'MU');
  148. $localtaxes[2] += $result[11];
  149. }
  150. $apply_tax = false;
  151. switch($localtax2_type) {
  152. case '2': // localtax on product or service
  153. $apply_tax = true;
  154. break;
  155. case '4': // localtax on product
  156. if ($type == 0) $apply_tax = true;
  157. break;
  158. case '6': // localtax on service
  159. if ($type == 1) $apply_tax = true;
  160. break;
  161. }
  162. if ($uselocaltax2_rate && $apply_tax) {
  163. $result[15] = price2num(($tot_sans_remise * (1 + ( $localtax2_rate / 100))) - $tot_sans_remise, 'MT');
  164. $localtaxes[0] += $result[15];
  165. $result[10] = price2num(($tot_avec_remise * (1 + ( $localtax2_rate / 100))) - $tot_avec_remise, 'MT');
  166. $localtaxes[1] += $result[10];
  167. $result[12] = price2num(($pu * (1 + ( $localtax2_rate / 100))) - $pu, 'MU');
  168. $localtaxes[2] += $result[12];
  169. }
  170. //dol_syslog("price.lib::calcul_price_total $qty, $pu, $remise_percent_ligne, $txtva, $price_base_type $info_bits");
  171. if ($price_base_type == 'HT')
  172. {
  173. // We work to define prices using the price without tax
  174. $result[6] = price2num($tot_sans_remise, 'MT');
  175. $result[8] = price2num(($tot_sans_remise + $localtaxes[0]) * (1 + ( (($info_bits & 1)?0:$txtva) / 100)), 'MT'); // Selon TVA NPR ou non
  176. $result8bis= price2num(($tot_sans_remise + $localtaxes[0]) * (1 + ( $txtva / 100)), 'MT'); // Si TVA consideree normale (non NPR)
  177. $result[7] = price2num($result8bis - ($result[6] + $localtaxes[0]), 'MT');
  178. $result[0] = price2num($tot_avec_remise, 'MT');
  179. $result[2] = price2num(($tot_avec_remise + $localtaxes[1]) * (1 + ( (($info_bits & 1)?0:$txtva) / 100)), 'MT'); // Selon TVA NPR ou non
  180. $result2bis= price2num(($tot_avec_remise + $localtaxes[1]) * (1 + ( $txtva / 100)), 'MT'); // Si TVA consideree normale (non NPR)
  181. $result[1] = price2num($result2bis - ($result[0] + $localtaxes[1]), 'MT'); // Total VAT = TTC - (HT + localtax)
  182. $result[3] = price2num($pu, 'MU');
  183. $result[5] = price2num(($pu + $localtaxes[2]) * (1 + ((($info_bits & 1)?0:$txtva) / 100)), 'MU'); // Selon TVA NPR ou non
  184. $result5bis= price2num(($pu + $localtaxes[2]) * (1 + ($txtva / 100)), 'MU'); // Si TVA consideree normale (non NPR)
  185. $result[4] = price2num($result5bis - ($result[3] + $localtaxes[2]), 'MU');
  186. }
  187. else
  188. {
  189. // We work to define prices using the price with tax
  190. $result[8] = price2num($tot_sans_remise + $localtaxes[0], 'MT');
  191. $result[6] = price2num(($tot_sans_remise + $localtaxes[0]) / (1 + ((($info_bits & 1)?0:$txtva) / 100)), 'MT'); // Selon TVA NPR ou non
  192. $result6bis= price2num(($tot_sans_remise + $localtaxes[0]) / (1 + ($txtva / 100)), 'MT'); // Si TVA consideree normale (non NPR)
  193. $result[7] = price2num($result[8] - ($result6bis + $localtaxes[0]), 'MT');
  194. $result[2] = price2num($tot_avec_remise + $localtaxes[1], 'MT');
  195. $result[0] = price2num(($tot_avec_remise + $localtaxes[1]) / (1 + ((($info_bits & 1)?0:$txtva) / 100)), 'MT'); // Selon TVA NPR ou non
  196. $result0bis= price2num(($tot_avec_remise + $localtaxes[1]) / (1 + ($txtva / 100)), 'MT'); // Si TVA consideree normale (non NPR)
  197. $result[1] = price2num($result[2] - ($result0bis + $localtaxes[1]), 'MT'); // Total VAT = TTC - HT
  198. $result[5] = price2num(($pu + $localtaxes[2]), 'MU');
  199. $result[3] = price2num(($pu + $localtaxes[2]) / (1 + ((($info_bits & 1)?0:$txtva) / 100)), 'MU'); // Selon TVA NPR ou non
  200. $result3bis= price2num(($pu + $localtaxes[2]) / (1 + ($txtva / 100)), 'MU'); // Si TVA consideree normale (non NPR)
  201. $result[4] = price2num($result[5] - ($result3bis + $localtaxes[2]), 'MU');
  202. }
  203. // if there's some localtax without vat, we calculate localtaxes (we will add them at end)
  204. //If price is 'TTC' we need to have the totals without VAT for a correct calculation
  205. if ($price_base_type=='TTC')
  206. {
  207. $tot_sans_remise= price2num($tot_sans_remise / (1 + ($txtva / 100)),'MU');
  208. $tot_avec_remise= price2num($tot_avec_remise / (1 + ($txtva / 100)),'MU');
  209. $pu = price2num($pu / (1 + ($txtva / 100)),'MU');
  210. }
  211. $apply_tax = false;
  212. switch($localtax1_type) {
  213. case '1': // localtax on product or service
  214. $apply_tax = true;
  215. break;
  216. case '3': // localtax on product
  217. if ($type == 0) $apply_tax = true;
  218. break;
  219. case '5': // localtax on service
  220. if ($type == 1) $apply_tax = true;
  221. break;
  222. }
  223. if ($uselocaltax1_rate && $apply_tax) {
  224. $result[14] = price2num(($tot_sans_remise * (1 + ( $localtax1_rate / 100))) - $tot_sans_remise, 'MT'); // amount tax1 for total_ht_without_discount
  225. $result[8] += $result[14]; // total_ttc_without_discount + tax1
  226. $result[9] = price2num(($tot_avec_remise * (1 + ( $localtax1_rate / 100))) - $tot_avec_remise, 'MT'); // amount tax1 for total_ht
  227. $result[2] += $result[9]; // total_ttc + tax1
  228. $result[11] = price2num(($pu * (1 + ( $localtax1_rate / 100))) - $pu, 'MU'); // amount tax1 for pu_ht
  229. $result[5] += $result[11]; // pu_ht + tax1
  230. }
  231. $apply_tax = false;
  232. switch($localtax2_type) {
  233. case '1': // localtax on product or service
  234. $apply_tax = true;
  235. break;
  236. case '3': // localtax on product
  237. if ($type == 0) $apply_tax = true;
  238. break;
  239. case '5': // localtax on service
  240. if ($type == 1) $apply_tax = true;
  241. break;
  242. }
  243. if ($uselocaltax2_rate && $apply_tax) {
  244. $result[15] = price2num(($tot_sans_remise * (1 + ( $localtax2_rate / 100))) - $tot_sans_remise, 'MT'); // amount tax2 for total_ht_without_discount
  245. $result[8] += $result[15]; // total_ttc_without_discount + tax2
  246. $result[10] = price2num(($tot_avec_remise * (1 + ( $localtax2_rate / 100))) - $tot_avec_remise, 'MT'); // amount tax2 for total_ht
  247. $result[2] += $result[10]; // total_ttc + tax2
  248. $result[12] = price2num(($pu * (1 + ( $localtax2_rate / 100))) - $pu, 'MU'); // amount tax2 for pu_ht
  249. $result[5] += $result[12]; // pu_ht + tax2
  250. }
  251. // If rounding is not using base 10 (rare)
  252. if (! empty($conf->global->MAIN_ROUNDING_RULE_TOT))
  253. {
  254. if ($price_base_type == 'HT')
  255. {
  256. $result[0]=round($result[0]/$conf->global->MAIN_ROUNDING_RULE_TOT, 0)*$conf->global->MAIN_ROUNDING_RULE_TOT;
  257. $result[1]=round($result[1]/$conf->global->MAIN_ROUNDING_RULE_TOT, 0)*$conf->global->MAIN_ROUNDING_RULE_TOT;
  258. $result[2]=price2num($result[0]+$result[1], 'MT');
  259. $result[9]=round($result[9]/$conf->global->MAIN_ROUNDING_RULE_TOT, 0)*$conf->global->MAIN_ROUNDING_RULE_TOT;
  260. $result[10]=round($result[10]/$conf->global->MAIN_ROUNDING_RULE_TOT, 0)*$conf->global->MAIN_ROUNDING_RULE_TOT;
  261. }
  262. else
  263. {
  264. $result[1]=round($result[1]/$conf->global->MAIN_ROUNDING_RULE_TOT, 0)*$conf->global->MAIN_ROUNDING_RULE_TOT;
  265. $result[2]=round($result[2]/$conf->global->MAIN_ROUNDING_RULE_TOT, 0)*$conf->global->MAIN_ROUNDING_RULE_TOT;
  266. $result[0]=price2num($result[2]-$result[0], 'MT');
  267. $result[9]=round($result[9]/$conf->global->MAIN_ROUNDING_RULE_TOT, 0)*$conf->global->MAIN_ROUNDING_RULE_TOT;
  268. $result[10]=round($result[10]/$conf->global->MAIN_ROUNDING_RULE_TOT, 0)*$conf->global->MAIN_ROUNDING_RULE_TOT;
  269. }
  270. }
  271. dol_syslog('Price.lib::calcul_price_total MAIN_ROUNDING_RULE_TOT='.$conf->global->MAIN_ROUNDING_RULE_TOT.' pu='.$pu.' qty='.$qty.' price_base_type='.$price_base_type.' total_ht='.$result[0].'-total_vat='.$result[1].'-total_ttc='.$result[2]);
  272. return $result;
  273. }