【kintone】金融機関マスタを作ってみた!

この度、全銀協フォーマットプラグインを作ろうと考えまして、、、それには金融機関の情報が必要です。

都度、レコード内で検索して取得する方法も考えましたが、kintoneアプリでマスタ化していた方が使い勝手が良いかなと思い、金融機関マスタを作ってみようかしら♡ということで自動で取得・更新するプログラムを書いてみました。

まずアプリを作成し、フィールドを用意します。

フィールド名:フィールドコード ※フィールドタイプは、すべて「文字列(1行)」です

  • 金融機関名:bank_code
  • 金融機関コード:bank_code
  • 金融機関(ひらがな):bank_hira
  • 金融機関(カタカナ):bank_kana
  • 金融機関(ローマ字):bank_roma
  • 支店名:branch_name
  • 支店コード:branch_code
  • 支店(ひらがな):branch_hira
  • 支店(カタカナ):branch_kana
  • 支店(ローマ字):branch_roma

使用するライブラリ

以下のライブラリはCybozu CDNから引用している。

  • spin.js
    • https://js.cybozu.com/spinjs/2.3.2/spin.min.js

金融機関を取得するAPI

「銀行くん」(https://bank.teraren.com)

spinner.js

JavaScript
/*******************************************************************************
 *** spinner.js
 ******************************************************************************/

(() => {
  if (!window.KAIZEN) {
    window.KAIZEN = {};
  }

	window.KAIZEN.spinner = {};
	window.KAIZEN.spinner.show = () => {
		if (document.getElementById("kz-spin") === null) {
			const spin_div = document.createElement("div");
						spin_div.id = "kz-spin";
			const spin_bg_div = document.createElement("div");
						spin_bg_div.id = "kz-spin-bg";
			document.body.appendChild(spin_div);
			document.body.appendChild(spin_bg_div);

			spin_div.style.position = "fixed";
			spin_div.style.top = "50%";
			spin_div.style.left = "50%";
			spin_div.style.transform = "translate(-50%, -50%)";
			spin_div.style.backgroundColor = "none";
			spin_div.style.padding = "26px";
			spin_div.style.borderRadius = "4px";
			spin_div.style.zIndex = "510";

			spin_bg_div.style.position = "fixed";
			spin_bg_div.style.top = "0";
			spin_bg_div.style.left = "0";
			spin_bg_div.style.width = "100%";
			spin_bg_div.style.height = "100%";
			spin_bg_div.style.backgroundColor = "#000";
			spin_bg_div.style.opacity = "0.4";
			spin_bg_div.style.filter = "alpha(opacity=50)";
			spin_bg_div.style.zIndex = "500";

			const opts = {
				lines: 12,
				length: 65,
				width: 31,
				radius: 68,
				scale: 0.55,
				corners: 1,
				speed: 1,
				rotate: 19,
				fadeColor: "transparent",
				color: "#FFF"
			};
			new Spinner(opts).spin(spin_div);
		}
		document.getElementById("kz-spin").style.display = "block";
		document.getElementById("kz-spin-bg").style.display = "block";
	}

	window.KAIZEN.spinner.hide = () => {
		document.getElementById("kz-spin").style.display = "none";
		document.getElementById("kz-spin-bg").style.display = "none";
	};
})();

get.js

JavaScript
(function() {
	"use strict";
  const _spinner = window.KAIZEN.spinner;
 
	kintone.events.on("app.record.index.show", (e) => {
    if (document.getElementById("getButton") !== null) return e;
    
    const button = document.createElement("button");
    button.id = "getButton";
    button.innerText = "金融機関データーを取得&更新";
    kintone.app.getHeaderMenuSpaceElement().appendChild(button);
    
    button.onclick = async function() {
      _spinner.show();

      // 現在登録されている銀行情報を取得
	    const records = await getRecords();

      // APIで金融機関情報を取得
      const banks = await getBanks();

      const insertRecords = [];
      const updateRecords = [];

      for (const [i, bank] of banks.entries()) {
        console.log(`${i+1} / ${banks.length}`);
 
        const branches = await getBranches(bank.code);
        for (const branch of branches) {
          const record = records.find(
            x => x.bank_code.value == bank.code &&
            x.branch_code.value == branch.code);

          if (record) {
            updateRecords.push({
              id: record.$id.value,
              record: {
                bank_code: { value: bank.code },
                bank_name: { value: bank.normalize.name },
                bank_hira: { value: bank.normalize.hira },
                bank_kana: { value: bank.normalize.kana },
                bank_roma: { value: bank.normalize.roma },
                branch_code: { value: branch.code },
                branch_name: { value: branch.normalize.name },
                branch_hira: { value: branch.normalize.hira },
                branch_kana: { value: branch.normalize.kana },
                branch_roma: { value: branch.normalize.roma },
              }
            });
          } else {
            insertRecords.push({
              bank_code: { value: bank.code },
              bank_name: { value: bank.normalize.name },
              bank_hira: { value: bank.normalize.hira },
              bank_kana: { value: bank.normalize.kana },
              bank_roma: { value: bank.normalize.roma },
              branch_code: { value: branch.code },
              branch_name: { value: branch.normalize.name },
              branch_hira: { value: branch.normalize.hira },
              branch_kana: { value: branch.normalize.kana },
              branch_roma: { value: branch.normalize.roma },
            })
          }
        }
      }

      // 新規登録
      for (const recs of splitArray(insertRecords)) {
        await postRecords(recs)
      }

      // 更新
      for (const recs of splitArray(updateRecords)) {
        await putRecords(recs)
      }
      _spinner.hide();
      window.location.reload();
    }

    return e;
	});
 
  // レコード全件取得
  function getRecords(app=kintone.app.getId(), query="", offset=0, records=[]) {
		const url = kintone.api.url("/k/v1/records.json", true);
		return kintone.api(url, "GET", {
			app: app,
			query: query + " limit 500 offset " + offset
		}).then((resp) => {
			records = records.concat(resp.records);
			if (resp.records.length == 500) {
				offset += 500;
				return getRecords(app, query, offset, records);
			}
			return records;
		}).catch((err) => {
			console.log(err);
			return false;
		});
	}
 
  // レコード複数登録
  function postRecords(records) {
		const url = kintone.api.url("/k/v1/records.json", true);
		return kintone.api(url, "POST", {
			app: kintone.app.getId(),
			records: records
		}).then((resp) => {
			return resp;
		}).catch((err) => {
			console.log(err);
			return false;
		});
	}
 
  // レコード複数更新
  function putRecords(records) {
		const url = kintone.api.url("/k/v1/records.json", true);
		return kintone.api(url, "PUT", {
			app: kintone.app.getId(),
			records: records
		}).then((resp) => {
			return resp;
		}).catch((err) => {
			console.log(err);
			return false;
		});
	}
 
  // 金融機関リスト取得
	function getBanks(page=1, banks=[]) {
	  const url = `https://bank.teraren.com/banks.json?page=${page}&per=500`;
	  return kintone.proxy(url, "GET", {}, {})
  		.then((resp) => {
  		  if (resp[1] == 200) {
  		    const response = JSON.parse(resp[0]);
  		    banks = banks.concat(response);
  		    if (response.length == 500) {
  		      page++;
  		      return getBanks(page, banks);
  		    }
  			  return banks;
  		  }
  			return false;
  		}).catch((error) => {
  			console.log(error);
  			return false;
  		});
	}
 
  // 支店リスト取得
	function getBranches(code, page=1, branches=[]) {
	  const url = `https://bank.teraren.com/banks/${code}/branches.json?page=${page}&per=500`;
	  return kintone.proxy(url, "GET", {}, {})
  		.then((resp) => {
  		  if (resp[1] == 200) {
  		    const response = JSON.parse(resp[0]);
  		    branches = branches.concat(response);
  		    if (response.length == 500) {
  		      page++;
  		      return getBranches(code, page, branches);
  		    }
  			  return branches;
  		  }
  			return false;
  		}).catch((error) => {
  			console.log(error);
  			return false;
  		});
	}
 
  // 配列を100件ずつ分割
  function splitArray(array, number=100) {
    const length = Math.ceil(array.length / number);
    return new Array(length).fill().map((_, i) =>
      array.slice(i * number, (i + 1) * number)
    );
  }

})();

style.css

CSS
@charset "UTF-8";
#getButton {
  padding: 0 12px;
  height: 48px;
  border: 1px solid #e3e7e8;
  background-color: #f7f9fa;
  box-shadow: 1px 1px 1px #fff inset;
  color: #3498db;
  vertical-align: top;
}
#getButton:hover {
  background-color: #c8d6dd;
  box-shadow: none;
}

あとは、画面上部にある「金融機関データーを取得&更新」ボタンをクリックすれば、約30,000件の金融機関データを登録することができます。

既に登録されているものは更新、なければ新規登録としているので定期的にボタンをクリックして更新すれば良いかと!

是非、皆さんもお試しあれ!

2024.09.24