Merge branch 'master' into adbhat/AddDeleteDapSample

This commit is contained in:
kaminasy 2022-07-12 10:22:31 -07:00 коммит произвёл GitHub
Родитель 3388613f67 14d92553f6
Коммит a898385a4d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
12 изменённых файлов: 318 добавлений и 49 удалений

Просмотреть файл

@ -40,6 +40,8 @@ internal record Subscription
public ItemType ProductType { get; init; } = new ItemType();
public bool AutoRenewEnabled { get; init; }
public NewCommerceEligibility MigrationEligibility { get; set; } = new NewCommerceEligibility();
public string MigratedFromSubscriptionId { get; init; } = string.Empty;
@ -63,6 +65,8 @@ internal record MigrationRequest
public DateTime ExpirationDate { get; init; }
public bool AutoRenewEnabled { get; init; }
public bool MigrationEligible { get; set; }
public string NcePsa { get; set; } = string.Empty;

Просмотреть файл

@ -38,9 +38,9 @@ internal class NewCommerceMigrationProvider : INewCommerceMigrationProvider
using var csvReader = new CsvReader(fileReader, CultureInfo.InvariantCulture, leaveOpen: true);
var inputMigrationRequests = csvReader.GetRecords<MigrationRequest>().ToList();
if (inputMigrationRequests.Count > 100)
if (inputMigrationRequests.Count > 200)
{
Console.WriteLine($"There are too many migration requests in the file: {fileName}. The maximum limit for migration uploads per file is 100. Please fix the input file to continue...");
Console.WriteLine($"There are too many migration requests in the file: {fileName}. The maximum limit for migration uploads per file is 200. Please fix the input file to continue...");
continue;
}
@ -226,7 +226,7 @@ internal class NewCommerceMigrationProvider : INewCommerceMigrationProvider
}
var result = this.PrepareMigrationResult(migrationResult, migrationResult.BatchId, migration, migrationError);
return (result, migration?.AddOnMigrations);
return (result!, migration?.AddOnMigrations ?? Enumerable.Empty<NewCommerceMigration>());
}
/// <summary>
@ -363,12 +363,18 @@ internal class NewCommerceMigrationProvider : INewCommerceMigrationProvider
/// <returns>The add on migration results.</returns>
private List<MigrationResult> PrepareAddOnMigrationResult(IEnumerable<MigrationRequest> addOnMigrationRequests, string batchId, NewCommerceMigration? newCommerceMigration, NewCommerceMigrationError? newCommerceMigrationError, List<MigrationResult> migrationResults)
{
foreach (var addOnMigrationResponse in newCommerceMigration.AddOnMigrations)
if(newCommerceMigration != null)
{
var addOnMigrationRequest = addOnMigrationRequests.SingleOrDefault(n => n.LegacySubscriptionId.Equals(addOnMigrationResponse.CurrentSubscriptionId, StringComparison.OrdinalIgnoreCase));
addOnMigrationResponse.Status = newCommerceMigration.Status;
addOnMigrationResponse.Id = newCommerceMigration.Id;
PrepareMigrationResult(addOnMigrationRequest, batchId, addOnMigrationResponse, newCommerceMigrationError, migrationResults);
foreach (var addOnMigrationResponse in newCommerceMigration.AddOnMigrations)
{
var addOnMigrationRequest = addOnMigrationRequests.SingleOrDefault(n => n.LegacySubscriptionId.Equals(addOnMigrationResponse.CurrentSubscriptionId, StringComparison.OrdinalIgnoreCase));
if(addOnMigrationRequest != null)
{
addOnMigrationResponse.Status = newCommerceMigration.Status;
addOnMigrationResponse.Id = newCommerceMigration.Id;
PrepareMigrationResult(addOnMigrationRequest, batchId, addOnMigrationResponse, newCommerceMigrationError, migrationResults);
}
}
}
return migrationResults;

Просмотреть файл

@ -61,6 +61,7 @@ static async Task RunAsync(IServiceProvider serviceProvider)
Directory.CreateDirectory($"{Constants.InputFolderPath}/migrations/processed");
Directory.CreateDirectory(Constants.OutputFolderPath);
ShowOptions:
Console.WriteLine("Please choose an option");
Console.WriteLine("1. Export customers");
@ -68,16 +69,23 @@ static async Task RunAsync(IServiceProvider serviceProvider)
Console.WriteLine("3. Upload migrations");
Console.WriteLine("4. Export migration status");
Console.WriteLine("5. Export NCE subscriptions");
Console.WriteLine("6. Exit");
SelectOption:
var option = Console.ReadLine();
if (!short.TryParse(option, out short input) || !(input >= 1 && input <= 5))
if (!short.TryParse(option, out short input) || !(input >= 1 && input <= 6))
{
Console.WriteLine("Invalid input, Please try again! Possible values are {1, 2, 3, 4, 5}");
Console.WriteLine("Invalid input, Please try again! Possible values are {1, 2, 3, 4, 5, 6}");
goto SelectOption;
}
if(input == 6)
{
Console.WriteLine("Exiting the app!");
Environment.Exit(Environment.ExitCode);
}
Stopwatch stopwatch = Stopwatch.StartNew();
var result = input switch
@ -91,5 +99,8 @@ SelectOption:
};
stopwatch.Stop();
Console.WriteLine($"Completed the operation in {stopwatch.Elapsed}");
Console.WriteLine($"Completed the operation {input} in {stopwatch.Elapsed}");
Console.WriteLine("========================================================");
goto ShowOptions;
}

Просмотреть файл

@ -76,8 +76,8 @@ internal class SubscriptionProvider : ISubscriptionProvider
if (failedCustomersBag.Count > 0)
{
Console.WriteLine("Exporting failed customers");
await csvProvider.ExportCsv(failedCustomersBag, "failedCustomers.csv");
Console.WriteLine($"Exported failed customers at {Environment.CurrentDirectory}/failedCustomers.csv");
await csvProvider.ExportCsv(failedCustomersBag, $"{Constants.OutputFolderPath}/failedCustomers.csv");
Console.WriteLine($"Exported failed customers at {Environment.CurrentDirectory}/{Constants.OutputFolderPath}/failedCustomers.csv");
}
return true;
@ -237,7 +237,7 @@ internal class SubscriptionProvider : ISubscriptionProvider
migrationResponse.EnsureSuccessStatusCode();
var newCommerceEligibility = await migrationResponse.Content.ReadFromJsonAsync<NewCommerceEligibility>().ConfigureAwait(false);
if (newCommerceEligibility.AddOnMigrations.Any())
if (newCommerceEligibility!.AddOnMigrations.Any())
{
addOnEligibilityList.Add(newCommerceEligibility.AddOnMigrations);
}
@ -279,6 +279,7 @@ internal class SubscriptionProvider : ISubscriptionProvider
LegacySubscriptionName = subscription.FriendlyName,
LegacyProductName = subscription.OfferName,
ExpirationDate = subscription.CommitmentEndDate,
AutoRenewEnabled = subscription.AutoRenewEnabled,
MigrationEligible = newCommerceEligibility.IsEligible,
NcePsa = newCommerceEligibility.CatalogItemId,
CurrentTerm = subscription.TermDuration,

Просмотреть файл

@ -46,14 +46,13 @@ Below is a high-level workflow of the console app experience and batch migration
![Batch Migration Workflow](assets/images/BatchMigrationWorkflow.png "Batch Migration Workflow")
## Software Pre-Requisites
In order to build and run the BAM tool, .NET 6.0 SDK software is required.
## Pre-Requisites
* In order to build and run the BAM tool, .NET 6.0 SDK is required.
* AAD AppId that is onboarded to access Partner Center Apis. The batch migration (BAM) tool is not configured for multitenant apps. When registering the App please use single tenant app.
## Step-by-step flow of migrating a batch
### Begin Running the Tool and Authenticate your Account
Steps for tool setup:
* Open command prompt and navigate to the folder where NCEBulkMigrationTool.sln is located.
@ -71,11 +70,6 @@ Steps to run the tool:
```
.\NCEBulkMigrationTool.exe <AppId> <Upn>
```
* If a previous version of the tool was installed, enter the following command in the Command Prompt to uninstall the older version:
```
dotnet tool uninstall ncebulkmigrationtool -g
```
* NOTE: If multiple users are running at the same time from the same folder then files can be overwritten or access can be denied. It is better to copy the tool to multiple folders and each user can operate on a separate instance of the tool
@ -225,6 +219,16 @@ To export NCE subscriptions, enter command 5. The exported list will show up in
![Export NCE subscriptions CSV file output](assets/images/ExportNceSubscriptionsCsvOutput.png "Export NCE subscriptions CSV file output")
## Key Scenarios
In the case a user wants to migrate more than 100 subscriptions (the maximum batch size recommendation), multiple batches can be uploaded into the BAM tool. Users can organize folders by a variety of fields to reduce the size of the files they would like to upload to be migrated; users may organize subscriptions to be migrated by indirect reseller, product name, subscription name, and more. If a batch file, which the user has organized, exceeds the maximum recommendation of 100 subscriptions, users may separate one CSV into multiple by effectively copying over subscriptions to new files to maintain the 100 subscription maximum of each batch. For example, if a user would like to migrate 325 subscriptions, this can be split into four separate files (three files can each contain 100 subscriptions and the last one can contain 25).
Multiple files can be uploaded into the batch tool at once; the tool will read migration requests one batch file and a time and will automatically begin reading in other batch files saved to the input directory (in the case multiple batches have been added). The tool will read in batches one-by-one and call the [Create Migration API](https://docs.microsoft.com/en-us/partner-center/develop/create-migration) on each subscription individually. Users would not need to wait for one batch file to be finished executing to add additional batch files to the input directory.
The anticipated timelines for each batch to complete is zero to six hours; exceptions will be seen in cases where Partner Center is receiving a high volume of migration requests from multiple users in a short timeframe. More details regarding expected migration timelines are available [here](https://docs.microsoft.com/en-us/partner-center/migrate-subscriptions-to-new-commerce#expected-migration-timelines).
## Known Issues
* If you receive a 409 error when exporting the subscription list, please wait 5 minutes and retry this step. This error primarily happens in cases where the tool is making parallel calls while the system is still taking action on previous call
## Additional notes and resources
Please migrate only one batch of subscriptions at a time to avoid API throttling and rate limits.

Просмотреть файл

@ -0,0 +1,87 @@
// -----------------------------------------------------------------------
// <copyright file="ValidateAndCreateNewCommerceMigrationWithAddOn.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------
namespace Microsoft.Store.PartnerCenter.Samples.NewCommerceMigrations
{
using Microsoft.Store.PartnerCenter.Models.NewCommerceMigrations;
using System;
using System.Collections.Generic;
/// <summary>
/// A scenario that validates a New-Commerce migration with an add-on and then creates it.
/// </summary>
public class ValidateAndCreateNewCommerceMigrationWithAddOn : BasePartnerScenario
{
/// <summary>
/// Initializes a new instance of the <see cref="ValidateAndCreateNewCommerceMigrationWithAddOn"/> class.
/// </summary>
/// <param name="context">The scenario context.</param>
public ValidateAndCreateNewCommerceMigrationWithAddOn(IScenarioContext context) : base("Validate and create a New-Commerce migration with add-on", context)
{
}
/// <summary>
/// Executes the scenario.
/// </summary>
protected override void RunScenario()
{
var partnerOperations = this.Context.UserPartnerOperations;
string customerId = this.ObtainCustomerId("Enter the ID of the customer making the purchase");
string subscriptionId = this.ObtainSubscriptionId(customerId, "Enter the ID of the subscription to be migrated to New-Commerce");
string addOnSubscriptionId = this.ObtainSubscriptionId(customerId, "Enter the ID of the add-on subscription to be migrated to New-Commerce");
// Get the add-on subscription and display information.
var addOnSubscription = partnerOperations.Customers.ById(customerId).Subscriptions.ById(addOnSubscriptionId).Get();
this.Context.ConsoleHelper.WriteObject(addOnSubscription, "Add-on Subscription");
Console.WriteLine();
string addOnSubscriptionTermDuration = this.ObtainRenewalTermDuration("Enter a term duration for the add-on subscription [example: P1Y, P1M]");
string addOnSubscriptionBillingCycle = this.ObtainBillingCycle("Enter a billing cycle for the add-on subscription [example: Annual or Monthly]");
string addOnSubscriptionQuantityString = this.ObtainQuantity("Enter the quantity for the add-on subscription");
var addOnSubscriptionQuantity = int.Parse(addOnSubscriptionQuantityString);
var newCommerceMigration = new NewCommerceMigration
{
CurrentSubscriptionId = subscriptionId,
AddOnMigrations = new List<NewCommerceMigration>
{
new NewCommerceMigration
{
CurrentSubscriptionId = addOnSubscriptionId,
TermDuration = addOnSubscriptionTermDuration,
BillingCycle = addOnSubscriptionBillingCycle,
Quantity = addOnSubscriptionQuantity,
}
},
};
var newCommerceMigrationOperations = partnerOperations.Customers.ById(customerId).NewCommerceMigrations;
this.Context.ConsoleHelper.StartProgress("Validating New-Commerce migration");
var newCommerceEligibility = newCommerceMigrationOperations.Validate(newCommerceMigration);
this.Context.ConsoleHelper.WriteObject(newCommerceEligibility, "New-Commerce eligibility for the specified subscription");
this.Context.ConsoleHelper.StopProgress();
if (newCommerceEligibility.IsEligible)
{
this.Context.ConsoleHelper.StartProgress("Creating New-Commerce migration");
newCommerceMigration = newCommerceMigrationOperations.Create(newCommerceMigration);
this.Context.ConsoleHelper.WriteObject(newCommerceEligibility, "New-Commerce migration created for the specified subscription");
newCommerceMigration = newCommerceMigrationOperations.ById(newCommerceMigration.Id).Get();
this.Context.ConsoleHelper.WriteObject(newCommerceMigration, "Final New-Commerce migration");
this.Context.ConsoleHelper.StopProgress();
}
else
{
this.Context.ConsoleHelper.Warning("The specified subscription is not eligibile for migrating to New-Commerce.");
}
}
}
}

Просмотреть файл

@ -1,4 +1,4 @@
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// <copyright file="CreateOrder.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
@ -6,8 +6,10 @@
namespace Microsoft.Store.PartnerCenter.Samples.Orders
{
using System;
using System.Collections.Generic;
using Store.PartnerCenter.Models.Orders;
using Microsoft.Store.PartnerCenter.Models.Orders;
using Microsoft.Store.PartnerCenter.Models.Offers;
/// <summary>
/// A scenario that creates a new order for a customer.
@ -32,16 +34,36 @@ namespace Microsoft.Store.PartnerCenter.Samples.Orders
string customerId = this.ObtainCustomerId("Enter the ID of the customer making the purchase");
string offerId = this.ObtainOfferId("Enter the ID of the offer to purchase");
string termDuration = this.Context.ConsoleHelper.ReadOptionalString("Enter a term duration [example: P1Y, P1M] if applicable");
if (string.IsNullOrWhiteSpace(termDuration)) {
termDuration = null;
}
string billingCycleString = this.ObtainBillingCycle("Enter a billing cycle [example: Annual or Monthly]");
var billingCycle = (BillingCycleType)Enum.Parse(typeof(BillingCycleType), billingCycleString);
string quantityString = this.ObtainQuantity();
var quantity = int.Parse(quantityString);
string customTermEndDateString = this.Context.ConsoleHelper.ReadOptionalString("Enter a custom term end date or leave blank to keep default");
DateTime? customTermEndDate = null;
if (!string.IsNullOrWhiteSpace(customTermEndDateString)) {
customTermEndDate = DateTime.Parse(customTermEndDateString);
}
var order = new Order()
{
ReferenceCustomerId = customerId,
BillingCycle = billingCycle,
LineItems = new List<OrderLineItem>()
{
new OrderLineItem()
{
OfferId = offerId,
FriendlyName = "new offer purchase",
Quantity = 5
Quantity = quantity,
TermDuration = termDuration,
CustomTermEndDate = customTermEndDate
}
}
};

Просмотреть файл

@ -1,4 +1,4 @@
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// <copyright file="Program.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
@ -20,8 +20,8 @@ namespace Microsoft.Store.PartnerCenter.Samples
using DevicesDeployment;
using Entitlements;
using IndirectModel;
using Invoice;
using Microsoft.Store.PartnerCenter.Samples.SelfServePolicies;
using Invoice;
using Microsoft.Store.PartnerCenter.Samples.SelfServePolicies;
using Models.Auditing;
using Models.Customers;
using Models.Query;
@ -29,7 +29,7 @@ namespace Microsoft.Store.PartnerCenter.Samples
using Offers;
using Orders;
using Products;
using Profile;
using Profile;
using PromotionEligibilities;
using RateCards;
using RatedUsage;
@ -287,8 +287,8 @@ namespace Microsoft.Store.PartnerCenter.Samples
private static IPartnerScenario GetProductScenarios(IScenarioContext context)
{
var productScenarios = new IPartnerScenario[]
{
new GetProductPromotions(context),
{
new GetProductPromotions(context),
new GetProductPromotion(context),
new GetProducts(context),
new GetProductsByTargetSegment(context),
@ -664,14 +664,14 @@ namespace Microsoft.Store.PartnerCenter.Samples
/// </summary>
/// <param name="context">A scenario context</param>
/// <returns>The post promotion eligibilities scenarios.</returns>
private static IPartnerScenario PostPromotionEligibilitiesScenarios(IScenarioContext context)
{
var postPromotionEligibilitiesScenarios = new IPartnerScenario[]
{
new PostPromotionEligibilities(context)
};
return new AggregatePartnerScenario("Post Promotion Eligibilities Scenarios", postPromotionEligibilitiesScenarios, context);
private static IPartnerScenario PostPromotionEligibilitiesScenarios(IScenarioContext context)
{
var postPromotionEligibilitiesScenarios = new IPartnerScenario[]
{
new PostPromotionEligibilities(context)
};
return new AggregatePartnerScenario("Post Promotion Eligibilities Scenarios", postPromotionEligibilitiesScenarios, context);
}
/// <summary>
@ -684,6 +684,7 @@ namespace Microsoft.Store.PartnerCenter.Samples
var profileScenarios = new IPartnerScenario[]
{
new ValidateAndCreateNewCommerceMigration(context),
new ValidateAndCreateNewCommerceMigrationWithAddOn(context),
};
return new AggregatePartnerScenario("New-Commerce migration samples", profileScenarios, context);

Просмотреть файл

@ -15,6 +15,21 @@
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@ -45,13 +60,13 @@
<Reference Include="Microsoft.Identity.Client, Version=4.31.0.0, Culture=neutral, PublicKeyToken=0a613f4dd989e8ae, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Identity.Client.4.31.0\lib\net461\Microsoft.Identity.Client.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Store.PartnerCenter, Version=3.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="Microsoft.Store.PartnerCenter, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Store.PartnerCenter.3.0.1\lib\netstandard2.0\Microsoft.Store.PartnerCenter.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Store.PartnerCenter.Extensions, Version=3.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="Microsoft.Store.PartnerCenter.Extensions, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Store.PartnerCenter.3.0.1\lib\netstandard2.0\Microsoft.Store.PartnerCenter.Extensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Store.PartnerCenter.Models, Version=3.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="Microsoft.Store.PartnerCenter.Models, Version=3.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Store.PartnerCenter.3.0.1\lib\netstandard2.0\Microsoft.Store.PartnerCenter.Models.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
@ -200,6 +215,7 @@
<Compile Include="Invoice\GetUsageLineItemsForClosePeriodPaging.cs" />
<Compile Include="Invoice\GetUsageLineItemsForOpenPeriodPaging.cs" />
<Compile Include="NewCommerceMigrations\ValidateAndCreateNewCommerceMigration.cs" />
<Compile Include="NewCommerceMigrations\ValidateAndCreateNewCommerceMigrationWithAddOn.cs" />
<Compile Include="Offers\GetCustomerOfferCategories.cs" />
<Compile Include="Offers\GetCustomerOffers.cs" />
<Compile Include="Offers\GetOffer.cs" />
@ -285,6 +301,17 @@
<SubType>Designer</SubType>
</None>
</ItemGroup>
<ItemGroup />
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.6.1">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.6.1 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Просмотреть файл

@ -25,8 +25,8 @@ namespace Microsoft.Store.PartnerCenter.Samples.Subscriptions
protected override void RunScenario()
{
var partnerOperations = this.Context.UserPartnerOperations;
string customerId = this.ObtainCustomerId("Enter the ID of the customer whom to retrieve their Subscriptions");
string subscriptionId = this.ObtainSubscriptionId(customerId, "Enter the ID of the subscription to find transtions for");
string customerId = this.ObtainCustomerId("Enter the ID of the customer whom to retrieve their subscriptions");
string subscriptionId = this.ObtainSubscriptionId(customerId, "Enter the ID of the subscription to find transitions for");
var subscriptionOperations = partnerOperations.Customers.ById(customerId).Subscriptions.ById(subscriptionId);
this.Context.ConsoleHelper.StartProgress("Retrieving customer subscription transitions");

Просмотреть файл

@ -6,7 +6,10 @@
namespace Microsoft.Store.PartnerCenter.Samples.Subscriptions
{
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Store.PartnerCenter.Models.PromotionEligibilities;
using Microsoft.Store.PartnerCenter.Models.Subscriptions;
/// <summary>
@ -89,11 +92,105 @@ namespace Microsoft.Store.PartnerCenter.Samples.Subscriptions
{
targetTransition.BillingCycle = targetBillingCycle;
}
else
{
var sourceSubscription = subscriptionOperations.Get();
targetTransition.BillingCycle = sourceSubscription.BillingCycle.ToString();
}
}
else
{
var sourceSubscription = subscriptionOperations.Get();
targetTransition.TermDuration = sourceSubscription.TermDuration;
targetTransition.BillingCycle = sourceSubscription.BillingCycle.ToString();
}
string updatePromoId = this.Context.ConsoleHelper.ReadOptionalString("Would you like to set target promotion id? [y/n]");
if (string.Equals(updatePromoId, "y", System.StringComparison.OrdinalIgnoreCase))
{
string promotionCountry = this.Context.ConsoleHelper.ReadOptionalString("Enter promotion country, leave blank to default to US");
if (string.IsNullOrWhiteSpace(promotionCountry))
{
promotionCountry = "US";
}
string promotionSegment = this.Context.ConsoleHelper.ReadOptionalString("Enter promotion segment, leave blank to default to Commercial");
if (string.IsNullOrWhiteSpace(promotionSegment))
{
promotionSegment = "Commercial";
}
// Get available promotions
this.Context.ConsoleHelper.StartProgress("Retrieving available promotions");
var availablePromotions = partnerOperations.ProductPromotions.ByCountry(promotionCountry).BySegment(promotionSegment).Get();
this.Context.ConsoleHelper.StopProgress();
var psaArray = targetTransition.ToCatalogItemId.Split(':');
var availablePromotionsByTargetTransition = availablePromotions.Items.FirstOrDefault(
item => item.RequiredProducts.Any(
eligibleItem =>
string.Equals(eligibleItem.ProductId, psaArray[0], StringComparison.InvariantCultureIgnoreCase) &&
string.Equals(eligibleItem.SkuId, psaArray[1], StringComparison.InvariantCultureIgnoreCase) &&
string.Equals(eligibleItem.Term.Duration, targetTransition.TermDuration, StringComparison.InvariantCultureIgnoreCase) &&
string.Equals(eligibleItem.Term.BillingCycle, targetTransition.BillingCycle, StringComparison.InvariantCultureIgnoreCase)));
this.Context.ConsoleHelper.WriteObject(availablePromotionsByTargetTransition, "Available promotion based on target product, term and billing frequency");
// prompt the user to enter the promotion ID of the desired promotion
string targetPromotionId = this.Context.ConsoleHelper.ReadOptionalString("Enter the promotion ID");
if (!string.IsNullOrWhiteSpace(targetPromotionId))
{
targetTransition.PromotionId = targetPromotionId;
Enum.TryParse<Models.PromotionEligibilities.Enums.BillingCycleType>(targetTransition.BillingCycle, true, out var targetBillingCycle);
// Build the promotion elibities request.
var promotionEligibilitiesRequest = new PromotionEligibilitiesRequest()
{
Items = new List<PromotionEligibilitiesRequestItem>()
{
new PromotionEligibilitiesRequestItem()
{
Id = 0,
CatalogItemId = targetTransition.ToCatalogItemId,
TermDuration = targetTransition.TermDuration,
BillingCycle = targetBillingCycle,
Quantity = targetTransition.Quantity,
PromotionId = targetTransition.PromotionId,
},
},
};
this.Context.ConsoleHelper.StartProgress("Retrieving promotion eligibilities");
var promotionEligibilities = partnerOperations.Customers.ById(customerId).PromotionEligibilities.Post(promotionEligibilitiesRequest);
this.Context.ConsoleHelper.StopProgress();
foreach (var eligibility in promotionEligibilities.Items)
{
Console.Out.WriteLine("Eligibility result for CatalogItemId: {0}", eligibility.CatalogItemId);
Console.Out.WriteLine("IsCustomerEligible: {0}", eligibility.Eligibilities.First().IsEligible.ToString());
if (!eligibility.Eligibilities.First().IsEligible)
{
Console.Out.WriteLine("Reasons for ineligibility:");
foreach (var error in eligibility.Eligibilities.First().Errors)
{
Console.Out.WriteLine("Type: {0}", error.Type);
Console.Out.WriteLine("Description: {0}", error.Description);
}
}
}
}
}
}
// the selected transition is eligible, go ahead and perform the transition
this.Context.ConsoleHelper.StartProgress("Transtioning subscription");
this.Context.ConsoleHelper.StartProgress("Transitioning subscription");
var transitionResult = subscriptionOperations.Transitions.Create(targetTransition);
this.Context.ConsoleHelper.StopProgress();

Просмотреть файл

@ -83,10 +83,18 @@ namespace Microsoft.Store.PartnerCenter.Samples.Subscriptions
// prompt the user to enter the term duration for the scheduled change
string changeToTermDuration = this.Context.ConsoleHelper.ReadNonEmptyString("Enter the scheduled change term duration", "Scheduled change term duration can't be empty");
// prompt the user to enter the term duration for the scheduled change
// prompt the user to enter the quantity for the scheduled change
string quantity = this.Context.ConsoleHelper.ReadNonEmptyString("Enter the scheduled change quantity", "Scheduled change term quantity can't be empty");
var changeToQuantity = int.Parse(quantity);
// prompt the user to enter the custom term end date for the scheduled change
string customTermEndDate = this.Context.ConsoleHelper.ReadOptionalString("Enter the scheduled change custom term end date or leave blank to keep the current term end date");
DateTime? changeToCustomTermEndDate = null;
if (!string.IsNullOrWhiteSpace(customTermEndDate)) {
changeToCustomTermEndDate = DateTime.Parse(customTermEndDate);
}
this.Context.ConsoleHelper.StartProgress("Updating subscription scheduled change");
selectedSubscription.ScheduledNextTermInstructions = new ScheduledNextTermInstructions
{
@ -99,6 +107,7 @@ namespace Microsoft.Store.PartnerCenter.Samples.Subscriptions
TermDuration = changeToTermDuration,
},
Quantity = changeToQuantity,
CustomTermEndDate = changeToCustomTermEndDate
};
var updatedSubscription = subscriptionOperations.Patch(selectedSubscription);