WriteOffOrderServices.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  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\store;
  12. use app\dao\order\StoreOrderDao;
  13. use app\services\order\StoreOrderCartInfoServices;
  14. use app\services\order\StoreOrderCreateServices;
  15. use app\services\order\StoreOrderRefundServices;
  16. use app\services\order\StoreOrderTakeServices;
  17. use app\services\activity\integral\StoreIntegralOrderServices;
  18. use app\services\activity\integral\StoreIntegralOrderStatusServices;
  19. use app\services\activity\combination\StorePinkServices;
  20. use app\services\BaseServices;
  21. use app\services\store\SystemStoreStaffServices;
  22. use app\services\store\DeliveryServiceServices;
  23. use app\services\user\UserServices;
  24. use crmeb\services\FormBuilder as Form;
  25. use think\exception\ValidateException;
  26. /**
  27. * 核销订单
  28. * Class StoreOrderWriteOffServices
  29. * @package app\sservices\order
  30. * @mixin StoreOrderDao
  31. */
  32. class WriteOffOrderServices extends BaseServices
  33. {
  34. /**
  35. * 构造方法
  36. * StoreOrderWriteOffServices constructor.
  37. * @param StoreOrderDao $dao
  38. */
  39. public function __construct(StoreOrderDao $dao)
  40. {
  41. $this->dao = $dao;
  42. }
  43. /**
  44. * 验证核销订单权限
  45. * @param int $uid
  46. * @param array $orderInfo
  47. * @param int $auth 0:管理员 1门店 2配送员
  48. * @param int $staff_id
  49. * @return bool
  50. */
  51. public function checkAuth(int $uid, array $orderInfo, int $auth = 1, int $staff_id = 0)
  52. {
  53. if (($auth > 0 && !$uid && !$staff_id) || !$orderInfo) {
  54. throw new ValidateException('订单不存在');
  55. }
  56. $store_id = $orderInfo['store_id'] ?? 0;
  57. $info = $this->checkUserAuth($uid, $auth, $store_id, $staff_id);
  58. $isAuth = true;
  59. switch ($auth) {
  60. case 0://管理员
  61. break;
  62. case 1://门店
  63. if ($orderInfo['shipping_type'] == 2 && $info && isset($info['store_id']) && $info['store_id'] == $store_id) {
  64. $isAuth = true;
  65. } else {
  66. $isAuth = false;
  67. }
  68. break;
  69. case 2://配送员
  70. if (in_array($orderInfo['shipping_type'], [1, 3]) && $info && $orderInfo['delivery_type'] == 'send' && $orderInfo['delivery_uid'] == $uid) {
  71. $isAuth = true;
  72. } else {
  73. $isAuth = false;
  74. }
  75. break;
  76. }
  77. if (!$isAuth) {
  78. throw new ValidateException('您无权限核销此订单,请联系管理员');
  79. }
  80. return true;
  81. }
  82. /**
  83. * 验证核销权限
  84. * @param int $uid
  85. * @param int $auth
  86. * @param int $store_id
  87. * @param int $staff_id
  88. * @return array|\think\Model
  89. */
  90. public function checkUserAuth(int $uid, int $auth = 1, int $store_id = 0, int $staff_id = 0)
  91. {
  92. if ($auth > 0 && !$uid && !$staff_id) {
  93. throw new ValidateException('用户不存在');
  94. }
  95. $isAuth = true;
  96. $info = [];
  97. switch ($auth) {
  98. case 0://管理员
  99. break;
  100. case 1://门店
  101. //验证店员
  102. /** @var SystemStoreStaffServices $storeStaffServices */
  103. $storeStaffServices = app()->make(SystemStoreStaffServices::class);
  104. try {
  105. if ($staff_id) {
  106. $info = $storeStaffServices->getStaffInfo($staff_id);
  107. } else {
  108. $info = $storeStaffServices->getStaffInfoByUid($uid, $store_id);
  109. }
  110. } catch (\Throwable $e) {
  111. }
  112. if ($info && $info['verify_status'] == 1) {
  113. $isAuth = true;
  114. }
  115. break;
  116. case 2://配送员
  117. /** @var DeliveryServiceServices $deliverServiceServices */
  118. $deliverServiceServices = app()->make(DeliveryServiceServices::class);
  119. try {
  120. $info = $deliverServiceServices->getDeliveryInfoByUid($uid, 1, (int)$store_id);
  121. } catch (\Throwable $e) {
  122. }
  123. if ($info) {
  124. $isAuth = true;
  125. }
  126. break;
  127. }
  128. if (!$isAuth) {
  129. throw new ValidateException('您无权限核销,请联系管理员');
  130. }
  131. return $info;
  132. }
  133. /**
  134. * 用户码获取待核销订单列表
  135. * @param int $uid
  136. * @param string $code
  137. * @param int $auth
  138. * @return array
  139. * @throws \think\db\exception\DataNotFoundException
  140. * @throws \think\db\exception\DbException
  141. * @throws \think\db\exception\ModelNotFoundException
  142. */
  143. public function userUnWriteoffOrder(int $uid, string $code, int $auth = 1)
  144. {
  145. /** @var UserServices $userServices */
  146. $userServices = app()->make(UserServices::class);
  147. $userInfo = $userServices->getOne(['bar_code' => $code]);
  148. if (!$userInfo) {
  149. throw new ValidateException('该用户不存在');
  150. }
  151. $info = $this->checkUserAuth($uid, $auth);
  152. $unWriteoffOrder = [];
  153. if ($info && isset($info['store_id'])) {
  154. if ($auth == 1) {//店员
  155. $where = ['store_id' => $info['store_id']];
  156. } else {//配送员
  157. $where = ['delivery_uid' => $info['uid']];
  158. }
  159. $unWriteoffOrder = $this->dao->getUnWirteOffList(['uid' => $userInfo['uid']] + $where, ['id']);
  160. }
  161. $data = [];
  162. if ($unWriteoffOrder) {
  163. foreach ($unWriteoffOrder as $item) {
  164. try {
  165. $orderInfo = $this->writeoffOrderInfo($uid, '', $auth, $item['id']);
  166. } catch (\Throwable $e) {//无权限或其他异常不返回订单信息
  167. $orderInfo = [];
  168. }
  169. if ($orderInfo) $data[] = $orderInfo;
  170. }
  171. }
  172. return $data;
  173. }
  174. /**
  175. * 获取核销订单信息
  176. * @param int $uid
  177. * @param string $code
  178. * @param int $auth
  179. * @param int $oid
  180. * @return array
  181. * @throws \think\db\exception\DataNotFoundException
  182. * @throws \think\db\exception\DbException
  183. * @throws \think\db\exception\ModelNotFoundException
  184. */
  185. public function writeoffOrderInfo(int $uid, string $code = '', int $auth = 1, int $oid = 0, int $staff_id = 0)
  186. {
  187. if ($oid) {
  188. //订单
  189. $orderInfo = $this->dao->getOne(['id' => $oid, 'is_del' => 0], '*', ['user', 'pink']);
  190. $order_type = 'order';
  191. if (!$orderInfo) {
  192. //积分兑换订单
  193. /** @var StoreIntegralOrderServices $storeIntegralOrderServices */
  194. $storeIntegralOrderServices = app()->make(StoreIntegralOrderServices::class);
  195. $orderInfo = $storeIntegralOrderServices->getOne(['id' => $oid]);
  196. $order_type = 'integral';
  197. }
  198. } else {
  199. //订单
  200. $orderInfo = $this->dao->getOne(['verify_code' => $code, 'is_del' => 0], '*', ['user', 'pink']);
  201. $order_type = 'order';
  202. if (!$orderInfo) {
  203. //积分兑换订单
  204. /** @var StoreIntegralOrderServices $storeIntegralOrderServices */
  205. $storeIntegralOrderServices = app()->make(StoreIntegralOrderServices::class);
  206. $orderInfo = $storeIntegralOrderServices->getOne(['verify_code' => $code]);
  207. $order_type = 'integral';
  208. }
  209. }
  210. if (!$orderInfo) {
  211. throw new ValidateException('Write off order does not exist');
  212. }
  213. if ($order_type == 'order' && !$orderInfo['paid']) {
  214. throw new ValidateException('订单还未完成支付');
  215. }
  216. if ($order_type == 'order' && $orderInfo['refund_status'] != 0) {
  217. throw new ValidateException('该订单状态暂不支持核销');
  218. }
  219. $orderInfo['order_type'] = $order_type;
  220. $orderInfo = $orderInfo->toArray();
  221. //验证权限
  222. $this->checkAuth($uid, $orderInfo, $auth, $staff_id);
  223. if ($order_type == 'order') {
  224. /** @var StoreOrderCartInfoServices $cartServices */
  225. $cartServices = app()->make(StoreOrderCartInfoServices::class);
  226. $cartInfo = $cartServices->getCartInfoList(['oid' => $orderInfo['id']], ['id', 'oid', 'write_times', 'write_surplus_times', 'write_start', 'write_end']);
  227. $orderInfo['write_off'] = $orderInfo['write_times'] = 0;
  228. $orderInfo['write_day'] = '';
  229. $cart = $cartInfo[0] ?? [];
  230. if ($orderInfo['product_type'] == 4 && $cart) {//次卡商品
  231. $orderInfo['write_off'] = max(bcsub((string)$cart['write_times'], (string)$cart['write_surplus_times'], 0), 0);
  232. $orderInfo['write_times'] = $cart['write_times'] ?? 0;
  233. $start = $cart['write_start'] ?? 0;
  234. $end = $cart['write_end'] ?? 0;
  235. if (!$start && !$end) {
  236. $orderInfo['write_day'] = '不限时';
  237. } else {
  238. $orderInfo['write_day'] = ($start ? date('Y-m-d', $start) : '') . '/' . ($end ? date('Y-m-d', $end) : '');
  239. }
  240. }
  241. }
  242. return $orderInfo;
  243. }
  244. /**
  245. * 获取订单商品信息
  246. * @param int $uid
  247. * @param int $id
  248. * @param int $auth
  249. * @param int $staff_id
  250. * @param bool $isCasher
  251. * @return array|\think\Model|null
  252. * @throws \think\db\exception\DataNotFoundException
  253. * @throws \think\db\exception\DbException
  254. * @throws \think\db\exception\ModelNotFoundException
  255. */
  256. public function getOrderCartInfo(int $uid, int $id, int $auth = 1, int $staff_id = 0, bool $isCasher = false)
  257. {
  258. if ($isCasher) {//获取订单信息 暂时不验证权限
  259. $orderInfo = $this->dao->getOne(['id' => $id], '*', ['user', 'pink']);
  260. if (!$orderInfo) {
  261. throw new ValidateException('Write off order does not exist');
  262. }
  263. $orderInfo = $orderInfo->toArray();
  264. } else {
  265. $orderInfo = $this->writeoffOrderInfo($uid, '', $auth, $id, $staff_id);
  266. }
  267. $writeoff_count = 0;
  268. /** @var StoreOrderCartInfoServices $cartInfoServices */
  269. $cartInfoServices = app()->make(StoreOrderCartInfoServices::class);
  270. $cartInfo = $cartInfoServices->getCartColunm(['oid' => $orderInfo['id']], 'id,cart_id,cart_num,surplus_num,is_writeoff,cart_info,product_type,is_support_refund,is_gift,write_times,write_surplus_times');
  271. foreach ($cartInfo as &$item) {
  272. $_info = is_string($item['cart_info']) ? json_decode($item['cart_info'], true) : $item['cart_info'];
  273. if (!isset($_info['productInfo'])) $_info['productInfo'] = [];
  274. //缩略图处理
  275. if (isset($_info['productInfo']['attrInfo'])) {
  276. $_info['productInfo']['attrInfo'] = get_thumb_water($_info['productInfo']['attrInfo']);
  277. }
  278. $_info['productInfo'] = get_thumb_water($_info['productInfo']);
  279. $item['cart_info'] = $_info;
  280. if ($item['write_times'] > $item['write_surplus_times']) {
  281. $writeoff_count = bcadd((string)$writeoff_count, (string)bcsub((string)$item['write_times'], (string)$item['write_surplus_times']));
  282. }
  283. $item['surplus_num'] = $item['write_surplus_times'];
  284. unset($_info);
  285. }
  286. $orderInfo['cart_count'] = count($cartInfo);
  287. $orderInfo['writeoff_count'] = $writeoff_count;
  288. $orderInfo['cart_info'] = $cartInfo;
  289. return $orderInfo;
  290. }
  291. /**
  292. * 核销订单
  293. * @param int $uid
  294. * @param array $orderInfo
  295. * @param array $cartIds
  296. * @param int $auth
  297. * @return array|null
  298. * @throws \think\db\exception\DataNotFoundException
  299. * @throws \think\db\exception\DbException
  300. * @throws \think\db\exception\ModelNotFoundException
  301. */
  302. public function writeoffOrder(int $uid, array $orderInfo, array $cartIds = [], int $auth = 1, int $staff_id = 0)
  303. {
  304. if (!$orderInfo) {
  305. throw new ValidateException('订单不存在');
  306. }
  307. //默认正常订单
  308. $orderInfo['order_type'] = $orderInfo['order_type'] ?? 'order';
  309. $time = time();
  310. if ($orderInfo['order_type'] == 'order') {
  311. //验证核销权限
  312. $this->checkAuth($uid, $orderInfo, $auth, $staff_id);
  313. if (!$orderInfo['verify_code'] || ($orderInfo['shipping_type'] != 2 && $orderInfo['delivery_type'] != 'send')) {
  314. throw new ValidateException('此订单不能被核销');
  315. }
  316. /** @var StoreOrderRefundServices $storeOrderRefundServices */
  317. $storeOrderRefundServices = app()->make(StoreOrderRefundServices::class);
  318. if ($storeOrderRefundServices->count(['store_order_id' => $orderInfo['id'], 'refund_type' => [1, 2, 4, 5, 6], 'is_cancel' => 0, 'is_del' => 0])) {
  319. throw new ValidateException('订单有售后申请请先处理');
  320. }
  321. if (isset($orderInfo['pinkStatus']) && $orderInfo['pinkStatus'] != 2) {
  322. throw new ValidateException('拼团未完成暂不能核销!');
  323. }
  324. /** @var StoreOrderCartInfoServices $cartInfoServices */
  325. $cartInfoServices = app()->make(StoreOrderCartInfoServices::class);
  326. if ($orderInfo['status'] >= 2 && !$cartInfoServices->count(['oid' => $orderInfo['id'], 'is_writeoff' => 0])) {
  327. throw new ValidateException('订单已核销');
  328. }
  329. $store_id = $orderInfo['store_id'];
  330. if ($orderInfo['type'] == 3 && $orderInfo['activity_id'] && $orderInfo['pink_id']) {
  331. /** @var StorePinkServices $services */
  332. $services = app()->make(StorePinkServices::class);
  333. $res = $services->getCount([['id', '=', $orderInfo['pink_id']], ['status', '<>', 2]]);
  334. if ($res) throw new ValidateException('Failed to write off the group order');
  335. }
  336. $cartInfo = [];
  337. if ($cartIds) {//商城存在部分核销
  338. $ids = array_unique(array_column($cartIds, 'cart_id'));
  339. //订单下原商品信息
  340. $cartInfo = $cartInfoServices->getCartColunm(['oid' => $orderInfo['id'], 'cart_id' => $ids, 'is_writeoff' => 0], 'id,cart_id,cart_num,surplus_num,product_id,write_times,write_surplus_times,write_start,write_end', 'cart_id');
  341. if (count($ids) != count($cartInfo)) {
  342. throw new ValidateException('订单中有商品已核销');
  343. }
  344. foreach ($cartIds as $cart) {
  345. $info = $cartInfo[$cart['cart_id']] ?? [];
  346. if (!$info) {
  347. throw new ValidateException('核销商品不存在');
  348. }
  349. if ($cart['cart_num'] > $info['write_surplus_times']) {
  350. throw new ValidateException('核销数量超出剩余总核销次数');
  351. }
  352. }
  353. } else {//整单核销
  354. $cartInfo = $cartInfoServices->getCartColunm(['oid' => $orderInfo['id'], 'is_writeoff' => 0], 'id,cart_id,cart_num,surplus_num,product_id,write_times,write_surplus_times,write_start,write_end', 'cart_id');
  355. }
  356. foreach ($cartInfo as $info) {
  357. if ($info['write_start'] && $time < $info['write_start']) {
  358. throw new ValidateException('还未到指定核销的开始时间,无法核销');
  359. }
  360. if ($info['write_end'] && $time > $info['write_end']) {
  361. throw new ValidateException('已经超过指定核销的结束时间,无法核销');
  362. }
  363. }
  364. $data = ['clerk_id' => $uid];
  365. $cartData = ['writeoff_time' => $time];
  366. if ($auth == 1) {//店员
  367. /** @var SystemStoreStaffServices $storeStaffServices */
  368. $storeStaffServices = app()->make(SystemStoreStaffServices::class);
  369. if ($uid) {//商城前端
  370. $staffInfo = $storeStaffServices->getStaffInfoByUid($uid, $store_id);
  371. } else {//门店后台
  372. $staffInfo = $storeStaffServices->getStaffInfo($staff_id);
  373. if ($store_id != $staffInfo['store_id']) {
  374. throw new ValidateException('订单不存在');
  375. }
  376. if ($staffInfo['verify_status'] != 1) {
  377. throw new ValidateException('您暂无核销权限');
  378. }
  379. $data['clerk_id'] = $staffInfo['uid'];
  380. }
  381. $data['staff_id'] = $staffInfo['id'] ?? 0;
  382. $cartData['staff_id'] = $staffInfo['id'] ?? 0;
  383. } else if ($auth == 2) {//配送员
  384. /** @var DeliveryServiceServices $deliverServiceServices */
  385. $deliverServiceServices = app()->make(DeliveryServiceServices::class);
  386. $deliveryInfo = $deliverServiceServices->getDeliveryInfoByUid($uid, 1, (int)$store_id);
  387. $cartData['delivery_id'] = $deliveryInfo['id'] ?? 0;
  388. }
  389. $data = $this->transaction(function () use ($orderInfo, $staff_id, $data, $cartIds, $cartInfoServices, $cartData, $auth, $cartInfo) {
  390. if ($cartIds) {//选择商品、件数核销
  391. foreach ($cartIds as $cart) {
  392. $write_surplus_num = $cartInfo[$cart['cart_id']]['write_surplus_times'] ?? 0;
  393. if (!isset($cartInfo[$cart['cart_id']]) || !$write_surplus_num) continue;
  394. if ($cart['cart_num'] >= $write_surplus_num) {//拆分完成
  395. $cartData['write_surplus_times'] = 0;
  396. $cartData['is_writeoff'] = 1;
  397. } else {//拆分部分数量
  398. $cartData['write_surplus_times'] = bcsub((string)$write_surplus_num, $cart['cart_num'], 0);
  399. $cartData['is_writeoff'] = 0;
  400. }
  401. //修改原来订单商品信息
  402. $cartInfoServices->update(['oid' => $orderInfo['id'], 'cart_id' => $cart['cart_id']], $cartData);
  403. }
  404. } else {//整单核销
  405. //修改原来订单商品信息
  406. $cartData['is_writeoff'] = 1;
  407. $cartData['write_surplus_times'] = 0;
  408. $cartInfoServices->update(['oid' => $orderInfo['id']], $cartData);
  409. }
  410. if (!$cartInfoServices->count(['oid' => (int)$orderInfo['id'], 'is_writeoff' => 0])) {//全部核销
  411. if ($orderInfo['type'] == 8) {
  412. $data['status'] = 3;
  413. } else {
  414. $data['status'] = 2;
  415. }
  416. /** @var StoreOrderTakeServices $storeOrdeTask */
  417. $storeOrdeTask = app()->make(StoreOrderTakeServices::class);
  418. $re = $storeOrdeTask->storeProductOrderUserTakeDelivery($orderInfo);
  419. if (!$re) {
  420. throw new ValidateException('Write off failure');
  421. }
  422. } else {//部分核销
  423. /** @var StoreOrderCreateServices $storeOrderCreateServices */
  424. $storeOrderCreateServices = app()->make(StoreOrderCreateServices::class);
  425. $data['verify_code'] = $storeOrderCreateServices->getStoreCode();
  426. $data['status'] = 5;
  427. }
  428. if (!$this->dao->update($orderInfo['id'], $data)) {
  429. throw new ValidateException('Write off failure');
  430. }
  431. return $data;
  432. });
  433. event('order.writeoff', [$orderInfo, $auth, $data, $cartIds, $cartInfo]);
  434. } else {//积分订单
  435. if ($orderInfo['status'] == 3) {
  436. throw new ValidateException('订单已核销');
  437. }
  438. $data = ['status' => 3];
  439. /** @var StoreIntegralOrderServices $storeIntegralOrderServices */
  440. $storeIntegralOrderServices = app()->make(StoreIntegralOrderServices::class);
  441. if (!$storeIntegralOrderServices->update($orderInfo['id'], $data)) {
  442. throw new ValidateException('Write off failure');
  443. }
  444. //增加收货订单状态
  445. /** @var StoreIntegralOrderStatusServices $statusService */
  446. $statusService = app()->make(StoreIntegralOrderStatusServices::class);
  447. $statusService->save([
  448. 'oid' => $orderInfo['id'],
  449. 'change_type' => 'take_delivery',
  450. 'change_message' => '已收货',
  451. 'change_time' => time()
  452. ]);
  453. }
  454. return $orderInfo;
  455. }
  456. /**
  457. * 次卡商品核销表单
  458. * @param int $id
  459. * @param int $staffId
  460. * @param int $cart_num
  461. * @return mixed
  462. * @throws \think\db\exception\DataNotFoundException
  463. * @throws \think\db\exception\DbException
  464. * @throws \think\db\exception\ModelNotFoundException
  465. */
  466. public function writeOrderFrom(int $id, int $staffId, int $cart_num = 1)
  467. {
  468. $orderInfo = $this->getOrderCartInfo(0, (int)$id, 1, (int)$staffId);
  469. $cartInfo = $orderInfo['cart_info'] ?? [];
  470. if (!$cartInfo) {
  471. throw new ValidateException('核销订单商品信息不存在');
  472. }
  473. if ($orderInfo['product_type'] != 4) {
  474. throw new ValidateException('订单商品不支持此类型核销');
  475. }
  476. $name = ($cartInfo[0]['write_surplus_times'] ?? 0) . '/'. ($cartInfo[0]['write_times'] ?? 0);
  477. $f[] = Form::hidden('cart_id', $cartInfo[0]['cart_id'] ?? 0);
  478. $f[] = Form::input('name', '核销数', $name)->disabled(true);
  479. $f[] = Form::number('cart_num', '本次核销数量', min(max($cart_num, 1), $cartInfo[0]['write_surplus_times'] ?? 0))->min(1)->max($cartInfo[0]['write_surplus_times'] ?? 1);
  480. return create_form('次卡核销', $f, $this->url('/order/write/form/' . $id), 'POST');
  481. }
  482. }