initial commit
[namibia] / module / PriceGuide / src / PriceGuide / Service / PriceGuide.php
1 <?php
2 namespace PriceGuide\Service;
3
4
5
6 /**
7  * Manage PriceGuide data.
8  * @author andre.fourie
9  */
10 class PriceGuide extends \PriceGuide\DataBin\PriceGuide
11 {
12
13
14         /**
15          * New Price Guide Item from existing Valuation.
16          *
17          * @param \Valuation\Entity\Valuation $valuation
18          * @param string $previousState
19          * @param array $routingData
20          */
21         public function initNewItemFromValuation(
22                         \Valuation\Entity\Valuation $valuation, $previousState, array $routingData = array()
23                         )
24         {
25
26
27                 $prevListingId = is_object($valuation->stock->priceGuide)
28                         ? $valuation->stock->priceGuide->id
29                         : false;
30                 $record = $this->create(array(
31                         'valuation' => $valuation->id,
32                         'stock'     => $valuation->stock->id,
33                         'clubs'     => $routingData['clubs']
34                 ));
35                 $valuation->stock->priceGuide = $record;
36                 $valuation->stock->loadedOnPriceGuide = new \DateTime("now");
37                 $valuation->stock->highestOffer = 0.0;
38                 $this->em->flush($valuation);
39                 $authData = \Utility\Registry::getAuthData();
40                 $fromCompanyId  = isset($authData['company']['id']) ? $authData['company']['id'] : null;
41                 $fromProfileId  = isset($authData['id']) ? $authData['id'] : null;
42
43                 //$this->sendToMembers($record, $fromCompanyId, $fromProfileId);
44                 exec("php " . getcwd() . "/public/index.php priceguide notify "
45                                 . $record->id
46                                 . " $fromCompanyId $fromProfileId  >>/log/php.log &");
47
48                 // Send to the public user that his car has been send to price guide
49                 // do a check for isPublic
50                 if ($valuation->isPublic == true)
51                 {
52                         #-> Notify send to price guide - for the public user.
53                          $params = array(
54                         'firstName'     => $valuation->firstName,
55                         'familyName'    => $valuation->familyName,
56                         'year'                  => $valuation->stock->vehicleYear->name,
57                         'make'                  => $valuation->stock->type->model->make->name,
58                         'model'                 => $valuation->stock->type->model->name,
59                         'type'                  => $valuation->stock->type->name,
60                         'regNo'                 => $valuation->stock->registrationNumber
61                         );
62
63                          //\Utility\Debug::errorLog('send to priceguide from valuations', $params);
64
65                         $oNotify = new \Utility\Comms\Notification();
66                         $oNotify->sendFromTemplate(
67                                         $fromCompanyId, $fromProfileId,
68                                         '', '',
69                                         $valuation->email, null, null,
70                                         'new-public-to-priceguide',
71                                         $params
72                         );
73                 }
74
75
76
77
78                 if ($prevListingId)
79                 {
80                         $acceptedOffer = $this->em->getRepository('\PriceGuide\Entity\Offer')
81                                 ->findOneBy(array(
82                                                 'priceGuideStock' => $prevListingId,
83                                                 'status' => 'Offer Accepted'
84                                 ));
85                         #-> Expire all previous offers.
86                         $this->em->createQuery(
87                                         'UPDATE \PriceGuide\Entity\Offer o '
88                                         . "SET o.status = 'Expired' "
89                                         . 'WHERE IDENTITY(o.priceGuideStock) = '
90                                         . $prevListingId
91                                         )
92                                 ->execute();
93                         if ($acceptedOffer)
94                         {
95                                 #-> Re-create accepted offer as updateable.
96                                 $newOffer = new \PriceGuide\Entity\Offer();
97                                 $newOffer->priceGuideStock = $record;
98                                 $newOffer->company = $acceptedOffer->company;
99                                 $newOffer->profile = $acceptedOffer->profile;
100                                 $newOffer->amount = $acceptedOffer->amount;
101                                 $newOffer->status = 'Updateable Offer';
102                                 $this->em->persist($newOffer);
103
104                                 #-> Update stock entry with correct data.
105                                 $valuation->stock->numberOfOffers = 1;
106                                 $valuation->stock->highestOffer = $acceptedOffer->amount;
107
108                                 #-> Set price guide entry to status updateable offers.
109                                 $record->previousState = 'Open4Offers';
110                                 $record->jobState = 'Updateable Offers';
111                                 $this->em->flush();
112
113                                 #-> Notify accepted offer user of the relisting.
114                                 $params = array(
115                                                 'firstName'     => $acceptedOffer->profile->firstName,
116                                                 'familyName'    => $acceptedOffer->profile->familyName,
117                                                 'offerAmount'   => 'R' . $acceptedOffer->amount,
118                                                 'year'                  => $valuation->stock->vehicleYear->name,
119                                                 'make'                  => $valuation->stock->type->model->make->name,
120                                                 'model'                 => $valuation->stock->type->model->name,
121                                                 'type'                  => $valuation->stock->type->name,
122                                                 'regNo'                 => $valuation->stock->registrationNumber,
123                                                 'referenceNumber' => $valuation->stock->referenceNumber
124                                 );
125                                 $oNotify = new \Utility\Comms\Notification();
126                                 $oNotify->sendFromTemplate(
127                                                 $fromCompanyId, $fromProfileId,
128                                                 $acceptedOffer->company->id, $acceptedOffer->profile->id,
129                                                 $acceptedOffer->profile->email, null, null,
130                                                 'price-guide-offer-relist',
131                                                 $params
132                                 );
133                         }
134                 }
135         }
136
137         /**
138          * New Price Guide Item from existing Stock.
139          *
140          * @param \Stock\Entity\Stock $stock
141          * @param string $previousState
142          * @param array $routingData
143          */
144         public function initNewItemFromStock(
145                         \Stock\Entity\Stock $stock, $previousState, array $routingData = array()
146                         )
147         {
148                 $prevListingId = is_object($stock->priceGuide)
149                         ? $stock->priceGuide->id
150                         : false;
151                 $record = $this->create(array(
152                         'stock'     => $stock->id,
153                         'clubs'     => $routingData['clubs']
154                 ));
155                 $stock->priceGuide = $record;
156                 $stock->loadedOnPriceGuide = new \DateTime("now");
157                 $stock->highestOffer = 0.0;
158                 $this->em->flush($stock);
159                 $authData = \Utility\Registry::getAuthData();
160                 $fromCompanyId  = isset($authData['company']['id']) ? $authData['company']['id'] : null;
161                 $fromProfileId  = isset($authData['id']) ? $authData['id'] : null;
162                 exec("php /var/www/B4C2/public/index.php priceguide notify "
163                                 . $record->id
164                                 . " $fromCompanyId $fromProfileId  > /dev/null &");
165                 if ($prevListingId)
166                 {
167                         $acceptedOffer = $this->em->getRepository('\PriceGuide\Entity\Offer')
168                                 ->findOneBy(array(
169                                                 'priceGuideStock' => $prevListingId,
170                                                 'status' => 'Offer Accepted'
171                                 ));
172                         #-> Expire all previous offers.
173                         $this->em->createQuery(
174                                         'UPDATE \PriceGuide\Entity\Offer o '
175                                         . "SET o.status = 'Expired' "
176                                         . 'WHERE IDENTITY(o.priceGuideStock) = '
177                                         . $prevListingId
178                                         )
179                                 ->execute();
180                         if ($acceptedOffer)
181                         {
182                                 #-> Re-create accepted offer as updateable.
183                                 $newOffer = new \PriceGuide\Entity\Offer();
184                                 $newOffer->priceGuideStock = $record;
185                                 $newOffer->company = $acceptedOffer->company;
186                                 $newOffer->profile = $acceptedOffer->profile;
187                                 $newOffer->amount = $acceptedOffer->amount;
188                                 $newOffer->status = 'Updateable Offer';
189                                 $this->em->persist($newOffer);
190
191                                 #-> Update stock entry with correct data.
192                                 $stock->numberOfOffers = 1;
193                                 $stock->highestOffer = $acceptedOffer->amount;
194
195                                 #-> Set price guide entry to status updateable offers.
196                                 $record->previousState = 'Open4Offers';
197                                 $record->jobState = 'Updateable Offers';
198                                 $this->em->flush();
199
200                                 #-> Notify accepted offer user of the relisting.
201                                 $params = array(
202                                                 'firstName'     => $acceptedOffer->profile->firstName,
203                                                 'familyName'    => $acceptedOffer->profile->familyName,
204                                                 'offerAmount'   => 'R' . $acceptedOffer->amount,
205                                                 'year'                  => $stock->vehicleYear->name,
206                                                 'make'                  => $stock->type->model->make->name,
207                                                 'model'                 => $stock->type->model->name,
208                                                 'type'                  => $stock->type->name,
209                                                 'regNo'                 => $stock->registrationNumber,
210                                                 'referenceNumber' => $stock->referenceNumber
211                                 );
212                                 $oNotify = new \Utility\Comms\Notification();
213                                 $oNotify->sendFromTemplate(
214                                                 $fromCompanyId, $fromProfileId,
215                                                 $acceptedOffer->company->id, $acceptedOffer->profile->id,
216                                                 $acceptedOffer->profile->email, null, null,
217                                                 'price-guide-offer-relist',
218                                                 $params
219                                 );
220                         }
221                 }
222         }
223
224         /**
225          * Route newly added item to initial state.
226          *
227          * @param \PriceGuide\Entity\PriceGuide
228          * @param string|null $previousState
229          * @param array|null $routingData
230          * @return string
231          */
232         public function routeNewItem(\PriceGuide\Entity\PriceGuide $valuation, $previousState, $routingData)
233         {
234                 $status = \Utility\Registry::checkOnce('NewPriceGuideItem.Status');
235                 $status = is_null($status)
236                         ? 'This.NewPriceGuide'
237                         : $status;
238                 if ('This.NewPriceGuide' == $status)
239                 {
240                         $valuation->queueStatus = 1;
241                 }
242                 if ('PriceGuide.NewItem' == $status)
243                 {
244                         $valuation->previousState = 'Pending PriceGuide';
245                 }
246                 if ('This.Stock' == $status)
247                 {
248                         $valuation->previousState = 'Pending PriceGuide';
249                 }
250                 return $status;
251         }
252
253         /**
254          * ExecuteAfter: Create.
255          * Send sms notifications to linked members for relevant clubs.
256          *
257          * @param array $meta
258          * @param object|null $jobRecord
259          * @param object|null $record
260          * @param \Workspace\Utility\ServiceInputParams $contract
261          * @return array
262          */
263         public function sendToMembers($record, $fromCompanyId, $fromProfileId)
264         {
265                 set_time_limit(0);
266                 ini_set('memory_limit','1024M');
267                 //\Utility\Debug::errorLog('pg cron start', $record->toArray());
268                 \Utility\Registry::setOnce('Stock.IgnorePriceGuide', true);
269                 $jobRecord = $record;
270                 $record = $record->toArray(array('stock', 'clubs', 'type', 'make', 'model', 'company'));
271                 $stock  = $record['stock'];
272                 $clubs  = $record['clubs'];
273
274                 $vehicleYear = $stock['vehicleYear']['id'];
275
276                 /*
277                  * Set template parameters
278                 */
279                 $params = array();
280                 $params['company.name']         = $stock['company']['name'];
281                 $params['seller']                       = $stock['company']['name'];
282                 $params['make.name']            = $stock['type']['model']['make']['name'];
283                 $params['model.name']           = $stock['type']['model']['name'];
284                 $params['tradeRetail']          = 'Trade: R ' . $stock['tradePrice'] . ', Retail: R ' . $stock['retailPrice'];
285
286                 $templateName = 'club-stock-on-offer';
287
288                 /*
289                  * Get club data for member notifications
290                  */
291                 $clubIds = array();
292                 foreach ($clubs as $club)
293                 {
294                         $clubIds[] = $club['club']['id'];
295                 }
296                 $query = 'SELECT m, p, make, fromYear, toYear, IDENTITY(p.company) as companyId
297                                   FROM \PriceGuide\Entity\Member m
298                                   JOIN m.profile p
299                                   LEFT JOIN m.makes make
300                                   LEFT JOIN m.fromYear fromYear
301                                   LEFT JOIN m.toYear toYear
302                                   WHERE IDENTITY(m.club) IN (:clubs) AND m.status=\'Active\'';
303                 $query = $this->em->createQuery($query);
304                 $query->setParameter('clubs', $clubIds);
305                 $result = $query->getArrayResult();
306                 $recipientsSentTo = array();
307
308                 //\Utility\Debug::errorLog('count($result)', count($result));
309                 /*
310                  * Cycle through members and send notifications where neccessarry
311                  */
312                 for($i = 0; $i < count($result); $i++)
313                 {
314                         /*
315                          * Duplicate notifiction check
316                          */
317                         if(!isset($recipientsSentTo[$result[$i]['companyId']]))
318                         {
319                                 /*
320                                  * Set vehicle makes subscription preferences
321                                  */
322                                 $allMakes   = $result[$i][0]['allMakes'];
323                                 $makes      = array();
324                                 if(0 == $allMakes)
325                                 {
326                                         for($m = 0; $m < count($result[$i][0]['makes']); $m++)
327                                         {
328                                                 $makes[] = $result[$i][0]['makes'][$m]['id'];
329                                         }
330                                 }
331                                 $inMakes = (1 == $allMakes || in_array($stock['type']['model']['make']['id'], $makes))
332                                                  ? true
333                                                  : false;
334
335
336                                 /*
337                                  * Set vehicle year subscription preferences
338                                  */
339                                 $fromYear   = $result[$i][0]['fromYear']['id'];
340                                 $toYear     = $result[$i][0]['toYear']['id'];
341                                 if (!is_null($toYear) && $fromYear > $toYear)
342                                 {
343                                         $swap = $fromYear;
344                                         $fromYear = $toYear;
345                                         $toYear = $swap;
346                                 }
347                                 $inYears    = ((null == $fromYear || $vehicleYear >= $fromYear) && (null == $toYear || $vehicleYear <= $toYear))
348                                                     ? true
349                                                     : false;
350
351                                 //\Utility\Debug::errorLog('$inMakes', $inMakes);
352                                 //\Utility\Debug::errorLog('$inYears', $inYears);
353                                 /*
354                                  * Check if recipient is subscribed to vehicle make & year
355                                  */
356                                 if(true == $inMakes && true == $inYears)
357                                 {
358
359                                         $insert = new \PriceGuide\Entity\MemberStock();
360                                         $params = array('priceGuideStock' => $jobRecord, 'member' => $this->em->getReference('\PriceGuide\Entity\Member', $result[$i][0]['id']));
361                                         $insert->fromArray($params);
362                                         $this->em->persist($insert);
363                                 //\Utility\Debug::errorLog('created link', $insert->id);
364
365                                         $recipientsSentTo[$result[$i]['companyId']] = true;
366
367                                         $params = array(
368                                                 'company.name'  => $record['company']['name'],
369                                                 'make.name'     => $record['stock']['type']['model']['make']['name'],
370                                                 'model.name'    => $record['stock']['type']['model']['name'],
371                                                 'type.name'     => $record['stock']['type']['name'],
372                                                 'tradeRetail'   => 'Trade: R ' . $record['stock']['tradePrice']
373                                                                                 . ', Retail: R ' . $record['stock']['retailPrice'],
374                                                 'seller'                => $record['company']['name'],
375                                                 'link'          => '/#/offerview?pgId=' . $record['id'] . '&id=0'
376                                         );
377                                         $subject          = null;
378
379                                         $company = $this->em->getRepository('Company\Entity\Company')
380                                                 ->find($result[$i]['companyId']);
381                                         $iterator = $company->profiles->getIterator();
382                                         foreach ($iterator as $profile)
383                                         {
384                                 //\Utility\Debug::errorLog('a profile', $profile->id);
385                                                 if ($profile->override->pgMakeOffer)
386                                                 {
387                                 //\Utility\Debug::errorLog('have permissions', 'sending notification');
388                                                         $params['firstName']    = $profile->firstName;
389                                                         $params['familyName']   = $profile->familyName;
390                                                         $email                                  = true == $result[$i][0]['emailNotification']
391                                                                 ? $profile->email
392                                                                 : null;
393                                                         $mobile                                 = true == $result[$i][0]['smsNotification']
394                                                                 ? $profile->mobile
395                                                                 : null;
396                                                         if(null != $email || null != $mobile)
397                                                         {
398                                                                 $oNotify = new \Utility\Comms\Notification();
399                                                                 $oNotify->sendFromTemplate(
400                                                                                 $fromCompanyId, $fromProfileId,
401                                                                                 $result[$i]['companyId'], $profile->id,
402                                                                                 $email, $mobile,
403                                                                                 $subject,
404                                                                                 $templateName,
405                                                                                 $params);
406                                                         }
407                                                 }
408                                         }
409                                 }
410
411
412
413                         }
414                 }
415
416                 /*
417                  * Commit inserts
418                  */
419                 $this->em->flush();
420         }
421
422         /**
423          * ExecuteAfter: CreatePending, CreateComplete, CreatePriceGuide, CreateStock.
424          * Set the valuator from session authentication data.
425          *
426          * @param array $meta
427          * @param object|null $jobRecord
428          * @param object|null $record
429          * @param \Workspace\Utility\ServiceInputParams $contract
430          * @return array
431          */
432         public function setValuatorFromAuth($meta, $jobRecord, $record, \Workspace\Utility\ServiceInputParams $contract)
433         {
434                 $jobRecord->valuatedBy = $this->em->getReference(
435                                 '\User\Entity\Profile', \Utility\Registry::getAuthParam('id')
436                                 );
437                 $this->em->flush();
438         }
439
440         /**
441          * ExecuteAfter: CreateComplete, RouteMoveToComplete.
442          *
443          * @param array $meta
444          * @param object|null $jobRecord
445          * @param object|null $record
446          * @param \Workspace\Utility\ServiceInputParams $contract
447          * @return array
448          */
449         public function setPreviousStateToComplete($meta, $jobRecord, $record, \Workspace\Utility\ServiceInputParams $contract)
450         {
451                 $jobRecord->previousState = 'Complete PriceGuide';
452                 $this->em->flush($jobRecord);
453         }
454
455         /**
456          * ConditionalContract: Update.
457          *
458          * @param array $meta
459          * @param object|null $jobRecord
460          * @param object|null $record
461          * @param \Workspace\Contract\AbstractBase $contract
462          * @return array
463          */
464         public function noEditOnPgItemWithOffers($meta, $jobRecord, $record, \Workspace\Contract\AbstractBase $contract)
465         {
466                 if ('Price Guide' == $jobRecord->jobState
467                         && 0 < $jobRecord->stock->numberOfOffers)
468                 {
469                         throw new \Exception('PriceGuide in status Price Guide with offers may not be edited.');
470                 }
471         }
472
473         /**
474          * ConditionalContract: Update.
475          *
476          * @param array $meta
477          * @param object|null $jobRecord
478          * @param object|null $record
479          * @param \Workspace\Contract\AbstractBase $contract
480          * @return array
481          */
482         public function noSendToSalesWithoutValuation($meta, $jobRecord, $record, \Workspace\Contract\AbstractBase $contract)
483         {
484                 if (is_null($jobRecord->valuation))
485                 {
486                         throw new \Exception('No valuation connected to this entry, cannot send to sales.');
487                 }
488         }
489
490
491
492         /**
493          * Contract to add company to all traders clubs.
494          * @param object|null $jobRecord
495          * @param array $input
496          * @return \Workspace\Contract\UseOnce
497          */
498         public function contractAddToTradeClub($jobRecord, array $input = array())
499         {
500                 $options = new \Workspace\UseCase\Options();
501                 $requirement = new \Workspace\UseCase\Requirement();
502                 $requirement->addRequiredInput(array(
503                                 'Company' => array(
504                                                 'id' => 'Id'
505                                 )
506                 ));
507                 return new \Workspace\Contract\UseOnce($options, $requirement);
508         }
509
510         /**
511          * Add company to all traders clubs
512          * @param object|null $jobRecord
513          * @param \Workspace\Utility\ServiceInputParams $contract
514          * @return array
515          */
516         public function executeAddToTradeClub($jobRecord, \Workspace\Utility\ServiceInputParams $contract)
517         {
518                 #-> Retrieve relevant company, profile and allowed club member to work with.
519                 $em = \Utility\Registry::getEntityManager();
520                 $company = $em->getRepository('\Company\Entity\Company')
521                         ->find($contract->data->Company['id']);
522                 if (is_null($company))
523                 {
524                         return $contract->error('Failure.', 'Could not find company.');
525                 }
526                 if (1 == $company->group->id)
527                 {
528                         return $contract->error('Failure.', 'Imperial dealer, cannot add as trader.');
529                 }
530                 $profile = $em->getRepository('\User\Entity\Profile')
531                         ->findOneBy(array('company' => $contract->data->Company['id']), array('id' => 'ASC'));
532                 if (is_null($profile))
533                 {
534                         return $contract->error('Failure.', 'Could not find primary profile.');
535                 }
536                 $allowedMember = $em->getRepository('\PriceGuide\Entity\AllowedMember')
537                         ->findOneBy(array('email' => $profile->email));
538                 if (is_null($allowedMember))
539                 {
540                         $allowedMember = new \PriceGuide\Entity\AllowedMember();
541                         $allowedMember->name = $company->name;
542                         $allowedMember->email = $profile->email;
543                         $em->persist($allowedMember);
544                         $em->flush();
545                 }
546
547                 #-> Find clubs we need to work with.
548                 $query = 'SELECT club, company '
549                                 . 'FROM \PriceGuide\Entity\Club club '
550                                 . 'JOIN club.company company '
551                                 . 'WHERE IDENTITY(company.group) = 1 '
552                                 . 'ORDER BY company.id, club.id ASC';
553                 $query = $this->em->createQuery($query);
554                 $result = $query->getArrayResult();
555                 $comp = 0;
556                 $club = 0;
557                 $clubs = array();
558
559                 #-> Add new member to clubs.
560                 foreach ($result as $row)
561                 {
562                         if ($comp != $row['company']['id'])
563                         {
564                                 $comp = $row['company']['id'];
565                                 $club = 1;
566                                 continue;
567                         }
568                         if (1 == $club)
569                         {
570                                 $clubs[$row['id']] = $row['name'];
571                                 $member = new \PriceGuide\Entity\Member();
572                                 $member->club = $em->getReference('\PriceGuide\Entity\Club', $row['id']);
573                                 $member->company = $company;
574                                 $member->profile = $profile;
575                                 $member->allowedMember = $allowedMember;
576                                 $member->allMakes = true;
577                                 $member->status = 'Active';
578                                 $em->persist($member);
579                                 $em->flush();
580                         }
581                         $club++;
582                 }
583
584                 return $contract->success('Trader added to all trade clubs.', array());
585         }
586
587
588
589         /**
590          * Contract to add company to all traders clubs.
591          * @param object|null $jobRecord
592          * @param array $input
593          * @return \Workspace\Contract\UseOnce
594          */
595         public function contractSetupImperialClubs($jobRecord, array $input = array())
596         {
597                 $options = new \Workspace\UseCase\Options();
598                 $requirement = new \Workspace\UseCase\Requirement();
599                 $requirement->addRequiredInput(array(
600                                 'Company' => array(
601                                                 'id' => 'Id'
602                                 )
603                 ));
604                 return new \Workspace\Contract\UseOnce($options, $requirement);
605         }
606
607         /**
608          * Add company to all traders clubs
609          * @param object|null $jobRecord
610          * @param \Workspace\Utility\ServiceInputParams $contract
611          * @return array
612          */
613         public function executeSetupImperialClubs($jobRecord, \Workspace\Utility\ServiceInputParams $contract)
614         {
615                 #-> Retrieve relevant company, profile and allowed club member to work with.
616                 $em = \Utility\Registry::getEntityManager();
617                 $company = $em->getRepository('\Company\Entity\Company')
618                         ->find($contract->data->Company['id']);
619                 if (is_null($company))
620                 {
621                         return $contract->error('Failure.', 'Could not find company.');
622                 }
623                 $profile = $em->getRepository('\User\Entity\Profile')
624                         ->findOneBy(array('company' => $contract->data->Company['id']), array('id' => 'ASC'));
625                 if (is_null($profile))
626                 {
627                         return $contract->error('Failure.', 'Could not find primary profile.');
628                 }
629
630                 #-> Create memberships for this company in other internal clubs.
631                 $query = 'SELECT club, company '
632                                 . 'FROM \PriceGuide\Entity\Club club '
633                                 . 'JOIN club.company company '
634                                 . 'WHERE IDENTITY(company.groupDivision) = :groupDivision '
635                                 . 'ORDER BY company.id, club.id ASC';
636                 $query = $this->em->createQuery($query)
637                         ->setParameter('groupDivision', $company->groupDivision->id);
638                 $result = $query->getArrayResult();
639                 $comp = 0;
640
641                 #-> Add this company to internal clubs from same division.
642                 foreach ($result as $row)
643                 {
644                         if ($comp != $row['company']['id'])
645                         {
646                                 $comp = $row['company']['id'];
647                                 if ($row['company']['id'] == $company->id)
648                                 {
649                                         continue;
650                                 }
651                                 $member = $em->getRepository('\PriceGuide\Entity\Member')
652                                         ->findOneBy(array(
653                                                 'club'    => $row['id'],
654                                                 'company' => $company->id
655                                         ));
656                                 if (is_object($member))
657                                 {
658                                         continue;
659                                 }
660                                 $member = new \PriceGuide\Entity\Member();
661                                 $member->club = $em->getReference('\PriceGuide\Entity\Club', $row['id']);
662                                 $member->company = $company;
663                                 $member->profile = $profile;
664                                 $member->allMakes = true;
665                                 $member->status = 'Active';
666                                 $em->persist($member);
667                                 $em->flush();
668                         }
669                 }
670
671                 #-> Create internal club.
672                 $club = $em->getRepository('\PriceGuide\Entity\Club')
673                         ->findOneBy(
674                                         array('company' => $company->id),
675                                         array('id' => 'ASC')
676                         );
677                 if (!is_object($club))
678                 {
679                         $club = new \PriceGuide\Entity\Club();
680                         $club->company = $company;
681                         $club->name = $company->name . ' Internal Club - IAR';
682                         $club->useAsDefault = true;
683                         $em->persist($club);
684                         $em->flush();
685                 }
686
687                 #-> Link companies from same division.
688                 $companies  = $em->getRepository('\Company\Entity\Company')
689                         ->findBy(array('groupDivision' => $company->groupDivision->id));
690                 foreach ($companies as $cmpMember)
691                 {
692                         if ($cmpMember->id == $company->id)
693                         {
694                                 continue;
695                         }
696                         $member = $em->getRepository('\PriceGuide\Entity\Member')
697                                 ->findOneBy(array(
698                                         'club'    => $club->id,
699                                         'company' => $cmpMember->id
700                                 ));
701                         if (is_object($member))
702                         {
703                                 continue;
704                         }
705                         $profile  = $em->getRepository('\User\Entity\Profile')
706                                 ->findOneBy(array('company' => $cmpMember->id), array('id' => 'ASC'));
707                         if (!is_object($profile))
708                         {
709                                 continue;
710                         }
711                         $member = new \PriceGuide\Entity\Member();
712                         $member->club = $club;
713                         $member->company = $cmpMember;
714                         $member->profile = $profile;
715                         $member->allMakes = true;
716                         $member->status = 'Active';
717                         $em->persist($member);
718                         $em->flush();
719                 }
720
721                 #-> Create traders club.
722                 $clubs = $em->getRepository('\PriceGuide\Entity\Club')
723                         ->findBy(
724                                 array('company' => $company->id),
725                                 array('id' => 'ASC')
726                         );
727                 if (!empty($clubs) && count($clubs) > 1)
728                 {
729                         array_shift($clubs);
730                         $club = array_shift($clubs);
731                 }
732                 else
733                 {
734                         $club = new \PriceGuide\Entity\Club();
735                         $club->company = $company;
736                         $club->name = $company->name . ' Trader Club - IAR Approved';
737                         $club->useAsDefault = false;
738                         $em->persist($club);
739                         $em->flush();
740                 }
741
742                 #-> Link traders to club.
743                 $companies = array();
744                 $allowedMembers  = $em->getRepository('\PriceGuide\Entity\AllowedMember')
745                         ->findBy(array('archived' => 0));
746                 foreach ($allowedMembers as $allowedMember)
747                 {
748                         $profile = $em->getRepository('\User\Entity\Profile')
749                                 ->findOneBy(array('email' => $allowedMember->email));
750                         if (!is_object($profile))
751                         {
752                                 continue;
753                         }
754                         if (isset($companies[$profile->company->id]) || 1 != $profile->company->group->id)
755                         {
756                                 continue;
757                         }
758                         $member = $em->getRepository('\PriceGuide\Entity\Member')
759                                 ->findOneBy(array(
760                                         'club'    => $club->id,
761                                         'company' => $profile->company->id
762                                 ));
763                         if (is_object($member))
764                         {
765                                 continue;
766                         }
767                         $companies[$profile->company->id] = true;
768                         $member = new \PriceGuide\Entity\Member();
769                         $member->club = $club;
770                         $member->company = $profile->company;
771                         $member->profile = $profile;
772                         $member->allMakes = true;
773                         $member->status = 'Active';
774                         $em->persist($member);
775                         $em->flush();
776                 }
777
778                 return $contract->success('Added clubs, members and memberships.', array());
779         }
780
781         /**
782          * Contract to remove item from price guide.
783          * @param object|null $jobRecord
784          * @param array $input
785          * @return \Workspace\Contract\UseOnce
786          */
787         public function contractRemove($jobRecord, array $input = array())
788         {
789                 $options = new \Workspace\UseCase\Options();
790                 $requirement = new \Workspace\UseCase\Requirement();
791                 return new \Workspace\Contract\UseOnce($options, $requirement);
792         }
793
794         /**
795          * Remove item from price guide.
796          * @param object|null $jobRecord
797          * @param \Workspace\Utility\ServiceInputParams $contract
798          * @return array
799          */
800
801         public function executeRemove($jobRecord, \Workspace\Utility\ServiceInputParams $contract)
802         {
803                 //\Utility\Debug::errorLog('jobRecord', $jobRecord->toArray());
804                 try
805                 {
806                         if ($jobRecord->valuation)
807                         {
808                                 $workflow = \Utility\Registry::getServiceManager()
809                                         ->get('Valuation');
810                                 $workflow->handover('Price Guide', $jobRecord->valuation->id);
811                         }
812                         else
813                         {
814                                 $workflow = \Utility\Registry::getServiceManager()
815                                         ->get('Stock');
816                                 $workflow->handover('Price Guide', $jobRecord->stock->id);
817                         }
818                 }
819                 catch (\Exception $e)
820                 {
821                         \Utility\Debug::errorLog(
822                                         'Error on Price Guide single removal process for item ' . $jobRecord->id,
823                                         $e->getMessage()
824                         );
825                 }
826                 $this->workflowNode->changeState('This.ValidOffers');
827                 $this->em->createQuery(
828                                 'UPDATE \PriceGuide\Entity\Offer o '
829                                 . "SET o.status = 'Valid Offer' "
830                                 . 'WHERE IDENTITY(o.priceGuideStock) = '
831                                 . $jobRecord->id
832                                 . ' AND o.status != \'Archived\''
833                         )
834                         ->execute();
835                 $this->em->createQuery(
836                                 'UPDATE \PriceGuide\Entity\Offer o '
837                                 . "SET o.previousStatus = 'Valid Offer' "
838                                 . 'WHERE IDENTITY(o.priceGuideStock) = '
839                                 . $jobRecord->id
840                                 . ' AND o.status = \'Archived\''
841                         )
842                         ->execute();
843                 return $contract->success('Vehicle removed from auction.', array());
844         }
845
846         /**
847          * Contract to remove item from price guide and expire.
848          * @param object|null $jobRecord
849          * @param array $input
850          * @return \Workspace\Contract\UseOnce
851          */
852         public function contractExpire($jobRecord, array $input = array())
853         {
854                 $options = new \Workspace\UseCase\Options();
855                 $requirement = new \Workspace\UseCase\Requirement();
856                 return new \Workspace\Contract\UseOnce($options, $requirement);
857         }
858
859         /**
860          * Remove item from price guide and expire.
861          * @param object|null $jobRecord
862          * @param \Workspace\Utility\ServiceInputParams $contract
863          * @return array
864          */
865
866         public function executeExpire($jobRecord, \Workspace\Utility\ServiceInputParams $contract)
867         {
868                 try
869                 {
870                         if ($jobRecord->valuation)
871                         {
872                                 $workflow = \Utility\Registry::getServiceManager()
873                                         ->get('Valuation');
874                                 $workflow->handover('Price Guide', $jobRecord->valuation->id);
875                         }
876                         else
877                         {
878                                 $workflow = \Utility\Registry::getServiceManager()
879                                         ->get('Stock');
880                                 $workflow->handover('Price Guide', $jobRecord->stock->id);
881                         }
882                 }
883                 catch (\Exception $e)
884                 {
885                         \Utility\Debug::errorLog(
886                                         'Error on Price Guide single removal process for item ' . $jobRecord->id,
887                                         $e->getMessage()
888                         );
889                 }
890                 $this->workflowNode->changeState('This.Archived');
891                 $this->em->createQuery(
892                                 'UPDATE \PriceGuide\Entity\Offer o '
893                                 . "SET o.status = 'Expired' "
894                                 . 'WHERE IDENTITY(o.priceGuideStock) = '
895                                 . $jobRecord->id
896                                 . ' AND o.status != \'Archived\''
897                         )
898                         ->execute();
899                 $this->em->createQuery(
900                                 'UPDATE \PriceGuide\Entity\Offer o '
901                                 . "SET o.previousStatus = 'Expired' "
902                                 . 'WHERE IDENTITY(o.priceGuideStock) = '
903                                 . $jobRecord->id
904                                 . ' AND o.status = \'Archived\''
905                         )
906                         ->execute();
907                 return $contract->success('Vehicle removed from auction.', array());
908         }
909
910
911
912         /**
913          * CRON functionality: Move PriceGuide item and related Offers to ValidOffer(s) status.
914          * @param arary $meta
915          * @param \PriceGuide\Entity\PriceGuide $record
916          * @param \Workspace\Contract\AbstractBase $contract
917          */
918         public function cronProcess()
919         {
920                 #-> Phase 1.
921
922                 $days = \Utility\Definitions\Locale::getPriceGuideOpenDays();
923                 $date = date('Y-m-d H:i:s', time() - (3600 * $days));
924                 $result = $this->em->createQuery(
925                                 'SELECT priceGuide, stock, vehicleYear, type, model, make, valuation '
926                                 . 'FROM \PriceGuide\Entity\PriceGuide priceGuide '
927                                 . 'JOIN priceGuide.stock stock '
928                                 . 'JOIN stock.vehicleYear vehicleYear '
929                                 . 'JOIN stock.type type '
930                                 . 'JOIN type.model model '
931                                 . 'JOIN model.make make '
932                                 . 'LEFT JOIN priceGuide.valuation valuation '
933                                 . 'WHERE (priceGuide.jobState = \'Open4Offers\' OR priceGuide.jobState = \'Updateable Offers\')'
934                                 . ' AND priceGuide.created <= \'' . $date . '\''
935                         )
936                         ->getArrayResult();
937                 foreach ($result as $item)
938                 {
939                         try
940                         {
941                                 if (!is_null($item['valuation']['id']))
942                                 {
943                                         $workflow = \Utility\Registry::getServiceManager()
944                                                 ->get('Valuation');
945                                         $workflow->handover('Price Guide', $item['valuation']['id']);
946                                 }
947                                 else
948                                 {
949                                         $workflow = \Utility\Registry::getServiceManager()
950                                                 ->get('Stock');
951                                         $workflow->handover('Price Guide', $item['stock']['id']);
952                                 }
953                         }
954                         catch (\Exception $e)
955                         {
956                                 \Utility\Debug::errorLog('Error on PriceGuide cron process for item ' . $item['id'], $e->getMessage());
957                         }
958
959                         try
960                         {
961                                 #-> Set all related offers to Valid Offer status.
962                                 $this->workflowNode->loadJob($item['id']);
963                                 if ('Updateable Offers' == $item['jobState'])
964                                 {
965                                         $this->workflowNode->changeState('This.ValidOffers');
966                                         $this->em->createQuery(
967                                                         'UPDATE \PriceGuide\Entity\Offer o '
968                                                         . "SET o.status = 'Valid Offer' "
969                                                         . 'WHERE IDENTITY(o.priceGuideStock) = '
970                                                         . $item['id']
971                                                         . ' AND o.status != \'Archived\''
972                                                 )
973                                                 ->execute();
974                                         $this->em->createQuery(
975                                                         'UPDATE \PriceGuide\Entity\Offer o '
976                                                         . "SET o.previousStatus = 'Valid Offer' "
977                                                         . 'WHERE IDENTITY(o.priceGuideStock) = '
978                                                         . $item['id']
979                                                         . ' AND o.status = \'Archived\''
980                                                 )
981                                                 ->execute();
982
983                                         $resultx = $this->em->createQuery(
984                                                         'SELECT offer, company, profile '
985                                                         . 'FROM \PriceGuide\Entity\Offer offer '
986                                                         . 'JOIN offer.company company '
987                                                         . 'JOIN offer.profile profile '
988                                                         . 'WHERE IDENTITY(offer.priceGuideStock) = :priceGuideId'
989                                                         . ' AND offer.amount = :highestOffer'
990                                                 )
991                                                 ->setParameter('priceGuideId', $item['id'])
992                                                 ->setParameter('highestOffer', $item['stock']['highestOffer'])
993                                                 ->getArrayResult();
994                                         $earliestDate = null;
995                                         $earliestId = 0;
996                                         foreach($resultx as $id => $itemx)
997                                         {
998                                                 if (0 == $earliestId)
999                                                 {
1000                                                         $earliestId = $id;
1001                                                         $earliestDate = $itemx['created']->getTimestamp();
1002                                                 }
1003                                                 elseif ($itemx['created']->getTimestamp() < $earliestDate)
1004                                                 {
1005                                                         $earliestId = $id;
1006                                                         $earliestDate = $itemx['created']->getTimestamp();
1007                                                 }
1008                                         }
1009                                         foreach($resultx as $id => $itemx)
1010                                         {
1011                                                 if ($earliestId != $id)
1012                                                 {
1013                                                         continue;
1014                                                 }
1015                                                 /* $oNotify = new \Utility\Comms\Notification();
1016                                                 $oNotify->sendFromTemplate(
1017                                                         null,
1018                                                         null,
1019                                                         '1',
1020                                                         $itemx['profile']['id'],
1021                                                         $itemx['profile']['email'],
1022                                                         null,
1023                                                         'Confirmation of Highest Offer on Price Guide',
1024                                                         'highest-price-guide',
1025                                                         array(
1026                                                                         'firstName'                             => $itemx['profile']['firstName'],
1027                                                                         'familyName'                            => $itemx['profile']['familyName'],
1028                                                                         'highest_offer_amount'          => 'R' . $itemx['amount'],
1029                                                                         'Dealership_Name'                       => $itemx['company']['name'],
1030                                                                         'year'                                          => $item['stock']['vehicleYear']['name'],
1031                                                                         'make'                                          => $item['stock']['type']['model']['make']['name'],
1032                                                                         'model'                                         => $item['stock']['type']['model']['name'],
1033                                                                         'Trade'                                         => 'Trade price: R' . $item['stock']['tradePrice'],
1034                                                                         'Retail'                                        => 'Retail price: R' . $item['stock']['retailPrice'],
1035                                                                         'registration_number'           => $item['stock']['registrationNumber']
1036                                                 )); */
1037                                         }
1038                                 }
1039                                 else
1040                                 {
1041                                         $this->workflowNode->changeState('This.Archived');
1042                                         $this->em->createQuery(
1043                                                         'UPDATE \PriceGuide\Entity\Offer o '
1044                                                         . "SET o.status = 'Expired' "
1045                                                         . 'WHERE IDENTITY(o.priceGuideStock) = '
1046                                                         . $item['id']
1047                                                         . ' AND o.status != \'Archived\''
1048                                                         )
1049                                                 ->execute();
1050                                         $this->em->createQuery(
1051                                                         'UPDATE \PriceGuide\Entity\Offer o '
1052                                                         . "SET o.previousStatus = 'Expired' "
1053                                                         . 'WHERE IDENTITY(o.priceGuideStock) = '
1054                                                         . $item['id']
1055                                                         . ' AND o.status = \'Archived\''
1056                                                         )
1057                                                 ->execute();
1058                                 }
1059                         }
1060                         catch (\Exception $e)
1061                         {
1062                                 echo $e->getMessage();
1063                                 \Utility\Debug::errorLog('Error on PriceGuide cron process for item ' . $item['id'], $e->getMessage());
1064                         }
1065                 }
1066
1067
1068                 #-> Phase 2.
1069                 $days += \Utility\Definitions\Locale::getPriceGuideCompletionDays();
1070                 $date = date('Y-m-d H:i:s', time() - (86400 * $days));
1071                 $result = $this->em->createQuery(
1072                                 'SELECT priceGuide, stock, valuation FROM \PriceGuide\Entity\PriceGuide priceGuide '
1073                                 . 'JOIN priceGuide.stock stock LEFT JOIN priceGuide.valuation valuation '
1074                                 . 'WHERE (priceGuide.jobState = \'Valid Offers\')'
1075                                 . ' AND priceGuide.created <= \'' . $date . '\''
1076                         )
1077                         ->getArrayResult();
1078                 foreach ($result as $item)
1079                 {
1080                         try
1081                         {
1082                                 #-> Set all related offers to Expired status.
1083                                 $this->workflowNode->loadJob($item['id']);
1084                                 $this->workflowNode->changeState('This.Archived');
1085                                 $this->em->createQuery(
1086                                                 'UPDATE \PriceGuide\Entity\Offer o '
1087                                                 . "SET o.status = 'Expired' "
1088                                                 . 'WHERE IDENTITY(o.priceGuideStock) = '
1089                                                 . $item['id']
1090                                                 . ' AND o.status != \'Archived\''
1091                                                 )
1092                                         ->execute();
1093                                 $this->em->createQuery(
1094                                                 'UPDATE \PriceGuide\Entity\Offer o '
1095                                                 . "SET o.previousStatus = 'Expired' "
1096                                                 . 'WHERE IDENTITY(o.priceGuideStock) = '
1097                                                 . $item['id']
1098                                                 . ' AND o.status = \'Archived\''
1099                                                 )
1100                                         ->execute();
1101                         }
1102                         catch (\Exception $e)
1103                         {
1104                                 \Utility\Debug::errorLog('Error on PriceGuide cron process for item ' . $item['id'], $e->getMessage());
1105                         }
1106                 }
1107         }
1108
1109
1110
1111 }