2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

商品購入アプリのカートの中身を自動でExcel領収書に転記する

2
Last updated at Posted at 2026-03-29

はじめに

本記事は、たなさん主催の気ままに勉強会138回 2026/3/7(土)のLT「Office Scriptsの活用について」で紹介したアプリのExcel領収書に転記する機能の紹介です。

Power Appsのほうで購入ボタンを押すと、カートの中身のデータがSharePointリストに登録されるのと同時に、Excel領収書ファイルにも転記できる機能をご紹介しました。

image.png

LTでは簡単にしか説明ができなかったため、アプリ(フローへデータを渡す部分)フロースクリプトの詳細を記事にします。

※領収書はMicrosoft Officeテンプレート領収書を活用させていただいてます。
https://www.microsoft.com/ja-jp/office/pipc/template/result.aspx?id=13284


アプリ(フローへデータを渡す部分)の内容

アプリは以下のような画面になっています。
image.png

Power AutomateにJSONデータを渡す部分について、ようさんが運営されている業務ハックラボ#08~気ままに勉強会で使ったアプリを作るよ~を参考にさせていただきました。
JSONをPower Automateに渡すという手法すら思いつかなく、この手法を知ったときは目から鱗の状態でした(__)

購入ボタンを押すと、以下のようなJSON形式のデータをPower Automateに渡しています。

JSON形式のデータ

カートの中身以外の情報として「customer(顧客名)」「detailNo(明細No)」「orderNo(注文No)」も渡しています。

[
    {
        "amount": 240000,
        "customer": "気ままにデモByまさやん",
        "detailNo": "1",
        "num": 2,
        "orderNo": "PURCHASE-260307191002",
        "price": 120000,
        "product": "ノートパソコン"
    },
    {
        "amount": 80000,
        "customer": "気ままにデモByまさやん",
        "detailNo": "2",
        "num": 1,
        "orderNo": "PURCHASE-260307191002",
        "price": 80000,
        "product": "スマートフォン"
    },
    {
        "amount": 45000,
        "customer": "気ままにデモByまさやん",
        "detailNo": "3",
        "num": 3,
        "orderNo": "PURCHASE-260307191002",
        "price": 15000,
        "product": "デスクチェア"
    }
]

OnSelectプロパティ(購入ボタン)

割愛している部分もあるのですが、以下処理を行っています。※あくまで例です。
1. JSON関数でカートの中身のデータをJSONに変換する。
2. Excel帳票作成のフローを呼び出して引数にJSONとメールアドレスを渡す。
3. エラー判定で失敗した場合はNotify関数でアラートを出力する。

//1.JSON関数でカートの中身のデータをJSONに変換する。
Set(
    loc_Json,
    JSON(
        ShowColumns(
            colOrderTable,明細No,商品,数量,単価,金額,顧客名,注文No),
        JSONFormat.IndentFour
    )
);

//2.Excel帳票作成のフローを呼び出して引数にJSONとメールアドレスを渡す。
UpdateContext({loc_FlowResult:Excel帳票作成.Run(loc_Json, User().Email)});

//3.エラー判定で失敗した場合はNotify関数でアラートを出力する。
If(IsBlankOrError(loc_FlowResult) || loc_FlowResult.msg<>"Succeeded",
    Notify("エラーが発生しました", NotificationType.Error))

フローの内容

全体図は以下のとおりになっています。

image.png

Power AppsV2トリガー

Power Appsから渡されるJSONとメールの文字列を受け取れるようにします。

image.png

変数の初期化

Excel領収書は原本の領収書ファイルをコピーしてスクリプトを実行しますが、そのコピー先のファイル名に使用する「Now変数」を用意します。

また、スクリプトの実行結果(成功or失敗)を記録するために使用する「Condition変数」を用意します。

image.png
「Now変数」はYYYY-MM-ddTHHmmss形式で現在の日時を取得。

formatDateTime(
    convertTimeZone(utcNow(),'UTC','Tokyo Standard Time'),
    'yyyy-MM-ddTHHmmss'
  )

「Conditon変数」はSucceededをあらかじめ設定。

スクリプト実行処理

原本の「領収書ひな形.xlsx」ファイルを「ファイルコンテンツの取得」「ファイルの作成」アクションでコピーします。
ファイル名は「Now変数」を使用して「領収書_YYYY-MM-ddTHHmmss.xlsx」で作成。

「SharePoint ライブラリからスクリプトを実行する」アクションで領収書に転記します。
スクリプトの引数:JsonDataAsStringはPower AppsV2アクションのjsonをそのまま設定。

「チャットまたはチャネルでメッセージを投稿する」アクションでスクリプトを実行した「領収書_YYYY-MM-ddTHHmmss.xlsx」ファイルのリンク通知をTeamsフローボットで自分自身にします。

image.png

エラー時の処理

スクリプトの実行時間が長い場合は制限に引っ掛かかりタイムアウトとなってしまう場合もありますので、「Catch(エラー時)」のスコープを用意して、失敗、スキップ、タイムアウト時は変数「Condition」にFaildを設定しています。
image.png

「Catch(エラー時)」が実行されるタイミングは、成功時以外にすべてチェックしています。
image.png

Power Appsへ応答で返却

スクリプトの成功失敗の結果をアプリに返すため「Condition変数」を返却します。
image.png


スクリプトの内容

コードは以下内容となっています。

function main(workbook: ExcelScript.Workbook, jsonDataAsString: string) {
  //jsonDataAsString:Power AppsからPower Automateに送ったJSON文字列

  //JSON文字列をキー(文字列)と値(文字列、数値、ブールのUnion型)のレコード型のオブジェクト配列に変換
  const dataArray: Record<string, string | number | boolean>[] = JSON.parse(jsonDataAsString);
  //データが空の場合は処理を終了
  if (dataArray.length === 0) {
    console.log("処理対象のデータがありませんでした。");
    return;
  }

  //表の部分は一括書込みをするため、明細No、商品、数量、単価、金額のヘッダー項目を指定
  const headers = ["detailNo", "product", "num", "price", "amount"];

  //JSON配列を二次元配列に変換
  //外側の行ごとの処理 
  const values: (string | number | boolean)[][] = dataArray.map(obj => {
    // ヘッダー項目(明細No、商品、数量、単価、金額)の処理
    return headers.map(header => {
      const value = obj[header];
      return (value == null) ? "" : value;
    });
  });

  //シート名を指定
  const sheet = workbook.getWorksheet("領収書(PC入力用)"); 


  //今日日付をyyyy/mm/dd形式に変換
  const today = new Date();
  const todayWestern  = today.toLocaleDateString("ja-JP", {
    year: "numeric",
    month: "2-digit",
    day: "2-digit"
  });

  //今日日付をyyyy年mm月dd形式に変換
  const todayJapanese = today.toLocaleDateString("ja-JP", {
    year: "numeric",
    month: "long", 
    day: "numeric"
  });

  //発行日~領収日を入力
  workbook.getNamedItem("発行日").getRange().setValue(`発行日: ${todayWestern}`)
  workbook.getNamedItem("注文No").getRange().setValue(`注文No: ${dataArray[0]["orderNo"]}`)
  workbook.getNamedItem("お客様氏名").getRange().setValue(dataArray[0]["customer"])
  workbook.getNamedItem("領収日").getRange().setValue(todayJapanese)

  //明細No~金額を一括転記
  const detailName = workbook.getNamedItem("明細No").getRange()
  const startRow = detailName.getRowIndex();
  const startCol = detailName.getColumnIndex();
  const detailRange = sheet.getRangeByIndexes(startRow, startCol, values.length, headers.length);
  detailRange.setValues(values);

}

データ変換・設定の流れ

上記のコードで重要な変数は以下の3つになります。

変数名 内容
jsonDataAsString 文字列 Power Apps、Power Automateから受取るJSON文字列引数
dataArray オブジェクト配列 上記JSON文字列をスクリプトで使用可能なオブジェクト配列に変換
Values 2次元配列 明細No、商品名、数量、単価、金額を一括設定するための2次元配列

JSON文字列の変換及びExcel領収書反映の設定イメージは以下のとおりです。
image.png

JSON文字列引渡し(変数:jsonDataAsString)

フローからスクリプトにJSON文字列を渡すための引数「jsonDataAsString」を定義。
引数「Workbook」(※必ず指定)に加えて引数「jsonDataAsString」を指定しています。

function main(workbook: ExcelScript.Workbook, jsonDataAsString: string) {

}

オブジェクト配列へ変換(変数:jsonDataAsString → 変数:dataArray)

変数「jsonDataAsString」をキーと値のオブジェクト配列に変換して変数「dataArray」に格納しています。

  //JSON文字列をキー(文字列)と値(文字列、数値、ブールのUnion型)のレコード型のオブジェクト配列に変換
  const dataArray: Record<string, string | number | boolean>[] = JSON.parse(jsonDataAsString);
  //データが空の場合は処理を終了
  if (dataArray.length === 0) {
    console.log("処理対象のデータがありませんでした。");
    return;
  }

処理の流れとしては①→②の流れになります。

image.png

①の変数「jsonDataAsString」は型が文字列になっていますのでそのままでは扱えません。
JSON.parseでオブジェクト配列に変換して、スクリプト内でデータとして扱えるようにしています。

2次元配列へ変換(変数:dataArray → 変数:Values)

オブジェクト配列変数「dataArray」を2次元配列変数「Values」に変換しています。

  //表の部分は一括書込みをするため、明細No、商品、数量、単価、金額のヘッダー項目を指定
  const headers = ["detailNo", "product", "num", "price", "amount"];

  //JSON配列を二次元配列に変換
  //外側の行ごとの処理 
  const values: (string | number | boolean)[][] = dataArray.map(obj => {
    // ヘッダー項目(明細No、商品、数量、単価、金額)の処理
    return headers.map(header => {
      const value = obj[header];
      return (value == null) ? "" : value;
    });
  });

処理の流れとしては②→③の流れになります。
image.png

Excel領収書の明細部分は、明細No、商品名、数量、単価、金額の5項目になります。
配列変数「headers」を宣言して、dataArrayから値を取り出すために5項目のキーを指定しています。

2次元配列変数「Values」は2回map関数を使っています。
外側のmap関数はオブジェクト単位にデータを取り出して、内側のmap関数は列ごとにデータを取り出しています。

内側のmap関数のreturn文で、三項演算子を使用してValueがnullまたはundefinedであれば空文字を返して、そうでなければValueを返すようにしています。

三項演算子:条件式 ? 真の場合の値 : 偽の場合の値; を使用

各項目転記

変換した日付を使用して、発行日、注文No、お客様氏名、領収日の4か所を転記しています。

  //シート名を指定
  const sheet = workbook.getWorksheet("領収書(PC入力用)"); 

  //今日日付をyyyy/mm/dd形式に変換
  const today = new Date();
  const todayWestern  = today.toLocaleDateString("ja-JP", {
    year: "numeric",
    month: "2-digit",
    day: "2-digit"
  });

  //今日日付をyyyy年mm月dd形式に変換
  const todayJapanese = today.toLocaleDateString("ja-JP", {
    year: "numeric",
    month: "long", 
    day: "numeric"
  });

  //発行日~領収日を入力
  workbook.getNamedItem("発行日").getRange().setValue(`発行日: ${todayWestern}`)
  workbook.getNamedItem("注文No").getRange().setValue(`注文No: ${dataArray[0]["orderNo"]}`)
  workbook.getNamedItem("お客様氏名").getRange().setValue(dataArray[0]["customer"])
  workbook.getNamedItem("領収日").getRange().setValue(todayJapanese)

処理のイメージとしては以下のとおりになります。
image.png

発行日、注文Noの転記はテンプレートリテラルを活用しています。
注文Noとお客様氏名は1つ目のオブジェクトの値を参照しています。
getNamedItem関数で事前に名前を付けたセルに範囲を取得して転記を行っています。

明細表転記

明細表に2次元配列変数「Values」を一括で書き込む処理をしています。

  //明細No~金額を一括転記
  const detailName = workbook.getNamedItem("明細No").getRange()
  const startRow = detailName.getRowIndex();
  const startCol = detailName.getColumnIndex();
  const detailRange = sheet.getRangeByIndexes(startRow, startCol, values.length, headers.length);
  detailRange.setValues(values);

処理のイメージとしては以下のとおりになります。
image.png

getNamedItem関数で事前に名前を付けたセルを指定して、getRowIndex関数とgetColumnIndex関数で行列位置を取得して、getRangeByIndexes関数で書き込む範囲を指定します。
最後にsetValues関数を使用して、2次元配列を書込みしています。


終わりに

Office Scriptsはメジャーな機能ではないと思いますが、活用できると手段が増えるように感じました。
たなさん主催の気ままに勉強会#138で登壇もしていまして、もしよろしければ以下スライドを参照いただけますと幸いです。

2
1
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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?