Skip to content

Instantly share code, notes, and snippets.

@plexus
Created January 4, 2019 16:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save plexus/a1308bc40431a4d2e6c7143a84a70cec to your computer and use it in GitHub Desktop.
Save plexus/a1308bc40431a4d2e6c7143a84a70cec to your computer and use it in GitHub Desktop.
# coding: utf-8
$:.unshift '/home/arne/github/kramdown/lib'
require 'fileutils'
require 'prawn'
require 'kramdown'
require 'json'
CURRENCIES = {
'EUR' => '€ %.2f',
'USD' => 'USD %.2f'
}
PAYMENTS = {
'bank' => 'Please make payment directly to the account of Arne Brasseur :
Arne Brasseur
IBAN: DE67100110012625668716
BIC: NTSBDEB1XXX',
'paypal' => 'Please make payment through PayPal to the account **arne@arnebrasseur.net**.'
}
DEFAULTS = {
'currency' => 'EUR',
'payment' => 'bank',
'region' => 'EU',
'pre_message' => '',
'description' => "Software development"
}
class Prawn::Document
alias current_page page # :(
end
TEMPLATE = File.read('template.md')
class Invoice
def self.from_file(infile)
new(DEFAULTS.merge(JSON.parse(File.read(infile))))
end
def initialize(data)
data.each do |k,v|
define_singleton_method(k){v}
end
end
def total
if respond_to?(:days) && respond_to?(:day_price)
days.to_f * day_price.to_f
elsif respond_to?(:hours) && respond_to?(:hour_price)
hrs = hours
if respond_to?(:minutes)
hrs += (minutes.to_f/60)
end
hrs.to_f * hour_price.to_f
else
line_items.map(&:last).map(&:to_f).inject(:+)
end
end
def fmt_month
%w[
January February March
April May June
July August September
Oktober November December
][month.to_i - 1]
end
def payment_info
PAYMENTS[payment]
end
def fmt_price(price)
CURRENCIES[currency.upcase] % Float(price)
end
def customer_vat_nr
"VAT no.: #{customer_vat}" if respond_to?(:customer_vat)
end
def full_invoice_number
if invoice_number =~ /^\d+$/
"#{year}/#{invoice_number}"
else
invoice_number
end
end
unless respond_to?(:post_message)
def post_message
"Reverse charge method; customer is responsible for the VAT." if region == 'EU'
end
end
def table(data)
data.map do |line|
('| ' + line.join(' | ') + ' |').gsub(/(\d) \|/, '\1|')
end.join("\n")
end
def bold(str)
'**' + str.to_s + '**'
end
def fmt_hours
if respond_to?(:minutes)
"%d:%02d hours" % [hours, minutes]
else
"%d hours" % [hours]
end
end
def vat
if region == "DE"
total * 0.19
else
0
end
end
def grand_total
if region == "DE"
total * 1.19
else
total
end
end
def line_items_table
lines = if respond_to?(:days)
tbl = [ [ description , "#{days} days", "#{fmt_price day_price} / day" , fmt_price(total) ] ]
if region == "DE"
tbl << [nil, nil, "VAT 19%", fmt_price(total * 0.19)]
tbl << [nil, nil, "Total", fmt_price(total * 1.19)]
else
tbl << [nil, nil, "Total", fmt_price(total)]
end
tbl
elsif respond_to?(:hours)
tbl = [ [ description , fmt_hours, "#{fmt_price hour_price} / hour" , fmt_price(total) ] ]
if region == "DE"
tbl << [nil, nil, "VAT 19%", fmt_price(total * 0.19)]
tbl << [nil, nil, "Total", fmt_price(total * 1.19)]
else
tbl << [nil, nil, "Total", fmt_price(total)]
end
tbl
else
tbl = line_items.map do |(desc, price)|
[ desc, fmt_price(price) ]
end
if region == "DE"
tbl << ["VAT 19%", fmt_price(total * 0.19)]
tbl << ["Total", bold(fmt_price(total * 1.19))]
else
tbl << ["Total", bold(fmt_price(total))]
end
tbl
end
table(lines)
end
def call(outfile)
markdown = TEMPLATE.gsub(/\{\{[^\}]+\}\}/) do |token|
token = token[2...-2]
self.send(token)
end
doc = Kramdown::Document.new(markdown, input: 'GFM')
puts outfile
File.write(outfile, doc.to_pdf)
dir = "/home/arne/Doku/DE/#{year}#{month}"
FileUtils.mkdir_p(dir)
FileUtils.cp(outfile, dir)
end
end
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require_relative './invoice'
infile = ARGV.shift
outfile = ARGV.shift || 'pdf/' + infile.sub(/json$/, 'pdf')
Invoice.from_file(infile).call(outfile)

INVOICE

Arne Brasseur (IT-Consult)

Date of invoice : {{invoice_date}}

Invoice number: {{full_invoice_number}}

{{customer_address}}

{{customer_vat_nr}}

{{pre_message}}

{{line_items_table}}

{{post_message}}


{{payment_info}}


Arne Brasseur Roennebergstr 8 - 12161 Berlin (DE) VAT no.: DE291146993 Telephone: +49 176 9746 8014 Email: arne@arnebrasseur.net

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment