Date.php 85 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542
  1. <?php
  2. namespace app\crontab\controller;
  3. use think\facade\Db;
  4. /**
  5. * ============================================================================
  6. * DSMall多用户商城
  7. * ============================================================================
  8. * 版权所有 2014-2028 长沙德尚网络科技有限公司,并保留所有权利。
  9. * 网站地址: http://www.csdeshang.com
  10. * ----------------------------------------------------------------------------
  11. * 这不是一个自由软件!您只能在不用于商业目的的前提下对程序代码进行修改和使用 .
  12. * 不允许对程序代码以任何形式任何目的的再发布。
  13. * ============================================================================
  14. * 定时器
  15. */
  16. class Date extends BaseCron
  17. {
  18. /**
  19. * 该文件中所有任务执行频率,默认1天,单位:秒
  20. * @var int
  21. */
  22. const EXE_TIMES = 86400;
  23. /**
  24. * 优惠券即将到期提醒时间,单位:天
  25. * @var int
  26. */
  27. const VOUCHER_INTERVAL = 5;
  28. /**
  29. * 兑换码即将到期提醒时间,单位:天
  30. * @var int
  31. */
  32. const VR_CODE_INTERVAL = 5;
  33. /**
  34. * 订单结束后可评论时间,15天,60*60*24*15
  35. * @var int
  36. */
  37. const ORDER_EVALUATE_TIME = 1296000;
  38. /**
  39. * 每次到货通知消息数量
  40. * @var int
  41. */
  42. const ARRIVAL_NOTICE_NUM = 100;
  43. /**
  44. * 默认方法
  45. */
  46. public function index()
  47. {
  48. //实物订单已付款24小时未发货,增加短信提醒
  49. $this->_order_timeout_no_translate();
  50. /*//小程序直播商品状态查询
  51. $this->_minipro_live_goods_state();
  52. //小程序直播商品删除
  53. $this->_minipro_live_goods_delete();
  54. //小程序直播商品创建
  55. $this->_minipro_live_goods_add();
  56. //小程序直播商品更新
  57. $this->_minipro_live_goods_update();
  58. //订单超期后不允许评价
  59. $this->_order_eval_expire_update();
  60. //未付款订单超期自动关闭
  61. $this->_order_timeout_cancel();
  62. //增加会员积分和经验值
  63. $this->_add_points();
  64. //订单自动完成
  65. $this->_order_auto_complete();
  66. //更新订单扩展表收货人所在省份ID
  67. $this->_order_reciver_provinceid_update();
  68. //更新退款申请超时处理
  69. model('trade')->editRefundConfirm();
  70. //店铺到期关闭
  71. $this->_store_auto_close();
  72. //生成店铺结算单
  73. $this->_creat_bill();
  74. //代金券即将过期提醒
  75. $this->_voucher_will_expire();
  76. //虚拟兑换码即将过期提醒
  77. $this->_vr_code_will_expire();
  78. //更新商品访问量
  79. $this->_goods_click_update();
  80. //更新商品促销到期状态
  81. $this->_goods_promotion_state_update();
  82. //商品到货通知提醒
  83. $this->_arrival_notice();
  84. //更新浏览量
  85. $this->_goods_browse_update();
  86. //缓存订单及订单商品相关数据
  87. $this->_order_goods_cache();
  88. //会员相关数据统计
  89. $this->_member_stat();*/
  90. $this->log('24小时计划任务跑完');
  91. }
  92. /*
  93. * 小程序直播商品创建(调用额度:500次/一天)
  94. */
  95. function _minipro_live_goods_add()
  96. {
  97. if (intval(config('ds_config.live_type')) != 1) {
  98. return;
  99. }
  100. $goods_list = Db::name('goodscommon')->alias('goodscommon')->join('minipro_live_goods minipro_live_goods', 'minipro_live_goods.goods_commonid=goodscommon.goods_commonid', 'LEFT')->field('goodscommon.gc_id,goodscommon.gc_id_1,goodscommon.gc_id_2,goodscommon.gc_id_3,goodscommon.gc_name,goodscommon.goods_name,goodscommon.goods_image,goodscommon.goods_price,goodscommon.goods_commonid,goodscommon.store_id,goodscommon.store_name')->where([['minipro_live_goods.goods_commonid', 'null']])->limit(100)->select()->toArray();
  101. $wechat_model = model('wechat');
  102. $wechat_model->getOneWxconfig();
  103. $accessToken = $wechat_model->getAccessToken('miniprogram', 0);
  104. if ($wechat_model->error_code) {
  105. $this->log('获取小程序AccessToken失败' . $wechat_model->error_message);
  106. return;
  107. }
  108. $minipro_live_goods_model = model('minipro_live_goods');
  109. foreach ($goods_list as $goods_info) {
  110. $goods_id = Db::name('goods')->where([['goods_commonid', '=', $goods_info['goods_commonid']]])->order('goods_id asc')->value('goods_id');
  111. if (!$goods_id) {
  112. $this->log('商品不存在');
  113. continue;
  114. }
  115. //上传临时素材
  116. $goods_image = str_replace(UPLOAD_SITE_URL, BASE_UPLOAD_PATH, goods_thumb($goods_info));
  117. $image_path = pathinfo($goods_image, PATHINFO_DIRNAME);
  118. $image_name = pathinfo($goods_image, PATHINFO_BASENAME);
  119. if (!strstr($image_name, '_240')) {
  120. create_albumpic_thumb($image_path, $image_name);
  121. $goods_image = str_ireplace('.', '_240.', $image_name);
  122. }
  123. $res = $wechat_model->uploadMedia('image', $goods_image, "image/jpeg", $image_name);
  124. if (!$res['code']) {
  125. $this->log('上传临时素材失败' . $res['msg']);
  126. continue;
  127. }
  128. $coverImgUrl = $res['data'];
  129. $data = [
  130. 'goodsInfo' => [
  131. 'coverImgUrl' => $coverImgUrl,
  132. 'name' => mb_substr($goods_info['goods_name'], 0, 14), //商品名称,最长14个汉字
  133. 'priceType' => 1,
  134. 'price' => $goods_info['goods_price'],
  135. 'url' => 'pages/index/index?ret_url=' . urlencode(config('ds_config.h5_site_url') . '/home/goodsdetail?goods_id=' . $goods_id),
  136. ],
  137. ];
  138. $res = http_request('https://api.weixin.qq.com/wxaapi/broadcast/goods/add?access_token=' . $accessToken, 'POST', $data);
  139. $res = json_decode($res, true);
  140. if (!$res || $res['errcode']) {
  141. $this->log(isset($res['errmsg']) ? $res['errmsg'] : '添加商品出错,错误码:' . $res['errcode']);
  142. continue;
  143. }
  144. $minipro_live_goods_model->addMiniproLiveGoods([
  145. 'store_id' => $goods_info['store_id'],
  146. 'store_name' => $goods_info['store_name'],
  147. 'goods_id' => $goods_id,
  148. 'goods_commonid' => $goods_info['goods_commonid'],
  149. 'goods_name' => $goods_info['goods_name'],
  150. 'goods_price' => $goods_info['goods_price'],
  151. 'goods_image' => $goods_info['goods_image'],
  152. 'minipro_live_goods_add_time' => TIMESTAMP,
  153. 'minipro_live_goods_state' => 0,
  154. 'minipro_live_goods_result_id' => $res['goodsId'],
  155. 'minipro_live_goods_verify_id' => $res['auditId'],
  156. ]);
  157. }
  158. }
  159. /*
  160. * 小程序直播商品删除(调用额度:1000次/一天)
  161. */
  162. function _minipro_live_goods_delete()
  163. {
  164. if (intval(config('ds_config.live_type')) != 1) {
  165. return;
  166. }
  167. $wechat_model = model('wechat');
  168. $wechat_model->getOneWxconfig();
  169. $accessToken = $wechat_model->getAccessToken('miniprogram', 0);
  170. if ($wechat_model->error_code) {
  171. $this->log('获取小程序AccessToken失败' . $wechat_model->error_message);
  172. return;
  173. }
  174. $minipro_live_goods_model = model('minipro_live_goods');
  175. //商品不存在的删除,审核中的、已审核的商品名称、商品图片不一致的删除
  176. $minipro_live_goods_result_ids = Db::name('minipro_live_goods')->alias('minipro_live_goods')->join('goodscommon goodscommon', 'minipro_live_goods.goods_commonid=goodscommon.goods_commonid', 'LEFT')->where([['minipro_live_goods_close', '=', 0], ['goodscommon.goods_commonid', 'null']])->whereOr(function ($query) {
  177. $query->where([['minipro_live_goods_state', '<>', 0]])->where(function ($query) {
  178. $query->whereOr([['goodscommon.goods_name', '<>', Db::raw('minipro_live_goods.goods_name')]])->whereOr([['goodscommon.goods_image', '<>', Db::raw('minipro_live_goods.goods_image')]]);
  179. });
  180. })->limit(100)->column('minipro_live_goods_result_id');
  181. foreach ($minipro_live_goods_result_ids as $minipro_live_goods_result_id) {
  182. $data = [
  183. 'goodsId' => $minipro_live_goods_result_id,
  184. ];
  185. $res = http_request('https://api.weixin.qq.com/wxaapi/broadcast/goods/delete?access_token=' . $accessToken, 'POST', $data);
  186. $res = json_decode($res, true);
  187. if (!$res || $res['errcode']) {
  188. $this->log(isset($res['errmsg']) ? $res['errmsg'] : '删除商品出错,错误码:' . $res['errcode']);
  189. continue;
  190. }
  191. $minipro_live_goods_model->delMiniproLiveGoods([['minipro_live_goods_result_id', '=', $minipro_live_goods_result_id]]);
  192. }
  193. //审核中的、已审核的商品ID不存在的删除
  194. $subQuery = Db::name('goods')->field('goods_id')->where('1=1')->buildSql();
  195. $minipro_live_goods_result_ids = Db::name('minipro_live_goods')->where([['minipro_live_goods_close', '=', 0], ['minipro_live_goods_state', '<>', 0], ['goods_id', 'not in', Db::raw($subQuery)]])->limit(100)->column('minipro_live_goods_result_id');
  196. foreach ($minipro_live_goods_result_ids as $minipro_live_goods_result_id) {
  197. $data = [
  198. 'goodsId' => $minipro_live_goods_result_id,
  199. ];
  200. $res = http_request('https://api.weixin.qq.com/wxaapi/broadcast/goods/delete?access_token=' . $accessToken, 'POST', $data);
  201. $res = json_decode($res, true);
  202. if (!$res || $res['errcode']) {
  203. $this->log(isset($res['errmsg']) ? $res['errmsg'] : '删除商品出错,错误码:' . $res['errcode']);
  204. continue;
  205. }
  206. $minipro_live_goods_model->delMiniproLiveGoods([['minipro_live_goods_result_id', '=', $minipro_live_goods_result_id]]);
  207. }
  208. }
  209. /*
  210. * 小程序直播商品更新(调用额度:1000次/一天)
  211. */
  212. function _minipro_live_goods_update()
  213. {
  214. if (intval(config('ds_config.live_type')) != 1) {
  215. return;
  216. }
  217. $wechat_model = model('wechat');
  218. $wechat_model->getOneWxconfig();
  219. $accessToken = $wechat_model->getAccessToken('miniprogram', 0);
  220. if ($wechat_model->error_code) {
  221. $this->log('获取小程序AccessToken失败' . $wechat_model->error_message);
  222. return;
  223. }
  224. $minipro_live_goods_model = model('minipro_live_goods');
  225. //未审核的商品、已审核的商品价格不一致的更新
  226. $goods_list = Db::name('minipro_live_goods')->alias('minipro_live_goods')->field('minipro_live_goods_result_id,goodscommon.goods_name,goodscommon.goods_image,minipro_live_goods.goods_image as goods_image2,goodscommon.goods_price,goodscommon.goods_commonid,goodscommon.store_id,goodscommon.store_name')->join('goodscommon goodscommon', 'minipro_live_goods.goods_commonid=goodscommon.goods_commonid')->where([['minipro_live_goods_close', '=', 0]])->where(function ($query) {
  227. $query->where([['minipro_live_goods_state', '=', 2]])->where([['goodscommon.goods_price', '<>', Db::raw('minipro_live_goods.goods_price')]]);
  228. })->whereOr(function ($query) {
  229. $query->where([['minipro_live_goods_state', '=', 0]])->where(function ($query) {
  230. $query->whereOr([['goodscommon.goods_price', '<>', Db::raw('minipro_live_goods.goods_price')]])->whereOr([['goodscommon.goods_name', '<>', Db::raw('minipro_live_goods.goods_name')]])->whereOr([['goodscommon.goods_image', '<>', Db::raw('minipro_live_goods.goods_image')]]);
  231. });
  232. })->limit(100)->select()->toArray();
  233. foreach ($goods_list as $goods_info) {
  234. $goods_data = [
  235. 'goodsId' => $goods_info['minipro_live_goods_result_id'],
  236. 'priceType' => 1,
  237. ];
  238. if ($goods_info['minipro_live_goods_state'] == 2) {
  239. $goods_data['price'] = $goods_info['goods_price'];
  240. }
  241. if ($goods_info['minipro_live_goods_state'] == 0) {
  242. if ($goods_info['goods_image'] != $goods_info['goods_image2']) {
  243. //上传临时素材
  244. $goods_image = str_replace(UPLOAD_SITE_URL, BASE_UPLOAD_PATH, goods_thumb($goods_info));
  245. $image_path = pathinfo($goods_image, PATHINFO_DIRNAME);
  246. $image_name = pathinfo($goods_image, PATHINFO_BASENAME);
  247. if (!strstr($image_name, '_240')) {
  248. create_albumpic_thumb($image_path, $image_name);
  249. $goods_image = str_ireplace('.', '_240.', $image_name);
  250. }
  251. $res = $wechat_model->uploadMedia('image', $goods_image, "image/jpeg", $image_name);
  252. if (!$res['code']) {
  253. $this->log('上传临时素材失败' . $res['msg']);
  254. continue;
  255. }
  256. $coverImgUrl = $res['data'];
  257. $goods_data['coverImgUrl'] = $coverImgUrl;
  258. }
  259. $goods_data['name'] = mb_substr($goods_info['goods_name'], 0, 14); //商品名称,最长14个汉字
  260. $goods_data['price'] = $goods_info['goods_price'];
  261. }
  262. $data = [
  263. 'goodsInfo' => $goods_data,
  264. ];
  265. $res = http_request('https://api.weixin.qq.com/wxaapi/broadcast/goods/update?access_token=' . $accessToken, 'POST', $data);
  266. $res = json_decode($res, true);
  267. if (!$res || $res['errcode']) {
  268. $this->log(isset($res['errmsg']) ? $res['errmsg'] : '更新商品出错,错误码:' . $res['errcode']);
  269. continue;
  270. }
  271. $minipro_live_goods_model->editMiniproLiveGoods([
  272. 'goods_name' => $goods_info['goods_name'],
  273. 'goods_price' => $goods_info['goods_price'],
  274. 'goods_image' => $goods_info['goods_image'],
  275. ], [['minipro_live_goods_result_id', '=', $goods_info['minipro_live_goods_result_id']]]);
  276. }
  277. //未审核的商品ID不存在的更新
  278. $subQuery = Db::name('goods')->field('goods_id')->where('1=1')->buildSql();
  279. $goods_list = Db::name('minipro_live_goods')->where([['minipro_live_goods_close', '=', 0], ['minipro_live_goods_state', '=', 0], ['goods_id', 'not in', Db::raw($subQuery)]])->limit(100)->select()->toArray();
  280. foreach ($goods_list as $goods_info) {
  281. $goods_id = Db::name('goods')->where([['goods_commonid', '=', $goods_info['goods_commonid']]])->order('goods_id asc')->value('goods_id');
  282. if (!$goods_id) {
  283. $this->log('商品不存在');
  284. continue;
  285. }
  286. $goods_data = [
  287. 'goodsId' => $goods_info['minipro_live_goods_result_id'],
  288. 'url' => 'pages/index/index?ret_url=' . urlencode(config('ds_config.h5_site_url') . '/home/goodsdetail?goods_id=' . $goods_id),
  289. ];
  290. $data = [
  291. 'goodsInfo' => $goods_data,
  292. ];
  293. $res = http_request('https://api.weixin.qq.com/wxaapi/broadcast/goods/update?access_token=' . $accessToken, 'POST', $data);
  294. $res = json_decode($res, true);
  295. if (!$res || $res['errcode']) {
  296. $this->log(isset($res['errmsg']) ? $res['errmsg'] : '更新商品出错,错误码:' . $res['errcode']);
  297. continue;
  298. }
  299. $minipro_live_goods_model->editMiniproLiveGoods([
  300. 'goods_id' => $goods_id,
  301. ], [['minipro_live_goods_result_id', '=', $goods_info['minipro_live_goods_result_id']]]);
  302. }
  303. }
  304. /*
  305. * 小程序直播商品状态查询(调用额度:1000次/一天)
  306. */
  307. function _minipro_live_goods_state()
  308. {
  309. if (intval(config('ds_config.live_type')) != 1) {
  310. return;
  311. }
  312. //审核时间为1~7天
  313. $wechat_model = model('wechat');
  314. $wechat_model->getOneWxconfig();
  315. $accessToken = $wechat_model->getAccessToken('miniprogram', 0);
  316. if ($wechat_model->error_code) {
  317. $this->log('获取小程序AccessToken失败' . $wechat_model->error_message);
  318. return;
  319. }
  320. $ids = Db::name('minipro_live_goods')->where([['minipro_live_goods_close', '=', 0], ['minipro_live_goods_state', '=', 0]])->limit(200)->column('minipro_live_goods_result_id');
  321. if (!empty($ids)) {
  322. $data = [
  323. 'goods_ids' => $ids,
  324. ];
  325. $res = http_request('https://api.weixin.qq.com/wxa/business/getgoodswarehouse?access_token=' . $accessToken, 'POST', json_encode($data));
  326. $res = json_decode($res, true);
  327. if (!$res || $res['errcode']) {
  328. $this->log('小程序直播商品状态查询失败' . (isset($res['errmsg']) ? $res['errmsg'] : ',错误码:' . $res['errcode']));
  329. return;
  330. }
  331. $minipro_live_goods_model = model('minipro_live_goods');
  332. foreach ($res['goods'] as $val) {
  333. if (in_array($val['audit_status'], [2, 3])) {
  334. $minipro_live_goods_model->editMiniproLiveGoods(['minipro_live_goods_state' => $val['audit_status']], [['minipro_live_goods_result_id', '=', $val['goods_id']]]);
  335. }
  336. }
  337. }
  338. }
  339. /*
  340. * 店铺到期关闭
  341. */
  342. function _store_auto_close()
  343. {
  344. $store_model = model('store');
  345. $condition = [];
  346. $condition[] = ['store_state', '=', 1];
  347. $condition[] = ['store_endtime', '>', 0];
  348. $condition[] = ['store_endtime', '<', TIMESTAMP];
  349. $store_ids = Db::name('store')->where($condition)->limit(100)->column('store_id');
  350. $goods_model = model('goods');
  351. foreach ($store_ids as $store_id) {
  352. Db::startTrans();
  353. try {
  354. $store_model->editStore(['store_state' => 0, 'store_recommend' => 0], [['store_id', '=', $store_id]]);
  355. //根据店铺状态修改该店铺所有商品状态
  356. $goods_model->editProducesOffline([['store_id', '=', $store_id]]);
  357. } catch (\Exception $e) {
  358. Db::rollback();
  359. $this->log('到期店铺关闭失败[店铺ID:' . $store_id . ']' . $e->getMessage());
  360. }
  361. Db::commit();
  362. }
  363. }
  364. /*
  365. * 生成店铺结算单
  366. */
  367. public function _creat_bill()
  368. {
  369. //搜索商家结算日期小于当前时间减结算周期的所有商家,每次100个
  370. $store_ids = Db::name('store')->where([['store_bill_time', '<', strtotime(date('Y-m-d 0:0:0')) - intval(config('ds_config.store_bill_cycle')) * 86400]])->limit(100)->column('store_id');
  371. $storemoneylog_mod = model('storemoneylog');
  372. $orderinviter_model = model('orderinviter');
  373. $bill_model = model('bill');
  374. $trade_model = model('trade');
  375. $order_refund_day = intval($trade_model->getMaxDay('order_refund'));
  376. $order_refund_time = strtotime(date('Y-m-d 0:0:0')) - $order_refund_day * 86400;
  377. $vr_order_refund_day = intval(config('ds_config.code_invalid_refund'));
  378. $vr_order_refund_time = strtotime(date('Y-m-d 0:0:0')) - $vr_order_refund_day * 86400;
  379. foreach ($store_ids as $store_id) {
  380. Db::startTrans();
  381. $store_info = Db::name('store')->where('store_id', $store_id)->field('store_id,store_name,seller_name,is_platform_store,store_bill_time')->lock(true)->find();
  382. if ($store_info) {
  383. try {
  384. $data = [];
  385. //如果店铺没有结算过,则查询与结算单相关项目的最小时间作为结算单开始时间
  386. if (!$store_info['store_bill_time']) {
  387. $ob_startdate = 0;
  388. $storecost_time = Db::name('storecost')->where([['storecost_store_id', '=', $store_id], ['storecost_state', '=', 0], ['storecost_time', '<', strtotime(date('Y-m-d 0:0:0')) - intval(config('ds_config.store_bill_cycle')) * 86400]])->order('storecost_time asc')->lock(true)->value('storecost_time');
  389. //取结算时间和退款过期时间的较小者
  390. $temp_time = $order_refund_time;
  391. if ($temp_time > (strtotime(date('Y-m-d 0:0:0')) - intval(config('ds_config.store_bill_cycle')) * 86400)) {
  392. $temp_time = strtotime(date('Y-m-d 0:0:0')) - intval(config('ds_config.store_bill_cycle')) * 86400;
  393. }
  394. $order_time = Db::name('order')->where([['store_id', '=', $store_id], ['order_state', '=', ORDER_STATE_SUCCESS], ['delay_time', '<', $temp_time], ['payment_code', '<>', 'offline'], ['ob_no', '=', 0]])->order('add_time asc')->lock(true)->value('add_time');
  395. //不允许退款且超过使用期限的、允许退款且超过可退款期限、允许退款并且全部完成退款的虚拟订单
  396. $vr_order_time = Db::name('vrorder')->where([['store_id', '=', $store_id], ['order_state', '=', ORDER_STATE_SUCCESS], ['finnshed_time', '<', strtotime(date('Y-m-d 0:0:0')) - intval(config('ds_config.store_bill_cycle')) * 86400], ['ob_no', '=', 0]])->where('((vr_invalid_refund=0) || (vr_invalid_refund=1 AND vr_indate<' . $vr_order_refund_time . ') || (vr_invalid_refund=1 AND refund_state=2))')->order('add_time asc')->lock(true)->value('add_time');
  397. $ob_startdate = (!$ob_startdate || ($ob_startdate && $storecost_time && $storecost_time < $ob_startdate)) ? $storecost_time : $ob_startdate;
  398. $ob_startdate = (!$ob_startdate || ($ob_startdate && $order_time && $order_time < $ob_startdate)) ? $order_time : $ob_startdate;
  399. $ob_startdate = (!$ob_startdate || ($ob_startdate && $vr_order_time && $vr_order_time < $ob_startdate)) ? $vr_order_time : $ob_startdate;
  400. } else {
  401. $ob_startdate = $store_info['store_bill_time'];
  402. }
  403. if ($ob_startdate) {
  404. //零点开始
  405. $ob_startdate = strtotime(date('Y-m-d 0:0:0', $ob_startdate));
  406. $ob_enddate = $ob_startdate + intval(config('ds_config.store_bill_cycle')) * 86400;
  407. //店铺促销活动费用
  408. $storecost_sum = Db::name('storecost')->where([['storecost_store_id', '=', $store_id], ['storecost_state', '=', 0], ['storecost_time', '<', $ob_enddate]])->field('SUM(storecost_price) AS ob_store_cost_totals,COUNT(*) AS count')->lock(true)->find();
  409. //取结算时间和退款过期时间的较小者
  410. $temp_time = $order_refund_time;
  411. if ($temp_time > $ob_enddate) {
  412. $temp_time = $ob_enddate;
  413. }
  414. $order_ids = Db::name('order')->where([['store_id', '=', $store_id], ['order_state', '=', ORDER_STATE_SUCCESS], ['delay_time', '<', $temp_time], ['payment_code', '<>', 'offline'], ['ob_no', '=', 0]])->lock(true)->column('order_id');
  415. $vr_order_ids = Db::name('vrorder')->where([['store_id', '=', $store_id], ['order_state', '=', ORDER_STATE_SUCCESS], ['finnshed_time', '<', $temp_time], ['ob_no', '=', 0]])->where('((vr_invalid_refund=0) || (vr_invalid_refund=1 AND vr_indate<' . $vr_order_refund_time . ') || (vr_invalid_refund=1 AND refund_state=2))')->lock(true)->column('order_id');
  416. if ($storecost_sum && $storecost_sum['count']) {
  417. $data['ob_store_cost_totals'] = $storecost_sum['ob_store_cost_totals'];
  418. }
  419. if ($order_ids) {
  420. //查看相关订单是否有未完成的退款
  421. $r_order_ids = Db::name('refundreturn')->where('order_id', 'in', $order_ids)->where('refund_state', 'not in', [3, 4])->lock(true)->column('order_id');
  422. if ($r_order_ids) {
  423. $order_ids = array_diff($order_ids, $r_order_ids);
  424. }
  425. //如果全部为待处理退款的订单,则不生成结算单,等退款完成再处理
  426. if ($order_ids) {
  427. //结算订单金额,结算运费,结算退单金额
  428. $order_sum = Db::name('order')->where('order_id', 'in', $order_ids)->field('SUM(order_amount) AS ob_order_totals,SUM(shipping_fee) AS ob_shipping_totals,SUM(refund_amount) AS ob_order_return_totals')->lock(true)->find();
  429. //结算佣金金额
  430. $ordergoods_sum = Db::name('ordergoods')->where('order_id', 'in', $order_ids)->field('SUM(ROUND(goods_pay_price*commis_rate/100,2)) AS ob_commis_totals')->lock(true)->find();
  431. //结算退还佣金,部分退款的
  432. $refundreturn_sum_1 = Db::name('refundreturn')->alias('refundreturn')->join('ordergoods ordergoods', 'refundreturn.order_goods_id = ordergoods.rec_id')->where('refundreturn.order_id', 'in', $order_ids)->where('refundreturn.refund_state', 3)->where('refundreturn.seller_state', 2)->where('refundreturn.order_goods_id', '>', 0)->field('SUM(ROUND(refundreturn.refund_amount*ordergoods.commis_rate/100,2)) AS ob_commis_return_totals')->lock(true)->find();
  433. $refundreturn_sum_2 = [];
  434. $refundreturn_rec_ids_2 = Db::name('refundreturn')->where('order_id', 'in', $order_ids)->where('refund_state', 3)->where('seller_state', 2)->where('order_goods_id', 0)->lock(true)->column('order_id');
  435. if ($refundreturn_rec_ids_2) {
  436. $refundreturn_sum_2 = Db::name('ordergoods')->where('order_id', 'in', $refundreturn_rec_ids_2)->field('SUM(ROUND(goods_pay_price*commis_rate/100,2)) AS ob_commis_return_totals')->lock(true)->find();
  437. }
  438. foreach ($order_ids as $order_id) {
  439. $orderinviter_model->giveMoney($order_id, 0);
  440. }
  441. //分销的佣金
  442. $orderinviter_sum = Db::name('orderinviter')->where('orderinviter_order_id', 'in', $order_ids)->where('orderinviter_valid', 1)->where('orderinviter_order_type', 0)->field('SUM(orderinviter_money) AS ob_inviter_totals')->lock(true)->find();
  443. $data['ob_order_totals'] = $order_sum['ob_order_totals'];
  444. $data['ob_shipping_totals'] = $order_sum['ob_shipping_totals'];
  445. $data['ob_order_return_totals'] = $order_sum['ob_order_return_totals'];
  446. $data['ob_commis_totals'] = $ordergoods_sum['ob_commis_totals'];
  447. $data['ob_commis_return_totals'] = bcadd(((!empty($refundreturn_sum_1)) ? $refundreturn_sum_1['ob_commis_return_totals'] : 0), ((!empty($refundreturn_sum_2)) ? $refundreturn_sum_2['ob_commis_return_totals'] : 0), 2);
  448. $data['ob_inviter_totals'] = (!empty($orderinviter_sum)) ? $orderinviter_sum['ob_inviter_totals'] : 0;
  449. }
  450. }
  451. if ($vr_order_ids) {
  452. foreach ($vr_order_ids as $order_id) {
  453. $orderinviter_model->giveMoney($order_id, 1);
  454. }
  455. //分销的佣金
  456. $orderinviter_sum = Db::name('orderinviter')->where('orderinviter_order_id', 'in', $vr_order_ids)->where('orderinviter_valid', 1)->where('orderinviter_order_type', 1)->field('SUM(orderinviter_money) AS ob_vr_inviter_totals')->lock(true)->find();
  457. $vr_order_sum = Db::name('vrorder')->where('order_id', 'in', $vr_order_ids)->field('SUM(order_amount) AS ob_vr_order_totals,SUM(ROUND(order_amount*commis_rate/100,2)) AS ob_vr_commis_totals,SUM(refund_amount) AS ob_vr_order_return_totals,SUM(ROUND(refund_amount*commis_rate/100,2)) AS ob_vr_commis_return_totals')->lock(true)->find();
  458. $data['ob_vr_order_totals'] = $vr_order_sum['ob_vr_order_totals'];
  459. $data['ob_vr_commis_totals'] = $vr_order_sum['ob_vr_commis_totals'];
  460. $data['ob_vr_order_return_totals'] = $vr_order_sum['ob_vr_order_return_totals'];
  461. $data['ob_vr_commis_return_totals'] = $vr_order_sum['ob_vr_commis_return_totals'];
  462. $data['ob_vr_inviter_totals'] = (!empty($orderinviter_sum)) ? $orderinviter_sum['ob_vr_inviter_totals'] : 0;
  463. }
  464. if (!empty($data)) {
  465. $data['ob_createdate'] = TIMESTAMP;
  466. $data['ob_startdate'] = $ob_startdate;
  467. $data['ob_enddate'] = $ob_enddate;
  468. $data['ob_store_id'] = $store_id;
  469. $data['ob_store_name'] = $store_info['store_name']; //平台自营店铺不需要增加店铺资金
  470. $data['ob_state'] = ($store_info['is_platform_store'] == 1) ? 4 : 1;
  471. if (!isset($data['ob_order_totals'])) {
  472. $data['ob_order_totals'] = 0;
  473. }
  474. if (!isset($data['ob_store_cost_totals'])) {
  475. $data['ob_store_cost_totals'] = 0;
  476. }
  477. if (!isset($data['ob_inviter_totals'])) {
  478. $data['ob_inviter_totals'] = 0;
  479. }
  480. if (!isset($data['ob_order_return_totals'])) {
  481. $data['ob_order_return_totals'] = 0;
  482. }
  483. if (!isset($data['ob_commis_totals'])) {
  484. $data['ob_commis_totals'] = 0;
  485. }
  486. if (!isset($data['ob_commis_return_totals'])) {
  487. $data['ob_commis_return_totals'] = 0;
  488. }
  489. if (!isset($data['ob_vr_order_totals'])) {
  490. $data['ob_vr_order_totals'] = 0;
  491. }
  492. if (!isset($data['ob_vr_order_return_totals'])) {
  493. $data['ob_vr_order_return_totals'] = 0;
  494. }
  495. if (!isset($data['ob_vr_commis_totals'])) {
  496. $data['ob_vr_commis_totals'] = 0;
  497. }
  498. if (!isset($data['ob_vr_commis_return_totals'])) {
  499. $data['ob_vr_commis_return_totals'] = 0;
  500. }
  501. if (!isset($data['ob_vr_inviter_totals'])) {
  502. $data['ob_vr_inviter_totals'] = 0;
  503. }
  504. //计算实际可得金额
  505. $data['ob_result_totals'] = round($data['ob_order_totals'] - $data['ob_store_cost_totals'] - $data['ob_inviter_totals'] - $data['ob_order_return_totals'] - $data['ob_commis_totals'] + $data['ob_commis_return_totals'] + $data['ob_vr_order_totals'] - $data['ob_vr_order_return_totals'] - $data['ob_vr_commis_totals'] + $data['ob_vr_commis_return_totals'] - $data['ob_vr_inviter_totals'], 2);
  506. //插入到结算账单
  507. $ob_no = $bill_model->addOrderbill($data);
  508. if (!$ob_no) {
  509. throw new \think\Exception('新增结算单失败', 10006);
  510. }
  511. if ($order_ids) {
  512. //订单更新结算单号
  513. if (!Db::name('order')->where('order_id', 'in', $order_ids)->update(['ob_no' => $ob_no])) {
  514. throw new \think\Exception('更新实物订单结算单号失败', 10006);
  515. }
  516. }
  517. if ($vr_order_ids) {
  518. //订单更新结算单号
  519. if (!Db::name('vrorder')->where('order_id', 'in', $vr_order_ids)->update(['ob_no' => $ob_no])) {
  520. throw new \think\Exception('更新虚拟订单结算单号失败', 10006);
  521. }
  522. }
  523. }
  524. //店铺活动改成已结算
  525. if (!empty($storecost_sum) && $storecost_sum['count'] && !Db::name('storecost')->where([['storecost_store_id', '=', $store_id], ['storecost_state', '=', 0], ['storecost_time', '<', $ob_enddate]])->update(['storecost_state' => 1])) {
  526. throw new \think\Exception('更新店铺活动结算单号失败', 10006);
  527. }
  528. } else {
  529. $ob_enddate = strtotime(date('Y-m-d 0:0:0')) - intval(config('ds_config.store_bill_cycle')) * 86400;
  530. }
  531. //更新店铺结算时间
  532. if (!Db::name('store')->where('store_id', $store_id)->update(['store_bill_time' => $ob_enddate])) {
  533. throw new \think\Exception('更新店铺结算时间失败', 10006);
  534. }
  535. } catch (\Exception $e) {
  536. Db::rollback();
  537. $this->log('[店铺名称:' . $store_info['store_name'] . ']' . $e->getMessage());
  538. }
  539. }
  540. Db::commit();
  541. }
  542. //如果还有未更新结算日期的店铺,则重定向继续生产结算单
  543. if (Db::name('store')->where([['store_bill_time', '<', strtotime(date('Y-m-d 0:0:0')) - intval(config('ds_config.store_bill_cycle')) * 86400]])->count() > 0) {
  544. $this->redirect('date/index');
  545. }
  546. }
  547. /**
  548. * 未付款订单超期自动关闭
  549. */
  550. private function _order_timeout_cancel()
  551. {
  552. //实物订单超期未支付系统自动关闭
  553. $_break = false;
  554. $chain_order_model = model('chain_order');
  555. $order_model = model('order');
  556. $logic_order = model('order', 'logic');
  557. $condition = [];
  558. $condition[] = ['order_state', '=', ORDER_STATE_NEW];
  559. $condition[] = ['add_time', '<', TIMESTAMP - config('ds_config.order_auto_cancel_day') * self::EXE_TIMES];
  560. //分批,每批处理100个订单,最多处理5W个订单
  561. for ($i = 0; $i < 500; $i++) {
  562. if ($_break) {
  563. break;
  564. }
  565. $order_list = $order_model->getOrderList($condition, '', '*', '', 100);
  566. if (empty($order_list))
  567. break;
  568. foreach ($order_list as $order_info) {
  569. try {
  570. Db::startTrans();
  571. $logic_order->changeOrderStateCancel($order_info, 'system', '系统', '超期未支付系统自动关闭订单', true, false);
  572. } catch (\Exception $e) {
  573. Db::rollback();
  574. $this->log('实物订单超期未支付关闭失败SN:' . $order_info['order_sn']);
  575. $_break = true;
  576. break;
  577. }
  578. Db::commit();
  579. $chain_order_model->editChainOrderCancel($order_info['order_id']);
  580. }
  581. }
  582. //虚拟订单超期未支付系统自动关闭
  583. $_break = false;
  584. $vrorder_model = model('vrorder');
  585. $logic_vrorder = model('vrorder', 'logic');
  586. $condition = [];
  587. $condition[] = ['order_state', '=', ORDER_STATE_NEW];
  588. $condition[] = ['add_time', '<', TIMESTAMP - config('ds_config.order_auto_cancel_day') * self::EXE_TIMES];
  589. //分批,每批处理100个订单,最多处理5W个订单
  590. for ($i = 0; $i < 500; $i++) {
  591. if ($_break) {
  592. break;
  593. }
  594. $order_list = $vrorder_model->getVrorderList($condition, '', '*', '', 100);
  595. if (empty($order_list))
  596. break;
  597. foreach ($order_list as $order_info) {
  598. $result = $logic_vrorder->changeOrderStateCancel($order_info, 'system', '超期未支付系统自动关闭订单', false);
  599. }
  600. if (!$result['code']) {
  601. $this->log('虚拟订单超期未支付关闭失败SN:' . $order_info['order_sn']);
  602. $_break = true;
  603. break;
  604. }
  605. }
  606. }
  607. /**
  608. * 订单自动完成
  609. */
  610. private function _order_auto_complete()
  611. {
  612. //虚拟订单过使用期自动完成
  613. $_break = false;
  614. $vrorder_model = model('vrorder');
  615. $logic_vrorder = model('vrorder', 'logic');
  616. $condition = [];
  617. $condition[] = ['order_state', '=', ORDER_STATE_PAY];
  618. $condition[] = ['vr_indate', '<', TIMESTAMP];
  619. //分批,每批处理100个订单,最多处理5W个订单
  620. for ($i = 0; $i < 500; $i++) {
  621. if ($_break) {
  622. break;
  623. }
  624. $order_list = $vrorder_model->getVrorderList($condition, '', 'order_id,order_sn', 'vr_indate asc', 100);
  625. if (empty($order_list))
  626. break;
  627. foreach ($order_list as $order_info) {
  628. $result = $logic_vrorder->changeOrderStateSuccess($order_info['order_id']);
  629. if (!$result['code']) {
  630. $this->log('虚拟订单过使用期自动完成失败SN:' . $order_info['order_sn']);
  631. $_break = true;
  632. break;
  633. }
  634. }
  635. }
  636. //实物订单发货后,超期自动收货完成
  637. $_break = false;
  638. $order_model = model('order');
  639. $logic_order = model('order', 'logic');
  640. $condition = [];
  641. $condition[] = ['order_state', '=', ORDER_STATE_SEND];
  642. $condition[] = ['lock_state', '=', 0];
  643. $condition[] = ['delay_time', '<', TIMESTAMP - config('ds_config.order_auto_receive_day') * 86400];
  644. //分批,每批处理100个订单,最多处理5W个订单
  645. for ($i = 0; $i < 500; $i++) {
  646. if ($_break) {
  647. break;
  648. }
  649. $order_list = $order_model->getOrderList($condition, '', '*', 'delay_time asc', 100);
  650. if (empty($order_list))
  651. break;
  652. foreach ($order_list as $order_info) {
  653. $result = $logic_order->changeOrderStateReceive($order_info, 'system', '系统', '超期未收货系统自动完成订单');
  654. if (!$result['code']) {
  655. $this->log('实物订单超期未收货自动完成订单失败SN:' . $order_info['order_sn']);
  656. $_break = true;
  657. break;
  658. }
  659. }
  660. }
  661. }
  662. /**
  663. * 更新订单扩展表中收货人所在省份ID
  664. */
  665. private function _order_reciver_provinceid_update()
  666. {
  667. $order_model = model('order');
  668. $area_model = model('area');
  669. //每次最多处理5W个订单
  670. $condition = [];
  671. $condition[] = ['reciver_province_id', '=', 0];
  672. $condition[] = ['reciver_city_id', '<>', 0];
  673. for ($i = 0; $i < 500; $i++) {
  674. $order_list = $order_model->getOrdercommonList($condition, 'reciver_city_id', 'order_id desc', 100);
  675. if (!empty($order_list)) {
  676. $city_ids = [];
  677. foreach ($order_list as $v) {
  678. if (!in_array($v['reciver_city_id'], $city_ids)) {
  679. $city_ids[] = $v['reciver_city_id'];
  680. }
  681. }
  682. $area_list = $area_model->getAreaList([['area_id', 'in', $city_ids]], 'area_parent_id,area_id');
  683. if (!empty($area_list)) {
  684. foreach ($area_list as $v) {
  685. $update = $order_model->editOrdercommon(['reciver_province_id' => $v['area_parent_id']], ['reciver_city_id' => $v['area_id']]);
  686. if (!$update) {
  687. $this->log('更新订单扩展表中收货人所在省份ID失败');
  688. break;
  689. }
  690. }
  691. }
  692. } else {
  693. break;
  694. }
  695. }
  696. }
  697. /**
  698. * 增加会员积分和经验值
  699. */
  700. private function _add_points()
  701. {
  702. return;
  703. $points_model = model('points');
  704. $exppoints_model = model('exppoints');
  705. //24小时之内登录的会员送积分和经验值,每次最多处理5W个会员
  706. $member_model = model('member');
  707. $condition = [];
  708. $condition[] = ['member_logintime', '>', TIMESTAMP - self::EXE_TIMES];
  709. for ($i = 0; $i < 50000; $i = $i + 100) {
  710. $member_list = $member_model->getMemberList($condition, 'member_name,member_id', 0, '', "{$i},100");
  711. if (!empty($member_list)) {
  712. foreach ($member_list as $member_info) {
  713. if (config('ds_config.points_isuse')) {
  714. $points_model->savePointslog('login', ['pl_memberid' => $member_info['member_id'], 'pl_membername' => $member_info['member_name']], true);
  715. }
  716. $exppoints_model->saveExppointslog('login', ['explog_memberid' => $member_info['member_id'], 'explog_membername' => $member_info['member_name']], true);
  717. }
  718. } else {
  719. break;
  720. }
  721. }
  722. //24小时之内注册的会员送积分,每次最多处理5W个会员
  723. if (config('ds_config.points_isuse')) {
  724. $condition = [];
  725. $condition[] = ['member_addtime', '>', TIMESTAMP - self::EXE_TIMES];
  726. for ($i = 0; $i < 50000; $i = $i + 100) {
  727. $member_list = $member_model->getMemberList($condition, 'member_name,member_id', 0, 'member_id desc', "{$i},100");
  728. if (!empty($member_list)) {
  729. foreach ($member_list as $member_info) {
  730. $points_model->savePointslog('regist', ['pl_memberid' => $member_info['member_id'], 'pl_membername' => $member_info['member_name']], true);
  731. }
  732. } else {
  733. break;
  734. }
  735. }
  736. }
  737. //24小时之内完成了实物订单送积分和经验值,每次最多处理5W个订单
  738. $order_model = model('order');
  739. $condition = [];
  740. $condition[] = ['finnshed_time', '>', TIMESTAMP - self::EXE_TIMES];
  741. for ($i = 0; $i < 50000; $i = $i + 100) {
  742. $order_list = $order_model->getOrderList($condition, '', 'buyer_name,buyer_id,order_amount,order_sn,order_id', '', "{$i},100");
  743. if (!empty($order_list)) {
  744. foreach ($order_list as $order_info) {
  745. if (config('ds_config.points_isuse')) {
  746. $points_model->savePointslog('order', ['pl_memberid' => $order_info['buyer_id'], 'pl_membername' => $order_info['buyer_name'], 'orderprice' => $order_info['order_amount'], 'order_sn' => $order_info['order_sn'], 'order_id' => $order_info['order_id']], true);
  747. }
  748. $exppoints_model->saveExppointslog('order', ['explog_memberid' => $order_info['buyer_id'], 'explog_membername' => $order_info['buyer_name'], 'orderprice' => $order_info['order_amount'], 'order_sn' => $order_info['order_sn'], 'order_id' => $order_info['order_id']], true);
  749. }
  750. } else {
  751. break;
  752. }
  753. }
  754. //24小时之内完成了实物订单送积分和经验值,每次最多处理5W个订单
  755. $vrorder_model = model('vrorder');
  756. $condition = [];
  757. $condition[] = ['finnshed_time', '>', TIMESTAMP - self::EXE_TIMES];
  758. for ($i = 0; $i < 50000; $i = $i + 100) {
  759. $order_list = $vrorder_model->getVrorderList($condition, '', 'buyer_name,buyer_id,order_amount,order_sn,order_id', '', "{$i},100");
  760. if (!empty($order_list)) {
  761. foreach ($order_list as $order_info) {
  762. if (config('ds_config.points_isuse')) {
  763. $points_model->savePointslog('order', ['pl_memberid' => $order_info['buyer_id'], 'pl_membername' => $order_info['buyer_name'], 'orderprice' => $order_info['order_amount'], 'order_sn' => $order_info['order_sn'], 'order_id' => $order_info['order_id']], true);
  764. }
  765. $exppoints_model->saveExppointslog('order', ['explog_memberid' => $order_info['buyer_id'], 'explog_membername' => $order_info['buyer_name'], 'orderprice' => $order_info['order_amount'], 'order_sn' => $order_info['order_sn'], 'order_id' => $order_info['order_id']], true);
  766. }
  767. } else {
  768. break;
  769. }
  770. }
  771. }
  772. /**
  773. * 代金券即将过期提醒
  774. */
  775. private function _voucher_will_expire()
  776. {
  777. $time_start = mktime(0, 0, 0, date("m"), date("d") + self::VOUCHER_INTERVAL, date("Y"));
  778. $time_stop = $time_start + self::EXE_TIMES - 1;
  779. $where = [];
  780. $where[] = ['voucher_enddate', '>=', $time_start];
  781. $where[] = ['voucher_enddate', '<=', $time_stop];
  782. $list = model('voucher')->getVoucherUnusedList($where);
  783. if (!empty($list)) {
  784. foreach ($list as $val) {
  785. $param = [];
  786. $param['code'] = 'voucher_will_expire';
  787. $param['member_id'] = $val['voucher_owner_id'];
  788. $param['ali_param'] = [
  789. 'indate' => date('Y-m-d H:i:s', $val['voucher_enddate']),
  790. ];
  791. $param['ten_param'] = [
  792. date('Y-m-d H:i:s', $val['voucher_enddate']),
  793. ];
  794. $param['param'] = array_merge($param['ali_param'], [
  795. 'voucher_url' => HOME_SITE_URL . '/Membervoucher/index',
  796. ]);
  797. $param['weixin_param'] = [
  798. 'url' => config('ds_config.h5_site_url') . '/member/voucher_list',
  799. 'data' => [
  800. "keyword1" => [
  801. "value" => $val['voucher_code'],
  802. "color" => "#333",
  803. ],
  804. "keyword2" => [
  805. "value" => date('Y-m-d', $val['voucher_startdate']) . '~' . date('Y-m-d', $val['voucher_enddate']),
  806. "color" => "#333",
  807. ],
  808. ],
  809. ];
  810. \mall\queue\QueueClient::push('sendMemberMsg', $param);
  811. }
  812. }
  813. }
  814. /**
  815. * 虚拟兑换码即将过期提醒
  816. */
  817. private function _vr_code_will_expire()
  818. {
  819. $time_start = mktime(0, 0, 0, date("m"), date("d") + self::VR_CODE_INTERVAL, date("Y"));
  820. $time_stop = $time_start + self::EXE_TIMES - 1;
  821. $where = [];
  822. $where[] = ['vr_indate', '>=', $time_start];
  823. $where[] = ['vr_indate', '<=', $time_stop];
  824. $list = model('vrorder')->getCodeUnusedList($where);
  825. if (!empty($list)) {
  826. foreach ($list as $val) {
  827. $param = [];
  828. $param['code'] = 'vr_code_will_expire';
  829. $param['member_id'] = $val['buyer_id'];
  830. $param['ali_param'] = [
  831. 'indate' => date('Y-m-d H:i:s', $val['vr_indate']),
  832. ];
  833. $param['ten_param'] = [
  834. date('Y-m-d H:i:s', $val['vr_indate']),
  835. ];
  836. $param['param'] = array_merge($param['ali_param'], [
  837. 'vr_order_url' => HOME_SITE_URL . '/Membervrorder/index',
  838. ]);
  839. $vrorder = model('vrorder')->getVrorderInfo(['order_id' => $val['order_id']]);
  840. $param['weixin_param'] = [
  841. 'url' => config('ds_config.h5_site_url') . '/member/vrorder_detail?order_id=' . $val['order_id'],
  842. 'data' => [
  843. "keyword1" => [
  844. "value" => (!empty($vrorder)) ? $vrorder['goods_name'] : '',
  845. "color" => "#333",
  846. ],
  847. "keyword2" => [
  848. "value" => date('Y-m-d', $val['vr_indate']),
  849. "color" => "#333",
  850. ],
  851. ],
  852. ];
  853. \mall\queue\QueueClient::push('sendMemberMsg', $param);
  854. }
  855. }
  856. }
  857. /**
  858. * 订单超期后不允许评价
  859. */
  860. private function _order_eval_expire_update()
  861. {
  862. //实物订单超期未评价自动更新状态,每次最多更新1000个订单
  863. $order_model = model('order');
  864. $condition = [];
  865. $condition[] = ['order_state', '=', ORDER_STATE_SUCCESS];
  866. $condition[] = ['evaluation_state', '=', 0];
  867. $condition[] = ['finnshed_time', '<', TIMESTAMP - self::ORDER_EVALUATE_TIME];
  868. $update = [];
  869. $update['evaluation_state'] = 2;
  870. $update = $order_model->editOrder($update, $condition, 1000);
  871. if (!$update) {
  872. $this->log('更新实物订单超期不能评价失败');
  873. }
  874. //虚拟订单超期未评价自动更新状态,每次最多更新1000个订单
  875. $vrorder_model = model('vrorder');
  876. $condition = [];
  877. $condition[] = ['order_state', '=', ORDER_STATE_SUCCESS];
  878. $condition[] = ['evaluation_state', '=', 0];
  879. $condition[] = ['use_state', '=', 1];
  880. $condition[] = ['finnshed_time', '<', TIMESTAMP - self::ORDER_EVALUATE_TIME];
  881. $update = [];
  882. $update['evaluation_state'] = 2;
  883. $update = $vrorder_model->editVrorder($update, $condition, 1000);
  884. if (!$update) {
  885. $this->log('更新虚拟订单超期不能评价失败');
  886. }
  887. }
  888. /**
  889. * 更新商品访问量(redis)
  890. */
  891. private function _goods_click_update()
  892. {
  893. $data = rcache('updateRedisDate', 'goodsClick');
  894. if (is_array($data)) {
  895. foreach ($data as $key => $val) {
  896. model('goods')->editGoodsById(['goods_click' => Db::raw('goods_click+' . $val)], $key);
  897. }
  898. }
  899. dcache('updateRedisDate', 'goodsClick');
  900. }
  901. /**
  902. * 更新商品促销到期状态(目前只有满即送)
  903. */
  904. private function _goods_promotion_state_update()
  905. {
  906. //满即送过期
  907. model('pmansong')->editExpireMansong();
  908. }
  909. /**
  910. * 商品到货通知提醒
  911. */
  912. private function _arrival_notice()
  913. {
  914. $arrivalnotice_model = model('arrivalnotice');
  915. $count = $arrivalnotice_model->getArrivalNoticeCount([]);
  916. $times = ceil($count / self::ARRIVAL_NOTICE_NUM);
  917. if ($times == 0)
  918. return false;
  919. for ($i = 0; $i <= $times; $i++) {
  920. $notice_list = $arrivalnotice_model->getArrivalNoticeList([], '*', $i . ',' . self::ARRIVAL_NOTICE_NUM);
  921. if (empty($notice_list))
  922. continue;
  923. // 查询商品是否已经上架
  924. $goodsid_array = [];
  925. foreach ($notice_list as $val) {
  926. $goodsid_array[] = $val['goods_id'];
  927. }
  928. $goodsid_array = array_unique($goodsid_array);
  929. $condition = [];
  930. $condition[] = ['goods_id', 'in', $goodsid_array];
  931. $condition[] = ['goods_storage', '>', 0];
  932. $goods_list = model('goods')->getGoodsOnlineList($condition, 'goods_id');
  933. if (empty($goods_list))
  934. continue;
  935. // 需要通知到货的商品
  936. $goodsid_array = [];
  937. $storage_array = [];
  938. foreach ($goods_list as $val) {
  939. $goodsid_array[] = $val['goods_id'];
  940. $storage_array[$val['goods_id']] = $val['goods_storage'];
  941. }
  942. // 根据商品id重新查询需要通知的列表
  943. $notice_list = $arrivalnotice_model->getArrivalNoticeList([['goods_id', 'in', $goodsid_array]], '*');
  944. if (empty($notice_list))
  945. continue;
  946. foreach ($notice_list as $val) {
  947. $param = [];
  948. $param['code'] = 'arrival_notice';
  949. $param['member_id'] = $val['member_id'];
  950. $param['ali_param'] = [
  951. 'goods_name' => $val['goods_name'],
  952. ];
  953. $param['ten_param'] = [
  954. $val['goods_name'],
  955. ];
  956. $param['param'] = array_merge([
  957. 'goods_name' => $val['goods_name'],
  958. 'goods_url' => HOME_SITE_URL . '/Goods/index?goods_id=' . $val['goods_id'],
  959. ]);
  960. $param['number'] = ['mobile' => $val['arrivalnotice_mobile'], 'email' => $val['arrivalnotice_email']];
  961. $param['weixin_param'] = [
  962. 'url' => config('ds_config.h5_site_url') . '/home/goodsdetail?goods_id=' . $val['goods_id'],
  963. 'data' => [
  964. "keyword1" => [
  965. "value" => $val['goods_name'],
  966. "color" => "#333",
  967. ],
  968. "keyword2" => [
  969. "value" => isset($storage_array[$val['goods_id']]) ? $storage_array[$val['goods_id']] : '99',
  970. "color" => "#333",
  971. ],
  972. "keyword3" => [
  973. "value" => date('Y-m-d'),
  974. "color" => "#333",
  975. ],
  976. ],
  977. ];
  978. \mall\queue\QueueClient::push('sendMemberMsg', $param);
  979. }
  980. // 清楚发送成功的数据
  981. $arrivalnotice_model->editArrivalNotice(['arrivalnotice_state' => 2, 'arrivalnotice_time' => TIMESTAMP], [['goods_id', 'in', $goodsid_array]]);
  982. }
  983. }
  984. /**
  985. * 将缓存中的浏览记录存入数据库中,并删除30天前的浏览历史
  986. */
  987. private function _goods_browse_update()
  988. {
  989. $goodsbrowse_model = model('goodsbrowse');
  990. //将cache中的记录存入数据库
  991. //如果浏览记录已经存入了缓存中,则将其整理到数据库中
  992. //上次更新缓存的时间
  993. $latest_record = $goodsbrowse_model->getOneGoodsbrowse([], '', 'goodsbrowse_time desc');
  994. $starttime = ($t = intval($latest_record['goodsbrowse_time'])) ? $t : 0;
  995. $monthago = strtotime(date('Y-m-d', TIMESTAMP)) - 86400 * 30;
  996. $member_model = model('member');
  997. //查询会员信息总条数
  998. $countnum = $member_model->getMemberCount([]);
  999. $eachnum = 100;
  1000. for ($i = 0; $i < $countnum; $i += $eachnum) {//每次查询100条
  1001. $member_list = $member_model->getMemberList([], '*', 0, 'member_id asc', "$i,$eachnum");
  1002. foreach ((array)$member_list as $k => $v) {
  1003. $insert_arr = [];
  1004. $goodsid_arr = [];
  1005. //生成缓存的键值
  1006. $hash_key = $v['member_id'];
  1007. $browse_goodsid = rcache($hash_key, 'goodsbrowse');
  1008. if ($browse_goodsid) {
  1009. //删除缓存中多余的浏览历史记录,仅保留最近的30条浏览历史,先取出最近30条浏览历史的商品ID
  1010. $cachegoodsid_arr = $browse_goodsid['goodsid'] ? unserialize($browse_goodsid['goodsid']) : [];
  1011. unset($browse_goodsid['goodsid']);
  1012. if ($cachegoodsid_arr) {
  1013. $cachegoodsid_arr = array_slice($cachegoodsid_arr, -30, 30, true);
  1014. }
  1015. //处理存入数据库的浏览历史缓存信息
  1016. $_cache = rcache($hash_key, 'goodsbrowse');
  1017. foreach ((array)$_cache as $c_k => $c_v) {
  1018. $c_v = unserialize($c_v);
  1019. if (isset($c_v['goodsbrowse_time']) && $c_v['goodsbrowse_time'] >= $starttime) {//如果 缓存中的数据未更新到数据库中(即添加时间大于上次更新到数据库中的数据时间)则将数据更新到数据库中
  1020. $tmp_arr = [];
  1021. $tmp_arr['goods_id'] = $c_v['goods_id'];
  1022. $tmp_arr['member_id'] = $v['member_id'];
  1023. $tmp_arr['goodsbrowse_time'] = $c_v['goodsbrowse_time'];
  1024. $tmp_arr['gc_id'] = $c_v['gc_id'];
  1025. $tmp_arr['gc_id_1'] = $c_v['gc_id_1'];
  1026. $tmp_arr['gc_id_2'] = $c_v['gc_id_2'];
  1027. $tmp_arr['gc_id_3'] = $c_v['gc_id_3'];
  1028. $insert_arr[] = $tmp_arr;
  1029. $goodsid_arr[] = $c_v['goods_id'];
  1030. }
  1031. //除了最近的30条浏览历史之外多余的浏览历史记录或者30天之前的浏览历史从缓存中删除
  1032. if (!in_array($c_v['goods_id'], $cachegoodsid_arr) || $c_v['goodsbrowse_time'] < $monthago) {
  1033. unset($_cache[$c_k]);
  1034. }
  1035. }
  1036. //删除已经存在的该商品浏览记录
  1037. if ($goodsid_arr) {
  1038. $condition = [];
  1039. $condition[] = ['member_id', '=', $v['member_id']];
  1040. $condition[] = ['goods_id', 'in', $goodsid_arr];
  1041. $goodsbrowse_model->delGoodsbrowse($condition);
  1042. }
  1043. //将缓存中的浏览历史存入数据库
  1044. if ($insert_arr) {
  1045. $goodsbrowse_model->addGoodsbrowseAll($insert_arr);
  1046. }
  1047. //重新赋值浏览历史缓存
  1048. dcache($hash_key, 'goodsbrowse');
  1049. $_cache['goodsid'] = serialize($cachegoodsid_arr);
  1050. wcache($hash_key, $_cache, 'goodsbrowse');
  1051. }
  1052. }
  1053. }
  1054. //删除30天前的浏览历史
  1055. $goodsbrowse_model->delGoodsbrowse([['goodsbrowse_time', '<', $monthago]]);
  1056. }
  1057. /**
  1058. * 缓存订单及订单商品相关数据
  1059. */
  1060. private function _order_goods_cache()
  1061. {
  1062. //查询最后统计的记录
  1063. $latest_record = Db::name('statordergoods')->order('stat_updatetime desc,rec_id desc')->find();
  1064. $stime = 0;
  1065. if ($latest_record) {
  1066. $start_time = strtotime(date('Y-m-d', $latest_record['stat_updatetime']));
  1067. } else {
  1068. $start_time = strtotime(date('Y-m-d', strtotime(config('ds_config.setup_date')))); //从系统的安装时间开始统计
  1069. }
  1070. for ($stime = $start_time; $stime < TIMESTAMP; $stime = $stime + 86400) {
  1071. $etime = $stime + 86400 - 1;
  1072. //避免重复统计,开始时间必须大于最后一条记录的记录时间
  1073. $search_stime = $latest_record['stat_updatetime'] > $stime ? $latest_record['stat_updatetime'] : $stime;
  1074. //统计一天的数据,如果结束时间大于当前时间,则结束时间为当前时间,避免因为查询时间的延迟造成数据遗落
  1075. $search_etime = ($t = ($stime + 86400 - 1)) > TIMESTAMP ? TIMESTAMP : ($stime + 86400 - 1);
  1076. //查询时间段内新订单或者更新过的订单,在缓存表中需要将新订单和更新过的订单进行重新缓存
  1077. $where = [];
  1078. $where[] = ['log_time', 'between', [$search_stime, $search_etime]];
  1079. //查询记录总条数
  1080. $countnum_arr = Db::name('orderlog')->field('COUNT(DISTINCT order_id) as countnum')->where($where)->find();
  1081. $countnum = intval($countnum_arr['countnum']);
  1082. for ($i = 0; $i < $countnum; $i += 100) {//每次查询100条
  1083. $orderlog_list = [];
  1084. $orderlog_list = Db::name('orderlog')->field('DISTINCT order_id')->where($where)->limit($i . ',100')->select()->toArray();
  1085. if ($orderlog_list) {
  1086. //店铺ID数组
  1087. $storeid_arr = [];
  1088. //商品ID数组
  1089. $goodsid_arr = [];
  1090. //商品公共表ID数组
  1091. $goods_commonid_arr = [];
  1092. //订单ID数组
  1093. $orderid_arr = [];
  1094. //整理需要缓存的订单ID
  1095. foreach ((array)$orderlog_list as $k => $v) {
  1096. $orderid_arr[] = $v['order_id'];
  1097. }
  1098. unset($orderlog_list);
  1099. //查询订单数据
  1100. $field = 'order_id,order_sn,store_id,buyer_id,buyer_name,add_time,payment_code,order_amount,shipping_fee,evaluation_state,order_state,refund_state,refund_amount,order_from';
  1101. $order_list_tmp = Db::name('order')->field($field)->where('order_id', 'in', $orderid_arr)->select()->toArray();
  1102. $order_list = [];
  1103. foreach ((array)$order_list_tmp as $k => $v) {
  1104. //判读订单是否计入统计(在线支付订单已支付或者经过退款的取消订单或者货到付款订单订单已成功)
  1105. $v['order_isvalid'] = 0;
  1106. if ($v['payment_code'] != 'offline' && $v['order_state'] != ORDER_STATE_NEW && $v['order_state'] != ORDER_STATE_CANCEL) {//在线支付并且已支付并且未取消
  1107. $v['order_isvalid'] = 1;
  1108. } elseif ($v['order_state'] == ORDER_STATE_CANCEL && $v['refund_state'] != 0) {//经过退款的取消订单
  1109. $v['order_isvalid'] = 1;
  1110. } elseif ($v['payment_code'] == 'offline' && $v['order_state'] == ORDER_STATE_SUCCESS) {//货到付款订单,订单成功之后才计入统计
  1111. $v['order_isvalid'] = 1;
  1112. }
  1113. $order_list[$v['order_id']] = $v;
  1114. $storeid_arr[] = $v['store_id'];
  1115. }
  1116. unset($order_list_tmp);
  1117. //查询订单扩展数据
  1118. $field = 'order_id,reciver_province_id';
  1119. $order_common_list_tmp = Db::name('ordercommon')->field($field)->where('order_id', 'in', $orderid_arr)->select()->toArray();
  1120. $order_common_list = [];
  1121. foreach ((array)$order_common_list_tmp as $k => $v) {
  1122. $order_common_list[$v['order_id']] = $v;
  1123. }
  1124. unset($order_common_list_tmp);
  1125. //查询店铺信息
  1126. $field = 'store_id,store_name,grade_id,storeclass_id';
  1127. $store_list_tmp = Db::name('store')->field($field)->where('store_id', 'in', $storeid_arr)->select()->toArray();
  1128. $store_list = [];
  1129. foreach ((array)$store_list_tmp as $k => $v) {
  1130. $store_list[$v['store_id']] = $v;
  1131. }
  1132. unset($store_list_tmp);
  1133. //查询订单商品
  1134. $field = 'rec_id,order_id,goods_id,goods_name,goods_price,goods_num,goods_image,goods_pay_price,store_id,buyer_id,goods_type,promotions_id,commis_rate,gc_id';
  1135. $ordergoods_list = Db::name('ordergoods')->field($field)->where('order_id', 'in', $orderid_arr)->select()->toArray();
  1136. foreach ((array)$ordergoods_list as $k => $v) {
  1137. $goodsid_arr[] = $v['goods_id'];
  1138. }
  1139. //查询商品信息
  1140. $field = 'goods_id,goods_commonid,goods_price,goods_serial,gc_id,gc_id_1,gc_id_2,gc_id_3,goods_image';
  1141. $goods_list_tmp = Db::name('goods')->field($field)->where('goods_id', 'in', $goodsid_arr)->select()->toArray();
  1142. foreach ((array)$goods_list_tmp as $k => $v) {
  1143. $goods_commonid_arr[] = $v['goods_commonid'];
  1144. }
  1145. //查询商品公共信息
  1146. $field = 'goods_commonid,goods_name,brand_id,brand_name';
  1147. $goods_common_list_tmp = Db::name('goodscommon')->field($field)->where('goods_commonid', 'in', $goods_commonid_arr)->select()->toArray();
  1148. $goods_common_list = [];
  1149. foreach ((array)$goods_common_list_tmp as $k => $v) {
  1150. $goods_common_list[$v['goods_commonid']] = $v;
  1151. }
  1152. unset($goods_common_list_tmp);
  1153. //处理商品数组
  1154. $goods_list = [];
  1155. foreach ((array)$goods_list_tmp as $k => $v) {
  1156. $v['goods_commonname'] = $goods_common_list[$v['goods_commonid']]['goods_name'];
  1157. $v['brand_id'] = $goods_common_list[$v['goods_commonid']]['brand_id'];
  1158. $v['brand_name'] = $goods_common_list[$v['goods_commonid']]['brand_name'];
  1159. $goods_list[$v['goods_id']] = $v;
  1160. }
  1161. unset($goods_list_tmp);
  1162. //查询订单缓存是否存在,存在则删除
  1163. Db::name('statordergoods')->where('order_id', 'in', $orderid_arr)->delete();
  1164. //查询订单缓存是否存在,存在则删除
  1165. Db::name('statorder')->where('order_id', 'in', $orderid_arr)->delete();
  1166. //整理新增数据
  1167. $ordergoods_insert_arr = [];
  1168. foreach ((array)$ordergoods_list as $k => $v) {
  1169. $tmp = [];
  1170. $tmp['rec_id'] = $v['rec_id'];
  1171. $tmp['stat_updatetime'] = $search_etime;
  1172. $tmp['order_id'] = $v['order_id'];
  1173. $tmp['order_sn'] = $order_list[$v['order_id']]['order_sn'];
  1174. $tmp['order_add_time'] = $order_list[$v['order_id']]['add_time'];
  1175. $tmp['payment_code'] = $order_list[$v['order_id']]['payment_code'];
  1176. $tmp['order_amount'] = $order_list[$v['order_id']]['order_amount'];
  1177. $tmp['shipping_fee'] = $order_list[$v['order_id']]['shipping_fee'];
  1178. $tmp['evaluation_state'] = (string)$order_list[$v['order_id']]['evaluation_state'];
  1179. $tmp['order_state'] = (string)$order_list[$v['order_id']]['order_state'];
  1180. $tmp['refund_state'] = $order_list[$v['order_id']]['refund_state'];
  1181. $tmp['refund_amount'] = $order_list[$v['order_id']]['refund_amount'];
  1182. $tmp['order_from'] = $order_list[$v['order_id']]['order_from'];
  1183. $tmp['order_isvalid'] = $order_list[$v['order_id']]['order_isvalid'];
  1184. $tmp['reciver_province_id'] = $order_common_list[$v['order_id']]['reciver_province_id'];
  1185. $tmp['store_id'] = $v['store_id'];
  1186. $tmp['store_name'] = $store_list[$v['store_id']]['store_name'];
  1187. $tmp['grade_id'] = $store_list[$v['store_id']]['grade_id'];
  1188. $tmp['storeclass_id'] = $store_list[$v['store_id']]['storeclass_id'];
  1189. $tmp['buyer_id'] = $order_list[$v['order_id']]['buyer_id'];
  1190. $tmp['buyer_name'] = $order_list[$v['order_id']]['buyer_name'];
  1191. $tmp['goods_id'] = $v['goods_id'];
  1192. $tmp['goods_name'] = $v['goods_name'];
  1193. $tmp['goods_commonid'] = intval($goods_list[$v['goods_id']]['goods_commonid']);
  1194. $tmp['goods_commonname'] = ($t = $goods_list[$v['goods_id']]['goods_commonname']) ? $t : '';
  1195. $tmp['gc_id'] = intval($goods_list[$v['goods_id']]['gc_id']);
  1196. $tmp['gc_parentid_1'] = intval($goods_list[$v['goods_id']]['gc_id_1']);
  1197. $tmp['gc_parentid_2'] = intval($goods_list[$v['goods_id']]['gc_id_2']);
  1198. $tmp['gc_parentid_3'] = intval($goods_list[$v['goods_id']]['gc_id_3']);
  1199. $tmp['brand_id'] = intval($goods_list[$v['goods_id']]['brand_id']);
  1200. $tmp['brand_name'] = ($t = $goods_list[$v['goods_id']]['brand_name']) ? $t : '';
  1201. $tmp['goods_serial'] = ($t = $goods_list[$v['goods_id']]['goods_serial']) ? $t : '';
  1202. $tmp['goods_price'] = $v['goods_price'];
  1203. $tmp['goods_num'] = $v['goods_num'];
  1204. $tmp['goods_image'] = $goods_list[$v['goods_id']]['goods_image'];
  1205. $tmp['goods_pay_price'] = $v['goods_pay_price'];
  1206. $tmp['goods_type'] = $v['goods_type'];
  1207. $tmp['promotions_id'] = $v['promotions_id'];
  1208. $tmp['commis_rate'] = $v['commis_rate'];
  1209. $ordergoods_insert_arr[] = $tmp;
  1210. }
  1211. Db::name('statordergoods')->insertAll($ordergoods_insert_arr);
  1212. $order_insert_arr = [];
  1213. foreach ((array)$order_list as $k => $v) {
  1214. $tmp = [];
  1215. $tmp['order_id'] = $v['order_id'];
  1216. $tmp['order_sn'] = $v['order_sn'];
  1217. $tmp['order_add_time'] = $v['add_time'];
  1218. $tmp['payment_code'] = $v['payment_code'];
  1219. $tmp['order_amount'] = $v['order_amount'];
  1220. $tmp['shipping_fee'] = $v['shipping_fee'];
  1221. $tmp['evaluation_state'] = (string)$v['evaluation_state'];
  1222. $tmp['order_state'] = (string)$v['order_state'];
  1223. $tmp['refund_state'] = $v['refund_state'];
  1224. $tmp['refund_amount'] = $v['refund_amount'];
  1225. $tmp['order_from'] = $v['order_from'];
  1226. $tmp['order_isvalid'] = $v['order_isvalid'];
  1227. $tmp['reciver_province_id'] = $order_common_list[$v['order_id']]['reciver_province_id'];
  1228. $tmp['store_id'] = $v['store_id'];
  1229. $tmp['store_name'] = $store_list[$v['store_id']]['store_name'];
  1230. $tmp['grade_id'] = $store_list[$v['store_id']]['grade_id'];
  1231. $tmp['storeclass_id'] = $store_list[$v['store_id']]['storeclass_id'];
  1232. $tmp['buyer_id'] = $v['buyer_id'];
  1233. $tmp['buyer_name'] = $v['buyer_name'];
  1234. $order_insert_arr[] = $tmp;
  1235. }
  1236. Db::name('statorder')->insertAll($order_insert_arr);
  1237. }
  1238. }
  1239. }
  1240. }
  1241. /**
  1242. * 会员相关数据统计
  1243. */
  1244. private function _member_stat()
  1245. {
  1246. $stat_model = model('stat');
  1247. //查询最后统计的记录
  1248. $latest_record = $stat_model->getOneStatmember([], '', 'statm_id desc');
  1249. $stime = 0;
  1250. if ($latest_record) {
  1251. $start_time = strtotime(date('Y-m-d', $latest_record['statm_updatetime']));
  1252. } else {
  1253. $start_time = strtotime(date('Y-m-d', strtotime(config('ds_config.setup_date')))); //从系统的安装时间开始统计
  1254. }
  1255. $j = 1;
  1256. for ($stime = $start_time; $stime < TIMESTAMP; $stime = $stime + 86400) {
  1257. //数据库更新数据数组
  1258. $insert_arr = [];
  1259. $update_arr = [];
  1260. $etime = $stime + 86400 - 1;
  1261. //避免重复统计,开始时间必须大于最后一条记录的记录时间
  1262. $search_stime = $latest_record['statm_updatetime'] > $stime ? $latest_record['statm_updatetime'] : $stime;
  1263. //统计一天的数据,如果结束时间大于当前时间,则结束时间为当前时间,避免因为查询时间的延迟造成数据遗落
  1264. $search_etime = ($t = ($stime + 86400 - 1)) > TIMESTAMP ? TIMESTAMP : ($stime + 86400 - 1);
  1265. //统计订单下单量和下单金额
  1266. $field = ' order.order_id,add_time,buyer_id,buyer_name,order_amount';
  1267. $where = [];
  1268. $where[] = ['order.order_state', '<>', ORDER_STATE_NEW]; //去除未支付订单
  1269. $where[] = ['order.refund_state', '<>', "0"]; //没有参与退款的取消订单,不记录到统计中
  1270. $where[] = ['orderlog.log_time', 'between', [$search_stime, $search_etime]]; //按照订单付款的操作时间统计
  1271. //货到付款当交易成功进入统计,非货到付款当付款后进入统计
  1272. $where = "(order.payment_code='offline' and orderlog.log_orderstate = '" . ORDER_STATE_SUCCESS . "') or (order.payment_code<>'offline' and orderlog.log_orderstate = '" . ORDER_STATE_PAY . "' )";
  1273. $orderlist_tmp = $stat_model->statByOrderLog($where, $field, 0, 0, 'order_id'); //此处由于底层的限制,仅能查询1000条,如果日下单量大于1000,则需要limit的支持
  1274. $order_list = [];
  1275. $orderid_list = [];
  1276. foreach ((array)$orderlist_tmp as $k => $v) {
  1277. $addtime = strtotime(date('Y-m-d', $v['add_time']));
  1278. if ($addtime != $stime) {//订单如果隔天支付的话,需要进行统计数据更新
  1279. $update_arr[$addtime][$v['buyer_id']]['statm_membername'] = $v['buyer_name'];
  1280. $update_arr[$addtime][$v['buyer_id']]['statm_ordernum'] = intval($update_arr[$addtime][$v['buyer_id']]['statm_ordernum']) + 1;
  1281. $update_arr[$addtime][$v['buyer_id']]['statm_orderamount'] = floatval($update_arr[$addtime][$v['buyer_id']]['statm_orderamount']) + (($t = floatval($v['order_amount'])) > 0 ? $t : 0);
  1282. } else {
  1283. $order_list[$v['buyer_id']]['buyer_name'] = $v['buyer_name'];
  1284. $order_list[$v['buyer_id']]['ordernum'] = intval($order_list[$v['buyer_id']]['ordernum']) + 1;
  1285. $order_list[$v['buyer_id']]['orderamount'] = floatval($order_list[$v['buyer_id']]['orderamount']) + (($t = floatval($v['order_amount'])) > 0 ? $t : 0);
  1286. }
  1287. //记录订单ID数组
  1288. $orderid_list[] = $v['order_id'];
  1289. }
  1290. //统计下单商品件数
  1291. if ($orderid_list) {
  1292. $field = ' add_time,order.buyer_id,order.buyer_name,goods_num ';
  1293. $where = [];
  1294. $where[] = ['order.order_id', 'in', $orderid_list];
  1295. $ordergoods_tmp = $stat_model->statByOrderGoods($where, $field, 0, 0, 'order.order_id');
  1296. $ordergoods_list = [];
  1297. foreach ((array)$ordergoods_tmp as $k => $v) {
  1298. $addtime = strtotime(date('Y-m-d', $v['add_time']));
  1299. if ($addtime != $stime) {//订单如果隔天支付的话,需要进行统计数据更新
  1300. $update_arr[$addtime][$v['buyer_id']]['statm_goodsnum'] = intval($update_arr[$addtime][$v['buyer_id']]['statm_goodsnum']) + (($t = floatval($v['goods_num'])) > 0 ? $t : 0);
  1301. } else {
  1302. $ordergoods_list[$v['buyer_id']]['goodsnum'] = $ordergoods_list[$v['buyer_id']]['goodsnum'] + (($t = floatval($v['goods_num'])) > 0 ? $t : 0);
  1303. }
  1304. }
  1305. }
  1306. //统计的预存款记录
  1307. $field = ' lg_member_id,lg_member_name,lg_av_amount as predincrease, lg_av_amount as predreduce ';
  1308. $where = [];
  1309. $where[] = ['lg_addtime', 'between', [$stime, $etime]];
  1310. $predeposit_tmp = $stat_model->getPredepositInfo($where, $field, 0, 'lg_member_id', 0, 'lg_member_id');
  1311. $predeposit_list = [];
  1312. foreach ((array)$predeposit_tmp as $k => $v) {
  1313. $predeposit_list[$v['lg_member_id']] = $v;
  1314. }
  1315. //统计的积分记录
  1316. $field = ' pl_memberid,pl_membername,pl_points as pointsincrease, pl_points as pointsreduce ';
  1317. $where = [];
  1318. $where[] = ['pl_addtime', 'between', [$stime, $etime]];
  1319. $points_tmp = $stat_model->statByPointslog($where, $field, 0, 0, '', 'pl_memberid');
  1320. $points_list = [];
  1321. foreach ((array)$points_tmp as $k => $v) {
  1322. $points_list[$v['pl_memberid']] = $v;
  1323. }
  1324. //处理需要更新的数据
  1325. foreach ((array)$update_arr as $k => $v) {
  1326. foreach ($v as $m_k => $m_v) {
  1327. //查询记录是否存在
  1328. $statmember_info = $stat_model->getOneStatmember(['statm_time' => $k, 'statm_memberid' => $m_k]);
  1329. if ($statmember_info) {
  1330. $m_v['statm_ordernum'] = intval($statmember_info['statm_ordernum']) + $m_v['statm_ordernum'];
  1331. $m_v['statm_orderamount'] = floatval($statmember_info['statm_ordernum']) + $m_v['statm_orderamount'];
  1332. $m_v['statm_updatetime'] = $search_etime;
  1333. $stat_model->editStatmember(['statm_time' => $k, 'statm_memberid' => $m_k], $m_v);
  1334. } else {
  1335. $tmp = [];
  1336. $tmp['statm_memberid'] = $m_k;
  1337. $tmp['statm_membername'] = $m_v['statm_membername'];
  1338. $tmp['statm_time'] = $k;
  1339. $tmp['statm_updatetime'] = $search_etime;
  1340. $tmp['statm_ordernum'] = ($t = intval($m_v['statm_ordernum'])) > 0 ? $t : 0;
  1341. $tmp['statm_orderamount'] = ($t = floatval($m_v['statm_orderamount'])) > 0 ? $t : 0;
  1342. $tmp['statm_goodsnum'] = ($t = intval($m_v['statm_goodsnum'])) ? $t : 0;
  1343. $tmp['statm_predincrease'] = 0;
  1344. $tmp['statm_predreduce'] = 0;
  1345. $tmp['statm_pointsincrease'] = 0;
  1346. $tmp['statm_pointsreduce'] = 0;
  1347. $insert_arr[] = $tmp;
  1348. }
  1349. unset($statmember_info);
  1350. }
  1351. }
  1352. //处理获得所有会员ID数组
  1353. $memberidarr_order = isset($order_list) ? array_keys($order_list) : [];
  1354. $memberidarr_ordergoods = isset($ordergoods_list) ? array_keys($ordergoods_list) : [];
  1355. $memberidarr_predeposit = isset($predeposit_list) ? array_keys($predeposit_list) : [];
  1356. $memberidarr_points = isset($points_list) ? array_keys($points_list) : [];
  1357. $memberid_arr = array_merge($memberidarr_order, $memberidarr_ordergoods, $memberidarr_predeposit, $memberidarr_points);
  1358. //查询会员信息
  1359. $memberid_list = model('member')->getMemberList([['member_id', 'in', $memberid_arr]], '', 0);
  1360. //查询记录是否存在
  1361. $statmemberlist_tmp = $stat_model->statByStatmember(['statm_time' => $stime]);
  1362. $statmemberlist = [];
  1363. foreach ((array)$statmemberlist_tmp as $k => $v) {
  1364. $statmemberlist[$v['statm_memberid']] = $v;
  1365. }
  1366. foreach ((array)$memberid_list as $k => $v) {
  1367. $tmp = [];
  1368. $tmp['statm_memberid'] = $v['member_id'];
  1369. $tmp['statm_membername'] = $v['member_name'];
  1370. $tmp['statm_time'] = $stime;
  1371. $tmp['statm_updatetime'] = $search_etime;
  1372. //因为记录可能已经存在,所以加上之前的统计记录
  1373. $statmemberlist[$tmp['statm_memberid']] = isset($statmemberlist[$tmp['statm_memberid']]) ? $statmemberlist[$tmp['statm_memberid']] : 0;
  1374. $order_list[$tmp['statm_memberid']] = isset($order_list[$tmp['statm_memberid']]) ? $order_list[$tmp['statm_memberid']] : 0;
  1375. $ordergoods_list[$tmp['statm_memberid']] = isset($ordergoods_list[$tmp['statm_memberid']]) ? $ordergoods_list[$tmp['statm_memberid']] : 0;
  1376. $predeposit_list[$tmp['statm_memberid']] = isset($predeposit_list[$tmp['statm_memberid']]) ? $predeposit_list[$tmp['statm_memberid']] : 0;
  1377. $tmp['statm_ordernum'] = intval($statmemberlist[$tmp['statm_memberid']]['statm_ordernum']) + (($t = intval($order_list[$tmp['statm_memberid']]['ordernum'])) > 0 ? $t : 0);
  1378. $tmp['statm_orderamount'] = floatval($statmemberlist[$tmp['statm_memberid']]['statm_orderamount']) + (($t = floatval($order_list[$tmp['statm_memberid']]['orderamount'])) > 0 ? $t : 0);
  1379. $tmp['statm_goodsnum'] = intval($statmemberlist[$tmp['statm_memberid']]['statm_goodsnum']) + (($t = intval($ordergoods_list[$tmp['statm_memberid']]['goodsnum'])) ? $t : 0);
  1380. $tmp['statm_predincrease'] = (($t = floatval($predeposit_list[$tmp['statm_memberid']]['predincrease'])) ? $t : 0);
  1381. $tmp['statm_predreduce'] = (($t = floatval($predeposit_list[$tmp['statm_memberid']]['predreduce'])) ? $t : 0);
  1382. $tmp['statm_pointsincrease'] = (($t = intval($points_list[$tmp['statm_memberid']]['pointsincrease'])) ? $t : 0);
  1383. $tmp['statm_pointsreduce'] = (($t = intval($points_list[$tmp['statm_memberid']]['pointsreduce'])) ? $t : 0);
  1384. $insert_arr[] = $tmp;
  1385. }
  1386. //删除旧的统计数据
  1387. $stat_model->delByStatmember(['statm_time' => $stime]);
  1388. Db::name('statmember')->insertAll($insert_arr);
  1389. }
  1390. }
  1391. /**
  1392. * 实物订单已付款24小时未发货,增加短信提醒
  1393. */
  1394. private function _order_timeout_no_translate()
  1395. {
  1396. //获取超时订单
  1397. $out_time = TIMESTAMP - (60 * 60 * 24);
  1398. $order_list = Db::name('order')
  1399. ->where('order_state', 20)
  1400. ->where('payment_time', '<', $out_time)
  1401. ->where('timeout_no_translate_message', 0)
  1402. ->select();
  1403. //获取店铺信息
  1404. $store_ids = [];
  1405. foreach ($order_list as $v) {
  1406. $store_ids[] = $v['store_id'];
  1407. }
  1408. $store_list = Db::name('store')->where('store_id', 'in', $store_ids)->column('store_phone', 'store_id');
  1409. //发送短信
  1410. $smslog_model = model('smslog');
  1411. $storemsg_model = model('storemsg');
  1412. foreach ($order_list as $v) {
  1413. $store_phone = $store_list[$v['store_id']];
  1414. if (!empty($store_phone)) {
  1415. $smslog_model->sendSms($store_phone, ['message' => '福利商城有订单已超过24小时未发货,订单号:' . $v['order_sn'] . '请及时发货']);
  1416. }
  1417. Db::name('order')->where('order_id', $v['order_id'])->update(['timeout_no_translate_message' => 1]);
  1418. $storemsg_model->addStoremsg([
  1419. 'storemt_code' => 'timeout_no_translate',
  1420. 'store_id' => $v['store_id'],
  1421. 'storemsg_content' => '福利商城有订单已超过24小时未发货,订单号:' . $v['order_sn'] . '请及时发货',
  1422. ]);
  1423. }
  1424. }
  1425. }