<?php
namespace Diplix\KMGBundle\Repository;
use Diplix\KMGBundle\Controller\Rating\RatingController;
use Diplix\KMGBundle\Entity\Accounting\CoopMember;
use Diplix\KMGBundle\Entity\Order;
use Diplix\KMGBundle\Entity\OrderStatus;
use Diplix\KMGBundle\Entity\Rating;
use Diplix\KMGBundle\Entity\User;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\QueryBuilder;
use PDO;
class OrderRepository extends BasicRepository
{
public function findHistoryFor(Order $o)
{
$st = $this->dbQuery("SELECT A.*,B.username, B.first_name,B.last_name
FROM syslog A
LEFT JOIN users B ON B.id = A.user_id
WHERE ref_entity = :class
AND ref_id = :id
ORDER BY log_time DESC
LIMIT 0,20",
array("class"=>get_class($o),"id"=>$o->getId()));
$res = $st->fetchAllAssociative();
if (count($res)>0)
for ($i=0; $i < count($res); $i++)
{
$res[$i]["log_time"] = new \DateTime($res[$i]["log_time"]);
if ($res[$i]["changeset"]!="[]") $res[$i]["message"] .= $res[$i]["changeset"];
}
return $res;
}
public function countByDay($from,$to,$userList = [], $customerId=0)
{
$sql = "SELECT DATE_FORMAT(order_time,'%Y-%m-%d') AS day, COUNT(*) AS cnt
FROM orders
WHERE order_time >= :from AND order_time <= :to
";
$params = array("from"=>$from->format("Y-m-d"),"to"=>$to->format("Y-m-d"));
if ($customerId > 0)
{
$sql .= " AND customer_id = :cid";
$params["cid"] = $customerId;
}
if ($userList != null )
{
if (count($userList)<1) throw new \Exception("No userlist provided.");
$sql .= "AND be_owner IN (:userlist)";
$params["userlist"] = implode(",",array_map(function($u){return (int)$u->getId();},$userList));
}
$sql .= "
GROUP BY day
ORDER BY day ASC";
$st = $this->dbQuery($sql,$params);
$list = $st->fetchAllAssociative();
$ret = [];
foreach ($list as $l)
{
$ret[$l["day"]] = $l["cnt"];
}
return $ret;
}
public function findForTamiStatusUpdate()
{
$qb = $this->createQueryBuilder("A")
->select("A,B,C,S")
->leftJoin("A.customer","B")
->leftJoin("A.beOwner","C")
->leftJoin("A.orderStatus","S")
->where("A.remoteStatus = :rs")
->setParameter("rs",Order::REMOTE_SUCCESS)
->andWhere("A.orderStatus < 3"); // 1==offen,2==vermittelt,3==erledigt, > 3 = fehler/storno/...
return $qb->getQuery()->getResult(AbstractQuery::HYDRATE_OBJECT);
}
/** @return QueryBuilder */
public function getQb(): QueryBuilder
{
return $this->createQueryBuilder("A")
->select("A,B,C,S,D,R,P,M,X,J")
->leftJoin("A.customer","B")
->leftJoin("A.beOwner","C")
->leftJoin("A.orderStatus","S")
->leftJoin('A.paymentType','P')
->leftJoin("A.addressList","D")
->leftJoin("A.referencedParentOrder","R")
->leftJoin('A.assignedTo','M')
->leftJoin("A.xchgTo","X")
->leftJoin("A.job","J");
}
/**
* @param array $userList
* @param int $customerId
* @param $filterStatus
* @param int $from
* @param int $to
* @param int $assignedTo
* @return array
* @throws \Exception
*/
public function findAllForOverview($userList = array(), $customerId=0, $filterStatus,$from=0, $to=0,$assignedTo=0)
{
$qb = $this->getQb();
if ($userList != null )
{
if (count($userList)<1) throw new \Exception("No userlist provided.");
$or = $qb->expr()->orX();
foreach ($userList as $u)
{
$or->add(sprintf("A.beOwner = '%d'",$u->getId()));
}
$qb->where($or);
}
if ($customerId > 0)
{
$qb->andWhere("B.id = :cid")
->setParameter("cid",$customerId);
}
if ($assignedTo > 0)
{
$qb->andWhere("A.assignedTo = :mm")
->setParameter('mm',$assignedTo);
}
if (is_array($filterStatus))
{
$qb->andWhere( $qb->expr()->in('A.orderStatus',':hiddenStati'))
->setParameter('hiddenStati',$filterStatus);
}
else
if ($filterStatus>0)
{
$qb->andWhere("A.orderStatus = :os")
->setParameter("os",$filterStatus);
}
if (is_object($from))
{
$qb->andWhere("A.orderTime >= :start")
->setParameter("start",$from);
}
if (is_object($to))
{
$qb->andWhere("A.orderTime <= :to")
->setParameter("to",$to);
}
$qb->orderBy("A.orderTime");
return $qb->getQuery()->getResult(AbstractQuery::HYDRATE_ARRAY);
}
public function getSingleAsArray($id)
{
$qb = $this->getQb();
$qb->andWhere('A.id = :id')->setParameter('id',$id);
return $qb->getQuery()->getSingleResult(AbstractQuery::HYDRATE_ARRAY);
}
public function getPendingInstantOrdersForDispo($hydrationMode = AbstractQuery::HYDRATE_ARRAY)
{
$limit = new \DateTime();
$limit->modify('-7 days');
$qb = $this->getQb();
$qb->where(
$qb->expr()->orX(
$qb->expr()->eq('A.instantOrderStatus',Order::INSTANT_ORDER_REQUEST_PENDING),
$qb->expr()->andX(
$qb->expr()->gte('A.instantOrderStatus',Order::INSTANT_ORDER_REQUEST_PENDING),
$qb->expr()->gte('A.instantOrderInitiated',':timelimit')
)
)
)
->setParameter('timelimit',$limit->format('Y-m-d H:i'))
->orderBy('A.instantOrderInitiated','desc');
return $qb->getQuery()->getResult($hydrationMode);
}
public function getPendingInstantOrder(User $forUser, $hydrationMode = AbstractQuery::HYDRATE_ARRAY)
{
$limit = new \DateTime();
$limit->modify('-7 days');
$qb = $this->getQb();
$qb->andWhere('A.beOwner = :owner')
->andWhere(
$qb->expr()->orX(
$qb->expr()->eq('S.id',OrderStatus::STATUS_INSTANT_ORDER_PENDING),
$qb->expr()->andX(
$qb->expr()->gte('A.instantOrderStatus',Order::INSTANT_ORDER_REQUEST_PENDING),
$qb->expr()->gte('A.instantOrderInitiated',':timelimit')
)
)
)
->setParameter('owner',$forUser->getId())
->setParameter('timelimit',$limit->format('Y-m-d H:i'))
->orderBy('A.instantOrderInitiated','desc');
return $qb->getQuery()->getResult($hydrationMode);
}
/**
* Find all Orders for customers with showRating=1 which are not yet rated
* @param $customerId int customer.id or -1 for all customers
* @param null $userList
* @return array
* @throws \Exception
*/
public function findUnrated($customerId,$userList = null,$maxDaysIntoPast=null)
{
if ($maxDaysIntoPast===null) $maxDaysIntoPast = RatingController::MAX_AGE_FOR_RATING_DAYS;
$maxPast = (new \DateTime())->sub(new \DateInterval(sprintf("P%dD", $maxDaysIntoPast)));
$now = (new \DateTime())->sub(new \DateInterval(sprintf("PT%dH", 2)));
$qb = $this->createQueryBuilder("A")
->select("A,B")
->leftJoin("A.customer","B")
->where("A.orderStatus = :os")
->setParameter("os",OrderStatus::STATUS_FINISHED)
->andWhere("A.orderTime > :limit")
->setParameter("limit",$maxPast)
->andWhere("A.orderTime < :now")
->setParameter("now",$now)
->andWhere("B.showRating = '1'");
if ($customerId>=0)
{
$qb->andWhere("B.id = :cid")
->setParameter("cid",$customerId);
}
if ($userList != null )
{
if (count($userList)<1) throw new \Exception("No userlist provided.");
$or = $qb->expr()->orX();
foreach ($userList as $u)
{
$or->add(sprintf("A.beOwner = '%d'",$u->getId()));
}
$qb->andWhere($or);
}
$qb->orderBy("A.orderTime");
$all = $qb->getQuery()->getResult(AbstractQuery::HYDRATE_OBJECT);
$ids = [];
/** @var Order $order */
foreach ($all as $order)
{
$ids[]= $order->getId();
}
$ratingRepo = $this->_em->getRepository(Rating::class);
$exist = $ratingRepo->findExistingRatings($ids);
$newResult = [];
foreach ($all as $order)
{
if (!in_array($order->getId(),$exist))
$newResult[]=$order;
}
return $newResult;
}
public function findByTamiOrderNumbers(array $list)
{
$qb = $this->createQueryBuilder("A")
->select("A,B,C,S,D,R")
->leftJoin("A.customer","B")
->leftJoin("A.beOwner","C")
->leftJoin("A.orderStatus","S")
->leftJoin("A.addressList","D")
->leftJoin("A.referencedParentOrder","R");
$qb->where($qb->expr()->in('A.remoteOrderId',$list));
$all = $qb->getQuery()->getResult();
$ret = [];
/** @var Order $one */
foreach ($all as $one)
{
$ret[$one->getRemoteOrderId()] = $one;
}
return $ret;
}
public function findOpenNotInSyncWithTami()
{
$last = (new \DateTime())->sub(new \DateInterval("P14D"));
$qb = $this->getQb();
$qb ->where($qb->expr()->in("A.orderStatus",":status"))->setParameter("status",[OrderStatus::STATUS_OPEN,OrderStatus::STATUS_CANCELED])
->andWhere("A.remoteStatus != :remoteStatus")->setParameter("remoteStatus", Order::REMOTE_SUCCESS)
->andWhere("A.orderTime > :last")->setParameter("last",$last)
->orderBy("A.orderTime",'desc');
return $qb->getQuery()->getResult();
}
public function getNewOrderId($date = null)
{
if ($date === null) $date = new \DateTime();
// Format: YYMMDDXXX
$prefix = $date->format("ymd"); // length of prefix = 6
// MySQL: For all forms of SUBSTRING(), the position of the first character in the string from which the substring is to be extracted is reckoned as 1.
$st = $this->dbQuery("
SELECT MAX(CAST(SUBSTRING(order_id,7) AS UNSIGNED)) FROM orders
WHERE order_id LIKE :pattern
AND be_deleted = '0'
", array("pattern"=>$prefix. "%"));
$max = $st->fetchOne();
if ($max === false) $max = 0;
if ($max >= 999)
{
throw new \Exception("Reached max. order number limit on this day !");
}
return sprintf("%s%03d",$prefix,$max+1);
}
public function findAssignedToAnyMemberForDay($day, $sortByMemberId = true, $specificMember = null)
{
$from = clone $day;
$until = clone $day;
$from->modify('today'); // start of day
$until->modify('tomorrow')->modify('1 second ago'); // end of day
$list = $this->findAssignedToAnyMemberForDateRange($from,$until,$specificMember);
if ($sortByMemberId)
{
$sorted = [];
/** @var Order $item */
foreach ($list as $item)
{
$mid = $item->getAssignedTo()->getId();
if (!array_key_exists($mid,$sorted)) $sorted[$mid] = [];
$sorted[$mid] []= $item;
}
return $sorted;
}
return $list;
}
public function findNotAssignedToAnyMemberForDateRange($dateFrom, $dateUntil)
{
return $this->_findAssignedToAnyMemberOrNotForDateRange($dateFrom,$dateUntil,null,true);
}
public function findAssignedToAnyMemberForDateRange($dateFrom, $dateUntil, $specificMember=null)
{
return $this->_findAssignedToAnyMemberOrNotForDateRange($dateFrom,$dateUntil,$specificMember,false);
}
protected function _findAssignedToAnyMemberOrNotForDateRange($dateFrom, $dateUntil, $specificMember, $notAssignedToAnyMember)
{
$qb = $this->getQb();
$ex = $qb->expr();
$qb->andWhere($ex->gte("A.orderTime", ':from' ),$ex->lte("A.orderTime", ':until' ))
->setParameter('from',$dateFrom)
->setParameter('until',$dateUntil);
$qb->andWhere('A.orderStatus < :s')->setParameter('s',OrderStatus::STATUS_CANCELED);
if ($specificMember != null)
{
$qb->andWhere('A.assignedTo = :m')->setParameter('m',$specificMember);
}
else
{
if ($notAssignedToAnyMember)
$qb->andWhere('A.assignedTo is null');
else
$qb->andWhere('A.assignedTo is not null');
}
$qb->addOrderBy('A.orderTime','asc');
return $qb->getQuery()->getResult();
}
public function findAssignedButNotConfirmedFor(CoopMember $specificMember)
{
$qb = $this->getQb();
$maxPast = (new \DateTime())->modify('-1 days');
$qb ->andWhere($qb->expr()->gte("A.orderTime", ':from' ))->setParameter('from',$maxPast)
->andWhere('A.assignedTo = :m')->setParameter('m',$specificMember)
->andWhere('A.assignmentConfirmed = 0')
->addOrderBy('A.orderTime','asc');
return $qb->getQuery()->getResult();
}
}