Part-DB-server/src/Entity/Parts/Supplier.php

232 lines
9.7 KiB
PHP
Raw Normal View History

<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
2022-11-29 22:28:53 +01:00
* Copyright (C) 2019 - 2022 Jan Böhmer (https://github.com/jbtronics)
*
2020-02-22 18:14:36 +01:00
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2020-02-22 18:14:36 +01:00
* GNU Affero General Public License for more details.
*
2020-02-22 18:14:36 +01:00
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace App\Entity\Parts;
2024-06-22 00:31:43 +02:00
use Doctrine\Common\Collections\Criteria;
2024-03-03 19:57:31 +01:00
use ApiPlatform\Doctrine\Common\Filter\DateFilterInterface;
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
2023-08-06 20:57:32 +02:00
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Get;
2023-08-06 20:57:32 +02:00
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Link;
use ApiPlatform\Metadata\McpTool;
use ApiPlatform\Metadata\McpToolCollection;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
2023-10-25 20:40:41 +02:00
use ApiPlatform\OpenApi\Model\Operation;
2023-08-06 20:57:32 +02:00
use ApiPlatform\Serializer\Filter\PropertyFilter;
use App\ApiPlatform\Filter\LikeFilter;
use App\Entity\Attachments\Attachment;
use App\Mcp\DTO\ElementByIdInput;
use App\Mcp\DTO\StructuralElementOverview;
use App\Mcp\DTO\StructuralElementSearchInput;
2023-06-11 14:55:06 +02:00
use App\Repository\Parts\SupplierRepository;
use App\State\Mcp\GetStructuralElementDetailsProcessor;
use App\State\Mcp\ListStructuralElementsProcessor;
2023-06-11 14:55:06 +02:00
use App\Entity\PriceInformations\Orderdetail;
use Doctrine\Common\Collections\ArrayCollection;
use App\Entity\Attachments\SupplierAttachment;
use App\Entity\Base\AbstractCompany;
2023-04-15 22:25:03 +02:00
use App\Entity\Base\AbstractStructuralDBElement;
use App\Entity\Parameters\SupplierParameter;
use App\Entity\PriceInformations\Currency;
use App\Validator\Constraints\BigDecimal\BigDecimalPositiveOrZero;
use App\Validator\Constraints\Selectable;
use Brick\Math\BigDecimal;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
2023-03-13 00:52:22 +01:00
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
/**
2023-06-13 10:36:34 +02:00
* This entity represents a supplier of parts (the company that sells the parts).
*
* @extends AbstractCompany<SupplierAttachment, SupplierParameter>
*/
2023-06-11 14:55:06 +02:00
#[ORM\Entity(repositoryClass: SupplierRepository::class)]
#[ORM\Table('`suppliers`')]
2024-03-03 19:57:31 +01:00
#[ORM\Index(columns: ['name'], name: 'supplier_idx_name')]
#[ORM\Index(columns: ['parent_id', 'name'], name: 'supplier_idx_parent_name')]
2023-08-06 20:57:32 +02:00
#[ApiResource(
operations: [
new Get(security: 'is_granted("read", object)'),
new GetCollection(security: 'is_granted("@suppliers.read")'),
new Post(securityPostDenormalize: 'is_granted("create", object)'),
new Patch(security: 'is_granted("edit", object)'),
new Delete(security: 'is_granted("delete", object)'),
new GetCollection(
uriTemplate: '/suppliers/{id}/children.{_format}',
uriVariables: ['id' => new Link(fromProperty: 'children', fromClass: Supplier::class)],
openapi: new Operation(summary: 'Retrieves the children elements of a supplier.'),
security: 'is_granted("@manufacturers.read")'
),
],
2023-08-06 20:57:32 +02:00
normalizationContext: ['groups' => ['supplier:read', 'company:read', 'api:basic:read'], 'openapi_definition_name' => 'Read'],
denormalizationContext: ['groups' => ['supplier:write', 'company:write', 'api:basic:write', 'attachment:write', 'parameter:write'], 'openapi_definition_name' => 'Write'],
mcp: [
'list_suppliers' => new McpToolCollection(
title: 'List/search suppliers',
description: 'List all suppliers, optionally filtered by a keyword matched against the name and comment. Each entry includes its full hierarchical path, and results are sorted by that path so parents are immediately followed by their own children, making it easy to derive the tree structure from the flat list.',
annotations: ['readOnlyHint' => true, 'destructiveHint' => false, 'idempotentHint' => true, 'openWorldHint' => false],
output: StructuralElementOverview::class,
normalizationContext: ['groups' => ['mcp_structural_overview:read']],
input: StructuralElementSearchInput::class,
security: 'is_granted("@suppliers.read")',
processor: ListStructuralElementsProcessor::class,
),
'get_supplier_details' => new McpTool(
title: 'Get supplier details by ID',
description: 'Get detailed information about a specific supplier by its database ID.',
annotations: ['readOnlyHint' => true, 'destructiveHint' => false, 'idempotentHint' => true, 'openWorldHint' => false],
normalizationContext: ['groups' => ['supplier:read', 'company:read', 'api:basic:read']],
input: ElementByIdInput::class,
security: 'is_granted("@suppliers.read")',
validate: true,
processor: GetStructuralElementDetailsProcessor::class,
),
],
2023-08-06 20:57:32 +02:00
)]
#[ApiFilter(PropertyFilter::class)]
#[ApiFilter(LikeFilter::class, properties: ["name", "comment"])]
2024-03-03 19:57:31 +01:00
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])]
class Supplier extends AbstractCompany
{
2024-03-03 19:57:31 +01:00
#[ORM\OneToMany(mappedBy: 'parent', targetEntity: self::class)]
2024-06-22 00:31:43 +02:00
#[ORM\OrderBy(['name' => Criteria::ASC])]
2023-04-15 22:25:03 +02:00
protected Collection $children;
2023-06-13 20:24:54 +02:00
#[ORM\ManyToOne(targetEntity: self::class, inversedBy: 'children')]
#[ORM\JoinColumn(name: 'parent_id')]
2023-08-06 20:57:32 +02:00
#[Groups(['supplier:read', 'supplier:write'])]
#[ApiProperty(readableLink: false, writableLink: false)]
protected ?AbstractStructuralDBElement $parent = null;
2023-06-11 14:55:06 +02:00
/**
* @var Collection<int, Orderdetail>
2023-06-11 14:55:06 +02:00
*/
2024-03-03 19:57:31 +01:00
#[ORM\OneToMany(mappedBy: 'supplier', targetEntity: Orderdetail::class)]
2023-04-15 22:25:03 +02:00
protected Collection $orderdetails;
/**
* @var Currency|null The currency that should be used by default for order informations with this supplier.
* Set to null, to use global base currency.
*/
2023-06-11 14:55:06 +02:00
#[ORM\ManyToOne(targetEntity: Currency::class)]
#[ORM\JoinColumn(name: 'default_currency_id')]
2024-03-03 19:57:31 +01:00
#[Selectable]
2022-09-18 22:59:31 +02:00
protected ?Currency $default_currency = null;
/**
* @var BigDecimal|null The shipping costs that have to be paid, when ordering via this supplier
*/
2023-05-28 01:21:05 +02:00
#[Groups(['extended', 'full', 'import'])]
2024-03-03 19:57:31 +01:00
#[ORM\Column(name: 'shipping_costs', type: 'big_decimal', precision: 11, scale: 5, nullable: true)]
#[BigDecimalPositiveOrZero]
2022-09-18 22:59:31 +02:00
protected ?BigDecimal $shipping_costs = null;
2020-01-05 22:49:00 +01:00
/**
2020-03-29 23:13:25 +02:00
* @var Collection<int, SupplierAttachment>
2020-01-05 22:49:00 +01:00
*/
2023-05-28 01:21:05 +02:00
#[Assert\Valid]
2024-03-03 19:57:31 +01:00
#[ORM\OneToMany(mappedBy: 'element', targetEntity: SupplierAttachment::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
2024-06-22 00:31:43 +02:00
#[ORM\OrderBy(['name' => Criteria::ASC])]
2023-08-06 20:57:32 +02:00
#[Groups(['supplier:read', 'supplier:write'])]
#[ApiProperty(readableLink: false, writableLink: true)]
2023-04-15 22:25:03 +02:00
protected Collection $attachments;
#[ORM\ManyToOne(targetEntity: SupplierAttachment::class)]
#[ORM\JoinColumn(name: 'id_preview_attachment', onDelete: 'SET NULL')]
2023-08-06 20:57:32 +02:00
#[Groups(['supplier:read', 'supplier:write'])]
#[ApiProperty(readableLink: false, writableLink: true)]
protected ?Attachment $master_picture_attachment = null;
2020-03-29 23:13:25 +02:00
/** @var Collection<int, SupplierParameter>
*/
2023-05-28 01:21:05 +02:00
#[Assert\Valid]
2024-03-03 19:57:31 +01:00
#[ORM\OneToMany(mappedBy: 'element', targetEntity: SupplierParameter::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
2024-06-22 00:31:43 +02:00
#[ORM\OrderBy(['group' => Criteria::ASC, 'name' => 'ASC'])]
2023-08-06 20:57:32 +02:00
#[Groups(['supplier:read', 'supplier:write'])]
#[ApiProperty(readableLink: false, writableLink: true)]
2023-04-15 22:25:03 +02:00
protected Collection $parameters;
/**
2019-09-16 22:04:59 +02:00
* Gets the currency that should be used by default, when creating a orderdetail with this supplier.
*/
public function getDefaultCurrency(): ?Currency
{
return $this->default_currency;
}
/**
2019-09-16 22:04:59 +02:00
* Sets the default currency.
*/
public function setDefaultCurrency(?Currency $default_currency): self
{
$this->default_currency = $default_currency;
return $this;
}
/**
2019-09-16 22:04:59 +02:00
* Gets the shipping costs for an order with this supplier, given in base currency.
*
* @return BigDecimal|null A BigDecimal with the shipping costs
*/
public function getShippingCosts(): ?BigDecimal
{
return $this->shipping_costs;
}
/**
2019-09-16 22:04:59 +02:00
* Sets the shipping costs for an order with this supplier.
*
* @param BigDecimal|null $shipping_costs a BigDecimal with the shipping costs
*/
public function setShippingCosts(?BigDecimal $shipping_costs): self
{
2023-06-11 14:55:06 +02:00
if (!$shipping_costs instanceof BigDecimal) {
$this->shipping_costs = null;
}
//Only change the object, if the value changes, so that doctrine does not detect it as changed.
if ((string) $shipping_costs !== (string) $this->shipping_costs) {
$this->shipping_costs = $shipping_costs;
}
return $this;
}
public function __construct()
{
parent::__construct();
2023-06-11 14:55:06 +02:00
$this->children = new ArrayCollection();
$this->orderdetails = new ArrayCollection();
$this->attachments = new ArrayCollection();
$this->parameters = new ArrayCollection();
}
}