Topics

I Built a Purchase Order Generator Desktop App with Claude Code Because We Needed One

  • column

In our day-to-day work, whenever we run into something that's a bit too tedious to keep doing by hand, our go-to answer has become: build a small system with Claude Code!

This time was a perfect example of that, and it was triggered by increasing our company's capital.

Our fiscal year begins in February, and we carried out this capital increase in February as well. With more capital, we needed to organize our ordering processes with external partners and subcontractors more rigorously than ever before.

This is the area often referred to as the Subcontract Act, which, under the current system, has been called the "Act on Ensuring Appropriate Transactions" since January 2026. As the ordering party, there are more obligations to handle, such as clearly stating the order details, preparing and retaining transaction documents, and setting payment due dates.

Of course, this isn't just a matter of "doing it because the law requires it"!

When we ask external partners to take on work, it's important for both the ordering and receiving parties to clearly define the order details, amounts, dates, and how they correspond to the quotation. (Kiri)

It also wasn't a feature built into accounting tools.

We use MoneyForward (hereinafter "Manebo") tools for accounting, quoting, and invoicing.
They're convenient for day-to-day accounting and billing, but what we wanted to do this time was a little different.

Creating a Liberogic purchase order PDF based on a quote PDF received from an external partner

At least within the scope we use it, MoneyForward doesn't have a feature that fits well, and signing up for a service just for this would feel like a waste, right?

If we were to do it by hand,

  • Create a purchase order format
  • Manually transcribe the quote into the purchase order format while referring to the quote
  • Enter the purchase order date
  • Transcribe the quote number
  • Transcribe the line items
  • Check the details, such as the total amount
  • Tidying up file names
  • Miscellaneous, miscellaneous...

Tedious, right? As this task kept piling up... so we decided to build something for it.

Made practical in under an hour with Claude Code

The timing was good, too.

The start of our fiscal year in February, a capital increase in February, and the release of Claude Code and its adoption among our staff all happened at the same time.

At the time, our team had just started a hackathon-style push: using tools like Claude Code to build internal productivity tools and small internal apps, and even shipping side ideas, all the way to deployment!

From a very simple spec outline to instructions for Claude Code, including fine-tuning details...

We were able to get it to a practical, usable state in just under an hour.

Of course, throwing everything at AI won't finish the job on its own, but when you translate your needs into a well-crafted prompt, it's fast and genuinely handy!

Desktop App Completed

A simple purchase order generator that runs on the OS you're probably using too.

Simply drag and drop a quote PDF onto the dedicated .app file, and a Python script runs, reads the contents of the quote PDF, and generates a purchase order PDF in the same folder.
Once complete, it sends a macOS notification and automatically opens the generated purchase order PDF.

The structure is as follows.

~/Desktop/発注書生成/
 見積書をドロップ→発注書生成.app
 _lib/
  generate_purchase_order.py
  liberogic_logo.png
  liberogic_seal.png
  purchase_order_counter.json

Since we wanted staff in accounting and administration to be able to use it without opening a terminal, we used an AppleScript droplet as the entry point, while the actual PDF generation is handled on the Python side.

In short, it's a desktop app where you drag and drop a quote PDF and a purchase order PDF comes out. Since it can be used without opening a terminal, we designed it to be easy to handle in everyday administrative work.

The design of the purchase order PDF follows the layout of the invoice and quote PDFs we use internally, which are based on MoneyForward's format.
The notes section contains wording such as the following.

This purchase order constitutes a formal order. We place this order based on quote number XXX.

The purchase order number follows the format below.

Purchase Order for {会社略称} {YYYY}{MM}{3桁連番}

For example, for the first purchase order of February 2026 for Mr./Ms. XX,

Purchase Order for XX 202602001

would be generated.

Sequential numbers for each company and month are managed in purchase_order_counter.json, and the order date is automatically calculated as 5 business days after the date on the quotation. (This is just a provisional spec, by the way! I'll change it later under proper management!)
To exclude not only weekends but also Japanese public holidays, I used jpholiday in Python.

A slightly tricky part

The quotations that serve as the basis for purchase orders come from external partners and subcontractors, so the format differs from company to company.
It can't be handled by simply hardcoding rules like "the company name is at this coordinate" or "the total amount is at this position."

In the end, I used regular expressions to extract as flexibly as possible the vendor name, address, TEL, quotation number, quotation date, subject, line items, subtotal, consumption tax, total, and so on. I also made it treat companies marked with "御中" as our own company and anything else as the ordering party. And when extracting text from PDFs, information that looks separated visually often ends up stuck together in the text, and so on and so forth.

There were also cases where building names or floor numbers got mixed in after the subject line, so I added logic that uses markers like "ビル" and "階" as clues to cut out unnecessary address information.

Whether it's AI or anything else, this is the usual PDF processing headache.

Prompt given to Claude Code

Rather than vague requests, it's more economical in terms of token usage to be as specific as possible, covering things like folder structure, processing flow, layout, numbering rules, business day calculations, and PDF extraction fields.
Let it read the sample PDF too!

以下の条件で、見積書PDFを発注書PDFに自動変換するツールをmacOS向けに作ってください。

## 環境

- macOS / Python3(pip可)
- フォント:`~/Library/Fonts/NotoSansJP-Regular.ttf` / `NotoSansJP-Bold.ttf`

## フォルダ構成

`~/Desktop/発注書生成/
  見積書をドロップ→発注書生成.app
  _lib/
    generate_purchase_order.py
    liberogic_logo.png
    liberogic_seal.png
    purchase_order_counter.json`

## 処理フロー

1. `.app` に見積書PDFをドラッグ&ドロップ
2. Pythonスクリプトを実行し発注書PDFを生成
3. 完了通知(macOS通知)を出して発注書PDFを自動で開く
4. 発注書PDFは見積書と同じフォルダに保存

## 発注書の仕様

出力フォーマットは添付のMoneyForward形式のPDFに合わせること。

このPDFから以下を抽出して使う:

- ロゴ画像
- 押印画像
- レイアウト座標
- 列幅
- 余白
- フォントサイズ

## 自社情報

リベロジック株式会社
登録番号:T2010401081132
〒108-0073 東京都港区三田1-3-37 板金会館2F
TEL: 03-6809-4366 / FAX: 03-6809-4367

## 発注書番号

- 形式:`{会社略称}様 発注書{YYYY}{MM}{3桁連番}`
- 会社別・月別の連番を `purchase_order_counter.json` で管理
- 出力ファイル名もこの発注書番号に揃える

## 発注日

- 見積書の日付から5営業日後
- 土日と日本の祝日を除外する

## 見積書からの情報抽出

- どんな会社のフォーマットでも対応できる柔軟な正規表現で抽出
- 抽出項目:ベンダー名・住所・TEL、見積書番号、見積日、件名、明細、小計・消費税・合計
- ベンダー判定:「御中」の付いた会社=自社、それ以外=発注先
- 件名に住所の建物名が混入するケースに対応

## 発注書レイアウト

- タイトル「発注書」中央大文字
- 左:発注先の社名・住所・TEL
- 右:自社情報+ロゴ+押印+発注書番号・発注日・見積書番号・見積日
- 件名・発注金額を大きく表示
- 明細テーブル:品目/単価/数量/単位/価格
- 交互グレー背景
- 最低8行
- 合計エリア:小計・消費税・合計のみ
- 備考欄を枠付きで表示
- ページ番号なし

It's essentially a simple spec sheet, but it's important to give concrete business constraints and a clear picture of the finished result, rather than just saying "make something nice."
Ultimately, if you feed it a different format, it tends to fail, so you do need to push Claude a bit further, but it's still fast, so I think it's worth it.
(Our outside staff and partner collaborators don't even add up to double digits, so it's not a big deal!)

Because it's convenient, we also need to watch security

On the other hand, when using AI development assistance, you need to consider security as well as convenience.

While giving instructions to Claude Code and moving work forward, a number of operations are performed on the local environment.

- ~/Desktop へのファイル読み書き
- ~/Library/Services/ へのアクセス検討
- pip install によるPythonライブラリの追加
- osacompile によるAppleScriptアプリの生成
- ~/Library/Fonts/ にあるフォントファイルの読み取り

This isn't a major topic, but once you give AI execution permissions on your local environment, it's honestly a little scary, isn't it? 😨

When you let it handle terminal and file operations, there's a possibility of unintended file creation, overwriting, or deletion, so

  • Check what you're permitting!
  • Take a backup!
  • For anything managed by git, check the diff!
  • Let's separate the working folders!

Basic measures like these are important. If you use it for development work, it may be a good idea to load your .env file through 1Password. It's a bit of a hassle, but it makes a noticeable difference. (by our CTO)

On the other hand, if it is only used to run locally, as in this case, the risk is relatively limited. It is rare for effects to spread externally over the network, and in most cases the impact stays within "the worst case being an effect on your own environment."

There are many other things to keep in mind, but "being quick to build" and "being safe to use" are two different issues. When developing with AI, let's check permissions for execution, file operations, external libraries, and how input data is handled as we go!

Next: Staff sharing and Supabase integration

So, what I built this time is a simple purchase order generation tool that runs in a local environment.

In the initial stage, I managed sequential numbers by company and by month using purchase_order_counter.json. However, when considering sharing it with staff, managing sequential numbers with local JSON files alone naturally leads to various issues, such as duplicate purchase order numbers.

So I plan to keep counters by company and by month in Supabase, so multiple users can work without duplicate numbers. I also plan to implement purchase order issue history, supplier, quote number, order amount, order date, and PDF storage location!

About the author

Though I'm the president, I'm always a hands-on counterpart. I take joy in understanding new technologies and in those moments when something becomes more convenient, and I love being completely absorbed in the work on the ground. I get excited about future technologies and want to keep enjoying new experiences no matter how old I get.

Tadanori Morimoto

Project Manager / Director / Founded 2007

View this staff member's articles

Reliable team structure and responsive support are our strengths

Liberogic's experienced staff actively drive projects forward, which has earned high praise from our clients.
We make sure to properly assign project managers and directors to keep the entire project running smoothly. Our style of allocating resources to the right people, rather than adding full-time commitment unnecessarily, helps prevent cost increases. We are also known for our speed, from understanding the scope of work to preparing and submitting estimates.

Note: Please be advised that we do not actively engage in SES-style on-site staffing assignments.

We support nearly all major project management and chat tools, including Slack, Teams, Redmine, Backlog, Asana, Jira, Notion, Google Workspace, Zoom, and Webex.

Have a web challenge? Let us know.

Case Studies