EC-CUBE4でCSVファイル出力時に数値項目へ'.00'を付与させない方法

EC-CUBE Advent Calendar 2020 20日目の記事です。

EC-CUBE4で注文CSVダウンロードした時に数値項目(金額など)に.00が付与されてダウンロードされます。

国際化対応されているので小数点以下が付与されても別に気にしなくても良いのですが、偶に外部連携時に不要なことがあります。

今回は付与しない方法の説明です。

CsvExportServiceの変更

今回は一部の箇所を変更するのみです。

  • src/Eccube/Service/CsvExportService.php
/**
 * CSV出力項目と比較し, 合致するデータを返す.
 *
 * @param \Eccube\Entity\Csv $Csv
 * @param $entity
 *
 * @return string|null
 */
public function getData(Csv $Csv, $entity)
{
    // エンティティ名が一致するかどうかチェック.
    $csvEntityName = str_replace('\\\\', '\\', $Csv->getEntityName());
    $entityName = ClassUtils::getClass($entity);
    if ($csvEntityName !== $entityName) {
        return null;
    }

    // カラム名がエンティティに存在するかどうかをチェック.
    if (!$entity->offsetExists($Csv->getFieldName())) {
        return null;
    }

    // データを取得.
    $data = $entity->offsetGet($Csv->getFieldName());

    // one to one の場合は, dtb_csv.reference_field_name, 合致する結果を取得する.
    if ($data instanceof \Eccube\Entity\AbstractEntity) {
        if (EntityUtil::isNotEmpty($data)) {
            return $data->offsetGet($Csv->getReferenceFieldName());
        }
    } elseif ($data instanceof \Doctrine\Common\Collections\Collection) {
        // one to manyの場合は, カンマ区切りに変換する.
        $array = [];
        foreach ($data as $elem) {
            if (EntityUtil::isNotEmpty($elem)) {
                $array[] = $elem->offsetGet($Csv->getReferenceFieldName());
            }
        }

        return implode($this->eccubeConfig['eccube_csv_export_multidata_separator'], $array);
    } elseif ($data instanceof \DateTime) {
        // datetimeの場合は文字列に変換する.
        return $data->format($this->eccubeConfig['eccube_csv_export_date_format']);
    } else {
        // スカラ値の場合はそのまま.
        return $data;
    }

    return null;
}

となっています、がそれを

/**
 * CSV出力項目と比較し, 合致するデータを返す.
 *
 * @param \Eccube\Entity\Csv $Csv
 * @param $entity
 *
 * @return string|null
 */
public function getData(Csv $Csv, $entity)
{
    // エンティティ名が一致するかどうかチェック.
    $csvEntityName = str_replace('\\\\', '\\', $Csv->getEntityName());
    $entityName = ClassUtils::getClass($entity);
    if ($csvEntityName !== $entityName) {
        return null;
    }

    // カラム名がエンティティに存在するかどうかをチェック.
    if (!$entity->offsetExists($Csv->getFieldName())) {
        return null;
    }

    // データを取得.
    $data = $entity->offsetGet($Csv->getFieldName());

    // one to one の場合は, dtb_csv.reference_field_name, 合致する結果を取得する.
    if ($data instanceof \Eccube\Entity\AbstractEntity) {
        if (EntityUtil::isNotEmpty($data)) {
            return $data->offsetGet($Csv->getReferenceFieldName());
        }
    } elseif ($data instanceof \Doctrine\Common\Collections\Collection) {
        // one to manyの場合は, カンマ区切りに変換する.
        $array = [];
        foreach ($data as $elem) {
            if (EntityUtil::isNotEmpty($elem)) {
                $array[] = $elem->offsetGet($Csv->getReferenceFieldName());
            }
        }

        return implode($this->eccubeConfig['eccube_csv_export_multidata_separator'], $array);
    } elseif ($data instanceof \DateTime) {
        // datetimeの場合は文字列に変換する.
        return $data->format($this->eccubeConfig['eccube_csv_export_date_format']);
    } else {
        // スカラ値の場合はそのまま.
        if (is_string($data)) {
            $data = preg_replace('/\.0+$/', '', $data);
        }
        return $data;
    }

    return null;
}

に変更するだけで対応可能です。

変更箇所は

// スカラ値の場合はそのまま.
if (is_string($data)) {
    $data = preg_replace('/\.0+$/', '', $data);
}

になります。

特に対応する箇所でもないのですが、必要な方はこの記述を追加してください。

EC-CUBE4でポイント履歴を作成する方法

EC-CUBE Advent Calendar 2020 19日目の記事です。

EC-CUBE4ではEC-CUBE3系で無くなったポイント機能が標準で搭載されています。

このポイント機能ですが、ポイント利用とポイント付与しかなくポイント履歴機能は存在しません。

時々お客さんによってはポイント履歴が欲しいと言われることがありますので、今回はポイント履歴を作成します。

今回の変更は複雑な箇所も多いため慣れていない方はお気をつけください。

会員登録時と商品レビュー公開時にも自動ポイント付与及びポイント履歴として表示させるようにカスタマイズも可能ですが今回は省きます。

続きを読む

EC-CUBE4でメールアドレスではなく任意のユーザー名でログインする方法

EC-CUBE Advent Calendar 2020 17日目の記事です。

時々お客さんからの要望で、メールアドレスだけではなく任意のユーザー名でログインさせたいという要望があります。 もっと詰めていくと、会員登録時には「任意のユーザー名」「メールアドレス」「パスワード」だけで登録させたいというものまであります。

その場合、住所はどのタイミングで入力させるのかというと購入画面で入力させるようにすれば良いということですが、購入画面で購入者情報と配送情報を入力させる方法は別の機会に説明します。

今回は会員登録画面を「ユーザー名」「メールアドレス」「パスワード」だけの項目にし、ユーザー名でもログインできる方法を説明します。

続きを読む

EC-CUBE4とWordPressを連携する方法

EC-CUBE Advent Calendar 2020 15日目の記事です。

EC-CUBE4でWordPressの記事を取得する方法を先日書きました。

EC-CUBE4でWordPressの投稿記事を簡単に出力する方法 - AmidaikeBlog

今回は記事を取得するのではなく、WordPressからEC-CUBE4の関数やEC-CUBE4からWordPressの関数を利用できる方法を説明します。

ちなみにEC-CUBE2系はこちらの記事を参考にしてください。

qiita.com

今回は前回とは異なり、EC-CUBE4とWordPressは同階層にインストールするようにします。

というように、同一ドメイン、同階層でEC-CUBE4とWordPressが動作されている事を想定しています。

続きを読む

EC-CUBE4でお問い合わせ内容をDBへ保存する方法

EC-CUBE Advent Calendar 2020 11日目の記事です。

EC-CUBE4のお問い合わせフォームの内容は標準ではメールアドレスしか送られません。

ただ、お客様によっては時々お問い合わせフォームの内容をDBへ保存しておきたいという方がいます。

今回はお問い合わせフォームの内容をDBへ保存する方法を説明します。

続きを読む

EC-CUBE4でParsleyを利用したリアルタイムバリデーションの実装方法

EC-CUBE Advent Calendar 2020 8日目の記事です。

EC-CUBE4でフォーム画面の入力チェックはサーバ側のチェックで行っている画面と、HTML5のrequired属性を設定して入力チェックを行っている画面の2パターン存在しています。

サーバ側で入力チェックが必須なのは当然ですが、項目のフォーカスアウト時にリアルタイムバリデーションを行うように使い勝手をもう少し良くするために、入力チェックライブラリであるParsleyを利用します。

parsleyjs.org

利用方法はサイトを見れば一目瞭然なのですが、EC-CUBE4で利用する方法を説明します。

Parsleyのダウンロード、配置

Parsley - Download the pieces

こちらよりparsley.zipファイルをダウンロードします。
parsley.zipリンクを押すとGitHubの画面へ遷移するのでSource code (zip)をダウンロード後解凍し、distディレクトリにあるi18nディレクトリとparsley.min.jsを下記のディレクトリへ配置します。

html/template/default/assets/js

Parsleyの利用方法

会員登録入力画面を参考にParsleyを設定してみます。

src/Eccube/Resource/template/default/Entry/index.twig

ファイルを開き、以下の内容をを追記します。

{% block javascript %}
    <script src="//yubinbango.github.io/yubinbango/yubinbango.js" charset="UTF-8"></script>
{% endblock javascript %}{% block javascript %}
    <script src="//yubinbango.github.io/yubinbango/yubinbango.js" charset="UTF-8"></script>
    <script src="{{ asset('assets/js/parsley.min.js') }}"></script>
    <script src="{{ asset('assets/js/i18n/ja.js') }}"></script>
    <script>
        $(function() {
            Parsley.options.trigger = 'keyup focusout change input';

            $('#form1').parsley({
                classHandler: function(ParsleyField) {
                    return ParsleyField.$element;
                },
                errorsWrapper: '<p class="ec-errorMessage"></p>',
                errorTemplate: '<span></span>'
            }).on('field:validated', function() {
                var ok = $('.parsley-error').length === 0;
                if (!ok) {
                    $('.bg-load-overlay').remove();
                    if (this.$element.attr('required')) {
                        if (this.$element.hasClass('parsley-success')) {
                            this.$element.parent('div').removeClass('error');
                        } else {
                            this.$element.parent('div').addClass('error');
                        }
                    }
                }
            });
        });
    </script>
{% endblock javascript %}
Parsley.options.trigger = 'keyup focusout change input';

という箇所は、エラーチェックを行うタイミングを指定していますので、不要な方は削除してください。

次に、formタグにid属性を付与します。

<form method="post" action="{{ url('entry') }}" novalidate class="h-adr"><form id="form1" method="post" action="{{ url('entry') }}" novalidate class="h-adr">

この設定を行う事で、フォーカスアウト時にリアルタイムバリデーションを行ってくれるようになります。

一部デザイン崩れを起こす箇所もありますが、そこは適宜修正してください。

また、独自にデザインを作成している方は、parsleyに記載されている内容をデザインに合わせて修正してください。

Bootstrap4を利用してフォーム画面を作成されている方は以下の内容を適用する事でエラー箇所がキレイに表示されます。

$('#form1').parsley({
    errorClass: 'is-invalid',
    successClass: 'is-valid',
    classHandler: function(ParsleyField) {
        return ParsleyField.$element;
    },
    errorsWrapper: '<div class="invalid-feedback"></div>',
    errorTemplate: '<div></div>'
}).on('field:validated', function() {
    var ok = $('.is-invalid').length === 0;
    if (!ok) {
        $('.bg-load-overlay').remove();
    }
});

今回は必須入力のみのチェックを行なっていますが、他にも電話番号やメールアドレス等の入力チェックもありますので詳しくはParsleyのドキュメントをご覧ください。

EC-CUBE4で利用している郵便番号ライブラリの変更

EC-CUBE Advent Calendar 2020 6日目の記事です。

EC-CUBE4で会員登録等に住所補完を目的として利用している郵便番号ライブラリですが、こちらのyubinbangoライブラリを利用しています。

github.com

このライブラリは非常に便利なのですが、EC-CUBEにもissueが上がっているように一度入力した郵便番号へフォーカスを当てると、住所の項目が消えてしまいます。

github.com

通常利用している分にはそこまで大きな問題ではありませんが、どうしても不便だという方もいるため、別の郵便番号ライブラリを反映して対応するようにします。

ajaxzip3の利用

yubinbangoライブラリと同一作者が作成されているajaxzip3を利用します。

github.com

GitHubのREADMEにも記載されている通り、yubinbangoライブラリをオススメしているため、特に不都合がない方は無理に変更する必要はありません。

ソース変更箇所

郵便番号の住所補完を行なっている箇所は以下となります。

src/Eccube/Resource/template/default/Contact/index.twig
src/Eccube/Resource/template/default/Entry/index.twig
src/Eccube/Resource/template/default/Mypage/change.twig
src/Eccube/Resource/template/default/Mypage/delivery_edit.twig
src/Eccube/Resource/template/default/Shopping/nonmember.twig
src/Eccube/Resource/template/default/Shopping/shipping_edit.twig
src/Eccube/Resource/template/default/Shopping/shipping_multiple_edit.twig
src/Eccube/Resource/template/admin/Customer/delivery_edit.twig
src/Eccube/Resource/template/admin/Customer/edit.twig
src/Eccube/Resource/template/admin/Order/edit.twig
src/Eccube/Resource/template/admin/Order/shipping.twig
src/Eccube/Resource/template/admin/Setting/Shop/shop_master.twig

このtwigファイル内に記載されている箇所を以下のように変更します。

<script src="//yubinbango.github.io/yubinbango/yubinbango.js" charset="UTF-8"></script>
↓
<script src="//yubinbango.github.io/ajaxzip3/ajaxzip3.js" charset="UTF-8"></script>

次に、この郵便番号を利用できるようにfunction.jsへ処理を追加します。

処理内容はこちらを参考にさせてもらっています。

qiita.com

  • html/template/default/js/function.js
var postalHandler = function() {
    $postal = $('.p-postal-code');
    $region = $('.p-region-id');
    $locality = $('.p-locality');

    AjaxZip3.zip2addr($postal[0].name, '', $region[0].name, $locality[0].name, '', '', false);
};
$(function() {

    var postalHandler = function() {
        $postal = $('.p-postal-code');
        $region = $('.p-region-id');
        $locality = $('.p-locality');

        AjaxZip3.zip2addr($postal[0].name, '', $region[0].name, $locality[0].name, '', '', false);
    };
    $('.p-postal-code').change(function() {
        if ($(this).val().length >= 7) {
            postalHandler();
        }
    });

});
  • html/template/admin/assets/js/function.js
$(function() {

    var postalHandler = function(){
        $postal = $('.p-postal-code');
        $region = $('.p-region-id');
        $locality = $('.p-locality');

        AjaxZip3.zip2addr($postal[0].name, '', $region[0].name, $locality[0].name, '', '', false);
    };
    $('.p-postal-code').change(function(){
        if ($(this).val().length >= 7) {
            postalHandler();
        }
    });

});

また、app/template/admin/Order/edit.twigファイルのみ以下の処理を{% block javascript %}〜{% endblock javascript %}内へ記述します。

  • app/template/admin/Order/edit.twig
var postalHandler = function(id) {
    $postal = $(id + ' .p-postal-code');
    $region = $(id + ' .p-region-id');
    $locality = $(id + ' .p-locality');

    AjaxZip3.zip2addr($postal[0].name, '', $region[0].name, $locality[0].name, '', '', false);
};

$('#shippingInfo .p-postal-code').change(function() {
    if ($(this).val().length >= 7) {
        postalHandler('#shippingInfo');
    }
});
$('#ordererInfo .p-postal-code').change(function() {
    if ($(this).val().length >= 7) {
        postalHandler('#ordererInfo');
    }
});

以上でajaxzip3が利用できるようになり、郵便番号へフォーカスを当てても一度入力した住所が消えることはありません。

一点対応できていない箇所として、 p-street-addressp-extended-addressが対応できていませんので、そちらも適用させたい方は、

EC-CUBE4で郵便番号にTABでフォーカス移動すると番地が消える - Qiita

の処理をfunction.jsへ適用させるようにしてください。