Baugruppen Stückliste um referenzierte Baugruppe erweitern

This commit is contained in:
Marcel Diegelmann 2025-07-03 13:38:51 +02:00
parent 4f9c20a409
commit 4e1c890b5b
48 changed files with 1205 additions and 152 deletions

View file

@ -48,7 +48,14 @@ parameters:
######################################################################################################################
# Table settings
######################################################################################################################
<<<<<<< HEAD
partdb.table.assemblies.default_columns: '%env(trim:string:TABLE_ASSEMBLIES_DEFAULT_COLUMNS)%' # The default columns in assembly tables and their order
=======
partdb.table.default_page_size: '%env(int:TABLE_DEFAULT_PAGE_SIZE)%' # The default number of entries shown per page in tables
partdb.table.parts.default_columns: '%env(trim:string:TABLE_PARTS_DEFAULT_COLUMNS)%' # The default columns in part tables and their order
partdb.table.assemblies.default_columns: '%env(trim:string:TABLE_ASSEMBLIES_DEFAULT_COLUMNS)%' # The default columns in assembly tables and their order
partdb.table.assemblies_bom.default_columns: '%env(trim:string:TABLE_ASSEMBLIES_BOM_DEFAULT_COLUMNS)%' # The default columns in assembly bom tables and their order
>>>>>>> 2779c55a (Baugruppen Stückliste um referenzierte Baugruppe erweitern)
######################################################################################################################
# Miscellaneous

View file

@ -171,9 +171,12 @@ services:
####################################################################################################################
# Table settings
####################################################################################################################
App\DataTables\AssemblyBomEntriesDataTable:
App\DataTables\AssemblyDataTable:
arguments:
$visible_columns: '%partdb.table.assemblies.default_columns%'
App\DataTables\AssemblyBomEntriesDataTable:
arguments:
$visible_columns: '%partdb.table.assemblies_bom.default_columns%'
App\DataTables\Helpers\ColumnSortHelper:
shared: false # Service has a state so not share it between different tables

View file

@ -140,7 +140,10 @@ bundled with Part-DB. Set `DATABASE_MYSQL_SSL_VERIFY_CERT` if you want to accept
* `TABLE_ASSEMBLIES_DEFAULT_COLUMNS`: The columns in assemblies tables, which are visible by default (when loading table for first
time).
Also specify the default order of the columns. This is a comma separated list of column names. Available columns
are: `name`, `id`, `quantity`, `ipn`, `description`, `category`, `footprint`, `manufacturer`, `mountnames`, `instockAmount`, `storageLocations`, `addedDate`, `lastModified`.
are: `name`, `id`, `ipn`, `description`, `referencedAssemblies`, `edit`, `addedDate`, `lastModified`.
* `TABLE_ASSEMBLIES_BOM_DEFAULT_COLUMNS`: The columns in assemblies bom tables, which are visible by default (when loading table for first time).
Also specify the default order of the columns. This is a comma separated list of column names. Available columns
are: `quantity`, `name`, `id`, `ipn`, `description`, `addedDate`, `lastModified`.
* `CREATE_ASSEMBLY_USE_IPN_PLACEHOLDER_IN_NAME`: Use an %%ipn%% placeholder in the name of a assembly. Placeholder is replaced with the ipn input while saving.
### History/Eventlog-related settings

View file

@ -146,6 +146,7 @@ final class Version20250304081039 extends AbstractMultiPlatformMigration
id_assembly INTEGER DEFAULT NULL,
id_part INTEGER DEFAULT NULL,
id_project INTEGER DEFAULT NULL,
id_referenced_assembly INTEGER DEFAULT NULL,
price_currency_id INTEGER DEFAULT NULL,
quantity DOUBLE PRECISION NOT NULL,
mountnames CLOB NOT NULL,
@ -156,8 +157,9 @@ final class Version20250304081039 extends AbstractMultiPlatformMigration
datetime_added DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
CONSTRAINT FK_8C74887E4AD2039E FOREIGN KEY (id_assembly) REFERENCES assemblies (id) NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_8C74887EC22F6CC4 FOREIGN KEY (id_part) REFERENCES "parts" (id) NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_8C74887EF12E799E FOREIGN KEY (id_project) REFERENCES projects (id) NOT DEFERRABLE INITIALLY IMMEDIATE
CONSTRAINT FK_8C74887E3FFDCD60 FOREIGN KEY (price_currency_id) REFERENCES currencies (id) NOT DEFERRABLE INITIALLY IMMEDIATE
CONSTRAINT FK_8C74887EF12E799E FOREIGN KEY (id_project) REFERENCES projects (id) NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_8C74887E22522999 FOREIGN KEY (id_referenced_assembly) REFERENCES assemblies (id) ON UPDATE NO ACTION ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE,
CONSTRAINT FK_8C74887E3FFDCD60 FOREIGN KEY (price_currency_id) REFERENCES currencies (id) NOT DEFERRABLE INITIALLY IMMEDIATE
)
SQL);
$this->addSql(<<<'SQL'
@ -169,6 +171,9 @@ final class Version20250304081039 extends AbstractMultiPlatformMigration
$this->addSql(<<<'SQL'
CREATE INDEX IDX_8C74887EF12E799E ON assembly_bom_entries (id_project)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_8C74887E22522999 ON assembly_bom_entries (id_referenced_assembly)
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_8C74887E3FFDCD60 ON assembly_bom_entries (price_currency_id)
SQL);

View file

@ -0,0 +1,78 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use App\Migration\AbstractMultiPlatformMigration;
use Doctrine\DBAL\Schema\Schema;
final class Version20250627130848 extends AbstractMultiPlatformMigration
{
public function getDescription(): string
{
return 'Add id_referenced_assembly in assembly_bom_entries';
}
public function mySQLUp(Schema $schema): void
{
$this->addSql(<<<'SQL'
ALTER TABLE assembly_bom_entries ADD id_referenced_assembly INT DEFAULT NULL AFTER id_project
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE assembly_bom_entries ADD CONSTRAINT FK_8C74887E22522999 FOREIGN KEY (id_referenced_assembly) REFERENCES assemblies (id) ON DELETE SET NULL
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_8C74887E22522999 ON assembly_bom_entries (id_referenced_assembly)
SQL);
}
public function mySQLDown(Schema $schema): void
{
$this->addSql(<<<'SQL'
ALTER TABLE assembly_bom_entries DROP FOREIGN KEY FK_8C74887E22522999
SQL);
$this->addSql(<<<'SQL'
DROP INDEX IDX_8C74887E22522999 ON assembly_bom_entries
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE assembly_bom_entries DROP id_referenced_assembly
SQL);
}
public function sqLiteUp(Schema $schema): void
{
//nothing to do. Done via Version20250304081039
}
public function sqLiteDown(Schema $schema): void
{
//nothing to do. Done via Version20250304081039
}
public function postgreSQLUp(Schema $schema): void
{
$this->addSql(<<<'SQL'
ALTER TABLE assembly_bom_entries ADD id_referenced_assembly INT DEFAULT NULL
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE assembly_bom_entries ADD CONSTRAINT FK_8C74887E22522999 FOREIGN KEY (id_referenced_assembly) REFERENCES assemblies (id) ON DELETE SET NULL NOT DEFERRABLE INITIALLY IMMEDIATE
SQL);
$this->addSql(<<<'SQL'
CREATE INDEX IDX_8C74887E22522999 ON assembly_bom_entries (id_referenced_assembly)
SQL);
}
public function postgreSQLDown(Schema $schema): void
{
$this->addSql(<<<'SQL'
ALTER TABLE assembly_bom_entries DROP CONSTRAINT FK_8C74887E22522999
SQL);
$this->addSql(<<<'SQL'
DROP INDEX IDX_8C74887E22522999
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE assembly_bom_entries DROP id_referenced_assembly
SQL);
}
}

View file

@ -200,7 +200,7 @@ abstract class BaseAdminController extends AbstractController
* depending on CREATE_ASSEMBLY_USE_IPN_PLACEHOLDER_IN_NAME, when creating a new one,
* to avoid having to insert it manually */
$entity->setName(str_ireplace('%%ipn%%', $entity->getIpn(), $entity->getName()));
$entity->setName(str_ireplace('%%ipn%%', $entity->getIpn() ?? '', $entity->getName()));
}
$this->commentHelper->setMessage($form['log_comment']->getData());
@ -233,6 +233,13 @@ abstract class BaseAdminController extends AbstractController
$repo = $this->entityManager->getRepository($this->entity_class);
$showParameters = true;
if ($this instanceof AssemblyAdminController) {
//currently not needed for assemblies
$showParameters = false;
}
return $this->render($this->twig_template, [
'entity' => $entity,
'form' => $form,
@ -242,7 +249,7 @@ abstract class BaseAdminController extends AbstractController
'timeTravel' => $timeTravel_timestamp,
'repo' => $repo,
'partsContainingElement' => $repo instanceof PartsContainingRepositoryInterface,
'showParameters' => !($this instanceof AssemblyAdminController),
'showParameters' => $showParameters,
]);
}
@ -303,7 +310,7 @@ abstract class BaseAdminController extends AbstractController
* depending on CREATE_ASSEMBLY_USE_IPN_PLACEHOLDER_IN_NAME, when creating a new one,
* to avoid having to insert it manually */
$new_entity->setName(str_ireplace('%%ipn%%', $new_entity->getIpn(), $new_entity->getName()));
$new_entity->setName(str_ireplace('%%ipn%%', $new_entity->getIpn() ?? '', $new_entity->getName()));
}
$this->commentHelper->setMessage($form['log_comment']->getData());
@ -396,13 +403,20 @@ abstract class BaseAdminController extends AbstractController
}
}
$showParameters = true;
if ($this instanceof AssemblyAdminController) {
//currently not needed for assemblies
$showParameters = false;
}
return $this->render($this->twig_template, [
'entity' => $new_entity,
'form' => $form,
'import_form' => $import_form,
'mass_creation_form' => $mass_creation_form,
'route_base' => $this->route_base,
'showParameters' => !($this instanceof AssemblyAdminController),
'showParameters' => $showParameters,
]);
}

View file

@ -22,8 +22,10 @@ declare(strict_types=1);
namespace App\Controller;
use App\Entity\AssemblySystem\Assembly;
use App\Entity\Parameters\AbstractParameter;
use App\Entity\ProjectSystem\Project;
use App\Services\Attachments\AssemblyPreviewGenerator;
use App\Services\Attachments\ProjectPreviewGenerator;
use Symfony\Component\HttpFoundation\Response;
use App\Entity\Attachments\Attachment;
@ -195,6 +197,44 @@ class TypeaheadController extends AbstractController
return new JsonResponse($result);
}
#[Route(path: '/assemblies/search/{query}', name: 'typeahead_assemblies')]
public function assemblies(
EntityManagerInterface $entityManager,
AssemblyPreviewGenerator $assemblyPreviewGenerator,
AttachmentURLGenerator $attachmentURLGenerator,
string $query = ""
): JsonResponse {
$this->denyAccessUnlessGranted('@assemblies.read');
$result = [];
$assemblyRepository = $entityManager->getRepository(Assembly::class);
$assemblies = $assemblyRepository->autocompleteSearch($query, 100);
foreach ($assemblies as $assembly) {
$preview_attachment = $assemblyPreviewGenerator->getTablePreviewAttachment($assembly);
if($preview_attachment instanceof Attachment) {
$preview_url = $attachmentURLGenerator->getThumbnailURL($preview_attachment, 'thumbnail_sm');
} else {
$preview_url = '';
}
/** @var Assembly $assembly */
$result[] = [
'id' => $assembly->getID(),
'name' => $assembly->getName(),
'category' => '',
'footprint' => '',
'description' => mb_strimwidth($assembly->getDescription(), 0, 127, '...'),
'image' => $preview_url,
];
}
return new JsonResponse($result);
}
#[Route(path: '/parameters/{type}/search/{query}', name: 'typeahead_parameters', requirements: ['type' => '.+'])]
public function parameters(string $type, EntityManagerInterface $entityManager, string $query = ""): JsonResponse
{

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
namespace App\Entity\AssemblySystem;
use App\Repository\AssemblyRepository;
use Doctrine\Common\Collections\Criteria;
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Metadata\ApiFilter;
@ -38,6 +39,7 @@ use ApiPlatform\Serializer\Filter\PropertyFilter;
use App\ApiPlatform\Filter\LikeFilter;
use App\Entity\Attachments\Attachment;
use App\Validator\Constraints\UniqueObjectCollection;
use App\Validator\Constraints\AssemblySystem\UniqueReferencedAssembly;
use Doctrine\DBAL\Types\Types;
use App\Entity\Attachments\AssemblyAttachment;
use App\Entity\Base\AbstractStructuralDBElement;
@ -58,7 +60,7 @@ use Symfony\Component\Validator\Context\ExecutionContextInterface;
*
* @extends AbstractStructuralDBElement<AssemblyAttachment, AssemblyParameter>
*/
#[ORM\Entity]
#[ORM\Entity(repositoryClass: AssemblyRepository::class)]
#[ORM\Table(name: 'assemblies')]
#[UniqueEntity(fields: ['ipn'], message: 'assembly.ipn.must_be_unique')]
#[ORM\Index(columns: ['ipn'], name: 'assembly_idx_ipn')]
@ -109,8 +111,9 @@ class Assembly extends AbstractStructuralDBElement
*/
#[Assert\Valid]
#[Groups(['extended', 'full', 'import'])]
#[ORM\OneToMany(mappedBy: 'assembly', targetEntity: AssemblyBOMEntry::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
#[ORM\OneToMany(targetEntity: AssemblyBOMEntry::class, mappedBy: 'assembly', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[UniqueObjectCollection(message: 'assembly.bom_entry.part_already_in_bom', fields: ['part'])]
#[UniqueReferencedAssembly]
#[UniqueObjectCollection(message: 'assembly.bom_entry.project_already_in_bom', fields: ['project'])]
#[UniqueObjectCollection(message: 'assembly.bom_entry.name_already_in_bom', fields: ['name'])]
protected Collection $bom_entries;
@ -386,4 +389,22 @@ class Assembly extends AbstractStructuralDBElement
}
}
}
/**
* Get all referenced assemblies which uses this assembly.
*
* @return Assembly[] all referenced assemblies which uses this assembly as a one-dimensional array of assembly objects
*/
public function getReferencedAssemblies(): array
{
$assemblies = [];
foreach($this->bom_entries as $entry) {
if ($entry->getAssembly() !== null) {
$assemblies[] = $entry->getReferencedAssembly();
}
}
return $assemblies;
}
}

View file

@ -133,6 +133,18 @@ class AssemblyBOMEntry extends AbstractDBElement implements UniqueValidatableInt
#[Groups(['bom_entry:read', 'bom_entry:write', 'full'])]
protected ?Part $part = null;
/**
* @var Assembly|null The associated assembly
*/
#[Assert\Expression(
'(this.getPart() === null or this.getReferencedAssembly() === null) and (this.getName() === null or (this.getName() != null and this.getName() != ""))',
message: 'validator.assembly.bom_entry.only_part_or_assembly_allowed'
)]
#[ORM\ManyToOne(targetEntity: Assembly::class)]
#[ORM\JoinColumn(name: 'id_referenced_assembly', nullable: true, onDelete: 'SET NULL')]
#[Groups(['bom_entry:read', 'bom_entry:write', ])]
protected ?Assembly $referencedAssembly = null;
/**
* @var Project|null The associated project
*/
@ -237,6 +249,17 @@ class AssemblyBOMEntry extends AbstractDBElement implements UniqueValidatableInt
return $this;
}
public function getReferencedAssembly(): ?Assembly
{
return $this->referencedAssembly;
}
public function setReferencedAssembly(?Assembly $referencedAssembly): AssemblyBOMEntry
{
$this->referencedAssembly = $referencedAssembly;
return $this;
}
public function getProject(): ?Project
{
return $this->project;

View file

@ -51,14 +51,17 @@ class AssemblyAddPartsType extends AbstractType
$builder->add('bom_entries', AssemblyBOMEntryCollectionType::class, [
'entry_options' => [
'constraints' => [
new UniqueEntity(fields: ['part', 'assembly'], message: 'assembly.bom_entry.part_already_in_bom',
new UniqueEntity(fields: ['part'], message: 'assembly.bom_entry.part_already_in_bom',
entityClass: AssemblyBOMEntry::class),
new UniqueEntity(fields: ['name', 'assembly'], message: 'assembly.bom_entry.name_already_in_bom',
new UniqueEntity(fields: ['referencedAssembly'], message: 'assembly.bom_entry.assembly_already_in_bom',
entityClass: AssemblyBOMEntry::class),
new UniqueEntity(fields: ['name'], message: 'assembly.bom_entry.name_already_in_bom',
entityClass: AssemblyBOMEntry::class, ignoreNull: true),
]
],
'constraints' => [
new UniqueObjectCollection(message: 'assembly.bom_entry.part_already_in_bom', fields: ['part']),
new UniqueObjectCollection(message: 'assembly.bom_entry.assembly_already_in_bom', fields: ['referencedAssembly']),
new UniqueObjectCollection(message: 'assembly.bom_entry.name_already_in_bom', fields: ['name']),
]
]);

View file

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace App\Form\AssemblySystem;
use App\Entity\AssemblySystem\AssemblyBOMEntry;
use App\Form\Type\AssemblySelectType;
use App\Form\Type\BigDecimalNumberType;
use App\Form\Type\CurrencyEntityType;
use App\Form\Type\PartSelectType;
@ -42,6 +43,10 @@ class AssemblyBOMEntryType extends AbstractType
'label' => 'assembly.bom.project',
'required' => false,
])
->add('referencedAssembly', AssemblySelectType::class, [
'label' => 'assembly.bom.referencedAssembly',
'required' => false,
])
->add('name', TextType::class, [
'label' => 'assembly.bom.name',
'required' => false,

View file

@ -0,0 +1,124 @@
<?php
declare(strict_types=1);
namespace App\Form\Type;
use App\Entity\AssemblySystem\Assembly;
use App\Entity\Attachments\Attachment;
use App\Services\Attachments\AssemblyPreviewGenerator;
use App\Services\Attachments\AttachmentURLGenerator;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\ChoiceList\ChoiceList;
use Symfony\Component\Form\DataMapperInterface;
use Symfony\Component\Form\Event\PreSetDataEvent;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
class AssemblySelectType extends AbstractType implements DataMapperInterface
{
public function __construct(private readonly UrlGeneratorInterface $urlGenerator, private readonly EntityManagerInterface $em, private readonly AssemblyPreviewGenerator $previewGenerator, private readonly AttachmentURLGenerator $attachmentURLGenerator)
{
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
//At initialization, we have to fill the form element with our selected data, so the user can see it
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (PreSetDataEvent $event) {
$form = $event->getForm();
$config = $form->getConfig()->getOptions();
$data = $event->getData() ?? [];
$config['compound'] = false;
$config['choices'] = is_iterable($data) ? $data : [$data];
$config['error_bubbling'] = true;
$form->add('autocomplete', EntityType::class, $config);
});
//After form submit, we have to add the selected element as choice, otherwise the form will not accept this element
$builder->addEventListener(FormEvents::PRE_SUBMIT, function(FormEvent $event) {
$data = $event->getData();
$form = $event->getForm();
$options = $form->get('autocomplete')->getConfig()->getOptions();
if (!isset($data['autocomplete']) || '' === $data['autocomplete'] || empty($data['autocomplete'])) {
$options['choices'] = [];
} else {
//Extract the ID from the submitted data
$id = $data['autocomplete'];
//Find the element in the database
$element = $this->em->find($options['class'], $id);
//Add the element as choice
$options['choices'] = [$element];
$options['error_bubbling'] = true;
$form->add('autocomplete', EntityType::class, $options);
}
});
$builder->setDataMapper($this);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'class' => Assembly::class,
'choice_label' => 'name',
'compound' => true,
'error_bubbling' => false,
]);
error_log($this->urlGenerator->generate('typeahead_assemblies', ['query' => '__QUERY__']));
$resolver->setDefaults([
'attr' => [
'data-controller' => 'elements--assembly-select',
'data-autocomplete' => $this->urlGenerator->generate('typeahead_assemblies', ['query' => '__QUERY__']),
'autocomplete' => 'off',
],
]);
$resolver->setDefaults([
//Prefill the selected choice with the needed data, so the user can see it without an additional Ajax request
'choice_attr' => ChoiceList::attr($this, function (?Assembly $assembly) {
if($assembly instanceof Assembly) {
//Determine the picture to show:
$preview_attachment = $this->previewGenerator->getTablePreviewAttachment($assembly);
if ($preview_attachment instanceof Attachment) {
$preview_url = $this->attachmentURLGenerator->getThumbnailURL($preview_attachment,
'thumbnail_sm');
} else {
$preview_url = '';
}
}
return $assembly instanceof Assembly ? [
'data-description' => $assembly->getDescription() ? mb_strimwidth($assembly->getDescription(), 0, 127, '...') : '',
'data-category' => '',
'data-footprint' => '',
'data-image' => $preview_url,
] : [];
})
]);
}
public function mapDataToForms($data, \Traversable $forms): void
{
$form = current(iterator_to_array($forms, false));
$form->setData($data);
}
public function mapFormsToData(\Traversable $forms, &$data): void
{
$form = current(iterator_to_array($forms, false));
$data = $form->getData();
}
}

View file

@ -0,0 +1,69 @@
<?php
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2022 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 Affero General Public License as published
* by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2022 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 Affero General Public License as published
* by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace App\Repository;
use App\Entity\AssemblySystem\Assembly;
/**
* @template TEntityClass of Assembly
* @extends DBElementRepository<TEntityClass>
*/
class AssemblyRepository extends StructuralDBElementRepository
{
/**
* @return Assembly[]
*/
public function autocompleteSearch(string $query, int $max_limits = 50): array
{
$qb = $this->createQueryBuilder('assembly');
$qb->select('assembly')
->where('ILIKE(assembly.name, :query) = TRUE')
->orWhere('ILIKE(assembly.description, :query) = TRUE');
$qb->setParameter('query', '%'.$query.'%');
$qb->setMaxResults($max_limits);
$qb->orderBy('NATSORT(assembly.name)', 'ASC');
return $qb->getQuery()->getResult();
}
}

View file

@ -67,6 +67,7 @@ class AssemblyBuildHelper
public function getMaximumBuildableCount(Assembly $assembly): int
{
$maximum_buildable_count = PHP_INT_MAX;
/** @var AssemblyBOMEntry $bom_entry */
foreach ($assembly->getBomEntries() as $bom_entry) {
//Skip BOM entries without a part (as we can not determine that)
if (!$bom_entry->isPartBomEntry() && $bom_entry->getProject() === null) {
@ -76,8 +77,8 @@ class AssemblyBuildHelper
//The maximum buildable count for the whole project is the minimum of all BOM entries
if ($bom_entry->getPart() !== null) {
$maximum_buildable_count = min($maximum_buildable_count, $this->getMaximumBuildableCountForBOMEntry($bom_entry));
} elseif ($bom_entry->getProject() !== null) {
$maximum_buildable_count = min($maximum_buildable_count, $this->projectBuildHelper->getMaximumBuildableCount($bom_entry->getProject()));
} elseif ($bom_entry->getReferencedAssembly() !== null) {
$maximum_buildable_count = min($maximum_buildable_count, $this->projectBuildHelper->getMaximumBuildableCount($bom_entry->getReferencedAssembly()));
}
}
@ -117,11 +118,12 @@ class AssemblyBuildHelper
$nonBuildableEntries = [];
/** @var AssemblyBOMEntry $bomEntry */
foreach ($assembly->getBomEntries() as $bomEntry) {
$part = $bomEntry->getPart();
//Skip BOM entries without a part (as we can not determine that)
if (!$part instanceof Part && $bomEntry->getAssembly() === null) {
if (!$part instanceof Part && $bomEntry->getReferencedAssembly() === null) {
continue;
}
@ -131,8 +133,8 @@ class AssemblyBuildHelper
if ($amount_sum < $bomEntry->getQuantity() * $number_of_builds) {
$nonBuildableEntries[] = $bomEntry;
}
} elseif ($bomEntry->getAssembly() !== null) {
$nonBuildableAssemblyEntries = $this->projectBuildHelper->getNonBuildableProjectBomEntries($bomEntry->getProject(), $number_of_builds);
} elseif ($bomEntry->getReferencedAssembly() !== null) {
$nonBuildableAssemblyEntries = $this->getNonBuildableAssemblyBomEntries($bomEntry->getReferencedAssembly(), $number_of_builds);
$nonBuildableEntries = array_merge($nonBuildableEntries, $nonBuildableAssemblyEntries);
}
}

View file

@ -0,0 +1,93 @@
<?php
/**
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2022 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 Affero General Public License as published
* by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace App\Services\Attachments;
use App\Entity\AssemblySystem\Assembly;
use App\Entity\Attachments\Attachment;
class AssemblyPreviewGenerator
{
public function __construct(protected AttachmentManager $attachmentHelper)
{
}
/**
* Returns a list of attachments that can be used for previewing the assembly ordered by priority.
*
* @param Assembly $assembly the assembly for which the attachments should be determined
*
* @return (Attachment|null)[]
*
* @psalm-return list<Attachment|null>
*/
public function getPreviewAttachments(Assembly $assembly): array
{
$list = [];
//Master attachment has top priority
$attachment = $assembly->getMasterPictureAttachment();
if ($this->isAttachmentValidPicture($attachment)) {
$list[] = $attachment;
}
//Then comes the other images of the assembly
foreach ($assembly->getAttachments() as $attachment) {
//Dont show the master attachment twice
if ($this->isAttachmentValidPicture($attachment) && $attachment !== $assembly->getMasterPictureAttachment()) {
$list[] = $attachment;
}
}
return $list;
}
/**
* Determines what attachment should be used for previewing a assembly (especially in assembly table).
* The returned attachment is guaranteed to be existing and be a picture.
*
* @param Assembly $assembly The assembly for which the attachment should be determined
*/
public function getTablePreviewAttachment(Assembly $assembly): ?Attachment
{
$attachment = $assembly->getMasterPictureAttachment();
if ($this->isAttachmentValidPicture($attachment)) {
return $attachment;
}
return null;
}
/**
* Checks if a attachment is exising and a valid picture.
*
* @param Attachment|null $attachment the attachment that should be checked
*
* @return bool true if the attachment is valid
*/
protected function isAttachmentValidPicture(?Attachment $attachment): bool
{
return $attachment instanceof Attachment
&& $attachment->isPicture()
&& $this->attachmentHelper->isFileExisting($attachment);
}
}

View file

@ -188,6 +188,15 @@ class TreeViewGenerator
$root_node->setExpanded($this->rootNodeExpandedByDefault);
$root_node->setIcon($this->entityClassToRootNodeIcon($class));
$generic = [$root_node];
} elseif ($mode === 'assemblies' && $this->rootNodeEnabled) {
//We show the root node as a link to the list of all assemblies
$show_all_parts_url = $this->router->generate('assemblies_list');
$root_node = new TreeViewNode($this->entityClassToRootNodeString($class), $show_all_parts_url, $generic);
$root_node->setExpanded($this->rootNodeExpandedByDefault);
$root_node->setIcon($this->entityClassToRootNodeIcon($class));
$generic = [$root_node];
}

View file

@ -2,6 +2,7 @@
namespace App\Twig;
use App\Entity\AssemblySystem\AssemblyBOMEntry;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
@ -14,6 +15,9 @@ class AssemblyTwigExtension extends AbstractExtension
];
}
/**
* @param AssemblyBOMEntry[] $bomEntries
*/
public function hasProject(array $bomEntries): bool
{
foreach ($bomEntries as $entry) {

View file

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2023 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 Affero General Public License as published
* by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace App\Validator\Constraints\AssemblySystem;
use Symfony\Component\Validator\Constraint;
/**
* This constraint checks that the given UniqueReferencedAssembly is valid.
*/
#[\Attribute(\Attribute::TARGET_PROPERTY)]
class UniqueReferencedAssembly extends Constraint
{
public string $message = 'assembly.bom_entry.assembly_already_in_bom';
}

View file

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2023 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 Affero General Public License as published
* by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace App\Validator\Constraints\AssemblySystem;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class UniqueReferencedAssemblyValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
$assemblies = [];
foreach ($value as $entry) {
$referencedAssemblyId = $entry->getReferencedAssembly()?->getId();
if ($referencedAssemblyId === null) {
continue;
}
if (isset($assemblies[$referencedAssemblyId])) {
$this->context->buildViolation($constraint->message)
->atPath('referencedAssembly')
->addViolation();
return;
}
$assemblies[$referencedAssemblyId] = true;
}
}
}

View file

@ -28,6 +28,8 @@
<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 %}
{% elseif bom_entry.referencedAssembly %}
<b><a target="_blank" href="{{ entity_url(bom_entry.referencedAssembly) }}">{{ 'assembly.build.form.referencedAssembly'|trans({'%name%': bom_entry.referencedAssembly.name}) }}</a></b> {% if bom_entry.name %}({{ bom_entry.name }}){% endif %}
{% else %}
<b>{{ bom_entry.name }}</b>
{% endif %}

View file

@ -0,0 +1,91 @@
{% import "helper.twig" as helper %}
<table class="table table-striped table-sm table-hover table-responsive-sm">
<thead>
<tr>
<th></th>
<th>{% trans %}attachment.name{% endtrans %}</th>
<th>{% trans %}attachment.attachment_type{% endtrans %}</th>
<th>{% trans %}attachment.file_name{% endtrans %}</th>
<th>{% trans %}attachment.file_size{% endtrans %}</th>
<th></th>
</tr>
</thead>
<tbody>
{% for attachment in assembly.attachments %}
<tr>
<td>
{% import "components/attachments.macro.html.twig" as attachments %}
{{ attachments.attachment_icon(attachment, attachment_manager) }}
</td>
<td class="align-middle">{{ attachment.name }}</td>
<td class="align-middle">{{ attachment.attachmentType.fullPath }}</td>
<td class="align-middle">
{% if attachment.hasInternal() %}
{{ attachment.filename }}
{% endif %}
</td>
<td class="align-middle h6">
{% if not attachment.hasInternal() %}
<span class="badge bg-primary">
<i class="fas fa-fw fa-globe"></i> {% trans %}attachment.external_only{% endtrans %}
</span>
{% elseif attachment_manager.internalFileExisting(attachment) %}
<span class="badge bg-secondary">
<i class="fas fa-hdd fa-fw"></i> {{ attachment_manager.humanFileSize(attachment) }}
</span>
{% else %}
<span class="badge bg-warning">
<i class="fas fa-exclamation-circle fa-fw"></i> {% trans %}attachment.file_not_found{% endtrans %}
</span>
{% endif %}
{% if attachment.secure %}
<br><span class="badge bg-success">
<i class="fas fa-fw fa-shield-alt"></i> {% trans %}attachment.secure{% endtrans %}
</span>
{% endif %}
{% if attachment == assembly.masterPictureAttachment %}
<br>
<span class="badge bg-primary">
<i class="fas fa-id-card"></i> {% trans %}attachment.preview{% endtrans %}
</span>
{% endif %}
</td>
<td><div class="btn-group" role="group" aria-label="">
<a {% if attachment.hasExternal() %}href="{{ attachment.externalPath }}"{% endif %} target="_blank"
class="btn btn-secondary {% if not attachment.hasExternal() %}disabled{% endif %}"
data-turbo="false" title="{% trans with {"%host%": attachment.host} %}attachment.view_external.view_at{% endtrans %}" rel="noopener">
<i class="fas fa-globe fa-fw"></i>
</a>
<a {% if attachment_manager.isInternalFileExisting(attachment) %}href="{{ entity_url(attachment, 'file_view') }}"{% endif %} target="_blank"
class="btn btn-secondary {% if not attachment_manager.isInternalFileExisting(attachment) or (attachment.secure and not is_granted("show_private", attachment)) %}disabled{% endif %}"
data-turbo="false" title="{% trans %}attachment.view_local{% endtrans %}" rel="noopener">
<i class="fas fa-eye fa-fw"></i>
</a>
<a {% if attachment_manager.isInternalFileExisting(attachment) %}href="{{ entity_url(attachment, 'file_download') }}"{% endif %} data-turbo="false"
class="btn btn-secondary {% if not attachment_manager.isInternalFileExisting(attachment) or (attachment.secure and not is_granted("show_private", attachment)) %}disabled{% endif %}"
title="{% trans %}attachment.download_local{% endtrans %}">
<i class="fas fa-download fa-fw"></i>
</a>
<div class="btn-group" role="group">
<button id="btnGroupDrop1" type="button" class="btn btn-secondary dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-boundary="window">
</button>
<div class="dropdown-menu" aria-labelledby="btnGroupDrop1">
<span class="text-muted dropdown-item-text" ><i class="fas fa-lightbulb fa-fw"></i> <b>ID:</b> {{ attachment.iD }}</span>
<span class="text-muted dropdown-item-text" ><i class="fas fa-history fa-fw"></i> <b>{% trans %}lastModified{% endtrans %}:</b> {{ helper.entity_last_modified(attachment) }}</span>
<span class="text-muted dropdown-item-text" ><i class="fas fa-calendar-plus fa-fw"></i> <b>{% trans %}createdAt{% endtrans %}:</b> {{ helper.entity_created_at(attachment) }}</span>
</div>
</div>
</div></td>
</tr>
{% endfor %}
</tbody>
</table>

View file

@ -108,7 +108,7 @@
{% 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 "parts/info/_attachments_info.html.twig" with {"part": assembly} %}
{% include "assemblies/info/_attachments_info.html.twig" with {"assembly": assembly} %}
</div>
</div>

View file

@ -6,7 +6,7 @@
<tr>
<th></th> {# expand button #}
<th>{% trans %}assembly.bom.quantity{% endtrans %}</th>
<th>{% trans %}assembly.bom.partOrProject{% endtrans %}</th>
<th>{% trans %}assembly.bom.partOrAssembly{% endtrans %}</th>
<th>{% trans %}assembly.bom.name{% endtrans %}</th>
<th></th> {# Remove button #}
</tr>
@ -44,18 +44,9 @@
<td style="min-width: 300px;">
{{ form_row(form.part) }}
{{ form_errors(form.part) }}
{% if form.vars.value is not null and form.vars.value.assembly is not null %}
{% if is_granted("@projects.read") or has_project(form.vars.value.assembly.bomEntries.toArray) %}
<div class="text-center mb-2" style="line-height: 1"></div>
{{ form_widget(form.project) }}
{{ form_errors(form.project) }}
{% endif %}
{% elseif is_granted("@projects.read") %}
<div class="text-center mb-2" style="line-height: 1"></div>
{{ form_widget(form.project) }}
{{ form_errors(form.project) }}
{% endif %}
<div class="text-center mb-2" style="line-height: 1"></div>
{{ form_widget(form.referencedAssembly) }}
{{ form_errors(form.referencedAssembly) }}
</td>
<td>
{{ form_widget(form.name) }}

View file

@ -9867,7 +9867,7 @@ Element 3</target>
<unit id="hIIFtI1" name="assembly.edit.status">
<segment state="translated">
<source>assembly.edit.status</source>
<target>Stav</target>
<target>Stav sestavy</target>
</segment>
</unit>
<unit id="9uJEwv1" name="assembly.edit.ipn">
@ -13852,6 +13852,12 @@ Vezměte prosím na vědomí, že se nemůžete vydávat za uživatele se zakáz
<target>%value% (Součást)</target>
</segment>
</unit>
<unit id="o4zUJc5" name="part.table.name.value.for_assembly">
<segment state="translated">
<source>part.table.name.value.for_assembly</source>
<target>%value% (Sestava)</target>
</segment>
</unit>
<unit id="GW8ZOX7" name="part.table.name.value.for_project">
<segment state="translated">
<source>part.table.name.value.for_project</source>
@ -13888,6 +13894,12 @@ Vezměte prosím na vědomí, že se nemůžete vydávat za uživatele se zakáz
<target>Sestavy</target>
</segment>
</unit>
<unit id="Tab5Ou1" name="assembly.referencedAssembly.labelp">
<segment>
<source>assembly.referencedAssembly.labelp</source>
<target>Odkazované sestavy</target>
</segment>
</unit>
<unit id="gyRGdfv" name="assembly.edit">
<segment>
<source>assembly.edit</source>
@ -14056,6 +14068,12 @@ Vezměte prosím na vědomí, že se nemůžete vydávat za uživatele se zakáz
<target>Sestavit</target>
</segment>
</unit>
<unit id="1bCA1zb" name="assembly.build.form.referencedAssembly">
<segment>
<source>assembly.build.form.referencedAssembly</source>
<target>Sestava "%name%"</target>
</segment>
</unit>
<unit id="LFSVVcP" name="assembly.builds.no_stocked_builds">
<segment>
<source>assembly.builds.no_stocked_builds</source>
@ -14110,6 +14128,12 @@ Vezměte prosím na vědomí, že se nemůžete vydávat za uživatele se zakáz
<target>Projekt</target>
</segment>
</unit>
<unit id="od1xTi3" name="assembly.bom.referencedAssembly">
<segment>
<source>assembly.bom.referencedAssembly</source>
<target>Sestava</target>
</segment>
</unit>
<unit id="PPsM0Dg" name="assembly.bom.name">
<segment>
<source>assembly.bom.name</source>
@ -14146,10 +14170,10 @@ Vezměte prosím na vědomí, že se nemůžete vydávat za uživatele se zakáz
<target>Importovat součásti do sestavy</target>
</segment>
</unit>
<unit id="WTasGao" name="assembly.bom.partOrProject">
<unit id="WTasGao" name="assembly.bom.partOrAssembly">
<segment>
<source>assembly.bom.partOrProject</source>
<target>Součást</target>
<source>assembly.bom.partOrAssembly</source>
<target>Součást nebo sestava</target>
</segment>
</unit>
<unit id="jHKh8Zp" name="assembly.bom.add_entry">

View file

@ -9893,7 +9893,7 @@ Element 3</target>
<unit id="hIIFtI1" name="assembly.edit.status">
<segment state="translated">
<source>assembly.edit.status</source>
<target>Status</target>
<target>Samlingens status</target>
</segment>
</unit>
<unit id="9uJEwv1" name="assembly.edit.ipn">
@ -12569,6 +12569,12 @@ Bemærk venligst, at du ikke kan kopiere fra deaktiveret bruger. Hvis du prøver
<target>%value% (Del)</target>
</segment>
</unit>
<unit id="o4zUJc5" name="part.table.name.value.for_assembly">
<segment state="translated">
<source>part.table.name.value.for_assembly</source>
<target>%value% (Samling)</target>
</segment>
</unit>
<unit id="GW8ZOX7" name="part.table.name.value.for_project">
<segment state="translated">
<source>part.table.name.value.for_project</source>
@ -12605,6 +12611,12 @@ Bemærk venligst, at du ikke kan kopiere fra deaktiveret bruger. Hvis du prøver
<target>Samlinger</target>
</segment>
</unit>
<unit id="Tab5Ou1" name="assembly.referencedAssembly.labelp">
<segment>
<source>assembly.referencedAssembly.labelp</source>
<target>Refererede samlinger</target>
</segment>
</unit>
<unit id="gyRGdfv" name="assembly.edit">
<segment>
<source>assembly.edit</source>
@ -12773,6 +12785,12 @@ Bemærk venligst, at du ikke kan kopiere fra deaktiveret bruger. Hvis du prøver
<target>Byg</target>
</segment>
</unit>
<unit id="1bCA1zb" name="assembly.build.form.referencedAssembly">
<segment>
<source>assembly.build.form.referencedAssembly</source>
<target>Samling "%name%"</target>
</segment>
</unit>
<unit id="LFSVVcP" name="assembly.builds.no_stocked_builds">
<segment>
<source>assembly.builds.no_stocked_builds</source>
@ -12827,6 +12845,12 @@ Bemærk venligst, at du ikke kan kopiere fra deaktiveret bruger. Hvis du prøver
<target>Projekt</target>
</segment>
</unit>
<unit id="od1xTi3" name="assembly.bom.referencedAssembly">
<segment>
<source>assembly.bom.referencedAssembly</source>
<target>Sammenstilling</target>
</segment>
</unit>
<unit id="PPsM0Dg" name="assembly.bom.name">
<segment>
<source>assembly.bom.name</source>
@ -12863,10 +12887,10 @@ Bemærk venligst, at du ikke kan kopiere fra deaktiveret bruger. Hvis du prøver
<target>Importer dele til samling</target>
</segment>
</unit>
<unit id="WTasGao" name="assembly.bom.partOrProject">
<unit id="WTasGao" name="assembly.bom.partOrAssembly">
<segment>
<source>assembly.bom.partOrProject</source>
<target>Del</target>
<source>assembly.bom.partOrAssembly</source>
<target>Del eller samling</target>
</segment>
</unit>
<unit id="jHKh8Zp" name="assembly.bom.add_entry">

View file

@ -4746,6 +4746,12 @@ Wenn Sie dies fehlerhafterweise gemacht haben oder ein Computer nicht mehr vertr
<target>%value% (Bauteil)</target>
</segment>
</unit>
<unit id="o4zUJc5" name="part.table.name.value.for_assembly">
<segment state="translated">
<source>part.table.name.value.for_assembly</source>
<target>%value% (Baugruppe)</target>
</segment>
</unit>
<unit id="GW8ZOX7" name="part.table.name.value.for_project">
<segment state="translated">
<source>part.table.name.value.for_project</source>
@ -9953,7 +9959,7 @@ Element 1 -&gt; Element 1.2</target>
<unit id="hIIFtI1" name="assembly.edit.status">
<segment state="translated">
<source>assembly.edit.status</source>
<target>Status</target>
<target>Status Baugruppe</target>
</segment>
</unit>
<unit id="9uJEwv1" name="assembly.edit.ipn">
@ -13338,6 +13344,12 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
<target>Baugruppen</target>
</segment>
</unit>
<unit id="Tab5Ou1" name="assembly.referencedAssembly.labelp">
<segment>
<source>assembly.referencedAssembly.labelp</source>
<target>Referenzierte Baugruppen</target>
</segment>
</unit>
<unit id="gyRGdfv" name="assembly.edit">
<segment>
<source>assembly.edit</source>
@ -13506,6 +13518,12 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
<target>Bauen</target>
</segment>
</unit>
<unit id="1bCA1zb" name="assembly.build.form.referencedAssembly">
<segment>
<source>asssembly.build.form.referencedAssembly</source>
<target>Baugruppe "%name%"</target>
</segment>
</unit>
<unit id="LFSVVcP" name="assembly.builds.no_stocked_builds">
<segment>
<source>assembly.builds.no_stocked_builds</source>
@ -13560,6 +13578,12 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
<target>Projekt</target>
</segment>
</unit>
<unit id="od1xTi3" name="assembly.bom.referencedAssembly">
<segment>
<source>assembly.bom.referencedAssembly</source>
<target>Baugruppe</target>
</segment>
</unit>
<unit id="PPsM0Dg" name="assembly.bom.name">
<segment>
<source>assembly.bom.name</source>
@ -13596,10 +13620,10 @@ Bitte beachten Sie, dass Sie sich nicht als deaktivierter Benutzer ausgeben kön
<target>Importiere Parts für Baugruppe</target>
</segment>
</unit>
<unit id="WTasGao" name="assembly.bom.partOrProject">
<unit id="WTasGao" name="assembly.bom.partOrAssembly">
<segment>
<source>assembly.bom.partOrProject</source>
<target>Bauteil oder Projekt</target>
<source>assembly.bom.partOrAssembly</source>
<target>Bauteil oder Baugruppe</target>
</segment>
</unit>
<unit id="jHKh8Zp" name="assembly.bom.add_entry">

View file

@ -1541,6 +1541,12 @@
<target>%value% (Μέρος)</target>
</segment>
</unit>
<unit id="o4zUJc5" name="part.table.name.value.for_assembly">
<segment state="translated">
<source>part.table.name.value.for_assembly</source>
<target>%value% (Συναρμολόγηση)</target>
</segment>
</unit>
<unit id="GW8ZOX7" name="part.table.name.value.for_project">
<segment state="translated">
<source>part.table.name.value.for_project</source>
@ -1550,7 +1556,7 @@
<unit id="hIIFtI1" name="assembly.edit.status">
<segment state="translated">
<source>assembly.edit.status</source>
<target>Κατάσταση</target>
<target>Κατάσταση συναρμολόγησης</target>
</segment>
</unit>
<unit id="zRd.psv" name="assembly.status.draft">
@ -1613,6 +1619,12 @@
<target>Συναρμολογήσεις</target>
</segment>
</unit>
<unit id="Tab5Ou1" name="assembly.referencedAssembly.labelp">
<segment>
<source>assembly.referencedAssembly.labelp</source>
<target>Αναφερόμενες συναρμολογήσεις</target>
</segment>
</unit>
<unit id="gyRGdfv" name="assembly.edit">
<segment>
<source>assembly.edit</source>
@ -1781,6 +1793,12 @@
<target>Κατασκευή</target>
</segment>
</unit>
<unit id="1bCA1zb" name="assembly.build.form.referencedAssembly">
<segment>
<source>assembly.build.form.referencedAssembly</source>
<target>Συναρμολόγηση "%name%"</target>
</segment>
</unit>
<unit id="LFSVVcP" name="assembly.builds.no_stocked_builds">
<segment>
<source>assembly.builds.no_stocked_builds</source>
@ -1835,6 +1853,12 @@
<target>έργο</target>
</segment>
</unit>
<unit id="od1xTi3" name="assembly.bom.referencedAssembly">
<segment>
<source>assembly.bom.referencedAssembly</source>
<target>Συναρμολόγηση</target>
</segment>
</unit>
<unit id="PPsM0Dg" name="assembly.bom.name">
<segment>
<source>assembly.bom.name</source>
@ -1871,10 +1895,10 @@
<target>Εισαγωγή εξαρτημάτων συναρμολόγησης</target>
</segment>
</unit>
<unit id="WTasGao" name="assembly.bom.partOrProject">
<unit id="WTasGao" name="assembly.bom.partOrAssembly">
<segment>
<source>assembly.bom.partOrProject</source>
<target>Εξάρτημα</target>
<source>assembly.bom.partOrAssembly</source>
<target>Μέρος ή συναρμολόγηση</target>
</segment>
</unit>
<unit id="jHKh8Zp" name="assembly.bom.add_entry">

View file

@ -4747,6 +4747,12 @@ If you have done this incorrectly or if a computer is no longer trusted, you can
<target>%value% (Part)</target>
</segment>
</unit>
<unit id="o4zUJc5" name="part.table.name.value.for_assembly">
<segment state="translated">
<source>part.table.name.value.for_assembly</source>
<target>%value% (Assembly)</target>
</segment>
</unit>
<unit id="GW8ZOX7" name="part.table.name.value.for_project">
<segment state="translated">
<source>part.table.name.value.for_project</source>
@ -9954,7 +9960,7 @@ Element 1 -&gt; Element 1.2</target>
<unit id="hIIFtI1" name="assembly.edit.status">
<segment state="translated">
<source>assembly.edit.status</source>
<target>Project status</target>
<target>Assembly status</target>
</segment>
</unit>
<unit id="9uJEwv1" name="assembly.edit.ipn">
@ -13339,6 +13345,12 @@ Please note, that you can not impersonate a disabled user. If you try you will g
<target>Assemblies</target>
</segment>
</unit>
<unit id="Tab5Ou1" name="assembly.referencedAssembly.labelp">
<segment>
<source>assembly.referencedAssembly.labelp</source>
<target>Referenced assemblies</target>
</segment>
</unit>
<unit id="gyRGdfv" name="assembly.edit">
<segment>
<source>assembly.edit</source>
@ -13507,6 +13519,12 @@ Please note, that you can not impersonate a disabled user. If you try you will g
<target>Build</target>
</segment>
</unit>
<unit id="1bCA1zb" name="assembly.build.form.referencedAssembly">
<segment>
<source>assembly.build.form.referencedAssembly</source>
<target>Assembly "%name%"</target>
</segment>
</unit>
<unit id="LFSVVcP" name="assembly.builds.no_stocked_builds">
<segment>
<source>assembly.builds.no_stocked_builds</source>
@ -13561,6 +13579,12 @@ Please note, that you can not impersonate a disabled user. If you try you will g
<target>Project</target>
</segment>
</unit>
<unit id="od1xTi3" name="assembly.bom.referencedAssembly">
<segment>
<source>assembly.bom.referencedAssembly</source>
<target>Assembly</target>
</segment>
</unit>
<unit id="PPsM0Dg" name="assembly.bom.name">
<segment>
<source>assembly.bom.name</source>
@ -13597,10 +13621,10 @@ Please note, that you can not impersonate a disabled user. If you try you will g
<target>Import part list for assembly</target>
</segment>
</unit>
<unit id="WTasGao" name="assembly.bom.partOrProject">
<unit id="WTasGao" name="assembly.bom.partOrAssembly">
<segment>
<source>assembly.bom.partOrProject</source>
<target>Part</target>
<source>assembly.bom.partOrAssembly</source>
<target>Part or assembly</target>
</segment>
</unit>
<unit id="jHKh8Zp" name="assembly.bom.add_entry">

View file

@ -4746,6 +4746,12 @@ Subelementos serán desplazados hacia arriba.</target>
<target>%value% (Componente)</target>
</segment>
</unit>
<unit id="o4zUJc5" name="part.table.name.value.for_assembly">
<segment state="translated">
<source>part.table.name.value.for_assembly</source>
<target>%value% (Ensamblaje)</target>
</segment>
</unit>
<unit id="GW8ZOX7" name="part.table.name.value.for_project">
<segment state="translated">
<source>part.table.name.value.for_project</source>
@ -9897,7 +9903,7 @@ Elemento 3</target>
<unit id="hIIFtI1" name="assembly.edit.status">
<segment state="translated">
<source>assembly.edit.status</source>
<target>Estatus</target>
<target>Estado del ensamblaje</target>
</segment>
</unit>
<unit id="9uJEwv1" name="assembly.edit.ipn">
@ -12777,6 +12783,12 @@ Por favor ten en cuenta que no puedes personificar a un usuario deshabilitado. S
<target>Ensamblajes</target>
</segment>
</unit>
<unit id="Tab5Ou1" name="assembly.referencedAssembly.labelp">
<segment>
<source>assembly.referencedAssembly.labelp</source>
<target>Conjuntos referenciados</target>
</segment>
</unit>
<unit id="gyRGdfv" name="assembly.edit">
<segment>
<source>assembly.edit</source>
@ -12945,6 +12957,12 @@ Por favor ten en cuenta que no puedes personificar a un usuario deshabilitado. S
<target>Construir</target>
</segment>
</unit>
<unit id="1bCA1zb" name="assembly.build.form.referencedAssembly">
<segment>
<source>assembly.build.form.referencedAssembly</source>
<target>Ensamblaje "%name%"</target>
</segment>
</unit>
<unit id="LFSVVcP" name="assembly.builds.no_stocked_builds">
<segment>
<source>assembly.builds.no_stocked_builds</source>
@ -12999,6 +13017,12 @@ Por favor ten en cuenta que no puedes personificar a un usuario deshabilitado. S
<target>Proyecto</target>
</segment>
</unit>
<unit id="od1xTi3" name="assembly.bom.referencedAssembly">
<segment>
<source>assembly.bom.referencedAssembly</source>
<target>Ensamblaje</target>
</segment>
</unit>
<unit id="PPsM0Dg" name="assembly.bom.name">
<segment>
<source>assembly.bom.name</source>
@ -13035,10 +13059,10 @@ Por favor ten en cuenta que no puedes personificar a un usuario deshabilitado. S
<target>Importar piezas para ensamblaje</target>
</segment>
</unit>
<unit id="WTasGao" name="assembly.bom.partOrProject">
<unit id="WTasGao" name="assembly.bom.partOrAssembly">
<segment>
<source>assembly.bom.partOrProject</source>
<target>Pieza</target>
<source>assembly.bom.partOrAssembly</source>
<target>Parte o conjunto</target>
</segment>
</unit>
<unit id="jHKh8Zp" name="assembly.bom.add_entry">

View file

@ -4709,6 +4709,12 @@ Si vous avez fait cela de manière incorrecte ou si un ordinateur n'est plus fia
<target>%value% (Componente)</target>
</segment>
</unit>
<unit id="o4zUJc5" name="part.table.name.value.for_assembly">
<segment state="translated">
<source>part.table.name.value.for_assembly</source>
<target>%value% (Assemblage)</target>
</segment>
</unit>
<unit id="GW8ZOX7" name="part.table.name.value.for_project">
<segment state="translated">
<source>part.table.name.value.for_project</source>
@ -9112,7 +9118,7 @@ exemple de ville</target>
<unit id="hIIFtI1" name="assembly.edit.status">
<segment state="translated">
<source>assembly.edit.status</source>
<target>Statut</target>
<target>Statut de l'assemblage</target>
</segment>
</unit>
<unit id="zRd.psv" name="assembly.status.draft">
@ -9175,6 +9181,12 @@ exemple de ville</target>
<target>Assemblages</target>
</segment>
</unit>
<unit id="Tab5Ou1" name="assembly.referencedAssembly.labelp">
<segment>
<source>assembly.referencedAssembly.labelp</source>
<target>Assemblages référencés</target>
</segment>
</unit>
<unit id="gyRGdfv" name="assembly.edit">
<segment>
<source>assembly.edit</source>
@ -9343,6 +9355,12 @@ exemple de ville</target>
<target>Construire</target>
</segment>
</unit>
<unit id="1bCA1zb" name="assembly.build.form.referencedAssembly">
<segment>
<source>assembly.build.form.referencedAssembly</source>
<target>Assemblage "%name%"</target>
</segment>
</unit>
<unit id="LFSVVcP" name="assembly.builds.no_stocked_builds">
<segment>
<source>assembly.builds.no_stocked_builds</source>
@ -9397,6 +9415,12 @@ exemple de ville</target>
<target>Projet</target>
</segment>
</unit>
<unit id="od1xTi3" name="assembly.bom.referencedAssembly">
<segment>
<source>assembly.bom.referencedAssembly</source>
<target>Assemblage</target>
</segment>
</unit>
<unit id="PPsM0Dg" name="assembly.bom.name">
<segment>
<source>assembly.bom.name</source>
@ -9433,10 +9457,10 @@ exemple de ville</target>
<target>Importer des pièces pour l'assemblage</target>
</segment>
</unit>
<unit id="WTasGao" name="assembly.bom.partOrProject">
<unit id="WTasGao" name="assembly.bom.partOrAssembly">
<segment>
<source>assembly.bom.partOrProject</source>
<target>Pièce</target>
<source>assembly.bom.partOrAssembly</source>
<target>Pièce ou assemblage</target>
</segment>
</unit>
<unit id="jHKh8Zp" name="assembly.bom.add_entry">

View file

@ -4748,6 +4748,12 @@ Se è stato fatto in modo errato o se un computer non è più attendibile, puoi
<target>%value% (Componente)</target>
</segment>
</unit>
<unit id="o4zUJc5" name="part.table.name.value.for_assembly">
<segment state="translated">
<source>part.table.name.value.for_assembly</source>
<target>%value% (Assemblaggio)</target>
</segment>
</unit>
<unit id="GW8ZOX7" name="part.table.name.value.for_project">
<segment state="translated">
<source>part.table.name.value.for_project</source>
@ -9899,7 +9905,7 @@ Element 3</target>
<unit id="hIIFtI1" name="assembly.edit.status">
<segment state="translated">
<source>assembly.edit.status</source>
<target>Stato</target>
<target>Stato dell'assemblaggio</target>
</segment>
</unit>
<unit id="9uJEwv1" name="assembly.edit.ipn">
@ -12755,6 +12761,12 @@ Notare che non è possibile impersonare un utente disattivato. Quando si prova a
<target>Assemblaggi</target>
</segment>
</unit>
<unit id="Tab5Ou1" name="assembly.referencedAssembly.labelp">
<segment>
<source>assembly.referencedAssembly.labelp</source>
<target>Assembly referenziati</target>
</segment>
</unit>
<unit id="gyRGdfv" name="assembly.edit">
<segment>
<source>assembly.edit</source>
@ -12923,6 +12935,12 @@ Notare che non è possibile impersonare un utente disattivato. Quando si prova a
<target>Costruire</target>
</segment>
</unit>
<unit id="1bCA1zb" name="assembly.build.form.referencedAssembly">
<segment>
<source>assembly.build.form.referencedAssembly</source>
<target>Gruppo "%name%"</target>
</segment>
</unit>
<unit id="LFSVVcP" name="assembly.builds.no_stocked_builds">
<segment>
<source>assembly.builds.no_stocked_builds</source>
@ -12977,6 +12995,12 @@ Notare che non è possibile impersonare un utente disattivato. Quando si prova a
<target>Progetto</target>
</segment>
</unit>
<unit id="od1xTi3" name="assembly.bom.referencedAssembly">
<segment>
<source>assembly.bom.referencedAssembly</source>
<target>Assemblaggio</target>
</segment>
</unit>
<unit id="PPsM0Dg" name="assembly.bom.name">
<segment>
<source>assembly.bom.name</source>
@ -13013,10 +13037,10 @@ Notare che non è possibile impersonare un utente disattivato. Quando si prova a
<target>Importa componenti per il gruppo</target>
</segment>
</unit>
<unit id="WTasGao" name="assembly.bom.partOrProject">
<unit id="WTasGao" name="assembly.bom.partOrAssembly">
<segment>
<source>assembly.bom.partOrProject</source>
<target>Componente</target>
<source>assembly.bom.partOrAssembly</source>
<target>Parte o assieme</target>
</segment>
</unit>
<unit id="jHKh8Zp" name="assembly.bom.add_entry">

View file

@ -4709,6 +4709,12 @@
<target>%value%(部品)</target>
</segment>
</unit>
<unit id="o4zUJc5" name="part.table.name.value.for_assembly">
<segment state="translated">
<source>part.table.name.value.for_assembly</source>
<target>%value%(アセンブリ)</target>
</segment>
</unit>
<unit id="GW8ZOX7" name="part.table.name.value.for_project">
<segment state="translated">
<source>part.table.name.value.for_project</source>
@ -8849,7 +8855,7 @@ Exampletown</target>
<unit id="hIIFtI1" name="assembly.edit.status">
<segment state="translated">
<source>assembly.edit.status</source>
<target>ステータス</target>
<target>アセンブリのステータス</target>
</segment>
</unit>
<unit id="zRd.psv" name="assembly.status.draft">
@ -8912,6 +8918,12 @@ Exampletown</target>
<target>アセンブリ一覧</target>
</segment>
</unit>
<unit id="Tab5Ou1" name="assembly.referencedAssembly.labelp">
<segment>
<source>assembly.referencedAssembly.labelp</source>
<target>参照されたアセンブリ</target>
</segment>
</unit>
<unit id="gyRGdfv" name="assembly.edit">
<segment>
<source>assembly.edit</source>
@ -9080,6 +9092,12 @@ Exampletown</target>
<target>ビルド</target>
</segment>
</unit>
<unit id="1bCA1zb" name="assembly.build.form.referencedAssembly">
<segment>
<source>assembly.build.form.referencedAssembly</source>
<target>アセンブリ「%name%」</target>
</segment>
</unit>
<unit id="LFSVVcP" name="assembly.builds.no_stocked_builds">
<segment>
<source>assembly.builds.no_stocked_builds</source>
@ -9134,6 +9152,12 @@ Exampletown</target>
<target>プロジェクト</target>
</segment>
</unit>
<unit id="od1xTi3" name="assembly.bom.referencedAssembly">
<segment>
<source>assembly.bom.referencedAssembly</source>
<target>アセンブリ</target>
</segment>
</unit>
<unit id="PPsM0Dg" name="assembly.bom.name">
<segment>
<source>assembly.bom.name</source>

View file

@ -730,6 +730,12 @@
<target>%value% (Onderdeel)</target>
</segment>
</unit>
<unit id="o4zUJc5" name="part.table.name.value.for_assembly">
<segment state="translated">
<source>part.table.name.value.for_assembly</source>
<target>%value% (Assemblage)</target>
</segment>
</unit>
<unit id="GW8ZOX7" name="part.table.name.value.for_project">
<segment state="translated">
<source>part.table.name.value.for_project</source>
@ -739,7 +745,7 @@
<unit id="hIIFtI1" name="assembly.edit.status">
<segment state="translated">
<source>assembly.edit.status</source>
<target>Κατάσταση</target>
<target>Montagestatus</target>
</segment>
</unit>
<unit id="zRd.psv" name="assembly.status.draft">
@ -802,6 +808,12 @@
<target>Assemblages</target>
</segment>
</unit>
<unit id="Tab5Ou1" name="assembly.referencedAssembly.labelp">
<segment>
<source>assembly.referencedAssembly.labelp</source>
<target>Gerefereerde assemblages</target>
</segment>
</unit>
<unit id="gyRGdfv" name="assembly.edit">
<segment>
<source>assembly.edit</source>
@ -970,6 +982,12 @@
<target>Bouwen</target>
</segment>
</unit>
<unit id="1bCA1zb" name="assembly.build.form.referencedAssembly">
<segment>
<source>assembly.build.form.referencedAssembly</source>
<target>Assemblage "%name%"</target>
</segment>
</unit>
<unit id="LFSVVcP" name="assembly.builds.no_stocked_builds">
<segment>
<source>assembly.builds.no_stocked_builds</source>
@ -1024,6 +1042,12 @@
<target>Project</target>
</segment>
</unit>
<unit id="od1xTi3" name="assembly.bom.referencedAssembly">
<segment>
<source>assembly.bom.referencedAssembly</source>
<target>Assemblage</target>
</segment>
</unit>
<unit id="PPsM0Dg" name="assembly.bom.name">
<segment>
<source>assembly.bom.name</source>
@ -1060,10 +1084,10 @@
<target>Importeer onderdelen voor assemblage</target>
</segment>
</unit>
<unit id="WTasGao" name="assembly.bom.partOrProject">
<unit id="WTasGao" name="assembly.bom.partOrAssembly">
<segment>
<source>assembly.bom.partOrProject</source>
<target>Onderdeel</target>
<source>assembly.bom.partOrAssembly</source>
<target>Onderdeel of samenstelling</target>
</segment>
</unit>
<unit id="jHKh8Zp" name="assembly.bom.add_entry">

View file

@ -4751,6 +4751,12 @@ Jeśli zrobiłeś to niepoprawnie lub komputer nie jest już godny zaufania, mo
<target>%value%(部品)</target>
</segment>
</unit>
<unit id="o4zUJc5" name="part.table.name.value.for_assembly">
<segment state="translated">
<source>part.table.name.value.for_assembly</source>
<target>%value% (Złożenie)</target>
</segment>
</unit>
<unit id="GW8ZOX7" name="part.table.name.value.for_project">
<segment state="translated">
<source>part.table.name.value.for_project</source>
@ -9902,7 +9908,7 @@ Element 3</target>
<unit id="hIIFtI1" name="assembly.edit.status">
<segment state="translated">
<source>assembly.edit.status</source>
<target>Status</target>
<target>Status montażu</target>
</segment>
</unit>
<unit id="9uJEwv1" name="assembly.edit.ipn">
@ -12632,6 +12638,12 @@ Należy pamiętać, że nie możesz udawać nieaktywnych użytkowników. Jeśli
<target>Zespoły</target>
</segment>
</unit>
<unit id="Tab5Ou1" name="assembly.referencedAssembly.labelp">
<segment>
<source>assembly.referencedAssembly.labelp</source>
<target>Odwołane zestawy</target>
</segment>
</unit>
<unit id="gyRGdfv" name="assembly.edit">
<segment>
<source>assembly.edit</source>
@ -12800,6 +12812,12 @@ Należy pamiętać, że nie możesz udawać nieaktywnych użytkowników. Jeśli
<target>Zbuduj</target>
</segment>
</unit>
<unit id="1bCA1zb" name="assembly.build.form.referencedAssembly">
<segment>
<source>assembly.build.form.referencedAssembly</source>
<target>Zespół "%name%"</target>
</segment>
</unit>
<unit id="LFSVVcP" name="assembly.builds.no_stocked_builds">
<segment>
<source>assembly.builds.no_stocked_builds</source>
@ -12854,6 +12872,12 @@ Należy pamiętać, że nie możesz udawać nieaktywnych użytkowników. Jeśli
<target>Projekt</target>
</segment>
</unit>
<unit id="od1xTi3" name="assembly.bom.referencedAssembly">
<segment>
<source>assembly.bom.referencedAssembly</source>
<target>Złożenie</target>
</segment>
</unit>
<unit id="PPsM0Dg" name="assembly.bom.name">
<segment>
<source>assembly.bom.name</source>
@ -12890,10 +12914,10 @@ Należy pamiętać, że nie możesz udawać nieaktywnych użytkowników. Jeśli
<target>Importuj części dla zespołu</target>
</segment>
</unit>
<unit id="WTasGao" name="assembly.bom.partOrProject">
<unit id="WTasGao" name="assembly.bom.partOrAssembly">
<segment>
<source>assembly.bom.partOrProject</source>
<target>Część</target>
<source>assembly.bom.partOrAssembly</source>
<target>Część lub zespół</target>
</segment>
</unit>
<unit id="jHKh8Zp" name="assembly.bom.add_entry">

View file

@ -4757,6 +4757,12 @@
<target>%value% (Часть)</target>
</segment>
</unit>
<unit id="o4zUJc5" name="part.table.name.value.for_assembly">
<segment state="translated">
<source>part.table.name.value.for_assembly</source>
<target>%value% (Сборка)</target>
</segment>
</unit>
<unit id="GW8ZOX7" name="part.table.name.value.for_project">
<segment state="translated">
<source>part.table.name.value.for_project</source>
@ -9906,7 +9912,7 @@
<unit id="hIIFtI1" name="assembly.edit.status">
<segment state="translated">
<source>assembly.edit.status</source>
<target>Статус</target>
<target>Статус сборки</target>
</segment>
</unit>
<unit id="9uJEwv1" name="assembly.edit.ipn">
@ -12732,6 +12738,12 @@
<target>Сборки</target>
</segment>
</unit>
<unit id="Tab5Ou1" name="assembly.referencedAssembly.labelp">
<segment>
<source>assembly.referencedAssembly.labelp</source>
<target>Ссылочные сборки</target>
</segment>
</unit>
<unit id="gyRGdfv" name="assembly.edit">
<segment>
<source>assembly.edit</source>
@ -12900,6 +12912,12 @@
<target>Собрать</target>
</segment>
</unit>
<unit id="1bCA1zb" name="assembly.build.form.referencedAssembly">
<segment>
<source>assembly.build.form.referencedAssembly</source>
<target>Сборка "%name%"</target>
</segment>
</unit>
<unit id="LFSVVcP" name="assembly.builds.no_stocked_builds">
<segment>
<source>assembly.builds.no_stocked_builds</source>
@ -12954,6 +12972,12 @@
<target>Проект</target>
</segment>
</unit>
<unit id="od1xTi3" name="assembly.bom.referencedAssembly">
<segment>
<source>assembly.bom.referencedAssembly</source>
<target>Сборка</target>
</segment>
</unit>
<unit id="PPsM0Dg" name="assembly.bom.name">
<segment>
<source>assembly.bom.name</source>
@ -12990,10 +13014,10 @@
<target>Импортировать детали для сборки</target>
</segment>
</unit>
<unit id="WTasGao" name="assembly.bom.partOrProject">
<unit id="WTasGao" name="assembly.bom.partOrAssembly">
<segment>
<source>assembly.bom.partOrProject</source>
<target>Компонент</target>
<source>assembly.bom.partOrAssembly</source>
<target>Часть или сборка</target>
</segment>
</unit>
<unit id="jHKh8Zp" name="assembly.bom.add_entry">

View file

@ -4755,6 +4755,12 @@
<target>%value%(部件)</target>
</segment>
</unit>
<unit id="o4zUJc5" name="part.table.name.value.for_assembly">
<segment state="translated">
<source>part.table.name.value.for_assembly</source>
<target>%value%(装配)</target>
</segment>
</unit>
<unit id="GW8ZOX7" name="part.table.name.value.for_project">
<segment state="translated">
<source>part.table.name.value.for_project</source>
@ -9905,7 +9911,7 @@ Element 3</target>
<unit id="hIIFtI1" name="assembly.edit.status">
<segment state="translated">
<source>assembly.edit.status</source>
<target>状态</target>
<target>装配状态</target>
</segment>
</unit>
<unit id="9uJEwv1" name="assembly.edit.ipn">
@ -12617,6 +12623,12 @@ Element 3</target>
<target>装配列表</target>
</segment>
</unit>
<unit id="Tab5Ou1" name="assembly.referencedAssembly.labelp">
<segment>
<source>assembly.referencedAssembly.labelp</source>
<target>引用的程序集</target>
</segment>
</unit>
<unit id="gyRGdfv" name="assembly.edit">
<segment>
<source>assembly.edit</source>
@ -12785,6 +12797,12 @@ Element 3</target>
<target>构建</target>
</segment>
</unit>
<unit id="1bCA1zb" name="assembly.build.form.referencedAssembly">
<segment>
<source>assembly.build.form.referencedAssembly</source>
<target>组件“%name%”</target>
</segment>
</unit>
<unit id="LFSVVcP" name="assembly.builds.no_stocked_builds">
<segment>
<source>assembly.builds.no_stocked_builds</source>
@ -12839,6 +12857,12 @@ Element 3</target>
<target>项目</target>
</segment>
</unit>
<unit id="od1xTi3" name="assembly.bom.referencedAssembly">
<segment>
<source>assembly.bom.referencedAssembly</source>
<target>组件</target>
</segment>
</unit>
<unit id="PPsM0Dg" name="assembly.bom.name">
<segment>
<source>assembly.bom.name</source>
@ -12875,10 +12899,10 @@ Element 3</target>
<target>导入组件的零件</target>
</segment>
</unit>
<unit id="WTasGao" name="assembly.bom.partOrProject">
<unit id="WTasGao" name="assembly.bom.partOrAssembly">
<segment>
<source>assembly.bom.partOrProject</source>
<target>件</target>
<source>assembly.bom.partOrAssembly</source>
<target>部件或组件</target>
</segment>
</unit>
<unit id="jHKh8Zp" name="assembly.bom.add_entry">

View file

@ -251,12 +251,6 @@
<target>Musíte vybrat díl pro položku BOM dílu nebo nastavit název pro položku BOM bez dílu.</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.project.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.project.bom_entry.only_part_or_assembly_allowed</source>
<target>Je povoleno vybrat pouze jednu součástku nebo sestavu. Upravit prosím svůj výběr!</target>
</segment>
</unit>
<unit id="5CEup_N" name="project.bom_entry.name_already_in_bom">
<segment state="translated">
<source>project.bom_entry.name_already_in_bom</source>
@ -395,6 +389,12 @@
<target>Tato součást již existuje ve skupině!</target>
</segment>
</unit>
<unit id="KiW1eoj" name="assembly.bom_entry.assembly_already_in_bom">
<segment>
<source>assembly.bom_entry.assembly_already_in_bom</source>
<target>Tato sestava již existuje jako položka v seznamu materiálů!</target>
</segment>
</unit>
<unit id="6bkQ3bo" name="assembly.bom_entry.project_already_in_bom">
<segment>
<source>assembly.bom_entry.project_already_in_bom</source>
@ -413,6 +413,12 @@
<target>Musíte vybrat součást nebo nastavit název pro nesoučást!</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.assembly.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.assembly.bom_entry.only_part_or_assembly_allowed</source>
<target>Je povoleno vybrat pouze jednu součástku nebo sestavu. Upravit prosím svůj výběr!</target>
</segment>
</unit>
<unit id="a1dKro7" name="validator.bom_importer.json_csv.quantity.required">
<segment>
<source>validator.bom_importer.json_csv.quantity.required</source>

View file

@ -251,12 +251,6 @@
<target>Du skal vælge en komponent eller angive et navn til en ikke-komponent styklistepost!</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.project.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.project.bom_entry.only_part_or_assembly_allowed</source>
<target>Det er kun tilladt at vælge én del eller en samling. Venligst tilpas dit valg!</target>
</segment>
</unit>
<unit id="WF_v4ih" name="project.bom_entry.name_already_in_bom">
<segment state="translated">
<source>project.bom_entry.name_already_in_bom</source>
@ -371,6 +365,12 @@
<target>Denne del eksisterer allerede i gruppen!</target>
</segment>
</unit>
<unit id="KiW1eoj" name="assembly.bom_entry.assembly_already_in_bom">
<segment>
<source>assembly.bom_entry.assembly_already_in_bom</source>
<target>Denne samling findes allerede som en post!</target>
</segment>
</unit>
<unit id="6bkQ3bo" name="assembly.bom_entry.project_already_in_bom">
<segment>
<source>assembly.bom_entry.project_already_in_bom</source>
@ -389,6 +389,12 @@
<target>Du skal vælge en del eller sætte et navn for en ikke-del!</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.assembly.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.assembly.bom_entry.only_part_or_assembly_allowed</source>
<target>Det er kun tilladt at vælge én del eller en samling. Venligst tilpas dit valg!</target>
</segment>
</unit>
<unit id="a1dKro7" name="validator.bom_importer.json_csv.quantity.required">
<segment>
<source>validator.bom_importer.json_csv.quantity.required</source>

View file

@ -251,12 +251,6 @@
<target>Sie müssen ein Bauteil bzw. eine Baugruppe auswählen, oder einen Namen für ein nicht-Bauteil BOM-Eintrag setzen!</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.project.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.project.bom_entry.only_part_or_assembly_allowed</source>
<target>Es darf nur ein Bauteil oder eine Baugruppe ausgewählt werden. Bitte passen Sie Ihre Auswahl an!</target>
</segment>
</unit>
<unit id="5CEup_N" name="project.bom_entry.name_already_in_bom">
<segment state="translated">
<source>project.bom_entry.name_already_in_bom</source>
@ -395,6 +389,12 @@
<target>Dieses Bauteil existiert bereits in der Gruppe!</target>
</segment>
</unit>
<unit id="KiW1eoj" name="assembly.bom_entry.assembly_already_in_bom">
<segment>
<source>assembly.bom_entry.assembly_already_in_bom</source>
<target>Diese Baugruppe existiert bereits als Eintrag!</target>
</segment>
</unit>
<unit id="6bkQ3bo" name="assembly.bom_entry.project_already_in_bom">
<segment>
<source>assembly.bom_entry.project_already_in_bom</source>
@ -413,6 +413,12 @@
<target>Sie müssen ein Bauteil auswählen, oder einen Namen für den Eintrag setzen!</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.assembly.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.assembly.bom_entry.only_part_or_assembly_allowed</source>
<target>Es darf nur ein Bauteil oder eine Baugruppe ausgewählt werden. Bitte passen Sie Ihre Auswahl an!</target>
</segment>
</unit>
<unit id="a1dKro7" name="validator.bom_importer.json_csv.quantity.required">
<segment>
<source>validator.bom_importer.json_csv.quantity.required</source>

View file

@ -13,12 +13,6 @@
<target>Ο εσωτερικός αριθμός εξαρτήματος πρέπει να είναι μοναδικός. {{ value }} χρησιμοποιείται ήδη!</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.project.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.project.bom_entry.only_part_or_assembly_allowed</source>
<target>Det er kun tilladt at vælge én del eller en samling. Venligst tilpas dit valg!</target>
</segment>
</unit>
<unit id="b1ZWoQ5" name="validator.bom_importer.invalid_import_type">
<segment state="translated">
<source>validator.bom_importer.invalid_import_type</source>
@ -37,6 +31,12 @@
<target>Αυτό το εξάρτημα υπάρχει ήδη στην ομάδα!</target>
</segment>
</unit>
<unit id="KiW1eoj" name="assembly.bom_entry.assembly_already_in_bom">
<segment>
<source>assembly.bom_entry.assembly_already_in_bom</source>
<target>Αυτή η συναρμολόγηση υπάρχει ήδη ως εγγραφή!</target>
</segment>
</unit>
<unit id="6bkQ3bo" name="assembly.bom_entry.project_already_in_bom">
<segment>
<source>assembly.bom_entry.project_already_in_bom</source>
@ -55,6 +55,12 @@
<target>Πρέπει να επιλέξετε ένα εξάρτημα ή να βάλετε ένα όνομα για ένα μη εξάρτημα!</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.assembly.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.assembly.bom_entry.only_part_or_assembly_allowed</source>
<target>Det er kun tilladt at vælge én del eller en samling. Venligst tilpas dit valg!</target>
</segment>
</unit>
<unit id="a1dKro7" name="validator.bom_importer.json_csv.quantity.required">
<segment>
<source>validator.bom_importer.json_csv.quantity.required</source>

View file

@ -251,12 +251,6 @@
<target>You have to select a part or assembly, or set a name for a non-component Bom entry!</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.project.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.project.bom_entry.only_part_or_assembly_allowed</source>
<target>Only one part or assembly may be selected. Please modify your selection!</target>
</segment>
</unit>
<unit id="5CEup_N" name="project.bom_entry.name_already_in_bom">
<segment state="translated">
<source>project.bom_entry.name_already_in_bom</source>
@ -395,6 +389,12 @@
<target>This part already exists in the list!</target>
</segment>
</unit>
<unit id="KiW1eoj" name="assembly.bom_entry.assembly_already_in_bom">
<segment>
<source>assembly.bom_entry.assembly_already_in_bom</source>
<target>This assembly already exists as an entry!</target>
</segment>
</unit>
<unit id="6bkQ3bo" name="assembly.bom_entry.project_already_in_bom">
<segment>
<source>assembly.bom_entry.project_already_in_bom</source>
@ -413,6 +413,12 @@
<target>You must select a part or set a name for the entry!</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.assembly.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.assembly.bom_entry.only_part_or_assembly_allowed</source>
<target>Only one part or assembly may be selected. Please modify your selection!</target>
</segment>
</unit>
<unit id="a1dKro7" name="validator.bom_importer.json_csv.quantity.required">
<segment>
<source>validator.bom_importer.json_csv.quantity.required</source>

View file

@ -203,12 +203,6 @@
<target>L'emplacement de stockage a été marqué comme "Composant seul", par conséquent aucun nouveau composant ne peut être ajouté.</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.project.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.project.bom_entry.only_part_or_assembly_allowed</source>
<target>Seule une pièce ou un assemblage peut être sélectionné. Veuillez ajuster votre sélection!</target>
</segment>
</unit>
<unit id="b1ZWoQ5" name="validator.bom_importer.invalid_import_type">
<segment state="translated">
<source>validator.bom_importer.invalid_import_type</source>
@ -227,6 +221,12 @@
<target>Cette pièce existe déjà dans le groupe!</target>
</segment>
</unit>
<unit id="KiW1eoj" name="assembly.bom_entry.assembly_already_in_bom">
<segment>
<source>assembly.bom_entry.assembly_already_in_bom</source>
<target>Cet assemblage existe déjà en tant qu'entrée !</target>
</segment>
</unit>
<unit id="6bkQ3bo" name="assembly.bom_entry.project_already_in_bom">
<segment>
<source>assembly.bom_entry.project_already_in_bom</source>
@ -245,6 +245,12 @@
<target>Vous devez sélectionner une pièce ou attribuer un nom pour un non-élément!</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.assembly.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.assembly.bom_entry.only_part_or_assembly_allowed</source>
<target>Seule une pièce ou un assemblage peut être sélectionné. Veuillez ajuster votre sélection!</target>
</segment>
</unit>
<unit id="a1dKro7" name="validator.bom_importer.json_csv.quantity.required">
<segment>
<source>validator.bom_importer.json_csv.quantity.required</source>

View file

@ -251,12 +251,6 @@
<target>Morate odabrati dio za unos u BOM ili postaviti naziv za unos koji nije dio.</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.project.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.project.bom_entry.only_part_or_assembly_allowed</source>
<target>Dozvoljeno je odabrati samo jednu komponentu ili sklop. Molimo prilagodite svoj odabir!</target>
</segment>
</unit>
<unit id="5CEup_N" name="project.bom_entry.name_already_in_bom">
<segment state="translated">
<source>project.bom_entry.name_already_in_bom</source>
@ -389,6 +383,12 @@
<target>Ovaj dio već postoji u grupi!</target>
</segment>
</unit>
<unit id="KiW1eoj" name="assembly.bom_entry.assembly_already_in_bom">
<segment>
<source>assembly.bom_entry.assembly_already_in_bom</source>
<target>Ova se montaža već nalazi kao zapis!</target>
</segment>
</unit>
<unit id="6bkQ3bo" name="assembly.bom_entry.project_already_in_bom">
<segment>
<source>assembly.bom_entry.project_already_in_bom</source>
@ -407,6 +407,12 @@
<target>Morate odabrati dio ili unijeti naziv za nedio!</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.assembly.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.assembly.bom_entry.only_part_or_assembly_allowed</source>
<target>Dozvoljeno je odabrati samo jednu komponentu ili sklop. Molimo prilagodite svoj odabir!</target>
</segment>
</unit>
<unit id="a1dKro7" name="validator.bom_importer.json_csv.quantity.required">
<segment>
<source>validator.bom_importer.json_csv.quantity.required</source>

View file

@ -251,12 +251,6 @@
<target>È necessario selezionare un componente o assegnare un nome ad una voce BOM che non indica un componente!</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.project.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.project.bom_entry.only_part_or_assembly_allowed</source>
<target>È consentito selezionare solo una parte o un assieme. Si prega di modificare la selezione!</target>
</segment>
</unit>
<unit id="5CEup_N" name="project.bom_entry.name_already_in_bom">
<segment state="translated">
<source>project.bom_entry.name_already_in_bom</source>
@ -389,6 +383,12 @@
<target>Questa parte è già presente nel gruppo!</target>
</segment>
</unit>
<unit id="KiW1eoj" name="assembly.bom_entry.assembly_already_in_bom">
<segment>
<source>assembly.bom_entry.assembly_already_in_bom</source>
<target>Questo assemblaggio è già presente come voce!</target>
</segment>
</unit>
<unit id="6bkQ3bo" name="assembly.bom_entry.project_already_in_bom">
<segment>
<source>assembly.bom_entry.project_already_in_bom</source>
@ -407,6 +407,12 @@
<target>È necessario selezionare una parte o inserire un nome per un non-parte!</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.assembly.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.assembly.bom_entry.only_part_or_assembly_allowed</source>
<target>È consentito selezionare solo una parte o un assieme. Si prega di modificare la selezione!</target>
</segment>
</unit>
<unit id="a1dKro7" name="validator.bom_importer.json_csv.quantity.required">
<segment>
<source>validator.bom_importer.json_csv.quantity.required</source>

View file

@ -203,12 +203,6 @@
<target>新しい部品を追加できません。保管場所は「1つの部品のみ」とマークされています。</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.project.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.project.bom_entry.only_part_or_assembly_allowed</source>
<target>部品またはアセンブリのみ選択可能です。選択内容を調整してください!</target>
</segment>
</unit>
<unit id="b1ZWoQ5" name="validator.bom_importer.invalid_import_type">
<segment state="translated">
<source>validator.bom_importer.invalid_import_type</source>
@ -227,6 +221,12 @@
<target>この部品はすでにグループに存在します!</target>
</segment>
</unit>
<unit id="KiW1eoj" name="assembly.bom_entry.assembly_already_in_bom">
<segment>
<source>assembly.bom_entry.assembly_already_in_bom</source>
<target>このアセンブリはすでにエントリとして存在します!</target>
</segment>
</unit>
<unit id="6bkQ3bo" name="assembly.bom_entry.project_already_in_bom">
<segment>
<source>assembly.bom_entry.project_already_in_bom</source>
@ -245,6 +245,12 @@
<target>部品を選択するか、非部品の名前を入力する必要があります!</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.assembly.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.assembly.bom_entry.only_part_or_assembly_allowed</source>
<target>部品またはアセンブリのみ選択可能です。選択内容を調整してください!</target>
</segment>
</unit>
<unit id="a1dKro7" name="validator.bom_importer.json_csv.quantity.required">
<segment>
<source>validator.bom_importer.json_csv.quantity.required</source>

View file

@ -251,12 +251,6 @@
<target>Należy wybrać część dla wpisu BOM części lub ustawić nazwę dla wpisu BOM niebędącego częścią.</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.project.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.project.bom_entry.only_part_or_assembly_allowed</source>
<target>Można wybrać tylko jedną część lub zespół. Proszę dostosować swój wybór!</target>
</segment>
</unit>
<unit id="5CEup_N" name="project.bom_entry.name_already_in_bom">
<segment state="translated">
<source>project.bom_entry.name_already_in_bom</source>
@ -389,6 +383,12 @@
<target>Ten element już istnieje w grupie!</target>
</segment>
</unit>
<unit id="KiW1eoj" name="assembly.bom_entry.assembly_already_in_bom">
<segment>
<source>assembly.bom_entry.assembly_already_in_bom</source>
<target>To zestawienie jest już dodane jako wpis!</target>
</segment>
</unit>
<unit id="6bkQ3bo" name="assembly.bom_entry.project_already_in_bom">
<segment>
<source>assembly.bom_entry.project_already_in_bom</source>
@ -407,6 +407,12 @@
<target>Musisz wybrać element lub przypisać nazwę dla elementu niestandardowego!</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.assembly.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.assembly.bom_entry.only_part_or_assembly_allowed</source>
<target>Można wybrać tylko jedną część lub zespół. Proszę dostosować swój wybór!</target>
</segment>
</unit>
<unit id="a1dKro7" name="validator.bom_importer.json_csv.quantity.required">
<segment>
<source>validator.bom_importer.json_csv.quantity.required</source>

View file

@ -251,12 +251,6 @@
<target>Вам необходимо выбрать компонент или задать имя для BOM, не относящейся к компоненту!</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.project.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.project.bom_entry.only_part_or_assembly_allowed</source>
<target>Можно выбрать только деталь или сборку. Пожалуйста, измените ваш выбор!</target>
</segment>
</unit>
<unit id="5CEup_N" name="project.bom_entry.name_already_in_bom">
<segment state="translated">
<source>project.bom_entry.name_already_in_bom</source>
@ -389,6 +383,12 @@
<target>Эта деталь уже существует в группе!</target>
</segment>
</unit>
<unit id="KiW1eoj" name="assembly.bom_entry.assembly_already_in_bom">
<segment>
<source>assembly.bom_entry.assembly_already_in_bom</source>
<target>Этот сборочный узел уже добавлен как запись!</target>
</segment>
</unit>
<unit id="6bkQ3bo" name="assembly.bom_entry.project_already_in_bom">
<segment>
<source>assembly.bom_entry.project_already_in_bom</source>
@ -407,6 +407,12 @@
<target>Необходимо выбрать деталь или ввести название для недетали!</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.assembly.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.assembly.bom_entry.only_part_or_assembly_allowed</source>
<target>Можно выбрать только деталь или сборку. Пожалуйста, измените ваш выбор!</target>
</segment>
</unit>
<unit id="a1dKro7" name="validator.bom_importer.json_csv.quantity.required">
<segment>
<source>validator.bom_importer.json_csv.quantity.required</source>

View file

@ -251,12 +251,6 @@
<target>您必须为 BOM 条目选择部件,或为非部件 BOM 条目设置名称。</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.project.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.project.bom_entry.only_part_or_assembly_allowed</source>
<target>只能选择一个零件或组件。请修改您的选择!</target>
</segment>
</unit>
<unit id="WF_v4ih" name="project.bom_entry.name_already_in_bom">
<segment state="translated">
<source>project.bom_entry.name_already_in_bom</source>
@ -377,6 +371,12 @@
<target>此零件已存在于组中!</target>
</segment>
</unit>
<unit id="KiW1eoj" name="assembly.bom_entry.assembly_already_in_bom">
<segment>
<source>assembly.bom_entry.assembly_already_in_bom</source>
<target>此装配已经作为条目存在!</target>
</segment>
</unit>
<unit id="6bkQ3bo" name="assembly.bom_entry.project_already_in_bom">
<segment>
<source>assembly.bom_entry.project_already_in_bom</source>
@ -395,6 +395,12 @@
<target>必须选择零件或为非零件指定名称!</target>
</segment>
</unit>
<unit id="Q42Zh.e" name="validator.assembly.bom_entry.only_part_or_assembly_allowed">
<segment state="translated">
<source>validator.assembly.bom_entry.only_part_or_assembly_allowed</source>
<target>只能选择一个零件或组件。请修改您的选择!</target>
</segment>
</unit>
<unit id="a1dKro7" name="validator.bom_importer.json_csv.quantity.required">
<segment>
<source>validator.bom_importer.json_csv.quantity.required</source>