500 likes | 694 Views
Sage CRM Developers Course. Using the .NET API (2 ). Looking ahead to the classes. DP01: Introduction to the Development Partner Program DP02: Entities and the Data Model (Part 1 of 2) DP03: Entities and the Data Model (Part 2 of 2) DP04: Implementing Screen Based Rules (Part 1 of 2)
E N D
Sage CRM Developers Course Using the .NET API (2)
Looking ahead to the classes • DP01: Introduction to the Development Partner Program • DP02: Entities and the Data Model (Part 1 of 2) • DP03: Entities and the Data Model (Part 2 of 2) • DP04: Implementing Screen Based Rules (Part 1 of 2) • DP05: Implementing Screen Based Rules (Part 2 of 2) • DP06: Screen and User Independent Business Rules • DP07: Workflow (Part 1 of 2) • DP08: Workflow (Part 2 of 2) • DP09: Using the API Objects in ASP Pages (Part 1 of 2) • DP10 : Using the API Objects in ASP Pages (Part 2 of 2) • DP11: Using the Component Manager • DP12: Programming for the Advanced Email Manager • DP13: Using the Web Services API • DP14: Using the Web Services API (Part 2 of 2) • DP15: Coding the Web Self Service COM API (Part 1 of 2) • DP16: Coding the Web Self Service COM API (Part 2 of 2) • DP17: Using the .NET API (Part 1 of 2) • DP18: Using the .NET API (Part 2 of 2)
Agenda • The Specialised Classes • ListPage • DataPage • DataPageEdit • DataPageDelete • DataPageNew • SearchPage • Workflow using the .Net API • Customizing the Specialised Classes • Programmatic Control of Screens • Building Complex Pages • Controlling Screen Positioning
ListPage • using System; • using System.Collections.Generic; • using System.Text; • using Sage.CRM.WebObject; • namespace crm72a • { • public class OppoListPage : ListPage • { • public OppoListPage() • : base("opportunity", "opportunitylist", "opportunityfilterbox") • { • FilterByField = "oppo_assigneduserID"; • FilterByContextId = (int)Sage.KeyList.UserId; • } • } • }
DataPage • using System.Collections.Generic; • using System.Text; • using Sage.CRM.WebObject; • using Sage.CRM.Data; • namespace crm72a • { • public class myDataPage : DataPage • { • public myDataPage() • : base("company", "comp_companyid", "companyboxshort") • { • this.UseEntityTabs = true; • this.UseWorkflow = true; • this.EditMethod = "RunDataPageEdit"; • this.ContinueMethod = "RunListPage"; • } • } • } • Allows complex screens to be built using simple DataPage class
DataPageEdit • using System.Collections.Generic; • using System.Text; • using Sage.CRM.WebObject; • namespace myProject{ public class myClass : DataPageEdit { /* Constructor needs EntityName, IdField and ScreenName • */ public myClass() • : base("xxxxTableName", "xxxx_fieldname", "xxxxScreenName") {this.UseEntityTabs = true;this.UseWorkflow = true;this.CancelMethod = "RunListPage";this.DeleteMethod = "RunDataPageDelete";this.SaveMethod = "RunDataPage"; } }}
DataPageDelete • using System.Collections.Generic; • using System.Text; • using Sage.CRM.WebObject; • namespace myProject • { • public class myClass : DataPageDelete • { • /* If inherited from DataPageDelete then just need to set the EntityName, IdField and ScreenName • */ • public myClass() • : base("xxxxTableName", "xxxx_fieldname", "xxxxScreenName") • { • this.CancelMethod = "RunListPage"; • this.DeleteMethod = "RunDataPage"; • } • } • }
DataPageNew • using System.Collections.Generic;using System.Text;using Sage.CRM.WebObject;using Sage.CRM.Controls;using Sage.CRM.Data;namespace myProject{ public class myClass : DataPageNew { public myClass() : base("xxxxTableName", "xxxx_fieldname", "xxxxScreenName") {this.SaveMethod = "RunDataPage";this.UseWorkflow = true;this.WorkflowName = "Entity Workflow";this.WorkflowState = "NewRecord"; } public override void AfterSave(EntryGroup screen) { /*Record recNewOppo = screen.getRecord; *recNewOppo.SetField("xxxxx_companyid", int.Parse(GetContextInfo("company", "comp_companyid"))); *recNewOppo.SetField("xxxxx_personid", int.Parse(GetContextInfo("company", "comp_primarypersonid"))); *recNewOppo.SaveChanges(); */base.AfterSave(screen); } }}
SearchPage • using System.Collections.Generic; • using System.Text; • using Sage.CRM.WebObject; • namespace myProject • { • public class myClass : SearchPage • { • /*if descended from SearchPage then you just need to set the • * appropriate ListName and SearchBoxName • */ • public myClass() • : base("xxxxSearchBoxName", "xxxxListName") • { • this.SavedSearch = true; • /* ************* • * Other objects available include: • * • * SearchScreen • * ResultsGrid • */ • } • } • }
Search Screen Additional Components • Saved Search available • Keyword Search available • Clear Button automatic in class • Create New Group • Requires additional custom coding by developer • Actions • Requires additional custom coding by developer
Workflow in DataPages • Controlled by properties of Specialised Classes • DataPageBase • UseWorkflow • DataPage • isWorkflowPostBack • DataPageEdit • WorkflowScreen • DataPageNew • WorkflowName • WorkflowState
Calling Custom ASP and .NET Workflow Behaviour • ASP pages and .NET assemblies may only be called by user driven rules (Primary, Transitional, Global) and may not be invoked by Escalation rules. • Can either call ASP page or .NET assembly • Workflow actions would be ignored • Jscript conditions maybe used to control availability of rule
Programmatic Control of Screens • Adding Conditional Behaviour to a screenControlling the display of data elements • Adding and removing default buttons • Adding Custom controls to screens • Buttons and Hyperlinks (Save, Cancel, Help, Clear etc) • Adding/Removing Fields from screens and lists • Interacting with existing CRM information (TopContent and (recent) menus)
Sage.CRM.Controls • The Sage.CRM.Controls namespace provides access to screen components to allow programmatic update of properties • Entry • Fields within a Meta Data defined screen • EntryGroup • Control of HTML returned and interaction with component Fields (Entry) • GridCol • Columns within a Meta Data defined list • List • Control of the HTML returned and interaction with component Columns (GridCol)
Interacting with the Screens • When you call AddEntryGroup (c.f. DataPage) it stores up all the names of the entry groups that you have added in the array called EntryGroups Contains EntryGroup objects for each screen. • Can reference EntryGroups array in BuildContents • In ListPage can access ResultsGrid • Screen Fields • EntryGroupmygroup = EntryGroups[1]; • Entry newE = mygroup.CreateEntry("oppo_createddate"); • base.BuildContents(); • List Columns • for (int i = 0; i < ResultsGrid.Count; i++) • { • if (ResultsGrid[i].Name == "oppo_stage") • { • ResultsGrid[i].ShowHeading = false; • break; • } • }
Linking GridCols to ASP and .NET • To link to an ASP page • GridColcolOppoStatus = this.ResultsGrid[0]; colOppoStatus.JumpAction = 430; colOppoStatus.CustomActionFile = "CRMtest.asp"; colOppoStatus.CustomIdField = "oppo_opportunityid"; • To call a CustomDotNetdll • GridColcolOppoStatus = this.ResultsGrid[0]; colOppoStatus.JumpAction = 432; colOppoStatus.CustomActionFile = "CRMtest&dotnetfunc=RunOppoSummary"; colOppoStatus.CustomIdField = "oppo_opportunityid";
User Screen TopContent • Custom Entity • GetCustomEntityTopFrame("Project"); • User Screen control • HTMLStringstrFieldText = new HTMLString("<span class=TOPCAPTION>Custom Entity Information</span>"); • VerticalPanelpanelFields = new VerticalPanel(); • panelFields.Add(strFieldText); • ImageObjectmyEntityImage = new ImageObject(CurrentUser.VirtualImgPath() + "Icons/company.png"); • this.AddTopContent(new HorizontalPanel(myEntityImage, panelFields));
Admin Screen TopContent • //change the breadcrumb trail as needed; • string strCrumbTrail = "<A CLASS=TOPBC TARGET = EWARE_MID HREF=" + Url("1650") + "&MenuName=Admin&BC=Admin,Admin>Administration</A> ->"; • strCrumbTrail += " <A CLASS=TOPBC TARGET = EWARE_MID HREF=" + Url("1650") + "&MenuName=AdminSystem&BC=Admin,Admin,AdminSystem,System>System</A> ->"; • strCrumbTrail += " <A CLASS=TOPBC TARGET = EWARE_MID HREF=" + UrlDotNet(ThisDotNetDll, ThisDotNetFunction) + "&MenuName=Admin&BC=Admin,Admin,AdminSystem>My Admin</A> ->"; • HTMLStringstrFieldText = new HTMLString(strCrumbTrail); • VerticalPanelpanelFields = new VerticalPanel(); • panelFields.Add(strFieldText); • ImageObjectmyEntityImage = new ImageObject(CurrentUser.VirtualImgPath() + "Icons/admin.png"); • this.AddTopContent(new HorizontalPanel(myEntityImage, panelFields));
Button Types • Main Default Buttons • AddEditButton • AddHelpButton • AddDeleteButton • AddContinueButton • AddSaveButton • AddCancelButton • Custom Buttons • AddConfirmButton("CaptionCode","Image.gif","Question"); • AddConfirmButton("CaptionCode","Image.gif","Question","fieldname","fieldvalue"); • AddSubmitButton("CaptionCode","Image.gif","javascript") • AddSubmitButton("CaptionCode","Image.gif","fieldname","fieldvalue"); • AddUrlButton("CaptionCode","Image.gif","URL"); • string test = "/Main Menu/wwhelp/wwhimpl/js/html/wwhelp.htm?href=AddingInformation.html"; • AddHelpButton(test);
Special Help Method • Add the help button • AddHelpButton("help.htm"); • In CRM - turn on inline translation mode and go to your dot net dll page with the help button on it. • Click the help button and the list of available help files will be displayed. • Select the desired help file and save. • Turn off inline translation mode and your help button on your .netdll page will launch the help file you selected previously.
Overriding Button Behaviour • Examples • AddEditButton public override void AddEditButton() { string sUrl = UrlDotNet(ThisDotNetDll, "RunEditOpportunity"); AddUrlButton("Edit", "Edit.gif", sUrl); } • AddContinueButton public override void AddContinueButton() { //base.AddContinueButton(); //string sUrl = UrlDotNet(ThisDotNetDll, "RunDeleteOpportunity"); string sUrl = Url("184"); ; AddUrlButton("Continue", "Continue.gif", sUrl); } • Tip: • Ensure Base.AddCancelButton is commented out to stop default behaviour being implemented
Dealing with Security Policy • For example adding Custom Button to a Screen • Delete, Edit if (CurrentUser.IsInRange(Sage.PermissionType.Delete, "EntityName", TerritoryId,AssignedToUserId, AssignedToTeamId, CreatedByUserId)) { string sUrl = UrlDotNet(ThisDotNetDll, "RunCustomAction"); AddUrlButton("Continue", "Continue.gif", sUrl); } • New Button CurrentUser.HasRights(Sage.PermissionType.Insert, "Entity");
Custom Validation • Can override the Validate method to add your own validation • Must always call the base validation method as this checks for required fields. public override bool Validate() { //Always call the base validation method as it checks for required fields Boolean ok = base.Validate(); if (ok) { //do my validation here! //Check values on screen with Dispatch.ContentField("fieldname"); string name = Dispatch.ContentField("core_name"); if (name == "aaa") { ok = false; AddError("The name cannot be aaa"); } } return ok; }
Overriding the AfterSave() • public override void AfterSave(EntryGroup screen) { Record recNewOppo = EntryGroups[0].getRecord; recNewOppo.SetField("oppo_primarycompanyid", int.Parse(GetContextInfo("company","comp_companyid"))); recNewOppo.SetField("oppo_primarypersonid", int.Parse(GetContextInfo("company", "comp_primarypersonid"))); recNewOppo.SaveChanges(); base.AfterSave(screen); }
Intercepting the SaveChanges() • Override of the EntryGroups_FillRecordFromContent method public override void EntryGroups_FillRecordFromContent(Sage.CRM.Data.Record info) { base.EntryGroups_FillRecordFromContent(info); info.SetField("core_name", "Override the core name"); info.SetField("core_Status", "Logged"); }
Typical Web Page Tasks • Building Pages without Reference to Meta Data • Data Tasks Cloning and copying data • E.g. Copying a Case • Cloning a Report or Group • Custom Complex Pages Multi-Entity Edit or Entry Screens Multiple Lists on Page Interaction with 3rd Party Apps via COM or web services API including screen scraping from legacy systems • Rebuild of Company Quicklook showing inclusion of custom entity • Demonstration of dll called via workflow e.g. Opportunity Workflow • Rebuild of the Company Summary Screen • Editable grid example e.g. quick editing/entry of contacts in company • Custom Import example e.g. Importing folder contents to create library entries • List with check boxes (to allow batch tasks) • Listing and Notes with a Custom Entity • Compound Entry Screen quick entry of company with oppo/case details
Sage.CRM.Data • Specialised Web Classes referencing Meta Data screens and lists automatically imply Data Interaction • Explicit control of Data Interaction provided by Record and Entity classes within Sage.CRM.Data namespace • Record • Allows individual records and data sets to be handled for Create, Read and Update and Delete • Entity • Allows compound entities to be handled in a unified manner • E.g. Insert of Company together with Person, Address, Phone, Email and intersection table records
Record Handling • FindCurrentRecord(tablename) • gets current record • FindRecord(tablename, whereclause) • gets the record specified by where clause (like the existing COM)
Data Handling Changes • EntryGroup screenPersonBoxShort = new EntryGroup(“CompanyBoxShort"); • compGroup.Fill (compRec); • QuerySelectPhonQuery = GetQuery(); • PhonQuery.SQLCommand=querySQL; • PhonQuery.ExecuteReader(); • //PhonQuery.ExecuteNonQuery();
Usage • Record object FindCurrentRecord(“Tablename”) FindCurrentEntity(“EntityName”) FindRecord(“TableName”,”WhereClause”) • record set maybe returned • Record NewUserConRec = new Record("UserContacts"); • Specialised Classes CreateAppointment() CreateTask() Record OppoRecords = FindRecord("opportunity", "oppo_assigneduserid=" + CurrentUser.UserId); while (!OppoRecords.Eof()) { AddContent(OppoRecords.GetFieldAsString("oppo_description")); OppoRecords.GoToNext(); }
Sage.CRM.HTML • Building forms, fields and tables with out reference to meta data • UI control
Creating Lists and Screens • List • List CommList = new List("CommunicationList"); • Screen • EntryGroupcompGroup = new EntryGroup("companyboxlong");
Filtering of Lists • AddContent(HTML.Form()); • AddContent(HTML.StartTable()); • GetTabs(); • List CommList = new List("CommunicationList"); • CommList.RowsPerScreen = 4; • CommList.ShowNavigationButtons = false; • CommList.Filter = "cmli_comm_companyid =" + Dispatch.EitherField("key1"); • AddContent(HTML.GridData(CommList.ToHtml())); • AddContent(HTML.EndTable());
Controlling Positioning Using objects in the Sage.CRM.UI namespace
Use of Vertical Panel • using System; • using System.Collections.Generic; • using System.Text; • using Sage.CRM.WebObject; • using Sage.CRM.UI; • using Sage.CRM.Data; • using Sage.CRM.Controls; • namespace CRM62a • { • class OpportunityQuotes : Web • { • public override void BuildContents() • { • GetTabs(); • VerticalPanel vp = new VerticalPanel(); • vp.AddAttribute("width", "100%"); • Record oppRecord = FindCurrentRecord("Opportunity"); • EntryGroup oppScreen = new EntryGroup("OpportunityDetailBox"); • oppScreen.Title = "Opportunity Detail"; • oppScreen.Fill(oppRecord); • vp.Add(oppScreen); • List quotesGrid = new List("QuotesGrid"); • quotesGrid.SelectSql = "Select * From quotes"; • quotesGrid.Filter = "Quot_Opportunityid = " + oppRecord.GetFieldAsString("Oppo_OpportunityId"); • vp.Add(quotesGrid); • AddContent(vp); • } • } • }
Compounding Pages • When using Panels must convert to UI object • HorizontalPanel • VerticalPanel • VerticalPanel myPipeandList = new VerticalPanel(); • HTMLStringmyPipeLine = new HTMLString(); • myPipeLine.Html = myPipe.Execute(); • myPipeandList.Add(myPipeLine); • HorizontalPanel myListandFilter = new HorizontalPanel(); • EntryGroupoppoFilter = new EntryGroup("OpportunityFilterBox"); • HTMLStringFilterBoxHTML = new HTMLString(); • FilterBoxHTML.Html = oppoFilter.GetHtmlInEditMode(); • myListandFilter.Add(FilterBoxHTML);
Looking ahead to the classes • DP01: Introduction to the Development Partner Program • DP02: Entities and the Data Model (Part 1 of 2) • DP03: Entities and the Data Model (Part 2 of 2) • DP04: Implementing Screen Based Rules (Part 1 of 2) • DP05: Implementing Screen Based Rules (Part 2 of 2) • DP06: Screen and User Independent Business Rules • DP07: Workflow (Part 1 of 2) • DP08: Workflow (Part 2 of 2) • DP09: Using the API Objects in ASP Pages (Part 1 of 2) • DP10 : Using the API Objects in ASP Pages (Part 2 of 2) • DP11: Using the Component Manager • DP12: Programming for the Advanced Email Manager • DP13: Using the Web Services API • DP14: Using the Web Services API (Part 2 of 2) • DP15: Coding the Web Self Service COM API (Part 1 of 2) • DP16: Coding the Web Self Service COM API (Part 2 of 2) • DP17: Using the .NET API (Part 1 of 2) • DP18: Using the .NET API (Part 2 of 2)