Compare commits

...

5 Commits

Author SHA1 Message Date
d9fbcc0b98 add $ 2026-02-02 19:24:45 -07:00
6a20f179af make the program installable 2026-01-22 21:17:24 -07:00
ef80b03029 Merge pull request 'complex-bill' (#1) from complex-bill into master
Reviewed-on: #1
2026-01-23 01:51:18 +00:00
23d8ce3910 1 and 2 column pdfs work 2026-01-22 18:18:08 -07:00
4d1342782d testing 2026-01-22 16:59:07 -07:00
8 changed files with 168 additions and 69 deletions

1
.gitignore vendored
View File

@@ -1,3 +1,4 @@
*.bak
*.pdf
last_invoice_number
*.csv

View File

@@ -7,34 +7,35 @@
.PH ''''
\# Centered block
.DS C
.HU "Your Bill"
.HU "${COMPANY}'s Bill"
.DE
\# Contact info
.TS
nospaces center tab(;);
LR.
Cooies Unlimited;(123) 456-7890
123 Sesame St.;cookie@example.com
Dumpster 1;\*[DT]
Nicevile FL;Invoice ID #${INVOICE_NUM}
${COMPANY_NAME};$PHONE
${ADDR_LN_1};${EMAIL}
${ADDR_LN_2};\*[DT]
${ADDR_LN_3};Invoice ID #${INVOICE_NUM}
.TE
\# Billing info
.TS
nospaces center tab(;);
CbSS
CiCi|Ci
RN|N.
${COMPANY}
Work Performed
Job;Hours;Cost
_
${BODY}
${HRS_BODY}
_
.T&
RbN|Nb.
${TOTAL}
Total;${HRS_TOTAL}
.TE
.DS C
.R
.DE
.PP
Hours were charged at $${RATE}/hr. If you have any questions please reach out at any of the provided contacts above.
Thank you for your business!

62
2col.template.mm Normal file
View File

@@ -0,0 +1,62 @@
\# Make headers bold
.ds HF 3 3
\# Make lvl 1 headers 20pt, lvl 2 18pt
.ds HP 20 18
.S 12
\# Disable page header
.PH ''''
\# Centered block
.DS C
.HU "${COMPANY}'s Bill"
.DE
\# Contact info
.TS
nospaces center tab(;);
LR.
${COMPANY_NAME};$PHONE
${ADDR_LN_1};${EMAIL}
${ADDR_LN_2};\*[DT]
${ADDR_LN_3};Invoice ID #${INVOICE_NUM}
.TE
.2C
.TS
nospaces center tab(;);
CbSS
CiCi|Ci
RN|N.
Work Performed
Job;Hours;Cost
_
${HRS_BODY}
_
.T&
RiNi|Ni.
Sub-Total;${HRS_TOTAL}
.TE
.NCOL
.TS
nospaces center tab(;);
CbS
Ci|Ci
R|N.
Other
Item;Cost
_
${ITEM_BODY}
_
.T&
Ri|Ni.
Sub-Total;$${ITEM_TOTAL}
.TE
.1C 1
.DS C
.PP
.B
Total: $${TOTAL}
.R
.DE
.PP
Hours were charged at $${RATE}/hr. If you have any questions please reach out at any of the provided contacts above.
Thank you for your business!

18
Makefile Normal file
View File

@@ -0,0 +1,18 @@
support_files := ${XDG_DATA_HOME}/bill-generator/
config_files:= ${XDG_CONFIG_HOME}/bill-generator/
install_loc := ~/.local/bin/
install:
mkdir -p $(support_files)
mkdir -p $(config_files)
mkdir -p $(install_loc)
cp *.mm $(support_files)
# Copy the ident file but don't overwrite one that is already there.
cp --update=none ident $(config_files)
cp gen.sh $(install_loc)/bill-gen
printf "\nInstalled!\nUpdate your identity at $(config_files)ident\n\n"
remove:
# Remove everything except the config files
rm -r $(support_files)
rm $(install_loc)bill-gen

107
gen.sh
View File

@@ -1,45 +1,22 @@
#!/bin/bash
DATA_HOME="$XDG_DATA_HOME/bill-generator"
source "$XDG_CONFIG_HOME/bill-generator/ident"
# Need to be set to the installed location
TEMPLATE_1COL="$DATA_HOME/1col.template.mm"
TEMPLATE_2COL="$DATA_HOME/2col.template.mm"
INV_FILE="$DATA_HOME/last_invoice_number"
# What you charge an hour
RATE=50
short_help() {
echo "$0 <file.csv> <Paying Company Name> [output file]"
echo "--help for help"
}
long_help() {
short_help
print_help() {
echo "$(basename $0) -1 <hrs.csv> <Paying Company Name> [output file]"
echo "$(basename $0) -2 <hrs.csv> <items.csv> <Paying Company Name> [output file]"
echo ""
echo "The csv file should be setup as:"
echo ""
echo "Job <string>, Hours <number>"
echo ""
echo "With no empty line at the end."
echo "CSV files should be <name>,<value>."
echo "CSV files should have no empty line at the end."
echo "Paying company name is any string"
echo "The output argument is optional and will by default output to invoice-<num>.pdf"
}
CSV=""
if [[ -z $1 ]]; then
short_help
exit
elif [[ $1 = "--help" ]]; then
long_help
exit
else
CSV=$1
fi
COMPANY=""
if [[ -z $2 ]]; then
short_help
exit
else
COMPANY=$2
fi
get_invoice_num() {
# Increment a global invoice number
INV_FILE="last_invoice_number"
INV_NUM=0
if [[ -f $INV_FILE ]]; then
INV_NUM=$(expr $(cat $INV_FILE) + 1)
@@ -47,24 +24,52 @@ else
INV_NUM=1
fi
echo $INV_NUM > $INV_FILE
echo $INV_NUM
}
read_hrs_csv() {
TMP=$(mktemp)
# Parse the CSV into: Label;Hrs;Cost
cat $1 | RATE=$RATE awk -F, '{ sum += $2 }; { print $1 ";" $2 ";" $2 * ENVIRON["RATE"] } END { print sum "; $" sum * ENVIRON["RATE"] }' > $TMP
echo $TMP
}
read_items_csv() {
TMP=$(mktemp)
cat $1 | awk -F, '{ sum += $2 }; { print $1 ";" $2 } END { print sum }' > $TMP
echo $TMP
}
# 3rd argument is output location (optional)
OUTPUT="invoice-${INV_NUM}.pdf"
if [[ ! -z $3 ]]; then
OUTPUT=$3
if [[ -z $1 ]]; then
print_help
exit
fi
# Parse the CSV into: Label;Hrs;Cost
TMP=$(mktemp)
cat $CSV | RATE=$RATE awk -F, '{ sum += $2 }; { print $1 ";" $2 ";" $2 * ENVIRON["RATE"] } END { print "Total" ";" sum ";" sum * ENVIRON["RATE"]}' > $TMP
export INVOICE_NUM=$(get_invoice_num)
OUTPUT="invoice-${INVOICE_NUM}.pdf"
# TOTAL = Last line
# BODY = Everything but the last line
TOTAL=$(cat $TMP | tail -n 1) \
BODY=$(cat $TMP | head -n -1) \
COMPANY=$COMPANY \
INVOICE_NUM=$INV_NUM \
RATE=$RATE \
envsubst < template.mm | groff -t -mm -T pdf > $OUTPUT
HRS_TMP=$(read_hrs_csv $2)
export HRS_TOTAL=$(cat $HRS_TMP | tail -n 1)
export HRS_BODY=$(cat $HRS_TMP | head -n -1)
rm $TMP
if [[ $1 = "-1" ]]; then
if [[ ! -z $4 ]]; then
OUTPUT=$4
fi
export COMPANY=$3
envsubst < $TEMPLATE_1COL | groff -t -mm -T pdf > $OUTPUT
elif [[ $1 = "-2" ]]; then
if [[ ! -z $5 ]]; then
OUTPUT=$5
fi
HRS_COST=$(cat $HRS_TMP | tail -n 1 | sed s/\\$//g | awk -F";" '{ print $2 }')
CONSUME_TMP=$(read_items_csv $3)
CONSUME_COST=$(cat $CONSUME_TMP | tail -n 1 | awk -F";" '{ print $2 }')
export ITEM_TOTAL=$(cat $CONSUME_TMP | tail -n 1 )
echo $ITEM_TOTAL
echo $HRS_COST
export ITEM_BODY=$(cat $CONSUME_TMP | head -n -1)
export TOTAL=$(A=$HRS_COST B=$ITEM_TOTAL awk 'BEGIN{ print ENVIRON["A"] + ENVIRON["B"] }')
export COMPANY=$4
envsubst < $TEMPLATE_2COL | groff -t -mm -T pdf > $OUTPUT
else
echo First arg should be either -1 or -2
fi

View File

8
ident Normal file
View File

@@ -0,0 +1,8 @@
#!/bin/bash
export RATE=50
export COMPANY_NAME="Cookies Unlimited, LLC"
export ADDR_LN_1="123 Sesasme St"
export ADDR_LN_2="Dumpster 1"
export ADDR_LN_3="12345, Nicevile, FL"
export PHONE="(123) 456-7890"
export EMAIL="cookie@exapmle.com"

4
items.csv Normal file
View File

@@ -0,0 +1,4 @@
Prep,2
Cooking,1.25
Event,10
Cleanup,2.5
1 Prep 2
2 Cooking 1.25
3 Event 10
4 Cleanup 2.5