Am trying to set a default customer for CS but am am getting an error "RevisionID' cannot be empty" please assist
protected void SOOrder_CustomerID_FieldUpdating(PXCache cache, PXFieldUpdatingEventArgs e)
{
SOOrder row = (SOOrder)e.Row;
if(row == null) return;
if (row.OrderType == "CS" || row.OrderType == "SS")
{
row.CustomerID = 7211;
}
else
{
row.CustomerID = null;
}
}
In your specific case FieldDefaulting event must be used instead of FieldUpdating to generate default value for the Customer ID field. According to the API Reference, in FieldDefaulting event handlers the new value must be assigned to the NewValue property of PXFieldDefaultingEventArgs and never directly to the DAC field:
protected void SOOrder_CustomerID_FieldDefaulting(PXCache cache, PXFieldDefaultingEventArgs e)
{
SOOrder row = (SOOrder)e.Row;
if(row == null) return;
if (row.OrderType == "CS" || row.OrderType == "SS")
{
e.NewValue = 7211;
}
}
Related
I want to display the 'Default Branch' (screenshot 1) from the Customers' (AR303000) Shipping tab to the Payment and Applications'(AR302000) 'LOAD DOCUMENTS' dialog box's, 'Company Branch'(screenshot 2)
Screenshot 1: Customers Default Branch
Screenshot 2: Load Document Company Branch (Payments and Applications)
The code I have does not seem to be displaying the Default Branch from the Customers Shipping tab to the Payments and Applications Company Branch.
Code snippet:
public class ARPaymentEntry_Extension : PXGraphExtension<PX.Objects.AR.ARPaymentEntry>
{
#region Event Handlers
protected void LoadOptions_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
{
var row = (LoadOptions)e.Row;
if (row == null)
{
return;
}
ARPayment aRPayment = Base.Document.Current;
if (aRPayment == null)
{
return;
}
Customer customer = PXSelect<Customer,
Where<Customer.bAccountID, Equal<Required<ARPayment.customerID>>>>
.Select(Base, aRPayment.CustomerID);
if (customer == null)
{
return;
}
Location location = PXSelect<Location,
Where<Location.bAccountID, Equal<Required<ARPayment.customerID>>,
And<Location.locationID, Equal<Required<Customer.defLocationID>>>>>
.Select(Base, aRPayment.CustomerID, customer.DefLocationID);
if (location == null)
{
return;
}
row.BranchID = location.CBranchID;
}
[PXMergeAttributes(Method = MergeMethod.Replace)]
// [OrganizationTree(typeof(organizationID), typeof(branchID), onlyActive: true)]
protected virtual void LoadOptions_OrgBAccountID_CacheAttached(PXCache cache)
{
}
I would move your code into FieldDefaulting for the LoadOptions, rather than row selected.
protected virtual void LoadOptions_OrgBAccountID_FieldDefaulting(PXCache cache, PXFieldDefaultingEventArgs args, PXFieldDefaulting del)
{
var row = (LoadOptions)e.Row;
if (row == null)
{
return;
}
ARPayment aRPayment = Base.Document.Current;
if (aRPayment == null)
{
return;
}
Customer customer = PXSelect<Customer,
Where<Customer.bAccountID, Equal<Required<ARPayment.customerID>>>>
.Select(Base, aRPayment.CustomerID);
if (customer == null)
{
return;
}
Location location = PXSelect<Location,
Where<Location.bAccountID, Equal<Required<ARPayment.customerID>>,
And<Location.locationID, Equal<Required<Customer.defLocationID>>>>>
.Select(Base, aRPayment.CustomerID, customer.DefLocationID);
if (location == null)
{
return;
}
//set the default with customers branch
args.NewValue = location.CBranchID;
}
I am using Acumatica 2020 R1. I have a custom text field on the PMQuote DAC. This field is in a custom tab on the project quotes screen. I want that field to always be editable. I put the following in my RowSelected event:
protected virtual void PMQuote_RowSelected(PXCache cache, PXRowSelectedEventArgs e, PXRowSelected del)
{
del?.Invoke(cache, e);
PMQuote quote = e.Row as PMQuote;
cache.AllowUpdate = true;
PXUIFieldAttribute.SetEnabled(cache, e.Row, true);
PXUIFieldAttribute.SetEnabled<PMQuoteExt.usrMyCustomField>(cache, e.Row, true);
}
This didn't work, so I also looked in the automation steps. I didn't see any automation steps available to modify.
I then looked at Workflow. I didn't see any workflows to edit either. I tried creating a new one based on the status field. I added the user field for each status and made sure disabled was unchecked. This didn't work either.
Any ideas on how I can get that field to be enabled regardless of the document status?
Thanks for your help!
AllowUpdate is called only on the cache object, add it for the data view, example:
Base.Quote.AllowUpdate = true
Also, try to extend PXQuoteMaintExt graph extension:
public class PMQuoteMaintExtExtension : PXGraphExtension<PMQuoteMaintExt, PMQuoteMaint>
{
protected virtual void PMQuote_RowSelected(PXCache sender, PXRowSelectedEventArgs e, PXRowSelected sel)
{
sel?.Invoke(sender, e);
}
}
It manages visibility with RowSelected event:
namespace PX.Objects.PM
{
public class PMQuoteMaintExt : PXGraphExtension<PMDiscount, PMQuoteMaint>
{
protected virtual void PMQuote_RowSelected(PXCache sender, PXRowSelectedEventArgs e, PXRowSelected sel)
{
sel?.Invoke(sender, e);
var row = e.Row as PMQuote;
if (row == null) return;
VisibilityHandler(sender, row);
}
private void VisibilityHandler(PXCache sender, PMQuote row)
{
CR.Standalone.CROpportunityRevision revisionInDb = PXSelectReadonly<CR.Standalone.CROpportunityRevision,
Where<CR.Standalone.CROpportunityRevision.noteID, Equal<Required<CR.Standalone.CROpportunityRevision.noteID>>>>.Select(Base, row.QuoteID).FirstOrDefault();
CR.Standalone.CROpportunity opportunityInDb = (revisionInDb == null) ? null : PXSelectReadonly<CR.Standalone.CROpportunity,
Where<CR.Standalone.CROpportunity.opportunityID, Equal<Required<CR.Standalone.CROpportunity.opportunityID>>>>.Select(Base, revisionInDb.OpportunityID).FirstOrDefault();
CR.Standalone.CROpportunity opportunity = PXSelect<CR.Standalone.CROpportunity,
Where<CR.Standalone.CROpportunity.opportunityID, Equal<Required<CR.Standalone.CROpportunity.opportunityID>>>>.Select(Base, row.OpportunityID).FirstOrDefault();
var opportunityIsClosed = opportunity?.IsActive == false;
bool allowUpdate = row.IsDisabled != true && !opportunityIsClosed && row.Status != PMQuoteStatusAttribute.Closed;
if (opportunityInDb?.OpportunityID == opportunity?.OpportunityID)
Base.Caches[typeof(PMQuote)].AllowUpdate = allowUpdate;
else
{
var quoteCache = Base.Caches[typeof(PMQuote)];
foreach (var field in quoteCache.Fields)
{
if (!quoteCache.Keys.Contains(field) &&
field != quoteCache.GetField(typeof(PMQuote.opportunityID)) &&
field != quoteCache.GetField(typeof(PMQuote.isPrimary)))
PXUIFieldAttribute.SetEnabled(sender, row, field, allowUpdate);
}
}
PXUIFieldAttribute.SetEnabled<PMQuote.bAccountID>(sender, row, row.OpportunityID == null);
Base.Caches[typeof(PMQuote)].AllowDelete = !opportunityIsClosed;
foreach (var type in new[]
{
typeof(CR.CROpportunityDiscountDetail),
typeof(CR.CROpportunityProducts),
typeof(CR.CRTaxTran),
typeof(CR.CRAddress),
typeof(CR.CRContact),
typeof(CR.CRPMTimeActivity),
typeof(PM.PMQuoteTask)
})
{
Base.Caches[type].AllowInsert = Base.Caches[type].AllowUpdate = Base.Caches[type].AllowDelete = allowUpdate;
}
Base.Caches[typeof(CopyQuoteFilter)].AllowUpdate = true;
Base.Caches[typeof(RecalcDiscountsParamFilter)].AllowUpdate = true;
Base.Actions[nameof(Base.Approval.Submit)]
.SetVisible(row.Status == PMQuoteStatusAttribute.Draft);
Base.actionsFolder
.SetVisible(nameof(Base.Approval.Approve), Base.Actions[nameof(Base.Approval.Approve)].GetVisible());
Base.actionsFolder
.SetVisible(nameof(Base.Approval.Reject), Base.Actions[nameof(Base.Approval.Reject)].GetVisible());
Base.Actions[nameof(EditQuote)]
.SetVisible(row.Status != PMQuoteStatusAttribute.Draft);
Base.Actions[nameof(Base.Approval.Submit)]
.SetEnabled(row.Status == PMQuoteStatusAttribute.Draft && !opportunityIsClosed);
Base.Actions[nameof(Base.Approval.Approve)]
.SetEnabled(row.Status == PMQuoteStatusAttribute.PendingApproval);
Base.Actions[nameof(Base.Approval.Reject)]
.SetEnabled(row.Status == PMQuoteStatusAttribute.PendingApproval);
Base.Actions[nameof(EditQuote)]
.SetEnabled(row.Status != PMQuoteStatusAttribute.Draft && row.Status != PMQuoteStatusAttribute.Closed);
Base.Actions[nameof(Base.CopyQuote)]
.SetEnabled(Base.Caches[typeof(PMQuote)].AllowInsert);
Base.Actions[nameof(PMDiscount.GraphRecalculateDiscountsAction)]
.SetEnabled((row.Status == PMQuoteStatusAttribute.Draft));
Base.Actions[nameof(Base.PrimaryQuote)].SetEnabled(!String.IsNullOrEmpty(row.OpportunityID) && row.IsPrimary == false && row.Status != PMQuoteStatusAttribute.Closed);
Base.Actions[nameof(Base.SendQuote)].SetEnabled(row.Status.IsIn<string>(PMQuoteStatusAttribute.Approved, PMQuoteStatusAttribute.Sent, PMQuoteStatusAttribute.Closed));
Base.Actions[nameof(Base.PrintQuote)].SetEnabled(true);
Base.convertToProject.SetEnabled( (row.OpportunityID == null || row.IsPrimary == true) && row.QuoteProjectID == null && row.Status.IsIn<string>(PMQuoteStatusAttribute.Approved, PMQuoteStatusAttribute.Sent));
PXUIFieldAttribute.SetEnabled<PMQuote.subject>(sender, row, true);
PXUIFieldAttribute.SetEnabled<PMQuote.status>(sender, row, false);
}
}
}
Some user fields were added to the ARInvoice entry screen (AR301000). The user fields exist in the Transactions grid. They are text fields only. There is no custom logic associated, and are bound to the DB table.
A user wishes to modify a particular user text field after the invoice is released - what would be the best way to achievee this?
Thankfully, the Transactions grid on the ARInvoces entry screen is never disabled by automation steps. All UI presentation logic for the Transactions grid is only defined within the ARInvoiceEntry BLC:
public class ARInvoiceEntry : ARDataEntryGraph<ARInvoiceEntry, ARInvoice>, PXImportAttribute.IPXPrepareItems
{
...
protected virtual void ARInvoice_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
{
ARInvoice doc = e.Row as ARInvoice;
if (doc == null) return;
...
bool shouldDisable = doc.Released == true
|| doc.Voided == true
|| doc.DocType == ARDocType.SmallCreditWO
|| doc.PendingPPD == true
|| doc.DocType == ARDocType.FinCharge && !IsProcessingMode && cache.GetStatus(doc) == PXEntryStatus.Inserted;
if (shouldDisable)
{
...
Transactions.Cache.AllowDelete = false;
Transactions.Cache.AllowUpdate = false;
Transactions.Cache.AllowInsert = false;
...
}
else
{
...
Transactions.Cache.AllowDelete = true;
Transactions.Cache.AllowUpdate = true;
Transactions.Cache.AllowInsert =
doc.CustomerID != null &&
doc.CustomerLocationID != null &&
doc.DocType != ARDocType.FinCharge &&
(doc.ProjectID != null || !PM.ProjectAttribute.IsPMVisible(this, BatchModule.AR));
...
}
...
}
protected virtual void ARTran_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
ARTran row = e.Row as ARTran;
if (row != null)
{
PXUIFieldAttribute.SetEnabled<ARTran.defScheduleID>(sender, row, row.TranType == ARInvoiceType.CreditMemo || row.TranType == ARInvoiceType.DebitMemo);
PXUIFieldAttribute.SetEnabled<ARTran.deferredCode>(sender, row, row.DefScheduleID == null);
}
}
...
}
To enable a custom field on AR301000 after the ARInvoice is released, you should complete the following relatevely simple steps:
Set AllowUpdate to true for the ARTran cache within the ARInvoice_RowSelected event handler
Invoke the static PXUIFieldAttribute.SetEnabled method to disable all ARTran fields, except the particular custom text field, the user wants to modify
The complete code snippet is listed below:
public class ARInvoiceEntryExt : PXGraphExtension<ARInvoiceEntry>
{
private bool IsDisabled(ARInvoice doc)
{
return doc.Released == true
|| doc.Voided == true
|| doc.DocType == ARDocType.SmallCreditWO
|| doc.PendingPPD == true
|| doc.DocType == ARDocType.FinCharge
&& !Base.IsProcessingMode
&& Base.Document.Cache.GetStatus(doc) == PXEntryStatus.Inserted;
}
public void ARInvoice_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
{
ARInvoice doc = e.Row as ARInvoice;
if (doc == null) return;
if (IsDisabled(doc))
{
Base.Transactions.Cache.AllowUpdate = true;
}
}
public void ARTran_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
var doc = Base.Document.Current;
ARTran row = e.Row as ARTran;
if (row != null && doc != null && IsDisabled(doc))
{
PXUIFieldAttribute.SetEnabled(sender, row, false);
PXUIFieldAttribute.SetEnabled<ARTranExt.usrCustomTextField>(sender, row, true);
}
}
}
I just created QT on 28-08-2016 and then change the businessDate to 30-08-2016 and copy it to SOOrder so after copy to SOOrder, I open the QT again and status will change to Completed. But RequestDate on SOLine didn't update.
protected void SOOrder_Status_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e)
{
var row = (SOOrder)e.Row;
SOOrderExt rowExt = PXCache<SOOrder>.GetExtension<SOOrderExt>(row);
if(row != null)
{
if(row.OrderType == "QT" && row.Status == "C")
{
rowExt.UsrRequestDate = Base.Accessinfo.BusinessDate;
}
else
{
rowExt.UsrRequestDate = row.OrderDate;
}
}
}
protected void SOOrder_OrderDate_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e)
{
var row = (SOOrder)e.Row;
SOOrderExt rowExt = PXCache<SOOrder>.GetExtension<SOOrderExt>(row);
if(row != null)
{
rowExt.UsrRequestDate = row.OrderDate;
}
}
I think your problem is in the wrong event. You have subscribed to SOLine_RowUpdated, which is event for details. But copy order function will update only document (SOOrder) and will not touch details. You should little bit rethink your flow.
But actually my questions is - why you do not what to use standard logic (as shown on image) that updates requested date for details?
protected void SOOrder_Status_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e)
{
var row = (SOOrder)e.Row;
SOOrderExt rowExt = PXCache<SOOrder>.GetExtension<SOOrderExt>(row);
if(row != null)
{
if(row.OrderType == "QT" && row.Status == "C")
{
rowExt.UsrRequestDate = Base.Accessinfo.BusinessDate;
}
else
{
rowExt.UsrRequestDate = row.OrderDate;
}
}
}
protected void SOOrder_OrderDate_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e)
{
var row = (SOOrder)e.Row;
SOOrderExt rowExt = PXCache<SOOrder>.GetExtension<SOOrderExt>(row);
if(row != null)
{
rowExt.UsrRequestDate = row.OrderDate;
}
}
After I customized the code below and I want to update SLA by AssignDateTime. But with the Severity changed then my SLA has changed to get datetime from createdDateTime also. I think it should have other event that need to customize.
protected virtual void CRCase_RowUpdated(PXCache cache, PXRowUpdatedEventArgs e, PXRowUpdated InvokeBaseHandler)
{
if (InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = e.Row as CRCase;
var oldRow = e.OldRow as CRCase;
CRCaseExt rowExt = PXCache<CRCase>.GetExtension<CRCaseExt>(row);
if (row == null || oldRow == null) return;
if (row.OwnerID == null)
{
row.AssignDate = null;
row.SLAETA = null;
}
else if (oldRow.OwnerID == null)
{
row.AssignDate = PXTimeZoneInfo.Now;
if (row == null || row.AssignDate == null) return;
if (row.ClassID != null && row.Severity != null)
{
var severity = (CRClassSeverityTime)PXSelect<CRClassSeverityTime,
Where<CRClassSeverityTime.caseClassID, Equal<Required<CRClassSeverityTime.caseClassID>>,
And<CRClassSeverityTime.severity, Equal<Required<CRClassSeverityTime.severity>>>>>
.Select(Base, row.ClassID, row.Severity);
if (severity != null && severity.TimeReaction != null)
{
row.SLAETA = ((DateTime)row.AssignDate).AddMinutes((int)severity.TimeReaction);
}
}
if (row.Severity != null && row.ContractID != null)
{
var template = (Contract)PXSelect<Contract, Where<Contract.contractID, Equal<Required<CRCase.contractID>>>>.Select(Base, row.ContractID);
if (template == null) return;
var sla = (ContractSLAMapping)PXSelect<ContractSLAMapping,
Where<ContractSLAMapping.severity, Equal<Required<CRCase.severity>>,
And<ContractSLAMapping.contractID, Equal<Required<CRCase.contractID>>>>>
.Select(Base, row.Severity, template.TemplateID);
if (sla != null && sla.Period != null)
{
row.SLAETA = ((DateTime)row.AssignDate).AddMinutes((int)sla.Period);
}
}
}
}
SLAETA field is decorated with PXFormulaAttribute to raise FieldDefaulting event every time change is made to one of the following fields:
CRCase.contractID
CRCase.severity
CRCase.caseClassID
public partial class CRCase : IBqlTable, IAssign, IAttributeSupport, IPXSelectable
{
...
#region SLAETA
public abstract class sLAETA : IBqlField { }
[PXDBDate(PreserveTime = true, DisplayMask = "g")]
[PXUIField(DisplayName = "SLA")]
[PXFormula(typeof(Default<CRCase.contractID, CRCase.severity, CRCase.caseClassID>))]
public virtual DateTime? SLAETA { get; set; }
#endregion
...
}
It’s a way better to only customize CRCase_SLAETA_FieldDefaulting handler in the CRCaseMaint BLC extension instead of implementing CRCase_RowUpdated:
public class CRCaseMaint : PXGraph<CRCaseMaint, CRCase>
{
...
protected virtual void CRCase_SLAETA_FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e)
{
CRCase row = e.Row as CRCase;
if (row == null || row.CreatedDateTime == null) return;
if (row.ClassID != null && row.Severity != null)
{
var severity = (CRClassSeverityTime)PXSelect<CRClassSeverityTime,
Where<CRClassSeverityTime.caseClassID, Equal<Required<CRClassSeverityTime.caseClassID>>,
And<CRClassSeverityTime.severity, Equal<Required<CRClassSeverityTime.severity>>>>>.
Select(this, row.ClassID, row.Severity);
if (severity != null && severity.TimeReaction != null)
{
e.NewValue = ((DateTime)row.CreatedDateTime).AddMinutes((int)severity.TimeReaction);
e.Cancel = true;
}
}
if (row.Severity != null && row.ContractID != null)
{
var template = (Contract)PXSelect<Contract, Where<Contract.contractID, Equal<Required<CRCase.contractID>>>>.Select(this, row.ContractID);
if (template == null) return;
var sla = (ContractSLAMapping)PXSelect<ContractSLAMapping,
Where<ContractSLAMapping.severity, Equal<Required<CRCase.severity>>,
And<ContractSLAMapping.contractID, Equal<Required<CRCase.contractID>>>>>.
Select(this, row.Severity, template.TemplateID);
if (sla != null && sla.Period != null)
{
e.NewValue = ((DateTime)row.CreatedDateTime).AddMinutes((int)sla.Period);
e.Cancel = true;
}
}
}
...
}
You can either use the FieldUpdated Event or in the row updated event you can look for the change of your field.
Eg: row.Severity != oldRow.Severity