config.yml.dist
に設定項目と雛形となる値、項目の説明を追記します。
config.py に DataClassJsonMixin
を継承し、 config.yml で設定できる項目を property として定義した dataclass を作成します。
config.py の Config クラスに新規対応口座の DataClassJsonMixin
インスタンスの type hint のための property を追加します。
新しい口座の明細から Zaim のお店・品目への変換のために
新しい変換用テーブル CSV ファイルを追加する必要がある場合は、
file_csv_convert.py
の FileCsvConvert
に
変換用テーブル CSV の定義を追加します。
プロパティ名 | 内容 |
---|---|
id | データベースカラムで変換用テーブル CSV の種類を表すfile_csv_convert_id として使われます。重複しないように連番を付与してください。 |
name | CSV ファイル名を定義します。 |
convert_table_type | 入力 CSV ファイルの各行がお店単位の場合は ConvertTableType.STORE を、品目単位の場合は ConvertTableType.ITEM を、それぞれ指定します。 |
新規対応口座の入力 CSV モデル module を作成します。
zaimcsvconverter/data/
配下に新規対応口座の入力 CSV の行モデル dataclass を作成します。
- dataclass のプロパティとして、入力 CSV の行の各列を定義します。
- CSV の各行は文字列としてプロパティに代入されますが、
pydantic を使って型変換やバリデーションを実装します。
zaimcsvconverter/inputtooutput/datasources/csv/data/
配下に、新規対応口座の入力 CSV の行モデル dataclass を拡張する dataclass を作成します。
次の複数のクラスを多重継承して定義します:
- 手順 3-1. で作成した行モデル
- 次のいずれか:
- 入力 CSV の行がお店単位の場合:
InputStoreRowData
- 入力 CSV の行が品目単位の場合:
InputItemRowData
- 入力 CSV の行がお店単位の場合:
抽象メソッド、プロパティは以下の内容を実装してください:
メソッド、プロパティ名 | 実装内容 |
---|---|
date | 入力 CSV の行のいずれかの列データから日付型を返してください |
store_name (入力 CSV の行がお店単位の場合のみ) | 変換用テーブルの CSV からお店を検索するための、入力 CSV の行のいずれかの列プロパティを返してください |
item_name | 変換用テーブルの CSV から品目を検索するための、入力 CSV の行のいずれかの列プロパティを返してください |
zaimcsvconverter/inputtooutput/datasources/csv/records/
配下に、
入力 CSV のレコードのモデルクラスを作成します。
入力 CSV のレコードがお店単位の場合は InputStoreRow を継承、
入力 CSV のレコードが品目単位の場合は InputItemRow を継承して作成します。
init() で必ず super().init() を呼び出してください。 インスタンス生成時、super().init() 内で、 手順2-1.で指定した store, item プロパティを使ってデータベースを検索し、 store, item に検索結果のモデルがセットされます。 検索に失敗した場合、store, item は None となり、 変換処理がこれを検知して、この行のお店、品目がデータベースに未登録であると判定し、 error_undefined_content.csv に書き出します。
なお、InputItemRow を継承した場合は store プロパティをオーバーライトして Store モデルを返すように実装してください。(amazon.py を参考にしてください。)
抽象メソッド、プロパティは以下の内容を実装してください。
メソッド、プロパティ名 | 実装内容 |
---|---|
validate | モデル内のプロパティを検証し、異常があれば InvalidRowError を生成してプロパティ list_error に追加して True を返してください。 異常がなければ False を返してください。 |
is_row_to_skip | この行を処理する必要がない場合、True を返すように実装してください。実装しない場合は常に skip せず処理されます。 |
CSV 形式は、実際には性質の異なる行や、その属性を、 言わば強引に 1 つのテーブルとして出力しています。 (データベース用語の「非正規化」) たとえば、多くの CSV では、出金の行と入金の行で、 それぞれの行のみが値を持つ列が存在することがあります。
このような観点から、行の中の不要な列などはプロパティとして持たないモデルクラスに変換した方が、 プログラム中で間違った仕訳をコーディングしてしまうリスクが減らせることが期待できます。
zaimcsvconverter/inputtooutput/converters/recordtozaim/
配下に新規対応口座の CSV レコードモデル変換 module を作成します。
処理の中では InputRow を直接生成せず、 Factory クラスを経由して生成するようにしています。 これは以下の理由のためです:
- InputRow は CSV のフォーマットを表しており、
同じ CSV フォーマットの異なる口座の設定を DI できるようにするため
(
zaimcsvconverter/inputtooutput/datasources/csv/records/sf_card_viewer.py
を参考にしてください。) - 手順3-3.で実装した InputRow モデルの各プロパティの実装が if だらけにならないようにするため
- 行の種類によって不要な列を処理から省くため
InputRowFactory を継承した Factory クラスを作成し、 手順3-2.で作成した dataclass を引数に、手順3-3.で作成したモデルクラスを返す create メソッドを実装してください。
InputRow モデルを ZaimRow モデルに変換するための Converter クラスと、 手順 4-5. で後述する ZaimRowConverterFactory クラスで、 入力 CSV の行モデルクラスインスタンスを作り分けることにより、 Strategy パターンを実装できます。
実装する Converter クラスは、対象の行がZaimの支出、収入、振替の内、どの記録にあたるかによって、
ZaimIncomeRowConverter
, ZaimPaymentRowConverter
, ZaimTransferRowConverter
のいずれかを継承して実装してください。
ZaimIncomeRowConverter
メソッド、プロパティ名 | 実装内容 |
---|---|
cash_flow_target | この行が収入の行の場合、出力 CSV に「入金先」として記載すべき文字列を返してください。 |
amount | この行が収入の行の場合、出力 CSV に「収入」として記載すべき数値を返してください。 |
ZaimPaymentRowConverter
メソッド、プロパティ名 | 実装内容 |
---|---|
cash_flow_source | この行が支出の行の場合、出力 CSV に「支払元」として記載すべき文字列を返してください。 |
amount | この行が支出の行の場合、出力 CSV に「支出」として記載すべき数値を返してください。 |
ZaimTransferRowConverter
メソッド、プロパティ名 | 実装内容 |
---|---|
cash_flow_source | この行が振替の行の場合、出力 CSV に「支払元」として記載すべき文字列を返してください。 |
cash_flow_target | この行が振替の行の場合、出力 CSV に「入金先」として記載すべき文字列を返してください。 |
amount | この行が振替の行の場合、出力 CSV に「振替」として記載すべき数値を返してください。 |
ZaimRowConverterFactory
クラスを継承し、create()
メソッドを実装します。
引数の ValidatedInputRow
に対して、どの ZaimRowConverter
クラスを利用するかを選択します。
(zaimcsvconverter/inputtooutput/converters/recordtozaim/
の waon.py
, mufg.py
, sf_card_viewer.py
を参考にしてください。)
account.py
の Account
Enum クラスに新規対応口座用の AccountContext
インスタンス定数を追加します。
AccountContext
の各プロパティは以下のように定義します。
プロパティ名 | 内容 |
---|---|
regex_csv_file_name | 入力 CSV ファイルが、この口座の CSV ファイルであると判定するための正規表現を定義します。 |
god_slayer_factory | CSV ファイルのレコードを読み取るためのジェネレーターである GodSlayer の Factory クラス GodSlayerFactory のインスタンスを指定します。CSV の書式に合わせ、引数で hedder , footer , partition , encoding などを指定します。詳しくは GodSlayer の README を確認してください。 |
input_row_data_class | 手順3.で実装した InputRowData を指定します。 |
input_row_factory | 手順4.で実装した InputRowFactory を指定します。こちらはクラスではなくインスタンス生成して渡します。 |
zaim_row_converter_factory | 手順4.で実装した ZaimRowConverter を指定します。こちらはクラスではなくインスタンス生成して渡します。 |
手順 2. で変換テーブル CSV ファイルに依存する属性の定義を追加すると、 テストが失敗するようになるので修正します。
tests/test_file_csv_convert.py
の FilePathConvertTable
に
追加した口座のお店、品目の変換テーブルが定義されている
CSV ファイルへのパスの例を追加します。
手順 5. で口座に依存する属性の定義を追加すると、 テストが失敗するようになるので修正します。
tests/test_account.py
の FilePathInput
に
追加した口座の入力 CSV ファイルへのパスの例を追加します。
次のディレクトリー内に変換テーブルの例となる CSV ファイルを追加します。
tests/testresources/test_zaim_csv_converter/csvconvettable
次のディレクトリー内に入力 CSV ファイルの例となる CSV ファイルを追加します。 クレジットカード情報などをリポジトリーにコミットしないよう注意します。
tests/testresources/test_zaim_csv_converter/csvinput_test_success
tests/testresources/config.yml.dist
に追加した口座の設定の例を追加します。
tests/testlibraries/integration_test_expected_factory.py
に、期待する変換結果を返す関数を定義します。
tests/test_zaim_csv_converter.py
を開き、test_success()
を確認します。
ファイルの数を確認している箇所を修正します:
- assert len(files) == 17
+ assert len(files) == 18
変換後のファイルの assertion を追加します:
checker.assert_file("pay_pal201810.csv", create_zaim_row_data_pay_pal_201810())
+ checker.assert_file("sbi_sumishin_net_bank202201.csv", create_zaim_row_data_sbi_sumishin_net_bank_202201())
pipenv shell
inv coverage
「現在は以下の口座の CSV に対応しています」の箇所に口座を追加します。
「各口座毎に、以下のファイル名と形式で準備します」の箇所に口座とファイル名を追加します。
「変換対象の CSV を準備します」の箇所に口座とファイル名に含まれるべき文字列を追加します。
「変換対象 CSV の準備方法」の箇所に口座の CSV ファイルを準備する方法を追加します。
言葉 | 内容 |
---|---|
data source | データの入力元となるもの。例えば、CSV など。 |
row | CSV の行を表します。 |
data | CSV の行の各セルを全てプロパティにセットし、オブジェクト化するための dataclass です。pydantic で CSV の各セルの文字列を正しい型に変換してプロパティにセットできるかバリデーションし、成功すると値がプロパティにセットされます。 |
record | CSV の設計者が意図していると思われる、 1 レコード分のデータを表します。神 CSV に対応するため、必ずしも CSV 1 行と対応するとは限らないものとして設計します。(PayPal など) |
converter | 何かの形式から別の形式への変換処理です。 |
exporter | 出力先の対象となるアプリケーションとフォーマットを持つ出力処理です。例: Zaim の CSV 形式への出力処理。 |
store | Zaim の「お店」を表します。 |
item | Zaim の「品目」を表します。 |
変換処理の全体の流れは次の通りです:
CSV -> 行データ -> レコードモデル -> Zaim 行モデル -> CSV