diff --git a/.github/actions/spelling/allow/occ.txt b/.github/actions/spelling/allow/occ.txt
index 7fbcf6a82..a13600e92 100644
--- a/.github/actions/spelling/allow/occ.txt
+++ b/.github/actions/spelling/allow/occ.txt
@@ -17,6 +17,7 @@ foobool
footext
GST
htmlfield
+JConvert
LCID
markdownlint
Mastercard
@@ -39,4 +40,4 @@ testproductvariant
unpublish
vnd
webhooks
-webshop
\ No newline at end of file
+webshop
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 4ec0c6247..516dba95f 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -6,20 +6,22 @@
- 1.8.0
+ 2.0.0-preview-18282
+
+ 10.0.1-alpha.3.occ-245
+ 10.0.2-alpha.1.occ-245
-
-
+
+
-
-
-
+
+
+
-
diff --git a/NuGet.config b/NuGet.config
new file mode 100644
index 000000000..f8deebdec
--- /dev/null
+++ b/NuGet.config
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Nuget.config b/Nuget.config
deleted file mode 100644
index ddd7f13a1..000000000
--- a/Nuget.config
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/OrchardCore.Commerce.sln b/OrchardCore.Commerce.sln
index 4b0c7ccbb..bfdea0c9e 100644
--- a/OrchardCore.Commerce.sln
+++ b/OrchardCore.Commerce.sln
@@ -11,10 +11,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
Directory.Build.props = Directory.Build.props
License.md = License.md
mkdocs.yml = mkdocs.yml
- Nuget.config = Nuget.config
Readme.md = Readme.md
Reset-Local.ps1 = Reset-Local.ps1
Directory.Packages.props = Directory.Packages.props
+ NuGet.config = NuGet.config
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{B2D057AA-E3F7-404D-A713-C3C59F9DE562}"
@@ -118,6 +118,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "guides", "guides", "{EF8008
docs\guides\create-webshop.md = docs\guides\create-webshop.md
EndProjectSection
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "releases", "releases", "{0A8AB166-9C4F-4161-BD69-362DBC73A11E}"
+ ProjectSection(SolutionItems) = preProject
+ docs\releases\3.0.0.md = docs\releases\3.0.0.md
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -214,6 +219,7 @@ Global
{28DB6CBB-1527-42A1-8EFE-3D95BF185884} = {90913510-3D7F-4BCC-B55E-56343128F049}
{73925C09-BF96-4727-91D8-57A88AD1601F} = {E6C02BDF-EEB0-4ABD-ADEC-9932F60923AE}
{EF8008F1-64F5-4053-A639-6285084AFA52} = {BEBA1764-178A-4722-A193-4DEF26DCE8D1}
+ {0A8AB166-9C4F-4161-BD69-362DBC73A11E} = {BEBA1764-178A-4722-A193-4DEF26DCE8D1}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {456CBC78-579D-483F-A4C3-AF5C12AB3324}
diff --git a/docs/guides/create-webshop.md b/docs/guides/create-webshop.md
index a78a13863..747fdc832 100644
--- a/docs/guides/create-webshop.md
+++ b/docs/guides/create-webshop.md
@@ -91,7 +91,7 @@ Navigate to _Design > Settings > Zones_ and define the zone where you want the S
_Header, Content, Footer, any zone can be created here. Except for Ozone, that's illegal._
- **Layers**:
-A Layer is also going to be necessary for the Widget, so if you don't have one set up yet, see the [relevant documentation page](https://github.com/OrchardCMS/OrchardCore/tree/main/src/docs/reference/modules/Layers/).
+A Layer is also going to be necessary for the Widget, so if you don't have one set up yet, see the [relevant documentation page](https://docs.orchardcore.net/en/latest/reference/modules/Layers/).
- **Widget**:
Widgets are content items that have their stereotype set to Widget. The Commerce module creates a simple Shopping Cart Widget when it's enabled, so we'll just use that. For more extensive documentation about Widgets, see the [usual place](https://docs.orchardcore.net/en/main/docs/reference/modules/Widgets/).
diff --git a/docs/releases/3.0.0.md b/docs/releases/3.0.0.md
new file mode 100644
index 000000000..cb775dda2
--- /dev/null
+++ b/docs/releases/3.0.0.md
@@ -0,0 +1,30 @@
+# Orchard Core Commerce 3.0.0
+
+Release date: Not yet released
+
+## Important Upgrade Instructions
+
+Prior to making the leap to Orchard Core Commerce 3.0.0, please read and follow the instructions for the [Orchard Core 2.0.0 release](https://docs.orchardcore.net/en/latest/releases/2.0.0/), as it contains several major breaking changes.
+
+## Breaking Changes
+
+### Dropped `Newtonsoft.Json` Support
+
+The most important breaking change in OC 2.0 is the end of support for [Newtonsoft Json.NET](https://www.newtonsoft.com/json) and the switch to the [System.Text.Json](https://www.nuget.org/packages/System.Text.Json) (STJ) library. For OCC, all Newtonsoft converters are removed, STJ converters were written or updated as necessary. Any models and interfaces that use `JToken` or `JObject` (such as `OrderPart.AdditionalData` and `IUserService.AlterUserSettingAsync()`) now use `JsonNode` and `JsonObject` respectively.
+
+### Replaced `IPayment` with `Payment` Everywhere
+
+We've dropped the [`IPayment`](https://github.com/OrchardCMS/OrchardCore.Commerce/blob/34ae00470e954459f19f688c9bfc51d196c386ca/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IPayment.cs) interface, now services and models use `Payment` directly, which was also moved into the `OrchardCore.Commerce.Abstractions` library. Migrating to STJ meant that to retain the polymorphic deserialization support for models using `IPayment` would've taken on some additional complexity, while we already found the separate interface unnecessary.
+
+Update using references to `OrchardCore.Commerce.Abstractions.Models`. If you have a custom payment processor integration, update it to use `Payment`.
+
+### Liquid Filters
+
+The `order_line_item_view_models_and_tax_rates` Liquid filter has been removed. A new `order_part_to_order_summary` filter has been added instead, which can be treated as a drop-in replacement. It has additional `Amount` type properties: `UnitTax`, `SubTotal`, `TaxTotal`, and `Total`. These contain the calculated and appropriately rounded values.
+
+The new `amount_to_string` filter processes the input object as `Amount` (like the `amount` filter) and correctly formats it just like the `Amount.ToString()` override in C#. You can use `amount_to_string: dot: ","` to make it display a comma as the decimal separator when it would use a dot. Unlike `amount`, you can also use this filter on a number with the `currency: "three-letter-code""` argument (e.g. `{{ value | amount_to_string: currency: "EUR" }}`). This will display any numeric value as the given currency.
+
+## Change Logs
+
+Please check the GitHub release entry [here](https://github.com/OrchardCMS/OrchardCore.Commerce/releases/tag/v3.0.0).
+
diff --git a/mkdocs.yml b/mkdocs.yml
index b15b08087..b8df9eadf 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -100,4 +100,6 @@ nav:
- NumericProductAttributeField: features/numeric-product-attribute-field.md
- Resources:
- Libraries: resources/libraries/README.md
- - Releases: https://github.com/OrchardCMS/OrchardCore.Commerce/releases
+ - Releases and Notes:
+ - GitHub: https://github.com/OrchardCMS/OrchardCore.Commerce/releases
+ - 3.0.0: docs/releases/3.0.0.md
diff --git a/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IPayment.cs b/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IPayment.cs
deleted file mode 100644
index 80179343f..000000000
--- a/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IPayment.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using OrchardCore.Commerce.MoneyDataType;
-using System;
-
-namespace OrchardCore.Commerce.Abstractions.Abstractions;
-
-///
-/// Describes a payment transaction's details.
-///
-public interface IPayment
-{
- ///
- /// Gets the kind of charge, such as "Credit Card", "Cash", "Bitcoin", etc.
- ///
- string Kind { get; }
-
- ///
- /// Gets a unique ID for the transaction. The semantics of this can vary by provider.
- ///
- string TransactionId { get; }
-
- ///
- /// Gets the text accompanying the charge. The semantics of this can vary by provider.
- ///
- string ChargeText { get; }
-
- ///
- /// Gets the amount charged.
- ///
- Amount Amount { get; }
-
- ///
- /// Gets the UTC creation date and time of the charge.
- ///
- DateTime CreatedUtc { get; }
-}
diff --git a/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IProductAttributeDeserializer.cs b/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IProductAttributeDeserializer.cs
index cd501407c..3af599530 100644
--- a/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IProductAttributeDeserializer.cs
+++ b/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IProductAttributeDeserializer.cs
@@ -1,5 +1,4 @@
-using Newtonsoft.Json.Linq;
-using System;
+using System;
using System.Collections.Generic;
using System.Text.Json.Nodes;
@@ -23,11 +22,6 @@ public interface IProductAttributeDeserializer
///
string AttributeTypeName { get; }
- ///
- /// Deserializes using Newtonsoft.Json.
- ///
- IProductAttributeValue Deserialize(string attributeName, JObject attribute);
-
///
/// Deserializes using System.Text.Json.
///
diff --git a/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IProductAttributeValue.cs b/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IProductAttributeValue.cs
index 6c7584f0b..7d744ba9d 100644
--- a/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IProductAttributeValue.cs
+++ b/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IProductAttributeValue.cs
@@ -1,8 +1,8 @@
-using Newtonsoft.Json;
using OrchardCore.Commerce.Abstractions.Serialization;
using System;
using System.Globalization;
using System.Linq;
+using System.Text.Json.Serialization;
namespace OrchardCore.Commerce.Abstractions.Abstractions;
diff --git a/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IUserService.cs b/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IUserService.cs
index 46b27012f..10235b1fc 100644
--- a/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IUserService.cs
+++ b/src/Libraries/OrchardCore.Commerce.Abstractions/Abstractions/IUserService.cs
@@ -1,9 +1,9 @@
using Microsoft.AspNetCore.Http;
-using Newtonsoft.Json.Linq;
using OrchardCore.ContentManagement;
using OrchardCore.Users.Models;
using System;
using System.Security.Claims;
+using System.Text.Json.Nodes;
using System.Threading.Tasks;
namespace OrchardCore.Commerce.Abstractions.Abstractions;
@@ -22,7 +22,7 @@ public interface IUserService
/// Alters the JSON of a custom user setting content item and saves the result. If the setting doesn't exist for the
/// user then also creates it.
///
- Task AlterUserSettingAsync(User user, string contentType, Func updateContentItemJson);
+ Task AlterUserSettingAsync(User user, string contentType, Func updateContentItemJson);
///
/// Retrieves a that belongs to the custom user setting.
@@ -33,8 +33,7 @@ public interface IUserService
public static class UserServiceExtensions
{
public static Task GetCurrentFullUserAsync(this IUserService service, IHttpContextAccessor hca) =>
- hca.HttpContext?.User is { } user &&
- hca.HttpContext.User.Identity?.IsAuthenticated == true
+ hca.HttpContext?.User is { Identity.IsAuthenticated: true } user
? service.GetFullUserAsync(user)
: Task.FromResult(null);
diff --git a/src/Libraries/OrchardCore.Commerce.Abstractions/Models/OrderLineItem.cs b/src/Libraries/OrchardCore.Commerce.Abstractions/Models/OrderLineItem.cs
index 3c6831525..227f19756 100644
--- a/src/Libraries/OrchardCore.Commerce.Abstractions/Models/OrderLineItem.cs
+++ b/src/Libraries/OrchardCore.Commerce.Abstractions/Models/OrderLineItem.cs
@@ -2,6 +2,7 @@
using OrchardCore.Commerce.MoneyDataType;
using System;
using System.Collections.Generic;
+using System.Text.Json.Serialization;
namespace OrchardCore.Commerce.Abstractions.Models;
@@ -13,10 +14,15 @@ public class OrderLineItem
public Amount UnitPrice { get; set; }
public Amount LinePrice { get; set; }
public string ContentItemVersion { get; set; }
- public ISet Attributes { get; }
- public IDictionary> SelectedAttributes { get; } =
+ public ISet Attributes { get; init; }
+ public IDictionary> SelectedAttributes { get; init; } =
new Dictionary>();
+ [JsonConstructor]
+ private OrderLineItem()
+ {
+ }
+
// These are necessary.
#pragma warning disable S107 // Methods should not have too many parameters
public OrderLineItem(
diff --git a/src/Libraries/OrchardCore.Commerce.Abstractions/Models/OrderPart.cs b/src/Libraries/OrchardCore.Commerce.Abstractions/Models/OrderPart.cs
index 98d39f185..2b9090d5e 100644
--- a/src/Libraries/OrchardCore.Commerce.Abstractions/Models/OrderPart.cs
+++ b/src/Libraries/OrchardCore.Commerce.Abstractions/Models/OrderPart.cs
@@ -1,12 +1,11 @@
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using OrchardCore.Commerce.Abstractions.Abstractions;
using OrchardCore.Commerce.Abstractions.Constants;
using OrchardCore.Commerce.Abstractions.Fields;
using OrchardCore.ContentFields.Fields;
using OrchardCore.ContentManagement;
using System;
using System.Collections.Generic;
+using System.Text.Json.Nodes;
+using System.Text.Json.Serialization;
namespace OrchardCore.Commerce.Abstractions.Models;
@@ -26,16 +25,9 @@ public class OrderPart : ContentPart
public IList AdditionalCosts { get; } = new List();
///
- /// Gets the amounts charged for this order. Typically a single credit card charge.
+ /// Gets the amounts charged for this order. Typically, a single credit card charge.
///
-
- // This is a temporary solution, it needs to be reworked in the future!
-#pragma warning disable CA2326 // Do not use TypeNameHandling values other than None
-#pragma warning disable SCS0028 // TypeNameHandling is set to the other value than 'None'. It may lead to deserialization vulnerability.
- [JsonProperty(ItemTypeNameHandling = TypeNameHandling.Auto)]
-#pragma warning restore SCS0028 // TypeNameHandling is set to the other value than 'None'. It may lead to deserialization vulnerability.
-#pragma warning restore CA2326 // Do not use TypeNameHandling values other than None
- public IList Charges { get; } = new List();
+ public IList Charges { get; } = new List();
public TextField Email { get; set; } = new();
public TextField Phone { get; set; } = new();
@@ -46,7 +38,7 @@ public class OrderPart : ContentPart
public BooleanField BillingAndShippingAddressesMatch { get; set; } = new();
public BooleanField IsCorporation { get; set; } = new();
- public IDictionary AdditionalData { get; } = new Dictionary();
+ public IDictionary AdditionalData { get; } = new Dictionary();
[JsonIgnore]
public bool IsPending => string.IsNullOrWhiteSpace(Status?.Text) || Status.Text.EqualsOrdinalIgnoreCase(OrderStatusCodes.Pending);
diff --git a/src/Modules/OrchardCore.Commerce.Payment/Models/Payment.cs b/src/Libraries/OrchardCore.Commerce.Abstractions/Models/Payment.cs
similarity index 53%
rename from src/Modules/OrchardCore.Commerce.Payment/Models/Payment.cs
rename to src/Libraries/OrchardCore.Commerce.Abstractions/Models/Payment.cs
index b23b4cc18..92f4d90eb 100644
--- a/src/Modules/OrchardCore.Commerce.Payment/Models/Payment.cs
+++ b/src/Libraries/OrchardCore.Commerce.Abstractions/Models/Payment.cs
@@ -1,13 +1,11 @@
-using OrchardCore.Commerce.Abstractions.Abstractions;
using OrchardCore.Commerce.MoneyDataType;
using System;
-namespace OrchardCore.Commerce.Payment.Models;
+namespace OrchardCore.Commerce.Abstractions.Models;
public record Payment(
string Kind,
string TransactionId,
string ChargeText,
Amount Amount,
- DateTime CreatedUtc)
- : IPayment;
+ DateTime CreatedUtc);
diff --git a/src/Libraries/OrchardCore.Commerce.Abstractions/Models/PrioritizedPrice.cs b/src/Libraries/OrchardCore.Commerce.Abstractions/Models/PrioritizedPrice.cs
index 7128fe5a3..be45f4130 100644
--- a/src/Libraries/OrchardCore.Commerce.Abstractions/Models/PrioritizedPrice.cs
+++ b/src/Libraries/OrchardCore.Commerce.Abstractions/Models/PrioritizedPrice.cs
@@ -1,16 +1,15 @@
-using Newtonsoft.Json;
using OrchardCore.Commerce.Abstractions.Serialization;
using OrchardCore.Commerce.MoneyDataType;
using System.Diagnostics;
using System.Globalization;
+using System.Text.Json.Serialization;
namespace OrchardCore.Commerce.Abstractions.Models;
///
/// A price and its priority.
///
-[JsonConverter(typeof(LegacyPrioritizedPriceConverter))]
-[System.Text.Json.Serialization.JsonConverter(typeof(PrioritizedPriceConverter))]
+[JsonConverter(typeof(PrioritizedPriceConverter))]
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class PrioritizedPrice
{
diff --git a/src/Libraries/OrchardCore.Commerce.Abstractions/Models/ShoppingCart.cs b/src/Libraries/OrchardCore.Commerce.Abstractions/Models/ShoppingCart.cs
index f69a3583e..6373b9529 100644
--- a/src/Libraries/OrchardCore.Commerce.Abstractions/Models/ShoppingCart.cs
+++ b/src/Libraries/OrchardCore.Commerce.Abstractions/Models/ShoppingCart.cs
@@ -21,14 +21,12 @@ public class ShoppingCart
///
/// Gets the number of lines in the cart.
///
- [Newtonsoft.Json.JsonIgnore]
[JsonIgnore]
public int Count => Items.Count;
///
/// Gets the total number of items (i.e. products) in the cart. In other words, the sum of quantities of all lines.
///
- [Newtonsoft.Json.JsonIgnore]
[JsonIgnore]
public int ItemCount => Items.Sum(item => item.Quantity);
diff --git a/src/Libraries/OrchardCore.Commerce.Abstractions/Models/ShoppingCartItem.cs b/src/Libraries/OrchardCore.Commerce.Abstractions/Models/ShoppingCartItem.cs
index 4fd342798..0349ec1e2 100644
--- a/src/Libraries/OrchardCore.Commerce.Abstractions/Models/ShoppingCartItem.cs
+++ b/src/Libraries/OrchardCore.Commerce.Abstractions/Models/ShoppingCartItem.cs
@@ -1,4 +1,3 @@
-using Newtonsoft.Json;
using OrchardCore.Commerce.Abstractions.Abstractions;
using OrchardCore.Commerce.Abstractions.ProductAttributeValues;
using OrchardCore.Commerce.Abstractions.Serialization;
@@ -6,14 +5,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Text.Json.Serialization;
namespace OrchardCore.Commerce.Abstractions.Models;
///
/// A shopping cart item.
///
-[JsonConverter(typeof(LegacyShoppingCartItemConverter))]
-[System.Text.Json.Serialization.JsonConverter(typeof(ShoppingCartItemConverter))]
+[JsonConverter(typeof(ShoppingCartItemConverter))]
public sealed class ShoppingCartItem : IEquatable
{
///
diff --git a/src/Libraries/OrchardCore.Commerce.Abstractions/ProductAttributeValues/RawProductAttributeValue.cs b/src/Libraries/OrchardCore.Commerce.Abstractions/ProductAttributeValues/RawProductAttributeValue.cs
index e2752c05b..70ea92510 100644
--- a/src/Libraries/OrchardCore.Commerce.Abstractions/ProductAttributeValues/RawProductAttributeValue.cs
+++ b/src/Libraries/OrchardCore.Commerce.Abstractions/ProductAttributeValues/RawProductAttributeValue.cs
@@ -1,13 +1,12 @@
-using Newtonsoft.Json;
using OrchardCore.Commerce.Abstractions.Serialization;
+using System.Text.Json.Serialization;
namespace OrchardCore.Commerce.Abstractions.ProductAttributeValues;
///
/// Used only to deserialize attributes, before they're post-processed into concrete attribute values.
///
-[JsonConverter(typeof(LegacyRawProductAttributeValueConverter))]
-[System.Text.Json.Serialization.JsonConverter(typeof(RawProductAttributeValueConverter))]
+[JsonConverter(typeof(RawProductAttributeValueConverter))]
internal sealed class RawProductAttributeValue : BaseProductAttributeValue
[JsonConverter(typeof(AmountConverter))]
-[Newtonsoft.Json.JsonConverter(typeof(LegacyAmountConverter))]
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public readonly struct Amount : IEquatable, IComparable
{
@@ -98,15 +97,19 @@ private void ThrowIfCurrencyDoesntMatch(Amount other, string operation = "compar
public static Amount operator +(Amount first, Amount second)
{
first.ThrowIfCurrencyDoesntMatch(second, operation: "add");
- return new Amount(first.Value + second.Value, first.Currency);
+ return new(first.Value + second.Value, first.Currency);
}
+ public static Amount operator +(Amount first, decimal second) => new(first.Value + second, first.Currency);
+
public static Amount operator -(Amount first, Amount second)
{
first.ThrowIfCurrencyDoesntMatch(second, operation: "subtract");
- return new Amount(first.Value - second.Value, first.Currency);
+ return new(first.Value - second.Value, first.Currency);
}
+ public static Amount operator -(Amount first, decimal second) => new(first.Value - second, first.Currency);
+
public static Amount operator -(Amount amount) =>
new(-amount.Value, amount.Currency);
diff --git a/src/Libraries/OrchardCore.Commerce.MoneyDataType/Currency.cs b/src/Libraries/OrchardCore.Commerce.MoneyDataType/Currency.cs
index ebcefc087..98d4eb029 100644
--- a/src/Libraries/OrchardCore.Commerce.MoneyDataType/Currency.cs
+++ b/src/Libraries/OrchardCore.Commerce.MoneyDataType/Currency.cs
@@ -9,7 +9,6 @@
namespace OrchardCore.Commerce.MoneyDataType;
[JsonConverter(typeof(CurrencyConverter))]
-[Newtonsoft.Json.JsonConverter(typeof(LegacyCurrencyConverter))]
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public readonly partial struct Currency : ICurrency, IEquatable
{
diff --git a/src/Libraries/OrchardCore.Commerce.MoneyDataType/Extensions/JObjectExtensions.cs b/src/Libraries/OrchardCore.Commerce.MoneyDataType/Extensions/JObjectExtensions.cs
deleted file mode 100644
index e424269cc..000000000
--- a/src/Libraries/OrchardCore.Commerce.MoneyDataType/Extensions/JObjectExtensions.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace Newtonsoft.Json.Linq;
-
-public static class JObjectExtensions
-{
- public static T Get(this JObject attribute, params string[] keys)
- {
- foreach (var key in keys)
- {
- if (attribute.TryGetValue(key, out var token))
- {
- return token.ToObject();
- }
- }
-
- return default;
- }
-}
diff --git a/src/Libraries/OrchardCore.Commerce.MoneyDataType/OrchardCore.Commerce.MoneyDataType.csproj b/src/Libraries/OrchardCore.Commerce.MoneyDataType/OrchardCore.Commerce.MoneyDataType.csproj
index 6e60abd9f..faff36fe1 100644
--- a/src/Libraries/OrchardCore.Commerce.MoneyDataType/OrchardCore.Commerce.MoneyDataType.csproj
+++ b/src/Libraries/OrchardCore.Commerce.MoneyDataType/OrchardCore.Commerce.MoneyDataType.csproj
@@ -24,7 +24,6 @@
-
diff --git a/src/Libraries/OrchardCore.Commerce.MoneyDataType/Serialization/AmountConverter.cs b/src/Libraries/OrchardCore.Commerce.MoneyDataType/Serialization/AmountConverter.cs
index 3262d700e..c018db964 100644
--- a/src/Libraries/OrchardCore.Commerce.MoneyDataType/Serialization/AmountConverter.cs
+++ b/src/Libraries/OrchardCore.Commerce.MoneyDataType/Serialization/AmountConverter.cs
@@ -1,12 +1,14 @@
using OrchardCore.Commerce.MoneyDataType.Abstractions;
using System;
+using System.Globalization;
+using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using static OrchardCore.Commerce.MoneyDataType.Currency;
namespace OrchardCore.Commerce.MoneyDataType.Serialization;
-internal sealed class AmountConverter : JsonConverter
+public sealed class AmountConverter : JsonConverter
{
public const string ValueName = "value";
public const string CurrencyName = "currency";
@@ -27,6 +29,11 @@ public override Amount Read(ref Utf8JsonReader reader, Type typeToConvert, JsonS
string iso = null;
int? decimalDigits = null;
+ if (reader.TokenType == JsonTokenType.String)
+ {
+ return ReadString(reader.GetString());
+ }
+
while (reader.Read() && reader.TokenType == JsonTokenType.PropertyName)
{
var propertyName = reader.GetString();
@@ -61,37 +68,35 @@ public override Amount Read(ref Utf8JsonReader reader, Type typeToConvert, JsonS
}
}
- if (reader.TokenType == JsonTokenType.String) return LegacyAmountConverter.ReadString(reader.GetString());
-
currency = HandleUnknownCurrency(currency, nativeName, englishName, symbol, iso, decimalDigits);
- return new Amount(value, currency);
+ return new(value, currency);
}
- public override void Write(Utf8JsonWriter writer, Amount amount, JsonSerializerOptions options)
+ public override void Write(Utf8JsonWriter writer, Amount value, JsonSerializerOptions options)
{
- if (amount.Currency is null)
+ if (value.Currency is null)
{
throw new InvalidOperationException("Amount must have a currency applied to allow serialization.");
}
writer.WriteStartObject();
- writer.WriteNumber(ValueName, amount.Value);
+ writer.WriteNumber(ValueName, value.Value);
- if (IsKnownCurrency(amount.Currency.CurrencyIsoCode))
+ if (IsKnownCurrency(value.Currency.CurrencyIsoCode))
{
- writer.WriteString(CurrencyName, amount.Currency.CurrencyIsoCode);
+ writer.WriteString(CurrencyName, value.Currency.CurrencyIsoCode);
}
else
{
- writer.WriteString(NativeName, amount.Currency.NativeName);
- writer.WriteString(EnglishName, amount.Currency.EnglishName);
- writer.WriteString(Symbol, amount.Currency.Symbol);
- writer.WriteString(Iso, amount.Currency.CurrencyIsoCode);
+ writer.WriteString(NativeName, value.Currency.NativeName);
+ writer.WriteString(EnglishName, value.Currency.EnglishName);
+ writer.WriteString(Symbol, value.Currency.Symbol);
+ writer.WriteString(Iso, value.Currency.CurrencyIsoCode);
- if (amount.Currency.DecimalPlaces != DefaultDecimalDigits)
+ if (value.Currency.DecimalPlaces != DefaultDecimalDigits)
{
- writer.WriteNumber(DecimalDigits, amount.Currency.DecimalPlaces);
+ writer.WriteNumber(DecimalDigits, value.Currency.DecimalPlaces);
}
}
@@ -120,4 +125,20 @@ private static ICurrency HandleUnknownCurrency(
throw new InvalidOperationException($"Invalid amount format. Must include a {nameof(currency)}.");
}
+
+ public static Amount ReadString(string text)
+ {
+ ArgumentException.ThrowIfNullOrEmpty(text);
+
+ var parts = text.Split();
+ if (parts.Length < 2)
+ {
+ throw new InvalidOperationException($"Unable to parse string amount \"{text}\".");
+ }
+
+ var currency = FromIsoCode(parts[0]);
+ var value = decimal.Parse(string.Join(string.Empty, parts.Skip(1)), CultureInfo.InvariantCulture);
+
+ return new(value, currency);
+ }
}
diff --git a/src/Libraries/OrchardCore.Commerce.MoneyDataType/Serialization/CurrencyConverter.cs b/src/Libraries/OrchardCore.Commerce.MoneyDataType/Serialization/CurrencyConverter.cs
index f2a16628a..8fb7f0a1a 100644
--- a/src/Libraries/OrchardCore.Commerce.MoneyDataType/Serialization/CurrencyConverter.cs
+++ b/src/Libraries/OrchardCore.Commerce.MoneyDataType/Serialization/CurrencyConverter.cs
@@ -1,10 +1,11 @@
using OrchardCore.Commerce.MoneyDataType.Abstractions;
using System;
using System.Text.Json;
+using System.Text.Json.Serialization;
namespace OrchardCore.Commerce.MoneyDataType.Serialization;
-internal sealed class CurrencyConverter : System.Text.Json.Serialization.JsonConverter
+public sealed class CurrencyConverter : JsonConverter
{
public override ICurrency Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
Currency.FromIsoCode(reader.GetString());
diff --git a/src/Libraries/OrchardCore.Commerce.MoneyDataType/Serialization/LegacyAmountConverter.cs b/src/Libraries/OrchardCore.Commerce.MoneyDataType/Serialization/LegacyAmountConverter.cs
deleted file mode 100644
index a4776eb5c..000000000
--- a/src/Libraries/OrchardCore.Commerce.MoneyDataType/Serialization/LegacyAmountConverter.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using System;
-using System.Globalization;
-using System.Linq;
-using static OrchardCore.Commerce.MoneyDataType.Currency;
-using static OrchardCore.Commerce.MoneyDataType.Serialization.AmountConverter;
-
-namespace OrchardCore.Commerce.MoneyDataType.Serialization;
-
-internal sealed class LegacyAmountConverter : JsonConverter
-{
- public override Amount ReadJson(
- JsonReader reader,
- Type objectType,
- Amount existingValue,
- bool hasExistingValue,
- JsonSerializer serializer)
- {
- var token = JToken.Load(reader);
- if (token.Type == JTokenType.String) return ReadString(token.Value());
-
- var attribute = (JObject)token;
-
- var value = attribute.Get(ValueName);
- var currencyCode = attribute.Get(CurrencyName);
- var nativeName = attribute.Get(Name, NativeName);
- var englishName = attribute.Get(EnglishName);
- var symbol = attribute.Get(Symbol);
- var iso = attribute.Get(Iso);
- var decimalDigits = attribute.Get(DecimalDigits);
- var currency = string.IsNullOrEmpty(currencyCode ?? iso) ? null : FromIsoCode(currencyCode ?? iso);
-
- var currencyIsEmpty = string.IsNullOrEmpty(currency?.CurrencyIsoCode);
- if (currencyIsEmpty && (string.IsNullOrEmpty(iso) || iso == UnspecifiedCurrency.CurrencyIsoCode))
- {
- return Amount.Unspecified;
- }
-
- if (currencyIsEmpty || !IsKnownCurrency(currency.CurrencyIsoCode))
- {
- currency = new Currency(
- nativeName,
- englishName,
- symbol,
- iso,
- decimalDigits.GetValueOrDefault(DefaultDecimalDigits));
- }
-
- return new Amount(value, currency);
- }
-
- public override void WriteJson(JsonWriter writer, Amount amount, JsonSerializer serializer)
- {
- if (amount.Currency is null) return;
-
- writer.WriteStartObject();
- writer.WritePropertyName(ValueName);
- writer.WriteValue(amount.Value);
-
- if (IsKnownCurrency(amount.Currency.CurrencyIsoCode))
- {
- writer.WritePropertyName(CurrencyName);
- writer.WriteValue(amount.Currency.CurrencyIsoCode);
- }
- else
- {
- writer.WritePropertyName(NativeName);
- writer.WriteValue(amount.Currency.NativeName);
- writer.WritePropertyName(EnglishName);
- writer.WriteValue(amount.Currency.EnglishName);
- writer.WritePropertyName(Symbol);
- writer.WriteValue(amount.Currency.Symbol);
- writer.WritePropertyName(Iso);
- writer.WriteValue(amount.Currency.CurrencyIsoCode);
-
- if (amount.Currency.DecimalPlaces != DefaultDecimalDigits)
- {
- writer.WritePropertyName(DecimalDigits);
- writer.WriteValue(amount.Currency.DecimalPlaces);
- }
- }
-
- writer.WriteEndObject();
- }
-
- public static Amount ReadString(string text)
- {
- var parts = text.Split();
- if (parts.Length < 2) throw new InvalidOperationException($"Unable to parse string amount \"{text}\".");
-
- var currency = FromIsoCode(parts[0]);
- var value = decimal.Parse(string.Join(string.Empty, parts.Skip(1)), CultureInfo.InvariantCulture);
-
- return new Amount(value, currency);
- }
-}
diff --git a/src/Libraries/OrchardCore.Commerce.MoneyDataType/Serialization/LegacyCurrencyConverter.cs b/src/Libraries/OrchardCore.Commerce.MoneyDataType/Serialization/LegacyCurrencyConverter.cs
deleted file mode 100644
index ea89a5894..000000000
--- a/src/Libraries/OrchardCore.Commerce.MoneyDataType/Serialization/LegacyCurrencyConverter.cs
+++ /dev/null
@@ -1,19 +0,0 @@
-using Newtonsoft.Json;
-using OrchardCore.Commerce.MoneyDataType.Abstractions;
-using System;
-
-namespace OrchardCore.Commerce.MoneyDataType.Serialization;
-
-internal sealed class LegacyCurrencyConverter : JsonConverter
-{
- public override ICurrency ReadJson(
- JsonReader reader,
- Type objectType,
- ICurrency existingValue,
- bool hasExistingValue,
- JsonSerializer serializer) =>
- Currency.FromIsoCode(reader.ReadAsString());
-
- public override void WriteJson(JsonWriter writer, ICurrency value, JsonSerializer serializer) =>
- writer.WriteValue(value.CurrencyIsoCode);
-}
diff --git a/src/Modules/OrchardCore.Commerce.ContentFields/Services/FieldsOnlyDisplayManager.cs b/src/Modules/OrchardCore.Commerce.ContentFields/Services/FieldsOnlyDisplayManager.cs
index 8465ce2a3..070192fa5 100644
--- a/src/Modules/OrchardCore.Commerce.ContentFields/Services/FieldsOnlyDisplayManager.cs
+++ b/src/Modules/OrchardCore.Commerce.ContentFields/Services/FieldsOnlyDisplayManager.cs
@@ -80,7 +80,7 @@ public async Task> DisplayFieldsAsync(
var returnUrl = context.Request.PathBase + context.Request.Path + context.Request.QueryString;
var editAction = context.ActionTask(controller => controller.Edit(null, false, returnUrl));
- var createAction = context.ActionTask(controller => controller.Create(false, returnUrl));
+ var createAction = context.ActionTask(controller => controller.Create(null, false, returnUrl));
return (await GetFieldShapeTypesAsync(contentItem, displayType))
.Select(name =>
diff --git a/src/Modules/OrchardCore.Commerce.ContentFields/Settings/AddressFieldSettingsDriver.cs b/src/Modules/OrchardCore.Commerce.ContentFields/Settings/AddressFieldSettingsDriver.cs
index 2f70c0e33..b1f26dfe6 100644
--- a/src/Modules/OrchardCore.Commerce.ContentFields/Settings/AddressFieldSettingsDriver.cs
+++ b/src/Modules/OrchardCore.Commerce.ContentFields/Settings/AddressFieldSettingsDriver.cs
@@ -2,7 +2,7 @@
using OrchardCore.ContentManagement.Metadata.Models;
using OrchardCore.ContentTypes.Editors;
using OrchardCore.DisplayManagement.Views;
-using System;
+using System.Text.Json.Nodes;
using System.Threading.Tasks;
namespace OrchardCore.Commerce.Settings;
@@ -10,9 +10,11 @@ namespace OrchardCore.Commerce.Settings;
public class AddressFieldSettingsDriver : ContentPartFieldDefinitionDisplayDriver
{
public override IDisplayResult Edit(ContentPartFieldDefinition model) =>
- Initialize(
- "AddressFieldSettings_Edit",
- (Action)model.PopulateSettings)
+ Initialize("AddressFieldSettings_Edit", viewModel =>
+ {
+ var settings = model.Settings.ToObject();
+ viewModel.Hint = settings.Hint;
+ })
.PlaceInContent();
public override async Task UpdateAsync(
diff --git a/src/Modules/OrchardCore.Commerce.ContentFields/Startup.cs b/src/Modules/OrchardCore.Commerce.ContentFields/Startup.cs
index f446a316d..1323a069c 100644
--- a/src/Modules/OrchardCore.Commerce.ContentFields/Startup.cs
+++ b/src/Modules/OrchardCore.Commerce.ContentFields/Startup.cs
@@ -15,7 +15,6 @@
using OrchardCore.DisplayManagement.Descriptors;
using OrchardCore.Modules;
using OrchardCore.ResourceManagement;
-
using static OrchardCore.Commerce.ContentFields.Constants.FeatureIds;
namespace OrchardCore.Commerce.ContentFields;
diff --git a/src/Modules/OrchardCore.Commerce.ContentFields/Views/AddressField.cshtml b/src/Modules/OrchardCore.Commerce.ContentFields/Views/AddressField.cshtml
index 73c2f525f..c856fc687 100644
--- a/src/Modules/OrchardCore.Commerce.ContentFields/Views/AddressField.cshtml
+++ b/src/Modules/OrchardCore.Commerce.ContentFields/Views/AddressField.cshtml
@@ -1,7 +1,6 @@
-@model AddressFieldViewModel
-
-@using OrchardCore.Mvc.Utilities
@using OrchardCore.ContentManagement.Metadata.Models
+@using OrchardCore.Mvc.Utilities
+@model AddressFieldViewModel
@{
var definition = Model.PartFieldDefinition;
diff --git a/src/Modules/OrchardCore.Commerce.ContentFields/Views/AddressFieldEditor-WesternCommonNameParts.cshtml b/src/Modules/OrchardCore.Commerce.ContentFields/Views/AddressFieldEditor-WesternCommonNameParts.cshtml
index b1d5dfea9..2d252e917 100644
--- a/src/Modules/OrchardCore.Commerce.ContentFields/Views/AddressFieldEditor-WesternCommonNameParts.cshtml
+++ b/src/Modules/OrchardCore.Commerce.ContentFields/Views/AddressFieldEditor-WesternCommonNameParts.cshtml
@@ -1,15 +1,14 @@
@model AddressFieldEditorViewModel
-@using Newtonsoft.Json
+@using Microsoft.AspNetCore.Mvc.Localization
+@using Microsoft.AspNetCore.Mvc.TagHelpers
@using OrchardCore.Commerce.Abstractions.Fields
@using OrchardCore.Commerce.Abstractions.Models
@using OrchardCore.Commerce.AddressDataType
@using OrchardCore.DisplayManagement
@using OrchardCore.DisplayManagement.TagHelpers
-
+@using System.Text.Json
@using static OrchardCore.Commerce.AddressDataType.Constants.CommonNameParts
-@using Microsoft.AspNetCore.Mvc.TagHelpers
-@using Microsoft.AspNetCore.Mvc.Localization
@{
var namePrefix = Model.CityName[..^(nameof(Address.City).Length)];
@@ -24,7 +23,7 @@
var regions = Model.Regions.Select(region =>
{
- region.Selected = region.Value == address?.Region;
+ region.Selected = region.Value == address.Region;
return region;
});
@@ -112,7 +111,7 @@