一个小demo

从混乱到有序

简介

服务市场上架的应用,商户可以任意购买使用,随着业务的发展收费模式有最初只有买断模式,进化到支持买断模式、单次模式、订阅模式三种,后期可能还会增加购买方式。

  • 买断模式:商户购买并付款后,拥有永久使用权限
  • 单次模式:一次购买只服务一次
  • 订阅模式:服务购买后,有到期时间

业务流程

购买支付流程

创建订单原始伪代码

// 创建订单
if(单次模式){
  // 查询有效的partnerOpenApp
  .......
  // 校验是否可下单
  .......
  // 创建订单
  .......
} else if(买断模式){
  // 查询有效的partnerOpenApp
  .......
  // 校验是否可下单
  .......
  // 创建订单
  .......
} else if(订阅模式){
  // 查询有效的partnerOpenApp
  .......
  // 校验是否可下单
  .......
  // 创建订单
  .......
} else{
  throw new OpenServiceException(OpenErrorType.NOT_SUPPORTED);
}
........


// 支付回调
if(单次模式){
  
} else if(买断模式){

} else if(订阅模式){

} else{
  throw new OpenServiceException(OpenErrorType.NOT_SUPPORTED);
}

重构之后:

购买支付类图

代码实现

@Service
public class PuchaseOrderServiceFactory {

    @Autowired
    private ByoutPuchaseOrderServiceImpl byoutAppPuchaseOrderService;

    @Autowired
    private OneTimePurchaseOrderServiceImpl oneTimeAppPurchaseOrderService;

    @Autowired
    private SubscribePurchaseOrderServiceImpl subscribeAppPurchaseOrderService;

    public PurchaseOrderService getPuchaeOrderService(AppChargeType chargeType){
        switch (chargeType){
            case BUYOUT:
                return byoutAppPuchaseOrderService;
            case ONETIME:
                return oneTimeAppPurchaseOrderService;
            case SUBSCRIBE:
                return subscribeAppPurchaseOrderService;
        }
        throw new OpenServiceException(OpenErrorType.BUSINESS_ERROR,"不支持类型"+chargeType.getKey());
    }
}
@Slf4j
public abstract class PurchaseOrderService {

    @Autowired
    private OpenAppService openAppService;

    @Autowired
    private PartnerAppPurchaseOrderDao partnerAppPurchaseOrderDao;

    @Autowired
    private PartnerAppPurchaseHistoryService partnerAppPurchaseHistoryService;

    @Autowired
    private PartnerOpenAppPurchasedProducer partnerOpenAppPurchasedProducer;

    /**
     * 创建订单
     * @param orderCreatorTo
     * @return
     */
    public final PartnerAppPurchaseOrder createOrder(OrderCreatorTo orderCreatorTo) {

        // 查询有效的partnerOpenApp
        PartnerOpenApp partnerOpenApp = openAppService.findOneValidPartnerOpenApp(orderCreatorTo.getTo().getAppId());

        // 校验是否可下单
        verify(orderCreatorTo, partnerOpenApp);

        // 创建订单
        PartnerAppPurchaseOrder order = buildOrder(orderCreatorTo, partnerOpenApp);

        if (isFree(order)) {
            paySuccess(order,0L);
            return order;
        } else {
            order.setPayStatus(PayStatusType.PAYING.getKey());
            partnerAppPurchaseOrderDao.save(order);
            return order;
        }
    }

    // 是否免费应用
    private boolean isFree(PartnerAppPurchaseOrder order) {
        return order.getPayFee() == 0 || order.getSource() == PurchaseSourceType.ERP.getKey();
    }


    private PartnerAppPurchaseOrder buildOrder(OrderCreatorTo orderCreatorTo, PartnerOpenApp partnerOpenApp) {

        final OpenPurchaseTo to = orderCreatorTo.getTo();
        OrderCreator orderCreator = new OrderCreator(orderCreatorTo, partnerOpenApp, to).invoke();
        buildOrderCustomer(orderCreatorTo,orderCreator, partnerOpenApp);
        log.info("创建的订单[{}]", OpenGsonWrapper.toJson(orderCreator.getOrder()));
        return orderCreator.getOrder();
    }


    /**
     * 免费应用或者支付成功回调
     *
     * @param partnerAppPurchaseOrder
     * @param payFee
     */
    public void paySuccess(PartnerAppPurchaseOrder partnerAppPurchaseOrder, Long payFee) {
        partnerAppPurchaseOrder.setPayStatus(PayStatusType.PAYED.getKey());
        PartnerAppPurchaseHistory history = partnerAppPurchaseHistoryService.createHistory(partnerAppPurchaseOrder, payFee);
        partnerAppPurchaseOrder.setHistoryId(history.getId());
        partnerAppPurchaseOrderDao.save(partnerAppPurchaseOrder);
        partnerOpenAppPurchasedProducer.sendMessage(partnerAppPurchaseOrder.getId());
    }

    /**
     *  特殊应用自定义构造,如订阅模式的应用
     * @param orderCreatorTo
     * @param orderCreator
     * @param partnerOpenApp
     */
    protected void buildOrderCustomer(OrderCreatorTo orderCreatorTo, OrderCreator orderCreator, PartnerOpenApp partnerOpenApp) {

    }

    /**
     * 通用下单校验,这边只检验了存在购买中的
     * @param orderCreatorTo
     * @param partnerOpenApp
     */
    protected void verify(OrderCreatorTo orderCreatorTo, PartnerOpenApp partnerOpenApp){
        OpenPurchaseTo to = orderCreatorTo.getTo();
        final List<PartnerAppPurchaseOrder> ordersList = partnerAppPurchaseOrderDao.findByAppIdAndShopIdenty(to.getAppId(), to.getShopIdentyList(), null);
        if (!CollectionUtils.isEmpty(ordersList)) {
            for(PartnerAppPurchaseOrder iorder : ordersList){
                if(iorder.getPayStatus() == PayStatusType.PAYED.getKey()){
                    log.info("下单购买门店[{}],已经存在购买过门店[{}]", to.getShopIdentyList(), ordersList.stream().map(e -> e.getAuthShopList()).collect(Collectors.toSet()));
                    throw new OpenServiceException(OpenErrorType.BUSINESS_ERROR, "存在已经购买的门店");
                }
            }
            log.info("存在购买中的订单{}",OpenGsonWrapper.toJson(ordersList));
            throw new OpenServiceException(OpenErrorType.BUSINESS_ERROR,"此应用正在购买中,请稍后");
        }
    }


    protected class OrderCreator {
        private OrderCreatorTo orderCreatorTo;
        private PartnerOpenApp partnerOpenApp;
        private OpenPurchaseTo to;
        private Integer shopNums;
        private PartnerAppPurchaseOrder order;

        public OrderCreator(OrderCreatorTo orderCreatorTo, PartnerOpenApp partnerOpenApp, OpenPurchaseTo to) {
            this.orderCreatorTo = orderCreatorTo;
            this.partnerOpenApp = partnerOpenApp;
            this.to = to;
        }

        public Integer getShopNums() {
            return shopNums;
        }

        public PartnerAppPurchaseOrder getOrder() {
            return order;
        }

        public OrderCreator invoke() {
            final List<Long> toShopList = to.getShopIdentyList() == null ? Lists.newArrayList() : to.getShopIdentyList();
            shopNums = to.getShopIdentyList().size();
            shopNums = shopNums > 0 ? shopNums : 0;

            order = new PartnerAppPurchaseOrder();
            order.setAppId(to.getAppId());
            order.setAppName(partnerOpenApp.getName());
            order.setBrandIdenty(orderCreatorTo.getBrandId());
            order.setAuthShopList(toShopList);
            order.setPrice(partnerOpenApp.getPrice().longValue());
            order.setShopNums(shopNums);
            order.setPayFee(order.getPrice() * shopNums);
            order.setActualFee(order.getPayFee());
            order.setCouponFee(0L);
            order.setUserId(orderCreatorTo.getUserId());
            order.setServerCreateTime(new Date());
            order.setServerUpdateTime(new Date());
            order.setAppName(partnerOpenApp.getName());
            order.setUserName(orderCreatorTo.getUserName());
            order.setClassifications(partnerOpenApp.getClassifications());
            order.setPartnerOpenApp(partnerOpenApp);
            order.setSource(orderCreatorTo.getSource());
            return this;
        }
    }
}
@Service
@Slf4j
class SubscribePurchaseOrderServiceImpl extends PurchaseOrderService {

    @Autowired
    private OpenAppService openAppService;

    @Autowired
    private PartnerAppSubscribeDao partnerAppSubscribeDao;

    // 保存订阅模式的有效期
    private void savePartnerAppSubscibe(PartnerOpenApp partnerOpenApp, PartnerAppPurchaseOrder partnerAppOrder, List<Long> shopIdentyList) {
        shopIdentyList.forEach(shopIdenty->{
            PartnerAppSubscribe partnerAppSubscribe = partnerAppSubscribeDao.findByShopIdentyAndAppId(partnerAppOrder.getAppId(), shopIdenty);
            if(partnerAppSubscribe == null){
                partnerAppSubscribe = new PartnerAppSubscribe();
                partnerAppSubscribe.setHistoryId(partnerAppOrder.getHistoryId());
                partnerAppSubscribe.setAppId(partnerAppOrder.getAppId());
                partnerAppSubscribe.setShopIdenty(shopIdenty);
                partnerAppSubscribe.setStartTime(partnerAppOrder.getServerCreateTime());
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(partnerAppOrder.getServerCreateTime());
                if(partnerOpenApp.getChargeTimeType() == APPChargeTimeType.MONTH.getKey()) {
                    calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) + partnerAppOrder.getTimes());
                } else {
                    calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + partnerAppOrder.getTimes());
                }
                partnerAppSubscribe.setEndTime(calendar.getTime());
            } else {
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(partnerAppSubscribe.getEndTime());
                if(partnerOpenApp.getChargeTimeType() == APPChargeTimeType.MONTH.getKey()) {
                    calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) + partnerAppOrder.getTimes());
                } else {
                    calendar.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + partnerAppOrder.getTimes());
                }
                partnerAppSubscribe.setEndTime(calendar.getTime());

            }
            partnerAppSubscribeDao.save(partnerAppSubscribe);

        });
    }


    @Override
    public void paySuccess(PartnerAppPurchaseOrder partnerAppPurchaseOrder, Long payFee) {
        super.paySuccess(partnerAppPurchaseOrder, payFee);
        final PartnerOpenApp partnerOpenApp =
                openAppService.findOneValidPartnerOpenApp(partnerAppPurchaseOrder.getAppId());

        savePartnerAppSubscibe(partnerOpenApp,partnerAppPurchaseOrder,partnerAppPurchaseOrder.getAuthShopList());
    }

    // 订阅模式时间处理
    @Override
    protected void buildOrderCustomer(OrderCreatorTo orderCreatorTo, OrderCreator orderCreator, PartnerOpenApp partnerOpenApp) {
        OpenPurchaseTo openPurchaseTo = orderCreatorTo.getTo();
        if (partnerOpenApp.getChargeTimeType() == APPChargeTimeType.MONTH.getKey()) {
            if(openPurchaseTo.getTimes() == null){
                openPurchaseTo.setTimes(TimeType.ONEMONTH.getTimes());
            }
        } else if (partnerOpenApp.getChargeTimeType() == APPChargeTimeType.YEAR.getKey()) {
            if(openPurchaseTo.getTimes() == null){
                openPurchaseTo.setTimes(TimeType.ONEYEWAR.getTimes());
            }
        } else {
            throw new OpenServiceException(OpenErrorType.BUSINESS_ERROR, "不支持的时间类型" + partnerOpenApp.getChargeTimeType());
        }
        orderCreator.getOrder().setTimes(TimeType.getTimeType(openPurchaseTo.getTimes()).getTimes());
        orderCreator.getOrder().setPayFee(orderCreator.getOrder().getPrice() * orderCreator.getShopNums() * orderCreator.getOrder().getTimes());
    }

    @Override
    protected void verify(OrderCreatorTo orderCreatorTo, PartnerOpenApp partnerOpenApp) {
        super.verify(orderCreatorTo,partnerOpenApp);
        if(orderCreatorTo.getTo().getTimes() == null){
            throw new OpenServiceException(OpenErrorType.PARAM_DATA_ERROR, "订阅模式times必传");

        }
        if (partnerOpenApp == null) {
            throw new OpenServiceException(OpenErrorType.BUSINESS_ERROR, "不存应用[" + orderCreatorTo.getTo().getAppId() + "]");
        }

    }

}

单元测试

@RunWith(MockitoJUnitRunner.class)
public class PurchaseOrderServiceFactoryTest {
    @Mock
    private ByoutPuchaseOrderServiceImpl byoutAppPuchaseOrderService;

    @Mock
    private OneTimePurchaseOrderServiceImpl oneTimeAppPurchaseOrderService;

    @Mock
    private SubscribePurchaseOrderServiceImpl subscribeAppPurchaseOrderService;

    @InjectMocks
    private PurchaseOrderServiceFactory purchaseOrderServiceFactory;
    @Test
    public void shouldReturnRightPurchaseOrderService() throws Exception {
        final PurchaseOrderService buyOutPurchaseOrderService = purchaseOrderServiceFactory.getPuchaeOrderService(AppChargeType.BUYOUT);
        assertThat(buyOutPurchaseOrderService,is(byoutAppPuchaseOrderService));

        final PurchaseOrderService onetimePurchaseOrderService = purchaseOrderServiceFactory.getPuchaeOrderService(AppChargeType.ONETIME);
        assertThat(onetimePurchaseOrderService,is(oneTimeAppPurchaseOrderService));

        final PurchaseOrderService subscribePurchaseOrderService = purchaseOrderServiceFactory.getPuchaeOrderService(AppChargeType.SUBSCRIBE);
        assertThat(subscribePurchaseOrderService,is(subscribeAppPurchaseOrderService));
    }

}
@RunWith(MockitoJUnitRunner.class)
public class OneTimePurchaseOrderServiceImplTest {
    // mock对象

    @Before
    public void setUp(){
        // mock 数据
    }

    @Test
    public void shouldSaveCreatOrderSuccess(){
        final PartnerAppPurchaseOrder order = oneTimePurchaseOrderService.createOrder(orderCreatorTo);
        assertThat(order.getPayFee(),is(1L));
        verify(partnerAppPurchaseOrderDao).save(eq(order));

    }

    @Test
    public void shouldNoErrorWhenPaySuccess(){
        final PartnerAppPurchaseOrder order = oneTimePurchaseOrderService.createOrder(orderCreatorTo);
        oneTimePurchaseOrderService.paySuccess(order,1L);
        verify(partnerOpenAppPurchasedProducer).sendMessage(eq(order.getId()));

    }
@RunWith(MockitoJUnitRunner.class)
public class SubscribePurchaseOrderServiceImplTest {


    // mock对象

    @Before
    public void setUp(){
        // mock数据
    }

    @Test
    public void shouldSaveCreatOrderSuccess(){
        final PartnerAppPurchaseOrder order = subscribePurchaseOrderService.createOrder(orderCreatorTo);
        assertThat(order.getPayFee(),is(1L));
        verify(partnerAppPurchaseOrderDao).save(eq(order));

    }

    @Test
    public void shouldNoErrorWhenPaySuccessWhenSunscibeNotNull(){
        PartnerAppSubscribe partnerAppSubscribe = new PartnerAppSubscribe();
        partnerAppSubscribe.setStartTime(new Date());
        partnerAppSubscribe.setEndTime(new Date());
        doReturn(partnerAppSubscribe).when(partnerAppSubscribeDao).findByShopIdentyAndAppId(eq(orderCreatorTo.getTo().getAppId()),anyLong());
        final PartnerAppPurchaseOrder order = subscribePurchaseOrderService.createOrder(orderCreatorTo);
        subscribePurchaseOrderService.paySuccess(order,1L);
        verify(partnerAppSubscribeDao).save(eq(partnerAppSubscribe));
        verify(partnerOpenAppPurchasedProducer).sendMessage(eq(order.getId()));

    }

    @Test
    public void shouldNoErrorWhenPaySuccessWhenSunscibeIsNull(){
        doReturn(null).when(partnerAppSubscribeDao).findByShopIdentyAndAppId(eq(orderCreatorTo.getTo().getAppId()),anyLong());
        final PartnerAppPurchaseOrder order = subscribePurchaseOrderService.createOrder(orderCreatorTo);
        subscribePurchaseOrderService.paySuccess(order,1L);
        verify(partnerAppSubscribeDao).save(any(PartnerAppSubscribe.class));
        verify(partnerOpenAppPurchasedProducer).sendMessage(eq(order.getId()));

    }
}
@RunWith(MockitoJUnitRunner.class)
public class ByoutPuchaseOrderServiceImplTest {
    // mock对象

    @InjectMocks
    private ByoutPuchaseOrderServiceImpl byoutPuchaseOrderService;

    @Before
    public void setUp(){
      //mock 数据
        .....
    }

    @Test
    public void shouldSaveCreatOrderSuccess(){
        final PartnerAppPurchaseOrder order = byoutPuchaseOrderService.createOrder(orderCreatorTo);
        assertThat(order.getPayFee(),is(1L));
        verify(partnerAppPurchaseOrderDao).save(eq(order));

    }

    @Test(expected= OpenServiceException.class)
    public void shouldThrowExceptionWhenBrandIdHasPurchased(){
        PartnerAppPurchaseHistory partnerAppPurchaseHistory = new PartnerAppPurchaseHistory();
        partnerAppPurchaseHistory.setId("wqersww");
        partnerAppPurchaseHistory.setAppId("123435465");
        partnerAppPurchaseHistory.setShopIdenty(Lists.newArrayList());
        doReturn(partnerAppPurchaseHistory).when(partnerAppPurchaseHistoryDao).findByAppIdAndUserId(anyString(),anyLong(),anyLong());

        final PartnerAppPurchaseOrder order = byoutPuchaseOrderService.createOrder(orderCreatorTo);

    }

    @Test(expected= OpenServiceException.class)
    public void shouldThrowExceptionWhenShopHasPurchased(){
        PartnerAppPurchaseHistory partnerAppPurchaseHistory = new PartnerAppPurchaseHistory();
        partnerAppPurchaseHistory.setId("wqersww");
        partnerAppPurchaseHistory.setAppId("123435465");
        partnerAppPurchaseHistory.setShopIdenty(Lists.newArrayList(222L));
        doReturn(Lists.newArrayList(partnerAppPurchaseHistory)).when(partnerAppPurchaseHistoryDao).findByAppIdAndShopIdenty(anyString(),anyList());
        final PartnerAppPurchaseOrder order = byoutPuchaseOrderService.createOrder(orderCreatorTo);

    }

    @Test
    public void shouldNoErrorWhenPaySuccess(){
        final PartnerAppPurchaseOrder order = byoutPuchaseOrderService.createOrder(orderCreatorTo);
        byoutPuchaseOrderService.paySuccess(order,1L);
        verify(partnerOpenAppPurchasedProducer).sendMessage(eq(order.getId()));
    }
}
posted @ 2017-12-10 22:42  dragonfei  阅读(180)  评论(0)    收藏  举报