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
add invoice
  • Loading branch information
Andreas Müller committed Feb 23, 2021
commit da0f40a33f8dc07291bbfb8f438e7cfb01dbdc22
22 changes: 20 additions & 2 deletions src/gtt-report.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const Output = {
csv: require('./output/csv'),
pdf: require('./output/pdf'),
markdown: require('./output/markdown'),
invoice: require('./output/invoice'),
dump: require('./output/dump'),
xlsx: require('./output/xlsx')
};
Expand Down Expand Up @@ -64,6 +65,13 @@ program
.option('--verbose', 'show verbose output')
.option('--show_without_times', 'show issues/merge requests without time records')
.option('--from_dump <file>', 'instead of querying gitlab, use data from the given dump file')
.option('--invoiceTitle <title>', 'title on invoice')
.option('--invoiceAddress [address...]', 'address')
.option('--invoiceCurrency <currency>', 'currecnty on invoice')
.option('--invoiceCurrencyPerHour <number>', 'hourly wage rate on invoice')
.option('--invoiceVAT <number>', 'vat decimal (20% = 0.2)')
.option('--invoiceDate <number>', 'date string')
.option('--invoiceCurrencyMaxUnit <number>', 'rouning invoice total, e.g. 0.01, 0.05 or 1')
.parse(process.argv);

// init helpers
Expand Down Expand Up @@ -123,6 +131,16 @@ config
.set('type', program.opts().type)
.set('subgroups', program.opts().subgroups)
.set('_verbose', program.opts().verbose)
<<<<<<< Updated upstream
=======
.set('invoiceTitle', program.opts().invoiceTitle)
.set('invoiceAddress', program.opts().invoiceAddress)
.set('invoiceCurrency', program.opts().invoiceCurrency)
.set('invoiceCurrencyPerHour', program.opts().invoiceCurrencyPerHour)
.set('invoiceVAT', program.opts().invoiceVAT)
.set('invoiceDate', program.opts().invoiceDate)
.set('invoiceCurrencyMaxUnit', program.opts().invoiceCurrencyMaxUnit)
>>>>>>> Stashed changes
.set('_createDump', program.opts().output === 'dump');

// date shortcuts
Expand Down Expand Up @@ -150,10 +168,10 @@ let reports = new ReportCollection(config),
output;

// warnings
if (config.get('iids').length > 1 && config.get('query').length > 1) {
if (config.get('iids').length >= 1 && config.get('query').length > 1) {
Cli.warn(`The ids argument is ignored when querying issues and merge requests`);
}
if (config.get('iids').length > 1 && (config.get('type') !== 'project' || projects.length > 1)) {
if (config.get('iids').length >= 1 && (config.get('type') !== 'project' || projects.length > 1)) {
Cli.warn(`The ids argument is ignored when querying multiple projects`);
}
if ((config.get('report').includes('issues') && !config.get('query').includes('issues'))) {
Expand Down
3 changes: 3 additions & 0 deletions src/output/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ class base {
'total spent': this.config.toHumanReadable(totalSpent, 'stats'),
'spent': this.config.toHumanReadable(spent, 'stats')
};
this.totalEstimate = totalEstimate;
this.spent = spent;
this.totalSpent = totalSpent;
}

/**
Expand Down
127 changes: 127 additions & 0 deletions src/output/invoice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
const _ = require('underscore');

const Table = require('markdown-table');
const Base = require('./base');

const format = {
headline: h => `\n### ${h}\n`,
warning: w => `${w}`
};

/**
* stdout table output
*/
class invoice extends Base {
constructor(config, report) {
super(config, report);
this.format = format;
this.invoiceCurrency = this.config.get('invoiceCurrency');
this.invoiceCurrencyPerHour = this.config.get('invoiceCurrencyPerHour');
this.invoiceVAT = this.config.get('invoiceVAT');
this.invoiceCurrencyMaxUnit = this.config.get('invoiceCurrencyMaxUnit');
this.totalhForInvoice = this.spent / 3600.0;
this.totalForInvoiceExkl = this.totalhForInvoice * this.invoiceCurrencyPerHour;
this.totalForInvoiceMwst = this.totalForInvoiceExkl * this.invoiceVAT;
this.totalForInvoice = this.totalForInvoiceExkl + this.totalForInvoiceMwst;
// round
this.totalForInvoice = Math.round(this.totalForInvoice/this.invoiceCurrencyMaxUnit)*this.invoiceCurrencyMaxUnit;
}


concat(data, separator) {
if(null == data) {
return "";
}
if(!Array.isArray(data)) {
return data;
}
return data.join(separator);
}

makeStats() {

let stats = '';

_.each(this.stats, (time, name) => stats += `\n* **${name}**: ${time}`);
stats += `\n`;

if (this.projects.length > 1) {
_.each(this.projects, (time, name) => stats += `\n* **${name.red}**: ${time}`);
stats += `\n`;
}
// REMOVE
// _.each(this.users, (time, name) => stats += `\n* **${name}**: ${time}`);
let to = this.concat(this.config.get('invoiceAddress'), '</br>');
let from = this.concat(this.config.get('invoiceSettings').from, '</br>');
let opening = this.concat(this.config.get('invoiceSettings').opening, '</br>');
let closing = this.concat(this.config.get('invoiceSettings').closing, '</br>');
let positionText = this.concat(this.config.get('invoiceSettings').positionText, '</br>');

this.out +=
`<div class="senderBox">${from}</div>

<div class="addressBox">
<div class="addressFrom">${this.config.get('invoiceSettings').fromShort}</div>
<div class="addressTo">${to}</div>
</div>
<div class="dateBox">${this.config.get('invoiceDate')}</div>

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

${opening}

<div class="positionBox">
<div class="positionDesc">${positionText} (${this.totalhForInvoice.toFixed(2)} Stunden zu ${this.invoiceCurrencyPerHour} ${this.invoiceCurrency})</div>
<div class="positionValue">${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</div>
<div class="positionValueTot">${this.invoiceCurrency} ${this.totalForInvoice.toFixed(2)}</div>
</div>

${this.config.get('invoiceSettings').bankAccount}

${closing}


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

this.headline('Total');
this.write(stats.substr(1));
}

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.headline('Details');

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));
}
}

module.exports = invoice;