取引先ごとにバラバラの明細を貼り付けるだけで、請求書を人数分まとめて作成します。 消費税(10%・軽減8%)の計算と請求番号の採番も自動です。作成後はそのまま印刷・PDF保存できます。
※ このページはポートフォリオ用のデモです。会社名・金額・振込先はすべて架空のものです。
入力したデータはブラウザの中だけで処理され、サーバーには一切送信されません。
「請求書を一括作成する」を押すと、ここに請求書が並びます。
GASで請求書をPDF化し、取引先ごとにGoogleドライブへ保存、メール送信まで自動化できます。
既存のExcelテンプレートに差し込んで、取引先の数だけファイルを書き出します(Python / VBA)。
定期実行を設定し、締め日に自動で当月分を作成、担当者には確認用の通知だけを届けます。
// 明細シートから取引先ごとの請求書PDFを作り、Driveに保存する const TAX = { normal: 0.10, reduced: 0.08 }; function 請求書を一括作成() { const ss = SpreadsheetApp.getActive(); const rows = ss.getSheetByName('明細').getDataRange().getValues(); const head = rows.shift(); const col = name => head.indexOf(name); const folder = DriveApp.createFolder('請求書_' + Utilities.formatDate(new Date(), 'JST', 'yyyyMM')); // 取引先ごとに明細をまとめる const groups = {}; rows.forEach(r => { const client = r[col('取引先名')]; if (!client) return; (groups[client] = groups[client] || []).push({ item: r[col('品目')], qty: Number(r[col('数量')]), unit: Number(r[col('単価')]), rate: String(r[col('税率')]).indexOf('8') >= 0 ? TAX.reduced : TAX.normal }); }); const tpl = ss.getSheetByName('請求書テンプレート'); Object.keys(groups).forEach((client, i) => { const lines = groups[client]; const subtotal = lines.reduce((s, l) => s + l.qty * l.unit, 0); const tax = Math.floor(lines.reduce((s, l) => s + l.qty * l.unit * l.rate, 0)); tpl.getRange('B3').setValue(client + ' 御中'); tpl.getRange('B5').setValue('INV-' + Utilities.formatDate(new Date(), 'JST', 'yyyy') + '-' + ('000' + (i + 1)).slice(-4)); tpl.getRange('B7').setValue(subtotal + tax); tpl.getRange('A10:D' + (9 + lines.length)) .setValues(lines.map(l => [l.item, l.qty, l.unit, l.qty * l.unit])); SpreadsheetApp.flush(); // シートをPDFにしてフォルダへ保存 const url = ss.getUrl().replace(/\/edit.*$/, '') + '/export?format=pdf&gid=' + tpl.getSheetId() + '&portrait=true&fitw=true'; const pdf = UrlFetchApp.fetch(url, { headers: { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() } }).getBlob().setName(client + '_請求書.pdf'); folder.createFile(pdf); }); SpreadsheetApp.getUi().alert( Object.keys(groups).length + '件の請求書を作成しました。\nフォルダ: ' + folder.getName()); }
# Excelのひな形に差し込んで、取引先の数だけ請求書ファイルを書き出す from datetime import date, timedelta from pathlib import Path import math import pandas as pd from openpyxl import load_workbook TAX = {"10%": 0.10, "8%": 0.08} OUT = Path("請求書") OUT.mkdir(exist_ok=True) df = pd.read_csv("明細.csv", dtype=str).fillna("") df["数量"] = df["数量"].astype(int) df["単価"] = df["単価"].astype(int) df["金額"] = df["数量"] * df["単価"] issue_date = date.today() due_date = (issue_date.replace(day=1) + timedelta(days=62)).replace(day=1) - timedelta(days=1) for i, (client, group) in enumerate(df.groupby("取引先名", sort=False), start=1): subtotal = int(group["金額"].sum()) tax = math.floor(sum(row["金額"] * TAX.get(row["税率"], 0.10) for _, row in group.iterrows())) wb = load_workbook("請求書テンプレート.xlsx") # 既存のひな形を使い回す ws = wb.active ws["B3"] = f"{client} 御中" ws["B5"] = f"INV-{issue_date:%Y}-{i:04d}" ws["B6"] = issue_date.strftime("%Y年%m月%d日") ws["B7"] = due_date.strftime("%Y年%m月%d日") for r, (_, row) in enumerate(group.iterrows(), start=10): # 10行目から明細 ws.cell(r, 1, row["品目"]) ws.cell(r, 2, row["数量"]) ws.cell(r, 3, row["単価"]) ws.cell(r, 4, row["金額"]) ws["D30"], ws["D31"], ws["D32"] = subtotal, tax, subtotal + tax wb.save(OUT / f"{client}_請求書_{issue_date:%Y%m}.xlsx") print(f"{client}: {subtotal + tax:,}円(税込)") print(f"合計 {df['取引先名'].nunique()} 件を {OUT} に出力しました")