Box Sign: Monitor Sign Request

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

This item monitors the progress of a Sign Request on Box Sign until its completion. File ID of the signed document can be saved when all the signers have signed.

Basic Configs
Step Name
Note
Auto Step icon
Configs for this Auto Step
conf_OAuth2
C1: OAuth2 Setting *
conf_RequestId
C2: Sign Request ID *
conf_Status
C3: Data item to save the status of the sign request
conf_NotSigned
C4-A: Data item to save the signers who have not signed yet
conf_Signed
C4-B: Data item to save the signers who have signed
conf_Declined
C4-C: Data item to save the signer who has declined
conf_SignedFileId
C5: Data item to save the File ID of the signed document
conf_LogFileId
C6: Data item to save the File ID of the signing log

Notes

Capture

See Also

Script (click to open)
  • An XML file that contains the code below is available to download
    • box-sign-request-monitor.xml (C) Questetra, Inc. (MIT License)
    • If you are using Professional, you can modify the contents of this file and use it as your own add-on auto step


// 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 bloggers like this: