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!
*This post is locked for comments