diff --git a/hwe/sammo/Auction.php b/hwe/sammo/Auction.php index e4c127c9..e390cee5 100644 --- a/hwe/sammo/Auction.php +++ b/hwe/sammo/Auction.php @@ -2,6 +2,9 @@ namespace sammo; +use DateTime; +use DateTimeImmutable; +use DateTimeInterface; use Ds\Map; use sammo\DTO\AuctionBidItem; use sammo\DTO\AuctionBidItemData; @@ -45,11 +48,41 @@ class Auction if (!$prevAuction->info->finished) { return '아직 경매가 끝나지 않았습니다.'; } + unset($openedAuction[$info->reqResource->value]); + $general->setAuxVar('openedAuction', $openedAuction); } $auctionStor->setValue("id_{$auctionID}", $info->toArray()); } + public function getHighestBid(): AuctionBidItem + { + $db = DB::db(); + $rawHighestBid = $db->queryFirstRow( + 'SELECT * FROM ng_auction WHERE auction_id = %i ORDER BY `amount` DESC LIMIT 1', + $this->info->id + ); + if(!$rawHighestBid){ + throw new \Exception('입찰이 없습니다.'); + } + + return AuctionBidItem::fromArray($rawHighestBid); + } + + public function getMyPrevBid(): ?AuctionBidItem + { + $db = DB::db(); + $rawMyPrevBid = $db->queryFirstRow( + 'SELECT * FROM ng_auction WHERE general_id = %i AND auction_id = %i ORDER BY `amount` DESC LIMIT 1', + $this->general->getID(), + $this->info->id + ); + if (!$rawMyPrevBid) { + return null; + } + return AuctionBidItem::fromArray($rawMyPrevBid); + } + public function __construct(private readonly int $auctionID, private General $general) { $db = DB::db(); @@ -61,7 +94,66 @@ class Auction $this->info = AuctionInfo::fromArray($rawAuctionInfo); } - public function closeAuction(): void + public function getInfo(): AuctionInfo + { + return $this->info; + } + + public function extendCloseDate(DateTimeInterface $date): void + { + $db = DB::db(); + $auctionStor = KVStorage::getStorage($db, 'auction'); + $this->info->closeDate = DateTimeImmutable::createFromInterface($date); + $auctionStor->setValue("id_{$this->info->id}", $this->info->toArray()); + } + + public function refundBid(AuctionBidItem $bidItem, string $reason): void + { + if($bidItem->auctionID !== $this->info->id){ + throw new \RuntimeException('잘못된 경매입니다.'); + } + + $db = DB::db(); + if($bidItem->generalID === $this->general->generalID) { + $oldBidder = $this->general; + } else { + $oldBidder = General::createGeneralObjFromDB($bidItem->general_id); + } + + if($this->info->reqResource === ResourceType::inheritancePoint){ + $oldBidder->increaseInheritancePoint(InheritanceKey::previous, $bidItem->amount); + } + else{ + $oldBidder->increaseVar($this->info->reqResource->value, $bidItem->amount); + } + + $staticNation = $oldBidder->getStaticNation(); + $src = new MessageTarget(0, '', 0, 'System', '#000000'); + $dest = new MessageTarget( + $oldBidder->getID(), + $oldBidder->getName(), + $oldBidder->getNationID(), + $staticNation['name'], + $staticNation['color'], + GetImageURL($oldBidder->getVar('imgsvr'), $oldBidder->getVar('picture')) + ); + + //TODO: 전역 알림이 나타나야한다. 일반 메시지보다는 중요하고, 메시지보단 약하게.. + //TODO: 바로가기를 제공하는 편이 좋을 것 같다. + $msg = new Message( + Message::MSGTYPE_PRIVATE, + $src, + $dest, + $reason, + new DateTime(), + new DateTime('9999-12-31'), + [] + ); + $oldBidder->applyDB($db); + $msg->send(true); + } + + public function closeAuction(bool $isRollback = false): void { $db = DB::db(); $auctionStor = KVStorage::getStorage($db, 'auction'); @@ -73,25 +165,21 @@ class Auction unset($openedAuction[$this->info->reqResource->value]); $this->general->setAuxVar('openedAuction', $openedAuction); } + if ($isRollback) { + $this->refundBid($this->getHighestBid(), "{$this->info->title} 경매가 취소되었습니다."); + } $auctionID = $this->info->id; $auctionStor->setValue("id_{$auctionID}", $this->info->toArray()); } - private function bidInheritPoint(int $amount, ?int $priority, string $now): void + private function bidInheritPoint(int $amount, \DateTimeImmutable $now): void { $db = DB::db(); $auctionInfo = $this->info; $general = $this->general; - $rawHighestBid = $db->queryFirstRow( - 'SELECT * FROM ng_auction WHERE auction_id = %i ORDER BY `amount` DESC LIMIT 1', - $auctionInfo->id - ); - if (!$rawHighestBid) { - throw new \RuntimeException('최고 입찰가가 없습니다.'); - } - $highestBid = AuctionBidItem::fromArray($rawHighestBid); + $highestBid = $this->getHighestBid(); if ($amount <= $highestBid->amount) { throw new \RuntimeException('현재입찰가보다 높게 입찰해야 합니다.'); } @@ -109,7 +197,7 @@ class Auction $morePoint = $amount - ($myPrevBid ? $myPrevBid->amount : 0); $currPoint = $general->getInheritancePoint(InheritanceKey::previous); - if($currPoint === null || $currPoint < $morePoint){ + if ($currPoint === null || $currPoint < $morePoint) { throw new \RuntimeException('유산포인트가 부족합니다.'); } @@ -125,7 +213,6 @@ class Auction new AuctionBidItemData( $general->getVar('owner_name'), $general->getName(), - $priority ) ); $db->insert('ng_auction', $newBid->toArray()); @@ -134,18 +221,12 @@ class Auction $general->increaseRankVar(RankColumn::inherit_point_spent_dynamic, $morePoint); if ($myPrevBid === null || $myPrevBid->id !== $highestBid->id) { - $oldBidder = General::createGeneralObjFromDB($highestBid->general_id); - $oldBidder->increaseInheritancePoint(InheritanceKey::previous, $highestBid->amount); - //TODO: 전역 알림이 나타나야한다. - $oldBidder->getLogger()->pushGeneralActionLog( - "유산포인트 {$auctionInfo->id}번 경매에 상회입찰이 되었습니다.", - ); - $oldBidder->applyDB($db); + $this->refundBid($highestBid, "{$auctionInfo->title} 경매에 상회입찰자가 나타났습니다."); } $general->applyDB($db); } - public function bid(int $amount, ?int $priority): void + public function bid(int $amount): void { $auctionInfo = $this->info; $general = $this->general; @@ -154,7 +235,7 @@ class Auction throw new \RuntimeException('경매가 이미 끝났습니다.'); } - $now = TimeUtil::now(); + $now = new \DateTimeImmutable(); if ($auctionInfo->closeDate < $now) { throw new \RuntimeException('경매가 이미 끝났습니다.'); @@ -168,7 +249,7 @@ class Auction } if ($auctionInfo->reqResource === ResourceType::inheritancePoint) { - $this->bidInheritPoint($amount, $priority, $now); + $this->bidInheritPoint($amount, $now); return; } @@ -188,16 +269,7 @@ class Auction throw new \RuntimeException('현재입찰가보다 높게 입찰해야 합니다.'); } - $rawMyPrevBid = $db->queryFirstRow( - 'SELECT * FROM ng_auction WHERE general_id = %i AND auction_id = %i ORDER BY `amount` DESC LIMIT 1', - $general->getID(), - $auctionInfo->id - ); - if ($rawMyPrevBid === null) { - $myPrevBid = null; - } else { - $myPrevBid = AuctionBidItem::fromArray($rawMyPrevBid); - } + $myPrevBid = $this->getMyPrevBid(); $morePoint = $amount - ($myPrevBid ? $myPrevBid->amount : 0); $resType = $auctionInfo->reqResource; @@ -222,7 +294,6 @@ class Auction new AuctionBidItemData( $general->getVar('owner_name'), $general->getName(), - $priority ) ); $db->insert('ng_auction', $newBid->toArray()); @@ -230,13 +301,7 @@ class Auction $general->setVar($resType->value, $general->getVar($resType->value) - $morePoint); if ($myPrevBid === null || $myPrevBid->id !== $highestBid->id) { - $oldBidder = General::createGeneralObjFromDB($highestBid->general_id); - $oldBidder->increaseVar($resType->value, $highestBid->amount); - //TODO: 전역 알림이 나타나야한다. - $oldBidder->getLogger()->pushGeneralActionLog( - "{$resType->getName()} {$auctionInfo->id}번 경매에 상회입찰이 되었습니다.", - ); - $oldBidder->applyDB($db); + $this->refundBid($highestBid, "{$auctionInfo->title} 경매에 상회입찰자가 나타났습니다."); } $general->applyDB($db); } diff --git a/hwe/sammo/DTO/AuctionBidItem.php b/hwe/sammo/DTO/AuctionBidItem.php index d16beffc..d4eecc84 100644 --- a/hwe/sammo/DTO/AuctionBidItem.php +++ b/hwe/sammo/DTO/AuctionBidItem.php @@ -2,9 +2,11 @@ namespace sammo\DTO; +use sammo\DTO\Attr\Convert; use sammo\DTO\Attr\JsonString; use sammo\DTO\Attr\NullIsUndefined; use sammo\DTO\Attr\RawName; +use sammo\DTO\Converter\DateTimeConverter; class AuctionBidItem extends DTO { @@ -20,7 +22,8 @@ class AuctionBidItem extends DTO public int $amount, - public string $date, + #[Convert(DateTimeConverter::class)] + public \DateTimeImmutable $date, #[JsonString] public AuctionBidItemData $data, ) { diff --git a/hwe/sammo/DTO/AuctionBidItemData.php b/hwe/sammo/DTO/AuctionBidItemData.php index 76d51e9d..41478689 100644 --- a/hwe/sammo/DTO/AuctionBidItemData.php +++ b/hwe/sammo/DTO/AuctionBidItemData.php @@ -10,8 +10,6 @@ class AuctionBidItemData extends DTO #[NullIsUndefined] public ?string $ownerName, public string $generalName, - #[NullIsUndefined] - public ?int $priority, ) { } } diff --git a/hwe/sammo/DTO/AuctionInfo.php b/hwe/sammo/DTO/AuctionInfo.php index 7534081c..6854ed37 100644 --- a/hwe/sammo/DTO/AuctionInfo.php +++ b/hwe/sammo/DTO/AuctionInfo.php @@ -2,6 +2,8 @@ namespace sammo\DTO; +use sammo\DTO\Attr\Convert; +use sammo\DTO\Converter\DateTimeConverter; use sammo\Enums\ResourceType; class AuctionInfo extends DTO @@ -11,12 +13,16 @@ class AuctionInfo extends DTO public int $openerName, public int $openerGeneralID, public string $type, + public string $title, public bool $finished, public ResourceType $reqResource, public int $minAmount, public ?int $buyImmediatelyAmount, - public string $openDate, - public string $closeDate, + + #[Convert(DateTimeConverter::class)] + public \DateTimeImmutable $openDate, + #[Convert(DateTimeConverter::class)] + public \DateTimeImmutable $closeDate, ) { } }