🧾
週N日稼働の最終営業日に「請求書を送る」というリマインドが欲しい
TL;DR
このスクリプトを一日一回、スケジュール実行しましょう。月末の営業日に Slack 通知が来るようになります。
要件
- 例えば、フリーランスで週3日の案件を受けているとします
- 月火水の稼働
- 毎月、最終営業日に「請求書を送る」というリマインドが欲しい
- 祝日と重なった場合は、その前日が最終営業日になる
- 月火水の稼働であっても、暦の周期の都合で「最終水曜日」が最終営業日とは限らない
最終水曜日が祝日と重なる例
「昭和の日」と重なる関係上、前日の 4/28(火)が最終営業日となる
暦の周期の都合で最終営業日が火曜日になる例
5/31(火)が最終営業日
事の発端
Slack の /remind
は「月末」を指定できない
iPhone の標準アプリ「リマインダー」であれば「最終水曜日」に通知を受け取ることは可能
が、「最終水曜日」の通知では不完全です。
- 最終日が祝日と重なった場合、最終営業日はその前日となる
- 月火水の稼働であっても、暦の周期の都合で「最終水曜日」が最終営業日とは限らない
というわけで、自分でスクリプトを書いて自動化しました。
Invoice Reminder
ソースコードを GitHub に公開しています。ご自由に fork して書き換えて使ってください。
解説
すべてのプログラムをフィルタとして設計したいというか、リスト操作だけで実装したいですよね。
- 月初から月末までのうち、月火水以外の曜日を除外する
- 祝日を除外する
- この処理のために holiday_jp という gem を使用しました
BUSINESS_DAYS = {
Sunday: false,
Monday: true,
Tuesday: true,
Wednesday: true,
Thursday: false,
Friday: false,
Saturday: false,
}
def business_days_of_month(today: Date.today)
business_days = BUSINESS_DAYS.select { _2 }.keys
(today.beginning_of_month..today.end_of_month).select {
_1.strftime("%A").to_sym.in? business_days
}.reject {
HolidayJp.holiday? _1
}
end
その日が最終営業日の場合は Slack に通知します。
if business_days_of_month.last.today?
notifier = Slack::Notifier.new ENV["INVOICE_REMINDER_WEBHOOK_URL"]
notifier.ping "今日は最終営業日です。請求書を提出しましょう!"
end
today
を 外部入力として、引数で渡して やればテストも簡単です。
RSpec.describe do
subject { business_days_of_month(today: today).last }
context "最終営業日が水曜日になる場合" do
let(:today) { Date.new(2022, 7, 1) }
it { is_expected.to eq Date.new(2022, 7, 27) }
end
context "最終営業日が水曜日ではない場合" do
let(:today) { Date.new(2022, 5, 1) }
it { is_expected.to eq Date.new(2022, 5, 31) }
end
context "最終水曜日が祝日と重なる場合" do
let(:today) { Date.new(2020, 4, 1) }
it { is_expected.to eq Date.new(2020, 4, 28) }
end
end
月末ではなく月初に通知したい場合
2行書き換えるだけで簡単に月初に変更できます。下記のブランチをマージしてください。
スケジュール実行の設定
スケジュール実行の実現方法は、本来なら運用の手間を減らすために EventBridge で AWS Lambda を定時実行する とかの方がマネージドサービスに頼ることができて良いと思うんですが、今回は、サーバー代を完全に無料にしたかったのと、個人的に OCI の Always Free インスタンス を試したかったので、普通に Linux サーバーを立てて、昔ながらの crontab でスケジュール実行しました。ランチに行く前に請求書の送付を済ませたいので午前 11:45 に設定してあります。
$ crontab -l
MAILTO=""
45 11 * * * /usr/bin/ruby /home/ubuntu/invoice_reminder/main.rb
まとめ
- Slack の
/remind
も iPhone の「リマインダー」も最終営業日を指定できない - holiday_jp べんり
- OCI の Always Free インスタンスべんり
- 請求書の送付はランチに行く前に済ませるのが吉
Discussion