Compare commits

...

23 commits

Author SHA1 Message Date
github-actions[bot]
ae6ef6200d Update KiCad symbols and footprints lists
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
Docker Image Build / merge (push) Has been cancelled
Docker Image Build (FrankenPHP) / merge (push) Has been cancelled
2026-03-30 04:51:34 +00:00
Albert Koczy
991daf0ead
Implement parsing of TME QR codes (#1324)
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
Docker Image Build / merge (push) Has been cancelled
Docker Image Build (FrankenPHP) / merge (push) Has been cancelled
* Implement parsing of TME QR codes

They are present on parts purchased on tme.eu. It's based on the LCSC
parser. Some older codes I found are in upper-case so I handle those
too.

* Removed unused method

* Fixed translation message keys

* Try to find TME part via SPN

---------

Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-29 14:53:31 +02:00
Jan Böhmer
34a84bce8f Updated depedencies
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
Docker Image Build / merge (push) Has been cancelled
Docker Image Build (FrankenPHP) / merge (push) Has been cancelled
2026-03-27 23:27:03 +01:00
Marc
4206b702ff
Made EIGP114 parsing less strict (#1321)
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
Docker Image Build / merge (push) Has been cancelled
Docker Image Build (FrankenPHP) / merge (push) Has been cancelled
* Enhance barcode format checking in isFormat06Code

Updated isFormat06Code method to handle additional barcode formats for compatibility with older Mouser parts and Eyoyo barcode scanners that don't omit the record separator character

* Added tests

---------

Co-authored-by: Jan Böhmer <mail@jan-boehmer.de>
2026-03-24 21:33:41 +01:00
Jan Böhmer
abf0ba5301 Updated dependencies 2026-03-24 20:43:50 +01:00
Jan Böhmer
9ce215c8f9 Added tests for custom doctrine functions
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
Docker Image Build / merge (push) Has been cancelled
Docker Image Build (FrankenPHP) / merge (push) Has been cancelled
2026-03-22 21:50:15 +01:00
Jan Böhmer
753ecee849 Merge remote-tracking branch 'origin/master'
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
Docker Image Build / merge (push) Has been cancelled
Docker Image Build (FrankenPHP) / merge (push) Has been cancelled
2026-03-15 22:09:22 +01:00
Jan Böhmer
8f6ed74d93 Bumped version to 2.9.1 2026-03-15 22:09:10 +01:00
Jan Böhmer
17f11c02f3
New Crowdin updates (#1301)
* New translations validators.en.xlf (Chinese Simplified)

* New translations messages.en.xlf (English)

* New translations messages.en.xlf (German)
2026-03-15 22:08:38 +01:00
Jan Böhmer
a070ebb2ce Fixed 500 error with displaying part prices, when a user has a currency preference different of base currency, and there is no conversion rate known for it
This fixes issue #1317
2026-03-15 22:02:10 +01:00
Jan Böhmer
44bb132de1 Merge remote-tracking branch 'origin/master' 2026-03-15 21:47:21 +01:00
Jan Böhmer
95f3fc66c2 Do not throw an 500 error, if mapping is not possible
This fixes issue #1298
2026-03-15 21:47:15 +01:00
Jan Böhmer
74e5102943 Automatically detect the delimiter of generic BOM imports
The detectFields does this anyway, so use that guessed value further on
2026-03-15 21:35:38 +01:00
swdee
60c5e24c94
Bug fix: Remove fallback from LCSC barcode part resolver (#1302)
Some checks are pending
Build assets artifact / Build assets artifact (push) Waiting to run
Docker Image Build / build (linux/amd64, amd64, ubuntu-latest) (push) Waiting to run
Docker Image Build / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Waiting to run
Docker Image Build / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Waiting to run
Docker Image Build / merge (push) Blocked by required conditions
Docker Image Build (FrankenPHP) / build (linux/amd64, amd64, ubuntu-latest) (push) Waiting to run
Docker Image Build (FrankenPHP) / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Waiting to run
Docker Image Build (FrankenPHP) / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Waiting to run
Docker Image Build (FrankenPHP) / merge (push) Blocked by required conditions
Static analysis / Static analysis (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Waiting to run
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Waiting to run
2026-03-15 18:57:54 +01:00
Jan Böhmer
de371877b9 Make GenericWebProvider more forgiving with URLs and accept the "fixed" strings traefik provides as security measure
This fixes issue #1296
2026-03-15 18:55:16 +01:00
Jan Böhmer
baeef1228a updated dependencies 2026-03-15 15:06:24 +01:00
Jan Böhmer
45da6dacff
Update KiCad symbols and footprints lists (#1303)
Some checks failed
Build assets artifact / Build assets artifact (push) Has been cancelled
Docker Image Build / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/amd64, amd64, ubuntu-latest) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm/v7, armv7, ubuntu-24.04-arm) (push) Has been cancelled
Docker Image Build (FrankenPHP) / build (linux/arm64, arm64, ubuntu-24.04-arm) (push) Has been cancelled
Static analysis / Static analysis (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, mysql) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, postgres) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.2, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.3, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.4, sqlite) (push) Has been cancelled
PHPUnit Tests / PHPUnit and coverage Test (PHP 8.5, sqlite) (push) Has been cancelled
Docker Image Build / merge (push) Has been cancelled
Docker Image Build (FrankenPHP) / merge (push) Has been cancelled
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-11 11:28:23 +01:00
Moritz Wörmann
c4d8192e76
add data-tube=false to SAML auth button (#1308) 2026-03-11 11:28:09 +01:00
dependabot[bot]
dca0cb8a16
Bump docker/setup-buildx-action from 3 to 4 (#1309)
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3 to 4.
- [Release notes](https://github.com/docker/setup-buildx-action/releases)
- [Commits](https://github.com/docker/setup-buildx-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/setup-buildx-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-11 11:15:36 +01:00
dependabot[bot]
3abc0d8b38
Bump docker/build-push-action from 6 to 7 (#1311)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6 to 7.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v6...v7)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-11 11:15:20 +01:00
dependabot[bot]
9ea3ead246
Bump docker/login-action from 3 to 4 (#1310)
Bumps [docker/login-action](https://github.com/docker/login-action) from 3 to 4.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/v3...v4)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-11 11:12:27 +01:00
dependabot[bot]
1de440d71e
Bump docker/metadata-action from 5 to 6 (#1312)
Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 5 to 6.
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Commits](https://github.com/docker/metadata-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: docker/metadata-action
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-11 11:08:29 +01:00
dependabot[bot]
5243f90dd8
Bump web-auth/webauthn-symfony-bundle from 5.2.3 to 5.2.4 (#1313)
Bumps [web-auth/webauthn-symfony-bundle](https://github.com/web-auth/webauthn-symfony-bundle) from 5.2.3 to 5.2.4.
- [Commits](https://github.com/web-auth/webauthn-symfony-bundle/compare/5.2.3...5.2.4)

---
updated-dependencies:
- dependency-name: web-auth/webauthn-symfony-bundle
  dependency-version: 5.2.4
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-11 11:07:56 +01:00
31 changed files with 2198 additions and 1276 deletions

View file

@ -36,7 +36,7 @@ jobs:
-
name: Docker meta
id: docker_meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
# list of Docker images to use as base name for tags
images: |
@ -66,11 +66,11 @@ jobs:
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
-
name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
@ -78,7 +78,7 @@ jobs:
-
name: Build and push by digest
id: build
uses: docker/build-push-action@v6
uses: docker/build-push-action@v7
with:
context: .
platforms: ${{ matrix.platform }}
@ -121,12 +121,12 @@ jobs:
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
-
name: Docker meta
id: docker_meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
images: |
jbtronics/part-db1
@ -142,7 +142,7 @@ jobs:
-
name: Login to DockerHub
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

View file

@ -36,7 +36,7 @@ jobs:
-
name: Docker meta
id: docker_meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
# list of Docker images to use as base name for tags
images: |
@ -66,11 +66,11 @@ jobs:
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
-
name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
@ -78,7 +78,7 @@ jobs:
-
name: Build and push by digest
id: build
uses: docker/build-push-action@v6
uses: docker/build-push-action@v7
with:
context: .
file: Dockerfile-frankenphp
@ -122,12 +122,12 @@ jobs:
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
-
name: Docker meta
id: docker_meta
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
images: |
partdborg/part-db
@ -143,7 +143,7 @@ jobs:
-
name: Login to DockerHub
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

View file

@ -1 +1 @@
2.9.0
2.9.1

795
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1712,7 +1712,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* length?: scalar|Param|null, // Default: 5
* width?: scalar|Param|null, // Default: 130
* height?: scalar|Param|null, // Default: 50
* font?: scalar|Param|null, // Default: "C:\\Users\\mail\\Documents\\PHP\\Part-DB-server\\vendor\\gregwar\\captcha-bundle\\DependencyInjection/../Generator/Font/captcha.ttf"
* font?: scalar|Param|null, // Default: "E:\\PHP\\Part-DB-server\\vendor\\gregwar\\captcha-bundle\\DependencyInjection/../Generator/Font/captcha.ttf"
* keep_value?: scalar|Param|null, // Default: false
* charset?: scalar|Param|null, // Default: "abcdefhjkmnprstuvwxyz23456789"
* as_file?: scalar|Param|null, // Default: false
@ -2390,6 +2390,9 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* serialize_payload_fields?: mixed, // Set to null to serialize all payload fields when a validation error is thrown, or set the fields you want to include explicitly. // Default: []
* query_parameter_validation?: bool|Param, // Deprecated: Will be removed in API Platform 5.0. // Default: true
* },
* jsonapi?: array{
* use_iri_as_id?: bool|Param, // Set to false to use entity identifiers instead of IRIs as the "id" field in JSON:API responses. // Default: true
* },
* eager_loading?: bool|array{
* enabled?: bool|Param, // Default: true
* fetch_partial?: bool|Param, // Fetch only partial data according to serialization groups. If enabled, Doctrine ORM entities will not work as expected if any of the other fields are used. // Default: false
@ -2401,11 +2404,12 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* enable_json_streamer?: bool|Param, // Enable json streamer. // Default: false
* enable_swagger_ui?: bool|Param, // Enable Swagger UI // Default: true
* enable_re_doc?: bool|Param, // Enable ReDoc // Default: true
* enable_scalar?: bool|Param, // Enable Scalar API Reference // Default: true
* enable_entrypoint?: bool|Param, // Enable the entrypoint // Default: true
* enable_docs?: bool|Param, // Enable the docs // Default: true
* enable_profiler?: bool|Param, // Enable the data collector and the WebProfilerBundle integration. // Default: true
* enable_phpdoc_parser?: bool|Param, // Enable resource metadata collector using PHPStan PhpDocParser. // Default: true
* enable_link_security?: bool|Param, // Enable security for Links (sub resources) // Default: false
* enable_link_security?: bool|Param, // Deprecated: This option is always enabled and will be removed in API Platform 5.0. // Enable security for Links (sub resources). // Default: true
* collection?: array{
* exists_parameter_name?: scalar|Param|null, // The name of the query parameter to filter on nullable field values. // Default: "exists"
* order?: scalar|Param|null, // The default order of results. // Default: "ASC"
@ -2489,7 +2493,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* max_header_length?: int|Param, // Max header length supported by the cache server. // Default: 7500
* request_options?: mixed, // To pass options to the client charged with the request. // Default: []
* purger?: scalar|Param|null, // Specify a purger to use (available values: "api_platform.http_cache.purger.varnish.ban", "api_platform.http_cache.purger.varnish.xkey", "api_platform.http_cache.purger.souin"). // Default: "api_platform.http_cache.purger.varnish"
* xkey?: array{ // Deprecated: The "xkey" configuration is deprecated, use your own purger to customize surrogate keys or the appropriate paramters.
* xkey?: array{ // Deprecated: The "xkey" configuration is deprecated, use your own purger to customize surrogate keys or the appropriate parameters.
* glue?: scalar|Param|null, // xkey glue between keys // Default: " "
* },
* },
@ -2505,6 +2509,9 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* elasticsearch?: bool|array{
* enabled?: bool|Param, // Default: false
* hosts?: list<scalar|Param|null>,
* ssl_ca_bundle?: scalar|Param|null, // Path to the SSL CA bundle file for Elasticsearch SSL verification. // Default: null
* ssl_verification?: bool|Param, // Enable or disable SSL verification for Elasticsearch connections. // Default: true
* client?: "elasticsearch"|"opensearch"|Param, // The search engine client to use: "elasticsearch" or "opensearch". // Default: "elasticsearch"
* },
* openapi?: array{
* contact?: array{
@ -2523,12 +2530,18 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* identifier?: scalar|Param|null, // An SPDX license expression for the API. The identifier field is mutually exclusive of the url field. // Default: null
* },
* swagger_ui_extra_configuration?: mixed, // To pass extra configuration to Swagger UI, like docExpansion or filter. // Default: []
* scalar_extra_configuration?: mixed, // To pass extra configuration to Scalar API Reference, like theme or darkMode. // Default: []
* overrideResponses?: bool|Param, // Whether API Platform adds automatic responses to the OpenAPI documentation. // Default: true
* error_resource_class?: scalar|Param|null, // The class used to represent errors in the OpenAPI documentation. // Default: null
* validation_error_resource_class?: scalar|Param|null, // The class used to represent validation errors in the OpenAPI documentation. // Default: null
* },
* maker?: bool|array{
* enabled?: bool|Param, // Default: true
* namespace_prefix?: scalar|Param|null, // Add a prefix to all maker generated classes. e.g set it to "Api" to set the maker namespace to "App\Api\" (if the maker.root_namespace config is App). e.g. App\Api\State\MyStateProcessor // Default: ""
* },
* mcp?: bool|array{
* enabled?: bool|Param, // Default: true
* format?: scalar|Param|null, // The serialization format used for MCP tool input/output. Must be a format registered in api_platform.formats (e.g. "jsonld", "json", "jsonapi"). // Default: "jsonld"
* },
* exception_to_status?: array<string, int|Param>,
* formats?: array<string, array{ // Default: {"jsonld":{"mime_types":["application/ld+json"]}}
@ -2613,12 +2626,37 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* rules?: mixed,
* policy?: mixed,
* middleware?: mixed,
* parameters?: mixed,
* parameters?: array<string, array{ // Default: []
* key?: mixed,
* schema?: mixed,
* open_api?: mixed,
* provider?: mixed,
* filter?: mixed,
* property?: mixed,
* description?: mixed,
* properties?: mixed,
* required?: mixed,
* priority?: mixed,
* hydra?: mixed,
* constraints?: mixed,
* security?: mixed,
* security_message?: mixed,
* extra_properties?: mixed,
* filter_context?: mixed,
* native_type?: mixed,
* cast_to_array?: mixed,
* cast_to_native_type?: mixed,
* cast_fn?: mixed,
* default?: mixed,
* filter_class?: mixed,
* ...<mixed>
* }>,
* strict_query_parameter_validation?: mixed,
* hide_hydra_operation?: mixed,
* json_stream?: mixed,
* extra_properties?: mixed,
* map?: mixed,
* mcp?: mixed,
* route_name?: mixed,
* errors?: mixed,
* read?: mixed,
@ -2626,6 +2664,7 @@ use Symfony\Component\Config\Loader\ParamConfigurator as Param;
* validate?: mixed,
* write?: mixed,
* serialize?: mixed,
* content_negotiation?: mixed,
* priority?: mixed,
* name?: mixed,
* allow_create?: mixed,

View file

@ -1,4 +1,4 @@
# Generated on Tue Mar 3 14:26:21 UTC 2026
# Generated on Mon Mar 30 04:50:04 UTC 2026
# This file contains all footprints available in the offical KiCAD library
Audio_Module:Reverb_BTDR-1H
Audio_Module:Reverb_BTDR-1V

View file

@ -1,4 +1,4 @@
# Generated on Tue Mar 3 14:27:05 UTC 2026
# Generated on Mon Mar 30 04:50:41 UTC 2026
# This file contains all symbols available in the offical KiCAD library
4xxx:14528
4xxx:14529
@ -15731,6 +15731,7 @@ Power_Management:RT9742AGJ5F
Power_Management:RT9742ANGJ5F
Power_Management:RT9742BGJ5F
Power_Management:RT9742BNGJ5F
Power_Management:RT9742SNGV
Power_Management:SN6505ADBV
Power_Management:SN6505BDBV
Power_Management:SN6507DGQ
@ -18692,6 +18693,7 @@ Regulator_Linear:TPS7A0530PDBZ
Regulator_Linear:TPS7A0531PDBV
Regulator_Linear:TPS7A0533PDBV
Regulator_Linear:TPS7A0533PDBZ
Regulator_Linear:TPS7A20xxxDBV
Regulator_Linear:TPS7A20xxxDQN
Regulator_Linear:TPS7A3301RGW
Regulator_Linear:TPS7A39
@ -22324,6 +22326,7 @@ Transistor_FET:PSMN5R2-60YL
Transistor_FET:QM6006D
Transistor_FET:QM6015D
Transistor_FET:Q_Dual_NMOS_G1S2G2D2S1D1
Transistor_FET:Q_Dual_NMOS_PMOS_G1S2G2D2S1D1
Transistor_FET:Q_Dual_NMOS_S1G1D2S2G2D1
Transistor_FET:Q_Dual_NMOS_S1G1S2G2D2D1
Transistor_FET:Q_Dual_NMOS_S1G1S2G2D2D2D1D1

View file

@ -240,7 +240,8 @@ class ProjectController extends AbstractController
}
// Detect fields and get suggestions
$detected_fields = $BOMImporter->detectFields($file_content);
$detected_delimiter = $BOMImporter->detectDelimiter($file_content);
$detected_fields = $BOMImporter->detectFields($file_content, $detected_delimiter);
$suggested_mapping = $BOMImporter->getSuggestedFieldMapping($detected_fields);
// Create mapping of original field names to sanitized field names for template
@ -257,7 +258,7 @@ class ProjectController extends AbstractController
$builder->add('delimiter', ChoiceType::class, [
'label' => 'project.bom_import.delimiter',
'required' => true,
'data' => ',',
'data' => $detected_delimiter,
'choices' => [
'project.bom_import.delimiter.comma' => ',',
'project.bom_import.delimiter.semicolon' => ';',

View file

@ -721,26 +721,36 @@ class BOMImporter
return $mapped;
}
/**
* Try to detect the separator used in the CSV data by analyzing the first line and counting occurrences of common delimiters.
* @param string $data
* @return string
*/
public function detectDelimiter(string $data): string
{
$delimiters = [',', ';', "\t"];
$lines = explode("\n", $data, 2);
$header_line = $lines[0] ?? '';
$delimiter_counts = [];
foreach ($delimiters as $delim) {
$delimiter_counts[$delim] = substr_count($header_line, $delim);
}
// Choose the delimiter with the highest count, default to comma if all are zero
$max_count = max($delimiter_counts);
$delimiter = array_search($max_count, $delimiter_counts, true);
if ($max_count === 0 || $delimiter === false) {
$delimiter = ',';
}
return $delimiter;
}
/**
* Detect available fields in CSV data for field mapping UI
*/
public function detectFields(string $data, ?string $delimiter = null): array
{
if ($delimiter === null) {
// Detect delimiter by counting occurrences in the first row (header)
$delimiters = [',', ';', "\t"];
$lines = explode("\n", $data, 2);
$header_line = $lines[0] ?? '';
$delimiter_counts = [];
foreach ($delimiters as $delim) {
$delimiter_counts[$delim] = substr_count($header_line, $delim);
}
// Choose the delimiter with the highest count, default to comma if all are zero
$max_count = max($delimiter_counts);
$delimiter = array_search($max_count, $delimiter_counts, true);
if ($max_count === 0 || $delimiter === false) {
$delimiter = ',';
}
$delimiter = $this->detectDelimiter($data);
}
// Handle potential BOM (Byte Order Mark) at the beginning
$data = preg_replace('/^\xEF\xBB\xBF/', '', $data);

View file

@ -315,7 +315,14 @@ class GenericWebProvider implements InfoProviderInterface
//Remove any leading slashes
$url = ltrim($url, '/');
$url = 'https://'.$url;
//If the URL starts with https:/ or http:/, add the missing slash
//Traefik removes the double slash as secruity measure, so we want to be forgiving and add it back if needed
//See https://github.com/Part-DB/Part-DB-server/issues/1296
if (preg_match('/^https?:\/[^\/]/', $url)) {
$url = preg_replace('/^(https?:)\/([^\/])/', '$1//$2', $url);
} else {
$url = 'https://'.$url;
}
}
//If this is not a valid URL with host, domain and path, throw an exception

View file

@ -105,6 +105,10 @@ final class BarcodeScanHelper
return new AmazonBarcodeScanResult($input);
}
if ($type === BarcodeSourceType::TME) {
return TMEBarcodeScanResult::parse($input);
}
//Null means auto and we try the different formats
$result = $this->parseInternalBarcode($input);
@ -144,6 +148,11 @@ final class BarcodeScanHelper
return new AmazonBarcodeScanResult($input);
}
// Try TME barcode
if (TMEBarcodeScanResult::isTMEBarcode($input)) {
return TMEBarcodeScanResult::parse($input);
}
throw new InvalidArgumentException('Unknown barcode');
}
@ -162,6 +171,7 @@ final class BarcodeScanHelper
return LCSCBarcodeScanResult::parse($input);
}
private function parseUserDefinedBarcode(string $input): ?LocalBarcodeScanResult
{
$lot_repo = $this->entityManager->getRepository(PartLot::class);

View file

@ -150,6 +150,10 @@ final readonly class BarcodeScanResultHandler
?? $this->em->getRepository(Part::class)->getPartBySPN($barcodeScan->asin);
}
if ($barcodeScan instanceof TMEBarcodeScanResult) {
return $this->resolvePartFromTME($barcodeScan);
}
return null;
}
@ -217,8 +221,8 @@ final readonly class BarcodeScanResultHandler
* Resolve LCSC barcode -> Part.
* Strategy:
* 1) Try providerReference.provider_id == pc (LCSC "Cxxxxxx") if you store it there
* 2) Fallback to manufacturer_product_number == pm (MPN)
* Returns first match (consistent with EIGP114 logic)
* 2) Fallback to search across supplier part number (SPN)
*/
private function resolvePartFromLCSC(LCSCBarcodeScanResult $barcodeScan): ?Part
{
@ -231,16 +235,31 @@ final readonly class BarcodeScanResultHandler
}
}
// Fallback to MPN (pm)
$pm = $barcodeScan->mpn; // e.g. RC0402FR-071ML
if (!$pm) {
return null;
}
return $this->em->getRepository(Part::class)->getPartByMPN($pm);
// fallback to search by SPN
return $this->em->getRepository(Part::class)->getPartBySPN($pc);
}
private function resolvePartFromTME(TMEBarcodeScanResult $barcodeScan): ?Part
{
$pn = $barcodeScan->tmePartNumber;
if ($pn) {
$part = $this->em->getRepository(Part::class)->getPartByProviderInfo($pn);
if ($part !== null) {
return $part;
}
//Try to find the part by SPN/SKU
$part = $this->em->getRepository(Part::class)->getPartBySPN($pn);
if ($part !== null) {
return $part;
}
}
// Fallback: search by MPN
return $this->em->getRepository(Part::class)->getPartByMPN($barcodeScan->mpn, $barcodeScan->manufacturer);
}
/**
* Tries to extract creation information for a part from the given barcode scan result. This can be used to
* automatically fill in the info provider reference of a part, when creating a new part based on the scan result.
@ -252,6 +271,20 @@ final readonly class BarcodeScanResultHandler
*/
public function getCreateInfos(BarcodeScanResultInterface $scanResult): ?array
{
// TME
if ($scanResult instanceof TMEBarcodeScanResult) {
if ($scanResult->tmePartNumber === null) {
return null;
}
return [
'providerKey' => 'tme',
'providerId' => $scanResult->tmePartNumber,
'lotAmount' => $scanResult->quantity,
'lotName' => $scanResult->purchaseOrder,
'lotUserBarcode' => $scanResult->rawInput,
];
}
// LCSC
if ($scanResult instanceof LCSCBarcodeScanResult) {
return [

View file

@ -52,4 +52,7 @@ enum BarcodeSourceType: string
case LCSC = 'lcsc';
case AMAZON = 'amazon';
/** For TME (tme.eu) formatted QR codes */
case TME = 'tme';
}

View file

@ -254,12 +254,16 @@ readonly class EIGP114BarcodeScanResult implements BarcodeScanResultInterface
*/
public static function isFormat06Code(string $input): bool
{
//Code must begin with [)><RS>06<GS>
if(!str_starts_with($input, "[)>\u{1E}06\u{1D}")){
return false;
//Code should begin with [)><RS>06<GS> as per the standard
if(!str_starts_with($input, "[)>\u{1E}06\u{1D}")
// some codes don't contain record separators
&& !str_starts_with($input, "[)>06\u{1D}")
// This is found on old Mouser parts
&& !str_starts_with($input, ">[)>06\u{1D}"))
{
return false;
}
//Digikey does not put a trailer onto the barcode, so we just check for the header
//Digikey and Mouser don't put a trailer onto the barcode, so we just check for the header
return true;
}

View file

@ -0,0 +1,143 @@
<?php
/*
* 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/>.
*/
declare(strict_types=1);
namespace App\Services\LabelSystem\BarcodeScanner;
use InvalidArgumentException;
/**
* This class represents the content of a tme.eu barcode label.
* The format is space-separated KEY:VALUE tokens, e.g.:
* QTY:1000 PN:SMD0603-5K1-1% PO:32723349/7 MFR:ROYALOHM MPN:0603SAF5101T5E CoO:TH RoHS https://www.tme.eu/details/...
*/
readonly class TMEBarcodeScanResult implements BarcodeScanResultInterface
{
/** @var int|null Quantity (QTY) */
public ?int $quantity;
/** @var string|null TME part number (PN) */
public ?string $tmePartNumber;
/** @var string|null Purchase order number (PO) */
public ?string $purchaseOrder;
/** @var string|null Manufacturer name (MFR) */
public ?string $manufacturer;
/** @var string|null Manufacturer part number (MPN) */
public ?string $mpn;
/** @var string|null Country of origin (CoO) */
public ?string $countryOfOrigin;
/** @var bool Whether the part is RoHS compliant */
public bool $rohs;
/** @var string|null The product URL */
public ?string $productUrl;
/**
* @param array<string, string> $fields Parsed key-value fields (keys uppercased)
* @param string $rawInput Original barcode string
*/
public function __construct(
public array $fields,
public string $rawInput,
) {
$this->quantity = isset($this->fields['QTY']) ? (int) $this->fields['QTY'] : null;
$this->tmePartNumber = $this->fields['PN'] ?? null;
$this->purchaseOrder = $this->fields['PO'] ?? null;
$this->manufacturer = $this->fields['MFR'] ?? null;
$this->mpn = $this->fields['MPN'] ?? null;
$this->countryOfOrigin = $this->fields['COO'] ?? null;
$this->rohs = isset($this->fields['ROHS']);
$this->productUrl = $this->fields['URL'] ?? null;
}
public function getSourceType(): BarcodeSourceType
{
return BarcodeSourceType::TME;
}
public function getDecodedForInfoMode(): array
{
return [
'Barcode type' => 'TME',
'TME Part No. (PN)' => $this->tmePartNumber ?? '',
'MPN' => $this->mpn ?? '',
'Manufacturer (MFR)' => $this->manufacturer ?? '',
'Qty' => $this->quantity !== null ? (string) $this->quantity : '',
'Purchase Order (PO)' => $this->purchaseOrder ?? '',
'Country of Origin (CoO)' => $this->countryOfOrigin ?? '',
'RoHS' => $this->rohs ? 'Yes' : 'No',
'URL' => $this->productUrl ?? '',
];
}
/**
* Returns true if the input looks like a TME barcode label (contains tme.eu URL).
*/
public static function isTMEBarcode(string $input): bool
{
return str_contains(strtolower($input), 'tme.eu');
}
/**
* Parse the TME barcode string into a TMEBarcodeScanResult.
*/
public static function parse(string $input): self
{
$raw = trim($input);
if (!self::isTMEBarcode($raw)) {
throw new InvalidArgumentException('Not a TME barcode');
}
$fields = [];
// Split on whitespace; each token is either KEY:VALUE, a bare keyword, or the URL
$tokens = preg_split('/\s+/', $raw);
foreach ($tokens as $token) {
if ($token === '') {
continue;
}
// The TME URL
if (str_starts_with(strtolower($token), 'http')) {
$fields['URL'] = $token;
continue;
}
$colonPos = strpos($token, ':');
if ($colonPos !== false) {
$key = strtoupper(substr($token, 0, $colonPos));
$value = substr($token, $colonPos + 1);
$fields[$key] = $value;
} else {
// Bare keyword like "RoHS"
$fields[strtoupper($token)] = '';
}
}
return new self($fields, $raw);
}
}

View file

@ -47,17 +47,17 @@
</td>
<td>
{{ detail.price | format_money(detail.currency) }} / {{ detail.PriceRelatedQuantity | format_amount(part.partUnit) }}
{% set tmp = pricedetail_helper.convertMoneyToCurrency(detail.price, detail.currency) %}
{% set tmp = pricedetail_helper.convertMoneyToCurrency(detail.price, detail.currency, app.user.currency ?? null) %}
{% if detail.currency != (app.user.currency ?? null) and tmp is not null and tmp.GreaterThan(0) %}
<span class="text-muted">({{ pricedetail_helper.convertMoneyToCurrency(detail.price, detail.currency, app.user.currency ?? null) | format_money(app.user.currency ?? null) }})</span>
<span class="text-muted">({{ tmp | format_money(app.user.currency ?? null) }})</span>
{% endif %}
<small class="text-muted">{{- helper.vat_text(detail.includesVAT) -}}</small>
</td>
<td>
{{ detail.PricePerUnit | format_money(detail.currency) }}
{% set tmp = pricedetail_helper.convertMoneyToCurrency(detail.PricePerUnit, detail.currency) %}
{% set tmp = pricedetail_helper.convertMoneyToCurrency(detail.PricePerUnit, detail.currency, app.user.currency ?? null) %}
{% if detail.currency != (app.user.currency ?? null) and tmp is not null and tmp.GreaterThan(0) %}
<span class="text-muted">({{ pricedetail_helper.convertMoneyToCurrency(detail.PricePerUnit, detail.currency, app.user.currency ?? null) | format_money(app.user.currency ?? null) }})</span>
<span class="text-muted">({{ tmp | format_money(app.user.currency ?? null) }})</span>
{% endif %}
<small class="text-muted">{{- helper.vat_text(detail.includesVAT) -}}</small>
</td>

View file

@ -48,51 +48,59 @@
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>{% trans %}project.bom_import.field_mapping.csv_field{% endtrans %}</th>
<th>{% trans %}project.bom_import.field_mapping.maps_to{% endtrans %}</th>
<th>{% trans %}project.bom_import.field_mapping.suggestion{% endtrans %}</th>
<th>{% trans %}project.bom_import.field_mapping.priority{% endtrans %}</th>
</tr>
<tr>
<th>{% trans %}project.bom_import.field_mapping.csv_field{% endtrans %}</th>
<th>{% trans %}project.bom_import.field_mapping.maps_to{% endtrans %}</th>
<th>{% trans %}project.bom_import.field_mapping.suggestion{% endtrans %}</th>
<th>{% trans %}project.bom_import.field_mapping.priority{% endtrans %}</th>
</tr>
</thead>
<tbody>
{% for field in detected_fields %}
<tr>
<td>
<code>{{ field }}</code>
</td>
<td>
{% for field in detected_fields %}
<tr>
<td>
<code>{{ field }}</code>
</td>
<td>
{# TODO: This is more a workaround than a proper fix. Ideally the controller should be fixed in a way, that we get the correct fields here #}
{% if field_name_mapping[field] is defined %}
{% set field_name = field_name_mapping[field] %}
{{ form_widget(form['mapping_' ~ field_name_mapping[field]], {
'attr': {
'class': 'form-select field-mapping-select',
'data-field': field
}
}) }}
</td>
<td>
{% if suggested_mapping[field] is defined %}
<span class="badge bg-success">
{% else %}
<b class="text-danger">
{% trans %}project.bom_import.field_mapping.error.check_delimiter{% endtrans %}
</b>
{% endif %}
</td>
<td>
{% if suggested_mapping[field] is defined %}
<span class="badge bg-success">
<i class="fa-solid fa-magic fa-fw"></i>
{{ suggested_mapping[field] }}
</span>
{% else %}
<span class="text-muted">
{% else %}
<span class="text-muted">
<i class="fa-solid fa-question fa-fw"></i>
{% trans %}project.bom_import.field_mapping.no_suggestion{% endtrans %}
</span>
{% endif %}
</td>
<td>
<input type="number"
class="form-control form-control-sm priority-input"
min="1"
value="10"
style="width: 80px;"
data-field="{{ field }}"
title="{% trans %}project.bom_import.field_mapping.priority_help{% endtrans %}">
</td>
</tr>
{% endfor %}
{% endif %}
</td>
<td>
<input type="number"
class="form-control form-control-sm priority-input"
min="1"
value="10"
style="width: 80px;"
data-field="{{ field }}"
title="{% trans %}project.bom_import.field_mapping.priority_help{% endtrans %}">
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>

View file

@ -23,7 +23,7 @@
{% if saml_enabled %}
<div class="{{ offset_label }} {{ col_input }}">
<a class="btn btn-secondary" href="{{ path('saml_login') }}"><i class="fa-solid fa-house-user"></i> {% trans %}login.sso_saml_login{% endtrans %}</a>
<a class="btn btn-secondary" href="{{ path('saml_login') }}" data-turbo="false"><i class="fa-solid fa-house-user"></i> {% trans %}login.sso_saml_login{% endtrans %}</a>
<p class="text-muted">{% trans %}login.local_login_hint{% endtrans %}</p>
</div>

View file

@ -0,0 +1,68 @@
<?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/>.
*/
declare(strict_types=1);
namespace App\Tests\Doctrine\Functions;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\ORM\Query\AST\Node;
use Doctrine\ORM\Query\SqlWalker;
use PHPUnit\Framework\TestCase;
abstract class AbstractDoctrineFunctionTestCase extends TestCase
{
protected function createSqlWalker(AbstractPlatform $platform, string $serverVersion = '11.0.0-MariaDB'): SqlWalker
{
$connection = $this->createMock(Connection::class);
$connection->method('getDatabasePlatform')->willReturn($platform);
$connection->method('getServerVersion')->willReturn($serverVersion);
$sqlWalker = $this->getMockBuilder(SqlWalker::class)
->disableOriginalConstructor()
->onlyMethods(['getConnection'])
->getMock();
$sqlWalker->method('getConnection')->willReturn($connection);
return $sqlWalker;
}
protected function createNode(string $sql): Node
{
$node = $this->createMock(Node::class);
$node->method('dispatch')->willReturn($sql);
return $node;
}
protected function setObjectProperty(object $object, string $property, mixed $value): void
{
$reflection = new \ReflectionProperty($object, $property);
$reflection->setValue($object, $value);
}
protected function setStaticProperty(string $class, string $property, mixed $value): void
{
$reflection = new \ReflectionProperty($class, $property);
$reflection->setValue(null, $value);
}
}

View file

@ -0,0 +1,42 @@
<?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/>.
*/
declare(strict_types=1);
namespace App\Tests\Doctrine\Functions;
use App\Doctrine\Functions\ArrayPosition;
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
final class ArrayPositionTest extends AbstractDoctrineFunctionTestCase
{
public function testArrayPositionBuildsSql(): void
{
$function = new ArrayPosition('ARRAY_POSITION');
$this->setObjectProperty($function, 'array', $this->createNode(':ids'));
$this->setObjectProperty($function, 'field', $this->createNode('p.id'));
$sql = $function->getSql($this->createSqlWalker(new PostgreSQLPlatform()));
$this->assertSame('ARRAY_POSITION(:ids, p.id)', $sql);
}
}

View file

@ -0,0 +1,45 @@
<?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/>.
*/
declare(strict_types=1);
namespace App\Tests\Doctrine\Functions;
use App\Doctrine\Functions\Field2;
use Doctrine\DBAL\Platforms\MySQLPlatform;
final class Field2Test extends AbstractDoctrineFunctionTestCase
{
public function testField2BuildsSql(): void
{
$function = new Field2('FIELD2');
$this->setObjectProperty($function, 'field', $this->createNode('p.id'));
$this->setObjectProperty($function, 'values', [
$this->createNode('1'),
$this->createNode('2'),
$this->createNode('3'),
]);
$sql = $function->getSql($this->createSqlWalker(new MySQLPlatform()));
$this->assertSame('FIELD2(p.id, 1, 2, 3)', $sql);
}
}

View file

@ -0,0 +1,66 @@
<?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/>.
*/
declare(strict_types=1);
namespace App\Tests\Doctrine\Functions;
use App\Doctrine\Functions\ILike;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\DBAL\Platforms\SQLitePlatform;
use Doctrine\DBAL\Platforms\SQLServerPlatform;
use PHPUnit\Framework\Attributes\DataProvider;
final class ILikeTest extends AbstractDoctrineFunctionTestCase
{
public static function iLikePlatformProvider(): \Generator
{
yield 'mysql' => [new MySQLPlatform(), '(part_name LIKE :pattern)'];
yield 'postgres' => [new PostgreSQLPlatform(), '(part_name ILIKE :pattern)'];
yield 'sqlite' => [new SQLitePlatform(), "(part_name LIKE :pattern ESCAPE '\\')"];
}
#[DataProvider('iLikePlatformProvider')]
public function testILikeUsesExpectedOperator(AbstractPlatform $platform, string $expectedSql): void
{
$function = new ILike('ILIKE');
$function->value = $this->createNode('part_name');
$function->expr = $this->createNode(':pattern');
$sql = $function->getSql($this->createSqlWalker($platform));
$this->assertSame($expectedSql, $sql);
}
public function testILikeThrowsOnUnsupportedPlatform(): void
{
$function = new ILike('ILIKE');
$function->value = $this->createNode('part_name');
$function->expr = $this->createNode(':pattern');
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('does not support case insensitive like expressions');
$function->getSql($this->createSqlWalker(new SQLServerPlatform()));
}
}

View file

@ -0,0 +1,95 @@
<?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/>.
*/
declare(strict_types=1);
namespace App\Tests\Doctrine\Functions;
use App\Doctrine\Functions\Natsort;
use Doctrine\DBAL\Platforms\MariaDBPlatform;
use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\DBAL\Platforms\SQLitePlatform;
final class NatsortTest extends AbstractDoctrineFunctionTestCase
{
protected function setUp(): void
{
parent::setUp();
Natsort::allowSlowNaturalSort(false);
$this->setStaticProperty(Natsort::class, 'supportsNaturalSort', null);
}
public function testNatsortUsesPostgresCollation(): void
{
$function = new Natsort('NATSORT');
$this->setObjectProperty($function, 'field', $this->createNode('part_name'));
$sql = $function->getSql($this->createSqlWalker(new PostgreSQLPlatform()));
$this->assertSame('part_name COLLATE numeric', $sql);
}
public function testNatsortUsesMariaDbNativeFunctionOnSupportedVersion(): void
{
$function = new Natsort('NATSORT');
$this->setObjectProperty($function, 'field', $this->createNode('part_name'));
$sql = $function->getSql($this->createSqlWalker(new MariaDBPlatform(), '10.11.2-MariaDB'));
$this->assertSame('NATURAL_SORT_KEY(part_name)', $sql);
}
public function testNatsortFallsBackWithoutSlowSort(): void
{
$function = new Natsort('NATSORT');
$this->setObjectProperty($function, 'field', $this->createNode('part_name'));
$sql = $function->getSql($this->createSqlWalker(new MariaDBPlatform(), '10.6.10-MariaDB'));
$this->assertSame('part_name', $sql);
}
public function testNatsortUsesSlowSortFunctionOnMySqlWhenEnabled(): void
{
Natsort::allowSlowNaturalSort();
$function = new Natsort('NATSORT');
$this->setObjectProperty($function, 'field', $this->createNode('part_name'));
$sql = $function->getSql($this->createSqlWalker(new MySQLPlatform()));
$this->assertSame('NatSortKey(part_name, 0)', $sql);
}
public function testNatsortUsesSlowSortCollationOnSqliteWhenEnabled(): void
{
Natsort::allowSlowNaturalSort();
$function = new Natsort('NATSORT');
$this->setObjectProperty($function, 'field', $this->createNode('part_name'));
$sql = $function->getSql($this->createSqlWalker(new SQLitePlatform()));
$this->assertSame('part_name COLLATE NATURAL_CMP', $sql);
}
}

View file

@ -0,0 +1,66 @@
<?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/>.
*/
declare(strict_types=1);
namespace App\Tests\Doctrine\Functions;
use App\Doctrine\Functions\Regexp;
use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
use Doctrine\DBAL\Platforms\SQLitePlatform;
use Doctrine\DBAL\Platforms\SQLServerPlatform;
use PHPUnit\Framework\Attributes\DataProvider;
final class RegexpTest extends AbstractDoctrineFunctionTestCase
{
public static function regexpPlatformProvider(): \Generator
{
yield 'mysql' => [new MySQLPlatform(), '(part_name REGEXP :regex)'];
yield 'sqlite' => [new SQLitePlatform(), '(part_name REGEXP :regex)'];
yield 'postgres' => [new PostgreSQLPlatform(), '(part_name ~* :regex)'];
}
#[DataProvider('regexpPlatformProvider')]
public function testRegexpUsesExpectedOperator(AbstractPlatform $platform, string $expectedSql): void
{
$function = new Regexp('REGEXP');
$this->setObjectProperty($function, 'value', $this->createNode('part_name'));
$this->setObjectProperty($function, 'regexp', $this->createNode(':regex'));
$sql = $function->getSql($this->createSqlWalker($platform));
$this->assertSame($expectedSql, $sql);
}
public function testRegexpThrowsOnUnsupportedPlatform(): void
{
$function = new Regexp('REGEXP');
$this->setObjectProperty($function, 'value', $this->createNode('part_name'));
$this->setObjectProperty($function, 'regexp', $this->createNode(':regex'));
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('does not support regular expressions');
$function->getSql($this->createSqlWalker(new SQLServerPlatform()));
}
}

View file

@ -115,8 +115,8 @@ final class BarcodeScanResultHandlerTest extends KernelTestCase
public function testLCSCBarcodeResolvePartOrNullReturnsNullWhenNotFound(): void
{
$scan = new LCSCBarcodeScanResult(
fields: ['pc' => 'C0000000', 'pm' => ''],
rawInput: '{pc:C0000000,pm:}'
fields: ['pc' => 'C0000000', 'pm' => 'NON_EXISTENT_MPN_12345'],
rawInput: '{pc:C0000000,pm:NON_EXISTENT_MPN_12345}'
);
$this->assertNull($this->service->resolvePart($scan));

View file

@ -93,6 +93,13 @@ final class EIGP114BarcodeScanResultTest extends TestCase
//Valid code (digikey, without trailer)
$this->assertTrue(EIGP114BarcodeScanResult::isFormat06Code("[)>\x1e06\x1dPQ1045-ND\x1d1P364019-01\x1d30PQ1045-ND\x1dK12432 TRAVIS FOSS P\x1d1K85732873\x1d10K103332956\x1d9D231013\x1d1TQJ13P\x1d11K1\x1d4LTW\x1dQ3\x1d11ZPICK\x1d12Z7360988\x1d13Z999999\x1d20Z0000000000000000000000000000000000000000000000000000000000000000000000000000000000000"));
//Valid code (without record separator)
$this->assertTrue(EIGP114BarcodeScanResult::isFormat06Code("[)>06\x1DP596-777A1-ND\x1D1PXAF4444\x1DQ3\x1D10D1452\x1D1TBF1103\x1D4LUS\x1E\x04"));
//Old mouser format
$this->assertTrue(EIGP114BarcodeScanResult::isFormat06Code(">[)>06\x1DP596-777A1-ND\x1D1PXAF4444\x1DQ3\x1D10D1452\x1D1TBF1103\x1D4LUS\x1E\x04"));
}
public function testParseFormat06CodeInvalid(): void
@ -101,6 +108,32 @@ final class EIGP114BarcodeScanResultTest extends TestCase
EIGP114BarcodeScanResult::parseFormat06Code('');
}
public function testParseWithoutRecordSeparator(): void
{
$barcode = EIGP114BarcodeScanResult::parseFormat06Code("[)>06\x1DP596-777A1-ND\x1D1PXAF4444\x1DQ3\x1D10D1452\x1D1TBF1103\x1D4LUS\x1E\x04");
$this->assertSame([
'P' => '596-777A1-ND',
'1P' => 'XAF4444',
'Q' => '3',
'10D' => '1452',
'1T' => 'BF1103',
'4L' => 'US',
], $barcode->data);
}
public function testParseOldMouserFormat(): void
{
$barcode = EIGP114BarcodeScanResult::parseFormat06Code(">[)>06\x1DP596-777A1-ND\x1D1PXAF4444\x1DQ3\x1D10D1452\x1D1TBF1103\x1D4LUS\x1E\x04");
$this->assertSame([
'P' => '596-777A1-ND',
'1P' => 'XAF4444',
'Q' => '3',
'10D' => '1452',
'1T' => 'BF1103',
'4L' => 'US',
], $barcode->data);
}
public function testParseFormat06Code(): void
{
$barcode = EIGP114BarcodeScanResult::parseFormat06Code("[)>\x1E06\x1DP596-777A1-ND\x1D1PXAF4444\x1DQ3\x1D10D1452\x1D1TBF1103\x1D4LUS\x1E\x04");

View file

@ -0,0 +1,110 @@
<?php
/*
* 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\Tests\Services\LabelSystem\BarcodeScanner;
use App\Services\LabelSystem\BarcodeScanner\BarcodeSourceType;
use App\Services\LabelSystem\BarcodeScanner\TMEBarcodeScanResult;
use InvalidArgumentException;
use PHPUnit\Framework\TestCase;
class TMEBarcodeScanResultTest extends TestCase
{
private const EXAMPLE1 = 'QTY:1000 PN:SMD0603-5K1-1% PO:32723349/7 MFR:ROYALOHM MPN:0603SAF5101T5E CoO:TH RoHS https://www.tme.eu/details/SMD0603-5K1-1%25';
private const EXAMPLE2 = 'QTY:5 PN:ETQP3M6R8KVP PO:31199729/3 MFR:PANASONIC MPN:ETQP3M6R8KVP RoHS https://www.tme.eu/details/ETQP3M6R8KVP';
public function testIsTMEBarcode(): void
{
$this->assertFalse(TMEBarcodeScanResult::isTMEBarcode('invalid'));
$this->assertFalse(TMEBarcodeScanResult::isTMEBarcode('QTY:5 PN:ABC MPN:XYZ'));
$this->assertFalse(TMEBarcodeScanResult::isTMEBarcode(''));
$this->assertTrue(TMEBarcodeScanResult::isTMEBarcode(self::EXAMPLE1));
$this->assertTrue(TMEBarcodeScanResult::isTMEBarcode(self::EXAMPLE2));
}
public function testParseInvalidThrows(): void
{
$this->expectException(InvalidArgumentException::class);
TMEBarcodeScanResult::parse('not-a-tme-barcode');
}
public function testParseExample1(): void
{
$scan = TMEBarcodeScanResult::parse(self::EXAMPLE1);
$this->assertSame(1000, $scan->quantity);
$this->assertSame('SMD0603-5K1-1%', $scan->tmePartNumber);
$this->assertSame('32723349/7', $scan->purchaseOrder);
$this->assertSame('ROYALOHM', $scan->manufacturer);
$this->assertSame('0603SAF5101T5E', $scan->mpn);
$this->assertSame('TH', $scan->countryOfOrigin);
$this->assertTrue($scan->rohs);
$this->assertSame('https://www.tme.eu/details/SMD0603-5K1-1%25', $scan->productUrl);
$this->assertSame(self::EXAMPLE1, $scan->rawInput);
}
public function testParseExample2(): void
{
$scan = TMEBarcodeScanResult::parse(self::EXAMPLE2);
$this->assertSame(5, $scan->quantity);
$this->assertSame('ETQP3M6R8KVP', $scan->tmePartNumber);
$this->assertSame('31199729/3', $scan->purchaseOrder);
$this->assertSame('PANASONIC', $scan->manufacturer);
$this->assertSame('ETQP3M6R8KVP', $scan->mpn);
$this->assertNull($scan->countryOfOrigin);
$this->assertTrue($scan->rohs);
$this->assertSame('https://www.tme.eu/details/ETQP3M6R8KVP', $scan->productUrl);
}
public function testGetSourceType(): void
{
$scan = TMEBarcodeScanResult::parse(self::EXAMPLE2);
$this->assertSame(BarcodeSourceType::TME, $scan->getSourceType());
}
public function testParseUppercaseUrl(): void
{
$input = 'QTY:500 PN:M0.6W-10K MFR:ROYAL.OHM MPN:MF006FF1002A50 PO:7792659/8 HTTPS://WWW.TME.EU/DETAILS/M0.6W-10K';
$this->assertTrue(TMEBarcodeScanResult::isTMEBarcode($input));
$scan = TMEBarcodeScanResult::parse($input);
$this->assertSame(500, $scan->quantity);
$this->assertSame('M0.6W-10K', $scan->tmePartNumber);
$this->assertSame('ROYAL.OHM', $scan->manufacturer);
$this->assertSame('MF006FF1002A50', $scan->mpn);
$this->assertSame('7792659/8', $scan->purchaseOrder);
$this->assertSame('HTTPS://WWW.TME.EU/DETAILS/M0.6W-10K', $scan->productUrl);
}
public function testGetDecodedForInfoMode(): void
{
$scan = TMEBarcodeScanResult::parse(self::EXAMPLE1);
$decoded = $scan->getDecodedForInfoMode();
$this->assertSame('TME', $decoded['Barcode type']);
$this->assertSame('SMD0603-5K1-1%', $decoded['TME Part No. (PN)']);
$this->assertSame('0603SAF5101T5E', $decoded['MPN']);
$this->assertSame('ROYALOHM', $decoded['Manufacturer (MFR)']);
$this->assertSame('1000', $decoded['Qty']);
$this->assertSame('Yes', $decoded['RoHS']);
}
}

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en" trgLang="de">
<file id="messages.en">
<file id="messages.de">
<unit id="x_wTSQS" name="attachment_type.caption">
<segment state="translated">
<source>attachment_type.caption</source>
@ -12861,6 +12861,12 @@ Buerklin-API-Authentication-Server:
<target>Amazon Barcode</target>
</segment>
</unit>
<unit id="d.V2Pid" name="scan_dialog.mode.tme">
<segment state="translated">
<source>scan_dialog.mode.tme</source>
<target>TME Barcode</target>
</segment>
</unit>
<unit id="BQWuR_G" name="settings.ips.canopy">
<segment state="translated">
<source>settings.ips.canopy</source>
@ -12945,5 +12951,11 @@ Buerklin-API-Authentication-Server:
<target>[Part_lot] aus Barcode erstellt: Bitte überprüfen Sie, ob die Daten korrekt und gewünscht sind.</target>
</segment>
</unit>
<unit id="F8pQuL9" name="project.bom_import.field_mapping.error.check_delimiter">
<segment state="translated">
<source>project.bom_import.field_mapping.error.check_delimiter</source>
<target>Zuordnungsfehler: Bitte prüfen Sie, ob Sie das richtige Trennzeichen ausgewählt haben!</target>
</segment>
</unit>
</file>
</xliff>

View file

@ -12863,6 +12863,12 @@ Buerklin-API Authentication server:
<target>Amazon barcode</target>
</segment>
</unit>
<unit id="d.V2Pid" name="scan_dialog.mode.tme">
<segment state="translated">
<source>scan_dialog.mode.tme</source>
<target>TME barcode</target>
</segment>
</unit>
<unit id="BQWuR_G" name="settings.ips.canopy">
<segment state="translated">
<source>settings.ips.canopy</source>
@ -12947,5 +12953,11 @@ Buerklin-API Authentication server:
<target>[Part_lot] created from barcode: Please check if the data is correct and desired.</target>
</segment>
</unit>
<unit id="F8pQuL9" name="project.bom_import.field_mapping.error.check_delimiter">
<segment state="translated">
<source>project.bom_import.field_mapping.error.check_delimiter</source>
<target>Mapping error: Check if you have selected the right delimiter!</target>
</segment>
</unit>
</file>
</xliff>

View file

@ -247,5 +247,11 @@
<target>该类型在此语言下已存在翻译定义!</target>
</segment>
</unit>
<unit id="zT_j_oQ" name="validator.invalid_gtin">
<segment state="translated">
<source>validator.invalid_gtin</source>
<target>无效的GTIN / EAN 码。</target>
</segment>
</unit>
</file>
</xliff>
</xliff>

1681
yarn.lock

File diff suppressed because it is too large Load diff