123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- <?php
- namespace refill;
- use Log;
- use trans_wapper;
- use Exception;
- class order_clear
- {
- public function clear($start_date, $end_date, $start_line = 0)
- {
- $mchorder_gen = function ($start)
- {
- $end = $start + 3600;
- $cond = ['order_time&order_time' => ['_multi' => true, ['egt', $start], ['lt', $end]], 'inner_status' => 0];
- $i = 0;
- while (true)
- {
- $start = $i * 1000;
- $items = Model()->table('refill_order')
- ->field('mchid,mch_order,order_time')
- ->where($cond)
- ->order('order_time asc')->limit("{$start},1000")->select();
- $i++;
- if(empty($items)) break;
- foreach ($items as $item) {
- yield $item;
- }
- }
- };
- $mchorder_saver = function ($start,$file) use ($mchorder_gen)
- {
- if (file_exists($file)) {
- return true;
- }
- $fp = fopen($file,'w');
- if($fp === false) {
- Log::record("Cannot open file {$file} with write.",Log::ERR);
- return false;
- }
- $end = $start + 86400;
- for ($hour = $start; $hour < $end; $hour += 3600)
- {
- $orders = $mchorder_gen($hour);
- foreach ($orders as $order)
- {
- $ret = fputcsv($fp,$order);
- if($ret === false) {
- return false;
- }
- }
- }
- fclose($fp);
- return true;
- };
- $handle_days = function ($start_date, $end_date,$line = 0) use ($mchorder_saver)
- {
- for ($date = $start_date; $date < $end_date; $date += 86400)
- {
- $sdate = date('Y-m-d',$date);
- $morder_file = BASE_DATA_PATH . "/log/order/{$sdate}-morder.csv";
- $check_file = BASE_DATA_PATH . "/log/order/{$sdate}-check.csv";
- $refill_file = BASE_DATA_PATH . "/log/order/{$sdate}-refill.csv";
- $vr_file = BASE_DATA_PATH . "/log/order/{$sdate}-vr.csv";
- $ret = $mchorder_saver($date,$morder_file);
- if($ret === false) {
- Log::record("fetch or save {$sdate} mch_order fail.",Log::ERR);
- break;
- }
- $this->order_delete($morder_file,$check_file,$refill_file,$vr_file,$line);
- }
- };
- $handle_days($start_date, $end_date,$start_line);
- }
- private function order_delete($mch_file, $check_file, $refill_file, $vr_file, $line)
- {
- $rorder_getter = function ($mchid,$mch_order,$mod_refill)
- {
- $result = [];
- $i = 0;
- while(true)
- {
- $start = $i * 1000;
- $ritems = $mod_refill->table('refill_order')->field('*')
- ->where(['mchid' => $mchid, 'mch_order' => $mch_order])
- ->order('order_id asc')
- ->limit("{$start},1000")->master(true)->select();
- $i++;
- $result = array_merge($ritems,$result);
- if(count($ritems) < 1000) {
- break;
- }
- }
- return $result;
- };
- $vorder_getter = function ($order_ids,$mod_vr)
- {
- $result = [];
- $i = 0;
- while(true)
- {
- $start = $i * 1000;
- $vitems = $mod_vr->table('vr_order')->field('*')
- ->where(['order_id' => ['in', $order_ids]])
- ->order('order_id asc')
- ->limit("{$start},1000")->master(true)->select();
- $i++;
- $result = array_merge($vitems,$result);
- if(count($vitems) < 1000) {
- break;
- }
- }
- return $result;
- };
- $order_checker = function ($mchid,$mch_order,$frefill,$fvr) use($rorder_getter,$vorder_getter)
- {
- $mod_refill = Model('refill_order');
- $ritems = $rorder_getter($mchid,$mch_order,$mod_refill);
- if(empty($ritems)) {
- return [false, [], 'order count = 0'];
- }
- $oids = [];
- $inner_state = [0 => 0 ,1 => 0];
- $is_retrying = 0;
- $mch_notify_counts = 0;
- foreach ($ritems as $item)
- {
- $oids[] = $item['order_id'];
- $state = intval($item['inner_status']);
- $inner_state[$state] += 1;
- $mch_notify_counts += intval($item['mch_notify_state']) >= 1 ? 1 : 0;
- if($state === 0 && $is_retrying === 0) {
- $is_retrying = intval($item['is_retrying']);
- }
- }
- //检查inner_status=0唯一性。
- if($inner_state[0] != 1) {
- return [false, [], "inner_status=0 counts={$inner_state[0]}"];
- }
- if($mch_notify_counts === 0) {
- return [false, [], "not notify merchant"];
- }
- elseif($mch_notify_counts > 1) {
- return [false, [], "more than one order notify merchant"];
- }
- if($is_retrying) {
- return [false, [], 'is_retrying = 1'];
- }
- $mod_vr = Model('vr_order');
- $vitems = $vorder_getter($oids,$mod_vr);
- //检查refill 表记录和vr_order表记录是否一致
- if(count($ritems) !== count($vitems)) {
- return [false, [], 'refill count != vr count'];
- }
- $order_state = [];
- foreach ($vitems as $item)
- {
- $state = intval($item['order_state']);
- if(!array_key_exists($state,$order_state)) {
- $order_state[$state] = 0;
- }
- $order_state[$state] += 1;
- }
- //检查一种订单只能有,成功或者失败状态.
- $vcount = count($vitems);
- if($vcount != $order_state[ORDER_STATE_SUCCESS] + $order_state[ORDER_STATE_CANCEL]) {
- return [false, [], 'ORDER: SUCCESS + CANCEL != COUNT.'];
- }
- elseif($order_state[ORDER_STATE_SUCCESS] > 1) {
- //成功订单只能小于等于1,否则为错误
- return [false, [], 'ORDER:SUCCESS COUNT > 1'];
- }
- else
- {
- foreach ($ritems as $item) {
- fputcsv($frefill,$item);
- }
- foreach ($vitems as $item) {
- fputcsv($fvr,$item);
- }
- }
- $inner_oids = [];
- foreach ($ritems as $item)
- {
- $status = intval($item['inner_status']);
- if($status === 1) {
- $inner_oids[] = $item['order_id'];
- }
- }
- return [true,$inner_oids,''];
- };
- $delter = function ($order_ids,$order_time)
- {
- if(empty($order_ids)) return;
- try {
- $mod_refill = Model('refill_order');
- $mod_vr = Model('vr_order');
- $trans = new trans_wapper($mod_refill, __METHOD__);
- $mod_refill->table('refill_order')->where(['order_id' => ['in',$order_ids],'order_time' => $order_time])->delete();
- $mod_vr->table('vr_order')->where(['order_id' => ['in',$order_ids]])->delete();
- $trans->commit();
- } catch (Exception $e) {
- $trans->rollback();
- }
- };
- $file_opener = function ($mch_file, $check_file, $refill_file, $vr_file)
- {
- $fp = fopen($mch_file,'r');
- $fcheck = fopen($check_file,'a+');
- $frefill = fopen($refill_file,'a+');
- $fvr = fopen($vr_file,'a+');
- if($fp === false || $fcheck === false || $frefill === false || $fvr === false)
- {
- if($fp !== false) {
- fclose($fp);
- }
- if($fcheck !== false) {
- fclose($fcheck);
- }
- if($frefill !== false) {
- fclose($frefill);
- }
- if($fvr !== false) {
- fclose($fvr);
- }
- return [false,false,false,false,false];
- }
- else {
- return [true,$fp,$fcheck,$frefill,$fvr];
- }
- };
- $file_closer = function($files)
- {
- foreach ($files as $fp) {
- fclose($fp);
- }
- };
- $goto_line = function ($fp,$line)
- {
- $index = 0;
- while(!feof($fp) && $index < $line) {
- $items = fgetcsv($fp);
- $index += 1;
- }
- };
- $mch_order_reader = function($fp)
- {
- while(!feof($fp))
- {
- [$mchid, $mch_order, $order_time] = fgetcsv($fp);
- if(empty($mchid) || empty($mch_order)) continue;
- yield [$mchid,$mch_order,$order_time];
- }
- };
- $mod_refill_err = Model('refill_error');
- $err_recorder = function($fcheck,$mchid,$mch_order,$order_time,$err) use($mod_refill_err)
- {
- fputcsv($fcheck,[$mchid,$mch_order,$err]);
- $mod_refill_err->insert(['mchid' => $mchid, 'mch_order' => $mch_order, 'order_time' => $order_time, 'msg' => $err, 'add_time' => time()]);
- };
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- [$succ,$fp,$fcheck,$frefill,$fvr] = $file_opener($mch_file, $check_file, $refill_file, $vr_file);
- if(!$succ) {
- return false;
- }
- $goto_line($fp,$line);
- $mch_orders = $mch_order_reader($fp);
- foreach ($mch_orders as $order)
- {
- [$mchid, $mch_order, $order_time] = $order;
- [$succ, $order_ids, $err] = $order_checker($mchid, $mch_order, $frefill, $fvr);
- if ($succ) {
- $delter($order_ids, $order_time);
- } else {
- $err_recorder($fcheck, $mchid, $mch_order, $order_time, $err);
- }
- }
- $file_closer([$fp,$fcheck,$frefill,$fvr]);
- return true;
- }
- }
|