bmc_hub/patch_time_modal.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

172 lines
9.2 KiB
Python

with open('app/modules/sag/templates/detail.html', 'r', encoding='utf-8') as f:
text = f.read()
# Replace HTML for timeForm
html_start = text.find('<form id="timeForm">')
html_end = text.find('</form>', html_start) + 7
new_html = """<form id="timeForm">
<input type="hidden" id="time_sag_id" value="{{ case.id }}">
<div class="row g-3">
<div class="col-12 col-md-6">
<label class="form-label">Dato *</label>
<input type="date" class="form-control" id="time_date" required>
</div>
<div class="col-12 col-md-6">
<label class="form-label">Tid brugt *</label>
<div class="input-group">
<span class="input-group-text">Min.</span>
<input type="number" class="form-control" id="time_total_minutes" min="1" placeholder="45" step="1" required>
</div>
</div>
<div class="col-6">
<label class="form-label">Starttid</label>
<input type="time" class="form-control" id="time_start_input">
</div>
<div class="col-6">
<label class="form-label">Sluttid</label>
<input type="time" class="form-control" id="time_end_input">
</div>
<div class="col-6">
<label class="form-label">Type</label>
<select class="form-select" id="time_work_type">
<option value="support" selected>Support</option>
<option value="troubleshooting">Fejlsøgning</option>
<option value="development">Udvikling</option>
<option value="on_site">Kørsel / On-site</option>
<option value="meeting">Møde</option>
<option value="other">Andet</option>
</select>
</div>
<div class="col-6">
<label class="form-label">Afregning</label>
<select class="form-select" id="time_billing_method">
<option value="invoice" selected>Faktura</option>
{% if prepaid_cards %}
<optgroup label="Klippekort">
{% for card in prepaid_cards %}
<option value="card_{{ card.id }}">💳 Klippekort #{{ card.card_number or card.id }} ({{ '%.2f' % card.remaining_hours }}t tilbage{% if card.expires_at %} • Udløber {{ card.expires_at }}{% endif %})</option>
{% endfor %}
</optgroup>
{% endif %}
{% if fixed_price_agreements %}
<optgroup label="Fastpris Aftaler">
{% for agr in fixed_price_agreements %}
<option value="fpa_{{ agr.id }}">📋 Fastpris #{{ agr.agreement_number }} ({{ '%.1f' % agr.remaining_hours_this_month }}t tilbage / {{ '%.0f' % agr.monthly_hours }}t/måned)</option>
{% endfor %}
</optgroup>
{% endif %}
<option value="internal">Internt / Ingen faktura</option>
<option value="warranty">Garanti / Reklamation</option>
</select>
</div>
<div class="col-12">
<label class="form-label">Beskrivelse</label>
<textarea class="form-control" id="time_desc" rows="3" placeholder="Hvad er der brugt tid på?"></textarea>
</div>
</div>
</form>"""
if html_start != -1 and html_end != -1:
text = text[:html_start] + new_html + text[html_end:]
print("Replaced timeForm HTML.")
# Modify reset logic in showAddTimeModal
reset_start = text.find('if(document.getElementById(\'time_hours_input\')) {')
reset_end = text.find('}', reset_start) + 1
if reset_start != -1:
new_reset = """if(document.getElementById('time_total_minutes')) {
document.getElementById('time_total_minutes').value = '';
document.getElementById('time_start_input').value = '';
document.getElementById('time_end_input').value = '';
}"""
text = text[:reset_start] + new_reset + text[reset_end:]
print("Replaced modal form reset.")
# Delete old updateTimeTotal function, add bindTimeModalCalculations
updateTotalStart = text.find('function updateTimeTotal() {')
updateTotalEnd = text.find('}', updateTotalStart) + 1
if updateTotalStart != -1:
new_updateTotal = """function bindTimeModalCalculations() {
const startIn = document.getElementById('time_start_input');
const endIn = document.getElementById('time_end_input');
const minIn = document.getElementById('time_total_minutes');
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'));
}"""
text = text[:updateTotalStart] + new_updateTotal + text[updateTotalEnd:]
print("Replaced updateTimeTotal with bindTimeModalCalculations")
# Fix listeners initialization
dom_start = text.find('const hInput = document.getElementById(\'time_hours_input\');')
dom_end = text.find('if(mInput) mInput.addEventListener(\'input\', updateTimeTotal);', dom_start) + 63
if dom_start != -1:
text = text[:dom_start] + "bindTimeModalCalculations();" + text[dom_end:]
print("Fixed DOM listeners")
# Replace saveTime body part logic: calculate minutes explicitly from `time_total_minutes`
save_start = text.find('async function saveTime() {')
save_end = text.find('const isInternal = document.getElementById(\'time_internal\')?.checked || false;', save_start)
if save_start != -1:
new_save = """async function saveTime() {
const mInput = document.getElementById('time_total_minutes');
const minVal = parseInt(mInput ? mInput.value : 0);
if (!minVal || minVal <= 0) {
alert('Indtast en gyldig varighed (minutter).');
return;
}
const totalHours = minVal / 60;
"""
text = text[:save_start] + new_save + text[save_end:]
print("Updated saveTime first half.")
# Note: saveTime uses `POST /api/v1/cases/${sagId}/time` or similar, wait let me check the actual fetch path.
# Let's check `saveTime` first before committing blindly. I will just do the above first, then verify `saveTime`.
with open('app/modules/sag/templates/detail.html', 'w', encoding='utf-8') as f:
f.write(text)