Invoice

From Wiki
Revision as of 22:48, 14 December 2011 by Hraban (talk | contribs) (new)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

< Sample documents

This is my invoice setup, it works with MkIV as of 2011-12.

It’s an application of Wolfgang’s letter module with a lot of tweaks that I could never think of on my own.

The code isn’t pretty or modular or readily usable for you, but works for me and might get you over some hurds.

As you see, I need my invoices in Euros or Swiss Francs. And I need to charge some work by time and some by fixed amounts. If you need number of pieces etc., it should be easy to adapt.

Big thanks to Wolfgang and all the other helpful power users on NTG-ConTeXt!

Lua functions

File invoicefunctions.tex

\startluacode
userdata = userdata or {}

userdata.invoice = { amount = 0, hours = 0, perhour = 50, currency1 = "€", currency2 = "SFr", exchangerate=1.22, items = {} }

function userdata.RegisterTimeItem(text, hours)
	if tex.systemmodes.trialtypesetting then return end
	table.insert(userdata.invoice.items, {text=text, hours=hours, amount=0})
	userdata.invoice.hours = userdata.invoice.hours + hours
	userdata.invoice.amount = userdata.invoice.amount + hours * userdata.invoice.perhour
end

function userdata.RegisterAmountItem(text, amount)
	if tex.systemmodes.trialtypesetting then return end
	table.insert(userdata.invoice.items, {text=text, hours=0, amount=amount})
	userdata.invoice.amount = userdata.invoice.amount + amount
end

function userdata.RegisterTextItem(text)
	if tex.systemmodes.trialtypesetting then return end
	table.insert(userdata.invoice.items, {text=text, hours=0, amount=0})
end

function userdata.numberformat(amount)
	-- replace decimal point with comma (= German format)
	return string.gsub(string.format("\%.2f", amount), "%.", ",")
end

function userdata.InvoiceTimeLine(text, hours, printperhour)
	context.NC(text)
	context.NC(userdata.numberformat(hours) .. "\\,h")
	if printperhour then
		context.NC("à " .. userdata.numberformat(userdata.invoice.perhour) .. "\\," .. userdata.invoice.currency1 .. "/h")
	else
		context.NC()
	end
	context.NC(userdata.numberformat(hours * userdata.invoice.perhour) .. "\\," .. userdata.invoice.currency1)
	context.NC()
	context.NR()
end

function userdata.InvoiceAmountLine(text, amount)
	context.NC(text)
	context.NC()
	context.NC()
	context.NC(userdata.numberformat(amount) .. "\\," .. userdata.invoice.currency1)
	context.NC()
	context.NR()
end

function userdata.InvoiceTextLine(text)
	context.NC(text)
	context.NC()
	context.NC()
	context.NC()
	context.NC()
	context.NR()
end

function userdata.InvoiceSumLine(text, printperhour)
	context.HL()
	context.NC("\\bf " .. text)
	if userdata.invoice.hours > 0 then
		context.NC(userdata.numberformat(userdata.invoice.hours) .. "\\,h")
	else
		context.NC()
	end
	if printperhour then
		context.NC("à " .. userdata.numberformat(userdata.invoice.perhour) .. "\\," .. userdata.invoice.currency1 .. "/h")
	else
		context.NC()
	end
	context.NC("\\bf " .. userdata.numberformat(userdata.invoice.amount) .. "\\," .. userdata.invoice.currency1)
	context.NC()
	context.NR()
	if userdata.invoice.currency1 ~= userdata.invoice.currency2 then
		context.NC()
		context.NC()
		context.NC()
		context.NC("(" .. userdata.numberformat(userdata.invoice.amount * userdata.invoice.exchangerate) .. "\\," .. userdata.invoice.currency2 .. ")")
		context.NC()
		context.NR()
	end
end

function userdata.Invoice()
	local amountsum, hoursum = 0,0
	local printperhour
	printperhour = (userdata.invoice.amount ~= (userdata.invoice.hours * userdata.invoice.perhour))
	context.starttabulate({"|lw(8cm)|rg(,)w(2cm)|rg(,)w(2cm)|rg(,)w(3cm)|"})
	for no, item in ipairs(userdata.invoice.items) do
		if item.hours ~= 0 and item.amount == 0 then
			userdata.InvoiceTimeLine(item.text, item.hours, printperhour)
			hoursum = hoursum + item.hours
			amountsum = amountsum + item.hours * userdata.invoice.perhour
		elseif item.amount ~= 0 and item.hours == 0 then
			userdata.InvoiceAmountLine(item.text, item.amount)
			amountsum = amountsum + item.amount
		else
			userdata.InvoiceTextLine(item.text)
		end
	end
	printperhour = (hoursum > 0) and (amountsum == (hoursum * userdata.invoice.perhour))
	--userdata.invoice.hours = hoursum
	--userdata.invoice.amount = amountsum
	userdata.InvoiceSumLine("gesamt", printperhour)
	context.stoptabulate()
end

\stopluacode

Letter setup

File invoicesetup.tex

\mainlanguage[de]
\usemodule[letter]

\setuplanguage [de] [date={year, –, mm, –, dd}] % ISO 8601 date

\usemodule[simplefonts]
\setmainfont[Gentium Basic][expansion=quality,protrusion=quality]
\setsansfont[Delicious][scale=0.9]
\setupbodyfont[rm,9.5pt]
\setupinterlinespace[3.0ex] % default: 2.8ex

\setuptabulate[distance=0pt]

\def\MyCompany{{\it MyCompany}}
\useexternalfigure[logo][logo-head]
\useexternalfigure[schriftzug][logo-type]

\setupletter[
	% Sender address in envelope window
	backaddress={\MyCompany\ · My Name · Samplestr.\,11 · CH-1234 Village}
]

% Use the sender address line, but not the default subject line
\setupletterstyle[backaddress=yes,reference=no]

% We put our logo in the head
\setupletterstyle[head,nexthead][
	hoffset=128mm,
	voffset=0pt,
	alternative=fiee,
]

% Define logo for the first page
\defineletterelement[head][fiee]{%
\framed[background=logo,height=35mm,frame=off]{\vbox{
\par\blank[15mm]\par
\externalfigure[schriftzug]}}

}

% Other logo for subsequent (right) pages
\defineletterelement[nexthead][fiee]{%
\externalfigure[logo][height=2cm, width=6cm]}

\setupletterstyle[nexthead][
	state=right,
]

% We don't really use this
\copyletterelement[location][fiee][reference][d]

\setupletterstyle[location][
	hoffset=128mm,
	voffset=3cm,
	alternative=fiee,
	list={name,street,city,phone,email,web,skype}
]

\setupletter[
	name={My Name},
	street={Samplestrasse 11},
	city={CH-1234 Village},
	phone={+41 11 23\,45\,67},
	mobile={+41 00 99\,88\,88\,88},
	email={me@mycompany.com},
	web={www.example.com},
	skype={example}
]

% center around the :
\startsetups letter:location
\tfx\it
\starttabulate[|rw(39mm)|p|]
	\NC name \NC\lettervalue{name} \NC\NR
	\NC location \NC\lettervalue{street}\\\lettervalue{city}\NC\NR
	\NC phone \NC\lettervalue{phone}\\\lettervalue{mobile} \NC\NR
	\NC internet \NC\lettervalue{email}\\\lettervalue{web} \NC\NR
	\NC skype \NC\lettervalue{skype} \NC\NR
\stoptabulate
\stopsetups


\setupletterstyle[address][alternative=fiee]
% Our own recipient setup without too much space before the address
\defineletterelement[address][fiee]{
\setupinterlinespace
\blank
\lettervalue{toname}\\
\lettervalue{toaddress}
}

% Subject and date on the same line, date below logo
\startsetups letter:subject
\bTABLE[frame=off]
	\bTR
		\bTD[width=\dimexpr169mm-\backspace\relax]\lettervalue{subject}\eTD
		\bTD{\tf\lettervalue{date}}\eTD % auto date
		%\bTD{\tf 2011-11-14}\eTD % manual date
	\eTR
\eTABLE
\stopsetups

% account information at the foot, below the logo
\defineletterelement[foot][fiee]{
\tfx\it
%	\starttabulate[|rw(5em)a{{\tf~:}}|p|]
	\starttabulate[|rw(39mm)|p|]
		\NC account \NC \NC\NR
		\NC Swiss \NC 12-34567-89 \NC\NR
		\NC IBAN \NC CH12\,1234\,5678\,0000\,1234\,X \NC\NR
		\NC German \NC Kto. 111\,222\,333\\Fraudbank, BLZ 110\,110\,10 \NC\NR
		\NC IBAN \NC DE11\,1234\,0000\,1234\,9999\,12 \NC\NR
	\stoptabulate
	\crlf
}

\setupletterstyle[foot][
	preset=leftbottom,
	hoffset=130mm,
	voffset=3.4cm,
	alternative=fiee,
]

% switch off reference line
\setupletterstyle[reference][alternative=none]

% Move the text a bit up
\setupletterstyle[firstpage][
	topspace=10cm
]

% Adjust text start on subsequent pages
\setupletterstyle[secondpage][
	topspace=3cm,
]

% Move marks to the paper rim (won't print on most printers)
\setupletterstyle[topmark,botmark,cutmark][
	hoffset=-2mm
]

Invoice

File invoice.tex

\input invoicesetup.tex
\input invoicefunctions.tex

\setupletter[
	% Recipient
	%toname={Pragma ADE\\Mr.\\,Hans Hagen},toaddress={Ridderstraat 27\\8061GH Hasselt NL},
	% here I keep commented all of my few customers
]
\starttext

\startletter[subject={Invoice No.\,99/2011}]
%\startletter[subject={Reminder on invoice No.\,1/2011}]

Special services in December 2011:

{
\setuptabulate[distance=.25em]
\startluacode
userdata.invoice.perhour = 111
--userdata.invoice.currency1 = "SFr"

userdata.RegisterTextItem("Some project description")

userdata.RegisterAmountItem("Data handling, flat-rate", 500)

userdata.RegisterTimeItem("Design of issue 1 of Some magazine", 42.5)

userdata.Invoice()
\stopluacode
}

Due on 1.\,1.\2012. Earlier is nicer.

\blank[2*big]

\MyCompany\ bedankt sich für den Auftrag.
\blank[2*big]
Mit freundlichen Grüßen,

\externalfigure[signature]

My Name

\stopletter

\stoptext