From cb503770e3eab4cde2a0a2c72104a72d46e86142 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Fri, 8 May 2026 17:06:47 +0200 Subject: [PATCH 01/56] ATR-966: reworked and extended concurrent utils - added extensions for value tasks, added catching of all exceptions, not just operation cancelled exceptions --- .../Acuminator.Utilities.csproj | 1 + .../Common/Concurrent/ConcurrentExtensions.cs | 61 +++++++++++++++++-- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/src/Acuminator/Acuminator.Utilities/Acuminator.Utilities.csproj b/src/Acuminator/Acuminator.Utilities/Acuminator.Utilities.csproj index ad7a4aa1d..347706ef8 100644 --- a/src/Acuminator/Acuminator.Utilities/Acuminator.Utilities.csproj +++ b/src/Acuminator/Acuminator.Utilities/Acuminator.Utilities.csproj @@ -15,6 +15,7 @@ ../../packages enable Nullable + $(NoWarn);CS0168 https://github.com/Acumatica/Acuminator/blob/dev/LICENSE diff --git a/src/Acuminator/Acuminator.Utilities/Common/Concurrent/ConcurrentExtensions.cs b/src/Acuminator/Acuminator.Utilities/Common/Concurrent/ConcurrentExtensions.cs index 26ce6b61e..4e1d87bae 100644 --- a/src/Acuminator/Acuminator.Utilities/Common/Concurrent/ConcurrentExtensions.cs +++ b/src/Acuminator/Acuminator.Utilities/Common/Concurrent/ConcurrentExtensions.cs @@ -35,18 +35,41 @@ public static void Clear(this ConcurrentQueue? queue) /// A Task extension method that attempts to await task which could be cancelled. /// /// The task to act on. + /// (Optional) True to continue on captured context. /// - public async static Task TryAwait(this Task? task) + public async static Task TryAwait(this Task? task, bool continueOnCapturedContext = false) { if (task == null || task.IsCanceled || task.IsFaulted) return false; try { - await task.ConfigureAwait(false); + await task.ConfigureAwait(continueOnCapturedContext); return true; } - catch (OperationCanceledException) + catch (Exception exception) + { + return false; + } + } + + /// + /// A extension method that attempts to await task which could be cancelled. + /// + /// The task to act on. + /// (Optional) True to continue on captured context. + /// + public async static ValueTask TryAwait(this ValueTask? task, bool continueOnCapturedContext = false) + { + if (task == null || task.Value.IsCanceled || task.Value.IsFaulted) + return false; + + try + { + await task.Value.ConfigureAwait(continueOnCapturedContext); + return true; + } + catch (Exception exception) { return false; } @@ -57,18 +80,44 @@ public async static Task TryAwait(this Task? task) /// /// Type of the result. /// The task to act on. + /// (Optional) True to continue on captured context. /// - public async static Task> TryAwait(this Task? task) + public async static Task> TryAwait(this Task? task, + bool continueOnCapturedContext = false) { if (task == null || task.IsCanceled || task.IsFaulted) return new TaskResult(false, default); try { - TResult? result = await task.ConfigureAwait(false); + TResult? result = await task.ConfigureAwait(continueOnCapturedContext); + return new TaskResult(true, result); + } + catch (Exception exception) + { + return new TaskResult(false, default); + } + } + + /// + /// A extension method that attempts to await task which could be cancelled. + /// + /// Type of the result. + /// The task to act on. + /// (Optional) True to continue on captured context. + /// + public async static ValueTask> TryAwait(this ValueTask? task, + bool continueOnCapturedContext = false) + { + if (task == null || task.Value.IsCanceled || task.Value.IsFaulted) + return new TaskResult(false, default); + + try + { + TResult? result = await task.Value.ConfigureAwait(continueOnCapturedContext); return new TaskResult(true, result); } - catch (OperationCanceledException) + catch (Exception exception) { return new TaskResult(false, default); } From 716400e53fcbd10159ce92cc2e658c7c4a4e0edc Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Fri, 8 May 2026 17:19:12 +0200 Subject: [PATCH 02/56] ATR-966: fixed file indentation and formatting --- .../Coloriser/Base/PXTaggerBase.cs | 152 +++++++++--------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs index f0124e882..1b7ed61db 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs @@ -15,78 +15,78 @@ namespace Acuminator.Vsix.Coloriser { - /// - /// Values that represent tagger types. - /// - public enum TaggerType - { - /// - /// The general tagger which chooses other taggers according to the settings. - /// - General, - - /// - /// The tagger based on Roslyn - /// - Roslyn, - - /// - /// The tagger based on regular expressions - /// - RegEx, - - /// - /// The tagger used for outlining - /// - Outlining - }; - - public abstract class PXTaggerBase : IDisposable - { + /// + /// Values that represent tagger types. + /// + public enum TaggerType + { + /// + /// The general tagger which chooses other taggers according to the settings. + /// + General, + + /// + /// The tagger based on Roslyn + /// + Roslyn, + + /// + /// The tagger based on regular expressions + /// + RegEx, + + /// + /// The tagger used for outlining + /// + Outlining + }; + + public abstract class PXTaggerBase : IDisposable + { #pragma warning disable CS0067 - public event EventHandler? TagsChanged; + public event EventHandler? TagsChanged; #pragma warning restore CS0067 - protected ITextBuffer Buffer { get; } + protected ITextBuffer Buffer { get; } - protected internal ITextSnapshot? Snapshot { get; private set; } + protected internal ITextSnapshot? Snapshot { get; private set; } - protected bool ColoringSettingsChanged { get; private set; } + protected bool ColoringSettingsChanged { get; private set; } - protected bool SubscribedToSettingsChanges { get; private set; } + protected bool SubscribedToSettingsChanges { get; private set; } - protected PXTaggerProviderBase ProviderBase { get; } + protected PXTaggerProviderBase ProviderBase { get; } - /// - /// The type of the tagger. - /// - public abstract TaggerType TaggerType { get; } + /// + /// The type of the tagger. + /// + public abstract TaggerType TaggerType { get; } - protected bool CacheCheckingEnabled { get; } + protected bool CacheCheckingEnabled { get; } - protected PXTaggerBase(ITextBuffer buffer, PXTaggerProviderBase provider, bool subscribeToSettingsChanges, bool useCacheChecking) - { - Buffer = buffer.CheckIfNull(); - ProviderBase = provider.CheckIfNull(); - SubscribedToSettingsChanges = subscribeToSettingsChanges; - CacheCheckingEnabled = useCacheChecking; + protected PXTaggerBase(ITextBuffer buffer, PXTaggerProviderBase provider, bool subscribeToSettingsChanges, bool useCacheChecking) + { + Buffer = buffer.CheckIfNull(); + ProviderBase = provider.CheckIfNull(); + SubscribedToSettingsChanges = subscribeToSettingsChanges; + CacheCheckingEnabled = useCacheChecking; - if (SubscribedToSettingsChanges) - { - var genOptionsPage = AcuminatorVSPackage.Instance?.GeneralOptionsPage; + if (SubscribedToSettingsChanges) + { + var genOptionsPage = AcuminatorVSPackage.Instance?.GeneralOptionsPage; - if (genOptionsPage != null) - { - genOptionsPage.ColoringSettingChanged += ColoringSettingChangedHandler; - } - } - } + if (genOptionsPage != null) + { + genOptionsPage.ColoringSettingChanged += ColoringSettingChangedHandler; + } + } + } - protected virtual void ColoringSettingChangedHandler(object sender, SettingChangedEventArgs e) - { - ColoringSettingsChanged = true; + protected virtual void ColoringSettingChangedHandler(object sender, SettingChangedEventArgs e) + { + ColoringSettingsChanged = true; Shell.ThreadHelper.JoinableTaskFactory.Run(RaiseTagsChangedAsync); - } + } internal async virtual Task RaiseTagsChangedAsync() { @@ -101,26 +101,26 @@ internal async virtual Task RaiseTagsChangedAsync() new Span(0, Buffer.CurrentSnapshot.Length)))); } - protected internal virtual void ResetCacheAndFlags(ITextSnapshot newCache) - { - ColoringSettingsChanged = false; - Snapshot = newCache; - } + protected internal virtual void ResetCacheAndFlags(ITextSnapshot newCache) + { + ColoringSettingsChanged = false; + Snapshot = newCache; + } - protected virtual bool CheckIfRetaggingIsNotNecessary(ITextSnapshot snapshot) => - CacheCheckingEnabled && Snapshot != null && Snapshot == snapshot && !ColoringSettingsChanged; + protected virtual bool CheckIfRetaggingIsNotNecessary(ITextSnapshot snapshot) => + CacheCheckingEnabled && Snapshot != null && Snapshot == snapshot && !ColoringSettingsChanged; - public virtual void Dispose() - { - if (!SubscribedToSettingsChanges) - return; + public virtual void Dispose() + { + if (!SubscribedToSettingsChanges) + return; - var genOptionsPage = AcuminatorVSPackage.Instance?.GeneralOptionsPage; + var genOptionsPage = AcuminatorVSPackage.Instance?.GeneralOptionsPage; - if (genOptionsPage != null) - { - genOptionsPage.ColoringSettingChanged -= ColoringSettingChangedHandler; - } - } - } + if (genOptionsPage != null) + { + genOptionsPage.ColoringSettingChanged -= ColoringSettingChangedHandler; + } + } + } } From 966c42aa626ef75da24e98c0494f8d6c0b5b6732 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Fri, 8 May 2026 17:26:21 +0200 Subject: [PATCH 03/56] ATR-966: refactoring - fixed mistype --- .../Acuminator.Vsix/Coloriser/PXColorizerTaggerProvider.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerProvider.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerProvider.cs index e3618aa1e..d0b3d6f31 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerProvider.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerProvider.cs @@ -94,7 +94,7 @@ protected override void Initialize(ITextBuffer textBuffer) AreClassificationsInitialized = true; InitializeClassificationTypes(); - IncreaseCommentFormatTypesPrioirity(_classificationRegistry, _classificationFormatMapService, + IncreaseCommentFormatTypesPriority(_classificationRegistry, _classificationFormatMapService, _codeColoringClassificationTypes[PXCodeType.BqlParameter]); } @@ -142,7 +142,7 @@ protected void InitializeClassificationTypes() }; } - private static void IncreaseCommentFormatTypesPrioirity(IClassificationTypeRegistryService registry, IClassificationFormatMapService formatMapService, + private static void IncreaseCommentFormatTypesPriority(IClassificationTypeRegistryService registry, IClassificationFormatMapService formatMapService, IClassificationType highestPriorityType) { bool lockTaken = false; From 5e106261fd710f734051af7b5e066f8c489647da Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Fri, 8 May 2026 18:19:44 +0200 Subject: [PATCH 04/56] ATR-966: refactoring - fixed mistype and renamed file --- ....cs => PXRoslynColorizerTagger.PXColorizerSyntaxWalker.cs} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/{PXColoriserSyntaxWalker.cs => PXRoslynColorizerTagger.PXColorizerSyntaxWalker.cs} (99%) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXColoriserSyntaxWalker.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXRoslynColorizerTagger.PXColorizerSyntaxWalker.cs similarity index 99% rename from src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXColoriserSyntaxWalker.cs rename to src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXRoslynColorizerTagger.PXColorizerSyntaxWalker.cs index 296e2d84c..c087142ad 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXColoriserSyntaxWalker.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXRoslynColorizerTagger.PXColorizerSyntaxWalker.cs @@ -28,7 +28,7 @@ namespace Acuminator.Vsix.Coloriser { public partial class PXRoslynColorizerTagger : PXColorizerTaggerBase { - protected class PXColoriserSyntaxWalker : CSharpSyntaxWalker + protected class PXColorizerSyntaxWalker : CSharpSyntaxWalker { private const string VarKeyword = "var"; @@ -43,7 +43,7 @@ protected class PXColoriserSyntaxWalker : CSharpSyntaxWalker private bool IsInsideBqlCommand => _bqlDeepnessLevel > 0; - public PXColoriserSyntaxWalker(PXRoslynColorizerTagger tagger, ParsedDocument parsedDocument, CancellationToken cToken) : + public PXColorizerSyntaxWalker(PXRoslynColorizerTagger tagger, ParsedDocument parsedDocument, CancellationToken cToken) : base(SyntaxWalkerDepth.Node) { _tagger = tagger.CheckIfNull(); From 8af26d919303712eaa6d94e1c0e139eace05ee64 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Fri, 8 May 2026 18:32:21 +0200 Subject: [PATCH 05/56] ATR-966: added LastTaggingWasSuccessful flag to the base tagger class to avoid skipping re-tagging on faulted tagging tasks --- .../Coloriser/Base/PXTaggerBase.cs | 6 +++- .../MainTagger/PXColorizerMainTagger.cs | 33 +++++++++++++++++-- .../Coloriser/Outlining/PXOutliningTagger.cs | 6 ++++ .../Coloriser/Regex/PXRegexColorizerTagger.cs | 19 ++++++++++- .../Roslyn/PXRoslynColorizerTagger.cs | 10 ++++-- 5 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs index 1b7ed61db..a4294393d 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs @@ -55,6 +55,8 @@ public abstract class PXTaggerBase : IDisposable protected bool SubscribedToSettingsChanges { get; private set; } + internal abstract bool LastTaggingWasSuccessful { get; set; } + protected PXTaggerProviderBase ProviderBase { get; } /// @@ -85,6 +87,7 @@ protected PXTaggerBase(ITextBuffer buffer, PXTaggerProviderBase provider, bool s protected virtual void ColoringSettingChangedHandler(object sender, SettingChangedEventArgs e) { ColoringSettingsChanged = true; + LastTaggingWasSuccessful = false; Shell.ThreadHelper.JoinableTaskFactory.Run(RaiseTagsChangedAsync); } @@ -104,11 +107,12 @@ internal async virtual Task RaiseTagsChangedAsync() protected internal virtual void ResetCacheAndFlags(ITextSnapshot newCache) { ColoringSettingsChanged = false; + LastTaggingWasSuccessful = false; Snapshot = newCache; } protected virtual bool CheckIfRetaggingIsNotNecessary(ITextSnapshot snapshot) => - CacheCheckingEnabled && Snapshot != null && Snapshot == snapshot && !ColoringSettingsChanged; + CacheCheckingEnabled && Snapshot != null && Snapshot == snapshot && !ColoringSettingsChanged && LastTaggingWasSuccessful; public virtual void Dispose() { diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/MainTagger/PXColorizerMainTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/MainTagger/PXColorizerMainTagger.cs index 3a9452344..db6787c9f 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/MainTagger/PXColorizerMainTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/MainTagger/PXColorizerMainTagger.cs @@ -27,7 +27,8 @@ public class PXColorizerMainTagger : PXColorizerTaggerBase protected internal override bool UseAsyncTagging { - get { + get + { TaggerType currentTaggerType = GetCurrentTaggerTypeFromSettings(); return _taggersByType.TryGetValue(currentTaggerType, out PXColorizerTaggerBase tagger) ? tagger.UseAsyncTagging @@ -37,7 +38,8 @@ protected internal override bool UseAsyncTagging protected internal override ITagsCache ClassificationTagsCache { - get { + get + { TaggerType currentTaggerType = GetCurrentTaggerTypeFromSettings(); return _taggersByType.TryGetValue(currentTaggerType, out PXColorizerTaggerBase tagger) ? tagger.ClassificationTagsCache @@ -47,7 +49,8 @@ protected internal override ITagsCache ClassificationTagsCac protected internal override ITagsCache OutliningsTagsCache { - get { + get + { TaggerType currentTaggerType = GetCurrentTaggerTypeFromSettings(); return _taggersByType.TryGetValue(currentTaggerType, out PXColorizerTaggerBase tagger) ? tagger.OutliningsTagsCache @@ -55,6 +58,30 @@ protected internal override ITagsCache OutliningsTagsCache } } + internal override bool LastTaggingWasSuccessful + { + get + { + TaggerType currentTaggerType = GetCurrentTaggerTypeFromSettings(); + return _taggersByType.TryGetValue(currentTaggerType, out PXColorizerTaggerBase tagger) + ? tagger.LastTaggingWasSuccessful + : throw new NotSupportedException($"Tagger type {currentTaggerType} not supported"); + } + set + { + TaggerType currentTaggerType = GetCurrentTaggerTypeFromSettings(); + + if (_taggersByType.TryGetValue(currentTaggerType, out PXColorizerTaggerBase tagger)) + { + tagger.LastTaggingWasSuccessful = value; + } + else + { + throw new NotSupportedException($"Tagger type {currentTaggerType} not supported"); + } + } + } + public PXColorizerMainTagger(ITextBuffer buffer, PXColorizerTaggerProvider aProvider, bool subscribeToSettingsChanges, bool useCacheChecking) : base(buffer, aProvider, subscribeToSettingsChanges, useCacheChecking) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs index a52a5d1a2..921748feb 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs @@ -25,6 +25,12 @@ public class PXOutliningTagger : PXTaggerBase, ITagger protected PXColorizerTaggerBase? ColorizerTagger { get; private set; } + internal override bool LastTaggingWasSuccessful + { + get => ColorizerTagger?.LastTaggingWasSuccessful ?? false; + set { } + } + public PXOutliningTagger(ITextBuffer buffer, PXOutliningTaggerProvider aProvider, bool subscribeToSettingsChanges, bool useCacheChecking) : base(buffer, aProvider, subscribeToSettingsChanges, useCacheChecking) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/PXRegexColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/PXRegexColorizerTagger.cs index d368e2a07..fd3ec153a 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/PXRegexColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/PXRegexColorizerTagger.cs @@ -32,6 +32,7 @@ internal class PXRegexColorizerTagger : PXColorizerTaggerBase protected internal override ITagsCache OutliningsTagsCache => _outliningTagsCache; + internal override bool LastTaggingWasSuccessful { get; set; } private readonly ConcurrentBag> _tagsBag = new ConcurrentBag>(); @@ -48,17 +49,33 @@ protected internal async override Task> .TryAwait(); if (!taggingInfo.IsSuccess) + { + LastTaggingWasSuccessful = false; return []; + } return taggingInfo.Result ?? []; } protected internal override IEnumerable> GetTagsSynchronousImplementation(ITextSnapshot snapshot) { - GetTagsFromSnapshot(snapshot); + bool success; + + try + { + GetTagsFromSnapshot(snapshot); + success = true; + } + catch (Exception) + { + success = false; + } + _classificationTagsCache.AddTags(_tagsBag); ClassificationTagsCache.CompleteProcessing(); OutliningsTagsCache.CompleteProcessing(); + LastTaggingWasSuccessful = success && ClassificationTagsCache.IsCompleted; + return ClassificationTagsCache; } diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXRoslynColorizerTagger.cs index 6db789637..e00ac242b 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXRoslynColorizerTagger.cs @@ -27,6 +27,8 @@ public partial class PXRoslynColorizerTagger : PXColorizerTaggerBase protected internal override ITagsCache OutliningsTagsCache => _outliningTagsCache; + internal override bool LastTaggingWasSuccessful { get; set; } + internal PXRoslynColorizerTagger(ITextBuffer buffer, PXColorizerTaggerProvider aProvider, bool subscribeToSettingsChanges, bool useCacheChecking) : base(buffer, aProvider, subscribeToSettingsChanges, useCacheChecking) @@ -103,7 +105,10 @@ protected internal override IEnumerable> GetTagsSyn #pragma warning restore VSTHRD002 // Avoid problematic synchronous waits if (document != null) + { WalkDocumentSyntaxTreeForTags(document, CancellationToken.None); + LastTaggingWasSuccessful = ClassificationTagsCache.IsCompleted; + } //documentCache = document; //isParsed = true; @@ -131,13 +136,14 @@ protected internal async override Task> if (document == null || cToken.IsCancellationRequested) return ClassificationTagsCache.ProcessedTags; - await WalkDocumentSyntaxTreeForTagsAsync(document, cToken).TryAwait(); + bool completedSuccessfully = await WalkDocumentSyntaxTreeForTagsAsync(document, cToken).TryAwait(); + LastTaggingWasSuccessful = completedSuccessfully && ClassificationTagsCache.IsCompleted; return ClassificationTagsCache.ProcessedTags; } private void WalkDocumentSyntaxTreeForTags(ParsedDocument document, CancellationToken cancellationToken) { - var syntaxWalker = new PXColoriserSyntaxWalker(this, document, cancellationToken); + var syntaxWalker = new PXColorizerSyntaxWalker(this, document, cancellationToken); syntaxWalker.Visit(document.SyntaxRoot); ClassificationTagsCache.CompleteProcessing(); From 079f5481af389d7b801f37703120d6174dc6dda8 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Fri, 8 May 2026 18:32:53 +0200 Subject: [PATCH 06/56] ATR-966: added more error processing for tagging faluts to the background tagging --- .../Coloriser/AsyncTagging/BackgroundTagging.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/BackgroundTagging.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/BackgroundTagging.cs index 69e2418e2..5818edec2 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/BackgroundTagging.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/BackgroundTagging.cs @@ -48,9 +48,9 @@ public static BackgroundTagging StartBackgroundTagging(PXColorizerTaggerBase tag // No need for synchronization because FromCurrentSynchronizationContext creates schedulers which wrap around the same synchronization context // Therefore all schedulers should be identical and nothing wrong will happen if different thread will create multiple instance of the scheduler in a race condition _vsTaskScheduler = _vsTaskScheduler ?? TaskScheduler.FromCurrentSynchronizationContext(); - backgroundTagging.TaggingTask = taggingTask.ContinueWith(task => AfterTaggingActionAsync(tagger, backgroundTagging.CancellationToken), //continuation should be on the UI thread + backgroundTagging.TaggingTask = taggingTask.ContinueWith(task => AfterTaggingActionAsync(task, tagger, backgroundTagging.CancellationToken), //continuation should be on the UI thread backgroundTagging.CancellationToken, - TaskContinuationOptions.OnlyOnRanToCompletion, + TaskContinuationOptions.NotOnCanceled, _vsTaskScheduler); return backgroundTagging; } @@ -76,10 +76,19 @@ public void Dispose() _cancellationTokenSource.Dispose(); } - private static Task AfterTaggingActionAsync(PXColorizerTaggerBase tagger, CancellationToken cancellationToken) + private static Task AfterTaggingActionAsync(Task taggingTask, PXColorizerTaggerBase tagger, CancellationToken cancellationToken) { - if (cancellationToken.IsCancellationRequested) + if (taggingTask.IsCanceled || cancellationToken.IsCancellationRequested) + { + tagger.LastTaggingWasSuccessful = false; return Task.FromCanceled(cancellationToken); + } + + if (taggingTask.IsFaulted) + { + tagger.LastTaggingWasSuccessful = false; + return Task.FromException(taggingTask.Exception!); + } // We should be on UI thread here but the tagger.RaiseTagsChangedAsync switches to UI thread from non UI threads internally if needed return Shell.ThreadHelper.JoinableTaskFactory.RunAsync(tagger.RaiseTagsChangedAsync).Task; From 21221cb58130ea5c1d034c4e5f77453be071167f Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Tue, 12 May 2026 08:22:53 +0200 Subject: [PATCH 07/56] ATR-966: refactored tagger type enum into a separate file --- .../Coloriser/Base/PXTaggerBase.cs | 26 ---------------- .../Coloriser/Base/TaggerType.cs | 30 +++++++++++++++++++ 2 files changed, 30 insertions(+), 26 deletions(-) create mode 100644 src/Acuminator/Acuminator.Vsix/Coloriser/Base/TaggerType.cs diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs index a4294393d..9e7b69369 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs @@ -15,32 +15,6 @@ namespace Acuminator.Vsix.Coloriser { - /// - /// Values that represent tagger types. - /// - public enum TaggerType - { - /// - /// The general tagger which chooses other taggers according to the settings. - /// - General, - - /// - /// The tagger based on Roslyn - /// - Roslyn, - - /// - /// The tagger based on regular expressions - /// - RegEx, - - /// - /// The tagger used for outlining - /// - Outlining - }; - public abstract class PXTaggerBase : IDisposable { #pragma warning disable CS0067 diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/TaggerType.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/TaggerType.cs new file mode 100644 index 000000000..e63c44fe9 --- /dev/null +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/TaggerType.cs @@ -0,0 +1,30 @@ +#nullable enable + +namespace Acuminator.Vsix.Coloriser +{ + /// + /// Values that represent tagger types. + /// + public enum TaggerType + { + /// + /// The general tagger which chooses other taggers according to the settings. + /// + General, + + /// + /// The tagger based on Roslyn + /// + Roslyn, + + /// + /// The tagger based on regular expressions + /// + RegEx, + + /// + /// The tagger used for outlining + /// + Outlining + }; +} From a4550f85b0e0a8b7833e737c30614ebe1186367a Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Tue, 12 May 2026 12:22:45 +0200 Subject: [PATCH 08/56] ATR-966: refactoring - used more sensitive parameter name --- .../Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs | 4 ++-- .../Coloriser/MainTagger/PXColorizerMainTagger.cs | 6 +++--- .../Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs | 4 ++-- .../Coloriser/Regex/PXRegexColorizerTagger.cs | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs index 9e7b69369..7d0559b0d 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs @@ -78,11 +78,11 @@ internal async virtual Task RaiseTagsChangedAsync() new Span(0, Buffer.CurrentSnapshot.Length)))); } - protected internal virtual void ResetCacheAndFlags(ITextSnapshot newCache) + protected internal virtual void ResetCacheAndFlags(ITextSnapshot newSnapshotToCache) { ColoringSettingsChanged = false; LastTaggingWasSuccessful = false; - Snapshot = newCache; + Snapshot = newSnapshotToCache; } protected virtual bool CheckIfRetaggingIsNotNecessary(ITextSnapshot snapshot) => diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/MainTagger/PXColorizerMainTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/MainTagger/PXColorizerMainTagger.cs index db6787c9f..6f226a67c 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/MainTagger/PXColorizerMainTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/MainTagger/PXColorizerMainTagger.cs @@ -134,10 +134,10 @@ public override void Dispose() base.Dispose(); } - protected internal override void ResetCacheAndFlags(ITextSnapshot newCache) + protected internal override void ResetCacheAndFlags(ITextSnapshot newSnapshotToCache) { - base.ResetCacheAndFlags(newCache); - _taggersByType.Values.ForEach(tagger => tagger.ResetCacheAndFlags(newCache)); + base.ResetCacheAndFlags(newSnapshotToCache); + _taggersByType.Values.ForEach(tagger => tagger.ResetCacheAndFlags(newSnapshotToCache)); } protected TaggerType GetCurrentTaggerTypeFromSettings() diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs index a4812a06d..2cd6d3532 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs @@ -35,9 +35,9 @@ protected PXColorizerTaggerBase(ITextBuffer buffer, PXColorizerTaggerProvider aP { } - protected internal override void ResetCacheAndFlags(ITextSnapshot newCache) + protected internal override void ResetCacheAndFlags(ITextSnapshot newSnapshotToCache) { - base.ResetCacheAndFlags(newCache); + base.ResetCacheAndFlags(newSnapshotToCache); ClassificationTagsCache.Reset(); OutliningsTagsCache.Reset(); } diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/PXRegexColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/PXRegexColorizerTagger.cs index fd3ec153a..51602f56f 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/PXRegexColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/PXRegexColorizerTagger.cs @@ -79,9 +79,9 @@ protected internal override IEnumerable> GetTagsSyn return ClassificationTagsCache; } - protected internal override void ResetCacheAndFlags(ITextSnapshot newCache) + protected internal override void ResetCacheAndFlags(ITextSnapshot newSnapshotToCache) { - base.ResetCacheAndFlags(newCache); + base.ResetCacheAndFlags(newSnapshotToCache); _tagsBag.Clear(); } From 4aacc69999aa63d3de53d21d94efddb2f1494619 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Tue, 12 May 2026 12:26:44 +0200 Subject: [PATCH 09/56] ATR-966: removed the check for the reference to Acumatica platform from tagger providers because it happens too early when workspace is not initialized yet. The check should be moved to taggers instead. Added check of UI thread to all tagger providers. --- .../Acuminator.Vsix/Coloriser/Base/PXTaggerProviderBase.cs | 6 +----- .../Coloriser/Outlining/PXOutliningTaggerProvider.cs | 3 --- .../Acuminator.Vsix/Coloriser/PXColorizerTaggerProvider.cs | 7 ++++++- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerProviderBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerProviderBase.cs index 5036ccd68..fe398bc84 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerProviderBase.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerProviderBase.cs @@ -14,18 +14,14 @@ namespace Acuminator.Vsix.Coloriser { public abstract class PXTaggerProviderBase { - protected bool HasReferenceToAcumaticaPlatform { get; private set; } - public Workspace? Workspace { get; private set; } /// - /// Initializes the base fields - and . + /// Initializes the base . /// protected virtual void Initialize(ITextBuffer buffer) { Workspace = buffer?.GetWorkspace(); - HasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(); - } protected bool CheckIfCurrentSolutionHasReferenceToAcumatica() { diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTaggerProvider.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTaggerProvider.cs index 8b8cd5728..617845b41 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTaggerProvider.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTaggerProvider.cs @@ -27,9 +27,6 @@ public class PXOutliningTaggerProvider : PXTaggerProviderBase, ITaggerProvider Initialize(buffer); - if (!HasReferenceToAcumaticaPlatform) - return null; - PXOutliningTagger outliningTagger = buffer.Properties.GetOrCreateSingletonProperty(() => { return new PXOutliningTagger(buffer, this, subscribeToSettingsChanges: true, useCacheChecking: true); diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerProvider.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerProvider.cs index d0b3d6f31..4c9cb8cb4 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerProvider.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerProvider.cs @@ -19,6 +19,8 @@ using Microsoft.VisualStudio.Text.Tagging; using Microsoft.VisualStudio.Utilities; +using ThreadHelper = Microsoft.VisualStudio.Shell.ThreadHelper; + namespace Acuminator.Vsix.Coloriser { [ContentType(Constants.CSharp.LegacyLanguageName)] @@ -71,9 +73,12 @@ public IClassificationType? this[int braceLevel] public virtual ITagger? CreateTagger(ITextView textView, ITextBuffer textBuffer) where T : ITag { + if (textView == null || textBuffer == null || textView.TextBuffer != textBuffer || !ThreadHelper.CheckAccess()) + return null; + Initialize(textBuffer); - if (textView.TextBuffer != textBuffer || !HasReferenceToAcumaticaPlatform) + if (Workspace == null) return null; var tagger = textBuffer.Properties.GetOrCreateSingletonProperty(typeof(PXColorizerTaggerBase), () => From 605d1591cc2f9d1faaec9998a3d37bd70ed35181 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Tue, 12 May 2026 12:29:30 +0200 Subject: [PATCH 10/56] ATR-966: added HasReferenceToAcumaticaPlatform abstract flag to taggers + a helper property for Roslyn workspace. In the outlining tagger implemented this flag through the colorizing tagger --- .../Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs | 7 +++++-- .../Coloriser/Outlining/PXOutliningTagger.cs | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs index 7d0559b0d..778f6164a 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs @@ -1,5 +1,4 @@ #nullable enable - using System; using System.Collections.Generic; using System.Linq; @@ -8,8 +7,8 @@ using Acuminator.Utilities.Common; using Acuminator.Vsix.Settings; +using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Tagging; using Shell = Microsoft.VisualStudio.Shell; @@ -31,8 +30,12 @@ public abstract class PXTaggerBase : IDisposable internal abstract bool LastTaggingWasSuccessful { get; set; } + public abstract bool HasReferenceToAcumaticaPlatform { get; } + protected PXTaggerProviderBase ProviderBase { get; } + protected Workspace? RoslynWorkspace => ProviderBase.Workspace; + /// /// The type of the tagger. /// diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs index 921748feb..3231cac52 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs @@ -31,6 +31,8 @@ internal override bool LastTaggingWasSuccessful set { } } + public override bool HasReferenceToAcumaticaPlatform => ColorizerTagger?.HasReferenceToAcumaticaPlatform ?? false; + public PXOutliningTagger(ITextBuffer buffer, PXOutliningTaggerProvider aProvider, bool subscribeToSettingsChanges, bool useCacheChecking) : base(buffer, aProvider, subscribeToSettingsChanges, useCacheChecking) @@ -50,6 +52,10 @@ public IEnumerable> GetTags(NormalizedSnapshotSpan SubscribeToColorizingTaggerEvents(colorizingTagger); } + // Check reference to Acumatica platform only after initializing ColorizerTagger + if (!HasReferenceToAcumaticaPlatform) + return []; + switch (ColorizerTagger?.TaggerType) { case TaggerType.General when AcuminatorVSPackage.Instance?.UseRegexColoring == true: From 15d6024bd81a9f19c31258bd9dc415ad07ca0c2e Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Tue, 12 May 2026 13:33:39 +0200 Subject: [PATCH 11/56] ATR-966: moved check for the Acumatica platform reference to the colorizer tagger and do it not on the tagger initialization but at the start of the tagging process. Added additional fast check for the possibility to create PXGraph in the project, the check works only if the Roslyn compilation is available. Added subscription to Workspace events to recalculate cached HasReferenceToAcumaticaPlatform flag when needed --- .../Coloriser/Base/PXTaggerProviderBase.cs | 22 ----- .../Coloriser/PXColorizerTaggerBase.cs | 85 +++++++++++++++++-- 2 files changed, 79 insertions(+), 28 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerProviderBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerProviderBase.cs index fe398bc84..c25b696cf 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerProviderBase.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerProviderBase.cs @@ -22,28 +22,6 @@ public abstract class PXTaggerProviderBase protected virtual void Initialize(ITextBuffer buffer) { Workspace = buffer?.GetWorkspace(); - - protected bool CheckIfCurrentSolutionHasReferenceToAcumatica() - { - if (Workspace?.CurrentSolution == null) - return false; - - bool hasAcumaticaProjectsInSolution = - Workspace.CurrentSolution.Projects.Any(project => IsAcumaticaAssemblyName(project.Name) || - IsAcumaticaAssemblyName(project.AssemblyName)); - if (hasAcumaticaProjectsInSolution) - return true; - - bool hasMetadataRefs = (from project in Workspace.CurrentSolution.Projects - from reference in project.MetadataReferences - select Path.GetFileNameWithoutExtension(reference.Display)) - .Any(reference => IsAcumaticaAssemblyName(reference)); - - return hasMetadataRefs; - - //********************************************************************************************************************************* - static bool IsAcumaticaAssemblyName(string dllName) => ColoringConstants.PlatformDllName == dllName || - ColoringConstants.AppDllName == dllName; } } } diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs index 2cd6d3532..59558845e 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs @@ -1,15 +1,16 @@ #nullable enable -// The asynchronous tagging part of the PXColorizerTaggerBase class - - using System; using System.Collections.Generic; using System.Linq; +using System.IO; using System.Threading; using System.Threading.Tasks; +using Acuminator.Utilities.Roslyn.Constants; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Classification; using Microsoft.VisualStudio.Text.Tagging; namespace Acuminator.Vsix.Coloriser @@ -29,10 +30,19 @@ public abstract class PXColorizerTaggerBase : PXTaggerBase, ITagger (ProviderBase as PXColorizerTaggerProvider)!; + private bool _hasReferenceToAcumaticaPlatform; + + public sealed override bool HasReferenceToAcumaticaPlatform => _hasReferenceToAcumaticaPlatform; + protected PXColorizerTaggerBase(ITextBuffer buffer, PXColorizerTaggerProvider aProvider, bool subscribeToSettingsChanges, bool useCacheChecking) : base(buffer, aProvider, subscribeToSettingsChanges, useCacheChecking) { + if (RoslynWorkspace != null) + { + _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(ProviderBase.Workspace, Buffer.CurrentSnapshot); + RoslynWorkspace.WorkspaceChanged += OnWorkspaceChanged; + } } protected internal override void ResetCacheAndFlags(ITextSnapshot newSnapshotToCache) @@ -42,9 +52,9 @@ protected internal override void ResetCacheAndFlags(ITextSnapshot newSnapshotToC OutliningsTagsCache.Reset(); } - public virtual IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) + public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) { - if (spans == null || spans.Count == 0 || AcuminatorVSPackage.Instance?.ColoringEnabled != true) + if ((spans?.Count is null or 0) || AcuminatorVSPackage.Instance?.ColoringEnabled != true || !HasReferenceToAcumaticaPlatform) return Array.Empty>(); ITextSnapshot snapshot = spans[0].Snapshot; @@ -100,7 +110,70 @@ public override void Dispose() ClassificationTagsCache?.Reset(); OutliningsTagsCache?.Reset(); + if (RoslynWorkspace != null) + { + RoslynWorkspace.WorkspaceChanged -= OnWorkspaceChanged; + } + base.Dispose(); } + + private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) + { + switch (e.Kind) + { + case WorkspaceChangeKind.SolutionRemoved: + case WorkspaceChangeKind.SolutionCleared: + _hasReferenceToAcumaticaPlatform = false; + break; + case WorkspaceChangeKind.SolutionChanged: + case WorkspaceChangeKind.SolutionAdded: + case WorkspaceChangeKind.SolutionReloaded: + case WorkspaceChangeKind.ProjectAdded: + case WorkspaceChangeKind.ProjectRemoved: + case WorkspaceChangeKind.ProjectChanged: + case WorkspaceChangeKind.ProjectReloaded: + _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(ProviderBase.Workspace, Snapshot); + break; + } + } + + protected static bool CheckIfCurrentSolutionHasReferenceToAcumatica(Workspace? workspace, ITextSnapshot? textSnapshot) + { + var currentSolution = workspace?.CurrentSolution; + + if (currentSolution == null || currentSolution.ProjectIds.Count == 0) + return false; + + var roslynDocument = textSnapshot?.GetOpenDocumentInCurrentContextWithChanges(); + + if (roslynDocument?.Project != null && CanCreateGraphFastCheck(roslynDocument.Project) is bool canCreateGraph) + return canCreateGraph; + + bool hasAcumaticaProjectsInSolution = + currentSolution.Projects.Any(project => IsAcumaticaAssemblyName(project.Name) || IsAcumaticaAssemblyName(project.AssemblyName)); + + if (hasAcumaticaProjectsInSolution) + return true; + + bool hasMetadataRefs = (from project in currentSolution.Projects + from reference in project.MetadataReferences + select Path.GetFileNameWithoutExtension(reference.Display)) + .Any(reference => IsAcumaticaAssemblyName(reference)); + + return hasMetadataRefs; + } + + private static bool IsAcumaticaAssemblyName(string dllName) => ColoringConstants.PlatformDllName == dllName || + ColoringConstants.AppDllName == dllName; + + private static bool? CanCreateGraphFastCheck(Project project) + { + if (!project.TryGetCompilation(out var compilation) || compilation == null) + return null; + + var graphType = compilation.GetTypeByMetadataName(TypeFullNames.PXGraph); + return graphType != null; + } } } From 28543360d4272c4ff0b7b1f2b8b09b7996582dd2 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Tue, 12 May 2026 16:27:32 +0200 Subject: [PATCH 12/56] ATR-966: added synhronous version of raising tags changes event to the base tagger + changed outlining tagger code to call sync version --- .../Coloriser/AsyncTagging/BackgroundTagging.cs | 2 +- .../Coloriser/Base/PXTaggerBase.cs | 17 +++++++++++++++-- .../Coloriser/Outlining/PXOutliningTagger.cs | 4 +--- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/BackgroundTagging.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/BackgroundTagging.cs index 5818edec2..6a94b8861 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/BackgroundTagging.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/BackgroundTagging.cs @@ -90,7 +90,7 @@ private static Task AfterTaggingActionAsync(Task taggingTask, PXColorizerTaggerB return Task.FromException(taggingTask.Exception!); } - // We should be on UI thread here but the tagger.RaiseTagsChangedAsync switches to UI thread from non UI threads internally if needed + // We should be on UI thread here but the tagger.RaiseTagsChangedAsync switches to UI thread from non UI threads internally if needed return Shell.ThreadHelper.JoinableTaskFactory.RunAsync(tagger.RaiseTagsChangedAsync).Task; } } diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs index 778f6164a..ce408267b 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs @@ -65,16 +65,29 @@ protected virtual void ColoringSettingChangedHandler(object sender, SettingChang { ColoringSettingsChanged = true; LastTaggingWasSuccessful = false; - Shell.ThreadHelper.JoinableTaskFactory.Run(RaiseTagsChangedAsync); + RaiseTagsChanged(); } - internal async virtual Task RaiseTagsChangedAsync() + internal async Task RaiseTagsChangedAsync() { if (!Shell.ThreadHelper.CheckAccess()) { await Shell.ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); } + RaiseTagsChangedImpl(); + } + + internal void RaiseTagsChanged() + { + if (!Shell.ThreadHelper.CheckAccess()) + return; + + RaiseTagsChangedImpl(); + } + + private void RaiseTagsChangedImpl() + { TagsChanged?.Invoke(this, new SnapshotSpanEventArgs( new SnapshotSpan(Buffer.CurrentSnapshot, diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs index 3231cac52..2de72bdf9 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs @@ -9,8 +9,6 @@ using Microsoft.VisualStudio.Text.Classification; using Microsoft.VisualStudio.Text.Tagging; -using Shell = Microsoft.VisualStudio.Shell; - namespace Acuminator.Vsix.Coloriser { public class PXOutliningTagger : PXTaggerBase, ITagger @@ -86,7 +84,7 @@ private void SubscribeToColorizingTaggerEvents(PXColorizerTaggerBase colorizerTa private void OnColorizingTaggerTagsChanged(object sender, SnapshotSpanEventArgs e) { - Shell.ThreadHelper.JoinableTaskFactory.Run(RaiseTagsChangedAsync); + RaiseTagsChanged(); } public override void Dispose() From 4108e8f4041021f473d965aec06e44ea5a75d25a Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Tue, 12 May 2026 16:38:59 +0200 Subject: [PATCH 13/56] ATR-966: made input snapshot in ResetCacheAndFlags nullable + refactoring - renaming --- .../Coloriser/Base/PXTaggerBase.cs | 8 ++++---- .../Coloriser/MainTagger/PXColorizerMainTagger.cs | 2 +- .../Coloriser/PXColorizerTaggerBase.cs | 15 ++++++++------- .../Coloriser/Regex/PXRegexColorizerTagger.cs | 2 +- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs index ce408267b..a37eb91c2 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs @@ -38,7 +38,7 @@ public abstract class PXTaggerBase : IDisposable /// /// The type of the tagger. - /// + /// public abstract TaggerType TaggerType { get; } protected bool CacheCheckingEnabled { get; } @@ -94,15 +94,15 @@ private void RaiseTagsChangedImpl() new Span(0, Buffer.CurrentSnapshot.Length)))); } - protected internal virtual void ResetCacheAndFlags(ITextSnapshot newSnapshotToCache) + protected internal virtual void ResetCacheAndFlags(ITextSnapshot? newSnapshotToCache) { ColoringSettingsChanged = false; LastTaggingWasSuccessful = false; Snapshot = newSnapshotToCache; } - protected virtual bool CheckIfRetaggingIsNotNecessary(ITextSnapshot snapshot) => - CacheCheckingEnabled && Snapshot != null && Snapshot == snapshot && !ColoringSettingsChanged && LastTaggingWasSuccessful; + protected virtual bool CheckIfRetaggingIsNotNecessary(ITextSnapshot newSnapshotToTag) => + CacheCheckingEnabled && Snapshot != null && Snapshot == newSnapshotToTag && !ColoringSettingsChanged && LastTaggingWasSuccessful; public virtual void Dispose() { diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/MainTagger/PXColorizerMainTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/MainTagger/PXColorizerMainTagger.cs index 6f226a67c..078f9c858 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/MainTagger/PXColorizerMainTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/MainTagger/PXColorizerMainTagger.cs @@ -134,7 +134,7 @@ public override void Dispose() base.Dispose(); } - protected internal override void ResetCacheAndFlags(ITextSnapshot newSnapshotToCache) + protected internal override void ResetCacheAndFlags(ITextSnapshot? newSnapshotToCache) { base.ResetCacheAndFlags(newSnapshotToCache); _taggersByType.Values.ForEach(tagger => tagger.ResetCacheAndFlags(newSnapshotToCache)); diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs index 59558845e..c1168fa17 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Tagging; +using Acuminator.Utilities.Roslyn.ProjectSystem; namespace Acuminator.Vsix.Coloriser { @@ -45,7 +46,7 @@ protected PXColorizerTaggerBase(ITextBuffer buffer, PXColorizerTaggerProvider aP } } - protected internal override void ResetCacheAndFlags(ITextSnapshot newSnapshotToCache) + protected internal override void ResetCacheAndFlags(ITextSnapshot? newSnapshotToCache) { base.ResetCacheAndFlags(newSnapshotToCache); ClassificationTagsCache.Reset(); @@ -55,23 +56,23 @@ protected internal override void ResetCacheAndFlags(ITextSnapshot newSnapshotToC public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) { if ((spans?.Count is null or 0) || AcuminatorVSPackage.Instance?.ColoringEnabled != true || !HasReferenceToAcumaticaPlatform) - return Array.Empty>(); + return []; - ITextSnapshot snapshot = spans[0].Snapshot; + ITextSnapshot newSnapshotToTag = spans[0].Snapshot; - if (CheckIfRetaggingIsNotNecessary(snapshot)) + if (CheckIfRetaggingIsNotNecessary(newSnapshotToTag)) { return ClassificationTagsCache.ProcessedTags; } if (UseAsyncTagging) { - return GetTagsAsync(snapshot); + return GetTagsAsync(newSnapshotToTag); } else { - ResetCacheAndFlags(snapshot); - return GetTagsSynchronousImplementation(snapshot); + ResetCacheAndFlags(newSnapshotToTag); + return GetTagsSynchronousImplementation(newSnapshotToTag); } } diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/PXRegexColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/PXRegexColorizerTagger.cs index 51602f56f..36be42046 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/PXRegexColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/PXRegexColorizerTagger.cs @@ -79,7 +79,7 @@ protected internal override IEnumerable> GetTagsSyn return ClassificationTagsCache; } - protected internal override void ResetCacheAndFlags(ITextSnapshot newSnapshotToCache) + protected internal override void ResetCacheAndFlags(ITextSnapshot? newSnapshotToCache) { base.ResetCacheAndFlags(newSnapshotToCache); _tagsBag.Clear(); From 2552594ee45fe8bc590f0a99271a2b4799454b6a Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Tue, 12 May 2026 16:45:26 +0200 Subject: [PATCH 14/56] ATR-966: reworked the workspace changed event handler to reduce the number of HasReferenceToAcumaticaPlatform calculatons --- .../Coloriser/PXColorizerTaggerBase.cs | 82 +++++++++++++++---- 1 file changed, 64 insertions(+), 18 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs index c1168fa17..43881098e 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs @@ -41,7 +41,7 @@ protected PXColorizerTaggerBase(ITextBuffer buffer, PXColorizerTaggerProvider aP { if (RoslynWorkspace != null) { - _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(ProviderBase.Workspace, Buffer.CurrentSnapshot); + _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(projectId: null); RoslynWorkspace.WorkspaceChanged += OnWorkspaceChanged; } } @@ -121,48 +121,94 @@ public override void Dispose() private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) { + bool oldValue = _hasReferenceToAcumaticaPlatform; + switch (e.Kind) { case WorkspaceChangeKind.SolutionRemoved: case WorkspaceChangeKind.SolutionCleared: _hasReferenceToAcumaticaPlatform = false; break; - case WorkspaceChangeKind.SolutionChanged: + case WorkspaceChangeKind.SolutionAdded: - case WorkspaceChangeKind.SolutionReloaded: case WorkspaceChangeKind.ProjectAdded: + _hasReferenceToAcumaticaPlatform |= CheckIfCurrentSolutionHasReferenceToAcumatica(e.ProjectId); + break; + + case WorkspaceChangeKind.SolutionChanged: + case WorkspaceChangeKind.SolutionReloaded: case WorkspaceChangeKind.ProjectRemoved: + _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(e.ProjectId); + break; + case WorkspaceChangeKind.ProjectChanged: case WorkspaceChangeKind.ProjectReloaded: - _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(ProviderBase.Workspace, Snapshot); + if (e.IsProjectMetadataChanged()) + { + _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(e.ProjectId); + } + break; + + default: + return; + } + + if (Buffer.CurrentSnapshot != null && (oldValue != _hasReferenceToAcumaticaPlatform || !LastTaggingWasSuccessful)) + { + ResetCacheAndFlags(newSnapshotToCache: null); + RaiseTagsChanged(); } } - protected static bool CheckIfCurrentSolutionHasReferenceToAcumatica(Workspace? workspace, ITextSnapshot? textSnapshot) + protected bool CheckIfCurrentSolutionHasReferenceToAcumatica(ProjectId? projectId) { - var currentSolution = workspace?.CurrentSolution; + var currentSolution = RoslynWorkspace?.CurrentSolution; if (currentSolution == null || currentSolution.ProjectIds.Count == 0) return false; - var roslynDocument = textSnapshot?.GetOpenDocumentInCurrentContextWithChanges(); + var roslynDocument = Buffer.CurrentSnapshot?.GetOpenDocumentInCurrentContextWithChanges(); + var currentProject = roslynDocument?.Project; + bool allProjectsChanged = projectId == null; + + if (allProjectsChanged) + { + bool hasAcumaticaProjectsInSolution = + currentSolution.Projects.Any(project => IsAcumaticaAssemblyName(project.Name) || IsAcumaticaAssemblyName(project.AssemblyName)); + + if (hasAcumaticaProjectsInSolution) + return true; - if (roslynDocument?.Project != null && CanCreateGraphFastCheck(roslynDocument.Project) is bool canCreateGraph) - return canCreateGraph; + bool hasReferenceInMetadata = (from project in currentSolution.Projects + from reference in project.MetadataReferences + select Path.GetFileNameWithoutExtension(reference.Display)) + .Any(reference => IsAcumaticaAssemblyName(reference)); + return hasReferenceInMetadata; + } + else if (currentProject?.Id == projectId) // Check that the changed project is the same as the project of the current document. If not, then return the old value. + { + if (CanCreateGraphFastCheck(currentProject!) is bool canCreateGraph) + return canCreateGraph; - bool hasAcumaticaProjectsInSolution = - currentSolution.Projects.Any(project => IsAcumaticaAssemblyName(project.Name) || IsAcumaticaAssemblyName(project.AssemblyName)); + bool hasReferenceInMetadata = currentProject!.MetadataReferences.Count > 0 + ? currentProject.MetadataReferences.Any(IsAcumaticaAssemblyName) + : false; - if (hasAcumaticaProjectsInSolution) - return true; + if (hasReferenceInMetadata) + return true; - bool hasMetadataRefs = (from project in currentSolution.Projects - from reference in project.MetadataReferences - select Path.GetFileNameWithoutExtension(reference.Display)) - .Any(reference => IsAcumaticaAssemblyName(reference)); + bool isAcumaticaProject = IsAcumaticaAssemblyName(currentProject.Name) || IsAcumaticaAssemblyName(currentProject.AssemblyName); + return isAcumaticaProject; + } + else + return _hasReferenceToAcumaticaPlatform; + } - return hasMetadataRefs; + private static bool IsAcumaticaAssemblyName(MetadataReference reference) + { + string referenceName = Path.GetFileNameWithoutExtension(reference.Display); + return IsAcumaticaAssemblyName(referenceName); } private static bool IsAcumaticaAssemblyName(string dllName) => ColoringConstants.PlatformDllName == dllName || From cabf80961caae6745460077b42a21b709b62e32b Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Tue, 12 May 2026 16:58:22 +0200 Subject: [PATCH 15/56] ATR-966: removed base tagger provide class to not cache workspace in the tagger provider. Tagger should cache it instead. --- .../Coloriser/Base/PXTaggerBase.cs | 7 +---- .../Coloriser/Base/PXTaggerProviderBase.cs | 27 ------------------- .../Coloriser/Outlining/PXOutliningTagger.cs | 7 ++--- .../Outlining/PXOutliningTaggerProvider.cs | 6 ++--- .../Coloriser/PXColorizerTaggerProvider.cs | 10 ++----- 5 files changed, 7 insertions(+), 50 deletions(-) delete mode 100644 src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerProviderBase.cs diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs index a37eb91c2..9ea2a804d 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs @@ -32,10 +32,6 @@ public abstract class PXTaggerBase : IDisposable public abstract bool HasReferenceToAcumaticaPlatform { get; } - protected PXTaggerProviderBase ProviderBase { get; } - - protected Workspace? RoslynWorkspace => ProviderBase.Workspace; - /// /// The type of the tagger. /// @@ -43,10 +39,9 @@ public abstract class PXTaggerBase : IDisposable protected bool CacheCheckingEnabled { get; } - protected PXTaggerBase(ITextBuffer buffer, PXTaggerProviderBase provider, bool subscribeToSettingsChanges, bool useCacheChecking) + protected PXTaggerBase(ITextBuffer buffer, bool subscribeToSettingsChanges, bool useCacheChecking) { Buffer = buffer.CheckIfNull(); - ProviderBase = provider.CheckIfNull(); SubscribedToSettingsChanges = subscribeToSettingsChanges; CacheCheckingEnabled = useCacheChecking; diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerProviderBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerProviderBase.cs deleted file mode 100644 index c25b696cf..000000000 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerProviderBase.cs +++ /dev/null @@ -1,27 +0,0 @@ -#nullable enable - -using System; -using System.Collections.Generic; -using System.Linq; - -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.Text; - -using Path = System.IO.Path; - -namespace Acuminator.Vsix.Coloriser -{ - public abstract class PXTaggerProviderBase - { - public Workspace? Workspace { get; private set; } - - /// - /// Initializes the base . - /// - protected virtual void Initialize(ITextBuffer buffer) - { - Workspace = buffer?.GetWorkspace(); - } - } -} diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs index 2de72bdf9..c19862397 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs @@ -19,8 +19,6 @@ public class PXOutliningTagger : PXTaggerBase, ITagger public override TaggerType TaggerType => TaggerType.Outlining; - protected PXOutliningTaggerProvider Provider => (ProviderBase as PXOutliningTaggerProvider)!; - protected PXColorizerTaggerBase? ColorizerTagger { get; private set; } internal override bool LastTaggingWasSuccessful @@ -31,9 +29,8 @@ internal override bool LastTaggingWasSuccessful public override bool HasReferenceToAcumaticaPlatform => ColorizerTagger?.HasReferenceToAcumaticaPlatform ?? false; - public PXOutliningTagger(ITextBuffer buffer, PXOutliningTaggerProvider aProvider, - bool subscribeToSettingsChanges, bool useCacheChecking) : - base(buffer, aProvider, subscribeToSettingsChanges, useCacheChecking) + public PXOutliningTagger(ITextBuffer buffer, bool subscribeToSettingsChanges, bool useCacheChecking) : + base(buffer, subscribeToSettingsChanges, useCacheChecking) { } diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTaggerProvider.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTaggerProvider.cs index 617845b41..1a525d29b 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTaggerProvider.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTaggerProvider.cs @@ -18,18 +18,16 @@ namespace Acuminator.Vsix.Coloriser [TagType(typeof(IOutliningRegionTag))] [TextViewRole(PredefinedTextViewRoles.Document)] [Export(typeof(ITaggerProvider))] - public class PXOutliningTaggerProvider : PXTaggerProviderBase, ITaggerProvider + public class PXOutliningTaggerProvider : ITaggerProvider { public ITagger? CreateTagger(ITextBuffer buffer) where T : ITag { if (buffer == null || !ThreadHelper.CheckAccess()) return null; - Initialize(buffer); - PXOutliningTagger outliningTagger = buffer.Properties.GetOrCreateSingletonProperty(() => { - return new PXOutliningTagger(buffer, this, subscribeToSettingsChanges: true, useCacheChecking: true); + return new PXOutliningTagger(buffer, subscribeToSettingsChanges: true, useCacheChecking: true); }); return outliningTagger as ITagger; diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerProvider.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerProvider.cs index 4c9cb8cb4..c8ea5ab71 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerProvider.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerProvider.cs @@ -1,5 +1,4 @@ #nullable enable - using System; using System.Collections.Generic; using System.ComponentModel.Composition; @@ -27,7 +26,7 @@ namespace Acuminator.Vsix.Coloriser [TagType(typeof(IClassificationTag))] [TextViewRole(PredefinedTextViewRoles.Document)] [Export(typeof(IViewTaggerProvider))] - public class PXColorizerTaggerProvider : PXTaggerProviderBase, IViewTaggerProvider + public class PXColorizerTaggerProvider : IViewTaggerProvider { [Import] internal IClassificationTypeRegistryService _classificationRegistry = null!; // Set via MEF @@ -78,9 +77,6 @@ public IClassificationType? this[int braceLevel] Initialize(textBuffer); - if (Workspace == null) - return null; - var tagger = textBuffer.Properties.GetOrCreateSingletonProperty(typeof(PXColorizerTaggerBase), () => { return new PXColorizerMainTagger(textBuffer, this, subscribeToSettingsChanges: true, useCacheChecking: true); @@ -90,10 +86,8 @@ public IClassificationType? this[int braceLevel] } [MemberNotNull(nameof(_codeColoringClassificationTypes), nameof(_braceTypeByLevel))] - protected override void Initialize(ITextBuffer textBuffer) + protected void Initialize(ITextBuffer textBuffer) { - base.Initialize(textBuffer); - if (AreClassificationsInitialized) return; From 5779b2cf8c1250717fcebd253c130fc74ac38cda Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Tue, 12 May 2026 17:06:41 +0200 Subject: [PATCH 16/56] ATR-966: fixed mistype in the constant name --- src/Acuminator/Acuminator.Vsix/BannedApi/BannedApiDeployer.cs | 2 +- src/Acuminator/Acuminator.Vsix/Utils/Constants/Constants.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/BannedApi/BannedApiDeployer.cs b/src/Acuminator/Acuminator.Vsix/BannedApi/BannedApiDeployer.cs index b20b8f373..50f9bc271 100644 --- a/src/Acuminator/Acuminator.Vsix/BannedApi/BannedApiDeployer.cs +++ b/src/Acuminator/Acuminator.Vsix/BannedApi/BannedApiDeployer.cs @@ -35,7 +35,7 @@ private BannedApiDeployer(AcuminatorMyDocumentsStorage myDocumentsStorage, strin return null; try { - string bannedApiFolder = Path.Combine(myDocumentsStorage.AcuminatorFolder, Constants.BannedApi.BannnedApiFolder); + string bannedApiFolder = Path.Combine(myDocumentsStorage.AcuminatorFolder, Constants.BannedApi.BannedApiFolder); return new BannedApiDeployer(myDocumentsStorage, bannedApiFolder); } catch (Exception e) diff --git a/src/Acuminator/Acuminator.Vsix/Utils/Constants/Constants.cs b/src/Acuminator/Acuminator.Vsix/Utils/Constants/Constants.cs index 67d2adbb9..820b7d2a1 100644 --- a/src/Acuminator/Acuminator.Vsix/Utils/Constants/Constants.cs +++ b/src/Acuminator/Acuminator.Vsix/Utils/Constants/Constants.cs @@ -55,7 +55,7 @@ public static class CodeMap /// public static class BannedApi { - public const string BannnedApiFolder = "Acumatica Banned API"; + public const string BannedApiFolder = "Acumatica Banned API"; } /// From 9935883a30f9cf30ec7b5105f383985d77ed76d5 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Tue, 12 May 2026 17:12:38 +0200 Subject: [PATCH 17/56] ATR-966: removed RegEx coloring option from Acuminator VS options --- .../Resources/VSIXResource.resx | 6 ------ .../Settings/UI/GeneralOptionsPage.cs | 20 ------------------- .../Utils/Constants/Constants.cs | 1 - 3 files changed, 27 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Resources/VSIXResource.resx b/src/Acuminator/Acuminator.Vsix/Resources/VSIXResource.resx index 3fa5e4ef8..8deecd680 100644 --- a/src/Acuminator/Acuminator.Vsix/Resources/VSIXResource.resx +++ b/src/Acuminator/Acuminator.Vsix/Resources/VSIXResource.resx @@ -469,12 +469,6 @@ This option should be used together with the "Banned API File" setting. Use BQL outlining - - Use the syntax colorizer based on regular expressions, which provides worse coloring but works faster. If set to false, Roslyn coloring is used. - - - Use RegEx colorizer - Invalid or not existing file diff --git a/src/Acuminator/Acuminator.Vsix/Settings/UI/GeneralOptionsPage.cs b/src/Acuminator/Acuminator.Vsix/Settings/UI/GeneralOptionsPage.cs index fb17c2a2f..ecbde50a3 100644 --- a/src/Acuminator/Acuminator.Vsix/Settings/UI/GeneralOptionsPage.cs +++ b/src/Acuminator/Acuminator.Vsix/Settings/UI/GeneralOptionsPage.cs @@ -149,25 +149,6 @@ public bool ColorOnlyInsideBQL } } - private bool _useRegexColoring = Constants.Settings.Coloring.UseRegexColoringDefault; - - [DefaultValue(Constants.Settings.Coloring.UseRegexColoringDefault)] - [CategoryFromResources(nameof(VSIXResource.Category_Coloring), ColoringCategoryName)] - [DisplayNameFromResources(resourceKey: nameof(VSIXResource.Setting_UseRegexColoring_Title))] - [DescriptionFromResources(resourceKey: nameof(VSIXResource.Setting_UseRegexColoring_Description))] - public bool UseRegexColoring - { - get => _useRegexColoring; - set - { - if (_useRegexColoring != value) - { - _useRegexColoring = value; - _colorSettingsChanged = true; - } - } - } - private bool _useBqlOutlining = Constants.Settings.Outlining.UseBqlOutliningDefault; [DefaultValue(Constants.Settings.Outlining.UseBqlOutliningDefault)] @@ -375,7 +356,6 @@ public override void ResetSettings() _useBqlDetailedOutlining = Constants.Settings.Outlining.UseBqlDetailedOutliningDefault; _coloringEnabled = Constants.Settings.Coloring.ColoringEnabledDefault; - _useRegexColoring = Constants.Settings.Coloring.UseRegexColoringDefault; _pxActionColoringEnabled = Constants.Settings.Coloring.PXActionColoringEnabledDefault; _pxGraphColoringEnabled = Constants.Settings.Coloring.PXGraphColoringEnabledDefault; _colorOnlyInsideBQL = Constants.Settings.Coloring.ColorOnlyInsideBQLDefault; diff --git a/src/Acuminator/Acuminator.Vsix/Utils/Constants/Constants.cs b/src/Acuminator/Acuminator.Vsix/Utils/Constants/Constants.cs index 820b7d2a1..976d60998 100644 --- a/src/Acuminator/Acuminator.Vsix/Utils/Constants/Constants.cs +++ b/src/Acuminator/Acuminator.Vsix/Utils/Constants/Constants.cs @@ -33,7 +33,6 @@ public static class Coloring public const bool PXActionColoringEnabledDefault = true; public const bool PXGraphColoringEnabledDefault = true; public const bool ColorOnlyInsideBQLDefault = false; - public const bool UseRegexColoringDefault = false; } public static class Outlining From 5c63e665154d5916b742d4fb4b12b4ffd8cfe3bc Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Tue, 12 May 2026 17:14:22 +0200 Subject: [PATCH 18/56] ATR-966: removed the regex tagger and the delegating tagger from the coloring --- .../MainTagger/PXColorizerMainTagger.cs | 150 - .../Coloriser/Regex/PXRegexColorizerTagger.cs | 205 - .../Coloriser/Regex/Test/APInvoice.cs | 1911 ------ .../Coloriser/Regex/Test/APRegister.cs | 2813 -------- .../Coloriser/Regex/Test/ARDocumentRelease.cs | 5688 ----------------- .../Regex/Test/PMAllocationProcess.cs | 266 - .../Coloriser/Regex/Utils/RegExpressions.cs | 56 - 7 files changed, 11089 deletions(-) delete mode 100644 src/Acuminator/Acuminator.Vsix/Coloriser/MainTagger/PXColorizerMainTagger.cs delete mode 100644 src/Acuminator/Acuminator.Vsix/Coloriser/Regex/PXRegexColorizerTagger.cs delete mode 100644 src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Test/APInvoice.cs delete mode 100644 src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Test/APRegister.cs delete mode 100644 src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Test/ARDocumentRelease.cs delete mode 100644 src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Test/PMAllocationProcess.cs delete mode 100644 src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Utils/RegExpressions.cs diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/MainTagger/PXColorizerMainTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/MainTagger/PXColorizerMainTagger.cs deleted file mode 100644 index 078f9c858..000000000 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/MainTagger/PXColorizerMainTagger.cs +++ /dev/null @@ -1,150 +0,0 @@ -#nullable enable - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -using Acuminator.Utilities; -using Acuminator.Utilities.Common; - -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Classification; -using Microsoft.VisualStudio.Text.Tagging; - -namespace Acuminator.Vsix.Coloriser -{ - /// - /// A colorizer tagger base class. - /// - public class PXColorizerMainTagger : PXColorizerTaggerBase - { - public override TaggerType TaggerType => TaggerType.General; - - private readonly Dictionary _taggersByType; - - protected internal override bool UseAsyncTagging - { - get - { - TaggerType currentTaggerType = GetCurrentTaggerTypeFromSettings(); - return _taggersByType.TryGetValue(currentTaggerType, out PXColorizerTaggerBase tagger) - ? tagger.UseAsyncTagging - : false; - } - } - - protected internal override ITagsCache ClassificationTagsCache - { - get - { - TaggerType currentTaggerType = GetCurrentTaggerTypeFromSettings(); - return _taggersByType.TryGetValue(currentTaggerType, out PXColorizerTaggerBase tagger) - ? tagger.ClassificationTagsCache - : throw new NotSupportedException($"Tagger type {currentTaggerType} not supported"); - } - } - - protected internal override ITagsCache OutliningsTagsCache - { - get - { - TaggerType currentTaggerType = GetCurrentTaggerTypeFromSettings(); - return _taggersByType.TryGetValue(currentTaggerType, out PXColorizerTaggerBase tagger) - ? tagger.OutliningsTagsCache - : throw new NotSupportedException($"Tagger type {currentTaggerType} not supported"); - } - } - - internal override bool LastTaggingWasSuccessful - { - get - { - TaggerType currentTaggerType = GetCurrentTaggerTypeFromSettings(); - return _taggersByType.TryGetValue(currentTaggerType, out PXColorizerTaggerBase tagger) - ? tagger.LastTaggingWasSuccessful - : throw new NotSupportedException($"Tagger type {currentTaggerType} not supported"); - } - set - { - TaggerType currentTaggerType = GetCurrentTaggerTypeFromSettings(); - - if (_taggersByType.TryGetValue(currentTaggerType, out PXColorizerTaggerBase tagger)) - { - tagger.LastTaggingWasSuccessful = value; - } - else - { - throw new NotSupportedException($"Tagger type {currentTaggerType} not supported"); - } - } - } - - public PXColorizerMainTagger(ITextBuffer buffer, PXColorizerTaggerProvider aProvider, bool subscribeToSettingsChanges, - bool useCacheChecking) : - base(buffer, aProvider, subscribeToSettingsChanges, useCacheChecking) - { - PXColorizerTaggerBase roslynTagger = new PXRoslynColorizerTagger(buffer, aProvider, subscribeToSettingsChanges: false, - useCacheChecking: false); - PXColorizerTaggerBase regexTagger = new PXRegexColorizerTagger(buffer, aProvider, subscribeToSettingsChanges: false, - useCacheChecking: false); - - _taggersByType = new Dictionary(capacity: 2) - { - { roslynTagger.TaggerType, roslynTagger }, - { regexTagger.TaggerType, regexTagger } - }; - } - - protected internal override IEnumerable> GetTagsSynchronousImplementation(ITextSnapshot snapshot) - { - TaggerType currentTaggerType = GetCurrentTaggerTypeFromSettings(); - - if (!_taggersByType.TryGetValue(currentTaggerType, out PXColorizerTaggerBase activeTagger)) - return []; - - return activeTagger.GetTagsSynchronousImplementation(snapshot); - } - - protected internal override Task>> GetTagsAsyncImplementationAsync(ITextSnapshot snapshot, - CancellationToken cancellationToken) - { - TaggerType currentTaggerType = GetCurrentTaggerTypeFromSettings(); - - if (!_taggersByType.TryGetValue(currentTaggerType, out PXColorizerTaggerBase activeTagger)) - return Task.FromResult(Enumerable.Empty>()); - - if (activeTagger.UseAsyncTagging) - { - return activeTagger.GetTagsAsyncImplementationAsync(snapshot, cancellationToken); - } - else - { - var tags = activeTagger.GetTagsSynchronousImplementation(snapshot); - return Task.FromResult(tags); - } - } - - public override void Dispose() - { - _taggersByType.Values.Distinct() - .ForEach(tagger => tagger.Dispose()); - base.Dispose(); - } - - protected internal override void ResetCacheAndFlags(ITextSnapshot? newSnapshotToCache) - { - base.ResetCacheAndFlags(newSnapshotToCache); - _taggersByType.Values.ForEach(tagger => tagger.ResetCacheAndFlags(newSnapshotToCache)); - } - - protected TaggerType GetCurrentTaggerTypeFromSettings() - { - return AcuminatorVSPackage.Instance?.UseRegexColoring == true - ? TaggerType.RegEx - : TaggerType.Roslyn; - } - } -} diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/PXRegexColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/PXRegexColorizerTagger.cs deleted file mode 100644 index 36be42046..000000000 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/PXRegexColorizerTagger.cs +++ /dev/null @@ -1,205 +0,0 @@ -#nullable enable - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; -using System.Threading; -using System.Threading.Tasks; - -using Acuminator.Utilities; -using Acuminator.Utilities.Common; -using Acuminator.Utilities.Roslyn; - -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Classification; -using Microsoft.VisualStudio.Text.Tagging; - -namespace Acuminator.Vsix.Coloriser -{ - internal class PXRegexColorizerTagger : PXColorizerTaggerBase - { - protected internal override bool UseAsyncTagging => false; - - public override TaggerType TaggerType => TaggerType.RegEx; - - private readonly TagsCacheSync _classificationTagsCache = new TagsCacheSync(); - - protected internal override ITagsCache ClassificationTagsCache => _classificationTagsCache; - - private readonly TagsCacheSync _outliningTagsCache = new TagsCacheSync(capacity: 0); - - protected internal override ITagsCache OutliningsTagsCache => _outliningTagsCache; - - internal override bool LastTaggingWasSuccessful { get; set; } - - private readonly ConcurrentBag> _tagsBag = new ConcurrentBag>(); - - internal PXRegexColorizerTagger(ITextBuffer buffer, PXColorizerTaggerProvider aProvider, bool subscribeToSettingsChanges, - bool useCacheChecking) : - base(buffer, aProvider, subscribeToSettingsChanges, useCacheChecking) - { - } - - protected internal async override Task>> GetTagsAsyncImplementationAsync(ITextSnapshot snapshot, - CancellationToken cancellationToken) - { - var taggingInfo = await Task.Run(() => GetTagsSynchronousImplementation(snapshot)) - .TryAwait(); - - if (!taggingInfo.IsSuccess) - { - LastTaggingWasSuccessful = false; - return []; - } - - return taggingInfo.Result ?? []; - } - - protected internal override IEnumerable> GetTagsSynchronousImplementation(ITextSnapshot snapshot) - { - bool success; - - try - { - GetTagsFromSnapshot(snapshot); - success = true; - } - catch (Exception) - { - success = false; - } - - _classificationTagsCache.AddTags(_tagsBag); - ClassificationTagsCache.CompleteProcessing(); - OutliningsTagsCache.CompleteProcessing(); - LastTaggingWasSuccessful = success && ClassificationTagsCache.IsCompleted; - - return ClassificationTagsCache; - } - - protected internal override void ResetCacheAndFlags(ITextSnapshot? newSnapshotToCache) - { - base.ResetCacheAndFlags(newSnapshotToCache); - _tagsBag.Clear(); - } - - private void GetTagsFromSnapshot(ITextSnapshot newSnapshot) - { - string wholeText = newSnapshot.GetText(); - var matches = RegExpressions.BQLSelectCommandRegex - .Matches(wholeText) - .OfType() - .Where(bqlCommandMatch => !string.IsNullOrWhiteSpace(bqlCommandMatch.Value)); - - Parallel.ForEach(matches, - bqlCommandMatch => GetTagsFromBQLCommand(newSnapshot, bqlCommandMatch.Value, bqlCommandMatch.Index)); - } - - private void GetTagsFromBQLCommand(ITextSnapshot newSnapshot, string bqlCommand, int offset) - { - int lastAngleBraces = bqlCommand.LastIndexOf('>'); - bqlCommand = bqlCommand.Substring(0, lastAngleBraces + 1); - int lastAngleBraceIndex = bqlCommand.LastIndexOf('>'); - - if (lastAngleBraceIndex >= 0) - bqlCommand = bqlCommand.Substring(0, lastAngleBraceIndex + 1); - - int firstAngleBraceIndex = bqlCommand.IndexOf('<'); - - if (firstAngleBraceIndex < 0) - return; - - string selectOp = bqlCommand.Substring(0, firstAngleBraceIndex); - GetSelectCommandTag(newSnapshot, bqlCommand, offset); - - GetBQLOperandTags(newSnapshot, bqlCommand, offset); - GetDacWithFieldTags(newSnapshot, bqlCommand, offset); - GetSingleDacAndConstantTags(newSnapshot, bqlCommand, offset); - GetBqlParameterTags(newSnapshot, bqlCommand, offset); - } - - private void GetBQLOperandTags(ITextSnapshot newSnapshot, string bqlCommand, int offset) - { - var matches = RegExpressions.DacOperandRegex.Matches(bqlCommand); - - foreach (Match bqlOperandMatch in matches.OfType().Skip(1)) - { - string bqlOperand = bqlOperandMatch.Value.TrimEnd('<'); - CreateTag(newSnapshot, bqlOperandMatch, offset, bqlOperand, Provider[PXCodeType.BqlOperator]); - } - } - - private void GetSelectCommandTag(ITextSnapshot newSnapshot, string selectOp, int offset) - { - Span span = new Span(offset, selectOp.Length); - SnapshotSpan snapshotSpan = new SnapshotSpan(newSnapshot, span); - var tag = new TagSpan(snapshotSpan, new ClassificationTag(Provider[PXCodeType.BqlOperator])); - _tagsBag.Add(tag); - } - - private void GetBqlParameterTags(ITextSnapshot newSnapshot, string bqlCommand, int offset) - { - var matches = RegExpressions.BQLParametersRegex.Matches(bqlCommand); - - foreach (Match bqlParamMatch in matches) - { - string bqlParam = bqlParamMatch.Value; - CreateTag(newSnapshot, bqlParamMatch, offset, bqlParam, Provider[PXCodeType.BqlParameter]); - } - } - - private void GetSingleDacAndConstantTags(ITextSnapshot newSnapshot, string bqlCommand, int offset) - { - var matches = RegExpressions.DacOrConstantRegex.Matches(bqlCommand); - - foreach (Match dacOrConstMatch in matches) - { - string dacOrConst = dacOrConstMatch.Value.Trim(',', '<', '>'); - CreateTag(newSnapshot, dacOrConstMatch, offset, dacOrConst, Provider[PXCodeType.Dac]); - } - } - - private void GetDacWithFieldTags(ITextSnapshot newSnapshot, string bqlCommand, int offset) - { - var matches = RegExpressions.DacWithFieldRegex.Matches(bqlCommand); - - foreach (Match dacWithFieldMatch in matches) - { - string[] dacParts = dacWithFieldMatch.Value.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries); - - if (dacParts.Length != 2) - continue; - - GetDacTag(newSnapshot, dacWithFieldMatch, offset, dacParts); - GetFieldTag(newSnapshot, dacWithFieldMatch, offset, dacParts); - } - } - - private void GetDacTag(ITextSnapshot newSnapshot, Match match, int offset, string[] dacParts) - { - string dacPart = dacParts[0].TrimStart(',', '<'); - CreateTag(newSnapshot, match, offset, dacPart, Provider[PXCodeType.Dac]); - } - - private void GetFieldTag(ITextSnapshot newSnapshot, Match match, int offset, string[] dacParts) - { - string fieldPart = dacParts[1].TrimEnd(',', '>'); - CreateTag(newSnapshot, match, offset, fieldPart, Provider[PXCodeType.DacField]); - } - - private void CreateTag(ITextSnapshot newSnapshot, Match match, int offset, string tagContent, IClassificationType? classType) - { - if (classType == null) - return; - - int startIndex = offset + match.Index + match.Value.IndexOf(tagContent); - var span = new Span(startIndex, tagContent.Length); - var snapshotSpan = new SnapshotSpan(newSnapshot, span); - var tag = new TagSpan(snapshotSpan, new ClassificationTag(classType)); - - _tagsBag.Add(tag); - } - } -} diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Test/APInvoice.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Test/APInvoice.cs deleted file mode 100644 index 2a38758cc..000000000 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Test/APInvoice.cs +++ /dev/null @@ -1,1911 +0,0 @@ -using System; - -using PX.Common; - -using PX.Data; -using PX.Data.EP; - -using PX.Objects.GL; -using PX.Objects.CM; -using PX.Objects.CS; -using PX.Objects.TX; -using PX.Objects.CR; -using PX.Objects.CA; - -using CRLocation = PX.Objects.CR.Standalone.Location; - -namespace PX.Objects.AP -{ - public class APInvoiceType : APDocType - { - /// - /// Specialized selector for APInvoice RefNbr.
- /// By default, defines the following set of columns for the selector:
- /// APInvoice.refNbr,APInvoice.docDate, APInvoice.finPeriodID,
- /// APInvoice.vendorID, APInvoice.vendorID_Vendor_acctName,
- /// APInvoice.vendorLocationID, APInvoice.curyID, APInvoice.curyOrigDocAmt,
- /// APInvoice.curyDocBal,APInvoice.status, APInvoice.dueDate, APInvoice.invoiceNbr
- ///
- public class RefNbrAttribute : PXSelectorAttribute - { - public RefNbrAttribute(Type SearchType) - : base(SearchType, - typeof(APRegister.refNbr), - typeof(APRegister.docDate), - typeof(APRegister.finPeriodID), - typeof(APRegister.vendorID), - typeof(APRegister.vendorID_Vendor_acctName), - typeof(APRegister.vendorLocationID), - typeof(APInvoice.invoiceNbr), - typeof(APRegister.curyID), - typeof(APRegister.curyOrigDocAmt), - typeof(APRegister.curyDocBal), - typeof(APRegister.status), - typeof(APInvoice.dueDate)) - { - } - } - - public class AdjdRefNbrAttribute : PXSelectorAttribute - { - public AdjdRefNbrAttribute(Type SearchType) - : base(SearchType, - typeof(APRegister.refNbr), - typeof(APRegister.docDate), - typeof(APRegister.finPeriodID), - typeof(APRegister.vendorLocationID), - typeof(APRegister.curyID), - typeof(APRegister.curyOrigDocAmt), - typeof(APRegister.curyDocBal), - typeof(APRegister.status), - typeof(APAdjust.APInvoice.dueDate), - typeof(APAdjust.APInvoice.invoiceNbr), - typeof(APRegister.docDesc)) - { - } - } - - /// - /// Specialized for APInvoices version of the
- /// It defines how the new numbers are generated for the AP Invoice.
- /// References APInvoice.docType and APInvoice.docDate fields of the document,
- /// and also define a link between numbering ID's defined in AP Setup and APInvoice types:
- /// namely APSetup.invoiceNumberingID, APSetup.adjustmentNumberingID,
- /// APSetup.adjustmentNumberingID, APSetup.invoiceNumberingID
- ///
- public class NumberingAttribute : AutoNumberAttribute - { - private static string[] _DocTypes - { - get - { - return new string[] { Invoice, CreditAdj, DebitAdj, Prepayment }; - } - } - - private static Type[] _SetupFields - { - get - { - return new Type[] - { - typeof(APSetup.invoiceNumberingID), - typeof(APSetup.creditAdjNumberingID), - typeof(APSetup.debitAdjNumberingID), - typeof(APSetup.invoiceNumberingID) - }; - } - } - - public static Type GetNumberingIDField(string docType) - { - foreach (var pair in _DocTypes.Zip(_SetupFields)) - if (pair.Item1 == docType) - return pair.Item2; - - return null; - } - - public NumberingAttribute() - : base(typeof(APInvoice.docType), typeof(APInvoice.docDate), _DocTypes, _SetupFields) - { - } - } - - public new static readonly string[] Values = { Invoice, CreditAdj, DebitAdj, Prepayment }; - public new static readonly string[] Labels = { Messages.Invoice, Messages.CreditAdj, Messages.DebitAdj, Messages.Prepayment }; - - public new class ListAttribute : PXStringListAttribute - { - public ListAttribute() - : base(Values, Labels) - { - } - } - - public class TaxInvoiceListAttribute : PXStringListAttribute - { - public TaxInvoiceListAttribute() - : base( - new string[] { Invoice, CreditAdj, DebitAdj }, - new string[] { Messages.Invoice, Messages.CreditAdj, Messages.DebitAdj }) - { } - } - - public class AdjdListAttribute : PXStringListAttribute - { - public AdjdListAttribute() - : base( - new string[] { Invoice, CreditAdj }, - new string[] { Messages.Invoice, Messages.CreditAdj }) - { } - } - - /// - /// String list with DocType, suitable for the APInvoice document.
- /// Used in the DocType selector of APInvoices.
- ///
- public class InvoiceListAttribute : PXStringListAttribute - { - public InvoiceListAttribute() - : base( - new string[] { Invoice, CreditAdj, Prepayment }, - new string[] { Messages.Invoice, Messages.CreditAdj, Messages.Prepayment }) - { } - } - - public static string DrCr(string DocType) - { - switch (DocType) - { - case Invoice: - case CreditAdj: - case Prepayment: - case QuickCheck: - return GL.DrCr.Debit; - case DebitAdj: - case VoidQuickCheck: - return GL.DrCr.Credit; - default: - return null; - } - } - } - - public class APPaymentBy - { - public const int DueDate = 0; - public const int DiscountDate = 1; - - public class List : PXIntListAttribute - { - public List() - : base( - new[] { DueDate, DiscountDate }, - new[] { Messages.DueDate, Messages.DiscountDate }) - { - } - } - - public class dueDate : Constant - { - public dueDate() : base(DueDate) - { - } - } - public class discountDate : Constant - { - public discountDate() : base(DiscountDate) - { - } - } - } - - /// - /// Represents AP Invoices, Credit and Debit Adjustments. - /// The DAC is based on and extends it with the fields - /// relevant to the documents of the above types. - /// - [System.SerializableAttribute()] - [PXTable()] - [PXSubstitute(GraphType = typeof(APInvoiceEntry))] - [PXSubstitute(GraphType = typeof(TX.TXInvoiceEntry))] - [PXPrimaryGraph(typeof(APInvoiceEntry))] - [PXCacheName(Messages.APInvoice)] - [PXEMailSource] - public partial class APInvoice : APRegister, IInvoice, IAssign - { - #region Selected - public new abstract class selected : PX.Data.IBqlField - { - } - #endregion - #region BranchID - public new abstract class branchID : PX.Data.IBqlField - { - } - - /// - /// Identifier of the Branch, to which the document belongs. - /// - /// - /// Corresponds to the Branch.BranchID field. - /// - [GL.Branch(typeof(Coalesce< - Search>, And>>>>, - Search>>>>), IsDetail = false)] - public override Int32? BranchID - { - get - { - return this._BranchID; - } - set - { - this._BranchID = value; - } - } - #endregion - #region DocType - public new abstract class docType : PX.Data.IBqlField - { - } - - /// - /// [key] Type of the document. - /// - /// - /// Possible values are: "INV" - Invoice, "ACR" - Credit Adjustment, "ADR" - Debit Adjustment, - /// "PPM" - Prepayment. - /// - [PXDBString(3, IsKey = true, IsFixed = true)] - [PXDefault()] - [APInvoiceType.List()] - [PXUIField(DisplayName = "Type", Visibility = PXUIVisibility.SelectorVisible, Enabled = true, TabOrder = 0)] - [PXFieldDescription] - public override String DocType - { - get - { - return this._DocType; - } - set - { - this._DocType = value; - } - } - #endregion - #region RefNbr - public new abstract class refNbr : PX.Data.IBqlField - { - } - - /// - /// [key] Reference number of the document. - /// - [PXDBString(15, IsKey = true, IsUnicode = true, InputMask = ">CCCCCCCCCCCCCCC")] - [PXDefault()] - [PXUIField(DisplayName = "Reference Nbr.", Visibility = PXUIVisibility.SelectorVisible, TabOrder = 1)] - [APInvoiceType.RefNbr(typeof(Search2, - And>>, - InnerJoinSingleTable>>>, - Where>, - And2, - Or>>, - And>>>>, - OrderBy>>), Filterable = true, IsPrimaryViewCompatible = true)] - [APInvoiceType.Numbering()] - [PXFieldDescription] - public override String RefNbr - { - get - { - return this._RefNbr; - } - set - { - this._RefNbr = value; - } - } - #endregion - #region Status - public new abstract class status : PX.Data.IBqlField - { - } - #endregion - #region VendorID - public new abstract class vendorID : PX.Data.IBqlField - { - } - #endregion - #region VendorLocationID - public new abstract class vendorLocationID : PX.Data.IBqlField - { - } - #endregion - #region CuryID - public new abstract class curyID : PX.Data.IBqlField - { - } - #endregion - #region APAccountID - public new abstract class aPAccountID : PX.Data.IBqlField - { - } - #endregion - #region APSubID - public new abstract class aPSubID : PX.Data.IBqlField - { - } - #endregion - #region TermsID - public abstract class termsID : PX.Data.IBqlField - { - } - protected String _TermsID; - - /// - /// The credit terms associated with the document (unavailable for prepayments and debit adjustments).\ - /// Defaults to the credit terms of the vendor. - /// - [PXDBString(10, IsUnicode = true)] - [PXDefault(typeof(Search>, And, NotEqual>>>), PersistingCheck = PXPersistingCheck.Nothing)] - [PXUIField(DisplayName = "Terms", Visibility = PXUIVisibility.Visible)] - [PXSelector(typeof(Search, Or>>>), DescriptionField = typeof(Terms.descr), Filterable = true)] - [Terms(typeof(APInvoice.docDate), typeof(APInvoice.dueDate), typeof(APInvoice.discDate), typeof(APInvoice.curyOrigDocAmt), typeof(APInvoice.curyOrigDiscAmt))] - public virtual String TermsID - { - get - { - return this._TermsID; - } - set - { - this._TermsID = value; - } - } - #endregion - #region DueDate - public abstract class dueDate : PX.Data.IBqlField - { - } - protected DateTime? _DueDate; - - /// - /// The date when payment for the document is due in accordance with the credit terms. - /// - [PXDBDate()] - [PXUIField(DisplayName = "Due Date", Visibility = PXUIVisibility.SelectorVisible)] - public virtual DateTime? DueDate - { - get - { - return this._DueDate; - } - set - { - this._DueDate = value; - } - } - #endregion - #region DiscDate - public abstract class discDate : PX.Data.IBqlField - { - } - protected DateTime? _DiscDate; - - /// - /// The date when the cash discount can be taken in accordance with the credit terms. - /// - [PXDBDate()] - [PXUIField(DisplayName = "Cash Discount Date", Visibility = PXUIVisibility.SelectorVisible)] - public virtual DateTime? DiscDate - { - get - { - return this._DiscDate; - } - set - { - this._DiscDate = value; - } - } - #endregion - #region MasterRefNbr - public abstract class masterRefNbr : IBqlField { } - /// - /// For an installment this field holds the reference number of the master document. - /// - [PXDBString(15, IsUnicode = true)] - public virtual string MasterRefNbr { get; set; } - #endregion - #region InstallmentNbr - public abstract class installmentNbr : IBqlField { } - /// - /// The number of the installment, which the document represents. - /// - /// - /// Corresponds to the TermsInstallments.InstallmentNbr field. - /// - [PXDBShort] - public virtual short? InstallmentNbr { get; set; } - #endregion - #region InstallmentCntr - public abstract class installmentCntr : IBqlField { } - /// - /// Counter of the document's installments. - /// - [PXDBShort] - [PXUIField(DisplayName = "Number of Installments")] - public virtual short? InstallmentCntr { get; set; } - #endregion - #region InvoiceNbr - public abstract class invoiceNbr : PX.Data.IBqlField - { - } - protected String _InvoiceNbr; - - /// - /// The document’s original reference number as assigned by the vendor (for informational purposes). - /// The reference to the vendor document is required if is set to true. - /// The reference should also be unique if is set to true. - /// - [PXDBString(40, IsUnicode = true)] - [PXUIField(DisplayName = "Vendor Ref.", Visibility = PXUIVisibility.SelectorVisible)] - [APVendorRefNbr] - public virtual String InvoiceNbr - { - get - { - return this._InvoiceNbr; - } - set - { - this._InvoiceNbr = value; - } - } - #endregion - #region InvoiceDate - public abstract class invoiceDate : PX.Data.IBqlField - { - } - protected DateTime? _InvoiceDate; - - /// - /// The document’s original date as assigned by the vendor (for informational purposes). - /// - [PXDBDate()] - [PXDefault(TypeCode.DateTime, "01/01/1900")] - [PXUIField(DisplayName = "Vendor Ref. Date", Visibility = PXUIVisibility.Invisible)] - public virtual DateTime? InvoiceDate - { - get - { - return this._InvoiceDate; - } - set - { - this._InvoiceDate = value; - } - } - #endregion - #region TaxZoneID - public abstract class taxZoneID : PX.Data.IBqlField - { - } - protected String _TaxZoneID; - - /// - /// Identifier of the tax zone associated with the document. - /// Defaults to vendor's tax zone. - /// - [PXDBString(10, IsUnicode = true)] - [PXDefault(typeof(Search>, And>>>>), PersistingCheck = PXPersistingCheck.Nothing)] - [PXUIField(DisplayName = "Vendor Tax Zone", Visibility = PXUIVisibility.Visible)] - [PXSelector(typeof(TaxZone.taxZoneID), DescriptionField = typeof(TaxZone.descr), Filterable = true)] - public virtual String TaxZoneID - { - get - { - return this._TaxZoneID; - } - set - { - this._TaxZoneID = value; - } - } - #endregion - #region DocDate - public new abstract class docDate : PX.Data.IBqlField - { - } - #endregion - #region CuryTaxTotal - public abstract class curyTaxTotal : PX.Data.IBqlField - { - } - protected Decimal? _CuryTaxTotal; - - /// - /// The total amount of taxes associated with the document. (Presented in the currency of the document, see ) - /// - [PXDBCurrency(typeof(APInvoice.curyInfoID), typeof(APInvoice.taxTotal))] - [PXUIField(DisplayName = "Tax Total", Visibility = PXUIVisibility.Visible, Enabled = false)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? CuryTaxTotal - { - get - { - return this._CuryTaxTotal; - } - set - { - this._CuryTaxTotal = value; - } - } - #endregion - #region TaxTotal - public abstract class taxTotal : PX.Data.IBqlField - { - } - protected Decimal? _TaxTotal; - - /// - /// The total amount of taxes associated with the document. (Presented in the base currency of the company, see ) - /// - [PXDBDecimal(4)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? TaxTotal - { - get - { - return this._TaxTotal; - } - set - { - this._TaxTotal = value; - } - } - #endregion - #region CuryLineTotal - public abstract class curyLineTotal : PX.Data.IBqlField - { - } - protected Decimal? _CuryLineTotal; - - /// - /// The document total presented in the currency of the document. (See ) - /// - [PXDBCurrency(typeof(APInvoice.curyInfoID), typeof(APInvoice.lineTotal))] - [PXUIField(DisplayName = "Detail Total", Visibility = PXUIVisibility.Visible, Enabled = false)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? CuryLineTotal - { - get - { - return this._CuryLineTotal; - } - set - { - this._CuryLineTotal = value; - } - } - #endregion - #region LineTotal - public abstract class lineTotal : PX.Data.IBqlField - { - } - protected Decimal? _LineTotal; - - /// - /// The document total presented in the base currency of the company. (See ) - /// - [PXDBDecimal(4)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? LineTotal - { - get - { - return this._LineTotal; - } - set - { - this._LineTotal = value; - } - } - #endregion - #region DiscTot - public new abstract class discTot : PX.Data.IBqlField - { - } - #endregion - #region CuryDiscTot - public new abstract class curyDiscTot : PX.Data.IBqlField - { - } - #endregion - #region CuryTaxAmt - public abstract class curyTaxAmt : IBqlField { } - [PXDBCurrency(typeof(APInvoice.curyInfoID), typeof(APInvoice.taxAmt))] - [PXUIField(DisplayName = "Tax Amount")] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? CuryTaxAmt { get; set; } - #endregion - #region TaxAmt - public abstract class taxAmt : IBqlField { } - [PXDBDecimal(4)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? TaxAmt { get; set; } - #endregion - - #region DocDisc - public new abstract class docDisc : PX.Data.IBqlField - { - } - #endregion - #region CuryDocDisc - public new abstract class curyDocDisc : PX.Data.IBqlField - { - } - #endregion - - #region CuryVatExemptTotal - public abstract class curyVatExemptTotal : PX.Data.IBqlField - { - } - protected Decimal? _CuryVatExemptTotal; - - /// - /// The part of the document total that is exempt from VAT. - /// This total is calculated as a sum of the taxable amounts for the taxes - /// of type VAT, which are marked as exempt - /// and are neither statistical nor reverse. - /// (Presented in the currency of the document, see ) - /// - [PXDBCurrency(typeof(APInvoice.curyInfoID), typeof(APInvoice.vatExemptTotal))] - [PXUIField(DisplayName = "VAT Exempt Total", Visibility = PXUIVisibility.Visible, Enabled = false)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? CuryVatExemptTotal - { - get - { - return this._CuryVatExemptTotal; - } - set - { - this._CuryVatExemptTotal = value; - } - } - #endregion - - #region VatExemptTaxTotal - public abstract class vatExemptTotal : PX.Data.IBqlField - { - } - protected Decimal? _VatExemptTotal; - - /// - /// The part of the document total that is exempt from VAT. - /// This total is calculated as a sum of the taxable amounts for the taxes - /// of type VAT, which are marked as exempt - /// and are neither statistical nor reverse. - /// (Presented in the base currency of the company, see ) - /// - [PXDBDecimal(4)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? VatExemptTotal - { - get - { - return this._VatExemptTotal; - } - set - { - this._VatExemptTotal = value; - } - } - #endregion - - #region CuryVatTaxableTotal - public abstract class curyVatTaxableTotal : PX.Data.IBqlField - { - } - protected Decimal? _CuryVatTaxableTotal; - - /// - /// The part of the document total, which is subject to VAT. - /// This total is calculated as a sum of the taxable amounts for the taxes - /// of type VAT, which are neither exempt, - /// nor statistical, nor reverse. - /// (Presented in the currency of the document, see ) - /// - [PXDBCurrency(typeof(APInvoice.curyInfoID), typeof(APInvoice.vatTaxableTotal))] - [PXUIField(DisplayName = "VAT Taxable Total", Visibility = PXUIVisibility.Visible, Enabled = false)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? CuryVatTaxableTotal - { - get - { - return this._CuryVatTaxableTotal; - } - set - { - this._CuryVatTaxableTotal = value; - } - } - #endregion - - #region VatTaxableTotal - public abstract class vatTaxableTotal : PX.Data.IBqlField - { - } - protected Decimal? _VatTaxableTotal; - - /// - /// The part of the document total, which is subject to VAT. - /// This total is calculated as a sum of the taxable amounts for the taxes - /// of type VAT, which are neither exempt, - /// nor statistical, nor reverse. - /// (Presented in the base currency of the company, see ) - /// - [PXDBDecimal(4)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? VatTaxableTotal - { - get - { - return this._VatTaxableTotal; - } - set - { - this._VatTaxableTotal = value; - } - } - #endregion - - #region CuryInfoID - public new abstract class curyInfoID : PX.Data.IBqlField - { - } - #endregion - #region CuryOrigDocAmt - public new abstract class curyOrigDocAmt : PX.Data.IBqlField - { - } - #endregion - #region OrigDocAmt - public new abstract class origDocAmt : PX.Data.IBqlField - { - } - #endregion - #region CuryDocBal - public new abstract class curyDocBal : PX.Data.IBqlField - { - } - #endregion - #region DocBal - public new abstract class docBal : PX.Data.IBqlField - { - } - #endregion - #region CuryDiscBal - public new abstract class curyDiscBal : PX.Data.IBqlField - { - } - #endregion - #region DiscBal - public new abstract class discBal : PX.Data.IBqlField - { - } - #endregion - #region CuryOrigDiscAmt - public new abstract class curyOrigDiscAmt : PX.Data.IBqlField - { - } - #endregion - #region OrigDiscAmt - public new abstract class origDiscAmt : PX.Data.IBqlField - { - } - #endregion - #region CuryOrigWhTaxAmt - public new abstract class curyOrigWhTaxAmt : PX.Data.IBqlField - { - } - #endregion - #region OrigWhTaxAmt - public new abstract class origWhTaxAmt : PX.Data.IBqlField - { - } - #endregion - #region CuryWhTaxBal - public new abstract class curyWhTaxBal : PX.Data.IBqlField - { - } - #endregion - #region WhTaxBal - public new abstract class whTaxBal : PX.Data.IBqlField - { - } - #endregion - #region CuryTaxWheld - public new abstract class curyTaxWheld : PX.Data.IBqlField - { - } - #endregion - #region TaxWheld - public new abstract class taxWheld : PX.Data.IBqlField - { - } - #endregion - #region DrCr - public abstract class drCr : PX.Data.IBqlField - { - } - protected string _DrCr; - - /// - /// Read-only field indicating whether the document is of debit or credit type. - /// The value of this field is based solely on the field. - /// - /// - /// Possible values are "D" (for Invoice, Credit Adjustment, Prepayment, Quick Check) - /// and "C" (for Debit Adjustment and Void Quick Check). - /// - [PXString(1, IsFixed = true)] - public string DrCr - { - [PXDependsOnFields(typeof(docType))] - get - { - return APInvoiceType.DrCr(this._DocType); - } - set - { - } - } - #endregion - #region SeparateCheck - public abstract class separateCheck : PX.Data.IBqlField - { - } - protected Boolean? _SeparateCheck; - - /// - /// When set to true indicates that the document should be paid for by a separate check. - /// In other words, the payment to such a document must not be consolidated with other payments. - /// - /// - /// Defaults to the value of the same setting for vendor. - /// - [PXDBBool()] - [PXUIField(DisplayName = "Pay Separately", Visibility = PXUIVisibility.Visible)] - [PXDefault(typeof(Search>, And>>>>))] - public virtual Boolean? SeparateCheck - { - get - { - return this._SeparateCheck; - } - set - { - this._SeparateCheck = value; - } - } - #endregion - #region PaySel - public abstract class paySel : IBqlField - { - } - protected bool? _PaySel; - - /// - /// When set to true indicates that the document is approved for payment. - /// - [PXDBBool] - [PXDefault(false)] - [PXUIField(DisplayName = "Approved for Payment")] - public bool? PaySel - { - get - { - return _PaySel; - } - set - { - _PaySel = value; - } - } - #endregion - #region PayLocationID - public abstract class payLocationID : PX.Data.IBqlField - { - } - protected Int32? _PayLocationID; - - /// - /// location for payment. - /// - /// - /// Defaults to vendor's default location - /// or to the first active location of the vendor if the former is not set. - /// - [LocationID( - typeof(Where>, - And, And>>>), - DescriptionField = typeof(Location.descr), - Visibility = PXUIVisibility.SelectorVisible, - DisplayName = "Payment Location")] - [PXDefault(typeof(Coalesce< - Search2, - And>>>, - Where>, - And, And>>>>, - Search>, - And, And>>>>>))] - public virtual Int32? PayLocationID - { - get - { - return this._PayLocationID; - } - set - { - this._PayLocationID = value; - } - } - #endregion - #region PayDate - public abstract class payDate : PX.Data.IBqlField - { - } - protected DateTime? _PayDate; - - /// - /// The date when the bill has been approved for payment. - /// - [PXDBDate()] - [PXUIField(DisplayName = "Pay Date", Visibility = PXUIVisibility.Visible)] - [PXDefault()] - [PXFormula(typeof(SO.DateMinusDaysNotLessThenDate< - Switch< - Case, Equal, - And>, APInvoice.discDate>, - APInvoice.dueDate>, - IsNull, decimal0>, APInvoice.docDate>))] - public virtual DateTime? PayDate - { - get - { - return this._PayDate; - } - set - { - this._PayDate = value; - } - } - #endregion - #region PayTypeID - public abstract class payTypeID : PX.Data.IBqlField - { - } - protected String _PayTypeID; - - /// - /// The payment method used for the document. - /// - /// - /// Corresponds to the PaymentMethod.PaymentMethodID field. - /// Defaults to the payment method associated with the vendor location. - /// - [PXDBString(10, IsUnicode = true)] - [PXUIField(DisplayName = "Payment Method", Visibility = PXUIVisibility.Visible)] - - [PXSelector(typeof(Search, - And>>>), DescriptionField = typeof(PaymentMethod.descr))] - [PXDefault(typeof(Search>, And>>>>), PersistingCheck = PXPersistingCheck.Nothing)] - public virtual String PayTypeID - { - get - { - return this._PayTypeID; - } - set - { - this._PayTypeID = value; - } - } - #endregion - #region PayAccountID - public abstract class payAccountID : PX.Data.IBqlField - { - } - protected Int32? _PayAccountID; - - /// - /// The cash account used for the payment. - /// - /// - /// Defaults to the cash account associated with the selected location and payment method. - /// In case such account is not found the default value will be the cash account which is specified as - /// default for AP for the selected payment method. - /// - [PXDefault(typeof(Coalesce, - And, - And>>>>, - Where< - Location.bAccountID, Equal>, - And>, - And>>>>>, - // Handle the case when the payment settings for the currently selected payment - // location are set to "Same as Main" (the first condition in the Where clause). - // - - Search2< - Location.cashAccountID, - InnerJoin>, - InnerJoin, - And, - And>>>>>, - Where< - CR.Standalone.LocationAlias.locationID, NotEqual, - And>, - And>, - And>>>>>>>, - Search2< - PaymentMethodAccount.cashAccountID, - InnerJoin>>, - Where< - PaymentMethodAccount.paymentMethodID, Equal>, - And>, - And, - And>>>>>>), - PersistingCheck = PXPersistingCheck.Nothing)] - [CashAccount(typeof(APInvoice.branchID), typeof(Search2>>, - Where2>, - And, - And>, - And>>>>>), - Visibility = PXUIVisibility.Visible)] - [PXFormula(typeof(Validate))] - public virtual Int32? PayAccountID - { - get - { - return this._PayAccountID; - } - set - { - this._PayAccountID = value; - } - } - #endregion - #region PrebookAcctID - public abstract class prebookAcctID : PX.Data.IBqlField - { - } - protected Int32? _PrebookAcctID; - - /// - /// The expense account used to record the expenses pending reclassification. - /// The field is relevant only if the Support for Expense Reclassification feature is activated - /// and the document has or has had the Prebooked ("K") status. (See ) - /// - /// - /// Defaults to the account associated with the vendor of the document. - /// Corresponds to the AccountID field. - /// - [PXDefault(typeof(Select>>>), SourceField = typeof(Vendor.prebookAcctID), PersistingCheck = PXPersistingCheck.Nothing)] - [Account(DisplayName = "Reclassification Account", Visibility = PXUIVisibility.Visible, DescriptionField = typeof(Account.description))] - public virtual Int32? PrebookAcctID - { - get - { - return this._PrebookAcctID; - } - set - { - this._PrebookAcctID = value; - } - } - #endregion - #region PrebookSubID - public abstract class prebookSubID : PX.Data.IBqlField - { - } - protected Int32? _PrebookSubID; - - - /// - /// The subaccount used to record the expenses pending reclassification. - /// The field is relevant only if the Support for Expense Reclassification feature is activated - /// and the document has or has had the Prebooked ("K") status. (See ) - /// - /// - /// Defaults to the subaccount associated with the vendor of the document. - /// Corresponds to the AccountID field. - /// - [PXDefault(typeof(Select>>>), SourceField = typeof(Vendor.prebookSubID), PersistingCheck = PXPersistingCheck.Nothing)] - [SubAccount(typeof(APInvoice.prebookAcctID), DisplayName = "Reclassification Subaccount", Visibility = PXUIVisibility.Visible, DescriptionField = typeof(Sub.description))] - public virtual Int32? PrebookSubID - { - get - { - return this._PrebookSubID; - } - set - { - this._PrebookSubID = value; - } - } - #endregion - #region Released - public new abstract class released : PX.Data.IBqlField - { - } - #endregion - #region OpenDoc - public new abstract class openDoc : PX.Data.IBqlField - { - } - #endregion - #region Hold - public new abstract class hold : PX.Data.IBqlField - { - } - #endregion - #region Printed - public new abstract class printed : PX.Data.IBqlField - { - } - #endregion - #region Voided - public new abstract class voided : PX.Data.IBqlField - { - } - #endregion - #region Prebooked - public new abstract class prebooked : PX.Data.IBqlField - { - } - #endregion - #region BatchNbr - public new abstract class batchNbr : PX.Data.IBqlField - { - } - #endregion - #region PrebookBatchNbr - public new abstract class prebookBatchNbr : PX.Data.IBqlField - { - } - #endregion - #region VoidBatchNbr - public new abstract class voidBatchNbr : PX.Data.IBqlField - { - } - #endregion - #region ScheduleID - public new abstract class scheduleID : IBqlField - { - } - #endregion - #region Scheduled - public new abstract class scheduled : IBqlField - { - } - #endregion - #region DocDesc - public new abstract class docDesc : PX.Data.IBqlField - { - } - #endregion - #region VendorID_Vendor_acctName - public new abstract class vendorID_Vendor_acctName : PX.Data.IBqlField - { - } - #endregion - #region EstPayDate - public abstract class estPayDate : PX.Data.IBqlField - { - } - protected DateTime? _EstPayDate; - - /// - /// Estimated payment date. - /// - /// - /// The field is calculated and equals either if the document is - /// selected for payment or the otherwise. - /// - [PXDBCalced(typeof(Switch>, APInvoice.payDate>, APInvoice.dueDate>), typeof(DateTime))] - public virtual DateTime? EstPayDate - { - get - { - return this._EstPayDate; - } - set - { - this._EstPayDate = value; - } - } - #endregion - - #region LCEnabled - public abstract class lCEnabled : PX.Data.IBqlField - { - } - protected Boolean? _LCEnabled = false; - - /// - /// Indicates whether landed cost is enabled for the document. - /// - /// - /// Equals true if the vendor of the document is a Landed Cost vendor and - /// the document has landed cost associated with it. - /// - [PXBool()] - [PXUIField(Visible = false)] - public virtual Boolean? LCEnabled - { - get - { - return this._LCEnabled; - } - set - { - this._LCEnabled = value; - } - } - #endregion - #region IsTaxValid - public new abstract class isTaxValid : PX.Data.IBqlField - { - } - #endregion - #region IsTaxPosted - public new abstract class isTaxPosted : PX.Data.IBqlField - { - } - #endregion - #region IsTaxSaved - public new abstract class isTaxSaved : PX.Data.IBqlField - { - } - #endregion - #region NoteID - public new abstract class noteID : PX.Data.IBqlField - { - } - - /// - /// Identifier of the Note object, associated with the document. - /// - /// - /// Corresponds to the Note.NoteID field. - /// - [PXSearchable(SM.SearchCategory.AP, "AP {0}: {1} - {3}", new Type[] { typeof(APInvoice.docType), typeof(APInvoice.refNbr), typeof(APInvoice.vendorID), typeof(Vendor.acctName) }, - new Type[] { typeof(APInvoice.invoiceNbr), typeof(APInvoice.docDesc) }, - NumberFields = new Type[] { typeof(APInvoice.refNbr) }, - Line1Format = "{0:d}{1}{2}", Line1Fields = new Type[] { typeof(APInvoice.docDate), typeof(APInvoice.status), typeof(APInvoice.invoiceNbr) }, - Line2Format = "{0}", Line2Fields = new Type[] { typeof(APInvoice.docDesc) }, - MatchWithJoin = typeof(InnerJoin>>), - SelectForFastIndexing = typeof(Select2>>>) - )] - [PXNote(ShowInReferenceSelector = true)] - public override Guid? NoteID - { - get - { - return this._NoteID; - } - set - { - this._NoteID = value; - } - } - #endregion - - #region RefNoteID - public new abstract class refNoteID : PX.Data.IBqlField - { - } - #endregion - - #region PONumber - public abstract class pONumber : PX.Data.IBqlField - { - } - protected String _PONumber; - [PXString(15, IsUnicode = true)] - public String PONumber - { - get - { - return this._PONumber; - } - set - { - this._PONumber = value; - } - } - #endregion - - #region TaxCalcMode - public new abstract class taxCalcMode : IBqlField { } - #endregion - #region HasWithHoldTax - public abstract class hasWithHoldTax : IBqlField { } - protected bool? _HasWithHoldTax; - [PXBool] - [RestrictWithholdingTaxCalcMode(typeof(APInvoice.taxZoneID), typeof(APInvoice.taxCalcMode))] - public virtual bool? HasWithHoldTax - { - get { return this._HasWithHoldTax; } - set { this._HasWithHoldTax = value; } - } - #endregion - #region HasUseTax - public abstract class hasUseTax : IBqlField { } - protected bool? _HasUseTax; - [PXBool] - [RestrictUseTaxCalcMode(typeof(APInvoice.taxZoneID), typeof(APInvoice.taxCalcMode))] - public virtual bool? HasUseTax - { - get { return this._HasUseTax; } - set { this._HasUseTax = value; } - } - #endregion - #region UsesManualVAT - public abstract class usesManualVAT : IBqlField - { - } - protected bool? _UsesManualVAT; - [PXDBBool] - [RestrictManualVAT(typeof(APInvoice.taxZoneID), typeof(APInvoice.taxCalcMode))] - [PXUIField(DisplayName = "Manual VAT Entry", Enabled = false)] - public virtual bool? UsesManualVAT - { - get - { - return this._UsesManualVAT; - } - set - { - this._UsesManualVAT = value; - } - } - #endregion - - #region IsTaxDocument - public abstract class isTaxDocument : IBqlField { } - - /// - /// Specifies (if set to true) that the document is tax bill and orginally has been created by tax reporting process. - /// - [PXDBBool] - public virtual bool? IsTaxDocument { get; set; } - #endregion - } -} - -namespace PX.Objects.AP.Standalone -{ - [Serializable] - [PXHidden(ServiceVisible = false)] - public partial class APInvoice : PX.Data.IBqlTable - { - #region DocType - public abstract class docType : PX.Data.IBqlField - { - } - protected string _DocType; - [PXDBString(3, IsKey = true, IsFixed = true)] - [PXDefault()] - public virtual String DocType - { - get - { - return this._DocType; - } - set - { - this._DocType = value; - } - } - #endregion - #region RefNbr - public abstract class refNbr : PX.Data.IBqlField - { - } - protected string _RefNbr; - [PXDBString(15, IsUnicode = true, IsKey = true, InputMask = "")] - [PXDefault()] - public virtual String RefNbr - { - get - { - return this._RefNbr; - } - set - { - this._RefNbr = value; - } - } - #endregion - #region TermsID - public abstract class termsID : PX.Data.IBqlField - { - } - protected String _TermsID; - [PXDBString(10, IsUnicode = true)] - public virtual String TermsID - { - get - { - return this._TermsID; - } - set - { - this._TermsID = value; - } - } - #endregion - #region DueDate - public abstract class dueDate : PX.Data.IBqlField - { - } - protected DateTime? _DueDate; - [PXDBDate()] - public virtual DateTime? DueDate - { - get - { - return this._DueDate; - } - set - { - this._DueDate = value; - } - } - #endregion - #region DiscDate - public abstract class discDate : PX.Data.IBqlField - { - } - protected DateTime? _DiscDate; - [PXDBDate()] - public virtual DateTime? DiscDate - { - get - { - return this._DiscDate; - } - set - { - this._DiscDate = value; - } - } - #endregion - #region InvoiceNbr - public abstract class invoiceNbr : PX.Data.IBqlField - { - } - protected String _InvoiceNbr; - [PXDBString(40, IsUnicode = true)] - public virtual String InvoiceNbr - { - get - { - return this._InvoiceNbr; - } - set - { - this._InvoiceNbr = value; - } - } - #endregion - #region InvoiceDate - public abstract class invoiceDate : PX.Data.IBqlField - { - } - protected DateTime? _InvoiceDate; - [PXDBDate()] - [PXDefault(TypeCode.DateTime, "01/01/1900")] - [PXUIField(DisplayName = "Vendor Ref. Date", Visibility = PXUIVisibility.Invisible)] - public virtual DateTime? InvoiceDate - { - get - { - return this._InvoiceDate; - } - set - { - this._InvoiceDate = value; - } - } - #endregion - #region TaxZoneID - public abstract class taxZoneID : PX.Data.IBqlField - { - } - protected String _TaxZoneID; - [PXDBString(10, IsUnicode = true)] - public virtual String TaxZoneID - { - get - { - return this._TaxZoneID; - } - set - { - this._TaxZoneID = value; - } - } - #endregion - #region MasterRefNbr - public abstract class masterRefNbr : PX.Data.IBqlField - { - } - protected String _MasterRefNbr; - [PXDBString(15, IsUnicode = true)] - public virtual String MasterRefNbr - { - get - { - return this._MasterRefNbr; - } - set - { - this._MasterRefNbr = value; - } - } - #endregion - #region InstallmentNbr - public abstract class installmentNbr : PX.Data.IBqlField - { - } - protected Int16? _InstallmentNbr; - [PXDBShort()] - public virtual Int16? InstallmentNbr - { - get - { - return this._InstallmentNbr; - } - set - { - this._InstallmentNbr = value; - } - } - #endregion - #region CuryTaxTotal - public abstract class curyTaxTotal : PX.Data.IBqlField - { - } - protected Decimal? _CuryTaxTotal; - [PXDBDecimal(4)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? CuryTaxTotal - { - get - { - return this._CuryTaxTotal; - } - set - { - this._CuryTaxTotal = value; - } - } - #endregion - #region TaxTotal - public abstract class taxTotal : PX.Data.IBqlField - { - } - protected Decimal? _TaxTotal; - [PXDBDecimal(4)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? TaxTotal - { - get - { - return this._TaxTotal; - } - set - { - this._TaxTotal = value; - } - } - #endregion - #region CuryTaxAmt - public abstract class curyTaxAmt : IBqlField { } - [PXDBDecimal(4)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? CuryTaxAmt { get; set; } - #endregion - #region TaxAmt - public abstract class taxAmt : IBqlField { } - [PXDBDecimal(4)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? TaxAmt { get; set; } - #endregion - #region CuryVatTaxableTotal - public abstract class curyVatTaxableTotal : PX.Data.IBqlField - { - } - protected Decimal? _CuryVatTaxableTotal; - [PXDBDecimal(4)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? CuryVatTaxableTotal - { - get - { - return this._CuryVatTaxableTotal; - } - set - { - this._CuryVatTaxableTotal = value; - } - } - #endregion - #region VatTaxableTotal - public abstract class vatTaxableTotal : PX.Data.IBqlField - { - } - protected Decimal? _VatTaxableTotal; - [PXDBDecimal(4)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? VatTaxableTotal - { - get - { - return this._VatTaxableTotal; - } - set - { - this._VatTaxableTotal = value; - } - } - #endregion - #region CuryVatExemptTotal - public abstract class curyVatExemptTotal : PX.Data.IBqlField - { - } - protected Decimal? _CuryVatExemptTotal; - [PXDBDecimal(4)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? CuryVatExemptTotal - { - get - { - return this._CuryVatExemptTotal; - } - set - { - this._CuryVatExemptTotal = value; - } - } - #endregion - #region VatExemptTotal - public abstract class vatExemptTotal : PX.Data.IBqlField - { - } - protected Decimal? _VatExemptTotal; - [PXDBDecimal(4)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? VatExemptTotal - { - get - { - return this._VatExemptTotal; - } - set - { - this._VatExemptTotal = value; - } - } - #endregion - #region CuryLineTotal - public abstract class curyLineTotal : PX.Data.IBqlField - { - } - protected Decimal? _CuryLineTotal; - [PXDBDecimal(4)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? CuryLineTotal - { - get - { - return this._CuryLineTotal; - } - set - { - this._CuryLineTotal = value; - } - } - #endregion - #region LineTotal - public abstract class lineTotal : PX.Data.IBqlField - { - } - protected Decimal? _LineTotal; - [PXDBDecimal(4)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? LineTotal - { - get - { - return this._LineTotal; - } - set - { - this._LineTotal = value; - } - } - #endregion - #region SeparateCheck - public abstract class separateCheck : PX.Data.IBqlField - { - } - protected Boolean? _SeparateCheck; - [PXDBBool()] - [PXDefault(true)] - public virtual Boolean? SeparateCheck - { - get - { - return this._SeparateCheck; - } - set - { - this._SeparateCheck = value; - } - } - #endregion - #region PaySel - public abstract class paySel : IBqlField - { - } - protected bool? _PaySel = false; - [PXDBBool] - [PXDefault(false)] - public bool? PaySel - { - get - { - return _PaySel; - } - set - { - _PaySel = value; - } - } - #endregion - #region PayDate - public abstract class payDate : PX.Data.IBqlField - { - } - protected DateTime? _PayDate; - [PXDBDate()] - public virtual DateTime? PayDate - { - get - { - return this._PayDate; - } - set - { - this._PayDate = value; - } - } - #endregion - #region PayTypeID - public abstract class payTypeID : PX.Data.IBqlField - { - } - protected String _PayTypeID; - [PXDBString(10, IsUnicode = true)] - public virtual String PayTypeID - { - get - { - return this._PayTypeID; - } - set - { - this._PayTypeID = value; - } - } - #endregion - #region PayAccountID - public abstract class payAccountID : PX.Data.IBqlField - { - } - protected Int32? _PayAccountID; - [PXDBInt()] - public virtual Int32? PayAccountID - { - get - { - return this._PayAccountID; - } - set - { - this._PayAccountID = value; - } - } - #endregion - #region PayLocationID - public abstract class payLocationID : PX.Data.IBqlField - { - } - protected Int32? _PayLocationID; - [PXDBInt()] - public virtual Int32? PayLocationID - { - get - { - return this._PayLocationID; - } - set - { - this._PayLocationID = value; - } - } - #endregion - #region PrebookAcctID - public abstract class prebookAcctID : PX.Data.IBqlField - { - } - protected Int32? _PrebookAcctID; - - [PXDBInt()] - public virtual Int32? PrebookAcctID - { - get - { - return this._PrebookAcctID; - } - set - { - this._PrebookAcctID = value; - } - } - #endregion - #region PrebookSubID - public abstract class prebookSubID : PX.Data.IBqlField - { - } - protected Int32? _PrebookSubID; - - [PXDBInt()] - public virtual Int32? PrebookSubID - { - get - { - return this._PrebookSubID; - } - set - { - this._PrebookSubID = value; - } - } - #endregion - #region TaxCalcMode - public abstract class taxCalcMode : IBqlField { } - #endregion - } -} \ No newline at end of file diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Test/APRegister.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Test/APRegister.cs deleted file mode 100644 index 581e9adf5..000000000 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Test/APRegister.cs +++ /dev/null @@ -1,2813 +0,0 @@ -#define USE_CACHE_EXTENSION - -using System; -using System.Collections.Generic; -using System.Linq; - -using PX.Common; - -using PX.Data; -using PX.Data.EP; - -using PX.TM; - -using PX.Objects.AP.BQL; -using PX.Objects.Common; -using PX.Objects.GL; -using PX.Objects.CM; -using PX.Objects.CS; -using PX.Objects.CR; - -using APQuickCheck = PX.Objects.AP.Standalone.APQuickCheck; -using CRLocation = PX.Objects.CR.Standalone.Location; -using IRegister = PX.Objects.CM.IRegister; - -namespace PX.Objects.AP -{ - public class APDocType : ILabelProvider - { - public const string Invoice = "INV"; - public const string CreditAdj = "ACR"; - public const string DebitAdj = "ADR"; - public const string Check = "CHK"; - public const string VoidCheck = "VCK"; - public const string Prepayment = "PPM"; - public const string Refund = "REF"; - public const string QuickCheck = "QCK"; - public const string VoidQuickCheck = "VQC"; - - protected static readonly IEnumerable _valueLabelPairs = new ValueLabelList - { - { Invoice, Messages.Invoice }, - { CreditAdj, Messages.CreditAdj }, - { DebitAdj, Messages.DebitAdj }, - { Check, Messages.Check }, - { VoidCheck, Messages.VoidCheck }, - { Prepayment, Messages.Prepayment }, - { Refund, Messages.Refund }, - { QuickCheck, Messages.QuickCheck }, - { VoidQuickCheck, Messages.VoidQuickCheck }, - }; - - protected static readonly IEnumerable _valuePrintableLabelPairs = new ValueLabelList - { - { Invoice, Messages.PrintInvoice }, - { CreditAdj, Messages.PrintCreditAdj }, - { DebitAdj, Messages.PrintDebitAdj }, - { Check, Messages.PrintCheck }, - { VoidCheck, Messages.PrintVoidCheck }, - { Prepayment, Messages.PrintPrepayment }, - { Refund, Messages.PrintRefund }, - { QuickCheck, Messages.PrintQuickCheck }, - { VoidQuickCheck, Messages.PrintVoidQuickCheck }, - }; - - public static readonly string[] Values = { Invoice, CreditAdj, DebitAdj, Check, VoidCheck, Prepayment, Refund, QuickCheck, VoidQuickCheck }; - public static readonly string[] Labels = { Messages.Invoice, Messages.CreditAdj, Messages.DebitAdj, Messages.Check, Messages.VoidCheck, Messages.Prepayment, Messages.Refund, Messages.QuickCheck, Messages.VoidQuickCheck }; - - public IEnumerable ValueLabelPairs => _valueLabelPairs; - - public class ListAttribute : LabelListAttribute - { - public ListAttribute() : base(_valueLabelPairs) - { } - } - - /// - /// Defines a Selector of the AP Document types with shorter description.
- /// In the screens displayed as combo-box.
- /// Mostly used in the reports.
- ///
- public class PrintListAttribute : LabelListAttribute - { - public PrintListAttribute() : base(_valuePrintableLabelPairs) - { } - } - - public class invoice : Constant - { - public invoice() : base(Invoice) { } - } - - public class creditAdj : Constant - { - public creditAdj() : base(CreditAdj) { } - } - - public class debitAdj : Constant - { - public debitAdj() : base(DebitAdj) { } - } - - public class check : Constant - { - public check() : base(Check) { } - } - - public class voidCheck : Constant - { - public voidCheck() : base(VoidCheck) { } - } - - public class prepayment : Constant - { - public prepayment() : base(Prepayment) { } - } - - public class refund : Constant - { - public refund() : base(Refund) { } - } - - public class quickCheck : Constant - { - public quickCheck() : base(QuickCheck) { } - } - - public class voidQuickCheck : Constant - { - public voidQuickCheck() : base(VoidQuickCheck) { } - } - - public static string DocClass(string DocType) - { - switch (DocType) - { - case Invoice: - case CreditAdj: - case DebitAdj: - case QuickCheck: - case VoidQuickCheck: - return GLTran.tranClass.Normal; - case Check: - case VoidCheck: - case Refund: - return GLTran.tranClass.Payment; - case Prepayment: - return GLTran.tranClass.Charge; - default: - return null; - } - } - - public static bool? Payable(string DocType) - { - switch (DocType) - { - case Invoice: - case CreditAdj: - return true; - case Check: - case DebitAdj: - case VoidCheck: - case Prepayment: - case Refund: - case QuickCheck: - case VoidQuickCheck: - return false; - default: - return null; - } - } - - public static Int16? SortOrder(string DocType) - { - switch (DocType) - { - case Invoice: - case CreditAdj: - case QuickCheck: - return 0; - case Prepayment: - return 1; - case DebitAdj: - return 2; - case Check: - return 3; - case VoidCheck: - case VoidQuickCheck: - return 4; - case Refund: - return 5; - default: - return null; - } - } - - public static Decimal? SignBalance(string DocType) - { - switch (DocType) - { - case Refund: - case Invoice: - case CreditAdj: - return 1m; - case DebitAdj: - case Check: - case VoidCheck: - return -1m; - case Prepayment: - return -1m; - case QuickCheck: - case VoidQuickCheck: - return 0m; - default: - return null; - } - } - - public static Decimal? SignAmount(string DocType) - { - switch (DocType) - { - case Refund: - case Invoice: - case CreditAdj: - case QuickCheck: - return 1m; - case DebitAdj: - case Check: - case VoidCheck: - case VoidQuickCheck: - return -1m; - case Prepayment: - return -1m; - default: - return null; - } - } - - public static string TaxDrCr(string DocType) - { - switch (DocType) - { - //Invoice Types - case Invoice: - case CreditAdj: - case QuickCheck: - return DrCr.Debit; - case DebitAdj: - case VoidQuickCheck: - return DrCr.Credit; - //Payment Types - case Check: - case Prepayment: - case VoidCheck: - return DrCr.Debit; - case Refund: - return DrCr.Credit; - default: - return DrCr.Debit; - } - } - - public static bool? HasNegativeAmount(string docType) - { - switch (docType) - { - case Refund: - case Invoice: - case CreditAdj: - case QuickCheck: - case DebitAdj: - case Check: - case Prepayment: - case VoidQuickCheck: - return false; - case VoidCheck: - return true; - default: - return null; - } - } - } - - public class APDocStatus - { - public static readonly string[] Values = { Hold, Balanced, Voided, Scheduled, Open, Closed, Printed, Prebooked, PendingApproval, Rejected, Reserved }; - public static readonly string[] Labels = { Messages.Hold, Messages.Balanced, Messages.Voided, Messages.Scheduled, Messages.Open, Messages.Closed, Messages.Printed, Messages.Prebooked, Messages.PendingApproval, Messages.Rejected, Messages.Reserved }; - - public class ListAttribute : PXStringListAttribute - { - public ListAttribute() - : base(Values, Labels) { } - } - - public const string Hold = "H"; - public const string Balanced = "B"; - public const string Voided = "V"; - public const string Scheduled = "S"; - public const string Open = "N"; - public const string Closed = "C"; - public const string Printed = "P"; - public const string Prebooked = "K"; - public const string PendingApproval = "E"; - public const string Rejected = "R"; - public const string Reserved = "Z"; - - public class hold : Constant - { - public hold() : base(Hold) { } - } - - public class balanced : Constant - { - public balanced() : base(Balanced) { } - } - - public class voided : Constant - { - public voided() : base(Voided) { } - } - - public class scheduled : Constant - { - public scheduled() : base(Scheduled) { } - } - - public class open : Constant - { - public open() : base(Open) { } - } - - public class closed : Constant - { - public closed() : base(Closed) { } - } - - public class printed : Constant - { - public printed() : base(Printed) { } - } - - public class prebooked : Constant - { - public prebooked() : base(Prebooked) { } - } - - public class pendingApproval : Constant - { - public pendingApproval() : base(PendingApproval) { } - } - - public class rejected : Constant - { - public rejected() : base(Rejected) { } - } - - public class reserved : Constant - { - public reserved() : base(Reserved) { } - } - } - - /// - /// An auxiliary DAC that is used in Accounts Payable and Accounts Receivable balance reports - /// to properly join documents with their adjustments. - /// - [Serializable] - [PXCacheName(Messages.APAROrd)] - public partial class APAROrd : PX.Data.IBqlTable - { - #region Ord - public abstract class ord : PX.Data.IBqlField - { - } - protected Int16? _Ord; - - /// - /// [key] The field is used in reports for joining and filtering purposes. - /// - [PXDBShort(IsKey = true)] - public virtual Int16? Ord - { - get - { - return this._Ord; - } - set - { - this._Ord = value; - } - } - #endregion - } - - /// - /// Primary DAC for the Accounts Payable documents. - /// Includes fields common to all types of AP documents. - /// - [PXCacheName(Messages.Document)] - [System.SerializableAttribute()] - [PXPrimaryGraph(new Type[] { - typeof(APQuickCheckEntry), - typeof(TX.TXInvoiceEntry), - typeof(APInvoiceEntry), - typeof(APPaymentEntry) - }, - new Type[] { - typeof(Select>, - And>>>>), - typeof(Select>, - And>, - And, And>>>>>>), - typeof(Select>, - And>>>>), - typeof(Select>, - And>>>>) - })] - public partial class APRegister : IBqlTable, IRegister, IBalance - { - #region Selected - public abstract class selected : PX.Data.IBqlField - { - } - protected bool? _Selected = false; - - /// - /// Indicates whether the record is selected for mass processing or not. - /// - [PXBool] - [PXDefault(false)] - [PXUIField(DisplayName = "Selected")] - public virtual bool? Selected - { - get - { - return _Selected; - } - set - { - _Selected = value; - } - } - #endregion - #region Hidden - public abstract class hidden : PX.Data.IBqlField - { - } - protected bool? _Hidden = false; - - /// - /// If set to true, this field indicates that the document represents a payment by a separate check. - /// In this case the payment cannot be combined with other payments to the vendor. - /// Applicable only in case VSeparateCheck option - /// is turned on for the Vendor. - /// - [PXBool] - [PXDefault(false)] - public virtual bool? Hidden - { - get - { - return _Hidden; - } - set - { - _Hidden = value; - } - } - #endregion - #region BranchID - public abstract class branchID : PX.Data.IBqlField - { - } - protected Int32? _BranchID; - - /// - /// Identifier of the Branch, to which the document belongs. - /// - /// - /// Corresponds to the Branch.BranchID field. - /// - [GL.Branch()] - public virtual Int32? BranchID - { - get - { - return this._BranchID; - } - set - { - this._BranchID = value; - } - } - #endregion - #region Passed - public virtual bool? Passed - { - get; - set; - } - #endregion - #region DocType - public abstract class docType : PX.Data.IBqlField - { - } - protected String _DocType; - - /// - /// [key] Type of the document. - /// - /// - /// Possible values are: "INV" - Invoice, "ACR" - Credit Adjustment, "ADR" - Debit Adjustment, - /// "CHK" - Check, "VCK" - Void Check, "PPM" - Prepayment, "REF" - Vendor Refund, - /// "QCK" - Quick Check, "VQC" - Void Quick Check. - /// - [PXDBString(3, IsKey = true, IsFixed = true)] - [PXDefault()] - [APDocType.List()] - [PXUIField(DisplayName = "Type", Visibility = PXUIVisibility.SelectorVisible, Enabled = true, TabOrder = 0)] - [PXFieldDescription] - public virtual String DocType - { - get - { - return this._DocType; - } - set - { - this._DocType = value; - } - } - - [PXString] - [PXUIFieldAttribute(DisplayName = "Document Type (Internal)")] - public string InternalDocType - { - [PXDependsOnFields(typeof(docType))] - get - { - return DocType; - } - } - #endregion - #region PrintDocType - public abstract class printDocType : PX.Data.IBqlField - { - } - - /// - /// Type of the document for displaying in reports. - /// This field has the same set of possible internal values as the field, - /// but exposes different user-friendly values. - /// - /// - /// - /// - [PXString(3, IsFixed = true)] - [APDocType.PrintList()] - [PXUIField(DisplayName = "Type", Visibility = PXUIVisibility.Visible, Enabled = true)] - public virtual String PrintDocType - { - get - { - return this._DocType; - } - set - { - } - } - #endregion - #region RefNbr - public abstract class refNbr : PX.Data.IBqlField - { - } - protected String _RefNbr; - - /// - /// [key] Reference number of the document. - /// - [PXDBString(15, IsUnicode = true, IsKey = true, InputMask = "")] - [PXDefault()] - [PXUIField(DisplayName = "Reference Nbr.", Visibility = PXUIVisibility.SelectorVisible, TabOrder = 1)] - [PXSelector(typeof(Search>>>), Filterable = true)] - [PXFieldDescription] - public virtual String RefNbr - { - get - { - return this._RefNbr; - } - set - { - this._RefNbr = value; - } - } - #endregion - #region OrigModule - public abstract class origModule : PX.Data.IBqlField - { - } - protected String _OrigModule; - - /// - /// Module, from which the document originates. - /// - /// - /// Code of the module of the system. Defaults to "AP". - /// Possible values are: "GL", "AP", "AR", "CM", "CA", "IN", "DR", "FA", "PM", "TX", "SO", "PO". - /// - [PXDBString(2, IsFixed = true)] - [PXDefault(GL.BatchModule.AP)] - [PXUIField(DisplayName = "Source", Visibility = PXUIVisibility.SelectorVisible, Enabled = false)] - [GL.BatchModule.FullList()] - public virtual String OrigModule - { - get - { - return this._OrigModule; - } - set - { - this._OrigModule = value; - } - } - #endregion - #region DocDate - public abstract class docDate : PX.Data.IBqlField - { - } - protected DateTime? _DocDate; - - /// - /// Date of the document. - /// - [PXDBDate()] - [PXDefault(typeof(AccessInfo.businessDate))] - [PXUIField(DisplayName = "Date", Visibility = PXUIVisibility.SelectorVisible)] - public virtual DateTime? DocDate - { - get - { - return this._DocDate; - } - set - { - this._DocDate = value; - } - } - #endregion - #region OrigDocDate - public abstract class origDocDate : PX.Data.IBqlField - { - } - protected DateTime? _OrigDocDate; - - /// - /// Date of the original (source) document. - /// - [PXDBDate()] - public virtual DateTime? OrigDocDate - { - get - { - return this._OrigDocDate; - } - set - { - this._OrigDocDate = value; - } - } - #endregion - #region TranPeriodID - public abstract class tranPeriodID : PX.Data.IBqlField - { - } - protected String _TranPeriodID; - - /// - /// Financial Period of the document. - /// - /// - /// Determined by the date of the document. Unlike - /// the value of this field can't be overriden by user. - /// - [TranPeriodID(typeof(APRegister.docDate))] - [PXUIField(DisplayName = "Transaction Period")] - public virtual String TranPeriodID - { - get - { - return this._TranPeriodID; - } - set - { - this._TranPeriodID = value; - } - } - #endregion - #region FinPeriodID - public abstract class finPeriodID : PX.Data.IBqlField - { - } - protected String _FinPeriodID; - - /// - /// Financial Period of the document. - /// - /// - /// Defaults to the period, to which the belongs, but can be overriden by user. - /// - [APOpenPeriod(typeof(APRegister.docDate))] - [PXDefault()] - [PXUIField(DisplayName = "Post Period", Visibility = PXUIVisibility.SelectorVisible)] - public virtual String FinPeriodID - { - get - { - return this._FinPeriodID; - } - set - { - this._FinPeriodID = value; - } - } - #endregion - #region VendorID - public abstract class vendorID : PX.Data.IBqlField - { - } - /// - /// Identifier of the , whom the document belongs to. - /// - [VendorActive( - Visibility = PXUIVisibility.SelectorVisible, - DescriptionField = typeof(Vendor.acctName), - CacheGlobal = true, - Filterable = true)] - [PXDefault] - public virtual int? VendorID - { - get; - set; - } - #endregion - #region VendorID_Vendor_acctName - public abstract class vendorID_Vendor_acctName : PX.Data.IBqlField - { - } - #endregion - #region VendorLocationID - public abstract class vendorLocationID : PX.Data.IBqlField - { - } - protected Int32? _VendorLocationID; - - /// - /// Identifier of the Location of the Vendor, associated with the document. - /// - /// - /// Corresponds to the field. Defaults to vendor's default location. - /// - [LocationID( - typeof(Where>, - And, - And>>>), - DescriptionField = typeof(Location.descr), - Visibility = PXUIVisibility.SelectorVisible)] - [PXDefault(typeof(Coalesce< - Search2, - And>>>, - Where>, - And, And>>>>, - Search>, - And, And>>>>>))] - public virtual Int32? VendorLocationID - { - get - { - return this._VendorLocationID; - } - set - { - this._VendorLocationID = value; - } - } - #endregion - #region CuryID - public abstract class curyID : PX.Data.IBqlField - { - } - protected String _CuryID; - - /// - /// Code of the Currency of the document. - /// - /// - /// Defaults to the company's base currency. - /// - [PXDBString(5, IsUnicode = true, InputMask = ">LLLLL")] - [PXUIField(DisplayName = "Currency", Visibility = PXUIVisibility.SelectorVisible)] - [PXDefault(typeof(Search))] - [PXSelector(typeof(Currency.curyID))] - public virtual String CuryID - { - get - { - return this._CuryID; - } - set - { - this._CuryID = value; - } - } - #endregion - #region APAccountID - public abstract class aPAccountID : PX.Data.IBqlField - { - } - protected Int32? _APAccountID; - - /// - /// Identifier of the AP account, to which the document belongs. - /// - /// - /// Corresponds to the field. - /// - [PXDefault] - [Account(typeof(APRegister.branchID), typeof(Search>, - And, - And, - And, IsNull, - Or>>>>>>>>), DisplayName = "AP Account")] - public virtual Int32? APAccountID - { - get - { - return this._APAccountID; - } - set - { - this._APAccountID = value; - } - } - #endregion - #region APSubID - public abstract class aPSubID : PX.Data.IBqlField - { - } - protected Int32? _APSubID; - - /// - /// Identifier of the AP subaccount, to which the document belongs. - /// - /// - /// Corresponds to the field. - /// - [PXDefault] - [SubAccount(typeof(APRegister.aPAccountID), typeof(APRegister.branchID), true, DescriptionField = typeof(Sub.description), DisplayName = "AP Subaccount", Visibility = PXUIVisibility.Visible)] - public virtual Int32? APSubID - { - get - { - return this._APSubID; - } - set - { - this._APSubID = value; - } - } - #endregion - #region LineCntr - public abstract class lineCntr : PX.Data.IBqlField - { - } - protected Int32? _LineCntr; - - /// - /// Counter of the document lines, used internally to assign numbers to newly created lines. - /// It is not recommended to rely on this fields to determine the exact count of lines, because it might not reflect the latter under various conditions. - /// - [PXDBInt()] - [PXDefault(0)] - public virtual Int32? LineCntr - { - get - { - return this._LineCntr; - } - set - { - this._LineCntr = value; - } - } - #endregion - #region CuryInfoID - public abstract class curyInfoID : PX.Data.IBqlField - { - } - protected Int64? _CuryInfoID; - - /// - /// Identifier of the CurrencyInfo object associated with the document. - /// - /// - /// Generated automatically. Corresponds to the field. - /// - [PXDBLong()] - [CurrencyInfo(ModuleCode = "AP")] - public virtual Int64? CuryInfoID - { - get - { - return this._CuryInfoID; - } - set - { - this._CuryInfoID = value; - } - } - #endregion - #region CuryOrigDocAmt - public abstract class curyOrigDocAmt : PX.Data.IBqlField - { - } - protected Decimal? _CuryOrigDocAmt; - - /// - /// The amount to be paid for the document in the currency of the document. (See ) - /// - [PXDefault(TypeCode.Decimal, "0.0")] - [PXDBCurrency(typeof(APRegister.curyInfoID), typeof(APRegister.origDocAmt))] - [PXUIField(DisplayName = "Amount", Visibility = PXUIVisibility.SelectorVisible)] - public virtual Decimal? CuryOrigDocAmt - { - get - { - return this._CuryOrigDocAmt; - } - set - { - this._CuryOrigDocAmt = value; - } - } - #endregion - #region OrigDocAmt - public abstract class origDocAmt : PX.Data.IBqlField - { - } - protected Decimal? _OrigDocAmt; - - /// - /// The amount to be paid for the document in the base currency of the company. (See ) - /// - [PXDBBaseCury()] - [PXDefault(TypeCode.Decimal, "0.0")] - [PXUIField(DisplayName = "Amount")] - public virtual Decimal? OrigDocAmt - { - get - { - return this._OrigDocAmt; - } - set - { - this._OrigDocAmt = value; - } - } - #endregion - #region CuryDocBal - public abstract class curyDocBal : PX.Data.IBqlField - { - } - protected Decimal? _CuryDocBal; - - /// - /// The balance of the Accounts Payable document after tax (if inclusive) and the discount in the currency of the document. (See ) - /// - [PXDefault(TypeCode.Decimal, "0.0")] - [PXDBCurrency(typeof(APRegister.curyInfoID), typeof(APRegister.docBal), BaseCalc = false)] - [PXUIField(DisplayName = "Balance", Visibility = PXUIVisibility.SelectorVisible, Enabled = false)] - public virtual Decimal? CuryDocBal - { - get - { - return this._CuryDocBal; - } - set - { - this._CuryDocBal = value; - } - } - #endregion - #region DocBal - public abstract class docBal : PX.Data.IBqlField - { - } - protected Decimal? _DocBal; - - /// - /// The balance of the Accounts Payable document after tax (if inclusive) and the discount in the base currency of the company. (See ) - /// - [PXDBBaseCury()] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? DocBal - { - get - { - return this._DocBal; - } - set - { - this._DocBal = value; - } - } - #endregion - #region DiscTot - public abstract class discTot : PX.Data.IBqlField - { - } - protected Decimal? _DiscTot; - - /// - /// Total discount associated with the document in the base currency of the company. (See ) - /// - [PXDBBaseCury()] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? DiscTot - { - get - { - return this._DiscTot; - } - set - { - this._DiscTot = value; - } - } - #endregion - #region CuryDiscTot - public abstract class curyDiscTot : PX.Data.IBqlField - { - } - protected Decimal? _CuryDiscTot; - - /// - /// Total discount associated with the document in the currency of the document. (See ) - /// - [PXDBCurrency(typeof(APRegister.curyInfoID), typeof(APRegister.discTot))] - [PXDefault(TypeCode.Decimal, "0.0")] - [PXUIField(DisplayName = "Discount Total", Enabled = true)] - public virtual Decimal? CuryDiscTot - { - get - { - return this._CuryDiscTot; - } - set - { - this._CuryDiscTot = value; - } - } - #endregion - #region DocDisc - public abstract class docDisc : PX.Data.IBqlField - { - } - protected Decimal? _DocDisc; - [PXBaseCury()] - [PXDefault(TypeCode.Decimal, "0.0", PersistingCheck = PXPersistingCheck.Nothing)] - public virtual Decimal? DocDisc - { - get - { - return this._DocDisc; - } - set - { - this._DocDisc = value; - } - } - #endregion - #region CuryDocDisc - public abstract class curyDocDisc : PX.Data.IBqlField - { - } - protected Decimal? _CuryDocDisc; - [PXCurrency(typeof(APRegister.curyInfoID), typeof(APRegister.docDisc))] - [PXDefault(TypeCode.Decimal, "0.0", PersistingCheck = PXPersistingCheck.Nothing)] - [PXUIField(DisplayName = "Document Discount", Enabled = true)] - public virtual Decimal? CuryDocDisc - { - get - { - return this._CuryDocDisc; - } - set - { - this._CuryDocDisc = value; - } - } - #endregion - #region CuryOrigDiscAmt - public abstract class curyOrigDiscAmt : PX.Data.IBqlField - { - } - protected Decimal? _CuryOrigDiscAmt; - - /// - /// !REV! The amount of the cash discount taken for the original document. - /// (Presented in the currency of the document, see ) - /// - [PXDefault(TypeCode.Decimal, "0.0")] - [PXDBCurrency(typeof(APRegister.curyInfoID), typeof(APRegister.origDiscAmt))] - [PXUIField(DisplayName = "Cash Discount", Visibility = PXUIVisibility.SelectorVisible)] - public virtual Decimal? CuryOrigDiscAmt - { - get - { - return this._CuryOrigDiscAmt; - } - set - { - this._CuryOrigDiscAmt = value; - } - } - #endregion - #region OrigDiscAmt - public abstract class origDiscAmt : PX.Data.IBqlField - { - } - protected Decimal? _OrigDiscAmt; - - /// - /// The amount of the cash discount taken for the original document. - /// (Presented in the base currency of the company, see ) - /// - [PXDBBaseCury()] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? OrigDiscAmt - { - get - { - return this._OrigDiscAmt; - } - set - { - this._OrigDiscAmt = value; - } - } - #endregion - #region CuryDiscTaken - public abstract class curyDiscTaken : PX.Data.IBqlField - { - } - protected Decimal? _CuryDiscTaken; - - /// - /// !REV! The amount of the cash discount taken. - /// (Presented in the currency of the document, see ) - /// - [PXDefault(TypeCode.Decimal, "0.0")] - [PXDBCurrency(typeof(APRegister.curyInfoID), typeof(APRegister.discTaken))] - public virtual Decimal? CuryDiscTaken - { - get - { - return this._CuryDiscTaken; - } - set - { - this._CuryDiscTaken = value; - } - } - #endregion - #region DiscTaken - public abstract class discTaken : PX.Data.IBqlField - { - } - protected Decimal? _DiscTaken; - - /// - /// The amount of the cash discount taken. - /// (Presented in the base currency of the company, see ) - /// - [PXDBBaseCury()] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? DiscTaken - { - get - { - return this._DiscTaken; - } - set - { - this._DiscTaken = value; - } - } - #endregion - #region CuryDiscBal - public abstract class curyDiscBal : PX.Data.IBqlField - { - } - protected Decimal? _CuryDiscBal; - - /// - /// The difference between the cash discount that was available and the actual amount of cash discount taken. - /// (Presented in the currency of the document, see ) - /// - [PXDefault(TypeCode.Decimal, "0.0")] - [PXDBCurrency(typeof(APRegister.curyInfoID), typeof(APRegister.discBal), BaseCalc = false)] - [PXUIField(DisplayName = "Cash Discount Balance", Visibility = PXUIVisibility.SelectorVisible, Enabled = false)] - public virtual Decimal? CuryDiscBal - { - get - { - return this._CuryDiscBal; - } - set - { - this._CuryDiscBal = value; - } - } - #endregion - #region DiscBal - public abstract class discBal : PX.Data.IBqlField - { - } - protected Decimal? _DiscBal; - - /// - /// The difference between the cash discount that was available and the actual amount of cash discount taken. - /// (Presented in the base currency of the company, see ) - /// - [PXDBBaseCury()] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? DiscBal - { - get - { - return this._DiscBal; - } - set - { - this._DiscBal = value; - } - } - #endregion - #region CuryOrigWhTaxAmt - public abstract class curyOrigWhTaxAmt : PX.Data.IBqlField - { - } - protected Decimal? _CuryOrigWhTaxAmt; - - /// - /// The amount of withholding tax calculated for the document, if applicable, in the currency of the document. (See ) - /// - [PXDefault(TypeCode.Decimal, "0.0")] - [PXDBCurrency(typeof(APRegister.curyInfoID), typeof(APRegister.origWhTaxAmt))] - [PXUIField(DisplayName = "With. Tax", Visibility = PXUIVisibility.SelectorVisible, Enabled = false)] - public virtual Decimal? CuryOrigWhTaxAmt - { - get - { - return this._CuryOrigWhTaxAmt; - } - set - { - this._CuryOrigWhTaxAmt = value; - } - } - #endregion - #region OrigWhTaxAmt - public abstract class origWhTaxAmt : PX.Data.IBqlField - { - } - protected Decimal? _OrigWhTaxAmt; - - /// - /// The amount of withholding tax calculated for the document, if applicable, in the base currency of the company. (See ) - /// - [PXDBBaseCury()] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? OrigWhTaxAmt - { - get - { - return this._OrigWhTaxAmt; - } - set - { - this._OrigWhTaxAmt = value; - } - } - #endregion - #region CuryWhTaxBal - public abstract class curyWhTaxBal : PX.Data.IBqlField - { - } - protected Decimal? _CuryWhTaxBal; - - /// - /// !REV! The difference between the original amount of withholding tax to be payed and the amount that was actually paid. - /// (Presented in the currency of the document, see ) - /// - [PXDefault(TypeCode.Decimal, "0.0")] - [PXDBCurrency(typeof(APRegister.curyInfoID), typeof(APRegister.whTaxBal), BaseCalc = false)] - public virtual Decimal? CuryWhTaxBal - { - get - { - return this._CuryWhTaxBal; - } - set - { - this._CuryWhTaxBal = value; - } - } - #endregion - #region WhTaxBal - public abstract class whTaxBal : PX.Data.IBqlField - { - } - protected Decimal? _WhTaxBal; - - /// - /// The difference between the original amount of withholding tax to be payed and the amount that was actually paid. - /// (Presented in the base currency of the company, see ) - /// - [PXDBBaseCury()] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? WhTaxBal - { - get - { - return this._WhTaxBal; - } - set - { - this._WhTaxBal = value; - } - } - #endregion - #region CuryTaxWheld - public abstract class curyTaxWheld : PX.Data.IBqlField - { - } - protected Decimal? _CuryTaxWheld; - - /// - /// !REV! The amount of tax withheld from the payments to the document. - /// (Presented in the currency of the document, see ) - /// - [PXDefault(TypeCode.Decimal, "0.0")] - [PXDBCurrency(typeof(APRegister.curyInfoID), typeof(APRegister.taxWheld))] - public virtual Decimal? CuryTaxWheld - { - get - { - return this._CuryTaxWheld; - } - set - { - this._CuryTaxWheld = value; - } - } - #endregion - #region TaxWheld - public abstract class taxWheld : PX.Data.IBqlField - { - } - protected Decimal? _TaxWheld; - - /// - /// The amount of tax withheld from the payments to the document. - /// (Presented in the base currency of the company, see ) - /// - [PXDBBaseCury()] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? TaxWheld - { - get - { - return this._TaxWheld; - } - set - { - this._TaxWheld = value; - } - } - #endregion - #region CuryChargeAmt - public abstract class curyChargeAmt : PX.Data.IBqlField - { - } - protected Decimal? _CuryChargeAmt; - - /// - /// The amount of charges associated with the document in the currency of the document. (See ) - /// - [PXDBCurrency(typeof(APRegister.curyInfoID), typeof(APRegister.chargeAmt))] - [PXDefault(TypeCode.Decimal, "0.0")] - [PXUIField(DisplayName = "Finance Charges", Visibility = PXUIVisibility.Visible, Enabled = false)] - public virtual Decimal? CuryChargeAmt - { - get - { - return this._CuryChargeAmt; - } - set - { - this._CuryChargeAmt = value; - } - } - #endregion - #region ChargeAmt - public abstract class chargeAmt : PX.Data.IBqlField - { - } - protected Decimal? _ChargeAmt; - - /// - /// The amount of charges associated with the document in the base currency of the company. (See ) - /// - [PXDBDecimal(4)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? ChargeAmt - { - get - { - return this._ChargeAmt; - } - set - { - this._ChargeAmt = value; - } - } - #endregion - #region DocDesc - public abstract class docDesc : PX.Data.IBqlField - { - } - protected String _DocDesc; - - /// - /// Description of the document. - /// - [PXDBString(60, IsUnicode = true)] - [PXUIField(DisplayName = "Description", Visibility = PXUIVisibility.SelectorVisible)] - public virtual String DocDesc - { - get - { - return this._DocDesc; - } - set - { - this._DocDesc = value; - } - } - #endregion - #region CreatedByID - public abstract class createdByID : PX.Data.IBqlField - { - } - protected Guid? _CreatedByID; - [PXDBCreatedByID()] - public virtual Guid? CreatedByID - { - get - { - return this._CreatedByID; - } - set - { - this._CreatedByID = value; - } - } - #endregion - #region CreatedByScreenID - public abstract class createdByScreenID : PX.Data.IBqlField - { - } - protected String _CreatedByScreenID; - [PXDBCreatedByScreenID()] - public virtual String CreatedByScreenID - { - get - { - return this._CreatedByScreenID; - } - set - { - this._CreatedByScreenID = value; - } - } - #endregion - #region CreatedDateTime - public abstract class createdDateTime : PX.Data.IBqlField - { - } - protected DateTime? _CreatedDateTime; - [PXDBCreatedDateTime()] - public virtual DateTime? CreatedDateTime - { - get - { - return this._CreatedDateTime; - } - set - { - this._CreatedDateTime = value; - } - } - #endregion - #region LastModifiedByID - public abstract class lastModifiedByID : PX.Data.IBqlField - { - } - protected Guid? _LastModifiedByID; - [PXDBLastModifiedByID()] - public virtual Guid? LastModifiedByID - { - get - { - return this._LastModifiedByID; - } - set - { - this._LastModifiedByID = value; - } - } - #endregion - #region LastModifiedByScreenID - public abstract class lastModifiedByScreenID : PX.Data.IBqlField - { - } - protected String _LastModifiedByScreenID; - [PXDBLastModifiedByScreenID()] - public virtual String LastModifiedByScreenID - { - get - { - return this._LastModifiedByScreenID; - } - set - { - this._LastModifiedByScreenID = value; - } - } - #endregion - #region LastModifiedDateTime - public abstract class lastModifiedDateTime : PX.Data.IBqlField - { - } - protected DateTime? _LastModifiedDateTime; - [PXDBLastModifiedDateTime()] - public virtual DateTime? LastModifiedDateTime - { - get - { - return this._LastModifiedDateTime; - } - set - { - this._LastModifiedDateTime = value; - } - } - #endregion - #region tstamp - public abstract class Tstamp : PX.Data.IBqlField - { - } - protected Byte[] _tstamp; - [PXDBTimestamp()] - public virtual Byte[] tstamp - { - get - { - return this._tstamp; - } - set - { - this._tstamp = value; - } - } - #endregion - #region DocClass - public abstract class docClass : PX.Data.IBqlField - { - } - - /// - /// Class of the document. This field is calculated based on the . - /// - /// - /// Possible values are: "N" - for Invoice, Credit Adjustment, Debit Adjustment, Quick Check and Void Quick Check; "P" - for Check, Void Check and Refund; "U" - for Prepayment. - /// - [PXString(1, IsFixed = true)] - public virtual string DocClass - { - [PXDependsOnFields(typeof(docType))] - get - { - return APDocType.DocClass(this._DocType); - } - set - { - } - } - #endregion - #region BatchNbr - public abstract class batchNbr : PX.Data.IBqlField - { - } - protected String _BatchNbr; - - /// - /// Number of the , generated for the document on release. - /// - /// - /// Corresponds to the Batch.BatchNbr field. - /// - [PXDBString(15, IsUnicode = true)] - [PXUIField(DisplayName = "Batch Nbr.", Visibility = PXUIVisibility.Visible, Enabled = false)] - [PXSelector(typeof(Search>>))] - public virtual String BatchNbr - { - get - { - return this._BatchNbr; - } - set - { - this._BatchNbr = value; - } - } - #endregion - #region PrebookBatchNbr - public abstract class prebookBatchNbr : PX.Data.IBqlField - { - } - protected String _PrebookBatchNbr; - - /// - /// Stores the number of the generated during prebooking. - /// - /// - /// Corresponds to the Batch.BatchNbr field. - /// - [PXDBString(15, IsUnicode = true)] - [PXUIField(DisplayName = "Pre-Releasing Batch Nbr.", Visibility = PXUIVisibility.Visible, Enabled = false)] - [PXSelector(typeof(Batch.batchNbr))] - public virtual String PrebookBatchNbr - { - get - { - return this._PrebookBatchNbr; - } - set - { - this._PrebookBatchNbr = value; - } - } - #endregion - #region VoidBatchNbr - public abstract class voidBatchNbr : PX.Data.IBqlField - { - } - protected String _VoidBatchNbr; - - /// - /// Stores the number of the generated when the document was voided. - /// - /// - /// Corresponds to the Batch.BatchNbr field. - /// - [PXDBString(15, IsUnicode = true)] - [PXUIField(DisplayName = "Void Batch Nbr.", Visibility = PXUIVisibility.Visible, Enabled = false)] - [PXSelector(typeof(Batch.batchNbr))] - public virtual String VoidBatchNbr - { - get - { - return this._VoidBatchNbr; - } - set - { - this._VoidBatchNbr = value; - } - } - #endregion - #region Released - public abstract class released : PX.Data.IBqlField - { - } - protected Boolean? _Released; - - /// - /// When set to true indicates that the document was released. - /// - [PXDBBool()] - [PXDefault(false)] - [PXUIField(DisplayName = "Released", Visible = false)] - public virtual Boolean? Released - { - get - { - return this._Released; - } - set - { - this._Released = value; - } - } - #endregion - #region OpenDoc - public abstract class openDoc : PX.Data.IBqlField - { - } - protected Boolean? _OpenDoc; - - /// - /// When set to true indicates that the document is open. - /// - [PXDBBool()] - [PXDefault(true)] - [PXUIField(DisplayName = "Open", Visible = false)] - public virtual Boolean? OpenDoc - { - get - { - return this._OpenDoc; - } - set - { - this._OpenDoc = value; - } - } - #endregion - #region Hold - public abstract class hold : PX.Data.IBqlField - { - } - protected Boolean? _Hold; - - /// - /// When set to true indicates that the document is on hold and thus cannot be released. - /// - [PXDBBool()] - [PXUIField(DisplayName = "Hold", Visibility = PXUIVisibility.Visible)] - [PXDefault(true, typeof(APSetup.holdEntry))] - public virtual Boolean? Hold - { - get - { - return this._Hold; - } - set - { - this._Hold = value; - } - } - #endregion - #region Scheduled - public abstract class scheduled : PX.Data.IBqlField - { - } - protected Boolean? _Scheduled; - - /// - /// When set to true indicates that the document is part of a Schedule and serves as a template for generating other documents according to it. - /// - [PXDBBool()] - [PXDefault(false)] - public virtual Boolean? Scheduled - { - get - { - return this._Scheduled; - } - set - { - this._Scheduled = value; - } - } - #endregion - #region Voided - public abstract class voided : PX.Data.IBqlField - { - } - protected Boolean? _Voided; - - /// - /// When set to true indicates that the document was voided. In this case field will hold the number of the voiding . - /// - [PXDBBool()] - [PXDefault(false)] - [PXUIField(DisplayName = "Void", Visible = false)] - public virtual Boolean? Voided - { - get - { - return this._Voided; - } - set - { - this._Voided = value; - } - } - #endregion - #region Printed - public abstract class printed : PX.Data.IBqlField - { - } - protected Boolean? _Printed; - - /// - /// When set to true indicates that the document was printed. - /// - [PXDBBool()] - [PXDefault(false)] - public virtual Boolean? Printed - { - get - { - return this._Printed; - } - set - { - this._Printed = value; - } - } - #endregion - #region Prebooked - public abstract class prebooked : PX.Data.IBqlField - { - } - protected Boolean? _Prebooked; - - /// - /// When set to true indicates that the document was prebooked. - /// - [PXDBBool()] - [PXDefault(false)] - [PXUIField(DisplayName = "Prebooked")] - public virtual Boolean? Prebooked - { - get - { - return this._Prebooked; - } - set - { - this._Prebooked = value; - } - } - #endregion - #region Approved - public abstract class approved : PX.Data.IBqlField - { - } - [PXDBBool] - [PXDefault(false, PersistingCheck = PXPersistingCheck.Nothing)] - public virtual bool? Approved - { - get; - set; - } - #endregion - #region Rejected - public abstract class rejected : IBqlField - { - } - [PXDBBool] - [PXDefault(false, PersistingCheck = PXPersistingCheck.Nothing)] - public bool? Rejected - { - get; - set; - } - #endregion - #region RequestApproval - public abstract class requestApproval : PX.Data.IBqlField - { - } - /// - /// Indicates that requests approval - /// for AP documents. - /// - [PXBool] - [PXDefault(typeof(Search), PersistingCheck = PXPersistingCheck.Nothing)] - [PXDBScalar(typeof(Search))] - [PXUIField(DisplayName = "Request Approval", Visible = false)] - public virtual bool? RequestApproval - { - get; - set; - } - #endregion - #region DontApprove - public abstract class dontApprove : PX.Data.IBqlField - { - } - /// - /// Indicates that the current document should be excluded from the - /// approval process. - /// - [PXBool] - [PXFormula(typeof(Switch< - Case, - Or, Equal>>, - True, - Case>, - False>>, - True>))] - [PXUIField(DisplayName = "Don't Approve", Visible = false, Enabled = false)] - public virtual bool? DontApprove - { - get; - set; - } - #endregion - #region NoteID - public abstract class noteID : PX.Data.IBqlField - { - } - protected Guid? _NoteID; - - /// - /// Identifier of the Note object, associated with the document. - /// - /// - /// Corresponds to the Note.NoteID field. - /// - [PXNote(DescriptionField = typeof(APRegister.refNbr))] - public virtual Guid? NoteID - { - get - { - return this._NoteID; - } - set - { - this._NoteID = value; - } - } - #endregion - #region RefNoteID - public abstract class refNoteID : PX.Data.IBqlField - { - } - protected Guid? _RefNoteID; - - /// - /// !REV! - /// - [PXDBGuid()] - public virtual Guid? RefNoteID - { - get - { - return this._RefNoteID; - } - set - { - this._RefNoteID = value; - } - } - #endregion - #region ClosedFinPeriodID - public abstract class closedFinPeriodID : PX.Data.IBqlField - { - } - protected String _ClosedFinPeriodID; - - /// - /// The Financial Period, in which the document was closed. - /// - /// - /// Corresponds to the field. - /// - [FinPeriodID()] - [PXUIField(DisplayName = "Closed Period", Visibility = PXUIVisibility.Invisible)] - public virtual String ClosedFinPeriodID - { - get - { - return this._ClosedFinPeriodID; - } - set - { - this._ClosedFinPeriodID = value; - } - } - #endregion - #region ClosedTranPeriodID - public abstract class closedTranPeriodID : PX.Data.IBqlField - { - } - protected String _ClosedTranPeriodID; - - /// - /// The Financial Period, in which the document was closed. - /// - /// - /// Corresponds to the field. - /// - [FinPeriodID()] - [PXUIField(DisplayName = "Closed Period", Visibility = PXUIVisibility.Invisible)] - public virtual String ClosedTranPeriodID - { - get - { - return this._ClosedTranPeriodID; - } - set - { - this._ClosedTranPeriodID = value; - } - } - #endregion - #region RGOLAmt - public abstract class rGOLAmt : PX.Data.IBqlField - { - } - protected Decimal? _RGOLAmt; - - /// - /// Realized Gain and Loss amount associated with the document. - /// - [PXDBDecimal(4)] - [PXDefault(TypeCode.Decimal, "0.0")] - public virtual Decimal? RGOLAmt - { - get - { - return this._RGOLAmt; - } - set - { - this._RGOLAmt = value; - } - } - #endregion - #region CuryRoundDiff - public abstract class curyRoundDiff : IBqlField { } - - /// - /// The difference between the original amount and the rounded amount in the currency of the document. (See ) - /// (Applicable only in case Invoice Rounding feature is on.) - /// - [PXDBCurrency(typeof(APRegister.curyInfoID), typeof(APRegister.roundDiff), BaseCalc = false)] - [PXDefault(TypeCode.Decimal, "0.0")] - [PXUIField(DisplayName = "Rounding Diff.", Visibility = PXUIVisibility.SelectorVisible, Enabled = false)] - public decimal? CuryRoundDiff - { - get; - set; - } - #endregion - #region RoundDiff - public abstract class roundDiff : IBqlField { } - - /// - /// The difference between the original amount and the rounded amount in the base currency of the company. (See ) - /// (Applicable only in case Invoice Rounding feature is on.) - /// - [PXDBBaseCury()] - [PXDefault(TypeCode.Decimal, "0.0")] - public decimal? RoundDiff - { - get; - set; - } - #endregion - #region CuryTaxRoundDiff - public abstract class curyTaxRoundDiff : IBqlField { } - - [PXDBCurrency(typeof(APRegister.curyInfoID), typeof(APRegister.taxRoundDiff), BaseCalc = false)] - [PXDefault(TypeCode.Decimal, "0.0")] - [PXUIField(DisplayName = "Rounding Diff.", Visibility = PXUIVisibility.SelectorVisible, Enabled = false)] - public decimal? CuryTaxRoundDiff - { - get; - set; - } - #endregion - #region TaxRoundDiff - public abstract class taxRoundDiff : IBqlField { } - - [PXDBBaseCury()] - [PXDefault(TypeCode.Decimal, "0.0")] - public decimal? TaxRoundDiff - { - get; - set; - } - #endregion - #region Payable - - /// - /// Read-only field indicating whether the document is payable. Depends solely on the APRegister.DocType field. - /// Opposite to field. - /// - /// - /// true - for payable documents, e.g. bills; false - for paying, e.g. checks. - /// - public virtual Boolean? Payable - { - [PXDependsOnFields(typeof(docType))] - get - { - return APDocType.Payable(this._DocType); - } - set - { - } - } - #endregion - #region Paying - - /// - /// Read-only field indicating whether the document is paying. Depends solely on the APRegister.DocType field. - /// Opposite to field. - /// - /// - /// true - for paying documents, e.g. checks; false - for payable ones, e.g. bills. - /// - public virtual Boolean? Paying - { - [PXDependsOnFields(typeof(docType))] - get - { - return (APDocType.Payable(this._DocType) == false); - } - set - { - } - } - #endregion - #region SortOrder - - /// - /// Read-only field determining the sort order for AP documents based on the field. - /// - public virtual Int16? SortOrder - { - [PXDependsOnFields(typeof(docType))] - get - { - return APDocType.SortOrder(this._DocType); - } - set - { - } - } - #endregion - #region SignBalance - - /// - /// Read-only field indicating the sign of the document's impact on AP balance . - /// Depends solely on the - /// - /// - /// Can be 1, -1 or 0. - /// - public virtual Decimal? SignBalance - { - [PXDependsOnFields(typeof(docType))] - get - { - return APDocType.SignBalance(this._DocType); - } - set - { - } - } - #endregion - #region SignAmount - - /// - /// Read-only field indicating the sign of the document amount. - /// Depends solely on the - /// - /// - /// Can be 1, -1 or 0. - /// - public virtual Decimal? SignAmount - { - [PXDependsOnFields(typeof(docType))] - get - { - return APDocType.SignAmount(this._DocType); - } - set - { - } - } - #endregion - #region Status - public abstract class status : IBqlField { } - protected string _Status; - - /// - /// Status of the document. The field is calculated based on the values of status flag. It can't be changed directly. - /// The fields tht determine status of a document are: , , , - /// , , , , . - /// - /// - /// Possible values are: - /// "H" - Hold, "B" - Balanced, "V" - Voided, "S" - Scheduled, - /// "N" - Open, "C" - Closed, "P" - Printed, "K" - Prebooked, - /// "E" - Pending Approval, "R" - Rejected, "Z" - Reserved. - /// Defaults to Hold. - /// - [PXDBString(1, IsFixed = true)] - [PXDefault(APDocStatus.Hold)] - [PXUIField(DisplayName = "Status", Visibility = PXUIVisibility.SelectorVisible, Enabled = false)] - [APDocStatus.List] - [SetStatus] - [PXDependsOnFields( - typeof(APRegister.voided), - typeof(APRegister.hold), - typeof(APRegister.scheduled), - typeof(APRegister.released), - typeof(APRegister.printed), - typeof(APRegister.prebooked), - typeof(APRegister.openDoc), - typeof(APRegister.approved), - typeof(APRegister.rejected))] - public virtual string Status - { - get - { - return this._Status; - } - set - { - this._Status = value; - } - } - #endregion - #region Methods - public class SetStatusAttribute : PXEventSubscriberAttribute, IPXRowUpdatingSubscriber, IPXRowInsertingSubscriber - { - public override void CacheAttached(PXCache sender) - { - base.CacheAttached(sender); - - sender.Graph.FieldUpdating.AddHandler( - sender.GetItemType(), - nameof(APRegister.hold), - (cache, e) => - { - PXBoolAttribute.ConvertValue(e); - - APRegister item = e.Row as APRegister; - if (item != null) - { - StatusSet(cache, item, (bool?)e.NewValue); - } - }); - - sender.Graph.FieldVerifying.AddHandler( - sender.GetItemType(), - nameof(APRegister.status), - (cache, e) => { e.NewValue = cache.GetValue(e.Row); }); - - sender.Graph.RowSelecting.AddHandler(sender.GetItemType(), RowSelecting); - - sender.Graph.RowSelected.AddHandler( - sender.GetItemType(), - (cache, e) => - { - APRegister document = e.Row as APRegister; - - if (document != null) - { - StatusSet(cache, document, document.Hold); - } - }); - } - - protected virtual void StatusSet(PXCache cache, APRegister item, bool? HoldVal) - { - if (item.Voided == true) - { - item.Status = APDocStatus.Voided; - } - else if (item.Hold == true) - { - if (item.Released == true) - { - item.Status = APDocStatus.Reserved; - } - else - { - item.Status = APDocStatus.Hold; - } - } - else if (item.Scheduled == true) - { - item.Status = APDocStatus.Scheduled; - } - else if (item.Rejected == true) - { - item.Status = APDocStatus.Rejected; - } - else if (item.Released != true) - { - if (item.Printed == true && item.DocType == APDocType.Check) - { - item.Status = APDocStatus.Printed; - } - else if (item.Prebooked == true) - { - item.Status = APDocStatus.Prebooked; - } - else if ( - item.Approved != true && - item.DontApprove != true) - { - item.Status = APDocStatus.PendingApproval; - } - else - { - item.Status = APDocStatus.Balanced; - } - } - else if (item.OpenDoc == true) - { - item.Status = APDocStatus.Open; - } - else if (item.OpenDoc == false) - { - item.Status = APDocStatus.Closed; - } - } - - public virtual void RowSelecting(PXCache sender, PXRowSelectingEventArgs e) - { - APRegister item = (APRegister)e.Row; - if (item != null) - StatusSet(sender, item, item.Hold); - } - - public virtual void RowInserting(PXCache sender, PXRowInsertingEventArgs e) - { - APRegister item = (APRegister)e.Row; - StatusSet(sender, item, item.Hold); - } - - public virtual void RowUpdating(PXCache sender, PXRowUpdatingEventArgs e) - { - APRegister item = (APRegister)e.NewRow; - StatusSet(sender, item, item.Hold); - } - } - #endregion - #region ScheduleID - public abstract class scheduleID : IBqlField - { - } - protected string _ScheduleID; - - /// - /// Identifier of the Schedule object, associated with the document. - /// In case is true, ScheduleID points to the Schedule, to which the document belongs as a template. - /// Otherwise, ScheduleID points to the Schedule, from which this document was generated, if any. - /// - /// - /// Corresponds to the field. - /// - [PXDBString(10, IsUnicode = true)] - public virtual string ScheduleID - { - get - { - return this._ScheduleID; - } - set - { - this._ScheduleID = value; - } - } - #endregion - #region ImpRefNbr - public abstract class impRefNbr : PX.Data.IBqlField - { - } - protected String _ImpRefNbr; - - /// - /// Implementation specific reference number of the document. - /// This field is neither filled nor used by the core Acumatica itself, but may be utilized by customizations or extensions. - /// - [PXDBString(15, IsUnicode = true)] - public virtual String ImpRefNbr - { - get - { - return this._ImpRefNbr; - } - set - { - this._ImpRefNbr = value; - } - } - #endregion - - #region IsTaxValid - public abstract class isTaxValid : PX.Data.IBqlField - { - } - - /// - /// When true, indicates that the amount of tax calculated with the external Tax Engine(Avalara) is up to date. - /// If this field equals false, the document was updated since last synchronization with the Tax Engine - /// and taxes might need recalculation. - /// - [PXDBBool()] - [PXDefault(false)] - [PXUIField(DisplayName = "Tax is up to date", Enabled = false)] - public virtual Boolean? IsTaxValid - { - get; - set; - } - #endregion - #region IsTaxPosted - public abstract class isTaxPosted : PX.Data.IBqlField - { - } - - /// - /// When true, indicates that the tax information was successfully commited to the external Tax Engine(Avalara). - /// - [PXDBBool()] - [PXDefault(false)] - [PXUIField(DisplayName = "Tax is posted/commited to the external Tax Engine(Avalara)", Enabled = false)] - public virtual Boolean? IsTaxPosted - { - get; - set; - } - #endregion - #region IsTaxSaved - public abstract class isTaxSaved : PX.Data.IBqlField - { - } - - /// - /// Indicates whether the tax information related to the document was saved to the external Tax Engine (Avalara). - /// - [PXDBBool()] - [PXDefault(false)] - [PXUIField(DisplayName = "Tax is saved in external Tax Engine(Avalara)", Enabled = false)] - public virtual Boolean? IsTaxSaved - { - get; - set; - } - #endregion - #region OrigDocType - public abstract class origDocType : PX.Data.IBqlField - { - } - protected String _OrigDocType; - - /// - /// Type of the original (source) document. - /// - [PXDBString(3, IsFixed = true)] - [APDocType.List()] - [PXUIField(DisplayName = "Orig. Doc. Type")] - public virtual String OrigDocType - { - get - { - return this._OrigDocType; - } - set - { - this._OrigDocType = value; - } - } - #endregion - #region OrigRefNbr - public abstract class origRefNbr : PX.Data.IBqlField - { - } - protected String _OrigRefNbr; - - /// - /// Reference number of the original (source) document. - /// - [PXDBString(15, IsUnicode = true, InputMask = "")] - [PXUIField(DisplayName = "Orig. Ref. Nbr.")] - public virtual String OrigRefNbr - { - get - { - return this._OrigRefNbr; - } - set - { - this._OrigRefNbr = value; - } - } - #endregion - #region Released - public abstract class releasedOrPrebooked : IBqlField - { - } - /// - /// Read-only field that is equal to true in case the document - /// was either prebooked or - /// released. - /// - [PXBool] - public virtual bool? ReleasedOrPrebooked - { - [PXDependsOnFields(typeof(released), typeof(prebooked))] - get - { - return - this.Released == true || - this.Prebooked == true; - } - set - { - } - } - #endregion - #region TaxCalcMode - public abstract class taxCalcMode : IBqlField { } - protected string _TaxCalcMode; - [PXDBString(1, IsFixed = true)] - [PXDefault(VendorClass.taxCalcMode.TaxSetting, typeof(Search>, - And>>>>))] - [VendorClass.taxCalcMode.List] - [PXUIField(DisplayName = "Tax Calculation Mode")] - public virtual string TaxCalcMode - { - get { return this._TaxCalcMode; } - set { this._TaxCalcMode = value; } - } - #endregion - internal string WarningMessage { get; set; } - #region EmployeeWorkgroupID - public abstract class employeeWorkgroupID : PX.Data.IBqlField - { - } - /// - /// The workgroup that is responsible for the document. - /// - /// - /// Corresponds to the EPCompanyTree.WorkGroupID field. - /// - [PXDBInt] - [PXDefault(typeof(Vendor.workgroupID), PersistingCheck = PXPersistingCheck.Nothing)] - [PXCompanyTreeSelector] - [PXUIField(DisplayName = Messages.WorkgroupID, Enabled = false)] - public virtual int? EmployeeWorkgroupID - { - get; - set; - } - #endregion - #region EmployeeID - public abstract class employeeID : IBqlField - { - } - /// - /// The employee responsible - /// for the document. - /// - /// - /// Corresponds to the field. - /// - [PXDBGuid] - [PXDefault(typeof(Coalesce< - Search< - CREmployee.userID, - Where< - CREmployee.userID, Equal>, - And>>>, - Search< - BAccount.ownerID, - Where< - BAccount.bAccountID, Equal>>>>), - PersistingCheck = PXPersistingCheck.Nothing)] - [PXOwnerSelector(typeof(APRegister.employeeWorkgroupID))] - [PXUIField(DisplayName = Messages.Owner)] - public virtual Guid? EmployeeID - { - get; - set; - } - #endregion - #region WorkgroupID - public abstract class workgroupID : PX.Data.IBqlField - { - } - /// - /// The workgroup that is responsible for document - /// approval process. - /// - [PXInt] - [PXSelector( - typeof(Search), - SubstituteKey = typeof(EPCompanyTree.description))] - [PXUIField(DisplayName = Messages.ApprovalWorkGroupID, Enabled = false)] - public virtual int? WorkgroupID - { - get; - set; - } - #endregion - #region OwnerID - public abstract class ownerID : IBqlField - { - } - /// - /// The employee responsible - /// for document approval process. - /// - /// - /// Corresponds to the field. - /// - [PXGuid] - [PXOwnerSelector] - [PXUIField(DisplayName = Messages.Approver, Enabled = false)] - public virtual Guid? OwnerID - { - get; - set; - } - #endregion - } - - [PXProjection(typeof(Select2>>>))] - [PXBreakInheritance] - [Serializable] - public partial class APRegisterAccess : Vendor - { - #region DocType - public abstract class docType : PX.Data.IBqlField - { - } - protected String _DocType; - [PXDBString(3, IsKey = true, IsFixed = true, BqlField = typeof(APRegister.docType))] - public virtual String DocType - { - get - { - return this._DocType; - } - set - { - this._DocType = value; - } - } - #endregion - #region RefNbr - public abstract class refNbr : PX.Data.IBqlField - { - } - protected String _RefNbr; - [PXDBString(15, IsUnicode = true, IsKey = true, BqlField = typeof(APRegister.refNbr))] - public virtual String RefNbr - { - get - { - return this._RefNbr; - } - set - { - this._RefNbr = value; - } - } - #endregion - #region Scheduled - public abstract class scheduled : PX.Data.IBqlField - { - } - protected Boolean? _Scheduled; - [PXDBBool(BqlField = typeof(APRegister.scheduled))] - public virtual Boolean? Scheduled - { - get - { - return this._Scheduled; - } - set - { - this._Scheduled = value; - } - } - #endregion - #region ScheduleID - public abstract class scheduleID : IBqlField - { - } - protected string _ScheduleID; - [PXDBString(10, IsUnicode = true, BqlField = typeof(APRegister.scheduleID))] - public virtual string ScheduleID - { - get - { - return this._ScheduleID; - } - set - { - this._ScheduleID = value; - } - } - #endregion - } - - [PXProjection(typeof(Select))] - public class APRegisterP : IBqlTable - { - #region OrigModule - public abstract class origModule : PX.Data.IBqlField - { - } - protected String _OrigModule; - - [PXDBString(2, IsFixed = true, BqlField = typeof(APRegister.origModule))] - public virtual String OrigModule - { - get - { - return this._OrigModule; - } - set - { - this._OrigModule = value; - } - } - #endregion - #region DocDesc - public abstract class docDesc : PX.Data.IBqlField - { - } - protected String _DocDesc; - - [PXDBString(60, IsUnicode = true, BqlField = typeof(APRegister.docDesc))] - public virtual String DocDesc - { - get - { - return this._DocDesc; - } - set - { - this._DocDesc = value; - } - } - #endregion - #region DocType - public abstract class docType : PX.Data.IBqlField - { - } - protected String _DocType; - - [PXDBString(3, IsFixed = true, BqlField = typeof(APRegister.docType))] - public virtual String OrigDocType - { - get - { - return this._DocType; - } - set - { - this._DocType = value; - } - } - #endregion - #region RefNbr - public abstract class refNbr : PX.Data.IBqlField - { - } - protected String _RefNbr; - - [PXDBString(15, IsUnicode = true, BqlField = typeof(APRegister.refNbr))] - public virtual String RefNbr - { - get - { - return this._RefNbr; - } - set - { - this._RefNbr = value; - } - } - #endregion - } -} \ No newline at end of file diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Test/ARDocumentRelease.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Test/ARDocumentRelease.cs deleted file mode 100644 index f9ebf6434..000000000 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Test/ARDocumentRelease.cs +++ /dev/null @@ -1,5688 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; - -using PX.Data; - -using PX.Common; - -using PX.Objects.AR.BQL; -using PX.Objects.CM; -using PX.Objects.GL; -using PX.Objects.CS; -using PX.Objects.PM; -using PX.Objects.TX; -using PX.Objects.CA; -using PX.Objects.DR; -using PX.Objects.CR; -using PX.Objects.SO; -using PX.Objects.AR.CCPaymentProcessing; -using PX.Objects.AR.Overrides.ARDocumentRelease; -using PX.Objects.Common; -using PX.Objects.Common.DataIntegrity; - -using Avalara.AvaTax.Adapter; -using Avalara.AvaTax.Adapter.TaxService; - -using SOOrder = PX.Objects.SO.SOOrder; -using SOInvoice = PX.Objects.SO.SOInvoice; -using SOOrderShipment = PX.Objects.SO.SOOrderShipment; -using INTran = PX.Objects.IN.INTran; -using PMTran = PX.Objects.PM.PMTran; -using CRLocation = PX.Objects.CR.Standalone.Location; - -namespace PX.Objects.AR -{ - [System.SerializableAttribute()] - public partial class BalancedARDocument : ARRegister - { - #region Selected - public new abstract class selected : IBqlField - { - } - #endregion - #region DocType - public new abstract class docType : PX.Data.IBqlField - { - } - #endregion - #region RefNbr - public new abstract class refNbr : PX.Data.IBqlField - { - } - #endregion - #region OrigModule - public new abstract class origModule : PX.Data.IBqlField - { - } - #endregion - #region OpenDoc - public new abstract class openDoc : PX.Data.IBqlField - { - } - #endregion - #region Released - public new abstract class released : PX.Data.IBqlField - { - } - #endregion - #region Hold - public new abstract class hold : PX.Data.IBqlField - { - } - #endregion - #region Scheduled - public new abstract class scheduled : PX.Data.IBqlField - { - } - #endregion - #region Voided - public new abstract class voided : PX.Data.IBqlField - { - } - #endregion - #region Status - public new abstract class status : PX.Data.IBqlField - { - } - [PXDBString(1, IsFixed = true)] - [PXUIField(DisplayName = "Status", Visibility = PXUIVisibility.SelectorVisible, Enabled = false)] - [ARDocStatus.List()] - public override String Status - { - get - { - return this._Status; - } - set - { - this._Status = value; - } - } - #endregion - #region CreatedByID - public new abstract class createdByID : PX.Data.IBqlField - { - } - #endregion - #region LastModifiedByID - public new abstract class lastModifiedByID : PX.Data.IBqlField - { - } - #endregion - #region CustomerRefNbr - public abstract class customerRefNbr : IBqlField - { - } - protected String _CustomerRefNbr; - [PXString(40, IsUnicode = true)] - [PXUIField(DisplayName = "Customer Order")] - public String CustomerRefNbr - { - get - { - return _CustomerRefNbr; - } - set - { - _CustomerRefNbr = value; - } - } - #endregion - #region IsTaxValid - public new abstract class isTaxValid : PX.Data.IBqlField - { - } - #endregion - #region IsTaxPosted - public new abstract class isTaxPosted : PX.Data.IBqlField - { - } - #endregion - #region IsTaxSaved - public new abstract class isTaxSaved : PX.Data.IBqlField - { - } - #endregion - #region PaymentMethodID - public abstract class paymentMethodID : IBqlField { } - [PXString(10, IsUnicode = true)] - [PXUIField(DisplayName = CA.Messages.PaymentMethod, Visible = false)] - public virtual string PaymentMethodID { get; set; } - #endregion - } - - - public class PXMassProcessException : PXException - { - protected Exception _InnerException; - protected int _ListIndex; - - public int ListIndex - { - get - { - return this._ListIndex; - } - } - - public PXMassProcessException(int ListIndex, Exception InnerException) - : base(InnerException is PXOuterException ? InnerException.Message + "\r\n" + String.Join("\r\n", ((PXOuterException)InnerException).InnerMessages) : InnerException.Message, InnerException) - { - this._ListIndex = ListIndex; - } - - public PXMassProcessException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - PXReflectionSerializer.RestoreObjectProps(this, info); - } - - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - PXReflectionSerializer.GetObjectData(this, info); - base.GetObjectData(info, context); - } - } - - [PX.Objects.GL.TableAndChartDashboardType] - public class ARDocumentRelease : PXGraph - { - public PXCancel Cancel; - [PXFilterable] - [PX.SM.PXViewDetailsButton(typeof(BalancedARDocument.refNbr), WindowMode = PXRedirectHelper.WindowMode.NewWindow)] - public PXProcessingJoin, - And>>, - LeftJoin, - And>>, - InnerJoinSingleTable>, - LeftJoin, - And, - And, - And>>>>>>>>, - Where2>, And, And, And, And, And, Or, And>>>>>>>>> ARDocumentList; - - public PXSetup arsetup; - - public static string[] TransClassesWithoutZeroPost = { GLTran.tranClass.Discount, GLTran.tranClass.RealizedAndRoundingGOL, GLTran.tranClass.WriteOff }; - - public ARDocumentRelease() - { - ARSetup setup = arsetup.Current; - ARDocumentList.SetProcessDelegate( - delegate (List list) - { - List newlist = new List(list.Count); - foreach (BalancedARDocument doc in list) - { - newlist.Add(doc); - } - ReleaseDoc(newlist, true); - } - ); - ARDocumentList.SetProcessCaption(Messages.Release); - ARDocumentList.SetProcessAllCaption(Messages.ReleaseAll); - } - - public delegate void ARMassProcessDelegate(ARRegister ardoc, bool isAborted); - - public delegate void ARMassProcessReleaseTransactionScopeDelegate(ARRegister ardoc); - - public static void ReleaseDoc(List list, bool isMassProcess) - { - ReleaseDoc(list, isMassProcess, null, null); - } - - public static void ReleaseDoc(List list, bool isMassProcess, List externalPostList) - { - ReleaseDoc(list, isMassProcess, externalPostList, null); - } - - public static void ReleaseDoc(List list, bool isMassProcess, List externalPostList, ARMassProcessDelegate onsuccess) - { - ReleaseDoc(list, isMassProcess, externalPostList, onsuccess, null); - } - - /// - /// Static function for release of AR documents and posting of the released batch. - /// Released batches will be posted if the corresponded flag in ARSetup is set to true. - /// SkipPost parameter is used to override this flag. - /// This function can not be called from inside of the covering DB transaction scope, unless skipPost is set to true. - /// - /// List of the documents to be released - /// Flag specifing if the function is called from mass process - affects error handling - /// List of batches that should not be posted inside the release procedure - /// Delegate to be called if release process completed successfully - /// Delegate to be called inside the transaction scope of AR document release process - public static void ReleaseDoc(List list, bool isMassProcess, List externalPostList, ARMassProcessDelegate onsuccess, ARMassProcessReleaseTransactionScopeDelegate onreleasecomplete) - { - bool failed = false; - ARReleaseProcess rg = PXGraph.CreateInstance(); - JournalEntry je = PXGraph.CreateInstance(); - je.FieldVerifying.AddHandler((PXCache sender, PXFieldVerifyingEventArgs e) => { e.Cancel = true; }); - je.FieldVerifying.AddHandler((PXCache sender, PXFieldVerifyingEventArgs e) => { e.Cancel = true; }); - je.RowInserting.AddHandler((sender, e) => { je.SetZeroPostIfUndefined((GLTran)e.Row, TransClassesWithoutZeroPost); }); - - PostGraph pg = PXGraph.CreateInstance(); - Dictionary batchbind = new Dictionary(); - List pmBatchList = new List(); - bool isSkipPost = externalPostList != null; - - for (int i = 0; i < list.Count; i++) - { - if (list[i] == null) - continue; - - ARRegister doc = list[i]; - try - { - bool onefailed = false; - rg.Clear(); - - if (onsuccess != null || onreleasecomplete != null) - { - PXTimeStampScope.SetRecordComesFirst(typeof(ARRegister), true); - PXTimeStampScope.DuplicatePersisted(rg.ARDocument.Cache, doc, typeof(ARInvoice)); - } - - try - { - List childs = rg.ReleaseDocProc(je, doc, pmBatchList, onreleasecomplete); - - object cached; - if ((cached = rg.ARDocument.Cache.Locate(doc)) != null) - { - PXCache.RestoreCopy(doc, (ARRegister)cached); - doc.Selected = true; - } - - int k; - if ((k = je.created.IndexOf(je.BatchModule.Current)) >= 0 && batchbind.ContainsKey(k) == false) - { - batchbind.Add(k, i); - } - - - if (childs != null) - { - foreach (ARRegister child in childs) - { - rg.Clear(); - rg.ReleaseDocProc(je, child, pmBatchList, null); - - if ((cached = rg.ARDocument.Cache.Locate(doc)) != null) - { - PXCache.RestoreCopy(doc, (ARRegister)cached); - doc.Selected = true; - } - } - } - } - catch - { - je.CleanupCreated(batchbind.Keys); - je.Clear(); - - onefailed = true; - throw; - } - finally - { - if (onsuccess != null) - { - onsuccess(doc, onefailed); - } - } - - if (isMassProcess) - { - if (string.IsNullOrEmpty(doc.WarningMessage)) - PXProcessing.SetInfo(i, ActionsMessages.RecordProcessed); - else - { - PXProcessing.SetWarning(i, doc.WarningMessage); - } - } - } - catch (Exception e) - { - if (isMassProcess) - { - PXProcessing.SetError(i, e); - failed = true; - } - else - { - throw new PXMassProcessException(i, e); - } - } - } - - if (isSkipPost) - { - if (rg.AutoPost) - externalPostList.AddRange(je.created); - } - else - { - for (int i = 0; i < je.created.Count; i++) - { - Batch batch = je.created[i]; - try - { - if (rg.AutoPost) - { - pg.Clear(); - pg.PostBatchProc(batch); - } - } - catch (Exception e) - { - if (isMassProcess) - { - failed = true; - PXProcessing.SetError(batchbind[i], e); - } - else - { - throw new PXMassProcessException(batchbind[i], e); - } - } - } - } - if (failed) - { - throw new PXOperationCompletedWithErrorException(GL.Messages.DocumentsNotReleased); - } - - List> infoList = new List>(); - ProcessInfo processInfo = new ProcessInfo(0); - processInfo.Batches.AddRange(pmBatchList); - infoList.Add(processInfo); - PM.RegisterRelease.Post(infoList, isMassProcess); - } - - protected virtual IEnumerable ardocumentlist() - { - PXSelectBase cmd = new PXSelectJoinGroupBy>, - LeftJoin, - And, - And, - And>>>>, - LeftJoin, - And>>, - LeftJoin, - And>>>>>>, - Where2>, - And, - And, - And, - And2>, - And, - And, - Or, And>>>>>>>>>, - Aggregate>>>>>>>>>>>>>>>>, - OrderBy>>>(this); - - int startRow = PXView.StartRow; - int totalRows = 0; - - bool isSyncPosition = PXView.Searches.Any(search => search != null); - - foreach (PXResult res in - cmd.View.Select( - null, - null, - PXView.Searches, - ARDocumentList.View.GetExternalSorts(), - ARDocumentList.View.GetExternalDescendings(), - ARDocumentList.View.GetExternalFilters(), - ref startRow, - PXView.MaximumRows, - ref totalRows)) - { - BalancedARDocument ardoc = (BalancedARDocument)res; - ardoc = ARDocumentList.Locate(ardoc) ?? ardoc; - ARInvoice invoice = (ARInvoice)res; - ARPayment payment = (ARPayment)res; - - ardoc.PaymentMethodID = payment?.PaymentMethodID; - - if (invoice != null && string.IsNullOrEmpty(invoice.InvoiceNbr) == false) - { - ardoc.CustomerRefNbr = invoice.InvoiceNbr; - } - else if (payment != null && string.IsNullOrEmpty(payment.ExtRefNbr) == false) - { - ardoc.CustomerRefNbr = payment.ExtRefNbr; - } - - if (invoice != null && string.IsNullOrEmpty(invoice.RefNbr) == false) - { - //if PrintBeforeRelease is off and EmailBeforeRelease is on document will be simply skipped - if (ardoc.Released == false && ardoc.Status == ARDocStatus.PendingPrint && arsetup.Current.PrintBeforeRelease != true) - { - ardoc.Status = ARDocStatus.Balanced; - } - if (ardoc.Released == false && ardoc.Status == ARDocStatus.PendingEmail && arsetup.Current.EmailBeforeRelease != true) - { - ardoc.Status = ARDocStatus.Balanced; - } - } - - if (payment != null && payment.PMInstanceID != null - && this.arsetup.Current.IntegratedCCProcessing == true) - { - // Filter out payments by credit cards - they are processed separately - PXResult paymentMethodResult = (PXResult) - PXSelectJoin< - CustomerPaymentMethod, - InnerJoin>>, - Where>>> - .Select(this, payment.PMInstanceID); - - PaymentMethod paymentMethod = paymentMethodResult; - - if (paymentMethod != null && - paymentMethod.PaymentType == PaymentMethodType.CreditCard && - paymentMethod.ARIsProcessingRequired == true) - { - continue; - } - } - - ARAdjust adj = res; - if (ardoc.Released == true || - invoice.RefNbr == null || - ( - (arsetup.Current.PrintBeforeRelease == false || - invoice.Printed == true || invoice.DontPrint == true) - && - (arsetup.Current.EmailBeforeRelease == false || - invoice.Emailed == true || invoice.DontEmail == true) - )) - { - if (adj.AdjdRefNbr != null) - { - ardoc.DocDate = adj.AdjgDocDate; - ardoc.TranPeriodID = adj.AdjgTranPeriodID; - ardoc.FinPeriodID = adj.AdjgFinPeriodID; - } - yield return new PXResult(ardoc, res, res, res, res); - } - } - - PXView.StartRow = 0; - } - - [PXHidden()] - [Serializable()] - public partial class ARInvoice : IBqlTable - { - #region DocType - public abstract class docType : PX.Data.IBqlField - { - } - [PXDBString(3, IsKey = true, IsFixed = true)] - public virtual String DocType - { - get; - set; - } - #endregion - #region RefNbr - public abstract class refNbr : PX.Data.IBqlField - { - } - [PXDBString(15, IsKey = true, IsUnicode = true)] - public virtual String RefNbr - { - get; - set; - } - #endregion - #region InvoiceNbr - public abstract class invoiceNbr : PX.Data.IBqlField - { - } - [PXDBString(15, IsKey = true, IsUnicode = true)] - public virtual String InvoiceNbr - { - get; - set; - } - #endregion - #region DontPrint - public abstract class dontPrint : PX.Data.IBqlField - { - } - protected Boolean? _DontPrint; - [PXDBBool()] - public virtual Boolean? DontPrint - { - get; - set; - } - #endregion - #region Printed - public abstract class printed : PX.Data.IBqlField - { - } - protected Boolean? _Printed; - [PXDBBool()] - public virtual Boolean? Printed - { - get; - set; - } - #endregion - #region DontEmail - public abstract class dontEmail : PX.Data.IBqlField - { - } - protected Boolean? _DontEmail; - [PXDBBool()] - public virtual Boolean? DontEmail - { - get; - set; - } - #endregion - #region Emailed - public abstract class emailed : PX.Data.IBqlField - { - } - protected Boolean? _Emailed; - [PXDBBool()] - public virtual Boolean? Emailed - { - get; - set; - } - #endregion - } - - [PXHidden()] - [Serializable()] - public partial class ARPayment : IBqlTable - { - #region DocType - public abstract class docType : PX.Data.IBqlField - { - } - [PXDBString(3, IsKey = true, IsFixed = true)] - public virtual String DocType - { - get; - set; - } - #endregion - #region RefNbr - public abstract class refNbr : PX.Data.IBqlField - { - } - [PXDBString(15, IsKey = true, IsUnicode = true)] - public virtual String RefNbr - { - get; - set; - } - #endregion - #region ExtRefNbr - public abstract class extRefNbr : PX.Data.IBqlField - { - } - [PXDBString(15, IsUnicode = true)] - public virtual String ExtRefNbr - { - get; - set; - } - #endregion - #region PMInstanceID - public abstract class pMInstanceID : PX.Data.IBqlField - { - } - [PXDBInt()] - public virtual int? PMInstanceID - { - get; - set; - } - #endregion - #region PaymentMethodID - public abstract class paymentMethodID : IBqlField { } - [PXDBString(10, IsUnicode = true)] - public virtual string PaymentMethodID { get; set; } - #endregion - } - } - - public class ARPayment_CurrencyInfo_Currency_Customer : PXSelectJoin>, InnerJoin>, LeftJoin>, LeftJoin>>>>>, Where>, And>>>> - { - public ARPayment_CurrencyInfo_Currency_Customer(PXGraph graph) - : base(graph) - { - } - } - - public class ARInvoice_CurrencyInfo_Terms_Customer : PXSelectJoin>, - LeftJoin>, - LeftJoin>, - LeftJoin>>>>>, - Where>, And>>>> - { - public ARInvoice_CurrencyInfo_Terms_Customer(PXGraph graph) - : base(graph) - { - } - } - - public class ARReleaseProcess : PXGraph - { - public PXSelect ARDocument; - - public PXSelectJoin< - ARTran, - LeftJoin, - And, - And>>>, - LeftJoin>, - LeftJoin>, - LeftJoin>, - LeftJoin>>>>>>, - Where< - ARTran.tranType, Equal>, - And>>>, - OrderBy< - Asc>>> - ARTran_TranType_RefNbr; - - public PXSelectJoin< - ARTaxTran, - LeftJoin>>, - Where< - ARTaxTran.module, Equal, - And>, - And>>>>, - OrderBy< - Asc>> - ARTaxTran_TranType_RefNbr; - public PXSelect SVATConversionHistory; - - public PXSelect Batch; - - public ARInvoice_CurrencyInfo_Terms_Customer ARInvoice_DocType_RefNbr; - public ARPayment_CurrencyInfo_Currency_Customer ARPayment_DocType_RefNbr; - - public PXSelectJoin< - ARAdjust, - InnerJoin>, - InnerJoin>, - // Adjusted ARInvoice records. Replaced with ARRegister - // for performance reasons (to avoid projection subselect). - // - - LeftJoin, - And, - And, - Or, - Or, - Or, - Or, - Or, - Or>>>>>>>>>>, - LeftJoin, - And>>>>>>, - Where< - ARAdjust.adjgDocType, Equal>, - And>, - And>>>>> - ARAdjust_AdjgDocType_RefNbr_CustomerID; - - public PXSelectJoin< - ARAdjust, - InnerJoin>, - InnerJoin>, - LeftJoin, - And>>>>>, - Where< - ARAdjust.adjdDocType, Equal>, - And>, - And>>>>> - ARAdjust_AdjdDocType_RefNbr_CustomerID; - - public PXSelect>, And>>>> ARPaymentChargeTran_DocType_RefNbr; - - public PXSelect>, - And>>>> ARDoc_SalesPerTrans; - - public PXSelect CashTran; - public PXSelect intranselect; - public PXSetup glsetup; - public PXSetup SOSetup; - - public PXSelect taxes; - public PM.PMCommitmentSelect Commitments; - protected PXResultset ARAdjustsToRelease; - - private ARSetup _arsetup; - public ARSetup arsetup - { - get - { - _arsetup = (_arsetup ?? PXSelect.Select(this)); - return _arsetup; - } - } - - public bool AutoPost - { - get - { - return (bool)arsetup.AutoPost; - } - } - - public bool SummPost - { - get - { - return (arsetup.TransactionPosting == "S"); - } - } - - public string InvoiceRounding - { - get - { - return arsetup.InvoiceRounding; - } - } - - public decimal? InvoicePrecision - { - get - { - return arsetup.InvoicePrecision; - } - } - - public decimal? RoundingLimit - { - get - { - return glsetup.Current.RoundingLimit; - } - } - - protected ARInvoiceEntry _ie = null; - public ARInvoiceEntry ie - { - get - { - _ie = (_ie ?? PXGraph.CreateInstance()); - return _ie; - } - } - - protected ARPaymentEntry _pe = null; - public ARPaymentEntry pe - { - get - { - _pe = (_pe ?? PXGraph.CreateInstance()); - return _pe; - } - } - - [PXDBString(6, IsFixed = true)] - [PXDefault()] - protected virtual void ARPayment_AdjFinPeriodID_CacheAttached(PXCache sender) - { } - - [PXDBString(6, IsFixed = true)] - [PXDefault()] - protected virtual void ARPayment_AdjTranPeriodID_CacheAttached(PXCache sender) - { } - - - [PXDBString(1, IsFixed = true)] - public virtual void Tax_TaxType_CacheAttached(PXCache sender) { } - - [PXDBString(1, IsFixed = true)] - public virtual void Tax_TaxCalcLevel_CacheAttached(PXCache sender) { } - - public ARReleaseProcess() - { - //Caches[typeof(ARRegister)] = new PXCache(this); - OpenPeriodAttribute.SetValidatePeriod(ARDocument.Cache, null, PeriodValidation.Nothing); - OpenPeriodAttribute.SetValidatePeriod(ARPayment_DocType_RefNbr.Cache, null, PeriodValidation.Nothing); - - PXDBDefaultAttribute.SetDefaultForUpdate(Caches[typeof(ARAdjust)], null, false); - PXDBDefaultAttribute.SetDefaultForUpdate(Caches[typeof(ARAdjust)], null, false); - PXDBDefaultAttribute.SetDefaultForUpdate(Caches[typeof(ARAdjust)], null, false); - PXDBLiteDefaultAttribute.SetDefaultForUpdate(Caches[typeof(ARAdjust)], null, false); - PXDBDefaultAttribute.SetDefaultForUpdate(Caches[typeof(ARAdjust)], null, false); - PXDBDefaultAttribute.SetDefaultForUpdate(Caches[typeof(ARAdjust)], null, false); - PXDBDefaultAttribute.SetDefaultForUpdate(Caches[typeof(ARAdjust)], null, false); - - PXDBDefaultAttribute.SetDefaultForInsert(Caches[typeof(ARTran)], null, false); - PXDBDefaultAttribute.SetDefaultForInsert(Caches[typeof(ARTran)], null, false); - PXDBDefaultAttribute.SetDefaultForUpdate(Caches[typeof(ARTran)], null, false); - PXDBDefaultAttribute.SetDefaultForUpdate(Caches[typeof(ARTran)], null, false); - PXDBLiteDefaultAttribute.SetDefaultForUpdate(Caches[typeof(ARTran)], null, false); - PXDBDefaultAttribute.SetDefaultForUpdate(Caches[typeof(ARTran)], null, false); - PXDBDefaultAttribute.SetDefaultForUpdate(Caches[typeof(ARTran)], null, false); - PXDBDefaultAttribute.SetDefaultForUpdate(Caches[typeof(ARTran)], null, false); - - PXDBDefaultAttribute.SetDefaultForUpdate(Caches[typeof(ARTaxTran)], null, false); - PXDBDefaultAttribute.SetDefaultForUpdate(Caches[typeof(ARTaxTran)], null, false); - PXDBLiteDefaultAttribute.SetDefaultForUpdate(Caches[typeof(ARTaxTran)], null, false); - PXDBDefaultAttribute.SetDefaultForUpdate(Caches[typeof(ARTaxTran)], null, false); - PXDBDefaultAttribute.SetDefaultForUpdate(Caches[typeof(ARTaxTran)], null, false); - - PXDBDefaultAttribute.SetDefaultForUpdate(intranselect.Cache, null, false); - PXDBDefaultAttribute.SetDefaultForUpdate(intranselect.Cache, null, false); - PXDBDefaultAttribute.SetDefaultForUpdate(intranselect.Cache, null, false); - PXDBDefaultAttribute.SetDefaultForUpdate(intranselect.Cache, null, false); - - PXFormulaAttribute.SetAggregate(Caches[typeof(ARAdjust)], null); - PXFormulaAttribute.SetAggregate(Caches[typeof(ARAdjust)], null); - PXFormulaAttribute.SetAggregate(Caches[typeof(ARAdjust)], null); - } - - protected virtual void ARPayment_CashAccountID_FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e) - { - e.Cancel = true; - } - - protected virtual void ARPayment_PMInstanceID_FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e) - { - e.Cancel = true; - } - - protected virtual void ARPayment_PaymentMethodID_FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e) - { - e.Cancel = true; - } - - protected virtual void ARPayment_ExtRefNbr_FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e) - { - e.Cancel = true; - } - - protected virtual void ARRegister_FinPeriodID_CommandPreparing(PXCache sender, PXCommandPreparingEventArgs e) - { - if ((e.Operation & PXDBOperation.Command) == PXDBOperation.Update) - { - e.FieldName = string.Empty; - e.Cancel = true; - } - } - - protected virtual void ARRegister_TranPeriodID_CommandPreparing(PXCache sender, PXCommandPreparingEventArgs e) - { - if ((e.Operation & PXDBOperation.Command) == PXDBOperation.Update) - { - e.FieldName = string.Empty; - e.Cancel = true; - } - } - - protected virtual void ARRegister_DocDate_CommandPreparing(PXCache sender, PXCommandPreparingEventArgs e) - { - if ((e.Operation & PXDBOperation.Command) == PXDBOperation.Update) - { - e.FieldName = string.Empty; - e.Cancel = true; - } - } - - protected virtual void ARAdjust_AdjdRefNbr_FieldVerifying(PXCache sender, PXFieldVerifyingEventArgs e) - { - e.Cancel = true; - } - - protected virtual void ARTran_RowUpdating(PXCache sender, PXRowUpdatingEventArgs e) - { - e.Cancel = _IsIntegrityCheck; - } - - protected virtual void ARTran_TaxCategoryID_FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e) - { - e.NewValue = null; - e.Cancel = true; - } - - protected virtual void ARTran_SalesPersonID_FieldDefaulting(PXCache sender, PXFieldDefaultingEventArgs e) - { - e.NewValue = null; - e.Cancel = true; - } - - private ARHist CreateHistory(int? BranchID, int? AccountID, int? SubID, int? CustomerID, string PeriodID) - { - ARHist accthist = new ARHist(); - accthist.BranchID = BranchID; - accthist.AccountID = AccountID; - accthist.SubID = SubID; - accthist.CustomerID = CustomerID; - accthist.FinPeriodID = PeriodID; - return (ARHist)Caches[typeof(ARHist)].Insert(accthist); - } - - private CuryARHist CreateHistory(int? BranchID, int? AccountID, int? SubID, int? CustomerID, string CuryID, string PeriodID) - { - CuryARHist accthist = new CuryARHist(); - accthist.BranchID = BranchID; - accthist.AccountID = AccountID; - accthist.SubID = SubID; - accthist.CustomerID = CustomerID; - accthist.CuryID = CuryID; - accthist.FinPeriodID = PeriodID; - return (CuryARHist)Caches[typeof(CuryARHist)].Insert(accthist); - } - - private class ARHistItemDiscountsBucket : ARHistBucket - { - public ARHistItemDiscountsBucket(ARTran tran) - : base() - { - switch (tran.TranType) - { - case ARDocType.Invoice: - case ARDocType.DebitMemo: - case ARDocType.CashSale: - SignPtdItemDiscounts = 1m; - break; - case ARDocType.CreditMemo: - case ARDocType.CashReturn: - SignPtdItemDiscounts = -1m; - break; - } - } - } - - private class ARHistBucket - { - public int? arAccountID = null; - public int? arSubID = null; - public decimal SignPayments = 0m; - public decimal SignDeposits = 0m; - public decimal SignSales = 0m; - public decimal SignFinCharges = 0m; - public decimal SignCrMemos = 0m; - public decimal SignDrMemos = 0m; - public decimal SignDiscTaken = 0m; - public decimal SignRGOL = 0m; - public decimal SignPtd = 0m; - public decimal SignPtdItemDiscounts = 0m; - - public ARHistBucket(GLTran tran, string TranType) - { - arAccountID = tran.AccountID; - arSubID = tran.SubID; - - switch (TranType + tran.TranClass) - { - case "CSLN": - SignSales = -1m; - SignPayments = -1m; - SignPtd = 0m; - break; - case "RCSN": - SignSales = -1m; - SignPayments = -1m; - SignPtd = 0m; - break; - case "INVN": - SignSales = 1m; - SignPtd = 1m; - break; - case "DRMN": - SignDrMemos = 1m; - SignPtd = 1m; - break; - case "FCHN": - SignFinCharges = 1m; - SignPtd = 1m; - break; - case "CRMP": - case "CRMN": - SignCrMemos = -1m; - SignPtd = 1m; - break; - case "CRMR": - arAccountID = tran.OrigAccountID; - arSubID = tran.OrigSubID; - SignCrMemos = -1m; - SignRGOL = 1m; - break; - case "CRMD": - arAccountID = tran.OrigAccountID; - arSubID = tran.OrigSubID; - SignCrMemos = -1m; - SignDiscTaken = 1m; - break; - case "CRMB": - arAccountID = tran.OrigAccountID; - arSubID = tran.OrigSubID; - SignCrMemos = 0m; - break; - case "PPMP": - SignDeposits = -1m; - break; - case "PPMU": - arAccountID = tran.OrigAccountID; - arSubID = tran.OrigSubID; - SignDeposits = -1m; - SignDrMemos = -1m; - SignPtd = -1m; - break; - case "PMTU": - arAccountID = tran.OrigAccountID; - arSubID = tran.OrigSubID; - SignPayments = -1m; - SignDrMemos = -1m; - break; - case "RPMP": - case "RPMN": - case "PMTP": - case "PMTN": - case "PPMN": - case "REFP": - case "REFN": - SignPayments = -1m; - SignPtd = 1m; - break; - case "REFU": - SignDeposits = -1m; - break; - case "RPMR": - case "PPMR": - case "PMTR": - case "REFR": - case "CSLR": - case "RCSR": - arAccountID = tran.OrigAccountID; - arSubID = tran.OrigSubID; - SignPayments = -1m; - SignRGOL = 1m; - break; - case "RPMD": - case "PPMD": - case "PMTD": - case "REFD": //not really happens - case "CSLD": - case "RCSD": - arAccountID = tran.OrigAccountID; - arSubID = tran.OrigSubID; - SignPayments = -1m; - SignDiscTaken = 1m; - break; - case "SMCP": - //Zero Update - //will insert SCWO Account in ARHistory for trial balance report - //arAccountID = tran.OrigAccountID; - //arSubID = tran.OrigSubID; - break; - case "SMCN": - SignDrMemos = 1m; - SignPtd = 1m; - break; - case "SMBP": - //Zero Update - //will insert SBWO Account in ARHistory for trial balance report - break; - case "SMBD": //not really happens - //Zero Update - arAccountID = tran.OrigAccountID; - arSubID = tran.OrigSubID; - break; - case "SMBN": - SignCrMemos = -1m; - SignPtd = 1m; - break; - case "SMBR": - arAccountID = tran.OrigAccountID; - arSubID = tran.OrigSubID; - SignCrMemos = -1m; - SignRGOL = 1m; - break; - case "RPMB": - case "PPMB": - case "REFB": //not really happens - case "CSLB": - case "RCSB": - case "PMTB": - case "SMBB": - arAccountID = tran.OrigAccountID; - arSubID = tran.OrigSubID; - SignPayments = -1m; - SignCrMemos = 1m; - break; - } - } - - public ARHistBucket() - { - } - } - - private void UpdateHist(History accthist, ARHistBucket bucket, bool FinFlag, GLTran tran) - where History : class, IBaseARHist - { - if (_IsIntegrityCheck == false || accthist.DetDeleted == false) - { - accthist.FinFlag = FinFlag; - accthist.PtdPayments += bucket.SignPayments * (tran.DebitAmt - tran.CreditAmt); - accthist.PtdSales += bucket.SignSales * (tran.DebitAmt - tran.CreditAmt); - accthist.PtdDrAdjustments += bucket.SignDrMemos * (tran.DebitAmt - tran.CreditAmt); - accthist.PtdCrAdjustments += bucket.SignCrMemos * (tran.DebitAmt - tran.CreditAmt); - accthist.PtdFinCharges += bucket.SignFinCharges * (tran.DebitAmt - tran.CreditAmt); - accthist.PtdDiscounts += bucket.SignDiscTaken * (tran.DebitAmt - tran.CreditAmt); - accthist.PtdRGOL += bucket.SignRGOL * (tran.DebitAmt - tran.CreditAmt); - accthist.YtdBalance += bucket.SignPtd * (tran.DebitAmt - tran.CreditAmt); - accthist.PtdDeposits += bucket.SignDeposits * (tran.DebitAmt - tran.CreditAmt); - accthist.YtdDeposits += bucket.SignDeposits * (tran.DebitAmt - tran.CreditAmt); - accthist.PtdItemDiscounts += bucket.SignPtdItemDiscounts * (tran.DebitAmt - tran.CreditAmt); - } - } - - private void UpdateFinHist(History accthist, ARHistBucket bucket, GLTran tran) - where History : class, IBaseARHist - { - UpdateHist(accthist, bucket, true, tran); - } - - private void UpdateTranHist(History accthist, ARHistBucket bucket, GLTran tran) - where History : class, IBaseARHist - { - UpdateHist(accthist, bucket, false, tran); - } - - private void CuryUpdateHist(History accthist, ARHistBucket bucket, bool FinFlag, GLTran tran) - where History : class, ICuryARHist, IBaseARHist - { - if (_IsIntegrityCheck == false || accthist.DetDeleted == false) - { - UpdateHist(accthist, bucket, FinFlag, tran); - - accthist.FinFlag = FinFlag; - accthist.CuryPtdPayments += bucket.SignPayments * (tran.CuryDebitAmt - tran.CuryCreditAmt); - accthist.CuryPtdSales += bucket.SignSales * (tran.CuryDebitAmt - tran.CuryCreditAmt); - accthist.CuryPtdDrAdjustments += bucket.SignDrMemos * (tran.CuryDebitAmt - tran.CuryCreditAmt); - accthist.CuryPtdCrAdjustments += bucket.SignCrMemos * (tran.CuryDebitAmt - tran.CuryCreditAmt); - accthist.CuryPtdFinCharges += bucket.SignFinCharges * (tran.CuryDebitAmt - tran.CuryCreditAmt); - accthist.CuryPtdDiscounts += bucket.SignDiscTaken * (tran.CuryDebitAmt - tran.CuryCreditAmt); - accthist.CuryYtdBalance += bucket.SignPtd * (tran.CuryDebitAmt - tran.CuryCreditAmt); - accthist.CuryPtdDeposits += bucket.SignDeposits * (tran.CuryDebitAmt - tran.CuryCreditAmt); - accthist.CuryYtdDeposits += bucket.SignDeposits * (tran.CuryDebitAmt - tran.CuryCreditAmt); - } - } - - private void CuryUpdateFinHist(History accthist, ARHistBucket bucket, GLTran tran) - where History : class, ICuryARHist, IBaseARHist - { - CuryUpdateHist(accthist, bucket, true, tran); - } - - private void CuryUpdateTranHist(History accthist, ARHistBucket bucket, GLTran tran) - where History : class, ICuryARHist, IBaseARHist - { - CuryUpdateHist(accthist, bucket, false, tran); - } - - - protected void UpdateItemDiscountsHistory(ARTran tran, ARRegister ardoc) - { - ARHistBucket bucket = new ARHistItemDiscountsBucket(tran); - { - ARHist accthist = CreateHistory(tran.BranchID, ardoc.ARAccountID, ardoc.ARSubID, ardoc.CustomerID, ardoc.FinPeriodID); - if (accthist != null) - { - UpdateFinHist(accthist, bucket, new GLTran { DebitAmt = tran.DiscAmt, CreditAmt = 0m }); - } - } - - { - ARHist accthist = CreateHistory(tran.BranchID, ardoc.ARAccountID, ardoc.ARSubID, ardoc.CustomerID, ardoc.TranPeriodID); - if (accthist != null) - { - UpdateTranHist(accthist, bucket, new GLTran { DebitAmt = tran.DiscAmt, CreditAmt = 0m }); - } - } - } - - private void UpdateHistory(GLTran tran, Customer cust) - { - string HistTranType = tran.TranType; - if (tran.TranType == ARDocType.VoidPayment) - { - ARRegister doc = PXSelect>, And, Or>>>>, OrderBy>, int0>, int1>, Asc>>>>.Select(this, tran.RefNbr); - if (doc != null) - { - HistTranType = doc.DocType; - } - } - - ARHistBucket bucket = new ARHistBucket(tran, HistTranType); - UpdateHistory(tran, cust, bucket); - } - - private void UpdateHistory(GLTran tran, Customer cust, ARHistBucket bucket) - { - { - ARHist accthist = CreateHistory(tran.BranchID, bucket.arAccountID, bucket.arSubID, cust.BAccountID, tran.FinPeriodID); - if (accthist != null) - { - UpdateFinHist(accthist, bucket, tran); - } - } - - { - ARHist accthist = CreateHistory(tran.BranchID, bucket.arAccountID, bucket.arSubID, cust.BAccountID, tran.TranPeriodID); - if (accthist != null) - { - UpdateTranHist(accthist, bucket, tran); - } - } - } - - private void UpdateHistory(GLTran tran, Customer cust, CurrencyInfo info) - { - string HistTranType = tran.TranType; - if (tran.TranType == ARDocType.VoidPayment) - { - ARRegister doc = PXSelect>, And, Or>>>>, OrderBy>, int0>, int1>, Asc>>>>.Select(this, tran.RefNbr); - if (doc != null) - { - HistTranType = doc.DocType; - } - } - - ARHistBucket bucket = new ARHistBucket(tran, HistTranType); - UpdateHistory(tran, cust, info, bucket); - } - - private void UpdateHistory(GLTran tran, Customer cust, CurrencyInfo info, ARHistBucket bucket) - { - { - CuryARHist accthist = CreateHistory(tran.BranchID, bucket.arAccountID, bucket.arSubID, cust.BAccountID, info.CuryID, tran.FinPeriodID); - if (accthist != null) - { - CuryUpdateFinHist(accthist, bucket, tran); - } - } - - { - CuryARHist accthist = CreateHistory(tran.BranchID, bucket.arAccountID, bucket.arSubID, cust.BAccountID, info.CuryID, tran.TranPeriodID); - if (accthist != null) - { - CuryUpdateTranHist(accthist, bucket, tran); - } - } - } - - private List CreateInstallments(PXResult res) - { - ARInvoice ardoc = (ARInvoice)res; - CurrencyInfo info = (CurrencyInfo)res; - Terms terms = (Terms)res; - Customer customer = (Customer)res; - List ret = new List(); - - decimal CuryTotalInstallments = 0m; - - ARInvoiceEntry docgraph = PXGraph.CreateInstance(); - - PXResultset installments = TermsAttribute.SelectInstallments(this, terms, (DateTime)ardoc.DueDate); - foreach (TermsInstallments inst in installments) - { - docgraph.customer.Current = customer; - PXCache sender = ARInvoice_DocType_RefNbr.Cache; - //force precision population - object CuryOrigDocAmt = sender.GetValueExt(ardoc, "CuryOrigDocAmt"); - - CurrencyInfo new_info = PXCache.CreateCopy(info); - new_info.CuryInfoID = null; - new_info = docgraph.currencyinfo.Insert(new_info); - - ARInvoice new_ardoc = PXCache.CreateCopy(ardoc); - new_ardoc.CuryInfoID = new_info.CuryInfoID; - new_ardoc.DueDate = ((DateTime)new_ardoc.DueDate).AddDays((double)inst.InstDays); - new_ardoc.DiscDate = new_ardoc.DueDate; - new_ardoc.InstallmentNbr = inst.InstallmentNbr; - new_ardoc.MasterRefNbr = new_ardoc.RefNbr; - new_ardoc.RefNbr = null; - new_ardoc.ProjectID = ProjectDefaultAttribute.NonProject(docgraph); - TaxAttribute.SetTaxCalc(docgraph.Transactions.Cache, null, TaxCalc.NoCalc); - - if (inst.InstallmentNbr == installments.Count) - { - new_ardoc.CuryOrigDocAmt = new_ardoc.CuryOrigDocAmt - CuryTotalInstallments; - } - else - { - if (terms.InstallmentMthd == TermsInstallmentMethod.AllTaxInFirst) - { - new_ardoc.CuryOrigDocAmt = PXDBCurrencyAttribute.Round(sender, ardoc, (decimal)((ardoc.CuryOrigDocAmt - ardoc.CuryTaxTotal) * inst.InstPercent / 100m), CMPrecision.TRANCURY); - if (inst.InstallmentNbr == 1) - { - new_ardoc.CuryOrigDocAmt += (decimal)ardoc.CuryTaxTotal; - } - } - else - { - new_ardoc.CuryOrigDocAmt = PXDBCurrencyAttribute.Round(sender, ardoc, (decimal)(ardoc.CuryOrigDocAmt * inst.InstPercent / 100m), CMPrecision.TRANCURY); - } - } - new_ardoc.CuryDocBal = new_ardoc.CuryOrigDocAmt; - new_ardoc.CuryLineTotal = new_ardoc.CuryOrigDocAmt; - new_ardoc.CuryTaxTotal = 0m; - new_ardoc.CuryOrigDiscAmt = 0m; - new_ardoc.CuryVatTaxableTotal = 0m; - new_ardoc.CuryDiscTot = 0m; - new_ardoc.OrigModule = BatchModule.AR; - new_ardoc = docgraph.Document.Insert(new_ardoc); - CuryTotalInstallments += (decimal)new_ardoc.CuryOrigDocAmt; - - //Insert of ARInvoice causes the TaxZone to change thus setting the TaxCalc back to TaxCalc.Calc for the External (Avalara) - //Set it back to NoCalc to avoid Document Totals recalculation on adding new transactions: - TaxAttribute.SetTaxCalc(docgraph.Transactions.Cache, null, TaxCalc.NoCalc); - - ARTran new_artran = new ARTran(); - new_artran.AccountID = new_ardoc.ARAccountID; - new_artran.SubID = new_ardoc.ARSubID; - new_artran.CuryTranAmt = new_ardoc.CuryOrigDocAmt; - using (new PXLocaleScope(customer.LocaleName)) - { - new_artran.TranDesc = PXMessages.LocalizeNoPrefix(Messages.MultiplyInstallmentsTranDesc); - } - - docgraph.Transactions.Insert(new_artran); - - foreach (ARSalesPerTran sptran in docgraph.salesPerTrans.Select()) - { - docgraph.salesPerTrans.Delete(sptran); - } - - foreach (ARSalesPerTran sptran in PXSelect>, And>>>>.Select(this, ardoc.DocType, ardoc.RefNbr)) - { - ARSalesPerTran new_sptran = PXCache.CreateCopy(sptran); - new_sptran.RefNbr = null; - new_sptran.CuryInfoID = new_info.CuryInfoID; - - new_sptran.RefCntr = 999; - new_sptran.CuryCommnblAmt = PXDBCurrencyAttribute.Round(sender, ardoc, (decimal)(sptran.CuryCommnblAmt * inst.InstPercent / 100m), CMPrecision.TRANCURY); - new_sptran.CuryCommnAmt = PXDBCurrencyAttribute.Round(sender, ardoc, (decimal)(sptran.CuryCommnAmt * inst.InstPercent / 100m), CMPrecision.TRANCURY); - new_sptran = docgraph.salesPerTrans.Insert(new_sptran); - } - - docgraph.Save.Press(); - - ret.Add((ARRegister)docgraph.Document.Current); - - docgraph.Clear(); - } - - if (installments.Count > 0) - { - docgraph.Document.WhereNew>>>(); - docgraph.Document.Search(ardoc.RefNbr, ardoc.DocType); - docgraph.Document.Current.InstallmentCntr = Convert.ToInt16(installments.Count); - docgraph.Document.Cache.SetStatus(docgraph.Document.Current, PXEntryStatus.Updated); - - docgraph.Save.Press(); - docgraph.Clear(); - } - - return ret; - } - - private void SetClosedPeriodsFromLatestApplication(ARRegister doc, int? adjNbr) - { - // We should collect applications both from original and voiding documents - // because in some cases their applications may have different periods - // - IEnumerable docTypes = doc.PossibleOriginalDocumentTypes().Append(doc.DocType).Distinct(); - - foreach (string docType in docTypes) - { - foreach (ARAdjust adj in PXSelect>, - And>, - Or>, - And>>>>>, - And, - Or>>>>>> - .Select(this, docType, doc.RefNbr, docType, doc.RefNbr, adjNbr)) - { - doc.ClosedFinPeriodID = PeriodIDAttribute.Max(doc.ClosedFinPeriodID, adj.AdjgFinPeriodID); - doc.ClosedTranPeriodID = PeriodIDAttribute.Max(doc.ClosedTranPeriodID, adj.AdjgTranPeriodID); - } - } - - doc.ClosedFinPeriodID = PeriodIDAttribute.Max(doc.ClosedFinPeriodID, doc.FinPeriodID); - doc.ClosedTranPeriodID = PeriodIDAttribute.Max(doc.ClosedTranPeriodID, doc.TranPeriodID); - } - - private void SetAdjgPeriodsFromLatestApplication(ARRegister doc, ARAdjust adj) - { - if (adj.VoidAppl == true) - { - // We should collect original applications to find max periods and dates, - // because in some cases their values can be greater than values from voiding application - // - foreach (string adjgDocType in doc.PossibleOriginalDocumentTypes()) - { - ARAdjust orig = PXSelect>, - And>, - And>, - And>, - And>, - And>>>>>>> - .SelectSingleBound(this, null, adj.AdjdDocType, adj.AdjdRefNbr, adjgDocType, adj.AdjgRefNbr, adj.VoidAdjNbr); - if (orig != null) - { - adj.AdjgFinPeriodID = PeriodIDAttribute.Max(orig.AdjgFinPeriodID, adj.AdjgFinPeriodID); - adj.AdjgTranPeriodID = PeriodIDAttribute.Max(orig.AdjgTranPeriodID, adj.AdjgTranPeriodID); - adj.AdjgDocDate = PeriodIDAttribute.Max((DateTime)orig.AdjgDocDate, (DateTime)adj.AdjgDocDate); - - break; - } - } - } - - adj.AdjgFinPeriodID = PeriodIDAttribute.Max(adj.AdjdFinPeriodID, adj.AdjgFinPeriodID); - adj.AdjgTranPeriodID = PeriodIDAttribute.Max(adj.AdjdTranPeriodID, adj.AdjgTranPeriodID); - adj.AdjgDocDate = PeriodIDAttribute.Max((DateTime)adj.AdjdDocDate, (DateTime)adj.AdjgDocDate); - } - - private void CreatePayment(PXResult res, ref List ret) - { - ret = ret ?? new List(); - - Lazy lazyPaymentEntry = new Lazy(() => - { - ARPaymentEntry result = CreateInstance(); - - result.AutoPaymentApp = true; - result.arsetup.Current.HoldEntry = false; - result.arsetup.Current.RequireControlTotal = false; - - return result; - }); - - ARInvoice invoice = PXCache.CreateCopy(res); - - PXResultset invoicesNotCSL = PXSelectJoin>, - InnerJoin>, - LeftJoin, - And>>>>>, - Where>, - And>, - And, - And>>>>.Select(this, invoice.DocType, invoice.RefNbr); - - if (invoicesNotCSL.Count() > 0) - { - foreach (SOInvoice soinvoice in invoicesNotCSL) - { - PXSelectBase cmd = new PXSelectJoin, - And>>>, - Where>, - And>, - Or>, - And>, - And>>>>>>, - OrderBy>>(this); - - CCPaymentEntry.UpdateCapturedState(soinvoice, cmd.Select(soinvoice.DocType, soinvoice.RefNbr, soinvoice.DocType, soinvoice.RefNbr)); - - if (soinvoice.IsCCCaptured == true) - { - ARPaymentEntry docgraph = lazyPaymentEntry.Value; - - if (((Terms)res).InstallmentType != TermsInstallmentType.Single) - { - throw new PXException(Messages.PrepaymentAppliedToMultiplyInstallments); - } - - ARPayment payment = new ARPayment() - { - DocType = ARDocType.Payment, - AdjDate = soinvoice.AdjDate, - AdjFinPeriodID = soinvoice.AdjFinPeriodID - }; - - payment = PXCache.CreateCopy(docgraph.Document.Insert(payment)); - payment.CustomerID = invoice.CustomerID; - payment.CustomerLocationID = invoice.CustomerLocationID; - payment.ARAccountID = invoice.ARAccountID; - payment.ARSubID = invoice.ARSubID; - - payment.PaymentMethodID = soinvoice.PaymentMethodID; - payment.PMInstanceID = soinvoice.PMInstanceID; - payment.CashAccountID = soinvoice.CashAccountID; - payment.ExtRefNbr = soinvoice.ExtRefNbr; - payment.CuryOrigDocAmt = soinvoice.CuryCCCapturedAmt; - - docgraph.Document.Update(payment); - - invoice.Released = true; - invoice.OpenDoc = true; - invoice.CuryDocBal = invoice.CuryOrigDocAmt; - invoice.DocBal = invoice.OrigDocAmt; - invoice.CuryDiscBal = invoice.CuryOrigDiscAmt; - invoice.DiscBal = invoice.OrigDiscAmt; - - docgraph.Caches[typeof(ARInvoice)].SetStatus(invoice, PXEntryStatus.Held); - - - decimal? _CuryAdjgAmt = payment.CuryOrigDocAmt > invoice.CuryDocBal ? invoice.CuryDocBal : payment.CuryOrigDocAmt; - decimal? _CuryAdjgDiscAmt = payment.CuryOrigDocAmt > invoice.CuryDocBal ? 0m : invoice.CuryDiscBal; - - if (_CuryAdjgDiscAmt + _CuryAdjgAmt > invoice.CuryDocBal) - { - _CuryAdjgDiscAmt = invoice.CuryDocBal - _CuryAdjgAmt; - } - - ARAdjust adj = new ARAdjust() - { - AdjdDocType = soinvoice.DocType, - AdjdRefNbr = soinvoice.RefNbr, - CuryAdjgAmt = _CuryAdjgAmt, - CuryAdjgDiscAmt = _CuryAdjgDiscAmt - }; - - docgraph.Adjustments.Insert(adj); - - using (PXTransactionScope ts = new PXTransactionScope()) - { - docgraph.Save.Press(); - - PXDatabase.Update( - new PXDataFieldAssign("DocType", docgraph.Document.Current.DocType), - new PXDataFieldAssign("RefNbr", docgraph.Document.Current.RefNbr), - new PXDataFieldRestrict("DocType", PXDbType.Char, 3, soinvoice.DocType, PXComp.EQ), - new PXDataFieldRestrict("RefNbr", PXDbType.NVarChar, 15, soinvoice.RefNbr, PXComp.EQ) - ); - - int i = 0; - bool ccproctranupdated = false; - - foreach (SOOrderShipment order in PXSelect>, - And>>>>.Select(docgraph, soinvoice.DocType, soinvoice.RefNbr)) - { - ccproctranupdated |= PXDatabase.Update( - new PXDataFieldAssign("DocType", docgraph.Document.Current.DocType), - new PXDataFieldAssign("RefNbr", docgraph.Document.Current.RefNbr), - new PXDataFieldRestrict("OrigDocType", PXDbType.Char, 3, order.OrderType, PXComp.EQ), - new PXDataFieldRestrict("OrigRefNbr", PXDbType.NVarChar, 15, order.OrderNbr, PXComp.EQ), - new PXDataFieldRestrict("RefNbr", PXDbType.NVarChar, 15, null, PXComp.ISNULL) - ); - - if (ccproctranupdated && i > 0) - { - throw new PXException(Messages.ERR_CCMultiplyPreauthCombined); - } - - i++; - } - - ts.Complete(); - } - - ret.Add(docgraph.Document.Current); - - docgraph.Clear(); - } - } - } - else - { - PXResultset invoicesCSL = PXSelectJoin>, - InnerJoin>, - LeftJoin, - And>>>>>, - Where>, - And>, - And, - And>>>>.Select(this, invoice.DocType, invoice.RefNbr); - - foreach (PXResult csls in invoicesCSL) - { - SOInvoice currInvoice = csls; - ARPayment currPayment = csls; - - using (PXTransactionScope ts = new PXTransactionScope()) - { - PXDatabase.Update( - new PXDataFieldAssign("DocType", currPayment.DocType), - new PXDataFieldAssign("RefNbr", currPayment.RefNbr), - new PXDataFieldRestrict("DocType", PXDbType.Char, 3, currInvoice.DocType, PXComp.EQ), - new PXDataFieldRestrict("RefNbr", PXDbType.NVarChar, 15, currInvoice.RefNbr, PXComp.EQ) - ); - - int i = 0; - bool ccproctranupdated = false; - - foreach (SOOrderShipment order in PXSelect>, - And>>>>.Select(this, currInvoice.DocType, currInvoice.RefNbr)) - { - ccproctranupdated |= PXDatabase.Update( - new PXDataFieldAssign("DocType", currPayment.DocType), - new PXDataFieldAssign("RefNbr", currPayment.RefNbr), - new PXDataFieldRestrict("OrigDocType", PXDbType.Char, 3, order.OrderType, PXComp.EQ), - new PXDataFieldRestrict("OrigRefNbr", PXDbType.NVarChar, 15, order.OrderNbr, PXComp.EQ), - new PXDataFieldRestrict("RefNbr", PXDbType.NVarChar, 15, null, PXComp.ISNULL) - ); - - if (ccproctranupdated && i > 0) - { - throw new PXException(Messages.ERR_CCMultiplyPreauthCombined); - } - - i++; - } - - ts.Complete(); - } - } - } - } - - private void UpdateARBalancesDates(ARRegister ardoc) - { - ARBalances arbal = (ARBalances)Caches[typeof(ARBalances)].Insert(new ARBalances - { - BranchID = ardoc.BranchID, - CustomerID = ardoc.CustomerID, - CustomerLocationID = ardoc.CustomerLocationID - }); - - if (ardoc.DueDate != null && (arbal.OldInvoiceDate == null || ardoc.DueDate <= arbal.OldInvoiceDate)) - { - if (ardoc.OpenDoc == true && ardoc.OrigDocAmt > 0) - { - arbal.OldInvoiceDate = ardoc.DueDate; - } - } - } - - private void UpdateARBalancesDates(ARRegister invoice, int rowCount) - { - ARBalances arbal = (ARBalances)Caches[typeof(ARBalances)].Insert(new ARBalances - { - BranchID = invoice.BranchID, - CustomerID = invoice.CustomerID, - CustomerLocationID = invoice.CustomerLocationID - }); - - if (invoice.DueDate != null && (arbal.OldInvoiceDate == null || invoice.DueDate <= arbal.OldInvoiceDate)) - { - if (invoice.OpenDoc == true) - { - if (invoice.OrigDocAmt > 0) - { - arbal.OldInvoiceDate = invoice.DueDate; - } - } - else - { - if (arbal.DatesUpdated != true) - { - arbal.tstamp = PXDatabase.SelectTimeStamp(); - arbal.DatesUpdated = true; - } - arbal.OldInvoiceDate = null; - - foreach (ARInvoice olddoc in PXSelectReadonly>, - And>, - And>, - And, - And, - And>>>>>>>, - OrderBy>> - .SelectWindowed(this, 0, rowCount + 1, invoice.CustomerID, invoice.CustomerLocationID, invoice.BranchID)) - { - ARRegister cached = (ARRegister)ARDocument.Cache.Locate(olddoc); - if (cached == null || (bool)cached.OpenDoc) - { - arbal.OldInvoiceDate = olddoc.DueDate; - break; - } - } - } - } - } - - public static decimal? RoundAmount(decimal? amount, string RoundType, decimal? precision) - { - decimal? toround = amount / precision; - - switch (RoundType) - { - case RoundingType.Floor: - return Math.Floor((decimal)toround) * precision; - case RoundingType.Ceil: - return Math.Ceiling((decimal)toround) * precision; - case RoundingType.Mathematical: - return Math.Round((decimal)toround, 0, MidpointRounding.AwayFromZero) * precision; - default: - return amount; - } - } - - protected virtual decimal? RoundAmount(decimal? amount) - { - return RoundAmount(amount, this.InvoiceRounding, this.InvoicePrecision); - } - - public virtual List ReleaseDocProc(JournalEntry je, ref ARRegister doc, PXResult res, out PM.PMRegister pmDoc) - { - pmDoc = null; - ARInvoice ardoc = (ARInvoice)res; - CurrencyInfo info = (CurrencyInfo)res; - Terms terms = (Terms)res; - Customer vend = (Customer)res; - Account arAccount = (Account)res; - - List ret = null; - - if ((bool)doc.Released == false) - { - if (_IsIntegrityCheck == false) - { - if ((bool)arsetup.PrintBeforeRelease && ardoc.Printed != true && ardoc.DontPrint != true) - throw new PXException(Messages.Invoice_NotPrinted_CannotRelease); - if ((bool)arsetup.EmailBeforeRelease && ardoc.Emailed != true && ardoc.DontEmail != true) - throw new PXException(Messages.Invoice_NotEmailed_CannotRelease); - } - - if (ardoc.CreditHold == true) - { - throw new PXException( - Messages.InvoiceCreditHoldCannotRelease, - GetLabel.For(ardoc.DocType), - ardoc.RefNbr); - } - - string _InstallmentType = terms.InstallmentType; - - if (_IsIntegrityCheck && ardoc.InstallmentNbr == null) - { - _InstallmentType = ardoc.InstallmentCntr != null - ? _InstallmentType = TermsInstallmentType.Multiple - : _InstallmentType = TermsInstallmentType.Single; - } - - if (_InstallmentType == TermsInstallmentType.Multiple && (ardoc.DocType == ARDocType.CashSale || ardoc.DocType == ARDocType.CashReturn)) - { - throw new PXException(Messages.Cash_Sale_Cannot_Have_Multiply_Installments); - } - - if (_InstallmentType == TermsInstallmentType.Multiple && ardoc.InstallmentNbr == null) - { - if (_IsIntegrityCheck == false) - { - ret = CreateInstallments(res); - } - doc.CuryDocBal = 0m; - doc.DocBal = 0m; - doc.CuryDiscBal = 0m; - doc.DiscBal = 0m; - doc.CuryDiscTaken = 0m; - doc.DiscTaken = 0m; - - doc.OpenDoc = false; - doc.ClosedFinPeriodID = doc.FinPeriodID; - doc.ClosedTranPeriodID = doc.TranPeriodID; - - UpdateARBalances(this, doc, -1m * doc.OrigDocAmt, 0m); - } - else - { - doc.CuryDocBal = doc.CuryOrigDocAmt; - doc.DocBal = doc.OrigDocAmt; - doc.CuryDiscBal = doc.CuryOrigDiscAmt; - doc.DiscBal = doc.OrigDiscAmt; - doc.CuryDiscTaken = 0m; - doc.DiscTaken = 0m; - doc.RGOLAmt = 0m; - - doc.OpenDoc = true; - doc.ClosedFinPeriodID = null; - doc.ClosedTranPeriodID = null; - - UpdateARBalancesDates(ardoc); - } - - //should always restore ARRegister to ARInvoice after above assignments - PXCache.RestoreCopy(ardoc, doc); - - CurrencyInfo new_info = PXCache.CreateCopy(info); - new_info.CuryInfoID = null; - new_info.ModuleCode = "GL"; - new_info.BaseCalc = false; - new_info = je.currencyinfo.Insert(new_info) ?? new_info; - - if (ardoc.DocType == ARDocType.CashSale || ardoc.DocType == ARDocType.CashReturn) - { - GLTran tran = new GLTran(); - tran.SummPost = true; - tran.ZeroPost = false; - tran.BranchID = ardoc.BranchID; - tran.AccountID = ardoc.ARAccountID; - tran.ReclassificationProhibited = true; - tran.SubID = ardoc.ARSubID; - tran.CuryDebitAmt = (ardoc.DrCr == DrCr.Debit) ? 0m : ardoc.CuryOrigDocAmt + ardoc.CuryOrigDiscAmt; - tran.DebitAmt = (ardoc.DrCr == DrCr.Debit) ? 0m : ardoc.OrigDocAmt + ardoc.OrigDiscAmt; - tran.CuryCreditAmt = (ardoc.DrCr == DrCr.Debit) ? ardoc.CuryOrigDocAmt + ardoc.CuryOrigDiscAmt : 0m; - tran.CreditAmt = (ardoc.DrCr == DrCr.Debit) ? ardoc.OrigDocAmt + ardoc.OrigDiscAmt : 0m; - tran.TranType = ardoc.DocType; - tran.TranClass = GLTran.tranClass.Normal; - tran.RefNbr = ardoc.RefNbr; - tran.TranDesc = ardoc.DocDesc; - tran.TranPeriodID = ardoc.TranPeriodID; - tran.FinPeriodID = ardoc.FinPeriodID; - tran.TranDate = ardoc.DocDate; - tran.CuryInfoID = new_info.CuryInfoID; - tran.Released = true; - tran.ReferenceID = ardoc.CustomerID; - - if (arAccount != null && arAccount.AccountGroupID != null && ardoc.ProjectID != null && !ProjectDefaultAttribute.IsNonProject(this, ardoc.ProjectID)) - { - PMAccountTask mapping = PXSelect>, - And>>>>.Select(this, ardoc.ProjectID, ardoc.ARAccountID); - - if (mapping == null) - { - throw new PXException(Messages.AccounTaskMappingNotFound); - } - - tran.ProjectID = ardoc.ProjectID; - tran.TaskID = mapping.TaskID; - } - else - { - tran.ProjectID = ProjectDefaultAttribute.NonProject(this); - tran.TaskID = null; - } - - //no history update should take place - je.GLTranModuleBatNbr.Insert(tran); - } - else - { - GLTran tran = new GLTran(); - tran.SummPost = true; - tran.BranchID = ardoc.BranchID; - tran.AccountID = ardoc.ARAccountID; - tran.ReclassificationProhibited = true; - tran.SubID = ardoc.ARSubID; - tran.CuryDebitAmt = (ardoc.DrCr == DrCr.Debit) ? 0m : ardoc.CuryOrigDocAmt; - tran.DebitAmt = (ardoc.DrCr == DrCr.Debit) ? 0m : ardoc.OrigDocAmt - ardoc.RGOLAmt; - tran.CuryCreditAmt = (ardoc.DrCr == DrCr.Debit) ? ardoc.CuryOrigDocAmt : 0m; - tran.CreditAmt = (ardoc.DrCr == DrCr.Debit) ? ardoc.OrigDocAmt - ardoc.RGOLAmt : 0m; - tran.TranType = ardoc.DocType; - tran.TranClass = GLTran.tranClass.Normal; - tran.RefNbr = ardoc.RefNbr; - tran.TranDesc = ardoc.DocDesc; - tran.TranPeriodID = ardoc.TranPeriodID; - tran.FinPeriodID = ardoc.FinPeriodID; - tran.TranDate = ardoc.DocDate; - tran.CuryInfoID = new_info.CuryInfoID; - tran.Released = true; - tran.ReferenceID = ardoc.CustomerID; - - if (arAccount != null && arAccount.AccountGroupID != null && ardoc.ProjectID != null && !ProjectDefaultAttribute.IsNonProject(this, ardoc.ProjectID)) - { - PMAccountTask mapping = PXSelect>, - And>>>>.Select(this, ardoc.ProjectID, ardoc.ARAccountID); - - if (mapping == null) - { - throw new PXException(Messages.ARAccountTaskMappingNotFound, arAccount.AccountCD); - } - - tran.ProjectID = ardoc.ProjectID; - tran.TaskID = mapping.TaskID; - } - else - { - tran.ProjectID = ProjectDefaultAttribute.NonProject(this); - tran.TaskID = null; - } - - //if (ardoc.InstallmentNbr == null || ardoc.InstallmentNbr == 0) - if ((bool)doc.OpenDoc) - { - UpdateHistory(tran, vend); - UpdateHistory(tran, vend, info); - } - - je.GLTranModuleBatNbr.Insert(tran); - } - ARTran prev_n = new ARTran(); - - foreach (PXResult r in ARTran_TranType_RefNbr.Select((object)ardoc.DocType, ardoc.RefNbr)) - { - ARTran n = r; - SO.SOOrderType sotype = r; - - n.TranDate = ardoc.DocDate; - n.FinPeriodID = ardoc.FinPeriodID; - - if (_IsIntegrityCheck == false && sotype.PostLineDiscSeparately == true && sotype.DiscountAcctID != null && n.CuryDiscAmt > 0.00005m && !object.Equals(prev_n, n)) - { - ARTran new_tran = PXCache.CreateCopy(n); - new_tran.InventoryID = null; - new_tran.TaxCategoryID = null; - new_tran.SalesPersonID = null; - new_tran.UOM = null; - new_tran.LineType = SO.SOLineType.Discount; - using (new PXLocaleScope(vend.LocaleName)) - new_tran.TranDesc = PXMessages.LocalizeNoPrefix(SO.Messages.LineDiscDescr); - new_tran.LineNbr = (int?)PXLineNbrAttribute.NewLineNbr(ARTran_TranType_RefNbr.Cache, doc); - new_tran.CuryTranAmt = PXDBCurrencyAttribute.RoundCury(ARTran_TranType_RefNbr.Cache, new_tran, (decimal)new_tran.CuryDiscAmt * (decimal)(n.CuryTranAmt != 0m && n.CuryTaxableAmt.GetValueOrDefault() != 0 ? n.CuryTaxableAmt / n.CuryTranAmt : 1m)); - new_tran.CuryExtPrice = PXDBCurrencyAttribute.RoundCury(ARTran_TranType_RefNbr.Cache, new_tran, (decimal)new_tran.CuryDiscAmt * (decimal)(n.CuryTranAmt != 0m && n.CuryTaxableAmt.GetValueOrDefault() != 0 ? n.CuryTaxableAmt / n.CuryTranAmt : 1m)); - PXDBCurrencyAttribute.CalcBaseValues(ARTran_TranType_RefNbr.Cache, new_tran); - PXDBCurrencyAttribute.CalcBaseValues(ARTran_TranType_RefNbr.Cache, new_tran); - new_tran.CuryDiscAmt = 0m; - new_tran.Qty = 0m; - new_tran.DiscPct = 0m; - new_tran.CuryUnitPrice = 0m; - new_tran.DiscountID = null; - new_tran.DiscountSequenceID = null; - new_tran.DetDiscIDC1 = null; - new_tran.DetDiscIDC2 = null; - new_tran.DetDiscSeqIDC1 = null; - new_tran.DetDiscSeqIDC2 = null; - new_tran.DocDiscIDC1 = null; - new_tran.DocDiscIDC2 = null; - new_tran.DocDiscSeqIDC1 = null; - new_tran.DocDiscSeqIDC2 = null; - - ARTran_TranType_RefNbr.Cache.Insert(new_tran); - - new_tran = PXCache.CreateCopy(n); - new_tran.InventoryID = null; - new_tran.TaxCategoryID = null; - new_tran.SalesPersonID = null; - new_tran.UOM = null; - new_tran.LineType = SO.SOLineType.Discount; - using (new PXLocaleScope(vend.LocaleName)) - new_tran.TranDesc = PXMessages.LocalizeNoPrefix(SO.Messages.LineDiscDescr); - - switch (sotype.DiscAcctDefault) - { - case SO.SODiscAcctSubDefault.OrderType: - new_tran.AccountID = sotype.DiscountAcctID; - break; - case SO.SODiscAcctSubDefault.MaskLocation: - { - Location customerloc = PXSelect>, - And>>>> - .Select(this, ardoc.CustomerID, ardoc.CustomerLocationID); - if (customerloc != null) - { - if (customerloc.CDiscountAcctID != null) - new_tran.AccountID = customerloc.CDiscountAcctID; - else - { - if (PXAccess.FeatureInstalled()) - throw new PXException(IN.Messages.DiscountAccountIsNotSetupLocation, customerloc.LocationCD, Caches[typeof(ARInvoice)].GetValueExt(ardoc).ToString()); - else - throw new PXException(IN.Messages.DiscountAccountIsNotSetupCustomer, Caches[typeof(ARInvoice)].GetValueExt(ardoc).ToString()); - } - } - } - break; - } - - new_tran.LineNbr = (int?)PXLineNbrAttribute.NewLineNbr(ARTran_TranType_RefNbr.Cache, doc); - new_tran.CuryTranAmt = -PXDBCurrencyAttribute.RoundCury(ARTran_TranType_RefNbr.Cache, new_tran, (decimal)new_tran.CuryDiscAmt * (decimal)(n.CuryTranAmt != 0m && n.CuryTaxableAmt.GetValueOrDefault() != 0 ? n.CuryTaxableAmt / n.CuryTranAmt : 1m)); - new_tran.CuryExtPrice = -PXDBCurrencyAttribute.RoundCury(ARTran_TranType_RefNbr.Cache, new_tran, (decimal)new_tran.CuryDiscAmt * (decimal)(n.CuryTranAmt != 0m && n.CuryTaxableAmt.GetValueOrDefault() != 0 ? n.CuryTaxableAmt / n.CuryTranAmt : 1m)); - PXDBCurrencyAttribute.CalcBaseValues(ARTran_TranType_RefNbr.Cache, new_tran); - PXDBCurrencyAttribute.CalcBaseValues(ARTran_TranType_RefNbr.Cache, new_tran); - new_tran.CuryDiscAmt = 0m; - new_tran.DiscPct = 0m; - new_tran.Qty = 0m; - new_tran.CuryUnitPrice = 0m; - new_tran.DiscountID = null; - new_tran.DiscountSequenceID = null; - new_tran.DetDiscIDC1 = null; - new_tran.DetDiscIDC2 = null; - new_tran.DetDiscSeqIDC1 = null; - new_tran.DetDiscSeqIDC2 = null; - new_tran.DocDiscIDC1 = null; - new_tran.DocDiscIDC2 = null; - new_tran.DocDiscSeqIDC1 = null; - new_tran.DocDiscSeqIDC2 = null; - - if (sotype.UseDiscountSubFromSalesSub == false) - { - Location customerloc = PXSelect>, - And>>>> - .Select(this, ardoc.CustomerID, ardoc.CustomerLocationID); - CRLocation companyloc = PXSelectJoin, - And>>, - InnerJoin>>>, - Where>>> - .Select(this, ardoc.BranchID); - object ordertype_SubID = GetValue(sotype); - object customer_Location = GetValue(customerloc); - object company_Location = GetValue(companyloc); - - //if (customer_Location != null && company_Location != null) - { - object value = SO.SODiscSubAccountMaskAttribute.MakeSub(this, - sotype.DiscSubMask, - new object[] - { - ordertype_SubID, - customer_Location, - company_Location - }, - new Type[] - { - typeof(SO.SOOrderType.discountSubID), - typeof(Location.cDiscountSubID), - typeof(Location.cMPDiscountSubID) - }); - ARTran_TranType_RefNbr.Cache.RaiseFieldUpdating(new_tran, ref value); - new_tran.SubID = (int?)value; - } - } - - ARTran_TranType_RefNbr.Cache.Insert(new_tran); - } - prev_n = n; - } - - List> creditMemoPMReversal = new List>(); - List> nonglBillLater = new List>(); - List> nonglReverse = new List>(); - prev_n = new ARTran(); - - foreach (PXResult r in ARTran_TranType_RefNbr.Select((object)ardoc.DocType, ardoc.RefNbr)) - { - ARTran n = r; - ARTax x = r; - Tax salestax = r; - DRDeferredCode defcode = r; - PMTran pmtran = r; - - if (!object.Equals(prev_n, n) && _IsIntegrityCheck == false && n.Released == true) - { - throw new PXException(Messages.Document_Status_Invalid); - } - - if (!object.Equals(prev_n, n)) - { - GLTran tran = new GLTran(); - tran.SummPost = this.SummPost && string.IsNullOrEmpty(n.PMDeltaOption); - tran.BranchID = n.BranchID; - tran.CuryInfoID = new_info.CuryInfoID; - tran.TranType = n.TranType; - tran.TranClass = ardoc.DocClass; - tran.RefNbr = n.RefNbr; - tran.InventoryID = n.InventoryID; - tran.UOM = n.UOM; - tran.Qty = (n.DrCr == DrCr.Credit) ? n.Qty : -1 * n.Qty; - tran.TranDate = n.TranDate; - tran.ProjectID = n.ProjectID; - tran.TaskID = n.TaskID; - tran.AccountID = n.AccountID; - tran.SubID = GetValueInt(je, n); - tran.TranDesc = n.TranDesc; - tran.Released = true; - tran.ReferenceID = ardoc.CustomerID; - tran.TranLineNbr = (tran.SummPost == true) ? null : n.LineNbr; - - Amount postedAmount = GetSalesPostingAmount(this, doc, n, x, salestax, amount => PXDBCurrencyAttribute.Round(je.GLTranModuleBatNbr.Cache, tran, amount, CMPrecision.TRANCURY)); - - tran.CuryDebitAmt = (n.DrCr == DrCr.Debit) ? postedAmount.Cury : 0m; - tran.DebitAmt = (n.DrCr == DrCr.Debit) ? postedAmount.Base : 0m; - tran.CuryCreditAmt = (n.DrCr == DrCr.Debit) ? 0m : postedAmount.Cury; - tran.CreditAmt = (n.DrCr == DrCr.Debit) ? 0m : postedAmount.Base; - - if (_IsIntegrityCheck == false) - { - bool transactionsAdded = false; - - if (defcode != null && defcode.DeferredCodeID != null) - { - DRProcess dr = PXGraph.CreateInstance(); - - dr.CreateSchedule(n, defcode, ardoc, postedAmount.Base.Value, isDraft: false); - dr.Actions.PressSave(); - - var transactions = je.CreateTransBySchedule(dr, tran); - je.CorrectCuryAmountsDueToRounding(transactions, tran, postedAmount.Cury.Value); - - foreach (var generated in transactions) - { - je.GLTranModuleBatNbr.Insert(generated); - } - - transactionsAdded = transactions.Any(); - } - - if (transactionsAdded == false) - { - je.GLTranModuleBatNbr.Insert(tran); - } - } - - UpdateItemDiscountsHistory(n, ardoc); - - if (!_IsIntegrityCheck) - { - bool tranCostSet = false; - if (n.LineType == SO.SOLineType.Inventory || n.LineType == SO.SOLineType.NonInventory) - { - n.TranCost = 0m; - - foreach (INTran intran in PXSelect>, And>, - And>, And>, And>>>>>>>.SelectMultiBound(this, new object[] { n })) - { - intran.ARDocType = n.TranType; - intran.ARRefNbr = n.RefNbr; - intran.ARLineNbr = n.LineNbr; - intran.UnitPrice = n.UnitPrice; - intran.TranAmt = Math.Sign((decimal)n.Qty) != Math.Sign((decimal)n.BaseQty) ? -n.TranAmt : n.TranAmt; - - if (n.Qty != 0m && n.SOShipmentLineNbr == null) - { - object TranAmt = Math.Sign((decimal)n.Qty) != Math.Sign((decimal)n.BaseQty) ? -n.TranAmt : n.TranAmt / n.Qty * intran.Qty; - this.intranselect.Cache.RaiseFieldUpdating(intran, ref TranAmt); - intran.TranAmt = (decimal?)TranAmt; - } - - this.intranselect.Cache.SetStatus(intran, PXEntryStatus.Updated); - - if (intran.Released == true) - { - IN.InventoryItem initem = PXSelect>>>.SelectSingleBound(this, null, n.InventoryID); - - if (initem != null && initem.StkItem != true && initem.KitItem == true && PXAccess.FeatureInstalled() && SOSetup != null && SOSetup.Current != null) - { - switch (SOSetup.Current.SalesProfitabilityForNSKits) - { - case SalesProfitabilityNSKitMethod.NSKitStandardCostOnly: //do nothing - break; - case SalesProfitabilityNSKitMethod.NSKitStandardAndStockComponentsCost: //kit standard cost will be added later - n.TranCost += intran.TranCost; - n.TranCostOrig = n.TranCost; - n.IsTranCostFinal = true; - break; - case SalesProfitabilityNSKitMethod.StockComponentsCostOnly: - n.TranCost += intran.TranCost; - n.TranCostOrig = n.TranCost; - n.IsTranCostFinal = true; - tranCostSet = true; - break; - } - } - else - { - n.TranCost += intran.TranCost; - n.TranCostOrig = n.TranCost; - n.IsTranCostFinal = true; - tranCostSet = true; - } - } - - if (intran.UpdateShippedNotInvoiced == true) - { - PXResultset trancosts = PXSelect>, And>, And>>>>>.Select(this, intran.DocType, intran.RefNbr, intran.LineNbr); - if (trancosts.Count < 1) throw new PXException(PXMessages.LocalizeFormatNoPrefixNLA(Messages.ShippedNotInvoicedINtranNotReleased, intran.RefNbr)); - foreach (IN.INTranCost trancost in trancosts) - { - PXResult itemPostClassRes = (PXResult)PXSelectJoin>>, Where>>>.Select(this, intran.InventoryID); - IN.INSite site = PXSelect>>>.Select(this, intran.SiteID); - - if (trancost != null && trancost.COGSAcctID != null && intran != null) - { - //Credit shipped-not-invoiced account - bool isControlAccount = false; - GLTran tranFromIN = new GLTran(); - tranFromIN.SummPost = this.SummPost; - tranFromIN.BranchID = intran.BranchID; - tran.CuryInfoID = new_info.CuryInfoID; - tranFromIN.TranType = trancost.TranType; - tranFromIN.TranClass = GLTran.tranClass.Normal; - - tranFromIN.AccountID = intran.COGSAcctID ?? IN.INReleaseProcess.GetAccountDefaults(this, (IN.InventoryItem)itemPostClassRes, site, (IN.INPostClass)itemPostClassRes, intran, out isControlAccount); - tranFromIN.SubID = intran.COGSSubID ?? IN.INReleaseProcess.GetAccountDefaults(this, (IN.InventoryItem)itemPostClassRes, site, (IN.INPostClass)itemPostClassRes, intran, out isControlAccount); - - tranFromIN.CuryDebitAmt = (trancost.InvtMult == (short)1) ? trancost.TranCost : 0m; - tranFromIN.DebitAmt = (trancost.InvtMult == (short)1) ? trancost.TranCost : 0m; - tranFromIN.CuryCreditAmt = (trancost.InvtMult == (short)1) ? 0m : trancost.TranCost; - tranFromIN.CreditAmt = (trancost.InvtMult == (short)1) ? 0m : trancost.TranCost; - - tranFromIN.RefNbr = trancost.RefNbr; - tranFromIN.InventoryID = trancost.InventoryID; - tranFromIN.Qty = (trancost.InvtMult == (short)1) ? trancost.Qty : -trancost.Qty; - tranFromIN.UOM = intran.UOM; - tranFromIN.TranDesc = intran.TranDesc; - tranFromIN.TranDate = n.TranDate; - bool isNonProject = trancost.InvtMult == (short)0; - tranFromIN.ProjectID = isNonProject ? PM.ProjectDefaultAttribute.NonProject(this) : intran.ProjectID; - tranFromIN.TaskID = isNonProject ? null : intran.TaskID; - tranFromIN.Released = true; - - je.GLTranModuleBatNbr.Insert(tranFromIN); - - //Debit COGS account - tranFromIN = new GLTran(); - tranFromIN.SummPost = this.SummPost; - tranFromIN.BranchID = intran.BranchID; - tranFromIN.AccountID = IN.INReleaseProcess.GetAccountDefaults(this, (IN.InventoryItem)itemPostClassRes, site, (IN.INPostClass)itemPostClassRes); - if (((IN.INPostClass)itemPostClassRes) != null && ((IN.INPostClass)itemPostClassRes).COGSSubFromSales != true) //we cannot use intran here to retrive cogs/sales sub - tranFromIN.SubID = IN.INReleaseProcess.GetAccountDefaults(this, (IN.InventoryItem)itemPostClassRes, site, (IN.INPostClass)itemPostClassRes); - else - tranFromIN.SubID = n.SubID; - - tranFromIN.CuryDebitAmt = (trancost.InvtMult == (short)1) ? 0m : trancost.TranCost; - tranFromIN.DebitAmt = (trancost.InvtMult == (short)1) ? 0m : trancost.TranCost; - tranFromIN.CuryCreditAmt = (trancost.InvtMult == (short)1) ? trancost.TranCost : 0m; - tranFromIN.CreditAmt = (trancost.InvtMult == (short)1) ? trancost.TranCost : 0m; - - tranFromIN.TranType = trancost.TranType; - tranFromIN.TranClass = GLTran.tranClass.Normal; - tranFromIN.RefNbr = trancost.RefNbr; - tranFromIN.InventoryID = trancost.InventoryID; - tranFromIN.Qty = (trancost.InvtMult == (short)1) ? -trancost.Qty : trancost.Qty; - tranFromIN.UOM = intran.UOM; - tranFromIN.TranDesc = intran.TranDesc; - tranFromIN.TranDate = n.TranDate; - tranFromIN.ProjectID = (trancost.InvtMult == (short)1) ? PM.ProjectDefaultAttribute.NonProject(this) : intran.ProjectID; - tranFromIN.TaskID = (trancost.InvtMult == (short)1) ? null : intran.TaskID; - tranFromIN.Released = true; - tranFromIN.TranLineNbr = (tranFromIN.SummPost == true) ? null : intran.LineNbr; - - je.GLTranModuleBatNbr.Insert(tranFromIN); - } - } - } - } - if (n.SOShipmentType == SO.SOShipmentType.DropShip) - { - foreach (INTran intran in PXSelect>, And>, - And, And, And>>>>>>.SelectMultiBound(this, new object[] { n })) - { - n.TranCost += intran.TranCost; - } - } - } - if (n.InventoryID != null && (n.LineType == null || ((n.LineType == SO.SOLineType.Inventory || n.LineType == SO.SOLineType.NonInventory) && !tranCostSet) || n.LineType == SO.SOLineType.MiscCharge)) - { - //TO DO: review this part and add more accurate cost selection conditions (INItemSite?) - PXResult result = (PXResult)PXSelectJoin, - And>>>>, - Where>>>.SelectSingleBound(this, null, n.SiteID, n.InventoryID); - if (result != null) - { - IN.InventoryItem item = (IN.InventoryItem)result; - IN.INItemSite itemSite = (IN.INItemSite)result; - if (item.StkItem == true) - { - if (itemSite.ValMethod != null) - { - if (item.ValMethod == IN.INValMethod.Standard) - { - n.TranCostOrig = n.Qty * itemSite.StdCost; - } - else - { - n.TranCostOrig = n.Qty * itemSite.AvgCost; - } - } - } - else if (n.SOShipmentType != SOShipmentType.DropShip) - { - if (item.KitItem == true && PXAccess.FeatureInstalled() && SOSetup != null && SOSetup.Current != null) - { - switch (SOSetup.Current.SalesProfitabilityForNSKits) - { - case SalesProfitabilityNSKitMethod.NSKitStandardCostOnly: - n.TranCost += n.Qty * item.StdCost; - n.TranCostOrig = n.TranCost; - n.IsTranCostFinal = true; - break; - case SalesProfitabilityNSKitMethod.NSKitStandardAndStockComponentsCost: - n.TranCost += n.Qty * item.StdCost; - n.TranCostOrig = n.TranCost; - n.IsTranCostFinal = HasStockComponents(n); - break; - case SalesProfitabilityNSKitMethod.StockComponentsCostOnly: - n.IsTranCostFinal = HasStockComponents(n); - break; - } - } - else - { - n.TranCost += n.Qty * item.StdCost; - n.TranCostOrig = n.TranCost; - n.IsTranCostFinal = true; - } - } - } - } - - if (n.CommitmentID != null) - { - decimal sign = (n.DrCr == DrCr.Credit) ? Decimal.One : Decimal.MinusOne; - - PMCommitment container = new PMCommitment(); - container.CommitmentID = n.CommitmentID; - container.UOM = n.UOM; - container.InventoryID = n.InventoryID; - container.InvoicedAmount = sign * n.TranAmt; - container.InvoicedQty = sign * n.Qty; - - PMCommitmentAttribute.AddToInvoiced(Caches[typeof(SO.SOLine)], container); - } - } - - if (pmtran.TranID != null) - { - if (pmtran.IsNonGL != true && pmtran.Reverse == PM.PMReverse.OnInvoice && pmtran.OffsetAccountID != null) - { - if (doc.DocType == ARDocType.CreditMemo && doc.OrigDocType == ARDocType.Invoice)//credit memo reversal only for Invoice created by PM billing. CreditMemo created by PM Billing should be handled same as INV. - { - creditMemoPMReversal.Add(new PXResult(n, pmtran)); - } - else if (pmtran.AccountID != pmtran.OffsetAccountID) - { - tran.PMTranID = null; - tran.OrigPMTranID = pmtran.TranID; - tran.TranLineNbr = null; - - decimal amount = pmtran.Amount.Value; - if (n.TranAmt < pmtran.Amount && n.PMDeltaOption != ARTran.pMDeltaOption.CompleteLine) - { - amount = n.TranAmt.Value; - } - - decimal curyval; - PXDBCurrencyAttribute.CuryConvCury(je.GLTranModuleBatNbr.Cache, new_info, amount, out curyval); - - tran.AccountID = pmtran.OffsetAccountID; - tran.SubID = pmtran.OffsetSubID; - tran.CuryDebitAmt = curyval; - tran.DebitAmt = amount; - tran.CuryCreditAmt = 0m; - tran.CreditAmt = 0m; - - je.GLTranModuleBatNbr.Insert(tran); - - tran.AccountID = pmtran.AccountID; - tran.SubID = pmtran.SubID; - tran.CuryDebitAmt = 0m; - tran.DebitAmt = 0m; - tran.CuryCreditAmt = curyval; - tran.CreditAmt = amount; - - je.GLTranModuleBatNbr.Insert(tran); - } - } - else if (pmtran.IsNonGL == true) - { - //NON-GL - - if (doc.DocType == ARDocType.CreditMemo && doc.OrigDocType == ARDocType.Invoice) - //credit memo reversal only for Invoice created by PM billing. CreditMemo created by PM Billing should be handled same as INV. - { - creditMemoPMReversal.Add(new PXResult(n, pmtran)); - } - else - { - if (n.TranAmt < pmtran.Amount && n.PMDeltaOption != ARTran.pMDeltaOption.CompleteLine) - { - nonglBillLater.Add(new PXResult(n, pmtran)); - } - if (pmtran.Reverse == PMReverse.OnInvoice) - { - nonglReverse.Add(new PXResult(n, pmtran)); - } - } - } - } - - n.Released = true; - ARTran_TranType_RefNbr.Cache.SmartSetStatus(n, PXEntryStatus.Updated); - } - prev_n = n; - } - - if (_IsIntegrityCheck == false) - { - if (creditMemoPMReversal.Count > 0) - { - PM.PMAllocator allocator = PXGraph.CreateInstance(); - allocator.ReverseCreditMemo(doc.RefNbr, creditMemoPMReversal); - allocator.Actions.PressSave(); - pmDoc = allocator.Document.Current; - } - else if (nonglBillLater.Count > 0 || nonglReverse.Count > 0) - { - PM.PMAllocator allocator = PXGraph.CreateInstance(); - allocator.NonGlBillLaterAndReverse(doc.RefNbr, nonglBillLater, nonglReverse); - allocator.Actions.PressSave(); - pmDoc = allocator.Document.Current; - } - } - foreach (PXResult rs in ARTaxTran_TranType_RefNbr.Select(ardoc.DocType, ardoc.RefNbr)) - { - ARTaxTran x = (ARTaxTran)rs; - Account taxAccount = (Account)rs; - GLTran tran = new GLTran(); - tran.SummPost = this.SummPost; - tran.BranchID = x.BranchID; - tran.CuryInfoID = new_info.CuryInfoID; - tran.TranType = x.TranType; - tran.TranClass = GLTran.tranClass.Tax; - tran.RefNbr = x.RefNbr; - tran.TranDate = x.TranDate; - tran.AccountID = x.AccountID; - tran.SubID = x.SubID; - tran.TranDesc = x.TaxID; - tran.CuryDebitAmt = (ardoc.DrCr == DrCr.Debit) ? x.CuryTaxAmt : 0m; - tran.DebitAmt = (ardoc.DrCr == DrCr.Debit) ? x.TaxAmt : 0m; - tran.CuryCreditAmt = (ardoc.DrCr == DrCr.Debit) ? 0m : x.CuryTaxAmt; - tran.CreditAmt = (ardoc.DrCr == DrCr.Debit) ? 0m : x.TaxAmt; - tran.Released = true; - tran.ReferenceID = ardoc.CustomerID; - - if (taxAccount != null && taxAccount.AccountGroupID != null && ardoc.ProjectID != null && !ProjectDefaultAttribute.IsNonProject(this, ardoc.ProjectID)) - { - PMAccountTask mapping = PXSelect>, - And>>>>.Select(this, ardoc.ProjectID, taxAccount.AccountID); - - if (mapping == null) - { - throw new PXException(Messages.TaxAccountTaskMappingNotFound, taxAccount.AccountCD); - } - - tran.ProjectID = ardoc.ProjectID; - tran.TaskID = mapping.TaskID; - } - - je.GLTranModuleBatNbr.Insert(tran); - - x.Released = true; - ARTaxTran_TranType_RefNbr.Cache.SetStatus(x, PXEntryStatus.Updated); - - if (PXAccess.FeatureInstalled() && _IsIntegrityCheck == false && - (x.TaxType == TX.TaxType.PendingPurchase || x.TaxType == TX.TaxType.PendingSales)) - { - AP.Vendor vendor = PXSelect>>>.SelectSingleBound(this, null, x.VendorID); - - decimal mult = ReportTaxProcess.GetMultByTranType(BatchModule.AR, x.TranType); - string reversalMethod = x.TranType == ARDocType.CashSale || x.TranType == ARDocType.CashReturn - ? SVATTaxReversalMethods.OnDocuments - : vendor?.SVATReversalMethod; - - SVATConversionHist histSVAT = new SVATConversionHist - { - Module = BatchModule.AR, - AdjdBranchID = x.BranchID, - AdjdDocType = x.TranType, - AdjdRefNbr = x.RefNbr, - AdjgDocType = x.TranType, - AdjgRefNbr = x.RefNbr, - AdjdDocDate = doc.DocDate, - AdjdFinPeriodID = doc.FinPeriodID, - - TaxID = x.TaxID, - TaxType = x.TaxType, - TaxRate = x.TaxRate, - VendorID = x.VendorID, - ReversalMethod = reversalMethod, - - CuryInfoID = x.CuryInfoID, - CuryTaxableAmt = x.CuryTaxableAmt * mult, - CuryTaxAmt = x.CuryTaxAmt * mult, - CuryUnrecognizedTaxAmt = x.CuryTaxAmt * mult - }; - - histSVAT.FillBaseAmounts(SVATConversionHistory.Cache); - SVATConversionHistory.Cache.Insert(histSVAT); - } - } - - foreach (ARSalesPerTran n in ARDoc_SalesPerTrans.Select(doc.DocType, doc.RefNbr)) - { - //multiply installments master and deferred revenue should not have commission - n.Released = doc.OpenDoc; - ARDoc_SalesPerTrans.Cache.Update(n); - - PXTimeStampScope.DuplicatePersisted(ARDoc_SalesPerTrans.Cache, n, typeof(ARSalesPerTran)); - } - - if (_IsIntegrityCheck == false) - { - foreach (PXResult appres in PXSelectJoin, And>>>, Where>, And>, And, And>>>>>.Select(this, doc.DocType, doc.RefNbr)) - { - ARAdjust adj = (ARAdjust)appres; - ARPayment payment = (ARPayment)appres; - - if (((ARAdjust)appres).CuryAdjdAmt > 0m) - { - if (_InstallmentType != TermsInstallmentType.Single) - { - throw new PXException(Messages.PrepaymentAppliedToMultiplyInstallments); - } - - if (ret == null) - { - ret = new List(); - } - - //sync fields with the max value: - if (DateTime.Compare((DateTime)payment.AdjDate, (DateTime)adj.AdjdDocDate) < 0) - { - payment.AdjDate = adj.AdjdDocDate; - payment.AdjFinPeriodID = adj.AdjdFinPeriodID; - payment.AdjTranPeriodID = adj.AdjdTranPeriodID; - } - else if (string.Compare(payment.AdjFinPeriodID, adj.AdjgFinPeriodID) > 0) - { - adj.AdjgDocDate = payment.AdjDate; - adj.AdjgFinPeriodID = payment.AdjFinPeriodID; - adj.AdjgTranPeriodID = payment.AdjTranPeriodID; - } - - if (payment.Released == true) - { - ret.Add(payment); - } - - ARPayment_DocType_RefNbr.Cache.Update(payment); - - adj.AdjAmt += adj.RGOLAmt; - adj.RGOLAmt = -adj.RGOLAmt; - adj.Hold = false; - - ARAdjust_AdjgDocType_RefNbr_CustomerID.Cache.SetStatus(adj, PXEntryStatus.Updated); - } - } - - if (doc.DocType == ARDocType.CreditMemo) - { - if (ret == null) - { - ret = new List(); - } - - doc.AdjCntr = 0; - - ret.Add(doc); - } - - CreatePayment(res, ref ret); - } - - Batch arbatch = je.BatchModule.Current; - - if (Math.Abs(Math.Round((decimal)(arbatch.CuryDebitTotal - arbatch.CuryCreditTotal), 4)) >= 0.00005m) - { - VerifyRoundingAllowed(ardoc, arbatch, je.currencyinfo.Current.BaseCuryID); - - GLTran tran = new GLTran(); - tran.SummPost = true; - tran.BranchID = ardoc.BranchID; - Currency c = PXSelect>>>.Select(this, doc.CuryID); - - if (Math.Sign((decimal)(arbatch.CuryDebitTotal - arbatch.CuryCreditTotal)) == 1) - { - tran.AccountID = c.RoundingGainAcctID; - tran.SubID = GainLossSubAccountMaskAttribute.GetSubID(je, tran.BranchID, c); - tran.CuryCreditAmt = Math.Round((decimal)(arbatch.CuryDebitTotal - arbatch.CuryCreditTotal), 4); - tran.CuryDebitAmt = 0m; - } - else - { - tran.AccountID = c.RoundingLossAcctID; - tran.SubID = GainLossSubAccountMaskAttribute.GetSubID(je, tran.BranchID, c); - tran.CuryCreditAmt = 0m; - tran.CuryDebitAmt = Math.Round((decimal)(arbatch.CuryCreditTotal - arbatch.CuryDebitTotal), 4); - } - tran.CreditAmt = 0m; - tran.DebitAmt = 0m; - tran.TranType = doc.DocType; - tran.RefNbr = doc.RefNbr; - tran.TranClass = GLTran.tranClass.Normal; - tran.TranDesc = GL.Messages.RoundingDiff; - tran.LedgerID = arbatch.LedgerID; - tran.FinPeriodID = arbatch.FinPeriodID; - tran.TranDate = arbatch.DateEntered; - tran.Released = true; - tran.ReferenceID = ardoc.CustomerID; - - CurrencyInfo infocopy = new CurrencyInfo(); - infocopy = je.currencyinfo.Insert(infocopy) ?? infocopy; - - tran.CuryInfoID = infocopy.CuryInfoID; - je.GLTranModuleBatNbr.Insert(tran); - } - - if (Math.Abs(Math.Round((decimal)(arbatch.DebitTotal - arbatch.CreditTotal), 4)) >= 0.00005m) - { - GLTran tran = new GLTran(); - tran.SummPost = true; - tran.BranchID = ardoc.BranchID; - Currency c = PXSelect>>>.Select(this, doc.CuryID); - - if (Math.Sign((decimal)(arbatch.DebitTotal - arbatch.CreditTotal)) == 1) - { - tran.AccountID = c.RoundingGainAcctID; - tran.SubID = GainLossSubAccountMaskAttribute.GetSubID(je, tran.BranchID, c); - tran.CreditAmt = Math.Round((decimal)(arbatch.DebitTotal - arbatch.CreditTotal), 4); - tran.DebitAmt = 0m; - } - else - { - tran.AccountID = c.RoundingLossAcctID; - tran.SubID = GainLossSubAccountMaskAttribute.GetSubID(je, tran.BranchID, c); - tran.CreditAmt = 0m; - tran.DebitAmt = Math.Round((decimal)(arbatch.CreditTotal - arbatch.DebitTotal), 4); - } - tran.CuryCreditAmt = 0m; - tran.CuryDebitAmt = 0m; - tran.TranType = doc.DocType; - tran.RefNbr = doc.RefNbr; - tran.TranClass = GLTran.tranClass.Normal; - tran.TranDesc = GL.Messages.RoundingDiff; - tran.LedgerID = arbatch.LedgerID; - tran.FinPeriodID = arbatch.FinPeriodID; - tran.TranDate = arbatch.DateEntered; - tran.Released = true; - tran.ReferenceID = ardoc.CustomerID; - - CurrencyInfo infocopy = new CurrencyInfo(); - infocopy = je.currencyinfo.Insert(infocopy) ?? infocopy; - - tran.CuryInfoID = infocopy.CuryInfoID; - je.GLTranModuleBatNbr.Insert(tran); - } - - if (doc.CuryDocBal == 0m) - { - doc.DocBal = 0m; - doc.CuryDiscBal = 0m; - doc.DiscBal = 0m; - - doc.OpenDoc = false; - doc.ClosedFinPeriodID = doc.FinPeriodID; - doc.ClosedTranPeriodID = doc.TranPeriodID; - } - } - - return ret; - } - - public virtual bool HasStockComponents(ARTran n) - { - return (n.IsTranCostFinal == true - || (PXSelect>, - And>, - And>>>>.SelectSingleBound(this, new object[] { n }).Count() == 0 - && PXSelect>, - And>, - And>, - And>>>>>.SelectSingleBound(this, new object[] { n }).Count() == 0)); - - } - - public class Amount : Tuple - { - public decimal? Cury { get { return Item1; } } - public decimal? Base { get { return Item2; } } - - public Amount(decimal? cury, decimal? baaase) - : base(cury, baaase) - { - } - } - - public static Amount GetSalesPostingAmount(PXGraph graph, ARTran documentLine) - { - var documentLineWithTaxes = new PXSelectJoin< - ARTran, - LeftJoin, - And, - And>>>, - LeftJoin>, - LeftJoin, - And>>>>>, - Where< - ARTran.tranType, Equal>, - And>, - And>>>>> - (graph); - - PXResult queryResult = - documentLineWithTaxes - .Select(documentLine.TranType, documentLine.RefNbr, documentLine.LineNbr) - .Cast>() - .First(); - - Func roundingFunction = amount => - PXDBCurrencyAttribute.Round( - graph.Caches[typeof(ARTran)], - documentLine, - amount, - CMPrecision.TRANCURY); - - return GetSalesPostingAmount(graph, queryResult, documentLine, queryResult, queryResult, roundingFunction); - } - - [Obsolete("The method has been renamed to " + nameof(GetSalesPostingAmount) + ".", false)] - public static Amount GetPostedTranAmount(PXGraph graph, ARRegister doc, ARTran tran, ARTax tranTax, Tax salestax, Func round) - => GetSalesPostingAmount(graph, doc, tran, tranTax, salestax, round); - - /// - /// Gets the amount to be posted to the sales acount - /// for the given document line. - /// - public static Amount GetSalesPostingAmount( - PXGraph graph, - ARRegister document, - ARTran documentLine, - ARTax lineTax, - Tax salesTax, - Func round) - { - if (lineTax?.TaxID != null && - salesTax != null && - salesTax.TaxCalcLevel == "0") - { - decimal? curyAddUp = documentLine.CuryTranAmt - - round((decimal)(documentLine.CuryTranAmt * documentLine.GroupDiscountRate * documentLine.DocumentDiscountRate)); - - decimal? addUp = documentLine.TranAmt - - round((decimal)(documentLine.TranAmt * documentLine.GroupDiscountRate * documentLine.DocumentDiscountRate)); - - return new Amount( - lineTax.CuryTaxableAmt + curyAddUp, - lineTax.TaxableAmt + addUp); - } - - bool postedPPD = document.PendingPPD == true && document.DocType == ARDocType.CreditMemo; - - if (!postedPPD && - lineTax != null && - lineTax.TaxID == null && - document.DocType == ARDocType.DebitMemo && - document.OrigDocType == ARDocType.CreditMemo && - document.OrigRefNbr != null) - { - // Same logic for the DebitMemo, reversed from the PPD CreditMemo - // - - postedPPD = PXSelect< - ARRegister, - Where< - ARRegister.refNbr, Equal>, - And>, - And>>>> - .SelectSingleBound(graph, null, document.OrigRefNbr, document.OrigDocType).Count > 0; - } - - return postedPPD ? - new Amount(documentLine.CuryTaxableAmt, documentLine.TaxableAmt) : - new Amount(documentLine.CuryTranAmt, documentLine.TranAmt); - } - - protected virtual void VerifyRoundingAllowed(ARInvoice document, Batch batch, string baseCuryID) - { - //p. "document" may be used in customization (see AC-59109) - - if (this.InvoiceRounding == RoundingType.Currency) - { - throw new PXException(Messages.DocumentOutOfBalance); - } - - decimal roundDiff = Math.Abs(Math.Round((decimal)(batch.DebitTotal - batch.CreditTotal), 4)); - if (roundDiff > this.RoundingLimit) - { - throw new PXException(AP.Messages.RoundingAmountTooBig, baseCuryID, roundDiff, - IN.PXDBQuantityAttribute.Round(this.RoundingLimit)); - } - } - - protected object GetValue(object data) - where Field : IBqlField - { - return this.Caches[typeof(Field).DeclaringType].GetValue(data, typeof(Field).Name); - } - - public int? GetValueInt(PXGraph target, object item) - where SourceField : IBqlField - { - PXCache source = this.Caches[typeof(SourceField).DeclaringType]; - PXCache dest = target.Caches[typeof(SourceField).DeclaringType]; - - object value = source.GetValueExt(item); - if (value is PXFieldState) - { - value = ((PXFieldState)value).Value; - } - - if (value != null) - { - dest.RaiseFieldUpdating(item, ref value); - } - - return (int?)value; - } - - public static void UpdateARBalances(PXGraph graph, ARRegister ardoc, decimal? BalanceAmt) - { - //voided payment is both released and voided - //voided invoice(previously scheduled) is not released and voided - if ((bool)ardoc.Released && ardoc.Voided == false && ardoc.SignBalance != 0m) - { - UpdateARBalances(graph, ardoc, ardoc.SignBalance == 1m ? BalanceAmt : -BalanceAmt, 0m); - } - else if (ardoc.Hold == false && ardoc.Scheduled == false && ardoc.Voided == false && ardoc.SignBalance != 0m) - { - UpdateARBalances(graph, ardoc, 0m, ardoc.SignBalance == 1m ? BalanceAmt : -BalanceAmt); - } - } - - public static void UpdateARBalances(PXGraph graph, ARRegister ardoc, decimal? CurrentBal, decimal? UnreleasedBal) - { - if (ardoc.CustomerID != null && ardoc.CustomerLocationID != null) - { - ARBalances arbal = new ARBalances(); - arbal.BranchID = ardoc.BranchID; - arbal.CustomerID = ardoc.CustomerID; - arbal.CustomerLocationID = ardoc.CustomerLocationID; - arbal = (ARBalances)graph.Caches[typeof(ARBalances)].Insert(arbal); - - arbal.CurrentBal += CurrentBal; - arbal.UnreleasedBal += UnreleasedBal; - } - } - - public static void UpdateARBalances(PXGraph graph, ARInvoice ardoc, decimal? BalanceAmt) - { - //voided payment is both released and voided - //voided invoice(previously scheduled) is not released and voided - if ((bool)ardoc.Released && ardoc.Voided == false && ardoc.SignBalance != 0m) - { - UpdateARBalances(graph, ardoc, ardoc.SignBalance == 1m ? BalanceAmt : -BalanceAmt, 0m); - } - else if (ardoc.Hold == false && ardoc.CreditHold == false && ardoc.Scheduled == false && ardoc.Voided == false && ardoc.SignBalance != 0m) - { - UpdateARBalances(graph, ardoc, 0m, ardoc.SignBalance == 1m ? BalanceAmt : -BalanceAmt); - } - } - - public static void UpdateARBalances(PXGraph graph, SOOrder order, decimal? UnbilledAmount, decimal? UnshippedAmount) - { - if (order.CustomerID != null && order.CustomerLocationID != null) - { - ARBalances arbal = new ARBalances(); - arbal.BranchID = order.BranchID; - arbal.CustomerID = order.CustomerID; - arbal.CustomerLocationID = order.CustomerLocationID; - arbal = (ARBalances)graph.Caches[typeof(ARBalances)].Insert(arbal); - - if (ARDocType.SignBalance(order.ARDocType) != 0m && ARDocType.SignBalance(order.ARDocType) != null) - { - decimal? BalanceAmt; - if (order.ShipmentCntr == 0) - { - BalanceAmt = UnbilledAmount; - } - else - { - BalanceAmt = UnshippedAmount; - arbal.TotalOpenOrders += ARDocType.SignBalance(order.ARDocType) == 1m ? (UnbilledAmount - UnshippedAmount) : -(UnbilledAmount - UnshippedAmount); - } - - //don't check field 'Completed' here it will cause incorrect calculation of 'Open Order Balance' - if (order.Cancelled == false && order.Hold == false && order.CreditHold == false && order.InclCustOpenOrders == true) - { - arbal.TotalOpenOrders += ARDocType.SignBalance(order.ARDocType) == 1m ? BalanceAmt : -BalanceAmt; - } - } - } - } - - private void UpdateARBalances(ARAdjust adj, ARRegister ardoc) - { - if (object.Equals(ardoc.DocType, adj.AdjdDocType) && string.Equals(ardoc.RefNbr, adj.AdjdRefNbr, StringComparison.OrdinalIgnoreCase)) - { - if (ardoc.CustomerID != null && ardoc.CustomerLocationID != null) - { - ARBalances arbal = new ARBalances(); - arbal.BranchID = ardoc.BranchID; - arbal.CustomerID = ardoc.CustomerID; - arbal.CustomerLocationID = ardoc.CustomerLocationID; - arbal = (ARBalances)this.Caches[typeof(ARBalances)].Insert(arbal); - - arbal.CurrentBal += adj.AdjdTBSign * (adj.AdjAmt + adj.AdjDiscAmt + adj.AdjWOAmt) - adj.RGOLAmt; - } - } - else if (object.Equals(ardoc.DocType, adj.AdjgDocType) && string.Equals(ardoc.RefNbr, adj.AdjgRefNbr, StringComparison.OrdinalIgnoreCase)) - { - if (ardoc.CustomerID != null && ardoc.CustomerLocationID != null) - { - ARBalances arbal = new ARBalances(); - arbal.BranchID = ardoc.BranchID; - arbal.CustomerID = ardoc.CustomerID; - arbal.CustomerLocationID = ardoc.CustomerLocationID; - arbal = (ARBalances)this.Caches[typeof(ARBalances)].Insert(arbal); - - arbal.CurrentBal += adj.AdjgTBSign * (adj.AdjAmt); - } - } - else - { - throw new PXException(Messages.AdjustRefersNonExistentDocument, adj.AdjgDocType, adj.AdjgRefNbr, adj.AdjdDocType, adj.AdjdRefNbr); - } - } - - private void UpdateARBalances(ARRegister ardoc) - { - UpdateARBalances(this, ardoc, ardoc.OrigDocAmt); - } - - private void UpdateARBalances(ARRegister ardoc, decimal? BalanceAmt) - { - UpdateARBalances(this, ardoc, BalanceAmt); - } - - public virtual void VoidOrigAdjustment(ARAdjust adj) - { - bool isVoidPayment = (adj.AdjgDocType == ARDocType.VoidPayment); - ARAdjust voidadj = PXSelect>, - Or>>>, - And>, - And>, - And>, - And>>>>>>>.Select - ( - this, - isVoidPayment ? ARDocType.Prepayment : adj.AdjgDocType, - isVoidPayment ? ARDocType.Payment : adj.AdjgDocType, - adj.AdjgRefNbr, - adj.AdjdDocType, - adj.AdjdRefNbr, - adj.VoidAdjNbr - ); - - if (voidadj != null) - { - if ((bool)voidadj.Voided) - { - throw new PXException(Messages.DocumentApplicationAlreadyVoided); - } - - voidadj.Voided = true; - Caches[typeof(ARAdjust)].Update(voidadj); - - adj.AdjAmt = -voidadj.AdjAmt; - adj.AdjDiscAmt = -voidadj.AdjDiscAmt; - adj.AdjWOAmt = -voidadj.AdjWOAmt; - adj.RGOLAmt = -voidadj.RGOLAmt; - adj.CuryAdjdAmt = -voidadj.CuryAdjdAmt; - adj.CuryAdjdDiscAmt = -voidadj.CuryAdjdDiscAmt; - adj.CuryAdjdWOAmt = -voidadj.CuryAdjdWOAmt; - adj.CuryAdjgAmt = -voidadj.CuryAdjgAmt; - adj.CuryAdjgDiscAmt = -voidadj.CuryAdjgDiscAmt; - adj.CuryAdjgWOAmt = -voidadj.CuryAdjgWOAmt; - - Caches[typeof(ARAdjust)].Update(adj); - - if (voidadj.AdjgDocType == ARDocType.CreditMemo && voidadj.AdjdHasPPDTaxes == true) - { - ARRegister crmemo = PXSelect, - And>>>>.SelectSingleBound(this, null, voidadj.AdjgRefNbr); - if (crmemo != null && crmemo.PendingPPD == true) - { - PXUpdate, ARAdjust, - Where, - And>, - And>, - And>>>>>> - .Update(this, voidadj.AdjdDocType, voidadj.AdjdRefNbr, voidadj.AdjgRefNbr); - } - } - } - } - - public virtual void UpdateBalances(ARAdjust adj, ARRegister adjddoc) - { - ARRegister ardoc = (ARRegister)adjddoc; - ARRegister cached = (ARRegister)ARDocument.Cache.Locate(ardoc); - if (cached != null) - { - ardoc = cached; - } - else if (_IsIntegrityCheck == true) - { - return; - } - - if (_IsIntegrityCheck == false && adj.VoidAdjNbr != null) - { - VoidOrigAdjustment(adj); - } - - if (string.Equals(adj.AdjdDocType, ardoc.DocType) && string.Equals(adj.AdjdRefNbr, ardoc.RefNbr, StringComparison.OrdinalIgnoreCase)) - { - ardoc.CuryDocBal -= (adj.CuryAdjdAmt + adj.CuryAdjdDiscAmt + adj.CuryAdjdWOAmt); - ardoc.DocBal -= (adj.AdjAmt + adj.AdjDiscAmt + adj.AdjWOAmt + (adj.ReverseGainLoss == false ? adj.RGOLAmt : -adj.RGOLAmt)); - ardoc.CuryDiscBal -= adj.CuryAdjdDiscAmt; - ardoc.DiscBal -= adj.AdjDiscAmt; - ardoc.CuryDiscTaken += adj.CuryAdjdDiscAmt; - ardoc.DiscTaken += adj.AdjDiscAmt; - ardoc.RGOLAmt += adj.RGOLAmt; - } - else if (string.Equals(adj.AdjgDocType, ardoc.DocType) && string.Equals(adj.AdjgRefNbr, ardoc.RefNbr, StringComparison.OrdinalIgnoreCase)) - { - ardoc.CuryDocBal -= adj.CuryAdjgAmt; - ardoc.DocBal -= adj.AdjAmt; - } - - if (ardoc.CuryDiscBal == 0m) - { - ardoc.DiscBal = 0m; - } - - if (_IsIntegrityCheck == false && ardoc.CuryDocBal < 0m) - { - throw new PXException(Messages.DocumentBalanceNegative); - } - - if (_IsIntegrityCheck == false && adj.AdjgDocDate < adjddoc.DocDate) - { - throw new PXException(Messages.ApplDate_Less_DocDate, PXUIFieldAttribute.GetDisplayName(ARPayment_DocType_RefNbr.Cache)); - } - - if (_IsIntegrityCheck == false && string.Compare(adj.AdjgFinPeriodID, adjddoc.FinPeriodID) < 0) - { - throw new PXException(Messages.ApplPeriod_Less_DocPeriod, PXUIFieldAttribute.GetDisplayName(ARPayment_DocType_RefNbr.Cache)); - } - - if (ardoc.CuryDocBal == 0m) - { - ardoc.CuryDiscBal = 0m; - ardoc.DiscBal = 0m; - ardoc.DocBal = 0m; - ardoc.OpenDoc = false; - - SetClosedPeriodsFromLatestApplication(ardoc, adj.AdjNbr); - } - else - { - if (ardoc.CuryDocBal == ardoc.CuryOrigDocAmt) - { - ardoc.CuryDiscBal = ardoc.CuryOrigDiscAmt; - ardoc.DiscBal = ardoc.OrigDiscAmt; - ardoc.CuryDiscTaken = 0m; - ardoc.DiscTaken = 0m; - } - - ardoc.OpenDoc = true; - ardoc.ClosedTranPeriodID = null; - ardoc.ClosedFinPeriodID = null; - } - - ARDocument.Cache.Update(ardoc); - } - - private void UpdateVoidedCheck(ARRegister voidcheck) - { - foreach (string origDocType in voidcheck.PossibleOriginalDocumentTypes()) - { - foreach (PXResult res in ARPayment_DocType_RefNbr - .Select(origDocType, voidcheck.RefNbr, voidcheck.CustomerID)) - { - ARRegister ardoc = res; - ARRegister cached = (ARRegister)ARDocument.Cache.Locate(ardoc); - - if (cached != null) - { - ardoc = cached; - } - - ardoc.Voided = true; - ardoc.OpenDoc = false; - ardoc.Hold = false; - ardoc.CuryDocBal = 0m; - ardoc.DocBal = 0m; - ardoc.ClosedFinPeriodID = voidcheck.ClosedFinPeriodID; - ardoc.ClosedTranPeriodID = voidcheck.ClosedTranPeriodID; - - ARDocument.Cache.Update(ardoc); - - if (!_IsIntegrityCheck) - { - // For the voided document, we must remove all unreleased applications. - // - - foreach (ARAdjust application in PXSelect>, - And>, - And>, - And>>>>> - .Select(this, ardoc.DocType, ardoc.RefNbr, ardoc.AdjCntr)) - { - Caches[typeof(ARAdjust)].Delete(application); - } - } - - PXDatabase.Update( - new PXDataFieldRestrict(typeof(SO.SOAdjust.adjgDocType).Name, PXDbType.VarChar, SO.SOAdjust.AdjgDocTypeLength, ardoc.DocType, PXComp.EQ), - new PXDataFieldRestrict(typeof(SO.SOAdjust.adjgRefNbr).Name, PXDbType.VarChar, SO.SOAdjust.AdjgRefNbrLength, ardoc.RefNbr, PXComp.EQ), - new PXDataFieldAssign(typeof(SO.SOAdjust.voided).Name, PXDbType.Bit, true)); - } - } - } - - private void VerifyVoidCheckNumberMatchesOriginalPayment(ARPayment voidcheck) - { - foreach (string origDocType in voidcheck.PossibleOriginalDocumentTypes()) - { - foreach (PXResult res in ARPayment_DocType_RefNbr - .Select(origDocType, voidcheck.RefNbr, voidcheck.CustomerID)) - { - ARPayment payment = res; - if (_IsIntegrityCheck == false && - !string.Equals(voidcheck.ExtRefNbr, payment.ExtRefNbr, StringComparison.OrdinalIgnoreCase)) - { - throw new PXException(Messages.VoidAppl_CheckNbr_NotMatchOrigPayment); - } - } - } - } - - public virtual void ReleaseDocProc(JournalEntry je, ref ARRegister doc, PXResult res) - { - ReleaseDocProc(je, ref doc, res, doc.AdjCntr); - - //increment default for AdjNbr - doc.AdjCntr++; - } - - /// - /// Ensures that no unreleased voiding document exists for the specified payment. - /// (If the applications of the voided and the voiding document are not - /// synchronized, it can lead to a balance discrepancy, see AC-78131). - /// - public static void EnsureNoUnreleasedVoidPaymentExists(PXGraph selectGraph, ARRegister payment, string actionDescription) - { - ARRegister unreleasedVoidPayment = - HasUnreleasedVoidPayment.Select(selectGraph, payment); - - if (unreleasedVoidPayment != null) - { - throw new PXException( - Common.Messages.CannotPerformActionOnDocumentUnreleasedVoidPaymentExists, - PXLocalizer.Localize(GetLabel.For(payment.DocType)), - payment.RefNbr, - PXLocalizer.Localize(actionDescription), - PXLocalizer.Localize(GetLabel.For(unreleasedVoidPayment.DocType)), - PXLocalizer.Localize(GetLabel.For(payment.DocType)), - PXLocalizer.Localize(GetLabel.For(unreleasedVoidPayment.DocType)), - unreleasedVoidPayment.RefNbr); - } - } - - public virtual void ReleaseDocProc(JournalEntry je, ref ARRegister doc, PXResult res, int? AdjNbr) - { - ARPayment ardoc = res; - CurrencyInfo info = res; - Customer vend = res; - Currency paycury = res; - CashAccount cashacct = res; - - EnsureNoUnreleasedVoidPaymentExists(this, ardoc, Common.Messages.ActionReleased); - - CustomerClass custclass = PXSelectJoin>>>.Select(this, null); - - CurrencyInfo new_info = PXCache.CreateCopy(info); - new_info.CuryInfoID = null; - new_info.ModuleCode = "GL"; - new_info = je.currencyinfo.Insert(new_info) ?? new_info; - - if (doc.Released == false) - { - //should always restore ARRegister to ARPayment after invoice part release of cash sale - PXCache.RestoreCopy(ardoc, doc); - - if (doc.DocType != ARDocType.SmallBalanceWO) - { - GLTran tran = new GLTran(); - tran.SummPost = true; - tran.BranchID = cashacct.BranchID; - tran.AccountID = cashacct.AccountID; - tran.SubID = cashacct.SubID; - tran.CuryDebitAmt = (ardoc.DrCr == DrCr.Debit) ? ardoc.CuryOrigDocAmt : 0m; - tran.DebitAmt = (ardoc.DrCr == DrCr.Debit) ? ardoc.OrigDocAmt : 0m; - tran.CuryCreditAmt = (ardoc.DrCr == DrCr.Debit) ? 0m : ardoc.CuryOrigDocAmt; - tran.CreditAmt = (ardoc.DrCr == DrCr.Debit) ? 0m : ardoc.OrigDocAmt; - tran.TranType = ardoc.DocType; - tran.TranClass = ardoc.DocClass; - tran.RefNbr = ardoc.RefNbr; - tran.TranDesc = ardoc.DocDesc; - tran.TranDate = ardoc.DocDate; - tran.TranPeriodID = ardoc.TranPeriodID; - tran.FinPeriodID = ardoc.FinPeriodID; - tran.CuryInfoID = new_info.CuryInfoID; - tran.Released = true; - tran.CATranID = ardoc.CATranID; - tran.ReferenceID = ardoc.CustomerID; - tran.ProjectID = PM.ProjectDefaultAttribute.NonProject(this); - - je.GLTranModuleBatNbr.Insert(tran); - - //Debit Payment AR Account - tran = new GLTran(); - tran.SummPost = true; - //if (ardoc.DocType == ARDocType.CashSale || ardoc.DocType == ARDocType.CashReturn) - if (!ARPaymentType.CanHaveBalance(ardoc.DocType)) - { - tran.ZeroPost = false; - } - tran.BranchID = ardoc.BranchID; - tran.AccountID = ardoc.ARAccountID; - tran.ReclassificationProhibited = true; - tran.SubID = ardoc.ARSubID; - tran.CuryDebitAmt = (ardoc.DrCr == DrCr.Debit) ? 0m : ardoc.CuryOrigDocAmt; - tran.DebitAmt = (ardoc.DrCr == DrCr.Debit) ? 0m : ardoc.OrigDocAmt; - tran.CuryCreditAmt = (ardoc.DrCr == DrCr.Debit) ? ardoc.CuryOrigDocAmt : 0m; - tran.CreditAmt = (ardoc.DrCr == DrCr.Debit) ? ardoc.OrigDocAmt : 0m; - tran.TranType = ardoc.DocType; - tran.TranClass = GLTran.tranClass.Payment; - tran.RefNbr = ardoc.RefNbr; - tran.TranDesc = ardoc.DocDesc; - tran.TranDate = ardoc.DocDate; - tran.TranPeriodID = ardoc.TranPeriodID; - tran.FinPeriodID = ardoc.FinPeriodID; - tran.CuryInfoID = new_info.CuryInfoID; - tran.Released = true; - tran.ReferenceID = ardoc.CustomerID; - tran.ProjectID = ardoc.ProjectID; - tran.TaskID = ardoc.TaskID; - - UpdateHistory(tran, vend); - UpdateHistory(tran, vend, new_info); - - je.GLTranModuleBatNbr.Insert(tran); - } - - foreach (ARPaymentChargeTran charge in ARPaymentChargeTran_DocType_RefNbr.Select(doc.DocType, doc.RefNbr)) - { - bool isCADebit = charge.GetCASign() == 1; - - GLTran tran = new GLTran(); - tran.SummPost = true; - tran.BranchID = cashacct.BranchID; - tran.AccountID = cashacct.AccountID; - tran.SubID = cashacct.SubID; - tran.CuryDebitAmt = isCADebit ? charge.CuryTranAmt : 0m; - tran.DebitAmt = isCADebit ? charge.TranAmt : 0m; - tran.CuryCreditAmt = isCADebit ? 0m : charge.CuryTranAmt; - tran.CreditAmt = isCADebit ? 0m : charge.TranAmt; - tran.TranType = charge.DocType; - tran.TranClass = ardoc.DocClass; - tran.RefNbr = charge.RefNbr; - tran.TranDesc = charge.TranDesc; - tran.TranDate = charge.TranDate; - tran.TranPeriodID = charge.TranPeriodID; - tran.FinPeriodID = charge.FinPeriodID; - tran.CuryInfoID = new_info.CuryInfoID; - tran.Released = true; - tran.CATranID = charge.CashTranID ?? ardoc.CATranID; - tran.ReferenceID = ardoc.CustomerID; - - je.GLTranModuleBatNbr.Insert(tran); - - tran = new GLTran(); - tran.SummPost = true; - tran.ZeroPost = false; - tran.BranchID = ardoc.BranchID; - tran.AccountID = charge.AccountID; - tran.SubID = charge.SubID; - tran.CuryDebitAmt = isCADebit ? 0m : charge.CuryTranAmt; - tran.DebitAmt = isCADebit ? 0m : charge.TranAmt; - tran.CuryCreditAmt = isCADebit ? charge.CuryTranAmt : 0m; - tran.CreditAmt = isCADebit ? charge.TranAmt : 0m; - tran.TranType = charge.DocType; - tran.TranClass = GLTran.tranClass.Charge; - tran.RefNbr = charge.RefNbr; - tran.TranDesc = charge.TranDesc; - tran.TranDate = charge.TranDate; - tran.TranPeriodID = charge.TranPeriodID; - tran.FinPeriodID = charge.FinPeriodID; - tran.CuryInfoID = new_info.CuryInfoID; - tran.Released = true; - tran.ReferenceID = ardoc.CustomerID; - - je.GLTranModuleBatNbr.Insert(tran); - - charge.Released = true; - ARPaymentChargeTran_DocType_RefNbr.Update(charge); - } - - doc.CuryDocBal = doc.CuryOrigDocAmt; - doc.DocBal = doc.OrigDocAmt; - - doc.Voided = false; - doc.OpenDoc = true; - doc.ClosedFinPeriodID = null; - doc.ClosedTranPeriodID = null; - - if (ardoc.VoidAppl == true) - { - doc.OpenDoc = false; - doc.ClosedFinPeriodID = doc.FinPeriodID; - doc.ClosedTranPeriodID = doc.TranPeriodID; - - VerifyVoidCheckNumberMatchesOriginalPayment(ardoc); - } - } - - if (doc.DocType == ARDocType.CashSale || doc.DocType == ARDocType.CashReturn) - { - if (_IsIntegrityCheck == false) - { - ARAdjust adj = new ARAdjust(); - adj.AdjdDocType = doc.DocType; - adj.AdjdRefNbr = doc.RefNbr; - adj.AdjdBranchID = doc.BranchID; - adj.AdjgDocType = doc.DocType; - adj.AdjgRefNbr = doc.RefNbr; - adj.AdjgBranchID = doc.BranchID; - adj.AdjdCustomerID = doc.CustomerID; - adj.AdjdARAcct = doc.ARAccountID; - adj.AdjdARSub = doc.ARSubID; - adj.AdjdCuryInfoID = doc.CuryInfoID; - adj.AdjdDocDate = doc.DocDate; - adj.AdjdFinPeriodID = doc.FinPeriodID; - adj.AdjdTranPeriodID = doc.TranPeriodID; - adj.AdjdOrigCuryInfoID = doc.CuryInfoID; - adj.AdjgCuryInfoID = doc.CuryInfoID; - adj.AdjgDocDate = doc.DocDate; - adj.AdjgFinPeriodID = doc.FinPeriodID; - adj.AdjgTranPeriodID = doc.TranPeriodID; - adj.AdjNbr = doc.AdjCntr; - adj.AdjAmt = doc.OrigDocAmt; - adj.AdjDiscAmt = doc.OrigDiscAmt; - adj.RGOLAmt = 0m; - adj.CuryAdjdAmt = doc.CuryOrigDocAmt; - adj.CuryAdjdDiscAmt = doc.CuryOrigDiscAmt; - adj.CuryAdjgAmt = doc.CuryOrigDocAmt; - adj.CuryAdjgDiscAmt = doc.CuryOrigDiscAmt; - adj.Released = false; - adj.CustomerID = doc.CustomerID; - ARAdjust_AdjgDocType_RefNbr_CustomerID.Cache.Insert(adj); - } - - doc.CuryDocBal += doc.CuryOrigDiscAmt; - doc.DocBal += doc.OrigDiscAmt; - doc.ClosedFinPeriodID = doc.FinPeriodID; - doc.ClosedTranPeriodID = doc.TranPeriodID; - } - - doc.Released = true; - - PXResultset adjustments = ARAdjustsToRelease - ?? ARAdjust_AdjgDocType_RefNbr_CustomerID.Select(doc.DocType, doc.RefNbr, AdjNbr); - - var lastAdjustment = ProcessAdjustments(je, adjustments, doc, ardoc, vend, new_info, paycury); - - ARAdjust prev_adj = lastAdjustment.Item1; - CurrencyInfo prev_info = lastAdjustment.Item2; - - if (_IsIntegrityCheck == false && (bool)ardoc.VoidAppl == false && doc.CuryDocBal < 0m) - { - throw new PXException(Messages.DocumentBalanceNegative); - } - - /// The case, when payment is open and sum of base amounts for applications - /// exceeds payment base amount, due to small rounding for each application. - /// - bool isOpenPaymentWithNegativeBalance = doc.CuryDocBal > 0m && doc.DocBal < 0; - - if (!_IsIntegrityCheck && - prev_adj.AdjdRefNbr != null && - (doc.CuryDocBal == 0m && doc.DocBal != 0m || isOpenPaymentWithNegativeBalance)) - { - ProcessRounding(je, doc, prev_adj, ardoc, vend, paycury, prev_info, new_info, doc.DocBal, prev_adj.ReverseGainLoss); - } - - bool isVoidingDoc = ardoc.VoidAppl == true || - (ardoc.SelfVoidingDoc == true && prev_adj.Voided == true); - - if (doc.CuryDocBal == 0m || isVoidingDoc) - { - doc.CuryDocBal = 0m; - doc.DocBal = 0m; - doc.OpenDoc = false; - - SetClosedPeriodsFromLatestApplication(doc, doc.AdjCntr); - if (isVoidingDoc && doc.DocType != ARDocType.CashReturn) - { - UpdateVoidedCheck(doc); - } - - if (!(bool)ardoc.VoidAppl) - { - DeactivateOneTimeCustomerIfAllDocsIsClosed(vend); - } - } - else - { - if (isOpenPaymentWithNegativeBalance) - { - doc.DocBal = 0m; - } - - doc.OpenDoc = true; - doc.ClosedTranPeriodID = null; - doc.ClosedFinPeriodID = null; - } - } - - protected void DeactivateOneTimeCustomerIfAllDocsIsClosed(Customer customer) - { - if (customer.Status != BAccount.status.OneTime) - return; - - ARRegister apRegister = PXSelect>, - And, - And>>>> - .SelectWindowed(this, 0, 1, customer.BAccountID); - - if (apRegister != null) - return; - - customer.Status = BAccount.status.Inactive; - Caches[typeof(Customer)].Update(customer); - Caches[typeof(Customer)].Persist(PXDBOperation.Update); - Caches[typeof(Customer)].Persisted(false); - } - - protected virtual Tuple ProcessAdjustments(JournalEntry je, PXResultset adjustments, ARRegister paymentRegister, ARPayment payment, Customer paymentCustomer, CurrencyInfo new_info, Currency paycury) - { - ARAdjust prev_adj = new ARAdjust(); - CurrencyInfo prev_info = new CurrencyInfo(); - - foreach (PXResult adjres in adjustments) - { - ARAdjust adj = adjres; - CurrencyInfo vouch_info = adjres; - Currency cury = adjres; - ARRegister adjustedInvoice = adjres; - ARPayment adjgdoc = adjres; - - EnsureNoUnreleasedVoidPaymentExists( - this, - adjgdoc, - payment.DocType == ARDocType.Refund - ? Common.Messages.ActionRefunded - : Common.Messages.ActionAdjusted); - - if (adj.CuryAdjgAmt == 0m && adj.CuryAdjgDiscAmt == 0m) - { - ARAdjust_AdjgDocType_RefNbr_CustomerID.Cache.Delete(adj); - continue; - } - - if (adj.Hold == true) - { - throw new PXException(Messages.Document_OnHold_CannotRelease); - } - - if (_IsIntegrityCheck == false && adj.PendingPPD == true) - { - adjustedInvoice.PendingPPD = !adj.Voided; - ARDocument.Cache.Update(adjustedInvoice); - } - - bool notValidatingCrossCustomerFromAdjusting = (_IsIntegrityCheck && adj.CustomerID != adj.AdjdCustomerID) == false; - - ProcessSalesPersonCommission(adj, payment, adjustedInvoice, cury); - - if (adjustedInvoice.RefNbr != null) - { - if (notValidatingCrossCustomerFromAdjusting) - { - //Void Payment is processed after SC, avoid balance update since SC does not hold any balance even after application reversal and has WO Account in AR Account - if (adjustedInvoice.DocType != ARDocType.SmallCreditWO) - { - UpdateBalances(adj, adjustedInvoice); - UpdateARBalances(adj, adjustedInvoice); - } - else if (adj.Voided == true && adjustedInvoice.Voided != true) - { - adjustedInvoice.Voided = true; - ARDocument.Cache.Update(adjustedInvoice); - - if (_IsIntegrityCheck == false && adj.VoidAdjNbr != null) - { - VoidOrigAdjustment(adj); - } - } - } - - UpdateARBalances(adj, paymentRegister); - - if (notValidatingCrossCustomerFromAdjusting) - { - UpdateARBalancesDates(adjustedInvoice, adjustments.Count); - } - } - else - { - UpdateBalances(adj, adjgdoc); - UpdateARBalances(adj, paymentRegister); - UpdateARBalances(adj, adjgdoc); - } - - ProcessAdjusting(je, adj, payment, paymentCustomer, new_info); - - if (notValidatingCrossCustomerFromAdjusting) - { - ProcessAdjusted(je, adj, adjustedInvoice, payment, vouch_info, new_info); - } - - ProcessCashDiscount(je, adj, payment, paymentCustomer, new_info, vouch_info); - ProcessWriteOff(je, adj, payment, paymentCustomer, new_info, vouch_info); - ProcessGOL(je, adj, payment, paymentCustomer, adjustedInvoice, paycury, cury, new_info, vouch_info); - - //true for Quick Check and Void Quick Check - if (adj.AdjgDocType != adj.AdjdDocType || adj.AdjgRefNbr != adj.AdjdRefNbr) - { - paymentRegister.CuryDocBal -= adj.AdjgBalSign * adj.CuryAdjgAmt; - paymentRegister.DocBal -= adj.AdjgBalSign * adj.AdjAmt; - } - - if (_IsIntegrityCheck == false) - { - if (je.GLTranModuleBatNbr.Cache.IsInsertedUpdatedDeleted) - { - je.Save.Press(); - } - - if (!je.BatchModule.Cache.IsDirty) - { - adj.AdjBatchNbr = ((Batch)je.BatchModule.Current).BatchNbr; - } - adj.Released = true; - adj = (ARAdjust)Caches[typeof(ARAdjust)].Update(adj); - } - - prev_adj = adj; - prev_info = adjres; - - ProcessSVATAdjustments(prev_adj, adjustedInvoice, paymentRegister); - } - - return new Tuple(prev_adj, prev_info); - } - - protected virtual void ProcessSVATAdjustments(ARAdjust adj, ARRegister adjddoc, ARRegister adjgdoc) - { - if (PXAccess.FeatureInstalled() && _IsIntegrityCheck == false) - { - foreach (SVATConversionHist docSVAT in PXSelect, - And2>, - And>, - Or>, - And>>>>>, - And, - And, - And>>>>>>> - .SelectMultiBound(this, new object[] { adj })) - { - bool isPayment = adj.AdjgDocType == docSVAT.AdjdDocType && adj.AdjgRefNbr == docSVAT.AdjdRefNbr; - decimal percent = isPayment - ? ((adj.CuryAdjgAmt ?? 0m) + (adj.CuryAdjgDiscAmt ?? 0m) + (adj.CuryAdjgWOAmt ?? 0m)) / (adjgdoc.CuryOrigDocAmt ?? 0m) - : ((adj.CuryAdjdAmt ?? 0m) + (adj.CuryAdjdDiscAmt ?? 0m) + (adj.CuryAdjdWOAmt ?? 0m)) / (adjddoc.CuryOrigDocAmt ?? 0m); - decimal curyTaxableAmt = PXDBCurrencyAttribute.RoundCury(SVATConversionHistory.Cache, docSVAT, (docSVAT.CuryTaxableAmt ?? 0m) * percent); - decimal curyTaxAmt = PXDBCurrencyAttribute.RoundCury(SVATConversionHistory.Cache, docSVAT, (docSVAT.CuryTaxAmt ?? 0m) * percent); - - SVATConversionHist adjSVAT = new SVATConversionHist - { - Module = BatchModule.AR, - AdjdBranchID = adj.AdjdBranchID, - AdjdDocType = isPayment ? adj.AdjgDocType : adj.AdjdDocType, - AdjdRefNbr = isPayment ? adj.AdjgRefNbr : adj.AdjdRefNbr, - AdjgDocType = isPayment ? adj.AdjdDocType : adj.AdjgDocType, - AdjgRefNbr = isPayment ? adj.AdjdRefNbr : adj.AdjgRefNbr, - AdjNbr = adj.AdjNbr, - AdjdDocDate = adj.AdjgDocDate, - AdjdFinPeriodID = adj.AdjdFinPeriodID, - - TaxID = docSVAT.TaxID, - TaxType = docSVAT.TaxType, - TaxRate = docSVAT.TaxRate, - VendorID = docSVAT.VendorID, - ReversalMethod = SVATTaxReversalMethods.OnPayments, - - CuryInfoID = docSVAT.CuryInfoID, - CuryTaxableAmt = curyTaxableAmt, - CuryTaxAmt = curyTaxAmt, - CuryUnrecognizedTaxAmt = curyTaxAmt - }; - - adjSVAT.FillBaseAmounts(SVATConversionHistory.Cache); - - if (adjSVAT.CuryTaxAmt != docSVAT.CuryTaxAmt && - (isPayment ? adjgdoc.CuryDocBal : adjddoc.CuryDocBal) == 0m) - { - PXResultset rows = PXSelect, - And>, - And>, - And>, - And, - Or>>>>>>>> - .SelectMultiBound(this, new object[] { docSVAT }); - if (rows.Any()) - { - adjSVAT.CuryTaxableAmt = docSVAT.CuryTaxableAmt; - adjSVAT.TaxableAmt = docSVAT.TaxableAmt; - adjSVAT.CuryTaxAmt = docSVAT.CuryTaxAmt; - adjSVAT.TaxAmt = docSVAT.TaxAmt; - - foreach (SVATConversionHist row in rows) - { - adjSVAT.CuryTaxableAmt -= (row.CuryTaxableAmt ?? 0m); - adjSVAT.TaxableAmt -= (row.TaxableAmt ?? 0m); - adjSVAT.CuryTaxAmt -= (row.CuryTaxAmt ?? 0m); - adjSVAT.TaxAmt -= (row.TaxAmt ?? 0m); - } - - adjSVAT.CuryUnrecognizedTaxAmt = adjSVAT.CuryTaxAmt; - adjSVAT.UnrecognizedTaxAmt = adjSVAT.TaxAmt; - } - } - - adjSVAT = (SVATConversionHist)SVATConversionHistory.Cache.Insert(adjSVAT); - - docSVAT.Processed = false; - docSVAT.AdjgFinPeriodID = null; - - PXTimeStampScope.PutPersisted(SVATConversionHistory.Cache, docSVAT, PXDatabase.SelectTimeStamp()); - SVATConversionHistory.Cache.Update(docSVAT); - } - } - } - - protected virtual void ProcessAdjustmentsOnlyAdjusted(JournalEntry je, PXResultset adjustments) - { - foreach (PXResult adjres in adjustments) - { - ARAdjust adj = adjres; - CurrencyInfo vouch_info = adjres; - Currency cury = adjres; - ARInvoice adjddoc = adjres; - ARPayment adjgdoc = adjres; - - if (adj.CuryAdjgAmt == 0m && adj.CuryAdjgDiscAmt == 0m) - { - ARAdjust_AdjgDocType_RefNbr_CustomerID.Cache.Delete(adj); - continue; - } - - if (adj.Hold == true) - { - throw new PXException(Messages.Document_OnHold_CannotRelease); - } - - if (adjddoc.RefNbr != null) - { - if (adjddoc.DocType != ARDocType.SmallCreditWO) - { - UpdateBalances(adj, adjddoc); - UpdateARBalances(adj, adjddoc); - } - else if (adj.Voided == true && adjddoc.Voided != true) - { - adjddoc.Voided = true; - Caches[typeof(ARInvoice)].Update(adjddoc); - - if (_IsIntegrityCheck == false && adj.VoidAdjNbr != null) - { - VoidOrigAdjustment(adj); - } - } - - UpdateARBalancesDates(adjddoc, adjustments.Count); - } - - CurrencyInfo payment_info = PXSelect>>>.Select(this, adjgdoc.CuryInfoID); - - ProcessAdjusted(je, adj, adjddoc, adjgdoc, vouch_info, payment_info); - } - } - - private void ProcessSalesPersonCommission(ARAdjust adj, ARPayment payment, ARRegister adjustedInvoice, Currency cury) - { - /// dont process if validating child - List spTrans = new List(); - if (payment.DocType != ARDocType.CreditMemo) //Credit memos are treates as negative invoice - { - foreach (ARSalesPerTran iSPT in this.ARDoc_SalesPerTrans.Select(adjustedInvoice.DocType, adjustedInvoice.RefNbr)) - { - ARSalesPerTran paySPT = new ARSalesPerTran(); - Copy(paySPT, payment); - Copy(paySPT, adj); - decimal applRatio = ((adj.CuryAdjdAmt + adj.CuryAdjdDiscAmt) / adjustedInvoice.CuryOrigDocAmt).Value; - if (payment.DocType == ARDocType.CashSale || payment.DocType == ARDocType.CashReturn) - { - applRatio = 1m; - } - else if (payment.DocType == ARDocType.CreditMemo) - { - applRatio = -applRatio; - } - CopyShare(paySPT, iSPT, applRatio, (cury.DecimalPlaces ?? 2)); - paySPT = this.ARDoc_SalesPerTrans.Insert(paySPT); - } - } - } - - private void ProcessAdjusting(JournalEntry je, ARAdjust adj, ARPayment payment, Customer paymentCustomer, CurrencyInfo new_info) - { - GLTran tran = new GLTran(); - tran.SummPost = true; - tran.ZeroPost = false; - tran.BranchID = adj.AdjgBranchID; - tran.AccountID = payment.ARAccountID; - tran.ReclassificationProhibited = true; - tran.SubID = payment.ARSubID; - tran.DebitAmt = (adj.AdjgGLSign == 1m) ? adj.AdjAmt : 0m; - tran.CuryDebitAmt = (adj.AdjgGLSign == 1m) ? adj.CuryAdjgAmt : 0m; - tran.CreditAmt = (adj.AdjgGLSign == 1m) ? 0m : adj.AdjAmt; - tran.CuryCreditAmt = (adj.AdjgGLSign == 1m) ? 0m : adj.CuryAdjgAmt; - tran.TranType = adj.AdjgDocType; - tran.TranClass = GLTran.tranClass.Payment; - tran.RefNbr = adj.AdjgRefNbr; - tran.TranDesc = payment.DocDesc; - tran.TranDate = adj.AdjgDocDate; - tran.TranPeriodID = adj.AdjgTranPeriodID; - tran.FinPeriodID = adj.AdjgFinPeriodID; - tran.CuryInfoID = new_info.CuryInfoID; - tran.Released = true; - tran.ReferenceID = payment.CustomerID; - tran.OrigAccountID = adj.AdjdARAcct; - tran.OrigSubID = adj.AdjdARSub; - tran.ProjectID = payment.ProjectID; - tran.TaskID = payment.TaskID; - - UpdateHistory(tran, paymentCustomer); - UpdateHistory(tran, paymentCustomer, new_info); - - if (adj.AdjdDocType == ARDocType.SmallCreditWO) - { - bool isPrepayment = (adj.AdjgDocType == ARDocType.Prepayment); - if (adj.AdjgDocType == ARDocType.VoidPayment) - { - ARRegister orig = PXSelect>, - And, - Or>>>>, - OrderBy>, int0>, int1>, Asc>>>>.Select(this, tran.RefNbr); - isPrepayment = (orig != null && orig.DocType == ARDocType.Prepayment); - } - - if (isPrepayment) - { - ARHistBucket bucket = new ARHistBucket(); - bucket.arAccountID = tran.AccountID; - bucket.arSubID = tran.SubID; - bucket.SignPayments = 1m; - bucket.SignDeposits = -1m; - bucket.SignPtd = -1m; - - UpdateHistory(tran, paymentCustomer, bucket); - UpdateHistory(tran, paymentCustomer, new_info, bucket); - } - } - - je.GLTranModuleBatNbr.Insert(tran); - } - - private void ProcessAdjusted(JournalEntry je, ARAdjust adj, ARRegister adjustedInvoice, ARPayment payment, CurrencyInfo vouch_info, CurrencyInfo new_info) - { - Customer voucherCustomer = PXSelect>>>.Select(this, adj.AdjdCustomerID); - - //Credit Voucher AR Account/minus RGOL for refund - var tran = new GLTran(); - tran.SummPost = true; - tran.ZeroPost = false; - tran.BranchID = adj.AdjdBranchID; - //Small-Credit has Payment AR Account in AdjdARAcct and WO Account in ARAccountID - tran.AccountID = (adj.AdjdDocType == ARDocType.SmallCreditWO) ? adjustedInvoice.ARAccountID : adj.AdjdARAcct; - tran.ReclassificationProhibited = true; - tran.SubID = (adj.AdjdDocType == ARDocType.SmallCreditWO) ? adjustedInvoice.ARSubID : adj.AdjdARSub; - //Small-Credit reversal should update history for payment AR Account(AdjdARAcct) - tran.OrigAccountID = adj.AdjdARAcct; - tran.OrigSubID = adj.AdjdARSub; - tran.CreditAmt = (adj.AdjgGLSign == 1m) ? adj.AdjAmt + adj.AdjDiscAmt + adj.AdjWOAmt + adj.RGOLAmt : 0m; - tran.CuryCreditAmt = (adj.AdjgGLSign == 1m) ? (object.Equals(new_info.CuryID, new_info.BaseCuryID) ? tran.CreditAmt : adj.CuryAdjgAmt + adj.CuryAdjgDiscAmt + adj.CuryAdjgWOAmt) : 0m; - tran.DebitAmt = (adj.AdjgGLSign == 1m) ? 0m : adj.AdjAmt + adj.AdjDiscAmt + adj.AdjWOAmt - adj.RGOLAmt; - tran.CuryDebitAmt = (adj.AdjgGLSign == 1m) ? 0m : (object.Equals(new_info.CuryID, new_info.BaseCuryID) ? tran.DebitAmt : adj.CuryAdjgAmt + adj.CuryAdjgDiscAmt + adj.CuryAdjgWOAmt); - tran.TranType = adj.AdjgDocType; - //always N for AdjdDocs except Prepayment - tran.TranClass = ARDocType.DocClass(adj.AdjdDocType); - tran.RefNbr = adj.AdjgRefNbr; - tran.TranDesc = payment.DocDesc; - tran.TranDate = adj.AdjgDocDate; - tran.TranPeriodID = adj.AdjgTranPeriodID; - tran.FinPeriodID = adj.AdjgFinPeriodID; - tran.CuryInfoID = new_info.CuryInfoID; - tran.Released = true; - tran.ReferenceID = payment.CustomerID; - tran.ProjectID = PM.ProjectDefaultAttribute.NonProject(je); - - UpdateHistory(tran, voucherCustomer); - - je.GLTranModuleBatNbr.Insert(tran); - - //Update CuryHistory in Voucher currency - tran.CuryCreditAmt = (adj.AdjgGLSign == 1m) ? (object.Equals(vouch_info.CuryID, vouch_info.BaseCuryID) ? tran.CreditAmt : adj.CuryAdjdAmt + adj.CuryAdjdDiscAmt + adj.CuryAdjdWOAmt) : 0m; - tran.CuryDebitAmt = (adj.AdjgGLSign == 1m) ? 0m : (object.Equals(vouch_info.CuryID, vouch_info.BaseCuryID) ? tran.DebitAmt : adj.CuryAdjdAmt + adj.CuryAdjdDiscAmt + adj.CuryAdjdWOAmt); - UpdateHistory(tran, voucherCustomer, vouch_info); - } - - private void ProcessCashDiscount(JournalEntry je, ARAdjust adj, ARPayment payment, Customer paymentCustomer, CurrencyInfo new_info, CurrencyInfo vouch_info) - { - //Credit Discount Taken/does not apply to refund, since no disc in AD - var tran = new GLTran(); - tran.SummPost = this.SummPost; - tran.BranchID = adj.AdjdBranchID; - tran.AccountID = paymentCustomer.DiscTakenAcctID; - tran.SubID = paymentCustomer.DiscTakenSubID; - tran.OrigAccountID = adj.AdjdARAcct; - tran.OrigSubID = adj.AdjdARSub; - tran.DebitAmt = (adj.AdjgGLSign == 1m) ? adj.AdjDiscAmt : 0m; - tran.CuryDebitAmt = (adj.AdjgGLSign == 1m) ? adj.CuryAdjgDiscAmt : 0m; - tran.CreditAmt = (adj.AdjgGLSign == 1m) ? 0m : adj.AdjDiscAmt; - tran.CuryCreditAmt = (adj.AdjgGLSign == 1m) ? 0m : adj.CuryAdjgDiscAmt; - tran.TranType = adj.AdjgDocType; - tran.TranClass = GLTran.tranClass.Discount; - tran.RefNbr = adj.AdjgRefNbr; - tran.TranDesc = payment.DocDesc; - tran.TranDate = adj.AdjgDocDate; - tran.TranPeriodID = adj.AdjgTranPeriodID; - tran.FinPeriodID = adj.AdjgFinPeriodID; - tran.CuryInfoID = new_info.CuryInfoID; - tran.Released = true; - tran.ReferenceID = payment.CustomerID; - tran.ProjectID = PM.ProjectDefaultAttribute.NonProject(je); - - UpdateHistory(tran, paymentCustomer); - - je.GLTranModuleBatNbr.Insert(tran); - - //Update CuryHistory in Voucher currency - tran.CuryDebitAmt = (adj.AdjgGLSign == 1m) ? adj.CuryAdjdDiscAmt : 0m; - tran.CuryCreditAmt = (adj.AdjgGLSign == 1m) ? 0m : adj.CuryAdjdDiscAmt; - UpdateHistory(tran, paymentCustomer, vouch_info); - } - - private void ProcessWriteOff(JournalEntry je, ARAdjust adj, ARPayment payment, Customer paymentCustomer, CurrencyInfo new_info, CurrencyInfo vouch_info) - { - //Credit WO Account - if (adj.AdjWOAmt != 0) - { - ARInvoice adjusted = PXSelect>, And>>>>.Select(pe, adj.AdjdDocType, adj.AdjdRefNbr); - - ReasonCode reasonCode = PXSelect>>>.Select(this, adj.WriteOffReasonCode); - - if (reasonCode == null) - throw new PXException(PXMessages.LocalizeFormatNoPrefixNLA(Messages.ReasonCodeNotFound, adj.WriteOffReasonCode)); - - Location customerLocation = PXSelect>, - And>>>>.Select((PXGraph)pe, adjusted.CustomerID, adjusted.CustomerLocationID); - - CRLocation companyLocation = PXSelectJoin, And>>, - InnerJoin>>>, Where>>>.Select((PXGraph)pe, adjusted.BranchID); - - object value = null; - if (reasonCode.Usage == ReasonCodeUsages.BalanceWriteOff || reasonCode.Usage == ReasonCodeUsages.CreditWriteOff) - { - value = ReasonCodeSubAccountMaskAttribute.MakeSub((PXGraph)pe, reasonCode.SubMask, - new object[] { reasonCode.SubID, customerLocation.CSalesSubID, companyLocation.CMPSalesSubID }, - new Type[] { typeof(ReasonCode.subID), typeof(Location.cSalesSubID), typeof(Location.cMPSalesSubID) }); - } - else - { - throw new PXException(Messages.InvalidReasonCode); - } - - var tran = new GLTran(); - tran.SummPost = this.SummPost; - tran.BranchID = adj.AdjdBranchID; - tran.AccountID = reasonCode.AccountID; - tran.SubID = reasonCode.SubID; - tran.OrigAccountID = adj.AdjdARAcct; - tran.OrigSubID = adj.AdjdARSub; - tran.DebitAmt = (adj.AdjgGLSign == 1m) ? adj.AdjWOAmt : 0m; - tran.CuryDebitAmt = (adj.AdjgGLSign == 1m) ? adj.CuryAdjgWOAmt : 0m; - tran.CreditAmt = (adj.AdjgGLSign == 1m) ? 0m : adj.AdjWOAmt; - tran.CuryCreditAmt = (adj.AdjgGLSign == 1m) ? 0m : adj.CuryAdjgWOAmt; - tran.TranType = adj.AdjgDocType; - tran.TranClass = GLTran.tranClass.WriteOff; - tran.RefNbr = adj.AdjgRefNbr; - tran.TranDesc = payment.DocDesc; - tran.TranDate = adj.AdjgDocDate; - tran.TranPeriodID = adj.AdjgTranPeriodID; - tran.FinPeriodID = adj.AdjgFinPeriodID; - tran.CuryInfoID = new_info.CuryInfoID; - tran.Released = true; - tran.ReferenceID = payment.CustomerID; - tran.ProjectID = PM.ProjectDefaultAttribute.NonProject(je); - - UpdateHistory(tran, paymentCustomer); - - GLTran tranNew = je.GLTranModuleBatNbr.Insert(tran); - je.GLTranModuleBatNbr.SetValueExt(tranNew, value); - - //Update CuryHistory in Voucher currency - tran.CuryDebitAmt = (adj.AdjgGLSign == 1m) ? adj.CuryAdjdWOAmt : 0m; - tran.CuryCreditAmt = (adj.AdjgGLSign == 1m) ? 0m : adj.CuryAdjdWOAmt; - UpdateHistory(tran, paymentCustomer, vouch_info); - } - } - - private void ProcessGOL(JournalEntry je, ARAdjust adj, ARPayment payment, Customer paymentCustomer, ARRegister adjustedInvoice, Currency paycury, Currency cury, CurrencyInfo new_info, CurrencyInfo vouch_info) - { - //Debit/Credit RGOL Account - if (cury.RealGainAcctID != null && cury.RealLossAcctID != null) - { - var tran = new GLTran(); - tran.SummPost = this.SummPost; - tran.BranchID = (adj.AdjdDocType == ARDocType.SmallCreditWO) ? adjustedInvoice.BranchID : adj.AdjdBranchID; - tran.AccountID = (adj.RGOLAmt > 0m && !(bool)adj.VoidAppl || adj.RGOLAmt < 0m && (bool)adj.VoidAppl) - ? cury.RealLossAcctID - : cury.RealGainAcctID; - tran.SubID = (adj.RGOLAmt > 0m && !(bool)adj.VoidAppl || adj.RGOLAmt < 0m && (bool)adj.VoidAppl) - ? GainLossSubAccountMaskAttribute.GetSubID(je, tran.BranchID, cury) - : GainLossSubAccountMaskAttribute.GetSubID(je, tran.BranchID, cury); - //SC has Payment AR Account in AdjdARAcct and WO Account in ARAccountID - tran.OrigAccountID = (adj.AdjdDocType == ARDocType.SmallCreditWO) ? adjustedInvoice.ARAccountID : adj.AdjdARAcct; - tran.OrigSubID = (adj.AdjdDocType == ARDocType.SmallCreditWO) ? adjustedInvoice.ARSubID : adj.AdjdARSub; - tran.CreditAmt = (adj.RGOLAmt < 0m) ? -1m * adj.RGOLAmt : 0m; - //!object.Equals(vouch_info.CuryID, vouch_info.BaseCuryID) === precision alteration before payment application - tran.CuryCreditAmt = object.Equals(new_info.CuryID, new_info.BaseCuryID) && !object.Equals(vouch_info.CuryID, vouch_info.BaseCuryID) ? tran.CreditAmt : 0m; - tran.DebitAmt = (adj.RGOLAmt > 0m) ? adj.RGOLAmt : 0m; - tran.CuryDebitAmt = object.Equals(new_info.CuryID, new_info.BaseCuryID) && !object.Equals(vouch_info.CuryID, vouch_info.BaseCuryID) ? tran.DebitAmt : 0m; - tran.TranType = adj.AdjgDocType; - tran.TranClass = GLTran.tranClass.RealizedAndRoundingGOL; - tran.RefNbr = adj.AdjgRefNbr; - tran.TranDesc = payment.DocDesc; - tran.TranDate = adj.AdjgDocDate; - tran.TranPeriodID = adj.AdjgTranPeriodID; - tran.FinPeriodID = adj.AdjgFinPeriodID; - tran.CuryInfoID = new_info.CuryInfoID; - tran.Released = true; - tran.ReferenceID = payment.CustomerID; - tran.ProjectID = PM.ProjectDefaultAttribute.NonProject(je); - - UpdateHistory(tran, paymentCustomer); - - je.GLTranModuleBatNbr.Insert(tran); - - //Update CuryHistory in Voucher currency - tran.CuryDebitAmt = 0m; - tran.CuryCreditAmt = 0m; - UpdateHistory(tran, paymentCustomer, vouch_info); - } - //Debit/Credit Rounding Gain-Loss Account - else if (paycury.RoundingGainAcctID != null && paycury.RoundingLossAcctID != null) - { - var tran = new GLTran(); - tran.SummPost = this.SummPost; - tran.BranchID = (adj.AdjdDocType == ARDocType.SmallCreditWO) ? adjustedInvoice.BranchID : adj.AdjdBranchID; - tran.AccountID = (adj.RGOLAmt > 0m && !(bool)adj.VoidAppl || adj.RGOLAmt < 0m && (bool)adj.VoidAppl) - ? paycury.RoundingLossAcctID - : paycury.RoundingGainAcctID; - tran.SubID = (adj.RGOLAmt > 0m && !(bool)adj.VoidAppl || adj.RGOLAmt < 0m && (bool)adj.VoidAppl) - ? GainLossSubAccountMaskAttribute.GetSubID(je, tran.BranchID, paycury) - : GainLossSubAccountMaskAttribute.GetSubID(je, tran.BranchID, paycury); - - //SC has Payment AR Account in AdjdARAcct and WO Account in ARAccountID - tran.OrigAccountID = (adj.AdjdDocType == ARDocType.SmallCreditWO) ? adjustedInvoice.ARAccountID : adj.AdjdARAcct; - tran.OrigSubID = (adj.AdjdDocType == ARDocType.SmallCreditWO) ? adjustedInvoice.ARSubID : adj.AdjdARSub; - tran.CreditAmt = (adj.RGOLAmt < 0m) ? -1m * adj.RGOLAmt : 0m; - //!object.Equals(vouch_info.CuryID, vouch_info.BaseCuryID) === precision alteration before payment application - tran.CuryCreditAmt = object.Equals(new_info.CuryID, new_info.BaseCuryID) && !object.Equals(vouch_info.CuryID, vouch_info.BaseCuryID) ? tran.CreditAmt : 0m; - tran.DebitAmt = (adj.RGOLAmt > 0m) ? adj.RGOLAmt : 0m; - tran.CuryDebitAmt = object.Equals(new_info.CuryID, new_info.BaseCuryID) && !object.Equals(vouch_info.CuryID, vouch_info.BaseCuryID) ? tran.DebitAmt : 0m; - tran.TranType = adj.AdjgDocType; - tran.TranClass = GLTran.tranClass.RealizedAndRoundingGOL; - tran.RefNbr = adj.AdjgRefNbr; - tran.TranDesc = payment.DocDesc; - tran.TranDate = adj.AdjgDocDate; - tran.TranPeriodID = adj.AdjgTranPeriodID; - tran.FinPeriodID = adj.AdjgFinPeriodID; - tran.CuryInfoID = new_info.CuryInfoID; - tran.Released = true; - tran.ReferenceID = payment.CustomerID; - tran.ProjectID = PM.ProjectDefaultAttribute.NonProject(je); - - UpdateHistory(tran, paymentCustomer); - - je.GLTranModuleBatNbr.Insert(tran); - - //Update CuryHistory in Voucher currency - tran.CuryDebitAmt = 0m; - tran.CuryCreditAmt = 0m; - UpdateHistory(tran, paymentCustomer, vouch_info); - } - } - - private void ProcessRounding( - JournalEntry je, - ARRegister doc, - ARAdjust prev_adj, - ARPayment ardoc, - Customer vend, - Currency paycury, - CurrencyInfo prev_info, - CurrencyInfo new_info, - decimal? amount, - bool? isReversed = false) - { - if (prev_adj.VoidAppl == true || Equals(new_info.CuryID, new_info.BaseCuryID)) - { - throw new PXException(Messages.UnexpectedRoundingForApplication); - } - - UpdateARBalances(this, doc, amount, 0m); - - //BaseCalc should be false - prev_adj.AdjAmt += amount; - decimal? roundingLoss = isReversed != true ? amount : -amount; - prev_adj.RGOLAmt -= roundingLoss; - prev_adj = (ARAdjust)Caches[typeof(ARAdjust)].Update(prev_adj); - - ARRegister adjdDoc = (ARRegister)ARDocument.Cache.Locate( - new ARRegister { DocType = prev_adj.AdjdDocType, RefNbr = prev_adj.AdjdRefNbr }); - if (adjdDoc != null) - { - adjdDoc.RGOLAmt -= roundingLoss; - ARDocument.Cache.Update(adjdDoc); - } - - //signs are reversed to RGOL - GLTran tran = new GLTran(); - tran.SummPost = SummPost; - tran.BranchID = ardoc.BranchID; - tran.AccountID = (roundingLoss < 0m) - ? paycury.RoundingLossAcctID - : paycury.RoundingGainAcctID; - tran.SubID = (roundingLoss < 0m) - ? GainLossSubAccountMaskAttribute.GetSubID(je, tran.BranchID, paycury) - : GainLossSubAccountMaskAttribute.GetSubID(je, tran.BranchID, paycury); - tran.OrigAccountID = prev_adj.AdjdARAcct; - tran.OrigSubID = prev_adj.AdjdARSub; - tran.CreditAmt = (roundingLoss > 0m) ? roundingLoss : 0m; - tran.CuryCreditAmt = 0m; - tran.DebitAmt = (roundingLoss < 0m) ? -roundingLoss : 0m; - tran.CuryDebitAmt = 0m; - tran.TranType = prev_adj.AdjgDocType; - tran.TranClass = "R"; - tran.RefNbr = prev_adj.AdjgRefNbr; - tran.TranDesc = ardoc.DocDesc; - tran.TranDate = prev_adj.AdjgDocDate; - tran.TranPeriodID = prev_adj.AdjgTranPeriodID; - tran.FinPeriodID = prev_adj.AdjgFinPeriodID; - tran.CuryInfoID = new_info.CuryInfoID; - tran.Released = true; - tran.ReferenceID = ardoc.CustomerID; - tran.ProjectID = ProjectDefaultAttribute.NonProject(je); - - UpdateHistory(tran, vend); - //Update CuryHistory in Voucher currency - UpdateHistory(tran, vend, prev_info); - - je.GLTranModuleBatNbr.Insert(tran); - - //Credit Payment AR Account - tran = new GLTran(); - tran.SummPost = true; - tran.ZeroPost = false; - tran.BranchID = ardoc.BranchID; - tran.AccountID = ardoc.ARAccountID; - tran.SubID = ardoc.ARSubID; - tran.ReclassificationProhibited = true; - tran.DebitAmt = (roundingLoss > 0m) ? roundingLoss : 0m; - tran.CuryDebitAmt = 0m; - tran.CreditAmt = (roundingLoss < 0m) ? -roundingLoss : 0m; - tran.CuryCreditAmt = 0m; - tran.TranType = prev_adj.AdjgDocType; - tran.TranClass = "P"; - tran.RefNbr = prev_adj.AdjgRefNbr; - tran.TranDesc = ardoc.DocDesc; - tran.TranDate = prev_adj.AdjgDocDate; - tran.TranPeriodID = prev_adj.AdjgTranPeriodID; - tran.FinPeriodID = prev_adj.AdjgFinPeriodID; - tran.CuryInfoID = new_info.CuryInfoID; - tran.Released = true; - tran.ReferenceID = ardoc.CustomerID; - tran.OrigAccountID = prev_adj.AdjdARAcct; - tran.OrigSubID = prev_adj.AdjdARSub; - tran.ProjectID = ProjectDefaultAttribute.NonProject(je); - - UpdateHistory(tran, vend); - //Update CuryHistory in Payment currency - UpdateHistory(tran, vend, new_info); - - je.GLTranModuleBatNbr.Insert(tran); - } - - public virtual void ReleaseSmallCreditProc(JournalEntry je, ref ARRegister doc, PXResult res) - { - ARInvoice ardoc = res; - CurrencyInfo info = res; - Customer vend = res; - CustomerClass custclass = PXSelectJoin>>>.Select(this, null); - - CurrencyInfo new_info = PXCache.CreateCopy(info); - new_info.CuryInfoID = null; - new_info.ModuleCode = "GL"; - new_info = je.currencyinfo.Insert(new_info) ?? new_info; - - if (doc.Released == false) - { - doc.CuryDocBal = doc.CuryOrigDocAmt; - doc.DocBal = doc.OrigDocAmt; - - doc.OpenDoc = true; - doc.ClosedFinPeriodID = null; - doc.ClosedTranPeriodID = null; - } - - doc.Released = true; - decimal? docRGOLAmt = doc.RGOLAmt; - ARAdjust prev_adj = new ARAdjust(); - - foreach (PXResult adjres in ARAdjust_AdjdDocType_RefNbr_CustomerID - .Select(doc.DocType, doc.RefNbr, doc.AdjCntr)) - { - ARAdjust adj = adjres; - CurrencyInfo vouch_info = adjres; - Currency cury = adjres; - ARPayment adjddoc = adjres; - - EnsureNoUnreleasedVoidPaymentExists(this, adjddoc, Common.Messages.ActionWrittenOff); - - /// For correct balance calculation, - /// application RGOL amount should be equal to zero. - /// - decimal? adjRGOLAmt = adj.RGOLAmt; - adj.RGOLAmt = 0m; - - UpdateBalances(adj, adjddoc); - UpdateARBalances(adj, doc); - UpdateARBalances(adj, adjddoc); - - /// Credit WO Account - /// - GLTran tran = new GLTran(); - tran.SummPost = true; - tran.BranchID = ardoc.BranchID; - tran.AccountID = ardoc.ARAccountID; - tran.ReclassificationProhibited = true; - tran.SubID = ardoc.ARSubID; - tran.DebitAmt = (ardoc.DrCr == DrCr.Debit) ? adj.AdjAmt : 0m; - tran.CuryDebitAmt = (ardoc.DrCr == DrCr.Debit) ? adj.CuryAdjgAmt : 0m; - tran.CreditAmt = (ardoc.DrCr == DrCr.Debit) ? 0m : adj.AdjAmt; - tran.CuryCreditAmt = (ardoc.DrCr == DrCr.Debit) ? 0m : adj.CuryAdjgAmt; - tran.TranType = adj.AdjdDocType; - tran.TranClass = GLTran.tranClass.Payment; - tran.RefNbr = adj.AdjdRefNbr; - tran.TranDesc = ardoc.DocDesc; - tran.TranDate = adj.AdjdDocDate; - tran.TranPeriodID = ardoc.TranPeriodID; - tran.FinPeriodID = ardoc.FinPeriodID; - tran.CuryInfoID = new_info.CuryInfoID; - tran.Released = true; - tran.ReferenceID = ardoc.CustomerID; - tran.OrigAccountID = adjddoc.ARAccountID; - tran.OrigSubID = adjddoc.ARSubID; - tran.ProjectID = PM.ProjectDefaultAttribute.NonProject(je); - - /// Create history for SCWO Account. - /// - UpdateHistory(tran, vend); - - je.GLTranModuleBatNbr.Insert(tran); - - tran.CuryDebitAmt = (ardoc.DrCr == DrCr.Debit) ? (object.Equals(vouch_info.CuryID, vouch_info.BaseCuryID) ? adj.AdjAmt : adj.CuryAdjdAmt) : 0m; - tran.CuryCreditAmt = (ardoc.DrCr == DrCr.Debit) ? 0m : (object.Equals(vouch_info.CuryID, vouch_info.BaseCuryID) ? adj.AdjAmt : adj.CuryAdjdAmt); - - UpdateHistory(tran, vend, vouch_info); - - /// Debit Payment AR Account. - /// - tran = new GLTran(); - tran.SummPost = true; - tran.BranchID = adjddoc.BranchID; - tran.AccountID = adjddoc.ARAccountID; - tran.ReclassificationProhibited = true; - tran.SubID = adjddoc.ARSubID; - tran.CreditAmt = (ardoc.DrCr == DrCr.Debit) ? adj.AdjAmt : 0m; - tran.CuryCreditAmt = (ardoc.DrCr == DrCr.Debit) ? (object.Equals(new_info.CuryID, new_info.BaseCuryID) ? adj.AdjAmt : adj.CuryAdjgAmt) : 0m; - tran.DebitAmt = (ardoc.DrCr == DrCr.Debit) ? 0m : adj.AdjAmt; - tran.CuryDebitAmt = (ardoc.DrCr == DrCr.Debit) ? 0m : (object.Equals(new_info.CuryID, new_info.BaseCuryID) ? adj.AdjAmt : adj.CuryAdjgAmt); - tran.TranType = adj.AdjdDocType; - tran.TranClass = GLTran.tranClass.Normal; - tran.RefNbr = adj.AdjdRefNbr; - tran.TranDesc = ardoc.DocDesc; - tran.TranDate = adj.AdjdDocDate; - tran.TranPeriodID = ardoc.TranPeriodID; - tran.FinPeriodID = ardoc.FinPeriodID; - tran.CuryInfoID = new_info.CuryInfoID; - tran.Released = true; - tran.ReferenceID = ardoc.CustomerID; - tran.ProjectID = PM.ProjectDefaultAttribute.NonProject(je); - - UpdateHistory(tran, vend); - ARHistBucket bucket = null; - bool isPrepayment = adj.AdjgDocType == ARDocType.Prepayment && adj.AdjdDocType == ARDocType.SmallCreditWO; - if (isPrepayment) - { - bucket = new ARHistBucket(); - bucket.arAccountID = tran.AccountID; - bucket.arSubID = tran.SubID; - bucket.SignPayments = 1m; - bucket.SignDeposits = -1m; - bucket.SignPtd = -1m; - - UpdateHistory(tran, vend, bucket); - } - - je.GLTranModuleBatNbr.Insert(tran); - - /// Update CuryHistory in Voucher currency. - /// - tran.CuryCreditAmt = (ardoc.DrCr == DrCr.Debit) ? (object.Equals(vouch_info.CuryID, vouch_info.BaseCuryID) ? adj.AdjAmt : adj.CuryAdjdAmt) : 0m; - tran.CuryDebitAmt = (ardoc.DrCr == DrCr.Debit) ? 0m : (object.Equals(vouch_info.CuryID, vouch_info.BaseCuryID) ? adj.AdjAmt : adj.CuryAdjdAmt); - UpdateHistory(tran, vend, vouch_info); - if (isPrepayment) - { - UpdateHistory(tran, vend, vouch_info, bucket); - } - - /// No Discount should take place. - /// No RGOL should take place. - /// - doc.CuryDocBal -= adj.CuryAdjgAmt; - doc.DocBal -= adj.AdjAmt; - - if (je.GLTranModuleBatNbr.Cache.IsInsertedUpdatedDeleted) - { - je.Save.Press(); - } - - if (!je.BatchModule.Cache.IsDirty) - { - adj.AdjBatchNbr = ((Batch)je.BatchModule.Current).BatchNbr; - } - - adj.Released = true; - adj.RGOLAmt = adjRGOLAmt; - prev_adj = (ARAdjust)Caches[typeof(ARAdjust)].Update(adj); - - if (!_IsIntegrityCheck && adjRGOLAmt != 0m) - { - prev_adj.RGOLAmt = 0m; - ProcessRounding(je, doc, prev_adj, adjddoc, vend, cury, vouch_info, new_info, adjRGOLAmt); - } - } - - /// In cases when the SmallCreditWO document has RGOL amount, we should decrease it DocBal - /// to this value (which is sum of RGOL amounts for applications), - /// because RGOL amount for it applications is excluded from DocBal calculation. - /// - if (doc.CuryDocBal == 0m && doc.DocBal - docRGOLAmt != 0m) - { - throw new PXException(Messages.DocumentBalanceNegative); - } - - if ((bool)doc.OpenDoc == false || doc.CuryDocBal == 0m) - { - doc.CuryDocBal = 0m; - doc.DocBal = 0m; - doc.OpenDoc = false; - - doc.ClosedFinPeriodID = doc.FinPeriodID; - doc.ClosedTranPeriodID = doc.TranPeriodID; - } - - /// Increment default for AdjNbr. - /// - doc.AdjCntr++; - } - - private void SegregateBatch(JournalEntry je, int? branchID, string curyID, DateTime? docDate, string finPeriodID, string description, CurrencyInfo curyInfo) - { - JournalEntry.SegregateBatch(je, BatchModule.AR, branchID, curyID, docDate, finPeriodID, description, curyInfo, null); - } - - public virtual List ReleaseDocProc(JournalEntry je, ARRegister ardoc, List pmBatchList) - { - return ReleaseDocProc(je, ardoc, pmBatchList, null); - } - - public virtual List ReleaseDocProc(JournalEntry je, ARRegister ardoc, List pmBatchList, ARDocumentRelease.ARMassProcessReleaseTransactionScopeDelegate onreleasecomplete) - { - List ret = null; - - if ((bool)ardoc.Hold) - { - throw new PXException(Messages.Document_OnHold_CannotRelease); - } - - // Finding some known data inconsistency problems, - // if any, the process will be stopped. - // - if (_IsIntegrityCheck != true) - { - new DataIntegrityValidator( - je, ARDocument.Cache, ardoc, BatchModule.AR, ardoc.CustomerID, ardoc.Released, arsetup.DataInconsistencyHandlingMode) - .CheckTransactionsExistenceForUnreleasedDocument() - .Commit(); - } - - ARPayment pmt = PXSelect>, - And>>>>.Select(je, ardoc.DocType, ardoc.RefNbr); - if (pmt != null && pmt.DocType != ARDocType.CreditMemo && pmt.DocType != ARDocType.SmallBalanceWO && arsetup.RequireExtRef == true && string.IsNullOrEmpty(pmt.ExtRefNbr)) - { - throw new PXException(ErrorMessages.FieldIsEmpty, PXUIFieldAttribute.GetDisplayName(je.Caches[typeof(ARPayment)])); - } - - ARRegister doc = PXCache.CreateCopy(ardoc); - - //using (new PXConnectionScope()) - { - using (PXTransactionScope ts = new PXTransactionScope()) - { - //mark as updated so that doc will not expire from cache and update with Released = 1 will not override balances/amount in document - ARDocument.Cache.SetStatus(doc, PXEntryStatus.Updated); - - UpdateARBalances(doc, -doc.OrigDocAmt); - - bool Released = (bool)doc.Released; - List pmDocList = new List(); - - foreach (PXResult res in ARInvoice_DocType_RefNbr.Select((object)doc.DocType, doc.RefNbr)) - { - Customer c = res; - switch (c.Status) - { - case Customer.status.Inactive: - case Customer.status.Hold: - case Customer.status.CreditHold: - throw new PXSetPropertyException(Messages.CustomerIsInStatus, new Customer.status.ListAttribute().ValueLabelDic[c.Status]); - } - - PM.PMRegister pmDoc = null; - ARInvoice invoice = res; - - //must check for CM application in different period - if (doc.Released == false) - { - SegregateBatch(je, doc.BranchID, doc.CuryID, doc.DocDate, doc.FinPeriodID, doc.DocDesc, (CurrencyInfo)res); - } - if (doc.DocType == ARDocType.SmallCreditWO) - { - ReleaseSmallCreditProc(je, ref doc, res); - } - else if (_IsIntegrityCheck == false && invoice.DocType != ARDocType.CashSale && invoice.DocType != ARDocType.CashReturn && ((Customer)res).AutoApplyPayments == true && invoice.Released == false) - { - bool isCCCaptured = false; - if (invoice.OrigModule == BatchModule.SO) - { - SOInvoice soinvoice = PXSelect>, And>>>>.Select(this, invoice.DocType, invoice.RefNbr); - isCCCaptured = soinvoice != null && soinvoice.IsCCCaptured == true; - } - - if (!isCCCaptured) - { - ie.Clear(); - ie.Document.Current = invoice; - - if (ie.Adjustments_Inv.View.SelectSingle() == null) - { - ie.LoadInvoicesProc(); - } - ie.Save.Press(); - doc = (ARRegister)ie.Document.Current; - ret = ReleaseDocProc(je, ref doc, new PXResult(ie.Document.Current, (CurrencyInfo)res, (Terms)res, (Customer)res, (Account)res), out pmDoc); - } - } - else - { - ret = ReleaseDocProc(je, ref doc, res, out pmDoc); - } - //ensure correct PXDBDefault behaviour on ARTran persisting - ARInvoice_DocType_RefNbr.Current = (ARInvoice)res; - if (pmDoc != null) - pmDocList.Add(pmDoc); - } - - foreach (PXResult res in ARPayment_DocType_RefNbr.Select((object)doc.DocType, doc.RefNbr, doc.CustomerID)) - { - Customer c = res; - if (c.Status == Customer.status.Inactive) - { - throw new PXSetPropertyException(Messages.CustomerIsInStatus, - new Customer.status.ListAttribute().ValueLabelDic[c.Status]); - } - - ARPayment payment = res; - if ((doc.DocType == ARDocType.Payment || doc.DocType == ARDocType.VoidPayment || doc.DocType == ARDocType.Refund) && doc.Released == false) - { - SegregateBatch(je, doc.BranchID, doc.CuryID, ((ARPayment)res).DocDate, ((ARPayment)res).FinPeriodID, doc.DocDesc, (CurrencyInfo)res); - - if (_IsIntegrityCheck == false && ((Customer)res).AutoApplyPayments == true && payment.DocType == ARDocType.Payment && payment.Released == false) - { - pe.Clear(); - bool anyAdj = false; - if (PXTransactionScope.IsScoped) - { - //It's required to select curyInfo as it may be not committed to the database yet. - //So it cannot be selected through RowSelecting for the balance calculation if it is not in the database. - //(as RowSelecting have it's own connection scope) - pe.CurrencyInfo_CuryInfoID.Select(payment.CuryInfoID); - foreach (ARAdjust adj in pe.Adjustments_Raw.Select(payment.DocType, payment.RefNbr, payment.AdjCntr)) - { - if (!anyAdj) - { - anyAdj = true; - pe.CurrencyInfo_CuryInfoID.View.Clear(); - } - pe.CurrencyInfo_CuryInfoID.Select(adj.AdjdCuryInfoID); - } - pe.CurrencyInfo_CuryInfoID.Select(payment.CuryInfoID); - } - else - { - anyAdj = (pe.Adjustments_Raw.View.SelectSingle() != null); - } - pe.Document.Current = payment; - if (!anyAdj) - { - pe.LoadInvoicesProc(false); - } - pe.Save.Press(); - doc = pe.Document.Current; - ReleaseDocProc(je, ref doc, new PXResult(pe.Document.Current, (CurrencyInfo)res, (Currency)res, (Customer)res, (CashAccount)res), -1); - } - else - { - ReleaseDocProc(je, ref doc, res, -1); - } - - if (je.GLTranModuleBatNbr.Cache.IsInsertedUpdatedDeleted) - { - je.Save.Press(); - } - - if (!je.BatchModule.Cache.IsDirty && string.IsNullOrEmpty(doc.BatchNbr)) - { - doc.BatchNbr = je.BatchModule.Current.BatchNbr; - } - - Dictionary>> appsbyperiod = new Dictionary>>(); - Dictionary datesbyperiod = new Dictionary(); - - foreach (PXResult adjres in ARAdjust_AdjgDocType_RefNbr_CustomerID.Select(doc.DocType, doc.RefNbr, doc.AdjCntr)) - { - ARAdjust adj = (ARAdjust)adjres; - SetAdjgPeriodsFromLatestApplication(doc, adj); - - List> apps; - if (!appsbyperiod.TryGetValue(adj.AdjgFinPeriodID, out apps)) - { - appsbyperiod[adj.AdjgFinPeriodID] = apps = new List>(); - } - apps.Add(adjres); - - DateTime? maxdate; - if (!datesbyperiod.TryGetValue(adj.AdjgFinPeriodID, out maxdate)) - { - datesbyperiod[adj.AdjgFinPeriodID] = maxdate = adj.AdjgDocDate; - } - - if (DateTime.Compare((DateTime)adj.AdjgDocDate, (DateTime)maxdate) > 0) - { - datesbyperiod[adj.AdjgFinPeriodID] = adj.AdjgDocDate; - } - - if (doc.OpenDoc == false) - { - //this is true for VoidCheck - doc.OpenDoc = true; - doc.CuryDocBal = doc.CuryOrigDocAmt; - doc.DocBal = doc.OrigDocAmt; - } - } - - Batch paymentBatch = je.BatchModule.Current; - - int i = -2; - try - { - foreach (KeyValuePair>> pair in appsbyperiod) - { - JournalEntry.SegregateBatch(je, BatchModule.AR, doc.BranchID, doc.CuryID, datesbyperiod[pair.Key], pair.Key, - doc.DocDesc, (CurrencyInfo)res, paymentBatch); - - ARAdjustsToRelease = new PXResultset(); - ARAdjustsToRelease.AddRange(pair.Value); - - //parameter "i" is irrelevant, it has been left for backward compatibility - ReleaseDocProc(je, ref doc, res, i); - - i--; - } - } - finally - { - ARAdjustsToRelease = null; - } - - //increment default for AdjNbr - doc.AdjCntr++; - } - else - { - if (doc.DocType != ARDocType.CashSale && doc.DocType != ARDocType.CashReturn) - { - SegregateBatch(je, doc.BranchID, doc.CuryID, payment.AdjDate, payment.AdjFinPeriodID, payment.DocDesc, (CurrencyInfo)res); - } - ReleaseDocProc(je, ref doc, res); - } - //ensure correct PXDBDefault behaviour on ARAdjust persisting - ARPayment_DocType_RefNbr.Current = (ARPayment)res; - } - if (doc.DocType == ARDocType.VoidPayment) - { - //create deposit rgol reverse batch - ARPayment voidPayment = PXSelect, And>>>>.Select(je, doc.RefNbr); - ARPayment origPayment = PXSelect, And>>>>.Select(je, doc.RefNbr); - if (origPayment != null && origPayment.Deposited == true) - { - CADeposit deposit = PXSelect>>>.Select(je, origPayment.DepositNbr); - if (deposit != null) - { - CADepositDetail detail = PXSelect>, - And>, - And>>>>.Select(je, deposit.RefNbr, origPayment.RefNbr); - if (detail != null) - { - decimal rgol = Math.Round((detail.OrigAmtSigned.Value - detail.TranAmt.Value), 3); - if (rgol != Decimal.Zero) - { - if (deposit.CashAccountID == voidPayment.CashAccountID) - { - CashAccount depositCashacct = PXSelect>>>.Select(je, deposit.CashAccountID); - GLTran rgol_tran = new GLTran(); - rgol_tran.DebitAmt = Decimal.Zero; - rgol_tran.CreditAmt = Decimal.Zero; - rgol_tran.AccountID = depositCashacct.AccountID; - rgol_tran.SubID = depositCashacct.SubID; - rgol_tran.BranchID = depositCashacct.BranchID; - rgol_tran.TranDate = doc.DocDate; - rgol_tran.FinPeriodID = doc.FinPeriodID; - rgol_tran.TranPeriodID = doc.TranPeriodID; - rgol_tran.TranType = CATranType.CATransferRGOL; - rgol_tran.RefNbr = doc.RefNbr; - rgol_tran.TranDesc = Messages.ReversingRGOLTanDescription; - rgol_tran.Released = true; - rgol_tran.CuryInfoID = doc.CuryInfoID; - - - rgol_tran.DebitAmt += ((origPayment.DrCr == CADrCr.CACredit) == rgol > 0 ? Decimal.Zero : Math.Abs(rgol)); - rgol_tran.CreditAmt += ((origPayment.DrCr == CADrCr.CACredit) == rgol > 0 ? Math.Abs(rgol) : Decimal.Zero); - - Currency rgol_cury = PXSelect>>>.Select(je, deposit.CuryID); - - decimal rgolAmt = (decimal)(rgol_tran.DebitAmt - rgol_tran.CreditAmt); - int sign = Math.Sign(rgolAmt); - rgolAmt = Math.Abs(rgolAmt); - - if ((rgolAmt) != Decimal.Zero) - { - GLTran tran = (GLTran)je.Caches[typeof(GLTran)].CreateCopy(rgol_tran); - tran.CuryDebitAmt = Decimal.Zero; - tran.CuryCreditAmt = Decimal.Zero; - if (doc.DocType == CATranType.CADeposit) - { - tran.AccountID = (sign < 0) ? rgol_cury.RealLossAcctID : rgol_cury.RealGainAcctID; - tran.SubID = (sign < 0) - ? GainLossSubAccountMaskAttribute.GetSubID(je, rgol_tran.BranchID, rgol_cury) - : GainLossSubAccountMaskAttribute.GetSubID(je, rgol_tran.BranchID, rgol_cury); - } - else - { - tran.AccountID = (sign < 0) ? rgol_cury.RealGainAcctID : rgol_cury.RealLossAcctID; - tran.SubID = (sign < 0) - ? GainLossSubAccountMaskAttribute.GetSubID(je, rgol_tran.BranchID, rgol_cury) - : GainLossSubAccountMaskAttribute.GetSubID(je, rgol_tran.BranchID, rgol_cury); - } - - tran.DebitAmt = sign < 0 ? rgolAmt : Decimal.Zero; - tran.CreditAmt = sign < 0 ? Decimal.Zero : rgolAmt; - tran.TranType = CATranType.CATransferRGOL; - tran.RefNbr = doc.RefNbr; - tran.TranDesc = Messages.ReversingRGOLTanDescription; - tran.TranDate = rgol_tran.TranDate; - tran.FinPeriodID = rgol_tran.FinPeriodID; - tran.TranPeriodID = rgol_tran.TranPeriodID; - tran.Released = true; - tran.CuryInfoID = origPayment.CuryInfoID; - tran = je.GLTranModuleBatNbr.Insert(tran); - - rgol_tran.CuryDebitAmt = Decimal.Zero; - rgol_tran.DebitAmt = (sign > 0) ? rgolAmt : Decimal.Zero; - rgol_tran.CreditAmt = (sign > 0) ? Decimal.Zero : rgolAmt; - je.GLTranModuleBatNbr.Insert(rgol_tran); - } - } - } - } - } - } - } - doc.Released = true; - //when doc is loaded in ARInvoiceEntry, ARPaymentEntry it will set Selected = 0 and document will dissappear from - //list of processing items. - doc.Selected = true; - - UpdateARBalances(doc); - - if (_IsIntegrityCheck == false) - { - if (je.GLTranModuleBatNbr.Cache.IsInsertedUpdatedDeleted) - { - je.Save.Press(); - } - - if (!je.BatchModule.Cache.IsDirty && string.IsNullOrEmpty(doc.BatchNbr)) - { - doc.BatchNbr = ((Batch)je.BatchModule.Current).BatchNbr; - } - } - - #region Auto Commit/Post document to avalara. - - ARInvoice arInvoice = PXSelect>, And>>>>.Select(this, doc.DocType, doc.RefNbr); - if (arInvoice != null && AvalaraMaint.IsExternalTax(this, arInvoice.TaxZoneID) && doc.IsTaxValid == true && arInvoice.InstallmentNbr == null) - { - TXAvalaraSetup avalaraSetup = PXSelect.Select(this); - if (avalaraSetup != null) - { - TaxSvc service = new TaxSvc(); - AvalaraMaint.SetupService(this, service); - - CommitTaxRequest request = new CommitTaxRequest(); - request.CompanyCode = AvalaraMaint.CompanyCodeFromBranch(this, doc.BranchID); - request.DocCode = string.Format("AR.{0}.{1}", doc.DocType, doc.RefNbr); - - if (doc.DocType == ARDocType.CreditMemo) - request.DocType = DocumentType.ReturnInvoice; - else - request.DocType = DocumentType.SalesInvoice; - - - CommitTaxResult result = service.CommitTax(request); - if (result.ResultCode == SeverityLevel.Success) - { - doc.IsTaxPosted = true; - } - else - { - //Avalara retuned an error - The given document is already marked as posted on the avalara side. - if (result.ResultCode == SeverityLevel.Error && result.Messages.Count == 1 && - result.Messages[0].Details == "Expected Posted") - { - //ignore this error - everything is cool - } - else - { - //show as warning. - StringBuilder sb = new StringBuilder(); - foreach (Avalara.AvaTax.Adapter.Message msg in result.Messages) - { - sb.AppendLine(msg.Name + ": " + msg.Details); - } - - if (sb.Length > 0) - { - ardoc.WarningMessage = PXMessages.LocalizeFormatNoPrefixNLA(Messages.PostingToAvalaraFailed, sb.ToString()); - } - } - } - } - } - #endregion - - doc = (ARRegister)ARDocument.Cache.Update(doc); - - PXCache.RestoreCopy(ardoc, doc); - - PXTimeStampScope.DuplicatePersisted(ARDocument.Cache, doc, typeof(ARInvoice)); - PXTimeStampScope.DuplicatePersisted(ARDocument.Cache, doc, typeof(ARPayment)); - - if (doc.DocType == ARDocType.CreditMemo) - { - if (Released) - { - ARPayment_DocType_RefNbr.Cache.SetStatus(ARPayment_DocType_RefNbr.Current, PXEntryStatus.Notchanged); - } - else - { - ARPayment crmemo = (ARPayment)ARPayment_DocType_RefNbr.Cache.Extend(doc); - crmemo.CreatedByID = doc.CreatedByID; - crmemo.CreatedByScreenID = doc.CreatedByScreenID; - crmemo.CreatedDateTime = doc.CreatedDateTime; - crmemo.CashAccountID = null; - crmemo.AdjDate = crmemo.DocDate; - crmemo.AdjTranPeriodID = crmemo.TranPeriodID; - crmemo.AdjFinPeriodID = crmemo.FinPeriodID; - ARPayment_DocType_RefNbr.Cache.Update(crmemo); - ARDocument.Cache.SetStatus(doc, PXEntryStatus.Notchanged); - } - } - else - { - if (ARDocument.Cache.ObjectsEqual(doc, ARPayment_DocType_RefNbr.Current)) - { - ARPayment_DocType_RefNbr.Cache.SetStatus(ARPayment_DocType_RefNbr.Current, PXEntryStatus.Notchanged); - } - } - - foreach (ARPayment item in ARPayment_DocType_RefNbr.Cache.Updated) - { - PXTimeStampScope.DuplicatePersisted(ARPayment_DocType_RefNbr.Cache, item, typeof(ARRegister)); - } - - List> batchList; - PM.RegisterRelease.ReleaseWithoutPost(pmDocList, false, out batchList); - foreach (ProcessInfo processInfo in batchList) - { - pmBatchList.AddRange(processInfo.Batches); - } - - this.Actions.PressSave(); - - // Finding some known data inconsistency problems, - // if any, the process will be stopped. - // - if (_IsIntegrityCheck != true) - { - // We need this condition to prevent applications verification, - // until the ARPayment part will not be created. - // - bool isUnreleasedCreditMemo = doc.DocType == ARDocType.CreditMemo && !Released; - - new DataIntegrityValidator( - je, ARDocument.Cache, doc, BatchModule.AR, doc.CustomerID, doc.Released, arsetup.DataInconsistencyHandlingMode) - .CheckTransactionsExistenceForUnreleasedDocument() - .CheckTransactionsExistenceForReleasedDocument() - .CheckBatchAndTransactionsSumsForDocument() - .CheckApplicationsReleasedForDocument(disableCheck: isUnreleasedCreditMemo) - .CheckDocumentHasNonNegativeBalance() - .CheckDocumentTotalsConformToCurrencyPrecision() - .Commit(); - } - - if (onreleasecomplete != null) - { - onreleasecomplete(ardoc); - } - - ts.Complete(this); - } - } - PXCache.RestoreCopy(ardoc, doc); - - if (ardoc is ARInvoice) - { - PXTimeStampScope.DuplicatePersisted(Caches[typeof(ARInvoice)], ardoc, typeof(ARRegister)); - } - if (ardoc is ARPayment) - { - PXTimeStampScope.DuplicatePersisted(Caches[typeof(ARPayment)], ardoc, typeof(ARRegister)); - } - - return ret; - } - - public override void Persist() - { - using (PXTransactionScope ts = new PXTransactionScope()) - { - ARPayment_DocType_RefNbr.Cache.Persist(PXDBOperation.Insert); - ARPayment_DocType_RefNbr.Cache.Persist(PXDBOperation.Update); - - ARDocument.Cache.Persist(PXDBOperation.Update); - ARTran_TranType_RefNbr.Cache.Persist(PXDBOperation.Insert); - ARTran_TranType_RefNbr.Cache.Persist(PXDBOperation.Update); - ARTaxTran_TranType_RefNbr.Cache.Persist(PXDBOperation.Update); - SVATConversionHistory.Cache.Persist(PXDBOperation.Insert); - SVATConversionHistory.Cache.Persist(PXDBOperation.Update); - intranselect.Cache.Persist(PXDBOperation.Update); - ARPaymentChargeTran_DocType_RefNbr.Cache.Persist(PXDBOperation.Update); - - ARAdjust_AdjgDocType_RefNbr_CustomerID.Cache.Persist(PXDBOperation.Insert); - ARAdjust_AdjgDocType_RefNbr_CustomerID.Cache.Persist(PXDBOperation.Update); - ARAdjust_AdjgDocType_RefNbr_CustomerID.Cache.Persist(PXDBOperation.Delete); - - ARDoc_SalesPerTrans.Cache.Persist(PXDBOperation.Insert); - ARDoc_SalesPerTrans.Cache.Persist(PXDBOperation.Update); - - Caches[typeof(ARHist)].Persist(PXDBOperation.Insert); - - Caches[typeof(CuryARHist)].Persist(PXDBOperation.Insert); - - Caches[typeof(ARBalances)].Persist(PXDBOperation.Insert); - - Caches[typeof(CADailySummary)].Persist(PXDBOperation.Insert); - - this.Caches[typeof(PMCommitment)].Persist(PXDBOperation.Insert); - this.Caches[typeof(PMCommitment)].Persist(PXDBOperation.Update); - this.Caches[typeof(PMCommitment)].Persist(PXDBOperation.Delete); - this.Caches[typeof(PMHistoryAccum)].Persist(PXDBOperation.Insert); - this.Caches[typeof(PMProjectStatusAccum)].Persist(PXDBOperation.Insert); - - ts.Complete(this); - } - - ARPayment_DocType_RefNbr.Cache.Persisted(false); - ARDocument.Cache.Persisted(false); - ARTran_TranType_RefNbr.Cache.Persisted(false); - ARTaxTran_TranType_RefNbr.Cache.Persisted(false); - intranselect.Cache.Persisted(false); - ARAdjust_AdjgDocType_RefNbr_CustomerID.Cache.Persisted(false); - - Caches[typeof(ARHist)].Persisted(false); - - Caches[typeof(CuryARHist)].Persisted(false); - - Caches[typeof(ARBalances)].Persisted(false); - - ARDoc_SalesPerTrans.Cache.Persisted(false); - - Caches[typeof(CADailySummary)].Persisted(false); - } - - protected bool _IsIntegrityCheck = false; - - protected virtual int SortCustDocs(PXResult a, PXResult b) - { - return ((IComparable)((ARRegister)a).SortOrder).CompareTo(((ARRegister)b).SortOrder); - } - - public virtual void IntegrityCheckProc(Customer cust, string startPeriod) - { - _IsIntegrityCheck = true; - JournalEntry je = PXGraph.CreateInstance(); - je.SetOffline(); - - Caches[typeof(Customer)].Current = cust; - - using (new PXConnectionScope()) - { - using (PXTransactionScope ts = new PXTransactionScope()) - { - string minPeriod = "190001"; - - ARHistory maxHist = (ARHistory)PXSelectGroupBy>, And>>, Aggregate>>.Select(this); - - if (maxHist != null && maxHist.FinPeriodID != null) - { - minPeriod = FinPeriodIDAttribute.PeriodPlusPeriod(this, maxHist.FinPeriodID, 1); - } - - if (string.IsNullOrEmpty(startPeriod) == false && string.Compare(startPeriod, minPeriod) > 0) - { - minPeriod = startPeriod; - } - - foreach (CuryARHist old_hist in PXSelectReadonly>, And>>>>.Select(this, cust.BAccountID, minPeriod)) - { - CuryARHist hist = new CuryARHist(); - hist.BranchID = old_hist.BranchID; - hist.AccountID = old_hist.AccountID; - hist.SubID = old_hist.SubID; - hist.CustomerID = old_hist.CustomerID; - hist.FinPeriodID = old_hist.FinPeriodID; - hist.CuryID = old_hist.CuryID; - - hist = (CuryARHist)Caches[typeof(CuryARHist)].Insert(hist); - - hist.FinPtdRevalued += old_hist.FinPtdRevalued; - - ARHist basehist = new ARHist(); - basehist.BranchID = old_hist.BranchID; - basehist.AccountID = old_hist.AccountID; - basehist.SubID = old_hist.SubID; - basehist.CustomerID = old_hist.CustomerID; - basehist.FinPeriodID = old_hist.FinPeriodID; - - basehist = (ARHist)Caches[typeof(ARHist)].Insert(basehist); - - basehist.FinPtdRevalued += old_hist.FinPtdRevalued; - } - - PXDatabase.Delete( - new PXDataFieldRestrict("CustomerID", PXDbType.Int, 4, cust.BAccountID, PXComp.EQ), - new PXDataFieldRestrict("FinPeriodID", PXDbType.Char, 6, minPeriod, PXComp.GE) - ); - - PXDatabase.Delete( - new PXDataFieldRestrict("CustomerID", PXDbType.Int, 4, cust.BAccountID, PXComp.EQ), - new PXDataFieldRestrict("FinPeriodID", PXDbType.Char, 6, minPeriod, PXComp.GE) - ); - - PXDatabase.Update( - new PXDataFieldAssign(0m), - new PXDataFieldAssign(0m), - new PXDataFieldAssign("CurrentBal", 0m), - new PXDataFieldAssign("OldInvoiceDate", null), - new PXDataFieldRestrict("CustomerID", PXDbType.Int, 4, cust.BAccountID, PXComp.EQ) - ); - - PXRowInserting ARHist_RowInserting = delegate (PXCache sender, PXRowInsertingEventArgs e) - { - if (string.Compare(((ARHist)e.Row).FinPeriodID, minPeriod) < 0) - { - e.Cancel = true; - } - }; - - PXRowInserting CuryARHist_RowInserting = delegate (PXCache sender, PXRowInsertingEventArgs e) - { - if (string.Compare(((CuryARHist)e.Row).FinPeriodID, minPeriod) < 0) - { - e.Cancel = true; - } - }; - - this.RowInserting.AddHandler(ARHist_RowInserting); - this.RowInserting.AddHandler(CuryARHist_RowInserting); - - PXResultset custdocs = PXSelect>, And, And>, Or>>>>>>>.Select(this, minPeriod, minPeriod); - PXResultset other = PXSelectJoinGroupBy, - Or, And, - Or, And>>>>>, - And>>, - InnerJoin, - And>>>>, - Where>, - And2>, - Or>>>, - And, - And>, - And, - And>, Or>>>>>>>, - Aggregate>>>>>>>>>>>>>.Select(this, minPeriod, minPeriod, minPeriod, minPeriod); - - custdocs.AddRange(other); - custdocs.Sort(SortCustDocs); - - foreach (ARRegister custdoc in custdocs) - { - je.Clear(); - - ARRegister doc = custdoc; - - //mark as updated so that doc will not expire from cache and update with Released = 1 will not override balances/amount in document - ARDocument.Cache.SetStatus(doc, PXEntryStatus.Updated); - - doc.Released = false; - - foreach (PXResult res in ARInvoice_DocType_RefNbr.Select((object)doc.DocType, doc.RefNbr)) - { - //must check for CM application in different period - if ((bool)doc.Released == false) - { - SegregateBatch(je, doc.BranchID, doc.CuryID, doc.DocDate, doc.FinPeriodID, doc.DocDesc, (CurrencyInfo)res); - } - if (doc.DocType == ARDocType.SmallCreditWO) - { - doc.AdjCntr = -1; - ReleaseSmallCreditProc(je, ref doc, res); - } - else - { - PM.PMRegister pmDoc; - ReleaseDocProc(je, ref doc, res, out pmDoc); - } - doc.Released = true; - } - - foreach (PXResult res in ARPayment_DocType_RefNbr.Select((object)doc.DocType, doc.RefNbr, doc.CustomerID)) - { - ARPayment payment = (ARPayment)res; - SegregateBatch(je, doc.BranchID, doc.CuryID, payment.AdjDate, payment.AdjFinPeriodID, payment.DocDesc, (CurrencyInfo)res); - - int OrigAdjCntr = (int)doc.AdjCntr; - doc.AdjCntr = 0; - - while (doc.AdjCntr < OrigAdjCntr) - { - ReleaseDocProc(je, ref doc, res); - doc.Released = true; - } - ARAdjust reversal = ARAdjust_AdjgDocType_RefNbr_CustomerID.Select(doc.DocType, doc.RefNbr, OrigAdjCntr); - if (reversal != null) - { - doc.OpenDoc = true; - } - } - - ARDocument.Cache.Update(doc); - } - - foreach (ARRegister custdoc in custdocs) - { - je.Clear(); - - ARRegister doc = custdoc; - ARDocument.Cache.SetStatus(doc, PXEntryStatus.Updated); - - foreach (PXResult res in ARInvoice_DocType_RefNbr.Select((object)doc.DocType, doc.RefNbr)) - { - ARInvoice invoice = res; - - SegregateBatch(je, doc.BranchID, doc.CuryID, doc.DocDate, doc.FinPeriodID, doc.DocDesc, (CurrencyInfo)res); - - var adjustments = PXSelectJoin>, - InnerJoin>, - LeftJoin, And>>, - LeftJoin, And>>>>>>, - Where>, - And>, - And>, - And>>>>>.Select(this, invoice.DocType, invoice.RefNbr, invoice.CustomerID); - - ProcessAdjustmentsOnlyAdjusted(je, adjustments); - } - - ARDocument.Cache.Update(doc); - } - - Caches[typeof(ARBalances)].Clear(); - - foreach (ARRegister ardoc in ARDocument.Cache.Updated) - { - ARDocument.Cache.PersistUpdated(ardoc); - } - - foreach (SOOrder order in PXSelectReadonly>, And, And>>>>.Select(this, cust.BAccountID)) - { - ARReleaseProcess.UpdateARBalances(this, order, order.UnbilledOrderTotal, order.OpenOrderTotal); - } - - foreach (ARRegister ardoc in PXSelectReadonly>, And, And>>>>.Select(this, cust.BAccountID)) - { - ARReleaseProcess.UpdateARBalances(this, ardoc, ardoc.DocBal); - UpdateARBalancesDates(ardoc); - } - - foreach (ARRegister ardoc in PXSelectReadonly>, And, And, And, And>>>>>>.Select(this, cust.BAccountID)) - { - ARReleaseProcess.UpdateARBalances(this, ardoc, ardoc.OrigDocAmt); - } - - foreach (ARInvoice ardoc in PXSelectReadonly>, And, And, And, And, And>>>>>>>.Select(this, cust.BAccountID)) - { - ardoc.CreditHold = false; - ARReleaseProcess.UpdateARBalances(this, ardoc, -ardoc.OrigDocAmt); - } - - this.RowInserting.RemoveHandler(ARHist_RowInserting); - this.RowInserting.RemoveHandler(CuryARHist_RowInserting); - - Caches[typeof(ARHist)].Persist(PXDBOperation.Insert); - - Caches[typeof(CuryARHist)].Persist(PXDBOperation.Insert); - - Caches[typeof(ARBalances)].Persist(PXDBOperation.Insert); - - ts.Complete(this); - } - - ARDocument.Cache.Persisted(false); - - Caches[typeof(ARHist)].Persisted(false); - - Caches[typeof(CuryARHist)].Persisted(false); - - Caches[typeof(ARBalances)].Persisted(false); - } - } - - protected static void Copy(ARSalesPerTran aDest, ARAdjust aAdj) - { - aDest.AdjdDocType = aAdj.AdjdDocType; - aDest.AdjdRefNbr = aAdj.AdjdRefNbr; - aDest.AdjNbr = aAdj.AdjNbr; - aDest.BranchID = aAdj.AdjdBranchID; - aDest.Released = true; - } - - protected static void Copy(ARSalesPerTran aDest, ARRegister aReg) - { - aDest.DocType = aReg.DocType; - aDest.RefNbr = aReg.RefNbr; - } - - protected static void CopyShare(ARSalesPerTran aDest, ARSalesPerTran aSrc, decimal aRatio, short aPrecision) - { - aDest.SalespersonID = aSrc.SalespersonID; - aDest.CuryInfoID = aSrc.CuryInfoID; //We will use currency Info of the orifginal invoice for the commission calculations - aDest.CommnPct = aSrc.CommnPct; - aDest.CuryCommnblAmt = Math.Round((decimal)(aRatio * aSrc.CuryCommnblAmt), aPrecision); - aDest.CuryCommnAmt = Math.Round((decimal)(aRatio * aSrc.CuryCommnAmt), aPrecision); - } - } -} - -namespace PX.Objects.AR.Overrides.ARDocumentRelease -{ - public interface IBaseARHist - { - Boolean? DetDeleted - { - get; - set; - } - - Boolean? FinFlag - { - get; - set; - } - Decimal? PtdCrAdjustments - { - get; - set; - } - Decimal? PtdDrAdjustments - { - get; - set; - } - Decimal? PtdSales - { - get; - set; - } - Decimal? PtdPayments - { - get; - set; - } - Decimal? PtdDiscounts - { - get; - set; - } - Decimal? YtdBalance - { - get; - set; - } - Decimal? BegBalance - { - get; - set; - } - Decimal? PtdCOGS - { - get; - set; - } - Decimal? PtdRGOL - { - get; - set; - } - Decimal? PtdFinCharges - { - get; - set; - } - Decimal? PtdDeposits - { - get; - set; - } - Decimal? YtdDeposits - { - get; - set; - } - Decimal? PtdItemDiscounts - { - get; - set; - } - } - - public interface ICuryARHist - { - Decimal? CuryPtdCrAdjustments - { - get; - set; - } - Decimal? CuryPtdDrAdjustments - { - get; - set; - } - Decimal? CuryPtdSales - { - get; - set; - } - Decimal? CuryPtdPayments - { - get; - set; - } - Decimal? CuryPtdDiscounts - { - get; - set; - } - Decimal? CuryPtdFinCharges - { - get; - set; - } - Decimal? CuryYtdBalance - { - get; - set; - } - Decimal? CuryBegBalance - { - get; - set; - } - Decimal? CuryPtdDeposits - { - get; - set; - } - Decimal? CuryYtdDeposits - { - get; - set; - } - } - - [PXAccumulator(new Type[] { - typeof(CuryARHistory.finYtdBalance), - typeof(CuryARHistory.tranYtdBalance), - typeof(CuryARHistory.curyFinYtdBalance), - typeof(CuryARHistory.curyTranYtdBalance), - typeof(CuryARHistory.finYtdBalance), - typeof(CuryARHistory.tranYtdBalance), - typeof(CuryARHistory.curyFinYtdBalance), - typeof(CuryARHistory.curyTranYtdBalance), - typeof(CuryARHistory.finYtdDeposits), - typeof(CuryARHistory.tranYtdDeposits), - typeof(CuryARHistory.curyFinYtdDeposits), - typeof(CuryARHistory.curyTranYtdDeposits) - }, - new Type[] { - typeof(CuryARHistory.finBegBalance), - typeof(CuryARHistory.tranBegBalance), - typeof(CuryARHistory.curyFinBegBalance), - typeof(CuryARHistory.curyTranBegBalance), - typeof(CuryARHistory.finYtdBalance), - typeof(CuryARHistory.tranYtdBalance), - typeof(CuryARHistory.curyFinYtdBalance), - typeof(CuryARHistory.curyTranYtdBalance), - typeof(CuryARHistory.finYtdDeposits), - typeof(CuryARHistory.tranYtdDeposits), - typeof(CuryARHistory.curyFinYtdDeposits), - typeof(CuryARHistory.curyTranYtdDeposits) - } - )] - [Serializable] - [PXHidden] - public partial class CuryARHist : CuryARHistory, ICuryARHist, IBaseARHist - { - #region BranchID - public new abstract class branchID : PX.Data.IBqlField - { - } - [PXDBInt(IsKey = true)] - public override Int32? BranchID - { - get - { - return this._BranchID; - } - set - { - this._BranchID = value; - } - } - #endregion - #region AccountID - public new abstract class accountID : PX.Data.IBqlField - { - } - [PXDBInt(IsKey = true)] - [PXDefault()] - public override Int32? AccountID - { - get - { - return this._AccountID; - } - set - { - this._AccountID = value; - } - } - #endregion - #region SubID - public new abstract class subID : PX.Data.IBqlField - { - } - [PXDBInt(IsKey = true)] - [PXDefault()] - public override Int32? SubID - { - get - { - return this._SubID; - } - set - { - this._SubID = value; - } - } - #endregion - #region CustomerID - public new abstract class customerID : PX.Data.IBqlField - { - } - [PXDBInt(IsKey = true)] - [PXDefault()] - public override Int32? CustomerID - { - get - { - return this._CustomerID; - } - set - { - this._CustomerID = value; - } - } - #endregion - #region CuryID - public new abstract class curyID : PX.Data.IBqlField - { - } - [PXDBString(5, IsUnicode = true, IsKey = true, InputMask = ">LLLLL")] - [PXDefault()] - public override String CuryID - { - get - { - return this._CuryID; - } - set - { - this._CuryID = value; - } - } - #endregion - #region FinPeriodID - public new abstract class finPeriodID : PX.Data.IBqlField - { - } - [PXDBString(6, IsKey = true, IsFixed = true)] - [PXDefault()] - public override String FinPeriodID - { - get - { - return this._FinPeriodID; - } - set - { - this._FinPeriodID = value; - } - } - #endregion - } - - [PXAccumulator(new Type[] { - typeof(ARHistory.finYtdBalance), - typeof(ARHistory.tranYtdBalance), - typeof(ARHistory.finYtdBalance), - typeof(ARHistory.tranYtdBalance), - typeof(ARHistory.finYtdDeposits), - typeof(ARHistory.tranYtdDeposits) - }, - new Type[] { - typeof(ARHistory.finBegBalance), - typeof(ARHistory.tranBegBalance), - typeof(ARHistory.finYtdBalance), - typeof(ARHistory.tranYtdBalance), - typeof(ARHistory.finYtdDeposits), - typeof(ARHistory.tranYtdDeposits) - } - )] - [Serializable] - [PXHidden] - public partial class ARHist : ARHistory, IBaseARHist - { - #region BranchID - public new abstract class branchID : IBqlField - { - } - [PXDBInt(IsKey = true)] - public override int? BranchID - { - get; - set; - } - #endregion - #region AccountID - public new abstract class accountID : IBqlField - { - } - [PXDBInt(IsKey = true)] - [PXDefault] - public override int? AccountID - { - get; - set; - } - #endregion - #region SubID - public new abstract class subID : IBqlField - { - } - [PXDBInt(IsKey = true)] - [PXDefault] - public override int? SubID - { - get; - set; - } - #endregion - #region CustomerID - public new abstract class customerID : IBqlField - { - } - [PXDBInt(IsKey = true)] - [PXDefault] - public override int? CustomerID - { - get; - set; - } - #endregion - #region FinPeriodID - public new abstract class finPeriodID : IBqlField - { - } - [PXDBString(6, IsKey = true, IsFixed = true)] - [PXDefault] - public override string FinPeriodID - { - get; - set; - } - #endregion - } - - public class ARBalAccumAttribute : PXAccumulatorAttribute - { - public ARBalAccumAttribute() - { - base._SingleRecord = true; - } - protected override bool PrepareInsert(PXCache sender, object row, PXAccumulatorCollection columns) - { - if (!base.PrepareInsert(sender, row, columns)) - { - return false; - } - - ARBalances bal = (ARBalances)row; - - columns.Update(bal.LastInvoiceDate, PXDataFieldAssign.AssignBehavior.Maximize); - columns.Update(bal.NumberInvoicePaid, PXDataFieldAssign.AssignBehavior.Summarize); - if (bal.DatesUpdated == true) - { - columns.Update(bal.OldInvoiceDate, PXDataFieldAssign.AssignBehavior.Replace); - columns.Restrict(PXComp.LE, bal.tstamp ?? sender.Graph.TimeStamp); - } - else - { - columns.Update(bal.OldInvoiceDate, PXDataFieldAssign.AssignBehavior.Minimize); - } - columns.Update(bal.PaidInvoiceDays, PXDataFieldAssign.AssignBehavior.Summarize); - columns.Update(bal.LastModifiedByID, PXDataFieldAssign.AssignBehavior.Replace); - columns.Update(bal.LastModifiedByScreenID, PXDataFieldAssign.AssignBehavior.Replace); - columns.Update(bal.LastModifiedDateTime, PXDataFieldAssign.AssignBehavior.Replace); - - return bal.LastInvoiceDate != null - || bal.NumberInvoicePaid != null - || bal.DatesUpdated == true - || bal.OldInvoiceDate != null - || bal.PaidInvoiceDays != null - || bal.CuryID != null - || bal.CurrentBal != 0m - || bal.UnreleasedBal != 0m - || bal.TotalOpenOrders != 0 - || bal.TotalPrepayments != 0 - || bal.TotalQuotations != 0 - || bal.TotalShipped != 0; - } - } -} \ No newline at end of file diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Test/PMAllocationProcess.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Test/PMAllocationProcess.cs deleted file mode 100644 index adaee8c9c..000000000 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Test/PMAllocationProcess.cs +++ /dev/null @@ -1,266 +0,0 @@ -using System; -using PX.Data; -using PX.Objects.AR; - -namespace PX.Objects.PM -{ - [GL.TableDashboardType] - public class AllocationProcess : PXGraph - { - [PXSelector(typeof(Search>>), DescriptionField = typeof(PMAllocation.description))] - [PXUIField(DisplayName = "Allocation Rule")] - [PXDBString(15, IsUnicode = true)] - protected virtual void PMTask_AllocationID_CacheAttached(PXCache sender) - { } - - [PXDBInt(IsKey = true)] - [PXUIField(DisplayName = "Project")] - [PXSelector(typeof(PMProject.contractID), SubstituteKey = typeof(PMProject.contractCD))] - protected virtual void PMTask_ProjectID_CacheAttached(PXCache sender) { } - - - public PXCancel Cancel; - public PXFilter Filter; - - public PXFilteredProcessingJoin>, - LeftJoin>>>, - Where, - And, - And, IsNull, Or>>>, - And2, IsNull, Or>>>, - And2, IsNull, Or>>>, - And2, IsNull, Or>>>, - And2, IsNull, Or>>>, - And>>>>>>>>>> Items; - - public PXSelect pmAllocation; - - public AllocationProcess() - { - Items.SetProcessCaption(PM.Messages.ProcAllocate); - Items.SetProcessAllCaption(PM.Messages.ProcAllocateAll); - } - - #region EventHandlers - protected virtual void AllocationFilter_RowUpdated(PXCache cache, PXRowUpdatedEventArgs e) - { - if (!cache.ObjectsEqual(e.Row, e.OldRow)) - Items.Cache.Clear(); - } - protected virtual void AllocationFilter_RowSelected(PXCache cache, PXRowSelectedEventArgs e) - { - AllocationFilter filter = Filter.Current; - - Items.SetProcessDelegate( - delegate (PMAllocator engine, PMTask item) - { - Run(engine, item, filter.Date, filter.DateFrom, filter.DateTo); - }); - } - #endregion - #region CacheAttached - [PXCustomizeBaseAttribute(typeof(PXUIFieldAttribute), nameof(PXUIFieldAttribute.DisplayName), "Allocation Rule Description")] - protected virtual void PMAllocation_Description_CacheAttached(PXCache sender) - { - } - #endregion - - private PMSetup setup; - - public bool AutoReleaseAllocation - { - get - { - if (setup == null) - { - setup = PXSelect.Select(this); - } - - return setup.AutoReleaseAllocation == true; - } - } - - public static void Run(PMAllocator graph, PMTask item, DateTime? date, DateTime? fromDate, DateTime? toDate) - { - graph.Clear(); - graph.OverrideAllocationDate = date; - graph.FilterStartDate = fromDate; - graph.FilterEndDate = toDate; - graph.Execute(item); - if (graph.Document.Current != null) - { - graph.Actions.PressSave(); - PMSetup setup = PXSelect.Select(graph); - PMRegister doc = graph.Caches[typeof(PMRegister)].Current as PMRegister; - if (doc != null && setup.AutoReleaseAllocation == true) - { - RegisterRelease.Release(doc); - } - } - else - { - throw new PXSetPropertyException(Warnings.NothingToAllocate, PXErrorLevel.RowWarning); - } - } - - [Serializable] - public partial class AllocationFilter : IBqlTable - { - #region Date - public abstract class date : PX.Data.IBqlField - { - } - protected DateTime? _Date; - [PXDBDate()] - [PXDefault(typeof(AccessInfo.businessDate))] - [PXUIField(DisplayName = "Posting Date", Visibility = PXUIVisibility.Visible, Required = true)] - public virtual DateTime? Date - { - get - { - return this._Date; - } - set - { - this._Date = value; - } - } - #endregion - #region AllocationID - public abstract class allocationID : PX.Data.IBqlField - { - } - protected String _AllocationID; - [PXSelector(typeof(PMAllocation.allocationID), DescriptionField = typeof(PMAllocation.description))] - [PXDBString(15, IsUnicode = true)] - [PXUIField(DisplayName = "Allocation Rule")] - public virtual String AllocationID - { - get - { - return this._AllocationID; - } - set - { - this._AllocationID = value; - } - } - #endregion - #region CustomerClassID - public abstract class customerClassID : PX.Data.IBqlField - { - } - protected String _CustomerClassID; - [PXDBString(10, IsUnicode = true)] - [PXSelector(typeof(CustomerClass.customerClassID), DescriptionField = typeof(CustomerClass.descr), CacheGlobal = true)] - [PXUIField(DisplayName = "Customer Class")] - public virtual String CustomerClassID - { - get - { - return this._CustomerClassID; - } - set - { - this._CustomerClassID = value; - } - } - #endregion - #region CustomerID - public abstract class customerID : PX.Data.IBqlField - { - } - protected Int32? _CustomerID; - [Customer()] - public virtual Int32? CustomerID - { - get - { - return this._CustomerID; - } - set - { - this._CustomerID = value; - } - } - #endregion - #region ProjectID - public abstract class projectID : PX.Data.IBqlField - { - } - protected Int32? _ProjectID; - [Project()] - public virtual Int32? ProjectID - { - get - { - return this._ProjectID; - } - set - { - this._ProjectID = value; - } - } - #endregion - #region TaskID - public abstract class taskID : PX.Data.IBqlField - { - } - protected Int32? _TaskID; - [ProjectTask(typeof(AllocationFilter.projectID))] - public virtual Int32? TaskID - { - get - { - return this._TaskID; - } - set - { - this._TaskID = value; - } - } - #endregion - #region DateFrom - public abstract class dateFrom : PX.Data.IBqlField - { - } - protected DateTime? _DateFrom; - [PXDBDate()] - [PXUIField(DisplayName = "From", Visibility = PXUIVisibility.Visible)] - public virtual DateTime? DateFrom - { - get - { - return this._DateFrom; - } - set - { - this._DateFrom = value; - } - } - #endregion - #region DateTo - public abstract class dateTo : PX.Data.IBqlField - { - } - protected DateTime? _DateTo; - [PXDBDate()] - [PXUIField(DisplayName = "To", Visibility = PXUIVisibility.Visible)] - public virtual DateTime? DateTo - { - get - { - return this._DateTo; - } - set - { - this._DateTo = value; - } - } - #endregion - } - } -} \ No newline at end of file diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Utils/RegExpressions.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Utils/RegExpressions.cs deleted file mode 100644 index 7ebfbbcc5..000000000 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Regex/Utils/RegExpressions.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -namespace Acuminator.Vsix.Coloriser -{ - public static class RegExpressions - { - private static readonly string[] _bqlSelectNames = new[] - { - "(PX)?Select(GroupBy)?(OrderBy)?", - @"Search\d?", - "PXSetup", - "PXUpdate", - @"PXSelectReadonly\d?", - "PXSelectGroupJoin", - "PXSelectJoin(OrderBy|GroupBy)?", - "PX(Filtered)?Processing(Join)?" - }; - - private static readonly string[] _bqlParameterNames = new[] - { - "Current2?", - "Optional2?", - "Required" - }; - - private const string DacWithFieldPattern = @"<\W*?([A-Z]+\w*\.)?([A-Z]+\w*)+\d?\.\W*([a-z]+\w*\d*)([>|,])?"; - private const string DacOrConstantPattern = @"<\W*?([A-Z]+\w*\.)?([A-Z]+\w*\d?)\W*(>|\,)"; - private const string DacOperandPattern = @"(,|<)?([A-Z]+\w*)\d?<"; - private const string BqlAllowedSymbols = @"[^;\{\}\(\)\[\]]"; - private const string AfterBqlAllowedSymbols = @"[^;\{\}\(\)\[\]]"; - private const string BqlEndingSymbol = @"(;|\{|\]|\[|\(|\))"; - - public static Regex DacWithFieldRegex { get; } = new Regex(DacWithFieldPattern, RegexOptions.Compiled); - - public static Regex DacOrConstantRegex { get; } = new Regex(DacOrConstantPattern, RegexOptions.Compiled); - - public static Regex DacOperandRegex { get; } = new Regex(DacOperandPattern, RegexOptions.Compiled); - - public static Regex BQLSelectCommandRegex { get; } - - public static Regex BQLParametersRegex { get; } - - static RegExpressions() - { - string bqlSelectCommandPattern = "(" + string.Join("|", _bqlSelectNames) + ")" + $"<{BqlAllowedSymbols}*>" + @"\.?" + - $"{AfterBqlAllowedSymbols}*?" + BqlEndingSymbol; - string bqlParametersPattern = "(" + string.Join("|", _bqlParameterNames) + ")"; - BQLSelectCommandRegex = new Regex(bqlSelectCommandPattern, RegexOptions.Compiled | RegexOptions.Singleline); - BQLParametersRegex = new Regex(bqlParametersPattern, RegexOptions.Compiled); - } - } -} From 6f45620322c059b519d659599842f469a2676f5c Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Tue, 12 May 2026 17:19:18 +0200 Subject: [PATCH 19/56] ATR-966: removed tagger type enum --- .../Coloriser/Base/PXTaggerBase.cs | 5 ---- .../Coloriser/Base/TaggerType.cs | 30 ------------------- .../Coloriser/Outlining/PXOutliningTagger.cs | 16 ++-------- .../Roslyn/PXRoslynColorizerTagger.cs | 2 -- 4 files changed, 2 insertions(+), 51 deletions(-) delete mode 100644 src/Acuminator/Acuminator.Vsix/Coloriser/Base/TaggerType.cs diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs index 9ea2a804d..47eb78d59 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs @@ -32,11 +32,6 @@ public abstract class PXTaggerBase : IDisposable public abstract bool HasReferenceToAcumaticaPlatform { get; } - /// - /// The type of the tagger. - /// - public abstract TaggerType TaggerType { get; } - protected bool CacheCheckingEnabled { get; } protected PXTaggerBase(ITextBuffer buffer, bool subscribeToSettingsChanges, bool useCacheChecking) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/TaggerType.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/TaggerType.cs deleted file mode 100644 index e63c44fe9..000000000 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/TaggerType.cs +++ /dev/null @@ -1,30 +0,0 @@ -#nullable enable - -namespace Acuminator.Vsix.Coloriser -{ - /// - /// Values that represent tagger types. - /// - public enum TaggerType - { - /// - /// The general tagger which chooses other taggers according to the settings. - /// - General, - - /// - /// The tagger based on Roslyn - /// - Roslyn, - - /// - /// The tagger based on regular expressions - /// - RegEx, - - /// - /// The tagger used for outlining - /// - Outlining - }; -} diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs index c19862397..18505e894 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs @@ -1,7 +1,7 @@ #nullable enable - using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Threading; @@ -17,8 +17,6 @@ public class PXOutliningTagger : PXTaggerBase, ITagger private const int NOT_SUBSCRIBED = 0; private const int SUBSCRIBED = 1; - public override TaggerType TaggerType => TaggerType.Outlining; - protected PXColorizerTaggerBase? ColorizerTagger { get; private set; } internal override bool LastTaggingWasSuccessful @@ -27,6 +25,7 @@ internal override bool LastTaggingWasSuccessful set { } } + [MemberNotNullWhen(returnValue: true, nameof(ColorizerTagger))] public override bool HasReferenceToAcumaticaPlatform => ColorizerTagger?.HasReferenceToAcumaticaPlatform ?? false; public PXOutliningTagger(ITextBuffer buffer, bool subscribeToSettingsChanges, bool useCacheChecking) : @@ -51,14 +50,6 @@ public IEnumerable> GetTags(NormalizedSnapshotSpan if (!HasReferenceToAcumaticaPlatform) return []; - switch (ColorizerTagger?.TaggerType) - { - case TaggerType.General when AcuminatorVSPackage.Instance?.UseRegexColoring == true: - case TaggerType.RegEx: - case null: - return []; - } - return ColorizerTagger.OutliningsTagsCache.ProcessedTags; } @@ -69,9 +60,6 @@ private static bool TryGetColorizingTaggerFromBuffer(ITextBuffer textBuffer, out private void SubscribeToColorizingTaggerEvents(PXColorizerTaggerBase colorizerTagger) { - if (colorizerTagger.TaggerType == TaggerType.RegEx) - return; - if (Interlocked.Exchange(ref _isSubscribed, SUBSCRIBED) == NOT_SUBSCRIBED) { ColorizerTagger = colorizerTagger; diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXRoslynColorizerTagger.cs index e00ac242b..df1d15007 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXRoslynColorizerTagger.cs @@ -17,8 +17,6 @@ public partial class PXRoslynColorizerTagger : PXColorizerTaggerBase { protected internal override bool UseAsyncTagging => true; - public override TaggerType TaggerType => TaggerType.Roslyn; - private readonly TagsCacheAsync _classificationTagsCache; protected internal override ITagsCache ClassificationTagsCache => _classificationTagsCache; From 5177969c7e5fbe3e477d10a0bbd02d59ab195258 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Tue, 12 May 2026 17:45:11 +0200 Subject: [PATCH 20/56] ATR-966: refactoring - formatted indentation --- .../Coloriser/AsyncTagging/TagsCacheAsync.cs | 99 +++++++++---------- 1 file changed, 49 insertions(+), 50 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/TagsCacheAsync.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/TagsCacheAsync.cs index dc8ba60fd..cedd89555 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/TagsCacheAsync.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/TagsCacheAsync.cs @@ -1,5 +1,4 @@ #nullable enable - using System; using System.Collections; using System.Collections.Concurrent; @@ -14,70 +13,70 @@ namespace Acuminator.Vsix.Coloriser { - public class TagsCacheAsync : ITagsCache - where TTag : ITag - { - protected CancellationToken CancellationToken { get; set; } + public class TagsCacheAsync : ITagsCache + where TTag : ITag + { + protected CancellationToken CancellationToken { get; set; } + + public bool IsCompleted { get; private set; } - public bool IsCompleted { get; private set; } + private readonly ConcurrentQueue> _tagsQueue = new ConcurrentQueue>(); - private readonly ConcurrentQueue> _tagsQueue = new ConcurrentQueue>(); + public IReadOnlyCollection> ProcessedTags => _tagsQueue; - public IReadOnlyCollection> ProcessedTags => _tagsQueue; - - public int Count => ProcessedTags.Count; + public int Count => ProcessedTags.Count; - public TagsCacheAsync() - { - CancellationToken = CancellationToken.None; - } + public TagsCacheAsync() + { + CancellationToken = CancellationToken.None; + } - internal void SetCancellation(CancellationToken cancellationToken) - { - CancellationToken = cancellationToken; - } + internal void SetCancellation(CancellationToken cancellationToken) + { + CancellationToken = cancellationToken; + } - public void CompleteProcessing() - { - if (CancellationToken.IsCancellationRequested) - return; + public void CompleteProcessing() + { + if (CancellationToken.IsCancellationRequested) + return; - IsCompleted = true; - } + IsCompleted = true; + } - public void Reset() - { - _tagsQueue.Clear(); + public void Reset() + { + _tagsQueue.Clear(); - IsCompleted = false; - } + IsCompleted = false; + } - public void AddTag(ITagSpan tag) - { - if (tag == null || CancellationToken.IsCancellationRequested) - return; + public void AddTag(ITagSpan tag) + { + if (tag == null || CancellationToken.IsCancellationRequested) + return; - _tagsQueue.Enqueue(tag); - } + _tagsQueue.Enqueue(tag); + } - public void AddTags(IEnumerable> tags) - { - List>? tagsCopy = tags?.ToList(); + public void AddTags(IEnumerable> tags) + { + List>? tagsCopy = tags?.ToList(); - if (tagsCopy.IsNullOrEmpty() || CancellationToken.IsCancellationRequested) - return; + if (tagsCopy.IsNullOrEmpty() || CancellationToken.IsCancellationRequested) + return; - foreach (ITagSpan tag in tagsCopy) - { - if (CancellationToken.IsCancellationRequested) - return; + foreach (ITagSpan tag in tagsCopy) + { + if (CancellationToken.IsCancellationRequested) + return; - _tagsQueue.Enqueue(tag); - } - } + _tagsQueue.Enqueue(tag); + } + } - public IEnumerator> GetEnumerator() => ProcessedTags.GetEnumerator(); + public IEnumerator> GetEnumerator() => ProcessedTags.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + } } From 6478e40e0464d9e47a594dc802065d97241ff9da Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Tue, 12 May 2026 21:53:26 +0200 Subject: [PATCH 21/56] ATR-966: removed redundant tag cache components --- .../AsyncTagging/Interfaces/ITagsCache.cs | 27 --------- .../Coloriser/AsyncTagging/TagsCacheAsync.cs | 7 +-- .../Coloriser/AsyncTagging/TagsCacheSync.cs | 55 ------------------- 3 files changed, 3 insertions(+), 86 deletions(-) delete mode 100644 src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/Interfaces/ITagsCache.cs delete mode 100644 src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/TagsCacheSync.cs diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/Interfaces/ITagsCache.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/Interfaces/ITagsCache.cs deleted file mode 100644 index 0998c5b68..000000000 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/Interfaces/ITagsCache.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Linq; -using System.Collections.Generic; -using System.Collections.Concurrent; -using Microsoft.VisualStudio.Text.Tagging; -using System.Collections; -using Acuminator.Vsix.Utilities; - - -namespace Acuminator.Vsix.Coloriser -{ - public interface ITagsCache : IReadOnlyCollection> - where TTag : ITag - { - bool IsCompleted { get; } - - IReadOnlyCollection> ProcessedTags { get; } - - void CompleteProcessing(); - - void Reset(); - - void AddTag(ITagSpan tag); - - void AddTags(IEnumerable> tags); - } -} diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/TagsCacheAsync.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/TagsCacheAsync.cs index cedd89555..67f2c10ab 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/TagsCacheAsync.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/TagsCacheAsync.cs @@ -6,14 +6,13 @@ using System.Linq; using System.Threading; -using Acuminator.Utilities; using Acuminator.Utilities.Common; using Microsoft.VisualStudio.Text.Tagging; namespace Acuminator.Vsix.Coloriser { - public class TagsCacheAsync : ITagsCache + public class TagsCacheAsync : IReadOnlyCollection> where TTag : ITag { protected CancellationToken CancellationToken { get; set; } @@ -75,8 +74,8 @@ public void AddTags(IEnumerable> tags) } } - public IEnumerator> GetEnumerator() => ProcessedTags.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + + public IEnumerator> GetEnumerator() => ProcessedTags.GetEnumerator(); } } diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/TagsCacheSync.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/TagsCacheSync.cs deleted file mode 100644 index c8dc7bc07..000000000 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/TagsCacheSync.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Linq; -using System.Collections.Generic; -using Microsoft.VisualStudio.Text.Tagging; -using System.Collections; -using Acuminator.Utilities; - - -namespace Acuminator.Vsix.Coloriser -{ - public class TagsCacheSync : ITagsCache - where TTag : ITag - { - private const int DefaultCapacity = 64; - - public bool IsCompleted { get; private set; } - - private readonly List> _resultTagsList; - - public IReadOnlyCollection> ProcessedTags { get; } - - public int Count => ProcessedTags.Count; - - public TagsCacheSync(int? capacity = null) - { - _resultTagsList = new List>(capacity ?? DefaultCapacity); - ProcessedTags = _resultTagsList.AsReadOnly(); - } - - public void CompleteProcessing() - { - IsCompleted = true; - } - - public void Reset() - { - _resultTagsList.Clear(); - IsCompleted = false; - } - - public void AddTag(ITagSpan tag) - { - if (tag == null) - return; - - _resultTagsList.Add(tag); - } - - public void AddTags(IEnumerable> tags) => _resultTagsList.AddRange(tags); - - public IEnumerator> GetEnumerator() => ProcessedTags.GetEnumerator(); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - } -} From d40a9f6807d9f7fce0b7a4499e4a674e63871c79 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Tue, 12 May 2026 22:34:11 +0200 Subject: [PATCH 22/56] ATR-966: merged PXColorizerTaggerBase and PXRoslynColorizer taggers together and simplified their code --- .../AsyncTagging/BackgroundTagging.cs | 12 +- .../Coloriser/Outlining/PXOutliningTagger.cs | 12 +- .../Coloriser/PXColorizerTaggerProvider.cs | 16 +- ...ggerBase.cs => PXRoslynColorizerTagger.cs} | 151 ++++++++++++----- ...ColorizerTagger.PXColorizerSyntaxWalker.cs | 4 +- .../Roslyn/PXRoslynColorizerTagger.cs | 156 ------------------ 6 files changed, 130 insertions(+), 221 deletions(-) rename src/Acuminator/Acuminator.Vsix/Coloriser/{PXColorizerTaggerBase.cs => PXRoslynColorizerTagger.cs} (56%) delete mode 100644 src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXRoslynColorizerTagger.cs diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/BackgroundTagging.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/BackgroundTagging.cs index 6a94b8861..a93aea273 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/BackgroundTagging.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/BackgroundTagging.cs @@ -1,7 +1,5 @@ #nullable enable - using System; -using System.Collections; using System.Collections.Generic; using System.Linq; using System.Threading; @@ -13,10 +11,9 @@ namespace Acuminator.Vsix.Coloriser { - public class BackgroundTagging : IDisposable + internal class BackgroundTagging : IDisposable { - private static TaskScheduler? _vsTaskScheduler; - + private static TaskScheduler? _vsTaskScheduler; private CancellationTokenSource _cancellationTokenSource = new(); public CancellationToken CancellationToken => _cancellationTokenSource.Token; @@ -27,10 +24,9 @@ public class BackgroundTagging : IDisposable private BackgroundTagging() { - } - public static BackgroundTagging StartBackgroundTagging(PXColorizerTaggerBase tagger) + public static BackgroundTagging StartBackgroundTagging(PXRoslynColorizerTagger tagger) { tagger.ThrowOnNull(); @@ -76,7 +72,7 @@ public void Dispose() _cancellationTokenSource.Dispose(); } - private static Task AfterTaggingActionAsync(Task taggingTask, PXColorizerTaggerBase tagger, CancellationToken cancellationToken) + private static Task AfterTaggingActionAsync(Task taggingTask, PXRoslynColorizerTagger tagger, CancellationToken cancellationToken) { if (taggingTask.IsCanceled || cancellationToken.IsCancellationRequested) { diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs index 18505e894..a6e8054b9 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs @@ -11,13 +11,13 @@ namespace Acuminator.Vsix.Coloriser { - public class PXOutliningTagger : PXTaggerBase, ITagger + internal class PXOutliningTagger : PXTaggerBase, ITagger { private int _isSubscribed = NOT_SUBSCRIBED; private const int NOT_SUBSCRIBED = 0; private const int SUBSCRIBED = 1; - protected PXColorizerTaggerBase? ColorizerTagger { get; private set; } + protected PXRoslynColorizerTagger? ColorizerTagger { get; private set; } internal override bool LastTaggingWasSuccessful { @@ -40,7 +40,7 @@ public IEnumerable> GetTags(NormalizedSnapshotSpan if (ColorizerTagger == null) { - if (!TryGetColorizingTaggerFromBuffer(Buffer, out PXColorizerTaggerBase colorizingTagger) || colorizingTagger == null) + if (!TryGetColorizingTaggerFromBuffer(Buffer, out PXRoslynColorizerTagger colorizingTagger) || colorizingTagger == null) return []; SubscribeToColorizingTaggerEvents(colorizingTagger); @@ -53,12 +53,12 @@ public IEnumerable> GetTags(NormalizedSnapshotSpan return ColorizerTagger.OutliningsTagsCache.ProcessedTags; } - private static bool TryGetColorizingTaggerFromBuffer(ITextBuffer textBuffer, out PXColorizerTaggerBase colorizingTagger) + private static bool TryGetColorizingTaggerFromBuffer(ITextBuffer textBuffer, out PXRoslynColorizerTagger colorizingTagger) { - return textBuffer.Properties.TryGetProperty(typeof(PXColorizerTaggerBase), out colorizingTagger); + return textBuffer.Properties.TryGetProperty(typeof(PXRoslynColorizerTagger), out colorizingTagger); } - private void SubscribeToColorizingTaggerEvents(PXColorizerTaggerBase colorizerTagger) + private void SubscribeToColorizingTaggerEvents(PXRoslynColorizerTagger colorizerTagger) { if (Interlocked.Exchange(ref _isSubscribed, SUBSCRIBED) == NOT_SUBSCRIBED) { diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerProvider.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerProvider.cs index c8ea5ab71..2e25233b1 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerProvider.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerProvider.cs @@ -77,9 +77,9 @@ public IClassificationType? this[int braceLevel] Initialize(textBuffer); - var tagger = textBuffer.Properties.GetOrCreateSingletonProperty(typeof(PXColorizerTaggerBase), () => + var tagger = textBuffer.Properties.GetOrCreateSingletonProperty(typeof(PXRoslynColorizerTagger), () => { - return new PXColorizerMainTagger(textBuffer, this, subscribeToSettingsChanges: true, useCacheChecking: true); + return new PXRoslynColorizerTagger(textBuffer, this, subscribeToSettingsChanges: true, useCacheChecking: true); }); return tagger as ITagger; @@ -104,17 +104,17 @@ protected void InitializeClassificationTypes() _codeColoringClassificationTypes = new Dictionary { - [PXCodeType.Dac] = _classificationRegistry.GetClassificationType(ColoringConstants.DacFormat), + [PXCodeType.Dac] = _classificationRegistry.GetClassificationType(ColoringConstants.DacFormat), [PXCodeType.DacExtension] = _classificationRegistry.GetClassificationType(ColoringConstants.DacExtensionFormat), - [PXCodeType.DacField] = _classificationRegistry.GetClassificationType(ColoringConstants.DacFieldFormat), + [PXCodeType.DacField] = _classificationRegistry.GetClassificationType(ColoringConstants.DacFieldFormat), [PXCodeType.BqlParameter] = _classificationRegistry.GetClassificationType(ColoringConstants.BQLParameterFormat), - [PXCodeType.BqlOperator] = bqlClassificationType, - [PXCodeType.BqlCommand] = bqlClassificationType, + [PXCodeType.BqlOperator] = bqlClassificationType, + [PXCodeType.BqlCommand] = bqlClassificationType, [PXCodeType.BQLConstantPrefix] = _classificationRegistry.GetClassificationType(ColoringConstants.BQLConstantPrefixFormat), [PXCodeType.BQLConstantEnding] = _classificationRegistry.GetClassificationType(ColoringConstants.BQLConstantEndingFormat), - [PXCodeType.PXGraph] = _classificationRegistry.GetClassificationType(ColoringConstants.PXGraphFormat), + [PXCodeType.PXGraph] = _classificationRegistry.GetClassificationType(ColoringConstants.PXGraphFormat), [PXCodeType.PXAction] = _classificationRegistry.GetClassificationType(ColoringConstants.PXActionFormat), }; @@ -132,7 +132,7 @@ protected void InitializeClassificationTypes() [7] = _classificationRegistry.GetClassificationType(ColoringConstants.BraceLevel_8_Format), [8] = _classificationRegistry.GetClassificationType(ColoringConstants.BraceLevel_9_Format), - [9] = _classificationRegistry.GetClassificationType(ColoringConstants.BraceLevel_10_Format), + [9] = _classificationRegistry.GetClassificationType(ColoringConstants.BraceLevel_10_Format), [10] = _classificationRegistry.GetClassificationType(ColoringConstants.BraceLevel_11_Format), [11] = _classificationRegistry.GetClassificationType(ColoringConstants.BraceLevel_12_Format), diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs similarity index 56% rename from src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs rename to src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index 43881098e..9ea16e106 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXColorizerTaggerBase.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -6,46 +6,98 @@ using System.Threading; using System.Threading.Tasks; +using Acuminator.Utilities.Common; using Acuminator.Utilities.Roslyn.Constants; +using Acuminator.Utilities.Roslyn.ProjectSystem; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Tagging; -using Acuminator.Utilities.Roslyn.ProjectSystem; namespace Acuminator.Vsix.Coloriser { - /// - /// A colorizer tagger base class. - /// - public abstract class PXColorizerTaggerBase : PXTaggerBase, ITagger, IDisposable - { - public BackgroundTagging? BackgroundTagging { get; protected set; } - protected internal abstract ITagsCache ClassificationTagsCache { get; } + /// + /// A Roslyn-based colorizer tagger. + /// + internal partial class PXRoslynColorizerTagger : PXTaggerBase, ITagger, IDisposable + { + protected internal TagsCacheAsync ClassificationTagsCache { get; } - protected internal abstract ITagsCache OutliningsTagsCache { get; } + protected internal TagsCacheAsync OutliningsTagsCache { get; } - protected internal abstract bool UseAsyncTagging { get; } + public BackgroundTagging? BackgroundTagging { get; private set; } - protected PXColorizerTaggerProvider Provider => (ProviderBase as PXColorizerTaggerProvider)!; + protected PXColorizerTaggerProvider Provider { get; } private bool _hasReferenceToAcumaticaPlatform; public sealed override bool HasReferenceToAcumaticaPlatform => _hasReferenceToAcumaticaPlatform; - protected PXColorizerTaggerBase(ITextBuffer buffer, PXColorizerTaggerProvider aProvider, bool subscribeToSettingsChanges, + internal override bool LastTaggingWasSuccessful { get; set; } + + public PXRoslynColorizerTagger(ITextBuffer buffer, PXColorizerTaggerProvider provider, bool subscribeToSettingsChanges, bool useCacheChecking) : - base(buffer, aProvider, subscribeToSettingsChanges, useCacheChecking) + base(buffer, subscribeToSettingsChanges, useCacheChecking) { + Provider = provider.CheckIfNull(); + + ClassificationTagsCache = new TagsCacheAsync(); + OutliningsTagsCache = new TagsCacheAsync(); + if (RoslynWorkspace != null) { _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(projectId: null); RoslynWorkspace.WorkspaceChanged += OnWorkspaceChanged; } + + //Buffer.Changed += Buffer_Changed; } + #region Commented Parsing optimizations + //private bool isParsed; + //private ParsedDocument documentCache; + //private volatile static int walking; + + //private async void Buffer_Changed(object sender, TextContentChangedEventArgs e) + //{ + // if (TagsChangedIsNull() || Buffer.CurrentSnapshot == null || e.Changes.IsNullOrEmpty()) + // return; + + // if (e.After != Buffer.CurrentSnapshot) + // return; + + // try + // { + // // If this isn't the most up-to-date version of the buffer, then ignore it for now (we'll eventually get another change event). + // int min = Int32.MaxValue, max = Int32.MinValue; + + // foreach (var change in e.Changes) + // { + // min = Math.Min(min, change.NewPosition); + // max = Math.Max(max, change.NewPosition + change.NewLength); + // } + + // TextSpan span = new TextSpan(min, max); + // var parsedDoc = await ParsedDocument.Resolve(Buffer, Buffer.CurrentSnapshot).ConfigureAwait(false); + + // documentCache = parsedDoc; + + // if (System.Threading.Interlocked.CompareExchange(ref walking, 1, comparand: 0) == 0) + // { + // WalkDocumentSyntaxTreeForTags(parsedDoc); + // RaiseTagsChanged(); + // walking = 0; + // } + // } + // catch + // { + + // } + //} + #endregion + protected internal override void ResetCacheAndFlags(ITextSnapshot? newSnapshotToCache) { base.ResetCacheAndFlags(newSnapshotToCache); @@ -53,6 +105,13 @@ protected internal override void ResetCacheAndFlags(ITextSnapshot? newSnapshotTo OutliningsTagsCache.Reset(); } + /// + /// Gets the tags asynchronously from the specified snapshot with Roslyn. + /// + /// The spans for tagging. The current implementation doesn't take them into account and re-tags the entire document. + /// + /// The current snapshot of the collected tags. + /// public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) { if ((spans?.Count is null or 0) || AcuminatorVSPackage.Instance?.ColoringEnabled != true || !HasReferenceToAcumaticaPlatform) @@ -65,45 +124,57 @@ public IEnumerable> GetTags(NormalizedSnapshotSpanC return ClassificationTagsCache.ProcessedTags; } - if (UseAsyncTagging) - { - return GetTagsAsync(newSnapshotToTag); - } - else - { - ResetCacheAndFlags(newSnapshotToTag); - return GetTagsSynchronousImplementation(newSnapshotToTag); - } - } - -#pragma warning disable VSTHRD200 // Use "Async" suffix for async methods - this method is async by its nature. - /// - /// Gets the tags asynchronous in this collection. - /// - /// The snapshot. - /// - /// An enumerator that allows foreach to be used to process the tags asynchronous in this collection. - /// - protected virtual IEnumerable> GetTagsAsync(ITextSnapshot snapshot) - - { if (BackgroundTagging != null) { BackgroundTagging.CancelTagging(); //Cancel currently running task BackgroundTagging = null; } - ResetCacheAndFlags(snapshot); + ResetCacheAndFlags(newSnapshotToTag); BackgroundTagging = BackgroundTagging.StartBackgroundTagging(this); return ClassificationTagsCache.ProcessedTags; } -#pragma warning restore VSTHRD200 - protected internal abstract IEnumerable> GetTagsSynchronousImplementation(ITextSnapshot snapshot); + protected internal async Task>> GetTagsAsyncImplementationAsync(ITextSnapshot snapshot, + CancellationToken cToken) + { + ClassificationTagsCache.SetCancellation(cToken); + OutliningsTagsCache.SetCancellation(cToken); + + Task getDocumentTask = ParsedDocument.ResolveAsync(snapshot, cToken); + + if (cToken.IsCancellationRequested) // Razor cshtml returns a null document for some reason. + return ClassificationTagsCache.ProcessedTags; + + var documentTaskResult = await getDocumentTask.TryAwait(); + + if (!documentTaskResult.IsSuccess) + return ClassificationTagsCache.ProcessedTags; + + ParsedDocument? document = documentTaskResult.Result; + + if (document == null || cToken.IsCancellationRequested) + return ClassificationTagsCache.ProcessedTags; + + bool completedSuccessfully = await WalkDocumentSyntaxTreeForTagsOnThreadpoolAsync(document, cToken).TryAwait(); + LastTaggingWasSuccessful = completedSuccessfully && ClassificationTagsCache.IsCompleted; + return ClassificationTagsCache.ProcessedTags; + } + + private Task WalkDocumentSyntaxTreeForTagsOnThreadPoolAsync(ParsedDocument document, CancellationToken cancellationToken) + { + return Task.Run(() => WalkDocumentSyntaxTreeForTags(document, cancellationToken)); + } - protected internal abstract Task>> GetTagsAsyncImplementationAsync(ITextSnapshot snapshot, - CancellationToken cancellationToken); + private void WalkDocumentSyntaxTreeForTags(ParsedDocument document, CancellationToken cancellationToken) + { + var syntaxWalker = new PXColorizerSyntaxWalker(this, document, cancellationToken); + + syntaxWalker.Visit(document.SyntaxRoot); + ClassificationTagsCache.CompleteProcessing(); + OutliningsTagsCache.CompleteProcessing(); + } public override void Dispose() { diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXRoslynColorizerTagger.PXColorizerSyntaxWalker.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXRoslynColorizerTagger.PXColorizerSyntaxWalker.cs index c087142ad..48a33c144 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXRoslynColorizerTagger.PXColorizerSyntaxWalker.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXRoslynColorizerTagger.PXColorizerSyntaxWalker.cs @@ -14,11 +14,9 @@ using Acuminator.Utilities.Roslyn.Semantic; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Classification; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; -using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Classification; using Microsoft.VisualStudio.Text.Tagging; @@ -26,7 +24,7 @@ namespace Acuminator.Vsix.Coloriser { - public partial class PXRoslynColorizerTagger : PXColorizerTaggerBase + internal partial class PXRoslynColorizerTagger : PXTaggerBase { protected class PXColorizerSyntaxWalker : CSharpSyntaxWalker { diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXRoslynColorizerTagger.cs deleted file mode 100644 index df1d15007..000000000 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/PXRoslynColorizerTagger.cs +++ /dev/null @@ -1,156 +0,0 @@ -#nullable enable - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; - -using Acuminator.Utilities.Common; - -using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Tagging; - -namespace Acuminator.Vsix.Coloriser -{ - public partial class PXRoslynColorizerTagger : PXColorizerTaggerBase - { - protected internal override bool UseAsyncTagging => true; - - private readonly TagsCacheAsync _classificationTagsCache; - - protected internal override ITagsCache ClassificationTagsCache => _classificationTagsCache; - - private readonly TagsCacheAsync _outliningTagsCache; - - protected internal override ITagsCache OutliningsTagsCache => _outliningTagsCache; - - internal override bool LastTaggingWasSuccessful { get; set; } - - internal PXRoslynColorizerTagger(ITextBuffer buffer, PXColorizerTaggerProvider aProvider, bool subscribeToSettingsChanges, - bool useCacheChecking) : - base(buffer, aProvider, subscribeToSettingsChanges, useCacheChecking) - { - _classificationTagsCache = new TagsCacheAsync(); - _outliningTagsCache = new TagsCacheAsync(); - - //Buffer.Changed += Buffer_Changed; - } - - #region Commented Parsing optimizations - //private bool isParsed; - //private ParsedDocument documentCache; - //private volatile static int walking; - - //private async void Buffer_Changed(object sender, TextContentChangedEventArgs e) - //{ - // if (TagsChangedIsNull() || Buffer.CurrentSnapshot == null || e.Changes.IsNullOrEmpty()) - // return; - - // if (e.After != Buffer.CurrentSnapshot) - // return; - - // try - // { - // // If this isn't the most up-to-date version of the buffer, then ignore it for now (we'll eventually get another change event). - // int min = Int32.MaxValue, max = Int32.MinValue; - - // foreach (var change in e.Changes) - // { - // min = Math.Min(min, change.NewPosition); - // max = Math.Max(max, change.NewPosition + change.NewLength); - // } - - // TextSpan span = new TextSpan(min, max); - // var parsedDoc = await ParsedDocument.Resolve(Buffer, Buffer.CurrentSnapshot).ConfigureAwait(false); - - // documentCache = parsedDoc; - - // if (System.Threading.Interlocked.CompareExchange(ref walking, 1, comparand: 0) == 0) - // { - // WalkDocumentSyntaxTreeForTags(parsedDoc); - // RaiseTagsChanged(); - // walking = 0; - // } - // } - // catch - // { - - // } - //} - #endregion - - protected internal override IEnumerable> GetTagsSynchronousImplementation(ITextSnapshot snapshot) - { - _classificationTagsCache.SetCancellation(CancellationToken.None); - _outliningTagsCache.SetCancellation(CancellationToken.None); - - Task getDocumentTask = ParsedDocument.ResolveAsync(snapshot, CancellationToken.None); - - try - { - //This method is deliberately synchronous so we ignore warnings -#pragma warning disable VSTHRD002 // Avoid problematic synchronous waits - getDocumentTask.Wait(); - - } - catch (Exception) - { - return ClassificationTagsCache.ProcessedTags; // TODO: report this to someone. - } - - ParsedDocument? document = getDocumentTask.Result; -#pragma warning restore VSTHRD002 // Avoid problematic synchronous waits - - if (document != null) - { - WalkDocumentSyntaxTreeForTags(document, CancellationToken.None); - LastTaggingWasSuccessful = ClassificationTagsCache.IsCompleted; - } - //documentCache = document; - //isParsed = true; - - return ClassificationTagsCache.ProcessedTags; - } - - protected internal async override Task>> GetTagsAsyncImplementationAsync(ITextSnapshot snapshot, - CancellationToken cToken) - { - _classificationTagsCache.SetCancellation(cToken); - _outliningTagsCache.SetCancellation(cToken); - - Task getDocumentTask = ParsedDocument.ResolveAsync(snapshot, cToken); - - if (cToken.IsCancellationRequested) // Razor cshtml returns a null document for some reason. - return ClassificationTagsCache.ProcessedTags; - - var documentTaskResult = await getDocumentTask.TryAwait(); - - if (!documentTaskResult.IsSuccess) - return ClassificationTagsCache.ProcessedTags; - - ParsedDocument? document = documentTaskResult.Result; - - if (document == null || cToken.IsCancellationRequested) - return ClassificationTagsCache.ProcessedTags; - - bool completedSuccessfully = await WalkDocumentSyntaxTreeForTagsAsync(document, cToken).TryAwait(); - LastTaggingWasSuccessful = completedSuccessfully && ClassificationTagsCache.IsCompleted; - return ClassificationTagsCache.ProcessedTags; - } - - private void WalkDocumentSyntaxTreeForTags(ParsedDocument document, CancellationToken cancellationToken) - { - var syntaxWalker = new PXColorizerSyntaxWalker(this, document, cancellationToken); - - syntaxWalker.Visit(document.SyntaxRoot); - ClassificationTagsCache.CompleteProcessing(); - OutliningsTagsCache.CompleteProcessing(); - } - - private Task WalkDocumentSyntaxTreeForTagsAsync(ParsedDocument document, CancellationToken cancellationToken) - { - return Task.Run(() => WalkDocumentSyntaxTreeForTags(document, cancellationToken)); - } - } -} From a43ef41dc025bdfc3fba989bee67bb81b8cd4157 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Tue, 12 May 2026 22:50:44 +0200 Subject: [PATCH 23/56] ATR-966: reworked starting the tagging task on the thread pool --- .../Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index 9ea16e106..aa90a1f2d 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -164,7 +164,10 @@ protected internal async Task>> GetTags private Task WalkDocumentSyntaxTreeForTagsOnThreadPoolAsync(ParsedDocument document, CancellationToken cancellationToken) { - return Task.Run(() => WalkDocumentSyntaxTreeForTags(document, cancellationToken)); + return Task.Factory.StartNew(() => WalkDocumentSyntaxTreeForTags(document, cancellationToken), + cancellationToken, + TaskCreationOptions.LongRunning, + TaskScheduler.Default); } private void WalkDocumentSyntaxTreeForTags(ParsedDocument document, CancellationToken cancellationToken) From 61424cf5bb7ac99075ef2e151a0b0fd7777da052 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Tue, 12 May 2026 22:52:04 +0200 Subject: [PATCH 24/56] ATR-966: refactoring - reduced indentation --- .../Coloriser/PXRoslynColorizerTagger.cs | 454 +++++++++--------- 1 file changed, 226 insertions(+), 228 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index aa90a1f2d..634c76183 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -15,286 +15,284 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Tagging; -namespace Acuminator.Vsix.Coloriser +namespace Acuminator.Vsix.Coloriser; + +/// +/// A Roslyn-based colorizer tagger. +/// +internal partial class PXRoslynColorizerTagger : PXTaggerBase, ITagger, IDisposable { + protected internal TagsCacheAsync ClassificationTagsCache { get; } - /// - /// A Roslyn-based colorizer tagger. - /// - internal partial class PXRoslynColorizerTagger : PXTaggerBase, ITagger, IDisposable - { - protected internal TagsCacheAsync ClassificationTagsCache { get; } + protected internal TagsCacheAsync OutliningsTagsCache { get; } - protected internal TagsCacheAsync OutliningsTagsCache { get; } + public BackgroundTagging? BackgroundTagging { get; private set; } - public BackgroundTagging? BackgroundTagging { get; private set; } + protected PXColorizerTaggerProvider Provider { get; } - protected PXColorizerTaggerProvider Provider { get; } + private bool _hasReferenceToAcumaticaPlatform; - private bool _hasReferenceToAcumaticaPlatform; + public sealed override bool HasReferenceToAcumaticaPlatform => _hasReferenceToAcumaticaPlatform; - public sealed override bool HasReferenceToAcumaticaPlatform => _hasReferenceToAcumaticaPlatform; + internal override bool LastTaggingWasSuccessful { get; set; } - internal override bool LastTaggingWasSuccessful { get; set; } + public PXRoslynColorizerTagger(ITextBuffer buffer, PXColorizerTaggerProvider provider, bool subscribeToSettingsChanges, + bool useCacheChecking) : + base(buffer, subscribeToSettingsChanges, useCacheChecking) + { + Provider = provider.CheckIfNull(); + + ClassificationTagsCache = new TagsCacheAsync(); + OutliningsTagsCache = new TagsCacheAsync(); - public PXRoslynColorizerTagger(ITextBuffer buffer, PXColorizerTaggerProvider provider, bool subscribeToSettingsChanges, - bool useCacheChecking) : - base(buffer, subscribeToSettingsChanges, useCacheChecking) + if (RoslynWorkspace != null) { - Provider = provider.CheckIfNull(); + _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(projectId: null); + RoslynWorkspace.WorkspaceChanged += OnWorkspaceChanged; + } - ClassificationTagsCache = new TagsCacheAsync(); - OutliningsTagsCache = new TagsCacheAsync(); + //Buffer.Changed += Buffer_Changed; + } - if (RoslynWorkspace != null) - { - _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(projectId: null); - RoslynWorkspace.WorkspaceChanged += OnWorkspaceChanged; - } + #region Commented Parsing optimizations + //private bool isParsed; + //private ParsedDocument documentCache; + //private volatile static int walking; + + //private async void Buffer_Changed(object sender, TextContentChangedEventArgs e) + //{ + // if (TagsChangedIsNull() || Buffer.CurrentSnapshot == null || e.Changes.IsNullOrEmpty()) + // return; + + // if (e.After != Buffer.CurrentSnapshot) + // return; + + // try + // { + // // If this isn't the most up-to-date version of the buffer, then ignore it for now (we'll eventually get another change event). + // int min = Int32.MaxValue, max = Int32.MinValue; + + // foreach (var change in e.Changes) + // { + // min = Math.Min(min, change.NewPosition); + // max = Math.Max(max, change.NewPosition + change.NewLength); + // } + + // TextSpan span = new TextSpan(min, max); + // var parsedDoc = await ParsedDocument.Resolve(Buffer, Buffer.CurrentSnapshot).ConfigureAwait(false); + + // documentCache = parsedDoc; + + // if (System.Threading.Interlocked.CompareExchange(ref walking, 1, comparand: 0) == 0) + // { + // WalkDocumentSyntaxTreeForTags(parsedDoc); + // RaiseTagsChanged(); + // walking = 0; + // } + // } + // catch + // { + + // } + //} + #endregion + + protected internal override void ResetCacheAndFlags(ITextSnapshot? newSnapshotToCache) + { + base.ResetCacheAndFlags(newSnapshotToCache); + ClassificationTagsCache.Reset(); + OutliningsTagsCache.Reset(); + } - //Buffer.Changed += Buffer_Changed; - } + /// + /// Gets the tags asynchronously from the specified snapshot with Roslyn. + /// + /// The spans for tagging. The current implementation doesn't take them into account and re-tags the entire document. + /// + /// The current snapshot of the collected tags. + /// + public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) + { + if ((spans?.Count is null or 0) || AcuminatorVSPackage.Instance?.ColoringEnabled != true || !HasReferenceToAcumaticaPlatform) + return []; - #region Commented Parsing optimizations - //private bool isParsed; - //private ParsedDocument documentCache; - //private volatile static int walking; - - //private async void Buffer_Changed(object sender, TextContentChangedEventArgs e) - //{ - // if (TagsChangedIsNull() || Buffer.CurrentSnapshot == null || e.Changes.IsNullOrEmpty()) - // return; - - // if (e.After != Buffer.CurrentSnapshot) - // return; - - // try - // { - // // If this isn't the most up-to-date version of the buffer, then ignore it for now (we'll eventually get another change event). - // int min = Int32.MaxValue, max = Int32.MinValue; - - // foreach (var change in e.Changes) - // { - // min = Math.Min(min, change.NewPosition); - // max = Math.Max(max, change.NewPosition + change.NewLength); - // } - - // TextSpan span = new TextSpan(min, max); - // var parsedDoc = await ParsedDocument.Resolve(Buffer, Buffer.CurrentSnapshot).ConfigureAwait(false); - - // documentCache = parsedDoc; - - // if (System.Threading.Interlocked.CompareExchange(ref walking, 1, comparand: 0) == 0) - // { - // WalkDocumentSyntaxTreeForTags(parsedDoc); - // RaiseTagsChanged(); - // walking = 0; - // } - // } - // catch - // { - - // } - //} - #endregion - - protected internal override void ResetCacheAndFlags(ITextSnapshot? newSnapshotToCache) + ITextSnapshot newSnapshotToTag = spans[0].Snapshot; + + if (CheckIfRetaggingIsNotNecessary(newSnapshotToTag)) { - base.ResetCacheAndFlags(newSnapshotToCache); - ClassificationTagsCache.Reset(); - OutliningsTagsCache.Reset(); + return ClassificationTagsCache.ProcessedTags; } - /// - /// Gets the tags asynchronously from the specified snapshot with Roslyn. - /// - /// The spans for tagging. The current implementation doesn't take them into account and re-tags the entire document. - /// - /// The current snapshot of the collected tags. - /// - public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) + if (BackgroundTagging != null) { - if ((spans?.Count is null or 0) || AcuminatorVSPackage.Instance?.ColoringEnabled != true || !HasReferenceToAcumaticaPlatform) - return []; + BackgroundTagging.CancelTagging(); //Cancel currently running task + BackgroundTagging = null; + } - ITextSnapshot newSnapshotToTag = spans[0].Snapshot; + ResetCacheAndFlags(newSnapshotToTag); + BackgroundTagging = BackgroundTagging.StartBackgroundTagging(this); - if (CheckIfRetaggingIsNotNecessary(newSnapshotToTag)) - { - return ClassificationTagsCache.ProcessedTags; - } + return ClassificationTagsCache.ProcessedTags; + } - if (BackgroundTagging != null) - { - BackgroundTagging.CancelTagging(); //Cancel currently running task - BackgroundTagging = null; - } + protected internal async Task>> GetTagsAsyncImplementationAsync(ITextSnapshot snapshot, + CancellationToken cToken) + { + ClassificationTagsCache.SetCancellation(cToken); + OutliningsTagsCache.SetCancellation(cToken); - ResetCacheAndFlags(newSnapshotToTag); - BackgroundTagging = BackgroundTagging.StartBackgroundTagging(this); + Task getDocumentTask = ParsedDocument.ResolveAsync(snapshot, cToken); + if (cToken.IsCancellationRequested) // Razor cshtml returns a null document for some reason. return ClassificationTagsCache.ProcessedTags; - } - protected internal async Task>> GetTagsAsyncImplementationAsync(ITextSnapshot snapshot, - CancellationToken cToken) - { - ClassificationTagsCache.SetCancellation(cToken); - OutliningsTagsCache.SetCancellation(cToken); + var documentTaskResult = await getDocumentTask.TryAwait(); - Task getDocumentTask = ParsedDocument.ResolveAsync(snapshot, cToken); + if (!documentTaskResult.IsSuccess) + return ClassificationTagsCache.ProcessedTags; - if (cToken.IsCancellationRequested) // Razor cshtml returns a null document for some reason. - return ClassificationTagsCache.ProcessedTags; + ParsedDocument? document = documentTaskResult.Result; - var documentTaskResult = await getDocumentTask.TryAwait(); + if (document == null || cToken.IsCancellationRequested) + return ClassificationTagsCache.ProcessedTags; - if (!documentTaskResult.IsSuccess) - return ClassificationTagsCache.ProcessedTags; + bool completedSuccessfully = await WalkDocumentSyntaxTreeForTagsOnThreadpoolAsync(document, cToken).TryAwait(); + LastTaggingWasSuccessful = completedSuccessfully && ClassificationTagsCache.IsCompleted; + return ClassificationTagsCache.ProcessedTags; + } - ParsedDocument? document = documentTaskResult.Result; + private Task WalkDocumentSyntaxTreeForTagsOnThreadPoolAsync(ParsedDocument document, CancellationToken cancellationToken) + { + return Task.Factory.StartNew(() => WalkDocumentSyntaxTreeForTags(document, cancellationToken), + cancellationToken, + TaskCreationOptions.LongRunning, + TaskScheduler.Default); + } - if (document == null || cToken.IsCancellationRequested) - return ClassificationTagsCache.ProcessedTags; + private void WalkDocumentSyntaxTreeForTags(ParsedDocument document, CancellationToken cancellationToken) + { + var syntaxWalker = new PXColorizerSyntaxWalker(this, document, cancellationToken); - bool completedSuccessfully = await WalkDocumentSyntaxTreeForTagsOnThreadpoolAsync(document, cToken).TryAwait(); - LastTaggingWasSuccessful = completedSuccessfully && ClassificationTagsCache.IsCompleted; - return ClassificationTagsCache.ProcessedTags; - } + syntaxWalker.Visit(document.SyntaxRoot); + ClassificationTagsCache.CompleteProcessing(); + OutliningsTagsCache.CompleteProcessing(); + } + + public override void Dispose() + { + BackgroundTagging?.Dispose(); + ClassificationTagsCache?.Reset(); + OutliningsTagsCache?.Reset(); - private Task WalkDocumentSyntaxTreeForTagsOnThreadPoolAsync(ParsedDocument document, CancellationToken cancellationToken) + if (RoslynWorkspace != null) { - return Task.Factory.StartNew(() => WalkDocumentSyntaxTreeForTags(document, cancellationToken), - cancellationToken, - TaskCreationOptions.LongRunning, - TaskScheduler.Default); + RoslynWorkspace.WorkspaceChanged -= OnWorkspaceChanged; } - private void WalkDocumentSyntaxTreeForTags(ParsedDocument document, CancellationToken cancellationToken) - { - var syntaxWalker = new PXColorizerSyntaxWalker(this, document, cancellationToken); + base.Dispose(); + } - syntaxWalker.Visit(document.SyntaxRoot); - ClassificationTagsCache.CompleteProcessing(); - OutliningsTagsCache.CompleteProcessing(); - } + private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) + { + bool oldValue = _hasReferenceToAcumaticaPlatform; - public override void Dispose() + switch (e.Kind) { - BackgroundTagging?.Dispose(); - ClassificationTagsCache?.Reset(); - OutliningsTagsCache?.Reset(); + case WorkspaceChangeKind.SolutionRemoved: + case WorkspaceChangeKind.SolutionCleared: + _hasReferenceToAcumaticaPlatform = false; + break; + + case WorkspaceChangeKind.SolutionAdded: + case WorkspaceChangeKind.ProjectAdded: + _hasReferenceToAcumaticaPlatform |= CheckIfCurrentSolutionHasReferenceToAcumatica(e.ProjectId); + break; + + case WorkspaceChangeKind.SolutionChanged: + case WorkspaceChangeKind.SolutionReloaded: + case WorkspaceChangeKind.ProjectRemoved: + _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(e.ProjectId); + break; + + case WorkspaceChangeKind.ProjectChanged: + case WorkspaceChangeKind.ProjectReloaded: + if (e.IsProjectMetadataChanged()) + { + _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(e.ProjectId); + } - if (RoslynWorkspace != null) - { - RoslynWorkspace.WorkspaceChanged -= OnWorkspaceChanged; - } + break; - base.Dispose(); + default: + return; } - private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) + if (Buffer.CurrentSnapshot != null && (oldValue != _hasReferenceToAcumaticaPlatform || !LastTaggingWasSuccessful)) { - bool oldValue = _hasReferenceToAcumaticaPlatform; - - switch (e.Kind) - { - case WorkspaceChangeKind.SolutionRemoved: - case WorkspaceChangeKind.SolutionCleared: - _hasReferenceToAcumaticaPlatform = false; - break; - - case WorkspaceChangeKind.SolutionAdded: - case WorkspaceChangeKind.ProjectAdded: - _hasReferenceToAcumaticaPlatform |= CheckIfCurrentSolutionHasReferenceToAcumatica(e.ProjectId); - break; - - case WorkspaceChangeKind.SolutionChanged: - case WorkspaceChangeKind.SolutionReloaded: - case WorkspaceChangeKind.ProjectRemoved: - _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(e.ProjectId); - break; - - case WorkspaceChangeKind.ProjectChanged: - case WorkspaceChangeKind.ProjectReloaded: - if (e.IsProjectMetadataChanged()) - { - _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(e.ProjectId); - } - - break; - - default: - return; - } - - if (Buffer.CurrentSnapshot != null && (oldValue != _hasReferenceToAcumaticaPlatform || !LastTaggingWasSuccessful)) - { - ResetCacheAndFlags(newSnapshotToCache: null); - RaiseTagsChanged(); - } + ResetCacheAndFlags(newSnapshotToCache: null); + RaiseTagsChanged(); } + } - protected bool CheckIfCurrentSolutionHasReferenceToAcumatica(ProjectId? projectId) - { - var currentSolution = RoslynWorkspace?.CurrentSolution; - - if (currentSolution == null || currentSolution.ProjectIds.Count == 0) - return false; - - var roslynDocument = Buffer.CurrentSnapshot?.GetOpenDocumentInCurrentContextWithChanges(); - var currentProject = roslynDocument?.Project; - bool allProjectsChanged = projectId == null; - - if (allProjectsChanged) - { - bool hasAcumaticaProjectsInSolution = - currentSolution.Projects.Any(project => IsAcumaticaAssemblyName(project.Name) || IsAcumaticaAssemblyName(project.AssemblyName)); - - if (hasAcumaticaProjectsInSolution) - return true; - - bool hasReferenceInMetadata = (from project in currentSolution.Projects - from reference in project.MetadataReferences - select Path.GetFileNameWithoutExtension(reference.Display)) - .Any(reference => IsAcumaticaAssemblyName(reference)); - return hasReferenceInMetadata; - } - else if (currentProject?.Id == projectId) // Check that the changed project is the same as the project of the current document. If not, then return the old value. - { - if (CanCreateGraphFastCheck(currentProject!) is bool canCreateGraph) - return canCreateGraph; - - bool hasReferenceInMetadata = currentProject!.MetadataReferences.Count > 0 - ? currentProject.MetadataReferences.Any(IsAcumaticaAssemblyName) - : false; - - if (hasReferenceInMetadata) - return true; - - bool isAcumaticaProject = IsAcumaticaAssemblyName(currentProject.Name) || IsAcumaticaAssemblyName(currentProject.AssemblyName); - return isAcumaticaProject; - } - else - return _hasReferenceToAcumaticaPlatform; - } + protected bool CheckIfCurrentSolutionHasReferenceToAcumatica(ProjectId? projectId) + { + var currentSolution = RoslynWorkspace?.CurrentSolution; - private static bool IsAcumaticaAssemblyName(MetadataReference reference) + if (currentSolution == null || currentSolution.ProjectIds.Count == 0) + return false; + + var roslynDocument = Buffer.CurrentSnapshot?.GetOpenDocumentInCurrentContextWithChanges(); + var currentProject = roslynDocument?.Project; + bool allProjectsChanged = projectId == null; + + if (allProjectsChanged) { - string referenceName = Path.GetFileNameWithoutExtension(reference.Display); - return IsAcumaticaAssemblyName(referenceName); - } + bool hasAcumaticaProjectsInSolution = + currentSolution.Projects.Any(project => IsAcumaticaAssemblyName(project.Name) || IsAcumaticaAssemblyName(project.AssemblyName)); - private static bool IsAcumaticaAssemblyName(string dllName) => ColoringConstants.PlatformDllName == dllName || - ColoringConstants.AppDllName == dllName; + if (hasAcumaticaProjectsInSolution) + return true; - private static bool? CanCreateGraphFastCheck(Project project) + bool hasReferenceInMetadata = (from project in currentSolution.Projects + from reference in project.MetadataReferences + select Path.GetFileNameWithoutExtension(reference.Display)) + .Any(reference => IsAcumaticaAssemblyName(reference)); + return hasReferenceInMetadata; + } + else if (currentProject?.Id == projectId) // Check that the changed project is the same as the project of the current document. If not, then return the old value. { - if (!project.TryGetCompilation(out var compilation) || compilation == null) - return null; + if (CanCreateGraphFastCheck(currentProject!) is bool canCreateGraph) + return canCreateGraph; - var graphType = compilation.GetTypeByMetadataName(TypeFullNames.PXGraph); - return graphType != null; + bool hasReferenceInMetadata = currentProject!.MetadataReferences.Count > 0 + ? currentProject.MetadataReferences.Any(IsAcumaticaAssemblyName) + : false; + + if (hasReferenceInMetadata) + return true; + + bool isAcumaticaProject = IsAcumaticaAssemblyName(currentProject.Name) || IsAcumaticaAssemblyName(currentProject.AssemblyName); + return isAcumaticaProject; } + else + return _hasReferenceToAcumaticaPlatform; + } + + private static bool IsAcumaticaAssemblyName(MetadataReference reference) + { + string referenceName = Path.GetFileNameWithoutExtension(reference.Display); + return IsAcumaticaAssemblyName(referenceName); + } + + private static bool IsAcumaticaAssemblyName(string dllName) => ColoringConstants.PlatformDllName == dllName || + ColoringConstants.AppDllName == dllName; + + private static bool? CanCreateGraphFastCheck(Project project) + { + if (!project.TryGetCompilation(out var compilation) || compilation == null) + return null; + + var graphType = compilation.GetTypeByMetadataName(TypeFullNames.PXGraph); + return graphType != null; } } From 207228c80060480334ea20d861cf3e07e3e518b5 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Tue, 12 May 2026 23:15:08 +0200 Subject: [PATCH 25/56] ATR-966: removed remaining RegEx coloring options --- src/Acuminator/Acuminator.Vsix/AcuminatorVSPackage.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/AcuminatorVSPackage.cs b/src/Acuminator/Acuminator.Vsix/AcuminatorVSPackage.cs index 30f8c306d..3c1f919d9 100644 --- a/src/Acuminator/Acuminator.Vsix/AcuminatorVSPackage.cs +++ b/src/Acuminator/Acuminator.Vsix/AcuminatorVSPackage.cs @@ -504,9 +504,6 @@ private static void DeployCodeSnippets(AcuminatorMyDocumentsStorage? myDocuments #region Package Settings public bool ColoringEnabled => GeneralOptionsPage?.ColoringEnabled ?? AcuminatorConstants.Settings.Coloring.ColoringEnabledDefault; - - public bool UseRegexColoring => GeneralOptionsPage?.UseRegexColoring ?? AcuminatorConstants.Settings.Coloring.UseRegexColoringDefault; - public bool UseBqlOutlining => GeneralOptionsPage?.UseBqlOutlining ?? AcuminatorConstants.Settings.Outlining.UseBqlOutliningDefault; public bool UseBqlDetailedOutlining => From 3a27f4bca2c4fa043e13c83b32de10f67e774245 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Wed, 13 May 2026 00:17:24 +0200 Subject: [PATCH 26/56] ATR-966: added filtering of miscellanous files workspace created by VS while it initialize the main roslyn workspace --- .../Coloriser/PXRoslynColorizerTagger.cs | 21 ++++++++++++++++++- .../Roslyn/Utils/RoslynVSEditorExtensions.cs | 16 +++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index 634c76183..dce957624 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -36,6 +36,8 @@ internal partial class PXRoslynColorizerTagger : PXTaggerBase, ITagger(); OutliningsTagsCache = new TagsCacheAsync(); + RoslynWorkspace = Buffer.GetWorkspaceThatSupportsColoring(); if (RoslynWorkspace != null) { @@ -113,7 +116,23 @@ protected internal override void ResetCacheAndFlags(ITextSnapshot? newSnapshotTo /// public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) { - if ((spans?.Count is null or 0) || AcuminatorVSPackage.Instance?.ColoringEnabled != true || !HasReferenceToAcumaticaPlatform) + if (spans?.Count is null or 0 || AcuminatorVSPackage.Instance?.ColoringEnabled != true) + return []; + + // If Roslyn workspace wasn't initialized yet, we need to try to initialize it. + if (RoslynWorkspace == null) + { + RoslynWorkspace = Buffer.GetWorkspaceThatSupportsColoring(); + + if (RoslynWorkspace == null) + return []; + + // If initialization was successful, we need to subscribe to workspace events and calculate the hasReferenceToAcumaticaPlatform flag. + _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(projectId: null); + RoslynWorkspace.WorkspaceChanged += OnWorkspaceChanged; + } + + if (!HasReferenceToAcumaticaPlatform) return []; ITextSnapshot newSnapshotToTag = spans[0].Snapshot; diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/Utils/RoslynVSEditorExtensions.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/Utils/RoslynVSEditorExtensions.cs index 8aa0efbf0..d87474f14 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/Utils/RoslynVSEditorExtensions.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/Utils/RoslynVSEditorExtensions.cs @@ -4,6 +4,7 @@ using Acuminator.Utilities.Common; +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; @@ -13,7 +14,7 @@ namespace Acuminator.Vsix.Coloriser { - public static class RoslynVSEditorExtensions + internal static class RoslynVSEditorExtensions { public static ITagSpan ToClassificationTagSpan(this TextSpan span, ITextSnapshot snapshot, IClassificationType classificationType) { @@ -43,5 +44,18 @@ public static ITagSpan ToOutliningTagSpan(this TextSpan spa public static string GetText(this ITextSnapshot snapshot, TextSpan span) => snapshot.GetText(span.Start, span.Length); + + public static Workspace? GetWorkspaceThatSupportsColoring(this ITextBuffer? buffer) + { + var workspace = buffer?.GetWorkspace(); + + if (workspace == null) + return null; + + const string previewWorkspaceKind = "MiscellaneousFiles"; + return previewWorkspaceKind.Equals(workspace.Kind, StringComparison.OrdinalIgnoreCase) + ? null + : workspace; + } } } From 6a915a9639abfffd64a487bcfdf5618faa2d5e31 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Wed, 13 May 2026 13:30:10 +0200 Subject: [PATCH 27/56] ATR-966: updated workspace initialization logic in the tagger --- .../Coloriser/PXRoslynColorizerTagger.cs | 38 +++++++++++++------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index dce957624..886ccc20c 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -120,19 +120,9 @@ public IEnumerable> GetTags(NormalizedSnapshotSpanC return []; // If Roslyn workspace wasn't initialized yet, we need to try to initialize it. - if (RoslynWorkspace == null) - { - RoslynWorkspace = Buffer.GetWorkspaceThatSupportsColoring(); - - if (RoslynWorkspace == null) - return []; - - // If initialization was successful, we need to subscribe to workspace events and calculate the hasReferenceToAcumaticaPlatform flag. - _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(projectId: null); - RoslynWorkspace.WorkspaceChanged += OnWorkspaceChanged; - } + UpdateWorkspaceAndStateIfNeeded(); - if (!HasReferenceToAcumaticaPlatform) + if (RoslynWorkspace == null || !HasReferenceToAcumaticaPlatform) return []; ITextSnapshot newSnapshotToTag = spans[0].Snapshot; @@ -154,6 +144,30 @@ public IEnumerable> GetTags(NormalizedSnapshotSpanC return ClassificationTagsCache.ProcessedTags; } + private void UpdateWorkspaceAndStateIfNeeded() + { + Workspace? currentBufferWorkspace = Buffer.GetWorkspaceThatSupportsColoring(); + + if (ReferenceEquals(RoslynWorkspace, currentBufferWorkspace)) + return; + + if (RoslynWorkspace != null) + RoslynWorkspace.WorkspaceChanged -= OnWorkspaceChanged; + + RoslynWorkspace = currentBufferWorkspace; + + // If initialization was successful, we need to subscribe to workspace events and calculate the hasReferenceToAcumaticaPlatform flag. + if (RoslynWorkspace != null) + { + RoslynWorkspace.WorkspaceChanged += OnWorkspaceChanged; + _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(projectId: null); + } + else + { + _hasReferenceToAcumaticaPlatform = false; + } + } + protected internal async Task>> GetTagsAsyncImplementationAsync(ITextSnapshot snapshot, CancellationToken cToken) { From b238d5f87b7e78d775de9e4630bc27f8d7049a4d Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Wed, 13 May 2026 15:16:48 +0200 Subject: [PATCH 28/56] ATR-966: made retagging on settings changed called synchronously --- .../Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs index 47eb78d59..efa60f4a2 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs @@ -7,10 +7,9 @@ using Acuminator.Utilities.Common; using Acuminator.Vsix.Settings; -using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.Text; -using Shell = Microsoft.VisualStudio.Shell; +using ThreadHelper = Microsoft.VisualStudio.Shell.ThreadHelper; namespace Acuminator.Vsix.Coloriser { @@ -51,18 +50,21 @@ protected PXTaggerBase(ITextBuffer buffer, bool subscribeToSettingsChanges, bool } } - protected virtual void ColoringSettingChangedHandler(object sender, SettingChangedEventArgs e) + private void ColoringSettingChangedHandler(object sender, SettingChangedEventArgs e) { ColoringSettingsChanged = true; LastTaggingWasSuccessful = false; + + // Coloring setting should be called from the UI thread and there is a safety check in RaiseTagsChanged + // It should be OK to make a sync call RaiseTagsChanged(); } internal async Task RaiseTagsChangedAsync() { - if (!Shell.ThreadHelper.CheckAccess()) + if (!ThreadHelper.CheckAccess()) { - await Shell.ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); } RaiseTagsChangedImpl(); @@ -70,7 +72,7 @@ internal async Task RaiseTagsChangedAsync() internal void RaiseTagsChanged() { - if (!Shell.ThreadHelper.CheckAccess()) + if (!ThreadHelper.CheckAccess()) return; RaiseTagsChangedImpl(); From da57b71c1954bfa9b3a35fdf322c6e43a40fcf46 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Wed, 13 May 2026 15:17:06 +0200 Subject: [PATCH 29/56] ATR-966: updated comments --- .../Common/Concurrent/ConcurrentExtensions.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Acuminator/Acuminator.Utilities/Common/Concurrent/ConcurrentExtensions.cs b/src/Acuminator/Acuminator.Utilities/Common/Concurrent/ConcurrentExtensions.cs index 4e1d87bae..4205361b6 100644 --- a/src/Acuminator/Acuminator.Utilities/Common/Concurrent/ConcurrentExtensions.cs +++ b/src/Acuminator/Acuminator.Utilities/Common/Concurrent/ConcurrentExtensions.cs @@ -32,7 +32,7 @@ public static void Clear(this ConcurrentQueue? queue) } /// - /// A Task extension method that attempts to await task which could be cancelled. + /// A Task extension method that attempts to await task which could be cancelled or faulted. /// /// The task to act on. /// (Optional) True to continue on captured context. @@ -54,7 +54,7 @@ public async static Task TryAwait(this Task? task, bool continueOnCaptured } /// - /// A extension method that attempts to await task which could be cancelled. + /// A extension method that attempts to await task which could be cancelled or faulted. /// /// The task to act on. /// (Optional) True to continue on captured context. @@ -76,7 +76,7 @@ public async static ValueTask TryAwait(this ValueTask? task, bool continue } /// - /// A extension method that attempts to await task which could be cancelled. + /// A extension method that attempts to await task which could be cancelled or faulted. /// /// Type of the result. /// The task to act on. @@ -100,7 +100,7 @@ public async static Task> TryAwait(this Task - /// A extension method that attempts to await task which could be cancelled. + /// A extension method that attempts to await task which could be cancelled or faulted. ///
/// Type of the result. /// The task to act on. From eb79ff9785be624b0da9c013781625c23587bc43 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Wed, 13 May 2026 15:19:30 +0200 Subject: [PATCH 30/56] ATR-966: made sync call to raise outlining tags changed event --- .../Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs index a6e8054b9..7735721b2 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Outlining/PXOutliningTagger.cs @@ -6,7 +6,6 @@ using System.Threading; using Microsoft.VisualStudio.Text; -using Microsoft.VisualStudio.Text.Classification; using Microsoft.VisualStudio.Text.Tagging; namespace Acuminator.Vsix.Coloriser From 44f5b80776090e7656b161cfa95e5dfdd2310a11 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Wed, 13 May 2026 16:24:49 +0200 Subject: [PATCH 31/56] ATR-966: moved check for unnecesassary parsing and retagging to the derived Roslyn colorizer + fixed the check based on the last tagging flag --- src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs | 3 --- .../Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs index efa60f4a2..ffea0f188 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs @@ -93,9 +93,6 @@ protected internal virtual void ResetCacheAndFlags(ITextSnapshot? newSnapshotToC Snapshot = newSnapshotToCache; } - protected virtual bool CheckIfRetaggingIsNotNecessary(ITextSnapshot newSnapshotToTag) => - CacheCheckingEnabled && Snapshot != null && Snapshot == newSnapshotToTag && !ColoringSettingsChanged && LastTaggingWasSuccessful; - public virtual void Dispose() { if (!SubscribedToSettingsChanges) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index 886ccc20c..cb42f7324 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -168,6 +168,10 @@ private void UpdateWorkspaceAndStateIfNeeded() } } + protected virtual bool CheckIfParsingAndRetaggingIsNotNecessary(ITextSnapshot newSnapshotToTag) => + CacheCheckingEnabled && Snapshot != null && Snapshot == newSnapshotToTag && !ColoringSettingsChanged && + (LastTaggingWasSuccessful || BackgroundTagging?.IsTaskRunning() == true); + protected internal async Task>> GetTagsAsyncImplementationAsync(ITextSnapshot snapshot, CancellationToken cToken) { From 191bca75e800fa7e3cad0c834782fcae0fcb532e Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Wed, 13 May 2026 18:55:02 +0200 Subject: [PATCH 32/56] ATR-966: added Roslyn Workspace provider - a dedicated component for obtaining Roslyn workspace and tracking its changes --- .../Coloriser/Roslyn/ParsedSymbolsCache.cs | 3 +- .../Roslyn/RoslynWorkspaceProvider.cs | 100 ++++++++++++++++++ .../Roslyn/Utils/RoslynVSEditorExtensions.cs | 13 --- .../Roslyn/WorkspaceChangedEventArgs.cs | 13 +++ 4 files changed, 115 insertions(+), 14 deletions(-) create mode 100644 src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs create mode 100644 src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/WorkspaceChangedEventArgs.cs diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/ParsedSymbolsCache.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/ParsedSymbolsCache.cs index 9a1f26c3d..99d00175a 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/ParsedSymbolsCache.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/ParsedSymbolsCache.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +#nullable enable +using System.Collections.Generic; using System.Runtime.CompilerServices; using Acuminator.Utilities.Roslyn.Constants; diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs new file mode 100644 index 000000000..da28090bd --- /dev/null +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs @@ -0,0 +1,100 @@ +#nullable enable +using System; +using System.Collections.Generic; + +using Acuminator.Utilities.Common; + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; +using Microsoft.VisualStudio.Text; + +namespace Acuminator.Vsix.Coloriser; + +/// +/// A Roslyn workspace provider that tracks workspace changes. +/// +internal class RoslynWorkspaceProvider : IDisposable +{ + private readonly ITextBuffer _buffer; + private readonly WorkspaceRegistration _workspaceRegistration; + + private readonly object _locker = new object(); + private Workspace? _workspace; + + public Workspace? Workspace + { + get + { + lock (_locker) + { + return _workspace; + } + } + private set + { + if (!ReferenceEquals(_workspace, value)) + { + lock (_locker) + { + if (!ReferenceEquals(value, _workspace)) + { + _workspace = value; + } + } + } + } + } + + public event EventHandler? WorkspaceChanged; + + public RoslynWorkspaceProvider(ITextBuffer buffer) + { + _buffer = buffer.CheckIfNull(); + + SourceTextContainer sourceTextContainer = _buffer.AsTextContainer(); + _workspaceRegistration = Workspace.GetWorkspaceRegistration(sourceTextContainer); + _workspaceRegistration.WorkspaceChanged += OnWorkspaceChanged; + + Workspace = GetWorkspaceThatSupportsColoring(_workspaceRegistration); + } + + private void OnWorkspaceChanged(object sender, EventArgs e) + { + Workspace? newWorkspace = GetWorkspaceThatSupportsColoring(_workspaceRegistration); + Workspace? oldWorkspace; + + lock (_locker) + { + oldWorkspace = _workspace; + + // Swallow event if the workspace didn't really change or if it changed to another workspace that doesn't support coloring + if (ReferenceEquals(oldWorkspace, newWorkspace)) + return; + + _workspace = newWorkspace; + } + + WorkspaceChangedEventArgs eventArgs = new(oldWorkspace, newWorkspace); + WorkspaceChanged?.Invoke(this, eventArgs); + } + + public void Dispose() + { + WorkspaceChanged = null; + Workspace = null; + _workspaceRegistration.WorkspaceChanged -= OnWorkspaceChanged; + } + + private static Workspace? GetWorkspaceThatSupportsColoring(WorkspaceRegistration workspaceRegistration) + { + var workspace = workspaceRegistration.Workspace; + + if (workspace == null) + return null; + + const string previewWorkspaceKind = "MiscellaneousFiles"; + return previewWorkspaceKind.Equals(workspace.Kind, StringComparison.OrdinalIgnoreCase) + ? null + : workspace; + } +} diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/Utils/RoslynVSEditorExtensions.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/Utils/RoslynVSEditorExtensions.cs index d87474f14..8edf08ebc 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/Utils/RoslynVSEditorExtensions.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/Utils/RoslynVSEditorExtensions.cs @@ -44,18 +44,5 @@ public static ITagSpan ToOutliningTagSpan(this TextSpan spa public static string GetText(this ITextSnapshot snapshot, TextSpan span) => snapshot.GetText(span.Start, span.Length); - - public static Workspace? GetWorkspaceThatSupportsColoring(this ITextBuffer? buffer) - { - var workspace = buffer?.GetWorkspace(); - - if (workspace == null) - return null; - - const string previewWorkspaceKind = "MiscellaneousFiles"; - return previewWorkspaceKind.Equals(workspace.Kind, StringComparison.OrdinalIgnoreCase) - ? null - : workspace; - } } } diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/WorkspaceChangedEventArgs.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/WorkspaceChangedEventArgs.cs new file mode 100644 index 000000000..c55be25d4 --- /dev/null +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/WorkspaceChangedEventArgs.cs @@ -0,0 +1,13 @@ +#nullable enable +using System; + +using Microsoft.CodeAnalysis; + +namespace Acuminator.Vsix.Coloriser; + +public class WorkspaceChangedEventArgs(Workspace? oldWorkspace, Workspace? newWorkspace) : EventArgs() +{ + public Workspace? OldWorkspace { get; } = oldWorkspace; + + public Workspace? NewWorkspace { get; } = newWorkspace; +} From 17853549906c92563dd3f12649f580819dae46c0 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Wed, 13 May 2026 19:13:45 +0200 Subject: [PATCH 33/56] ATR-966: integrated Roslyn workspace provider into the Roslyn coloring tagger --- .../Coloriser/PXRoslynColorizerTagger.cs | 46 +++++++++++++++---- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index cb42f7324..fbbfe4f60 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -15,6 +15,8 @@ using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Tagging; +using ThreadHelper = Microsoft.VisualStudio.Shell.ThreadHelper; + namespace Acuminator.Vsix.Coloriser; /// @@ -36,22 +38,24 @@ internal partial class PXRoslynColorizerTagger : PXTaggerBase, ITagger(); OutliningsTagsCache = new TagsCacheAsync(); - RoslynWorkspace = Buffer.GetWorkspaceThatSupportsColoring(); - if (RoslynWorkspace != null) + _roslynWorkspaceProvider = new RoslynWorkspaceProvider(buffer); + _roslynWorkspaceProvider.WorkspaceChanged += WorkspaceAttachedToDocumentChanged; + var currentWorkspace = _roslynWorkspaceProvider.Workspace; + + if (currentWorkspace != null) { - _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(projectId: null); - RoslynWorkspace.WorkspaceChanged += OnWorkspaceChanged; + _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(currentWorkspace, projectId: null); + currentWorkspace.WorkspaceChanged += OnWorkspaceChanged; } //Buffer.Changed += Buffer_Changed; @@ -221,11 +225,15 @@ public override void Dispose() ClassificationTagsCache?.Reset(); OutliningsTagsCache?.Reset(); - if (RoslynWorkspace != null) - { - RoslynWorkspace.WorkspaceChanged -= OnWorkspaceChanged; - } + var workspace = _roslynWorkspaceProvider.Workspace; + if (workspace != null) + workspace.WorkspaceChanged -= OnWorkspaceChanged; + + _roslynWorkspaceProvider.WorkspaceChanged -= WorkspaceAttachedToDocumentChanged; + _roslynWorkspaceProvider.Dispose(); + + _hasReferenceToAcumaticaPlatform = false; base.Dispose(); } @@ -268,7 +276,25 @@ private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) { ResetCacheAndFlags(newSnapshotToCache: null); RaiseTagsChanged(); + private void WorkspaceAttachedToDocumentChanged(object sender, WorkspaceChangedEventArgs e) + { + if (e.OldWorkspace != null) + e.OldWorkspace.WorkspaceChanged -= OnWorkspaceChanged; + + // if new Workspace supports coloring, we need to subscribe to workspace events and calculate the hasReferenceToAcumaticaPlatform flag. + if (e.NewWorkspace != null) + { + e.NewWorkspace.WorkspaceChanged += OnWorkspaceChanged; + _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(e.NewWorkspace, projectId: null); } + else + { + _hasReferenceToAcumaticaPlatform = false; + } + + // We need to raise the tags changed event to trigger re-coloring on workspace change + ResetCacheAndFlags(newSnapshotToCache: null); + ThreadHelper.JoinableTaskFactory.Run(RaiseTagsChangedAsync); } protected bool CheckIfCurrentSolutionHasReferenceToAcumatica(ProjectId? projectId) From 02e168b07bb65dbbadb9d0a3c755f71bffafc2bb Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Wed, 13 May 2026 19:15:52 +0200 Subject: [PATCH 34/56] ATR-966: refactoring - renamed event args --- .../Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs | 1 + .../Coloriser/Roslyn/RoslynWorkspaceProvider.cs | 4 ++-- .../Coloriser/Roslyn/WorkspaceChangedEventArgs.cs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index fbbfe4f60..6153a93e4 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -277,6 +277,7 @@ private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) ResetCacheAndFlags(newSnapshotToCache: null); RaiseTagsChanged(); private void WorkspaceAttachedToDocumentChanged(object sender, WorkspaceChangedEventArgs e) + private void WorkspaceAttachedToDocumentChanged(object sender, DocumentWorkspaceChangedEventArgs e) { if (e.OldWorkspace != null) e.OldWorkspace.WorkspaceChanged -= OnWorkspaceChanged; diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs index da28090bd..d169e7cdf 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs @@ -45,7 +45,7 @@ private set } } - public event EventHandler? WorkspaceChanged; + public event EventHandler? WorkspaceChanged; public RoslynWorkspaceProvider(ITextBuffer buffer) { @@ -74,7 +74,7 @@ private void OnWorkspaceChanged(object sender, EventArgs e) _workspace = newWorkspace; } - WorkspaceChangedEventArgs eventArgs = new(oldWorkspace, newWorkspace); + DocumentWorkspaceChangedEventArgs eventArgs = new(oldWorkspace, newWorkspace); WorkspaceChanged?.Invoke(this, eventArgs); } diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/WorkspaceChangedEventArgs.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/WorkspaceChangedEventArgs.cs index c55be25d4..43e942c30 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/WorkspaceChangedEventArgs.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/WorkspaceChangedEventArgs.cs @@ -5,7 +5,7 @@ namespace Acuminator.Vsix.Coloriser; -public class WorkspaceChangedEventArgs(Workspace? oldWorkspace, Workspace? newWorkspace) : EventArgs() +public class DocumentWorkspaceChangedEventArgs(Workspace? oldWorkspace, Workspace? newWorkspace) : EventArgs() { public Workspace? OldWorkspace { get; } = oldWorkspace; From 77764a17300ceaf8e78f8d87ca218018d5be89c9 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Wed, 13 May 2026 19:35:52 +0200 Subject: [PATCH 35/56] ATR-966: integration of roslyn workspace provider into tagger - part 2 --- .../Coloriser/PXRoslynColorizerTagger.cs | 35 ++++--------------- 1 file changed, 6 insertions(+), 29 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index 6153a93e4..9ed2b5838 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -120,18 +120,17 @@ protected internal override void ResetCacheAndFlags(ITextSnapshot? newSnapshotTo /// public IEnumerable> GetTags(NormalizedSnapshotSpanCollection spans) { - if (spans?.Count is null or 0 || AcuminatorVSPackage.Instance?.ColoringEnabled != true) + if (spans?.Count is null or 0 || AcuminatorVSPackage.Instance?.ColoringEnabled != true || !HasReferenceToAcumaticaPlatform) return []; - // If Roslyn workspace wasn't initialized yet, we need to try to initialize it. - UpdateWorkspaceAndStateIfNeeded(); - - if (RoslynWorkspace == null || !HasReferenceToAcumaticaPlatform) + var workspace = _roslynWorkspaceProvider.Workspace; + + if (workspace == null) return []; ITextSnapshot newSnapshotToTag = spans[0].Snapshot; - if (CheckIfRetaggingIsNotNecessary(newSnapshotToTag)) + if (CheckIfParsingAndRetaggingIsNotNecessary(newSnapshotToTag)) { return ClassificationTagsCache.ProcessedTags; } @@ -148,29 +147,7 @@ public IEnumerable> GetTags(NormalizedSnapshotSpanC return ClassificationTagsCache.ProcessedTags; } - private void UpdateWorkspaceAndStateIfNeeded() - { - Workspace? currentBufferWorkspace = Buffer.GetWorkspaceThatSupportsColoring(); - - if (ReferenceEquals(RoslynWorkspace, currentBufferWorkspace)) - return; - - if (RoslynWorkspace != null) - RoslynWorkspace.WorkspaceChanged -= OnWorkspaceChanged; - - RoslynWorkspace = currentBufferWorkspace; - - // If initialization was successful, we need to subscribe to workspace events and calculate the hasReferenceToAcumaticaPlatform flag. - if (RoslynWorkspace != null) - { - RoslynWorkspace.WorkspaceChanged += OnWorkspaceChanged; - _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(projectId: null); - } - else - { - _hasReferenceToAcumaticaPlatform = false; - } - } + protected virtual bool CheckIfParsingAndRetaggingIsNotNecessary(ITextSnapshot newSnapshotToTag) => CacheCheckingEnabled && Snapshot != null && Snapshot == newSnapshotToTag && !ColoringSettingsChanged && From 7b29cfe4fd2ced9314a78e5bb16cacce6e700245 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Wed, 13 May 2026 19:37:27 +0200 Subject: [PATCH 36/56] ATR-966: reverting the start of the thread pool operation to how it was before --- .../Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index 9ed2b5838..548b19bbb 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -174,17 +174,14 @@ protected internal async Task>> GetTags if (document == null || cToken.IsCancellationRequested) return ClassificationTagsCache.ProcessedTags; - bool completedSuccessfully = await WalkDocumentSyntaxTreeForTagsOnThreadpoolAsync(document, cToken).TryAwait(); + bool completedSuccessfully = await WalkDocumentSyntaxTreeForTagsOnThreadPoolAsync(document, cToken).TryAwait(); LastTaggingWasSuccessful = completedSuccessfully && ClassificationTagsCache.IsCompleted; return ClassificationTagsCache.ProcessedTags; } private Task WalkDocumentSyntaxTreeForTagsOnThreadPoolAsync(ParsedDocument document, CancellationToken cancellationToken) { - return Task.Factory.StartNew(() => WalkDocumentSyntaxTreeForTags(document, cancellationToken), - cancellationToken, - TaskCreationOptions.LongRunning, - TaskScheduler.Default); + return Task.Run(() => WalkDocumentSyntaxTreeForTags(document, cancellationToken)); } private void WalkDocumentSyntaxTreeForTags(ParsedDocument document, CancellationToken cancellationToken) From 2089037ded43e9c3a92161e3688be076f77f537b Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Wed, 13 May 2026 19:39:59 +0200 Subject: [PATCH 37/56] ATR-966: reworked workspace changed checks to use faster checks that should not try to obtain compilation --- .../Coloriser/PXRoslynColorizerTagger.cs | 64 ++++++++++--------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index 548b19bbb..39488344f 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -7,7 +7,6 @@ using System.Threading.Tasks; using Acuminator.Utilities.Common; -using Acuminator.Utilities.Roslyn.Constants; using Acuminator.Utilities.Roslyn.ProjectSystem; using Microsoft.CodeAnalysis; @@ -224,20 +223,23 @@ private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) case WorkspaceChangeKind.SolutionAdded: case WorkspaceChangeKind.ProjectAdded: - _hasReferenceToAcumaticaPlatform |= CheckIfCurrentSolutionHasReferenceToAcumatica(e.ProjectId); + _hasReferenceToAcumaticaPlatform |= CheckIfCurrentSolutionHasReferenceToAcumatica( + _roslynWorkspaceProvider.Workspace, e.ProjectId); break; case WorkspaceChangeKind.SolutionChanged: case WorkspaceChangeKind.SolutionReloaded: case WorkspaceChangeKind.ProjectRemoved: - _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(e.ProjectId); + _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica( + _roslynWorkspaceProvider.Workspace, e.ProjectId); break; case WorkspaceChangeKind.ProjectChanged: case WorkspaceChangeKind.ProjectReloaded: if (e.IsProjectMetadataChanged()) { - _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(e.ProjectId); + _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica( + _roslynWorkspaceProvider.Workspace, e.ProjectId); } break; @@ -246,11 +248,13 @@ private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) return; } - if (Buffer.CurrentSnapshot != null && (oldValue != _hasReferenceToAcumaticaPlatform || !LastTaggingWasSuccessful)) + if (oldValue != _hasReferenceToAcumaticaPlatform) { ResetCacheAndFlags(newSnapshotToCache: null); - RaiseTagsChanged(); - private void WorkspaceAttachedToDocumentChanged(object sender, WorkspaceChangedEventArgs e) + ThreadHelper.JoinableTaskFactory.Run(RaiseTagsChangedAsync); + } + } + private void WorkspaceAttachedToDocumentChanged(object sender, DocumentWorkspaceChangedEventArgs e) { if (e.OldWorkspace != null) @@ -272,35 +276,42 @@ private void WorkspaceAttachedToDocumentChanged(object sender, DocumentWorkspace ThreadHelper.JoinableTaskFactory.Run(RaiseTagsChangedAsync); } - protected bool CheckIfCurrentSolutionHasReferenceToAcumatica(ProjectId? projectId) + protected bool CheckIfCurrentSolutionHasReferenceToAcumatica(Workspace? workspace, ProjectId? projectId) { - var currentSolution = RoslynWorkspace?.CurrentSolution; + var currentSolution = workspace?.CurrentSolution; if (currentSolution == null || currentSolution.ProjectIds.Count == 0) return false; - var roslynDocument = Buffer.CurrentSnapshot?.GetOpenDocumentInCurrentContextWithChanges(); - var currentProject = roslynDocument?.Project; bool allProjectsChanged = projectId == null; if (allProjectsChanged) { + bool hasReferenceInMetadata = currentSolution.Projects.SelectMany(project => project.MetadataReferences) + .Any(IsAcumaticaAssemblyName); + if (hasReferenceInMetadata) + return true; + bool hasAcumaticaProjectsInSolution = currentSolution.Projects.Any(project => IsAcumaticaAssemblyName(project.Name) || IsAcumaticaAssemblyName(project.AssemblyName)); - if (hasAcumaticaProjectsInSolution) - return true; - - bool hasReferenceInMetadata = (from project in currentSolution.Projects - from reference in project.MetadataReferences - select Path.GetFileNameWithoutExtension(reference.Display)) - .Any(reference => IsAcumaticaAssemblyName(reference)); - return hasReferenceInMetadata; + return hasAcumaticaProjectsInSolution; } - else if (currentProject?.Id == projectId) // Check that the changed project is the same as the project of the current document. If not, then return the old value. + + if (Buffer.CurrentSnapshot == null) + return false; + + SourceTextContainer sourceTextContainer = Buffer.AsTextContainer(); + var documentId = workspace!.GetDocumentIdInCurrentContext(sourceTextContainer); + + if (documentId == null) + return false; + else if (documentId.ProjectId == projectId) // Check that the changed project is the same as the project of the current document. If not, then return the old value. { - if (CanCreateGraphFastCheck(currentProject!) is bool canCreateGraph) - return canCreateGraph; + Project? currentProject = currentSolution.GetProject(projectId); + + if (currentProject == null) + return false; bool hasReferenceInMetadata = currentProject!.MetadataReferences.Count > 0 ? currentProject.MetadataReferences.Any(IsAcumaticaAssemblyName) @@ -324,13 +335,4 @@ private static bool IsAcumaticaAssemblyName(MetadataReference reference) private static bool IsAcumaticaAssemblyName(string dllName) => ColoringConstants.PlatformDllName == dllName || ColoringConstants.AppDllName == dllName; - - private static bool? CanCreateGraphFastCheck(Project project) - { - if (!project.TryGetCompilation(out var compilation) || compilation == null) - return null; - - var graphType = compilation.GetTypeByMetadataName(TypeFullNames.PXGraph); - return graphType != null; - } } From 3171f4c508f13c318417788c699c3078b60bc1c7 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Thu, 14 May 2026 02:00:54 +0200 Subject: [PATCH 38/56] ATR-966: fixed AI remark by always recalculating HasReferenceToAcumaticaPlatform flag for the entire solution --- .../Coloriser/PXRoslynColorizerTagger.cs | 62 ++++--------------- 1 file changed, 13 insertions(+), 49 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index 39488344f..dd58575bd 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -53,7 +53,7 @@ public PXRoslynColorizerTagger(ITextBuffer buffer, PXColorizerTaggerProvider pro if (currentWorkspace != null) { - _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(currentWorkspace, projectId: null); + _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(currentWorkspace); currentWorkspace.WorkspaceChanged += OnWorkspaceChanged; } @@ -223,23 +223,20 @@ private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) case WorkspaceChangeKind.SolutionAdded: case WorkspaceChangeKind.ProjectAdded: - _hasReferenceToAcumaticaPlatform |= CheckIfCurrentSolutionHasReferenceToAcumatica( - _roslynWorkspaceProvider.Workspace, e.ProjectId); + _hasReferenceToAcumaticaPlatform |= CheckIfCurrentSolutionHasReferenceToAcumatica(_roslynWorkspaceProvider.Workspace); break; case WorkspaceChangeKind.SolutionChanged: case WorkspaceChangeKind.SolutionReloaded: case WorkspaceChangeKind.ProjectRemoved: - _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica( - _roslynWorkspaceProvider.Workspace, e.ProjectId); + _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(_roslynWorkspaceProvider.Workspace); break; case WorkspaceChangeKind.ProjectChanged: case WorkspaceChangeKind.ProjectReloaded: if (e.IsProjectMetadataChanged()) { - _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica( - _roslynWorkspaceProvider.Workspace, e.ProjectId); + _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(_roslynWorkspaceProvider.Workspace); } break; @@ -264,7 +261,7 @@ private void WorkspaceAttachedToDocumentChanged(object sender, DocumentWorkspace if (e.NewWorkspace != null) { e.NewWorkspace.WorkspaceChanged += OnWorkspaceChanged; - _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(e.NewWorkspace, projectId: null); + _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(e.NewWorkspace); } else { @@ -276,55 +273,22 @@ private void WorkspaceAttachedToDocumentChanged(object sender, DocumentWorkspace ThreadHelper.JoinableTaskFactory.Run(RaiseTagsChangedAsync); } - protected bool CheckIfCurrentSolutionHasReferenceToAcumatica(Workspace? workspace, ProjectId? projectId) + protected bool CheckIfCurrentSolutionHasReferenceToAcumatica(Workspace? workspace) { var currentSolution = workspace?.CurrentSolution; if (currentSolution == null || currentSolution.ProjectIds.Count == 0) return false; - bool allProjectsChanged = projectId == null; + bool hasReferenceInMetadata = currentSolution.Projects.SelectMany(project => project.MetadataReferences) + .Any(IsAcumaticaAssemblyName); + if (hasReferenceInMetadata) + return true; - if (allProjectsChanged) - { - bool hasReferenceInMetadata = currentSolution.Projects.SelectMany(project => project.MetadataReferences) - .Any(IsAcumaticaAssemblyName); - if (hasReferenceInMetadata) - return true; - - bool hasAcumaticaProjectsInSolution = - currentSolution.Projects.Any(project => IsAcumaticaAssemblyName(project.Name) || IsAcumaticaAssemblyName(project.AssemblyName)); - - return hasAcumaticaProjectsInSolution; - } + bool hasAcumaticaProjectsInSolution = + currentSolution.Projects.Any(project => IsAcumaticaAssemblyName(project.Name) || IsAcumaticaAssemblyName(project.AssemblyName)); - if (Buffer.CurrentSnapshot == null) - return false; - - SourceTextContainer sourceTextContainer = Buffer.AsTextContainer(); - var documentId = workspace!.GetDocumentIdInCurrentContext(sourceTextContainer); - - if (documentId == null) - return false; - else if (documentId.ProjectId == projectId) // Check that the changed project is the same as the project of the current document. If not, then return the old value. - { - Project? currentProject = currentSolution.GetProject(projectId); - - if (currentProject == null) - return false; - - bool hasReferenceInMetadata = currentProject!.MetadataReferences.Count > 0 - ? currentProject.MetadataReferences.Any(IsAcumaticaAssemblyName) - : false; - - if (hasReferenceInMetadata) - return true; - - bool isAcumaticaProject = IsAcumaticaAssemblyName(currentProject.Name) || IsAcumaticaAssemblyName(currentProject.AssemblyName); - return isAcumaticaProject; - } - else - return _hasReferenceToAcumaticaPlatform; + return hasAcumaticaProjectsInSolution; } private static bool IsAcumaticaAssemblyName(MetadataReference reference) From 9af304c05ca3ed10426e6ecc88f653489979c0df Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Thu, 14 May 2026 02:12:26 +0200 Subject: [PATCH 39/56] ATR-966: fixes suggested by Claude AI --- .../Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs | 2 +- .../Coloriser/Roslyn/RoslynWorkspaceProvider.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index dd58575bd..cc6a0281b 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -31,7 +31,7 @@ internal partial class PXRoslynColorizerTagger : PXTaggerBase, ITagger _hasReferenceToAcumaticaPlatform; diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs index d169e7cdf..3d5cc6edc 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs @@ -36,7 +36,7 @@ private set { lock (_locker) { - if (!ReferenceEquals(value, _workspace)) + if (!ReferenceEquals(_workspace, value)) { _workspace = value; } @@ -81,8 +81,8 @@ private void OnWorkspaceChanged(object sender, EventArgs e) public void Dispose() { WorkspaceChanged = null; - Workspace = null; _workspaceRegistration.WorkspaceChanged -= OnWorkspaceChanged; + Workspace = null; } private static Workspace? GetWorkspaceThatSupportsColoring(WorkspaceRegistration workspaceRegistration) From 1bfd667c38bb3f7769d5ccdd667d4bd9983bef51 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Thu, 14 May 2026 02:17:22 +0200 Subject: [PATCH 40/56] ATR-966: fixed calculation of HasReferenceToAcumaticaPlatform from the AI remark --- .../Coloriser/PXRoslynColorizerTagger.cs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index cc6a0281b..8c6197b90 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -222,23 +222,13 @@ private void OnWorkspaceChanged(object sender, WorkspaceChangeEventArgs e) break; case WorkspaceChangeKind.SolutionAdded: - case WorkspaceChangeKind.ProjectAdded: - _hasReferenceToAcumaticaPlatform |= CheckIfCurrentSolutionHasReferenceToAcumatica(_roslynWorkspaceProvider.Workspace); - break; - case WorkspaceChangeKind.SolutionChanged: case WorkspaceChangeKind.SolutionReloaded: + case WorkspaceChangeKind.ProjectAdded: case WorkspaceChangeKind.ProjectRemoved: - _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(_roslynWorkspaceProvider.Workspace); - break; - case WorkspaceChangeKind.ProjectChanged: case WorkspaceChangeKind.ProjectReloaded: - if (e.IsProjectMetadataChanged()) - { - _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(_roslynWorkspaceProvider.Workspace); - } - + _hasReferenceToAcumaticaPlatform = CheckIfCurrentSolutionHasReferenceToAcumatica(_roslynWorkspaceProvider.Workspace); break; default: From 853e1245d85a5821a6384db910d26680f2149e24 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Thu, 14 May 2026 18:05:10 +0200 Subject: [PATCH 41/56] ATR-966: added unwrapping of the continuation task from the AI suggestions + added explanation from the Copilot --- .../Coloriser/AsyncTagging/BackgroundTagging.cs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/BackgroundTagging.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/BackgroundTagging.cs index a93aea273..72d583c5d 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/BackgroundTagging.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/AsyncTagging/BackgroundTagging.cs @@ -44,10 +44,22 @@ public static BackgroundTagging StartBackgroundTagging(PXRoslynColorizerTagger t // No need for synchronization because FromCurrentSynchronizationContext creates schedulers which wrap around the same synchronization context // Therefore all schedulers should be identical and nothing wrong will happen if different thread will create multiple instance of the scheduler in a race condition _vsTaskScheduler = _vsTaskScheduler ?? TaskScheduler.FromCurrentSynchronizationContext(); - backgroundTagging.TaggingTask = taggingTask.ContinueWith(task => AfterTaggingActionAsync(task, tagger, backgroundTagging.CancellationToken), //continuation should be on the UI thread + var continuationTask = taggingTask.ContinueWith(task => AfterTaggingActionAsync(task, tagger, backgroundTagging.CancellationToken), //continuation should be on the UI thread backgroundTagging.CancellationToken, TaskContinuationOptions.NotOnCanceled, _vsTaskScheduler); + + // ContinueWith schedules the lambda on the VS UI thread scheduler. The lambda runs on the UI thread and calls AfterTaggingActionAsync(...). + // Inside AfterTaggingActionAsync, the important path calls ThreadHelper.JoinableTaskFactory.RunAsync(tagger.RaiseTagsChangedAsync).Task + // this starts RaiseTagsChangedAsync and immediately returns the underlying Task representing it (still running). + // The lambda returns that inner Task immediately — it does not await it. + // The outer Task stored in TaggingTask is marked as Completed (RanToCompletion) at this point, because the lambda has returned. + // The outer task's result is the still-running inner task, but the outer task itself is done. + // RaiseTagsChangedAsync may still be running in the background raising tags-changed notifications. + // + // Thus, we need to keep the nested unwrapped task as the tagging task to be able to correctly calculate IsTaskRunning() and + // handle exceptions thrown in the AfterTaggingActionAsync. + backgroundTagging.TaggingTask = continuationTask.Unwrap(); return backgroundTagging; } From 484ac471151c26b4483f7a30ad2374aa38abd1d5 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Thu, 14 May 2026 18:43:31 +0200 Subject: [PATCH 42/56] ATR-966: reworked the disposal and unsubscribing logic after review from Claude AI --- .../Coloriser/PXRoslynColorizerTagger.cs | 11 +------- .../Roslyn/RoslynWorkspaceProvider.cs | 27 +++++++++++++++++-- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index 8c6197b90..741b5a7a7 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -7,10 +7,8 @@ using System.Threading.Tasks; using Acuminator.Utilities.Common; -using Acuminator.Utilities.Roslyn.ProjectSystem; using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Text; using Microsoft.VisualStudio.Text.Tagging; @@ -198,15 +196,8 @@ public override void Dispose() ClassificationTagsCache?.Reset(); OutliningsTagsCache?.Reset(); - var workspace = _roslynWorkspaceProvider.Workspace; - - if (workspace != null) - workspace.WorkspaceChanged -= OnWorkspaceChanged; - - _roslynWorkspaceProvider.WorkspaceChanged -= WorkspaceAttachedToDocumentChanged; - _roslynWorkspaceProvider.Dispose(); - _hasReferenceToAcumaticaPlatform = false; + _roslynWorkspaceProvider.Dispose(); base.Dispose(); } diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs index 3d5cc6edc..fbeeab6de 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Acuminator.Utilities.Common; +using Acuminator.Vsix.Logger; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text; @@ -75,14 +76,36 @@ private void OnWorkspaceChanged(object sender, EventArgs e) } DocumentWorkspaceChangedEventArgs eventArgs = new(oldWorkspace, newWorkspace); - WorkspaceChanged?.Invoke(this, eventArgs); + InvokeWorkspaceChangedEventSafely(eventArgs); } public void Dispose() { - WorkspaceChanged = null; _workspaceRegistration.WorkspaceChanged -= OnWorkspaceChanged; + + // Clear workspace reference to prevent any external usage after disposal + var oldWorkspace = Workspace; Workspace = null; + + // Let subscribers know that the workspace is no longer available due to disposal and unsubscribe from events to prevent memory leaks + DocumentWorkspaceChangedEventArgs disposalEventArgs = new(oldWorkspace, null); + InvokeWorkspaceChangedEventSafely(disposalEventArgs); + + // Clear event subscribers + WorkspaceChanged = null; + } + + private void InvokeWorkspaceChangedEventSafely(DocumentWorkspaceChangedEventArgs eventArgs) + { + try + { + WorkspaceChanged?.Invoke(this, eventArgs); + } + catch (Exception exception) + { + AcuminatorVSPackage.Instance.AcuminatorLogger.LogException(exception, logOnlyFromAcuminatorAssemblies: false, + LogMode.Warning); + } } private static Workspace? GetWorkspaceThatSupportsColoring(WorkspaceRegistration workspaceRegistration) From 5dc8567d83795315146777937e40a69db9834c8e Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Thu, 14 May 2026 18:51:31 +0200 Subject: [PATCH 43/56] ATR-966: added diagnostic failure message from Claude suggestion --- .../Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs index ffea0f188..0ecf4b4e4 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Base/PXTaggerBase.cs @@ -1,6 +1,7 @@ #nullable enable using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Threading.Tasks; @@ -73,7 +74,11 @@ internal async Task RaiseTagsChangedAsync() internal void RaiseTagsChanged() { if (!ThreadHelper.CheckAccess()) + { + Debug.Fail("RaiseTagsChanged should be called from the UI thread. " + + "Call RaiseTagsChangedAsync if you need to raise tags changed from a background thread."); return; + } RaiseTagsChangedImpl(); } From 3f6095635d4a5b9ed1128a2e3a5bdcc73e487cbb Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Thu, 14 May 2026 18:56:02 +0200 Subject: [PATCH 44/56] ATR-966: added synchronization for access to the shared LastTaggingWasSuccessful flag (Claude remark) --- .../Coloriser/PXRoslynColorizerTagger.cs | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index 741b5a7a7..57a999bb3 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -33,7 +33,26 @@ internal partial class PXRoslynColorizerTagger : PXTaggerBase, ITagger _hasReferenceToAcumaticaPlatform; - internal override bool LastTaggingWasSuccessful { get; set; } + private readonly object _lastTaggingLock = new object(); + private volatile bool _lastTaggingWasSuccessful; + + internal override bool LastTaggingWasSuccessful + { + get + { + lock (_lastTaggingLock) + { + return _lastTaggingWasSuccessful; + } + } + set + { + lock (_lastTaggingLock) + { + _lastTaggingWasSuccessful = value; + } + } + } private readonly RoslynWorkspaceProvider _roslynWorkspaceProvider; From 5756e0a34873921ce15dee87a76b4d3efac2653d Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Thu, 14 May 2026 19:16:58 +0200 Subject: [PATCH 45/56] ATR-966: removed unused _buffer field from Claude remark --- .../Coloriser/Roslyn/RoslynWorkspaceProvider.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs index fbeeab6de..21ac0834f 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs @@ -16,7 +16,6 @@ namespace Acuminator.Vsix.Coloriser; /// internal class RoslynWorkspaceProvider : IDisposable { - private readonly ITextBuffer _buffer; private readonly WorkspaceRegistration _workspaceRegistration; private readonly object _locker = new object(); @@ -50,9 +49,7 @@ private set public RoslynWorkspaceProvider(ITextBuffer buffer) { - _buffer = buffer.CheckIfNull(); - - SourceTextContainer sourceTextContainer = _buffer.AsTextContainer(); + SourceTextContainer sourceTextContainer = buffer.CheckIfNull().AsTextContainer(); _workspaceRegistration = Workspace.GetWorkspaceRegistration(sourceTextContainer); _workspaceRegistration.WorkspaceChanged += OnWorkspaceChanged; From 830da86066b01c6962ead8bcf86a053c647602ee Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Thu, 14 May 2026 19:18:48 +0200 Subject: [PATCH 46/56] ATR-966: removed redundant setter for Workspace from the Claude suggestions --- .../Coloriser/Roslyn/RoslynWorkspaceProvider.cs | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs index 21ac0834f..e94314485 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs @@ -30,19 +30,6 @@ public Workspace? Workspace return _workspace; } } - private set - { - if (!ReferenceEquals(_workspace, value)) - { - lock (_locker) - { - if (!ReferenceEquals(_workspace, value)) - { - _workspace = value; - } - } - } - } } public event EventHandler? WorkspaceChanged; @@ -53,7 +40,7 @@ public RoslynWorkspaceProvider(ITextBuffer buffer) _workspaceRegistration = Workspace.GetWorkspaceRegistration(sourceTextContainer); _workspaceRegistration.WorkspaceChanged += OnWorkspaceChanged; - Workspace = GetWorkspaceThatSupportsColoring(_workspaceRegistration); + _workspace = GetWorkspaceThatSupportsColoring(_workspaceRegistration); } private void OnWorkspaceChanged(object sender, EventArgs e) @@ -82,7 +69,7 @@ public void Dispose() // Clear workspace reference to prevent any external usage after disposal var oldWorkspace = Workspace; - Workspace = null; + _workspace = null; // Let subscribers know that the workspace is no longer available due to disposal and unsubscribe from events to prevent memory leaks DocumentWorkspaceChangedEventArgs disposalEventArgs = new(oldWorkspace, null); From 96a6f0ac26680c1edd5e197e3b371487c699ce70 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Thu, 14 May 2026 20:18:48 +0200 Subject: [PATCH 47/56] ATR-966: reworked contention race in the tagger counstuctor with the help of Claude --- .../Coloriser/PXRoslynColorizerTagger.cs | 58 +++++++++++++------ 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index 57a999bb3..cab9c42dd 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -36,6 +36,9 @@ internal partial class PXRoslynColorizerTagger : PXTaggerBase, ITagger Date: Thu, 14 May 2026 20:20:45 +0200 Subject: [PATCH 48/56] ATR-966: fixed nulalble ValueTask as per Claude suggestions --- .../Common/Concurrent/ConcurrentExtensions.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Acuminator/Acuminator.Utilities/Common/Concurrent/ConcurrentExtensions.cs b/src/Acuminator/Acuminator.Utilities/Common/Concurrent/ConcurrentExtensions.cs index 4205361b6..bbc384da5 100644 --- a/src/Acuminator/Acuminator.Utilities/Common/Concurrent/ConcurrentExtensions.cs +++ b/src/Acuminator/Acuminator.Utilities/Common/Concurrent/ConcurrentExtensions.cs @@ -59,14 +59,14 @@ public async static Task TryAwait(this Task? task, bool continueOnCaptured /// The task to act on. /// (Optional) True to continue on captured context. /// - public async static ValueTask TryAwait(this ValueTask? task, bool continueOnCapturedContext = false) + public async static ValueTask TryAwait(this ValueTask task, bool continueOnCapturedContext = false) { - if (task == null || task.Value.IsCanceled || task.Value.IsFaulted) + if (task.IsCanceled || task.IsFaulted) return false; try { - await task.Value.ConfigureAwait(continueOnCapturedContext); + await task.ConfigureAwait(continueOnCapturedContext); return true; } catch (Exception exception) @@ -106,15 +106,15 @@ public async static Task> TryAwait(this TaskThe task to act on. /// (Optional) True to continue on captured context. /// - public async static ValueTask> TryAwait(this ValueTask? task, + public async static ValueTask> TryAwait(this ValueTask task, bool continueOnCapturedContext = false) { - if (task == null || task.Value.IsCanceled || task.Value.IsFaulted) + if (task.IsCanceled || task.IsFaulted) return new TaskResult(false, default); try { - TResult? result = await task.Value.ConfigureAwait(continueOnCapturedContext); + TResult? result = await task.ConfigureAwait(continueOnCapturedContext); return new TaskResult(true, result); } catch (Exception exception) From e69a4bb0274453f147e3858f197c5894a0e16d69 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Thu, 14 May 2026 20:41:16 +0200 Subject: [PATCH 49/56] ATR-966: reworked disposal logic in the workspace provider and tagger from the Copilot review remarks --- .../Coloriser/PXRoslynColorizerTagger.cs | 11 ++++++----- .../Coloriser/Roslyn/RoslynWorkspaceProvider.cs | 16 ++++++---------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index cab9c42dd..7f3b4c50c 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -213,11 +213,6 @@ private void WalkDocumentSyntaxTreeForTags(ParsedDocument document, Cancellation public override void Dispose() { - BackgroundTagging?.Dispose(); - ClassificationTagsCache?.Reset(); - OutliningsTagsCache?.Reset(); - - _hasReferenceToAcumaticaPlatform = false; _roslynWorkspaceProvider.Dispose(); if (_subscribedWorkspace != null) @@ -232,6 +227,12 @@ public override void Dispose() } } + BackgroundTagging?.Dispose(); + ClassificationTagsCache?.Reset(); + OutliningsTagsCache?.Reset(); + + _hasReferenceToAcumaticaPlatform = false; + base.Dispose(); } diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs index e94314485..bd6fdd20f 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs @@ -66,17 +66,13 @@ private void OnWorkspaceChanged(object sender, EventArgs e) public void Dispose() { _workspaceRegistration.WorkspaceChanged -= OnWorkspaceChanged; - - // Clear workspace reference to prevent any external usage after disposal - var oldWorkspace = Workspace; - _workspace = null; - - // Let subscribers know that the workspace is no longer available due to disposal and unsubscribe from events to prevent memory leaks - DocumentWorkspaceChangedEventArgs disposalEventArgs = new(oldWorkspace, null); - InvokeWorkspaceChangedEventSafely(disposalEventArgs); - - // Clear event subscribers WorkspaceChanged = null; + + lock (_locker) + { + // Clear workspace reference to prevent any external usage after disposal + _workspace = null; + } } private void InvokeWorkspaceChangedEventSafely(DocumentWorkspaceChangedEventArgs eventArgs) From bfccbad3e0f20369ddb44fb9fdd3559ee5ef41a2 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Thu, 14 May 2026 20:47:44 +0200 Subject: [PATCH 50/56] ATR-966: fixes for minor Claude remarks --- .../Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs | 8 ++++---- .../Coloriser/Roslyn/RoslynWorkspaceProvider.cs | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index 7f3b4c50c..32fd84dfd 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -34,10 +34,7 @@ internal partial class PXRoslynColorizerTagger : PXTaggerBase, ITagger _hasReferenceToAcumaticaPlatform; private readonly object _lastTaggingLock = new object(); - private volatile bool _lastTaggingWasSuccessful; - - private volatile Workspace? _subscribedWorkspace; - private readonly object _workspaceSubscriptionLock = new(); + private bool _lastTaggingWasSuccessful; internal override bool LastTaggingWasSuccessful { @@ -57,6 +54,9 @@ internal override bool LastTaggingWasSuccessful } } + private volatile Workspace? _subscribedWorkspace; + private readonly object _workspaceSubscriptionLock = new(); + private readonly RoslynWorkspaceProvider _roslynWorkspaceProvider; public PXRoslynColorizerTagger(ITextBuffer buffer, PXColorizerTaggerProvider provider, bool subscribeToSettingsChanges, diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs index bd6fdd20f..990cbb75c 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/RoslynWorkspaceProvider.cs @@ -83,8 +83,8 @@ private void InvokeWorkspaceChangedEventSafely(DocumentWorkspaceChangedEventArgs } catch (Exception exception) { - AcuminatorVSPackage.Instance.AcuminatorLogger.LogException(exception, logOnlyFromAcuminatorAssemblies: false, - LogMode.Warning); + AcuminatorVSPackage.Instance?.AcuminatorLogger?.LogException(exception, logOnlyFromAcuminatorAssemblies: false, + LogMode.Warning); } } From 26aab1c9d9ae72e208be8df13c68f36dfb22f547 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Thu, 14 May 2026 21:01:37 +0200 Subject: [PATCH 51/56] ATR-966: added clearing of LastTaggingWasSuccessful from the Copilot remark --- .../Coloriser/PXRoslynColorizerTagger.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index 32fd84dfd..fb5b06bc2 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -177,20 +177,29 @@ protected internal async Task>> GetTags ClassificationTagsCache.SetCancellation(cToken); OutliningsTagsCache.SetCancellation(cToken); - Task getDocumentTask = ParsedDocument.ResolveAsync(snapshot, cToken); + Task getDocumentTask = ParsedDocument.ResolveAsync(snapshot, cToken); // Razor cshtml returns a null document for some reason. - if (cToken.IsCancellationRequested) // Razor cshtml returns a null document for some reason. - return ClassificationTagsCache.ProcessedTags; + if (cToken.IsCancellationRequested) + { + LastTaggingWasSuccessful = false; + return []; + } var documentTaskResult = await getDocumentTask.TryAwait(); if (!documentTaskResult.IsSuccess) - return ClassificationTagsCache.ProcessedTags; + { + LastTaggingWasSuccessful = false; + return []; + } ParsedDocument? document = documentTaskResult.Result; if (document == null || cToken.IsCancellationRequested) - return ClassificationTagsCache.ProcessedTags; + { + LastTaggingWasSuccessful = false; + return []; + } bool completedSuccessfully = await WalkDocumentSyntaxTreeForTagsOnThreadPoolAsync(document, cToken).TryAwait(); LastTaggingWasSuccessful = completedSuccessfully && ClassificationTagsCache.IsCompleted; From 8fe63929f55888b22500f88c1b0b839a5271696b Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Thu, 14 May 2026 22:23:47 +0200 Subject: [PATCH 52/56] ATR-966: reworked parsing of the document by the colorizer to handle last tagging successful indicator + added indicator of whether the parsed document supports tagging --- .../Coloriser/PXRoslynColorizerTagger.cs | 15 ++++++++-- .../Coloriser/Roslyn/ParsedDocument.cs | 28 ++++++++----------- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index fb5b06bc2..24d95cbfb 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -177,7 +177,12 @@ protected internal async Task>> GetTags ClassificationTagsCache.SetCancellation(cToken); OutliningsTagsCache.SetCancellation(cToken); - Task getDocumentTask = ParsedDocument.ResolveAsync(snapshot, cToken); // Razor cshtml returns a null document for some reason. + Workspace? workspace; + + lock (_workspaceSubscriptionLock) + { + workspace = _subscribedWorkspace; + } if (cToken.IsCancellationRequested) { @@ -185,6 +190,9 @@ protected internal async Task>> GetTags return []; } + Task<(ParsedDocument? Parsed, bool TaggingSupported)> getDocumentTask = + ParsedDocument.ResolveAsync(snapshot, workspace, cToken); // Razor cshtml returns a null document for some reason. + var documentTaskResult = await getDocumentTask.TryAwait(); if (!documentTaskResult.IsSuccess) @@ -193,11 +201,12 @@ protected internal async Task>> GetTags return []; } - ParsedDocument? document = documentTaskResult.Result; + var (document, taggingSupported) = documentTaskResult.Result; if (document == null || cToken.IsCancellationRequested) { - LastTaggingWasSuccessful = false; + // If the text buffer doesn't support tagging, we can mark tagging as successful to avoid repeated attempts + LastTaggingWasSuccessful = !taggingSupported; return []; } diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/ParsedDocument.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/ParsedDocument.cs index 43e28b427..9955ffcbe 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/ParsedDocument.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/ParsedDocument.cs @@ -5,6 +5,7 @@ using System.Threading.Tasks; using Acuminator.Utilities.Common; +using Acuminator.Utilities.Roslyn.Semantic; using Acuminator.Vsix.Utilities; using Microsoft.CodeAnalysis; @@ -33,32 +34,27 @@ public class ParsedDocument(Workspace workspace, Document document, SyntaxNode s public ITextSnapshot Snapshot { get; } = snapshot.CheckIfNull(); - public static async Task ResolveAsync(ITextSnapshot snapshot, CancellationToken cancellationToken) + public static async Task<(ParsedDocument? Parsed, bool TaggingSupported)> ResolveAsync(ITextSnapshot snapshot, Workspace? workspace, + CancellationToken cancellationToken) { - if (cancellationToken.IsCancellationRequested) - return null; + if (workspace == null || cancellationToken.IsCancellationRequested) + return (Parsed: null, TaggingSupported: true); - Workspace? workspace = await AcuminatorVSPackage.Instance.GetVSWorkspaceAsync() - .ConfigureAwait(false); Document? document = snapshot.GetOpenDocumentInCurrentContextWithChanges(); - if (workspace == null || document == null || !IsSupportedFileType(document) || !document.SupportsSemanticModel || + if (document == null || !IsSupportedFileType(document) || !document.SupportsSemanticModel || !document.SupportsSyntaxTree) { - return null; // Razor cshtml returns a null document for some reason. + return (Parsed: null, TaggingSupported: false); // Razor cshtml returns a null document for some reason. } - - var semanticModel = await GetSemanticModelAsync(document, cancellationToken).ConfigureAwait(false); - if (cancellationToken.IsCancellationRequested || semanticModel is null) - return null; + var (semanticModel, syntaxRoot) = await document.GetSemanticModelAndRootAsync(cancellationToken); - var syntaxRoot = await GetSyntaxRootAsync(document, cancellationToken).ConfigureAwait(false); + if (semanticModel is null || syntaxRoot is null || cancellationToken.IsCancellationRequested) + return (Parsed: null, TaggingSupported: true); - if (cancellationToken.IsCancellationRequested || syntaxRoot is null) - return null; - - return new ParsedDocument(workspace, document, syntaxRoot, semanticModel, snapshot); + var parsed = new ParsedDocument(workspace, document, syntaxRoot, semanticModel, snapshot); + return (parsed, TaggingSupported: true); } private static async ValueTask GetSemanticModelAsync(Document document, CancellationToken cancellationToken) From a0146613dddec8e750d155c7e1596ae27706c50c Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Thu, 14 May 2026 22:24:00 +0200 Subject: [PATCH 53/56] ATR-966: updated semantic model utils --- .../Roslyn/Semantic/SemanticModelUtils.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Acuminator/Acuminator.Utilities/Roslyn/Semantic/SemanticModelUtils.cs b/src/Acuminator/Acuminator.Utilities/Roslyn/Semantic/SemanticModelUtils.cs index f338dbd93..1fc944d3b 100644 --- a/src/Acuminator/Acuminator.Utilities/Roslyn/Semantic/SemanticModelUtils.cs +++ b/src/Acuminator/Acuminator.Utilities/Roslyn/Semantic/SemanticModelUtils.cs @@ -15,10 +15,10 @@ namespace Acuminator.Utilities.Roslyn.Semantic public static class SemanticModelUtils { /// - /// Safely analyse data flow for a and return if analysis succeeded. + /// Safely analyze data flow for a and return if analysis succeeded. /// /// The semanticModel to act on. - /// The node to analyse. + /// The node to analyze. /// /// A if the data flow analysis succeeded, if not. /// @@ -62,12 +62,14 @@ public static class SemanticModelUtils [SuppressMessage("Usage", "VSTHRD103:Call async methods when in an async method", Justification = "Aggregated await is used")] public static async Task<(SemanticModel? SemanticModel, SyntaxNode? Root)> GetSemanticModelAndRootAsync(this Document document, - CancellationToken cancellation = default) + CancellationToken cancellation = default, + bool continueOnCapturedContext = false) { var semanticModelTask = document.CheckIfNull().GetSemanticModelAsync(cancellation); var syntaxRootTask = document.GetSyntaxRootAsync(cancellation); - await Task.WhenAll(semanticModelTask, syntaxRootTask).ConfigureAwait(false); + await Task.WhenAll(semanticModelTask, syntaxRootTask) + .ConfigureAwait(continueOnCapturedContext); return (semanticModelTask.Result, syntaxRootTask.Result); } From c32878d6b1eed26866b7a5ad151dc89b47e40862 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Thu, 14 May 2026 22:26:07 +0200 Subject: [PATCH 54/56] ATR-966: reworked tagger disposal logic from Copiolt remark --- .../Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index 24d95cbfb..77fb3e532 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -231,7 +231,7 @@ private void WalkDocumentSyntaxTreeForTags(ParsedDocument document, Cancellation public override void Dispose() { - _roslynWorkspaceProvider.Dispose(); + _roslynWorkspaceProvider.WorkspaceChanged -= WorkspaceAttachedToDocumentChanged; if (_subscribedWorkspace != null) { @@ -245,6 +245,7 @@ public override void Dispose() } } + _roslynWorkspaceProvider.Dispose(); BackgroundTagging?.Dispose(); ClassificationTagsCache?.Reset(); OutliningsTagsCache?.Reset(); From 51cfe3bef58a945bc776f6972bbb0b4b4e7eddc0 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Thu, 14 May 2026 22:43:36 +0200 Subject: [PATCH 55/56] ATR-966: added logging capabilities to TryAwait and integrated them into the coloring. Removed redundant code --- .../Common/Concurrent/ConcurrentExtensions.cs | 36 ++++++++++++++++--- .../Coloriser/PXRoslynColorizerTagger.cs | 8 +++-- .../Coloriser/Roslyn/ParsedDocument.cs | 35 ++++++------------ 3 files changed, 47 insertions(+), 32 deletions(-) diff --git a/src/Acuminator/Acuminator.Utilities/Common/Concurrent/ConcurrentExtensions.cs b/src/Acuminator/Acuminator.Utilities/Common/Concurrent/ConcurrentExtensions.cs index bbc384da5..a08e44e90 100644 --- a/src/Acuminator/Acuminator.Utilities/Common/Concurrent/ConcurrentExtensions.cs +++ b/src/Acuminator/Acuminator.Utilities/Common/Concurrent/ConcurrentExtensions.cs @@ -35,9 +35,11 @@ public static void Clear(this ConcurrentQueue? queue) /// A Task extension method that attempts to await task which could be cancelled or faulted. /// /// The task to act on. + /// (Optional) The optional logger for non cancellation exceptions. /// (Optional) True to continue on captured context. - /// - public async static Task TryAwait(this Task? task, bool continueOnCapturedContext = false) + /// + public async static Task TryAwait(this Task? task, Action? logger = null, + bool continueOnCapturedContext = false) { if (task == null || task.IsCanceled || task.IsFaulted) return false; @@ -47,8 +49,13 @@ public async static Task TryAwait(this Task? task, bool continueOnCaptured await task.ConfigureAwait(continueOnCapturedContext); return true; } + catch (OperationCanceledException cancelledException) + { + return false; + } catch (Exception exception) { + logger?.Invoke(exception); return false; } } @@ -57,9 +64,11 @@ public async static Task TryAwait(this Task? task, bool continueOnCaptured /// A extension method that attempts to await task which could be cancelled or faulted. /// /// The task to act on. + /// (Optional) The optional logger for non cancellation exceptions. /// (Optional) True to continue on captured context. /// - public async static ValueTask TryAwait(this ValueTask task, bool continueOnCapturedContext = false) + public async static ValueTask TryAwait(this ValueTask task, Action? logger = null, + bool continueOnCapturedContext = false) { if (task.IsCanceled || task.IsFaulted) return false; @@ -69,8 +78,13 @@ public async static ValueTask TryAwait(this ValueTask task, bool continueO await task.ConfigureAwait(continueOnCapturedContext); return true; } + catch (OperationCanceledException cancelledException) + { + return false; + } catch (Exception exception) { + logger?.Invoke(exception); return false; } } @@ -80,9 +94,10 @@ public async static ValueTask TryAwait(this ValueTask task, bool continueO /// /// Type of the result. /// The task to act on. + /// (Optional) The optional logger for non cancellation exceptions. /// (Optional) True to continue on captured context. /// - public async static Task> TryAwait(this Task? task, + public async static Task> TryAwait(this Task? task, Action? logger = null, bool continueOnCapturedContext = false) { if (task == null || task.IsCanceled || task.IsFaulted) @@ -93,8 +108,13 @@ public async static Task> TryAwait(this Task(true, result); } + catch (OperationCanceledException cancelledException) + { + return new TaskResult(false, default); + } catch (Exception exception) { + logger?.Invoke(exception); return new TaskResult(false, default); } } @@ -104,9 +124,10 @@ public async static Task> TryAwait(this Task /// Type of the result. /// The task to act on. + /// (Optional) The optional logger for non cancellation exceptions. /// (Optional) True to continue on captured context. /// - public async static ValueTask> TryAwait(this ValueTask task, + public async static ValueTask> TryAwait(this ValueTask task, Action? logger = null, bool continueOnCapturedContext = false) { if (task.IsCanceled || task.IsFaulted) @@ -117,8 +138,13 @@ public async static ValueTask> TryAwait(this ValueT TResult? result = await task.ConfigureAwait(continueOnCapturedContext); return new TaskResult(true, result); } + catch (OperationCanceledException cancelledException) + { + return new TaskResult(false, default); + } catch (Exception exception) { + logger?.Invoke(exception); return new TaskResult(false, default); } } diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index 77fb3e532..96d68b4fe 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -193,7 +193,7 @@ protected internal async Task>> GetTags Task<(ParsedDocument? Parsed, bool TaggingSupported)> getDocumentTask = ParsedDocument.ResolveAsync(snapshot, workspace, cToken); // Razor cshtml returns a null document for some reason. - var documentTaskResult = await getDocumentTask.TryAwait(); + var documentTaskResult = await getDocumentTask.TryAwait(LogError); if (!documentTaskResult.IsSuccess) { @@ -210,11 +210,15 @@ protected internal async Task>> GetTags return []; } - bool completedSuccessfully = await WalkDocumentSyntaxTreeForTagsOnThreadPoolAsync(document, cToken).TryAwait(); + bool completedSuccessfully = await WalkDocumentSyntaxTreeForTagsOnThreadPoolAsync(document, cToken).TryAwait(LogError); LastTaggingWasSuccessful = completedSuccessfully && ClassificationTagsCache.IsCompleted; return ClassificationTagsCache.ProcessedTags; } + private static void LogError(Exception exception) => + AcuminatorVSPackage.Instance?.AcuminatorLogger?.LogException(exception, logOnlyFromAcuminatorAssemblies: true, + Logger.LogMode.Warning); + private Task WalkDocumentSyntaxTreeForTagsOnThreadPoolAsync(ParsedDocument document, CancellationToken cancellationToken) { return Task.Run(() => WalkDocumentSyntaxTreeForTags(document, cancellationToken)); diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/ParsedDocument.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/ParsedDocument.cs index 9955ffcbe..7f3f7d26f 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/ParsedDocument.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/Roslyn/ParsedDocument.cs @@ -48,7 +48,12 @@ public class ParsedDocument(Workspace workspace, Document document, SyntaxNode s return (Parsed: null, TaggingSupported: false); // Razor cshtml returns a null document for some reason. } - var (semanticModel, syntaxRoot) = await document.GetSemanticModelAndRootAsync(cancellationToken); + var taskResult = await document.GetSemanticModelAndRootAsync(cancellationToken) + .TryAwait(LogError); + if (!taskResult.IsSuccess) + return (Parsed: null, TaggingSupported: true); + + var (semanticModel, syntaxRoot) = taskResult.Result; if (semanticModel is null || syntaxRoot is null || cancellationToken.IsCancellationRequested) return (Parsed: null, TaggingSupported: true); @@ -57,30 +62,10 @@ public class ParsedDocument(Workspace workspace, Document document, SyntaxNode s return (parsed, TaggingSupported: true); } - private static async ValueTask GetSemanticModelAsync(Document document, CancellationToken cancellationToken) - { - if (document.TryGetSemanticModel(out SemanticModel? semanticModel)) - return semanticModel; - - var semanticModelTaskResult = await document.GetSemanticModelAsync(cancellationToken) - .TryAwait() - .ConfigureAwait(false); - semanticModel = semanticModelTaskResult.Result; - return semanticModelTaskResult.IsSuccess ? semanticModel : null; - } - - private static async ValueTask GetSyntaxRootAsync(Document document, CancellationToken cancellationToken) - { - if (document.TryGetSyntaxRoot(out SyntaxNode? syntaxRoot)) - return syntaxRoot; - - var syntaxRootTaskResult = await document.GetSyntaxRootAsync(cancellationToken) - .TryAwait() - .ConfigureAwait(false); - syntaxRoot = syntaxRootTaskResult.Result; - return syntaxRootTaskResult.IsSuccess ? syntaxRoot : null; - } - private static bool IsSupportedFileType(Document document) => allowedExtensions.Contains(Path.GetExtension(document.FilePath)); + + private static void LogError(Exception exception) => + AcuminatorVSPackage.Instance?.AcuminatorLogger?.LogException(exception, logOnlyFromAcuminatorAssemblies: true, + Logger.LogMode.Warning); } } From d223e67fe52913cc2f82d52ebcfec4a6ecf138f1 Mon Sep 17 00:00:00 2001 From: Sergey Nikomarov Date: Thu, 14 May 2026 22:59:54 +0200 Subject: [PATCH 56/56] ATR-966: minor refactoring - removed empty lines --- .../Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs index 96d68b4fe..00218015c 100644 --- a/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs +++ b/src/Acuminator/Acuminator.Vsix/Coloriser/PXRoslynColorizerTagger.cs @@ -165,8 +165,6 @@ public IEnumerable> GetTags(NormalizedSnapshotSpanC return ClassificationTagsCache.ProcessedTags; } - - protected virtual bool CheckIfParsingAndRetaggingIsNotNecessary(ITextSnapshot newSnapshotToTag) => CacheCheckingEnabled && Snapshot != null && Snapshot == newSnapshotToTag && !ColoringSettingsChanged && (LastTaggingWasSuccessful || BackgroundTagging?.IsTaskRunning() == true);