mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2026-01-18 08:09:34 +00:00
Merge 3408334a1f into 600686c32b
This commit is contained in:
commit
bd1163d6df
18 changed files with 275 additions and 7 deletions
48
migrations/Version20240905085300.php
Normal file
48
migrations/Version20240905085300.php
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
|
use App\Migration\AbstractMultiPlatformMigration;
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
|
||||||
|
final class Version20240905085300 extends AbstractMultiPlatformMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Added order fields';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function mySQLUp(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE parts ADD orderamount DOUBLE PRECISION NOT NULL DEFAULT 0, ADD orderDelivery DATETIME');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function mySQLDown(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE `parts` DROP orderamount, DROP orderDelivery');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function postgreSQLUp(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE parts ADD orderamount DOUBLE PRECISION NOT NULL DEFAULT 0, ADD orderDelivery timestamp');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function postgreSQLDown(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE parts DROP orderamount, DROP orderDelivery');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sqLiteUp(Schema $schema): void
|
||||||
|
{
|
||||||
|
$this->addSql('ALTER TABLE parts ADD COLUMN orderamount DOUBLE PRECISION NOT NULL DEFAULT 0');
|
||||||
|
$this->addSql('ALTER TABLE parts ADD COLUMN orderDelivery DATETIME');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sqLiteDown(Schema $schema): void
|
||||||
|
{
|
||||||
|
$error;
|
||||||
|
// TODO: implement backwards migration for SQlite
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -181,6 +181,27 @@ final class PartController extends AbstractController
|
||||||
return $this->redirectToRoute('bulk_info_provider_step2', ['jobId' => $jobId]);
|
return $this->redirectToRoute('bulk_info_provider_step2', ['jobId' => $jobId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Route(path: '/{id}/delivered', name: 'part_delivered')]
|
||||||
|
public function delivered(Part $part, Request $request): Response
|
||||||
|
{
|
||||||
|
$this->denyAccessUnlessGranted('edit', $part);
|
||||||
|
|
||||||
|
$partLot = $part->getPartLots()[0] ?? null;
|
||||||
|
if (!$partLot instanceof PartLot) {
|
||||||
|
$this->addFlash('error', 'part.delivered.error.no_lot');
|
||||||
|
return $this->redirectToRoute('part_info', ['id' => $part->getID()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$partLot->setAmount($partLot->getAmount() + $part->getOrderAmount());
|
||||||
|
$part->setOrderAmount(0);
|
||||||
|
$part->setOrderDelivery(null);
|
||||||
|
|
||||||
|
$this->em->persist($part);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
return $this->redirectToRoute('part_info', ['id' => $part->getID()]);
|
||||||
|
}
|
||||||
|
|
||||||
#[Route(path: '/{id}/delete', name: 'part_delete', methods: ['DELETE'])]
|
#[Route(path: '/{id}/delete', name: 'part_delete', methods: ['DELETE'])]
|
||||||
public function delete(Request $request, Part $part): RedirectResponse
|
public function delete(Request $request, Part $part): RedirectResponse
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ class LessThanDesiredConstraint extends BooleanConstraint
|
||||||
public function __construct(?string $property = null, ?string $identifier = null, ?bool $default_value = null)
|
public function __construct(?string $property = null, ?string $identifier = null, ?bool $default_value = null)
|
||||||
{
|
{
|
||||||
parent::__construct($property ?? '(
|
parent::__construct($property ?? '(
|
||||||
SELECT COALESCE(SUM(ld_partLot.amount), 0.0)
|
SELECT COALESCE(SUM(ld_partLot.amount) + part.orderamount, 0.0)
|
||||||
FROM '.PartLot::class.' ld_partLot
|
FROM '.PartLot::class.' ld_partLot
|
||||||
WHERE ld_partLot.part = part.id
|
WHERE ld_partLot.part = part.id
|
||||||
AND ld_partLot.instock_unknown = false
|
AND ld_partLot.instock_unknown = false
|
||||||
|
|
@ -48,7 +48,7 @@ class LessThanDesiredConstraint extends BooleanConstraint
|
||||||
|
|
||||||
//If value is true, we want to filter for parts with stock < desired stock
|
//If value is true, we want to filter for parts with stock < desired stock
|
||||||
if ($this->value) {
|
if ($this->value) {
|
||||||
$queryBuilder->andHaving( $this->property . ' < part.minamount');
|
$queryBuilder->andHaving($this->property . ' < part.minamount');
|
||||||
} else {
|
} else {
|
||||||
$queryBuilder->andHaving($this->property . ' >= part.minamount');
|
$queryBuilder->andHaving($this->property . ' >= part.minamount');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,8 @@ class PartFilter implements FilterInterface
|
||||||
public readonly TextConstraint $comment;
|
public readonly TextConstraint $comment;
|
||||||
public readonly TagsConstraint $tags;
|
public readonly TagsConstraint $tags;
|
||||||
public readonly NumberConstraint $minAmount;
|
public readonly NumberConstraint $minAmount;
|
||||||
|
public readonly NumberConstraint $orderAmount;
|
||||||
|
public readonly DateTimeConstraint $orderDelivery;
|
||||||
public readonly BooleanConstraint $favorite;
|
public readonly BooleanConstraint $favorite;
|
||||||
public readonly BooleanConstraint $needsReview;
|
public readonly BooleanConstraint $needsReview;
|
||||||
public readonly NumberConstraint $mass;
|
public readonly NumberConstraint $mass;
|
||||||
|
|
@ -135,6 +137,8 @@ class PartFilter implements FilterInterface
|
||||||
$this->lastModified = new DateTimeConstraint('part.lastModified');
|
$this->lastModified = new DateTimeConstraint('part.lastModified');
|
||||||
|
|
||||||
$this->minAmount = new NumberConstraint('part.minamount');
|
$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
|
/* 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)
|
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
|
TODO: Find a better solution here
|
||||||
|
|
|
||||||
|
|
@ -157,6 +157,15 @@ final class PartsDataTable implements DataTableTypeInterface
|
||||||
$context->getPartUnit()
|
$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, [
|
->add('partUnit', TextColumn::class, [
|
||||||
'label' => $this->translator->trans('part.table.partUnit'),
|
'label' => $this->translator->trans('part.table.partUnit'),
|
||||||
'orderField' => 'NATSORT(_partUnit.name)',
|
'orderField' => 'NATSORT(_partUnit.name)',
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Doctrine\Common\Collections\Criteria;
|
use Doctrine\Common\Collections\Criteria;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
use Doctrine\DBAL\Types\Types;
|
||||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
use Symfony\Component\Serializer\Annotation\Groups;
|
use Symfony\Component\Serializer\Annotation\Groups;
|
||||||
use Symfony\Component\Validator\Constraints as Assert;
|
use Symfony\Component\Validator\Constraints as Assert;
|
||||||
|
|
@ -112,9 +113,9 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||||
#[ApiFilter(LikeFilter::class, properties: ["name", "comment", "description", "ipn", "manufacturer_product_number"])]
|
#[ApiFilter(LikeFilter::class, properties: ["name", "comment", "description", "ipn", "manufacturer_product_number"])]
|
||||||
#[ApiFilter(TagFilter::class, properties: ["tags"])]
|
#[ApiFilter(TagFilter::class, properties: ["tags"])]
|
||||||
#[ApiFilter(BooleanFilter::class, properties: ["favorite", "needs_review"])]
|
#[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(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
|
class Part extends AttachmentContainingDBElement
|
||||||
{
|
{
|
||||||
use AdvancedPropertyTrait;
|
use AdvancedPropertyTrait;
|
||||||
|
|
@ -137,6 +138,15 @@ class Part extends AttachmentContainingDBElement
|
||||||
#[UniqueObjectCollection(fields: ['name', 'group', 'element'])]
|
#[UniqueObjectCollection(fields: ['name', 'group', 'element'])]
|
||||||
protected Collection $parameters;
|
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
|
* Overridden properties
|
||||||
|
|
@ -234,6 +244,26 @@ class Part extends AttachmentContainingDBElement
|
||||||
parent::__clone();
|
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]
|
#[Assert\Callback]
|
||||||
public function validate(ExecutionContextInterface $context, $payload): void
|
public function validate(ExecutionContextInterface $context, $payload): void
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,14 @@ trait InstockTrait
|
||||||
#[ORM\Column(type: Types::FLOAT)]
|
#[ORM\Column(type: Types::FLOAT)]
|
||||||
protected float $minamount = 0;
|
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
|
* @var ?MeasurementUnit the unit in which the part's amount is measured
|
||||||
*/
|
*/
|
||||||
|
|
@ -137,6 +145,21 @@ trait InstockTrait
|
||||||
return round($this->minamount);
|
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 .
|
* Checks if this part uses the float amount .
|
||||||
* This setting is based on the part unit (see MeasurementUnit->isInteger()).
|
* This setting is based on the part unit (see MeasurementUnit->isInteger()).
|
||||||
|
|
@ -158,7 +181,7 @@ trait InstockTrait
|
||||||
*/
|
*/
|
||||||
public function isNotEnoughInstock(): bool
|
public function isNotEnoughInstock(): bool
|
||||||
{
|
{
|
||||||
return $this->getAmountSum() < $this->getMinAmount();
|
return ($this->getAmountSum() + $this->getOrderAmount()) < $this->getMinAmount();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -238,4 +261,19 @@ trait InstockTrait
|
||||||
|
|
||||||
return $this;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -211,6 +211,16 @@ class PartFilterType extends AbstractType
|
||||||
'min' => 0,
|
'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, [
|
$builder->add('lotCount', NumberConstraintType::class, [
|
||||||
'label' => 'part.filter.lot_count',
|
'label' => 'part.filter.lot_count',
|
||||||
'min' => 0,
|
'min' => 0,
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ use Symfony\Bundle\SecurityBundle\Security;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
|
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\EnumType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\ResetType;
|
use Symfony\Component\Form\Extension\Core\Type\ResetType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
|
|
@ -96,6 +97,21 @@ class PartBaseType extends AbstractType
|
||||||
'label' => 'part.edit.mininstock',
|
'label' => 'part.edit.mininstock',
|
||||||
'measurement_unit' => $part->getPartUnit(),
|
'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, [
|
->add('category', StructuralEntityType::class, [
|
||||||
'class' => Category::class,
|
'class' => Category::class,
|
||||||
'allow_add' => $this->security->isGranted('@categories.create'),
|
'allow_add' => $this->security->isGranted('@categories.create'),
|
||||||
|
|
|
||||||
|
|
@ -136,6 +136,9 @@ class PartNormalizer implements NormalizerInterface, DenormalizerInterface, Norm
|
||||||
if (empty($data['minamount'])) {
|
if (empty($data['minamount'])) {
|
||||||
$data['minamount'] = 0.0;
|
$data['minamount'] = 0.0;
|
||||||
}
|
}
|
||||||
|
if (empty($data['orderamount'])) {
|
||||||
|
$data['orderamount'] = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
$context[self::ALREADY_CALLED] = true;
|
$context[self::ALREADY_CALLED] = true;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ class EntityURLGenerator
|
||||||
'delete' => $this->deleteURL($entity),
|
'delete' => $this->deleteURL($entity),
|
||||||
'file_download' => $this->downloadURL($entity),
|
'file_download' => $this->downloadURL($entity),
|
||||||
'file_view' => $this->viewURL($entity),
|
'file_view' => $this->viewURL($entity),
|
||||||
|
'delivered' => $this->deliveredURL($entity),
|
||||||
default => throw new InvalidArgumentException('Method is not supported!'),
|
default => throw new InvalidArgumentException('Method is not supported!'),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -169,6 +170,11 @@ class EntityURLGenerator
|
||||||
throw new \RuntimeException('Attachment has no internal nor external path!');
|
throw new \RuntimeException('Attachment has no internal nor external path!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function deliveredURL(Part $entity): string
|
||||||
|
{
|
||||||
|
return $this->urlGenerator->generate('part_delivered', ['id' => $entity->getID()]);
|
||||||
|
}
|
||||||
|
|
||||||
public function downloadURL($entity): string
|
public function downloadURL($entity): string
|
||||||
{
|
{
|
||||||
if (!($entity instanceof Attachment)) {
|
if (!($entity instanceof Attachment)) {
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ final class SandboxedTwigFactory
|
||||||
Supplier::class => ['getShippingCosts', 'getDefaultCurrency'],
|
Supplier::class => ['getShippingCosts', 'getDefaultCurrency'],
|
||||||
Part::class => ['isNeedsReview', 'getTags', 'getMass', 'getIpn', 'getProviderReference',
|
Part::class => ['isNeedsReview', 'getTags', 'getMass', 'getIpn', 'getProviderReference',
|
||||||
'getDescription', 'getComment', 'isFavorite', 'getCategory', 'getFootprint',
|
'getDescription', 'getComment', 'isFavorite', 'getCategory', 'getFootprint',
|
||||||
'getPartLots', 'getPartUnit', 'useFloatAmount', 'getMinAmount', 'getAmountSum', 'isNotEnoughInstock', 'isAmountUnknown', 'getExpiredAmountSum',
|
'getPartLots', 'getPartUnit', 'useFloatAmount', 'getMinAmount', 'getOrderAmount', 'getOrderDelivery', 'getAmountSum', 'isNotEnoughInstock', 'isAmountUnknown', 'getExpiredAmountSum',
|
||||||
'getManufacturerProductUrl', 'getCustomProductURL', 'getManufacturingStatus', 'getManufacturer',
|
'getManufacturerProductUrl', 'getCustomProductURL', 'getManufacturingStatus', 'getManufacturer',
|
||||||
'getManufacturerProductNumber', 'getOrderdetails', 'isObsolete',
|
'getManufacturerProductNumber', 'getOrderdetails', 'isObsolete',
|
||||||
'getParameters', 'getGroupedParameters',
|
'getParameters', 'getGroupedParameters',
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@
|
||||||
{{ form_row(form.category) }}
|
{{ form_row(form.category) }}
|
||||||
{{ form_row(form.tags) }}
|
{{ form_row(form.tags) }}
|
||||||
{{ form_row(form.minAmount) }}
|
{{ form_row(form.minAmount) }}
|
||||||
|
{{ form_row(form.orderAmount) }}
|
||||||
|
{{ form_row(form.orderDelivery) }}
|
||||||
|
|
||||||
{{ form_row(form.footprint) }}
|
{{ form_row(form.footprint) }}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,17 @@
|
||||||
{% if part.expiredAmountSum > 0 %}
|
{% if part.expiredAmountSum > 0 %}
|
||||||
<span title="{% trans %}part_lots.is_expired{% endtrans %}" class="text-muted">(+{{ part.expiredAmountSum }})</span>
|
<span title="{% trans %}part_lots.is_expired{% endtrans %}" class="text-muted">(+{{ part.expiredAmountSum }})</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if part.orderAmount > 0 %}
|
||||||
|
(+
|
||||||
|
<span title="{% trans %}orderstock.label{% endtrans %}">{{ part.orderAmount | format_amount(part.partUnit) }}</span>
|
||||||
|
{% if part.orderDelivery %}
|
||||||
|
@
|
||||||
|
<span class="badge bg-info mb-1" title="{% trans %}part.filter.orderDelivery{% endtrans %}">
|
||||||
|
<i class="fas fa-calendar-alt fa-fw"></i> {{ part.orderDelivery | format_date() }}<br>
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
)
|
||||||
|
{% endif %}
|
||||||
/
|
/
|
||||||
<span title="{% trans %}mininstock.label{% endtrans %}">{{ part.minAmount | format_amount(part.partUnit) }}</span>
|
<span title="{% trans %}mininstock.label{% endtrans %}">{{ part.minAmount | format_amount(part.partUnit) }}</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,14 @@
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if is_granted('edit', part) %}
|
||||||
|
<br>
|
||||||
|
<a class="btn btn-info mt-2" href="{{ entity_url(part, 'delivered') }}">
|
||||||
|
<i class="fas fa-cloud-arrow-down"></i>
|
||||||
|
{% trans %}part.delivered.btn{% endtrans %}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
<form method="post" class="mt-2" action="{{ entity_url(part, 'delete') }}"
|
<form method="post" class="mt-2" action="{{ entity_url(part, 'delete') }}"
|
||||||
{{ stimulus_controller('elements/delete_btn') }} {{ stimulus_action('elements/delete_btn', "submit", "submit") }}
|
{{ stimulus_controller('elements/delete_btn') }} {{ stimulus_action('elements/delete_btn', "submit", "submit") }}
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,8 @@
|
||||||
<div class="tab-pane pt-3" id="filter-stocks" role="tabpanel" aria-labelledby="filter-stocks-tab" tabindex="0">
|
<div class="tab-pane pt-3" id="filter-stocks" role="tabpanel" aria-labelledby="filter-stocks-tab" tabindex="0">
|
||||||
{{ form_row(filterForm.storelocation) }}
|
{{ form_row(filterForm.storelocation) }}
|
||||||
{{ form_row(filterForm.minAmount) }}
|
{{ form_row(filterForm.minAmount) }}
|
||||||
|
{{ form_row(filterForm.orderAmount) }}
|
||||||
|
{{ form_row(filterForm.orderDelivery) }}
|
||||||
{{ form_row(filterForm.amountSum) }}
|
{{ form_row(filterForm.amountSum) }}
|
||||||
{{ form_row(filterForm.lessThanDesired) }}
|
{{ form_row(filterForm.lessThanDesired) }}
|
||||||
{{ form_row(filterForm.lotCount) }}
|
{{ form_row(filterForm.lotCount) }}
|
||||||
|
|
@ -162,4 +164,4 @@
|
||||||
{{ form_end(filterForm) }}
|
{{ form_end(filterForm) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -4820,6 +4820,18 @@ Wenn Sie dies fehlerhafterweise gemacht haben oder ein Computer nicht mehr vertr
|
||||||
<target>Min. Menge</target>
|
<target>Min. Menge</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
|
<unit id="paZGdmg" name="part.table.orderamount">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>part.table.orderamount</source>
|
||||||
|
<target>Bestellte Menge</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="paZGdmh" name="part.table.orderDelivery">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>part.table.orderDelivery</source>
|
||||||
|
<target>Lieferdatum</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
<unit id="F6gnPca" name="part.table.partUnit">
|
<unit id="F6gnPca" name="part.table.partUnit">
|
||||||
<notes>
|
<notes>
|
||||||
<note category="file-source" priority="1">Part-DB1\src\DataTables\PartsDataTable.php:232</note>
|
<note category="file-source" priority="1">Part-DB1\src\DataTables\PartsDataTable.php:232</note>
|
||||||
|
|
@ -5584,6 +5596,18 @@ Wenn Sie dies fehlerhafterweise gemacht haben oder ein Computer nicht mehr vertr
|
||||||
<target>Mindestbestand</target>
|
<target>Mindestbestand</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
|
<unit id="AVZaczj" name="part.edit.orderstock">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>part.edit.orderstock</source>
|
||||||
|
<target>Bestellte Menge</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="AVZaczk" name="part.edit.orderDelivery">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>part.edit.orderDelivery</source>
|
||||||
|
<target>Lieferdatum</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
<unit id="EpsnDlo" name="part.edit.category">
|
<unit id="EpsnDlo" name="part.edit.category">
|
||||||
<notes>
|
<notes>
|
||||||
<note category="file-source" priority="1">Part-DB1\src\Form\Part\PartBaseType.php:129</note>
|
<note category="file-source" priority="1">Part-DB1\src\Form\Part\PartBaseType.php:129</note>
|
||||||
|
|
@ -12076,6 +12100,12 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
|
||||||
<target>Bauteil aus Informationsquelle aktualisieren</target>
|
<target>Bauteil aus Informationsquelle aktualisieren</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
|
<unit id="Bxk6TEx" name="part.delivered.btn">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>part.delivered.btn</source>
|
||||||
|
<target>Bestellte Menge wurde geliefert</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
<unit id="7pDRUQB" name="info_providers.update_part.title">
|
<unit id="7pDRUQB" name="info_providers.update_part.title">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>info_providers.update_part.title</source>
|
<source>info_providers.update_part.title</source>
|
||||||
|
|
|
||||||
|
|
@ -2345,6 +2345,18 @@ Sub elements will be moved upwards.</target>
|
||||||
<target>Minimum amount</target>
|
<target>Minimum amount</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
|
<unit id="paZGdmg" name="part.table.orderamount">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>part.table.orderamount</source>
|
||||||
|
<target>Ordered amount</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="paZGdmh" name="part.table.orderDelivery">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>part.table.orderDelivery</source>
|
||||||
|
<target>Delivery date</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
<unit id="oO3jvSb" name="part.order.price">
|
<unit id="oO3jvSb" name="part.order.price">
|
||||||
<notes>
|
<notes>
|
||||||
<note category="file-source" priority="1">Part-DB1\templates\Parts\info\_order_infos.html.twig:29</note>
|
<note category="file-source" priority="1">Part-DB1\templates\Parts\info\_order_infos.html.twig:29</note>
|
||||||
|
|
@ -5585,6 +5597,18 @@ If you have done this incorrectly or if a computer is no longer trusted, you can
|
||||||
<target>Minimum stock</target>
|
<target>Minimum stock</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
|
<unit id="AVZaczj" name="part.edit.orderstock">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>part.edit.orderstock</source>
|
||||||
|
<target>Ordered amount</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="AVZaczk" name="part.edit.orderDelivery">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>part.edit.orderDelivery</source>
|
||||||
|
<target>Delivery date</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
<unit id="EpsnDlo" name="part.edit.category">
|
<unit id="EpsnDlo" name="part.edit.category">
|
||||||
<notes>
|
<notes>
|
||||||
<note category="file-source" priority="1">Part-DB1\src\Form\Part\PartBaseType.php:129</note>
|
<note category="file-source" priority="1">Part-DB1\src\Form\Part\PartBaseType.php:129</note>
|
||||||
|
|
@ -12077,6 +12101,12 @@ Please note, that you can not impersonate a disabled user. If you try you will g
|
||||||
<target>Update part from info providers</target>
|
<target>Update part from info providers</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
|
<unit id="Bxk6TEx" name="part.delivered.btn">
|
||||||
|
<segment state="translated">
|
||||||
|
<source>part.delivered.btn</source>
|
||||||
|
<target>Ordered amount has been delivered</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
<unit id="7pDRUQB" name="info_providers.update_part.title">
|
<unit id="7pDRUQB" name="info_providers.update_part.title">
|
||||||
<segment state="translated">
|
<segment state="translated">
|
||||||
<source>info_providers.update_part.title</source>
|
<source>info_providers.update_part.title</source>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue