Understanding the global address book

The global address book normalizes the name and address data held against entities such as customers and suppliers. Changing the name, address, or contact information against a customer will also appear to change the address of the vendor if it is linked to the same address book entry and this information isn't actually stored in the vendor record.

It does so by associating the entity with a record in DirPartyTable. This table also has some special case tables that inherit from it, as shown in the following diagram (which was taken using the Type hierarchy browser):

Understanding the global address book

The tables generally used are DirPartyTable and DirPerson. Looking at these tables, there doesn't appear to be enough fields. We have the following fields against DirPartyTable:

  • KnownAs
  • LanguageId
  • Name
  • NameAlias
  • PartyNumber
  • PrimaryAddressLocation
  • PrimaryContactEmail
  • PrimaryContactFax
  • PrimaryContactPhone
  • PrimaryContactTelex
  • PrimaryContactURL

The fields beginning with PrimaryContact are primary key relations to LogisticsElectronicAddress. The PrimaryAddressLocation relates to the entity's primary address location.

Electronic addresses

The structure of electronic addresses in AX is designed to be as flexible as possible so there isn't a field for each type of communication, such as phone, fax, and e-mail. There is a record that relates to a table that determines the type of communication.

The main tables used in this set are as follows:

Table

Relation

Purpose

DirPartyTable

 

A global address book record

DirPartyLocation

Party ==

DirPartyTable.RecId

This relates the address book record to the location records

LogisticsLocation

LogisticsLocation.RecId ==

DirPartyLocation.Location

The location we are associating with the address book record

LogisticsElectronicAddress

Location ==

LogisticsLocation.RecId

This stores the communication address and type, such as e-mail or telephone number

LogisticsElectronicAddressRole

ElectronicAddress ==

LogisticsElectronicAddress.RecId

This maps the address to the location role

LogisticsLocationRole

RecId ==

LogisticsElectronicAddressRole. LocationRole

This determines the location type, such as business, not the type of communication

Although this design is designed to be fully flexible, there has to be a basis by which we can determine the type. This is the LogisticsElectronicAddressTypes enum. This doesn't differentiate between types of telephones, a mobile or cellphone number is when Type is Phone and isMobilePhone is Yes.

This level of flexibility comes at a cost, and even when armed with relationships, it is still difficult to navigate at table level. Thankfully, we can use a view to simplify this. Locate the LogisticsEntityContactInfoView view and open the table browser. We usually won't use the tables to get the contact information data; we would normally use this view.

Postal addresses

The PrimaryAddressLocation field reveals how addresses are stored in Dynamics AX. This doesn't relate to an address but a location. A location could be something like 'main office', which in turn relates to an address record in LogisticsPostalAddress.

This design is made to handle situations such as this: a company has moved to a new address and this address might be known in advance. The LogisticsPostalAddress table is a ValidTimeState table, which means that changes to the records in this table create a new version. We can also say that the address will change at a specific date/time. When the interface shows the current record, it does so by selecting a record where the current date and time fall between the ValidFrom and ValidTo fields.

A good example of this in use is a sales order. Against a customer, we can set up a primary location, which is associated with an address. When the sales order is created, the current address from LogisticsPostalAddress is associated with it—not the location. Should the customer's address change, the address associated with the sales order record will not be changed, so the order will be delivered to the address that was set when the order was created.

The ValidTimeState tables will be discussed in Chapter 10, Advanced Development Techniques.

The logistics tables define locations (LogisticsLocation) and their addresses (LogisticsPostalAddress). But looking at the location associated with a customer, we can have multiple roles, such as delivery address, invoice address, and so on. These location roles are defined in data by the LogisticsLocationRole and LogisticsLocationRoleTranslation tables. The translation table allows the client to present the role in the any of the supported languages.

To take the example of a customer, the tables involved in this are listed in the following table:

Table

Relation

Purpose

DirPartyTable

 

The global address book record

DirPartyLocation

DirPartyLocation.Party ==

DirPartyTable.RecId

Relates the address book record to location records

DirPartyLocationRole

DirPartyLocationRole.PartyLocation ==

DirPartyLocation.RecId

Associates the location's role with the party location record

LogisticsLocation

LogisticsLocation.RecId ==

DirPartyLocation.Location

The location we are associating with the address book record

LogisticsPostalAddress

LogisticsPostalAddress.Location ==

LogisticsLocation.RecId

The address of the location

The other main address tables to be aware of are those starting with LogisticsAddress. These are the backing tables for the address element, such as country, city, and so on. This can seem a little complicated, especially if we wish to create an address programmatically. Fortunately, Microsoft has written views that flatten some of this information for easier access. Some useful views are:

  • DirPartyPostalAddressView
  • LogisticsPostalAddressView
  • LogisticsEntityPostalAddressView

Creating addresses programmatically

The DirPartyPostalAddressView view is particularly interesting, as it also allows us to create records. Like all views in AX, it is read-only. However, we can write to the record buffer, and submit it to a class that will do all the hard work for us.

The code to create an address from a party record (for example,CustTable.Party) is as follows:

DirPartyPostalAddressView   addressView;

addressView.Party           = _partyRecId;
addressView.IsLocationOwner = NoYes::Yes;
addressView.IsPrimary       = _isPrimary;
addressView.State           = _state; // must exist or blank
addressView.County          = _county; // must exist or blank
addressView.City            = _city;
addressView.Street          = _street;
addressView.ZipCode         = _postalcode;
addressView.CountryRegionId = _country; // must exist
if(_isPrimary)
    addressView.LocationName = "Primary address";
addressView = DirPartyLocationEntity::createAddressForParty(
                                           addressView, _roles);

The _roles variable is a container of record IDs from LogisticsLocationRole. To get the business role, use the following lines of code:

RefRecId roleId = LogisticsLocationRole::findBytype(
                      LogisticsLocationRoleType::Business).RecId;

If we wish to pass a single role, we can use the syntax [roledId] as the parameter. We can use a similar technique to create an electronic address in this case:

private RefRecId createElectronicAddress(
                LogisticsElectronicAddressMethodType _type,
                Description _description,
                LogisticsElectronicAddressLocator _locator,
                PhoneLocal _extension,
                RefRecId _locationRecId,
                NoYes _isPrimary,
                NoYes _isMobile,
                NoYes _isSMS)
{
    LogisticsElectronicAddress  electronic;
    LogisticsLocation           location;
    RefRecId                    childLocRecId;
    // A location record id would be passed if we
    // were adding an electronic address
    // to a logistics address, for example, head office phone number
    select firstOnly RecId from location
        where location.ParentLocation == _locationRecId &&
                location.IsPostalAddress == false;
    childLocRecId = location.RecId;
    if(childLocRecId == 0)
    {
        childLocRecId = LogisticsLocation::create(_description,
                                            false,
                                            _locationRecId).RecId;
    }
    electronic.clear();
    electronic.initValue();
    electronic.Type = _type;
    electronic.Description = _description;
    electronic.IsMobilePhone = _isMobile;
    electronic.Locator = _locator;
    electronic.Location = childLocRecId;
    electronic.LocatorExtension = _extension;
    electric.IsInstantMessage = _isSMS;

    if(_isMobil == NoYes::No)
        electric.IsPrimary = _isPrimary;

    electric.insert();

    return electric.RecId;
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.96.5