order_clear.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. <?php
  2. namespace refill;
  3. use Log;
  4. use trans_wapper;
  5. use Exception;
  6. class order_clear
  7. {
  8. public function clear($start_date, $end_date, $start_line = 0)
  9. {
  10. $mchorder_gen = function ($start)
  11. {
  12. $end = $start + 3600;
  13. $cond = ['order_time&order_time' => ['_multi' => true, ['egt', $start], ['lt', $end]], 'inner_status' => 0];
  14. $order_id = 0;
  15. $i = 0;
  16. while (true)
  17. {
  18. $cond['order_id'] = ['gt', $order_id];
  19. // $start = $i * 1000;
  20. $start = 0;
  21. $items = Model()->table('refill_order')
  22. ->field('order_id,mchid,mch_order,order_time')
  23. ->where($cond)
  24. ->order('order_id asc')->limit("{$start},1000")->select();
  25. $i++;
  26. if(empty($items)) break;
  27. $last_item = end($items);
  28. $order_id = intval($last_item['order_id']);
  29. foreach ($items as $item) {
  30. unset($item['order_id']);
  31. yield $item;
  32. }
  33. }
  34. };
  35. $mchorder_saver = function ($start,$file) use ($mchorder_gen)
  36. {
  37. if (file_exists($file)) {
  38. return true;
  39. }
  40. $fp = fopen($file,'w');
  41. if($fp === false) {
  42. Log::record("Cannot open file {$file} with write.",Log::ERR);
  43. return false;
  44. }
  45. $end = $start + 86400;
  46. for ($hour = $start; $hour < $end; $hour += 3600)
  47. {
  48. $orders = $mchorder_gen($hour);
  49. foreach ($orders as $order)
  50. {
  51. $ret = fputcsv($fp,$order);
  52. if($ret === false) {
  53. return false;
  54. }
  55. }
  56. }
  57. fclose($fp);
  58. return true;
  59. };
  60. $handle_days = function ($start_date, $end_date,$line = 0) use ($mchorder_saver)
  61. {
  62. for ($date = $start_date; $date < $end_date; $date += 86400)
  63. {
  64. $sdate = date('Y-m-d',$date);
  65. $morder_file = BASE_DATA_PATH . "/log/order/{$sdate}-morder.csv";
  66. $check_file = BASE_DATA_PATH . "/log/order/{$sdate}-check.csv";
  67. $refill_file = BASE_DATA_PATH . "/log/order/{$sdate}-refill.csv";
  68. $vr_file = BASE_DATA_PATH . "/log/order/{$sdate}-vr.csv";
  69. $ret = $mchorder_saver($date,$morder_file);
  70. if($ret === false) {
  71. Log::record("fetch or save {$sdate} mch_order fail.",Log::ERR);
  72. break;
  73. }
  74. $this->order_delete($morder_file,$check_file,$refill_file,$vr_file,$line);
  75. }
  76. };
  77. $handle_days($start_date, $end_date,$start_line);
  78. }
  79. private function order_delete($mch_file, $check_file, $refill_file, $vr_file, $line)
  80. {
  81. $rorder_getter = function ($mchid,$mch_order,$mod_refill)
  82. {
  83. $result = [];
  84. $i = 0;
  85. while(true)
  86. {
  87. $start = $i * 1000;
  88. $ritems = $mod_refill->table('refill_order')->field('*')
  89. ->where(['mchid' => $mchid, 'mch_order' => $mch_order])
  90. ->order('order_id asc')
  91. ->limit("{$start},1000")->master(true)->select();
  92. $i++;
  93. $result = array_merge($ritems,$result);
  94. if(count($ritems) < 1000) {
  95. break;
  96. }
  97. }
  98. return $result;
  99. };
  100. $vorder_getter = function ($order_ids,$mod_vr)
  101. {
  102. $result = [];
  103. $i = 0;
  104. while(true)
  105. {
  106. $start = $i * 1000;
  107. $vitems = $mod_vr->table('vr_order')->field('*')
  108. ->where(['order_id' => ['in', $order_ids]])
  109. ->order('order_id asc')
  110. ->limit("{$start},1000")->master(true)->select();
  111. $i++;
  112. $result = array_merge($vitems,$result);
  113. if(count($vitems) < 1000) {
  114. break;
  115. }
  116. }
  117. return $result;
  118. };
  119. $order_checker = function ($mchid,$mch_order,$frefill,$fvr) use($rorder_getter,$vorder_getter)
  120. {
  121. $mod_refill = Model('refill_order');
  122. $ritems = $rorder_getter($mchid,$mch_order,$mod_refill);
  123. if(empty($ritems)) {
  124. return [false, [], 'order count = 0'];
  125. }
  126. $oids = [];
  127. $inner_state = [0 => 0 ,1 => 0];
  128. $is_retrying = 0;
  129. $mch_notify_counts = 0;
  130. foreach ($ritems as $item)
  131. {
  132. $oids[] = $item['order_id'];
  133. $state = intval($item['inner_status']);
  134. $inner_state[$state] += 1;
  135. $mch_notify_counts += intval($item['mch_notify_state']) >= 1 ? 1 : 0;
  136. if($state === 0 && $is_retrying === 0) {
  137. $is_retrying = intval($item['is_retrying']);
  138. }
  139. }
  140. //检查inner_status=0唯一性。
  141. if($inner_state[0] != 1) {
  142. return [false, [], "inner_status=0 counts={$inner_state[0]}"];
  143. }
  144. if($mch_notify_counts === 0) {
  145. return [false, [], "not notify merchant"];
  146. }
  147. elseif($mch_notify_counts > 1) {
  148. return [false, [], "more than one order notify merchant"];
  149. }
  150. if($is_retrying) {
  151. return [false, [], 'is_retrying = 1'];
  152. }
  153. $mod_vr = Model('vr_order');
  154. $vitems = $vorder_getter($oids,$mod_vr);
  155. //检查refill 表记录和vr_order表记录是否一致
  156. if(count($ritems) !== count($vitems)) {
  157. return [false, [], 'refill count != vr count'];
  158. }
  159. $order_state = [];
  160. foreach ($vitems as $item)
  161. {
  162. $state = intval($item['order_state']);
  163. if(!array_key_exists($state,$order_state)) {
  164. $order_state[$state] = 0;
  165. }
  166. $order_state[$state] += 1;
  167. }
  168. //检查一种订单只能有,成功或者失败状态.
  169. $vcount = count($vitems);
  170. if($vcount != $order_state[ORDER_STATE_SUCCESS] + $order_state[ORDER_STATE_CANCEL]) {
  171. return [false, [], 'ORDER: SUCCESS + CANCEL != COUNT.'];
  172. }
  173. elseif($order_state[ORDER_STATE_SUCCESS] > 1) {
  174. //成功订单只能小于等于1,否则为错误
  175. return [false, [], 'ORDER:SUCCESS COUNT > 1'];
  176. }
  177. else
  178. {
  179. // foreach ($ritems as $item) {
  180. // fputcsv($frefill,$item);
  181. // }
  182. // foreach ($vitems as $item) {
  183. // fputcsv($fvr,$item);
  184. // }
  185. }
  186. $inner_oids = [];
  187. foreach ($ritems as $item)
  188. {
  189. $status = intval($item['inner_status']);
  190. if($status === 1) {
  191. $inner_oids[] = $item['order_id'];
  192. }
  193. }
  194. return [true,$inner_oids,''];
  195. };
  196. $delter = function ($order_ids,$order_time)
  197. {
  198. if(empty($order_ids)) return;
  199. try {
  200. $mod_refill = Model('refill_order');
  201. $mod_vr = Model('vr_order');
  202. $trans = new trans_wapper($mod_refill, __METHOD__);
  203. $mod_refill->table('refill_order')->where(['order_id' => ['in',$order_ids],'order_time' => $order_time])->delete();
  204. $mod_vr->table('vr_order')->where(['order_id' => ['in',$order_ids]])->delete();
  205. $trans->commit();
  206. } catch (Exception $e) {
  207. $trans->rollback();
  208. }
  209. };
  210. $file_opener = function ($mch_file, $check_file, $refill_file, $vr_file)
  211. {
  212. $fp = fopen($mch_file,'r');
  213. $fcheck = fopen($check_file,'a+');
  214. $frefill = fopen($refill_file,'a+');
  215. $fvr = fopen($vr_file,'a+');
  216. if($fp === false || $fcheck === false || $frefill === false || $fvr === false)
  217. {
  218. if($fp !== false) {
  219. fclose($fp);
  220. }
  221. if($fcheck !== false) {
  222. fclose($fcheck);
  223. }
  224. if($frefill !== false) {
  225. fclose($frefill);
  226. }
  227. if($fvr !== false) {
  228. fclose($fvr);
  229. }
  230. return [false,false,false,false,false];
  231. }
  232. else {
  233. return [true,$fp,$fcheck,$frefill,$fvr];
  234. }
  235. };
  236. $file_closer = function($files)
  237. {
  238. foreach ($files as $fp) {
  239. fclose($fp);
  240. }
  241. };
  242. $goto_line = function ($fp,$line)
  243. {
  244. $index = 0;
  245. while(!feof($fp) && $index < $line) {
  246. $items = fgetcsv($fp);
  247. $index += 1;
  248. }
  249. };
  250. $mch_order_reader = function($fp)
  251. {
  252. while(!feof($fp))
  253. {
  254. [$mchid, $mch_order, $order_time] = fgetcsv($fp);
  255. if(empty($mchid) || empty($mch_order)) continue;
  256. yield [$mchid,$mch_order,$order_time];
  257. }
  258. };
  259. $mod_refill_err = Model('refill_error');
  260. $err_recorder = function($fcheck,$mchid,$mch_order,$order_time,$err) use($mod_refill_err)
  261. {
  262. fputcsv($fcheck,[$mchid,$mch_order,$err]);
  263. $mod_refill_err->insert(['mchid' => $mchid, 'mch_order' => $mch_order, 'order_time' => $order_time, 'msg' => $err, 'add_time' => time()]);
  264. };
  265. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  266. [$succ,$fp,$fcheck,$frefill,$fvr] = $file_opener($mch_file, $check_file, $refill_file, $vr_file);
  267. if(!$succ) {
  268. return false;
  269. }
  270. $goto_line($fp,$line);
  271. $mch_orders = $mch_order_reader($fp);
  272. foreach ($mch_orders as $order)
  273. {
  274. [$mchid, $mch_order, $order_time] = $order;
  275. [$succ, $order_ids, $err] = $order_checker($mchid, $mch_order, $frefill, $fvr);
  276. if ($succ) {
  277. $delter($order_ids, $order_time);
  278. } else {
  279. $err_recorder($fcheck, $mchid, $mch_order, $order_time, $err);
  280. }
  281. }
  282. $file_closer([$fp,$fcheck,$frefill,$fvr]);
  283. return true;
  284. }
  285. }