VSTO: Get long-term EntryID from Microsoft.Office.Interop.Outlook.Folder query - outlook

I'm wondering if it's possible to get the long-term entry id from a Microsoft.Office.Interop.Outlook.Folder query. I can successfully query the table, but the entry id is always the short-term entry id. As I understand it, the short-term entry id has the potential to change from session to session.
Here's my example code that -- additionally -- gets the sender's address as well as the base columns:
Table table = folder.GetTable();
table.Columns.Add("SenderEmailAddress");
while (!table.EndOfTable)
{
Row row = table.GetNextRow();
string entryId = row["EntryID"].ToString();
string sender = row["SenderEmailAddress"].ToString();
...
}
Is it possible to add an additional column, allowing me to query the long-term entry id? Thank you.

Yes, you will need to request the PR_LONGTERM_ENTRYID_FROM_TABLE MAPI property. Since it is not one of the OOM properties, you will need to specify its DASL name - "http://schemas.microsoft.com/mapi/proptag/0x66700102":
table.Columns.Add("http://schemas.microsoft.com/mapi/proptag/0x66700102");
See Columns.Add on MSDN for more details.

You can open the item to get a long-term EntryID property value. Consider using the NameSpace.GetItemFromID method which returns a Microsoft Outlook item identified by the specified entry ID (if valid). Then you may retrieve the EntryID property value which should be a long-term EntryID.
Short-term entry identifiers are used primarily for rows in tables and entries in dialog boxes, whereas long-term entry identifiers are used for many objects such as messages, folders, and distribution lists.

Related

How to use Get Record to lookup a related record on another object when I don't have the schema Entity Name - Just the LogicalName

All,
I am building a Power Flow. I am returning an object that has a relationship to another entity.
I want to get some values from the related entity.
I am attemping to use the "Get Record" connector. The returning object returns just the logicalEntityName (in this case "opportunities") but Get Record wants an Entity Name that is the Schema Name ("Working Opportunities").
Big Question: What's the secret to use CDS to get information from a related record in another object?
Little Question: How do I do get the Schema Name?
The logical name will be the same as schema name except some casing difference, ie schema name will have camel casing (first letter of first/second word with capitals, you can notice it clearly in custom entity which will have publisher prefix like new_entityname) and logical name will have pascal casing (all lower case).
You can find the details in XrmToolBox metadata browser or in Solution.
In the below snip, (Logical) Name = Opportunity and Schema Name = Opportunity, also Display Name can be anything and can be changed anytime.
Regarding the related entities, you should use List Records: GetItems_V2 and you can use filter by passing parent record to get related child records. Read more
Could you please share flow screenshot and response to help you with your requirement?
As suggested by Arun you could use List Record and filter query to pass parent record id which will be available from dynamic content.
see below link.
https://crmkeeper.com/2019/08/31/cds-list-records-filter-query-using-flow/
Please mark my answer verified if i were helpful

Dealing with disassociated records in a poorly designed database

Overview
I have inherited a website that allows users to order customised products. The customisations were saved in a way that disassociates them from their record. I would like to modify the db so these records can be associated.
Example
Users can get Product #1 "stock", or customise it, changing as many as 10 different properties. Let's say color, fabric, width, height etc.
Orders can, and regularly do, contain multiple products, each of which may be customised.
Additionally, users can save their orders, so they can re-order later.
When the database was designed, the details of the order was neatly organised into individual columns. Customer name, address, payment type etc. But the list of products and more notably their customisations were saved as a JSON string in a single column. For ease, let's call this column the "cart".
Basically, the order table has a column cart and the cart column contains a JSON-formatted list of products and customisations.
Unfortunately, the JSON object has reference ids to the product table, but lacks references to the customisation table. Instead it uses a bunch of strings meant for a human to read. Fortunately those strings exist in the customisation table, but they were written as the cart was created.
The problem we face is that the list of customisations can be changed by a CMS. So far, they haven't been changed. 🙏 But they will need to be soon and that's going to cause problems:
Problems
If a customisation option is removed (say, a fabric option) and a customer re-orders from an old saved order, we need to be able to parse the cart, detect this and warn them of the change.
Customisations are currently immutable. Once a product is added to the cart, it cannot be changed. Users need to delete and re-add to make a single change. Poor UX.
If anyone changes the human-readable text on a customisation we're dead. ☠️
Questions
How would you design this if you were staring from scratch?
How might we go about converting the current implementation and legacy data to this new schema?
I don't know if stack is notable, but we're on Postgres and Django-Python.
I would implement this with the following tables:
Products {
productId // primary key
name
price
}
Customization_Types {
customizationTypeId // primary key
name // e.g. COLOR, FABRIC, LENGTH
}
Customizations {
customizationId // primary key
customizationTypeId // foreign key
value // e.g. BEIGE, VELVET, 8
}
Product_Customizations {
productCustomizationId // primary key
productId // foreign key
customizationId // foreign key
priceModifier // price markup for applying the customization
isValid // false if this record is invalid/obsolete
}
Orders {
orderId // primary key
customerId // foreign key
}
Product_Orders {
productOrderId // primary key
orderId // foreign key
productId // foreign key
quantity
}
Customization_Orders {
customizationOrderId // primary key
productOrderId // foreign key
productCustomizationId // foreign key
}
The Products table contains the data for your base products - name, price, etc
The Customization_Types table contains the type names for your different customizations - COLOR, FABRIC, LENGTH, etc
The Customizations table contains a link to a customizationTypeId as well as a legal value - I'm assuming that users can't enter arbitrary numerical values (for e.g. LENGTH or WIDTH) i.e. they're given a drop-down box instead of a text box, however if they can enter arbitrary numerical data then you'll need MIN/MAX fields that are null for named constraints (so e.g. you could have Type:COLOR/Value:BEIGE/Min:NULL/Max:NULL or Type:LENGTH/Value:NULL/Min:4/Max:8)
The Product_Customizations table links a Customization to a Product, so for example if ProductX can come in BEIGE then you would create a Product_Customization record that links ProductX to BEIGE.
The Orders table just contains an orderId and anything else relevant to the order (e.g. a link to the customerId and shippingAddressId)
Product_Orders links a product to an order
Customization_Orders links a Product_Customization to a Product_Order
Let's say a customer orders ProductX in BEIGE and LENGTH=8, then you would create an Order record, a Product_Order record with a link to ProductX, and two Customization_Order records - one linked to COLOR=BEIGE and one linked to LENGTH=8.
This should make it easy to modify a product's customizations without having to reload the entire product - the user can modify color to COLOR=RED without touching the length customization (delete the old Customization_Order:COLOR=BEIGE record and create a new COLOR=RED record), or the user can remove the length customization without touching the color customization (delete the old Customization_Order:LENGTH=8 record).
When reloading an old order/product you can quickly verify that the same productCustomizationIds still apply to the product in question, else flag the user. Additionally, you can flag the user if the customization still applies but the customization's price modifier has changed.
As far as converting the legacy data, I'm not familiar with Python but I do have experience with reading JSON via Java and I'm assuming that Python offers similar if not better libraries for this. The trick is going to be matching the existing data to pre-loaded Product_Customization data - if the data fails to match then create a new Product_Customization row corresponding to it with isValid=FALSE (this is assuming that the customization in question is no longer offered), and when you get a chance manually iterate through the invalid Product_Customization rows to ensure that these really are unmatched customizations and not just parsing errors.
Little improvement to Zim-Zam's answer.
Even better approach is to store not plain values (BEIGE, VELVET, 8) as customization parameters, but kind of schema from which code can build up correct view of a customization.
It could be just JSON/XML formatted text. And the entity that is responsible for building view and applying logic should be able to work with JSON data of different versions.
For example, if properties of a customization have changed and something new has been added, in that case you only need to change code and adjusted JSON will be saved. No need to change existing data. Also there should be possibility to read old JSON versions with old properties and work with it.
Two possible ways of what to do if you read an old entity from DB:
View builder will ignore all old properties of a customization, add new properties and set their values to default. I would go with that personally.
Old view is presented to user, but when user clicks, for example, Ok button or Finish, additional logic will check that there are old properties and notifies user that they should be removed manually or just removes them automatically.
More flexible approach that requires only code changes without touching db and allows to show user old customization properties if it is necessary.
Update:
Customizations could have two kind of properties: one that administrator can define, such as title or price, which are not frequently changed and common for all customizations and another one such as size and color which could be changed frequently, could have user defined values and are not common for all customizations.
The first kind should be stored in Customization table as separate columns. That will allow to changed such properties in administrative panel and have all previously stored data consistent.
The second kind of properties could be 1) frequently changed 2) not all customization types could have such properties. It is a bad idea to store them as separate columns because if there are huge amount of data, changing column type or adding new column could cause performance degradation and sometimes could not be possible due to incompatible types of properties.
Actually, if they are stored as separate columns, you are probably will have to change code to support new properties anyway.
My idea is that you still allow administrator to change type of such properties and add new one or remove old one through some interface. The key thing here is that you are storing JSON data like this
{
"properties": {
{
"propertyName": "height",
"propertyType": "int",
"min" : 10,
"max" : 25,
},
{
"propertyName": "color",
"propertyType": "color",
},
{
"propertyName": "anotherCustomField",
"propertyType": "text",
},
}
}
What's left to do is to implement view builders or renderers for all kinds of property type. And add a separate table with only values. You fetched a customization record from db, you found out which customization properties there are, checked which one are still valid and rendered only valid ones. If administrator changed type of customization's property or just removed one, you marked that customization's property as not valid in db and that's all the work. No code changes, no database schema changes.

Show Order ID in Dynamics CRM Order Look up instead of Order Name

In Dynamics CRM 2016 (on-prem), I've custom child entity Partiesthat have a look of type order. Currently it is working properly and it is showing order name but I want it to show Order ID.
I tried to resolve by creating my own view, adding order id field only and making it default view for the look up but it don't meet my requirements.
This is controlled by the lookup view for Orders. The first three fields in the lookup view are shown when selecting records from the lookup field.
You cannot change the position of (or remove) the Name field from the lookup view. That still leaves you with two additional fields to be shown, one of which could be the Order ID.
I know no supported ways around this (except creating a workflow to copy the Order ID to the Name field and adding a custom name field instead, if you really insist).
Changing what appears on the form after you make a selection in a lookup field is not possible, unfortunately. The primary attribute is always what gets displayed after a user specifies a lookup value (which, for the Order entity, is the Name attribute). As Henrik's answer mentions, people commonly get around this by copying the value they want to see into the primary attribute using a workflow or a plugin.

GUIDs as the value field in drop-down, Any better approaches?

I have a Products table in SQL Server database, it has an ID column that contains uniqueidentifiers, and a ProductName column with VARCHAR(100). This table contains over 5000 entries.
Now on my razor cshtml page, I have a drop down that displays these pProduct names. The way I have done is by binding drop-down value field to ID column and display text to ProductName. This mean that on the client side, if someone does a view source in their browser (or use any http sniffer etc), they can see all the GUIDs associated with these Product Names. Now when user submits this information, I have setup a server side validation, where I make sure that all the submitted GUIDs are
1) Valid Guids (not strings or anything else)
2) Submitted Guid exists among the IDs in Products. This ensure that any Guid that don't exists in Products.ID will not be processed.
The fact that a user can see this GUID data, does it expose any security risks? Are there any better ways of handling this situation?
Assuming your database has foreign keys, this causes no security hole. Even if it has no foreign keys (between a product table and product orders), you can simply look for the product first. If it doesn't exist, ignore the request.
So no, it's not a security hole - unless there is a security hole in the Guid Parsing of the .NET framework.

Dynamics CRM error "A currency is required if a value exists in a money field" after converting Activity to Case

We have a Dynamics CRM 4.0 instance with some custom attributes of type "money" on the Case entity and on all Activity entities (Email, Phone Call, etc.) When I use the built-in "Convert Activity to Case" functionality I find that the resulting Case does not have a Currency set, even if the Activity it was created from does have it. Whenever the case is opened the user then gets this JavaScript error:
A currency is required if a value exists in a money field. Select a
currency and try again.
This is extremely annoying! How do I fix it? Is there any way I can set the currency? It needs to be done synchronously, because the Case is opened immediately when it's created from an Activity. So even if I started a workflow to set the currency the user would still get that error at least once. Alterntatively, can I just suppress the warning somehow? I don't really care about setting the Currency, I just want the error gone.
I guess this code will be helpful for next person who have a same problem.
I spent whole day to figure out what I did below.
There are two steps involved here:
set default currency
set currency symbol for the money field.
Here is the code sample.
var currency = crmForm.all.transactioncurrencyid;
if (currency.DataValue == null) {
var lookupData = new Array();
var lookupItem= new Object();
//Get transaction currency value from :
select **TransactionCurrencyId** from MSCRM.dbo.TransactionCurrency
lookupItem.id = '{The GUID that you get from the SELECT statement above}';
lookupItem.typename = 'transactioncurrency';
lookupItem.name = 'US Dollar';
lookupData[0] = lookupItem;
currency.DataValue = lookupData;
//set default currency symbol for all the Money field.
var defaultSymbol = '$';
for(var i=0; i < crmForm.all.length ; i++) {
var oCtr = crmForm.all[i];
if(!IsNull(oCtr.IsMoney) && !oCtr.IsBaseCurrency)
{
oCtr.CurrencySymbol = defaultSymbol;
}
}
}
This annoying issue was resolved on my system by discovering the transactioncurrencyid used for US dollars and then updating the transactioncurrencyid column in the entity's database table for all the existing entity records. After doing this I was able to add money values on the entity form with no further problems. Not sure if this solution would be ideal for everyone, but as I did not want to write code to do this and felt I shouldn't have to since if I added money attributes to a newly defined entity it didn't require writing code on my part to populate the transactioncurrencyid field - it just did it by default. So in summary, this problem only seems to occur if the the money fields are added to an existing entity that has existing data associated with it.
set default currency in Personalize Workspace, General tab
NEW records will use this currency
For EXISTING records (before money field(s) added) use Advanced Find to find records with NO currency value, then use Bulk Edit to set currency
You might want to check out this article CRM 4 Currency Calculations by Mitch Milam
Update : After googling around, i found out that you might need to set the transactioncurrencyid lookup somewhere. So in your case, it might be onsave or inside the execution of the workflow codes. I read it from here Error: Assign a decimal value to CRM 4.0 money field using Javascript
If your form has a money field on it, CRM needs to know which currency to use. Verify that a default currency is set in your user preferences (Personalize Workplace from the main page, then the General tab). That is, each of your users will need to have a default currency set.
I have also been able to work around this issue by adding the currency field to the form, defaulting it to US dollars, and then hiding the field. If memory serves, though, this isn't ideal because the US dollars currency is a record in the system and can have different GUIDs in different environments.
Since this thread came up in my Google search when I was looking for a solution to this problem for CRM 2011, I thought I'd add my blog article explaining how to set the default currency lookup in the Onload of a CRM 2011 form using JavaScript, JSON and OData.
http://crmscape.blogspot.com/2011/03/crm-2011-set-default-transaction.html
I agree with Hadi Teo that you need to set the transactioncurrencyid. Its been awhile since I ran across this - so here is what I think I remember.
If you create a new entity with a money field populated the transaction currency will be set.
If you update an entity, the transaction currency field will not be set.
I haven't used the Activity to Case function so I'm not all that sure what it does. One thing you can do as a work around is to add the transactioncurrencyid onto the form. Then you can set it before you modify your Case.
The other would be to default the currency in code. There are two places to determine the default currency. First off of the user settings. Second (if that is null) off of the organization settings.
Fix for this problem
1. Add the base currency field also to the form.
2. Untick the "visible by default option" of the base currency field.

Resources