/// <summary> /// 相殺データ準備 相殺データより 入金データを作成し、<see cref="Matching.ReceiptId"/>を修正する処理 /// </summary> /// <param name="matchings"></param> /// <param name="loginUserId"></param> /// <param name="updateAt"></param> private async Task <List <Receipt> > PrepareNettingDataAsync( MatchingSource source, int loginUserId, DateTime updateAt, CancellationToken token = default(CancellationToken)) { var matchings = source.Matchings; var nettingIds = matchings.Where(x => x.IsNetting).Select(x => x.ReceiptId).Distinct(); var result = new List <Receipt>(); foreach (var nettingId in nettingIds) { var netting = await nettingQueryProcessor.GetByIdAsync(nettingId, token); var receipt = netting.ConvertToReceiptInput(loginUserId, updateAt); var receiptResult = await matchingQueryProcessor.SaveMatchingReceiptAsync(receipt, token); result.Add(receiptResult); if (!string.IsNullOrEmpty(netting.ReceiptMemo)) { await addReceiptMemoQueryProcessor.SaveAsync(receiptResult.Id, netting.ReceiptMemo, token); } await updateNettingQueryProcessor.UpdateMatchingNettingAsync(netting.CompanyId, receiptResult.Id, netting.Id, CancelFlg : 0, token : token); // performance issue foreach (var matching in matchings.Where(x => x.IsNetting && x.ReceiptId == nettingId)) { matching.ReceiptId = receiptResult.Id; } foreach (var rcpt in source.Receipts.Where(x => x.NettingId == nettingId)) { rcpt.Id = receiptResult.Id; } } return(result); }
public async Task <MatchingResult> SaveAsync( MatchingSource source, ApplicationControl applicationControl, CancellationToken token = default(CancellationToken)) { var companyId = source.Billings.First().CompanyId; if (applicationControl == null) { applicationControl = await applicationControlQueryProcessor.GetAsync(companyId, token); } var billings = source.Billings; var receipts = source.Receipts; var matchings = source.Matchings; var header = source.MatchingHeader; var matchingBillingDiscounts = source.MatchingBillingDiscounts; var billingDiscounts = source.BillingDiscounts; var billingScheduledIncomes = source.BillingScheduledIncomes; var loginUserId = source.LoginUserId; var updateAt = source.UpdateAt; var matchingProcessType = source.MatchingProcessType; var customerId = source.CustomerId; var paymentAgencyId = source.PaymentAgencyId; var advanceReceivedCustomerId = source.AdvanceReceivedCustomerId; var matchingResults = new List <Matching>(); var advanceReceivedResults = new List <AdvanceReceived>(); var clientKey = source.ClientKey; foreach (var billing in billings) { billing.UpdateBy = loginUserId; billing.NewUpdateAt = updateAt; if (applicationControl.UseDeclaredAmount == 0) { billing.OffsetAmount = 0; } var result = await addMatchingQueryProcessor.UpdateBillingForMatchingAsync(billing, token); if (result != 1) { return new MatchingResult { MatchingErrorType = MatchingErrorType.BillingRemainChanged } } ; } foreach (var receipt in receipts) { receipt.UpdateBy = loginUserId; receipt.NewUpdateAt = updateAt; var result = await addMatchingQueryProcessor.UpdateReceiptForMatchingAsync(receipt, token); if (result != 1) { return new MatchingResult { MatchingErrorType = MatchingErrorType.ReceiptRemainChanged } } ; if (receipt.ReceiptHeaderId.HasValue) { var receiptHeaderId = receipt.ReceiptHeaderId.Value; await matchingQueryProcessor.UpdateReceiptHeaderAsync(receiptHeaderId, loginUserId, updateAt, token); } } header.MatchingProcessType = matchingProcessType; header.CustomerId = customerId; header.PaymentAgencyId = paymentAgencyId; header.Memo = header.Memo ?? string.Empty; header.Approved = (applicationControl.UseAuthorization == 1) ? 0 : 1; header.CreateBy = loginUserId; header.UpdateBy = loginUserId; header.CreateAt = updateAt; header.UpdateAt = updateAt; var headerResult = await addMatchingQueryProcessor.SaveMatchingHeaderAsync(header, token); if (headerResult == null) { return new MatchingResult { MatchingErrorType = MatchingErrorType.DBError } } ; var advanceRecievedReciptId = new HashSet <long>(); foreach (var matching in matchings) { matching.MatchingHeaderId = headerResult.Id; matching.CreateBy = loginUserId; matching.CreateAt = updateAt; matching.UpdateBy = loginUserId; matching.UpdateAt = updateAt; if (!advanceReceivedCustomerId.HasValue && matching.AdvanceReceivedOccured == 1) { matching.AdvanceReceivedOccured = 0; } var matchingResult = await addMatchingQueryProcessor.SaveMatchingAsync(matching, token); matchingResults.Add(matchingResult); if (applicationControl.UseDiscount == 1) { foreach (var matchingBillingDiscount in matchingBillingDiscounts.Where(x => x.MatchingId == matching.Id)) { matchingBillingDiscount.MatchingId = matchingResult.Id; await addMatchingBillingDiscountQueryProcessor.SaveAsync(matchingBillingDiscount, token); } } if (advanceReceivedCustomerId.HasValue && matching.ReceiptRemain > 0M && !advanceRecievedReciptId.Contains(matching.ReceiptId)) { var originalReceiptId = matching.ReceiptId; advanceRecievedReciptId.Add(originalReceiptId); var receiptItem = receipts.Find(item => (item.Id == originalReceiptId)); if (matchingProcessType == 1 && advanceReceivedCustomerId != 0) { receiptItem.CustomerId = advanceReceivedCustomerId; } var advReceipt = await addReceiptQueryProcessor.AddAdvanceReceivedAsync( originalReceiptId, advanceReceivedCustomerId, loginUserId, updateAt, updateAt, token); if (advReceipt != null) { advanceReceivedResults.Add(new AdvanceReceived { ReceiptId = advReceipt.Id, OriginalReceiptId = advReceipt.OriginalReceiptId.Value, UpdateAt = advReceipt.UpdateAt, ReceiptCategoryId = advReceipt.ReceiptCategoryId, LoginUserId = advReceipt.UpdateBy, }); var receipt = (await matchingQueryProcessor.SearchReceiptByIdAsync(new long[] { advReceipt.Id }, token)).First(); await matchingQueryProcessor.SaveWorkReceiptTargetAsync(clientKey, receipt.Id, receipt.CompanyId, receipt.CurrencyId, receipt.PayerName, receipt.BankCode, receipt.BranchCode, receipt.PayerCode, receipt.SourceBankName, receipt.SourceBranchName, receipt.CollationKey, receipt.CustomerId, token); await matchingQueryProcessor.SaveWorkCollationAsync(clientKey, advReceipt.Id, customerId ?? 0, paymentAgencyId ?? 0, advanceReceivedCustomerId ?? 0, receipt.PayerName, receipt.PayerCode, receipt.BankCode, receipt.BranchCode, receipt.SourceBankName, receipt.SourceBranchName, receipt.CollationKey, receipt.ReceiptAmount, token); } await updateReceiptQueryProcessor.UpdateOriginalRemainAsync(originalReceiptId, loginUserId, updateAt, token); if (matchingResult != null) { var advanceReceipt_matching = matching; advanceReceipt_matching.Id = matchingResult.Id; await addMatchingQueryProcessor.UpdateMatchingAsync(advanceReceipt_matching, token); } } #region 期日入金データ消込 if (matching.UseCashOnDueDates == 1) { Billing b = null; Receipt r = null; if (matchingProcessType == 0) { b = billings.FirstOrDefault(x => x.Id == matching.BillingId); r = receipts.FirstOrDefault(x => x.Id == matching.ReceiptId); } else { b = await billingGetByIdQueryProcessor.GetByIdAsync(matching.BillingId, token); r = await receiptGetByIdQueryProcessor.GetByIdAsync(matching.ReceiptId, token); } var newbill = b.ConvertScheduledIncome(r, matching.Amount); newbill.CreateBy = loginUserId; newbill.CreateAt = updateAt; newbill.UpdateBy = loginUserId; newbill.UpdateAt = updateAt; var scheduled_billing_result = await addMatchingQueryProcessor.SaveMatchingBillingAsync(newbill, token); foreach (var income in billingScheduledIncomes.Where(x => x.MatchingId == matching.Id)) { income.BillingId = scheduled_billing_result.Id; income.MatchingId = matchingResult.Id; income.CreateBy = loginUserId; income.CreateAt = updateAt; await addBillingScheduledIncomeQueryProcessor.SaveAsync(income); } } #endregion } if (applicationControl.UseDiscount == 1) //歩引き対応 { foreach (var billingId in billingDiscounts) { await updateBillingDiscountQueryProcessor.UpdateAssignmentFlagAsync(billingId, AssignmentFlag : 1, token : token); } } return(new MatchingResult { ProcessResult = new ProcessResult { Result = true }, Matchings = matchingResults, AdvanceReceiveds = advanceReceivedResults, }); } } }
/// <summary> /// 消込登録前の金額検証処理 消込処理実施時の残額とDBの残額の検証 /// </summary> /// <param name="source"></param> /// <param name="setter"></param> /// <param name="token"></param> /// <returns></returns> private async Task <bool> ValidateMatchingDataAsync( MatchingSource source, Action <MatchingResult> setter, CancellationToken token = default(CancellationToken)) { var billingIds = new HashSet <long>(); var receiptIds = new HashSet <long>(); var nettingIds = new HashSet <long>(); foreach (var matching in source.Matchings) { if (!billingIds.Contains(matching.BillingId)) { billingIds.Add(matching.BillingId); } if (!matching.IsNetting && !receiptIds.Contains(matching.ReceiptId)) { receiptIds.Add(matching.ReceiptId); } if (matching.IsNetting && !nettingIds.Contains(matching.ReceiptId)) { nettingIds.Add(matching.ReceiptId); } } var billing = await matchingQueryProcessor.GetBillingRemainAmountAsync(billingIds, token); var dbBillingTotal = billing.RemainAmount; var dbDiscountTotal = billing.DiscountAmount; if (dbBillingTotal != source.BillingRemainTotal) { setter?.Invoke(new MatchingResult { MatchingErrorType = MatchingErrorType.BillingRemainChanged, }); return(false); } if (dbDiscountTotal != source.BillingDiscountTotal) { setter?.Invoke(new MatchingResult { MatchingErrorType = MatchingErrorType.BillingDiscountChanged, }); return(false); } var dbReceiptTotal = 0M; var dbNettingTotal = 0M; if (receiptIds.Any()) { dbReceiptTotal = await matchingQueryProcessor.GetReceiptRemainAmountAsync(receiptIds, token); } if (nettingIds.Any()) { dbNettingTotal = await matchingQueryProcessor.GetNettingRemainAmountAsync(nettingIds, token); } dbReceiptTotal = dbReceiptTotal + dbNettingTotal; if (dbReceiptTotal != source.ReceiptRemainTotal) { setter?.Invoke(new MatchingResult { MatchingErrorType = MatchingErrorType.ReceiptRemainChanged, }); return(false); } return(true); }
public async Task <MatchingResult> MatchAsync( MatchingSource source, CancellationToken token = default(CancellationToken), IProgressNotifier notifier = null) { var matchings = source.Matchings; var loginUserId = source.LoginUserId; var companyId = source.CompanyId; var customerId = source.CustomerId ?? 0; var paymentAgencyId = source.PaymentAgencyId ?? 0; var childCustomerIds = source.ChildCustomerIds; var useKanaLearning = source.UseKanaLearning == 1; var useFeeLearning = source.UseFeeLearning == 1; var appControl = await applicationControlQueryProcessor.GetAsync(companyId, token); var updateAt = await dbSystemDateTimeQueryProcessor.GetAsync(token); source.UpdateAt = updateAt; var useAuthorization = appControl?.UseAuthorization == 1; var nettingReceipts = new List <Receipt>(); // DBサーバーから取得する var billings = new List <Billing>(); var receipts = new List <Receipt>(); var matchingBillingDiscounts = new List <MatchingBillingDiscount>(); var billingScheduledIncomes = new List <BillingScheduledIncome>(); var billingDiscounts = new HashSet <long>(); MatchingResult validateResult = null; if (!(await ValidateMatchingDataAsync(source, x => validateResult = x, token))) { return(validateResult); } var currencyId = source.Matchings.First().CurrencyId; using (var scope = transactionScopeBuilder.Create()) { #region 相殺データ変換 nettingReceipts = await PrepareNettingDataAsync(source, loginUserId, updateAt, token); foreach (var r in nettingReceipts) { var item = source.Receipts.First(x => x.Id == r.Id); item.UpdateAt = r.UpdateAt; } #endregion #region matchingHeader var header = source.MatchingHeader; header.MatchingProcessType = 1; header.Approved = useAuthorization ? 0 : 1; header.CreateBy = loginUserId; header.UpdateBy = loginUserId; header.CreateAt = updateAt; header.UpdateAt = updateAt; #endregion #region 手数料学習 var bankFee = header.BankTransferFee; if (useFeeLearning) { await SaveBankTransferFeeAsync(customerId, paymentAgencyId, currencyId, bankFee, updateAt, loginUserId, token); } #endregion #region 債権代表者登録 if (childCustomerIds.Any()) { var isParent = 1; await updateCustomerQueryProcessor.UpdateIsParentAsync(isParent, loginUserId, new[] { customerId }, token); foreach (var childId in childCustomerIds) { var group = new CustomerGroup(); group.ParentCustomerId = customerId; group.ChildCustomerId = childId; group.CreateAt = updateAt; group.CreateBy = loginUserId; group.UpdateAt = updateAt; group.UpdateBy = loginUserId; await addCustomerGroupQueryProcessor.SaveAsync(group, token); } } #endregion #region 学習履歴の登録 if (useKanaLearning) { await SaveKanaLearningAsync(matchings, companyId, customerId, paymentAgencyId, loginUserId, updateAt); } #endregion var matchingResult = await matchingSaveProcessor.SaveAsync(source, appControl, token); if (matchingResult.ProcessResult.Result) { scope.Complete(); } matchingResult.NettingReceipts = nettingReceipts; return(matchingResult); } }
public async Task <MatchingResult> MatchAsync( IEnumerable <Collation> collations, CollationSearch option, CancellationToken token = default(CancellationToken), IProgressNotifier notifier = null) { var appControl = await applicationControlQueryProcessor.GetAsync(option.CompanyId, token); var nettingReceipts = new List <Receipt>(); var updateAt = await dbSystemDateTimeQueryProcessor.GetAsync(token); var matchingOrders = await matchingOrderQueryProcessor.GetItemsAsync(option.CompanyId, token); var matchingBillingOrder = matchingOrders.Where(x => x.TransactionCategory == 1 && x.Available == 1).ToArray(); var matchingReceiptOrder = matchingOrders.Where(x => x.TransactionCategory == 2 && x.Available == 1).ToArray(); var matchings = new List <Matching>(); var advanceReceiveds = new List <AdvanceReceived>(); List <Billing> billings = null; List <Netting> nettings = null; List <Receipt> receipts = null; var index = 0; using (var scope = transactionScopeBuilder.Create()) { foreach (var collation in collations) { // 請求データ取得 var billingSearchOption = new MatchingBillingSearch { ClientKey = option.ClientKey, ParentCustomerId = collation.CustomerId, PaymentAgencyId = collation.PaymentAgencyId, CurrencyId = collation.CurrencyId, }; billings = (await matchingQueryProcessor.GetBillingsForSequentialMatchingAsync(billingSearchOption, matchingBillingOrder, token)).ToList(); var billingAmount = billings.Sum(item => (item.RemainAmount - item.DiscountAmount - item.OffsetAmount)); var billingCount = billings.Count; // 請求データチェック if (billingAmount != collation.BillingAmount || billingCount != collation.BillingCount) { notifier?.Abort(); return(new MatchingResult { MatchingErrorType = MatchingErrorType.BillingRemainChanged, ErrorIndex = index, }); } // 相殺データ取得 nettings = (await matchingQueryProcessor.SearchMatchingNettingAsync(option, collation, token)).ToList(); // 相殺データ登録 var createdReceipstFromNetting = new List <Receipt>(); foreach (var netting in nettings) { var receipt = netting.ConvertToReceiptInput(option.LoginUserId, updateAt); var nettingReceipt = await matchingQueryProcessor.SaveMatchingReceiptAsync(receipt, token); if (!string.IsNullOrEmpty(netting.ReceiptMemo)) { await addReceiptMemoQueryProcessor.SaveAsync(nettingReceipt.Id, netting.ReceiptMemo, token); } netting.ReceiptId = nettingReceipt.Id; createdReceipstFromNetting.Add(nettingReceipt); } // 入金データ取得 var receiptSearch = new MatchingReceiptSearch { ClientKey = option.ClientKey, CompanyId = option.CompanyId, CurrencyId = collation.CurrencyId, ParentCustomerId = collation.CustomerId, PaymentAgencyId = collation.PaymentAgencyId, UseScheduledPayment = appControl.UseScheduledPayment, }; receipts = (await matchingQueryProcessor.GetReceiptsForSequentialMatchingAsync(receiptSearch, matchingReceiptOrder, token)).ToList(); var receiptAmount = receipts.Sum(item => (item.RemainAmount)); var receiptCount = receipts.Count(); var hasAdvanceReceived = receipts.Exists(item => item.UseAdvanceReceived == 1); // 入金データチェック if (receiptAmount != collation.ReceiptAmount || receiptCount != collation.ReceiptCount) { notifier?.Abort(); return(new MatchingResult { MatchingErrorType = MatchingErrorType.ReceiptRemainChanged, ErrorIndex = index, }); } foreach (var netting in nettings) { await updateNettingQueryProcessor.UpdateMatchingNettingAsync(netting.CompanyId, netting.ReceiptId.Value, netting.Id, CancelFlg : 0, token : token); foreach (var receipt in receipts .Where(x => x.NettingId.HasValue && x.NettingId == netting.Id)) { receipt.Id = netting.ReceiptId.Value; } } // 前受処理日付取得 var recordedAt = option.GetRecordedAt(hasAdvanceReceived ? billings : null); option.AdvanceReceivedRecordedAt = recordedAt; var requestSource = new MatchingSource { Billings = billings, Receipts = receipts, BankTransferFee = collation.BankTransferFee, TaxDifference = collation.TaxDifference, }; var source = await matchingSolveProcessor.SolveAsync(requestSource, option, appControl, token); foreach (var netting in nettings) { foreach (var matching in source.Matchings.Where(x => x.IsNetting && x.ReceiptId == netting.Id)) { matching.ReceiptId = netting.ReceiptId.Value; } } if (collation.UseFeeLearning == 1 && collation.BankTransferFee != 0M) { await SaveBankTransferFeeAsync(collation, option, updateAt, token); } // データの更新処理 int?customerId = collation.CustomerId; if (customerId == 0) { customerId = null; } int?paymentAgencyId = collation.PaymentAgencyId; if (paymentAgencyId == 0) { paymentAgencyId = null; } source.LoginUserId = option.LoginUserId; source.UpdateAt = updateAt; source.MatchingProcessType = 0; source.CustomerId = customerId; source.PaymentAgencyId = paymentAgencyId; source.AdvanceReceivedCustomerId = option.DoTransferAdvanceReceived ? customerId : null; source.ClientKey = option.ClientKey; foreach (var r in createdReceipstFromNetting) { var item = receipts.First(x => x.Id == r.Id); item.UpdateAt = r.UpdateAt; } var matchingResult = await matchingSaveProcessor.SaveAsync(source, appControl, token); if (!matchingResult.ProcessResult.Result) { notifier?.Abort(); return(matchingResult); } matchings.AddRange(matchingResult.Matchings); advanceReceiveds.AddRange(matchingResult.AdvanceReceiveds); nettingReceipts.AddRange(createdReceipstFromNetting); notifier?.UpdateState(); index++; } scope.Complete(); } return(new MatchingResult { ProcessResult = new ProcessResult { Result = true }, Matchings = matchings, AdvanceReceiveds = advanceReceiveds, NettingReceipts = nettingReceipts }); }
public async Task <MatchingSource> SolveAsync( MatchingSource source, CollationSearch option, ApplicationControl control = null, CancellationToken token = default(CancellationToken)) { if (control == null) { control = await applicationControlQueryProcessor.GetAsync(option.CompanyId, token); } var useCashOnDueDates = control.UseCashOnDueDates; var useScheduledPayment = control.UseScheduledPayment; var useDeclaredAmount = control.UseDeclaredAmount; int?doCreateAdvanceReceived = option.DoTransferAdvanceReceived ? 1 : 0; var taxDifference = source.TaxDifference; var bankTransferFee = source.BankTransferFee; var billingItems = source.Billings; var receiptItems = source.Receipts; if (!(billingItems?.Any() ?? false)) { throw new ArgumentNullException("Billings"); } if (!(receiptItems?.Any() ?? false)) { throw new ArgumentNullException("Receipts"); } int companyId; int currencyId; { var billing = billingItems.First(); companyId = billing.CompanyId; currencyId = billing.CurrencyId; } var isAllMinusBilling = true; var billingTotal = 0M; var billingPair = GetBillingPair(billingItems, useScheduledPayment, useDeclaredAmount, ref doCreateAdvanceReceived, ref billingTotal, ref isAllMinusBilling); var isAllMinusReceipt = true; var receiptTotal = 0M; var receiptPair = GetReceiptPair(receiptItems, ref receiptTotal, ref isAllMinusReceipt); var isAllMinus = isAllMinusBilling && isAllMinusReceipt; var taxDiff = taxDifference; var bankFee = bankTransferFee; var isEqual = (billingTotal == receiptTotal + bankFee - taxDiff); Func <decimal, decimal, decimal> amountSolver = Math.Min; if (isAllMinus) { amountSolver = Math.Max; } var header = new MatchingHeader { Id = 1, CompanyId = companyId, CurrencyId = currencyId, BankTransferFee = bankFee, TaxDifference = taxDiff, }; var recordedAt = option.AdvanceReceivedRecordedAt; var matchings = new List <Matching>(); var billingScheduledIncomes = new List <BillingScheduledIncome>(); var matchingBillingDiscounts = new List <MatchingBillingDiscount>(); var billingDiscounts = new HashSet <long>(); var discountTotal = 0M; var beforBillingRemainTotal = 0M; var beforReceiptRemainTotal = 0M; var bindex = 0; var rindex = 0; var nextBilling = true; var nextReceipt = true; Billing bill = null; Receipt rcpt = null; while (bindex < billingItems.Count && rindex < receiptItems.Count && (nextBilling || nextReceipt)) { if (token.IsCancellationRequested) { throw new OperationCanceledException(); } if (nextBilling) { bill = billingItems[bindex]; } if (nextReceipt) { rcpt = receiptItems[rindex]; } var isLastBill = bindex == billingItems.Count - 1; var isLastRcpt = rindex == receiptItems.Count - 1; var discount = bill.DiscountAmount; var billTaxDiff = (0M < taxDiff) ? taxDiff : 0M; var rcptTaxDiff = (0M < taxDiff) ? 0M : -taxDiff; var matching = new Matching(); matching.Id = matchings.Count; matching.CompanyId = companyId; matching.CurrencyId = currencyId; matching.MatchingHeaderId = header.Id; matching.ReceiptId = rcpt.NettingId ?? rcpt.Id; matching.PayerName = rcpt.PayerName; matching.SourceBankName = rcpt.SourceBankName; matching.SourceBranchName = rcpt.SourceBranchName; matching.IsNetting = rcpt.NettingId.HasValue; matching.RecordedAt = (rcpt.OriginalReceiptId.HasValue ? recordedAt : null) ?? rcpt.RecordedAt; matching.ReceiptHeaderId = rcpt.ReceiptHeaderId; if (useCashOnDueDates == 1 && rcpt.UseCashOnDueDates == 1) { matching.UseCashOnDueDates = 1; } matching.BillingId = bill.Id; if (useScheduledPayment == 1 && useDeclaredAmount == 1) { matching.OffsetAmount = bill.OffsetAmount; } if (discount != 0M) { #region billing discount matching.DiscountAmount1 = bill.DiscountAmount1; matching.DiscountAmount2 = bill.DiscountAmount2; matching.DiscountAmount3 = bill.DiscountAmount3; matching.DiscountAmount4 = bill.DiscountAmount4; matching.DiscountAmount5 = bill.DiscountAmount5; if (!billingDiscounts.Contains(bill.Id)) { billingDiscounts.Add(bill.Id); } matchingBillingDiscounts.AddRange(ConvertBillingToDiscounts(bill, matching.Id)); discountTotal += discount; bill.DiscountAmount = 0M; bill.DiscountAmount1 = 0M; bill.DiscountAmount2 = 0M; bill.DiscountAmount3 = 0M; bill.DiscountAmount4 = 0M; bill.DiscountAmount5 = 0M; #endregion } matching.BankTransferFee = bankFee; matching.TaxDifference = taxDiff; matching.Memo = bill.Memo; var billAmount = billingPair[bindex] - rcptTaxDiff - bankFee - discount; var rcptAmount = receiptPair[rindex] - billTaxDiff; matching.Amount = (isEqual && isLastRcpt && !isLastBill) ? billAmount : (isEqual && !isLastRcpt && isLastBill) ? rcptAmount : amountSolver(billAmount, rcptAmount); header.Amount += matching.Amount; if (matching.Amount == 0M && taxDiff == 0M && bankFee == 0M && discount == 0M) { break; } var billAssignAmount = (matching.Amount + rcptTaxDiff + bankFee + discount); var rcptAssignAmount = (matching.Amount + billTaxDiff); if (nextBilling) { beforBillingRemainTotal += bill.RemainAmount; bill.AssignmentAmount = billAssignAmount; } else { bill.AssignmentAmount += billAssignAmount; } if (nextReceipt) { beforReceiptRemainTotal += rcpt.RemainAmount; rcpt.AssignmentAmount = rcptAssignAmount; } else { rcpt.AssignmentAmount += rcptAssignAmount; } billingPair[bindex] -= billAssignAmount; receiptPair[rindex] -= rcptAssignAmount; nextBilling = billingPair[bindex] == 0M && !isLastBill; nextReceipt = receiptPair[rindex] == 0M && !isLastRcpt; matchings.Add(matching); if (!isEqual) { if (!nextBilling && isLastBill && receiptPair[rindex] > 0M && !rcpt.OriginalReceiptId.HasValue) { matching.AdvanceReceivedOccured = 1; } if (!nextBilling && isLastBill && receiptPair[rindex] != 0M) { foreach (var m in matchings.Where(x => x.ReceiptId == rcpt.Id)) { m.ReceiptRemain = receiptPair[rindex]; } } if (!nextReceipt && isLastRcpt && billingPair[bindex] != 0M) { foreach (var m in matchings.Where(x => x.BillingId == bill.Id)) { m.BillingRemain = billingPair[bindex]; } } if (billingPair[bindex] == 0M && isLastBill || receiptPair[rindex] == 0M && isLastRcpt) { break; } } if (nextBilling) { bindex++; } if (nextReceipt) { rindex++; } taxDiff = 0M; bankFee = 0M; } var remainType = 0; var billingRemainTotal = billingPair.Sum(x => x.Value); var receiptRemainTotal = receiptPair.Sum(x => x.Value); if (billingRemainTotal == 0M && receiptRemainTotal == 0M) { remainType = 0; } else if (billingRemainTotal != 0M) { remainType = 1; } else { if (!rcpt.OriginalReceiptId.HasValue && option.UseAdvanceReceived && receiptPair[rindex] > 0M) { remainType = 3; } else { remainType = 2; } } if (useCashOnDueDates == 1) { billingScheduledIncomes.AddRange(ConvertMatchingToScheduled(matchings)); } billingItems = billingItems.Take(bindex + 1).ToList(); receiptItems = receiptItems.Take(rindex + 1).ToList(); header.BillingCount = billingItems.Count; header.ReceiptCount = receiptItems.Count; if (token.IsCancellationRequested) { throw new OperationCanceledException(); } return(new MatchingSource { RemainType = remainType, Matchings = matchings, Billings = billingItems, Receipts = receiptItems, BillingDiscounts = billingDiscounts, MatchingBillingDiscounts = matchingBillingDiscounts, MatchingHeader = header, BillingScheduledIncomes = billingScheduledIncomes, BillingRemainTotal = beforBillingRemainTotal, ReceiptRemainTotal = beforReceiptRemainTotal, BillingDiscountTotal = discountTotal }); }