PIVOT 1.1.0
This commit is contained in:
commit
8a53234eb6
161 files changed
+31109
No files matched your search
@@ -0,0 +1,419 @@
|
||||
"""
|
||||
Beheer › Database › Toestellen: de tabel Toestellen aanvullen vanuit een Excel-bestand.
|
||||
|
||||
Werkwijze (twee stappen, zodat er niets in de database komt zonder dat je het gezien hebt):
|
||||
1. lees_excel() : het geüploade bestand → ruwe rijen (enkel tekst / ISO-datums)
|
||||
2. maak_plan() : ruwe rijen → per rij 'nieuw', 'bijwerken', 'ongewijzigd' of 'fout' (niets wordt bewaard)
|
||||
3. voer_uit() : het plan in één transactie uitvoeren (het plan wordt opnieuw gemaakt, nooit blind vertrouwd)
|
||||
|
||||
Een toestel wordt herkend aan het toestelnummer (Schooleigen_ID) en anders aan het serienummer.
|
||||
Er wordt nooit iets verwijderd. Lege cellen wissen nooit een bestaande waarde.
|
||||
"""
|
||||
import io
|
||||
from datetime import date, datetime
|
||||
|
||||
from database import execute_query, get_db_connection
|
||||
from services import toestellen as tst
|
||||
|
||||
STATUSSEN = ('Beschikbaar', 'Uitgeleend', 'Defect')
|
||||
MAX_RIJEN = 5000
|
||||
|
||||
# (sleutel, kolomkop in het sjabloon, max. lengte, uitleg, andere namen die ook herkend worden)
|
||||
KOLOMMEN = [
|
||||
('schooleigen_id', 'Toestelnummer', 50,
|
||||
"Het eigen toestelnummer van de school (Schooleigen_ID). Uniek. Toestelnummer of serienummer is verplicht.",
|
||||
('schooleigen_id', 'schooleigen id', 'kamxm_nummer', 'kamxm nummer', 'kamxm', 'nummer', 'toestel')),
|
||||
('serienummer', 'Serienummer', 100,
|
||||
"Serienummer van de fabrikant (nodig om het toestel in Google te blokkeren). "
|
||||
"Toestelnummer of serienummer is verplicht.",
|
||||
('serial', 'serial number', 'serienr', 'serie')),
|
||||
('type', 'Type', 100, "Model van het toestel, bv. Lenovo 300e Gen 4.", ('model', 'toesteltype')),
|
||||
('status', 'Status', None,
|
||||
"Beschikbaar, Uitgeleend of Defect. Leeg bij een nieuw toestel = Beschikbaar.", ()),
|
||||
('afschrijfdatum', 'Afschrijfdatum', None,
|
||||
"Datum (dd-mm-jjjj) of een Excel-datum. Mag leeg.", ('afschrijving', 'afschrijf datum')),
|
||||
('lokaal', 'Lokaal', None,
|
||||
"Naam van een lokaal dat al in PIVOT bestaat (zie het tabblad Lokalen). Mag leeg.", ('lokaalnaam', 'lokaal_id')),
|
||||
]
|
||||
SLEUTELS = [k[0] for k in KOLOMMEN]
|
||||
KOPPEN = {k[0]: k[1] for k in KOLOMMEN}
|
||||
|
||||
# Databasekolom per sleutel (lokaal → Lokaal_ID wordt apart opgezocht)
|
||||
DB_KOLOM = {'schooleigen_id': 'Schooleigen_ID', 'serienummer': 'Serienummer', 'type': 'Type',
|
||||
'status': 'Status', 'afschrijfdatum': 'Afschrijfdatum', 'lokaal': 'Lokaal_ID'}
|
||||
|
||||
|
||||
class ImportFout(Exception):
|
||||
"""Het bestand zelf kan niet gelezen worden (geen rijfout)."""
|
||||
|
||||
|
||||
def _norm(tekst):
|
||||
return ' '.join(str(tekst or '').strip().lower().replace('_', ' ').replace('-', ' ').split())
|
||||
|
||||
|
||||
_HERKEN = {}
|
||||
for _k, _kop, _m, _u, _alias in KOLOMMEN:
|
||||
for _naam in (_k, _kop) + tuple(_alias):
|
||||
_HERKEN[_norm(_naam)] = _k
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Sjabloon
|
||||
# ---------------------------------------------------------------------------
|
||||
def lokalen():
|
||||
"""Alle lokalen van de huidige school: [{'Lokaal_ID', 'Naam', 'Campus'}]."""
|
||||
return execute_query(
|
||||
"SELECT l.Lokaal_ID, l.Naam, c.Campus_naam AS Campus FROM Lokalen l "
|
||||
"LEFT JOIN Campus c ON c.Campus_ID = l.Campus_ID ORDER BY l.Naam") or []
|
||||
|
||||
|
||||
def maak_sjabloon(schoolnaam=''):
|
||||
"""Excel-sjabloon (bytes): tabblad Toestellen (in te vullen), Uitleg en Lokalen."""
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.styles import Font, PatternFill, Alignment
|
||||
from openpyxl.worksheet.datavalidation import DataValidation
|
||||
|
||||
wb = Workbook()
|
||||
ws = wb.active
|
||||
ws.title = 'Toestellen'
|
||||
ws.append([k[1] for k in KOLOMMEN])
|
||||
kop_vulling = PatternFill('solid', fgColor='1E6FA5')
|
||||
for c in ws[1]:
|
||||
c.font = Font(bold=True, color='FFFFFF')
|
||||
c.fill = kop_vulling
|
||||
c.alignment = Alignment(vertical='center')
|
||||
breedtes = {'Toestelnummer': 16, 'Serienummer': 20, 'Type': 26, 'Status': 14, 'Afschrijfdatum': 16, 'Lokaal': 18}
|
||||
for i, k in enumerate(KOLOMMEN):
|
||||
letter = ws.cell(row=1, column=i + 1).column_letter
|
||||
ws.column_dimensions[letter].width = breedtes.get(k[1], 16)
|
||||
ws.freeze_panes = 'A2'
|
||||
ws.row_dimensions[1].height = 22
|
||||
|
||||
kol = {k[0]: ws.cell(row=1, column=i + 1).column_letter for i, k in enumerate(KOLOMMEN)}
|
||||
# Nummers als tekst (anders maakt Excel van 00123 → 123)
|
||||
for sleutel in ('schooleigen_id', 'serienummer'):
|
||||
for r in range(2, MAX_RIJEN + 2):
|
||||
ws[f"{kol[sleutel]}{r}"].number_format = '@'
|
||||
for r in range(2, MAX_RIJEN + 2):
|
||||
ws[f"{kol['afschrijfdatum']}{r}"].number_format = 'DD-MM-YYYY'
|
||||
|
||||
dv_status = DataValidation(type='list', formula1='"' + ','.join(STATUSSEN) + '"', allow_blank=True,
|
||||
showErrorMessage=True, errorTitle='Status',
|
||||
error='Kies Beschikbaar, Uitgeleend of Defect (of laat leeg).')
|
||||
dv_status.add(f"{kol['status']}2:{kol['status']}{MAX_RIJEN + 1}")
|
||||
ws.add_data_validation(dv_status)
|
||||
dv_datum = DataValidation(type='date', operator='greaterThan', formula1='1', allow_blank=True,
|
||||
showErrorMessage=True, errorTitle='Afschrijfdatum',
|
||||
error='Vul een datum in, bv. 31-08-2030.')
|
||||
dv_datum.add(f"{kol['afschrijfdatum']}2:{kol['afschrijfdatum']}{MAX_RIJEN + 1}")
|
||||
ws.add_data_validation(dv_datum)
|
||||
|
||||
# Lokalen van deze school (keuzelijst in de kolom Lokaal)
|
||||
wl = wb.create_sheet('Lokalen')
|
||||
wl.append(['Lokaal', 'Campus'])
|
||||
for c in wl[1]:
|
||||
c.font = Font(bold=True)
|
||||
lijst = []
|
||||
try:
|
||||
lijst = lokalen()
|
||||
except Exception:
|
||||
pass
|
||||
for l in lijst:
|
||||
wl.append([l['Naam'], l.get('Campus') or ''])
|
||||
wl.column_dimensions['A'].width = 24
|
||||
wl.column_dimensions['B'].width = 28
|
||||
if lijst:
|
||||
dv_lokaal = DataValidation(type='list', formula1=f"=Lokalen!$A$2:$A${len(lijst) + 1}", allow_blank=True,
|
||||
showErrorMessage=True, errorTitle='Lokaal',
|
||||
error='Kies een lokaal uit de lijst (tabblad Lokalen) of laat leeg.')
|
||||
dv_lokaal.add(f"{kol['lokaal']}2:{kol['lokaal']}{MAX_RIJEN + 1}")
|
||||
ws.add_data_validation(dv_lokaal)
|
||||
|
||||
# Uitleg
|
||||
wu = wb.create_sheet('Uitleg')
|
||||
wu.column_dimensions['A'].width = 18
|
||||
wu.column_dimensions['B'].width = 95
|
||||
wu.append([f"Toestellen importeren in PIVOT{' – ' + schoolnaam if schoolnaam else ''}"])
|
||||
wu['A1'].font = Font(bold=True, size=14)
|
||||
regels = [
|
||||
"Vul het tabblad 'Toestellen' in: één toestel per rij, vanaf rij 2. Laat de kolomkoppen in rij 1 staan.",
|
||||
"Een toestel wordt herkend aan het toestelnummer, en anders aan het serienummer.",
|
||||
"Bestaat het toestel nog niet, dan wordt het toegevoegd.",
|
||||
"Bestaat het al, dan worden (afhankelijk van je keuze bij het uploaden) enkel lege velden aangevuld "
|
||||
"of de ingevulde velden overschreven. Een lege cel wist nooit iets.",
|
||||
"Er wordt nooit een toestel verwijderd. Je krijgt eerst een voorbeeld te zien voordat er iets bewaard wordt.",
|
||||
f"Maximaal {MAX_RIJEN} rijen per bestand.",
|
||||
]
|
||||
for t in regels:
|
||||
wu.append(['', t])
|
||||
wu.append([])
|
||||
wu.append(['Kolom', 'Uitleg'])
|
||||
for c in wu[wu.max_row]:
|
||||
c.font = Font(bold=True)
|
||||
for _k, kop, maxlen, uitleg, _a in KOLOMMEN:
|
||||
wu.append([kop, uitleg + (f" Max. {maxlen} tekens." if maxlen else '')])
|
||||
for rij in wu.iter_rows(min_row=2):
|
||||
for c in rij:
|
||||
c.alignment = Alignment(wrap_text=True, vertical='top')
|
||||
wu.append([])
|
||||
wu.append(['Voorbeeld', 'Toestelnummer CB-0123 · Serienummer PF3ABC12 · Type Lenovo 300e Gen 4 · '
|
||||
'Status Beschikbaar · Afschrijfdatum 31-08-2030 · Lokaal A101'])
|
||||
|
||||
wb.active = 0
|
||||
buf = io.BytesIO()
|
||||
wb.save(buf)
|
||||
return buf.getvalue()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Excel lezen
|
||||
# ---------------------------------------------------------------------------
|
||||
def _cel(waarde):
|
||||
"""Celwaarde → tekst (datums als ISO 'jjjj-mm-dd', 123.0 → '123')."""
|
||||
if waarde is None:
|
||||
return ''
|
||||
if isinstance(waarde, datetime):
|
||||
return waarde.date().isoformat()
|
||||
if isinstance(waarde, date):
|
||||
return waarde.isoformat()
|
||||
if isinstance(waarde, float) and waarde.is_integer():
|
||||
return str(int(waarde))
|
||||
return str(waarde).strip()
|
||||
|
||||
|
||||
def lees_excel(bestand):
|
||||
"""Leest een .xlsx (bestandsobject of bytes). Geeft (rijen, onbekende_kolommen).
|
||||
rijen = [{'rij': <rijnummer in Excel>, 'schooleigen_id': '...', ...}] (enkel niet-lege rijen)."""
|
||||
from openpyxl import load_workbook
|
||||
data = bestand if isinstance(bestand, (bytes, bytearray)) else bestand.read()
|
||||
if not data:
|
||||
raise ImportFout("Het bestand is leeg.")
|
||||
try:
|
||||
wb = load_workbook(io.BytesIO(data), read_only=True, data_only=True)
|
||||
except Exception:
|
||||
raise ImportFout("Dit bestand kan niet gelezen worden. Gebruik een Excel-bestand (.xlsx), "
|
||||
"bv. het sjabloon van deze pagina.")
|
||||
try:
|
||||
ws = wb['Toestellen'] if 'Toestellen' in wb.sheetnames else wb.worksheets[0]
|
||||
rijen_iter = ws.iter_rows(values_only=True)
|
||||
# Kopregel zoeken in de eerste 10 rijen: de eerste rij met een herkende kolom
|
||||
kop_index, onbekend, rijnr = None, [], 0
|
||||
for rij in rijen_iter:
|
||||
rijnr += 1
|
||||
gevonden = {i: _HERKEN[_norm(v)] for i, v in enumerate(rij or ()) if _norm(v) in _HERKEN}
|
||||
if gevonden:
|
||||
kop_index = {}
|
||||
for i, sleutel in gevonden.items():
|
||||
kop_index.setdefault(sleutel, i) # dubbele kolom: de eerste telt
|
||||
onbekend = [_cel(v) for i, v in enumerate(rij) if _cel(v) and i not in gevonden]
|
||||
break
|
||||
if rijnr >= 10:
|
||||
break
|
||||
if not kop_index:
|
||||
raise ImportFout("Geen kolomkoppen gevonden. Rij 1 moet de kolomnamen van het sjabloon bevatten "
|
||||
f"({', '.join(KOPPEN.values())}).")
|
||||
if 'schooleigen_id' not in kop_index and 'serienummer' not in kop_index:
|
||||
raise ImportFout("De kolom Toestelnummer of Serienummer ontbreekt.")
|
||||
|
||||
uit = []
|
||||
for rij in rijen_iter:
|
||||
rijnr += 1
|
||||
waarden = {s: _cel(rij[i]) if rij and i < len(rij) else '' for s, i in kop_index.items()}
|
||||
if not any(waarden.values()):
|
||||
continue
|
||||
if len(uit) >= MAX_RIJEN:
|
||||
raise ImportFout(f"Het bestand bevat meer dan {MAX_RIJEN} rijen. Splits het op in kleinere bestanden.")
|
||||
uit.append({'rij': rijnr, **{s: waarden.get(s, '') for s in SLEUTELS}})
|
||||
return uit, onbekend
|
||||
finally:
|
||||
wb.close()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Plan maken (niets bewaren)
|
||||
# ---------------------------------------------------------------------------
|
||||
def _datum_tekst(w):
|
||||
"""'2030-08-31' / '31-08-2030' / '31/08/2030' → date, of ValueError."""
|
||||
w = (w or '').strip()
|
||||
if not w:
|
||||
return None
|
||||
try:
|
||||
return date.fromisoformat(w[:10]) if len(w) >= 10 and w[4] == '-' else tst.lees_datum(w)
|
||||
except ValueError:
|
||||
return tst.lees_datum(w)
|
||||
|
||||
|
||||
def _toon(w):
|
||||
if isinstance(w, date):
|
||||
return w.strftime('%d-%m-%Y')
|
||||
return '' if w is None else str(w)
|
||||
|
||||
|
||||
def maak_plan(rijen, modus='aanvullen'):
|
||||
"""Bepaalt per rij wat er zou gebeuren. modus: 'aanvullen' (enkel lege velden) of 'overschrijven'.
|
||||
Geeft {'rijen': [...], 'tellers': {...}}; elke rij heeft 'actie', 'meldingen' en 'waarden' (voor de database)."""
|
||||
overschrijven = modus == 'overschrijven'
|
||||
bestaand = execute_query("SELECT Toestel_ID, Schooleigen_ID, Serienummer, Type, Status, Afschrijfdatum, Lokaal_ID "
|
||||
"FROM Toestellen") or []
|
||||
op_nummer = {(r['Schooleigen_ID'] or '').strip().upper(): r for r in bestaand if (r['Schooleigen_ID'] or '').strip()}
|
||||
op_serie = {}
|
||||
for r in bestaand:
|
||||
s = (r['Serienummer'] or '').strip().upper()
|
||||
if s:
|
||||
op_serie.setdefault(s, r)
|
||||
lok = {}
|
||||
for l in lokalen():
|
||||
lok.setdefault((l['Naam'] or '').strip().upper(), l)
|
||||
lok_naam = {l['Lokaal_ID']: l['Naam'] for l in lok.values()}
|
||||
|
||||
gezien_nummer, gezien_serie = {}, {}
|
||||
uit = []
|
||||
tellers = {'nieuw': 0, 'bijwerken': 0, 'ongewijzigd': 0, 'fout': 0}
|
||||
|
||||
for invoer in rijen:
|
||||
r = {'rij': invoer.get('rij'), 'invoer': {s: str(invoer.get(s) or '').strip() for s in SLEUTELS},
|
||||
'meldingen': [], 'wijzigingen': [], 'actie': None, 'toestel_id': None, 'waarden': {}}
|
||||
v = r['invoer']
|
||||
fouten = []
|
||||
|
||||
# --- waarden controleren ---
|
||||
nummer, serie = v['schooleigen_id'], v['serienummer']
|
||||
if not nummer and not serie:
|
||||
fouten.append("Toestelnummer of serienummer is verplicht.")
|
||||
for s in ('schooleigen_id', 'serienummer', 'type'):
|
||||
maxlen = next(k[2] for k in KOLOMMEN if k[0] == s)
|
||||
if len(v[s]) > maxlen:
|
||||
fouten.append(f"{KOPPEN[s]} is te lang (max. {maxlen} tekens).")
|
||||
status = None
|
||||
if v['status']:
|
||||
status = next((x for x in STATUSSEN if x.lower() == v['status'].lower()), None)
|
||||
if not status:
|
||||
fouten.append(f"Status '{v['status']}' is ongeldig (kies {', '.join(STATUSSEN)}).")
|
||||
afschrijf = None
|
||||
if v['afschrijfdatum']:
|
||||
try:
|
||||
afschrijf = _datum_tekst(v['afschrijfdatum'])
|
||||
except ValueError:
|
||||
fouten.append(f"Afschrijfdatum '{v['afschrijfdatum']}' is geen geldige datum (gebruik dd-mm-jjjj).")
|
||||
lokaal_id = None
|
||||
if v['lokaal']:
|
||||
l = lok.get(v['lokaal'].upper())
|
||||
if l:
|
||||
lokaal_id = l['Lokaal_ID']
|
||||
else:
|
||||
fouten.append(f"Lokaal '{v['lokaal']}' bestaat niet in PIVOT.")
|
||||
|
||||
# --- dubbels in het bestand (enkel t.o.v. eerdere rijen zonder fout) ---
|
||||
if nummer and gezien_nummer.get(nummer.upper()):
|
||||
fouten.append(f"Toestelnummer {nummer} staat al op rij {gezien_nummer[nummer.upper()]}.")
|
||||
if serie and gezien_serie.get(serie.upper()):
|
||||
fouten.append(f"Serienummer {serie} staat al op rij {gezien_serie[serie.upper()]}.")
|
||||
|
||||
# --- bestaand toestel? ---
|
||||
t_nummer = op_nummer.get(nummer.upper()) if nummer else None
|
||||
t_serie = op_serie.get(serie.upper()) if serie else None
|
||||
toestel = t_nummer or t_serie
|
||||
if t_nummer and t_serie and t_nummer['Toestel_ID'] != t_serie['Toestel_ID']:
|
||||
fouten.append(f"Toestelnummer {nummer} en serienummer {serie} horen in PIVOT bij twee verschillende "
|
||||
f"toestellen. Pas dit eerst aan in 💻 Alle toestellen.")
|
||||
elif toestel:
|
||||
db_nummer = (toestel['Schooleigen_ID'] or '').strip()
|
||||
db_serie = (toestel['Serienummer'] or '').strip()
|
||||
if t_nummer and serie and db_serie and db_serie.upper() != serie.upper():
|
||||
fouten.append(f"Toestel {nummer} heeft in PIVOT serienummer {db_serie}, niet {serie}.")
|
||||
if not t_nummer and nummer and db_nummer and db_nummer.upper() != nummer.upper():
|
||||
fouten.append(f"Serienummer {serie} hoort in PIVOT bij toestel {db_nummer}, niet bij {nummer}.")
|
||||
|
||||
if fouten:
|
||||
r['actie'] = 'fout'
|
||||
r['meldingen'] = fouten
|
||||
tellers['fout'] += 1
|
||||
uit.append(r)
|
||||
continue
|
||||
|
||||
if nummer:
|
||||
gezien_nummer[nummer.upper()] = r['rij']
|
||||
if serie:
|
||||
gezien_serie[serie.upper()] = r['rij']
|
||||
|
||||
nieuw = {'schooleigen_id': nummer or None, 'serienummer': serie or None, 'type': v['type'] or None,
|
||||
'status': status, 'afschrijfdatum': afschrijf, 'lokaal': lokaal_id}
|
||||
|
||||
if not toestel:
|
||||
nieuw['status'] = status or 'Beschikbaar'
|
||||
r['actie'] = 'nieuw'
|
||||
r['waarden'] = {DB_KOLOM[s]: w for s, w in nieuw.items() if w is not None}
|
||||
tellers['nieuw'] += 1
|
||||
uit.append(r)
|
||||
continue
|
||||
|
||||
# --- bijwerken ---
|
||||
r['toestel_id'] = toestel['Toestel_ID']
|
||||
r['label'] = toestel['Schooleigen_ID'] or toestel['Serienummer'] or str(toestel['Toestel_ID'])
|
||||
overgeslagen = []
|
||||
for s, w in nieuw.items():
|
||||
if w is None:
|
||||
continue
|
||||
kolom = DB_KOLOM[s]
|
||||
huidig = toestel[kolom]
|
||||
if isinstance(huidig, datetime):
|
||||
huidig = huidig.date()
|
||||
gelijk = (str(huidig).strip().upper() == str(w).strip().upper()) if huidig not in (None, '') else False
|
||||
if gelijk:
|
||||
continue
|
||||
leeg = huidig is None or (isinstance(huidig, str) and not huidig.strip())
|
||||
if s == 'status' and not overschrijven:
|
||||
leeg = False # status heeft altijd een waarde: enkel wijzigen bij overschrijven
|
||||
if leeg or overschrijven:
|
||||
r['waarden'][kolom] = w
|
||||
oud = lok_naam.get(huidig, huidig) if s == 'lokaal' else huidig
|
||||
nw = lok_naam.get(w, w) if s == 'lokaal' else w
|
||||
r['wijzigingen'].append(f"{KOPPEN[s]}: {_toon(oud) or '–'} → {_toon(nw)}")
|
||||
else:
|
||||
oud = lok_naam.get(huidig, huidig) if s == 'lokaal' else huidig
|
||||
overgeslagen.append(f"{KOPPEN[s]} ({_toon(oud)})")
|
||||
if overgeslagen:
|
||||
r['meldingen'].append("Niet overschreven: " + ', '.join(overgeslagen) + '.')
|
||||
if r['waarden']:
|
||||
r['actie'] = 'bijwerken'
|
||||
tellers['bijwerken'] += 1
|
||||
else:
|
||||
r['actie'] = 'ongewijzigd'
|
||||
tellers['ongewijzigd'] += 1
|
||||
uit.append(r)
|
||||
|
||||
return {'rijen': uit, 'tellers': tellers, 'modus': 'overschrijven' if overschrijven else 'aanvullen'}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Uitvoeren
|
||||
# ---------------------------------------------------------------------------
|
||||
def voer_uit(rijen, modus, gebruiker=None):
|
||||
"""Maakt het plan opnieuw en voert 'nieuw' en 'bijwerken' uit in één transactie.
|
||||
Geeft (plan, aantal_nieuw, aantal_bijgewerkt). Bij een databasefout wordt niets bewaard."""
|
||||
plan = maak_plan(rijen, modus)
|
||||
conn = get_db_connection()
|
||||
cur = conn.cursor()
|
||||
nieuw = bijgewerkt = 0
|
||||
try:
|
||||
conn.start_transaction()
|
||||
for r in plan['rijen']:
|
||||
w = r['waarden']
|
||||
if r['actie'] == 'nieuw':
|
||||
kolommen = list(w.keys())
|
||||
cur.execute(f"INSERT INTO Toestellen ({', '.join(kolommen)}) "
|
||||
f"VALUES ({', '.join(['%s'] * len(kolommen))})", tuple(w[k] for k in kolommen))
|
||||
nieuw += 1
|
||||
elif r['actie'] == 'bijwerken':
|
||||
kolommen = list(w.keys())
|
||||
cur.execute(f"UPDATE Toestellen SET {', '.join(k + ' = %s' for k in kolommen)} WHERE Toestel_ID = %s",
|
||||
tuple(w[k] for k in kolommen) + (r['toestel_id'],))
|
||||
bijgewerkt += 1
|
||||
conn.commit()
|
||||
except Exception:
|
||||
conn.rollback()
|
||||
raise
|
||||
finally:
|
||||
cur.close()
|
||||
conn.close()
|
||||
return plan, nieuw, bijgewerkt
|
||||
Reference in new issue
Block a user