Atrae Tech Blog

People Tech Companyの株式会社アトラエのテックブログです。

国税庁のインボイスWeb-APIを使って、取引先のインボイス制度登録番号を一気に取得してみた

みなさんこんにちは。GreenのCSチームの荻原です。
普段はGreenの利用企業様のサポートをしたりプロダクトを企画をしたりしているのですが、自身の仕事を効率化し業務改善をゴリゴリ進めていたら、いつの間にか社内全体の業務プロセス改善や基幹システム整備なども担当するようになっていました。

今日は社内でインボイス制度に関する対応を効率化できたのでその話をしようと思います。インボイス制度は2023年10月これから多くの会社が対応していくと思いますので、誰かのお役に立てれば嬉しいなと思い記事を投稿することにしました。

何をやったのか

まず経理チームからもらった相談は「現在の取引先のインボイス制度の登録状況を調べたいんだけど、なにか良い方法はないか?」という内容でした。実際僕もGreenのお客様からインボイス制度の登録状況に関するアンケートの入力依頼をもらうことが増えてきており、「インボイス制度もいよいよ始まるな〜」なんて思っていました。

色々と調べてみると、どうやら国税庁が「インボイスWeb-API」なるものを出しており、国税庁が発行している13桁の法人番号さえあれば、適格請求書発行事業者の登録があるかどうかを判別し、登録がある場合は登録番号を取得することができることがわかりました。ありがたい!!

https://www.invoice-kohyo.nta.go.jp/web-api/index.html

以下、実際に利用したコードを載せていますので参考にしてください。

事前準備

今回説明するやり方は事前に準備が必要なものがあります。

①登録状況を調べたい取引先の法人番号リスト
インボイスWeb-APIの利用申請

①法人番号リストについては下記の画像のように法人番号が並んでいるリストを用意してもらえればOKです。このとき、法人番号を昇順(上から小さい順)になるように並べ替えをしておいてください。(インボイスWeb-APIの仕様上、予め昇順に並べておく必要があります)

インボイスWeb-APIの利用申請については下記URLから行えます。申請が承認されるまでに1ヶ月程度かかる可能性があるとのことなので、利用したい方は早めの申請をおすすめします…

https://www.invoice-kohyo.nta.go.jp/web-api/index.html#cmspagelink2

申請が承認されるとAPIを利用するための「アプリケーションID」が発行されますので、こちらを予め取得しておいてください。

GASでAPIから情報を取得するプログラムを作成

ここはエンジニアチームに相談しながら進めました。Googleスプレッドシートの「ツール>Apps Script」からGAS(Google App Script)のエディタを開きコードを生成します。

function myFunction() { 
  get_invoice_by_hojinbango();
}

//-----------------------
// 設定
//-----------------------
const max = 1000; //最大件数
const unit = 10; //APIは1セッション10件まで
const staySecond = 1; //APIの発行間隔[秒]
const apiurl = "https://web-api.invoice-kohyo.nta.go.jp/1/num?id={アプリケーションID}&number=";
const apisuffix = "&type=11&history=0";
//-----------------------
var startRow;
var countSum = 0;
var endFlg = 0;


//-----------------------
// メイン
// ・法人番号をキーに、その登録番号("T"+法人番号)があるかAPIで検索
// ・登録番号が無い場合は、その番号はスルーされる
//   よって10件検索して未登録2件あればレスポンスは8件
// ・レスポンスは登録番号の昇順で返ってくる
//   よってシートはあらかじめ法人番号の昇順でソートしておく
//-----------------------
function get_invoice_by_hojinbango() {
  var sheet, companyinfo, companynum, companynums, count, arrs, i, j, k, countnoresp;
  sheet = SpreadsheetApp.getActiveSheet();
  companynums = [];
  count = 0;
  countnoresp = 0;
  
  //空きセル(スタート位置)を探索し、スタート位置から法人番号を全件取得していく
  var lastrow = sheet.getRange(sheet.getMaxRows(), 3).getNextDataCell(SpreadsheetApp.Direction.UP).getRow();

  for (i = 0; i < unit; i++) {
    companynum = "T" + sheet.getRange(lastrow+i, 2).getValue();
    companynums.push(companynum);
    count++; countSum++;

    // 10件までに最終行に達したら終了
    if (i+lastrow == sheet.getLastRow()) {
      count = 0;
      endFlg++;
      break;
    }
    // 設定した10件ずつ取得
    if (count >= unit) {
      count = 0;
      break;
    }
  }

  //APIから10件取得してくる
  arrs = fetch_info_ten(companynums.join());

  //シートにセット
  for (j = 1; j < companynums.length; j++) {
    //法人番号が同一のときは書き込み、無いときはbreak
    if(j - countnoresp <= arrs.length - 1) { //取得したレスポンス数がjを超えないようにする
      if(companynums[j] === arrs[j - countnoresp][1]) { //登録番号が合致したら
        for (k = 0; k < arrs[j - countnoresp].length; k++) {
          sheet.getRange(lastrow + j, 3 + k).setValue(arrs[j - countnoresp][k+1]);
        }
      } else { //登録番号が合致しなかったら「0」を書き込んで次へ
        sheet.getRange(lastrow + j, 3).setValue(0);
        countnoresp = countnoresp +1; //レスポンスの無かった件数
      }
    } else { //取得したレスポンス数がjを超えたら「0」を書き込んでbreak
      sheet.getRange(lastrow + j, 3).setValue(0);
      break;
    }
  }

  //まだレコードが残っている時は再実行
  if (countSum < max && endFlg < 1) {
    Utilities.sleep(staySecond * 1000);
    get_invoice_by_hojinbango()
  }

}

//-----------------------
// APIで取得したXMLを配列で返す
//-----------------------
function fetch_info_ten(companynums) {
  var arrs,temp;
  // フィードを取得
  var fetchurl = apiurl + companynums + apisuffix;
  const options = {
    "muteHttpExceptions" : true,
  }
  try {
    var response = UrlFetchApp.fetch(fetchurl, options);
  } catch(e) {
    // 例外エラー処理
    Logger.log('Error:')
    Logger.log(e)
  }
  var xmlitems = XmlService.parse(response.getContentText()).getRootElement().getChildren('announcement');
  arrs = [];
  for (var i = 0; i < xmlitems.length; i++) {
    arrs[i] = [];
    arrs[i].push(xmlitems[i].getChildText('sequenceNumber'));
  }
  return arrs;
}

多少勉強すればコードの内容も理解できると思いますが、正直ここはエンジニアの人に相談したほうが早いかもしれません笑

const apiurl = "https://web-api.invoice-kohyo.nta.go.jp/1/num?id={アプリケーションID}&number=";

の部分だけ変更してもらえれば動くと思います。

ちなみにこのコードは下記の記事を参考にしながら、インボイス用に改良しました! stabucky.com

プログラムを実行

「実行」ボタンを押すとプログラムが動き始めて、GASが勝手に登録状況を入力してくれます。登録がない場合には3列目に「0」が、登録がある場合には登録番号が入力されるようになります。

なおGASの実行時間が30分が限度となっており、それを超えるとシステムの実行が止まってしまいます。件数が5000件を超える場合などは、システムが止まったら再度実行をする必要があります。

以上の手順で一気に大量の会社の登録状況を調べられるので、ぜひ参考にしていただければ嬉しいです。(なお記事内のコードなどは勝手に利用頂いてOKですが、もっと良いコードの書き方はあるかもしれません。あくまで参考程度に…そしてこのやり方では個人事業主の登録状況は調べられないのでご注意ください。)

これの結果、具体的にどんなメリットがあった?

アトラエでは全取引先の登録状況と登録番号を30分くらいですべて精査できました!

取引のある会社すべてにアンケートを送って、未回答の企業に催促の連絡をして、アンケートの回答を集計して…みたいな作業がすべて不要になりました。取引先の手間を減らし、自分たちの手間も減らせて、まさにwin-winなプロジェクトでした!IT最高!!

世の中の経理担当の方にこのブログが届き、こんなやり方もあるんだと知るキッカケになれば嬉しいなと思っています。

最後に

アトラエでは一緒に働く仲間を募集しております。
アトラエでは前例の無いことにも積極的に挑戦し、常に生産性の高い会社であろうと日々挑戦を続けています。オフィス内に無料でお酒を飲めるバーもあるので、興味がある方はぜひご連絡ください〜!

speakerdeck.com