Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
fb47d8f
Post migration validation feature
jaymckinney Nov 10, 2025
9604166
Most of the changes after review
jaymckinney Nov 17, 2025
79eb54e
Changes after review
jaymckinney Nov 20, 2025
e564021
Removed unused namespace
jaymckinney Nov 26, 2025
a761d03
Removed unused using statements, corrected. Corrected Migration Type/…
jaymckinney Nov 26, 2025
10dee8a
Removed unused tests
jaymckinney Nov 26, 2025
c920ee4
Handle duplicate account records better
jaymckinney Nov 26, 2025
709af84
Added missing using statement
jaymckinney Dec 9, 2025
a459da5
Commit changes in the loop. Correct counters.
jaymckinney Dec 10, 2025
26e1a94
Added Validator Code to any error messages
jaymckinney Dec 10, 2025
4ed5197
Better manual starting of validation by using either the job queue or…
jaymckinney Dec 22, 2025
41fc523
Updated tests to match refactoring changes
jaymckinney Dec 22, 2025
dd11c67
Changes after review
jaymckinney Jan 21, 2026
caaad5e
Refactored to use existing Hybrid Companies List page
jaymckinney Jan 22, 2026
0b726ec
Moved the buffer table to an internal GP PO specific version.
jaymckinney Jan 26, 2026
640c175
Additional changes after review
jaymckinney Jan 27, 2026
3db5957
Additional changes after review
jaymckinney Jan 27, 2026
7bebc75
Refactoring changes after review
jaymckinney Jan 27, 2026
a31f419
A few updates after review
jaymckinney Jan 28, 2026
bea5451
Merge remote-tracking branch 'origin/main' into GPUpdates202511
jaymckinney Jan 28, 2026
28ebe8f
Added missing namespaces
jaymckinney Feb 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ permissionset 4713 "HybridGPUS - Objects"
codeunit "GP Vendor 1099 Mapping Helpers" = X,
codeunit "GP IRS Form Data" = X,
page "GP 1099 Migration Log" = X,
page "GP 1099 Migration Log Factbox" = X;
page "GP 1099 Migration Log Factbox" = X,
codeunit "GP IRS1099 Migration Validator" = X;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ using System.Integration;

codeunit 42004 "GP Cloud Migration US"
{

[EventSubscriber(ObjectType::Codeunit, CodeUnit::"Data Migration Mgt.", 'OnAfterMigrationFinished', '', false, false)]
local procedure OnAfterMigrationFinishedSubscriber(var DataMigrationStatus: Record "Data Migration Status"; WasAborted: Boolean; StartTime: DateTime; Retry: Boolean)
[EventSubscriber(ObjectType::Codeunit, CodeUnit::"Data Migration Mgt.", OnCreatePostMigrationData, '', false, false)]
local procedure OnCreatePostMigrationDataSubscriber(var DataMigrationStatus: Record "Data Migration Status")
var
HelperFunctions: Codeunit "Helper Functions";
begin
if not (DataMigrationStatus."Migration Type" = HelperFunctions.GetMigrationTypeTxt()) then
if DataMigrationStatus."Migration Type" <> HelperFunctions.GetMigrationTypeTxt() then
exit;

RunPostMigration();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
namespace Microsoft.DataMigration.GP;

using Microsoft.DataMigration;
using Microsoft.Finance.VAT.Reporting;
using Microsoft.Purchases.Payables;
using Microsoft.Purchases.Vendor;

codeunit 42006 "GP IRS1099 Migration Validator"
{
trigger OnRun()
var
GPCompanyAdditionalSettings: Record "GP Company Additional Settings";
begin
if not GPCompanyAdditionalSettings.GetMigrateVendor1099Enabled() then
exit;

ValidationSuiteIdTxt := GetValidationSuiteId();
CompanyNameTxt := CompanyName();

RunVendor1099MigrationValidation(GPCompanyAdditionalSettings);
end;

local procedure RunVendor1099MigrationValidation(var GPCompanyAdditionalSettings: Record "GP Company Additional Settings")
var
GPPM00200: Record "GP PM00200";
Vendor: Record Vendor;
VendorLedgerEntry: Record "Vendor Ledger Entry";
IRS1099VendorFormBoxSetup: Record "IRS 1099 Vendor Form Box Setup";
GPVendor1099MappingHelpers: Codeunit "GP Vendor 1099 Mapping Helpers";
IRS1099Code: Code[10];
ActualIRS1099Code: Code[20];
TaxAmount: Decimal;
VendorYear1099AmountDictionary: Dictionary of [Code[10], Decimal];
EntityType: Text[50];
VendorNo: Code[20];
begin
EntityType := Vendor1099EntityCaptionLbl;

if GPCompanyAdditionalSettings.GetMigrateVendor1099Enabled() then begin
GPPM00200.SetRange(TEN99TYPE, 2, 5);
GPPM00200.SetFilter(VENDORID, '<>%1', '');
if GPPM00200.FindSet() then
repeat
if MigrationValidationAssert.IsSourceRowValidated(ValidationSuiteIdTxt, GPPM00200) then
continue;

VendorNo := CopyStr(GPPM00200.VENDORID.TrimEnd(), 1, MaxStrLen(VendorNo));
Vendor.SetLoadFields("No.", Name, "Federal ID No.");
if not Vendor.Get(VendorNo) then
continue;

MigrationValidationAssert.SetContext(ValidationSuiteIdTxt, EntityType, VendorNo);
IRS1099Code := GPVendor1099MappingHelpers.GetIRS1099BoxCode(System.Date2DMY(System.Today(), 3), GPPM00200.TEN99TYPE, GPPM00200.TEN99BOXNUMBER);

Clear(ActualIRS1099Code);
if IRS1099VendorFormBoxSetup.Get(Format(GPCompanyAdditionalSettings.Get1099TaxYear()), VendorNo) then
ActualIRS1099Code := IRS1099VendorFormBoxSetup."Form Box No.";

MigrationValidationAssert.ValidateAreEqual(Test_VEND1099IRS1099CODE_Tok, IRS1099Code, ActualIRS1099Code, IRS1099CodeLbl);
MigrationValidationAssert.ValidateAreEqual(Test_VEND1099FEDIDNO_Tok, CopyStr(GPPM00200.TXIDNMBR.TrimEnd(), 1, MaxStrLen(Vendor."Federal ID No.")), Vendor."Federal ID No.", FederalIdNoLbl);

Clear(VendorYear1099AmountDictionary);
BuildVendor1099Entries(VendorNo, VendorYear1099AmountDictionary);
foreach IRS1099Code in VendorYear1099AmountDictionary.Keys() do begin
TaxAmount := VendorYear1099AmountDictionary.Get(IRS1099Code);

if TaxAmount > 0 then begin
Clear(VendorLedgerEntry);
VendorLedgerEntry.SetLoadFields(Description, Amount);
VendorLedgerEntry.SetRange("Vendor No.", VendorNo);
VendorLedgerEntry.SetRange("Document Type", VendorLedgerEntry."Document Type"::Payment);
VendorLedgerEntry.SetRange(Description, IRS1099Code);

if not MigrationValidationAssert.ValidateRecordExists(Test_VEND1099TRXEXISTS_Tok, VendorLedgerEntry.FindFirst(), StrSubstNo(MissingBoxAndAmountLbl, IRS1099Code, TaxAmount)) then
continue;

VendorLedgerEntry.CalcFields(Amount);

MigrationValidationAssert.ValidateAreEqual(Test_VEND1099TEN99BOX_Tok, IRS1099Code, VendorLedgerEntry.Description, Vendor1099BoxLbl);
MigrationValidationAssert.ValidateAreEqual(Test_VEND1099TEN99TRXAMT_Tok, TaxAmount, VendorLedgerEntry.Amount, Vendor1099BoxAmountLbl);
end;
end;

MigrationValidationAssert.SetSourceRowValidated(ValidationSuiteIdTxt, GPPM00200);
until GPPM00200.Next() = 0;
end;
Commit();
end;

local procedure BuildVendor1099Entries(VendorNo: Code[20]; var VendorYear1099AmountDictionary: Dictionary of [Code[10], Decimal])
var
GPCompanyAdditionalSettings: Record "GP Company Additional Settings";
GPPM00204: Record "GP PM00204";
GPVendor1099MappingHelpers: Codeunit "GP Vendor 1099 Mapping Helpers";
IRS1099Code: Code[10];
TaxAmount: Decimal;
TaxYear: Integer;
begin
TaxYear := GPCompanyAdditionalSettings.Get1099TaxYear();
GPPM00204.SetRange(VENDORID, VendorNo);
GPPM00204.SetRange(YEAR1, TaxYear);
GPPM00204.SetFilter(TEN99AMNT, '>0');
if GPPM00204.FindSet() then
repeat
IRS1099Code := GPVendor1099MappingHelpers.GetIRS1099BoxCode(TaxYear, GPPM00204.TEN99TYPE, GPPM00204.TEN99BOXNUMBER);
if IRS1099Code <> '' then
if VendorYear1099AmountDictionary.Get(IRS1099Code, TaxAmount) then
VendorYear1099AmountDictionary.Set(IRS1099Code, TaxAmount + GPPM00204.TEN99AMNT)
else
VendorYear1099AmountDictionary.Add(IRS1099Code, GPPM00204.TEN99AMNT);
until GPPM00204.Next() = 0;
end;

internal procedure GetValidationSuiteId(): Code[20]
begin
exit('GP-US');
end;

[EventSubscriber(ObjectType::Codeunit, Codeunit::"Migration Validation", OnPrepareValidation, '', false, false)]
local procedure OnPrepareValidation(ProductID: Text[250])
var
HybridGPWizard: Codeunit "Hybrid GP Wizard";
begin
if ProductID <> HybridGPWizard.ProductId() then
exit;

RegisterValidator();

AddTest(Test_VEND1099IRS1099CODE_Tok, Vendor1099EntityCaptionLbl, IRS1099CodeLbl);
AddTest(Test_VEND1099FEDIDNO_Tok, Vendor1099EntityCaptionLbl, FederalIdNoLbl);
AddTest(Test_VEND1099TRXEXISTS_Tok, Vendor1099EntityCaptionLbl, Vendor1099MissingTrxLbl);
AddTest(Test_VEND1099TEN99BOX_Tok, Vendor1099EntityCaptionLbl, Vendor1099TrxBoxNoLbl);
AddTest(Test_VEND1099TEN99TRXAMT_Tok, Vendor1099EntityCaptionLbl, Vendor1099TrxAmtLbl);
end;

local procedure RegisterValidator()
var
ValidationSuite: Record "Validation Suite";
HybridGPWizard: Codeunit "Hybrid GP Wizard";
ValidationSuiteId: Code[20];
MigrationType: Text[250];
ValidatorCodeunitId: Integer;
begin
ValidationSuiteId := GetValidationSuiteId();
MigrationType := HybridGPWizard.ProductId();
ValidatorCodeunitId := Codeunit::"GP IRS1099 Migration Validator";
if not ValidationSuite.Get(ValidationSuiteId) then begin
ValidationSuite.Validate(Id, ValidationSuiteId);
ValidationSuite.Validate("Migration Type", MigrationType);
ValidationSuite.Validate(Description, ValidatorDescriptionLbl);
ValidationSuite.Validate("Codeunit Id", ValidatorCodeunitId);
ValidationSuite.Validate(Automatic, true);
ValidationSuite.Validate("Errors should fail migration", false);
ValidationSuite.Insert(true);
end;
end;

local procedure AddTest(Code: Code[30]; Entity: Text[50]; Description: Text)
var
ValidationSuiteLine: Record "Validation Suite Line";
begin
if not ValidationSuiteLine.Get(Code, GetValidationSuiteId()) then begin
ValidationSuiteLine.Validate(Code, Code);
ValidationSuiteLine.Validate("Validation Suite Id", GetValidationSuiteId());
ValidationSuiteLine.Validate(Entity, Entity);
ValidationSuiteLine.Validate("Test Description", Description);
ValidationSuiteLine.Insert(true);
end;
end;

var
MigrationValidationAssert: Codeunit "Migration Validation Assert";
ValidationSuiteIdTxt: Code[20];
CompanyNameTxt: Text;
FederalIdNoLbl: Label 'Federal ID No.';
IRS1099CodeLbl: Label 'IRS 1099 Code';
MissingBoxAndAmountLbl: Label 'Missing 1099 Box Payment. 1099 Box = %1, Amount = %2', Comment = '%1 = 1099 Box Code, %2 = Amount of the payment';
Vendor1099BoxLbl: Label '1099 Box';
Vendor1099BoxAmountLbl: Label '1099 Box Amount';
Vendor1099MissingTrxLbl: Label 'Missing 1099 transaction';
Vendor1099TrxBoxNoLbl: Label '1099 transaction Box No/Description';
Vendor1099TrxAmtLbl: Label '1099 transaction amount';
Vendor1099EntityCaptionLbl: Label 'Vendor 1099', MaxLength = 50;
ValidatorDescriptionLbl: Label 'GP IRS 1099 migration validator', MaxLength = 250;
Test_VEND1099IRS1099CODE_Tok: Label 'VEND1099IRS1099CODE', Locked = true;
Test_VEND1099FEDIDNO_Tok: Label 'VEND1099FEDIDNO', Locked = true;
Test_VEND1099TRXEXISTS_Tok: Label 'VEND1099TRXEXISTS', Locked = true;
Test_VEND1099TEN99BOX_Tok: Label 'VEND1099TEN99BOX', Locked = true;
Test_VEND1099TEN99TRXAMT_Tok: Label 'VEND1099TEN99TRXAMT', Locked = true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
namespace Microsoft.DataMigration.GP;

using Microsoft.DataMigration;

pageextension 41105 "GP Upgrade Settings Ext" extends "GP Upgrade Settings"
{
layout
{
addafter(GPAutomaticValidation)
{
field(GPUSAutomaticValidation; GPIRS1099AutoValidation)
{
ApplicationArea = All;
Caption = 'GP-US (1099)';
ToolTip = 'Specifies whether automatic validation is enabled for the GP-US (1099) migration.';

trigger OnValidate()
begin
if not GPIRS1099AutoValidation then
GPIRS1099ValidationErrorsShouldFailMigration := false;

UpdateValidatorConfig();
end;
}
}
addafter(GPValidationErrorHandling)
{
field(GPUSValidationErrorHandling; GPIRS1099ValidationErrorsShouldFailMigration)
{
ApplicationArea = All;
Caption = 'GP-US (1099)';
ToolTip = 'Specifies whether GP-US (1099) validation errors should fail the migration. Only applies when automatic validation is enabled.';

trigger OnValidate()
begin
GPIRS1099AutoValidation := GPIRS1099ValidationErrorsShouldFailMigration;
UpdateValidatorConfig();
end;
}
}
}

trigger OnOpenPage()
var
ValidationSuite: Record "Validation Suite";
GPIRS1099MigrtionValidator: Codeunit "GP IRS1099 Migration Validator";
begin
if ValidationSuite.Get(GPIRS1099MigrtionValidator.GetValidationSuiteId()) then begin
GPIRS1099AutoValidation := ValidationSuite.Automatic;
GPIRS1099ValidationErrorsShouldFailMigration := ValidationSuite."Errors should fail migration";
end;
end;

local procedure UpdateValidatorConfig()
var
ValidationSuite: Record "Validation Suite";
GPIRS1099MigrtionValidator: Codeunit "GP IRS1099 Migration Validator";
begin
if ValidationSuite.Get(GPIRS1099MigrtionValidator.GetValidationSuiteId()) then begin
ValidationSuite.Validate(Automatic, GPIRS1099AutoValidation);
ValidationSuite.Validate("Errors should fail migration", GPIRS1099ValidationErrorsShouldFailMigration);
ValidationSuite.Modify(true);
end;
end;

var
GPIRS1099AutoValidation: Boolean;
GPIRS1099ValidationErrorsShouldFailMigration: Boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,14 @@ permissionset 4006 "HBD - Objects"
Permissions = page "Hybrid DA Approval" = X,
page "Add Migration Table Mappings" = X,
table "Hybrid Company Status" = X,
table "Hybrid DA Approval" = X;
table "Hybrid DA Approval" = X,
table "Migration Validation Error" = X,
page "Migration Validation Errors" = X,
codeunit "Migration Validation Assert" = X,
codeunit "Migration Validation" = X,
table "Validation Suite" = X,
table "Validation Suite Line" = X,
page "Migration Validation Results" = X,
table "Validation Progress" = X,
codeunit "Migration Validator Warning" = X;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,9 @@ permissionsetextension 4003 "INTELLIGENT CLOUD - HBD" extends "INTELLIGENT CLOUD
tabledata "Hybrid DA Approval" = rmi,
tabledata "Replication Record Link Buffer" = RIMD,
tabledata "Record Link Mapping" = RIMD,
tabledata "Cloud Migration Warning" = RIMD;
tabledata "Cloud Migration Warning" = RIMD,
tabledata "Validation Suite" = RIMD,
tabledata "Migration Validation Error" = RIMD,
tabledata "Validation Suite Line" = RIMD,
tabledata "Validation Progress" = RIMD;
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,9 @@ permissionsetextension 4000 "D365 BASIC - HBD" extends "D365 BASIC"
tabledata "Replication Run Completed Arg" = RIMD,
tabledata "Replication Record Link Buffer" = RIMD,
tabledata "Record Link Mapping" = RIMD,
tabledata "Cloud Migration Warning" = RIMD;
tabledata "Cloud Migration Warning" = RIMD,
tabledata "Validation Suite" = RIMD,
tabledata "Migration Validation Error" = RIMD,
tabledata "Validation Suite Line" = RIMD,
tabledata "Validation Progress" = RIMD;
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,9 @@ permissionsetextension 4001 "D365 BASIC ISV - HBD" extends "D365 BASIC ISV"
tabledata "Hybrid DA Approval" = rmi,
tabledata "Replication Record Link Buffer" = RIMD,
tabledata "Record Link Mapping" = RIMD,
tabledata "Cloud Migration Warning" = RIMD;
tabledata "Cloud Migration Warning" = RIMD,
tabledata "Validation Suite" = RIMD,
tabledata "Migration Validation Error" = RIMD,
tabledata "Validation Suite Line" = RIMD,
tabledata "Validation Progress" = RIMD;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,9 @@ permissionsetextension 4002 "D365 TEAM MEMBER - HBD" extends "D365 TEAM MEMBER"
tabledata "Replication Run Completed Arg" = RIMD,
tabledata "Replication Record Link Buffer" = RIMD,
tabledata "Record Link Mapping" = RIMD,
tabledata "Cloud Migration Warning" = RIMD;
tabledata "Cloud Migration Warning" = RIMD,
tabledata "Validation Suite" = RIMD,
tabledata "Migration Validation Error" = RIMD,
tabledata "Validation Suite Line" = RIMD,
tabledata "Validation Progress" = RIMD;
}
Loading
Loading