source: branches/version-2_11-dev/data/class/SC_CartSession.php @ 20813

Revision 20813, 22.7 KB checked in by nanasess, 13 years ago (diff)

#1243 (決済モジュールから「戻る」場合の挙動改善)

  • 以下の関数を追加
    • SC_Helper_Purchase::cancelOrder()
    • SC_Helper_Purchase::rollbackOrder()
    • SC_Helper_Purchase::getOrderTempByOrderId()
  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-httpd-php; charset=UTF-8
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/* カートセッション管理クラス */
25class SC_CartSession {
26    /** ユニークIDを指定する. */
27    var $key_tmp;
28
29    /** カートのセッション変数. */
30    var $cartSession;
31
32    /* コンストラクタ */
33    function SC_CartSession($cartKey = 'cart') {
34        if (!isset($_SESSION[$cartKey])) {
35            $_SESSION[$cartKey] = array();
36        }
37        $this->cartSession =& $_SESSION[$cartKey];
38    }
39
40    // 商品購入処理中のロック
41    function saveCurrentCart($key_tmp, $productTypeId) {
42        $this->key_tmp = "savecart_" . $key_tmp;
43        // すでに情報がなければ現状のカート情報を記録しておく
44        if(count($_SESSION[$this->key_tmp]) == 0) {
45            $_SESSION[$this->key_tmp] = $this->cartSession[$productTypeId];
46        }
47        // 1世代古いコピー情報は、削除しておく
48        foreach($_SESSION as $k => $val) {
49            if($k != $this->key_tmp && preg_match("/^savecart_/", $k)) {
50                unset($this->cartSession[$productTypeId][$k]);
51            }
52        }
53    }
54
55    // 商品購入中の変更があったかをチェックする。
56    function getCancelPurchase($productTypeId) {
57        $ret = isset($this->cartSession[$productTypeId]['cancel_purchase'])
58            ? $this->cartSession[$productTypeId]['cancel_purchase'] : "";
59        $this->cartSession[$productTypeId]['cancel_purchase'] = false;
60        return $ret;
61    }
62
63    // 購入処理中に商品に変更がなかったかを判定
64    function checkChangeCart($productTypeId) {
65        $change = false;
66        $max = $this->getMax($productTypeId);
67        for($i = 1; $i <= $max; $i++) {
68            if ($this->cartSession[$productTypeId][$i]['quantity']
69                != $_SESSION[$this->key_tmp][$i]['quantity']) {
70
71                $change = true;
72                break;
73            }
74            if ($this->cartSession[$productTypeId][$i]['id']
75                != $_SESSION[$this->key_tmp][$i]['id']) {
76
77                $change = true;
78                break;
79            }
80        }
81        if ($change) {
82            // 一時カートのクリア
83            unset($_SESSION[$this->key_tmp]);
84            $this->cartSession[$productTypeId][$key]['cancel_purchase'] = true;
85        } else {
86            $this->cartSession[$productTypeId]['cancel_purchase'] = false;
87        }
88        return $this->cartSession[$productTypeId]['cancel_purchase'];
89    }
90
91    // 次に割り当てるカートのIDを取得する
92    function getNextCartID($productTypeId) {
93        foreach($this->cartSession[$productTypeId] as $key => $val){
94            $arrRet[] = $this->cartSession[$productTypeId][$key]['cart_no'];
95        }
96        return max($arrRet) + 1;
97    }
98
99    /**
100     * 商品ごとの合計価格
101     * XXX 実際には、「商品」ではなく、「カートの明細行(≒商品規格)」のような気がします。
102     *
103     * @param integer $id
104     * @return string 商品ごとの合計価格(税込み)
105     * @deprecated SC_CartSession::getCartList() を使用してください
106     */
107    function getProductTotal($id, $productTypeId) {
108        $max = $this->getMax($productTypeId);
109        for($i = 0; $i <= $max; $i++) {
110            if(isset($this->cartSession[$productTypeId][$i]['id'])
111               && $this->cartSession[$productTypeId][$i]['id'] == $id) {
112
113                // 税込み合計
114                $price = $this->cartSession[$productTypeId][$i]['price'];
115                $quantity = $this->cartSession[$productTypeId][$i]['quantity'];
116                $incTax = SC_Helper_DB_Ex::sfCalcIncTax($price);
117                $total = $incTax * $quantity;
118                return $total;
119            }
120        }
121        return 0;
122    }
123
124    // 値のセット
125    function setProductValue($id, $key, $val, $productTypeId) {
126        $max = $this->getMax($productTypeId);
127        for($i = 0; $i <= $max; $i++) {
128            if(isset($this->cartSession[$productTypeId][$i]['id'])
129               && $this->cartSession[$productTypeId][$i]['id'] == $id) {
130                $this->cartSession[$productTypeId][$i][$key] = $val;
131            }
132        }
133    }
134
135    // カート内商品の最大要素番号を取得する。
136    function getMax($productTypeId) {
137        $max = 0;
138        if (count($this->cartSession[$productTypeId]) > 0){
139            foreach($this->cartSession[$productTypeId] as $key => $val) {
140                if (is_numeric($key)) {
141                    if($max < $key) {
142                        $max = $key;
143                    }
144                }
145            }
146        }
147        return $max;
148    }
149
150    // カート内商品数の合計
151    function getTotalQuantity($productTypeId) {
152        $total = 0;
153        $max = $this->getMax($productTypeId);
154        for($i = 0; $i <= $max; $i++) {
155            $total+= $this->cartSession[$productTypeId][$i]['quantity'];
156        }
157        return $total;
158    }
159
160    // 全商品の合計価格
161    function getAllProductsTotal($productTypeId) {
162        // 税込み合計
163        $total = 0;
164        $max = $this->getMax($productTypeId);
165        for($i = 0; $i <= $max; $i++) {
166
167            if (!isset($this->cartSession[$productTypeId][$i]['price'])) {
168                $this->cartSession[$productTypeId][$i]['price'] = "";
169            }
170
171            $price = $this->cartSession[$productTypeId][$i]['price'];
172
173            if (!isset($this->cartSession[$productTypeId][$i]['quantity'])) {
174                $this->cartSession[$productTypeId][$i]['quantity'] = "";
175            }
176            $quantity = $this->cartSession[$productTypeId][$i]['quantity'];
177
178            $incTax = SC_Helper_DB_Ex::sfCalcIncTax($price);
179            $total+= ($incTax * $quantity);
180        }
181        return $total;
182    }
183
184    // 全商品の合計税金
185    function getAllProductsTax($productTypeId) {
186        // 税合計
187        $total = 0;
188        $max = $this->getMax($productTypeId);
189        for($i = 0; $i <= $max; $i++) {
190            $price = $this->cartSession[$productTypeId][$i]['price'];
191            $quantity = $this->cartSession[$productTypeId][$i]['quantity'];
192            $tax = SC_Helper_DB_Ex::sfTax($price);
193            $total+= ($tax * $quantity);
194        }
195        return $total;
196    }
197
198    // 全商品の合計ポイント
199    function getAllProductsPoint($productTypeId) {
200        // ポイント合計
201        $total = 0;
202        if (USE_POINT !== false) {
203            $max = $this->getMax($productTypeId);
204            for($i = 0; $i <= $max; $i++) {
205                $price = $this->cartSession[$productTypeId][$i]['price'];
206                $quantity = $this->cartSession[$productTypeId][$i]['quantity'];
207
208                if (!isset($this->cartSession[$productTypeId][$i]['point_rate'])) {
209                    $this->cartSession[$productTypeId][$i]['point_rate'] = "";
210                }
211                $point_rate = $this->cartSession[$productTypeId][$i]['point_rate'];
212
213                if (!isset($this->cartSession[$productTypeId][$i]['id'][0])) {
214                    $this->cartSession[$productTypeId][$i]['id'][0] = "";
215                }
216                $id = $this->cartSession[$productTypeId][$i]['id'][0];
217                $point = SC_Utils_Ex::sfPrePoint($price, $point_rate, POINT_RULE, $id);
218                $total+= ($point * $quantity);
219            }
220        }
221        return $total;
222    }
223
224    // カートへの商品追加
225    function addProduct($product_class_id, $quantity) {
226        $objProduct = new SC_Product_Ex();
227        $arrProduct = $objProduct->getProductsClass($product_class_id);
228        $productTypeId = $arrProduct['product_type_id'];
229        $find = false;
230        $max = $this->getMax($productTypeId);
231        for($i = 0; $i <= $max; $i++) {
232
233            if($this->cartSession[$productTypeId][$i]['id'] == $product_class_id) {
234                $val = $this->cartSession[$productTypeId][$i]['quantity'] + $quantity;
235                if(strlen($val) <= INT_LEN) {
236                    $this->cartSession[$productTypeId][$i]['quantity'] += $quantity;
237                }
238                $find = true;
239            }
240        }
241        if(!$find) {
242            $this->cartSession[$productTypeId][$max+1]['id'] = $product_class_id;
243            $this->cartSession[$productTypeId][$max+1]['quantity'] = $quantity;
244            $this->cartSession[$productTypeId][$max+1]['cart_no'] = $this->getNextCartID($productTypeId);
245        }
246    }
247
248    // 前頁のURLを記録しておく
249    function setPrevURL($url, $excludePaths = array()) {
250        // 前頁として記録しないページを指定する。
251        $arrExclude = array(
252            "/shopping/"
253        );
254        $arrExclude = array_merge($arrExclude, $excludePaths);
255        $exclude = false;
256        // ページチェックを行う。
257        foreach($arrExclude as $val) {
258            if(preg_match("|" . preg_quote($val) . "|", $url)) {
259                $exclude = true;
260                break;
261            }
262        }
263        // 除外ページでない場合は、前頁として記録する。
264        if(!$exclude) {
265            $_SESSION['prev_url'] = $url;
266        }
267    }
268
269    // 前頁のURLを取得する
270    function getPrevURL() {
271        return isset($_SESSION['prev_url']) ? $_SESSION['prev_url'] : "";
272    }
273
274    // キーが一致した商品の削除
275    function delProductKey($keyname, $val, $productTypeId) {
276        $max = count($this->cartSession[$productTypeId]);
277        for($i = 0; $i < $max; $i++) {
278            if($this->cartSession[$productTypeId][$i][$keyname] == $val) {
279                unset($this->cartSession[$productTypeId][$i]);
280            }
281        }
282    }
283
284    function setValue($key, $val, $productTypeId) {
285        $this->cartSession[$productTypeId][$key] = $val;
286    }
287
288    function getValue($key, $productTypeId) {
289        return $this->cartSession[$productTypeId][$key];
290    }
291
292    function getCartList($productTypeId) {
293        $objProduct = new SC_Product_Ex();
294        $max = $this->getMax($productTypeId);
295        $arrRet = array();
296        for($i = 0; $i <= $max; $i++) {
297            if(isset($this->cartSession[$productTypeId][$i]['cart_no'])
298               && $this->cartSession[$productTypeId][$i]['cart_no'] != "") {
299
300                if (SC_Utils_Ex::isBlank($this->cartSession[$productTypeId][$i]['productsClass'])) {
301                    $this->cartSession[$productTypeId][$i]['productsClass'] =&
302                            $objProduct->getDetailAndProductsClass(
303                                    $this->cartSession[$productTypeId][$i]['id']);
304                }
305
306                $price = $this->cartSession[$productTypeId][$i]['productsClass']['price02'];
307                $this->cartSession[$productTypeId][$i]['price'] = $price;
308
309                $this->cartSession[$productTypeId][$i]['point_rate'] =
310                    $this->cartSession[$productTypeId][$i]['productsClass']['point_rate'];
311
312                $quantity = $this->cartSession[$productTypeId][$i]['quantity'];
313                $incTax = SC_Helper_DB_Ex::sfCalcIncTax($price);
314                $total = $incTax * $quantity;
315
316                $this->cartSession[$productTypeId][$i]['total_inctax'] = $total;
317
318                $arrRet[] =& $this->cartSession[$productTypeId][$i];
319            }
320        }
321        return $arrRet;
322    }
323
324    /**
325     * すべてのカートの内容を取得する.
326     *
327     * @return array すべてのカートの内容
328     */
329    function getAllCartList() {
330        $results = array();
331        $cartKeys = $this->getKeys();
332        $i = 0;
333        foreach ($cartKeys as $key) {
334            $cartItems = $this->getCartList($key);
335            foreach (array_keys($cartItems) as $itemKey) {
336                $cartItem =& $cartItems[$itemKey];
337                $results[$key][$i] =& $cartItem;
338                $i++;
339            }
340        }
341        return $results;
342    }
343
344    // カート内にある商品IDを全て取得する
345    function getAllProductID($productTypeId) {
346        $max = $this->getMax($productTypeId);
347        for($i = 0; $i <= $max; $i++) {
348            if($this->cartSession[$productTypeId][$i]['cart_no'] != "") {
349                $arrRet[] = $this->cartSession[$productTypeId][$i]['id'][0];
350            }
351        }
352        return $arrRet;
353    }
354
355    /**
356     * カート内にある商品規格IDを全て取得する.
357     *
358     * @param integer $productTypeId 商品種別ID
359     * @return array 商品規格ID の配列
360     */
361    function getAllProductClassID($productTypeId) {
362        $max = $this->getMax($productTypeId);
363        for($i = 0; $i <= $max; $i++) {
364            if($this->cartSession[$productTypeId][$i]['cart_no'] != "") {
365                $arrRet[] = $this->cartSession[$productTypeId][$i]['id'];
366            }
367        }
368        return $arrRet;
369    }
370
371    function delAllProducts($productTypeId) {
372        $max = $this->getMax($productTypeId);
373        for($i = 0; $i <= $max; $i++) {
374            unset($this->cartSession[$productTypeId][$i]);
375        }
376    }
377
378    // 商品の削除
379    function delProduct($cart_no, $productTypeId) {
380        $max = $this->getMax($productTypeId);
381        for($i = 0; $i <= $max; $i++) {
382            if($this->cartSession[$productTypeId][$i]['cart_no'] == $cart_no) {
383                unset($this->cartSession[$productTypeId][$i]);
384            }
385        }
386    }
387
388    // 数量の増加
389    function upQuantity($cart_no, $productTypeId) {
390        $quantity = $this->getQuantity($cart_no, $productTypeId);
391        if (strlen($quantity + 1) <= INT_LEN) {
392            $this->setQuantity($quantity + 1, $cart_no, $productTypeId);
393        }
394    }
395
396    // 数量の減少
397    function downQuantity($cart_no, $productTypeId) {
398        $quantity = $this->getQuantity($cart_no, $productTypeId);
399        if ($quantity > 1) {
400            $this->setQuantity($quantity - 1, $cart_no, $productTypeId);
401        }
402    }
403
404    function getQuantity($cart_no, $productTypeId) {
405        $max = $this->getMax($productTypeId);
406        for ($i = 0; $i <= $max; $i++) {
407            if ($this->cartSession[$productTypeId][$i]['cart_no'] == $cart_no) {
408                return $this->cartSession[$productTypeId][$i]['quantity'];
409            }
410        }
411    }
412
413    function setQuantity($quantity, $cart_no, $productTypeId) {
414        $max = $this->getMax($productTypeId);
415        for ($i = 0; $i <= $max; $i++) {
416            if ($this->cartSession[$productTypeId][$i]['cart_no'] == $cart_no) {
417                $this->cartSession[$productTypeId][$i]['quantity'] = $quantity;
418            }
419        }
420    }
421
422    function getProductClassId($cart_no, $productTypeId) {
423        for ($i = 0; $i <= $max; $i++) {
424            if ($this->cartSession[$productTypeId][$i]['cart_no'] == $cart_no) {
425                return $this->cartSession[$productTypeId][$i]['id'];
426            }
427        }
428    }
429
430    /**
431     * カート内の商品の妥当性をチェックする.
432     *
433     * エラーが発生した場合は, 商品をカート内から削除又は数量を調整し,
434     * エラーメッセージを返す.
435     *
436     * 1. 商品種別に関連づけられた配送業者の存在チェック
437     * 2. 削除/非表示商品のチェック
438     * 3. 商品購入制限数のチェック
439     * 4. 在庫数チェック
440     *
441     * @param string $key 商品種別ID
442     * @return string エラーが発生した場合はエラーメッセージ
443     */
444    function checkProducts($productTypeId) {
445        $objProduct = new SC_Product_Ex();
446        $tpl_message = "";
447
448        // カート内の情報を取得
449        $items = $this->getCartList($productTypeId);
450        foreach (array_keys($items) as $key) {
451            $item =& $items[$key];
452            $product =& $item['productsClass'];
453
454            /*
455             * 配送業者のチェック
456             */
457            $arrDeliv = SC_Helper_Purchase_Ex::getDeliv($productTypeId);
458            if (SC_Utils_Ex::isBlank($arrDeliv)) {
459                $tpl_message .= "※「" . $product['name'] . "」はまだ配送の準備ができておりません。恐れ入りますがお問い合わせページよりお問い合わせください。\n";
460            }
461
462            /*
463             * 表示/非表示商品のチェック
464             */
465            if (SC_Utils_Ex::isBlank($product)) {
466                $this->delProduct($item['cart_no'], $productTypeId);
467                $tpl_message .= "※ 現時点で販売していない商品が含まれておりました。該当商品をカートから削除しました。\n";
468            }
469
470            /*
471             * 商品購入制限数, 在庫数のチェック
472             */
473            $limit = $objProduct->getBuyLimit($product);
474            if (!is_null($limit) && $item['quantity'] > $limit) {
475                if ($limit > 0) {
476                    $this->setProductValue($item['id'], 'quantity', $limit, $productTypeId);
477                    $tpl_message .= "※「" . $product['name'] . "」は販売制限(または在庫が不足)しております。一度に数量{$limit}以上の購入はできません。\n";
478                } else {
479                    $this->delProduct($item['cart_no'], $productTypeId);
480                    $tpl_message .= "※「" . $product['name'] . "」は売り切れました。\n";
481                    continue;
482                }
483            }
484        }
485        return $tpl_message;
486    }
487
488    /**
489     * カートの内容を計算する.
490     *
491     * カートの内容を計算し, 下記のキーを保持する連想配列を返す.
492     *
493     * - tax: 税額
494     * - subtotal: カート内商品の小計
495     * - deliv_fee: カート内商品の合計送料 FIXME
496     * - total: 合計金額
497     * - payment_total: お支払い合計
498     * - add_point: 加算ポイント
499     *
500     *  TODO ダウンロード商品のみの場合の送料を検討する
501     *  TODO 使用ポイント, 配送都道府県, 支払い方法, 手数料の扱いを検討
502     *
503     * @param integer $productTypeId 商品種別ID
504     * @param SC_Customer $objCustomer ログイン中の SC_Customer インスタンス
505     * @param integer $use_point 今回使用ポイント
506     * @param integer|array $deliv_pref 配送先都道府県ID.
507                                        複数に配送する場合は都道府県IDの配列
508     * @param integer $charge 手数料
509     * @param integer $discount 値引
510     * @param integer $deliv_id 配送業者ID
511     * @return array カートの計算結果の配列
512     */
513    function calculate($productTypeId, &$objCustomer, $use_point = 0,
514                       $deliv_pref = "", $charge = 0, $discount = 0, $deliv_id = 0) {
515        $objDb = new SC_Helper_DB_Ex();
516
517        $total_point = $this->getAllProductsPoint($productTypeId);
518        $results['tax'] = $this->getAllProductsTax($productTypeId);
519        $results['subtotal'] = $this->getAllProductsTotal($productTypeId);
520        $results['deliv_fee'] = 0;
521
522        // 商品ごとの送料を加算
523        if (OPTION_PRODUCT_DELIV_FEE == 1) {
524            $cartItems = $this->getCartList($productTypeId);
525            foreach ($cartItems as $item) {
526                $results['deliv_fee'] += $item['deliv_fee'] * $item['quantity'];
527            }
528        }
529
530        // 配送業者の送料を加算
531        if (OPTION_DELIV_FEE == 1
532            && !SC_Utils_Ex::isBlank($deliv_pref)
533            && !SC_Utils_Ex::isBlank($deliv_id)) {
534            $results['deliv_fee'] += $objDb->sfGetDelivFee($deliv_pref, $deliv_id);
535        }
536
537        // 送料無料の購入数が設定されている場合
538        if (DELIV_FREE_AMOUNT > 0) {
539            // 商品の合計数量
540            $total_quantity = $this->getTotalQuantity($productTypeId);
541
542            if($total_quantity >= DELIV_FREE_AMOUNT) {
543                $results['deliv_fee'] = 0;
544            }
545        }
546
547        // 送料無料条件が設定されている場合
548        $arrInfo = $objDb->sfGetBasisData();
549        if($arrInfo['free_rule'] > 0) {
550            // 小計が無料条件を超えている場合
551            if($results['subtotal'] >= $arrInfo['free_rule']) {
552                $results['deliv_fee'] = 0;
553            }
554        }
555
556        // 合計を計算
557        $results['total'] = $results['subtotal'];
558        $results['total'] += $results['deliv_fee'];
559        $results['total'] += $charge;
560        $results['total'] -= $discount;
561
562        // お支払い合計
563        $results['payment_total'] = $results['total'] - $use_point * POINT_VALUE;
564
565        // 加算ポイントの計算
566        if (USE_POINT !== false) {
567            $results['add_point'] = SC_Helper_DB_Ex::sfGetAddPoint($total_point,
568                                                                   $use_point);
569            if($objCustomer != "") {
570                // 誕生日月であった場合
571                if($objCustomer->isBirthMonth()) {
572                    $results['birth_point'] = BIRTH_MONTH_POINT;
573                    $results['add_point'] += $results['birth_point'];
574                }
575            }
576            if($results['add_point'] < 0) {
577                $results['add_point'] = 0;
578            }
579        }
580        return $results;
581    }
582
583    function getKeys() {
584        $keys = array_keys($this->cartSession);
585        // 数量が 0 の商品種別は削除する
586        foreach ($keys as $key) {
587            $quantity = $this->getTotalQuantity($key);
588            if ($quantity < 1) {
589                unset($this->cartSession[$key]);
590            }
591        }
592        return array_keys($this->cartSession);
593    }
594
595    function registerKey($key) {
596        $_SESSION['cartKey'] = $key;
597    }
598
599    function unsetKey() {
600        unset($_SESSION['cartKey']);
601    }
602
603    function getKey() {
604        return $_SESSION['cartKey'];
605    }
606
607    /**
608     * 複数配送扱いかどうか.
609     *
610     * @return boolean カートが複数配送扱いの場合 true
611     */
612    function isMultiple() {
613        return count($this->getKeys()) > 1;
614    }
615
616    /**
617     * 引数の商品種別の商品がカートに含まれるかどうか.
618     *
619     * @param integer $product_type_id 商品種別ID
620     * @return boolean 指定の商品種別がカートに含まれる場合 true
621     */
622    function hasProductType($product_type_id) {
623        return in_array($product_type_id, $this->getKeys());
624    }
625}
626?>
Note: See TracBrowser for help on using the repository browser.