Hello Team.
I hope this article will be useful for some developers who will try to sync "Sales Invoice Line" table to Dataverse separately.
I created replication for many Business Central tables to Dataverse using steps described here:
But with "Sales Invoice Line" - I failed first time. I created standard set of objects, created "Integration Table mappings" and so on. And after I ran "Full synchronization" - I got next error on my job:
"Cannot synchronize invoice lines separately."
It's quite hard to debug job sync especially on Production environment, so I started to check Dataverse replication objects because error looked like some Label type variable. I extracted from Base Application all objects with name started with "CRM":
And in the codeunit 5341 "CRM Int. Table. Subscriber" I found what I wanted:
This Error label used in only event subscriber:
[EventSubscriber(ObjectType::Codeunit, Codeunit::"CRM Integration Table Synch.", 'OnQueryPostFilterIgnoreRecord', '', false, false)]
procedure OnQueryPostFilterIgnoreRecord(SourceRecordRef: RecordRef; var IgnoreRecord: Boolean)
begin
if IgnoreRecord then
exit;
case SourceRecordRef.Number() of
DATABASE::Contact:
HandleContactQueryPostFilterIgnoreRecord(SourceRecordRef, IgnoreRecord);
DATABASE::Opportunity:
HandleOpportunityQueryPostFilterIgnoreRecord(SourceRecordRef, IgnoreRecord);
DATABASE::"Sales Invoice Line":
Error(CannotSynchOnlyLinesErr);
DATABASE::Item:
HandleItemQueryPostFilterIgnoreRecord(SourceRecordRef, IgnoreRecord);
DATABASE::Resource:
HandleResourceQueryPostFilterIgnoreRecord(SourceRecordRef, IgnoreRecord);
end;
end;
So "Sales Invoice Line" the only table you can't sync. You'll get the error each time you run the sync process. I think because it's a part of D365 Sales integration. But we don't use it and I need this table in Dataverse.
I can't change standard code and must resolve this issue using extensions only.
Event placed in codeunit 5340 "CRM Integration Table Synch.":
procedure SyncNAVRecordToCRM(var SourceRecordRef: RecordRef; IntegrationTableMapping: Record "Integration Table Mapping"; var IntegrationTableSynch: Codeunit "Integration Table Synch."; var TempCRMIntegrationRecord: Record "CRM Integration Record" temporary; var LatestLocalModifiedOn: DateTime)
var
DestinationRecordRef: RecordRef;
SystemIdFieldRef: FieldRef;
IgnoreRecord: Boolean;
ForceModify: Boolean;
LocalModifiedOn: DateTime;
begin
ForceModify := IntegrationTableMapping."Delete After Synchronization";
IgnoreRecord := false;
OnQueryPostFilterIgnoreRecord(SourceRecordRef, IgnoreRecord);
if not IgnoreRecord then begin
SystemIdFieldRef := SourceRecordRef.Field(SourceRecordRef.SystemIdNo);
if not TempCRMIntegrationRecord.IsIntegrationIdCoupled(SystemIdFieldRef.Value()) then
IgnoreRecord := IntegrationTableMapping."Synch. Only Coupled Records";
if not IgnoreRecord then
IntegrationTableSynch.Synchronize(SourceRecordRef, DestinationRecordRef, ForceModify, false);
end;
// collect latest modified time across all local records including not synched
LocalModifiedOn := IntegrationTableSynch.GetRowLastModifiedOn(IntegrationTableMapping, SourceRecordRef);
if LocalModifiedOn > LatestLocalModifiedOn then
LatestLocalModifiedOn := LocalModifiedOn;
end;
We could see that we can skip this event if send IgnoreRecord = true, but this way we skip record sync totally (checked).
As I use SaaS and "Sales Invoice Line" is not a big table - I created a clone of this table using this event:
[EventSubscriber(ObjectType::Table, Database::"Sales Invoice Line", 'OnAfterInsertEvent', '', false, false)]
local procedure InsertCloneLine(var Rec: Record "Sales Invoice Line"; RunTrigger: Boolean)
var
SalesInvoiceLineClone: Record "AWR_Sales Invoice Line clone";
begin
If Rec.IsTemporary then
exit;
SalesInvoiceLineClone.Init();
SalesInvoiceLineClone.TransferFields(Rec, true);
if SalesInvoiceLineClone.Insert() then;
end;
So the Idea is next:
1. After sales invoice post - lines automatically creates in my clone table
2. Job queue then sync this clone table into Dataverse as usual.
Now this schema works like a charm and shows that we can find a way when it seems like you can't do something with extensions.
Hope that it'll be useful for somebody!

Like
Report
*This post is locked for comments