0
votes

I have to show the price in a mask based on the alphabets setup in the configuration screen.

I am trying to write a custom attribute for the DAC field so that I can use the same in reports.

I have given the existing piece of code below. The function calls are working fine and i am using it for getting value, but I am not able to use it as DAC Attribute

#region PXPriceMaskAttribute
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.Class)]
public class PXPriceMaskAttribute : PXStringAttribute
{
    #region Ctor
    public PXPriceMaskAttribute()
         : base()
    {

    }
    #endregion
    #region Implementation
    /// <exclude/>
    /// 
    public static string GetPriceMask(PXGraph grp , decimal? val)
    {
        string _maskedstring = string.Empty;
        decimal value = val ?? 0m;
        int ivalue = Convert.ToInt32(Math.Floor(value));
        if (ivalue > 0)
        {
            MemoSetUp setUp = PXSelect<MemoSetUp>.Select(grp);
            char[] arr = ivalue.ToString().ToCharArray();
            char prevvalue = ' ';

            foreach (char cval in arr)
            {
                if (prevvalue != cval)
                {
                    prevvalue = cval;
                    switch (cval)
                    {
                        case '1': _maskedstring += setUp.N1; break;
                        case '2': _maskedstring += setUp.N2; break;
                        case '3': _maskedstring += setUp.N3; break;
                        case '4': _maskedstring += setUp.N4; break;
                        case '5': _maskedstring += setUp.N5; break;
                        case '6': _maskedstring += setUp.N6; break;
                        case '7': _maskedstring += setUp.N7; break;
                        case '8': _maskedstring += setUp.N8; break;
                        case '9': _maskedstring += setUp.N9; break;
                        case '0': _maskedstring += setUp.N0; break;
                        default: break;
                    }
                }
                else
                {
                    _maskedstring += setUp.Repeate;
                }
            }
        }
        return _maskedstring;
    }

    public static string GetPriceMask(MemoSetUp setUp, decimal? val)
    {
        string _maskedstring = string.Empty;
        decimal value = val ?? 0m;
        int ivalue = Convert.ToInt32(Math.Floor(value));
        if (ivalue > 0)
        {
            char[] arr = ivalue.ToString().ToCharArray();
            char prevvalue = ' ';

            foreach (char cval in arr)
            {
                if (prevvalue != cval)
                {
                    prevvalue = cval;
                    switch (cval)
                    {
                        case '1': _maskedstring += setUp.N1; break;
                        case '2': _maskedstring += setUp.N2; break;
                        case '3': _maskedstring += setUp.N3; break;
                        case '4': _maskedstring += setUp.N4; break;
                        case '5': _maskedstring += setUp.N5; break;
                        case '6': _maskedstring += setUp.N6; break;
                        case '7': _maskedstring += setUp.N7; break;
                        case '8': _maskedstring += setUp.N8; break;
                        case '9': _maskedstring += setUp.N9; break;
                        case '0': _maskedstring += setUp.N0; break;
                        default: break;
                    }
                }
                else
                {
                    _maskedstring += setUp.Repeate;
                }
            }
        }
        return _maskedstring;
    }
    public override void FieldUpdating(PXCache sender, PXFieldUpdatingEventArgs e)
    {

        if (e.NewValue != null && !e.Cancel)
        {
            decimal? value = Convert.ToDecimal(e.NewValue);
            e.NewValue = GetPriceMask(sender.Graph, value);
        }
    }
    /// <exclude/>
    public override void FieldSelecting(PXCache sender, PXFieldSelectingEventArgs e)
    {
        if (_AttributeLevel == PXAttributeLevel.Item || e.IsAltered)
        {
            e.ReturnState = PXStringState.CreateInstance(e.ReturnState, _Length, _IsUnicode, _FieldName, _IsKey, null, _InputMask, null, null, null, null);
        }
    }
    /// <exclude/>

    #endregion
}
#endregion

The above piece of code is not working. What is the best way to fix the issue.

Update

I have created a BQL Evaluator and attached to DAC and it always returns zero.

public class PriceRounding<PriceField> : BqlFormulaEvaluator<PriceField>, IBqlOperand
        where PriceField : IBqlField
    {
        public override object Evaluate(PXCache cache, object item,
                                        Dictionary<Type, object> pars)
        {
            PXFieldState fState = cache.GetStateExt<PriceField>(item) as PXFieldState;
            return GetSortOrderValueExt(Convert.ToDecimal(fState.Value));
        }

        public decimal GetSortOrderValueExt(decimal dVal)
        {
            dVal = Math.Round(dVal, 0);
            decimal divider = (dVal <= 5000) ? 25m : (dVal <= 10000) ? 50m : (dVal <= 100000) ? 100m : 500m;
            decimal reminder = dVal % divider;
            if (reminder > 0)
            {
                decimal diff = divider - reminder;
                dVal = dVal + diff;
            }
            return dVal;
        }
    }

The DAC field

#region RetailPrice
        public abstract class retailPrice : PX.Data.IBqlField
        {
        }
        protected decimal? _RetailPrice;
        [PXDBDecimal(2)]
        [PXUIField(DisplayName = "Retail Price")]
        [PXFormula(typeof(PriceRounding<InfoInventoryItemAttributeExtNV.retailPrice>))]
        public virtual decimal? RetailPrice
        {
            get
            {
                return this._RetailPrice;
            }
            set
            {
                this._RetailPrice = value;
            }
        }
        #endregion
2
What error do you get when using your custom PXPriceMaskAttribute? It will also help if you include in the question part of your DAC with definition of the field decorated with PXPriceMaskAttribute.RuslanDev

2 Answers

1
votes

Consider using custom BQL Function (derived from BqlFormulaEvaluator) – You can refer out-of-box custom BQL functions available in formula sub-folder of PX.Objects source code. Or you can refer KB article where such custom BQL function HierarchySorting is used.

0
votes

The following code works fine for me for custom rounding off than using BQL Formula Evaluator

#region PXDBPriceRoundingAttribute

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter | AttributeTargets.Class)]
    public class PXDBPriceRoundingAttribute : PXDBDecimalAttribute
    {
        #region Implementation
        public static decimal Round(decimal value)
        {
            value = Math.Round(value, 0);
            decimal divider = (value <= 5000) ? 25m : (value <= 10000) ? 50m : (value <= 100000) ? 100m : 500m;
            decimal reminder = value % divider;
            if (reminder > 0)
            {
                decimal diff = divider - reminder;
                value = value + diff;
            }

            return value;
        }

        public override void RowSelecting(PXCache sender, PXRowSelectingEventArgs e)
        {
            base.RowSelecting(sender, e);
            string name = _FieldName;
            if (sender.GetValue(e.Row, _FieldOrdinal) == null)
            {
                sender.SetValue(e.Row, _FieldOrdinal, 0m);
            }
            else
            {
                decimal? value = sender.GetValue(e.Row, _FieldOrdinal) as decimal?;
                decimal _roundedValue = Round(value ?? 0m);
                if ((value ?? 0m) != _roundedValue)
                {
                    sender.SetValue(e.Row, _FieldOrdinal, _roundedValue);
                }
            }

        }
        public override void FieldUpdating(PXCache sender, PXFieldUpdatingEventArgs e)
        {
            base.FieldUpdating(sender, e);
            decimal? value = sender.GetValue(e.Row, _FieldOrdinal) as decimal?;
            decimal _roundedValue = Round(value??0m);
            if((value??0m) != _roundedValue)
            {
                sender.SetValue(e.Row, _FieldOrdinal, _roundedValue);
            }
        }

        public void FieldUpdated(PXCache sender, PXFieldUpdatedEventArgs e)
        {
            decimal? value = sender.GetValue(e.Row, _FieldOrdinal) as decimal?;
            decimal _roundedValue = Round(value ?? 0m);
            if ((value ?? 0m) != _roundedValue)
            {
                sender.SetValue(e.Row, _FieldOrdinal, _roundedValue);
            }
        }

        public override void RowPersisting(PXCache sender, PXRowPersistingEventArgs e)
        {
            base.RowPersisting(sender, e);
            decimal? value = sender.GetValue(e.Row, _FieldOrdinal) as decimal?;
            decimal _roundedValue = Round(value ?? 0m);
            if ((value ?? 0m) != _roundedValue)
            {
                sender.SetValue(e.Row, _FieldOrdinal, _roundedValue);
            }
        }
        #endregion
        #region Initialization
        public override void CacheAttached(PXCache sender)
        {
            base.CacheAttached(sender);
            _Precision = CommonSetupDecPl.PrcCst;
        }
        #endregion
    }

    #endregion

Using In DAC

#region WholeSalesPrice
        public abstract class wholeSalesPrice : PX.Data.IBqlField
        {
        }
        protected decimal? _WholeSalesPrice;
        [PXDBPriceRoundingAttribute()]
        [PXUIField(DisplayName = "Wholesale Price")]

        public virtual decimal? WholeSalesPrice
        {
            get
            {
                return this._WholeSalesPrice;
            }
            set
            {
                this._WholeSalesPrice = value;
            }
        }
        #endregion