下单接口完善,添加支付成功回调及自动取消超时订单接口

This commit is contained in:
zhh
2018-09-05 17:05:11 +08:00
parent cae7f7e4f8
commit cbdb93ee3f
21 changed files with 872 additions and 423 deletions

View File

@@ -1,7 +1,10 @@
package com.macro.mall.portal.component;
import com.macro.mall.portal.domain.CommonResult;
import com.macro.mall.portal.service.OmsPortalOrderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@@ -12,13 +15,16 @@ import org.springframework.stereotype.Component;
@Component
public class OrderTimeOutCancelTask {
private Logger LOGGER =LoggerFactory.getLogger(OrderTimeOutCancelTask.class);
@Autowired
private OmsPortalOrderService portalOrderService;
/**
* cron表达式Seconds Minutes Hours DayofMonth Month DayofWeek [Year]
* 每10分钟扫描一次扫描超时时间*2时间内所下订单,如果没支付则取消该订单
* 每10分钟扫描一次扫描设定超时时间之前下的订单,如果没支付则取消该订单
*/
@Scheduled(cron = "0 0/10 * ? * ?")
private void cancelTimeOutOrder(){
LOGGER.info("取消订单并根据sku编号释放锁定库存");
CommonResult result = portalOrderService.cancelTimeOutOrder();
LOGGER.info("取消订单并根据sku编号释放锁定库存:{}",result);
}
}

View File

@@ -8,10 +8,7 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.*;
/**
* 订单管理Controller
@@ -37,4 +34,17 @@ public class OmsPortalOrderController {
public Object generateOrder(@RequestBody OrderParam orderParam){
return portalOrderService.generateOrder(orderParam);
}
@ApiOperation("支付成功的回调")
@RequestMapping(value = "/paySuccess",method = RequestMethod.POST)
@ResponseBody
public Object paySuccess(@RequestParam Long orderId){
return portalOrderService.paySuccess(orderId);
}
@ApiOperation("自动取消超时订单")
@RequestMapping(value = "/cancelTimeOutOrder",method = RequestMethod.POST)
@ResponseBody
public Object cancelTimeOutOrder(){
return portalOrderService.cancelTimeOutOrder();
}
}

View File

@@ -0,0 +1,40 @@
package com.macro.mall.portal.dao;
import com.macro.mall.model.OmsOrderItem;
import com.macro.mall.portal.domain.OmsOrderDetail;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 前台订单自定义Dao
* Created by macro on 2018/9/4.
*/
public interface PortalOrderDao {
/**
* 获取订单及下单商品详情
*/
OmsOrderDetail getDetail(@Param("orderId") Long orderId);
/**
* 修改 pms_sku_stock表的锁定库存及真实库存
*/
int updateSkuStock(@Param("itemList") List<OmsOrderItem> orderItemList);
/**
* 获取超时订单
* @param minute 超时时间(分)
*/
List<OmsOrderDetail> getTimeOutOrders(@Param("minute") Integer minute);
/**
* 批量修改订单状态
*/
int updateOrderStatus(@Param("ids") List<Long> ids,@Param("status") Integer status);
/**
* 解除取消订单的库存锁定
*/
int releaseSkuStockLock(@Param("itemList") List<OmsOrderItem> orderItemList);
}

View File

@@ -0,0 +1,22 @@
package com.macro.mall.portal.domain;
import com.macro.mall.model.OmsOrder;
import com.macro.mall.model.OmsOrderItem;
import java.util.List;
/**
* 包含订单商品信息的订单详情
* Created by macro on 2018/9/4.
*/
public class OmsOrderDetail extends OmsOrder {
private List<OmsOrderItem> orderItemList;
public List<OmsOrderItem> getOrderItemList() {
return orderItemList;
}
public void setOrderItemList(List<OmsOrderItem> orderItemList) {
this.orderItemList = orderItemList;
}
}

View File

@@ -20,4 +20,16 @@ public interface OmsPortalOrderService {
*/
@Transactional
CommonResult generateOrder(OrderParam orderParam);
/**
* 支付成功后的回调
*/
@Transactional
CommonResult paySuccess(Long orderId);
/**
* 自动取消超时订单
*/
@Transactional
CommonResult cancelTimeOutOrder();
}

View File

@@ -25,4 +25,11 @@ public interface RedisService {
* 删除数据
*/
void remove(String key);
/**
* 自增操作
* @param delta 自增步长
*/
Long increment(String key, long delta);
}

View File

@@ -14,6 +14,11 @@ public interface UmsMemberService {
*/
UmsMember getByUsername(String username);
/**
* 根据会员编号获取会员
*/
UmsMember getById(Long id);
/**
* 用户注册
*/
@@ -35,4 +40,9 @@ public interface UmsMemberService {
* 获取当前登录会员
*/
UmsMember getCurrentMember();
/**
* 根据会员id修改会员积分
*/
void updateIntegration(Long id,Integer integration);
}

View File

@@ -1,20 +1,20 @@
package com.macro.mall.portal.service.impl;
import com.macro.mall.mapper.OmsOrderMapper;
import com.macro.mall.mapper.PmsSkuStockMapper;
import com.macro.mall.mapper.SmsCouponHistoryMapper;
import com.macro.mall.mapper.UmsIntegrationConsumeSettingMapper;
import com.macro.mall.mapper.*;
import com.macro.mall.model.*;
import com.macro.mall.portal.dao.PortalOrderDao;
import com.macro.mall.portal.dao.PortalOrderItemDao;
import com.macro.mall.portal.dao.SmsCouponHistoryDao;
import com.macro.mall.portal.domain.*;
import com.macro.mall.portal.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
/**
@@ -43,7 +43,14 @@ public class OmsPortalOrderServiceImpl implements OmsPortalOrderService {
private PortalOrderItemDao orderItemDao;
@Autowired
private SmsCouponHistoryMapper couponHistoryMapper;
@Autowired
private RedisService redisService;
@Value("${redis.key.prefix.orderId}")
private String REDIS_KEY_PREFIX_ORDER_ID;
@Autowired
private PortalOrderDao portalOrderDao;
@Autowired
private OmsOrderSettingMapper orderSettingMapper;
@Override
public ConfirmOrderResult generateConfirmOrder() {
ConfirmOrderResult result = new ConfirmOrderResult();
@@ -184,15 +191,25 @@ public class OmsPortalOrderServiceImpl implements OmsPortalOrderService {
order.setIntegration(calcGifIntegration(orderItemList));
//计算赠送成长值
order.setGrowth(calcGiftGrowth(orderItemList));
// TODO: 2018/9/3 order_sn,bill_*,delivery_*
//生成订单号
order.setOrderSn(generateOrderSn(order));
// TODO: 2018/9/3 bill_*,delivery_*
//插入order表和order_item表
orderMapper.insert(order);
for (OmsOrderItem orderItem : orderItemList) {
orderItem.setOrderId(order.getId());
orderItem.setOrderSn(order.getOrderSn());
}
orderItemDao.insertList(orderItemList);
//更新优惠券使用状态
updateCouponStatus(orderParam.getCouponId(),currentMember);
//如使用优惠券更新优惠券使用状态
if(orderParam.getCouponId()!=null){
updateCouponStatus(orderParam.getCouponId(),currentMember.getId(),1);
}
//如使用积分需要扣除积分
if(orderParam.getUseIntegration()!=null){
order.setUseIntegration(orderParam.getUseIntegration());
memberService.updateIntegration(currentMember.getId(),currentMember.getIntegration()-orderParam.getUseIntegration());
}
//删除购物车中的下单商品
deleteCartItemList(cartPromotionItemList,currentMember);
Map<String,Object> result = new HashMap<>();
@@ -201,6 +218,67 @@ public class OmsPortalOrderServiceImpl implements OmsPortalOrderService {
return new CommonResult().success("下单成功", result);
}
@Override
public CommonResult paySuccess(Long orderId) {
//修改订单支付状态
OmsOrder order = new OmsOrder();
order.setId(orderId);
order.setStatus(1);
orderMapper.updateByPrimaryKeySelective(order);
//恢复所有下单商品的锁定库存,扣减真实库存
OmsOrderDetail orderDetail = portalOrderDao.getDetail(orderId);
int count = portalOrderDao.updateSkuStock(orderDetail.getOrderItemList());
return new CommonResult().success("支付成功",count);
}
@Override
public CommonResult cancelTimeOutOrder() {
OmsOrderSetting orderSetting = orderSettingMapper.selectByPrimaryKey(1L);
//查询超时、未支付的订单及订单详情
List<OmsOrderDetail> timeOutOrders = portalOrderDao.getTimeOutOrders(orderSetting.getNormalOrderOvertime());
if(CollectionUtils.isEmpty(timeOutOrders)){
return new CommonResult().failed("暂无超时订单");
}
//修改订单状态为交易取消
List<Long> ids = new ArrayList<>();
for (OmsOrderDetail timeOutOrder : timeOutOrders) {
ids.add(timeOutOrder.getId());
}
portalOrderDao.updateOrderStatus(ids,4);
for (OmsOrderDetail timeOutOrder : timeOutOrders) {
//解除订单商品库存锁定
portalOrderDao.releaseSkuStockLock(timeOutOrder.getOrderItemList());
//修改优惠券使用状态
updateCouponStatus(timeOutOrder.getCouponId(),timeOutOrder.getMemberId(),0);
//返还使用积分
if(timeOutOrder.getUseIntegration()!=null){
UmsMember member = memberService.getById(timeOutOrder.getMemberId());
memberService.updateIntegration(timeOutOrder.getMemberId(),member.getIntegration()+timeOutOrder.getUseIntegration());
}
}
return new CommonResult().success(null);
}
/**
* 生成18位订单编号:8位日期+2位平台号码+2位支付方式+6位以上自增id
*/
private String generateOrderSn(OmsOrder order) {
StringBuilder sb = new StringBuilder();
String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
String key = REDIS_KEY_PREFIX_ORDER_ID + date;
Long increment = redisService.increment(key, 1);
sb.append(date);
sb.append(String.format("%02d",order.getSourceType()));
sb.append(String.format("%02d",order.getPayType()));
String incrementStr = increment.toString();
if(incrementStr.length()<=6){
sb.append(String.format("%06d",increment));
}else{
sb.append(incrementStr);
}
return sb.toString();
}
/**
* 删除下单商品的购物车信息
*/
@@ -235,22 +313,22 @@ public class OmsPortalOrderServiceImpl implements OmsPortalOrderService {
}
/**
* 更新sms_coupon_history的可用信息
* 将优惠券信息更改为指定状态
* @param couponId 优惠券id
* @param currentMember 当前会员
* @param memberId 会员id
* @param useStatus 0->未使用1->已使用
*/
private void updateCouponStatus(Long couponId, UmsMember currentMember) {
SmsCouponHistory record = new SmsCouponHistory();
record.setUseStatus(1);
//查询第一张未使用优惠券
private void updateCouponStatus(Long couponId, Long memberId,Integer useStatus) {
if(couponId==null)return;
//查询第一张优惠券
SmsCouponHistoryExample example = new SmsCouponHistoryExample();
example.createCriteria().andMemberIdEqualTo(currentMember.getId())
.andCouponIdEqualTo(couponId).andUseStatusEqualTo(0);
example.createCriteria().andMemberIdEqualTo(memberId)
.andCouponIdEqualTo(couponId).andUseStatusEqualTo(useStatus==0?1:0);
List<SmsCouponHistory> couponHistoryList = couponHistoryMapper.selectByExample(example);
if(!CollectionUtils.isEmpty(couponHistoryList)){
SmsCouponHistory couponHistory = couponHistoryList.get(0);
couponHistory.setUseTime(new Date());
couponHistory.setUseStatus(1);
couponHistory.setUseStatus(useStatus);
couponHistoryMapper.updateByPrimaryKeySelective(couponHistory);
}
}

View File

@@ -35,4 +35,9 @@ public class RedisServiceImpl implements RedisService {
public void remove(String key) {
stringRedisTemplate.delete(key);
}
@Override
public Long increment(String key, long delta) {
return stringRedisTemplate.opsForValue().increment(key,delta);
}
}

View File

@@ -13,9 +13,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.*;
/**
* 会员优惠券管理Service实现类
@@ -56,7 +54,7 @@ public class UmsMemberCouponServiceImpl implements UmsMemberCouponService {
//生成领取优惠券历史
SmsCouponHistory couponHistory = new SmsCouponHistory();
couponHistory.setCouponId(couponId);
couponHistory.setCouponCode(coupon.getCode());
couponHistory.setCouponCode(generateCouponCode(currentMember.getId()));
couponHistory.setCreateTime(now);
couponHistory.setMemberId(currentMember.getId());
couponHistory.setMemberNickname(currentMember.getNickname());
@@ -72,6 +70,26 @@ public class UmsMemberCouponServiceImpl implements UmsMemberCouponService {
return new CommonResult().success("领取成功",null);
}
/**
* 16位优惠码生成时间戳后8位+4位随机数+用户id后4位
*/
private String generateCouponCode(Long memberId) {
StringBuilder sb = new StringBuilder();
Long currentTimeMillis = System.currentTimeMillis();
String timeMillisStr = currentTimeMillis.toString();
sb.append(timeMillisStr.substring(timeMillisStr.length() - 8));
for (int i = 0; i < 4; i++) {
sb.append(new Random().nextInt(10));
}
String memberIdStr = memberId.toString();
if (memberIdStr.length() <= 4) {
sb.append(String.format("%04d", memberId));
} else {
sb.append(memberIdStr.substring(memberIdStr.length()-4));
}
return sb.toString();
}
@Override
public List<SmsCouponHistory> list(Integer useStatus) {
UmsMember currentMember = memberService.getCurrentMember();

View File

@@ -54,6 +54,11 @@ public class UmsMemberServiceImpl implements UmsMemberService {
return null;
}
@Override
public UmsMember getById(Long id) {
return memberMapper.selectByPrimaryKey(id);
}
@Override
public CommonResult register(String username, String password, String telephone, String authCode) {
//验证验证码
@@ -125,6 +130,15 @@ public class UmsMemberServiceImpl implements UmsMemberService {
MemberDetails memberDetails = (MemberDetails) auth.getPrincipal();
return memberDetails.getUmsMember();
}
@Override
public void updateIntegration(Long id, Integer integration) {
UmsMember record=new UmsMember();
record.setId(id);
record.setIntegration(integration);
memberMapper.updateByPrimaryKeySelective(record);
}
//对输入的验证码进行校验
private boolean verifyAuthCode(String authCode, String telephone){
if(StringUtils.isEmpty(authCode)){

View File

@@ -11,6 +11,7 @@ mybatis.mapper-locations=classpath:dao/*.xml,classpath*:com/**/mapper/*.xml
#===redis custom key start===
redis.key.prefix.authCode=portal:authCode:
redis.key.prefix.orderId=portal:orderId:
authCode.expire.seconds=90
#===redis custom key end===

View File

@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.macro.mall.portal.dao.PortalOrderDao">
<resultMap id="orderDetailMap" type="com.macro.mall.portal.domain.OmsOrderDetail"
extends="com.macro.mall.mapper.OmsOrderMapper.BaseResultMap">
<collection property="orderItemList" columnPrefix="ot_"
resultMap="com.macro.mall.mapper.OmsOrderItemMapper.BaseResultMap">
</collection>
</resultMap>
<select id="getDetail" resultMap="orderDetailMap">
SELECT
o.id,
o.order_sn,
o.coupon_id,
o.integration,
o.member_id,
ot.id ot_id,
ot.product_name ot_product_name,
ot.product_sku_id ot_product_sku_id,
ot.product_sku_code ot_product_sku_code,
ot.product_quantity ot_product_quantity
FROM
oms_order o
LEFT JOIN oms_order_item ot ON o.id = ot.order_id
WHERE
o.id = #{orderId}
</select>
<select id="getTimeOutOrders" resultMap="orderDetailMap">
SELECT
o.id,
o.order_sn,
o.coupon_id,
o.integration,
o.member_id,
o.use_integration,
ot.id ot_id,
ot.product_name ot_product_name,
ot.product_sku_id ot_product_sku_id,
ot.product_sku_code ot_product_sku_code,
ot.product_quantity ot_product_quantity
FROM
oms_order o
LEFT JOIN oms_order_item ot ON o.id = ot.order_id
WHERE
o.status = 0
AND o.create_time &lt; date_add(NOW(), INTERVAL -#{minute} MINUTE);
</select>
<update id="updateSkuStock">
UPDATE pms_sku_stock
SET
stock = CASE id
<foreach collection="itemList" item="item">
WHEN #{item.productSkuId} THEN stock - #{item.productQuantity}
</foreach>
END,
lock_stock = CASE id
<foreach collection="itemList" item="item">
WHEN #{item.productSkuId} THEN lock_stock - #{item.productQuantity}
</foreach>
END
WHERE
id IN
<foreach collection="itemList" item="item" separator="," open="(" close=")">
#{item.productSkuId}
</foreach>
</update>
<update id="updateOrderStatus">
update oms_order
set status=#{status}
where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</update>
<update id="releaseSkuStockLock">
UPDATE pms_sku_stock
SET
lock_stock = CASE id
<foreach collection="itemList" item="item">
WHEN #{item.productSkuId} THEN lock_stock - #{item.productQuantity}
</foreach>
END
WHERE
id IN
<foreach collection="itemList" item="item" separator="," open="(" close=")">
#{item.productSkuId}
</foreach>
</update>
</mapper>