Files

1237 lines
37 KiB
JavaScript

var slib = $.import("uniorg.ServiceLayer", "B1SLLogic");
var datetimelib = $.import("uniorg.libs", "datetime");
var logginglib = $.import("uniorg.libs", "uologging");
var slDest = $.import("uniorg.destinations", "uodestlib");
var slfwlib = $.import("uniorg.ServiceLayer", "B1SLFramework");
var output = {};
var outMessages = [];
var outMsg = {};
var outStatus = "success";
var myDebug = {};
var companyid = 0;
var UserName = '';
var UserPass = '';
var UserComp = '';
var SESSIONID = "";
var NODEID = "";
var slLoggedIn = false;
var logTableId = 0;
var logDocEntry = -1;
var serviceName = "crm.cancellation.v1.cancelinvoice.xsjs";
var serviceVersion = '1.9';
var objecttype = "13C";
var schemaName = "A19753_EON_P01";
var projectsReactivated = false;
var projectsReverted = false;
var followupProjects = {
count: 0,
rows: []
};
var debugLevel = 0;
switch ($.request.parameters.get("debug")) {
case "true":
case "yes":
case "1":
debugLevel = 1;
break;
case "full":
case "2":
debugLevel = 2;
break;
}
if (debugLevel > 0) {
output.requestParams = $.request.parameters;
}
function updateLogEntry(id, docEntry, b1Obj) {
var conn = $.hdb.getConnection();
try {
conn.executeUpdate(
"UPDATE \"INTEGRATION_DATA\".\"UO_DOCUMENTS_RAWCALL\" SET \"B1_PK\" = ?, \"B1_OBJ\" = ?, \"UPDATE_TS\" = CURRENT_TIMESTAMP WHERE \"ID\" = ?",
docEntry, b1Obj, id);
conn.commit();
} catch (e) {
exceptionHandler(e);
return;
}
}
function setOutputMessage() {
output.status = outStatus;
if (debugLevel > 0) {
output.debugInfos = myDebug;
}
output.messages = outMessages;
$.response.contentType = "application/json";
$.response.setBody(JSON.stringify(output));
$.response.status = $.net.http.OK;
}
function exceptionHandler(ex) {
if (outMsg.method) {
outMessages.push(outMsg);
}
outMsg = {};
outMsg.method = "exceptionHandler";
outMsg.status = "error";
outMsg.message = ex.toString();
if (debugLevel > 0) {
outMsg.exceptionInfo = {};
outMsg.exceptionInfo.name = ex.name;
outMsg.exceptionInfo.message = ex.message;
outMsg.exceptionInfo.fileName = ex.fileName;
outMsg.exceptionInfo.lineNumber = ex.lineNumber;
outMsg.exceptionInfo.columnNumber = ex.columnNumber;
outMsg.exceptionInfo.stack = ex.stack;
//outMsg.exceptionInfo.source = ex.toSource();
}
outMessages.push(outMsg);
outStatus = "error";
output.status = outStatus;
if (debugLevel > 0) {
output.debugInfos = myDebug;
}
output.messages = outMessages;
var errbody = JSON.stringify(output);
$.response.contentType = 'application/json';
$.response.setBody(errbody);
//$.response.status = $.net.http.INTERNAL_SERVER_ERROR;
// Workaround, weil CRM scheinbar Probleme mit anderen Statuscodes hat
$.response.status = $.net.http.OK;
try {
if (slLoggedIn) {
slib.SLLogout(SESSIONID, NODEID);
}
} catch (e) {
}
}
function setConnectionParams() {
var idValue = schemaName;
var idFieldname = 'SYS_NAME';
var CompanyConfig = slDest.getCompanyCfg(idValue, idFieldname);
UserComp = CompanyConfig.COMPANYNAME;
UserName = CompanyConfig.USERNAME;
UserPass = slDest.readSecureStore(CompanyConfig.ID);
if (debugLevel > 1) {
myDebug.connectionParams = CompanyConfig;
}
myDebug.idValue = idValue;
myDebug.idFieldname = idFieldname;
if (CompanyConfig.COMPANYNAME === undefined) {
outMsg = {};
outMsg.method = "getCompany";
outStatus = "error";
outMsg.status = "error";
outMsg.message = "System " + idValue + " is invalid for this endpoint";
outMessages.push(outMsg);
}
myDebug.CompanyName = UserComp;
}
function slLogin() {
var loginResult = false;
var loginInfo = {};
loginInfo.UserName = UserName;
loginInfo.Password = UserPass;
loginInfo.CompanyDB = UserComp;
// SL LOGIN
var response = slib.SLLogin(JSON.stringify(loginInfo), null, null);
// B1SESSION and ROUTEID cookies returned by Login
for (var j in response.cookies) {
if (response.cookies[j].name == "B1SESSION") {
SESSIONID = response.cookies[j].value;
//output.SessionID = SESSIONID;
} else if (response.cookies[j].name == "ROUTEID") {
NODEID = response.cookies[j].value;
//output.NodeID = NODEID;
}
}
var loginResponse;
try {
loginResponse = JSON.parse(response.body.asString());
} catch (e) {
loginResponse = response.body.asString();
}
if (debugLevel > 1) {
myDebug.loginInfo = loginInfo;
}
myDebug.loginResponse = loginResponse;
if (response.status === 200) {
loginResult = true;
} else {
outMsg = {};
outMsg.method = "login";
outMsg.status = "error";
var slError = myDebug.loginResponse.error;
if (slError && slError.hasOwnProperty("code") && slError.message && slError.message.value) {
outMsg.message = slError.message.value + " (Code: " + slError.code.toString() + ")";
} else {
outMsg.message = JSON.stringify(myDebug.loginResponse);
}
outMsg.response = myDebug.loginResponse;
//outMsg.message = loginResponse;
outMessages.push(outMsg);
outStatus = "error";
}
return loginResult;
}
function getDocDates() {
var docDate, taxDate;
outMsg = {};
outMsg.method = "getDocDates";
outMsg.status = "error";
var conn = $.db.getConnection();
var pstmt;
var query =
'with currentPeriod as (select * from "XXREPXX".OFPR where current_date between "F_RefDate" and "T_RefDate"), \
nextPeriod as (select top 1 * from "XXREPXX".OFPR where "F_RefDate" > current_date order by "F_RefDate") \
select case when currentPeriod."PeriodStat"=\'N\' then current_date \
else to_date(nextPeriod."F_RefDate")end "DocDate", current_date as "TaxDate" \
from currentPeriod, nextPeriod';
query = query.replace(/XXREPXX/g, UserComp);
pstmt = conn.prepareStatement(query);
try {
var rs = pstmt.executeQuery();
while (rs.next()) {
docDate = rs.getDate(1);
taxDate = rs.getDate(2);
outMsg.docDate = docDate;
outMsg.taxDate = taxDate;
outMsg.status = "success";
}
rs.close();
} finally {
pstmt.close();
conn.close();
if (debugLevel > 0 || outMsg.status === "error") {
if (debugLevel > 1) {
outMsg.Query = query;
}
outMessages.push(outMsg);
}
}
return {
docDate: docDate,
taxDate: taxDate
};
}
function getDraft(invoiceCrmGuid) {
outMsg = {};
outMsg.method = "getDraft";
outMsg.status = "error";
outMsg.invoiceCrmGuid = invoiceCrmGuid;
var resultData = {};
var conn = $.hdb.getConnection();
conn.executeUpdate("SET SCHEMA \"" + schemaName + "\"");
var queryResult = conn.executeQuery(
'select \
T0."U_EON_SRC_GUID", T0."U_EON_SRC_ID", \'ODRF\' as "Table", T0."DocEntry", T0."DocNum", T0."DocStatus", T0."CANCELED", T0."draftKey" \
from ODRF T0 \
where T0."ObjType"=\'13\' \
and T0."U_EON_SRC_SYSTEM"=\'crm\' \
and T0."U_EON_SRC_GUID" = ? \
and not exists ( \
select 1 from OINV T1 WHERE T1."draftKey"=T0."DocEntry" \
) \
order by T0."DocEntry"',
invoiceCrmGuid);
var iterator = queryResult.getIterator();
var resultSet = [];
while (iterator.next()) {
resultSet.push(iterator.value());
}
conn.close();
resultData = {
count: resultSet.length,
rows: resultSet
};
outMsg.status = "success";
outMsg.result = resultData;
if (debugLevel > 0 || outMsg.status === "error") {
outMessages.push(outMsg);
}
return resultData;
}
function filterUnprocessedSpoolQueueEntries(docEntry) {
outMsg = {};
outMsg.method = "filterSpoolQueue";
outMsg.status = "error";
outMsg.docEntry = docEntry;
var resultData = {};
var conn = $.hdb.getConnection();
conn.executeUpdate("SET SCHEMA \"" + schemaName + "\"");
var statement =
'update T0 \
set U_UO_STATUS=\'F\', \
U_UO_UPDATEDATE=TO_DATE(CURRENT_TIMESTAMP), \
U_UO_UPDATETIME=HOUR(TO_TIME(CURRENT_TIMESTAMP)) * 100 + MINUTE(TO_TIME(CURRENT_TIMESTAMP)), \
U_UO_LASTERROR=\'Filtered by cancellation process\' \
from "@UO_SPOOL_QUEUE" T0 \
where T0.U_UO_STATUS IN (\'N\',\'E\') and \
T0.U_UO_OBJTYPE=\'13\' and T0.U_UO_DOCENTRY=?';
var affectedRows = conn.executeUpdate(statement, docEntry);
conn.commit();
conn.close();
resultData = {
count: affectedRows
};
outMsg.status = "success";
if (debugLevel > 1) {
outMsg.statement = statement;
}
outMsg.result = resultData;
if (debugLevel > 0 || outMsg.status === "error") {
outMessages.push(outMsg);
}
return resultData;
}
function cancelSpoolTasks(docEntry) {
outMsg = {};
outMsg.method = "cancelSpoolTasks";
outMsg.status = "error";
outMsg.docEntry = docEntry;
var resultData = {};
var conn = $.hdb.getConnection();
conn.executeUpdate("SET SCHEMA \"" + schemaName + "\"");
var statement =
'update t1 \
set U_UO_STATUS=\'C\' \
from "@UO_SPOOL_TASKS" T1 \
where T1.U_UO_STATUS NOT IN (\'I\',\'S\') and T1.U_UO_SPOOLTYPE IN (\'M\',\'P\') and \
exists ( \
select 1 from "@UO_SPOOL" T0 where T0."DocEntry"=T1."DocEntry" and T0.U_UO_OBJTYPE=\'13\' and T0.U_UO_DOCENTRY=? \
)';
var affectedRows = conn.executeUpdate(statement, docEntry);
conn.commit();
conn.close();
resultData = {
count: affectedRows
};
outMsg.status = "success";
if (debugLevel > 1) {
outMsg.statement = statement;
}
outMsg.result = resultData;
if (debugLevel > 0 || outMsg.status === "error") {
outMessages.push(outMsg);
}
return resultData;
}
function getInvoice(invoiceCrmGuid) {
outMsg = {};
outMsg.method = "getInvoice";
outMsg.status = "error";
outMsg.invoiceCrmGuid = invoiceCrmGuid;
var resultData = {};
var conn = $.hdb.getConnection();
conn.executeUpdate("SET SCHEMA \"" + schemaName + "\"");
var queryResult = conn.executeQuery(
'select \
T0."U_EON_SRC_GUID", T0."U_EON_SRC_ID", \'OINV\' as "Table", T0."DocEntry", T0."DocNum", T0."DocStatus", T0."CANCELED", T0."draftKey" \
from OINV T0 \
where T0."U_EON_SRC_SYSTEM"=\'crm\' \
and T0."U_EON_SRC_GUID" = ? \
order by T0."DocEntry"',
invoiceCrmGuid);
var iterator = queryResult.getIterator();
var resultSet = [];
while (iterator.next()) {
resultSet.push(iterator.value());
}
conn.close();
resultData = {
count: resultSet.length,
rows: resultSet
};
outMsg.status = "success";
outMsg.result = resultData;
if (debugLevel > 0 || outMsg.status === "error") {
outMessages.push(outMsg);
}
return resultData;
}
function getCancellationInvoice(baseEntry) {
outMsg = {};
outMsg.method = "getCancellationInvoice";
outMsg.status = "error";
outMsg.baseEntry = baseEntry;
var resultData = {};
var conn = $.hdb.getConnection();
conn.executeUpdate("SET SCHEMA \"" + schemaName + "\"");
var queryResult = conn.executeQuery(
'select T0."DocEntry", T0."DocNum", T0."TransId", T0."Comments" \
from OINV T0 \
where T0.CANCELED=\'C\' and exists ( \
select 1 from INV1 T1 where T1."DocEntry"=T0."DocEntry" and T1."BaseType"=T0."ObjType" and T1."BaseEntry"=? \
)',
baseEntry);
var iterator = queryResult.getIterator();
var resultSet = [];
while (iterator.next()) {
resultSet.push(iterator.value());
}
conn.close();
resultData = {
count: resultSet.length,
rows: resultSet
};
outMsg.status = "success";
outMsg.result = resultData;
if (debugLevel > 0 || outMsg.status === "error") {
outMessages.push(outMsg);
}
return resultData;
}
function checkInactiveProjects(docEntry, docDate) {
outMsg = {};
outMsg.method = "checkInactiveProjects";
outMsg.status = "error";
outMsg.docEntry = docEntry;
outMsg.docDate = datetimelib.convertToISODate(docDate);
var resultData = {};
var conn = $.hdb.getConnection();
conn.executeUpdate("SET SCHEMA \"" + schemaName + "\"");
var queryResult = conn.executeQuery(
'select distinct T1."Project", GET_FOLLOWUP_PROJECT(T1."Project") as "FollowupProject" \
from INV1 T1 \
inner join OPRJ T2 ON T1."Project" = T2."PrjCode" \
where T1."DocEntry" = ? and (T2."Active" = \'N\' or T2."ValidTo" < ?)',
docEntry, datetimelib.convertToISODate(docDate));
var iterator = queryResult.getIterator();
var resultSet = [];
while (iterator.next()) {
resultSet.push(iterator.value());
}
conn.close();
resultData = {
count: resultSet.length,
rows: resultSet
};
if (resultSet.length > 0) {
outMsg.message = "Invoice must be canceled manually in SAP B1 due to inactive projects: " + resultSet.map(function(p) {
return p.Project;
}).join(", ");
} else {
outMsg.status = "success";
}
outMsg.result = resultData;
if (debugLevel > 0 || outMsg.status === "error") {
outMessages.push(outMsg);
}
return resultData;
}
function getFollowupProjects(docEntry) {
outMsg = {};
outMsg.method = "getFollowupProjects";
outMsg.status = "error";
outMsg.docEntry = docEntry;
var resultData = {};
var conn = $.hdb.getConnection();
conn.executeUpdate("SET SCHEMA \"" + schemaName + "\"");
var queryResult = conn.executeQuery(
'with \
oldProjects as ( \
select distinct T2."PrjCode", T2.U_EON_PROFCTR, T2.U_EON_PSP, T2."ValidTo", T2.U_TEMP_VALID_TO \
from OINV T0 \
inner join INV1 T1 on T0."DocEntry"=T1."DocEntry" \
inner join OPRJ T2 on T1."Project" = T2."PrjCode" \
where T0."DocEntry"=? and T2.U_EON_NEWPROJECT!=\'\' \
), \
followupProjects as ( \
select "PrjCode", GET_FOLLOWUP_PROJECT("PrjCode") as "FollowupProject" \
from oldProjects \
) \
select T0."PrjCode" as "ProjectOld", T0."ValidTo", T0.U_TEMP_VALID_TO, T0.U_EON_PROFCTR as "ProfitCenterOld", T0.U_EON_PSP as "PspOld", T1."FollowupProject", T2.U_EON_PROFCTR, T2.U_EON_PSP \
from oldProjects T0 \
inner join followupProjects T1 on T0."PrjCode"=T1."PrjCode" \
inner join OPRJ T2 on T1."FollowupProject" = T2."PrjCode"',
docEntry);
var iterator = queryResult.getIterator();
var resultSet = [];
while (iterator.next()) {
resultSet.push(iterator.value());
}
conn.close();
resultData = {
count: resultSet.length,
rows: resultSet
};
if (resultSet.length > 0) {
outMsg.message = "Projects will be replaced: " + resultSet.map(function(p) {
return p.Project;
}).join(", ");
}
outMsg.status = "success";
outMsg.result = resultData;
if (debugLevel > 0 || outMsg.status === "error") {
outMessages.push(outMsg);
}
return resultData;
}
function reactivateOldProjects(projects) {
/*
- service layer update Project
- U_TEMP_VALID_TO = ValidTo
- ValidTo = '31122099'
*/
var result = false;
var success = true;
if (!slLoggedIn) {
slLoggedIn = slLogin();
}
outMsg = {};
outMsg.method = "reactivateOldProjects";
outMsg.status = "error";
outMsg.proclist = [];
projects.forEach(function(p) {
var slBody = {
ValidTo: '2099-12-31',
U_TEMP_VALID_TO: datetimelib.convertToISODate(p.ValidTo)
};
var newIdx = outMsg.proclist.push({
project: p.ProjectOld,
slBody: slBody,
status: 'error',
resultStatusCode: null,
resultMessage: '',
response: null
}) - 1;
var responseProjectUpdate = slib.patchDynamicEntity('Projects', p.ProjectOld, JSON.stringify(slBody), SESSIONID, NODEID, false);
outMsg.proclist[newIdx].resultStatusCode = responseProjectUpdate.status;
if (responseProjectUpdate.status >= 200 && responseProjectUpdate.status < 300) {
outMsg.proclist[newIdx].status = 'success';
} else {
success = false;
outMsg.status = "error";
outStatus = "error";
if (responseProjectUpdate.body) {
var responseBodyParsed = JSON.parse(responseProjectUpdate.body.asString());
var slError = responseBodyParsed.error;
if (slError && slError.hasOwnProperty("code") && slError.message && slError.message.value) {
outMsg.proclist[newIdx].resultMessage = slError.message.value + " (Code: " + slError.code.toString() + ")";
} else {
outMsg.proclist[newIdx].resultMessage = responseProjectUpdate.body.asString();
}
outMsg.proclist[newIdx].response = responseBodyParsed;
} else {
outMsg.proclist[newIdx].resultMessage = JSON.stringify(responseProjectUpdate);
}
}
});
if (success) {
outMsg.status = "success";
result = true;
}
if (debugLevel > 0 || outMsg.status === "error") {
outMessages.push(outMsg);
}
return result;
}
function revertOldProjects(projects) {
/*
- service layer update Project
- ValidTo = U_TEMP_VALID_TO
- U_TEMP_VALID_TO = NULL
*/
var result = false;
var success = true;
if (!slLoggedIn) {
slLoggedIn = slLogin();
}
outMsg = {};
outMsg.method = "revertOldProjects";
outMsg.status = "error";
outMsg.proclist = [];
projects.forEach(function(p) {
var slBody = {
ValidTo: p.U_TEMP_VALID_TO === null ? datetimelib.convertToISODate(p.ValidTo) : datetimelib.convertToISODate(p.U_TEMP_VALID_TO),
U_TEMP_VALID_TO: null
};
var newIdx = outMsg.proclist.push({
project: p.ProjectOld,
slBody: slBody,
status: 'error',
resultStatusCode: null,
resultMessage: '',
response: null
}) - 1;
var responseProjectUpdate = slib.patchDynamicEntity('Projects', p.ProjectOld, JSON.stringify(slBody), SESSIONID, NODEID, false);
outMsg.proclist[newIdx].resultStatusCode = responseProjectUpdate.status;
if (responseProjectUpdate.status >= 200 && responseProjectUpdate.status < 300) {
outMsg.proclist[newIdx].status = 'success';
} else {
success = false;
outMsg.status = "error";
outStatus = "error";
if (responseProjectUpdate.body) {
var responseBodyParsed = JSON.parse(responseProjectUpdate.body.asString());
var slError = responseBodyParsed.error;
if (slError && slError.hasOwnProperty("code") && slError.message && slError.message.value) {
outMsg.proclist[newIdx].resultMessage = slError.message.value + " (Code: " + slError.code.toString() + ")";
} else {
outMsg.proclist[newIdx].resultMessage = responseProjectUpdate.body.asString();
}
outMsg.proclist[newIdx].response = responseBodyParsed;
} else {
outMsg.proclist[newIdx].resultMessage = JSON.stringify(responseProjectUpdate);
}
}
});
if (success) {
outMsg.status = "success";
result = true;
}
if (debugLevel > 0 || outMsg.status === "error") {
outMessages.push(outMsg);
}
return result;
}
function updateProjectsInJE(transId, projectMapping) {
/*
projectMapping = [
{
projectOld: "123456",
projectNew: "130123456789",
profitCenterNew: "PC12345",
pspNew: "987654321"
}
]
*/
/*
- JE-Update Blockierung deaktivieren
- UPDATE "@EON_FEATURES" SET U_EON_ACTIVE='N' WHERE "Code"='EON_TN6'
- Service Layer Update JournalEntry Lines
- Project => FollowupProject
- Evtl. auch U_EON_PROFCTR und U_EON_PSP aus FollowupProject
- Ggf. nur bestimmte Positionen (nur mit Betrag <> 0)
- JE-Update Blockierung aktivieren
- UPDATE "@EON_FEATURES" SET U_EON_ACTIVE='Y' WHERE "Code"='EON_TN6'
*/
var result = false;
if (!slLoggedIn) {
slLoggedIn = slLogin();
}
outMsg = {};
outMsg.method = "updateProjectsInJE";
outMsg.status = "error";
outMsg.transId = transId;
var conn = $.hdb.getConnection();
conn.executeUpdate("SET SCHEMA \"" + schemaName + "\"");
var affectedRows = conn.executeUpdate("UPDATE \"@EON_FEATURES\" SET U_EON_ACTIVE='N' WHERE \"Code\"='EON_TN6'");
conn.commit();
if (affectedRows === 1) {
outMsg.JEUpdateBlockDeactivated = true;
try {
var getJE = slib.getDynamicEntity('JournalEntries', transId, SESSIONID, NODEID);
if (getJE.status >= 200 && getJE.status < 300) {
var oldJE = JSON.parse(getJE.body.asString());
//myDebug.oldJE = oldJE;
if (oldJE.JournalEntryLines.findIndex(function(je) {
return je.Credit !== 0;
}) > -1) {
var updJE = {
JournalEntryLines: oldJE.JournalEntryLines.map(function(je) {
var jeLine = {
Line_ID: je.Line_ID
};
var prjIdx = projectMapping.findIndex(function(p) {
return p.projectCode = je.ProjectCode;
});
if (prjIdx > -1) {
jeLine.ProjectCode = projectMapping[prjIdx].projectNew;
jeLine.U_EON_PROFCTR = projectMapping[prjIdx].profitCenterNew;
jeLine.U_EON_PSP = projectMapping[prjIdx].pspNew;
}
return jeLine;
})
};
var jeUpdate = slib.patchDynamicEntity('JournalEntries', transId, JSON.stringify(updJE), SESSIONID, NODEID, false);
if (jeUpdate.status >= 200 && jeUpdate.status < 300) {
result = true;
outMsg.status = "success";
} else {
outMsg.status = "error";
outStatus = "error";
if (jeUpdate.body) {
var responseBodyParsed = JSON.parse(jeUpdate.body.asString());
var slError = responseBodyParsed.error;
if (slError && slError.hasOwnProperty("code") && slError.message && slError.message.value) {
outMsg.message = slError.message.value + " (Code: " + slError.code.toString() + ")";
} else {
outMsg.message = jeUpdate.body.asString();
}
outMsg.response = responseBodyParsed;
} else {
outMsg.message = JSON.stringify(jeUpdate);
}
}
} else {
outMsg.status = "success";
outMsg.message = "no update for zero amount journal entry";
}
} else {
// JE Get failed
outMsg.message = 'failed to retrieve journal entry for cancelled invoice';
outStatus = "error";
}
} catch (e) {
throw e;
} finally {
if (outMsg.JEUpdateBlockDeactivated) {
conn.executeUpdate("SET SCHEMA \"" + schemaName + "\"");
affectedRows = conn.executeUpdate("UPDATE \"@EON_FEATURES\" SET U_EON_ACTIVE='Y' WHERE \"Code\"='EON_TN6'");
conn.commit();
if (affectedRows === 1) {
outMsg.JEUpdateBlockReactivated = true;
}
}
}
}
conn.close();
if (debugLevel > 0 || outMsg.status === "error") {
outMessages.push(outMsg);
}
return result;
}
function getInternalReconciliation(docEntry) {
outMsg = {};
outMsg.method = "getInternalReconciliation";
outMsg.status = "error";
outMsg.docEntry = docEntry;
var resultData = {};
var conn = $.hdb.getConnection();
conn.executeUpdate("SET SCHEMA \"" + schemaName + "\"");
var queryResult = conn.executeQuery(
'SELECT T0."ReconNum", T0."ReconType", T0."IsSystem" \
FROM OITR T0 \
INNER JOIN ITR1 T1 ON T0."ReconNum" = T1."ReconNum" \
WHERE T1."SrcObjTyp" = \'13\' and T1."SrcObjAbs" = ? and T0."Canceled" = \'N\'',
docEntry);
var iterator = queryResult.getIterator();
var resultSet = [];
while (iterator.next()) {
var oitr = JSON.parse(JSON.stringify(iterator.value()));
switch (oitr.ReconType) {
case '0':
oitr.ReconTypeDescription = 'Manual';
break;
case '1':
oitr.ReconTypeDescription = 'Automatic';
break;
case '2':
oitr.ReconTypeDescription = 'Semi-Automatic';
break;
case '3':
oitr.ReconTypeDescription = 'Payment';
break;
case '4':
oitr.ReconTypeDescription = 'Credit Memo';
break;
case '6':
oitr.ReconTypeDescription = 'Zero Value';
break;
case '7':
oitr.ReconTypeDescription = 'Cancellation';
break;
case '8':
oitr.ReconTypeDescription = 'BoE';
break;
case '9':
oitr.ReconTypeDescription = 'Deposit';
break;
case '10':
oitr.ReconTypeDescription = 'Bank Statement Processing';
break;
case '11':
oitr.ReconTypeDescription = 'Period Closing';
break;
case '12':
oitr.ReconTypeDescription = 'Correction Invoice';
break;
case '13':
oitr.ReconTypeDescription = 'Inventory/Expense Allocation';
break;
case '14':
oitr.ReconTypeDescription = 'WIP';
break;
case '15':
oitr.ReconTypeDescription = 'Deferred Tax Interim Account';
break;
case '16':
oitr.ReconTypeDescription = 'Down Payment Allocation';
break;
case '17':
oitr.ReconTypeDescription = 'Auto. Conversion Difference';
break;
case '18':
oitr.ReconTypeDescription = 'Interim Document';
break;
case '19':
oitr.ReconTypeDescription = 'Withholding Tax Interim Account';
break;
default:
oitr.ReconTypeDescription = 'Unknown Reconciliation Type';
}
resultSet.push(oitr);
}
conn.close();
resultData = {
count: resultSet.length,
rows: resultSet
};
outMsg.status = "success";
outMsg.result = resultData;
if (debugLevel > 0 || outMsg.status === "error") {
outMessages.push(outMsg);
}
return resultData;
}
function getInternalReconciliationCreditLines(reconNum) {
outMsg = {};
outMsg.method = "getInternalReconciliationCreditLines";
outMsg.status = "error";
outMsg.reconNum = reconNum;
var resultData = {};
var conn = $.hdb.getConnection();
conn.executeUpdate("SET SCHEMA \"" + schemaName + "\"");
var queryResult = conn.executeQuery(
'SELECT T0."ReconNum", T0."ReconType", T0."IsSystem", T1."SrcObjTyp", T1."SrcObjAbs" \
FROM OITR T0 \
INNER JOIN ITR1 T1 ON T0."ReconNum" = T1."ReconNum" \
WHERE T0."ReconNum" = ? and T1."IsCredit" = \'C\'',
reconNum);
var iterator = queryResult.getIterator();
var resultSet = [];
while (iterator.next()) {
resultSet.push(iterator.value());
}
conn.close();
resultData = {
count: resultSet.length,
rows: resultSet
};
outMsg.status = "success";
outMsg.result = resultData;
if (debugLevel > 0 || outMsg.status === "error") {
outMessages.push(outMsg);
}
return resultData;
}
function deleteDraft(docEntry) {
logDocEntry = docEntry;
if (!slLoggedIn) {
slLoggedIn = slLogin();
}
outMsg = {};
outMsg.method = "deleteDraft";
outMsg.status = "error";
outMsg.docEntry = docEntry;
var responseDelete = slib.deleteDraft(docEntry, SESSIONID, NODEID);
outMsg.statuscode = responseDelete.status;
if (responseDelete.status >= 200 && responseDelete.status < 300) {
outMsg.status = "success";
} else {
outMsg.status = "error";
myDebug.statusDelete = responseDelete.status;
myDebug.responseDetele = JSON.stringify(responseDelete);
//outMsg.message = responseDelete.body.asString();
//outMsg.message = JSON.parse(responseDelete.body.asString());
outStatus = "error";
}
outMessages.push(outMsg);
}
function cancelManualReconciliation(reconNum) {
var result = false;
if (!slLoggedIn) {
slLoggedIn = slLogin();
}
outMsg = {};
outMsg.method = "cancelManualReconciliation";
outMsg.status = "error";
outMsg.reconNum = reconNum;
var responseCancel = slib.cancelInternalReconciliation(reconNum, SESSIONID, NODEID);
outMsg.statuscode = responseCancel.status;
if (responseCancel.status >= 200 && responseCancel.status < 300) {
outMsg.status = "success";
result = true;
} else {
outMsg.status = "error";
myDebug.statusCancelReconciliation = responseCancel.status;
myDebug.responseCancelReconciliation = JSON.stringify(responseCancel);
if (responseCancel.body) {
var responseBodyParsed = JSON.parse(responseCancel.body.asString());
var slError = responseBodyParsed.error;
if (slError && slError.hasOwnProperty("code") && slError.message && slError.message.value) {
outMsg.message = slError.message.value + " (Code: " + slError.code.toString() + ")";
} else {
outMsg.message = responseCancel.body.asString();
}
outMsg.response = responseBodyParsed;
} else {
outMsg.message = JSON.stringify(responseCancel);
}
outStatus = "error";
}
outMessages.push(outMsg);
return result;
}
function cancelIncomingPayment(docEntry) {
var result = false;
if (!slLoggedIn) {
slLoggedIn = slLogin();
}
outMsg = {};
outMsg.method = "cancelIncomingPayment";
outMsg.status = "error";
outMsg.docEntry = docEntry;
var responseCancel = slib.CancelIncomingPaymentByCurrentSystemDate(docEntry, SESSIONID, NODEID);
outMsg.statuscode = responseCancel.status;
if (responseCancel.status >= 200 && responseCancel.status < 300) {
outMsg.status = "success";
result = true;
} else {
outMsg.status = "error";
myDebug.statusCancelPayment = responseCancel.status;
myDebug.responseCancelPayment = JSON.stringify(responseCancel);
if (responseCancel.body) {
var responseBodyParsed = JSON.parse(responseCancel.body.asString());
var slError = responseBodyParsed.error;
if (slError && slError.hasOwnProperty("code") && slError.message && slError.message.value) {
outMsg.message = slError.message.value + " (Code: " + slError.code.toString() + ")";
} else {
outMsg.message = responseCancel.body.asString();
}
outMsg.response = responseBodyParsed;
} else {
outMsg.message = JSON.stringify(responseCancel);
}
outStatus = "error";
}
outMessages.push(outMsg);
return result;
}
function updateCancellationInvoice(docEntry, body) {
if (!slLoggedIn) {
slLoggedIn = slLogin();
}
outMsg = {};
outMsg.method = "updateCancellationInvoice";
outMsg.status = "error";
outMsg.docEntry = docEntry;
var responseUpdate = slib.updateInvoice(docEntry, JSON.stringify(body), SESSIONID, NODEID);
outMsg.statuscode = responseUpdate.status;
if (responseUpdate.status >= 200 && responseUpdate.status < 300) {
outMsg.status = "success";
} else {
outMsg.status = "error";
myDebug.statusUpdateInvoice = responseUpdate.status;
myDebug.responseUpdateInvoice = JSON.stringify(responseUpdate);
if (responseUpdate.body) {
var responseBodyParsed = JSON.parse(responseUpdate.body.asString());
var slError = responseBodyParsed.error;
if (slError && slError.hasOwnProperty("code") && slError.message && slError.message.value) {
outMsg.message = slError.message.value + " (Code: " + slError.code.toString() + ")";
} else {
outMsg.message = responseUpdate.body.asString();
}
outMsg.response = responseBodyParsed;
} else {
outMsg.message = JSON.stringify(responseUpdate);
}
outStatus = "error";
}
if (debugLevel > 0 || outMsg.status === "error") {
outMessages.push(outMsg);
}
}
function cancelInvoice(docEntry, docDate) {
logDocEntry = docEntry;
if (!slLoggedIn) {
slLoggedIn = slLogin();
}
outMsg = {};
outMsg.method = "cancelInvoice";
outMsg.status = "error";
outMsg.docEntry = docEntry;
//outMsg.cancellationReason = cancellationReason;
var slBody = {
Document: {
DocEntry: docEntry,
DocDate: datetimelib.convertToISODate(docDate)
}
};
/*if (cancellationReason) {
slBody.Document.U_EON_Cancellation = cancellationReason;
}*/
myDebug.cancelBody = slBody;
var responseCancel = slib.cancelInvoice(JSON.stringify(slBody), SESSIONID, NODEID);
outMsg.statuscode = responseCancel.status;
if (responseCancel.status >= 200 && responseCancel.status < 300) {
outMsg.status = "success";
} else {
outMsg.status = "error";
myDebug.statusCancel = responseCancel.status;
myDebug.responseCancel = JSON.stringify(responseCancel);
if (responseCancel.body) {
var responseBodyParsed = JSON.parse(responseCancel.body.asString());
var slError = responseBodyParsed.error;
if (slError && slError.hasOwnProperty("code") && slError.message && slError.message.value) {
outMsg.message = slError.message.value + " (Code: " + slError.code.toString() + ")";
} else {
outMsg.message = responseCancel.body.asString();
}
outMsg.response = responseBodyParsed;
} else {
outMsg.message = JSON.stringify(responseCancel);
}
outStatus = "error";
}
outMessages.push(outMsg);
}
function cancelWorkflow(inObj) {
try {
var cancelRequest = JSON.parse(inObj);
var invoiceCrmGuid = cancelRequest.invoice_crm_guid;
// check for open draft invoices and delete them
var draftList = getDraft(invoiceCrmGuid);
if (draftList.count > 0) {
draftList.rows.forEach(function(r) {
deleteDraft(r.DocEntry);
});
}
// check for invoice(s)
var invoiceList = getInvoice(invoiceCrmGuid);
if (draftList.count === 0 && invoiceList.count === 0) {
// Rechnungsbeleg existiert nicht in B1
outMsg = {};
outMsg.method = "checkExist";
outMsg.status = "error";
outMsg.invoiceCrmGuid = invoiceCrmGuid;
outMsg.message = "Invoice doesn't exist in SAP B1";
outMessages.push(outMsg);
outStatus = "error";
}
// check cancellation status of found invoice(s)
var invoiceListCanceled = invoiceList.rows.filter(function(r) {
return r.CANCELED !== 'N';
});
myDebug.invoiceListCanceled = invoiceListCanceled;
// error, if results with cancellation status Y (canceled) or C (cancellation document) exist
if (invoiceListCanceled.length > 0 && invoiceListCanceled.length === invoiceList.count) {
outMsg = {};
outMsg.method = "checkCanceled";
outMsg.status = "error";
outMsg.message = "Invoice was already canceled before";
outMessages.push(outMsg);
outStatus = "error";
}
if (invoiceList.count > 0 && outStatus !== "error") {
const {
docDate, taxDate
} = getDocDates();
invoiceList.rows.filter(function(r) {
return r.CANCELED === 'N';
}).forEach(function(r) {
var spoolCancellationInvoice = true; // controls if the cancellation invoice is relevant for output management
// filter spool queue entry if unprocessed
var filteredSpoolQueueInvoice = filterUnprocessedSpoolQueueEntries(r.DocEntry);
if (filteredSpoolQueueInvoice.count > 0) {
spoolCancellationInvoice = false;
}
// abort processing of spool tasks with type Mail and Print, if possible
var canceledSpoolTasks = cancelSpoolTasks(r.DocEntry);
if (canceledSpoolTasks.count > 0) {
spoolCancellationInvoice = false;
}
// check if invoice contains inactive projects (if yes, the invoice must be canceled manually due to complex workaround implemented with add-on)
/* var inactiveProjects = checkInactiveProjects(r.DocEntry, docDate);
if (inactiveProjects.count > 0) {
outStatus = "error";
} else {*/
var cancellationAllowed = true;
// check for manual or automatic internal reconciliations of invoice
var internalReconciliations = getInternalReconciliation(r.DocEntry);
try {
internalReconciliations.rows.forEach(function(oitr) {
switch (oitr.ReconType) {
// 13.10.2025: Kein Storno für Rechnungen mit Zahlung oder anderen internen Abstimmungen
/*
case '0':
// Manual reconciliation -> can be canceled
if (!cancelManualReconciliation(oitr.ReconNum)) {
cancellationAllowed = false;
};
break;
case '3':
// Automatic reconciliation by payment -> get payment entries from ITR1
var internalReconciliationCreditLines = getInternalReconciliationCreditLines(oitr.ReconNum);
internalReconciliationCreditLines.rows.forEach(function(itr1) {
if (itr1.SrcObjTyp === '24') {
// Incoming Payment -> can be canceled
if (!cancelIncomingPayment(itr1.SrcObjAbs)) {
cancellationAllowed = false;
};
}
});
break;
*/
default:
// error for other types of internal reconciliation (Zero value invoice, credit memo, ...)
outMsg = {};
outMsg.method = "checkInternalReconciliation";
outMsg.status = "error";
outMsg.message = "Cannot cancel invoice due to an existing internal reconciliation: " + oitr.ReconTypeDescription;
outMessages.push(outMsg);
outStatus = "error";
cancellationAllowed = false;
throw new Error('ExitForEachLoop');
}
});
} catch (e) {
if (!e.message === 'ExitForEachLoop') {
throw e;
}
}
if (cancellationAllowed && outStatus !== "error") {
// if projects need to be replaced
// reactivateProjects(projects)
followupProjects = getFollowupProjects(r.DocEntry);
var reactivateProjects = followupProjects.rows.filter(function(p) {
return p.U_TEMP_VALID_TO === null;
});
myDebug.reactivateProjects = reactivateProjects;
projectsReactivated = reactivateOldProjects(reactivateProjects);
if (outStatus !== "error") {
// finally cancel the invoice
cancelInvoice(r.DocEntry, docDate);
// get DocEntry and DocNum of created cancellation document
var cancellationInvoice = getCancellationInvoice(r.DocEntry);
cancellationInvoice.rows.forEach(function(ci) {
// update outMsg 'cancelInvoice' with DocEntry and DocNum
var omIndex = outMessages.findIndex(function(om) {
return om.method === 'cancelInvoice' && om.docEntry === r.DocEntry;
});
if (omIndex > -1) {
outMessages[omIndex].cancellationDocEntry = ci.DocEntry;
outMessages[omIndex].cancellationDocNum = ci.DocNum;
}
if (spoolCancellationInvoice === false) {
// no spooling of cancellation document if spooling of original invoice was aborted
filterUnprocessedSpoolQueueEntries(ci.DocEntry);
}
if (cancelRequest.cancellation_reason || cancelRequest.cancellation_remarks) {
// update cancellation invoice UDF and remarks, if provided
// this subsequent update is a workaround, since the UDF cannot be changed when the cancellation document is created
var updateBody = {};
if (cancelRequest.cancellation_reason) {
updateBody.U_EON_Cancellation = cancelRequest.cancellation_reason;
}
if (cancelRequest.cancellation_remarks) {
updateBody.Comments = cancelRequest.cancellation_remarks + '\n' + ci.Comments;
}
updateCancellationInvoice(ci.DocEntry, updateBody);
}
if (projectsReactivated) {
var projectMapping = followupProjects.rows.map(function(fp) {
return {
projectOld: fp.ProjectOld,
projectNew: fp.FollowupProject,
profitCenterNew: fp.U_EON_PROFCTR,
pspNew: fp.U_EON_PSP
};
});
// replace projects in journal entry
var journalEntryUpdated = updateProjectsInJE(ci.TransId, projectMapping);
// deactivate old projects again
projectsReverted = revertOldProjects(followupProjects.rows);
}
});
}
}
//}
});
}
} catch (e) {
exceptionHandler(e);
} finally {
if (projectsReactivated && !projectsReverted) {
try {
revertOldProjects(followupProjects.rows);
} catch (ex) {
}
}
if (slLoggedIn) {
try {
slib.SLLogout(SESSIONID, NODEID);
} catch (ex) {
}
}
}
}
var content = $.request.body.asString();
try {
outMsg = {};
outMsg.method = "logRequest";
outMsg.status = "error";
logTableId = logginglib.logCall2Table(content, "UO_DOCUMENTS_RAWCALL", objecttype, serviceName, true);
outMsg.logTableId = logTableId;
if (logTableId > 0) {
outMsg.status = "success";
}
if (debugLevel > 0) {
outMessages.push(outMsg);
}
} catch (e) {
outStatus = "error";
exceptionHandler(e);
}
setConnectionParams(content);
if (outStatus !== "error") {
cancelWorkflow(content);
}
updateLogEntry(logTableId, logDocEntry, objecttype);
setOutputMessage();