public async Task AddBonusOperationAsync(BonusOperation bonusOperation) { var campaignId = bonusOperation.CampaignId.ToGuid(); var bonusIssuedEvent = new BonusIssuedEvent { OperationId = Guid.NewGuid(), Amount = bonusOperation.Reward, CampaignId = campaignId, ConditionId = bonusOperation.BonusOperationType == Domain.Enums.BonusOperationType.CampaignReward ? Guid.Empty : bonusOperation.ConditionId.ToGuid(), PartnerId = bonusOperation.PartnerId, LocationId = bonusOperation.LocationId, UnitLocationCode = bonusOperation.UnitLocationCode, CustomerId = bonusOperation.CustomerId, BonusOperationType = _mapper.Map <BonusOperationType>(bonusOperation.BonusOperationType), TimeStamp = bonusOperation.TimeStamp, ReferralId = bonusOperation.ReferralId }; // Zero reward operations are not accepted by blockchain facade if (bonusIssuedEvent.Amount > 0) { await _bonusIssuedPublisher.PublishAsync(bonusIssuedEvent); _log.Info( $"Bonus issued: {bonusIssuedEvent.ToJson()}", bonusIssuedEvent.BonusOperationType, process: nameof(AddBonusOperationAsync)); } }
private async Task ProcessCampaignForCustomerAsync(MAVN.Service.BonusEngine.Domain.Models.Campaign campaign, CampaignCompletion campaignCompletion, Guid operationId, IReadOnlyDictionary <string, string> data) { var customerId = campaignCompletion.CustomerId; var campaignId = campaign.Id; var conditionCompletions = await _conditionCompletionService .GetConditionCompletionsAsync(customerId, campaignId); if (IsCampaignCompleted(conditionCompletions, campaign) == false) { return; } var reward = await _bonusCalculatorService.CalculateRewardAmountAsync(campaign, customerId, conditionCompletions); var bonusOperation = new BonusOperation { CustomerId = customerId, CampaignId = campaignId, ExternalOperationId = operationId, Reward = reward, TimeStamp = DateTime.UtcNow, BonusOperationType = BonusOperationType.CampaignReward }; if (data.TryGetValue(ReferralId, out string referralId)) { bonusOperation.ReferralId = referralId; } await _bonusOperationService.AddBonusOperationAsync(bonusOperation); _log.Info("Customer completed all condition in campaign.", context: $"operationId: {operationId}; campaignId: {campaignId}; customerId: {customerId}"); await _campaignCompletionService.IncreaseCompletionCountAsync(campaignCompletion, campaign, conditionCompletions); }
private async Task ProcessConditionsForCustomerAsync( string customerId, string partnerId, string locationId, string campaignId, IEnumerable <Condition> conditions, IReadOnlyDictionary <string, string> data, Guid operationId) { // Doesn't make sense to have multiple of the same conditions in the same campaign, but just in case foreach (var condition in conditions) { // If condition has any partners we need to make sure we match one them, otherwise just skip the check if (condition.PartnerIds != null && condition.PartnerIds.Any()) { if (!Guid.TryParse(partnerId, out var partnerIdGuid) || !condition.PartnerIds.Contains(partnerIdGuid)) { _log.Info("The partner identifier does not match campaign condition partners.", context: $"partnerId: {partnerId}'; conditionId: {condition.Id}"); continue; } } var conditionCompletion = await _conditionCompletionService .GetConditionCompletionAsync(customerId, condition.Id); // ConditionCompletion being null is a valid case handled by IncreaseOrCreateAsync if (conditionCompletion != null && conditionCompletion.IsCompleted) { continue; } conditionCompletion = await _conditionCompletionService .IncreaseOrCreateAsync(customerId, conditionCompletion, data, condition); Money18 reward = 0; if (condition.RewardHasRatio && condition.RewardRatio != null) { if (data.TryGetValue(PaymentId, out string paymentId)) { reward = await _bonusCalculatorService.CalculateConditionRewardRatioAmountAsync(condition, conditionCompletion, paymentId); } else { _log.Error("No paymentId was passed"); } } else { reward = await _bonusCalculatorService.CalculateConditionRewardAmountAsync(condition, conditionCompletion); } if (reward > 0.0M) { var bonusOperation = new BonusOperation { CustomerId = customerId, CampaignId = campaignId, ConditionId = condition.Id, ExternalOperationId = operationId, PartnerId = partnerId, LocationId = locationId, Reward = reward, TimeStamp = DateTime.UtcNow, BonusOperationType = BonusOperationType.ConditionReward }; if (data.TryGetValue(UnitLocationCodeKey, out string locationCode)) { bonusOperation.UnitLocationCode = locationCode; } if (data.TryGetValue(ReferralId, out string referralId)) { bonusOperation.ReferralId = referralId; } else if (data.TryGetValue(PaymentId, out string paymentId)) { bonusOperation.ReferralId = paymentId; } await _bonusOperationService.AddBonusOperationAsync(bonusOperation); } if (conditionCompletion.CurrentCount == condition.CompletionCount && !condition.RewardHasRatio) { await _conditionCompletionService.SetConditionCompletedAsync(conditionCompletion.Id); _log.Info("Customer completed condition.", context: $"operationId: {operationId}; campaignId: {campaignId}; conditionId: {condition.Id}; customerId: {customerId}"); } else if (condition.RewardHasRatio) { var lastThreshold = _conditionCompletionService.SetConditionCompletionLastGivenRatioReward(data, condition, conditionCompletion, out bool allGiven); if (lastThreshold >= 100m && conditionCompletion.CurrentCount == condition.CompletionCount && allGiven) { conditionCompletion.IsCompleted = true; _log.Info("Customer completed condition.", context: $"operationId: {operationId}; campaignId: {campaignId}; conditionId: {condition.Id}; customerId: {customerId}"); } else { _log.Info("Customer not complete condition.", context: $"operationId: {operationId}; campaignId: {campaignId}; conditionId: {condition.Id}; customerId: {customerId}; currentCount: {conditionCompletion.CurrentCount}; requiredCount {condition.CompletionCount ?? int.MaxValue}"); } await _conditionCompletionService.UpdateAsync(conditionCompletion); } else { _log.Info("Customer not complete condition.", context: $"operationId: {operationId}; campaignId: {campaignId}; conditionId: {condition.Id}; customerId: {customerId}; currentCount: {conditionCompletion.CurrentCount}; requiredCount {condition.CompletionCount ?? int.MaxValue}"); } } }
private void CreateConditionTestData() { BonusType = new BonusType { Type = BonusTypeName, DisplayName = BonusTypeName }; ConditionModel = new Condition() { CampaignId = CampaignId, CompletionCount = 1, BonusType = BonusType, Id = ConditionId, ImmediateReward = 10 }; ConditionModels = new List <Condition>() { ConditionModel }; NewConditionCompletion = new ConditionCompletion { CustomerId = CustomerId, ConditionId = ConditionId, Id = ConditionCompletionsId, CurrentCount = 0, IsCompleted = false }; ConditionCompletions = new List <ConditionCompletion>(); NewConditionBonusOperation = new BonusOperation { CustomerId = CustomerId, Reward = ConditionModel.ImmediateReward, BonusOperationType = BonusOperationType.CampaignReward }; CampaignModel = new CampaignModel() { Name = "SignUp Campaign", Reward = 20, Id = CampaignId, CompletionCount = 1, Conditions = new List <Condition>() { ConditionModel } }; CampaignModels = new List <CampaignModel>() { CampaignModel }; CampaignCompletion = new CampaignCompletion() { CustomerId = CustomerId, CampaignId = CampaignId, CampaignCompletionCount = 0 }; CampaignCompletions = new List <CampaignCompletion>() { CampaignCompletion }; NewCampaignBonusOperation = new BonusOperation { CustomerId = CustomerId, Reward = CampaignModel.Reward, BonusOperationType = BonusOperationType.CampaignReward }; }