feat: render additional info to teamer invoice
This commit is contained in:
@@ -13,6 +13,7 @@ class Hotel
|
||||
private ?string $phone = null;
|
||||
private ?string $type = null;
|
||||
private ?string $country = null;
|
||||
private ?string $costUnit = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
@@ -121,4 +122,16 @@ class Hotel
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
public function getCostUnit(): ?string
|
||||
{
|
||||
return $this->costUnit;
|
||||
}
|
||||
|
||||
public function setCostUnit(?string $costUnit): static
|
||||
{
|
||||
$this->costUnit = $costUnit;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,6 +260,7 @@ class ResponseParser
|
||||
->setStreet((string) $item->strasse)
|
||||
->setPhone((string) $item->telefon)
|
||||
->setType((string) $item->art)
|
||||
->setCostUnit($item->kostenstelle)
|
||||
;
|
||||
$hotels[$busProId] = $hotel;
|
||||
}
|
||||
@@ -281,4 +282,4 @@ class ResponseParser
|
||||
|
||||
return $optionsResolver->resolve($options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +95,7 @@ class BpnImportCommand extends Command
|
||||
'date_to' => $dateTo->format('Y-m-d'),
|
||||
'product' => $product,
|
||||
'pickups' => json_encode($datePickups),
|
||||
'cost_unit' => $hotel->getCostUnit(),
|
||||
'country' => $hotel->getCountry(),
|
||||
'updated_at' => (new \DateTimeImmutable())->format('Y-m-d H:i:s')
|
||||
], [
|
||||
|
||||
@@ -4,11 +4,13 @@ namespace App\Controller\Administrative\Document;
|
||||
|
||||
use App\Controller\Traits\ReturnUrlTrait;
|
||||
use App\Entity\Upload;
|
||||
use App\Entity\User;
|
||||
use App\Event\DocumentConfirmedEvent;
|
||||
use App\Event\DocumentRejectedEvent;
|
||||
use App\Form\DocumentCheckType;
|
||||
use App\Htmx\HxRedirectResponse;
|
||||
use App\Model\DocumentCheckDto;
|
||||
use App\Service\Pdf\InvoiceApprover;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
@@ -29,6 +31,7 @@ class CheckController extends AbstractController
|
||||
#[Target('disposition')]
|
||||
private readonly WorkflowInterface $workflow,
|
||||
private readonly EventDispatcherInterface $eventDispatcher,
|
||||
private readonly InvoiceApprover $invoiceApprover,
|
||||
private readonly LoggerInterface $logger
|
||||
) {
|
||||
}
|
||||
@@ -114,7 +117,18 @@ class CheckController extends AbstractController
|
||||
|
||||
private function confirmDocument(Upload $document, string $transition, string $status, DocumentCheckDto $formData): void
|
||||
{
|
||||
$document->setStatus($status);
|
||||
/** @var User $user */
|
||||
$user = $this->getUser();
|
||||
$document
|
||||
->setApprovedAt(new \DateTimeImmutable())
|
||||
->setApprovedBy($user->getInitials())
|
||||
->setStatus($status)
|
||||
;
|
||||
|
||||
if (Upload::TYPE_INVOICE === $document->getType()) {
|
||||
$this->invoiceApprover->render($document->getDisposition());
|
||||
}
|
||||
|
||||
$this->addFlash('success', 'Das Dokument wurde bestätigt');
|
||||
$this->logger->info('Confirm document', [
|
||||
'document_id' => $document->getId(),
|
||||
|
||||
@@ -43,6 +43,10 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa
|
||||
#[Assert\NotNull(message: 'Bitte gib die Destination an')]
|
||||
private ?Destination $destination = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
#[Assert\NotBlank(message: 'Bitte gib den Konstenträger an')]
|
||||
private ?string $costCenter = null;
|
||||
|
||||
#[ORM\ManyToOne]
|
||||
#[Assert\NotNull(message: 'Bitte gib das Jobprofil an')]
|
||||
private ?JobProfile $jobProfile = null;
|
||||
@@ -194,6 +198,18 @@ class Assignment implements BlameableEntityInterface, TimestampableEntityInterfa
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCostCenter(): ?string
|
||||
{
|
||||
return $this->costCenter;
|
||||
}
|
||||
|
||||
public function setCostCenter(?string $costCenter): static
|
||||
{
|
||||
$this->costCenter = $costCenter;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getJobProfile(): ?JobProfile
|
||||
{
|
||||
return $this->jobProfile;
|
||||
|
||||
@@ -47,6 +47,9 @@ class Destination implements TimestampableEntityInterface, SoftDeletableEntityIn
|
||||
#[ORM\Column]
|
||||
private ?int $hotelBusProId = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?string $costUnit = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private array $pickups = [];
|
||||
|
||||
@@ -163,6 +166,18 @@ class Destination implements TimestampableEntityInterface, SoftDeletableEntityIn
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCostUnit(): ?string
|
||||
{
|
||||
return $this->costUnit;
|
||||
}
|
||||
|
||||
public function setCostUnit(?string $costUnit): static
|
||||
{
|
||||
$this->costUnit = $costUnit;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPickups(): array
|
||||
{
|
||||
return $this->pickups;
|
||||
|
||||
@@ -72,6 +72,12 @@ class Upload implements BlameableEntityInterface, TimestampableEntityInterface
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?string $downloadedBy = null;
|
||||
|
||||
#[ORM\Column(type: Types::DATE_IMMUTABLE, nullable: true)]
|
||||
private ?\DateTimeImmutable $approvedAt = null;
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?string $approvedBy = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->uuid = Uuid::v4();
|
||||
@@ -284,4 +290,28 @@ class Upload implements BlameableEntityInterface, TimestampableEntityInterface
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getApprovedAt(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->approvedAt;
|
||||
}
|
||||
|
||||
public function setApprovedAt(?\DateTimeImmutable $approvedAt): static
|
||||
{
|
||||
$this->approvedAt = $approvedAt;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getApprovedBy(): ?string
|
||||
{
|
||||
return $this->approvedBy;
|
||||
}
|
||||
|
||||
public function setApprovedBy(?string $approvedBy): static
|
||||
{
|
||||
$this->approvedBy = $approvedBy;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormEvent;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
@@ -57,6 +58,9 @@ class AssignmentType extends AbstractType
|
||||
'hx-swap' => 'innerHTML',
|
||||
],
|
||||
])
|
||||
->add('costCenter', TextType::class, [
|
||||
'label' => 'Kostenträger',
|
||||
])
|
||||
->add('jobProfile', EntityType::class, [
|
||||
'label' => 'Jobprofil',
|
||||
'class' => JobProfile::class,
|
||||
@@ -204,4 +208,4 @@ class AssignmentType extends AbstractType
|
||||
'anti_xss' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service\Pdf;
|
||||
|
||||
use App\Entity\Disposition;
|
||||
use App\Entity\Upload;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
||||
class InvoiceApprover extends AbstractPdfRenderer
|
||||
{
|
||||
public function render(Disposition $disposition): Pdf
|
||||
{
|
||||
$teamer = $disposition->getTeamer();
|
||||
$invoice = $disposition->getDocumentByType(Upload::TYPE_INVOICE);
|
||||
$originalPdfFilename = $invoice->getFilename();
|
||||
|
||||
$pdf = new Pdf();
|
||||
|
||||
$pdf->SetAuthor($teamer->getFullName(), true);
|
||||
$pdf->SetCreator($teamer->getFullName(), true);
|
||||
|
||||
// Load template
|
||||
$filepath = sprintf('%s/uploads/invoice/%s', $this->config['project_dir'], $originalPdfFilename);
|
||||
$pdf->appendPdf($filepath);
|
||||
$pdf->setPage(1);
|
||||
|
||||
$pdf->SetFont('Arial', '', 11);
|
||||
$pdf->SetTextColor(0, 128, 0);
|
||||
$pdf->Text(116.5,84, utf8_decode('geprüft: '.$invoice->getApprovedBy()));
|
||||
|
||||
$this->createBackup($filepath);
|
||||
|
||||
$pdf->Output('F', $filepath);
|
||||
|
||||
return $pdf;
|
||||
}
|
||||
|
||||
private function createBackup(string $source): void
|
||||
{
|
||||
$filesystem = new Filesystem();
|
||||
|
||||
if (!$filesystem->exists($source)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$path = pathinfo($source, PATHINFO_DIRNAME);
|
||||
$filename = pathinfo($source, PATHINFO_FILENAME);
|
||||
$extension = pathinfo($source, PATHINFO_EXTENSION);
|
||||
|
||||
$target = sprintf('%s/%s.bak.%s', $path, $filename, $extension);
|
||||
|
||||
$filesystem->copy($source, $target);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace App\Service\Pdf;
|
||||
|
||||
use App\Entity\Disposition;
|
||||
use App\Entity\Upload;
|
||||
|
||||
class InvoiceRenderer extends AbstractPdfRenderer
|
||||
{
|
||||
@@ -35,6 +36,18 @@ class InvoiceRenderer extends AbstractPdfRenderer
|
||||
// Tax ID
|
||||
$pdf->Text(144,62, utf8_decode($teamer->getTaxId()));
|
||||
|
||||
// Cost unit
|
||||
if (null !== $costUnit = $assignment->getDestination()->getCostUnit()) {
|
||||
$pdf->SetFont('Arial', '', 11);
|
||||
$pdf->Text(116.5,74, utf8_decode('Kostenstelle: '.$costUnit));
|
||||
}
|
||||
|
||||
// Cost center
|
||||
if (null !== $costCenter = $assignment->getCostCenter()) {
|
||||
$pdf->SetFont('Arial', '', 11);
|
||||
$pdf->Text(116.5,79, utf8_decode('Kostenträger: '.$costCenter));
|
||||
}
|
||||
|
||||
// Invoice number
|
||||
$pdf->SetFont('Arial', '', 12);
|
||||
$number = $assignment->getEffectivePeriod()->start->format('d/m/Y');
|
||||
|
||||
Reference in New Issue
Block a user