だ。ログ。

開発とかスノボとかやきうとか。

EC-CUBE3のCSVの新規出力データを作成し画面上でダウンロードできるようにする

CSVファイルで取り込んで連動する。多分今後もなかなかこの手法から脱却するのは難しいと思う。
各システムがその他の事を考えていないし、連動するシステムを想定した作りなんてしない。
だからCSVであればエクスポート可能だよーとしておけば、あとは運用側が創意工夫してなんとかしてね。となる訳で。
EC-CUBEにもCSVファイルを「作る」事は出来ても、項目を追加するのはちょっと手間が掛かる。

マスタデータの追加

設定 > システム情報管理 > マスターデータ管理を開き mtb_csv_type を選択する。
ここでCSVファイル出力用のプルダウンのデータを制御している。
IDには既存の数値とは被らないIDを入れ、Nameには好きな物を入れる。

設定 > 基本情報設定 > CSV出力項目設定を選択しプルダウンをクリックするとマスターデータで追加された項目が追加されている。
ただし問題は、CSV出力する項目が入力されていない。
ここからはSQLを利用する。

DBの流し込み

phpMyAdminを使うと簡単だが、まず設定項目に関してはdtb_csvに格納されている。
csv_idは自動採番なのであまり気にする必要はない。csv_typeはマスタデータで必要となるデータを入れる。
必要なデータはテーブル定義書あたりを参考にすると良い。マスタに既に入っているIDから出力するデータが何かと言う事自体は確認出来るので、それをコピーしてINSERT文を流し込む。
例) 1.商品(dtb_product) 2.会員(dtb_customer) 3.受注(dtb_order)

仮に会員データを取得したい場合はcsv_typeが2のデータを抽出し、マスターデータ管理で追加したIDに書き換えてINSERT文を実行。
csv_idは現在の最大値からネストした数値を割り振る。
新規マスターデータIDが6の場合はこんな感じ。

INSERT INTO `dtb_csv` (`csv_id`, `csv_type`, `creator_id`, `entity_name`, `field_name`, `reference_field_name`, `disp_name`, `rank`, `enable_flg`, `create_date`, `update_date`) VALUES
(999, 6, 1, 'Eccube\\Entity\\Customer', 'id', NULL, '会員ID', 1, 1, '2017-07-12 20:58:58', '2017-07-12 20:58:58'),

任意のページでCSVダウンロード出来るようにする。

間借りする形になるが、会員管理>会員マスター>CSVダウンロードに新たに今回のダウンロード項目を付け足し、管理画面からCSVダウンロード出来るようにする。

フックポイントの作成
/src/Eccube/ControllerProvider/AdminControllerProvider.php

#customerの部分に追加
#_customの部分は自分の好きな名前にしておく。
        $c->match('/customer/export_custom', '\Eccube\Controller\Admin\Customer\CustomerController::export_custom')->bind('admin_customer_export_custom');

イベントの作成
/src/Eccube/Controller/Admin/Customer/CustomerController.php

#public function export(Application $app, Request $request) をコピーする
#_customの部分はフックするポイントに合わせる。
    public function export_custom(Application $app, Request $request)
    {

        // タイムアウトを無効にする.
        set_time_limit(0);

        // sql loggerを無効にする.
        $em = $app['orm.em'];
        $em->getConfiguration()->setSQLLogger(null);

        $response = new StreamedResponse();
        $response->setCallback(function () use ($app, $request) {

            // CSV種別を元に初期化.
	  // ※※ここのinitCsvTypeを今回追加したcsv_typeの番号にする。
            $app['eccube.service.csv.export']->initCsvType(6);
	・
	・
	・
    }

テンプレートの追加
/src/Eccube/Resource/template/admin/Customer/index.twig

              <ul class="dropdown-menu">
                <li><a href="{{ url('admin_customer_export') }}">CSVダウンロード</a></li>
                <li><a href="{{ url('admin_setting_shop_csv', { id : constant('\\Eccube\\Entity\\Master\\CsvType::CSV_TYPE_CUSTOMER') }) }}">出力項目設定</a></li>
                <li><a href="/admin/customer/export_custom">カスタムCSVダウンロード</a></li>

ここまで設定すると、CSVダウンロードの項目にカスタムCSVがダウンロード出来るようになる。
項目は、設定>基本情報設定>CSV出力項目設定
で設定した物が出力されている事を確認。

細かいけど、こう言うカスタマイズって必要な物だから文献としてあって損は無いかなーと。

EC-CUBEにPOSTしたデータを取得する

他サイトとEC-CUBEの連動をしたい。特に要望として挙がるのはSSO関連部分。
ただ、EC-CUBEの仕様上セッションジャックやクロスサイトスクリプティングの問題からSSO自体はコアをいじれば出来るけど、相当手間が掛かる。
まずは第一段階として、他サイトからPOSTしたデータを受信して、EC-CUBEサイトからCSRFトークンを発行してログインさせれば。
って言う似非SSOで対処の為の調査。
そもそも他サイトからのPOSTデータ取れるの?って言う疑問もあった。
着地するページは任意だが、そのコントローラで以下のようにする。

$request->request->get('hoge');
$request->request->get('fuga');

$_POST['hoge'];
$_POST['fuga'];

を取り出す場合は上記のように記述すれば取得出来る。
とりあえず外部からのデータ受信をEC-CUBEで受信出来る事はOK
あとは特定のサイトからのPOSTで秘密鍵か何かを渡してページを表示するか否かをコントローラで判断するように設計すれば良い。

モンスター

クライアントがモンスターだと言う前に考えたい。
受注したチーム側がモンスターじゃないかと。

一つだけあらかじめ断っておく。
この文章は、異世界に転生した冴えない主人公が可愛い女の子とハーレムとなり世界を救う。
要はファンタジーだ。

(しようが)ないです。

相槌を打つ。とにかく相槌を打つ。どんなサイトですか?どう言うテイストですか?
ンなモノは二の次だ。お客様に適正な解決策の提案 <<<<<<<< 受注するための提案
と言う本末転倒な事になっている。
結局、じゃあ見積をお願いしようかな。となった時に出て来る材料は
「(ライバル社)と同じテイストで」
1時間なり2時間なり御用聞きをした結果がこの1行なのだ。
とても濃密で濃厚、この1行からサイトの構成、サーバーの用意、システムの構成、デザインのテイストを決定しなければならない。

もっと具体的に~と言うことを営業に言おうものなら
「しょうがないじゃないか!」

渡る世間は鬼ばかりである。

前にやってたじゃん

で、これでなんで出来るっつったんですか?
と言う質問の常套句である。
「だって、前にやってたじゃん」

やった、やりきった事に関して全てが平穏無事に済んだと言うハッピー回路に変換される。
何度となく怒号と怨嗟の会議をした事なんて忘れている。

放棄する

とは言え決まった事だ。全うするしかない。
しかし自分は結局はシステム屋だ、依頼主とは喋った事もない。コミュニケーションのとりようもない。
今までのやらかしからして、全てを壁打ちするだけだ。
いや、壁打ちで返すなら良いが勝手に言葉を付け加える。それも制作不利にさせる事だけは長けたスキルで。

質問をする。
その質問を最初は考える。だが答えは出ない。何故か?
考える事を放棄しているからである。売れたモノだから後は制作が勝手にやれよ。スタンスである。
あれだけ電話越しに質問質問した人間がまるで事済ませた後の賢者モードのように冷たい。
「んな事俺に聴くなよ、そう言うのは制作が決めて提案しろよ」

ただ、決めて提案しても予算は決まってしまっている。
提案するのは良いけど金勘定してくれと言っても受け付けられない。
結局は制作が折れるしかない。

提案の定義

解決策を提案する。
サラリーマンをしている以上、売上をあげてナンボである。
1円でも多く利益還元しなければならない、そして自分は売上をあげる事においてはパワプロで言えば赤スキルだ。
だからこそ営業さんに頼る、お金を稼ぐ働き口を下さい。と。
持ってくれば仕様ガー、要求ガー、工数ガーと言って素直に仕事をしない。
営業さんは四の五の言わずに受けてきてやった仕事なんだからやれよ。と思う。

もうそこに信頼関係は無い。有るのは全方向に売った喧嘩の禍根だけだ。
その禍根は、営業に反発するモンスター制作を生み出し、モンスター営業を生み出す。
チームとしては瓦解に近い。

お互いが歩み寄る為に必要な事はなんだろう。と常々思うようになってきた。

EC-CUBE3購入画面の文字化け

EC-CUBE3の支払い方法部分の改造をしていた時のこと。

  1. 商品をカートに入れる
  2. ログイン/非ログインで操作を続ける
  3. 支払い方法ページを表示する

ここにjsで任意の文字列を表示させようとした際に、jsのデバッグの為にソースコードを開くと文字列が全てURLエンコード変換されていて「日本語」として確認する事が出来ない。
そのままjsの

alert("こんにちは、お昼ごはんです");

を実行すると「こんにちは、お昼ごはんです」が全て文字化けしてしまう。

%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF%E3%80%81%E3%81%8A%E6%98%BC%E3%81%94%E3%81%AF%E3%82%93%E3%81%A7%E3%81%99

こんなかんじ。


文字列自体はエンコードされていて、ブラウザで表示すると「日本語」として解釈されているがjsは文字列が解釈されない。

解決策

明示的にmetaタグにエンコードタイプを記述する。

/src/Eccube/Resource/template/default/default.twig 41行目

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

明示的にUTF-8ですよ。と宣言する。
サーバーやシステムの仕様上エンコードが違う場合はcharsetを変更する。

EC-CUBE3のリファラの取り方

まず最初はセッションを使って、一旦ランディングページにアクセスしたか?
と言う事を記録して、それによってページの要素の出し分けをしたい。と言う事を考えていたがEC-CUBEの仕様上、セッションやは /app/cache/eccube/session内にデフォルトでは登録される。
その為、ランディングページ等でセッションを登録し、EC-CUBEのシステム内のページに遷移するとセッションが消えている。
Cookieも同様にランディングページで設定したCookieが引き継がれない。

と言う事で、少し変化球ではあるものの、ページ内のリファラを参照し自ドメイン内のアクセスであれば処理はそのまま。
ドメイン「以外」のドメインからのアクセスの場合は要素を変更させる。と言う処理を入れてみる。

通常の場合

何も無い場合は以下

$referer = $_SERVER['HTTP_REFERER'];

「普通」の場合はコレで取得出来る。しかしEC-CUBE3だとコレでもダメ。
ドメインからアクセスしても、自ドメインにアクセスした。とみなされてしまう。

EC-CUBE3の場合

トップページでの判定
/src/Eccube/Controller/TopController.php

    public function index(Application $app)
    {
	$referer = $app['request']->headers->get('referer');
	if(!preg_match("/{$hogehoge.com}/",$referer)){
		header("Location: 任意のページ");
		exit;
	}

$refererを取得する所がミソで、$app内から取得する。取得したリファラが自ドメイン「以外」だったらリダイレクトと言う処理を噛ませている。
グローバルの変数もEC-CUBE内では操作する事が難しいので、今後その辺は「出来る」ようにしていかねばならないが、とりあえず急場しのぎと言う事で。

EC-CUBEの受注ステータスを「購入処理中」にすると受注管理から消える

EC-CUBE3.014にて確認した事象として、一度受注したデータを管理画面にて編集しオーダーを「購入処理中」に編集し、受注マスターに戻った際に対象の受注が消える。
もう大分EC-CUBEを触っていなかったので、これが仕様かどうかは分からないが、現状のデフォルトのEC-CUBEの受注ステータスID:8「購入処理中」にプルダウンを変更しデータを確定すると消える。
これが現状のEC-CUBEの仕様らしい。

システム屋の目線で見れば、それが仕様だからそうなんだろう。位で済むのだが、運用しているシステムなんて知らないよ。って言う人からすれば
じゃあ何のために購入処理中が選べちゃうのさ!と言われるし、実際に言われたワケで。

問題となる部分は以下
/src/Eccube/Repository/OrderRepository.php 303行目から

        if (!$filterStatus) {
            // 購入処理中は検索対象から除外
            $OrderStatuses = $this->getEntityManager()
                ->getRepository('Eccube\Entity\Master\OrderStatus')
                ->findNotContainsBy(array('id' => $this->app['config']['order_processing']));
            $qb->andWhere($qb->expr()->in('o.OrderStatus', ':status'))
                ->setParameter('status', $OrderStatuses);
        }

「購入処理中は検索対象から除外」とソースコードにしっかりと記載されている。
導入前にこのステータスは他の決済で利用するモノで手動で使うとオーダー消えちゃうんですよ~的にクライアントに説明して使わない。とする事も一つの手だが、目で見える物だから使いたい。と言われる事は安易に想像出来る。

        if (!$filterStatus) {
            // 購入処理中は検索対象から除外
            $OrderStatuses = $this->getEntityManager()
                ->getRepository('Eccube\Entity\Master\OrderStatus')
                ->findNotContainsBy(array('id' => $this->app['config']['order_processing']));
            //$qb->andWhere($qb->expr()->in('o.OrderStatus', ':status'))
            //    ->setParameter('status', $OrderStatuses);
        }

というわけでクエリビルダ―のパラメータとして除外ステータスをコメントアウトさせると、購入処理中のデータ自体も表示される事が確認された。
ただしこれだと受注日が入っていない「仮オーダー」状態の物も全て出てしまうので実用的ではない。
細かく設定が必要となってしまうが、プルダウンから購入処理中を選べないようにする。と言う処理を入れて対処した。

しかしこの仕様は不親切だなあ。。

勝負のアヤ

週末は横浜スタジアムジャイアンツ戦をライトスタンドで観戦していました。
日曜日の6-6に追いつかれて9回裏の筒香選手の劇的なホームラン、打球が上がった瞬間周りの人とのハイタッチの嵐は本当に楽しい時間だったなーと。

このカードは引き分け→○菅野投手→○山﨑康晃投手と言う事で1勝1敗1分と言う両者譲らずの五分で終えた。
どの試合も内容が濃く、全ての試合にハイライトが有ったが、3試合目の筒香選手のホームランに至る3試合通しての最後の結果までのプロセス
いわばオカルトである「勝負のアヤ」と言う言葉で表現すると分かりやすい。

21日(金)両者譲らず 3-3 12回引き分け

ジャイアンツ田口投手、ベイスターズ井納投手共に両者譲らずの展開。
特に6回以降は決定打を許さない展開で12回、一打サヨナラまで追い詰めるもあと一本が出ず。
ベイスターズは砂田投手、加賀投手、パットン投手、三上投手、田中健二朗投手、山﨑康晃投手を細かく繋ぐ。
ジャイアンツは西村投手、マシソン投手、カミネロ投手と言うリレー。
ベイスターズはワンポイントを含めて細かく細かく繋ぐ作戦、対してジャイアンツはマシソン投手の圧巻の2回パーフェクトリリーフ。
結果的にジャイアンツはベンチ入りしていた、桜井投手や中川投手を使わず温存出来たと言う見方も出来るリリーフ内容
次の日の菅野投手の事を考えると、マシソン投手を出し惜しみせず使った事で、次の日以降もこの日好投したマシソン投手の陰がチラつく状態に。

22日(土)菅野投手圧巻の投球 ベイスターズ 1 - 3 ジャイアン

初回、飯塚投手はマギー選手に出塁を許し坂本選手のフライを山下選手が追いきれずに落球。
そして5番村田選手には痛い3ランを浴び初回3点献上、ベイスターズも裏にチャンスを作るものの菅野投手に抑え込まれその後は淡々と試合が続く状況に。
飯塚投手は6回を投げ終えた所でお役御免、6回86球被安打6、3失点と先発としての役割を果たす事が出来たものの相手の菅野投手に3点は大きくのしかかる展開に。
後を受けた投手はエスコバー投手、ノーコンで直球ゴリ押しと言う話を聞いていたもののジャイアンツ相手に物怖じせずどんどんストライクを取り被安打0で抑える好投
最終回、平田投手もキッチリと抑えて9回反撃に。
カミネロ投手は1点を簡単に献上しなおも満塁、たまらず高橋監督はマシソン投手を投入しなんとか火消しをして逃げ切り。
あと一本が出なかったとは言え、手も足も出ない状況から最後は抵抗を見せた事で次に繋がる試合が出来た事は大きかった。
そしてなんと言ってもマシソン投手に連投をさせたこと、僅差でピンチと言う使わざるを得ない状況を作った事が次の日の呼び水となる。

23日(日) 筒香選手のサヨナラ ベイスターズ 8x - 6 ジャイアン

そしてカード最終戦ベイスターズは久保投手、ジャイアンツは大竹投手の両ベテラン。
試合はシーソーゲームになり、8回に亀井選手が砂田投手から同点の3ランで6-6の同点に。
三上投手がピリっとせずランナーを溜め失点し、火消しを任された砂田投手が狙いすまされたインコース高めをライトスタンド上段に突き刺す形に。

そして9回表、横浜スタジアムにはKernKraftが流れ山崎康晃投手が登板、苦しみながらも0で抑えジャイアンツの守備
ここで考えられる選択肢としては、カミネロだろうな。と思っていたが、出てきたのは高木勇投手。
前日の簡単に失点したカミネロ投手、それもグランドスラムを献上している桑原選手に回る状況、そしてなによりもマシソン津酒が3試合で70球を要している状況から回を跨がせるのは今後の戦いに響く。
と言う投手選択が一つ目の勝負のポイント。

2アウトをポンポンと取るも柴田選手にヒットを浴び2アウト1塁、ここで筒香選手との勝負。
この時の選択肢として筒香選手との勝負を避けてロペス選手と勝負。と言う事も考えられるものの、今度は極端なバックホームでの前進守備を取ると頭を越される。
逆に単打でも2塁に柴田選手が居るので、本塁突入勝負になる。長打を警戒して後ろの場合力ないポテンヒットでもサヨナラのリスクがあり守りづらくなる。
と言う中から筒香選手との勝負を選択、この選択がベイスターズファンの大歓喜に変わったと。

仮にこれが1アウトの場合、引っ掛けてゲッツーを狙う事を考えれば筒香選手勝負は無く、ロペス選手へは徹底的な外角へのスライダー引っ掛け狙いになっていたんじゃないかと。
ひとつひとつの事象が重なり合い、勝負の「結果」が生まれる。
確かに結果だけを見れば、そうなっただけ。と言う見方も出来るが、この1カードに凝縮した勝負や流れと言う言葉を楽しめる週末となりました。