Add everything
This commit is contained in:
commit
63d7293fc5
14 changed files with 221 additions and 0 deletions
21
README.md
Normal file
21
README.md
Normal file
|
@ -0,0 +1,21 @@
|
|||
make sure taskdb is actual and everything relevant is tagged
|
||||
|
||||
cp customer-name/prev-month-date customer-name/new-month-date
|
||||
cd customer-name/new-month-date
|
||||
make clean
|
||||
make timesheet.txt
|
||||
cat timesheet.txt
|
||||
|
||||
create payment link with data from timesheet.txt
|
||||
edit pay.url
|
||||
edit env.sh.inc
|
||||
edit email-template/*
|
||||
|
||||
make email-draft.txt
|
||||
review it
|
||||
|
||||
edit invoice-top.html
|
||||
make invoice.pdf
|
||||
review it
|
||||
|
||||
make email.txt
|
74
invoice-system-common/Makefile
Normal file
74
invoice-system-common/Makefile
Normal file
|
@ -0,0 +1,74 @@
|
|||
SHELL := /bin/bash
|
||||
CUSTOMER := $(shell basename $(shell dirname $(shell pwd) ) )
|
||||
INVOICE_DATE := $(shell basename $(shell pwd) )
|
||||
|
||||
#.PHONY: timesheet.txt timesheet.html invoice.html invoice.pdf
|
||||
|
||||
default: invoice.pdf
|
||||
|
||||
clean:
|
||||
rm -fv amount.sh.inc pay.url invoice-top.html billable.sql complete.sql timesheet.txt timesheet.html email.txt email-draft.txt invoice.html invoice.pdf
|
||||
|
||||
amount.sh.inc: amount.sql billable.sql
|
||||
cat billable.sql amount.sql | ssh taskdb psql --tuples-only --quiet --no-align > $@
|
||||
cat $@
|
||||
|
||||
pay.url: amount.sh.inc timesheet.txt
|
||||
# Double-check timesheet.txt
|
||||
# Duplicate product from previous month
|
||||
# Change amount and month in item description
|
||||
# Create payment link
|
||||
# When done, put the link into pay.url
|
||||
false
|
||||
|
||||
invoice-top.html: invoice-top.html.in pay.url amount.sh.inc
|
||||
#false # render
|
||||
export CUSTOMER=$(CUSTOMER) INVOICE_DATE=$(INVOICE_DATE); source <(cat env.sh.inc amount.sh.inc | sed -e 's/^.*=/export &/') && envsubst < $< > $@
|
||||
|
||||
amount.sql: amount.sql.in env.sh.inc
|
||||
export CUSTOMER=$(CUSTOMER) INVOICE_DATE=$(INVOICE_DATE); source <(cat env.sh.inc | sed -e 's/^.*=/export &/') && envsubst < $< > $@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
billable.sql: billable.sql.in env.sh.inc
|
||||
export CUSTOMER=$(CUSTOMER) INVOICE_DATE=$(INVOICE_DATE); source <(cat env.sh.inc | sed -e 's/^.*=/export &/') && envsubst < $< > $@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
complete.sql: complete.sql.in billable.sql env.sh.inc
|
||||
cat billable.sql > $@.tmp
|
||||
export CUSTOMER=$(CUSTOMER) INVOICE_DATE=$(INVOICE_DATE); source <(cat env.sh.inc | sed -e 's/^.*=/export &/') && envsubst < $< >> $@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
timesheet.txt: complete.sql
|
||||
ssh taskdb psql --quiet < complete.sql > $@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
timesheet.html: complete.sql
|
||||
ssh taskdb psql -H --quiet < complete.sql > $@.tmp
|
||||
# avoid overflow on the right in PDF:
|
||||
sed -i -e 's/<table border="1">/<table border="1" style="font-size: 70%;">/g' $@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
upload:
|
||||
rsync -rtv $(PWD) webserver:/var/www/zorg.example/html/tmp/$(CUSTOMER)
|
||||
echo https://zorg.example/tmp/$(CUSTOMER)/$(shell basename $(shell pwd))/timesheet.txt
|
||||
echo https://zorg.example/tmp/$(CUSTOMER)/$(shell basename $(shell pwd))/invoide.html
|
||||
echo https://zorg.example/tmp/$(CUSTOMER)/$(shell basename $(shell pwd))/invoice.pdf
|
||||
|
||||
email-draft.txt: pay.url amount.sh.inc generate-email invoice.pdf
|
||||
./generate-email | tee $@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
email.txt: email-draft.txt invoice.pdf
|
||||
mutt -H email-draft.txt -a invoice.pdf
|
||||
mv email-draft.txt email.txt
|
||||
|
||||
invoice.html: invoice-top.html timesheet.html
|
||||
cat invoice-top.html > $@.tmp
|
||||
cat timesheet.html >> $@.tmp
|
||||
echo '<br>Thank you! <body> </html>' >> $@.tmp
|
||||
mv $@.tmp $@
|
||||
|
||||
invoice.pdf: invoice.html
|
||||
weasyprint invoice.html invoice.pdf
|
||||
|
||||
echo Now do '"make email-draft.txt"', and then '"make email.txt"'
|
9
invoice-system-common/amount.sql.in
Normal file
9
invoice-system-common/amount.sql.in
Normal file
|
@ -0,0 +1,9 @@
|
|||
\pset footer off
|
||||
|
||||
SELECT
|
||||
'HOURS=' || ROUND(SUM(duration)/3600.0, 2)::text
|
||||
FROM billable
|
||||
UNION
|
||||
SELECT
|
||||
'AMOUNT=' || (ROUND(SUM(duration)/3600.0, 2) * ${RATE})::text
|
||||
FROM billable
|
12
invoice-system-common/billable.sql.in
Normal file
12
invoice-system-common/billable.sql.in
Normal file
|
@ -0,0 +1,12 @@
|
|||
CREATE TEMPORARY TABLE billable
|
||||
AS
|
||||
SELECT * FROM depgraph(alias('$CUSTOMER'))
|
||||
WHERE
|
||||
NOT COALESCE(tags, '') ~ 'nonbillable'
|
||||
AND scheduled >= '$PERIOD_START'
|
||||
AND scheduled < '$PERIOD_NEXT_START'
|
||||
AND scheduled < CURRENT_TIMESTAMP -- CURRENT_DATE
|
||||
AND COALESCE(duration, 0) > 0
|
||||
EXCEPT
|
||||
SELECT * FROM depgraph(alias('$CUSTOMER-nonbillable'))
|
||||
;
|
21
invoice-system-common/complete.sql.in
Normal file
21
invoice-system-common/complete.sql.in
Normal file
|
@ -0,0 +1,21 @@
|
|||
\pset footer off
|
||||
|
||||
SELECT
|
||||
scheduled AS date,
|
||||
ROUND(duration/3600.0, 2) AS hours,
|
||||
regexp_replace(description, '^${CUSTOMER}: ', '', 'i') AS description
|
||||
FROM billable
|
||||
ORDER BY scheduled
|
||||
;
|
||||
SELECT
|
||||
date_trunc('week', scheduled)::date AS week,
|
||||
ROUND(SUM(duration)/3600.0, 2) AS hours_in_week
|
||||
FROM billable
|
||||
GROUP BY week
|
||||
ORDER BY week
|
||||
;
|
||||
SELECT
|
||||
ROUND(SUM(duration)/3600.0, 2) AS "hours total",
|
||||
${RATE} AS "hourly rate, ${RATE_CURRENCY}",
|
||||
ROUND(SUM(duration)/3600.0, 2) * ${RATE} AS "amount billed"
|
||||
FROM billable
|
22
invoice-system-common/generate-email
Executable file
22
invoice-system-common/generate-email
Executable file
|
@ -0,0 +1,22 @@
|
|||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
|
||||
source env.sh.inc
|
||||
|
||||
if ! cat email-template/headers.txt; then
|
||||
echo "To: $RECIPIENTS"
|
||||
echo "Cc: $RECIPIENTS_CC"
|
||||
fi
|
||||
echo "Subject: Invoice for $COVERED_PERIOD_STR"
|
||||
echo # end of headers, start of body
|
||||
|
||||
cat << EOF
|
||||
$GREETING
|
||||
|
||||
Please see the timesheet and invoice attached.
|
||||
|
||||
The payment link:
|
||||
$(cat pay.url)
|
||||
|
||||
Thanks!
|
||||
EOF
|
35
invoice-system-common/invoice-top.html.in
Normal file
35
invoice-system-common/invoice-top.html.in
Normal file
|
@ -0,0 +1,35 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<!-- <body style="width: 210mm;"> -->
|
||||
<body>
|
||||
<h1>Invoice</h1>
|
||||
<h2>Jean-Baptiste Emanuel Zorg</h2>
|
||||
<table style="width: 100%;">
|
||||
<tr>
|
||||
<td style="vertical-align: top;">
|
||||
Invoice number: $INVOICE_ID
|
||||
<br>Date of issue: $ISSUED_DATE
|
||||
<br>Date due: $DUE_DATE
|
||||
<br>Jean-Baptiste Emanuel Zorg
|
||||
<br><a href="mailto:customer-support@zorg.example">customer-support@zorg.example</a>
|
||||
<br>
|
||||
</td>
|
||||
|
||||
<td style="vertical-align: top;">
|
||||
Bill to:
|
||||
$BILL_TO
|
||||
</td>
|
||||
</tr>
|
||||
<table>
|
||||
<br>
|
||||
|
||||
<h2>
|
||||
$CURRENCY_SYMBOL$AMOUNT due $DUE_DATE
|
||||
<br>
|
||||
<a href="$PAY_URL">Pay online</a>
|
||||
</h2>
|
||||
|
||||
<br>Software development work for $PROJECT in $COVERED_PERIOD_STR, $HOURS hr @ $RATE $CURRENCY/hr
|
||||
|
||||
<br>Amount: $CURRENCY_SYMBOL$AMOUNT
|
1
ultimate-evil/2024-10-01/Makefile
Symbolic link
1
ultimate-evil/2024-10-01/Makefile
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../invoice-system-common/Makefile
|
1
ultimate-evil/2024-10-01/amount.sql.in
Symbolic link
1
ultimate-evil/2024-10-01/amount.sql.in
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../invoice-system-common/amount.sql.in
|
1
ultimate-evil/2024-10-01/billable.sql.in
Symbolic link
1
ultimate-evil/2024-10-01/billable.sql.in
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../invoice-system-common/billable.sql.in
|
1
ultimate-evil/2024-10-01/complete.sql.in
Symbolic link
1
ultimate-evil/2024-10-01/complete.sql.in
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../invoice-system-common/complete.sql.in
|
21
ultimate-evil/2024-10-01/env.sh.inc
Normal file
21
ultimate-evil/2024-10-01/env.sh.inc
Normal file
|
@ -0,0 +1,21 @@
|
|||
GREETING="Hi Mr. Shadow!"
|
||||
RECIPIENTS="Mr. Shadow <shadow@ultimate-evil.example>, accounting@corp.ultimate-evil.example, evil@example.com"
|
||||
RECIPIENTS_CC="mail@zorg.example" # recommended to CC to your other mailbox for archival purposes
|
||||
PROJECT="Peace on Earth"
|
||||
RATE="1000000"
|
||||
RATE_CURRENCY="USD"
|
||||
CURRENCY_SYMBOL="$"
|
||||
|
||||
INVOICE_ID="ZG-UE-20241001"
|
||||
COVERED_PERIOD_STR="September 2024"
|
||||
PERIOD_START='2024-09-01'
|
||||
PERIOD_NEXT_START='2024-10-01'
|
||||
ISSUED_DATE='October 1, 2024'
|
||||
DUE_DATE='November 1, 2024'
|
||||
PAY_URL=$(cat pay.url)
|
||||
|
||||
BILL_TO="
|
||||
<br>Ultimate Evil
|
||||
<br>Mr. Shadow
|
||||
<br>shadow@ultimate-evil.example
|
||||
"
|
1
ultimate-evil/2024-10-01/generate-email
Symbolic link
1
ultimate-evil/2024-10-01/generate-email
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../invoice-system-common/generate-email
|
1
ultimate-evil/2024-10-01/invoice-top.html.in
Symbolic link
1
ultimate-evil/2024-10-01/invoice-top.html.in
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../invoice-system-common/invoice-top.html.in
|
Loading…
Reference in a new issue