From 081854c35267d9d0ee51ba5858f32e26236077cf Mon Sep 17 00:00:00 2001 From: Mo Farouk <122031508+fmido88@users.noreply.github.com> Date: Sat, 10 Feb 2024 03:24:22 +0200 Subject: [PATCH] Fix discount calculation logic --- classes/util/instance.php | 21 +++++++++---- classes/util/offers.php | 63 +++++++++++++++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 9 deletions(-) diff --git a/classes/util/instance.php b/classes/util/instance.php index 1f9d164a..26c1d2f7 100644 --- a/classes/util/instance.php +++ b/classes/util/instance.php @@ -252,7 +252,7 @@ private function get_offers_discount() { break; case self::B_SEQ; default: - $discount = $this->calculate_sequential_discount($offers->get_available_discounts()); + $discount = $this->calculate_sequential_discount($offers->get_available_discounts(), true); } return min(1, $discount / 100); } @@ -326,7 +326,9 @@ private function calculate_cost_after_discount() { $discount = 0; if ($this->behavior === self::B_SUM) { - $discount = array_sum($discounts); + foreach ($discounts as $d) { + $discount += $d; + } } else if ($this->behavior === self::B_MAX) { $discount = max($discounts); } else { @@ -339,16 +341,23 @@ private function calculate_cost_after_discount() { /** * sequentially calculate discount * @param array $discounts + * @param bool $percentage * @return float */ - private function calculate_sequential_discount($discounts) { - $discount = 0; + private function calculate_sequential_discount($discounts, $percentage = false) { \core_collator::asort($discounts, \core_collator::SORT_NUMERIC); $discounts = array_reverse($discounts); + + $discount = 0; foreach ($discounts as $d) { - $discount = $discount + $d * (1 - $discount); + $d = $percentage ? $d / 100 : $d; + $discount = 1 - (1 - $discount) * (1 - $d); } - return min(1, $discount); + $discount = min(1, $discount); + if ($percentage) { + return $discount * 100; + } + return $discount; } /** * Get the cost of the enrol instance after discount. diff --git a/classes/util/offers.php b/classes/util/offers.php index d98bc90a..27e0cd44 100644 --- a/classes/util/offers.php +++ b/classes/util/offers.php @@ -25,6 +25,7 @@ */ namespace enrol_wallet\util; +use stdClass; defined('MOODLE_INTERNAL') || die(); global $CFG; @@ -143,7 +144,7 @@ public function __construct($instance, $userid = 0) { $this->userid = $USER->id; } if (!empty($instance->customtext3)) { - $this->offers = json_decode($instance->customtext3); + $this->offers = (array)json_decode($instance->customtext3); } else { $this->offers = []; } @@ -227,7 +228,7 @@ public function get_detailed_offers() { 'op' => get_string('offers_pfop_'.$offer->op, 'enrol_wallet'), 'discount' => $offer->discount, 'field' => $fieldname, - 'value' => $offer->v, + 'value' => $offer->value, ]; $descriptions[$key] = get_string('offers_pf_desc', 'enrol_wallet', $a); break; @@ -301,7 +302,11 @@ public function get_sum_discounts() { return 0; } } - return min(array_sum($this->discounts), 1); + $sum = 0; + foreach ($this->discounts as $d) { + $sum += $d; + } + return min($sum, 100); } /** * Return array with available valid discounts for the passed user. @@ -964,6 +969,58 @@ private function get_stored_offers() { return $return; } + + /** + * Get all courses with offers and add it to course object $course->offers as array keyed with + * instance id and each contain array with offers details. + * @param int $categoryid + * @return array + */ + public static function get_courses_with_offers($categoryid = 0) { + global $DB; + $sql = "SELECT e.id as instanceid, c.*, e.customtext3 + From {course} c + JOIN {enrol} e ON e.courseid = c.id + WHERE e.status = :stat + AND (e.enrolstartdate < :time1 OR e.enrolstartdate = 0) + AND (e.enrolenddate > :time2 OR e.enrolenddate = 0) + AND e.enrol = :wallet"; + $params = [ + 'stat' => ENROL_INSTANCE_ENABLED, + 'time1' => time(), + 'time2' => time(), + 'wallet' => 'wallet', + ]; + if (!empty($categoryid)) { + $category = core_course_category::get($categoryid); + $catids = $category->get_all_children_ids(); + $catids[] = $categoryid; + list($in, $inparams) = $DB->get_in_or_equal($catids, SQL_PARAMS_NAMED); + $sql .= " AND c.category $in"; + $params = $params + $inparams; + } + $courses = $DB->get_records_sql($sql, $params); + $final = []; + foreach ($courses as $instanceid => $course) { + $instance = new stdClass; + $instance->id = $instanceid; + $instance->courseid = $course->id; + $instance->customtext3 = $course->customtext3; + + $class = new self($instance); + if (empty($class->get_raw_offers())) { + continue; + } + if (!isset($final[$course->id])) { + $final[$course->id] = $course; + $final[$course->id]->offers = []; + unset($final[$course->id]->instanceid); + unset($final[$course->id]->customtext3); + } + $final[$course->id]->offers[$instanceid] = $class; + } + return $final; + } } /**