source: branches/version-2_11-dev/data/class/pages/admin/order/LC_Page_Admin_Order_UploadCSVDetail.php @ 20865

Revision 20865, 21.8 KB checked in by saiteisan, 11 years ago (diff)

refs #1197(新規受注明細登録CSV)

Line 
1<?php
2/*
3 * This file is part of EC-CUBE
4 *
5 * Copyright(c) 2000-2011 LOCKON CO.,LTD. All Rights Reserved.
6 *
7 * http://www.lockon.co.jp/
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22 */
23
24// {{{ requires
25require_once CLASS_EX_REALDIR . 'page_extends/admin/LC_Page_Admin_Ex.php';
26require_once CLASS_EX_REALDIR . 'helper_extends/SC_Helper_CSV_Ex.php';
27
28/**
29 * 受注登録CSVのページクラス.
30 *
31 * @package Page
32 * @author LOCKON CO.,LTD.
33 *
34 */
35class LC_Page_Admin_Order_UploadCSVDetail extends LC_Page_Admin_Ex {
36
37    // }}}
38    // {{{ functions
39
40    /** TAGエラーチェックフィールド情報 */
41    var $arrTagCheckItem;
42
43    /** 受注テーブルカラム情報 (登録処理用) **/
44    var $arrOrderColumn;
45
46    /** 登録フォームカラム情報 **/
47    var $arrFormKeyList;
48
49    var $arrRowErr;
50
51    var $arrRowResult;
52
53    /**
54     * Page を初期化する.
55     *
56     * @return void
57     */
58    function init() {
59        parent::init();
60        $this->tpl_mainpage = 'order/upload_csv_detail.tpl';
61        $this->tpl_subnavi = 'order/subnavi.tpl';
62        $this->tpl_mainno = 'order';
63        $this->tpl_subno = 'upload_csv';
64        $this->tpl_subtitle = '受注明細追加登録CSV';
65        $this->csv_id = '10';
66
67        $masterData = new SC_DB_MasterData_Ex();
68        $this->arrDISP = $masterData->getMasterData("mtb_disp");
69        $this->arrSTATUS = $masterData->getMasterData("mtb_status");
70        $this->arrOrderSTATUS = $masterData->getMasterData("mtb_order_status");
71        $this->arrDELIVERYDATE = $masterData->getMasterData("mtb_delivery_date");
72        $this->arrPayments = SC_Helper_DB_Ex::sfGetIDValueList("dtb_payment", "payment_id", "payment_method");
73        $this->arrInfo = SC_Helper_DB_Ex::sfGetBasisData();
74        $this->arrAllowedTag = $masterData->getMasterData("mtb_allowed_tag");
75        $this->arrTagCheckItem = array();
76    }
77
78    /**
79     * Page のプロセス.
80     *
81     * @return void
82     */
83    function process() {
84        $this->action();
85        $this->sendResponse();
86    }
87
88    /**
89     * Page のアクション.
90     *
91     * @return void
92     */
93    function action() {
94        $this->objDb = new SC_Helper_DB_Ex();
95
96        // CSV管理ヘルパー
97        $objCSV = new SC_Helper_CSV_Ex();
98        // CSV構造読み込み
99        $arrCSVFrame = $objCSV->sfGetCsvOutput($this->csv_id);
100
101        // CSV構造がインポート可能かのチェック
102        if(!$objCSV->sfIsImportCSVFrame($arrCSVFrame) ) {
103            // 無効なフォーマットなので初期状態に強制変更
104            $arrCSVFrame = $objCSV->sfGetCsvOutput($this->csv_id, '', array(), 'no');
105            $this->tpl_is_format_default = true;
106        }
107        // CSV構造は更新可能なフォーマットかのフラグ取得
108        $this->tpl_is_update = $objCSV->sfIsUpdateCSVFrame($arrCSVFrame);
109
110        // CSVファイルアップロード情報の初期化
111        $objUpFile = new SC_UploadFile_Ex(IMAGE_TEMP_REALDIR, IMAGE_SAVE_REALDIR);
112        $this->lfInitFile($objUpFile);
113
114        // パラメータ情報の初期化
115        $objFormParam = new SC_FormParam_Ex();
116        $this->lfInitParam($objFormParam, $arrCSVFrame);
117
118        $objFormParam->setHtmlDispNameArray();
119        $this->arrTitle = $objFormParam->getHtmlDispNameArray();
120
121        switch($this->getMode()) {
122        case 'csv_upload':
123            $this->doUploadCsv($objFormParam, $objUpFile);
124            break;
125        default:
126            break;
127        }
128    }
129
130    /**
131     * 登録/編集結果のメッセージをプロパティへ追加する
132     *
133     * @param integer $line_count 行数
134     * @param stirng $message メッセージ
135     * @return void
136     */
137    function addRowResult($line_count, $message) {
138        $this->arrRowResult[] = $line_count . "行目:" . $message;
139    }
140
141    /**
142     * 登録/編集結果のエラーメッセージをプロパティへ追加する
143     *
144     * @param integer $line_count 行数
145     * @param stirng $message メッセージ
146     * @return void
147     */
148    function addRowErr($line_count, $message) {
149        $this->arrRowErr[] = $line_count . "行目:" . $message;
150    }
151
152    /**
153     * CSVアップロードを実行します.
154     *
155     * @return void
156     */
157    function doUploadCsv(&$objFormParam, &$objUpFile) {
158        // ファイルアップロードのチェック
159        $objUpFile->makeTempFile('csv_file');
160        $arrErr = $objUpFile->checkExists();
161        if (count($arrErr) > 0) {
162            $this->arrErr = $arrErr;
163            return;
164        }
165        // 一時ファイル名の取得
166        $filepath = $objUpFile->getTempFilePath('csv_file');
167        // CSVファイルの文字コード変換
168        $enc_filepath = SC_Utils_Ex::sfEncodeFile($filepath, CHAR_CODE, CSV_TEMP_REALDIR);
169        // CSVファイルのオープン
170        $fp = fopen($enc_filepath, 'r');
171        // 失敗した場合はエラー表示
172        if (!$fp) {
173             SC_Utils_Ex::sfDispError("");
174        }
175
176        // 登録先テーブル カラム情報の初期化
177        $this->lfInitTableInfo();
178
179        // 登録フォーム カラム情報
180        $this->arrFormKeyList = $objFormParam->getKeyList();
181
182        // 登録対象の列数
183        $col_max_count = $objFormParam->getCount();
184        // 行数
185        $line_count = 0;
186
187        $objQuery =& SC_Query_Ex::getSingletonInstance();
188        $objQuery->begin();
189
190        $errFlag = false;
191        $all_line_checked = false;
192
193        while (!feof($fp)) {
194            $arrCSV = fgetcsv($fp, CSV_LINE_MAX);
195
196            // 全行入力チェック後に、ファイルポインターを先頭に戻す
197            if (feof($fp) && !$all_line_checked) {
198                rewind($fp);
199                $line_count = 0;
200                $all_line_checked = true;
201                continue;
202            }
203
204            // 行カウント
205            $line_count++;
206            // ヘッダ行はスキップ
207            if ($line_count == 1) {
208                continue;
209            }
210            // 空行はスキップ
211            if (empty($arrCSV)) {
212                continue;
213            }
214            // 列数が異なる場合はエラー
215            $col_count = count($arrCSV);
216            if ($col_max_count != $col_count) {
217                $this->addRowErr($line_count, "※ 項目数が" . $col_count . "個検出されました。項目数は" . $col_max_count . "個になります。");
218                $errFlag = true;
219                break;
220            }
221            // シーケンス配列を格納する。
222            $objFormParam->setParam($arrCSV, true);
223            $arrRet = $objFormParam->getHashArray();
224            $objFormParam->setParam($arrRet);
225            // 入力値の変換
226            $objFormParam->convParam();
227            // <br>なしでエラー取得する。
228            $arrCSVErr = $this->lfCheckError($objFormParam);
229
230            // 入力エラーチェック
231            if (count($arrCSVErr) > 0) {
232                foreach ($arrCSVErr as $err) {
233                    $this->addRowErr($line_count, $err);
234                }
235                $errFlag = true;
236                break;
237            }
238           
239            $product_class_id = $this->lfGetProductClassId($objQuery,$objFormParam);
240
241            if(!is_numeric($product_class_id)){
242                $this->addRowErr($line_count, '規格が存在しません。');
243                $errFlag = true;
244                break;
245            }
246           
247            if ($all_line_checked) {
248                $this->lfRegistOrder($objQuery, $line_count, $objFormParam, $product_class_id);
249                $arrParam = $objFormParam->getHashArray();
250
251                $this->addRowResult($line_count, "受注ID:".$arrParam['order_id'] ."/商品ID:". $arrParam['product_id']);
252            }
253        }
254
255        // 実行結果画面を表示
256        $this->tpl_mainpage = 'order/upload_csv_detail_complete.tpl';
257
258        fclose($fp);
259
260        if ($errFlag) {
261            $objQuery->rollback();
262            return;
263        }
264
265        $objQuery->commit();
266        return;
267    }
268
269    /**
270     * デストラクタ.
271     *
272     * @return void
273     */
274    function destroy() {
275        parent::destroy();
276    }
277
278    /**
279     * ファイル情報の初期化を行う.
280     *
281     * @return void
282     */
283    function lfInitFile(&$objUpFile) {
284        $objUpFile->addFile("CSVファイル", 'csv_file', array('csv'), CSV_SIZE, true, 0, 0, false);
285    }
286
287    /**
288     * 入力情報の初期化を行う.
289     *
290     * @param array CSV構造設定配列
291     * @return void
292     */
293    function lfInitParam(&$objFormParam, &$arrCSVFrame) {
294        // 固有の初期値調整
295        $arrCSVFrame = $this->lfSetParamDefaultValue($arrCSVFrame);
296        // CSV項目毎の処理
297        foreach($arrCSVFrame as $item) {
298            if($item['status'] == CSV_COLUMN_STATUS_FLG_DISABLE) continue;
299            //サブクエリ構造の場合は AS名 を使用
300            if(preg_match_all('/\(.+\)[ ]*as[ ]*(.+)$/i', $item['col'], $match, PREG_SET_ORDER)) {
301                $col = $match[0][1];
302            }else{
303                $col = $item['col'];
304            }
305            // HTML_TAG_CHECKは別途実行なので除去し、別保存しておく
306            if(strpos(strtoupper($item['error_check_types']), 'HTML_TAG_CHECK') !== FALSE) {
307                $this->arrTagCheckItem[] = $item;
308                $error_check_types = str_replace('HTML_TAG_CHECK', '', $item['error_check_types']);
309            }else{
310                $error_check_types = $item['error_check_types'];
311            }
312            $arrErrorCheckTypes = explode(',', $error_check_types);
313            foreach($arrErrorCheckTypes as $key => $val) {
314                if(trim($val) == "") {
315                    unset($arrErrorCheckTypes[$key]);
316                }else{
317                    $arrErrorCheckTypes[$key] = trim($val);
318                }
319            }
320            // パラメーター登録
321            $objFormParam->addParam(
322                    $item['disp_name']
323                    , $col
324                    , constant($item['size_const_type'])
325                    , $item['mb_convert_kana_option']
326                    , $arrErrorCheckTypes
327                    , $item['default']
328                    , ($item['rw_flg'] != CSV_COLUMN_RW_FLG_READ_ONLY) ? true : false
329                    );
330        }
331    }
332
333    /**
334     * 入力チェックを行う.
335     *
336     * @return void
337     */
338    function lfCheckError(&$objFormParam) {
339        // 入力データを渡す。
340        $arrRet =  $objFormParam->getHashArray();
341        $objErr = new SC_CheckError_Ex($arrRet);
342        $objErr->arrErr = $objFormParam->checkError(false);
343        // HTMLタグチェックの実行
344        foreach($this->arrTagCheckItem as $item) {
345            $objErr->doFunc(array( $item['disp_name'], $item['col'], $this->arrAllowedTag), array("HTML_TAG_CHECK"));
346        }
347        // このフォーム特有の複雑系のエラーチェックを行う
348        if(count($objErr->arrErr) == 0) {
349            $objErr->arrErr = $this->lfCheckErrorDetail($arrRet, $objErr->arrErr);
350        }
351        return $objErr->arrErr;
352    }
353
354    /**
355     * 保存先テーブル情報の初期化を行う.
356     *
357     * @return void
358     */
359    function lfInitTableInfo() {
360        $objQuery =& SC_Query_Ex::getSingletonInstance();
361        $this->arrOrderColumn = $objQuery->listTableFields('dtb_order_detail');
362    }
363   
364    /**
365     * 規格名称等からproduct_class_idを出す.
366     *
367     *
368     * @param SC_Query $objQuery SC_Queryインスタンス
369     * @return product_class_id 規格ID
370     */
371    function lfGetProductClassId($objQuery,$objFormParam){
372        // 登録データ対象取得
373        $arrList = $objFormParam->getHashArray();
374        //規格ある場合
375        if($arrList['parent_class_name'] != "" && $arrList['parent_classcategory_name'] != ""){
376        $parent_class_id = $objQuery->getOne("SELECT class_id FROM dtb_class WHERE name = ?", array($arrList['parent_class_name']));
377        $classcategory_id1 = $objQuery->getOne("SELECT classcategory_id FROM dtb_classcategory WHERE class_id =? AND name = ?", array($parent_class_id,$arrList['parent_classcategory_name']));
378
379        $class_combination_id = $objQuery->select("class_combination_id", "dtb_class_combination", "classcategory_id = ?", array($classcategory_id1));
380        // where文作成
381        $where = "";
382        $arrval = array();
383        foreach($class_combination_id as $val){
384            if($where == ""){
385                $where = "( parent_class_combination_id = ?";
386            }else{
387                $where .= " OR parent_class_combination_id = ?";
388            }
389                $arrval[] = $val['class_combination_id'];
390        }
391        $where .= " )";
392        if($arrList['class_name'] != "" && $arrList['classcategory_name'] != ""){
393            $class_id = $objQuery->getOne("SELECT class_id FROM dtb_class WHERE name = ?", array($arrList['class_name']));
394            $classcategory_id2 = $objQuery->getOne("SELECT classcategory_id FROM dtb_classcategory WHERE class_id =? AND name = ?", array($class_id,$arrList['classcategory_name']));
395            $where .= " AND classcategory_id = ?";
396            $arrval[] = $classcategory_id2;
397           
398            $class_combination_id = $objQuery->getOne("SELECT class_combination_id FROM dtb_class_combination WHERE ".$where, $arrval);
399            $product_class_id = $objQuery->getOne("SELECT product_class_id FROM dtb_products_class WHERE product_id = ? AND class_combination_id = ?", array($arrList['product_id'], $class_combination_id));
400        }else{
401            $where .= " AND product_id = ?";
402            $arrval[] = $arrList['product_id'];
403            $product_class_id = $objQuery->getOne("SELECT product_class_id FROM dtb_products_class WHERE ".$where, $arrval);
404        }
405
406        //規格無い場合
407        }else{
408            $product_class_id = $objQuery->getOne("SELECT product_class_id FROM dtb_products_class WHERE product_id = ? AND class_combination_id IS NULL", array($arrList['product_id']));
409        }
410        /*
411        if($arrList['parent_classcategory_name'] != ""){
412            $sqlval['classcategory_name1'] = $arrList['parent_classcategory_name'];
413        }else{
414            $sqlval['classcategory_name1'] = NULL;
415        }
416       
417        if($arrList['classcategory_name'] != ""){
418            $sqlval['classcategory_name2'] = $arrList['classcategory_name'];
419        }else{
420            $sqlval['classcategory_name2'] = NULL;
421        }
422        */
423        return $product_class_id;
424    }
425   
426   
427    /**
428     * 新規受注登録を行う.
429     *
430     *
431     * @param SC_Query $objQuery SC_Queryインスタンス
432     * @param string|integer $line 処理中の行数
433     * @return void
434     */
435    function lfRegistOrder($objQuery, $line = "", &$objFormParam, $product_class_id) {
436        // 登録データ対象取得
437        $arrList = $objFormParam->getHashArray();
438
439        // 商品テーブルのカラムに存在しているもののうち、Form投入設定されていないデータは上書きしない。
440        $sqlval = SC_Utils_Ex::sfArrayIntersectKeys($arrList, $this->arrOrderColumn);
441       
442        $sqlval['product_class_id'] = $product_class_id;
443
444        // 必須入力では無い項目だが、空文字では問題のある特殊なカラム値の初期値設定
445        $sqlval = $this->lfSetOrderDefaultData($sqlval);
446        $sqlval['order_detail_id'] = $objQuery->nextVal('dtb_order_detail_order_detail_id');
447        // INSERTの実行
448        $objQuery->insert("dtb_order_detail", $sqlval);
449           
450    }
451
452    /**
453     * 初期値の設定
454     *
455     * @param array $arrCSVFrame CSV構造配列
456     * @return array $arrCSVFrame CSV構造配列
457     */
458    function lfSetParamDefaultValue(&$arrCSVFrame) {
459        foreach($arrCSVFrame as $key => $val) {
460            switch($val['col']) {
461                default:
462                    break;
463            }
464        }
465        return $arrCSVFrame;
466    }
467
468    /**
469     * 受注データ登録前に特殊な値の持ち方をする部分のデータ部分の初期値補正を行う
470     *
471     * @param array $sqlval 受注登録情報配列
472     * @return $sqlval 登録情報配列
473     */
474    function lfSetOrderDefaultData(&$sqlval) {
475        return $sqlval;
476    }
477
478    /**
479     * このフォーム特有の複雑な入力チェックを行う.
480     *
481     * @param array 確認対象データ
482     * @param array エラー配列
483     * @return array エラー配列
484     */
485    function lfCheckErrorDetail($item, $arrErr) {
486        // 受注IDの存在チェック
487        if(!$this->lfIsDbRecord('dtb_order', 'order_id', $item)) {
488            $arrErr['order_id'] = "※ 指定の受注IDは、登録されていません。";
489        }
490        // 商品IDの存在チェック
491        if(!$this->lfIsDbRecord('dtb_products', 'product_id', $item)) {
492            $arrErr['order_id'] = "※ 指定の受注IDは、登録されていません。";
493        }
494        $objQuery =& SC_Query_Ex::getSingletonInstance();
495        return $arrErr;
496    }
497
498    // TODO: ここから下のルーチンは汎用ルーチンとして移動が望ましい
499
500    /**
501     * 指定された行番号をmicrotimeに付与してDB保存用の時間を生成する。
502     * トランザクション内のnow()は全てcommit()時の時間に統一されてしまう為。
503     *
504     * @param string $line_no 行番号
505     * @return string $time DB保存用の時間文字列
506     */
507    function lfGetDbFormatTimeWithLine($line_no = '') {
508        $time = date("Y-m-d H:i:s");
509        // 秒以下を生成
510        if($line_no != '') {
511            $microtime = sprintf("%06d", $line_no);
512            $time .= ".$microtime";
513        }
514        return $time;
515    }
516
517    /**
518     * 指定されたキーと複数値の有効性の配列内確認
519     *
520     * @param string $arr チェック対象配列
521     * @param string $keyname フォームキー名
522     * @param array  $item 入力データ配列
523     * @param string $delimiter 分割文字
524     * @return boolean true:有効なデータがある false:有効ではない
525     */
526    function lfIsArrayRecordMulti($arr, $keyname, $item, $delimiter = ',') {
527        if(array_search($keyname, $this->arrFormKeyList) === FALSE) {
528            return true;
529        }
530        if($item[$keyname] == "") {
531            return true;
532        }
533        $arrItems = explode($delimiter, $item[$keyname]);
534        //空項目のチェック 1つでも空指定があったら不正とする。
535        if(array_search("", $arrItems) !== FALSE) {
536            return false;
537        }
538        //キー項目への存在チェック
539        foreach($arrItems as $item) {
540            if(!array_key_exists($item, $arr)) {
541                return false;
542            }
543        }
544        return true;
545    }
546
547    /**
548     * 指定されたキーと複数値の有効性のDB確認
549     *
550     * @param string $table テーブル名
551     * @param string $tblkey テーブルキー名
552     * @param string $keyname フォームキー名
553     * @param array  $item 入力データ配列
554     * @param string $delimiter 分割文字
555     * @return boolean true:有効なデータがある false:有効ではない
556     */
557    function lfIsDbRecordMulti($table, $tblkey, $keyname, $item, $delimiter = ',') {
558        if(array_search($keyname, $this->arrFormKeyList) === FALSE) {
559            return true;
560        }
561        if($item[$keyname] == "") {
562            return true;
563        }
564        $arrItems = explode($delimiter, $item[$keyname]);
565        //空項目のチェック 1つでも空指定があったら不正とする。
566        if(array_search("", $arrItems) !== FALSE) {
567            return false;
568        }
569        $count = count($arrItems);
570        $where = $tblkey ." IN (" . implode(",", array_fill(0, $count, "?")) . ")";
571
572        $objQuery =& SC_Query_Ex::getSingletonInstance();
573        $db_count = $objQuery->count($table, $where, $arrItems);
574        if($count != $db_count) {
575            return false;
576        }
577        return true;
578    }
579
580    /**
581     * 指定されたキーと値の有効性のDB確認
582     *
583     * @param string $table テーブル名
584     * @param string $keyname キー名
585     * @param array  $item 入力データ配列
586     * @return boolean true:有効なデータがある false:有効ではない
587     */
588    function lfIsDbRecord($table, $keyname, $item) {
589        if(array_search($keyname, $this->arrFormKeyList) !== FALSE  //入力対象である
590                and $item[$keyname] != ""   // 空ではない
591                and !$this->objDb->sfIsRecord($table, $keyname, (array)$item[$keyname]) //DBに存在するか
592                ) {
593            return false;
594        }
595        return true;
596    }
597
598    /**
599     * 指定されたキーと値の有効性の配列内確認
600     *
601     * @param string $arr チェック対象配列
602     * @param string $keyname キー名
603     * @param array  $item 入力データ配列
604     * @return boolean true:有効なデータがある false:有効ではない
605     */
606    function lfIsArrayRecord($arr, $keyname, $item) {
607        if(array_search($keyname, $this->arrFormKeyList) !== FALSE //入力対象である
608                and $item[$keyname] != "" // 空ではない
609                and !array_key_exists($item[$keyname], $arr) //配列に存在するか
610                ) {
611            return false;
612        }
613        return true;
614    }
615}
Note: See TracBrowser for help on using the repository browser.