/// <summary> /// Calculates the loyalty reward points for a given transaction. /// </summary> /// <param name="request">The request containing the transaction.</param> /// <returns>The response containing the transaction with calculated reward points.</returns> private static CalculateLoyaltyRewardPointsServiceResponse CalculateLoyaltyRewardPoints(CalculateLoyaltyRewardPointsServiceRequest request) { if (request == null) { throw new ArgumentNullException("request"); } if (request.SalesTransaction == null) { throw new ArgumentNullException("request", "request.SalesTransaction"); } // Calculate loyalty only when the loyalty card number exists. // Calculate loyalty only when the transaction type is Sales (i.e. Cash and carry). // Other transactions such as PendingOrder and CustomerOrder will calculate in HQ after invoicing. var loyaltyCardNumber = request.SalesTransaction.LoyaltyCardId; if (!string.IsNullOrWhiteSpace(loyaltyCardNumber) && request.SalesTransaction.TransactionType == Microsoft.Dynamics.Commerce.Runtime.DataModel.SalesTransactionType.Sales) { // Clear existing reward point lines. if (request.SalesTransaction.LoyaltyRewardPointLines != null && request.SalesTransaction.LoyaltyRewardPointLines.Count > 0) { IEnumerable <LoyaltyRewardPointLine> otherLines = request.SalesTransaction.LoyaltyRewardPointLines.Where <LoyaltyRewardPointLine>( l => (l.EntryType != LoyaltyRewardPointEntryType.Earn && l.EntryType != LoyaltyRewardPointEntryType.ReturnEarned)); request.SalesTransaction.LoyaltyRewardPointLines = new Collection <LoyaltyRewardPointLine>(otherLines.ToList()); } // Find the applied earn scheme lines of the current channel var getLoyaltySchemeLineEarnDataRequest = new GetLoyaltySchemeLineEarnDataRequest(request.RequestContext.GetPrincipal().ChannelId, loyaltyCardNumber); getLoyaltySchemeLineEarnDataRequest.QueryResultSettings = QueryResultSettings.AllRecords; var earnSchemeLines = request.RequestContext.Execute <EntityDataServiceResponse <LoyaltySchemeLineEarn> >(getLoyaltySchemeLineEarnDataRequest).PagedEntityCollection.Results; // Calculate returned reward points, deduct points first before earn new points LoyaltyServiceHelper.FillInLoyaltyRewardPointLinesForReturn(request.RequestContext, request.SalesTransaction, earnSchemeLines, loyaltyCardNumber); // Calculate earned reward points LoyaltyServiceHelper.FillInLoyaltyRewardPointLinesForSales(request.RequestContext, request.SalesTransaction, earnSchemeLines, loyaltyCardNumber); } var response = new CalculateLoyaltyRewardPointsServiceResponse(request.SalesTransaction); return(response); }
/// <summary> /// Authorizes the payment. /// This step checks whether the loyalty card has enough reward points to redeem. If yes, it decides the points /// to redeem based on redeem ranking. /// </summary> /// <param name="request">The request.</param> /// <returns>A response containing the authorized tender line.</returns> private static AuthorizePaymentServiceResponse AuthorizePayment(AuthorizePaymentServiceRequest request) { if (request == null) { throw new ArgumentNullException("request"); } if (request.TenderLine == null) { throw new ArgumentException("request.TenderLine cannot be null."); } if (request.RequestContext == null) { throw new ArgumentException("request.RequestContext cannot be null."); } if (request.Transaction == null) { throw new ArgumentException("request.Transaction cannot be null."); } // Check tender amount. if (request.TenderLine.Amount == 0m) { throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidPaymentRequest, "The tender amount must be greater than zero."); } // Check tender currency. if (string.IsNullOrWhiteSpace(request.TenderLine.Currency)) { throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidPaymentRequest, "The tender currency is missing."); } // Check if the transaction already has loyalty payments var activeTenderLines = request.Transaction.ActiveTenderLines; if (activeTenderLines != null && activeTenderLines.Any(line => !string.IsNullOrWhiteSpace(line.LoyaltyCardId))) { throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_NoMoreThanOneLoyaltyTender, "The transaction cannot contain more than one loyalty payment line."); } SalesOrder salesOrder = request.Transaction as SalesOrder; if (salesOrder != null && salesOrder.HasLoyaltyPayment && (salesOrder.CustomerOrderMode != CustomerOrderMode.Cancellation || salesOrder.AmountDue > decimal.Zero)) { throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_NoMoreThanOneLoyaltyTender, "The transaction cannot contain more than one loyalty payment line."); } // Check whether the loyalty card is valid. var getLoyaltyCardDataRequest = new GetLoyaltyCardDataRequest(request.TenderLine.LoyaltyCardId); LoyaltyCard loyaltyCard = request.RequestContext.Execute <SingleEntityDataServiceResponse <LoyaltyCard> >(getLoyaltyCardDataRequest).Entity; if (loyaltyCard == null || string.IsNullOrWhiteSpace(loyaltyCard.CardNumber)) { throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidLoyaltyCardNumber, "The loyalty card number does not exists."); } // Check whether the loyalty card is blocked. if (loyaltyCard.CardTenderType == LoyaltyCardTenderType.Blocked) { throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_BlockedLoyaltyCard, "The loyalty card is blocked."); } if (loyaltyCard.CardTenderType == LoyaltyCardTenderType.NoTender) { throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_NoTenderLoyaltyCard, "The loyalty card is not allowed for payment."); } // Calculate redeem trans and fill in the sales transaction. if (request.TenderLine.Amount >= 0) { LoyaltyServiceHelper.FillInLoyaltyRewardPointLinesForPayment( request.RequestContext, request.Transaction, loyaltyCard, request.TenderLine.Amount, request.TenderLine.Currency); } else { LoyaltyServiceHelper.FillInLoyaltyRewardPointLinesForRefund( request.RequestContext, request.Transaction, loyaltyCard, request.TenderLine.Amount, request.TenderLine.Currency); } // Set Card Type Id for Loyalty Card if not set by the client. if (request.TenderLine.CardTypeId == null) { string tenderTypeId = request.TenderLine.TenderTypeId; var cardTypeDataRequest = new GetCardTypeDataRequest(QueryResultSettings.AllRecords); var cardTypeInfoResponse = request.RequestContext.Execute <EntityDataServiceResponse <CardTypeInfo> >(cardTypeDataRequest); IEnumerable <CardTypeInfo> cardTypes = cardTypeInfoResponse.PagedEntityCollection.Results; CardTypeInfo loyaltyCardTypeInfo = cardTypes.FirstOrDefault(cardType => cardType.PaymentMethodId == tenderTypeId); if (loyaltyCardTypeInfo == null) { throw new ConfigurationException(ConfigurationErrors.Microsoft_Dynamics_Commerce_Runtime_ConfigurationSettingNotFound, "The loyalty card payment as a tender type card is not configured for the channel."); } request.TenderLine.CardTypeId = loyaltyCardTypeInfo.TypeId; } // Authorize. request.TenderLine.Status = TenderLineStatus.PendingCommit; request.TenderLine.IsVoidable = true; return(new AuthorizePaymentServiceResponse(request.TenderLine)); }