Using the Web Services API (Part 2 of 2)

advertisement
Sage CRM Developers Course
Using the Web
Services 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
Web Services Data Tasks in Detail
Find
Update
Delete
Insert
Development and Integration Issues
Usage of Objects
and Functions
Data Objects
Methods
Query
queryentity
queryrecord
Query function
Arguments:
queryString: a SQL WHERE clause
entityname: the name of the target table
Returns a queryresult object
private void buttonSearchCompanyName_Click_1(object sender,
EventArgs e)
{
queryresult CRMQueryResult;
ewarebase[] CRMBase;
try
{
string strSQL = "comp_name like '" + textBoxSearch.Text + "%'";
MessageBox.Show(strSQL);
CRMQueryResult = CRMService.query(strSQL, "Company");
CRMBase = CRMQueryResult.records;
MessageBox.Show(CRMBase.Length.ToString());
for (int intCount = 0; intCount < CRMBase.Length; intCount++)
{
CRMCompany = (company)CRMBase[intCount];
listBoxCompanyNames.Items.Add(CRMCompany.name);
}
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
}
Usage: next()
queryresult myQueryResult = CRMService.query(“comp_name like ‘A%’
“,"company");
MessageBox.Show(myQueryResult.more.ToString());
if(myQueryResult.more)
{
myQueryResult = CRMService.next();
}
Usage: queryentity()
Arguments:
if (CRMPerson.personid == CRMCompany.primarypersonid)
id: integer, the ID value of the record being sought
{
entityname: the name of the target table
labelPers_LastName.Text = CRMPerson.lastname;
break;
Returns a queryentityresult object
}
}
private void buttonSearchCompanyID_Click(object sender, EventArgs e)
textBoxComp_Name.Text = CRMCompany.name;
{
textBoxComp_WebSite.Text = CRMCompany.website;
queryentityresult CRMEntityResult;
textboxComp_Companyid.Text = CRMCompany.companyid.ToString();
ewarebase CRMBase;
}
ewarebase[] CRMBase2;
catch (Exception exc)
ewarebaselist CRMCompanyPeople = new ewarebaselist();
{
person CRMPerson;
MessageBox.Show(exc.Message);
try
}
{
CRMEntityResult =
CRMService.queryentity(int.Parse(textBoxSearch.Text), "Company");
CRMBase = CRMEntityResult.records;
CRMCompany = (company)CRMBase;
CRMCompanyPeople = CRMCompany.people;
CRMBase2 = CRMCompanyPeople.records;
for (int intCount = 0; intCount < CRMBase2.Length; intCount++)
{
CRMPerson = (person)CRMBase2[intCount];
queryrecord method
Syntax
queryrecord ( fieldlist As string , queryString As string ,
entityname As string , orderby As string ) As queryrecordresult
Specify what fields are to be selected, a where clause and order
by, returns a list of CRMRecord objects
Notes:
Instead of querying an entity (for example, a company) and
getting back a strongly typed (company) object, using the
flexibility afforded by the crmrecordtype object, it is possible to
query an entity and get back a list of fields that you can iterate
through.
private void buttonQueryRecord_Click(object sender,
EventArgs e)
{
queryrecordresult myQueryRecordResult =
CRMService.queryrecord("comp_companyid, comp_name",
"comp_type='Customer'", "company", "comp_name");
crmrecord[] myRecordList = myQueryRecordResult.records;
for (int intCount = 0; intCount < myRecordList.Length;
intCount++)
{
recordfield[] myFieldList = myRecordList[intCount].records;
for (int intCount2 = 0; intCount2 < myFieldList.Length;
intCount2++)
{
recordfield myField = (recordfield)myFieldList[intCount2];
listBoxCompanyNames.Items.Add(myField.name + ": =" +
myField.value);
}
}
TabControl.SelectedTab = tabPage1;
}
Note: Fields list must include primary key.
Usage: nextqueryrecord()
queryrecordresult myQueryRecordResult =
CRMService.queryrecord("comp_companyid, comp_name",
"comp_type='Customer'", "company", "comp_name");
MessageBox.Show(myQueryRecordResult.more.ToString());
if(myQueryRecordResult.more)
{
myQueryRecordResult = CRMService.nextqueryrecord();
}
Working with Selection Lists
Syntax
getdropdownvalues ( entityname As string ) As dropdownvaluesresult
Returns the list of the drop-down fields in a table and the list of values that CRM expects for that field.
– CRM expects a given set of values for drop-down fields
– Must get these values programmatically.
Usage
dropdownvalues[] compDropDowns = CRMService.getdropdownvalues("company");
comboBox1.Items.Clear();
for (int i = 1; i < compDropDowns.Length; i++)
{
// MessageBox.Show(compDropDowns[i].fieldname);
if (compDropDowns[i].fieldname.ToString() == "source")
{
for (int x = 1; x < compDropDowns[i].records.Length; x++)
{
comboBox1.Items.Add(compDropDowns[i].records[x].ToString());
if (CRMCompany.source == compDropDowns[i].records[x].ToString())
{
comboBox1.SelectedIndex = x-1;
}
//MessageBox.Show(compDropDowns[i].records[x].ToString());
}
}
}
Update Method
Arguments:
entityname: string, the name of the target table
records: an ewarebase array instance
private void buttonSave_Click(object sender, EventArgs e)
{
ewarebase[] CRMBase;
updateresult CRMUpdateResult;
Returns an updateresult object
try
{
CRMBase = new ewarebase[1];
CRMCompany.companyid =
int.Parse(textboxComp_Companyid.Text);
CRMCompany.companyidSpecified = true;
CRMCompany.name = textBoxComp_Name.Text;
CRMCompany.website = textBoxComp_WebSite.Text;
CRMCompany.source = comboBox1.Text;
CRMBase[0] = CRMCompany;
CRMUpdateResult = CRMService.update("company", CRMBase);
MessageBox.Show("Record Updated");
}
catch (Exception exc)
{
MessageBox.Show(exc.Message);
}
}
Inserting Records
All inserts should typically be performed on an entity basis.
Can update a company (or person) with
– Address
– Phone
– E-mail information.
Facilitate integration
– In 3rd Party Systems, a single contact record may represent company, person, phone, email, and address information.
Types of Insert Task
Insert a Single Entity
Insert a Set of Entities
Insert a Single of Row in a Table
Insert a Set of Records in a Table
Migration Considerations
Insertion of new/unknown users
– addresource function
– Adds a user as a resource. This user is not a fully enabled user. The functionality exists purely to
facilitate data migration.
Differing Data Lengths
– altercolumnwidth function
– Used to resize a column width to ensure compatibility with third-party databases
Development and
Integration Issues
Integration Development Issues
Version Change
Has the implementation of Sage CRM been upgraded since the last synchronization?
– getversionstring
Handling Data Change
What data has changed since the last time synchronisation took place?
How do I match users from one system to another?
– queryid()
– queryidnodate()
– addresource()
Handling Application Change
What has changed about the data structures since last time synchronisation took
place?
– What if tables have been added?
– What if columns have been added?
– Do data field lengths match?
Handling Application Change
What has changed about the data structures since last time synchronisation took
place?
What if tables have been added?
What if columns have been added?
Do data field lengths match?
– altercolumnwidth()
WSDL Types
WSDL defines the Types and Methods exposed
In .NET the objects exposed by WSDL are strongly typed representations
Example
Company entity has
– Name
– Status
– Etc
In referencing WSDL the Company’s properties are fixed.
Problems may occur post compilation if columns are removed or added to Entity or new
Entities included
Significant Issues
facing Developers are…
Any Live CRM Implementation is likely to change
Strongly Type representations cause issues for 3rd party applications
Especially true for Hosted Environment
Requirement to have access to dynamic information about data model, available
entities and columns
Metadata exposed via getmetadata and getallmetadata methods
Using SData
New features depend on Tomcat
Sage CRM v7.2
Tomcat is Used By
The ReadOnly SData Provider
The Interactive Dashboard
Exchange Integration
Sage E-marketing
Data Import and Export
Document drop panel
Server Side Mail Merge
Other Java based features
include the spell checker and the
printing to PDF.
These requires a set of
supporting technologies.
Google Web Tool Kit
– http://code.google.com/webtoolkit/
Apache Tomcat
– http://tomcat.apache.org/
Spring Framework
– http://www.springsource.org/
Hibernate
– https://www.hibernate.org/
What is SData?
http://sdata.sage.com
SData (Sage Standard)
Enables desktop, server, and web-based Sage applications to communicate with each
other as well as third-party applications and the Web.
SData is built on top of leading industry standards including HTTP, XML, REST, and
Atom/RSS
– Representational state transfer (REST)
The full standard covers basic reading, writing, updating and deleting of data between and
across products as well as more complex functions such as synchronisation of data,
security, discoverability of services, single sign-on, error handling, and paging and batching
of information for increased performance.
SData Provider within Sage CRM
SDATA is based on RESTful principles.
HTTP Method
Sage CRM can consume SData feeds
within the Interactive Dashboard
https://sdata.showcase.sage.com/sdata/acc
ounts50/SDO/-/$schema
Implied Data
Interaction
GET
Query the state
POST
Modify the state
PUT
Create Data
DELETE
Delete Data
Sage CRM’s implementation of SData
Provider
Certain entities and views from Sage CRM
will be exposed using the SData standard
– An XSD Schema definition is available
– lists the available entities, fields, and views
– It will be read-only and will get updated /
refreshed if custom entities are added or
deleted or if other changes are made to
exposed entities
In version Sage CRM v7.x only GET is
available for 3rd Party Developers
SQL
REST
Create
Insert
PUT
Read
Select
GET
Update
Update
POST
Delete
Delete/Drop
DELETE
Sage CRM SData plays “Nice”
Structure of a RESTful URI
https://server.domain.com/rest/resource/search?q=rest&start=10#1
–
–
–
–
–
URI scheme
Authority
Path
Query
Fragment
Sage CRM
– http://[servername]/sdata/[installname]j/sagecrm/-/person?where=lower(pers_firstname) like 'william%'
“Nice” URI are
Short
Use Nouns rather than Verbs
Example Read Only Sage CRM SData
Requests
SData Queries
Queries support “order by” and “filtering”
All fields are returned by default
Pattern
http://myserver/sdata/installnamej/sagecrm/-/entity
Examples
http://myserver/sdata/crmj/sagecrm/-/company/$schema
http://myserver/sdata/crmj/sagecrm/-/company('43')
http://myserver/sdata/crmj/sagecrm/-/company?where=comp_companyid in ('43', '45')
http://myserver/sdata/crmj/sagecrm/-/company('43')?include=person
http://myserver/sdata/crmj/sagecrm/-/company(comp_companyid eq '962')
http://myserver/sdata/crmj/sagecrm/-/person?where=lower(pers_firstname) like 'william%'
Security and Firewalls
SData
Web Services
Access to data is controlled by the user's security profile and
territory rights.
Access to data is controlled by the user's security
profile and territory rights.
Access does not use the eware.dll to create the session and
access is NOT logged in the user activity tables within CRM.
Read Only requests use HTTP GET Method
This works well with network firewalls.
Some firewalls of HTTP proxies may drop PUT/DELETE requests therefore not
all VERBS may be used as CRUD capability is developed. Restriction will be
overcome using the override call. See:
http://interop.sage.com/daisy/sdata/UpdateOperation/Example.html
Web Services access because it requires a user
session to be created it automatically logged in the
user activity tables within CRM.
Requests use HTTP POST Method.
This works well with network firewalls.
This means that the web service client accessing CRM can be
beyond the corporate Firewall.
Relative Performance
SData
Web Services
It’s fast!
A message is posted to
http://[servername]/[installname]/eware.dll/Web
Services/SOAP
http://[servername]/sdata/[installname]j/sagecr
m/-/person?where=lower(pers_firstname) like
'william%'
Request routed to Tomcat. Single SQL
statement. And XML sent back.
Message has to be parsed and ‘unpacked’
Need to think hard about methods used.
Then is turned by DLL into a series of SQL statements,
the return XML is assembled and a response is issued.
Interaction with Security
SData
Web Services
User security profile rights apply. This limits
access to rows within entities and views.
User security profile rights apply. This limits
access to rows within entities and views.
Field Level security applies. This limits
columns returned.
Field Level security applies. This limits
columns returned.
Within external applications the dynamically
constructed feed will need to be handled.
Within external applications strongly typed
objects can create its own issues. Can use
getmetadata(), getallmetadata() and record()
methods to discover dynamic information.
Can not assume column returned or data source available.
Information contained in Schema
– http://[servername]/sdata/[installname]j/sagecrm/-/$schema
– http://[servername]/sdata/[installname]j/sagecrm//company/$schema
Creating Sessions
SData
Web Services
Any User can access SData. What they see is subject
to rights.
Only Users enabled can access via Web Service.
All requests must be authenticated
Web Services are Session based similar to interactive
user logons
using HTTP Basic authentication.
Web Service usage shows in Activity Reports
Access controlled by security profiles and field
Activity table
SysAdmin
Locking
Sage CRM 7.x does not advertise supported
authentication methods via the usual WWWAuthenticate response header. You need to perform a
pre-emptive authentication.
The SData in the
Interactive Dashboard
Sage CRM 7.x & SData
Sage CRM consumes SData feeds within the Interactive Dashboard
http://[server]:[port]/sdata/X32CRM/GCRM_1_1_1/X3DEMO/$schema
http://[server]/SDataServlet/sdata/sageERP/accpac/SAMINC/$schema
Sage CRM’s implementation of SData Provider
Entities and views from Sage CRM will be exposed using the SData standard
– An XSD Schema definition is available
– lists the available entities, fields, and views
– It will be read-only and will get updated / refreshed if custom entities are added or deleted
or if other changes are made to exposed entities
Making a ‘User View’ Available for SData Access
Only User views.
Core and System can not be changed
The View can then be accessed like a table.
http://myserver/sdata/crmj/sagecrm/-/vOppoDatesOpen
Internal SData Feeds
SData capabilities using external
ERP data
Create a Pre-defined
SData feed Template
Create a Pre-defined Sdata feed Template
Storing the User name and password for
the feed in the SData Feed Template
definition means that there isn't a
requirement anymore for an Admin to
provide Users with complicated SData
schema URLs and authentication details
every time they create a new SData
Gadget.
SData Gadget Filters
SData Record Summary
Can add a SData Record Summary and link to existing SData feed.
SData Gadget Restrictions
Limited use within company dashboard
Will not filter by comp_companyid
Can not link between SData and Non SData Gadgets
EXTERNAL USE OF SDATA
FEEDS
Sage CRM v7.1 SData Authentication
Schema requests do not require authentication, so they will show all possible data
fields.
http://[servername]/sdata/[installname]j/sagecrm/-/$schema
http://[servername]/sdata/[installname]j/sagecrm/-/company/$schema
To make an actual data request Sage CRM 7.x does not advertise supported
authentication methods via the usual WWW-Authenticate response header. The
programmer needs to perform a pre-emptive authentication.
This javascript code snippet shows how authentication can be carried out.
SID (Session ID) can be used in SData
Requests from Sage CRM v7.1
<script>
function GetKeyValue(querystringname)
{
var strPath = window.location.search.substring(1);
var arrayKeys = strPath.split("&");
for (var i=0;i<arrayKeys.length;i++)
{
var arrayValue = arrayKeys[i].split("=");
if (arrayValue[0].toLowerCase()== querystringname.toLowerCase())
{
return arrayValue[1];
}
}
return "";
}
window.alert("start:"+GetKeyValue("SID"));
XmlHttp = new XMLHttpRequest();
var strURL = "http://richardsj-lt/sdata/crm71j/sagecrm//company?where=comp_companyid in ('43',
'45')&SID="+GetKeyValue("SID");
XmlHttp.open('GET',strURL,false);
window.alert("open");
XmlHttp.send(null);
window.alert("send");
var strHtml = XmlHttp.responseText;
XmlHttp=null; // always clear the XmlHttp object when you are done to
avoid memory leaks
window.alert("test:"+strHtml);
window.alert("end");
</script>
http://[servername]/sdata/[installname]j/s
agecrm/-/company('43')&SID=
61546204736053
Fast SData requests can now be used for
AJAX in Custom Content and onChange
scripts
Simple SData Ajax ReadOnly
Fetches in Sage CRM v7.2
var personID = crm.fields("oppo_primarypersonid").value();
var accountID = crm.fields("oppo_primaryaccountid").value();
var successPerson = function (crmRecord) {
crm.infoMessage("This opportunity belongs to :" + crmRecord.pers_firstname + " " + crmRecord.pers_lastname);
}
var successAccount = function (crmRecord) {
crm.infoMessage("This opportunity belongs to :" + crmRecord.acc_name);
}
crm.sdata({
entity: "person",
id: personID,
success: successPerson
});
crm.sdata({
entity: "account",
id: accountID,
success: successAccount
});
External Development
Web Self Service Extensions
Self Service can use both SOAP and
SData feeds but this integration has to
be managed by the Developer.
– Visitor vs User
Using SData in 3rd Party Access
Excel can consume XML
http://stl00539/sdata/crmj/sagecrm//opportunity?SID=161980816526651
Q&A
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)
Download