Authored by wujiexiang

优惠券结算

package com.yohoufo.dal.order;
import com.yohoufo.dal.order.model.OrderCoupon;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* Created by jiexiang.wu on 2018/11/20.
*/
public interface OrderCouponMapper {
int insert(OrderCoupon orderCoupon);
List<OrderCoupon> selectByUidAndOrderCode(@Param("uid") int uid, @Param("orderCode") long orderCode);
}
... ...
... ... @@ -15,6 +15,11 @@ public class BuyerOrderGoods {
private BigDecimal goodsAmount;
/**
* 优惠券减免金额
*/
private BigDecimal couponCutAmount;
public Integer getUid() {
return uid;
}
... ... @@ -62,4 +67,12 @@ public class BuyerOrderGoods {
public void setGoodsAmount(BigDecimal goodsAmount) {
this.goodsAmount = goodsAmount;
}
public BigDecimal getCouponCutAmount() {
return couponCutAmount;
}
public void setCouponCutAmount(BigDecimal couponCutAmount) {
this.couponCutAmount = couponCutAmount;
}
}
\ No newline at end of file
... ...
package com.yohoufo.dal.order.model;
/**
* Created by jiexiang.wu on 2018/11/20.
*/
public class OrderCoupon {
private int uid;
private long orderCode;
private String couponCode;
private int createTime;
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public long getOrderCode() {
return orderCode;
}
public void setOrderCode(long orderCode) {
this.orderCode = orderCode;
}
public String getCouponCode() {
return couponCode;
}
public void setCouponCode(String couponCode) {
this.couponCode = couponCode;
}
public int getCreateTime() {
return createTime;
}
public void setCreateTime(int createTime) {
this.createTime = createTime;
}
}
... ...
... ... @@ -8,6 +8,7 @@
<result column="skup" jdbcType="INTEGER" property="skup" />
<result column="goods_price" jdbcType="DECIMAL" property="goodsPrice" />
<result column="goods_amount" jdbcType="DECIMAL" property="goodsAmount" />
<result column="coupons_cut_amount" jdbcType="DECIMAL" property="couponCutAmount" />
</resultMap>
<sql id="Base_Column_List">
id, order_code, skup, goods_price, goods_amount, uid
... ... @@ -83,6 +84,9 @@
<if test="uid != null">
uid,
</if>
<if test="couponCutAmount != null">
coupons_cut_amount,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="orderCode != null">
... ... @@ -100,6 +104,9 @@
<if test="uid != null">
#{uid,jdbcType=INTEGER},
</if>
<if test="couponCutAmount != null">
#{couponCutAmount,jdbcType=DECIMAL},
</if>
</trim>
</insert>
<update id="updateByPrimaryKeySelective" parameterType="com.yohoufo.dal.order.model.BuyerOrderGoods">
... ...
<?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.yohoufo.dal.order.OrderCouponMapper">
<resultMap id="BaseResultMap" type="com.yohoufo.dal.order.model.OrderCoupon">
<id column="id" jdbcType="BIGINT" property="id"/>
<result column="uid" jdbcType="INTEGER" property="uid"/>
<result column="order_code" jdbcType="BIGINT" property="orderCode"/>
<result column="coupon_code" jdbcType="VARCHAR" property="couponCode"/>
<result column="create_time" jdbcType="INTEGER" property="createTime"/>
</resultMap>
<sql id="Base_Column_List">
id, uid, order_code, coupon_code, create_time
</sql>
<insert id="insert" keyColumn="id" keyProperty="id" parameterType="com.yohoufo.dal.order.model.OrderCoupon" useGeneratedKeys="true">
insert into order_coupon (uid, order_code, coupon_code,create_time)
values (#{uid,jdbcType=INTEGER}, #{orderCode,jdbcType=BIGINT}, #{couponCode,jdbcType=VARCHAR}, #{createTime,jdbcType=INTEGER})
</insert>
<select id="selectByUidAndOrderCode" resultMap="BaseResultMap">
select
<include refid="Base_Column_List"/>
from buyer_order
where order_code = #{orderCode,jdbcType=BIGINT}
and uid = #{uid,jdbcType=INTEGER}
</select>
</mapper>
\ No newline at end of file
... ...
... ... @@ -31,4 +31,9 @@ public class ChargeResult {
*/
private double finalAmount;
public ChargeResult() {
//init
this.couponPayResult = CouponPayResult.builder().build();
}
}
... ...
... ... @@ -32,4 +32,9 @@ public class CouponPayResult {
*/
private double couponAmount = 0;
/**
* 券数量
*/
private int couponCount = 0;
}
... ...
package com.yohoufo.order.model.bo;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Builder;
import java.math.BigDecimal;
/**
* Created by jiexiang.wu on 2018/11/20.
*/
@Data
@ToString
@Builder
public class CouponBo {
//券code
private String couponCode;
//券金额
private BigDecimal couponAmount;
}
... ...
... ... @@ -3,11 +3,13 @@ package com.yohoufo.order.model.dto;
import com.yoho.service.model.response.UserAddressRspBO;
import com.yohoufo.order.model.AddressInfo;
import com.yohoufo.order.model.bo.CouponBo;
import lombok.Data;
import lombok.ToString;
import lombok.experimental.Builder;
import java.math.BigDecimal;
import java.util.List;
@Data
@Builder
... ... @@ -39,4 +41,9 @@ public class OrderBuilder {
AddressInfo addressInfo;
AddressInfo hiddenAddressInfo;
/**
* 使用的优惠券
*/
CouponBo couponBo;
}
... ...
... ... @@ -142,6 +142,11 @@ public class OrderDetailInfo {
String feePrice;
/**
* 优惠券金额
*/
String couponCutPrice;
/**
* 实付金额
*/
String realPayPrice;
... ...
... ... @@ -150,6 +150,7 @@ public abstract class AbsOrderDetailService implements IOrderDetailService{
OrderDetailInfo.PriceInfo priceInfo = OrderDetailInfo.PriceInfo.builder()
.goodPrice(buyerOrderGoods.getGoodsPrice() == null ? "0" : buyerOrderGoods.getGoodsPrice().toPlainString() )
.feePrice(buyerOrder.getShipFee() == null ? "0" : buyerOrder.getShipFee().toPlainString())
.couponCutPrice(buyerOrderGoods.getCouponCutAmount() == null ? "0":buyerOrderGoods.getCouponCutAmount().toPlainString())
.realPayPrice(buyerOrder.getAmount() == null ? "0" : buyerOrder.getAmount().toPlainString())
.build();
orderDetailInfo.setPriceInfo(priceInfo);
... ...
... ... @@ -23,6 +23,7 @@ import com.yohoufo.order.charge.model.CouponMatchResult;
import com.yohoufo.order.event.BuyerCancelEvent;
import com.yohoufo.order.event.NotPaidNoticeEvent;
import com.yohoufo.order.model.AddressInfo;
import com.yohoufo.order.model.bo.CouponBo;
import com.yohoufo.order.model.dto.BuyerOrderSubmitResult;
import com.yohoufo.order.model.dto.OrderBuilder;
import com.yohoufo.order.model.request.ShoppingRequest;
... ... @@ -272,6 +273,10 @@ public class ShoppingServiceImpl implements IShoppingService {
.channelNo(shoppingRequest.getChannelNo())
.amount(BigDecimal.valueOf(chargeResult.getFinalAmount()))
.shipFee(BigDecimal.valueOf(chargeResult.getExpressDeliveryAmount()))
.couponBo(CouponBo.builder().couponCode(chargeResult.getCouponPayResult().getCouponCode())
.couponAmount(BigDecimal.valueOf(chargeResult.getCouponPayResult().getCouponAmount()))
.build()
)
.hiddenAddressInfo(hiddenAddress)
.addressInfo(addressInfo)
.clientType(shoppingRequest.getClientType())
... ...
... ... @@ -3,6 +3,7 @@ package com.yohoufo.order.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.yoho.core.common.utils.DateUtil;
import com.yoho.core.dal.datasource.annotation.Database;
import com.yoho.core.transaction.annoation.YHTransaction;
import com.yoho.error.ServiceError;
import com.yoho.error.exception.ServiceException;
import com.yohoufo.dal.order.*;
... ... @@ -15,6 +16,7 @@ import com.yohoufo.order.constants.MetaKey;
import com.yohoufo.order.model.dto.BuyerOrderSubmitResult;
import com.yohoufo.order.model.dto.OrderBuilder;
import com.yohoufo.order.service.ISubmitOrderService;
import com.yohoufo.order.service.proxy.CouponProxyService;
import com.yohoufo.order.service.proxy.ProductProxyService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
... ... @@ -34,13 +36,21 @@ public class SubmitOrderServiceImpl implements ISubmitOrderService {
@Autowired
private ProductProxyService productProxyService;
@Autowired
private CouponProxyService couponProxyService;
@YHTransaction
public BuyerOrderSubmitResult doSumbitOrder(OrderBuilder orderBuilder){
BuyerOrderSubmitResult result = null;
try {
// 减库存
if(productProxyService.subtractStorage(orderBuilder.getProductId(), orderBuilder.getSkup())) {
//使用优惠券
if (orderBuilder.getCouponBo().getCouponAmount().doubleValue() > 0) {
couponProxyService.orderUseCoupon(orderBuilder.getUid(), orderBuilder.getOrderCode(), orderBuilder.getCouponBo());
}
// 创建订单
return orderCreateService.createOrder(orderBuilder);
}
... ... @@ -91,7 +101,8 @@ public class SubmitOrderServiceImpl implements ISubmitOrderService {
@Autowired
BuyerOrderMetaMapper buyerOrderMetaMapper;
@Autowired
OrderCouponMapper orderCouponMapper;
@Autowired
private ProductProxyService productProxyService;
... ... @@ -110,6 +121,7 @@ public class SubmitOrderServiceImpl implements ISubmitOrderService {
* 3.插入订单 表buyer_order
* 4.插入订单商品 buyer_order_goods
* 5.插入收货地址 buyer_order_meta
* 6.插入优惠券 order_coupon
*/
// 1.表seller_order_goods ==> 不可售
... ... @@ -127,6 +139,9 @@ public class SubmitOrderServiceImpl implements ISubmitOrderService {
// 5.插入收货地址 buyer_order_meta 买家收货地址
insertOrderMeta(orderBuilder);
//6.插入优惠券 order_coupon
insertOrderCouponIfNeed(orderBuilder);
BuyerOrderSubmitResult result = BuyerOrderSubmitResult.builder()
.orderCode(orderBuilder.getOrderCode())
.sellerOrder(sellerOrder).sellerOrderGoods(sellerOrderGoods).build();
... ... @@ -159,6 +174,7 @@ public class SubmitOrderServiceImpl implements ISubmitOrderService {
buyerOrderGoods.setGoodsPrice(sellerOrderGoods.getGoodsPrice());
buyerOrderGoods.setGoodsAmount(sellerOrderGoods.getGoodsPrice());
buyerOrderGoods.setUid(orderBuilder.getUid());
buyerOrderGoods.setCouponCutAmount(orderBuilder.getCouponBo().getCouponAmount());
buyerOrderGoodsMapper.insertSelective(buyerOrderGoods);
}
... ... @@ -181,6 +197,18 @@ public class SubmitOrderServiceImpl implements ISubmitOrderService {
buyerOrderMapper.insert(buyerOrder);
}
private void insertOrderCouponIfNeed(OrderBuilder orderBuilder) {
if (orderBuilder.getCouponBo().getCouponAmount().doubleValue() > 0) {
OrderCoupon orderCoupon = new OrderCoupon();
orderCoupon.setUid(orderBuilder.getUid());
orderCoupon.setOrderCode(orderBuilder.getOrderCode());
orderCoupon.setCouponCode(orderBuilder.getCouponBo().getCouponCode());
orderCoupon.setCreateTime(DateUtil.getCurrentTimeSecond());
orderCouponMapper.insert(orderCoupon);
}
}
private SellerOrder selectSellerOrder(OrderBuilder orderBuilder) {
SellerOrder sellerOrder = sellerOrderMapper.selectBySkup(orderBuilder.getSkup());
return sellerOrder;
... ...
package com.yohoufo.order.service.proxy;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.yoho.core.transaction.Compensator;
import com.yoho.core.transaction.annoation.TxCompensatable;
import com.yoho.core.transaction.annoation.TxCompensateArgs;
import com.yoho.error.ServiceError;
import com.yoho.error.exception.ServiceException;
import com.yohobuy.ufo.model.promotion.UserCouponsBo;
import com.yohoufo.common.ApiResponse;
import com.yohoufo.common.caller.UfoServiceCaller;
import com.yohoufo.order.model.bo.CouponBo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
... ... @@ -11,7 +24,13 @@ import java.util.List;
* Created by jiexiang.wu on 2018/11/19.
*/
@Service
public class CouponProxyService {
public class CouponProxyService implements Compensator {
private final static Logger logger = LoggerFactory.getLogger(CouponProxyService.class);
@Autowired
private UfoServiceCaller serviceCaller;
/**
* 查询用户可以使用的券
*
... ... @@ -54,4 +73,75 @@ public class CouponProxyService {
userCouponsBo.setEndTime(1546275661L);
return Lists.newArrayList(userCouponsBo);
}
/**
* 使用优惠券,有补偿功能
*
* @param uid
* @param orderCode
* @param coupon
*/
@TxCompensatable(value = CouponProxyService.class)
public void orderUseCoupon(@TxCompensateArgs("uid") int uid, @TxCompensateArgs("orderCode") long orderCode,
@TxCompensateArgs("couponBo") CouponBo coupon) {
logger.info("[{}] request to use coupon,couponBo is {}", orderCode, coupon);
ApiResponse resp = serviceCaller.call("app.coupons.use", uid, orderCode, Lists.newArrayList(coupon.getCouponCode()));
if (getResultFromApiResponse(resp) == false) {
logger.warn("[{}] use couponBo fail,coupons is {}", orderCode, coupon);
throw new ServiceException(ServiceError.PROMOTION_COUPON_IS_NOT_VAILD);
}
logger.info("[{}] use coupon success", orderCode);
}
/**
* 取消券使用
*
* @param uid
* @param orderCode
* @param coupon
*/
public void orderCancelCoupon(int uid, long orderCode, CouponBo coupon) {
logger.info("[{}] request to cancel coupon,couponBo is {}", orderCode, coupon);
ApiResponse resp = serviceCaller.call("app.coupons.cancel", uid, orderCode, Lists.newArrayList(coupon.getCouponCode()));
if (getResultFromApiResponse(resp) == false) {
logger.warn("[{}] cancel couponBo fail,coupons is {}", orderCode, coupon);
throw new ServiceException(ServiceError.PROMOTION_COUPON_IS_NOT_VAILD);
}
logger.info("[{}] cancel coupon success", orderCode);
}
private boolean getResultFromApiResponse(ApiResponse resp) {
if (resp == null) {
return false;
}
if (resp.getCode() != 200 || resp.getData() == null) {
return false;
}
return (boolean) resp.getData();
}
/**
* 补偿
*
* @param message json格式的字符串
*/
@Override
public void compensate(String message) {
logger.info("CouponProxyService begin to compensate : {}", message);
int uid = 0;
long orderCode = 0;
CouponBo couponBo = null;
try {
JSONObject json = JSON.parseObject(message);
uid = json.getIntValue("uid");
orderCode = json.getLongValue("orderCode");
couponBo = json.getObject("coupons", CouponBo.class);
} catch (Exception ex) {
logger.warn("parse message to json error,message is {}", message, ex);
}
orderCancelCoupon(uid, orderCode, couponBo);
logger.info("CouponProxyService compensate end,uid is {},orderCode is {}", uid, orderCode);
}
}
... ...
package com.yohoufo.order.service.support;
import com.fasterxml.jackson.databind.deser.DataFormatReaders;
import com.google.common.collect.Lists;
import com.yohoufo.common.helper.ImageUrlAssist;
import com.yohoufo.common.utils.BigDecimalHelper;
import com.yohoufo.dal.order.model.SellerOrderGoods;
import com.yohobuy.ufo.model.order.constants.OrderConstant;
import com.yohoufo.order.charge.ChargeContext;
import com.yohoufo.order.charge.model.ChargeResult;
import com.yohoufo.order.charge.model.CouponPayResult;
import com.yohoufo.order.model.response.CouponInfo;
import com.yohoufo.order.model.response.CouponInfo;
import com.yohoufo.order.model.response.GoodsInfo;
import com.yohoufo.order.model.response.PaymentResponse;
import com.yohoufo.order.model.response.PromotionFormula;
... ... @@ -98,7 +94,7 @@ public class ShoppingSupport {
//优惠券
CouponPayResult couponPayResult = chargeResult.getCouponPayResult();
if (couponPayResult != null) {
if (couponPayResult.getCouponAmount() > 0) {
PromotionFormula couponFormula = new PromotionFormula();
couponFormula.setPromotion(OrderConstant.COUPON_DESC);
couponFormula.setPromotionAmount(OrderConstant.SUB_SIGN + MathUtils.formatCurrencyStr(couponPayResult.getCouponAmount()));
... ... @@ -134,16 +130,17 @@ public class ShoppingSupport {
}
/**
* 使用的优惠券信息
* @param chargeResult
* @return
*/
public CouponInfo getCouponInfo(ChargeResult chargeResult) {
CouponPayResult couponPayResult = chargeResult.getCouponPayResult();
if (couponPayResult == null) {
return null;
}
return CouponInfo.builder().couponCode(couponPayResult.getCouponCode())
.couponTitle(couponPayResult.getCouponTitle())
.couponAmountStr(MathUtils.formatCurrencyStr(couponPayResult.getCouponAmount()))
.couponCount(1)
.couponCount(couponPayResult.getCouponCount())
.build();
}
}
... ...
... ... @@ -34,8 +34,8 @@ public class OrderCouponController {
@RequestMapping(params = "method=app.coupons.use")
@ResponseBody
public ApiResponse useCoupon(@RequestParam(value = "uid") Integer uid,
@RequestParam(value = "couponCodes") List<String> couponCodes,
@RequestParam(value = "orderCode") long orderCode) {
@RequestParam(value = "orderCode") long orderCode,
@RequestParam(value = "couponCodes") List<String> couponCodes) {
logger.info("use coupons, uid: {},couponCodes: {}, orderCode :{}", uid, couponCodes, orderCode);
boolean useSuccess = couponService.useCoupon(uid, couponCodes, orderCode);
... ... @@ -54,8 +54,8 @@ public class OrderCouponController {
@RequestMapping(params = "method=app.coupons.cancel")
@ResponseBody
public ApiResponse cancelCoupon(@RequestParam(value = "uid") Integer uid,
@RequestParam(value = "couponCodes") List<String> couponCodes,
@RequestParam(value = "orderCode") long orderCode) {
@RequestParam(value = "orderCode") long orderCode,
@RequestParam(value = "couponCodes") List<String> couponCodes) {
logger.info("cancel coupons, uid: {},couponCodes: {}, orderCode :{}", uid, couponCodes, orderCode);
boolean cancelSuccess = couponService.cancelCoupon(uid, couponCodes, orderCode);
... ... @@ -64,4 +64,4 @@ public class OrderCouponController {
}
}
}
\ No newline at end of file
... ...
... ... @@ -104,4 +104,9 @@ order.buyer.cancelWhenSellerUnDelivery.sellerGetMoneyRate=0.8
uic.url=http://java-yoho-uic.test3.ingress.dev.yohocorp.com/uic
yoho.message.controller.url=http://message-controller.yohoops.org/yoho-message-controller
\ No newline at end of file
yoho.message.controller.url=http://message-controller.yohoops.org/yoho-message-controller
#rabbit address for transaction compensate
rabbit_host=192.168.102.45:5672
rabbit_user=yoho
rabbit_password=yoho
... ...
... ... @@ -76,3 +76,9 @@ order.buyer.cancelWhenSellerUnDelivery.sellerGetMoneyRate=${order.buyer.cancelWh
erp-gateway.url=${erp-gateway.url}
uic.url=${uic.url}
yoho.message.controller.url=${yoho.message.controller.url}
#rabbit address for transaction compensate
rabbit_host=${rabbit_order}
rabbit_user=${rabbit_order_user}
rabbit_password=${rabbit_order_password}
\ No newline at end of file
... ...