mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2026-05-13 15:01:30 +00:00
First order details draft
This commit is contained in:
parent
1a0fab0615
commit
62754bdbf3
13 changed files with 170 additions and 7 deletions
|
|
@ -48,9 +48,9 @@ class LessThanDesiredConstraint extends BooleanConstraint
|
|||
|
||||
//If value is true, we want to filter for parts with stock < desired stock
|
||||
if ($this->value) {
|
||||
$queryBuilder->andHaving( $this->property . ' < part.minamount');
|
||||
$queryBuilder->andHaving($this->property . ' + part.orderamount < part.minamount');
|
||||
} else {
|
||||
$queryBuilder->andHaving($this->property . ' >= part.minamount');
|
||||
$queryBuilder->andHaving($this->property . ' + part.orderamount >= part.minamount');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ class PartFilter implements FilterInterface
|
|||
public readonly TextConstraint $comment;
|
||||
public readonly TagsConstraint $tags;
|
||||
public readonly NumberConstraint $minAmount;
|
||||
public readonly NumberConstraint $orderAmount;
|
||||
public readonly DateTimeConstraint $orderDelivery;
|
||||
public readonly BooleanConstraint $favorite;
|
||||
public readonly BooleanConstraint $needsReview;
|
||||
public readonly NumberConstraint $mass;
|
||||
|
|
@ -124,6 +126,8 @@ class PartFilter implements FilterInterface
|
|||
$this->lastModified = new DateTimeConstraint('part.lastModified');
|
||||
|
||||
$this->minAmount = new NumberConstraint('part.minamount');
|
||||
$this->orderAmount = new NumberConstraint('part.orderamount');
|
||||
$this->orderDelivery = new DateTimeConstraint('part.orderDelivery');
|
||||
/* We have to use an IntConstraint here because otherwise we get just an empty result list when applying the filter
|
||||
This seems to be related to the fact, that PDO does not have an float parameter type and using string type does not work in this situation (at least in SQLite)
|
||||
TODO: Find a better solution here
|
||||
|
|
|
|||
|
|
@ -155,6 +155,15 @@ final class PartsDataTable implements DataTableTypeInterface
|
|||
'render' => fn($value, Part $context): string => htmlspecialchars($this->amountFormatter->format($value,
|
||||
$context->getPartUnit())),
|
||||
])
|
||||
->add('orderamount', TextColumn::class, [
|
||||
'label' => $this->translator->trans('part.table.orderamount'),
|
||||
'render' => fn($value, Part $context): string => htmlspecialchars($this->amountFormatter->format($value,
|
||||
$context->getPartUnit())),
|
||||
])
|
||||
->add('orderDelivery', LocaleDateTimeColumn::class, [
|
||||
'label' => $this->translator->trans('part.table.orderDelivery'),
|
||||
'timeFormat' => 'none',
|
||||
])
|
||||
->add('partUnit', TextColumn::class, [
|
||||
'label' => $this->translator->trans('part.table.partUnit'),
|
||||
'orderField' => 'NATSORT(_partUnit.name)',
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ use App\Validator\Constraints\UniqueObjectCollection;
|
|||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Doctrine\DBAL\Types\Types;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
|
@ -101,9 +102,9 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
|||
#[ApiFilter(LikeFilter::class, properties: ["name", "comment", "description", "ipn", "manufacturer_product_number"])]
|
||||
#[ApiFilter(TagFilter::class, properties: ["tags"])]
|
||||
#[ApiFilter(BooleanFilter::class, properties: ["favorite" , "needs_review"])]
|
||||
#[ApiFilter(RangeFilter::class, properties: ["mass", "minamount"])]
|
||||
#[ApiFilter(RangeFilter::class, properties: ["mass", "minamount", "orderamount"])]
|
||||
#[ApiFilter(DateFilter::class, strategy: DateFilterInterface::EXCLUDE_NULL)]
|
||||
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'addedDate', 'lastModified'])]
|
||||
#[ApiFilter(OrderFilter::class, properties: ['name', 'id', 'orderDelivery', 'addedDate', 'lastModified'])]
|
||||
class Part extends AttachmentContainingDBElement
|
||||
{
|
||||
use AdvancedPropertyTrait;
|
||||
|
|
@ -126,6 +127,15 @@ class Part extends AttachmentContainingDBElement
|
|||
#[UniqueObjectCollection(fields: ['name', 'group', 'element'])]
|
||||
protected Collection $parameters;
|
||||
|
||||
/**
|
||||
* @var \DateTimeInterface|null Set a time when the new order will arive.
|
||||
* Set to null, if there is no known date or no order.
|
||||
*/
|
||||
#[Groups(['extended', 'full', 'import', 'part_lot:read', 'part_lot:write'])]
|
||||
#[ORM\Column(name: 'orderDelivery', type: Types::DATETIME_MUTABLE, nullable: true)]
|
||||
#[Year2038BugWorkaround]
|
||||
protected ?\DateTimeInterface $orderDelivery = null;
|
||||
|
||||
|
||||
/** *************************************************************
|
||||
* Overridden properties
|
||||
|
|
@ -216,6 +226,26 @@ class Part extends AttachmentContainingDBElement
|
|||
parent::__clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the expected delivery date of the part. Returns null, if no delivery is due.
|
||||
*/
|
||||
public function getOrderDelivery(): ?\DateTimeInterface
|
||||
{
|
||||
return $this->orderDelivery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expected delivery date of the part. Set to null, if no delivery is due.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public function setOrderDelivery(?\DateTimeInterface $orderDelivery): self
|
||||
{
|
||||
$this->orderDelivery = $orderDelivery;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
#[Assert\Callback]
|
||||
public function validate(ExecutionContextInterface $context, $payload): void
|
||||
{
|
||||
|
|
|
|||
|
|
@ -55,6 +55,14 @@ trait InstockTrait
|
|||
#[ORM\Column(type: Types::FLOAT)]
|
||||
protected float $minamount = 0;
|
||||
|
||||
/**
|
||||
* @var float The number of already ordered units
|
||||
*/
|
||||
#[Assert\PositiveOrZero]
|
||||
#[Groups(['extended', 'full', 'import', 'part:read', 'part:write'])]
|
||||
#[ORM\Column(type: Types::FLOAT)]
|
||||
protected float $orderamount = 0;
|
||||
|
||||
/**
|
||||
* @var ?MeasurementUnit the unit in which the part's amount is measured
|
||||
*/
|
||||
|
|
@ -137,6 +145,21 @@ trait InstockTrait
|
|||
return round($this->minamount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the count of parts which are already ordered.
|
||||
* If an integer-based part unit is selected, the value will be rounded to integers.
|
||||
*
|
||||
* @return float count of parts which are already ordered
|
||||
*/
|
||||
public function getOrderAmount(): float
|
||||
{
|
||||
if ($this->useFloatAmount()) {
|
||||
return $this->orderamount;
|
||||
}
|
||||
|
||||
return round($this->orderamount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this part uses the float amount .
|
||||
* This setting is based on the part unit (see MeasurementUnit->isInteger()).
|
||||
|
|
@ -158,7 +181,7 @@ trait InstockTrait
|
|||
*/
|
||||
public function isNotEnoughInstock(): bool
|
||||
{
|
||||
return $this->getAmountSum() < $this->getMinAmount();
|
||||
return ($this->getAmountSum() + $this->getOrderAmount()) < $this->getMinAmount();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -238,4 +261,19 @@ trait InstockTrait
|
|||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the amount of already ordered parts.
|
||||
* See getPartUnit() for the associated unit.
|
||||
*
|
||||
* @param float $new_orderamount the new count of parts are already ordered
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setOrderAmount(float $new_orderamount): self
|
||||
{
|
||||
$this->orderamount = $new_orderamount;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,6 +202,16 @@ class PartFilterType extends AbstractType
|
|||
'min' => 0,
|
||||
]);
|
||||
|
||||
$builder->add('orderAmount', NumberConstraintType::class, [
|
||||
'label' => 'part.edit.orderstock',
|
||||
'min' => 0,
|
||||
]);
|
||||
|
||||
$builder->add('orderDelivery', DateTimeConstraintType::class, [
|
||||
'label' => 'part.edit.orderDelivery',
|
||||
'input_type' => DateType::class,
|
||||
]);
|
||||
|
||||
$builder->add('lotCount', NumberConstraintType::class, [
|
||||
'label' => 'part.filter.lot_count',
|
||||
'min' => 0,
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ use Symfony\Bundle\SecurityBundle\Security;
|
|||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\DateType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\EnumType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ResetType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
|
|
@ -96,6 +97,21 @@ class PartBaseType extends AbstractType
|
|||
'label' => 'part.edit.mininstock',
|
||||
'measurement_unit' => $part->getPartUnit(),
|
||||
])
|
||||
->add('orderAmount', SIUnitType::class, [
|
||||
'attr' => [
|
||||
'min' => 0,
|
||||
'placeholder' => 'part.editmininstock.placeholder',
|
||||
],
|
||||
'label' => 'part.edit.orderstock',
|
||||
'measurement_unit' => $part->getPartUnit(),
|
||||
])
|
||||
->add('orderDelivery', DateType::class, [
|
||||
'label' => 'part.edit.orderDelivery',
|
||||
'attr' => [],
|
||||
'widget' => 'single_text',
|
||||
'model_timezone' => 'UTC',
|
||||
'required' => false,
|
||||
])
|
||||
->add('category', StructuralEntityType::class, [
|
||||
'class' => Category::class,
|
||||
'allow_add' => $this->security->isGranted('@categories.create'),
|
||||
|
|
|
|||
|
|
@ -136,6 +136,9 @@ class PartNormalizer implements NormalizerInterface, DenormalizerInterface, Norm
|
|||
if (empty($data['minamount'])) {
|
||||
$data['minamount'] = 0.0;
|
||||
}
|
||||
if (empty($data['orderamount'])) {
|
||||
$data['orderamount'] = 0.0;
|
||||
}
|
||||
|
||||
$context[self::ALREADY_CALLED] = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ final class SandboxedTwigFactory
|
|||
Supplier::class => ['getShippingCosts', 'getDefaultCurrency'],
|
||||
Part::class => ['isNeedsReview', 'getTags', 'getMass', 'getIpn', 'getProviderReference',
|
||||
'getDescription', 'getComment', 'isFavorite', 'getCategory', 'getFootprint',
|
||||
'getPartLots', 'getPartUnit', 'useFloatAmount', 'getMinAmount', 'getAmountSum', 'isNotEnoughInstock', 'isAmountUnknown', 'getExpiredAmountSum',
|
||||
'getPartLots', 'getPartUnit', 'useFloatAmount', 'getMinAmount', 'getOrderAmount', 'getOrderDate', 'getAmountSum', 'isNotEnoughInstock', 'isAmountUnknown', 'getExpiredAmountSum',
|
||||
'getManufacturerProductUrl', 'getCustomProductURL', 'getManufacturingStatus', 'getManufacturer',
|
||||
'getManufacturerProductNumber', 'getOrderdetails', 'isObsolete',
|
||||
'getParameters', 'getGroupedParameters',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue