I'm trying to write some code for a customization with an action button, AddFollowUp to Leads. I want to:
update a custom field called UsrNextFollwup -> how do I access the custom field in the object?
I can update objects I find with PXSelect<> but how I can insert new objects? eg if I create Contact myContact=new Contact(); //set properties, etc -> how do I insert it?
How can I find the current user's ID? I can get the current lead from Contact curLead=Base.LeadCurrent.SelectSingle() but I also want something like #me function.
My code:
public class LeadMaint_Extension:PXGraphExtension<LeadMaint>
{
public PXAction<PX.Objects.CR.Contact> AddFollowUp;
public PXSelect<CRActivity> Task;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Add FollowUp")]
public void addFollowUp()
{
Contact curLead=Base.LeadCurrent.SelectSingle();
DateTime dueDate = DateTime.Now;
curLead.CreatedDateTime = dueDate.AddDays(14); //works great
curLead.UsrNextFollwup = dueDate.AddDays(14); //doesn't work
}
}
In Acumatica custom fields are declared via DAC extensions. To access the DAC extension object, you can use the following methods:
The GetExtension() generic method available for each DAC instance:
ContactExt contactExt = curLead.GetExtension<ContactExt>();
The GetExtension(object) generic method declared within the non-generic PXCache class
ContactExt contactExt = Base.LeadCurrent.Cache.GetExtension<ContactExt>(curLead);
or
ContactExt contactExt = Base.Caches[typeof(Contact)].GetExtension<ContactExt>(curLead);
The GetExtension(object) static generic method of the PXCache generic class
ContactExt contactExt = PXCache<Contact>.GetExtension<ContactExt>(curLead);
To insert, update or delete a DAC record, one should invoke Insert, Update or Delete method on appropriate PXCache instance (or a data view, which simply redirects the call to PXCache -> ShipmentLines.Insert(line) is an equivalent to ShipmentLines.Cache.Insert(line) statement). For instance, to insert a data record into the cache in code, you invoke the Insert() method of a data view as follows:
ShipmentLine line = new ShipmentLine();
line.ProductID = card.ProductID;
...
ShipmentLines.Insert(line);
Some application settings, such as BranchID, UserID and UserName are accessible via Accessinfo property of the PXGraph class. The Accessinfo property returns an instance of the AccessInfo DAC - AccessInfo.UserID will return ID for the current user. To access the Accessinfo property from a BLC extension, use Base.Accessinfo statement
Starting ver. 5 Acumatica introduced runtime compilation, which allowed to publish customizations without a mandatory restart of IIS app pool when there are no dlls included with any of currently applied customization projects. Before runtime compilation was released, customization manager created all code files in App_Code\Caches folder of the website. Asp.Net runtime takes care of any code files created in App_Code\Caches folder, immediately compiles them and restarts IIS app pool to also immediately bring all changes on your Acumatica website. The beauty of this approach is that all classes declared in any file located under App_Code\Caches folder, are available with VS IntelliSense and never highlighted with red underlines as potential issue. The only drawback - every time you make any change inside App_Code\Caches folder, IIS app pool restarts (same thing as if you re-compiled a dll located in Bin folder) and it takes some time for your website to reboot so you can test your changes.
With runtime compilation in place, Acumatica created all code files in App_RuntimeCode folder of the website. Now it's Acumatica's responsibility to compile all code files from App_RuntimeCode folder into an assembly and load it at runtime without a restart of IIS app pool. With this approach you don't need to wait for your website to reboot every time you make some changes in your customization. On the other hand, sometimes runtime complication doesn't always properly clear up what was done in your previous code files and time to time, it might be necessary to manually recycle app pool or restart IIS on your developer machine to make sure Acumatica loads only actual code from the App_RuntimeCode folder. Another drawback is lack of support by VS IntelliSense: all classes declared in any file located under App_RuntimeCode folder is never suggested by IntelliSense and always highlighted with red underlines as potential issue, though both yourself and Acumatica are confident, that everything is fine and all files will compile with mo issues.
To have all customization files automatically created in App_Code\Caches folder, just disable runtime compilation on your development website by adding following key to appSettings in web.config file:
<add key="UseRuntimeCompilation" value="false" />
Related
We are in to acumatica 20 r2 and when we publish the custom package, the default report menu print salesorder/quote option disappears.
We have custom reports which are added by overriding the initialize method of salesorderentry graph in my extension.
public override void Initialize()
{
base.Initialize();
base.Base.report.AddMenuAction(embroideryreport);
base.Base.report.AddMenuAction(embroiderysoreport);
base.Base.report.AddMenuAction(screenprintreport);
base.Base.report.AddMenuAction(screenprintsoreport);
}
I am not able to figure out the reason for missing report. I have upgraded the workflow to latest version and still having the issue.
UPDATE
I did not call base.Initialize() initially and since the default report is not coming, I thought it may be due to not invoking the base method.
I have tried bahaa-zantout suggestion and the base report is already tagged to the report menu and when I commented on the code in Initialize method for adding the report the default report appeared again under-report menu.
It looks like there is conflict in the workflow and I am not able to figure it out.
I have tried to add those report in the workflow action section and tagged them to Report and the entire report menu disappeared
Change you initialization method to....
public override void Initialize()
{
base.Base.report.AddMenuAction(embroideryreport);
base.Base.report.AddMenuAction(embroiderysoreport);
base.Base.report.AddMenuAction(screenprintreport);
base.Base.report.AddMenuAction(screenprintsoreport);
}
From Acumatica DEV documentation portal
You do not need to explicitly invoke the Initialize() method on the previous extension levels; these methods are called automatically. Invoking base.Initialize() makes no sense, because the base variable points to the base class, which is PXGraphExtension (not the base graph). The PXGraphExtension class defines Initialize() as an empty method.
You could attempt the following in attempt to restore the toolbar menu item.
Navigate to the Sales Order screen in the customization project
Go to the Actions
Locate the missing print options (ie. printSalesOrder) and place the Toolbar folder in the original folder in this case "Reports". If it doesn't work try moving to "Actions" and see if it appears.
See example screenshot.
I am not sure it is due to this statement or not but when I changed the following statement it fixed the issue
[PXButton(SpecialType = PXSpecialButtonType.ReportsFolder)]
to
[PXButton]
for Report action
public PXAction<SOOrder> embroideryreport;
[PXUIField(DisplayName = "Embroidery Production Report", MapEnableRights = PXCacheRights.Select)]
//[PXButton(SpecialType = PXSpecialButtonType.ReportsFolder)]
[PXButton]
I want to create a custom page that allows me to track manually every data modification made by kentico in the database
I understood that I can implement it by code by using the NewClassWizard. But when done how I can use it in Kentico admin ?
I try to load it from Page Type module but can find a way to specify my custom class
Is it the right way to use that? The documentation is not really clear on that
thanks for your help
I'd suggest creating a global event handler to track changes. While Kentico will already do a lot of this tracking for you, you can specifically add whatever specific events you want as a global event. This will handle any changes made on the customer-facing public website, inside the Kentico UI, and in any Kentico API calls.
In your custom global event handler, you can check for different types of events based on the object and the CRUD activity. For instance something like this:
using CMS;
using CMS.CustomTables;
using CMS.DataEngine;
using CMS.DocumentEngine;
// Registers the custom module into the system
[assembly: RegisterModule(typeof(CustomInitializationModule))]
public class CustomInitializationModule : Module
{
// Module class constructor, the system registers the module under the name "CustomInit"
public CustomInitializationModule()
: base("CustomInit")
{
}
// Contains initialization code that is executed when the application starts
protected override void OnInit()
{
base.OnInit();
// Assigns custom handlers to events
DocumentEvents.Insert.After += Document_Insert_After;
}
private void Document_Insert_After(object sender, DocumentEventArgs e)
{
if (e.Node.ClassName.ToLower() == "your.classname")
{
// create an event to log to a custom module table or a custom table so it's not logged directly in the Kentico Event log
CustomTableItem item = new CustomTableItem("customtable.name");
item.SetValue("ItemEventType", "Create document");
item.SetValue("ItemEventCode", "Your event code");
item.SetValue("ItemEventUserID", e.Node.DocumentModifiedByUserID);
item.SetValue("ItemEventUrl", e.Node.NodeAliasPath);
item.SetValue("ItemEventName", e.Node.DocumentName);
item.Insert();
}
}
}
This is a simple example of when a document is created. You don't have to check the page type's classname if you don't want to. You can also include a global event handler for any "object" like a cms_class object, just use that definition in your code <name>Info.TYPEINFO.Events.<eventtype>. This is not limited to any object, you can track transformation updates, page type field modifications, etc. You just need to know the object name/type and write code around it.
I'm have a Xamarin.iOS app. It was written some time ago and used XIB to define user interface. I want to add new view (and controller for it) but every time I'm adding new page and launching the app I get the following error:
Failed to marshal the Objective-C object 0x17a37a70 (type: LoginView). Could not find an existing managed instance for this object, nor was it possible to create a new managed instance (because the type 'Touch.LoginView' does not have a constructor that takes one IntPtr argument).
Additional information:
Selector: viewDidLoad
Method: Touch.LoginView:ViewDidLoad ()
What is more interesting if I'm creating new view by copying existing one and renaming it - everything works fine. I tried to figure out what is the difference but the only thing I found is the following:
If you noticed the extra level of hierarchy was added.
What it is the level and why my app continue to fail with newly created view (i have to copy existing one if I want new view).
This kind of error message can be a real pain normally. In your case, you're pretty lucky as there is a very simple fix to this. When working with xib or storyboard files, you want to have the following in your controllers:
public Test1ViewController (IntPtr handle) : base (handle)
{
}
A general explanation of the error message you are seeing:
Such issues are, 99% of the time, related to a managed instance with no
reference. At some point the GC will collect it and it will crash whenever some native code tries to callback into the (now freed) managed instance.
Use Case: User logged in and a Vaadin Table component opened showing statuses of appointments. Every row has a drop down (ComboBox) to change status (Scheduled, Arrived, Reviewed). Now multiple users has opened this table in their own browsers and making continuous changes to appointment status. These changes should be reflected on all opened tables i.e if user A changes status of appointment appt-1 it reflects and refresh on all Tables currently opened.
Previously we applied event based refreshing with ICE-PUSH Add-on i.e if Change made on PC-1 (i.e Application instance a1), i get the other instances of Vaadin application from static CopyOnWriteArrayList from MainApplication class and by that instance I call loadTable function. after that I call the ICEPUSH to push new changes to all users.
public class MainApplication extends Application {
public static CopyOnWriteArrayList<MainMedMaxApplication> appList=new CopyOnWriteArrayList<MainMedMaxApplication>();
#Override
public void init() {
setMainWindow(new Window("APPointment Dashboard"));
getMainWindow().setContent(mainLayout);
setMainComponent(getCustomTable());
//Custome Table make table . it also register listeners over table.
//loadTable will load the table.
loadTable()
appList.add(this);
}
}
public void loadTabl(String date) {
//this will reload the table component By Querying database
}
private void registerlistener() {
table.addListeners()
{
//do any change to table in this instance and save it to db then call ICE push so it can referesh all app instances by getting from applist.
synchronizePortlets();
}
}
public void synchronizePortlets() {
// TODO Auto-generated method stub
Iterator<MainApplication>itM = appList.iterator();
while(itM.hasNext()) {
MainApplication app = itM.next();
app.loadTabl();
app.getPusher().push();
}
}
}
This works fine but in some conditions when to many frequent changes made then Concurrent Modification Exception rises. so if any one can help to improve this?
The solution I am thinking after this is to refresh table component not forcefully rather continuously in every 1 mint by its own app instances. This will query database and reload the table container with updated statuses. For this purpose I use Refresher add-on But it raises an exception i.e ConcurrentModificationException, because sometimes user also changing the table component by changing combo statuses in table meanwhile refresher refresh the Table and here raises concurrent Modification exception. So I am thinking of freezing Table component from user point of view so user can't do anything and in background can easily refresh table.
If for this use case you guys have better solution please do tell me. I am grateful of you.
Using Vaadin 6.8.12, java 1.7, apache Tomcat 7.42
Vaadin 6
You need to apply synchronization since you're making changes to the GUI from another thread (and I think it doesn't matter whether Refresher or IcePush is used, I think in both cases you'll use another thread). Synchronize on the Application instance.
See this post on the Vaadin forum.
Vaadin 7
EDIT: I encourage you to upgrade to Vaadin 7.1 and use this new method on UI: UI#access as is recommended here.
I'm writing a VS2012 add-in, adding a command to Build Explorer context menu (see related question). The command gets added to 2 different context menus:
Build Explorer
Team Explorer, Builds page, My Builds section
When my one callback is called, how do I know which of these it is?
I tried get the focused control (using P/Invoke as this question suggests). However, it gets me a Tabs container for (1), and null for (2). I could try to cast the control to the tabbed container, but that sounds pretty bad...
Any better alternative?
My new/other idea - it is similar to yours:
You should try to monitor which window was activated lastly.
If you create an eventhandler for your command, then you may be able to check which window is active when your command fired. A simple evenent handler for a command:
void cmdEvents_BeforeExecute( string guid, int ID, object customIn, object customOut, ref bool cancelDefault )
{
Window2 teamExplorer = _applicationObject.Windows.Item("Team Explorer") as Window2;
if (_applicationObject.ActiveWindow.Caption == teamExplorer.Caption)
{
//You are called from Team Explorer
}
else
{
//Somewhere else
}
}
And the way you can subscribe:
static _dispCommandEvents_BeforeExecuteEventHandler _myHandler;
static CommandEvents _cmdEvents;
public void OnConnection(...)
{
Command command = ...; // Init your command
int ID = command.ID;
string GUID = command.Guid;
CommandEvents _cmdEvents = _applicationObject.Events.get_CommandEvents(GUID, ID);
_myHandler = new _dispCommandEvents_BeforeExecuteEventHandler(cmdEvents_BeforeExecute);
_cmdEvents.BeforeExecute += _myHandler;
}
You may find a better way to identify the window(s) by GUID. You should keep at least _cmdEvents as static because when it will be desroyed, your event handler could vanish (least for internal commands).
In OnDisconnection you should unsubscribe.
Reworked by the comment, and founded links:
As the menu item is shown every place it seems there is no way to distinct between them from an Add-In, you should add two command and distinct them by their context.
The way instead of converting the Add-In to a VS-Package MZ-Tools HOWTO: Controlling the state of command in a Visual Studio add-in, try MZ-Tools HOWTO: Use the IVsMonitorSelection ... you can also get it from an Add-In.
But:
Neither the AddNamedCommand nor the QueryStatus methods honor the
invisible state: the button that must be invisible ...
remains disabled rather than invisible.
I think this makes it impossible to do it from an Add-In on a suitable way, but maybe you can check the contexts.
Other way you could get further, if you try to migrate your command/menu into a VSPackage and create a custom UIContext for the menu items or find a suitable predefined one. I have no access to a Studio enhanced with Build Explorer so I can't try it.
The following discussion is about custom contexts for vs-packages:
http://davedewinter.com/2008/04/05/dynamic-menu-commands-in-visual-studio-packages-part-3/
Sadly the links are broken from the post, and I can't reach Part 1. and Part 2. which is about the discussion of the problem from the beginning.
But there is no guarantee you can create a context which suits you.
Only context ID I found for Team Explorer is the guidTeamProjectCmdUIContext.
It is placed at vsshilds.h in Visual Studio 2010 SDK, vsshell*.h are also contain several others.
MSDN: Vsct files to define command, menus, ect. from packages.
Condition attribute for items:
http://msdn.microsoft.com/en-us/library/bb491718.aspx
http://msdn.microsoft.com/en-us/library/bb166515.aspx
MSDN: VisibilityItem element for commands and toolbars.
VisibilityItem element determines the static visibility of commands and toolbars.
... After the VSPackage is loaded, Visual Studio expects command visibility to be determined by the VSPackage rather than the VisibilityItem.
And finally about predefined Context Guids:
http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.shell.interop.uicontextguids80.aspx
http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.shell.interop.uicontextguids.aspx