From 63d7293fc504f2d65c299dbd3fa6588df7f42c10 Mon Sep 17 00:00:00 2001 From: Andriy Utkin Date: Fri, 13 Sep 2024 14:38:24 +0100 Subject: [PATCH] Add everything --- README.md | 21 ++++++ invoice-system-common/Makefile | 74 ++++++++++++++++++++ invoice-system-common/amount.sql.in | 9 +++ invoice-system-common/billable.sql.in | 12 ++++ invoice-system-common/complete.sql.in | 21 ++++++ invoice-system-common/generate-email | 22 ++++++ invoice-system-common/invoice-top.html.in | 35 +++++++++ ultimate-evil/2024-10-01/Makefile | 1 + ultimate-evil/2024-10-01/amount.sql.in | 1 + ultimate-evil/2024-10-01/billable.sql.in | 1 + ultimate-evil/2024-10-01/complete.sql.in | 1 + ultimate-evil/2024-10-01/env.sh.inc | 21 ++++++ ultimate-evil/2024-10-01/generate-email | 1 + ultimate-evil/2024-10-01/invoice-top.html.in | 1 + 14 files changed, 221 insertions(+) create mode 100644 README.md create mode 100644 invoice-system-common/Makefile create mode 100644 invoice-system-common/amount.sql.in create mode 100644 invoice-system-common/billable.sql.in create mode 100644 invoice-system-common/complete.sql.in create mode 100755 invoice-system-common/generate-email create mode 100644 invoice-system-common/invoice-top.html.in create mode 120000 ultimate-evil/2024-10-01/Makefile create mode 120000 ultimate-evil/2024-10-01/amount.sql.in create mode 120000 ultimate-evil/2024-10-01/billable.sql.in create mode 120000 ultimate-evil/2024-10-01/complete.sql.in create mode 100644 ultimate-evil/2024-10-01/env.sh.inc create mode 120000 ultimate-evil/2024-10-01/generate-email create mode 120000 ultimate-evil/2024-10-01/invoice-top.html.in diff --git a/README.md b/README.md new file mode 100644 index 0000000..8636135 --- /dev/null +++ b/README.md @@ -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 diff --git a/invoice-system-common/Makefile b/invoice-system-common/Makefile new file mode 100644 index 0000000..a0b9933 --- /dev/null +++ b/invoice-system-common/Makefile @@ -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//
/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 '
Thank you! ' >> $@.tmp + mv $@.tmp $@ + +invoice.pdf: invoice.html + weasyprint invoice.html invoice.pdf + + echo Now do '"make email-draft.txt"', and then '"make email.txt"' diff --git a/invoice-system-common/amount.sql.in b/invoice-system-common/amount.sql.in new file mode 100644 index 0000000..8063407 --- /dev/null +++ b/invoice-system-common/amount.sql.in @@ -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 diff --git a/invoice-system-common/billable.sql.in b/invoice-system-common/billable.sql.in new file mode 100644 index 0000000..69f8882 --- /dev/null +++ b/invoice-system-common/billable.sql.in @@ -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')) +; diff --git a/invoice-system-common/complete.sql.in b/invoice-system-common/complete.sql.in new file mode 100644 index 0000000..ab2d8ec --- /dev/null +++ b/invoice-system-common/complete.sql.in @@ -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 diff --git a/invoice-system-common/generate-email b/invoice-system-common/generate-email new file mode 100755 index 0000000..f399a32 --- /dev/null +++ b/invoice-system-common/generate-email @@ -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 diff --git a/invoice-system-common/invoice-top.html.in b/invoice-system-common/invoice-top.html.in new file mode 100644 index 0000000..81e38e1 --- /dev/null +++ b/invoice-system-common/invoice-top.html.in @@ -0,0 +1,35 @@ + + + + + +

Invoice

+

Jean-Baptiste Emanuel Zorg

+
+ + + + + +
+Invoice number: $INVOICE_ID +
Date of issue: $ISSUED_DATE +
Date due: $DUE_DATE +
Jean-Baptiste Emanuel Zorg +
customer-support@zorg.example +
+
+Bill to: +$BILL_TO +
+
+ +

+$CURRENCY_SYMBOL$AMOUNT due $DUE_DATE +
+Pay online +

+ +
Software development work for $PROJECT in $COVERED_PERIOD_STR, $HOURS hr @ $RATE $CURRENCY/hr + +
Amount: $CURRENCY_SYMBOL$AMOUNT diff --git a/ultimate-evil/2024-10-01/Makefile b/ultimate-evil/2024-10-01/Makefile new file mode 120000 index 0000000..e8cf57d --- /dev/null +++ b/ultimate-evil/2024-10-01/Makefile @@ -0,0 +1 @@ +../../invoice-system-common/Makefile \ No newline at end of file diff --git a/ultimate-evil/2024-10-01/amount.sql.in b/ultimate-evil/2024-10-01/amount.sql.in new file mode 120000 index 0000000..0998146 --- /dev/null +++ b/ultimate-evil/2024-10-01/amount.sql.in @@ -0,0 +1 @@ +../../invoice-system-common/amount.sql.in \ No newline at end of file diff --git a/ultimate-evil/2024-10-01/billable.sql.in b/ultimate-evil/2024-10-01/billable.sql.in new file mode 120000 index 0000000..6379e4f --- /dev/null +++ b/ultimate-evil/2024-10-01/billable.sql.in @@ -0,0 +1 @@ +../../invoice-system-common/billable.sql.in \ No newline at end of file diff --git a/ultimate-evil/2024-10-01/complete.sql.in b/ultimate-evil/2024-10-01/complete.sql.in new file mode 120000 index 0000000..1ded4ff --- /dev/null +++ b/ultimate-evil/2024-10-01/complete.sql.in @@ -0,0 +1 @@ +../../invoice-system-common/complete.sql.in \ No newline at end of file diff --git a/ultimate-evil/2024-10-01/env.sh.inc b/ultimate-evil/2024-10-01/env.sh.inc new file mode 100644 index 0000000..49912f9 --- /dev/null +++ b/ultimate-evil/2024-10-01/env.sh.inc @@ -0,0 +1,21 @@ +GREETING="Hi Mr. Shadow!" +RECIPIENTS="Mr. Shadow , 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=" +
Ultimate Evil +
Mr. Shadow +
shadow@ultimate-evil.example +" diff --git a/ultimate-evil/2024-10-01/generate-email b/ultimate-evil/2024-10-01/generate-email new file mode 120000 index 0000000..9b35b69 --- /dev/null +++ b/ultimate-evil/2024-10-01/generate-email @@ -0,0 +1 @@ +../../invoice-system-common/generate-email \ No newline at end of file diff --git a/ultimate-evil/2024-10-01/invoice-top.html.in b/ultimate-evil/2024-10-01/invoice-top.html.in new file mode 120000 index 0000000..3aabbd4 --- /dev/null +++ b/ultimate-evil/2024-10-01/invoice-top.html.in @@ -0,0 +1 @@ +../../invoice-system-common/invoice-top.html.in \ No newline at end of file