public async Task WhenDataRepresentsAPartialWeek_ItShouldReturnUncommittedResult()
        {
            var data = this.CreateData(StartTimeInclusive, StartTimeInclusive.AddDays(14).AddTicks(-1));

            var cost = new AggregateCostSummary(10);

            this.subscriberPaymentPipeline.Setup(v => v.CalculatePayment(
                                                     data.GetOrderedSnapshots(),
                                                     null,
                                                     SubscriberId,
                                                     CreatorId,
                                                     data.StartTimeInclusive,
                                                     data.EndTimeExclusive)).Returns(cost);

            var result = await this.target.ExecuteAsync(data);

            Assert.AreEqual(
                new PaymentProcessingResults(
                    InitialCommittedAccountBalance,
                    new List <PaymentProcessingResult>
            {
                new PaymentProcessingResult(
                    data.StartTimeInclusive,
                    data.EndTimeExclusive,
                    new AggregateCostSummary(10),
                    null,
                    false),
            }),
                result);
        }
        public void ItShouldCallServicesInOrder()
        {
            var snapshots = new List <ISnapshot> {
                CreatorChannelsSnapshot.Default(Now, new UserId(Guid.NewGuid()))
            };
            var creatorPosts = new List <CreatorPost> {
                new CreatorPost(new Api.Channels.Shared.ChannelId(Guid.NewGuid()), Now)
            };

            var trimmedAtEndSnapshots = new List <ISnapshot> {
                CreatorChannelsSnapshot.Default(Now, new UserId(Guid.NewGuid()))
            };

            this.trimSnapshotsAtEnd.Setup(v => v.Execute(EndTimeExclusive, snapshots)).Returns(trimmedAtEndSnapshots);

            this.verifySnapshots.Setup(v => v.Execute(StartTimeInclusive, EndTimeExclusive, SubscriberId1, CreatorId1, trimmedAtEndSnapshots));

            var mergedSnapshots = CreateMergedSnapshotResult();

            this.mergeSnapshots.Setup(v => v.Execute(SubscriberId1, CreatorId1, StartTimeInclusive, trimmedAtEndSnapshots))
            .Returns(mergedSnapshots);

            var rolledBackSnapshots = CreateMergedSnapshotResult();

            this.rollBackSubscriptions.Setup(v => v.Execute(mergedSnapshots)).Returns(rolledBackSnapshots);

            var rolledForwardSnapshots = CreateMergedSnapshotResult();

            this.rollForwardSubscriptions.Setup(v => v.Execute(EndTimeExclusive, rolledBackSnapshots)).Returns(rolledForwardSnapshots);

            var trimmedAtStartSnapshots = CreateMergedSnapshotResult();

            this.trimSnapshotsAtStart.Setup(v => v.Execute(StartTimeInclusive, rolledForwardSnapshots)).Returns(trimmedAtStartSnapshots);

            var snapshotsWithBillingDates = CreateMergedSnapshotResult();

            this.addSnapshotsForBillingEndDates.Setup(v => v.Execute(trimmedAtStartSnapshots)).Returns(snapshotsWithBillingDates);

            var costPeriods = new List <CostPeriod> {
                new CostPeriod(StartTimeInclusive, EndTimeExclusive, 101)
            };

            this.calculateCostPeriods.Setup(v => v.Execute(StartTimeInclusive, EndTimeExclusive, snapshotsWithBillingDates, creatorPosts))
            .Returns(costPeriods);

            var aggregateCost = new AggregateCostSummary(201);

            this.aggregateCostPeriods.Setup(v => v.Execute(costPeriods)).Returns(aggregateCost);

            var result = this.target.CalculatePayment(snapshots, creatorPosts, SubscriberId1, CreatorId1, StartTimeInclusive, EndTimeExclusive);

            Assert.AreEqual(aggregateCost, result);
        }
        public async Task WhenExaclyTwoWeeksAndCreatorPercentageOverrideSpecifiedAndExpiredInCommittedWeek_ItShouldNotIncludeInResults()
        {
            var creatorPercentageOverride = new CreatorPercentageOverrideData(
                0.9m,
                StartTimeInclusive.AddDays(7).AddTicks(-1));

            var data = this.CreateData(
                StartTimeInclusive,
                StartTimeInclusive.AddDays(14),
                creatorPercentageOverride);

            var cost1 = new AggregateCostSummary(10);

            this.subscriberPaymentPipeline.Setup(v => v.CalculatePayment(
                                                     data.GetOrderedSnapshots(),
                                                     data.CreatorPosts,
                                                     SubscriberId,
                                                     CreatorId,
                                                     data.StartTimeInclusive,
                                                     data.StartTimeInclusive.AddDays(7))).Returns(cost1);

            var cost2 = new AggregateCostSummary(20);

            this.subscriberPaymentPipeline.Setup(v => v.CalculatePayment(
                                                     data.GetOrderedSnapshots(),
                                                     null,
                                                     SubscriberId,
                                                     CreatorId,
                                                     data.StartTimeInclusive.AddDays(7),
                                                     data.EndTimeExclusive)).Returns(cost2);

            var result = await this.target.ExecuteAsync(data);

            Assert.AreEqual(
                new PaymentProcessingResults(
                    InitialCommittedAccountBalance.Subtract(cost1.Cost),
                    new List <PaymentProcessingResult>
            {
                new PaymentProcessingResult(
                    data.StartTimeInclusive,
                    data.StartTimeInclusive.AddDays(7),
                    cost1,
                    null,
                    true),
                new PaymentProcessingResult(
                    data.StartTimeInclusive.AddDays(7),
                    data.EndTimeExclusive,
                    cost2,
                    null,
                    false),
            }),
                result);
        }
        public async Task WhenDataRepresentsExactlyTwoWeeks_ItShouldReturnCommittedAndUncommittedResult()
        {
            var data = this.CreateData(StartTimeInclusive, StartTimeInclusive.AddDays(14));

            var cost1 = new AggregateCostSummary(10);

            this.subscriberPaymentPipeline.Setup(v => v.CalculatePayment(
                                                     data.GetOrderedSnapshots(),
                                                     data.CreatorPosts,
                                                     SubscriberId,
                                                     CreatorId,
                                                     data.StartTimeInclusive,
                                                     data.StartTimeInclusive.AddDays(7))).Returns(cost1);

            var cost2 = new AggregateCostSummary(20);

            this.subscriberPaymentPipeline.Setup(v => v.CalculatePayment(
                                                     data.GetOrderedSnapshots(),
                                                     null,
                                                     SubscriberId,
                                                     CreatorId,
                                                     data.StartTimeInclusive.AddDays(7),
                                                     data.EndTimeExclusive)).Returns(cost2);

            var result = await this.target.ExecuteAsync(data);

            Assert.AreEqual(
                new PaymentProcessingResults(
                    InitialCommittedAccountBalance.Subtract(cost1.Cost),
                    new List <PaymentProcessingResult>
            {
                new PaymentProcessingResult(
                    data.StartTimeInclusive,
                    data.StartTimeInclusive.AddDays(7),
                    cost1,
                    null,
                    true),
                new PaymentProcessingResult(
                    data.StartTimeInclusive.AddDays(7),
                    data.EndTimeExclusive,
                    cost2,
                    null,
                    false),
            }),
                result);
        }
        public async Task WhenCreatorPercentageOverrideSpecifiedAndNoExpiry_ItShouldIncludeInResults()
        {
            var creatorPercentageOverride = new CreatorPercentageOverrideData(
                0.9m,
                null);

            var data = this.CreateData(
                StartTimeInclusive,
                StartTimeInclusive.AddDays(14).AddTicks(-1),
                creatorPercentageOverride);

            var cost = new AggregateCostSummary(10);

            this.subscriberPaymentPipeline.Setup(v => v.CalculatePayment(
                                                     data.GetOrderedSnapshots(),
                                                     null,
                                                     SubscriberId,
                                                     CreatorId,
                                                     data.StartTimeInclusive,
                                                     data.EndTimeExclusive)).Returns(cost);

            var result = await this.target.ExecuteAsync(data);

            Assert.AreEqual(
                new PaymentProcessingResults(
                    InitialCommittedAccountBalance,
                    new List <PaymentProcessingResult>
            {
                new PaymentProcessingResult(
                    data.StartTimeInclusive,
                    data.EndTimeExclusive,
                    new AggregateCostSummary(10),
                    creatorPercentageOverride,
                    false),
            }),
                result);
        }
Beispiel #6
0
        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 WhenDataRepresentsMultipleWeeks_AndExceedsCommittedCredit_ItShouldReturnAdjustedResults()
        {
            var creatorPercentageOverride = new CreatorPercentageOverrideData(
                0.9m,
                StartTimeInclusive.AddDays(9));

            var data = this.CreateData(
                StartTimeInclusive,
                StartTimeInclusive.AddDays(23),
                creatorPercentageOverride);

            var cost1 = new AggregateCostSummary(60);

            this.subscriberPaymentPipeline.Setup(v => v.CalculatePayment(
                                                     data.GetOrderedSnapshots(),
                                                     data.CreatorPosts,
                                                     SubscriberId,
                                                     CreatorId,
                                                     data.StartTimeInclusive,
                                                     data.StartTimeInclusive.AddDays(7))).Returns(cost1);

            var cost2 = new AggregateCostSummary(60);

            this.subscriberPaymentPipeline.Setup(v => v.CalculatePayment(
                                                     data.GetOrderedSnapshots(),
                                                     data.CreatorPosts,
                                                     SubscriberId,
                                                     CreatorId,
                                                     data.StartTimeInclusive.AddDays(7),
                                                     data.StartTimeInclusive.AddDays(14))).Returns(cost2);

            var cost3 = new AggregateCostSummary(60);

            this.subscriberPaymentPipeline.Setup(v => v.CalculatePayment(
                                                     data.GetOrderedSnapshots(),
                                                     null,
                                                     SubscriberId,
                                                     CreatorId,
                                                     data.StartTimeInclusive.AddDays(14),
                                                     data.EndTimeExclusive)).Returns(cost3);

            var result = await this.target.ExecuteAsync(data);

            Assert.AreEqual(
                new PaymentProcessingResults(
                    new CommittedAccountBalance(0),
                    new List <PaymentProcessingResult>
            {
                new PaymentProcessingResult(
                    data.StartTimeInclusive,
                    data.StartTimeInclusive.AddDays(7),
                    new AggregateCostSummary(60),
                    creatorPercentageOverride,
                    true),
                new PaymentProcessingResult(
                    data.StartTimeInclusive.AddDays(7),
                    data.StartTimeInclusive.AddDays(14),
                    new AggregateCostSummary(40),
                    null,
                    true),
                new PaymentProcessingResult(
                    data.StartTimeInclusive.AddDays(14),
                    data.EndTimeExclusive,
                    new AggregateCostSummary(60),
                    null,
                    false),
            }),
                result);
        }