クレジットの決済結果をエクセルに反映
投稿:2018-10-31
毎月出てくるクレジットの決済結果をエクセルの家計簿にコピーするのが手作業なので面倒くさくなってきた。
せっかくだからPerlでアップデータを作り自動化しよう。
- カード会社はライフカード
- 決済結果をサイトから手動ダウンロード(自動ログイン/ダウンロードはクラックを疑われる可能性あり)
- ファイル形式は、なんちゃってCSV(行毎にカラム数が異なる)
- 家計簿はエクセルで、科目設定シート、1~12月の各シート、集計シート、他
- 決済結果と家計簿をデスクトップに置く
- アップデータはGUI(Tkx)を使う
- エクセル操作はOLEを使う
こんな感じです。
なんちゃってCSVファイルを読み込むと、決済件数と総額がメッセージで報告されます。
それから家計簿に追加すると決済日の月のシートの末尾に追加します。
クレジット会社のサイトから決済結果をオンラインで入手できるAPIとか公開されないかなあ。
そのうち手動ダウンロードが面倒くさくなる(笑)。
#!/usr/bin/env perl -w use utf8; use strict; use warnings; use open IO => ":utf8"; use Data::Dumper; use DateTime; use Encode::Argv; use Encode::Locale; use Spreadsheet::WriteExcel; use Tkx; use Win32::OLE; use Win32::OLE::Const; use Win32::OLE "CP_UTF8"; binmode STDIN, ":encoding(console_in)"; binmode STDOUT, ":encoding(console_out)"; $| = 1; $Win32::OLE::CP = CP_UTF8; # リストボックス内の文字を等幅にするため一律でフォントを指定 Tkx::option_add("*Listbox.font", "System"); my $userprofile = $ENV{USERPROFILE} =~ s#\\#/#gr; my $desktop_dir = "$userprofile/Desktop/"; my $now_dt = DateTime->now(time_zone => "local"); my $default_csv = $now_dt->strftime("lifecard_meisai_%Y%m.csv"); my $mw = Tkx::widget->new("."); menu_build($mw, [ [ "ファイル", "F", [ [ "決済データを読み込む", "O", \&file_open, ], [ "家計簿に追加", "A", \&file_append, ], [ "終了", "X", \&wm_delete_window, ], ], ], ]); $mw->g_wm_title("クレジット決済アップデータ"); $mw->g_wm_minsize(300, 0); $mw->g_wm_protocol(WM_DELETE_WINDOW => \&wm_delete_window); $mw->g_wm_resizable(0, 0); my @meisai; Tkx::MainLoop(); exit; sub my_msg($$) { my ($msg, $parent) = @_; $parent = $parent // $mw; Tkx::tk___messageBox( -parent => $parent, -title => "メッセージ", -type => "ok", -icon => "info", -message => "$msg", ); } sub file_open { my $csv_file = Tkx::tk___getOpenFile( -defaultextension => "*.csv", -filetypes => [ ["CSVファイル", [".csv",]], ["すべてのファイル", [".*",]], ], -initialdir => $desktop_dir, -initialfile => $default_csv, -title => "クレジット決済CSVファイルを選択してください", ); if ($csv_file) { load_csv($csv_file); } } sub load_csv { my ($csv_file) = @_; if (open my $csv_fh, "<:encoding(cp932)", $csv_file) { my $meisai_in = 0; my @line; my @header; while (<$csv_fh>) { chomp; if (!$meisai_in && /^明細No\.,/) { $meisai_in = 1; @header = split /,/; } elsif ($meisai_in && /^$/) { undef $meisai_in; last; } elsif ($meisai_in) { push @line, $_; } } close $csv_fh; my %field_idx = ( date => "利用日", shop => "利用先", money => "利用金額", ); for (my $column = 0; $column < @header; $column++) { for (keys %field_idx) { if ($header[$column] eq $field_idx{$_}) { $field_idx{$_} = $column; } } } undef @meisai; for (@line) { my @field = split /,/; push @meisai, { date => $field[$field_idx{date}], shop => $field[$field_idx{shop}], money => $field[$field_idx{money}], }; } @meisai = sort {$a->{date} cmp $b->{date}} @meisai; my $total = 0; $total += $_->{money} for @meisai; my_msg "@{[scalar @meisai]}件、${total}円", $mw; } } sub file_append { my $excel = Win32::OLE->new("Excel.Application", "Quit"); my $wb = $excel->Workbooks->Open(Encode::encode locale => "${desktop_dir}家計簿.xlsx"); my @month_name = qw(1 2 3 4 5 6 7 8 9 10 11 12); for (@meisai) { $_->{date} =~ m#/(\d\d)/#; my $ws = $wb->Worksheets($month_name[$1 - 1] . "月"); my $row; for ($row = 5; $row <= 104; $row++) { my $v = $ws->Cells($row, 3)->{Value}; last if !defined $v; } if ($row <= 104) { $ws->Cells($row, 3)->{Value} = $_->{date}; $ws->Cells($row, 4)->{Value} = $_->{shop}; $ws->Cells($row, 5)->{Value} = $_->{money}; } } $wb->Save(); $wb->Close(); $excel->Quit(); } sub wm_delete_window { $mw->g_destroy; } sub menu_build { my ($mainwindow, $tree) = @_; my $top = $mainwindow->new_menu; for (@$tree) { my $second = $top->new_menu( -tearoff => 0, ); $top->add_cascade( -label => "${$_}[0](${$_}[1])", -underline => 1 + length ${$_}[0], -menu => $second, ); for (@{${$_}[2]}) { my $label = ${$_}[0]; my $label_after = ""; my $underline = 1 + length ${$_}[0]; if ($label =~ /\.\.\.$/) { $label =~ s/\.\.\.$//; $label_after = "..."; $underline -= 3; } $label .= "(${$_}[1])$label_after"; if ("CODE" eq ref ${$_}[2]) { $second->add_command( -label => $label, -underline => $underline, -command => ${$_}[2], ); } elsif ("SCALAR" eq ref ${$_}[2]) { $second->add_checkbutton( -label => $label, -underline => $underline, -variable => ${$_}[2], -offvalue => 0, -onvalue => 1, ); } } } $mainwindow->configure(-menu => $top); }