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; } } 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; } //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; [$_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; if (!PolicyUtil::mixed_quality($org_quality)) { return false; } $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; } }