<?php
namespace Diplix\KMGBundle\Controller\Accounting;
use Diplix\Commons\DataHandlingBundle\Repository\SysLogRepository;
use Diplix\KMGBundle\Controller\BaseController;
use Diplix\KMGBundle\Controller\Member\MyMembershipController;
use Diplix\KMGBundle\DataTables\DataTablesHelper;
use Diplix\KMGBundle\DataTables\Expr\ExprStub;
use Diplix\KMGBundle\Entity\Accounting\Billing;
use Diplix\KMGBundle\Entity\Accounting\CoopMember;
use Diplix\KMGBundle\Entity\Accounting\Job;
use Diplix\KMGBundle\Entity\Accounting\JobCalcItem;
use Diplix\KMGBundle\Entity\Customer;
use Diplix\KMGBundle\Entity\Order;
use Diplix\KMGBundle\Entity\Role;
use Diplix\KMGBundle\Form\Accounting\ImportJobFileForm;
use Diplix\KMGBundle\Form\Accounting\JobForm;
use Diplix\KMGBundle\Helper\ClientConfigProvider;
use Diplix\KMGBundle\PriceCalculator\CalculatorService;
use Diplix\KMGBundle\Repository\JobRepository;
use Diplix\KMGBundle\Service\Accounting\PaymentCalculator;
use Diplix\KMGBundle\Service\Accounting\TamiJobImporter;
use Diplix\KMGBundle\Service\OrderHandler;
use Diplix\KMGBundle\Util\ExcelExportHelper;
use Doctrine\ORM\AbstractQuery;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Tools\Pagination\Paginator;
use PHPExcel_Style_Border;
use Symfony\Component\Form\FormError;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Vtiful\Kernel\Excel;
class JobController extends BaseController
{
public static $columnSetup =
array( 0=>array('fieldName' => 'job.id', 'caption' => '#', 'headStyle' => 'width:16px;', 'type' =>DataTablesHelper::T_SELECTOR),
1=>array('fieldName' => 'job.orderNumber', 'caption' => 'Auftrag'),
2=>array('fieldName' => 'job.orderTime' , 'caption'=>'Datum'),
3=>array('fieldName' => 'cust.name','caption'=>'Kunde'),
4=>array('fieldName' => 'job.originCity','caption'=>'Ab Ort'),
5=>array('fieldName' => 'job.destinationCity', 'caption'=>'Zu Ort'),
6=>array('fieldName' => 'mem.id', 'caption'=>'MID','visible'=>false,'searchWithLike'=>false),
7=>array('fieldName' => 'job.driverId', 'caption'=>'Fahrer','visible'=>false),
8=>array('fieldName' => 'job.member', 'caption'=>'M', 'virtual'=>true,'visible'=>false,'sortable'=>false),
9=>array('fieldName' => 'job.billed', 'caption'=>'A', 'type'=>DataTablesHelper::T_CSSICON, 'virtual'=>true),
10=>array('fieldName' => 'mem.shortCode','virtual'=>false,'visible'=>true,'caption'=>"Mitglied"),
11=>array('fieldName' => '_order_id','virtual'=>true,'visible'=>false),
12=>array('fieldName' => '_ffl','virtual'=>true,'visible'=>false),
13=>array('fieldName' => '_readyforBilling','virtual'=>true,'visible'=>false),
14=>array('fieldName' => '_customer_id','virtual'=>true,'visible'=>false),
15=>array('fieldName' => 'job.totalCustomerNet', 'caption'=>'€Kunde'),
16=>array('fieldName' => 'job.totalMemberNet', 'caption'=> '€Mitgld.'),
17=>array('fieldName' => '_buttons', 'caption' => '', 'virtual' =>true, 'headStyle' => 'width:96px;', 'type' =>DataTablesHelper::T_BUTTONS),
18=>array('fieldName'=>'job.passenerNotMet','visible'=>false,'sortable'=>false,'searchable'=>false),
19=>array('fieldName'=>'job.discarded','visible'=>false,'sortable'=>false,'searchable'=>false),
20=> [ 'fieldName' => '_hasExtraMemberKm', 'visible'=>false, 'virtual'=>true],
21=> [ 'fieldName' => '_changedByMember', 'visible'=>false, 'virtual'=>true],
22=> [ 'fieldName' => 'lastReadyForBillingCheckResult', 'visible'=>false, 'virtual'=>true],
23=> [ 'fieldName' => '_approvalStatus', 'visible'=>false, 'virtual'=>true],
24=> [ 'fieldName' => 'ord.orderId', 'visible'=>false],
25=> [ 'fieldName' => 'ord.orderStatus', 'visible'=>false,'sortable'=>false,'searchable'=>false],
26=> [ 'fieldName' => 'ord.internalComment','visible'=>false,'sortable'=>false,'searchable'=>false],
27=> [ 'fieldName' => 'ord.taxameter','visible'=>false,'sortable'=>false,'searchable'=>false],
28=>['fieldName'=>'_km','caption'=>'A/KM','virtual'=>true,'sortable'=>false],
29=>['fieldName'=>'_p','caption'=>'A/P','virtual'=>true,'sortable'=>false],
30=>['fieldName'=>'_wz','caption'=>'A/WZ(€)','virtual'=>true,'sortable'=>false],
31=>['fieldName'=>'_ex','caption'=>'A/EX(€)','virtual'=>true,'sortable'=>false],
32=>['fieldName'=>'_ctrl1','virtual'=>true,'visible'=>false],
33=>['fieldName'=>'_ctrl2','virtual'=>true,'visible'=>false],
34=>[ 'fieldName' => 'pt.icon','visible'=>false,'sortable'=>false,'searchable'=>false],
35=>['fieldName'=>'_wzmin','caption'=>'A/WZ(Min)','virtual'=>true,'sortable'=>false],
36=>['fieldName'=>'_customersignature','caption'=>'','virtual'=>true,'sortable'=>false,'visible'=>false],
37=>['fieldName'=>'_discount','caption'=>'R','virtual'=>true,'sortable'=>false],
38=>['fieldName'=>'ord.originOrderId','caption'=>'','virtual'=>false,'sortable'=>false,'visible'=>false]
);
protected function getDth()
{
if ($this->config->isAlternateJobListView())
{
self::$columnSetup[3]['visible']=false;
}
return new DataTablesHelper(self::$columnSetup,
[
'ajaxUrl' => $this->get('router')->generate('acc-jobs-jsonlist'),
'ajaxData' => 'requestData',
'ajaxType' => "POST",
'deferLoading' => true,
'stateSave'=>false, // implemented manually
'defaultSorting'=> array(2=> 'asc')
]);
}
protected function init()
{
$this->ensureUserHasRole(Role::ACCOUNTING);
}
public function __construct(
protected PaymentCalculator $paymentCalculator,
protected CalculatorService $calculatorService,
protected TamiJobImporter $tamiJobImporter,
ClientConfigProvider $ccp,
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry
)
{
$this->config = $ccp;
}
protected function getMemberList()
{
$r = $this->managerRegistry->getRepository(CoopMember::class);
$all = $r->findBy([],['name'=>'asc']);
$list = [];
foreach ($all as $a){
$list [$a->getId()] = $a->getShortCode() . ' ('.$a->getName().')';
}
return $list;
}
/** @var \Diplix\KMGBundle\Helper\ClientConfigProvider */
protected $config;
public function indexAction()
{
$this->init();
//$jr = $this->getDoctrine()->getRepository(Job::class);
//$carList = $jr->findCars();
$now = new \DateTime();
$from = (new \DateTime())->sub(new \DateInterval('P3M'));
$dth = $this->getDth();
return $this->render('@DiplixKMG/Accounting/Job/list.html.twig',[
'columnSetup' =>$dth->getColumnSetup(),
'memberList' => $this->getMemberList(),
'filterFrom' =>$from->format('Y-m-d'),
'filterTo' =>$now->format('Y-m-d')
]);
}
public function memberListAction(Request $request)
{
$this->init();
/** @var EntityRepository $repo */
$repo = $this->managerRegistry->getRepository(Job::class);
$cb = $repo->createQueryBuilder('job')
->select('job,mem')
->leftJoin('job.member','mem')
->groupBy('mem.id');
$req = $request->query->all();
$from = new \DateTime($req["filterFrom"]); $from->setTime(0,0,0);
$to = new \DateTime($req["filterTo"]); $to->setTime(23,59,59);
$cb->andWhere('job.orderTime >= :from')->setParameter('from',$from);
$cb->andWhere('job.orderTime <= :to')->setParameter('to',$to);
//$cb->orderBy('mem.shortCode','asc');
$jobs = $cb->getQuery()->getResult();
$members = [];
/** @var Job $j */
foreach ($jobs as $j)
{
if ($j->getMember()===null) continue;
$mid = $j->getMember()->getId();
if (!array_key_exists($mid,$members))
{
$members[$mid] = $j->getMember()->getShortCode() . ' ('.$j->getMember()->getName().')';
}
}
uasort($members, fn($a,$b) => strcmp($a,$b));
return $this->getJsonDataResponse($request,true,$members);
}
protected function nf($v)
{
return number_format($v,2,',','.');
}
protected function diTi($time)
{
if ($time === null) return '-';
return $time->format('H:i');
}
public function jsonListAction(Request $request)
{
$this->init();
$dth = $this->getDth();
$req = array_merge($request->query->all(),$request->request->all());
/** @var EntityRepository $repo */
$repo = $this->managerRegistry->getRepository(Job::class);
$cb = $repo->createQueryBuilder('job')
->select('job','ord')
->leftJoin('job.member','mem')
->leftJoin('job.customer','cust')
->leftJoin('job.knownOrder','ord')
->leftJoin("ord.paymentType","pt");
// process filtering,ordering,paging
$dth->setQueryBuilder($cb);
$dth->processRequest($request);
// additional filters
$from = new \DateTime($req["filterFrom"]); $from->setTime(0,0,0);
$to = new \DateTime($req["filterTo"]); $to->setTime(23,59,59);
$cb->andWhere('job.orderTime >= :from')->setParameter('from',$from);
$cb->andWhere('job.orderTime <= :to')->setParameter('to',$to);
$dth->addSimpleFilter(10,$req,$dth->getRawColumnOrder($req),
[ExprStub::like("mem.shortCode")],"mem.shortCode",true);
//// XOR filter
if ($req['filterBilled']==="true")
{
$cb->andWhere('job.billingForCustomer IS NOT NULL');
$cb->andWhere('job.billingForMember IS NOT NULL');
}
else
{
$cb->andWhere($cb->expr()->orX('job.billingForCustomer IS NULL','job.billingForMember IS NULL'));
}
if ($req['filterDiscarded']==='true')
{
$cb->andWhere('job.discarded = 1');
}
else
{
$cb->andWhere('job.discarded = 0');
}
/// triState Filter
if ($req['filterFFL']==="true")
{
$cb->andWhere("job.detectedFFL != ''");
}
else
if ($req['filterFFL']==="false")
{
$cb->andWhere("job.detectedFFL = ''");
}
$plainBoolFilters = [
'filterReadyForBilling' => 'job.readyForBilling',
'filterApprovedByDriver' => 'job.approvedByDriver',
'filterApprovedByPassenger' => 'job.approvedByPassenger',
'filterApprovedByAccounting' => 'job.approvedByAccounting'
];
foreach ($plainBoolFilters as $formName=>$dbName)
{
if ($req[$formName]==='true')
{
$cb->andWhere($dbName.' = 1');
}
else
if ($req[$formName]==='false')
{
$cb->andWhere($dbName.' = 0');
}
}
// query and compile paged data
$query = $cb->getQuery();
$query->setHydrationMode(AbstractQuery::HYDRATE_OBJECT);
$paginator = new Paginator($cb->getQuery(),true);
$filteredCount = $paginator->count();
$filteredAndPaged = array();
$dit = $paginator->getIterator();
/** @var Job $row */
foreach ($dit as $row)
{
$memberDetails = MyMembershipController::sumUpMemberCalcCategories($row,true);
$options = [];
$options[]= array('route' => 'acc-jobs-edit', 'title' => 'Bearbeiten', 'icon' => 'glyphicon glyphicon-pencil', 'parameters' =>array('id' =>$row->getId()) );
if ($this->hasUserRole(Role::ACCOUNTING_EDIT))
{
$options[]= array('attr'=>['onClick' => sprintf('approvePrompt([%d],true);',$row->getId())], 'title' => 'Freigeben für Abrechnung', 'icon' => 'glyphicon glyphicon-thumbs-up', 'parameters' =>array('id' =>$row->getId()) );
$options[]= array('attr'=>['onClick' => sprintf('delPrompt(%d,%s);',$row->getId(),$row->isDiscarded()?'true':false)], 'title' => 'Löschen', 'icon' => 'glyphicon glyphicon-trash', 'parameters' =>array('id' =>$row->getId()) );
}
$one = array(
0 => $row->getId(),
1 => $row->getOrderNumber(),
2 => ( $row->getOrderTime() !== null ? $row->getOrderTime()->format('d.m.Y H:i') : '-'),
3 => $row->getCustomer() !== null ? $row->getCustomer()->getName(): $row->getCustomerName(),
4 => $row->getOriginCity(),
5 => $row->getDestinationCity(),
6 => $row->getMember()!== null ? $row->getMember()->getId() : 0,
7 => $row->getDriverId(),
8 => $row->getMember() !== null ? 1: 0,
9 => ($row->isBilled(Billing::TYPE_CUSTOMER) && $row->isBilled(Billing::TYPE_MEMBER)) ? 1 : 0,
10 => $row->getMember() !== null ? $row->getMember()->getShortCode(): '',
11 => $row->getKnownOrder() !== null ? $row->getKnownOrder()->getId() : 0,
12 => $row->getDetectedFFL() ,
13 => $row->isReadyForBilling(),
14 => $row->getCustomer() !== null ? $row->getCustomer()->getId() : 0,
15 => $row->getTotalCustomerNet(),
16 => $row->getTotalMemberNet(),
17 =>$options,
18 => $row->getPassengerNotMet() ? 1 : 0,
19 => $row->isDiscarded() ? 1 : 0,
20 => $row->getHasMemberExtraKm() ? 1 : 0,
21 => $row->getLastChangeByMember()!==null ? 1 : 0,
22 => $row->getLastReadyForBillingCheckResult(),
23 => $row->getApprovalStatus(),
24 => $row->getKnownOrder() !== null ? $row->getKnownOrder()->getOrderId() : '',
25 => $row->getKnownOrder() !== null ? $row->getKnownOrder()->getOrderStatus()->getId() : '',
26 => $row->getKnownOrder() !== null ? $row->getKnownOrder()->getInternalComment() : '',
27 => $row->getTaxameter(),
28 => $memberDetails[JobCalcItem::KM],
29 => $memberDetails[JobCalcItem::Pauschale],
30 => $this->nf($memberDetails[JobCalcItem::Wartezeit]['value']),
31 => $this->nf($memberDetails[JobCalcItem::Extra]['value']),
32 => implode(";",$row->getControlling()),
33 => $memberDetails[JobCalcItem::Extra]['text'],
34 => $row->getKnownOrder() !== null ? $row->getKnownOrder()->getPaymentType()->getIcon() : '',
35 => $memberDetails[MyMembershipController::WartezeitMin] ?? 0,
36 => ($row->getCustomerSignature()!==null) ? 1 : 0,
37 => $row->getKnownOrder() !== null ? ( ($row->getKnownOrder()->getDiscount())??0) : 0,
38 => ($row->getKnownOrder()!==null ? $row->getKnownOrder()->getOriginOrderId() : '')
);
$filteredAndPaged[]= $one;
}
// get total unfiltered count
$query = $repo->createQueryBuilder('job')
->select('COUNT(job.id)')
->getQuery();
$res = $query->getResult();
$totalRecords = (int)$res[0][1];
// compile output
$output = array(
'draw' => $req['draw'],
'recordsTotal' =>$totalRecords,
'recordsFiltered' =>$filteredCount,
'data' => $filteredAndPaged
);
return $this->getJsonResponse($request,$output);
}
public function exportAction(Request $request)
{
$this->init();
$req = $request->query->all();
$from = new \DateTime($req['filterFrom']); $from->setTime(0,0,0);
$to = new \DateTime($req['filterTo']); $to->setTime(23,59,59);
$repo = $this->managerRegistry->getRepository(Job::class);
$cb = $repo->createQueryBuilder('job')
->select('job','ord')
->leftJoin('job.member','mem')
->leftJoin('job.knownOrder','ord');
// filter time range
$from = new \DateTime($req["filterFrom"]); $from->setTime(0,0,0);
$to = new \DateTime($req["filterTo"]); $to->setTime(23,59,59);
$cb->andWhere('job.orderTime >= :from')->setParameter('from',$from);
$cb->andWhere('job.orderTime <= :to')->setParameter('to',$to);
$member = (int)($req['filterCar']??0);
if ($member > 0)
{
$cb->andWhere('job.member = :member')->setParameter('member',$member);
}
$cb
->andWhere('job.discarded = 0')
->orderBy('job.orderTime','asc');
$list = $cb->getQuery()->getResult(AbstractQuery::HYDRATE_OBJECT);
$tempFn = $this->getParameter("dx.temp_dir") . uniqid("export", true) . ".xlsx";
$xh = new ExcelExportHelper();
ExcelExportHelper::$xlsHeadStyle['borders'] = array('bottom' => ['style' => PHPExcel_Style_Border::BORDER_THIN]);
$xh->setSingleSheetMode('Fahrten');
$xh->addIndexedRow(sprintf('Fahrten %s bis %s (%s)',$from->format('d.m.y'),$to->format('d.m.y'),($member>0 ? 'Einzelmitglied':'Alle Mitglieder')));
/** @var Job $row */
foreach ($list as $row)
{
$memberDetails = MyMembershipController::sumUpMemberCalcCategories($row,true);
$one = array(
"Bestellung" => $row->getKnownOrder() !== null ? $row->getKnownOrder()->getOrderId() : '',
"Datum" => ($row->getOrderTime() !== null ? $row->getOrderTime()->format('d.m.Y H:i') : '-'),
"Kostenstelle" => [$row->getKnownOrder() !== null ? $row->getKnownOrder()->getCostCenter() : '', ExcelExportHelper::TYPE_STRING],
"Start" => $row->getOriginCity(),
"Ziel" => $row->getDestinationCity(),
"Mitglied" => $row->getMember() !== null ? $row->getMember()->getShortCode(): '',
"Kunde" => $row->getCustomer() !== null ? $row->getCustomer()->getName(): '',
"Stil" => [$row->getRideStyle(),ExcelExportHelper::TYPE_STRING],
"FRA" => [$row->getDetectedFFL() != '' ? 1: 0, ExcelExportHelper::TYPE_NUMERIC],
"Nicht angetroffen" => [$row->getPassengerNotMet() ? 1 : 0 , ExcelExportHelper::TYPE_NUMERIC],
"Werksrundfahrt" => [$row->isWerksRundfahrt()?1:0,ExcelExportHelper::TYPE_NUMERIC],
"Bewerberfahrt" => [$row->isApplicantTimeRide()?1:0,ExcelExportHelper::TYPE_NUMERIC],
"Sofortfahrt" => [$row->isInstantRide()?1:0,ExcelExportHelper::TYPE_NUMERIC],
"Wartezeitfahrt" => [$row->isExtraWaitingTimeRide()?1:0,ExcelExportHelper::TYPE_NUMERIC],
"Wartezeit" => [$row->getExtraWaitingTime(),ExcelExportHelper::TYPE_NUMERIC],
"Mehr-KM abw." => [$row->getHasMemberExtraKm()?1:0, ExcelExportHelper::TYPE_NUMERIC],
"Mehr-KM" => [$row->getMemberExtraKm(), ExcelExportHelper::TYPE_NUMERIC],
"Kunde/€" => [$row->getTotalCustomerNet(), ExcelExportHelper::TYPE_NUMERIC],
"Mitglied/€" => [$row->getTotalMemberNet(), ExcelExportHelper::TYPE_NUMERIC],
"Abfahrt" => [$row->getDepartureAtOriginTime()!==null ? $row->getDepartureAtOriginTime()->format("H:i") :'', ExcelExportHelper::TYPE_STRING],
"Ankunft" => [$row->getArrivalAtDestinationTime()!==null ?$row->getArrivalAtDestinationTime()->format("H:i") :'', ExcelExportHelper::TYPE_STRING],
"Pos-Zeit" => [$row->getFlightOnPositionTime()!==null ? $row->getFlightOnPositionTime()->format("H:i") :'', ExcelExportHelper::TYPE_STRING],
'KM' => [ $memberDetails[JobCalcItem::KM], ExcelExportHelper::TYPE_NUMERIC],
'P' => $memberDetails[JobCalcItem::Pauschale],
'WZ(€)' => [$memberDetails[JobCalcItem::Wartezeit]['value'], ExcelExportHelper::TYPE_NUMERIC],
'DA(€)' => [$memberDetails[JobCalcItem::Stunde]['value'], ExcelExportHelper::TYPE_NUMERIC],
'EX(€)' => [$memberDetails[JobCalcItem::Extra]['value'], ExcelExportHelper::TYPE_NUMERIC],
'EX Kommentar' => [$row->getExtraCostName(), ExcelExportHelper::TYPE_STRING],
"Ursprungsauftrag" => [ $row->getKnownOrder() !== null ? $row->getKnownOrder()->getOriginOrderId() : '', ExcelExportHelper::TYPE_STRING]
);
$xh->addRow($one,false,[ 0 => ExcelExportHelper::$centerH]);
}
$xh->changeColumnWidths([
1 => 20,
3 => 25,
4 => 25,
]);
// finalize
$outFn = ""
.'Fahrten'
.'_von_'.$from->format('Y-m-d')
.'_bis_'.$to->format('Y-m-d')
.'_Stand_'.date('Y-m-d_H-i')
.'.' .$xh->getExtension();
$xh->saveTo($tempFn);
$resp = new BinaryFileResponse( $tempFn);
$resp->setContentDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
$outFn
);
return $resp;
}
public function exportAccAction(Request $request)
{
$this->init();
$req = $request->query->all();
$from = new \DateTime($req['filterFrom']); $from->setTime(0,0,0);
$to = new \DateTime($req['filterTo']); $to->setTime(23,59,59);
$repo = $this->managerRegistry->getRepository(Job::class);
$cb = $repo->createQueryBuilder('job')
->select('job','ord')
->leftJoin('job.member','mem')
->leftJoin('job.knownOrder','ord');
// filter time range
$from = new \DateTime($req["filterFrom"]); $from->setTime(0,0,0);
$to = new \DateTime($req["filterTo"]); $to->setTime(23,59,59);
$cb->andWhere('job.orderTime >= :from')->setParameter('from',$from);
$cb->andWhere('job.orderTime <= :to')->setParameter('to',$to);
$member = (int)($req['filterCar']??0);
if ($member > 0)
{
$cb->andWhere('job.member = :member')->setParameter('member',$member);
}
$cb
->andWhere('job.discarded = 0')
->orderBy('job.orderTime','asc');
$list = $cb->getQuery()->getResult(AbstractQuery::HYDRATE_OBJECT);
$tempFn = $this->getParameter("dx.temp_dir") . uniqid("export", true) . ".xlsx";
$xh = new ExcelExportHelper();
ExcelExportHelper::$xlsHeadStyle['borders'] = array('bottom' => ['style' => PHPExcel_Style_Border::BORDER_THIN]);
$xh->setSingleSheetMode('Mitglieder,Fahrer');
$xh->addIndexedRow(sprintf('Fahrten %s bis %s (%s)',$from->format('d.m.y'),$to->format('d.m.y'),($member>0 ? 'Einzelmitglied':'Alle Mitglieder')));
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
$SAP_NR = 'LeistungsNr';
$item2array = function ($type, JobCalcItem $item) use($SAP_NR) {
return [
"M/K" => $type,
$SAP_NR => $item->accNumber,
"Menge" => [$item->quantity, ExcelExportHelper::TYPE_NUMERIC],
"Betrag" => [$item->amount, ExcelExportHelper::TYPE_NUMERIC],
"Summe" => [$item->totalNet, ExcelExportHelper::TYPE_NUMERIC],
"MwSt." => [$item->vat, ExcelExportHelper::TYPE_NUMERIC],
"Text" => [$item->name, ExcelExportHelper::TYPE_STRING]
];
};
$all = [
'M' => [],
'K' => [],
];
/** @var Job $row */
foreach ($list as $row)
{
$base = [
"Bestellung" => $row->getKnownOrder() !== null ? $row->getKnownOrder()->getOrderId() : '',
"Datum" => ($row->getOrderTime() !== null ? $row->getOrderTime()->format('d.m.Y H:i') : '-'),
"Kostenstelle" => [$row->getKnownOrder() !== null ? $row->getKnownOrder()->getCostCenter() : '', ExcelExportHelper::TYPE_STRING],
"Start" => $row->getOriginCity(),
"Ziel" => $row->getDestinationCity(),
"Mitglied" => $row->getMember() !== null ? $row->getMember()->getShortCode(): '',
"Stil" => [$row->getRideStyle(),ExcelExportHelper::TYPE_STRING],
];
/** @var JobCalcItem $item */
foreach ($row->getMemberCalculationItems() as $item)
{
$all["M"][] = array_merge($item2array("M",$item),$base);
}
foreach ($row->getCustomerCalculationItems() as $item)
{
$all["K"][] = array_merge($item2array("K",$item),$base);
}
}
// Summieren
$blank = [ 'Menge'=>0,'Summe'=>0];
$sum = [];
foreach ($all as $part)
foreach ($part as $one)
{
$k = $one[$SAP_NR];
if (!array_key_exists($k,$sum))
{
$sum[$k] = $blank;
}
$sum[$k]['Menge'] += (int)$one['Menge'][0];
$sum[$k]['Summe'] += $one['Summe'][0];
}
// erstes sheet
foreach ($all['M'] as $one)
{
$xh->addRow($one);
}
// zweites Sheet
$xh->addSheet('Interne Kunden',true);
foreach ($all['K'] as $one)
{
$xh->addRow($one);
}
// Summen
$xh->addSheet('Summen');
$xh->setupColumns([$SAP_NR,"Menge","Summe"]);
foreach ($sum as $k=>$one)
{
$xh->addRow([
$SAP_NR => $k,
'Menge'=> [$one['Menge'], ExcelExportHelper::TYPE_NUMERIC],
'Summe' => [$one['Summe'], ExcelExportHelper::TYPE_NUMERIC]
]);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// finalize
$outFn = ""
.'Fahrten-Abrechnung'
.'_von_'.$from->format('Y-m-d')
.'_bis_'.$to->format('Y-m-d')
.'_Stand_'.date('Y-m-d_H-i')
.'.' .$xh->getExtension();
$xh->saveTo($tempFn);
$resp = new BinaryFileResponse( $tempFn);
$resp->setContentDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
$outFn
);
return $resp;
}
public function recalcAction(Request $request)
{
$this->init();
/** @var JobRepository $repo */
$repo = $this->managerRegistry->getRepository(Job::class);
$ids = json_decode($request->request->get('selector','[]'),true);
if (count($ids)<1)
{
$this->addFlash('warning','Keine Einträge ausgewählt.');
return $this->redirectToRoute('acc-jobs');
}
if (count($ids)>250)
{
$this->addFlash('warning','Bitte wählen Sie max. 250 Einträge für eine Neuberechnung aus.');
return $this->redirectToRoute('acc-jobs');
}
$qb = $repo->createQueryBuilder('J');
$qb->where($qb->expr()->in('J.id',':ids'))->setParameter('ids',$ids);
$jobs = $qb->getQuery()->getResult();
/** @var Job $row */
foreach ($jobs as $row)
{
if ($row->getMember() === null) {
continue;
}
if ($row->getCustomer() === null) {
continue;
}
$pc = $this->paymentCalculator;
$pc->setFlashBag($this->container->get('session')->getFlashBag());
$pc->calculateTotals($row,$row->isBilled(Billing::TYPE_CUSTOMER),$row->isBilled(Billing::TYPE_MEMBER),);
$on = $row->getKnownOrder() !== null ? $row->getKnownOrder()->getOrderId() : $row->getOrderNumber();
$this->addFlash('info', ['html' => PaymentCalculator::log2html($on.': Berechnungsergebnis für Mitglieder', $row->getMemberCalculationItems())]);
$this->addFlash('info', ['html' => PaymentCalculator::log2html($on.': Berechnungsergebnis für Kunden', $row->getCustomerCalculationItems())]);
if (count($row->getControlling())>0)
{
$this->addFlash('info', ['html' => PaymentCalculator::log2html($on.': Controlling ', $row->getControlling())]);
}
}
$repo->flush();
return $this->redirectToRoute('acc-jobs');
}
public function editAction(Request $request, $id)
{
$this->init();
/** @var EntityManagerInterface $em */
$em = $this->managerRegistry->getManager();
/** @var JobRepository $repo */
$repo = $this->managerRegistry->getRepository(Job::class);
/** @var Job $row */
$row = $repo->findOneBy(['id'=>$id]);
$prev = $repo->findPreviousJobForMember($row);
$next = $repo->findNextJobForMember($row);
$customerPrev = $repo->findPreviousJobForCustomer($row);
$customerNext = $repo->findNextJobForCustomer($row);
$form = $this->createForm(JobForm::class,$row,[]);
$form->handleRequest($request);
if ( $form->isSubmitted() )
{
$this->ensureUserHasRole(Role::ACCOUNTING_EDIT);
// fetch changes
$uow = $em->getUnitOfWork();
$uow->computeChangeSets();
$changeSet = $uow->getEntityChangeSet($row);
if ( (isset($changeSet['member'])) && ($form->has('confirmMemberChange')) && ($form->get('confirmMemberChange')->getData()!==true) )
{
$form->get('confirmMemberChange')->addError(new FormError('Bitte bestätigen Sie die Änderung des Mitglieds.'));
}
if ( (isset($changeSet['customer'])) && ($form->has('confirmCustomerChange')) && ($form->get('confirmCustomerChange')->getData()!==true) )
{
$form->get('confirmCustomerChange')->addError(new FormError('Bitte bestätigen Sie die Änderung des Kunden.'));
}
if ($form->isValid())
{
$repo->flush($row); // initial flush required, otherwise doctrine may loose changes on the way. TODO : why is that ?
if ( ($form->has('calc')) && ($form->get('calc')->isClicked()) ) {
if ($row->getMember() === null) {
$this->addFlash('danger', 'Fehler: Kein Mitglied zugeordnet !');
}
if ($row->getCustomer() === null) {
$this->addFlash('danger', 'Fehler: Kein Kunde zugeordnet !');
}
$pc = $this->paymentCalculator;
$pc->setFlashBag($this->container->get('session')->getFlashBag());
$pc->calculateTotals($row,
$row->isBilled(Billing::TYPE_CUSTOMER),
$row->isBilled(Billing::TYPE_MEMBER),
);
$this->addFlash('info', ['html' => PaymentCalculator::log2html('Berechnungsergebnis für Mitglieder', $row->getMemberCalculationItems())]);
$this->addFlash('info', ['html' => PaymentCalculator::log2html('Berechnungsergebnis für Kunden', $row->getCustomerCalculationItems())]);
if (count($row->getControlling())>0)
{
$this->addFlash('info', ['html' => PaymentCalculator::log2html('Controlling ', $row->getControlling())]);
}
}
if (($form->has('checkReadyForBilling')) && ($form->get('checkReadyForBilling')->isClicked())) {
$msg = [];
JobRepository::detectReadyForBilling($row, $msg);
if ($row->isReadyForBilling())
{
$this->addFlash('info', 'Buchung ist bereit zur Abrechnung');
}
else
{
// if the job is not ready for billing, the warning messages and the state are not persisted since
// we also do not want to persist the other changes made via form
$this->addFlash('warning', 'Buchung ist nicht bereit zur Abrechnung');
foreach ($msg as $k=>$m) {
$this->addFlash('warning', $m);
if ($form->has($k))
{
$form->get($k)->addError(new FormError($m));
}
}
}
}
if ($form->getErrors(true,true)->count() < 1)
{
$row->setLastChangeByMember(null);
$this->addFlash('success','Änderungen gespeichert.');
$repo->flush($row);
return $this->redirectToRoute('acc-jobs-edit', ['id' => $row->getId()]);
}
}
}
return $this->render('@DiplixKMG/Accounting/Job/edit.html.twig',[
'row'=>$row,
'prev' => $prev,
'next' => $next,
'config'=>$this->config,
'customerPrev'=>$customerPrev,
'customerNext'=>$customerNext,
'form' => $form->createView(),
]);
}
public function deleteAction(Request $request, $id)
{
$this->init();
$this->ensureUserHasRole(Role::ACCOUNTING_EDIT);
/** @var EntityManagerInterface $em */
$em = $this->managerRegistry->getManager();
/** @var JobRepository $repo */
$repo = $this->managerRegistry->getRepository(Job::class);
$d = $request->request->get('discard',-1);
$ids = [ $id ];
/** @noinspection TypeUnsafeComparisonInspection */
if ($id == 0)
{
$ids = json_decode($request->request->get('selector','[]'),true);
}
if (count($ids)<1)
{
$this->addFlash('warning','Keine Einträge ausgewählt.');
return $this->redirectToRoute('acc-jobs');
}
$r = $repo->discardJobs($ids,$d==1?true:false,$this->getCurrentUser()->getId());
$this->addFlash('success',sprintf('%d Einträge wurden aktualisiert.',$r));
return $this->redirectToRoute('acc-jobs');
}
public function importAction(Request $request)
{
$this->init();
$this->ensureUserHasRole(Role::ACCOUNTING_EDIT);
// if (!$this->getParameter('tami.enabled'))
// {
// $this->addFlash('warning', 'TaMi-Integration ist deaktiviert.');
// return $this->redirectToRoute('acc-jobs');
// }
/** @var EntityManagerInterface $em */
$em = $this->managerRegistry->getManager();
$form = $this->createForm(ImportJobFileForm::class);
$form->handleRequest($request);
if ($form->isSubmitted())
{
if ($form->isValid())
{
/** @var UploadedFile $file */
$file = $form->get("importFile")->getData();
if ($file->isValid())
{
try
{
$imp = $this->tamiJobImporter;
$resultMessages = $imp->importAndProcessJobFile($file->getRealPath());
foreach ($resultMessages as $m)
{
$this->addFlash('success',$m);
}
return $this->redirectToRoute('acc-jobs');
}
catch (\Throwable $ex)
{
$this->addFlash('danger', 'Import fehlgeschlagen. (' .$ex->getMessage(). ')');
throw $ex;
}
}
$this->addFlash('danger', 'Upload fehlgeschlagen.');
}
else
{
$this->addFlash('warning', 'Bitte überprüfen SIe Ihre Eingaben');
}
}
return $this->render('@DiplixKMG/Accounting/Job/import.html.twig', array('form' => $form->createView()));
}
public function reprocessAction(Request $request)
{
$this->init();
$this->ensureUserHasRole(Role::ACCOUNTING_EDIT);
if (!$this->getParameter('tami.enabled'))
{
$this->addFlash('warning', 'TaMi-Integration ist deaktiviert.');
return $this->redirectToRoute('acc-jobs');
}
/** @var EntityManagerInterface $em */
$em = $this->managerRegistry->getManager();
$imp = $this->tamiJobImporter;
$repo = $em->getRepository(Job::class);
$items = $repo->findBy(['readyForBilling'=>false]);
$this->addFlash('success', count($items) . ' noch nicht zur Abrechnung bereite Einträge geladen');
$resultInfo = $imp->postProcessImport($items);
foreach ($items as $job)
{
JobRepository::detectReadyForBilling($job);
}
$repo->flush();
$msgs = $imp->getResultMessages($resultInfo);
foreach ($msgs as $m)
{
$this->addFlash('success',$m);
}
return $this->redirectToRoute('acc-jobs');
}
protected function timeOrNull($date)
{
if ($date === null)
return null;
return $date->format('H:i');
}
const XFER_ENTRY = "[TRANSFER]";
public function submitxchgAction(Request $request)
{
/** @var Job $job */
$job = null;
$repo = null;
try
{
$this->init();
if ($request->getMethod()!==Request::METHOD_POST)
{
throw new \RuntimeException('Use POST');
}
/** @var JobRepository $repo */
$repo = $this->managerRegistry->getRepository(Job::class);
$sel = $request->get('selector','[]');
$ids = strpos($sel,"[") !== false ? json_decode($sel,true) : [(int)$sel];
if (count($ids)<1)
{
throw new \RuntimeException("Keine Einträge ausgewählt. ($sel)");
}
if (count($ids)>1)
{
throw new \RuntimeException('Zuviele Einträge ausgewählt.');
}
$qb = $repo->createQueryBuilder('J');
$qb->where($qb->expr()->in('J.id',':ids'))->setParameter('ids',$ids);
$jobs = $qb->getQuery()->getResult();
$clientCache = [];
/** @var Job $job */
$job = reset($jobs);
if ($job->getCustomer() === null)
{
throw new \RuntimeException("Kein Kunde im Auftrag");
}
if ($job->getKnownOrder() === null)
{
throw new \RuntimeException("Keine Bestellung im Auftrag");
}
if ($job->getCustomer()->getXchgPlatformUrl()=="")
{
throw new \RuntimeException("Fehlende Fremdsystem-URL");
}
if ($job->getKnownOrder()->getXchgStatus()!==Order::XCHG_RECEIVED_FROM_OTHER)
{
throw new \RuntimeException("Auftrag kommt nicht von Fremdsystem.");
}
if (!array_key_exists($job->getCustomer()->getId(),$clientCache))
{
$clientCache[$job->getCustomer()->getId()]= OrderHandler::getClientForCustomerWhoLoginsAsMember($job->getCustomer());;
}
$client = $clientCache[$job->getCustomer()->getId()];
$res = $client->request("POST",rtrim($job->getCustomer()->getXchgPlatformUrl(),'/')."/job-update-by-oid",[
'headers'=> [
"Content-Type"=>"application/json"
],
'body' => json_encode(
[
"login" => $job->getCustomer()->getXchgLoginAsMember(),
"password" => $job->getCustomer()->getXchgLoginPassword(),
"orderId"=> $job->getKnownOrder()->getXchgOrderId(),
"xchg"=>true,
// data
'flightOnPositionTime' => $this->timeOrNull($job->getFlightOnPositionTime()),
'departureAtOriginTime' => $this->timeOrNull($job->getDepartureAtOriginTime()),
'arrivalAtDestinationTime' => $this->timeOrNull($job->getArrivalAtDestinationTime()),
'passengerNotMet'=>$job->getPassengerNotMet(),
'taxameter'=>$job->getTaxameter(),
'taxameterVat'=>$job->getTaxameterVat(),
'extraCostName'=>$job->getExtraCostName(),
'extraCostPrice'=>$job->getExtraCostPrice(),
'hasMemberExtraKm' => $job->getHasMemberExtraKm(),
'memberExtraKm'=>$job->getMemberExtraKm(),
'confirmedByCustomerThrough'=>$job->getConfirmedByCustomerThrough(),
'approvedByDriver'=>$job->isApprovedByDriver(),
'werksRundfahrt' => $job->isWerksRundfahrt(),
'extraWaitingTimeRide' => $job->isExtraWaitingTimeRide(),
'extraWaitingTime' => $job->getExtraWaitingTime(),
'instantRideAdditionalWaitingTime' => $job->getInstantRideAdditionalWaitingTime(),
]
, JSON_THROW_ON_ERROR)
]);
$res = json_decode($res->getBody(), true, 512, JSON_THROW_ON_ERROR);
if ($res['success']!==true)
{
throw new \RuntimeException('Fehler bei der Übertragung.'.var_export($res,true));
}
$jobId =$job->getKnownOrder() !== null ? $job->getKnownOrder()->getOrderId().": " : '';
return new JsonResponse(['success'=>true,'message'=> $jobId.'Job übertragen.']);
}
catch (\Throwable $ex)
{
$jobId= '';
if ($job !== null)
{
$cleanCo = array_filter($job->getControlling(), function($v) { return strpos($v, self::XFER_ENTRY) === false; });
$cleanCo[]= self::XFER_ENTRY.$ex->getMessage();
$job->setControlling($cleanCo);
if ($repo !==null) $repo->flush($job);
SysLogRepository::logError($this->managerRegistry->getConnection(),$ex->getMessage().$ex->getTraceAsString(),$job);
$jobId =$job->getKnownOrder() !== null ? $job->getKnownOrder()->getOrderId().": " : '';
}
return new JsonResponse(['success'=>false,'message'=>$jobId.$ex->getMessage()]);
}
// $qb = $repo->createQueryBuilder('J');
// $qb->where($qb->expr()->in('J.id',':ids'))->setParameter('ids',$ids);
// $jobs = $qb->getQuery()->getResult();
// $clientCache = [];
// /** @var Job $job */
// foreach ($jobs as $job)
// {
// try
// {
// if ($job->getCustomer() === null)
// {
// throw new \RuntimeException("Kein Kunde im Auftrag");
// }
// if ($job->getKnownOrder() === null)
// {
// throw new \RuntimeException("Keine Bestellung im Auftrag");
// }
// if ($job->getCustomer()->getXchgPlatformUrl()=="")
// {
// throw new \RuntimeException("Fehlende Fremdsystem-URL");
// }
// if ($job->getKnownOrder()->getXchgStatus()!==Order::XCHG_RECEIVED_FROM_OTHER)
// {
// throw new \RuntimeException("Auftrag kommt nicht von Fremdsystem.");
// }
//
// if (!array_key_exists($job->getCustomer()->getId(),$clientCache))
// {
// $clientCache[$job->getCustomer()->getId()]= OrderHandler::getClientForCustomerWhoLoginsAsMember($job->getCustomer());;
// }
// $client = $clientCache[$job->getCustomer()->getId()];
//
// $res = $client->request("POST",rtrim($job->getCustomer()->getXchgPlatformUrl(),'/')."/job-update-by-oid",[
// 'headers'=> [
// "Content-Type"=>"application/json"
// ],
// 'body' => json_encode(
// [
// "login" => $job->getCustomer()->getXchgLoginAsMember(),
// "password" => $job->getCustomer()->getXchgLoginPassword(),
// "orderId"=> $job->getKnownOrder()->getXchgOrderId(),
// "xchg"=>true,
// // data
// 'flightOnPositionTime' => $this->timeOrNull($job->getFlightOnPositionTime()),
// 'departureAtOriginTime' => $this->timeOrNull($job->getDepartureAtOriginTime()),
// 'arrivalAtDestinationTime' => $this->timeOrNull($job->getArrivalAtDestinationTime()),
// 'passengerNotMet'=>$job->getPassengerNotMet(),
// 'taxameter'=>$job->getTaxameter(),
// 'taxameterVat'=>$job->getTaxameterVat(),
// 'extraCostName'=>$job->getExtraCostName(),
// 'extraCostPrice'=>$job->getExtraCostPrice(),
// 'hasMemberExtraKm' => $job->getHasMemberExtraKm(),
// 'memberExtraKm'=>$job->getMemberExtraKm(),
// 'confirmedByCustomerThrough'=>$job->getConfirmedByCustomerThrough(),
// 'approvedByDriver'=>$job->isApprovedByDriver(),
//
// 'werksRundfahrt' => $job->isWerksRundfahrt(),
// 'extraWaitingTimeRide' => $job->isExtraWaitingTimeRide(),
// 'extraWaitingTime' => $job->getExtraWaitingTime(),
// 'instantRideAdditionalWaitingTime' => $job->getInstantRideAdditionalWaitingTime(),
//
// ]
// , JSON_THROW_ON_ERROR)
// ]);
//
// $res = json_decode($res->getBody(), true, 512, JSON_THROW_ON_ERROR);
// if ($res['success']!==true)
// {
// throw new \RuntimeException('Fehler bei der Übertragung.'.var_export($res,true));
// }
// $this->addFlash("success",sprintf("Job %s: %s",$job->getKnownOrder()->getOrderId(),"Übertragen."));
// }
// catch (\Throwable $ex)
// {
// $this->addFlash('danger',sprintf("Job %s: %s",$job->getKnownOrder()->getOrderId(),$ex->getMessage()));
// SysLogRepository::logError($this->getDoctrine()->getConnection(),$ex->getMessage().$ex->getTraceAsString(),$job);
// }
// }
// return $this->redirectToRoute('acc-jobs');
}
public function customerRatesAction(Request $request, $customerId)
{
$repo = $this->managerRegistry->getRepository(Customer::class);
/** @var Customer $customer */
$customer = $repo->findOneBy(['id'=>$customerId]);
return new JsonResponse( $customer->getAccRates() );
}
public function memberRatesAction(Request $request, $memberId)
{
$repo = $this->managerRegistry->getRepository(CoopMember::class);
/** @var CoopMember $mem */
$mem = $repo->findOneBy(['id'=>$memberId]);
return new JsonResponse( $mem->getRates() );
}
public function checkReady4BillingAction(Request $request)
{
$this->init();
$this->ensureUserHasRole(Role::ACCOUNTING_EDIT);
/** @var JobRepository $repo */
$repo = $this->managerRegistry->getRepository(Job::class);
$ids = json_decode($request->request->get('selector','[]'),true);
if (count($ids)<1)
{
$this->addFlash('warning','Keine Einträge ausgewählt.');
return $this->redirectToRoute('acc-jobs');
}
$qb = $repo->createQueryBuilder('J');
$qb->where($qb->expr()->in('J.id',':ids'))->setParameter('ids',$ids);
$jobs = $qb->getQuery()->getResult();
/** @var Job $j */
foreach ($jobs as $j)
{
$msg = [];
JobRepository::detectReadyForBilling($j, $msg);
if ($j->isReadyForBilling())
{
$j->setLastChangeByMember(null);
}
$repo->flush($j);
$orderTitle = $j->getKnownOrder()!==null ? $j->getKnownOrder()->getOrderId() : 'null';
if ($j->getOrderNumber()!=='') $orderTitle.= ' (TaMi: '.$j->getOrderNumber().')';
if ($j->isReadyForBilling())
{
$this->addFlash('success', $orderTitle.': Buchung ist bereit zur Abrechnung');
}
else
{
$txt = '<b>'.$orderTitle.'</b><br>';
foreach ($msg as $k=>$m) {
$txt.= $m.'<br>';
}
$this->addFlash('danger',['html'=>$txt]);
}
}
return $this->redirectToRoute('acc-jobs');
}
public function approve4BillingAction(Request $request, $approveOrNot)
{
$this->init();
$this->ensureUserHasRole(Role::ACCOUNTING_EDIT);
/** @var JobRepository $repo */
$repo = $this->managerRegistry->getRepository(Job::class);
$ids = json_decode($request->request->get('selector','[]'),true);
if (count($ids)<1)
{
$this->addFlash('warning','Keine Einträge ausgewählt.');
return $this->redirectToRoute('acc-jobs');
}
$qb = $repo->createQueryBuilder('J');
$qb->where($qb->expr()->in('J.id',':ids'))->setParameter('ids',$ids);
$jobs = $qb->getQuery()->getResult();
/** @var Job $j */
foreach ($jobs as $j)
{
$on = ($j->getKnownOrder()!==null?$j->getKnownOrder()->getOrderId():'').' '.$j->getOrderNumber();
if (!$j->isReadyForBilling())
{
$this->addFlash('warning', $on.': Achtung: Buchung war nicht bereit zur Abrechnung. Freigabestatus wurde trotzdem verändert.');
}
/** @noinspection TypeUnsafeComparisonInspection */
$approveOrNot = ($approveOrNot==1);
$j->setApprovedByAccounting($approveOrNot);
$this->addFlash('success', $on.': '.($approveOrNot?"Freigegeben":"Freigabe entfernt"));
}
$repo->flush();
return $this->redirectToRoute('acc-jobs');
}
public function refreshFromOrderAction(Request $request, $jobId)
{
$this->init();
$this->ensureUserHasRole(Role::ACCOUNTING_EDIT);
$redir = $this->redirectToRoute('acc-jobs-edit',['id'=>$jobId]);
/** @var EntityManagerInterface $em */
$em = $this->managerRegistry->getManager();
/** @var JobRepository $repo */
$repo = $this->managerRegistry->getRepository(Job::class);
/** @var Job $job */
$job = $repo->findOneBy(['id'=>$jobId]);
if ($job->isApprovedByAccounting())
{
$this->addFlash('warning','Fahrtdaten wurden bereits durch die Abrechnung bestätigt. Abgleich mit Bestellung nicht mehr möglich.');
return $redir;
}
if ($job->getKnownOrder() === null)
{
$this->addFlash('warning','Es ist keine Bestellung verknüpft.');
return $redir;
}
$job->updateFromOrder($job->getKnownOrder());
$this->addFlash('info','Daten aus Bestellung neu übernommen');
if ($job->getMember()===null)
{
$job->setMember($job->getKnownOrder()->getAssignedTo());
if ($job->getMember()!==null)
{
$this->addFlash('info',sprintf('Mitglied %s wurde übernommen.',$job->getMember()->getName()));
}
}
else
{
if (( $job->getKnownOrder()->getAssignedTo()!==null)&&($job->getKnownOrder()->getAssignedTo()->getId()!=$job->getMember()->getId()) )
{
$this->addFlash('warning',sprintf('Achtung Mitglieder unterscheiden sich. Bestellung: %s, Fahrauftrag: %s. Diese Änderung wurde nicht automatisch übernommen.',
$job->getKnownOrder()->getAssignedTo()->getName(), $job->getMember()->getName()
));
}
}
$repo->flush();
return $redir;
}
public function reCalcDistanceAction(Request $request, $jobId)
{
$this->init();
$this->ensureUserHasRole(Role::ACCOUNTING_EDIT);
$redir = $this->redirectToRoute('acc-jobs-edit',['id'=>$jobId]);
/** @var EntityManagerInterface $em */
$em = $this->managerRegistry->getManager();
/** @var JobRepository $repo */
$repo = $this->managerRegistry->getRepository(Job::class);
/** @var Job $job */
$job = $repo->findOneBy(['id'=>$jobId]);
if ($job->isApprovedByAccounting())
{
$this->addFlash('warning','Fahrtdaten wurden bereits durch die Abrechnung bestätigt. Abgleich mit Bestellung nicht mehr möglich.');
return $redir;
}
if ($job->getKnownOrder() === null)
{
$this->addFlash('warning','Es ist keine Bestellung verknüpft.');
return $redir;
}
$calcService = $this->calculatorService;
/** @var Order $order */
$order = $job->getKnownOrder();
$flatWaypoints = [ $order->getPriceList()->getHomeAddress() ]; // start/endpoint
foreach ($order->getAddressList() as $a) {
$flatWaypoints[] = CalculatorService::addressToFlatString(json_decode(json_encode($a),true));
}
$distances = $calcService->getDistance($flatWaypoints);
$job->setActualKm( $calcService->getDistanceSumInKm($distances) );
$this->addFlash('info',sprintf('Berechnete Distanz: %02.2f',$job->getActualKm()));
$repo->flush();
return $redir;
}
public function reCheckCombiAction(Request $request, $jobId)
{
$this->init();
$this->ensureUserHasRole(Role::ACCOUNTING_EDIT);
$redir = $this->redirectToRoute('acc-jobs-edit',['id'=>$jobId]);
/** @var EntityManagerInterface $em */
$em = $this->managerRegistry->getManager();
/** @var JobRepository $repo */
$repo = $this->managerRegistry->getRepository(Job::class);
/** @var Job $job */
$job = $repo->findOneBy(['id'=>$jobId]);
if ($job->isApprovedByAccounting())
{
$this->addFlash('warning','Fahrtdaten wurden bereits durch die Abrechnung bestätigt. Aktualisierung nicht möglich.');
return $redir;
}
$pc = $this->paymentCalculator;
if ($pc->detectCombiAssociations($job))
{
$this->addFlash('info','Zuordnung wurde erneut durchgeführt');
$em->flush();
}
return $redir;
}
public function removeCombiAction(Request $request, $jobId)
{
$this->init();
$this->ensureUserHasRole(Role::ACCOUNTING_EDIT);
$redir = $this->redirectToRoute('acc-jobs-edit',['id'=>$jobId]);
/** @var EntityManagerInterface $em */
$em = $this->managerRegistry->getManager();
/** @var JobRepository $repo */
$repo = $this->managerRegistry->getRepository(Job::class);
/** @var Job $job */
$job = $repo->findOneBy(['id'=>$jobId]);
if ($job->isApprovedByAccounting())
{
$this->addFlash('warning','Fahrtdaten wurden bereits durch die Abrechnung bestätigt. Aktualisierung nicht möglich.');
return $redir;
}
self::removeRelation($job);
// if ($job->getCombiRideChild()!==null)
// {
// $job->getCombiRideChild()->setCombiRideParent(null);
// }
// $job->setCombiRideParent(null);
$job->setCombiAssignmentState(Job::CAS_MANUAL);
$em->flush();
$this->addFlash('info','Zuordnung wurde entfernt. Automatik deaktiviert.');
return $redir;
}
public function getPossibleCombiOptionsAction(Request $request, $jobId)
{
$this->init();
$this->ensureUserHasRole(Role::ACCOUNTING_EDIT);
$redir = $this->redirectToRoute('acc-jobs-edit',['id'=>$jobId]);
/** @var EntityManagerInterface $em */
$em = $this->managerRegistry->getManager();
/** @var JobRepository $repo */
$repo = $this->managerRegistry->getRepository(Job::class);
/** @var Job $job */
$job = $repo->findOneBy(['id'=>$jobId]);
$possible = $repo->findPossiblyRelatedRidesForMemberAsArray($job);
return $this->getJsonDataResponse($request,true,$possible);
}
protected static function removeRelation(Job $job)
{
if ($job->getCombiRideChild()!==null)
{
$job->getCombiRideChild()->setCombiRideParent(null);
}
$job->setCombiRideParent(null);
}
public function setManualCombiAction(Request $request, $jobId, $assignJobId)
{
$this->init();
$this->ensureUserHasRole(Role::ACCOUNTING_EDIT);
$redir = $this->redirectToRoute('acc-jobs-edit',['id'=>$jobId]);
/** @var EntityManagerInterface $em */
$em = $this->managerRegistry->getManager();
/** @var JobRepository $repo */
$repo = $this->managerRegistry->getRepository(Job::class);
/** @var Job $job */
$job = $repo->findOneBy(['id'=>$jobId]);
/** @var Job $assignJob */
$assignJob = $repo->findOneBy(['id'=>$assignJobId]);
if ($job->isApprovedByAccounting() || $assignJob->isApprovedByAccounting())
{
$this->addFlash('warning','Fahrtdaten wurden bereits durch die Abrechnung bestätigt. Aktualisierung nicht möglich.');
return $redir;
}
if ($jobId === $assignJobId)
{
$this->addFlash('warning','Zuordnung zweier gleicher Fahrten nicht möglich.');
return $redir;
}
// remove assignment
self::removeRelation($job);
self::removeRelation($assignJob);
// set assignment
if ($assignJob->getOrderTime() < $job->getOrderTime())
{
$job->setCombiRideParent($assignJob);
}
else
{
$assignJob->setCombiRideParent($job);
}
$job->setCombiAssignmentState(Job::CAS_MANUAL);
$assignJob->setCombiAssignmentState(Job::CAS_MANUAL);
$em->flush();
$this->addFlash('info','Zuordnung wurde gespeichert. Automatik deaktiviert.');
return $redir;
}
}