Skip to content

他の項目から計算する

金額=単価×数量のような、自動で埋まる項目。

他の項目から自動で決まる値は computed に書く。入力が変わると再計算される。

yaml
fields:
  - { field: qty,    label: 数量, type: number, required: true }
  - { field: price,  label: 単価, type: number, required: true }
  - { field: amount, label: 金額, computed: { op: product, fields: [qty, price] } }

op が計算の種類、fields が使う項目。上の例は「金額 = 数量 × 単価」。

同じレコードの項目をまとめる op

op計算
sum足す小計 + 消費税
subtract引く売価 − 原価
product掛ける数量 × 単価
concat文字をつなぐ姓 + 名

concat のときだけ separator で区切り文字を指定できる。

yaml
- { field: fullName, label: 氏名,
    computed: { op: concat, fields: [lastName, firstName], separator: " " } }

計算項目は入力欄にならない

computed を付けた項目は読み取り表示になる。type を書く必要はなく、利用者が直接触ることもできない。だから「金額を手で上書きしたい」という要求には合わない(それは readOnly でもない普通の項目にして、計算はしない)。

明細の1行の中でも使える

subTablefields に書けば、行ごとに計算される。受注明細の「金額」はこれで済む。

yaml
- field: lines
  label: 明細
  type: subTable
  columns:
    - { field: qty,    label: 数量, type: number }
    - { field: price,  label: 単価, type: number }
    - { field: amount, label: 金額, type: number, format: currency }
  fields:
    - { field: qty,    label: 数量, type: number, required: true }
    - { field: price,  label: 単価, type: number, required: true }
    - { field: amount, label: 金額, computed: { op: product, fields: [qty, price] } }

明細の合計(縦計)

fields は同じレコードの項目を指すので、行をまたいだ集計はできない。行をまとめるときは field(明細の項目名)と of(行の項目名)を書く。

yaml
- title: 金額
  fields:
    - { field: subtotal, label: 小計, format: currency,
        computed: { op: sum, field: lines, of: amount } }
    - { field: lineCount, label: 明細行数,
        computed: { op: count, field: lines } }

行を1行足す・数量を直すと、その場で変わる。保存する内容にも入る。

数のまとめ方は5つ。count / sum / avg / min / max(文字にする join は後述)。ダッシュボードのカードや compare の検証と同じ語彙なので、同じ書き方をすれば同じ数が出る。

書き方何が出るか
{ op: sum, field: lines, of: amount }金額の合計
{ op: count, field: lines }行数(of は要らない)
{ op: avg, field: lines, of: price }単価の平均
{ op: max, field: lines, of: amount }一番大きい行の金額

取消した行を外す(where

業務の合計は「全部の行」ではないことが多い。畳む前に行を絞るなら where を書く。

yaml
- { field: subtotal, label: 小計, format: currency,
    computed: { op: sum, field: lines, of: amount,
                where: { field: cancelled, operator: notEquals, value: true } } }

条件の書き方は visibleWhen と同じ(all / any / not も使える)。条件の書き方を 2つ覚える必要はない。ただし判定するのは行1件なので、{ mode: create }(新規のとき) はここでは意味を持たない=常に当たらない(validate が言う)。

絞った結果が 0 件になったときの値は「行が無いとき」と同じ。

品名を1行にまとめる(join

数ではなく文字をまとめるときは join。伝票の「品名」欄や確認画面の要約で要る。

yaml
- { field: itemNames, label: 品名, type: textarea, readOnly: true,
    computed: { op: join, field: lines, of: item, separator: "、" } }

区切りの既定は ", "concat の既定が空なのは姓と名を詰めるためで、行を並べるときに 詰めると読めないから、既定が違う。空の値は飛ばす(区切りだけが並ばないように)。行が 1件も無ければ空文字(0 ではない)。

決まりごと

  • ofcount 以外で必須。無いと空欄になる(validate が先に言う)
  • 行が1件も無いとき sumcount は 0、avg / min / max は空(「平均 0 円」と 出ると読み違えるので、値が定まらないときは空にする)、join は空文字
  • 数として読めない値の行は飛ばす(文字で来た数は読む)
  • 計算は書いた順に1回。小計を使って消費税を出すなら、消費税は小計より後ろに書く (逆に書くと空のまま計算される。画面では空欄に見えるだけなので validate が言う)
  • 畳めるのは親と一緒に保存する明細だけ。source を書いた明細はページ送りで別に 取るので、画面に出ている行を足しても業務の合計にはならない(これも validate が言う)

紙に出す小計(グループごとの小計・総計)は帳票の totals の担当で、これとは別。

依存は絵にできる

順番の警告(computed-order)が出たとき、どこを動かせばいいかは依存を辿らないと分からない。定義から読めるので、絵にできる。

bash
npx hatake diagram order_entry.yaml --computed

Mermaid で出る(PR の本文にそのまま貼れる。--format dot なら Graphviz)。明細の行から親への線も、畳む前の絞り込みが見ている行の項目も出る。順番が逆の線は赤なので、動かす所が色で分かる。

確認画面の表示にも使える

ステップ入力の最後で「入力内容の確認」を見せたいとき、concat でまとめて1項目にすると手軽。

yaml
- { field: summary, label: 登録内容,
    computed: { op: concat, fields: [code, name], separator: " / " } }

足りない計算は足す

op も開いた文字列。税込金額の計算や社内固有の按分ルールなどは、名前を決めて登録すれば op: withTax のように書ける。消費税や年度・元号のような日本の業務でよく要る計算は、Framework 側に道具として用意されている(定義からではなくコードから呼ぶ)。

書けるキー

キー書く場所必須既定値有効なページ種別説明
computedfieldobjectfield.computed任意crud dashboard detail form master report search wizardDerive the field value from the record. Two modes: fields folds values of the same record (concat / sum / subtract / product), while field folds the rows of a subTable (count / sum / avg / min / max — the same aggregate vocabulary as dashboards and compare — plus join, which lists the rows as one string). Row-folding accepts where to keep only some rows. Derived once, in declaration order. Extensible via ComputedRegistry.
opfield.computedstringconcat / sum / subtract / product / count / avg / min / max / join ほか)必須crud dashboard detail form master report search wizardSame-record ops: concat, sum, subtract, product (with fields). Row-folding ops: count, sum, avg, min, max, join (with field). Open string — register your own on ComputedRegistry.
separatorfield.computedstring任意crud dashboard detail form master report search wizardWhat goes between the joined values. Default: empty for concat (it packs values of one record, like a name), ", " for join (it lists rows, which are unreadable packed together).
offield.computedstringamount ほか)任意crud dashboard detail form master report search wizardWhich value of each row to fold. Required except for count. Same meaning as of on the compare validator.
wherefield.computedobjectcondition任意crud dashboard detail form master report search wizardRow-folding mode only: fold just the rows matching this condition, evaluated against one row (the same condition language as visibleWhen). { mode: ... } is never true here — a row has no form mode.

この表は spec/reference.json から生成している(JSON Schema が正)。手元では npx hatake reference <キー名> で同じものが引ける。

近い例

例は丸ごと写して直すのが一番速い。以下は CI で検証済み(そのまま動く形)。

ファイル種別画面どういうときに使うか
customer_wizard.yamlwizard顧客登録項目が多いので入力をステップに分けて、1ステップずつ検証したい
order_entry.yamlform受注入力ヘッダと明細行を1画面で入力して、まとめて保存したい

実物を見る

デモアプリの「受注入力」がこれを使っている。 デモを開く