クレジットの決済結果をエクセルに反映
投稿:2018-10-31
毎月出てくるクレジットの決済結果をエクセルの家計簿にコピーするのが手作業なので面倒くさくなってきた。
せっかくだからPerlでアップデータを作り自動化しよう。
- カード会社はライフカード
- 決済結果をサイトから手動ダウンロード(自動ログイン/ダウンロードはクラックを疑われる可能性あり)
- ファイル形式は、なんちゃってCSV(行毎にカラム数が異なる)
- 家計簿はエクセルで、科目設定シート、1~12月の各シート、集計シート、他
- 決済結果と家計簿をデスクトップに置く
- アップデータはGUI(Tkx)を使う
- エクセル操作はOLEを使う
こんな感じです。
なんちゃってCSVファイルを読み込むと、決済件数と総額がメッセージで報告されます。
それから家計簿に追加すると決済日の月のシートの末尾に追加します。
クレジット会社のサイトから決済結果をオンラインで入手できるAPIとか公開されないかなあ。
そのうち手動ダウンロードが面倒くさくなる(笑)。
なんちゃって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);
}
