Hi I am trying to extend the ARPaymentEntry graph so I can do some extra stuff when the user releases the payment.
I have extended the paymententry graph and copied the Release action over like so
public PXAction<ARPayment> release;
[PXUIField(DisplayName = "Release", MapEnableRights = PXCacheRights.Update, MapViewRights = PXCacheRights.Update)]
[PXProcessButton]
public virtual IEnumerable Release(PXAdapter adapter)
{
PXCache cache = Base.Document.Cache;
List<ARRegister> list = new List<ARRegister>();
foreach (ARPayment ardoc in adapter.Get<ARPayment>())
{
if (!(bool)ardoc.Hold)
{
cache.Update(ardoc);
list.Add(ardoc);
}
}
if (list.Count == 0)
{
throw new PXException(Messages.Document_Status_Invalid);
}
Base.Save.Press();
PXLongOperation.StartOperation(this, delegate()
{
if (SyncPaymentToRex(list))
{
ARDocumentRelease.ReleaseDoc(list, false);
}
});
return list;
}
If you look at the PXLongOperation I have a my own method I want to pass before it goes and releases the document.
Now this works for me but there is no user feedback on the screen (e.g. the controls arent disabled, no processing icon appears while its performing the operation etc) and also the screen doesnt reload, I have to manually reload the page before I can see the payment has been release etc
Can I get some help so I can get the page updating and reacting like it usually does on release but with my code in there as well?
Try this
public PXAction<ARPayment> release;
[PXUIField(DisplayName = "Release", MapEnableRights = PXCacheRights.Update, MapViewRights = PXCacheRights.Update)]
[PXProcessButton]
[PXOverride]
public virtual IEnumerable Release(PXAdapter adapter)
{
PXCache cache = Base.Document.Cache;
List<ARRegister> list = new List<ARRegister>();
foreach (ARPayment ardoc in adapter.Get<ARPayment>())
{
if (!(bool)ardoc.Hold)
{
cache.Update(ardoc);
list.Add(ardoc);
}
}
if (list.Count == 0)
{
throw new PXException(Messages.Document_Status_Invalid);
}
Base.Save.Press();
PXLongOperation.StartOperation(this.Base, delegate()
{
if (SyncPaymentToRex(list))
{
ARDocumentRelease.ReleaseDoc(list, false);
}
});
return list;
}
Related
I have a need to modify the behavior of the Create Sales Order action on the Opportunity screen.
I'm trying to find the best / least intrusive method possible. I have a snippet of the base code below.
The changes I need to make are relatively simple. I need to populate some custom fields that exist on new SO.
What's the best approach?
public PXAction<CROpportunity> createSalesOrder;
[PXUIField(DisplayName = Messages.CreateSalesOrder, MapEnableRights = PXCacheRights.Update, MapViewRights = PXCacheRights.Select)]
[PXButton(ImageKey = PX.Web.UI.Sprite.Main.DataEntry)]
public virtual IEnumerable CreateSalesOrder(PXAdapter adapter)
{
foreach (CROpportunity opportunity in adapter.Get<CROpportunity>())
{
Customer customer = (Customer)PXSelect<Customer, Where<Customer.bAccountID, Equal<Current<CROpportunity.bAccountID>>>>
.SelectSingleBound(this, new object[] { opportunity });
if (customer == null)
{
throw new PXException(Messages.ProspectNotCustomer);
}
if (CreateOrderParams.AskExtFullyValid((graph, viewName) => { }, DialogAnswerType.Positive))
{
Actions.PressSave();
PXLongOperation.StartOperation(this, delegate()
{
var grapph = PXGraph.CreateInstance<OpportunityMaint>();
grapph.Opportunity.Current = opportunity;
grapph.CreateOrderParams.Current = CreateOrderParams.Current;
grapph.DoCreateSalesOrder(CreateOrderParams.Current);
});
}
yield return opportunity;
}
}
protected virtual void DoCreateSalesOrder(CreateSalesOrderFilter param)
{
bool recalcAny = param.RecalculatePrices == true ||
param.RecalculateDiscounts == true ||
param.OverrideManualDiscounts == true ||
param.OverrideManualDocGroupDiscounts == true ||
param.OverrideManualPrices == true;
var opportunity = this.Opportunity.Current;
Customer customer = (Customer)PXSelect<Customer, Where<Customer.bAccountID, Equal<Current<CROpportunity.bAccountID>>>>.Select(this);
A simple override should accomplish your goal. Below is an example, which injects custom logic into the event handler SOOrder.RowInserted, during the Create Sales Order action. Then allow the action to finish normally. This approach extends the action with your custom logic, while retaining base code of the Action.
public class OpportunityMaint_Extension : PXGraphExtension<OpportunityMaint>
{
public delegate IEnumerable CreateSalesOrderDelegate(PXAdapter adapter);
[PXOverride]
public IEnumerable CreateSalesOrder(PXAdapter adapter, CreateSalesOrderDelegate baseMethod)
{
PXGraph.InstanceCreated.AddHandler<SOOrderEntry>((graph) =>
{
graph.RowInserted.AddHandler<SOOrder>((sender, e) =>
{
SOOrder order = (SOOrder)e.Row;
SOOrderExt orderExt = PXCache<SOOrder>.GetExtension<SOOrderExt>(order);
orderExt.UsrCustomOne = "Howdy"; //assign anything you want here
});
});
return baseMethod(adapter);
}
}
}
Hopefully this will be an easy question!
I've created a new report for the Acumatica Opportunity screen, and I'd like to add it to the screen itself. I've previously added a new report to the existing REPORTS dropdown, but I have not played with Automation Steps enough to create the REPORTS dropdown if it does not already exist.
Can someone provide instructions or point me in the direction of the appropriate documentation?
EDIT: So, what I'm running into is that the Opportunity doesn't have a Reports section already there to add to; I have to create it.
What I have so far gets a REPORTS button on the screen but it's not a dropdown and it doesn't appear to do anything.
public class OpportunityMaint_Extension : PXGraphExtension<OpportunityMaint>
{
#region Event Handlers
#endregion
#region Actions
public PXAction<CROpportunity> report;
[PXUIField(DisplayName = "Reports", MapEnableRights = PXCacheRights.Select)]
[PXButton(SpecialType = PXSpecialButtonType.Report)]
protected virtual IEnumerable Report(PXAdapter adapter,
[PXString(8, InputMask = "CC.CC.CC.CC")]
[PXStringList(new string[] { "IOCR6410" }, new string[] { "Quote" })]
string reportID)
{
List<CROpportunity> list = adapter.Get<CROpportunity>().ToList();
if (!String.IsNullOrEmpty(reportID))
{
Base.Save.Press();
int i = 0;
Dictionary<string, string> parameters = new Dictionary<string, string>();
foreach (CROpportunity opp in list)
{
if (reportID == "IOCR6410")
{
parameters["CROpportunity.OpportunityID" + i.ToString()] = opp.OpportunityID;
}
i++;
}
if (i > 0)
{
throw new PXReportRequiredException(parameters, reportID, string.Format("Report {0}", reportID));
}
}
return list;
}
#endregion
}
For this type of changes, it's better to not make changes in automation step(s), but follow the approach suggested in How to add report to Inventory Transfers dropdown menu for reports
Below is a slightly updated version of your code snippet, which should lead to the following result:
public class OpportunityMaint_Extension : PXGraphExtension<OpportunityMaint>
{
public override void Initialize()
{
Report.AddMenuAction(QuoteReport);
Report.MenuAutoOpen = true;
}
public PXAction<CROpportunity> Report;
[PXButton]
[PXUIField(DisplayName = "Reports", MapEnableRights = PXCacheRights.Select)]
protected void report()
{ }
public PXAction<CROpportunity> QuoteReport;
[PXButton]
[PXUIField(DisplayName = "Quote", MapEnableRights = PXCacheRights.Select)]
protected IEnumerable quoteReport(PXAdapter adapter)
{
var reportID = "IOCR6410";
List<CROpportunity> list = adapter.Get<CROpportunity>().ToList();
Base.Save.Press();
int i = 0;
Dictionary<string, string> parameters = new Dictionary<string, string>();
foreach (CROpportunity opp in list)
{
parameters["CROpportunity.OpportunityID" + i.ToString()] = opp.OpportunityID;
i++;
}
if (i > 0)
{
throw new PXReportRequiredException(parameters, reportID, string.Format("Report {0}", reportID));
}
return list;
}
}
I have to adjust how an action works. I know that I cannot adjust the code that runs the action itself, so is there any way to execute extra code when a specific action has been executed?
You simply declare the Action in your extension the same as the base action to "override"
Here is an example overriding the View Source Document action on GL Journal Entry:
public class JournalEntryMyExtension : PXGraphExtension<JournalEntry>
{
public PXAction<Batch> viewDocument;
[PXLookupButton]
[PXUIField(DisplayName = "View Source Document", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)]
public virtual IEnumerable ViewDocument(PXAdapter adapter)
{
// Logic Before Base Action
Base.viewDocument.Press(adapter);
// Logic After Base Action
return adapter.Get();
}
}
Here is the action direct from the base graph for comparison:
public PXAction<Batch> viewDocument;
[PXUIField(DisplayName = Messages.ViewSourceDocument, MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)]
[PXLookupButton()]
public virtual IEnumerable ViewDocument(PXAdapter adapter)
{
if (this.GLTranModuleBatNbr.Current != null)
{
GLTran tran = (GLTran) this.GLTranModuleBatNbr.Current;
OpenDocumentByTran(tran, BatchModule.Current);
}
return adapter.Get();
}
I want to execute some code (to change the shipment date) upon the 'Confirm Shipment' action on the Shipments screen (SO302000).
I was thinking that this would be the way to do it:
public class SOShipmentEntryExt : PXGraphExtension<SOShipmentEntry>
{
[PXOverride]
public virtual void ConfirmShipment(SOOrderEntry docgraph, SOShipment shiporder)
{
Base.ConfirmShipment(docgraph, shiporder);
//Add my code to do something here...
}
}
When I try this, I get a shipment counter error. Is there a better way to do this?
From a similar case:
How to add custom business logic to Acumatica framework's Actions?
public class SOShipmentEntryExt : PXGraphExtension<SOShipmentEntry>
{
public PXAction<SOShipment> action;
[PXButton]
[PXUIField(DisplayName = "Actions", MapEnableRights = PXCacheRights.Select)]
protected IEnumerable Action(PXAdapter adapter
,[PXIntList(new int[] { 1 }
,new string[] { "Confirm Shipment" })
,PXInt] int? actionID)
{
//actionID = 1 means the Confirm Shipment action was the one invoked
if (actionID == 1)
{
Base.Document.Current.ShipDate = Base.Accessinfo.BusinessDate;
Base.Document.Update(Base.Document.Current);
}
//calls the basic action that was invoked
return Base.action.Press(adapter);
}
}
When I do a custom logic before the APPROVE in requisition screen, it seems like the logic is triggered after. My code is as below.
public PXAction<RQRequisition> action;
[PXUIField(DisplayName = "Actions")]
[PXButton]
protected virtual IEnumerable Action(PXAdapter adapter,
[PXInt][PXIntList(new int[] { 1, 2 }, new string[] { "Approve", "Reject" })] int? actionID,
[PXBool]bool refresh,
[PXString]string actionName)
{
if (adapter.Menu == "Approve")
{
SIApprovalInfo.updateNextApprover(this.Base);
}
return Base.action.Press(adapter);
}
and I tried this action without calling the return Base.action.Press(adapter);
Sample code:
public PXAction<RQRequisition> action;
[PXUIField(DisplayName = "Actions")]
[PXButton]
protected virtual IEnumerable Action(PXAdapter adapter,
[PXInt][PXIntList(new int[] { 1, 2 }, new string[] { "Approve", "Reject" })]int? actionID,
[PXBool]bool refresh,
[PXString]string actionName)
{
if (adapter.Menu == "Approve")
{
SIApprovalInfo.updateNextApprover(this.Base);
}
return adapter.Get();
}
Still the document is getting approved somehow. So where exactly is this approval getting triggered? How can I add my custom logic before that action?
I suggest a workaround which would be the create your own action, add it to the menu and depending on your business logic, call the Approval. Here is the basic snippet you could use :
using PX.Data;
using System.Collections;
namespace PX.Objects.RQ
{
public class RQRequisitionEntry_Extension : PXGraphExtension<RQRequisitionEntry>
{
public override void Initialize()
{
Base.action.AddMenuAction(CustomApprove);
CustomApprove.SetEnabled(true);
}
public PXAction<RQRequisition> CustomApprove;
[PXButton]
[PXUIField(DisplayName = "Custom Approve")]
protected virtual IEnumerable customApprove(PXAdapter adapter)
{
PXCache cache = Base.Caches[typeof(RQRequisition)];
var requisition = Base.Document.Current;
if (Base.Approval.Approve(requisition))
{
requisition.Approved = true;
yield return Base.Document.Update(requisition); ;
}
else
{
throw new PXInvalidOperationException(PXLocalizer.Localize("Approval failed"));
}
}
}
}