['invoice:read']], denormalizationContext: ['groups' => ['invoice:write']] )] class Invoice implements ModuleAwareInterface { #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column] #[Groups(['invoice:read'])] private ?int $id = null; #[ORM\Column(length: 50, unique: true)] #[Groups(['invoice:read', 'invoice:write'])] private string $invoiceNumber; #[ORM\Column] #[Groups(['invoice:read', 'invoice:write'])] private \DateTimeImmutable $invoiceDate; #[ORM\Column(nullable: true)] #[Groups(['invoice:read', 'invoice:write'])] private ?\DateTimeImmutable $dueDate = null; #[ORM\Column(length: 20)] #[Groups(['invoice:read', 'invoice:write'])] private string $status = 'draft'; // draft, sent, paid, overdue, cancelled #[ORM\Column(type: 'decimal', precision: 10, scale: 2)] #[Groups(['invoice:read'])] private string $totalAmount = '0.00'; #[ORM\Column(type: 'decimal', precision: 10, scale: 2)] #[Groups(['invoice:read'])] private string $taxAmount = '0.00'; #[ORM\Column(length: 3)] #[Groups(['invoice:read', 'invoice:write'])] private string $currency = 'EUR'; #[ORM\Column(type: 'text', nullable: true)] #[Groups(['invoice:read', 'invoice:write'])] private ?string $notes = null; /** * Verknüpfung zum Contact aus dem Core-System * (Über API-Relation, nicht über Foreign Key) */ #[ORM\Column(nullable: true)] #[Groups(['invoice:read', 'invoice:write'])] private ?int $contactId = null; /** * @var Collection */ #[ORM\OneToMany( targetEntity: InvoiceItem::class, mappedBy: 'invoice', cascade: ['persist', 'remove'], orphanRemoval: true )] #[Groups(['invoice:read', 'invoice:write'])] private Collection $items; #[ORM\Column] #[Groups(['invoice:read'])] private \DateTimeImmutable $createdAt; #[ORM\Column] #[Groups(['invoice:read'])] private \DateTimeImmutable $updatedAt; public function __construct() { $this->items = new ArrayCollection(); $this->invoiceDate = new \DateTimeImmutable(); $this->createdAt = new \DateTimeImmutable(); $this->updatedAt = new \DateTimeImmutable(); } // Getters und Setters... public function getId(): ?int { return $this->id; } public function getInvoiceNumber(): string { return $this->invoiceNumber; } public function setInvoiceNumber(string $invoiceNumber): self { $this->invoiceNumber = $invoiceNumber; return $this; } public function getStatus(): string { return $this->status; } public function setStatus(string $status): self { $this->status = $status; $this->updatedAt = new \DateTimeImmutable(); return $this; } public function getTotalAmount(): string { return $this->totalAmount; } public function setTotalAmount(string $totalAmount): self { $this->totalAmount = $totalAmount; return $this; } public function getContactId(): ?int { return $this->contactId; } public function setContactId(?int $contactId): self { $this->contactId = $contactId; return $this; } /** * @return Collection */ public function getItems(): Collection { return $this->items; } public function addItem(InvoiceItem $item): self { if (!$this->items->contains($item)) { $this->items->add($item); $item->setInvoice($this); } return $this; } public function removeItem(InvoiceItem $item): self { if ($this->items->removeElement($item)) { if ($item->getInvoice() === $this) { $item->setInvoice(null); } } return $this; } /** * Berechnet Gesamtsumme aus Items */ public function calculateTotal(): void { $total = 0; $tax = 0; foreach ($this->items as $item) { $itemTotal = $item->getQuantity() * (float) $item->getUnitPrice(); $total += $itemTotal; $tax += $itemTotal * ((float) $item->getTaxRate() / 100); } $this->totalAmount = number_format($total + $tax, 2, '.', ''); $this->taxAmount = number_format($tax, 2, '.', ''); $this->updatedAt = new \DateTimeImmutable(); } /** * ModuleAwareInterface: Gibt den Modul-Namen zurück */ public function getModuleName(): string { return 'billing'; } }