diff --git a/src/System Application/App/AppSource Gallery/src/AppSourceProductDetails.Page.al b/src/System Application/App/AppSource Gallery/src/AppSourceProductDetails.Page.al
index a39e4ecdfc..5898be3f86 100644
--- a/src/System Application/App/AppSource Gallery/src/AppSourceProductDetails.Page.al
+++ b/src/System Application/App/AppSource Gallery/src/AppSourceProductDetails.Page.al
@@ -180,9 +180,10 @@ page 2516 "AppSource Product Details"
var
ExtensionManagement: Codeunit "Extension Management";
begin
- if (PlansAreVisible) then
+ if PlansAreVisible then
if not Confirm(PurchaseLicensesElsewhereLbl) then
exit;
+
ExtensionManagement.InstallMarketplaceExtension(AppID);
end;
}
@@ -305,7 +306,7 @@ page 2516 "AppSource Product Details"
PlansOverview := '';
end;
- CurrentRecordCanBeInstalled := (AppID <> '') and (not CurrentRecordCanBeUninstalled) and AppSourceProductManager.CanInstallProductWithPlans(AllPlans);
+ CurrentRecordCanBeInstalled := (AppID <> '') and (not CurrentRecordCanBeUninstalled) and AppSourceProductManager.CanInstallProductWithPlans(UniqueProductID);
end;
local procedure BuildPlanPriceText(Availabilities: JsonArray; var MonthlyPriceText: Text; var YearlyPriceText: Text): Boolean
diff --git a/src/System Application/App/AppSource Gallery/src/AppSourceProductManager.Codeunit.al b/src/System Application/App/AppSource Gallery/src/AppSourceProductManager.Codeunit.al
index 89d7bc58d2..da2b2eda96 100644
--- a/src/System Application/App/AppSource Gallery/src/AppSourceProductManager.Codeunit.al
+++ b/src/System Application/App/AppSource Gallery/src/AppSourceProductManager.Codeunit.al
@@ -28,8 +28,10 @@ codeunit 2515 "AppSource Product Manager"
CatalogProductsUriLbl: Label 'https://catalogapi.azure.com/products', Locked = true;
CatalogApiVersionQueryParamNameLbl: Label 'api-version', Locked = true;
CatalogApiVersionQueryParamValueLbl: Label '2023-05-01-preview', Locked = true;
+ CatalogApiVersionOldQueryParamValueLbl: Label '2018-08-01-beta', Locked = true;
CatalogApiOrderByQueryParamNameLbl: Label '$orderby', Locked = true;
CatalogMarketQueryParamNameLbl: Label 'market', Locked = true;
+ CatalogListMarketNameLbl: label 'all', Locked = true;
CatalogLanguageQueryParamNameLbl: Label 'language', Locked = true;
CatalogApiFilterQueryParamNameLbl: Label '$filter', Locked = true;
CatalogApiSelectQueryParamNameLbl: Label '$select', Locked = true;
@@ -92,54 +94,46 @@ codeunit 2515 "AppSource Product Manager"
///
/// Checks if the product can be installed or your are required to perform operations on AppSource before you can install the product.
///
- /// JSonArray representing the product plans
- /// True if the product can be installed, otherwise false
- internal procedure CanInstallProductWithPlans(Plans: JsonArray): Boolean
+ internal procedure CanInstallProductWithPlans(UniqieProductIDValue: Text): Boolean
var
+ LegacyProductObject: JsonObject;
+ LegacyPlansToken: JsonToken;
+ LegacyPlans: JsonArray;
PlanToken: JsonToken;
PlanObject: JsonObject;
- PricingTypesToken: JsonToken;
- PricingTypes: JsonArray;
- PricingType: JsonToken;
+ CallToActionToken: JsonToken;
begin
- foreach PlanToken in Plans do begin
- PlanObject := PlanToken.AsObject();
+ Init();
- if PlanObject.Get('pricingTypes', PricingTypesToken) then
- if (PricingTypesToken.IsArray()) then begin
- PricingTypes := PricingTypesToken.AsArray();
- if PricingTypes.Count() = 0 then
- exit(false); // No price structure, you need to contact the publisher
-
- foreach PricingType in PricingTypes do
- case LowerCase(PricingType.AsValue().AsText()) of
- 'free', // Free
- 'freetrial', // Free trial
- 'payg', // Pay as you go
- 'byol': // Bring your own license
- exit(true);
- end;
- end;
+ // Query legacy api toget all the plan and test if there is a contact me call to action.
+ LegacyProductObject := GetProductDetails(UniqieProductIDValue, ConstructProductUri(UniqieProductIDValue, CatalogApiVersionOldQueryParamValueLbl));
+ LegacyProductObject.Get('plans', LegacyPlansToken);
+ LegacyPlans := LegacyPlansToken.AsArray();
+ foreach PlanToken in LegacyPlans do begin
+ PlanObject := PlanToken.AsObject();
+ if PlanObject.Get('callToAction', CallToActionToken) then
+ if LowerCase(CallToActionToken.AsValue().AsText()) = 'contactme' then
+ exit(false);
end;
- exit(false);
+ exit(true);
end;
#endregion
#region Market and language helper functions
- procedure GetCurrentLanguageCultureName(): Text
+ local procedure GetCurrentLanguageCultureName(): Text
var
Language: Codeunit Language;
begin
exit(Language.GetCultureName(GetCurrentUserLanguageID()));
end;
- procedure ResolveMarketAndLanguage(var Market: Code[2]; var LanguageName: Text)
+ local procedure ResolveLanguageName() LanguageName: Text;
var
Language: Codeunit Language;
LanguageID: Integer;
begin
- GetCurrentUserLanguageAndLocaleID(LanguageID, Market);
+ LanguageID := GetCurrentUserLanguageAndLocaleID();
// Marketplace API only supports two letter languages.
LanguageName := Language.GetTwoLetterISOLanguageName(LanguageID);
@@ -161,7 +155,7 @@ codeunit 2515 "AppSource Product Manager"
exit(LanguageID);
end;
- local procedure GetCurrentUserLanguageAndLocaleID(var LanguageID: Integer; var LocaleID: Code[2])
+ local procedure GetCurrentUserLanguageAndLocaleID() LanguageID: Integer
var
TempUserSettings: Record "User Settings" temporary;
Language: Codeunit Language;
@@ -172,9 +166,6 @@ codeunit 2515 "AppSource Product Manager"
LanguageID := Language.GetLanguageIdFromCultureName(AppSourceProductManagerDependencies.GetPreferredLanguage());
if (LanguageID = 0) then
LanguageID := 1033; // Default to EN-US
-
- if (AppSourceProductManagerDependencies.IsSaas()) then
- LocaleID := AppSourceProductManagerDependencies.GetCountryLetterCode();
end;
///
@@ -229,14 +220,21 @@ codeunit 2515 "AppSource Product Manager"
///
local procedure GetProductDetails(UniqueProductIDValue: Text): JsonObject
var
- RestClient: Codeunit "Rest Client";
RequestUri: Text;
+ begin
+ Init();
+ RequestUri := ConstructProductUri(UniqueProductIDValue);
+ exit(GetProductDetails(UniqueProductIDValue, RequestUri));
+ end;
+
+ local procedure GetProductDetails(UniqueProductIDValue: Text; RequestUri: Text): JsonObject
+ var
+ RestClient: Codeunit "Rest Client";
ClientRequestID: Guid;
TelemetryDictionary: Dictionary of [Text, Text];
begin
Init();
ClientRequestID := CreateGuid();
- RequestUri := ConstructProductUri(UniqueProductIDValue);
PopulateTelemetryDictionary(ClientRequestID, UniqueProductIDValue, RequestUri, TelemetryDictionary);
Session.LogMessage('AL:AppSource-GetProduct', 'Requesting product details.', Verbosity::Normal, DataClassification::SystemMetadata, TelemetryScope::All, TelemetryDictionary);
@@ -297,13 +295,12 @@ codeunit 2515 "AppSource Product Manager"
UriBuilder: Codeunit "Uri Builder";
Uri: Codeunit Uri;
Language: Text;
- Market: Code[2];
begin
- ResolveMarketAndLanguage(Market, Language);
+ Language := ResolveLanguageName();
UriBuilder.Init(CatalogProductsUriLbl);
UriBuilder.AddQueryParameter(CatalogApiVersionQueryParamNameLbl, CatalogApiVersionQueryParamValueLbl);
- UriBuilder.AddQueryParameter(CatalogMarketQueryParamNameLbl, Market);
+ UriBuilder.AddQueryParameter(CatalogMarketQueryParamNameLbl, CatalogListMarketNameLbl);
UriBuilder.AddQueryParameter(CatalogLanguageQueryParamNameLbl, Language);
UriBuilder.AddODataQueryParameter(CatalogApiFilterQueryParamNameLbl, 'productType eq ''DynamicsBC''');
@@ -315,16 +312,23 @@ codeunit 2515 "AppSource Product Manager"
end;
local procedure ConstructProductUri(UniqueIdentifier: Text): Text
+ begin
+ exit(ConstructProductUri(UniqueIdentifier, CatalogApiVersionQueryParamValueLbl));
+ end;
+
+ local procedure ConstructProductUri(UniqueIdentifier: Text; ApiVersion: Text): Text
var
UriBuilder: Codeunit "Uri Builder";
Uri: Codeunit Uri;
Language: Text;
- Market: Code[2];
+ Market: Text;
begin
- ResolveMarketAndLanguage(Market, Language);
+ // For market in the product details we use the Entra ID country code.
+ Market := AppSourceProductManagerDependencies.GetCountryLetterCode();
+ Language := ResolveLanguageName();
UriBuilder.Init(CatalogProductsUriLbl);
UriBuilder.SetPath('products/' + UniqueIdentifier);
- UriBuilder.AddQueryParameter(CatalogApiVersionQueryParamNameLbl, CatalogApiVersionQueryParamValueLbl);
+ UriBuilder.AddQueryParameter(CatalogApiVersionQueryParamNameLbl, ApiVersion);
UriBuilder.AddQueryParameter(CatalogMarketQueryParamNameLbl, Market);
UriBuilder.AddQueryParameter(CatalogLanguageQueryParamNameLbl, Language);
UriBuilder.GetUri(Uri);
diff --git a/src/System Application/Test Library/AppSource Gallery/src/AppSrcProductMgrTestImpl.Codeunit.al b/src/System Application/Test Library/AppSource Gallery/src/AppSrcProductMgrTestImpl.Codeunit.al
index fe54403190..bfb21d5580 100644
--- a/src/System Application/Test Library/AppSource Gallery/src/AppSrcProductMgrTestImpl.Codeunit.al
+++ b/src/System Application/Test Library/AppSource Gallery/src/AppSrcProductMgrTestImpl.Codeunit.al
@@ -46,11 +46,6 @@ codeunit 132935 "AppSrc Product Mgr. Test Impl."
exit(AppSourceProductManager.ExtractAppIDFromUniqueProductID(UniqueProductIDValue))
end;
- procedure CanInstallProductWithPlans(Plans: JsonArray): Boolean
- begin
- exit(AppSourceProductManager.CanInstallProductWithPlans(Plans));
- end;
-
#region Record handling functions
///
diff --git a/src/System Application/Test/AppSource Gallery/src/AppSourceGalleryTest.Codeunit.al b/src/System Application/Test/AppSource Gallery/src/AppSourceGalleryTest.Codeunit.al
index 0f79dc74d0..b50f0da56c 100644
--- a/src/System Application/Test/AppSource Gallery/src/AppSourceGalleryTest.Codeunit.al
+++ b/src/System Application/Test/AppSource Gallery/src/AppSourceGalleryTest.Codeunit.al
@@ -172,82 +172,6 @@ codeunit 135074 "AppSource Gallery Test"
AppSrcProductMgrTestImpl.ResetDependencies();
end;
- [Test]
- // In AppSource this shows up as having the Buy Now button enabled
- procedure TestCanInstallProduct_BuyNow()
- var
- PlansList: JsonArray;
- CanInstall: Boolean;
- begin
- // Given
- // Hello world sample: PUBID.microsoftdynsmb%7CAID.helloworld%7CPAPPID.8e315acc-413d-46d5-abb9-c16912d3f3e3
- PlansList.ReadFrom('[{"id": "0002","availabilities": [{"id": "DZH318Z0BMGT","actions": ["Browse","Curate","Details","License","Purchase"],"meter": null,"pricingAudience": "DirectCommercial","terms": [{"termDescriptionParameters": null,"termId": "bh3541oe15ry","termUnit": "P1M","prorationPolicy": {"minimumProratedUnits": "P1D"},"termDescription": "1 Month Trial to 1 Year Subscription","price": {"currencyCode": "USD","isPIRequired": true,"listPrice": 0.0,"msrp": 0.0},"renewTermId": "qdp73gtwa5dy","renewTermUnits": "P1Y","isAutorenewable": true},{"termDescriptionParameters": null,"termId": "njspcsugneyy","termUnit": "P1M","prorationPolicy": {"minimumProratedUnits": "P1D"},"termDescription": "1 Month Trial to 1 Month Subscription","price": {"currencyCode": "USD","isPIRequired": true,"listPrice": 0.0,"msrp": 0.0},"renewTermId": "usrac41besqy","renewTermUnits": "P1M","isAutorenewable": true}],"hasFreeTrials": true,"consumptionUnitType": "DAY","displayRank": 0},{"id": "DZH318Z0BMGP","actions": ["Browse","Curate","Details","License","Purchase","Renew"],"meter": null,"pricingAudience": "DirectCommercial","terms": [{"termDescriptionParameters": null,"termId": "qdp73gtwa5dy","termUnit": "P1Y","prorationPolicy": {"minimumProratedUnits": "P1D"},"termDescription": "1 Year Subscription","price": {"currencyCode": "USD","isPIRequired": true,"listPrice": 0.02,"msrp": 0.02},"renewTermId": "qdp73gtwa5dy","renewTermUnits": "P1Y","isAutorenewable": true},{"termDescriptionParameters": null,"termId": "usrac41besqy","termUnit": "P1M","prorationPolicy": {"minimumProratedUnits": "P1D"},"termDescription": "1 Month Subscription","price": {"currencyCode": "USD","isPIRequired": true,"listPrice": 0.01,"msrp": 0.01},"renewTermId": "usrac41besqy","renewTermUnits": "P1M","isAutorenewable": true}],"hasFreeTrials": false,"consumptionUnitType": "DAY","displayRank": 1}],"uiDefinitionUri": "https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RW15J0G","isHidden": false,"isStopSell": false,"cspState": "OptOut","minQuantity": 1,"maxQuantity": 10,"isQuantifiable": true,"purchaseDurationDiscounts": [],"planId": "transactableplan1","uniquePlanId": "microsoftdynsmb.helloworldtransactableplan1","displayName": "First 10 users","metadata": {"generation": null,"altStackReference": null},"categoryIds": [],"pricingTypes": ["FreeTrial","Payg"],"description": "Test plan to test first 10 users configurations","skuId": "0002","planType": "DynamicsBC","displayRank": "2147483647","isPrivate": false},{"id": "0003","availabilities": [{"id": "DZH318Z0BMGW","actions": ["Browse","Curate","Details","License","Purchase","Renew"],"meter": null,"pricingAudience": "DirectCommercial","terms": [{"termDescriptionParameters": null,"termId": "qdp73gtwa5dy","termUnit": "P1Y","prorationPolicy": {"minimumProratedUnits": "P1D"},"termDescription": "1 Year Subscription","price": {"currencyCode": "USD","isPIRequired": true,"listPrice": 0.03,"msrp": 0.03},"renewTermId": "qdp73gtwa5dy","renewTermUnits": "P1Y","isAutorenewable": true},{"termDescriptionParameters": null,"termId": "usrac41besqy","termUnit": "P1M","prorationPolicy": {"minimumProratedUnits": "P1D"},"termDescription": "1 Month Subscription","price": {"currencyCode": "USD","isPIRequired": true,"listPrice": 0.02,"msrp": 0.02},"renewTermId": "usrac41besqy","renewTermUnits": "P1M","isAutorenewable": true}],"hasFreeTrials": false,"consumptionUnitType": "DAY","displayRank": 0}],"uiDefinitionUri": "https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RW15J0H","isHidden": false,"isStopSell": false,"cspState": "OptOut","minQuantity": 10,"maxQuantity": 100,"isQuantifiable": true,"purchaseDurationDiscounts": [],"planId": "transactableplan2","uniquePlanId": "microsoftdynsmb.helloworldtransactableplan2","displayName": "Ten to Hundred plan","metadata": {"generation": null,"altStackReference": null},"categoryIds": [],"pricingTypes": ["Payg"],"description": "Test 10 - 100 User plan","skuId": "0003","planType": "DynamicsBC","displayRank": "2147483647","isPrivate": false}]');
-
- // When
- CanInstall := AppSrcProductMgrTestImpl.CanInstallProductWithPlans(PlansList);
-
- // Then
- LibraryAssert.IsTrue(CanInstall, 'The product should be installable.');
- end;
-
- [Test]
- // In AppSource this shows up as having the Get It Now button enabled
- procedure TestCanInstallProduct_GetItNow()
- var
- PlansList: JsonArray;
- CanInstall: Boolean;
- begin
- // Given
- // Hello world too sample: PUBID.microsoftdynsmb%7CAID.helloworldtoo%7CPAPPID.37447a59-b131-4e9c-83a3-a7856bfc30ff
- PlansList.ReadFrom('[{"id": "0001","availabilities": [{"id": "DZH318Z0BMTW","actions": ["Browse","Curate","Details"],"meter": null,"pricingAudience": "DirectCommercial","terms": null,"hasFreeTrials": false,"displayRank": 0}],"uiDefinitionUri": "https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RE5c9A4","isHidden": false,"isStopSell": false,"isQuantifiable": false,"purchaseDurationDiscounts": [],"planId": "69fe2a5e-cb01-43ea-9af3-2417d0c843f2","uniquePlanId": "microsoftdynsmb.helloworldtoo69fe2a5e-cb01-43ea-9af3-2417d0c843f2","displayName": "HelloWorldToo","metadata": {"generation": null,"altStackReference": null},"categoryIds": [],"pricingTypes": [],"description": "desc
","skuId": "0001","planType": "DynamicsBC","isPrivate": false}]');
-
- // When
- CanInstall := AppSrcProductMgrTestImpl.CanInstallProductWithPlans(PlansList);
-
- // Then
- if (CanInstall) then
- LibraryAssert.Fail('Test now produces expected outcome and should be update.');
- end;
-
-
- [Test]
- // In AppSource this shows up as having the Free Trial button enabled
- procedure TestCanInstallProduct_FreeTrial()
- var
- PlansList: JsonArray;
- CanInstall: Boolean;
- begin
- // Given
- // Manufacturing Central by Intech: PUBID.intechsystems%7CAID.manufacturing_central%7CPAPPID.cea8e27e-050e-4880-840c-954ceb2e3f13
- PlansList.ReadFrom('[{"id": "0001","availabilities": [{"id": "DZH318Z0BMV3","actions": ["Browse","Curate","Details"],"meter": null,"pricingAudience": "DirectCommercial","terms": null,"hasFreeTrials": false,"displayRank": 0}],"uiDefinitionUri": "https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RW1fI7S","isHidden": false,"isStopSell": false,"isQuantifiable": false,"purchaseDurationDiscounts": [],"planId": "77447b7c-9737-4132-8191-b9ce21d35a0e","uniquePlanId": "intechsystems.manufacturing_central77447b7c-9737-4132-8191-b9ce21d35a0e","displayName": "Manufacturing Central","metadata": {"generation": null,"altStackReference": null},"categoryIds": [],"pricingTypes": [],"description": "Hey there
","skuId": "0001","planType": "DynamicsBC","isPrivate": false}]');
-
- // When
- CanInstall := AppSrcProductMgrTestImpl.CanInstallProductWithPlans(PlansList);
-
- // Then
- if (CanInstall) then
- LibraryAssert.Fail('Test now produces expected outcome and should be update.');
- end;
-
- [Test]
-
- // In AppSource this shows up as having the Contact Me button enabled
- procedure TestCanInstallProduct_ContactMe()
- var
- PlansList: JsonArray;
- CanInstall: Boolean;
- begin
- // Given
- // Salesforce Integration by Celigo Inc: PUBID.celigoinc-causa1621285384596%7CAID.salesforce-integration-celigo%7CPAPPID.0595b87b-7670-4bd2-91e2-bd98a7fe2f5a
- PlansList.ReadFrom('[{"id": "0001","availabilities": [{"id": "DZH318Z0BMV7","actions": ["Browse","Curate","Details"],"meter": null,"pricingAudience": "DirectCommercial","terms": null,"hasFreeTrials": false,"displayRank": 0}],"uiDefinitionUri": "https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RE5fzzR","isHidden": false,"isStopSell": false,"isQuantifiable": false,"purchaseDurationDiscounts": [],"planId": "4b4a5c29-40ad-4169-b23c-1ea9a51fd176","uniquePlanId": "celigoinc-causa1621285384596.salesforce-integration-celigo4b4a5c29-40ad-4169-b23c-1ea9a51fd176","displayName": "Salesforce Integration for Dynamics 365 Business Central","metadata": {"generation": null,"altStackReference": null},"categoryIds": [],"pricingTypes": [],"description": "Celigo
","skuId": "0001","planType": "DynamicsBC","isPrivate": false}]');
-
- // When
- CanInstall := AppSrcProductMgrTestImpl.CanInstallProductWithPlans(PlansList);
-
- // Then
- LibraryAssert.IsFalse(CanInstall, 'The product NOT should be installable.');
- end;
-
[HyperlinkHandler]
procedure HyperlinkHandler(Message: Text[1024])
begin