Files
erp-efintel-2026-portainer/patch_html.py
T
2026-09-07 18:44:32 -03:00

99 lines
4.5 KiB
Python

import re
with open('templates/expenses/expense_form.html', 'r', encoding='utf-8') as f:
content = f.read()
# 1. Add x-data
content = content.replace('<form method="post" enctype="multipart/form-data">', '<form method="post" enctype="multipart/form-data" x-data="expenseForm()">')
# 2. Add x-show to responsible person container
content = content.replace('<div id="responsible-person-container"', '<div id="responsible-person-container" x-show="isReimbursement"')
# 3. Add x-show to new vendor fields
# We need to bind the toggle-new-vendor checkbox
content = content.replace('<input type="checkbox" id="toggle-new-vendor"', '<input type="checkbox" id="toggle-new-vendor" x-model="isNewVendor"')
content = content.replace('<div id="new-vendor-fields"', '<div id="new-vendor-fields" x-show="isNewVendor"')
content = content.replace('style="display: none;', 'style="display: none;" x-cloak ')
# Add x-cloak style to head or just use x-show directly
# Actually replacing the display: none might be tricky, let's just do x-show.
content = content.replace('<div id="new-vendor-fields" style="display: none;', '<div id="new-vendor-fields" x-cloak x-show="isNewVendor" style="')
content = content.replace('<div id="responsible-person-container" x-show="isReimbursement" style="margin-top:0.5rem;">', '<div id="responsible-person-container" x-cloak x-show="isReimbursement" style="margin-top:0.5rem;">')
# Replace the giant vanilla JS <script> with Alpine
# The original script starts at <script> around line 242 and ends at </script> around line 875
script_pattern = re.compile(r'<script>\s*document\.querySelectorAll.*?</script>', re.DOTALL)
alpine_script = """
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('expenseForm', () => ({
isReimbursement: document.getElementById('id_is_reimbursement')?.checked || false,
isNewVendor: false,
amountClp: document.getElementById('id_amount_clp')?.value || '',
taxType: document.getElementById('id_tax_type')?.value || 'EXENTO',
taxAmountClp: document.getElementById('id_tax_amount_clp')?.value || '0',
totalAmountClp: document.getElementById('id_total_amount_clp')?.value || '0',
newVendorRut: '',
rutError: false,
formatAmount() {
let cleanVal = this.amountClp.replace(/\./g, '').replace(/\D/g, '');
if (cleanVal) {
this.amountClp = cleanVal.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ".");
} else {
this.amountClp = '';
}
},
async calculateTax() {
let cleanVal = this.amountClp.replace(/\./g, '');
let amount = parseFloat(cleanVal) || 0;
if (amount > 0 && this.taxType) {
try {
const response = await fetch(`/api/v1/sii/calculate-tax?amount=${amount}&tax_type=${this.taxType}`);
const data = await response.json();
this.taxAmountClp = data.tax_amount.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ".");
this.totalAmountClp = data.total_amount.toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, ".");
} catch (e) {
console.error('Error calculating tax', e);
}
} else {
this.taxAmountClp = '0';
this.totalAmountClp = '0';
}
},
async validateRut() {
if (!this.newVendorRut) {
this.rutError = false;
return;
}
try {
const response = await fetch(`/api/v1/sii/validate-rut?rut=${this.newVendorRut}`);
const data = await response.json();
if (data.is_valid) {
this.newVendorRut = data.formatted_rut;
this.rutError = false;
} else {
this.rutError = true;
alert(data.error_message || "RUT inválido");
}
} catch (e) {
console.error('Error validating RUT', e);
}
}
}));
});
</script>
<style>
[x-cloak] { display: none !important; }
</style>
"""
content = script_pattern.sub(alpine_script, content)
with open('templates/expenses/expense_form.html', 'w', encoding='utf-8') as f:
f.write(content)