This commit is contained in:
2026-08-19 12:39:14 +02:00
parent 28d4f51d7d
commit 4012170172
5 changed files with 12 additions and 3 deletions
Executable → Regular
View File
+1 -1
View File
@@ -1,4 +1,4 @@
const SHELL_CACHE='fixfin-shell-v3.17';
const SHELL_CACHE='fixfin-shell-v3.18';
const DATA_CACHE='fixfin-data-v1';
const APP_SHELL=['/','/manifest.webmanifest','/icons/icon-192.png','/icons/icon-512.png','/icons/apple-touch-icon.png'];
+1 -1
View File
@@ -77,7 +77,7 @@ async function readPushoverConfig(){const value=await readJsonFile(pushoverFile,
async function savePushoverConfig(input){const token=String(input?.token||'').trim();const user=String(input?.user||'').trim();if(!pushoverKeyPattern.test(token))throw new Error('Der Pushover Application API Token muss 30 alphanumerische Zeichen enthalten.');if(!pushoverKeyPattern.test(user))throw new Error('Der Pushover User/Group Key muss 30 alphanumerische Zeichen enthalten.');await writePrivateJson(pushoverFile,{token,user,updatedAt:new Date().toISOString()});return {configured:true,userMasked:maskKey(user)};}
async function sendPushover(config,{title,message}){
const body=new URLSearchParams({token:config.token,user:config.user,title,message});
const response=await fetch(PUSHOVER_ENDPOINT,{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded','User-Agent':'FixFin/3.17'},body});
const response=await fetch(PUSHOVER_ENDPOINT,{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded','User-Agent':'FixFin/3.18'},body});
let payload={}; try{payload=await response.json();}catch{}
if(!response.ok||payload.status!==1)throw new Error(Array.isArray(payload.errors)?payload.errors.join(' '):`Pushover-API Fehler (${response.status})`);
return payload;
+10 -1
View File
@@ -103,7 +103,16 @@ export async function createPdfReport(data,{year,accountId}={}){
const cols=[{label:'Art',width:88},{label:'Bezeichnung',width:167},{label:'Kategorie',width:105},{label:'Zufluss',width:68,align:'right'},{label:'Abfluss',width:67,align:'right'}];
for(let monthIndex=0;monthIndex<12;monthIndex++){
const monthRows=rows.filter(r=>r.monthIndex===monthIndex);const month=forecast.rows[monthIndex];
addPageIfNeeded(doc,115);doc.fillColor('#17233B').font('Helvetica-Bold').fontSize(14).text(month.name);doc.moveDown(.35);
// Jeder Monat beginnt auf einer eigenen Seite. Der Monatsname steht immer
// links und nutzt die volle Inhaltsbreite, damit er niemals umbrechen kann.
doc.addPage();
drawPdfHeader(doc,`Kontoauszug ${reportYear}`,account.name);
const monthY=doc.y;
doc.fillColor('#17233B').font('Helvetica-Bold').fontSize(16)
.text(month.name,50,monthY,{width:495,align:'left',lineBreak:false});
doc.y=monthY+24;
pdfMetricRow(doc,[{label:'Zuflüsse',value:pdfMoney(month.displayIncome),positive:true},{label:'Abflüsse',value:pdfMoney(month.displayExpense),negative:true},{label:'Nettofluss',value:pdfMoney(month.balance),positive:month.balance>=0,negative:month.balance<0}]);
if(!monthRows.length){doc.fillColor('#667085').font('Helvetica').fontSize(8).text('Keine geplanten Kontobewegungen.');doc.moveDown(.8);continue;}
pdfTableHeader(doc,cols);
Executable → Regular
View File