I have the following code to override the "Email Purchase Order" action on the PO entry screen.
The code compiles and the message is displayed, but after selecting Yes Or No the message is displayed again and again until I click the X. Any idea what would cause that?
public delegate IEnumerable NotificationDelegate(PXAdapter adapter, String notificationCD);
[PXOverride]
public IEnumerable Notification(PXAdapter adapter, String notificationCD, NotificationDelegate baseMethod)
{
if(Base.Document.Ask("Are you sure you want to Email the PO?", MessageButtons.YesNo)
!= WebDialogResult.Yes) return adapter.Get();
return baseMethod(adapter, notificationCD);
}
UPDATE:
Here's my latest attempt, that's still not working. The code compiles, but I never get the message box. Added a trace message to confirm it's hitting the code:
public PXAction<POOrder> notification;
[PXUIField(DisplayName = "Notifications", Visible = false)]
[PXButton(ImageKey = PX.Web.UI.Sprite.Main.DataEntryF)]
protected virtual IEnumerable Notification(PXAdapter adapter,
[PXString] string notificationCD)
{
PXTrace.WriteInformation("Reached Notification Action - Notification CD = " + notificationCD + '|');
if (notificationCD == "PURCHASE ORDER")
{
PXTrace.WriteInformation("Notification Action - If reached");
if(Base.Document.Ask("Are you sure you want to Email the PO?", MessageButtons.YesNo)
!= WebDialogResult.Yes) return adapter.Get();
}
return Base.notification.Press(adapter);
}
This happens if the message dialog request is in a place where the framework cant handle a message box.
Try overriding the action itself (21R1):
public PXAction<POOrder> emailPurchaseOrder;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Email Purchase Order", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)]
public virtual IEnumerable EmailPurchaseOrder(
PXAdapter adapter,
[PXString]
string notificationCD = null)
{
if(Base.Document.Ask("Are you sure you want to Email the PO?", MessageButtons.YesNo)
!= WebDialogResult.Yes) return adapter.Get();
return Base.emailPurchaseOrder.Press(adapter);
}
Or for 20R2
public PXAction<POOrder> notification;
[PXUIField(DisplayName = "Notifications", Visible = false)]
[PXButton(ImageKey = PX.Web.UI.Sprite.Main.DataEntryF)]
protected virtual IEnumerable Notification(PXAdapter adapter,
[PXString] string notificationCD)
{
if (notificationCD == "EM")
{
if(Base.Document.Ask("Are you sure you want to Email the PO?", MessageButtons.YesNo)
!= WebDialogResult.Yes) return adapter.Get();
}
return Base.emailPurchaseOrder.Press(adapter);
}
Related
I would like to see the code behind the grid actions button. let say buttons in the grid sectoin of Bills and Adjustment Screen are marked with orange boxes.
I would like to see how the code is configured behind the buttons.
Where can I find the file or code in the Acumatica website folder?
Especially I want code behind the "ADD SUBCONTRACT" button.
The code for the buttons/actions looks like it comes from the construction edition found in PX.Objects.CN.Subcontracts.AP.GraphExtensions.ApInvoiceEntryAddSubcontractsExtension (PX.Objects.CN.dll)
Snippets of related code:
[PXButton]
[PXUIField(DisplayName = "Add Subcontracts", FieldClass = "DISTR", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)]
public virtual IEnumerable addSubcontracts(PXAdapter adapter)
{
this.Base.checkTaxCalcMode();
if (!this.ShouldAddSubcontracts())
return adapter.Get();
this.Base.updateTaxCalcMode();
return this.addSubcontract(adapter);
}
[PXButton]
[PXUIField(DisplayName = "Add Subcontract", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select, Visible = false)]
public virtual IEnumerable addSubcontract(PXAdapter adapter)
{
return ApInvoiceEntryAddSubcontractsExtension.AddLines(new Func<PXAdapter, IEnumerable>(this.Base1.AddPOOrder2), adapter);
}
[PXButton]
[PXUIField(DisplayName = "Add Subcontract Line", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)]
public virtual IEnumerable addSubcontractLines(PXAdapter adapter)
{
this.Base.checkTaxCalcMode();
return this.ShouldAddSubcontractLines() ? this.addSubcontractLine(adapter) : adapter.Get();
}
[PXButton]
[PXUIField(DisplayName = "Add Subcontract Line", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select, Visible = false)]
public virtual IEnumerable addSubcontractLine(PXAdapter adapter)
{
return ApInvoiceEntryAddSubcontractsExtension.AddLines(new Func<PXAdapter, IEnumerable>(this.Base2.AddPOOrderLine2), adapter);
}
private static IEnumerable AddLines(
Func<PXAdapter, IEnumerable> addLine,
PXAdapter adapter)
{
try
{
return addLine(adapter);
}
catch (PXException ex) when (ex.MessageNoPrefix == "Failed to add one or more lines from the PO order. Please check the Trace for details.")
{
throw new Exception("SC Error: Failed to add one or more lines from the Subcontract. Please check the Trace for details.");
}
}
Looking at this code we can see it will use AddPOOrder2 from PX.Objects.PO.GraphExtensions.APInvoiceSmartPanel.AddPOOrderExtension from PX.Objects.dll
This code is found in the source availabine in Acumatica as:
[PXUIField(DisplayName = Messages.AddPOOrder, MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select, Visible = false)]
[PXLookupButton]
[APMigrationModeDependentActionRestriction(
restrictInMigrationMode: true,
restrictForRegularDocumentInMigrationMode: true,
restrictForUnreleasedMigratedDocumentInNormalMode: true)]
public virtual IEnumerable AddPOOrder2(PXAdapter adapter)
{
bool isInvoice = (Base.Document.Current.DocType == APDocType.Invoice),
isPrepayment = (Base.Document.Current.DocType == APDocType.Prepayment);
if (Base.Document.Current != null &&
isInvoice &&
Base.Document.Current.Released == false &&
Base.Document.Current.Prebooked == false)
{
List<POOrder> orders = poorderslist.Cache.Updated.RowCast<POOrder>().Where(rc => rc.Selected == true).ToList();
foreach (POOrder rc in orders)
{
Base.InvoicePOOrder(rc, false);
}
Base.AttachPrepayment(orders);
}
return adapter.Get();
}
The Base call here is referring to APInvoiceEntry
when you decompile the PX.Objects.dll file we can find code for "ADD PO"
PX.Objects.PO.GraphExtensions.APInvoiceSmartPanel.AddPOOrderExtension
but, I need code for ADD Subcontracts
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);
}
}
I am trying to add Add Items functionality in Opportunity like in Sales Order. I have gone through the code in SOOrderEntry and I have tried to replicate the same functionality.
The Add Item menu brings the smart panel with filter options, but it does not populate the data. I have compared the setting with Sales Order Add Item Smart panel settings and I did not miss anything.
I have replicated the table structure and events as in sales order with changes required for Opportunity.
#region SiteStatus Lookup
public PXFilter<OpportunitySiteStatusFilter> oppsitestatusfilter;
[PXFilterable]
[PXCopyPasteHiddenView]
public OpportunityStatusLookup<OpportunitySiteStatusSelected, OpportunitySiteStatusFilter> opportunitysitestatus;
public PXAction<CROpportunity> addOppBySite;
[PXUIField(DisplayName = "Add Stock Item", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)]
[PXLookupButton]
public virtual IEnumerable AddOppBySite(PXAdapter adapter)
{
oppsitestatusfilter.Cache.Clear();
if (opportunitysitestatus.AskExt() == WebDialogResult.OK)
{
return AddOppSelBySite(adapter);
}
oppsitestatusfilter.Cache.Clear();
opportunitysitestatus.Cache.Clear();
return adapter.Get();
}
public PXAction<CROpportunity> addOppSelBySite;
[PXUIField(DisplayName = "Add", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select, Visible = false)]
[PXLookupButton]
public virtual IEnumerable AddOppSelBySite(PXAdapter adapter)
{
foreach (OpportunitySiteStatusSelected line in opportunitysitestatus.Cache.Cached)
{
if (line.Selected == true && line.QtySelected > 0)
{
CROpportunityProducts newline = PXCache<CROpportunityProducts>.CreateCopy(Base.Products.Insert(new CROpportunityProducts()));
newline.SiteID = line.SiteID;
newline.InventoryID = line.InventoryID;
newline.SubItemID = line.SubItemID;
newline.UOM = line.SalesUnit;
//newline.AlternateID = line.AlternateID;
//newline = PXCache<SOLine>.CreateCopy(Transactions.Update(newline));
//if (newline.RequireLocation != true || PXAccess.FeatureInstalled<FeaturesSet.warehouseLocation>())
// newline.LocationID = null;
newline = PXCache<CROpportunityProducts>.CreateCopy(Base.Products.Update(newline));
//newline.Qty = line.QtySelected;
cnt = 0;
Base.Products.Update(newline);
}
}
opportunitysitestatus.Cache.Clear();
return adapter.Get();
}
protected virtual void OpportunitySiteStatusFilter_RowInserted(PXCache cache, PXRowInsertedEventArgs e)
{
OpportunitySiteStatusFilter row = (OpportunitySiteStatusFilter)e.Row;
if (row != null && Base.Products.Current != null)
row.SiteID = Base.Products.Current.SiteID;
}
int cnt;
public IEnumerable<PXDataRecord> ProviderSelect(BqlCommand command, int topCount, params PXDataValue[] pars)
{
cnt++;
return Base.ProviderSelect(command, topCount, pars);
}
#endregion
Regards,
R. Muralidharan
You may want to compare your custom SmartPanel aspx with out-of-box Add Stock Item SmartPanel of SalesOrderEntry screen. As #Hybridzz mentioned, most likely you haven’t set AutoSize property. You need to set AutoSize to True when Grid pagination is Enabled.
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;
}