/// <summary>
        /// Retrieves a specific partner offer using its ID.
        /// </summary>
        /// <param name="partnerOfferId">The ID of the partner offer to look for.</param>
        /// <returns>The matching partner offer.</returns>
        //public async Task<PartnerOffer> RetrieveAsync(string partnerOfferId)
        //{
        //    //partnerOfferId.AssertNotEmpty(nameof(partnerOfferId));
        //    PartnerOffer matchingPartnerOffer = (await RetrieveAsync().ConfigureAwait(false)).FirstOrDefault(offer => offer.Id == partnerOfferId);

        //    if (matchingPartnerOffer != null)
        //    {
        //        return matchingPartnerOffer;
        //    }
        //    else
        //    {
        //        throw new PartnerDomainException(ErrorCode.PartnerOfferNotFound, Resources.OfferNotFound);
        //    }
        //}


        /// <summary>
        /// Fetches all Microsoft CSP offers.
        /// </summary>
        /// <returns>A list of all Microsoft CSP offers.</returns>
        public async Task <MicrosoftOffer> RetrieveMicrosoftOfferByIdAsync(string OfferId)
        {
            //List<MicrosoftOffer> microsoftOffers = await ApplicationDomain.CachingService
            //    .FetchAsync<List<MicrosoftOffer>>(MicrosoftOffersCacheKey).ConfigureAwait(false);

            //if (microsoftOffers == null)
            //{
            // Need to manage this based on the offer locale supported by the Offer API. Either its english or using one of the supported offer locale to retrieve localized offers for the store front.
            IPartner localeSpecificPartnerCenterClient = ApplicationDomain.PartnerCenterClient.With(RequestContextFactory.Instance.Create(ApplicationDomain.PortalLocalization.OfferLocale));

            // Offers.ByCountry is required to pull country / region specific offers.
            Microsoft.Store.PartnerCenter.Models.Offers.Offer partnerCenterOffers = await localeSpecificPartnerCenterClient.Offers.ByCountry(ApplicationDomain.PortalLocalization.CountryIso2Code).ById(OfferId).GetAsync().ConfigureAwait(false);

            //IEnumerable<Microsoft.Store.PartnerCenter.Models.Offers.Offer> eligibleOffers = partnerCenterOffers?.Items.Where(offer =>
            //    !offer.IsAddOn &&
            //    (offer.PrerequisiteOffers == null || !offer.PrerequisiteOffers.Any())
            //    && offer.IsAvailableForPurchase);

            MicrosoftOffer microsoftOffers = new MicrosoftOffer()
            {
                Offer = partnerCenterOffers
                        // ThumbnailUri = new Uri(await ApplicationDomain.MicrosoftOfferLogoIndexer.GetOfferLogoUriAsync(partnerCenterOffer).ConfigureAwait(false), UriKind.Relative)
            };

            //if (eligibleOffers != null)
            //{
            //    foreach (Microsoft.Store.PartnerCenter.Models.Offers.Offer partnerCenterOffer in eligibleOffers)
            //    {
            //        microsoftOffers.Add(new MicrosoftOffer()
            //        {
            //            Offer = partnerCenterOffer,
            //            // ThumbnailUri = new Uri(await ApplicationDomain.MicrosoftOfferLogoIndexer.GetOfferLogoUriAsync(partnerCenterOffer).ConfigureAwait(false), UriKind.Relative)
            //        });
            //    }
            //}

            // cache the Microsoft offers for one day
            //await ApplicationDomain.CachingService.StoreAsync(
            //    MicrosoftOffersCacheKey,
            //    microsoftOffers,
            //    TimeSpan.FromDays(1)).ConfigureAwait(false);
            //}

            return(microsoftOffers);
        }
Example #2
0
        public async Task <OfferCatalogViewModel> GetOffersCatalog()
        {
            bool isBrandingConfigured = await ApplicationDomain.Instance.PortalBranding.IsConfiguredAsync().ConfigureAwait(false);

            bool isOffersConfigured = await ApplicationDomain.Instance.OffersRepository.IsConfiguredAsync().ConfigureAwait(false);

            bool isPaymentConfigured = await ApplicationDomain.Instance.PaymentConfigurationRepository.IsConfiguredAsync().ConfigureAwait(false);

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

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


            OfferCatalogViewModel offerCatalogViewModel = new OfferCatalogViewModel
            {
                IsPortalConfigured = isBrandingConfigured && isOffersConfigured && isPaymentConfigured
            };

            if (offerCatalogViewModel.IsPortalConfigured)
            {
                foreach (PartnerOffer offer in partnerOffers)
                {
                    // TODO :: Handle Microsoft offer being pulled back due to EOL.
                    MicrosoftOffer microsoftOfferItem = microsoftOffers.FirstOrDefault(msOffer => msOffer.Offer.Id == offer.MicrosoftOfferId);

                    // temporarily remove the partner offer from catalog display if the corresponding Microsoft offer does not exist.
                    if (microsoftOfferItem != null)
                    {
                        offer.Thumbnail = microsoftOfferItem.ThumbnailUri;
                    }
                    else
                    {
                        // temporary fix - remove the items from the collection by marking it as Inactive.
                        offer.IsInactive = true;
                    }
                }

                offerCatalogViewModel.Offers = partnerOffers.OrderBy(o => o.DisplayIndex).Where(offer => !offer.IsInactive);
            }

            return(offerCatalogViewModel);
        }
        public async Task <ActionResult> AddOrUpdate(string Offerid)
        {
            MicrosoftOffer microsoftOffers = await ApplicationDomain.Instance.OffersRepository.RetrieveMicrosoftOfferByIdAsync(Offerid).ConfigureAwait(false);

            OffersSetup offersSetup = new Models.OffersSetup();

            ViewModel.OffersSetup.OffersSetup _o = new ViewModel.OffersSetup.OffersSetup();
            offersSetup = _o.GetOfferByMicrosoftOfferId(Offerid);

            if (offersSetup.MicrosoftOfferId == null)
            {
                offersSetup.MicrosoftOfferId = Offerid;
                offersSetup.Title            = microsoftOffers.Offer.Name;
            }

            Models.OffersSetupRepository rep = new OffersSetupRepository();
            rep.MicrosoftOffer = microsoftOffers;
            rep.OffersSetup    = offersSetup;

            return(View(rep));
        }
        /// <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);
        }
Example #5
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.
            });
        }