TOrderServiceImpl.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. package com.ylx.massage.service.impl;
  2. import cn.hutool.core.collection.CollectionUtil;
  3. import com.alibaba.fastjson.JSONArray;
  4. import com.alibaba.fastjson.JSONObject;
  5. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  6. import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
  7. import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
  8. import com.baomidou.mybatisplus.core.toolkit.StringUtils;
  9. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  10. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  11. import com.ylx.common.constant.MassageConstants;
  12. import com.ylx.common.core.domain.R;
  13. import com.ylx.common.exception.ServiceException;
  14. import com.ylx.massage.domain.*;
  15. import com.ylx.massage.domain.vo.CouponReceiveVo;
  16. import com.ylx.massage.enums.BillTypeEnum;
  17. import com.ylx.massage.enums.DiscountTypeEnum;
  18. import com.ylx.massage.enums.JsStatusEnum;
  19. import com.ylx.massage.enums.OrderStatusEnum;
  20. import com.ylx.massage.mapper.TOrderMapper;
  21. import com.ylx.massage.service.*;
  22. import com.ylx.massage.utils.DateTimeUtils;
  23. import com.ylx.massage.utils.MassageUtil;
  24. import com.ylx.massage.utils.OrderNumberGenerator;
  25. import org.apache.commons.compress.utils.Lists;
  26. import org.springframework.stereotype.Service;
  27. import org.springframework.transaction.annotation.Transactional;
  28. import javax.annotation.Resource;
  29. import java.math.BigDecimal;
  30. import java.math.RoundingMode;
  31. import java.time.LocalDateTime;
  32. import java.util.*;
  33. import java.util.stream.Collectors;
  34. /**
  35. * 订单表 服务实现类
  36. */
  37. @Service
  38. public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> implements TOrderService {
  39. @Resource
  40. private TOrderMapper orderMapper;
  41. @Resource
  42. private TWxUserService wxUserService;
  43. @Resource
  44. private TRechargeService rechargeService;
  45. @Resource
  46. private TXiangmuService xiangmuService;
  47. @Resource
  48. private OrderNumberGenerator generator;
  49. @Resource
  50. private TJsService jsService;
  51. @Resource
  52. private TAddressService addressService;
  53. @Resource
  54. private TConsumptionLogService consumptionLogService;
  55. @Resource
  56. private MassageUtil massageUtil;
  57. @Resource
  58. private CouponReceiveService couponReceiveService;
  59. // @Resource
  60. // private TInfoService infoService;
  61. public Boolean isFree(String jsId, BigDecimal distance) {
  62. TJs js = jsService.getById(jsId);
  63. Date date = new Date();
  64. //白天免车费(07.30-20.00)
  65. long current = Long.parseLong(DateTimeUtils.numTime(date));
  66. if (current >= MassageConstants.START_FREE && current <= MassageConstants.END_FREE) {
  67. if (js.getDaytimeMileage().compareTo(distance) >= 0) {
  68. //免车费
  69. return Boolean.TRUE;
  70. } else {
  71. return Boolean.FALSE;
  72. }
  73. } else {
  74. //夜间免车费(20.00-07.30)
  75. if (js.getNigthMileage().compareTo(distance) >= 0) {
  76. //免车费
  77. return Boolean.TRUE;
  78. } else {
  79. return Boolean.FALSE;
  80. }
  81. }
  82. }
  83. /**
  84. * 添加订单
  85. *
  86. * @param order
  87. */
  88. @Override
  89. @Transactional(rollbackFor = Exception.class)
  90. public TOrder addOrder(TOrder order) {
  91. if (StringUtils.isBlank(order.getcJsId())) {
  92. throw new ServiceException("请选择技师");
  93. }
  94. if (order.getcGoods().isEmpty()) {
  95. throw new ServiceException("请选择项目");
  96. }
  97. //计算车费
  98. if (order.getDistance() != null) {
  99. //判断是否可以免车费
  100. if (!this.isFree(order.getcJsId(), order.getDistance())) {
  101. BigDecimal bigDecimal = massageUtil.calculateTaxiFare(order.getDistance());
  102. order.setFare(bigDecimal.setScale(MassageConstants.INTEGER_TWO, RoundingMode.HALF_UP));
  103. }
  104. }
  105. //优惠卷减免
  106. List<CouponReceiveVo> coupons = couponReceiveService.getByOpenId(order.getcOpenId());
  107. BigDecimal preferential = this.setCoupon(coupons);
  108. order.setPreferential(preferential);
  109. //订单价格
  110. List<TXiangmu> list = JSONObject.parseArray(order.getcGoods().toJSONString(), TXiangmu.class);
  111. BigDecimal sum = list.stream().map(TXiangmu::getSum).reduce(BigDecimal.ZERO, BigDecimal::add);
  112. order.setdTotalMoney(sum);
  113. //总价 = 订单 + 车费 - 优惠
  114. order.setTotalPrice(sum.add(Optional.ofNullable(order.getFare()).orElse(BigDecimal.ZERO)).subtract(preferential));
  115. if (order.getOrderType() == 2) {
  116. //升级订单 补差价
  117. TOrder partOrder = this.getByNo(order.getParentNo());
  118. order.setPriceDifference(order.getTotalPrice().subtract(partOrder.getTotalPrice()));
  119. }
  120. //获取用户默认地址
  121. TAddress address = addressService.getByOpenId(order.getcOpenId());
  122. if (address == null) {
  123. throw new ServiceException("请先添加地址");
  124. }
  125. order.setcAddress(address.getAddress());
  126. order.setcPhone(address.getPhone());
  127. order.setcName(address.getUserName());
  128. order.setAtlasAdd(address.getAtlasAdd());
  129. order.setOrderNo(generator.generateNextOrderNumber(OrderNumberGenerator.KEY_PREFIX_ORDER));
  130. order.setnStatus(OrderStatusEnum.WAIT_PAY.getCode());
  131. order.setDtCreateTime(LocalDateTime.now());
  132. save(order);
  133. return order;
  134. }
  135. private BigDecimal setCoupon(List<CouponReceiveVo> coupons) {
  136. //过滤过期的优惠券
  137. coupons = coupons.stream().filter(coupon -> coupon.getExpirationTime().after(new Date())).collect(Collectors.toList());
  138. //无门槛优惠券
  139. List<CouponReceiveVo> collect = coupons.stream().filter(coupon -> coupon.getDiscountType().equals(DiscountTypeEnum.NO_THRESHOLD.getCode())).collect(Collectors.toList());
  140. //删除优惠卷
  141. couponReceiveService.removeCoupons(collect);
  142. //计算优惠金额
  143. return collect.stream().map(CouponReceiveVo::getDiscountValue).reduce(BigDecimal.ZERO, BigDecimal::add);
  144. }
  145. @Override
  146. public void payNotifyOrder(String outTradeNo) {
  147. TOrder orderNew = this.getByNo(outTradeNo);
  148. TWxUser user = wxUserService.getByOpenId(orderNew.getcOpenId());
  149. orderPayManage(user, orderNew);
  150. }
  151. /**
  152. * 支付订单
  153. *
  154. * @param order
  155. */
  156. @Override
  157. public R payOrder(TOrder order) throws Exception {
  158. // 根据orderid查询订单信息
  159. TOrder orderNew = getById(order.getcId());
  160. if (!orderNew.getnStatus().equals(OrderStatusEnum.WAIT_PAY.getCode())) {
  161. throw new ServiceException("该订单已经支付或者超时被取消");
  162. }
  163. if (StringUtils.isBlank(orderNew.getParentNo())) {
  164. TJs js = jsService.getById(orderNew.getcJsId());
  165. if (null == js || js.getnStatus().equals(JsStatusEnum.JS_SERVICE.getCode())) {
  166. throw new ServiceException("该技师已在服务中请重新下单");
  167. }
  168. }
  169. //判断支付方式
  170. if (order.getPayType().equals(MassageConstants.INTEGER_ONE)) {
  171. //微信支付
  172. R resp = rechargeService.getPay(orderNew.getOrderNo(), orderNew.getTotalPrice(), orderNew.getcOpenId(), BillTypeEnum.WX_PAY.getInfo(),BillTypeEnum.WX_PAY.getCode().toString());
  173. return resp;
  174. }
  175. // 从对应账户扣款
  176. TWxUser user = wxUserService.getByOpenId(orderNew.getcOpenId());
  177. if (null == user) {
  178. throw new ServiceException("用户不存在");
  179. }
  180. if (user.getdBalance().compareTo(orderNew.getTotalPrice()) < MassageConstants.INTEGER_ZERO) {
  181. throw new ServiceException("账户金额不够请充值");
  182. } else {
  183. orderPayManage(user, orderNew);
  184. return R.ok();
  185. }
  186. }
  187. @Transactional(rollbackFor = Exception.class)
  188. public void orderPayManage(TWxUser user, TOrder orderNew) {
  189. // 更新用户金额 及下单此时
  190. TWxUser paramUser = new TWxUser();
  191. paramUser.setcOpenid(user.getcOpenid());
  192. if (!orderNew.getPayType().equals(MassageConstants.INTEGER_ONE)){
  193. paramUser.setdBalance(user.getdBalance().subtract(orderNew.getTotalPrice()));
  194. }
  195. paramUser.setdMoney(user.getdMoney().add(orderNew.getTotalPrice()));
  196. paramUser.setnNum(user.getnNum() + MassageConstants.INTEGER_ZERO);
  197. paramUser.setId(user.getId());
  198. wxUserService.updateById(paramUser);
  199. //增加消费记录
  200. TConsumptionLog tConsumptionLog = new TConsumptionLog();
  201. tConsumptionLog.setAmount(orderNew.getTotalPrice().negate());
  202. tConsumptionLog.setBillNo(orderNew.getOrderNo());
  203. tConsumptionLog.setOpenId(orderNew.getcOpenId());
  204. if (!orderNew.getPayType().equals(MassageConstants.INTEGER_ONE)){
  205. tConsumptionLog.setBillType(BillTypeEnum.BALANCE_PAYMENT.getCode());
  206. tConsumptionLog.setNote("余额支付");
  207. }else{
  208. tConsumptionLog.setBillType(BillTypeEnum.WX_PAY.getCode());
  209. tConsumptionLog.setNote("微信支付");
  210. }
  211. consumptionLogService.save(tConsumptionLog);
  212. // 更新项目数据
  213. JSONArray objects = orderNew.getcGoods();
  214. objects.forEach(item -> {
  215. UpdateWrapper<TXiangmu> wrapper = new UpdateWrapper<>();
  216. // 获取参数
  217. wrapper.lambda().eq(TXiangmu::getcId, ((JSONObject) item).getString("cId"));
  218. // 设置数量
  219. wrapper.setSql(" n_sale_number = n_sale_number + " + ((JSONObject) item).getInteger("number"));
  220. xiangmuService.update(wrapper);
  221. });
  222. TOrder orderParam = new TOrder();
  223. orderParam.setcId(orderNew.getcId());
  224. orderParam.setnStatus(OrderStatusEnum.WAIT_JD.getCode());
  225. //加钟的订单支付完直接服务中
  226. if (StringUtils.isNotBlank(orderNew.getParentNo())) {
  227. orderParam.setnStatus(OrderStatusEnum.SERVICE.getCode());
  228. }
  229. // orderParam.setnStatus(OrderStatusEnum.SERVICE.getCode());
  230. //更新及技师状态
  231. updateJs(orderNew);
  232. updateById(orderParam);
  233. }
  234. /**
  235. * 拒绝订单
  236. *
  237. * @param order
  238. */
  239. @Override
  240. public Boolean jujue(TOrder order) {
  241. TOrder orderNew = getById(order.getcId());
  242. TWxUser user = wxUserService.getById(orderNew.getcOpenId());
  243. // 更新用户金额 及下单此时
  244. TWxUser paramUser = new TWxUser();
  245. paramUser.setcOpenid(user.getcOpenid());
  246. // 金额归还对应账户
  247. paramUser.setdBalance(user.getdBalance().add(orderNew.getdTotalMoney()));
  248. // 消费金额对应减少
  249. paramUser.setdMoney(user.getdMoney().subtract(orderNew.getdTotalMoney()));
  250. // 下单次数减一
  251. paramUser.setnNum(user.getnNum() - MassageConstants.INTEGER_ONE);
  252. wxUserService.updateById(paramUser);
  253. // 更新项目数据
  254. JSONArray objects = orderNew.getcGoods();
  255. objects.forEach(item -> {
  256. UpdateWrapper<TXiangmu> wrapper = new UpdateWrapper<>();
  257. // 获取参数
  258. wrapper.lambda().eq(TXiangmu::getcId, ((JSONObject) item).getString("cId"));
  259. // 设置数量
  260. wrapper.setSql(" n_sale_number = n_sale_number - " + ((JSONObject) item).getInteger("number"));
  261. xiangmuService.update(wrapper);
  262. });
  263. TOrder orderParam = new TOrder();
  264. orderParam.setcId(orderNew.getcId());
  265. orderParam.setnStatus(OrderStatusEnum.REFUSE.getCode());
  266. return updateById(orderParam);
  267. }
  268. /**
  269. * 确认服务完成
  270. *
  271. * @param order
  272. * @return
  273. */
  274. @Override
  275. @Transactional(rollbackFor = Exception.class)
  276. public Boolean confirm(TOrder order) {
  277. // 获取订单信息
  278. TOrder orderNew = getById(order);
  279. // 更新技师信息
  280. TJs jsParam = new TJs();
  281. jsParam.setId(orderNew.getcJsId());
  282. jsParam.setnStatus(JsStatusEnum.JS_SERVICEABLE.getCode());
  283. // 更新技师状态
  284. jsService.updateById(jsParam);
  285. // 更新技师钱包金额
  286. TJs jsById = jsService.getById(orderNew.getcJsId());
  287. // 获取技师抽成
  288. BigDecimal multiply = orderNew.getdTotalMoney().multiply(new BigDecimal(jsById.getnBili()));
  289. multiply = multiply.divide(new BigDecimal(100), MassageConstants.INTEGER_TWO, RoundingMode.HALF_UP);
  290. // 获取技师所对应的用户
  291. TWxUser jsUser = wxUserService.getByOpenId(jsById.getcOpenId());
  292. // 更新余额
  293. jsUser.setdBalance(jsUser.getdBalance().add(multiply));
  294. // 更新总钱数
  295. jsUser.setdAllMoney(jsUser.getdAllMoney().add(multiply));
  296. wxUserService.updateById(jsUser);
  297. //增加消费记录
  298. TConsumptionLog tConsumptionLog = new TConsumptionLog();
  299. tConsumptionLog.setAmount(multiply);
  300. tConsumptionLog.setBillNo(orderNew.getOrderNo());
  301. tConsumptionLog.setOpenId(jsUser.getcOpenid());
  302. tConsumptionLog.setBillType(BillTypeEnum.INCOME.getCode());
  303. tConsumptionLog.setNote("技师收益");
  304. consumptionLogService.save(tConsumptionLog);
  305. // // 如果该技师有推荐人员
  306. // if(StringUtils.isNotBlank(jsUser.getcUpUser())){
  307. // // 获取技师上级对应的用户
  308. // TWxUser jsUp = wxUserService.getById(jsUser.getcUpUser());
  309. // // 获取基本信息
  310. // List<TInfo> list = infoService.list();
  311. // BigDecimal up = orderNew.getdTotalMoney().multiply(new BigDecimal(list.get(0).getnBili()));
  312. // up = up.divide(new BigDecimal(100),2, RoundingMode.HALF_UP);
  313. // // 更新余额
  314. // jsUp.setdBalance(jsUp.getdBalance().add(up));
  315. // // 更新总钱数
  316. // jsUp.setdAllMoney(jsUp.getdAllMoney().add(up));
  317. // wxUserService.updateById(jsUp);
  318. // }
  319. // 更新订单
  320. orderNew.setnStatus(OrderStatusEnum.WAIT_EVALUATE.getCode());
  321. return updateById(orderNew);
  322. }
  323. /**
  324. * 取消订单
  325. *
  326. * @param order
  327. * @return
  328. */
  329. @Override
  330. public Boolean cancle(TOrder order) {
  331. // 获取订单信息
  332. // 根据orderid查询订单信息
  333. TOrder orderNew = getById(order.getcId());
  334. //待接单
  335. // if (Objects.equals(orderNew.getnStatus(), OrderStatusEnum.WAIT_JD.getCode())) {
  336. // TWxUser user = wxUserService.getById(orderNew.getcOpenId());
  337. // // 更新用户金额 及下单此时
  338. // TWxUser paramUser = new TWxUser();
  339. // paramUser.setcOpenid(user.getcOpenid());
  340. // // 金额归还对应账户
  341. // paramUser.setdBalance(user.getdBalance().add(orderNew.getdTotalMoney()));
  342. // // 消费金额对应减少
  343. // paramUser.setdMoney(user.getdMoney().subtract(orderNew.getdTotalMoney()));
  344. // // 下单次数减一
  345. // paramUser.setnNum(user.getnNum() - MassageConstants.INTEGER_ONE);
  346. // wxUserService.updateById(paramUser);
  347. //
  348. // // 更新项目数据
  349. // JSONArray objects = orderNew.getcGoods();
  350. // objects.forEach(item -> {
  351. // UpdateWrapper<TXiangmu> wrapper = new UpdateWrapper<>();
  352. // // 获取参数
  353. // wrapper.lambda().eq(TXiangmu::getcId, ((JSONObject) item).getString("cId"));
  354. // // 设置数量
  355. // wrapper.setSql(" n_sale_number = n_sale_number - " + ((JSONObject) item).getInteger("number"));
  356. // xiangmuService.update(wrapper);
  357. // });
  358. // TOrder orderParam = new TOrder();
  359. // orderParam.setcId(orderNew.getcId());
  360. // orderParam.setnStatus(OrderStatusEnum.CANCEL.getCode());
  361. // return updateById(orderParam);
  362. //
  363. // } else
  364. if (Objects.equals(orderNew.getnStatus(), OrderStatusEnum.WAIT_PAY.getCode())) {
  365. //待付款
  366. TOrder orderParam = new TOrder();
  367. orderParam.setcId(orderNew.getcId());
  368. orderParam.setnStatus(OrderStatusEnum.CANCEL.getCode());
  369. return updateById(orderParam);
  370. } else {
  371. return false;
  372. }
  373. }
  374. @Override
  375. public TOrder getByNo(String orderNo) {
  376. LambdaQueryWrapper<TOrder> objectLambdaQueryWrapper = new LambdaQueryWrapper<>();
  377. return this.getOne(objectLambdaQueryWrapper.eq(TOrder::getOrderNo, orderNo));
  378. }
  379. private TOrder gettOrder(TOrder order) {
  380. LambdaUpdateWrapper<TOrder> objectLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
  381. objectLambdaUpdateWrapper.eq(TOrder::getOrderNo, order.getOrderNo());
  382. return this.getOne(objectLambdaUpdateWrapper);
  383. }
  384. @Override
  385. public Page<TOrder> getAll(Page<TOrder> page, TOrder param) {
  386. Page<TOrder> orderPage = orderMapper.getAll(page, param);
  387. if (orderPage != null && CollectionUtil.isNotEmpty(orderPage.getRecords())) {
  388. ArrayList<TOrder> orders = Lists.newArrayList();
  389. orderPage.getRecords().forEach(order -> {
  390. order.setStatusName(OrderStatusEnum.getDescByCode(order.getnStatus()));
  391. orders.add(order);
  392. });
  393. orderPage.setRecords(orders);
  394. }
  395. return orderPage;
  396. }
  397. @Override
  398. @Transactional(rollbackFor = Exception.class)
  399. public void takingOrders(TOrder order) {
  400. if (order == null || StringUtils.isBlank(order.getcId())) {
  401. throw new IllegalArgumentException("订单对象不能为空");
  402. }
  403. TOrder orderNew = this.getById(order);
  404. // 检查订单对应的技师是否存在
  405. // updateJs (orderNew);
  406. // 更新订单状态
  407. TOrder orderParam = new TOrder();
  408. orderParam.setcId(order.getcId());
  409. orderParam.setnStatus(OrderStatusEnum.RECEIVED_ORDER.getCode());
  410. this.updateById(orderParam);
  411. }
  412. private void updateJs(TOrder orderNew) {
  413. TJs js = jsService.getById(orderNew.getcJsId());
  414. if (js == null) {
  415. throw new IllegalStateException("无法找到对应的技师");
  416. }
  417. // 更新技师状态
  418. js.setnStatus(JsStatusEnum.JS_SERVICE.getCode());
  419. // 确保js.getnNum()不为null,避免 NullPointerException
  420. int num = js.getnNum() == null ? 0 : js.getnNum();
  421. js.setnNum(num + MassageConstants.INTEGER_ONE);
  422. jsService.updateById(js);
  423. }
  424. }