private async Task PayFor(Appointment appointment)
        {
            var availablePayments = await _checkoutService.GetAppointmentPaymentMethodsAsync(appointment.Id);

            var summary = await _priceCalculationService.CalculatePriceAsync(appointment);

            var paymentMethod = summary.Total == decimal.Zero
                ? availablePayments.SingleOrDefault(payment => payment.Type == PaymentType.FreePayment)
                : GetAutoPaymentMethod(availablePayments);

            if (paymentMethod is null)
            {
                _logger.LogCritical(
                    "No auto-payment method found for patient {patientId}, appointment {appointmentId}",
                    appointment.Patient.Id,
                    appointment.Id);
                return;
            }
            _logger.LogDebug("Found payment-method {paymentMethod}", paymentMethod.Type);
            var paymentInfo = new ProcessPaymentInfo(paymentMethod);

            try
            {
                var transaction = await _checkoutService.ProcessAppointmentPaymentAsync(appointment, paymentInfo);

                _logger.LogInformation("Auto-payment is completed with {transactionId}", transaction.Id);
            }
            catch (Exception exception)
            {
                _logger.LogError(exception, "Auto-payment Failed to process payment.");
            }
        }
        /// <summary>
        /// Gets the base price info for a product.
        /// </summary>
        /// <param name="priceCalculationService">Price calculation service.</param>
        /// <param name="product">The product to get the base price info for.</param>
        /// <param name="options">Price calculation options. The default options are used if <c>null</c>.</param>
        /// <returns>Base price info.</returns>
        public static async Task <string> GetBasePriceInfoAsync(this IPriceCalculationService priceCalculationService, Product product, PriceCalculationOptions options = null)
        {
            Guard.NotNull(priceCalculationService, nameof(priceCalculationService));
            Guard.NotNull(product, nameof(product));

            if (!product.BasePriceHasValue || product.BasePriceAmount == 0)
            {
                return(string.Empty);
            }

            options ??= priceCalculationService.CreateDefaultOptions(false);

            var context = new PriceCalculationContext(product, options);
            var price   = await priceCalculationService.CalculatePriceAsync(context);

            return(priceCalculationService.GetBasePriceInfo(product, price.FinalPrice, options.TargetCurrency));
        }
        /// <summary>
        /// Calculates the price adjustments of product attributes, usually <see cref="ProductVariantAttributeValue.PriceAdjustment"/>.
        /// Typically used to display price adjustments of selected attributes on the cart page.
        /// The calculated adjustment is always a unit price.
        /// </summary>
        /// <param name="priceCalculationService">Price calculation service.</param>
        /// <param name="product">The product.</param>
        /// <param name="selection">Attribute selection. If <c>null</c> then the price adjustments of all attributes of <paramref name="product"/> are determined.</param>
        /// <param name="quantity">
        /// The product quantity. May have impact on the price, e.g. if tier prices are applied to price adjustments.
        /// Note that the calculated price is always the unit price.
        /// </param>
        /// <param name="options">Price calculation options. The default options are used if <c>null</c>.</param>
        /// <returns>Price adjustments of selected attributes. Key: <see cref="ProductVariantAttributeValue.Id"/>, value: attribute price adjustment.</returns>
        public static async Task <IDictionary <int, CalculatedPriceAdjustment> > CalculateAttributePriceAdjustmentsAsync(
            this IPriceCalculationService priceCalculationService,
            Product product,
            ProductVariantAttributeSelection selection = null,
            int quantity = 1,
            PriceCalculationOptions options = null)
        {
            Guard.NotNull(priceCalculationService, nameof(priceCalculationService));

            options ??= priceCalculationService.CreateDefaultOptions(false);

            var context = new PriceCalculationContext(product, quantity, options);

            context.Options.DeterminePriceAdjustments = true;
            context.Options.TaxFormat = null;

            context.AddSelectedAttributes(selection, product.Id);

            var price = await priceCalculationService.CalculatePriceAsync(context);

            return(price.AttributePriceAdjustments.ToDictionarySafe(x => x.AttributeValue.Id));
        }