Skip to content

Commit 7697740

Browse files
committed
fix phone number duplication
1 parent 22de816 commit 7697740

50 files changed

Lines changed: 1716 additions & 545 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CrestApps.OrchardCore.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
<Project Path="src/Modules/CrestApps.OrchardCore.AzureAIInference/CrestApps.OrchardCore.AzureAIInference.csproj" />
6161
<Project Path="src/Modules/CrestApps.OrchardCore.ContentAccessControl/CrestApps.OrchardCore.ContentAccessControl.csproj" />
6262
<Project Path="src/Modules/CrestApps.OrchardCore.ContentTransfer/CrestApps.OrchardCore.ContentTransfer.csproj" />
63+
<Project Path="src/Modules/CrestApps.OrchardCore.ContentTransfer.OpenXml/CrestApps.OrchardCore.ContentTransfer.OpenXml.csproj" />
6364
<Project Path="src/Modules/CrestApps.OrchardCore.DncRegistry/CrestApps.OrchardCore.DncRegistry.csproj" />
6465
<Project Path="src/Modules/CrestApps.OrchardCore.Ollama/CrestApps.OrchardCore.Ollama.csproj" />
6566
<Project Path="src/Modules/CrestApps.OrchardCore.Omnichannel.EventGrid/CrestApps.OrchardCore.Omnichannel.EventGrid.csproj" />
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using OrchardCore.ContentManagement.Metadata.Models;
2+
3+
namespace CrestApps.OrchardCore.ContentTransfer;
4+
5+
/// <summary>
6+
/// Context passed to <see cref="IContentImportRowFilter.PrepareBatchAsync(ContentImportRowFilterBatchContext)"/>
7+
/// so a filter can preload state for the next import batch.
8+
/// </summary>
9+
public sealed class ContentImportRowFilterBatchContext
10+
{
11+
/// <summary>
12+
/// Gets or sets the content type definition for the import.
13+
/// </summary>
14+
public ContentTypeDefinition ContentTypeDefinition { get; set; }
15+
16+
/// <summary>
17+
/// Gets or sets the content transfer entry associated with the import.
18+
/// </summary>
19+
public ContentTransferEntry Entry { get; set; }
20+
21+
/// <summary>
22+
/// Gets or sets the rows that will be evaluated in the current batch.
23+
/// </summary>
24+
public IReadOnlyList<ContentImportRowFilterContext> Rows { get; set; }
25+
26+
/// <summary>
27+
/// Gets or sets the cancellation token for the current batch operation.
28+
/// </summary>
29+
public CancellationToken CancellationToken { get; set; }
30+
}

src/Abstractions/CrestApps.OrchardCore.ContentTransfer.Abstractions/ContentImportRowFilterContext.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,9 @@ public sealed class ContentImportRowFilterContext
3232
/// Gets or sets the row index (1-based).
3333
/// </summary>
3434
public int RowIndex { get; set; }
35+
36+
/// <summary>
37+
/// Gets or sets the reason the row should be skipped.
38+
/// </summary>
39+
public string SkipReason { get; set; }
3540
}

src/Abstractions/CrestApps.OrchardCore.ContentTransfer.Abstractions/IContentImportRowFilter.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@ public interface IContentImportRowFilter
2222
/// </returns>
2323
Task<bool> InitializeAsync(ContentImportRowFilterInitContext context);
2424

25+
/// <summary>
26+
/// Prepares filter state for the next import batch.
27+
/// </summary>
28+
/// <param name="context">The context containing the rows that are about to be evaluated.</param>
29+
/// <returns>A task that completes when the batch state is ready.</returns>
30+
Task PrepareBatchAsync(ContentImportRowFilterBatchContext context);
31+
2532
/// <summary>
2633
/// Determines whether a row should be skipped during import.
2734
/// </summary>

src/Core/CrestApps.OrchardCore.ContentTransfer.Core/Services/ContentImportManager.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public async Task<IReadOnlyCollection<ImportColumn>> GetColumnsAsync(ImportConte
4949
if (part == null)
5050
{
5151
part = partActivator.CreateInstance();
52-
part.Weld(typePartDefinition.Name, part);
52+
contentItem.Weld(typePartDefinition.Name, part);
5353
}
5454

5555
var partHandlers = _contentImportHandlerResolver.GetPartHandlers(partName);
@@ -134,7 +134,7 @@ public async Task ImportAsync(ContentImportContext context)
134134
if (part == null)
135135
{
136136
part = partActivator.CreateInstance();
137-
part.Weld(typePartDefinition.Name, part);
137+
context.ContentItem.Weld(typePartDefinition.Name, part);
138138
}
139139

140140
foreach (var partFieldDefinition in typePartDefinition.PartDefinition.Fields)
@@ -182,7 +182,7 @@ public async Task ExportAsync(ContentExportContext context)
182182
if (part == null)
183183
{
184184
part = partActivator.CreateInstance();
185-
part.Weld(typePartDefinition.Name, part);
185+
context.ContentItem.Weld(typePartDefinition.Name, part);
186186
}
187187

188188
var partHandlers = _contentImportHandlerResolver.GetPartHandlers(partName);

src/Core/CrestApps.OrchardCore.Omnichannel.Core/Indexes/OmnichannelContactIndex.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,21 @@ public sealed class OmnichannelContactIndex : MapIndex
1717
/// </summary>
1818
public string PrimaryCellPhoneNumber { get; set; }
1919

20+
/// <summary>
21+
/// Gets or sets the normalized primary cell phone number.
22+
/// </summary>
23+
public string NormalizedPrimaryCellPhoneNumber { get; set; }
24+
2025
/// <summary>
2126
/// Gets or sets the primary home phone number.
2227
/// </summary>
2328
public string PrimaryHomePhoneNumber { get; set; }
2429

30+
/// <summary>
31+
/// Gets or sets the normalized primary home phone number.
32+
/// </summary>
33+
public string NormalizedPrimaryHomePhoneNumber { get; set; }
34+
2535
/// <summary>
2636
/// Gets or sets the primary email address.
2737
/// </summary>

src/CrestApps.Docs/docs/changelog/v2.0.0.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,14 @@ Large parts of the reusable AI infrastructure are no longer implemented only ins
111111
- Azure AI Search index editors for **AI Documents** and **AI Memory** now normalize their built-in managed mappings on load and update so repeated edits do not keep appending duplicate `Content`, `Embedding`, and related managed fields, while custom mappings remain preserved
112112
- The **Clear saved AI memory** action in the current user's profile editor now uses Orchard Core's standard admin confirmation dialog and clears the user's saved memory entries by filtering the store's persisted records for the current user before removing the corresponding indexed AI memory documents
113113
- Content Transfer content-type settings now default **Allow Bulk Import** and **Allow Bulk Export** to enabled, so content types participate by default and can explicitly opt out by turning either setting off
114-
- Omnichannel contact import and export now map the first contact-method bag entries to workbook `Email`, `Cell Phone`, and `Phone` columns, also read and write `DoNotCall`, `DoNotCallUtc`, `DoNotSms`, `DoNotSmsUtc`, `DoNotEmail`, `DoNotEmailUtc`, `DoNotChat`, and `DoNotChatUtc` on `OmnichannelContactPart`, support duplicate-phone filtering during import, and can enforce national do-not-call registry checks through **Settings** -> **Import Content Settings**
114+
- Content Transfer now keeps CSV support in the base `CrestApps.OrchardCore.ContentTransfer` feature and moves optional `.xlsx` support into `CrestApps.OrchardCore.ContentTransfer.OpenXml`, with the import and export UI showing only the file extensions enabled by the current tenant feature set
115+
- Content Transfer now welds lazily created parts onto the parent content item during column discovery, import, and export so `.xlsx` exports no longer fail with a `System.Text.Json` node-cycle exception when a content item does not already materialize one of its configured parts
116+
- Omnichannel contact import and export now map the first contact-method bag entries to workbook `Email`, `Cell Phone`, and `Phone` columns, also read and write `DoNotCall`, `DoNotCallUtc`, `DoNotSms`, `DoNotSmsUtc`, `DoNotEmail`, `DoNotEmailUtc`, `DoNotChat`, and `DoNotChatUtc` on `OmnichannelContactPart`, advertise `true` and `false` for the `DoNot*` boolean columns, default duplicate-phone filtering to enabled, add skipped duplicate rows to the error export with a reason, batch-check duplicate phone numbers against both the import file and the existing Orchard contact records, fall back to legacy stored phone values when older tenants have not yet backfilled normalized-phone indexes, and can enforce national do-not-call registry checks through **Settings** -> **Import Content Settings**
115117
- Omnichannel contact definitions now enforce a fixed `ContactMethods` bag for content types that attach `OmnichannelContactPart`, while `OmnichannelContactPart` itself owns the contact-level Do-Not-Call, Do-Not-SMS, Do-Not-Email, and Do-Not-Chat compliance flags so omnichannel indexing, campaign actions, and activity loading all use one C#-controlled contact model
116118
- Omnichannel Management now declares the `OrchardCore.Flows` feature dependency required to render the enforced `ContactMethods` bag editor on content types that attach `OmnichannelContactPart`
117119
- Omnichannel contact type definitions now inject the named `ContactMethods` bag from Orchard's `IContentDefinitionHandler` build pipeline, ensuring the bag materializes whenever a content type attaches `OmnichannelContactPart` even before any stored definition repair runs
118120
- DNC registry provider configuration is now split into dedicated settings pages under **Settings** -> **DNC Registries** with separate **USA FTC Registry** and **Canada LNNTE-DNCL Registry** pages, and registry API keys are stored as protected values instead of being shown back in the UI
121+
- DNC registry settings navigation now only shows **USA FTC Registry** and **Canada LNNTE-DNCL Registry** when their matching provider features are enabled, which fixes the 404 links from the shared DNC settings menu
119122
- DNC registry providers now expose their shared contract through `CrestApps.OrchardCore.DncRegistry.Abstractions`, and Content Transfer row filters now use `InitializeAsync` to opt into an import while keeping import-scoped filtering state on the filter instance itself
120123

121124
### Typed AI deployments replace legacy deployment selectors
@@ -223,8 +226,9 @@ Review the current admin navigation after upgrade and update any operator docume
223226
### Content Transfer module
224227

225228
- added `CrestApps.OrchardCore.ContentTransfer`, `CrestApps.OrchardCore.ContentTransfer.Core`, and `CrestApps.OrchardCore.ContentTransfer.Abstractions`
229+
- added `CrestApps.OrchardCore.ContentTransfer.OpenXml` so Excel workbook support can be enabled separately from the base CSV transfer feature
226230
- added unit coverage for the imported content transfer services and Excel validation behavior
227-
- added module documentation for bulk Excel-based content import and export
231+
- added module documentation for bulk content import and export across CSV and optional OpenXml workbook formats
228232

229233
### Orchestrator-based AI execution
230234

0 commit comments

Comments
 (0)