/// <summary>
        ///     获取下一个摊销日期
        /// </summary>
        /// <param name="interval">间隔类型</param>
        /// <param name="last">上一次摊销日期</param>
        /// <returns>下一个摊销日期</returns>
        private static DateTime NextAmortizationDate(AmortizeInterval interval, DateTime last)
        {
            switch (interval)
            {
            case AmortizeInterval.EveryDay:
                return(last.AddDays(1));

            case AmortizeInterval.SameDayOfWeek:
                return(last.AddDays(7));

            case AmortizeInterval.LastDayOfWeek:
                return(last.DayOfWeek == DayOfWeek.Sunday
                        ? last.AddDays(7)
                        : last.AddDays(14 - (int)last.DayOfWeek));

            case AmortizeInterval.SameDayOfMonth:
                return(last.AddMonths(1));

            case AmortizeInterval.LastDayOfMonth:
                return(AccountantHelper.LastDayOfMonth(last.Year, last.Month + 1));

            case AmortizeInterval.SameDayOfYear:
                return(last.AddYears(1));

            case AmortizeInterval.LastDayOfYear:
                return(new DateTime(last.Year + 2, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddDays(-1));

            default:
                throw new ArgumentException("间隔类型未知", nameof(interval));
            }
        }
        /// <summary>
        ///     获取本次摊销日期
        /// </summary>
        /// <param name="interval">间隔类型</param>
        /// <param name="the">日期</param>
        /// <returns>这次摊销日期</returns>
        private static DateTime ThisAmortizationDate(AmortizeInterval interval, DateTime the)
        {
            switch (interval)
            {
            case AmortizeInterval.EveryDay:
            case AmortizeInterval.SameDayOfWeek:
                return(the);

            case AmortizeInterval.SameDayOfYear:
                if (the.Month == 2 &&
                    the.Day == 29)
                {
                    return(the.AddDays(1));
                }

                return(the);

            case AmortizeInterval.SameDayOfMonth:
                return(the.Day > 28 ? the.AddDays(1 - the.Day).AddMonths(1) : the);

            case AmortizeInterval.LastDayOfWeek:
                return(the.DayOfWeek == DayOfWeek.Sunday ? the : the.AddDays(7 - (int)the.DayOfWeek));

            case AmortizeInterval.LastDayOfMonth:
                return(AccountantHelper.LastDayOfMonth(the.Year, the.Month));

            case AmortizeInterval.LastDayOfYear:
                return(new DateTime(the.Year + 1, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddDays(-1));

            default:
                throw new ArgumentException("间隔类型未知", nameof(interval));
            }
        }
예제 #3
0
        /// <summary>
        ///     调整资产计算表
        /// </summary>
        /// <param name="asset">资产</param>
        /// <returns>资产</returns>
        public static Asset InternalRegular(Asset asset)
        {
            if (asset.Remark == Asset.IgnoranceMark)
            {
                return(asset);
            }
            if (!asset.Date.HasValue ||
                !asset.Value.HasValue)
            {
                return(asset);
            }

            var lst = asset.Schedule?.ToList() ?? new();

            foreach (var assetItem in lst)
            {
                if (assetItem is DepreciateItem ||
                    assetItem is DevalueItem)
                {
                    if (assetItem.Date.HasValue)
                    {
                        assetItem.Date = AccountantHelper.LastDayOfMonth(
                            assetItem.Date.Value.Year,
                            assetItem.Date.Value.Month);
                    }
                }
            }

            lst.Sort(new AssetItemComparer());

            if (lst.Count == 0 ||
                lst[0] is not AcquisitionItem acq0)
            {
                lst.Insert(
                    0,
                    new AcquisitionItem {
                    Date = asset.Date, OrigValue = asset.Value.Value
                });
            }
        /// <inheritdoc />
        public override IQueryResult Execute(string expr, IEntitiesSerializer serializer)
        {
            var content = Parsing.Token(ref expr);
            var avg     = Parsing.DoubleF(ref expr);

            Parsing.Eof(expr);

            var tdy     = ClientDateTime.Today;
            var ldom    = AccountantHelper.LastDayOfMonth(tdy.Year, tdy.Month);
            var srng    = new DateFilter(new DateTime(tdy.Year, tdy.Month, 1, 0, 0, 0, DateTimeKind.Utc), tdy);
            var balance = Accountant.RunGroupedQuery(
                $"T1002 {content.Quotation('\'')} [~{tdy.AsDate()}]`vD{srng.AsDateRange()}");

            var bal = 0D;
            var btd = 0D;

            foreach (var b in balance.Items.Cast <ISubtotalDate>())
            {
                if (b.Date == tdy)
                {
                    btd += b.Fund;
                }
                else
                {
                    bal += b.Fund;
                }
            }

            var targ = ldom.Day * avg;

            var sb = new StringBuilder();

            sb.AppendLine($"Target: {targ.AsCurrency()}");
            sb.AppendLine($"Balance until yesterday: {bal.AsCurrency()}");
            if ((bal - targ).IsNonNegative())
            {
                sb.AppendLine("Achieved.");
                sb.AppendLine();

                sb.AppendLine(
                    (btd - avg).IsNonNegative()
                        ? $"Plan A: Credit {(btd - avg).AsCurrency()}, Balance {avg.AsCurrency()}"
                        : $"Plan A: Debit {(avg - btd).AsCurrency()}, Balance {avg.AsCurrency()}");
                sb.AppendLine("Plan B: No Action");
            }
            else
            {
                var res = targ - bal;
                var rsd = ldom.Day - tdy.Day + 1;
                sb.AppendLine($"Deficiency: {res.AsCurrency()}");
                var avx = res / rsd;
                if ((rsd * avg - res).IsNonNegative())
                {
                    sb.AppendLine($"Average deficiency: {avx.AsCurrency()} <= {avg.AsCurrency()}");
                    sb.AppendLine();

                    sb.AppendLine(
                        (btd - avx).IsNonNegative()
                            ? $"Plan A: Credit {(btd - avx).AsCurrency()}, Balance {avx.AsCurrency()}"
                            : $"Plan A: Debit {(avx - btd).AsCurrency()}, Balance {avx.AsCurrency()}");
                    sb.AppendLine(
                        (btd - avg).IsNonNegative()
                            ? $"Plan B: Credit {(btd - avg).AsCurrency()}, Balance {avg.AsCurrency()}"
                            : $"Plan B: Debit {(avg - btd).AsCurrency()}, Balance {avg.AsCurrency()}");
                }
                else
                {
                    sb.AppendLine($"Average deficiency: {avx.AsCurrency()} > {avg.AsCurrency()}");
                    sb.AppendLine();

                    sb.AppendLine(
                        (btd - avx).IsNonNegative()
                            ? $"Plan: Credit {(btd - avx).AsCurrency()}, Balance {avx.AsCurrency()}"
                            : $"Plan: Debit {(avx - btd).AsCurrency()}, Balance {avx.AsCurrency()}");
                }
            }

            return(new PlainText(sb.ToString()));
        }
예제 #5
0
 public void IsNonPositiveTest(bool expected, double value)
 {
     Assert.Equal(expected, AccountantHelper.IsNonPositive(value));
 }
예제 #6
0
        public void LastDayOfMonthTest(string expectedS, int year, int month)
        {
            var expected = expectedS.ToDateTime();

            Assert.Equal(expected, AccountantHelper.LastDayOfMonth(year, month));
        }
예제 #7
0
        /// <summary>
        ///     折旧
        /// </summary>
        public static void Depreciate(Asset asset)
        {
            if (!asset.Date.HasValue ||
                !asset.Value.HasValue ||
                !asset.Salvge.HasValue ||
                !asset.Life.HasValue)
            {
                return;
            }

            var items =
                asset.Schedule.Where(
                    assetItem =>
                    !(assetItem is DepreciateItem) || assetItem.Remark == AssetItem.IgnoranceMark)
                .ToList();

            switch (asset.Method)
            {
            case DepreciationMethod.None:
                break;

            case DepreciationMethod.StraightLine:
            {
                var lastYear  = asset.Date.Value.Year + asset.Life.Value;
                var lastMonth = asset.Date.Value.Month;

                var dt   = asset.Date.Value;
                var flag = false;
                for (var i = 0;; i++)
                {
                    if (i < items.Count)
                    {
                        if (items[i].Date > dt)
                        {
                            dt   = items[i].Date ?? dt;
                            flag = false;
                            continue;
                        }

                        if (flag)
                        {
                            continue;
                        }
                        if (items[i] is AcquisationItem ||
                            items[i] is DispositionItem)
                        {
                            continue;
                        }

                        if (items[i] is DepreciateItem)         // With IgnoranceMark
                        {
                            flag = true;
                            continue;
                        }
                    }

                    flag = true;

                    if (dt.Year == asset.Date.Value.Year &&
                        dt.Month == asset.Date.Value.Month)
                    {
                        dt = AccountantHelper.LastDayOfMonth(dt.Year, dt.Month + 1);
                        if (i == items.Count)
                        {
                            i--;
                        }
                        continue;
                    }

                    var amount  = items[i - 1].Value - asset.Salvge.Value;
                    var monthes = 12 * (lastYear - dt.Year) + lastMonth - dt.Month;

                    if (amount.IsZero() ||
                        monthes < 0)         // Ended, Over-depreciated or Dispositoned
                    {
                        if (i < items.Count)
                        {
                            continue;         // If another AcquisationItem exists
                        }
                        break;
                    }

                    items.Insert(
                        i,
                        new DepreciateItem
                        {
                            Date   = dt,
                            Amount = amount / (monthes + 1),
                            Value  = items[i - 1].Value - amount / (monthes + 1)
                        });

                    dt = AccountantHelper.LastDayOfMonth(dt.Year, dt.Month + 1);
                }
            }
                //if (mo < 12)
                //    for (var mon = mo + 1; mon <= 12; mon++)
                //        items.Add(
                //                  new DepreciateItem
                //                      {
                //                          Date = LastDayOfMonth(yr, mon),
                //                          Amount = amount / n / 12
                //                      });
                //for (var year = 1; year < n; year++)
                //    for (var mon = 1; mon <= 12; mon++)
                //        items.Add(
                //                  new DepreciateItem
                //                      {
                //                          Date = LastDayOfMonth(yr + year, mon),
                //                          Amount = amount / n / 12
                //                      });
                //// if (mo > 0)
                //{
                //    for (var mon = 1; mon <= mo; mon++)
                //        items.Add(
                //                  new DepreciateItem
                //                      {
                //                          Date = LastDayOfMonth(yr + n, mon),
                //                          Amount = amount / n / 12
                //                      });
                //}
                break;

            case DepreciationMethod.SumOfTheYear:
                if (items.Any(a => a is DevalueItem || a.Remark == AssetItem.IgnoranceMark) ||
                    items.Count(a => a is AcquisationItem) != 1)
                {
                    throw new NotImplementedException();
                }

                {
                    var n      = asset.Life.Value;
                    var mo     = asset.Date.Value.Month;
                    var yr     = asset.Date.Value.Year;
                    var amount = asset.Value.Value - asset.Salvge.Value;
                    var z      = n * (n + 1) / 2;
                    var nstar  = n - mo / 12D;
                    var zstar  = (Math.Floor(nstar) + 1) * (Math.Floor(nstar) + 2 * (nstar - Math.Floor(nstar))) / 2;
                    if (mo < 12)
                    {
                        var a = amount * n / z * (12 - mo) / z;
                        amount -= a;
                        for (var mon = mo + 1; mon <= 12; mon++)
                        {
                            items.Add(
                                new DepreciateItem
                            {
                                Date   = AccountantHelper.LastDayOfMonth(yr, mon),
                                Amount = a / (12 - mo)
                            });
                        }
                    }

                    for (var year = 1; year < n; year++)
                    {
                        for (var mon = 1; mon <= 12; mon++)
                        {
                            items.Add(
                                new DepreciateItem
                            {
                                Date   = AccountantHelper.LastDayOfMonth(yr + year, mon),
                                Amount = amount * (nstar - year + 1) / zstar / 12
                            });
                        }
                    }
                    // if (mo > 0)
                    {
                        for (var mon = 1; mon <= mo; mon++)
                        {
                            items.Add(
                                new DepreciateItem
                            {
                                Date   = AccountantHelper.LastDayOfMonth(yr + n, mon),
                                Amount = amount * (nstar - (n + 1) + 2) / zstar / 12
                            });
                        }
                    }
                }

                break;

            case DepreciationMethod.DoubleDeclineMethod:
                throw new NotImplementedException();
            }

            asset.Schedule = items;
        }
예제 #8
0
        /// <summary>
        ///     调整资产计算表
        /// </summary>
        /// <param name="asset">资产</param>
        /// <returns>资产</returns>
        public static Asset InternalRegular(Asset asset)
        {
            if (asset.Remark == Asset.IgnoranceMark)
            {
                return(asset);
            }
            if (!asset.Date.HasValue ||
                !asset.Value.HasValue)
            {
                return(asset);
            }

            var lst = asset.Schedule?.ToList() ?? new List <AssetItem>();

            foreach (var assetItem in lst)
            {
                if (assetItem is DepreciateItem ||
                    assetItem is DevalueItem)
                {
                    if (assetItem.Date.HasValue)
                    {
                        assetItem.Date = AccountantHelper.LastDayOfMonth(
                            assetItem.Date.Value.Year,
                            assetItem.Date.Value.Month);
                    }
                }
            }

            lst.Sort(new AssetItemComparer());

            if (lst.Count == 0 ||
                !(lst[0] is AcquisationItem acq0))
            {
                lst.Insert(
                    0,
                    new AcquisationItem
                {
                    Date      = asset.Date,
                    OrigValue = asset.Value.Value
                });
            }
            else if (lst[0].Remark != AssetItem.IgnoranceMark)
            {
                acq0.Date      = asset.Date;
                acq0.OrigValue = asset.Value.Value;
            }

            var bookValue = 0D;

            for (var i = 0; i < lst.Count; i++)
            {
                var item = lst[i];
                if (item is AcquisationItem acq)
                {
                    bookValue += acq.OrigValue;
                    item.Value = bookValue;
                }
                else if (item is DepreciateItem dep)
                {
                    bookValue -= dep.Amount;
                    item.Value = bookValue;
                }
                else if (item is DevalueItem dev)
                {
                    if (bookValue <= dev.FairValue &&
                        item.Remark != AssetItem.IgnoranceMark)
                    {
                        lst.RemoveAt(i--);
                        continue;
                    }

                    dev.Amount = bookValue - dev.FairValue;
                    bookValue  = dev.FairValue;
                    item.Value = dev.FairValue;
                }
                else if (item is DispositionItem)
                {
                    bookValue = 0;
                }
            }

            asset.Schedule = lst;
            return(asset);
        }