AIF Document/Interface Development

Report
Dynamics AX TAP
Knowledge
Transfer
Wave 2
Application Integration
Framework (AIF)
Document/Interface Development
Søren Vagn Andersen
Program Manager
Microsoft Dynamics AX
Agenda
Extensibility Model
XML Document Structure
Key Concepts
Implementing New Documents
Sending Documents
Advanced Topics
Supported XML Documents
Trade
Price List [out]
Price/Discount Agreement [in]
Purchase Order [out]
Sales Order [in]
Picking List [out]
Packing Slip [in]
Advance Ship Notice [out]
Sales Invoice [out]
Purchase Invoice [in]
Free Text Invoice [in]
Finance
Exchange Rates [out,in]
GL Chart of Accounts [out,in]
GL Dimensions [out,in]
Inventory
Inventory Counting Journal [in]
Inventory Transfer Journal [in]
Inventory Balances [out]
Inventory Transactions [out]
Inventory Profit/Loss Journal [in]
XML Document Development
Model driven approach
Focus on data and business logic
Customizations handled (almost)
automatically
Generalized framework
Tools support
Wizard for generating class skeletons
Best practice check to detect data model
changes
Model Driven Approach
Axd<Document> query defines
XML structure and content
SalesTable
SalesLine
Axd<Document>
class performs
serialization and
de-serialization
XML
HOW ?
...
...
DB
Ax<Table> classes manage data access
Agenda
Extensibility Model
XML Document Structure
Key Concepts
Implementing New Documents
Sending Documents
Advanced Topics
XML Schema Structure
<?xml version="1.0" encoding="utf-16"?>
<SalesOrder
xmlns="http://schemas.microsoft.com/dynamics/">
<DocPurpose>Original</DocPurpose>
<SenderId>dmo</SenderId>
Empty
Hidden
<SalesTable class="entity">
<CaseTagging>No</CaseTagging>
<CovStatus>1</CovStatus>
<CurrencyCode>EUR</CurrencyCode>
<CustAccount>4020</CustAccount>
Parm<Property>()
methods on
Axd<Document>
class
<SalesLine class="entity">
<Blocked>No</Blocked>
<CaseTagging>No</CaseTagging>
<Complete>No</Complete>
<CurrencyCode>EUR</CurrencyCode>
...
<InventDim class="entity">…</InventDim>
</SalesLine>
<DocuRefHeader class="entity">…</DocuRefHeader>
<DocuRefHeader class="entity">…</DocuRefHeader>
</SalesTable>
</SalesOrder>
Serialization Strategy
Serialize parm<Property>() methods on the
Axd<Document> class
Read data using Ax<Table> class, if present
Read directly from table, if no Ax<Table> class
Field list on Axd<Document> query controls what
fields are serialized
If Ax<Table> exists, only fields with parm<Field>()
method on Ax<Table> class
Calculated fields (display fields) are always serialized
Mapping Simple Datatypes
X++ Datatype
XSD Type
String
xsd:string, maxLength=StringSize
(maxLength=max(StringSize,50) in case of
value mapping)
xsd:int
xsd:time, ISO format: HH:MM:SS
(Time stamp if global::isTypeTime is true)
xsd:long
xsd:decimal, fractionDigits=NoOfDecimals
xsd:date, ISO format: YYYY-MM-DD
xsd:string, enumeration=<EnumName>, ...
xsd:string, pattern=’[0-9A-Fa-f]{8}-...’
xsd:string, Base64 encoded
Integer
Integer
Int64
Real
Date
Enum
GUID
BLOB
Arrays
All elements are serialized
<Dimension>
<element>Department</element>
<element>Cost Center</element>
<element>Purpose</element>
</Dimension>
Null Values
Outbound
Null values are not serialized
Arrays may contain empty elements
Inbound
Empty string elements interpreted as
zero-length string, not null
Use <element xsi:nil=”true”/> to specify
null value
Security
Respects Microsoft Dynamics AX security
Security keys
Record level security
MaxAccessMode property
AllowEditOnCreate property
Visible property
No access to system tables
SystemTable=Yes
TableType≠Table
Agenda
Extensibility Model
XML Document Structure
Key Concepts
Implementing New Documents
Sending Documents
Advanced Topics
Axd<Document> Query
Describes structure of XML document
Controls amount of data retrieved from
Microsoft Dynamics AX
Disabled fields and data sources are
excluded from Schema
Only one (1) ”root” data source allowed
Same name as Axd class
Work Tables and Journals
Posting
XML
PurchTable
VendPurchOrderJour
Read from
journals
Insert into
work tables
PurchLine
VendPurchOrderTrans
XML
Documents With Header/Lines
Header = ”Root” data source
SalesTable
SalesLine
Lines
Notes at both header and lines
Axd<Document> Classes
Service classes
Implement AifServiceable interface
Expose document actions
Validation of entire document, e.g.
Cross-table dependencies
Document life-cycle constraints
May invoke business logic
Posting
Ax<Table> Classes
1-to-1 relationship with tables
Name derived from table, e.g. AxSalesLine
parm<Field>() method for each field
Defaulting of fields with no values
Validation of fields with respect to, e.g.
Referential integrity
Number sequences
Business logic
Value mapping of specific fields
Also used by other modules
Enterprise Portal
...
Class Hierarchy
AifServiceable
AxdBase
Axd<Document>
Axd<Document>
+getActionList()
?
Action
AxInternalBase
Axd<Document> Method
SendDocument
Table
Ax<Table>XML read(entityKey, ...)
ReceiveDocument
entityKey create(XML, ...)
...
...
Action
Axd<Document> Method
SendDocument
XML read(entityKey, ...)
Generate XML document identified
by entity key
SendDocumentList
XML readList(entityKeyList, ...)
Generate list of XML documents
each identified by entity key
QueryDocuments
XML findList(queryCriteria, ...)
Generate list of XML documents
matching query criteria
QueryEntityKeys
Generate list of entity keys for XML
documents matching query criteria
ReceiveDocument
entityKeyList
findEntityKeyList(queryCriteria, ...)
entityKey create(XML, ...)
Parse XML document and write data
to database
ReceiveDocumentList
Parse list of XML documents and
write data to database
entityKeyList createList(XML, ...)
Entity Keys
Identify specific document instance
Table
(Field, Value) pairs for primary keys
Use entity keys returned by AIF
Table
Must be ”root” data source in query
Use ID in X++
Not needed in XML / Web Client
Field
Use ID in X++
Use Field Name in XML / Web Client
Using Entity Keys
XML
<?xml version="1.0" encoding="utf-8" ?>
<Envelope xmlns="http://schemas.microsoft.com/dynamics/2005/12/documents">
<Header>
…
<Action>readInventSum</action>
Action
</Header>
<Body>
<EntityKey>
<KeyData>
Entity Key
<KeyField>
<Field>ItemId</Field>
<Value>B-R12</Value>
</KeyField>
<KeyField>
<Field>InventDimId</Field>
<Value>00001_060</Value>
</KeyField>
</KeyData>
</EntityKey>
</Body>
</Envelope>
Using Entity Keys
Web Services
Create entity key object
//Set the Enity Key
EntityKey entityKey = new EntityKey();
entityKey.KeyData = new KeyField[2] { new KeyField(),
new KeyField() };
entityKey.KeyData[0].Field = "ItemId";
entityKey.KeyData[0].Value = "B-R12";
entityKey.KeyData[1].Field = "InventDimId";
entityKey.KeyData[1].Value = "00001_060";
Populate entity key
Query Criteria
Similar to entity keys
Criteria for identifying range of documents
List of
Table
Field
Operator
Operand1
Operand2 (optional; operator dependent)
Table must be ”root” data source or
inner-joined with ”root” data source
Query must not contain hidden or locked range for
<Table>.<Field>
Valid Operators
X++ Operator
==
!=
>
>=
<
<=
..
XML Enumeration # of Operands
Equals
1
NotEquals
1
GreaterThan
1
GreaterThanEqual
1
s
LessThan
1
LessThanEquals
1
Range
2
Using Query Criteria
<?xml version="1.0" encoding="utf-8" ?>
<Envelope xmlns="http://schemas.microsoft.com/dynamics/2005/12/documents">
<Header>
…
<Action>findListSalesOrder</action>
Action
</Header>
<Body>
Query
<QueryCriteria>
<CriteriaElement>
criteria
<DataSourceName>SalesTable</DataSourceName>
<FieldName>CustAccount</FieldName>
<Operator>Range</Operator>
<Value1>4000</Value1>
<Value2>4020</Value2>
</CriteriaElement>
<CriteriaElement>
<DataSourceName>SalesTable</DataSourceName>
<FieldName>CurrencyCode</FieldName>
<Operator>Equals</Operator>
<Value1>USD</Value1>
</CriteriaElement>
</QueryCriteria>
</Body>
</Envelope>
Constraints
Enables the AIF to make decisions based
on document contents
Routing
Security (to prevent spoofing)
Constraint types
Customer
Vendor
Warehouse
Constraint Based Routing
EndpointA
Microsoft Dynamics AX

EndpointB
PurchaseOrder1
[3001,3004]
[3001]
PurchaseOrder2
[3004]
XML
[3001]

EndpointC
[3000,3001]
EndpointD
[3001,3002,3004]
EndpointE
[No Constraints]
Constraint Based Security
EndpointA
[4000]
Microsoft Dynamics AX


SalesOrder1
[4000]
SalesOrder2
[4002]
XML
EndpointB
[4000,4002]
EndpointC
[4000,4012]
EndpointD
[4000,4002,4012]
EndpointE
[No Constraints]
Agenda
Extensibility Model
XML Document Structure
Key Concepts
Implementing New Documents
Sending Documents
Advanced Topics
Axd<Document> TO DO’s
... in code generated by the Axd Wizard
getLabel()
getActionList()
initQueryFromEntityKey(),
initQueryFromQuery()
Validate entity key contents
Update query based on configuration settings
prepareForSave()
Validate data across tables
Provide defaults for document
getConstraintList()
Identify document constraints
Update Query
Example: AxdSalesInvoice
public void initQueryFromEntityKey(AifEntityKey _aifEntityKey = null,
boolean _validateEntityKey = false)
{
QueryBuildDataSource
qbdsFormLetterRem;
...
//Disable FormLetterRemarks if no remarks for sales invoice.
if (!(select formLetterRemarks where
formLetterRemarks.FormLetter ==
FormTextType::SalesInvoice).RecId)
{
qbdsFormLetterRem =
query.dataSourceTable(tablenum(formLetterRemarks),1);
qbdsFormLetterRem.enabled(false);
qbdsFormLetterRem =
query.dataSourceTable(tablenum(formLetterRemarks),2);
if (qbdsFormLetterRem)
{
qbdsFormLetterRem.enabled(false);
}
}
Disable data sources not needed
}
Document Validation/Defaulting
Example: AxdSalesOrder
public boolean prepareForSave(AxdStack _axdStack,
str _dataSourceName)
{
AxSalesTable
axSalesTable;
...
Verify
;
switch (classidget(_axdStack.top()))
{
case classnum(AxSalesTable) :
axSalesTable = _axdStack.top();
this.checkSalesTable(axSalesTable);
that elements
required by document
are provided
axSalesTable.parmSalesType(this.salesType());
...
}
...
}
Set default order type
Document Validation Logic
Example: AxdSalesOrder
private void checkSalesTable(AxSalesTable _axSalesTable)
{
;
if (!_axSalesTable.parmDeliveryDate())
{
error(strfmt("@SYS88971"));
}
if (!_axSalesTable.parmCustAccount())
{
error(strfmt("@SYS88972"));
}
if (!_axSalesTable.parmPurchOrderFormNum())
{
error(strfmt("@SYS88973"));
}
}
Verify that values
are provide
Document Defaults As Parameters
Example: AxdSalesOrder
protected SalesType salesType()
{
;
switch (AxdDocumentParameters::find().SalesType)
{
case AxdSalesType::Journal :
return SalesType::Journal;
case AxdSalesType::Sales :
return SalesType::Sales;
}
return SalesType::Journal;
}
Identifying Constraints
Example: AxdSalesOrder
public void getConstraintList(Common _curRec,
AifConstraintList _constraintList)
{
AifConstraint
aifConstraint = new AifConstraint();
SalesTable
salesTable;
;
if (_curRec.TableId != tablenum(SalesTable))
{
throw error(strfmt("@SYS23396",funcname()));
}
Constraint = Customer ID
salesTable = _curRec ;
aifConstraint.parmId(salesTable.CustAccount);
aifConstraint.parmType(AIFConstraintType::Customer);
_constraintList.addConstraint(aifConstraint) ;
}
Add constraint to list
Ax<Table> TO DO’s
... in code generated by the Axd Wizard
Implement defaulting logic
Add to set<Field>() methods
Add parm<Field>() methods for calculated
fields (display fields)
Implement caching as appropriate
Use cacheObject() as skeleton for objects
Use cacheRecordRecord() as skeleton for
records
Resolving Defaulting Logic
Example: SalesTable.CashDisc
void initInvoiceAccount()
{
CustTable
custTable;
;
custTable = this.custTable_InvoiceAccount();
this.NumberSequenceGroup
this.Payment
this.initFromPayment();
if (custTable.PaymSched)
{
this.PaymentSched
}
this.PaymMode
this.PaymSpec
this.CashDisc
this.setListCode();
}
= custTable.NumberSequenceGroup;
= custTable.PaymTermId;
= custTable.PaymSched;
= custTable.PaymMode;
= custTable.PaymSpec;
= custTable.CashDisc;
CashDisc is defaulted from CustTable
Ax<Table> Defaulting Logic
Example: AxSalesTable.setCashDisc()
protected void setCashDisc()
{
if (this.isMethodExecuted(funcname(),
fieldnum(SalesTable, CashDisc)))
{
return; Make sure the invoice account is set
}
this.setInvoiceAccount();
Default CashDisc from (cached) custome
record associated with the invoice accou
if (this.isFieldSet(fieldnum(SalesTable, InvoiceAccount)))
{
this.parmCashDisc(this.invoiceAccount_CustTableRecord().CashDisc);
}
}
Calculated (Display) Fields
Typically method on table
parm<Field>() method on Ax<Table> class
Always included in XML schema
Always serialized
Read-only
Can not be mandatory
Ax<Table> Class Performance
Caching Frequently Used Data
Avoid duplicate database lookups
Cache table variables
Cache Ax<Table> classes
Axd Wizard generates code templates
Copy for each table variable/Ax<Table> class
Search/replace table variable/class name
Use cache for data lookup
Caching Table Variables
Example: AxSalesLine
public InventTable inventTableRecord(InventTable _inventTable = null)
{
InventTable
inventTable;
Insert
in cache
if (!inventTableIdx)
{
inventTableIdx = this.nextCacheIdx();
}
if (!prmisdefault(_inventTable))
{
this.tableCacheInsert(inventTableIdx, _inventTable);
inventTable = _inventTable;
}
else
{
if (this.tableCacheExist(inventTableIdx))
{
inventTable = this.tableCacheLookup(inventTableIdx);
}
else
{
this.setInventTableRecordFields();
inventTable = InventTable::find(this.parmItemId());
this.tableCacheInsert(inventTableIdx, inventTable);
}
}
return inventTable;
Lookup record
in cache
}
Lookup record and insert in cache
Using Cached Table Variables
Example: AxSalesLine
protected void setSalesUnit()
{
if (this.isMethodExecuted(funcname(),
fieldnum(SalesLine, SalesUnit)))
{
return;
}
this.setInventTableRecordFields();
if (this.isInventTableRecordFieldsSet())
{
this.parmSalesUnit(this.inventTableRecord().salesUnitId());
}
}
Lookup inventTable in cache
Best Practices
Don’t override AxdBase.getName()
Be careful with inner joins
Use FetchMode=1:n for outer joins
Watch out for display fields
Agenda
Extensibility Model
XML Document Structure
Key Concepts
Implementing New Documents
Sending Documents
Advanced Topics
Enabling The Application
Send Electronically
Calling the AIF Send Service
Using the Send Framework
Integrating with exising business logic, e.g.
posting routines
”Send Electronically” Button
Example: VendPurchOrderJour form
void clicked()
{
VendPurchOrderJour vendPurchOrderJourLocal;
;
for (vendPurchOrderJourLocal = vendPurchOrderJour_ds.getFirst(true) ?
vendPurchOrderJour_ds.getFirst(true) :
vendPurchOrderJour;
vendPurchOrderJourLocal;
vendPurchOrderJourLocal = vendPurchOrderJour_ds.getNext())
{
vendPurchOrderJourLocal.sendElectronically(XMLDocPurpose::Original);
}
super();
}
Original
Calling The AIF Send Service
void sendElectronically(XMLDocPurpose _xMLDocPurpose,
AifSendMode _aifSendMode = AifSendMode::Async)
{
AxdSendContext
axdSendContext
= AxdSendContext::construct();
AifEntityKey
aifEntityKey
= AifEntityKey::construct();
Map
keyData;
AifConstraintList
aifConstraintList
= new AifConstraintList();
AifConstraint
aifConstraint
= new AifConstraint();
;
keyData = SysDictTable::getKeyData(this);
Create entity
aifEntityKey.parmTableId(this.TableId);
key
aifEntityKey.parmRecId(this.RecId);
Establish
aifEntityKey.parmKeyDataMap(keyData);
document
axdSendContext.parmXMLDocPurpose(_xMLDocPurpose);
context
axdSendContext.parmSecurity(false);
aifConstraint.parmType(AifConstraintType::Vendor) ;
aifConstraint.parmId(this.OrderAccount) ;
aifConstraintList.addConstraint(aifConstraint) ;
AifSendService::submitDefault(
classnum(AxdPurchaseRequisition),
aifEntityKey,
aifConstraintList,
_aifSendMode,
axdSendContext.pack());
}
Identify
constraint
s
Call AIF Send
Service
(”send and forget”)
Send Framework
Example: General Ledger > Chart of Accounts
Select target endpoints
Select which documents
(here: accounts) to send
Using the Send Framework
Example: AxdSendChartofAccounts
class AxdSendChartofAccounts extends AxdSend
{
}
static public void main(Args args)
{
AxdSendChartofAccounts
axdSendChartofAccounts ;
AifConstraintList
aifConstraintList;
AifConstraint
aifConstraint;
;
axdSendChartofAccounts
aifConstraintList
aifConstraint
= new AxdSendChartofAccounts();
= new AifConstraintList();
= new AifConstraint();
aifConstraint.parmType(AifConstraintType::NoConstraint);
aifConstraintList.addConstraint(aifConstraint);
axdSendChartofAccounts.parmShowDocPurpose(true) ;
Configure
form
axdSendChartofAccounts.sendMultipleDocuments(classnum(AxdChartOfAccounts),
AifSendMode::Async,
aifConstraintList);
}
Invoke Send
Sending As Part Of Posting
Example: PurchFormLetter_PurchOrder
void printJournal()
{
if (journalList.len() > 0)
{
if (printFormletter)
{
this.sendAsXML();
Send document
before printing
vendPurchOrderJour.printJournal(this, journalList);
}
if (this.proforma())
{
this.removeProforma();
}
}
}
Sending As Part Of Posting
Example: PurchFormLetter_PurchOrder
protected void sendAsXML()
{
boolean
newLine;
}
if (new PrintJobSettings(printerSettingsFormletter,
true).getTarget() !=
PrintMedium::Screen && !this.proforma())
{
newLine = journalList.first(vendPurchOrderJour);
while (newLine)
{
vendPurchOrderJour.sendElectronically(XMLDocPurpose::Original);
newLine = journalList.next(vendPurchOrderJour);
}
}
Same method as invoked
from ”Send Electronically”
Button
Agenda
Extensibility Model
XML Document Structure
Key Concepts
Implementing New Documents
Sending Documents
Advanced Topics
Mandatory Fields
... or Required Elements?
Mandatory Field
Field that must contain a value when a record is
inserted into the Microsoft Dynamics AX
database, e.g. SalesTable.SalesId
Required Element
Element required to be present in the XML
document to satisfy the schema, e.g.
<DeliveryDate> on a Sales Order
Required Elements
An XML element is required when
Element is required by Axd<Document> class
OR
Field is mandatory on table
AND
Field value can not be defaulted
Mandatory Fields
Example: Sales Order
SalesTable
CurrencyCode
CustAccount
CustGroup
InvoiceAccount
LanguageId
SalesId
ShippingDateRequested
SalesLine
CurrencyCode
CustAccount
CustGroup
ItemId
ShippingDateRequested
Defaulting Mandatory Fields
Example: AxSalesTable
protected void initMandatoryFieldsExemptionList()
{
Register field as not required
super();
Override
this.setParmMethodAsNotMandatory(methodstr(AxSalesTable,
parmSalesId));
this.setParmMethodAsNotMandatory(methodstr(AxSalesTable,
parmInvoiceAccount));
this.setParmMethodAsNotMandatory(methodstr(AxSalesTable,
parmCustGroup));
this.setParmMethodAsNotMandatory(methodstr(AxSalesTable,
parmLanguageId));
this.setParmMethodAsNotMandatory(methodstr(AxSalesTable,
parmShippingDateRequested));
}
Required By Axd<Document> Class
Example: AxdSalesOrder
protected void initMandatoryFieldsMap()
{
Register field as required
super();
Override
this.setParmMethodAsMandatory(classnum(AxSalesLine),
methodstr(AxSalesLine,parmSalesQty));
this.setParmMethodAsMandatory(classnum(AxSalesLine),
methodstr(AxSalesLine,parmSalesUnit));
this.setParmMethodAsMandatory(classnum(AxSalesTable),
methodstr(AxSalesTable,parmPurchOrderFormNum));
this.setParmMethodAsMandatory(classnum(AxSalesTable),
methodstr(AxSalesTable,parmDeliveryDate));
}
Inventory Dimensions
<SalesLine class=”entity”>
...
<ItemId>CL-100B</ItemId>
...
<InventDim class="entity">
<inventColorId>Gold</inventColorId>
<inventSizeId>30</inventSizeId>
</InventDim>
...
</SalesLine>
InventDim.inventDimId = 00003_060
AxInventDim_<ParentTable>
Example: AxInventDim_SalesLine
class AxInventDim_SalesLine extends AxInventDim
{
Class is specific
AxSalesLine axSalesLine;
SalesLine
}
to
public static AxInventDim_SalesLine
newAxSalesLine(AxSalesLine _axSalesLine)
{
AxInventDim_SalesLine
axInventDim_SalesLine;
;
axInventDim_SalesLine = new AxInventDim_SalesLine();
axInventDim_SalesLine.axSalesLine(_axSalesLine);
return axInventDim_SalesLine;
Register parent
}
SalesLine
public void save()
Update SalesLine instead
{
of saving InventDim
;
record
axSalesLine.updateFromInventDim();
}
AxInventDim_<ParentTable>
Example: AxSalesLine.updateFromInventDim
public void updateFromInventDim()
{
ttsbegin;
runState
= AxBCRunState::Save;
fieldModified
= new Set(Types::Integer);
this.initRecord();
this.inputStatus(InternalExternal::Internal);
Invoke defaulting logic
this.setInventDimId();
inventDimIdDirtySaved = false; SalesLine.InventDimId
this.validateFields();
this.validateWrite();
Re-validate data
Update SalesLine
this.write();
SalesLine.InventDimId
this.resetInternalValues();
ttscommit;
}
for
Document References (Notes)
Accounts Receivable > Setup > Forms > Form Setup
Control whether
document references
are included in
XML document
Configuring Document References
Example: AxdSalesOrder
Disable data sources depending on value
of ”Include documents on sheet”
Select configured document type
Allow only ”external” notes
public void initQueryFromEntityKey(AifEntityKey _aifEntityKey,
boolean _validateEntityKey)
{
super(_aifEntityKey, _validateEntityKey);
this.docuRefEnabling();
}
Disabling DocuRef Data Sources
Example: AxdSalesOrder
protected void docuRefEnabling()
{
CustFormLetterDocument custFormLetterDocument;
void disableDocuRef(tableId _tableId)
{ ... }
;
custFormLetterDocument = CustFormLetterDocument::find();
switch (custFormLetterDocument.DocuOnConfirm)
{
case DocuOnFormular::Head:
disableDocuRef(tablenum(SalesLine));
break;
case DocuOnFormular::Line:
disableDocuRef(tablenum(SalesTable));
break;
case DocuOnFormular::None:
disableDocuRef(tablenum(SalesTable));
disableDocuRef(tablenum(SalesLine));
}
...
}
Selecting Correct DocuRef Type
Example: AxdSalesOrder
protected void docuRefEnabling()
{
CustFormLetterDocument custFormLetterDocument;
void disableDocuRef(tableId _tableId)
{ ... }
;
custFormLetterDocument = CustFormLetterDocument::find();
switch (custFormLetterDocument.DocuOnConfirm)
{
...
}
query.dataSourceTable(tablenum(DocuRef),1).
findRange(fieldnum(DocuRef,TypeId)).
value(custFormLetterDocument.DocuTypeConfirm);
query.dataSourceTable(tablenum(DocuRef),2).
findRange(fieldnum(DocuRef,TypeId)).
value(custFormLetterDocument.DocuTypeConfirm);
}
Allow Only External DocuRef Notes
Example: AxdSalesOrder
Only external notes
Place restriction
on data source
in query
Make sure the
range is locked!
Multiple Constraints
EndpointA
Microsoft Dynamics AX

EndpointB
PickingList1
[WH1,WH2]
[WH1,WH2]
PickingList2
[WH1]
XML
[WH1]

EndpointC
[WH2,WH3]
EndpointD
[WH1,WH2,WH4]
EndpointE
[No Constraints]
Multiple Constraints
Example: AxdPickingList
class AxdPickingList extends AxdBase
{
AifConstraintList
aifConstraintList;
}
public void getConstraintList(Common _common,
AifConstraintList _constraintList)
{
int
i ;
int
noOfConstraints ;
;
noOfConstraints = aifConstraintList.getConstraintCount() ;
for(i=1 ;i <= noOfConstraints; i++)
{
_constraintList.addConstraint(aifConstraintList.getConstraint(i);
}
Copy constraints identified
}
while processing document
Multiple Constraints
Example: AxdPickingList
public void processingRecord(Common common)
{
AIFConstraint
AIFConstraint ; Called for every data
InventDim
inventDim ;
source
;
if (common.TableId == tablenum(InventDim))
{
inventDim = common ;
AIFConstraint = new AIFConstraint();
if (inventDim.InventLocationId)
{
AIFConstraint.parmType(AifConstraintType::Warehouse) ;
AIFConstraint.parmId(inventDim.InventLocationId) ;
}
else
Identify constraint
{
AIFConstraint.parmType(AifConstraintType::NotSet ) ;
}
aifConstraintList.addConstraint(AIFConstraint) ;
}
Add constraint to list
}
Exposing Calculated Data
Problem:
The data to be read is not readily available
in Microsoft Dynamics AX
Solution
Create Axd<Document> query with temporary
table as data source
Make Axd<Document> class generate data in
temporary table
Generating Data In Temporary Table
Example: AxdPriceList
class AxdPricelist extends AxdBase
{
...
PriceDiscTmpPrintout
priceDiscTmpPrintout;
}
void prepareForQuery(QueryRun _queryRun)
{
;
Run before seriallization
and after de-serialization
select firstonly priceDiscTmpPrintout;
if(!priceDiscTmpPrintout)
this.insertPriceDiscTmpPrintout();
_queryRun.setCursor(priceDiscTmpPrintout);
}
Generate data
”Connect” query to
temporary table
Invoking Business Logic
Problem
Want to invoke business logic, such as a posting
routine without reading or creating data
Solution
Create Axd<Document> class with no query
Add properties to Axd<Document> class for holding
results
Add parm<Property>() method per property
Override read() method to invoke business logic
before serializing data
Axd<Document> Class With No Query
class AxdOperation extends AxdBase
{
str
result;
Property
}
will be serialized
public Str parmResult(str _result = result)
{
;
result = _result;
return result;
}
public QueryName getQueryName()
{
return '';
No query!
}
Invoking Business Logic
public AifDocumentXml read(AifEntityKey _entityKey,
AifSchemaInfo _xsdInfo,
AifEndpointActionPolicyInfo
_actionPolicyInfo,
AifConstraintList _constraintList,
AifPropertyBag _aifPropertyBag)
{
AifDocumentXml xml;
;
// Call business logic here using data in _entityKey as
// parameters. Save result in ’result’ property.
xml = super(_entityKey,
_xsdInfo,
_actionPolicyInfo,
_constraintList,
_aifPropertyBag);
return xml;
}
questions?
© 2006 Microsoft Corporation. All rights reserved.
This presentation is for informational purposes only.
Microsoft makes no warranties, express or implied, in this summary.

similar documents