kintone Advent Calendar 2016 の 12日目です。
Qiita初投稿です。
今日は,linq.js を使って、kintoneに総平均法の単価計算を組み込みたいと思います。
#linq.js とは
linq.jsはこちらからダウンロード
linq.js が何かは、ここに書いてありました。
JavaScriptで配列をLINQにより処理できるライブラリ「linq.js」を利用するには? - @IT
マイクロソフトのLINQを、有志(多分)が、javascriptに移植した物の様です。
尚、私がこの存在を知ったのは、
グループ化による件数の集計について cybozu developer network
このスレッドにあった、rex0220 さんのコメントです。
今回書いたコードも、この rex0200さんの書いたコードが肝です。
(この場を借りてお礼を(笑))
#総平均法による単価計算とは
業務システムで在庫を扱っている方々にはおなじみの計算です。
業務システムエンジニアは、総平均法をシステムに組み込んで初めて、一人前(か?)。
1.先月末時点で10個で1,000円のリンゴがあった(単価100円)
2.今月20個のリンゴを3,000円(単価150円),10個のリンゴを2,000円(単価200円)で買った。
3.じゃあ今手元にあるリンゴ1個あたり、一体いくらなの?
という問題を解決するための計算法ですね。
(先月末在庫金額+当月入庫金額)÷(前月末在庫数量+当月入庫数量)
で、リンゴ1個あたりの単価が計算可能です。
上記例の場合は、リンゴ1個あたり150円ですね。
#kintoneのAPIは集計弱いです(いつか強くなるはず)
現状は、弱いというか、ないです。
レコード100件の合計を出そうとすると、レコードを100件取得して、それを合計するしかありません。その労力を、linq.jsで解消します。
#早速組み込んでいきます。無駄に長いです。
注意:私、JavaScriptは必要な技術を必要な時に、基礎を無視してかじっていますので、以下のコードも色々とお見苦しいところがあると思います。先にお詫びしておきます。あと良いプログラマは変数名や関数名にローマ字とか使わない方がいいかもしれません。
##APP作成
APP名 | フィールドコード | 表示名 | タイプ |
---|---|---|---|
在庫 | skubangou | 品番 | SINGLE_LINE_TEXT |
zengetsumatsuzan | 前月末残在庫数 | NUMBER | |
zengetuzaikokingaku | 前月末残在庫金額 | NUMBER | |
商品 | skubangou | 品番 | SINGLE_LINE_TEXT |
zengetuzan | 前月残数量 | NUMBER | |
zengetuzankingaku | 前月残金額 | NUMBER | |
nyuukosuu | 当月入庫数量 | NUMBER | |
nyuukokingaku | 当月入庫金額 | NUMBER | |
heikintanka | 総平均単価 | NUMBER | |
recordno | レコード番号 | ||
入庫 | skubangou | 品番 | SINGLE_LINE_TEXT |
nyuukabi | 入荷日 | DATE | |
nyuukasuuryou | 今回入荷数 | NUMBER | |
nyuukatankazeinuki | 入荷単価(税抜) | NUMBER | |
nyuukakingakuzeinuki | 入荷金額(税抜) | CALC | |
総平均計算 | datefrom | 処理日From | DATE |
dateto | 処理日To | DATE | |
zaikocal | 総平均計算 | DROPDOWN |
総平均計算APPは処理を起動する為だけの画面です。
##やること
1)商品を全件取得
2)在庫を全件取得
3)入庫を該当期間内全て取得
4)linq.js で各項目の合計と単価計算
5)計算結果を商品に書き込み(計算根拠と計算結果)
本来は商品、在庫、入庫をそれぞれの配列に代入して、linq.jsで連結。というのがスマートだと思うのですが、構文が難しそうなので、今回は、一つの配列に全部放り込んで、それを無理やり合計する方法を取ります。
総平均計算APPに必要なJSを読み込んでおきます。
zaikocal.js は今回のロジックを書き込むJSファイルです。
なんかいらないものがまじっていたらすみません。
##商品全件取得
まずは商品を全件取得して、配列に代入します。
getRecordsAPI()はレコード取得用関数です。
//レコード格納用
var zaikocal = [];
//商品全件取得
var obj = getRecordsAPI(shohinappId, '');
//商品数分ループ
for (var j = 0; j < obj.results.records.length; j++) {
//挿入用文字列生成
//skubangou 品番
//heikintanka 総平均計算結果格納用(これいらないよな)
//zengetuzaikokingaku 前月末残在庫金額
//zengetsumatsuzan 前月末残在庫数
//nyuukasuuryou 当月入庫数量
//nyuukakingakuzeinuki 闘劇入庫金額
//品番だけ代入。他は0。
var row = {
"skubangou" : obj.results.records[j]['skubangou']['value'],
"heikintanka" : 0,
"zengetuzaikokingaku" : 0,
"zengetsumatsuzan" : 0,
"nyuukasuuryou" : 0,
"nyuukakingakuzeinuki" : 0
}
//Objectに挿入
zaikocal.push(row);
}
##在庫全件取得
在庫全件取得します。
//在庫を全て取得
var obj = getRecordsAPI(stockappId, '');
//在庫全件ループ
for (var j = 0; j < obj.results.records.length; j++) {
//挿入用文字列生成
//品番、前月末在庫金額、前月末在庫数を代入
var row = {
"skubangou" : obj.results.records[j]['skubangou']['value'],
"heikintanka" : 0,
"zengetuzaikokingaku" : Number(obj.results.records[j]['zengetuzaikokingaku']['value']),
"zengetsumatsuzan" : Number(obj.results.records[j]['zengetsumatsuzan']['value']),
"nyuukasuuryou" : 0,
"nyuukakingakuzeinuki" : 0
}
//Objectに挿入
zaikocal.push(row);
}//for
##該当期間内の入庫を取得します。
期間条件は画面上の値を取得しています。
//入庫情報取得
//画面上の日付条件範囲を取得
var strQuery = 'nyuukabi <= "' + mrecord['dateto']['value'] + '"';
strQuery += ' and nyuukabi >= "' + mrecord['datefrom']['value'] + '"';
var obj = getRecordsAPI(nyuukameisaiappId, strQuery);
for (var j = 0; j < obj.results.records.length; j++) {
//挿入用文字列生成
//品番、当月入荷数量、当月入庫金額を代入
var row = {
"skubangou" : obj.results.records[j]['skubangou']['value'],
"heikintanka" : 0,
"zengetuzaikokingaku" : 0,
"zengetsumatsuzan" : 0,
"nyuukasuuryou" : Number(obj.results.records[j]['nyuukasuuryou']['value']),
"nyuukakingakuzeinuki" : Number(obj.results.records[j]['nyuukakingakuzeinuki']['value'])
}
//Objectに挿入
zaikocal.push(row);
}//for
##linq.jsで単価計算をします。
//linqで集計
var query1 = $.Enumerable.From(zaikocal)
.GroupBy("$.skubangou", null,
function (key, g) {
var result = {
skubangou: key,
nyuukasuuryou: g.Sum("$.nyuukasuuryou"),
nyuukakingakuzeinuki: g.Sum("$.nyuukakingakuzeinuki"),
zengetuzaikokingaku: g.Sum("$.zengetuzaikokingaku"),
zengetsumatsuzan: g.Sum("$.zengetsumatsuzan"),
heikintanka: (g.Sum("$.zengetuzaikokingaku") + g.Sum("$.nyuukakingakuzeinuki"))/(g.Sum("$.zengetsumatsuzan")+g.Sum("$.nyuukasuuryou"))
}
return result
})
.ToArray();
上記コードを見て頂くのが一番早いですね。こんな感じで、品番をキーにして、各要素の合計計算や、合計結果を組み合わせた計算の実行が可能です。
超便利ですね。もうJavaScriptでいっぱいループをまわなさくてもいいですね。
早くkintoneのAPIで集計機能実装してほしいですね!
集計結果は、query1 に代入されます。
##計算結果を商品APPに代入します。
//最終結果をループして、商品マスタを更新
for ( var i = 0; i < query1.length; ++i ) {
var updatesku = query1[i];
//販売単価更新
hanbaitankaupdate(updatesku);
} // for
hanbaitankaupdate は商品APP更新用の関数です。いるんですよねこういう関数名を付けるプログラマ(ほんとすみません)。
総平均単価がちゃんと 150円になっていますね。
確認用は計算式を組み込んでいます。
(1,000+5,000)/(10+30)=150円 です。
#まとめ
linq.jsをきちんと勉強すれば、kintoneでの集計処理がすごく楽になりそうな気がしています。サーバーサイドでの集計ではないので、集計対象が大量になると厳しいかもしれません、kintoneの標準APIで集計が可能になるまで、皆さんがんばりましょう。