Box Sign: 署名リクエストの進捗確認

Box Sign: Monitor Sign Request

この工程は、Box Sign の署名リクエストの進捗を、リクエストが完了するまで確認し続けます。署名者全員が署名を終えると、署名済みドキュメントのファイル ID を保存できます。

Basic Configs
工程名
メモ
Auto Step icon
Configs for this Auto Step
conf_OAuth2
C1: OAuth2 設定 *
conf_RequestId
C2: 署名リクエスト ID *
conf_Status
C3: 署名リクエストのステータスを保存するデータ項目
conf_NotSigned
C4-A: 未署名者のメールアドレス一覧を保存するデータ項目
conf_Signed
C4-B: 署名済みの署名者のメールアドレス一覧を保存するデータ項目
conf_Declined
C4-C: 署名を拒否した署名者のメールアドレスを保存するデータ項目
conf_SignedFileId
C5: 署名済みドキュメントのファイル ID を保存するデータ項目
conf_LogFileId
C6: 署名ログのファイル ID を保存するデータ項目

Notes

Capture

See Also

Script (click to open)
  • 次のスクリプトが記述されている XML ファイルをダウンロードできます
    • box-sign-request-monitor.xml (C) Questetra, Inc. (MIT License)
    • Professional のワークフロー基盤では、ファイル内容を改変しオリジナルのアドオン自動工程として活用できます


// OAuth2 config sample at [OAuth 2.0 Setting]
// - Authorization Endpoint URL: https://account.box.com/api/oauth2/authorize
// - Token Endpoint URL: https://api.box.com/oauth2/token
// - Scope: sign_requests.readwrite root_readwrite
// - Consumer Key: (Get by Box Developer Console)
// - Consumer Secret: (Get by Box Developer Console)

const SIGNED_STATUS = 'signed';

const PROCESSING_STATUSES = [
    'converting',
    'created',
    'sent',
    'viewed',
    'finalizing'
];

function main(){
    //// == 工程コンフィグ・ワークフローデータの参照 / Config & Data Retrieving ==
    const oauth2 = configs.get('conf_OAuth2');
    const requestId = retrieveRequestId();
    const dataDefs = retrieveDataDefs();
    
    //// == 演算 / Calculating ==
    if (checkAndSaveStatus(oauth2, requestId, dataDefs) === false) {
        return false;
    }
}

function proceed() {
    return main();
}

/**
  * config から署名リクエスト ID を読み出す
  * 設定値が空の場合はエラー
  * @return {String} requestId 署名リクエスト ID
  */
function retrieveRequestId() {
    const requestId = engine.findData(configs.getObject('conf_RequestId'));
    if (requestId === null) {
        throw 'Sign Request ID is blank.';
    }
    return requestId;
}

/**
  * config からデータ保存先の DataDefinitionView を読み出す
  * @return {Object} dataDefs
  * @return {DataDefinitionView} dataDefs.statusDef
  * @return {DataDefinitionView} dataDefs.notSignedDef
  * @return {DataDefinitionView} dataDefs.signedDef
  * @return {DataDefinitionView} dataDefs.declinedDef
  * @return {DataDefinitionView} dataDefs.signedFileIdDef
  * @return {DataDefinitionView} dataDefs.logFileIdDef
  */
function retrieveDataDefs() {
    const statusDef = configs.getObject('conf_Status');
    const notSignedDef = configs.getObject('conf_NotSigned');
    const signedDef = configs.getObject('conf_Signed');
    const declinedDef = configs.getObject('conf_Declined');
    const signedFileIdDef = configs.getObject('conf_SignedFileId');
    const logFileIdDef = configs.getObject('conf_LogFileId');

    return {
        statusDef,
        notSignedDef,
        signedDef,
        declinedDef,
        signedFileIdDef,
        logFileIdDef
    };
}

/**
  * 署名リクエストのステータスを確認し、保存する
  * @param {String} oauth2 OAuth2 設定
  * @param {String} requestId 署名リクエスト ID
  * @param {Object} dataDefs
  * @param {DataDefinitionView} dataDefs.statusDef
  * @param {DataDefinitionView} dataDefs.notSignedDef
  * @param {DataDefinitionView} dataDefs.signedDef
  * @param {DataDefinitionView} dataDefs.declinedDef
  * @param {DataDefinitionView} dataDefs.signedFileIdDef
  * @param {DataDefinitionView} dataDefs.logFileIdDef
  * @return {Boolean} isFinished 処理中の場合、false
  */
function checkAndSaveStatus(oauth2, requestId, {statusDef, notSignedDef, signedDef, declinedDef, signedFileIdDef, logFileIdDef}) {
    const signRequest = getSignRequest(oauth2, requestId);
    const status = signRequest.status;
    const {notSigned, signed, declined} = classifySigners(signRequest.signers);

    // 処理状況のデータ保存
    setData(statusDef, status);
    setData(notSignedDef, notSigned);
    setData(signedDef, signed);
    setData(declinedDef, declined);

    // 処理中の場合、false を返す
    if (PROCESSING_STATUSES.includes(status)) {
        return false;
    }

    // 処理完了の場合、ログファイルの ID を保存
    if (signRequest.signing_log !== null) {
        setData(logFileIdDef, signRequest.signing_log.id);
    }
    // 署名済みドキュメントの ID は、署名完了時のみ保存
    if (status === SIGNED_STATUS) {
        const signedFileId = signRequest.sign_files.files[0].id;
        setData(signedFileIdDef, signedFileId);
    }
}

/**
  * 署名リクエストを取得
  * @param {String} oauth2 OAuth2 設定
  * @param {String} requestId 署名リクエストの ID
  * @return {Object} signRequest 署名リクエスト
  */
function getSignRequest(oauth2, requestId) {
    const url = `https://api.box.com/2.0/sign_requests/${requestId}`;
    const response = httpClient.begin()
        .authSetting(oauth2)
        .get(url);
    const status = response.getStatusCode();
    const responseTxt = response.getResponseAsString();
    if (status !== 200) {
        engine.log(responseTxt);
        throw `Failed to get Sign Request. status: ${status}`;
    }
    return JSON.parse(responseTxt);
}

/**
  * 署名者を未署名、署名済み、拒否の各グループに分類する
  * @param {Array<Object>} signers 署名者のリスト
  * @return {Object} classified 分類結果
  * @return {String} classified.notSigned 未署名の署名者のメールアドレスのリスト(改行区切りの文字列)
  * @return {String} classified.signed 署名済みの署名者のメールアドレスのリスト(改行区切りの文字列)
  * @return {String} classified.declined 署名を拒否した署名者のメールアドレス
  */
function classifySigners(signers) {
    const notSignedList = [];
    const signedList = [];
    let declined = '';
    signers.forEach(signer => {
        if (signer.role === 'final_copy_reader') {
            return;
        }
        const decision = signer.signer_decision;
        if (decision === null) {
            notSignedList.push(signer.email);
            return;
        }
        if (decision.type === 'signed') {
            signedList.push(signer.email);
            return;
        }
        // 1 人でも拒否した時点で declined ステータスになるので、declined は 1 人だけのはず
        declined = signer.email;
    });
    return {
        notSigned: notSignedList.join('\n'),
        signed: signedList.join('\n'),
        declined
    };
}

/**
  * データ項目にデータを保存する
  * @param {DataDefinitionView} dataDef データ項目の DataDefinitionView
  * @param {Object} value 保存する値
  */
function setData(dataDef, value) {
    if (dataDef !== null) {
        engine.setData(dataDef, value);
    }
}

%d