public Task<PaymentProcessingResults> ExecuteAsync(PaymentProcessingData data) { using (PaymentsPerformanceLogger.Instance.Log(typeof(ProcessPaymentProcessingData))) { data.AssertNotNull("data"); var subscriberId = data.SubscriberId; var creatorId = data.CreatorId; DateTime startTimeInclusive = data.StartTimeInclusive; DateTime endTimeExclusive = data.EndTimeExclusive; IReadOnlyList<ISnapshot> orderedSnapshots = data.GetOrderedSnapshots(); IReadOnlyList<CreatorPost> posts = data.CreatorPosts; var committedAccountBalance = data.CommittedAccountBalance; var currentStartTimeInclusive = startTimeInclusive; var currentEndTimeExclusive = startTimeInclusive.AddDays(7); // This is the final time at which we can be totally sure if the creator // has posted in the billing week, as the subscriber billing week most likely // doesn't line up with the payment billing week. var committedRecordsEndTimeExclusive = endTimeExclusive.AddDays(-7); var result = new List<PaymentProcessingResult>(); while (currentEndTimeExclusive <= committedRecordsEndTimeExclusive) { // Calculate complete week. var cost = this.subscriberPaymentPipeline.CalculatePayment( orderedSnapshots, posts, subscriberId, creatorId, currentStartTimeInclusive, currentEndTimeExclusive); if (cost.Cost > committedAccountBalance.Amount) { cost = new AggregateCostSummary(committedAccountBalance.Amount); } committedAccountBalance = committedAccountBalance.Subtract(cost.Cost); var creatorPercentageOverride = PaymentProcessingUtilities.GetCreatorPercentageOverride( data.CreatorPercentageOverride, currentEndTimeExclusive); result.Add(new PaymentProcessingResult(currentStartTimeInclusive, currentEndTimeExclusive, cost, creatorPercentageOverride, true)); currentStartTimeInclusive = currentEndTimeExclusive; currentEndTimeExclusive = currentStartTimeInclusive.AddDays(7); } if (currentStartTimeInclusive < endTimeExclusive) { // Calculate uncommitted period. // We calculate without taking into account CreatorPosts, // as we assume they will post until we can be totally sure // know otherwise. var cost = this.subscriberPaymentPipeline.CalculatePayment( orderedSnapshots, null, subscriberId, creatorId, currentStartTimeInclusive, endTimeExclusive); var creatorPercentageOverride = PaymentProcessingUtilities.GetCreatorPercentageOverride( data.CreatorPercentageOverride, endTimeExclusive); result.Add(new PaymentProcessingResult(currentStartTimeInclusive, endTimeExclusive, cost, creatorPercentageOverride, false)); } return Task.FromResult(new PaymentProcessingResults(committedAccountBalance, result)); } }
public async Task ExecuteAsync(PaymentProcessingData data, PaymentProcessingResults results) { data.AssertNotNull("data"); results.AssertNotNull("results"); var committedResults = results.Items.Where(v => v.IsCommitted).ToList(); var uncommittedResult = results.Items.SingleOrDefault(v => !v.IsCommitted); var dataId = this.guidCreator.Create(); var committedRecords = new List <AppendOnlyLedgerRecord>(); foreach (var result in committedResults) { var transactionId = this.guidCreator.Create(); if (result.SubscriptionCost.Cost == 0) { // A single zero record, so we know when to start processing from // next time. committedRecords.Add(new AppendOnlyLedgerRecord( this.guidCreator.CreateSqlSequential(), data.SubscriberId.Value, data.CreatorId.Value, result.EndTimeExclusive, 0, LedgerAccountType.FifthweekCredit, LedgerTransactionType.SubscriptionPayment, transactionId, dataId, null, null, null)); continue; } committedRecords.Add(new AppendOnlyLedgerRecord( this.guidCreator.CreateSqlSequential(), data.SubscriberId.Value, data.CreatorId.Value, result.EndTimeExclusive, -result.SubscriptionCost.Cost, LedgerAccountType.FifthweekCredit, LedgerTransactionType.SubscriptionPayment, transactionId, dataId, null, null, null)); committedRecords.Add(new AppendOnlyLedgerRecord( this.guidCreator.CreateSqlSequential(), Guid.Empty, data.CreatorId.Value, result.EndTimeExclusive, result.SubscriptionCost.Cost, LedgerAccountType.FifthweekRevenue, LedgerTransactionType.SubscriptionPayment, transactionId, dataId, null, null, null)); var creatorPercentage = result.CreatorPercentageOverride == null ? Payments.Constants.DefaultCreatorPercentage : result.CreatorPercentageOverride.Percentage; var creatorPayment = result.SubscriptionCost.Cost * creatorPercentage; committedRecords.Add(new AppendOnlyLedgerRecord( this.guidCreator.CreateSqlSequential(), Guid.Empty, data.CreatorId.Value, result.EndTimeExclusive, -creatorPayment, LedgerAccountType.FifthweekRevenue, LedgerTransactionType.SubscriptionPayment, transactionId, dataId, null, null, null)); committedRecords.Add(new AppendOnlyLedgerRecord( this.guidCreator.CreateSqlSequential(), data.CreatorId.Value, data.CreatorId.Value, result.EndTimeExclusive, creatorPayment, LedgerAccountType.FifthweekRevenue, LedgerTransactionType.SubscriptionPayment, transactionId, dataId, null, null, null)); } UncommittedSubscriptionPayment uncommittedRecord = null; if (uncommittedResult != null && uncommittedResult.SubscriptionCost.Cost != 0) { uncommittedRecord = new UncommittedSubscriptionPayment( data.SubscriberId.Value, data.CreatorId.Value, uncommittedResult.StartTimeInclusive, uncommittedResult.EndTimeExclusive, uncommittedResult.SubscriptionCost.Cost, dataId); } if (committedRecords.Count > 0) { await this.persistPaymentProcessingData.ExecuteAsync(new PersistedPaymentProcessingData(dataId, data, results)); } if (committedRecords.Count > 0 || uncommittedResult != null) { await this.persistCommittedAndUncommittedRecords.ExecuteAsync(data.SubscriberId, data.CreatorId, committedRecords, uncommittedRecord); } }