bmc_hub/patch_time_form.py
Christian bc504b9257 feat: Add subscription management functionality and AnyDesk API integration
- Implemented subscription creation, updating, and rendering in script_9.js.
- Added functions for handling subscription line items, product selection, and total calculations.
- Integrated AnyDesk API for session management in test_anydesk.py.
- Created REST client test requests for API endpoints in api.http.
- Developed a script to check ESET machine status and save details in tmp_check_eset_machine.py.
2026-03-30 07:50:15 +02:00

208 lines
9.7 KiB
Python

with open('app/modules/sag/templates/detail.html', 'r', encoding='utf-8') as f:
text = f.read()
html_start = text.find('<form id="timeManualFormV1"')
html_end = text.find('</form>', html_start) + 7
new_html = """<form id="timeManualFormV1" class="row g-2 align-items-end" onsubmit="createManualTimeV1(event); return false;">
<div class="col-xl-2 col-md-3 col-12">
<label class="form-label small mb-1">Medarbejder</label>
<select class="form-select form-select-sm" id="timeV1EmployeeId">
<option value="">Mig (nuværende bruger)</option>
{% for user in assignment_users %}
<option value="{{ user.user_id }}">{{ user.display_name }}</option>
{% endfor %}
</select>
</div>
<div class="col-xl-2 col-md-3 col-6">
<label class="form-label small mb-1">Dato</label>
<input type="date" class="form-control form-control-sm" id="timeV1Date">
</div>
<div class="col-xl-1 col-md-2 col-3">
<label class="form-label small mb-1">Start</label>
<input type="time" class="form-control form-control-sm" id="timeV1Start">
</div>
<div class="col-xl-1 col-md-2 col-3">
<label class="form-label small mb-1">Slut</label>
<input type="time" class="form-control form-control-sm" id="timeV1End">
</div>
<div class="col-xl-1 col-md-2 col-6">
<label class="form-label small mb-1">Minutt.</label>
<input type="number" min="1" class="form-control form-control-sm" id="timeV1Minutes" placeholder="45" required>
</div>
<div class="col-xl-2 col-md-6 col-6">
<label class="form-label small mb-1">Beskrivelse</label>
<input type="text" class="form-control form-control-sm" id="timeV1Description" placeholder="Hvad er udført?">
</div>
<div class="col-xl-2 col-md-4 col-12 d-flex gap-1">
<div class="w-50">
<label class="form-label small mb-1">Type</label>
<select class="form-select form-select-sm px-1" id="timeV1Type">
<option value="ukendt">Ukendt</option>
<option value="manuel" selected>Manuel</option>
<option value="opkald">Opkald</option>
<option value="mail">Mail</option>
<option value="indedesk">IndeDesk</option>
</select>
</div>
<div class="w-50">
<label class="form-label small mb-1">Status</label>
<select class="form-select form-select-sm px-1" id="timeV1Status">
<option value="kladde">Kladde</option>
<option value="afventer" selected>Afventer</option>
<option value="godkendt">Godkendt</option>
</select>
</div>
</div>
<div class="col-xl-1 col-md-2 col-12 d-grid">
<button class="btn btn-sm btn-primary" type="submit" title="Tilføj registrering"><i class="bi bi-plus-lg fs-6"></i></button>
</div>
</form>"""
if html_start != -1 and html_end != -1:
text = text[:html_start] + new_html + text[html_end:]
print("HTML updated.")
js_start = text.find('async function createManualTimeV1(event) {')
js_end = text.find(' document.addEventListener(\'DOMContentLoaded\'', js_start)
# Notice here the JS checks for start_tid / slut_tid to populate them.
new_js = """function bindTimeV1Calculations() {
const startIn = document.getElementById('timeV1Start');
const endIn = document.getElementById('timeV1End');
const minIn = document.getElementById('timeV1Minutes');
if (!startIn || !endIn || !minIn) return;
const parseTime = (val) => {
if (!val) return null;
const [h,m] = val.split(':').map(Number);
return (h * 60) + m;
};
const toTimeStr = (totalMins) => {
const h = Math.floor(totalMins / 60) % 24;
const m = totalMins % 60;
return `${h.toString().padStart(2,'0')}:${m.toString().padStart(2,'0')}`;
};
const recalculate = (trigger) => {
const s = parseTime(startIn.value);
const e = parseTime(endIn.value);
const dur = parseInt(minIn.value);
if (trigger === 'start' || trigger === 'end') {
if (s !== null && e !== null) {
let diff = e - s;
if (diff < 0) diff += 24*60;
minIn.value = diff;
} else if (s !== null && !isNaN(dur) && dur > 0 && !endIn.value) {
endIn.value = toTimeStr(s + dur);
} else if (e !== null && !isNaN(dur) && dur > 0 && !startIn.value) {
let base = e - dur;
while (base < 0) base += 24*60;
startIn.value = toTimeStr(base);
}
} else if (trigger === 'min') {
if (s !== null && !isNaN(dur) && dur > 0) {
endIn.value = toTimeStr(s + dur);
} else if (e !== null && !isNaN(dur) && dur > 0 && !startIn.value) {
let base = e - dur;
while(base < 0) base+=24*60;
startIn.value = toTimeStr(base);
}
}
};
startIn.addEventListener('change', () => recalculate('start'));
endIn.addEventListener('change', () => recalculate('end'));
minIn.addEventListener('input', () => recalculate('min'));
}
async function createManualTimeV1(event) {
event.preventDefault();
const minutes = Number(document.getElementById('timeV1Minutes')?.value || 0);
if (minutes <= 0) {
alert('Indtast minutter over 0');
return;
}
const dateVal = document.getElementById('timeV1Date')?.value || null;
const tStart = document.getElementById('timeV1Start')?.value;
const tEnd = document.getElementById('timeV1End')?.value;
let startObj = null;
let endObj = null;
if (dateVal && tStart) {
try {
const l = new Date(`${dateVal}T${tStart}:00`);
startObj = l.toISOString();
} catch(e){}
}
if (dateVal && tEnd) {
try {
const l = new Date(`${dateVal}T${tEnd}:00`);
if (startObj && new Date(startObj) > l) {
l.setDate(l.getDate() + 1);
}
endObj = l.toISOString();
} catch(e){}
}
const payload = {
sag_id: timeCaseId,
medarbejder_id: getTimeV1EmployeeId(),
faktisk_tid_min: minutes,
worked_date: dateVal,
entry_type: document.getElementById('timeV1Type')?.value || 'manuel',
entry_status: document.getElementById('timeV1Status')?.value || 'afventer',
beskrivelse: document.getElementById('timeV1Description')?.value || null,
kilde: 'manuel',
start_tid: startObj,
slut_tid: endObj
};
try {
const res = await fetch('/api/v1/timetracking/time/manual', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!res.ok) throw new Error(await res.text());
const minutesInput = document.getElementById('timeV1Minutes');
const descInput = document.getElementById('timeV1Description');
const startIn = document.getElementById('timeV1Start');
const endIn = document.getElementById('timeV1End');
if (minutesInput) minutesInput.value = '';
if (descInput) descInput.value = '';
if (startIn) startIn.value = '';
if (endIn) endIn.value = '';
await loadTimeTrackingTab();
} catch (error) {
alert('Kunne ikke oprette tidsregistrering: ' + (error.message || 'ukendt fejl'));
}
}
\n"""
if js_start != -1 and js_end != -1:
text = text[:js_start] + new_js + text[js_end:]
print("JS updated.")
dom_start = text.find('document.addEventListener(\'DOMContentLoaded\'')
if dom_start != -1:
dom_body_start = text.find('{', dom_start) + 1
# Check if we already injected it
if 'bindTimeV1Calculations();' not in text[dom_start:dom_start+200]:
text = text[:dom_body_start] + "\n bindTimeV1Calculations();" + text[dom_body_start:]
print("DOMContentLoaded updated.")
with open('app/modules/sag/templates/detail.html', 'w', encoding='utf-8') as f:
f.write(text)
print("File saved successfully.")