摘要:在項目開發中,有這樣一個業務場景,就是我們有個虛擬服務,服務是按一定的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;
}
}