Custom addressformat and the preview pane on the sidebar

Hi everyone

A customer has been using a custom addressformat since they used 7.5 and it always worked just as it was supposed to. But since they upgraded to version 8, with the new preview pane of the left sidebar, they can't see any address there. The addressformat still works as designated for the company card, however for some reason nothing shows up in the preview pane.

I've previously used this article to construct custom address formats:

https://community.superoffice.com/en/technical/documentation/older-versions/documentation-7/admin/database/addressformat/ 

But that piece of documentation was written for version 7, and does not mention anything about visibility in the preview pane. We've been asking support, but they can only advise to use another standard addressformat, which tthe customer has been doing since. But now they recently figured out that it's not a usable solution, and that they need the old addressformat back, which is why i've been reopening the case and is now writing here out of desperation.

The addressformat is set up as follows:

addressformat_id name layout_id atype_idx address1_line address1_subpos address1_leadtext address1_zip address1_length address1_flags address1_mask address2_line address2_subpos address2_leadtext address2_zip address2_length address2_flags address2_mask address3_line address3_subpos address3_leadtext address3_zip address3_length address3_flags address3_mask city_line city_subpos city_leadtext city_zip city_length city_flags city_mask county_line county_subpos county_leadtext county_zip county_length county_flags county_mask state_line state_subpos state_leadtext state_zip state_length state_flags state_mask zip_line zip_subpos zip_leadtext zip_zip zip_length zip_flags zip_mask extraFlags labelLayout registered registered_associate_id updated updated_associate_id updatedCount labelLayout2 isBuiltIn
101 DI Addresser 99 2 1 1 14.000 1.024 42 0   2 1 14.001 0 42 0   0 0 0 0 0 0   0 0 0 0 0 0   0 0 0 0 0 0   0 0 0 0 0 0   0 0 0 0 0 0   384 <name>[\n]<dept>\n<atfn>[ ]<atm?>[ ]<atln>[\n]|x|<sadr>[\n]<szip>[ ]<scit>[\n]<cnt?> 15-09-2016 08:52:37 0 01-01-1760 0 0   0
102 DI Addresser 99 1 0 0 0 0 42 0   0 0 0 0 0 0   0 0 0 0 0 0   0 0 0 0 0 0   0 0 0 0 0 0   0 0 0 0 0 0   0 0 0 0 0 0   384 <name>[\n]<dept>\n<atfn>[ ]<atm?>[ ]<atln>\n|x|\n<padr>[\n]\n<zipc>[ ]<city>[\n]<cnt?> 15-09-2016 08:52:37 0 01-01-1760 0 0   0
103 DI Addresser 99 16.387 1 1 14.004 0 42 0   0 0 0 0 0 0   0 0 0 0 0 0   2 2 0 513 30 1   0 0 0 0 0 0   0 0 0 0 0 0   2 1 14.002 257 10 0   384 <name>[\n]<dept>\n<atfn>[ ]<atm?>[ ]<atln>[\n]|x|<apad>[\n]<azip>[ ]<acit>[\n]<act?> 15-09-2016 08:52:37 0 01-01-1760 0 0   0

Are there something we need to change in order to have the addresses to show in the preview pane? I've tried to compare them to the other addressformats, but i can't quite see any major difference that stands out.

The customer is running 8.0 SR4, and it's on the windows client. Web client suffers the same problem though.

Hope you can help me

Thanks

Dennis

RE: Custom addressformat and the preview pane on the sidebar

Hi,

The Preview Hint system used in the Navigator (both Win & Web) is a fairly new system based on Preview Plugins living in Netsever (SoDatabase.dll).

It is a simply system with a header, an image, a collection of Label/Data fields and a footer.
The default implementation for a Contact preview shows 1 address field for AddressType.ContactStreetAddress and 1 for AddressType.ContactPostalAddress. It makes no attempt to be smarter..

Since this is a plugin system, I suspect you should be able to write your own but probably not trivial.
I suggest you register a issue to make the defualt ContactPreview smarter.

Conrad

Af: Conrad Weyns 9. maj 2018

RE: Custom addressformat and the preview pane on the sidebar

Hi Conrad, i am not sure if i understand what you are telling me.

You tell me the current contact preview plugin doesn't attempt to be smart - but the thing that doesn't make sense in my head is that it somehows figures out to be smart enough to drop the information that should go there, probably because of the changed addressformat - so if it were as basic as you tell me it is, then why doesn't it just write the street and postal address despite that i've setup postal address to be hidden in the contact card? or then just at least the street address which should be almost identical to the danish address format in the addressformat table?

 

If i choose any of the built in addressformats, the preview pane handles them all just fine.

 

It's a bit confusing :)

Can you point me in the direction of where to look in order to see how the preview hint system can be extended?

Thanks

Af: Dennis Mortensgaard 9. maj 2018

RE: Custom addressformat and the preview pane on the sidebar

Hi Dennis,

The preview is a relatively new feature that is, as Conrad stated, pluggable. Here is the main part of the ContactPreview that determines what is shown in that preview:

public static PreviewData FormatLargePreview(PreviewData pd, ContactRow contactRow, PhoneRow phoneRow, AddressRow addressRow, AddressRow postalAddressRow, URLRow urlRow)
{           
    pd.heading = contactRow.Name; //ContactNameFormatter.GetFullName(contactRow,);
    pd.previewImageUrl = "[IMG:flagid=" + contactRow.CountryId + "]";
    pd.subheading = "";

    pd.AddField("[SR_ARCHIVE_DEPARTEMENT]", contactRow.Department);
    if (contactRow.AssociateId != 0)
        pd.AddField("[SR_CC_OUR_CONTACT]", AssociateCache.GetCurrent().GetAssociateFullName(contactRow.AssociateId));

    pd.AddField("[SR_LABEL_NUMBER]", contactRow.Number2);
    string category = CategoryCache.GetCurrent().GetNameFromId(contactRow.CategoryIdx);
    //if (category != null && category.Trim() != string.Empty)
        pd.AddField("[SR_LABEL_CATEGORY]", category);

    ListItemLookupHelper lih = ListItemLookupHelper.GetCurrent();
    pd.AddField("[SR_LIST_BUSINESS]", lih.LookupItem("Business", contactRow.BusinessIdx).Name);
    pd.AddField("", "");

    AddressRow dummyRow = AddressRow.CreateNew();
    pd.AddField("[SR_AL_STREET_LABEL]", AddressFormatter.FormatContact(contactRow, addressRow, dummyRow).ToString() );
    pd.AddField("[SR_AL_POSTAL_LABEL]", AddressFormatter.FormatContact(contactRow, postalAddressRow, dummyRow).ToString());
    pd.AddField("[SR_CC_PHONE]", PhoneFormatter.GetShortDisplayNumber(SoContext.CurrentPrincipal.HomeCountryId, contactRow.CountryId, phoneRow.Phone, true) );
    pd.AddField("[SR_COMMON_URL]", urlRow.UrlAddress);

    return pd;
}

I believe the key to understanding what you are experiencing is looking at the results of the last section of this code - with regards to AddressFormatter.FormatContact. 

If you create a test console app and use the AddressFormatter for that particular contact, are your customizations included?

If you would like to override the standard behavior of the preview, you will need to create one. Unfortunately there are not examples of one in the SDK [yet], so here is the default ContactPreviewPlugin in NetServer.

I have modified this one by adding the priority if int.MaxValue / 3, so as to take precedence over the default (which is int.MaxValue / 2).

Feel free to modify it as necessary to show a contact preview with the PreviewData you are interested in.

using System;
using System.Collections.Generic;
using System.Text;
using SuperOffice.CRM.ArchiveLists;
using SuperOffice.Factory;
using SuperOffice.CRM.Entities;
using SuperOffice.CRM.Data;
using SuperOffice.Data;
using SuperOffice.Data.SQL;
using SuperOffice.CRM.Globalization;
using SuperOffice.CRM.Cache;
using SuperOffice.CRM.Rows;

namespace SuperOffice.CRM.Previews
{
    [PreviewPlugin("SuperOffice:ContactPreview", int.MaxValue/3, ContactHint)]
    public class ContactPreviewPlugin : PreviewPluginBase
    {
        public const string ContactHint = "contact_id";

        private static ContactTableInfo _contactTableInfo;
        private static PhoneTableInfo _phoneTableInfo;
        private static AddressTableInfo _addressTableInfo;
        private static AddressTableInfo _postalAddressTableInfo;
        private static URLTableInfo _URLTable;

        #region IPreviewProviderPlugin Members

        protected override PreviewData InnerGetPreview(PreviewData previewData)
        {
            int contactId;
            if (TryGetIntHint(ContactHint, out contactId))
            {
                Select query = S.NewSelect();

                query.ReturnFields.Add(_contactTableInfo.All);
                query.ReturnFields.Add(_phoneTableInfo.All);
                query.ReturnFields.Add(_addressTableInfo.All);
                query.ReturnFields.Add(_postalAddressTableInfo.All);
                query.ReturnFields.Add(_URLTable.All);


                query.JoinRestriction.LeftOuterJoin(_contactTableInfo.ContactId.Equal(_URLTable.ContactId), _URLTable.Rank.Equal(S.Parameter(1)));
                query.JoinRestriction.LeftOuterJoin(_contactTableInfo.ContactId.Equal(_phoneTableInfo.OwnerId), _phoneTableInfo.PtypeIdx.Equal(S.Parameter(PhoneType.ContactPhone)).And(_phoneTableInfo.Rank.Equal(S.Parameter(1))));
                query.JoinRestriction.LeftOuterJoin(_contactTableInfo.ContactId.Equal(_addressTableInfo.OwnerId),
                    _addressTableInfo.AtypeIdx.Equal(S.Parameter(AddressType.ContactStreetAddress)));
                query.JoinRestriction.LeftOuterJoin(_contactTableInfo.ContactId.Equal(_postalAddressTableInfo.OwnerId),
                    _postalAddressTableInfo.AtypeIdx.Equal(S.Parameter(AddressType.ContactPostalAddress)));

                query.Restriction = _contactTableInfo.ContactId.Equal(S.Parameter(contactId));

                using (SoConnection conn = ConnectionFactory.GetConnection())
                {
                    conn.Open();
                    SoCommand cmd = conn.CreateCommand();
                    cmd.SqlCommand = query;
                    using (SoDataReader reader = cmd.ExecuteReader())
                    {
                        if (reader.Read())
                        {
                            ContactRow contactRow = ContactRow.GetFromReader(reader, _contactTableInfo);
                            PhoneRow phoneRow = PhoneRow.GetFromReader(reader, _phoneTableInfo);
                            AddressRow addressRow = AddressRow.GetFromReader(reader, _addressTableInfo);
                            AddressRow postalAddressRow = AddressRow.GetFromReader(reader, _postalAddressTableInfo);
                            URLRow urlRow = URLRow.GetFromReader(reader, _URLTable);
                            return FormatLargePreview(previewData,contactRow, phoneRow, addressRow,postalAddressRow,urlRow);
                        }
                    }
                }
            }

            return previewData;
        }

        #endregion

        public static PreviewData FormatLargePreview(PreviewData pd, ContactRow contactRow, PhoneRow phoneRow, AddressRow addressRow, AddressRow postalAddressRow, URLRow urlRow)
        {           
            pd.heading = contactRow.Name; //ContactNameFormatter.GetFullName(contactRow,);
            pd.previewImageUrl = "[IMG:flagid=" + contactRow.CountryId + "]";
            pd.subheading = "";

            pd.AddField("[SR_ARCHIVE_DEPARTEMENT]", contactRow.Department);
            if (contactRow.AssociateId != 0)
                pd.AddField("[SR_CC_OUR_CONTACT]", AssociateCache.GetCurrent().GetAssociateFullName(contactRow.AssociateId));

            pd.AddField("[SR_LABEL_NUMBER]", contactRow.Number2);
            string category = CategoryCache.GetCurrent().GetNameFromId(contactRow.CategoryIdx);
            //if (category != null && category.Trim() != string.Empty)
                pd.AddField("[SR_LABEL_CATEGORY]", category);

            ListItemLookupHelper lih = ListItemLookupHelper.GetCurrent();
            pd.AddField("[SR_LIST_BUSINESS]", lih.LookupItem("Business", contactRow.BusinessIdx).Name);
            pd.AddField("", "");

            AddressRow dummyRow = AddressRow.CreateNew();
            pd.AddField("[SR_AL_STREET_LABEL]", AddressFormatter.FormatContact(contactRow, addressRow, dummyRow).ToString() );
            pd.AddField("[SR_AL_POSTAL_LABEL]", AddressFormatter.FormatContact(contactRow, postalAddressRow, dummyRow).ToString());
            pd.AddField("[SR_CC_PHONE]", PhoneFormatter.GetShortDisplayNumber(SoContext.CurrentPrincipal.HomeCountryId, contactRow.CountryId, phoneRow.Phone, true) );
            pd.AddField("[SR_COMMON_URL]", urlRow.UrlAddress);

            return pd;
        }

        static ContactPreviewPlugin()
        {
            _contactTableInfo = TablesInfo.GetContactTableInfo();
            _phoneTableInfo = TablesInfo.GetPhoneTableInfo();
            _addressTableInfo = TablesInfo.GetAddressTableInfo();
            _postalAddressTableInfo = TablesInfo.GetAddressTableInfo();
            _URLTable = TablesInfo.GetURLTableInfo();
        }
    }
}

Hope this helps.

Af: Tony Yates 9. maj 2018

RE: Custom addressformat and the preview pane on the sidebar

Thanks Tony, i'll try that :)

Af: Dennis Mortensgaard 9. maj 2018

RE: Custom addressformat and the preview pane on the sidebar

Hi,
I am not a c#, netserver dude so take this with some precausions.
But I know a thing or two about the Address View system in Win and it is not exactly trivial.
The view depends on interpreting the address format meta data.

This address:

 

Gives me the following preview:

Why?
Because AddressFormatter.FormatContact(...).ToString() does not apply any meta data rules. It's like a kind of OutputDebugString()

I think that what you want is for the preview to mirror the job of a proper address view.
Conrad

 

 

Af: Conrad Weyns 9. maj 2018

RE: Custom addressformat and the preview pane on the sidebar

Don't fight the system if the Company card's address view is showing your custom address format correctly..
No point in trying to juggle to get the preview hint system to show better data.
The problem is with the preview hint system. It's a hint...
Do register an issue so it may get prioritized.

Conrad

Af: Conrad Weyns 14. maj 2018