Posted at
kintoneDay 12

linq.jsでkintoneに総平均法単価計算を組み込む

More than 1 year has passed since last update.

kintone Advent Calendar 2016 の 12日目です。

Qiita初投稿です。

今日は,linq.js を使って、kintoneに総平均法の単価計算を組み込みたいと思います。


linq.js とは

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()はレコード取得用関数です。


zaikocal.js

        //レコード格納用

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);
}



在庫全件取得

在庫全件取得します。


zaikocal.js

        //在庫を全て取得

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



該当期間内の入庫を取得します。

期間条件は画面上の値を取得しています。


zaikocal.js

        //入庫情報取得

//画面上の日付条件範囲を取得
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で単価計算をします。


zaikocal.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に代入します。


zaikocal.js

        //最終結果をループして、商品マスタを更新

for ( var i = 0; i < query1.length; ++i ) {
var updatesku = query1[i];

//販売単価更新
hanbaitankaupdate(updatesku);

} // for


hanbaitankaupdate は商品APP更新用の関数です。いるんですよねこういう関数名を付けるプログラマ(ほんとすみません)。


動作確認

商品APP

りんご

在庫APP

前月残は 10個で1000円

入庫APP

入庫が2件

この条件で計算をかけると、、

結果!

総平均単価がちゃんと 150円になっていますね。

確認用は計算式を組み込んでいます。

(1,000+5,000)/(10+30)=150円 です。


まとめ

linq.jsをきちんと勉強すれば、kintoneでの集計処理がすごく楽になりそうな気がしています。サーバーサイドでの集計ではないので、集計対象が大量になると厳しいかもしれません、kintoneの標準APIで集計が可能になるまで、皆さんがんばりましょう。