Example #1
0
        private static List <PriceComponent> GetPriceComponents(this WorkEffort @this, Part part)
        {
            var priceComponents = new List <PriceComponent>();

            var extent = new PriceComponents(@this.Strategy.Session).Extent();

            foreach (PriceComponent priceComponent in extent)
            {
                if (priceComponent.ExistPart && priceComponent.Part.Equals(part) &&
                    priceComponent.FromDate <= @this.ActualStart &&
                    (!priceComponent.ExistThroughDate || priceComponent.ThroughDate >= @this.ActualStart))
                {
                    priceComponents.Add(priceComponent);
                }
            }

            // Discounts and surcharges can be specified without product or product feature, these need te be added to collection of pricecomponents
            extent = new PriceComponents(@this.Strategy.Session).Extent();
            foreach (PriceComponent priceComponent in extent)
            {
                if (!priceComponent.ExistProduct && !priceComponent.ExistPart && !priceComponent.ExistProductFeature &&
                    priceComponent.FromDate <= @this.ActualStart &&
                    (!priceComponent.ExistThroughDate || priceComponent.ThroughDate >= @this.ActualStart))
                {
                    priceComponents.Add(priceComponent);
                }
            }

            return(priceComponents);
        }
Example #2
0
        private static List <PriceComponent> GetPriceComponents(Product product, DateTime date)
        {
            // TODO: Code duplication ?
            var priceComponents = new List <PriceComponent>();

            var session = product.Strategy.Session;
            var extent  = new PriceComponents(session).Extent();

            foreach (PriceComponent priceComponent in extent)
            {
                if (priceComponent.ExistProduct && priceComponent.Product.Equals(product) && !priceComponent.ExistProductFeature &&
                    priceComponent.FromDate <= date && (!priceComponent.ExistThroughDate || priceComponent.ThroughDate >= date))
                {
                    priceComponents.Add(priceComponent);
                }
            }

            if (priceComponents.Count == 0 && product.ExistProductWhereVariant)
            {
                extent = new PriceComponents(session).Extent();
                foreach (PriceComponent priceComponent in extent)
                {
                    if (priceComponent.ExistProduct && priceComponent.Product.Equals(product.ProductWhereVariant) && !priceComponent.ExistProductFeature &&
                        priceComponent.FromDate <= date && (!priceComponent.ExistThroughDate || priceComponent.ThroughDate >= date))
                    {
                        priceComponents.Add(priceComponent);
                    }
                }
            }

            // Discounts and surcharges can be specified without product or product feature, these need te be added to collection of pricecomponents
            extent = new PriceComponents(session).Extent();
            foreach (PriceComponent priceComponent in extent)
            {
                if (!priceComponent.ExistProduct && !priceComponent.ExistProductFeature &&
                    priceComponent.FromDate <= date && (!priceComponent.ExistThroughDate || priceComponent.ThroughDate >= date))
                {
                    priceComponents.Add(priceComponent);
                }
            }

            return(priceComponents);
        }
Example #3
0
        public void BaseCalculateSellingPrice(WorkEffortPurchaseOrderItemAssignmentCalculateSellingPrice method)
        {
            if (!method.Result.HasValue)
            {
                if (this.AssignedUnitSellingPrice.HasValue)
                {
                    this.UnitSellingPrice = this.AssignedUnitSellingPrice.Value;
                }
                else
                {
                    var part = this.PurchaseOrderItem.Part;
                    var currentPriceComponents     = new PriceComponents(this.Strategy.Session).CurrentPriceComponents(this.Assignment.ScheduledStart);
                    var currentPartPriceComponents = part.GetPriceComponents(currentPriceComponents);

                    var price = currentPartPriceComponents.OfType <BasePrice>().Max(v => v.Price);
                    this.UnitSellingPrice = price ?? 0M;
                }

                method.Result = true;
            }
        }
Example #4
0
        public void BaseOnDerive(ObjectOnDerive method)
        {
            var derivation = method.Derivation;
            var session    = this.Session();

            this.ValidQuoteItems = this.QuoteItems.Where(v => v.IsValid).ToArray();

            var currentPriceComponents = new PriceComponents(session).CurrentPriceComponents(this.IssueDate);

            var quantityOrderedByProduct = this.ValidQuoteItems
                                           .Where(v => v.ExistProduct)
                                           .GroupBy(v => v.Product)
                                           .ToDictionary(v => v.Key, v => v.Sum(w => w.Quantity));

            // First run to calculate price
            foreach (QuoteItem quoteItem in this.ValidQuoteItems)
            {
                decimal quantityOrdered = 0;

                if (quoteItem.ExistProduct)
                {
                    quantityOrderedByProduct.TryGetValue(quoteItem.Product, out quantityOrdered);
                }

                foreach (QuoteItem featureItem in quoteItem.QuotedWithFeatures)
                {
                    featureItem.Quantity = quoteItem.Quantity;
                    this.CalculatePrices(derivation, featureItem, currentPriceComponents, quantityOrdered, 0);
                }

                this.CalculatePrices(derivation, quoteItem, currentPriceComponents, quantityOrdered, 0);
            }

            var totalBasePriceByProduct = this.QuoteItems
                                          .Where(v => v.ExistProduct)
                                          .GroupBy(v => v.Product)
                                          .ToDictionary(v => v.Key, v => v.Sum(w => w.TotalBasePrice));

            // Second run to calculate price (because of order value break)
            foreach (QuoteItem quoteItem in this.ValidQuoteItems)
            {
                decimal quantityOrdered = 0;
                decimal totalBasePrice  = 0;

                if (quoteItem.ExistProduct)
                {
                    quantityOrderedByProduct.TryGetValue(quoteItem.Product, out quantityOrdered);
                    totalBasePriceByProduct.TryGetValue(quoteItem.Product, out totalBasePrice);
                }

                foreach (QuoteItem featureItem in quoteItem.QuotedWithFeatures)
                {
                    this.CalculatePrices(derivation, featureItem, currentPriceComponents, quantityOrdered, totalBasePrice);
                }

                this.CalculatePrices(derivation, quoteItem, currentPriceComponents, quantityOrdered, totalBasePrice);
            }

            // SalesOrderItem Derivations and Validations
            foreach (QuoteItem quoteItem in this.ValidQuoteItems)
            {
                var isSubTotalItem = quoteItem.ExistInvoiceItemType && (quoteItem.InvoiceItemType.IsProductItem || quoteItem.InvoiceItemType.IsPartItem);
                if (isSubTotalItem)
                {
                    if (quoteItem.Quantity == 0)
                    {
                        derivation.Validation.AddError(quoteItem, M.QuoteItem.Quantity, "Quantity is Required");
                    }
                }
                else
                {
                    if (quoteItem.UnitPrice == 0)
                    {
                        derivation.Validation.AddError(quoteItem, M.QuoteItem.UnitPrice, "Price is Required");
                    }
                }
            }

            // Calculate Totals
            if (this.ExistQuoteItems)
            {
                this.TotalBasePrice           = 0;
                this.TotalDiscount            = 0;
                this.TotalSurcharge           = 0;
                this.TotalExVat               = 0;
                this.TotalFee                 = 0;
                this.TotalShippingAndHandling = 0;
                this.TotalVat                 = 0;
                this.TotalIncVat              = 0;
                this.TotalListPrice           = 0;

                foreach (QuoteItem quoteItem in this.ValidQuoteItems)
                {
                    if (!quoteItem.ExistQuoteItemWhereQuotedWithFeature)
                    {
                        this.TotalBasePrice += quoteItem.TotalBasePrice;
                        this.TotalDiscount  += quoteItem.TotalDiscount;
                        this.TotalSurcharge += quoteItem.TotalSurcharge;
                        this.TotalExVat     += quoteItem.TotalExVat;
                        this.TotalVat       += quoteItem.TotalVat;
                        this.TotalIncVat    += quoteItem.TotalIncVat;
                        this.TotalListPrice += quoteItem.TotalExVat;
                    }
                }

                if (this.ExistDiscountAdjustment)
                {
                    var discount = this.DiscountAdjustment.Percentage.HasValue ?
                                   Math.Round(this.TotalExVat * this.DiscountAdjustment.Percentage.Value / 100, 2) :
                                   this.DiscountAdjustment.Amount ?? 0;

                    this.TotalDiscount += discount;
                    this.TotalExVat    -= discount;

                    if (this.ExistVatRegime)
                    {
                        var vat = Math.Round(discount * this.VatRegime.VatRate.Rate / 100, 2);

                        this.TotalVat    -= vat;
                        this.TotalIncVat -= discount + vat;
                    }
                }

                if (this.ExistSurchargeAdjustment)
                {
                    var surcharge = this.SurchargeAdjustment.Percentage.HasValue ?
                                    Math.Round(this.TotalExVat * this.SurchargeAdjustment.Percentage.Value / 100, 2) :
                                    this.SurchargeAdjustment.Amount ?? 0;

                    this.TotalSurcharge += surcharge;
                    this.TotalExVat     += surcharge;

                    if (this.ExistVatRegime)
                    {
                        var vat = Math.Round(surcharge * this.VatRegime.VatRate.Rate / 100, 2);
                        this.TotalVat    += vat;
                        this.TotalIncVat += surcharge + vat;
                    }
                }

                if (this.ExistFee)
                {
                    var fee = this.Fee.Percentage.HasValue ?
                              Math.Round(this.TotalExVat * this.Fee.Percentage.Value / 100, 2) :
                              this.Fee.Amount ?? 0;

                    this.TotalFee   += fee;
                    this.TotalExVat += fee;

                    if (this.Fee.ExistVatRate)
                    {
                        var vat1 = Math.Round(fee * this.Fee.VatRate.Rate / 100, 2);
                        this.TotalVat    += vat1;
                        this.TotalIncVat += fee + vat1;
                    }
                }

                if (this.ExistShippingAndHandlingCharge)
                {
                    var shipping = this.ShippingAndHandlingCharge.Percentage.HasValue ?
                                   Math.Round(this.TotalExVat * this.ShippingAndHandlingCharge.Percentage.Value / 100, 2) :
                                   this.ShippingAndHandlingCharge.Amount ?? 0;

                    this.TotalShippingAndHandling += shipping;
                    this.TotalExVat += shipping;

                    if (this.ShippingAndHandlingCharge.ExistVatRate)
                    {
                        var vat2 = Math.Round(shipping * this.ShippingAndHandlingCharge.VatRate.Rate / 100, 2);
                        this.TotalVat    += vat2;
                        this.TotalIncVat += shipping + vat2;
                    }
                }

                //// Only take into account items for which there is data at the item level.
                //// Skip negative sales.
                decimal totalUnitBasePrice = 0;
                decimal totalListPrice     = 0;

                foreach (QuoteItem item1 in this.ValidQuoteItems)
                {
                    if (item1.TotalExVat > 0)
                    {
                        totalUnitBasePrice += item1.UnitBasePrice;
                        totalListPrice     += item1.UnitPrice;
                    }
                }
            }

            this.DeriveWorkflow();

            this.Sync(this.Strategy.Session);

            this.ResetPrintDocument();
        }
Example #5
0
        public void CalculatePrices(
            IDerivation derivation,
            QuoteItem quoteItem,
            PriceComponent[] currentPriceComponents,
            decimal quantityOrdered,
            decimal totalBasePrice)
        {
            var quoteItemDeriveRoles = (QuoteItemDerivedRoles)quoteItem;

            var currentGenericOrProductOrFeaturePriceComponents = Array.Empty <PriceComponent>();

            if (quoteItem.ExistProduct)
            {
                currentGenericOrProductOrFeaturePriceComponents = quoteItem.Product.GetPriceComponents(currentPriceComponents);
            }
            else if (quoteItem.ExistProductFeature)
            {
                currentGenericOrProductOrFeaturePriceComponents = quoteItem.ProductFeature.GetPriceComponents(quoteItem.QuoteItemWhereQuotedWithFeature.Product, currentPriceComponents);
            }

            var priceComponents = currentGenericOrProductOrFeaturePriceComponents.Where(
                v => PriceComponents.BaseIsApplicable(
                    new PriceComponents.IsApplicable
            {
                PriceComponent  = v,
                Customer        = this.Receiver,
                Product         = quoteItem.Product,
                QuantityOrdered = quantityOrdered,
                ValueOrdered    = totalBasePrice,
            })).ToArray();

            var unitBasePrice = priceComponents.OfType <BasePrice>().Min(v => v.Price);

            if (!unitBasePrice.HasValue)
            {
                unitBasePrice = 0;
            }

            // Calculate Unit Price (with Discounts and Surcharges)
            if (quoteItem.AssignedUnitPrice.HasValue)
            {
                quoteItemDeriveRoles.UnitBasePrice = unitBasePrice ?? quoteItem.AssignedUnitPrice.Value;
                quoteItemDeriveRoles.UnitDiscount  = 0;
                quoteItemDeriveRoles.UnitSurcharge = 0;
                quoteItemDeriveRoles.UnitPrice     = quoteItem.AssignedUnitPrice.Value;
            }
            else
            {
                quoteItemDeriveRoles.UnitBasePrice = unitBasePrice.Value;

                quoteItemDeriveRoles.UnitDiscount = priceComponents.OfType <DiscountComponent>().Sum(
                    v => v.Percentage.HasValue
                             ? Math.Round(quoteItem.UnitBasePrice * v.Percentage.Value / 100, 2)
                             : v.Price ?? 0);

                quoteItemDeriveRoles.UnitSurcharge = priceComponents.OfType <SurchargeComponent>().Sum(
                    v => v.Percentage.HasValue
                             ? Math.Round(quoteItem.UnitBasePrice * v.Percentage.Value / 100, 2)
                             : v.Price ?? 0);

                quoteItemDeriveRoles.UnitPrice = quoteItem.UnitBasePrice - quoteItem.UnitDiscount + quoteItem.UnitSurcharge;

                if (quoteItem.ExistDiscountAdjustment)
                {
                    quoteItemDeriveRoles.UnitDiscount += quoteItem.DiscountAdjustment.Percentage.HasValue ?
                                                         Math.Round(quoteItem.UnitPrice * quoteItem.DiscountAdjustment.Percentage.Value / 100, 2) :
                                                         quoteItem.DiscountAdjustment.Amount ?? 0;
                }

                if (quoteItem.ExistSurchargeAdjustment)
                {
                    quoteItemDeriveRoles.UnitSurcharge += quoteItem.SurchargeAdjustment.Percentage.HasValue ?
                                                          Math.Round(quoteItem.UnitPrice * quoteItem.SurchargeAdjustment.Percentage.Value / 100, 2) :
                                                          quoteItem.SurchargeAdjustment.Amount ?? 0;
                }

                quoteItemDeriveRoles.UnitPrice = quoteItem.UnitBasePrice - quoteItem.UnitDiscount + quoteItem.UnitSurcharge;
            }

            foreach (QuoteItem featureItem in quoteItem.QuotedWithFeatures)
            {
                quoteItemDeriveRoles.UnitBasePrice += featureItem.UnitBasePrice;
                quoteItemDeriveRoles.UnitPrice     += featureItem.UnitPrice;
                quoteItemDeriveRoles.UnitDiscount  += featureItem.UnitDiscount;
                quoteItemDeriveRoles.UnitSurcharge += featureItem.UnitSurcharge;
            }

            quoteItemDeriveRoles.UnitVat = quoteItem.ExistVatRate ? Math.Round(quoteItem.UnitPrice * quoteItem.VatRate.Rate / 100, 2) : 0;

            // Calculate Totals
            quoteItemDeriveRoles.TotalBasePrice       = quoteItem.UnitBasePrice * quoteItem.Quantity;
            quoteItemDeriveRoles.TotalDiscount        = quoteItem.UnitDiscount * quoteItem.Quantity;
            quoteItemDeriveRoles.TotalSurcharge       = quoteItem.UnitSurcharge * quoteItem.Quantity;
            quoteItemDeriveRoles.TotalPriceAdjustment = quoteItem.TotalSurcharge - quoteItem.TotalDiscount;

            if (quoteItem.TotalBasePrice > 0)
            {
                quoteItemDeriveRoles.TotalDiscountAsPercentage  = Math.Round(quoteItem.TotalDiscount / quoteItem.TotalBasePrice * 100, 2);
                quoteItemDeriveRoles.TotalSurchargeAsPercentage = Math.Round(quoteItem.TotalSurcharge / quoteItem.TotalBasePrice * 100, 2);
            }
            else
            {
                quoteItemDeriveRoles.TotalDiscountAsPercentage  = 0;
                quoteItemDeriveRoles.TotalSurchargeAsPercentage = 0;
            }

            quoteItemDeriveRoles.TotalExVat  = quoteItem.UnitPrice * quoteItem.Quantity;
            quoteItemDeriveRoles.TotalVat    = quoteItem.UnitVat * quoteItem.Quantity;
            quoteItemDeriveRoles.TotalIncVat = quoteItem.TotalExVat + quoteItem.TotalVat;
        }
Example #6
0
        public void BaseOnDerive(ObjectOnDerive method)
        {
            var derivation = method.Derivation;
            var session    = this.Session();

            this.ValidQuoteItems = this.QuoteItems.Where(v => v.IsValid).ToArray();

            var currentPriceComponents = new PriceComponents(session).CurrentPriceComponents(this.IssueDate);

            var quantityOrderedByProduct = this.ValidQuoteItems
                                           .Where(v => v.ExistProduct)
                                           .GroupBy(v => v.Product)
                                           .ToDictionary(v => v.Key, v => v.Sum(w => w.Quantity));

            // First run to calculate price
            foreach (QuoteItem quoteItem in this.ValidQuoteItems)
            {
                decimal quantityOrdered = 0;

                if (quoteItem.ExistProduct)
                {
                    quantityOrderedByProduct.TryGetValue(quoteItem.Product, out quantityOrdered);
                }

                foreach (QuoteItem featureItem in quoteItem.QuotedWithFeatures)
                {
                    featureItem.Quantity = quoteItem.Quantity;
                    this.CalculatePrices(derivation, featureItem, currentPriceComponents, quantityOrdered, 0);
                }

                this.CalculatePrices(derivation, quoteItem, currentPriceComponents, quantityOrdered, 0);
            }

            var totalBasePriceByProduct = this.QuoteItems
                                          .Where(v => v.ExistProduct)
                                          .GroupBy(v => v.Product)
                                          .ToDictionary(v => v.Key, v => v.Sum(w => w.TotalBasePrice));

            // Second run to calculate price (because of order value break)
            foreach (QuoteItem quoteItem in this.ValidQuoteItems)
            {
                decimal quantityOrdered = 0;
                decimal totalBasePrice  = 0;

                if (quoteItem.ExistProduct)
                {
                    quantityOrderedByProduct.TryGetValue(quoteItem.Product, out quantityOrdered);
                    totalBasePriceByProduct.TryGetValue(quoteItem.Product, out totalBasePrice);
                }

                foreach (QuoteItem featureItem in quoteItem.QuotedWithFeatures)
                {
                    this.CalculatePrices(derivation, featureItem, currentPriceComponents, quantityOrdered, totalBasePrice);
                }

                this.CalculatePrices(derivation, quoteItem, currentPriceComponents, quantityOrdered, totalBasePrice);
            }

            // SalesOrderItem Derivations and Validations
            foreach (QuoteItem quoteItem in this.ValidQuoteItems)
            {
                var isSubTotalItem = quoteItem.ExistInvoiceItemType && (quoteItem.InvoiceItemType.IsProductItem || quoteItem.InvoiceItemType.IsPartItem);
                if (isSubTotalItem)
                {
                    if (quoteItem.Quantity == 0)
                    {
                        derivation.Validation.AddError(quoteItem, M.QuoteItem.Quantity, "Quantity is Required");
                    }
                }
                else
                {
                    if (quoteItem.UnitPrice == 0)
                    {
                        derivation.Validation.AddError(quoteItem, M.QuoteItem.UnitPrice, "Price is Required");
                    }
                }
            }

            // Calculate Totals
            this.TotalBasePrice           = 0;
            this.TotalDiscount            = 0;
            this.TotalSurcharge           = 0;
            this.TotalExVat               = 0;
            this.TotalFee                 = 0;
            this.TotalShippingAndHandling = 0;
            this.TotalExtraCharge         = 0;
            this.TotalVat                 = 0;
            this.TotalIrpf                = 0;
            this.TotalIncVat              = 0;
            this.TotalListPrice           = 0;
            this.GrandTotal               = 0;

            foreach (QuoteItem quoteItem in this.ValidQuoteItems)
            {
                if (!quoteItem.ExistQuoteItemWhereQuotedWithFeature)
                {
                    this.TotalBasePrice += quoteItem.TotalBasePrice;
                    this.TotalDiscount  += quoteItem.TotalDiscount;
                    this.TotalSurcharge += quoteItem.TotalSurcharge;
                    this.TotalExVat     += quoteItem.TotalExVat;
                    this.TotalVat       += quoteItem.TotalVat;
                    this.TotalIrpf      += quoteItem.TotalIrpf;
                    this.TotalIncVat    += quoteItem.TotalIncVat;
                    this.TotalListPrice += quoteItem.TotalExVat;
                    this.GrandTotal     += quoteItem.GrandTotal;
                }
            }

            var discount          = 0M;
            var discountVat       = 0M;
            var discountIrpf      = 0M;
            var surcharge         = 0M;
            var surchargeVat      = 0M;
            var surchargeIrpf     = 0M;
            var fee               = 0M;
            var feeVat            = 0M;
            var feeIrpf           = 0M;
            var shipping          = 0M;
            var shippingVat       = 0M;
            var shippingIrpf      = 0M;
            var miscellaneous     = 0M;
            var miscellaneousVat  = 0M;
            var miscellaneousIrpf = 0M;

            if (this.ExistIssueDate)
            {
                this.DerivedVatRate  = this.DerivedVatRegime?.VatRates.First(v => v.FromDate <= this.IssueDate && (!v.ExistThroughDate || v.ThroughDate >= this.IssueDate));
                this.DerivedIrpfRate = this.DerivedIrpfRegime?.IrpfRates.First(v => v.FromDate <= this.IssueDate && (!v.ExistThroughDate || v.ThroughDate >= this.IssueDate));
            }

            foreach (OrderAdjustment orderAdjustment in this.OrderAdjustments)
            {
                if (orderAdjustment.GetType().Name.Equals(typeof(DiscountAdjustment).Name))
                {
                    discount = orderAdjustment.Percentage.HasValue ?
                               this.TotalExVat * orderAdjustment.Percentage.Value / 100 :
                               orderAdjustment.Amount ?? 0;

                    this.TotalDiscount += discount;

                    if (this.ExistDerivedVatRegime)
                    {
                        discountVat = discount * this.DerivedVatRate.Rate / 100;
                    }

                    if (this.ExistDerivedIrpfRegime)
                    {
                        discountIrpf = discount * this.DerivedIrpfRate.Rate / 100;
                    }
                }

                if (orderAdjustment.GetType().Name.Equals(typeof(SurchargeAdjustment).Name))
                {
                    surcharge = orderAdjustment.Percentage.HasValue ?
                                this.TotalExVat * orderAdjustment.Percentage.Value / 100 :
                                orderAdjustment.Amount ?? 0;

                    this.TotalSurcharge += surcharge;

                    if (this.ExistDerivedVatRegime)
                    {
                        surchargeVat = surcharge * this.DerivedVatRate.Rate / 100;
                    }

                    if (this.ExistDerivedIrpfRegime)
                    {
                        surchargeIrpf = surcharge * this.DerivedIrpfRate.Rate / 100;
                    }
                }

                if (orderAdjustment.GetType().Name.Equals(typeof(Fee).Name))
                {
                    fee = orderAdjustment.Percentage.HasValue ?
                          this.TotalExVat * orderAdjustment.Percentage.Value / 100 :
                          orderAdjustment.Amount ?? 0;

                    this.TotalFee += fee;

                    if (this.ExistDerivedVatRegime)
                    {
                        feeVat = fee * this.DerivedVatRate.Rate / 100;
                    }

                    if (this.ExistDerivedIrpfRegime)
                    {
                        feeIrpf = fee * this.DerivedIrpfRate.Rate / 100;
                    }
                }

                if (orderAdjustment.GetType().Name.Equals(typeof(ShippingAndHandlingCharge).Name))
                {
                    shipping = orderAdjustment.Percentage.HasValue ?
                               this.TotalExVat * orderAdjustment.Percentage.Value / 100 :
                               orderAdjustment.Amount ?? 0;

                    this.TotalShippingAndHandling += shipping;

                    if (this.ExistDerivedVatRegime)
                    {
                        shippingVat = shipping * this.DerivedVatRate.Rate / 100;
                    }

                    if (this.ExistDerivedIrpfRegime)
                    {
                        shippingIrpf = shipping * this.DerivedIrpfRate.Rate / 100;
                    }
                }

                if (orderAdjustment.GetType().Name.Equals(typeof(MiscellaneousCharge).Name))
                {
                    miscellaneous = orderAdjustment.Percentage.HasValue ?
                                    this.TotalExVat * orderAdjustment.Percentage.Value / 100 :
                                    orderAdjustment.Amount ?? 0;

                    this.TotalExtraCharge += miscellaneous;

                    if (this.ExistDerivedVatRegime)
                    {
                        miscellaneousVat = miscellaneous * this.DerivedVatRate.Rate / 100;
                    }

                    if (this.ExistDerivedIrpfRegime)
                    {
                        miscellaneousIrpf = miscellaneous * this.DerivedIrpfRate.Rate / 100;
                    }
                }
            }

            var totalExtraCharge = fee + shipping + miscellaneous;
            var totalExVat       = this.TotalExVat - discount + surcharge + fee + shipping + miscellaneous;
            var totalVat         = this.TotalVat - discountVat + surchargeVat + feeVat + shippingVat + miscellaneousVat;
            var totalIncVat      = this.TotalIncVat - discount - discountVat + surcharge + surchargeVat + fee + feeVat + shipping + shippingVat + miscellaneous + miscellaneousVat;
            var totalIrpf        = this.TotalIrpf + discountIrpf - surchargeIrpf - feeIrpf - shippingIrpf - miscellaneousIrpf;
            var grandTotal       = totalIncVat - totalIrpf;

            if (this.ExistIssueDate && this.ExistDerivedCurrency && this.ExistIssuer)
            {
                this.TotalBasePriceInPreferredCurrency           = Rounder.RoundDecimal(Currencies.ConvertCurrency(this.TotalBasePrice, this.IssueDate, this.DerivedCurrency, this.Issuer.PreferredCurrency), 2);
                this.TotalDiscountInPreferredCurrency            = Rounder.RoundDecimal(Currencies.ConvertCurrency(this.TotalDiscount, this.IssueDate, this.DerivedCurrency, this.Issuer.PreferredCurrency), 2);
                this.TotalSurchargeInPreferredCurrency           = Rounder.RoundDecimal(Currencies.ConvertCurrency(this.TotalSurcharge, this.IssueDate, this.DerivedCurrency, this.Issuer.PreferredCurrency), 2);
                this.TotalExtraChargeInPreferredCurrency         = Rounder.RoundDecimal(Currencies.ConvertCurrency(totalExtraCharge, this.IssueDate, this.DerivedCurrency, this.Issuer.PreferredCurrency), 2);
                this.TotalFeeInPreferredCurrency                 = Rounder.RoundDecimal(Currencies.ConvertCurrency(this.TotalFee, this.IssueDate, this.DerivedCurrency, this.Issuer.PreferredCurrency), 2);
                this.TotalShippingAndHandlingInPreferredCurrency = Rounder.RoundDecimal(Currencies.ConvertCurrency(this.TotalShippingAndHandling, this.IssueDate, this.DerivedCurrency, this.Issuer.PreferredCurrency), 2);
                this.TotalExVatInPreferredCurrency               = Rounder.RoundDecimal(Currencies.ConvertCurrency(totalExVat, this.IssueDate, this.DerivedCurrency, this.Issuer.PreferredCurrency), 2);
                this.TotalVatInPreferredCurrency                 = Rounder.RoundDecimal(Currencies.ConvertCurrency(totalVat, this.IssueDate, this.DerivedCurrency, this.Issuer.PreferredCurrency), 2);
                this.TotalIncVatInPreferredCurrency              = Rounder.RoundDecimal(Currencies.ConvertCurrency(totalIncVat, this.IssueDate, this.DerivedCurrency, this.Issuer.PreferredCurrency), 2);
                this.TotalIrpfInPreferredCurrency                = Rounder.RoundDecimal(Currencies.ConvertCurrency(totalIrpf, this.IssueDate, this.DerivedCurrency, this.Issuer.PreferredCurrency), 2);
                this.GrandTotalInPreferredCurrency               = Rounder.RoundDecimal(Currencies.ConvertCurrency(grandTotal, this.IssueDate, this.DerivedCurrency, this.Issuer.PreferredCurrency), 2);
            }

            this.TotalBasePrice           = Rounder.RoundDecimal(this.TotalBasePrice, 2);
            this.TotalDiscount            = Rounder.RoundDecimal(this.TotalDiscount, 2);
            this.TotalSurcharge           = Rounder.RoundDecimal(this.TotalSurcharge, 2);
            this.TotalExtraCharge         = Rounder.RoundDecimal(totalExtraCharge, 2);
            this.TotalFee                 = Rounder.RoundDecimal(this.TotalFee, 2);
            this.TotalShippingAndHandling = Rounder.RoundDecimal(this.TotalShippingAndHandling, 2);
            this.TotalExVat               = Rounder.RoundDecimal(totalExVat, 2);
            this.TotalVat                 = Rounder.RoundDecimal(totalVat, 2);
            this.TotalIncVat              = Rounder.RoundDecimal(totalIncVat, 2);
            this.TotalIrpf                = Rounder.RoundDecimal(totalIrpf, 2);
            this.GrandTotal               = Rounder.RoundDecimal(grandTotal, 2);

            //// Only take into account items for which there is data at the item level.
            //// Skip negative sales.
            decimal totalUnitBasePrice = 0;
            decimal totalListPrice     = 0;

            foreach (QuoteItem item1 in this.ValidQuoteItems)
            {
                if (item1.TotalExVat > 0)
                {
                    totalUnitBasePrice += item1.UnitBasePrice;
                    totalListPrice     += item1.UnitPrice;
                }
            }

            this.TotalListPriceInPreferredCurrency = Rounder.RoundDecimal(Currencies.ConvertCurrency(TotalListPrice, this.IssueDate, this.DerivedCurrency, this.Issuer.PreferredCurrency), 2);
            this.TotalListPrice = Rounder.RoundDecimal(this.TotalListPrice, 2);

            this.DeriveWorkflow();

            this.Sync(this.Strategy.Session);

            this.ResetPrintDocument();
        }
Example #7
0
        private IEnumerable <PriceComponent> GetPriceComponents()
        {
            var priceComponents = new List <PriceComponent>();

            if (priceComponents.Count == 0)
            {
                var extent = new PriceComponents(this.strategy.Session).Extent();
                if (this.ExistProduct)
                {
                    foreach (PriceComponent priceComponent in extent)
                    {
                        if (priceComponent.ExistProduct && priceComponent.Product.Equals(this.Product) && !priceComponent.ExistProductFeature &&
                            priceComponent.FromDate <= this.SalesInvoiceWhereSalesInvoiceItem.InvoiceDate &&
                            (!priceComponent.ExistThroughDate || priceComponent.ThroughDate >= this.SalesInvoiceWhereSalesInvoiceItem.InvoiceDate))
                        {
                            priceComponents.Add(priceComponent);
                        }
                    }

                    if (priceComponents.Count == 0 && this.Product.ExistProductWhereVariant)
                    {
                        extent = new PriceComponents(this.strategy.Session).Extent();
                        foreach (PriceComponent priceComponent in extent)
                        {
                            if (priceComponent.ExistProduct && priceComponent.Product.Equals(this.Product.ProductWhereVariant) && !priceComponent.ExistProductFeature &&
                                priceComponent.FromDate <= this.SalesInvoiceWhereSalesInvoiceItem.InvoiceDate &&
                                (!priceComponent.ExistThroughDate || priceComponent.ThroughDate >= this.SalesInvoiceWhereSalesInvoiceItem.InvoiceDate))
                            {
                                priceComponents.Add(priceComponent);
                            }
                        }
                    }
                }

                if (this.ExistProductFeature)
                {
                    foreach (PriceComponent priceComponent in extent)
                    {
                        if (priceComponent.ExistProductFeature && priceComponent.ProductFeature.Equals(this.ProductFeature) && !priceComponent.ExistProduct &&
                            priceComponent.FromDate <= this.SalesInvoiceWhereSalesInvoiceItem.InvoiceDate &&
                            (!priceComponent.ExistThroughDate || priceComponent.ThroughDate >= this.SalesInvoiceWhereSalesInvoiceItem.InvoiceDate))
                        {
                            priceComponents.Add(priceComponent);
                        }
                    }
                }

                // Discounts and surcharges can be specified without product or product feature, these need te be added to collection of pricecomponents
                extent = new PriceComponents(this.strategy.Session).Extent();
                foreach (PriceComponent priceComponent in extent)
                {
                    if (!priceComponent.ExistProduct && !priceComponent.ExistProductFeature &&
                        priceComponent.FromDate <= this.SalesInvoiceWhereSalesInvoiceItem.InvoiceDate &&
                        (!priceComponent.ExistThroughDate || priceComponent.ThroughDate >= this.SalesInvoiceWhereSalesInvoiceItem.InvoiceDate))
                    {
                        priceComponents.Add(priceComponent);
                    }
                }
            }

            return(priceComponents);
        }
Example #8
0
        public void AppsOnDerivePrices(IDerivation derivation, decimal quantityInvoiced, decimal totalBasePrice)
        {
            this.UnitBasePrice       = 0;
            this.UnitDiscount        = 0;
            this.UnitSurcharge       = 0;
            this.CalculatedUnitPrice = 0;
            decimal discountAdjustmentAmount  = 0;
            decimal surchargeAdjustmentAmount = 0;

            var internalOrganisation = this.Strategy.Session.GetSingleton();
            var customer             = this.SalesInvoiceWhereSalesInvoiceItem.BillToCustomer;
            var salesInvoice         = this.SalesInvoiceWhereSalesInvoiceItem;

            var baseprices = new PriceComponent[0];

            if (this.ExistProduct && this.Product.ExistBasePrices)
            {
                baseprices = this.Product.BasePrices;
            }

            if (this.ExistProductFeature && this.ProductFeature.ExistBasePrices)
            {
                baseprices = this.ProductFeature.BasePrices;
            }

            foreach (BasePrice priceComponent in baseprices)
            {
                if (priceComponent.FromDate <= this.SalesInvoiceWhereSalesInvoiceItem.InvoiceDate &&
                    (!priceComponent.ExistThroughDate || priceComponent.ThroughDate >= this.SalesInvoiceWhereSalesInvoiceItem.InvoiceDate))
                {
                    if (priceComponent.Strategy.Class.Equals(M.BasePrice.ObjectType))
                    {
                        if (PriceComponents.AppsIsEligible(new PriceComponents.IsEligibleParams
                        {
                            PriceComponent = priceComponent,
                            Customer = customer,
                            Product = this.Product,
                            SalesInvoice = salesInvoice,
                            QuantityOrdered = quantityInvoiced,
                            ValueOrdered = totalBasePrice
                        }))
                        {
                            if (priceComponent.ExistPrice)
                            {
                                if (priceComponent.Price.HasValue && (this.UnitBasePrice == 0 || priceComponent.Price < this.UnitBasePrice))
                                {
                                    this.UnitBasePrice = priceComponent.Price.Value;

                                    this.RemoveCurrentPriceComponents();
                                    this.AddCurrentPriceComponent(priceComponent);
                                }
                            }
                        }
                    }
                }
            }

            if (!this.ExistActualUnitPrice)
            {
                var priceComponents = this.GetPriceComponents();

                var revenueBreakDiscount  = 0M;
                var revenueBreakSurcharge = 0M;

                foreach (var priceComponent in priceComponents)
                {
                    if (priceComponent.Strategy.Class.Equals(M.DiscountComponent.ObjectType) || priceComponent.Strategy.Class.Equals(M.SurchargeComponent.ObjectType))
                    {
                        if (PriceComponents.AppsIsEligible(new PriceComponents.IsEligibleParams
                        {
                            PriceComponent = priceComponent,
                            Customer = customer,
                            Product = this.Product,
                            SalesInvoice = salesInvoice,
                            QuantityOrdered = quantityInvoiced,
                            ValueOrdered = totalBasePrice,
                        }))
                        {
                            this.AddCurrentPriceComponent(priceComponent);

                            revenueBreakDiscount  = this.SetUnitDiscount(priceComponent, revenueBreakDiscount);
                            revenueBreakSurcharge = this.SetUnitSurcharge(priceComponent, revenueBreakSurcharge);
                        }
                    }
                }

                var adjustmentBase = this.UnitBasePrice - this.UnitDiscount + this.UnitSurcharge;

                if (this.ExistDiscountAdjustment)
                {
                    if (this.DiscountAdjustment.Percentage.HasValue)
                    {
                        discountAdjustmentAmount = Math.Round((adjustmentBase * this.DiscountAdjustment.Percentage.Value) / 100, 2);
                    }
                    else
                    {
                        discountAdjustmentAmount = this.DiscountAdjustment.Amount.HasValue ? this.DiscountAdjustment.Amount.Value : 0;
                    }

                    this.UnitDiscount += discountAdjustmentAmount;
                }

                if (this.ExistSurchargeAdjustment)
                {
                    if (this.SurchargeAdjustment.Percentage.HasValue)
                    {
                        surchargeAdjustmentAmount = Math.Round((adjustmentBase * this.SurchargeAdjustment.Percentage.Value) / 100, 2);
                    }
                    else
                    {
                        surchargeAdjustmentAmount = this.SurchargeAdjustment.Amount.HasValue ? this.SurchargeAdjustment.Amount.Value : 0;
                    }

                    this.UnitSurcharge += surchargeAdjustmentAmount;
                }
            }

            var price = this.ActualUnitPrice.HasValue ? this.ActualUnitPrice.Value : this.UnitBasePrice;

            decimal vat = 0;

            if (this.ExistDerivedVatRate)
            {
                var vatRate = this.DerivedVatRate.Rate;
                var vatBase = price - this.UnitDiscount + this.UnitSurcharge;
                vat = Math.Round((vatBase * vatRate) / 100, 2);
            }

            this.UnitVat                = vat;
            this.TotalBasePrice         = price * this.Quantity;
            this.TotalDiscount          = this.UnitDiscount * this.Quantity;
            this.TotalSurcharge         = this.UnitSurcharge * this.Quantity;
            this.TotalInvoiceAdjustment = (0 - discountAdjustmentAmount + surchargeAdjustmentAmount) * this.Quantity;

            if (this.TotalBasePrice > 0)
            {
                this.TotalDiscountAsPercentage  = Math.Round((this.TotalDiscount / this.TotalBasePrice) * 100, 2);
                this.TotalSurchargeAsPercentage = Math.Round((this.TotalSurcharge / this.TotalBasePrice) * 100, 2);
            }

            if (this.ActualUnitPrice.HasValue)
            {
                this.CalculatedUnitPrice = this.ActualUnitPrice.Value;
            }
            else
            {
                this.CalculatedUnitPrice = this.UnitBasePrice - this.UnitDiscount + this.UnitSurcharge;
            }

            this.TotalVat    = this.UnitVat * this.Quantity;
            this.TotalExVat  = this.CalculatedUnitPrice * this.Quantity;
            this.TotalIncVat = this.TotalExVat + this.TotalVat;

            var toCurrency   = this.SalesInvoiceWhereSalesInvoiceItem.Currency;
            var fromCurrency = this.SalesInvoiceWhereSalesInvoiceItem.BilledFrom.PreferredCurrency;

            if (fromCurrency.Equals(toCurrency))
            {
                this.TotalBasePriceCustomerCurrency = this.TotalBasePrice;
                this.TotalDiscountCustomerCurrency  = this.TotalDiscount;
                this.TotalSurchargeCustomerCurrency = this.TotalSurcharge;
                this.TotalExVatCustomerCurrency     = this.TotalExVat;
                this.TotalVatCustomerCurrency       = this.TotalVat;
                this.TotalIncVatCustomerCurrency    = this.TotalIncVat;
            }
            else
            {
                this.TotalBasePriceCustomerCurrency = Currencies.ConvertCurrency(this.TotalBasePrice, fromCurrency, toCurrency);
                this.TotalDiscountCustomerCurrency  = Currencies.ConvertCurrency(this.TotalDiscount, fromCurrency, toCurrency);
                this.TotalSurchargeCustomerCurrency = Currencies.ConvertCurrency(this.TotalSurcharge, fromCurrency, toCurrency);
                this.TotalExVatCustomerCurrency     = Currencies.ConvertCurrency(this.TotalExVat, fromCurrency, toCurrency);
                this.TotalVatCustomerCurrency       = Currencies.ConvertCurrency(this.TotalVat, fromCurrency, toCurrency);
                this.TotalIncVatCustomerCurrency    = Currencies.ConvertCurrency(this.TotalIncVat, fromCurrency, toCurrency);
            }

            this.AppsOnDeriveMarkupAndProfitMargin(derivation);
        }
Example #9
0
        private void CalculatePrice(IDerivation derivation, SalesOrder salesOrder, bool useValueOrdered = false)
        {
            var sameProductItems = salesOrder.SalesOrderItems
                                   .Where(v => v.IsValid && v.ExistProduct && v.Product.Equals(this.Product))
                                   .ToArray();

            var quantityOrdered = sameProductItems.Sum(w => w.QuantityOrdered);
            var valueOrdered    = useValueOrdered ? sameProductItems.Sum(w => w.TotalBasePrice) : 0;

            var orderPriceComponents     = new PriceComponents(this.Session()).CurrentPriceComponents(salesOrder.OrderDate);
            var orderItemPriceComponents = Array.Empty <PriceComponent>();

            if (this.ExistProduct)
            {
                orderItemPriceComponents = this.Product.GetPriceComponents(orderPriceComponents);
            }
            else if (this.ExistProductFeature)
            {
                orderItemPriceComponents = this.ProductFeature.GetPriceComponents(this.SalesOrderItemWhereOrderedWithFeature.Product, orderPriceComponents);
            }

            var priceComponents = orderItemPriceComponents.Where(
                v => PriceComponents.BaseIsApplicable(
                    new PriceComponents.IsApplicable
            {
                PriceComponent  = v,
                Customer        = salesOrder.BillToCustomer,
                Product         = this.Product,
                SalesOrder      = salesOrder,
                QuantityOrdered = quantityOrdered,
                ValueOrdered    = valueOrdered,
            })).ToArray();

            var unitBasePrice = priceComponents.OfType <BasePrice>().Min(v => v.Price);

            // Calculate Unit Price (with Discounts and Surcharges)
            if (this.AssignedUnitPrice.HasValue)
            {
                this.UnitBasePrice = unitBasePrice ?? this.AssignedUnitPrice.Value;
                this.UnitDiscount  = 0;
                this.UnitSurcharge = 0;
                this.UnitPrice     = this.AssignedUnitPrice.Value;
            }
            else
            {
                if (!unitBasePrice.HasValue)
                {
                    derivation.Validation.AddError(this, M.SalesOrderItem.UnitBasePrice, "No BasePrice with a Price");
                    return;
                }

                this.UnitBasePrice = unitBasePrice.Value;

                this.UnitDiscount = priceComponents.OfType <DiscountComponent>().Sum(
                    v => v.Percentage.HasValue
                        ? Math.Round(this.UnitBasePrice * v.Percentage.Value / 100, 2)
                        : v.Price ?? 0);

                this.UnitSurcharge = priceComponents.OfType <SurchargeComponent>().Sum(
                    v => v.Percentage.HasValue
                        ? Math.Round(this.UnitBasePrice * v.Percentage.Value / 100, 2)
                        : v.Price ?? 0);

                this.UnitPrice = this.UnitBasePrice - this.UnitDiscount + this.UnitSurcharge;

                foreach (OrderAdjustment orderAdjustment in this.DiscountAdjustments)
                {
                    this.UnitDiscount += orderAdjustment.Percentage.HasValue
                        ? Math.Round(this.UnitPrice * orderAdjustment.Percentage.Value / 100, 2)
                        : orderAdjustment.Amount ?? 0;
                }

                foreach (OrderAdjustment orderAdjustment in this.SurchargeAdjustments)
                {
                    this.UnitSurcharge += orderAdjustment.Percentage.HasValue
                        ? Math.Round(this.UnitPrice * orderAdjustment.Percentage.Value / 100, 2)
                        : orderAdjustment.Amount ?? 0;
                }

                this.UnitPrice = this.UnitBasePrice - this.UnitDiscount + this.UnitSurcharge;
            }

            foreach (SalesOrderItem featureItem in this.OrderedWithFeatures)
            {
                this.UnitBasePrice += featureItem.UnitBasePrice;
                this.UnitPrice     += featureItem.UnitPrice;
                this.UnitDiscount  += featureItem.UnitDiscount;
                this.UnitSurcharge += featureItem.UnitSurcharge;
            }

            this.UnitVat  = this.ExistVatRate ? this.UnitPrice * this.VatRate.Rate / 100 : 0;
            this.UnitIrpf = this.ExistIrpfRate ? this.UnitPrice * this.IrpfRate.Rate / 100 : 0;

            // Calculate Totals
            this.TotalBasePrice       = this.UnitBasePrice * this.QuantityOrdered;
            this.TotalDiscount        = this.UnitDiscount * this.QuantityOrdered;
            this.TotalSurcharge       = this.UnitSurcharge * this.QuantityOrdered;
            this.TotalOrderAdjustment = this.TotalSurcharge - this.TotalDiscount;

            if (this.TotalBasePrice > 0)
            {
                this.TotalDiscountAsPercentage  = Math.Round(this.TotalDiscount / this.TotalBasePrice * 100, 2);
                this.TotalSurchargeAsPercentage = Math.Round(this.TotalSurcharge / this.TotalBasePrice * 100, 2);
            }
            else
            {
                this.TotalDiscountAsPercentage  = 0;
                this.TotalSurchargeAsPercentage = 0;
            }

            this.TotalExVat  = this.UnitPrice * this.QuantityOrdered;
            this.TotalVat    = Math.Round(this.UnitVat * this.QuantityOrdered, 2);
            this.TotalIncVat = this.TotalExVat + this.TotalVat;
            this.TotalIrpf   = Math.Round(this.UnitIrpf * this.QuantityOrdered, 2);
            this.GrandTotal  = this.TotalIncVat - this.TotalIrpf;
        }
Example #10
0
        private static decimal BaseCatalogPrice(
            SalesOrder salesOrder,
            SalesInvoice salesInvoice,
            Product product,
            DateTime date)
        {
            var productBasePrice = 0M;
            var productDiscount  = 0M;
            var productSurcharge = 0M;

            var baseprices = new PriceComponent[0];

            if (product.ExistBasePrices)
            {
                baseprices = product.BasePrices;
            }

            var party = salesOrder != null ? salesOrder.ShipToCustomer : salesInvoice?.BillToCustomer;

            foreach (BasePrice priceComponent in baseprices)
            {
                if (priceComponent.FromDate <= date &&
                    (!priceComponent.ExistThroughDate || priceComponent.ThroughDate >= date))
                {
                    if (PriceComponents.BaseIsApplicable(new PriceComponents.IsApplicable
                    {
                        PriceComponent = priceComponent,
                        Customer = party,
                        Product = product,
                        SalesOrder = salesOrder,
                        SalesInvoice = salesInvoice,
                    }))
                    {
                        if (priceComponent.ExistPrice)
                        {
                            if (productBasePrice == 0 || priceComponent.Price < productBasePrice)
                            {
                                productBasePrice = priceComponent.Price ?? 0;
                            }
                        }
                    }
                }
            }

            var currentPriceComponents = new PriceComponents(product.Strategy.Session).CurrentPriceComponents(date);
            var priceComponents        = product.GetPriceComponents(currentPriceComponents);

            foreach (var priceComponent in priceComponents)
            {
                if (priceComponent.Strategy.Class.Equals(M.DiscountComponent.ObjectType) || priceComponent.Strategy.Class.Equals(M.SurchargeComponent.ObjectType))
                {
                    if (PriceComponents.BaseIsApplicable(new PriceComponents.IsApplicable
                    {
                        PriceComponent = priceComponent,
                        Customer = party,
                        Product = product,
                        SalesOrder = salesOrder,
                        SalesInvoice = salesInvoice,
                    }))
                    {
                        if (priceComponent.Strategy.Class.Equals(M.DiscountComponent.ObjectType))
                        {
                            var     discountComponent = (DiscountComponent)priceComponent;
                            decimal discount;

                            if (discountComponent.Price.HasValue)
                            {
                                discount         = discountComponent.Price.Value;
                                productDiscount += discount;
                            }
                            else
                            {
                                var percentage = discountComponent.Percentage ?? 0;
                                discount         = Rounder.RoundDecimal(productBasePrice * percentage / 100, 2);
                                productDiscount += discount;
                            }
                        }

                        if (priceComponent.Strategy.Class.Equals(M.SurchargeComponent.ObjectType))
                        {
                            var     surchargeComponent = (SurchargeComponent)priceComponent;
                            decimal surcharge;

                            if (surchargeComponent.Price.HasValue)
                            {
                                surcharge         = surchargeComponent.Price.Value;
                                productSurcharge += surcharge;
                            }
                            else
                            {
                                var percentage = surchargeComponent.Percentage ?? 0;
                                surcharge         = Rounder.RoundDecimal(productBasePrice * percentage / 100, 2);
                                productSurcharge += surcharge;
                            }
                        }
                    }
                }
            }

            return(productBasePrice - productDiscount + productSurcharge);
        }
Example #11
0
        public void CalculatePrices(
            IDerivation derivation,
            SalesInvoiceItem salesInvoiceItem,
            PriceComponent[] currentPriceComponents,
            decimal quantityOrdered,
            decimal totalBasePrice)
        {
            var salesInvoiceItemDerivedRoles = (SalesInvoiceItemDerivedRoles)salesInvoiceItem;

            var currentGenericOrProductOrFeaturePriceComponents = new List <PriceComponent>();

            if (salesInvoiceItem.ExistProduct)
            {
                currentGenericOrProductOrFeaturePriceComponents.AddRange(salesInvoiceItem.Product.GetPriceComponents(currentPriceComponents));
            }

            foreach (ProductFeature productFeature in salesInvoiceItem.ProductFeatures)
            {
                currentGenericOrProductOrFeaturePriceComponents.AddRange(productFeature.GetPriceComponents(salesInvoiceItem.Product, currentPriceComponents));
            }

            var priceComponents = currentGenericOrProductOrFeaturePriceComponents.Where(
                v => PriceComponents.BaseIsApplicable(
                    new PriceComponents.IsApplicable
            {
                PriceComponent  = v,
                Customer        = this.BillToCustomer,
                Product         = salesInvoiceItem.Product,
                SalesInvoice    = this,
                QuantityOrdered = quantityOrdered,
                ValueOrdered    = totalBasePrice,
            })).ToArray();

            var unitBasePrice = priceComponents.OfType <BasePrice>().Min(v => v.Price);

            // Calculate Unit Price (with Discounts and Surcharges)
            if (salesInvoiceItem.AssignedUnitPrice.HasValue)
            {
                salesInvoiceItemDerivedRoles.UnitBasePrice = unitBasePrice ?? salesInvoiceItem.AssignedUnitPrice.Value;
                salesInvoiceItemDerivedRoles.UnitDiscount  = 0;
                salesInvoiceItemDerivedRoles.UnitSurcharge = 0;
                salesInvoiceItemDerivedRoles.UnitPrice     = salesInvoiceItem.AssignedUnitPrice.Value;
            }
            else
            {
                if (!unitBasePrice.HasValue)
                {
                    derivation.Validation.AddError(salesInvoiceItem, M.SalesOrderItem.UnitBasePrice, "No BasePrice with a Price");
                    return;
                }

                salesInvoiceItemDerivedRoles.UnitBasePrice = unitBasePrice.Value;

                salesInvoiceItemDerivedRoles.UnitDiscount = priceComponents.OfType <DiscountComponent>().Sum(
                    v => v.Percentage.HasValue
                             ? Math.Round(salesInvoiceItem.UnitBasePrice * v.Percentage.Value / 100, 2)
                             : v.Price ?? 0);

                salesInvoiceItemDerivedRoles.UnitSurcharge = priceComponents.OfType <SurchargeComponent>().Sum(
                    v => v.Percentage.HasValue
                             ? Math.Round(salesInvoiceItem.UnitBasePrice * v.Percentage.Value / 100, 2)
                             : v.Price ?? 0);

                salesInvoiceItemDerivedRoles.UnitPrice = salesInvoiceItem.UnitBasePrice - salesInvoiceItem.UnitDiscount + salesInvoiceItem.UnitSurcharge;

                if (salesInvoiceItem.ExistDiscountAdjustment)
                {
                    salesInvoiceItemDerivedRoles.UnitDiscount += salesInvoiceItem.DiscountAdjustment.Percentage.HasValue ?
                                                                 Math.Round(salesInvoiceItem.UnitPrice * salesInvoiceItem.DiscountAdjustment.Percentage.Value / 100, 2) :
                                                                 salesInvoiceItem.DiscountAdjustment.Amount ?? 0;
                }

                if (salesInvoiceItem.ExistSurchargeAdjustment)
                {
                    salesInvoiceItemDerivedRoles.UnitSurcharge += salesInvoiceItem.SurchargeAdjustment.Percentage.HasValue ?
                                                                  Math.Round(salesInvoiceItem.UnitPrice * salesInvoiceItem.SurchargeAdjustment.Percentage.Value / 100, 2) :
                                                                  salesInvoiceItem.SurchargeAdjustment.Amount ?? 0;
                }

                salesInvoiceItemDerivedRoles.UnitPrice = salesInvoiceItem.UnitBasePrice - salesInvoiceItem.UnitDiscount + salesInvoiceItem.UnitSurcharge;
            }

            salesInvoiceItemDerivedRoles.UnitVat = salesInvoiceItem.ExistVatRate ? Math.Round(salesInvoiceItem.UnitPrice * salesInvoiceItem.VatRate.Rate / 100, 2) : 0;

            // Calculate Totals
            salesInvoiceItemDerivedRoles.TotalBasePrice = salesInvoiceItem.UnitBasePrice * salesInvoiceItem.Quantity;
            salesInvoiceItemDerivedRoles.TotalDiscount  = salesInvoiceItem.UnitDiscount * salesInvoiceItem.Quantity;
            salesInvoiceItemDerivedRoles.TotalSurcharge = salesInvoiceItem.UnitSurcharge * salesInvoiceItem.Quantity;

            if (salesInvoiceItem.TotalBasePrice > 0)
            {
                salesInvoiceItemDerivedRoles.TotalDiscountAsPercentage  = Math.Round(salesInvoiceItem.TotalDiscount / salesInvoiceItem.TotalBasePrice * 100, 2);
                salesInvoiceItemDerivedRoles.TotalSurchargeAsPercentage = Math.Round(salesInvoiceItem.TotalSurcharge / salesInvoiceItem.TotalBasePrice * 100, 2);
            }
            else
            {
                salesInvoiceItemDerivedRoles.TotalDiscountAsPercentage  = 0;
                salesInvoiceItemDerivedRoles.TotalSurchargeAsPercentage = 0;
            }

            salesInvoiceItemDerivedRoles.TotalExVat  = salesInvoiceItem.UnitPrice * salesInvoiceItem.Quantity;
            salesInvoiceItemDerivedRoles.TotalVat    = salesInvoiceItem.UnitVat * salesInvoiceItem.Quantity;
            salesInvoiceItemDerivedRoles.TotalIncVat = salesInvoiceItem.TotalExVat + salesInvoiceItem.TotalVat;
        }
Example #12
0
        public void BaseOnDerive(ObjectOnDerive method)
        {
            var derivation = method.Derivation;
            var session    = this.Session();

            var internalOrganisations = new Organisations(session).InternalOrganisations();

            if (!this.ExistBilledFrom && internalOrganisations.Count() == 1)
            {
                this.BilledFrom = internalOrganisations.First();
            }

            if (!this.ExistStore && this.ExistBilledFrom)
            {
                var stores = new Stores(session).Extent();
                stores.Filter.AddEquals(M.Store.InternalOrganisation, this.BilledFrom);
                this.Store = stores.FirstOrDefault();
            }

            if (!this.ExistInvoiceNumber && this.ExistStore)
            {
                this.InvoiceNumber = this.Store.NextTemporaryInvoiceNumber();
            }

            if (!this.ExistBilledFromContactMechanism && this.ExistBilledFrom)
            {
                this.BilledFromContactMechanism = this.BilledFrom.ExistBillingAddress ? this.BilledFrom.BillingAddress : this.BilledFrom.GeneralCorrespondence;
            }

            if (!this.ExistBillToContactMechanism && this.ExistBillToCustomer)
            {
                this.BillToContactMechanism = this.BillToCustomer.BillingAddress;
            }

            if (!this.ExistBillToEndCustomerContactMechanism && this.ExistBillToEndCustomer)
            {
                this.BillToEndCustomerContactMechanism = this.BillToEndCustomer.BillingAddress;
            }

            if (!this.ExistShipToEndCustomerAddress && this.ExistShipToEndCustomer)
            {
                this.ShipToEndCustomerAddress = this.ShipToEndCustomer.ShippingAddress;
            }

            if (!this.ExistShipToAddress && this.ExistShipToCustomer)
            {
                this.ShipToAddress = this.ShipToCustomer.ShippingAddress;
            }

            if (!this.ExistCurrency && this.ExistBilledFrom)
            {
                if (this.ExistBillToCustomer && (this.BillToCustomer.ExistPreferredCurrency || this.BillToCustomer.ExistLocale))
                {
                    this.Currency = this.BillToCustomer.ExistPreferredCurrency ? this.BillToCustomer.PreferredCurrency : this.BillToCustomer.Locale.Country.Currency;
                }
                else
                {
                    this.Currency = this.BilledFrom.ExistPreferredCurrency ?
                                    this.BilledFrom.PreferredCurrency :
                                    session.GetSingleton().DefaultLocale.Country.Currency;
                }
            }

            this.VatRegime   = this.VatRegime ?? this.BillToCustomer?.VatRegime;
            this.IsRepeating = this.ExistRepeatingSalesInvoiceWhereSource;

            foreach (SalesInvoiceItem salesInvoiceItem in this.SalesInvoiceItems)
            {
                foreach (OrderItemBilling orderItemBilling in salesInvoiceItem.OrderItemBillingsWhereInvoiceItem)
                {
                    if (orderItemBilling.OrderItem is SalesOrderItem salesOrderItem && !this.SalesOrders.Contains(salesOrderItem.SalesOrderWhereSalesOrderItem))
                    {
                        this.AddSalesOrder(salesOrderItem.SalesOrderWhereSalesOrderItem);
                    }
                }

                foreach (WorkEffortBilling workEffortBilling in salesInvoiceItem.WorkEffortBillingsWhereInvoiceItem)
                {
                    if (!this.WorkEfforts.Contains(workEffortBilling.WorkEffort))
                    {
                        this.AddWorkEffort(workEffortBilling.WorkEffort);
                    }
                }

                foreach (TimeEntryBilling timeEntryBilling in salesInvoiceItem.TimeEntryBillingsWhereInvoiceItem)
                {
                    if (!this.WorkEfforts.Contains(timeEntryBilling.TimeEntry.WorkEffort))
                    {
                        this.AddWorkEffort(timeEntryBilling.TimeEntry.WorkEffort);
                    }
                }
            }

            this.IsRepeatingInvoice = this.ExistRepeatingSalesInvoiceWhereSource && (!this.RepeatingSalesInvoiceWhereSource.ExistFinalExecutionDate || this.RepeatingSalesInvoiceWhereSource.FinalExecutionDate.Value.Date >= this.Strategy.Session.Now().Date);

            this.SalesInvoiceItems = this.SalesInvoiceItems.ToArray();

            if (this.ExistBillToCustomer && this.BillToCustomer.ExistLocale)
            {
                this.Locale = this.BillToCustomer.Locale;
            }
            else
            {
                this.Locale = session.GetSingleton().DefaultLocale;
            }

            if (this.ExistSalesTerms)
            {
                foreach (AgreementTerm term in this.SalesTerms)
                {
                    if (term.TermType.Equals(new InvoiceTermTypes(session).PaymentNetDays))
                    {
                        if (int.TryParse(term.TermValue, out var netDays))
                        {
                            this.PaymentDays = netDays;
                        }
                    }
                }
            }
            else if (this.BillToCustomer?.PaymentNetDays().HasValue == true)
            {
                this.PaymentDays = this.BillToCustomer.PaymentNetDays().Value;
            }
            else if (this.ExistStore && this.Store.ExistPaymentNetDays)
            {
                this.PaymentDays = this.Store.PaymentNetDays;
            }

            if (!this.ExistPaymentDays)
            {
                this.PaymentDays = 0;
            }

            if (this.ExistInvoiceDate)
            {
                this.DueDate = this.InvoiceDate.AddDays(this.PaymentNetDays);
            }

            var validInvoiceItems = this.SalesInvoiceItems.Where(v => v.IsValid).ToArray();

            this.ValidInvoiceItems = validInvoiceItems;

            var currentPriceComponents = new PriceComponents(this.Strategy.Session).CurrentPriceComponents(this.InvoiceDate);

            var quantityByProduct = validInvoiceItems
                                    .Where(v => v.ExistProduct)
                                    .GroupBy(v => v.Product)
                                    .ToDictionary(v => v.Key, v => v.Sum(w => w.Quantity));

            // First run to calculate price
            foreach (var salesInvoiceItem in validInvoiceItems)
            {
                decimal quantityOrdered = 0;

                if (salesInvoiceItem.ExistProduct)
                {
                    quantityByProduct.TryGetValue(salesInvoiceItem.Product, out quantityOrdered);
                }

                this.CalculatePrices(derivation, salesInvoiceItem, currentPriceComponents, quantityOrdered, 0);
            }

            var totalBasePriceByProduct = validInvoiceItems
                                          .Where(v => v.ExistProduct)
                                          .GroupBy(v => v.Product)
                                          .ToDictionary(v => v.Key, v => v.Sum(w => w.TotalBasePrice));

            // Second run to calculate price (because of order value break)
            foreach (var salesInvoiceItem in validInvoiceItems)
            {
                decimal quantityOrdered = 0;
                decimal totalBasePrice  = 0;

                if (salesInvoiceItem.ExistProduct)
                {
                    quantityByProduct.TryGetValue(salesInvoiceItem.Product, out quantityOrdered);
                    totalBasePriceByProduct.TryGetValue(salesInvoiceItem.Product, out totalBasePrice);
                }

                this.CalculatePrices(derivation, salesInvoiceItem, currentPriceComponents, quantityOrdered, totalBasePrice);
            }

            // Calculate Totals
            if (this.ExistSalesInvoiceItems)
            {
                this.TotalBasePrice           = 0;
                this.TotalDiscount            = 0;
                this.TotalSurcharge           = 0;
                this.TotalExVat               = 0;
                this.TotalFee                 = 0;
                this.TotalShippingAndHandling = 0;
                this.TotalVat                 = 0;
                this.TotalIncVat              = 0;
                this.TotalListPrice           = 0;

                foreach (var item in validInvoiceItems)
                {
                    this.TotalBasePrice += item.TotalBasePrice;
                    this.TotalDiscount  += item.TotalDiscount;
                    this.TotalSurcharge += item.TotalSurcharge;
                    this.TotalExVat     += item.TotalExVat;
                    this.TotalVat       += item.TotalVat;
                    this.TotalIncVat    += item.TotalIncVat;
                    this.TotalListPrice += item.UnitPrice;
                }

                if (this.ExistDiscountAdjustment)
                {
                    var discount = this.DiscountAdjustment.Percentage.HasValue ?
                                   Math.Round(this.TotalExVat * this.DiscountAdjustment.Percentage.Value / 100, 2) :
                                   this.DiscountAdjustment.Amount ?? 0;

                    this.TotalDiscount += discount;
                    this.TotalExVat    -= discount;

                    if (this.ExistVatRegime)
                    {
                        var vat = Math.Round(discount * this.VatRegime.VatRate.Rate / 100, 2);

                        this.TotalVat    -= vat;
                        this.TotalIncVat -= discount + vat;
                    }
                }

                if (this.ExistSurchargeAdjustment)
                {
                    var surcharge = this.SurchargeAdjustment.Percentage.HasValue ?
                                    Math.Round(this.TotalExVat * this.SurchargeAdjustment.Percentage.Value / 100, 2) :
                                    this.SurchargeAdjustment.Amount ?? 0;

                    this.TotalSurcharge += surcharge;
                    this.TotalExVat     += surcharge;

                    if (this.ExistVatRegime)
                    {
                        var vat = Math.Round(surcharge * this.VatRegime.VatRate.Rate / 100, 2);
                        this.TotalVat    += vat;
                        this.TotalIncVat += surcharge + vat;
                    }
                }

                if (this.ExistFee)
                {
                    var fee = this.Fee.Percentage.HasValue ?
                              Math.Round(this.TotalExVat * this.Fee.Percentage.Value / 100, 2) :
                              this.Fee.Amount ?? 0;

                    this.TotalFee   += fee;
                    this.TotalExVat += fee;

                    if (this.Fee.ExistVatRate)
                    {
                        var vat1 = Math.Round(fee * this.Fee.VatRate.Rate / 100, 2);
                        this.TotalVat    += vat1;
                        this.TotalIncVat += fee + vat1;
                    }
                }

                if (this.ExistShippingAndHandlingCharge)
                {
                    var shipping = this.ShippingAndHandlingCharge.Percentage.HasValue ?
                                   Math.Round(this.TotalExVat * this.ShippingAndHandlingCharge.Percentage.Value / 100, 2) :
                                   this.ShippingAndHandlingCharge.Amount ?? 0;

                    this.TotalShippingAndHandling += shipping;
                    this.TotalExVat += shipping;

                    if (this.ShippingAndHandlingCharge.ExistVatRate)
                    {
                        var vat2 = Math.Round(shipping * this.ShippingAndHandlingCharge.VatRate.Rate / 100, 2);
                        this.TotalVat    += vat2;
                        this.TotalIncVat += shipping + vat2;
                    }
                }

                //// Only take into account items for which there is data at the item level.
                //// Skip negative sales.
                decimal totalUnitBasePrice = 0;
                decimal totalListPrice     = 0;

                foreach (var item1 in validInvoiceItems)
                {
                    if (item1.TotalExVat > 0)
                    {
                        totalUnitBasePrice += item1.UnitBasePrice;
                        totalListPrice     += item1.UnitPrice;
                    }
                }
            }

            var salesInvoiceItemStates = new SalesInvoiceItemStates(derivation.Session);
            var salesInvoiceStates     = new SalesInvoiceStates(derivation.Session);

            foreach (var invoiceItem in validInvoiceItems)
            {
                if (!invoiceItem.SalesInvoiceItemState.Equals(salesInvoiceItemStates.ReadyForPosting))
                {
                    if (invoiceItem.AmountPaid == 0)
                    {
                        invoiceItem.SalesInvoiceItemState = salesInvoiceItemStates.NotPaid;
                    }
                    else if (invoiceItem.ExistAmountPaid && invoiceItem.AmountPaid > 0 && invoiceItem.AmountPaid >= invoiceItem.TotalIncVat)
                    {
                        invoiceItem.SalesInvoiceItemState = salesInvoiceItemStates.Paid;
                    }
                    else
                    {
                        invoiceItem.SalesInvoiceItemState = salesInvoiceItemStates.PartiallyPaid;
                    }
                }
            }

            if (validInvoiceItems.Any() && !this.SalesInvoiceState.Equals(salesInvoiceStates.ReadyForPosting))
            {
                if (this.SalesInvoiceItems.All(v => v.SalesInvoiceItemState.IsPaid))
                {
                    this.SalesInvoiceState = salesInvoiceStates.Paid;
                }
                else if (this.SalesInvoiceItems.All(v => v.SalesInvoiceItemState.IsNotPaid))
                {
                    this.SalesInvoiceState = salesInvoiceStates.NotPaid;
                }
                else
                {
                    this.SalesInvoiceState = salesInvoiceStates.PartiallyPaid;
                }
            }

            this.AmountPaid  = this.AdvancePayment;
            this.AmountPaid += this.PaymentApplicationsWhereInvoice.Sum(v => v.AmountApplied);

            //// Perhaps payments are recorded at the item level.
            if (this.AmountPaid == 0)
            {
                this.AmountPaid = this.InvoiceItems.Sum(v => v.AmountPaid);
            }

            // If receipts are not matched at invoice level
            if (this.AmountPaid > 0)
            {
                if (this.AmountPaid >= this.TotalIncVat)
                {
                    this.SalesInvoiceState = salesInvoiceStates.Paid;
                }
                else
                {
                    this.SalesInvoiceState = salesInvoiceStates.PartiallyPaid;
                }

                foreach (var invoiceItem in validInvoiceItems)
                {
                    if (!invoiceItem.SalesInvoiceItemState.Equals(salesInvoiceItemStates.CancelledByInvoice) &&
                        !invoiceItem.SalesInvoiceItemState.Equals(salesInvoiceItemStates.WrittenOff))
                    {
                        if (this.AmountPaid >= this.TotalIncVat)
                        {
                            invoiceItem.SalesInvoiceItemState = salesInvoiceItemStates.Paid;
                        }
                        else
                        {
                            invoiceItem.SalesInvoiceItemState = salesInvoiceItemStates.PartiallyPaid;
                        }
                    }
                }
            }

            if (this.ExistVatRegime && this.VatRegime.ExistVatClause)
            {
                this.DerivedVatClause = this.VatRegime.VatClause;
            }
            else
            {
                if (Equals(this.VatRegime, new VatRegimes(session).ServiceB2B))
                {
                    this.DerivedVatClause = new VatClauses(session).ServiceB2B;
                }
                else if (Equals(this.VatRegime, new VatRegimes(session).IntraCommunautair))
                {
                    this.DerivedVatClause = new VatClauses(session).Intracommunautair;
                }
            }

            this.DerivedVatClause = this.ExistAssignedVatClause ? this.AssignedVatClause : this.DerivedVatClause;

            this.BaseOnDeriveCustomers(derivation);

            if (this.ExistBillToCustomer && !this.BillToCustomer.BaseIsActiveCustomer(this.BilledFrom, this.InvoiceDate))
            {
                derivation.Validation.AddError(this, M.SalesInvoice.BillToCustomer, ErrorMessages.PartyIsNotACustomer);
            }

            if (this.ExistShipToCustomer && !this.ShipToCustomer.BaseIsActiveCustomer(this.BilledFrom, this.InvoiceDate))
            {
                derivation.Validation.AddError(this, M.SalesInvoice.ShipToCustomer, ErrorMessages.PartyIsNotACustomer);
            }

            this.PreviousBillToCustomer = this.BillToCustomer;
            this.PreviousShipToCustomer = this.ShipToCustomer;

            // this.BaseOnDeriveRevenues(derivation);
            var singleton = this.Session().GetSingleton();

            this.AddSecurityToken(new SecurityTokens(this.Session()).DefaultSecurityToken);

            this.Sync(this.Session());

            this.ResetPrintDocument();
        }
Example #13
0
        private static decimal AppsCatalogPrice(
            SalesOrder salesOrder,
            SalesInvoice salesInvoice,
            Product product,
            DateTime date)
        {
            var productBasePrice = 0M;
            var productDiscount  = 0M;
            var productSurcharge = 0M;

            var baseprices = new PriceComponent[0];

            if (product.ExistBasePrices)
            {
                baseprices = product.BasePrices;
            }

            var party = salesOrder != null ? salesOrder.ShipToCustomer : salesInvoice != null ? salesInvoice.BillToCustomer : null;

            foreach (BasePrice priceComponent in baseprices)
            {
                if (priceComponent.FromDate <= date &&
                    (!priceComponent.ExistThroughDate || priceComponent.ThroughDate >= date))
                {
                    if (PriceComponents.AppsIsEligible(new PriceComponents.IsEligibleParams
                    {
                        PriceComponent = priceComponent,
                        Customer = party,
                        Product = product,
                        SalesOrder = salesOrder,
                        SalesInvoice = salesInvoice,
                    }))
                    {
                        if (priceComponent.ExistPrice)
                        {
                            if (productBasePrice == 0 || priceComponent.Price < productBasePrice)
                            {
                                productBasePrice = priceComponent.Price ?? 0;
                            }
                        }
                    }
                }
            }

            var priceComponents = GetPriceComponents(product, date);

            var revenueBreakDiscount  = 0M;
            var revenueBreakSurcharge = 0M;

            foreach (var priceComponent in priceComponents)
            {
                if (priceComponent.Strategy.Class.Equals(M.DiscountComponent.ObjectType) || priceComponent.Strategy.Class.Equals(M.SurchargeComponent.ObjectType))
                {
                    if (PriceComponents.AppsIsEligible(new PriceComponents.IsEligibleParams
                    {
                        PriceComponent = priceComponent,
                        Customer = party,
                        Product = product,
                        SalesOrder = salesOrder,
                        SalesInvoice = salesInvoice,
                    }))
                    {
                        if (priceComponent.Strategy.Class.Equals(M.DiscountComponent.ObjectType))
                        {
                            var     discountComponent = (DiscountComponent)priceComponent;
                            decimal discount;

                            if (discountComponent.Price.HasValue)
                            {
                                discount         = discountComponent.Price.Value;
                                productDiscount += discount;
                            }
                            else
                            {
                                var percentage = discountComponent.Percentage.HasValue ? discountComponent.Percentage.Value : 0;
                                discount         = Math.Round((productBasePrice * percentage) / 100, 2);
                                productDiscount += discount;
                            }
                        }

                        if (priceComponent.Strategy.Class.Equals(M.SurchargeComponent.ObjectType))
                        {
                            var     surchargeComponent = (SurchargeComponent)priceComponent;
                            decimal surcharge;

                            if (surchargeComponent.Price.HasValue)
                            {
                                surcharge         = surchargeComponent.Price.Value;
                                productSurcharge += surcharge;
                            }
                            else
                            {
                                var percentage = surchargeComponent.Percentage.HasValue ? surchargeComponent.Percentage.Value : 0;
                                surcharge         = Math.Round((productBasePrice * percentage) / 100, 2);
                                productSurcharge += surcharge;
                            }
                        }
                    }
                }
            }

            return(productBasePrice - productDiscount + productSurcharge);
        }