1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【GAS】スプレッドシートからkintoneのフィールドを登録する

Last updated at Posted at 2022-07-19

やりたいこと

大量のフィールドをアプリに登録するのがめんどくさいので、スプレッドシートにフィールド情報を入力してkintoneにフィールドを登録&配置させたい。
利用するAPI

おおまかな流れ

  1. 空のアプリを作る
  2. APIトークンを生成(アクセス権はアプリ管理だけでOK)
  3. スプレッドシートにフィールド名やらフィールドコードとかを入力する
  4. スプレッドシートに入力された情報を元にkintoneにフィールドを登録する
  5. スプレッドシートに入力された情報を元にフィールドを配置する

注意

↓のフィールドは対象外。ルックアップとかは設定が多すぎてめんどくさくなった...そのうち作るかも
レコード番号とかは配置はできそうだけどめんどくさくなった...そのうち作るかも
・レコード番号、作成者、更新者、作成日時、更新日時、ルックアップ、関連レコード、サブテーブル

とりあえずフィールドを置く作業を軽減したかったのでフィールド設定の更新には対応してないです。

急ぎで動くものがほしかったのでバリデーションは甘々です。

スプレッドシートの構成

image.png
A列:ここに入力した数字でレイアウトを調整※
D列:対象外以外のフィールドで入力規制
E列:true or false
F列:true or false

※行1が↓に該当します。行数は昇順にしか対応してないので1,10,8とかで入力されると想定どおりに動かないです。すみません...
スクリーンショット 2022-07-19 222053.png

コード全体

sample.js
const main = (data) => {
  try{
    const ss = SpreadsheetApp.getActive();
    const sheet = ss.getActiveSheet();
    const columnLength = sheet.getMaxColumns();
    const lastRow = sheet.getLastRow();
    const values = sheet.getRange(2, 1, lastRow - 1, columnLength).getValues();
    const apiToken = data.token;
    const appId = data.appId;
    const domain = data.domain;
    const fieldsBody = getFieldsBody(appId, values);
    const layoutBody = getLayoutBody(appId, values);
    const options = {
      "method": "post",
      "contentType": "application/json",
      "headers": {
        "X-Cybozu-API-Token": apiToken
      },
      "payload": JSON.stringify(fieldsBody)
    };
    const fetchFieldsUrl = `https://${domain}.cybozu.com/k/v1/preview/app/form/fields.json`;
    UrlFetchApp.fetch(fetchFieldsUrl,options);
    options.method = "put";
    options.payload = JSON.stringify(layoutBody);
    const fetchLayoutUrl = `https://${domain}.cybozu.com/k/v1/preview/app/form/layout.json`;
    UrlFetchApp.fetch(fetchLayoutUrl,options);
    Browser.msgBox(`処理が完了しました。設定画面で結果を確認して下さい。https://${domain}.cybozu.com/k/admin/app/flow?app=${appId}#section=form`);
  } catch (err) {
    Browser.msgBox(err)
    console.log(err);
  }
}

const getFieldsBody = (appId, values) => {
  const fieldsBody = {
    "app": appId,
    "properties": {}
  }

  values.forEach(e => {
    const fieldLabel = e[1];
    const fieldCode = e[2];
    const fieldType = e[3];
    const required = e[4] !== "" ? e[4] : false;
    const unique = e[5] !== "" ? e[5] : false;

    fieldsBody.properties[fieldCode] = {
      "type": fieldType,
      "code": fieldCode,
      "label": fieldLabel,
      "required": required,
      "unique": unique,
    }
    if (e[6] !== "") {
      const options = e[6].split(',');
      const optionsObj = {}
      for (let i = 0; i < options.length; i++) {
          optionsObj[options[i]] = {
              "label": options[i],
              "index": i
          }
      }
      fieldsBody.properties[fieldCode].options = optionsObj;
    }
    if (fieldType === "LINK") {
      if (e[7] === "") {
        throw new Error(`フィールドコード${fieldCode}にリンクタイプを指定してください。`)
      }
      fieldsBody.properties[fieldCode]["protocol"] = e[7];
    }
    if (fieldType === "CALC") {
      if (e[8] === "") {
        throw new Error(`フィールドコード${fieldCode}に計算式を指定してください。`)
      }
      fieldsBody.properties[fieldCode]["expression"] = e[8];
    }
  });
  return fieldsBody;
}

const getLayoutBody = (appId, values) => {
    const layoutBody = {
        "app": appId,
        "layout": []
    }
    const rows = [];
    values.forEach(e => {
        const rowValue = e[0];
        const fieldCode = e[2];
        const fieldType = e[3];
        if (rows.indexOf(rowValue) === -1) {
            rows.push(rowValue);
            layoutBody.layout.push({
                "type": "ROW",
                "fields": [
                    {
                        "type": fieldType,
                        "code": fieldCode
                    }
                ]
            })
        } else {
            const index = rows.indexOf(rowValue);
            layoutBody.layout[index].fields.push({
                "type": fieldType,
                "code": fieldCode
            })
        }
    });
    return layoutBody;
}

コードの補足

sample.js
const main = (data) => {
  try{
    const ss = SpreadsheetApp.getActive();
    const sheet = ss.getActiveSheet();
    const columnLength = sheet.getMaxColumns();
    const lastRow = sheet.getLastRow();
    const values = sheet.getRange(2, 1, lastRow - 1, columnLength).getValues();
    const apiToken = data.token;
    const appId = data.appId;
    const domain = data.domain; // https://〇〇〇〇.cybozu.comの〇〇〇〇部分だけ

mainの引数のdataは↓のダイアログに入力したものが入ります。コードに直接情報を記載してもらっても問題ないです。
ダイアログの作り方は こちら の記事を参考にしてます。

image.png

sample.js
const fieldsBody = getFieldsBody(appId, values);

getFieldsBody メソッドの処理でフィールド登録用のJSONを作成

sample.js
const layoutBody = getLayoutBody(appId, values);

layoutBody メソッドでフィールドの配置を設定するためのJSONを作成

sample.js
UrlFetchApp.fetch(fetchFieldsUrl,options);

これでまずフィールドをアプリに登録する。

sample.js
options.method = "put";
options.payload = JSON.stringify(layoutBody);
const fetchLayoutUrl = `https://${domain}.cybozu.com/k/v1/preview/app/form/layout.json`;
UrlFetchApp.fetch(fetchLayoutUrl,options);

methodとpayloadの中身を更新して、配置を設定するリクエストを送る

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?