Merge branch 'gtin'

This commit is contained in:
Jan Böhmer 2026-02-14 22:12:39 +01:00
commit 7a83581597
71 changed files with 1405 additions and 92 deletions

View file

@ -23,6 +23,8 @@ declare(strict_types=1);
namespace App\Tests\Entity\Attachments;
use App\Entity\Attachments\AttachmentType;
use App\Entity\Attachments\PartAttachment;
use App\Entity\Attachments\UserAttachment;
use Doctrine\Common\Collections\Collection;
use PHPUnit\Framework\TestCase;
@ -34,4 +36,51 @@ class AttachmentTypeTest extends TestCase
$this->assertInstanceOf(Collection::class, $attachment_type->getAttachmentsForType());
$this->assertEmpty($attachment_type->getFiletypeFilter());
}
public function testSetAllowedTargets(): void
{
$attachmentType = new AttachmentType();
$this->expectException(\InvalidArgumentException::class);
$attachmentType->setAllowedTargets(['target1', 'target2']);
}
public function testGetSetAllowedTargets(): void
{
$attachmentType = new AttachmentType();
$attachmentType->setAllowedTargets([PartAttachment::class, UserAttachment::class]);
$this->assertSame([PartAttachment::class, UserAttachment::class], $attachmentType->getAllowedTargets());
//Caching should also work
$this->assertSame([PartAttachment::class, UserAttachment::class], $attachmentType->getAllowedTargets());
//Setting null should reset the allowed targets
$attachmentType->setAllowedTargets(null);
$this->assertNull($attachmentType->getAllowedTargets());
}
public function testIsAllowedForTarget(): void
{
$attachmentType = new AttachmentType();
//By default, all targets should be allowed
$this->assertTrue($attachmentType->isAllowedForTarget(PartAttachment::class));
$this->assertTrue($attachmentType->isAllowedForTarget(UserAttachment::class));
//Set specific allowed targets
$attachmentType->setAllowedTargets([PartAttachment::class]);
$this->assertTrue($attachmentType->isAllowedForTarget(PartAttachment::class));
$this->assertFalse($attachmentType->isAllowedForTarget(UserAttachment::class));
//Set both targets
$attachmentType->setAllowedTargets([PartAttachment::class, UserAttachment::class]);
$this->assertTrue($attachmentType->isAllowedForTarget(PartAttachment::class));
$this->assertTrue($attachmentType->isAllowedForTarget(UserAttachment::class));
//Reset allowed targets
$attachmentType->setAllowedTargets(null);
$this->assertTrue($attachmentType->isAllowedForTarget(PartAttachment::class));
$this->assertTrue($attachmentType->isAllowedForTarget(UserAttachment::class));
}
}

View file

@ -61,4 +61,18 @@ class OrderdetailTest extends TestCase
$this->assertSame($price5, $orderdetail->findPriceForQty(5.3));
$this->assertSame($price5, $orderdetail->findPriceForQty(10000));
}
public function testGetSetPricesIncludesVAT(): void
{
$orderdetail = new Orderdetail();
//By default, the pricesIncludesVAT property should be null for empty orderdetails
$this->assertNull($orderdetail->getPricesIncludesVAT());
$orderdetail->setPricesIncludesVAT(true);
$this->assertTrue($orderdetail->getPricesIncludesVAT());
$orderdetail->setPricesIncludesVAT(false);
$this->assertFalse($orderdetail->getPricesIncludesVAT());
}
}

View file

@ -108,6 +108,7 @@ class BulkSearchResponseDTOTest extends KernelTestCase
'manufacturing_status' => NULL,
'provider_url' => NULL,
'footprint' => NULL,
'gtin' => NULL,
),
'source_field' => 'mpn',
'source_keyword' => '1234',
@ -129,6 +130,7 @@ class BulkSearchResponseDTOTest extends KernelTestCase
'manufacturing_status' => NULL,
'provider_url' => NULL,
'footprint' => NULL,
'gtin' => NULL,
),
'source_field' => 'name',
'source_keyword' => '1234',

View file

@ -22,6 +22,7 @@ declare(strict_types=1);
*/
namespace App\Tests\Services\InfoProviderSystem\DTOs;
use App\Services\InfoProviderSystem\DTOs\PriceDTO;
use App\Services\InfoProviderSystem\DTOs\PurchaseInfoDTO;
use PHPUnit\Framework\TestCase;
@ -33,4 +34,40 @@ class PurchaseInfoDTOTest extends TestCase
$this->expectExceptionMessage('The prices array must only contain PriceDTO instances');
new PurchaseInfoDTO('test', 'test', [new \stdClass()]);
}
public function testPricesIncludesVATHandling(): void
{
$pricesTrue = [
new PriceDTO(minimum_discount_amount: 1, price: '10.00', currency_iso_code: 'USD', includes_tax: true),
new PriceDTO(minimum_discount_amount: 5, price: '9.00', currency_iso_code: 'USD', includes_tax: true),
];
$pricesFalse = [
new PriceDTO(minimum_discount_amount: 1, price: '10.00', currency_iso_code: 'USD', includes_tax: false),
new PriceDTO(minimum_discount_amount: 5, price: '9.00', currency_iso_code: 'USD', includes_tax: false),
];
$pricesMixed = [
new PriceDTO(minimum_discount_amount: 1, price: '10.00', currency_iso_code: 'USD', includes_tax: true),
new PriceDTO(minimum_discount_amount: 5, price: '9.00', currency_iso_code: 'USD', includes_tax: false),
];
$pricesNull = [
new PriceDTO(minimum_discount_amount: 1, price: '10.00', currency_iso_code: 'USD', includes_tax: null),
new PriceDTO(minimum_discount_amount: 5, price: '9.00', currency_iso_code: 'USD', includes_tax: null),
];
//If the prices_include_vat parameter is given, use it:
$dto = new PurchaseInfoDTO('test', 'test', $pricesMixed, prices_include_vat: true);
$this->assertTrue($dto->prices_include_vat);
$dto = new PurchaseInfoDTO('test', 'test', $pricesMixed, prices_include_vat: false);
$this->assertFalse($dto->prices_include_vat);
//If the prices_include_vat parameter is not given, try to deduct it from the prices:
$dto = new PurchaseInfoDTO('test', 'test', $pricesTrue);
$this->assertTrue($dto->prices_include_vat);
$dto = new PurchaseInfoDTO('test', 'test', $pricesFalse);
$this->assertFalse($dto->prices_include_vat);
$dto = new PurchaseInfoDTO('test', 'test', $pricesMixed);
$this->assertNull($dto->prices_include_vat);
$dto = new PurchaseInfoDTO('test', 'test', $pricesNull);
$this->assertNull($dto->prices_include_vat);
}
}

View file

@ -94,7 +94,6 @@ class DTOtoEntityConverterTest extends WebTestCase
minimum_discount_amount: 5,
price: "10.0",
currency_iso_code: 'EUR',
includes_tax: true,
);
$entity = $this->service->convertPrice($dto);
@ -115,6 +114,7 @@ class DTOtoEntityConverterTest extends WebTestCase
order_number: 'TestOrderNumber',
prices: $prices,
product_url: 'https://example.com',
prices_include_vat: true,
);
$entity = $this->service->convertPurchaseInfo($dto);
@ -122,6 +122,7 @@ class DTOtoEntityConverterTest extends WebTestCase
$this->assertSame($dto->distributor_name, $entity->getSupplier()->getName());
$this->assertSame($dto->order_number, $entity->getSupplierPartNr());
$this->assertEquals($dto->product_url, $entity->getSupplierProductUrl());
$this->assertTrue($dto->prices_include_vat);
}
public function testConvertFileWithName(): void
@ -159,12 +160,13 @@ class DTOtoEntityConverterTest extends WebTestCase
$shopping_infos = [new PurchaseInfoDTO('TestDistributor', 'TestOrderNumber', [new PriceDTO(1, "10.0", 'EUR')])];
$dto = new PartDetailDTO(
provider_key: 'test_provider', provider_id: 'test_id', provider_url: 'https://invalid.invalid/test_id',
name: 'TestPart', description: 'TestDescription', category: 'TestCategory',
manufacturer: 'TestManufacturer', mpn: 'TestMPN', manufacturing_status: ManufacturingStatus::EOL,
preview_image_url: 'https://invalid.invalid/image.png',
footprint: 'DIP8', notes: 'TestNotes', mass: 10.4,
parameters: $parameters, datasheets: $datasheets, vendor_infos: $shopping_infos, images: $images
provider_key: 'test_provider', provider_id: 'test_id', name: 'TestPart',
description: 'TestDescription', category: 'TestCategory', manufacturer: 'TestManufacturer',
mpn: 'TestMPN', preview_image_url: 'https://invalid.invalid/image.png',
manufacturing_status: ManufacturingStatus::EOL,
provider_url: 'https://invalid.invalid/test_id',
footprint: 'DIP8', gtin: "1234567890123", notes: 'TestNotes', datasheets: $datasheets,
images: $images, parameters: $parameters, vendor_infos: $shopping_infos, mass: 10.4
);
$entity = $this->service->convertPart($dto);
@ -180,6 +182,8 @@ class DTOtoEntityConverterTest extends WebTestCase
$this->assertEquals($dto->mass, $entity->getMass());
$this->assertEquals($dto->footprint, $entity->getFootprint());
$this->assertEquals($dto->gtin, $entity->getGtin());
//We just check that the lenghts of parameters, datasheets, images and shopping infos are the same
//The actual content is tested in the corresponding tests
$this->assertCount(count($parameters), $entity->getParameters());

View file

@ -154,4 +154,19 @@ class PartLotWithdrawAddHelperTest extends WebTestCase
$this->assertEqualsWithDelta(5.0, $this->partLot2->getAmount(), PHP_FLOAT_EPSILON);
$this->assertEqualsWithDelta(2.0, $this->partLot3->getAmount(), PHP_FLOAT_EPSILON);
}
public function testStocktake(): void
{
//Stocktake lot 1 to 20
$this->service->stocktake($this->partLot1, 20, "Test");
$this->assertEqualsWithDelta(20.0, $this->partLot1->getAmount(), PHP_FLOAT_EPSILON);
$this->assertNotNull($this->partLot1->getLastStocktakeAt()); //Stocktake date should be set
//Stocktake lot 2 to 5
$this->partLot2->setInstockUnknown(true);
$this->service->stocktake($this->partLot2, 0, "Test");
$this->assertEqualsWithDelta(0.0, $this->partLot2->getAmount(), PHP_FLOAT_EPSILON);
$this->assertFalse($this->partLot2->isInstockUnknown()); //Instock unknown should be cleared
}
}

View file

@ -0,0 +1,72 @@
<?php
/*
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
*
* Copyright (C) 2019 - 2026 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\Tests\Validator\Constraints;
use App\Validator\Constraints\ValidGTINValidator;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Validator\ConstraintValidatorInterface;
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;
class ValidGTINValidatorTest extends ConstraintValidatorTestCase
{
public function testAllowNull(): void
{
$this->validator->validate(null, new \App\Validator\Constraints\ValidGTIN());
$this->assertNoViolation();
}
public function testValidGTIN8(): void
{
$this->validator->validate('12345670', new \App\Validator\Constraints\ValidGTIN());
$this->assertNoViolation();
}
public function testValidGTIN12(): void
{
$this->validator->validate('123456789012', new \App\Validator\Constraints\ValidGTIN());
$this->assertNoViolation();
}
public function testValidGTIN13(): void
{
$this->validator->validate('1234567890128', new \App\Validator\Constraints\ValidGTIN());
$this->assertNoViolation();
}
public function testValidGTIN14(): void
{
$this->validator->validate('12345678901231', new \App\Validator\Constraints\ValidGTIN());
$this->assertNoViolation();
}
public function testInvalidGTIN(): void
{
$this->validator->validate('1234567890123', new \App\Validator\Constraints\ValidGTIN());
$this->buildViolation('validator.invalid_gtin')
->assertRaised();
}
protected function createValidator(): ConstraintValidatorInterface
{
return new ValidGTINValidator();
}
}