order_clear.php 11 KB

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