public Task <MatchingHeader> CancelApprovalAsync(MatchingHeader header, CancellationToken token = default(CancellationToken))
        {
            var query = @"
UPDATE  MatchingHeader
SET     Approved    = 0
,       UpdateBy    = @UpdateBy
,       UpdateAt    = GETDATE()
OUTPUT  inserted.*
WHERE   Id          = @Id
AND     UpdateAt    = @UpdateAt";

            return(dbHelper.ExecuteAsync <MatchingHeader>(query, header, token));
        }
示例#2
0
        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
            });
        }