Start: kintone: Record's Datetime Field
This item starts a Process when the time in a record’s datetime field has passed in a Kintone App. It is also possible to specify “Created datetime” or “Updated datetime” as the datetime field.
Configs: Common
  • Step Name
  • Note
Configs
  • C1: Authorization Setting in which API Token is set *
  • C2: Basic Auth Setting (required if enabled on Kintone)
  • C3: Domain (such as xxxxx.kintone.com or xxxxx.cybozu.com) *
  • C4: Guest Space ID (required if the App is in a Guest Space)
  • C5: App ID *
  • C6: Field Code of Datetime Field to be checked *
  • C7: Search Query
  • C8: Data item to save Record ID *
  • C9: Data item to save Datetime data

Notes

  • To get the API Token, open the App Settings on Kintone and click “API Token” in the App Settings tab

    Click “Generate”, select the Permissions (“View records” permission is required), and click “Save”.

    Do not forget to click “Update App” to apply the update
  • Guest Space ID (only when the Kintone App is in a guest space) and App ID can be confirmed in the API Token settings on Kintone
  • Questetra BPM Suite will periodically poll the Kintone App to check the records
    • If the App has any records whose data matches the search query and whose datetime data in the specified field has now passed, the Process will be started
  • Supported field types are: Date and time, Created datetime and Updated datetime
    • If you specify the field code of Created datetime, Processes will be started for newly created records
    • If you specify the field code of Updated datetime, Processes will be started for newly modified records
  • See the Kintone Reference for the operators and functions that can be used in the search query
    • Query options (order by, limit, offset) are not supported
  • A Process will not be started on the first check; only the check will be done
    • You can confirm the check status from the “Process Log”
  • If the App has a large number of records whose datetime data has passed in a short period of time, the Processes may not be started for all records
    • Approx. 90 Processes every 15 minutes

Capture

See also

Script (click to open)
  • An XML file that contains the code below is available to download
    • kintone-record-datetime-field.xml (C) Questetra, Inc. (MIT License)
      • Just use it for a reference for the codes
      • This file cannot be imported into a Workflow App as an Add-on

/**
 * @typedef {Object} timestamp java.sql.Timestamp オブジェクト
 */

/** 日時フォーマッター */
const datetimeFormatter = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
/**
 * @param {string} str 日時文字列
 * @return {timestamp} java.sql.Timestamp オブジェクト
 */
const parseDatetime = str => new java.sql.Timestamp(datetimeFormatter.parse(str).getTime());

/**
 * configs から必要な情報の取り出し
 * @return {object} result 設定情報
 * @return {string} result.appId アプリ ID
 * @return {string} result.apiUrl API の URL
 * @return {string} result.datetimeField チェック対象の日時データのフィールドコード
 * @return {string} result.query 検索条件
 * @return {string} result.apiToken API トークン
 * @return {string} result.basic Basic 認証設定
 */
const prepare = () => {
    const auth = configs.get("conf_auth");
    const basic = configs.get("conf_basic");
    const domain = configs.get("conf_domain");
    const guestSpaceId = configs.get("conf_guestSpaceId");
    const appId = configs.get("conf_appId");
    const datetimeField = configs.get("conf_datetimeField");
    const query = configs.get("conf_query");

    checkAppId(appId);
    const apiUri = determineApiUri(domain, guestSpaceId);

    const apiToken = httpClient.getOAuth2Token(auth);

    return {
        appId,
        apiUri,
        datetimeField,
        query,
        apiToken,
        basic
    };
};

/**
 * kintone REST API のレコード取得の URI を決定する
 * ドメインが空、または kintone のドメインとして不正な文字列であればエラーとする
 * @param {String} domain  ドメイン
 * @param {String} guestSpaceId  ゲストスペース ID
 * @return {String} apiUri  API の URI
 */
const determineApiUri = (domain, guestSpaceId) => {
    checkDomain(domain);
    let apiUri;
    if (guestSpaceId === "" || guestSpaceId === null) {
        apiUri = `https://${domain}/k/v1/`;
    } else {
        if (!isValidId(guestSpaceId)) {
            throw "Invalid Guest Space ID.";
        }
        apiUri = `https://${domain}/k/guest/${guestSpaceId}/v1/`;
    }
    return apiUri;
};

/**
 * ドメインが空または不正な文字列であればエラーとする
 * @param {String} domain  ドメイン
 */
const checkDomain = (domain) => {
    if (domain === "" || domain === null) {
        throw "Domain is empty.";
    }
    const reg = new RegExp('^[0-9a-zA-Z-]{3,32}.(?:kintone.com|cybozu.com)$');
    if (!reg.test(domain)) {
        throw "Invalid Kintone domain.";
    }
};

/**
 * アプリ ID が空または不正な文字列であればエラーとする
 * @param {String} appId  アプリ ID
 */
const checkAppId = (appId) => {
    if (appId === "" || appId === null) {
        throw "App ID is empty.";
    }
    if (!isValidId(appId)) {
        throw "Invalid App ID.";
    }
};

/**
 * ID が有効か(自然数か)を判定する
 * @param {String} idString  ID の文字列
 * @return {Boolean}  有効な ID かどうか
 */
const isValidId = (idString) => {
    const idReg = new RegExp('^[1-9][0-9]*$');
    return idReg.test(idString);
};

/**
 * レコードの検索
 * @param limit レコード数の上限
 * @param timestampLowerLimit timestamp の下限
 * @return {Array} records レコード一覧
 */
const list = (limit, timestampLowerLimit) => {
    const {
        appId,
        apiUri,
        datetimeField,
        query,
        apiToken,
        basic
    } = prepare();

    const records = getRecords(apiUri, apiToken, basic, {
        appId,
        datetimeField,
        query,
        limit,
        timestampLowerLimit
    });
    logRecords(records);
    return records;
};

/**
 * レコードのログ出力
 * @param {Array} records レコード一覧
 */
const logRecords = (records) => {
    const replacer = (key, value) => value instanceof java.sql.Timestamp ? datetimeFormatter.format(value) : value;
    records.forEach(record => {
        engine.log(JSON.stringify(record, replacer));
    });
};

/**
 * kintone REST API にレコード取得の GET リクエストを送信する
 * @param {String} apiUri  API の URI
 * @param {String} apiToken  API トークン
 * @param {String} basic  Basic 認証設定
 * @param {Object} params API リクエストのパラメータに使用する情報が格納されたオブジェクト
 * @param {string} params.appId アプリ ID
 * @param {string} params.datetimeField 日時データのフィールドコード
 * @param {string} params.query 検索条件
 * @param {number} params.limit 結果件数の上限
 * @param {timestamp} params.timestampLowerLimit timestamp の下限
 * @return {Array} records レコード一覧
 * @return {string} records[].id レコードID + 日時データ
 * @return {string} records[].recordId レコードID
 * @return {timestamp} records[].timestamp レコードの日時データ
 */
const getRecords = (apiUri, apiToken, basic, {
    appId,
    datetimeField,
    query,
    limit,
    timestampLowerLimit
}) => {
    const getRecordsUri = `${apiUri}records.json`;
    engine.log(`API URI: ${getRecordsUri}`);
    engine.log(`appId: ${appId}`);

    let request = httpClient.begin()
        .header("X-Cybozu-API-Token", apiToken)
        .queryParam('app', appId);
    if (basic !== "" && basic !== null) {
        request = request.authSetting(basic);
    }

    let queryString = `${datetimeField} >= "${datetimeFormatter.format(timestampLowerLimit)}" and ${datetimeField} <= NOW()`;
    if (query !== '') {
        queryString = `(${query}) and ${queryString}`;
    }
    queryString = `${queryString} order by ${datetimeField} desc, $id desc limit ${limit}`;
    engine.log(`query: ${queryString}`);
    request = request.queryParam('query', queryString);
    request = request.queryParam('fields[0]', '$id');
    request = request.queryParam('fields[1]', datetimeField);
    const response = request.get(getRecordsUri);

    //when error thrown
    const responseJson = response.getResponseAsString();
    const status = response.getStatusCode();
    if (status >= 300) {
        const accessLog = `---GET request--- ${status}\n${responseJson}\n`;
        engine.log(accessLog);
        throw `Failed to get records. status: ${status}`;
    }
    const json = JSON.parse(responseJson);

    // レコードオブジェクトを整形して返す
    const formatRecord = (record) => {
        const recordId = String(record['$id']['value']);
        const timestamp = parseDatetime(record[datetimeField]['value']);
        // recordId と timestamp の組み合わせを id に。日時データの変更に対応するため。
        const id = `${recordId}_${timestamp.getTime()}`;
        return {
            id,
            recordId,
            timestamp
        };
    };

    return json.records.map(formatRecord);
};

    

1 thought on “Start: kintone: Record’s Datetime Field”

  1. Pingback: Starting Processes According to Records Shown in kintone Calendar. – Questetra Support

Comments are closed.

%d bloggers like this: