mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2026-01-21 09:39:34 +00:00
Merge branch 'Part-DB:master' into master
This commit is contained in:
commit
47e70826dc
22 changed files with 2310 additions and 2195 deletions
2
.env
2
.env
|
|
@ -214,7 +214,7 @@ APP_SECRET=a03498528f5a5fc089273ec9ae5b2849
|
||||||
|
|
||||||
|
|
||||||
# Set the trusted IPs here, when using an reverse proxy
|
# Set the trusted IPs here, when using an reverse proxy
|
||||||
#TRUSTED_PROXIES=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
|
#TRUSTED_PROXIES=127.0.0.0/8,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
|
||||||
#TRUSTED_HOSTS='^(localhost|example\.com)$'
|
#TRUSTED_HOSTS='^(localhost|example\.com)$'
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
560
composer.lock
generated
560
composer.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -20,4 +20,21 @@ TRUSTED_PROXIES=192.168.2.10
|
||||||
```
|
```
|
||||||
|
|
||||||
Set the `DEFAULT_URI` environment variable to the URL of your Part-DB installation, available from the outside (so via
|
Set the `DEFAULT_URI` environment variable to the URL of your Part-DB installation, available from the outside (so via
|
||||||
the reverse proxy).
|
the reverse proxy).
|
||||||
|
|
||||||
|
## Part-DB in a subpath via reverse proxy
|
||||||
|
|
||||||
|
If you put Part-DB into a subpath via the reverse proxy, you have to configure your webserver to include `X-Forwarded-Prefix` in the request headers.
|
||||||
|
For example if you put Part-DB behind a reverse proxy with the URL `https://example.com/partdb`, you have to set the `X-Forwarded-Prefix` header to `/partdb`.
|
||||||
|
|
||||||
|
In apache, you can do this by adding the following line to your virtual host configuration:
|
||||||
|
|
||||||
|
```
|
||||||
|
RequestHeader set X-Forwarded-Prefix "/partdb"
|
||||||
|
```
|
||||||
|
|
||||||
|
and in nginx, you can do this by adding the following line to your server configuration:
|
||||||
|
|
||||||
|
```
|
||||||
|
proxy_set_header X-Forwarded-Prefix "/partdb";
|
||||||
|
```
|
||||||
|
|
@ -71,11 +71,12 @@ class ScanController extends AbstractController
|
||||||
|
|
||||||
if ($input === null && $form->isSubmitted() && $form->isValid()) {
|
if ($input === null && $form->isSubmitted() && $form->isValid()) {
|
||||||
$input = $form['input']->getData();
|
$input = $form['input']->getData();
|
||||||
|
$mode = $form['mode']->getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($input !== null) {
|
if ($input !== null) {
|
||||||
try {
|
try {
|
||||||
$scan_result = $this->barcodeNormalizer->scanBarcodeContent($input);
|
$scan_result = $this->barcodeNormalizer->scanBarcodeContent($input, $mode ?? null);
|
||||||
try {
|
try {
|
||||||
return $this->redirect($this->barcodeParser->getRedirectURL($scan_result));
|
return $this->redirect($this->barcodeParser->getRedirectURL($scan_result));
|
||||||
} catch (EntityNotFoundException) {
|
} catch (EntityNotFoundException) {
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ class PartFixtures extends Fixture implements DependentFixtureInterface
|
||||||
$part->setManufacturer($manager->find(Manufacturer::class, 1));
|
$part->setManufacturer($manager->find(Manufacturer::class, 1));
|
||||||
$part->setTags('test, Test, Part2');
|
$part->setTags('test, Test, Part2');
|
||||||
$part->setMass(100.2);
|
$part->setMass(100.2);
|
||||||
|
$part->setIpn('IPN123');
|
||||||
$part->setNeedsReview(true);
|
$part->setNeedsReview(true);
|
||||||
$part->setManufacturingStatus(ManufacturingStatus::ACTIVE);
|
$part->setManufacturingStatus(ManufacturingStatus::ACTIVE);
|
||||||
$manager->persist($part);
|
$manager->persist($part);
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,9 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Form\LabelSystem;
|
namespace App\Form\LabelSystem;
|
||||||
|
|
||||||
|
use App\Services\LabelSystem\Barcodes\BarcodeSourceType;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\EnumType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
|
@ -59,6 +61,20 @@ class ScanDialogType extends AbstractType
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
$builder->add('mode', EnumType::class, [
|
||||||
|
'label' => 'scan_dialog.mode',
|
||||||
|
'expanded' => true,
|
||||||
|
'class' => BarcodeSourceType::class,
|
||||||
|
'required' => false,
|
||||||
|
'placeholder' => 'scan_dialog.mode.auto',
|
||||||
|
'choice_label' => fn (?BarcodeSourceType $enum) => match($enum) {
|
||||||
|
null => 'scan_dialog.mode.auto',
|
||||||
|
BarcodeSourceType::INTERNAL => 'scan_dialog.mode.internal',
|
||||||
|
BarcodeSourceType::IPN => 'scan_dialog.mode.ipn',
|
||||||
|
},
|
||||||
|
|
||||||
|
]);
|
||||||
|
|
||||||
$builder->add('submit', SubmitType::class, [
|
$builder->add('submit', SubmitType::class, [
|
||||||
'label' => 'scan_dialog.submit',
|
'label' => 'scan_dialog.submit',
|
||||||
]);
|
]);
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,8 @@ declare(strict_types=1);
|
||||||
namespace App\Services\LabelSystem\Barcodes;
|
namespace App\Services\LabelSystem\Barcodes;
|
||||||
|
|
||||||
use App\Entity\LabelSystem\LabelSupportedElement;
|
use App\Entity\LabelSystem\LabelSupportedElement;
|
||||||
|
use App\Entity\Parts\Part;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -61,6 +63,10 @@ final class BarcodeScanHelper
|
||||||
'location' => LabelSupportedElement::STORELOCATION,
|
'location' => LabelSupportedElement::STORELOCATION,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public function __construct(private readonly EntityManagerInterface $entityManager)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the given barcode content and return the target type and ID.
|
* Parse the given barcode content and return the target type and ID.
|
||||||
* If the barcode could not be parsed, an exception is thrown.
|
* If the barcode could not be parsed, an exception is thrown.
|
||||||
|
|
@ -76,6 +82,9 @@ final class BarcodeScanHelper
|
||||||
if ($type === BarcodeSourceType::INTERNAL) {
|
if ($type === BarcodeSourceType::INTERNAL) {
|
||||||
return $this->parseInternalBarcode($input) ?? throw new InvalidArgumentException('Could not parse barcode');
|
return $this->parseInternalBarcode($input) ?? throw new InvalidArgumentException('Could not parse barcode');
|
||||||
}
|
}
|
||||||
|
if ($type === BarcodeSourceType::IPN) {
|
||||||
|
return $this->parseIPNBarcode($input) ?? throw new InvalidArgumentException('Could not parse barcode');
|
||||||
|
}
|
||||||
|
|
||||||
//Null means auto and we try the different formats
|
//Null means auto and we try the different formats
|
||||||
$result = $this->parseInternalBarcode($input);
|
$result = $this->parseInternalBarcode($input);
|
||||||
|
|
@ -83,9 +92,35 @@ final class BarcodeScanHelper
|
||||||
if ($result !== null) {
|
if ($result !== null) {
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Try to parse as IPN barcode
|
||||||
|
$result = $this->parseIPNBarcode($input);
|
||||||
|
if ($result !== null) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
throw new InvalidArgumentException('Unknown barcode format');
|
throw new InvalidArgumentException('Unknown barcode format');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function parseIPNBarcode(string $input): ?BarcodeScanResult
|
||||||
|
{
|
||||||
|
$part_repo = $this->entityManager->getRepository(Part::class);
|
||||||
|
//Find only the first result
|
||||||
|
$results = $part_repo->findBy(['ipn' => $input], limit: 1);
|
||||||
|
|
||||||
|
if (count($results) === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
//We found a part, so use it to create the result
|
||||||
|
$part = $results[0];
|
||||||
|
|
||||||
|
return new BarcodeScanResult(
|
||||||
|
target_type: LabelSupportedElement::PART,
|
||||||
|
target_id: $part->getID(),
|
||||||
|
source_type: BarcodeSourceType::IPN
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function tries to interpret the given barcode content as an internal barcode.
|
* This function tries to interpret the given barcode content as an internal barcode.
|
||||||
* If the barcode could not be parsed at all, null is returned. If the barcode is a valid format, but could
|
* If the barcode could not be parsed at all, null is returned. If the barcode is a valid format, but could
|
||||||
|
|
|
||||||
|
|
@ -30,4 +30,6 @@ enum BarcodeSourceType
|
||||||
{
|
{
|
||||||
/** This Barcode was generated using Part-DB internal recommended barcode generator */
|
/** This Barcode was generated using Part-DB internal recommended barcode generator */
|
||||||
case INTERNAL;
|
case INTERNAL;
|
||||||
|
/** This barcode is containing an internal part number (IPN) */
|
||||||
|
case IPN;
|
||||||
}
|
}
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
{% if entity.buildPart %}
|
{% if entity.buildPart %}
|
||||||
<span class="form-control-static"><a href="{{ entity_url(entity.buildPart) }}">{{ entity.buildPart.name }}</a></span>
|
<span class="form-control-static"><a href="{{ entity_url(entity.buildPart) }}">{{ entity.buildPart.name }}</a></span>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{{ path('part_new_build_part', {"project_id": entity.id , "_redirect": app.request.requestUri}) }}"
|
<a href="{{ path('part_new_build_part', {"project_id": entity.id , "_redirect": app.request.baseUrl ~ app.request.requestUri}) }}"
|
||||||
class="btn btn-outline-success">{% trans %}project.edit.associated_build_part.add{% endtrans %}</a>
|
class="btn btn-outline-success">{% trans %}project.edit.associated_build_part.add{% endtrans %}</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p class="text-muted">{% trans %}project.edit.associated_build.hint{% endtrans %}</p>
|
<p class="text-muted">{% trans %}project.edit.associated_build.hint{% endtrans %}</p>
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,8 @@
|
||||||
|
|
||||||
{% macro partsDatatableWithForm(datatable, state_save_tag = 'parts') %}
|
{% macro partsDatatableWithForm(datatable, state_save_tag = 'parts') %}
|
||||||
<form method="post" action="{{ path("table_action") }}"
|
<form method="post" action="{{ path("table_action") }}"
|
||||||
{{ stimulus_controller('elements/datatables/parts', {"stateSaveTag": state_save_tag}) }} data-dt-settings='{{ datatable_settings(datatable)|escape('html_attr') }}' data-dt-url="{{ app.request.requestUri }}"
|
{# The app.request.baseUrl here is important or it wont work behind a reverse proxy with subfolder #}
|
||||||
|
{{ stimulus_controller('elements/datatables/parts', {"stateSaveTag": state_save_tag}) }} data-dt-settings='{{ datatable_settings(datatable)|escape('html_attr') }}' data-dt-url="{{ app.request.baseUrl ~ app.request.requestUri }}"
|
||||||
{{ stimulus_action('elements/datatables/parts', 'confirmDeletionAtSubmit') }} data-delete-title="{% trans %}part_list.action.delete-title{% endtrans %}"
|
{{ stimulus_action('elements/datatables/parts', 'confirmDeletionAtSubmit') }} data-delete-title="{% trans %}part_list.action.delete-title{% endtrans %}"
|
||||||
data-delete-message="{% trans %}part_list.action.delete-message{% endtrans %}">
|
data-delete-message="{% trans %}part_list.action.delete-message{% endtrans %}">
|
||||||
<input type="hidden" name="_token" value="{{ csrf_token('table_action') }}">
|
<input type="hidden" name="_token" value="{{ csrf_token('table_action') }}">
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
{{ stimulus_controller('elements/delete_btn') }} {{ stimulus_action('elements/delete_btn', "submit", "submit") }}
|
{{ stimulus_controller('elements/delete_btn') }} {{ stimulus_action('elements/delete_btn', "submit", "submit") }}
|
||||||
data-delete-title="{% trans %}log.undo.confirm_title{% endtrans %}"
|
data-delete-title="{% trans %}log.undo.confirm_title{% endtrans %}"
|
||||||
data-delete-message="{% trans %}log.undo.confirm_message{% endtrans %}">
|
data-delete-message="{% trans %}log.undo.confirm_message{% endtrans %}">
|
||||||
<input type="hidden" name="redirect_back" value="{{ app.request.requestUri }}">
|
<input type="hidden" name="redirect_back" value="{{ app.request.baseUrl ~ app.request.requestUri }}">
|
||||||
|
|
||||||
{{ datatables.logDataTable(datatable, tag) }}
|
{{ datatables.logDataTable(datatable, tag) }}
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
data-delete-title="{% trans %}log.undo.confirm_title{% endtrans %}"
|
data-delete-title="{% trans %}log.undo.confirm_title{% endtrans %}"
|
||||||
data-delete-message="{% trans %}log.undo.confirm_message{% endtrans %}">
|
data-delete-message="{% trans %}log.undo.confirm_message{% endtrans %}">
|
||||||
|
|
||||||
<input type="hidden" name="redirect_back" value="{{ app.request.requestUri }}">
|
<input type="hidden" name="redirect_back" value="{{ app.request.baseUrl ~ app.request.requestUri }}">
|
||||||
|
|
||||||
<div class="btn-group btn-group-sm" role="group">
|
<div class="btn-group btn-group-sm" role="group">
|
||||||
<button type="submit" class="btn btn-outline-secondary" name="undo" value="{{ entry.id }}" {% if disabled %}disabled{% endif %}>
|
<button type="submit" class="btn btn-outline-secondary" name="undo" value="{{ entry.id }}" {% if disabled %}disabled{% endif %}>
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<a class="btn btn-success" {% if not is_granted('@projects.edit') %}disabled{% endif %}
|
<a class="btn btn-success" {% if not is_granted('@projects.edit') %}disabled{% endif %}
|
||||||
href="{{ path('project_add_parts_no_id', {"parts": part.id, "_redirect": app.request.requestUri}) }}">
|
href="{{ path('project_add_parts_no_id', {"parts": part.id, "_redirect": app.request.baseUrl ~ app.request.requestUri}) }}">
|
||||||
<i class="fa-solid fa-magnifying-glass-plus fa-fw"></i>
|
<i class="fa-solid fa-magnifying-glass-plus fa-fw"></i>
|
||||||
{% trans %}part.info.add_part_to_project{% endtrans %}
|
{% trans %}part.info.add_part_to_project{% endtrans %}
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
{{ dropdown.profile_dropdown('part', part.id) }}
|
{{ dropdown.profile_dropdown('part', part.id) }}
|
||||||
|
|
||||||
<a class="btn btn-success mt-2" {% if not is_granted('@projects.edit') %}disabled{% endif %}
|
<a class="btn btn-success mt-2" {% if not is_granted('@projects.edit') %}disabled{% endif %}
|
||||||
href="{{ path('project_add_parts_no_id', {"parts": part.id, "_redirect": app.request.requestUri}) }}">
|
href="{{ path('project_add_parts_no_id', {"parts": part.id, "_redirect": app.request.baseUrl ~ app.request.requestUri}) }}">
|
||||||
<i class="fa-solid fa-magnifying-glass-plus fa-fw"></i>
|
<i class="fa-solid fa-magnifying-glass-plus fa-fw"></i>
|
||||||
{% trans %}part.info.add_part_to_project{% endtrans %}
|
{% trans %}part.info.add_part_to_project{% endtrans %}
|
||||||
</a>
|
</a>
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
<input type="hidden" name="lot_id" value="">
|
<input type="hidden" name="lot_id" value="">
|
||||||
<input type="hidden" name="action" value="">
|
<input type="hidden" name="action" value="">
|
||||||
<input type="hidden" name="_csfr" value="{{ csrf_token('part_withraw' ~ part.iD) }}">
|
<input type="hidden" name="_csfr" value="{{ csrf_token('part_withraw' ~ part.iD) }}">
|
||||||
<input type="hidden" name="_redirect" value="{{ app.request.requestUri }}">
|
<input type="hidden" name="_redirect" value="{{ app.request.baseUrl ~ app.request.requestUri }}">
|
||||||
|
|
||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<label class="col-form-label col-sm-3">
|
<label class="col-form-label col-sm-3">
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<div class="btn-group mb-2 mt-2">
|
<div class="btn-group mb-2 mt-2">
|
||||||
<a class="btn btn-success" {% if not is_granted('@projects.edit') %}disabled{% endif %}
|
<a class="btn btn-success" {% if not is_granted('@projects.edit') %}disabled{% endif %}
|
||||||
href="{{ path('project_add_parts', {"id": project.id, "_redirect": app.request.requestUri}) }}">
|
href="{{ path('project_add_parts', {"id": project.id, "_redirect": app.request.baseUrl ~ app.request.requestUri}) }}">
|
||||||
<i class="fa-solid fa-square-plus fa-fw"></i>
|
<i class="fa-solid fa-square-plus fa-fw"></i>
|
||||||
{% trans %}project.info.bom_add_parts{% endtrans %}
|
{% trans %}project.info.bom_add_parts{% endtrans %}
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
<div class="input-group mb-3">
|
<div class="input-group mb-3">
|
||||||
<input type="number" min="1" class="form-control" placeholder="{% trans %}project.builds.number_of_builds{% endtrans %}" name="n" required>
|
<input type="number" min="1" class="form-control" placeholder="{% trans %}project.builds.number_of_builds{% endtrans %}" name="n" required>
|
||||||
<input type="hidden" name="_redirect" value="{{ app.request.requestUri }}">
|
<input type="hidden" name="_redirect" value="{{ app.request.baseUrl ~ app.request.requestUri }}">
|
||||||
<button class="btn btn-outline-secondary" type="submit" id="button-addon2">{% trans %}project.build.btn_build{% endtrans %}</button>
|
<button class="btn btn-outline-secondary" type="submit" id="button-addon2">{% trans %}project.build.btn_build{% endtrans %}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,10 @@ class BarcodeScanHelperTest extends WebTestCase
|
||||||
'00001236'];
|
'00001236'];
|
||||||
yield [new BarcodeScanResult(LabelSupportedElement::PART, 1_234_567, BarcodeSourceType::INTERNAL),
|
yield [new BarcodeScanResult(LabelSupportedElement::PART, 1_234_567, BarcodeSourceType::INTERNAL),
|
||||||
'12345678'];
|
'12345678'];
|
||||||
|
|
||||||
|
//Test IPN barcode
|
||||||
|
yield [new BarcodeScanResult(LabelSupportedElement::PART, 2, BarcodeSourceType::IPN),
|
||||||
|
'IPN123'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function invalidDataProvider(): array
|
public static function invalidDataProvider(): array
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -2,13 +2,13 @@
|
||||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en" trgLang="en">
|
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en" trgLang="en">
|
||||||
<file id="security.en">
|
<file id="security.en">
|
||||||
<unit id="aazoCks" name="user.login_error.user_disabled">
|
<unit id="aazoCks" name="user.login_error.user_disabled">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>user.login_error.user_disabled</source>
|
<source>user.login_error.user_disabled</source>
|
||||||
<target>Your account is disabled! Contact an administrator if you think this is wrong.</target>
|
<target>Your account is disabled! Contact an administrator if you think this is wrong.</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="Dpb9AmY" name="saml.error.cannot_login_local_user_per_saml">
|
<unit id="Dpb9AmY" name="saml.error.cannot_login_local_user_per_saml">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>saml.error.cannot_login_local_user_per_saml</source>
|
<source>saml.error.cannot_login_local_user_per_saml</source>
|
||||||
<target>You cannot login as local user via SSO! Use your local user password instead.</target>
|
<target>You cannot login as local user via SSO! Use your local user password instead.</target>
|
||||||
</segment>
|
</segment>
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
<note priority="1">Part-DB1\src\Entity\UserSystem\Group.php:0</note>
|
<note priority="1">Part-DB1\src\Entity\UserSystem\Group.php:0</note>
|
||||||
<note priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
|
<note priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
|
||||||
</notes>
|
</notes>
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>part.master_attachment.must_be_picture</source>
|
<source>part.master_attachment.must_be_picture</source>
|
||||||
<target>The preview attachment must be a valid picture!</target>
|
<target>The preview attachment must be a valid picture!</target>
|
||||||
</segment>
|
</segment>
|
||||||
|
|
@ -82,7 +82,7 @@
|
||||||
<note priority="1">src\Entity\StructuralDBElement.php:0</note>
|
<note priority="1">src\Entity\StructuralDBElement.php:0</note>
|
||||||
<note priority="1">src\Entity\Supplier.php:0</note>
|
<note priority="1">src\Entity\Supplier.php:0</note>
|
||||||
</notes>
|
</notes>
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>structural.entity.unique_name</source>
|
<source>structural.entity.unique_name</source>
|
||||||
<target>An element with this name already exists on this level!</target>
|
<target>An element with this name already exists on this level!</target>
|
||||||
</segment>
|
</segment>
|
||||||
|
|
@ -102,7 +102,7 @@
|
||||||
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\StorelocationParameter.php:0</note>
|
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\StorelocationParameter.php:0</note>
|
||||||
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\SupplierParameter.php:0</note>
|
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\SupplierParameter.php:0</note>
|
||||||
</notes>
|
</notes>
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>parameters.validator.min_lesser_typical</source>
|
<source>parameters.validator.min_lesser_typical</source>
|
||||||
<target>Value must be lesser or equal the the typical value ({{ compared_value }}).</target>
|
<target>Value must be lesser or equal the the typical value ({{ compared_value }}).</target>
|
||||||
</segment>
|
</segment>
|
||||||
|
|
@ -122,7 +122,7 @@
|
||||||
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\StorelocationParameter.php:0</note>
|
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\StorelocationParameter.php:0</note>
|
||||||
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\SupplierParameter.php:0</note>
|
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\SupplierParameter.php:0</note>
|
||||||
</notes>
|
</notes>
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>parameters.validator.min_lesser_max</source>
|
<source>parameters.validator.min_lesser_max</source>
|
||||||
<target>Value must be lesser than the maximum value ({{ compared_value }}).</target>
|
<target>Value must be lesser than the maximum value ({{ compared_value }}).</target>
|
||||||
</segment>
|
</segment>
|
||||||
|
|
@ -142,7 +142,7 @@
|
||||||
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\StorelocationParameter.php:0</note>
|
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\StorelocationParameter.php:0</note>
|
||||||
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\SupplierParameter.php:0</note>
|
<note category="file-source" priority="1">Part-DB1\src\Entity\Parameters\SupplierParameter.php:0</note>
|
||||||
</notes>
|
</notes>
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>parameters.validator.max_greater_typical</source>
|
<source>parameters.validator.max_greater_typical</source>
|
||||||
<target>Value must be greater or equal than the typical value ({{ compared_value }}).</target>
|
<target>Value must be greater or equal than the typical value ({{ compared_value }}).</target>
|
||||||
</segment>
|
</segment>
|
||||||
|
|
@ -152,7 +152,7 @@
|
||||||
<note category="file-source" priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
|
<note category="file-source" priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
|
||||||
<note priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
|
<note priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
|
||||||
</notes>
|
</notes>
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>validator.user.username_already_used</source>
|
<source>validator.user.username_already_used</source>
|
||||||
<target>A user with this name is already exisiting</target>
|
<target>A user with this name is already exisiting</target>
|
||||||
</segment>
|
</segment>
|
||||||
|
|
@ -162,7 +162,7 @@
|
||||||
<note category="file-source" priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
|
<note category="file-source" priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
|
||||||
<note priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
|
<note priority="1">Part-DB1\src\Entity\UserSystem\User.php:0</note>
|
||||||
</notes>
|
</notes>
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>user.invalid_username</source>
|
<source>user.invalid_username</source>
|
||||||
<target>The username must contain only letters, numbers, underscores, dots, pluses or minuses!</target>
|
<target>The username must contain only letters, numbers, underscores, dots, pluses or minuses!</target>
|
||||||
</segment>
|
</segment>
|
||||||
|
|
@ -171,7 +171,7 @@
|
||||||
<notes>
|
<notes>
|
||||||
<note category="state" priority="1">obsolete</note>
|
<note category="state" priority="1">obsolete</note>
|
||||||
</notes>
|
</notes>
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>validator.noneofitschild.self</source>
|
<source>validator.noneofitschild.self</source>
|
||||||
<target>An element can not be its own parent!</target>
|
<target>An element can not be its own parent!</target>
|
||||||
</segment>
|
</segment>
|
||||||
|
|
@ -180,139 +180,139 @@
|
||||||
<notes>
|
<notes>
|
||||||
<note category="state" priority="1">obsolete</note>
|
<note category="state" priority="1">obsolete</note>
|
||||||
</notes>
|
</notes>
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>validator.noneofitschild.children</source>
|
<source>validator.noneofitschild.children</source>
|
||||||
<target>You can not assign children element as parent (This would cause loops)!</target>
|
<target>You can not assign children element as parent (This would cause loops)!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="ayNr6QK" name="validator.select_valid_category">
|
<unit id="ayNr6QK" name="validator.select_valid_category">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>validator.select_valid_category</source>
|
<source>validator.select_valid_category</source>
|
||||||
<target>Please select a valid category!</target>
|
<target>Please select a valid category!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="6vIlN5q" name="validator.part_lot.only_existing">
|
<unit id="6vIlN5q" name="validator.part_lot.only_existing">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>validator.part_lot.only_existing</source>
|
<source>validator.part_lot.only_existing</source>
|
||||||
<target>Can not add new parts to this location as it is marked as "Only Existing"</target>
|
<target>Can not add new parts to this location as it is marked as "Only Existing"</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="3xoKOIS" name="validator.part_lot.location_full.no_increase">
|
<unit id="3xoKOIS" name="validator.part_lot.location_full.no_increase">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>validator.part_lot.location_full.no_increase</source>
|
<source>validator.part_lot.location_full.no_increase</source>
|
||||||
<target>Location is full. Amount can not be increased (new value must be smaller than {{ old_amount }}).</target>
|
<target>Location is full. Amount can not be increased (new value must be smaller than {{ old_amount }}).</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="R6Ov4Yt" name="validator.part_lot.location_full">
|
<unit id="R6Ov4Yt" name="validator.part_lot.location_full">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>validator.part_lot.location_full</source>
|
<source>validator.part_lot.location_full</source>
|
||||||
<target>Location is full. Can not add new parts to it.</target>
|
<target>Location is full. Can not add new parts to it.</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="BNQk2e7" name="validator.part_lot.single_part">
|
<unit id="BNQk2e7" name="validator.part_lot.single_part">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>validator.part_lot.single_part</source>
|
<source>validator.part_lot.single_part</source>
|
||||||
<target>This location can only contain a single part and it is already full!</target>
|
<target>This location can only contain a single part and it is already full!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="4gPskOG" name="validator.attachment.must_not_be_null">
|
<unit id="4gPskOG" name="validator.attachment.must_not_be_null">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>validator.attachment.must_not_be_null</source>
|
<source>validator.attachment.must_not_be_null</source>
|
||||||
<target>You must select an attachment type!</target>
|
<target>You must select an attachment type!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="cDDVrWT" name="validator.orderdetail.supplier_must_not_be_null">
|
<unit id="cDDVrWT" name="validator.orderdetail.supplier_must_not_be_null">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>validator.orderdetail.supplier_must_not_be_null</source>
|
<source>validator.orderdetail.supplier_must_not_be_null</source>
|
||||||
<target>You must select an supplier!</target>
|
<target>You must select an supplier!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="k5DDdB4" name="validator.measurement_unit.use_si_prefix_needs_unit">
|
<unit id="k5DDdB4" name="validator.measurement_unit.use_si_prefix_needs_unit">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>validator.measurement_unit.use_si_prefix_needs_unit</source>
|
<source>validator.measurement_unit.use_si_prefix_needs_unit</source>
|
||||||
<target>To enable SI prefixes, you have to set a unit symbol!</target>
|
<target>To enable SI prefixes, you have to set a unit symbol!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="DuzIOCr" name="part.ipn.must_be_unique">
|
<unit id="DuzIOCr" name="part.ipn.must_be_unique">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>part.ipn.must_be_unique</source>
|
<source>part.ipn.must_be_unique</source>
|
||||||
<target>The internal part number must be unique. {{ value }} is already in use!</target>
|
<target>The internal part number must be unique. {{ value }} is already in use!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="Z4Kuuo2" name="validator.project.bom_entry.name_or_part_needed">
|
<unit id="Z4Kuuo2" name="validator.project.bom_entry.name_or_part_needed">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>validator.project.bom_entry.name_or_part_needed</source>
|
<source>validator.project.bom_entry.name_or_part_needed</source>
|
||||||
<target>You have to choose a part for a part BOM entry or set a name for a non-part BOM entry.</target>
|
<target>You have to choose a part for a part BOM entry or set a name for a non-part BOM entry.</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="WF_v4ih" name="project.bom_entry.name_already_in_bom">
|
<unit id="WF_v4ih" name="project.bom_entry.name_already_in_bom">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>project.bom_entry.name_already_in_bom</source>
|
<source>project.bom_entry.name_already_in_bom</source>
|
||||||
<target>There is already an BOM entry with this name!</target>
|
<target>There is already an BOM entry with this name!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="5v4p85H" name="project.bom_entry.part_already_in_bom">
|
<unit id="5v4p85H" name="project.bom_entry.part_already_in_bom">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>project.bom_entry.part_already_in_bom</source>
|
<source>project.bom_entry.part_already_in_bom</source>
|
||||||
<target>This part already exists in the BOM!</target>
|
<target>This part already exists in the BOM!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="3lM32Tw" name="project.bom_entry.mountnames_quantity_mismatch">
|
<unit id="3lM32Tw" name="project.bom_entry.mountnames_quantity_mismatch">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>project.bom_entry.mountnames_quantity_mismatch</source>
|
<source>project.bom_entry.mountnames_quantity_mismatch</source>
|
||||||
<target>The number of mountnames has to match the BOMs quantity!</target>
|
<target>The number of mountnames has to match the BOMs quantity!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="x47D5WT" name="project.bom_entry.can_not_add_own_builds_part">
|
<unit id="x47D5WT" name="project.bom_entry.can_not_add_own_builds_part">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>project.bom_entry.can_not_add_own_builds_part</source>
|
<source>project.bom_entry.can_not_add_own_builds_part</source>
|
||||||
<target>You can not add a project's own builds part to the BOM.</target>
|
<target>You can not add a project's own builds part to the BOM.</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="2x2XDI_" name="project.bom_has_to_include_all_subelement_parts">
|
<unit id="2x2XDI_" name="project.bom_has_to_include_all_subelement_parts">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>project.bom_has_to_include_all_subelement_parts</source>
|
<source>project.bom_has_to_include_all_subelement_parts</source>
|
||||||
<target>The project BOM has to include all subprojects builds parts. Part %part_name% of project %project_name% missing!</target>
|
<target>The project BOM has to include all subprojects builds parts. Part %part_name% of project %project_name% missing!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="U9b1EzD" name="project.bom_entry.price_not_allowed_on_parts">
|
<unit id="U9b1EzD" name="project.bom_entry.price_not_allowed_on_parts">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>project.bom_entry.price_not_allowed_on_parts</source>
|
<source>project.bom_entry.price_not_allowed_on_parts</source>
|
||||||
<target>Prices are not allowed on BOM entries associated with a part. Define the price on the part instead.</target>
|
<target>Prices are not allowed on BOM entries associated with a part. Define the price on the part instead.</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="ID056SR" name="validator.project_build.lot_bigger_than_needed">
|
<unit id="ID056SR" name="validator.project_build.lot_bigger_than_needed">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>validator.project_build.lot_bigger_than_needed</source>
|
<source>validator.project_build.lot_bigger_than_needed</source>
|
||||||
<target>You have selected more quantity to withdraw than needed! Remove unnecessary quantity.</target>
|
<target>You have selected more quantity to withdraw than needed! Remove unnecessary quantity.</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="6hV5UqD" name="validator.project_build.lot_smaller_than_needed">
|
<unit id="6hV5UqD" name="validator.project_build.lot_smaller_than_needed">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>validator.project_build.lot_smaller_than_needed</source>
|
<source>validator.project_build.lot_smaller_than_needed</source>
|
||||||
<target>You have selected less quantity to withdraw than needed for the build! Add additional quantity.</target>
|
<target>You have selected less quantity to withdraw than needed for the build! Add additional quantity.</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="G9ZKt.4" name="part.name.must_match_category_regex">
|
<unit id="G9ZKt.4" name="part.name.must_match_category_regex">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>part.name.must_match_category_regex</source>
|
<source>part.name.must_match_category_regex</source>
|
||||||
<target>The part name does not match the regular expression stated by the category: %regex%</target>
|
<target>The part name does not match the regular expression stated by the category: %regex%</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="m8kMFhf" name="validator.attachment.name_not_blank">
|
<unit id="m8kMFhf" name="validator.attachment.name_not_blank">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>validator.attachment.name_not_blank</source>
|
<source>validator.attachment.name_not_blank</source>
|
||||||
<target>Set a value here, or upload a file to automatically use its filename as name for the attachment.</target>
|
<target>Set a value here, or upload a file to automatically use its filename as name for the attachment.</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="nwGaNBW" name="validator.part_lot.owner_must_match_storage_location_owner">
|
<unit id="nwGaNBW" name="validator.part_lot.owner_must_match_storage_location_owner">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>validator.part_lot.owner_must_match_storage_location_owner</source>
|
<source>validator.part_lot.owner_must_match_storage_location_owner</source>
|
||||||
<target>The owner of this lot must match the owner of the selected storage location (%owner_name%)!</target>
|
<target>The owner of this lot must match the owner of the selected storage location (%owner_name%)!</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
<unit id="HXSz3nQ" name="validator.part_lot.owner_must_not_be_anonymous">
|
<unit id="HXSz3nQ" name="validator.part_lot.owner_must_not_be_anonymous">
|
||||||
<segment state="translated">
|
<segment>
|
||||||
<source>validator.part_lot.owner_must_not_be_anonymous</source>
|
<source>validator.part_lot.owner_must_not_be_anonymous</source>
|
||||||
<target>A lot owner must not be the anonymous user!</target>
|
<target>A lot owner must not be the anonymous user!</target>
|
||||||
</segment>
|
</segment>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue