|
|
@@ -0,0 +1,367 @@
|
|
|
+package com.sapit.client.app.user.controller.order;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.sql.Timestamp;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+import javax.servlet.http.HttpServletRequest;
|
|
|
+
|
|
|
+import org.apache.commons.lang.StringUtils;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.web.bind.annotation.PostMapping;
|
|
|
+import org.springframework.web.bind.annotation.RequestMapping;
|
|
|
+import org.springframework.web.bind.annotation.RestController;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.sapit.client.app.user.service.order.OrderApiService;
|
|
|
+import com.sapit.client.app.user.service.system.CommonApiService;
|
|
|
+import com.sapit.common.bean.mobile.SettingBean;
|
|
|
+import com.sapit.common.bean.mobile.StoreGoodsModelBean;
|
|
|
+import com.sapit.common.bean.system.WxPayBean;
|
|
|
+import com.sapit.common.constant.ReturnCode;
|
|
|
+import com.sapit.common.entity.order.BuOrder;
|
|
|
+import com.sapit.common.entity.order.BuOrderDetail;
|
|
|
+import com.sapit.common.framwork.ResultBean;
|
|
|
+import com.sapit.common.search.order.BuOrderSearchBean;
|
|
|
+import com.sapit.common.util.ApiUtil;
|
|
|
+import com.sapit.common.util.SystemParam;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 用户端 订单 Controller
|
|
|
+ *
|
|
|
+ */
|
|
|
+@RestController
|
|
|
+@RequestMapping(value = "orderApiV2", produces = "application/json")
|
|
|
+public class OrderApiCtlV2 {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private OrderApiService orderApiService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private CommonApiService commonApiService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private RedisLockService redisLockService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private WxPayV2Service wxPayV2Service;
|
|
|
+
|
|
|
+ /* 订单锁过期时间(秒) */
|
|
|
+ private static final long LOCK_EXPIRE = 10L;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 下单处理:校验商品与店铺、计算金额、将订单快照写入 Redis,等待支付
|
|
|
+ */
|
|
|
+ @PostMapping(value = "/createOrder")
|
|
|
+ public ResultBean createOrder(Long memberId, Long sourceType, String addressInfo, String requireTime,
|
|
|
+ String goodsstr, Long orderType, String timestamp, String sign, String rmk) {
|
|
|
+ ResultBean bean = new ResultBean();
|
|
|
+ // 参数基本验证
|
|
|
+ if (memberId == null || sign == null || timestamp == null) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.PARAM_WRONG);
|
|
|
+ bean.getRtnBean().setRtnMsg(ReturnCode.getName(ReturnCode.PARAM_WRONG));
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+ // 签名验证
|
|
|
+ if (!ApiUtil.validate(memberId + timestamp + SystemParam.secretKey, sign)) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.SIGN_WRONG);
|
|
|
+ bean.getRtnBean().setRtnMsg(ReturnCode.getName(ReturnCode.SIGN_WRONG));
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+ // 平台营业状态校验
|
|
|
+ Long areaId = commonApiService.getSysAreaId();
|
|
|
+ SettingBean setting = commonApiService.getSysSetting(areaId);
|
|
|
+ if (setting.getSysStatus() != null && setting.getSysStatus().equals(2L)) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.SYSTEMERR);
|
|
|
+ bean.getRtnBean().setRtnMsg("本平台已暂停营业,请待正常营业后,再行下单");
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<BuOrderDetail> detaillist = new ArrayList<>();
|
|
|
+ JSONArray list = JSONArray.parseArray(goodsstr);
|
|
|
+
|
|
|
+ Long storeId = null;
|
|
|
+ for (int i = 0; i < list.size(); i++) {
|
|
|
+ JSONObject info = list.getJSONObject(i);
|
|
|
+ String modelIdStr = info.getString("modelId");
|
|
|
+
|
|
|
+ StoreGoodsModelBean model = orderApiService
|
|
|
+ .getStoreGoodsModelInfo(Long.valueOf(modelIdStr.replace("t", "")));
|
|
|
+
|
|
|
+ Long buyCount = info.getLong("modelCount");
|
|
|
+
|
|
|
+ if (buyCount <= 0) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.FAILED);
|
|
|
+ bean.getRtnBean().setRtnMsg("商品数量有误,请重新选择商品");
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+ if (model.getStoreStatus().equals(2L)) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.FAILED);
|
|
|
+ bean.getRtnBean().setRtnMsg("本店铺已冻结,不能下单");
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+ if (!model.getBusinessStatus().equals(1L)) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.FAILED);
|
|
|
+ bean.getRtnBean().setRtnMsg("本店铺已休息,不能下单");
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+ if (model.getGoodsStatus() == 0L) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.FAILED);
|
|
|
+ bean.getRtnBean().setRtnMsg(model.getGoodsName() + "已经下架,请选购其他商品");
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+ // 校验最小购买数量
|
|
|
+ if (buyCount < model.getMiniNum()) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.FAILED);
|
|
|
+ bean.getRtnBean().setRtnMsg(model.getGoodsName() + "小于当前商品的最小购买数量,请重新选择数量");
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+
|
|
|
+ BuOrderDetail detail = new BuOrderDetail();
|
|
|
+ detail.setGoodsId(model.getGoodsId());
|
|
|
+ detail.setGoodsName(model.getGoodsName());
|
|
|
+
|
|
|
+ if (modelIdStr.startsWith("t") && !model.getModelCostPrice().equals(model.getModelSalePrice())) {
|
|
|
+ detail.setModelId(modelIdStr);
|
|
|
+ detail.setPrice(model.getModelCostPrice());
|
|
|
+ detail.setSalesPrice(model.getModelSalePrice());
|
|
|
+ } else {
|
|
|
+ detail.setModelId(modelIdStr.replace("t", ""));
|
|
|
+ detail.setPrice(model.getModelCostPrice());
|
|
|
+ detail.setSalesPrice(model.getModelCostPrice());
|
|
|
+ }
|
|
|
+
|
|
|
+ detail.setModelName(model.getModelName());
|
|
|
+ detail.setPropertys(info.getString("paramsStr"));
|
|
|
+ detail.setBuyCount(buyCount);
|
|
|
+ detail.setLimitedNum(model.getLimitedNum());
|
|
|
+ detail.setPackingFee(model.getPackingFee());
|
|
|
+ storeId = model.getStoreId();
|
|
|
+
|
|
|
+ detaillist.add(detail);
|
|
|
+ }
|
|
|
+
|
|
|
+ JSONObject addressinfo = JSON.parseObject(addressInfo);
|
|
|
+ BuOrder order = new BuOrder();
|
|
|
+ order.setMemberId(memberId);
|
|
|
+ if (addressinfo.containsKey("province") && !StringUtils.equals(addressinfo.getString("province"), "null")) {
|
|
|
+ order.setProvince(addressinfo.getLong("province"));
|
|
|
+ }
|
|
|
+ if (addressinfo.containsKey("city") && !StringUtils.equals(addressinfo.getString("city"), "null")) {
|
|
|
+ order.setCity(addressinfo.getLong("city"));
|
|
|
+ }
|
|
|
+ if (addressinfo.containsKey("county") && !StringUtils.equals(addressinfo.getString("county"), "null")) {
|
|
|
+ order.setCounty(addressinfo.getLong("county"));
|
|
|
+ }
|
|
|
+ if (addressinfo.containsKey("roomNumber") && !StringUtils.equals(addressinfo.getString("roomNumber"), "null")) {
|
|
|
+ order.setRoomNumber(addressinfo.getString("roomNumber"));
|
|
|
+ }
|
|
|
+ if (addressinfo.containsKey("address") && !StringUtils.equals(addressinfo.getString("address"), "null")) {
|
|
|
+ order.setOrderAddress(addressinfo.getString("address").replace("+", "+").replace("\"", "“").replace("'", "")
|
|
|
+ .replace("{", "").replace("}", ""));
|
|
|
+ }
|
|
|
+ order.setOrderName(addressinfo.getString("addressName"));
|
|
|
+ order.setOrderTel(addressinfo.getString("addressTel"));
|
|
|
+ order.setOrderType(orderType);
|
|
|
+ order.setSourceType(sourceType);
|
|
|
+ order.setStoreId(storeId);
|
|
|
+ order.setRequireDate(Timestamp.valueOf(requireTime));
|
|
|
+
|
|
|
+ if (order.getCounty() != null) {
|
|
|
+ order.setAddressId(order.getCounty());
|
|
|
+ } else if (order.getCity() != null) {
|
|
|
+ order.setAddressId(order.getCity());
|
|
|
+ } else if (order.getProvince() != null) {
|
|
|
+ order.setAddressId(order.getProvince());
|
|
|
+ }
|
|
|
+
|
|
|
+ order.setCustomerMes(rmk);
|
|
|
+
|
|
|
+ return orderApiService.createOrder(order, order, detaillist);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 微信支付:加锁 -> 判重 -> 取 Redis 订单 -> 统一下单 -> 落库 -> 返回支付参数
|
|
|
+ */
|
|
|
+ @PostMapping(value = "/wxPay")
|
|
|
+ public ResultBean wxPay(HttpServletRequest request, String orderCode, Long memberId, String openid,
|
|
|
+ String timestamp, String sign, String rmk) {
|
|
|
+ ResultBean bean = new ResultBean();
|
|
|
+ // 参数基本验证
|
|
|
+ if (orderCode == null || memberId == null || sign == null || timestamp == null) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.PARAM_WRONG);
|
|
|
+ bean.getRtnBean().setRtnMsg(ReturnCode.getName(ReturnCode.PARAM_WRONG));
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+ // 签名验证
|
|
|
+ if (!ApiUtil.validate(memberId + timestamp + SystemParam.secretKey, sign)) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.SIGN_WRONG);
|
|
|
+ bean.getRtnBean().setRtnMsg(ReturnCode.getName(ReturnCode.SIGN_WRONG));
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 分布式锁:同一 orderCode 仅允许一个请求进入
|
|
|
+ String lockKey = "order:lock" + orderCode;
|
|
|
+ if (!redisLockService.tryLock(lockKey, LOCK_EXPIRE)) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.FAILED);
|
|
|
+ bean.getRtnBean().setRtnMsg("订单处理中,请稍后重试");
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ if (orderApiService.isHaveOrder(orderCode)) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.FAILED);
|
|
|
+ bean.getRtnBean().setRtnMsg("订单已经存在");
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+
|
|
|
+ String orderInfo = orderApiService.getPayedOrderFromRedis(orderCode);
|
|
|
+ if (orderInfo == null || "".equals(orderInfo)) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.FAILED);
|
|
|
+ bean.getRtnBean().setRtnMsg("数据不存在");
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 累加订单金额(分)
|
|
|
+ Long orderMoney = 0L;
|
|
|
+ JSONArray info = JSONArray.parseArray(orderInfo);
|
|
|
+ for (int i = 0; i < info.size(); i++) {
|
|
|
+ JSONObject obj = info.getJSONObject(i);
|
|
|
+ orderMoney = orderMoney + obj.getLong("orderfee");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 统一下单获取 prepay_id
|
|
|
+ String prepayId = wxPayV2Service.prepay(orderCode, orderMoney, openid);
|
|
|
+ if (prepayId == null) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.SYSTEMERR);
|
|
|
+ bean.getRtnBean().setRtnMsg("下单错误,请稍后尝试!");
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 通过 Redis 快照真正创建订单及明细
|
|
|
+ ResultBean makeOrderResult;
|
|
|
+ try {
|
|
|
+ makeOrderResult = orderApiService.makeOrder(orderInfo, prepayId, rmk);
|
|
|
+ } catch (RuntimeException e) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.SYSTEMERR);
|
|
|
+ bean.getRtnBean().setRtnMsg("订单创建失败,请重新下单!");
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+ if (makeOrderResult.getRtnBean().getRtnCode() != 0) {
|
|
|
+ return makeOrderResult;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 生成小程序端支付数据
|
|
|
+ WxPayBean wxPayBean = wxPayV2Service.buildPayParams(prepayId);
|
|
|
+ bean.setObj(wxPayBean);
|
|
|
+ return bean;
|
|
|
+ } finally {
|
|
|
+ redisLockService.unlock(lockKey);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 零元支付(免微信支付的订单落地)
|
|
|
+ */
|
|
|
+ @PostMapping(value = "/noMoneyPay")
|
|
|
+ public ResultBean noMoneyPay(HttpServletRequest request, String orderCode, Long memberId, String openid,
|
|
|
+ String timestamp, String sign, String rmk) {
|
|
|
+ ResultBean bean = new ResultBean();
|
|
|
+ // 参数基本验证
|
|
|
+ if (orderCode == null || memberId == null || sign == null || timestamp == null) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.PARAM_WRONG);
|
|
|
+ bean.getRtnBean().setRtnMsg(ReturnCode.getName(ReturnCode.PARAM_WRONG));
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+ // 签名验证
|
|
|
+ if (!ApiUtil.validate(memberId + timestamp + SystemParam.secretKey, sign)) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.SIGN_WRONG);
|
|
|
+ bean.getRtnBean().setRtnMsg(ReturnCode.getName(ReturnCode.SIGN_WRONG));
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (orderApiService.isHaveOrder(orderCode)) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.FAILED);
|
|
|
+ bean.getRtnBean().setRtnMsg("订单已经存在");
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+
|
|
|
+ String orderInfo = orderApiService.getPayedOrderFromRedis(orderCode);
|
|
|
+ if (orderInfo == null || "".equals(orderInfo)) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.FAILED);
|
|
|
+ bean.getRtnBean().setRtnMsg("数据不存在");
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ ResultBean makeOrderResult = orderApiService.noMoneyPay(orderInfo, rmk);
|
|
|
+ if (makeOrderResult.getRtnBean().getRtnCode() != 0) {
|
|
|
+ return makeOrderResult;
|
|
|
+ }
|
|
|
+ return bean;
|
|
|
+ } catch (RuntimeException e) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.SYSTEMERR);
|
|
|
+ bean.getRtnBean().setRtnMsg("订单创建失败,请重新下单!");
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 再次微信支付
|
|
|
+ */
|
|
|
+ @PostMapping(value = "/reWxPay")
|
|
|
+ public ResultBean reWxPay(HttpServletRequest request, String groupOrderCode, Long memberId, Long wxFlag,
|
|
|
+ String openid, String timestamp, String sign) {
|
|
|
+ ResultBean bean = new ResultBean();
|
|
|
+ // 参数基本验证
|
|
|
+ if (groupOrderCode == null || memberId == null || sign == null || timestamp == null) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.PARAM_WRONG);
|
|
|
+ bean.getRtnBean().setRtnMsg(ReturnCode.getName(ReturnCode.PARAM_WRONG));
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+ // 签名验证
|
|
|
+ if (!ApiUtil.validate(memberId + timestamp + SystemParam.secretKey, sign)) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.SIGN_WRONG);
|
|
|
+ bean.getRtnBean().setRtnMsg(ReturnCode.getName(ReturnCode.SIGN_WRONG));
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+
|
|
|
+ BuOrderSearchBean searchBean = new BuOrderSearchBean();
|
|
|
+ searchBean.setOrderCode(groupOrderCode);
|
|
|
+ List<BuOrder> orderList = orderApiService.getOrderListForUserAll(searchBean);
|
|
|
+
|
|
|
+ if (orderList.isEmpty()) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.FAILED);
|
|
|
+ bean.getRtnBean().setRtnMsg("订单不存在");
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (orderList.get(0).getPrepayId() != null) {
|
|
|
+ // 已存在 prepay_id,直接重新生成支付参数
|
|
|
+ WxPayBean wxPayBean = wxPayV2Service.buildPayParams(orderList.get(0).getPrepayId());
|
|
|
+ bean.setObj(wxPayBean);
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 累加订单金额并转成分
|
|
|
+ BigDecimal orderMoney = new BigDecimal(0);
|
|
|
+ for (int i = 0; i < orderList.size(); i++) {
|
|
|
+ orderMoney = orderMoney.add(new BigDecimal(orderList.get(i).getOrderFee()));
|
|
|
+ }
|
|
|
+ Long totalfee = orderMoney.multiply(new BigDecimal("100")).longValue();
|
|
|
+
|
|
|
+ String prepayId = wxPayV2Service.prepay(groupOrderCode, totalfee, openid);
|
|
|
+ if (prepayId == null) {
|
|
|
+ bean.getRtnBean().setRtnCode(ReturnCode.SYSTEMERR);
|
|
|
+ bean.getRtnBean().setRtnMsg("微信支付下单错误,请稍后尝试!");
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+ orderApiService.updateOrderPayedInfo(groupOrderCode, prepayId);
|
|
|
+
|
|
|
+ WxPayBean wxPayBean = wxPayV2Service.buildPayParams(prepayId);
|
|
|
+ bean.setObj(wxPayBean);
|
|
|
+ return bean;
|
|
|
+ }
|
|
|
+}
|