/// <summary> /// Calculate specific reason codes on an affiliation line and add them to the incoming collection. /// </summary> /// <param name="request">The request object.</param> /// <param name="requiredReasonCodes">The collection to which required reason codes are added.</param> /// <param name="reasonCodeRequirements">The required specific reason codes map.</param> /// <param name="salesAffiliationLoyaltyTier">The sales affiliation loyalty tier on which to calculate required reason codes.</param> private static void CalculateRequiredSpecificReasonCodesOnAffiliationLine( CalculateRequiredReasonCodesServiceRequest request, IDictionary <string, ReasonCode> requiredReasonCodes, HashSet <ReasonCodeRequirement> reasonCodeRequirements, SalesAffiliationLoyaltyTier salesAffiliationLoyaltyTier) { // Gets the affiliation according to the foreign key AffiliationId of the salesAffiliationLoyaltyTier. GetAffiliationByAffiliationIdDataRequest dataRequest = new GetAffiliationByAffiliationIdDataRequest(salesAffiliationLoyaltyTier.AffiliationId); Affiliation affiliation = request.RequestContext.Execute <SingleEntityDataServiceResponse <Affiliation> >(dataRequest).Entity; if (affiliation != null) { CalculateReasonCodesSpecificToEntity( request, salesAffiliationLoyaltyTier.AffiliationId.ToString(CultureInfo.InvariantCulture), ReasonCodeTableRefType.Affiliation, affiliation.Name, string.Empty, string.Empty, requiredReasonCodes, reasonCodeRequirements, salesAffiliationLoyaltyTier.ReasonCodeLines, null); } }
/// <summary> /// Calculates the required reason codes on an income expense line. /// </summary> /// <param name="requestContext">The request context.</param> /// <param name="transaction">Current transaction.</param> /// <param name="incomeExpenseLine">The income expense line.</param> /// <param name="sourceType">Type of the source.</param> public static void CalculateRequiredReasonCodesOnIncomeExpenseLine(RequestContext requestContext, SalesTransaction transaction, IncomeExpenseLine incomeExpenseLine, ReasonCodeSourceType sourceType) { ThrowIf.Null(requestContext, "requestContext"); ThrowIf.Null(incomeExpenseLine, "incomeExpenseLine"); var serviceRequest = new CalculateRequiredReasonCodesServiceRequest(transaction, sourceType, new[] { incomeExpenseLine }); CalculateRequiredReasonCodesHelper(requestContext, serviceRequest); }
/// <summary> /// Calculates the required reason codes on affiliation line. /// </summary> /// <param name="requestContext">The request context.</param> /// <param name="transaction">Current transaction.</param> /// <param name="salesAffiliationLoyaltyTiers">The sales affiliation lines.</param> /// <param name="sourceType">Type of the source.</param> public static void CalculateRequiredReasonCodesOnAffiliationLines(RequestContext requestContext, SalesTransaction transaction, IEnumerable <SalesAffiliationLoyaltyTier> salesAffiliationLoyaltyTiers, ReasonCodeSourceType sourceType) { ThrowIf.Null(requestContext, "requestContext"); ThrowIf.Null(salesAffiliationLoyaltyTiers, "salesAffiliationLoyaltyTiers"); var serviceRequest = new CalculateRequiredReasonCodesServiceRequest(transaction, sourceType, salesAffiliationLoyaltyTiers); CalculateRequiredReasonCodesHelper(requestContext, serviceRequest); }
/// <summary> /// Calculates the required reason codes on tender line. /// </summary> /// <param name="requestContext">The request context.</param> /// <param name="transaction">Current transaction.</param> /// <param name="tenderLine">The tender line.</param> /// <param name="sourceType">Type of the source.</param> public static void CalculateRequiredReasonCodesOnTenderLine(RequestContext requestContext, SalesTransaction transaction, TenderLine tenderLine, ReasonCodeSourceType sourceType) { ThrowIf.Null(requestContext, "requestContext"); ThrowIf.Null(tenderLine, "tenderLine"); var serviceRequest = new CalculateRequiredReasonCodesServiceRequest(transaction, sourceType, new[] { tenderLine }); CalculateRequiredReasonCodesHelper(requestContext, serviceRequest); }
/// <summary> /// Calculates the required reason codes on the current sales transaction level. /// </summary> /// <param name="requestContext">The request context.</param> /// <param name="salesTransaction">The sales transaction.</param> /// <param name="sourceType">Type of the source.</param> public static void CalculateRequiredReasonCodesOnTransaction(RequestContext requestContext, SalesTransaction salesTransaction, ReasonCodeSourceType sourceType) { ThrowIf.Null(requestContext, "requestContext"); ThrowIf.Null(salesTransaction, "salesTransaction"); var serviceRequest = new CalculateRequiredReasonCodesServiceRequest(salesTransaction, sourceType); CalculateRequiredReasonCodesHelper(requestContext, serviceRequest); }
/// <summary> /// Validates the required reason code lines filled. /// </summary> /// <param name="requestContext">The request context.</param> /// <param name="salesTransaction">The sales transaction.</param> /// <exception cref="ConfigurationException">Required Service missing.</exception> /// <exception cref="DataValidationException">One or more reason codes required for the transaction are missing.</exception> public static void ValidateRequiredReasonCodeLinesFilled(RequestContext requestContext, SalesTransaction salesTransaction) { ThrowIf.Null(requestContext, "requestContext"); ThrowIf.Null(salesTransaction, "salesTransaction"); var serviceRequest = new CalculateRequiredReasonCodesServiceRequest(salesTransaction, ReasonCodeSourceType.None); var serviceResponse = requestContext.Execute <CalculateRequiredReasonCodesServiceResponse>(serviceRequest); ReasonCodesWorkflowHelper.ThrowIfRequiredReasonCodesMissing(serviceResponse); }
/// <summary> /// Calculates the specific reason code on an entity like sales line, tender line etc. /// </summary> /// <param name="request">The request.</param> /// <param name="sourceId">The source identifier.</param> /// <param name="tableRefType">The table identifier for the specific reason code.</param> /// <param name="refRelation">The first reference relation key corresponding to the entity and table.</param> /// <param name="refRelation2">The second reference relation key corresponding to the entity and table.</param> /// <param name="refRelation3">The third reference relation key corresponding to the entity and table.</param> /// <param name="requiredReasonCodes">The collection to which required reason codes are added.</param> /// <param name="reasonCodeRequirements">The required specific reason codes map.</param> /// <param name="presentReasonCodeLines">The collection with the already present reason code lines.</param> /// <param name="salesLine">The sales line when applicable.</param> private static void CalculateReasonCodesSpecificToEntity( CalculateRequiredReasonCodesServiceRequest request, string sourceId, ReasonCodeTableRefType tableRefType, string refRelation, string refRelation2, string refRelation3, IDictionary <string, ReasonCode> requiredReasonCodes, HashSet <ReasonCodeRequirement> reasonCodeRequirements, IEnumerable <ReasonCodeLine> presentReasonCodeLines, SalesLine salesLine) { GetReasonCodesByTableRefTypeDataRequest getReasonCodesByTableRefTypeDataRequest = new GetReasonCodesByTableRefTypeDataRequest(tableRefType, refRelation, refRelation2, refRelation3, QueryResultSettings.AllRecords); IEnumerable <ReasonCode> reasonCodes = request.RequestContext.Runtime.Execute <EntityDataServiceResponse <ReasonCode> >(getReasonCodesByTableRefTypeDataRequest, request.RequestContext).PagedEntityCollection.Results; reasonCodes = AddLinkedReasonCodes(reasonCodes, request.RequestContext); var triggeredReasonCodes = CalculateTriggeredReasonCodes(reasonCodes, presentReasonCodeLines, request.RequestContext); reasonCodes = reasonCodes.Union(triggeredReasonCodes).Distinct(); reasonCodes = AddLinkedReasonCodes(reasonCodes, request.RequestContext); foreach (var reasonCode in reasonCodes) { if (presentReasonCodeLines.Any(rc => string.Equals(rc.ReasonCodeId, reasonCode.ReasonCodeId, StringComparison.OrdinalIgnoreCase))) { continue; } bool entitySpecificApplicability = true; switch (tableRefType) { case ReasonCodeTableRefType.Item: entitySpecificApplicability = HasSalesLineSpecificApplicability(reasonCode, salesLine); break; } if (entitySpecificApplicability && ShouldReasonCodeBeApplied(reasonCode, request.SalesTransaction)) { var reasonCodeRequirement = new ReasonCodeRequirement() { ReasonCodeId = reasonCode.ReasonCodeId, SourceId = sourceId, TableRefTypeValue = (int)tableRefType, }; reasonCodeRequirements.Add(reasonCodeRequirement); requiredReasonCodes[reasonCode.ReasonCodeId] = reasonCode; } } }
/// <summary> /// Calculate specific reason codes on a tender line and add them to the incoming collection. /// </summary> /// <param name="request">The request object.</param> /// <param name="requiredReasonCodes">The collection to which required reason codes are added.</param> /// <param name="reasonCodeRequirements">The required specific reason codes map.</param> /// <param name="tenderLine">The tenderLine on which to calculate required reason codes.</param> private static void CalculateRequiredSpecificReasonCodesOnTenderLine( CalculateRequiredReasonCodesServiceRequest request, IDictionary <string, ReasonCode> requiredReasonCodes, HashSet <ReasonCodeRequirement> reasonCodeRequirements, TenderLine tenderLine) { if (tenderLine.Status == TenderLineStatus.Historical) { return; } // if tenderline is a card, refrelation3 becomes tenderline.cardtypeid and tablerefid is creditcard var getChannelTenderTypesDataRequest = new GetChannelTenderTypesDataRequest(request.RequestContext.GetPrincipal().ChannelId, QueryResultSettings.AllRecords); var tenderTypes = request.RequestContext.Runtime.Execute <EntityDataServiceResponse <TenderType> >(getChannelTenderTypesDataRequest, request.RequestContext).PagedEntityCollection.Results; ReasonCodeTableRefType tableRef = ReasonCodeTableRefType.Tender; string refRelation3 = string.Empty; TenderType tenderType = tenderTypes.Where(type => type.TenderTypeId == tenderLine.TenderTypeId).SingleOrDefault(); if (tenderType.OperationId == (int)RetailOperation.PayCard) { refRelation3 = tenderLine.CardTypeId; tableRef = ReasonCodeTableRefType.CreditCard; } CalculateReasonCodesSpecificToEntity( request, tenderLine.TenderTypeId, tableRef, request.SalesTransaction.StoreId, tenderLine.TenderTypeId, refRelation3, requiredReasonCodes, reasonCodeRequirements, tenderLine.ReasonCodeLines, null); }
/// <summary> /// Calculates the required reason codes. /// </summary> /// <param name="request">The request.</param> /// <returns>The info codes response.</returns> private static CalculateRequiredReasonCodesServiceResponse CalculateRequiredReasonCodes(CalculateRequiredReasonCodesServiceRequest request) { CalculateRequiredReasonCodesServiceResponse response = ReasonCodesCalculator.CalculateRequiredReasonCodes(request); SetProductIdsForUpsell(request.RequestContext, response.RequiredReasonCodes); return(response); }
/// <summary> /// Helper methods to calculates the required reason codes. /// </summary> /// <param name="requestContext">The request context.</param> /// <param name="serviceRequest">The service request.</param> /// <exception cref="ConfigurationException">Required Service missing: {0}.</exception> private static void CalculateRequiredReasonCodesHelper(RequestContext requestContext, CalculateRequiredReasonCodesServiceRequest serviceRequest) { ThrowIf.Null(serviceRequest.SalesTransaction, "serviceRequest.SalesTransaction"); // Reason codes are only calculated for retail stores and carts that are not customer orders. if ((requestContext.GetChannelConfiguration().ChannelType == RetailChannelType.RetailStore) && (serviceRequest.SalesTransaction.CartType != CartType.CustomerOrder)) { var serviceResponse = requestContext.Execute <CalculateRequiredReasonCodesServiceResponse>(serviceRequest); ReasonCodesWorkflowHelper.ThrowIfRequiredReasonCodesMissing(serviceResponse); } }
/// <summary> /// Calculates the required reason codes. /// </summary> /// <param name="request">The request.</param> /// <returns>The calculate required reason codes response.</returns> public static CalculateRequiredReasonCodesServiceResponse CalculateRequiredReasonCodes(CalculateRequiredReasonCodesServiceRequest request) { // Keeps track of required reason code lines added. Dictionary <string, ReasonCode> requiredReasonCodes = new Dictionary <string, ReasonCode>(); HashSet <string> transactionRequiredReasonCodeIds = new HashSet <string>(StringComparer.OrdinalIgnoreCase); HashSet <ReasonCodeRequirement> reasonCodeRequirements = new HashSet <ReasonCodeRequirement>(); // calculate reason codes for source type CalculateRequiredReasonCodesBySourceType(request, requiredReasonCodes, transactionRequiredReasonCodeIds, reasonCodeRequirements); // calculate reason codes for sales lines foreach (var salesLine in request.SalesLines) { // calculate specific reason codes CalculateReasonCodesSpecificToEntity( request, salesLine.ProductId.ToString(CultureInfo.InvariantCulture), ReasonCodeTableRefType.Item, salesLine.ItemId, string.Empty, string.Empty, requiredReasonCodes, reasonCodeRequirements, salesLine.ReasonCodeLines, salesLine); } // calculate reason codes for tender lines foreach (var tenderLine in request.TenderLines) { // calculate specific reason codes CalculateRequiredSpecificReasonCodesOnTenderLine( request, requiredReasonCodes, reasonCodeRequirements, tenderLine); } // calculate reason codes for affiliation lines foreach (var salesAffiliationLoyaltyTier in request.SalesAffiliationLoyaltyTiers) { // Calculate specific reason codes CalculateRequiredSpecificReasonCodesOnAffiliationLine( request, requiredReasonCodes, reasonCodeRequirements, salesAffiliationLoyaltyTier); } // calculate reason codes for income expense lines foreach (var incomeExpenseLine in request.SalesTransaction.IncomeExpenseLines) { CalculateReasonCodesSpecificToEntity( request, System.Enum.GetName(typeof(IncomeExpenseAccountType), incomeExpenseLine.AccountType), ReasonCodeTableRefType.IncomeExpense, incomeExpenseLine.StoreNumber, incomeExpenseLine.IncomeExpenseAccount, string.Empty, requiredReasonCodes, reasonCodeRequirements, request.SalesTransaction.ReasonCodeLines, null); } // calculate reason codes for customer CalculateReasonCodesSpecificToEntity( request, request.SalesTransaction.CustomerId, ReasonCodeTableRefType.Customer, request.SalesTransaction.CustomerId, string.Empty, string.Empty, requiredReasonCodes, reasonCodeRequirements, request.SalesTransaction.ReasonCodeLines, null); // move the customer and income expense reason codes to transaction level. var ids = reasonCodeRequirements.Where(r => (r.TableRefType == ReasonCodeTableRefType.IncomeExpense || r.TableRefType == ReasonCodeTableRefType.Customer)) .Select(r => r.ReasonCodeId); transactionRequiredReasonCodeIds.AddRange(ids); return(new CalculateRequiredReasonCodesServiceResponse( requiredReasonCodes.Values, transactionRequiredReasonCodeIds, reasonCodeRequirements)); }
/// <summary> /// Calculates the required reason codes given the source type. /// </summary> /// <param name="request">The request.</param> /// <param name="requiredReasonCodes">The collection to which required reason codes are added.</param> /// <param name="transactionRequiredReasonCodeIds">The identifiers of reason codes required at transaction level.</param> /// <param name="reasonCodeRequirements">The collection of reason code requirements.</param> private static void CalculateRequiredReasonCodesBySourceType( CalculateRequiredReasonCodesServiceRequest request, Dictionary <string, ReasonCode> requiredReasonCodes, HashSet <string> transactionRequiredReasonCodeIds, HashSet <ReasonCodeRequirement> reasonCodeRequirements) { // Look up operation level reason codes if available. if (request.SourceType != ReasonCodeSourceType.None) { ReasonCodeSettings settingsDictionary = GetReasonCodeSettings(request.RequestContext); string reasonCodeId = settingsDictionary[request.SourceType]; if (!string.IsNullOrWhiteSpace(reasonCodeId)) { GetReasonCodesDataRequest getReasonCodeRequest = new GetReasonCodesDataRequest(QueryResultSettings.AllRecords, new string[] { reasonCodeId }); IEnumerable <ReasonCode> reasonCodes = request.RequestContext.Execute <EntityDataServiceResponse <ReasonCode> >(getReasonCodeRequest).PagedEntityCollection.Results; foreach (var reasonCode in reasonCodes) { if (IsTransactionSourceType(request.SourceType) && ShouldReasonCodeBeApplied(reasonCode, request.SalesTransaction)) { if (!ContainsReasonCode(request.SalesTransaction.ReasonCodeLines, reasonCode.ReasonCodeId)) { requiredReasonCodes[reasonCode.ReasonCodeId] = reasonCode; transactionRequiredReasonCodeIds.Add(reasonCode.ReasonCodeId); } var triggeredReasonCodes = CalculateTriggeredReasonCodes( new ReasonCode[] { reasonCode }, request.SalesTransaction.ReasonCodeLines, request.RequestContext); if (triggeredReasonCodes.Any()) { requiredReasonCodes.AddRange(triggeredReasonCodes.ToDictionary(rc => rc.ReasonCodeId, rc => rc)); transactionRequiredReasonCodeIds.AddRange(triggeredReasonCodes.Select(rc => rc.ReasonCodeId)); } } else { foreach (var salesLine in request.SalesLines) { if (ShouldReasonCodeBeApplied(reasonCode, request.SalesTransaction)) { if (!ContainsReasonCode(salesLine.ReasonCodeLines, reasonCode.ReasonCodeId)) { var reasonCodeRequirement = new ReasonCodeRequirement() { ReasonCodeId = reasonCode.ReasonCodeId, SourceId = salesLine.ProductId.ToString(CultureInfo.InvariantCulture), TableRefTypeValue = (int)ReasonCodeTableRefType.Item, }; reasonCodeRequirements.Add(reasonCodeRequirement); requiredReasonCodes[reasonCode.ReasonCodeId] = reasonCode; } var triggeredReasonCodes = CalculateTriggeredReasonCodes( new ReasonCode[] { reasonCode }, salesLine.ReasonCodeLines, request.RequestContext); if (triggeredReasonCodes.Any()) { requiredReasonCodes.AddRange(triggeredReasonCodes.ToDictionary(rc => rc.ReasonCodeId, rc => rc)); reasonCodeRequirements.AddRange(triggeredReasonCodes.Select(rc => new ReasonCodeRequirement() { ReasonCodeId = rc.ReasonCodeId, SourceId = salesLine.ProductId.ToString(CultureInfo.InvariantCulture), TableRefTypeValue = (int)ReasonCodeTableRefType.Item, })); } } } } } } } }