public async Task <SubscriptionsSummary> ProcessOrderForUnAuthenticatedCustomer(string customerId, string paymentId, string payerId)
        {
            var startTime = DateTime.Now;

            customerId.AssertNotEmpty(nameof(customerId));

            paymentId.AssertNotEmpty(nameof(paymentId));
            payerId.AssertNotEmpty(nameof(payerId));
            PayPalGateway paymentGateway = new PayPalGateway(ApplicationDomain.Instance, "ProcessingOrder");

            // use payment gateway to extract order information.
            OrderViewModel orderToProcess = await paymentGateway.GetOrderDetailsFromPaymentAsync(payerId, paymentId, string.Empty, string.Empty);

            CommerceOperations commerceOperation = new CommerceOperations(ApplicationDomain.Instance, customerId, paymentGateway);
            await commerceOperation.PurchaseAsync(orderToProcess);

            SubscriptionsSummary summaryResult = await this.GetSubscriptionSummaryAsync(customerId);

            // Capture the request for the customer summary for analysis.
            var eventProperties = new Dictionary <string, string> {
                { "CustomerId", orderToProcess.CustomerId }, { "PayerId", payerId }, { "PaymentId", paymentId }
            };

            // Track the event measurements for analysis.
            var eventMetrics = new Dictionary <string, double> {
                { "ElapsedMilliseconds", DateTime.Now.Subtract(startTime).TotalMilliseconds }
            };

            ApplicationDomain.Instance.TelemetryService.Provider.TrackEvent("api/order/NewCustomerProcessOrder", eventProperties, eventMetrics);

            return(summaryResult);
        }
        public async Task <TransactionResult> UpdateSubscription([FromBody] OrderViewModel orderUpdateInformation)
        {
            if (!ModelState.IsValid)
            {
                var errorList = (from item in ModelState.Values
                                 from error in item.Errors
                                 select error.ErrorMessage).ToList();
                string errorMessage = JsonConvert.SerializeObject(errorList);
                throw new PartnerDomainException(ErrorCode.InvalidInput).AddDetail("ErrorMessage", errorMessage);
            }

            string clientCustomerId = this.Principal.PartnerCenterCustomerId;

            orderUpdateInformation.Subscriptions.AssertNotNull(nameof(orderUpdateInformation.Subscriptions));
            List <OrderSubscriptionItemViewModel> orderSubscriptions = orderUpdateInformation.Subscriptions.ToList();

            if (!(orderSubscriptions.Count == 1))
            {
                throw new PartnerDomainException(ErrorCode.InvalidInput).AddDetail("ErrorMessage", Resources.MoreThanOneSubscriptionUpdateErrorMessage);
            }

            string subscriptionId  = orderSubscriptions.First().SubscriptionId;
            int    additionalSeats = orderSubscriptions.First().Quantity;

            subscriptionId.AssertNotEmpty(nameof(subscriptionId));      // required for commerce operation.
            additionalSeats.AssertPositive(nameof(additionalSeats));    // required & should be greater than 0.

            string             operationDescription = string.Format("Customer Id:[{0}] - Added to subscription:{1}.", clientCustomerId, subscriptionId);
            PayPalGateway      paymentGateway       = new PayPalGateway(ApplicationDomain.Instance, orderUpdateInformation.CreditCard, operationDescription);
            CommerceOperations commerceOperation    = new CommerceOperations(ApplicationDomain.Instance, clientCustomerId, paymentGateway);

            return(await commerceOperation.PurchaseAdditionalSeatsAsync(subscriptionId, additionalSeats));
        }
Ejemplo n.º 3
0
        public async Task <TransactionResult> ProcessOrderForAuthenticatedCustomer(string paymentId, string payerId, string orderId)
        {
            DateTime startTime = DateTime.Now;

            // extract order information and create payment payload.
            string clientCustomerId = Principal.PartnerCenterCustomerId;

            paymentId.AssertNotEmpty(nameof(paymentId));
            payerId.AssertNotEmpty(nameof(payerId));
            orderId.AssertNotEmpty(nameof(orderId));

            // Create the right payment gateway to use for customer oriented payment transactions.
            IPaymentGateway paymentGateway = await CreatePaymentGateway("ProcessingOrder", clientCustomerId).ConfigureAwait(false);

            // use payment gateway to extract order information.
            OrderViewModel orderToProcess = await paymentGateway.GetOrderDetailsFromPaymentAsync(payerId, paymentId, orderId, clientCustomerId).ConfigureAwait(false);

            orderToProcess.CustomerId = clientCustomerId;
            CommerceOperations commerceOperation = new CommerceOperations(ApplicationDomain.Instance, clientCustomerId, paymentGateway);

            TransactionResult transactionResult = null;

            switch (orderToProcess.OperationType)
            {
            case CommerceOperationType.Renewal:
                transactionResult = await commerceOperation.RenewSubscriptionAsync(orderToProcess).ConfigureAwait(false);

                break;

            case CommerceOperationType.AdditionalSeatsPurchase:
                transactionResult = await commerceOperation.PurchaseAdditionalSeatsAsync(orderToProcess).ConfigureAwait(false);

                break;

            case CommerceOperationType.NewPurchase:
                transactionResult = await commerceOperation.PurchaseAsync(orderToProcess).ConfigureAwait(false);

                break;
            }

            // Capture the request for the customer summary for analysis.
            Dictionary <string, string> eventProperties = new Dictionary <string, string> {
                { "CustomerId", orderToProcess.CustomerId }, { "OperationType", orderToProcess.OperationType.ToString() }, { "PayerId", payerId }, { "PaymentId", paymentId }
            };

            // Track the event measurements for analysis.
            Dictionary <string, double> eventMetrics = new Dictionary <string, double> {
                { "ElapsedMilliseconds", DateTime.Now.Subtract(startTime).TotalMilliseconds }
            };

            ApplicationDomain.Instance.TelemetryService.Provider.TrackEvent("api/order/process", eventProperties, eventMetrics);

            return(transactionResult);
        }
        /// <summary>
        /// Adds a portal subscription for the Customer.
        /// </summary>
        /// <param name="clientCustomerId">The Customer Id.</param>
        /// <param name="orderSubscriptions">The Order information containing credit card and list of subscriptions to add.</param>
        /// <returns>Transaction Result from commerce operation.</returns>
        private async Task <TransactionResult> AddCustomerSubscription(string clientCustomerId, OrderViewModel orderSubscriptions)
        {
            string operationDescription = string.Format("Customer Id:[{0}] - Added Subscription(s).", clientCustomerId);

            PayPalGateway      paymentGateway    = new PayPalGateway(ApplicationDomain.Instance, orderSubscriptions.CreditCard, operationDescription);
            CommerceOperations commerceOperation = new CommerceOperations(ApplicationDomain.Instance, clientCustomerId, paymentGateway);

            List <PurchaseLineItem> orderItems = new List <PurchaseLineItem>();

            foreach (var orderItem in orderSubscriptions.Subscriptions)
            {
                string offerId  = orderItem.OfferId;
                int    quantity = orderItem.Quantity;

                offerId.AssertNotEmpty(nameof(offerId));        // required for commerce operation.
                quantity.AssertPositive(nameof(quantity));      // required & should be greater than 0.

                orderItems.Add(new PurchaseLineItem(offerId, quantity));
            }

            return(await commerceOperation.PurchaseAsync(orderItems));
        }
        /// <summary>
        /// Gets the subscriptions managed by customers and partners
        /// </summary>
        /// <returns>returns managed subscriptions view model</returns>
        private async Task <ManagedSubscriptionsViewModel> GetManagedSubscriptions()
        {
            DateTime startTime = DateTime.Now;

            string clientCustomerId = Principal.PartnerCenterCustomerId;

            // responseCulture determines decimals, currency and such
            CultureInfo responseCulture = new CultureInfo(ApplicationDomain.Instance.PortalLocalization.Locale);

            // localeSpecificApiClient allows pulling offer names localized to supported portal locales compatible with Offer API supported locales.
            IPartner localeSpecificPartnerCenterClient = ApplicationDomain.Instance.PartnerCenterClient.With(RequestContextFactory.Instance.Create(ApplicationDomain.Instance.PortalLocalization.OfferLocale));

            // Get all subscriptions of customer from PC
            ResourceCollection <Subscription> customerAllSubscriptions = await localeSpecificPartnerCenterClient.Customers.ById(clientCustomerId).Subscriptions.GetAsync().ConfigureAwait(false);

            IEnumerable <CustomerSubscriptionEntity> customerSubscriptions = await ApplicationDomain.Instance.CustomerSubscriptionsRepository.RetrieveAsync(clientCustomerId).ConfigureAwait(false);

            IEnumerable <PartnerOffer> allPartnerOffers = await ApplicationDomain.Instance.OffersRepository.RetrieveAsync().ConfigureAwait(false);

            IEnumerable <MicrosoftOffer> currentMicrosoftOffers = await ApplicationDomain.Instance.OffersRepository.RetrieveMicrosoftOffersAsync().ConfigureAwait(false);

            List <SubscriptionViewModel> customerSubscriptionsView = new List <SubscriptionViewModel>();

            // iterate through and build the list of customer's subscriptions.
            foreach (CustomerSubscriptionEntity subscription in customerSubscriptions)
            {
                PartnerOffer partnerOfferItem  = allPartnerOffers.FirstOrDefault(offer => offer.Id == subscription.PartnerOfferId);
                string       subscriptionTitle = partnerOfferItem.Title;
                string       portalOfferId     = partnerOfferItem.Id;
                decimal      portalOfferPrice  = partnerOfferItem.Price;

                DateTime subscriptionExpiryDate = subscription.ExpiryDate.ToUniversalTime();
                int      remainingDays          = (subscriptionExpiryDate.Date - DateTime.UtcNow.Date).Days;
                bool     isRenewable            = remainingDays <= 30;                                 // IsRenewable is true if subscription is going to expire in 30 days.
                bool     isEditable             = DateTime.UtcNow.Date <= subscriptionExpiryDate.Date; // IsEditable is true if today is lesser or equal to subscription expiry date.

                // Temporarily mark this partnerOffer item as inactive and dont allow store front customer to manage this subscription.
                MicrosoftOffer alignedMicrosoftOffer = currentMicrosoftOffers.FirstOrDefault(offer => offer.Offer.Id == partnerOfferItem.MicrosoftOfferId);

                if (alignedMicrosoftOffer == null)
                {
                    // The offer is inactive (marked for deletion) then dont allow renewals or editing on this subscription tied to this offer.
                    partnerOfferItem.IsInactive = true;
                    isRenewable = false;
                    isEditable  = false;
                }

                BrandingConfiguration portalBranding = await ApplicationDomain.Instance.PortalBranding.RetrieveAsync().ConfigureAwait(false);

                // Compute the pro rated price per seat for this subcription & return for client side processing during updates.
                decimal proratedPerSeatPrice = Math.Round(CommerceOperations.CalculateProratedSeatCharge(subscription.ExpiryDate,
                                                                                                         portalOfferPrice,
                                                                                                         portalBranding.BillingCycle),
                                                          Resources.Culture.NumberFormat.CurrencyDecimalDigits);

                SubscriptionViewModel subscriptionItem = new SubscriptionViewModel()
                {
                    SubscriptionId            = subscription.SubscriptionId,
                    FriendlyName              = subscriptionTitle,
                    PortalOfferId             = portalOfferId,
                    PortalOfferPrice          = portalOfferPrice.ToString("C", responseCulture),
                    IsRenewable               = isRenewable,
                    IsEditable                = isEditable,
                    SubscriptionExpiryDate    = subscriptionExpiryDate.Date.ToString("d", responseCulture),
                    SubscriptionProRatedPrice = proratedPerSeatPrice
                };

                // add this subcription to the customer's subscription list.
                customerSubscriptionsView.Add(subscriptionItem);
            }

            List <CustomerSubscriptionModel> customerManagedSubscriptions = new List <CustomerSubscriptionModel>();
            List <PartnerSubscriptionModel>  partnerManagedSubscriptions  = new List <PartnerSubscriptionModel>();

            // Divide the subscriptions by customer and partner
            foreach (Subscription customerSubscriptionFromPC in customerAllSubscriptions.Items)
            {
                SubscriptionViewModel subscription = customerSubscriptionsView.FirstOrDefault(sub => sub.SubscriptionId == customerSubscriptionFromPC.Id);

                // Customer managed subscription found
                if (subscription != null)
                {
                    CustomerSubscriptionModel customerSubscription = new CustomerSubscriptionModel()
                    {
                        SubscriptionId            = customerSubscriptionFromPC.Id,
                        LicensesTotal             = customerSubscriptionFromPC.Quantity.ToString("G", responseCulture),
                        Status                    = GetStatusType(customerSubscriptionFromPC.Status),
                        CreationDate              = customerSubscriptionFromPC.CreationDate.ToString("d", responseCulture),
                        FriendlyName              = subscription.FriendlyName,
                        IsRenewable               = subscription.IsRenewable,
                        IsEditable                = subscription.IsEditable,
                        PortalOfferId             = subscription.PortalOfferId,
                        SubscriptionProRatedPrice = subscription.SubscriptionProRatedPrice
                    };

                    customerManagedSubscriptions.Add(customerSubscription);
                }
                else
                {
                    PartnerSubscriptionModel partnerSubscription = new PartnerSubscriptionModel()
                    {
                        Id           = customerSubscriptionFromPC.Id,
                        OfferName    = customerSubscriptionFromPC.OfferName,
                        Quantity     = customerSubscriptionFromPC.Quantity.ToString("G", responseCulture),
                        Status       = GetStatusType(customerSubscriptionFromPC.Status),
                        CreationDate = customerSubscriptionFromPC.CreationDate.ToString("d", responseCulture),
                    };

                    partnerManagedSubscriptions.Add(partnerSubscription);
                }
            }

            ManagedSubscriptionsViewModel managedSubscriptions = new ManagedSubscriptionsViewModel()
            {
                CustomerManagedSubscriptions = customerManagedSubscriptions.OrderByDescending(customerManagedSubscription => customerManagedSubscription.CreationDate),
                PartnerManagedSubscriptions  = partnerManagedSubscriptions.OrderByDescending(partnerManagedSubscription => partnerManagedSubscription.CreationDate)
            };

            // Capture the request for customer managed subscriptions and partner managed subscriptions for analysis.
            Dictionary <string, string> eventProperties = new Dictionary <string, string> {
                { "CustomerId", clientCustomerId }
            };

            // Track the event measurements for analysis.
            Dictionary <string, double> eventMetrics = new Dictionary <string, double> {
                { "ElapsedMilliseconds", DateTime.Now.Subtract(startTime).TotalMilliseconds }, { "CustomerManagedSubscriptions", customerManagedSubscriptions.Count }, { "PartnerManagedSubscriptions", partnerManagedSubscriptions.Count }
            };

            ApplicationDomain.Instance.TelemetryService.Provider.TrackEvent("GetManagedSubscriptions", eventProperties, eventMetrics);

            return(managedSubscriptions);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Gets the summary of subscriptions for a portal customer.
        /// </summary>
        /// <param name="customerId">The customer Id.</param>
        /// <returns>Subscription Summary.</returns>
        private async Task <SubscriptionsSummary> GetSubscriptionSummaryAsync(string customerId)
        {
            DateTime startTime = DateTime.Now;
            IEnumerable <CustomerSubscriptionEntity> customerSubscriptions = await ApplicationDomain.Instance.CustomerSubscriptionsRepository.RetrieveAsync(customerId).ConfigureAwait(false);

            IEnumerable <CustomerPurchaseEntity> customerSubscriptionsHistory = await ApplicationDomain.Instance.CustomerPurchasesRepository.RetrieveAsync(customerId).ConfigureAwait(false);

            IEnumerable <PartnerOffer> allPartnerOffers = await ApplicationDomain.Instance.OffersRepository.RetrieveAsync().ConfigureAwait(false);

            IEnumerable <MicrosoftOffer> currentMicrosoftOffers = await ApplicationDomain.Instance.OffersRepository.RetrieveMicrosoftOffersAsync().ConfigureAwait(false);

            // start building the summary.
            decimal summaryTotal = 0;

            // format all responses to client using portal locale.
            CultureInfo responseCulture = new CultureInfo(ApplicationDomain.Instance.PortalLocalization.Locale);
            List <SubscriptionViewModel> customerSubscriptionsView = new List <SubscriptionViewModel>();

            // iterate through and build the list of customer's subscriptions.
            foreach (CustomerSubscriptionEntity subscription in customerSubscriptions)
            {
                decimal subscriptionTotal = 0;
                int     licenseTotal      = 0;
                List <SubscriptionHistory> historyItems = new List <SubscriptionHistory>();

                // collect the list of history items for this subcription.
                IOrderedEnumerable <CustomerPurchaseEntity> subscriptionHistoryList = customerSubscriptionsHistory
                                                                                      .Where(historyItem => historyItem.SubscriptionId == subscription.SubscriptionId)
                                                                                      .OrderBy(historyItem => historyItem.TransactionDate);

                // iterate through and build the SubsriptionHistory for this subscription.
                foreach (CustomerPurchaseEntity historyItem in subscriptionHistoryList)
                {
                    decimal orderTotal = Math.Round(historyItem.SeatPrice * historyItem.SeatsBought, responseCulture.NumberFormat.CurrencyDecimalDigits);
                    historyItems.Add(new SubscriptionHistory()
                    {
                        OrderTotal    = orderTotal.ToString("C", responseCulture),                                // Currency format.
                        PricePerSeat  = historyItem.SeatPrice.ToString("C", responseCulture),                     // Currency format.
                        SeatsBought   = historyItem.SeatsBought.ToString("G", responseCulture),                   // General format.
                        OrderDate     = historyItem.TransactionDate.ToLocalTime().ToString("d", responseCulture), // Short date format.
                        OperationType = GetOperationType(historyItem.PurchaseType)                                // Localized Operation type string.
                    });

                    // Increment the subscription total.
                    licenseTotal += historyItem.SeatsBought;

                    // Increment the subscription total.
                    subscriptionTotal += orderTotal;
                }

                PartnerOffer partnerOfferItem  = allPartnerOffers.FirstOrDefault(offer => offer.Id == subscription.PartnerOfferId);
                string       subscriptionTitle = partnerOfferItem.Title;
                string       portalOfferId     = partnerOfferItem.Id;
                decimal      portalOfferPrice  = partnerOfferItem.Price;

                DateTime subscriptionExpiryDate = subscription.ExpiryDate.ToUniversalTime();
                int      remainingDays          = (subscriptionExpiryDate.Date - DateTime.UtcNow.Date).Days;
                bool     isRenewable            = remainingDays <= 30;
                bool     isEditable             = DateTime.UtcNow.Date <= subscriptionExpiryDate.Date;

                // TODO :: Handle Microsoft offer being pulled back due to EOL.

                // Temporarily mark this partnerOffer item as inactive and dont allow store front customer to manage this subscription.
                MicrosoftOffer alignedMicrosoftOffer = currentMicrosoftOffers.FirstOrDefault(offer => offer.Offer.Id == partnerOfferItem.MicrosoftOfferId);
                if (alignedMicrosoftOffer == null)
                {
                    partnerOfferItem.IsInactive = true;
                }

                if (partnerOfferItem.IsInactive)
                {
                    // in case the offer is inactive (marked for deletion) then dont allow renewals or editing on this subscription tied to this offer.
                    isRenewable = false;
                    isEditable  = false;
                }

                // Compute the pro rated price per seat for this subcription & return for client side processing during updates.
                decimal proratedPerSeatPrice = Math.Round(CommerceOperations.CalculateProratedSeatCharge(subscription.ExpiryDate, portalOfferPrice), responseCulture.NumberFormat.CurrencyDecimalDigits);

                SubscriptionViewModel subscriptionItem = new SubscriptionViewModel()
                {
                    SubscriptionId            = subscription.SubscriptionId,
                    FriendlyName              = subscriptionTitle,
                    PortalOfferId             = portalOfferId,
                    PortalOfferPrice          = portalOfferPrice.ToString("C", responseCulture),
                    IsRenewable               = isRenewable,                                                // IsRenewable is true if subscription is going to expire in 30 days.
                    IsEditable                = isEditable,                                                 // IsEditable is true if today is lesser or equal to subscription expiry date.
                    LicensesTotal             = licenseTotal.ToString("G", responseCulture),                // General format.
                    SubscriptionTotal         = subscriptionTotal.ToString("C", responseCulture),           // Currency format.
                    SubscriptionExpiryDate    = subscriptionExpiryDate.Date.ToString("d", responseCulture), // Short date format.
                    SubscriptionOrderHistory  = historyItems,
                    SubscriptionProRatedPrice = proratedPerSeatPrice
                };

                // add this subcription to the customer's subscription list.
                customerSubscriptionsView.Add(subscriptionItem);

                // Increment the summary total.
                summaryTotal += subscriptionTotal;
            }

            // Capture the request for the customer summary for analysis.
            Dictionary <string, string> eventProperties = new Dictionary <string, string> {
                { "CustomerId", customerId }
            };

            // Track the event measurements for analysis.
            Dictionary <string, double> eventMetrics = new Dictionary <string, double> {
                { "ElapsedMilliseconds", DateTime.Now.Subtract(startTime).TotalMilliseconds }, { "NumberOfSubscriptions", customerSubscriptionsView.Count }
            };

            ApplicationDomain.Instance.TelemetryService.Provider.TrackEvent("GetSubscriptionSummaryAsync", eventProperties, eventMetrics);

            // Sort List of subscriptions based on portal offer name.
            return(new SubscriptionsSummary()
            {
                Subscriptions = customerSubscriptionsView.OrderBy(subscriptionItem => subscriptionItem.FriendlyName),
                SummaryTotal = summaryTotal.ToString("C", responseCulture)      // Currency format.
            });
        }
Ejemplo n.º 7
0
        public async Task <SubscriptionsSummary> ProcessOrderForUnAuthenticatedCustomer(string customerId, string paymentId, string payerId)
        {
            DateTime startTime = DateTime.Now;

            customerId.AssertNotEmpty(nameof(customerId));
            paymentId.AssertNotEmpty(nameof(paymentId));
            payerId.AssertNotEmpty(nameof(payerId));

            BrandingConfiguration branding = await ApplicationDomain.Instance.PortalBranding.RetrieveAsync().ConfigureAwait(false);

            CustomerViewModel customerRegistrationInfoPersisted = await ApplicationDomain.Instance.CustomerRegistrationRepository.RetrieveAsync(customerId).ConfigureAwait(false);

            Customer newCustomer = new Customer()
            {
                CompanyProfile = new CustomerCompanyProfile()
                {
                    Domain = customerRegistrationInfoPersisted.DomainName,
                },
                BillingProfile = new CustomerBillingProfile()
                {
                    Culture     = customerRegistrationInfoPersisted.BillingCulture,
                    Language    = customerRegistrationInfoPersisted.BillingLanguage,
                    Email       = customerRegistrationInfoPersisted.Email,
                    CompanyName = customerRegistrationInfoPersisted.CompanyName,

                    DefaultAddress = new Address()
                    {
                        FirstName    = customerRegistrationInfoPersisted.FirstName,
                        LastName     = customerRegistrationInfoPersisted.LastName,
                        AddressLine1 = customerRegistrationInfoPersisted.AddressLine1,
                        AddressLine2 = customerRegistrationInfoPersisted.AddressLine2,
                        City         = customerRegistrationInfoPersisted.City,
                        State        = customerRegistrationInfoPersisted.State,
                        Country      = customerRegistrationInfoPersisted.Country,
                        PostalCode   = customerRegistrationInfoPersisted.ZipCode,
                        PhoneNumber  = customerRegistrationInfoPersisted.Phone,
                    }
                }
            };

            // Register customer
            newCustomer = await ApplicationDomain.Instance.PartnerCenterClient.Customers.CreateAsync(newCustomer).ConfigureAwait(false);

            ResourceCollection <AgreementMetaData> agreements = await ApplicationDomain.Instance.PartnerCenterClient.AgreementDetails.GetAsync().ConfigureAwait(false);

            // Obtain reference to the Microsoft Cloud Agreement.
            AgreementMetaData microsoftCloudAgreement = agreements.Items.FirstOrDefault(agr => agr.AgreementType == AgreementType.MicrosoftCloudAgreement);

            // Attest that the customer has accepted the Microsoft Cloud Agreement (MCA).
            await ApplicationDomain.Instance.PartnerCenterClient.Customers[newCustomer.Id].Agreements.CreateAsync(
                new Agreement
            {
                DateAgreed     = DateTime.UtcNow,
                PrimaryContact = new PartnerCenter.Models.Agreements.Contact
                {
                    Email       = customerRegistrationInfoPersisted.Email,
                    FirstName   = customerRegistrationInfoPersisted.FirstName,
                    LastName    = customerRegistrationInfoPersisted.LastName,
                    PhoneNumber = customerRegistrationInfoPersisted.Phone
                },
                TemplateId = microsoftCloudAgreement.TemplateId,
                Type       = AgreementType.MicrosoftCloudAgreement,
                UserId     = branding.AgreementUserId
            });

            string newCustomerId = newCustomer.CompanyProfile.TenantId;

            CustomerViewModel customerViewModel = new CustomerViewModel()
            {
                AddressLine1     = newCustomer.BillingProfile.DefaultAddress.AddressLine1,
                AddressLine2     = newCustomer.BillingProfile.DefaultAddress.AddressLine2,
                City             = newCustomer.BillingProfile.DefaultAddress.City,
                State            = newCustomer.BillingProfile.DefaultAddress.State,
                ZipCode          = newCustomer.BillingProfile.DefaultAddress.PostalCode,
                Country          = newCustomer.BillingProfile.DefaultAddress.Country,
                Phone            = newCustomer.BillingProfile.DefaultAddress.PhoneNumber,
                Language         = newCustomer.BillingProfile.Language,
                FirstName        = newCustomer.BillingProfile.DefaultAddress.FirstName,
                LastName         = newCustomer.BillingProfile.DefaultAddress.LastName,
                Email            = newCustomer.BillingProfile.Email,
                CompanyName      = newCustomer.BillingProfile.CompanyName,
                MicrosoftId      = newCustomer.CompanyProfile.TenantId,
                UserName         = newCustomer.BillingProfile.Email,
                Password         = newCustomer.UserCredentials.Password,
                AdminUserAccount = newCustomer.UserCredentials.UserName + "@" + newCustomer.CompanyProfile.Domain
            };

            IPaymentGateway paymentGateway = PaymentGatewayConfig.GetPaymentGatewayInstance(ApplicationDomain.Instance, "ProcessingOrder");
            OrderViewModel  orderToProcess = await paymentGateway.GetOrderDetailsFromPaymentAsync(payerId, paymentId, string.Empty, string.Empty).ConfigureAwait(false);

            // Assign the actual customer Id
            orderToProcess.CustomerId = newCustomerId;

            CommerceOperations commerceOperation = new CommerceOperations(ApplicationDomain.Instance, newCustomerId, paymentGateway);
            await commerceOperation.PurchaseAsync(orderToProcess).ConfigureAwait(false);

            SubscriptionsSummary summaryResult = await GetSubscriptionSummaryAsync(newCustomerId).ConfigureAwait(false);

            // Remove the persisted customer registration info.
            await ApplicationDomain.Instance.CustomerRegistrationRepository.DeleteAsync(customerId).ConfigureAwait(false);

            // Capture the request for the customer summary for analysis.
            Dictionary <string, string> eventProperties = new Dictionary <string, string> {
                { "CustomerId", orderToProcess.CustomerId }
            };

            // Track the event measurements for analysis.
            Dictionary <string, double> eventMetrics = new Dictionary <string, double> {
                { "ElapsedMilliseconds", DateTime.Now.Subtract(startTime).TotalMilliseconds }
            };

            ApplicationDomain.Instance.TelemetryService.Provider.TrackEvent("api/order/NewCustomerProcessOrder", eventProperties, eventMetrics);

            summaryResult.CustomerViewModel = customerViewModel;

            return(summaryResult);
        }
        public async Task <SubscriptionsSummary> ProcessOrderForUnAuthenticatedCustomer(string customerId, string paymentId, string payerId)
        {
            var startTime = DateTime.Now;

            customerId.AssertNotEmpty(nameof(customerId));

            paymentId.AssertNotEmpty(nameof(paymentId));
            payerId.AssertNotEmpty(nameof(payerId));

            // Retrieve customer registration details persisted
            CustomerRegistrationRepository customerRegistrationRepository = new CustomerRegistrationRepository(ApplicationDomain.Instance);

            CustomerViewModel customerRegistrationInfoPersisted = await ApplicationDomain.Instance.CustomerRegistrationRepository.RetrieveAsync(customerId);

            var newCustomer = new Customer()
            {
                CompanyProfile = new CustomerCompanyProfile()
                {
                    Domain = customerRegistrationInfoPersisted.DomainName,
                },
                BillingProfile = new CustomerBillingProfile()
                {
                    Culture     = customerRegistrationInfoPersisted.BillingCulture,
                    Language    = customerRegistrationInfoPersisted.BillingLanguage,
                    Email       = customerRegistrationInfoPersisted.Email,
                    CompanyName = customerRegistrationInfoPersisted.CompanyName,

                    DefaultAddress = new Address()
                    {
                        FirstName    = customerRegistrationInfoPersisted.FirstName,
                        LastName     = customerRegistrationInfoPersisted.LastName,
                        AddressLine1 = customerRegistrationInfoPersisted.AddressLine1,
                        AddressLine2 = customerRegistrationInfoPersisted.AddressLine2,
                        City         = customerRegistrationInfoPersisted.City,
                        State        = customerRegistrationInfoPersisted.State,
                        Country      = customerRegistrationInfoPersisted.Country,
                        PostalCode   = customerRegistrationInfoPersisted.ZipCode,
                        PhoneNumber  = customerRegistrationInfoPersisted.Phone,
                    }
                }
            };

            // Register customer
            newCustomer = await ApplicationDomain.Instance.PartnerCenterClient.Customers.CreateAsync(newCustomer);

            var newCustomerId = newCustomer.CompanyProfile.TenantId;

            CustomerViewModel customerViewModel = new CustomerViewModel()
            {
                AddressLine1     = newCustomer.BillingProfile.DefaultAddress.AddressLine1,
                AddressLine2     = newCustomer.BillingProfile.DefaultAddress.AddressLine2,
                City             = newCustomer.BillingProfile.DefaultAddress.City,
                State            = newCustomer.BillingProfile.DefaultAddress.State,
                ZipCode          = newCustomer.BillingProfile.DefaultAddress.PostalCode,
                Country          = newCustomer.BillingProfile.DefaultAddress.Country,
                Phone            = newCustomer.BillingProfile.DefaultAddress.PhoneNumber,
                Language         = newCustomer.BillingProfile.Language,
                FirstName        = newCustomer.BillingProfile.DefaultAddress.FirstName,
                LastName         = newCustomer.BillingProfile.DefaultAddress.LastName,
                Email            = newCustomer.BillingProfile.Email,
                CompanyName      = newCustomer.BillingProfile.CompanyName,
                MicrosoftId      = newCustomer.CompanyProfile.TenantId,
                UserName         = newCustomer.BillingProfile.Email,
                Password         = newCustomer.UserCredentials.Password,
                AdminUserAccount = newCustomer.UserCredentials.UserName + "@" + newCustomer.CompanyProfile.Domain
            };

            IPaymentGateway paymentGateway = PaymentGatewayConfig.GetPaymentGatewayInstance(ApplicationDomain.Instance, "ProcessingOrder");
            OrderViewModel  orderToProcess = await paymentGateway.GetOrderDetailsFromPaymentAsync(payerId, paymentId, string.Empty, string.Empty);

            // Assign the actual customer Id
            orderToProcess.CustomerId = newCustomerId;

            CommerceOperations commerceOperation = new CommerceOperations(ApplicationDomain.Instance, newCustomerId, paymentGateway);
            await commerceOperation.PurchaseAsync(orderToProcess);

            SubscriptionsSummary summaryResult = await this.GetSubscriptionSummaryAsync(newCustomerId);

            // Remove the persisted customer registration info.
            var deleteResult = ApplicationDomain.Instance.CustomerRegistrationRepository.DeleteAsync(customerId);

            // Capture the request for the customer summary for analysis.
            var eventProperties = new Dictionary <string, string> {
                { "CustomerId", orderToProcess.CustomerId }
            };

            // Track the event measurements for analysis.
            var eventMetrics = new Dictionary <string, double> {
                { "ElapsedMilliseconds", DateTime.Now.Subtract(startTime).TotalMilliseconds }
            };

            ApplicationDomain.Instance.TelemetryService.Provider.TrackEvent("api/order/NewCustomerProcessOrder", eventProperties, eventMetrics);

            summaryResult.CustomerViewModel = customerViewModel;

            return(summaryResult);
        }
        /// <summary>
        /// Gets the summary of subscriptions for a portal customer.
        /// </summary>
        /// <param name="customerId">The customer Id.</param>
        /// <returns>Subscription Summary.</returns>
        private async Task <SubscriptionsSummary> GetSubscriptionSummary(string customerId)
        {
            var customerSubscriptionsTask        = ApplicationDomain.Instance.CustomerSubscriptionsRepository.RetrieveAsync(customerId);
            var customerSubscriptionsHistoryTask = ApplicationDomain.Instance.CustomerPurchasesRepository.RetrieveAsync(customerId);
            var allPartnerOffersTask             = ApplicationDomain.Instance.OffersRepository.RetrieveAsync();
            await Task.WhenAll(customerSubscriptionsTask, customerSubscriptionsHistoryTask, allPartnerOffersTask);

            var customerSubscriptionsHistory = customerSubscriptionsHistoryTask.Result;

            // retrieve all the partner offers to match against them
            IEnumerable <PartnerOffer> allPartnerOffers = allPartnerOffersTask.Result;

            // start building the summary.
            decimal summaryTotal = 0;

            // format all responses to client using portal locale.
            CultureInfo responseCulture = new CultureInfo(ApplicationDomain.Instance.PortalLocalization.Locale);
            List <SubscriptionViewModel> customerSubscriptionsView = new List <SubscriptionViewModel>();

            // iterate through and build the list of customer's subscriptions.
            foreach (var subscription in customerSubscriptionsTask.Result)
            {
                decimal subscriptionTotal = 0;
                int     licenseTotal      = 0;
                List <SubscriptionHistory> historyItems = new List <SubscriptionHistory>();

                // collect the list of history items for this subcription.
                var subscriptionHistoryList = customerSubscriptionsHistory
                                              .Where(historyItem => historyItem.SubscriptionId == subscription.SubscriptionId)
                                              .OrderBy(historyItem => historyItem.TransactionDate);

                // iterate through and build the SubsriptionHistory for this subscription.
                foreach (var historyItem in subscriptionHistoryList)
                {
                    decimal orderTotal = Math.Round(historyItem.SeatPrice * historyItem.SeatsBought, 2);
                    historyItems.Add(new SubscriptionHistory()
                    {
                        OrderTotal    = orderTotal.ToString("C", responseCulture),
                        PricePerSeat  = historyItem.SeatPrice.ToString("C", responseCulture),                     // Currency format.
                        SeatsBought   = historyItem.SeatsBought.ToString("G", responseCulture),                   // General format.
                        OrderDate     = historyItem.TransactionDate.ToLocalTime().ToString("d", responseCulture), // Short date format.
                        OperationType = this.GetOperationType(historyItem.PurchaseType)                           // Localized Operation type string.
                    });

                    // Increment the subscription total.
                    licenseTotal += historyItem.SeatsBought;

                    // Increment the subscription total.
                    subscriptionTotal += orderTotal;
                }

                var     partnerOfferItem  = allPartnerOffers.Where(offer => offer.Id == subscription.PartnerOfferId).FirstOrDefault();
                string  subscriptionTitle = partnerOfferItem.Title;
                string  portalOfferId     = partnerOfferItem.Id;
                decimal portalOfferPrice  = partnerOfferItem.Price;

                DateTime subscriptionExpiryDate = subscription.ExpiryDate.ToUniversalTime();
                int      remainingDays          = (subscriptionExpiryDate.Date - DateTime.UtcNow.Date).Days;
                bool     isRenewable            = remainingDays <= 30;
                bool     isEditable             = DateTime.UtcNow.Date <= subscriptionExpiryDate.Date;

                if (partnerOfferItem.IsInactive)
                {
                    // in case the offer is inactive (marked for deletion) then dont allow renewals or editing on this subscription tied to this offer.
                    isRenewable = false;
                    isEditable  = false;
                }

                // Compute the pro rated price per seat for this subcription & return for client side processing during updates.
                decimal proratedPerSeatPrice = Math.Round(CommerceOperations.CalculateProratedSeatCharge(subscription.ExpiryDate, portalOfferPrice), 2);

                SubscriptionViewModel subscriptionItem = new SubscriptionViewModel()
                {
                    SubscriptionId            = subscription.SubscriptionId,
                    FriendlyName              = subscriptionTitle,
                    PortalOfferId             = portalOfferId,
                    PortalOfferPrice          = portalOfferPrice.ToString("C", responseCulture),
                    IsRenewable               = isRenewable,                                                // IsRenewable is true if subscription is going to expire in 30 days.
                    IsEditable                = isEditable,                                                 // IsEditable is true if today is lesser or equal to subscription expiry date.
                    LicensesTotal             = licenseTotal.ToString("G", responseCulture),                // General format.
                    SubscriptionTotal         = subscriptionTotal.ToString("C", responseCulture),           // Currency format.
                    SubscriptionExpiryDate    = subscriptionExpiryDate.Date.ToString("d", responseCulture), // Short date format.
                    SubscriptionOrderHistory  = historyItems,
                    SubscriptionProRatedPrice = proratedPerSeatPrice
                };

                // add this subcription to the customer's subscription list.
                customerSubscriptionsView.Add(subscriptionItem);

                // Increment the summary total.
                summaryTotal += subscriptionTotal;
            }

            // Sort List of subscriptions based on portal offer name.
            return(new SubscriptionsSummary()
            {
                Subscriptions = customerSubscriptionsView.OrderBy(subscriptionItem => subscriptionItem.FriendlyName),
                SummaryTotal = summaryTotal.ToString("C", responseCulture)      // Currency format.
            });
        }