Upgrade auf 24.0.0
Unbedingt die aktuellen Installationsvoraussetzungen vorab prüfen!
Diese Anleitung berücksichtigt immer nur den Sprung von der vorhergehenden Version zu der gerade beschriebenen Version. Bei Upgrades über mehrere Versionen hinweg müssen alle Änderungen der Zwischenversionen ebenfalls beachtet werden! Siehe genereller Ablauf von Upgrades.
Breaking Changes
Diese Version integriert das neue One Unity Standard-DMS und ist demnach ausschließlich mit OUD Versionen kompatibel, welche bereits das Standard-DMS enthalten (ab Version 23.0.0).
Was wurde gemacht?
Zusammenfassung
- Der Datenbank-View
viewInvoiceFileSearchfür die Beleganzeige wurde entfernt und durch eine Scripting-Logik ersetzt. - Validierung: Es gibt nun ein Mandantenattribut
ptpINVRoundingErrorMargin, das die Rundungstoleranz festlegt, die beim Validieren der Kopf- und Positionsdaten berücksichtigt werden soll INV-447 - Invoice ist nun im Standard-DMS integriert INV-537
- Die Outbar "Konfiguration" wurde aufgelöst – deren Inhalt ist nun in der Outbar "One Unity Administration" im Ordner "Rechnungen" zu finden
- In der Outbar "Rechnungen" ist der Ordner "Meine Vorgänge" nun unter "Meine Rechnungsvorgänge", "Rechnungen" unter "Rechungsprozess" und "Fehlerhafte Rechnungen" unter "Prüfung und Validierung" zu finden.
- Mithilfe eines Jobs kann nun der regelmäßige Stammdatenupload über den Insiders-Connector eingerichtet werden INV-575
- Verbesserung des Buchungsvorschlags und der automatischen Zuweisung des fachlichen Prüfers bei der Autoindexierung INV-560
- Der User Exit beim Anlegen einer neuen Steuerschlüssel-Mappe wurde überarbeitet, sodass der TableDialog nun bei nicht gesetztem Buchungskreis Steuerschlüssel für ALLE Buchungskreise anzeigt. Dieser Fallback greift nun ebenso wenn für einen gesetzten Buchungskreis keine Steuerschlüssel gefunden wurden. INV-574
- Einige Funktionen des Skripts
ou.spc.ptpINV.lib.release.listwurden inou.spc.ptpINV.lib.release.list.functionsausgelagert, sodass das Skriptou.tmpl.ptpINV.callbacks.releasediese Funktionen importieren kann, ohne einen Import-Loop zu erzeugen. INV-579 - Eine neue Installations- und Upgradelogik wurde implementiert. INV-553
- Bei Eingabe von '0' als Steuersatz im TableMonitor wurde der TableDialog nicht geöffnet bzw. der zugehörige Steuercode nicht gezogen. Dies wurde behoben. INV-587
- Invoice verwendet ab jetzt den neuen Webworkflow INV-573
- Für die Migration des Visioworkflows siehe Otris-Doku
- Der
ptpInvoice Workflowwurde am MappentypptpInvoiceals zulässiger Workflow hinzugefügt, sowie als Standard-Workflow hinterlegt INV-589 - Die Funktion
validatePositionsMandatoryColumnswurde jeweils aus den Skriptenou.spc.ptpINV.lib.validation.rmbundou.spc.ptpINV.lib.validation.rmbentfernt und als eine einzelne Funktion vom gleichen Namen inou.spc.ptpINV.lib.validationausgelagert. Der FunktionvalidatePositionsinou.spc.ptpINV.lib.validation.rmb, dievalidatePositionsMandatoryColumnsaufruft, kann daher nun das ArgumentmandatoryColumnsübergeben werden, um die zu validierenden Spalten zu definieren – davor waren diese fest im Skript definiert. INV-585 - Neustarts von Workflows sind nun ausschließlich für Benutzer mit der Rolle ptpInvoiceAdmin möglich. INV-572
- Das Speichern einer Mappe vom Typ
cfgVatCodemit einem Steuersatz, der Nachkommastellen hat, wirft nun keinen Fehler mehr. INV-591 - Am Mappentyp
ptpInvoicewurden die MappenfelderescalationCheckundescalationDateentfernt. INV-593
Manuell auszuführende Schritte
Datenbank
Wie in genereller Ablauf von Upgrades beschrieben, muss je nach DBMS entweder die Database/mssql.sql oder die Database/mariadb.sql ausgeführt werden.
Mappentypen
- Am Mappentyp
ptpInvoicemuss - sofern noch nicht vorhanden - unter dem Reiter 'Zulässige Workflows' derptpInvoice Workflowhinzugefügt werden. Ebenso muss unter dem Reiter 'Workflow' derptpInvoice Workflowals Standard-Workflow hinterlegt sein. - Am Mappentyp
ptpInvoicemuss in der Trefferlistereleasedas FeldverificationGroupmit der Bezeichnungpf:filetype.ptpInvoice.verificationGroupam Ende hinzugefügt werden. - Am Mappentyp
ptpInvoicemüssen die bisher ungenutzten FelderescalationCheckundescalationDateentfernt werden. Anschließend viaMappen änderndie Änderungen auf alle bestehenden Mappen anwenden.
Workflow
Es muss ein neuer Signaleingang zwischen Status 100 (FinalState_216) und dem letzten Merge-Element davor (DecisionMerge_164) mit dem Name "Speichern des fachlichen Prüfers" und dem verknüpften Skript ou.sp.ptpINV.workflow.receivesignal.logVerificationUser erstellt werden. Dieser speichert für jede erfolgreich abgeschlossenen Mappe den fachlichen Prüfer in der Datenbank.
Workflow-ext
D:\<EASY|otris>\Workflow-ext\js\ou\cust\ptp\invoice\rob-callbacks-multiTable.js
Hier muss innerhalb der Funktion getVatCodeByVatRate die if-Bedingung if(!vatRate){...} wie unten beschrieben angepasst werden, sodass sich auch bei Eingabe von '0' als Steuersatz im TableMonitor der TableDialog öffnet.
function getVatCodeByVatRate(vatRate, options) {
function clear() {
options.row.set("itemVatRate", "")
options.row.set("itemVatCode", "")
options.row.set("itemVatCodeDescription", "")
}
function clearAndFocusBack() {
clear()
options.row.focus("itemVatRate")
}
clear()
if (vatRate !== 0 && !vatRate) {
return ""
}
var recipient = documentsContext.getFileContext().getFileFieldValue("recipient");
showTableDialog({
...
}
D:\<EASY|otris>\Workflow-ext\js\ou\cust\ptp\invoice\rob-callbacks-multiTable.js
Hier muss in der Funktion getVatCode in der success-Funktion, die an showTableDialog obergeben wird, der Steuersatz anders formatiert werden, sodass auch Steuersätze mit Nachkommastellen korrekt übergeben werden:
Vorher:
success: function (selectedRows) {
if (selectedRows.length <= 0) {
clearAndFocusBack()
return
}
var selectedRow = selectedRows[0]
options.row.set(invplus.mapping.tableAmountFields.cellVatCode, selectedRow.vatcode)
/* Diese Zeile muss ausgetauscht werden */
options.row.set(invplus.mapping.tableAmountFields.cellTaxRate, parseFloat(selectedRow.vatrate))
/* Ende */
var vatRate = options.row.get(invplus.mapping.tableAmountFields.cellTaxRate);
invplus.calculationAmountMultiTable.calculateAmountForRow(options.row, vatRate !== "");
options.row.focus("itemBookingText")
}
Nachher:
success: function (selectedRows) {
if (selectedRows.length <= 0) {
clearAndFocusBack()
return
}
var selectedRow = selectedRows[0]
options.row.set(invplus.mapping.tableAmountFields.cellVatCode, selectedRow.vatcode)
/* Diese Zeile muss hinzugefügt werden */
options.row.set(invplus.mapping.tableAmountFields.cellTaxRate, FormatHelper.convertStringToNumber(selectedRow.vatrate))
/* Ende */
var vatRate = options.row.get(invplus.mapping.tableAmountFields.cellTaxRate);
invplus.calculationAmountMultiTable.calculateAmountForRow(options.row, vatRate !== "");
options.row.focus("itemBookingText")
}
Das gleiche muss für die Funktion getVatCodeByVatRate in der selben Datei gemacht werden:
Vorher:
success: function (selectedRows) {
if (selectedRows.length <= 0) {
clearAndFocusBack()
return
}
var selectedRow = selectedRows[0]
options.row.set(invplus.mapping.tableAmountFields.cellVatCode, selectedRow.vatcode)
/* Diese Zeile muss ausgetauscht werden */
options.row.set(invplus.mapping.tableAmountFields.cellTaxRate, parseFloat(selectedRow.vatrate))
/* Ende */
var vatRate = options.row.get(invplus.mapping.tableAmountFields.cellTaxRate);
invplus.calculationAmountMultiTable.calculateAmountForRow(options.row, vatRate !== "");
options.row.focus("itemBookingText")
}
Nachher:
success: function (selectedRows) {
if (selectedRows.length <= 0) {
clearAndFocusBack()
return
}
var selectedRow = selectedRows[0]
options.row.set(invplus.mapping.tableAmountFields.cellVatCode, selectedRow.vatcode)
/* Diese Zeile muss hinzugefügt werden */
options.row.set(invplus.mapping.tableAmountFields.cellTaxRate, FormatHelper.convertStringToNumber(selectedRow.vatrate))
/* Ende */
var vatRate = options.row.get(invplus.mapping.tableAmountFields.cellTaxRate);
invplus.calculationAmountMultiTable.calculateAmountForRow(options.row, vatRate !== "");
options.row.focus("itemBookingText")
}
D:\<EASY|otris>\Workflow-ext\js\ou\cust\ptp\invoice\invoice-callbacks-file.js
Hier muss in der success-Funktion der unten mit einem Kommentar markierte Block eingesetzt werden, sodass beim Speichern eines Steuersatzes mit Nachkommastellen kein Fehler mehr geworfen wird.
documents.sdk.exitRegistry.registerFileFieldExitCallback(
"cfgVatCode",
"vatCode",
function (documentsContext, options) {
var fileContext = documentsContext.getFileContext();
var fields = ["vatCode", "vatCodeName", "vatRate"];
// Hole Werte
var value = options.fileFieldValue;
var recipient = fileContext.getFileFieldValue("recipient");
if (!value) {
return;
}
showTableDialog({
title: "Steuerschlüssel auswählen",
script: "ou.spc.cfgVC.callback.functions.getVatCode",
preLookupScript: "ou.spc.cfgVC.callback.functions.lookupVatCode",
params: {
searchValue: value,
recipient: recipient,
},
success: function (selectedRows) {
if (selectedRows.length <= 0) {
fields.forEach(function (field) {
fileContext.setFileFieldValue(field, "");
});
return;
}
var selectedRow = selectedRows[0];
// Do not fill field 'recipient' if it is already set
if (fileContext.getFileFieldValue("recipient") != "") {
delete selectedRow.recipient;
}
/* Diesen Block hinzufügen */
if (selectedRow["vatRate"] !== undefined) {
selectedRow["vatRate"] = documents.sdk.utils.formatNumber(selectedRow["vatRate"], ",", null, 2);
}
/* Block Ende */
fileContext.setFileFieldValues(selectedRow);
},
error: function (error) {
documentsContext.openMessageDialog("Fehler", error);
fields.forEach(function (field) {
fileContext.setFileFieldValue(field, "");
});
},
close: function () {
fields.forEach(function (field) {
fileContext.setFileFieldValue(field, "");
});
},
});
}
);
D:\<EASY|otris>\Workflow-ext/html/ou/sp/ptpINV/cover.html
Die Datei cover.html wurde angepasst, d.h. falls es eine Custom-Version von dieser Datei gibt, muss diese ebenfalls folgende Anpassung in der Funktion executeApplyPositions erhalten:
executeApplyPositions(rows, shouldReplace) {
...
rows.forEach(function (row) {
var suggestion = validator.createRowWithNetAmountSuggestion() || {}
for (var key in row) {
if (Object.hasOwnProperty.call(row, key) && excludeColumns.indexOf(key) < 0) {
suggestion[key] = row[key]
}
}
/* Diesen Block einfügen */
if (typeof suggestion.itemVatRate === "string") {
suggestion.itemVatRate = FormatHelper.convertStringToNumber(suggestion.itemVatRate);
}
/* Block Ende */
var newRow = multiTable.addRowWithData(suggestion)
if (newRow && newRow.itemVatRate) {
getDefaultVatCode(newRow.itemVatRate, function (entry) {
newRow.itemVatCode = entry.vatcode
newRow.itemVatCodeDescription = entry.vatcodeName
})
}
})
...
},
Scripting
Alle der Anpassungen unter "Scripting", die sich auf spc-Skripte beziehen, müssen nur übertragen werden, falls für das jeweilige spc-Skript ein gleichnamiges cust-Skript existiert.
ou.spc.ptpINV.install.cfgEnumerationValues
Hier muss die Datenbank 'ptpData' durch 'ousp' ersetzt werden.
Vorher:
...
var db = ou_sp_ptpINV_settings_1.ptpConnections.getDatabaseConnection("ptpData");
...
Nachher:
...
var db = ou_sp_ptpINV_settings_1.ptpConnections.getDatabaseConnection("ousp");
...
ou.spc.ptpINV.settings
Hier muss die Definition von mailTemplateHandlebars entfernt werden, da diese Einstellung nun in ou.cust.oud.settings gesetzt wird:
...
var mailTemplateHandlebars = util.isWindowsOS() ? "".concat(context.getServerInstallPath().replace(/\\server.*$/, ""), "-ext\\reports\\ouMailTemplate.handlebars") : "/usr/share/documents5-ext/reports/ouMailTemplate.handlebars";
exports.mailTemplateHandlebars = mailTemplateHandlebars;
...
ou.spc.ptpINV.settings.monitorRMB
Dieses Skript muss angepasst werden, sodass die Rundungstoleranz auch im Monitor-Gadget verfügbar ist (INV-447):
-
Folgender Import muss hinzugefügt werden:
var getRoundingErrorMarginAsNumberInEuros =
require("ou.sp.ptpINV.lib.roundingErrorMargin").getRoundingErrorMarginAsNumberInEuros; -
Folgender Eintrag muss den
monitorOptionshinzugefügt werden:var monitorOptions = {
roundingErrorMargin: getRoundingErrorMarginAsNumberInEuros(),
...
} -
Die Spalte
itemTotalNetAmountbekommt einen neuen Eintrag:itemTotalNetAmount: {
...
additionalOptions: {
roundingErrorMargin: getRoundingErrorMarginAsNumberInEuros()
},
... -
Die Eigenschaft
footerTemplateder SpalteitemTotalNetAmountmuss ersetzt werden:footerTemplate: function footerTemplate(options) {
var validator = new invplus.validationAmountMultiTable(
options.rows,
options.column.additionalOptions.roundingErrorMargin
);
var result = validator.validate();
var positionsAmount = options.rows
.reduce(function (acc, row) {
return acc.plus(+row.itemTotalNetAmount || 0);
}, new Big(0))
.round(2)
.toNumber();
var textColor = result.success ? "#1b5e20" : "#f44336";
var styles = [
result.showWarning
? "display: flex;justify-content: space-between;align-items: center"
: "text-align: right",
"border-top: solid 2px #000",
"border-bottom: double 3px #000",
"margin: -4px",
"padding-right: 4px",
"padding-left: 4px",
"font-weight: bold",
"color: ".concat(textColor),
];
var formatted = documents.sdk.utils.formatNumber(positionsAmount, null, null, 2);
return "<div style='"
.concat(styles.join(";"), "' title='")
.concat(result.message, "'>")
.concat(result.showWarning ? "<span class='entypo warning' style='color: #333333'></span>" : "")
.concat(formatted, " €</div>");
} -
Die Eigenschaft
clickder SpaltecompareAmountmuss ersetzt werden:click: function click(options) {
var _a;
var roundingErrorMargin =
((_a = multiTableInstances.invoiceItems) === null || _a === void 0
? void 0
: _a.options.roundingErrorMargin) || 0;
var validator = new invplus.validationAmountMultiTable(options.rows, roundingErrorMargin);
var result = validator.validate();
result.showDialog();
}
ou.spc.ptpINV.settings.monitorROB
Dieses Skript muss angepasst werden, sodass die Rundungstoleranz auch im Monitor-Gadget verfügbar ist (INV-447):
-
Folgender Import muss hinzugefügt werden:
var getRoundingErrorMarginAsNumberInEuros =
require("ou.sp.ptpINV.lib.roundingErrorMargin").getRoundingErrorMarginAsNumberInEuros; -
Folgender Eintrag muss den
monitorOptionshinzugefügt werden:var monitorOptions = {
roundingErrorMargin: getRoundingErrorMarginAsNumberInEuros(),
...
} -
Die Spalte
itemTotalNetAmountbekommt einen neuen Eintrag:itemTotalNetAmount: {
...
additionalOptions: {
roundingErrorMargin: getRoundingErrorMarginAsNumberInEuros()
},
... -
Die Eigenschaft
footerTemplateder SpalteitemTotalAmountmuss ersetzt werden:footerTemplate: function footerTemplate(options) {
var validator = new invplus.validationAmountMultiTable(
options.rows,
options.column.additionalOptions.roundingErrorMargin
);
var result = validator.validate();
var fileContext = documentsContext.getFileContext();
var docType = fileContext.getFileFieldValue("docType");
var debitCreditIndicator = docType.substring(0, 1).toUpperCase() === "R" ? "S" : "H";
var positionsAmount = options.rows
.reduce(function (acc, row) {
var amount = +row.itemTotalAmount || 0;
if (row.itemDebitCreditIndicator && debitCreditIndicator !== row.itemDebitCreditIndicator) {
// If debitCreditIndicator doesn't match to itemDebitCreditIndicator, flip operator
amount *= -1;
}
return acc.plus(amount);
}, new Big(0))
.round(2)
.toNumber();
var textColor = result.success ? "#1b5e20" : "#f44336";
var styles = [
result.showWarning
? "display: flex;justify-content: space-between;align-items: center"
: "text-align: right",
"border-top: solid 2px #000",
"border-bottom: double 3px #000",
"margin: -4px",
"padding-right: 4px",
"padding-left: 4px",
"font-weight: bold",
"color: ".concat(textColor),
];
var formatted = documents.sdk.utils.formatNumber(positionsAmount, null, null, 2);
return "<div style='"
.concat(styles.join(";"), "' title='")
.concat(result.message, "'>")
.concat(result.showWarning ? "<span class='entypo warning' style='color: #333333'></span>" : "")
.concat(formatted, " €</div>");
} -
Die Eigenschaft
buttons->appendNewRow->clickmuss angepasst werden:click: function click(options) {
var _a;
var roundingErrorMargin =
((_a = multiTableInstances.invoiceItems) === null || _a === void 0
? void 0
: _a.options.roundingErrorMargin) || 0;
var validator = new invplus.validationAmountMultiTable(options.rows, roundingErrorMargin);
...
} -
Die Eigenschaft
clickder SpaltecompareAmountmuss ersetzt werden:click: function click(options) {
var _a;
var roundingErrorMargin =
((_a = multiTableInstances.invoiceItems) === null || _a === void 0
? void 0
: _a.options.roundingErrorMargin) || 0;
var validator = new invplus.validationAmountMultiTable(options.rows, roundingErrorMargin);
var result = validator.validate();
result.showDialog();
}
ou.spc.ptpINV.callback.functions.cover.historyVerification
Hier muss zuerst ein neuer Import hinzugefügt werden:
var ou_spc_ptpINV_lib_proposal_1 = require("ou.spc.ptpINV.lib.proposal");
Anschließend muss die Funktion getQuery wie folgt angepasst werden:
function getQuery(db) {
var verificationUserPriority = (0, ou_spc_ptpINV_lib_proposal_1.getVerificationUserPriorityFor)(
recipient,
vendorId
);
if (method === "history") {
return ou_sp_SelectBuilder_1.SelectBuilder.from(
verificationUserPriority === "assigned"
? "viewVerificationUserLatestAssigned"
: "viewVerificationUserLatestExecuted",
db
)
.select("editor", "string")
.select("invoiceDate", "date")
.select("Anzahl", "number")
.where("recipient = '".concat(recipient, "'"))
.andWhere("vendorId = '".concat(vendorId, "'"))
.orderBy("invoiceDate", false)
.orderBy("Anzahl", false);
}
return ou_sp_SelectBuilder_1.SelectBuilder.from(
verificationUserPriority === "assigned"
? "viewVerificationUserFrequencyAssigned"
: "viewVerificationUserFrequencyExecuted",
db
)
.select("editor", "string")
.select("Prozent", "float")
.select("Anzahl", "number")
.where("recipient = '".concat(recipient, "'"))
.andWhere("vendorId = '".concat(vendorId, "'"))
.orderBy("Prozent", false)
.orderBy("Anzahl", false);
}
ou.spc.ptpINV.filetype.action.manStartWF
Hier muss zuerst ein neuer Import hinzugefügt werden:
var ou_sp_ptpINV_lib_verificationUserMonitor_1 = require("ou.sp.ptpINV.lib.verificationUserMonitor");
Anschließend muss nach dem docFile.sync(); folgende Zeile eingefügt werden:
(0, ou_sp_ptpINV_lib_verificationUserMonitor_1.deleteVerificationUserEntriesForFile)(docFile);
ou.spc.ptpINV.filetype.field.html.cover
In der Funktion getVerificationData muss unter der Variable var methods = ... folgender Code hinzugefügt werden:
var selectedPriority = (0, ou_spc_ptpINV_lib_proposal_1.getVerificationUserPriorityFor)(
docFile.recipient,
docFile.vendorId
);
var selectedPriorityLabel =
selectedPriority === "assigned"
? context.getFromSystemTable("filetype.cfgBP.verificationUserPriority.assigned")
: context.getFromSystemTable("filetype.cfgBP.verificationUserPriority.executed");
Im Rückgabeobjekt der gleichen Funktion muss der Eintrag header erweitert werden:
{
header: "Vergangene Rechnungsprüfer (".concat(selectedPriorityLabel, ")"),
...
}
ou.spc.ptpINV.lib.proposal
Es gibt eine neue Funktion:
/**
* Returns the value for the given key from the first booking proposal
* @param {keyof cfgBookingProposal} key
* @param {string} recipient
* @param {string} vendorId
* @param {string} defaultValue
* @returns {string}
*/
function getValueFromFirstBookingProposal(key, recipient, vendorId, defaultValue) {
if (!recipient || !vendorId) {
logger.debug("getValueFromFirstBookingProposal recipient oder vendorId ist leer");
return defaultValue;
}
var filter = "recipient='".concat(recipient, "' AND vendorId='").concat(vendorId, "'");
logger.debug("Suche nach ptpVendorSettings: ".concat(filter));
var vendorSettingsFiles = new FileResultset("ptpVendorSettings", filter);
if (!vendorSettingsFiles || vendorSettingsFiles.size() <= 0) {
logger.debug("Keine Einträge gefunden");
return defaultValue;
}
var ids = [];
ou_sp_Iterators_1.Iterators.foreach(vendorSettingsFiles, function (vendorSettingsFile) {
ids.push(vendorSettingsFile.uuid);
});
var filterIds = "vendorFileId~".concat(util.getQuoted(ids.join("|")));
logger.debug("Suche nach cfgBookingProposal: ".concat(filterIds));
var files = new FileResultset("cfgBookingProposal", filterIds, "");
if (!files || files.size() <= 0) {
logger.debug("Keine Einträge gefunden");
return defaultValue;
}
var proposal = files.first();
logger.debug("Verwende '".concat(proposal[key], "' aus ").concat(proposal.getid()));
return proposal[key];
}
Zudem haben sich zwei Funktionen geändert:
/**
* Returns the booking proposal method for specified vendor or globally selected proposal method
* @param {string} recipient
* @param {string} vendorId
* @returns {"frequency"|"history"|"custom"|"none"|""}
*/
function getVerificationUserProposalMethodFor(recipient, vendorId) {
var defaultMethod = getGlobalVerificationUserProposalMethod();
var method = getValueFromFirstBookingProposal("verificationUserProposalMethod", recipient, vendorId, defaultMethod);
return method;
}
/**
* Returns the booking proposal method for specified vendor or globally selected proposal method
* @param {string} recipient
* @param {string} vendorId
* @returns {"assigned" | "executed"}
*/
function getVerificationUserPriorityFor(recipient, vendorId) {
var defaultPriority = "executed";
var priority = getValueFromFirstBookingProposal("verificationUserPriority", recipient, vendorId, defaultPriority);
return priority || defaultPriority;
}
ou.spc.ptpINV.lib.proposal.verificationUser.frequency
Zuerst muss ein neuer Import hinzugefügt werden:
var ou_spc_ptpINV_lib_proposal_1 = require("ou.spc.ptpINV.lib.proposal");
Dann muss die Funktion getLastEditor ausgetauscht werden:
function getLastEditor(db, recipient, vendorId) {
var verificationUserPriority = (0, ou_spc_ptpINV_lib_proposal_1.getVerificationUserPriorityFor)(
recipient,
vendorId
);
var view =
verificationUserPriority === "assigned"
? "viewVerificationUserFrequencyAssigned"
: "viewVerificationUserFrequencyExecuted";
var query = ou_sp_SelectBuilder_1.SelectBuilder.from(view, db)
.select("editor", "string")
.select("Prozent", "float")
.where("recipient = '".concat(recipient, "'"))
.andWhere("vendorId = '".concat(vendorId, "'"))
.andWhere("Prozent >= ".concat(minPercentage))
.andWhere("Anzahl >= ".concat(minVerificationCount))
.orderBy("Prozent", false);
logger.debug("SQL: ".concat(query.toSQL()));
var rows = query.execute();
if (rows.length <= 0) {
logger.debug("No data");
return "";
}
logger.debug("Daten aus View: ".concat(JSON.stringify(rows[0])));
return rows[0].editor;
}
ou.spc.ptpINV.lib.proposal.verificationUser.history
Zuerst muss ein neuer Import hinzugefügt werden:
var ou_spc_ptpINV_lib_proposal_1 = require("ou.spc.ptpINV.lib.proposal");
Dann muss die Funktion getLastEditor ausgetauscht werden:
function getLastEditor(db, recipient, vendorId) {
var verificationUserPriority = (0, ou_spc_ptpINV_lib_proposal_1.getVerificationUserPriorityFor)(
recipient,
vendorId
);
var view =
verificationUserPriority === "assigned"
? "viewVerificationUserLatestAssigned"
: "viewVerificationUserLatestExecuted";
var query = ou_sp_SelectBuilder_1.SelectBuilder.from(view, db)
.select("editor", "string")
.select("invoiceDate", "date")
.select("Anzahl", "number")
.where("recipient = '".concat(recipient, "'"))
.where(" AND vendorId = '".concat(vendorId, "'"))
.orderBy("invoiceDate", false)
.orderBy("Anzahl", false);
logger.debug("SQL: ".concat(query.toSQL()));
var rows = query.execute();
var lastEditor = rows.length > 0 ? rows[0].editor : "";
logger.debug("Editor aus View: ".concat(lastEditor));
return lastEditor;
}
ou.tmpl.ptpINV.callbacks.monitor
Hier gibt es zwei neue callbacks:
/**
* Callback bevor die Funktion logVerificationUser ausgeführt wird
* @param { { docFile: ptpInvoice } } data
*/
var logVerificationUserBefore = function logVerificationUserBefore(data) {
logger.debug("trigger logVerificationUser before");
};
/**
* Callback nachdem die Funktion logVerificationUser ausgeführt wurde
* @param { { docFile: ptpInvoice, assigned: string, executed: string } } data
*/
var logVerificationUserAfter = function logVerificationUserAfter(data) {
logger.debug("trigger logVerificationUser after");
};
...
ou_sp_ptpINV_lib_callbacks_1.ptpINVCallbacks.registerCallback("before", "logVerificationUser", logVerificationUserBefore);
ou_sp_ptpINV_lib_callbacks_1.ptpINVCallbacks.registerCallback("after", "logVerificationUser", logVerificationUserAfter);
ou.spc.cfgVC.callback.functions.getVatCode
Hier muss das cust-Skript mit dem zugehörigen spc-Skript verglichen werden und es müssen ggf. die Änderungen, die sich aus dem Vergleich des 'alten' mit dem 'neuen' spc-Skript ergeben, übernommen werden.
spc-Skript vorheriges Release:
context.enableModules(); // ************************************************************************
// One Unity Consulting GmbH & Co. KG
// ************************************************************************
// Beschreibung: User Exit Callback für Steuerschlüssel
// ************************************************************************
if (typeof module !== "undefined") {
exports.executeDirectly = executeDirectly;
}
var ou_sp_gadget_TableDialog_1 = require("ou.sp.gadget.TableDialog");
var ou_spc_ptpINV_settings_1 = require("ou.spc.ptpINV.settings");
var ou_sp_SelectBuilder_1 = require("ou.sp.SelectBuilder");
function executeDirectly() {
var ptpConnections = (0, ou_spc_ptpINV_settings_1.getSettings)().ptpConnections;
var db = ptpConnections.getDatabaseConnection("ptpData");
try {
var args = ou_sp_gadget_TableDialog_1.TableDialog.getParams();
var recipient = args.recipient.replace(/\*/, "%") || "%";
var searchValue = args.searchValue.replace(/\*/, "%") || "%";
var rows = ou_sp_SelectBuilder_1.SelectBuilder.from("vatcode", db)
.select("vatcode", "string")
.select("vatcodeName", "string")
.select("vatrate", "float")
.where("recipient = '".concat(recipient, "'"))
.andWhere("vatcode LIKE '%".concat(searchValue, "%'"))
.orderBy("vatcodeName", false)
.execute();
var table = new ou_sp_gadget_TableDialog_1.TableDialog({
rows: rows,
columns: {
vatcode: {
label: "de:Steuerschlüssel;en:Vat code",
field: "vatCode",
},
vatcodeName: {
label: "de:Bezeichnung;en:Description",
field: "vatCodeName",
},
vatrate: {
label: "de:Steuersatz;en:Vat rate",
field: "vatRate",
type: "number",
},
},
});
return table.transfer();
} catch (error) {
context.errorMessage = error.message;
return -1;
} finally {
if (db) {
db.close();
}
}
}
spc-Skript aktuelles Release:
context.enableModules(); // ************************************************************************
// One Unity Consulting GmbH & Co. KG
// ************************************************************************
// Beschreibung: User Exit Callback für Steuerschlüssel
// ************************************************************************
if (typeof module !== "undefined") {
exports.executeDirectly = executeDirectly;
}
var tslib_1 = require("ou.sp.externals.tslib");
var ou_sp_gadget_TableDialog_1 = require("ou.sp.gadget.TableDialog");
var ou_spc_ptpINV_settings_1 = require("ou.spc.ptpINV.settings");
var ou_sp_SelectBuilder_1 = require("ou.sp.SelectBuilder");
function executeDirectly() {
var columnsVat = {
vatcode: {
label: "de:Steuerschlüssel;en:Vat code",
field: "vatCode",
},
vatcodeName: {
label: "de:Bezeichnung;en:Description",
field: "vatCodeName",
},
vatrate: {
label: "de:Steuersatz;en:Vat rate",
field: "vatRate",
type: "number",
},
};
var columnRecipient = {
recipient: {
label: "de:Buchungskreis;en:Recipient",
field: "recipient",
},
};
var ptpConnections = (0, ou_spc_ptpINV_settings_1.getSettings)().ptpConnections;
var db = ptpConnections.getDatabaseConnection("ptpData");
try {
var args = ou_sp_gadget_TableDialog_1.TableDialog.getParams();
var recipient = args.recipient || "%";
var searchValue = args.searchValue.replace(/\*/, "%") || "%";
var rows = ou_sp_SelectBuilder_1.SelectBuilder.from("vatcode", db)
.select("recipient", "string")
.select("vatcode", "string")
.select("vatcodeName", "string")
.select("vatrate", "float")
.where("recipient ".concat(recipient === "%" ? "LIKE" : "=", " '").concat(recipient, "'"))
.andWhere("vatcode LIKE '%".concat(searchValue, "%'"))
.orderBy("vatcodeName", false)
.execute();
if (recipient === "%") {
// Display results for all recipients
var table_1 = new ou_sp_gadget_TableDialog_1.TableDialog({
rows: rows,
columns: tslib_1.__assign(tslib_1.__assign({}, columnRecipient), columnsVat),
});
return table_1.transfer();
}
if (rows.length > 0) {
// Results found for given recipient -> display results
var table_2 = new ou_sp_gadget_TableDialog_1.TableDialog({
rows: rows,
columns: columnsVat,
});
return table_2.transfer();
}
// No results found for given recipient -> query all recipients
rows = ou_sp_SelectBuilder_1.SelectBuilder.from("vatcode", db)
.select("recipient", "string")
.select("vatcode", "string")
.select("vatcodeName", "string")
.select("vatrate", "float")
.where("vatcode LIKE '%".concat(searchValue, "%'"))
.orderBy("vatcodeName", false)
.execute();
if (rows.length === 1) {
// Add empty row to ensure that table dialog is displayed
rows.push({
recipient: "",
vatcode: "",
vatcodeName: "",
vatrate: null,
});
}
var table = new ou_sp_gadget_TableDialog_1.TableDialog({
rows: rows,
columns: tslib_1.__assign(tslib_1.__assign({}, columnRecipient), columnsVat),
});
return table.transfer();
} catch (error) {
context.errorMessage = error.message;
return -1;
} finally {
if (db) {
db.close();
}
}
}
ou.spc.cfgVC.callback.functions.lookupVatCode
Auch hier muss das cust-Skript mit dem zugehörigen spc-Skript verglichen werden und es müssen ggf. die Änderungen, die sich aus dem Vergleich des 'alten' mit dem 'neuen' spc-Skript ergeben, übernommen werden.
spc-Skript vorheriges Release:
context.enableModules(); // ************************************************************************
// One Unity Consulting GmbH & Co. KG
// ************************************************************************
// Beschreibung: User Exit Callback für Steuerschlüssel
// ************************************************************************
if (typeof module !== "undefined") {
exports.executeDirectly = executeDirectly;
}
var ou_sp_gadget_TableDialog_1 = require("ou.sp.gadget.TableDialog");
var ou_spc_ptpINV_settings_1 = require("ou.spc.ptpINV.settings");
var ou_sp_SelectBuilder_1 = require("ou.sp.SelectBuilder");
function executeDirectly() {
var ptpConnections = (0, ou_spc_ptpINV_settings_1.getSettings)().ptpConnections;
var db = ptpConnections.getDatabaseConnection("ptpData");
try {
var args = ou_sp_gadget_TableDialog_1.TableDialog.getParams();
var recipient = args.recipient.replace(/\*/, "%") || "%";
var searchValue = args.searchValue.replace(/\*/, "%") || "%";
var rows = ou_sp_SelectBuilder_1.SelectBuilder.from("vatcode", db)
.count("vatcodeName", "count")
.where("recipient = '".concat(recipient, "'"))
.andWhere("vatcode LIKE '%".concat(searchValue, "%'"))
.execute();
return rows[0].count;
} catch (error) {
context.errorMessage = error.message;
return -1;
} finally {
if (db) {
db.close();
}
}
}
spc-Skript aktuelles Release:
context.enableModules(); // ************************************************************************
// One Unity Consulting GmbH & Co. KG
// ************************************************************************
// Beschreibung: User Exit Callback für Steuerschlüssel
// ************************************************************************
if (typeof module !== "undefined") {
exports.executeDirectly = executeDirectly;
}
var ou_sp_gadget_TableDialog_1 = require("ou.sp.gadget.TableDialog");
var ou_spc_ptpINV_settings_1 = require("ou.spc.ptpINV.settings");
var ou_sp_SelectBuilder_1 = require("ou.sp.SelectBuilder");
function executeDirectly() {
var ptpConnections = (0, ou_spc_ptpINV_settings_1.getSettings)().ptpConnections;
var db = ptpConnections.getDatabaseConnection("ptpData");
try {
var args = ou_sp_gadget_TableDialog_1.TableDialog.getParams();
var recipient = args.recipient || "%";
var searchValue = args.searchValue.replace(/\*/, "%") || "%";
var rows = ou_sp_SelectBuilder_1.SelectBuilder.from("vatcode", db)
.count("vatcodeName", "count")
.where("recipient ".concat(recipient === "%" ? "LIKE" : "=", " '").concat(recipient, "'"))
.andWhere("vatcode LIKE '%".concat(searchValue, "%'"))
.execute();
if (rows[0].count === 0 && recipient != "%") {
rows = ou_sp_SelectBuilder_1.SelectBuilder.from("vatcode", db)
.count("vatcodeName", "count")
.where("vatcode LIKE '%".concat(searchValue, "%'"))
.execute();
if (rows[0].count === 1) {
// Add empty row to ensure that table dialog is displayed
rows[0].count = rows[0].count + 1;
}
}
return rows[0].count;
} catch (error) {
context.errorMessage = error.message;
return -1;
} finally {
if (db) {
db.close();
}
}
}
ou.spc.ptpINV.lib.index.validation
In der Funktion validateRMB muss dem Funktionsaufruf rmbValidation.validatePositions als zweites Argument nun ein Objekt übergeben werden, das die zu validierenden Spalten definiert:
errors = tslib_1.__spreadArray(tslib_1.__spreadArray([], tslib_1.__read(errors), false), tslib_1.__read(rmbValidation.validatePositions(docFile, /* Dieses Objekt muss als Argument eingefügt werden */ {
itemOrderNumber: "Bestell-Nr muss gefüllt sein",
itemQuantity: "Menge muss gefüllt sein",
itemSingleAmount: "Einzelpreis muss gefüllt sein",
itemTotalNetAmount: "Nettobetrag muss gefüllt sein"
} /* Objekt Ende */ )), false);
ou.spc.ptpINV.workflow.guard.export
Dem Funktionsaufruf validationRMB.validatePositions muss als zweites Argument ein Objekt übergeben werden, das die zu validierenden Spalten definiert:
errors = tslib_1.__spreadArray(tslib_1.__spreadArray([], tslib_1.__read(errors), false), tslib_1.__read(validationRMB.validatePositions(docFile, /* Dieses Objekt muss als Argument eingefügt werden */ {
itemOrderNumber: "Bestell-Nr muss gefüllt sein",
itemQuantity: "Menge muss gefüllt sein",
itemSingleAmount: "Einzelpreis muss gefüllt sein",
itemTotalNetAmount: "Nettobetrag muss gefüllt sein"
} /* Objekt Ende */ )), false);
ou.spc.ptpINV.workflow.guard.manualExport
Dem Funktionsaufruf rmbValidation.validatePositions muss als zweites Argument ein Objekt übergeben werden, das die zu
validierenden Spalten definiert:
errors = rmbValidation.validatePositions(docFile, /* Dieses Objekt muss als Argument eingefügt werden */ {
itemOrderNumber: "Bestell-Nr muss gefüllt sein",
itemQuantity: "Menge muss gefüllt sein",
itemSingleAmount: "Einzelpreis muss gefüllt sein",
itemTotalNetAmount: "Nettobetrag muss gefüllt sein"
} /* Objekt Ende */);
ou.spc.ptpINV.filetype.action.approvedButtons.ts
Auch hier muss das cust-Skript mit dem zugehörigen spc-Skript verglichen werden und es müssen ggf. die Änderungen, die sich aus dem Vergleich des 'alten' mit dem 'neuen' spc-Skript ergeben, übernommen werden.
spc-Skript vorheriges Release:
import { isLockingWorfklowUser } from "./ou.sp.ptpINV.lib";
function executeDirectly() {
const docFile = context.file as ptpInvoice;
const globalState = docFile.globalState;
const su = context.getSystemUser();
const hasAdmin = su.hasAccessProfile("ptpInvoiceAdmin");
const hasAccounting = su.hasAccessProfile("ptpInvoiceAccounting");
const isArchiveFile = docFile.isArchiveFile();
// Wenn Archivmappe, alle Buttons ausblenden
if (isArchiveFile) {
enumval.forEach((_, index) => {
enumval[index] = "";
});
return;
}
const locksWF = isLockingWorfklowUser(docFile, su.login);
for (var i = 0; i < enumval.length; i++) {
// Aufgabe übernehmen nur für Buchhaltung und nur in Status 30
if (enumval[i] == "takeTask") {
if (!hasAccounting || locksWF || globalState != "30") enumval[i] = "";
continue;
}
// DocType darf nur in den Fehlerstati und der Indexierung geändert werden
if (enumval[i] == "changeDocType") {
if (["0", "10", "20", "91", "95"].indexOf(globalState) < 0 || !locksWF) enumval[i] = "";
continue;
}
// Kontierungsvorlagen dürfen nur in der Indexierung verwendet werden
if (enumval[i] == "loadBookingTemplate" || enumval[i] == "writeBookingTemplate") {
if (globalState != "20" || !locksWF) enumval[i] = "";
continue;
}
}
}
export { executeDirectly };
spc-Skript aktuelles Release:
import { isLockingWorfklowUser } from "./ou.sp.ptpINV.lib";
function executeDirectly() {
const docFile = context.file as ptpInvoice;
const globalState = docFile.globalState;
const su = context.getSystemUser();
const hasAdmin = su.hasAccessProfile("ptpInvoiceAdmin");
const hasAccounting = su.hasAccessProfile("ptpInvoiceAccounting");
const isArchiveFile = docFile.isArchiveFile();
// Wenn Archivmappe, alle Buttons ausblenden
if (isArchiveFile) {
enumval.forEach((_, index) => {
enumval[index] = "";
});
return;
}
const locksWF = isLockingWorfklowUser(docFile, su.login);
for (var i = 0; i < enumval.length; i++) {
// Aufgabe übernehmen nur für Buchhaltung und nur in Status 30
if (enumval[i] == "takeTask") {
if (!hasAccounting || locksWF || globalState != "30") enumval[i] = "";
continue;
}
// DocType darf nur in den Fehlerstati und der Indexierung geändert werden
if (enumval[i] == "changeDocType") {
if (["0", "10", "20", "91", "95"].indexOf(globalState) < 0 || !locksWF) enumval[i] = "";
continue;
}
// Kontierungsvorlagen dürfen nur in der Indexierung verwendet werden
if (enumval[i] == "loadBookingTemplate" || enumval[i] == "writeBookingTemplate") {
if (globalState != "20" || !locksWF) enumval[i] = "";
continue;
}
// Neustarten des Workflows dürfen nur von ptpInvoiceAdmin verwendet werden
if (enumval[i] == "startReleaseWF") {
if (!hasAdmin) enumval[i] = "";
continue;
}
}
}
export { executeDirectly };
Alle cust-Skripte, die darüber hinaus (siehe die drei letzten Skripte) die Funktion validatePositionsMandatoryColumns aus dem Skript ou.spc.ptpINV.lib.validation.rmb oder ou.spc.ptpINV.lib.validation.rmb importieren, müssen angepasst werden und die Funktion nun aus dem Skript ou.sp.ptpINV.lib.validation importieren. Zudem is das Objekt, das die zu validierenden Spalten festlegt, für die RMB-Validierung nun nicht mehr fest im Code hinterlegt, sondern muss als zweites Argument an die Funktion übergeben werden. Dies betrifft also nun sowohl die eben genannte Funktion validatePositionsMandatoryColumns als auch die Funktion validatePositions in ou.spc.ptpINV.lib.validation.rmb:
ou.spc.ptpINV.settings.monitorROB.ts
Hier wurde für die Spalte itemVatRate die Eigenschaft decimalPrecision von 0 auf 2 geändert, um auch Steuersätze mit Nachkommastellen anzeigen zu können:
itemVatRate: {
label: "de:Steuersatz;en:Vat rate",
width: "90px",
type: "number",
decimalPrecision: 2,
selectOnFocus: true,
change: function change(value, options) {
//@ts-ignore
invplus.calculationAmountMultiTable.calculateAmountForRow(options.row, value !== "");
getVatCodeByVatRate(value, options);
}
},
Folgende Funktionen wurden vom Skript ou.spc.ptpINV.lib.release.list in das Skript ou.spc.ptpINV.lib.release.list.functions ausgelagert:
validateCreateReleaseListOptionsgetCurrentRequiredReleaseUserensureUserWithSufficentReleaseRoleExistgetCurrentReleaseEntrygetCurrentVerificationEntrymarkCurrentVerificationUserAsReleasedmarkAllAsInactiveensureNextReleaseUserIsRequiredInCaseOfSubstituteloginNameToFullNamegetNextReleaseUserSubstituteensureMinNumberOfReleaseUsers
Existiert das Skript ou.cust.ptpINV.lib.release.list, so muss das Skript ou.cust.ptpINV.lib.release.list.functions erstellt werden. In diesem Skript müssen dann alle Funktionen mit den gleichnamigen Funktionen aus ou.cust.ptpINV.lib.release.list überschrieben werden.
Zudem muss in allen cust-Skripten, die eine der oben genannten Funktionen verwenden, der Import von ou.spc.ptpINV.lib.release.list durch ou.spc.ptpINV.lib.release.list.functions ersetzt werden – dies betrifft folgende Skripte aus dem Standard und ggf. auch eigene cust-Skripte:
ou.spc.ptpINV.filetype.action.manStartWFou.spc.ptpINV.lib.gadgets.verificationou.spc.ptpINV.workflow.decision.checkAfterVerifyou.spc.ptpINV.workflow.guard.backToIndexou.spc.ptpINV.workflow.guard.verified
Abschließend müssen folgende Skripte gelöscht werden:
ou.sp.ptpINV.installou.sp.ptpINV.update.bookingTemplatesou.sp.ptpINV.update.INV-447ou.sp.ptpINV.update.INV-537ou.sp.ptpINV.update.INV-541ou.sp.ptpINV.update.INV-543ou.sp.ptpINV.update.INV-549ou.sp.ptpINV.update.INV-557ou.sp.ptpINV.update.INV-560ou.sp.ptpINV.update.INV-564ou.sp.ptpINV.update.INV-577ou.sp.ptpINV.updateou.spc.ptpINV.install.adminDashboard