Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[E-Document Connector] SignUp E-Document Connector #27261

Open
wants to merge 37 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
d70b100
EDocument Connector SignUp
Sep 16, 2024
758acd2
Change obsolete field reference
Sep 17, 2024
013d1a7
Use IsSaaSInfrastructure to make fields visible if not in SaaS Sandbo…
Sep 17, 2024
5d3ad67
Push forward object id range by 10 due to Avalara addition
Sep 17, 2024
74c785b
Menu item Open Onboarding only available in SaaS
Sep 17, 2024
1042f9f
Change permission structure. Correct spelling. Adjust broken file ending
Sep 18, 2024
69453b6
Change to using instead of full namespace path
Sep 19, 2024
ebdb725
Refactor (MS) - Prefix Removal, Error Raise on Missing Config, Parame…
Sep 20, 2024
9eb3704
Resolve Build Conflict in GitHub - Rename
Sep 24, 2024
94266e2
Resolve Build Conflict in GitHub - Refactor Codeunit Processing
Sep 24, 2024
f9c4dc2
Merge branch 'microsoft:main' into edocumentconnector
geschwint Sep 25, 2024
def7176
Relocate To Own App - Move Files
Sep 25, 2024
9e817ea
Merge branch 'microsoft:main' into edocumentconnector
geschwint Sep 25, 2024
cd8da89
Merge branch 'edocumentconnector' of https://github.com/geschwint/ALA…
Sep 25, 2024
3811370
Refactor - Rename Files
Sep 25, 2024
17944a2
Refactor - Add app.json
Sep 25, 2024
6cdeaea
Refactor - Restore Original Objects
Sep 25, 2024
4382237
Refactor - Rename Processing
Sep 25, 2024
7bd134c
Refactor - Permission Extensions, Object Rename
Sep 25, 2024
42b9a11
Refactor - References to Processing
Sep 25, 2024
6480969
Refactor - Restore app.json
Sep 25, 2024
d7ecea8
Refactor - Missed a spot in restoring original
Sep 25, 2024
f6bc5f9
Merge branch 'microsoft:main' into edocumentconnector
geschwint Sep 25, 2024
f39fb47
Refactor - Missing Logo
Sep 26, 2024
a8c22c7
Refactor - Exit return value
Sep 27, 2024
e11508a
Refactor - Move UriTemplates to Global
Sep 27, 2024
bfca640
Refactor - Eliminate unneeded calls
Sep 27, 2024
1e24593
Refactor - Error when unsupported EDocument Type
Sep 27, 2024
8027450
Refactor - To use ErrorInfo
Sep 27, 2024
cdc94a6
Merge branch 'microsoft:main' into edocumentconnector
geschwint Sep 27, 2024
8bd90ac
Refactor - Move local labels to global
Sep 27, 2024
896cbe8
Refactor - No need for Retry
Sep 27, 2024
a12493f
Refactor - Make labels Global
Sep 27, 2024
ea3a35e
Refactor - Remove labels, API path inline the Avalara way
Sep 27, 2024
e991757
Refactor - Correct Telemetry Token
Sep 30, 2024
a8c547d
Refactor - Fix bug introduced during refactoring, Rename procedure to…
Oct 1, 2024
594e897
Merge branch 'microsoft:main' into edocumentconnector
geschwint Oct 1, 2024
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
47 changes: 47 additions & 0 deletions Apps/W1/EDocumentConnectors/SignUp/app/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"id": "b56171bd-9a8e-47ad-a527-99f476d5af83",
"name": "E-Document Connector - SignUp",
"publisher": "Microsoft",
"brief": "E-Document Connector - SignUp",
"description": "E-Document Connector - SignUp",
"version": "26.0.0.0",
"privacyStatement": "https://go.microsoft.com/fwlink/?LinkId=724009",
"EULA": "https://go.microsoft.com/fwlink/?linkid=2009120",
"help": "https://go.microsoft.com/fwlink/?linkid=2204541",
"url": "https://go.microsoft.com/fwlink/?LinkId=724011",
"logo": "ExtensionLogo.png",
"contextSensitiveHelpUrl": "https://go.microsoft.com/fwlink/?linkid=2206603",
"dependencies": [
{
"id": "e1d97edc-c239-46b4-8d84-6368bdf67c8b",
"name": "E-Document Core",
"publisher": "Microsoft",
"version": "26.0.0.0"
},
{
"id": "d852a468-263e-49e5-bfda-f09e33342b89",
"name": "E-Documents Connector with External Endpoints",
"publisher": "Microsoft",
"version": "26.0.0.0"
}
],
"internalsVisibleTo": [],
"screenshots": [],
"platform": "26.0.0.0",
"idRanges": [
{
"from": 6380,
"to": 6389
}
],
"resourceExposurePolicy": {
"allowDebugging": true,
"allowDownloadingSource": true,
"includeSourceInSymbolFile": true
},
"application": "26.0.0.0",
"target": "OnPrem",
"features": [
"TranslationFile"
]
}
221 changes: 221 additions & 0 deletions Apps/W1/EDocumentConnectors/SignUp/app/src/APIRequests.Codeunit.al
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
// ------------------------------------------------------------------------------------------------
// 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.EDocumentConnector.SignUp;

using Microsoft.EServices.EDocument;
using Microsoft.Foundation.Company;
using Microsoft.Sales.Customer;
using System.Security.Authentication;
using System.Text;
using System.Utilities;
using System.Xml;

codeunit 6380 APIRequests
{
Access = Internal;

// https://<BASE URL>/api/Peppol
procedure SendFilePostRequest(var TempBlob: Codeunit "Temp Blob"; EDocument: Record "E-Document"; var HttpRequestMessage: HttpRequestMessage; var HttpResponseMessage: HttpResponseMessage): Boolean
var
ConnectionSetup: Record ConnectionSetup;
Payload: Text;
ContentHttpHeaders: HttpHeaders;
HttpContent: HttpContent;
ContentText: Text;
UriTemplateLbl: Label '%1/api/Peppol', Comment = '%1 = Service Url', Locked = true;
geschwint marked this conversation as resolved.
Show resolved Hide resolved
begin
InitRequest(ConnectionSetup, HttpRequestMessage, HttpResponseMessage);
HttpRequestMessage := PrepareRequestMsg("Http Request Type"::POST, StrSubstNo(UriTemplateLbl, ConnectionSetup.ServiceURL));

Payload := XmlToTxt(TempBlob);
if Payload = '' then
exit(false);
Clear(HttpContent);
ContentText := PrepareContentForSend(GetDocumentType(EDocument), ConnectionSetup."Company Id", GetCustomerID(EDocument), GetSenderCountryCode(), Payload, ConnectionSetup."Send Mode");
HttpContent.WriteFrom(ContentText);
HttpContent.GetHeaders(ContentHttpHeaders);
if ContentHttpHeaders.Contains('Content-Type') then
ContentHttpHeaders.Remove('Content-Type');
ContentHttpHeaders.Add('Content-Type', 'application/json');
HttpRequestMessage.Content(HttpContent);

exit(SendRequest(HttpRequestMessage, HttpResponseMessage));
end;

// https://<BASE URL>/api/Peppol/status?peppolInstanceId=
procedure GetSentDocumentStatus(EDocument: Record "E-Document"; var HttpRequestMessage: HttpRequestMessage; var HttpResponseMessage: HttpResponseMessage): Boolean
var
ConnectionSetup: Record ConnectionSetup;
UriTemplateLbl: Label '%1/api/Peppol/status?peppolInstanceId=%2', Comment = '%1 = Service Url, %2 = Document ID', Locked = true;
begin
InitRequest(ConnectionSetup, HttpRequestMessage, HttpResponseMessage);
HttpRequestMessage := PrepareRequestMsg("Http Request Type"::GET, StrSubstNo(UriTemplateLbl, ConnectionSetup.ServiceURL, EDocument."Document Id"));
exit(SendRequest(HttpRequestMessage, HttpResponseMessage));
end;

// https://<BASE URL>/api/Peppol/outbox?peppolInstanceId=
procedure PatchADocument(EDocument: Record "E-Document"; var HttpRequestMessage: HttpRequestMessage; var HttpResponseMessage: HttpResponseMessage): Boolean
var
ConnectionSetup: Record ConnectionSetup;
UriTemplateLbl: Label '%1/api/Peppol/outbox?peppolInstanceId=%2', Comment = '%1 = Service Url, %2 = Document ID', Locked = true;
begin
InitRequest(ConnectionSetup, HttpRequestMessage, HttpResponseMessage);
HttpRequestMessage := PrepareRequestMsg("Http Request Type"::PATCH, StrSubstNo(UriTemplateLbl, ConnectionSetup.ServiceURL, EDocument."Document Id"));
exit(SendRequest(HttpRequestMessage, HttpResponseMessage));
end;

// https://<BASE URL>/api/Peppol/Inbox?peppolId=
procedure GetReceivedDocumentsRequest(var HttpRequestMessage: HttpRequestMessage; var HttpResponseMessage: HttpResponseMessage; Parameters: Dictionary of [Text, Text]): Boolean
var
ConnectionSetup: Record ConnectionSetup;
UriTemplateLbl: Label '%1/api/Peppol/Inbox?peppolId=%2', Comment = '%1 = Service Url, %2 = Peppol Identifier', Locked = true;
begin
InitRequest(ConnectionSetup, HttpRequestMessage, HttpResponseMessage);
HttpRequestMessage := PrepareRequestMsg("Http Request Type"::GET, StrSubstNo(UriTemplateLbl, ConnectionSetup.ServiceURL, GetSenderReceiverPrefix() + ConnectionSetup."Company Id"));
exit(SendRequest(HttpRequestMessage, HttpResponseMessage));
end;

// https://<BASE URL>/api/Peppol/inbox-document?peppolId=
procedure GetTargetDocumentRequest(DocumentId: Text; var HttpRequestMessage: HttpRequestMessage; var HttpResponseMessage: HttpResponseMessage): Boolean
var
ConnectionSetup: Record ConnectionSetup;
UriTemplateLbl: Label '%1/api/Peppol/inbox-document?peppolId=%2&peppolInstanceId=%3', Comment = '%1 = Service Url, %2 = Peppol Identifier, %3 = Peppol Gateway Instance', Locked = true;
begin
InitRequest(ConnectionSetup, HttpRequestMessage, HttpResponseMessage);
HttpRequestMessage := PrepareRequestMsg("Http Request Type"::GET, StrSubstNo(UriTemplateLbl, ConnectionSetup.ServiceURL, GetSenderReceiverPrefix() + ConnectionSetup."Company Id", DocumentId));
exit(SendRequest(HttpRequestMessage, HttpResponseMessage));
end;

// https://<BASE URL>/api/Peppol/inbox?peppolInstanceId=
procedure PatchReceivedDocument(EDocument: Record "E-Document"; var HttpRequestMessage: HttpRequestMessage; var HttpResponseMessage: HttpResponseMessage): Boolean
var
ConnectionSetup: Record ConnectionSetup;
UriTemplateLbl: Label '%1/api/Peppol/inbox?peppolInstanceId=%2', Comment = '%1 = Service Url, %2 = Peppol Gateway Instance', Locked = true;
begin
InitRequest(ConnectionSetup, HttpRequestMessage, HttpResponseMessage);
HttpRequestMessage := PrepareRequestMsg("Http Request Type"::PATCH, StrSubstNo(UriTemplateLbl, ConnectionSetup.ServiceURL, EDocument."Document Id"));
exit(SendRequest(HttpRequestMessage, HttpResponseMessage));
end;

procedure GetMarketPlaceCredentials(var HttpRequestMessage: HttpRequestMessage; var HttpResponseMessage: HttpResponseMessage): Boolean
var
ConnectionSetup: Record ConnectionSetup;
Auth: Codeunit Auth;
BaseUrlTxt: Label '%1/api/Registration/init?EntraTenantId=%2', Locked = true;
begin
InitRequest(ConnectionSetup, HttpRequestMessage, HttpResponseMessage);
HttpRequestMessage := PrepareRequestMsg("Http Request Type"::POST, StrSubstNo(BaseUrlTxt, Auth.GetRootUrl(), Auth.GetBCInstanceIdentifier()));
exit(SendRequest(HttpRequestMessage, HttpResponseMessage, true));
end;

local procedure InitRequest(var ConnectionSetup: Record ConnectionSetup; var HttpRequestMessage: HttpRequestMessage; var HttpResponseMessage: HttpResponseMessage)
begin
Clear(HttpRequestMessage);
Clear(HttpResponseMessage);
if not ConnectionSetup.Get() then
Error(MissingSetupErr);
end;

local procedure SendRequest(HttpRequestMessage: HttpRequestMessage; var HttpResponseMessage: HttpResponseMessage): Boolean
begin
SendRequest(HttpRequestMessage, HttpResponseMessage, false);
end;

local procedure SendRequest(HttpRequestMessage: HttpRequestMessage; var HttpResponseMessage: HttpResponseMessage; RootRequest: Boolean): Boolean
var
Auth: Codeunit Auth;
HttpClient: HttpClient;
HttpHeaders: HttpHeaders;
begin
HttpRequestMessage.GetHeaders(HttpHeaders);
if RootRequest then
HttpHeaders.Add('Authorization', Auth.GetRootBearerAuthText())
else
HttpHeaders.Add('Authorization', Auth.GetBearerAuthText());
exit(HttpClient.Send(HttpRequestMessage, HttpResponseMessage));
end;

local procedure PrepareRequestMsg(HttpRequestType: Enum "Http Request Type"; Uri: Text) RequestMessage: HttpRequestMessage
var
Headers: HttpHeaders;
begin
RequestMessage.Method(Format(HttpRequestType));
RequestMessage.SetRequestUri(Uri);
RequestMessage.GetHeaders(Headers);
Headers.Add('Accept', '*/*');
end;

local procedure XmlToTxt(var TempBlob: Codeunit "Temp Blob"): Text
var
XMLDOMManagement: Codeunit "XML DOM Management";
InStr: InStream;
Content: Text;
begin
TempBlob.CreateInStream(InStr, TextEncoding::UTF8);
XMLDOMManagement.TryGetXMLAsText(InStr, Content);
exit(Content);
end;

local procedure GetDocumentType(EDocument: Record "E-Document"): Text
begin
if EDocument.Direction = EDocument.Direction::Incoming then
exit('ApplicationResponse');

case EDocument."Document Type" of
geschwint marked this conversation as resolved.
Show resolved Hide resolved
"E-Document Type"::"Sales Invoice", "E-Document Type"::"Sales Credit Memo", "E-Document Type"::"Service Invoice", "E-Document Type"::"Service Credit Memo":
exit('Invoice');
"E-Document Type"::"Issued Finance Charge Memo", "E-Document Type"::"Issued Reminder":
exit('PaymentReminder');
end;
end;

local procedure GetCustomerID(EDocument: Record "E-Document"): Text[50]
var
Customer: Record Customer;
begin
Customer.Get(EDocument."Bill-to/Pay-to No.");
Customer.TestField("Service Participant Id");

Check failure on line 179 in Apps/W1/EDocumentConnectors/SignUp/app/src/APIRequests.Codeunit.al

View workflow job for this annotation

GitHub Actions / Build 1st Party Apps (W1) (Translated) / 1st Party Apps (W1) (Translated)

AL0118 The name '"Service Participant Id"' does not exist in the current context.
exit(Customer."Service Participant Id");

Check failure on line 180 in Apps/W1/EDocumentConnectors/SignUp/app/src/APIRequests.Codeunit.al

View workflow job for this annotation

GitHub Actions / Build 1st Party Apps (W1) (Translated) / 1st Party Apps (W1) (Translated)

AL0132 'Record Customer' does not contain a definition for 'Service Participant Id'
end;

local procedure GetSenderCountryCode(): Text
var
CompanyInformation: Record "Company Information";
begin
CompanyInformation.Get();
CompanyInformation.TestField("Country/Region Code");
exit(CompanyInformation."Country/Region Code");
end;

local procedure PrepareContentForSend(DocumentType: Text; SendingCompanyID: Text; RecieverCompanyID: Text; SenderCountryCode: Text; Payload: Text; SendMode: Enum SendMode): Text
var
Base64Convert: Codeunit "Base64 Convert";
SendJsonObject: JsonObject;
ContentText: Text;
begin
SendJsonObject.Add('documentType', DocumentType);
SendJsonObject.Add('receiver', GetSenderReceiverPrefix() + RecieverCompanyID);
SendJsonObject.Add('sender', GetSenderReceiverPrefix() + SendingCompanyID);
SendJsonObject.Add('senderCountryCode', SenderCountryCode);
SendJsonObject.Add('documentId', 'urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0::2.1');
SendJsonObject.Add('documentIdScheme', 'busdox-docid-qns');
SendJsonObject.Add('processId', 'urn:fdc:peppol.eu:2017:poacc:billing:01:1.0');
SendJsonObject.Add('processIdScheme', 'cenbii-procid-ubl');
SendJsonObject.Add('sendMode', Format(SendMode));
SendJsonObject.Add('document', Base64Convert.ToBase64(Payload));
SendJsonObject.WriteTo(ContentText);
exit(ContentText);
end;

local procedure GetSenderReceiverPrefix(): Text
var
SenderReceiverPrefixLbl: Label 'iso6523-actorid-upis::', Locked = true;
begin
exit(SenderReceiverPrefixLbl);
end;

var
MissingSetupErr: Label 'You must set up service integration in the E-Document service card.';
}
Loading
Loading