How do I Activate a project in a BLC extension? - acumatica

I'm creating a project record in a BLC extension - and I'm trying to Activate it after a save - but in looking through the source code, it's a protected method that's inaccessible and can't be executed:
public PXAction<PMProject> activate;
[PXButton(CommitChanges = true), PXUIField(DisplayName = "Activate Project")]
protected virtual IEnumerable Activate(PXAdapter adapter) => adapter.Get();
This code snippet also tells me nothing about what's actually occurring in that method - where's the body?
So - bottom line: How do I activate the project through code?

It should be as simple as setting the current project record to your project and pressing the Activate action from the code like below
ProjectEntry projectEntry = PXGraph.CreateInstance<ProjectEntry>();
/*
* Configure your current project record here
*/
projectEntry.activate.PressButton();// this line will run te Activate action
/*
* Do the remaining required actions/changes
*/

Related

How do I clear the input of a Smart Panel dialog (PXFilter)?

I have created a smart panel in a custom screen to ask for user input that is used to facilitate moving stock from normal inventory into an isolation area. My original smart panel example that I always use is the Copy Order in the SOOrderEntry graph (SO301000). In this case, I need to do a bit of validation, and the user may very well decide to close the smart panel and update the document in the screen before reopening the smart panel again. If the user clicks the cancel button, I need the smart panel to reset back to defaults every time it is opened.
I thought this might be handled in the ASPX screen definition, but I can't find the right setting for the form itself. I use AutoRefresh on selectors to refresh every time they are opened, but I need the form itself to do the same and refresh back to default every time it is opened. The desired behavior DOES occur automatically when I navigate to another record of the graph's primary DAC, but I cannot seem to force the smart panel to refresh automatically every time it is opened. I looked at the various options for the form in ASPX, but I overlooked it if it is there.
Similarly to CopyOrder on SOOrderEntry, here is my code sample from my graph.
public PXFilter<StockParamFilter> stockparamfilter;
#region AddFromStock
public PXAction<MyTag> addFromStock;
[PXUIField(DisplayName = Messages.AddFromStock, MapEnableRights = PXCacheRights.Insert, MapViewRights = PXCacheRights.Insert)]
[PXButton]
protected virtual IEnumerable AddFromStock(PXAdapter adapter)
{
MyTag tag = Tags.Current;
if (tag?.TranRefNbr != null)
{
throw new PXException(Messages.TagAlreadyReceived);
}
MyTagEntry graph = PXGraph.CreateInstance<MyTagEntry>();
WebDialogResult dialogResult = stockparamfilter.AskExt(setStockStateFilter, true);
if (dialogResult == WebDialogResult.OK || (IsContractBasedAPI && dialogResult == WebDialogResult.Yes))
{
// My Business Logic Here
}
return adapter.Get();
}
#endregion
#region CheckStockParams (OK Button in Smart Panel)
public PXAction<MyTag> checkStockParams;
[PXUIField(DisplayName = "OK", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)]
[PXLookupButton]
public virtual IEnumerable CheckStockParams(PXAdapter adapter)
{
return adapter.Get();
}
#endregion
#region setStockStateFilter
private void setStockStateFilter(PXGraph aGraph, string ViewName)
{
checkStockStateFilter();
}
#endregion
#region checkStockStateFilter
protected virtual void checkStockStateFilter()
{
// My Business Logic Here to set bool enableStockParams = ???
checkStockParams.SetEnabled(enableStockParams);
}
#endregion
This seems like something I did in the past, but I cannot seem to locate the code. I think it is related to stockparamfilter being a PXFilter instead of a PXSelect (or SelectFrom).
I have tried stockparamfilter.ClearDialog() with no luck. I have tried stockparamfilter.RequestRefresh() with no luck. I even tried stockparamfilter.DeleteCurrent() which seemed to work when I hit Cancel, but then my code did not execute when I hit OK. I also seemed to get the desired results when I used stockparamfilter.Cache.SetDefaultExt<StockParamFilter.locationID>(filter); on every field, until I hit OK which did nothing. It's like every time I try to manipulate the filter, I break the smart panel without any errors in the trace. In fact, here is the list of what I tried unsuccessfully:
StockParamFilter filter = stockparamfilter.Current;
stockparamfilter.View.Clear();
stockparamfilter.View.RequestRefresh();
stockparamfilter.Cache.Clear();
stockparamfilter.View.RequestRefresh();
stockparamfilter.View.RequestFiltersReset();
stockparamfilter.DeleteCurrent();
stockparamfilter.ClearDialog();
stockparamfilter.Cache.SetDefaultExt<StockParamFilter.locationID>(filter);
stockparamfilter.Cache.SetDefaultExt<StockParamFilter.toLocationID>(filter);
stockparamfilter.Cache.SetDefaultExt<StockParamFilter.qty>(filter);
stockparamfilter.Cache.SetDefaultExt<StockParamFilter.lotSerialNbr>(filter);
stockparamfilter.Cache.SetDefaultExt<StockParamFilter.origRefNbr>(filter);
What is the ASPX code or C# Code that will let me reset the smart panel to defaults?
A big thanks to Hughes Beausejour at Acumatica for the offline assist. Posting solution for anyone else that may have this issue.
First, it is important to understand that AskExt generates 2 passes of the code. The first pass prompts the smart panel. Upon response to the smart panel, the code executes again, but in this second context skips the ask. With that in mind, the reason for my code not working became clear, as Hughes explained to me.
To execute the code when the form is initialized, that code must be executed before the ask occurs. Otherwise, the form is presented and then the initializing code is executed too late. Additionally, it must be conditioned such that it only fires when the smart panel was not given an OK response by the user. (Not realizing the code executes twice, I was unaware that I was resetting the fields on both passes. When I could get the form to reset, the subsequent processing would fail becuase I was resetting it on that pass as well.) Following that code, the AskExt can be used to present the form along with the normal processing of the user response.
My code, to show the working example, is as follows:
StockParamFilter filter = stockparamfilter.Current;
// If the user response is anything except an affirmative, default the fields
if (!(stockparamfilter.View.Answer == WebDialogResult.OK || (IsContractBasedAPI && stockparamfilter.View.Answer == WebDialogResult.Yes)))
{
stockparamfilter.Cache.SetDefaultExt<StockParamFilter.locationID>(filter);
stockparamfilter.Cache.SetDefaultExt<StockParamFilter.toLocationID>(filter);
stockparamfilter.Cache.SetDefaultExt<StockParamFilter.qty>(filter);
stockparamfilter.Cache.SetDefaultExt<StockParamFilter.lotSerialNbr>(filter);
stockparamfilter.Cache.SetDefaultExt<StockParamFilter.origRefNbr>(filter);
}
// Present the Smart Panel Dialog (happens only on the 1st pass - AskExt causes the code to execute twice)
WebDialogResult dialogResult = stockparamfilter.AskExt(setStockStateFilter, true);
// If the response was affirmative, execute the business logic
if (dialogResult == WebDialogResult.OK || (IsContractBasedAPI && dialogResult == WebDialogResult.Yes))
{
// Do Business Logic Based On User Response In Smart Panel
}

Adding Excel upload feature to Employee Timecard Entry doesn't show ProjectTask field

I have a customization to the Employee Timecard Entry screen (EP305000) which enables the Excel upload functionality into the Details tab grid. I did this by adding the attribute [PXImport(typeof(EPTimeCard))] to the 'Activities' view re-declaration in a TimeCardMaint BLC extension as follows:
[PXImport(typeof(EPTimeCard))]
[PXViewName(PX.Objects.EP.Messages.TimeCardDetail)]
public PXSelectJoin<EPTimecardDetail,
InnerJoin<CREmployee,
On<CREmployee.userID, Equal<EPTimecardDetail.ownerID>>,
LeftJoin<CRActivityLink,
On<CRActivityLink.noteID, Equal<EPTimecardDetail.refNoteID>>,
LeftJoin<CRCase,
On<CRCase.noteID, Equal<CRActivityLink.refNoteID>>,
LeftJoin<PX.Objects.AR.Customer,
On<PX.Objects.AR.Customer.bAccountID, Equal<CRCase.customerID>>,
LeftJoin<PX.Objects.EP.TimeCardMaint.ContractEx,
On<PX.Objects.EP.TimeCardMaint.ContractEx.contractID, Equal<CRCase.contractID>>,
LeftJoin<PMProject,
On<PMProject.contractID, Equal<EPTimecardDetail.projectID>>>>>>>>,
Where<CREmployee.bAccountID, Equal<Current<EPTimeCard.employeeID>>,
And<EPTimecardDetail.weekID, Equal<Current<EPTimeCard.weekId>>,
And<EPTimecardDetail.trackTime, Equal<True>,
And<EPTimecardDetail.approvalStatus, NotEqual<ActivityStatusListAttribute.canceled>,
And<Where<EPTimecardDetail.timeCardCD, IsNull, Or<EPTimecardDetail.timeCardCD, Equal<Current<EPTimeCard.timeCardCD>>>>>>>>>,
OrderBy<Asc<EPTimecardDetail.date>>> Activities;
I also set the 'AllowImport' property of the grid to 'True'. This seems to work ok, except that the 'ProjectTask' field of the upload does not allow mapping - i.e., if you go through the import process, when you get to the field mapping part, you can't map the Excel field for ProjectTask to the grid's ProjectTask. It just doesn't show up.
Would this be because the source BLC has as delegate method for 'activities' that I didn't reproduce in my extension?
What could be the reason for not allowing mapping to the ProjectTask field?
Since the ProjectTask field is disabled by default, this was solved by adding a parameter to the [ProjectTask] attribute, called "AlwaysEnabled" via the CacheAttached event, as shown below:
public class TimeCardMaint_Extension : PXGraphExtension<TimeCardMaint>
{
[PXDefault(typeof(Search<PMTask.taskID, Where<PMTask.projectID, Equal<Current<TimeCardMaint.EPTimecardDetail.projectID>>, And<PMTask.isDefault, Equal<True>>>>), PersistingCheck = PXPersistingCheck.Nothing)]
[ProjectTask(typeof(TimeCardMaint.EPTimecardDetail.projectID),
BatchModule.TA,
DisplayName = "Project Task",
BqlField = typeof(PMTimeActivity.projectTaskID),
AlwaysEnabled = true)]
protected virtual void EPTimecardDetail_ProjectTaskID_CacheAttached(PXCache cache)
{
}

While loading the page, processRequest() won't called

I am new in OAF. I am writing a small program for displaying data in the browser window. But as per the OAF Documentation, when a page loads processRequest() should be called automatically. But in my case the processRequest() method is not called. So any one please help me to get the processRequest() method to be called when page is loaded.
This is my Controller code. Note I associate this controller to a page. While loading the page, processRequest() method is not called.
public class MyController extends OAControllerImpl
{
public static final String RCS_ID = "$Header$";
public static final boolean RCS_ID_RECORDED =
VersionInfo.recordClassVersion(RCS_ID, "%packagename%");
/**
* Layout and page setup logic for a region.
* #param pageContext the current OA page context
* #param webBean the web bean corresponding to the region
*/
public void processRequest(OAPageContext pageContext, OAWebBean webBean)
{
/* The below code line is used to initialize the application module */
System.out.println("inside processRequest");
OAApplicationModule am =
(OAApplicationModule)pageContext.getApplicationModule(webBean);
// am.invokeMethod("execVO");
/* The below code line is used to initialize VO*/
OAViewObject vo = (OAViewObject)am.findViewObject("EmpView1");
/* DataDisplayVO1 is the instance name in AM which is the original name of the VO */
vo.executeQuery();
RowSetIterator rowsetIterator = vo.createRowSetIterator(null);
while (rowsetIterator.hasNext())
{
Row r = rowsetIterator.next();
System.out.println("Empno is ... " + r.getAttribute("Empno"));
}
}
This is impossible. In my experience, till now I have never faced any issues like this.
On a second thought, just thinking if the controller is not assigned to the page. It may happen although in rarest case. And the case is you have run the page before attaching the controller and the page xml is stored in your classes directory. This directory is refreshed on each run, but rarely it doesn't get refreshed.
Try to rebuild your application, if possible delete the classes folder content of your relevant package. Hopefully it may help.

Error #153 Another process has added 'Note' record. Your changes will be lost(SalesOrderEntry)

In the Sales Order page, I created a custom button which purpose is to save and refresh the page. Currently it saves fine and processes the new order to an order number but when I try to add an item/edit or perform an action in the drop down menu I receive the error message.
Here's my code:
public PXAction<SOOrder> SRefresh;
[PXUIField(DisplayName = "S RefreshT")]
[PXButton(CommitChanges = true)]
protected virtual IEnumerable sRefresh(PXAdapter adapter)
{
SOOrderEntry graph = PXGraph.CreateInstance<SOOrderEntry>();
Base.Actions.PressSave();
SOLine sLine = PXSelect<SOLine, Where<SOLine.orderNbr, Equal<Required<SOLine.orderNbr>>>>.Select(graph, this.Base.Document.Current.OrderNbr);
if (sLine != null && sLine.InventoryID.HasValue)
{
graph.Document.Current = graph.Document.Search<SOLine.orderNbr>(sLine.OrderNbr);
throw new PXRedirectRequiredException(graph, null);
}
return adapter.Get();
}
I've also tried using graph.Persist() as said in the manual instead of Action.PressSave(); with no success.
I appreciate any input you guys may have, Thank you
Since you're working with the current sales order, you don't need to create a new instance of the sales order entery graph and redirect your user. You can work with the Base object and run all your logic on it.
Base.Document.Current contains a reference to the current SOOrder, and Base.Transactions contains the list of SOLine of this document. Another problem I also found in your code is that you're calling Document.Search<SOline.orderNbr>; it should be SOOrder.orerNbr since you're searching inside the Document view, which contains sales orders, and not lines. In this case, it's not even necessary to search, Base.Document.Current will already be set to the order you're looking at.
I strongly recommend completing the standard Acumatica developer trainings - T100, T200, T300; this stuff is all covered and will get you productive quickly

VS 2012 Start UI Windows from VSPackage

i've started to work with the VS2012 extensibility possibilities. I did the first few Walkthroughs and now I'm trying get further on. What I'm trying is pretty easy I guess... I'm trying to build a simply vspackage which starts an UI window. Actually i do not find any howto or sample code.
Do you have some links with further information about doing something like that ?
Thanks for you help..
Iki
You can find initial information here.
Here is my code for menu item:
/// <summary>
/// Initialization of the package; this method is called right after the package is sited, so this is the place
/// where you can put all the initialization code that rely on services provided by VisualStudio.
/// </summary>
protected override void Initialize()
{
Debug.WriteLine ("Entering Initialize() of: {0}", this);
base.Initialize();
// Add our command handlers for menu (commands must exist in the .vsct file)
OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if ( null != mcs )
{
// Create the command for the menu item.
CommandID menuCommandID = new CommandID(GuidList.guidPackageProject, (int)PkgCmdIDList.Impl);
OleMenuCommand menuItem = new OleMenuCommand(MenuItemCallback, menuCommandID);
mcs.AddCommand( menuItem );
}
}
/// <summary>
/// This function is the callback used to execute a command when the a menu item is clicked.
/// See the Initialize method to see how the menu item is associated to this function using
/// the OleMenuCommandService service and the MenuCommand class.
/// </summary>
private void MenuItemCallback(object sender, EventArgs e)
{
MyForm form = new MyForm();
form.ShowDialog(); // Here your form is opening
}
I have been searching for a solution to this recently as I also needed to start a WPF form from a VSPackage. I have got things working after a couple of hours searching various topics on this and some good ol' trial and error.
I had an existing WPF-Project in a separate solution, which had to be merged into a VSPackage. Here's the steps to get this working:
Create a new Solution of Project type 'Visual Studio Package'
Make sure you select the 'Tool Window' option in the VS Package
Wizard (see the image below)
Now that the Solution has been created, add the already existing
WPF-Project to it (Right-Click 'Solution', Add->Existing Project) NOTE: It might be wise to copy the WPF-project to the Solution folder prior to adding it to the Solution.
Make sure you create a reference to the WPF-Project from your
VSPackage-Project and (if necessary) edit the namespaces of the WPF-Project to meet those of the VSPackage-Project, or the other way around.
Your Solution will now look something like this:
Now, you need to edit MyToolWindow.cs:
// Original:
base.Content = new MyControl();
// Change to:
base.Content = new MainWindow();
Make the following changes to VSPackage1Package.cs (or whatever your *Package.cs file is called)
// Original
private void ShowToolWindow(object sender, EventArgs e)
{
// Get the instance number 0 of this tool window. This window is single instance so this instance
// is actually the only one.
// The last flag is set to true so that if the tool window does not exists it will be created.
ToolWindowPane window = this.FindToolWindow(typeof(MyToolWindow), 0, true);
if ((null == window) || (null == window.Frame))
{
throw new NotSupportedException(Resources.CanNotCreateWindow);
}
IVsWindowFrame windowFrame = (IVsWindowFrame)window.Frame;
Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(windowFrame.Show());
}
// Change to:
private void ShowToolWindow(object sender, EventArgs e)
{
// Get the instance number 0 of this tool window. This window is single instance so this instance
// is actually the only one.
// The last flag is set to true so that if the tool window does not exists it will be created.
//ToolWindowPane window = this.FindToolWindow(typeof(MyToolWindow), 0, true);
//if ((null == window) || (null == window.Frame))
//{
// throw new NotSupportedException(Resources.CanNotCreateWindow);
//}
//IVsWindowFrame windowFrame = (IVsWindowFrame)window.Frame;
//Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(windowFrame.Show());
MainWindow mainwin = new MainWindow();
mainwin.Show();
}
If you get no build errors, you should be fine.
To test if your WPF-form opens, Press 'Start' to run the VSPackage in a new 'Experimental' Visual Studio instance. If everything went OK, you will find and should be able to run your WPF-from from the View->Other Windows menu.
If you don't see your VSPackage listed in the menu, close your 'Experimental' Visual Studio instance. Then Clean en Build your Solution and press 'Start' again. It should show up now.

Resources