Pythonで学ぶ簿記　～簿記一巡の流れ編～

## はじめに
Python（主にPandas）で簿記一巡の流れをコーディングしながら理解することが、この記事の目的です。

おおまかな流れの理解を目的としているため、簿記の教科書に出てくる項目を一部省略して説明しています。
例えば、

- 商品在庫、仕入金額を元にした売上原価の算定
- 精算表の作成
- 翌期への繰越

といった事項は割愛しています。

## 0.簿記とは

企業で行われた取引を**仕訳**として記録し、**貸借対照表（B/S）**と**損益計算書（P/L）**を作成する手続きです。

**仕訳**のイメージは以下のとおりです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635447/443e379b-1d4b-a851-8e62-5916bc7c3900.png "仕訳")

仕訳の**左側を借方**、**右側を貸方**と呼びます。
（残念ながら、これは覚えるしかない約束事です。。。）

**貸借対照表（B/S）**は企業の財政状態、平たく言うと
「企業が今どれだけの財産を持っているか」
をあらわす表です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635447/84238c93-1602-3c6c-804c-02d90f7f59b9.png "貸借対照表")

**損益計算書（P/L）**は企業の経営成績、平たく言うと
「企業が一定の期間にどれだけ儲かったか（損したか）」
をあらわす表です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635447/af9b8f8f-a879-7154-8eb6-1a7cb2996ec7.png "損益計算書")


簿記の手続きは、ごく大まかに言うと以下1～3の流れで行います。

**1. 仕訳の作成**

　　取引を**仕訳**として**仕訳帳**に記録する。

**2. 残高試算表（T/B）の作成**

　　仕訳帳から勘定科目ごとの借方金額、貸方金額を集計し、**残高試算表**を作成する。
  
**3. 貸借対照表（B/S）、損益計算書（P/L）の作成**

　　残高試算表を**貸借対照表（B/S）**、**損益計算書（P/L）**に分割する。（注1）  


なお**1.仕訳の作成**にあたっては以下４つのルールを守る必要があります。

- 仕訳ルール①：**借方（左側）**、**貸方（右側）**に**勘定科目**と**金額**を記載する
- 仕訳ルール②：借方、貸方それぞれの合計金額は必ず**一致する**
- 仕訳ルール③：**資産**の増加は借方、**負債**と**純資産**の増加は貸方に記載する
- 仕訳ルール④：**費用**は借方、**収益**は貸方に記載する


・・・ここまで、簿記特有の用語が次から次へと現れました。
特に簿記の初学者の方は、用語の多さに戸惑うことと思います。

まずは、簿記の世界では

- 企業の取引を**仕訳**という形式であらわす
- 仕訳の**左側を借方**、**右側を貸方**と呼ぶ

という点だけご確認ください。

その他用語については、仕訳を作成する中で①～④のルールを都度引用しながら説明していきます。

<details><summary>（注1）</summary>  
簿記の教科書では、1→2の間に「決算整理仕訳」を作成し、2→3の間に「精算表」を作成する、とあります。  
　**残高試算表　→　決算整理仕訳　→　貸借対照表、損益計算書**  
の数字を記録するのが精算表です。  
 しかし経理業務の現場では、決算整理仕訳は通常の仕訳と区別せず行うケースが多いものと思われます。  
また2→3はシステム上自動で生成され、わざわざ精算表を作成しないケースが多いと思われるため、本稿では割愛します。
（簿記の試験のように手書きで財務諸表を作成する際には必要な表ですが。。）<details>

## 1.仕訳の作成

【やりたいこと】
取引を**仕訳**として**仕訳帳**に記録します。

【コーディングの方針】
仕訳をPandasのDataFrame形式で、仕訳帳 **df_siwake** に入力します。
**Siwake**クラスの関数 **entry** を呼び出すことで、**df_siwake**に仕訳データの行を追加し、更新します。

`仕訳ルール①：借方（左側）、貸方（右側）に勘定科目と金額を記載する` 

に従い、仕訳を入力するための空のDataFrameとして仕訳帳 **df_siwake** を作成します。


```python
import pandas as pd
df_siwake = pd.DataFrame(index=[],
                         columns=['仕訳番号', '日付', '借方科目', '借方金額', '貸方科目', '貸方金額'])
```

例えば
（借方）現金　／（貸方）資本金
という仕訳を入力する場合、DataFrameの型に従って毎回

```python
df_siwake.append(pd.Series([1, 20200401, '現金', 1000, '資本金', 1000], index=df_kamoku.columns), ignore_index=True)
```

というコードを書き、DataFrameの行を追加しても良いのですが、

- 複合仕訳（借方と貸方が1対1対応していない仕訳）を入力できない　・・・①
- 入力時に、仕訳のデータ型が正しいか（借方金額に文字列を入力するなど）確認できない　・・・②
- 入力時に、仕訳の貸借が一致しているか確認できない　・・・③

との問題があります。

※簿記の世界では③が守られていることが非常に重要です。
仕訳入力時に必ず貸借が一致していることにより、後ほど残高試算表を作るときにも、
貸借金額が一致することが保証されます。

そこで仕訳入力用のクラス **Siwake** を定義し、まずは①複合仕訳の入力に対応する形で
関数 **entry** を定義します。

※最終的には **Siwake** 内に②データ型チェック、③貸借一致チェックの関数を実装しますが、
コードが長くなるため、末尾に補足として追記します。

```python
class Siwake:
    def __init__(self):
        self.siwake_no = 0

    def entry(self, df, date, kari, kashi): 
        self.siwake_no += 1 # ...仕訳番号を更新
            
        for i in range(len(kari)): # ...複合仕訳に対応するため[借方科目、借方金額]の数だけループを回す                    
            kari_entry = pd.Series([self.siwake_no] + [date] + kari[i] + ["", 0], index=df.columns)          
            df = df.append(kari_entry, ignore_index=True)
            
        for i in range(len(kashi)): # ...複合仕訳に対応するため[貸方科目、貸方金額]の数だけループを回す                    
            kashi_entry = pd.Series([self.siwake_no] + [date] + ["", 0] + kashi[i], index=df.columns)
            df = df.append(kashi_entry, ignore_index=True)
            
        return df
```

クラス **Siwake** 内のコメントについて補足します。

仕訳帳には仕訳を日付順に記録していくため、クラス変数として仕訳番号**siwake_no**を定義しています。
仕訳が作成される（関数entryが呼び出される）ごとに

```python
self.siwake_no += 1 # ...仕訳番号を更新
```
で仕訳番号を連番として更新しています。

また本稿では借方科目、貸方科目とも1行の仕訳のみを扱っていますが、実務上は複数行の仕訳を作成することが多いです。
複合仕訳に対応するため以下のようにループを回し、借方・貸方それぞれのpd.Seriesを生成した上で、
仕訳日記帳 **df_siwake** に行を追加しています。

```python
for i in range(len(kari)): # ...複合仕訳に対応するため[借方科目、借方金額]の数だけループを回す
    kari_entry = pd.Series([self.siwake_no] + [date] + kari[i] + ["", 0], index=df.columns)          
    df = df.append(kari_entry, ignore_index=True)

for i in range(len(kashi)): # ...複合仕訳に対応するため[貸方科目、貸方金額]の数だけループを回す
    kashi_entry = pd.Series([self.siwake_no] + [date] + ["", 0] + kashi[i], index=df.columns)
    df = df.append(kashi_entry, ignore_index=True)
```

クラス **Siwake** の補足説明は以上です。


関数**entry**には以下の形式で入力します。

```python
siwake.entry(df_siwake:仕訳帳, date:日付,
             kari :[[借方科目1, 借方金額1], [借方科目2, 借方金額2], ... ],
             kashi:[[貸方科目1, 貸方金額1], [貸方科目2, 貸方金額2], ... ])
```

すると仕訳日記帳 **df_siwake** に以下の行が追加されます。

|index|仕訳番号|日付|借方科目|借方金額|貸方科目|貸方金額
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|0|**siwake_no**<br>（数値）|**date**<br>（数値）|**kari[0][0]**<br>（文字列）|**kari[0][1]<br>**（数値）|**""**<br>（文字列）|**0**<br>（数値）|
|1|**siwake_no**<br>（数値）|**date**<br>（数値）|**""**<br>（文字列）|**0<br>**（数値）|**kashi[0][0]**<br>（文字列）|**kashi[0][1]**<br>（数値）|
|…|…|…|…|…|…|…|


それではクラス**Siwake**のインスタンスを生成し、

```python
siwake = Siwake()
```

会社運営の最も基本的なサイクルである

1. 会社を設立
2. 商品の仕入
3. 商品の販売
4. 仕入代金の支払
5. 販売代金の回収

の各取引について仕訳を作成していきます。

#### 仕訳①：会社を設立

現金1000を元手に会社を設立しました。

この元手のことを**資本金**と呼び、仕訳は以下の通りです。

```python
df_siwake = siwake.entry(df_siwake, 20200401,
                         [['現金', 1000]],
                         [['資本金', 1000]])

df_siwake[df_siwake['仕訳番号']==siwake.siwake_no]
```

|index|仕訳番号|日付|借方科目|借方金額|貸方科目|貸方金額
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|0|1|20200401|現金|1000||0|
|1|1|20200401||0|資本金|1000|

会社に払い込まれた現金は会社のもの、つまり**資産**ですから**借方**に記載します。

一方、資本金は現金1000を払込した（株式会社であれば）株主のものです。**純資産**といい、**貸方**に記載します。

借方金額1000と貸方金額1000が必ず一致していることが大事です。

少し話は先に進みますが、貸方の純資産はおおまかに言うと

**会社設立時に払い込まれた資本金　＋　会社設立後に稼いだ利益**

からなります。
事業を行うことで利益を蓄積し、（株式会社であれば）株主に配当として還元する、
というのが会社の基本サイクルです。

会社設立後に稼いだ利益が、貸方の純資産に来ることから、

- 収益の発生　→　貸方の利益を増やす　→　貸方に記載
- 費用の発生　→　貸方の利益を減らす　→　借方に記載

すなわち、
`仕訳ルール④：費用は借方、収益は貸方に記載する`
が導かれます。

#### 仕訳②：商品の仕入

商品500を外部業者より仕入れました。
仕訳は以下の通りです。

```python
df_siwake = siwake.entry(df_siwake, 20200402,
                         [['商品', 500]],
                         [['買掛金', 500]])

df_siwake[df_siwake['仕訳番号']==siwake.siwake_no]
```

|index|仕訳番号|日付|借方科目|借方金額|貸方科目|貸方金額
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|2|2|20200402|商品|500||0|
|3|2|20200402||0|買掛金|500|

仕入れた商品は会社のもの、つまり**資産**ですから借方に記載します。
（`ルール③：資産の増加は借方、負債と純資産の増加は貸方に記載する`）

会社間の取引において、仕入代金は仕入先と〇〇日後支払、などの条件を取り決めて
後払いすることがほとんどです。
（もちろんその場で支払する場合もあります）

この支払うまでの債務（代金を支払う義務）を**買掛金**といいます。

買掛金は将来、外部業者の現金となる、つまり**負債**ですから貸方に記載します。
（`ルール③：資産の増加は借方、負債と純資産の増加は貸方に記載する`）

#### 仕訳③：商品を売上
仕入れた商品のうち200について、価格300で販売しました。
売上についての仕訳は以下の通りです。

```python
df_siwake = siwake.entry(df_siwake, 20200403,
                         [['売掛金', 300]],
                         [['売上', 300]])

df_siwake[df_siwake['仕訳番号']==siwake.siwake_no]
```

|index|仕訳番号|日付|借方科目|借方金額|貸方科目|貸方金額
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|4|3|20200403|売掛金|300||0|
|5|3|20200403||0|売上|300|

会社間の取引において 、販売代金は販売先と〇〇日後回収、などの条件を取り決めて
後日回収することがほとんどです。
（もちらん、その場で回収する場合もあります）

この回収するまでの債権（代金をもらう権利）を**売掛金**といいます。

売掛金は将来、会社の現金となる、つまり**資産**ですから**借方**に記載します。
（`ルール③：資産の増加は借方、負債と純資産の増加は貸方に記載する`）

売上は**収益**であり、会社の**純資産（貸方）**を増やす効果がありますから、**貸方**に記載します。
（`ルール④：費用は借方、収益は貸方に記載する`）

売上に対応する原価についての仕訳は以下の通りです。

```python
df_siwake = siwake.entry(df_siwake, 20200403,
                         [['売上原価', 200]],
                         [['商品', 200]])

df_siwake[df_siwake['仕訳番号']==siwake.siwake_no]
```

|index|仕訳番号|日付|借方科目|借方金額|貸方科目|貸方金額
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|6|4|20200403|売上原価|200||0|
|7|4|20200403||0|商品|200|

商品を販売することで、会社のものである**商品（借方）**が減るので、その反対である**貸方**に記載します 
（`ルール③：資産の増加は借方、負債と純資産の増加は貸方に記載する`
⇔`ルール'③：資産の減少は貸方、負債と純資産の減少は借方に記載する`）

商品の減少と共に、商品の売上に対応する**費用**を**売上原価**として計上します。（注2）

費用は会社の**純資産（貸方）**を減らす効果がありますから、その反対である**借方**に記載します。
（`ルール④：費用は借方、収益は貸方に記載する`）

<details><summary>（注2）</summary>
本稿では簡略化のため、商品を売り上げたと同時に売上原価を計上しています。  
実際には売上原価は、冒頭に少しだけ触れた「決算整理仕訳」により  
**売上原価　＝　仕入金額の総額　＋　期首の商品在庫金額　－　期末の商品在庫金額**  
という式で算定します。</details>

なお原価200の商品を、販売価額300で売り上げたため、その取引の利益は100になります。

しかし簿記の手続きでは、商品を販売するたびに利益を認識することはありません。
簿記の目的は**一定の期間（会計期間）における利益を算定すること**であるためです。

利益については、期末に当期分の収益および費用の合計金額を集計し、
その差額である利益について**損益振替**という仕訳を作成することで、
会計期間末に一度に認識します（後述）。

#### 仕訳④：仕入代金を支払
仕入代金500のうち300について、外部業者に支払いました。
（残りの200は翌月支払の契約と仮定します）
仕訳は以下の通りです。

```python
df_siwake = siwake.entry(df_siwake, 20200420,
                         [['買掛金', 300]],
                         [['現金', 300]])

df_siwake[df_siwake['仕訳番号']==siwake.siwake_no]
```

|index|仕訳番号|日付|借方科目|借方金額|貸方科目|貸方金額
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|8|5|20200420|買掛金|300||0|
|9|5|20200420||0|現金|300|

仕入代金を支払うことで、会社の資産である**現金**（**借方**）が減りますから、
その反対である**貸方**に記載します。
（`ルール③：資産の増加は借方、負債と純資産の増加は貸方に記載する`
⇔`ルール'③：資産の減少は貸方、負債と純資産の減少は借方に記載する`）

一方、仕入先に代金を支払う債務である**買掛金**（**貸方**）も、支払完了と共になくなるため、
その反対である**借方**に記載します。
（`ルール③：資産の増加は借方、負債と純資産の増加は貸方に記載する`
⇔`ルール'③：資産の減少は貸方、負債と純資産の減少は借方に記載する`）

#### 仕訳⑤：販売代金を回収
販売代金200について、販売先から現金で回収しました。
（残りの100は翌月回収の契約と仮定します）
仕訳は以下の通りです。

```python
df_siwake = siwake.entry(df_siwake, 20200430,
                         [['現金', 200]],
                         [['売掛金', 200]])

df_siwake[df_siwake['仕訳番号']==siwake.siwake_no]
```

|index|仕訳番号|日付|借方科目|借方金額|貸方科目|貸方金額
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|10|6|20200430|現金|200||0|
|11|6|20200430||0|売掛金|200|

販売代金を回収することで、会社の資産である**現金**（**借方**）が増えますから、
**借方**に記載します。
（`ルール③：資産の増加は借方、負債と純資産の増加は貸方に記載する`）

一方、販売先から代金をもらう債権である**売掛金**（**借方**）も、回収完了と共になくなるため、
その反対である**貸方**に記載します。
（`ルール③：資産の増加は借方、負債と純資産の増加は貸方に記載する`
⇔`ルール'③：資産の減少は貸方、負債と純資産の減少は借方に記載する`）

ここまで

1. 会社を設立
2. 商品の仕入
3. 商品の販売
4. 仕入代金の支払
5. 販売代金の回収

という一連の仕訳を作成しました。仕訳帳 **df_siwake** の中身を確認してみます。

```python
df_siwake
```

|index|仕訳番号|日付|借方科目|借方金額|貸方科目|貸方金額
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|0|1|20200401|現金|1000||0|
|1|1|20200401||0|資本金|1000|
|2|2|20200402|商品|500||0|
|3|2|20200402||0|買掛金|500|
|4|3|20200403|売掛金|300||0|
|5|3|20200403||0|売上|300|
|6|4|20200403|売上原価|200||0|
|7|4|20200403||0|商品|200|
|8|5|20200420|買掛金|300||0|
|9|5|20200420||0|現金|300|
|10|6|20200430|現金|200||0|
|11|6|20200430||0|売掛金|200|

## 2.残高試算表の作成

【やりたいこと】
仕訳帳から勘定科目ごとの借方金額、貸方金額を集計し、**残高試算表**（T/B:Trial Balance）を作成します。  　　

【コーディングの方針】
仕訳帳 **df_siwake** から残高試算表 **df_TB** が生成されるよう、
クラス **TrialBalance** 内に、関数 **create_tb** および勘定科目のDataFrame **df_kamoku**を定義します。

最終的に財務諸表を作成することを見据え、残高試算表の各勘定科目に以下の属性を与えるよう、
**df_kamoku**を定義します（注3）。

<details><summary>（注3）</summary>
実務上は仕訳帳や残高試算表などの他に、勘定科目マスタを用意し、科目コードや貸借区分などの属性を定義します。  
仕訳の作成も科目コードで入力し、勘定科目名はマスタから引用するのが一般的です。</details>

- 科目コード：科目の表示順
- 科目分類：資産、負債、純資産のいずれに属するか
- BS/PL：B/Sの科目か、P/Lの科目か
- 貸借区分：借方（資産）、貸方（負債、純資産）いずれに属するか

```python
df_kamoku = pd.DataFrame({'貸借科目': ['現金', '売掛金', '商品', '買掛金', '資本金', '繰越利益剰余金', '売上', '売上原価', '当期利益'],
                          '科目コード': ['100', '110', '120', '200', '300', '310', '400', '500', '600'],
                          '科目分類': ['資産', '資産', '資産', '負債', '負債', '純資産', '収益', '費用', '利益'],
                          'BS/PL': ['BS', 'BS', 'BS', 'BS', 'BS', 'BS', 'PL', 'PL', 'PL'],
                          '貸借区分': [1, 1, 1, -1, -1, -1, -1, 1, 1]})
```

そして **df_kamoku** と、仕訳日記帳 **df_siwake** の金額を勘定科目ごとに集計したテーブル

```python
df = df_siwake.groupby('貸借科目').sum()[['貸借金額']]
```

を結合します。

なおPandasでの集計の都合上、借方をプラス、貸方をマイナスと考えたほうが扱いやすいため（注4）、

- 貸借金額：借方金額 －　貸方金額

とのカラムを作成します。


<details><summary>（注4）</summary>
「集計の都合上」と書きましたが、借方と貸方、プラスとマイナスとの概念は同値と言えます。
- プラスの反対がマイナス、マイナスの反対がプラス
- 借方の反対が貸方、貸方の反対が借方
- プラスの数とマイナスの数を足すとゼロになる
- 借方と貸方の金額は一致する
「借方」「貸方」という言葉の分かりにくさが、簿記を初めて学ぶ上での障害となりますが、
数学に親しい方は、プラスとマイナスの概念に置き換えれば理解しやすいかもしれません。</details>

```python
class TrialBalance:
    
    df_kamoku = pd.DataFrame({'貸借科目': ['現金', '売掛金', '商品', '買掛金', '資本金', '繰越利益剰余金', '売上', '売上原価', '当期利益'],
                              '科目コード': ['100', '110', '120', '200', '300', '310', '400', '500', '600'],
                              '科目分類': ['資産', '資産', '資産', '負債', '負債', '純資産', '収益', '費用', '利益'],
                              'BS/PL': ['BS', 'BS', 'BS', 'BS', 'BS', 'BS', 'PL', 'PL', 'PL'],
                              '貸借区分': [1, 1, 1, -1, -1, -1, -1, 1, 1]})
     
    def create_tb(self, df_siwake):
        df = df_siwake.copy()
        df['貸借科目'] = df['借方科目'] + df['貸方科目'] 
        df['貸借金額'] = df['借方金額'] - df['貸方金額'] 
        df = df.groupby('貸借科目').sum()[['貸借金額']]
        
        df_merge = pd.merge(df, self.df_kamoku, on='貸借科目').sort_values('科目コード').reset_index(drop=True)
        
        return df_merge
```

**TrialBalance**クラスのインスタンスを生成し、関数 **create_tb** に仕訳日記帳 **df_siwake** を渡して
残高試算表 **df_TB** を作成します。

```python
TB = TrialBalance()

df_TB = TB.create_tb(df_siwake)
df_TB
```

|index|貸借科目|貸借金額|科目コード|科目分類|BS/PL|貸借区分|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|0|現金|900|100|資産|BS|1|
|1|売掛金|100|110|資産|BS|1|
|2|商品|300|120|資産|BS|1|
|3|買掛金|-200|200|負債|BS|-1|
|4|資本金|-1000|300|負債|BS|-1|
|5|売上|-300|400|収益|PL|-1|
|6|売上原価|200|500|費用|PL|1|

科目ごとの貸借金額（借方の場合＋、貸方の場合－）が集計され、科目コードや科目分類などの属性が付与されています。

あとは残高試算表を、貸借対照表（B/S）、損益計算書（P/L）に分割するだけですが、
**単純に分割しただけでは貸借対照表の借方金額、貸方金額が一致しない**という問題が生じます。

確認のため、残高試算表のうち科目分類が「BS」であるものだけを取り出します。

```python
df_TB[df_TB['BS/PL']=='BS']
```

|index|貸借科目|貸借金額|科目コード|科目分類|BS/PL|貸借区分|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|0|現金|900|100|資産|BS|1|
|1|売掛金|100|110|資産|BS|1|
|2|商品|300|120|資産|BS|1|
|3|買掛金|-200|200|負債|BS|-1|
|4|資本金|-1000|300|負債|BS|-1|

一見問題ないように見えますが、この貸借対照表（B/S）は
`ルール②：借方、貸方それぞれの合計金額は必ず一致する`
を満たしていません。

借方金額（貸借金額が＋）、貸方金額（貸借金額が－）をそれぞれ集計してみます。

```python
df_TB[(df_TB['BS/PL']=='BS') & (df_TB['貸借金額'] > 0)]
```
|index|貸借科目|貸借金額|科目コード|科目分類|BS/PL|貸借区分|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|0|現金|900|100|資産|BS|1|
|1|売掛金|100|110|資産|BS|1|
|2|商品|300|120|資産|BS|1|

```python
df_TB[(df_TB['BS/PL']=='BS') & (df_TB['貸借金額'] < 0)]
```

|index|貸借科目|貸借金額|科目コード|科目分類|BS/PL|貸借区分|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|3|買掛金|-200|200|負債|BS|-1|
|4|資本金|-1000|300|負債|BS|-1|


```python
print('借方金額合計:',df_TB[(df_TB['BS/PL']=='BS') & (df_TB['貸借金額'] > 0)].sum()['貸借金額'])
print('貸方金額合計:',df_TB[(df_TB['BS/PL']=='BS') & (df_TB['貸借金額'] < 0)].sum()['貸借金額'])
```
```
借方金額合計: 1300
貸方金額合計: -1200
```

貸借対照表（B/S）における借方金額の合計と、貸方金額の合計が一致していないことがわかります。

この貸借対照表（B/S）における差額は、当期の損益計算書（P/L）における収益と費用の差額、つまり**当期利益**に一致します。

収益と費用の差額から当期利益を算出する手続きを**損益振替**といいます。

また損益計算書（P/L）における**当期利益**を、貸借対照表（B/S）の**繰越利益剰余金**という勘定に振り替える手続きを**資本振替**といいます。

資本振替の仕訳は以下のとおりです。

```python
df_siwake = siwake.entry(df_siwake, 20200430,
                         [['当期利益', 100]],
                         [['繰越利益剰余金', 100]])

df_siwake[df_siwake['仕訳番号']==siwake.siwake_no]
```

|index|仕訳番号|日付|借方科目|借方金額|貸方科目|貸方金額
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|12|7|20200430|当期利益|100||0|
|13|7|20200430||0|繰越利益剰余金|100|

なお当期利益は売上300と売上原価200の差額100です。

損益振替および資本振替を行った後の仕訳帳 **df_siwake** および残高試算表 **df_TB** を見てみます。

```python
df_siwake
```

|index|仕訳番号|日付|借方科目|借方金額|貸方科目|貸方金額
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|0|1|20200401|現金|1000||0|
|1|1|20200401||0|資本金|1000|
|2|2|20200402|商品|500||0|
|3|2|20200402||0|買掛金|500|
|4|3|20200403|売掛金|300||0|
|5|3|20200403||0|売上|300|
|6|4|20200403|売上原価|200||0|
|7|4|20200403||0|商品|200|
|8|5|20200420|買掛金|300||0|
|9|5|20200420||0|現金|300|
|10|6|20200430|現金|200||0|
|11|6|20200430||0|売掛金|200|
|12|7|20200430|当期利益|100||0|
|13|7|20200430||0|繰越利益剰余金|100|

```python
df_TB = TB.create_tb(df_siwake)
df_TB
```

|index|貸借科目|貸借金額|科目コード|科目分類|BS/PL|貸借区分|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|0|現金|900|100|資産|BS|1|
|1|売掛金|200|110|資産|BS|1|
|2|商品|300|120|資産|BS|1|
|3|買掛金|-200|200|負債|BS|-1|
|4|資本金|-1000|300|負債|BS|-1|
|5|繰越利益剰余金|-1000|300|負債|BS|-1|
|6|売上|-300|400|収益|PL|-1|
|7|売上原価|200|500|費用|PL|1|
|8|当期利益|100|500|利益|PL|1|

```python
print('借方金額合計:',df_TB[(df_TB['BS/PL']=='BS') & (df_TB['貸借金額'] > 0)].sum()['貸借金額'])
print('貸方金額合計:',df_TB[(df_TB['BS/PL']=='BS') & (df_TB['貸借金額'] < 0)].sum()['貸借金額'])
```

```
借方金額合計: 1300
貸方金額合計: -1300
```

損益振替および資本振替を行うことで、貸借対照表（B/S）の借方金額および貸方金額が一致するこどが確認できました。

## 3. 貸借対照表（B/S）、損益計算書（P/L）の作成

【やりたいこと】
残高試算表を貸借対照表（B/S）、損益計算書（P/L）に分割します。

【コーディングの方針】
残高試算表 **df_TB**を「BS/PL」列が'BS'か、'PL'かにより分割します。

なお「貸借金額」に「貸借区分」（+1、-1）を乗じることで、借方（＋）貸方（－）それぞれの金額を絶対値に戻し、
「表示貸借」という列に格納します。

```python
BS = df_TB[df_TB['BS/PL']=='BS'].reset_index(drop=True)
BS['表示貸借'] = BS['貸借金額'] * BS['貸借区分']
BS[['科目コード','科目分類', '貸借科目', '表示貸借']]
```

|index|科目コード|科目分類|貸借科目|表示貸借|
|:-:|:-:|:-:|:-:|:-:|
|0|100|資産|現金|900|
|1|110|資産|売掛金|100|
|2|120|資産|商品|300|
|3|200|負債|買掛金|200|
|4|300|負債|資本金|1000|
|5|310|純資産|繰越利益剰余金|100|

```python
PL = df_TB[df_TB['BS/PL']=='PL'].reset_index(drop=True)
PL['表示貸借'] = PL['貸借金額'] * PL['貸借区分']
PL[['科目コード','科目分類', '貸借科目', '表示貸借']]
```

|index|科目コード|科目分類|貸借科目|表示貸借|
|:-:|:-:|:-:|:-:|:-:|
|0|400|収益|売上|300|
|1|500|費用|売上原価|200|
|2|600|利益|当期利益|100|

貸借対照表（B/S）、損益計算書（P/L）が作成できました。
改めてイメージ図を表すと以下のとおりです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635447/26a66d46-9d0e-97e4-f882-68e99f0d356a.png "貸借対照表2")
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635447/1776a217-02f0-7aae-59a2-2dc9adaf2e95.png "損益計算書2")

もう一度振り返りますと、

**1. 仕訳の作成**

　　取引を**仕訳**として**仕訳帳**に記録する。

**2. 残高試算表（T/B）の作成**

　　仕訳帳から勘定科目ごとの借方金額、貸方金額を集計し、**残高試算表**を作成する。
  
**3. 貸借対照表（B/S）、損益計算書（P/L）の作成**

　　残高試算表を科目により**貸借対照表（B/S）**、**損益計算書（P/L）**に分割する。

との流れで、**日々の取引を集計して財務諸表を作成する**ことが、簿記一巡の手続きです。

### 補足：仕訳作成時のエラーチェック

仕訳入力用のクラス **Siwake** に②データ型チェック、③貸借一致チェックの関数を定義し、

- 仕訳のデータ型が正しいか、入力時に確認する　…②
- 仕訳の貸借が一致しているか、入力時に確認する　…③

ように実装します。

```python
class Siwake:
    def __init__(self):
        self.siwake_no = 0

    def entry(self, df, date, kari, kashi):             # ...①複合仕訳に対応
            if self.check_keishiki(date, kari, kashi):  # ...②データ型チェック
                if self.check_taisyaku(kari, kashi):    # ...③貸借一致チェック
                    self.siwake_no += 1                 # ...仕訳番号を更新
            
                    for i in range(len(kari)): #複合仕訳に対応するため[借方科目、借方金額]の数だけループを回す
                    
                        # 仕訳番号、日付、借方科目、借方金額、貸方科目、貸方金額をSereis化し、DataFrameに格納
                        # なお貸方科目は""、貸方金額は0とする
                        kari_entry = pd.Series([self.siwake_no] + [date] + kari[i] + ["", 0], index=df.columns)          
                        df = df.append(kari_entry, ignore_index=True)
            
                    for i in range(len(kashi)): #複合仕訳に対応するため[貸方科目、貸方金額]の数だけループを回す
                    
                        # 仕訳番号、日付、借方科目、借方金額、貸方科目、貸方金額をSereis化し、DataFrameに格納
                        # なお借方科目は""、借方金額は0とする
                        kashi_entry = pd.Series([self.siwake_no] + [date] + ["", 0] + kashi[i], index=df.columns)
                        df = df.append(kashi_entry, ignore_index=True)
            
                    return df
            
                else:
                    print("エラー：貸借金額を一致させてください")
                    return df

            else:
                pass

    
    def check_keishiki(self, date, kari, kashi):# ...②データ型チェック
        for i , k in zip(range(len(kari)),range(len(kashi))):
            if type(date) != int or len(str(date)) != 8:
                print("エラー：日付は8桁の整数yyyymmddで入力してください")
                return False                       
            
            elif len(kari[i]) != 2:
                print("エラー：借方科目、借方金額のみ入力してください")
                return False                
            
            elif type(kari[i][0]) != str or type(kari[i][1]) != int:
                print("エラー：データ型は　借方科目→文字列、借方金額→数値　としてください")
                return False
            
            elif len(kashi[k]) != 2:
                print("エラー：貸方科目、貸方金額のみ入力してください")
                return False                
            
            elif type(kashi[k][0]) != str or type(kashi[k][1]) != int:
                print("エラー：データ型は　貸方科目→文字列、貸方金額→数値　としてください")
                return False
            
            else:
                return True                    
                                        
    def check_taisyaku(self, kari, kashi):# ...③貸借一致チェック
        kari_sum = 0
        kashi_sum = 0
        
        for i in range(len(kari)):
                kari_sum += kari[i][1]
        
        for i in range(len(kashi)):
                kashi_sum += kashi[i][1]       
        
        if kari_sum != kashi_sum:
            return False
        
        else:
            return True
```

Siwakeクラスのインスタンスを生成し、不正な仕訳を作成していきます。

```python
siwake = Siwake()
```

「日付」に不正な値を入れてみます。

```python
df_siwake = siwake.entry(df_siwake, 1201,
             [['現金', 500]],
             [['資本金', 1000]])
```
```
エラー：日付は8桁の整数yyyymmddで入力してください
```

貸借金額が一致していない仕訳を入れてみます。

```python
df_siwake = siwake.entry(df_siwake, 20200401,
             [['現金', 500]],
             [['資本金', 1000]])
```
```
エラー：貸借金額を一致させてください
```

余計な項目の入った仕訳を入れてみます。

```python
df_siwake = siwake.entry(df_siwake, 20200401,
             [['現金', 500, '業者A']],
             [['資本金', 1000, '業者A']])
```
```
エラー：借方科目、借方金額のみ入力してください
```
データ型が不正な仕訳を入れてみます。

```python
df_siwake = siwake.entry(df_siwake, 20200401,
             [['現金', 500]],
             [['資本金', '1000']])
```
```
エラー：データ型は　貸方科目→文字列、貸方金額→数値　としてください
```

実務上は入力値が空でないかのチェック、勘定科目が科目マスタにあるかのチェックなど、
様々なチェック項目が考えられますが、本稿では最低限のチェックのみ実施しています。

## おわりに
Qiitaに初めて記事を投稿しました。

実際にアウトプットしてみると、Pythonも簿記もわかっていない点が次々と明るみに出て、大変興味深い体験でした。

今後は

- 商品在庫の評価と売上原価
- 固定資産の減価償却
- 翌期への繰越手続き

なども実装できるかやってみたいと思います。