package com.ks.app.service.impl.vip; import com.alipay.api.AlipayApiException; import com.alipay.api.response.AlipayTradeQueryResponse; import com.ks.app.dao.vip.OrderRecordMapper; import com.ks.app.dao.vip.UserVIPInfoMapper; import com.ks.app.dto.vip.OrderPaySuccessForm; import com.ks.app.dto.vip.PayWayInfoDTO; import com.ks.app.entity.SystemEnum; import com.ks.app.entity.vip.*; import com.ks.app.exception.goldcorn.GoldCornException; import com.ks.app.exception.vip.OrderException; import com.ks.app.exception.vip.PayException; import com.ks.app.exception.vip.VIPException; import com.ks.app.service.inter.user.UserInfoService; import com.ks.app.service.inter.vip.IPaySuccess; import com.ks.app.service.inter.vip.OrderService; import com.ks.app.service.inter.vip.VIPPriceService; import com.ks.app.service.manager.GoldCornManager; import com.ks.app.utils.PayConstant; import com.ks.app.utils.vip.VIPOrderUtil; import com.ks.app.utils.vip.VipUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.yeshi.utils.StringUtil; import org.yeshi.utils.alipay.AlipayH5PayUtil; import org.yeshi.utils.entity.wx.WXPayOrderInfoV3; import org.yeshi.utils.ios.pay.IOSPayVerifyUtil; import org.yeshi.utils.ios.pay.vo.IOSAPPBuyVerifyResult; import org.yeshi.utils.wx.WXPayV3Util; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.UUID; import java.util.concurrent.TimeUnit; /** * @author hxh * @title: OrderServiceImpl * @description: TODO * @date 2021/11/17 14:52 */ @Service public class OrderServiceImpl implements OrderService { private static Logger logger = LoggerFactory.getLogger("OrderService"); private static Logger orderLogger = LoggerFactory.getLogger("order"); @Resource private OrderRecordMapper OrderRecordDao; @Resource private RedisTemplate redisTemplate; @Resource private GoldCornManager goldCornManager; @Resource private VIPPriceService vipPriceService; @Resource private UserInfoService userInfoService; @Resource private UserVIPInfoMapper userVIPInfoDao; @Transactional(rollbackFor = Exception.class) @Override public OrderRecord createOrder(OrderRecord record) throws OrderException { if (record.getMoney() == null || record.getOrderType() == null || record.getUid() == null) { throw new OrderException(1, "参数不完整"); } if (record.getState() == null) { record.setState(OrderRecord.STATE_NOT_PAY); } if (record.getCreateTime() == null) { record.setCreateTime(new Date()); } if (record.getPayWay() == OrderRecord.PAY_WAY_WX) { if (record.getGoldCorn() != null && record.getGoldCorn() > 0) { if (record.getMoney().compareTo(new BigDecimal("0")) == 0) { record.setPayWay(OrderRecord.PAY_WAY_GOLDCORN); } else { record.setPayWay(OrderRecord.PAY_WAY_WX_GOLDCORN); } } } else if (record.getPayWay() == OrderRecord.PAY_WAY_ALIPAY) { if (record.getGoldCorn() != null && record.getGoldCorn() > 0) { if (record.getMoney().compareTo(new BigDecimal("0")) == 0) { record.setPayWay(OrderRecord.PAY_WAY_GOLDCORN); } else { record.setPayWay(OrderRecord.PAY_WAY_ALIPAY_GOLDCORN); } } } record.setMoneyPay(false); record.setGoldCornPay(false); OrderRecordDao.insertSelective(record); orderLogger.info("订单创建成功:id-{} 类型-{}", record.getId(), record.getOrderType().name()); return record; } @Transactional(rollbackFor = Exception.class) // @GlobalTransactional(timeoutMills = 30000, name = "buwan-order", rollbackFor = Exception.class) @Override public PayWayInfoDTO payOrder(OrderRecord record) throws OrderException, GoldCornException, PayException, VIPException { String orderNo = VIPOrderUtil.getOutOrderNo(userInfoService.getSystem(record.getUid()), record.getOrderType(), record.getId()); switch (record.getPayWay()) { case OrderRecord .PAY_WAY_ALIPAY_GOLDCORN: try { goldCornManager.consumeGoldCorn(record, record.getGoldCorn()); } catch (Exception e) { throw new GoldCornException(1, "影视豆扣除出错"); } paySuccess(new OrderPaySuccessForm(record.getId(), OrderRecord.PAY_WAY_GOLDCORN, null, new Date())); orderLogger.info("订单影视豆支付成功:id-{}", record.getId()); case OrderRecord .PAY_WAY_ALIPAY: { if (record.getMoney() != null && record.getMoney().compareTo(new BigDecimal(0)) == 0) { return new PayWayInfoDTO(0, VipUtil.getPaySuccessUrl(record.getId())); } //生成支付宝支付订单 String form = VipUtil.getVipChargeAlipayForm(record.getId(), record.getOrderType(), orderNo, record.getMoney()); //暂存2分钟 String id = StringUtil.Md5(UUID.randomUUID().toString() + "#" + System.currentTimeMillis()); redisTemplate.opsForValue().set(id, form, 120, TimeUnit.SECONDS); String payUrl = PayConstant.ALIPAY_PRINT_PAY_FORM_LINK.replace("{formId}", id); orderLogger.info("订单创建支付宝支付链接成功:id-{} 链接-{}", record.getId(), payUrl); return new PayWayInfoDTO(OrderRecord .PAY_WAY_ALIPAY, payUrl); } case OrderRecord .PAY_WAY_WX_GOLDCORN: try { goldCornManager.consumeGoldCorn(record, record.getGoldCorn()); } catch (Exception e) { throw new GoldCornException(1, "影视豆扣除出错"); } paySuccess(new OrderPaySuccessForm(record.getId(), OrderRecord.PAY_WAY_GOLDCORN, null, new Date())); orderLogger.info("订单影视豆支付成功:id-{} 类型-{}", record.getId(), record.getOrderType().name()); case OrderRecord .PAY_WAY_WX: { if (record.getMoney() != null && record.getMoney().compareTo(new BigDecimal(0)) == 0) { return new PayWayInfoDTO(0, VipUtil.getPaySuccessUrl(record.getId())); } //生成微信支付订单 try { String title = ""; if (record.getOrderType() == OrderType.vip) { title = "影视大全VIP-" + record.getType().getName(); } else { title = "单片购买"; } String payUrl = VipUtil.createWXOrder(record.getId(), record.getIpInfo(), orderNo, record.getMoney(), title); orderLogger.info("订单创建微信支付链接成功:id-{} 链接-{}", record.getId(), payUrl); return new PayWayInfoDTO(OrderRecord.PAY_WAY_WX, payUrl); } catch (Exception e) { logger.error("生成微信支付订单出错", e); throw new PayException(2, e.getMessage()); } } case OrderRecord.PAY_WAY_GOLDCORN: { try { goldCornManager.consumeGoldCorn(record, record.getGoldCorn()); orderLogger.info("订单影视豆支付成功:id-{}", record.getId()); } catch (Exception e) { throw new GoldCornException(1, "影视豆扣除出错"); } paySuccess(new OrderPaySuccessForm(record.getId(), OrderRecord.PAY_WAY_GOLDCORN, null, new Date())); return new PayWayInfoDTO(0, VipUtil.getPaySuccessUrl(record.getId())); } case OrderRecord.PAY_WAY_IAPP: return new PayWayInfoDTO(OrderRecord.PAY_WAY_IAPP, null); } throw new OrderException(1, "支付方式不存在"); } private int getPayState(OrderRecord record) { switch (record.getPayWay()) { case OrderRecord.PAY_WAY_ALIPAY: case OrderRecord.PAY_WAY_WX: if (record.getMoneyPay() != null && record.getMoneyPay()) { return OrderRecord.STATE_PAY; } else { return OrderRecord.STATE_NOT_PAY; } case OrderRecord.PAY_WAY_ALIPAY_GOLDCORN: case OrderRecord.PAY_WAY_WX_GOLDCORN: if (record.getMoneyPay() != null && record.getMoneyPay() && record.getGoldCornPay() != null && record.getGoldCornPay()) { return OrderRecord.STATE_PAY; } else { return OrderRecord.STATE_NOT_PAY; } case OrderRecord.PAY_WAY_GOLDCORN: if (record.getGoldCornPay() != null && record.getGoldCornPay()) { return OrderRecord.STATE_PAY; } else { return OrderRecord.STATE_NOT_PAY; } case OrderRecord.PAY_WAY_IAPP: if (record.getMoneyPay()) { return OrderRecord.STATE_PAY; } else { return OrderRecord.STATE_NOT_PAY; } } return OrderRecord.STATE_NOT_PAY; } @Transactional(rollbackFor = Exception.class) @Override public OrderRecord paySuccess(OrderPaySuccessForm successForm) throws VIPException, OrderException { return paySuccess(successForm, (OrderRecord record) -> { //TODO 支付成功 }); } @Transactional(rollbackFor = Exception.class) @Override public OrderRecord paySuccess(OrderPaySuccessForm successForm, IPaySuccess paySuccess) throws VIPException, OrderException { orderLogger.info("订单支付成功目的执行:id-{},支付方式-{},支付金额-{},支付时间-{}", successForm.getId(), successForm.getPayWay(), successForm.getPayMoney(), successForm.getPayTime()); OrderRecord record = OrderRecordDao.selectByPrimaryKeyForUpdate(successForm.getId()); //修改记录 if (record == null) { throw new OrderException(10, "订单不存在"); } if (record.getState() != OrderRecord.STATE_NOT_PAY) { throw new OrderException(1, "订单未处于待支付状态"); } if (successForm.getPayWay() != OrderRecord.PAY_WAY_GOLDCORN) { record.setPayMoney(successForm.getPayMoney()); record.setMoneyPay(true); record.setAppleTransactionId(successForm.getAppleTransactionId()); record.setAppleOriginalTransactionId(successForm.getAppleOriginalTransactionId()); } else { record.setGoldCornPay(true); } record.setPayTime(successForm.getPayTime()); record.setUpdateTime(new Date()); record.setState(getPayState(record)); //已经支付成功 if (record.getState() == OrderRecord.STATE_PAY) { OrderRecordDao.insertPaySuccess(successForm.getId()); } if (record.getOrderType() == OrderType.vip) { Date[] expireDate = addExpireTime(record.getUid(), successForm.getPayTime(), record.getType()); record.setVipStartTime(expireDate[0]); record.setVipEndTime(expireDate[1]); if (expireDate == null) { throw new VIPException(2, "添加用户会员时间出错"); } OrderRecordDao.updateByPrimaryKeySelective(record); if (record.getState() == OrderRecord.STATE_PAY) { orderLogger.info("订单全部支付成功:id-{}", successForm.getId()); if (paySuccess != null) { paySuccess.onSuccess(record); } orderLogger.info("购买VIP成功:id-{}", successForm.getId()); } else { orderLogger.info("订单部分支付成功:id-{}", successForm.getId()); } } return record; } @Transactional(rollbackFor = Exception.class) @Override public void cancelOrder(Long id, String reason) throws OrderException, GoldCornException { OrderRecord record = OrderRecordDao.selectByPrimaryKeyForUpdate(id); if (record == null) { throw new OrderException(1, "订单不存在"); } if (record.getState() == OrderRecord.STATE_PAY) { throw new OrderException(1, "已支付成功的订单不能取消"); } if (record.getPayWay() != OrderRecord.PAY_WAY_GOLDCORN && record.getMoneyPay() != null && record.getMoneyPay()) { throw new OrderException(2, "资金支付成功的订单不能取消"); } //返回豆 if (record.getGoldCornPay() != null && record.getGoldCornPay() && record.getGoldCorn() != null && record.getGoldCorn() > 0) { try { goldCornManager.drawbackGoldCorn(record); } catch (Exception e) { throw new GoldCornException(1, "影视豆退款失败"); } } //设置订单状态 record.setState(OrderRecord.STATE_CANCEL); record.setUpdateTime(new Date()); record.setRemarks(reason); OrderRecordDao.updateByPrimaryKeySelective(record); orderLogger.info("取消订单成功:id-{}", id); } @Override public List getCanCancelOrderList(int page, int pageSize) { OrderRecordMapper.DaoQuery daoQuery = new OrderRecordMapper.DaoQuery(); daoQuery.state = OrderRecord.STATE_NOT_PAY; //30分钟未支付取消订单 daoQuery.maxCreateTime = new Date(System.currentTimeMillis() - 1000 * 60 * 30); daoQuery.minCreateTime = new Date(daoQuery.maxCreateTime.getTime() - 1000 * 60 * 60L * 24); return OrderRecordDao.list(daoQuery); } @Transactional(rollbackFor = Exception.class) @Override public OrderRecord checkOrderPayState(Long id) { OrderRecord record = OrderRecordDao.selectByPrimaryKeyForUpdate(id); if (record.getState() == OrderRecord.STATE_PAY) { return record; } switch (record.getPayWay()) { case OrderRecord.PAY_WAY_ALIPAY_GOLDCORN: case OrderRecord.PAY_WAY_ALIPAY: { //支付宝 AlipayTradeQueryResponse res = null; try { res = AlipayH5PayUtil.queryOrder(VipUtil.getAlipayApp(), VIPOrderUtil.getOutOrderNo(userInfoService.getSystem(record.getUid()), record.getOrderType(), id), null); //支付成功 if (res.isSuccess() && "TRADE_SUCCESS".equalsIgnoreCase(res.getTradeStatus())) { try { return paySuccess(new OrderPaySuccessForm(id, OrderRecord.PAY_WAY_ALIPAY, new BigDecimal(res.getTotalAmount()), new Date())); } catch (Exception e) { e.printStackTrace(); } } } catch (AlipayApiException e) { e.printStackTrace(); } } break; case OrderRecord.PAY_WAY_WX_GOLDCORN: case OrderRecord.PAY_WAY_WX: { //微信 try { WXPayOrderInfoV3 info = WXPayV3Util.getPayOrderInfo(VIPOrderUtil.getOutOrderNo(userInfoService.getSystem(record.getUid()), record.getOrderType(), id), VipUtil.getWXAPP()); if (info != null && info.getTrade_state().equalsIgnoreCase("SUCCESS")) { paySuccess(new OrderPaySuccessForm(id, record.getPayWay(), new BigDecimal(info.getAmount().getPayer_total()).divide(new BigDecimal(100), 2, RoundingMode.FLOOR), new Date())); return record; } } catch (Exception e) { e.printStackTrace(); } } break; } return record; } @Transactional(rollbackFor = Exception.class) @Override public OrderRecord checkApplePay(Long orderNo, String receipt) throws Exception { OrderRecord orderRecord = OrderRecordDao.selectByPrimaryKeyForUpdate(orderNo); if (orderRecord == null) { throw new OrderException(1, "订单号不存在"); } SystemEnum system = userInfoService.getSystem(orderRecord.getUid()); if (!StringUtil.isNullOrEmpty(orderRecord.getAppleTransactionId())) { throw new OrderException(2, "订单已支付"); } IOSAPPBuyVerifyResult result = IOSPayVerifyUtil.buyAppVerify(receipt, "28ca52e358b94c4eba3de41dfa7dd023", false); List orderInfoList = result.getLatestReceiptInfo(); IOSAPPBuyVerifyResult.OrderInfo orderInfo = orderInfoList.get(0); String productId = orderInfo.getProduct_id(); VIPPrice vipPrice = vipPriceService.selectByIOSProductId(productId, system); if (vipPrice == null) { throw new Exception("商品ID不存在"); } if (orderRecord.getType() != vipPrice.getType()) { throw new Exception("价格类型不匹配"); } //String id, int payWay, BigDecimal payMoney, Date payTime, String appleTransactionId, String appleOriginalTransactionId OrderPaySuccessForm successForm = new OrderPaySuccessForm(orderRecord.getId(), OrderRecord.PAY_WAY_IAPP, new BigDecimal(0), new Date(orderInfo.getPurchaseDateMs()), orderInfo.getTransactionId(), orderInfo.getOriginalTransactionId()); paySuccess(successForm); return null; } @Override public List listOrderRecord(Long uid, OrderType orderType, Integer state, int page, int pageSize) { OrderRecordMapper.DaoQuery query = new OrderRecordMapper.DaoQuery(); query.start = (page - 1) * pageSize; query.count = pageSize; query.uid = uid; query.state = state; query.orderType = orderType; return OrderRecordDao.list(query); } @Override public long countOrderRecord(Long uid, OrderType orderType, Integer state) { OrderRecordMapper.DaoQuery query = new OrderRecordMapper.DaoQuery(); query.uid = uid; query.state = state; query.orderType = orderType; return OrderRecordDao.count(query); } @Override public OrderRecord getOrderRecord(Long id) { return OrderRecordDao.selectByPrimaryKey(id); } /** * 续期 * * @param uid * @param payTime * @param type * @return */ private Date[] addExpireTime(Long uid, Date payTime, VIPPriceType type) { if (type == null || uid == null) { return null; } UserVIPInfo userVIPInfo = userVIPInfoDao.selectByPrimaryKeyForUpdate(uid); if (userVIPInfo == null) { //新增 UserVIPInfo vip = new UserVIPInfo(); vip.setUid(uid); vip.setCreateTime(new Date()); Date[] expireDate = getExpireTime(payTime, null, type); vip.setExpireDate(expireDate[1]); userVIPInfoDao.insertSelective(vip); return expireDate; } else { //修改 UserVIPInfo update = new UserVIPInfo(); update.setUid(uid); Date[] expireDate = getExpireTime(payTime, userVIPInfo.getExpireDate(), type); update.setExpireDate(expireDate[1]); update.setUpdateTime(new Date()); userVIPInfoDao.updateByPrimaryKeySelective(update); return expireDate; } } /** * 获取到期时间 * * @param payTime * @param expireTime * @param type * @return */ private Date[] getExpireTime(Date payTime, Date expireTime, VIPPriceType type) { Calendar calendar = Calendar.getInstance(); if (expireTime != null) { //之前续期时间是否大于付款时间 if (payTime.getTime() < expireTime.getTime()) { calendar.setTimeInMillis(expireTime.getTime()); } else { calendar.setTimeInMillis(payTime.getTime()); } } else { calendar.setTimeInMillis(payTime.getTime()); } long startTime = calendar.getTimeInMillis(); if (type == VIPPriceType.day) { calendar.add(Calendar.DAY_OF_WEEK, 1); } else if (type == VIPPriceType.week) { calendar.add(Calendar.WEEK_OF_YEAR, 1); } else if (type == VIPPriceType.month) { calendar.add(Calendar.MONTH, 1); } else if (type == VIPPriceType.season) { calendar.add(Calendar.MONTH, 3); } else if (type == VIPPriceType.halfYear) { calendar.add(Calendar.MONTH, 6); } else if (type == VIPPriceType.year) { calendar.add(Calendar.YEAR, 1); } return new Date[]{new Date(startTime), new Date(calendar.getTimeInMillis())}; } }