项目背景:建行收到财政发来的公务卡垫款xml报文存库,报文格式分主单和明细,主单不包含收款账号,明细单包含收款账号,即一个主单包含多个明细(明细确定不超过500,但具体多少,未知)!建行公务卡支付需按照明细支付,支付完成以后,需按主单生成清算单到人行做清算,也是主单+明细的情况,但是明细单有一个要求,不能超过500,超过500必须分包,而且必须保证一个主单的明细单必须在一个清算单中,不能存在一个主单对应的明细单在两个清算单中,而且必须保证清算单最少(不能10个公务卡,生成10张清算单)。
解决思路草稿.png比如说主单A包含450条明细单,主单B包含300条明细单,主单C包含200条明细单,那么这种情况就只能生成3张清算单,如果主单D包含10条明细单,那么也只能生成3张清算单,虽然人行清算也是按照明细单做清算,但是为了三方对账方便(主要还是财政),建行规则必须按照这种业务逻辑生成!
所以依据草稿(解决思路),理了一下业务逻辑:
1、取出Map<明细条数,公务卡主单凭证号>
2、求Map明细条数的Sum
3、明细合计<499,则生成一个清算单,>499考虑递归,最终合计小于499为出口
模拟业务逻辑,代码如下:
package xf;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class Person {
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("79", "主单凭证号1"); // 1111
map.put("68", "主单凭证号2");
map.put("57", "主单凭证号3");
map.put("46", "主单凭证号4");
map.put("35", "主单凭证号5");
map.put("24", "主单凭证号6");
map.put("12", "主单凭证号7"); // 1111
map.put("1", "主单凭证号8"); // 1111
int count = SumList(map);
System.out.println("合计条数========" + count);
if (count < 100) {
System.out.println("就一笔清算单");
}
if (count > 100) {
System.out.println("清算明细单超过100======================================");
List<String> strArr = new ArrayList<String>();
strArr = returnVoucher(map); //第一次取出不超过100的主单凭证号 AA
Map<String, String> remMap = new HashMap<String, String>();
remMap = returnRemoveMap(map, strArr); //第一次剔除AA
// 统计remMap明细条数
int sum = SumList(remMap);
boolean turn = true;
int n = 0;
int m = 0;
while (turn) {
if (sum < 100) {
// 直接生成最后一笔清算
System.err.println("我是最后一笔清算 我是出口 递归函数出口!");
strArr = returnVoucher(remMap); //剩下的
for (String str : strArr) {
System.err.println("最后剩下的凭证号==" + str);
}
turn = false;
break; // 出口
}
if (sum > 100) {
// 循环
n++;
m++;
System.err.println("生成第" + n + "笔清算!"); //此时的strArr刚好是第一次取出来的
remMap = returnRemoveMap(remMap, strArr); // 在剔除
System.out.println("第" + m + "次剔除!");
sum = SumList(remMap); // 判断条数
System.out.println("统计明细条数===" + sum);
strArr = returnVoucher(remMap);
}
}
}
}
// 取出明细合计小于499的任意主单
public static List<String> returnVoucher(Map<String, String> map) {
List<String> strArr = new ArrayList<String>();
int sum = 0;
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
sum = sum + Integer.valueOf(entry.getKey()); // key是明细条数
if (sum < 100) {
strArr.add(entry.getValue());
// System.out.println("key= " + entry.getKey() + " and value= "
// + entry.getValue());
} else {
break;
}
}
return strArr;
}
// 剔除list 返回剩余Map
public static Map<String, String> returnRemoveMap(Map<String, String> map, List<String> listStr) {
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
for (String str : listStr) {
if (str.equals(entry.getValue())) {
// map.remove(entry.getKey()); //map移除元素必须用迭代器
it.remove();
}
}
}
return map;
}
//统计明细条数的sum
public static Integer SumList(Map<String, String> remMap) {
int sum = 0;
Iterator<Map.Entry<String, String>> it = remMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
sum = sum + Integer.valueOf(entry.getKey()); // key是明细条数
}
return sum;
}
}
模拟Console.png
main
函数汇总的map,模拟数据库中取出的Map,该业务逻辑需要注意的是,并非合计数除以500的结果+1就是最少清算单条数,这个就是该业务最大难点,比方说:
主单A
包含450
条明细单
主单B
包含300
条明细单
主单C
包含200
条明细单
主单D
包含100
条明细单
主单E
包含350
条明细单
虽然明细合计为1400
,但是必须生成4
张清算单,这是必须要注意到的地方!
网友评论