Cashier.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  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\controller\store\order;
  12. use app\controller\store\AuthController;
  13. use app\Request;
  14. use app\services\order\cashier\CashierOrderServices;
  15. use app\services\order\cashier\StoreHangOrderServices;
  16. use app\services\order\StoreCartServices;
  17. use app\services\other\QrcodeServices;
  18. use app\services\pay\PayServices;
  19. use app\services\product\branch\StoreBranchProductServices;
  20. use app\services\store\SystemStoreStaffServices;
  21. use app\services\user\UserServices;
  22. use app\services\product\category\StoreProductCategoryServices;
  23. use crmeb\services\AliPayService;
  24. use crmeb\services\wechat\Payment;
  25. use crmeb\utils\Canvas;
  26. use think\db\exception\DataNotFoundException;
  27. use think\db\exception\ModelNotFoundException;
  28. use think\Exception;
  29. use think\exception\DbException;
  30. use think\exception\ValidateException;
  31. use think\facade\App;
  32. /**
  33. * 收银台
  34. * Class Cashier
  35. * @package app\controller\store\order
  36. * @property Request $request
  37. */
  38. class Cashier extends AuthController
  39. {
  40. /**
  41. * @var CashierOrderServices
  42. */
  43. protected $service;
  44. /**
  45. * Cashier constructor.
  46. * @param App $app
  47. * @param CashierOrderServices $service
  48. */
  49. public function __construct(App $app, CashierOrderServices $service)
  50. {
  51. parent::__construct($app);
  52. $this->service = $service;
  53. }
  54. /**
  55. * 获取用户信息
  56. * @param UserServices $services
  57. * @return mixed
  58. */
  59. public function getUserInfo(UserServices $services, StoreCartServices $cartServices)
  60. {
  61. $code = $this->request->post('code', '');
  62. $uid = $this->request->post('uid', '');
  63. if (!$code && !$uid) {
  64. return $this->fail('缺少参数');
  65. }
  66. $field = ['uid', 'avatar', 'phone', 'nickname', 'now_money', 'integral'];
  67. if ($uid) {
  68. $userInfo = $services->getUserInfo($uid, $field);
  69. } elseif ($code) {
  70. $userInfo = $services->get(['uniqid' => $code], $field);
  71. }
  72. if (!isset($userInfo) && !$userInfo) {
  73. return $this->fail('用户不存在');
  74. }
  75. $cart = $this->request->post('cart', []);
  76. if ($cart) {
  77. $cartServices->batchAddCart($cart, $this->storeId, $userInfo->uid);
  78. }
  79. return $this->success($userInfo->toArray());
  80. }
  81. /**
  82. * 获取一级分类
  83. * @param StoreProductCategoryServices $services
  84. * @return mixed
  85. * @throws DataNotFoundException
  86. * @throws \think\db\exception\DbException
  87. * @throws ModelNotFoundException
  88. */
  89. public function getCateGoryList(StoreProductCategoryServices $services)
  90. {
  91. return $this->success($services->getOneCategory());
  92. }
  93. /**
  94. * 获取商品列表
  95. * @param Request $request
  96. * @param StoreBranchProductServices $services
  97. * @return mixed
  98. */
  99. public function getProductList(Request $request, StoreBranchProductServices $services)
  100. {
  101. $where = $request->getMore([
  102. ['store_name', ''],
  103. ['cate_id', 0],
  104. ['field_key', ''],
  105. ['staff_id', '']
  106. ]);
  107. $store_id = (int)$this->storeId;
  108. $where['field_key'] = $where['field_key'] == 'all' ? '' : $where['field_key'];
  109. $where['field_key'] = $where['field_key'] == 'id' ? 'product_id' : $where['field_key'];
  110. $staff_id = (int)$where['staff_id'];
  111. unset($where['staff_id']);
  112. $where['is_del'] = 0;
  113. $where['is_show'] = 1;
  114. $uid = $this->request->get('uid', 0);
  115. return $this->success($services->getCashierProductListV2($where, $store_id, (int)$uid, $staff_id));
  116. }
  117. /**
  118. * 获取商品详情
  119. * @param StoreBranchProductServices $services
  120. * @param $id
  121. * @return mixed
  122. */
  123. public function getProductDetail(StoreBranchProductServices $services, $id, $uid = 0)
  124. {
  125. if (!$id) {
  126. return $this->fail('缺少商品id');
  127. }
  128. $touristUid = $this->request->get('tourist_uid');
  129. return $this->success($services->getProductDetail($this->storeId, (int)$id, (int)$uid, (int)$touristUid));
  130. }
  131. /**
  132. * 购物车列表
  133. * @param StoreCartServices $services
  134. * @param $uid
  135. * @param $staff_id
  136. * @return mixed
  137. * @throws DataNotFoundException
  138. * @throws ModelNotFoundException
  139. * @throws \think\db\exception\DbException
  140. */
  141. public function getCartList(StoreCartServices $services, $uid, $staff_id)
  142. {
  143. if (!$staff_id) {
  144. return $this->fail('缺少参数');
  145. }
  146. $cartIds = $this->request->get('cart_ids', '');
  147. $touristUid = $this->request->get('tourist_uid', '');
  148. $cartIds = $cartIds ? explode(',', $cartIds) : [];
  149. if (!$touristUid && !$uid) {
  150. return $this->fail('缺少用户信息');
  151. }
  152. return $this->success($services->getUserCartList((int)$uid, -1, $cartIds, $this->storeId, $staff_id, 4, (int)$touristUid));
  153. }
  154. /**
  155. * 获取店员信息
  156. * @param SystemStoreStaffServices $services
  157. * @return mixed
  158. */
  159. public function getStaffList(SystemStoreStaffServices $services)
  160. {
  161. $where = [];
  162. $where['store_id'] = $this->storeId;
  163. $where['keyword'] = $this->request->get('keyword', '');
  164. $where['is_del'] = 0;
  165. return $this->success([
  166. 'staffInfo' => $this->request->storeStaffInfo(),
  167. 'staffList' => $services->getStoreStaff($where),
  168. 'count' => $services->count($where)
  169. ]);
  170. }
  171. /**
  172. * 解析条形码值
  173. * @return mixed
  174. */
  175. public function getAnalysisCode()
  176. {
  177. $code = $this->request->post('bar_code', '');
  178. $uid = $this->request->post('uid', 0);
  179. $staff_id = $this->request->post('staff_id', 0);
  180. $touristUid = $this->request->post('tourist_uid', '');
  181. if (!$touristUid && !$uid) {
  182. return $this->fail('缺少用户信息');
  183. }
  184. return $this->success($this->service->getAnalysisCode($code, $this->storeId, (int)$uid, (int)$staff_id, (int)$touristUid));
  185. }
  186. /**
  187. * 游客切换到用户
  188. * @param StoreCartServices $services
  189. * @param $staffId
  190. * @return mixed
  191. */
  192. public function switchCartUser(StoreCartServices $services, $staffId)
  193. {
  194. [$uid, $toUid, $isTourist] = $this->request->postMore([
  195. ['uid', 0],
  196. ['to_uid', 0],
  197. ['is_tourist', 0]
  198. ], true);
  199. if ($isTourist) {
  200. $where = ['tourist_uid' => $uid, 'store_id' => $this->storeId, 'staff_id' => $staffId];
  201. $touristCart = $services->getCartList($where);
  202. if ($touristCart) {
  203. $userWhere = ['uid' => $toUid, 'store_id' => $this->storeId, 'staff_id' => $staffId];
  204. $userCarts = $services->getCartList($userWhere);
  205. if ($userCarts) {
  206. foreach ($touristCart as $cart) {
  207. foreach ($userCarts as $userCart) {
  208. //游客商品 存在用户购物车商品中
  209. if($cart['product_id'] == $userCart['product_id'] && $cart['product_attr_unique'] == $userCart['product_attr_unique']) {
  210. //修改用户商品数量 删除游客购物车这条数据
  211. $services->update(['id' => $userCart['id']], ['cart_num' => bcadd((string)$cart['cart_num'], (string)$userCart['cart_num'])]);
  212. $services->delete(['id' => $cart['id']]);
  213. }
  214. }
  215. }
  216. }
  217. }
  218. $services->update($where, ['uid' => $toUid, 'tourist_uid' => '']);
  219. }
  220. return $this->success('修改成功');
  221. }
  222. /**
  223. * 加入购物车
  224. * @param StoreCartServices $services
  225. * @param $uid
  226. * @return mixed
  227. * @throws \Psr\SimpleCache\InvalidArgumentException
  228. * @throws DataNotFoundException
  229. * @throws \think\db\exception\DbException
  230. * @throws ModelNotFoundException
  231. */
  232. public function addCart(StoreCartServices $services, $uid)
  233. {
  234. $where = $this->request->postMore([
  235. ['productId', 0],//普通商品编号
  236. [['cartNum', 'd'], 1], //购物车数量
  237. ['uniqueId', ''],//属性唯一值
  238. ['staff_id', ''],//店员ID
  239. ['tourist_uid', '']//虚拟用户uid
  240. ]);
  241. if (!$where['productId']) {
  242. return $this->fail('参数错误');
  243. }
  244. //真实用户存在,虚拟用户uid为空
  245. if ($uid) {
  246. $where['tourist_uid'] = '';
  247. }
  248. if (!$uid && !$where['tourist_uid']) {
  249. return $this->fail('缺少用户UID');
  250. }
  251. $services->setItem('store_id', $this->storeId)
  252. ->setItem('tourist_uid', $where['tourist_uid']);
  253. $res = $services->addCashierCart((int)$uid, (int)$where['productId'], (int)$where['cartNum'], $where['uniqueId'], (int)$where['staff_id']);
  254. $services->reset();
  255. return $this->success(['cartId' => $res]);
  256. }
  257. /**
  258. * 删除购物车
  259. * @param StoreCartServices $services
  260. * @param $uid
  261. * @return mixed
  262. */
  263. public function delCart(StoreCartServices $services, $uid)
  264. {
  265. $where = $this->request->postMore([
  266. ['ids', []],//购物车编号
  267. ]);
  268. if (!count($where['ids'])) {
  269. return $this->fail('参数错误!');
  270. }
  271. if ($services->removeUserCart((int)$uid, $where['ids'])) {
  272. return $this->success();
  273. } else {
  274. return $this->fail('清除失败!');
  275. }
  276. }
  277. /**
  278. * 购物车 修改商品数量
  279. * @param Request $request
  280. * @return mixed
  281. * @throws Exception
  282. * @throws DataNotFoundException
  283. * @throws ModelNotFoundException
  284. * @throws DbException
  285. */
  286. public function numCart(StoreCartServices $services, $uid)
  287. {
  288. $where = $this->request->postMore([
  289. ['id', 0],//购物车编号
  290. ['number', 0],//购物数量
  291. ]);
  292. if (!$where['id'] || !$where['number'] || !is_numeric($where['id']) || !is_numeric($where['number'])) {
  293. return $this->fail('参数错误!');
  294. }
  295. if ($services->changeCashierCartNum((int)$where['id'], (int)$where['number'], $uid, $this->storeId)) {
  296. return $this->success();
  297. } else {
  298. return $this->fail('修改失败');
  299. }
  300. }
  301. /**
  302. * 购物车重选
  303. * @param Request $request
  304. * @return mixed
  305. */
  306. public function changeCart(StoreCartServices $services)
  307. {
  308. [$cart_id, $product_id, $unique] = $this->request->postMore([
  309. ['cart_id', 0],
  310. ['product_id', 0],
  311. ['unique', '']
  312. ], true);
  313. $services->modifyCashierCart($this->storeId, (int)$cart_id, (int)$product_id, $unique);
  314. return $this->success('重选成功');
  315. }
  316. /**
  317. * 获取用户优惠券列表
  318. * @param CashierOrderServices $services
  319. * @param $uid
  320. * @return mixed
  321. */
  322. public function couponList(CashierOrderServices $services, $uid)
  323. {
  324. [$cartIds] = $this->request->postMore([
  325. ['cart_id', []],
  326. ], true);
  327. if (!$uid) return $this->success([]);
  328. return $this->success($services->getCouponList((int)$uid, $this->storeId, $cartIds));
  329. }
  330. /**
  331. * 添加挂单数据
  332. * @return mixed
  333. */
  334. public function saveHangOrder()
  335. {
  336. return $this->success('挂单成功');
  337. }
  338. /**
  339. * 获取挂单列表和用户购买历史列表 挂单规定10个,历史记录规定20个没有分页
  340. * @param StoreHangOrderServices $services
  341. * @param int $staffId
  342. * @return mixed
  343. * @throws DataNotFoundException
  344. * @throws ModelNotFoundException
  345. * @throws \think\db\exception\DbException
  346. */
  347. public function getHangOrder(StoreHangOrderServices $services, $staffId = 0)
  348. {
  349. return $this->success($services->getHangOrder((int)$this->storeId, $staffId ?: (int)$this->storeStaffId));
  350. }
  351. /**
  352. * 获取挂单列表分页
  353. * @param StoreHangOrderServices $services
  354. * @param int $staffId
  355. * @return mixed
  356. * @throws DataNotFoundException
  357. * @throws ModelNotFoundException
  358. * @throws \think\db\exception\DbException
  359. */
  360. public function getHangOrderList(StoreHangOrderServices $services, $staffId = 0)
  361. {
  362. $search = $this->request->get('keyword', '');
  363. return $this->success($services->getHangOrderList((int)$this->storeId, 0, $search));
  364. }
  365. /**
  366. * 删除购物车信息
  367. * @param StoreCartServices $services
  368. * @return mixed
  369. */
  370. public function deleteHangOrder(StoreCartServices $services)
  371. {
  372. $id = $this->request->get('id');
  373. if (!$id) {
  374. return $this->fail('缺少参数');
  375. }
  376. $id = explode(',', $id) ?: [];
  377. if ($services->search(['id' => $id])->delete()) {
  378. return $this->success('删除成功');
  379. } else {
  380. return $this->fail('删除失败');
  381. }
  382. }
  383. /**
  384. * 计算门店下的购物车内的金额
  385. * @param CashierOrderServices $services
  386. * @param $uid
  387. * @return mixed
  388. * @throws DataNotFoundException
  389. * @throws \think\db\exception\DbException
  390. * @throws ModelNotFoundException
  391. */
  392. public function computeOrder(CashierOrderServices $services, $uid)
  393. {
  394. [$integral, $coupon, $cartIds, $coupon_id] = $this->request->postMore([
  395. ['integral', 0],
  396. ['coupon', 0],
  397. ['cart_id', []],
  398. ['coupon_id', 0]
  399. ], true);
  400. if (!$cartIds) {
  401. return $this->fail('缺少购物车ID');
  402. }
  403. return $this->success($services->computeOrder((int)$uid, $this->storeId, $cartIds, !!$integral, !!$coupon, [], $coupon_id));
  404. }
  405. /**
  406. * 生成订单
  407. * @param CashierOrderServices $services
  408. * @param $uid
  409. * @return mixed
  410. */
  411. public function createOrder(CashierOrderServices $services, $uid)
  412. {
  413. [$integral, $coupon, $cartIds, $payType, $remarks, $staffId, $changePrice, $isPrice, $userCode, $coupon_id, $authCode, $touristUid] = $this->request->postMore([
  414. ['integral', 0],
  415. ['coupon', 0],
  416. ['cart_id', []],
  417. ['pay_type', ''],
  418. ['remarks', ''],
  419. ['staff_id', 0],
  420. ['change_price', 0],
  421. ['is_price', 0],
  422. ['userCode', ''],
  423. ['coupon_id', 0],
  424. ['auth_code', ''],
  425. ['tourist_uid', '']
  426. ], true);
  427. if (!$staffId) {
  428. $staffId = $this->request->storeStaffId();
  429. }
  430. if (!$cartIds) {
  431. return $this->fail('缺少购物车ID');
  432. }
  433. if (!in_array($payType, ['yue', 'cash']) && $authCode) {
  434. if (Payment::isWechatAuthCode($authCode)) {
  435. $payType = PayServices::WEIXIN_PAY;
  436. } else if (AliPayService::isAliPayAuthCode($authCode)) {
  437. $payType = PayServices::ALIAPY_PAY;
  438. } else {
  439. return $this->fail('未知,付款二维码');
  440. }
  441. }
  442. $userInfo = [];
  443. if ($uid) {
  444. /** @var UserServices $userService */
  445. $userService = app()->make(UserServices::class);
  446. $userInfo = $userService->getUserInfo($uid);
  447. if (!$userInfo) {
  448. return $this->fail('用户不存在');
  449. }
  450. $userInfo = $userInfo->toArray();
  451. }
  452. $computeData = $services->computeOrder($uid, $this->storeId, $cartIds, $integral, $coupon, $userInfo, $coupon_id);
  453. $cartInfo = $computeData['cartInfo'];
  454. return $services->transaction(function () use ($services, $userInfo, $computeData, $authCode, $uid, $staffId, $cartIds, $payType, $integral, $coupon, $remarks, $changePrice, $isPrice, $userCode, $coupon_id) {
  455. $orderInfo = $services->createOrder((int)$uid, $userInfo, $computeData, $this->storeId, (int)$staffId, $cartIds, $payType, !!$integral, !!$coupon, $remarks, $changePrice, !!$isPrice, $coupon_id);
  456. if (in_array($payType, [PayServices::YUE_PAY, PayServices::CASH_PAY, PayServices::ALIAPY_PAY, PayServices::WEIXIN_PAY])) {
  457. $res = $services->paySuccess($orderInfo['order_id'], $payType, $userCode, $authCode);
  458. $res['order_id'] = $orderInfo['order_id'];
  459. return app('json')->success($res);
  460. } else {
  461. return app('json')->success(['status' => 'ORDER_CREATE', 'order_id' => $orderInfo['order_id']]);
  462. }
  463. });
  464. }
  465. /**
  466. * 订单支付
  467. * @param CashierOrderServices $services
  468. * @param $orderId
  469. * @return mixed
  470. */
  471. public function payOrder(CashierOrderServices $services, $orderId)
  472. {
  473. if (!$orderId) {
  474. return $this->fail('缺少订单号');
  475. }
  476. $payType = $this->request->post('payType', 'yue');
  477. $userCode = $this->request->post('userCode', '');
  478. $authCode = $this->request->post('auth_code', '');
  479. if ($payType == PayServices::YUE_PAY && !$userCode) {
  480. return $this->fail('缺少用户余额支付CODE');
  481. }
  482. if (!in_array($payType, ['yue', 'cash']) && $authCode) {
  483. if (Payment::isWechatAuthCode($authCode)) {
  484. $payType = PayServices::WEIXIN_PAY;
  485. } else if (AliPayService::isAliPayAuthCode($authCode)) {
  486. $payType = PayServices::ALIAPY_PAY;
  487. } else {
  488. return $this->fail('未知,付款二维码');
  489. }
  490. }
  491. $res = $services->paySuccess($orderId, $payType, $userCode, $authCode);
  492. $res['order_id'] = $orderId;
  493. return $this->success($res);
  494. }
  495. /** 获取二维码
  496. * @return mixed
  497. */
  498. public function cashier_scan()
  499. {
  500. $store_id = $this->storeId;
  501. //生成h5地址
  502. $weixinPage = "/pages/goods/order_pay/index?store_id=" . $store_id;
  503. $weixinFileName = "wechat_cashier_pay_" . $store_id . ".png";
  504. /** @var QrcodeServices $QrcodeService */
  505. $QrcodeService = app()->make(QrcodeServices::class);
  506. $wechatQrcode = $QrcodeService->getWechatQrcodePath($weixinFileName, $weixinPage, false, false);
  507. //生成小程序地址
  508. $routineQrcode = $QrcodeService->getRoutineQrcodePath($store_id, 0, 7, [], false);
  509. $qrcod = ['wechat' => $wechatQrcode, 'routine' => $routineQrcode];
  510. //生成画布
  511. $canvas = Canvas::instance();
  512. $path = 'uploads/offline/';
  513. $imageType = 'jpg';
  514. $siteUrl = sys_config('site_url');
  515. $canvas->setImageUrl(public_path() . 'statics/qrcode/offlines.jpg')->setImageHeight(730)->setImageWidth(500)->pushImageValue();
  516. foreach ($qrcod as $k => $v) {
  517. if ($v) {
  518. $name = 'offline_' . $k;
  519. $canvas->setImageUrl($v)->setImageHeight(344)->setImageWidth(344)->setImageLeft(76)->setImageTop(120)->pushImageValue();
  520. $image = $canvas->setFileName($name)->setImageType($imageType)->setPath($path)->setBackgroundWidth(500)->setBackgroundHeight(720)->starDrawChart();
  521. $data[$k] = $image ? $siteUrl . '/' . $image : '';
  522. } else {
  523. $data[$k] = "";
  524. }
  525. }
  526. return $this->success($data);
  527. }
  528. }