All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.dennisit.vplus.data.utils.grain.GrainUtils Maven / Gradle / Ivy

There is a newer version: 2.0.8
Show newest version
package com.github.dennisit.vplus.data.utils.grain;

import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.util.Assert;

import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

public class GrainUtils {


    /**
     * 检测目标集合元素是否够抵扣
     *
     * @param coll 抵扣的目标集合
     * @param sum  抵扣总数
     * @return 目标集合中的数据是否够抵扣
     */
    public static boolean deductible(List coll, long sum) {
        Assert.isTrue(sum > 0 && CollectionUtils.isNotEmpty(coll), "参数不合规(抵扣集合为空|抵扣总数<0)");
        boolean deductible = false;

        AtomicLong count = new AtomicLong(0);
        for (GrainEntry.GrainBatch triple : coll) {
            if (count.addAndGet(triple.getNum()) >= sum) {
                deductible = true;
                break;
            }
        }
        return deductible;
    }

    /**
     * 从原始批次中追加抠币目标批次数
     *
     * @param coll 目标扣除集合, 结构是因为需求要求扣除按顺序批次顺序
     * @param sum  目标总数
     * @return 抵扣逻辑
     */
    public static GrainEntry.DiscountEntry discount(List coll, long sum) {
        Assert.isTrue(deductible(coll, sum), "目标集合不够抵扣");

        AtomicLong total = new AtomicLong(sum);
        GrainEntry.GrainBatch tail = null;
        List used = Lists.newArrayList();

        for (GrainEntry.GrainBatch triple : coll) {
            if (total.get() - triple.getNum() >= 0) {               // 抵扣全部(只能>=)
                total.addAndGet(0 - triple.getNum());
                used.add(triple);
                if (total.get() == 0) {
                    tail = new GrainEntry.GrainBatch(triple.getId(), 0, triple.getCreateTime());
                    break;
                }

            } else if (total.get() > 0) {                           // 抵扣部分(只能>)
                long occupy = total.get();                        // 尾数占用
                total.addAndGet(0 - occupy);
                tail = new GrainEntry.GrainBatch(triple.getId(), triple.getNum() - occupy, triple.getCreateTime());
                used.add(new GrainEntry.GrainBatch(triple.getId(), occupy, triple.getCreateTime()));
            }
        }
        return new GrainEntry.DiscountEntry(tail, used);
    }


    /**
     * 退还币算法抽象, 这里有一些业务前提条件: 退还的所有数据,存放到优先使用批次集合中去
     *
     * @param referList    退换参照对象[对应的入账流水] 升序序列 (referList是priorityPair和usedPair的数据KEY的集合总集)
     * @param priorityPair 优先使用对象[对应的历史退币优先批次]
     * @param usedPair     待退还对象[对应的本次要退还的批次]
     * @return 要求返回结果需要按顺序进行入库抵消
     */
    public static GrainEntry.RefundEntry refund(List referList, Map priorityPair, Map usedPair) {
        // 退还记录总数
        AtomicLong refundTotal = new AtomicLong(0);
        // 退还更新后优先使用批次集合
        List priorityList = Lists.newCopyOnWriteArrayList();
        // 有效的真实有效的数据集合
        List refundedList = Lists.newCopyOnWriteArrayList();

        // 退还处理逻辑
        for (GrainEntry.GrainBatch triple : referList) {
            // 数据已经过期的不在处理
            if (triple.getCreateTime().getTime() <= System.currentTimeMillis()) {
                continue;
            }
            // 如果待退还的批次集包含在参照集中
            if (usedPair.containsKey(triple.getId())) {
                long refundNum = usedPair.get(triple.getId());
                // 退还优先批次处理
                if (priorityPair.containsKey(triple.getId())) {
                    // merge 如果退还的批次ID包含在优先批次集合中, 则将退还批次和优先批次上的数量聚合
                    long sum = refundNum + priorityPair.get(triple.getId());
                    long val = sum >= triple.getNum() ? triple.getNum() : sum;
                    priorityList.add(new GrainEntry.GrainBatch(triple.getId(), val, triple.getCreateTime()));
                } else {
                    // append 如果退还的批次ID不包含在优先批次集合中, 则追加到优先使用批次
                    long val = refundNum >= triple.getNum() ? triple.getNum() : refundNum;
                    priorityList.add(new GrainEntry.GrainBatch(triple.getId(), val, triple.getCreateTime()));
                }
                // 追加退还集合
                refundedList.add(new GrainEntry.GrainBatch(triple.getId(), refundNum, triple.getCreateTime()));
                // 追加退还总数
                refundTotal.addAndGet(refundNum);
            }

            // 退币批次不存在于优先批次的数据继续追加上去
            if (priorityPair.containsKey(triple.getId()) && !usedPair.containsKey(triple.getId())) {
                priorityList.add(new GrainEntry.GrainBatch(triple.getId(), priorityPair.get(triple.getId()), triple.getCreateTime()));
            }
        }

        return new GrainEntry.RefundEntry(refundedList, sortGrainBatch(priorityList), refundTotal.get());
    }

    /**
     * 按照批次编号升序排列优先使用批次信息
     *
     * @param coll 目标集合
     * @return 升序后的集合
     */
    public static List sortGrainBatch(List coll) {
        if (CollectionUtils.isEmpty(coll)) {
            return Lists.newArrayList();
        }
        Ordering batchIdAsc = Ordering.natural().nullsLast().onResultOf(new Function() {
            @Nullable
            @Override
            public Long apply(@Nullable GrainEntry.GrainBatch input) {
                return input.getId();
            }
        });
        Collections.sort(coll, batchIdAsc);
        return coll;
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy