mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-28 20:50:06 +02:00
Added a very basic modal on part info page for changing part instock
Related to issue #201
This commit is contained in:
parent
0e020dab74
commit
ba4085d882
7 changed files with 488 additions and 4 deletions
|
@ -40,6 +40,7 @@ use App\Services\LogSystem\EventCommentHelper;
|
|||
use App\Services\LogSystem\HistoryHelper;
|
||||
use App\Services\LogSystem\TimeTravel;
|
||||
use App\Services\Parameters\ParameterExtractor;
|
||||
use App\Services\Parts\PartLotWithdrawAddHelper;
|
||||
use App\Services\Parts\PricedetailHelper;
|
||||
use App\Services\ProjectSystem\ProjectBuildPartHelper;
|
||||
use DateTime;
|
||||
|
@ -52,6 +53,7 @@ use Symfony\Component\Form\FormInterface;
|
|||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
|
@ -319,4 +321,60 @@ class PartController extends AbstractController
|
|||
'form' => $form,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/{id}/add_withdraw", name="part_add_withdraw", methods={"POST"})
|
||||
*/
|
||||
public function withdrawAddHandler(Part $part, Request $request, EntityManagerInterface $em, PartLotWithdrawAddHelper $withdrawAddHelper): Response
|
||||
{
|
||||
if ($this->isCsrfTokenValid('part_withraw' . $part->getID(), $request->request->get('_csfr'))) {
|
||||
//Retrieve partlot from the request
|
||||
$partLot = $em->find(PartLot::class, $request->request->get('lot_id'));
|
||||
//Ensure that the partlot belongs to the part
|
||||
if($partLot->getPart() !== $part) {
|
||||
throw new \RuntimeException("The origin partlot does not belong to the part!");
|
||||
}
|
||||
//Try to determine the target lot (used for move actions)
|
||||
$targetLot = $em->find(PartLot::class, $request->request->get('target_id'));
|
||||
if ($targetLot && $targetLot->getPart() !== $part) {
|
||||
throw new \RuntimeException("The target partlot does not belong to the part!");
|
||||
}
|
||||
|
||||
//Extract the amount and comment from the request
|
||||
$amount = (float) $request->request->get('amount');
|
||||
$comment = $request->request->get('comment');
|
||||
$action = $request->request->get('action');
|
||||
|
||||
|
||||
|
||||
switch ($action) {
|
||||
case "withdraw":
|
||||
case "remove":
|
||||
$withdrawAddHelper->withdraw($partLot, $amount, $comment);
|
||||
break;
|
||||
case "add":
|
||||
$withdrawAddHelper->add($partLot, $amount, $comment);
|
||||
break;
|
||||
case "move":
|
||||
$withdrawAddHelper->move($partLot, $targetLot, $amount, $comment);
|
||||
break;
|
||||
default:
|
||||
throw new \RuntimeException("Unknown action!");
|
||||
}
|
||||
|
||||
//Save the changes to the DB
|
||||
$em->flush();
|
||||
$this->addFlash('success', 'part.withdraw.success');
|
||||
|
||||
} else {
|
||||
$this->addFlash('error', 'CSRF Token invalid!');
|
||||
}
|
||||
|
||||
//If an redirect was passed, then redirect there
|
||||
if($request->request->get('_redirect')) {
|
||||
return $this->redirect($request->request->get('_redirect'));
|
||||
}
|
||||
//Otherwise just redirect to the part page
|
||||
return $this->redirectToRoute('part_info', ['id' => $part->getID()]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,21 +38,21 @@ class StorelocationAdminForm extends BaseEntityAdminForm
|
|||
'required' => false,
|
||||
'label' => 'storelocation.edit.is_full.label',
|
||||
'help' => 'storelocation.edit.is_full.help',
|
||||
'disabled' => !$this->security->isGranted($is_new ? 'create' : 'move', $entity),
|
||||
'disabled' => !$this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||
]);
|
||||
|
||||
$builder->add('limit_to_existing_parts', CheckboxType::class, [
|
||||
'required' => false,
|
||||
'label' => 'storelocation.limit_to_existing.label',
|
||||
'help' => 'storelocation.limit_to_existing.help',
|
||||
'disabled' => !$this->security->isGranted($is_new ? 'create' : 'move', $entity),
|
||||
'disabled' => !$this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||
]);
|
||||
|
||||
$builder->add('only_single_part', CheckboxType::class, [
|
||||
'required' => false,
|
||||
'label' => 'storelocation.only_single_part.label',
|
||||
'help' => 'storelocation.only_single_part.help',
|
||||
'disabled' => !$this->security->isGranted($is_new ? 'create' : 'move', $entity),
|
||||
'disabled' => !$this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||
]);
|
||||
|
||||
$builder->add('storage_type', StructuralEntityType::class, [
|
||||
|
@ -61,7 +61,7 @@ class StorelocationAdminForm extends BaseEntityAdminForm
|
|||
'help' => 'storelocation.storage_type.help',
|
||||
'class' => MeasurementUnit::class,
|
||||
'disable_not_selectable' => true,
|
||||
'disabled' => !$this->security->isGranted($is_new ? 'create' : 'move', $entity),
|
||||
'disabled' => !$this->security->isGranted($is_new ? 'create' : 'edit', $entity),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
157
src/Services/Parts/PartLotWithdrawAddHelper.php
Normal file
157
src/Services/Parts/PartLotWithdrawAddHelper.php
Normal file
|
@ -0,0 +1,157 @@
|
|||
<?php
|
||||
|
||||
namespace App\Services\Parts;
|
||||
|
||||
use App\Entity\Parts\Part;
|
||||
use App\Entity\Parts\PartLot;
|
||||
|
||||
class PartLotWithdrawAddHelper
|
||||
{
|
||||
/**
|
||||
* Checks whether the given part can
|
||||
* @param PartLot $partLot
|
||||
* @return bool
|
||||
*/
|
||||
public function canAdd(PartLot $partLot): bool
|
||||
{
|
||||
//We cannot add or withdraw parts from lots with unknown instock value.
|
||||
if($partLot->isInstockUnknown()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//So far all other restrictions are defined at the storelocation level
|
||||
if($partLot->getStorageLocation() === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//We can not add parts if the storage location of the lot is marked as full
|
||||
if($partLot->getStorageLocation()->isFull()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function canWithdraw(PartLot $partLot): bool
|
||||
{
|
||||
//We cannot add or withdraw parts from lots with unknown instock value.
|
||||
if ($partLot->isInstockUnknown()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Withdraw the specified amount of parts from the given part lot.
|
||||
* Please note that the changes are not flushed to DB yet, you have to do this yourself
|
||||
* @param PartLot $partLot The partLot from which the instock should be taken (which value should be decreased)
|
||||
* @param float $amount The amount of parts that should be taken from the part lot
|
||||
* @param string|null $comment The optional comment describing the reason for the withdrawal
|
||||
* @return PartLot The modified part lot
|
||||
*/
|
||||
public function withdraw(PartLot $partLot, float $amount, ?string $comment = null): PartLot
|
||||
{
|
||||
//Ensure that amount is positive
|
||||
if ($amount <= 0) {
|
||||
throw new \InvalidArgumentException('Amount must be positive');
|
||||
}
|
||||
|
||||
$part = $partLot->getPart();
|
||||
|
||||
//Check whether we have to round the amount
|
||||
if (!$part->useFloatAmount()) {
|
||||
$amount = round($amount);
|
||||
}
|
||||
|
||||
//Ensure that we can withdraw from the part lot
|
||||
if (!$this->canWithdraw($partLot)) {
|
||||
throw new \RuntimeException("Cannot withdraw from this part lot!");
|
||||
}
|
||||
|
||||
//Ensure that there is enough stock to withdraw
|
||||
if ($amount > $partLot->getAmount()) {
|
||||
throw new \RuntimeException('Not enough stock to withdraw!');
|
||||
}
|
||||
|
||||
//Subtract the amount from the part lot
|
||||
$partLot->setAmount($partLot->getAmount() - $amount);
|
||||
|
||||
return $partLot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the specified amount of parts to the given part lot.
|
||||
* Please note that the changes are not flushed to DB yet, you have to do this yourself
|
||||
* @param PartLot $partLot The partLot from which the instock should be taken (which value should be decreased)
|
||||
* @param float $amount The amount of parts that should be taken from the part lot
|
||||
* @param string|null $comment The optional comment describing the reason for the withdrawal
|
||||
* @return PartLot The modified part lot
|
||||
*/
|
||||
public function add(PartLot $partLot, float $amount, ?string $comment = null): PartLot
|
||||
{
|
||||
if ($amount <= 0) {
|
||||
throw new \InvalidArgumentException('Amount must be positive');
|
||||
}
|
||||
|
||||
$part = $partLot->getPart();
|
||||
|
||||
//Check whether we have to round the amount
|
||||
if (!$part->useFloatAmount()) {
|
||||
$amount = round($amount);
|
||||
}
|
||||
|
||||
//Ensure that we can add to the part lot
|
||||
if (!$this->canAdd($partLot)) {
|
||||
throw new \RuntimeException("Cannot add to this part lot!");
|
||||
}
|
||||
|
||||
//Subtract the amount from the part lot
|
||||
$partLot->setAmount($partLot->getAmount() + $amount);
|
||||
|
||||
return $partLot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the specified amount of parts from the given source part lot to the given target part lot.
|
||||
* Please note that the changes are not flushed to DB yet, you have to do this yourself
|
||||
* @param PartLot $origin The part lot from which the parts should be taken
|
||||
* @param PartLot $target The part lot to which the parts should be added
|
||||
* @param float $amount The amount of parts that should be moved
|
||||
* @param string|null $comment A comment describing the reason for the move
|
||||
* @return void
|
||||
*/
|
||||
public function move(PartLot $origin, PartLot $target, float $amount, ?string $comment = null): void
|
||||
{
|
||||
if ($amount <= 0) {
|
||||
throw new \InvalidArgumentException('Amount must be positive');
|
||||
}
|
||||
|
||||
$part = $origin->getPart();
|
||||
|
||||
//Ensure that both part lots belong to the same part
|
||||
if($origin->getPart() !== $target->getPart()) {
|
||||
throw new \RuntimeException("Cannot move instock between different parts!");
|
||||
}
|
||||
|
||||
//Check whether we have to round the amount
|
||||
if (!$part->useFloatAmount()) {
|
||||
$amount = round($amount);
|
||||
}
|
||||
|
||||
//Ensure that we can withdraw from origin and add to target
|
||||
if (!$this->canWithdraw($origin) || !$this->canAdd($target)) {
|
||||
throw new \RuntimeException("Cannot move instock between these part lots!");
|
||||
}
|
||||
|
||||
//Ensure that there is enough stock to withdraw
|
||||
if ($amount > $origin->getAmount()) {
|
||||
throw new \RuntimeException('Not enough stock to withdraw!');
|
||||
}
|
||||
|
||||
//Subtract the amount from the part lot
|
||||
$origin->setAmount($origin->getAmount() - $amount);
|
||||
//And add it to the target
|
||||
$target->setAmount($target->getAmount() + $amount);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue