public ActionResult <double> Get(DateTime dateJoined)
        {
            var engine   = new DiscountEngine();
            var discount = engine.GetDiscountAmount(dateJoined);

            return(discount);
        }
        public void TestOderWithFiveItems()
        {
            // Setup
            PurchaseOrder po = new PurchaseOrder();

            po.AddItem(new cItem("Woman-Socks-123-456", 15));
            po.AddItem(new cItem("Woman-Socks-123-456", 15));
            po.AddItem(new cItem("Woman-Socks-123-456", 15));
            po.AddItem(new cItem("Shirt-222-111", 5));
            po.AddItem(new cItem("Shirt-123-456", 5));

            DiscountEngine de = new DiscountEngine();

            // Exercise
            Double totalprice = de.Compute(ref po);

            // Verify
            Assert.AreEqual(35.00, totalprice);
            Assert.AreEqual(po.GetOrders()[0].discountScheme, "Bundling Discount");
            Assert.AreEqual(po.GetOrders()[0].discountAmt, 6.67);
            Assert.AreEqual(po.GetOrders()[1].discountScheme, "Bundling Discount");
            Assert.AreEqual(po.GetOrders()[1].discountAmt, 6.67);
            Assert.AreEqual(po.GetOrders()[2].discountScheme, "Bundling Discount");
            Assert.AreEqual(po.GetOrders()[2].discountAmt, 6.67);
            Assert.AreEqual(po.GetOrders()[3].discountScheme, "");
            Assert.AreEqual(po.GetOrders()[3].discountAmt, 0);
            Assert.AreEqual(po.GetOrders()[4].discountScheme, "");
            Assert.AreEqual(po.GetOrders()[4].discountAmt, 0);
        }
        /// <summary>Adds the discount to the specified document.</summary>
        public virtual void AddDiscount(PXCache sender, Document row)
        {
            Detail discount = Details.Select();

            if (discount == null)
            {
                discount = (Detail)Details.Cache.CreateInstance();
                discount.FreezeManualDisc = true;
                discount = (Detail)Details.Cache.Insert(discount);
            }

            Detail old_row = (Detail)Details.Cache.CreateCopy(discount);

            discount.CuryLineAmount = row.CuryDiscTot;
            discount.TaxCategoryID  = null;

            DefaultDiscountAccountAndSubAccount(discount);

            if (Details.Cache.GetStatus(discount) == PXEntryStatus.Notchanged)
            {
                Details.Cache.SetStatus(discount, PXEntryStatus.Updated);
            }

            discount.ManualDisc = true; //escape SOManualDiscMode.RowUpdated
            Details.Cache.RaiseRowUpdated(discount, old_row);

            decimal auotDocDisc = DiscountEngine.GetTotalGroupAndDocumentDiscount(Discounts);

            if (auotDocDisc == discount.CuryLineAmount)
            {
                discount.ManualDisc = false;
            }
        }
        /// <summary>The RowUpdated event handler for the <see cref="Detail" /> mapped cache extension. When the value of any field of <see cref="Detail"/> is changed, the discount is recalulated for the current line.</summary>
        /// <param name="e">Parameters of the event.</param>
        protected virtual void _(Events.RowUpdated <Detail> e)
        {
            if (!Details.Cache.ObjectsEqual <Detail.branchID>(e.Row, e.OldRow) && !Details.Cache.ObjectsEqual <Detail.inventoryID>(e.Row, e.OldRow) ||
                !Details.Cache.ObjectsEqual <Detail.siteID>(e.Row, e.OldRow) || !Details.Cache.ObjectsEqual <Detail.quantity>(e.Row, e.OldRow) ||
                !Details.Cache.ObjectsEqual <Detail.curyUnitPrice>(e.Row, e.OldRow) || !Details.Cache.ObjectsEqual <Detail.curyExtPrice>(e.Row, e.OldRow) ||
                !Details.Cache.ObjectsEqual <Detail.curyDiscAmt>(e.Row, e.OldRow) || !Details.Cache.ObjectsEqual <Detail.discPct>(e.Row, e.OldRow) ||
                !Details.Cache.ObjectsEqual <Detail.manualDisc>(e.Row, e.OldRow) || !Details.Cache.ObjectsEqual <Detail.discountID>(e.Row, e.OldRow))
            {
                if (e.Row.ManualDisc != true)
                {
                    if (e.OldRow.ManualDisc == true)//Manual Discount Unckecked
                    {
                        if (e.Row.IsFree == true)
                        {
                            ResetQtyOnFreeItem(e.Cache.Graph, e.Row);
                        }
                    }
                    if (e.Row.IsFree == true)
                    {
                        DiscountEngine <Detail> .ClearDiscount(e.Cache, e.Row);
                    }
                }
            }

            RecalculateDiscounts(e.Cache, e.Row, e.Row);
        }
        public void Execute_BasketIsNotProvided_ShouldThrowArgumentNullException(DiscountEngine discountEngine)
        {
            // # Arrange - Act
            Action action = () => discountEngine.Execute(null);

            // # Assert
            action.ShouldThrow <ArgumentNullException>();
        }
Beispiel #6
0
        protected virtual void ARDiscount_RowPersisted(PXCache sender, PXRowPersistedEventArgs e)
        {
            if ((e.Operation & PXDBOperation.Delete) == PXDBOperation.Delete && e.TranStatus == PXTranStatus.Open)
            {
                RemoveChildReferences((ARDiscount)e.Row);
            }

            DiscountEngine.GetDiscountTypes(true);
        }
Beispiel #7
0
        protected override void Location_RowPersisted(PXCache sender, PXRowPersistedEventArgs e)
        {
            base.Location_RowPersisted(sender, e);

            if (e.TranStatus == PXTranStatus.Completed)
            {
                DiscountEngine.RemoveFromCachedCustomerPriceClasses(((Location)e.Row).BAccountID);
            }
        }
        /// <summary>The RowDeleted event handler for the <see cref="Discount" /> mapped cache extension.</summary>
        /// <param name="e">Parameters of the event.</param>
        protected virtual void _(Events.RowDeleted <Discount> e)
        {
            if (e.ExternalCall && e.Row != null)
            {
                DiscountEngine <Detail> .UpdateDocumentDiscount(Details.Cache, Details, Discounts, Documents.Current.BranchID, Documents.Current.LocationID ?? 0, Documents.Current.DocumentDate, (e.Row.Type != null && e.Row.Type != DiscountType.Document));

                (Discounts.Cache as PXModelExtension <Discount>)?.UpdateExtensionMapping(e.Row);
            }
            RefreshTotalsAndFreeItems(Discounts.Cache);
        }
        /// <summary>The RowInserted event handler for the <see cref="Discount" /> mapped cache extension.</summary>
        /// <param name="e">Parameters of the event.</param>
        protected virtual void _(Events.RowInserted <Discount> e)
        {
            if (e.ExternalCall && e.Row?.DiscountID != null)
            {
                e.Row.IsManual = true;
                DiscountEngine <Detail> .InsertDocGroupDiscount(Details.Cache, Details, Discounts, e.Row, e.Row.DiscountID, null,
                                                                Documents.Current.BranchID, Documents.Current.LocationID ?? 0, Documents.Current.DocumentDate);

                RefreshTotalsAndFreeItems(Discounts.Cache);
                (Discounts.Cache as PXModelExtension <Discount>)?.UpdateExtensionMapping(e.Row);
            }
        }
        public void TestDiscountEngine_DiscountStrategiesCalled()
        {
            var discountEngine = new DiscountEngine(_marketingCampaignMock, _discountEngineStrategy);
            var item           = NSubstitute.Substitute.For <IItem>();

            discountEngine.ApplyDiscountFor(item);

            _discountEngineStrategy.Received(1).GetDiscountStrategy(item.Price, _marketingCampaignMock);
            var itemDiscountStrategy = _discountEngineStrategy.Received(1).GetDiscountStrategy(item.Price, _marketingCampaignMock);

            item.Received(1).ApplyStrategy(itemDiscountStrategy);
        }
        /// <summary>Recalculates discounts for the specified detail line.</summary>
        /// <param name="sender">A cache object.</param>
        /// <param name="line">The line for which the discounts should be recalculated.</param>
        protected virtual void RecalculateDiscounts(PXCache sender, Detail line, object source)
        {
            if (line.InventoryID != null && line.Quantity != null && line.CuryLineAmount != null && line.IsFree != true)
            {
                Document doc = Documents.Current;

                DiscountEngine <Detail> .SetDiscounts(Details.Cache,
                                                      Details, line, Discounts, doc.BranchID ?? 0, doc.LocationID ?? 0, doc.CuryID, doc.DocumentDate ?? Base.Accessinfo.BusinessDate);

                RecalculateTotalDiscount();
                RefreshFreeItemLines(sender);
            }
        }
        /// <summary>The FieldUpdated2 event handler for the <see cref="Detail.DiscountID" /> field. When the DiscountID field value is changed, the discount is recalculated for the current line.</summary>
        /// <param name="e">Parameters of the event.</param>
        protected virtual void _(Events.FieldUpdated <Detail, Detail.discountID> e)
        {
            var doc = Documents.Current;

            if (e.ExternalCall && e.Row != null)
            {
                DiscountEngine <Detail> .UpdateManualLineDiscount(Details.Cache,
                                                                  Details, e.Row, Discounts, doc.BranchID, doc.LocationID ?? 0,
                                                                  doc.DocumentDate ?? (new PXGraph()).Accessinfo.BusinessDate);

                Details.Cache.RaiseFieldUpdated <Detail.curyDiscAmt>(e.Row, 0);
            }
        }
 public virtual IEnumerable RecalculateDiscountsAction(PXAdapter adapter)
 {
     if (recalcdiscountsfilter.AskExt() == WebDialogResult.OK)
     {
         DiscountEngine <Detail> .RecalculatePricesAndDiscounts(
             Details.Cache,
             Details,
             Details.Current,
             Discounts,
             Documents.Current.LocationID ?? 0,
             Documents.Current.DocumentDate,
             recalcdiscountsfilter.Current);
     }
     return(adapter.Get());
 }
        public void Execute_BasketHasZeroProducts_ShouldNotApplyDiscount(DiscountEngine discountEngine)
        {
            // # Arrange
            Basket basket = new Basket
            {
                Products = new List <Product>()
            };

            Discount expectation = new Discount();

            // # Act
            Discount actual = discountEngine.Execute(basket);

            // # Assert
            actual.Amount.Should().Be(expectation.Amount);
        }
        /// <summary>The RowUpdated event handler for the <see cref="Document" /> mapped cache extension.</summary>
        /// <param name="e">Parameters of the event.</param>
        protected virtual void _(Events.RowUpdated <Document> e)
        {
            if (e.Row == null)
            {
                return;
            }

            if (e.ExternalCall && (!Documents.Cache.ObjectsEqual <Document.documentDate>(e.OldRow, e.Row)))
            {
                DiscountEngine <Detail> .AutoRecalculatePricesAndDiscounts(Details.Cache,
                                                                           Details, null, Discounts, e.Row.LocationID ?? 0, e.Row.DocumentDate ?? (new PXGraph()).Accessinfo.BusinessDate);
            }

            if (e.ExternalCall && Documents.Cache.GetStatus(e.Row) != PXEntryStatus.Deleted && !Documents.Cache.ObjectsEqual <Document.curyDiscTot>(e.OldRow, e.Row))
            {
                var current = Documents.Current;
                DiscountEngine <Detail> .CalculateDocumentDiscountRate(Details.Cache,
                                                                       Details, null, Discounts, current.CuryLineTotal ?? 0m, current.CuryDiscTot ?? 0m);
            }

            if (e.Row.CustomerID != null && e.Row.CuryDiscTot != null && e.Row.CuryDiscTot > 0 && e.Row.CuryLineTotal != null && e.Row.CuryMiscTot != null && (e.Row.CuryLineTotal > 0 || e.Row.CuryMiscTot > 0))
            {
                decimal discountLimit = DiscountEngine.GetDiscountLimit(Documents.Cache, e.Row.CustomerID);
                if (((e.Row.CuryLineTotal + e.Row.CuryMiscTot) / 100 * discountLimit) < e.Row.CuryDiscTot)
                {
                    PXUIFieldAttribute.SetWarning <Document.curyDiscTot>(Documents.Cache, e.Row, string.Format(Messages.DocDiscountExceedLimit, discountLimit));
                }
            }

            if (!Documents.Cache.ObjectsEqual <Document.locationID>(e.OldRow, e.Row) || !Documents.Cache.ObjectsEqual <Document.documentDate>(e.OldRow, e.Row))
            {
                RecalcDiscountsParamFilter recalcFilter =
                    new RecalcDiscountsParamFilter
                {
                    OverrideManualDiscounts = false,
                    OverrideManualPrices    = false,
                    RecalcDiscounts         = true,
                    RecalcUnitPrices        = true,
                    RecalcTarget            = RecalcDiscountsParamFilter.AllLines
                };
                DiscountEngine <Detail> .RecalculatePricesAndDiscounts(Details.Cache,
                                                                       Details, null, Discounts, e.Row.LocationID ?? 0, e.Row.DocumentDate ?? (new PXGraph()).Accessinfo.BusinessDate, recalcFilter);

                RecalculateTotalDiscount();
            }
        }
Beispiel #16
0
        public void CustomerWith_FiveYearsOrMoreLoyalty_RecievesFiftenPercentDiscount()
        {
            //Arrange
            var engine = new DiscountEngine();

            var customer = new Customer
            {
                LengthOfService = 5,
                Offer           = 100
            };

            //Act
            var discount = engine.CalculateDiscount(customer);

            //Assert
            Assert.Equal(15, discount);
        }
        public void TestOderWithOneItem()
        {
            // Setup
            PurchaseOrder po = new PurchaseOrder();

            po.AddItem(new cItem("Shirt-123-456", 5));

            DiscountEngine de = new DiscountEngine();

            // Exercise
            Double totalprice = de.Compute(ref po);

            // Verify
            Assert.AreEqual(4.75, totalprice);
            Assert.AreEqual(po.GetOrders()[0].discountScheme, "Progressive Discount");
            Assert.AreEqual(po.GetOrders()[0].discountAmt, 0.25);
        }
Beispiel #18
0
        public void TestForItem_10pReduction()
        {
            var item = new ItemBuilder()
                       .WithName("spaghetti")
                       .WithPrice(1500)
                       .Build();

            var aMonday = new AppDateTime
            {
                Now = new DateTime(2020, 7, 13)
            };

            var discountEngine = new DiscountEngine(new MarketingCampaign(aMonday));

            discountEngine.ApplyDiscountFor(item);

            Assert.True(item.Price.Equals(new Money(1500) % SecondTierDiscountStrategy.Percentage));
        }
Beispiel #19
0
        public void TestForItem_5pReduction()
        {
            var item = new ItemBuilder()
                       .WithName("sauce tomate")
                       .WithPrice(210)
                       .Build();

            var pairDateTime = new AppDateTime
            {
                Now = new DateTime(2020, 7, 9, 3, 57, 32, 12)
            };

            var discountEngine = new DiscountEngine(new MarketingCampaign(pairDateTime));

            discountEngine.ApplyDiscountFor(item);

            Assert.True(item.Price.Equals(new Money(210) % ThirdTierDiscountStrategy.Percentage));
        }
Beispiel #20
0
        public void TestForItem_NoReduction()
        {
            var item = new ItemBuilder()
                       .WithName("supplement d3")
                       .WithPrice(80)
                       .Build();

            var pairDateTime = new AppDateTime
            {
                Now = new DateTime(2020, 7, 13)
            };

            var discountEngine = new DiscountEngine(new MarketingCampaign(pairDateTime));

            discountEngine.ApplyDiscountFor(item);

            Assert.True(item.Price.Equals(new Money(80) % NoDiscountStrategy.Percentage));
        }
Beispiel #21
0
        public void TestForItem_15pReduction()
        {
            var item = new ItemBuilder()
                       .WithName("les pattes")
                       .WithPrice(100)
                       .Build();

            var aFriday = new AppDateTime
            {
                Now = new DateTime(2020, 7, 10)
            };

            var discountEngine = new DiscountEngine(new MarketingCampaign(aFriday));

            discountEngine.ApplyDiscountFor(item);

            Assert.True(item.Price.Equals(new Money(100) % FirstTierDiscountStrategy.Percentage));
        }
        public void Execute_WhenNoCampaignExist_ShouldNotApplyDiscount(DiscountEngine discountEngine)
        {
            // # Arrange
            Basket basket = new Basket
            {
                Products = new List <Product> {
                    new Product()
                }
            };

            Discount expectation = new Discount();

            // # Act
            Discount actual = discountEngine.Execute(basket);

            // # Assert
            actual.Amount.Should().Be(expectation.Amount); // # No mocks arranged at all. However, the expectation is satisfied. Dependency mocks arranged in Customization were injected to DiscountEngine.
        }
Beispiel #23
0
 private static AmountLineFields GetMapFor(object line, PXCache cache, Type lineType)
 {
     if (lineType == typeof(ARTran))
     {
         return(DiscountEngine.ApplyQuantityDiscountByBaseUOMForAR(cache.Graph)
                                 ? (AmountLineFields) new RetainedAmountLineFields <ARTran.baseQty, ARTran.curyUnitPrice, ARTran.curyExtPrice, ARTran.curyTranAmt, ARTran.curyRetainageAmt, ARTran.uOM, ARTran.origGroupDiscountRate, ARTran.origDocumentDiscountRate, ARTran.groupDiscountRate, ARTran.documentDiscountRate>(cache, line)
                                 : (AmountLineFields) new RetainedAmountLineFields <ARTran.qty, ARTran.curyUnitPrice, ARTran.curyExtPrice, ARTran.curyTranAmt, ARTran.curyRetainageAmt, ARTran.uOM, ARTran.origGroupDiscountRate, ARTran.origDocumentDiscountRate, ARTran.groupDiscountRate, ARTran.documentDiscountRate>(cache, line));
     }
     if (lineType == typeof(SOLine))
     {
         return(DiscountEngine.ApplyQuantityDiscountByBaseUOMForAR(cache.Graph)
                                 ? (AmountLineFields) new AmountLineFields <SOLine.baseOrderQty, SOLine.curyUnitPrice, SOLine.curyExtPrice, SOLine.curyLineAmt, SOLine.uOM, origGroupDiscountRate, origDocumentDiscountRate, SOLine.groupDiscountRate, SOLine.documentDiscountRate>(cache, line)
                                 : (AmountLineFields) new AmountLineFields <SOLine.orderQty, SOLine.curyUnitPrice, SOLine.curyExtPrice, SOLine.curyLineAmt, SOLine.uOM, origGroupDiscountRate, origDocumentDiscountRate, SOLine.groupDiscountRate, SOLine.documentDiscountRate>(cache, line));
     }
     if (lineType == typeof(SOShipLine))
     {
         return(DiscountEngine.ApplyQuantityDiscountByBaseUOMForAR(cache.Graph)
                                 ? (AmountLineFields) new AmountLineFields <SOShipLine.baseShippedQty, curyUnitCost, curyLineAmt, curyExtCost, SOShipLine.uOM, origGroupDiscountRate, origDocumentDiscountRate, groupDiscountRate, documentDiscountRate>(cache, line)
                                 : (AmountLineFields) new AmountLineFields <SOShipLine.shippedQty, curyUnitCost, curyLineAmt, curyExtCost, SOShipLine.uOM, origGroupDiscountRate, origDocumentDiscountRate, groupDiscountRate, documentDiscountRate>(cache, line));
     }
     if (lineType == typeof(APTran))
     {
         return(DiscountEngine.ApplyQuantityDiscountByBaseUOMForAP(cache.Graph)
                                 ? (AmountLineFields) new RetainedAmountLineFields <APTran.baseQty, APTran.curyUnitCost, APTran.curyLineAmt, APTran.curyTranAmt, APTran.curyRetainageAmt, APTran.uOM, APTran.origGroupDiscountRate, APTran.origDocumentDiscountRate, APTran.groupDiscountRate, APTran.documentDiscountRate>(cache, line)
                                 : (AmountLineFields) new RetainedAmountLineFields <APTran.qty, APTran.curyUnitCost, APTran.curyLineAmt, APTran.curyTranAmt, APTran.curyRetainageAmt, APTran.uOM, APTran.origGroupDiscountRate, APTran.origDocumentDiscountRate, APTran.groupDiscountRate, APTran.documentDiscountRate>(cache, line));
     }
     if (lineType == typeof(POLine))
     {
         return(DiscountEngine.ApplyQuantityDiscountByBaseUOMForAP(cache.Graph)
                                 ? (AmountLineFields) new RetainedAmountLineFields <POLine.baseOrderQty, POLine.curyUnitCost, POLine.curyLineAmt, POLine.curyExtCost, POLine.curyRetainageAmt, POLine.uOM, origGroupDiscountRate, origDocumentDiscountRate, POLine.groupDiscountRate, POLine.documentDiscountRate>(cache, line)
                                 : (AmountLineFields) new RetainedAmountLineFields <POLine.orderQty, POLine.curyUnitCost, POLine.curyLineAmt, POLine.curyExtCost, POLine.curyRetainageAmt, POLine.uOM, origGroupDiscountRate, origDocumentDiscountRate, POLine.groupDiscountRate, POLine.documentDiscountRate>(cache, line));
     }
     if (lineType == typeof(CROpportunityProducts))
     {
         return(new AmountLineFields <CROpportunityProducts.quantity, CROpportunityProducts.curyUnitPrice, CROpportunityProducts.curyExtPrice, CROpportunityProducts.curyAmount, CROpportunityProducts.uOM, origGroupDiscountRate, origDocumentDiscountRate, CROpportunityProducts.groupDiscountRate, CROpportunityProducts.documentDiscountRate, freezeManualDisc>(cache, line));
     }
     if (lineType == typeof(Detail))
     {
         return(new AmountLineFields <Detail.quantity, Detail.curyUnitPrice, Detail.curyExtPrice, Detail.curyLineAmount, Detail.uOM, Detail.origGroupDiscountRate, Detail.origDocumentDiscountRate, Detail.groupDiscountRate, Detail.documentDiscountRate>(cache, line));
     }
     return(DiscountEngine.ApplyQuantityDiscountByBaseUOMForAR(cache.Graph)
                         ? (AmountLineFields) new AmountLineFields <baseOrderQty, curyUnitPrice, curyExtPrice, curyLineAmt, uOM, origGroupDiscountRate, origDocumentDiscountRate, groupDiscountRate, documentDiscountRate>(cache, line)
                         : (AmountLineFields) new AmountLineFields <orderQty, curyUnitPrice, curyExtPrice, curyLineAmt, uOM, origGroupDiscountRate, origDocumentDiscountRate, groupDiscountRate, documentDiscountRate>(cache, line));
 }
Beispiel #24
0
        static void Main(string[] args)
        {
            var discountEngine = new DiscountEngine();

            while (true)
            {
                Console.WriteLine("Enter date joined:");
                var input = Console.ReadLine();

                DateTime dateJoined;
                if (!DateTime.TryParse(input, out dateJoined))
                {
                    Console.WriteLine($"Invalid input: '{input}'.");
                }

                var discount = discountEngine.GetDiscountAmount(dateJoined);
                Console.WriteLine($"Available discount: {discount * 100}%");
            }
        }
        public virtual void Persist(Action del)
        {
            if (Documents.Current != null && !Discounts.Any() && (Documents.Current.CuryDiscTot ?? 0m) != 0m)
            {
                AddDiscount(Documents.Cache, Documents.Current);
                DiscountEngine <Detail> .
                CalculateDocumentDiscountRate(
                    Details.Cache,
                    Details,
                    null,
                    Discounts,
                    Documents.Current.CuryLineTotal ?? 0m,
                    Documents.Current.CuryDiscTot ?? 0m);
            }

            DiscountEngine <Detail> .ValidateDiscountDetails(Discounts);

            del();
        }
        protected virtual void InsertDetails(ARInvoiceEntry invoiceEntry, ARInvoice scheduledInvoice, ARInvoice newInvoice)
        {
            foreach (ARTran originalLine in PXSelect <
                         ARTran,
                         Where <
                             ARTran.tranType, Equal <Required <ARTran.tranType> >,
                             And <ARTran.refNbr, Equal <Required <ARTran.refNbr> >,
                                  And <Where <
                                           ARTran.lineType, IsNull,
                                           Or <ARTran.lineType, NotEqual <SOLineType.discount> > > > > > >
                     .Select(invoiceEntry, scheduledInvoice.DocType, scheduledInvoice.RefNbr))
            {
                ARTran newLine = PXCache <ARTran> .CreateCopy(originalLine);

                newLine.RefNbr      = null;
                newLine.CuryInfoID  = null;
                newLine.ManualPrice = true;
                newLine.ManualDisc  = true;
                newLine.NoteID      = null;

                newLine = invoiceEntry.Transactions.Insert(newLine);

                PXNoteAttribute.CopyNoteAndFiles(Caches[typeof(ARTran)], originalLine, invoiceEntry.Transactions.Cache, newLine);
            }

            foreach (ARInvoiceDiscountDetail originalDiscountDetail in PXSelect <
                         ARInvoiceDiscountDetail,
                         Where <
                             ARInvoiceDiscountDetail.docType, Equal <Required <ARInvoiceDiscountDetail.docType> >,
                             And <ARInvoiceDiscountDetail.refNbr, Equal <Required <ARInvoiceDiscountDetail.refNbr> > > > >
                     .Select(invoiceEntry, scheduledInvoice.DocType, scheduledInvoice.RefNbr))
            {
                ARInvoiceDiscountDetail newDiscountDetail =
                    PXCache <ARInvoiceDiscountDetail> .CreateCopy(originalDiscountDetail);

                newDiscountDetail.RefNbr     = null;
                newDiscountDetail.CuryInfoID = null;
                newDiscountDetail.IsManual   = true;

                DiscountEngine <ARTran> .InsertDiscountDetail(invoiceEntry.ARDiscountDetails.Cache, invoiceEntry.ARDiscountDetails, newDiscountDetail);
            }
        }
        public void TestOderWithTwoItems()
        {
            // Setup
            PurchaseOrder po = new PurchaseOrder();

            po.AddItem(new cItem("Shirt-123-456", 5));
            po.AddItem(new cItem("Shirt-123-456", 5));

            DiscountEngine de = new DiscountEngine();

            // Exercise
            Double totalprice = de.Compute(ref po);

            // Verify
            Assert.AreEqual(8.50, totalprice);
            Assert.AreEqual(po.GetOrders()[0].discountScheme, "Multi-item Discount");
            Assert.AreEqual(po.GetOrders()[0].discountAmt, 0);
            Assert.AreEqual(po.GetOrders()[1].discountScheme, "Multi-item Discount");
            Assert.AreEqual(po.GetOrders()[1].discountAmt, 1.50);
        }
        /// <summary>The RowDeleted event handler for the <see cref="Detail" /> mapped cache extension. When a <see cref="Detail"/> line is deleted, the discount is recalulated.</summary>
        /// <param name="e">Parameters of the event.</param>
        protected virtual void _(Events.RowDeleted <Detail> e)
        {
            bool autoFreeItem = e.Row.ManualDisc != true && e.Row.IsFree == true;

            if (autoFreeItem)
            {
                return;
            }

            var documentCache = Documents.Cache;

            if (documentCache.Current != null && documentCache.GetStatus(documentCache.Current) != PXEntryStatus.Deleted)
            {
                var doc = Documents.Current;
                DiscountEngine <Detail> .RecalculateGroupAndDocumentDiscounts(Details.Cache,
                                                                              Details, null, Discounts, doc.BranchID, doc.LocationID ?? 0, doc.DocumentDate ?? (new PXGraph()).Accessinfo.BusinessDate);

                RecalculateTotalDiscount();
                RefreshFreeItemLines(Details.Cache);
            }
        }
        /// <summary>The RowUpdated event handler for the <see cref="Discount" /> mapped cache extension.</summary>
        /// <param name="e">Parameters of the event.</param>
        protected virtual void _(Events.RowUpdated <Discount> e)
        {
            if (e.ExternalCall && e.Row != null)
            {
                if (!Discounts.Cache.ObjectsEqual <Discount.skipDiscount>(e.Row, e.OldRow))
                {
                    DiscountEngine <Detail> .UpdateDocumentDiscount(Details.Cache, Details, Discounts, Documents.Current.BranchID, Documents.Current.LocationID ?? 0, Documents.Current.DocumentDate, e.Row.Type != DiscountType.Document);

                    RefreshTotalsAndFreeItems(Discounts.Cache);
                    (Discounts.Cache as PXModelExtension <Discount>)?.UpdateExtensionMapping(e.Row);
                }
                if (!Discounts.Cache.ObjectsEqual <Discount.discountID>(e.Row, e.OldRow) || !Discounts.Cache.ObjectsEqual <Discount.discountSequenceID>(e.Row, e.OldRow))
                {
                    e.Row.IsManual = true;
                    DiscountEngine <Detail> .InsertDocGroupDiscount(Details.Cache, Details, Discounts, e.Row, e.Row.DiscountID, Discounts.Cache.ObjectsEqual <SOOrderDiscountDetail.discountID>(e.Row, e.OldRow)?e.Row.DiscountSequenceID : null,
                                                                    Documents.Current.BranchID, Documents.Current.LocationID ?? 0, Documents.Current.DocumentDate);

                    RefreshTotalsAndFreeItems(Discounts.Cache);
                    (Discounts.Cache as PXModelExtension <Discount>)?.UpdateExtensionMapping(e.Row);
                }
            }
        }
 protected virtual void ARDiscount_RowPersisted(PXCache sender, PXRowPersistedEventArgs e)
 {
     DiscountEngine.GetDiscountTypes(true);
 }