<?php
/*
 * shopping/DaoShoppingOrder.class.php
 * 
 * CopyRight(C) 2010 Shopformer Development Team. All Right Reserved
 * URL: http://sourceforge.jp/projects/shopformer/
 * 
 * 
 * Mail: m_nakashima@users.sourceforge.jp
 * Auther: Masanori Nakashima
 * Last Update: 2010-06-18
 */
require_once( dirname(__FILE__)
.DIRECTORY_SEPARATOR.'PackageConfig.class.php');
require_once( dirname(dirname( __FILE__ ))
.DIRECTORY_SEPARATOR.'database2'
.DIRECTORY_SEPARATOR.'AbstractData.class.php');
require_once( dirname(dirname( __FILE__ ))
.DIRECTORY_SEPARATOR.'member'
.DIRECTORY_SEPARATOR.'DaoMember.class.php');
require_once( dirname(dirname( __FILE__ ))
.DIRECTORY_SEPARATOR.'util'
.DIRECTORY_SEPARATOR.'Mail.class.php');
require_once( dirname(dirname( __FILE__ ))
.DIRECTORY_SEPARATOR.'util'
.DIRECTORY_SEPARATOR.'CharUtility.class.php');
require_once( dirname(dirname( __FILE__ ))
.DIRECTORY_SEPARATOR.'system'
.DIRECTORY_SEPARATOR.'DataFileWriter.class.php');
require_once( dirname(__FILE__)
.DIRECTORY_SEPARATOR.'DaoShoppingOrderAddress.class.php');
require_once( dirname(__FILE__)
.DIRECTORY_SEPARATOR.'DaoShoppingOrderItem.class.php');
require_once( dirname(__FILE__)
.DIRECTORY_SEPARATOR.'DaoShoppingOrderOption.class.php');
require_once( dirname(__FILE__)
.DIRECTORY_SEPARATOR.'DaoShoppingProduct.class.php');
require_once( dirname(__FILE__)
.DIRECTORY_SEPARATOR.'DaoShoppingProductUnit.class.php');
require_once( dirname(__FILE__)
.DIRECTORY_SEPARATOR.'DaoShoppingPromotion.class.php');
require_once( dirname(__FILE__)
.DIRECTORY_SEPARATOR.'DaoShoppingOrderAddress.class.php');
/**
 * shopping_DaoShoppingOrder
 * shoppingパッケージ データアクセスオブジェクトクラス shopping_orderテーブル用
 */
class shopping_DaoShoppingOrder extends database2_AbstractData {
	// データベースカラムメンバ
	/** シリアル番号	*/
	var $order_number;
	/** 注文ID	*/
	var $order_id;
	/** 会員ID	*/
	var $member_id;
	/** 卸販売フラグ: 0=通常注文, 1=卸販売注文	*/
	var $buying_flag	= 0;
	/** 合計金額			*/
	var $price_total	= 0;
	/** プロモーション報酬	*/
	var $promotion_fee	= 0;
	/** 紹介割引金額		*/
	var $discount_price	= 0;
	/** 管理者割引（金額調整）	*/
	var $discount_admin	= 0;
	/** 購入合計金額	*/
	var $purchase_total	= 0;
	/** 支払い金額合計	*/
	var $payment_total	= 0;
	/** 仕入れ合計金額	*/
	var $cost_total		= 0;
	/** 配送料合計	*/
	var $delivery_price	= 0;
	/** 包装代	*/
	var $wrapping_price	= 0;
	/** 購入時の消費税割合設定	*/
	var $tax_rate		= 5;
	/** 付与ポイント合計	*/
	var $point_total	= 0;
	/** 利用ポイント	*/
	var $point_use		= 0;
	/** 注文通信欄	*/
	var $order_comment;
	/** 管理者メモ欄	*/
	var $admin_note;
	/** 履歴ノート	*/
	var $history_note;
	/** メール送信フラグ: 0=送信しない, 1=PCメール, 2=携帯メール, 11=新規会員PCメール, 12=新規会員携帯メール	*/
	var $mail_flag			= 1;
	/** 状態フラグ	*/
	var $status_flag		= 0;
	// 決済関連フィールド
	/** 決済フラグ */
	var $status_settle		= 0;
	/** 決済プラグイン番号	*/
	var $settle_method		= null;
	/** 決済金額	*/
	var $settle_price	= 0;
	/** 決済手数料	*/
	var $settle_fee			= 0;
	/** 決済用トランザクションコード	*/
	var $settle_transaction_code;
	/** 決済用システムログ	クレジット与信結果などのログを入れる	*/
	var $settle_log;
	// プロモーション関連フィールド
	/** プロモーション状態フラグ	*/
	var $status_promotion	= 0;
	/** プロモーションコード	*/
	var $promotion_code;
	/** プロモーションアクセスパラメータ	*/
	var $access_param;
	/** 注文日	*/
	var $order_date;
	/** 決済日	*/
	var $settle_date;
	/** 更新日	*/
	var $updated_date;
	/** 登録日	*/
	var $registered_date;
	/** 登録者ID	*/
	var $owner_id;
	/** 変更者ＩＤ	*/
	var $modifier_id;
	/** 関連検索データID	*/
	var $search_data_id;
	
	// 購入ログ情報
	/** ユーザーエージェント	*/
	var $user_agent;
	/** 携帯端末アクセスのID	*/
	var $sim_id;
	/** リモートホスト	*/
	var $remote_host;
	/** IPアドレス	*/
	var $remote_address;
	/** リンク元URL	*/
	var $referrer_url;
	/** 注文独自キー	*/
	var $order_key;

	// オブジェクト固有の拡張メンバ
	/** 個人情報オブジェクト	*/
	var $memberObject						= null;
	/** プロモーション情報オブジェクト	*/
	var $shoppingPromotionObject			= null;
	/** 宛先情報オブジェクト配列	*/
	var $shoppingOrderAddressObjectArray	= array();
	/** 注文オプションオブジェクト配列	*/
	var $shoppingOrderOptionObjectArray		= array();
	/** 表示用の販売単位オブジェクト連想配列	*/
	var $shoppingProductUnitObjectHash		= null;
	/** */
	var $searchDataObject	= null;
	/** 注文時のみの配送先の要不要	*/
	var $requireAddress		= true;
	/** データベースに保存しない表示内消費税額	*/
	var $tax_total			= 0;
	/** 計算済みフラグ	*/
	var $calculated			= false;
	
	/**
	 * コンストラクタ
	 */
	function shopping_DaoShoppingOrder(){
		$this->memberObject		= null;
		$this->shoppingOrderAddressObjectArray	= array();
		$this->shoppingOrderOptionObjectArray	= array();
		$this->shoppingProductUnitObjectHash	= null;
		$this->user_agent		= $_SERVER['HTTP_USER_AGENT'];
		$this->remote_host		= isset($_SERVER['REMOTE_HOST']) ? $_SERVER['REMOTE_HOST'] : '';
		$this->remote_address	= $_SERVER['REMOTE_ADDR'];
		$this->referrer_url		= '';
		$this->tax_rate			= 5;
		if( defined('SHOPPING_TAX_RATE') && preg_match('/^[0-9]{1,2}$/',SHOPPING_TAX_RATE) ) {
			$this->tax_rate		= SHOPPING_TAX_RATE;
		}
		$this->order_key		= date('YmdHis').util_CharUtility::get_rundom_key().util_CharUtility::get_rundom_key();
	}
	/**
	 * 関連情報の読み込みメソッド
	 */
	function loadRelation( $dbo ) {
		// 関連メンバーオブジェクトのロード
		$this->memberObject	= null;
		if( strlen(trim($this->member_id)) > 0 ) {
			$memberObject	= spider_Controller::createObject('member_DaoMember');
			if( $dbo->loadById( $memberObject, $this->member_id) ) {
				$this->setMemberObject( $memberObject );
			} else {
				$this->memberObject	= null;
			}
			// メール送信先アドレス
			if( strlen($memberObject->mb_mail) > 0
			&& ( $this->mail_flag == 2 || $this->mail_flag == 12 ) ) {
				$this->memberObject->email	= $memberObject->mb_mail;
				$this->email	= $memberObject->mb_mail;
			} else if( strlen($memberObject->pc_mail) == 0 ) {
				$this->memberObject->email	= $memberObject->mb_mail;
				$this->email	= $memberObject->mb_mail;
			} else {
				$this->memberObject->email	= $memberObject->pc_mail;
				$this->email	= $memberObject->pc_mail;
			}
		}
		// プロモーションIDがあるなら読み込み
		$promotionObject	= $this->getRelatedPromotionObject( $dbo->request );
		// 宛先情報の読み込み
		$shoppingOrderAddressObject	= spider_Controller::createObject('shopping_DaoShoppingOrderAddress');
		$sql	= 'SELECT * FROM '.TABLE_NAME_SHOPPING_ORDER_ADDRESS
			.' WHERE order_id='.$dbo->quote($this->order_id)
			.' ORDER BY address_order ASC';
		$this->shoppingOrderAddressObjectArray	= $dbo->queryAll( $sql,$shoppingOrderAddressObject,true, true );
		if ( false === $this->shoppingOrderAddressObjectArray ) {
			$this->shoppingOrderAddressObjectArray	= array();
		} else {
		}

		// 注文オプションの読み込み
		$optionHash	= $dbo->request->getAttribute('shopping.order.option.optionHash');
		if( is_null($optionHash) || !is_array($optionHash) ) {
			require_once(dirname(__FILE__).DIRECTORY_SEPARATOR.'order'.DIRECTORY_SEPARATOR.'option'.DIRECTORY_SEPARATOR.'LoadList.class.php');
			shopping_order_option_LoadList::execute( $dbo->request );
			$optionHash	= $dbo->request->getAttribute('shopping.order.option.optionHash');
		}
		$this->shoppingOrderOptionObjectArray	= $optionHash;
		$sql	= 'SELECT * FROM '.TABLE_NAME_SHOPPING_ORDER_OPTION
			.' WHERE order_id='.$dbo->quote($this->order_id)
			.' AND ( item_id IS NULL OR item_id=\'\' )'
			.' ORDER BY item_order ASC';
		$resultArray	= $dbo->queryAll( $sql,'hash',true );
		if ( false === $resultArray ) {
		} else {
			foreach( $resultArray as $row ) {
				$optionName	= $row['option_name'];
				$isExists	= false;
				foreach( $this->shoppingOrderOptionObjectArray as $optionNumber => $optionObject ) {
					$orderOptionObject	= & $this->shoppingOrderOptionObjectArray[$optionNumber];
					if( $orderOptionObject->optionName == $optionName ) {
						$isExists	= true;
						foreach( $row as $na => $val ) {
							$orderOptionObject->$na	= $val;
						}
						break;
					}
				}
				if( !$isExists ) {
					$className	= trim($row['option_class']);
					$shoppingOrderOptionObject	= null;
					if( strlen($className) > 0 && class_exists($className) ) {
						$shoppingOrderOptionObject	= spider_Controller::createObject($className);
					} else {
						$shoppingOrderOptionObject	= spider_Controller::createObject('shopping_DaoShoppingOrderOption');
					}
					foreach( $row as $na => $val ) {
						$shoppingOrderOptionObject->$na	= $val;
					}
					$shoppingOrderOptionObject->optionName	= $shoppingOrderOptionObject->option_name;
					array_push($this->shoppingOrderOptionObjectArray,$shoppingOrderOptionObject);
				}
			}
		}
		// 計算
		$this->calculate( $dbo->request );
		// 検索連携
		if( strlen($this->search_data_id) > 0 ) {
			$searchDataObject = spider_Controller::createObject('search_DaoSearchData');
			if( $dbo->loadById( $searchDataObject, $this->search_data_id) ) {
				$this->searchDataObject	= $searchDataObject;
			} else {
				$this->searchDataObject	= null;
			}
		}
	}
	/**
	 * 関連メンバーを設定
	 */
	function setMemberObject( & $memberObject ) {
		if( is_a($memberObject,'member_DaoMember') ) {
			$this->member_id	= $memberObject->member_id;
			$this->memberObject	= & $memberObject;
			$this->optimize();
			return true;
		} else {
			$this->member_id	= null;
			$this->memberObject	= null;
			return false;
		}
	}
	/**
	 * メールアドレスを設定
	 */
	function setEmail( $email ) {
		$this->email				= $email;
		$this->memberObject->email	= $email;
		$isMobile		= false;
		foreach( $GLOBALS['MEMBER_MOBILE_MAIL_DOMAIN_ARRAY'] as $domain ) {
			$regDomain	= util_CharUtility::escape_regx_str('@'.$domain);
			if( preg_match('/'.$regDomain.'$/',$email) > 0 ) {
				$isMobile		= true;
				break;
			}
		}
		if( $isMobile ) {
			$this->memberObject->mb_mail	= $email;
		} else {
			$this->memberObject->pc_mail	= $email;
		}
	}
	/**
	 * インサート前に行いたい処理
	 * @param MDBObject $dbo MDB2オブジェクトかその互換オブジェクト
	 * @return boolean 成功したらtrue
	 */
	function pre_insert( $dbo ) {
		return true;
	}
	/**
	 * インサート後に行いたい処理
	 * @param MDBObject $dbo MDB2オブジェクトかその互換オブジェクト
	 * @return boolean 成功したらtrue
	 */
	function post_insert( $dbo ) {
		$this->dbo	= $dbo;
		return $this->updateOrderTable( $dbo->request );
	}
	/**
	 * アップデート前に行いたい処理
	 * @param MDBObject $dbo MDB2オブジェクトかその互換オブジェクト
	 * @return boolean 成功したらtrue
	 */
	function pre_update( $dbo ) {
		// 履歴ノートは更新されていても更新しない(同時操作対策の為にデータ更新時に更新はおこないわない)
		// のでアップデート前に最新状態をＤＢから取得する
		$sql	= 'SELECT history_note FORM '.$this->getTableName().' WHERE order_number='.$this->order_number;
		$historyNote	= $dbo->queryOne($sql);
		if(false===$historyNote){
			return false;
		}else{
			$this->history_note	= $historyNote;
		}
		return true;
	}
	/**
	 * アップデート後に行いたい処理
	 * @param MDBObject $dbo MDB2オブジェクトかその互換オブジェクト
	 * @return boolean 成功したらtrue
	 */
	function post_update( $dbo ) {
		if( is_object($dbo->request) && $dbo->request->isError() ) {
			return false;
		} else {
			return true;
		}
	}
	/**
	 * 注文情報の従属テーブルを現在の状態に更新
	 * @param $request 
	 * @return boolean
	 */
	function updateOrderTable( & $request ) {
		if( !is_object($request) ) {
			$request->addLocaledError('system.error.common.invalidusage',SPIDER_LOG_LEVEL_FATAL,array(''));
			return false;
		}
		$dbo	= $request->getAttribute( 'dbo' );
		if( $this->dbo ) {
			$dbo	= $this->dbo;
		}
		if( $dbo ) {
			// 紐づいた注文情報を全て一度削除
			$sql	= 'DELETE FROM '.TABLE_NAME_SHOPPING_ORDER_ADDRESS
			.' WHERE order_id='.$dbo->quote($this->order_id);
			if( $dbo->query( $sql ) === false ) {
				$request->addLocaledError('database2.error.delete',SPIDER_LOG_LEVEL_FATAL,array($sql));
				return false;
			}
			$sql	= 'DELETE FROM '.TABLE_NAME_SHOPPING_ORDER_ITEM
			.' WHERE order_id='.$dbo->quote($this->order_id);
			if( $dbo->query( $sql ) === false ) {
				$request->addLocaledError('database2.error.delete',SPIDER_LOG_LEVEL_FATAL,array($sql));
				return false;
			}
			$sql	= 'DELETE FROM '.TABLE_NAME_SHOPPING_ORDER_OPTION
			.' WHERE order_id='.$dbo->quote($this->order_id);
			if( $dbo->query( $sql ) === false ) {
				$request->addLocaledError('database2.error.delete',SPIDER_LOG_LEVEL_FATAL,array($sql));
				return false;
			}
			// 宛先と紐づいた注文商品情報をインサート
			if( is_array($this->shoppingOrderAddressObjectArray) ) {
				foreach( $this->shoppingOrderAddressObjectArray as $addressOrder => $shoppingOrderAddressObject ) {
					// 商品選択があるならインサート
					if( count($shoppingOrderAddressObject->shoppingOrderItemObjectArray) > 0 ) {
						$this->shoppingOrderAddressObjectArray[$addressOrder]->order_id			= $this->order_id;
						$this->shoppingOrderAddressObjectArray[$addressOrder]->address_order	= $addressOrder;
						if( $dbo->setNextId( $this->shoppingOrderAddressObjectArray[$addressOrder], $this->order_id.'{num:4}' ) ) {
							if($dbo->insert( $this->shoppingOrderAddressObjectArray[$addressOrder] )) {
							} else if( is_object($request) ) {
								$request->addLocaledError('database2.error.insert',SPIDER_LOG_LEVEL_FATAL,array($GLOBALS['SHOPPING_LABEL_ADDRESS_NAME'].$addressOrder.$sql));
								return false;
							}
						} else if( is_object($request) ) {
							$request->addLocaledError('database2.error.setnextid',SPIDER_LOG_LEVEL_FATAL,array($GLOBALS['SHOPPING_LABEL_ADDRESS_NAME'].$addressOrder.$sql));
							return false;
						}
					}
				}
			}
			// 直接紐づいた注文オプション情報をインサート
			if( is_array($this->shoppingOrderOptionObjectArray) ) {
				foreach( $this->shoppingOrderOptionObjectArray as $optionNum => $shoppingOrderOptionObject ) {
					$this->shoppingOrderOptionObjectArray[$optionNum]->order_id		= $this->order_id;
					$this->shoppingOrderOptionObjectArray[$optionNum]->item_order	= $optionNum;
					if($dbo->insert( $this->shoppingOrderOptionObjectArray[$optionNum] )) {
					} else if( is_object($request) ) {
						$request->addLocaledError('database2.error.insert',SPIDER_LOG_LEVEL_FATAL,array($GLOBALS['SHOPPING_LABEL_ADDRESS_NAME'].$addressOrder.$sql));
						return false;
					}
				}
			}
			if( $request->isError() ) {
				return false;
			} else {
				return true;
			}
		} else {
			$request->addLocaledError('database2.error.noconnect',SPIDER_LOG_LEVEL_FATAL,array(''));
			return false;
		}
	}
	//
	// カート操作
	//
	/**
	 * カートの注文商品を全て削除
	 */
	function clearAll() {
		$this->shoppingProductUnitObjectHash	= null;
		if( is_array($this->shoppingOrderAddressObjectArray) ){
			foreach($this->shoppingOrderAddressObjectArray as $key => $addressObject){
				$this->shoppingOrderAddressObjectArray[$key]->shoppingOrderItemObjectArray	= array();
			}
		}
		$this->calculated	= false;
	}
	/**
	 * 指定宛先を削除
	 * @param $addressOrder 宛先番号
	 */
	function clear( $addressOrder=0 ) {
		if( isset($this->shoppingOrderAddressObjectArray[$addressOrder]) ) {
			$this->shoppingProductUnitObjectHash	= null;
			unset($this->shoppingOrderAddressObjectArray[$addressOrder]);
		}
		$this->calculated	= false;
	}
	/**
	 * 宛先を追加可能か確認
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function canAddAddress( & $request ) {
		$deliveryTypeArray	= $this->getDeliveryTypeArray( $request );
		foreach( $deliveryTypeArray as $deliveryType ) {
			if( $deliveryType >= 10 ) {
				return false;
			}
		}
		return true;
	}
	/**
	 * 宛先を追加
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function addAddress( & $request ) {
		$deliveryTypeArray	= $this->getDeliveryTypeArray( $request );
		foreach( $deliveryTypeArray as $deliveryType ) {
			if( $deliveryType >= 10 ) {
				$request->addLocaledError('shopping.error.cart.enableaddaddress',SPIDER_LOG_LEVEL_FATAL,array(''));
				return;
			}
		}
		$orderAddressObject = spider_Controller::createObject('shopping_DaoShoppingOrderAddress');
		if( !isset($this->shoppingOrderAddressObjectArray)
		|| !is_array($this->shoppingOrderAddressObjectArray) ) {
			$this->shoppingOrderAddressObjectArray	= array();
		}
		array_push($this->shoppingOrderAddressObjectArray,$orderAddressObject);
		$this->calculated	= false;
	}
	/**
	 * 宛先を削除
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @param $addressOrder 宛先番号
	 */
	function dropAddress( & $request, $addressOrder ) {
		if( !isset($this->shoppingOrderAddressObjectArray)
		|| !is_array($this->shoppingOrderAddressObjectArray) ) {
			$this->shoppingOrderAddressObjectArray	= array();
		}
		if( isset($this->shoppingOrderAddressObjectArray[$addressOrder]) ) {
			unset($this->shoppingOrderAddressObjectArray[$addressOrder]);
		}
		$counter	= 0;
		$newArray	= array();
		foreach($this->shoppingOrderAddressObjectArray as $addresOrder => $addressObject ) {
			$addressObject->address_order	= $counter;
			array_push($newArray,$addressObject);
		}
		$this->shoppingOrderAddressObjectArray	= $newArray;
		$this->calculated	= false;
	}
	/**
	 * 宛先番号を指定してカートにアイテムを追加
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @param $shoppingOrderItemObject shopping_DaoShoppingOrderItemオブジェクト
	 * @param $addressOrder 宛先番号
	 */
	function addItem( & $request, $shoppingOrderItemObject, $addressOrder=0 ) {
		if( 0 != $addressOrder && $shoppingOrderItemObject->shoppingProductUnitObject->delivery_type >= 10 ) {
			$request->addLocaledError('shopping.error.cart.enableaddressproduct',SPIDER_LOG_LEVEL_FATAL,array(''));
			return;
		}
		if( !isset($this->shoppingOrderAddressObjectArray)
		|| !is_array($this->shoppingOrderAddressObjectArray) ) {
			$this->shoppingOrderAddressObjectArray	= array();
		}
		if( !isset($this->shoppingOrderAddressObjectArray[$addressOrder])
		|| !is_object($this->shoppingOrderAddressObjectArray[$addressOrder]) ) {
			$this->shoppingOrderAddressObjectArray[$addressOrder]	= spider_Controller::createObject('shopping_DaoShoppingOrderAddress');
		}
		$this->shoppingOrderAddressObjectArray[$addressOrder]->addItem( $request, $shoppingOrderItemObject, $GLOBALS['SHOPPING_LABEL_ADDRESS_NAME'].($addressOrder+1).'：' );
		$this->calculated	= false;
	}
	/**
	 * 宛先番号とカート内順序を指定してアイテムをカートから削除
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @param $cartOrder カート内商品順序
	 * @param $addressOrder 宛先順序 指定しない場合は0
	 */
	function dropItem( & $request, $cartOrder, $addressOrder=0 ){
		if( is_array($this->shoppingOrderAddressObjectArray)
		&& isset($this->shoppingOrderAddressObjectArray[$addressOrder])
		&& is_object($this->shoppingOrderAddressObjectArray[$addressOrder]) ) {
			$this->shoppingOrderAddressObjectArray[$addressOrder]->dropItem( $request, $cartOrder );
		}
		$this->calculated	= false;
	}
	/**
	 * 宛先番号とカート内順序を指定して現在の注文数を取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @param $cartOrder カート内商品順序
	 * @param $addressOrder 宛先順序 指定しない場合は0
	 */
	function getItemObject( & $request, $cartOrder, $addressOrder=0 ){
		if( is_array($this->shoppingOrderAddressObjectArray)
		&& isset($this->shoppingOrderAddressObjectArray[$addressOrder])
		&& is_object($this->shoppingOrderAddressObjectArray[$addressOrder]) ) {
			$orderAddressObject	= & $this->shoppingOrderAddressObjectArray[$addressOrder];
			if( isset($orderAddressObject->shoppingOrderItemObjectArray[$cartOrder])
			&& is_object($orderAddressObject->shoppingOrderItemObjectArray[$cartOrder]) ) {
				$orderItemObject	= & $orderAddressObject->shoppingOrderItemObjectArray[$cartOrder];
				return $orderItemObject;
			}
		}
		return false;
	}
	/**
	 * 宛先番号とカート内順序を指定して現在の注文数を取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @param $cartOrder カート内商品順序
	 * @param $addressOrder 宛先順序 指定しない場合は0
	 */
	function getItemCount( & $request, $cartOrder, $addressOrder=0 ){
		$orderItemObject	= $this->getItemObject( $request, $cartOrder, $addressOrder );
		if( false === $orderItemObject ) {
			return 0;
		} else {
			return $orderItemObject->order_count;
		}
	}
	/**
	 * 宛先番号とカート内順序を指定してアイテムの注文数を変更
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @param $cartOrder カート内商品順序
	 * @param $orderCount 変更後の注文数
	 * @param $addressOrder 宛先順序 指定しない場合は0
	 */
	function changeItemCount( & $request, $cartOrder, $orderCount, $addressOrder=0, $loginUserObject ){
		if( $orderCount <= 0 ) {
			$this->dropItem( $request, $cartOrder, $addressOrder );
		} else {
			$orderItemObject	= $this->getItemObject( $request, $cartOrder, $addressOrder );
			if( false === $orderItemObject ) {
				$request->addLocaledError('shopping.error.cart.itemnotfount',SPIDER_LOG_LEVEL_FATAL,array(''));
			} else if( $orderCount == $orderItemObject->order_count ) {
				// 注文数に変更がない場合は何もしない
			} else if( $orderCount < $orderItemObject->order_count ) {
				// 数が減った場合はそのまま減らす
				$orderItemObject->order_count	= $orderCount;
			} else {
				// 数を増やす場合は追加してから在庫チェック
				$shoppingOrderItemObject	= spider_Controller::createObject('shopping_DaoShoppingOrderItem');
				$shoppingOrderItemObject->unit_id		= $orderItemObject->unit_id;
				$shoppingOrderItemObject->order_count	= $orderCount - $orderItemObject->order_count;
				$orgCount	= $orderItemObject->order_count;
				$orderItemObject->order_count	= $orderCount;
				if( $this->canExecuteOrder( $request ) ){
				} else {
					// 在庫確認に失敗したら元に戻す
					$orderItemObject->order_count	= $orgCount;
				}
			}
		}
		$this->calculated	= false;
	}
	/**
	 * 指定の宛先に都道府県のみ設定
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @param $shoppingOrderItemObject shopping_DaoShoppingOrderItemオブジェクト
	 * @param $addressOrder 宛先番号
	 */
	function setPrefecture( & $request, $prefectureNumber, $addressOrder=0 ) {
		if( !isset($this->shoppingOrderAddressObjectArray)
		|| !is_array($this->shoppingOrderAddressObjectArray) ) {
			$this->shoppingOrderAddressObjectArray	= array();
		}
		if( !isset($this->shoppingOrderAddressObjectArray[$addressOrder])
		|| !is_object($this->shoppingOrderAddressObjectArray[$addressOrder]) ) {
			$this->shoppingOrderAddressObjectArray[$addressOrder]	= spider_Controller::createObject('shopping_DaoShoppingOrderAddress');
		}
		$this->shoppingOrderAddressObjectArray[$addressOrder]->prefecture_number = $prefectureNumber;
	}
	/**
	 * 表示および計算の為全ての商品販売単位オブジェクトをセットします
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function setAllUnitObject( & $request ) {
		if( is_array($this->shoppingOrderAddressObjectArray) ) {
			$this->shoppingProductUnitObjectHash	= array();
			foreach( $this->shoppingOrderAddressObjectArray as $addressNum => $shoppingOrderAddressObject ) {
				$this->shoppingOrderAddressObjectArray[$addressNum]->setAllUnitObject($request,$this->shoppingProductUnitObjectHash);
			}
		}
	}
	/**
	 * セッション格納の為に全ての商品販売単位オブジェクトをアンセットします
	 */
	function unsetAllUnitObject() {
		if( is_array($this->shoppingOrderAddressObjectArray) ) {
			foreach( $this->shoppingOrderAddressObjectArray as $addressNum => $shoppingOrderAddressObject ) {
				$this->shoppingOrderAddressObjectArray[$addressNum]->unsetAllUnitObject();
			}
		}
		$this->shoppingProductUnitObjectHash	= null;
	}
	/**
	 * 現在のカート内の注文商品数を取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function getAllItemCount( & $request ) {
		$itemCount	= 0;
		if( is_array($this->shoppingOrderAddressObjectArray) ) {
			foreach( $this->shoppingOrderAddressObjectArray as $addressNum => $shoppingOrderAddressObject ) {
				if( is_array($shoppingOrderAddressObject->shoppingOrderItemObjectArray) ) {
					foreach($shoppingOrderAddressObject->shoppingOrderItemObjectArray as $itemNum => $shoppingOrderItemObject ) {
						$itemCount	+= $shoppingOrderItemObject->order_count;
					}
				}
			}
		}
		return $itemCount;
	}
	/**
	 * この注文における指定販売単位IDの注文数を取得
	 * @param $unitId 販売単位ID
	 */
	function getUnitOrderCount( $unitId ) {
		$unitOrderCount	= 0;
		if( is_array($this->shoppingOrderAddressObjectArray) ) {
			foreach( $this->shoppingOrderAddressObjectArray as $addressNum => $shoppingOrderAddressObject ) {
				$unitOrderCount	+= $shoppingOrderAddressObject->getUnitOrderCount( $unitId );
			}
		}
		return $unitOrderCount;
	}
	/**
	 * この注文オブジェクトに含まれる配送種別を配列で取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function getDeliveryTypeArray( & $request ) {
		$deliveryTypeArray	= array();
		if( is_null($this->shoppingProductUnitObjectHash) ) {
			$this->setAllUnitObject( $request );
		}
		if( is_array($this->shoppingOrderAddressObjectArray) ) {
			foreach( $this->shoppingOrderAddressObjectArray as $addressNum => $shoppingOrderAddressObject ) {
				$typeArray	= $this->shoppingOrderAddressObjectArray[$addressNum]->getDeliveryTypeArray( $request );
				$deliveryTypeArray	= array_merge( $deliveryTypeArray, $typeArray );
				$deliveryTypeArray	= array_unique($deliveryTypeArray);
			}
		}
		return $deliveryTypeArray;
	}
	/**
	 * 現在の注文販売単位数が現在の在庫内に収まっていて注文可能か確認します
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @param $unitObject shopping_DaoShoppingOrderItemインスタンスかnull。渡した場合は追加して注文可能か確認します
	 * @return boolean 注文可能ならtrue
	 */
	function canExecuteOrder( & $request ) {
		$dbo		= $request->getAttribute( 'dbo' );
		if( is_null($this->shoppingProductUnitObjectHash) ) {
			$this->setAllUnitObject( $request );
		}
		$unitTermCountHash	= array();
		$innerDeliveryTypeArray	= array();
		$hasDelTypeNomal		= false;
		$hasDelTypeContinue	= false;
		$hasDelTypeReserve	= false;
		$optionTermHash			= array();
		$reserveTermHash		= array();
		if( is_array($this->shoppingOrderAddressObjectArray) ) {
			foreach( $this->shoppingOrderAddressObjectArray as $addressNum => $shoppingOrderAddressObject ) {
				foreach( $shoppingOrderAddressObject->shoppingOrderItemObjectArray as $itemNum => $shoppingOrderItemObject) {
					// ＩＤと期間に対する申込数のハッシュに追加
					$keyString	= $shoppingOrderItemObject->unit_id
					.'<>'.$shoppingOrderItemObject->svc_start_date
					.'<>'.$shoppingOrderItemObject->svc_limit_date;
					$tUnitObject	= $this->shoppingProductUnitObjectHash[$shoppingOrderItemObject->unit_id];
					// 対象配送種別
					$targetDeliveryType	= $tUnitObject->delivery_type;
					if( isset($unitTermCountHash[$keyString]) && preg_match('/^[0-9]{1,2}$/',$unitTermCountHash[$keyString])>0 ){
						$unitTermCountHash[$keyString]	+= $shoppingOrderItemObject->order_count;
					} else {
						$unitTermCountHash[$keyString]	= $shoppingOrderItemObject->order_count;
					}
					// 配送タイプ
					if( !in_array($targetDeliveryType,$innerDeliveryTypeArray)
						&& strlen($targetDeliveryType) > 0 ){
						array_push($innerDeliveryTypeArray, $targetDeliveryType);
					}
					if( 100 >= $targetDeliveryType ){
						$hasNomalDelType		= true;
					} else if( 900 == $targetDeliveryType ){
						$hasDelTypeReserve	= true;
						array_push( $reserveTermHash,
						array('start'=>strtotime($shoppingOrderItemObject->svc_start_date)
						,'limit'=>strtotime($shoppingOrderItemObject->svc_limit_date)) );
					} else if( 1700 == $targetDeliveryType ){
						$hasDelTypeReserve	= true;
						array_push( $optionTermHash,
						array('start'=>strtotime($shoppingOrderItemObject->svc_start_date)
						,'limit'=>strtotime($shoppingOrderItemObject->svc_limit_date)) );
					} else if( 200 == $targetDeliveryType ){
						$hasDelTypeReserve	= true;
						array_push( $reserveTermHash,
						array('start'=>strtotime($shoppingOrderItemObject->svc_start_date)
						,'limit'=>strtotime($shoppingOrderItemObject->svc_limit_date)) );
					} else if( 1000 == $targetDeliveryType ){
						$hasDelTypeReserve	= true;
						array_push( $optionTermHash,
						array('start'=>strtotime($shoppingOrderItemObject->svc_start_date)
						,'limit'=>strtotime($shoppingOrderItemObject->svc_limit_date)) );
					} else {
						$hasDelTypeContinue	= true;
					}
				}
			}
		}
		// 配送種別の混在チェック
		if( $hasNomalDelType && $hasDelTypeContinue ){
			$request->addLocaledError('shopping.error.cart.enable.productandservice',SPIDER_LOG_LEVEL_ERROR,array(''));
			return false;
		} else if( $hasNomalDelType && $hasDelTypeReserve ){
			$request->addLocaledError('shopping.error.cart.enable.productandreserve',SPIDER_LOG_LEVEL_ERROR,array(''));
			return false;
		} else if( $hasDelTypeContinue && $hasDelTypeReserve ){
			$request->addLocaledError('shopping.error.cart.enable.serviceandreserve',SPIDER_LOG_LEVEL_ERROR,array(''));
			return false;
		} else if( in_array(900,$innerDeliveryTypeArray) && in_array(200,$innerDeliveryTypeArray) ){
			$request->addLocaledError('shopping.error.cart.enable.reserve',SPIDER_LOG_LEVEL_ERROR,array(''));
			return false;
		} else if( in_array(1700,$innerDeliveryTypeArray) && !in_array(900,$innerDeliveryTypeArray) ){
			$request->addLocaledError('shopping.error.cart.option.requirersv',SPIDER_LOG_LEVEL_ERROR,array(''));
			return false;
		} else if( in_array(1000,$innerDeliveryTypeArray) && !in_array(200,$innerDeliveryTypeArray) ){
			$request->addLocaledError('shopping.error.cart.option.requirersv',SPIDER_LOG_LEVEL_ERROR,array(''));
			return false;
		} else if( in_array(1700,$innerDeliveryTypeArray) || in_array(1000,$innerDeliveryTypeArray) ){
			// 予約オプションがある場合は期間の整合性チェック
			foreach( $optionTermHash as $tHash ){
				$inTime	= false;
				foreach( $reserveTermHash as $rHash ){
					if( $tHash['start'] >= $rHash['start'] && $tHash['limit'] <= $rHash['limit'] ){
						// 期間内ならOK
						$inTime	= true;
						break;
					}
				}
				if( !$inTime ){
					$request->addLocaledError('shopping.error.cart.option.requiredate',SPIDER_LOG_LEVEL_ERROR,array(''));
					return false;
				}
			}
		}
		// 在庫数のチェック
		foreach( $unitTermCountHash as $keyString => $ordCount ){
			list($tUnitId,$stime,$ltime)	= explode('<>',$keyString);
			$tUnitObject	= $this->shoppingProductUnitObjectHash[$tUnitId];
			$tStock = $tUnitObject->getStock( $request, $stime, $ltime, null, $this->order_id );
			if( $tStock < $ordCount ){
				$tProductObject	= $tUnitObject->getProductObject($request);
				$viewUnitName	= $tProductObject->product_name.' '.$tUnitObject->unit_name;
				if( $tProductObject->product_name == $tUnitObject->unit_name ){
					$viewUnitName	= $tUnitObject->unit_name;
				}
				$request->addLocaledError('shopping.error.cart.overstock',SPIDER_LOG_LEVEL_ERROR,array(''));
				return false;
			}
		}
		return true;
	}
	/**
	 * 現在の注文情報でデータベース上の在庫を消化
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function useUnitStock( & $request ) {
		if( is_array($this->shoppingOrderAddressObjectArray) ) {
			foreach( $this->shoppingOrderAddressObjectArray as $addressOrder => $shoppingOrderAddressObject ) {
				$this->shoppingOrderAddressObjectArray[$addressOrder]->useUnitStock( $request );
			}
		}
	}
	//
	// 金額計算関連のメソッド
	//
	/**
	 * 現在の注文情報に基づいて金額を再計算
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function calculate( & $request, $renew=false ) {
		// 計算済みなら計算しない
		if( $this->calculated ){
			return;
		}
		// 注文商品販売単位オブジェクトを再取得
		if( is_null($this->shoppingProductUnitObjectHash) ) {
			$this->setAllUnitObject( $request );
		}
		if( !$renew ) {
			// 内消費税計算
			$this->tax_total		= $this->_calculateTax( $request );
			return;
		}
		$this->tax_total		= 0;	// 内消費税はデータベースに保存していない
		// 注文金額関連
		$this->price_total		= 0;	// 商品合計金額
		$this->cost_total		= 0;	// 仕入合計金額
		$this->delivery_price	= 0;	// 配送料合計金額
		$this->settle_fee		= 0;	// 決済手数料
		$this->wrapping_price	= 0;	// 包装料金
		// 割引関連
		$this->discount_price	= 0;	// 割引合計金額
		if( $this->point_use < 0 ) {	// 利用ポイント
			$this->point_use	= 0;
		}
		$this->purchase_total	= 0;	// 購入合計金額
		$this->payment_total	= 0;	// 実際の支払合計金額
		$this->promotion_fee	= 0;	// プロモーション報酬合計金額
		$this->point_total		= 0;	// ポイント合計
		// 注文商品と注文オプションの合計金額を算出
		if( is_array($this->shoppingOrderAddressObjectArray) ) {
			foreach( $this->shoppingOrderAddressObjectArray as $addressOrder => $shoppingOrderAddressObject ) {
				$this->shoppingOrderAddressObjectArray[$addressOrder]->calculate( $request, $renew );
				// 商品金額＋注文オプション金額合計とコスト計算
				$this->price_total		+= $this->shoppingOrderAddressObjectArray[$addressOrder]->getTotalPaymentPrice( $request );
				$this->cost_total		+= $this->shoppingOrderAddressObjectArray[$addressOrder]->getTotalCost( $request );
				$this->point_total		+= $this->shoppingOrderAddressObjectArray[$addressOrder]->getTotalPresentPoint( $request );
				$this->wrapping_price	+= $this->shoppingOrderAddressObjectArray[$addressOrder]->wrapping_price;
			}
		}
		// 直接注文に紐づいている注文オプションの計算
		if( is_array($this->shoppingOrderOptionObjectArray) ) {
			foreach( $this->shoppingOrderOptionObjectArray as $num => $orderOptionObject ) {
				$this->shoppingOrderOptionObjectArray[$num]->calculate( $request, $renew );
				$this->price_total	+= $this->shoppingOrderOptionObjectArray[$num]->getTotalPrice( $request );
				$this->cost_total	+= $this->shoppingOrderOptionObjectArray[$num]->getTotalCost( $request );
			}
		}
		// 配送料金の計算
		$this->_calculateDeliveryPrice( $request, $renew );
		
		// ポイント付与と割引の処理
		if( is_object($this->memberObject) && $this->memberObject->member_class_org > 0 ) {
			// 元々会員の場合の購入
			$this->discount_id		= '';
			$this->promotion_fee	= 0;
			$this->discount_price	= 0;
			if( $this->buying_flag == 1 ) {
				// 卸購入の場合は一番割引率の高いプロモーション卸割引を適用
				$sql	= 'SELECT * FROM '.TABLE_NAME_SHOPPING_PROMOTION
				.' WHERE buying_flag>0 AND member_id='.$dbo->quote($this->memberObject->member_id)
				.' ORDER BY buying_rate DESC';
				$obj	= spider_Controller::createObject('shopping_DaoShoppingPromotion');
				$result	= $dbo->queryAll( $sql,$obj,true,true );
				if ( false === $result ) {
					$request->addLocaledError('database2.error.common',SPIDER_LOG_LEVEL_FATAL,array($sql));
				} else if( count($result) == 0 ) {
					$request->addLocaledError('shopping.error.cart.enablebuyinguser',SPIDER_LOG_LEVEL_FATAL,array(''));
				} else {
					$promotionObject	= $result[0];
					$discountRate		= $promotionObject->buying_rate;
					if( is_array($this->shoppingOrderAddressObjectArray) ) {
						foreach( $this->shoppingOrderAddressObjectArray as $addressOrder => $shoppingOrderAddressObject ) {
							// 割引は商品に対してのみ百分率で切り捨て計算（注文オプションは割引対象外）
							$this->discount_price
								+= $this->shoppingOrderAddressObjectArray[$addressOrder]->calculatePriceRate(
								$request, $discountRate, false, false, false, false );
						}
					}
				}
			}
		} else {
			// 元々会員でない場合の購入
			// プロモーションIDがあるなら読み込み
			$promotionObject	= $this->getRelatedPromotionObject( $request );
			// ポイント利用不可
			$this->point_use		= 0;
			if( is_object($this->memberObject) && $this->memberObject->member_class > 0 ) {
				// 会員になる場合
			} else {
				// 会員にならない場合はポイントはつかない
				$this->point_total	= 0;
			}
			// プロモーション計算
			$this->promotion_fee	= 0;
			$this->discount_price	= 0;
			if( is_object($promotionObject) ) {
				// 割引の計算
				if( preg_match('/^[mM][oO][nN][eE][yY]$/', $promotionObject->discount_type) > 0 ) {
					// 定額割引
					$promotionFixedDiscountBottom	= 10000;
					if( defined('SHOPPING_PROMO_FIXED_DISCOUNT_BTM')
					&& preg_match('/^[0-9]{1,7}$/',SHOPPING_PROMO_FIXED_DISCOUNT_BTM) > 0 ) {
						$promotionFixedDiscountBottom	= SHOPPING_PROMO_FIXED_DISCOUNT_BTM;
					}
					if( $this->price_total >= $promotionFixedDiscountBottom ) {
						$this->discount_price	= $promotionObject->discount_value;
					}
				} else if( preg_match('/^[rR][aA][tT][eE]$/', $promotionObject->discount_type) > 0 ) {
					// 定率割引
					if( is_array($this->shoppingOrderAddressObjectArray) ) {
						foreach( $this->shoppingOrderAddressObjectArray as $addressOrder => $shoppingOrderAddressObject ) {
							// 割引は商品に対してのみ百分率で切り捨て計算（注文オプションは割引対象外）
							$this->discount_price
								+= $this->shoppingOrderAddressObjectArray[$addressOrder]->calculatePriceRate(
								$request, $promotionObject->discount_value, false, false, false, false );
						}
					}
				}
				// 報酬の計算
				if( preg_match('/^[mM][oO][nN][eE][yY]$/', $promotionObject->pay_type) > 0 ) {
					// 定額報酬
					$promotionFixedFeeBottom		= 10000;
					if( defined('SHOPPING_PROMO_FIXED_FEE_BTM')
					&& preg_match('/^[0-9]{1,7}$/',SHOPPING_PROMO_FIXED_FEE_BTM) > 0 ) {
						$promotionFixedFeeBottom	= SHOPPING_PROMO_FIXED_FEE_BTM;
					}
					if( $this->price_total >= $promotionFixedFeeBottom ) {
						$this->promotion_fee	= $promotionObject->pay_value;
					}
				} else if( preg_match('/^[rR][aA][tT][eE]$/', $promotionObject->pay_type) > 0 ) {
					// 定率報酬
					if( is_array($this->shoppingOrderAddressObjectArray) ) {
						foreach( $this->shoppingOrderAddressObjectArray as $addressOrder => $shoppingOrderAddressObject ) {
							// 割引は商品に対してのみ百分率で切り捨て計算（注文オプションは割引対象外）
							$this->promotion_fee
								+= $this->shoppingOrderAddressObjectArray[$addressOrder]->calculatePriceRate(
								$request, $promotionObject->pay_value, false, false, false, false );
						}
					}
				}
			}
		}
		// 決済手数料の計算
		$settleMethodObject	= $this->getSettleMethodObject( $request );
		if( is_a($settleMethodObject,'shopping_order_settlement_MethodBase') ) {
			$settleMethodObject->setSettleFee( $request, $this );
		} else {
			$this->settle_fee	= 0;
		}
		// 購入合計金額の計算
		$this->purchase_total	= $this->price_total + $this->wrapping_price + $this->delivery_price + $this->settle_fee - $this->discount_price;
		
		// 利用ポイント調整
		$pointSettleRate	= 100;
		if( defined('SHOPPING_POINT_SETTLE_RATE') && strlen(SHOPPING_POINT_SETTLE_RATE) > 0 ) {
			$pointSettleRate	= SHOPPING_POINT_SETTLE_RATE;
		}
		// ポイント清算規則
		if( defined('SHOPPING_POINT_SETTLE_METHOD') && '2' == SHOPPING_POINT_SETTLE_METHOD ) {
			// 支払総額に対するパーセンテージの場合
			if( $this->point_use > floor($this->purchase_total*$pointSettleRate/100) ) {
				$this->point_use	= floor($this->purchase_total*$pointSettleRate/100);
			}
		} else {
			// 商品総額に対するパーセンテージの場合
			if( $this->point_use > floor($this->price_total*$pointSettleRate/100) ) {
				$this->point_use	= floor($this->price_total*$pointSettleRate/100);
			}
		}
		// ポイント付与設定で利用ポイント分は差し引くなら差し引き計算
		if( defined('SHOPPING_POINT_METHOD') && SHOPPING_POINT_METHOD != 0 && $this->point_use > 0 ) {
			$this->point_total	-= $this->point_use;
			if( $this->point_total < 0 ) {
				$this->point_total	= 0;
			}
		}
		// お支払金額の計算
		$this->payment_total	= $this->purchase_total - $this->point_use + $this->discount_admin;
		// 内消費税計算
		$this->tax_total		= $this->_calculateTax( $request );

		$this->calculated	= true;
		return;
	}
	/**
	 * 現在のカートの送料目安値合計から送料を再計算します
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @param $deliveryNomalWeightTotal 1.2から不要になりました
	 * @param $deliveryCoolWeightTotal 1.2から不要になりました
	 */
	function _calculateDeliveryPrice( & $request, $renew=false, $deliveryNomalWeightTotal=null, $deliveryCoolWeightTotal=null ) {
		$this->delivery_price	= 0;
		if( is_array($this->shoppingOrderAddressObjectArray) ) {
			$nomalWeightArray	= array();
			$coolWeightArray	= array();
			foreach( $this->shoppingOrderAddressObjectArray as $addressOrder => $shoppingOrderAddressObject ) {
				$this->delivery_price
					+= $this->shoppingOrderAddressObjectArray[$addressOrder]->calculateDeliveryPrice(
						$request, $renew, $nomalWeightArray, $coolWeightArray );
			}
		}
	}
	/**
	 * 内消費税を計算して取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @return int 設定ルールで計算された消費税額
	 */
	function _calculateTax( & $request ) {
		if( '1' == shopping_PackageConfig::_getTaxCalculateType() ) {
			// 各商品ごとの消費税合算の場合
			$tax	= 0;
			// 宛先ごとに消費税を取得
			if( is_array($this->shoppingOrderAddressObjectArray) ) {
				foreach( $this->shoppingOrderAddressObjectArray as $addressOrder => $shoppingOrderAddressObject ) {
					// 内消費税は商品に対してのみ百分率で計算（商品・オプション・包装代・送料も対象：送料は要検討）
					$tax += $this->shoppingOrderAddressObjectArray[$addressOrder]->calculatePriceRate(
						$request, 5, true, true, true, true, shopping_PackageConfig::_getTaxRoundType(),105 );
				}
			}
			// 決済手数料に対する内消費税
			$tax	+= shopping_PackageConfig::_roundNumeric( $this->settle_fee * 5 / 105, shopping_PackageConfig::_getTaxRoundType() );
			// 割引金額に対する内消費税を減算
			$tax	-= shopping_PackageConfig::_roundNumeric( $this->discount_price * 5 / 105, shopping_PackageConfig::_getTaxRoundDiscountType() );
			return $tax;
		} else {
			// 合計金額から計算の場合
			return shopping_PackageConfig::_roundNumeric( $this->purchase_total * 5 / 105, shopping_PackageConfig::_getTaxRoundType() );
		}
	}
	
	/**
	 * メンバの適正化
	 */
	function optimize() {
		// 個人情報オブジェクトの適正化
		if( is_object($this->memberObject) ) {
			$this->memberObject->optimize();
		}
		// 住所オブジェクトの適正化
		if( is_array($this->shoppingOrderAddressObjectArray) ) {
			foreach( $this->shoppingOrderAddressObjectArray as $number => $shoppingOrderAddressObject ) {
				if( is_object($shoppingOrderAddressObject) ) {
					$this->shoppingOrderAddressObjectArray[$number]->optimize();
				}
			}
		}
		// メールアドレスの取り出し
		if( strlen($this->memberObject->pc_mail) > 0 ) {
			$this->email				= $this->memberObject->pc_mail;
			$this->memberObject->email	= $this->memberObject->pc_mail;
		} else if( strlen($this->memberObject->mb_mail) > 0 ) {
			$this->email				= $this->memberObject->mb_mail;
			$this->memberObject->email	= $this->memberObject->mb_mail;
		}
	}
	/**
	 * 購入者情報の妥当性検査を行います
	 * @param $request spider_HttpRequestオブジェクトのインスタンス
	 * @return エラーがあるならfalseを返します
	 */
	function validatePurchaser( & $request, $requrireMailAddress = true ) {
		// 下位互換: 本オブジェクトにも登録された会員オブジェクトのカラムエラーを除去
		if( is_object($this->memberObject) ) {
			$vars	= get_object_vars( $this->memberObject );
			foreach ( $vars as $k => $v ) {
				if( !is_array( $v )
					&& isset($this->columnErrorHash[$k] ) ) {
					unset($this->columnErrorHash[$k]);
				}
			}
			// 会員オブジェクトの妥当性検査実行
			$this->memberObject->validate( $request, $requrireMailAddress );
			if( $this->memberObject->hasColumnError() ) {
				// 下位互換: 本オブジェクトにもカラムエラーを登録する
				foreach( $this->memberObject->columnErrorHash as $colName => $errors ) {
					$this->columnErrorHash[$colName]	= $errors;
				}
				// エラーなのでfalseで返す
				return false;
			}
		} else {
			return false;
		}
		return true;
	}
	/**
	 * 宛先情報の妥当性検査を行います
	 * @param $request spider_HttpRequestオブジェクトのインスタンス
	 * @return エラーがあるならfalseを返します
	 */
	function validateAddress( & $request ) {
		$isError	= false;
		$this->optimize();
		if( is_array($this->shoppingOrderAddressObjectArray) ) {
			foreach( $this->shoppingOrderAddressObjectArray as $addressOrder => $shoppingOrderAddressObject ) {
				$this->shoppingOrderAddressObjectArray[$addressOrder]->validate( $request, ($addressOrder+1).'番目の'.$GLOBALS['SHOPPING_LABEL_ADDRESS_NAME'].'の' );
				if( $this->shoppingOrderAddressObjectArray[$addressOrder]->hasColumnError() ) {
					$isError	= true;
					// 下位互換: 本オブジェクトにもカラムエラーを登録する
					foreach( $this->shoppingOrderAddressObjectArray[$addressOrder]->columnErrorHash as $colName => $errors ) {
						if( 'address' == $colName || preg_match('/^address/',$colName)==0 ) {
							$colName	= 'address_'.$colName;
						}
						if( !is_array($this->columnErrorHash[$colName]) ) {
							$this->columnErrorHash[$colName]	= array();
						}
						$this->columnErrorHash[$colName]	= array_merge($this->columnErrorHash[$colName],$errors);
					}
				}
			}
		}
		if( $isError ) {
			return false;
		}
		return true;
	}
	/**
	 * オプションの入力を全て妥当性検査
	 * @param $request spider_HttpRequestオブジェクトのインスタンス
	 */
	function validateOptions( & $request ) {
		// 定義済みオプション配列の読み込み
		if( !is_array($this->shoppingOrderOptionObjectArray) || count($this->shoppingOrderOptionObjectArray) == 0 ) {
			$optionHash	= $request->getAttribute('shopping.order.option.optionHash');
			if( is_null($optionHash) ) {
				require_once(dirname(__FILE__).DIRECTORY_SEPARATOR.'order'.DIRECTORY_SEPARATOR.'option'.DIRECTORY_SEPARATOR.'LoadList.class.php');
				shopping_order_option_LoadList::execute( $request );
				$optionHash	= $request->getAttribute('shopping.order.option.optionHash');
			}
			$this->shoppingOrderOptionObjectArray	= $optionHash;
		}
		if( !is_array($this->shoppingOrderOptionObjectArray) ) {
			$this->shoppingOrderOptionObjectArray	= array();
		}
		foreach( $this->shoppingOrderOptionObjectArray as $optionOrder => $shoppingOrderOptionObject ) {
			$this->shoppingOrderOptionObjectArray[$optionOrder]->clearColumnErrors();
			$this->shoppingOrderOptionObjectArray[$optionOrder]->validateFields( $request );
		}
	}
	/**
	 * オプション項目の入力をメンバにセットして妥当性検査を行います。
	 * ※事前にshopping.order.option.LoadListモジュールがコールされている必要があります。
	 * エラーメッセージを本インスタンス内の$this->columnErrorHash['option_value_erros']ハッシュに
	 * オプション番号を添え字で蓄積します
	 * @param $request spider_HttpRequestオブジェクトのインスタンス
	 * @return エラーがあるならfalseを返します
	 */
	function validatePostOptions( & $request, $renew=false ) {
		// 注文オプション定義を必要に応じて取得
		if( $renew
		|| is_null($this->shoppingOrderOptionObjectArray)
		|| count($this->shoppingOrderOptionObjectArray) == 0 ) {
			// 定義済みオプション配列の読み込み
			$optionHash	= $request->getAttribute('shopping.order.option.optionHash');
			if( is_null($optionHash) ) {
				require_once(dirname(__FILE__).DIRECTORY_SEPARATOR.'order'.DIRECTORY_SEPARATOR.'option'.DIRECTORY_SEPARATOR.'LoadList.class.php');
				shopping_order_option_LoadList::execute( $request );
				$optionHash	= $request->getAttribute('shopping.order.option.optionHash');
			}
			if( is_array($optionHash) ) {
				$this->shoppingOrderOptionObjectArray	= $optionHash;
			} else {
				$this->shoppingOrderOptionObjectArray	= array();
			}
		}
		// 今回の入力に対するエラー有無のフラグ
		$isError	= false;
		// 入力値は配列にする
		$optionNames	= $request->getParam('option_names','post','array');
		$optionValues	= $request->getParam('option_values','post','array');
		// @deprecated 下位互換の為オプション全体入力エラーを削除
		unset($this->columnErrorHash['option_values']);
		// 入力値の取得
		foreach( $this->shoppingOrderOptionObjectArray as $optionOrder => $shoppingOrderOptionObject ) {
			$this->shoppingOrderOptionObjectArray[$optionOrder]->clearColumnErrors();
			if( in_array( $shoppingOrderOptionObject->option_name, $optionNames) ) {
				// 入力がある場合は取得
				$inputValue	= null;
				foreach( $optionNames as $key => $val ) {
					if( $shoppingOrderOptionObject->option_name == $val ) {
						$inputValue	= $optionValues[$key];
						break;
					}
				}
				if( is_array($inputValue) ) {
					$inputValue	= implode('/',$inputValue);
				}
				$this->shoppingOrderOptionObjectArray[$optionOrder]->option_value	= $inputValue;
				// 妥当性検査
				$this->shoppingOrderOptionObjectArray[$optionOrder]->validateFields( $request );
			}
		}
		if( $isError ) {
			return false;
		} else {
			return true;
		}
	}
	/**
	 * メールテンプレートを使用して情報メールを送信します
	 */
	function sendInformationMail( & $request, $targetAddress, $templateName='SHOPMAILTHANKSNW', $bcc=null, $loginPassword='', $additionalReplaceHash=array(), $loginUserObject=null ) {
		$dbo	= $request->getAttribute( 'dbo' );
		if( strlen(trim($targetAddress)) == 0 ) {
			$request->addLocaledError('shopping.error.cart.nomail',SPIDER_LOG_LEVEL_FATAL,array(''));
			return false;
		}
		// 宛先とファイル名に応じたメールテンプレート情報を取得
		$templateInfo	= $this->getMailTemplateInformation( $request, $templateName, $targetAddress, $additionalReplaceHash );
		if( $templateInfo === false ){
			$request->addLocaledError('member.error.mail.template.notfound',SPIDER_LOG_LEVEL_FATAL,array('MEMBERJOINCMP'));
			return false;
		}
		// 件名と本文のどちらかが設定されていないなら送信しなくて良いものと判断する
		if( strlen($templateInfo['body']) == 0 || strlen($templateInfo['subject']) == 0 ){
			$historyNote	= $targetAddress.'宛に通知メール送信しませんでした :'.$templateInfo['templateName'].'の件名または本文が設定されていません。';
			$this->writeHistoryNote( $request, 'メール送信', $historyNote, $templateName, $loginUserObject );
			return true;
		}
		// メールオブジェクト
		$mailerObject	= $request->getSystemMailer();
		if( false === $mailerObject ) {
			$request->addLocaledError('system.error.common.noinstalled',SPIDER_LOG_LEVEL_FATAL,array(''));
			return false;
		}
		if( !is_null($bcc) ) {
			$mailerObject->addBcc($bcc);
		}
		// 送信実行
		if( strlen($templateInfo['fromString']) > 0 ) {
			$result	= $mailerObject->send( $targetAddress, $templateInfo['subject'], $templateInfo['body'],
			$templateInfo['fromString'], $templateInfo['replyAddress'], $templateInfo['returnAddress'] );
			if( $result ) {
				// メール送信を履歴ノートに追記
				$historyNote	= $targetAddress.'宛に通知メール送信 :'.$templateInfo['templateName'];
				$this->writeHistoryNote( $request, 'メール送信', $historyNote, $templateName, $loginUserObject );
				return true;
			} else {
				return false;
			}
		} else {
			$request->addLocaledError('system.error.common.noinstalled',SPIDER_LOG_LEVEL_FATAL,array(''));
			$this->memberObject->login_password	= $loginPassword;
			return false;
		}
	}
	/**
	 * 注文内容で文字を置換したメールテンプレート情報を取得します
	 */
	function getMailTemplateInformation( & $request, $templateName, $targetAddress, $additionalReplaceHash=array() ) {
		$dbo	= $request->getAttribute( 'dbo' );
		// 宛先とファイル名に応じたメールテンプレート情報を取得
		$templateInfo	= shopping_PackageConfig::getMailTemplateInformation( $request, $templateName, $targetAddress );
		if( $templateInfo === false ) {
			return false;
		}
		// 再計算
		$this->calculate( $request );
		// 支払残額計算
		$this->remain_price	= $this->payment_total - $this->settle_price;
		// 置換ハッシュ
		$replaceHash	= array();
		$replaceHash['order']	= $this;
		foreach( $additionalReplaceHash as $key => $val ) {
			$replaceHash[$key]	= $val;
		}
		// 個人情報オブジェクトの表示用文字列を設定
		$this->memberObject->setFieldViewValues( $request );
		$this->memberObject->login_password_decoded = $this->memberObject->decodePassword( $request, $this->memberObject->login_password );
		$replaceHash['purchaser']	= $this->memberObject;
		$replaceHash['member']	= $this->memberObject;
		// 検索データ連携
		if( strlen($this->search_data_id) > 0 ) {
			$searchDataObject = spider_Controller::createObject('search_DaoSearchData');
			if( $dbo->loadById( $searchDataObject, $this->search_data_id) ) {
				$this->searchDataObject = $searchDataObject;
				$this->searchDataObject->prefecture_name	= $GLOBALS['PREFECTURE_HASH'][$this->searchDataObject->prefecture_number];
				$replaceHash['search']	= $this->searchDataObject;
			} else {
				$this->searchDataObject = null;
			}
		}
		// 決済方法文字列の作成
		$settleMethodObject			= $this->getSettleMethodObject( $request );
		if( false === $settleMethodObject || is_null($settleMethodObject) ) {
			$request->addLocaledError('shopping.error.order.failtoloadplugin',SPIDER_LOG_LEVEL_FATAL,array(''));
			return false;
		} else {
			$this->settle_method_name	= $settleMethodObject->getMethodViewName();
		}
		// 決済方法ごとのコメントは先に処理
		$templateInfo['body']	= str_replace('{settle_method_comment}',$settleMethodObject->getMailComment(),$templateInfo['body']);
		$templateInfo['body']	= str_replace('{settle_method_order_comment}',$settleMethodObject->getMailOrder(),$templateInfo['body']);
		// 合計金額フォーマット
		$totalTemplateInfo	= shopping_PackageConfig::getMailTemplateInformation( $request, 'SHOPMAILSUBTTALP', $targetAddress );
		if( false === $totalTemplateInfo ) {
			return false;
		}
		$totalFormat	= $totalTemplateInfo['strings'];
		$templateInfo['body']		= str_replace('{order::settle_total_strings}',$totalFormat, $templateInfo['body'] );
		// 卸合計金額フォーマット
		$totalTemplateInfo	= shopping_PackageConfig::getMailTemplateInformation( $request, 'SHOPMAILSUBTTALA', $targetAddress );
		if( false === $totalTemplateInfo ) {
			return false;
		}
		$totalFormat	= $totalTemplateInfo['strings'];
		$templateInfo['body']		= str_replace('{order::settle_total_wholesale}',$totalFormat, $templateInfo['body'] );
		// ログイン情報の記載が必要ならログイン情報文字列を
		if( $this->mail_flag >= 10 ) {
			// テンプレートファイル名を判断
			$loginTemplateInfo	= shopping_PackageConfig::getMailTemplateInformation( $request, 'SHOPMAILSUBLOGIN', $targetAddress );
			if( false === $loginTemplateInfo ) {
				return false;
			}
			$loginFormat	= $loginTemplateInfo['strings'];
			$templateInfo['body']		= str_replace('{login_information}',$loginFormat, $templateInfo['body'] );
		} else {
			$templateInfo['body']	= str_replace('{login_information}','', $templateInfo['body'] );
		}
		
		// 宛先ごとの文字列置換
		$addressStrings	= '';
		if( is_array($this->shoppingOrderAddressObjectArray) ) {
			foreach( $this->shoppingOrderAddressObjectArray as $addressOrder => $shoppingOrderAddressObject ) {
				$addressStr	= $shoppingOrderAddressObject->getMailStrings( $request, $this, $targetAddress, 'public', $this->searchDataObject );
				if( false === $addressStr ) {
					return false;
				}
				$addressStrings	.= $addressStr;
			}
		}
		$replaceHash['address_items']	= $addressStrings;
		// 直接紐づいた注文オプションの置換
		$optionStrings	= '';
		if( is_array($this->shoppingOrderOptionObjectArray) ) {
			foreach( $this->shoppingOrderOptionObjectArray as $optionNum => $shoppingOrderOptionObject ) {
				$optStr		= $shoppingOrderOptionObject->getMailStrings( $request, $this, $targetAddress, 'public', $this->searchDataObject );
				if( false === $optStr ) {
					return false;
				}
				$optionStrings	.= $optStr;
			}
		}
		$replaceHash['option_items']	= $optionStrings;
		// 変換して返す
		spider_Controller::loadClassDefinition('util_Mail');
		$templateInfo['subject']	= util_Mail::replaceFormatStrings( $templateInfo['subject'], $replaceHash );
		$templateInfo['body']	= util_Mail::replaceFormatStrings( $templateInfo['body'], $replaceHash );
		return $templateInfo;
	}
	/**
	 * 設定されている決済方法の決済方法オブジェクトを取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @return mixed 選択されている決済方法プラグインオブジェクト,失敗したらfalse
	 */
	function getSettleMethodObject( & $request ) {
		if(preg_match( '/^[0-9]{1,3}$/',$this->settle_method) == 0 ) {
			return null;
		} else {
			$settleMethodObjectArray	= $request->getAttribute('shopping.order.settlement.methodExistsObjectArray');
			if( is_array($settleMethodObjectArray) ) {
				// 決済方法のLoadListが事前にコールされている場合
			} else {
				// 決済方法のLoadListが事前にコールされていない場合は強制コール
				require_once(dirname(__FILE__).DIRECTORY_SEPARATOR.'order'
					.DIRECTORY_SEPARATOR.'settlement'.DIRECTORY_SEPARATOR.'LoadListExists.class.php');
				shopping_order_settlement_LoadListExists::execute( $request );
				$settleMethodObjectArray	= $request->getAttribute('shopping.order.settlement.methodExistsObjectArray');
			}
			if( is_array($settleMethodObjectArray) ) {
				foreach( $settleMethodObjectArray as $settleObject ) {
					if( $settleObject->getMethodNumber() == $this->settle_method ) {
						return $settleObject;
					}
				}
			} else {
				return false;
			}
		}
	}
	/**
	 * 関連プロモーションオブジェクトを取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @return mixed 関連プロモーションがある場合はshopping_DaoShoppingPromotionインスタンス、ない場合はnull
	 */
	function getRelatedPromotionObject( & $request, $force=false ) {
		$dbo	= $request->getAttribute( 'dbo' );
		if( strlen($this->promotion_code) > 0 ) {
			if( $force || is_null($this->shoppingPromotionObject) ) {
				$sql	= 'SELECT * FROM '.TABLE_NAME_SHOPPING_PROMOTION
					.' WHERE promotion_code='.$dbo->quote($this->promotion_code)
					.' AND status_flag>=100 AND status_flag<200';
				$promotionObject	= spider_Controller::createObject('shopping_DaoShoppingPromotion');
				$result	= $dbo->queryAll( $sql, $promotionObject, false, false );
				if( false === $result ) {
					return false;
				} else if( count( $result ) > 0 ) {
					$this->shoppingPromotionObject	= $result[0];
				} else {
					$this->promotion_code			= null;
					$this->shoppingPromotionObject	= null;
				}
			}
		} else {
			$this->promotion_code			= null;
			$this->shoppingPromotionObject	= null;
		}
		return $this->shoppingPromotionObject;
	}
	/**
	 * オブジェクト情報を指定された順序のCSV行にして取得します。
	 */
	function getCsvString( $columnOrderHash, $quote=true ) {
		$includeItemInfo	= false;
		$returnString		= '';
		foreach ( $this->shoppingOrderAddressObjectArray as $num => $shoppingOrderAddressObjec ) {
			$rowString = '';
			foreach ( $columnOrderHash as $varName=>$order_number ) {
				$value	= '';
				if( preg_match( '/^member\\_/', $varName ) > 0 ) {
					// 個人情報の値
					$varName	= preg_replace('/^member\\_/','',$varName);
					$value	= $this->memberObject->getColumnString( $varName, $quote );
				} else if( preg_match( '/^address\\_/', $varName ) > 0 ) {
					// 宛先情報の値
					$varName	= preg_replace('/^address\\_/','',$varName);
					$value	= $shoppingOrderAddressObjec->getColumnString( $varName, $quote );
				} else if( preg_match( '/^item\\_/', $varName ) > 0 ) {
					if( 'item_all' == $varName ) {
						// 全ての注文情報を末尾に加える場合フラグを立てる
						$includeItemInfo	= true;
						continue;
					} else {
						// TODO:個別注文情報の場合の処理は今後のバージョン
						continue;
					}
				} else {
					$value	= $this->getColumnString( $varName, $quote );
				}
				$columnValueArray[$order_number]	= $value;
			}
			// キーでソート
			ksort( $columnValueArray );
			$rowString	= implode(',',$columnValueArray);
			
			// 商品情報
			if ( $includeItemInfo ) {
				// 商品情報が指定されていた場合、購入商品数分繰り返す
				$columnOrderUnitHash = array();
				$orderNumber = 0;
				foreach ( $GLOBALS['SHOPPING_ORDER_UNIT_CSV_DEFINITION'] as $itemKey=>$itemName ) {
					$columnOrderUnitHash[$itemKey] = $orderNumber;
					$orderNumber++;
				}
				foreach( $shoppingOrderAddressObjec->shoppingOrderItemObjectArray as $shoppingOrderItemObject ) {
					$returnStrings	= ','.$shoppingOrderItemObject->getCsvString($columnOrderUnitHash);
					$rowString	.= str_replace("\n","",$returnStrings);
				}
			}
			$returnString .= $rowString."\n";
		}
		
		return $returnString;
	}
	/**
	 * CSVダウンロードの為のカラム取得メソッド
	 * 項目キーから値を取得します
	 */
	function getColumnString( $key, $quote=true, $filter=null ) {
		$returnColumn	= $this->$key;
		$returnStrings	= '';
		if( is_array($returnColumn) ) {
			$returnStrings	= implode(',',$returnColumn);
		} else {
			if ( $key=='buying_flag' ) {
				// 卸販売
				$strBuying = '';
				if ( $returnColumn=='0' ) {
					$strBuying = '拒否';
				} else {
					if ( $returnColumn=='1' ) { $strBuying = '先払いのみ許可 '; }
					if ( $returnColumn=='2' ) { $strBuying = '許可 '; }
					$strBuying .= '卸割引'.$this->buying_rate.'%';
				}
				$returnStrings	= $strBuying;
			} else if ( $key=='status_flag' ) {
				// 状態
				$returnStrings	= $GLOBALS['SHOPPING_ORDER_STATUS_HASH'][$returnColumn];
			} else if ( $key=='status_settle' ) {
				// 決済フラグ
				$returnStrings	= $GLOBALS['SHOPPING_ORDER_STATUS_SETTLE_HASH'][$returnColumn];
			} else if ( $key=='status_promotion' ) {
				// プロモーション状態
				$returnStrings	= $GLOBALS['SHOPPING_PROMOTION_STATUS_HASH'][$returnColumn];
			} else if ( $key=='settle_method' ) {
				// 決済方法
				$returnStrings	= $GLOBALS['SHOPPING_SETTLEMENT_DEF_HASH'][$returnColumn];
			} else {
				// 注文情報の値
				$returnStrings	= $returnColumn;
			}
		}
		if( strlen(trim($filter)) > 0 ) {
			$returnStrings	= mb_convert_kana( $returnStrings, $filter );
		}
		if( $quote ) {
			$returnStrings	= '"'.str_replace('"','""',$returnStrings).'"';
		}
		return $returnStrings;
	}
	//
	// 決済プラグイン動作補助用メソッド
	//
	/**
	 * 決済トランザクションコードを保存
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @param $transactionCode ログメッセージ
	 */
	function setSettleTransactionCode( & $request, $transactionCode ) {
		$this->settle_transaction_code	= $transactionCode;
		if( strlen(trim($this->order_number)) > 0 ) {
			$dbo	= $request->getAttribute('dbo');
			$sql	= 'UPDATE '.TABLE_NAME_SHOPPING_ORDER
			.' SET settle_transaction_code='
			.$dbo->quote($this->settle_transaction_code)
			.' WHERE order_id='.$dbo->quote($this->order_id);
			$result	= $dbo->query($sql);
			if( $result === false ) {
				$request->addLocaledError('database2.error.update',SPIDER_LOG_LEVEL_FATAL,array($sql));
				return false;
			} else {
				return true;
			}
		}
		return true;
	}
	/**
	 * 実決済金額をを保存
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @param $price 実決済金額
	 */
	function setSettlePrice( & $request, $price ) {
		$this->settle_price	= $price;
		if( strlen(trim($this->order_number)) > 0 ) {
			$dbo	= $request->getAttribute('dbo');
			$sql	= 'UPDATE '.TABLE_NAME_SHOPPING_ORDER
			.' SET settle_price='
			.$dbo->quote($this->settle_price)
			.' WHERE order_id='.$dbo->quote($this->order_id);
			$result	= $dbo->query($sql);
			if( $result === false ) {
				$request->addLocaledError('database2.error.update',SPIDER_LOG_LEVEL_FATAL,array($sql));
				return false;
			} else {
				return true;
			}
		}
		return true;
	}
	/**
	 * 実決実行日時をを保存
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @param $price 実決済金額
	 */
	function setSettleDate( & $request, $dateTime=null ) {
		$this->settle_date	= $dateTime;
		if( strlen(trim($this->order_number)) > 0 ) {
			$dbo	= $request->getAttribute('dbo');
			$sql	= 'UPDATE '.TABLE_NAME_SHOPPING_ORDER
			.' SET settle_date='
			.$dbo->quote($this->settle_date)
			.' WHERE order_id='.$dbo->quote($this->order_id);
			$result	= $dbo->query($sql);
			if( $result === false ) {
				$request->addLocaledError('database2.error.update',SPIDER_LOG_LEVEL_FATAL,array($sql));
				return false;
			} else {
				return true;
			}
		}
		return true;
	}
	/**
	 * 決済ログを追記
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @param $logMessage ログメッセージ
	 */
	function settleLogLn( & $request, $logMessage ) {
		$this->settle_log	.= $logMessage."\r\n";
		if( strlen(trim($this->order_number)) > 0 ) {
			$dbo	= $request->getAttribute('dbo');
			$sql	= 'UPDATE '.TABLE_NAME_SHOPPING_ORDER
			.' SET settle_log='.$dbo->quote($this->settle_log)
			.' WHERE order_id='.$dbo->quote($this->order_id);
			$result	= $dbo->query($sql);
			if( $result === false ) {
				$request->addLocaledError('database2.error.update',SPIDER_LOG_LEVEL_FATAL,array($sql));
				return false;
			} else {
				return true;
			}
		}
		return true;
	}
	//
	//
	//
	/**
	 * この買い物かごにアイテムがはいっているか確認
	 */
	function hasItem( & $request ){
		if( !is_array($this->shoppingOrderAddressObjectArray)
		|| count($this->shoppingOrderAddressObjectArray)==0 ){
			return false;
		} else {
			foreach( $this->shoppingOrderAddressObjectArray as $aNum => $addressObject ){
				if(is_array($shoppingOrderAddressObject->shoppingOrderItemObjectArray)
				&& count($shoppingOrderAddressObject->shoppingOrderItemObjectArray) > 0 ){
					return true;
				}
			}
		}
		return false;
	}
	/**
	 * この注文に紐づく商品が注文オプション入力を必要とするか確認
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function hasItemOrderOptions( & $request ) {
		if( is_array($this->shoppingOrderOptionObjectArray) && count($this->shoppingOrderOptionObjectArray) > 0 ){
			return true;
		}
		if( is_array($this->shoppingOrderAddressObjectArray) ) {
			foreach( $this->shoppingOrderAddressObjectArray as $aNum => $addressObject ) {
				if( is_array($addressObject->shoppingOrderItemObjectArray) ) {
					foreach( $addressObject->shoppingOrderItemObjectArray as $itemNum => $shoppingOrderItemObject ) {
						if( $shoppingOrderItemObject->hasOrderOption( $request ) ) {
							return true;
						}
					}
				}
			}
		}
		return false;
	}
	//
	// 下位互換メソッド：1.3以降で削除予定
	//
	/**
	 * 現在の情報で金額計算して販売単位ハッシュを取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @deprecated
	 */
	function getProductUnitHash( & $request ) {
		if( is_null($this->shoppingProductUnitObjectHash) ) {
			$this->setAllUnitObject( $request );
		}
		return $this->shoppingProductUnitObjectHash;
	}
	/**
	 * 現在のカートの中身で配送サイズを判断して個数をハッシュで取得します
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @return hash $deliveryWeightCountHash
	 * @deprecated 下位互換の為1.2では0番目に設定されている宛先の口数を取得します
	 */
	function getDeliveryWeightCountHash( & $request ) {
		if( is_array($this->shoppingOrderAddressObjectArray)
		&& is_object($this->shoppingOrderAddressObjectArray[0]) ) {
			$nomalWeightArray	= array();
			$coolWeightArray	= array();
			$deliveryWeightCountHash
			= $this->shoppingOrderAddressObjectArray[0]->getDeliveryWeightCountHash( $request, $nomalWeightArray, $coolWeightArray );
		} else {
			$deliveryWeightCountHash	= array( '0'=> array(), '1'=>array() );
			return $deliveryWeightCountHash;
		}
		return $deliveryWeightCountHash;
	}
	/**
	 * 関連プロモーションの成果報告HTMLタグを取得します
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @deprecated 1.2
	 */
	function getRelatedPromotionComplateHtmlTag( & $request ) {
		$this->getRelatedPromotionObject( $request );
		if( is_object($this->shoppingPromotionObject) ) {
			return $this->shoppingPromotionObject->getReportHtmlTag( $request, $this );
		}
		return '';
	}
	/**
	 * 関連プロモーションの成果報告URLへのHTTPリクエストを実行します
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @deprecated 1.2
	 */
	function sendRelatedPromotionReportRequest( & $request ) {
		$this->getRelatedPromotionObject( $request );
		if( is_object($this->shoppingPromotionObject) ) {
			return $this->shoppingPromotionObject->sendReportHttpRequest( $request, $this );
		}
		return false;
	}
	/**
	 * 注文が継続サービスを含むか確認
	 * @deprecated
	 */
	function isContinued() {
		if( is_array($this->shoppingOrderAddressObjectArray) ) {
			foreach( $this->shoppingOrderAddressObjectArray as $aNum => $addressObject ) {
				$shoppingOrderAddressObject	= & $this->shoppingOrderAddressObjectArray[$aNum];
				if( is_array($shoppingOrderAddressObject->shoppingOrderItemObjectArray) ) {
					foreach( $shoppingOrderAddressObject->shoppingOrderItemObjectArray as $orderItemObject ) {
						if( $orderItemObject->delivery_type >= 20 ) {
							return true;
						}
					}
				}
			}
		}
		return false;
	}
	/**
	 * 編集権限があるか確認
	 * 管理者・申込者・商品提供者であれば編集可能
	 * 管理者なら1, 申込者なら2, 商品提供者なら3を返す
	 */
	function confirmModifyPermittion( & $request, $loginUserObject ) {
		if( is_null($loginUserObject) || !is_object($loginUserObject) ){
			return 0;
		} else if( SYSTEM_LOGIN_USER_ADMINISTRATORS == $loginUserObject->getLoginGroupLevel() ){
			return 1;
		} else {
			$dbo	= $request->getAttribute('dbo');
			foreach( $this->shoppingOrderAddressObjectArray as $aNum => $addressObject ) {
				$shoppingOrderAddressObject	= & $this->shoppingOrderAddressObjectArray[$aNum];
				if( is_array($shoppingOrderAddressObject->shoppingOrderItemObjectArray) ) {
					foreach( $shoppingOrderAddressObject->shoppingOrderItemObjectArray as $orderItemObject ) {
						$unitObject	= $orderItemObject->getUnitObject( $dbo->request );
						if( $unitObject->owner_id == $loginUserObject->getUniqueId() ) {
							return 3;
						} else if( !is_object($unitObject->shoppingProductObject)) {
							$unitObject->loadParentProductObject( $dbo );
						}
						if( $unitObject->shoppingProductObject->owner_id == $loginUserObject->getUniqueId() ) {
							return 3;
						}
					}
				}
			}
			if( $this->owner_id == $loginUserObject->getUniqueId() ) {
				return 2;
			}
		}
		return 0;
	}
	/**
	 * メール通知すべき提供者メンバーオブジェクトを全て取得します
	 */
	function getProducerMemberObjectArray( & $request ) {
		$dbo	= $request->getAttribute('dbo');
		$memberIdArray			= array();
		$memberIdQuotedArray	= array();
		foreach( $this->shoppingOrderAddressObjectArray as $aNum => $addressObject ) {
			$shoppingOrderAddressObject	= & $this->shoppingOrderAddressObjectArray[$aNum];
			if( is_array($shoppingOrderAddressObject->shoppingOrderItemObjectArray) ) {
				foreach( $shoppingOrderAddressObject->shoppingOrderItemObjectArray as $orderItemObject ) {
					$unitObject	= $orderItemObject->getUnitObject( $dbo->request );
					if( !in_array($unitObject->owner_id,$memberIdArray) && 'SYSADMIN' != $unitObject->owner_id ) {
						array_push($memberIdArray,$unitObject->owner_id);
						array_push($memberIdQuotedArray,$dbo->quote($unitObject->owner_id));
					}
					if( !is_object($unitObject->shoppingProductObject)) {
						$unitObject->loadParentProductObject( $dbo );
					}
					if( !in_array($unitObject->shoppingProductObject->owner_id,$memberIdArray)
					&& 'SYSADMIN' != $unitObject->shoppingProductObject->owner_id ) {
						array_push($memberIdArray,$unitObject->shoppingProductObject->owner_id);
						array_push($memberIdQuotedArray,$dbo->quote($unitObject->shoppingProductObject->owner_id));
					}
				}
			}
		}
		if( count($memberIdArray) > 0 ) {
			$sql	= 'SELECT * FROM '.TABLE_NAME_MEMBER
			.' WHERE member_id IN ('.implode(',',$memberIdQuotedArray).')';
			$memberObject	= spider_Controller::createObject('member_DaoMember');
			$result		= $dbo->queryAll( $sql,$memberObject, false, false );
			if ( false === $result ) {
				$request->addLocaledError('database2.error.common',SPIDER_LOG_LEVEL_FATAL,array($sql));
				return false;
			} else {
				return $result;
			}
		} else {
			return array();
		}
	}
	/**
	 * 変更履歴を追記します
	 * @param spider_HttpRequest &$request spider_HttpRequestインスタンス参照
	 * @param string $message 履歴文章
	 */
	function writeHistoryNote( & $request, $subject, $message, $mailTemplateId, $loginUserObject ){
		$dbo	= $request->getAttribute('dbo');
		$operationType	= $this->confirmModifyPermittion( $request, $loginUserObject );
		// 履歴テーブルにインサート
		$sql	= 'INSERT INTO '.TABLE_NAME_SHOPPING_ORDER_HISTORY.'(history_date,order_id,subject,description,operation_class,template_id)'
		.'VALUES('.$dbo->quote(date('Y-m-d H:i:s')).','.$dbo->quote($this->order_id).','.$dbo->quote($subject).','.$dbo->quote($message)
		.','.$operationType.','.$dbo->quote($mailTemplateId).')';
		$dbo->query($sql);
		// 暫定：今後はどうするか検討concatが使用できるDBMSとできないものがあるのでSELECTしてつなげて更新する
		$addLine		= date('Y-m-d H:i:s').' ['.$subject.']';
		if( 1 == $operationType ){
			$addLine	.= '[管理者]';
		} else if( 2 == $operationType ){
			$addLine	.= '['.$GLOBALS['SHOPPING_LABEL_ORDER'].'者]';
		} else if( 3 == $operationType ){
			$addLine	.= '['.$GLOBALS['SHOPPING_LABEL_PRODUCT'].'提供者]';
		} else {
			$addLine	.= '[不明]';
		}
		$addLine	.= $message."\n";
		$sql	= 'SELECT history_note FROM '.$this->getTableName().' WHERE order_number='.$this->order_number;
		$historyNote	= $dbo->queryOne($sql);
		if(false===$historyNote){
			return false;
		}else{
			$sql	= 'UPDATE '.$this->getTableName().' SET history_note='.$dbo->quote($addLine.$historyNote)
			.' WHERE order_number='.$this->order_number;
			if( $dbo->query($sql) ){
				return true;
			}else{
				return false;
			}
		}
	}
	/**
	 * オブジェクト比較して要素の違いを抽出します
	 * @param spider_HttpRequest &$request spider_HttpRequestインスタンス参照
	 * @param object $compareObject 比較対象オブジェクト
	 * @return array 違いのキーと値ハッシュ
	 */
	function getDifference( & $request, $compareObject ) {
		$defferenceHash	= parent::getDifference( $request, $compareObject );
		$newDefferenceHash	= array();
		$GLOBALS['SHOPPING_DEFFERENCE_ORDER_HASH']	= array(
			'member_id'	=>'予約者ID',
			'price_total'	=>'施設利用合計金額',
			'promotion_fee'	=>'プロモーション報酬',
			'discount_price'	=>'紹介割引金額',
			'discount_admin'	=>'管理者調整金額',
			'purchase_total'	=>'利用合計金額',
			'payment_total'	=>'お支払金額',
			'cost_total'	=>'合計コスト',
			'delivery_price'	=>'合計配送料',
			'wrapping_price'	=>'合計包装代',
			'tax_rate'	=>'消費税率',
			'point_total'	=>'付与ポイント合計',
			'point_use'	=>'利用ポイント',
			'order_comment'	=>'通信欄',
			'admin_note'	=>'管理者メモ欄',
			'mail_flag'	=>'メール送信フラグ',
			'status_flag'	=>'状態',
			'status_settle'	=>'決済状態',
			'settle_method'	=>'決済方法',
			'settle_price'	=>'決済金額',
			'settle_fee'	=>'決済手数料',
			'settle_transaction_code'	=>'決済用トランザクションコード',
			'status_promotion'	=>'プロモーション状態',
			'promotion_code'	=>'プロモーションコード',
			'order_date'	=>$GLOBALS['SHOPPING_LABEL_ORDER'].'日',
			'settle_date'	=>'最終決済日',
			'memberObject'	=>'予約者情報',
			'shoppingPromotionObject'	=>'プロモーション情報',
			'shoppingOrderAddressObjectArray'	=>$GLOBALS['SHOPPING_LABEL_ADDRESS_NAME'].'情報',
			'shoppingOrderOptionObjectArray'	=>'予約オプション情報',
			'memberObject'	=>'予約者情報',
		);
		foreach( $defferenceHash as $key => $val ){
			if( array_key_exists($key,$GLOBALS['SHOPPING_DEFFERENCE_ORDER_HASH']) ){
				$newKey	= $GLOBALS['SHOPPING_DEFFERENCE_ORDER_HASH'][$key];
				$newDefferenceHash[$newKey]	= $val;
			}
		}
		return $newDefferenceHash;
	}
	/**
	 * 変更前の情報を残す為にシリアル化してファイルに保存する
	 */
	function saveSerialized( & $request ){
		$saveUri	= '/shopping/history/'.$this->order_id.'.dat';
		$writer	= spider_Controller::createObject('system_DataFileWriter');
		if( $writer->open( $request, $saveUri, 'w', DIR_NAME_DATA ) ) {
			$writer->write( serialize($this) );
			$writer->close( $request );
		}
	}
	/**
	 * 最後の変更をオブジェクトで取得
	 */
	function getSerialized( & $request ){
		$saveUri	= '/shopping/history/'.$this->order_id.'.dat';
		spider_Controller::loadClassDefinition('system_DataFileWriter');
		if( system_DataFileWriter::isExists( $request, $saveUri, DIR_NAME_DATA ) ){
			$strings	= system_DataFileWriter::getContents($request,$saveUri,DIR_NAME_DATA);
			if( strlen($strings) > 0 ){
				$oldOrderObject	= unserialize($strings);
				return $oldOrderObject;
			}
		}
		return null;
	}
	/**
	 * 最後の変更保存ファイルを削除
	 */
	function deleteSerialized( & $request ){
		$saveUri	= '/shopping/history/'.$this->order_id.'.dat';
		spider_Controller::loadClassDefinition('system_DataFileWriter');
		if( system_DataFileWriter::isExists( $request, $saveUri, DIR_NAME_DATA ) ){
			system_DataFileWriter::delete($request,$saveUri,DIR_NAME_DATA);
		}
	}
}
?>