You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

OtherOrderServices.php 20KB

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