Understanding Address Framework Technically

LogisticsPostalAddress (Address): This table stores the actual physical postal address.
Postal Address have 2 important fields ValidFrom, ValidTo. This means that there could be multiple entries.

LogisticsElectronicAddress (Contact): This table stores all the contacts. Contacts are of 2 types
·         Contacts linked directly to Customer/Vendor.
·         Contacts linked to a Postal Address.

In Microsoft Dynamics AX, you add postal and electronic address information to entities such as customer, vendor, or contact person by using the DirPartyPostalAddressView and DirPartyContactInfoView views.

Table
Description
DirPartyTable
Global address book. This will contain entries for all people and organizations 
you deal with, including customers, suppliers, employees, etc.
This information is maintained across the entire organization. NB the table structure often refers to address book entries as 'parties'. Generally other records (like customer, supplier, etc) will reference a record in this table by a field named Party.
LogisticsLocation
This is a single 'location' that can be attached to one or more address book entries. This is similar in principle to the old 'Address' table from Ax2009, that no longer exists - The main difference now being that the location header always points to an address book entry, whereas in 2009 the Address table could point to anything.

Note that this is not an address - Physical address details are stored in
LogisticsPostalAddress
LogisticsPostalAddress
A postal address, linked to a LogisticsLocation record via field Location.
LogisticsElectronicAddress
'Electronic' address details, such as email, phone, web address etc.

Each different type of address is represented as a separate record, delineated by 'Type'. This links to the location record.
DirPartyLocation
This table links entries in the LogisticsLocation table to an address book entry (DirPartyTable).
LogisticsLocationRole
This defines types of roles that an address are classified as, such as "Delivery", "Invoice", etc.
DirPartyLocationRole
Links a location role type (LogisticsLocationRole) and an address book entry (DirPartyTable)
DirPartyPostalAddressView (view)
This is a view that collates address book entries with their linked postal adresses



Simple job to understand the relation between DirPartyLocation and DirPartyTable. Creation of postal address and contact info is shown below:

static void AddressJob(Args _args)  // X++ job.
{

    // Declare variables: views.
    DirPartyContactInfoView contactInfo;
    DirPartyPostalAddressView postalAddress;

    // Declare variables: tables.
    ContactPerson contactperson;
    DirPartyTable partyTable = DirPartyTable::findByName("Contoso", DirPartyType::Organization);
    LogisticsPostalAddress logisticsPostalAddressInfo;

    // Declare variables: classes.
    ContactPersonEntity contactPersonEntity;
    LogisticsLocationEntity entity;

    // Declare variables: extended data types.
    Phone phone;

    // Declare variables: primitives.
    str firstName;
    str middleName;
    str lastName;
   
    // Create and populate the contact person.
    contactPersonEntity = ContactPersonEntity::construct(contactPerson);
    contactPersonEntity.parmFirstName('Contact');
    contactPersonEntity.parmMiddleName('M.');
    contactPersonEntity.parmLastName('Person');
    contactPersonEntity.parmAssistantName('AssistantName');
    contactPersonEntity.parmBillingInformation('Billing info');
    contactPersonEntity.parmCharacter('Character description');
    contactPersonEntity.parmComputerNetworkName('Computer network name');
    contactPersonEntity.parmContactForParty(partyTable.RecId);
    contactPersonEntity.parmContactMemo('Memo');
    contactPersonEntity.parmContactPersonId('CP61');
    contactPersonEntity.parmLoyalty('Loyalty');
    contactPersonEntity.parmMileage('Mileage');
    contactPersonEntity.parmOfficeLocation('Office location');
    contactPersonEntity.parmOutlookCategories('Outlook categories');
    contactPersonEntity.parmProfession('Profession');
    contactPersonEntity.parmSensitivity(smmSensitivity::Personal);
    contactPersonEntity.parmSpouse('Spouse');
    contactPersonEntity.parmTimeAvailableFrom(1000);
    contactPersonEntity.parmTimeAvailableTo(2000);
    contactPersonEntity.write();

    // Populate the postal address information by using the view.
    postalAddress.Street = 'One Microsoft Way';
    postalAddress.City = 'Redmond';
    postalAddress.State = 'WA';
    postalAddress.ZipCode = '98052';
    postalAddress.CountryRegionId = 'US';




    // Update the postal address information.
    contactPersonEntity.createOrUpdatePostalAddress(postalAddress);

    // Populate the contact information by using the view.
    contactInfo.Locator = '555-555-5555';
    contactInfo.Type = LogisticsElectronicAddressMethodType::Phone;
    contactInfo.IsPrimary = true;
    // Update the contact information.
    contactPersonEntity.createOrUpdateContactInfo(contactInfo);
   
    // Verify that the data was stored correctly.
    firstName = contactPersonEntity.parmFirstName();
    middleName = contactPersonEntity.parmMiddleName();
    lastName = contactPersonEntity.parmLastName();
   
    logisticsPostalAddressInfo = entity.getPostalAddress();
    phone = contactPersonEntity.getPrimaryElectronicAddressLocation().getPhone();

    info(firstName + " " + middleName + " " + LastName +
        " is located at " + logisticsPostalAddressInfo.StreetNumber +
        " " + logisticsPostalAddressInfo.Street + ", " +
        logisticsPostalAddressInfo.City + ", " +
        logisticsPostalAddressInfo.State + " " +
        logisticsPostalAddressInfo.ZipCode +
        ". They can be contacted at " + phone + ".");
}



Note:
Ø  LogisticsPostalAddressView consists of LogisticsPostalAddress and LogisticsLocation.
Ø  DirPartyPostalAddressView consists of LogisticsPostalAddressView and DirPartyLocation.
Ø  DirPartyLocation consists of Party and Location.


Retrieve Customer/Vendor address:

static void CustomerAddressBook (Args _args)
{
    CustTable               custTable;
    DirPartyTable           dirPartyTable;
    DirPartyLocation        partyLocation;
    LogisticsLocation       logisticsLocation;
    LogisticsPostalAddress  postalAddress;
    ;
    custTable       = custTable::find('Test1001'); // Customer account id
    dirPartyTable   = dirPartyTable::findRec(custTable.Party);
    while select partyLocation
        where   partyLocation.Party     == dirPartyTable.RecId
    {
        logisticsLocation = logisticsLocation::find(partyLocation.Location);       
        if(logisticsLocation.IsPostalAddress)
        {
            postalAddress = LogisticsPostalAddress::findByLocation(logisticsLocation.RecId);           
            info(strFmt("%1 - %2",
                logisticsLocation.Description,
                postalAddress.CountryRegionId));
        }       
    }
}

  


Get Email address:     
             
static void CustomerEmailAddresses(Args _args)
{
    CustTable                   custTable;
    DirPartyTable               dirPartyTable;
    DirPartyLocation            partyLocation;
    LogisticsLocation           logisticsLocation;
    LogisticsElectronicAddress  electronicAddress;
    ;
    custTable       = custTable::find('Test1001'); // Customer account id
    dirPartyTable   = dirPartyTable::findRec(custTable.Party);
    while select partyLocation
        where   partyLocation.Party     == dirPartyTable.RecId
    {
        logisticsLocation = logisticsLocation::find(partyLocation.Location);       
        while select electronicAddress
            where   electronicAddress.Location  == logisticsLocation.RecId
            &&      electronicAddress.Type      == LogisticsElectronicAddressMethodType::Email
        {           
            info(strFmt("%1",electronicAddress.Locator));
        }       
    }
}




Get Phone number from warehouses:

static void PhoneNumbersAttachedToWarehouse(Args _args)
{

    InventLocation                      inventLocation;
    LogisticsEntityPostalAddressView    postalAddressView;
    LogisticsElectronicAddress          elecAddress;
    LogisticsLocation                   contactLocation;
   
    inventLocation = inventLocation::find('NB');
   
    if(inventLocation)
    {
        while select postalAddressView 
            where   postalAddressView.Entity            == inventLocation.RecId
            &&      postalAddressView.EntityType        == LogisticsLocationEntityType::Warehouse
        {               
            while select elecAddress               
                where   elecAddress.Type                == LogisticsElectronicAddressMethodType::Phone
            join contactLocation                                   
                where   contactLocation.ParentLocation  == postalAddressView.Location
                &&      contactLocation.RecId           == elecAddress.Location
            {           
                info(elecAddress.Locator);  
            }                  
        }
    }

}



Here is the static method which I've written to make the life easier for the developer, to find the already existing combination of street, city, zip code, state, country etc.
If it finds the existing data in the tables then it will return the ‘LogisticsPostalAddress’ buffer else it creates the new record in the LogisticsPostalAddress table using the below logic.       

public static LogisticsPostalAddress retrieveMatchingPostalAddress(
    Description                     _locationName,
    LogisticsAddressStreet          _street,
    LogisticsAddressCity            _city,
    LogisticsAddressCountyId        _county,
    LogisticsAddressZipCodeId       _zipCode,
    LogisticsAddressStateId         _state,
    LogisticsAddressCountryRegionId _countryRegionId,
    LogisticsPostalAddressRecId     _originalPostalAddress   = 0
    )
{
    LogisticsPostalAddress              ret;
    LogisticsPostalAddressEntity        postalAddressEntity = new LogisticsPostalAddressEntity();
    LogisticsPostalAddressView          postalAddressView;
    LogisticsPostalAddress              originalPostalAddress;
    LogisticsLocation                   originalLocation;
    boolean                             createAddress = false;

    if (_originalPostalAddress != 0)
    {
        originalPostalAddress   = LogisticsPostalAddress::findRecId(_originalPostalAddress);
        originalLocation        = LogisticsLocation::find(originalPostalAddress.Location);

        if (originalLocation.Description            == _locationName
        && originalPostalAddress.Street             == _street
        && originalPostalAddress.City               == _city
        && originalPostalAddress.ZipCode            == _zipCode
        && originalPostalAddress.State              == _state
        && originalPostalAddress.County             == _county
        && originalPostalAddress.CountryRegionId    == _countryRegionId)
        {
            ret = originalPostalAddress;
        }
        else
        {
            createAddress = true;
        }
    }
    else
    {
        createAddress = true;
    }

    if (createAddress)
    {
        postalAddressView.LocationName      = _locationName;
        postalAddressView.Street            = _street;
        postalAddressView.City              = _city;
        postalAddressView.ZipCode           = _zipCode;
        postalAddressView.State             = _state;
        postalAddressView.County            = _county;
        postalAddressView.CountryRegionId   = _countryRegionId;

        ret = postalAddressEntity.createPostalAddress(postalAddressView);
    }

    return ret;
}



9 comments:

  1. Hello :) Thank you so much for providing such useful tutorial about understanding Address Framework in the technical aspect. It will help me a lot, because I'm just a beginner in the field of Microsoft Dynamics AX and have to learn alot :)

    ReplyDelete
  2. this is probably the best explanation that I've found regarding AX6 and Addresses. Thank you

    ReplyDelete
  3. This comment has been removed by the author.

    ReplyDelete
  4. Thanks so much for this . But i need one thing on How to update the Address Purpose( Invoice,Delivery,Business( etc .) of customer or vendor . Actaully It inserts into dirPartyLocationRole where you will get the location from logisticsLocationRole.

    Can you please check i just need to update AddressType/Purpose

    ReplyDelete
  5. Thanks for your wonderful blog, today i was helped by your writing. Thanks

    ReplyDelete
  6. How can you update a contact person?

    ReplyDelete

Powered by Blogger.