mTimesConfig = []; $this->mInterceptConfig = []; $this->mGrossRatios = []; $this->mDetailRatios = []; $this->mMixedPrices = []; } public function load() { $this->load_retry(); $this->load_intercept(); } private function load_retry() { $isDay = functional::isDay(); $mch_configs = function ($isDay) { $result = []; $i = 0; while (true) { $start = $i * 100; $items = Model()->table('merchant')->where(['mchid' => ['gt', 0], 'merchant_state' => 1])->field('mchid,retry_times_cfg')->order('mchid asc')->limit("{$start},100")->select(); if(empty($items)) { break; } $i++; foreach ($items as $item) { $mchid = intval($item['mchid']); if($mchid <= 0) continue; $retry_times_cfg = unserialize($item['retry_times_cfg']); if(empty($retry_times_cfg)) continue; $qualities = &$retry_times_cfg['qualities']; foreach ($qualities as $quality => $cfg) { if ($isDay) { $qualities[$quality]['secs'] = $cfg['day_secs']; } else { $qualities[$quality]['secs'] = $cfg['night_secs']; } } $result[$mchid] = $retry_times_cfg; } } return $result; }; $this->mTimesConfig = $mch_configs($isDay); } private function load_intercept() { $mch_configs = function () { $result = []; $i = 0; while (true) { $start = $i * 100; $items = Model()->table('merchant')->where(['mchid' => ['gt', 0], 'merchant_state' => 1])->field('mchid,intercept_cfg')->order('mchid asc')->limit("{$start},100")->select(); if(empty($items)) { break; } $i++; foreach ($items as $item) { $mchid = intval($item['mchid']); if($mchid <= 0) continue; $cfg = unserialize($item['intercept_cfg']); if(empty($cfg)) continue; $result[$mchid] = $cfg; } } return $result; }; $this->mInterceptConfig = $mch_configs(); } public function update($gross_ratios, $detail_ratios) { if (!empty($gross_ratios)) { $this->mGrossRatios = $gross_ratios; } if (!empty($detail_ratios)) { $this->mDetailRatios = $detail_ratios; } $this->mMchQTS = []; foreach ($detail_ratios as $key=>$val) { [$mchid,$quality,$card_type,$spec] = explode('-',$key); $mchid = intval($mchid); $quality = intval($quality); $card_type = intval($card_type); $spec = intval($spec); $this->mMchQTS[$mchid][] = [$quality,$card_type,$spec]; } $this->ratio_match(10211,14,1,4,30,[1,2]); } public function setMixedPrice($mchid, $mixed_quality, $card_type, $spec, $prices) { $key = "{$card_type}-{$spec}"; $this->mMixedPrices[$mchid][$mixed_quality][$key] = $prices; } //获取售价和进价 private function getPrice($mchid, $mixed_quality, $card_type, $spec) { $key = "{$card_type}-{$spec}"; if (array_key_exists($mchid, $this->mMixedPrices)) { $prices = $this->mMixedPrices[$mchid]; if (array_key_exists($mixed_quality, $prices)) { $qprices = $prices[$mixed_quality]; if (array_key_exists($key, $qprices)) { $price = $qprices[$key]; return $price; } } } return false; } public function total($mchid,$qualities) { if (array_key_exists($mchid, $this->mTimesConfig)) { $items = $this->mTimesConfig[$mchid]['qualities']; $times = 0; $secs = 0; foreach ($items as $quality => $val) { if (!in_array($quality,$qualities,true)) { continue; } $times += $val['times'] ?? 1; $secs += $val['secs'] ?? 180; } return [true, $times, $secs]; } else { return [false, 0, 0]; } } public function times($mchid, $quality) { if (array_key_exists($mchid, $this->mTimesConfig)) { $items = $this->mTimesConfig[$mchid]['qualities'] ?? []; if (array_key_exists($quality, $items)) { return $items[$quality]['times']; } } return false; } public function seconds($mchid, $quality) { if (array_key_exists($mchid, $this->mTimesConfig)) { $items = $this->mTimesConfig[$mchid]['qualities'] ?? []; if (array_key_exists($quality, $items)) { return $items[$quality]['secs']; } } return false; } public function exist($mchid) { if (array_key_exists($mchid, $this->mTimesConfig)) { return true; } else { return false; } } private function lower_ratio($mchid) { $lower_ratio = $this->mTimesConfig[$mchid]['lower_ratio'] ?? []; if (empty($lower_ratio)) { return [0.0, 3600]; } else { return [$lower_ratio['ratio'], $lower_ratio['period']]; } } private function profit_ratio($mchid) { $profit_ratio = $this->mTimesConfig[$mchid]['profit_ratio'] ?? 0.0; return $profit_ratio; } private function gross_ratio($mchid, $period) { $mratios = $this->mGrossRatios; if (array_key_exists($mchid, $mratios)) { $mratios = $mratios[$mchid]; if (array_key_exists($period, $mratios)) { return $mratios[$period]; } } return [0, 0, 1.0]; } private function detail_ratio($mchid, $quality, $card_type, $spec, $period) { $key = "{$mchid}-{$quality}-{$card_type}-{$spec}"; if(array_key_exists($key,$this->mDetailRatios)) { $ratios = $this->mDetailRatios[$key]; if(array_key_exists($period,$ratios)) { return $ratios[$period]; } } return [0, 0, 1.0]; } private function detail_ratios($mchid,$qualities,$card_type, $spec,$period) { $result = []; foreach ($qualities as $quality) { $ret = $this->detail_ratio($mchid,$quality,$card_type,$spec,$period); $result[$quality] = $ret; } return $result; } private function getMerchantSuppleType($mchid) { return 'all'; } //return true 表示不可以补充。 public function ratio_match($mchid, $org_quality, $cur_quality, $card_type, $spec, $qualities) { if(count($qualities) <= 1) { return true; } $header = __METHOD__ . " mchid={$mchid} card_type={$card_type} spec={$spec}"; [$ratio, $period] = $this->lower_ratio($mchid); [$_succ, $_fail, $gross_ratio] = $this->gross_ratio($mchid, $period); Log::record("{$header} gross_ratio = {$gross_ratio},lower_ratio={$ratio}",Log::DEBUG); // if($gross_ratio >= $ratio) return true; if (!PolicyUtil::mixed_quality($org_quality)) { return false; } $type = $this->getMerchantSuppleType($mchid); if($type === 'all') { return $this->all_checker($mchid, $org_quality, $spec, $qualities, $period, $header, $ratio); } elseif($type === 'qt') { } else { return $this->qts_checker($mchid, $org_quality,$cur_quality, $card_type, $spec, $qualities,$period,$header,$ratio); } } private function all_checker($mchid, $org_quality, $spec, $qualities, $period, $header, $low_ratio) { $qtsex = $this->mMchQTS[$mchid]; $profit_judger = function ($mchid, $qtsex, $org_quality, $period, $profit_ratio, $header) { $profit = 0; $amount = 0; foreach ($qtsex as $qts) { [$quality,$card_type,$spec] = $qts; if($quality == $org_quality) { continue; } $prices = $this->getPrice($mchid, $org_quality, $card_type, $spec); $out_price = $prices[$org_quality]; $in_price = $prices[$quality] ?? false; if ($in_price === false) continue; [$succ, $fail, $ratio] = $this->detail_ratio($mchid, $quality,$card_type, $spec, $period); $profit += $succ * ($out_price - $in_price); $amount += $succ * $spec; } $cur_pratio = round(($profit + 0.00001) / ($amount + 0.00001),4); $profit_ratio = round($profit_ratio,4); $profit_ratio = round($profit_ratio,4); Log::record("{$header} cur_pratio = {$cur_pratio},profit_ratio={$profit_ratio}",Log::DEBUG); return $cur_pratio > $profit_ratio; }; $spec_max = function ($mchid,$qtsex, $org_quality, $qualities, $low_ratio,$period) { $specs = []; $spec_qt = []; foreach ($qtsex as $qts) { [$quality, $card_type, $spec] = $qts; $specs[] = $spec; $spec_qt[$spec][] = [$quality,$card_type]; } $specs = array_unique($specs); sort($specs); $ratio_calc = function ($mchid, $specs, $spec_qt, $max_spec, $org_quality, $qualities, $period) { $all_succ = 0; $all_fail = 0; foreach ($specs as $spec) { $qts = $spec_qt[$spec]; if($max_spec >= $spec) { $fHigtRatio = true; } else { $fHigtRatio = false; } $card_types = []; foreach ($qts as $qt) { [$quality,$card_type] = $qt; if($quality === $org_quality) { continue; } $card_types[] = $card_type; } $detail_ratios = $this->detail_ratios($mchid, $qualities,$card_type, $spec, $period); if($fHigtRatio) { $all = 0; $ratios = []; foreach ($detail_ratios as $quality => $sfr) { [$succ,$fail,$ratio] = $sfr; $ratios[] = $ratio; $all += $succ; $all += $fail; } $max_ratios = max($ratios); $succs = $max_ratios * $all; $fails = $all - $succs; $all_succ += $succs; $all_fail += $fails; } else { foreach ($detail_ratios as $quality => $sfr) { [$succ,$fail,$ratio] = $sfr; $all_succ += $succ; $all_fail += $fail; } } } $ratio = $all_succ / ($all_succ + $all_fail + 0.00001); return round($ratio,4); }; for ($i = 0; $i < count($specs); $i++) { $max_spec = $specs[$i]; $ratio = $ratio_calc($mchid, $specs, $spec_qt, $max_spec, $org_quality, $qualities, $period); if($ratio >= $low_ratio) { break; } } return $max_spec; }; $profit_ratio = $this->profit_ratio($mchid); $can_next = $profit_judger($mchid, $qtsex, $org_quality, $period, $profit_ratio, $header); if(!$can_next) { $max_spec = $spec_max($mchid,$qtsex, $org_quality, $qualities, $low_ratio,$period); if($max_spec >= $spec) { return false; } else { return true; } } else { return true; } } private function qts_checker($mchid, $org_quality,$cur_quality, $card_type, $spec, $qualities,$period,$header,$ratio) { [$_succ, $_fail, $cur_ratio] = $this->detail_ratio($mchid, $cur_quality, $card_type, $spec, $period); Log::record("{$header} cur_ratio = {$cur_ratio},lower_ratio={$ratio}",Log::DEBUG); if($cur_ratio >= $ratio) return true; $prices = $this->getPrice($mchid, $org_quality, $card_type, $spec); if ($prices === false) { return false; } $dratios = $this->detail_ratios($mchid, $qualities,$card_type, $spec, $period); $profit_ratio = $this->profit_ratio($mchid); $profit_judger = function ($org_quality,$qualities,$prices,$dratios,$profit_ratio) use ($header) { $sale = $prices[$org_quality]; $profit = 0; $amount = 0; foreach ($qualities as $quality) { $inprice = $prices[$quality] ?? false; if ($inprice === false) continue; [$succ, $fail, $ratio] = $dratios[$quality]; $profit += $succ * ($sale - $inprice); $amount += $succ * $sale; } $cur_pratio = round(($profit + 0.00001) / ($amount + 0.00001),4); $profit_ratio = round($profit_ratio,4); Log::record("{$header} cur_pratio = {$cur_pratio},profit_ratio={$profit_ratio}",Log::DEBUG); return $cur_pratio > $profit_ratio; }; $can_next = $profit_judger($org_quality,$qualities,$prices,$dratios,$profit_ratio); return !$can_next; } public function need_intercept($mchid,$card_type,$card_state,$is_transfer) : bool { $mintercepts = $this->mInterceptConfig; if(array_key_exists($mchid,$mintercepts)) { $mintercepts = $mintercepts[$mchid]; if(!empty($mintercepts['card_states']) && in_array($card_state,$mintercepts['card_states'],true)) { return true; } if(!empty($mintercepts['card_types']) && in_array($card_type,$mintercepts['card_types'],true)) { return true; } if($mintercepts['is_transfer'] && $is_transfer) { return true; } } return false; } }