mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-21 09:35:49 +02:00
Allow to specify an informational field during a part stock operation, where the user can specify, when this operation was really performed
Fixes issue #416
This commit is contained in:
parent
6cff19358a
commit
b447a69dae
6 changed files with 89 additions and 16 deletions
|
@ -401,22 +401,33 @@ class PartController extends AbstractController
|
|||
$comment = $request->request->get('comment');
|
||||
$action = $request->request->get('action');
|
||||
|
||||
$timestamp = null;
|
||||
$timestamp_str = $request->request->getString('timestamp', '');
|
||||
//Try to parse the timestamp
|
||||
if($timestamp_str !== '') {
|
||||
$timestamp = new DateTime($timestamp_str);
|
||||
}
|
||||
|
||||
//Ensure that the timestamp is not in the future
|
||||
if($timestamp !== null && $timestamp > new DateTime("+20min")) {
|
||||
throw new \LogicException("The timestamp must not be in the future!");
|
||||
}
|
||||
|
||||
try {
|
||||
switch ($action) {
|
||||
case "withdraw":
|
||||
case "remove":
|
||||
$this->denyAccessUnlessGranted('withdraw', $partLot);
|
||||
$withdrawAddHelper->withdraw($partLot, $amount, $comment);
|
||||
$withdrawAddHelper->withdraw($partLot, $amount, $comment, $timestamp);
|
||||
break;
|
||||
case "add":
|
||||
$this->denyAccessUnlessGranted('add', $partLot);
|
||||
$withdrawAddHelper->add($partLot, $amount, $comment);
|
||||
$withdrawAddHelper->add($partLot, $amount, $comment, $timestamp);
|
||||
break;
|
||||
case "move":
|
||||
$this->denyAccessUnlessGranted('move', $partLot);
|
||||
$this->denyAccessUnlessGranted('move', $targetLot);
|
||||
$withdrawAddHelper->move($partLot, $targetLot, $amount, $comment);
|
||||
$withdrawAddHelper->move($partLot, $targetLot, $amount, $comment, $timestamp);
|
||||
break;
|
||||
default:
|
||||
throw new \RuntimeException("Unknown action!");
|
||||
|
|
|
@ -41,8 +41,10 @@ class PartStockChangedLogEntry extends AbstractLogEntry
|
|||
* @param float $new_total_part_instock The new total instock of the part.
|
||||
* @param string $comment The comment associated with the change.
|
||||
* @param PartLot|null $move_to_target The target lot if the type is TYPE_MOVE.
|
||||
* @param \DateTimeInterface|null $action_timestamp The optional timestamp, where the action happened. Useful if the action happened in the past, and the log entry is created afterwards.
|
||||
*/
|
||||
protected function __construct(PartStockChangeType $type, PartLot $lot, float $old_stock, float $new_stock, float $new_total_part_instock, string $comment, ?PartLot $move_to_target = null)
|
||||
protected function __construct(PartStockChangeType $type, PartLot $lot, float $old_stock, float $new_stock, float $new_total_part_instock, string $comment, ?PartLot $move_to_target = null,
|
||||
?\DateTimeInterface $action_timestamp = null)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
|
@ -62,6 +64,11 @@ class PartStockChangedLogEntry extends AbstractLogEntry
|
|||
$this->extra['c'] = mb_strimwidth($comment, 0, self::COMMENT_MAX_LENGTH, '...');
|
||||
}
|
||||
|
||||
if ($action_timestamp instanceof \DateTimeInterface) {
|
||||
//The action timestamp is saved as an ISO 8601 string
|
||||
$this->extra['a'] = $action_timestamp->format(\DateTimeInterface::ATOM);
|
||||
}
|
||||
|
||||
if ($move_to_target instanceof PartLot) {
|
||||
if ($type !== PartStockChangeType::MOVE) {
|
||||
throw new \InvalidArgumentException('The move_to_target parameter can only be set if the type is "move"!');
|
||||
|
@ -78,11 +85,12 @@ class PartStockChangedLogEntry extends AbstractLogEntry
|
|||
* @param float $new_stock The new stock of the lot.
|
||||
* @param float $new_total_part_instock The new total instock of the part.
|
||||
* @param string $comment The comment associated with the change.
|
||||
* @param \DateTimeInterface|null $action_timestamp The optional timestamp, where the action happened. Useful if the action happened in the past, and the log entry is created afterwards.
|
||||
* @return self
|
||||
*/
|
||||
public static function add(PartLot $lot, float $old_stock, float $new_stock, float $new_total_part_instock, string $comment): self
|
||||
public static function add(PartLot $lot, float $old_stock, float $new_stock, float $new_total_part_instock, string $comment, ?\DateTimeInterface $action_timestamp = null): self
|
||||
{
|
||||
return new self(PartStockChangeType::ADD, $lot, $old_stock, $new_stock, $new_total_part_instock, $comment);
|
||||
return new self(PartStockChangeType::ADD, $lot, $old_stock, $new_stock, $new_total_part_instock, $comment, action_timestamp: $action_timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -92,11 +100,12 @@ class PartStockChangedLogEntry extends AbstractLogEntry
|
|||
* @param float $new_stock The new stock of the lot.
|
||||
* @param float $new_total_part_instock The new total instock of the part.
|
||||
* @param string $comment The comment associated with the change.
|
||||
* @param \DateTimeInterface|null $action_timestamp The optional timestamp, where the action happened. Useful if the action happened in the past, and the log entry is created afterwards.
|
||||
* @return self
|
||||
*/
|
||||
public static function withdraw(PartLot $lot, float $old_stock, float $new_stock, float $new_total_part_instock, string $comment): self
|
||||
public static function withdraw(PartLot $lot, float $old_stock, float $new_stock, float $new_total_part_instock, string $comment, ?\DateTimeInterface $action_timestamp = null): self
|
||||
{
|
||||
return new self(PartStockChangeType::WITHDRAW, $lot, $old_stock, $new_stock, $new_total_part_instock, $comment);
|
||||
return new self(PartStockChangeType::WITHDRAW, $lot, $old_stock, $new_stock, $new_total_part_instock, $comment, action_timestamp: $action_timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,10 +116,12 @@ class PartStockChangedLogEntry extends AbstractLogEntry
|
|||
* @param float $new_total_part_instock The new total instock of the part.
|
||||
* @param string $comment The comment associated with the change.
|
||||
* @param PartLot $move_to_target The target lot.
|
||||
* @param \DateTimeInterface|null $action_timestamp The optional timestamp, where the action happened. Useful if the action happened in the past, and the log entry is created afterwards.
|
||||
* @return self
|
||||
*/
|
||||
public static function move(PartLot $lot, float $old_stock, float $new_stock, float $new_total_part_instock, string $comment, PartLot $move_to_target): self
|
||||
public static function move(PartLot $lot, float $old_stock, float $new_stock, float $new_total_part_instock, string $comment, PartLot $move_to_target, ?\DateTimeInterface $action_timestamp = null): self
|
||||
{
|
||||
return new self(PartStockChangeType::MOVE, $lot, $old_stock, $new_stock, $new_total_part_instock, $comment, $move_to_target);
|
||||
return new self(PartStockChangeType::MOVE, $lot, $old_stock, $new_stock, $new_total_part_instock, $comment, $move_to_target, action_timestamp: $action_timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -169,4 +180,18 @@ class PartStockChangedLogEntry extends AbstractLogEntry
|
|||
{
|
||||
return $this->extra['m'] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timestamp when this action was performed and not when the log entry was created.
|
||||
* This is useful if the action happened in the past, and the log entry is created afterwards.
|
||||
* If the timestamp is not set, null is returned.
|
||||
* @return \DateTimeInterface|null
|
||||
*/
|
||||
public function getActionTimestamp(): ?\DateTimeInterface
|
||||
{
|
||||
if (!empty($this->extra['a'])) {
|
||||
return \DateTimeImmutable::createFromFormat(\DateTimeInterface::ATOM, $this->extra['a']);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -193,6 +193,10 @@ class LogEntryExtraFormatter
|
|||
htmlspecialchars($this->elementTypeNameGenerator->getLocalizedTypeLabel(PartLot::class))
|
||||
.' ' . $context->getMoveToTargetID();
|
||||
}
|
||||
if ($context->getActionTimestamp()) {
|
||||
$formatter = new \IntlDateFormatter($this->translator->getLocale(), \IntlDateFormatter::SHORT, \IntlDateFormatter::SHORT);
|
||||
$array['log.part_stock_changed.timestamp'] = $formatter->format($context->getActionTimestamp());
|
||||
}
|
||||
}
|
||||
|
||||
return $array;
|
||||
|
|
|
@ -53,9 +53,10 @@ final class PartLotWithdrawAddHelper
|
|||
* @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
|
||||
* @param \DateTimeInterface|null $action_timestamp The optional timestamp, where the action happened. Useful if the action happened in the past, and the log entry is created afterwards.
|
||||
* @return PartLot The modified part lot
|
||||
*/
|
||||
public function withdraw(PartLot $partLot, float $amount, ?string $comment = null): PartLot
|
||||
public function withdraw(PartLot $partLot, float $amount, ?string $comment = null, ?\DateTimeInterface $action_timestamp = null): PartLot
|
||||
{
|
||||
//Ensure that amount is positive
|
||||
if ($amount <= 0) {
|
||||
|
@ -83,7 +84,7 @@ final class PartLotWithdrawAddHelper
|
|||
$oldAmount = $partLot->getAmount();
|
||||
$partLot->setAmount($oldAmount - $amount);
|
||||
|
||||
$event = PartStockChangedLogEntry::withdraw($partLot, $oldAmount, $partLot->getAmount(), $part->getAmountSum() , $comment);
|
||||
$event = PartStockChangedLogEntry::withdraw($partLot, $oldAmount, $partLot->getAmount(), $part->getAmountSum() , $comment, $action_timestamp);
|
||||
$this->eventLogger->log($event);
|
||||
|
||||
//Apply the comment also to global events, so it gets associated with the elementChanged log entry
|
||||
|
@ -100,9 +101,10 @@ final class PartLotWithdrawAddHelper
|
|||
* @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
|
||||
* @param \DateTimeInterface|null $action_timestamp The optional timestamp, where the action happened. Useful if the action happened in the past, and the log entry is created afterwards.
|
||||
* @return PartLot The modified part lot
|
||||
*/
|
||||
public function add(PartLot $partLot, float $amount, ?string $comment = null): PartLot
|
||||
public function add(PartLot $partLot, float $amount, ?string $comment = null, ?\DateTimeInterface $action_timestamp = null): PartLot
|
||||
{
|
||||
if ($amount <= 0) {
|
||||
throw new \InvalidArgumentException('Amount must be positive');
|
||||
|
@ -123,7 +125,7 @@ final class PartLotWithdrawAddHelper
|
|||
$oldAmount = $partLot->getAmount();
|
||||
$partLot->setAmount($oldAmount + $amount);
|
||||
|
||||
$event = PartStockChangedLogEntry::add($partLot, $oldAmount, $partLot->getAmount(), $part->getAmountSum() , $comment);
|
||||
$event = PartStockChangedLogEntry::add($partLot, $oldAmount, $partLot->getAmount(), $part->getAmountSum() , $comment, $action_timestamp);
|
||||
$this->eventLogger->log($event);
|
||||
|
||||
//Apply the comment also to global events, so it gets associated with the elementChanged log entry
|
||||
|
@ -141,8 +143,9 @@ final class PartLotWithdrawAddHelper
|
|||
* @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
|
||||
* @param \DateTimeInterface|null $action_timestamp The optional timestamp, where the action happened. Useful if the action happened in the past, and the log entry is created afterwards.
|
||||
*/
|
||||
public function move(PartLot $origin, PartLot $target, float $amount, ?string $comment = null): void
|
||||
public function move(PartLot $origin, PartLot $target, float $amount, ?string $comment = null, ?\DateTimeInterface $action_timestamp = null): void
|
||||
{
|
||||
if ($amount <= 0) {
|
||||
throw new \InvalidArgumentException('Amount must be positive');
|
||||
|
@ -177,7 +180,7 @@ final class PartLotWithdrawAddHelper
|
|||
//And add it to the target
|
||||
$target->setAmount($target->getAmount() + $amount);
|
||||
|
||||
$event = PartStockChangedLogEntry::move($origin, $oldOriginAmount, $origin->getAmount(), $part->getAmountSum() , $comment, $target);
|
||||
$event = PartStockChangedLogEntry::move($origin, $oldOriginAmount, $origin->getAmount(), $part->getAmountSum() , $comment, $target, $action_timestamp);
|
||||
$this->eventLogger->log($event);
|
||||
|
||||
//Apply the comment also to global events, so it gets associated with the elementChanged log entry
|
||||
|
|
|
@ -50,6 +50,18 @@
|
|||
<div id="emailHelp" class="form-text">{% trans %}part.info.withdraw_modal.comment.hint{% endtrans %}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mb-2">
|
||||
<label class="col-form-label col-sm-3">
|
||||
{% trans %}part.info.withdraw_modal.timestamp{% endtrans %}
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
{# The timestamp must be between a year ago and 1 hour in the future #}
|
||||
<input type="datetime-local" class="form-control" name="timestamp" value=""
|
||||
max="{{ "+10mins"|date('Y-m-d\\TH:i') }}" min="{{ "-1year"|date('Y-m-d\\TH:i') }}">
|
||||
<div id="emailHelp" class="form-text">{% trans %}part.info.withdraw_modal.timestamp.hint{% endtrans %}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans %}modal.close{% endtrans %}</button>
|
||||
|
|
|
@ -12053,5 +12053,23 @@ Please note, that you can not impersonate a disabled user. If you try you will g
|
|||
<target>Please note that some permission operations depend on each other. If you encounter a warning that missing permissions were corrected and a permission was set to allow again, you have to set the dependent operation to forbid too. The dependents can normally found right of an operation.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="VFdWqOX" name="log.part_stock_changed.timestamp">
|
||||
<segment>
|
||||
<source>log.part_stock_changed.timestamp</source>
|
||||
<target>Timestamp</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="Hj7NX8C" name="part.info.withdraw_modal.timestamp">
|
||||
<segment>
|
||||
<source>part.info.withdraw_modal.timestamp</source>
|
||||
<target>Action timestamp</target>
|
||||
</segment>
|
||||
</unit>
|
||||
<unit id="USYGK0J" name="part.info.withdraw_modal.timestamp.hint">
|
||||
<segment>
|
||||
<source>part.info.withdraw_modal.timestamp.hint</source>
|
||||
<target>This field allows you to specify the real date, when the stock operation actually was performed, and not just when it was logged. This value is saved in the extra field of the log entry.</target>
|
||||
</segment>
|
||||
</unit>
|
||||
</file>
|
||||
</xliff>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue