一个小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()));
}
}
没有智能的代码,源码面前了无秘密
浙公网安备 33010602011771号