kongalib 2.0.4__cp314-cp314t-macosx_10_15_universal2.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of kongalib might be problematic. Click here for more details.
- _kongalib.cpython-314t-darwin.so +0 -0
- kongalib/__init__.py +394 -0
- kongalib/async_client.py +813 -0
- kongalib/client.py +1045 -0
- kongalib/constants.json +1 -0
- kongalib/constants.py +187 -0
- kongalib/data_dictionary.py +203 -0
- kongalib/db.py +267 -0
- kongalib/expression.py +841 -0
- kongalib/json.py +114 -0
- kongalib/lex.py +1058 -0
- kongalib/scripting.py +766 -0
- kongalib/yacc.py +3276 -0
- kongalib-2.0.4.dist-info/METADATA +150 -0
- kongalib-2.0.4.dist-info/RECORD +21 -0
- kongalib-2.0.4.dist-info/WHEEL +6 -0
- kongalib-2.0.4.dist-info/licenses/LICENSE +165 -0
- kongalib-2.0.4.dist-info/top_level.txt +4 -0
- kongalib-2.0.4.dist-info/zip-safe +1 -0
- kongaui.py +507 -0
- kongautil.py +581 -0
kongautil.py
ADDED
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# _ _ _ _
|
|
3
|
+
# | | | (_) |
|
|
4
|
+
# | | _____ _ __ __ _ __ _| |_| |__
|
|
5
|
+
# | |/ / _ \| '_ \ / _` |/ _` | | | '_ \
|
|
6
|
+
# | < (_) | | | | (_| | (_| | | | |_) |
|
|
7
|
+
# |_|\_\___/|_| |_|\__, |\__,_|_|_|_.__/
|
|
8
|
+
# __/ |
|
|
9
|
+
# |___/
|
|
10
|
+
#
|
|
11
|
+
# Konga client library, by EasyByte Software
|
|
12
|
+
#
|
|
13
|
+
# https://github.com/easybyte-software/kongalib
|
|
14
|
+
|
|
15
|
+
from __future__ import print_function
|
|
16
|
+
|
|
17
|
+
import sys
|
|
18
|
+
import os, os.path
|
|
19
|
+
import kongalib
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
from shlex import quote
|
|
23
|
+
except:
|
|
24
|
+
from pipes import quote
|
|
25
|
+
|
|
26
|
+
from kongalib.scripting import proxy as _proxy
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
PRINT_TARGET_PREVIEW = 0 #: Stampa a video
|
|
30
|
+
PRINT_TARGET_PAPER = 1 #: Stampa su carta
|
|
31
|
+
PRINT_TARGET_PDF = 2 #: Stampa su file PDF
|
|
32
|
+
PRINT_TARGET_CSV = 3 #: Stampa su file CSV
|
|
33
|
+
PRINT_TARGET_XLS = 4 #: Stampa su file Excel
|
|
34
|
+
PRINT_TARGET_LABEL = 5 #: Stampa su etichette
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
_last_client = None
|
|
38
|
+
_konga_exe = None
|
|
39
|
+
_konga_args = None
|
|
40
|
+
_konga_reuse_client = False
|
|
41
|
+
_konga_proc = None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class KongaRequiredError(RuntimeError):
|
|
46
|
+
"""Eccezione lanciata quando si esegue una funzione disponibile solo dall'interno di Konga."""
|
|
47
|
+
def __str__(self):
|
|
48
|
+
return "Function requires script to be executed from within Konga"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class PrintError(RuntimeError):
|
|
53
|
+
"""Eccezione lanciata se ci sono errori nell'esecuzione di una stampa con la funzione :func:`print_layout`."""
|
|
54
|
+
def __init__(self, log):
|
|
55
|
+
self._log = log
|
|
56
|
+
def __str__(self):
|
|
57
|
+
return 'Log:\n%s' % ('\n'.join([ (' %s' % line) for line in kongalib.ensure_text(self._log.dumps()).split(u'\n') ]))
|
|
58
|
+
def get_log(self):
|
|
59
|
+
"""Ottiene un oggetto di classe :class:`kongalib.Log` contenente gli errori di stampa."""
|
|
60
|
+
return self._log
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class ScriptContext(object):
|
|
65
|
+
""" Classe per l'accesso al contesto di esecuzione delle azioni esterne lato client di Konga.
|
|
66
|
+
La classe prevede l'uso di proprietà per accedere alle informazioni in lettura e scrittura."""
|
|
67
|
+
def __init__(self, database, company, tablename, record_id, record_code, record_data, **kwargs):
|
|
68
|
+
self._database = database
|
|
69
|
+
self._company = company
|
|
70
|
+
self._tablename = tablename
|
|
71
|
+
self._record_id = record_id
|
|
72
|
+
self._record_code = record_code
|
|
73
|
+
self._record_data = record_data
|
|
74
|
+
self._params = kwargs
|
|
75
|
+
self._result = None
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def database(self):
|
|
79
|
+
"""Ritorna un oggetto ``dict`` che contiene informazioni sul database attualmente connesso.
|
|
80
|
+
Contiene le chiavi ``name``, ``driver``, ``desc`` e tutti i nomi dei campi della tabella EB_Master,
|
|
81
|
+
i cui valori sono presi dal database."""
|
|
82
|
+
return self._database
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def company(self):
|
|
86
|
+
"""Ritorna un oggetto ``dict`` che contiene informazioni sull'azienda attualmente impostata nella
|
|
87
|
+
finestra che sta eseguendo l'azione esterna. Contiene come chiavi tutti i campi delle tabelle EB_Aziende
|
|
88
|
+
e EB_StatoArchivi (al contrario della proprietà ``database`` le cui chiavi sono nella forma ``<nomecampo>``,
|
|
89
|
+
qui i campi sono nella forma ``<nometabella>.<nomecampo>`` per evitare conflitti di nomi tra le tabelle
|
|
90
|
+
EB_Aziende e EB_StatoArchivi) con i relativi valori presi dal database."""
|
|
91
|
+
return self._company
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def tablename(self):
|
|
95
|
+
"""Ritorna il nome della tabella su cui l'azione esterna sta operando."""
|
|
96
|
+
return self._tablename
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def record_id(self):
|
|
100
|
+
"""Ritorna l'ID (chiave primaria) del record su cui l'azione esterna sta operando. Vedere anche :meth:`.tablename`."""
|
|
101
|
+
return self._record_id
|
|
102
|
+
|
|
103
|
+
@property
|
|
104
|
+
def record_code(self):
|
|
105
|
+
"""Ritorna il codice del record su cui l'azione esterna sta operando. Vedere anche :meth:`.tablename`."""
|
|
106
|
+
return self._record_code
|
|
107
|
+
|
|
108
|
+
@property
|
|
109
|
+
def record_data(self):
|
|
110
|
+
"""Ritorna un ``dict`` con i dati del record visibili sulla scheda della finestra che sta eseguendo l'azione esterna."""
|
|
111
|
+
return self._record_data
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def params(self):
|
|
115
|
+
"""Ritorna un ``dict`` con i parametri che Konga passa allo script per l'esecuzione dell'azione esterna;
|
|
116
|
+
questi parametri variano a seconda del tipo di azione che si sta eseguendo."""
|
|
117
|
+
return self._params
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def result(self):
|
|
121
|
+
"""Ritorna o imposta il valore di ritorno dell'azione esterna, in modo che Konga possa usarlo al termine dell'esecuzione dell'azione
|
|
122
|
+
stessa. Il tipo ed il valore che andranno impostati dipendono dal tipo di azione esterna che si sta eseguendo."""
|
|
123
|
+
return self._result
|
|
124
|
+
|
|
125
|
+
@result.setter
|
|
126
|
+
def result(self, result):
|
|
127
|
+
self._result = result
|
|
128
|
+
_proxy.util.set_script_result(result)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def connect(host=None, port=None, driver=None, database=None, username=None, password=None, tenant_key=None, config=None):
|
|
133
|
+
"""Restituisce un oggetto :class:`kongalib.Client` già connesso. Se eseguito dall'interno di Konga, la connessione sarà stabilita
|
|
134
|
+
con il server, il database e l'utenza correntemente aperti sul programma, e i parametri passati a questa funzione saranno ignorati.
|
|
135
|
+
Se eseguita fuori da Konga, la funzione proverà a collegarsi al primo server disponibile sulla rete locale, aprendo il primo
|
|
136
|
+
database disponibile autenticandosi col l'utenza *admin* con password vuota; ogni parametro di connessione può essere forzato
|
|
137
|
+
tramite i parametri passati a questa funzione, oppure da linea di comando specificando gli argomenti ``--host``, ``--port``,
|
|
138
|
+
``--driver``, ``-d|--database``, ``-u|--username``, ``-p|--password`` e ``-k|--tenant-key``. Inoltre, è possibile definire i
|
|
139
|
+
parametri come variabili all'interno di un file di configurazione, nella sezione ``[kongautil.connect]``; tale file deve avere
|
|
140
|
+
il nome passato a questa funzione con il parametro ``config``, altrimenti verranno ricercati nell'ordine anche il file con lo
|
|
141
|
+
stesso nome dello script lanciato da terminale, ma con estensione ``.cfg``, il file ``kongalib.cfg`` sempre nella stessa directory
|
|
142
|
+
da cui si esegue lo script e infine il file ``~/.kongalib`` (sotto Unix) o ``%userprofile%\\kongalib.cfg`` (sotto Windows)."""
|
|
143
|
+
if _proxy.is_valid():
|
|
144
|
+
info = _proxy.util.get_connection_info()
|
|
145
|
+
if info is not None:
|
|
146
|
+
host, port, driver, database, username, password, tenant_key = info
|
|
147
|
+
client = kongalib.Client()
|
|
148
|
+
client.connect(host=host, port=port, options={ 'tenant_key': tenant_key })
|
|
149
|
+
client.open_database(driver, database)
|
|
150
|
+
client.authenticate(username, password)
|
|
151
|
+
return client
|
|
152
|
+
else:
|
|
153
|
+
global _last_client
|
|
154
|
+
global _konga_exe
|
|
155
|
+
global _konga_args
|
|
156
|
+
global _konga_reuse_client
|
|
157
|
+
client = kongalib.Client()
|
|
158
|
+
if host is None:
|
|
159
|
+
import argparse
|
|
160
|
+
import configparser
|
|
161
|
+
files = [
|
|
162
|
+
os.path.abspath(os.path.expanduser(os.path.join('~', 'kongalib.cfg' if sys.platform == 'win32' else '.kongalib'))),
|
|
163
|
+
os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), 'kongalib.cfg'),
|
|
164
|
+
os.path.splitext(sys.argv[0])[0] + '.cfg',
|
|
165
|
+
]
|
|
166
|
+
if config:
|
|
167
|
+
files.append(config)
|
|
168
|
+
config = configparser.RawConfigParser({
|
|
169
|
+
'host': host or '',
|
|
170
|
+
'port': str(port or ''),
|
|
171
|
+
'driver': driver or '',
|
|
172
|
+
'database': database or '',
|
|
173
|
+
'username': username or '',
|
|
174
|
+
'password': password or '',
|
|
175
|
+
'tenant_key': tenant_key or '',
|
|
176
|
+
'konga_exe': '',
|
|
177
|
+
'konga_args': '',
|
|
178
|
+
'reuse_client': '',
|
|
179
|
+
})
|
|
180
|
+
config.add_section('kongautil.connect')
|
|
181
|
+
config.add_section('kongautil.print_layout')
|
|
182
|
+
config.read(files)
|
|
183
|
+
host = config.get('kongautil.connect', 'host') or None
|
|
184
|
+
try: port = int(config.get('kongautil.connect', 'port'))
|
|
185
|
+
except: pass
|
|
186
|
+
driver = config.get('kongautil.connect', 'driver') or None
|
|
187
|
+
database = config.get('kongautil.connect', 'database') or None
|
|
188
|
+
username = config.get('kongautil.connect', 'username') or None
|
|
189
|
+
password = config.get('kongautil.connect', 'password') or None
|
|
190
|
+
tenant_key = config.get('kongautil.connect', 'tenant_key') or None
|
|
191
|
+
|
|
192
|
+
_konga_exe = config.get('kongautil.print_layout', 'konga_exe') or None
|
|
193
|
+
_konga_args = config.get('kongautil.print_layout', 'konga_args') or None
|
|
194
|
+
_konga_reuse_client = config.get('kongautil.print_layout', 'reuse_client') or False
|
|
195
|
+
|
|
196
|
+
class ArgumentParser(argparse.ArgumentParser):
|
|
197
|
+
def _print_message(self, message, file=None):
|
|
198
|
+
pass
|
|
199
|
+
def exit(self, status=0, message=None):
|
|
200
|
+
if status:
|
|
201
|
+
raise RuntimeError
|
|
202
|
+
parser = ArgumentParser()
|
|
203
|
+
parser.add_argument('--host', default=host)
|
|
204
|
+
parser.add_argument('--port', type=int, default=port)
|
|
205
|
+
parser.add_argument('--driver', default=driver)
|
|
206
|
+
parser.add_argument('-d', '--database', default=database)
|
|
207
|
+
parser.add_argument('-u', '--username', default=username)
|
|
208
|
+
parser.add_argument('-p', '--password', default=password)
|
|
209
|
+
parser.add_argument('-k', '--tenant-key', default=tenant_key)
|
|
210
|
+
try:
|
|
211
|
+
args = parser.parse_args()
|
|
212
|
+
host = args.host
|
|
213
|
+
port = args.port
|
|
214
|
+
driver = args.driver
|
|
215
|
+
database = args.database
|
|
216
|
+
username = args.username
|
|
217
|
+
password = args.password
|
|
218
|
+
tenant_key = args.tenant_key
|
|
219
|
+
except:
|
|
220
|
+
pass
|
|
221
|
+
if host is None:
|
|
222
|
+
servers_list = client.list_servers(timeout=500)
|
|
223
|
+
if servers_list:
|
|
224
|
+
host = servers_list[0]['host']
|
|
225
|
+
port = servers_list[0]['port']
|
|
226
|
+
if host is not None:
|
|
227
|
+
client.connect(host=host, port=port or 0, options={ 'tenant_key': tenant_key })
|
|
228
|
+
db_list = None
|
|
229
|
+
if driver is None:
|
|
230
|
+
if database is not None:
|
|
231
|
+
db_list = client.list_databases(timeout=500)
|
|
232
|
+
for driver, dbs in db_list.items():
|
|
233
|
+
if database in [ db['name'] for db in dbs ]:
|
|
234
|
+
break
|
|
235
|
+
else:
|
|
236
|
+
driver = None
|
|
237
|
+
if driver is None:
|
|
238
|
+
drivers_list = client.list_drivers(timeout=500)
|
|
239
|
+
if drivers_list:
|
|
240
|
+
driver = drivers_list[0]['name']
|
|
241
|
+
if (driver is not None) and (database is None):
|
|
242
|
+
if db_list is None:
|
|
243
|
+
db_list = client.list_databases(driver, timeout=500)
|
|
244
|
+
if db_list and (len(db_list[driver]) > 0):
|
|
245
|
+
database = db_list[driver][0]['name']
|
|
246
|
+
if (driver is not None) and (database is not None):
|
|
247
|
+
client.open_database(driver, database)
|
|
248
|
+
client.authenticate(username or 'admin', password or '')
|
|
249
|
+
_last_client = client
|
|
250
|
+
return client
|
|
251
|
+
raise kongalib.Error(kongalib.DATABASE_NOT_CONNECTED, "No database connected")
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def get_window_vars():
|
|
256
|
+
"""Restituisce un ``dict`` contenente una serie di costanti definite per la finestra di navigazione correntemente aperta su Konga, incluse informazioni
|
|
257
|
+
sull'azienda corrente, l'eventuale selezione se la finestra mostra una vista a lista, e molto altro. Se la funzione è eseguita fuori da Konga, il ``dict``
|
|
258
|
+
restituito sarà vuoto."""
|
|
259
|
+
if _proxy.is_valid():
|
|
260
|
+
return _proxy.util.get_window_vars()
|
|
261
|
+
else:
|
|
262
|
+
return {}
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _terminate_script_proc():
|
|
267
|
+
try:
|
|
268
|
+
_konga_proc.stdin.write('.quit\n')
|
|
269
|
+
_konga_proc.stdin.flush()
|
|
270
|
+
try:
|
|
271
|
+
_konga_proc.wait(5)
|
|
272
|
+
except:
|
|
273
|
+
_konga_proc.terminate()
|
|
274
|
+
except:
|
|
275
|
+
pass
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def _run_script(script, log, client):
|
|
280
|
+
import tempfile, subprocess, string, random, atexit
|
|
281
|
+
client_exe = _konga_exe
|
|
282
|
+
if client_exe is None:
|
|
283
|
+
if sys.platform == 'win32':
|
|
284
|
+
files = ( 'kongaclient.com', 'konga.com' )
|
|
285
|
+
else:
|
|
286
|
+
files = ( 'easybyte-konga-client', 'easybyte-konga' )
|
|
287
|
+
path = os.environ.get("PATH", None)
|
|
288
|
+
if path is None:
|
|
289
|
+
try:
|
|
290
|
+
path = os.confstr("CS_PATH")
|
|
291
|
+
except (AttributeError, ValueError):
|
|
292
|
+
path = os.defpath
|
|
293
|
+
if path is not None:
|
|
294
|
+
path = path.split(os.pathsep)
|
|
295
|
+
for exe in files:
|
|
296
|
+
seen = set()
|
|
297
|
+
for dir in path:
|
|
298
|
+
normdir = os.path.normcase(dir)
|
|
299
|
+
if not normdir in seen:
|
|
300
|
+
seen.add(normdir)
|
|
301
|
+
name = os.path.join(dir, exe)
|
|
302
|
+
if os.path.exists(name) and os.access(name, os.F_OK | os.X_OK) and not os.path.isdir(name):
|
|
303
|
+
client_exe = exe
|
|
304
|
+
break
|
|
305
|
+
if client_exe is not None:
|
|
306
|
+
break
|
|
307
|
+
if client_exe is None:
|
|
308
|
+
raise RuntimeError('Cannot find Konga executable')
|
|
309
|
+
client = client or _last_client
|
|
310
|
+
if client is not None:
|
|
311
|
+
info = client.get_connection_info()
|
|
312
|
+
lines = [
|
|
313
|
+
'.connect "%s" -p %d' % (info['host'], info['port']),
|
|
314
|
+
'.user "%s" -p "%s"' % (info['user']['name'], info['user']['password']),
|
|
315
|
+
'.open_database "%s" -d "%s"' % (info['database']['name'], info['database']['driver']),
|
|
316
|
+
]
|
|
317
|
+
else:
|
|
318
|
+
lines = []
|
|
319
|
+
lines += script
|
|
320
|
+
try:
|
|
321
|
+
if _konga_reuse_client:
|
|
322
|
+
global _konga_proc
|
|
323
|
+
if (_konga_proc is None) or (_konga_proc.poll() is not None):
|
|
324
|
+
try:
|
|
325
|
+
_konga_proc = subprocess.Popen('%s %s --script -' % (client_exe, _konga_args or ''), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, universal_newlines=True)
|
|
326
|
+
except Exception as e:
|
|
327
|
+
raise subprocess.CalledProcessError(-1, '', e)
|
|
328
|
+
atexit.unregister(_terminate_script_proc)
|
|
329
|
+
atexit.register(_terminate_script_proc)
|
|
330
|
+
marker = ''.join(random.choice(string.ascii_uppercase + string.digits) for i in range(32))
|
|
331
|
+
if client is not None:
|
|
332
|
+
lines += [ '.disconnect' ]
|
|
333
|
+
lines += [ '.echo %s' % marker, '' ]
|
|
334
|
+
_konga_proc.stdin.write('\n'.join(lines))
|
|
335
|
+
_konga_proc.stdin.flush()
|
|
336
|
+
while True:
|
|
337
|
+
line = _konga_proc.stdout.readline()
|
|
338
|
+
if not line:
|
|
339
|
+
break
|
|
340
|
+
line = line[:-1]
|
|
341
|
+
if line == marker:
|
|
342
|
+
break
|
|
343
|
+
log.info(line)
|
|
344
|
+
else:
|
|
345
|
+
temp = tempfile.NamedTemporaryFile(mode='w', delete=False)
|
|
346
|
+
try:
|
|
347
|
+
with temp:
|
|
348
|
+
temp.write('\n'.join(lines))
|
|
349
|
+
output = subprocess.check_output('%s %s --script %s' % (client_exe, _konga_args or '', quote(temp.name)), stderr=subprocess.STDOUT, shell=True, universal_newlines=True).splitlines()
|
|
350
|
+
for line in output:
|
|
351
|
+
log.info(line)
|
|
352
|
+
finally:
|
|
353
|
+
os.unlink(temp.name)
|
|
354
|
+
except subprocess.CalledProcessError as e:
|
|
355
|
+
log.warning("Errors running script:")
|
|
356
|
+
output = kongalib.ensure_text(e.output).splitlines()
|
|
357
|
+
for line in output:
|
|
358
|
+
log.error(line)
|
|
359
|
+
log.info("Original script was:")
|
|
360
|
+
for line in script:
|
|
361
|
+
log.info(" %s" % line)
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def print_layout(command_or_layout, builtins=None, code_azienda=None, code_esercizio=None, target=None, filename=None, progress=True, client=None):
|
|
366
|
+
"""Esegue una stampa su Konga. *command_or_layout* può essere un nome di comando di Konga, oppure un sorgente XML contenente la struttura stessa del layout da
|
|
367
|
+
stampare; *builtins* è un ``dict`` i cui valori verranno passati al motore di stampa e saranno disponibili all'interno degli script del layout; *code_azienda* e
|
|
368
|
+
*code_esercizio* identificano l'azienda e l'esercizio per cui eseguire la stampa, mentre *target* è una delle costanti ``PRINT_TARGET_*`` definite sopra, che
|
|
369
|
+
specificano la destinazione della stampa (se non specificata e la funzione è eseguita all'interno di Konga, verrà assunta ``PRINT_TARGET_PREVIEW``,
|
|
370
|
+
altrimenti ``PRINT_TARGET_PDF``); *filename* è il nome del file da salvare ed ha un senso solo quando si stampa su file. Se *progress* è ``True`` verrà mostrata
|
|
371
|
+
a video una barra di progresso dell'operazione di stampa.
|
|
372
|
+
La funzione restituisce un oggetto di classe :class:`kongalib.Log` con il resoconto dell'operazione di stampa, oppure lancia un'eccezione di classe
|
|
373
|
+
:class:`kongautil.PrintError` in caso di errori.
|
|
374
|
+
|
|
375
|
+
.. warning::
|
|
376
|
+
Se eseguita fuori da Konga, questa funzione richiede che sull'host sia stato installato Konga Client (o Konga), e non supporta come *target* i valori
|
|
377
|
+
``PRINT_TARGET_PREVIEW`` e ``PRINT_TARGET_PAPER``. Konga Client (o Konga) verrà invocato e provvederà a connettersi al client corrente e stampare il
|
|
378
|
+
documento richiesto; i parametri di connessione saranno ricavati automaticamente dal client ottenuto dall'ultima chiamata alla funzione :func:`kongautil.connect`
|
|
379
|
+
oppure, se specificato, dal parametro ``client``.
|
|
380
|
+
"""
|
|
381
|
+
if _proxy.is_valid():
|
|
382
|
+
if target is None:
|
|
383
|
+
target = PRINT_TARGET_PREVIEW
|
|
384
|
+
log = _proxy.util.print_layout(command_or_layout, builtins or {}, code_azienda, code_esercizio, target, filename, progress)
|
|
385
|
+
else:
|
|
386
|
+
log = kongalib.Log()
|
|
387
|
+
if not filename:
|
|
388
|
+
raise ValueError("Output filename must be specified")
|
|
389
|
+
if isinstance(command_or_layout, str) and (command_or_layout.strip().startswith('<?xml') or command_or_layout.strip().startswith('<layout')):
|
|
390
|
+
import tempfile
|
|
391
|
+
temp = tempfile.NamedTemporaryFile(mode='w', delete=False)
|
|
392
|
+
with temp:
|
|
393
|
+
temp.write(command_or_layout)
|
|
394
|
+
command_or_layout = temp.name
|
|
395
|
+
else:
|
|
396
|
+
temp = None
|
|
397
|
+
target = {
|
|
398
|
+
PRINT_TARGET_PDF: 'pdf',
|
|
399
|
+
PRINT_TARGET_CSV: 'csv',
|
|
400
|
+
PRINT_TARGET_XLS: 'xls',
|
|
401
|
+
}.get(target, 'pdf')
|
|
402
|
+
builtins = builtins or {}
|
|
403
|
+
if code_azienda:
|
|
404
|
+
builtins['COMPANY_CODE'] = code_azienda
|
|
405
|
+
if code_esercizio:
|
|
406
|
+
builtins['ACCOUNTING_YEAR_CODE'] = code_esercizio
|
|
407
|
+
script = [
|
|
408
|
+
'.print "%s" %s -o %s -f "%s"' % (command_or_layout, ' '.join([ '%s=%s' % (key, quote(str(value))) for key, value in builtins.items() ]), target, filename)
|
|
409
|
+
]
|
|
410
|
+
try:
|
|
411
|
+
_run_script(script, log, client)
|
|
412
|
+
finally:
|
|
413
|
+
if temp is not None:
|
|
414
|
+
os.unlink(temp)
|
|
415
|
+
if log.has_errors():
|
|
416
|
+
raise PrintError(log)
|
|
417
|
+
return log
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def print_log(log, title, target=PRINT_TARGET_PREVIEW, filename=None):
|
|
422
|
+
"""Stampa il contenuto dell'oggetto *log* di classe :class:`kongalib.Log`; se si esegue questa funzione dall'interno di Konga, verrà usata la funzione
|
|
423
|
+
:func:`print_layout`, passando i parametri *target* e *filename*; viceversa se si esegue fuori da Konga, il log verrà stampato su terminale."""
|
|
424
|
+
if _proxy.is_valid():
|
|
425
|
+
template = """<?xml version='1.0' encoding='utf-8'?>
|
|
426
|
+
<layout version="3" name="%(title)s" title="%(title)s" orientation="vertical" margin_top="75" margin_right="75" margin_bottom="75" margin_left="75">
|
|
427
|
+
<init>
|
|
428
|
+
<![CDATA[set_datasource(Datasource(['id', 'type', 'message'], DATA, 'Master'))
|
|
429
|
+
]]></init>
|
|
430
|
+
<header width="100%%" height="175" only_first="true">
|
|
431
|
+
<label width="100%%" height="100" align="center" font_size="14" bgcolor="#EEE" border_edges="left|right|top|bottom">%(title)s</label>
|
|
432
|
+
</header>
|
|
433
|
+
|
|
434
|
+
<module width="100%%" alt_bgcolor="#EEE" condition="iterate('id')">
|
|
435
|
+
<field top="0" width="10%%" align="top" type="data">type</field>
|
|
436
|
+
<field left="10%%" top="0" width="90%%" align="top" wrapping="wrap" type="data">message</field>
|
|
437
|
+
</module>
|
|
438
|
+
<module width="100%%">
|
|
439
|
+
<init>
|
|
440
|
+
<![CDATA[this.visible = (len(DATA) == 0)
|
|
441
|
+
]]></init>
|
|
442
|
+
<label width="100%%" align="center">
|
|
443
|
+
<text>
|
|
444
|
+
<it>Operazione completata con successo</it>
|
|
445
|
+
</text>
|
|
446
|
+
</label>
|
|
447
|
+
</module>
|
|
448
|
+
|
|
449
|
+
<footer width="100%%" font_size="7" height="175">
|
|
450
|
+
<rect top="75" width="100%%" height="100" />
|
|
451
|
+
<field padding_left="50" top="75" left="0" width="30%%" height="50" align="bottom" type="expr">DATABASE_NAME</field>
|
|
452
|
+
<field padding_left="50" top="125" left="0" width="30%%" height="50" align="top" type="expr">COMPANY_NAME</field>
|
|
453
|
+
<field top="75" left="30%%" width="40%%" height="50" align="hcenter|bottom" type="expr">TITLE</field>
|
|
454
|
+
<datetime top="125" left="30%%" width="40%%" height="50" align="hcenter|top" format="PdmyHM">
|
|
455
|
+
<text>
|
|
456
|
+
<it>Stampato da $USER_NAME il %%d alle %%t</it>
|
|
457
|
+
<nl>Afgedrukt door $USER_NAME op %%d om %%t uur</nl>
|
|
458
|
+
</text>
|
|
459
|
+
</datetime>
|
|
460
|
+
<page padding_right="50" top="75" left="80%%" width="20%%" height="100" align="vcenter|right">
|
|
461
|
+
<text>
|
|
462
|
+
<it>Pagina %%p di %%t</it>
|
|
463
|
+
<nl>Pagina %%p van %%t</nl>
|
|
464
|
+
</text>
|
|
465
|
+
</page>
|
|
466
|
+
</footer>
|
|
467
|
+
</layout>
|
|
468
|
+
""" % {
|
|
469
|
+
'title': title,
|
|
470
|
+
}
|
|
471
|
+
data = []
|
|
472
|
+
for index, message in enumerate(log.get_messages()):
|
|
473
|
+
msg = log.strip_html(message[1])
|
|
474
|
+
if isinstance(msg, bytes):
|
|
475
|
+
msg = msg.decode('utf-8', 'replace')
|
|
476
|
+
data.append((index, ('INFO', 'WARNING', 'ERROR')[message[0]], msg))
|
|
477
|
+
|
|
478
|
+
print_layout(template, { 'DATA': data }, target=target, filename=filename)
|
|
479
|
+
else:
|
|
480
|
+
import colorama
|
|
481
|
+
print(colorama.Style.BRIGHT + title + colorama.Style.RESET_ALL)
|
|
482
|
+
status = {
|
|
483
|
+
kongalib.Log.INFO: colorama.Style.BRIGHT + "INFO " + colorama.Style.RESET_ALL,
|
|
484
|
+
kongalib.Log.WARNING: colorama.Style.BRIGHT + colorama.Fore.YELLOW + "WARNING " + colorama.Style.RESET_ALL,
|
|
485
|
+
kongalib.Log.ERROR: colorama.Style.BRIGHT + colorama.Fore.RED + "ERROR " + colorama.Style.RESET_ALL,
|
|
486
|
+
}
|
|
487
|
+
for message in log.get_messages():
|
|
488
|
+
print('%s%s' % (status[message[0]], message[1]))
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
def show_log(log, title, size=None, iconsize=32):
|
|
493
|
+
"""Visualizza il contenuto dell'oggetto *log* di classe :class:`kongalib.Log`; se si esegue questa funzione dall'interno di Konga, il log verrà
|
|
494
|
+
visualizzato in una finestra dedicata; viceversa se si esegue fuori da Konga, il comportamento di questa funzione equivale a chiamare
|
|
495
|
+
:func:`print_log` con gli stessi argomenti. La finestra del log mostrerà *title* come messaggio informativo e se specificato avrà dimensione *size*;
|
|
496
|
+
è possibile specificare anche la dimensione delle icone dei singoli messaggi tramite il parametro *iconsize*."""
|
|
497
|
+
if _proxy.is_valid():
|
|
498
|
+
log = _proxy.util.show_log(log.get_messages(), title, size, iconsize)
|
|
499
|
+
else:
|
|
500
|
+
print_log(log, title)
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
def suspend_timeout():
|
|
505
|
+
"""Sospende il timeout di esecuzione dello script. La funzione non comporta eccezioni ma non ha alcun effetto se eseguita al di fuori di Konga."""
|
|
506
|
+
if _proxy.is_valid():
|
|
507
|
+
return _proxy.builtin.set_timeout(restore=False)
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
def resume_timeout(timeout):
|
|
512
|
+
"""Ripristina il timeout di esecuzione dello script. La funzione non comporta eccezioni ma non ha alcun effetto se eseguita al di fuori di Konga."""
|
|
513
|
+
if _proxy.is_valid():
|
|
514
|
+
_proxy.builtin.set_timeout(timeout, restore=False)
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
def set_timeout(timeout):
|
|
519
|
+
"""Imposta il timeout di esecuzione dello script in secondi, passati i quali verrà mostrata una finestra di avviso. La funzione non comporta eccezioni ma non ha alcun effetto se eseguita al di fuori di Konga."""
|
|
520
|
+
if _proxy.is_valid():
|
|
521
|
+
_proxy.builtin.set_timeout(timeout * 1000, restore=False)
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
def get_external_images_path(table_name, code_azienda):
|
|
526
|
+
raise RuntimeError('Images storage is managed by the server since Konga 1.9; please use kongalib.Client.fetch_binary() and kongalib.Client.store_binary() to load/save images')
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
def get_external_attachments_path(table_name, code_azienda):
|
|
531
|
+
raise RuntimeError('Attachments storage is managed by the server since Konga 1.9; please use kongalib.Client.fetch_binary() and kongalib.Client.store_binary() to load/save attachments')
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
def get_site_packages():
|
|
536
|
+
"""Restituisce una lista di percorsi di installazione dei pacchetti Python."""
|
|
537
|
+
if _proxy.is_valid():
|
|
538
|
+
return [ _proxy.util.get_site_packages() ]
|
|
539
|
+
else:
|
|
540
|
+
import site
|
|
541
|
+
return site.getsitepackages()
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
|
|
545
|
+
def notify_data_changes(table_name, row_id=None):
|
|
546
|
+
"""Notifica Konga che uno o tutti i record di una tabella sono stati modificati, causando un aggiornamento a tutti quei client Konga che stanno operando su tali record. Se *row_id* è ``None``, tutti
|
|
547
|
+
i record della tabella *table_name* verranno marcati come modificati, altrimenti il solo record con *ID* *row_id*. La funzione non comporta eccezioni ma non ha alcun effetto se eseguita al di fuori di Konga."""
|
|
548
|
+
if _proxy.is_valid():
|
|
549
|
+
_proxy.util.notify_data_changes(table_name, row_id)
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
def open_uri(uri):
|
|
554
|
+
"""Tenta di aprire l'URI specificato con l'applicazione predefinita di sistema (se configurata)."""
|
|
555
|
+
import subprocess
|
|
556
|
+
if sys.platform == 'darwin':
|
|
557
|
+
subprocess.call(('open', uri))
|
|
558
|
+
elif sys.platform == 'win32':
|
|
559
|
+
os.startfile(uri)
|
|
560
|
+
else:
|
|
561
|
+
subprocess.call(('xdg-open', uri))
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
def get_context():
|
|
566
|
+
"""Restituisce un oggetto di classe :class:`kongautil.ScriptContext` da usare per la gestione dell'I/O da parte degli script usati come azioni esterne di Konga.
|
|
567
|
+
|
|
568
|
+
.. warning::
|
|
569
|
+
Questa funzione è disponibile solo all'interno di Konga; eseguendola da fuori verrà lanciata l'eccezione :class:`kongautil.KongaRequiredError`.
|
|
570
|
+
"""
|
|
571
|
+
if _proxy.is_valid():
|
|
572
|
+
return _proxy.util.get_context()
|
|
573
|
+
else:
|
|
574
|
+
raise KongaRequiredError
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
def is_batch():
|
|
579
|
+
"""Restituisce ``True`` se lo script è eseguito con Python da linea di comando, ``False`` se è eseguito dall'interno di Konga."""
|
|
580
|
+
return not _proxy.is_valid()
|
|
581
|
+
|