/// <summary> /// 从上次计息日后一日起计算单利利息并整理还款 /// </summary> /// <param name="info">借款信息</param> /// <param name="capitalIntegral">剩余本金</param> /// <param name="interestIntegral">剩余利息</param> /// <param name="lastSettlement">上次计息日</param> /// <param name="finalDay">截止日期</param> private void Regularize(LoanInfo info, ref double capitalIntegral, ref double interestIntegral, DateTime? lastSettlement, DateTime finalDay) { var capitalPattern = info.AsCapital(); var interestPattern = info.AsInterest(); DateFilter rng = lastSettlement.HasValue ? new(lastSettlement.Value.AddDays(1), finalDay) : new(null, finalDay); foreach (var grp in Accountant .RunVoucherQuery($"{info.QueryMajor()} {rng.AsDateRange()}") .GroupBy(v => v.Date) .OrderBy(grp => grp.Key, new DateComparer())) { var key = grp.Key ?? throw new ApplicationException("无法处理无穷长时间以前的利息收入"); lastSettlement ??= key; // Settle Interest interestIntegral += SettleInterest( info, capitalIntegral, key.Subtract(lastSettlement.Value).Days, grp.SingleOrDefault( v => v.Details.Any(d => d.IsMatch(interestPattern, Dir()))) ?? new() { Date = key, Details = new() });
/// <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())); }
private ValueTask <long> ResetCarry(Session session, DateFilter rng) => session.Accountant.DeleteVouchersAsync($"{rng.AsDateRange()} Carry");
/// <summary> /// 取消摊销 /// </summary> /// <param name="session">客户端会话</param> /// <param name="rng">过滤器</param> /// <returns>执行结果</returns> private ValueTask <long> ResetConversion(Session session, DateFilter rng) => session.Accountant.DeleteVouchersAsync($"{rng.AsDateRange()} %equity conversion% AnnualCarry");
private static IAsyncEnumerable<Couple> GetCouples(Session session, string user, DateFilter rng) => session.Accountant .SelectVouchersAsync(Parsing.VoucherQuery($"U{user.AsUser()} T3998 {rng.AsDateRange()}", session.Client)) .SelectMany(static v => Decouple(v).ToAsyncEnumerable());