mChannelControl = new chctl(); $this->mQuality = new quality_ploy(); $this->mPrices = new merchant_price(); $this->mGroupCtl = new rgroup_ctl(); $this->mRatioCtl = new mratio_control(); $this->mQuality->setRatioCtl($this->mRatioCtl); $this->mGlobalInterceptor = new interceptor(); } public function load() { parent::load(); $opened_names = $this->mOpenedProviderNames; sort($opened_names); $opened_merchants = $this->opened_merchants(); $this->mChannelControl->load($opened_names); $this->mChannelControl->update_price($this); $this->mQuality->load(); $this->mPrices->load($opened_merchants); $turn_name = 'oil_amount_lock_turn'; $this->mAmountLockTurn = rkcache($turn_name); Log::record("AmountLockTurn = {$this->mAmountLockTurn}",Log::DEBUG); $this->mGroupCtl->load($opened_names,$opened_merchants); $this->mRatioCtl->load(); $this->init_mavg_price(); } private function init_mavg_price() { $specs_merger = function ($qspecs) { $q_keys = []; foreach ($qspecs as $quality => $specs) { foreach ($specs as $item) { [$card_type, $spec] = $item; $q_keys[$quality][] = "{$card_type}-{$spec}"; } } $sspecs = []; $first = true; foreach ($q_keys as $quality => $specs) { if($first) { $sspecs = $specs; $first = false; } else { $sspecs = array_intersect($sspecs,$specs); } } $result = []; foreach ($sspecs as $item) { [$card_type, $spec] = explode('-',$item); $result[] = [intval($card_type), intval($spec)]; } return $result; }; $pQuality = $this->mQuality; $mchids = $pQuality->mechants_quality(); foreach ($mchids as $mchid => $mixed_quality) { $qualities = $pQuality->qualities($mixed_quality); $specs = []; foreach ($qualities as $quality) { $item = $this->mPrices->merchant_specs($mchid, $quality); if (empty($item)) continue; $specs[$quality] = $item; } $specs = $specs_merger($specs); foreach ($specs as $item) { [$card_type, $spec] = $item; if (!in_array($card_type, [4, 5, 6])) continue; $prices = []; $sale_price = $this->mPrices->price($mchid,$card_type,$spec,$mixed_quality,''); $prices[$mixed_quality] = round($sale_price,4); foreach ($qualities as $quality) { $inprice = $this->calc_maxprice($mchid, $quality, $card_type, $spec); $prices[$quality] = round($inprice,4); } $this->mRatioCtl->setMixedPrice($mchid, $mixed_quality, $card_type, $spec, $prices); } } } protected function calc_avgprice($mchid,$quality,$card_type,$spec) { $providers = parent::get_providers($mchid,$spec,$card_type,$quality,-1); $names = []; foreach ($providers as $provider) { $names[] = $provider->name(); } [$hasGroup,$can_others,$channels] = $this->mGroupCtl->find_providers($mchid, $spec, $card_type, $quality); if($hasGroup) { if(empty($channels)) { if(!$can_others) { return false; } } else { $ret = array_intersect($names, $channels); if (empty($ret)) { return false; } else { $names = $ret; } } } $name_provider = []; foreach ($providers as $provider) { $name = $provider->name(); $name_provider[$name] = $provider; } $total = 0.0; foreach ($names as $name) { $provider = $name_provider[$name]; [$goods_id, $price] = $provider->goods($quality, $spec, $card_type, -1, []); $total += $price; } return $total / count($names); } protected function calc_maxprice($mchid,$quality,$card_type,$spec) { $providers = parent::get_providers($mchid,$spec,$card_type,$quality,-1); $names = []; foreach ($providers as $provider) { $names[] = $provider->name(); } [$hasGroup,$can_others,$channels] = $this->mGroupCtl->find_providers($mchid, $spec, $card_type, $quality); if($hasGroup) { if(empty($channels)) { if(!$can_others) { return false; } } else { $ret = array_intersect($names, $channels); if (empty($ret)) { return false; } else { $names = $ret; } } } $name_provider = []; foreach ($providers as $provider) { $name = $provider->name(); $name_provider[$name] = $provider; } $max_price = 0.0; foreach ($names as $name) { $provider = $name_provider[$name]; [$goods_id, $price] = $provider->goods($quality, $spec, $card_type, -1, []); if($price > $max_price) $max_price = $price; } return $max_price; } private function opened_merchants() { $mchids = []; $i = 0; while (true) { $start = $i * 1000; $items = Model()->table('merchant')->field('*')->where(['merchant_state' => 1])->order('mchid asc')->limit("{$start},1000")->select(); if(empty($items)) { break; } $i++; foreach ($items as $item) { $mchids[] = intval($item['mchid']); } } sort($mchids); return $mchids; } public function find_providers(order $order): array { $mchid = $order->mchid(); $spec = $order->spec(); $card_type = $order->card_type(); $org_quality = $order->org_quality(); $cur_quality = $order->cur_quality(); $pcode = $order->pcode(); $regin_no = $order->region_no(); $order_time = $order->order_time(); $providers = parent::get_providers($mchid,$spec,$card_type,$cur_quality,$regin_no); if(empty($providers)) { return [$providers,false]; } $names = []; foreach ($providers as $provider) { $names[] = $provider->name(); } Log::record("ProviderManager::get_providers result=" . implode(',',$names),Log::DEBUG); [$hasGroup,$can_others,$channels] = $this->mGroupCtl->find_providers($mchid, $spec, $card_type, $cur_quality); Log::record("GroupControl mchid={$mchid} spec={$spec} quality={$cur_quality} card_type={$card_type} first result=" . implode(',',$channels),Log::DEBUG); if($hasGroup) { if(empty($channels)) { if(!$can_others) { return [[],false]; } } else { $ret = array_intersect($names, $channels); if (empty($ret)) { return [[],false]; } else { $names = $ret; } } } Log::record("GroupControl second result=" . implode(',',$names),Log::DEBUG); if(PolicyUtil::mixed_quality($org_quality)) { $mixedQuality = $org_quality; } else { $mixedQuality = $cur_quality; } $price = $this->mPrices->price($mchid,$card_type,$spec,$mixedQuality,$pcode); if($price === false) { return [[],false]; } $extra_price = $this->mPrices->extra_price($mchid,$card_type,$spec,$mixedQuality,$pcode); $extra_price = $extra_price == false ? 0.00 : $extra_price; //以当前通道质量为准 $max_inprice = $this->mPrices->max_inprice($mchid,$card_type,$spec,$cur_quality,$pcode); global $config; $auto_find = $config['auto_find_channels']; $mobile_types = [mtopcard\ChinaMobileCard, mtopcard\ChinaUnicomCard, mtopcard\ChinaTelecomCard]; $qualities = [Quality::Normal]; if ($auto_find && in_array($card_type, $mobile_types, true) && in_array($cur_quality, $qualities, true)) { $names = $this->mChannelControl->auto_match($names, $spec, $card_type, $cur_quality, $price - $extra_price, $max_inprice, time() - $order_time); Log::record("policy::find_providers ChannelControl auto_match quality={$cur_quality} spec={$spec} card_type={$card_type} result=" . implode(',', $names), Log::DEBUG); } else { $names = $this->mChannelControl->match($names, $spec, $card_type, $cur_quality, $max_inprice); Log::record("policy::find_providers ChannelControl match quality={$cur_quality} spec={$spec} card_type={$card_type} result=" . implode(',', $names), Log::DEBUG); } $name_provider = []; foreach ($providers as $provider) { $name = $provider->name(); $name_provider[$name] = $provider; } $result = []; foreach ($names as $name) { if(array_key_exists($name,$name_provider)) { $result[] = $name_provider[$name]; } } return [$result,false]; } public function price($mchid,$spec,$card_type,$quality,$pcode) { return $this->mPrices->price($mchid,$card_type,$spec,$quality,$pcode); } public function max_inprice($mchid, $spec, $card_type, $quality, $pcode) { return $this->mPrices->max_inprice($mchid,$card_type,$spec,$quality,$pcode); } public function channeles(int $mchid, int $spec, int $card_type, int $quality, $regin_no) { $providers = parent::get_providers($mchid, $spec, $card_type, $quality, $regin_no); return count($providers); } public function find_quality(order $order, bool $skip_pre = false): array { $mchid = $order->mchid(); $spec = $order->spec(); $card_type = $order->card_type(); $org_quality = $order->org_quality(); $cur_quality = $order->cur_quality(); $commit_times = $order->commit_times(); $elapse_secs = $order->elapse_secs(); $pcode = $order->pcode(); $regin_no = $order->region_no(); if($card_type == mtopcard\SinopecCard || $card_type == mtopcard\PetroChinaCard) { $caller = new times_caller($mchid,$spec,$card_type,-1,$this); } else { $caller = null; } [$org_quality, $qualities] = $this->mQuality->find_quality($mchid, $card_type, $spec, $org_quality, $cur_quality, $commit_times, $elapse_secs, $caller); if(empty($qualities)) { return [$org_quality,0]; } $namer = function ($providers) { $result = []; foreach ($providers as $provider) { $result[] = $provider->name(); } return $result; }; $start = false; foreach ($qualities as $quality) { if(!$start && $skip_pre) { if($quality == $cur_quality) { $start = true; } continue; } $price = $this->mPrices->price($mchid,$card_type,$spec,$quality,$pcode); if($price === false) { Log::record("{$mchid} 没有协商 quality = {$quality} 价格",Log::DEBUG); continue; } $max_inprice = $this->mPrices->max_inprice($mchid,$card_type,$spec,$cur_quality,$pcode); $providers = parent::get_providers($mchid, $spec, $card_type, $quality, $regin_no); if(empty($providers)) continue; $names = $namer($providers); $names = $this->mChannelControl->match($names, $spec, $card_type, $quality, $max_inprice); if (!empty($names)) { return [$org_quality, $quality]; } else { Log::record("Policy::find_quality:{$quality}-{$spec}-{$card_type} is fail", Log::DEBUG); } } return [$org_quality,0]; } public function allow($mchid, $card_type, $amount, $quality): bool { return true; } public function notify($order_info, $refill_info) : bool { $order_state = $order_info['order_state']; if ($order_state == ORDER_STATE_CANCEL) { $state = 2; } else { $state = 1; } $mchid = $refill_info['mchid']; $mch_info = Model('merchant')->getMerchantInfo(['mchid' => $mchid]); [$params, $sign] = $this->body($state, $refill_info, $mch_info); $params['sgn'] = $sign; $notify_url = $refill_info['notify_url']; $resp = http_request($notify_url, $params, 'GET'); return $resp == "ok"; } private function body($state, $refill_info, $mch_info) { $params = [ "usr" => $refill_info['mchid'], "ord" => $refill_info['mch_order'], 'bz' => $refill_info['official_sn'] ?? "", "state" => $state]; $secure_key = $mch_info['secure_key']; $card_type = $refill_info['card_type']; if($card_type == mtopcard\ThirdRefillCard) { $mod_third = Model('thrid_refill'); $thrid_info = $mod_third->getThird($refill_info['order_id']); if (!empty($thrid_info)) { $card_info = $thrid_info['card_info']; if (!empty($card_info)) { $encrypt = openssl_encrypt($card_info,'AES-128-CBC',$secure_key); if($encrypt != false) { $params['card_info'] = $encrypt; } } } } $sign = $this->sign($params, $secure_key); return [$params, $sign]; } public function need_intercept($mchid,$card_type,$card_state,$is_transfer) : bool { return $this->mRatioCtl->need_intercept($mchid,$card_type,$card_state,$is_transfer); } public function region_intercept($quality,$card_type,$region_no) : bool { return $this->mGlobalInterceptor->isIntercept($quality,$card_type,$region_no); } private function sign($params, $key) { $body = "{$params['ord']}{$params['state']}{$key}"; Log::record("notify body={$body}",Log::DEBUG); return strtoupper(md5($body)); } public function update_ratios($ratios) { $this->mChannelControl->update_ratios($ratios); } public function update_mchratios($gross,$detail) { $this->mRatioCtl->update($gross,$detail); } public function update_chspeeds($speeds) { $this->mChannelControl->update_speeds($speeds); } }