Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
remove invoice 2
  • Loading branch information
ndu2 committed May 25, 2025
commit 87ef5d687587b62d99acf1450d0a7b1a9dcef2fa
2 changes: 0 additions & 2 deletions src/gtt-report.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import table from './output/table.js';
import csv from './output/csv.js';
import markdown from './output/markdown.js';
import invoice from './output/invoice.js';
import invoice2 from './output/invoice2.js';
import dump from './output/dump.js';
import xlsx from './output/xlsx.js';

Expand All @@ -20,7 +19,6 @@ const Output = {
csv,
markdown,
invoice,
invoice2,
dump,
xlsx
};
Expand Down
163 changes: 93 additions & 70 deletions src/output/invoice.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import _ from 'underscore';
import {markdownTable as Table} from 'markdown-table';
import {markdownTable as Table} from 'markdown-table'
import Base from './base.js';
import { SwissQRBill } from "swissqrbill/svg";

Expand All @@ -18,7 +18,9 @@ class invoice extends Base {
this.invoiceCurrency = this.config.get('invoiceCurrency');
this.invoiceCurrencyPerHour = this.config.get('invoiceCurrencyPerHour');
this.invoiceVAT = this.config.get('invoiceVAT');
this.invoiceText = this.config.get('invoiceText') ? this.config.get('invoiceText') : '';
this.invoicePositionText = this.config.get('invoicePositionText');
this.invoicePositionExtra = this.config.get('invoicePositionExtra');
this.invoicePositionExtraTexts = this.config.get('invoicePositionExtraText');
this.invoicePositionExtraValues = this.config.get('invoicePositionExtraValue').map(
(v) => {
Expand All @@ -28,14 +30,33 @@ class invoice extends Base {
this.invoicePositionExtraTotal = 0.0;
this.invoicePositionExtraValues.forEach(v => (this.invoicePositionExtraTotal += v));

this.invoiceCurrencyMaxUnit = this.config.get('invoiceCurrencyMaxUnit');
this.invoiceTimeMaxUnit = this.config.get('invoiceTimeMaxUnit');

this.invoicePositions = {}; //key=iid, value=[text, total H, Rate, Total]

this.invoiceCurrencyMaxUnit = this.config.get('invoiceCurrencyMaxUnit');
this.totalhForInvoice = (this.spent-this.spentFree-(this.spentHalfPrice*0.5)) / 3600.0;
// round subtotals to 0.01 and total to invoiceCurrencyMaxUnit.
let invoiceTotal = this.totalhForInvoice * this.invoiceCurrencyPerHour + this.invoicePositionExtraTotal;
this.totalForInvoiceH = Math.round(this.totalhForInvoice * this.invoiceCurrencyPerHour * 100) * 0.01;
this.totalForInvoiceExkl = Math.round(invoiceTotal * 100) * 0.01;
Object.keys(this.daysNew).forEach(
k => {
let day = this.daysNew[k];
day.forEach(
(dayReport) => {
let iid = dayReport.getIid();
if(!this.invoicePositions[iid]) {
this.invoicePositions[iid] = [dayReport.getTitle(), 0.0, this.invoiceCurrencyPerHour * dayReport.getChargeRatio(), 0.0];
}
this.invoicePositions[iid][1] += dayReport.getSpent(this.invoiceTimeMaxUnit) / 3600;
this.invoicePositions[iid][3] = Math.round((this.invoicePositions[iid][1] * this.invoicePositions[iid][2]) * 100) * 0.01;
}
);
});

let invoiceTotal = this.invoicePositionExtraTotal;
Object.keys(this.invoicePositions).forEach(
k => {
invoiceTotal += this.invoicePositions[k][3];
}
)
this.totalForInvoiceExkl = invoiceTotal;
this.totalForInvoiceMwst = Math.round(invoiceTotal * this.invoiceVAT * 100) * 0.01;
this.totalForInvoice = Math.round((this.totalForInvoiceExkl + this.totalForInvoiceMwst)/this.invoiceCurrencyMaxUnit)*this.invoiceCurrencyMaxUnit;
}
Expand Down Expand Up @@ -135,16 +156,32 @@ class invoice extends Base {
svg.instance.viewBox(0,0,740,420)
svg.instance.height("");
svg.instance.width("");
let positions ="";
let positionIids = Object.keys(this.invoicePositions);
positionIids.sort();
positionIids.forEach(
k => {
// text, total H, Rate, Total
let position = this.invoicePositions[k];
positions +=
`<div class="positionDesc">${position[0]}: ${position[1].toFixed(2)}h (${position[2]} ${this.invoiceCurrency}/h)</div>
<div class="positionValue">${this.invoiceCurrency} ${position[3].toFixed(2)}</div>
`;
}
);

let extra = "";
if(this.invoicePositionExtraTotal > 0) {
if(this.invoicePositionExtra || this.invoicePositionExtraTotal > 0) {
if(this.invoicePositionExtra) {
extra += `<div class="position">${this.invoicePositionExtra}</div>`;
}
for(var i in this.invoicePositionExtraTexts) {
extra +=
`
<div class="positionDesc">${this.invoicePositionExtraTexts[i]}</div>
<div class="positionValue">${this.invoiceCurrency} ${this.invoicePositionExtraValues[i].toFixed(2)}</div>
`;
}

}

this.out +=
Expand All @@ -158,12 +195,14 @@ class invoice extends Base {

# ${this.config.get('invoiceTitle')}

${opening}
${opening} ${this.invoiceText}

<div class="positionBox">
<div class="positionDesc">${this.invoicePositionText} (${this.totalhForInvoice.toFixed(2)} Stunden zu ${this.invoiceCurrencyPerHour} ${this.invoiceCurrency})</div>
<div class="positionValue">${this.invoiceCurrency} ${this.totalForInvoiceH.toFixed(2)}</div>
<div class="position">${this.invoicePositionText}</div>
${positions}
${extra}
<div class="positionDescTot">Summe Netto</div>
<div class="positionValueTot">${this.invoiceCurrency} ${this.totalForInvoiceExkl.toFixed(2)}</div>
<div class="positionDesc">MWST (${this.invoiceVAT*100}%)</div>
<div class="positionValue">${this.invoiceCurrency} ${this.totalForInvoiceMwst.toFixed(2)}</div>
<div class="positionDescTot">Rechnungsbetrag inkl. MWST</div>
Expand All @@ -175,16 +214,52 @@ ${this.config.get('invoiceSettings').bankAccount}
${closing}


<div class="qr-div">${svg.toString()}</div>
<div class="qr-div">${svg.toString()}</div>`

}

makeIssues() {
}

makeMergeRequests() {
}

makeRecords() {
this.out += `

<h1 style="page-break-before: always;"><br/><br/>Stundenrapport</h1>`;

this.headline('Total');
//this.write(stats.substr(1));
this.write(this.config.toHumanReadable(this.spent, 'stats'));
this.write(this.config.toHumanReadable(this.spentHalfPrice, 'statsHalfPrice'));
this.write(this.config.toHumanReadable(this.spentFree, 'statsFree'));
let timesNew = [['Datum', 'Beschreibung', 'Stunden']];
let daysNew = Object.keys(this.daysNew);
daysNew.sort();
daysNew.forEach(
k => {
let day = this.daysNew[k];
day.forEach(
(dayReport) => {
let notesLi = "";

dayReport.getNotes().forEach(
(note) => (notesLi+=`<li>${note}</li>`));
if(notesLi !== "") {
notesLi = `<ul>${notesLi}</ul>`;
}
timesNew.push([dayReport.getDate().format(this.config.get('dateFormat')),
dayReport.getTitle() + notesLi,
this.config.toHumanReadable(dayReport.getSpent(this.invoiceTimeMaxUnit), 'records')
]);
}
);
});
this.write(`<style>
table th:first-of-type { width: 12%; }
table th:nth-of-type(2) { width: 78%; }
table th:nth-of-type(3) { width: 10%; }
</style>`);

this.write(Table(timesNew, { align: ['l', 'l', 'r'] }));



// warnings
let warnings = '';
Expand All @@ -201,58 +276,6 @@ ${closing}
}
}

makeIssues() {
this.headline('Issues');

if (this.report.issues.length === 0)
return this.warning('No issues found');

let issues = [this.config.get('issueColumns').map(c => c.replace('_', ' '))];
this.report.issues.forEach(issue => issues.push(this.prepare(issue, this.config.get('issueColumns'))));

this.write(Table(issues));
}

makeMergeRequests() {
this.headline('Merge Requests');

if (this.report.mergeRequests.length === 0)
return this.warning('No merge requests found');

let mergeRequests = [this.config.get('mergeRequestColumns').map(c => c.replace('_', ' '))];
this.report.mergeRequests.forEach(mergeRequest => mergeRequests.push(this.prepare(mergeRequest, this.config.get('mergeRequestColumns'))));

this.write(Table(mergeRequests));
}

makeRecords() {
this.out += `

<h1 style="page-break-before: always;"><br/><br/>Stundenrapport detailliert</h1>`;
this.headline('Details');

let times = [['date', 'iid', 'time']];
let days = Object.keys(this.days);
days.sort();
days.forEach(
k => {
let day = this.days[k];
let refD = this.daysMoment[k].format(this.config.get('dateFormat'));
let projects = Object.keys(day);
projects.forEach(
p => {
let iids = Object.keys(day[p]);
iids.sort();
iids.forEach(
iid => {
times.push([refD, iid, this.config.toHumanReadable(day[p][iid], 'records')]);
});
});
});
//let times = [this.config.get('recordColumns').map(c => c.replace('_', ' '))];
//this.times.forEach(time => times.push(this.prepare(time, this.config.get('recordColumns'))));
this.write(Table(times));
}
}

export default invoice;
Loading