Articles tagged with: JavaScript

事例:株式会社フラン様


基幹システムと店舗POSレジシステムの刷新にあたって、周辺システムにkintoneを選定

  Topへ↓

株式会社フラン様は、40年以上前の創業時から女性向けランジェリーを扱っておられます。
当初は輸入ランジェリーの販売が主でした。その後、各地のショッピングモールにチェーン展開を始めると同時に商品ラインナップを大幅に見直し、今では豊富なデザイン・機能・サイズのランジェリーを展開しています。
本稿を執筆時点では全国にリアル店舗が19店舗。オンラインショッピングモールに11店舗を出店し、順調に成長しておられます。

フラン様を弊社にご紹介くださったのは株式会社スマレジ様及び大幸パートナーズ株式会社様です。
フラン様と弊社のご縁のきっかけとなったのは、フラン様が各店舗のPOSレジシステムの刷新を行うと決めた時点からです。
フラン様はまず、スマレジ社にお声掛けしました。
スマレジ社の運営するスマレジはPOSレジ機能に特化しています。POSレジ機能を補完するため、スマレジにはアプリストアが用意されています。多くのアプリ群がスマレジの機能を支えています。そのアプリ群の一つにスマレジから請求書を出す「セイキューン」があります。大幸パートナーズ様は、この「セイキューン」を開発・運営されておられます。
ところが、フラン様が望む請求書発行の運用は「セイキューン」で満たせたものの、他の店舗運用を満たすためのアプリがアプリストアにはなく、その解決策をフラン様より相談された大幸パートナーズの五十嵐社長が提案したのがkintoneでした。
そして、kintone側を担うシステム開発会社として弊社を推していただきました。

多種多様の品揃えを管理するための設計

  Topへ↑

スマレジの標準機能では実現できない運用。フラン様の課題は最初から明確でした。

まず、商品管理です。
フラン様が展開するランジェリー商品のラインナップは、上に書いたとおり多種多様にわたります。そのラインアップを支える上で細かい商品管理が欠かせません。ところが、スマレジの備える商品管理機能はフラン様の要望を完全に満たしていませんでした。
例えば、フラン様のランジェリー品目はサイズごと色ごと品番ごとに設けています。それらの商品管理単位(SKU単位)の数はアクティブな点数だけを数えても五万点を超えています。その入力方法はどのように行うのか。データの関連性はどう設定するか。
さらに、SKUの一つ一つにJanCodeを発番する必要があります。スマレジのPOSレジ機能にはその機能がありませんでした。

次に商品物流管理です。
スマレジのリテールビジネスプランには入庫、入荷、出荷、出庫などの機能が備わっています。また、高度な在庫管理機能も備わっています。
ですが、それらの処理をスマレジに指示する際、一店舗ずつ処理を行う必要がありました。
つまり、多店舗×多品種で運用するフラン様の業務上、入力の手間が生じることが予想されていました。

続いて、売上分析機能です。
スマレジが擁する売り上げ分析機能では、経営のかじ取りを行うための分析ができず、分析をkintoneで代替させたいとのご要望もお持ちでした。

あと一つは、オンラインショップの売上データを変換し、そのデータをスマレジの売上データとして登録する機能です。
これもkintoneを経由させ、データを加工させればよいのではという構想をおもちでした。

最後に、ピッキングリストを発行する機能です。これが一番のフラン様のご要望でした。
ピッキングリストとは、倉庫の担当者が商品を棚から選ぶ際のリストの事です。
つまり出荷/出庫予定に対し、迅速に棚から商品を出すリストの出力が喫緊の課題でした。
スマレジはタブレットから簡単に出庫予定を出せます。が、紙のリストを出す機能はありません。SKU点数が多いフラン様の運用上、より運用に即したピッキングリストを出す必要に迫られていました。
望ましいピッキングリストとは、現在の在庫数に加え、入荷・入庫予定を算出してくれるものです。
店舗ごと、SKUごとに設定した在庫定数を下回るか、または指定した任意の期間の売上数に応じた数量を反映したピッキングリストを出すことは、フラン様の各店舗の在庫管理の肝でした。

スマレジはPOSシステムとして優れた機能を持っています。
ですが、それでも上記のようにフラン様のような多品種を扱う業種では補いきれない点がありました。
これらの機能をkintoneで補完し、スマレジのPOSレジ機能の良さを生かす。これが今回の案件のミッションでした。

SKUの多さを克服することが大変

  Topへ↑

開発の期間は約半年。
約半年の間、kintoneのアプリ間の連携や、JanCodeの発番機能の実装など、kintone側で出来ることは順次仕上げていきました。
特に商品管理を実現するため、多くのアプリを組み合わせました。品番やSKU、カラーやサイズなど。そうしたアパレル系のお客様ならではの商品管理を実現することがまず最初の難関でした。
フラン様のご担当者と何度もオンラインで打ち合わせを重ね、kintone自体の癖や特徴もお伝えしながら、より良い商品管理につなげていきました。

また、フラン様が求めるSKU単位で商品管理を行うご要望では、多数のレコードが必要でした。
それは、kintoneのレコード数の増加と、レコード数が多いことによる処理時間の増加に直結します。
処理時間を工夫し、タイムアウトエラーを起こさずに処理を実現する。それが開発上でもっとも苦労した点でした。
どうすれば処理時間を短くし、業務に影響を与えぬように短時間で処理を終わらせられるか。

例えば、新たな商品を登録した場合の処理です。
kintoneには商品データの背後に多くのマスタアプリが連なっています。商品データを登録した際、多くのアプリにデータを連動することが求められました。
さらに、kintoneで作ったデータをスマレジに登録する際も大量データによる問題が発生しました。
そのため、当初はフラン様がCSVを取り込む運用を行う想定でしたがうまく行きませんでした。
そこで、当初は開発範囲外だったkintoneからスマレジへの商品登録の必要が生じました。

また、店舗ごとSKUごとに在庫の定数レコードを作成する処理も必要です。
頻繁に新商品が発生するフラン様の場合、細かいデータの連携が必要となります。
当初はデータを連携するためにkintoneの画面上にボタンを設置していました。ところがボタンを押した後に処理を待つ時間が生じ、さらには大量のデータを処理する間にタイムアウトエラーが生じてしまいました。
これは一件ずつ、追加と更新の判断をしながら、大量のレコードをkintoneで処理する必要があったためです。これをどのように制御するか。処理がタイムアウトしてエラーになる事象をどのようにして回避するか、ここでも開発に腐心しました。
こうした処理はkintone内でJavaScriptに担わせる実装をやめ、サーバー内においたphpプログラムに任せるように処理を変更しました。
その際も、夜間バッチや都度処理の併用を幾パターンも試しました。

大量データに関する課題は、ピッキングリストの発行処理でも生じました。商品データ、在庫定数データ、売り上げデータ、そして入荷/入庫予定データ。ピッキングデータを出すまでにはいくつものアプリで大量のデータを扱う必要がありました。
これらの処理も全てphpに移管しました。しかもkintone画面上でもタイムアウトを生じさせないよう、Ajax処理を時折挟んで制御を行い、タイムアウトが生じないような工夫を行いました。

あと、ご要望としてあったのが、スマレジの各種データをバッチでkintoneに取り込む処理の実装てす。これも何度も調整を重ねました。
バッチ処理を実行するのは一時間おきなのか、それとも一日一回なのか。
スマレジのAPIの条件設定も含めて、その実装にもかなりの創意工夫を凝らしました。

スマレジのデータを追加/更新する際、スマレジ側で処理時間のタイムアウトにならないような工夫も必要でした。
そのエラーを回避する検討にもかなりの時間を掛けました。
ブラウザで制御を行うため、一定期間ごとにAjaxで処理を更新する機構はまさにその一つです。
データ数が何万件にもなる場合、kintoneとスマレジの両方で考慮しなければならない点が多く、それらを満たすための処理にはかなりの時間を掛けました。

お客様にもkintoneに関わっていただきながら運用へ

  Topへ↑

並行してフラン様にもkintoneの理解を深めていただきました。
フラン様のご担当者様は、kintoneのコマンドラインツールであるcli-kintoneの使い方を学び、自力で kintoneからの出力処理を実装するまでになりました。
弊社はこうした実装については助言をし、お客様自身で可能なように支援しました。
その助言をもとにkintoneを使いこなしていただけたのは、今回の開発において手応えを感じたことの一つです。

kintoneアプリの修正も双方で連携をとりながら、破綻させずに少しずつ運用開始に向けてkintoneとスマレジの双方で実装を進めていきました。
各店舗のスタッフ様への操作研修も順次実施していただき、無事に11月に運用が開始できました。

特筆すべきは、初めのご挨拶から運用開始まで、一度もフラン様とはオフラインの対面でお会いしていないことです。
全てをリモート(zoomとチャットワーク、たまに電話)の連絡だけでやり切りました。

これは弊社にとっても大きな自信となりました。フラン様の皆様には感謝です。

フラン様より

フラン社の奥村社長はこう語ってくださいました。

「ここまでクライアントの要望を何度もくみ取り対応頂ける開発会社は初めてです!」

弊社のPOSレジの切り替えに伴い、業界でも注目されているスマレジの利用を検討しておりました。機能を調べたところ弊社の運用において不足している機能が多々あり導入を半ば諦めていたころ、ご縁を頂いたのがアクアビット様になります。弊社ではKintoneの利用経験がなく実際の運用にあたり問題が発生しないか心配しておりましたが、アクアビット様の度重なるヒアリングをベースにした開発や問題発生時の素早い対応などにより、当初の心配が嘘のように無くなっていきました。これからも弊社のパートナーとしてサポート頂きたいと思ってます!

フラン社の小林様はこう語ってくださいました。

「kintoneについての知識がゼロの段階から、
毎回のミーティングを通して弊社側の要望や意図を汲み取り、
個別アプリの作成、アプリ間の連携、そしてスマレジとの連携に至るまで、次々と形にして頂けたこと、
またその後大きなトラブルもなく今日まで運用できているのは、
アクアビット様のお力無くしては出来なかったことだと改めて感じています。
運用開始後もエラー発生時の迅速な対応や、改善するために多くのサポート頂き、絶大な安心感を持って日々の運用が出来ていることにも本当に感謝しています。
引き続きどうぞよろしくお願いします。」

フラン様のご紹介

商号 株式会社フラン
本社 〒488-0044 愛知県尾張旭市南本地ヶ原町3-110
TEL 0561-54-6813
代表者 代表取締役 奥村 聡
設立 1981年1月23日
資本金 1000万円
ウェブサイト https://fran-de-lingerie.com/

アクアビット航海記 vol.36〜航海記 その21


あらためまして、合同会社アクアビットの長井です。
弊社の起業までの航海記を書いていきます。以下の文は2018/3/8にアップした当時の文章が喪われたので、一部を修正しています。

衝動的にホームページの作成に取り掛かる


今の私には、いくつもホームページを立ち上げた経験があります。
単にウェブサーバーにファイルをアップロードするだけではありません。サーバー用マシンを購入するところからはじめ、Linuxのディストリビューションのインストールから、Apache、MySQL、PHPをインストールするところまで。
社内ネットワークを敷設しましたし、サーバーの中を開けてメモリーの増設も経験しています。その他にもいろいろと経験を積んできています。

当たり前ですが、そんな私にも初めてホームページを作った時がありました。
真っさらな状態からHTMLの〈head〉タグや〈body〉タグの勉強を始めた瞬間が。今回はその時のことを思い出してみたいと思います。
本連載の主旨である起業への道筋を語るには不可欠のはずなので。

前回の連載で娘の誕生に立ち合った経緯を書きました。その時の感動は、私の内部に記録したい、表現したいという欲を呼び起こしました。娘の誕生の感動をホームページで表現しなければ。そんな衝動に駆られ、私は矢も盾もたまらずホームページ作成に取りかかります。
娘の誕生が12/28だったので、仕事も正月休みに重なっていたことが幸いしました。

私の知る限り、その当時はブラウザーを使ったウェブアプリは一般的ではありませんでした。もちろん、スカパーのカスタマーセンターの中でも私の知る範囲では使われていなかったはずです。というのも、ブラウザーといえばInternet ExplorerかNetscape Navigatorの二択だった時代。ブラウザーとはシステムのためのものではなく、あくまでもビジネスの広告媒体、つまりホームページの表示用のソフトでした。つまり、私も含めた大多数の人にとってブラウザーとは誰かがアップしたページを見るだけの場所でした。

もちろん、私の知識もその程度。ですから、技術的にも大したページは作れません。ページも静的なHTMLだけで作りました。CGIどころかJavaScriptも皆無。CSSすら適用しなかったように記憶しています。フォントサイズはCSSで指定せず、フォントタグの中の要素値として指定するのが一般的でした。
ホームページの設置場所もどこに置けば適切なのか分からず、ドメインについての知識もありません。そこで、当時加入していたインターネット接続プロバイダー(DTI)の加入者用スペースを利用しました。そこにFTP接続用のソフト(FFFTP)で接続し、HTMLで組み上げたファイルと画像をアップロードします。そうすると、プロバイダーから割り当てられたURLでページが閲覧できました。

独学でホームページ作成を学ぶ


私は一からホームページの作り方やアップロードのやり方を調べました。どのようにすればホームページがアップロードできるのか。ページが表示できるのか。確か「とほほのWWW入門」には多大なお世話になったはずです。
その結果、娘が生まれた次の日あたりにはホームページをアップすることができました。確か、取りかかってから半日程度だったはずです。ちょうどその時、娘の誕生を応援するため、私の母も東京に来ていました。出来上がったばかりのホームページをうちの母に見てもらいました。

今の私の感覚からすると単に〈html〉や〈img〉タグを組み合わせただけのページに半日はかかりすぎです。でも、それも無理はありません。
私にホームページのいろはを教えてくれる先生はおらず、サーバーやネットワークの概念から独りで学ぶ必要がありました。学びつつ作業する。ですから半日でアップできたのはむしろ早かったともいえます。
この時、独学でホームページの仕組みを学んだことは、私のその後に有益でした。もちろん起業の上でも。

冒頭にも書いたように、今の私はホームページの仕組みについてさまざまな経験を積んできています。それらの知識はほぼ独学で学びました。
芦屋市役所で学んだマクロの初歩も、スカパーで集計の仕組みを改良したのも独学。そしてホームページ作成も。
もちろん、芦屋市役所でお世話になったSさんや「集計チーム」で私にアクセスを教えてくれたOさんのように、その時々で私の手本となる方はいました。それでも私は独学で学んだのだとと思っています。
言うまでもなく、独学は学習効率から考えるととても非生産的です。本来は褒められることでも自慢することでもありません。ですが私にとっては独学とは自分の力で得た知識なのです。それは私に自信を与えてくれています。
その経験は尊く、自分の力で手に職を身につけた実感。これは自信となりました。私の起業の本質は独学にあると思っています。

連載の第十九回で妻と出会ったきっかけが電子掲示板であることは書きました。そしてその当時の私が電子掲示板やICQを使って英語で海外の方とコミュニケーションをとっていたことも書きました。しかし、当時の私はただブラウザーを利用するだけでした。裏にどれだけ複雑なロジックが使われているかも意識することもなく。
そんな私がホームページをアップする作業を経験したことで、私にとってブラウザーの位置づけが変わりました。単にホームページを見てコミュニケーションするためのソフトから、コンテンツをアップし自分を表現する場所へ。ホームページを独力でアップしたことにより、私は自分を表現するための手段を手に入れました。

ホームページ作成で起業の発想はなかった


ブラウザーで何かを表現する。この時、私が表現したのは娘の誕生の感動です。
その時ホームページに掲載した十数枚の画像の中には、娘が生まれた瞬間をとらえた際どい画も含まれていました。それも含めてホームページとは表現なのだと思います。
そして、ホームページをアップすることによって、私は表現とはこれほどまでにやりがいのある営みなのかという感触を得ました。
この時、私がもう少しホームページの可能性を真面目にとらえていたら、関西にいる時に抱いていたクリエイティブな職に就きたいとの望みはもっと早くに叶っていたのでしょう。それどころか、ホームページを使った起業さえ成し遂げていたかもしれません。
ただし、それは今だからいえる話。当時の私はそのような発想を全く持っていませんでした。

その頃の私はあいかわらず旺盛に本を読みまくっていました。そして、何かで私自らの生の証しを立てたいと夢想していました。でも、残念ながら、それは夢想でしかなかった。当時の私はあまりにも未熟でした。
しかし未熟であるが故に伸び盛りでもありました。私が自分の伸びしろを持て余し、自分の能力の可能性に戸惑っていました。自分の可能性を感じながら、何に向かって具体的な努力をすれば良いのか、全く理解していませんでした。
今から考えれば、その時の私には強大なチャンスが目の前に転がっていたにもかかわらず。
私の心の中にビジネスで身を立てる発想は皆無でした。

私がビジネスに興味を持てなかった理由。
それは妻の妊娠と娘の出産を控えた親の心情にかかわりがありました。娘には自分が親として教えられることの全てを伝えたい。良き父、良き夫でありたい。そんな理想の家庭像、理想の自分像に私が縛られていたのです。
その幻想は私の眼にはとても魅力的に映りました。クリエイティブな職を目指す余地を奪うほどに。

何にもまして日々の生活が十分なほどクリエイティブだったのですから。娘の誕生、結婚の日常、そして広大な家での生活。仕事も含めて全てが新鮮でした。
そのクリエイティブな状態は、娘が生まれる二年前の自分を比較すると隔世の感すらあります。二年前の私はブラック企業で追い詰められ、何も考えられなくなるまで消耗していました。それから二年。正社員となり、妻をいつくしみ、娘の誕生にまで立ち会えました。しかも持ち家まで構えていられる。
そんな風に恵まれた自分が、その当時の境遇に満足し、上を目指そうと思えなかったのも仕方ないと思えます。その時の私は、クリエイティブな職を目指すだけのモチベーションを持ちようがなかったのです。自分の境遇の変化に追随するだけで精いっぱいだったのでしょう。

ところが、世間的にはステータスであるはずの持ち家が、私を苦しめはじめるのです。
次回からは持ち家の処分について語っていこうと思います。ゆるく永くお願いいたします。


kintoneにシステム移したいんや


kintone Advent Calendar 2020の22日目の記事です。

  Topへ↓

おかげさまで今年はkintoneの案件が大幅に増え、ありがたい限りです。引き続き、頑張っていきまっせ^+++^

さて、案件が増えたのはめっちゃうれしいんやけど、今年は今までと比べ、案件の傾向に少し変化がありましてん。その傾向っちゅうのは旧システムからkintoneへ移行する案件の増加ですねん。
もちろん、昨年までも移行案件は請けてました。でも、今年はC/S(Cliend/Server)型の旧システムからkintoneへの移行案件をぎょうさんご依頼いただきまして。その数はめっちゃ増えましたわ。

おそらく今後もこうした移行案件は増えていくと思てますねん。そやさかい今年のkintone Advent Calendarは7回目の参加にして、初めて連携開発ではなく、移行について書いてみようと思とります。
これからkintoneへのシステム移行を手掛ける方の参考になればうれしいねん。

システム移行の建前と本音

  Topへ↑

システムを移行する目的はお客様によって千差万別です。
でも、システムを移行すると決断するのは経営層、少なくとも部署の責任者でっしゃろ?

この時、経営層と現場でシステムを扱う方の見る視点は違います。
経営層は人件費の削減や処理効率の改善に重きを置きます。一方で現場の視点は日々の業務の負担を軽減することと、業務を止めないことに向きがちです。

その時、建前上では業務改善を同時に行いながらシステム導入も行う、という意見が出ます。そりゃせやんなぁ。わてら提案側にとっても業務改善を錦の御旗に立てたほうが提案は通りやすいっちゅうもんで。

そやけど、往々にして現場の本音とは従来の業務フローを変えずに、なおかつ業務負担が軽くなることにあると思とります。業務改善によってオペレーションが大きく変わるのはいややなあ。新たなやり方になれるまでが大変やわ。てなわけで抵抗を覚えがちです。

わてがこの時に心がけとるんは、営業の相手である経営層や上層部とのお話がまとまったら、なるべく早いうちに現場の業務担当に挨拶し、現場の方とのコミュニケーションを増やし、現場の本音を伺いながら開発することですねん。
この時の建前と本音と取り違えると、あとあとまでボタンの掛け違いがえらいこっちゃになります。
また、営業目線でお客様の上層部とだけ話をしていると、現場のニーズが後から後から噴出してがっちゃがちゃになります。わては何度もこれでえらい目に遭っとります。

構築の順番

  Topへ↑

現場の方にとっては、慣れ親しんだ旧システムからkintoneという未知のシステムに触れるわけです。不安になって当然やんなぁ。
そやからわてはkintoneの良さ、つまり現場の方々が簡単にシステムが触れまっせ、簡単に設定ができまっせ、ということを早めにご説明します。

このあたりは旧来のシステム開発のセオリーとは違いますわな。要件定義、内部/外部設計、コーディング、単体テスト、結合テストが終わったあたりでようやくマニュアルが用意され、ユーザー受け入れテストで現場の方が触る。それが旧来のシステム開発。

わてはkintoneの場合はより早いうちに現場の方に触ってもらうことを重視します。フィールドコードは触らんといて、プラグインやJavaScriptはいじらんといて、という点だけお願いし、あとは積極的に使ってもらいます
その結果、kintoneってうちらでも触れるんや、現場でもシステム開発に参加してええんや、という実感を持ってもらえればもうしめたもんですわ。
この場合の現場というのは現場の統括者ではなく、文字通り日次の業務で手を動かしている方全員のことやからね。

これで現場の方からkintoneへの警戒感や拒否感が取り除けて、システム開発へ参加しているという実感を持ってもろたら、kintoneのファンにだってなってもらえます。そうなればシステム導入の成功は約束されたも同然ですねん。

その時、最後になるまでシステムを見せへん、という手法は逆効果。
まず移行が順調にできていることを示すためにも、一番やりやすいマスタ系からアプリを作っていくとよろしおま。
マスタは業務の基本であり、なおかつマスタアプリ自体には複雑なロジックはそれほど必要ないよって、導入側にとっても取り掛かりやすいはずですわ。
あと、早めにお客様にシステムに関わってもらうことによって、kintoneが苦手な部分をわかってもらうのも重要!なんでかいうたら、システム導入間近になっての仕様変更で断れるからやねん。

また、フィールドの追加や編集も自在にできるkintoneの特性がお客様に喜ばれるのもこの時。もちろん、ビジネスロジックに関わりの少ないフィールドを除いてやで。
例えば分析用に得意先種別を増やしたいねん、というご要望にもさくっと対応できるkintone。このかっこええ姿をアピールするだけで、好感度アップは間違いなしや。

また、ここで現場の方に新旧両方のシステムにマスタの入力を行ってもらえれば、次に述べるデータ移行の手間が大幅に減ります。ほんまやで。

データ移行の基本

  Topへ↑

kintoneへのシステム移行でいっちゃん肝心なんは、おそらくこの部分だと思とります。
kintoneはご存じの通り、簡単にアプリが構築できますやろ。そやから、元のシステムのデータの項目を再現するのはそれほど難しくない。そないに思うかたもおるんとちゃいますか?
ところが、ここを甘く見とったら後で苦労しますねん。

とくに、もともとのシステムの仕様で、マスタ上で管理する項目が制限されとったら要注意です。
入れたい情報を入れるべき項目がない。その場合、おうおうにしてお客様は備考欄にあれこれ詰め込みますねん。苦肉の策で本来ならメールアドレスやURLを入れるべき欄にまで雑多な情報を入れてしまいます。
kintoneでは簡単にフィールドを追加できまっしゃろ?でも、おうおうにして旧システムでは項目を追加するのに別途費用がかかります。だから、そないな状態になってしまうんですわ。
こうした雑多な情報がどこで管理されとるんか。その情報をkinotneのどの項目に移すんか。きちんと体系化されたデータとして活用したいんやったら、お客様ときちんと押さえとかなあきません。

次に、マスタをルックアップで呼び出す際の仕様は早めに定めとかなあきまへんで。御存じの通り、ルックアップでは関連付けるアプリを設定しますよって。
そしたら、コピー元のフィールドも設定せんならん。ルックアップフィールドではフィールドに文字を入力することで、候補を事前に絞り込むことができます。ただしコピー元のフィールドに設定した値に限りますけどな。

例えば得意先マスタの得意先コードを指定しておくと、マスタの得意先コードで検索が可能です。ですが、一度ルックアップフィールドをこさえた後にお客様から得意先名でも検索したい、と言われたらもうバンザイせなあきません。なんでかちゅうたら、コピー元のフィールドは一度設定すると変更でけへんよって。
もしどうしても変更の必要が生じたら、新たにルックアップフィールドを追加せんならんのです。もちろん古いルックアップのデータから新しいルックアップにデータを移さなあかん。そんなんいけずやんかぁ。

また、検索したい対象は得意先名だけに限りません。よくいわれるのは着信時の電話番号の末尾四桁ですわ。それ以外にもフリガナやらなんやら。つまり複数の項目で検索したいというご要望が出てきますねん。
この時は、わては検索キーっちゅう項目を設け、複数の項目の値を連結させとります。
この時はスペースなしでがっちゃんこしてまうとうまく検索がでけへんようになるから、半角スペースなどを間に挟んで連結するとよろしい。

さらに、その時は文字数にも気ぃ付けましょう。コピー元のフィールドに指定できるのは文字列(1行)です。
こちらのヘルプにも書かれとるけど、文字列(1行)の文字数に制限はあらへん。
ところが、今のページにはこうも書かれとったよね。
値の重複の禁止を設定すると、入力できる文字数が全角または半角で64文字までに制限されます、てな感じ。なんでやねん。

では、値の重複の禁止を設定せんかったらええんちゃうん?そう思いたなるやん?え?ならへん? いや、なってぇや。
なぜなら、ヘルプには以下のように書かとるからやねん。
既存のレコードを更新する場合、CSVファイルを読み込んで一括更新する方法が便利やと思うですわ。
けど、ヘルプにはこうも書かれとるねん。

こないな制限があったら、もうあかん。更新がでけへんのですわ。
APIで更新する場合も同じですわ。
ここのリファレンスにも。
システムの移行には、データの更新が欠かせませんわな。CSVで更新する場合も、APIで更新する場合も。
ルックアップ項目を更新するためには、値の重複の禁止せなあきません。ちゅうことは、連結した文字列の文字数が64文字を越えんようにせんならんのです。つまり、移行元のシステムの項目の文字数を考慮にいれなあかんちゅうわけですわ。難儀やなぁ。

もう一つ、移行にあたって注意しておかなあかんことがあります。
それは住所データの扱いです。日本の住所の場合、以下の4つの項目からなっとります。

  • 都道府県
  • 郡市町村
  • 住所(町・字・地番)
  • 建物・マンション名

これが旧システムでも四つに分かれとったら問題ないんよ。
そやけど、住所1、住所2という感じで二つだけのフィールドでしか管理されていない場合、えらいこっちゃになります。

なんでかゆうたら、それを分割する作業が発生するからですわ。分割?そんなんせんでええわ。てゆわれたかて、後々の分析のこと考えたらそうもゆわれへん。正味、お客様に後々の分析のことを考えてと提案してみたら、kintoneでは分割して管理するお客様が多いんですわ。
例えば旧システムの住所1に「東京都中央区日本橋2−7−1」。住所2に「東京日本橋タワー」の値が入っていたとしますやろ。そしたら、住所1から「東京都」「中央区」「日本橋2-7-1」を分割せんならんことになります。さて、ぼんやったらどないする?

わてはそんなとき、VBA(Excelマクロ)を活用しますねん。
その中でこちらのサイトを参考に正規表現から分割しますねん。
この正規表現をVBAの中に仕込んだら、都道府県と郡市町村と住所(町・字・地番)を分割できるんよ。
以下に簡単やけどコードを掲示してみたから、よかったらみてみて。必ず本番では使う前にテストしたってぇやぁ。もちろん当方では一切の責任は負われへんから。

Sub ConvertSplitAddressData()
    Dim regExp              As Object           '正規表現オブジェクト
    Dim strPattern          As String           '正規表現パターン
    Dim lngRowCounter       As Long             '行カウンター
    Dim intRegMatchCount    As Object           '結果
    Const clngMaxRowCount   As Long = 65535     '行の末尾
    Const cintTargetColumn  As Integer = 18     '結合された住所列番号
    Const cintPrefColumn    As Integer = 14     '結果の都道府県を格納する列番号
    Const cintCityColumn    As Integer = 15     '結果の郡市町村を格納する列番号
    Const cintAddressColumn As Integer = 16     '結果の住所を格納する列番号
    Const cintAnotherColumn As Integer = 17     '結果の建物を格納する列番号

    Set regExp = CreateObject("VBScript.RegExp")
    strPattern = "(...??[都道府県])((?:旭川|伊達|石狩|盛岡|奥州|田村|南相馬|那須塩原|東村山|武蔵村山|羽村|十日町|上越|富山|野々市|大町|蒲郡|四日市|姫路|大和郡山|廿日市|下松|岩国|田川|大村)市|.+?郡(?:玉村|大町|.+?)[町村]|.+?市.+?区|.+?[市区町村])(.+)"
    With regExp
        .Pattern = strPattern
        .IgnoreCase = True
        .Global = True
        For lngRowCounter = 2 To clngMaxRowCount
            If ActiveSheet.Cells(lngRowCounter, cintAddressColumn).Value = "" Then
                Set intRegMatchCount = .Execute(ActiveSheet.Cells(lngRowCounter, cintTargetColumn))
                If intRegMatchCount.Count > 0 Then
                    ActiveSheet.Cells(lngRowCounter, cintPrefColumn).Value = Trim(intRegMatchCount(0).SubMatches(0))
                    ActiveSheet.Cells(lngRowCounter, cintCityColumn).Value = Trim(intRegMatchCount(0).SubMatches(1))
                    If InStr(intRegMatchCount(0).SubMatches(2), " ") > 0 Then                '建物以降が全角空白で分割されている場合
                        ActiveSheet.Cells(lngRowCounter, cintAddressColumn).Value = Trim(Mid(intRegMatchCount(0).SubMatches(2), 1, InStr(intRegMatchCount(0).SubMatches(2), " ")))
                        ActiveSheet.Cells(lngRowCounter, cintAnotherColumn).Value = Trim(Mid(intRegMatchCount(0).SubMatches(2), InStr(intRegMatchCount(0).SubMatches(2), " ") + 1, 100))
                    ElseIf InStr(intRegMatchCount(0).SubMatches(2), " ") > 0 Then             '建物以降が半角空白で分割されている場合
                        ActiveSheet.Cells(lngRowCounter, cintAddressColumn).Value = Trim(Mid(intRegMatchCount(0).SubMatches(2), 1, InStr(intRegMatchCount(0).SubMatches(2), " ")))
                        ActiveSheet.Cells(lngRowCounter, cintAnotherColumn).Value = Trim(Mid(intRegMatchCount(0).SubMatches(2), InStr(intRegMatchCount(0).SubMatches(2), " ") + 1, 100))
                    Else                                                                      '建物がないか続けて入力されている場合
                        ActiveSheet.Cells(lngRowCounter, cintAddressColumn).Value = Trim(intRegMatchCount(0).SubMatches(2))
                    End If
                End If
            End If
        Next lngRowCounter
    End With
    Set intRegMatchCount = Nothing
    Set regExp = Nothing
End Sub

データ移行の方法

  Topへ↑

kintoneにデータを取り込む方法はいくつかあります。そやけど、だいたいはCSVによる一括登録・更新か、APIでの登録/更新かcli-kintoneの三択ちゃうやろか。
わてはCSV経由で取り込むことがほとんどですわ。
なんでかいうたら、APIやとHTTP Client Tool for kintoneを使う場合でも、何かのプログラムで書く場合でも、コードのマッピングの記述が面倒になるからやねん。
あと、一リクエストでも100件しか登録や更新ができないAPIの仕様制限があるやんか。そやから、100万件をこえるデータを移行する場合、一日のAPIリクエスト回数制限にも引っかかってしまうんや。
cli-kintoneは便利やねんけど、上と同じくマッピングの部分が手間なのであまり使用しとりません。ただ、余談すると、Bashとcli-kintoneを使った効率化は追及せなあかんと思とります。そやから弊社としてはcli-kintoneを使ったツールの作成ははよ進めよ思てます。
ただ、それでも画面上でマッピングを確認できるcsv取込の方が安全ちゃうかと思います。ここはよぉ考えてみてください。その時、旧システムが出すcsvの見出し項目名とkintoneのフィールドラベルは合わせといたほうが移行マッピングが圧倒的に楽になるで。

先に挙げた住所や備考以外にも、データの加工はあちこちのフィールドで発生しますやろ。それらはめっちゃ面倒やと思うねん。それらをチェックとか加工とかせなあかんから。例えば下のような感じやね。

  • 項目の値の中に半角カンマは入っていないか。
  • 項目の値の中にダブルクォーテーションなどは入っていないか。
  • 項目の値の前後に空白は入っていないか。
  • 旧システムから出力されたファイルの文字コードは統一されているか。(複数のシステムからそれぞれ出力して取り込む場合、Shift-JISとUTF-8が混在しているとkintone側で文字化けの恐れあり)
  • ルックアップの値はkintoneの関連付けるアプリの参照アプリのコピー元のフィールドに等しいか。
  • 電話番号や郵便番号、メールアドレスやURLの書式は正しいか。
  • 日付書式は正しいか。(元データがyyyymmdd形式の場合、空白セルがあると空白に変換してくれずエラーになる等)
  • データの重複はないか。
  • kintoneのラジオボタン/チェックボックス/複数選択/ドロップダウンの選択肢に等しい値のみが含まれているか。

もしでけるんやったら、VBAマクロやcli-kintoneなんかでツールを作ったほうがええと思うで。
あと、ツールの作成と簡単に書いとるけど、旧システムによって項目がまちまちなんは、わかりますやろ?旧システムごとに工数と時間を使うから、わては移行ツールの作成には消極的で、あまりやってへんかったわ。

そやけど、毎度Excelの関数を駆使して移行データを作るんはもうしんどい。わても実は今年手掛けた数々の移行の中で、一つだけめっちゃ苦労した移行がありましてん。それをしおに、めんどいかもしれんけど、移行ツールを作ったほうがええなぁと痛感しましたわ。

ただし、早めにマスタの項目を固め、マスタアプリを作り、初回のデータ移行がでけたところで、それ以降は本番までお客様にマスタデータの入力をしてくれまへんやろか?とお願いしたほうがよろし。もしそれがでけたらマスタの移行ツールはいらんからね。
ま、それでもトランザクションデータの移行に関しては何かしら作らんといかんけどね。

なんでかいうたら、マスタのデータは生き物やねん。お客様によってガーっと追加され、あちこちでバァーっと更新されますやろ。
しかも住所の更新が起こるし、しかも項目が連結されている住所データやったら、さっき書いたみたいに分割の作業が毎度いるんでっせ?
それに、本番移行直前でせーので一回でガバっと取り込めば済むほどシステム移行は甘いわけやあらへん。

もちろん、どっかの時点で初回分を取り込み、定期的に差分データを取り込み、最後に移行日までの残り差分がきれいに取り込めた場合は楽ですわ。そやけど、そうした移行の運用ができるのは、こっち側が旧システムにアクセスできる場合だけやねん。

遠方のお客様で、しかもVPNでつながれへんような旧システムの場合、データの取り出しはお客様にご依頼するほかありませんやろ。
お客様のやり方によっては項目に抜け漏れがあるやろし、項目の順番が違っていたりします。ましてや差分データの時間の基準もあいまいになってしまいますねん。そやから、きれいなデータを毎度もらえないと考えなあきません。
そやから、移行ツールを作らんでええ場合は、旧システムにこちらから簡単にアクセスできる場合に限ったほうがええね。もしそないにアクセス出来るんやったら、毎回Excelのフィルターや並び替えや置換などを駆使しても円滑に移行できると思うけどね。
ただ、実際はそうでない場合が多いから、そないなリスクを考えたら、最初に工数と時間をかけてでもお客様専用の移行ツールを作り、それを運用したほうが格段に楽やと思うんやけどどない?

データ移行のTIPS

  Topへ↑

なんぼかTIPSを列挙しておきますわ。

  • データの本番移行までは、取り込み時には変更履歴はオフにしといたほうがええで。
    設定は、アプリの設定→高度な設定→変更履歴のチェックを外す。
    そうしないとサイボウズさんに注意されまっさかい。また、変更履歴だけで契約のディスク使用量を軽く超過してしまいますねん。(一度、うっかりしていて100万件のデータを何度も取り込みなおし、サイボウズさんに注意されてもうた。※EvaCamp 2020で言いそびれた失敗談の一つ)
  • 可能であれば、本番移行後は旧システムのトランザクションデータ(売上や仕入などの伝票データ)は、kintoneでも別アプリにした方がええで。
    しかも、旧システムのトランザクションデータのフィールドはルックアップをなくし、文字列(1行)と数値のみにしといたほうが楽やで。なんでかいうたら、過去分のデータはマスタデータの変更などで古い値として入っとるからやねん。過去のルックアップはその時のマスタデータの値を再現して保存しといて、てな具合にご要望もろたら、移行作業はめっちゃごっつい苦行になってまう。さっきも書いたけど、ルックアップのコピー元のフィールドはマスタにある値やなかったらエラーになるからね。そやから、ここは初めのころに決めておいた方がええかも。
    旧システムの部分については別アプリに分け、ルックアップを外してしまえば、旧システムの生データをそのまま取り込むだけ済むさかい、ごっつい楽ですわ。
    そやけど、一つだけ注意しとかな。アプリを分けた場合、新旧両方のアプリをまたいだ分析に対応できませんやろ。その場合は、自分でカスタマイズビューを作成するか、トヨクモさんのDataCollectのようなプラグインを活用するとよろし。便利でっせー。
  • 添付ファイルの移行が必要な場合は先にも挙げたcli-kintoneを使うとええで。また、要件定義の段階でDropboxやboxなどのオンラインストレージの移行を提案しとったら、kintoneではそちらのストレージとの連携を行えばええから、あんじょういきまっせ。
    オンラインストレージへのデータ移行と整理作業は、お客様にお願いしといたほうがええやろし。
    2019年のわてのAdvent Calendarもご参考にしたってやー。
  • C/S側の旧システムは、たいがいレイアウトが小さくまとまっとるやろ。それに比べるとkintoneのフラットデザインは、項目の間の余白もがっつりとられとるし、そこは一目で情報が見られる旧システムに劣ると思われるかもしれへん。
    無理やりJavaScriptでレイアウトを調整したったりもしたけど、それはあんまり本筋のやり方ちゃうしなぁ。
    これも早い段階で現場の担当者と話を詰めといたほうがええで。
    あ、もう一個。デザインについてはkintoneのアプリの設定→デザインテーマの設定でブラックを選ぶとお客様の印象が変わるかもしれんで。一度試すとよろしおま。
  • Excel上でデータの加工を行う時、何使てます?フィルタ? もしそやったら、スライサーの機能とか試すと幸せになれるで。
    スライサーはこの記事が参考になるんちゃうかな。
  • kintoneの難儀な仕様ってあるやんか。例えば英単語の一部分の文字だけで検索でけへんとか。
    ヘルプにもこない書かれとるし。
    もしそれやったら、Excelのフィルタ使たらええねん。まあJavaScriptで
    一文字検索の機能を作ってもええし、プラグインでもええのんあるけどね。
  • C/S側の旧システムのユニークの項目は早めにお客様と共通認識をもっといたほうがええ。さっきも書いたけど、お客様からデータをもらう際は、旧システムのデータ出力方法を把握して、その設定や出力操作は完全に共通認識をもっといたほうがええ。あと、これも上で書いたけど、旧システムのデータを先に修正できるのならお客様に頼んで修正しといたほうがええ。

まとめ

Topへ↑

ちゅうわけで、本記事は皆様のkintoneへの移行のお役に、そしてご参考になればよろし思ぅて書きました。もちろん、これは弊社にとっても参考にすべき自社のノウハウですわ。
弊社も今年は一件、移行で苦労した案件がありましてん。だからこそ、一度ノウハウを言語化すべきやなぁと思ったんよ。それがきっかけです。
また、弊社の新規の案件の際にもお客様にも読んでもらお思ぅて、ここで知見を共有したいと思います。
なので、今後も折をみてアップデートを重ねていこうと思います。よろしゅうお願いいたします
また、こんなTipsや失敗談などありましたら、ガァーっとご意見をお寄せください。また本稿の内容に不備があった場合も遠慮せんとご指摘ください。

本稿が旧システムからkintoneへの移行をお考えの皆様にとってちょっとでも手助けになったら幸せやわ。


Cybozu OfficeのスケジュールをCalendar Plusで(だいぶ)再現!


カレンダーPlus Advent Calendar 2020の5日目の記事です。

  Topへ↓

先日のCybozu Days 2020 Osakaの後、Calendar PlusのAdvent Calendarに空きがあると聞き、やってみましょうか?と言ってしまいまして。
言った以上はエントリーせねば。というわけで翌日、神戸で商談する前に中華街で飯を食べながら記事にエントリー宣言。

さて、エントリーしたのはいいが、何を書けばええんやろ?しかもエントリーしたタイミングは前日やし(^^;)。これはひょっとして勇み足をやらかしてしまったのではなかろうか。

迷いを振り切った私が商談に臨むと、なんとお客様がCybozu Officeのスケジュールを愛用しており、それをkintoneに載せ替えたいとのこと。しかもkintone標準の標準のカレンダー機能は表現に乏しく、Calendar Plusを検討してみたけど、プラグイン設定の色設定の種類が少なくてなぁ。と悩みを吐露されまして。商談からネタが転がってきた瞬間です。
これはCybozu Officeのスケジュールアプリの画面です。

私は今までも何回かCalendar Plusは提案してきました。けれど、本格的なユーザーではないし、弊社のkintone納入実績からするとCalendar Plusの納品実績は一割もありません。熟練のユーザーではないのです。

が、Calendar Plus JavaScript APIを使ったカスタマイズの経験はあります。API使えば、ある程度ならCybozu Officeの体裁にCalendar Plusを合わせられるんちゃうの?という見切り発車でした。

Calendar Plusのプラグイン設定画面

  Topへ↑

うーむ、確かにCalendar Plusの色設定は12種類か。

そして、お客様のCybozu Officeのスケジュールの色設定で設けた種別は25種類。つまり倍。

確かにお客様がkintoneへの移行をためらわれるのもわかるなあ。

アプリを作る

  Topへ↑

じゃあ、ちょっと試しにアプリを作ってみよう。こんな感じで。

あらよっと、Cybozu Officeと同じようにレコードを登録してみました。さて、Calendar Plusで見るとどうなる・・・?

あかん・・・Calendar Plus側の色設定をしていないのですべて同じ緑地になってる。
しかも予定の状況がカレンダー上に表示されておらず、直行なのか直帰なのかが一目で区別できない。
やはり見にくいなあ・・・・これは、Calendar Plus JavaScript APIの出番かな。

コーダーモード発動

  Topへ↑

ということで、ガリガリとコーディングすること2時間。うん、こんな感じになりました。


というわけで最低限、記事にできるところまでこぎつけたのでいったん寝ます。アップ当日になってしまいましたが、AM2時前なのにもう眠い。年や。

プログラム開示

  Topへ↑
さて、アップ当日の朝、旅に出かける前に少しだけ記事を書きまして。
ここにコードを開示しておきます。すみません。洗練されたコードとは程遠くて・・・・。

(function () {
  "use strict"

  // 関数本体
  const calenderformat = function (event) {
    // Calendar Plusのイベントリスナー定義
    const calendareventslist = ["cp.event.show"];
    // kintoneのイベントの書き方と似ててわかりみ
    calendarplus.events.on(calendareventslist, function (calendarevent) {
      // kintoneのイベントのjson(上記イベントで対象データループしてくれます)
      const record = calendarevent.record;
      // kintoneのイベントの要素
      const element = calendarevent.element;
      // テーブルだけkintoneのイベントの要素
      const tdelement = document.getElementsByClassName("fc-event-container");
      // Cybozu Officeの時刻表示に合わせるため(ださいかも)
      const starttime =
        ("00" + new Date(record.開始時刻.value).getHours()).slice(-2) +
        ":" +
        ("00" + new Date(record.開始時刻.value).getMinutes()).slice(-2);
      const endtime =
        ("00" + new Date(record.終了時刻.value).getHours()).slice(-2) +
        ":" +
        ("00" + new Date(record.終了時刻.value).getMinutes()).slice(-2);
      // 左端の行高がCalendar Plusでは縮まるため、Cybozu Officeの行高っぽくする
      tdelement[0].style.minHeight = "90px";
      tdelement[1].style.minHeight = "90px";
      tdelement[2].style.minHeight = "90px";
      tdelement[3].style.minHeight = "90px";
      tdelement[4].style.minHeight = "90px";
      // リンクするためのurl
      const baseurl =
        kintone.api.url("/k/").replace(".json", "") +
        kintone.app.getId() +
        "/show#record=" +
        record.$id.value;
      // 予定の状況にあわせてSwitch(ださい)
      switch (record.予定の状況.value) {
        case "ーーー":
          // 枠の背景色
          element[0].style.backgroundColor = "#FFFFFF";
          // 文字色(本当はhoverとかの定義も必要。そもそもcssにまとめたほうがよい)
          element[0].style.color = "#006bac";
          // 折り返してくれなかったので折り返し(そもそもcssにまとめたほうがよい)
          element[0].style.whiteSpace = "break-spaces";

          // 終日フラグかどうか
          if (record.終日.value.length > 0) {
            // 頭に・をつける
            element[0].innerText = "・" + element[0].innerText;
          } else {
            // 頭に時刻をつけて改行
            element[0].innerHTML =
              starttime +
              "-" +
              endtime +
              "
 " +
              '<a href="' +
              baseurl +
              '">' +
              record.予定.value +
              "</a>";
          }
          break;
        case "直行":
          // 枠の背景色
          element[0].style.backgroundColor = "#ebf7ef";
          // 枠の線色
          element[0].style.borderColor = "#d8f2e0";
          // 文字色(本当はhoverとかの定義も必要。そもそもcssにまとめたほうがよい)
          element[0].style.color = "#006bac";
          // 折り返してくれなかったので折り返し(そもそもcssにまとめたほうがよい)
          element[0].style.whiteSpace = "break-spaces";
          // 終日フラグかどうか
          if (record.終日.value.length > 0) {
            // 頭に・をつけ、予定の状況を枠で囲む
            element[0].innerHTML =
              "・<span style="background-color:#32a759;color:#fff;" class="scheduleMarkEventMenu">" +
              record.予定の状況.value +
              "</span>" +
              record.予定.value;
          } else {
            // 頭に時刻をつけ、予定の状況を枠で囲む(以下コメントは省略)
            element[0].innerHTML =
              starttime +
              "-" +
              endtime +
              "
 " +
              '<a href="' +
              baseurl +
              '">' +
              '<span style="background-color:#32a759;color:#fff;" class="scheduleMarkEventMenu">' +
              record.予定の状況.value +
              "</span>" +
              record.予定.value +
              "</a>";
          }
          break;
        case "直帰":
        case "直行/直帰":
          element[0].style.backgroundColor = "#e8f2fc";
          element[0].style.borderColor = "#dae8f7";
          element[0].style.color = "#006bac";
          element[0].style.whiteSpace = "break-spaces";
          element[0].innerHTML =
            "・<span style="background-color:#3182dc;color:#fff;" class="scheduleMarkEventMenu">" +
            record.予定の状況.value +
            "</span>" +
            record.予定.value;
          break;
        case "転送":
        case "納品":
        case "設定":
        case "設置":
        case "移設":
          element[0].style.backgroundColor = "#f4fce8";
          element[0].style.borderColor = "#e5f2d3";
          element[0].style.color = "#006bac";
          element[0].style.whiteSpace = "break-spaces";
          element[0].innerHTML =
            "・<span style="background-color:#83cb26;color:#fff;" class="scheduleMarkEventMenu">" +
            record.予定の状況.value +
            "</span>" +
            record.予定.value;
          break;
        case "点検":
          element[0].style.backgroundColor = "#fff4e3";
          element[0].style.borderColor = "#fae8cd";
          element[0].style.color = "#006bac";
          element[0].style.whiteSpace = "break-spaces";
          element[0].innerHTML =
            "・<span style="background-color:#ef9201;color:#fff;" class="scheduleMarkEventMenu">" +
            record.予定の状況.value +
            "</span>" +
            record.予定.value;
          break;
        case "デモ":
        case "営業":
        case "商談":
        case "打合せ":
        case "来客":
          element[0].style.backgroundColor = "#faf6f2";
          element[0].style.borderColor = "#f2e9df";
          element[0].style.color = "#006bac";
          element[0].style.whiteSpace = "break-spaces";
          element[0].innerHTML =
            "・<span style="background-color:#c3a88b;color:#fff;" class="scheduleMarkEventMenu">" +
            record.予定の状況.value +
            "</span>" +
            record.予定.value;
          break;
        case "当番":
          element[0].style.backgroundColor = "#fcfae8";
          element[0].style.borderColor = "#f2efd3";
          element[0].style.color = "#006bac";
          element[0].style.whiteSpace = "break-spaces";
          element[0].innerHTML =
            "・<span style="background-color:#dfc506;color:#fff;" class="scheduleMarkEventMenu">" +
            record.予定の状況.value +
            "</span>" +
            record.予定.value;
          break;
        case "休み":
        case "有休":
        case "リフ":
        case "代休":
          element[0].style.backgroundColor = "#ffebeb";
          element[0].style.borderColor = "#fcdede";
          element[0].style.color = "#006bac";
          element[0].style.whiteSpace = "break-spaces";
          element[0].innerHTML =
            "・<span style="background-color:#f44848;color:#fff;" class="scheduleMarkEventMenu">" +
            record.予定の状況.value +
            "</span>" +
            record.予定.value;
          break;
        case "午前半休":
        case "午後半休":
          element[0].style.backgroundColor = "#fff2f5";
          element[0].style.borderColor = "#f7e9d2";
          element[0].style.color = "#006bac";
          element[0].style.whiteSpace = "break-spaces";
          element[0].innerHTML =
            "・<span style="background-color:#f3a4b4;color:#fff;" class="scheduleMarkEventMenu">" +
            record.予定の状況.value +
            "</span>" +
            record.予定.value;
          break;
        case "土曜当番出勤":
        case "出張":
        case "会議":
          element[0].style.backgroundColor = "#f5edfc";
          element[0].style.borderColor = "#ebe1f5";
          element[0].style.color = "#006bac";
          element[0].style.whiteSpace = "break-spaces";
          element[0].innerHTML =
            "・<span style="background-color:#b592d8;color:#fff;" class="scheduleMarkEventMenu">" +
            record.予定の状況.value +
            "</span>" +
            record.予定.value;
          break;
        case "土曜振休":
          element[0].style.backgroundColor = "#ffebeb";
          element[0].style.borderColor = "#fcdede";
          element[0].style.color = "#006bac";
          element[0].style.whiteSpace = "break-spaces";
          element[0].innerHTML =
            "・<span style="background-color:#f44848;color:#fff;" class="scheduleMarkEventMenu">" +
            record.予定の状況.value +
            "</span>" +
            record.予定.value;
          break;
      }
      return calendarevent;
    });
  };
  // kintone自体のイベント
  const eventslist = ["app.record.index.show"];
  kintone.events.on(eventslist, (event) => {
    // ビューが一致したら本体の関数呼び出し
    if (event.viewId === 5543487) {
      calenderformat(event);
    }
    return event;
  });
})(jQuery);

あと、cssも全体のフォントに関する設定と予定の状況の枠に対して設定しています。

div#calendarPlus {
    font-family:"ヒラギノ角ゴ Pro W3", "Hiragino Kaku Gothic Pro", ヒラギノ角ゴシック, "Hiragino Sans", メイリオ, Meiryo, "MS Pゴシック", "MS PGothic", sans-serif;
    font-size:14.4px;
    font-weight:400;
}
    
div#calendarPlus span.scheduleMarkEventMenu{
    display: inline-block;
    padding: 1px 2px;
    color: #fff;
    margin: 0 1px 2px 1px;
    line-height: 1.2em;
    border-radius: 2px;
    font-size: 12px;
    vertical-align: middle;
}
    

まとめ

  Topへ↑

てなわけで、日中は記事のことは一切忘れて徳島のあちこちをめぐっておりました。で、21時前に実家に帰ってきました。
では、早速記事の続きを。うん、あらためて確認しても表示はこんな感じで大丈夫かと。

本当は実装すべきなのは週だけでなく、他の日や月でも同じように表示できるか試さねばならないですね。また、Cybozu Officeのスケジュールアプリの日時と曜日の行見出しの部分はCalendar Plusでは再現していません。
まあこんな感じですが、記事の主旨は満たせたと判断し、今宵はここまでにしてアップしたいと思います。

あとは、金曜日に商談したお客様がこの実装でご満足いただけるかどうかでしょうか。なにしろ、お客様に商談の御礼のメールを送るより先に、こちらの記事をアップしてしまったので(^^;)。おいおい。

本稿がCybozu Officeからkintoneへの移行をお考えの皆様にとって少しでも手助けになれば幸せです。

もしお困りの際は弊社までご連絡くださいませ。

当エントリーの参考にさせていただいたブログ

  Topへ↑

最後になりましたが、このエントリー作成にあたり、以下のサイトからの情報を参考にさせていただきました。
ラジカルブリッジの斎藤さんにはいつも感謝です。内容にやばい内容が含まれていたら直しますね。
ありがとうございました。

 Calendar Plus JavaScript APIのリファレンス


kintoneのPromiseを説明できるスキル


以前よりお付き合いさせていただいている株式会社アディエム様(https://adiem.jp/)より、
先日ご依頼を受けたたkintone開発案件は、何重にも入れ子になった多重Promise処理が必要でした。

弊社にてコーディングと単体テストを行い、無事納品にこぎつけられたのですが、
アディエム社の技術者様にもコードの説明を行う必要が生じました。

弊社の代表もPromiseの習得にはかなり手を焼いたのですが、そのスキルを習得できたかの判断基準は、その内容を人に説明できるかどうかです。つまり今回、うまく説明できたかどうかは、弊社代表がPromiseを理解できているかのベンチマークにもなりました。

説明を行った結果、アディエム社の技術者様にPromise処理をご理解していただけたようです。追加の処理を実装し、さらにテストまでも行えるまでになったとか。その結果を以下のようなメッセージでいただきましたのでご紹介します。

先日はコードのレクチャーをありがとうござました。
本日、検索部分のエラーハンドリングを追加し、本番環境にリリース致しました。
負荷テストとして4001件のデータを使用して、正常に更新されることも確認しました。

kintone APIのノーマル呼び出しパターン、kintone promise を使ったパターン、promiseでも thenにresolve, rejectを引き渡すパターン、thenとcatchを書くパターンと、かなりケースの整理が できました。また返値の扱いもデバックすることで理解が進みました。
まだうまく関数化して可読性の良いソースを書く自信はありませんが、長井さんソースを参考にさせて 頂きたいと思います。

以上、ご報告まで。

弊社代表は以前より、kintoneのエバンジェリストとしてサイボウズ社より任命されております。
最近はこうしたマンツーマンに近い形で、技術をお伝えする案件も増えつつあります。
その中でこうしたご評価を頂戴したことは、弊社代表にとっても自信になりました。もちろん、スキルの習得に終わりはありません。新たな技術も次々と世の中に生まれています。まだまだ切磋琢磨していかねば。精進します。

今後もアディエム社とはkintone案件のご提案からコーディング・テストまでを協業できる関係を築いていければと思います。
kintoneでのシステム開発のご相談、アディエム社、および弊社にお気軽にお寄せ下さいませ。

また、もし御社の技術者に対し、こうしたマンツーマン形式でのレクチャーをご要望の際は、
ご連絡をください! ご相談に乗らせていただきます。