Example #1
0
        public void Should_fail_if_discounts_exceed()
        {
            var discounts = new List <decimal> {
                5m
            };

            decimal MarkupFunction(decimal amount) => amount * 1.04m;

            var result = DiscountsValidator.DiscountsDontExceedMarkups(discounts, MarkupFunction);

            Assert.True(result.IsFailure);
        }
Example #2
0
        public void Should_pass_if_discounts_dont_exceed()
        {
            var discounts = new List <decimal> {
                2, 1
            };

            decimal MarkupFunction(decimal amount) => amount * 1.04m;

            var result = DiscountsValidator.DiscountsDontExceedMarkups(discounts, MarkupFunction);

            Assert.True(result.IsSuccess);
        }
        public async Task <Result> ChangeActivityState(int agencyId, int discountId, bool newActivityState)
        {
            return(await Get(agencyId, discountId)
                   .Check(DiscountDoesntExceedMarkups)
                   .BindWithTransaction(_context, discount => Result.Success(discount)
                                        .Tap(Update)
                                        .Check(WriteAuditLog)));


            Task Update(Discount discount)
            => this.Update(discount, d => d.IsActive = newActivityState);


            Task <Result> WriteAuditLog(Discount _)
            => _managementAuditService.Write(ManagementEventType.DiscountEdit, new DiscountActivityStateEventData(agencyId, newActivityState));


            async Task <Result <Discount> > DiscountDoesntExceedMarkups(Discount discount)
            {
                // We need additional check for activated discounts
                // They can exceed markups
                if (!newActivityState)
                {
                    return(Result.Success(discount));
                }

                var markupPolicy = await _context.MarkupPolicies.SingleOrDefaultAsync(x => x.Id == discount.TargetPolicyId);

                var markupFunction = _templateService.CreateFunction(markupPolicy.TemplateId, markupPolicy.TemplateSettings);

                var allDiscounts = await _context.Discounts
                                   .Where(x => x.TargetPolicyId == markupPolicy.Id)
                                   .Where(d => d.TargetAgencyId == agencyId)
                                   .Where(d => d.IsActive)
                                   .Select(d => d.DiscountPercent)
                                   .ToListAsync();

                allDiscounts.Add(discount.DiscountPercent);

                var discountDoesntExceed = DiscountsValidator.DiscountsDontExceedMarkups(allDiscounts, markupFunction);

                return(discountDoesntExceed.IsSuccess
                    ? Result.Success(discount)
                    : Result.Failure <Discount>("One of activate discounts exceeds markups"));
            }
        }
        public async Task <Result> Update(int agencyId, int discountId, EditDiscountRequest editDiscountRequest)
        {
            return(await Get(agencyId, discountId)
                   .Check(_ => ValidatePercent(editDiscountRequest.DiscountPercent))
                   .Check(DiscountDoesntExceedMarkups)
                   .BindWithTransaction(_context, discount => Result.Success(discount)
                                        .Tap(Update)
                                        .Bind(WriteAuditLog)));


            async Task <Result> DiscountDoesntExceedMarkups(Discount discount)
            {
                var markupPolicy = await _context.MarkupPolicies.SingleOrDefaultAsync(x => x.Id == discount.TargetPolicyId);

                var markupFunction = _templateService.CreateFunction(markupPolicy.TemplateId, markupPolicy.TemplateSettings);

                var allDiscounts = await _context.Discounts
                                   .Where(x => x.TargetPolicyId == markupPolicy.Id)
                                   .Where(d => d.TargetAgencyId == agencyId)
                                   .Where(d => d.IsActive)
                                   .Where(d => d.Id != discountId) // excluding discount we want to edit
                                   .Select(d => d.DiscountPercent)
                                   .ToListAsync();

                allDiscounts.Add(editDiscountRequest.DiscountPercent);

                return(DiscountsValidator.DiscountsDontExceedMarkups(allDiscounts, markupFunction));
            }

            Task Update(Discount discount)
            => this.Update(discount, d =>
            {
                d.DiscountPercent = editDiscountRequest.DiscountPercent;
                d.Description     = editDiscountRequest.Description;
            });


            Task <Result> WriteAuditLog(Discount _)
            => _managementAuditService.Write(ManagementEventType.DiscountEdit, new DiscountEditEventData(agencyId, editDiscountRequest));
        }
        public Task <Result> Add(int agencyId, CreateDiscountRequest createDiscountRequest)
        {
            return(ValidatePercent(createDiscountRequest.DiscountPercent)
                   .Bind(ValidateTargetMarkup)
                   .Bind(ValidateAgency)
                   .Bind(DiscountsDontExceedMarkups)
                   .BindWithTransaction(_context, () => Result.Success()
                                        .Tap(UpdateDiscount)
                                        .Bind(WriteAuditLog)));


            async Task <Result> ValidateTargetMarkup()
            {
                var targetMarkup = await _context.MarkupPolicies
                                   .SingleOrDefaultAsync(p => p.Id == createDiscountRequest.TargetMarkupId);

                if (targetMarkup is null)
                {
                    return(Result.Failure($"Could not find markup policy with id {createDiscountRequest.TargetMarkupId}"));
                }

                return(targetMarkup.SubjectScopeType == SubjectMarkupScopeTypes.Global
                    ? Result.Success()
                    : Result.Failure("Cannot apply discount to non-global markup policy"));
            }

            async Task <Result> ValidateAgency()
            => await _context.Agencies.AnyAsync(a => a.Id == agencyId)
                    ? Result.Success()
                    : Result.Failure($"Could not find an agency with id {agencyId}");


            async Task <Result> DiscountsDontExceedMarkups()
            {
                var markupPolicy = await _context.MarkupPolicies.SingleOrDefaultAsync(x => x.Id == createDiscountRequest.TargetMarkupId);

                var markupFunction = _templateService.CreateFunction(markupPolicy.TemplateId, markupPolicy.TemplateSettings);

                var allDiscounts = await _context.Discounts
                                   .Where(x => x.TargetPolicyId == markupPolicy.Id)
                                   .Where(d => d.TargetAgencyId == agencyId)
                                   .Where(d => d.IsActive)
                                   .Select(d => d.DiscountPercent)
                                   .ToListAsync();

                allDiscounts.Add(createDiscountRequest.DiscountPercent);

                return(DiscountsValidator.DiscountsDontExceedMarkups(allDiscounts, markupFunction));
            }

            Task UpdateDiscount()
            {
                var now = _dateTimeProvider.UtcNow();

                _context.Discounts.Add(new Discount
                {
                    DiscountPercent = createDiscountRequest.DiscountPercent,
                    Description     = createDiscountRequest.Description,
                    TargetPolicyId  = createDiscountRequest.TargetMarkupId,
                    IsActive        = true,
                    TargetAgencyId  = agencyId,
                    Created         = now,
                    Modified        = now
                });
                return(_context.SaveChangesAsync());
            }

            Task <Result> WriteAuditLog()
            => _managementAuditService.Write(ManagementEventType.DiscountCreate, new DiscountCreateEventData(agencyId, createDiscountRequest));
        }
        public async Task <Result> Modify(int policyId, MarkupPolicySettings settings)
        {
            var destinationScopeType = await GetDestinationScopeType(settings.DestinationScopeId);

            if (destinationScopeType.IsFailure)
            {
                return(Result.Failure(destinationScopeType.Error));
            }

            var policy = await _context.MarkupPolicies.SingleOrDefaultAsync(p => p.Id == policyId);

            if (policy == null)
            {
                return(Result.Failure("Could not find policy"));
            }

            var(_, isFailure, markupPolicy, error) = await ValidateSettings()
                                                     .Bind(DiscountsDontExceedMarkups)
                                                     .Bind(UpdatePolicy)
                                                     .Tap(p => WriteAuditLog(p, MarkupPolicyEventOperationType.Modified));

            if (isFailure)
            {
                return(Result.Failure(error));
            }

            return(await UpdateDisplayedMarkupFormula(markupPolicy));


            Result ValidateSettings() => _templateService.Validate(settings.TemplateId, settings.TemplateSettings);


            async Task <Result> DiscountsDontExceedMarkups()
            {
                // This check is only applicable to agency scope markups
                if (policy.SubjectScopeType != SubjectMarkupScopeTypes.Agency)
                {
                    return(Result.Success());
                }

                var agencyId = int.Parse(policy.SubjectScopeId);

                var allDiscounts = await _context.Discounts
                                   .Where(x => x.IsActive)
                                   .Where(x => x.TargetAgencyId == agencyId)
                                   .Where(x => x.TargetPolicyId == policy.Id)
                                   .Select(x => x.DiscountPercent)
                                   .ToListAsync();

                var markupFunction = _templateService.CreateFunction(policy.TemplateId, policy.TemplateSettings);

                return(DiscountsValidator.DiscountsDontExceedMarkups(allDiscounts, markupFunction));
            }

            async Task <Result <MarkupPolicy> > UpdatePolicy()
            {
                policy.Description      = settings.Description;
                policy.Order            = settings.Order;
                policy.TemplateId       = settings.TemplateId;
                policy.TemplateSettings = settings.TemplateSettings;
                policy.Currency         = settings.Currency;
                policy.Modified         = _dateTimeProvider.UtcNow();
                policy.SubjectScopeId   = settings.LocationScopeId;
                // No SubjectScopeType here because changing its type is not allowed
                policy.DestinationScopeId   = settings.DestinationScopeId;
                policy.DestinationScopeType = destinationScopeType.Value;

                var policyData = GetPolicyData(policy);

                if (policyData.IsFailure)
                {
                    return(Result.Failure <MarkupPolicy>(policyData.Error));
                }

                var(_, isFailure, error) = await ValidatePolicy(policyData.Value, policy);

                if (isFailure)
                {
                    return(Result.Failure <MarkupPolicy>(error));
                }

                _context.Update(policy);
                await _context.SaveChangesAsync();

                return(policy);
            }
        }