根据时间区间拆分时间节点进行分账操作

最近遇到了一个财务分账逻辑,当时解决的时候感觉有点意思,因为最近比较忙,今天才有时间来写一篇博客文章记录一下,希望能对遇到相关问题的朋友提供一点思路。

业务逻辑:

按时间区间拆分时间节点在每个季度末生成账单。

注:15号及15号之前是当月,15号之后是下个月

比如合同期2023年2月15日到2024年2月15日,金额为1万元

23年1季度触发确认2个月,金额:1666

23年2季度确认3个月,金额:2499

23年3季度3个月,金额:2499

23年4季度3个月,金额:2499

24年1季度1个月,金额:837

金额:金额平摊至每个月,按季度算金额,最后一个月补差额(默认不会出现拆分类型变更的情况)

代码实现:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            //合同开始时间
            DateTime contractStartTime = new DateTime(2023, 12, 16);
            //合约期
            int contractPeriod = 6;
            //如果开始时间是15号后,账期归下个月
            if (contractStartTime.Day > 15)
            {
                contractStartTime= contractStartTime.AddMonths(1);
            }

            //合同结束时间
            DateTime contractEndTime = contractStartTime.AddMonths(contractPeriod);

            // 分摊合同金额
            AmortizeContract(10000, contractStartTime, contractEndTime);

            Console.ReadLine();
        }

        /// <summary>
        /// 计算合同差额
        /// </summary>
        /// <param name="totalAmount"></param>
        /// <param name="startDate"></param>
        /// <param name="endDate"></param>
        static void AmortizeContract(decimal totalAmount, DateTime startDate, DateTime endDate)
        {
            int monthNum = GetMonthDifference(startDate, endDate);

            decimal monthlyAmount = totalAmount / monthNum;

            while (startDate <= endDate)
            {
                int monthsInQuarter = GetMonthsInQuarter(startDate);
                decimal amortizedAmount = (int)monthlyAmount * monthsInQuarter;
                if (startDate.AddMonths(monthsInQuarter) > endDate)
                {
                    // 计算最后一个季度的分摊月份和金额
                    monthsInQuarter = (endDate.Month - startDate.Month) + 1;
                    amortizedAmount = totalAmount - ((int)monthlyAmount * (monthNum - monthsInQuarter + 1));
                    Console.WriteLine($"{startDate.Year}年{GetQuarter(startDate)}季度,分摊月份为{monthsInQuarter - 1}个月,分摊金额为{(int)amortizedAmount};");
                }
                else
                {
                    Console.WriteLine($"{startDate.Year}年{GetQuarter(startDate)}季度,分摊月份为{monthsInQuarter}个月,分摊金额为{(int)amortizedAmount};");
                }

                startDate = startDate.AddMonths(monthsInQuarter);
            }
        }

        /// <summary>
        /// 获取日期月份差额
        /// </summary>
        /// <param name="startDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        static int GetMonthDifference(DateTime startDate, DateTime endDate)
        {
            int startMonths = startDate.Year * 12 + startDate.Month;
            int endMonths = endDate.Year * 12 + endDate.Month;

            return endMonths - startMonths;
        }


        static int GetMonthsInQuarter(DateTime date)
        {
            int month = date.Month;
            if (month <= 3)
            {
                return 3 - (month - 1);
            }
            else if (month <= 6)
            {
                return 6 - (month - 1);
            }
            else if (month <= 9)
            {
                return 9 - (month - 1);
            }
            else
            {
                return 12 - (month - 1);
            }
        }

        static int GetQuarter(DateTime date)
        {
            int month = date.Month;
            if (month <= 3)
            {
                return 1;
            }
            else if (month <= 6)
            {
                return 2;
            }
            else if (month <= 9)
            {
                return 3;
            }
            else
            {
                return 4;
            }
        }

    }
}

 效果验证:

1.开始日期十五号及之前

2.开始日期15号之后

3.半年区间15号之后

4.半年区间15号之前

 

THE END