diff --git a/ax/SRC/A2012_UploadDocument.js b/ax/SRC/A2012_UploadDocument.js new file mode 100644 index 0000000..c0266b4 --- /dev/null +++ b/ax/SRC/A2012_UploadDocument.js @@ -0,0 +1,98 @@ +// -------------------------------------------------------------------------------------- +// A2012_UploadDocument.js +// Copyright 2020 SG|facilitor. 053-4800 700, helpdesk@mareon.nl +// Written by MB (2020) +// + + +function A2012_UploadDocument (v_base64_str) +{ + var v_API = "api/v0.2/UploadDocumentFileBase64"; + + var l_json_data = + { + base64: v_base64_str + } + + var v_req = JSON.stringify(l_json_data, null, 2); + var v_type = 0; + var v_soapAction = ""; + var v_discard_active_abort = 1; //In geval van 500-error, geen active abort... + var v_resp = api_AX2(v_API, v_req, v_type, v_soapAction, v_discard_active_abort); + + //Response v_resp is iets als dit: + //{ + // "checksum": "ouWe2rfVjQXRItrYVAh8zBLgXkK33c3fTvsW7eUaXJc1" + //} + return v_resp; +} + + +function A2012_GetCheckSum_UploadDocument(p_json_text){ + v_checksum = ""; + if (p_json_text){ + p_json = eval("(" + p_json_text + ")"); + v_checksum = p_json.checksum; + } + __Log("A2012_GetCheckSum_UploadDocument v_checksum: " + v_checksum, 3); + return v_checksum; +} + +// v_company_id, unieke id van (interne) bedrijf +// v_entityname, b.v. ServiceTask of PurchaseOrder, in dit geval altijd op nivo van PurchaseOrder +// v_entityid, b.v. MLD15009954-01 (Servicetask) of ION123456 (PurchaseOrder) +// v_checksum, een reeks (string) die AX via A_UploadDocument teruggeeft, en hier moet worden gebruikt. +// v_filename, naam van het te uploaden bestand, b.v test.png +// v_description, omschrijving van het bestand +// v_notes, een bijbehorende notitie. +function A2012_CreateDocuRefByEntityName (v_company_id, v_entityname, v_entityid, v_checksum, v_filename, v_notes) +{ + + var v_API = "api/v0.1/" + v_company_id + "/DocumentReferences"; + + var l_file_without_ext = MARX_substr(v_filename,".",1); + + var l_json_data = + {entityName: v_entityname, + entityId: v_entityid, + documentReference: + {name: l_file_without_ext, + notes: v_notes, + docuTypeId: "Mareon", + fileName: v_filename, + checksum: v_checksum + } + } + + +//Voorbeeld: +// {"entityName": "ServiceTask", +// "entityId": "MLD15009954-01", +// "documentReference": +// {"name": "omschrijving van het testbestand", +// "notes": "notitie", +// "docuTypeId": "Mareon", +// "fileName": "Testbestand.png", +// "checksum": "fGd0DavlPXvhM6wVgHM-zpSGM7R0h8q9xJkIzf3leIk1" +// } +// } + + + var v_req = JSON.stringify(l_json_data, null, 2); + var v_type = 0; + var v_soapAction = ""; + var v_discard_active_abort = 1; //In geval van 500-error, geen active abort... + var v_resp = api_AX2(v_API, v_req, v_type, v_soapAction, v_discard_active_abort); + +//Hieronder is een voorbeeld van de bericht body te zien +// {"entityName": "ServiceTask", +// "entityId": "MLD15009954-01", +// "documentReference": {"name": "Voorbeeld.txt", +// "notes": "Voorbeeld via webservice", +// "docuTypeId": "Bestand", +// "filename": "Voorbeeld.txt", +// "checksum": "89N3v4fkPjSQ5IgkZSEmou6GOjOdiUPRBfFC5tseejI1" } } + + +return v_resp; +} diff --git a/ax/SRC/A365_GetToken.js b/ax/SRC/A365_GetToken.js index 4a7925d..f8cdd0e 100644 --- a/ax/SRC/A365_GetToken.js +++ b/ax/SRC/A365_GetToken.js @@ -4,18 +4,31 @@ // Written by MB (2019) // +function A365_GetToken (){ + return MARX_GetToken(); +} -function A365_GetToken () +function A2012_GetToken (){ + return MARX_GetToken(); +} + +function MARX_GetToken () { - l_request_body = "client_id=" + G_MS_client_id - + "&client_secret=" + G_MS_client_secret - + "&grant_type=" + G_MS_grant_type - + "&resource=" + G_MS_resource + l_request_body = "client_id=" + G_ID_client_id + + "&client_secret=" + G_ID_client_secret + + "&grant_type=" + G_ID_grant_type; + // G_ID_resource is optioneel, in geval van AX365 is derze wel gevuld (en in AX2012 niet) + if (G_ID_resource != "") + l_request_body = l_request_body + "&resource=" + G_ID_resource; + // G_ID_scope is optioneel, in geval van AX365 is deze LEEG en in AX2012 is deze gevuld + if (G_ID_scope != "") + l_request_body = l_request_body + "&scope=" + G_ID_scope; + var v_type = 1; var v_contenttype = "application/x-www-form-urlencoded"; - __Log("A365_GetToken: Nieuwe token opgehaald" ,2); - var v_resp = apiMS(G_MS_url, l_request_body, v_type, v_contenttype, 0); + __Log("MARX_GetToken: Nieuwe token opgehaald" ,2); + var v_resp = apiIDentity(G_ID_url, l_request_body, v_type, v_contenttype, 0); var json_resp = JSON.parse(v_resp); var v_token = json_resp.access_token; diff --git a/ax/SRC/AxFacilitor.js b/ax/SRC/AxFacilitor.js index 3307d9c..97676da 100644 --- a/ax/SRC/AxFacilitor.js +++ b/ax/SRC/AxFacilitor.js @@ -79,6 +79,9 @@ function AX2012_2_FCLT_Opdrachten(){ A2012_GetOpdrachten(); } +function FCLT_2_AX2012_Bijlagen(){ + F_GetOpdrachten_Bijlagen(); +} function FCLT_2_AX2012_OpmerkingOpdrachten(){ F_GetOpdrachten_Opmerking(); } @@ -289,6 +292,27 @@ function Ax2012_2_FACILITOR() __Log("*** Communicatie logboek UIT", 2); } + if (G_mar_sync_bijlages_naar_opdrgvr != '0'){ + __Log("*** START FCLT --> AX2012 : Bijlagen bij opdrachten uit Mareon naar AX ***", 2); + + + //Bijlages naar AX2012 kan alleen via Token icm Saxton AX-webservice(s). Op soortgelijke (bijna identieke wijze) als AX365. + //--------------- + __Log("*** START AX2012 --> FCLT : Get Token ***", 2); + G_Token = ReadTokenFromFile(); + __Log("G_Token ReadTokenFromFile:" + G_Token, 4); + if (G_Token == ""){ + __Log("G_Token ReadTokenFromFile is leeg:", 4); + G_Token = A2012_GetToken(); + } + __Log("*** END Get Token", 2); + //--------------- + + + FCLT_2_AX2012_Bijlagen(); + __Log("*** END", 2); + } + __Log("*** START FCLT --> AX2012 : Afgemelde opdrachten uit Facilitor naar AX ***", 2); FCLT_2_AX2012_AfgemeldeOpdrachten(); __Log("*** END", 2); @@ -494,11 +518,12 @@ var G_ax_succeededfolder = Read_Ini_Setting("xtractor", "succeededfolder"); var G_ax_rejectedfolder = Read_Ini_Setting("xtractor", "rejectedfolder"); // Microsoft Token instellingen -var G_MS_url = Read_Ini_Setting("microsoft","token/url"); -var G_MS_client_id = Read_Ini_Setting("microsoft","token/client_id"); -var G_MS_client_secret = Read_Ini_Setting("microsoft","token/client_secret"); -var G_MS_grant_type = Read_Ini_Setting("microsoft","token/grant_type"); -var G_MS_resource = Read_Ini_Setting("microsoft","token/resource"); +var G_ID_url = Read_Ini_Setting("identityserver","token/url"); +var G_ID_client_id = Read_Ini_Setting("identityserver","token/client_id"); +var G_ID_client_secret = Read_Ini_Setting("identityserver","token/client_secret"); +var G_ID_grant_type = Read_Ini_Setting("identityserver","token/grant_type"); +var G_ID_resource = Read_Ini_Setting("identityserver","token/resource"); +var G_ID_scope = Read_Ini_Setting("identityserver","token/scope"); // Mareon instellingen, de term (XML node) "facilitor" is ivm historie cq. alle locale installaties bij woco's niet 1-2-3 aan te passen in de veel logischere term mareon. var G_marx_url = Read_Ini_Setting("facilitor","url"); @@ -524,7 +549,7 @@ var G_mar_timeout = 0; //initieel 1e keer. __Log("***XML- rems/opdrachtenfolder: " + G_rems_opdracht_xmlfolder, 1); __Log("***XML- rems/opdrachtstatusfolder: " + G_rems_opdrachtstatus_xmlfolder, 1); __Log("***XML- rems/facturenfolder: " + G_rems_facturen_xmlfolder, 1); - __Log("***XML- microsoft/token/url: " + G_MS_url, 1); + __Log("***XML- microsoft/token/url: " + G_ID_url, 1); __Log("***XML- mareon/url: " + G_marx_url, 1); __Log("***XML- xtractor/xmlfolder: " + G_ax_xtractorfolder, 1); __Log("***XML- xtractor/pdffolder: " + G_pdf_xtractorfolder, 1); diff --git a/ax/SRC/AxFacilitor.xml b/ax/SRC/AxFacilitor.xml index 5b2629e..e6e4790 100644 --- a/ax/SRC/AxFacilitor.xml +++ b/ax/SRC/AxFacilitor.xml @@ -28,7 +28,7 @@ http://emmpc0003.sg.nl:8087/MicrosoftDynamicsAXAif60/MSMSupplierPortalHttp/xppservice.svc - http://serviceax2012-dev.aareon.nl + https://saxton-test.aareoncloud.nl sg\robb @@ -44,15 +44,16 @@ 1 - + + - + https://xxxx.facilitor.nl/ diff --git a/ax/SRC/Common.js b/ax/SRC/Common.js index 47840b7..5a3745f 100644 --- a/ax/SRC/Common.js +++ b/ax/SRC/Common.js @@ -269,7 +269,7 @@ function apiAX_GENERAL (v_API, v_req, v_type, v_soapAction, v_discard_active_abo { switch (v_soort_api){ case 1: var v_url = G_ax2012_url; break; - case 2: var v_url = G_ax2012_url_serviceax; break; + case 2: var v_url = G_ax2012_url_serviceax + "/" + v_API; break; } l_result = api2_AX2012_inner(v_url, v_API, v_req, v_type, v_soapAction, v_discard_active_abort, v_soort_api); } @@ -370,6 +370,11 @@ function api2_AX2012_RequestXML(p_url, p_api, p_req_xml){ return v_msg; } +function api2_AX2012_RequestJSON(p_url, p_api, p_req_json){ + var v_msg = p_req_json; + return v_msg; +} + function api2_AX365_RequestXML(p_url, p_api, p_req_xml){ var v_msg = ' '+ '' + @@ -502,11 +507,21 @@ function api2_AX2012_inner (v_Url, v_API, v_req, v_type, v_soapAction, v_discard xmlhttp.setProxy(SXH_PROXY_SET_PROXY, proxy); xmlhttp.open("POST", v_Url, false); - xmlhttp.setRequestHeader("Content-Type", "text/xml"), - xmlhttp.setRequestHeader("Authorization", "Basic " + G_ax2012_bcProxy), - xmlhttp.setRequestHeader("SOAPAction", '"http://tempuri.org/'+v_soapAction+'"'); - - var v_msg = api2_AX2012_RequestXML(v_Url, v_API, v_req); + + if (v_soort_api == 1){ + xmlhttp.setRequestHeader("Content-Type", "text/xml"); + xmlhttp.setRequestHeader("Authorization", "Basic " + G_ax2012_bcProxy); + xmlhttp.setRequestHeader("SOAPAction", '"http://tempuri.org/'+v_soapAction+'"'); + var v_msg = api2_AX2012_RequestXML(v_Url, v_API, v_req); + } + if (v_soort_api == 2){ + xmlhttp.setRequestHeader("Content-Type", "application/json"), + __Log("api2_AX2012_inner G_Token: " + G_Token, 4); + xmlhttp.setRequestHeader("Authorization", "Bearer " + G_Token); + //xmlhttp.setRequestHeader("SOAPAction", '"http://tempuri.org/'+v_soapAction+'"'); + var v_msg = api2_AX2012_RequestJSON(v_Url, v_API, v_req); + } + __Log("api2_AX2012_inner v_msg: " + v_msg, 4); if (G_mar_timeout != 0){ @@ -555,18 +570,43 @@ function api2_AX2012_inner (v_Url, v_API, v_req, v_type, v_soapAction, v_discard } } else - { __Log("api2_AX2012_inner XML Response = FALSE :",1); + { __Log("api2_AX2012_inner XML Response = FALSE :",1); __Log("api2_AX2012_inner - HTTP <> 2xx",1); __Log("api2_AX2012_inner URL: " + v_Url,1); __Log("api2_AX2012_inner Message: " + v_msg,1); __Log("api2_AX2012_inner Status: "+ xmlhttp.status + " " + xmlhttp.statusText,1); - __Log("api2_AX2012_inner ResponseText:" + xmlhttp.responseText,1); - if (G_abort_http_error == 1) - { - MARXQUIT(v_discard_active_abort); + l_resp = xmlhttp.responseText; + __Log("api2_AX2012_inner ResponseText:" + l_resp,1); + + + if (xmlhttp.status == 401){ + // Token expired? Kan heel goed mogelijk zijn, token heeft geldigheid van uur + // In dit geval wordt een HTTP 401 (Unautorized) geretourneerd, (itt AX365, die doet HTTP-500) + + // Forbidden gevonden, we doen een retry, door een nieuwe token op te halen / op te vragen, max. 3 x in een sync (G_AX365_Allowed_Get_Token > 0) + if (G_AX365_Allowed_Get_Token > 0){ + G_AX365_Allowed_Get_Token = G_AX365_Allowed_Get_Token - 1; + G_Token = A365_GetToken(); + // We mogen nu de functie zelf nog eens aanroepen (iteratief). + l_result = api2_AX2012_inner (v_Url, v_API, v_req, v_type, v_soapAction, v_discard_active_abort, v_soort_api); + return l_result; + } + else{ + __Log("api2_AX2012_inner: Token problem, maximum van 3 pogingen zijn allemaal mislukt" ,1); + if (G_abort_http_error == 1) + { + MARXQUIT(v_discard_active_abort); + } + return {api_status_code: 0, api_status_message: xmlhttp.statusText, api_response_message: txt}; + } } - return {api_status_code: 0, api_status_message: xmlhttp.statusText, api_response_message: txt}; - //return "" + else{ + if (G_abort_http_error == 1) + { + MARXQUIT(v_discard_active_abort); + } + return {api_status_code: 0, api_status_message: xmlhttp.statusText, api_response_message: txt}; + } } } @@ -667,7 +707,7 @@ function api2_AX365_inner (v_Url, v_API, v_req, v_type, v_soapAction, v_discard_ G_AX365_Allowed_Get_Token = G_AX365_Allowed_Get_Token - 1; G_Token = A365_GetToken(); // We mogen nu de functie zelf nog eens aanroepen (iteratief). - l_result = api2_AX365_inner (v_Url, v_API, v_req, v_type, v_soapAction, v_soort_api); + l_result = api2_AX365_inner (v_Url, v_API, v_req, v_type, v_soapAction, v_discard_active_abort, v_soort_api); return l_result; } else{ @@ -690,24 +730,25 @@ function api2_AX365_inner (v_Url, v_API, v_req, v_type, v_soapAction, v_discard_ //return "" } } - if (G_abort_http_error == 1) - { - MARXQUIT(v_discard_active_abort); - } - return {api_status_code: 0, api_status_message: xmlhttp.statusText, api_response_message: txt}; - //return "" + else { + if (G_abort_http_error == 1) + { + MARXQUIT(v_discard_active_abort); + } + return {api_status_code: 0, api_status_message: xmlhttp.statusText, api_response_message: txt}; + } } } -function apiMS (v_url, v_req, v_type, v_contenttype, v_discard_active_abort) +function apiIDentity (v_url, v_req, v_type, v_contenttype, v_discard_active_abort) { - __Log("apiMS v_url: " + v_url, 3); - __Log("apiMS v_req: " + v_req, 3); - __Log("apiMS v_type: " + v_type, 3); - __Log("apiMS v_discard_active_abort: " + v_discard_active_abort, 3); + __Log("apiIDentity v_url: " + v_url, 3); + __Log("apiIDentity v_req: " + v_req, 3); + __Log("apiIDentity v_type: " + v_type, 3); + __Log("apiIDentity v_discard_active_abort: " + v_discard_active_abort, 3); var lResolve = 0; var lConnect = 60 * 1000; @@ -733,7 +774,7 @@ function apiMS (v_url, v_req, v_type, v_contenttype, v_discard_active_abort) catch (e) { //MARX#57502: AX Adapter robuuster maken: Waarschijnlijk timeout-error - __Log("apiMS failed/timeout: " + e.description,1); + __Log("apiIDentity failed/timeout: " + e.description,1); if (G_abort_http_error == 1) { MARXQUIT(v_discard_active_abort); @@ -746,20 +787,20 @@ function apiMS (v_url, v_req, v_type, v_contenttype, v_discard_active_abort) try { var txt = xmlhttp.responseText; - __Log("apiMS Response :" + txt, 3); + __Log("apiIDentity Response :" + txt, 3); return txt; } catch (e) { // Waarschijnlijk http-error terug gekregen - __Log("apiMS failed: " + e.description,1); + __Log("apiIDentity failed: " + e.description,1); __Log(txt,1); return ""; } } else - { __Log("apiMS - HTTP <> 2xx",1); + { __Log("apiIDentity - HTTP <> 2xx",1); __Log("URL: " + v_url,1); __Log("Request: " + v_req,1); __Log("Status: "+ xmlhttp.status + " " + xmlhttp.statusText,1); diff --git a/ax/SRC/FCLT_GetOpdrachtBijlages.js b/ax/SRC/FCLT_GetOpdrachtBijlages.js index 17b2e77..5cc3f0a 100644 --- a/ax/SRC/FCLT_GetOpdrachtBijlages.js +++ b/ax/SRC/FCLT_GetOpdrachtBijlages.js @@ -33,7 +33,14 @@ function MARX_2_AX_PutOpdrachtBijlages(v_ax_company_id, v_mld_opdr_key_marx, v_m var v_aantal_bestanden = FCLT_or_MARX_PutOpdrachtBijlages(G_marx_url, G_marx_apikey, v_mld_opdr_key_marx, "", v_ax_company_id, v_mld_opdr_externnr, "28", "", "MARX_2_AX", v_fac_bijlagen_filename); return v_aantal_bestanden; } - +// Parameters: +// v_mld_opdr_key_marx: key van mld_opdr in Mareon +// v_mld_opdr_key_ax: IONR (key) van inkooporder in AX (2012) omgeving +function MARX_2_AX2012_PutOpdrachtBijlages(v_ax_company_id, v_mld_opdr_key_marx, v_mld_opdr_externnr, v_fac_bijlagen_filename) +{ + var v_aantal_bestanden = FCLT_or_MARX_PutOpdrachtBijlages(G_marx_url, G_marx_apikey, v_mld_opdr_key_marx, "", v_ax_company_id, v_mld_opdr_externnr, "28", "", "MARX_2_AX2012", v_fac_bijlagen_filename); + return v_aantal_bestanden; +} function FCLT_or_MARX_PutOpdrachtBijlages(v_url_bron, v_apikey_bron, v_mld_opdr_key_bron, v_url_dest, v_apikey_dest, v_mld_opdr_key_dest, v_mld_kenmerk_key_bron, v_mld_kenmerk_key_dest, v_src_2_dest, v_fac_bijlagen_filename) { @@ -91,6 +98,17 @@ function FCLT_or_MARX_PutOpdrachtBijlages(v_url_bron, v_apikey_bron, v_mld_opdr_ __Log("FCLT_or_MARX_PutOpdrachtBijlages warning: checksum not returned by Tobias AX 2009",1); } } + if (v_src_2_dest == "MARX_2_AX2012") { + var v_resp_json_str = A2012_UploadDocument (v_base64_str); + var v_checksum = A2012_GetCheckSum_UploadDocument(v_resp_json_str); + if (v_checksum != ""){ + // v_company_id, v_entityname, v_entityid , v_checksum, v_filename, v_notes); + A2012_CreateDocuRefByEntityName (v_apikey_dest, "PurchaseOrder", v_mld_opdr_key_dest, v_checksum, l_filename, ""); + } + else{ + __Log("FCLT_or_MARX_PutOpdrachtBijlages warning: checksum not returned by Tobias AX 2012",1); + } + } if ((v_src_2_dest == "FCLT_2_MARX") || (v_src_2_dest == "MARX_2_FCLT")) { // Van Facilitor naar Mareon OF van Mareon naar Facilitor var l_kenmerk_arr = v_mld_kenmerk_key_dest.split(","); diff --git a/ax/SRC/F_GetOpdrachtenBijlagen.js b/ax/SRC/F_GetOpdrachtenBijlagen.js index 0292e86..9539ff6 100644 --- a/ax/SRC/F_GetOpdrachtenBijlagen.js +++ b/ax/SRC/F_GetOpdrachtenBijlagen.js @@ -47,6 +47,9 @@ function F_GetOpdrachten_Bijlagen() if (AX_or_Tobias() == "A") { MARX_2_AX_PutOpdrachtBijlages(v_ax_company_id, v_mld_opdr_key_marx, v_mld_opdr_externnr, v_fac_bijlagen_filename); } + if (AX_or_Tobias() == "A12") { + MARX_2_AX2012_PutOpdrachtBijlages(v_ax_company_id, v_mld_opdr_key_marx, v_mld_opdr_externnr, v_fac_bijlagen_filename); + } if (AX_or_Tobias() == "F") { MARX_2_FCLT_PutOpdrachtBijlages(v_mld_opdr_key_marx, v_mld_opdr_key_fclt, v_fac_bijlagen_filename); }