摘要:在项目开发中,有这样一个业务场景,就是我们有个虚拟服务,服务是按一定的YD(这里的YD相当于一般的积分即可)去抵扣的,同时YD又是通过用户下单购买产生的,规则如下图:
那么在用户使用服务的时候,会消费一定的YD,那么久需要计算账户的剩余YD,详细见如下代码:
/**
* Copyright 2019. yaodouwang.com Studio All Right Reserved
*
* Create on Nov 8, 2019 1:56:16 PM
* created by yolo
* Version 1.0.0
*/
package com.yaodou.baseproduct;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.yaodou.utils.OtherException;
/**
* 计算账户余额
* @author yolo
* @date 2019-11-08
*/
public class caculatePriceUtil {
public static void main(String[] args) {
generateTotal("A1001",new BigDecimal(1000));
generateTotal("A1001",new BigDecimal(1000));
generateTotal("A1001",new BigDecimal(1000));
}
private static final String DEAULT_ORDER_ID = "NA";
private static final BigDecimal DEFAULT_UNIT_PRICE = new BigDecimal(0.05);
/**
* 根据用户编码获取当前用户账户余额
* @param userId 用户唯一标示
* @return
* @author yolo
* @date 2019-11-08
*/
@SuppressWarnings("unchecked")
private static Map<String,Object> generateTotal(String userId,BigDecimal todayQuantity) {
//如果今日消费数量为0 则不用走以下统计流程
if(todayQuantity.compareTo(BigDecimal.ZERO) == 0) {
return null;
}
//返回数据形式定义
Map<String,Object> returnMap = new HashMap<>();
//--》消费记录map
List<YdyConsumePO> consumeList = new ArrayList<>();
//剩余总额
BigDecimal remainTotalMoney = BigDecimal.ZERO;
//TODO 根据userId去账户表ydy_account查询该用户对应的 账户account_id 余额remain_balance,剩余条数remain_quantity
String accountId = "A1001";
//剩余条数,这个条数是统计后的条数
BigDecimal remainQuantity = new BigDecimal(100000);
//TODO 去ydy_recharge表查询 status="N"的充值记录,时间正序排序。取出以下对应字段
List<YdyRechargePO> rechargeList = new LinkedList<YdyRechargePO>();
//如果没有可用充值记录,则直接把今日消费的条数记录成 欠费条数
if(rechargeList.size() ==0) {
YdyConsumePO consumer = new YdyConsumePO();
consumer.setAcountId(accountId);
consumer.setConsumeQuantity(remainQuantity);
consumer.setOrderId("初始化orderId"); //为空代表超前消费//欠费
consumeList.add(consumer);
remainTotalMoney = remainQuantity.multiply(DEFAULT_UNIT_PRICE).negate();//取负数
}else {
BigDecimal totalQuantity = rechargeList.get(0).getTotalQuanity();
//校准数据,如果剩余量和库存不一样则跑出异常
if(totalQuantity.compareTo(remainQuantity) != 0){
throw new OtherException("数据有异常,请联系开发人员核对数据!");
}
//如果今日消费条数大于或者等于剩余总的条数
if(todayQuantity.compareTo(totalQuantity) !=-1) {
//TODO 所有的rechage表中的状态都变成 N
for(YdyRechargePO recharge:rechargeList) {
generateConsumList(consumeList, recharge.getOrderId(), recharge.getRemainQuantity(), accountId);
remainTotalMoney = BigDecimal.ZERO;
}
//大于
if(todayQuantity.compareTo(totalQuantity) ==1) {
//欠费数量
BigDecimal oweQuantity = todayQuantity.divide(totalQuantity);
generateConsumList(consumeList, oweQuantity, accountId);
remainTotalMoney = oweQuantity.multiply(DEFAULT_UNIT_PRICE).negate();
}
}else {
Map<String,Object> rechargeMap = getIndex(rechargeList, todayQuantity);
List<YdyRechargePO> rechargeUpdateList= (List<YdyRechargePO>) rechargeMap.get("rechargeUpdateList");
BigDecimal newRemainQuantity = (BigDecimal) rechargeMap.get("newRemainQuantity");
int index = (int) rechargeMap.get("index");
YdyRechargePO updateRemaining = rechargeList.get(index);
if(newRemainQuantity.compareTo(BigDecimal.ZERO)!=0) {
//TODO 修改updateRemaining记录 把remianQuantity设置成newRemainQuantity
generateConsumList(consumeList, updateRemaining.getOrderId(),
updateRemaining.getRemainQuantity().divide(newRemainQuantity), accountId);
}
//TODO 把rechargeIdList 集合中的YdyRechargePO 记录状态都修改成N
generateConsumList(consumeList, rechargeUpdateList);
remainTotalMoney = (BigDecimal) rechargeMap.get("remianTotalMoney");
}
}
//返回的数据
returnMap.put("remainTotalMoney", remainTotalMoney);
returnMap.put("consumerList", consumeList);
return returnMap;
}
/**
* 生成消费记录
* @param consumeList
* @param rechargeList
* @author yolo
* @date 2019-11-08
*/
private static void generateConsumList(List<YdyConsumePO> consumeList,List<YdyRechargePO> rechargeList) {
for(YdyRechargePO recharge:rechargeList) {
generateConsumList(consumeList, recharge.getOrderId(), recharge.getRemainQuantity(), recharge.getAcountId());
}
}
/**
* 生成消费记录
* @param consumeList 消费记录insert数据的list
* @param orderId 充值编码
* @param consumeQuantity 消费数量
* @param accuntId 账户编码
* @author yolo
* @date 2019-11-08
*/
private static void generateConsumList(List<YdyConsumePO> consumeList,String orderId,BigDecimal consumeQuantity,String accountId) {
YdyConsumePO consumer = new YdyConsumePO();
consumer.setOrderId(orderId);
consumer.setConsumeQuantity(consumeQuantity);
consumer.setAcountId(accountId);
consumeList.add(consumer);
}
/**
* 生成消费记录
* @param consumeList 消费记录insert数据的list
* @param consumeQuantity 消费数量
* @param accountId 账户编码
* @author yolo
* @date 2019-11-08
*/
private static void generateConsumList(List<YdyConsumePO> consumeList, BigDecimal consumeQuantity,String accountId) {
generateConsumList(consumeList, DEAULT_ORDER_ID, consumeQuantity, accountId);
}
/**
* 计算剩余第几条记录的总条数满足扣除
* @param rechargeList 没有消费的充值记录的list
* @param todayQuantity 今日消费条数
* @return
* @author yolo
* @date 2019-11-08
*/
private static Map<String,Object> getIndex(List<YdyRechargePO> rechargeList,BigDecimal todayQuantity) {
BigDecimal total = BigDecimal.ZERO;
int size = rechargeList.size();
List<YdyRechargePO> rechargeUpdateList = new ArrayList<>(size);
//充值记录剩余未使用的条数
BigDecimal newRemainQuantity = BigDecimal.ZERO;
//账余额
BigDecimal remianTotalMoney = BigDecimal.ZERO;
//判断是否需要停止叠加价格
boolean isCaculateMoney = Boolean.FALSE;
Map<String,Object> returnMap = new HashMap<>();
for(int i=0;i< size;i++) {
YdyRechargePO recharge = rechargeList.get(i);
total = recharge.getRemainQuantity();//剩余未使用的的数量
if(isCaculateMoney) {
remianTotalMoney = remianTotalMoney.add(recharge.getRechargeAmount());//充值金额
}else {
if(total.compareTo(todayQuantity) !=-1) {
newRemainQuantity = total.divide(todayQuantity);
remianTotalMoney = recharge.getRechargeUnitPrice().multiply(newRemainQuantity).setScale(2);//充值金额
if(newRemainQuantity.compareTo(BigDecimal.ZERO)==0) {
rechargeUpdateList.add(recharge);
}
returnMap.put("index", i);
isCaculateMoney = Boolean.TRUE;
}else {
rechargeUpdateList.add(recharge);
total = total.add(recharge.getRemainQuantity());
}
}
}
returnMap.put("newRemainQuantity", newRemainQuantity);
returnMap.put("rechargeUpdateList", rechargeUpdateList);
returnMap.put("remianTotalMoney", remianTotalMoney);
return returnMap;
}
}