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

[kintone Advent Calendar 2016](http://qiita.com/advent-calendar/2016/kintone) の 12日目です。
Qiita初投稿です。
今日は,linq.js を使って、kintoneに総平均法の単価計算を組み込みたいと思います。

#linq.js とは
linq.jsはこちらからダウンロード

[linq.js](https://linqjs.codeplex.com)

linq.js が何かは、ここに書いてありました。

[JavaScriptで配列をLINQにより処理できるライブラリ「linq.js」を利用するには？ － ＠IT](http://www.atmarkit.co.jp/fdotnet/dotnettips/1058linqjsbasic/linqjsbasic.html)

マイクロソフトのLINQを、有志（多分）が、javascriptに移植した物の様です。
尚、私がこの存在を知ったのは、

[グループ化による件数の集計について cybozu developer network](https://cybozudev.zendesk.com/hc/ja/community/posts/214950763-グループ化による件数の集計について)

このスレッドにあった、rex0220 さんのコメントです。
今回書いたコードも、この rex0200さんの書いたコードが肝です。
（この場を借りてお礼を（笑））

#総平均法による単価計算とは
業務システムで在庫を扱っている方々にはおなじみの計算です。
業務システムエンジニアは、総平均法をシステムに組み込んで初めて、一人前（か？）。

1.先月末時点で10個で1,000円のリンゴがあった(単価100円)
2.今月20個のリンゴを3,000円(単価150円),10個のリンゴを2,000円(単価200円)で買った。
3.じゃあ今手元にあるリンゴ１個あたり、一体いくらなの？

という問題を解決するための計算法ですね。

(先月末在庫金額+当月入庫金額)÷(前月末在庫数量+当月入庫数量)

で、リンゴ１個あたりの単価が計算可能です。
上記例の場合は、リンゴ１個あたり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は処理を起動する為だけの画面です。
##やること
１）商品を全件取得
２）在庫を全件取得
３）入庫を該当期間内全て取得
４）linq.js で各項目の合計と単価計算
５）計算結果を商品に書き込み（計算根拠と計算結果）

本来は商品、在庫、入庫をそれぞれの配列に代入して、linq.jsで連結。というのがスマートだと思うのですが、構文が難しそうなので、今回は、一つの配列に全部放り込んで、それを無理やり合計する方法を取ります。

![画面1.PNG](https://qiita-image-store.s3.amazonaws.com/0/79724/4421ef5b-fdd5-53bd-8da8-37b52c0df151.png)

総平均計算APPに必要なJSを読み込んでおきます。
zaikocal.js は今回のロジックを書き込むJSファイルです。
なんかいらないものがまじっていたらすみません。

![画像0.PNG](https://qiita-image-store.s3.amazonaws.com/0/79724/bea28066-014b-add8-819b-7fa1bac4af8b.png)


##商品全件取得
まずは商品を全件取得して、配列に代入します。
getRecordsAPI()はレコード取得用関数です。

```js:zaikocal.js
		//レコード格納用
		var zaikocal = [];	
		
		//商品全件取得
		var obj = getRecordsAPI(shohinappId, '');

		//商品数分ループ
		for (var j = 0; j < obj.results.records.length; j++) {
			//挿入用文字列生成
			//skubangou				品番
			//heikintanka			総平均計算結果格納用(これいらないよな)
			//zengetuzaikokingaku	前月末残在庫金額
			//zengetsumatsuzan		前月末残在庫数
			//nyuukasuuryou			当月入庫数量
			//nyuukakingakuzeinuki	闘劇入庫金額

			//品番だけ代入。他は０。
			var row = {
				"skubangou" : obj.results.records[j]['skubangou']['value'], 
				"heikintanka" : 0,
				"zengetuzaikokingaku" : 0,
				"zengetsumatsuzan" : 0,
				"nyuukasuuryou" : 0,
				"nyuukakingakuzeinuki" : 0						
				}
			//Objectに挿入
			zaikocal.push(row);
		}

```

##在庫全件取得
在庫全件取得します。

```js: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
```


##該当期間内の入庫を取得します。
期間条件は画面上の値を取得しています。

```js: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で単価計算をします。
```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に代入します。
```js:zaikocal.js
		//最終結果をループして、商品マスタを更新
		for ( var i = 0; i < query1.length; ++i ) {
			var updatesku = query1[i];

			//販売単価更新
			hanbaitankaupdate(updatesku);
			
        } // for
```
hanbaitankaupdate は商品APP更新用の関数です。いるんですよねこういう関数名を付けるプログラマ（ほんとすみません）。

#動作確認
商品APP
りんご
![商品.PNG](https://qiita-image-store.s3.amazonaws.com/0/79724/2945b512-5c1c-78ab-2642-fd7ff6ec7c3a.png)

在庫APP
前月残は 10個で1000円
![在庫.PNG](https://qiita-image-store.s3.amazonaws.com/0/79724/10656b55-9910-de79-cf63-1a17acb2d87a.png)


入庫APP
入庫が2件
![入庫.PNG](https://qiita-image-store.s3.amazonaws.com/0/79724/d3539643-186e-eea8-19c3-291b5cacabac.png)

この条件で計算をかけると、、
![計算.PNG](https://qiita-image-store.s3.amazonaws.com/0/79724/8bf3d6aa-66ea-d1a1-6e61-ec3f49603098.png)

結果！
![結果.PNG](https://qiita-image-store.s3.amazonaws.com/0/79724/2c567d87-d1f5-1cce-c294-85c958230a7a.png)

総平均単価がちゃんと 150円になっていますね。
確認用は計算式を組み込んでいます。
(1,000+5,000)/(10+30)=150円　です。


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