Apps Scriptリファレンス: Apps Script Reference |障害・課題追跡: IssueTracker |Google Workspace: Status Dashboard - Summary

2021年8月15日日曜日

Service CloudのCaseをクローズするアクションを追加したい


ここでは

ケースをクローズする「Close Case」アクションを追加したときの手順を書いて行きます。


状況(status)にClosedを表示する方法はこちら↓



以下の道を通って追加できました。

設定 > オブジェクトマネージャー > ケース > ボタン、リンク、およびアクション > 定義済み設定項目値 > ケースページレイアウト > Case Layout > 


FYI
クローズケースクイックアクションを作成する



順番にやっていきます。


まずは左上の歯車アイコンから「設定」を開きます。


「オブジェクトマネージャ」を検索して選択します。


「ケース」を選択します。


「ボタン、リンク、およびアクション」 を選択します。


「新規アクション」を選択します。


「アクション種別」と「表示ラベル」を入力して保存します。
「名前」は自動で入ります。


「保存」を選択します。


定義済み項目値で「新規」を選択します。


項目名で「状況」を選択、特定値で「Closed」を選択して保存します。


ケースページレイアウトで「Case Layout」を選択します。


「モバイルおよび Lightning のアクション」を選択して、「Close Case」を「Salesforce モバイルおよび Lightning Experience アクション」までドラッグ&ドロップして、保存します。


これでケースのフィードに「Close Case」アクションが追加できました。

追加したいボタンを削除するときは、ドラッグ&ドロップを逆に移動して保存すると、ボタン、リンク、およびアクションで削除できるようになる。


参考

クローズケースクイックアクションを作成する

Lightning Experience のケースページレイアウトへのクイックアクションの追加

クローズケースの状況項目を表示するか非表示にするかを選択

ケースのクローズ

ケースの状況選択リスト値に「クローズ」オプションを割り当てられない

Service CloudでCaseの状況(status)に選択肢を追加したい


ここでは

ケースの状況に「Resolved」を追加してみます。





ケース 状況 選択リスト値で新規に「Resolve」を追加します。

設定 > 
オブジェクトマネージャー > 
ケース > 
項目とリレーション > 
状況 > 
ケース 状況 選択リスト値



以下順番にやっていきます。


オブジェクトマネージャ


ケース

項目とリレーション > 状況

ケース 状況 選択リスト値 > 新規

Resolvedを入力 > 保存


これで状況の選択肢に




補足

Closedと同じ完了フラグをつけるには

Resolvedの編集を選択

完了フラグをチェックして保存


完了フラグのついた状況項目を表示するには

「クローズケースの状況項目を表示」 をチェックする必要があるようです。

その方法は以下の記事に書きました。


Service Cloudでケースの状況にClosedを表示したい


以下のように設定すると表示できました。

設定 > サポート設定 > 編集 > クローズケースの状況項目を表示 をチェック > 保存



デフォルトではCaseの状況で「Closed」が選択肢にありません。

このように表示して選択できるようにしたい。



順番にやっていきます。


右上の歯車から設定を選択します。


サポート設定で「クローズケースの状況項目を表示」にチェックが入っていないので


編集を選択します。


クローズケースの状況項目を表示 をチェックして保存します。


これで「Closed」が選択できるようになりました。


参考

クローズケースの状況項目を表示するか非表示にするかを選択

ケースのクローズ

ケースの状況選択リスト値に「クローズ」オプションを割り当てられない

Salesforce APIでCase IDの一覧を取得したい


SOQLを利用して

SELECT+id+from+Case

というクエリでCase IDの一覧を取得してみます。



ここでは
で書いたtoken.gsもトークンをリフレッシュする際に使うため、別ファイルで保存しておきます。

token.gsと今回書くget.gsは別ファイルで持っておく。


事前準備

PropertiesService の UserProperties に access_token を保存しておく
保存する例



get.gs
function getCaseIds() {
  var query = "SELECT id from Case";
  var url = getUserProperty("instance_url") + "/services/data/v47.0/query?q=" + query;// SOQL クエリを実行する
  var response = UrlFetchApp.fetch(url, optionsGet());
  if(response.getResponseCode() === 401) {
    runRefresh();// アクセストークン切れで401ならトークンを更新する
    response = UrlFetchApp.fetch(url, optionsGet());// 再度リクエストを送る
  }
  Logger.log(response);
}

function optionsGet() {
  return {
    "method" : "GET",
    "headers" : {
      "Authorization": "Bearer " + getUserProperty("access_token")
    },
    "muteHttpExceptions": true
  }
}




getData() を実行すると、ログにCase IDの一覧が出力されます。


関連記事



Salesforce APIで使うアクセストークンを取得してリフレッシュ、リボークもしたい(Google Apps Script)


SalesforceのAPIをGoogle Apps Scriptで利用するときの備忘録です。

アクセストークンを取得→保存して、その後リフレッシュとリボークするコードを書きました。

動作環境:Developers Edition



STEP1: GAS
Webアプリを作成する→作り方


STEP2: Salesforce
接続アプリケーションを作成する→作り方


STEP3: GAS
アクセストークンを取得する
UserPropertiesに保存する
リフレッシュトークンでアクセストークンを更新する
リボークしてトークンを無効にする
→この記事


STEP4: GAS
APIにリクエストを送って結果を取得する→TBD


コードの実行

1. Salesforce上で接続アプリケーションを作成した際に発行される「コンシューマ鍵」「コンシューマの秘密」と、GASをWebアプリとして公開したURLを、グローバルの変数に貼り付ける

2. getMyUrl() を実行してログに出たURLにブラウザでアクセスする

3. UserPropertiesにトークン情報が保存される

4. runRefresh() でアクセストークンが更新される

5. runRevoke() でトークン情報を無効にする



token.gs
/************************************
グローバル
************************************/
var client_id = "コンシューマ鍵";
var client_secret = "コンシューマの秘密"
var redirect_uri = "このGASプロジェクトをWebアプリとして公開したURL";

var token_url = "https://login.salesforce.com/services/oauth2/token";

/************************************
//認可コード取得URL
************************************/
function getMyUrl() {
  var url = "https://login.salesforce.com/services/oauth2/authorize?" +// sandboxの場合はinstance_url 
      "response_type=code" + "&" + 
      "client_id=" + client_id + "&" +
      "redirect_uri=" + redirect_uri + "&" +
      "state=mystate";
  Logger.log(url);
}

/************************************
doGet
************************************/
function doGet(e) {// 認可コード取得URLを開いたときに動く処理
  var response = getAccessToken(e);
  setUserProperties( JSON.parse(response));
  return ContentService.createTextOutput(response);// ブラウザに表示する
}

/************************************
getAccessToken
************************************/
function getAccessToken(e) {// 認可コードを利用してトークン情報を取得して返す
  var code = e["parameter"]["code"];
  var payload = {
    "grant_type": "authorization_code",
    "client_id": client_id,
    "client_secret": client_secret,
    "code": code,
    "redirect_uri": redirect_uri
  }
  
  var options = {
    "method": "post",
    "contentType": "application/x-www-form-urlencoded",
    "payload": payload
  };
  var response = UrlFetchApp.fetch(token_url, options);
  return response;
}

/************************************
runRefresh
************************************/
function runRefresh() {// refresh_tokenを使って更新したトークン情報を返す
  var payload = {
    "grant_type": "refresh_token",
    "refresh_token": getUserProperty("refresh_token"),
    "client_id": client_id,
    "client_secret": client_secret
  }
  var options = {
    "method": "post",
    "contentType": "application/x-www-form-urlencoded",
    "payload": payload
  }
  var response = UrlFetchApp.fetch(token_url, options);
  Logger.log(response);
  setUserProperties(JSON.parse(response));
}

/************************************
revokeToken
************************************/
function revokeToken() {
  var url = "https://login.salesforce.com/services/oauth2/revoke";
  var options = {
    "method": "get",
    "contentType": "application/x-www-form-urlencoded",
    "payload": {
      "token": getUserProperty("access_token") // access_tokenをrevokeする場合
      //token: getProp("refresh_token")// refresh_tokenをrevokeする場合
      }
  }
  var response = UrlFetchApp.fetch(url, options);
  Logger.log(response);
}

/************************************
PropertiesService
************************************/
function setUserProperty(key, value) {// ユーザのプロパティに値をひとつ保存する
  PropertiesService.getUserProperties().setProperty(key, value);
}

function setUserProperties(jobj) {// ユーザのプロパティに値をまとめて保存する
  PropertiesService.getUserProperties().setProperties(jobj);
}

function getUserProperty(key) {// ユーザのプロパティから値をひとつ取得する
  return PropertiesService.getUserProperties().getProperty(key);
}

function getUserProperties() {// ユーザのプロパティから値をまとめて取得する
  return PropertiesService.getUserProperties().getProperties();
}




関連記事



2021年8月10日火曜日

配列内の最頻値を求めたい


統計学の勉強中に最頻値を求めようとしてちょっと手こずりました。

書き方は色々あると思います。
ライブラリを使う手もあると思います。


ここでは
与えられた配列から最頻値を出力するまでのプロセスを思うままに書きました。



コード.gsでやること

values = [1,3,2,3,4,2]

という配列内で最も頻度の多い値を

[2, 3]

の形で取得したくて書いたコードです。



コード.gs
/************************************
これを実行する
************************************/
function getMode(){
  const values =[1,3,2,3,4,2];
  const arrays = returnCountValues(values);
  const countKeyObj = returnCountKeyObj(arrays);
  const countValues = returnObjToArray(countKeyObj);
  const mode = returnMode(countValues);
  Logger.log(countValues);
  Logger.log(mode);
}

/************************************
values = [1,3,2,3,4,2]
を
[[1.0, 1.0], [2.0, 2.0], [3.0, 2.0], [4.0, 1.0]]
にして返す
***********************************/
function returnCountValues(values) {
  let arrays = [];
  let count = 1;
  let currentIndex = 0;
  const sortedValues = values.sort();
  for(let i = 0; i < sortedValues.length; i++) {
    if(sortedValues[i] === sortedValues[i-1]) {
      count++;
      arrays[currentIndex-1] = [sortedValues[i], count];
    } else {
      count = 1;
      arrays.push([sortedValues[i], count])
      currentIndex++;
    }
  }
  return arrays;
}

/************************************
arrays = [[1.0, 1.0], [2.0, 2.0], [3.0, 2.0], [4.0, 1.0]]
を
{1=[1.0, 4.0], 2=[2.0, 3.0]}
にして返す
************************************/
function returnCountKeyObj(arrays) {
  let obj = {};
  for(let i = 0; i < arrays.length; i++) {
    const array = arrays[i];
    if(obj[array[1]]) {
      obj[array[1]].push(array[0])
    } else {
      obj[array[1]] = [array[0]];
    }
  }
  return obj;
}

/************************************
obj = {1=[1.0, 4.0], 2=[2.0, 3.0]}
を
[[1, [1.0, 4.0]], [2, [2.0, 3.0]]]
にして返す
************************************/
function returnObjToArray(obj) {
  return Object.entries(obj);
}

/************************************
values = [[1, [1.0, 4.0]], [2, [2.0, 3.0]]]
から
末尾にある最頻値
[2.0, 3.0]
を返す
************************************/
function returnMode(values) {
  const tail = values[values.length - 1];
  const mode = tail[1];
  return mode
}



実行結果









配列内で重複する値の発生数を取得する(二次元配列で返す)


const values = [1, 2, 3, 2] のそれぞれの数値の件数を取得したい

このように
[[1, 1], [2, 2], [3, 1]]

1は1つ
2は2つ
3は1つ



コード.gs
function getCountValues() {
  const values = [1, 2, 3, 2];
  const countValues = returnCountValues(values);
  Logger.log(countValues);
}

function returnCountValues(values) {
  const sortedValues = values.sort();
  const unique = sortedValues.filter(returnUnique);

  let arrays = [];
  for(let i = 0; i < unique.length; i++) {
    const value = unique[i];
    const count = findDup(value, values);
    arrays.push([value, count]);
  }
  return arrays;
}

function findDup(value, values) {
  let count = 0;
  for(let i = 0; i < values.length; i++) {
    if(values[i] === value) {
      count++;
    }
  }
  return count;
}

function returnUnique(value, index, array){
  var valueIndex = array.indexOf(value);
  var result = valueIndex === index;
  Logger.log([array, "の中で", value, "は", valueIndex, "番目にあって、現在のindexは", index, "なのでuniqueの配列への追加は", result])
  return result;
}
意訳
これを実行する
valuesを決める
returnCountValuesに渡して
結果をログに出す


valuesの要素ごとの件数を返す
values並べ替える→1,2,2,3
それをユニークにする→1,2,3

結果を入れる配列を用意する
uniqueの数だけ繰り返す
uniqueをひとつずつ取り出して
values内の重複を探して
arraysに追加する

完成したarraysを返す


重複を見つける
countの初期値を0にしておく
valuesの数だけ繰り返す
もしvalues内にvalueと同じ値があれば
countに1追加していく


countを返す


ユニークを返す
arrayの中でvalueが何番目にあるか
それが現在のvalueの位置と同じならtrue, 違うならfalse
ログに出してみる
を返してtrueだけのunique配列を作る


実行結果

[[1.0, 1.0], [2.0, 2.0], [3.0, 1.0]]

returnUniqueの中で何をやっているのかログで確認しています。




別の書き方


コード.gs
function getCountValues(){
  const values = [1,2,3,2,2,2,3,3,3];
  const arrays = returnCountValues(values);
  Logger.log(arrays);
}

function returnCountValues(values) {
  let arrays = [];
  let count = 1;
  let currentIndex = 0;
  const sortedValues = values.sort();
  for(let i = 0; i < sortedValues.length; i++) {
    if(sortedValues[i] === sortedValues[i-1]) {
      count++;
      arrays[currentIndex-1] = [sortedValues[i], count];
    } else {
      count = 1;
      arrays.push([sortedValues[i], count])
      currentIndex++;
    }
  }
  return arrays;
}

実行結果


Latest post

Googleドキュメントに見出しを追加したい

今回の例では、ドキュメントの末尾に「見出しD」 を追加します。 見出しA, B, C, Dのスタイルは、見出し3 ( HEADING3 ) に設定しています。  下記Code.gsの  GOOGLE_DOCUMENT_URL を設定して  addHeadingToEnd()  を...