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