Assemblies einführen

This commit is contained in:
Marcel Diegelmann 2025-03-19 08:13:45 +01:00
parent c79fc47c1e
commit 55828d830d
45 changed files with 2754 additions and 127 deletions

View file

@ -62,4 +62,4 @@
</a>
{% endif %}
</div>
{% endblock %}
{% endblock %}

View file

@ -87,4 +87,4 @@
{{ form_row(form.submit) }}
{{ form_end(form) }}
{{ form_end(form) }}

View file

@ -105,6 +105,8 @@
{{ 'assembly.bom_import.template.kicad_pcbnew.exptected_columns.note'|trans|raw }}
{{ 'assembly.bom_import.template.kicad_pcbnew.table'|trans|raw }}
{{ 'assembly.bom_import.template.json.table'|trans|raw }}
</div>
</div>
</div>

View file

@ -0,0 +1,22 @@
{% import "components/datatables.macro.html.twig" as datatables %}
<div class="btn-group mb-2 mt-2">
<a class="btn btn-success" {% if not is_granted('@assemblies.edit') %}disabled{% endif %}
href="{{ path('assembly_add_parts', {"id": assembly.id, "_redirect": uri_without_host(app.request)}) }}">
<i class="fa-solid fa-square-plus fa-fw"></i>
{% trans %}assembly.info.bom_add_parts{% endtrans %}
</a>
<button type="button" class="btn btn-success dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false">
<span class="visually-hidden">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item" href="{{ path('assembly_import_bom', {'id': assembly.id}) }}" {% if not is_granted('edit', assembly) %}disabled="disabled"{% endif %}>
<i class="fa-solid fa-file-import fa-fw"></i>
{% trans %}assembly.edit.bom.import_bom{% endtrans %}
</a>
</li>
</ul>
</div>
{{ datatables.datatable(datatable, 'elements/datatables/datatables', 'assemblies') }}

View file

@ -37,6 +37,12 @@
{% trans %}entity.info.attachments.tab{% endtrans %}
</a>
{% endif %}
{% if assembly.parameters is not empty %}
<a class="nav-link" id="v-pills-parameters-tab" data-bs-toggle="pill" href="#v-pills-parameters" role="tab" aria-controls="v-pills-parameters" aria-selected="false">
<i class="fas fa-atlas fa-fw"></i>
{% trans %}entity.info.parameters.tab{% endtrans %}
</a>
{% endif %}
{% if assembly.comment is not empty %}
<a class="nav-link" id="v-pills-comment-tab" data-bs-toggle="pill" href="#v-pills-comment" role="tab">
<i class="fas fa-comment-alt fa-fw"></i>
@ -102,6 +108,15 @@
</div>
{% endif %}
{% if assembly.parameters is not empty %}
<div class="tab-pane fade" id="v-pills-parameters" role="tabpanel" aria-labelledby="v-pills-parameters-tab">
{% for name, parameters in assembly.groupedParameters %}
{% if name is not empty %}<h5 class="mt-1">{{ name }}</h5>{% endif %}
{{ helper.parameters_table(assembly) }}
{% endfor %}
</div>
{% endif %}
{% if assembly.comment is not empty %}
<div class="tab-pane fade" id="v-pills-comment" role="tabpanel" aria-labelledby="home-tab">
<div class="container-fluid mt-2 latex" data-controller="common--latex">
@ -115,4 +130,4 @@
</div>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,28 @@
<table class="table table-striped table-hover">
<thead>
<tr>
<th>{% trans %}name.label{% endtrans %}</th>
<th>{% trans %}description.label{% endtrans %}</th>
<th># {% trans %}assembly.info.bom_entries_count{% endtrans %}</th>
<th># {% trans %}assembly.info.sub_assemblies_count{% endtrans %}</th>
</tr>
</thead>
<tbody>
{% for subassembly in assembly.children %}
<tr>
<td> {# Name #}
<a href="{{ entity_url(subassembly, 'info') }}">{{ subassembly.name }}</a>
</td>
<td> {# Description #}
{{ subassembly.description | format_markdown }}
</td>
<td>
{{ subassembly.bomEntries | length }}
</td>
<td>
{{ subassembly.children | length }}
</td>
</tr>
{% endfor %}
</tbody>
</table>

View file

@ -70,8 +70,18 @@
{% trans %}assembly.info.info.label{% endtrans %}
</button>
</li>
{% if assembly.children is not empty %}
<li class="nav-item" role="presentation">
<button class="nav-link" id="subassemblies-tab" data-bs-toggle="tab" data-bs-target="#subassemblies-tab-pane"
type="button" role="tab" aria-controls="subassemblies-tab-pane" aria-selected="false">
<i class="fa-solid fa-folder-tree fa-fw"></i>
{% trans %}assembly.info.sub_assemblies.label{% endtrans %}
<span class="badge bg-secondary">{{ assembly.children | length }}</span>
</button>
</li>
{% endif %}
<li class="nav-item" role="presentation">
<button class="nav-link" id="part-tab" data-bs-toggle="tab" data-bs-target="#part-tab-pane"
<button class="nav-link" id="bom-tab" data-bs-toggle="tab" data-bs-target="#part-tab-pane"
type="button" role="tab" aria-controls="part-tab-pane" aria-selected="false">
<i class="fa-solid fa-list-check fa-fw"></i>
{% trans %}assembly_bom_entry.label{% endtrans %}
@ -95,6 +105,16 @@
</a>
</li>
{% endif %}
{% if assembly.parameters is not empty %}
<li class="nav-item">
<a class="nav-link" id="parameters-tab" data-bs-toggle="tab"
data-bs-target="#parameters-tab-pane" role="tab">
<i class="fas fa-atlas fa-fw"></i>
{% trans %}entity.info.parameters.tab{% endtrans %}
<span class="badge bg-secondary">{{ assembly.parameters | length }}</span>
</a>
</li>
{% endif %}
</ul>
<div class="tab-content">
@ -103,13 +123,26 @@
</div>
<div class="tab-pane fade" id="part-tab-pane" role="tabpanel" aria-labelledby="part-tab" tabindex="0">
{% include "assemblies/info/_part.html.twig" %}
{% if assembly.children is not empty %}
<div class="tab-pane fade" id="subassemblies-tab-pane" role="tabpanel" aria-labelledby="bom-tab" tabindex="0">
{% include "assemblies/info/_subassemblies.html.twig" %}
</div>
{% endif %}
<div class="tab-pane fade" id="bom-tab-pane" role="tabpanel" aria-labelledby="bom-tab" tabindex="0">
{% include "assemblies/info/_bom.html.twig" %}
</div>
<div class="tab-pane fade" id="builds-tab-pane" role="tabpanel" aria-labelledby="builds-tab" tabindex="0">
{% include "assemblies/info/_builds.html.twig" %}
</div>
<div class="tab-pane fade" id="attachments-tab-pane" role="tabpanel" aria-labelledby="attachments-tab" tabindex="0">
{% include "assemblies/info/_attachments_info.html.twig" with {"assembly": assembly} %}
{% include "assemblies/info/_attachments_info.html.twig" with {"part": assembly} %}
</div>
<div class="tab-pane fade" id="parameters-tab-pane" role="tabpanel" aria-labelledby="parameters-tab">
{% for name, parameters in assembly.groupedParameters %}
{% if name is not empty %}<h5 class="mt-1">{{ name }}</h5>{% endif %}
{{ helper.parameters_table(assembly.parameters) }}
{% endfor %}
</div>
</div>
{% endblock %}
{% endblock %}

View file

@ -6,7 +6,7 @@
<tr>
<th></th> {# expand button #}
<th>{% trans %}project.bom.quantity{% endtrans %}</th>
<th>{% trans %}project.bom.part{% endtrans %}</th>
<th>{% trans %}project.bom.partOrAssembly{% endtrans %}</th>
<th>{% trans %}project.bom.name{% endtrans %}</th>
<th></th> {# Remove button #}
</tr>
@ -41,9 +41,11 @@
{{ form_widget(form.quantity) }}
{{ form_errors(form.quantity) }}
</td>
<td style="min-width: 250px;">
{{ form_widget(form.part) }}
<td style="min-width: 300px;">
{{ form_row(form.part) }}
{{ form_errors(form.part) }}
{{ form_widget(form.assembly) }}
{{ form_errors(form.assembly) }}
</td>
<td>
{{ form_widget(form.name) }}

View file

@ -80,4 +80,4 @@
</div>
</td>
</tr>
{% endblock %}
{% endblock %}

View file

@ -27,7 +27,9 @@
</td>
<td >
{% if bom_entry.part %}
<b><a target="_blank" href="{{ entity_url(bom_entry.part) }}">{{ bom_entry.part.name }}</a></b> {% if bom_entry.name %}({{ bom_entry.name }}){% endif %}
<b><a target="_blank" href="{{ entity_url(bom_entry.part) }}">{{ 'projects.build.form.part'|trans({'%name%': bom_entry.part.name}) }}</a></b> {% if bom_entry.name %}({{ bom_entry.name }}){% endif %}
{% elseif bom_entry.assembly %}
<b><a target="_blank" href="{{ entity_url(bom_entry.assembly) }}">{{ 'projects.build.form.assembly'|trans({'%name%': bom_entry.assembly.name}) }}</a></b> {% if bom_entry.name %}({{ bom_entry.name }}){% endif %}
{% else %}
<b>{{ bom_entry.name }}</b>
{% endif %}
@ -45,9 +47,29 @@
<tr>
<td colspan="4">
{% set lots = build_request.partLotsForBOMEntry(bom_entry) %}
{% set assemblyBomEntriesWithoutPart = build_request.assemblyBomEntriesWithoutPart(bom_entry) %}
{% set assemblyBomEntriesWithPartNoStock = build_request.assemblyBomEntriesWithPartNoStock(bom_entry) %}
{% if lots is not null %}
{% set previousLabel = null %}
{% for lot in lots %}
{# @var lot \App\Entity\Parts\PartLot #}
{% set label = '' %}
{% if form["lot_"~lot.id].vars.label is defined and form["lot_"~lot.id].vars.label is not empty %}
{% set label = form["lot_"~lot.id].vars.label %}
{% endif %}
{% if label != '' and (previousLabel is null or label != previousLabel) %}
<div class="mb-2 row">
<label class="col-form-label col-lg-4">
<small>{{ label|raw }}</small>
</label>
</div>
{% endif %}
{% set previousLabel = label %}
<div class="mb-2 row">
<label class="col-form-label col-sm-4" for="category_admin_form_parent">
{% if lot.storageLocation %}
@ -61,12 +83,41 @@
{{ form_errors(form["lot_"~lot.id]) }}
{{ form_widget(form["lot_"~lot.id]) }}
</div>
<div class="col-sm-2 mt-1 text-end">
<div class="col-sm-2 mt-1 text-end">
/ <b>{{ lot.amount | format_amount(lot.part.partUnit) }}</b> {% trans %}project.builds.stocked{% endtrans %}
</div>
</div>
{% endfor %}
{% endif %}
{% if assemblyBomEntriesWithoutPart is not null %}
{% for bomEntryWithoutPart in assemblyBomEntriesWithoutPart %}
<div class="mb-2 row">
<label class="col-form-label col-sm-4" for="category_admin_form_parent">
<small>{{ 'projects.build.form.assembly.bom.entry'|trans({'%name%': bomEntryWithoutPart.name, '%quantity%': bomEntryWithoutPart.quantity * number_of_builds}) }}</small>
</label>
<div class="col-sm-6"></div>
<div class="col-sm-2 mt-1 text-end">
/ {% trans %}project.builds.no_stock{% endtrans %}
</div>
</div>
{% endfor %}
{% endif %}
{% if assemblyBomEntriesWithPartNoStock is not null %}
{% for bomEntryWithPartNoStock in assemblyBomEntriesWithPartNoStock %}
<div class="alert alert-danger">
<div class="mb-2 row">
<label class="col-form-label col-sm-4" for="category_admin_form_parent">
{% trans %}projects.build.form.assembly.bom.entry.no.stock{% endtrans %}<br/>
<small>{{ 'projects.build.form.assembly.bom.entry'|trans({'%name%': bomEntryWithPartNoStock.name ? bomEntryWithPartNoStock.name : bomEntryWithPartNoStock.part.name, '%quantity%': bomEntryWithPartNoStock.quantity * number_of_builds}) }}</small>
</label>
<div class="col-sm-6"></div>
<div class="col-sm-2 mt-1 text-end">
/ {% trans %}project.builds.no_stock{% endtrans %}
</div>
</div>
</div>
{% endfor %}
{% endif %}
</td>
</tr>
{% endfor %}