APplusJob implementiert

This commit is contained in:
Asol.Projects auf Deeg ADM 2023-08-23 13:43:38 +02:00 committed by Thomas Türk
parent 599339a270
commit a5a107c9ea
7 changed files with 244 additions and 2 deletions

View File

@ -1,5 +1,9 @@
# Changelog
## 23.08.2023 v1.1.1
- `APplusJob` für einfachen Zugriff auf `p2core.Job` implementiert
- Funktion für Ausführung von DB-Anpass Dateien implementiert
## 27.07.2023 v1.1.0
- implementiere Zugriff auf ASMX Seiten
- `getClient` -> `getAppClient` umbenannt

View File

@ -20,6 +20,14 @@ PyAPplus64.applus\_db module
:undoc-members:
:show-inheritance:
PyAPplus64.applus\_job module
-----------------------------
.. automodule:: PyAPplus64.applus_job
:members:
:undoc-members:
:show-inheritance:
PyAPplus64.applus\_scripttool module
------------------------------------

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "PyAPplus64"
version = "1.1.0"
version = "1.1.1"
authors = [
{ name="Thomas Tuerk", email="kontakt@thomas-tuerk.de" },
]

View File

@ -7,6 +7,7 @@
# https://opensource.org/licenses/MIT.
from . import applus_db
from . import applus_job
from . import applus_server
from . import applus_sysconf
from . import applus_scripttool
@ -56,12 +57,17 @@ class APplusServer:
self.sysconf: applus_sysconf.APplusSysConf = applus_sysconf.APplusSysConf(self)
"""erlaubt den Zugriff auf die Sysconfig"""
self.job: applus_job.APplusJob = applus_job.APplusJob(self)
"""erlaubt Arbeiten mit Jobs"""
self.scripttool: applus_scripttool.APplusScriptTool = applus_scripttool.APplusScriptTool(self)
"""erlaubt den einfachen Zugriff auf Funktionen des ScriptTools"""
self.client_table = self.server_conn.getAppClient("p2core", "Table")
self.client_xml = self.server_conn.getAppClient("p2core", "XML")
self.client_nummer = self.server_conn.getAppClient("p2system", "Nummer")
self.client_adaptdb = self.server_conn.getAppClient("p2dbtools", "AdaptDB");
def reconnectDB(self) -> None:
try:
@ -123,6 +129,12 @@ class APplusServer:
sqlC = self.completeSQL(sql, raw=raw)
return applus_db.rawQuerySingleValue(self.db_conn, sqlC, *args)
def dbExecute(self, sql: sql_utils.SqlStatement, *args: Any, raw: bool = False) -> Any:
"""Führt ein SQL Statement (z.B. update oder insert) aus. Das SQL wird zunächst
vom Server angepasst, so dass z.B. Mandanteninformation hinzugefügt werden."""
sqlC = self.completeSQL(sql, raw=raw)
return applus_db.rawExecute(self.db_conn, sqlC, *args)
def isDBTableKnown(self, table: str) -> bool:
"""Prüft, ob eine Tabelle im System bekannt ist"""
sql = "select count(*) from SYS.TABLES T where T.NAME=?"
@ -231,6 +243,24 @@ class APplusServer:
"""
return self.client_nummer.service.nextNumber(obj)
def updateDatabase(self, file : str) -> str:
"""
Führt eine DBAnpass-xml Datei aus.
:param file: DB-Anpass Datei, die ausgeführt werden soll
:type file: string
:return: Infos zur Ausführung
:rtype: str
"""
jobId = self.job.createSOAPJob("run DBAnpass " + file);
self.client_adaptdb.service.updateDatabase(jobId, "de", file);
res = self.job.getResultURLString(jobId)
if res is None: res = "FEHLER";
if (res == "Folgende Befehle konnten nicht ausgeführt werden:\n\n"):
return ""
else:
return res
def makeWebLink(self, base: str, **kwargs: Any) -> str:
if not self.server_settings.webserver:
raise Exception("keine Webserver-BaseURL gesetzt")

View File

@ -108,6 +108,11 @@ def rawQuerySingleValue(cnxn: pyodbc.Connection, sql: SqlStatement, *args: Any)
else:
return None
def rawExecute(cnxn: pyodbc.Connection, sql: SqlStatement, *args: Any) -> Any:
"""Führt ein SQL Statement direkt aus"""
_logSQLWithArgs(sql, *args)
with cnxn.cursor() as cursor:
return cursor.execute(str(sql), *args)
def getUniqueFieldsOfTable(cnxn: pyodbc.Connection, table: str) -> Dict[str, List[str]]:
"""

View File

@ -0,0 +1,195 @@
# Copyright (c) 2023 Thomas Tuerk (kontakt@thomas-tuerk.de)
#
# This file is part of PyAPplus64 (see https://www.thomas-tuerk.de/de/pyapplus64).
#
# Use of this source code is governed by an MIT-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/MIT.
from typing import TYPE_CHECKING, Optional
import uuid
if TYPE_CHECKING:
from .applus import APplusServer
class APplusJob:
"""
Zugriff auf Jobs
:param server: die Verbindung zum Server
:type server: APplusServer
"""
def __init__(self, server: 'APplusServer') -> None:
self.client = server.getAppClient("p2core", "Job")
def createSOAPJob(self, bez: str) -> str:
"""
Erzeugt einen neuen SOAP Job mit der gegebenen Bezeichnung und liefert die neue JobID.
:param bez: die Bezeichnung des neuen Jobs
:type bez: str
:return: die neue JobID
:rtype: str
"""
jobId = str(uuid.uuid4())
self.client.service.create(jobId, "SOAP", "0", "about:soapcall", bez)
return jobId
def restart(self, jobId: str) -> str:
"""
Startet einen Job neu
:param jobId: die ID des Jobs
:type jobId: str
:return: die URL des Jobs
:rtype: str
"""
return self.client.service.restart(jobId)
def setResultURL(self, jobId: str, resurl: str) -> None:
"""
Setzt die ResultURL eines Jobs
:param jobId: die ID des Jobs
:type jobId: str
:param resurl: die neue Result-URL
:type resurl: str
"""
self.client.service.setResultURL(jobId, resurl)
def getResultURL(self, jobId: str) -> str:
"""
Liefert die ResultURL eines Jobs
:param jobId: die ID des Jobs
:type jobId: str
:return: die Result-URL
:rtype: str
"""
return self.client.service.getResultURL(jobId)
def getResultURLString(self, jobId: str) -> Optional[str]:
"""
Liefert die ResultURL eines Jobs, wobei ein evtl. Präfix "retstring://" entfernt wird und
alle anderen Werte durch None ersetzt werden.
:param jobId: die ID des Jobs
:type jobId: str
:return: die Result-URL als String
:rtype: str
"""
res = self.getResultURL(jobId)
if res is None:
return None
if res.startswith("retstring://"):
return res[12:]
return None
def setPtURL(self, jobId: str, pturl: str) -> None:
"""
Setzt die ResultURL eines Jobs
:param jobId: die ID des Jobs
:type jobId: str
:param pturl: die neue PtURL
:type pturl: str
"""
self.client.service.setPtURL(jobId, pturl)
def getPtURL(self, jobId: str) -> str:
"""
Liefert die PtURL eines Jobs
:param jobId: die ID des Jobs
:type jobId: str
:return: die Pt-URL
:rtype: str
"""
return self.client.service.getPtURL(jobId)
def setResult(self, jobId: str, res: str) -> None:
"""
Setzt das Result eines Jobs
:param jobId: die ID des Jobs
:type jobId: str
:param res: das neue Result
:type res: str
"""
self.client.service.setResult(jobId, res)
def getResult(self, jobId: str) -> str:
"""
Liefert das Result eines Jobs
:param jobId: die ID des Jobs
:type jobId: str
:return: das Result
:rtype: str
"""
return self.client.service.getResult(jobId)
def setInfo(self, jobId: str, info: str) -> bool:
"""
Setzt die Informationen zu dem Job
:param jobId: die ID des Jobs
:type jobId: str
:param info: die neuen Infos
:type info: str
"""
return self.client.service.setInfo(jobId, info)
def getInfo(self, jobId: str) -> str:
"""
Liefert die Info eines Jobs
:param jobId: die ID des Jobs
:type jobId: str
:return: die Info
:rtype: str
"""
return self.client.service.getInfo(jobId)
def getStatus(self, jobId: str) -> str:
"""
Liefert Informationen zum Job
:param jobId: die ID des Jobs
:type jobId: str
:return: die Infos
:rtype: str
"""
return self.client.service.getStatus(jobId)
def setPosition(self, jobId: str, pos: int, max: int) -> bool:
"""
Schrittfunktion
:param jobId: die ID des Jobs
:type jobId: str
:param pos: Position
:type pos: int
:param max: Anzahl Schritte in Anzeige
:type max: int
"""
return self.client.service.setPosition(jobId, pos, max)
def start(self, jobId: str) -> bool:
"""
Startet einen Job
:param jobId: die ID des Jobs
:type jobId: str
"""
return self.client.service.start(jobId)
def kill(self, jobId: str) -> None:
"""
Startet einen Job
:param jobId: die ID des Jobs
:type jobId: str
"""
self.client.service.start(jobId)
def finish(self, jobId: str, status: int, resurl: str) -> bool:
"""
Beendet den Job
:param jobId: die ID des Jobs
:type jobId: str
:param status: der Status 2 (OK), 3 (Fehler)
:type status: int
:param resurl: die neue resurl des Jobs
:type resurl: str
"""
return self.client.service.finish(jobId, status, resurl)

View File

@ -392,7 +392,7 @@ class SqlConditionBinComp(SqlConditionPrepared):
:type value2: SqlValue
"""
def __init__(self, op: str, value1: SqlValue, value2: SqlValue):
if not value1 or not value2:
if value1 is None or value2 is None:
raise Exception("SqlConditionBinComp: value not provided")
cond = "({} {} {})".format(formatSqlValue(value1), op, formatSqlValue(value2))