Added the possibility to edit/create/delete part lots.

This commit is contained in:
Jan Böhmer 2019-08-19 23:31:16 +02:00
parent 6a0adae8f3
commit 813e7dc85b
11 changed files with 226 additions and 43 deletions

View file

@ -82,7 +82,7 @@ class PartController extends AbstractController
return $this->render('Parts/edit/edit_part_info.html.twig',
[
'part' => $part,
'form_main' => $form->createView(),
'form' => $form->createView(),
]);
}

View file

@ -179,7 +179,8 @@ class Part extends AttachmentContainingDBElement
/**
* @var ?PartLot[]
* @ORM\OneToMany(targetEntity="PartLot", mappedBy="part")
* @ORM\OneToMany(targetEntity="PartLot", mappedBy="part", cascade={"persist", "remove"}, orphanRemoval=true)
* @Assert\Valid()
*/
protected $partLots;
@ -593,6 +594,18 @@ class Part extends AttachmentContainingDBElement
return $this->partLots;
}
public function addPartLot(PartLot $lot): Part
{
$lot->setPart($this);
$this->partLots->add($lot);
return $this;
}
public function removePartLot(PartLot $lot): Part
{
$this->partLots->removeElement($lot);
return $this;
}
/**
* Returns the assigned manufacturer product number (MPN) for this part.

View file

@ -56,13 +56,13 @@ class PartLot extends DBElement
* @var string A short description about this lot, shown in table
* @ORM\Column(type="text")
*/
protected $description;
protected $description = "";
/**
* @var string A comment stored with this lot.
* @ORM\Column(type="text")
*/
protected $comment;
protected $comment = "";
/**
* @var ?\DateTime Set a time until when the lot must be used.
@ -90,21 +90,21 @@ class PartLot extends DBElement
* @var bool If this is set to true, the instock amount is marked as not known
* @ORM\Column(type="boolean")
*/
protected $instock_unknown;
protected $instock_unknown = false;
/**
* @var float For continuos sizes (length, volume, etc.) the instock is saved here.
* @ORM\Column(type="float")
* @Assert\Positive()
* @Assert\PositiveOrZero()
*/
protected $amount;
protected $amount = 0;
/**
* @var boolean Determines if this lot was manually marked for refilling.
* @ORM\Column(type="boolean")
*/
protected $needs_refill;
protected $needs_refill = false;
/**
* Returns the ID as an string, defined by the element class.
@ -198,7 +198,7 @@ class PartLot extends DBElement
* Gets the storage locatiion, where this part lot is stored.
* @return Storelocation The store location where this part is stored
*/
public function getStorageLocation(): Storelocation
public function getStorageLocation(): ?Storelocation
{
return $this->storage_location;
}
@ -260,7 +260,7 @@ class PartLot extends DBElement
*/
public function getAmount(): float
{
if (!$this->part->useFloatAmount()) {
if ($this->part instanceof Part && !$this->part->useFloatAmount()) {
return round($this->amount);
}
return (float) $this->amount;
@ -269,6 +269,7 @@ class PartLot extends DBElement
public function setAmount(float $new_amount): PartLot
{
$this->amount = $new_amount;
return $this;
}

View file

@ -43,6 +43,7 @@ use FOS\CKEditorBundle\Form\Type\CKEditorType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\UrlType;
use Symfony\Component\Form\FormBuilderInterface;
@ -119,14 +120,18 @@ class PartBaseType extends AbstractType
->add('favorite', CheckboxType::class, ['label_attr'=> ['class' => 'checkbox-custom'],
'required' => false, 'label' => 'part.edit.is_favorite']);
//Part Lots section
$builder->add('partLots', CollectionType::class, [
'entry_type' => PartLotType::class,
'allow_add' => true, 'allow_delete' => true,
'label' => false,
'by_reference' => false
]);
$builder
//Buttons
->add('save1', SubmitType::class, ['label' => 'part.edit.save'])
->add('reset1', ResetType::class, ['label' => 'part.edit.reset'])
->add('save2', SubmitType::class, ['label' => 'part.edit.save'])
->add('reset2', ResetType::class, ['label' => 'part.edit.reset'])
->add('save3', SubmitType::class, ['label' => 'part.edit.save'])
->add('reset3', ResetType::class, ['label' => 'part.edit.reset']);
->add('save', SubmitType::class, ['label' => 'part.edit.save'])
->add('reset', ResetType::class, ['label' => 'part.edit.reset']);
}
public function configureOptions(OptionsResolver $resolver)

View file

@ -0,0 +1,90 @@
<?php
/**
*
* part-db version 0.1
* Copyright (C) 2005 Christoph Lechner
* http://www.cl-projects.de/
*
* part-db version 0.2+
* Copyright (C) 2009 K. Jacobs and others (see authors.php)
* http://code.google.com/p/part-db/
*
* Part-DB Version 0.4+
* Copyright (C) 2016 - 2019 Jan Böhmer
* https://github.com/jbtronics
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
*/
namespace App\Form\Part;
use App\Entity\Parts\Part;
use App\Entity\Parts\PartLot;
use App\Entity\Parts\Storelocation;
use App\Form\Type\StructuralEntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use function GuzzleHttp\Promise\queue;
class PartLotType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('description', TextType::class, ['label' => 'part_lot.edit.description',
'required' => false, 'empty_data' => "", 'attr' => ['class' => 'form-control-sm']]);
$builder->add('storage_location', StructuralEntityType::class, ['class' => Storelocation::class,
'label' => 'part_lot.edit.location',
'disable_not_selectable' => true, 'attr' => ['class' => 'form-control-sm']]);
$builder->add('amount',NumberType::class, [ 'html5' => true,
'label' => 'part_lot.edit.amount',
'attr' => ['class' => 'form-control-sm', 'min' => 0, 'step' => 'any']
]);
$builder->add('instock_unknown', CheckboxType::class, ['required' => false,
'label' => 'part_lot.edit.instock_unknown',
'attr' => ['class' => 'form-control-sm'],
'label_attr'=> ['class' => 'checkbox-custom']]);
$builder->add('needs_refill', CheckboxType::class, ['label_attr'=> ['class' => 'checkbox-custom'],
'label' => 'part_lot.edit.needs_refill',
'attr' => ['class' => 'form-control-sm'],
'required' => false]);
$builder->add('expirationDate', DateTimeType::class, [
'label' => 'part_lot.edit.expiration_date',
'attr' => [],
'required' => false]);
$builder->add('comment', TextType::class, ['label' => 'part_lot.edit.comment',
'label' => 'part_lot.edit.comment',
'attr' => ['class' => 'form-control-sm'],
'required' => false, 'empty_data' => ""]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => PartLot::class,
]);
}
}

View file

@ -0,0 +1,60 @@
{% set delete_btn %}
<button type="button" class="btn btn-danger lot_btn_delete" onclick="delete_lot_entry(this);">
<i class="fas fa-trash-alt fa-fw"></i>
{% trans %}part_lot.delete{% endtrans %}
</button>
{% endset %}
<table class="table table-striped" id="lots_table" data-prototype="{{ form_widget(form.partLots.vars.prototype)|e('html_attr') }}">
<tbody>
{% for lot in form.partLots %}
<tr>
<td>
{{ form_widget(lot) }}
</td>
<td>
{{ delete_btn }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
<button type="button" class="btn btn-success" onclick="create_lot_entry(this)">
<i class="fas fa-plus-square fa-fw"></i>
{% trans %}part_lot.create{% endtrans %}
</button>
<script>
function delete_lot_entry(btn) {
window.bootbox.confirm('{% trans %}part_lot.edit.delete.confirm{% endtrans %}', function (result) {
if(result) {
$(btn).parents("tr").remove();
}
})
}
function create_lot_entry(btn) {
//Determine the table, so we can determine, how many entries there are already.
$holder = $("#lots_table");
var index = $holder.find(":input").length;
var newForm = $holder.data("prototype");
//Increase the index
newForm = newForm.replace(/__name__/g, index);
newForm = '<td>' + newForm + '</td>';
$newFormRow = $('<tr></tr>').html(newForm);
//Add delete button
$btn = '<td>' + '{{ delete_btn|e('js') }}' + '</td>';
$newFormRow.append($btn);
$holder.append($newFormRow);
//Reinit the selectpickers
$(".selectpicker").selectpicker();
}
</script>

View file

@ -1,13 +1,11 @@
{{ form_row(form_main.name) }}
{{ form_row(form_main.description) }}
{{ form_row(form_main.category) }}
{{ form_row(form_main.tags) }}
{{ form_row(form_main.minAmount) }}
{{ form_row(form_main.partUnit)}}
{{ form_row(form.name) }}
{{ form_row(form.description) }}
{{ form_row(form.category) }}
{{ form_row(form.tags) }}
{{ form_row(form.minAmount) }}
{{ form_row(form.partUnit)}}
{{ form_row(form_main.footprint) }}
{{ form_row(form.footprint) }}
{{ form_row(form_main.comment) }}
{{ form_row(form.comment) }}
{{ form_row(form_main.save1) }}
{{ form_row(form_main.reset1) }}

View file

@ -1,6 +1,3 @@
{{ form_row(form_main.manufacturer) }}
{{ form_row(form_main.manufacturer_product_number) }}
{{ form_row(form_main.manufacturer_product_url)}}
{{ form_row(form_main.save2) }}
{{ form_row(form_main.reset2) }}
{{ form_row(form.manufacturer) }}
{{ form_row(form.manufacturer_product_number) }}
{{ form_row(form.manufacturer_product_url)}}

View file

@ -1,5 +1,2 @@
{{ form_row(form_main.needsReview) }}
{{ form_row(form_main.favorite) }}
{{ form_row(form_main.save3) }}
{{ form_row(form_main.reset3) }}
{{ form_row(form.needsReview) }}
{{ form_row(form.favorite) }}

View file

@ -17,18 +17,34 @@
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link active" data-toggle="tab" role="tab" href="#common">{% trans %}part.edit.tab.common{% endtrans %}</a>
<a class="nav-link active" data-toggle="tab" role="tab" href="#common">
<i class="fas fa-id-card fa-fw"></i>
{% trans %}part.edit.tab.common{% endtrans %}
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" role="tab" href="#manufacturer">{% trans %}part.edit.tab.manufacturer{% endtrans %}</a>
<a class="nav-link" data-toggle="tab" role="tab" href="#manufacturer">
<i class="fas fa-industry fa-fw"></i>
{% trans %}part.edit.tab.manufacturer{% endtrans %}
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" role="tab" href="#options">{% trans %}part.edit.tab.options{% endtrans %}</a>
<a class="nav-link" data-toggle="tab" role="tab" href="#options">
<i class="fas fa-shapes fa-fw"></i>
{% trans %}part.edit.tab.options{% endtrans %}
</a>
</li>
<li class="nav-item">
<a class="nav-link" data-toggle="tab" role="tab" href="#part_lots">
<i class="fas fa-boxes fa-fw"></i>
{% trans %}part.edit.tab.part_lots{% endtrans %}
</a>
</li>
</ul>
{{ form_start(form) }}
<div class="tab-content">
{{ form_start(form_main) }}
<div class="tab-pane fade show active p-2" id="common" role="tabpanel">
{% include "Parts/edit/_main.html.twig" %}
</div>
@ -38,8 +54,14 @@
<div class="tab-pane fade p-2" id="options" role="tabpanel">
{% include "Parts/edit/_options.html.twig" %}
</div>
{{ form_end(form_main) }}
<div class="tab-pane fade p-2" id="part_lots" role="tabpanel">
{% include "Parts/edit/_lots.html.twig" %}
</div>
</div>
{{ form_row(form.save) }}
{{ form_row(form.reset) }}
{{ form_end(form) }}
{% endblock %}

View file

@ -1,4 +1,4 @@
{% extends "Parts/edit_part_info.html.twig" %}
{% extends "Parts/edit/edit_part_info.html.twig" %}
{% block card_border %}border-success{% endblock %}
{% block card_type %}bg-success text-white{% endblock %}