往来款余额划分账龄的一般方法

往来款项的账龄划分是个很简单的问题。本文主要用途为给实习生作简单的培训,让其看完后能快速上手做底稿。

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})\)

\[\begin{aligned} E&=S+D-C \newline &\Downarrow\newline \begin{bmatrix} e_1\newline e_2\newline e_3\newline \cdots\newline e_n \end{bmatrix} &= \begin{bmatrix} 0\newline s_1\newline s_2\newline \cdots\newline s_{n-1}+s_n \end{bmatrix} + \begin{bmatrix} d\newline 0\newline 0\newline \cdots\newline 0 \end{bmatrix} - \begin{bmatrix} 0\newline 0\newline 0\newline \cdots\newline c \end{bmatrix} \end{aligned} \]

其实\(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)]\)

结论:

\[\begin{aligned} e_j&= \begin{cases} max[0,d+min(0,\sum_{i=1}^{n}s_i-c)], & j=1 \newline max[0,s_{j-1}+min(0,\sum_{i=j}^{n}s_i-c)], & 1<j\leqslant{n}\newline \end{cases}\newline \newline \vec{E}&= \begin{bmatrix} max[0,d+min(0,\sum_{i=1}^{n}s_i-c)]\newline max[0,s_{1}+min(0,\sum_{i=2}^{n}s_i-c)]\newline \cdots\newline max[0,s_{n-2}+min(0,s_{n-1}+s_n-c)]\newline max[0,s_{n-1}+min(0,s_n-c)]\newline \end{bmatrix} \end{aligned} \]

2.2 多个客商的账龄矩阵推导

设有m个客商,账龄分为n段,于是有:

\[\begin{aligned} E&=S+D-C \newline \begin{bmatrix} e_{11}&e_{12}&e_{13}\cdots{e_{1n}}\newline e_{21}&e_{22}&e_{23}\cdots{e_{2n}}\newline e_{31}&e_{32}&e_{33}\cdots{e_{3n}}\newline \cdots\newline e_{m1}&e_{m2}&e_{m3}\cdots{e_{mn}}\newline \end{bmatrix}_{(m\times{n})} \newline &= \begin{bmatrix} {0}&s_{11}&s_{12}\cdots{s_{1,n-1}+s_{1n}}\newline {0}&s_{21}&s_{22}\cdots{s_{2,n-1}+s_{2n}}\newline {0}&s_{31}&s_{32}\cdots{s_{3,n-1}+s_{3n}}\newline \cdots\newline {0}&s_{m1}&s_{m2}\cdots{s_{m,n-1}+s_{mn}}\newline \end{bmatrix}_{(m\times{n})} \newline &+ \begin{bmatrix} d_{1}&{0}&{0}\cdots{0}\newline d_{2}&{0}&{0}\cdots{0}\newline d_{3}&{0}&{0}\cdots{0}\newline \cdots\newline d_{m}&{0}&{0}\cdots{0}\newline \end{bmatrix}_{(m\times{n})} - \begin{bmatrix} {0}&{0}&{0}\cdots{c_1}\newline {0}&{0}&{0}\cdots{c_2}\newline {0}&{0}&{0}\cdots{c_3}\newline \cdots\newline {0}&{0}&{0}\cdots{c_m}\newline \end{bmatrix}_{(m\times{n})} \newline &= \begin{bmatrix} max[0,d_1+min(0,\sum_{i=1}^{n}s_{1i}-c_1)]& max[0,s_{11}+min(0,\sum_{i=2}^{n}s_{1i}-c_1)]& \cdots& max[0,s_{1,n-1}+min(0,\sum_{i=n}^{n}s_{1i}-c_1)]\newline max[0,d_2+min(0,\sum_{i=1}^{n}s_{2i}-c_2)]& max[0,s_{21}+min(0,\sum_{i=2}^{n}s_{2i}-c_2)]& \cdots& max[0,s_{2,n-1}+min(0,\sum_{i=n}^{n}s_{2i}-c_2)]\newline max[0,d_3+min(0,\sum_{i=1}^{n}s_{3i}-c_3)]& max[0,s_{31}+min(0,\sum_{i=2}^{n}s_{3i}-c_3)]& \cdots& max[0,s_{3,n-1}+min(0,\sum_{i=n}^{n}s_{3i}-c_3)]\newline \cdots\cdots&\newline max[0,d_m+min(0,\sum_{i=1}^{n}s_{mi}-c_m)]& max[0,s_{m1}+min(0,\sum_{i=2}^{n}s_{mi}-c_m)]& \cdots& max[0,s_{m,n-1}+min(0,\sum_{i=n}^{n}s_{mi}-c_m)]\newline \end{bmatrix}_{m\times{n}}\newline \begin{Bmatrix} e_{ij} \end{Bmatrix}_{m\times{n}} &= \begin{Bmatrix} \begin{cases} max[0,s_{i,j-1}+min(0,\sum_{\lambda=j}^{n}s_{i,\lambda}-c_i], &(1\leqslant{i}\leqslant{m},1<{j}\leqslant{n},i,j\in{N_+})\newline max[0,d_i+min(0,\sum_{\lambda=1}^{n}s_{i,\lambda}-c_i)], &(j=1,1\leqslant{i}\leqslant{m},i\in{N_+}) \end{cases} \end{Bmatrix}_{m\times{n}} \end{aligned} \]

3. 结论

  • 经过上述推导可知,在一共划分n个账龄段,且上期账龄余额已知的情况下,本期第i个客商的第j个账龄段的余额为:

\[\begin{aligned} \begin{Bmatrix} e_{ij} \end{Bmatrix}_{m\times{n}} &= \begin{Bmatrix} \begin{cases} max[0,s_{i,j-1}+min(0,\sum_{\lambda=j}^{n}s_{i,\lambda}-c_i], &(1\leqslant{i}\leqslant{m},1<{j}\leqslant{n},i,j\in{N_+})\newline max[0,d_i+min(0,\sum_{\lambda=1}^{n}s_{i,\lambda}-c_i)], &(j=1,1\leqslant{i}\leqslant{m},i\in{N_+}) \end{cases} \end{Bmatrix}_{m\times{n}} \end{aligned} \]

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);
    }
}
posted @ 2025-08-18 18:42  zefsk  阅读(97)  评论(0)    收藏  举报