Browse Source

fix optional goods and add repeat sel goods

stanley-king 7 years ago
parent
commit
aa70c46f61
3 changed files with 212 additions and 95 deletions
  1. 60 45
      helper/activity/optional_goods.php
  2. 142 48
      helper/activity_helper.php
  3. 10 2
      test/TestActivity.php

+ 60 - 45
helper/activity/optional_goods.php

@@ -20,27 +20,63 @@ class opgroup
     private $mStartTm;
     private $mEndTm;
     private $mGoods;
+    private $mRepeat;
 
-    public function __construct($price,$options,$start,$end)
+    public function __construct($price,$options,$start,$end,$repeat)
     {
         $this->mPrice = $price;
         $this->mOptions = $options;
         $this->mStartTm = $start;
         $this->mEndTm = $end;
+        $this->mRepeat = $repeat;
         $this->mGoods = [];
     }
-    public function match($gids)
+
+    public function match($goods_nums)
     {
         if($this->acting() == false) return false;
 
-        $set = algorithm::set_intersection($this->mGoods,$gids);
-        if(count($set) >= $this->mOptions) {
-            return ['gids' => $set,'price' => $this->mPrice,'options' => $this->mOptions];
+        $gids = array_keys($goods_nums);
+        sort($gids);
+        $match_gids = algorithm::set_intersection($this->mGoods,$gids);
+
+        $matched = false;
+        if($this->mRepeat == false)
+        {
+            if(count($match_gids) >= $this->mOptions) {
+                $matched = true;
+            }
+        }
+        else
+        {
+            $goods_num = $this->goods_num($match_gids, $goods_nums);
+            if ($goods_num >= $this->mOptions) {
+                $matched = true;
+            }
+        }
+
+        if($matched)
+        {
+            $matched_goods = [];
+            foreach ($match_gids as $gid) {
+                $matched_goods[$gid] = $goods_nums[$gid];
+            }
+            return ['goods_nums' => $matched_goods,'price' => $this->mPrice,'options' => $this->mOptions,'repeat' => $this->mRepeat];
         } else {
             return false;
         }
     }
 
+    private function goods_num($gids,$gid_nums)
+    {
+        $num = 0;
+        foreach ($gids as $gid)
+        {
+            $num += $gid_nums[$gid];
+        }
+        return $num;
+    }
+
     public function add_goods($gid)
     {
         $gid = intval($gid);
@@ -121,29 +157,31 @@ class optional_goods
         $match_goods = algorithm::set_intersection($this->mAllGoods,$input_goods);
         if(empty($match_goods)) return false;
 
-        $parts = $this->parse($gidnums);
-        if(empty($parts)) return false;
+        $match_goods = $this->sel_goods($match_goods,$gidnums);
 
         $result = [];
-        foreach ($parts as $part)
+        foreach ($this->mOpgroups as $opgroup)
         {
-            $part_goods = algorithm::set_intersection($this->mAllGoods,$part);
-            $groups = $this->domatch($part_goods);
-            foreach ($groups as $val) {
-                $result[] = $val;
+            if(empty($match_goods)) break;
+
+            $part = $opgroup->match($match_goods);
+            if($part != false)
+            {
+                $result[] = $part;
+                $goods_nums = $part['goods_nums'];
+                foreach ($goods_nums as $gid => $num) {
+                    unset($match_goods[$gid]);
+                }
             }
         }
 
         return $result;
     }
-    private function domatch($part_goods)
+    private function sel_goods($gids, $gidnums)
     {
         $result = [];
-        foreach ($this->mOpgroups as $opgroup) {
-            $part = $opgroup->match($part_goods);
-            if($part != false) {
-                $result[] = $part;
-            }
+        foreach ($gids as $gid) {
+            $result[$gid] = $gidnums[$gid];
         }
         return $result;
     }
@@ -160,30 +198,6 @@ class optional_goods
         return $result;
     }
 
-    private function parse($gid_nums)
-    {
-        $result = [];
-        while (true)
-        {
-            $item = [];
-            foreach ($gid_nums as $gid => &$num) {
-                if($num > 0) {
-                    $item[] = $gid;
-                    $num--;
-                }
-            }
-            if(!empty($item)) {
-                sort($item);
-                $result[] = $item;
-            }
-            else {
-                break;
-            }
-        }
-
-        return $result;
-    }
-
     private function init()
     {
         global $config;
@@ -254,8 +268,9 @@ class optional_goods
         {
             $price   = intval($params[0] * 100 + 0.5);
             $options = intval($params[1]);
-            $startm  = strtotime($params[2]);
-            $hours   = intval($params[3]);
+            $repeat  = intval($params[2]) == 1 ? true : false;
+            $startm  = strtotime($params[3]);
+            $hours   = intval($params[4]);
 
             if($price > 0 && $options > 1)
             {
@@ -263,7 +278,7 @@ class optional_goods
                 if($group == null)
                 {
                     if($startm > 0 && $hours > 0 && $startm + 3600 * $hours >  time()) {
-                        $group = new opgroup($price,$options,$startm,$startm + 3600 * $hours);
+                        $group = new opgroup($price,$options,$startm,$startm + 3600 * $hours,$repeat);
                     }
                 }
                 return $group;

+ 142 - 48
helper/activity_helper.php

@@ -237,6 +237,138 @@ class activity_helper
     }
 }
 
+class price_matcher
+{
+    private $mGoodsNums;
+    private $mOptions;
+    private $mPrice;
+    private $mRepeat;
+    private $mGoodsList;
+
+    private $mResult;
+
+    public function __construct($content,$goods_list)
+    {
+        $goods_nums = $content['goods_nums'];
+        $this->mOptions   = $content['options'];
+        $this->mPrice     = $content['price'];
+        $this->mRepeat    = $content['repeat'];
+
+        $this->mGoodsList = [];
+        $goodses = [];
+        foreach ($goods_nums as $gid => $num) {
+            $this->mGoodsList[$gid] = $goods_list[$gid];
+            $goodses[] = $goods_list[$gid];
+        }
+
+        usort($goodses,['optional_match','price_desc']);
+
+        $this->mGoodsNums = [];
+        foreach($goodses as $val) {
+            $goods_id = intval($val['goods_id']);
+            $this->mGoodsNums[$goods_id] = $goods_nums[$goods_id];
+        }
+        $this->mResult = false;
+    }
+
+    public function match(&$total_price_cent)
+    {
+        if($this->mRepeat) {
+            $match_goods = $this->repeat();
+        }
+        else {
+            $match_goods = $this->nonrepeat();
+        }
+        if(empty($match_goods)) {
+            $total_price_cent = 0;
+            return false;
+        }
+        else {
+            $total_count = $this->goods_count($match_goods);
+            $total_price_cent = $this->mPrice * ($total_count / $this->mOptions);
+            return $match_goods;
+        }
+    }
+
+    private function repeat()
+    {
+        $match_goods = [];
+
+        $goods_num = $this->mGoodsNums;
+        while ($this->goods_count($goods_num) >= $this->mOptions)
+        {
+            $left = $this->mOptions;
+
+            foreach($goods_num as $gid => &$num)
+            {
+                if($left > $num) {
+                    $sel = $num;
+                } else {
+                    $sel = $left;
+                }
+
+                if(array_key_exists($gid,$match_goods)) {
+                    $match_goods[$gid] += $sel;
+                } else {
+                    $match_goods[$gid] = $sel;
+                }
+
+                $left -= $sel;
+                $num -= $sel;
+                if($num == 0) {
+                    unset($goods_num[$gid]);
+                }
+
+                if($left == 0) {
+                    break;
+                }
+            }
+        }
+
+        return $match_goods;
+    }
+    private function goods_count($goods_nums)
+    {
+        $count = 0;
+        foreach ($goods_nums as $gid => $num) {
+            $count += $num;
+        }
+        return $count;
+    }
+
+    private function nonrepeat()
+    {
+        $match_goods = [];
+
+        $goods_num = $this->mGoodsNums;
+        while (count($goods_num) >= $this->mOptions)
+        {
+            $i = 0;
+            foreach($goods_num as $gid => &$num)
+            {
+                if($i < $this->mOptions)
+                {
+                    if(array_key_exists($gid,$match_goods)) {
+                        $match_goods[$gid] += 1;
+                    } else {
+                        $match_goods[$gid] = 1;
+                    }
+                    ++$i;
+                    --$num;
+                    if($num == 0) {
+                        unset($goods_num[$gid]);
+                    }
+                }
+                else {
+                    break;
+                }
+            }
+        }
+
+        return $match_goods;
+    }
+}
+
 class optional_match
 {
     private $mPregids;
@@ -247,7 +379,6 @@ class optional_match
         $this->mPregids = [];
         $this->mAllGoods = [];
 
-
         foreach ($cart_list as $cart)
         {
             $bl_id = intval($cart['bl_id']);
@@ -275,63 +406,26 @@ class optional_match
 
         foreach ($matchs as $item)
         {
-            $gids = $item['gids'];
-            $options = $item['options'];
-            $price = $item['price'];
-
-            $num = count($gids);
-            $times = intval($num / $options);
-            $count = $options * $times;
-
-            if($num % $options == 0) {
-                $match_goods = $gids;
-            } else {
-                $match_goods = $this->find_goods($gids,$count);
-            }
-            $total_price = $this->total_price_cent($match_goods);
-            $discount_cent += ($total_price - $price * $times);
-
-            foreach ($match_goods as $gid)
+            $matcher = new price_matcher($item,$this->mAllGoods);
+            $match_goods = $matcher->match($total_oprice_cent);
+            if(!empty($match_goods))
             {
-                if(array_key_exists($gid,$goods_nums)) {
-                    $goods_nums[$gid] += 1;
-                } else {
-                    $goods_nums[$gid] = 1;
+                $total_price = $this->total_price_cent($match_goods);
+                $discount_cent += $total_price - $total_oprice_cent;
+                foreach ($match_goods as $gid => $num) {
+                    $goods_nums[$gid] = $num;
                 }
             }
         }
 
         return ['discount' => $discount_cent / 100, 'goods_nums' => $goods_nums];
     }
-    private function find_goods($gids,$count)
-    {
-        $goods_list = [];
-        foreach ($gids as $gid) {
-            $goods_list[] = $this->mAllGoods[$gid];
-        }
-        usort($goods_list,['optional_match','price_desc']);
-
-        $match_goods = [];
-        $index = 0;
-        foreach ($goods_list as $goods)
-        {
-            if($index < $count) {
-                $gid = intval($goods['goods_id']);
-                $match_goods[] = $gid;
-                $index++;
-            } else {
-                break;
-            }
-        }
-
-        return $match_goods;
-    }
 
-    private function total_price_cent($gids)
+    private function total_price_cent($match_goods)
     {
         $total_price = 0;
-        foreach ($gids as $gid) {
-            $total_price += intval($this->mAllGoods[$gid]['goods_price'] * 100 + 0.5);
+        foreach ($match_goods as $gid => $num) {
+            $total_price += intval($this->mAllGoods[$gid]['goods_price'] * 100 * $num + 0.5);
         }
         return $total_price;
     }

File diff suppressed because it is too large
+ 10 - 2
test/TestActivity.php