diff --git a/4.0.0.md b/4.0.0.md
index 6bef6b465..fa60da2fc 100644
--- a/4.0.0.md
+++ b/4.0.0.md
@@ -15,3 +15,7 @@ Please check the GitHub release entry [here](https://github.com/OrchardCMS/Orcha
### SKU Generators
Now it's possible to automatically generate the product SKU. Manual entry remains the default for backwards compatibility, but if the SKU doesn't have to be a specific value you can enable the "Orchard Core Commerce - SKU Generator - GUID" feature. This makes the SKU field read-only even during product creation. Instead, when you publish the product a new GUID string is automatically generated and filled as the SKU. You can also implement your own SKU generator by implementing the `ISkuGenerator` service.
+
+### Stripe
+
+The client script in _stripe-payment-form.js_ has changed. Now `stripePaymentForm` accepts an object instead of a lot of individual positional parameters. Additionally, some parameters that are no longer used have been removed. If you have overridden the `CheckoutStripe` shape on your site, make sure to update it based on the one in OCC.
diff --git a/Directory.Packages.props b/Directory.Packages.props
index c4c8c8f41..871f8f321 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -6,28 +6,28 @@
- 3.0.0-preview-18960
+ 3.0.0-preview-18997
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
+
@@ -46,7 +46,7 @@
-
+
diff --git a/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IShoppingCartHelpers.cs b/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IShoppingCartHelpers.cs
index 3c27a69ee..2b58c6ad9 100644
--- a/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IShoppingCartHelpers.cs
+++ b/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IShoppingCartHelpers.cs
@@ -84,7 +84,7 @@ public static Task CreateShoppingCartViewModelAsync(
string shoppingCartId,
IContent order)
{
- var orderPart = order as OrderPart ?? order.As();
+ var orderPart = order as OrderPart ?? order.GetOrCreate();
return service.CreateShoppingCartViewModelAsync(
shoppingCartId,
diff --git a/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IUserService.cs b/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IUserService.cs
index 10235b1fc..820d756f6 100644
--- a/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IUserService.cs
+++ b/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IUserService.cs
@@ -38,9 +38,9 @@ public static Task GetCurrentFullUserAsync(this IUserService service, IHtt
: Task.FromResult(null);
public static TPart GetUserSetting(this IUserService service, User user, string contentType = null)
- where TPart : ContentPart
+ where TPart : ContentPart, new()
{
contentType ??= typeof(TPart).Name.RegexReplace("Part$", string.Empty);
- return service.GetUserSetting(user, contentType)?.As();
+ return service.GetUserSetting(user, contentType)?.GetMaybe();
}
}
diff --git a/src/Modules/OrchardCore.Commerce.Payment.Exactly/Controllers/ExactlyController.cs b/src/Modules/OrchardCore.Commerce.Payment.Exactly/Controllers/ExactlyController.cs
index f11bdc5d7..ff7c3e779 100644
--- a/src/Modules/OrchardCore.Commerce.Payment.Exactly/Controllers/ExactlyController.cs
+++ b/src/Modules/OrchardCore.Commerce.Payment.Exactly/Controllers/ExactlyController.cs
@@ -58,7 +58,7 @@ await this.SafeJsonAsync(async () =>
shoppingCartId,
notifyOnError: false,
throwOnError: true);
- return await _exactlyService.CreateTransactionAsync(order.As());
+ return await _exactlyService.CreateTransactionAsync(order.GetOrCreate());
});
public async Task GetRedirectUrl(string transactionId) =>
@@ -84,7 +84,7 @@ public async Task VerifyApi()
order.DisplayText = S["Exactly API test order"];
await _contentManager.CreateAsync(order);
- var result = await _exactlyService.CreateTransactionAsync(order.As(), testAmount);
+ var result = await _exactlyService.CreateTransactionAsync(order.GetOrCreate(), testAmount);
var action = await GetActionRedirectRequestedAsync(result.Id);
await _notifier.SuccessAsync(
diff --git a/src/Modules/OrchardCore.Commerce.Payment.Exactly/Services/ExactlyPaymentProvider.cs b/src/Modules/OrchardCore.Commerce.Payment.Exactly/Services/ExactlyPaymentProvider.cs
index 6118d4c74..ed539593e 100644
--- a/src/Modules/OrchardCore.Commerce.Payment.Exactly/Services/ExactlyPaymentProvider.cs
+++ b/src/Modules/OrchardCore.Commerce.Payment.Exactly/Services/ExactlyPaymentProvider.cs
@@ -63,8 +63,8 @@ public ExactlyPaymentProvider(
public async Task CreatePaymentProviderDataAsync(IPaymentViewModel model, bool isPaymentRequest = false, string shoppingCartId = null)
{
- var settings = (await _siteService.GetSiteSettingsAsync())?.As();
- return string.IsNullOrEmpty(settings?.ApiKey) || string.IsNullOrEmpty(settings.ProjectId) ? null : new object();
+ var settings = await _siteService.GetSettingsAsync();
+ return string.IsNullOrEmpty(settings.ApiKey) || string.IsNullOrEmpty(settings.ProjectId) ? null : new object();
}
public async Task UpdateAndRedirectToFinishedOrderAsync(
diff --git a/src/Modules/OrchardCore.Commerce.Payment.Exactly/Services/ExactlySettingsConfiguration.cs b/src/Modules/OrchardCore.Commerce.Payment.Exactly/Services/ExactlySettingsConfiguration.cs
index ec197d711..d13a38618 100644
--- a/src/Modules/OrchardCore.Commerce.Payment.Exactly/Services/ExactlySettingsConfiguration.cs
+++ b/src/Modules/OrchardCore.Commerce.Payment.Exactly/Services/ExactlySettingsConfiguration.cs
@@ -10,12 +10,9 @@ public class ExactlySettingsConfiguration : IConfigureOptions
public ExactlySettingsConfiguration(ISiteService siteService) => _siteService = siteService;
- public void Configure(ExactlySettings options)
- {
- var siteSettings = _siteService
+ public void Configure(ExactlySettings options) =>
+ _siteService
.GetSiteSettings()
- .As();
-
- siteSettings.CopyTo(options);
- }
+ .GetOrCreate()
+ .CopyTo(options);
}
diff --git a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Abstractions/IPaymentIntentPersistence.cs b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Abstractions/IPaymentIntentPersistence.cs
index 25bd4517e..061bc2ae4 100644
--- a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Abstractions/IPaymentIntentPersistence.cs
+++ b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Abstractions/IPaymentIntentPersistence.cs
@@ -1,3 +1,5 @@
+#nullable enable
+using OrchardCore.Commerce.Payment.Stripe.Models;
using System.Threading.Tasks;
namespace OrchardCore.Commerce.Payment.Stripe.Abstractions;
@@ -8,17 +10,17 @@ namespace OrchardCore.Commerce.Payment.Stripe.Abstractions;
public interface IPaymentIntentPersistence
{
///
- /// Returns the payment intent Id stored in the current session.
+ /// Returns the payment intent information stored in the current session.
///
- Task RetrieveAsync(string shoppingCartId = null);
+ Task RetrieveAsync(string? shoppingCartId);
///
- /// Saves a payment intent Id to the session.
+ /// Saves a payment intent information to the session.
///
- Task StoreAsync(string paymentIntentId, string shoppingCartId = null);
+ Task StoreAsync(string? shoppingCartId, PaymentIntentPersistenceInfo info);
///
- /// Removes the payment intent Id stored in the current session.
+ /// Removes the payment intent information stored in the current session.
///
- Task RemoveAsync(string shoppingCartId = null);
+ Task RemoveAsync(string? shoppingCartId);
}
diff --git a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Controllers/StripeController.cs b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Controllers/StripeController.cs
index 5f428fab3..77fb1184e 100644
--- a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Controllers/StripeController.cs
+++ b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Controllers/StripeController.cs
@@ -13,25 +13,14 @@ namespace OrchardCore.Commerce.Payment.Stripe.Controllers;
public class StripeController : PaymentBaseController
{
- private readonly IPaymentIntentPersistence _paymentIntentPersistence;
private readonly IStripePaymentService _stripePaymentService;
public StripeController(
IOrchardServices services,
INotifier notifier,
- IPaymentIntentPersistence paymentIntentPersistence,
IStripePaymentService stripePaymentService)
- : base(notifier, services.Logger.Value)
- {
- _paymentIntentPersistence = paymentIntentPersistence;
+ : base(notifier, services.Logger.Value) =>
_stripePaymentService = stripePaymentService;
- }
-
- public async Task UpdatePaymentIntent(string paymentIntent)
- {
- await _paymentIntentPersistence.StoreAsync(paymentIntent);
- return Ok();
- }
[AllowAnonymous]
[HttpGet("stripe/middleware")]
diff --git a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Controllers/WebhookController.cs b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Controllers/WebhookController.cs
index 2cedf80f2..481f918c2 100644
--- a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Controllers/WebhookController.cs
+++ b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Controllers/WebhookController.cs
@@ -44,7 +44,7 @@ public async Task Index([FromHeader(Name = "Stripe-Signature")] s
var json = await streamReader.ReadToEndAsync(HttpContext.RequestAborted);
try
{
- var stripeApiSettings = (await _siteService.GetSiteSettingsAsync()).As();
+ var stripeApiSettings = (await _siteService.GetSiteSettingsAsync()).GetOrCreate();
var webhookSigningKey = stripeApiSettings.DecryptWebhookSigningSecret(_dataProtectionProvider, _logger);
var stripeEvent = _stripeHelperService.PrepareStripeEvent(
diff --git a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Models/PaymentIntentPersistenceInfo.cs b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Models/PaymentIntentPersistenceInfo.cs
new file mode 100644
index 000000000..aec28f457
--- /dev/null
+++ b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Models/PaymentIntentPersistenceInfo.cs
@@ -0,0 +1,5 @@
+using OrchardCore.Commerce.MoneyDataType;
+
+namespace OrchardCore.Commerce.Payment.Stripe.Models;
+
+public record PaymentIntentPersistenceInfo(string PaymentIntentId, Amount Amount);
diff --git a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/PaymentIntentPersistence.cs b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/PaymentIntentPersistence.cs
index f484dd1d5..ee1d3e521 100644
--- a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/PaymentIntentPersistence.cs
+++ b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/PaymentIntentPersistence.cs
@@ -1,5 +1,9 @@
+#nullable enable
+
using Microsoft.AspNetCore.Http;
using OrchardCore.Commerce.Payment.Stripe.Abstractions;
+using OrchardCore.Commerce.Payment.Stripe.Models;
+using System.Text.Json;
using System.Threading.Tasks;
namespace OrchardCore.Commerce.Payment.Stripe.Services;
@@ -7,46 +11,71 @@ namespace OrchardCore.Commerce.Payment.Stripe.Services;
public class PaymentIntentPersistence : IPaymentIntentPersistence
{
// Using _ as a separator to avoid separator character conflicts.
- private const string PaymentIntentKeyPrefix = "OrchardCore_Commerce_PaymentIntent";
+ private const string PaymentIntentKeyPrefix = "OrchardCore_Commerce_" + nameof(PaymentIntentPersistenceInfo);
private readonly IHttpContextAccessor _httpContextAccessor;
- private ISession Session => _httpContextAccessor.HttpContext?.Session;
+
+ private ISession? Session => _httpContextAccessor.HttpContext?.Session;
+ private HttpRequest? Request => _httpContextAccessor.HttpContext?.Request;
public PaymentIntentPersistence(IHttpContextAccessor httpContextAccessor) => _httpContextAccessor = httpContextAccessor;
- public Task RetrieveAsync(string shoppingCartId = null)
+ public Task RetrieveAsync(string? shoppingCartId)
{
var key = GetCacheId(shoppingCartId);
- var serialized = Session.GetString(key);
- if (serialized == null && _httpContextAccessor.HttpContext != null)
+
+ if (Session?.GetString(key)?.Trim() is { Length: > 0 } serializedFromSession &&
+ TryParse(serializedFromSession, out var sessionResult))
{
- _httpContextAccessor.HttpContext.Request.Cookies.TryGetValue(key, out var serializedCart);
- return Task.FromResult(serializedCart);
+ return Task.FromResult(sessionResult);
}
- return Task.FromResult(serialized);
+ if (Request != null &&
+ Request.Cookies.TryGetValue(key, out var serializedFromCookie) &&
+ TryParse(serializedFromCookie, out var cookieResult))
+ {
+ return Task.FromResult(cookieResult);
+ }
+
+ return Task.FromResult(null);
}
- public Task StoreAsync(string paymentIntentId, string shoppingCartId = null)
+ public Task StoreAsync(string? shoppingCartId, PaymentIntentPersistenceInfo info)
{
var key = GetCacheId(shoppingCartId);
- if (Session.GetString(key) == paymentIntentId) return Task.CompletedTask;
+ var serialized = JsonSerializer.Serialize(info);
- Session.SetString(key, paymentIntentId);
- _httpContextAccessor.SetCookieForever(key, paymentIntentId);
+ Session?.SetString(key, serialized);
+ _httpContextAccessor.SetCookieForever(key, serialized);
return Task.CompletedTask;
}
- public Task RemoveAsync(string shoppingCartId = null)
+ public Task RemoveAsync(string? shoppingCartId)
{
var key = GetCacheId(shoppingCartId);
- Session.Remove(key);
+ Session?.Remove(key);
_httpContextAccessor.HttpContext?.Response.Cookies.Delete(key);
return Task.CompletedTask;
}
- protected string GetCacheId(string shoppingCartId) =>
+ protected string GetCacheId(string? shoppingCartId) =>
string.IsNullOrEmpty(shoppingCartId) ? PaymentIntentKeyPrefix : $"{PaymentIntentKeyPrefix}_{shoppingCartId}";
+
+ private static bool TryParse(string serialized, out PaymentIntentPersistenceInfo? result)
+ {
+ result = null;
+ if (string.IsNullOrWhiteSpace(serialized)) return false;
+
+ try
+ {
+ result = JsonSerializer.Deserialize(serialized);
+ return !string.IsNullOrWhiteSpace(result?.PaymentIntentId);
+ }
+ catch
+ {
+ return false;
+ }
+ }
}
diff --git a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/RequestOptionsService.cs b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/RequestOptionsService.cs
index e5edf551d..58b5af660 100644
--- a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/RequestOptionsService.cs
+++ b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/RequestOptionsService.cs
@@ -27,7 +27,7 @@ ILogger logger
_apiKeyAccessor = siteSettings =>
siteSettings
- .As()
+ .GetOrCreate()
.SecretKey
.DecryptStripeApiKey(dataProtectionProvider, logger);
}
@@ -41,9 +41,9 @@ public async Task SetIdempotencyKeyAsync()
var requestOptions = await GetOrCreateRequestOptionsAsync();
requestOptions.IdempotencyKey = Guid.NewGuid().ToString();
- if (siteSettings.As().AccountId != null)
+ if (siteSettings.GetOrCreate().AccountId != null)
{
- requestOptions.StripeAccount = siteSettings.As().AccountId;
+ requestOptions.StripeAccount = siteSettings.GetOrCreate().AccountId;
}
return requestOptions;
@@ -53,7 +53,7 @@ private async Task CreateRequestOptionsAsync()
{
var siteSettings = await _siteService.GetSiteSettingsAsync();
var apiKey = _apiKeyAccessor(siteSettings);
- var accountId = siteSettings.As().AccountId;
+ var accountId = siteSettings.GetOrCreate().AccountId;
_requestOptions =
accountId != null
diff --git a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/StripeApiSettingsConfiguration.cs b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/StripeApiSettingsConfiguration.cs
index 2ac50f0bc..b002d80cd 100644
--- a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/StripeApiSettingsConfiguration.cs
+++ b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/StripeApiSettingsConfiguration.cs
@@ -26,7 +26,7 @@ public void Configure(StripeApiSettings options)
{
var settings = _siteService
.GetSiteSettings()
- .As();
+ .GetOrCreate();
options.PublishableKey = settings.PublishableKey;
diff --git a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/StripePaymentIntentService.cs b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/StripePaymentIntentService.cs
index 4f7ebe94d..4bdaa988f 100644
--- a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/StripePaymentIntentService.cs
+++ b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/StripePaymentIntentService.cs
@@ -7,7 +7,9 @@
using OrchardCore.Commerce.Payment.Stripe.Helpers;
using OrchardCore.Settings;
using Stripe;
+using System.Threading;
using System.Threading.Tasks;
+using static OrchardCore.Commerce.Payment.Stripe.Constants.PaymentIntentStatuses;
namespace OrchardCore.Commerce.Payment.Stripe.Services;
@@ -20,6 +22,8 @@ public class StripePaymentIntentService : IStripePaymentIntentService
private readonly IPaymentIntentPersistence _paymentIntentPersistence;
private readonly IStringLocalizer T;
+ private CancellationToken Aborted => _hca.HttpContext?.RequestAborted ?? default;
+
public StripePaymentIntentService(
PaymentIntentService paymentIntentService,
IHttpContextAccessor httpContextAccessor,
@@ -44,11 +48,19 @@ public async Task GetPaymentIntentAsync(string paymentIntentId)
paymentIntentId,
paymentIntentGetOptions,
await _requestOptionsService.SetIdempotencyKeyAsync(),
- _hca.HttpContext.RequestAborted);
+ Aborted);
}
public async Task CreatePaymentIntentAsync(Amount total, string shoppingCartId = null)
{
+ var paymentIntentInfo = await _paymentIntentPersistence.RetrieveAsync(shoppingCartId);
+ if (paymentIntentInfo?.Amount == total &&
+ await GetPaymentIntentAsync(paymentIntentInfo.PaymentIntentId) is { Status: RequiresPaymentMethod } storedPaymentIntent &&
+ storedPaymentIntent.Amount == AmountHelpers.GetPaymentAmount(total))
+ {
+ return storedPaymentIntent;
+ }
+
var siteSettings = await _siteService.GetSiteSettingsAsync();
var paymentIntentOptions = new PaymentIntentCreateOptions
{
@@ -59,8 +71,7 @@ public async Task CreatePaymentIntentAsync(Amount total, string s
};
var paymentIntent = await CreatePaymentIntentAsync(paymentIntentOptions);
-
- await _paymentIntentPersistence.StoreAsync(paymentIntent.Id, shoppingCartId);
+ await _paymentIntentPersistence.StoreAsync(shoppingCartId, new(paymentIntent.Id, total));
return paymentIntent;
}
@@ -69,7 +80,7 @@ public async Task CreatePaymentIntentAsync(PaymentIntentCreateOpt
await _paymentIntentService.CreateAsync(
options,
await _requestOptionsService.SetIdempotencyKeyAsync(),
- _hca.HttpContext.RequestAborted);
+ Aborted);
public async Task GetOrUpdatePaymentIntentAsync(
string paymentIntentId,
@@ -93,6 +104,6 @@ public async Task GetOrUpdatePaymentIntentAsync(
paymentIntentId,
updateOptions,
await _requestOptionsService.SetIdempotencyKeyAsync(),
- _hca.HttpContext.RequestAborted);
+ Aborted);
}
}
diff --git a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/StripePaymentProvider.cs b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/StripePaymentProvider.cs
index d3ad54dd4..9d0431261 100644
--- a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/StripePaymentProvider.cs
+++ b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/StripePaymentProvider.cs
@@ -61,7 +61,7 @@ await _session.SaveAsync(new OrderPayment
});
}
- var stripeApiSettings = (await _siteService.GetSiteSettingsAsync()).As();
+ var stripeApiSettings = (await _siteService.GetSiteSettingsAsync()).GetOrCreate();
return new StripePaymentProviderData
{
diff --git a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/StripePaymentService.cs b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/StripePaymentService.cs
index 1343d03db..6c6905b1e 100644
--- a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/StripePaymentService.cs
+++ b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Services/StripePaymentService.cs
@@ -66,13 +66,13 @@ public StripePaymentService(
public async Task GetPublicKeyAsync()
{
- var stripeApiSettings = (await _siteService.GetSiteSettingsAsync()).As();
+ var stripeApiSettings = (await _siteService.GetSiteSettingsAsync()).GetOrCreate();
return stripeApiSettings.PublishableKey;
}
public async Task CreateClientSecretAsync(Amount total, ShoppingCartViewModel cart)
{
- var stripeApiSettings = (await _siteService.GetSiteSettingsAsync()).As();
+ var stripeApiSettings = (await _siteService.GetSiteSettingsAsync()).GetOrCreate();
if (string.IsNullOrEmpty(stripeApiSettings.PublishableKey) ||
string.IsNullOrEmpty(stripeApiSettings.SecretKey) ||
@@ -81,7 +81,7 @@ public async Task CreateClientSecretAsync(Amount total, ShoppingCartView
return null;
}
- var paymentIntentId = await _paymentIntentPersistence.RetrieveAsync(cart.Id);
+ var paymentIntentId = (await _paymentIntentPersistence.RetrieveAsync(cart.Id))?.PaymentIntentId;
var totals = cart.GetTotalsOrThrowIfEmpty();
// Same here as on the checkout page: Later we have to figure out what to do if there are multiple
@@ -157,7 +157,7 @@ public async Task CreateOrUpdateOrderFromShoppingCartAsync(
string paymentIntentId = null,
OrderPart orderPart = null)
{
- var innerPaymentIntentId = paymentIntentId ?? await _paymentIntentPersistence.RetrieveAsync(shoppingCartId);
+ var innerPaymentIntentId = paymentIntentId ?? (await _paymentIntentPersistence.RetrieveAsync(shoppingCartId))?.PaymentIntentId;
var paymentIntent = await _stripePaymentIntentService.GetPaymentIntentAsync(innerPaymentIntentId);
// Stripe doesn't support multiple shopping cart IDs because we can't send that info to the middleware anyway.
@@ -194,7 +194,7 @@ public async Task CreateOrUpdateOrderFromShoppingCartAsync(
},
orderPart);
- if (!order.As().LineItems.Any() && updateModelAccessor != null)
+ if (!order.GetOrCreate().LineItems.Any() && updateModelAccessor != null)
{
updateModelAccessor.ModelUpdater.ModelState.AddModelError(
nameof(OrderPart.LineItems),
@@ -215,12 +215,12 @@ public async Task PaymentConfirmationAsync(
bool needToJudgeIntentStorage = true)
{
// If it is null it means the session was not loaded yet and a redirect is needed.
- if (needToJudgeIntentStorage && string.IsNullOrEmpty(await _paymentIntentPersistence.RetrieveAsync(shoppingCartId)))
+ if (needToJudgeIntentStorage && string.IsNullOrEmpty((await _paymentIntentPersistence.RetrieveAsync(shoppingCartId))?.PaymentIntentId))
{
return new PaymentOperationStatusViewModel
{
Status = PaymentOperationStatus.WaitingForRedirect,
- Url = _hca.HttpContext.Request.GetDisplayUrl(),
+ Url = _hca.HttpContext?.Request.GetDisplayUrl(),
};
}
@@ -239,7 +239,7 @@ await _contentManager.GetAsync(orderId) is not { } order)
};
}
- var part = order.As() ?? new OrderPart();
+ var part = order.GetOrCreate();
var succeeded = fetchedPaymentIntent.Status == PaymentIntentStatuses.Succeeded;
// Looks like there is nothing to do here.
@@ -277,12 +277,12 @@ await _contentManager.GetAsync(orderId) is not { } order)
});
await _contentManager.UpdateAsync(order);
- if (order.As().RetryCounter <= 10)
+ if (order.GetOrCreate().RetryCounter <= 10)
{
return new PaymentOperationStatusViewModel
{
Status = PaymentOperationStatus.WaitingForRedirect,
- Url = _hca.HttpContext.Request.GetDisplayUrl(),
+ Url = _hca.HttpContext?.Request.GetDisplayUrl(),
};
}
@@ -305,7 +305,7 @@ public async Task GetStripeConfirmParametersAsync(
await _paymentService.UpdateOrderWithDriversAsync(order);
}
- var part = order.As();
+ var part = order.GetOrCreate();
var billing = part.BillingAddress.Address ?? new Address();
var shipping = part.ShippingAddress.Address ?? new Address();
diff --git a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Views/CheckoutStripe.cshtml b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Views/CheckoutStripe.cshtml
index 32b1c19db..c1803433d 100644
--- a/src/Modules/OrchardCore.Commerce.Payment.Stripe/Views/CheckoutStripe.cshtml
+++ b/src/Modules/OrchardCore.Commerce.Payment.Stripe/Views/CheckoutStripe.cshtml
@@ -13,6 +13,17 @@
string clientSecret = Model.PaymentProviderData?.ClientSecret ?? string.Empty;
string paymentIntentId = Model.PaymentProviderData?.PaymentIntentId ?? string.Empty;
string accountId = Model.PaymentProviderData?.AccountId?.Trim();
+
+ var urlPrefix = Url.Content("~/").TrimEnd('/');
+ var missingText = T["A value is required for %LABEL%."].Value;
+ var stripeData = new
+ {
+ clientSecret,
+ paymentIntentId,
+ urlPrefix,
+ publishableKey,
+ missingText,
+ };
}
@@ -45,24 +56,8 @@
}
diff --git a/src/Modules/OrchardCore.Commerce.Payment.Stripe/wwwroot/js/stripe-payment-form.js b/src/Modules/OrchardCore.Commerce.Payment.Stripe/wwwroot/js/stripe-payment-form.js
index c254b9fdf..d2c88a0fc 100644
--- a/src/Modules/OrchardCore.Commerce.Payment.Stripe/wwwroot/js/stripe-payment-form.js
+++ b/src/Modules/OrchardCore.Commerce.Payment.Stripe/wwwroot/js/stripe-payment-form.js
@@ -1,164 +1,173 @@
-window.stripePaymentForm = function stripePaymentForm(
- stripe,
- clientSecret,
- paymentIntentId,
- antiForgeryToken,
- urlPrefix,
- errorText,
- missingText,
- updatePaymentIntentUrl,
- validateUrl = 'checkout/validate/stripe',
- paramsUrl = 'stripe/params',
- priceUrl = 'checkout/price',
- errorContainerSelector = '.message-error',
- stripeFieldErrorSelector = '.stripe-field-error',
- paymentFormSelector = '.payment-form',
- payButtonSelector = '.pay-button-stripe',
- payTextSelector = '.pay-text',
- paymentProcessingContainerSelector = '.payment-processing-container',
- placeOfPaymentSelector = '#payment-form_payment',
- payButtonValueSelector = '.pay-button-value',
- addressesSelector = '*[id^="OrderPart_ShippingAddress_"], *[id^="OrderPart_BillingAddress_"]',
- addressSelector = '.address',
- addressTitleSelector = '.address__title'
-) {
- const allErrorContainers = [document.querySelector(errorContainerSelector)];
- const form = document.querySelector(paymentFormSelector);
- const submitButton = form.querySelector(payButtonSelector);
- const payText = submitButton.querySelector(payTextSelector);
- const paymentProcessingContainer = submitButton.querySelector(paymentProcessingContainerSelector);
- const stripeElements = stripe.elements({ clientSecret });
- const payment = stripeElements.create('payment', { fields: { billingDetails: 'never' } });
- const placeOfPayment = document.querySelector(placeOfPaymentSelector);
-
- let formElements = Array.from(form.elements);
-
- function toggleInputs(enable) {
- formElements.forEach((element) => {
- element.readOnly = !enable;
- });
-
- payment.update({ readOnly: !enable });
- submitButton.disabled = !enable;
- paymentProcessingContainer.hidden = enable;
- payText.hidden = !enable;
+(function setupStripePaymentForm(Stripe) {
+ function toString(data, key, defaultValue) {
+ if (!data[key]) return defaultValue;
+ const value = `${data[key]}`.trim();
+ return value.length > 0 ? value : defaultValue;
}
- function displayError(errors, container = allErrorContainers[0]) {
- allErrorContainers.forEach((element) => { element.hidden = true; });
- if (!errors || errors.length === 0) return;
-
- const err = Array.isArray(errors) ? errors.filter((error) => error) : [errors];
-
- container.innerHTML = '';
- const ul = container.querySelector('ul');
- err.forEach((error) => {
- const li = document.createElement('li');
- li.textContent = error.message || error;
- ul.appendChild(li);
- });
-
- toggleInputs(true);
- container.hidden = false;
- container.scrollIntoView({ block: 'center' });
- }
-
- function fetchPost(path) {
- return fetch(`${urlPrefix}/${path}`, { method: 'POST', body: new FormData(form) })
- .then((response) => response.json());
- }
-
- function getText(element) {
- return element?.textContent.trim();
- }
-
- function registerElements() {
- // Displaying payment input error.
- const stripeFieldError = document.querySelector(stripeFieldErrorSelector);
- allErrorContainers.push(stripeFieldError);
- payment.on('change', (event) => {
- displayError(event?.error, stripeFieldError);
- });
-
- submitButton.addEventListener('click', async (event) => {
- // We don't want to let default form submission happen here, which would refresh the page.
- event.preventDefault();
- toggleInputs(false);
-
- let result;
- try {
- const emptyRequiredFields = Array.from(form.querySelectorAll('input'))
- .filter((element) => element.required && !element.hidden)
- .filter((element) => !element.value?.match(/\S+/));
-
- if (emptyRequiredFields.length) {
- toggleInputs(true);
- throw emptyRequiredFields
- .map((element) => document.querySelector(`label[for="${element.id}"]`))
- .filter(getText)
- .filter((label) => !label.closest(addressSelector)?.hidden)
- .map((label) => {
- const title = getText(label.closest(addressSelector)?.querySelector(addressTitleSelector));
- const name = title ? `${title} ${getText(label)}` : getText(label);
- return missingText.replace('%LABEL%', name);
- });
+ function stripePaymentForm(data) {
+ const stripe = Stripe(data.publishableKey, data.stripeAccountId);
+ const validateUrl = toString(data, 'validateUrl', 'checkout/validate/stripe');
+ const paramsUrl = toString(data, 'paramsUrl', 'stripe/params');
+ const priceUrl = toString(data, 'priceUrl', 'checkout/price');
+ const errorContainerSelector = toString(data, 'errorContainerSelector', '.message-error');
+ const stripeFieldErrorSelector = toString(data, 'stripeFieldErrorSelector', '.stripe-field-error');
+ const paymentFormSelector = toString(data, 'paymentFormSelector', '.payment-form');
+ const payButtonSelector = toString(data, 'payButtonSelector', '.pay-button-stripe');
+ const payTextSelector = toString(data, 'payTextSelector', '.pay-text');
+ const paymentProcessingContainerSelector = toString(
+ data,
+ 'paymentProcessingContainerSelector',
+ '.payment-processing-container');
+ const placeOfPaymentSelector = toString(data, 'placeOfPaymentSelector', '#payment-form_payment');
+ const payButtonValueSelector = toString(data, 'payButtonValueSelector', '.pay-button-value');
+ const addressesSelector = toString(
+ data,
+ 'addressesSelector',
+ '*[id^="OrderPart_ShippingAddress_"], *[id^="OrderPart_BillingAddress_"]');
+ const addressSelector = toString(data, 'addressSelector', '.address');
+ const addressTitleSelector = toString(data, 'addressTitleSelector', '.address__title');
+
+ const allErrorContainers = [document.querySelector(errorContainerSelector)];
+ const form = document.querySelector(paymentFormSelector);
+ const submitButton = form.querySelector(payButtonSelector);
+ const payText = submitButton.querySelector(payTextSelector);
+ const paymentProcessingContainer = submitButton.querySelector(paymentProcessingContainerSelector);
+ const stripeElements = stripe.elements({ clientSecret: data.clientSecret });
+ const payment = stripeElements.create('payment', { fields: { billingDetails: 'never' } });
+ const placeOfPayment = document.querySelector(placeOfPaymentSelector);
+
+ let formElements = Array.from(form.elements);
+
+ function toggleInputs(enable) {
+ formElements.forEach((element) => {
+ element.readOnly = !enable;
+ });
+
+ payment.update({ readOnly: !enable });
+ submitButton.disabled = !enable;
+ paymentProcessingContainer.hidden = enable;
+ payText.hidden = !enable;
+ }
+
+ function displayError(errors, container = allErrorContainers[0]) {
+ allErrorContainers.forEach((element) => { element.hidden = true; });
+ if (!errors || errors.length === 0) return;
+
+ const err = Array.isArray(errors) ? errors.filter((error) => error) : [errors];
+
+ container.innerHTML = '';
+ const ul = container.querySelector('ul');
+ err.forEach((error) => {
+ const li = document.createElement('li');
+ li.textContent = error.message || error;
+ ul.appendChild(li);
+ });
+
+ toggleInputs(true);
+ container.hidden = false;
+ container.scrollIntoView({ block: 'center' });
+ }
+
+ function fetchPost(path) {
+ return fetch(`${data.urlPrefix}/${path}`, { method: 'POST', body: new FormData(form) })
+ .then((response) => response.json());
+ }
+
+ function getText(element) {
+ return element?.textContent.trim();
+ }
+
+ function registerElements() {
+ // Displaying payment input error.
+ const stripeFieldError = document.querySelector(stripeFieldErrorSelector);
+ allErrorContainers.push(stripeFieldError);
+ payment.on('change', (event) => {
+ displayError(event?.error, stripeFieldError);
+ });
+
+ submitButton.addEventListener('click', async (event) => {
+ // We don't want to let default form submission happen here, which would refresh the page.
+ event.preventDefault();
+ toggleInputs(false);
+
+ let result;
+ try {
+ const emptyRequiredFields = Array.from(form.querySelectorAll('input'))
+ .filter((element) => element.required && !element.hidden)
+ .filter((element) => !element.value?.match(/\S+/));
+
+ if (emptyRequiredFields.length) {
+ toggleInputs(true);
+ throw emptyRequiredFields
+ .map((element) => document.querySelector(`label[for="${element.id}"]`))
+ .filter(getText)
+ .filter((label) => !label.closest(addressSelector)?.hidden)
+ .map((label) => {
+ const title = getText(label.closest(addressSelector)?.querySelector(addressTitleSelector));
+ const name = title ? `${title} ${getText(label)}` : getText(label);
+ return data.missingText.replace('%LABEL%', name);
+ });
+ }
+
+ const validationJson = await fetchPost(`${validateUrl}/${data.paymentIntentId}`);
+ if (validationJson?.errors?.length) {
+ toggleInputs(true);
+ throw validationJson.errors;
+ }
+
+ const confirmPaymentOptions = {
+ elements: stripeElements,
+ confirmParams: await fetchPost(paramsUrl),
+ };
+ result = await stripe.confirmPayment(confirmPaymentOptions);
+
+ displayError(result.error);
}
-
- const validationJson = await fetchPost(`${validateUrl}/${paymentIntentId}`);
- if (validationJson?.errors?.length) {
- toggleInputs(true);
- throw validationJson.errors;
+ catch (error) {
+ result = { error };
+ displayError(result.error);
}
-
- const confirmPaymentOptions = {
- elements: stripeElements,
- confirmParams: await fetchPost(paramsUrl),
- };
- result = await stripe.confirmPayment(confirmPaymentOptions);
-
- displayError(result.error);
- }
- catch (error) {
- result = { error };
- displayError(result.error);
- }
- });
- }
-
- function registerPriceUpdater() {
- let debounce = false;
- Array.from(document.querySelectorAll(addressesSelector))
- .forEach((element) => element.addEventListener('change', () => {
- if (debounce) return;
-
- const payButtonValue = document.querySelector(payButtonValueSelector);
- if (!payButtonValue) return;
-
- debounce = true;
- submitButton.disabled = true;
-
- setTimeout(async () => {
- const priceJson = await fetchPost(priceUrl);
- debounce = false;
- submitButton.disabled = false;
-
- // This is not essential if it fails so we intentionally don't catch it. This way if there is an error it can still be seen in the
- // browser log during development or UI testing.
- if ('error' in priceJson) throw priceJson;
-
- payButtonValue.setAttribute('data-value', priceJson.value);
- payButtonValue.setAttribute('data-currency', priceJson.currency);
- payButtonValue.textContent = priceJson.text;
- }, 50); // Prevent multiple requests when several fields are updated at once.
- }));
+ });
+ }
+
+ function registerPriceUpdater() {
+ let debounce = false;
+ Array.from(document.querySelectorAll(addressesSelector))
+ .forEach((element) => element.addEventListener('change', () => {
+ if (debounce) return;
+
+ const payButtonValue = document.querySelector(payButtonValueSelector);
+ if (!payButtonValue) return;
+
+ debounce = true;
+ submitButton.disabled = true;
+
+ setTimeout(async () => {
+ const priceJson = await fetchPost(priceUrl);
+ debounce = false;
+ submitButton.disabled = false;
+
+ // This is not essential if it fails so we intentionally don't catch it. This way if there is an
+ // error it can still be seen in the browser log during development or UI testing.
+ if ('error' in priceJson) throw priceJson;
+
+ payButtonValue.setAttribute('data-value', priceJson.value);
+ payButtonValue.setAttribute('data-currency', priceJson.currency);
+ payButtonValue.textContent = priceJson.text;
+ }, 50); // Prevent multiple requests when several fields are updated at once.
+ }));
+ }
+
+ if (placeOfPayment) {
+ payment.mount(placeOfPayment);
+
+ // Refreshing form elements with the payment input.
+ formElements = Array.from(form.elements);
+ registerElements();
+ registerPriceUpdater();
+ }
}
- if (placeOfPayment) {
- payment.mount(placeOfPayment);
-
- // Refreshing form elements with the payment input.
- formElements = Array.from(form.elements);
- registerElements();
- registerPriceUpdater();
- }
-};
+ window.stripePaymentForm = stripePaymentForm;
+})(window.Stripe);
diff --git a/src/Modules/OrchardCore.Commerce.Payment/Controllers/PaymentController.cs b/src/Modules/OrchardCore.Commerce.Payment/Controllers/PaymentController.cs
index 2c79b35ab..93a3679ca 100644
--- a/src/Modules/OrchardCore.Commerce.Payment/Controllers/PaymentController.cs
+++ b/src/Modules/OrchardCore.Commerce.Payment/Controllers/PaymentController.cs
@@ -102,8 +102,7 @@ public async Task Validate(string providerName, string paymentId,
[HttpGet("checkout/paymentrequest/{orderId}")]
public async Task PaymentRequest(string orderId)
{
- if (await _contentManager.GetAsync(orderId) is not { } order ||
- order.As() is not { } orderPart)
+ if (await _contentManager.GetAsync(orderId) is not { } order || !order.TryGet(out var orderPart))
{
return NotFound();
}
diff --git a/src/Modules/OrchardCore.Commerce.Payment/Endpoints/Api/PaymentEndpoint.cs b/src/Modules/OrchardCore.Commerce.Payment/Endpoints/Api/PaymentEndpoint.cs
index af9df08ce..6c4f10903 100644
--- a/src/Modules/OrchardCore.Commerce.Payment/Endpoints/Api/PaymentEndpoint.cs
+++ b/src/Modules/OrchardCore.Commerce.Payment/Endpoints/Api/PaymentEndpoint.cs
@@ -100,8 +100,7 @@ private static async Task PaymentRequestAsync(
return httpContext.ChallengeOrForbidApi();
}
- if (await contentManager.GetAsync(orderId) is not { } order ||
- order.As() is not { } orderPart)
+ if (await contentManager.GetAsync(orderId) is not { } order || !order.TryGet(out var orderPart))
{
return TypedResults.BadRequest();
}
diff --git a/src/Modules/OrchardCore.Commerce.Payment/Services/CheckoutAddressService.cs b/src/Modules/OrchardCore.Commerce.Payment/Services/CheckoutAddressService.cs
index 202719f98..dd7842908 100644
--- a/src/Modules/OrchardCore.Commerce.Payment/Services/CheckoutAddressService.cs
+++ b/src/Modules/OrchardCore.Commerce.Payment/Services/CheckoutAddressService.cs
@@ -11,11 +11,8 @@ public class CheckoutAddressService : ICheckoutAddressService
public CheckoutAddressService(ISiteService siteService) => _siteService = siteService;
- public virtual async Task ShouldIgnoreAddressAsync(CheckoutViewModel checkoutViewModel)
- {
- var settings = (await _siteService.GetSiteSettingsAsync()).As();
- var shouldIgnore = settings.ShouldIgnoreAddress;
-
- return shouldIgnore;
- }
+ public virtual async Task ShouldIgnoreAddressAsync(CheckoutViewModel checkoutViewModel) =>
+ (await _siteService.GetSiteSettingsAsync())
+ .GetOrCreate()
+ .ShouldIgnoreAddress;
}
diff --git a/src/Modules/OrchardCore.Commerce.Payment/Services/PaymentService.cs b/src/Modules/OrchardCore.Commerce.Payment/Services/PaymentService.cs
index 4ac07d574..ac1b07e55 100644
--- a/src/Modules/OrchardCore.Commerce.Payment/Services/PaymentService.cs
+++ b/src/Modules/OrchardCore.Commerce.Payment/Services/PaymentService.cs
@@ -263,15 +263,12 @@ public async Task CheckoutWithoutPaymentAsync(s
{
try
{
- return mustBeFree ?
- await PaymentServiceExtensions.UpdateAndRedirectToFinishedOrderAsync(
- this,
+ return mustBeFree
+ ? await this.UpdateAndRedirectToFinishedOrderAsync(
order,
shoppingCartId,
FeatureIds.WithoutPaymentProvider)
- :
- await PaymentServiceExtensions.UpdateAndRedirectToFinishedOrderAsync(
- this,
+ : await this.UpdateAndRedirectToFinishedOrderAsync(
order,
shoppingCartId,
FeatureIds.NoNecessaryPaymentProvider);
@@ -311,7 +308,7 @@ public async Task CallBackAsync(string paymentP
Status = PaymentOperationStatus.NotFound,
};
- var status = order.As()?.Status?.Text ?? OrderStatusCodes.Pending;
+ var status = order.GetMaybe()?.Status?.Text ?? OrderStatusCodes.Pending;
if (status is not OrderStatusCodes.Pending and not OrderStatusCodes.PaymentFailed)
{
@@ -394,10 +391,10 @@ public async Task UpdateOrderToOrderedAsync(
{
var order = await _contentManager.GetAsync(orderId) ?? await _contentManager.NewAsync(Order);
var isNew = order.IsNew();
- var part = order.As();
+ var part = order.GetOrCreate();
var cart = await _shoppingCartHelpers.RetrieveAsync(shoppingCartId);
- if (cart.Items.Any() && !order.As().LineItems.Any() && updateModelAccessor != null)
+ if (cart.Items.Any() && !order.GetOrCreate().LineItems.Any() && updateModelAccessor != null)
{
await _contentItemDisplayManager.UpdateEditorAsync(order, updateModelAccessor.ModelUpdater, isNew: false);
diff --git a/src/Modules/OrchardCore.Commerce.Tax/Extensions/AmountExtensions.cs b/src/Modules/OrchardCore.Commerce.Tax/Extensions/AmountExtensions.cs
index d2e519039..a56dd13de 100644
--- a/src/Modules/OrchardCore.Commerce.Tax/Extensions/AmountExtensions.cs
+++ b/src/Modules/OrchardCore.Commerce.Tax/Extensions/AmountExtensions.cs
@@ -9,7 +9,7 @@ public static Amount WithTax(this Amount netAmount, decimal taxRate) =>
new(netAmount.Value * ToMultiplier(taxRate), netAmount.Currency);
public static Amount WithTax(this Amount netAmount, IContent contentWithTaxPart) =>
- WithTax(netAmount, contentWithTaxPart.As()?.TaxRate.Value ?? 0);
+ WithTax(netAmount, contentWithTaxPart.GetMaybe()?.TaxRate.Value ?? 0);
public static Amount WithoutTax(this Amount grossAmount, decimal taxRate) =>
new(grossAmount.Value / ToMultiplier(taxRate), grossAmount.Currency);
diff --git a/src/Modules/OrchardCore.Commerce.Tax/Services/TaxRateSettingsConfiguration.cs b/src/Modules/OrchardCore.Commerce.Tax/Services/TaxRateSettingsConfiguration.cs
index 800e6633d..330cac638 100644
--- a/src/Modules/OrchardCore.Commerce.Tax/Services/TaxRateSettingsConfiguration.cs
+++ b/src/Modules/OrchardCore.Commerce.Tax/Services/TaxRateSettingsConfiguration.cs
@@ -14,7 +14,7 @@ public void Configure(TaxRateSettings options)
{
var settings = _siteService
.GetSiteSettings()
- .As();
+ .GetOrCreate();
options.CopyFrom(settings);
}
diff --git a/src/Modules/OrchardCore.Commerce/Controllers/ShoppingCartController.cs b/src/Modules/OrchardCore.Commerce/Controllers/ShoppingCartController.cs
index 3e7201ae7..c369106d7 100644
--- a/src/Modules/OrchardCore.Commerce/Controllers/ShoppingCartController.cs
+++ b/src/Modules/OrchardCore.Commerce/Controllers/ShoppingCartController.cs
@@ -163,7 +163,9 @@ await _workflowManagers.TriggerEventAsync(
if (!isValid)
{
var minOrderQuantity = (await _productService.GetProductAsync(line.ProductSku))?
- .As()?.MinimumOrderQuantity.Value ?? 0;
+ .GetMaybe()?
+ .MinimumOrderQuantity
+ .Value ?? 0;
// Choose new quantity based on whether Minimum Order Quantity has a value.
line.Quantity = (int)(minOrderQuantity > 0 ? minOrderQuantity : 1);
diff --git a/src/Modules/OrchardCore.Commerce/Controllers/UserController.cs b/src/Modules/OrchardCore.Commerce/Controllers/UserController.cs
index 47a0f7650..a6e969566 100644
--- a/src/Modules/OrchardCore.Commerce/Controllers/UserController.cs
+++ b/src/Modules/OrchardCore.Commerce/Controllers/UserController.cs
@@ -128,9 +128,9 @@ public async Task DetailsPost()
private async Task GetUserContentItemAsync(User user, string contentType)
{
- var contentItem = user.As(contentType);
+ var contentItem = user.GetOrCreate(contentType);
- return string.IsNullOrEmpty(contentItem?.ContentType)
+ return string.IsNullOrEmpty(contentItem.ContentType)
? await _contentManager.NewAsync(contentType)
: contentItem;
}
diff --git a/src/Modules/OrchardCore.Commerce/Drivers/DiscountPartDisplayDriver.cs b/src/Modules/OrchardCore.Commerce/Drivers/DiscountPartDisplayDriver.cs
index f4211040a..128f20f81 100644
--- a/src/Modules/OrchardCore.Commerce/Drivers/DiscountPartDisplayDriver.cs
+++ b/src/Modules/OrchardCore.Commerce/Drivers/DiscountPartDisplayDriver.cs
@@ -48,9 +48,9 @@ private static void BuildViewModel(DiscountPartViewModel model, DiscountInformat
private static Amount? CalculateNewPrice(DiscountInformation discount, DiscountPart part)
{
var contentItem = part?.ContentItem;
- var newPrice = contentItem?.As()?.GrossPrice?.Amount is { IsValid: true } grossPrice
+ var newPrice = contentItem?.GetMaybe()?.GrossPrice?.Amount is { IsValid: true } grossPrice
? grossPrice
- : contentItem?.As()?.Price;
+ : contentItem?.GetMaybe()?.Price;
if (newPrice is not { } notNullPrice) return null;
if (discount.DiscountPercentage > 0) return notNullPrice.WithDiscount(discount.DiscountPercentage);
diff --git a/src/Modules/OrchardCore.Commerce/Drivers/PriceVariantsPartDisplayDriver.cs b/src/Modules/OrchardCore.Commerce/Drivers/PriceVariantsPartDisplayDriver.cs
index 1496fc71c..c001cb4b0 100644
--- a/src/Modules/OrchardCore.Commerce/Drivers/PriceVariantsPartDisplayDriver.cs
+++ b/src/Modules/OrchardCore.Commerce/Drivers/PriceVariantsPartDisplayDriver.cs
@@ -99,7 +99,7 @@ private async Task BuildViewModelAsync(PriceVariantsPartViewModel model, PriceVa
model.InitializeVariants(variants, values, currencies);
// When creating a new PriceVariantsProduct item, initialize default inventories.
- if (part.ContentItem.As() is { } inventoryPart && !inventoryPart.Inventory.Any())
+ if (part.ContentItem.TryGet(out var inventoryPart) && !inventoryPart.Inventory.Any())
{
foreach (var variantKey in allVariantsKeys)
{
diff --git a/src/Modules/OrchardCore.Commerce/Drivers/ProductPartDisplayDriver.cs b/src/Modules/OrchardCore.Commerce/Drivers/ProductPartDisplayDriver.cs
index c31841374..c4629d0fd 100644
--- a/src/Modules/OrchardCore.Commerce/Drivers/ProductPartDisplayDriver.cs
+++ b/src/Modules/OrchardCore.Commerce/Drivers/ProductPartDisplayDriver.cs
@@ -59,7 +59,7 @@ public override async Task UpdateAsync(
// If the SKU is read-only then editing should not be possible, but here we undo any POST trickery just in case.
part.Sku = IsSkuReadOnly ? skuBefore : part.Sku.ToUpperInvariant();
- if (part.ContentItem.As() is { } inventoryPart)
+ if (part.ContentItem.TryGet(out var inventoryPart))
{
part.CanBeBought.Clear();
@@ -105,7 +105,7 @@ private async Task BuildViewModelAsync(ProductPartViewModel viewModel, ProductPa
viewModel.IsSkuReadOnly = IsSkuReadOnly;
viewModel.ProductPart = part;
- if (part.ContentItem.As() is { } inventoryPart)
+ if (part.ContentItem.TryGet(out var inventoryPart))
{
foreach (var (key, value) in inventoryPart.FilterOutdatedEntries())
{
diff --git a/src/Modules/OrchardCore.Commerce/Drivers/TaxRateTaxPartDisplayDriver.cs b/src/Modules/OrchardCore.Commerce/Drivers/TaxRateTaxPartDisplayDriver.cs
index c184c85a7..5936bdca0 100644
--- a/src/Modules/OrchardCore.Commerce/Drivers/TaxRateTaxPartDisplayDriver.cs
+++ b/src/Modules/OrchardCore.Commerce/Drivers/TaxRateTaxPartDisplayDriver.cs
@@ -35,7 +35,7 @@ public TaxRateTaxPartDisplayDriver(
public override async Task DisplayAsync(TaxPart part, BuildPartDisplayContext context)
{
- if (part.As() is not { } product || _hca.HttpContext is not { } httpContext) return null;
+ if (!part.ContentItem.TryGet(out var product) || _hca.HttpContext is not { } httpContext) return null;
try
{
diff --git a/src/Modules/OrchardCore.Commerce/Endpoints/Services/ShoppingCartService.cs b/src/Modules/OrchardCore.Commerce/Endpoints/Services/ShoppingCartService.cs
index c2676ea12..5a6ca6dd4 100644
--- a/src/Modules/OrchardCore.Commerce/Endpoints/Services/ShoppingCartService.cs
+++ b/src/Modules/OrchardCore.Commerce/Endpoints/Services/ShoppingCartService.cs
@@ -133,7 +133,7 @@ await _workflowManagers.TriggerEventAsync(
if (!string.IsNullOrEmpty(errored))
{
var minOrderQuantity = (await _productService.GetProductAsync(line.ProductSku))
- .As().MinimumOrderQuantity.Value;
+ .GetOrCreate().MinimumOrderQuantity.Value;
// Choose new quantity based on whether Minimum Order Quantity has a value.
line.Quantity = (int)(minOrderQuantity > 0 ? minOrderQuantity : 1);
diff --git a/src/Modules/OrchardCore.Commerce/Events/InventoryShoppingCartEvents.cs b/src/Modules/OrchardCore.Commerce/Events/InventoryShoppingCartEvents.cs
index 24ccd57a6..d33ee69da 100644
--- a/src/Modules/OrchardCore.Commerce/Events/InventoryShoppingCartEvents.cs
+++ b/src/Modules/OrchardCore.Commerce/Events/InventoryShoppingCartEvents.cs
@@ -40,7 +40,7 @@ public override async Task VerifyingItemAsync(ShoppingCartI
{
// If the product doesn't have InventoryPart then this event is not applicable.
if (await _productService.GetProductAsync(item.ProductSku) is not { } productPart ||
- productPart.ContentItem.As() is not { } inventoryPart)
+ !productPart.ContentItem.TryGet(out var inventoryPart))
{
return null;
}
@@ -52,7 +52,7 @@ public override async Task VerifyingItemAsync(ShoppingCartI
}
// If there are no attributes on a Price Variant Product, there's no need for the below checks.
- if (productPart.ContentItem.As() is not null && !item.Attributes.Any())
+ if (productPart.ContentItem.Has() && !item.Attributes.Any())
{
return null;
}
diff --git a/src/Modules/OrchardCore.Commerce/Events/TaxShoppingCartEvents.cs b/src/Modules/OrchardCore.Commerce/Events/TaxShoppingCartEvents.cs
index 0e7154a60..61b9cdfcb 100644
--- a/src/Modules/OrchardCore.Commerce/Events/TaxShoppingCartEvents.cs
+++ b/src/Modules/OrchardCore.Commerce/Events/TaxShoppingCartEvents.cs
@@ -64,7 +64,7 @@ public TaxShoppingCartEvents(
.ToList();
// When taxes are specified, Gross Price is always applicable, while Net Price is optional.
- var priceDisplaySettings = (await _siteService.GetSiteSettingsAsync()).As();
+ var priceDisplaySettings = (await _siteService.GetSiteSettingsAsync()).GetOrCreate();
if (priceDisplaySettings.UseNetPriceDisplay)
{
var grossIndex = newHeaders.FindIndex(header => header.Name == "Gross Price");
diff --git a/src/Modules/OrchardCore.Commerce/Events/UserSettingsOrderEvents.cs b/src/Modules/OrchardCore.Commerce/Events/UserSettingsOrderEvents.cs
index 06c0fe7c3..6472ff746 100644
--- a/src/Modules/OrchardCore.Commerce/Events/UserSettingsOrderEvents.cs
+++ b/src/Modules/OrchardCore.Commerce/Events/UserSettingsOrderEvents.cs
@@ -23,7 +23,7 @@ public UserSettingsOrderEvents(IHttpContextAccessor hca, IUserService userServic
public async Task FinalizeAsync(ContentItem order, string shoppingCartId, string paymentProviderName)
{
// Saving addresses.
- var orderPart = order.As();
+ var orderPart = order.GetOrCreate();
if (_hca.HttpContext != null && await _userService.GetFullUserAsync(_hca.HttpContext.User) is { } user)
{
diff --git a/src/Modules/OrchardCore.Commerce/Extensions/UserManagerExtensions.cs b/src/Modules/OrchardCore.Commerce/Extensions/UserManagerExtensions.cs
index c2c538963..907fa8408 100644
--- a/src/Modules/OrchardCore.Commerce/Extensions/UserManagerExtensions.cs
+++ b/src/Modules/OrchardCore.Commerce/Extensions/UserManagerExtensions.cs
@@ -16,12 +16,12 @@ public static class UserManagerExtensions
/// if the corresponding is not , returns otherwise.
///
public static async Task GetUserAddressAsync(this UserManager userManager, ClaimsPrincipal principal) =>
- (await userManager.GetUserAsync(principal) as User)?.As(UserAddresses)?.As();
+ (await userManager.GetUserAsync(principal) as User)?.GetOrCreate(UserAddresses).GetMaybe();
///
/// Returns the custom user setting of for the given
/// if the corresponding is not , returns otherwise.
///
public static async Task GetUserDetailsAsync(this UserManager userManager, ClaimsPrincipal principal) =>
- (await userManager.GetUserAsync(principal) as User)?.As(UserDetails)?.As();
+ (await userManager.GetUserAsync(principal) as User)?.GetOrCreate(UserDetails).GetMaybe();
}
diff --git a/src/Modules/OrchardCore.Commerce/Handlers/DiscountPartHandler.cs b/src/Modules/OrchardCore.Commerce/Handlers/DiscountPartHandler.cs
index a470cc680..b4a2fb159 100644
--- a/src/Modules/OrchardCore.Commerce/Handlers/DiscountPartHandler.cs
+++ b/src/Modules/OrchardCore.Commerce/Handlers/DiscountPartHandler.cs
@@ -29,7 +29,7 @@ public DiscountPartHandler(
protected override async Task CreatingOrUpdatingAsync(DiscountPart part)
{
- if (part.ContentItem.As() is not { } discountPart) return;
+ if (!part.ContentItem.TryGet(out var discountPart)) return;
var discountPercentage = discountPart.DiscountPercentage?.Value ?? 0;
var discountAmount = discountPart.DiscountAmount.Amount;
@@ -41,12 +41,14 @@ protected override async Task CreatingOrUpdatingAsync(DiscountPart part)
await InvalidateEvenStateAsync();
}
- if ((part.ContentItem.As()?.Price is { } pricePartPrice &&
+ var isPricePartInvalid = part.ContentItem.GetMaybe()?.Price is { } pricePartPrice &&
pricePartPrice.Currency.Equals(discountAmount.Currency) &&
- pricePartPrice < discountAmount) ||
- (part.ContentItem.As()?.GrossPrice.Amount is { IsValid: true } taxPartGrossPriceAmount &&
+ pricePartPrice < discountAmount;
+ var isTaxPartInvalid = part.ContentItem.GetMaybe()?.GrossPrice.Amount is { IsValid: true } taxPartGrossPriceAmount &&
taxPartGrossPriceAmount.Currency.Equals(discountAmount.Currency) &&
- taxPartGrossPriceAmount < discountAmount))
+ taxPartGrossPriceAmount < discountAmount;
+
+ if (isPricePartInvalid || isTaxPartInvalid)
{
await InvalidateNegativePriceStateAsync();
}
diff --git a/src/Modules/OrchardCore.Commerce/Handlers/OrderPartHandler.cs b/src/Modules/OrchardCore.Commerce/Handlers/OrderPartHandler.cs
index 906508ead..056f0f2be 100644
--- a/src/Modules/OrchardCore.Commerce/Handlers/OrderPartHandler.cs
+++ b/src/Modules/OrchardCore.Commerce/Handlers/OrderPartHandler.cs
@@ -20,7 +20,7 @@ public OrderPartHandler(IStringLocalizer stringLocalizer, ISes
protected override async Task CreatingOrUpdatingAsync(OrderPart part)
{
- if (part.ContentItem.As() is not { } orderPart) return;
+ if (!part.ContentItem.TryGet(out var orderPart)) return;
var guid = orderPart.OrderId.Text ?? Guid.NewGuid().ToString();
orderPart.OrderId.Text = guid;
@@ -32,7 +32,5 @@ protected override async Task CreatingOrUpdatingAsync(OrderPart part)
orderPart.Apply();
await _session.SaveAsync(orderPart.ContentItem);
-
- return;
}
}
diff --git a/src/Modules/OrchardCore.Commerce/Handlers/OrderPermissionsAuthorizationHandler.cs b/src/Modules/OrchardCore.Commerce/Handlers/OrderPermissionsAuthorizationHandler.cs
index cd7d84bcb..b23b2b737 100644
--- a/src/Modules/OrchardCore.Commerce/Handlers/OrderPermissionsAuthorizationHandler.cs
+++ b/src/Modules/OrchardCore.Commerce/Handlers/OrderPermissionsAuthorizationHandler.cs
@@ -16,7 +16,7 @@ public OrderPermissionsAuthorizationHandler(Lazy authoriz
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
{
- if (context.Resource is not IContent order || order.As() is null)
+ if (context.Resource is not IContent order || !order.ContentItem.Has())
{
return;
}
diff --git a/src/Modules/OrchardCore.Commerce/Handlers/TaxPartAndPricePartHandler.cs b/src/Modules/OrchardCore.Commerce/Handlers/TaxPartAndPricePartHandler.cs
index 5ececbfa2..895957cc7 100644
--- a/src/Modules/OrchardCore.Commerce/Handlers/TaxPartAndPricePartHandler.cs
+++ b/src/Modules/OrchardCore.Commerce/Handlers/TaxPartAndPricePartHandler.cs
@@ -33,7 +33,7 @@ public TaxPartAndPricePartHandler(
protected override async Task CreatingOrUpdatingAsync(PricePart part)
{
- if (part.ContentItem.As() is not { } taxPart) return;
+ if (!part.ContentItem.TryGet(out var taxPart)) return;
var taxRate = taxPart.TaxRate?.Value ?? 0;
diff --git a/src/Modules/OrchardCore.Commerce/Indexes/PriceIndex.cs b/src/Modules/OrchardCore.Commerce/Indexes/PriceIndex.cs
index 7d820edc3..f26ac0fae 100644
--- a/src/Modules/OrchardCore.Commerce/Indexes/PriceIndex.cs
+++ b/src/Modules/OrchardCore.Commerce/Indexes/PriceIndex.cs
@@ -22,7 +22,7 @@ public override void Describe(DescribeContext context) =>
{
if (!contentItem.Published || !contentItem.Latest) return null;
- if (contentItem.As() is { Price.Value: var price })
+ if (contentItem.GetMaybe() is { Price.Value: var price })
{
return new PriceIndex
{
@@ -31,7 +31,7 @@ public override void Describe(DescribeContext context) =>
};
}
- var variants = contentItem.As()?.Variants;
+ var variants = contentItem.GetMaybe()?.Variants;
if (variants?.Any() == true)
{
var amounts = variants.Values.Select(amount => amount.Value).ToList();
diff --git a/src/Modules/OrchardCore.Commerce/Indexes/ProductPartIndex.cs b/src/Modules/OrchardCore.Commerce/Indexes/ProductPartIndex.cs
index f54e89b57..b07234b8c 100644
--- a/src/Modules/OrchardCore.Commerce/Indexes/ProductPartIndex.cs
+++ b/src/Modules/OrchardCore.Commerce/Indexes/ProductPartIndex.cs
@@ -19,23 +19,13 @@ public class ProductPartIndexProvider : IndexProvider
public override void Describe(DescribeContext context) =>
context.For()
.Map(contentItem =>
- {
- if (!contentItem.IsPublished())
- {
- return null;
- }
-
- var productPart = contentItem.As();
-
- if (productPart?.Sku == null)
- {
- return null;
- }
-
- return new ProductPartIndex
- {
- Sku = productPart.Sku.ToUpperInvariant(),
- ContentItemId = contentItem.ContentItemId,
- };
- });
+ contentItem.IsPublished() &&
+ contentItem.TryGet(out var productPart) &&
+ !string.IsNullOrEmpty(productPart.Sku)
+ ? new ProductPartIndex
+ {
+ Sku = productPart.Sku.ToUpperInvariant(),
+ ContentItemId = contentItem.ContentItemId,
+ }
+ : null);
}
diff --git a/src/Modules/OrchardCore.Commerce/Indexes/SubscriptionPartIndex.cs b/src/Modules/OrchardCore.Commerce/Indexes/SubscriptionPartIndex.cs
index 853578570..9822f6903 100644
--- a/src/Modules/OrchardCore.Commerce/Indexes/SubscriptionPartIndex.cs
+++ b/src/Modules/OrchardCore.Commerce/Indexes/SubscriptionPartIndex.cs
@@ -28,7 +28,7 @@ public override void Describe(DescribeContext context) =>
.When(contentItem => contentItem.Has())
.Map(contentItem =>
{
- var subscriptionPart = contentItem.As();
+ var subscriptionPart = contentItem.GetOrCreate();
return new SubscriptionPartIndex
{
diff --git a/src/Modules/OrchardCore.Commerce/Liquid/OrderPartToOrderSummaryLiquidFilter.cs b/src/Modules/OrchardCore.Commerce/Liquid/OrderPartToOrderSummaryLiquidFilter.cs
index 11a8d3f84..8f4fa7203 100644
--- a/src/Modules/OrchardCore.Commerce/Liquid/OrderPartToOrderSummaryLiquidFilter.cs
+++ b/src/Modules/OrchardCore.Commerce/Liquid/OrderPartToOrderSummaryLiquidFilter.cs
@@ -50,7 +50,7 @@ private async ValueTask ProcessInnerAsync(OrderPart orderPart)
.Select(viewModel => new
{
ViewModel = viewModel,
- TaxRate = viewModel.ProductPart.ContentItem?.As()?.TaxRate?.Value,
+ TaxRate = viewModel.ProductPart.ContentItem?.GetMaybe()?.TaxRate?.Value,
UnitTax = viewModel.UnitPrice - Round(viewModel.UnitPriceValue, viewModel),
SubTotal = subTotal,
TaxTotal = total - subTotal,
diff --git a/src/Modules/OrchardCore.Commerce/Middlewares/LocalizationCurrencyRedirectMiddleware.cs b/src/Modules/OrchardCore.Commerce/Middlewares/LocalizationCurrencyRedirectMiddleware.cs
index 7e316ee53..eed4f23af 100644
--- a/src/Modules/OrchardCore.Commerce/Middlewares/LocalizationCurrencyRedirectMiddleware.cs
+++ b/src/Modules/OrchardCore.Commerce/Middlewares/LocalizationCurrencyRedirectMiddleware.cs
@@ -41,10 +41,11 @@ private async Task QueryAndRedirectAsync(HttpContext context, string id)
var contentManager = context.RequestServices.GetRequiredService();
var item = await contentManager.GetAsync(id);
- if (item?.As() is { } pricePart &&
- item.As() is { } localizationPart &&
+ if (item?.TryGet(out var pricePart) == true &&
+ item.TryGet(out var localizationPart) &&
await context.RequestServices.GetRequiredService().GetSiteSettingsAsync() is { } settings &&
- settings.As().CurrentDisplayCurrency is { } displayCurrency &&
+ settings.TryGet(out var currencySettings) &&
+ currencySettings.CurrentDisplayCurrency is { } displayCurrency &&
displayCurrency != pricePart.Price.Currency.CurrencyIsoCode)
{
var session = context.RequestServices.GetRequiredService();
@@ -55,7 +56,7 @@ await context.RequestServices.GetRequiredService().GetSiteSettings
.ListAsync();
var applicable = localizationSet
- .As()
+ .GetOrCreate()
.FirstOrDefault(part => part.Price.Currency.CurrencyIsoCode == displayCurrency);
if (applicable != null)
diff --git a/src/Modules/OrchardCore.Commerce/Services/ContentLocalizationProductService.cs b/src/Modules/OrchardCore.Commerce/Services/ContentLocalizationProductService.cs
index 2505f787d..d4c0763af 100644
--- a/src/Modules/OrchardCore.Commerce/Services/ContentLocalizationProductService.cs
+++ b/src/Modules/OrchardCore.Commerce/Services/ContentLocalizationProductService.cs
@@ -34,7 +34,7 @@ public override async Task> GetProductsAsync(IEnumerabl
// Shortcut if there are no duplicate localized products.
if (skuList.Count == products.Count ||
- (await _siteService.GetSiteSettingsAsync()).As() is not { } localizationSettings)
+ !(await _siteService.GetSiteSettingsAsync()).TryGet(out var localizationSettings))
{
return products;
}
@@ -53,7 +53,7 @@ public override async Task> GetProductsAsync(IEnumerabl
}
result.Add(parts
- .OrderByDescending(part => priority.IndexOf(part.ContentItem.As()?.Culture))
+ .OrderByDescending(part => priority.IndexOf(part.ContentItem.GetMaybe()?.Culture))
.First());
}
diff --git a/src/Modules/OrchardCore.Commerce/Services/GlobalDiscountProvider.cs b/src/Modules/OrchardCore.Commerce/Services/GlobalDiscountProvider.cs
index b6dd9be8d..14430d920 100644
--- a/src/Modules/OrchardCore.Commerce/Services/GlobalDiscountProvider.cs
+++ b/src/Modules/OrchardCore.Commerce/Services/GlobalDiscountProvider.cs
@@ -73,7 +73,7 @@ private async Task> QueryDiscountPartsAsync(Pro
int totalQuantity = model.Items.Sum(item => item.Quantity);
return globalDiscountItems
- .As()
+ .GetOrCreate()
.Where(part => part.IsApplicable(totalQuantity, model.PurchaseDateTime ?? _clock.UtcNow))
.Select(part => (DiscountInformation)part);
}
diff --git a/src/Modules/OrchardCore.Commerce/Services/LocalInventoryProvider.cs b/src/Modules/OrchardCore.Commerce/Services/LocalInventoryProvider.cs
index 47837bbac..729ada022 100644
--- a/src/Modules/OrchardCore.Commerce/Services/LocalInventoryProvider.cs
+++ b/src/Modules/OrchardCore.Commerce/Services/LocalInventoryProvider.cs
@@ -31,15 +31,12 @@ public LocalInventoryProvider(IProductService productService, ISession session)
public Task IsApplicableAsync(IList model) => Task.FromResult(true);
- public async Task> QueryAllInventoriesAsync(string sku)
- {
- var inventoryPart = (await _productService.GetProductAsync(sku))?.As();
- return inventoryPart?.Inventory;
- }
+ public async Task> QueryAllInventoriesAsync(string sku) =>
+ (await _productService.GetProductAsync(sku))?.GetMaybe()?.Inventory;
public async Task QueryInventoryAsync(string sku, string fullSku = null)
{
- var inventoryPart = (await _productService.GetProductAsync(sku))?.As();
+ var inventoryPart = (await _productService.GetProductAsync(sku))?.GetMaybe();
// If fullSku is specified, look for Price Variant Product's inventory.
var inventoryIdentifier = string.IsNullOrEmpty(fullSku) ? sku : fullSku;
@@ -70,8 +67,11 @@ private async Task UpdateInventoryAsync(ProductPart productPart, int difference,
try
{
- var inventoryPart = productPart?.ContentItem.As();
- if (inventoryPart == null || inventoryPart.IgnoreInventory.Value) return;
+ if (productPart?.ContentItem.TryGet(out var inventoryPart) != true ||
+ inventoryPart.IgnoreInventory.Value)
+ {
+ return;
+ }
var inventoryIdentifier = string.IsNullOrEmpty(fullSku) ? productPart.Sku : fullSku;
var inventoryRootIdentifier = inventoryIdentifier.Contains('-')
diff --git a/src/Modules/OrchardCore.Commerce/Services/LocalTaxProvider.cs b/src/Modules/OrchardCore.Commerce/Services/LocalTaxProvider.cs
index 2a19d6267..6f7294026 100644
--- a/src/Modules/OrchardCore.Commerce/Services/LocalTaxProvider.cs
+++ b/src/Modules/OrchardCore.Commerce/Services/LocalTaxProvider.cs
@@ -47,6 +47,6 @@ public async Task IsApplicableAsync(PromotionAndTaxProviderContext model)
await ITaxProvider.AllOrNoneAsync(model, items => Task.FromResult(HasTaxRate(items)));
private static int HasTaxRate(IList items) => items
- .SelectWhere(item => item.Content.ContentItem.As())
+ .SelectWhere(item => item.Content.ContentItem.GetMaybe())
.Count(taxPart => taxPart.TaxRate.Value == 0 || (taxPart.GrossPrice.Amount.IsValid && taxPart.TaxRate.Value > 0));
}
diff --git a/src/Modules/OrchardCore.Commerce/Services/LocalizationDuplicateSkuResolver.cs b/src/Modules/OrchardCore.Commerce/Services/LocalizationDuplicateSkuResolver.cs
index fafeceff0..6f484b93a 100644
--- a/src/Modules/OrchardCore.Commerce/Services/LocalizationDuplicateSkuResolver.cs
+++ b/src/Modules/OrchardCore.Commerce/Services/LocalizationDuplicateSkuResolver.cs
@@ -8,9 +8,9 @@ namespace OrchardCore.Commerce.Services;
public class LocalizationDuplicateSkuResolver : IDuplicateSkuResolver
{
public IList UpdateDuplicatesList(ContentItem current, IList otherProducts) =>
- current.As()?.LocalizationSet is { } currentLocalizationSet
+ current.GetMaybe()?.LocalizationSet is { } currentLocalizationSet
? otherProducts
- .WhereNot(other => other.As()?.LocalizationSet == currentLocalizationSet)
+ .WhereNot(other => other.GetMaybe()?.LocalizationSet == currentLocalizationSet)
.ToList()
: otherProducts;
}
diff --git a/src/Modules/OrchardCore.Commerce/Services/OrderLineItemService.cs b/src/Modules/OrchardCore.Commerce/Services/OrderLineItemService.cs
index 9cd931e98..282747c35 100644
--- a/src/Modules/OrchardCore.Commerce/Services/OrderLineItemService.cs
+++ b/src/Modules/OrchardCore.Commerce/Services/OrderLineItemService.cs
@@ -139,7 +139,7 @@ await _taxProviders.GetFirstApplicableProviderAsync(promotionAndTaxContext) is {
var allProducts = await _session.Query().ListAsync();
foreach (var product in allProducts)
{
- var productSku = product.As().Sku;
+ var productSku = product.GetOrCreate().Sku;
var booleanAttributes = (await _productAttributeService.GetProductAttributeFieldsAsync(product))
.Where(attribute => attribute.Field is BooleanProductAttributeField)
diff --git a/src/Modules/OrchardCore.Commerce/Services/PriceVariantProvider.cs b/src/Modules/OrchardCore.Commerce/Services/PriceVariantProvider.cs
index f4c80fc17..8a407c7db 100644
--- a/src/Modules/OrchardCore.Commerce/Services/PriceVariantProvider.cs
+++ b/src/Modules/OrchardCore.Commerce/Services/PriceVariantProvider.cs
@@ -55,7 +55,7 @@ public async Task> UpdateAsync(IList m
private async Task AddPriceToShoppingCartItemAsync(ShoppingCartItem item, ProductPart productPart)
{
- var priceVariantsPart = productPart.ContentItem.As();
+ var priceVariantsPart = productPart.ContentItem.GetMaybe();
if (priceVariantsPart is { Variants: { } variants } && variants.Any())
{
diff --git a/src/Modules/OrchardCore.Commerce/Services/ProductInventoryService.cs b/src/Modules/OrchardCore.Commerce/Services/ProductInventoryService.cs
index c03496e4e..03240ea6b 100644
--- a/src/Modules/OrchardCore.Commerce/Services/ProductInventoryService.cs
+++ b/src/Modules/OrchardCore.Commerce/Services/ProductInventoryService.cs
@@ -38,8 +38,8 @@ public async Task VerifyLinesAsync(IList lines)
{
foreach (var line in lines)
{
- var productPart = line.Product.ContentItem.As();
- if (productPart.As() is not { } inventoryPart)
+ var productPart = line.Product.ContentItem.GetOrCreate();
+ if (productPart.ContentItem?.TryGet(out var inventoryPart) != true)
{
continue;
}
diff --git a/src/Modules/OrchardCore.Commerce/Services/ProductService.cs b/src/Modules/OrchardCore.Commerce/Services/ProductService.cs
index 2006fc5d4..1b381c319 100644
--- a/src/Modules/OrchardCore.Commerce/Services/ProductService.cs
+++ b/src/Modules/OrchardCore.Commerce/Services/ProductService.cs
@@ -94,7 +94,7 @@ public string GetVariantKey(string sku) =>
public async Task<(PriceVariantsPart Part, string VariantKey)> GetExactVariantAsync(string sku)
{
var productPart = await this.GetProductAsync(sku);
- var priceVariantsPart = productPart?.ContentItem.As();
+ var priceVariantsPart = productPart?.ContentItem.GetMaybe();
return (priceVariantsPart, GetVariantKey(sku));
}
@@ -135,7 +135,7 @@ private async Task> FillContentItemsAndGetProductPartsAsync(IE
}
}
- results.Add(contentItem.As());
+ results.Add(contentItem.GetMaybe());
}
return results;
diff --git a/src/Modules/OrchardCore.Commerce/Services/RegionConfiguration.cs b/src/Modules/OrchardCore.Commerce/Services/RegionConfiguration.cs
index 3283c530c..eb85c6230 100644
--- a/src/Modules/OrchardCore.Commerce/Services/RegionConfiguration.cs
+++ b/src/Modules/OrchardCore.Commerce/Services/RegionConfiguration.cs
@@ -15,7 +15,7 @@ public void Configure(RegionSettings options)
{
var settings = _siteService
.GetSiteSettings()
- .As();
+ .GetOrCreate();
options.AllowedRegions = settings.AllowedRegions;
}
diff --git a/src/Modules/OrchardCore.Commerce/Services/RegionService.cs b/src/Modules/OrchardCore.Commerce/Services/RegionService.cs
index 888771ff7..0ee90f28b 100644
--- a/src/Modules/OrchardCore.Commerce/Services/RegionService.cs
+++ b/src/Modules/OrchardCore.Commerce/Services/RegionService.cs
@@ -26,7 +26,7 @@ public IEnumerable GetAllRegions() =>
public async Task> GetAvailableRegionsAsync()
{
var settings = await _siteService.GetSiteSettingsAsync();
- var allowedRegionCodes = (settings.As()?.AllowedRegions ?? []).AsList();
+ var allowedRegionCodes = (settings.GetOrCreate()?.AllowedRegions ?? []).AsList();
var allRegions = GetAllRegions();
diff --git a/src/Modules/OrchardCore.Commerce/Services/TaxRateTaxProvider.cs b/src/Modules/OrchardCore.Commerce/Services/TaxRateTaxProvider.cs
index 2f9828540..5248549af 100644
--- a/src/Modules/OrchardCore.Commerce/Services/TaxRateTaxProvider.cs
+++ b/src/Modules/OrchardCore.Commerce/Services/TaxRateTaxProvider.cs
@@ -32,7 +32,7 @@ public async Task UpdateAsync(PromotionAndTaxPro
var taxRate = MatchTaxRate(
taxRates.Rates,
model.ShippingAddress,
- item.Content.As()?.ProductTaxCode?.Text,
+ item.Content.GetMaybe()?.ProductTaxCode?.Text,
model.VatNumber,
model.IsCorporation);
@@ -51,14 +51,14 @@ public async Task IsApplicableAsync(PromotionAndTaxProviderContext model)
await ITaxProvider.AllOrNoneAsync(model, async items =>
{
var siteSettings = await _siteService.GetSiteSettingsAsync();
- var taxRates = siteSettings.As();
- if (taxRates?.Rates.Any() != true) return 0;
+ var taxRates = siteSettings.GetOrCreate();
+ if (!taxRates.Rates.Any()) return 0;
return items.Count(item =>
MatchTaxRate(
taxRates.Rates,
model.ShippingAddress,
- item.Content.As()?.ProductTaxCode?.Text,
+ item.Content.GetMaybe()?.ProductTaxCode?.Text,
model.VatNumber,
model.IsCorporation) >= 0);
});
diff --git a/src/Modules/OrchardCore.Commerce/Services/TieredPriceProvider.cs b/src/Modules/OrchardCore.Commerce/Services/TieredPriceProvider.cs
index 08eaecb13..91f9755d2 100644
--- a/src/Modules/OrchardCore.Commerce/Services/TieredPriceProvider.cs
+++ b/src/Modules/OrchardCore.Commerce/Services/TieredPriceProvider.cs
@@ -41,7 +41,7 @@ public async Task> UpdateAsync(IList m
private ShoppingCartItem AddPriceToShoppingCartItem(ShoppingCartItem item, ProductPart productPart)
{
- if (productPart.ContentItem.As() is not { } tieredPricePart) return null;
+ if (!productPart.ContentItem.TryGet(out var tieredPricePart)) return null;
return item.WithPrice(
new PrioritizedPrice(1, tieredPricePart.GetPriceForQuantity(_moneyService, item.Quantity)));
diff --git a/src/Modules/OrchardCore.Commerce/Settings/CurrencySettingsConfiguration.cs b/src/Modules/OrchardCore.Commerce/Settings/CurrencySettingsConfiguration.cs
index d6fd5d0e4..dfc559592 100644
--- a/src/Modules/OrchardCore.Commerce/Settings/CurrencySettingsConfiguration.cs
+++ b/src/Modules/OrchardCore.Commerce/Settings/CurrencySettingsConfiguration.cs
@@ -13,7 +13,7 @@ public void Configure(CurrencySettings options)
{
var settings = _site
.GetSiteSettings()
- .As();
+ .GetOrCreate