<?php
/*
 * shopping/DaoShoppingOrderItem.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' );
/**
 * shopping_DaoShoppingOrderItem
 * shoppingパッケージ データアクセスオブジェクトクラス shopping_order_itemテーブル用
 */
class shopping_DaoShoppingOrderItem extends database2_AbstractData {
	/** 商品注文番号	*/
	var $item_number;
	/** 商品注文ID	*/
	var $item_id;
	/** 注文ID	*/
	var $order_id;
	/** 宛先ID	*/
	var $address_id;
	/** 注文販売単位ID	*/
	var $unit_id;
	/** 販売単価(購入時点)	*/
	var $price_unit		= -1;
	/** 販売単位コスト(購入時点)	*/
	var $cost_unit		= 0;
	/** 販売単位付与ポイント(購入時点)	*/
	var $point_unit		= 0;
	/** 販売単位配送種別(購入時点)	*/
	var $delivery_type;
	/** 販売単位配送目安値(購入時点)	*/
	var $delivery_weight;
	/** 割引除外フラグ(購入時点)	*/
	var $discount_exception;
	/** 注文数	*/
	var $order_count	= 1;
	/** サービス開始日時	*/
	var $svc_start_date;
	/** サービス終了日時	*/
	var $svc_limit_date;
	/** サービス単位時間	*/
	var $service_term;
	/** 予約商品用：実利用販売単位ID	*/
	var $used_unit_id;

	// オブジェクト固有の情報
	/** 販売単位オブジェクト	*/
	var $shoppingProductUnitObject		= null;
	/** 販売単位用注文オプションオブジェクト配列	*/
	var $shoppingOrderOptionObjectArray	= array();
	/** オブジェクト拡張：ファイル配列	*/
	var $fileIdArray		= array();
	
	/**
	 * コンストラクタ
	 */
	function shopping_DaoShoppingOrderItem() {
		$this->shoppingProductUnitObject		= null;
		$this->shoppingOrderOptionObjectArray	= array();
		$this->fileIdArray		= array();
		$this->fileIdArray_org	= array();
	}
	/**
	 * 添付画像の読み込み
	 * @param $dbo database2_Connectionオブジェクト
	 * @param boolean 成功したらtrue
	 * @access public
	 */
	function loadRelatedFiles( $dbo ) {
		$this->fileIdArray		= array();
		$this->fileIdArray_org	= array();
		$sql	= 'SELECT file_id,order_number FROM '.TABLE_NAME_SHOPPING_ORDER_ITEM_FILE
			.' WHERE item_id='.$dbo->quote($this->item_id)
			.' ORDER BY order_number ASC';
		$rows	= $dbo->queryAll( $sql, 'hash', false );
		if ( $rows === false ) {
			return false;
		} else {
			foreach( $rows as $row ) {
				$this->fileIdArray[$row['order_number']]	= trim($row['file_id']);
				$this->fileIdArray_org[$row['order_number']]	= trim($row['file_id']);
			}
		}
		return true;
	}
	/**
	 * 関連情報読み込みメソッド
	 */
	function loadRelation( $dbo ) {
		// 販売単位を同時読み込み
		$this->getUnitObject( $dbo->request );
		// 注文オプションを読み込み
		$shoppingOrderOptionObject	= spider_Controller::createObject('shopping_DaoShoppingOrderOption');
		$sql	= 'SELECT * FROM '.TABLE_NAME_SHOPPING_ORDER_OPTION
			.' WHERE order_id='.$dbo->quote($this->order_id)
			.' AND item_id='.$dbo->quote($this->item_id)
			.' ORDER BY item_order ASC';
		$this->shoppingOrderOptionObjectArray	= $dbo->queryAll( $sql,$shoppingOrderOptionObject,true );
		if ( false === $this->shoppingOrderOptionObjectArray ) {
			$this->shoppingOrderOptionObjectArray	= array();
		} else {
		}
		// 添付ファイルの読み込み
		if( $this->loadRelatedFiles( $dbo ) === false ) { return false; }
	}
	/**
	 * インサート前に行いたい処理
	 * @param MDBObject $dbo MDB2オブジェクトかその互換オブジェクト
	 * @return boolean 成功したらtrue
	 */
	function pre_insert( $dbo ) {
		return true;
	}
	/**
	 * インサート後に行いたい処理
	 * @param MDBObject $dbo MDB2オブジェクトかその互換オブジェクト
	 * @return boolean 成功したらtrue
	 */
	function post_insert( $dbo ) {
		// 紐づいた注文オプション情報をインサート
		if( is_array($this->shoppingOrderOptionObjectArray) ) {
			foreach( $this->shoppingOrderOptionObjectArray as $optionNum => $shoppingOrderOptionObject ) {
				$this->shoppingOrderOptionObjectArray[$optionNum]->order_id		= $this->order_id;
				$this->shoppingOrderOptionObjectArray[$optionNum]->item_id		= $this->item_id;
				$this->shoppingOrderOptionObjectArray[$optionNum]->item_order	= $optionNum;
				if($dbo->insert( $this->shoppingOrderOptionObjectArray[$optionNum] )) {
				} else if( is_object($dbo->request) ) {
					$dbo->request->addLocaledError('database2.error.insert',SPIDER_LOG_LEVEL_FATAL,array(''));
				}
			}
		}
		if( is_object($dbo->request) && $dbo->request->isError() ) {
			return false;
		} else {
			return true;
		}
	}
	/**
	 * アップデート前に行いたい処理
	 * @param MDBObject $dbo MDB2オブジェクトかその互換オブジェクト
	 * @return boolean 成功したらtrue
	 */
	function pre_update( $dbo ) {
		return true;
	}
	/**
	 * 注文単位オブジェクトを取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function getUnitObject( & $request ) {
		$dbo	= $request->getAttribute( 'dbo' );
		if( is_null($dbo) ) {
			$request->addLocaledError('database2.error.connect',SPIDER_LOG_LEVEL_ERROR,array());
			return false;
		} else if( strlen($this->unit_id) == 0 ) {
			$request->addLocaledError('shopping.error.product.notfound',SPIDER_LOG_LEVEL_ERROR,array(''));
			return false;
		} else {
			if( is_null($this->usedUnitObject) && strlen($this->used_unit_id) > 0 ) {
				$this->usedUnitObject	= spider_Controller::createObject('shopping_DaoShoppingProductUnit');
				if( $dbo->loadById( $this->usedUnitObject, $this->used_unit_id, true, array('registered_date','updated_date'), false, false ) ) {
				} else {
					$this->usedUnitObject	= null;
				}
			}
			if( is_null($this->shoppingProductUnitObject) ) {
				$this->shoppingProductUnitObject	= spider_Controller::createObject('shopping_DaoShoppingProductUnit');
				if( $dbo->loadById( $this->shoppingProductUnitObject, $this->unit_id, true, array('registered_date','updated_date'), false, false ) ) {
					$productUnitObject	= & $this->shoppingProductUnitObject;
					return $productUnitObject;
				} else {
					$this->shoppingProductUnitObject	= null;
					$request->addLocaledError('shopping.error.product.notfound',SPIDER_LOG_LEVEL_ERROR,array(''));
					return false;
				}
			} else {
				$productUnitObject	= & $this->shoppingProductUnitObject;
				return $productUnitObject;
			}
		}
	}
	/*
	 * この注文アイテムの注文が現在のカートに追加可能な配送種別か確認
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @param $shoppingOrderObject shopping_DaoShoppingOrderオブジェクト参照
	 */
	function confirmDeliveryType( & $request, & $shoppingOrderObject ) {
		// 配送種別配列
		$deliveryTypeArray			= $shoppingOrderObject->getDeliveryTypeArray( $request );
		$shoppingProductUnitObject	= $this->getUnitObject( $request );
		if( !is_object($shoppingProductUnitObject) ) {
			return false;
		} else {
			return true;
		}
	}
	/**
	 * この注文アイテムに関してデータベース上から在庫を消化します
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function useUnitStock( & $request ) {
		$dbo	= $request->getAttribute( 'dbo' );
		$shoppingProductUnitObject	= $this->getUnitObject( $request );
		if( is_null($dbo) ) {
			$request->addLocaledError('database2.error.connect',SPIDER_LOG_LEVEL_ERROR,array());
			return false;
		} else if( is_null($shoppingProductUnitObject) ) {
			$request->addLocaledError('database2.error.connect',SPIDER_LOG_LEVEL_ERROR,array());
			return false;
		} else {
			return $shoppingProductUnitObject->useStock(
			$request,$this->order_count,$this->item_id,$this->svc_start_date,$this->svc_limit_date);
		}
	}
	/**
	 * 配送目安の合計値を取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function getTotalDeliveryWeight( & $request ) {
		if( preg_match('/^[0-9]+$/',$this->delivery_weight) == 0 ) {
			$shoppingProductUnitObject	= $this->getUnitObject( $request );
			if( !is_object($shoppingProductUnitObject) ) {
				$request->addLocaledError('shopping.error.product.notfound',SPIDER_LOG_LEVEL_ERROR,array(''));
				return false;
			} else {
				$this->delivery_weight	= $shoppingProductUnitObject->delivery_weight;
			}
		}
		return $this->delivery_weight * $this->order_count;
	}
	/**
	 * 現在の商品販売単位情報を取得して金額を再計算します
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function calculate( & $request, $renew=false ) {
		if( $renew ) {
//			$this->price_unit		= 0;	// 商品販売単価(注文時)
			$this->cost_unit		= 0;	// 商品仕入単価(注文時)
			$this->point_unit		= 0;	// 商品付与ポイント(注文時)
			$this->delivery_weight	= null;	// 商品配送目安値(注文時)
			$this->delivery_type	= null;	// 商品配送種別(注文時)
			$shoppingProductUnitObject	= $this->getUnitObject( $request );
			if( !is_object($shoppingProductUnitObject) ) {
				$request->addLocaledError('shopping.error.product.notfound',SPIDER_LOG_LEVEL_ERROR,array(''));
				return false;
			}
			// 商品自体の合計金額
			if( -1 == $this->price_unit ) {
				$this->price_unit	= $shoppingProductUnitObject->getPriceSell($request);
			}
			$this->cost_unit			= $shoppingProductUnitObject->cost;
			$this->point_unit			= $shoppingProductUnitObject->present_point;
			if( strlen($this->point_unit) == 0 ) {
				$this->point_unit	= 0;
			}
			$this->delivery_weight		= $shoppingProductUnitObject->delivery_weight;
			$this->delivery_type		= $shoppingProductUnitObject->delivery_type;
			$this->discount_exception	= $shoppingProductUnitObject->discount_exception;
		}
		// 注文オプションの合計金額
		if( is_array($this->shoppingOrderOptionObjectArray) ) {
			foreach( $this->shoppingOrderOptionObjectArray as $num => $orderOptionObject ) {
				$this->shoppingOrderOptionObjectArray[$num]->order_count	= $this->order_count;
				$this->shoppingOrderOptionObjectArray[$num]->calculate( $request, $renew );
			}
		}
		return true;
	}
	/**
	 * この注文商品に紐づいた支払合計金額を取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function getTotalPaymentPrice( & $request ) {
		return $this->getTotalUnitPrice( $request )
			+ $this->getTotalOptionPrice( $request );
	}
	/**
	 * この注文単位商品に紐づいた商品金額合計金額を取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function getTotalUnitPrice( & $request ) {
		// 予約商品の場合は種別によって計算を変更
		$productUnitObject	= $this->getUnitObject( $request );
		if( 900 == $productUnitObject->delivery_type
		|| 1700 == $productUnitObject->delivery_type ) {
			// 宿泊予約の場合は日ごとに設定されている金額があればその金額の和
			$totalPrice	= 0;
			for( $time=strtotime($this->svc_start_date); $time<strtotime($this->svc_limit_date); $time = $time + (60*60*24) ) {
				// 開始予定日から1日ずつ進めて金額を確認
				$sDate	= date('Y-m-d H:i:s',$time);
				$totalPrice	+= $productUnitObject->getPriceSell( $request, $sDate ) * $this->order_count;
			}
			return $totalPrice;
		} else if( 200 == $productUnitObject->delivery_type
		|| 1000 == $productUnitObject->delivery_type ) {
			// 時間予約の場合も日ごとに設定されている金額があればその和で計算
			$totalPrice	= 0;
			$termSec	= 60*60;
			if( preg_match('/^[0-9]{1,8}$/',$productUnitObject->service_term) > 0 ) {
				$termSec	= $productUnitObject->service_term;
			} else if( 200 < $productUnitObject->delivery_type ) {
				$termSec	= ($productUnitObject->delivery_type - 200) * 60;
			}
			for( $time=strtotime($this->svc_start_date); $time<strtotime($this->svc_limit_date); $time = $time + $termSec ) {
				// 開始予定日から予約時簡単にずつ進めて金額を確認
				$sDate	= date('Y-m-d H:i:s',$time);
				$totalPrice	+= $productUnitObject->getPriceSell( $request, $sDate ) * $this->order_count;
			}
			return $totalPrice;
		} else {
			// その他通常商品の場合
			return $this->price_unit * $this->order_count;
		}
	}
	/**
	 * この注文単位商品の合計コストを取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function getTotalCost( & $request ) {
		return $this->getTotalUnitCost( $request )
			+ $this->getTotalOptionCost( $request );
	}
	/**
	 * この注文単位商品に紐づいた注文商品の卸金額合計を取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function getTotalUnitCost( & $request ) {
		// 予約商品の場合は種別によって計算を変更
		$productUnitObject	= $this->getUnitObject( $request );
		if( 900 == $productUnitObject->delivery_type || 1700 == $productUnitObject->delivery_type ) {
			// 宿泊予約の場合
			return $this->cost_unit * $this->order_count * $this->getServiceDays( $request );
		} else if( 200 <= $productUnitObject->delivery_type ) {
			// 時間予約の場合
			$per	= 60;
			if( preg_match('/^[0-9]{1,8}$/',$productUnitObject->service_term) > 0 ) {
				$per	= floor($productUnitObject->service_term / 60);
			} else if( 200 < $productUnitObject->delivery_type ) {
				$per	= ($productUnitObject->delivery_type - 200);
			}
			$cnt	= ceil($this->getServiceMinutes( $request )/$per);
			return $this->cost_unit * $this->order_count * $cnt;
		} else {
			// その他通常商品の場合
			return $this->cost_unit * $this->order_count;
		}
	}
	/**
	 * この注文単位商品に紐づいた注文商品の付与ポイント合計を取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function getTotalPoint( & $request ) {
		// 予約商品の場合は種別によって計算を変更
		$productUnitObject	= $this->getUnitObject( $request );
		if( 900 == $productUnitObject->delivery_type || 1700 == $productUnitObject->delivery_type ) {
			// 宿泊予約の場合
			return $this->point_unit * $this->order_count * $this->getServiceDays( $request );
		} else if( 200 <= $productUnitObject->delivery_type ) {
			// 時間予約の場合
			$per	= 60;
			if( preg_match('/^[0-9]{1,8}$/',$productUnitObject->service_term) > 0 ) {
				$per	= floor($productUnitObject->service_term / 60);
			} else if( 200 < $productUnitObject->delivery_type ) {
				$per	= ($productUnitObject->delivery_type - 200);
			}
			$cnt	= ceil($this->getServiceMinutes( $request )/$per);
			return $this->point_unit * $this->order_count * $cnt;
		} else {
			// その他通常商品の場合
			return $this->point_unit * $this->order_count;
		}
	}
	/**
	 * 注文商品のオプション金額合計を取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function getTotalOptionPrice( & $request ) {
		$uncountPrice	= 0;	// 注文数で変動しない金額
		$encountPrice	= 0;	// 注文数で変動する金額
		if( is_array($this->shoppingOrderOptionObjectArray) ) {
			foreach( $this->shoppingOrderOptionObjectArray as $num => $orderOptionObject ) {
				if( $orderOptionObject->calculate_flag == 1 ){
					$uncountPrice	+= $orderOptionObject->option_price;
				} else {
					$encountPrice	+= $orderOptionObject->option_price;
				}
			}
		}
		// 予約商品の場合は種別によって計算を変更
		$productUnitObject	= $this->getUnitObject( $request );
		if( 900 == $productUnitObject->delivery_type || 1700 == $productUnitObject->delivery_type ) {
			// 宿泊予約の場合
			$encountPrice	= $encountPrice * $this->getServiceDays( $request );
		} else if( 200 == $productUnitObject->delivery_type || 1000 == $productUnitObject->delivery_type ) {
			// 時間予約の場合
			$per	= 60;
			if( preg_match('/^[0-9]{1,8}$/',$productUnitObject->service_term) > 0 ) {
				$per	= floor($productUnitObject->service_term / 60);
			} else if( 200 < $productUnitObject->delivery_type ) {
				$per	= ($productUnitObject->delivery_type - 200);
			}
			$cnt	= ceil($this->getServiceMinutes( $request )/$per);
			$encountPrice	= $encountPrice * $cnt;
		} else {
			// その他通常商品の場合
			$encountPrice	= $encountPrice * $this->order_count;
		}
		$encountPrice	= ceil($encountPrice);
		return $encountPrice + $uncountPrice;
	}
	/**
	 * 注文商品のオプションコスト合計を取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function getTotalOptionCost( & $request ) {
		// 合計金額を計算
		$totalPrice	= 0;
		if( is_array($this->shoppingOrderOptionObjectArray) ) {
			foreach( $this->shoppingOrderOptionObjectArray as $num => $orderOptionObject ) {
				$totalPrice	+= $orderOptionObject->option_cost;
			}
		}
		// 予約商品の場合は種別によって計算を変更
		$productUnitObject	= $this->getUnitObject( $request );
		if( 900 == $productUnitObject->delivery_type || 1700 == $productUnitObject->delivery_type ) {
			// 宿泊予約の場合
			$totalPrice	= $totalPrice * $this->getServiceDays( $request );
		} else if( 200 == $productUnitObject->delivery_type || 1000 == $productUnitObject->delivery_type ) {
			// 時間予約の場合
			$per	= 60;
			if( preg_match('/^[0-9]{1,8}$/',$productUnitObject->service_term) > 0 ) {
				$per	= floor($productUnitObject->service_term / 60);
			} else if( 200 < $productUnitObject->delivery_type ) {
				$per	= ($productUnitObject->delivery_type - 200);
			}
			$cnt	= ceil($this->getServiceMinutes( $request )/$per);
			$totalPrice	= $totalPrice * $cnt;
		} else {
			// その他通常商品の場合
			$totalPrice	= $this->price_unit * $this->order_count;
		}
		$totalPrice	= ceil($totalPrice);
		return $totalPrice;
	}
	/**
	 * この宛先に紐づいた購入情報の指定率の金額を計算して取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @param $rate int 割合
	 * @param $includeExceptions boolean 割引除外商品を含めるならtrue
	 * @param $includeOptions boolean オプション金額を含めるならtrue
	 * @param $roundMethod int 0=切り捨て, 1=切り上げ, 2=四捨五入, 3=五捨六入
	 * @param $denominator 分母（デフォルト100)
	 * @return int 金額
	 */
	function calculatePriceRate( & $request, $rate=5, $includeExceptions=false, $includeOptions=false, $roundMethod=0, $denominator=100 ) {
		$price	= 0;
		if( $this->discount_exception != '1' || $includeExceptions ) {
			$price	= ( $this->price_unit * $rate / $denominator );
			// 金額丸め方法に従い丸める
			$price	= shopping_PackageConfig::_roundNumeric($price, $roundMethod);
			// 注文数で乗算
			$price	= $price * $this->order_count;
		}
		// オプション計算
		if( $includeOptions ) {
			if( is_array($this->shoppingOrderOptionObjectArray) ) {
				foreach( $this->shoppingOrderOptionObjectArray as $num => $orderOptionObject ) {
					$this->shoppingOrderOptionObjectArray[$num]->order_count	= $this->order_count;
					$price	+= $this->shoppingOrderOptionObjectArray[$num]->calculatePriceRate( $request, $rate, $roundMethod, $denominator );
				}
			}
		}
		return $price;
	}
	/**
	 * 注文商品情報メール送信用文字列を注文内容に変換した文字列を取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @param $shoppingOrderObject shopping_DaoShoppingOrderオブジェクト
	 * @param $targetAddress 送信先メールアドレス
	 * @param $infoType wholesale/other
	 * @return string 変換後文字列
	 */
	function getMailStrings( & $request, $shoppingOrderObject, $targetAddress, $infoType=null, $searchDataObject=null ) {
		// フォーマット決定
		$formatName	= 'SHOPMAILSUBITEMP';
		if( 'wholesale' == $infoType ) {
			$formatName	= 'SHOPMAILSUBITEMA';
		}
		$itemFormatHash	= shopping_PackageConfig::getMailTemplateInformation( $request, $formatName, $targetAddress );
		if( false === $itemFormatHash ) {
			return false;
		}
		$itemFormat	= $itemFormatHash['strings'];
		// 商品と販売単位の情報読み込み
		$dbo	= $request->getAttribute( 'dbo' );
		$shoppingProductUnitObject	= $this->getUnitObject( $request );
		if( !is_object($shoppingProductUnitObject) ) {
			$request->addLocaledError('shopping.error.product.notfound',SPIDER_LOG_LEVEL_ERROR,array(''));
			return false;
		}
		$shoppingProductObject	= & $shoppingProductUnitObject->shoppingProductObject;
		if( is_null($shoppingProductObject) ) {
			if( $dbo->loadById($shoppingProductUnitObject->shoppingProductObject,
			$shoppingProductUnitObject->product_id,false) ) {
				$shoppingProductObject	= & $shoppingProductUnitObject->shoppingProductObject;
			} else {
				$request->addLocaledError('shopping.error.product.notfound',SPIDER_LOG_LEVEL_ERROR,array(''));
				return false;
			}
		}
		// ダウンロードURL
		$downloadUrl	= '';
		if( $shoppingProductUnitObject->delivery_type == 11 && defined('SHOPPING_DOWNLOAD_URL') ) {
			$downloadUrl	= SHOPPING_DOWNLOAD_URL;
			if( strpos($downloadUrl,'?') === false ) {
				$downloadUrl	.= '?';
			} else {
				$downloadUrl	.= '&';
			}
			$downloadUrl	.= 'shpoid='.urlencode($shoppingOrderObject->order_id)
				.'&shppid='.urlencode($shoppingOrderObject->member_id)
				.'&shppokey='.urlencode($shoppingOrderObject->order_key)
				.'&shpui='.urlencode($this->unit_id);
		}
		//関連検索データがある場合
		$shoppingProductObject->loadSearchData( $request );
		//
		$this->service_days	= $this->getServiceDays( $request );
		// 置換処理
		$replaceHash	= array(
		'unit_id'			=> $this->unit_id,
		'order_count'		=> $this->order_count,
		'price_unit'		=> $this->price_unit,
		'cost_unit'			=> $this->cost_unit,
		'point_unit'		=> $this->point_unit,
		'item_unit_price'		=> $this->getTotalUnitPrice($request),
		'item_cost_unit'		=> $this->getTotalUnitCost($request),
		'item_payment_total'	=> $this->getTotalPaymentPrice($request),
		'item_cost_total'		=> $this->getTotalCost($request),
		// 注文情報 @depricated 下位互換
		'unit_price_total'	=> $this->getTotalUnitPrice($request),
		'unit_cost_total'	=> $this->getTotalUnitCost($request),
		'payment_price'		=> $this->getTotalUnitPrice($request),
		'unit_price'		=> $this->price_unit,
		'unit_cost'			=> $this->cost_unit,
		// 販売単位情報置換
		'unit_name'		=> $shoppingProductUnitObject->unit_name,
		'unit_kana'		=> $shoppingProductUnitObject->unit_kana,
		// 商品情報置換
		'product_id'		=> $shoppingProductObject->product_id,
		'product_name'		=> $shoppingProductObject->product_name,
		'product_kana'		=> $shoppingProductObject->product_kana,
		// 付加情報
		'download_url'		=> $downloadUrl,
		// 商品個別配送先は仕様から削除
		'unit_address_strings'	=> '',
		// サービス日時関連
		'checkin_date'		=> date('Y年m月d日',strtotime($this->svc_start_date)),
		'checkout_date'		=> date('Y年m月d日',strtotime($this->svc_limit_date)),
		'checkin_time'		=> date('H:i:s',strtotime($this->svc_start_date)),
		'checkout_time'		=> date('H:i:s',strtotime($this->svc_limit_date)),
		'service_days'		=> $this->service_days,
		// 商品タイプ
		'is_stay_reserve'	=> ( $this->delivery_type==900 ? 1 : '' ),
		'is_stay_option'	=> ( $this->delivery_type==1700 ? 1 : '' ),
		'is_hour_reserve'	=> ( $this->delivery_type==200 ? 1 : '' ),
		'is_hour_option'	=> ( $this->delivery_type==1000 ? 1 : '' ),
		'search'	=> $searchDataObject,
		);
		spider_Controller::loadClassDefinition('util_Mail');
		$itemFormat	= util_Mail::replaceFormatStrings( $itemFormat, $replaceHash );
		
		// オプション文字列置換
		$optionStrings	= "\n";
		if( is_array($this->shoppingOrderOptionObjectArray) ) {
			$optionSFormat	= '';
			foreach( $this->shoppingOrderOptionObjectArray as $num => $orderOptionObject ) {
				$optionStrings	.= $orderOptionObject->getMailStrings( $request, $shoppingOrderObject, $targetAddress, $infoType, $searchDataObject );
			}
		}
		if( strlen(trim($optionStrings)) > 0 ) {
			$itemFormat	= str_replace('{option_strings}',$optionStrings,$itemFormat);
		} else {
			$itemFormat	= str_replace("{option_strings}\r\n",'',$itemFormat);
			$itemFormat	= str_replace("{option_strings}\r",'',$itemFormat);
			$itemFormat	= str_replace("{option_strings}\n",'',$itemFormat);
		}
		
		return $itemFormat;
	}
	//
	// 妥当性検査
	//
	/**
	 * フィールドデータの妥当性検査を実行します
	 * @param $request spider_HttpRequestオブジェクトインスタンス参照
	 */
	function validateFields( & $request ) {
		// エラーを一度クリア
		$this->clearColumnErrors();
		// 注文オプションの妥当性検査
		if( is_array($this->shoppingOrderOptionObjectArray) ) {
			foreach( $this->shoppingOrderOptionObjectArray as $key => $optionObject ) {
				$this->shoppingOrderOptionObjectArray[$key]->validateFields( $request );
			}
		}
	}
	//
	// 注文オプション関連
	//
	/**
	 * オプション入力が必要か確認
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @return オプション入力が必要ならtrue
	 */
	function hasOrderOption( & $request ) {
		$shoppingProductUnitObject	= $this->getUnitObject( $request );
		if( !is_object($shoppingProductUnitObject) ) {
			$request->addLocaledError('shopping.error.product.notfound',SPIDER_LOG_LEVEL_ERROR,array(''));
			return false;
		}
		return $shoppingProductUnitObject->hasOrderOption();
	}
	/**
	 * 本オブジェクトの設定から注文オプションオブジェクトの配列を取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @return array shopping_DaoShoppingOrderOption拡張実装クラスオブジェクトの配列
	 */
	function getOrderOptionObjectArray( & $request ) {
		// 商品と販売単位の情報読み込み
		$dbo	= $request->getAttribute( 'dbo' );
		$shoppingProductUnitObject	= $this->getUnitObject( $request );
		if( !is_object($shoppingProductUnitObject) ) {
			$request->addLocaledError('shopping.error.product.notfound',SPIDER_LOG_LEVEL_ERROR,array(''));
			return false;
		}
		$shoppingProductObject	= & $shoppingProductUnitObject->shoppingProductObject;
		if( is_null($shoppingProductObject) ) {
			if( $dbo->loadById($shoppingProductUnitObject->shoppingProductObject,
			$shoppingProductUnitObject->product_id,false) ) {
				$shoppingProductObject	= & $shoppingProductUnitObject->shoppingProductObject;
			} else {
				$request->addLocaledError('shopping.error.product.notfound',SPIDER_LOG_LEVEL_ERROR,array(''));
				return false;
			}
		}
		$orderOptionObjectArray	= $shoppingProductUnitObject->getOrderOptionObjectArray( $request );
		// 読み込み済みなら入力値を設定
		if( is_array($this->shoppingOrderOptionObjectArray) ) {
			foreach( $this->shoppingOrderOptionObjectArray as $num => $optionObject ) {
				if( isset($orderOptionObjectArray[$num]) && is_object($orderOptionObjectArray[$num]) ) {
					$orderOptionObjectArray[$num]->option_value	= $optionObject->option_value;
				}
			} 
		}
		return $orderOptionObjectArray;
	}
	/**
	 * カート追加時のPOST入力から販売単位注文オプションをセットします
	 * @param $request spider_HttpRequestオブジェクト参照
	 */
	function setOrderOptionOnCartPost( & $request ) {
		// 入力値は配列にする
		$optionNames	= $_POST['option_names'];
		$optionStrings	= $_POST['option_strings'];
		if( is_array($optionNames) ) {
		} else {
			$tmp	= $optionNames;
			$optionNames	= array($tmp);
		}
		if( is_array($optionStrings) ) {
		} else {
			$tmp	= $optionStrings;
			$optionStrings	= array($tmp);
		}
		$this->setOrderOption( $request, $optionNames, $optionStrings );
		foreach( $this->shoppingOrderOptionObjectArray as $key => $optionObject ){
			$this->shoppingOrderOptionObjectArray[$key]->required	= true;
			$this->shoppingOrderOptionObjectArray[$key]->validateFields( $request );
		}
	}
	/**
	 * オプション名とオプション入力値の配列で商品用注文オプションを設定
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @param $optionNames オプション名の配列
	 * @param $optionValues オプション入力値の配列
	 */
	function setOrderOption( & $request, $optionNames, $optionStrings ) {
		// 注文オプション
		$definedOptionObjectArray	= $this->getOrderOptionObjectArray( $request );
		$this->shoppingOrderOptionObjectArray	= array();
		// 名前入力があるものを全て取得
		foreach( $optionNames as $num => $optionName ) {
			$optionName 	= trim(stripslashes($optionName));
			$optionValue	= '';
			if( isset($optionStrings[$num]) ) {
				$optionValue	= trim(stripslashes($optionStrings[$num]));
				$optionValue	= str_replace("\r\n","\n",$optionValue);
				$optionValue	= str_replace("\r","\n",$optionValue);
			}
			if( strlen($optionValue) > 0 ) {
				if( strlen($optionName) == 0 ) {
					$tmpArray		= explode(':',$optionValue);
					$optionName		= array_shift($tmpArray);
					$optionValue	= implode(':',$tmpArray);
				}
			}
			if( strlen($optionName) > 0 ) {
				$isDefined	= false;
				if( is_array($definedOptionObjectArray) ) {
					foreach( $definedOptionObjectArray as $definedOptionObject ) {
						if( $definedOptionObject->option_name == $optionName ) {
							$isDefined	= true;
							$definedOptionObject->option_value	= $optionValue;
							$definedOptionObject->order_count	= $this->order_count;
							$definedOptionObject->validateFields( $request );
							array_push($this->shoppingOrderOptionObjectArray,$definedOptionObject);
							break;
						}
					}
				}
				if( !$isDefined ) {
					$shoppingOrderOptionObject	= spider_Controller::createObject('shopping_DaoShoppingOrderOption');
					$shoppingOrderOptionObject->option_name		= $optionName;
					$shoppingOrderOptionObject->item_order		= $num;
					$shoppingOrderOptionObject->option_value	= $optionValue;
					$shoppingOrderOptionObject->order_count	= $this->order_count;
					array_push($this->shoppingOrderOptionObjectArray,$shoppingOrderOptionObject);
				}
			}
		}
	}
	/**
	 * サービス単位のカウントを取得します
	 */
	function getServiceCount( & $request ){
		if(900==$this->delivery_type||1700==$this->delivery_type){
			return $this->getServiceDays($request);
		} else if(200==$this->delivery_type||1000==$this->delivery_type){
			$unitObject	= $this->getUnitObject( $request );
			$termSec		= $unitObject->service_term;
			$serviceSec	= $this->getServiceSec($request);
			if( false === $serviceSec ){
				return false;
			} else {
				if( $termSec <= 0 ){
					return ceil($serviceSec/(60*60));
				} else {
					return ceil($serviceSec/$termSec);
				}
			}
		}else{
			return 1;
		}
	}
	/**
	 * サービス開始日と終了日の差分を日数で返します
	 * 端数は切り上げます
	 */
	function getServiceDays( & $request ) {
		if( $min = $this->getServiceHours( $request ) ) {
			return ceil($min/24);
		} else {
			return false;
		}
	}
	/**
	 * サービス開始日と終了日の差分を時間で返します
	 * 端数は切り上げます
	 */
	function getServiceHours( & $request ) {
		if( $min = $this->getServiceMinutes( $request ) ) {
			return ceil($min/60);
		} else {
			return false;
		}
	}
	/**
	 * サービス開始日と終了日の差分を分で返します
	 */
	function getServiceMinutes( & $request ) {
		if( $sec = $this->getServiceSec( $request ) ) {
			return ($sec/60);
		} else {
			return false;
		}
	}
	/**
	 * サービス開始日と終了日の差分を秒で返します
	 */
	function getServiceSec( & $request ) {
		spider_Controller::loadClassDefinition('util_ValidateFunctions');
		if( util_ValidateFunctions::isAvailableDatetimeFormat($this->svc_start_date)
		&& util_ValidateFunctions::isAvailableDatetimeFormat($this->svc_limit_date) ) {
			// 開始と終了の日付のフォーマットが正しいなら計算
			$sec	= strtotime($this->svc_limit_date) - strtotime($this->svc_start_date);
			return $sec;
		} else {
			return false;
		}
	}
	/**
	 * CSVダウンロードの為のカラム取得メソッド
	 * 項目キーから値を取得します
	 */
	function getColumnString( $key, $quote=true, $filter=null ) {
		$returnColumn	= $this->$key;
		$returnStrings	= '';
		if( is_array($returnColumn) ) {
			$returnStrings	= implode(',',$returnColumn);
		} else {
			if ( $key=='unit_name' ) {
				// 注文単位商品名
				$returnStrings	= $this->shoppingProductUnitObject->unit_name;
			} else if ( $key=='total_unit_price' ) {
				// 注文単位商品に紐づいた商品金額合計金額
				$returnStrings	= $this->price_unit * $this->order_count;
			} 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オブジェクト参照
	 * @return string アップロードフォルダパス文字列
	 */
	function getUploadDirPath( & $request, $createDir=false ) {
		$saveRoot	= null;
		if( defined('SHOPPING_ORDER_ITEM_FILE_ROOT')
		&& strlen(SHOPPING_ORDER_ITEM_FILE_ROOT) > 0 ) {
			$saveRoot	= str_replace(DIRECTORY_SEPARATOR,'/',SHOPPING_ORDER_ITEM_FILE_ROOT);
		} else {
			$request->addLocaledError('system.error.common.noinstalled',SPIDER_LOG_LEVEL_FATAL,array(''));
			return false;
		}
		$savePath	= $saveRoot.'/'.$this->order_id.'/'.$this->item_id;
		if( !file_exists($savePath) && $createDir ) {
			$dirNameArray	= explode('/',$savePath);
			$dirPath		= '';
			if( strpos($savePath,'/') === 0 ) {
				$dirPath		= '/'.array_shift($dirNameArray);
			} else {
				$dirPath		= array_shift($dirNameArray);
			}
			foreach( $dirNameArray as $dirName ) {
				if( strlen($dirName) > 0 ) {
					$dirPath	.= '/'.$dirName;
					if( !file_exists($dirPath) ) {
						if( @mkdir($dirPath,0777) ) {
							@chmod($dirPath,0777);
						} else {
							$request->addLocaledError('system.error.writer.failtomkdir',SPIDER_LOG_LEVEL_FATAL,array(''));
							return false;
						}
					}
				}
			}
		}
		return $savePath;
	}
	/**
	 * アップロードファイルディレクトリを取得します
	 */
	function getUploadFilePath( & $request, $orderNumber ) {
		$upDir	= $this->getUploadDirPath( $request );
		if (is_dir($upDir)) {
			$fileRegx	= '/^file\\_'.sprintf('%02d',$orderNumber).'/';
			if( $upDirH = @opendir($upDir) ) {
				while (($fileName = readdir($upDirH)) !== false) {
					if( preg_match($fileRegx,$fileName) > 0 ) {
						return $upDir.'/'.$fileName;
					}
				}
				return false;
			} else {
				return false;
			}
		} 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_ITEM_HASH']	= array(
			'unit_id'	=>'施設ID',
			'price_unit'	=>'単価',
			'cost_unit'	=>'コスト単価',
			'point_unit'	=>'付与ポイント',
			'delivery_type'	=>'商品種別',
			'delivery_weight'	=>'配送目安値',
			'discount_exception'	=>'割引除外フラグ',
			'order_count'	=>	$GLOBALS['SHOPPING_LABEL_ORDER'].'数',
			'svc_start_date'	=>'チェックイン日時',
			'svc_limit_date'	=>'チェックアウト日時',
			'used_unit_id'	=>'実利用'.$GLOBALS['SHOPPING_LABEL_PRODUCT'].'ID',
			'shoppingOrderOptionObjectArray'	=>'固有オプション情報',
		);
		foreach( $defferenceHash as $key => $val ){
			if( array_key_exists($key,$GLOBALS['SHOPPING_DEFFERENCE_ORDER_ITEM_HASH']) ){
				$newKey	= $GLOBALS['SHOPPING_DEFFERENCE_ORDER_ITEM_HASH'][$key];
				$newDefferenceHash[$newKey]	= $val;
			}
		}
		return $newDefferenceHash;
	}
}
?>