Add 'Add stock' button to part stock info page

This commit is contained in:
kernchen-brc 2026-04-24 08:14:37 +02:00
parent 6330b71bfb
commit f90d0f37f4
4 changed files with 96 additions and 1 deletions

View file

@ -1712,7 +1712,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* length?: scalar|Param|null, // Default: 5
* width?: scalar|Param|null, // Default: 130
* height?: scalar|Param|null, // Default: 50
* font?: scalar|Param|null, // Default: "/home/jan/php/Part-DB-server/vendor/gregwar/captcha-bundle/DependencyInjection/../Generator/Font/captcha.ttf"
* font?: scalar|Param|null, // Default: "/home/user/documents/Part-DB-server/vendor/gregwar/captcha-bundle/DependencyInjection/../Generator/Font/captcha.ttf"
* keep_value?: scalar|Param|null, // Default: false
* charset?: scalar|Param|null, // Default: "abcdefhjkmnprstuvwxyz23456789"
* as_file?: scalar|Param|null, // Default: false

View file

@ -36,6 +36,7 @@ use App\Entity\PriceInformations\Orderdetail;
use App\Entity\ProjectSystem\Project;
use App\Exceptions\AttachmentDownloadException;
use App\Form\Part\PartBaseType;
use App\Form\Part\PartLotType;
use App\Services\Attachments\AttachmentSubmitHandler;
use App\Services\Attachments\PartPreviewGenerator;
use App\Services\EntityMergers\Mergers\PartMerger;
@ -127,6 +128,17 @@ final class PartController extends AbstractController
$table = null;
}
// Build the add-lot form for the INFO page modal (only when not in time-travel mode)
$addLotForm = null;
if ($timeTravel_timestamp === null && $this->isGranted('edit', $part)) {
$newLot = new PartLot();
$newLot->setPart($part);
$addLotForm = $this->createForm(PartLotType::class, $newLot, [
'measurement_unit' => $part->getPartUnit(),
'action' => $this->generateUrl('part_lot_add', ['id' => $part->getID()]),
]);
}
return $this->render(
'parts/info/show_part_info.html.twig',
[
@ -139,10 +151,39 @@ final class PartController extends AbstractController
'comment_params' => $this->partInfoSettings->extractParamsFromNotes ? $parameterExtractor->extractParameters($part->getComment()) : [],
'withdraw_add_helper' => $withdrawAddHelper,
'highlightLotId' => $request->query->getInt('highlightLot', 0),
'add_lot_form' => $addLotForm,
]
);
}
#[Route(path: '/{id}/add_lot', name: 'part_lot_add', methods: ['POST'])]
public function addLot(Part $part, Request $request, EntityManagerInterface $em): Response
{
$this->denyAccessUnlessGranted('edit', $part);
$newLot = new PartLot();
$newLot->setPart($part);
$form = $this->createForm(PartLotType::class, $newLot, [
'measurement_unit' => $part->getPartUnit(),
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em->persist($newLot);
$em->flush();
$this->addFlash('success', 'part.edited_flash');
return $this->redirectToRoute('part_info', [
'id' => $part->getID(),
'highlightLot' => $newLot->getID(),
]);
}
$this->addFlash('error', 'part.created_flash.invalid');
return $this->redirectToRoute('part_info', ['id' => $part->getID()]);
}
#[Route(path: '/{id}/edit', name: 'part_edit')]
public function edit(Part $part, Request $request): Response
{

View file

@ -0,0 +1,46 @@
{% if add_lot_form is not null %}
{% form_theme add_lot_form 'form/extended_bootstrap_layout.html.twig' %}
<div class="modal fade" id="add-lot-modal" tabindex="-1" aria-labelledby="add-lot-modal-title" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
{{ form_start(add_lot_form) }}
<div class="modal-header">
<h1 class="modal-title fs-5" id="add-lot-modal-title">
<i class="fas fa-plus-square fa-fw"></i>
{% trans %}part_lot.create{% endtrans %}
</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
{{ form_row(add_lot_form.description) }}
{{ form_row(add_lot_form.storage_location) }}
{{ form_row(add_lot_form.amount) }}
{{ form_row(add_lot_form.instock_unknown) }}
{{ form_row(add_lot_form.needs_refill) }}
{{ form_row(add_lot_form.expiration_date) }}
<div>
<a class="btn btn-link btn-sm {{ offset_label }}" data-bs-toggle="collapse" href="#add-lot-advanced" role="button" aria-expanded="false" aria-controls="add-lot-advanced">
{% trans %}part_lot.edit.advanced{% endtrans %}
</a>
<div class="collapse" id="add-lot-advanced">
{{ form_row(add_lot_form.comment) }}
{{ form_row(add_lot_form.owner) }}
{{ form_row(add_lot_form.user_barcode) }}
{{ form_row(add_lot_form.last_stocktake_at) }}
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans %}modal.close{% endtrans %}</button>
<button type="submit" class="btn btn-success">
<i class="fas fa-plus-square fa-fw"></i>
{% trans %}part_lot.create{% endtrans %}
</button>
</div>
{{ form_end(add_lot_form) }}
</div>
</div>
</div>
{% endif %}

View file

@ -3,6 +3,7 @@
{% include "parts/info/_withdraw_modal.html.twig" %}
{% include "parts/info/_stocktake_modal.html.twig" %}
{% include "parts/info/_add_lot_modal.html.twig" %}
<div class="table-responsive">
<table class="table table-striped table-hover">
@ -126,3 +127,10 @@
</table>
</div>
{% if add_lot_form is not null %}
<button type="button" class="btn btn-success" data-bs-toggle="modal" data-bs-target="#add-lot-modal">
<i class="fas fa-plus-square fa-fw"></i>
{% trans %}part_lot.create{% endtrans %}
</button>
{% endif %}