はじめに:なぜOSSでExcel DXなのか
「Excel業務をシステム化したい。でも、高額な商用ライブラリやSaaSを導入する予算がない…」
そんな悩みを持つエンジニアや情シス担当者は多いはずです。しかし、諦める必要はありません。OSSにもExcelのUIをWeb上で忠実に再現できるライブラリが存在します。
本記事では、商用ツールを一切使わず、「Luckysheet(フロントエンド)」と「FastAPI(バックエンド)」 という完全OSS構成で、「在庫管理・発注シミュレーションシステム」を構築するアプローチをご紹介します。
1. 目指すアーキテクチャ
「データはDBで堅牢に守り、UIはExcelライクに使いやすく」という方針は変わりません。
-
Frontend (UI): Luckysheet (MITライセンス)
- Webブラウザ上でExcelのような見た目と操作感(数式、ドラッグ&ドロップ、書式設定)を提供
-
Backend (API): FastAPI (Python)
- 高速かつモダンなPythonフレームワークで、計算ロジックとDB操作を担当
-
Database: PostgreSQL
- 堅牢なRDBでデータを一元管理
2. ユースケース:在庫発注シミュレーション
Excelで運用されがちな「在庫一覧を見ながら、システムが提案した発注数を手動で微調整する」業務を想定します。
3. 実装ステップとコード解説
Step 1: データベース構築 (PostgreSQL)
-- inventory_table.sql
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
current_stock INT NOT NULL, -- 現在在庫
safety_stock INT DEFAULT 10, -- 安全在庫
lead_time INT DEFAULT 3 -- 調達リードタイム(日)
);
-- サンプルデータ
INSERT INTO products (name, current_stock, safety_stock, lead_time) VALUES
('ネジ Type-A', 50, 20, 5),
('ボルト M8', 5, 30, 2),
('ワッシャー', 100, 10, 1);
Step2:バックエンドロジックの実装(FastAPI)
Excelマクロで行っていた発注点計算ロジックを、PythonでAPI化します。
# main.py
from fastapi import FastAPI
from pydantic import BaseModel
from typing import List
app = FastAPI()
# データモデル定義
class Product(BaseModel):
id: int
name: str
current_stock: int
suggested_order: int = 0
# ダミーのDB接続(実際はSQLAlchemy等を使用)
mock_db = [
{"id": 1, "name": "ネジ Type-A", "current_stock": 50, "safety_stock": 20, "lead_time": 5},
{"id": 2, "name": "ボルト M8", "current_stock": 5, "safety_stock": 30, "lead_time": 2},
]
def calculate_order_logic(stock, safety, lead_time):
"""
[脱属人化ポイント]
計算ロジックをここに集約。
在庫が (安全在庫 + リードタイム消費分) を下回ったら発注。
"""
avg_daily_sales = 5 # 簡易化のため固定値
threshold = safety + (lead_time * avg_daily_sales)
if stock < threshold:
return threshold - stock + 50 # 50個を発注ロットとする
return 0
@app.get("/api/inventory", response_model=List[Product])
def get_inventory():
results = []
for item in mock_db:
# サーバー側で計算を実行
suggestion = calculate_order_logic(
item["current_stock"],
item["safety_stock"],
item["lead_time"]
)
results.append({
"id": item["id"],
"name": item["name"],
"current_stock": item["current_stock"],
"suggested_order": suggestion
})
return results
Step 3: フロントエンド実装 (Luckysheet)
ここが「活Excel」の肝です。Luckysheetを使って、ブラウザ上にスプレッドシートを描画し、APIデータを流し込みます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>在庫管理システム(サンプル)</title>
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/css/pluginsCss.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/plugins.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/css/luckysheet.css' />
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet/dist/assets/iconfont/iconfont.css' />
<script src="https://cdn.jsdelivr.net/npm/luckysheet/dist/plugins/js/plugin.js"></script>
<script src="https://cdn.jsdelivr.net/npm/luckysheet/dist/luckysheet.umd.js"></script>
</head>
<body>
<div id="luckysheet" style="margin:0px;padding:0px;position:absolute;width:100%;height:100%;left:0px;top:0px;"></div>
<script>
document.addEventListener('DOMContentLoaded', async () => {
// 1. APIからデータを取得
const response = await fetch('http://localhost:8000/api/inventory');
const data = await response.json();
// 2. Luckysheet用のデータ形式(Celldata)に変換
// r:行, c:列, v:値(m:表示値, v:実値)
let cellData = [];
// ヘッダー
const headers = ["ID", "商品名", "現在在庫", "システム提案数", "手動調整", "発注確定数"];
headers.forEach((text, index) => {
cellData.push({ r: 0, c: index, v: { v: text, m: text, bg: "#f0f0f0", stat: "1" } }); // stat:1 は太字など
});
// データ行
data.forEach((item, index) => {
const row = index + 1;
cellData.push({ r: row, c: 0, v: { v: item.id, m: String(item.id) } });
cellData.push({ r: row, c: 1, v: { v: item.name, m: item.name } });
cellData.push({ r: row, c: 2, v: { v: item.current_stock, m: String(item.current_stock) } });
cellData.push({ r: row, c: 3, v: { v: item.suggested_order, m: String(item.suggested_order), fc: "#ff0000" } }); // 提案数は赤文字
// 手動調整欄(空欄)
cellData.push({ r: row, c: 4, v: { v: 0, m: "0", bg: "#ffffcc" } }); // 黄色背景で入力可を示唆
// 発注確定数(Excel数式を埋め込む!)
// =D2 + E2 のような形式
const formula = `=D${row + 1}+E${row + 1}`;
cellData.push({ r: row, c: 5, v: { f: formula, v: item.suggested_order } });
});
// 3. Luckysheetの初期化設定
luckysheet.create({
container: 'luckysheet',
title: '在庫発注管理',
lang: 'ja', // 日本語対応
data: [{
"name": "発注リスト",
"celldata": cellData,
"freeze": "A2"
}],
showinfobar: false, // インフォメーションバー非表示
});
});
</script>
</body>
</html>
4. OSS構成のメリット・デメリット
商用製品と比較した際の、現場のリアリティです。
メリット
-
ライセンス費ゼロ: 初期投資なしでPoC(概念実証)やスモールスタートが可能。
-
ブラックボックスなし: コードが公開されているため、バグがあっても自力で調査・修正が可能。
-
コミュニティ: 世界中の開発者が機能追加を行っていす(Luckysheetは非常に高機能です)。
デメリット・注意点
-
公式サポートがない: トラブル時は自己解決か、コミュニティ頼みになります。
-
ドキュメントの壁: Luckysheetは中国発祥のため、一部ドキュメントが中国語メインだったり、英語が不十分な場合があります。
-
印刷・PDF出力: 商用版ほど完璧な「帳票印刷機能」を持っていないことが多く、PDF生成はバックエンド側(PythonのReportLabなど)で実装する工夫が必要です。
まとめ
予算がなくても、技術選定次第で「脱Excel」と「活Excel」の両立は可能です。 特にLuckysheetのようなOSSは、現場ユーザーが求める「あのExcelの操作感」をWeb上で再現してくれます。
まずは、身近なExcelを一つ、OSSでWebアプリ化してみませんか? 現場の業務を少しでも楽にしましょう!