openpyxlで日本円表記の伝票をエクスポートする

PythonでExcelファイルを操作できるモジュール`openpyxl`を使って、
小計・消費税・合計金額を表示する簡易的なxlsx形式の伝票をエクスポートするアプリケーションのメモ。

## openpyxlをインストール
    pip install openpyxl

## テンプレートとなるxlsxファイルを用意
お手元のExcelやNumbers、Googleスプレッドシートなどで
下記のような`template.xlsx`ファイルを作成して、
これから作成する`app.py`ファイルと同じ階層に設置。

![template.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781928/b4f26951-713f-1304-fbb9-948973079d08.png)


## app.pyを作成
openpyxlをインポートし、`template.xlsx`をコピーして
新しいExcelファイル`template-new.xlsx`ファイルを作成する。

```python:app.py
import openpyxl

wb=openpyxl.load_workbook("template.xlsx")
sheet=wb.active

# ここに各セルへの指示を書いていく

wb.save("template-new.xlsx")
```

## 日本の通貨形式でセルに金額を書き込む
openpyxlで特定のセルに値を書き込むには、

    sheet["セル番号"].value = 値

のように書きますが、今回扱う値は「通貨」で、かつ「3桁区切りの日本円表記（¥1,200）」にしたいので、`number_format`を使って新しくユーザー定義フォーマットを指定します。

    sheet["セル番号"].number_format = '"¥"#,##0'　
    #先頭に¥をつけた3桁区切りの通貨表示になる（例：¥1,200）

```python:app.py
# ...略...

sheet["A1"].value = "ジャンプ"
sheet["B1"].number_format = '"¥"#,##0'　#先頭に¥をつけた3桁区切りの通貨表示になる
sheet["B1"].value = 290

sheet["A2"].value = "サンデー"
sheet["B2"].number_format = '"¥"#,##0'
sheet["B2"].value = 360

sheet["A3"].value = "マガジン"
sheet["B3"].number_format = '"¥"#,##0'
sheet["B3"].value = 340

# ...略...
```
(ジャンプ、安...)

それぞれのセルに価格が「¥000」と表示される
![cell.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781928/13a9613c-71a2-9b52-c366-c50353bc6792.png)


## 小計を計算してセルに書き込む
次に、全ての商品の金額を合計した小計を計算してセルに書き込みます。
openpyxlで計算結果をセルに表示する方法は、

1. Pythonアプリケーション上で計算した値をセルに書き込む
2. セルに関数を記入して、Excel上に計算結果を表示する

の2パターンが考えられます。

どちらでもExcel上に表示される金額は変わらないのですが、
2.の「セルに関数を記入して、Excel上に計算結果を表示する」にしておくと、
Excelファイルをエクスポートした後に、ExcelやNumbersなどのアプリケーションで
編集する際に、セルには関数が保持されているので、
一つの商品の金額を修正すると小計や消費税、合計金額も連動して変更されるので便利です。
（実際の業務でもアプリケーションで請求書を発行した後に、
顧客とのやり取りで金額を調整することが多いですよね・・・）

1.だと計算はPythonアプリケーション上で行い、その結果得られたいわばstaticな値がExcelに書き込まれます。（アプリケーションや業務の内容によってはそのほうがいい場合もありますので、その辺はケースバイケースで...）

なので、今回は2.のパターンで書いていきます。

セルに関数を書き込むには、

    sheet["セル番号"].value = "=関数(セル番号:セル番号)"

のように書きます。

```python:app.py
# ...略...

# 小計
sheet["A8"].value = "小計"
sheet["B8"].number_format = '"¥"#,##0'
sheet["B8"].value = "=SUM(B1:B7)" #セルB8にSUM関数を記入（B1からB7までの和）

# 消費税(10%で計算)
sheet["A9"].value = "消費税"
sheet["B9"].number_format = '"¥"#,##0'
sheet["B9"].value = "=PRODUCT(B8 * 0.1)" #セルB9にPRODUCT関数を記入（小計B8に0.1を掛けた値、軽減税率であれば0.08)

# ...略...
```

セル`B8`に小計、セル`B9`に消費税が記入された
![total.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781928/6962210a-a8de-e956-5273-a46475180eea.png)
![tax.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781928/cbbc953e-ba29-56eb-dd70-7002d30c0b6d.png)


あとは、`B10`のセルに小計と消費税を合計した金額を書き込んで完成です。

```python:app.py
# ...略...

# 合計
sheet["A10"].value = "合計"
sheet["B10"].number_format = '"¥"#,##0'
sheet["B10"].value = "=SUM(B8:B9)"

# ...略...
```

合計が追加された
![taxinclude.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2781928/f750eae8-87e9-930f-13e2-e9f9d1a02986.png)


最終的なapp.pyは、以下になります。

```python:app.py
import openpyxl

wb=openpyxl.load_workbook("template.xlsx")
sheet=wb.active

sheet["A1"].value = "ジャンプ"
sheet["B1"].number_format = '"¥"#,##0'
sheet["B1"].value = 290

sheet["A2"].value = "サンデー"
sheet["B2"].number_format = '"¥"#,##0'
sheet["B2"].value = 360

sheet["A3"].value = "マガジン"
sheet["B3"].number_format = '"¥"#,##0'
sheet["B3"].value = 340

#小計
sheet["A8"].value = "小計"
sheet["B8"].number_format = '"¥"#,##0'
sheet["B8"].value = "=SUM(B1:B7)" 

#消費税(10%で計算)
sheet["A9"].value = "消費税"
sheet["B9"].number_format = '"¥"#,##0'
sheet["B9"].value = "=PRODUCT(B8 * 0.1)" 

# 合計
sheet["A10"].value = "合計"
sheet["B10"].number_format = '"¥"#,##0'
sheet["B10"].value = "=SUM(B8:B9)"

wb.save("template-new.xlsx")
```