Life is Really Short, Have Your Life!!

ござ先輩の主に技術的なメモ

PWAを覚えるぞ

販売管理システムのデスクトップアプリは、ほぼ出来上がってきた。日常業務をこなすには問題なく、あとは管理業務としての分析・帳票出力・権限管理などが控えているが、4月から試験導入予定。

次の課題がスマホアプリ。主要の販売管理システムはクラサバなので、そもそも外に出れなかったりする。クラウド対応みたいな所もあるだろうけど、ブラウザでレスポンシブになるんでみたいな所しかないと思う。作るのは、顧客との販売チャネルとしてのスマホアプリ。カタログ配信、プッシュ通知、ネット注文(予約も可能)、請求、注残の管理・・・みたいなのがいい感じ出来るもの。ECのようなもんね、簡単に言えば。お客さんが注文してくれて販売管理システムに連動して請求までできれば、最強。

僕が知る限り、雑貨の小売店の現場にはPCを置いてあることが少ない。本部バイヤーがいる所はまだしも、PC開いてカタログ開いてぺちぺちとキーボードを叩いて注文する時間も手間もかけられない。スマホならできるし、商品のバーコード読んだら商品詳細ページに飛ばすとか、やりたいよね。

このアプリをネイティブで作ったら死ぬ(iOS/Androidを各々作ったらすげー頑張っても半年かかる)ので、PWAで作る。デバイスが必要なのカメラだけだし。SNS連携とか一切いらないし。1ヶ月あれば、だいたいの実装はできそうな気がする。見えていないのはキャッシュのさせ方。動的なクエリのついたURLとか、商品データJSONとか、そういうのをオフラインでキャッシュさせたい。適切なタイミングで更新も必要だし。そのあたりが見えてくれば、あとは単なるWebアプリだし。イケそう。

やっていき。

WordPressの記事カテゴリを一括置換するSQL

プラグインとか入れるの面倒じゃないですか。

WordPressには「wp_terms」(wp_はご自身のWordPressプレフィックスに読み替えて下さい)というテーブルがあります。ここに記事のカテゴリ等が全て格納されています。

記事のカテゴリと記事の紐付けは「wp_term_relationships」というテーブルにあります。「object_id」カラムがwp_postsの記事のIDです。「term_taxonomy_id」が「wp_terms」のterm_idと同じです。

なので、wp_termsテーブルのterm_idをメモしておいて、以下のSQLを投げると一括で記事のカテゴリを置換することができます。

UPDATE wp_term_relationships 
SET term_taxonomy_id = <変更後のカテゴリID> 
WHERE term_taxonomy_id =  <変更前のカテゴリID>

IDベースではなくカテゴリ名称やスラッグベースで更新したい場合は以下のとおりです。

UPDATE 
  wp_term_relationships AS tr 
  JOIN wp_terms AS t ON t.term_id = tr.term_taxonomy_id 
SET 
  term_taxonomy_id = (
    SELECT 
      term_id 
    FROM 
      wp_terms AS t2 
    WHERE 
      t2.slug = 'after'
  ) 
WHERE 
  t.slug = 'before';

beforeを置換前のカテゴリのスラッグ名称、afterを置換後のカテゴリのスラッグ名称にして下さい。

また、記事を置換しただけでは、wp_term_taxonomyのcountカラムが更新されません。置換前の件数が残ってしまうので、適宜UPDATEしてください。

販売管理システムのリリース間近

2017年10月頃からお話をもらっていた販売管理システム、MVPレベルでリリースできそうです。1次フェーズってやつですね。ファーストユーザである先方には圧倒的感謝。

自分が雑貨メーカーの中で業務を回していたこともあり、良くも悪くも細かい点に気がついてしまい、それらの例外処理パターンを整理整頓してルールに落とすこと、その(実は結構複雑な)ルールを画面からは感じさせずに、流れるように仕事ができること。そこに腐心しました。

販売管理は納品伝票が起こせたらあとは簡単。締め処理するだけ。問題は、そこに至るまで。注文をそのまま入力して出荷すればいい、とはいかないのです。

注文受けたらそのまま出荷できる以外のパターンが、代表的なものでこれだけある。

  • 欠品(入荷次第納品希望なら注残になる)
  • 分納(納期別 / 商品別)
  • 取置
  • 注残

分納には、納期別と商品別の2種類がある。納期別は、同じ商品で納期が違うもの。商品別は、全部で10の商品を注文してくれて、5つは即納、残り5つは二週間後になるもの。この場合、2週間後を待ち続けるとキャンセルを食らう可能性があるので即納分は先に出荷したい、とか。欠品なら次回入荷を自動で出して、注残であれば最短納期で一旦入荷予定の在庫から引き当てる、とか。色々なことが必要になります。

また、ほとんどのメーカーは中国やベトナムから輸入しているので、輸入事務のサポート、為替を絡めた原価計算など、その点も次のフェーズでやっていかねばなりません。営業マンに使ってもらう営業支援のスマホアプリ並びにお客様に使ってもらうスマホアプリの開発も控えております。

雑貨販売業がサブスクリプション制でずっと使いたいと思ってもらえる、販売管理を中心としたサービス展開をやりたい。販売管理が業務系パッケージで最もシェアが大きいし、硬直的で新しいシステムが全然ないので、チャンスだと思っている。自分が雑貨販売をやるかもしれないので、ま、ライフワークのようなものですね。空いた時間でやっていたから中々進まなかったけど、幹となる販売管理システムがリリースできれば、折り返し地点には来れた〜。

2018年は空いた時間全てこのリリースに注いでいたので、全然他の動きができなかった。2019年は体制強化の話も進められそうで、楽しみが多い1年です。予定納税などの恐怖が待ち構える創業3年目、やっていきだ。

DataGridのSelectedItemsを任意のListにキャストする

DataGridのSelectedItemsは、「System.Windows.Controls.SelectedItemCollection 」というクラスに値が保持されます。バインドされるオブジェクトが何が来るかわからないので、型はobject。

これを任意の型のListにキャストする場合はこう書く。

 this.DataGrid.SelectedItems.Cast<Hoge>().ToList();

こうすると、Listが戻り値として返ってくる。

ITコンサルティングってやる意味あるのかな

微妙にそんな事を感じてしまった今日この頃。意味があるというか、意義を見出すのが本当に難しいなぁと。

企業がITに期待することなんて「売上UP」か「生産性向上」のどちらかでしかない。で、大変残念ながら、導入するだけで売上UPするITソリューションなんて、どこにも無い。

ビジネスモデルやそれを支えるビジネスプロセス、更には営業戦略やマーケティング等の総合的な取り組みがあって、初めて売上をUPするための対策が取れる。単価を上げるのか、顧客を増やすのか、商材を増やすのか、購入回数を増やすのかを決めた上で、ITを活用するノウハウを貯めて成功する確率を高めていくしか無い。差別化を図るのは、目に見えない所であるべきだ。

生産性向上というのは「今までやっていることをもっと速く出来るようになること」ではなく「手を動かさなくてもいいようにすること」が達成できていないと意味がない。そのためには、企業内に流れる情報の集約と集計がなされていなければ絶対にできない。トラッキングできないデータは改善できないし、業務システムの活用意義ってドラッキング。重要なのは、トラッキングする視点。人の行動なのか、モノの動きなのか、お金の動きなのかという中で、何をトラッキングできれば、手を動かす必要なく仕事上の判断や意思決定を下すことが出来るのか、改善できるのかと言うのを考え無くてはならない。

・・・こういう事を考えるのが、ITコンサルティングというものだとすれば、うーん、これってITの話なんだけって思っちゃった。経営の話だよねぇ・・・。

ITコンサルティングというものが意味があるとすれば、上記の前提が腹落ちしていないと意味がないんじゃないか、意義が見いだせないんじゃないかなと思う所があって、表題の一文に至ったというわけ。ITの使い方を教えてくれっていうITコンサルティング、多分いらねーわ。

今みたいな話をまとめて、「誰でも出来る、IT戦略構築フレームワーク」を作ろうかなって思っています。多分、無いはずなんだよね。こういうの。40歳になる時までに作り上げたいな。現在、38歳と10ヶ月。14ヶ月かけて、トライアンドエラーよ。

SQLAlchemyの結合条件の制御

モデル定義で外部キー定義する場合は、こんな感じでJOINできる。Flask-SQLAlchemyの場合です。

Order.query.join(OrderDetail, Customer, Destination, Item)

こんな感じのSQLが生成される。

FROM orders 
INNER JOIN order_detail ON order.id = order_detail.order_id 
INNER JOIN customer ON customer.id = order.customer_id
INNER JOIN destination ON destination.customer_id = customer.id 
INNER JOIN items ON item.id = order_detail.item_id 

今回はこのCustomerが曲者です。

CustomerはOrderの外部キーでもあるし、Destinationの外部キーでもあるという構成なので、この書き方をしてしまうと結合順が優先されて、顧客と納品先が結合されます。そうすると、顧客に対して納品先がN件ある場合、注文明細がN倍に膨れ上がって表示されてしまいます。

どうするかというと、結合条件をJOIN関数の第2引数にくれてやります。

Order.query.join(Customer, OrderDetail, Item).\
join(Destination, Destination.id == Order.destination_id)

こういうSQLに変わりました。

FROM orders 
INNER JOIN order_detail ON order.id = order_detail.order_id 
INNER JOIN customer ON customer.id = order.customer_id
INNER JOIN items ON item.id = order_detail.item_id 
INNER JOIN destination ON destination_id = Order.id 

はー、まじでAlchemyすごく便利。

Python3でZIP圧縮する場合の文字化け対策

結論

頼む!UTF8がわかるアーカイバソフト使ってくれ!!

qiita.com

ピンズドなエントリ。やはり人類はエクスプローラーによるZIP圧縮や解凍に困っていた。Windows7でUTF8がわからない場合に辛い。パッチがMSから公開されているが社内のセキュリティポリシーがどうだのかんなので、手を出せないという。Windows10ならUTF8がわかるようになっている。

ASCII文字でエンコード出来ない文字列があった瞬間に、強制的にUTF8でエンコードしている。いやね、そりゃそうなんだよ。全世界で使うんだから。

PythonのZipファイルエンコードの仕様をモンキーパッチを当てて逃げるというやり方しかないのが、Pythonで日本語ファイルを含むZipファイルを作る時の辛み。