I have to email a CustomReceiptType1 receipt from a custom POS operation button. We are on V10.0.22.
The print part has no problem picking up the custom receipt type. However if the hardwareStation is setup as NONE and the customReceiptType is flag to allow for email, then it should email the receipt.
If you read "RetailSDK\Documents\SampleExtensionsInstructions\Receipts\readme.txt" it only give instructions for the printing part as if it can only print custom receipt types.
If you look at "RetailSDK\SampleExtensions\CommerceRuntime\Extensions.ReceiptsSample\CustomReceiptService.cs" and scroll down to method "GetCustomEmailReceiptsAsync", you see the following comment:
/// When adding support for new receipt type here, please make sure to mark the new receipt type as email compatible by updating 'RetailReceiptTypeConfiguration' table in HQ.
/// To update, override 'populateRetailReceiptTypeConfigurationTable' method on the table and use Commerce Parameters -> General -> Initialize.
I did the above custom using chain of command. I clicked on the initialize button they said to run but it never reaches the 'populateRetailReceiptTypeConfigurationTable' method on that table. So don't know if the latter is outdated. I created then a custom Initialize button that calls the 'populateRetailReceiptTypeConfigurationTable' method on the table. If I look in the DB the customReceiptType1 (code 101) is now showing it is enabled for email. I also looked in the channel DB table on my Dev box and even there it shows that it can be enabled. So the distribution schedule did push it to the channel DB.
However when I try to apply the logic for finding the custom receipt type receipt as shown in "RetailSDK\SampleExtensions\CommerceRuntime\Extensions.ReceiptsSample\CustomReceiptService.cs", method "GetCustomEmailReceiptsAsync", I get errors that the CustomReceiptType1 is not a valid receipt type.
IF I run the part that tries to first find the original receipts with GetEmailReceiptServiceRequest but pass in the CustomReceiptType1 as the receipt type, I get error :
***
Microsoft_Dynamics_Commerce_Runtime_ReceiptTypeNotSupported
Receipt for an invalid receipt type CustomReceipt1 was requested
***
If I run just the custom receipt part because I'm not actually interested in other receipt types that can be emailed, I only want the receipt for CustomReceiptType1, I also get an error that the receipt type is not valid:
***
Exception: Microsoft.Dynamics.Commerce.Runtime.ConfigurationException: Unknown request type Microsoft.Dynamics.Commerce.Runtime.Messages.GetCustomReceiptsRequest.
at Microsoft.Dynamics.Commerce.Runtime.CommerceRuntime.<Execute>d__43`1.MoveNext()
***
I'm working with Microsoft on this but is not getting anywhere at this point. And it is now becoming urgent to get this to work. The last correspondence yesterday was that I need to check to see if feature 'Email any receipt type and customize emailed receipts ' is enabled. It is enabled on my Dev box. So it is definitely not the feature that is causing the standard triggers not to recognize that the customReceiptType1 is email-enabled.
Setting in D365:

Please note that on the CRT and POS side the receipt type change to ReceiptType.CustomReceipt1. However the value behind the ENUM is still 101 for both.
"RetailSDK\SampleExtensions\CommerceRuntime\Extensions.SuspendTransactionReceiptSample" is a great example, however it only prints, no email part.
Below is my code. Can anybody who has successfully retrieved a CustomReceiptType receipt for email, please look at my code and let me know what is wrong? Or is the standard code not able to email customReceiptType receipts even though their is example code. Maybe the example code is outdated.
Please note that because I have to add a custom POS operation, I have a custom request/response trigger pair that is called from a custom RetailServer controller that is again called via the DataServices on the POS side when a button linked to the custom POS operation is clicked.
namespace TMCCustomReceiptTriggerHandlersCRT
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.Dynamics.Commerce.Runtime;
using Microsoft.Dynamics.Commerce.Runtime.DataModel;
using Microsoft.Dynamics.Commerce.Runtime.Messages;
using Microsoft.Dynamics.Commerce.Runtime.Services;
using Microsoft.Dynamics.Commerce.Runtime.Services.Messages;
using Microsoft.Dynamics.Commerce.Runtime.Workflow.Orders;
class GetCustomReceiptTypesRequestHandler : IRequestHandlerAsync
{
public IEnumerable SupportedRequestTypes
{
get
{
return new[]
{
typeof(CustomReceiptRequestTMC)
};
}
}
public async Task Execute(Request request)
{
if (request == null)
{
throw new ArgumentNullException("request");
}
Type reqType = ((object)request).GetType();
if (reqType == typeof(CustomReceiptRequestTMC))
{
return await this.GetReceipts((CustomReceiptRequestTMC)request).ConfigureAwait(false);
}
else
{
throw new NotSupportedException(string.Format((IFormatProvider)CultureInfo.InvariantCulture, "Request '{0}' is not supported.", (object)((object)request).GetType()));
}
}
// protected override async Task Process(GetCustomReceiptsRequest request)
private async Task GetReceipts(CustomReceiptRequestTMC request)
{
SalesOrder salesOrder;
ThrowIf.Null(request.receiptCriteria, "request.ReceiptRetrievalCriteria");
//1. The sales order that we are printing receipts for is retrieved.
salesOrder = await this.GetSalesOrderForTransactionWithId(request.RequestContext, request.transactionId).ConfigureAwait(false);
if (salesOrder == null)
{
throw new DataValidationException(
DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_ObjectNotFound,
string.Format("Unable to get the sales order created. ID: {0}", request.transactionId));
}
Collection result = new Collection();
// 2. Now we can handle any additional receipt here.
switch (request.receiptCriteria.ReceiptType)
{
// Proforma Receipt
case ReceiptType.CustomReceipt1:
{
IEnumerable customReceipts = await this.GetCustomReceiptsAsync(salesOrder, request).ConfigureAwait(false);
result.AddRange(customReceipts);
}
break;
default:
// Add more logic to handle more types of custom receipt types.
break;
}
return new CustomReceiptResponseTMC(new ReadOnlyCollection(result));
}
private async Task GetSalesOrderForTransactionWithId(RequestContext requestContext, string transactionId)
{
SalesOrder salesOrder = new SalesOrder();
SalesTransaction salesTransaction = await SalesTransactionRepository.LoadSalesTransaction(requestContext, transactionId).ConfigureAwait(false);
if (salesTransaction != null)
{
// The sales transaction is converted into a sales order so that existing receipt fields can be used.
salesOrder.CopyFrom(salesTransaction);
}
else
{
throw new DataValidationException(
DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_ObjectNotFound,
string.Format("Unable to get the sales transaction. ID: {0}", transactionId));
}
return salesOrder;
}
private async Task<Collection> GetCustomReceiptsAsync(SalesOrder salesOrder, CustomReceiptRequestTMC request)
{
//Full sample code: RetailSDK\SampleExtensions\CommerceRuntime\Extensions.SuspendTransactionReceiptSample folder.
// Also "RetailSDK\SampleExtensions\CommerceRuntime\Extensions.ReceiptsSample"
Collection result = new Collection();
ReceiptRetrievalCriteria criteria = request.receiptCriteria;
RequestContext requestContext = request.RequestContext;
// Call receipt service to get the custom receipt if printed.
if (criteria.HardwareProfileId != "NONE")
{
var getReceiptServiceRequest = new GetReceiptServiceRequest(
salesOrder,
new Collection { criteria.ReceiptType },
salesOrder.TenderLines,
criteria.IsCopy,
criteria.IsPreview,
criteria.HardwareProfileId,
includeExternalReceipt: false,
requestedReceiptType: criteria.ReceiptType);
var customReceiptsResponse = await requestContext.ExecuteAsync(getReceiptServiceRequest).ConfigureAwait(false);
ReadOnlyCollection customReceipts = customReceiptsResponse.Receipts;
// Add the custom receipt to the result collection.
result.AddRange(customReceipts);
}
else
{
List vList = await this.GetCustomEmailReceiptsAsync(request).ConfigureAwait(false);
ReadOnlyCollection customEmailReceipts = vList.AsReadOnly();
}
return result;
}
private async Task<List> GetCustomEmailReceiptsAsync(CustomReceiptRequestTMC request)
{
List result = new List(); ;
ReceiptRetrievalCriteria criteria = request.receiptCriteria;
criteria.QueryBySalesId = true;
GetCustomReceiptsRequest getCustomReceiptsRequest = new GetCustomReceiptsRequest(request.transactionId, criteria);
switch (criteria.ReceiptType)
{
case ReceiptType.CustomReceipt1:
{
var customReceipts = (await request.RequestContext.Runtime.ExecuteAsync(
getCustomReceiptsRequest, request.RequestContext).ConfigureAwait(false)).Receipts;
result.AddRange(customReceipts);
}
break;
}
return result;
}
}
}
The above works for GetReceiptServiceRequest when there is a hardware station ID other than NONE.
This is how I populate the receiptCriteria on the POS side in the handler of the custom POS operation ID:
let receiptRetrievalCriteria: ProxyEntities.ReceiptRetrievalCriteria = {
IsCopy: false,
IsRemoteTransaction: false,
IsPreview: false,
QueryBySalesId: true,
ReceiptTypeValue: ProxyEntities.ReceiptType.CustomReceipt1,
HardwareProfileId: hardwareProfile.ProfileId
};
let getCustomReceiptRequest: StoreOperations.TMCGetCustomReceiptActionRequest =
new StoreOperations.TMCGetCustomReceiptActionRequest(receiptRetrievalCriteria, salesOrderId, vRequestfor);
return me.context.runtime.executeAsync(getCustomReceiptRequest);
To print the receipt retrieved by GetReceiptserviceRequest when there is a hardware station ID other than NONE, I call the following code
public PrintReceipt(context: IExtensionContext, receipts: ProxyEntities.Receipt[]): Promise {
// Prints the receipts.
let printerPrintRequest: PrinterPrintRequest = new PrinterPrintRequest(receipts);
return context.runtime.executeAsync(printerPrintRequest);
}
The above works. I used the logic in the "RetailSDK\POS\Extensions\SuspendTransactionReceiptSample" example.
But as I said this example has no code for emailing the custom receipt type receipt.
If I can finally get the retrieval of the customReceiptType1 working, how do I email it?
I called GetReceiptEmailAddressClientRequest/GetReceiptEmailAddressClientResponse pair to prompt for the email address, but that is how far I got on the POS side. I do not see any trigger that is exposed that I can use to do the actual email of the receipt.
So any help is much appreciated. I HAVE TO get the email part to work. The customers want emails, not printouts. This has now become urgent. I will continue to try and work with Microsoft in the meantime but I don't have much hope at this point that I will get it to work from that end. It doesn't look like they have done it with a CustomReceiptType. It is just suppose dto work in theory.
So anybody who did it in real life?