Thank you SO MUCH for your help Oksana. I would not have been able to do this without you.
Here is my final code and it is working !!! I thought to put it here incase there are others that is new to Retail development like me and who has to learn on the fly.
References added to my project:
Make sure the namespace used inside the classes are the same as the name of the project.
Trigger class:
***
namespace ProdSearchViewCRT
{
using System;
using System.Collections.Generic;
using Microsoft.Dynamics.Commerce.Runtime;
using Microsoft.Dynamics.Commerce.Runtime.Data;
using Microsoft.Dynamics.Commerce.Runtime.DataModel;
using Microsoft.Dynamics.Commerce.Runtime.DataServices.Messages;
using Microsoft.Dynamics.Commerce.Runtime.Messages;
using Microsoft.Dynamics.Commerce.Runtime.Services.Messages;
/// <summary>
/// Class that implements a post trigger for the GetProductSearchResultsDataRequest request type.
/// </summary>
public class GetProductSearchTriggers : IRequestTrigger
{
/// <summary>
/// Gets the supported requests for this trigger.
/// </summary>
public IEnumerable<Type> SupportedRequestTypes
{
get
{
return new[] { typeof(GetProductSearchResultsDataRequest) };
}
}
/// <summary>
/// Post trigger code to retrieve extension properties.
/// </summary>
/// <param name="request">The request.</param>
/// <param name="response">The response.</param>
public void OnExecuted(Request request, Response response)
{
ThrowIf.Null(request, "request");
ThrowIf.Null(response, "response");
var productsList = ((EntityDataServiceResponse<ProductSearchResult>)response);
if (productsList == null)
{
return;
}
foreach (ProductSearchResult product in productsList)
{
CommerceProperty availPhys = new CommerceProperty();
availPhys.Key = "Inventory";
var query = new SqlPagedQuery(QueryResultSettings.AllRecords)
{
DatabaseSchema = "ext",
Select = new ColumnSet("RECID", "AVAILPHYSICAL"),
From = "TMCITEMSTOREAVAILABILITYVIEW",
Where = "ITEMID = @itemId AND INVENTLOCATIONID = @channelLocation AND DATAAREAID = @companyId"
};
query.Parameters["@itemId"] = product.ItemId;
query.Parameters["@channelLocation"] = request.RequestContext.GetChannelConfiguration().InventLocation;
query.Parameters["@companyId"] = request.RequestContext.GetChannelConfiguration().InventLocationDataAreaId;
decimal qty = 0;
using (var databaseContext = new DatabaseContext(request))
{
PagedResult<ProductAvailQty> extensions = databaseContext.ReadEntity<ProductAvailQty>(query);
var resultObj = extensions.Results;
foreach (ProductAvailQty obj in extensions.Results)
{
qty += obj.AvailQty;
}
// Remove the trailing zeroes where applicable e.g. 5.00000 will be displayed as 5 and 5.01000 will be displayed as 5.01
availPhys.Value = qty.ToString("0.####");
}
product.ExtensionProperties.Add(availPhys);
}
}
public void OnExecuting(Request request)
{
if (request == null)
{
throw new ArgumentNullException("request");
}
}
}
}
***
My Commerce Entity:
***
namespace ProdSearchViewCRT
{
using System.Runtime.Serialization;
using Microsoft.Dynamics.Commerce.Runtime.ComponentModel.DataAnnotations;
using Microsoft.Dynamics.Commerce.Runtime.DataModel;
using System;
class ProductAvailQty : CommerceEntity
{
//
// Summary:
// Initializes a new instance of the TMC.ProductAvailQtyy
// class.
public ProductAvailQty()
: base("ProductAvailQty")
{
}
/// <summary>
/// Gets or sets the physical available quantity.
/// </summary>
[DataMember]
[Column("AVAILPHYSICAL")]
public Decimal AvailQty
{
get
{
return (Decimal)(this["AVAILPHYSICAL"] ?? (object)Decimal.Zero);
}
set
{
this["AVAILPHYSICAL"] = (object)value;
}
}
/// <summary>
/// Gets or sets the id.
/// </summary>
[DataMember]
[Column("RECID")]
[Key]
public long RecordId
{
get
{
return (long)(this["RECID"] ?? (object)0L);
}
internal set
{
this["RECID"] = (object)value;
}
}
}
}
***
To reference it in CloudPos:
TypeScript file:
***
import { IProductSearchColumn } from "PosApi/Extend/Views/SearchView";
import { ICustomColumnsContext } from "PosApi/Extend/Views/CustomListColumns";
import { CurrencyFormatter } from "PosApi/Consume/Formatters";
import { ProxyEntities } from "PosApi/Entities";
import { ObjectExtensions, StringExtensions } from "PosApi/TypeExtensions";
/**
* Gets the property value given the column name.
* @param {ProxyEntities.CommerceProperty[]} extensionProperties The extension properties collection.
* @param {string} column The column name of the property value to be retrieved.
* @returns The property value.
*/
export default (context: ICustomColumnsContext): IProductSearchColumn[] => {
return [
{
title: "Item Id",
computeValue: (row: ProxyEntities.ProductSearchResult): string => { return row.ItemId; },
ratio: 20,
collapseOrder: 3,
minWidth: 120
}, {
title: "Name",
computeValue: (row: ProxyEntities.ProductSearchResult): string => { return row.Name; },
ratio: 40,
collapseOrder: 2,
minWidth: 200
}, {
title: "Inventory",
computeValue: (row: ProxyEntities.ProductSearchResult): string => {
if (!ObjectExtensions.isNullOrUndefined(row.ExtensionProperties)) {
let inventProperties: ProxyEntities.CommerceProperty[] = row.ExtensionProperties.filter(
(value: ProxyEntities.CommerceProperty): boolean => {return value.Key === "Inventory";});
return inventProperties.length > 0 ? inventProperties[0].Value.StringValue : StringExtensions.EMPTY;
}
return StringExtensions.EMPTY;
},
ratio: 20,
collapseOrder: 4,
minWidth: 100,
isRightAligned: true
}, {
title: "Price",
computeValue: (row: ProxyEntities.ProductSearchResult): string => { return CurrencyFormatter.toCurrency(row.Price); },
ratio: 20,
collapseOrder: 1,
minWidth: 100,
isRightAligned: true
}
];
};
***
And the manifest.json:
"extend": {
"views": {
"SearchView": {
"productListConfiguration": { "modulePath": "SearchViewExtensions/ProductSearchView/ProductSearchViewColumns" }
}
}
Because of a previous custom, I already had TMCPosExtension in Extensions.json and tsconfig.json