Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -10,7 +10,7 @@ enum 10971 "FR Regulatory Comment Type"

value(0; None)
{
Caption = '';
Caption = ' ';
}
value(1; AAA)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,10 @@ pageextension 10972 "E-Reporting Customer Card" extends "Customer Card"
{
ApplicationArea = Basic, Suite;
}
#if not CLEAN29
Comment thread
djukicmilica marked this conversation as resolved.
Comment thread
djukicmilica marked this conversation as resolved.
#pragma warning disable AS0105
field("FR Elec. Address Scheme"; Rec."FR Elec. Address Scheme")
{
ApplicationArea = Basic, Suite;
ObsoleteReason = 'French buyer electronic addresses always use scheme 0225.';
ObsoleteState = Pending;
ObsoleteTag = '29.0';
Visible = false;
}
#pragma warning restore AS0105
#endif
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ tableextension 10975 "FR Sales Comment Line" extends "Sales Comment Line"
ToolTip = 'Specifies the French regulatory purpose of the comment. The selected type is automatically added as a prefix when the comment is exported to an electronic invoice.';
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,11 @@ codeunit 10977 "Peppol BIS 3.0 FR Format" implements "E-Document"

InitNamespaceManager(NamespaceMgr, XmlDoc);

SetCustomizationId(XmlDoc, NamespaceMgr);
Comment thread
djukicmilica marked this conversation as resolved.
SetFrenchBillingMode(XmlDoc, NamespaceMgr, SourceDocumentLines);
RemoveZeroAllowanceTotal(XmlDoc, NamespaceMgr);
InjectSupplierIdentification(XmlDoc, NamespaceMgr, CompanyInformation);
InjectBuyerIdentification(XmlDoc, NamespaceMgr, SourceDocumentHeader);
InjectSupplierEndpoint(XmlDoc, NamespaceMgr, CompanyInformation, EDocumentService.Code);
InjectRegulatoryComments(XmlDoc, NamespaceMgr, SourceDocumentHeader);
InjectBillingReference(XmlDoc, NamespaceMgr, SourceDocumentHeader);
Expand All @@ -188,14 +190,15 @@ codeunit 10977 "Peppol BIS 3.0 FR Format" implements "E-Document"
OnAfterInjectFrenchElements(TempBlob, SourceDocumentHeader, SourceDocumentLines, EDocumentService);
end;

[IntegrationEvent(false, false)]
local procedure OnBeforeInjectFrenchElements(var TempBlob: Codeunit "Temp Blob"; SourceDocumentHeader: RecordRef; var SourceDocumentLines: RecordRef; EDocumentService: Record "E-Document Service"; var IsHandled: Boolean)
begin
end;

[IntegrationEvent(false, false)]
local procedure OnAfterInjectFrenchElements(var TempBlob: Codeunit "Temp Blob"; SourceDocumentHeader: RecordRef; var SourceDocumentLines: RecordRef; EDocumentService: Record "E-Document Service")
local procedure SetCustomizationId(var XmlDoc: XmlDocument; NamespaceMgr: XmlNamespaceManager)
Comment thread
djukicmilica marked this conversation as resolved.
var
CustomizationIdNode: XmlNode;
NewCustomizationIdNode: XmlNode;
begin
if not XmlDoc.SelectSingleNode('/*/cbc:CustomizationID', NamespaceMgr, CustomizationIdNode) then
Comment thread
djukicmilica marked this conversation as resolved.
exit;
NewCustomizationIdNode := XmlElement.Create('CustomizationID', CbcNamespaceTok, FranceCustomizationIdTok).AsXmlNode();
CustomizationIdNode.ReplaceWith(NewCustomizationIdNode);
end;

local procedure SetFrenchBillingMode(var XmlDoc: XmlDocument; NamespaceMgr: XmlNamespaceManager; var SourceDocumentLines: RecordRef)
Expand Down Expand Up @@ -276,14 +279,15 @@ codeunit 10977 "Peppol BIS 3.0 FR Format" implements "E-Document"
SalesInvoiceHeader: Record "Sales Invoice Header";
SalesInvoiceLine: Record "Sales Invoice Line";
ShipmentPostingDates: Dictionary of [Code[20], Date];
ShipmentBuyerReferences: Dictionary of [Code[20], Text];
CustomizationIdNode: XmlNode;
NewCustomizationIdNode: XmlNode;
begin
if SourceDocumentHeader.Number <> Database::"Sales Invoice Header" then
exit;

SourceDocumentHeader.SetTable(SalesInvoiceHeader);
if not RequiresExtendedCTCFrance(SalesInvoiceHeader."No.", ShipmentPostingDates) then
if not RequiresExtendedCTCFrance(SalesInvoiceHeader."No.", ShipmentPostingDates, ShipmentBuyerReferences) then
exit;

if XmlDoc.SelectSingleNode('/*/cbc:CustomizationID', NamespaceMgr, CustomizationIdNode) then begin
Expand All @@ -292,21 +296,22 @@ codeunit 10977 "Peppol BIS 3.0 FR Format" implements "E-Document"
end;

SalesInvoiceLine.SetRange("Document No.", SalesInvoiceHeader."No.");
SalesInvoiceLine.SetLoadFields("Line No.", "Order No.", "Order Line No.", "Shipment No.");
SalesInvoiceLine.SetLoadFields("Line No.", "Order Line No.", "Shipment No.");
if SalesInvoiceLine.FindSet() then
repeat
InjectExtendedLineReferences(XmlDoc, NamespaceMgr, SalesInvoiceLine, ShipmentPostingDates);
InjectExtendedLineReferences(XmlDoc, NamespaceMgr, SalesInvoiceLine, ShipmentPostingDates, ShipmentBuyerReferences);
until SalesInvoiceLine.Next() = 0;
end;

local procedure RequiresExtendedCTCFrance(DocumentNo: Code[20]; var ShipmentPostingDates: Dictionary of [Code[20], Date]): Boolean
local procedure RequiresExtendedCTCFrance(DocumentNo: Code[20]; var ShipmentPostingDates: Dictionary of [Code[20], Date]; var ShipmentBuyerReferences: Dictionary of [Code[20], Text]): Boolean
var
SalesInvoiceLine: Record "Sales Invoice Line";
SalesShipmentHeader: Record "Sales Shipment Header";
ShipmentNos: Dictionary of [Text, Boolean];
OrderNos: Dictionary of [Text, Boolean];
DeliveryDates: Dictionary of [Text, Boolean];
ShipmentNoFilterBuilder: TextBuilder;
BuyerReference: Text;
begin
SalesInvoiceLine.SetRange("Document No.", DocumentNo);
SalesInvoiceLine.SetLoadFields("Shipment No.", "Order No.");
Expand All @@ -323,10 +328,15 @@ codeunit 10977 "Peppol BIS 3.0 FR Format" implements "E-Document"

if ShipmentNoFilterBuilder.Length() > 0 then begin
SalesShipmentHeader.SetFilter("No.", ShipmentNoFilterBuilder.ToText());
SalesShipmentHeader.SetLoadFields("Posting Date");
SalesShipmentHeader.SetLoadFields("Posting Date", "Your Reference", "External Document No.");
if SalesShipmentHeader.FindSet() then
repeat
ShipmentPostingDates.Add(SalesShipmentHeader."No.", SalesShipmentHeader."Posting Date");
BuyerReference := SalesShipmentHeader."Your Reference";
if BuyerReference = '' then
BuyerReference := SalesShipmentHeader."External Document No.";
if BuyerReference <> '' then
ShipmentBuyerReferences.Add(SalesShipmentHeader."No.", BuyerReference);
AddDistinctValue(DeliveryDates, Format(SalesShipmentHeader."Posting Date", 0, 9));
until SalesShipmentHeader.Next() = 0;
end;
Expand Down Expand Up @@ -359,13 +369,14 @@ codeunit 10977 "Peppol BIS 3.0 FR Format" implements "E-Document"
Values.Add(Value, true);
end;

local procedure InjectExtendedLineReferences(var XmlDoc: XmlDocument; NamespaceMgr: XmlNamespaceManager; SalesInvoiceLine: Record "Sales Invoice Line"; ShipmentPostingDates: Dictionary of [Code[20], Date])
local procedure InjectExtendedLineReferences(var XmlDoc: XmlDocument; NamespaceMgr: XmlNamespaceManager; SalesInvoiceLine: Record "Sales Invoice Line"; ShipmentPostingDates: Dictionary of [Code[20], Date]; ShipmentBuyerReferences: Dictionary of [Code[20], Text])
var
InvoiceLineNode: XmlNode;
LineContentAnchorNode: XmlNode;
OrderLineReferenceElement: XmlElement;
OrderReferenceElement: XmlElement;
DeliveryElement: XmlElement;
BuyerReference: Text;
LineXPath: Text;
ShipmentPostingDate: Date;
begin
Expand All @@ -375,11 +386,12 @@ codeunit 10977 "Peppol BIS 3.0 FR Format" implements "E-Document"
if not InvoiceLineNode.SelectSingleNode('cac:AllowanceCharge | cac:TaxTotal | cac:WithholdingTaxTotal | cac:Item', NamespaceMgr, LineContentAnchorNode) then
exit;

if SalesInvoiceLine."Order No." <> '' then begin
BuyerReference := GetExtendedLineBuyerReference(SalesInvoiceLine, ShipmentBuyerReferences);
Comment thread
djukicmilica marked this conversation as resolved.
if BuyerReference <> '' then begin
OrderLineReferenceElement := XmlElement.Create('OrderLineReference', CacNamespaceTok);
OrderLineReferenceElement.Add(XmlElement.Create('LineID', CbcNamespaceTok, Format(SalesInvoiceLine."Order Line No.", 0, 9)));
OrderReferenceElement := XmlElement.Create('OrderReference', CacNamespaceTok);
OrderReferenceElement.Add(XmlElement.Create('ID', CbcNamespaceTok, SalesInvoiceLine."Order No."));
OrderReferenceElement.Add(XmlElement.Create('ID', CbcNamespaceTok, BuyerReference));
OrderLineReferenceElement.Add(OrderReferenceElement);
LineContentAnchorNode.AddBeforeSelf(OrderLineReferenceElement);
end;
Expand All @@ -396,12 +408,25 @@ codeunit 10977 "Peppol BIS 3.0 FR Format" implements "E-Document"
LineContentAnchorNode.AddBeforeSelf(DeliveryElement);
end;

local procedure GetExtendedLineBuyerReference(SalesInvoiceLine: Record "Sales Invoice Line"; ShipmentBuyerReferences: Dictionary of [Code[20], Text]) BuyerReference: Text
begin
if SalesInvoiceLine."Shipment No." <> '' then
Comment thread
djukicmilica marked this conversation as resolved.
if not ShipmentBuyerReferences.Get(SalesInvoiceLine."Shipment No.", BuyerReference) then
Clear(BuyerReference);

OnAfterGetExtendedLineBuyerReference(SalesInvoiceLine, BuyerReference);
exit(BuyerReference);
end;

local procedure InjectRegulatoryComments(var XmlDoc: XmlDocument; NamespaceMgr: XmlNamespaceManager; SourceDocumentHeader: RecordRef)
var
SalesCommentLine: Record "Sales Comment Line";
AnchorNode: XmlNode;
DocumentNo: Code[20];
DocumentType: Enum "Sales Comment Document Type";
RegulatoryComments: Dictionary of [Text, TextBuilder];
RegulatoryCommentTypeCodes: List of [Text];
RegulatoryCommentBuilder: TextBuilder;
RegulatoryCommentTypeCode: Text;
begin
case SourceDocumentHeader.Number of
Expand Down Expand Up @@ -437,8 +462,19 @@ codeunit 10977 "Peppol BIS 3.0 FR Format" implements "E-Document"
if SalesCommentLine.FindSet() then
repeat
RegulatoryCommentTypeCode := GetRegulatoryCommentTypeCode(SalesCommentLine."FR Regulatory Comment Type");
AddRegulatoryComment(AnchorNode, RegulatoryCommentTypeCode, SalesCommentLine.Comment);
if not RegulatoryComments.Get(RegulatoryCommentTypeCode, RegulatoryCommentBuilder) then begin
Comment thread
djukicmilica marked this conversation as resolved.
Clear(RegulatoryCommentBuilder);
Comment thread
djukicmilica marked this conversation as resolved.
RegulatoryComments.Add(RegulatoryCommentTypeCode, RegulatoryCommentBuilder);
RegulatoryCommentTypeCodes.Add(RegulatoryCommentTypeCode);
end;
if SalesCommentLine.Comment.Trim() <> '' then
RegulatoryCommentBuilder.Append(SalesCommentLine.Comment.Trim());
until SalesCommentLine.Next() = 0;

foreach RegulatoryCommentTypeCode in RegulatoryCommentTypeCodes do begin
RegulatoryComments.Get(RegulatoryCommentTypeCode, RegulatoryCommentBuilder);
AddRegulatoryComment(AnchorNode, RegulatoryCommentTypeCode, RegulatoryCommentBuilder.ToText());
end;
end;
end;

Expand Down Expand Up @@ -545,6 +581,39 @@ codeunit 10977 "Peppol BIS 3.0 FR Format" implements "E-Document"
InjectLegalEntitySIREN(PartyNode, NamespaceMgr, CopyStr(SIRENNo, 1, 20));
end;

local procedure InjectBuyerIdentification(var XmlDoc: XmlDocument; NamespaceMgr: XmlNamespaceManager; SourceDocumentHeader: RecordRef)
var
Customer: Record Customer;
FRCIIXMLBuilder: Codeunit "CII XML Builder";
CustomerNoFieldRef: FieldRef;
BuyerPartyNode: XmlNode;
CustomerNo: Code[20];
SIRENNo: Text;
VATRegistrationNo: Text;
begin
if not XmlDoc.SelectSingleNode('//cac:AccountingCustomerParty/cac:Party', NamespaceMgr, BuyerPartyNode) then
exit;
if not FRCIIXMLBuilder.TryGetCustomerNoFieldRef(SourceDocumentHeader, CustomerNoFieldRef) then
exit;
CustomerNo := CustomerNoFieldRef.Value();
Customer.SetLoadFields("Registration Number", "FR Electronic Address", "VAT Registration No.");
if not Customer.Get(CustomerNo) then
exit;
Comment thread
djukicmilica marked this conversation as resolved.

SIRENNo := GetSIRENNo(Customer."Registration Number", Customer."Registration Number");
if SIRENNo = '' then
if IsNumericIdentifier(CopyStr(Customer."FR Electronic Address", 1, 9), 9) then
SIRENNo := CopyStr(Customer."FR Electronic Address", 1, 9);
if SIRENNo = '' then begin
VATRegistrationNo := DelChr(Customer."VAT Registration No.", '=', ' ');
if (StrLen(VATRegistrationNo) = 13) and (CopyStr(VATRegistrationNo, 1, 2).ToUpper() = 'FR') then
if IsNumericIdentifier(CopyStr(VATRegistrationNo, 5, 9), 9) then
SIRENNo := CopyStr(VATRegistrationNo, 5, 9);
end;
if SIRENNo <> '' then
InjectLegalEntitySIREN(BuyerPartyNode, NamespaceMgr, CopyStr(SIRENNo, 1, 20));
end;

local procedure GetSIRENNo(RegistrationNo: Text; SIRETNo: Text): Text
begin
if IsNumericIdentifier(SIRETNo, 14) then
Expand Down Expand Up @@ -663,18 +732,19 @@ codeunit 10977 "Peppol BIS 3.0 FR Format" implements "E-Document"
if CustomerNo = '' then
exit(false);

if GetServiceParticipantAddress(EDocumentServiceCode, Enum::"E-Document Source Type"::Customer, CustomerNo, ElecAddress, ElecAddressScheme) then begin
ElecAddressScheme := ElecAddressScheme::"0225";
if GetServiceParticipantAddress(EDocumentServiceCode, Enum::"E-Document Source Type"::Customer, CustomerNo, ElecAddress, ElecAddressScheme) then
Comment thread
djukicmilica marked this conversation as resolved.
exit(true);
end;

Customer.SetLoadFields("FR Electronic Address", "Registration Number", "VAT Registration No.");
Customer.SetLoadFields("FR Electronic Address", "FR Elec. Address Scheme", "Registration Number", "VAT Registration No.");
Comment thread
djukicmilica marked this conversation as resolved.
if not Customer.Get(CustomerNo) then
exit(false);

if not FREDocHelpers.GetBuyerElectronicAddress(Customer, ElecAddress) then
exit(false);
ElecAddressScheme := ElecAddressScheme::"0225";
if (Customer."FR Electronic Address" <> '') and (Customer."FR Elec. Address Scheme" <> Customer."FR Elec. Address Scheme"::" ") then
ElecAddressScheme := Customer."FR Elec. Address Scheme"
else
ElecAddressScheme := ElecAddressScheme::"0225";
exit(true);
end;

Expand Down Expand Up @@ -778,10 +848,26 @@ codeunit 10977 "Peppol BIS 3.0 FR Format" implements "E-Document"
EDocServiceSupportedType.Insert();
end;

[IntegrationEvent(false, false)]
local procedure OnBeforeInjectFrenchElements(var TempBlob: Codeunit "Temp Blob"; SourceDocumentHeader: RecordRef; var SourceDocumentLines: RecordRef; EDocumentService: Record "E-Document Service"; var IsHandled: Boolean)
begin
end;

[IntegrationEvent(false, false)]
local procedure OnAfterInjectFrenchElements(var TempBlob: Codeunit "Temp Blob"; SourceDocumentHeader: RecordRef; var SourceDocumentLines: RecordRef; EDocumentService: Record "E-Document Service")
begin
end;

[IntegrationEvent(false, false)]
local procedure OnAfterGetExtendedLineBuyerReference(SalesInvoiceLine: Record "Sales Invoice Line"; var BuyerReference: Text)
begin
end;

var
CbcNamespaceTok: Label 'urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2', Locked = true;
CacNamespaceTok: Label 'urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2', Locked = true;
ExtendedCTCFranceCustomizationIdTok: Label 'EXTENDED-CTC-FR', Locked = true;
FranceCustomizationIdTok: Label 'urn:cen.eu:en16931:2017', Locked = true;
Comment thread
djukicmilica marked this conversation as resolved.
ExtendedCTCFranceCustomizationIdTok: Label 'urn:cen.eu:en16931:2017#conformant#urn.cpro.gouv.fr:1p0:extended-ctc-fr', Locked = true;
RegulatoryCommentFormatTok: Label '#%1#%2', Comment = '%1 = Regulatory comment type, %2 = Comment text', Locked = true;
BillingModeB1Tok: Label 'B1', Locked = true;
BillingModeS1Tok: Label 'S1', Locked = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// ------------------------------------------------------------------------------------------------
namespace Microsoft.eServices.EDocument.Formats.Test;

using Microsoft.eServices.EDocument;
using Microsoft.eServices.EDocument.Formats;
using Microsoft.eServices.EDocument.Processing.Import;
using Microsoft.eServices.EDocument.Processing.Import.Purchase;
using System.Utilities;

codeunit 148149 "E-Doc. FR Struct. Import Tests"
{
Subtype = Test;
Expand Down
Loading
Loading