From 16c1f84eb3aff2150e79ccb832a4bf8121da29d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hmer?= Date: Fri, 17 Apr 2020 21:10:08 +0200 Subject: [PATCH] Added placeholders for Part lots. --- config/services.yaml | 7 +- .../ckeditor/plugins/partdb_label/lang/de.js | 8 ++ .../ckeditor/plugins/partdb_label/lang/en.js | 8 ++ .../ckeditor/plugins/partdb_label/plugin.js | 18 +++- .../PlaceholderProviders/PartLotProvider.php | 91 +++++++++++++++++++ .../LabelSystem/LabelTextReplacerTest.php | 15 +++ .../PartLotProviderTest.php | 83 +++++++++++++++++ 7 files changed, 226 insertions(+), 4 deletions(-) create mode 100644 src/Services/LabelSystem/PlaceholderProviders/PartLotProvider.php create mode 100644 tests/Services/LabelSystem/PlaceholderProviders/PartLotProviderTest.php diff --git a/config/services.yaml b/config/services.yaml index ef7c9f92..085217f5 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -174,4 +174,9 @@ services: App\Services\TranslationExtractor\PermissionExtractor: tags: - - { name: 'translation.extractor', alias: 'permissionExtractor'} \ No newline at end of file + - { name: 'translation.extractor', alias: 'permissionExtractor'} + + # PartLotProvider must be invoked before all other providers, so it can override %%NAME%% placeholder + App\Services\LabelSystem\PlaceholderProviders\PartLotProvider: + tags: + - { name: 'app.label_placeholder_provider', priority: 10} \ No newline at end of file diff --git a/public/ckeditor/plugins/partdb_label/lang/de.js b/public/ckeditor/plugins/partdb_label/lang/de.js index 27d22bf5..d7599ddf 100644 --- a/public/ckeditor/plugins/partdb_label/lang/de.js +++ b/public/ckeditor/plugins/partdb_label/lang/de.js @@ -22,6 +22,7 @@ CKEDITOR.plugins.setLang( 'partdb_label', 'de', { label: 'Platzhalter', 'section.global': 'Global', 'section.part': 'Bauteil', + 'section.part_lot': 'Bauteilbestand', 'part.id': 'Datenbank ID', 'part.name': 'Bauteilename', 'part.category': 'Kategorie', @@ -47,4 +48,11 @@ CKEDITOR.plugins.setLang( 'partdb_label', 'de', { 'global.time': 'Uhrzeit', 'global.install_name': 'Installationsname', 'global.type': 'Zieltyp', + 'lot.id': 'Lot ID', + 'lot.name': 'Lot Name', + 'lot.comment': 'Lot Kommentar', + 'lot.expiration_date': 'Ablaufdatum', + 'lot.amount': 'Bestandsmenge', + 'lot.location': 'Lagerort', + 'lot.location_full': 'Lagerort (Ganzer Pfad)', } ); \ No newline at end of file diff --git a/public/ckeditor/plugins/partdb_label/lang/en.js b/public/ckeditor/plugins/partdb_label/lang/en.js index c50bbae9..42aa3b85 100644 --- a/public/ckeditor/plugins/partdb_label/lang/en.js +++ b/public/ckeditor/plugins/partdb_label/lang/en.js @@ -22,6 +22,7 @@ CKEDITOR.plugins.setLang( 'partdb_label', 'en', { label: 'Placeholders', 'section.global': 'Globals', 'section.part': 'Part', + 'section.part_lot': 'Part lot', 'part.id': 'Database ID', 'part.name': 'Part name', 'part.category': 'Category', @@ -47,4 +48,11 @@ CKEDITOR.plugins.setLang( 'partdb_label', 'en', { 'global.time': 'Current time', 'global.install_name': 'Instance name', 'global.type': 'Target type', + 'lot.id': 'Lot ID', + 'lot.name': 'Lot name', + 'lot.comment': 'Lot comment', + 'lot.expiration_date': 'Expiration date', + 'lot.amount': 'Lot amount', + 'lot.location': 'Storage location', + 'lot.location_full': 'Storage location (Full path)', } ); \ No newline at end of file diff --git a/public/ckeditor/plugins/partdb_label/plugin.js b/public/ckeditor/plugins/partdb_label/plugin.js index b01b91b2..bfd58e48 100644 --- a/public/ckeditor/plugins/partdb_label/plugin.js +++ b/public/ckeditor/plugins/partdb_label/plugin.js @@ -24,9 +24,9 @@ const PLACEHOLDERS = { ['%%ID%%', 'part.id'], ['%%NAME%%', 'part.name'], ['%%CATEGORY%%', 'part.category'], - ['%%CATEGORY_FULL', 'part.category_full'], - ['%%MANUFACTURER', 'part.manufacturer'], - ['%%MANUFACTURER_FULL', 'part.manufacturer_full'], + ['%%CATEGORY_FULL%%', 'part.category_full'], + ['%%MANUFACTURER%%', 'part.manufacturer'], + ['%%MANUFACTURER_FULL%%', 'part.manufacturer_full'], ['%%FOOTPRINT%%', 'part.footprint'], ['%%FOOTPRINT_FULL%%', 'part.footprint'], ['%%MASS%%', 'part.mass'], @@ -41,6 +41,18 @@ const PLACEHOLDERS = { ['%%CREATION_DATE%%', 'part.creation_date'], ] }, + part_lot: { + label: 'section.part_lot', + entries: [ + ['%%LOT_ID%%', 'lot.id'], + ['%%LOT_NAME%%', 'lot.name'], + ['%%LOT_COMMENT%%', 'lot.comment'], + ['%%EXPIRATION_DATE%%', 'lot.expiration_date'], + ['%%AMOUNT%%', 'lot.amount'], + ['%%LOCATION%%', 'lot.location'], + ['%%LOCATION_FULL%%', 'lot.location_full'], + ] + }, global: { label: 'section.global', entries: [ diff --git a/src/Services/LabelSystem/PlaceholderProviders/PartLotProvider.php b/src/Services/LabelSystem/PlaceholderProviders/PartLotProvider.php new file mode 100644 index 00000000..394f1b26 --- /dev/null +++ b/src/Services/LabelSystem/PlaceholderProviders/PartLotProvider.php @@ -0,0 +1,91 @@ +. + */ + +namespace App\Services\LabelSystem\PlaceholderProviders; + + +use App\Entity\Parts\PartLot; +use App\Services\AmountFormatter; +use App\Services\LabelSystem\LabelTextReplacer; +use IntlDateFormatter; +use Locale; + +class PartLotProvider implements PlaceholderProviderInterface +{ + protected $labelTextReplacer; + protected $amountFormatter; + + public function __construct(LabelTextReplacer $labelTextReplacer, AmountFormatter $amountFormatter) + { + $this->labelTextReplacer = $labelTextReplacer; + $this->amountFormatter = $amountFormatter; + } + + public function replace(string $placeholder, object $label_target, array $options = []): ?string + { + if ($label_target instanceof PartLot) { + if ($placeholder === '%%LOT_ID%%') { + return $label_target->getID() ?? 'unknown'; + } + + if ($placeholder === '%%LOT_NAME%%') { + return $label_target->getName(); + } + + if ($placeholder === '%%LOT_COMMENT%%') { + return $label_target->getComment(); + } + + if ($placeholder === '%%EXPIRATION_DATE%%') { + if ($label_target->getExpirationDate() === null) { + return ''; + } + $formatter = IntlDateFormatter::create( + Locale::getDefault(), + IntlDateFormatter::SHORT, + IntlDateFormatter::NONE + //$label_target->getExpirationDate()->getTimezone() + ); + + return $formatter->format($label_target->getExpirationDate()); + } + + if ($placeholder === '%%AMOUNT%%') { + if ($label_target->isInstockUnknown()) { + return '?'; + } + return $this->amountFormatter->format($label_target->getAmount(), $label_target->getPart()->getPartUnit()); + } + + if ($placeholder === '%%LOCATION%%') { + return $label_target->getStorageLocation() ? $label_target->getStorageLocation()->getName() : ''; + } + + if ($placeholder === '%%LOCATION_FULL%%') { + return $label_target->getStorageLocation() ? $label_target->getStorageLocation()->getFullPath() : ''; + } + + + return $this->labelTextReplacer->handlePlaceholder($placeholder, $label_target->getPart()); + } + + return null; + } +} \ No newline at end of file diff --git a/tests/Services/LabelSystem/LabelTextReplacerTest.php b/tests/Services/LabelSystem/LabelTextReplacerTest.php index 4ff381c0..1e155e55 100644 --- a/tests/Services/LabelSystem/LabelTextReplacerTest.php +++ b/tests/Services/LabelSystem/LabelTextReplacerTest.php @@ -21,6 +21,7 @@ namespace App\Tests\Services\LabelSystem; use App\Entity\Parts\Part; +use App\Entity\Parts\PartLot; use App\Services\AmountFormatter; use App\Services\LabelSystem\LabelTextReplacer; use PHPUnit\Framework\TestCase; @@ -94,4 +95,18 @@ class LabelTextReplacerTest extends WebTestCase { $this->assertSame($expected, $this->service->replace($input, $this->target)); } + + /** + * Test if the part lot has the highest priority of all providers. + */ + public function testPartLotPriority(): void + { + $part_lot = new PartLot(); + $part_lot->setDescription('Test'); + $part = new Part(); + $part->setName('Part'); + $part_lot->setPart($part); + + $this->assertSame('Part', $this->service->handlePlaceholder('%%NAME%%', $part_lot)); + } } diff --git a/tests/Services/LabelSystem/PlaceholderProviders/PartLotProviderTest.php b/tests/Services/LabelSystem/PlaceholderProviders/PartLotProviderTest.php new file mode 100644 index 00000000..e18bdb06 --- /dev/null +++ b/tests/Services/LabelSystem/PlaceholderProviders/PartLotProviderTest.php @@ -0,0 +1,83 @@ +. + */ + +namespace App\Tests\Services\LabelSystem\PlaceholderProviders; + +use App\Entity\Contracts\NamedElementInterface; +use App\Entity\Parts\Part; +use App\Entity\Parts\PartLot; +use App\Entity\Parts\Storelocation; +use App\Services\LabelSystem\PlaceholderProviders\NamedElementProvider; +use App\Services\LabelSystem\PlaceholderProviders\PartLotProvider; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; + +class PartLotProviderTest extends WebTestCase +{ + /** @var PartLotProvider */ + protected $service; + + protected $target; + + public function setUp(): void + { + self::bootKernel(); + \Locale::setDefault('en'); + $this->service = self::$container->get(PartLotProvider::class); + $this->target = new PartLot(); + $this->target->setDescription('Lot description'); + $this->target->setComment('Lot comment'); + $this->target->setExpirationDate(new \DateTime('1999-04-13')); + $this->target->setInstockUnknown(true); + + $location = new Storelocation(); + $location->setName('Location'); + $location->setParent((new Storelocation())->setName('Parent')); + $this->target->setStorageLocation($location); + + $part = new Part(); + $part->setName('Part'); + $part->setDescription('Part description'); + $this->target->setPart($part); + } + + public function dataProvider(): array + { + return [ + ['unknown', '%%LOT_ID%%'], + ['Lot description', '%%LOT_NAME%%'], + ['Lot comment', '%%LOT_COMMENT%%'], + ['4/13/99', '%%EXPIRATION_DATE%%'], + ['?', '%%AMOUNT%%'], + ['Location', '%%LOCATION%%'], + ['Parent → Location', '%%LOCATION_FULL%%'], + //Test part inheritance + ['Part', '%%NAME%%'], + ['Part description', '%%DESCRIPTION%%'], + ]; + } + + /** + * @dataProvider dataProvider + */ + public function testReplace(string $expected, string $placeholder): void + { + $this->assertSame($expected, $this->service->replace($placeholder, $this->target)); + } +}