往来款余额划分账龄的一般方法
往来款项的账龄划分是个很简单的问题。本文主要用途为给实习生作简单的培训,让其看完后能快速上手做底稿。
1. 假设
本文论述往来款余额账龄划分的方法,有如下假设:
- 上期账龄已知;
- 先进先出法。本期减少优先消耗上期末最长账龄的余额;
- 除最长账龄段之外,上期末任意账龄段的余额,在本期末的余额不会增加;
- 已经对本期增减金额作如下处理:本期增加金额如为负数,视同本期减少金额,本期减少如为负数,视同本期增加金额;
2. 公式推导
2.1 单个客商的账龄向量推导
首选考虑单个客商的账龄问题,设:
1.账龄共分为n段;
2.期初、本期增加、本期减少、期末金额分别为:S、D、C、E;
3.期初、本期增加、本期减少、期末金额的账龄向量分别为:\(\vec{S}=\begin{bmatrix}{0}\newline{s_1}\newline\cdots\newline{s_n+s_{n-1}}\end{bmatrix}\)、\(\vec{D}=\begin{bmatrix}{d}\newline{0}\newline\cdots\newline{0}\end{bmatrix}\)、\(\vec{C}=\begin{bmatrix}{0}\newline{0}\newline\cdots\newline{c}\end{bmatrix}\)、\(\vec{E}=\begin{bmatrix}{e_1}\newline{e_2}\newline\cdots\newline{e_n}\end{bmatrix}\);
期末余额与账龄向量之间有一个映射关系存在,易知\(E=sum(\vec{E}),S=sum(\vec{S}),D=sum(\vec{D}),C=sum(\vec{C})\);
其实\(e_j\)的结果只有三种可能,取决于\(c\)与\(\sum_{i=j}^{n}s_i\)、\(\sum_{i=j-1}^{n}s_i\)之间的大小关系:
- \(c\leqslant\sum_{i=j}^{n}s_i\),此时上期长于\(j\)(落到本期为长于\(j-1\))账龄段的余额合计,减去本期减少金额,还有余额,故\(e_j=s_{j-1}\);
- \(c\in(\sum_{i=j}^{n}s_i,\sum_{i=j-1}^{n}s_i)\),此时\(e_j=\sum_{i=j-1}^{n}s_i-c\);
- \(\sum_{i=j-1}^{n}s_i\leqslant{c}\),此时\(e_j=0\);
- 特别地,当\(j=1\)时,\(e_1=max[0,d+min(0,\sum_{i=1}^{n}s_i-c)]\);
- 特别地,当\(j=n\)时,\(e_n=max(0,s_{n-1}+s_n-c)=max[0,s_{n-1}+min(0,s_n-c)]\);
结论:
2.2 多个客商的账龄矩阵推导
设有m个客商,账龄分为n段,于是有:
3. 结论
- 经过上述推导可知,在一共划分n个账龄段,且上期账龄余额已知的情况下,本期第i个客商的第j个账龄段的余额为:
4. 算法实现
#[derive(Debug)]
struct CompData{
name:String,
start:Vec<f64>,//上期账龄向量未转化为本期视角下的账龄向量;
dr:f64,
cr:f64,
end:Vec<f64>,
}
impl CompData{
pub fn new(
na:String,
_st:Vec<f64>,
_dr:f64,
_cr:f64,
)->Self{
let mut d=CompData{
name:na,
start:_st,
dr:_dr,
cr:_cr,
end:Vec::new(),
};
d.age_split();
return d;
}
fn age_split(
self:&mut Self
)->(){
if self.start.is_empty(){
panic!();
}
if self.start.len()<2{
panic!();
}
self.end=self.start.clone();
self.end.insert(0,self.dr.clone());
let last_1=self.end.pop().unwrap();
let last_2=self.end.pop().unwrap();
self.end.push(last_1+last_2-self.cr.clone());
negative_tail_process(&mut self.end);
}
fn check_balance(self:&Self)->bool{
self.start.iter().sum::<f64>()+self.dr-self.cr==self.end.iter().sum::<f64>()
}
}
fn if_negative_tail<'a>(v:&'a Vec<f64>)->bool{
let tail=v.get(v.len()-1);
match tail{
Option::Some(tail)=>{
if tail <&0.0{
true
}else{
false
}
},
Option::None=>{
panic!("tail is not a number!");
},
}
}
fn negative_tail_process<'a>(
aged_split:&'a mut Vec<f64>
)->(){
if aged_split.is_empty(){
panic!("check the input argument:{:?}",aged_split);
}
let age_len=aged_split.len();
while if_negative_tail(&aged_split){
if aged_split.len()==1{break;}
let last_1=aged_split.pop();
let last_2=aged_split.pop();
match last_1{
Option::Some(last_1)=>{
match last_2{
Option::Some(last_2)=>{
aged_split.push(last_1+last_2);
},
Option::None=>{
panic!("last_1 is fine, yet last_2 is None.");
},
}
},
Option::None=>{
panic!("last_1 is None;last_2 does not matter.");
},
}
}
while aged_split.len()<age_len{
aged_split.push(0f64);
}
}
本文来自博客园,作者:zefsk,转载请注明原文链接:https://www.cnblogs.com/zefsk/p/19044970

浙公网安备 33010602011771号