Post

账单生成代码

最近公司做一个租房项目,其中有一个逻辑是账单账期生成。

比如租房押一付三,压2付5, 这类的需要根据租借时间生成账单和账期, 这里备注下,以备后用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
package org.example;

import lombok.Data;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;


public class BillUtil {

  public static final String yyyyMMSimple = "yyyyMM";


  /**
   *
   * 根据起始和结束日期生成账单, 返回账单列表
   *
   *
   *
   * @param start
   * @param end
   * @param payment 缴费方式   1月扣2季度扣3半年扣4一年扣   * 1月扣 2季度扣 3半年扣 4一年扣      * 11 全额支付      * 12 2月付      * 13 二年      * 14 三年      * 15 四年
   *
   * @param delay 提前延后天数,正数提前,负数延后
   * @param fixDay 固定日期收款
   * @return
   */
  public static List<BillDto> createBill(LocalDateTime start, LocalDateTime end, int payment, int delay, Integer fixDay) {
    int step1 = getPayTypeMonthStep(payment);

    if(payment == 11) {
      return doCreateBill11(start, end );
    } else {
      return doCreateBill0(start, end , step1, delay, fixDay);
    }
  }


  /**
   * 全额支付账单创建
   *
   * @param start
   * @param end
   * @return
   */
  public static List<BillDto> doCreateBill11(LocalDateTime start, LocalDateTime end) {
    List<BillDto> res = new ArrayList<>();
    BillDto tmp = new BillDto();
    tmp.setStart(start);
    tmp.setEnd(end);
    tmp.setDateRangeStr(String.format("%s-%s", formatDateSimpleYYYYMM(tmp.getStart()), formatDateSimpleYYYYMM(tmp.getEnd())));
    DateDiffDto diff1 = dateDiff(start, end);
    // 创建房租账单
    int diff = diff1.year*12 + diff1.month + (diff1.day > 0 ? 1 : 0);
    tmp.setPeriod(diff);
    res.add(tmp);
    return res;
  }


  public static String formatDateSimpleYYYYMM(LocalDateTime startDate){
    return startDate.format(DateTimeFormatter.ofPattern(yyyyMMSimple));
  }


  /**
   * 只保留年月日,其余格式化为0
   * 也就是0小时0分0秒0毫秒
   * @param rentTime
   * @return
   */
  public static LocalDateTime formatZero(LocalDateTime rentTime) {
    return LocalDateTime.of(rentTime.getYear(), rentTime.getMonth(), rentTime.getDayOfMonth(), 0,0,0,0);
  }


  /**
   *
   * @param start
   * @param end
   * @param step1 间隔月份
   * @param delay 提前延后天数,正数提前,负数延后
   * @param fixDay 固定日期收款
   * @return
   */
  public static List<BillDto> doCreateBill0(LocalDateTime start, LocalDateTime end, int step1, int delay, Integer fixDay) {
    start = formatZero(start);
    end = formatZero(end);

    List<BillDto> res = new ArrayList<>();
    BillDto tmp = null;

    DateDiffDto diff1 = dateDiff(start, end);
    // 创建房租账单
    int diff = diff1.year*12 + diff1.month + (diff1.day > 0 ? 1 : 0);
    int upround = (int)Math.ceil( diff / (double)step1);

    for (int i = 0; i < upround; i++) {
      tmp = new BillDto();
      res.add(tmp);
      tmp.setStart(start);
      if(fixDay != null) {
        // 固定收款日期直接处理
        tmp.setStart(start.withDayOfMonth(fixDay));
      } else {
        if(delay > 0) {
          // 延后收款直接处理
          tmp.setStart( start.plus(delay , ChronoUnit.DAYS));
        } else {
          // 提前收款,第一期不能提前,其他期数可以提前收款
          if(i > 0) {
            tmp.setStart( start.plus(delay , ChronoUnit.DAYS));
          }
        }
      }

      start = start.plus(step1, ChronoUnit.MONTHS);
      if(start.isAfter(end)) {
        tmp.setEnd(end);
      } else {
        tmp.setEnd(start);
      }
      tmp.setPeriod(diff >= step1 ? step1 : diff);
      tmp.setDateRangeStr(String.format("%s-%s", formatDateSimpleYYYYMM(tmp.getStart()), formatDateSimpleYYYYMM(tmp.getEnd())));

      diff = diff - step1;
    }
    return res;
  }


  /**
   * 根据支付方式获取间隔月份
   * @param proxyPayType
   * @return
   */
  public static int getPayTypeMonthStep(int proxyPayType) {
    /**
     * 缴费方式
     *
     * 1月扣 2季度扣 3半年扣 4一年扣
     * 11 全额支付
     * 12 2月付
     * 13 二年
     * 14 三年
     * 15 四年
     * 16 五年
     */
    switch (proxyPayType) {
      case 1: return 1;
      case 2 : return  3;
      case 3: return 6;
      case 4: return  12;
      case 11: return Short.MAX_VALUE;
      case 12: return 2;
      case 13 : return 24;
      case 14: return 36;
      case 15: return 48;
      case 16: return 60;
    }
    return 0;
  }




  /**
   * 两个日期之前的年月日之差
   * @param start
   * @param end
   * @return
   */
  public static DateDiffDto dateDiff(LocalDateTime start, LocalDateTime end) {
    long between = ChronoUnit.MONTHS.between(start, end);

    long y = between / 12;
    long m = between - (y*12);
    LocalDateTime d2 = start.plus(y, ChronoUnit.YEARS).plus(m, ChronoUnit.MONTHS);
    long d = ChronoUnit.DAYS.between(d2, end);


    DateDiffDto c = new DateDiffDto();
    c.day = (int)d;
    c.month =(int) m;
    c.year = (int)y;
    return c;

  }


  @Data
  public static class BillDto {
    private LocalDateTime start;
    private LocalDateTime end;
    // 日期字符串
    private String dateRangeStr;
    // 起始结束中间隔几个月,不足一个月按一个月计
    private int period;
  }


  @Data
  public static class DateDiffDto {
    public int day;
    public int month;
    public int year;

  }

}



This post is licensed under CC BY 4.0 by the author.