PluginProbe ʕ •ᴥ•ʔ
VikAppointments Services Booking Calendar / 1.2.21
VikAppointments Services Booking Calendar v1.2.21
1.2.21 1.2.20 trunk 1.2.17 1.2.18 1.2.19
vikappointments / site / helpers / libraries / cart / discount.php
vikappointments / site / helpers / libraries / cart Last commit date
cart.php 4 days ago discount.php 4 days ago index.html 4 days ago item.php 4 days ago option.php 4 days ago utils.php 4 days ago
discount.php
228 lines
1 <?php
2 /**
3 * @package VikAppointments
4 * @subpackage core
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2021 E4J s.r.l. All Rights Reserved.
7 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 * @link https://vikwp.com
9 */
10
11 // No direct access
12 defined('ABSPATH') or die('No script kiddies please!');
13
14 /**
15 * Encapsulates the details of a generic discount.
16 *
17 * @since 1.7
18 */
19 class VAPCartDiscount extends JObject implements JsonSerializable
20 {
21 /**
22 * The ID of the deal.
23 *
24 * @var mixed
25 */
26 private $id;
27
28 /**
29 * The amount of the discount.
30 *
31 * @var float
32 */
33 private $amount;
34
35 /**
36 * True whether the discount should be calculated in percentage.
37 *
38 * @var boolean
39 */
40 private $percent;
41
42 /**
43 * Class constructor.
44 *
45 * @param mixed $id The ID of the deal.
46 * @param float $amount The amount of the deal.
47 * @param integer $percent True if percent, false when fixed.
48 */
49 public function __construct($id, $amount, $percent = false)
50 {
51 $this->id = $id;
52 $this->amount = abs((float) $amount);
53 $this->percent = (bool) $percent;
54 }
55
56 /**
57 * Returns the discount identifier.
58 *
59 * @return mixed
60 */
61 public function getID()
62 {
63 return $this->id;
64 }
65
66 /**
67 * Returns the discount amount.
68 *
69 * @return float
70 */
71 public function getAmount()
72 {
73 return $this->amount;
74 }
75
76 /**
77 * Check if the amount type of the deal is percentage.
78 *
79 * @return boolean
80 */
81 public function isPercent()
82 {
83 return $this->percent;
84 }
85
86 /**
87 * Check if the amount type of the deal is total.
88 *
89 * @return boolean
90 */
91 public function isTotal()
92 {
93 return !$this->percent;
94 }
95
96 /**
97 * Applies a discount to the specified amount.
98 *
99 * @param float $amount The amount to discount.
100 * @param float $base The initial price of the item.
101 * @param mixed $item The item/option to discount.
102 *
103 * @return float The resulting amount.
104 */
105 public function apply($amount, $base, $item)
106 {
107 $dispatcher = VAPFactory::getEventDispatcher();
108
109 // get internal count
110 $count = (int) $this->get('count', 0);
111 // immediately increase internal count by one because external plugins
112 // might prevent the application of the discount
113 $this->set('count', ++$count);
114
115 /**
116 * Trigger event to let external plugins prevent the application of the
117 * discount at runtime. Useful in example to ignore the discount for
118 * certain items and options.
119 *
120 * @param self $discount The current discount instance.
121 * @param float $amount The current amount to discount.
122 * @param mixed $item The item/option to discount.
123 *
124 * @return void
125 *
126 * @since 1.7
127 */
128 if ($dispatcher->not('onBeforeApplyCartDiscount', array($this, $amount, $item)))
129 {
130 // do not apply the discount
131 return $amount;
132 }
133
134 // get total discount already applied
135 $applied = (float) $this->get('disctot', 0);
136
137 if ($this->isPercent())
138 {
139 // calculate percentage discount
140 $disc_val = $amount * $this->amount / 100.0;
141 }
142 else
143 {
144 // get total number of itema
145 $length = (int) $this->get('length', 0);
146
147 if ($count < $length)
148 {
149 // Fixed discount, apply proportionally according to
150 // the total cost of the items. Since the discounts
151 // might be applied on cascade, we need to calculate
152 // the proportion on the base cost of the item.
153 $percentage = $base * 100 / (float) $this->get('total', 0);
154 $disc_val = $this->amount * $percentage / 100;
155 }
156 else
157 {
158 // We are fetching the last element of the list, instead of calculating the
159 // proportional discount, we should subtract the total discount from the coupon
160 // value, in order to avoid rounding issues. Let's take as example a coupon of
161 // EUR 10 applied on 3 items. The final result would be 3.33 + 3.33 + 3.33,
162 // which won't match the initial discount value of the coupon. With this
163 // alternative way, the result would be: 10 - 3.33 - 3.33 = 3.34.
164 $disc_val = $this->amount - $applied;
165 }
166 }
167
168 // always round discount to 2 decimals
169 $disc_val = round($disc_val, 2);
170
171 /**
172 * Trigger event to let external plugins alter the discount to apply at runtime.
173 *
174 * @param float &$value The calculated discount value.
175 * @param self $discount The current discount instance.
176 * @param float $amount The current amount to discount.
177 * @param mixed $item The item/option to discount.
178 *
179 * @return void
180 *
181 * @since 1.7
182 */
183 $dispatcher->trigger('onAfterApplyCartDiscount', array(&$disc_val, $this, $amount, $item));
184
185 // discount value cannot be lower than 0 and cannot be higher than the total amount to discount
186 $disc_val = max(array($disc_val, 0));
187 $disc_val = min(array($disc_val, $amount));
188
189 // subtract discount from amount
190 $amount -= $disc_val;
191
192 // update internal total discount
193 $this->set('disctot', $applied + $disc_val);
194
195 return $amount;
196 }
197
198 /**
199 * Magic toString method to debug the discount contents.
200 *
201 * @return string The debug string of this object.
202 */
203 public function __toString()
204 {
205 return '<pre>' . print_r($this, true) . '</pre>';
206 }
207
208 /**
209 * Creates a standard object, containing all the supported properties,
210 * to be used when this class is passed to "json_encode()".
211 *
212 * @return object
213 *
214 * @since 1.7
215 *
216 * @see JsonSerializable
217 */
218 #[ReturnTypeWillChange]
219 public function jsonSerialize()
220 {
221 return array(
222 'id' => $this->id,
223 'amount' => $this->amount,
224 'percent' => $this->percent,
225 );
226 }
227 }
228