diff --git a/src/DataTables/Helpers/PartDataTableHelper.php b/src/DataTables/Helpers/PartDataTableHelper.php index 8499e303..c33c3a82 100644 --- a/src/DataTables/Helpers/PartDataTableHelper.php +++ b/src/DataTables/Helpers/PartDataTableHelper.php @@ -20,14 +20,17 @@ declare(strict_types=1); * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + namespace App\DataTables\Helpers; +use App\Entity\Parts\StorageLocation; use App\Entity\ProjectSystem\Project; use App\Entity\Attachments\Attachment; use App\Entity\Parts\Part; use App\Services\Attachments\AttachmentURLGenerator; use App\Services\Attachments\PartPreviewGenerator; use App\Services\EntityURLGenerator; +use App\Services\Formatters\AmountFormatter; use Symfony\Contracts\Translation\TranslatorInterface; /** @@ -35,8 +38,13 @@ use Symfony\Contracts\Translation\TranslatorInterface; */ class PartDataTableHelper { - public function __construct(private readonly PartPreviewGenerator $previewGenerator, private readonly AttachmentURLGenerator $attachmentURLGenerator, private readonly EntityURLGenerator $entityURLGenerator, private readonly TranslatorInterface $translator) - { + public function __construct( + private readonly PartPreviewGenerator $previewGenerator, + private readonly AttachmentURLGenerator $attachmentURLGenerator, + private readonly EntityURLGenerator $entityURLGenerator, + private readonly TranslatorInterface $translator, + private readonly AmountFormatter $amountFormatter, + ) { } public function renderName(Part $context): string @@ -45,14 +53,16 @@ class PartDataTableHelper //Depending on the part status we show a different icon (the later conditions have higher priority) if ($context->isFavorite()) { - $icon = sprintf('', $this->translator->trans('part.favorite.badge')); + $icon = sprintf('', + $this->translator->trans('part.favorite.badge')); } if ($context->isNeedsReview()) { - $icon = sprintf('', $this->translator->trans('part.needs_review.badge')); + $icon = sprintf('', + $this->translator->trans('part.needs_review.badge')); } if ($context->getBuiltProject() instanceof Project) { $icon = sprintf('', - $this->translator->trans('part.info.projectBuildPart.hint') . ': ' . $context->getBuiltProject()->getName()); + $this->translator->trans('part.info.projectBuildPart.hint').': '.$context->getBuiltProject()->getName()); } @@ -85,4 +95,62 @@ class PartDataTableHelper $title ); } + + public function renderStorageLocations(Part $context): string + { + $tmp = []; + foreach ($context->getPartLots() as $lot) { + //Ignore lots without storelocation + if (!$lot->getStorageLocation() instanceof StorageLocation) { + continue; + } + $tmp[] = sprintf( + '%s', + $this->entityURLGenerator->listPartsURL($lot->getStorageLocation()), + htmlspecialchars($lot->getStorageLocation()->getFullPath()), + htmlspecialchars($lot->getStorageLocation()->getName()) + ); + } + + return implode('
', $tmp); + } + + public function renderAmount(Part $context): string + { + $amount = $context->getAmountSum(); + $expiredAmount = $context->getExpiredAmountSum(); + + $ret = ''; + + if ($context->isAmountUnknown()) { + //When all amounts are unknown, we show a question mark + if ($amount === 0.0) { + $ret .= sprintf('?', + $this->translator->trans('part_lots.instock_unknown')); + } else { //Otherwise mark it with greater equal and the (known) amount + $ret .= sprintf('', + $this->translator->trans('part_lots.instock_unknown') + ); + $ret .= htmlspecialchars($this->amountFormatter->format($amount, $context->getPartUnit())); + } + } else { + $ret .= htmlspecialchars($this->amountFormatter->format($amount, $context->getPartUnit())); + } + + //If we have expired lots, we show them in parentheses behind + if ($expiredAmount > 0) { + $ret .= sprintf(' (+%s)', + $this->translator->trans('part_lots.is_expired'), + htmlspecialchars($this->amountFormatter->format($expiredAmount, $context->getPartUnit()))); + } + + //When the amount is below the minimum amount, we highlight the number red + if ($context->isNotEnoughInstock()) { + $ret = sprintf('%s', + $this->translator->trans('part.info.amount.less_than_desired'), + $ret); + } + + return $ret; + } } diff --git a/src/DataTables/PartsDataTable.php b/src/DataTables/PartsDataTable.php index 1718ca7c..8a5cd42a 100644 --- a/src/DataTables/PartsDataTable.php +++ b/src/DataTables/PartsDataTable.php @@ -139,63 +139,11 @@ final class PartsDataTable implements DataTableTypeInterface ->add('storelocation', TextColumn::class, [ 'label' => $this->translator->trans('part.table.storeLocations'), 'orderField' => 'storelocations.name', - 'render' => function ($value, Part $context): string { - $tmp = []; - foreach ($context->getPartLots() as $lot) { - //Ignore lots without storelocation - if (!$lot->getStorageLocation() instanceof StorageLocation) { - continue; - } - $tmp[] = sprintf( - '%s', - $this->urlGenerator->listPartsURL($lot->getStorageLocation()), - htmlspecialchars($lot->getStorageLocation()->getFullPath()), - htmlspecialchars($lot->getStorageLocation()->getName()) - ); - } - - return implode('
', $tmp); - }, + 'render' => fn ($value, Part $context) => $this->partDataTableHelper->renderStorageLocations($context), ], alias: 'storage_location') ->add('amount', TextColumn::class, [ 'label' => $this->translator->trans('part.table.amount'), - 'render' => function ($value, Part $context) { - $amount = $context->getAmountSum(); - $expiredAmount = $context->getExpiredAmountSum(); - - $ret = ''; - - if ($context->isAmountUnknown()) { - //When all amounts are unknown, we show a question mark - if ($amount === 0.0) { - $ret .= sprintf('?', - $this->translator->trans('part_lots.instock_unknown')); - } else { //Otherwise mark it with greater equal and the (known) amount - $ret .= sprintf('', - $this->translator->trans('part_lots.instock_unknown') - ); - $ret .= htmlspecialchars($this->amountFormatter->format($amount, $context->getPartUnit())); - } - } else { - $ret .= htmlspecialchars($this->amountFormatter->format($amount, $context->getPartUnit())); - } - - //If we have expired lots, we show them in parentheses behind - if ($expiredAmount > 0) { - $ret .= sprintf(' (+%s)', - $this->translator->trans('part_lots.is_expired'), - htmlspecialchars($this->amountFormatter->format($expiredAmount, $context->getPartUnit()))); - } - - //When the amount is below the minimum amount, we highlight the number red - if ($context->isNotEnoughInstock()) { - $ret = sprintf('%s', - $this->translator->trans('part.info.amount.less_than_desired'), - $ret); - } - - return $ret; - }, + 'render' => fn ($value, Part $context) => $this->partDataTableHelper->renderAmount($context), 'orderField' => 'amountSum' ]) ->add('minamount', TextColumn::class, [ diff --git a/src/DataTables/ProjectBomEntriesDataTable.php b/src/DataTables/ProjectBomEntriesDataTable.php index 5a706146..6e3bee5b 100644 --- a/src/DataTables/ProjectBomEntriesDataTable.php +++ b/src/DataTables/ProjectBomEntriesDataTable.php @@ -151,6 +151,28 @@ class ProjectBomEntriesDataTable implements DataTableTypeInterface }, ]) + ->add('instockAmount', TextColumn::class, [ + 'label' => 'project.bom.instockAmount', + 'visible' => false, + 'render' => function ($value, ProjectBOMEntry $context) { + if ($context->getPart()) { + return $this->partDataTableHelper->renderAmount($context->getPart()); + } + + return ''; + } + ]) + ->add('storageLocations', TextColumn::class, [ + 'label' => 'part.table.storeLocations', + 'visible' => false, + 'render' => function ($value, ProjectBOMEntry $context) { + if ($context->getPart()) { + return $this->partDataTableHelper->renderStorageLocations($context->getPart()); + } + + return ''; + } + ]) ->add('addedDate', LocaleDateTimeColumn::class, [ 'label' => $this->translator->trans('part.table.addedDate'), diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index 7197f3b7..f4449c9e 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -11951,5 +11951,11 @@ Please note, that you can not impersonate a disabled user. If you try you will g Vendor barcode (configured in part lot) + + + project.bom.instockAmount + Stocked amount + +