PageRenderTime 54ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/classes/Discount.php

https://github.com/pal/prestashop
PHP | 344 lines | 240 code | 47 blank | 57 comment | 27 complexity | 9314c708751ca2fd30f5b2a3b996fd0b MD5 | raw file
  1. <?php
  2. /**
  3. * Discount class, Discount.php
  4. * Discounts management
  5. * @category classes
  6. *
  7. * @author PrestaShop <support@prestashop.com>
  8. * @copyright PrestaShop
  9. * @license http://www.opensource.org/licenses/osl-3.0.php Open-source licence 3.0
  10. * @version 1.2
  11. *
  12. */
  13. class Discount extends ObjectModel
  14. {
  15. public $id;
  16. /** @var integer Customer id only if discount is reserved */
  17. public $id_customer;
  18. /** @var integer Discount type ID */
  19. public $id_discount_type;
  20. /** @var string Name (the one which must be entered) */
  21. public $name;
  22. /** @var string A short description for the discount */
  23. public $description;
  24. /** @var string Value in percent as well as in euros */
  25. public $value;
  26. /** @var integer Totale quantity available */
  27. public $quantity;
  28. /** @var integer User quantity available */
  29. public $quantity_per_user;
  30. /** @var boolean Indicate if discount is cumulable with others */
  31. public $cumulable;
  32. /** @var integer Indicate if discount is cumulable with already bargained products */
  33. public $cumulable_reduction;
  34. /** @var integer Date from wich discount become active */
  35. public $date_from;
  36. /** @var integer Date from wich discount is no more active */
  37. public $date_to;
  38. /** @var integer Minimum cart total amount required to use the discount */
  39. public $minimal;
  40. /** @var boolean Status */
  41. public $active = true;
  42. protected $fieldsRequired = array('id_discount_type', 'name', 'value', 'quantity', 'quantity_per_user', 'date_from', 'date_to');
  43. protected $fieldsSize = array('name' => '32', 'date_from' => '32', 'date_to' => '32');
  44. protected $fieldsValidate = array('id_customer' => 'isUnsignedId', 'id_discount_type' => 'isUnsignedId',
  45. 'name' => 'isDiscountName', 'value' => 'isPrice', 'quantity' => 'isUnsignedInt', 'quantity_per_user' => 'isUnsignedInt',
  46. 'cumulable' => 'isBool', 'cumulable_reduction' => 'isBool', 'date_from' => 'isDate',
  47. 'date_to' => 'isDate', 'minimal' => 'isFloat', 'active' => 'isBool');
  48. protected $fieldsRequiredLang = array('description');
  49. protected $fieldsSizeLang = array('description' => 128);
  50. protected $fieldsValidateLang = array('description' => 'isVoucherDescription');
  51. protected $table = 'discount';
  52. protected $identifier = 'id_discount';
  53. public function getFields()
  54. {
  55. parent::validateFields();
  56. $fields['id_customer'] = intval($this->id_customer);
  57. $fields['id_discount_type'] = intval($this->id_discount_type);
  58. $fields['name'] = pSQL($this->name);
  59. $fields['value'] = floatval($this->value);
  60. $fields['quantity'] = intval($this->quantity);
  61. $fields['quantity_per_user'] = intval($this->quantity_per_user);
  62. $fields['cumulable'] = intval($this->cumulable);
  63. $fields['cumulable_reduction'] = intval($this->cumulable_reduction);
  64. $fields['date_from'] = pSQL($this->date_from);
  65. $fields['date_to'] = pSQL($this->date_to);
  66. $fields['minimal'] = floatval($this->minimal);
  67. $fields['active'] = intval($this->active);
  68. return $fields;
  69. }
  70. public function add($autodate = true, $nullValues = false, $categories = null)
  71. {
  72. if (parent::add($autodate, $nullValues))
  73. $ret = true;
  74. $this->updateCategories($categories);
  75. return $ret;
  76. }
  77. /* Categories initialization is different between add() and update() because the addition will set all categories if none are selected (compatibility with old modules) and update won't update categories if none are selected */
  78. public function update($autodate = true, $nullValues = false, $categories = false)
  79. {
  80. if (parent::update($autodate, $nullValues))
  81. $ret = true;
  82. $this->updateCategories($categories);
  83. return $ret;
  84. }
  85. public function delete()
  86. {
  87. if (!parent::delete())
  88. return false;
  89. return (Db::getInstance()->Execute('DELETE FROM '._DB_PREFIX_.'cart_discount WHERE id_discount = '.intval($this->id))
  90. AND Db::getInstance()->Execute('DELETE FROM '._DB_PREFIX_.'discount_category WHERE id_discount = '.intval($this->id)));
  91. }
  92. public function getTranslationsFieldsChild()
  93. {
  94. if (!parent::validateFieldsLang())
  95. return false;
  96. return parent::getTranslationsFields(array('description'));
  97. }
  98. /**
  99. * Return discount types list
  100. *
  101. * @return array Discount types
  102. */
  103. static public function getDiscountTypes($id_lang)
  104. {
  105. return Db::getInstance()->ExecuteS('
  106. SELECT *
  107. FROM '._DB_PREFIX_.'discount_type dt
  108. LEFT JOIN `'._DB_PREFIX_.'discount_type_lang` dtl ON (dt.`id_discount_type` = dtl.`id_discount_type` AND dtl.`id_lang` = '.intval($id_lang).')');
  109. }
  110. /**
  111. * Get discount ID from name
  112. *
  113. * @param string $discountName Discount name
  114. * @return integer Discount ID
  115. */
  116. public static function getIdByName($discountName)
  117. {
  118. if (!Validate::isDiscountName($discountName))
  119. die(Tools::displayError());
  120. $result = Db::getInstance()->getRow('
  121. SELECT `id_discount`
  122. FROM `'._DB_PREFIX_.'discount`
  123. WHERE `name` = \''.pSQL($discountName).'\'');
  124. return isset($result['id_discount']) ? $result['id_discount'] : false;
  125. }
  126. /**
  127. * Return customer discounts
  128. *
  129. * @param integer $id_lang Language ID
  130. * @param boolean $id_customer Customer ID
  131. * @return array Discounts
  132. */
  133. static public function getCustomerDiscounts($id_lang, $id_customer, $active = false, $includeGenericOnes = true, $stock = false)
  134. {
  135. global $cart;
  136. $res = Db::getInstance()->ExecuteS('
  137. SELECT d.*, dtl.`name` AS `type`, dl.`description`
  138. FROM `'._DB_PREFIX_.'discount` d
  139. LEFT JOIN `'._DB_PREFIX_.'discount_lang` dl ON (d.`id_discount` = dl.`id_discount` AND dl.`id_lang` = '.intval($id_lang).')
  140. LEFT JOIN `'._DB_PREFIX_.'discount_type` dt ON dt.`id_discount_type` = d.`id_discount_type`
  141. LEFT JOIN `'._DB_PREFIX_.'discount_type_lang` dtl ON (dt.`id_discount_type` = dtl.`id_discount_type` AND dtl.`id_lang` = '.intval($id_lang).')
  142. WHERE (`id_customer` = '.intval($id_customer).($includeGenericOnes ? ' OR `id_customer` = 0' : '').')
  143. '.($active ? ' AND d.`active` = 1' : '').'
  144. '.($stock ? ' AND d.`quantity` != 0' : ''));
  145. foreach ($res as &$discount)
  146. if ($discount['quantity_per_user'])
  147. {
  148. $quantity_used = Order::getDiscountsCustomer(intval($id_customer), intval($discount['id_discount']));
  149. if (isset($cart) AND isset($cart->id))
  150. $quantity_used += $cart->getDiscountsCustomer(intval($discount['id_discount']));
  151. $discount['quantity_for_user'] = $discount['quantity_per_user'] - $quantity_used;
  152. }
  153. else
  154. $discount['quantity_for_user'] = 0;
  155. return $res;
  156. }
  157. /**
  158. * Return discount value
  159. *
  160. * @param integer $nb_discounts Number of discount currently in cart
  161. * @param boolean $order_total_products Total cart products amount
  162. * @return mixed Return a float value or '!' if reduction is 'Shipping free'
  163. */
  164. public function getValue($nb_discounts = 0, $order_total_products = 0, $shipping_fees = 0, $idCart = false, $useTax = true)
  165. {
  166. $totalAmount = 0;
  167. if ((!$this->cumulable AND intval($nb_discounts) > 1) OR !$this->active OR !$this->quantity)
  168. return 0;
  169. $date_start = strtotime($this->date_from);
  170. $date_end = strtotime($this->date_to);
  171. if (time() < $date_start OR time() > $date_end) return 0;
  172. $cart = new Cart(intval($idCart));
  173. $products = $cart->getProducts();
  174. $categories = Discount::getCategories(intval($this->id));
  175. $in_category = false;
  176. foreach ($products AS $product)
  177. if (count($categories) AND Product::idIsOnCategoryId($product['id_product'], $categories))
  178. $totalAmount += $useTax ? $product['total_wt'] : $product['total'];
  179. $totalAmount += floatval($shipping_fees);
  180. if ($this->minimal > 0 AND $totalAmount < $this->minimal)
  181. return 0;
  182. switch ($this->id_discount_type)
  183. {
  184. case 1:
  185. // % on order
  186. $amount = 0;
  187. $percentage = $this->value / 100;
  188. foreach ($products AS $product)
  189. if (Product::idIsOnCategoryId($product['id_product'], $categories))
  190. $amount += ($useTax ? $product['total_wt'] : $product['total']) * $percentage;
  191. return $amount;
  192. case 2:
  193. // amount
  194. foreach ($products AS $product)
  195. if (Product::idIsOnCategoryId($product['id_product'], $categories))
  196. {
  197. $in_category = true;
  198. break;
  199. }
  200. return (($in_category) ? Tools::convertPrice($this->value) : 0);
  201. case 3:
  202. // Shipping is free
  203. return '!';
  204. }
  205. return 0;
  206. }
  207. static public function isParentCategoryProductDiscount($id_category_product, $id_category_discount)
  208. {
  209. $category = new Category(intval($id_category_product));
  210. $parentCategories = $category->getParentsCategories();
  211. foreach($parentCategories AS $parentCategory)
  212. if($id_category_discount == $parentCategory['id_category'])
  213. return true;
  214. return false;
  215. }
  216. static public function getCategories($id_discount)
  217. {
  218. return Db::getInstance()->ExecuteS('
  219. SELECT `id_category`
  220. FROM `'._DB_PREFIX_.'discount_category`
  221. WHERE `id_discount` = '.intval($id_discount));
  222. }
  223. public function updateCategories($categories)
  224. {
  225. /* false value will avoid category update and null value will force all category to be selected */
  226. if ($categories === false)
  227. return ;
  228. if ($categories === null)
  229. {
  230. // Compatibility for modules which create discount without setting categories (ex. fidelity, sponsorship)
  231. $result = Db::getInstance()->ExecuteS('SELECT id_category FROM '._DB_PREFIX_.'category');
  232. $categories = array();
  233. foreach ($result as $row)
  234. $categories[] = $row['id_category'];
  235. }
  236. elseif (!is_array($categories) OR !sizeof($categories))
  237. return false;
  238. Db::getInstance()->Execute('DELETE FROM `'._DB_PREFIX_.'discount_category` WHERE `id_discount`='.intval($this->id));
  239. foreach($categories AS $category)
  240. {
  241. Db::getInstance()->Execute('
  242. SELECT `id_discount`
  243. FROM `'._DB_PREFIX_.'discount_category`
  244. WHERE `id_discount`='.intval($this->id).' AND `id_category`='.intval($category));
  245. if (Db::getInstance()->NumRows() == 0)
  246. Db::getInstance()->Execute('INSERT INTO `'._DB_PREFIX_.'discount_category` (`id_discount`, `id_category`) VALUES('.intval($this->id).','.intval($category).')');
  247. }
  248. }
  249. static public function discountExists($discountName, $id_discount = 0)
  250. {
  251. return Db::getInstance()->getRow('SELECT `id_discount` FROM '._DB_PREFIX_.'discount WHERE `name` LIKE \''.pSQL($discountName).'\' AND `id_discount` != '.intval($id_discount));
  252. }
  253. static public function createOrderDiscount($order, $productList, $qtyList, $name, $shipping_cost = false, $id_category = 0, $subcategory = 0)
  254. {
  255. $languages = Language::getLanguages($order);
  256. $products = $order->getProducts(false, $productList, $qtyList);
  257. $total = $order->getTotalProductsWithTaxes($products);
  258. if ($shipping_cost)
  259. $total += $order->total_shipping;
  260. // create discount
  261. $voucher = new Discount();
  262. $voucher->id_discount_type = 2;
  263. foreach ($languages as $language)
  264. $voucher->description[$language['id_lang']] = strval($name).intval($order->id);
  265. $voucher->value = floatval($total);
  266. $voucher->name = 'V0C'.intval($order->id_customer).'O'.intval($order->id);
  267. $voucher->id_customer = intval($order->id_customer);
  268. $voucher->quantity = 1;
  269. $voucher->quantity_per_user = 1;
  270. $voucher->cumulable = 1;
  271. $voucher->cumulable_reduction = 1;
  272. $voucher->minimal = floatval($voucher->value);
  273. $voucher->active = 1;
  274. $now = time();
  275. $voucher->date_from = date('Y-m-d H:i:s', $now);
  276. $voucher->date_to = date('Y-m-d H:i:s', $now + (3600 * 24 * 365.25)); /* 1 year */
  277. if (!$voucher->validateFieldsLang(false) OR !$voucher->add())
  278. return false;
  279. // set correct name
  280. $voucher->name = 'V'.intval($voucher->id).'C'.intval($order->id_customer).'O'.$order->id;
  281. if (!$voucher->update())
  282. return false;
  283. return $voucher;
  284. }
  285. static public function display($discountValue, $discountType, $currency=false)
  286. {
  287. if (floatval($discountValue) AND intval($discountType))
  288. {
  289. if ($discountType == 1)
  290. return $discountValue.chr(37); // ASCII #37 --> % (percent)
  291. elseif ($discountType == 2)
  292. return Tools::displayPrice($discountValue, $currency);
  293. }
  294. return ''; // return a string because it's a display method
  295. }
  296. }
  297. ?>