将客户属性复制到销售订单属性

时间:2018-01-18 08:29:22

标签: acumatica

在客户屏幕中,我根据客户类

配置了一些属性

enter image description here

我希望在为此客户筹集资金时将这些属性复制到销售订单中。示例屏幕如下:

enter image description here

销售订单属性网格将是只读的。 我知道如何添加标签项和网格。但我不确定如何为销售订单配置“属性”属性字段。我假设我可以依靠客户的“属性”定义?

我刚刚做了:

public class SOOrderExt : PXCacheExtension<PX.Objects.SO.SOOrder>
{
  #region Attributes

[CRAttributesField(typeof (Customer.customerClassID))]
public virtual string[] Attributes { get; set; }
  #endregion
}

答案视图:

namespace PX.Objects.SO
{
  public class SOOrderEntry_Extension:PXGraphExtension<SOOrderEntry>
  {
    [PXViewName("Answers")]
    public CRAttributeList<Customer>Answers;
  }
}

显示客户的属性......太棒了!但是他们需要根据销售订单进行保存。如果在线下,则客户的属性已更改。首次提出订单时,销售订单应复制原始客户的属性。那我该怎么做?谢谢!

1 个答案:

答案 0 :(得分:1)

问题是属性的引用是链接到客户而不是您需要的顺序(保存属性)。为此,我们需要在CRAttributeList类中编写自己的查询/关联调用。我创建了以下继承类,并通过将订单ref noteid与保存的答案相关联,使得属性能够坚持订单。 CRAttributeList类没有很好地覆盖,因此有很多复制的代码。您可以浏览源代码以查看完整的类并根据需要更新任何内容。我认为这可以简化,但现在它是一个有效的答案。

按照您的方式保持订单dac延期...

public class SOOrderExt : PXCacheExtension<PX.Objects.SO.SOOrder>
{
    [CRAttributesField(typeof (Customer.customerClassID))]
    public virtual string[] Attributes { get; set; }
}

替换视图以使用新类......

[PXViewName("Answers")]
public SalesCustomerAttributeList Answers;

新课程...... (更改SelectDelegate&amp; base SelectInternal)

public class SalesCustomerAttributeList : CRAttributeList<Customer>
{
    public SalesCustomerAttributeList(PXGraph graph) : base(graph)
    {
    }

    //Copy of private method from CRAttributeList
    protected string GetClassId(object row)
    {
        var classIdField = GetClassIdField(row);
        if (classIdField == null)
            return null;

        var entityCache = _Graph.Caches[row.GetType()];

        var classIdValue = entityCache.GetValueExt(row, classIdField.Name);

        return classIdValue?.ToString()?.Trim();
    }

    //Copy of private method from CRAttributeList
    protected Type GetClassIdField(object row)
    {
        if (row == null)
            return null;


        var fieldAttribute =
            _Graph.Caches[row.GetType()].GetAttributes(row, null)
                .OfType<CRAttributesFieldAttribute>()
                .FirstOrDefault();

        if (fieldAttribute == null)
            return null;

        return fieldAttribute.ClassIdField;
    }

    //Copy of private method from CRAttributeList
    protected Type GetEntityTypeFromAttribute(object row)
    {
        var classIdField = GetClassIdField(row);
        if (classIdField == null)
            return null;

        return classIdField.DeclaringType;
    }

    //Override to use desired query for sales order and customer/customer class related attributes
    protected override IEnumerable SelectDelegate()
    {
        return this.SelectInternal(
            (Customer)_Graph.Caches<Customer>()?.Current,
            (SOOrder)_Graph.Caches<SOOrder>()?.Current);
    }

    /// <summary>
    /// Find the customer default value based on the given answer
    /// </summary>
    protected bool TryGetCustomerAttributeValue(CSAnswers classAnswer, List<CSAnswers> customerAnswers, out string customerDefault)
    {
        customerDefault = null;
        if (classAnswer == null || customerAnswers == null)
        {
            return false;
        }

        foreach (var customerAttribute in customerAnswers)
        {
            if (customerAttribute.AttributeID != classAnswer.AttributeID)
            {
                continue;
            }
            customerDefault = customerAttribute.Value;
            return true;
        }

        return false;
    }

    protected List<CSAnswers> GetCustomerAttributes(Customer customerRow)
    {
        return PXSelect<CSAnswers, Where<CSAnswers.refNoteID, Equal<Required<CSAnswers.refNoteID>>>>
                .Select(_Graph, customerRow.NoteID).FirstTableItems.ToList();
    }

    //Override to use desired query for sales order and customer/customer class related attributes
    protected IEnumerable<CSAnswers> SelectInternal(Customer customerRow, SOOrder orderRow)
    {
        if (orderRow == null || customerRow == null)
        {
            yield break;
        }

        var noteId = GetNoteId(orderRow);

        if (!noteId.HasValue)
            yield break;

        var answerCache = _Graph.Caches[typeof(CSAnswers)];
        var orderCache = _Graph.Caches[orderRow.GetType()];

        List<CSAnswers> answerList;

        var status = orderCache.GetStatus(orderRow);

        if (status == PXEntryStatus.Inserted || status == PXEntryStatus.InsertedDeleted)
        {
            answerList = answerCache.Inserted.Cast<CSAnswers>().Where(x => x.RefNoteID == noteId).ToList();
        }
        else
        {
            answerList = PXSelect<CSAnswers, Where<CSAnswers.refNoteID, Equal<Required<CSAnswers.refNoteID>>>>
                .Select(_Graph, noteId).FirstTableItems.ToList();
        }

        var classId = GetClassId(customerRow);

        CRAttribute.ClassAttributeList classAttributeList = new CRAttribute.ClassAttributeList();
        if (classId != null)
        {
            classAttributeList = CRAttribute.EntityAttributes(GetEntityTypeFromAttribute(customerRow), classId);
        }

        //when coming from Import scenarios there might be attributes which don't belong to entity's current attribute class or the entity might not have any attribute class at all
        if (_Graph.IsImport && PXView.SortColumns.Any() && PXView.Searches.Any())
        {
            var columnIndex = Array.FindIndex(PXView.SortColumns,
                x => x.Equals(typeof(CSAnswers.attributeID).Name, StringComparison.OrdinalIgnoreCase));

            if (columnIndex >= 0 && columnIndex < PXView.Searches.Length)
            {
                var searchValue = PXView.Searches[columnIndex];

                if (searchValue != null)
                {
                    //searchValue can be either AttributeId or Description
                    var attributeDefinition = CRAttribute.Attributes[searchValue.ToString()] ??
                                            CRAttribute.AttributesByDescr[searchValue.ToString()];

                    if (attributeDefinition == null)
                    {
                        throw new PXSetPropertyException(PX.Objects.CR.Messages.AttributeNotValid);
                    }
                    //avoid duplicates

                    if (classAttributeList[attributeDefinition.ToString()] == null)
                    {
                        classAttributeList.Add(new CRAttribute.AttributeExt(attributeDefinition, null, false, true));
                    }
                }
            }
        }

        if (answerList.Count == 0 && classAttributeList.Count == 0)
        {
            yield break;
        }

        //attribute identifiers that are contained in CSAnswers cache/table but not in class attribute list
        List<string> attributeIdListAnswers =
            answerList.Select(x => x.AttributeID)
                .Except(classAttributeList.Select(x => x.ID))
                .Distinct()
                .ToList();

        //attribute identifiers that are contained in class attribute list but not in CSAnswers cache/table
        List<string> attributeIdListClass =
            classAttributeList.Select(x => x.ID)
                .Except(answerList.Select(x => x.AttributeID))
                .ToList();

        //attribute identifiers which belong to both lists
        List<string> attributeIdListIntersection =
            classAttributeList.Select(x => x.ID)
                .Intersect(answerList.Select(x => x.AttributeID))
                .Distinct()
                .ToList();


        var cacheIsDirty = answerCache.IsDirty;

        List<CSAnswers> output = new List<CSAnswers>();

        //attributes contained only in CSAnswers cache/table should be added "as is"
        output.AddRange(answerList.Where(x => attributeIdListAnswers.Contains(x.AttributeID)));

        var customerAnswers = GetCustomerAttributes(customerRow);

        //attributes contained only in class attribute list should be created and initialized with default value
        foreach (var attributeId in attributeIdListClass)
        {
            var classAttributeDefinition = classAttributeList[attributeId];

            if (PXSiteMap.IsPortal && classAttributeDefinition.IsInternal)
                continue;

            if (!classAttributeDefinition.IsActive)
                continue;

            CSAnswers answer = (CSAnswers)answerCache.CreateInstance();
            answer.AttributeID = classAttributeDefinition.ID;
            answer.RefNoteID = noteId;
            answer.Value = GetDefaultAnswerValue(classAttributeDefinition);
            if (TryGetCustomerAttributeValue(answer, customerAnswers, out var customerValue))
            {
                answer.Value = customerValue;
            }

            if (classAttributeDefinition.ControlType == CSAttribute.CheckBox)
            {
                bool value;
                if (bool.TryParse(answer.Value, out value))
                    answer.Value = Convert.ToInt32(value).ToString(CultureInfo.InvariantCulture);
                else if (answer.Value == null)
                    answer.Value = 0.ToString();
            }

            answer.IsRequired = classAttributeDefinition.Required;
            answer = (CSAnswers)(answerCache.Insert(answer) ?? answerCache.Locate(answer));
            output.Add(answer);
        }

        //attributes belonging to both lists should be selected from CSAnswers cache/table with and additional IsRequired check against class definition
        foreach (CSAnswers answer in answerList.Where(x => attributeIdListIntersection.Contains(x.AttributeID)).ToList())
        {
            var classAttributeDefinition = classAttributeList[answer.AttributeID];

            if (PXSiteMap.IsPortal && classAttributeDefinition.IsInternal)
                continue;

            if (!classAttributeDefinition.IsActive)
                continue;

            if (answer.Value == null && classAttributeDefinition.ControlType == CSAttribute.CheckBox)
                answer.Value = bool.FalseString;

            if (answer.IsRequired == null || classAttributeDefinition.Required != answer.IsRequired)
            {
                answer.IsRequired = classAttributeDefinition.Required;

                var fieldState = View.Cache.GetValueExt<CSAnswers.isRequired>(answer) as PXFieldState;
                var fieldValue = fieldState != null && ((bool?)fieldState.Value).GetValueOrDefault();

                answer.IsRequired = classAttributeDefinition.Required || fieldValue;
            }

            output.Add(answer);
        }

        answerCache.IsDirty = cacheIsDirty;

        output =
            output.OrderBy(
                x =>
                    classAttributeList.Contains(x.AttributeID)
                        ? classAttributeList.IndexOf(x.AttributeID)
                        : (x.Order ?? 0))
                .ThenBy(x => x.AttributeID)
                .ToList();

        short attributeOrder = 0;

        foreach (CSAnswers answer in output)
        {
            answer.Order = attributeOrder++;
            yield return answer;
        }
    }
}

有关“属性”选项卡的页面条目的示例,您可以查看“客户”页面 - “属性”选项卡。我复制了这个标签,用于测试这个答案。