
目次
請求書の自動生成を作っていると、ほぼ必ず一度は言われる言葉があります。「合計が、いつもの請求書と1円ずれてるんだけど」。
これはプログラムのバグではありません。消費税の端数(1円未満)をどう処理するかという、計算方式の違いから生まれる差です。方式が違えば、正しく計算していても合計は1円ずれます。そして厄介なことに、この1円は「どちらかが間違っている」のではなく、「ルールの決め方が違う」だけのことが多いのです。
この記事では、私たちが実案件(匿名)で踏んだ「1円ずれ」の実例と、インボイス制度での原則、そして実装前に必ず確認していることを整理します。
そもそも、なぜ1円がずれるのか
消費税の計算では、税額に必ず1円未満の端数が出ます。この端数を「切り捨て・切り上げ・四捨五入」のどれで処理するか。そして、どの単位でその処理をするかで、最終的な合計が変わります。
たとえば同じ明細でも、「明細1行ごとに丸めてから足す」のと、「全部足してから最後に1回丸める」のとでは、丸めが発生する回数が違います。回数が違えば、積み上がった端数の合計も変わる——これが1円ずれの正体です。
つまり、ずれをなくす鍵は計算の精度ではなく、丸めのルールをそろえることにあります。
実例1:丸める「単位」が違って1円ずれた
ある案件(匿名)で、請求書の自動生成を作ったときのことです。取引先が普段使っている請求書は、請求書(ヘッダ)単位で税額を丸めて合算する方式でした。
一方、私たちの最初の実装は、明細を全部集計してから、最後に1回だけ丸める方式でした。どちらも計算としては筋が通っています。ですが、丸める単位が違うため、合計すると1円の差が出ました。
対応はシンプルで、取引先の運用に合わせてヘッダ単位で丸める方式に修正し、一致させました。ここで大事なのは、「どちらが正しいか」を議論しなかったことです。請求書は取引先とやり取りする書類なので、相手の運用に合わせるのが基本になります。
実例2:小数の切り捨て「方向」でつまずく
もう1つの実例は、数量に小数が混じるデータでの話です。金額計算で小数を整数に落とすとき、プログラムには複数のやり方があります。
私たちが使っている環境(GAS=Google Apps Script、JavaScript系)には、代表的なものが2つあります。
| 処理 | 挙動 | 負の数のとき |
|---|---|---|
| Math.floor | 小さい方(床方向)へ落とす | -1.2 → -2 |
| Math.trunc | 0の方向へ切り捨てる | -1.2 → -1 |
正の数だけを扱うなら、この2つは同じ結果になります。ところが、値引きや返品などで負の数が混じると挙動が変わります。Math.floorは負の数を「より小さい側」へ落とすため、意図しない方向にずれることがあります。
この案件では、金額の切り捨ては**0方向への切り捨て(Math.trunc)**を採用しました。負の数でも「絶対値を小さくする」動きになり、請求金額の扱いとして自然だったためです。
小さな違いですが、負の明細が1件混じっただけで合計がずれます。どの関数で丸めているかを、方向まで意識して選ぶ必要があります。
インボイス制度の原則:丸めは「税率ごとに1回」
端数処理は運用でそろえるのが基本、と書きましたが、インボイス制度では守るべき原則があります。
インボイス(適格請求書)では、税率ごとに区分した合計額に対して、端数処理は1回までというのが原則です。つまり、8%対象と10%対象をそれぞれ合計し、その合計に対して丸めます。明細行ごとに端数処理をして、それを積み上げる方式は認められていません。
これはシステムの都合ではなく、制度上のルールです。過去に「明細ごとに丸めて足す」やり方をしていた場合、インボイス対応の請求書ではそのまま使えないことがあります。
なお、消費税や請求書の制度は改正されることがあります。実際の請求書に反映する際は、最新の要件を公式(国税庁の資料など)で確認してください。
教訓:確認すべきは「単位・方向・回数」の3点
ここまでの失敗から、私たちは請求書の自動化に入る前に、端数処理について必ず3点を確認するようにしています。
- どの単位で丸めるか:明細行ごとか、税率ごとの合計か、請求書全体か。インボイスの原則に沿いつつ、取引先の運用と合わせます。
- どの方向に丸めるか:切り捨て・切り上げ・四捨五入のどれか。切り捨ての場合は、負の数の扱い(0方向か床方向か)まで決めます。
- 何回丸めるか:途中で何度も丸めると端数が積み上がります。原則は「税率ごとの合計に対して1回」です。
この3点を実装前に取引先とすり合わせておけば、後から「1円合わない」で作り直す事態を避けられます。
突合テストは、過去の請求書と1円単位で
ルールをそろえても、実装が正しいかは別問題です。そこで私たちは、取引先が実際に発行した過去の請求書と、システムの出力を1円単位で突き合わせるテストを行います。
理屈上は合っているはずでも、端数の絡む計算は、実データを通すと想定外のパターンが出てきます。負の明細、小数の数量、税率の混在——こうした「現実のデータ」で確認して初めて、安心して運用に乗せられます。
判断のコツ:ダミーデータだけで「合った」と判断しないこと。端数は過去の実請求書で突合して初めて検証したと言えます。1円のずれは、たいてい現実のデータが教えてくれます。
まとめ
- 請求書の「1円ずれ」は多くの場合バグではなく、端数処理のルールの違いから生まれる
- 丸めは「どの単位で・どの方向に・何回」の3点で結果が変わる。実装前に取引先の運用と合わせる
- インボイス制度では、税率ごとの合計に対して端数処理は1回が原則。明細ごとの積み上げは不可(最新要件は公式で確認)
- 負の数が混じる計算は、切り捨ての方向(0方向か床方向か)で結果が変わる
- 検証は過去の実請求書と1円単位で突合する。ダミーデータだけで判断しない
RENOYでは、請求書や帳票の自動化を、こうした端数処理や既存フォーマットの踏襲まで含めて設計しています。「自動化したいが、いまの請求書と数字が合うか不安」という段階のご相談も歓迎です。まずはお気軽にお問い合わせください。サービス内容をまとめた資料は資料請求からご覧いただけます。
