Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ bundled with Part-DB. Set `DATABASE_MYSQL_SSL_VERIFY_CERT` if you want to accept
* `TABLE_PARTS_DEFAULT_COLUMNS`: The columns in parts 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`, `ipn`, `description`, `category`, `footprint`, `manufacturer`, `storage_location`, `amount`, `minamount`, `partUnit`, `partCustomState`, `addedDate`, `lastModified`, `needs_review`, `favorite`, `manufacturing_status`, `manufacturer_product_number`, `mass`, `tags`, `attachments`, `edit`.
are: `name`, `id`, `ipn`, `description`, `category`, `footprint`, `manufacturer`, `storage_location`, `amount`, `supplier`, `supplier_part_number`, `minamount`, `partUnit`, `partCustomState`, `addedDate`, `lastModified`, `needs_review`, `favorite`, `manufacturing_status`, `manufacturer_product_number`, `mass`, `tags`, `attachments`, `edit`.

### History/Eventlog-related settings

Expand Down
56 changes: 56 additions & 0 deletions src/DataTables/Helpers/PartDataTableHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
namespace App\DataTables\Helpers;

use App\Entity\Parts\StorageLocation;
use App\Entity\Parts\Supplier;
use App\Entity\ProjectSystem\Project;
use App\Entity\Attachments\Attachment;
use App\Entity\Parts\Part;
Expand Down Expand Up @@ -118,6 +119,61 @@ public function renderStorageLocations(Part $context): string
return implode('<br>', $tmp);
}

/**
* Renders the names of all suppliers of this part (taken from its orderdetails), linked to their part lists.
* Each supplier is only listed once, even if the part has multiple orderdetails for it.
*/
public function renderSuppliers(Part $context): string
{
$tmp = [];
foreach ($context->getOrderdetails() as $orderdetail) {
$supplier = $orderdetail->getSupplier();
//Ignore orderdetails without supplier
if (!$supplier instanceof Supplier) {
continue;
}
$tmp[$supplier->getID()] = sprintf(
'<a href="%s" title="%s">%s</a>',
$this->entityURLGenerator->listPartsURL($supplier),
htmlspecialchars($this->pathCache->getFullPath($supplier)),
htmlspecialchars($supplier->getName())
);
}

return implode(', ', $tmp);
}

/**
* Renders the supplier part numbers of all orderdetails of this part. A number is linked to the product page of
* the supplier, if one is known.
*/
public function renderSupplierPartNumbers(Part $context): string
{
$tmp = [];
foreach ($context->getOrderdetails() as $orderdetail) {
$number = $orderdetail->getSupplierPartNr();
if ($number === '') {
continue;
}

$title = $orderdetail->getSupplier()?->getName() ?? '';
$url = $orderdetail->getSupplierProductUrl();
//The URL can be entered freely by users, so only link to real web addresses
if (preg_match('#^https?://#i', $url) === 1) {
$tmp[$number] = sprintf(
'<a href="%s" title="%s" target="_blank" rel="noopener">%s</a>',
htmlspecialchars($url),
htmlspecialchars($title),
htmlspecialchars($number)
);
} else {
$tmp[$number] ??= sprintf('<span title="%s">%s</span>', htmlspecialchars($title), htmlspecialchars($number));
}
}

return implode(', ', $tmp);
}

/**
* Renders an EDA/KiCad completeness indicator for the given part.
* Shows icons for symbol, footprint, and value status.
Expand Down
17 changes: 17 additions & 0 deletions src/DataTables/PartsDataTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,21 @@ public function configure(DataTable $dataTable, array $options): void
'orderable' => false,
'data' => fn(Part $context) => $this->partDataTableHelper->renderSupplierAvailableAmount($context),
])
->add('supplier', HTMLColumn::class, [
'label' => $this->translator->trans('part.table.supplier'),
//A part can have many suppliers, so we sort by the first one (see storelocation above). The leading
//expression keeps the parts without any supplier at the end, regardless of the sort direction and
//of how the DBMS orders NULLs (the direction is only appended to the last expression).
'orderField' => 'CASE WHEN MIN(_suppliers.name) IS NULL THEN 1 ELSE 0 END, NATSORT(MIN(_suppliers.name))',
'data' => fn(Part $context) => $this->partDataTableHelper->renderSuppliers($context),
])
->add('supplier_part_number', HTMLColumn::class, [
'label' => $this->translator->trans('part.table.supplier_part_number'),
//Same as for the supplier column. Empty supplier part numbers are treated like missing ones.
'orderField' => 'CASE WHEN MIN(NULLIF(_orderdetails.supplierpartnr, \'\')) IS NULL THEN 1 ELSE 0 END, '
. 'NATSORT(MIN(NULLIF(_orderdetails.supplierpartnr, \'\')))',
'data' => fn(Part $context) => $this->partDataTableHelper->renderSupplierPartNumbers($context),
])
->add('minamount', TextColumn::class, [
'label' => $this->translator->trans('part.table.minamount'),
'data' => fn(Part $context, $value): string => $this->amountFormatter->format(
Expand Down Expand Up @@ -370,6 +385,7 @@ private function getDetailQuery(QueryBuilder $builder, array $filter_results): v
->addSelect('footprint_attachment')
->addSelect('partLots')
->addSelect('orderdetails')
->addSelect('suppliers')
->addSelect('attachments')
->addSelect('storelocations')
->addSelect('projectBomEntries')
Expand All @@ -388,6 +404,7 @@ private function getDetailQuery(QueryBuilder $builder, array $filter_results): v
->leftJoin('footprint.master_picture_attachment', 'footprint_attachment')
->leftJoin('part.manufacturer', 'manufacturer')
->leftJoin('part.orderdetails', 'orderdetails')
->leftJoin('orderdetails.supplier', 'suppliers')
->leftJoin('part.attachments', 'attachments')
->leftJoin('part.partUnit', 'partUnit')
->leftJoin('part.partCustomState', 'partCustomState')
Expand Down
2 changes: 2 additions & 0 deletions src/Settings/BehaviorSettings/PartTableColumns.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ enum PartTableColumns : string implements TranslatableInterface
case LOCATION = "storage_location";
case AMOUNT = "amount";
case SUPPLIER_AVAILABLE_AMOUNT = "supplier_available_amount";
case SUPPLIER = "supplier";
case SUPPLIER_PART_NUMBER = "supplier_part_number";
case MIN_AMOUNT = "minamount";
case PART_UNIT = "partUnit";
case ADDED_DATE = "addedDate";
Expand Down
12 changes: 12 additions & 0 deletions translations/messages.en.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -15926,5 +15926,17 @@ Buerklin-API Authentication server:
<target>This info provider has to throttle its requests heavily or needs a lot of processing time, so requests can take a while.</target>
</segment>
</unit>
<unit id="xxOseQB" name="part.table.supplier">
<segment state="translated">
<source>part.table.supplier</source>
<target>Supplier</target>
</segment>
</unit>
<unit id="1AS7MVG" name="part.table.supplier_part_number">
<segment state="translated">
<source>part.table.supplier_part_number</source>
<target>Supplier part number</target>
</segment>
</unit>
</file>
</xliff>
Loading