/// <summary>
        /// Is there a valid relation between the accountcode and relation?
        /// </summary>
        /// <param name="accountCode"></param>
        /// <param name="relation"></param>
        /// <returns></returns>
        private static bool ValidRelation(PriceDiscAccountCode accountCode, string relation)
        {
            bool ok = true;

            if (!string.IsNullOrEmpty(relation) && (accountCode == PriceDiscAccountCode.All))
            {
                ok = false;
            }

            if (string.IsNullOrEmpty(relation) && (accountCode != PriceDiscAccountCode.All))
            {
                ok = false;
            }

            return(ok);
        }
Example #2
0
        /// <summary>
        /// Gets price agreement 'account relations' based on args and given account relation code
        /// </summary>
        /// <param name="args">Price agreement args (item, customer, etc.)</param>
        /// <param name="accountCode">Account relation code (customer/price group/all)</param>
        /// <returns>Returns customer if 'customer' code given, price groups if 'group' code given, otherwise empty</returns>
        public ReadOnlyCollection <string> GetAccountRelations(PriceDiscAccountCode accountCode)
        {
            ReadOnlyCollection <string> accountRelations = new ReadOnlyCollection <string>(new List <string> {
                String.Empty
            });

            if (accountCode == PriceDiscAccountCode.Table && !String.IsNullOrEmpty(this.CustomerId))
            {
                accountRelations = new ReadOnlyCollection <string>(new List <string> {
                    this.CustomerId
                });
            }
            else if (accountCode == PriceDiscAccountCode.GroupId && this.PriceGroups.Count > 0)
            {
                accountRelations = this.PriceGroups;
            }
            return(accountRelations);
        }
Example #3
0
        /// <summary>
        /// Returns if a certain relation is active for a price search.
        /// </summary>
        /// <param name="accountCode"></param>
        /// <param name="itemCode"></param>
        /// <returns></returns>
        public bool IsRelationActive(PriceDiscAccountCode accountCode, PriceDiscItemCode itemCode)
        {
            switch (accountCode)
            {
            case PriceDiscAccountCode.Table:
                switch (itemCode)
                {
                case PriceDiscItemCode.Table: return(this.salesPriceAccountItem);

                case PriceDiscItemCode.GroupId: return(false);

                case PriceDiscItemCode.All: return(false);
                }
                break;

            case PriceDiscAccountCode.GroupId:
                switch (itemCode)
                {
                case PriceDiscItemCode.Table: return(this.salesPriceGroupItem);

                case PriceDiscItemCode.GroupId: return(false);

                case PriceDiscItemCode.All: return(false);
                }
                break;

            case PriceDiscAccountCode.All:
                switch (itemCode)
                {
                case PriceDiscItemCode.Table: return(this.salesPriceAllItem);

                case PriceDiscItemCode.GroupId: return(false);

                case PriceDiscItemCode.All: return(false);
                }
                break;
            }

            return(false);
        }
        /// <summary>
        /// This function takes arguments (customer, item, currency, etc.) related to price (trade) agreement
        ///  as well as the set of currently enabled trade agreement types. It returns the best trade agreement
        ///  price for the given constraints.
        ///
        /// As in AX, the method searches for a price on the given item which has been given to a
        ///  customer, price group, or anyone (in given precedence order). If a price is found and marked as
        ///  SearchAgain=False, the search will terminate. Otherwise, search for lowest price will continue.
        ///
        /// To recap, the logic is that three searches are done for customer, price group, and all, each bracket
        ///   will return the lowest price it has for the constraints. If it has SearchAgain=True, then the search
        ///   for lowest price continues to the next bracket.
        /// </summary>
        /// <param name="args">Arguments for price agreement search</param>
        /// <param name="priceParameters">Set of enabled price agreement types</param>
        /// <returns>Most applicable price for the given price agreement constraints.</returns>
        public static PriceResult priceAgr(PriceAgreementArgs args, PriceParameters priceParameters)
        {
            PriceResult priceResult = new PriceResult(0M, PriceGroupIncludesTax.NotSpecified);

            for (int idx = 0; idx < 9; idx++)
            {
                // Enum values for ItemCode/AccountCode:  0=Table, 1=Group, 2=All
                PriceDiscItemCode    itemCode    = (PriceDiscItemCode)(idx % 3);    //Mod divsion
                PriceDiscAccountCode accountCode = (PriceDiscAccountCode)(idx / 3); //three possible item-/account-Codes, as described in the ENUMs.

                if (priceParameters.IsRelationActive(accountCode, itemCode))
                {
                    IList <string> accountRelations = args.GetAccountRelations(accountCode);
                    string         itemRelation     = args.GetItemRelation(itemCode);

                    if (accountRelations.All(a => ValidRelation(accountCode, a)) &&
                        (ValidRelation(itemCode, itemRelation)))
                    {
                        bool        searchAgain;
                        PriceResult currentPriceResult = GetBestPriceAgreement(FindPriceAgreements(args, itemCode, accountCode), out searchAgain);

                        if (priceResult.Price == 0M ||
                            (currentPriceResult.Price > 0M && currentPriceResult.Price < priceResult.Price))
                        {
                            priceResult = currentPriceResult;
                        }

                        if (!searchAgain)
                        {
                            break;
                        }
                    }
                }
            }

            return(priceResult);
        }
        /// <summary>
        /// Find and total all multiline discount trade agreements that match the given relations and quantity
        /// </summary>
        /// <param name="itemCode">The item code to search by (item group or all)</param>
        /// <param name="retailTransaction">The transaction context with Id and customer Id</param>
        /// <param name="discountRow">Current row in multiline discount working table. Will be populated and returned.</param>
        /// <param name="currencyCode">The currency code to filter by</param>
        /// <returns>Discount row populated with sums for all discounts found</returns>
        private DataRow GetMultiLineDiscountLine(PriceDiscItemCode itemCode, RetailTransaction retailTransaction, DataRow discountRow, string currencyCode)
        {
            PriceDiscType relation  = PriceDiscType.MultiLineDiscSales; //Sales multiline discount - 6
            Dimensions    dimension = (Dimensions)this.Application.BusinessLogic.Utility.CreateDimension();

            bool searchAgain = true;
            var  codes       = new PriceDiscAccountCode[] { PriceDiscAccountCode.Table, PriceDiscAccountCode.GroupId, PriceDiscAccountCode.All };

            foreach (var accountCode in codes)
            {
                // skip to next configuration if this one isn't enabled
                if (!DiscountParameters.Activation(relation, accountCode, itemCode))
                {
                    continue;
                }

                // get item relation based on item code
                string itemRelation = (itemCode == PriceDiscItemCode.GroupId) ? discountRow.Field <string>("MULTILINEGROUP") : string.Empty;
                itemRelation = itemRelation ?? String.Empty;

                // get customer relation based on account code
                string accountRelation = String.Empty;
                if (accountCode == PriceDiscAccountCode.Table)
                {
                    accountRelation = retailTransaction.Customer.CustomerId;
                }
                else if (accountCode == PriceDiscAccountCode.GroupId)
                {
                    accountRelation = retailTransaction.Customer.MultiLineDiscountGroup;
                }
                accountRelation = accountRelation ?? String.Empty;

                // if both relations are valid for the given item and account codes, look for trade agreements matching these relations
                if ((Discount.ValidRelation(accountCode, accountRelation)) &&
                    (Discount.ValidRelation(itemCode, itemRelation)))
                {
                    // get any active multiline discount trade agreement matching relations and quantity
                    decimal quantityAmount = discountRow.Field <decimal>("QUANTITY");
                    var     priceDiscTable = this.DiscountService.GetPriceDiscDataCached(
                        retailTransaction.TransactionId, relation, itemRelation, accountRelation, (int)itemCode, (int)accountCode, quantityAmount, currencyCode, dimension, false);

                    // compute running sum of discount values found
                    foreach (Discount.DiscountAgreementArgs row in priceDiscTable)
                    {
                        discountRow["PERCENT1"] = discountRow.Field <decimal>("PERCENT1");
                        discountRow["PERCENT1"] = discountRow.Field <decimal>("PERCENT1") + row.Percent1;
                        discountRow["PERCENT2"] = discountRow.Field <decimal>("PERCENT2") + row.Percent2;
                        discountRow["AMOUNT"]   = discountRow.Field <decimal>("AMOUNT") + row.Amount;
                        discountRow["MINQTY"]   = discountRow.Field <decimal>("MINQTY") + row.QuantityAmountFrom;

                        // stop search when we find a trade agreement set to not find next trade agreement
                        if (!row.SearchAgain)
                        {
                            searchAgain = false;
                        }
                    }
                }

                // stop search if we found a discount without "find next" marked
                if (!searchAgain)
                {
                    break;
                }
            }

            return(discountRow);
        }
Example #6
0
        public bool Activation(PriceDiscType relation, PriceDiscAccountCode accountCode, PriceDiscItemCode itemCode)
        {
            switch (accountCode)
            {
            case PriceDiscAccountCode.Table:
                switch (itemCode)
                {
                case PriceDiscItemCode.Table:
                    switch (relation)
                    {
                    case PriceDiscType.LineDiscSales: return(SalesLineAccountItem);

                    default: return(false);
                    }

                case PriceDiscItemCode.GroupId:
                    switch (relation)
                    {
                    case PriceDiscType.LineDiscSales: return(SalesLineAccountGroup);

                    case PriceDiscType.MultiLineDiscSales: return(SalesMultiLineAccountGroup);

                    default: return(false);
                    }

                case PriceDiscItemCode.All:
                    switch (relation)
                    {
                    case PriceDiscType.LineDiscSales: return(SalesLineAccountAll);

                    case PriceDiscType.MultiLineDiscSales: return(SalesMultiLineAccountAll);

                    case PriceDiscType.EndDiscSales: return(SalesEndAccountAll);

                    default: return(false);
                    }

                default:
                    NetTracer.Warning("DiscountParameters::Activation: itemCode is out of range: {0}", itemCode);
                    throw new ArgumentOutOfRangeException("itemCode");
                }

            case PriceDiscAccountCode.GroupId:
                switch (itemCode)
                {
                case PriceDiscItemCode.Table:
                    switch (relation)
                    {
                    case PriceDiscType.LineDiscSales: return(SalesLineGroupItem);

                    default: return(false);
                    }

                case PriceDiscItemCode.GroupId:
                    switch (relation)
                    {
                    case PriceDiscType.LineDiscSales: return(SalesLineGroupGroup);

                    case PriceDiscType.MultiLineDiscSales: return(SalesMultiLineGroupGroup);

                    default: return(false);
                    }

                case PriceDiscItemCode.All:
                    switch (relation)
                    {
                    case PriceDiscType.LineDiscSales: return(SalesLineGroupAll);

                    case PriceDiscType.MultiLineDiscSales: return(SalesMultiLineGroupAll);

                    case PriceDiscType.EndDiscSales: return(SalesEndGroupAll);

                    default: return(false);
                    }

                default:
                    NetTracer.Warning("DiscountParameters::Activation: itemCode is out of range: {0}", itemCode);
                    throw new ArgumentOutOfRangeException("itemCode");
                }

            case PriceDiscAccountCode.All:
                switch (itemCode)
                {
                case PriceDiscItemCode.Table:
                    switch (relation)
                    {
                    case PriceDiscType.LineDiscSales: return(SalesLineAllItem);

                    default: return(false);
                    }

                case PriceDiscItemCode.GroupId:
                    switch (relation)
                    {
                    case PriceDiscType.LineDiscSales: return(SalesLineAllGroup);

                    case PriceDiscType.MultiLineDiscSales: return(SalesMultiLineAllGroup);

                    default: return(false);
                    }

                case PriceDiscItemCode.All:
                    switch (relation)
                    {
                    case PriceDiscType.LineDiscSales: return(SalesLineAllAll);

                    case PriceDiscType.MultiLineDiscSales: return(SalesMultiLineAllAll);

                    case PriceDiscType.EndDiscSales: return(SalesEndAllAll);

                    default: return(false);
                    }

                default:
                    NetTracer.Warning("DiscountParameters::Activation: itemCode is out of range: {0}", itemCode);
                    throw new ArgumentOutOfRangeException("itemCode");
                }

            default:
                NetTracer.Warning("DiscountParameters::Activation: accountCode is out of range: {0}", accountCode);
                throw new ArgumentOutOfRangeException("accountCode");
            }
        }
        /// <summary>
        /// This function retrieves all possible price agreements for the given args (item, customer, currency, etc.),
        ///   item relation code (item/group/all), and account relation code (customer/price group/all).
        /// </summary>
        /// <param name="args">Arguments for price agreement search</param>
        /// <param name="itemCode">Item relation code to look for (in order: item/group/all)</param>
        /// <param name="accountCode">Account relation code to look for (in order: customer/price group/all)</param>
        /// <returns>Collection of applicable price agreements, sorted by price amount ascending</returns>
        static private IEnumerable <DE.PriceDiscTable> FindPriceAgreements(PriceAgreementArgs args, PriceDiscItemCode itemCode, PriceDiscAccountCode accountCode)
        {
            List <DE.PriceDiscTable> tradeAgreements = new List <DE.PriceDiscTable>();
            string         itemRelation     = args.GetItemRelation(itemCode);
            IList <string> accountRelations = args.GetAccountRelations(accountCode);
            string         unitId           = args.GetUnitId(itemCode);
            DateTime       today            = DateTime.Now.Date;

            SqlConnection connection = Price.InternalApplication.Settings.Database.Connection;
            string        dataAreaId = Price.InternalApplication.Settings.Database.DataAreaID;

            bool isIndia = Functions.CountryRegion == SupportedCountryRegion.IN;

            try
            {
                // convert account relations list to data-table for use as TVP in the query.
                string queryString = @"
                        SELECT 
                            ta.PRICEUNIT,
                            ta.ALLOCATEMARKUP,
                            ta.AMOUNT,
                            ta.SEARCHAGAIN"
                                     + (isIndia ? ", ta.MAXIMUMRETAILPRICE_IN" : string.Empty)
                                     + @"
                        FROM 
                            PRICEDISCTABLE ta LEFT JOIN 
                                INVENTDIM invdim ON ta.INVENTDIMID = invdim.INVENTDIMID AND ta.DATAAREAID = invdim.DATAAREAID
                        WHERE
                            ta.RELATION = 4
                            AND ta.ITEMCODE = @ITEMCODE
                            AND ta.ITEMRELATION = @ITEMRELATION
                            AND ta.ACCOUNTCODE = @ACCOUNTCODE
                    
                            -- USES Tvp: CREATE TYPE FINDPRICEAGREEMENT_ACCOUNTRELATIONS_TABLETYPE AS TABLE(ACCOUNTRELATION nvarchar(20) NOT NULL);
                            AND (ta.ACCOUNTRELATION) IN (SELECT ar.ACCOUNTRELATION FROM @ACCOUNTRELATIONS ar)

                            AND ta.CURRENCY = @CURRENCYCODE
                            AND ta.UNITID = @UNITID
                            AND ta.QUANTITYAMOUNTFROM <= abs(@QUANTITY)
                            AND (ta.QUANTITYAMOUNTTO >= abs(@QUANTITY) OR ta.QUANTITYAMOUNTTO = 0)
                            AND ta.DATAAREAID = @DATAAREAID
                            AND ((ta.FROMDATE <= @TODAY OR ta.FROMDATE <= @NODATE)
                                    AND (ta.TODATE >= @TODAY OR ta.TODATE <= @NODATE))
                            AND (invdim.INVENTCOLORID in (@COLORID, ''))
                            AND (invdim.INVENTSIZEID in (@SIZEID,''))
                            AND (invdim.INVENTSTYLEID in (@STYLEID, ''))
                            AND (invdim.CONFIGID in (@CONFIGID, ''))

                            --// ORDERBY CLAUSE MUST MATCH THAT IN AX TO ENSURE COMPATIBLE PRICING BEHAVIOR.
                            --// SEE THE CLASS PRICEDISC.FINDPRICEAGREEMENT() AND TABLE PRICEDISCTABLE.PRICEDISCIDX
                            order by ta.AMOUNT, ta.QUANTITYAMOUNTFROM, ta.QUANTITYAMOUNTTO, ta.FROMDATE";

                using (SqlCommand command = new SqlCommand(queryString, connection))
                {
                    command.Parameters.AddWithValue("@DATAAREAID", dataAreaId);
                    command.Parameters.AddWithValue("@ITEMCODE", itemCode);
                    command.Parameters.AddWithValue("@ITEMRELATION", itemRelation);
                    command.Parameters.AddWithValue("@ACCOUNTCODE", accountCode);
                    command.Parameters.AddWithValue("@UNITID", unitId);
                    command.Parameters.AddWithValue("@CURRENCYCODE", args.CurrencyCode);
                    command.Parameters.AddWithValue("@QUANTITY", args.Quantity);
                    command.Parameters.AddWithValue("@COLORID", (args.Dimensions.ColorId) ?? string.Empty);
                    command.Parameters.AddWithValue("@SIZEID", (args.Dimensions.SizeId) ?? string.Empty);
                    command.Parameters.AddWithValue("@STYLEID", (args.Dimensions.StyleId) ?? string.Empty);
                    command.Parameters.AddWithValue("@CONFIGID", (args.Dimensions.ConfigId) ?? string.Empty);
                    command.Parameters.AddWithValue("@TODAY", today);
                    command.Parameters.AddWithValue("@NODATE", DateTime.Parse("1900-01-01"));

                    // Fill out TVP for account relations list
                    using (DataTable accountRelationsTable = new DataTable())
                    {
                        accountRelationsTable.Columns.Add("ACCOUNTRELATION", typeof(string));
                        foreach (string relation in accountRelations)
                        {
                            accountRelationsTable.Rows.Add(relation);
                        }

                        SqlParameter param = command.Parameters.Add("@ACCOUNTRELATIONS", SqlDbType.Structured);
                        param.Direction = ParameterDirection.Input;
                        param.TypeName  = "FINDPRICEAGREEMENT_ACCOUNTRELATIONS_TABLETYPE";
                        param.Value     = accountRelationsTable;

                        if (connection.State != ConnectionState.Open)
                        {
                            connection.Open();
                        }

                        SqlDataReader reader = command.ExecuteReader();
                        while (reader.Read())
                        {
                            DE.PriceDiscTable pdt = new DE.PriceDiscTable()
                            {
                                PriceUnit            = reader.GetDecimal(reader.GetOrdinal("PRICEUNIT")),
                                ShouldAllocateMarkup = reader.GetInt32(reader.GetOrdinal("ALLOCATEMARKUP")),
                                Amount            = reader.GetDecimal(reader.GetOrdinal("AMOUNT")),
                                ShouldSearchAgain = reader.GetInt32(reader.GetOrdinal("SEARCHAGAIN")),
                                IndiaMRP          = (isIndia) ? reader.GetDecimal(reader.GetOrdinal("MAXIMUMRETAILPRICE_IN")) : Decimal.Zero
                            };
                            tradeAgreements.Add(pdt);
                        }
                    }
                }
            }
            finally
            {
                if (connection.State == ConnectionState.Open)
                {
                    connection.Close();
                }
            }

            return(tradeAgreements);
        }