_increments) { $this->_increments = $this->em ->getRepository('\Auction\Entity\Increment') ->findBy(array(), array('to' => 'ASC')); } foreach ($this->_increments as $incr) { if ($incr->from >= $price) { return $incr; } } return false; } /** * ExecuteAfter: Create. * Handle bidding details. * @param array $meta * @param object|null $jobRecord * @param object|null $record * @param \Workspace\Utility\ServiceInputParams $contract * @return array */ public function updateStatus($meta, $auction, $record, \Workspace\Utility\ServiceInputParams $contract) { #-> Collect some info. $basket = $this->em ->getRepository('\Auction\Entity\Basket') ->findOneBy(array( 'auction' => $auction->id, 'company' => $record->company->id )); if (is_null($basket)) { $basket = new \Auction\Entity\Basket(); $basket->fromArray(array( 'auction' => $auction, 'company' => $record->company, 'profile' => $record->profile )); $this->em->persist($basket); $this->em->flush($basket); } elseif (true == $basket->archived) { $basket->archived = false; $this->em->flush($basket); } if ($auction->reservePrice > $record->amount) { $record->status = 'Archived'; $this->em->flush($record); throw new \Exception('Your bid was placed but you were just outbid.'); return; } $newCurrentBid = false; $newBid = null; $oldBid = null; $doNotify = false; #-> Lockdown some working space. $this->em->clear(); $this->em->getConnection()->beginTransaction(); $rsm = new \Doctrine\ORM\Query\ResultSetMappingBuilder($this->em); $rsm->addRootEntityFromClassMetadata('\Auction\Entity\Auction', 'auction'); $query = $this->em->createNativeQuery("SELECT * FROM auction WHERE id = :id FOR UPDATE", $rsm); $query->setParameter("id", $auction->id); $jobRecord = $query->getOneOrNullResult(); $cBidId = $jobRecord->currentBid ? $jobRecord->currentBid->id : 0; $aBidId = $jobRecord->currentBid && $jobRecord->currentBid->autoBid ? $jobRecord->currentBid->autoBid->id : 0; $record = $this->em->find('\Auction\Entity\AutoBid', $record->id); #-> Safety check. if ('Active' != $jobRecord->jobState || time() > $jobRecord->endDate->getTimestamp()) { $record->status = 'Archived'; $this->em->flush($record); $this->em->getConnection()->commit(); throw new \Exception('Your bid could not be placed. This auction item have been closed.'); return; } #-> Some more info. $base = $jobRecord->currentBidPrice != 0.0 ? $jobRecord->currentBidPrice : $jobRecord->reservePrice; $nextRule = $this->_getNextIncrement($base); $incr = $jobRecord->bidIncrement; #-> Process. // $jobRecord->numberOfBids++; //$record->amount = floor($record->amount / $incr) * $incr; //$record->amount = ($record->amount / $incr) * $incr; if ($nextRule && $base >= $nextRule->from) { $jobRecord->bidIncrement = $nextRule->amount; $incr = $nextRule->amount; $nextRule = $this->_getNextIncrement($base); } $base += $incr; if (is_null($jobRecord->currentBid)) { #-> First bid on this item. $atBid = new \Auction\Entity\Bid(); $atBid->fromArray(array( 'auction' => $jobRecord, 'company' => \Utility\Registry::resolveCompanyContext(null), 'profile' => \Utility\Registry::resolveProfileContext(null), 'autoBid' => $record, 'amount' => $jobRecord->reservePrice + $incr )); $this->em->persist($atBid); $this->em->flush($atBid); $newCurrentBid = true; $newBid = $atBid; $jobRecord->numberOfBids++; } elseif ($jobRecord->currentBidPrice + $incr >= $record->amount || $jobRecord->currentBid->company->id == $record->company->id) { #-> Late arrival or useless hack. $record->status = 'Archived'; $this->em->flush($record); if ($jobRecord->currentBid->company->id == $record->company->id) { throw new \Exception('Your bid was not successfull. Your dealership already has the winning bid.'); } else { throw new \Exception('Your bid was too low, please place a bid higher than R' . ($jobRecord->currentBidPrice + $incr)); } $doNotify = true; $oldBid = $record; // $jobRecord->numberOfBids++; } else { #-> Competing bids, figure it out. $doNotify = true; if (!is_null($jobRecord->currentBid->autoBid)) { #-> Auto-bid against existing auto-bid. $price = $jobRecord->currentBidPrice; $prevBid = $jobRecord->currentBid->autoBid->amount; $newBid = $record->amount; $win = false; $bidder = 0; // 0:prev auto, 1:new auto //error_log('Prev max: ' . $prevBid); //error_log('New max: ' . $newBid); while (!$win) { $price += $incr; $bidder = (0 == $bidder) ? 1 : 0; /* error_log((0 == $bidder) ? 'Previous bidder bids @ ' . $price : 'New bidder bids @ ' . $price); */ $autoMax = (0 == $bidder) ? $prevBid : $newBid; if ($price > $autoMax) { #-> Winning bid. //error_log('somebody is over max'); $price -= $incr; $win = true; if (1 == $bidder || $price <= $prevBid) { //error_log('Prev wins'); /* $atBid = new \Auction\Entity\Bid(); $atBid->fromArray(array( 'auction' => $jobRecord, 'company' => $jobRecord->currentBid->company, 'profile' => $jobRecord->currentBid->profile, 'autoBid' => $jobRecord->currentBid->autoBid, 'amount' => $price )); $this->em->persist($atBid); $this->em->flush($atBid); */ $newCurrentBid = true; $newBid = $atBid; $oldBid = $record; $record->status = 'Archived'; $this->em->flush($record); } else { //error_log('New wins'); /* $atBid = new \Auction\Entity\Bid(); $atBid->fromArray(array( 'auction' => $jobRecord, 'company' => $record->company, 'profile' => $record->profile, 'autoBid' => $record, 'amount' => $price )); $this->em->persist($atBid); $this->em->flush($atBid); */ $newCurrentBid = true; $newBid = $atBid; $oldBid = $jobRecord->currentBid; $jobRecord->currentBid->autoBid->status = 'Archived'; $jobRecord->currentBid->status = 'Archived'; // $jobRecord->numberOfBids++; $this->em->flush($jobRecord->currentBid->autoBid); $this->em->flush($jobRecord->currentBid); } } else { #-> Not-final bid. if (1 == $bidder) { $atBid = new \Auction\Entity\Bid(); $atBid->fromArray(array( 'auction' => $jobRecord, 'company' => $record->company, 'profile' => $record->profile, 'autoBid' => $record, 'amount' => $price )); $this->em->persist($atBid); $this->em->flush($atBid); } else { $atBid = new \Auction\Entity\Bid(); $atBid->fromArray(array( 'auction' => $jobRecord, 'company' => $jobRecord->currentBid->company, 'profile' => $jobRecord->currentBid->profile, 'autoBid' => $jobRecord->currentBid->autoBid, 'amount' => $price )); $this->em->persist($atBid); $this->em->flush($atBid); } $jobRecord->numberOfBids++; } if ($nextRule && $price >= $nextRule->from) { $jobRecord->bidIncrement = $nextRule->amount; $incr = $nextRule->amount; $nextRule = $this->_getNextIncrement($price); //$prevBid = floor($jobRecord->currentBid->autoBid->amount / $incr) * $incr; $prevBid = $jobRecord->currentBid->autoBid->amount; //$newBid = floor($record->amount / $incr) * $incr; $newBid = $record->amount; // $jobRecord->numberOfBids++; } } } else { #-> Auto-bid against bid. $price = $jobRecord->currentBidPrice + $incr; if ($record->amount >= $price) { $atBid = new \Auction\Entity\Bid(); $atBid->fromArray(array( 'auction' => $jobRecord, 'company' => $record->company, 'profile' => $record->profile, 'autoBid' => $record, 'amount' => $price )); $this->em->persist($atBid); $this->em->flush($atBid); $newCurrentBid = true; $newBid = $atBid; $oldBid = $jobRecord->currentBid; $jobRecord->currentBid->status = 'Archived'; $this->em->flush($jobRecord->currentBid); $jobRecord->numberOfBids++; } else { $oldBid = $record; $record->status = 'Archived'; $this->em->flush($record); } // $jobRecord->numberOfBids++; } } #-> Update auction with latest. if ($newCurrentBid) { $jobRecord->currentBid = $newBid; $jobRecord->currentBidPrice = $newBid->amount; if ($nextRule && $newBid->amount >= $nextRule->from) { $jobRecord->bidIncrement = $nextRule->amount; $incr = $nextRule->amount; } } #-> Expiry buffer. if (time() > ($jobRecord->endDate->getTimestamp() - 300)) { #-> Move end date out with 5 minutes. $jobRecord->endDate = new \DateTime( date('Y-m-d H:i:s', $jobRecord->endDate->getTimestamp() + 300) ); error_log($jobRecord->endDate->getTimestamp()); } $this->em->flush($jobRecord); #-> Unlock. $this->em->getConnection()->commit(); //\Utility\Doctrine::unlockTables(); #-> Notify clients with updated auction data. $vehicle = $jobRecord->stock->type->model->make->name . ', ' . $jobRecord->stock->type->model->name . ', ' . $jobRecord->stock->type->name . ' (' . $jobRecord->stock->vehicleYear->name . ')'; if ($newCurrentBid) { #-> Update stock entry. $jobRecord->stock->highestBid = $jobRecord->currentBidPrice; $this->em->flush(); #-> Chat to ape comet server. \Utility\Comms\Ape::broadcast('LiveAuction', array( 'id' => $jobRecord->id, 'current_bid' => $jobRecord->currentBid->toArray(array(), array(), 1), 'current_bid_id' => $jobRecord->currentBid->id, 'current_bid_price' => $jobRecord->currentBidPrice, 'number_of_bids' => $jobRecord->numberOfBids, 'expire_datetime' => $jobRecord->endDate->format(\Utility\Definitions\Locale::getDateTimeFormat()), 'winner' => $newBid->company->id, 'looser' => !is_null($oldBid) ? $oldBid->company->id : 0, 'basket' => $basket->toArray(array(), array(), 1), 'vehicle' => $vehicle )); } #-> Outbid notification. if ($newCurrentBid && $doNotify) { #-> Send email. $currPrefix = \Utility\Definitions\Locale::getCurrencyPrefix() . ' '; $oNotify = new \Utility\Comms\Notification(); $oNotify->sendFromTemplate( null, null, $oldBid->company->id, $oldBid->profile->id, null, $oldBid->profile->mobile, null, 'auction-outbid', array( 'first_name' => $oldBid->profile->firstName, 'family_name' => $oldBid->profile->familyName, 'vehicle' => $vehicle, 'seller' => $jobRecord->company->name, 'price' => $currPrefix . ($jobRecord->currentBidPrice + $incr), 'bid' => $currPrefix . $oldBid->amount, 'auction_expiry_date' => $jobRecord->endDate->format( \Utility\Definitions\Locale::getDateTimeFormat() ) )); } #-> Feedback. if ($newCurrentBid && $record->company->id != $newBid->company->id) { throw new \Exception('Your bid was placed but you were just outbid.'); } } }