OtherOrderServices.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2020 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace app\services\order;
  12. use app\dao\order\OtherOrderDao;
  13. use app\services\BaseServices;
  14. use app\services\pay\PayServices;
  15. use app\services\user\MemberShipServices;
  16. use app\services\user\UserBillServices;
  17. use app\services\user\UserServices;
  18. use app\services\user\MemberCardServices;
  19. use think\App;
  20. use app\jobs\OtherOrderJob;
  21. use think\exception\ValidateException;
  22. /**
  23. * Class OtherOrderServices
  24. * @package app\services\order
  25. * @method getDistinctCount(array $where, $field, ?bool $search = true)
  26. * @method getPayUserCount(int $time, string $channel_type)
  27. * @method getTrendData($time, $type, $timeType)
  28. */
  29. class OtherOrderServices extends BaseServices
  30. {
  31. /**
  32. * 初始化,获得dao层句柄
  33. * OtherOrderServices constructor.
  34. * @param OtherOrderDao $dao
  35. */
  36. public function __construct(OtherOrderDao $dao)
  37. {
  38. $this->dao = $dao;
  39. }
  40. /**
  41. * 生成会员购买订单数据
  42. * @param array $data
  43. * @return mixed
  44. */
  45. public function addOtherOrderData(array $data)
  46. {
  47. if (!$data) throw new ValidateException('数据不能为空');
  48. $add = [
  49. 'uid' => $data['uid'],
  50. 'type' => isset($data['type']) ? $data['type'] : 1,
  51. 'order_id' => $data['order_id'],
  52. 'channel_type' => $data['channel_type'],
  53. 'pay_type' => isset($data['pay_type']) ? $data['pay_type'] : 0,
  54. 'member_type' => isset($data['member_type']) ? $data['member_type'] : 0,
  55. 'member_price' => isset($data['member_price']) ? $data['member_price'] : 0.00,
  56. 'pay_price' => isset($data['pay_price']) ? $data['pay_price'] : 0.00,
  57. 'code' => isset($data['member_code']) ? $data['member_code'] : "",
  58. 'vip_day' => isset($data['vip_day']) ? $data['vip_day'] : 0,
  59. 'is_permanent' => isset($data['is_permanent']) ? $data['is_permanent'] : 0,
  60. 'is_free' => isset($data['is_free']) ? $data['is_free'] : 0,
  61. 'overdue_time' => isset($data['overdue_time']) ? $data['overdue_time'] : 0,
  62. 'status' => 0,
  63. 'paid' => isset($data['paid']) ? $data['paid'] : 0,
  64. 'pay_time' => isset($data['pay_time']) ? $data['pay_time'] : 0,
  65. 'money' => isset($data['money']) ? $data['money'] : 0,
  66. 'add_time' => time(),
  67. ];
  68. return $this->dao->save($add);
  69. }
  70. /**
  71. * 能否领取免费
  72. * @param int $uid
  73. * @return array
  74. * @throws \think\db\exception\DataNotFoundException
  75. * @throws \think\db\exception\DbException
  76. * @throws \think\db\exception\ModelNotFoundException
  77. */
  78. public function isCanGetFree(int $uid)
  79. {
  80. /** @var UserServices $userService */
  81. $userService = app()->make(UserServices::class);
  82. /** @var MemberShipServices $memberShipService */
  83. $memberShipService = app()->make(MemberShipServices::class);
  84. /** @var StoreOrderEconomizeServices $economizeService */
  85. $economizeService = app()->make(StoreOrderEconomizeServices::class);
  86. $freeDay = $memberShipService->getVipDay(['type' => "free"]);
  87. $freeConfig = array();
  88. $freeConfig['price'] = 0;
  89. $freeConfig['pre_price'] = 0;
  90. $freeConfig['title'] = "免费会员";
  91. $freeConfig['type'] = "free";
  92. $freeConfig['vip_day'] = $freeDay ? $freeDay : 0;
  93. $userInfo = $userService->get($uid);
  94. if ($freeConfig) {
  95. $freeConfig['is_record'] = 0;
  96. $record = $this->dao->getOneByWhere(['uid' => $uid, 'is_free' => 1]);
  97. if ($record) {
  98. $freeConfig['is_record'] = 1;
  99. }
  100. }
  101. $registerTime = $this->TimeConvert(['start_time' => date('Y-m-d H:i:s', $userInfo['add_time']), 'end_time' => date('Y-m-d H:i:s', time())]);
  102. $userInfo['register_days'] = $registerTime['days'];
  103. $userInfo['economize_money'] = $economizeService->sumEconomizeMoney($uid);
  104. $userInfo['shop_name'] = sys_config('site_name');
  105. $freeConfig['user_info'] = $userInfo;
  106. return $freeConfig;
  107. }
  108. /**搜索时间转换
  109. * @param $timeKey
  110. * @param bool $isNum
  111. * @throws \Exception
  112. */
  113. public function TimeConvert($timeKey, $isNum = false)
  114. {
  115. switch ($timeKey) {
  116. case "today" :
  117. $data['start_time'] = date('Y-m-d 00:00:00', time());
  118. $data['end_time'] = date('Y-m-d 23:59:59', time());
  119. $data['days'] = 1;
  120. break;
  121. case "yestoday" :
  122. $data['start_time'] = date('Y-m-d 00:00:00', strtotime('-1 day'));
  123. $data['end_time'] = date('Y-m-d 23:59:59', strtotime('-1 day'));
  124. $data['days'] = 1;
  125. break;
  126. case "last_month" :
  127. $data['start_time'] = date('Y-m-01 00:00:00', strtotime('-1 month'));
  128. $data['end_time'] = date('Y-m-t 23:59:59', strtotime('-1 month'));
  129. $data['days'] = 30;
  130. break;
  131. case "month" :
  132. $data['start_time'] = $month_start_time = date('Y-m-01 00:00:00', strtotime(date("Y-m-d")));
  133. $data['end_time'] = date('Y-m-d 23:59:59', strtotime("$month_start_time +1 month -1 day"));
  134. $data['days'] = 30;
  135. break;
  136. case "year" :
  137. $data['start_time'] = date('Y-01-01 00:00:00', time());
  138. $data['end_time'] = date('Y-12-t 23:59:59', time());
  139. $data['days'] = 365;
  140. break;
  141. case "last_year" :
  142. $data['start_time'] = date('Y-01-01 00:00:00', strtotime('-1 year'));
  143. $data['end_time'] = date('Y-12-t 23:59:59', strtotime('-1 year'));
  144. $data['days'] = 365;
  145. break;
  146. case 30 :
  147. case 15 :
  148. case 7 :
  149. if (!$isNum) {
  150. $data['start_time'] = date("Y-m-d 00:00:00", strtotime("-$timeKey day"));
  151. $data['end_time'] = date('Y-m-d 23:59:59', time());
  152. $data['days'] = $timeKey;
  153. } else {
  154. $day = $timeKey * 2;
  155. $data['start_time'] = date("Y-m-d 00:00:00", strtotime("-$day day"));
  156. $data['end_time'] = date("Y-m-d 23:59:59", strtotime("-$timeKey day"));
  157. $data['days'] = $timeKey;
  158. }
  159. break;
  160. default:
  161. $datetime_start = new \DateTime($timeKey['start_time']);
  162. $datetime_end = new \DateTime($timeKey['end_time']);
  163. $days = $datetime_start->diff($datetime_end)->days;
  164. $days = $days > 0 ? $days : 1;
  165. if (!$isNum) {
  166. $data['start_time'] = $timeKey['start_time'];
  167. $data['end_time'] = $timeKey['end_time'];
  168. $data['days'] = $days;
  169. } else {
  170. $data['start_time'] = date("Y-m-d 00:00:00", strtotime("-$days day"));
  171. $data['end_time'] = $timeKey['start_time'];
  172. $data['days'] = $days;
  173. }
  174. }
  175. return $data;
  176. }
  177. /**
  178. * 查询会员卡订单数据
  179. * @param array $where
  180. * @param string $field
  181. * @return array|\think\Model|null
  182. * @throws \think\db\exception\DataNotFoundException
  183. * @throws \think\db\exception\DbException
  184. * @throws \think\db\exception\ModelNotFoundException
  185. */
  186. public function getOne(array $where, string $field = '*')
  187. {
  188. return $this->dao->getOne($where, $field);
  189. }
  190. /**
  191. * @param int $uid
  192. * @param string $channelType 支付渠道
  193. * @param bool $memberType 会员卡类型
  194. * @param string $payPrice 支付金额
  195. * @param string $payType 支付方式
  196. * @param $type 订单类型
  197. * @return mixed
  198. * @throws \Exception
  199. */
  200. public function createOrder(int $uid, string $channelType, $memberType = false, string $payPrice, string $payType, $type, $money, $mcId)
  201. {
  202. /** @var StoreOrderCreateServices $storeOrderCreateService */
  203. $storeOrderCreateService = app()->make(StoreOrderCreateServices::class);
  204. $orderInfo = [
  205. 'uid' => $uid,
  206. 'order_id' => $storeOrderCreateService->getNewOrderId(),
  207. 'pay_price' => $payPrice,
  208. 'pay_type' => $payType,
  209. 'channel_type' => $channelType,
  210. 'member_code' => "",
  211. ];
  212. if ($type != 3) { //区别 0:免费领取会员 1:购买会员 2:卡密领取会员 3:线下付款
  213. if (!$memberType) throw new ValidateException('memberType miss');
  214. list($memberPrice, $isFree, $isPermanent, $overdueTime, $type, $newMemberRight) = $this->checkPayMemberType($memberType, $payPrice, $type, $uid, $mcId);
  215. $orderInfo['member_price'] = $memberPrice;
  216. $orderInfo['money'] = $memberPrice;
  217. $orderInfo['vip_day'] = $newMemberRight[$mcId]['vip_day'];
  218. $orderInfo['member_type'] = $memberType;
  219. $orderInfo['overdue_time'] = $overdueTime;
  220. $orderInfo['is_permanent'] = $isPermanent;
  221. $orderInfo['is_free'] = $isFree;
  222. $orderInfo['type'] = $type;
  223. $changeType = "create_member_order";
  224. } else {
  225. $orderInfo['type'] = $type;
  226. $orderInfo['member_code'] = "";
  227. $changeType = "create_offline_scan_order";
  228. $orderInfo['money'] = $money ? $money : $payPrice;
  229. }
  230. $memberOrder = $this->addOtherOrderData($orderInfo);
  231. if (!$memberOrder) {
  232. throw new ValidateException('订单生成失败!');
  233. }
  234. /** @var OtherOrderStatusServices $statusService */
  235. $statusService = app()->make(OtherOrderStatusServices::class);
  236. $statusService->save([
  237. 'oid' => $memberOrder['id'],
  238. 'change_type' => $changeType,
  239. 'change_message' => '订单生成',
  240. 'change_time' => time(),
  241. 'shop_type' => $type,
  242. ]);
  243. return $memberOrder;
  244. }
  245. /**
  246. * 免费卡领取支付
  247. * @param $orderInfo
  248. * @return bool
  249. */
  250. public function zeroYuanPayment($orderInfo)
  251. {
  252. if ($orderInfo['paid']) {
  253. throw new ValidateException('该订单已支付!');
  254. }
  255. if ($orderInfo['member_type'] != 'free') {
  256. throw new ValidateException('支付失败!');
  257. }
  258. $res = $this->paySuccess($orderInfo, 'yue');//余额支付成功
  259. return $res;
  260. }
  261. /**
  262. * 会员卡支付成功
  263. * @param array $orderInfo
  264. * @param string $paytype
  265. * @return bool
  266. */
  267. public function paySuccess(array $orderInfo, string $paytype = PayServices::WEIXIN_PAY, array $other = [])
  268. {
  269. /** @var OtherOrderStatusServices $statusService */
  270. $statusService = app()->make(OtherOrderStatusServices::class);
  271. /** @var UserServices $userServices */
  272. $userServices = app()->make(UserServices::class);
  273. /** @var UserBillServices $userBillServices */
  274. $userBillServices = app()->make(UserBillServices::class);
  275. switch ($orderInfo['type']) {
  276. case 0 :
  277. case 1:
  278. case 2 :
  279. $type = "pay_member";
  280. $res1 = $userServices->setMemberOverdueTime($orderInfo['vip_day'], $orderInfo['uid'], 1, $orderInfo['member_type']);
  281. break;
  282. case 3:
  283. $type = "offline_scan";
  284. $res1 = true;
  285. break;
  286. }
  287. if ($paytype == PayServices::ALIAPY_PAY && isset($other['trade_no'])) {
  288. $updata['trade_no'] = $other['trade_no'];
  289. }
  290. $updata['paid'] = 1;
  291. $updata['pay_type'] = $paytype;
  292. $updata['pay_time'] = time();
  293. $res2 = $this->dao->update($orderInfo['id'], $updata);
  294. $res3 = $statusService->save([
  295. 'oid' => $orderInfo['id'],
  296. 'change_type' => 'pay_success',
  297. 'change_message' => '用户付款成功',
  298. 'shop_type' => $orderInfo['type'],
  299. 'change_time' => time()
  300. ]);
  301. $now_money = $userServices->value(['uid' => $orderInfo['uid']], 'now_money');
  302. $res4 = $userBillServices->income($type, $orderInfo['uid'], $orderInfo['pay_price'], $now_money, $orderInfo['id']);
  303. //支付成功后发送消息
  304. OtherOrderJob::dispatch([$orderInfo]);
  305. $orderInfo['is_channel'] = 2;
  306. $orderInfo['total_num'] = 1;
  307. //用户推送消息事件
  308. event('notice.notice', [$orderInfo, 'order_pay_success']);
  309. //支付成功给客服发送消息
  310. event('notice.notice', [$orderInfo, 'admin_pay_success_code']);
  311. $res = $res1 && $res2 && $res3 && $res4;
  312. return false !== $res;
  313. }
  314. /**
  315. * 修改
  316. * @param array $where
  317. * @param array $data
  318. * @return mixed
  319. */
  320. public function update(array $where, array $data)
  321. {
  322. return $this->dao->update($where, $data);
  323. }
  324. /**
  325. * 购买会员卡数据校验
  326. * @param $memberType
  327. * @param $pay_price
  328. * @param $type
  329. * @return array
  330. */
  331. public function checkPayMemberType(string $memberType, string $payPrice, string $type, $uid, $mcId)
  332. {
  333. /** @var MemberCardServices $memberCardService */
  334. $memberCardService = app()->make(MemberCardServices::class);
  335. /** @var UserServices $userService */
  336. $userService = app()->make(UserServices::class);
  337. $userInfo = $userService->get($uid);
  338. if ($userInfo['is_money_level'] > 0 && $userInfo['is_ever_level'] > 0) throw new ValidateException('您已是永久会员无需再购买!');
  339. $newMemberRight = $memberCardService->getMemberTypeValue();
  340. if (!array_key_exists($mcId, $newMemberRight)) throw new ValidateException('该会员卡暂时无法购买!');
  341. $price = $newMemberRight[$mcId]['pre_price'];
  342. if ($payPrice != $price || ($memberType != 'free' && $payPrice <= 0)) throw new ValidateException('请核实价格!');
  343. if ($memberType == 'free' && $newMemberRight[$mcId]['vip_day'] <= 0) throw new ValidateException('网络错误!');
  344. switch ($memberType) {
  345. case "free"://免费会员
  346. $isCanGetFree = $this->isCanGetFree($uid);
  347. if ($isCanGetFree['is_record'] == 1) throw new ValidateException('您已经领取过免费会员!');
  348. $memberPrice = 0.00; //会员卡价格
  349. $isFree = 1;//代表免费
  350. $isPermanent = 0;//代表非永久
  351. $overdueTime = bcadd(bcmul(abs($newMemberRight[$mcId]['vip_day']), "86400", 0), time(), 0);
  352. break;
  353. case "month":
  354. case "year":
  355. case "quarter":
  356. case "owner":
  357. $memberPrice = $price;
  358. $isFree = 0;
  359. $isPermanent = 0;
  360. $overdueTime = bcadd(bcmul(abs($newMemberRight[$mcId]['vip_day']), '86400', 0), time(), 0);
  361. break;
  362. case "ever":
  363. $memberPrice = $price;
  364. $isFree = 0;
  365. $isPermanent = 1;
  366. $overdueTime = -1;
  367. break;
  368. default:
  369. throw new ValidateException('此类型会员卡暂未开售!');
  370. break;
  371. }
  372. //return compact('member_price', 'is_free', 'is_permanent', 'overdue_time', 'type');
  373. return [$memberPrice, $isFree, $isPermanent, $overdueTime, $type, $newMemberRight];
  374. }
  375. /**
  376. * 根据查询用户购买会员金额
  377. * @param array $where
  378. * @return mixed
  379. */
  380. public function getMemberMoneyByWhere(array $where, string $sumField, string $selectType, string $group = "")
  381. {
  382. switch ($selectType) {
  383. case "sum" :
  384. return $this->dao->getWhereSumField($where, $sumField);
  385. case "group" :
  386. return $this->dao->getGroupField($where, $sumField, $group);
  387. }
  388. }
  389. /**
  390. * 线下收银列表
  391. * @param array $where
  392. * @return array
  393. * @throws \think\db\exception\DataNotFoundException
  394. * @throws \think\db\exception\DbException
  395. * @throws \think\db\exception\ModelNotFoundException
  396. */
  397. public function getScanOrderList(array $where)
  398. {
  399. $where['type'] = 3;
  400. $where['paid'] = 1;
  401. [$page, $limit] = $this->getPageValue();
  402. if ($where['add_time']) {
  403. [$startTime, $endTime] = explode('-', $where['add_time']);
  404. if ($startTime || $endTime) {
  405. $startTime = strtotime($startTime);
  406. $endTime = strtotime($endTime . ' 23:59:59');
  407. $where['add_time'] = [$startTime, $endTime];
  408. }
  409. }
  410. if ($where['name']) {
  411. /** @var UserServices $userService */
  412. $userService = app()->make(UserServices::class);
  413. $userInfo = $userService->getUserInfoList(['nickname' => $where['name']], "uid");
  414. if ($userInfo) $where['uid'] = array_column($userInfo, 'uid');
  415. }
  416. $list = $this->dao->getScanOrderList($where, $page, $limit);
  417. if ($list) {
  418. /** @var UserServices $userService */
  419. $userService = app()->make(UserServices::class);
  420. $userInfo = $userService->getColumn([['uid', 'in', array_unique(array_column($list, 'uid'))]], 'uid,phone,nickname', 'uid');
  421. foreach ($list as &$v) {
  422. $v['add_time'] = date('Y-m-d H:i:s', $v['add_time']);
  423. $v['pay_time'] = date('Y-m-d H:i:s', $v['pay_time']);
  424. $v['phone'] = $userInfo[$v['uid']]['phone'] ?? '';
  425. $v['nickname'] = $userInfo[$v['uid']]['nickname'] ?? '';
  426. switch ($v['pay_type']) {
  427. case "yue" :
  428. $v['pay_type'] = "余额";
  429. break;
  430. case "weixin" :
  431. $v['pay_type'] = "微信";
  432. break;
  433. case "alipay" :
  434. $v['pay_type'] = "支付宝";
  435. break;
  436. }
  437. $v['true_price'] = bcsub($v['money'], $v['pay_price'], 2);
  438. }
  439. }
  440. $count = $this->dao->count($where);
  441. return compact('list', 'count');
  442. }
  443. /**
  444. * 获取会员记录
  445. * @param array $where
  446. * @return array
  447. * @throws \think\db\exception\DataNotFoundException
  448. * @throws \think\db\exception\DbException
  449. * @throws \think\db\exception\ModelNotFoundException
  450. */
  451. public function getMemberRecord(array $where)
  452. {
  453. $where['type'] = [0, 1, 2];
  454. $where['paid'] = 1;
  455. if ($where['add_time']) {
  456. $searchTime = explode('-', $where['add_time']);
  457. $startTime = strtotime($searchTime[0]);
  458. $endTime = strtotime($searchTime[1]);
  459. if ($startTime == $endTime) {
  460. $endTime += 86400;
  461. }
  462. $where['add_time'] = [$startTime, $endTime];
  463. }
  464. [$page, $limit] = $this->getPageValue();
  465. $list = $this->dao->getMemberRecord($where, $page, $limit);
  466. if ($list) {
  467. /** @var MemberShipServices $memberShipService */
  468. $memberShipService = app()->make(MemberShipServices::class);
  469. $shipInfo = $memberShipService->getApiList([]);
  470. $shipInfo = array_column($shipInfo, 'title', 'type');
  471. $shipInfo['owner'] = '自定义';
  472. foreach ($list as &$v) {
  473. $v['member_type'] = $v['member_type'] ? $shipInfo[$v['member_type']] : '其他';
  474. $v['pay_time'] = date('Y-m-d H:i:s', $v['pay_time']);
  475. $v['add_time'] = date('Y-m-d H:i:s', $v['add_time']);
  476. $v['overdue_time'] = date('Y-m-d H:i:s', $v['overdue_time']);
  477. switch ($v['pay_type']) {
  478. case "yue" :
  479. $v['pay_type'] = "余额";
  480. break;
  481. case "weixin" :
  482. $v['pay_type'] = "微信";
  483. break;
  484. case "alipay" :
  485. $v['pay_type'] = "支付宝";
  486. break;
  487. case "admin" :
  488. $v['pay_type'] = "后台赠送";
  489. break;
  490. }
  491. if ($v['type'] == 0) $v['pay_type'] = "免费领取";
  492. if ($v['type'] == 2) {
  493. $v['pay_type'] = "卡密领取";
  494. $v['member_type'] = "卡密激活";
  495. }
  496. if ($v['type'] == 1 && $v['is_free'] == 1) $v['pay_type'] = "免费领取";
  497. $v['user']['overdue_time'] = date('Y-m-d', $v['user']['overdue_time']) == "1970-01-01" ? "" : date('Y-m-d H:i:s', $v['user']['overdue_time']);
  498. }
  499. }
  500. $count = $this->dao->count($where);
  501. return compact('list', 'count');
  502. }
  503. }