public override async Task ReportItemProcessorFunctionAsync(
            BlockingCollection <ReportOutputItem> results,
            List <PartnerSdkModels.Customers.Customer> customers, PartnerSdkModels.Customers.Customer customer,
            int currentPage)
        {
            _logger.Info(string.Format("Thread: {0} Batch: {1}. Processing customer: {2} ({3}/{4}) / (ID: {5} - CID: {6} - TD: {7})",
                                       Thread.CurrentThread.ManagedThreadId, currentPage,
                                       customer.CompanyProfile.CompanyName, customers.IndexOf(customer) + 1, customers.Count,
                                       customer.Id, customer.CommerceId, customer.CompanyProfile.Domain));

            ActivationReportOutputItem reportOutputItem = new ActivationReportOutputItem()
            {
                Customer = customer
            };

            #region Execute base customer validations

            if (ExecuteReportItemProcessorCustomerBaseValidations(reportOutputItem, results, customer))
            {
                // Matched one of the validations. Return
                return;
            }

            #endregion

            try
            {
                #region Get customer domains

                // NOTE: We always include the customer domains, to include this info in the report,
                // even if the customer does not have any subscribed SKUs

                _logger.Debug("GetCustomerDomains");
                reportOutputItem.CustomerDomains = Program.GetCustomerDomains(customer);

                #endregion

                #region Get Subscribed Skus information

                _logger.Debug("GetCustomerSubscribedSkus");
                List <SubscribedSku> customerSubscribedSkus = await Program.GetCustomerSubscribedSkus(customer);

                #region Execute base subscribed Skus validations

                if (ExecuteReportItemProcessorSubscribedSkusBaseValidations(reportOutputItem, results, customer, customerSubscribedSkus))
                {
                    // Matched one of the validations. Return
                    return;
                }

                #endregion

                #endregion

                #region Get Subscriptions information

                _logger.Debug("GetCustomerSubscriptions");
                List <PartnerSdkModels.Subscriptions.Subscription> customerSubscriptions =
                    await Program.GetCustomerSubscriptions(customer);

                #region Execute base subscriptions validations

                if (ExecuteReportItemProcessorSubscriptionsBaseValidations(reportOutputItem, results, customer, customerSubscriptions))
                {
                    // Matched one of the validations. Return
                    return;
                }

                #endregion

                #endregion

                #region Get Subscription Offers information

                // This is necessary to match Subscribed SKU to a Subscription
                // Subscribed SKU has the SKU Product ID field
                // Subscription has the Offer ID field
                // The Offer detail is the connection between them, because the Offer has the Offer ID and the Product ID
                _logger.Debug("GetSubscriptionsOffers");
                List <PartnerSdkModels.Offers.Offer> subscriptionsOffers =
                    await Program.GetCustomerSubscriptionsOffers(customerSubscriptions);

                #endregion

                #region Process each subscribed Sku

                foreach (SubscribedSku subscribedSku in customerSubscribedSkus)
                {
                    #region Extract Sku information

                    _logger.Info(string.Format("Processing subscribedSku: {0} ({1}/{2})",
                                               subscribedSku.SkuPartNumber, customerSubscribedSkus.IndexOf(subscribedSku) + 1,
                                               customerSubscribedSkus.Count));

                    // Create new subscribed sku report output item
                    ActivationReportSubscribedSKUOutputItem skuAndSubscriptions = new ActivationReportSubscribedSKUOutputItem()
                    {
                        SubscribedSKU = subscribedSku
                    };

                    // Try to match subscribedSku with corresponding subscription offer
                    // to get subscribed sku subscriptions
                    // Get the offer detail that matches the subscribed SKU product ID
                    PartnerSdkModels.Offers.Offer skuOfferDetail = subscriptionsOffers.FirstOrDefault(offer =>
                                                                                                      offer.Product.Id.Equals(subscribedSku.SkuId.ToString(),
                                                                                                                              StringComparison.InvariantCultureIgnoreCase));

                    if (skuOfferDetail != null)
                    {
                        // Extract offer and subscribed Sku subscriptions
                        skuAndSubscriptions.Offer = skuOfferDetail;

                        // Filter all the SKU subscriptions by the offer id
                        skuAndSubscriptions.SKUSubscriptions = customerSubscriptions.Where(subscription =>
                                                                                           subscription.OfferId.ToString().Equals(skuOfferDetail.Id,
                                                                                                                                  StringComparison.InvariantCultureIgnoreCase)).ToList();
                    }
                    else
                    {
                        // No offer detail for the subscribed sku. Could not match subscriptions to subscribed Sku
                        skuAndSubscriptions.Offer         = null;
                        skuAndSubscriptions.ActionType    = "ACTIVATION OPPORTUNITY";
                        skuAndSubscriptions.ActionSubType = "Not a CSP offer";
                        reportOutputItem.CustomerSubscribedSkuAndSubscriptions.Add(Program.Clone(skuAndSubscriptions));
                        continue;
                    }

                    skuAndSubscriptions.ActiveSeats        = subscribedSku.PrepaidUnits.Enabled;
                    skuAndSubscriptions.InGracePeriodSeats = subscribedSku.PrepaidUnits.Warning;
                    skuAndSubscriptions.DisabledSeats      = subscribedSku.PrepaidUnits.Suspended;
                    skuAndSubscriptions.AssignedSeats      = subscribedSku.ConsumedUnits;

                    if (!subscribedSku.CapabilityStatus.Equals("Enabled", StringComparison.InvariantCultureIgnoreCase))
                    {
                        // Sku capability is different from enabled
                        skuAndSubscriptions.ActionType    = "ACTIVATION OPPORTUNITY";
                        skuAndSubscriptions.ActionSubType = "SKU capability status not enabled";
                        // Add processed subscribed SKU to customer
                        reportOutputItem.CustomerSubscribedSkuAndSubscriptions.Add(Program.Clone(skuAndSubscriptions));
                        continue;
                    }

                    #endregion

                    #region Execute activation action analysis logic

                    #region Check when no seats are assigned

                    if (skuAndSubscriptions.AssignedSeats == 0)
                    {
                        #region Check when no seats are assigned, and no seats are active

                        if (skuAndSubscriptions.ActiveSeats == 0)
                        {
                            // No seats assigned, and not active seats

                            if (skuAndSubscriptions.InGracePeriodSeats == 0)
                            {
                                if (skuAndSubscriptions.DisabledSeats == 0)
                                {
                                    skuAndSubscriptions.ActionType    = "ACTIVATION OPPORTUNITY";
                                    skuAndSubscriptions.ActionSubType = "No seats active, assigned, about to expire or disabled";
                                }

                                if (skuAndSubscriptions.DisabledSeats > 0)
                                {
                                    skuAndSubscriptions.ActionType    = "NO ACTION NEEDED";
                                    skuAndSubscriptions.ActionSubType = "Waiting for subscription life cycle to de-provision subscription";
                                }
                            }

                            if (skuAndSubscriptions.InGracePeriodSeats > 0)
                            {
                                skuAndSubscriptions.ActionType    = "ACTIVATION OPPORTUNITY";
                                skuAndSubscriptions.ActionSubType = "No seats assigned yet, all licenses are about to expire";
                            }
                        }

                        #endregion

                        #region Check when no seats are assigned, but there are active seats

                        if (skuAndSubscriptions.ActiveSeats > 0)
                        {
                            // No seats assigned, but there are active seats

                            if (skuAndSubscriptions.InGracePeriodSeats == 0)
                            {
                                // There are active seats, none about to expire, but no assigned seats
                                skuAndSubscriptions.ActionType    = "ACTIVATION OPPORTUNITY";
                                skuAndSubscriptions.ActionSubType = "No seats assigned yet";
                            }

                            if (skuAndSubscriptions.InGracePeriodSeats > 0)
                            {
                                // There are active and about to expire seats, but no assigned seats
                                skuAndSubscriptions.ActionType    = "ACTIVATION OPPORTUNITY";
                                skuAndSubscriptions.ActionSubType = "No seats assigned yet, some licenses are about to expire";
                            }
                        }

                        #endregion
                    }

                    #endregion

                    #region Check when there are assigned seats

                    if (skuAndSubscriptions.AssignedSeats > 0)
                    {
                        // Seats are assigned. Check other conditions

                        #region Check comparison between active and assigned seats

                        if (skuAndSubscriptions.ActiveSeats == skuAndSubscriptions.AssignedSeats &&
                            skuAndSubscriptions.InGracePeriodSeats == 0)
                        {
                            // There are active seats and all are assigned
                            // No seats are disabled or about to expire
                            skuAndSubscriptions.ActionType    = "NO ACTION NEEDED";
                            skuAndSubscriptions.ActionSubType = "All active licenses are assigned";
                            reportOutputItem.CustomerSubscribedSkuAndSubscriptions.Add(Program.Clone(skuAndSubscriptions));
                            continue;
                        }

                        if ((skuAndSubscriptions.ActiveSeats + skuAndSubscriptions.InGracePeriodSeats) == skuAndSubscriptions.AssignedSeats)
                        {
                            // The sum of the active and about to expire seats is equal to the assigned seats
                            // These are assigned aeats, and also disabled seats
                            skuAndSubscriptions.ActionType    = "ACTION NEEDED";
                            skuAndSubscriptions.ActionSubType = "All licenses assigned. Some licenses are about to expire";
                            reportOutputItem.CustomerSubscribedSkuAndSubscriptions.Add(Program.Clone(skuAndSubscriptions));
                            continue;
                        }

                        if ((skuAndSubscriptions.ActiveSeats + skuAndSubscriptions.InGracePeriodSeats) > skuAndSubscriptions.AssignedSeats)
                        {
                            // The sum of the active and about to expire seats is greater than the assigned seats and
                            // There are assigned seats and no disabled seats
                            skuAndSubscriptions.ActionType    = "ACTIVATION OPPORTUNITY";
                            skuAndSubscriptions.ActionSubType = "Not all seats have been assigned yet";
                            reportOutputItem.CustomerSubscribedSkuAndSubscriptions.Add(Program.Clone(skuAndSubscriptions));
                            continue;
                        }

                        if ((skuAndSubscriptions.ActiveSeats + skuAndSubscriptions.InGracePeriodSeats) < skuAndSubscriptions.AssignedSeats)
                        {
                            // The are assigned seats and they are fewer than the active plus the about to expire seats
                            skuAndSubscriptions.ActionType    = "ACTION NEEDED";
                            skuAndSubscriptions.ActionSubType = "Customer has more users with licenses than licenses available";
                            reportOutputItem.CustomerSubscribedSkuAndSubscriptions.Add(Program.Clone(skuAndSubscriptions));
                            continue;
                        }

                        #endregion
                    }

                    #endregion

                    // If it didnt match with anything
                    if (string.IsNullOrWhiteSpace(skuAndSubscriptions.ActionType))
                    {
                        skuAndSubscriptions.ActionType = "Scenario not defined";
                    }

                    // Add processed subscribed SKU to customer
                    reportOutputItem.CustomerSubscribedSkuAndSubscriptions.Add(Program.Clone(skuAndSubscriptions));

                    #endregion
                }

                // Add customer processing to all results
                results.Add(Program.Clone(reportOutputItem));

                #endregion
            }
            catch (Exception ex)
            {
                _logger.Warn("Error: " + ex.ToString());

                reportOutputItem.GlobalActionType    = "ERROR";
                reportOutputItem.GlobalActionSubType = ex.ToString().Replace("\r\n", " ").Replace("\n", " ").Replace("\t", " ");
                results.Add(Program.Clone(reportOutputItem));
            }
        }
Exemple #2
0
        public override async Task ReportItemProcessorFunctionAsync(
            BlockingCollection <ReportOutputItem> results,
            List <PartnerSdkModels.Customers.Customer> customers, PartnerSdkModels.Customers.Customer customer,
            int currentPage)
        {
            _logger.Info(string.Format("Thread: {0} Batch: {1}. Processing customer: {2} ({3}/{4}) / (ID: {5} - CID: {6} - TD: {7})",
                                       Thread.CurrentThread.ManagedThreadId, currentPage,
                                       customer.CompanyProfile.CompanyName, customers.IndexOf(customer) + 1, customers.Count,
                                       customer.Id, customer.CommerceId, customer.CompanyProfile.Domain));

            CustomerUsageReportOutputItem reportOutputItem = new CustomerUsageReportOutputItem()
            {
                Customer = customer
            };

            #region Execute base customer validations

            if (ExecuteReportItemProcessorCustomerBaseValidations(reportOutputItem, results, customer))
            {
                // Customer matched one of the validations. Return
                return;
            }

            #endregion

            try
            {
                #region Get customer domains

                // NOTE: We always include the customer domains, to include this info in the report,
                // even if the customer does not have any subscribed SKUs

                _logger.Debug("GetCustomerDomains");
                List <Domain> customerDomains = Program.GetCustomerDomains(customer);
                // Extract domains information
                reportOutputItem.OnMicrosoftDomain = customerDomains.FirstOrDefault(domain => domain.IsInitial && domain.IsVerified).Name;
                reportOutputItem.DefaultDomain     = customerDomains.FirstOrDefault(domain => domain.IsDefault && domain.IsVerified).Name;

                #endregion

                #region Get Subscribed Skus information

                _logger.Debug("GetCustomerSubscribedSkus");
                List <SubscribedSku> customerSubscribedSkus = await Program.GetCustomerSubscribedSkus(customer);

                #region Execute base subscribed Skus validations

                if (ExecuteReportItemProcessorSubscribedSkusBaseValidations(reportOutputItem, results, customer, customerSubscribedSkus))
                {
                    // Matched one of the validations. Return
                    return;
                }

                #endregion

                #endregion

                #region Get Subscriptions information

                _logger.Debug("GetCustomerSubscriptions");
                List <PartnerSdkModels.Subscriptions.Subscription> customerSubscriptions =
                    await Program.GetCustomerSubscriptions(customer);

                #region Execute base subscriptions validations

                if (ExecuteReportItemProcessorSubscriptionsBaseValidations(reportOutputItem, results, customer, customerSubscriptions))
                {
                    // Matched one of the validations. Return
                    return;
                }

                #endregion

                #endregion

                #region Extract information from each subscription

                foreach (PartnerSdkModels.Subscriptions.Subscription subscription in customerSubscriptions)
                {
                    _logger.Info(string.Format("Processing subscription: {0} ({1}/{2})",
                                               subscription.FriendlyName, customerSubscriptions.IndexOf(subscription) + 1,
                                               customerSubscriptions.Count));

                    reportOutputItem.SubscriptionId       = Guid.Parse(subscription.Id);
                    reportOutputItem.SubscriptionStatus   = subscription.Status.ToString();
                    reportOutputItem.SubscriptionQuantity = (uint)subscription.Quantity;

                    if (subscription.Status != PartnerSdkModels.Subscriptions.SubscriptionStatus.Active)
                    {
                        // Subscription is not active. Nothing to do
                        reportOutputItem.GlobalActionType    = "ACTIVATION OPPORTUNITY";
                        reportOutputItem.GlobalActionSubType = "Subscription state: " + subscription.Status.ToString();
                        results.Add(Program.Clone(reportOutputItem));
                        return;
                    }

                    // Subscription Offer information
                    // This is necessary to match Subscribed SKU to a Subscription
                    // Subscribed SKU has the SKU Product ID field
                    // Subscription has the Offer ID field
                    // The Offer detail is the connection between them, because the Offer has the Offer ID and the Product ID
                    _logger.Debug("GetSubscriptionOffer");
                    PartnerSdkModels.Offers.Offer subscriptionOffer = await Program.GetOfferById(subscription.OfferId.ToString());

                    reportOutputItem.OfferName = subscriptionOffer.Name;

                    // Subscription SKU
                    SubscribedSku subscriptionSubscribedSku = customerSubscribedSkus.FirstOrDefault(sku =>
                                                                                                    sku.SkuId.ToString().Equals(subscriptionOffer.Product.Id, StringComparison.InvariantCultureIgnoreCase));

                    if (subscriptionSubscribedSku == null)
                    {
                        reportOutputItem.GlobalActionType    = "Not supported";
                        reportOutputItem.GlobalActionSubType = "Subscription Offer does not map to any CSP Subscribed SKU Product";
                        results.Add(Program.Clone(reportOutputItem));
                        continue;
                    }

                    reportOutputItem.SKUPartNumber    = subscriptionSubscribedSku.SkuPartNumber;
                    reportOutputItem.SKUTotalServices = subscriptionSubscribedSku.ServicePlans.Count();
                    reportOutputItem.SKUAssignedSeats = subscriptionSubscribedSku.ConsumedUnits;

                    #region Extract global user's information (in terms of number of users, not detailed user's information)

                    // For tenant level information
                    // Ex: Subscription is for 20 seats, but only 5 are using each of the services?

                    foreach (ServicePlanInfo servicePlan in subscriptionSubscribedSku.ServicePlans)
                    {
                        _logger.Info(string.Format("Processing SKU Service Plan: {0} ({1}/{2})",
                                                   servicePlan.ServicePlanName, subscriptionSubscribedSku.ServicePlans.IndexOf(servicePlan) + 1,
                                                   subscriptionSubscribedSku.ServicePlans.Count));

                        reportOutputItem.SKUService = servicePlan.ServicePlanName;
                        reportOutputItem.SKUServiceProvisioningStatus = servicePlan.ProvisioningStatus.ToString();

                        switch (servicePlan.ServicePlanName)
                        {
                        case "EXCHANGE_S_STANDARD":
                        case "EXCHANGE_S_DESKLESS":
                            CustomerMailboxUsageReport customerMailboxUsageReport = Program.GetCustomerMailboxUsageReport(customer);
                            reportOutputItem.SKUServiceActiveUsers = customerMailboxUsageReport.TotalMailboxCount;
                            break;

                        case "MCOSTANDARD":
                            CustomerCsActiveUserReport customerCsActiveUserReport = Program.GetCustomerCsActiveUserReport(customer);
                            reportOutputItem.SKUServiceActiveUsers = customerCsActiveUserReport.ActiveUsers;
                            break;

                        case "SHAREPOINTSTANDARD":
                            CustomerSPOActiveUserReport customerSPOActiveUserReport = Program.GetCustomerSPOActiveUserReport(customer);
                            reportOutputItem.SKUServiceActiveUsers = customerSPOActiveUserReport.UniqueUsers;

                            // Also has OneDrive ?????
                            // CustomerSPOSkyDriveProDeployedReport customerSPOSkyDriveProDeployedReport = await Program.GetCustomerSPOSkyDriveProDeployedReport(customer);
                            //reportOutputItem.SKUServiceActiveUsers = customerSPOSkyDriveProDeployedReport.Active;
                            break;

                        case "SHAREPOINTWAC":
                        case "OFFICE_BUSINESS":
                        case "OFFICESUBSCRIPTION":
                        case "ONEDRIVEENTERPRISE":
                        case "ONEDRIVESTANDARD":
                        case "SWAY":
                        case "INTUNE_O365":
                        case "YAMMER_ENTERPRISE":
                        default:
                            reportOutputItem.GlobalActionType    = "Not supported";
                            reportOutputItem.GlobalActionSubType = "Service Plan information extraction not supported";
                            results.Add(Program.Clone(reportOutputItem));
                            continue;
                        }

                        if (reportOutputItem.SKUServiceActiveUsers < reportOutputItem.SKUAssignedSeats)
                        {
                            reportOutputItem.GlobalActionType    = "ACTIVATION OPPORTUNITY";
                            reportOutputItem.GlobalActionSubType = "Not all users are active on the service";
                        }
                        else
                        {
                            reportOutputItem.GlobalActionType    = "NO ACTION NEEDED";
                            reportOutputItem.GlobalActionSubType = "All users are active on the service";
                        }

                        results.Add(Program.Clone(reportOutputItem));
                    }

                    #endregion
                }

                #endregion
            }
            catch (Exception ex)
            {
                _logger.Warn("Error: " + ex.ToString());

                reportOutputItem.GlobalActionType    = "ERROR";
                reportOutputItem.GlobalActionSubType = ex.ToString().Replace("\r\n", " ").Replace("\n", " ").Replace("\t", " ");
                results.Add(Program.Clone(reportOutputItem));
            }
        }