<?php
/*
 * shopping/DaoShoppingProductUnit.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_DaoShoppingProductUnit
 * shoppingパッケージ データアクセスオブジェクトクラス shopping_product_unitテーブル用
 */
class shopping_DaoShoppingProductUnit extends database2_AbstractData {
	/** シリアル番号	*/
	var $unit_number;
	/** 販売単位ID	*/
	var $unit_id;
	/** 商品ID	*/
	var $product_id;
	/** 購入時要求販売単位ID	*/
	var $require_unit_id;
	/** 販売単位名	*/
	var $unit_name;
	/** 販売単位名フリガナ	*/
	var $unit_kana;
	/** 表記カウント単位	*/
	var $unit_string;
	/** 公開設定:閲覧	*/
	var $member_viewable	= -1;
	/** 公開設定:購入	*/
	var $member_purchasable		= -1;
	/** 標準・希望小売価格(税込)	*/
	var $price_standard	= 0;
	/** 販売価格(税込)	*/
	var $price_sell		= 0;
	/** コスト・仕入れ値	*/
	var $cost			= 0;
	/** 月次課金価格(税込)	*/
	var $price_monthly = 0;
	/** ウェブ用在庫数	0=在庫なし, 正の数=在庫数, -1=在庫無制限, -2=最小在庫連動, -3=最大在庫連動, -4=合計在庫連動	*/
	var $stock			= 0;
	/** 在庫連動販売単位ID(/区切り)	*/
	var $stock_relation	= null;
	/** 在庫連動注文カウント数	*/
	var $stock_relation_count	= 1;
	/** 表示在庫数	0=在庫なし, 正の数=在庫数, -1=在庫無制限	*/
	var $stock_display;
	/** 順序番号	*/
	var $order_number	= 100;
	/** 割引除外フラグ 割引対象外とするなら0以外に設定	*/
	var $discount_exception	= 0;
	/** 購入時のポイント数	*/
	var $present_point		= 0;
	/** 概要説明	*/
	var $description;
	/** 詳細コメント	*/
	var $detail_comment;
	/** オプション1選択名	*/
	var $option1_name;
	/** オプション1選択肢	*/
	var $option1_items;
	/** オプション1説明文 */
	var $option1_explanation;
	/** オプション1説明ＵＲＬ	*/
	var $option1_url;
	/** オプション1計算方法	*/
	var $option1_calculate	= 0;
	/** オプション2選択名	*/
	var $option2_name;
	/** オプション2選択肢	*/
	var $option2_items;
	/** オプション2説明文 */
	var $option2_explanation;
	/** オプション2説明ＵＲＬ	*/
	var $option2_url;
	/** オプション2計算方法	*/
	var $option2_calculate	= 0;
	/** オプション3選択名	*/
	var $option3_name;
	/** オプション3選択肢	*/
	var $option3_items;
	/** オプション3説明文 */
	var $option3_explanation;
	/** オプション3説明ＵＲＬ	*/
	var $option3_url;
	/** オプション3計算方法	*/
	var $option3_calculate	= 0;
	/** オプション4選択名	*/
	var $option4_name;
	/** オプション4選択肢	*/
	var $option4_items;
	/** オプション4説明文 */
	var $option4_explanation;
	/** オプション4説明ＵＲＬ	*/
	var $option4_url;
	/** オプション4計算方法	*/
	var $option4_calculate	= 0;
	/** オプション5選択名	*/
	var $option5_name;
	/** オプション5選択肢*/
	var $option5_items;
	/** オプション5説明文 */
	var $option5_explanation;
	/** オプション5説明ＵＲＬ	*/
	var $option5_url;
	/** オプション5計算方法	*/
	var $option5_calculate	= 0;
	/** 配送種別: 0=通常便, 1=クール便, 11=ダウンロードメディア	*/
	var $delivery_type	= 0;
	/** 梱包目安値：サイズも考慮して設定する。	*/
	var $delivery_weight	= 1;
	/** 状態フラグ	*/
	var $status_flag	= 101;
	/** 公開開始日時	*/
	var $open_date;
	/** 公開終了日時	*/
	var $close_date;
	/** 最大同時注文数	*/
	var $max_at_once;
	/** 予約許可： 開始日（当日を基準とした営業日数で設定：xx営業日後から）	*/
	var $rsv_permit_start;
	/** 予約許可： 制限日（当日を基準とした営業日数で設定：xx営業日後まで）	*/
	var $rsv_permit_limit;
	/** サービス開始標準時間: 現状宿泊予約のみで利用（チェックイン時間）	*/
	var $default_start_time;
	/** サービス提供期間: 秒数で入力。1時間なら3600	*/
	var $service_term	= 0;
	/** カレンダータイプ	*/
	var $calendar_type	= 1;
	/** 更新日	*/
	var $updated_date;
	/** 登録日	*/
	var $registered_date;
	/** 登録者ID	*/
	var $owner_id;
	/** 変更者ＩＤ	*/
	var $modifier_id;
	/** オブジェクト拡張：商品オブジェクト	*/
	var $shoppingProductObject;
	/** オブジェクト拡張：公開対象配列	*/
	var $openTargetArray	= array();
	/** オブジェクト拡張：ファイル配列	*/
	var $fileIdArray		= array();
	/** オブジェクト拡張：フラグオブジェクト配列	*/
	var $flagIdArray		= array();
	var $flagObjectHash		= array();

	/** オブジェクト拡張：公開設定(閲覧)ハッシュ	*/
	var $memberViewableArray	= array();
	/** オブジェクト拡張：公開設定(購入)ハッシュ	*/
	var $memberPurchasableArray	= array();
	/** オブジェクト拡張：在庫連動販売単位ＩＤ配列	*/
	var $stockRelationArray		= array();
	/** オブジェクト拡張：表示用在庫数	*/
	var $stock_view		= 0;

	/**
	 * コンストラクタ
	 */
	function shopping_DaoShoppingProductUnit(){
		$this->shoppingProductObject	= null;
		$this->openTargetArray		= array();
		$this->fileIdArray			= array();
		$this->fileIdArray_org		= array();
		$this->flagIdArray			= array();
		$this->flagIdArray_org		= array();
		$this->flagObjectHash		= array();
		$this->stockRelationArray	= array();
	}
	/**
	 * 在庫数を取得します
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスインスタンス参照
	 * @param datetime $serviceStartDate 開始時間（予約の場合のみ指定可能）
	 * @param datetime $serviceLimitDate 終了時間（予約の場合のみ指定可能）
	 * @param string $exceptOrderItemId 除外注文項目ID（予約の場合のみ指定可能）
	 * @return int 在庫数
	 * @access public
	 */
	function getStock( & $request, $serviceStartDate=null, $serviceLimitDate=null, $exceptOrderItemId=null, $exceptOrderId=null ) {
		$dbo	= $request->getAttribute( 'dbo' );
		if( is_null($dbo) ) {
			$request->addLocaledError('database2.error.noconnect',SPIDER_LOG_LEVEL_FATAL,array(''));
			return false;
		}
		if( -1 > $this->stock ){
			// 在庫連動商品の場合
			$resultCount	= 0;
			$sql	= 'SELECT * FROM '.TABLE_NAME_SHOPPING_PRODUCT_UNIT
			.' WHERE '.TABLE_NAME_SHOPPING_PRODUCT_UNIT.'.unit_id IN (\''.implode('\',\'',$this->stockRelationArray).'\')';
			$relatedUnitObject	= spider_Controller::createObject('shopping_DaoShoppingProductUnit');
			$relatedUnitObjectArray	= $dbo->queryAll($sql,$relatedUnitObject,false);
			if( false === $relatedUnitObjectArray ) {
				$request->addLocaledError('shopping.error.product.notfound',SPIDER_LOG_LEVEL_ERROR,array(''));
				return false;
			} else {
				// 設定されている在庫数の確認
				foreach( $relatedUnitObjectArray as $relatedUnitObject ) {
					$relatedUnitObject->optimizeLoadedVars($dbo);
					$targetStock = $relatedUnitObject->getStock($request,$serviceStartDate,$serviceLimitDate,$exceptOrderItemId,$exceptOrderId);
					if( false !== $targetStock ){
						if( -4 == $this->stock ){
							// 合計在庫なら合算
							$resultCount	+= $targetStock;
						} else if( -3 == $this->stock ){
							// 最大在庫ならMax
							if( $resultCount < $targetStock ) {
								$resultCount	= $targetStock;
							}
						} else if( -2 == $this->stock ){
							// 最小在庫ならMin
							if( $resultCount > $targetStock ) {
								$resultCount	= $targetStock;
							}
						}
					} else {
						return false;
					}
				}
				// 関連付けで複数減らすなら対象の在庫消化数で割る
				if( preg_match('/^[0-9]{1,3}$/',$this->stock_relation_count) > 0 ) {
					$resultCount	= floor($resultCount/$this->stock_relation_count);
				}
				return $resultCount;
			}
		} else if( -1 == $this->stock ) {
			// 在庫無制限：常に999を戻す
			return 999;
		} else {
			// 0以上の場合
			if( strlen($serviceStartDate) > 0 && strlen($serviceLimitDate) > 0 ){
				// 開始・終了日時入力がある場合
				$startDateTime	= strtotime($serviceStartDate);
				$limitDateTime	= strtotime($serviceLimitDate);
				$startTimeStr		= date('H:i:s',$startDateTime);
				$limitTimeStr		= date('H:i:s',$limitDateTime);
				$maxUsedCount		= 0;
				// 最初に全ての日程が営業日か確認する
				if( 900 == $this->delivery_type || 1700 == $this->delivery_type ){
					// 宿泊予約の場合開始日0時から終了日前までの営業時間を確認
					$sql	= 'SELECT * FROM '.TABLE_NAME_SHOPPING_CALENDAR
					.' WHERE start_date>='.$dbo->quote(date('Y-m-d 00:00:00',$startDateTime))
					.' AND start_date<'.$dbo->quote(date('Y-m-d 00:00:00',strtotime($serviceLimitDate)));
					if( 1 == $this->calendar_type ){
						$sql	.= ' AND unit_id='.$dbo->quote($this->unit_id);
					} else if( 2 == $this->calendar_type ) {
						$sql	.= ' AND (unit_id IS NULL OR unit_id=\'\') AND product_id='.$dbo->quote($this->product_id);
					} else {
						$sql	.= ' AND (unit_id IS NULL OR unit_id=\'\') AND (product_id IS NULL OR product_id=\'\')';
					}
					$sql	.= ' ORDER BY start_date ASC, unit_id DESC, product_id DESC';
					$rowArray	= $dbo->queryAll($sql,'hash');
					if( false === $rowArray ){
						$request->addLocaledError('database2.error.common',SPIDER_LOG_LEVEL_FATAL,array($sql));
						return 0;
					} else {
						$prevDate	= null;
						$onServiceDayArray	= array();
						$onServiceDayHash		= array();
						foreach( $rowArray as $row ){
							$sDT	= $row['start_date'];
							$sD		= date('Y-m-d',strtotime($sDT));
							if( $sD == $prevDate ){
								// 日付が同じレコードは無視する
								continue;
							} else {
								$onServiceDayHash[$sD]	= $row['stock'];
							}
							$prevDate	= $sD;
						}
						$prevDate	= null;
						$maxUsedCount	= 0;
						$realStock		= $this->stock;
						foreach($onServiceDayHash as $sD => $sStock ){
							if( !is_null($prevDate) && strtotime($sD)-strtotime($prevDate) > (60*60*24) ){
								// 前日があって24時間以上の差分があるなら連続した営業日でないので在庫0
								$request->addLocaledError('shopping.error.cart.includeholiday',SPIDER_LOG_LEVEL_ERROR,array(''));
								return 0;
							}
							// 宿泊予約の場合は日ごとの稼働・利用状態を確認
							$targetStartDatetime	= $sD.' '.$this->default_start_time;
							$targetLimitDatetime	= date('Y-m-d '.$limitTimeStr,strtotime('+1 day',strtotime($targetStartDatetime)));
							$usedCount	= $this->getTimeOrderCount( $request, $targetStartDatetime, $targetLimitDatetime, $exceptOrderItemId, $exceptOrderId );
							if( false === $usedCount ) {
								return false;
							} else if( $usedCount > $maxUsedCount ){
								$maxUsedCount	= $usedCount;
							}
							// 日ごとの在庫設定がある場合は一番小さい在庫に設定
							if( strlen($sStock) > 0 && $realStock > $sStock ){
								$realStock	= $sStock;
							}
							$prevDate	= $sD;
						}
						return $realStock - $maxUsedCount;
					}
				} else if( 200 == $this->delivery_type || 1000 == $this->delivery_type ){
						// 時間予約の場合は開始時間を含む営業日程を確認
					$sql	= 'SELECT COUNT(*) FROM '.TABLE_NAME_SHOPPING_CALENDAR
					.' WHERE  start_date<='.$dbo->quote($serviceStartDate)
					.' AND close_date>='.$dbo->quote($serviceLimitDate);
					if( 1 == $this->calendar_type ){
						$sql	.= ' AND unit_id='.$dbo->quote($this->unit_id);
					} else if( 2 == $this->calendar_type ) {
						$sql	.= ' AND (unit_id IS NULL OR unit_id=\'\') AND product_id='.$dbo->quote($this->product_id);
					} else {
						$sql	.= ' AND (unit_id IS NULL OR unit_id=\'\') AND (product_id IS NULL OR product_id=\'\')';
					}
					$sql	.= ' ORDER BY start_date ASC, unit_id DESC, product_id DESC';
					$existCount	= $dbo->queryOne($sql);
					if( false === $existCount ){
						$request->addLocaledError('database2.error.common',SPIDER_LOG_LEVEL_FATAL,array($sql));
						return 0;
					} else if( 0 == $existCount ){
						$request->addLocaledError('shopping.error.cart.includeholiday',SPIDER_LOG_LEVEL_ERROR,array(''));
						return 0;
					} else {
						for( $targetTime = $startDateTime; $targetTime<$limitDateTime; $targetTime += $this->service_term ) {
							$targetStartDatetime	= date('Y-m-d H:i:s',$targetTime);
							$targetLimitDatetime	= date('Y-m-d H:i:s',$targetTime+$this->service_term);
							$usedCount	= $this->getTimeOrderCount( $request, $targetStartDatetime, $targetLimitDatetime, $exceptOrderItemId, $exceptOrderId );
							if( false === $usedCount ) {
								return false;
							} else if( $usedCount > $maxUsedCount ){
								$maxUsedCount	= $usedCount;
							}
						}
						return $this->stock - $maxUsedCount;
					}
				} else {
					return $this->stock;
				}
			} else {
				return $this->stock;
			}
		} 
	}
	/**
	 * 指定日時が営業か確認
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスインスタンス参照
	 * @param datetime $serviceStartDate 開始時間（予約の場合のみ指定可能）
	 * @param datetime $serviceLimitDate 終了時間（予約の場合のみ指定可能）
	 */
	function isOnService( & $request, $targetDatetime ){
		$dbo	= $request->getAttribute('dbo');
		// TODO 未実装
	}
	/**
	 * 指定時間のこのアイテムの注文数を取得します
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスインスタンス参照
	 * @param datetime $serviceStartDate 開始時間（予約の場合のみ指定可能）
	 * @param datetime $serviceLimitDate 終了時間（予約の場合のみ指定可能）
	 * @param string $exceptOrderItemId 除外注文項目ID（予約の場合のみ指定可能）
	 * @return int 在庫数
	 */
	function getTimeOrderCount( & $request, $serviceStartDate, $serviceLimitDate, $exceptOrderItemId=null, $exceptOrderId=null ) {
		$dbo	= $request->getAttribute( 'dbo' );
		if( is_null($dbo) ) {
			$request->addLocaledError('database2.error.noconnect',SPIDER_LOG_LEVEL_FATAL,array(''));
			return false;
		}
		$sql	= 'SELECT SUM('.TABLE_NAME_SHOPPING_ORDER_ITEM.'.order_count)'
		.' FROM '.TABLE_NAME_SHOPPING_ORDER_ITEM
		.' LEFT OUTER JOIN '.TABLE_NAME_SHOPPING_ORDER
		.' ON '.TABLE_NAME_SHOPPING_ORDER.'.order_id='.TABLE_NAME_SHOPPING_ORDER_ITEM.'.order_id'
		.' WHERE '.TABLE_NAME_SHOPPING_ORDER.'.status_flag<200'
		.' AND ( '.TABLE_NAME_SHOPPING_ORDER_ITEM.'.unit_id='.$dbo->quote($this->unit_id)
		.' OR '.TABLE_NAME_SHOPPING_ORDER_ITEM.'.used_unit_id='.$dbo->quote($this->unit_id).' )'
		.' AND ('.$dbo->quote($serviceStartDate).' BETWEEN '.TABLE_NAME_SHOPPING_ORDER_ITEM.'.svc_start_date AND '.TABLE_NAME_SHOPPING_ORDER_ITEM.'.svc_limit_date'
		.' OR '.$dbo->quote($serviceLimitDate).' BETWEEN '.TABLE_NAME_SHOPPING_ORDER_ITEM.'.svc_start_date AND '.TABLE_NAME_SHOPPING_ORDER_ITEM.'.svc_limit_date'
		.' )';
		if( !is_null($exceptOrderItemId) && strlen($exceptOrderItemId) > 0 ){
			$sql	.= ' AND '.TABLE_NAME_SHOPPING_ORDER_ITEM.'.item_id<>'.$dbo->quote($exceptOrderItemId);
		}
		if( !is_null($exceptOrderId) && strlen($exceptOrderId) > 0 ){
			$sql	.= ' AND '.TABLE_NAME_SHOPPING_ORDER_ITEM.'.order_id<>'.$dbo->quote($exceptOrderId);
		}
		$usedCount	= $dbo->queryOne($sql);
		if( false === $usedCount ) {
			$request->addLocaledError('database2.error.common',SPIDER_LOG_LEVEL_FATAL,array($sql));
			return false;
		} else {
			return $usedCount;
		}
	}
	/**
	 * 在庫を消化します
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスインスタンス参照
	 * @return boolean 成功したらtrue
	 * @access public
	 */
	function useStock( & $request, $useCount, $itemId=null, $serviceStartDate=null, $serviceLimitDate=null ) {
		$dbo	= $request->getAttribute( 'dbo' );
		if( is_null($dbo) ) {
			$request->addLocaledError('database2.error.noconnect',SPIDER_LOG_LEVEL_FATAL,array(''));
			return false;
		}
		if( -1 > $this->stock ){
			// 在庫連動商品の場合
			if( preg_match('/^[0-9]{1,3}$/',$this->stock_relation_count) > 0 ) {
				$useCount	= ($useCount * $this->stock_relation_count);
			}
			$sql	= 'SELECT * FROM '.TABLE_NAME_SHOPPING_PRODUCT_UNIT
			.' WHERE '.TABLE_NAME_SHOPPING_PRODUCT_UNIT.'.unit_id IN (\''.implode('\',\'',$this->stockRelationArray).'\')';
			$relatedUnitObject	= spider_Controller::createObject('shopping_DaoShoppingProductUnit');
			$relatedUnitObjectArray	= $dbo->queryAll($sql,$relatedUnitObject,false);
			if( false === $relatedUnitObjectArray ) {
				$request->addLocaledError('shopping.error.product.notfound',SPIDER_LOG_LEVEL_ERROR,array(''));
				return false;
			} else {
				// 合計在庫の為にランダム並べ替え
				srand((float) microtime() * 10000000);
				$randomKeys	= array_rand($relatedUnitObjectArray,count($relatedUnitObjectArray));
				if( is_scalar($randomKeys) ) {
					$randomKeys	= array($randomKeys);
				}
				foreach( $randomKeys as $randomKey ) {
					$relatedUnitObject	= $relatedUnitObjectArray[$randomKey];
					$relatedUnitObject->optimizeLoadedVars($dbo);
					if( $relatedUnitObject->useStock( $request,$useCount,$itemId,$serviceStartDate,$serviceLimitDate) ){
						if( -4 == $this->stock ){
							return true;
						}
					} else {
						if( -4 == $this->stock ){
							continue;
						} else {
							$request->addLocaledError('shopping.error.cart.failtousestock',SPIDER_LOG_LEVEL_ERROR,array(''));
							return false;
						}
					}
				}
				if( -4 == $this->stock ){
					$request->addLocaledError('shopping.error.cart.failtousestock',SPIDER_LOG_LEVEL_ERROR,array(''));
					return false;
				} else {
					return true;
				}
			}
		} else if( -1 == $this->stock ) {
			// 在庫制限なし商品の場合なにもしない
			return true;
		} else if( $this->delivery_type >= 200 ){
			// 予約商品の場合
			if( strlen($itemId) == 0 ){
				$request->addLocaledError('system.error.common.invalidusage',SPIDER_LOG_LEVEL_ERROR,array(''));
				return false;
			} else if( strlen($serviceStartDate)==0 || strlen($serviceLimitDate)==0 ){
				$request->addLocaledError('shopping.error.cart.requiredate',SPIDER_LOG_LEVEL_ERROR,array(''));
				return false;
			}
			if( $this->delivery_type >= 200 ) {
				// 予約商品の場合指定期間で実際に予約できる残数を取得
				$realStock	= $this->getStock( $request, $serviceStartDate, $serviceLimitDate, $itemId );
				if( $realStock >= $useCount ){
					// キープできるなら予約の関連付けに確保
					$sql	= 'UPDATE '.TABLE_NAME_SHOPPING_ORDER_ITEM.' SET used_unit_id='.$dbo->quote($this->unit_id)
					.' WHERE item_id='.$dbo->quote($itemId);
					if($dbo->query($sql)){
						return true;
					} else {
						$request->addLocaledError('database2.error.update',SPIDER_LOG_LEVEL_ERROR,array($sql));
					}
				}
			}
			return false;
		} else {
			// 予約でない商品
			$sql	= 'UPDATE '.TABLE_NAME_SHOPPING_PRODUCT_UNIT
			.' SET '.TABLE_NAME_SHOPPING_PRODUCT_UNIT.'.stock='
			.TABLE_NAME_SHOPPING_PRODUCT_UNIT.'.stock-'.$useCount
			.', '.TABLE_NAME_SHOPPING_PRODUCT_UNIT.'.stock_display='
			.TABLE_NAME_SHOPPING_PRODUCT_UNIT.'.stock_display-'.$useCount
			.' WHERE '.TABLE_NAME_SHOPPING_PRODUCT_UNIT.'.unit_id='.$dbo->quote($this->unit_id);
			$result	= $dbo->query($sql);
			if( false === $result ) {
				return false;
			} else {
				return true;
			}
		}
	}
	/**
	 * 実売価格を取得します
	 * 
	 */
	function getPriceSell( & $request, $startDate = null ) {
		if( $this->delivery_type < 200 || is_null($startDate) ) {
			// 予約商品ではないまたは日時指定がない場合はカラムの販売金額をそのまま返す
			return $this->price_sell;
		} else if( $this->delivery_type == 900 ){
			// 宿泊予約商品で且つ日指定がある場合はカレンダーから該当日時の料金を探しあれば優先
			$dbo	= $request->getAttribute('dbo');
			$targetDayStr	= date('Y-m-d',strtotime($startDate));
			$sql	= 'SELECT * FROM '.TABLE_NAME_SHOPPING_CALENDAR
			.' WHERE '
			.' unit_id='.$dbo->quote($this->unit_id)
			.' AND '
			.' start_date>='.$dbo->quote($targetDayStr.' 00:00:00')
			.' AND '
			.' close_date<='.$dbo->quote($targetDayStr.' 23:59:59')
			.' ORDER BY start_date DESC';
			$result	= $dbo->queryAll($sql,'hash');
			if( false === $result ) {
				$request->addLocaledError('shopping.error.cart.failtogettimeprice',SPIDER_LOG_LEVEL_ERROR,array(''));
			} else if( count($result) > 0 ) {
				$price	= $result[0]['price_sell'];
				if( preg_match('/^[0-9]{1,6}$/',$price) > 0 ) {
					return $price;
				} else {
					return $this->price_sell;
				}
			} else {
				return $this->price_sell;
			}
		} else {
			// 日時予約商品で且つ日時指定がある場合はカレンダーから該当日時の料金を探しあれば優先
			$dbo	= $request->getAttribute('dbo');
			$targetDayStr	= date('Y-m-d',strtotime($startDate));
			// 指定開始時間に一番近い開始時間の金額を取得する
			$sql	= 'SELECT * FROM '.TABLE_NAME_SHOPPING_CALENDAR
			.' WHERE '
			.' unit_id='.$dbo->quote($this->unit_id)
			.' AND '
			.' start_date>='.$dbo->quote($targetDayStr.' 00:00:00')
			.' AND '
			.' start_date<='.$dbo->quote($startDate)
			.' ORDER BY start_date DESC';
			$result	= $dbo->queryAll($sql,'hash');
			if( false === $result ) {
				$request->addLocaledError('shopping.error.cart.failtogettimeprice',SPIDER_LOG_LEVEL_ERROR,array(''));
			} else if( count($result) > 0 ) {
				$price	= $result[0]['price_sell'];
				if( preg_match('/^[0-9]{1,6}$/',$price) > 0 ) {
					return $price;
				} else {
					return $this->price_sell;
				}
			} else {
				return $this->price_sell;
			}
		}
	}
	/**
	 * 付加情報を読み込み
	 * @param $dbo database2_Connectionオブジェクト
	 * @param boolean 成功したらtrue
	 * @access public
	 */
	function loadRelation( $dbo ) {
		// メンバ調整
		$this->optimizeLoadedVars($dbo);
		// 添付ファイルの読み込み
		if( $this->loadRelatedFiles( $dbo ) === false ) { return false; }
		// フラグ情報の読み込み
		if( $this->loadRelatedFlags( $dbo ) === false ) { return false; }
		// 親プロダクトの読み込み
		if( $this->loadParentProductObject( $dbo ) === false ) { return false; }
		return true;
	}
	/**
	 * 親プロダクトの読み込み
	 * @param $dbo database2_Connectionオブジェクト
	 * @param boolean 成功したらtrue
	 * @access public
	 */
	function loadParentProductObject( $dbo ) {
		// 親商品の読み込み
		$this->shoppingProductObject	= null;
		if( strlen($this->product_id) > 0 ) {
			$productObject	= spider_Controller::createObject('shopping_DaoShoppingProduct');
			if( $dbo->loadById( $productObject, $this->product_id, false ) ) {
				$productObject->optimizeLoadedVars();
				$productObject->loadRelatedCategories( $dbo );
				$productObject->loadRelatedFiles( $dbo );
				$this->shoppingProductObject	= $productObject;
			}
		}
	}
	/**
	 * 関連づいたプロダクトオブジェクトを取得
	 * @param spider_HttpRequest &$request spider_HttpRequestクラスインスタンス参照
	 * @return shopping_DaoShoppingProduct 商品情報オブジェクト
	 * @access public
	 */
	function getProductObject( & $request ){
		if( is_null($this->shoppingProductObject) ){
			$dbo	= $request->getAttribute('dbo');
			$this->loadParentProductObject( $dbo );
		}
		return $this->shoppingProductObject;
	}
	/**
	 * 添付画像の読み込み
	 * @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_PRODUCT_UNIT_FILE
			.' WHERE unit_id='.$dbo->quote($this->unit_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;
	}
	/**
	 * メンバ調整
	 * @return void
	 * @access public
	 */
	function optimizeLoadedVars( $dbo ) {
		// オプション文字列の分割
		for( $i=1; $i<=5; $i++ ) {
			$optionFieldName		= 'option'.$i.'_items';
			$optionNameArrayName	= 'option'.$i.'_item_array';
			$optionPriceArrayName	= 'option'.$i.'_price_array';
			$optionCostArrayName	= 'option'.$i.'_cost_array';
			if( strlen( $this->$optionFieldName ) > 0 ) {
				// オプション選択肢が設定されているなら処理
				$this->$optionFieldName			= str_replace("\r\n","\n",$this->$optionFieldName);
				$this->$optionFieldName			= str_replace("\r","\n",$this->$optionFieldName);
				$this->$optionNameArrayName		= array();
				$this->$optionPriceArrayName	= array();
				$this->$optionCostArrayName		= array();
				$itemStringArray				= explode("\n",$this->$optionFieldName);
				if( preg_match('/\\:/',$this->$optionFieldName) > 0 ) {
					// :を含むなら価格と分割
					foreach( $itemStringArray as $str ) {
						list( $itemName, $itemPrice, $itemCost )	= explode(':',$str);
						array_push($this->$optionNameArrayName,$itemName);
						if( strlen($itemPrice)==0 ) {
							$itemPrice	= 0;
						}
						if( strlen($itemCost)==0 ) {
							$itemCost	= 0;
						}
						array_push($this->$optionPriceArrayName,$itemPrice);
						array_push($this->$optionCostArrayName,$itemCost);
					}
				} else {
					$this->$optionNameArrayName	= $itemStringArray;
				}
			}
		}
		// 公開設定を配列に設定
		$this->memberViewableArray	= array();
		$this->memberPurchasableArray	= array();
		$memberViewableStr	= sprintf('%016b',$this->member_viewable);
		$memberPurchasableStr	= sprintf('%016b',$this->member_purchasable);
		$keyCol	= 0;
		foreach ( $GLOBALS['MEMBER_MEMBER_CLASS_HASH'] as $key=>$value ) {
			if ( substr($memberViewableStr,15-$keyCol,1) == '1' ) {
				array_push($this->memberViewableArray,$key);
			}
			if ( substr($memberPurchasableStr,15-$keyCol,1) == '1' ) {
				array_push($this->memberPurchasableArray,$key);
			}
			$keyCol++;
		}
		// 在庫連動商品の配列化
		$this->stockRelationArray	= array();
		if( strlen($this->stock_relation) > 0 ) {
			$array	= explode('/',$this->stock_relation);
			foreach( $array as $id ) {
				if( strlen($id) > 0 ) {
					array_push( $this->stockRelationArray, $id );
				}
			}
		}
		// 必要なら在庫確認
		if( $this->stock == -1 ) {
			$this->sotck_view	= 999;
		} else if( $this->stock < -1 ) {
			$this->stock_view = $this->getStock( $dbo->request );
		} else {
			$this->stock_view = $this->stock;
		}
		// チェックイン時間とサービス時間をデフォルト値で入力
		if( strlen($this->default_start_time) == 0 && defined('SHOPPING_RESERVE_STAY_CHECKIN') ){
			$this->default_start_time	= SHOPPING_RESERVE_STAY_CHECKIN;
		}
		if( strlen($this->service_term) == 0 && defined('SHOPPING_RESERVE_STAY_CHECKOUT') ){
			$this->service_term	= ( 24 - substr($this->default_start_time,0,strpos($this->default_start_time,':'))
			+ substr(SHOPPING_RESERVE_STAY_CHECKOUT,0,strpos(SHOPPING_RESERVE_STAY_CHECKOUT,':')) ) * 60 * 60;
		}
		// 予約可能日
		if( strlen($this->rsv_permit_start) == 0 && defined('SHOPPING_RESERVE_ENABLE_START') ){
			$this->rsv_permit_start	= SHOPPING_RESERVE_ENABLE_START;
		}
		if( strlen($this->rsv_permit_limit) == 0 && defined('SHOPPING_RESERVE_ENABLE_LIMIT') ){
			$this->rsv_permit_limit	= SHOPPING_RESERVE_ENABLE_LIMIT;
		}
		return true;
	}
	/**
	 * 商品フラグ情報の読み込み
	 * @param $dbo database2_Connectionオブジェクト
	 * @param boolean 成功したらtrue
	 * @access public
	 */
	function loadRelatedFlags( $dbo ) {
		$this->flagIdArray			= array();
		$this->flagIdArray_org		= array();
		$this->flagObjectHash	= array();
		$sql	= 'SELECT '.TABLE_NAME_SHOPPING_PRODUCT_UNIT_FLAG_RELATION.'.*, '.TABLE_NAME_SHOPPING_PRODUCT_FLAG.'.flag_name'
		.' FROM '.TABLE_NAME_SHOPPING_PRODUCT_UNIT_FLAG_RELATION
		.' LEFT OUTER JOIN ' . TABLE_NAME_SHOPPING_PRODUCT_FLAG
		.' ON ' . TABLE_NAME_SHOPPING_PRODUCT_FLAG . '.flag_id='.TABLE_NAME_SHOPPING_PRODUCT_UNIT_FLAG_RELATION.'.flag_id '
		.' WHERE unit_id='.$dbo->quote($this->unit_id)
		.' ORDER BY order_number ASC';
		$rows	= $dbo->queryAll( $sql, 'hash', false );
		if ( $rows === false ) {
			return false;
		} else {
			foreach( $rows as $row ) {
				$flagId = trim($row['flag_id']);
				if ( strlen($flagId)>0 ) {
					if ( !is_array($this->flagObjectHash[$flagId]) ) {
						$this->flagObjectHash[$flagId] = array();
					}
					$this->flagIdArray[$flagId] 	= $flagId;
					$this->flagIdArray_org[$flagId] = $flagId;
					$this->flagObjectHash[$flagId]['flag_name']		= trim($row['flag_name']);
					$this->flagObjectHash[$flagId]['order_number']	= trim($row['order_number']);
					$this->flagObjectHash[$flagId]['open_date']		= trim($row['open_date']);
					$this->flagObjectHash[$flagId]['close_date']	= trim($row['close_date']);
					if ( strlen(trim($row['open_date']))>0 ) {
						$this->flagObjectHash[$flagId]['open_date_year']	= date('Y',strtotime($row['open_date']));
						$this->flagObjectHash[$flagId]['open_date_month']	= date('n',strtotime($row['open_date']));
						$this->flagObjectHash[$flagId]['open_date_day']		= date('j',strtotime($row['open_date']));
					} else {
						$this->flagObjectHash[$flagId]['open_date_year']	= '';
						$this->flagObjectHash[$flagId]['open_date_month']	= '';
						$this->flagObjectHash[$flagId]['open_date_day']		= '';
					}
					if ( strlen(trim($row['close_date']))>0 ) {
						$this->flagObjectHash[$flagId]['close_date_year']	= date('Y',strtotime($row['close_date']));
						$this->flagObjectHash[$flagId]['close_date_month']	= date('n',strtotime($row['close_date']));
						$this->flagObjectHash[$flagId]['close_date_day']	= date('j',strtotime($row['close_date']));
					} else {
						$this->flagObjectHash[$flagId]['close_date_year']	= '';
						$this->flagObjectHash[$flagId]['close_date_month']	= '';
						$this->flagObjectHash[$flagId]['close_date_day']	= '';
					}
				}
			}
		}
		return true;
	}
	/**
	 * 親商品以外の付加情報を読み込みます
	 * @param $dbo database2_Connectionオブジェクト
	 * @param boolean 成功したらtrue
	 * @access public
	 */
	function loadRelationExceptProduct( $dbo ) {
		// 添付画像の読み込み
		$this->fileIdArray		= array();
		$this->fileIdArray_org	= array();
		$sql	= 'SELECT file_id,order_number FROM '.TABLE_NAME_SHOPPING_PRODUCT_UNIT_FILE
			.' WHERE unit_id='.$dbo->quote($this->unit_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']);
			}
		}
		// オプション文字列の分割
		for( $i=1; $i<=5; $i++ ) {
			$optionFieldName		= 'option'.$i.'_items';
			$optionNameArrayName	= 'option'.$i.'_item_array';
			$optionPriceArrayName	= 'option'.$i.'_price_array';
			$optionCostArrayName	= 'option'.$i.'_cost_array';
			if( strlen( $this->$optionFieldName ) > 0 ) {
				// オプション選択肢が設定されているなら処理
				$this->$optionFieldName			= str_replace("\r\n","\n",$this->$optionFieldName);
				$this->$optionFieldName			= str_replace("\r","\n",$this->$optionFieldName);
				$this->$optionNameArrayName		= array();
				$this->$optionPriceArrayName	= array();
				$this->$optionCostArrayName		= array();
				$itemStringArray				= explode("\n",$this->$optionFieldName);
				if( preg_match('/\\:/',$this->$optionFieldName) > 0 ) {
					// :を含むなら価格と分割
					foreach( $itemStringArray as $str ) {
						list( $itemName, $itemPrice, $itemCost )	= explode(':',$str);
						array_push($this->$optionNameArrayName,$itemName);
						if( strlen($itemPrice)==0 ) {
							$itemPrice	= 0;
						}
						if( strlen($itemCost)==0 ) {
							$itemCost	= 0;
						}
						array_push($this->$optionPriceArrayName,$itemPrice);
						array_push($this->$optionCostArrayName,$itemCost);
					}
				} else {
					$this->$optionNameArrayName	= $itemStringArray;
				}
			}
		}
	}
	/**
	 * インサート前に行いたい処理
	 * @param MDBObject $dbo MDB2オブジェクトかその互換オブジェクト
	 * @return boolean 成功したらtrue
	 * @access public
	 */
	function pre_insert( $dbo ) {
		return true;
	}
	/**
	 * インサート後に行いたい処理
	 * @param MDBObject $dbo MDB2オブジェクトかその互換オブジェクト
	 * @return boolean 成功したらtrue
	 * @access public
	 */
	function post_insert( $dbo ) {
		// ファイル関連付けをインサートする
		if( is_array($this->fileIdArray) ) {
			foreach( $this->fileIdArray as $key => $fileId ) {
				if( strlen(trim($fileId)) > 0 ) {
					$sql	= 'INSERT INTO '.TABLE_NAME_SHOPPING_PRODUCT_UNIT_FILE.'(file_id,unit_id,file_class,order_number) VALUES ('
						.$dbo->quote($fileId).','.$dbo->quote($this->unit_id).',0'.','.$key.' )';
					$result = $dbo->query( $sql );
					if( false === $result ) {
						return false;
					}
				}
			}
		}
		// 商品フラグ情報の登録
		if( is_array($this->flagObjectHash) && count(flagObjectHash)>0 ) {
			foreach ( $this->flagObjectHash as $flagId=>$flagObject ) {
				$sql	= 'INSERT INTO '.TABLE_NAME_SHOPPING_PRODUCT_UNIT_FLAG_RELATION
					.'(unit_id,flag_id,open_date,close_date,order_number) VALUES ('
					.$dbo->quote($this->unit_id).','
					.$dbo->quote($flagId).','
					.$dbo->quote($flagObject['open_date']).','
					.$dbo->quote($flagObject['close_date']).','
					.$dbo->quote($flagObject['order_number']).' )'
				;
				$result = $dbo->query( $sql );
				if( false === $result ) {
					return false;
				}
			}
		}
		return true;
	}
	/**	 * アップデート前に行いたい処理
	 * @param MDBObject $dbo MDB2オブジェクトかその互換オブジェクト
	 * @return boolean 成功したらtrue
	 */
	function pre_update( $dbo ) {
		return true;
	}
	/**
	 * アップデート後に行いたい処理
	 * @param MDBObject $dbo MDB2オブジェクトかその互換オブジェクト
	 * @return boolean 成功したらtrue
	 */
	function post_update( $dbo ) {
		$request	= spider_Controller::createObject('spider_HttpRequest');
		// ファイル関連付け
		if( is_array($this->fileIdArray_org) ) {
			// 旧関連ファイルで新にないものは削除する
			foreach( $this->fileIdArray_org as $key => $fileId ) {
				if( strlen(trim($fileId)) > 0 ) {
					if( !is_array($this->fileIdArray) || !in_array($fileId,$this->fileIdArray) ) {
						$fileObject	= spider_Controller::createObject('file_DaoFileBin');
						if( $dbo->loadById( $fileObject, $fileId ) ) {
							// 読み込めたら削除
							$fileObject->deleteFileAll( $request );
							$dbo->delete($fileObject);
						}
						$sql	= 'DELETE FROM '.TABLE_NAME_SHOPPING_PRODUCT_UNIT_FILE
							.' WHERE unit_id='.$dbo->quote($this->unit_id)
							.' AND file_id='.$dbo->quote($fileId);
						$result = $dbo->query( $sql );
						if( false === $result ) {
							return false;
						}
					}
				}
			}
		}
		if( is_array($this->fileIdArray) ) {
			// 新しい関連ファイルを登録する
			foreach( $this->fileIdArray as $key => $fileId ) {
				if( strlen(trim($fileId)) > 0 ) {
					if( !is_array($this->fileIdArray_org) || !in_array($fileId,$this->fileIdArray_org) ) {
						$sql	= 'INSERT INTO '.TABLE_NAME_SHOPPING_PRODUCT_UNIT_FILE.'(file_id,unit_id,file_class,order_number) VALUES ('
							.$dbo->quote($fileId).','.$dbo->quote($this->unit_id).',0'.','.$key	.' )';
						$result = $dbo->query( $sql );
						if( false === $result ) {
							return false;
						}
					}
				}
			}
		}
		// 関連する商品フラグ情報の削除
		if ( count($this->flagIdArray_org)>0 ) {
			// 登録前にフラグ情報が登録されていた場合、関連テーブルを削除する
			$sql	= 'DELETE FROM '.TABLE_NAME_SHOPPING_PRODUCT_UNIT_FLAG_RELATION
				.' WHERE unit_id='.$dbo->quote($this->unit_id)
			;
			$result = $dbo->query( $sql );
			if( false === $result ) {
				return false;
			}
		}
		// 商品フラグ情報の登録
		if( is_array($this->flagObjectHash) && count(flagObjectHash)>0 ) {
			foreach ( $this->flagObjectHash as $flagId=>$flagObject ) {
				$sql	= 'INSERT INTO '.TABLE_NAME_SHOPPING_PRODUCT_UNIT_FLAG_RELATION
					.'(unit_id,flag_id,open_date,close_date,order_number) VALUES ('
					.$dbo->quote($this->unit_id).','
					.$dbo->quote($flagId).','
					.$dbo->quote($flagObject['open_date']).','
					.$dbo->quote($flagObject['close_date']).','
					.$dbo->quote($flagObject['order_number']).' )'
				;
				$result = $dbo->query( $sql );
				if( false === $result ) {
					return false;
				}
			}
		}
		// 削除の場合ID再登録が可能なようにIDを変更しておく
		if( $this->status_flag >= 200 ) {
			$sql	= 'UPDATE '.TABLE_NAME_SHOPPING_PRODUCT_UNIT
				.' SET unit_id='.$dbo->quote('SDELETED'.sprintf('%08d',$this->unit_number) )
				.' WHERE unit_number='.$this->unit_number;
			$result = $dbo->query($sql);
      // 削除の場合は関連注文項目のIDも変更する
      $sql  = 'UPDATE '.TABLE_NAME_SHOPPING_ORDER_ITEM
        .' SET unit_id='.$dbo->quote('SDELETED'.sprintf('%08d',$this->unit_number) )
        .' WHERE unit_id='.$dbo->quote($this->unit_id);
      $result = $dbo->query($sql);
			if( false === $result ) {
				return false;
			}
		}
		return true;
	}
	/**
	 * 設定された値の妥当性検査を行います
	 */
	function validate( & $request ) {
		$dbo	= $request->getAttribute( 'dbo' );
		// 単位ID
		if( strlen(trim($this->unit_id)) == 0 ) {
		} else if( preg_match('/^[0-9a-zA-Z\\_]{1,32}$/',$this->unit_id) == 0 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invalidid',SPIDER_LOG_LEVEL_ERROR,array());
		} else if( preg_match('/^SDELETED[0-9]{8}$/',$this->unit_id) > 0 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.reservedid',SPIDER_LOG_LEVEL_ERROR,array());
		} else {
			$compareShoppingProductUnitObject	= spider_Controller::createObject('shopping_DaoShoppingProductUnit');
			if( $dbo->loadById( $compareShoppingProductUnitObject, $this->unit_id ) ) {
				if( $this->unit_number != $compareShoppingProductUnitObject->unit_number ) {
					if( $compareShoppingProductUnitObject->status_flag < 200 ) {
						$request->addLocaledError('shopping.error.dao.product.unit.duplicatedid',SPIDER_LOG_LEVEL_ERROR,array());
					} else if( is_numeric($compareShoppingProductUnitObject->product_number) ) {
						$compareShoppingProductUnitObject->status_flag	= 255;
						$compareShoppingProductUnitObject->updated_date	= date('Y-m-d H:i:s');
						$dbo->update($compareShoppingProductUnitObject,false);
					}
				}
			}
		}
		if( strlen(trim($this->require_unit_id)) == 0 ) {
		} else if( strlen(trim($this->require_unit_id)) > 32 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invalidrequireid',SPIDER_LOG_LEVEL_ERROR,array());
		} else {
			$requireUnitObject	= spider_Controller::createObject('shopping_DaoShoppingProductUnit');
			if( !$dbo->loadById($requireUnitObject,$this->require_unit_id) ) {
				$request->addLocaledError('shopping.error.dao.product.unit.invalidrequireid',SPIDER_LOG_LEVEL_ERROR,array());
			}
		}
		// 単位名
		if( strlen(trim($this->unit_name)) == 0 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.requirename',SPIDER_LOG_LEVEL_ERROR,array());
		} else if( strlen(trim($this->unit_name)) > 240 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invalidname',SPIDER_LOG_LEVEL_ERROR,array());
		}
		// 単位名フリガナ
		if( strlen(trim($this->unit_kana)) == 0 ) {
		} else if( strlen(trim($this->unit_kana)) > 240 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invalidkana',SPIDER_LOG_LEVEL_ERROR,array());
		}
		// 表記カウント単位
		if( strlen(trim($this->unit_string)) == 0 ) {
		} else if( strlen(trim($this->unit_string)) > 32 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invalidunitstring',SPIDER_LOG_LEVEL_ERROR,array());
		}
		// 配送種別
		// 2010-08-03 継続サービス条件追加
		$this->delivery_type	= mb_convert_kana($this->delivery_type,'a');
		if( !array_key_exists( $this->delivery_type, $GLOBALS['SHOPPING_DELIVERY_TYPE_HASH'] ) ) {
			$this->delivery_type	= '0';
		}
		// カレンダータイプ
		$this->calendar_type	= mb_convert_kana($this->calendar_type,'a');
		if( strlen(trim($this->calendar_type)) == 0 ) {
			$this->calendar_type	= '1';
		} else if( $this->calendar_type != '1' && $this->calendar_type != '2' ){
			$this->calendar_type	= '0';
		}
		
		// 公開設定（閲覧）
		if ( !is_array($this->memberViewableArray) ) {
			$memberViewableArray = array();
			if ( strlen($this->memberViewableArray)>0 ) {
				array_push($memberViewableArray,$this->memberViewableArray);
			}
			$this->memberViewableArray = $memberViewableArray;
		}
		foreach ( $this->memberViewableArray as $key=>$value ) {
			if( strlen($value) > 0 ) {
				if( preg_match('/^[0-9]{1,2}$/',$value) == 0 ) {
					$isExist = false;
					foreach ( $GLOBALS['MEMBER_MEMBER_CLASS_HASH'] as $mkey=>$mvalue ) {
						if ( $mvalue==$value ) {
							$this->memberViewableArray[$key] = $mkey;
							$isExist = true;
							break;
						}
					}
					if ( !$isExist ) {
						$request->addLocaledError('shopping.error.dao.product.unit.invalidviewmemberclass',SPIDER_LOG_LEVEL_ERROR,array($value));
						break;
					}			
				} else {
					if ( !array_key_exists($value,$GLOBALS['MEMBER_MEMBER_CLASS_HASH']) ) {
						$request->addLocaledError('shopping.error.dao.product.unit.invalidviewmemberclass',SPIDER_LOG_LEVEL_ERROR,array($value));
						break;
					}
				}
			}
		}
		// 公開設定（購入）
		if ( !is_array($this->memberPurchasableArray) ) {
			$memberPurchasableArray = array();
			if ( strlen($this->memberPurchasableArray)>0 ) {
				array_push($memberPurchasableArray,$this->memberPurchasableArray);
			}
			$this->memberPurchasableArray = $memberPurchasableArray;
		}
		foreach ( $this->memberPurchasableArray as $key=>$value ) {
			if( strlen($value) > 0 ) {
				if( preg_match('/^[0-9]{1,2}$/',$value) == 0 ) {
					$isExist = false;
					foreach ( $GLOBALS['MEMBER_MEMBER_CLASS_HASH'] as $mkey=>$mvalue ) {
						if ( $mvalue==$value ) {
							$this->memberPurchasableArray[$key] = $mkey;
							$isExist = true;
							break;
						}
					}
					if ( !$isExist ) {
						$request->addLocaledError('shopping.error.dao.product.unit.invalidpurchasememberclass',SPIDER_LOG_LEVEL_ERROR,array($value));
						break;
					}			
				} else {
					if ( !array_key_exists($value,$GLOBALS['MEMBER_MEMBER_CLASS_HASH']) ) {
						$request->addLocaledError('shopping.error.dao.product.unit.invalidpurchasememberclass',SPIDER_LOG_LEVEL_ERROR,array($value));
						break;
					}
				}
			}
		}
		$this->member_viewable	= 0;
		$this->member_purchasable	= 0;
		if( !$request->isError() ) {
			$keyOpen	= 1;
			foreach ( $GLOBALS['MEMBER_MEMBER_CLASS_HASH'] as $key=>$value ) {
				if( is_array($this->memberViewableArray) && in_array($key,$this->memberViewableArray) ) {
					$this->member_viewable	= $this->member_viewable | $keyOpen;
				}
				if( is_array($this->memberPurchasableArray) && in_array($key,$this->memberPurchasableArray) ) {
					$this->member_purchasable	= $this->member_purchasable | $keyOpen;
				}
				$keyOpen = $keyOpen * 2;
			}
		}
		
		// 公開販売開始日時
		if( strlen(trim($this->open_date)) == 0 ) {
			$this->open_date	= null;
		} else if( preg_match('/^[0-9]{4}\\-[0-9]{1,2}\\-[0-9]{1,2}\\s[0-9]{1,2}\\:[0-9]{1,2}:[0-9]{1,2}$/',$this->open_date) == 0
			|| !strtotime($this->open_date) ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invalidopenstart',SPIDER_LOG_LEVEL_ERROR,array());
		}
		if( strlen(trim($this->close_date)) == 0 ) {
			$this->close_date	= null;
		} else if( preg_match('/^[0-9]{4}\\-[0-9]{1,2}\\-[0-9]{1,2}\\s[0-9]{1,2}\\:[0-9]{1,2}:[0-9]{1,2}$/',$this->close_date) == 0
			|| !strtotime($this->close_date) ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invalidopenlimit',SPIDER_LOG_LEVEL_ERROR,array());
		}
		// 梱包目安値
		$this->delivery_weight	= mb_convert_kana($this->delivery_weight,'a');
		if( strlen(trim($this->delivery_weight)) == 0 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.requireweight',SPIDER_LOG_LEVEL_ERROR,array());
		} else if( preg_match('/^[0-9]{1,7}$/',$this->delivery_weight) == 0 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invalidweight',SPIDER_LOG_LEVEL_ERROR,array());
		}
		// 標準価格
		$this->price_standard	= mb_convert_kana($this->price_standard,'a');
		if( strlen(trim($this->price_standard)) == 0 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.requirestandardprice',SPIDER_LOG_LEVEL_ERROR,array());
		} else if( preg_match('/^[0-9]{1,8}$/',$this->price_standard) == 0 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invalidstandardprice',SPIDER_LOG_LEVEL_ERROR,array());
		}
		// 販売価格
		$this->price_sell	= mb_convert_kana($this->price_sell,'a');
		if( strlen(trim($this->price_sell)) == 0 ) {
			$request->addLocaledError('shopping.error.product.unit.requirepricesell',SPIDER_LOG_LEVEL_FATAL,array(''));
		} else if( preg_match('/^[0-9]{1,8}$/',$this->price_sell) == 0 ) {
			$request->addLocaledError('shopping.error.product.unit.invalidpricesell',SPIDER_LOG_LEVEL_FATAL,array(''));
		}
		// 仕入れ値
		$this->cost	= mb_convert_kana($this->cost,'a');
		if( strlen(trim($this->cost)) == 0 ) {
			$request->addLocaledError('shopping.error.product.unit.requirecost',SPIDER_LOG_LEVEL_FATAL,array(''));
		} else if( preg_match('/^[0-9]{1,8}$/',$this->cost) == 0 ) {
			$request->addLocaledError('shopping.error.product.unit.invalidcost',SPIDER_LOG_LEVEL_FATAL,array(''));
		}
		// 月次課金価格
		$this->price_monthly	= mb_convert_kana($this->price_monthly,'a');
		if( strlen(trim($this->price_monthly)) == 0 ) {
			$this->price_monthly	= 0;
		} else if( preg_match('/^[0-9]{1,8}$/',$this->price_monthly) == 0 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invalidmonthlyprice',SPIDER_LOG_LEVEL_ERROR,array());
		}
		// 在庫数
		$this->stock	= mb_convert_kana($this->stock,'a');
		if( strlen(trim($this->stock)) == 0 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.requirestock',SPIDER_LOG_LEVEL_ERROR,array());
		} else if( preg_match('/^[0-9]{1,8}$/',$this->stock) == 0
		&& '-1' != $this->stock && '-2' != $this->stock && '-3' != $this->stock && '-4' != $this->stock ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invalidstock',SPIDER_LOG_LEVEL_ERROR,array());
		}
		// 実在庫数
		$this->stock_display	= mb_convert_kana($this->stock_display,'a');
		if( strlen(trim($this->stock_display)) == 0 ) {
			$this->stock_display	= $this->stock;
		} else if( preg_match('/^[0-9]{1,8}$/',$this->stock_display) == 0
		&& '-1' != $this->stock_display && '-2' != $this->stock_display && '-3' != $this->stock_display && '-4' != $this->stock_display ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invalidviewstock',SPIDER_LOG_LEVEL_ERROR,array());
		}
		// 在庫連動商品
		$this->stockRelationArray	= array();
		if( strlen($this->stock_relation) > 0 ) {
			$array	= explode('/',$this->stock_relation);
			foreach( $array as $id ) {
				if( strlen($id) > 0 ) {
					array_push( $this->stockRelationArray, $id );
				}
			}
		}
		if( $this->stock < -1 ) {
			if( count($this->stockRelationArray) == 0 ) {
				$request->addLocaledError('shopping.error.dao.product.unit.requirerelatestock',SPIDER_LOG_LEVEL_ERROR,array());
			}
			if( strlen($this->stock_relation_count) == 0 ) {
				$this->stock_relation_count	= 1;
			} else if( preg_match('/^[0-9]{1,3}$/',$this->stock_relation_count) == 0 ){
				$request->addLocaledError('shopping.error.dao.product.unit.invalidrelatecount',SPIDER_LOG_LEVEL_ERROR,array());
			}
		}
		// 付与ポイント数
		$this->present_point	= mb_convert_kana($this->present_point,'a');
		if( strlen(trim($this->present_point)) == 0 ) {
			$this->present_point	= 0;
		} else if( preg_match('/^[0-9]{1,7}$/',$this->present_point) == 0 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invalidpoint',SPIDER_LOG_LEVEL_ERROR,array());
		}
		// プロモーション割引除外フラグ
		$this->discount_exception	= mb_convert_kana($this->discount_exception,'a');
		if( strlen(trim($this->discount_exception)) == 0 ) {
		} else if( preg_match('/^[0-9]{1}$/',$this->discount_exception) == 0 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invaliddscountexeption',SPIDER_LOG_LEVEL_ERROR,array());
		}
		// 順序番号
		$this->order_number	= mb_convert_kana($this->order_number,'a');
		if( strlen(trim($this->order_number)) == 0 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invalidorder',SPIDER_LOG_LEVEL_ERROR,array());
		} else if( preg_match('/^[0-9]{1,5}$/',trim($this->order_number)) == 0 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invalidorder',SPIDER_LOG_LEVEL_ERROR,array());
		}
		// 概要
		$this->description	= str_replace("\r\n","\n",$this->description);
		$this->description	= str_replace("\r","\n",$this->description);
		if( strlen(trim($this->description)) == 0 ) {
		} else if( strlen(trim($this->description)) > 3000 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invaliddescription',SPIDER_LOG_LEVEL_ERROR,array());
		}
		// 詳細コメント
		$this->detail_comment	= str_replace("\r\n","\n",$this->detail_comment);
		$this->detail_comment	= str_replace("\r","\n",$this->detail_comment);
		if( strlen(trim($this->detail_comment)) == 0 ) {
		} else if( strlen(trim($this->detail_comment)) > 15000 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invaliddetail',SPIDER_LOG_LEVEL_ERROR,array());
		}
		// オプション妥当性検査
		for( $num=1; $num<=5; $num++ ){
			// オプション名
			$varName	= 'option'.$num.'_name';
			if( strlen(trim($this->$varName)) == 0 ) {
			} else if( strlen(trim($this->$varName)) > 180 ) {
				$request->addLocaledError('shopping.error.dao.product.unit.invalidoptionname',SPIDER_LOG_LEVEL_ERROR,array($num));
			}
			// オプションURL
			$varName	= 'option'.$num.'_url';
			if( strlen(trim($this->$varName)) == 0 ) {
			} else if( strlen(trim($this->$varName)) > 180 ) {
				$request->addLocaledError('shopping.error.dao.product.unit.invalidoptionurl',SPIDER_LOG_LEVEL_ERROR,array($num));
			}
			// オプション計算フラグ
			$varName	= 'option'.$num.'_calculate';
			if( strlen(trim($this->$varName)) != '1' ) {
				$this->$varName	= 0;
			}
		}
		// 予約営業日制限
		if( $this->delivery_type < 200 ) {
			$this->rsv_permit_start	= null;
			$this->rsv_permit_limit	= null;
		} else {
			if( strlen($this->rsv_permit_start) == 0 ) {
				$this->rsv_permit_start	= null;
			} else if( preg_match('/^[0-9]{1,3}$/',$this->rsv_permit_start) == 0 ){
				$request->addLocaledError('shopping.error.dao.product.unit.invalidrsvstart',SPIDER_LOG_LEVEL_ERROR,array());
			} else if( $this->rsv_permit_start > 365 ) {
				$request->addLocaledError('shopping.error.dao.product.unit.invalidrsvstart',SPIDER_LOG_LEVEL_ERROR,array());
			}
			if( strlen($this->rsv_permit_limit) == 0 ) {
				$this->rsv_permit_limit	= null;
			} else if( preg_match('/^[0-9]{1,3}$/',$this->rsv_permit_limit) == 0 ){
				$request->addLocaledError('shopping.error.dao.product.unit.invalidrsvlimit',SPIDER_LOG_LEVEL_ERROR,array());
			} else if( preg_match('/^[0-9]{1,3}$/',$this->rsv_permit_limit) > 0
			&& $this->rsv_permit_limit <= $this->rsv_permit_start ) {
				$request->addLocaledError('shopping.error.dao.product.unit.invalidrsvlimit',SPIDER_LOG_LEVEL_ERROR,array());
			} else if( $this->rsv_permit_limit > 999 ) {
				$request->addLocaledError('shopping.error.dao.product.unit.invalidrsvlimit',SPIDER_LOG_LEVEL_ERROR,array());
			}
		}
		// 最大同時注文数
		if( strlen($this->max_at_once)== 0 ) {
			$this->max_at_once	= null;
		} else if( preg_match('/^[0-9]{1,4}$/',$this->max_at_once) == 0 ){
			$request->addLocaledError('shopping.error.dao.product.unit.invalidapplyatonce',SPIDER_LOG_LEVEL_ERROR,array());
		}
		$this->updated_date		= str_replace('/','-',$this->updated_date);
		$this->registered_date	= str_replace('/','-',$this->registered_date);
		
		// 商品フラグ関連
		foreach ( $this->flagObjectHash as $flagId=>$flagObject ) {
			// 表示順序
			$ordetNumber = $flagObject['order_number'];
			if( strlen(trim($ordetNumber)) == 0 ) {
				// 未入力の場合、0を設定
				$ordetNumber	= 0;
				$this->flagObjectHash[$flagId]['order_number']	= $ordetNumber;
			} else if( preg_match('/^[0-9]{1,4}$/',$ordetNumber) == 0 ) {
				$request->addLocaledError('shopping.error.dao.product.unit.invalidflagorder',SPIDER_LOG_LEVEL_ERROR,array($flagObject['flag_name']));
			} else if ( $ordetNumber < 0 ) {
				$request->addLocaledError('shopping.error.dao.product.unit.invalidflagorder',SPIDER_LOG_LEVEL_ERROR,array($flagObject['flag_name']));
			} else if ( $ordetNumber > 100 ) {
				$request->addLocaledError('shopping.error.dao.product.unit.invalidflagorder',SPIDER_LOG_LEVEL_ERROR,array($flagObject['flag_name']));
			}
			// 公開開始日
			$openDate		= $flagObject['open_date'];
			$openDateYear	= $flagObject['open_date_year'];
			$openDateMonth	= $flagObject['open_date_month'];
			$openDateDay	= $flagObject['open_date_day'];
			if ( strlen($openDate)>0 ) {
				spider_Controller::loadClassDefinition('util_ValidateFunctions');
				if( util_ValidateFunctions::isAvailableDate($openDateYear,$openDateMonth,$openDateDay) ){
				} else {
					$request->addLocaledError('shopping.error.dao.product.unit.invalidflagopen',SPIDER_LOG_LEVEL_ERROR,array($flagObject['flag_name']));
				}
			} else if ( strlen($openDateYear)>0 || strlen($openDateMonth)>0 || strlen($openDateDay)>0 ) {
				$request->addLocaledError('shopping.error.dao.product.unit.invalidflagopen',SPIDER_LOG_LEVEL_ERROR,array($flagObject['flag_name']));
			} else {
			}
			// 公開終了日
			$closeDate		= $flagObject['close_date'];
			$closeDateYear	= $flagObject['close_date_year'];
			$closeDateMonth	= $flagObject['close_date_month'];
			$closeDateDay	= $flagObject['close_date_day'];
			if ( strlen($closeDate)>0 ) {
				spider_Controller::loadClassDefinition('util_ValidateFunctions');
				if( util_ValidateFunctions::isAvailableDate($closeDateYear,$closeDateMonth,$closeDateDay) ){
				} else {
					$request->addLocaledError('shopping.error.dao.product.unit.invalidflagopen',SPIDER_LOG_LEVEL_ERROR,array($flagObject['flag_name']));
				}
			} else if ( strlen($closeDateYear)>0 || strlen($closeDateMonth)>0 || strlen($closeDateDay)>0 ) {
				$request->addLocaledError('shopping.error.dao.product.unit.invalidflagopen',SPIDER_LOG_LEVEL_ERROR,array($flagObject['flag_name']));
			} else {
			}
		}
		
		// サービス開始標準時間: 現状宿泊予約のみで利用（チェックイン時間）
		if( 900 == $this->delivery_type ) {
			if( is_null($this->default_start_time) || strlen($this->default_start_time) == 0 ) {
				$request->addLocaledError('shopping.error.dao.product.unit.invalidsvcstarttime',SPIDER_LOG_LEVEL_ERROR,array($flagObject['flag_name']));
			} else if( preg_match('/^((|[01])[0-9]|2[0-3])\\:[0-5][0-9](|\\:[0-9][0-9])$/',$this->default_start_time) == 0 ) {
				$request->addLocaledError('shopping.error.dao.product.unit.invalidsvcstarttime',SPIDER_LOG_LEVEL_ERROR,array($flagObject['flag_name']));
			}
		} else {
			$this->default_start_time	= null;
		}
		// サービス提供期間: 秒数で入力。1時間なら3600
		if( is_null($this->service_term) || strlen($this->service_term) == 0 ){
			$this->service_term	= 0;
		} else if( preg_match('/^[0-9]{1,8}/',$this->service_term) == 0 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invalidserviceterm',SPIDER_LOG_LEVEL_ERROR,array($flagObject['flag_name']));
		} else if( $this->service_term > 60*60*24*365*3 ) {
			$request->addLocaledError('shopping.error.dao.product.unit.invalidserviceterm',SPIDER_LOG_LEVEL_ERROR,array($flagObject['flag_name']));
		}

		return true;
	}
	/**
	 * CSVダウンロードの為のカラム取得メソッド
	 * 項目キーから値を取得します
	 */
	function getColumnString( $key, $quote=true, $filter=null ) {
		$returnColumn	= $this->$key;
		$returnStrings	= '';
		if( 'member_viewable' == $key || 'member_purchasable' == $key ) {
			// 公開設定は、該当の会員種別の文字列で返す
			$memberClassNameArray	= array();
			$memberOpenFlagStr		= sprintf('%016b',$returnColumn);
			$keyCol	= 0;
			foreach ( $GLOBALS['MEMBER_MEMBER_CLASS_HASH'] as $key=>$value ) {
				if ( substr($memberOpenFlagStr,15-$keyCol,1) == '1' ) {
					array_push($memberClassNameArray,$value);
				}
				$keyCol++;
			}
			$returnStrings = implode('/',$memberClassNameArray);
		} else if( is_array($returnColumn) ) {
			$returnStrings	= implode(',',$returnColumn);
		} else {
			// 商品情報の値
			$returnStrings	= $returnColumn;
		}
		if( strlen(trim($filter)) > 0 ) {
			$returnStrings	= mb_convert_kana( $returnStrings, $filter );
		}
		if( $quote ) {
			$returnStrings	= '"'.str_replace('"','""',$returnStrings).'"';
		}
		return $returnStrings;
	}
	//
	// オプション関連メソッド
	//
	/**
	 * この販売単位固有の注文オプションがあるか確認
	 * @return boolean 固有オプションを保持しているならtrue
	 */
	function hasUniqueOption() {
		for( $optionOrder=1; $optionOrder<=5; $optionOrder++ ) {
			$optionNameVarName		= 'option'.$optionOrder.'_name';
			$optionNameArrayName	= 'option'.$optionOrder.'_item_array';
			if( isset($this->$optionNameVarName)
			&& strlen($this->$optionNameVarName) > 0 ) {
				return true;
			}
		}
		return false;
	}
	/**
	 * 本オブジェクトの設定から注文オプションオブジェクトの配列を取得
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @return array shopping_DaoShoppingOrderOption拡張実装クラスオブジェクトの配列
	 */
	function getOrderOptionObjectArray( & $request ) {
		// 親プロダクトのオプションを取得
		$dbo	= $request->getAttribute('dbo');
		$productOptionObjectArray	= array();
		if( is_null($this->shoppingProductObject) ) {
			$this->loadParentProductObject( $dbo );
		}
		$productOptionObjectArray	= $this->shoppingProductObject->getOrderOptionObjectArray( $request );
		// 本ユニットのオプション配列を作成
		$orderOptionObjectArray		= array();
		for( $num=1; $num<=5; $num++ ) {
			$fieldNameOptionName	= 'option'.$num.'_name';
			$fieldNameOptionItems	= 'option'.$num.'_items';
			$fieldNameOptionExp	= 'option'.$num.'_explanation';
			$fieldNameOptionCalc	= 'option'.$num.'_calculate';
			$optionName		= trim($this->$fieldNameOptionName);
			$optionItems	= trim($this->$fieldNameOptionItems);
			if( strlen($optionName) > 0 ) {
				spider_Controller::loadClassDefinition('shopping_DaoShoppingOrderOption');
				$orderOptionObject	= null;
				if( $orderOptionObject = shopping_DaoShoppingOrderOption::createProductOptionObject( $optionName, $optionItems ) ) {
					$orderOptionObject->optionNumber	= $num-1;
					$orderOptionObject->item_order		= $num-1;
					$orderOptionObject->required		= true;
					$orderOptionObject->explanation		= $this->$fieldNameOptionExp;
					$orderOptionObject->calculate_flag		= $this->$fieldNameOptionCalc;
					$orderOptionObjectArray[$num-1]		= $orderOptionObject;
				}
			}
		}
		// キーでソート
		ksort($orderOptionObjectArray);
		// 配列を上書き調整
		$returnObjectArray	= array();
		for( $num=1; $num<=5; $num++ ) {
			if( isset($orderOptionObjectArray[$num-1]) && is_object($orderOptionObjectArray[$num-1]) ) {
				$returnObjectArray[$num-1]	= $orderOptionObjectArray[$num-1];
			} else if( isset($productOptionObjectArray[$num-1]) && is_object($productOptionObjectArray[$num-1]) ) {
				$returnObjectArray[$num-1]	= $productOptionObjectArray[$num-1];
			}
		}
		ksort($returnObjectArray);
		return $returnObjectArray;
	}
	//
	// 登録ファイル関連
	//
	/**
	 * サーバー上の任意フォルダ内に[プロダクトID]_[販売単位ID]_01～05.jpgファイルがあったら登録します
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @param $abstractUser system_login_AbstractUser実装インスタンス参照
	 * @param $targetFolderUri 登録画像ファイルをアップロードした公開URI
	 * @return boolean エラーがないならtrue
	 * @param boolean $override 上書き登録する場合はtrue,falseの場合は既に画像登録があるものには登録しない
	 */
	function importImageFiles( & $request, & $abstractUser, $targetFolderUri, $override=false ) {
		$dbo	= $request->getAttribute( 'dbo' );
		if( preg_match('/\\/$/',$targetFolderUri) == 0 ) {
			$targetFolderUri	.= '/';
		}
		if( !is_array($this->fileIdArray) ) {
			$this->fileIdArray	= array();
		}
		for( $i=1; $i<=10; $i++ ) {
			if( $override !== true && isset($this->fileIdArray[$i])
			&& strlen(trim($this->fileIdArray[$i])) > 0 ){
				// 上書き指定出ない場合にファイル登録が既にあるなら次のループへ
				continue;
			}
			$imageFileName	= $this->product_id.'_'.$this->unit_id.'_'.sprintf('%02d',$i).'.jpg';
			$fileUri		= $targetFolderUri.$imageFileName;
			spider_Controller::loadClassDefinition('system_DataFileWriter');
			$registFilePath	= system_DataFileWriter::getFilePathOnAnyHost( $request, $fileUri, 'public' );
			if( is_null($registFilePath) || strlen($registFilePath) == 0 ){
				$imageFileName	= $this->product_id.'_'.$this->unit_id.'_'.sprintf('%02d',$i).'.JPG';
				$fileUri		= $targetFolderUri.$imageFileName;
				spider_Controller::loadClassDefinition('system_DataFileWriter');
			}
			if( !is_null($registFilePath) && strlen($registFilePath) > 1 ) {
				// ファイルが分散サーバいずれかに存在すれば処理
				$deleteFileId	= $this->fileIdArray[($i-1)];
				if( strlen($deleteFileId) > 0 ) {
					$fileBinObject	= spider_Controller::createObject('file_DaoFileBin');
					if( $dbo->loadById( $fileBinObject, $deleteFileId ) ) {
						if($fileBinObject->deleteFileAll( $request ) ) {
							$dbo->delete( $fileBinObject );
						} else {
							$request->addLocaledError('system.error.common.file.delete',SPIDER_LOG_LEVEL_ERROR,array($imageFileName));
						}
					}
				}
				// 新しいファイルを登録
				$fileBinObject					= spider_Controller::createObject('file_DaoFileBin');
				$fileBinObject->file_name		= $imageFileName;
				$fileBinObject->file_size		= filesize( $registFilePath );
				$fileBinObject->extension		= 'jpg';
				$fileBinObject->mime_type		= 'image/jpeg';
				$fileBinObject->owner_id		= $abstractUser->getUniqueId();
				$fileBinObject->modifier_id		= $abstractUser->getUniqueId();
				$fileBinObject->updated_date	= date('Y-m-d H:i:s');
				$fileBinObject->registered_date	= date('Y-m-d H:i:s');
				$fileBinObject->file_id			= null;
				if( false !== $imageInfoHash = $fileBinObject->getImageInfo( $request ) ) {
					// 画像ファイルで情報を取得できた場合
					if( $imageInfoHash[0] > SHOPPING_PRODUCT_IMAGE_MAX_WIDTH
						|| $imageInfoHash[1] > SHOPPING_PRODUCT_IMAGE_MAX_HEIGHT ) {
						// 幅か高さがshoppingパッケージ設定上限値を超えているならリサイズ
						spider_Controller::loadClassDefinition('util_File');
						if( util_File::resizeImage( $registFilePath, $registFilePath, SHOPPING_PRODUCT_IMAGE_MAX_WIDTH, SHOPPING_PRODUCT_IMAGE_MAX_HEIGHT, 'ffffff' ) ) {
						} else {
							$request->addLocaledError('system.error.common.file.resize',SPIDER_LOG_LEVEL_ERROR,array($imageFileName));
							break;
						}
					}
				}
				// データベース登録
				if( $dbo->setNextId( $fileBinObject, 'FDAAAA{num:18}') ) {
					if( $dbo->insert( $fileBinObject ) ) {
						// インサートに成功したらファイルを保存フォルダに移動する
						if( $saveRootPath = $fileBinObject->getSaveRootPath( $request, true ) ) {
							// 保存フォルダ作成に成功したらファイルを保存パスに移動
							if( @copy( $registFilePath, $fileBinObject->getOriginalFilePath( $request ) ) ) {
								@chmod($fileBinObject->getOriginalFilePath( $request ),0666);
								if( is_writable($this->cacheContentPath) ) {
									@unlink($registFilePath);
								}
								$this->fileIdArray[($i-1)]	= $fileBinObject->file_id;
							} else {
								$request->addLocaledError('system.error.common.file.write',SPIDER_LOG_LEVEL_ERROR,array($imageFileName));
								break;
							}
						}
					} else {
						$request->addLocaledError('database2.error.insert',SPIDER_LOG_LEVEL_FATAL,array($imageFileName));
						break;
					}
				} else {
					$request->addLocaledError('database2.error.setnextid',SPIDER_LOG_LEVEL_FATAL,array($imageFileName));
					break;
				}
			} else {
				// ファイルが存在しない場合何もしない
			}
		}
		if( $request->isError() ) {
			return false;
		} else {
			return true;
		}
	}
	/**
	 * サーバー上の任意フォルダ内にdownload_01～05.txtファイルに指示記述があればダウンロードファイルを登録
	 * @param $request spider_HttpRequestオブジェクト参照
	 * @param $abstractUser system_login_AbstractUser実装インスタンス参照
	 * @param $targetFolderUri 登録画像ファイルをアップロードした公開URI
	 * @return boolean エラーがないならtrue
	 */
	function importDownloadFiles( & $request, & $abstractUser, $targetFolderUri ) {
		$dbo	= $request->getAttribute( 'dbo' );
		if( preg_match('/\\/$/',$targetFolderUri) == 0 ) {
			$targetFolderUri	.= '/';
		}
		if( !is_array($this->fileIdArray) ) {
			$this->fileIdArray	= array();
		}
		for( $num=1; $num<=10; $num++ ) {
			// 登録情報テキストファイルの確認
			$registInfoFileUri	= $targetFolderUri.'download_'.sprintf('%02d',$num).'.txt';
			spider_Controller::loadClassDefinition('system_DataFileWriter');
			if( !system_DataFileWriter::isExists( $request, $registInfoFileUri, 'public' ) ) {
				continue;
			} else {
				// ファイルがあるなら登録用情報を確認
				$registFileInfoHash	= array(
					'fileName'		=> null,
					'Content-Type'	=> null,
					'Target-User-Agent'	=> array(),
					'Additional-Header'	=> array(),
				);
				$registInfoText	= system_DataFileWriter::getContents( $request, $registInfoFileUri, 'public' );
				$registInfoText	= str_replace("\r\n","\n",$registInfoText);
				$registInfoText	= str_replace("\r","\n",$registInfoText);
				$regstInfoLines	= explode("\n",$registInfoText);
				foreach( $regstInfoLines as $line ) {
					$line		= trim($line);
					$elmArray	= explode('=',$line);
					$elmName	= trim(array_shift($elmArray));
					$elmValue	= trim(implode('=',$elmArray));
					if( 'fileName' == $elmName ) {
						$registFileInfoHash['fileName']	= $elmValue;
					} else if( 'Content-Type' == $elmName ) {
						$registFileInfoHash['Content-Type']	= $elmValue;
					} else if( 'Target-User-Agent' == $elmName ) {
						array_push($registFileInfoHash['Target-User-Agent'],$elmValue);
					} else if( 'Additional-Header' == $elmName ) {
						array_push($registFileInfoHash['Additional-Header'],$elmValue);
					}
				}
				if( strlen($registFileInfoHash['fileName']) > 0 ) {
					// 登録ファイルがあるか存在確認
					$registFileName	= str_replace('{product_id}',$this->product_id,$registFileInfoHash['fileName']);
					$registFileName	= str_replace('{unit_id}',$this->unit_id,$registFileName);
					$fileUri		= $targetFolderUri.$registFileName;
					$registFilePath	= system_DataFileWriter::getFilePathOnAnyHost( $request, $fileUri, 'public' );
					if( !is_null($registFilePath) && strlen($registFilePath) > 1 ) {
						// ファイルが分散サーバいずれかに存在すれば処理
						$deleteFileId	= $this->fileIdArray[($num-1+100)];
						if( strlen($deleteFileId) > 0 ) {
							$fileBinObject	= spider_Controller::createObject('file_DaoFileBin');
							if( $dbo->loadById( $fileBinObject, $deleteFileId ) ) {
								if($fileBinObject->deleteFileAll( $request ) ) {
									$dbo->delete( $fileBinObject );
								} else {
									$request->addLocaledError('system.error.common.file.delete',SPIDER_LOG_LEVEL_ERROR,array($registFileName));
								}
							}
						}
						// 新しいファイルを登録
						$fileBinObject						= spider_Controller::createObject('file_DaoFileBin');
						$fileBinObject->file_name			= $registFileName;
						$fileBinObject->file_size			= filesize( $registFilePath );
						$fileBinObject->extension			= pathinfo($registFilePath, PATHINFO_EXTENSION);
						$fileBinObject->mime_type			= $registFileInfoHash['Content-Type'];
						$fileBinObject->target_agent		= implode("\n",$registFileInfoHash['Target-User-Agent']);
						$fileBinObject->response_headers	= implode("\n",$registFileInfoHash['Additional-Header']);
						$fileBinObject->owner_id			= $abstractUser->getUniqueId();
						$fileBinObject->modifier_id			= $abstractUser->getUniqueId();
						$fileBinObject->updated_date		= date('Y-m-d H:i:s');
						$fileBinObject->registered_date		= date('Y-m-d H:i:s');
						$fileBinObject->file_id				= null;
						$fileBinObject->open_flag			= '1';
						// データベース登録
						if( $dbo->setNextId( $fileBinObject, 'SHPAAA{num:18}') ) {
							if( $dbo->insert( $fileBinObject ) ) {
								// インサートに成功したらファイルを保存フォルダに移動する
								if( $saveRootPath = $fileBinObject->getSaveRootPath( $request, true ) ) {
									// 保存フォルダ作成に成功したらファイルを保存パスに移動
									if( @copy( $registFilePath, $fileBinObject->getOriginalFilePath( $request ) ) ) {
										@chmod($fileBinObject->getOriginalFilePath( $request ),0666);
										if( is_writable($this->cacheContentPath) ) {
											@unlink($registFilePath);
										}
										$this->fileIdArray[($num-1+100)]	= $fileBinObject->file_id;
									} else {
										$request->addLocaledError('system.error.common.file.write',SPIDER_LOG_LEVEL_ERROR,array($registFilePath));
										break;
									}
								}
							} else {
								$request->addLocaledError('database2.error.insert',SPIDER_LOG_LEVEL_FATAL,array($registFilePath));
								break;
							}
						} else {
							$request->addLocaledError('database2.error.setnextid',SPIDER_LOG_LEVEL_FATAL,array($registFilePath));
							break;
						}
					}
				}
			}
		}
		if( $request->isError() ) {
			return false;
		} else {
			return true;
		}
	}
	/**
	 * 渡されたAbstractDataオブジェクトに対する編集権限があるか確認します
	 * @param &$request spider_HttpRequestオブジェクト
	 * @param $abstractUser system_login_AbstractUser実装クラスインスタンス
	 */
	function canEditData( & $request, $abstractUser ) {
		if( is_a($abstractUser,'system_login_UserAdministrator') ) {
			// システム管理者ならtrue
			return true;
		} else if( is_a($abstractUser,'admin_DaoAdminMember') ) {
			// adminパッケージのログインユーザの場合
			return true;
		} else if( is_a($abstractUser,'member_DaoMember') ) {
			// memberパッケージのログインユーザなら自分自身はtrue
			if( $this->owner_id == $abstractUser->member_id ) {
				return true;
			} else {
				return false;
			}
		} else {
			// パッケージユーザ以外は編集不可
			return false;
		}
	}
	/**
	 * 渡されたAbstractDataオブジェクトのステータスフラグの編集権限があるか確認します
	 * @param &$request spider_HttpRequestオブジェクト
	 * @param $abstractUser system_login_AbstractUser実装クラスインスタンス
	 */
	function canEditStatus( & $request, $abstractUser ) {
		if( is_a($abstractUser,'system_login_UserAdministrator') ) {
			// システム管理者ならtrue
			return true;
		} else if( is_a($abstractUser,'admin_DaoAdminMember') ) {
			// adminパッケージのログインユーザの場合
			return true;
		} else if( is_a($abstractUser,'member_DaoMember') ) {
			// memberパッケージのログインユーザの場合
			if ( $this->status_flag_org == 0 ) {
				// ステータスが新規の場合、編集不可
				return false;
			} else if ( $this->status_flag_org == 101 || $this->status_flag_org == 91 ) {
				// 変更前のステータスが掲載中、又は非公開の場合、新規以外のステータスへ編集可能
				if ( $this->status_flag == 0 ) {
					return false;
				} else {
					return true;
				}
			} else if ( $this->status_flag_org > 200 ) {
				// ステータスが削除の場合、編集不可
				return false;
			} else {
				return false;
			}
		} else {
			// パッケージユーザ以外は編集不可
			return false;
		}
	}
	/**
	 * 予約可能営業開始日数を取得
	 */
	function getReserveEnableStartDays(&$request) {
		if( is_null($this->rsv_permit_start)
		|| preg_match('/^[0-9]{1,3}$/',$this->rsv_permit_start) == 0
		|| $this->rsv_permit_start <= 0 ) {
			return 0;
		} else {
			return $this->rsv_permit_start;
		}
	}
	/**
	 * 予約可能営業終了日数を取得
	 */
	function getReserveEnableLimitDays(&$request) {
		if( is_null($this->rsv_permit_limit)
		|| preg_match('/^[0-9]{1,3}$/',$this->rsv_permit_limit) == 0
		|| $this->rsv_permit_limit <= 0 ) {
			return 0;
		} else {
			return $this->rsv_permit_limit;
		}
	}
	/**
	 * 現在時間から起算した予約可能開始時間タイムスタンプを取得
	 * @param &$request spider_HttpRequestオブジェクト
	 */
	function getReserveEnableStartTime( & $request ) {
		$days		= $this->getReserveEnableStartDays($request);
		// 営業日計算
		$countDays	= 0;
		// 当月から半年分順にカウントが$daysになるまで営業日を取得する
		$nowMonthSTime	= strtotime(date('Y-m-01 00:00:00'));
		require_once(dirname(__FILE__).DIRECTORY_SEPARATOR.'calendar'.DIRECTORY_SEPARATOR.'Load.class.php');
		for( $num=0; $num<6; $num++ ) {
			$targetSTime	= strtotime('+ '.$num.' month',$nowMonthSTime);
			$dayHash		= shopping_calendar_Load::getUnitMonthScheduleHash(
				$request, date('Y',$targetSTime), date('m',$targetSTime), $this->unit_id );
			if( is_array($dayHash) ) {
				foreach( $dayHash as $day => $infoArray ) {
					$targetDate	= date('Y-m-'.$day.' 00:00:00',$targetSTime);
					if( time() <= strtotime($targetDate) ) {
						$countDays++;
						if( $countDays >= $days ) {
							// カウントが指定日数に達したらその日のタイムスタンプを返す
							return strtotime($targetDate);
						}
					}
				}
			}
		}
		return time();
	}
	/**
	 * 現在時間から起算した予約可能終了時間タイムスタンプを取得
	 * @param &$request spider_HttpRequestオブジェクト
	 */
	function getReserveEnableLimitTime( & $request ) {
		$days	= $this->getReserveEnableLimitDays($request);
		if( $days % 30 == 0 ) {
			// 30日区切りで入力されているなら月単位と見なす
			$months	= $days / 30;
			$date	= date('Y-m-d 23:59:59',strtotime('+ '.$months.' month'));
			return strtotime($date);
		} else {
			$date	= date('Y-m-d 23:59:59',strtotime('+ '.$days.' day'));
			return strtotime($date);
		}
	}
	/**
	 * 注文オプションがあるか確認します
	 * @return boolean オプションを保持しているならtrue
	 * @deprecated 1.2
	 */
	function hasOrderOption() {
		for( $optionOrder=1; $optionOrder<=5; $optionOrder++ ) {
			$optionNameVarName		= 'option'.$optionOrder.'_name';
			$optionNameArrayName	= 'option'.$optionOrder.'_item_array';
			if( isset($this->$optionNameVarName)
				&& strlen($this->$optionNameVarName) > 0 ) {
				return true;
			} else if( isset($this->shoppingProductObject)
				&& is_object($this->shoppingProductObject)
				&& isset($this->shoppingProductObject->$optionNameVarName)
				&& strlen($this->shoppingProductObject->$optionNameVarName) > 0 ) {
				return true;
			}
		}
		return false;
	}
	/**
	 * 表示画像のURIを取得
	 */
	function getImageUri( & $request, $imageNumber=0, $maxWidth=null, $maxHeight=null ) {
		$fileId	= null;
		if( isset($this->fileIdArray[$imageNumber]) ) {
			$fileId	= $this->fileIdArray[$imageNumber];
		}
		if( is_null($fileId) || strlen($fileId) == 0 ) {
			return false;
		}
		spider_Controller::loadClassDefinition('file_DaoFileBin');
		return file_DaoFileBin::getPublicCacheUri( $request,$fileId,$maxWidth,$maxHeight);
	}
	//
	// 非推奨メソッド
	//
	/**
	 * 付加情報読み込み
	 * @deprecated
	 */
	function _load_optional_data( $dbo ) {
		return $this->loadRelation( $dbo );
	}
}
?>