Compare commits
32 Commits
v0.0.7
...
feat/admin
| Author | SHA1 | Date | |
|---|---|---|---|
| 311f523647 | |||
|
|
0d0aa788db | ||
| c010bdc262 | |||
|
|
0e905bfcbe | ||
| e6bb4ddf6a | |||
| 299ea84e87 | |||
| bb0b0092da | |||
| 33d21f6ae6 | |||
| 98ee62294d | |||
| 820386b87b | |||
| c17f7aa08a | |||
| 4a0d38d307 | |||
| e9948d6ac3 | |||
| 80d87b7c9b | |||
| a69556c554 | |||
| 13e8698673 | |||
| a34bdbfe8d | |||
| d8e1cdc72c | |||
| 2c54a8c950 | |||
| 7c85d91c78 | |||
| 149bced1c5 | |||
| 086279f962 | |||
| 1ce6357c1d | |||
| 9ae073e69e | |||
| 2cd05a39ba | |||
| 66e9c52914 | |||
| 80d6d72e37 | |||
| b883546575 | |||
| 038596951d | |||
| ac5a3493e7 | |||
| 7dc4fdd1c0 | |||
| 5395dfefda |
@@ -16,30 +16,50 @@ jobs:
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
persist-credentials: true
|
||||
|
||||
- name: Create next tag v0.0.X
|
||||
- name: Create next tag from config/version.yaml
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
# Skip if current commit already has a v0.0.* tag
|
||||
if git tag --points-at HEAD | grep -qE '^v0\.0\.'; then
|
||||
# Skip if current commit already has a vX.Y.Z tag
|
||||
if git tag --points-at HEAD | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then
|
||||
echo "Tag already exists on this commit. Skipping."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
last_tag="$(git tag -l 'v0.0.*' --sort=-v:refname | head -n1 || true)"
|
||||
if [ -z "$last_tag" ]; then
|
||||
next_tag="v0.0.1"
|
||||
else
|
||||
patch="${last_tag##v0.0.}"
|
||||
if ! [[ "$patch" =~ ^[0-9]+$ ]]; then
|
||||
echo "Unexpected tag format: $last_tag" >&2
|
||||
exit 1
|
||||
fi
|
||||
next_tag="v0.0.$((patch + 1))"
|
||||
changed_version=false
|
||||
if git diff --name-only "${{ gitea.event.before }}" "${{ gitea.event.after }}" | grep -q '^config/version\.yaml$'; then
|
||||
changed_version=true
|
||||
fi
|
||||
|
||||
git config user.name "gitea-actions"
|
||||
git config user.email "gitea-actions@local"
|
||||
git tag "$next_tag"
|
||||
git push origin "$next_tag"
|
||||
read_version() {
|
||||
awk -F': *' '/app\.version:/{print $2}' config/version.yaml | tr -d '[:space:]' | tr -d "'\""
|
||||
}
|
||||
|
||||
if $changed_version; then
|
||||
version="$(read_version)"
|
||||
if ! [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "Invalid version in version.yaml: $version" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
last_tag="$(git tag -l 'v*' --sort=-v:refname | head -n1 || true)"
|
||||
if [ -z "$last_tag" ]; then
|
||||
version="0.1.0"
|
||||
else
|
||||
base="${last_tag#v}"
|
||||
IFS='.' read -r major minor patch <<< "$base"
|
||||
version="${major}.${minor}.$((patch + 1))"
|
||||
fi
|
||||
|
||||
printf "parameters:\\n app.version: '%s'\\n" "$version" > config/version.yaml
|
||||
git config user.name "gitea-actions"
|
||||
git config user.email "gitea-actions@local"
|
||||
git add config/version.yaml
|
||||
git commit -m "chore: bump version to v$version" || true
|
||||
git push origin develop || true
|
||||
fi
|
||||
|
||||
tag="v$version"
|
||||
git tag "$tag"
|
||||
git push origin "$tag"
|
||||
|
||||
@@ -36,7 +36,8 @@ jobs:
|
||||
run: |
|
||||
cd frontend
|
||||
npm ci
|
||||
NUXT_PUBLIC_API_BASE=/api NUXT_PUBLIC_APP_BASE=/ npm run generate
|
||||
CI=1 NUXT_TELEMETRY_DISABLED=1 NUXT_PUBLIC_API_BASE=/api NUXT_PUBLIC_APP_BASE=/ npm run generate
|
||||
test -f .output/public/index.html
|
||||
|
||||
- name: Build artefact
|
||||
shell: bash
|
||||
@@ -54,7 +55,7 @@ jobs:
|
||||
composer.json \
|
||||
composer.lock \
|
||||
symfony.lock \
|
||||
frontend/.output/public
|
||||
frontend/.output
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
|
||||
6
.idea/copilot.data.migration.agent.xml
generated
Normal file
6
.idea/copilot.data.migration.agent.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AgentMigrationStateService">
|
||||
<option name="migrationStatus" value="COMPLETED" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/copilot.data.migration.ask.xml
generated
Normal file
6
.idea/copilot.data.migration.ask.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AskMigrationStateService">
|
||||
<option name="migrationStatus" value="COMPLETED" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/copilot.data.migration.ask2agent.xml
generated
Normal file
6
.idea/copilot.data.migration.ask2agent.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Ask2AgentMigrationStateService">
|
||||
<option name="migrationStatus" value="COMPLETED" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/copilot.data.migration.edit.xml
generated
Normal file
6
.idea/copilot.data.migration.edit.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EditMigrationStateService">
|
||||
<option name="migrationStatus" value="COMPLETED" />
|
||||
</component>
|
||||
</project>
|
||||
2
.idea/dataSources.xml
generated
2
.idea/dataSources.xml
generated
@@ -16,4 +16,4 @@
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
5
.idea/data_source_mapping.xml
generated
5
.idea/data_source_mapping.xml
generated
@@ -1,7 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourcePerFileMappings">
|
||||
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/ae622167-c834-4e7b-87a5-c1721036f5dc/console.sql" value="ae622167-c834-4e7b-87a5-c1721036f5dc" />
|
||||
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/f407a514-c6b4-4b26-9555-445a85892502/console.sql" value="f407a514-c6b4-4b26-9555-445a85892502" />
|
||||
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/f407a514-c6b4-4b26-9555-445a85892502/console_1.sql" value="f407a514-c6b4-4b26-9555-445a85892502" />
|
||||
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/f407a514-c6b4-4b26-9555-445a85892502/console_2.sql" value="f407a514-c6b4-4b26-9555-445a85892502" />
|
||||
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/f407a514-c6b4-4b26-9555-445a85892502/console_3.sql" value="f407a514-c6b4-4b26-9555-445a85892502" />
|
||||
<file url="file://$APPLICATION_CONFIG_DIR$/consoles/db/f407a514-c6b4-4b26-9555-445a85892502/console_4.sql" value="f407a514-c6b4-4b26-9555-445a85892502" />
|
||||
</component>
|
||||
</project>
|
||||
5
.idea/ferme.iml
generated
5
.idea/ferme.iml
generated
@@ -147,9 +147,14 @@
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/thecodingmachine/safe" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/lcobucci/jwt" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/lexik/jwt-authentication-bundle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/malio/ednotif-bundle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/monolog/monolog" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/monolog-bridge" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/monolog-bundle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/web-profiler-bundle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/data-fixtures" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/doctrine-fixtures-bundle" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/maker-bundle" />
|
||||
<excludePattern pattern="reference.php" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
|
||||
6
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
6
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="PhpCSFixerValidationInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
295
.idea/php.xml
generated
295
.idea/php.xml
generated
@@ -4,161 +4,183 @@
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCSFixerOptionsConfiguration">
|
||||
<option name="codingStandard" value="Custom" />
|
||||
<option name="rulesetPath" value="$PROJECT_DIR$/.php-cs-fixer.dist.php" />
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCodeSnifferOptionsConfiguration">
|
||||
<option name="highlightLevel" value="WARNING" />
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PhpCSFixer">
|
||||
<phpcsfixer_settings>
|
||||
<PhpCSFixerConfiguration tool_path="$PROJECT_DIR$/vendor/bin/php-cs-fixer" />
|
||||
</phpcsfixer_settings>
|
||||
</component>
|
||||
<component name="PhpCodeSniffer">
|
||||
<phpcs_settings>
|
||||
<phpcs_by_interpreter asDefaultInterpreter="true" interpreter_id="8475dcce-5d1d-4a2c-9e2f-7454868f1931" timeout="30000" />
|
||||
</phpcs_settings>
|
||||
</component>
|
||||
<component name="PhpIncludePathManager">
|
||||
<include_path>
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/framework-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/uid" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/log" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/event-dispatcher" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/clock" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/container" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/clue/ndjson-react" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/link" />
|
||||
<path value="$PROJECT_DIR$/vendor/fidry/cpu-core-counter" />
|
||||
<path value="$PROJECT_DIR$/vendor/twig/twig" />
|
||||
<path value="$PROJECT_DIR$/vendor/lexik/jwt-authentication-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/dns" />
|
||||
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/socket" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/child-process" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/event-loop" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/promise" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/stream" />
|
||||
<path value="$PROJECT_DIR$/vendor/dompdf/dompdf" />
|
||||
<path value="$PROJECT_DIR$/vendor/dompdf/php-font-lib" />
|
||||
<path value="$PROJECT_DIR$/vendor/nelmio/cors-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/dompdf/php-svg-lib" />
|
||||
<path value="$PROJECT_DIR$/vendor/monolog/monolog" />
|
||||
<path value="$PROJECT_DIR$/vendor/staabm/side-effects-detector" />
|
||||
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
|
||||
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpstan/phpdoc-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/var-dumper" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/runtime" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/string" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/css-selector" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-normalizer" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/cache-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/finder" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/asset" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/var-exporter" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/runtime" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/error-handler" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/translation-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/clock" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/twig-bridge" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/doctrine-bridge" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/type-info" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-migrations-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/deprecations" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/migrations" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/event-manager" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/lexer" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/orm" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/inflector" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/sql-formatter" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/common" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/collections" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/persistence" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/type" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/dbal" />
|
||||
<path value="$PROJECT_DIR$/vendor/evenement/evenement" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
|
||||
<path value="$PROJECT_DIR$/vendor/webmozart/assert" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/jsonld" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/hydra" />
|
||||
<path value="$PROJECT_DIR$/vendor/willdurand/negotiation" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/http-cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/serializer" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/doctrine-orm" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/validator" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/state" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/metadata" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/symfony" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/openapi" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/documentation" />
|
||||
<path value="$PROJECT_DIR$/vendor/friendsofphp/php-cs-fixer" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/type-resolver" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/json-schema" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/doctrine-common" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-common" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-docblock" />
|
||||
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/log" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/link" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/clock" />
|
||||
<path value="$PROJECT_DIR$/vendor/clue/ndjson-react" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/event-dispatcher" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/container" />
|
||||
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/promise" />
|
||||
<path value="$PROJECT_DIR$/vendor/twig/twig" />
|
||||
<path value="$PROJECT_DIR$/vendor/fidry/cpu-core-counter" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/stream" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/child-process" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/event-loop" />
|
||||
<path value="$PROJECT_DIR$/vendor/nelmio/cors-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/staabm/side-effects-detector" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/socket" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/dns" />
|
||||
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpstan/phpdoc-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
|
||||
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-client" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/flex" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/validator" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-csrf" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/dependency-injection" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/password-hasher" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-kernel" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/console" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/filesystem" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/web-link" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/serializer" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/css-selector" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/twig-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/process" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-http" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/config" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/clock" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/web-profiler-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/finder" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/browser-kit" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/options-resolver" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/password-hasher" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-core" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/dependency-injection" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-http" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/yaml" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/string" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/property-access" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-uuid" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/property-info" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/dom-crawler" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/var-dumper" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/expression-language" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/process" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-foundation" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php85" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/routing" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-core" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/dom-crawler" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/dotenv" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/stopwatch" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-client-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-client" />
|
||||
<path value="$PROJECT_DIR$/vendor/thecodingmachine/safe" />
|
||||
<path value="$PROJECT_DIR$/vendor/masterminds/html5" />
|
||||
<path value="$PROJECT_DIR$/vendor/dompdf/dompdf" />
|
||||
<path value="$PROJECT_DIR$/vendor/dompdf/php-svg-lib" />
|
||||
<path value="$PROJECT_DIR$/vendor/sabberworm/php-css-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/dompdf/php-font-lib" />
|
||||
<path value="$PROJECT_DIR$/vendor/lexik/jwt-authentication-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/lcobucci/jwt" />
|
||||
<path value="$PROJECT_DIR$/vendor/monolog/monolog" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/serializer" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/config" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/property-info" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/twig-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/monolog-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/stopwatch" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/options-resolver" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/error-handler" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/filesystem" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/framework-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-client-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php85" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-uuid" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/asset" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/twig-bridge" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/expression-language" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/console" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/web-link" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/property-access" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/doctrine-bridge" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-csrf" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-kernel" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/uid" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/validator" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/var-exporter" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/type-info" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/monolog-bridge" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/translation-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/routing" />
|
||||
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/sql-formatter" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/collections" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/common" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/dbal" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/orm" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/deprecations" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/migrations" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/lexer" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/persistence" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/event-manager" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-migrations-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/inflector" />
|
||||
<path value="$PROJECT_DIR$/vendor/evenement/evenement" />
|
||||
<path value="$PROJECT_DIR$/vendor/lcobucci/jwt" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/type" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
|
||||
<path value="$PROJECT_DIR$/vendor/webmozart/assert" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
|
||||
<path value="$PROJECT_DIR$/vendor/willdurand/negotiation" />
|
||||
<path value="$PROJECT_DIR$/vendor/sabberworm/php-css-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/http-cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/masterminds/html5" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/doctrine-common" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/documentation" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/metadata" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/doctrine-orm" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/hydra" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/symfony" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/jsonld" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/serializer" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/json-schema" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/openapi" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/validator" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/state" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-common" />
|
||||
<path value="$PROJECT_DIR$/vendor/friendsofphp/php-cs-fixer" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-docblock" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/type-resolver" />
|
||||
<path value="$PROJECT_DIR$/vendor/thecodingmachine/safe" />
|
||||
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||
<path value="$PROJECT_DIR$/vendor/malio/ednotif-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-fixtures-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/data-fixtures" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/maker-bundle" />
|
||||
</include_path>
|
||||
</component>
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="8.4" />
|
||||
<component name="PhpStan">
|
||||
<PhpStan_settings>
|
||||
<phpstan_by_interpreter asDefaultInterpreter="true" interpreter_id="8475dcce-5d1d-4a2c-9e2f-7454868f1931" timeout="60000" />
|
||||
</PhpStan_settings>
|
||||
</component>
|
||||
<component name="PhpStanOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
@@ -167,6 +189,11 @@
|
||||
<PhpUnitSettings custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" />
|
||||
</phpunit_settings>
|
||||
</component>
|
||||
<component name="Psalm">
|
||||
<Psalm_settings>
|
||||
<psalm_fixer_by_interpreter asDefaultInterpreter="true" interpreter_id="8475dcce-5d1d-4a2c-9e2f-7454868f1931" timeout="60000" />
|
||||
</Psalm_settings>
|
||||
</component>
|
||||
<component name="PsalmOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
|
||||
759
.idea/workspace.xml
generated
759
.idea/workspace.xml
generated
@@ -4,10 +4,16 @@
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="7c107abe-5995-4428-8429-b146aaca8386" name="Changes" comment="feat : Ajout du bundle Monolog pour la gestion des logs">
|
||||
<list default="true" id="7c107abe-5995-4428-8429-b146aaca8386" name="Changes" comment="feat : test auto-tag-develop.yml (auto incrément version)">
|
||||
<change afterPath="$PROJECT_DIR$/frontend/composables/useAppVersion.ts" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/config/packages/monolog.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/config/packages/monolog.yaml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/config/packages/security.yaml" beforeDir="false" afterPath="$PROJECT_DIR$/config/packages/security.yaml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/config/reference.php" beforeDir="false" afterPath="$PROJECT_DIR$/config/reference.php" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/frontend/app.vue" beforeDir="false" afterPath="$PROJECT_DIR$/frontend/app.vue" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/frontend/layouts/default.vue" beforeDir="false" afterPath="$PROJECT_DIR$/frontend/layouts/default.vue" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/frontend/pages/login.vue" beforeDir="false" afterPath="$PROJECT_DIR$/frontend/pages/login.vue" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/Dto/AppVersion.php" beforeDir="false" afterPath="$PROJECT_DIR$/src/ApiResource/AppVersion.php" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/State/AppVersionProvider.php" beforeDir="false" afterPath="$PROJECT_DIR$/src/State/AppVersionProvider.php" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -18,6 +24,11 @@
|
||||
<pharConfigPath>$PROJECT_DIR$/composer.json</pharConfigPath>
|
||||
<execution />
|
||||
</component>
|
||||
<component name="CopilotPersistence">
|
||||
<persistenceIdMap>
|
||||
<entry key="_//wsl.localhost/Ubuntu-24.04/home/kevin/Stage/Ferme" value="381AhnCm9yPeOiWgMObKHhtgv2C" />
|
||||
</persistenceIdMap>
|
||||
</component>
|
||||
<component name="EmbeddingIndexingInfo">
|
||||
<option name="cachedIndexableFilesCount" value="151" />
|
||||
<option name="fileBasedEmbeddingIndicesEnabled" value="true" />
|
||||
@@ -25,15 +36,15 @@
|
||||
<component name="FileTemplateManagerImpl">
|
||||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="TypeScript File" />
|
||||
<option value="Vue Composition API Component" />
|
||||
<option value="TypeScript File" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_BRANCH_BY_REPOSITORY">
|
||||
<map>
|
||||
<entry key="$PROJECT_DIR$" value="feat/202-connexion-utilisateur" />
|
||||
<entry key="$PROJECT_DIR$" value="feat/256-reception-etape-3-bovin" />
|
||||
</map>
|
||||
</option>
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
@@ -51,152 +62,157 @@
|
||||
</server>
|
||||
</servers>
|
||||
</component>
|
||||
<component name="PhpWorkspaceProjectConfiguration">
|
||||
<component name="PhpWorkspaceProjectConfiguration" interpreter_name="C:/php-8.4.3/php.exe">
|
||||
<include_path>
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/framework-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/uid" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/log" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/event-dispatcher" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/clock" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/container" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/clue/ndjson-react" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/link" />
|
||||
<path value="$PROJECT_DIR$/vendor/fidry/cpu-core-counter" />
|
||||
<path value="$PROJECT_DIR$/vendor/twig/twig" />
|
||||
<path value="$PROJECT_DIR$/vendor/lexik/jwt-authentication-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/dns" />
|
||||
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/socket" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/child-process" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/event-loop" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/promise" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/stream" />
|
||||
<path value="$PROJECT_DIR$/vendor/dompdf/dompdf" />
|
||||
<path value="$PROJECT_DIR$/vendor/dompdf/php-font-lib" />
|
||||
<path value="$PROJECT_DIR$/vendor/nelmio/cors-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/dompdf/php-svg-lib" />
|
||||
<path value="$PROJECT_DIR$/vendor/monolog/monolog" />
|
||||
<path value="$PROJECT_DIR$/vendor/staabm/side-effects-detector" />
|
||||
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
|
||||
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpstan/phpdoc-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/var-dumper" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/runtime" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/string" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/css-selector" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-normalizer" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/cache-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/finder" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/asset" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/var-exporter" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/runtime" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/error-handler" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/translation-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/clock" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/twig-bridge" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/doctrine-bridge" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/type-info" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-migrations-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/deprecations" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/migrations" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/event-manager" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/lexer" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/orm" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/inflector" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/sql-formatter" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/common" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/collections" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/persistence" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/type" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/dbal" />
|
||||
<path value="$PROJECT_DIR$/vendor/evenement/evenement" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
|
||||
<path value="$PROJECT_DIR$/vendor/webmozart/assert" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/jsonld" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/hydra" />
|
||||
<path value="$PROJECT_DIR$/vendor/willdurand/negotiation" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/http-cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/serializer" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/doctrine-orm" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/validator" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/state" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/metadata" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/symfony" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/openapi" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/documentation" />
|
||||
<path value="$PROJECT_DIR$/vendor/friendsofphp/php-cs-fixer" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/type-resolver" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/json-schema" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/doctrine-common" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-common" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-docblock" />
|
||||
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/log" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/link" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/clock" />
|
||||
<path value="$PROJECT_DIR$/vendor/clue/ndjson-react" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/event-dispatcher" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/container" />
|
||||
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/promise" />
|
||||
<path value="$PROJECT_DIR$/vendor/twig/twig" />
|
||||
<path value="$PROJECT_DIR$/vendor/fidry/cpu-core-counter" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/stream" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/child-process" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/event-loop" />
|
||||
<path value="$PROJECT_DIR$/vendor/nelmio/cors-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/staabm/side-effects-detector" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/socket" />
|
||||
<path value="$PROJECT_DIR$/vendor/react/dns" />
|
||||
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpstan/phpdoc-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
|
||||
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-invoker" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-client" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/flex" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/validator" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-csrf" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/dependency-injection" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/password-hasher" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-kernel" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/console" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/filesystem" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/web-link" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/serializer" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/css-selector" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/twig-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/process" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-http" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/config" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/clock" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/web-profiler-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/finder" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/browser-kit" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/options-resolver" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/password-hasher" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-core" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/dependency-injection" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-http" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/service-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/yaml" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-mbstring" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/string" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/property-access" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-uuid" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/property-info" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/dom-crawler" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/var-dumper" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/expression-language" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/deprecation-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/process" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-foundation" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php85" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/routing" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-core" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/dom-crawler" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/dotenv" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/stopwatch" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-client-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-client" />
|
||||
<path value="$PROJECT_DIR$/vendor/thecodingmachine/safe" />
|
||||
<path value="$PROJECT_DIR$/vendor/masterminds/html5" />
|
||||
<path value="$PROJECT_DIR$/vendor/dompdf/dompdf" />
|
||||
<path value="$PROJECT_DIR$/vendor/dompdf/php-svg-lib" />
|
||||
<path value="$PROJECT_DIR$/vendor/sabberworm/php-css-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/dompdf/php-font-lib" />
|
||||
<path value="$PROJECT_DIR$/vendor/lexik/jwt-authentication-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/lcobucci/jwt" />
|
||||
<path value="$PROJECT_DIR$/vendor/monolog/monolog" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/serializer" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/config" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/property-info" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/twig-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/monolog-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/stopwatch" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/options-resolver" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/error-handler" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/filesystem" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/framework-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-client-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php85" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-uuid" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/asset" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/twig-bridge" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/expression-language" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/console" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/web-link" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/property-access" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/doctrine-bridge" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/event-dispatcher-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/security-csrf" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/http-kernel" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/uid" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/validator" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-intl-grapheme" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/var-exporter" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/type-info" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/monolog-bridge" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/translation-contracts" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/routing" />
|
||||
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/sql-formatter" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/collections" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/common" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/dbal" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/orm" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/deprecations" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/migrations" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/lexer" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/persistence" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/event-manager" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-migrations-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/inflector" />
|
||||
<path value="$PROJECT_DIR$/vendor/evenement/evenement" />
|
||||
<path value="$PROJECT_DIR$/vendor/lcobucci/jwt" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/complexity" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/cli-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/type" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/lines-of-code" />
|
||||
<path value="$PROJECT_DIR$/vendor/webmozart/assert" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
|
||||
<path value="$PROJECT_DIR$/vendor/willdurand/negotiation" />
|
||||
<path value="$PROJECT_DIR$/vendor/sabberworm/php-css-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/http-cache" />
|
||||
<path value="$PROJECT_DIR$/vendor/masterminds/html5" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/doctrine-common" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/documentation" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/metadata" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/doctrine-orm" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/hydra" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/symfony" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/jsonld" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/serializer" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/json-schema" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/openapi" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/validator" />
|
||||
<path value="$PROJECT_DIR$/vendor/api-platform/state" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-common" />
|
||||
<path value="$PROJECT_DIR$/vendor/friendsofphp/php-cs-fixer" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-docblock" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/type-resolver" />
|
||||
<path value="$PROJECT_DIR$/vendor/thecodingmachine/safe" />
|
||||
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||
<path value="$PROJECT_DIR$/vendor/malio/ednotif-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-fixtures-bundle" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/data-fixtures" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/maker-bundle" />
|
||||
</include_path>
|
||||
</component>
|
||||
<component name="ProjectColorInfo">{
|
||||
@@ -209,47 +225,49 @@
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent"><![CDATA[{
|
||||
"keyToString": {
|
||||
"RunOnceActivity.MCP Project settings loaded": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
||||
"git-widget-placeholder": "develop",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"settings.editor.selected.configurable": "preferences.keymap",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
"RunOnceActivity.MCP Project settings loaded": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
||||
"git-widget-placeholder": "develop",
|
||||
"last_opened_file_path": "/home/sroy/Documents/test/Ferme",
|
||||
"node.js.detected.package.eslint": "true",
|
||||
"node.js.detected.package.tslint": "true",
|
||||
"node.js.selected.package.eslint": "(autodetect)",
|
||||
"node.js.selected.package.tslint": "(autodetect)",
|
||||
"nodejs_package_manager_path": "npm",
|
||||
"settings.editor.selected.configurable": "configurable.tailwindcss",
|
||||
"ts.external.directory.path": "/opt/phpstorm/plugins/javascript-plugin/jsLanguageServicesImpl/external",
|
||||
"vue.rearranger.settings.migration": "true"
|
||||
},
|
||||
"keyToStringList": {
|
||||
"DatabaseDriversLRU": [
|
||||
"postgresql"
|
||||
"keyToStringList": {
|
||||
"DatabaseDriversLRU": [
|
||||
"postgresql"
|
||||
],
|
||||
"com.intellij.ide.scratch.ScratchImplUtil$2/New Scratch File": [
|
||||
"TEXT"
|
||||
"com.intellij.ide.scratch.ScratchImplUtil$2/New Scratch File": [
|
||||
"TEXT"
|
||||
],
|
||||
"vue.recent.templates": [
|
||||
"Vue Composition API Component"
|
||||
"vue.recent.templates": [
|
||||
"Vue Composition API Component"
|
||||
]
|
||||
}
|
||||
}]]></component>
|
||||
}</component>
|
||||
<component name="RecentsManager">
|
||||
<key name="MoveFile.RECENT_KEYS">
|
||||
<recent name="\\wsl.localhost\Ubuntu-24.04\home\m-tristan\workspace\Ferme" />
|
||||
<recent name="\\wsl.localhost\Ubuntu-24.04\home\tristan\workspace\ferme\templates" />
|
||||
<recent name="C:\Users\autin\AppData\Roaming\JetBrains\PhpStorm2025.3\scratches" />
|
||||
<recent name="C:\Users\autin\AppData\Roaming\JetBrains\PhpStorm2025.3\scratches\Ferme_MCD\MCD_DOC" />
|
||||
<recent name="\\wsl.localhost\Ubuntu-24.04\home\tristan\workspace\ferme\frontend\pages\reception" />
|
||||
<recent name="\\wsl.localhost\Ubuntu-24.04\home\tristan\workspace\ferme\frontend\pages" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="SharedIndexes">
|
||||
<attachedChunks>
|
||||
<set>
|
||||
<option value="bundled-php-predefined-a98d8de5180a-0e0d91225499-com.jetbrains.php.sharedIndexes-PS-253.29346.257" />
|
||||
<option value="bundled-php-predefined-a98d8de5180a-0e0d91225499-com.jetbrains.php.sharedIndexes-PS-253.30387.85" />
|
||||
</set>
|
||||
</attachedChunks>
|
||||
</component>
|
||||
@@ -266,71 +284,23 @@
|
||||
<workItem from="1768374298711" duration="12403000" />
|
||||
<workItem from="1768460547451" duration="26946000" />
|
||||
<workItem from="1768547023783" duration="11371000" />
|
||||
<workItem from="1768894030675" duration="45508000" />
|
||||
</task>
|
||||
<task id="LOCAL-00001" summary="feat : Ajout de pinia, création de la table weight et reception mise en place du système de step pour les receptions (WIP)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1768237763998</created>
|
||||
<option name="number" value="00001" />
|
||||
<option name="presentableId" value="LOCAL-00001" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1768237763998</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00002" summary="feat : Ajout de zod, création d'un composant de chargement loading-dots.vue et finalisation du flow d'une reception">
|
||||
<option name="closed" value="true" />
|
||||
<created>1768316052474</created>
|
||||
<option name="number" value="00002" />
|
||||
<option name="presentableId" value="LOCAL-00002" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1768316052474</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00003" summary="feat : Ajout d'un composable pour la pesée qui sera réutilisable pour l'expédition, ajout de contrainte sur les entity de reception et weight pour plus de robustesse et correction de la class active des liens dans la nav">
|
||||
<option name="closed" value="true" />
|
||||
<created>1768316835575</created>
|
||||
<option name="number" value="00003" />
|
||||
<option name="presentableId" value="LOCAL-00003" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1768316835575</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00004" summary="feat : update du fichier AGENTS.md">
|
||||
<option name="closed" value="true" />
|
||||
<created>1768316965511</created>
|
||||
<option name="number" value="00004" />
|
||||
<option name="presentableId" value="LOCAL-00004" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1768316965511</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00005" summary="feat : update du fichier README.md et CHANGELOG.md">
|
||||
<option name="closed" value="true" />
|
||||
<created>1768317786187</created>
|
||||
<option name="number" value="00005" />
|
||||
<option name="presentableId" value="LOCAL-00005" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1768317786187</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00006" summary="fix : correction du useApi pour qu'il n'y ait plus de retry lors d'une erreur 500 par exemple">
|
||||
<option name="closed" value="true" />
|
||||
<created>1768318875533</created>
|
||||
<option name="number" value="00006" />
|
||||
<option name="presentableId" value="LOCAL-00006" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1768318875533</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00007" summary="test : ajout de TU sur les services et providers">
|
||||
<option name="closed" value="true" />
|
||||
<created>1768318921478</created>
|
||||
<option name="number" value="00007" />
|
||||
<option name="presentableId" value="LOCAL-00007" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1768318921478</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00008" summary="feat : ajout de la génération du bon de reception, correction de la base du formulaire multi-etape de reception et ajout d'une gestion d'erreur global">
|
||||
<option name="closed" value="true" />
|
||||
<created>1768498751836</created>
|
||||
<option name="number" value="00008" />
|
||||
<option name="presentableId" value="LOCAL-00008" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1768498751836</updated>
|
||||
<workItem from="1768894030675" duration="83922000" />
|
||||
<workItem from="1769413136483" duration="58000" />
|
||||
<workItem from="1769413279223" duration="40490000" />
|
||||
<workItem from="1769612160652" duration="23952000" />
|
||||
<workItem from="1769696465294" duration="8573000" />
|
||||
<workItem from="1769756623432" duration="21592000" />
|
||||
<workItem from="1770015653091" duration="73000" />
|
||||
<workItem from="1770040138216" duration="6492000" />
|
||||
<workItem from="1770050834470" duration="1873000" />
|
||||
<workItem from="1770054381680" duration="1292000" />
|
||||
<workItem from="1770055690365" duration="370000" />
|
||||
<workItem from="1770056515646" duration="21000" />
|
||||
<workItem from="1770102495553" duration="2280000" />
|
||||
<workItem from="1770195604082" duration="90000" />
|
||||
<workItem from="1770195718952" duration="215000" />
|
||||
<workItem from="1770195959162" duration="18915000" />
|
||||
<workItem from="1770274844804" duration="3940000" />
|
||||
</task>
|
||||
<task id="LOCAL-00009" summary="feat : ajout d'une gestion d'erreur au global côté front avec la lib toaster et I18n pour centraliser les messages d'erreur">
|
||||
<option name="closed" value="true" />
|
||||
@@ -452,7 +422,279 @@
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769075990984</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="24" />
|
||||
<task id="LOCAL-00024" summary="fix : affiche plus détail dans les logs en recette/prod">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769077633390</created>
|
||||
<option name="number" value="00024" />
|
||||
<option name="presentableId" value="LOCAL-00024" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769077633390</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00025" summary="fix : modification du script de déploiement pour corriger le problème d'écriture des logs de prod">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769079030808</created>
|
||||
<option name="number" value="00025" />
|
||||
<option name="presentableId" value="LOCAL-00025" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769079030808</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00026" summary="fix : doc de déploiement">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769094376813</created>
|
||||
<option name="number" value="00026" />
|
||||
<option name="presentableId" value="LOCAL-00026" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769094376813</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00027" summary="fix : doc et script de déploiement">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769096187792</created>
|
||||
<option name="number" value="00027" />
|
||||
<option name="presentableId" value="LOCAL-00027" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769096187792</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00028" summary="fix : doc et script de déploiement">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769097091268</created>
|
||||
<option name="number" value="00028" />
|
||||
<option name="presentableId" value="LOCAL-00028" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769097091268</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00029" summary="fix : gitea workflow">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769097476629</created>
|
||||
<option name="number" value="00029" />
|
||||
<option name="presentableId" value="LOCAL-00029" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769097476629</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00030" summary="fix : script de déploiement">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769098182184</created>
|
||||
<option name="number" value="00030" />
|
||||
<option name="presentableId" value="LOCAL-00030" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769098182184</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00031" summary="feat : ajout plus d'information sur la liste des réceptions côté front sur la page d'accueil">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769098861988</created>
|
||||
<option name="number" value="00031" />
|
||||
<option name="presentableId" value="LOCAL-00031" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769098861988</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00032" summary="fix : redirige sur le login sur une 401 et reset du auth state + doc + timeout du toaster">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769100048933</created>
|
||||
<option name="number" value="00032" />
|
||||
<option name="presentableId" value="LOCAL-00032" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769100048933</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00033" summary="feat : ajout de la debug bar en mod dev">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769177611987</created>
|
||||
<option name="number" value="00033" />
|
||||
<option name="presentableId" value="LOCAL-00033" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769177611987</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00034" summary="feat : ajout du bundle Malio ednotif pour l'utilisation des WS">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769184861047</created>
|
||||
<option name="number" value="00034" />
|
||||
<option name="presentableId" value="LOCAL-00034" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769184861047</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00035" summary="fix : modification de la conf du bundle ednotif">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769434793487</created>
|
||||
<option name="number" value="00035" />
|
||||
<option name="presentableId" value="LOCAL-00035" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769434793487</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00036" summary="feat : update du CHANGELOG.md">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769435038236</created>
|
||||
<option name="number" value="00036" />
|
||||
<option name="presentableId" value="LOCAL-00036" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769435038236</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00037" summary="feat : finalisation de l'étape 1 "Réception" (formulaire)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769529522614</created>
|
||||
<option name="number" value="00037" />
|
||||
<option name="presentableId" value="LOCAL-00037" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769529522614</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00038" summary="feat : ajout du numéro identification des receptions et ajustement du bon de reception">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769676223697</created>
|
||||
<option name="number" value="00038" />
|
||||
<option name="presentableId" value="LOCAL-00038" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769676223697</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00039" summary="feat : ajout de la partie reception des marchandises (étape 3) et modification du bon de réception">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769700808988</created>
|
||||
<option name="number" value="00039" />
|
||||
<option name="presentableId" value="LOCAL-00039" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769700808988</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00040" summary="feat : mise en place de composant UI pour les select, checkbox, date, text">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769705141157</created>
|
||||
<option name="number" value="00040" />
|
||||
<option name="presentableId" value="LOCAL-00040" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769705141157</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00041" summary="feat : update CHANGELOG.md">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769705240487</created>
|
||||
<option name="number" value="00041" />
|
||||
<option name="presentableId" value="LOCAL-00041" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769705240487</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00042" summary="feat : ajout de commentaire">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769760766200</created>
|
||||
<option name="number" value="00042" />
|
||||
<option name="presentableId" value="LOCAL-00042" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769760766200</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00043" summary="fix : correction de l'affichage de l'immatriculation sur une réception en cours + correction css étape 3 d'une réception">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769768517942</created>
|
||||
<option name="number" value="00043" />
|
||||
<option name="presentableId" value="LOCAL-00043" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769768517943</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00044" summary="feat : ajout de colonne pour les Supplier, Address et modification du numéro de réception">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769770092190</created>
|
||||
<option name="number" value="00044" />
|
||||
<option name="presentableId" value="LOCAL-00044" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769770092190</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00045" summary="feat : ajout de colonne pour les Supplier, Address. Modification du numéro de réception et ajout de fixtures">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769770142624</created>
|
||||
<option name="number" value="00045" />
|
||||
<option name="presentableId" value="LOCAL-00045" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769770142624</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00046" summary="feat : mise à jour du bon de réception">
|
||||
<option name="closed" value="true" />
|
||||
<created>1769782099473</created>
|
||||
<option name="number" value="00046" />
|
||||
<option name="presentableId" value="LOCAL-00046" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1769782099473</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00047" summary="feat : Ajout de la sélection des bovins étape 3 d'une réception (WIP)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1770131226364</created>
|
||||
<option name="number" value="00047" />
|
||||
<option name="presentableId" value="LOCAL-00047" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1770131226364</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00048" summary="feat : Ajout de la sélection des bovins étape 3 d'une réception (WIP)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1770206668867</created>
|
||||
<option name="number" value="00048" />
|
||||
<option name="presentableId" value="LOCAL-00048" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1770206668867</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00049" summary="feat : Ajout de la sélection des bovins étape 3 d'une réception (WIP)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1770217875423</created>
|
||||
<option name="number" value="00049" />
|
||||
<option name="presentableId" value="LOCAL-00049" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1770217875423</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00050" summary="feat : Ajout de la sélection des bovins étape 3 d'une réception (WIP)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1770283622425</created>
|
||||
<option name="number" value="00050" />
|
||||
<option name="presentableId" value="LOCAL-00050" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1770283622425</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00051" summary="feat : ajout du responsive sur la navbar et la page d'accueil">
|
||||
<option name="closed" value="true" />
|
||||
<created>1770308927948</created>
|
||||
<option name="number" value="00051" />
|
||||
<option name="presentableId" value="LOCAL-00051" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1770308927948</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00052" summary="fix : logo centré en mod mobile">
|
||||
<option name="closed" value="true" />
|
||||
<created>1770310504254</created>
|
||||
<option name="number" value="00052" />
|
||||
<option name="presentableId" value="LOCAL-00052" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1770310504254</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00053" summary="feat : ajout d'un numéro de version automatique via la CI">
|
||||
<option name="closed" value="true" />
|
||||
<created>1770369945257</created>
|
||||
<option name="number" value="00053" />
|
||||
<option name="presentableId" value="LOCAL-00053" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1770369945257</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00054" summary="feat : update numéro de version">
|
||||
<option name="closed" value="true" />
|
||||
<created>1770370216428</created>
|
||||
<option name="number" value="00054" />
|
||||
<option name="presentableId" value="LOCAL-00054" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1770370216428</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00055" summary="fix : auto-tag-develop.yml">
|
||||
<option name="closed" value="true" />
|
||||
<created>1770370700697</created>
|
||||
<option name="number" value="00055" />
|
||||
<option name="presentableId" value="LOCAL-00055" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1770370700698</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00056" summary="fix : auto-tag-develop.yml">
|
||||
<option name="closed" value="true" />
|
||||
<created>1770370919043</created>
|
||||
<option name="number" value="00056" />
|
||||
<option name="presentableId" value="LOCAL-00056" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1770370919043</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00057" summary="feat : test auto-tag-develop.yml (auto incrément version)">
|
||||
<option name="closed" value="true" />
|
||||
<created>1770371073055</created>
|
||||
<option name="number" value="00057" />
|
||||
<option name="presentableId" value="LOCAL-00057" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1770371073055</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="58" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
@@ -502,34 +744,43 @@
|
||||
</option>
|
||||
</component>
|
||||
<component name="VcsManagerConfiguration">
|
||||
<MESSAGE value="Feat : (WIP) Ajout de pinia, création de la table weight et reception mise en place du système de step pour les receptions" />
|
||||
<MESSAGE value="Feat : Ajout de pinia, création de la table weight et reception mise en place du système de step pour les receptions (WIP)" />
|
||||
<MESSAGE value="feat : Ajout de pinia, création de la table weight et reception mise en place du système de step pour les receptions (WIP)" />
|
||||
<MESSAGE value="feat : Ajout de zod, création d'un composant de chargement loading-dots.vue et finalisation du flow d'une reception" />
|
||||
<MESSAGE value="feat : Ajout d'un composable pour la pesée qui sera réutilisable pour l'expédition, ajout de contrainte sur les entity de reception et weight pour plus de robustesse et correction de la class active des liens dans la nav" />
|
||||
<MESSAGE value="feat : update du fichier AGENTS.md" />
|
||||
<MESSAGE value="feat : update du fichier README.md et CHANGELOG.md" />
|
||||
<MESSAGE value="fix : correction du useApi pour qu'il n'y ait plus de retry lors d'une erreur 500 par exemple" />
|
||||
<MESSAGE value="test : ajout de TU sur les services et providers" />
|
||||
<MESSAGE value="feat : ajout de la génération du bon de reception, correction de la base du formulaire multi-etape de reception et ajout d'une gestion d'erreur global" />
|
||||
<MESSAGE value="feat : ajout d'une gestion d'erreur au global côté front avec la lib toaster et I18n pour centraliser les messages d'erreur" />
|
||||
<MESSAGE value="feat : ajout de l'authentification avec lexik" />
|
||||
<MESSAGE value="fix : gitea workflow" />
|
||||
<MESSAGE value="fix : script de déploiement" />
|
||||
<MESSAGE value="feat : ajout plus d'information sur la liste des réceptions côté front sur la page d'accueil" />
|
||||
<MESSAGE value="fix : redirige sur le login sur une 401 et reset du auth state + doc + timeout du toaster" />
|
||||
<MESSAGE value="feat : ajout de la debug bar en mod dev" />
|
||||
<MESSAGE value="feat : ajout du bundle Malio ednotif pour l'utilisation des WS" />
|
||||
<MESSAGE value="fix : modification de la conf du bundle ednotif" />
|
||||
<MESSAGE value="feat : update du CHANGELOG.md" />
|
||||
<MESSAGE value="fix : correction de l'accès au swagger en mode dev qui n'était plus accessible" />
|
||||
<MESSAGE value="feat : ajout de la conf pour le déploiement en recette" />
|
||||
<MESSAGE value="fix : fix de la conf pour le déploiement en recette" />
|
||||
<MESSAGE value="fix : migration apache vers nginx pour un déploiement plus simple" />
|
||||
<MESSAGE value="fix : dernière modification pour le déploiement en recette et le changement de conf vers nginx" />
|
||||
<MESSAGE value="ci: auto tag + release artefact" />
|
||||
<MESSAGE value="ci : auto tag + release artefact" />
|
||||
<MESSAGE value="ci : fix release artefact" />
|
||||
<MESSAGE value="ci : ajout du script et de la doc déploiement" />
|
||||
<MESSAGE value="fix : correction du path URI pour la création d'un poids dans une réception" />
|
||||
<MESSAGE value="feat : Ajout du bundle Monolog pour la gestion des logs" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="feat : Ajout du bundle Monolog pour la gestion des logs" />
|
||||
<MESSAGE value="feat : finalisation de l'étape 1 "Réception" (formulaire)" />
|
||||
<MESSAGE value="feat : ajout du numéro identification des receptions et ajustement du bon de reception" />
|
||||
<MESSAGE value="feat : ajout de la partie reception des marchandises (étape 3) et modification du bon de réception" />
|
||||
<MESSAGE value="feat : mise en place de composant UI pour les select, checkbox, date, text" />
|
||||
<MESSAGE value="feat : update CHANGELOG.md" />
|
||||
<MESSAGE value="feat : ajout de commentaire" />
|
||||
<MESSAGE value="fix : correction de l'affichage de l'immatriculation sur une réception en cours + correction css étape 3 d'une réception" />
|
||||
<MESSAGE value="feat : ajout de colonne pour les Supplier, Address et modification du numéro de réception" />
|
||||
<MESSAGE value="feat : ajout de colonne pour les Supplier, Address. Modification du numéro de réception et ajout de fixtures" />
|
||||
<MESSAGE value="feat : mise à jour du bon de réception" />
|
||||
<MESSAGE value="feat : Ajout de la sélection des bovins étape 3 d'une réception (WIP)" />
|
||||
<MESSAGE value="feat : ajout du responsive sur la navbar et la page d'accueil" />
|
||||
<MESSAGE value="fix : logo centré en mod mobile" />
|
||||
<MESSAGE value="feat : ajout d'un numéro de version automatique via la CI" />
|
||||
<MESSAGE value="feat : update numéro de version" />
|
||||
<MESSAGE value="fix : auto-tag-develop.yml" />
|
||||
<MESSAGE value="feat : test auto-tag-develop.yml (auto incrément version)" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="feat : test auto-tag-develop.yml (auto incrément version)" />
|
||||
</component>
|
||||
<component name="XSLT-Support.FileAssociations.UIState">
|
||||
<expand />
|
||||
<select />
|
||||
</component>
|
||||
<component name="github-copilot-workspace">
|
||||
<instructionFileLocations>
|
||||
<option value=".github/instructions" />
|
||||
</instructionFileLocations>
|
||||
<promptFileLocations>
|
||||
<option value=".github/prompts" />
|
||||
</promptFileLocations>
|
||||
</component>
|
||||
</project>
|
||||
13
AGENTS.md
13
AGENTS.md
@@ -10,6 +10,7 @@ Backend conventions
|
||||
- API Platform operations are defined on Doctrine entities.
|
||||
- Reception entity is in `src/Entity/Reception.php`, with custom weigh endpoint `/receptions/weigh`.
|
||||
- Reception fields: `date_reception`, `license_plate`, `current_step` (default 0), `is_valid` (default false).
|
||||
- Reception also has `identification_number` (auto `N-BR-####`), `merchandise_type`, `merchandise_detail`, `buildings` (M2M), and `pellet_buildings` (via `reception_pellet_building`).
|
||||
- `date_reception` is set by the UI, stored as `DateTimeImmutable`, serialized as `Y-m-d`.
|
||||
- Weight entity (`src/Entity/Weight.php`) is 1–N with Reception, each row stores `type` (`gross` or `tare`), `dsd`, `weight`, `weighed_at` (all nullable except `type`).
|
||||
- Weigh endpoint `/receptions/weigh` returns `PontBasculeReading` with `dsd`, `weight`, `weighedAt` (formatted `Y-m-d`).
|
||||
@@ -21,6 +22,7 @@ Frontend conventions
|
||||
- Nuxt SSR disabled; Tailwind used.
|
||||
- Layout in `frontend/layouts/default.vue`: max width `1050px`, header full width.
|
||||
- Tailwind custom color palette is `primary` (e.g. `bg-primary-500`).
|
||||
- Global font stack uses Helvetica via Tailwind (`font-sans`) and `frontend/assets/css/main.css`.
|
||||
- API composable in `frontend/composables/useApi.ts` with `get/post/put/patch/delete` and default JSON/PATCH content types.
|
||||
- API errors/success toasts can be customized via `toastErrorMessage`/`toastSuccessMessage` or i18n keys `toastErrorKey`/`toastSuccessKey`. Global method fallbacks use `errors.http.*` keys.
|
||||
- `useApi` uses `useNuxtApp().$i18n` (not `useI18n`) to avoid setup-only constraint in service calls.
|
||||
@@ -28,6 +30,7 @@ Frontend conventions
|
||||
- Zod is used for form validation (e.g. `frontend/components/reception/reception-form.vue`); shared helpers live in `frontend/utils/zod-errors.ts`.
|
||||
- Weighing logic is shared via `frontend/composables/useWeighing.ts`.
|
||||
- Reception step UI uses store state (`currentStep`) in `frontend/pages/reception/[[id]].vue`.
|
||||
- Step 2 uses `frontend/components/reception/reception-product-received.vue` for merchandise selection; type codes in `frontend/utils/constants.ts`.
|
||||
- Active nav styles in header use `NuxtLink` with `custom` slot.
|
||||
- Reusable UI components live under `frontend/components/ui/` and are auto-imported with `Ui` prefix (e.g. `UiLoadingDots`).
|
||||
- Service layer lives in `frontend/services/` with typed DTOs in `frontend/services/dto/`.
|
||||
@@ -44,3 +47,13 @@ Environment & routing
|
||||
Notes
|
||||
- Do not add a GET that creates resources; use POST + PATCH.
|
||||
- Keep endpoints in plural (API Platform convention).
|
||||
- New reference data added:
|
||||
- Reception types (`reception_type`, fields: `label`, `code`), selectable on reception form.
|
||||
- Merchandise types (`merchandise_type`, fields: `label`, `code`) and pellet types (`pellet_type`, fields: `label`, `code`).
|
||||
- Buildings (`building`, fields: `label`, `code`) and reception allocations (`reception_building` M2M, `reception_pellet_building` unique on reception/pellet/building).
|
||||
- Suppliers (`supplier`) with addresses (`address`, fields: `label`, `street`, `postal_code`, `city`, `country_code` ISO2), via `supplier_address` join table.
|
||||
- Trucks (`truck`, field: `name`), linked to receptions.
|
||||
- Carriers (`carrier`, fields: `name`, nullable `code`), Drivers (`driver`, fields: `name`, `carrier_id`), Vehicles (`vehicle`, fields: `plate`, `carrier_id`, `truck_id`) used for LIOT logic.
|
||||
- Reception links: `reception_type_id`, `supplier_id`, `address_id`, `truck_id`, `carrier_id`, `driver_id`, `user_id`.
|
||||
- Address exposes `fullAddress` via getter for display.
|
||||
- LIOT behavior in reception form: if carrier code = `LIOT`, show driver + vehicle selects and hide manual license plate input; vehicle list filters by truck type and carrier; selected vehicle sets `license_plate`.
|
||||
|
||||
@@ -13,6 +13,10 @@ Ajouter dans le fichier .env
|
||||
- JWT_PUBLIC_KEY
|
||||
- JWT_PASSPHRASE (à généré dans le conteneur avec la commande php -r "echo bin2hex(random_bytes(32));")
|
||||
- COOKIE_SECURE=0 (en dev 0 et en prod 1)
|
||||
- EDNOTIF_EXPLOITATION_CODE
|
||||
- EDNOTIF_EXPLOITATION_NUMERO
|
||||
- EDNOTIF_LOGIN
|
||||
- EDNOTIF_PASSWORD
|
||||
|
||||
Ajouter dans le fichier .env du frontend
|
||||
- NUXT_PUBLIC_API_BASE
|
||||
@@ -20,6 +24,11 @@ Ajouter dans le fichier .env du frontend
|
||||
### Added
|
||||
* [#203] Réceptions — Parcours de pesée multi-étapes (début)
|
||||
* [#202] Authentification — Connexion utilisateur (JWT)
|
||||
* Ajout du bundle malio/ednotif-bundle
|
||||
* Ajout de composant UI
|
||||
* Finalisation de la partie réception de marchandise
|
||||
* [#267] Lister les réceptions en attente
|
||||
* [#268] Lister les réceptions terminées
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
@@ -68,10 +68,21 @@
|
||||
|
||||
1. Créer un tag sur `develop` (auto-tag `v0.0.X`)
|
||||
2. Attendre que la release Gitea soit publiée
|
||||
3. Déployer la release
|
||||
3. (Une seule fois) Donner les droits d'écriture à PHP sur `var/` via ACL
|
||||
```bash
|
||||
sudo DEPLOY_OWNER=malio /usr/local/bin/deploy-ferme v0.0.X
|
||||
sudo apt update
|
||||
sudo apt install -y acl
|
||||
sudo setfacl -R -m u:malio:rwx,g:www-data:rwx /var/www/ferme/var
|
||||
sudo setfacl -R -m d:u:malio:rwx,d:g:www-data:rwx /var/www/ferme/var
|
||||
```
|
||||
4. Déployer la release
|
||||
```bash
|
||||
/usr/local/bin/deploy-ferme vX.Y.Z
|
||||
```
|
||||
Notes :
|
||||
- Lancer le déploiement en tant que `malio` (ou `sudo -u malio`) pour éviter de casser les droits.
|
||||
- Le script applique `umask 002` pour garder les fichiers group-writable (`www-data`).
|
||||
- Le script force des droits d'exécution minimaux sur `/var/www` et `/var/www/ferme` pour éviter un blocage Nginx.
|
||||
|
||||
### Vérifications
|
||||
- Front : `http://ferme.malio-dev.fr/`
|
||||
|
||||
18
README.md
18
README.md
@@ -28,7 +28,7 @@ Vérifier que dans le .env.local, vous avez :
|
||||
* JWT_SECRET_KEY (à générer avec la commande php bin/console lexik:jwt:generate-keypair)
|
||||
* JWT_PUBLIC_KEY
|
||||
* JWT_PASSPHRASE (à généré dans le conteneur avec la commande php -r "echo bin2hex(random_bytes(32));")
|
||||
* COOKIE_SECURE=0 (en dev 0 et en prod 1)
|
||||
* COOKIE_SECURE=0 (en dev 0 et en prod 1. Si c'est du http, laisser en 0)
|
||||
|
||||
Vérifier que dans le .env du dossier frontend, vous avez :
|
||||
* NUXT_PUBLIC_API_BASE="http://localhost:8080/api"
|
||||
@@ -71,6 +71,18 @@ Le frontend ne lit jamais directement le token, le navigateur envoie automatique
|
||||
- Le cookie est automatiquement envoyé pour les futures requêtes.
|
||||
- La déconnexion utilise `POST /api/logout` et redirige vers `/login`.
|
||||
|
||||
### Fixtures
|
||||
Pour lancer les fixtures (Attention sa purge la bdd complètement)
|
||||
```bash
|
||||
php bin/console doctrine:fixtures:load
|
||||
```
|
||||
|
||||
Attention cette commande est dangereuse, à utiliser que pour les débuts de la prod ou en recette.
|
||||
Dans un premier temps pour remplir les listes, vous pouvez lancer la commande symfony
|
||||
```bash
|
||||
php bin/console app:seed
|
||||
```
|
||||
La commande va faire une update ou une création en fonction des data existante.
|
||||
|
||||
## Livraison en recette
|
||||
### Préparatifs
|
||||
@@ -82,8 +94,8 @@ Sur la machine, il est disponible dans /usr/local/bin/deploy-ferme <br>
|
||||
Pour le modifier, il faut copier le contenu du deploy-release.sh dans le deploy-ferme
|
||||
### Livraison
|
||||
Sur le serveur de recette, il suffit d'utiliser cette commande pour livrer
|
||||
```bash
|
||||
sudo DEPLOY_OWNER=malio /usr/local/bin/deploy-ferme vX.X.X
|
||||
```bash
|
||||
/usr/local/bin/deploy-ferme vX.Y.Z
|
||||
```
|
||||
## Commandes utiles
|
||||
Pour restart le container
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
"doctrine/orm": "^3.6",
|
||||
"dompdf/dompdf": "^3.1",
|
||||
"lexik/jwt-authentication-bundle": "*",
|
||||
"malio/ednotif-bundle": ">=0.0.4",
|
||||
"nelmio/cors-bundle": "^2.6",
|
||||
"phpdocumentor/reflection-docblock": "^5.6",
|
||||
"phpstan/phpdoc-parser": "^2.3",
|
||||
@@ -87,9 +88,19 @@
|
||||
}
|
||||
},
|
||||
"require-dev": {
|
||||
"doctrine/doctrine-fixtures-bundle": "^4.3",
|
||||
"friendsofphp/php-cs-fixer": "^3.92",
|
||||
"phpunit/phpunit": "^12.5",
|
||||
"symfony/browser-kit": "8.0.*",
|
||||
"symfony/css-selector": "8.0.*"
|
||||
}
|
||||
"symfony/css-selector": "8.0.*",
|
||||
"symfony/maker-bundle": "^1.65",
|
||||
"symfony/stopwatch": "8.0.*",
|
||||
"symfony/web-profiler-bundle": "8.0.*"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://gitea.malio.fr/MALIO-DEV/ednotif-bundle"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
951
composer.lock
generated
951
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -4,13 +4,17 @@ declare(strict_types=1);
|
||||
|
||||
use ApiPlatform\Symfony\Bundle\ApiPlatformBundle;
|
||||
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
|
||||
use Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle;
|
||||
use Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle;
|
||||
use Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle;
|
||||
use Malio\EdnotifBundle\EdnotifBundle;
|
||||
use Nelmio\CorsBundle\NelmioCorsBundle;
|
||||
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
|
||||
use Symfony\Bundle\MakerBundle\MakerBundle;
|
||||
use Symfony\Bundle\MonologBundle\MonologBundle;
|
||||
use Symfony\Bundle\SecurityBundle\SecurityBundle;
|
||||
use Symfony\Bundle\TwigBundle\TwigBundle;
|
||||
use Symfony\Bundle\WebProfilerBundle\WebProfilerBundle;
|
||||
|
||||
return [
|
||||
FrameworkBundle::class => ['all' => true],
|
||||
@@ -22,4 +26,8 @@ return [
|
||||
LexikJWTAuthenticationBundle::class => ['all' => true],
|
||||
ApiPlatformBundle::class => ['all' => true],
|
||||
MonologBundle::class => ['all' => true],
|
||||
EdnotifBundle::class => ['all' => true],
|
||||
WebProfilerBundle::class => ['dev' => true],
|
||||
DoctrineFixturesBundle::class => ['dev' => true, 'test' => true],
|
||||
MakerBundle::class => ['dev' => true],
|
||||
];
|
||||
|
||||
13
config/packages/ednotif.yaml
Normal file
13
config/packages/ednotif.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
ednotif:
|
||||
guichet_wsdl: 'https://ws-reswel-elv.equade.fr/wsguichet/WsGuichet?wsdl'
|
||||
metier_wsdl: 'https://ws-ednotif.equade.fr/wsIpBNotif/wsIpBNotif?wsdl'
|
||||
exploitation_code: '%env(string:EDNOTIF_EXPLOITATION_CODE)%'
|
||||
exploitation_number: '%env(string:EDNOTIF_EXPLOITATION_NUMERO)%'
|
||||
exploitation_country_code: 'FR'
|
||||
login: '%env(string:EDNOTIF_LOGIN)%'
|
||||
password: '%env(string:EDNOTIF_PASSWORD)%'
|
||||
token_ttl_seconds: 900
|
||||
soap_options:
|
||||
trace: false
|
||||
exceptions: true
|
||||
connection_timeout: 15
|
||||
@@ -53,6 +53,8 @@ security:
|
||||
- { path: ^/api/users, roles: PUBLIC_ACCESS, methods: [GET] }
|
||||
# Doc API (swagger) en public
|
||||
- { path: ^/api/docs, roles: PUBLIC_ACCESS }
|
||||
# Version de l'application en public
|
||||
- { path: ^/api/version, roles: PUBLIC_ACCESS, methods: [GET] }
|
||||
# Tout le reste nécessite un JWT
|
||||
- { path: ^/, roles: IS_AUTHENTICATED_FULLY }
|
||||
|
||||
|
||||
7
config/packages/web_profiler.yaml
Normal file
7
config/packages/web_profiler.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
when@dev:
|
||||
web_profiler:
|
||||
toolbar: true
|
||||
|
||||
framework:
|
||||
profiler:
|
||||
collect_serializer_data: true
|
||||
1502
config/reference.php
1502
config/reference.php
File diff suppressed because it is too large
Load Diff
8
config/routes/web_profiler.yaml
Normal file
8
config/routes/web_profiler.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
when@dev:
|
||||
web_profiler_wdt:
|
||||
resource: '@WebProfilerBundle/Resources/config/routing/wdt.php'
|
||||
prefix: /_wdt
|
||||
|
||||
web_profiler_profiler:
|
||||
resource: '@WebProfilerBundle/Resources/config/routing/profiler.php'
|
||||
prefix: /_profiler
|
||||
@@ -8,6 +8,9 @@
|
||||
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
|
||||
parameters:
|
||||
|
||||
imports:
|
||||
- { resource: version.yaml }
|
||||
|
||||
services:
|
||||
# default configuration for services in *this* file
|
||||
_defaults:
|
||||
|
||||
2
config/version.yaml
Normal file
2
config/version.yaml
Normal file
@@ -0,0 +1,2 @@
|
||||
parameters:
|
||||
app.version: '0.0.32'
|
||||
@@ -14,6 +14,8 @@ services:
|
||||
XDEBUG_CLIENT_HOST: ${XDEBUG_CLIENT_HOST:-host.docker.internal}
|
||||
XDEBUG_CONFIG: client_host=${XDEBUG_CLIENT_HOST:-host.docker.internal} client_port=9003
|
||||
DATABASE_URL: "postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}?serverVersion=16&charset=utf8"
|
||||
COMPOSER_HOME: /tmp/composer
|
||||
COMPOSER_CACHE_DIR: /tmp/composer/cache
|
||||
volumes:
|
||||
- ./:/var/www/html
|
||||
- ~/.cache:/var/www/.cache # Pour la cache de composer
|
||||
|
||||
@@ -7,3 +7,5 @@ POSTGRES_USER=root
|
||||
POSTGRES_PASSWORD=root
|
||||
POSTGRES_PORT=5432
|
||||
XDEBUG_CLIENT_HOST=host.docker.internal
|
||||
CURRENT_UID=1004
|
||||
CURRENT_GID=1004
|
||||
|
||||
@@ -10,6 +10,16 @@ server {
|
||||
try_files $uri /index.php?$query_string;
|
||||
}
|
||||
|
||||
location ^~ /_wdt/ {
|
||||
root /var/www/html/public;
|
||||
try_files $uri /index.php?$query_string;
|
||||
}
|
||||
|
||||
location ^~ /_profiler/ {
|
||||
root /var/www/html/public;
|
||||
try_files $uri /index.php?$query_string;
|
||||
}
|
||||
|
||||
location ^~ /bundles/ {
|
||||
root /var/www/html/public;
|
||||
try_files $uri =404;
|
||||
|
||||
@@ -102,6 +102,11 @@ RUN docker-php-ext-enable opcache
|
||||
RUN rm -rf /var/cache/apk/* && rm -rf /tmp/* && \
|
||||
curl --insecure https://getcomposer.org/composer.phar -o /usr/bin/composer && chmod +x /usr/bin/composer
|
||||
|
||||
# cache Composer pour www-data
|
||||
RUN mkdir -p /var/www/.composer/cache/vcs \
|
||||
&& chown -R www-data:www-data /var/www/.composer
|
||||
ENV COMPOSER_HOME=/var/www/.composer
|
||||
|
||||
# Création de la structure du projet
|
||||
RUN mkdir /var/www/html/LOG
|
||||
|
||||
|
||||
@@ -3,3 +3,11 @@
|
||||
<NuxtPage />
|
||||
</NuxtLayout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const { load } = useAppVersion()
|
||||
|
||||
onMounted(() => {
|
||||
load()
|
||||
})
|
||||
</script>
|
||||
|
||||
9
frontend/assets/css/main.css
Normal file
9
frontend/assets/css/main.css
Normal file
@@ -0,0 +1,9 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
body {
|
||||
@apply font-sans;
|
||||
}
|
||||
}
|
||||
30
frontend/components/card-link.vue
Normal file
30
frontend/components/card-link.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
|
||||
<template>
|
||||
<NuxtLink :to="link">
|
||||
<div class="w-[324px] h-[228px] border border-black rounded-md p-6 flex flex-col justify-between">
|
||||
<div class="flex justify-between">
|
||||
<div class="rounded-full w-[80px] h-[80px] bg-neutral-400 flex justify-center items-center">
|
||||
<Icon :name="iconName" style="color: black" size="44" />
|
||||
</div>
|
||||
<div>
|
||||
<Icon name="mdi:plus" style="color: black" size="44" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="uppercase font-bold">
|
||||
<p class="text-3xl"> {{ label }} </p>
|
||||
</div>
|
||||
</div>
|
||||
</NuxtLink>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
link: string
|
||||
iconName: string
|
||||
label: string
|
||||
}>()
|
||||
</script>
|
||||
|
||||
183
frontend/components/reception/reception-bovine-received.vue
Normal file
183
frontend/components/reception/reception-bovine-received.vue
Normal file
@@ -0,0 +1,183 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="receptionStore.current?.receptionType?.code === RECEPTION_TYPE_CODES.BOVINS"
|
||||
class="flex flex-col items-center gap-16">
|
||||
<h1 class="text-4xl uppercase font-bold">Sélection des marchandises réceptionnnées</h1>
|
||||
<div
|
||||
class="flex flex-row gap-8 items-center">
|
||||
<div
|
||||
v-for="type in bovineType"
|
||||
:key="type.id"
|
||||
class="mt-8 flex flex-row mb-2 gap-6">
|
||||
<UiNumberInput
|
||||
:label="type.label"
|
||||
:code="type.code"
|
||||
v-model="bovineQuantities[String(type.id)]"
|
||||
:placeholder="0"
|
||||
:min="0"
|
||||
:max="10"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="mt-8 flex flex-row mb-2 gap-6">
|
||||
<UiNumberInput
|
||||
label="Autres"
|
||||
v-model="otherQuantity"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]"
|
||||
@click="goNext"
|
||||
>Peser
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import type {BovineTypeData} from "~/services/dto/bovine-type-data";
|
||||
import {getBovineTypeList} from "~/services/bovine-type";
|
||||
import {RECEPTION_TYPE_CODES} from "~/utils/constants";
|
||||
import {useReceptionStore} from '~/stores/reception'
|
||||
import {
|
||||
createReceptionBovine,
|
||||
deleteReceptionBovine,
|
||||
getReceptionBovineList,
|
||||
updateReceptionBovine
|
||||
} from "~/services/reception-bovine";
|
||||
import {computed, onMounted, reactive, ref, watch} from "vue";
|
||||
|
||||
const toast = useToast()
|
||||
const isLoadingBovineType = ref(false)
|
||||
const bovineType = ref<BovineTypeData[]>([])
|
||||
const receptionStore = useReceptionStore()
|
||||
const bovineQuantities = reactive<Record<string, number | null>>({})
|
||||
const otherQuantity = ref<number | null>(0)
|
||||
const receptionId = computed(() => receptionStore.current?.id ?? null)
|
||||
const receptionIri = computed(() =>
|
||||
receptionId.value ? `/api/receptions/${receptionId.value}` : null
|
||||
)
|
||||
const totalBovines = computed(() => {
|
||||
const base = Object.values(bovineQuantities).reduce((sum, value) => {
|
||||
return sum + (value ?? 0)
|
||||
}, 0)
|
||||
return base + (otherQuantity.value ?? 0)
|
||||
})
|
||||
|
||||
const loadBovineType = async () => {
|
||||
isLoadingBovineType.value = true
|
||||
try {
|
||||
bovineType.value = await getBovineTypeList()
|
||||
} finally {
|
||||
isLoadingBovineType.value = false
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await loadBovineType()
|
||||
})
|
||||
|
||||
watch(
|
||||
() => receptionId.value,
|
||||
async (id) => {
|
||||
if (!id || !receptionIri.value) {
|
||||
return
|
||||
}
|
||||
|
||||
const selectionMap: Record<string, number | null> = {}
|
||||
for (const type of bovineType.value) {
|
||||
selectionMap[String(type.id)] = 0
|
||||
}
|
||||
|
||||
const existing = await getReceptionBovineList(receptionIri.value)
|
||||
for (const selection of existing) {
|
||||
const bovineTypeId = String(selection.bovineType.id)
|
||||
selectionMap[bovineTypeId] = selection.quantity ?? 0
|
||||
}
|
||||
|
||||
for (const key of Object.keys(bovineQuantities)) {
|
||||
delete bovineQuantities[key]
|
||||
}
|
||||
Object.assign(bovineQuantities, selectionMap)
|
||||
|
||||
const existingOther = receptionStore.current?.bovineDetail
|
||||
const parsedOther =
|
||||
typeof existingOther === 'string' && existingOther.trim() !== ''
|
||||
? Number(existingOther)
|
||||
: 0
|
||||
otherQuantity.value = Number.isFinite(parsedOther) ? parsedOther : 0
|
||||
},
|
||||
{immediate: true}
|
||||
)
|
||||
|
||||
async function syncBovineSelections(receptionIri: string) {
|
||||
const existing = await getReceptionBovineList(receptionIri)
|
||||
const existingMap = new Map<string, { id: number; quantity: number | null }>()
|
||||
|
||||
for (const selection of existing) {
|
||||
const bovineTypeId = String(selection.bovineType.id)
|
||||
existingMap.set(bovineTypeId, {
|
||||
id: selection.id,
|
||||
quantity: selection.quantity ?? 0
|
||||
})
|
||||
}
|
||||
|
||||
// Supprime les entrées supprimées ou modifiées
|
||||
for (const [bovineTypeId, entry] of existingMap.entries()) {
|
||||
const selectedQuantity = bovineQuantities[bovineTypeId] ?? 0
|
||||
if (!selectedQuantity) {
|
||||
await deleteReceptionBovine(entry.id)
|
||||
existingMap.delete(bovineTypeId)
|
||||
continue
|
||||
}
|
||||
|
||||
if (selectedQuantity !== entry.quantity) {
|
||||
await updateReceptionBovine(entry.id, {quantity: selectedQuantity})
|
||||
existingMap.set(bovineTypeId, {
|
||||
id: entry.id,
|
||||
quantity: selectedQuantity
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Crée les entrées manquantes
|
||||
for (const [bovineTypeId, quantity] of Object.entries(bovineQuantities)) {
|
||||
if (!quantity) {
|
||||
continue
|
||||
}
|
||||
if (existingMap.has(bovineTypeId)) {
|
||||
// Déjà à jour
|
||||
continue
|
||||
}
|
||||
await createReceptionBovine({
|
||||
reception: receptionIri,
|
||||
bovineType: `/api/bovine_types/${bovineTypeId}`,
|
||||
quantity
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async function goNext() {
|
||||
if (!receptionStore.current || !receptionIri.value) {
|
||||
return
|
||||
}
|
||||
|
||||
// @TODO Ajouter un composable pour le toaster qui gère les key i18n
|
||||
if (totalBovines.value > 52) {
|
||||
toast.error({
|
||||
title: 'Erreur',
|
||||
message: ('Le total des bovins ne peut pas dépasser 52.')
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const nextStep = receptionStore.current.currentStep + 1
|
||||
await syncBovineSelections(receptionIri.value)
|
||||
|
||||
await receptionStore.updateReception(receptionStore.current.id, {
|
||||
merchandiseType: null,
|
||||
merchandiseDetail: null,
|
||||
bovineDetail: otherQuantity.value ? String(otherQuantity.value) : null,
|
||||
currentStep: nextStep
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -1,22 +1,119 @@
|
||||
<template>
|
||||
<form @submit.prevent="validate">
|
||||
<div class="grid grid-cols-1 items-start gap-8 mb-16">
|
||||
<h1 class="font-bold text-5xl uppercase">Réception</h1>
|
||||
<div>
|
||||
<div class="grid grid-cols-2 items-start gap-y-8 gap-x-40 mb-16">
|
||||
<h1 class="font-bold text-5xl uppercase col-start-1 row-start-1">Réception</h1>
|
||||
<!-- Nom de l'utilisateur -->
|
||||
<UiSelect
|
||||
id="reception-user"
|
||||
v-model="form.userId"
|
||||
label="Nom de l'utilisateur"
|
||||
:options="users.map((user) => ({
|
||||
value: String(user.id),
|
||||
label: user.username
|
||||
}))"
|
||||
:loading="isLoadingUsers"
|
||||
wrapper-class="col-start-1 row-start-2"
|
||||
/>
|
||||
<!-- Date de réception -->
|
||||
<UiDateInput
|
||||
id="reception-date"
|
||||
v-model="form.receptionDate"
|
||||
label="Date de réception"
|
||||
wrapper-class="col-start-1 row-start-3"
|
||||
/>
|
||||
<!-- Type de réception -->
|
||||
<UiSelect
|
||||
id="reception-type"
|
||||
v-model="form.receptionTypeId"
|
||||
label="Type de réception"
|
||||
:options="receptionTypes.map((type) => ({
|
||||
value: String(type.id),
|
||||
label: type.label
|
||||
}))"
|
||||
wrapper-class="col-start-1 row-start-4"
|
||||
/>
|
||||
<!-- Fournisseur -->
|
||||
<UiSelect
|
||||
id="reception-supplier"
|
||||
v-model="form.supplierId"
|
||||
label="Fournisseur"
|
||||
:options="suppliers.map((supplier) => ({
|
||||
value: String(supplier.id),
|
||||
label: supplier.name
|
||||
}))"
|
||||
:loading="isLoadingSuppliers"
|
||||
wrapper-class="col-start-1 row-start-5"
|
||||
/>
|
||||
<!-- Adresse fournisseur -->
|
||||
<UiSelect
|
||||
id="reception-address"
|
||||
v-model="form.addressId"
|
||||
label="Adresse"
|
||||
:options="supplierAddresses.map((address) => ({
|
||||
value: String(address.id),
|
||||
label: address.fullAddress
|
||||
}))"
|
||||
:disabled="isLoadingSuppliers || supplierAddresses.length === 0"
|
||||
wrapper-class="col-start-2 row-start-1"
|
||||
/>
|
||||
<!-- Camion -->
|
||||
<UiSelect
|
||||
id="reception-truck"
|
||||
v-model="form.truckId"
|
||||
label="Camion"
|
||||
:options="trucks.map((truck) => ({
|
||||
value: String(truck.id),
|
||||
label: truck.name
|
||||
}))"
|
||||
:loading="isLoadingTrucks"
|
||||
wrapper-class="col-start-2 row-start-2"
|
||||
/>
|
||||
<!-- Transporteur -->
|
||||
<UiSelect
|
||||
id="reception-carrier"
|
||||
v-model="form.carrierId"
|
||||
label="Transporteur"
|
||||
:options="carriers.map((carrier) => ({
|
||||
value: String(carrier.id),
|
||||
label: carrier.name
|
||||
}))"
|
||||
:loading="isLoadingCarriers"
|
||||
select-class="h-[34px]"
|
||||
wrapper-class="col-start-2 row-start-3"
|
||||
/>
|
||||
<!-- Chauffeur (LIOT) -->
|
||||
<UiSelect
|
||||
id="reception-driver"
|
||||
v-model="form.driverId"
|
||||
label="Nom du chauffeur si LIOT"
|
||||
:options="filteredDrivers.map((driver) => ({
|
||||
value: String(driver.id),
|
||||
label: driver.name
|
||||
}))"
|
||||
:loading="isLoadingDrivers"
|
||||
wrapper-class="col-start-2 row-start-4"
|
||||
/>
|
||||
<!-- Plaque d'immatriculation -->
|
||||
<div v-if="!isLiotCarrier" class="col-start-2 row-start-5">
|
||||
<UiLicensePlateInput
|
||||
v-model="form.licensePlate"
|
||||
v-model:allowAny="allowAnyLicensePlate"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<label for="reception-date" class="font-bold uppercase text-xl mb-4">Date de reception</label>
|
||||
<input
|
||||
id="reception-date"
|
||||
v-model="form.receptionDate"
|
||||
type="date"
|
||||
class="border-b border-black justify-self-start text-xl pb-[6px] uppercase"
|
||||
/>
|
||||
</div>
|
||||
<!-- Immatriculation (LIOT) -->
|
||||
<UiSelect
|
||||
v-if="isLiotCarrier"
|
||||
id="reception-vehicle"
|
||||
v-model="form.vehicleId"
|
||||
label="Immatriculation"
|
||||
:options="filteredVehicles.map((vehicle) => ({
|
||||
value: String(vehicle.id),
|
||||
label: vehicle.plate
|
||||
}))"
|
||||
:loading="isLoadingVehicles"
|
||||
:disabled="isLoadingVehicles || filteredVehicles.length === 0"
|
||||
wrapper-class="col-start-2 row-start-5"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex justify-center">
|
||||
<button
|
||||
@@ -29,39 +126,395 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useReceptionStore } from '~/stores/reception'
|
||||
import {useReceptionStore} from '~/stores/reception'
|
||||
import type {ReceptionTypeData} from '~/services/dto/reception-type-data'
|
||||
import {getReceptionTypeList} from '~/services/reception-type'
|
||||
import type {UserData} from '~/services/dto/user-data'
|
||||
import {getUsers} from '~/services/auth'
|
||||
import {useAuthStore} from '~/stores/auth'
|
||||
import type {SupplierData} from '~/services/dto/supplier-data'
|
||||
import {getSupplierList} from '~/services/supplier'
|
||||
import type {TruckData} from '~/services/dto/truck-data'
|
||||
import {getTruckList} from '~/services/truck'
|
||||
import type {CarrierData} from '~/services/dto/carrier-data'
|
||||
import {getCarrierList} from '~/services/carrier'
|
||||
import type {DriverData} from '~/services/dto/driver-data'
|
||||
import {getDriverList} from '~/services/driver'
|
||||
import type {VehicleData} from '~/services/dto/vehicle-data'
|
||||
import {getVehicleList} from '~/services/vehicle'
|
||||
import {RECEPTION_TYPE_CODES, SUPLLIER_CODE} from "~/utils/constants";
|
||||
import {deleteReceptionBovine, getReceptionBovineList} from "~/services/reception-bovine";
|
||||
|
||||
type ReceptionFormData = {
|
||||
licensePlate: string
|
||||
receptionDate: string
|
||||
receptionTypeId: string
|
||||
userId: string
|
||||
supplierId: string
|
||||
addressId: string
|
||||
truckId: string
|
||||
carrierId: string
|
||||
driverId: string
|
||||
vehicleId: string
|
||||
}
|
||||
|
||||
const router = useRouter()
|
||||
const receptionStore = useReceptionStore()
|
||||
const form = reactive<ReceptionFormData>({
|
||||
licensePlate: '',
|
||||
receptionDate: new Date().toISOString().slice(0, 10)
|
||||
receptionDate: new Date().toISOString().slice(0, 10),
|
||||
receptionTypeId: '',
|
||||
userId: '',
|
||||
supplierId: '',
|
||||
addressId: '',
|
||||
truckId: '',
|
||||
carrierId: '',
|
||||
driverId: '',
|
||||
vehicleId: ''
|
||||
})
|
||||
const allowAnyLicensePlate = ref(false)
|
||||
const receptionTypes = ref<ReceptionTypeData[]>([])
|
||||
const users = ref<UserData[]>([])
|
||||
const isLoadingUsers = ref(false)
|
||||
const suppliers = ref<SupplierData[]>([])
|
||||
const isLoadingSuppliers = ref(false)
|
||||
const trucks = ref<TruckData[]>([])
|
||||
const isLoadingTrucks = ref(false)
|
||||
const carriers = ref<CarrierData[]>([])
|
||||
const isLoadingCarriers = ref(false)
|
||||
const drivers = ref<DriverData[]>([])
|
||||
const isLoadingDrivers = ref(false)
|
||||
const vehicles = ref<VehicleData[]>([])
|
||||
const isLoadingVehicles = ref(false)
|
||||
const authStore = useAuthStore()
|
||||
// Empêche les watchers de reset des champs pendant le remplissage initial
|
||||
const isHydrating = ref(false)
|
||||
|
||||
// Transporteur sélectionné dans le formulaire
|
||||
const selectedCarrier = computed(() =>
|
||||
carriers.value.find((carrier) => String(carrier.id) === form.carrierId) ?? null
|
||||
)
|
||||
// Indique si le transporteur est LIOT
|
||||
const isLiotCarrier = computed(() => selectedCarrier.value?.code === SUPLLIER_CODE.LIOT)
|
||||
// Adresses disponibles pour le fournisseur sélectionné
|
||||
const supplierAddresses = computed(() => {
|
||||
const supplierId = Number(form.supplierId)
|
||||
if (!Number.isFinite(supplierId)) {
|
||||
return []
|
||||
}
|
||||
return suppliers.value.find((supplier) => supplier.id === supplierId)?.addresses ?? []
|
||||
})
|
||||
// Chauffeurs filtrés par transporteur (LIOT)
|
||||
const filteredDrivers = computed<DriverData[]>(() => {
|
||||
if (!form.carrierId) {
|
||||
return []
|
||||
}
|
||||
return drivers.value.filter((driver) => String(driver.carrier?.id) === form.carrierId)
|
||||
})
|
||||
// Véhicules filtrés par transporteur + type de camion
|
||||
const filteredVehicles = computed<VehicleData[]>(() => {
|
||||
if (!form.carrierId) {
|
||||
return []
|
||||
}
|
||||
return vehicles.value.filter(
|
||||
(vehicle) =>
|
||||
String(vehicle.carrier?.id) === form.carrierId &&
|
||||
(!form.truckId || String(vehicle.truck?.id) === form.truckId)
|
||||
)
|
||||
})
|
||||
|
||||
const selectedReceptionType = computed(() =>
|
||||
receptionTypes.value.find((type) => String(type.id) === form.receptionTypeId) ?? null
|
||||
)
|
||||
|
||||
// Supprime les données bovines si on change de type de réception
|
||||
const clearReceptionBovines = async (receptionIri: string) => {
|
||||
const existing = await getReceptionBovineList(receptionIri)
|
||||
for (const selection of existing) {
|
||||
await deleteReceptionBovine(selection.id)
|
||||
}
|
||||
}
|
||||
|
||||
// Hydrate le formulaire depuis la réception en cours
|
||||
watch(
|
||||
() => receptionStore.current,
|
||||
(reception) => {
|
||||
isHydrating.value = true
|
||||
form.licensePlate = reception?.licensePlate ?? ''
|
||||
form.receptionDate = reception?.receptionDate ?? new Date().toISOString().slice(0, 10)
|
||||
form.receptionTypeId = reception?.receptionType?.id
|
||||
? String(reception.receptionType.id)
|
||||
: ''
|
||||
form.userId = reception?.user?.id
|
||||
? String(reception.user.id)
|
||||
: form.userId
|
||||
form.supplierId = reception?.supplier?.id
|
||||
? String(reception.supplier.id)
|
||||
: ''
|
||||
form.addressId = reception?.address?.id
|
||||
? String(reception.address.id)
|
||||
: ''
|
||||
form.truckId = reception?.truck?.id
|
||||
? String(reception.truck.id)
|
||||
: ''
|
||||
form.carrierId = reception?.carrier?.id
|
||||
? String(reception.carrier.id)
|
||||
: ''
|
||||
form.driverId = reception?.driver?.id
|
||||
? String(reception.driver.id)
|
||||
: ''
|
||||
isHydrating.value = false
|
||||
},
|
||||
{ immediate: true }
|
||||
{immediate: true}
|
||||
)
|
||||
|
||||
// Charge la liste des users pour le select
|
||||
const loadUsers = async () => {
|
||||
isLoadingUsers.value = true
|
||||
try {
|
||||
users.value = await getUsers()
|
||||
} finally {
|
||||
isLoadingUsers.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Charge la liste des fournisseurs pour le select
|
||||
const loadSuppliers = async () => {
|
||||
isLoadingSuppliers.value = true
|
||||
try {
|
||||
suppliers.value = await getSupplierList()
|
||||
} finally {
|
||||
isLoadingSuppliers.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Charge la liste des camions pour le select
|
||||
const loadTrucks = async () => {
|
||||
isLoadingTrucks.value = true
|
||||
try {
|
||||
trucks.value = await getTruckList()
|
||||
} finally {
|
||||
isLoadingTrucks.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Charge la liste des transporteurs pour le select
|
||||
const loadCarriers = async () => {
|
||||
isLoadingCarriers.value = true
|
||||
try {
|
||||
carriers.value = await getCarrierList()
|
||||
} finally {
|
||||
isLoadingCarriers.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Charge la liste des chauffeurs pour le select
|
||||
const loadDrivers = async () => {
|
||||
isLoadingDrivers.value = true
|
||||
try {
|
||||
drivers.value = await getDriverList()
|
||||
} finally {
|
||||
isLoadingDrivers.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Charge la liste des véhicules pour le select
|
||||
const loadVehicles = async () => {
|
||||
isLoadingVehicles.value = true
|
||||
try {
|
||||
vehicles.value = await getVehicleList()
|
||||
} finally {
|
||||
isLoadingVehicles.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// On met le user connecté par défaut dans le select
|
||||
const setDefaultUser = () => {
|
||||
if (form.userId) {
|
||||
return
|
||||
}
|
||||
if (authStore.user?.id) {
|
||||
form.userId = String(authStore.user.id)
|
||||
}
|
||||
}
|
||||
|
||||
// On récupère toutes les données des selects au chargement du composant
|
||||
onMounted(async () => {
|
||||
receptionTypes.value = await getReceptionTypeList()
|
||||
await loadUsers()
|
||||
await loadSuppliers()
|
||||
await loadTrucks()
|
||||
await loadCarriers()
|
||||
await loadDrivers()
|
||||
await loadVehicles()
|
||||
await authStore.ensureSession()
|
||||
setDefaultUser()
|
||||
})
|
||||
|
||||
// Ajuste driver/vehicle quand le transporteur change (logique LIOT)
|
||||
watch(
|
||||
() => [form.supplierId, suppliers.value],
|
||||
() => {
|
||||
if (!form.supplierId) {
|
||||
form.addressId = ''
|
||||
return
|
||||
}
|
||||
if (!form.addressId && supplierAddresses.value.length === 1) {
|
||||
form.addressId = String(supplierAddresses.value[0].id)
|
||||
return
|
||||
}
|
||||
if (!form.addressId) {
|
||||
return
|
||||
}
|
||||
const matches = supplierAddresses.value.some(
|
||||
(address) => String(address.id) === form.addressId
|
||||
)
|
||||
if (!matches) {
|
||||
form.addressId = ''
|
||||
}
|
||||
},
|
||||
{immediate: true}
|
||||
)
|
||||
|
||||
// Valide/auto-sélectionne le véhicule selon camion + transporteur (LIOT)
|
||||
watch(
|
||||
() => form.carrierId,
|
||||
() => {
|
||||
if (isHydrating.value) {
|
||||
return
|
||||
}
|
||||
if (!form.carrierId) {
|
||||
form.driverId = ''
|
||||
form.vehicleId = ''
|
||||
return
|
||||
}
|
||||
if (!isLiotCarrier.value) {
|
||||
form.driverId = ''
|
||||
form.vehicleId = ''
|
||||
return
|
||||
}
|
||||
if (filteredDrivers.value.length === 1) {
|
||||
form.driverId = String(filteredDrivers.value[0].id)
|
||||
}
|
||||
if (filteredVehicles.value.length === 1) {
|
||||
form.vehicleId = String(filteredVehicles.value[0].id)
|
||||
}
|
||||
},
|
||||
{immediate: true}
|
||||
)
|
||||
|
||||
// Récupère la plaque depuis le véhicule choisi (LIOT)
|
||||
watch(
|
||||
() => [form.truckId, form.carrierId, vehicles.value],
|
||||
() => {
|
||||
if (!isLiotCarrier.value) {
|
||||
return
|
||||
}
|
||||
if (filteredVehicles.value.length === 1) {
|
||||
form.vehicleId = String(filteredVehicles.value[0].id)
|
||||
return
|
||||
}
|
||||
if (!form.vehicleId) {
|
||||
return
|
||||
}
|
||||
const matches = filteredVehicles.value.some(
|
||||
(vehicle) => String(vehicle.id) === form.vehicleId
|
||||
)
|
||||
if (!matches) {
|
||||
form.vehicleId = ''
|
||||
}
|
||||
},
|
||||
{immediate: true}
|
||||
)
|
||||
|
||||
// Auto-renseigne le véhicule si la plaque correspond (LIOT)
|
||||
watch(
|
||||
() => [form.vehicleId, form.carrierId, vehicles.value],
|
||||
() => {
|
||||
if (!isLiotCarrier.value) {
|
||||
return
|
||||
}
|
||||
if (isHydrating.value) {
|
||||
return
|
||||
}
|
||||
const selected = filteredVehicles.value.find(
|
||||
(vehicle) => String(vehicle.id) === form.vehicleId
|
||||
)
|
||||
if (selected) {
|
||||
form.licensePlate = selected.plate
|
||||
allowAnyLicensePlate.value = false
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => [form.licensePlate, form.carrierId, vehicles.value],
|
||||
() => {
|
||||
if (!isLiotCarrier.value || form.vehicleId) {
|
||||
return
|
||||
}
|
||||
const match = filteredVehicles.value.find(
|
||||
(vehicle) => vehicle.plate === form.licensePlate
|
||||
)
|
||||
if (match) {
|
||||
form.vehicleId = String(match.id)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// Valide le formulaire et crée/met à jour la réception
|
||||
async function validate() {
|
||||
const normalizedLicensePlate = form.licensePlate.trim()
|
||||
const normalizedReceptionDate = form.receptionDate.trim()
|
||||
const normalizedReceptionTypeId = form.receptionTypeId.trim()
|
||||
const normalizedUserId = form.userId.trim()
|
||||
const normalizedSupplierId = form.supplierId.trim()
|
||||
const normalizedAddressId = form.addressId.trim()
|
||||
const normalizedTruckId = form.truckId.trim()
|
||||
const normalizedCarrierId = form.carrierId.trim()
|
||||
const normalizedDriverId = form.driverId.trim()
|
||||
const receptionTypeIri = normalizedReceptionTypeId
|
||||
? `/api/reception_types/${normalizedReceptionTypeId}`
|
||||
: null
|
||||
const userIri = normalizedUserId
|
||||
? `/api/users/${normalizedUserId}`
|
||||
: null
|
||||
const supplierIri = normalizedSupplierId
|
||||
? `/api/suppliers/${normalizedSupplierId}`
|
||||
: null
|
||||
const addressIri = normalizedAddressId
|
||||
? `/api/addresses/${normalizedAddressId}`
|
||||
: null
|
||||
const truckIri = normalizedTruckId
|
||||
? `/api/trucks/${normalizedTruckId}`
|
||||
: null
|
||||
const carrierIri = normalizedCarrierId
|
||||
? `/api/carriers/${normalizedCarrierId}`
|
||||
: null
|
||||
const driverIri = normalizedDriverId
|
||||
? `/api/drivers/${normalizedDriverId}`
|
||||
: null
|
||||
|
||||
const basePayload = {
|
||||
licensePlate: normalizedLicensePlate,
|
||||
receptionDate: normalizedReceptionDate,
|
||||
receptionType: receptionTypeIri,
|
||||
user: userIri,
|
||||
supplier: supplierIri,
|
||||
address: addressIri,
|
||||
truck: truckIri,
|
||||
carrier: carrierIri
|
||||
}
|
||||
|
||||
const payload = {
|
||||
...basePayload,
|
||||
...(isLiotCarrier.value && driverIri ? {driver: driverIri} : {})
|
||||
}
|
||||
|
||||
if (!receptionStore.current) {
|
||||
const created = await receptionStore.createReception({
|
||||
currentStep: 1,
|
||||
licensePlate: normalizedLicensePlate,
|
||||
receptionDate: normalizedReceptionDate
|
||||
...payload
|
||||
})
|
||||
if (created) {
|
||||
await router.push(`/reception/${created.id}`)
|
||||
@@ -69,11 +522,20 @@ async function validate() {
|
||||
return
|
||||
}
|
||||
|
||||
const previousTypeCode = receptionStore.current.receptionType?.code ?? null
|
||||
const nextTypeCode = selectedReceptionType.value?.code ?? null
|
||||
const receptionIri = `/api/receptions/${receptionStore.current.id}`
|
||||
|
||||
if (
|
||||
previousTypeCode === RECEPTION_TYPE_CODES.BOVINS &&
|
||||
nextTypeCode === RECEPTION_TYPE_CODES.MERCHANDISES
|
||||
) {
|
||||
await clearReceptionBovines(receptionIri)
|
||||
}
|
||||
const nextStep = receptionStore.current.currentStep + 1
|
||||
await receptionStore.updateReception(receptionStore.current.id, {
|
||||
currentStep: nextStep,
|
||||
licensePlate: normalizedLicensePlate,
|
||||
receptionDate: normalizedReceptionDate
|
||||
...payload
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
255
frontend/components/reception/reception-product-received.vue
Normal file
255
frontend/components/reception/reception-product-received.vue
Normal file
@@ -0,0 +1,255 @@
|
||||
<template>
|
||||
<div class="flex flex-col items-center gap-16">
|
||||
<div
|
||||
v-if="receptionStore.current?.receptionType?.code === RECEPTION_TYPE_CODES.MERCHANDISES"
|
||||
class="flex flex-col gap-16 items-center w-full">
|
||||
<h1 class="text-4xl uppercase font-bold">Sélection des marchandises réceptionnnées</h1>
|
||||
<UiSelect
|
||||
id="merchandise-type"
|
||||
v-model="selectedMerchandiseTypeId"
|
||||
label="Type de marchandises"
|
||||
:options="merchandiseTypes.map((type) => ({ value: String(type.id), label: type.label }))"
|
||||
wrapper-class="w-[550px]"
|
||||
/>
|
||||
<div
|
||||
v-if="selectedMerchandiseTypeId && isAutres"
|
||||
class="flex flex-col w-full max-w-[550px]"
|
||||
>
|
||||
<UiTextInput
|
||||
id="merchandise-detail"
|
||||
v-model="merchandiseDetail"
|
||||
label="Préciser"
|
||||
placeholder="Précisions complémentaires"
|
||||
:maxlength="255"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="selectedMerchandiseTypeId && !isGranule"
|
||||
class="flex gap-4 w-[550px] justify-evenly"
|
||||
>
|
||||
<div
|
||||
v-for="building in buildings"
|
||||
:key="building.id"
|
||||
>
|
||||
<UiCheckbox
|
||||
v-model="selectedBuildingIds"
|
||||
:value="String(building.id)"
|
||||
:label="building.label"
|
||||
label-class="text-xl"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="selectedMerchandiseTypeId && isGranule"
|
||||
class="flex flex-col gap-10 w-full max-w-[1100px]"
|
||||
>
|
||||
<div class="grid grid-cols-1 gap-10 md:grid-cols-4">
|
||||
<div v-for="type in pelletTypes" :key="type.id" class="flex flex-col gap-4">
|
||||
<p class="font-bold uppercase">{{ type.label }}</p>
|
||||
<div
|
||||
v-for="building in buildings"
|
||||
:key="building.id"
|
||||
class="flex items-center gap-2 text-lg"
|
||||
>
|
||||
<UiCheckbox
|
||||
v-model="selectedPelletBuildingIds[String(type.id)]"
|
||||
:value="String(building.id)"
|
||||
:label="building.label"
|
||||
label-class="text-lg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]"
|
||||
@click="goNext"
|
||||
>Peser
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {computed, onMounted, ref} from 'vue'
|
||||
import {getBuildingList} from '~/services/building'
|
||||
import {getMerchandiseTypeList} from '~/services/merchandise-type'
|
||||
import type {MerchandiseTypeData} from '~/services/dto/merchandise-type-data'
|
||||
import type {BuildingData} from '~/services/dto/building-data'
|
||||
import type {PelletTypeData} from '~/services/dto/pellet-type-data'
|
||||
import {getPelletTypeList} from '~/services/pellet-type'
|
||||
import {
|
||||
createReceptionPelletBuilding,
|
||||
deleteReceptionPelletBuilding,
|
||||
getReceptionPelletBuildingList
|
||||
} from '~/services/reception-pellet-building'
|
||||
import {useReceptionStore} from '~/stores/reception'
|
||||
import {MERCHANDISE_TYPE_CODES, RECEPTION_TYPE_CODES} from '~/utils/constants'
|
||||
import ReceptionBovineReceived from "~/components/reception/reception-bovine-received.vue";
|
||||
|
||||
const receptionStore = useReceptionStore()
|
||||
const merchandiseTypes = ref<MerchandiseTypeData[]>([])
|
||||
const buildings = ref<BuildingData[]>([])
|
||||
const pelletTypes = ref<PelletTypeData[]>([])
|
||||
const selectedMerchandiseTypeId = ref('')
|
||||
const selectedBuildingIds = ref<string[]>([])
|
||||
const selectedPelletBuildingIds = ref<Record<string, string[]>>({})
|
||||
const merchandiseDetail = ref('')
|
||||
|
||||
// Extrait l'ID d'une relation depuis un IRI ou un objet complet.
|
||||
const getRelationId = (value: unknown): string | null => {
|
||||
if (!value) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
const match = value.match(/\/(\d+)$/)
|
||||
return match ? match[1] : null
|
||||
}
|
||||
|
||||
if (typeof value === 'object' && 'id' in value) {
|
||||
const record = value as { id?: number | string }
|
||||
if (typeof record.id === 'number') {
|
||||
return String(record.id)
|
||||
}
|
||||
if (typeof record.id === 'string') {
|
||||
return record.id
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
// Type de marchandise sélectionné dans le select
|
||||
const selectedMerchandiseType = computed(() =>
|
||||
merchandiseTypes.value.find((type) => String(type.id) === selectedMerchandiseTypeId.value)
|
||||
)
|
||||
// Indique si le type est "Granulé"
|
||||
const isGranule = computed(() => selectedMerchandiseType.value?.code === MERCHANDISE_TYPE_CODES.GRANULE)
|
||||
// Indique si le type est "Autres"
|
||||
const isAutres = computed(() => selectedMerchandiseType.value?.code === MERCHANDISE_TYPE_CODES.AUTRES)
|
||||
|
||||
// Charge les référentiels et hydrate le formulaire depuis la réception
|
||||
onMounted(async () => {
|
||||
const [merchandiseTypeList, buildingList, pelletTypeList] = await Promise.all([
|
||||
getMerchandiseTypeList(),
|
||||
getBuildingList(),
|
||||
getPelletTypeList()
|
||||
])
|
||||
merchandiseTypes.value = merchandiseTypeList
|
||||
buildings.value = buildingList
|
||||
pelletTypes.value = pelletTypeList
|
||||
|
||||
const currentId = receptionStore.current?.merchandiseType?.id
|
||||
if (currentId) {
|
||||
selectedMerchandiseTypeId.value = String(currentId)
|
||||
}
|
||||
merchandiseDetail.value = receptionStore.current?.merchandiseDetail ?? ''
|
||||
|
||||
selectedBuildingIds.value =
|
||||
receptionStore.current?.buildings?.map((building) => String(building.id)) ?? []
|
||||
|
||||
const existingPelletSelections = receptionStore.current?.pelletBuildings ?? []
|
||||
const selectionMap: Record<string, string[]> = {}
|
||||
for (const selection of existingPelletSelections) {
|
||||
// L'API peut renvoyer les relations comme IRI ou comme objets selon le contexte.
|
||||
const pelletTypeId = getRelationId(selection.pelletType)
|
||||
const buildingId = getRelationId(selection.building)
|
||||
if (!pelletTypeId || !buildingId) {
|
||||
continue
|
||||
}
|
||||
if (!selectionMap[pelletTypeId]) {
|
||||
selectionMap[pelletTypeId] = []
|
||||
}
|
||||
selectionMap[pelletTypeId].push(buildingId)
|
||||
}
|
||||
for (const pelletType of pelletTypes.value) {
|
||||
const key = String(pelletType.id)
|
||||
if (!selectionMap[key]) {
|
||||
selectionMap[key] = []
|
||||
}
|
||||
}
|
||||
selectedPelletBuildingIds.value = selectionMap
|
||||
})
|
||||
// Enregistre les sélections et passe à l'étape suivante
|
||||
async function goNext() {
|
||||
if (!receptionStore.current) {
|
||||
return
|
||||
}
|
||||
|
||||
const nextStep = receptionStore.current.currentStep + 1
|
||||
const receptionIri = `/api/receptions/${receptionStore.current.id}`
|
||||
|
||||
await receptionStore.updateReception(receptionStore.current.id, {
|
||||
merchandiseType: selectedMerchandiseTypeId.value
|
||||
? `/api/merchandise_types/${selectedMerchandiseTypeId.value}`
|
||||
: null,
|
||||
merchandiseDetail: isAutres.value ? merchandiseDetail.value.trim() : null,
|
||||
buildings: isGranule.value
|
||||
? []
|
||||
: selectedBuildingIds.value.map((id) => `/api/buildings/${id}`),
|
||||
bovineDetail: null,
|
||||
bovinesTypes: null,
|
||||
currentStep: nextStep
|
||||
})
|
||||
|
||||
if (isGranule.value) {
|
||||
await syncPelletSelections(receptionIri)
|
||||
} else {
|
||||
await clearPelletSelections(receptionIri)
|
||||
}
|
||||
}
|
||||
|
||||
// Supprime toutes les associations granulés/bâtiments existantes
|
||||
async function clearPelletSelections(receptionIri: string) {
|
||||
const existing = await getReceptionPelletBuildingList(receptionIri)
|
||||
for (const selection of existing) {
|
||||
await deleteReceptionPelletBuilding(selection.id)
|
||||
}
|
||||
}
|
||||
// Synchronise les associations granulés/bâtiments avec l'état du formulaire
|
||||
async function syncPelletSelections(receptionIri: string) {
|
||||
const existing = await getReceptionPelletBuildingList(receptionIri)
|
||||
const existingMap = new Map<string, number>()
|
||||
for (const selection of existing) {
|
||||
// Construit la table de correspondance avec des IDs normalisés pour éviter les doublons.
|
||||
const pelletTypeId = getRelationId(selection.pelletType)
|
||||
const buildingId = getRelationId(selection.building)
|
||||
if (!pelletTypeId || !buildingId) {
|
||||
continue
|
||||
}
|
||||
const key = `${pelletTypeId}:${buildingId}`
|
||||
existingMap.set(key, selection.id)
|
||||
}
|
||||
|
||||
const desiredEntries: Array<{ pelletTypeId: string; buildingId: string }> = []
|
||||
for (const [pelletTypeId, buildingIds] of Object.entries(selectedPelletBuildingIds.value)) {
|
||||
for (const buildingId of buildingIds) {
|
||||
desiredEntries.push({pelletTypeId, buildingId})
|
||||
}
|
||||
}
|
||||
|
||||
const desiredKeys = new Set(desiredEntries.map(
|
||||
(entry) => `${entry.pelletTypeId}:${entry.buildingId}`
|
||||
))
|
||||
|
||||
for (const [key, id] of existingMap.entries()) {
|
||||
if (!desiredKeys.has(key)) {
|
||||
await deleteReceptionPelletBuilding(id)
|
||||
}
|
||||
}
|
||||
|
||||
for (const entry of desiredEntries) {
|
||||
const key = `${entry.pelletTypeId}:${entry.buildingId}`
|
||||
if (!existingMap.has(key)) {
|
||||
await createReceptionPelletBuilding({
|
||||
reception: receptionIri,
|
||||
pelletType: `/api/pellet_types/${entry.pelletTypeId}`,
|
||||
building: `/api/buildings/${entry.buildingId}`
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,30 +0,0 @@
|
||||
<template>
|
||||
<div class="flex flex-col items-center mt-[164px] gap-32">
|
||||
<div class="flex gap-8 items-center justify-center">
|
||||
<!--@TODO Prendre en compte que l'on peut aussi décharger de la marchandise-->
|
||||
<h1 class="text-4xl uppercase font-bold">Décharger les bêtes</h1>
|
||||
<UiLoadingDots />
|
||||
</div>
|
||||
<button
|
||||
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]"
|
||||
@click="goNext"
|
||||
>Peser</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useReceptionStore } from '~/stores/reception'
|
||||
|
||||
const receptionStore = useReceptionStore()
|
||||
|
||||
async function goNext() {
|
||||
if (!receptionStore.current) {
|
||||
return
|
||||
}
|
||||
|
||||
const nextStep = receptionStore.current.currentStep + 1
|
||||
await receptionStore.updateReception(receptionStore.current.id, {
|
||||
currentStep: nextStep
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -14,10 +14,6 @@
|
||||
class="w-full flex flex-col items-center justify-center border border-black h-[90px] mt-12 mb-[25px] text-4xl">
|
||||
{{ displayWeight }} kg
|
||||
</div>
|
||||
<!-- <div class="grid grid-cols-2 border border-black text-center">-->
|
||||
<!-- <p class="border-r border-black py-3 text-4xl font-bold">DSD</p>-->
|
||||
<!-- <p class="py-3 text-4xl">{{ displayDsd }}</p>-->
|
||||
<!-- </div>-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -37,14 +33,13 @@
|
||||
@click="printReceipt"
|
||||
>Générer le bon</button>
|
||||
</div>
|
||||
<UiPdfPrinter ref="pdfPrinter" />
|
||||
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { computed } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useWeighing } from '~/composables/useWeighing'
|
||||
import { usePdfPrinter } from '~/composables/usePdfPrinter'
|
||||
import { useReceptionStore } from '~/stores/reception'
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -54,14 +49,9 @@ const props = defineProps<{
|
||||
const router = useRouter()
|
||||
const receptionStore = useReceptionStore()
|
||||
const { current: storeReception } = storeToRefs(receptionStore)
|
||||
type PdfPrinterHandle = {
|
||||
print: (url: string) => Promise<void>
|
||||
}
|
||||
// Ref sur le composant d'impression pour déclencher le print() du PDF.
|
||||
const pdfPrinter = ref<PdfPrinterHandle | null>(null)
|
||||
const { printPdf } = usePdfPrinter()
|
||||
const {
|
||||
displayWeight,
|
||||
displayDsd,
|
||||
title,
|
||||
showLoadingBox,
|
||||
fetchWeight,
|
||||
@@ -72,17 +62,19 @@ const {
|
||||
updateReception: receptionStore.updateReception,
|
||||
loadReception: receptionStore.loadReception
|
||||
})
|
||||
// Affiche le bouton de génération du bon à l'étape tare
|
||||
const showGenerateReceipt = computed(
|
||||
() => props.mode === 'tare' && displayWeight.value !== null
|
||||
)
|
||||
|
||||
// Génère le bon de réception, puis clôture la réception
|
||||
const printReceipt = async () => {
|
||||
if (!import.meta.client || !receptionStore.current || !pdfPrinter.value) {
|
||||
if (!import.meta.client || !receptionStore.current) {
|
||||
return
|
||||
}
|
||||
|
||||
await saveWeight()
|
||||
await pdfPrinter.value.print(`/receptions/${receptionStore.current.id}/receipt`)
|
||||
await printPdf(`/receptions/${receptionStore.current.id}/receipt`)
|
||||
|
||||
// Laisse le temps a la boite de dialogue d'impression de s'ouvrir.
|
||||
await new Promise((resolve) => setTimeout(resolve, 600))
|
||||
@@ -98,7 +90,10 @@ const printReceipt = async () => {
|
||||
await router.push('/')
|
||||
}
|
||||
|
||||
// Récupère le poids dès l'arrivée sur l'écran
|
||||
onMounted(() => {
|
||||
fetchWeight()
|
||||
if (false === displayWeight.value) {
|
||||
fetchWeight()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
76
frontend/components/ui/UiCheckbox.vue
Normal file
76
frontend/components/ui/UiCheckbox.vue
Normal file
@@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<div :class="wrapperClass">
|
||||
<label
|
||||
class="flex items-center gap-2"
|
||||
:class="labelClass"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="checked"
|
||||
:disabled="disabled"
|
||||
:class="inputClass"
|
||||
@change="onChange"
|
||||
>
|
||||
<span v-if="label">{{ label }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
|
||||
type CheckboxValue = string | number
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
modelValue: boolean | CheckboxValue[]
|
||||
value?: CheckboxValue
|
||||
label?: string
|
||||
disabled?: boolean
|
||||
wrapperClass?: string
|
||||
labelClass?: string
|
||||
inputClass?: string
|
||||
}>(),
|
||||
{
|
||||
value: undefined,
|
||||
label: '',
|
||||
disabled: false,
|
||||
wrapperClass: '',
|
||||
labelClass: '',
|
||||
inputClass: ''
|
||||
}
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'update:modelValue', value: boolean | CheckboxValue[]): void
|
||||
}>()
|
||||
|
||||
const checked = computed(() => {
|
||||
if (Array.isArray(props.modelValue)) {
|
||||
if (props.value === undefined) {
|
||||
return false
|
||||
}
|
||||
return props.modelValue.includes(props.value)
|
||||
}
|
||||
return Boolean(props.modelValue)
|
||||
})
|
||||
|
||||
const onChange = (event: Event) => {
|
||||
const target = event.target as HTMLInputElement
|
||||
if (Array.isArray(props.modelValue)) {
|
||||
if (props.value === undefined) {
|
||||
emit('update:modelValue', props.modelValue)
|
||||
return
|
||||
}
|
||||
const next = new Set(props.modelValue)
|
||||
if (target.checked) {
|
||||
next.add(props.value)
|
||||
} else {
|
||||
next.delete(props.value)
|
||||
}
|
||||
emit('update:modelValue', Array.from(next))
|
||||
return
|
||||
}
|
||||
emit('update:modelValue', target.checked)
|
||||
}
|
||||
</script>
|
||||
62
frontend/components/ui/UiDateInput.vue
Normal file
62
frontend/components/ui/UiDateInput.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<div :class="['flex flex-col', wrapperClass]">
|
||||
<label
|
||||
v-if="label"
|
||||
:for="id"
|
||||
class="font-bold uppercase text-xl mb-2"
|
||||
:class="labelClass"
|
||||
>
|
||||
{{ label }}
|
||||
</label>
|
||||
<input
|
||||
:id="id"
|
||||
type="date"
|
||||
:value="modelValue ?? ''"
|
||||
:disabled="disabled"
|
||||
v-bind="attrs"
|
||||
class="border-b border-black justify-self-start text-xl pb-[6px] uppercase bg-transparent appearance-none h-[34px]"
|
||||
:class="[
|
||||
isEmpty ? 'text-neutral-400' : 'text-black',
|
||||
disabled ? 'cursor-not-allowed' : 'cursor-pointer',
|
||||
inputClass
|
||||
]"
|
||||
@input="onInput"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, useAttrs } from 'vue'
|
||||
|
||||
defineOptions({ inheritAttrs: false })
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
id?: string
|
||||
label?: string
|
||||
modelValue: string | null | undefined
|
||||
disabled?: boolean
|
||||
wrapperClass?: string
|
||||
labelClass?: string
|
||||
inputClass?: string
|
||||
}>(),
|
||||
{
|
||||
disabled: false,
|
||||
wrapperClass: '',
|
||||
labelClass: '',
|
||||
inputClass: ''
|
||||
}
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'update:modelValue', value: string): void
|
||||
}>()
|
||||
|
||||
const attrs = useAttrs()
|
||||
const isEmpty = computed(() => !props.modelValue)
|
||||
|
||||
const onInput = (event: Event) => {
|
||||
const target = event.target as HTMLInputElement
|
||||
emit('update:modelValue', target.value)
|
||||
}
|
||||
</script>
|
||||
91
frontend/components/ui/UiNumberInput.vue
Normal file
91
frontend/components/ui/UiNumberInput.vue
Normal file
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<div :class="['flex flex-row items-center gap-2', wrapperClass]">
|
||||
<label
|
||||
v-if="label"
|
||||
:for="id"
|
||||
class="text-xl text-bold flex items-center gap-2"
|
||||
:class="labelClass"
|
||||
>
|
||||
<span
|
||||
v-if="label">
|
||||
{{ label }}
|
||||
</span>
|
||||
<span
|
||||
v-if="code" class="text-neutral-600">
|
||||
({{ code }})
|
||||
</span>
|
||||
</label>
|
||||
<input
|
||||
:id="id"
|
||||
type="number"
|
||||
:value="modelValue ?? ''"
|
||||
:min="min"
|
||||
:max="max"
|
||||
:step="step"
|
||||
:disabled="disabled"
|
||||
v-bind="attrs"
|
||||
class="border-b border-black text-xl bg-transparent w-48"
|
||||
:class="[
|
||||
isEmpty ? 'text-neutral-400' : 'text-black',
|
||||
disabled ? 'cursor-not-allowed' : 'cursor-text',
|
||||
inputClass
|
||||
]"
|
||||
@keydown="onKeydown"
|
||||
@input="onInput"
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import {computed, useAttrs} from 'vue'
|
||||
|
||||
defineOptions({inheritAttrs: false})
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
id?: string
|
||||
label?: string
|
||||
code?: string
|
||||
modelValue: number | string | null | undefined
|
||||
min?: number | string
|
||||
max?: number | string
|
||||
step?: number | string
|
||||
disabled?: boolean
|
||||
wrapperClass?: string
|
||||
labelClass?: string
|
||||
inputClass?: string
|
||||
}>(),
|
||||
{
|
||||
min: undefined,
|
||||
max: undefined,
|
||||
step: undefined,
|
||||
disabled: false,
|
||||
wrapperClass: '',
|
||||
labelClass: '',
|
||||
inputClass: ''
|
||||
}
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'update:modelValue', value: number | null): void
|
||||
}>()
|
||||
|
||||
const attrs = useAttrs()
|
||||
const isEmpty = computed(() => props.modelValue === null || props.modelValue === undefined || props.modelValue === '')
|
||||
|
||||
const onInput = (event: Event) => {
|
||||
const target = event.target as HTMLInputElement
|
||||
if (target.value === '') {
|
||||
emit('update:modelValue', null)
|
||||
return
|
||||
}
|
||||
const numeric = Math.max(0, Number(target.value))
|
||||
emit('update:modelValue', Number.isNaN(numeric) ? null : numeric)
|
||||
}
|
||||
|
||||
const onKeydown = (event: KeyboardEvent) => {
|
||||
if (event.key === '-' || event.key === 'e' || event.key === 'E') {
|
||||
event.preventDefault()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
85
frontend/components/ui/UiSelect.vue
Normal file
85
frontend/components/ui/UiSelect.vue
Normal file
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<div :class="['flex flex-col', wrapperClass]">
|
||||
<label
|
||||
v-if="label"
|
||||
:for="id"
|
||||
class="font-bold uppercase text-xl mb-2"
|
||||
:class="labelClass"
|
||||
>
|
||||
{{ label }}
|
||||
</label>
|
||||
<select
|
||||
:id="id"
|
||||
:value="modelValue ?? ''"
|
||||
:disabled="disabled || loading"
|
||||
v-bind="attrs"
|
||||
class="border-b border-black justify-self-start text-xl pb-[6px] bg-transparent"
|
||||
:class="[
|
||||
isEmpty ? 'text-neutral-400' : 'text-black',
|
||||
disabled || loading ? 'cursor-not-allowed' : 'cursor-pointer',
|
||||
selectClass
|
||||
]"
|
||||
@change="onChange"
|
||||
>
|
||||
<option value="" disabled class="text-neutral-400">
|
||||
{{ placeholderText }}
|
||||
</option>
|
||||
<option
|
||||
v-for="option in options"
|
||||
:key="option.value"
|
||||
:value="option.value"
|
||||
class="text-black"
|
||||
>
|
||||
{{ option.label }}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, useAttrs } from 'vue'
|
||||
|
||||
type SelectOption = {
|
||||
value: string | number
|
||||
label: string
|
||||
}
|
||||
|
||||
defineOptions({ inheritAttrs: false })
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
id?: string
|
||||
label?: string
|
||||
placeholder?: string
|
||||
modelValue: string | number | null | undefined
|
||||
options: SelectOption[]
|
||||
disabled?: boolean
|
||||
loading?: boolean
|
||||
wrapperClass?: string
|
||||
labelClass?: string
|
||||
selectClass?: string
|
||||
}>(),
|
||||
{
|
||||
placeholder: 'Sélectionner',
|
||||
disabled: false,
|
||||
loading: false,
|
||||
wrapperClass: '',
|
||||
labelClass: '',
|
||||
selectClass: ''
|
||||
}
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'update:modelValue', value: string): void
|
||||
}>()
|
||||
|
||||
const attrs = useAttrs()
|
||||
|
||||
const isEmpty = computed(() => props.modelValue === '' || props.modelValue === null || props.modelValue === undefined)
|
||||
const placeholderText = computed(() => props.placeholder || 'Sélectionner')
|
||||
|
||||
const onChange = (event: Event) => {
|
||||
const target = event.target as HTMLSelectElement
|
||||
emit('update:modelValue', target.value)
|
||||
}
|
||||
</script>
|
||||
68
frontend/components/ui/UiTextInput.vue
Normal file
68
frontend/components/ui/UiTextInput.vue
Normal file
@@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div :class="['flex flex-col', wrapperClass]">
|
||||
<label
|
||||
v-if="label"
|
||||
:for="id"
|
||||
class="font-bold uppercase text-xl mb-2"
|
||||
:class="labelClass"
|
||||
>
|
||||
{{ label }}
|
||||
</label>
|
||||
<input
|
||||
:id="id"
|
||||
type="text"
|
||||
:value="modelValue ?? ''"
|
||||
:placeholder="placeholder"
|
||||
:maxlength="maxlength"
|
||||
:disabled="disabled"
|
||||
v-bind="attrs"
|
||||
class="border-b border-black text-xl pb-[6px] bg-transparent"
|
||||
:class="[
|
||||
isEmpty ? 'text-neutral-400' : 'text-black',
|
||||
disabled ? 'cursor-not-allowed' : 'cursor-text',
|
||||
inputClass
|
||||
]"
|
||||
@input="onInput"
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, useAttrs } from 'vue'
|
||||
|
||||
defineOptions({ inheritAttrs: false })
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
id?: string
|
||||
label?: string
|
||||
modelValue: string | null | undefined
|
||||
placeholder?: string
|
||||
maxlength?: number | string
|
||||
disabled?: boolean
|
||||
wrapperClass?: string
|
||||
labelClass?: string
|
||||
inputClass?: string
|
||||
}>(),
|
||||
{
|
||||
placeholder: '',
|
||||
maxlength: undefined,
|
||||
disabled: false,
|
||||
wrapperClass: '',
|
||||
labelClass: '',
|
||||
inputClass: ''
|
||||
}
|
||||
)
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: 'update:modelValue', value: string): void
|
||||
}>()
|
||||
|
||||
const attrs = useAttrs()
|
||||
const isEmpty = computed(() => !props.modelValue)
|
||||
|
||||
const onInput = (event: Event) => {
|
||||
const target = event.target as HTMLInputElement
|
||||
emit('update:modelValue', target.value)
|
||||
}
|
||||
</script>
|
||||
@@ -1,26 +1,27 @@
|
||||
<template>
|
||||
<div class="flex flex-col">
|
||||
<label :for="inputId" class="font-bold uppercase text-xl mb-4">{{ label }}</label>
|
||||
<input
|
||||
:id="inputId"
|
||||
:value="modelValue"
|
||||
v-maska="maskOptions"
|
||||
type="text"
|
||||
:maxlength="maxLength"
|
||||
:placeholder="placeholderText"
|
||||
class="border-b border-black justify-self-start text-xl pb-[6px] uppercase"
|
||||
@input="handleInput"
|
||||
/>
|
||||
<label :for="checkboxId" class="mt-3 flex items-center gap-3 text-sm">
|
||||
<input
|
||||
:id="checkboxId"
|
||||
:checked="allowAny"
|
||||
type="checkbox"
|
||||
class="h-4 w-4 accent-primary-500"
|
||||
@change="toggleAllowAny"
|
||||
/>
|
||||
Autoriser un format libre
|
||||
</label>
|
||||
<label :for="inputId" class="font-bold uppercase text-xl mb-2">{{ label }}</label>
|
||||
<div class="flex items-end gap-8">
|
||||
<input
|
||||
:id="inputId"
|
||||
:value="modelValue"
|
||||
v-maska="maskOptions"
|
||||
type="text"
|
||||
:maxlength="maxLength"
|
||||
:placeholder="placeholderText"
|
||||
class="border-b border-black flex-1 min-w-0 text-xl uppercase h-[30px]"
|
||||
@input="handleInput"
|
||||
/>
|
||||
<UiCheckbox
|
||||
:id="checkboxId"
|
||||
:model-value="allowAny"
|
||||
label="Autoriser un format libre"
|
||||
wrapper-class="ml-auto"
|
||||
label-class="gap-3 whitespace-nowrap text-sm"
|
||||
input-class="h-4 w-4 accent-primary-500"
|
||||
@update:modelValue="handleAllowAnyChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -78,13 +79,7 @@ const handleInput = (event: Event) => {
|
||||
emit('update:modelValue', target.value)
|
||||
}
|
||||
|
||||
const toggleAllowAny = (event: Event) => {
|
||||
const target = event.target as HTMLInputElement | null
|
||||
if (!target) {
|
||||
return
|
||||
}
|
||||
|
||||
const nextValue = target.checked
|
||||
const handleAllowAnyChange = (nextValue: boolean) => {
|
||||
emit('update:allowAny', nextValue)
|
||||
if (!nextValue) {
|
||||
emit('update:modelValue', props.modelValue)
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
<template>
|
||||
<iframe ref="printFrame" class="hidden" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { usePdfPrinter } from '~/composables/usePdfPrinter'
|
||||
|
||||
const printFrame = ref<HTMLIFrameElement | null>(null)
|
||||
const { printPdf } = usePdfPrinter()
|
||||
|
||||
// Expose une methode simple pour imprimer un PDF depuis les ecrans.
|
||||
const print = async (url: string): Promise<void> => {
|
||||
return printPdf(url, printFrame)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
print
|
||||
})
|
||||
</script>
|
||||
84
frontend/components/ui/stepper.vue
Normal file
84
frontend/components/ui/stepper.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<div class="relative w-full">
|
||||
<div class="relative h-[18px] text-[16px] uppercase font-bold text-black mb-3">
|
||||
<div
|
||||
v-for="(label, index) in labels"
|
||||
:key="label"
|
||||
class="absolute top-0 whitespace-nowrap"
|
||||
:class="labelClass(index)"
|
||||
:style="positionStyle(index)"
|
||||
>
|
||||
{{ label }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative h-[22px]">
|
||||
<div class="absolute left-0 right-0 top-1/2 h-[2px] -translate-y-1/2 bg-black"></div>
|
||||
<div
|
||||
v-for="(_, index) in labels"
|
||||
:key="index"
|
||||
class="absolute top-1/2 h-[22px] w-[22px] -translate-y-1/2 rounded-full border border-black"
|
||||
:class="[
|
||||
dotClass(index),
|
||||
isActive(index) ? 'bg-black' : 'bg-white',
|
||||
isClickable(index) ? 'cursor-pointer' : 'cursor-not-allowed'
|
||||
]"
|
||||
:style="positionStyle(index)"
|
||||
@click="handleClick(index)"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
type Props = {
|
||||
labels: string[]
|
||||
currentStep: number
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<{
|
||||
(e: 'select', step: number): void
|
||||
}>()
|
||||
|
||||
const stepCount = computed(() => Math.max(props.labels.length, 1))
|
||||
|
||||
const positionStyle = (index: number) => {
|
||||
if (stepCount.value <= 1) {
|
||||
return { left: '0%' }
|
||||
}
|
||||
if (index === 0) {
|
||||
return { left: '0%' }
|
||||
}
|
||||
if (index === stepCount.value - 1) {
|
||||
return { right: '0%' }
|
||||
}
|
||||
const percent = (index / (stepCount.value - 1)) * 100
|
||||
return { left: `${percent}%` }
|
||||
}
|
||||
|
||||
const isMiddle = (index: number) => index > 0 && index < stepCount.value - 1
|
||||
const isLast = (index: number) => index === stepCount.value - 1
|
||||
|
||||
const dotClass = (index: number) => (isMiddle(index) ? '-translate-x-1/2' : '')
|
||||
|
||||
const labelClass = (index: number) => {
|
||||
if (isLast(index)) {
|
||||
return 'text-right'
|
||||
}
|
||||
if (isMiddle(index)) {
|
||||
return 'text-center -translate-x-1/2'
|
||||
}
|
||||
return 'text-left'
|
||||
}
|
||||
|
||||
const isActive = (index: number) => index === props.currentStep
|
||||
|
||||
const isClickable = (index: number) => index <= props.currentStep
|
||||
|
||||
const handleClick = (index: number) => {
|
||||
if (!isClickable(index)) {
|
||||
return
|
||||
}
|
||||
emit('select', index)
|
||||
}
|
||||
</script>
|
||||
@@ -29,6 +29,7 @@ export const useApi = (): ApiClient => {
|
||||
const toast = useToast()
|
||||
const auth = useAuthStore()
|
||||
const nuxtApp = useNuxtApp()
|
||||
let isHandlingUnauthorized = false
|
||||
const i18n = nuxtApp.$i18n as
|
||||
| {
|
||||
t: (key: string) => string
|
||||
@@ -95,7 +96,23 @@ export const useApi = (): ApiClient => {
|
||||
})
|
||||
}
|
||||
},
|
||||
onResponseError({ response, error, options }) {
|
||||
async onResponseError({ response, error, options }) {
|
||||
if (response?.status === 401) {
|
||||
const requestUrl = typeof options?.url === 'string' ? options.url : ''
|
||||
if (!requestUrl.includes('login_check') && !requestUrl.includes('logout')) {
|
||||
if (!isHandlingUnauthorized) {
|
||||
isHandlingUnauthorized = true
|
||||
auth.clearSession()
|
||||
const route = useRoute()
|
||||
if (route.path !== '/login') {
|
||||
await navigateTo('/login')
|
||||
}
|
||||
isHandlingUnauthorized = false
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const apiOptions = options as ApiFetchOptions<'json'>
|
||||
if (apiOptions?.toast === false) {
|
||||
return
|
||||
|
||||
17
frontend/composables/useAppVersion.ts
Normal file
17
frontend/composables/useAppVersion.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
export const useAppVersion = () => {
|
||||
const api = useApi()
|
||||
const version = useState<string | null>('app-version', () => null)
|
||||
|
||||
const load = async () => {
|
||||
if (version.value) {
|
||||
return version.value
|
||||
}
|
||||
const response = await api.get<{ version: string }>('version', {}, {
|
||||
toast: false
|
||||
})
|
||||
version.value = response.version
|
||||
return version.value
|
||||
}
|
||||
|
||||
return { version, load }
|
||||
}
|
||||
@@ -1,40 +1,33 @@
|
||||
import type { Ref } from 'vue'
|
||||
import { useApi } from '~/composables/useApi'
|
||||
|
||||
type PrintFrameRef = Ref<HTMLIFrameElement | null>
|
||||
import {useApi} from '~/composables/useApi'
|
||||
|
||||
export const usePdfPrinter = () => {
|
||||
const api = useApi()
|
||||
const api = useApi()
|
||||
const receptionStore = useReceptionStore()
|
||||
const currentReception = receptionStore.current
|
||||
|
||||
const printPdf = async (url: string, frameRef: PrintFrameRef): Promise<void> => {
|
||||
if (!import.meta.client) {
|
||||
return
|
||||
const printPdf = async (url: string): Promise<void> => {
|
||||
const blob = await api.getBlob(url);
|
||||
|
||||
const pdfBlob = blob.type === 'application/pdf'
|
||||
? blob
|
||||
: new Blob([blob], { type: 'application/pdf' });
|
||||
|
||||
const blobUrl = URL.createObjectURL(pdfBlob);
|
||||
|
||||
const filename = `${currentReception.identificationNumber}_${currentReception.supplier.name}_${currentReception.licensePlate}.pdf`;
|
||||
|
||||
const a = document.createElement('a');
|
||||
a.href = blobUrl;
|
||||
a.download = filename;
|
||||
a.style.display = 'none';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
// L'ouverture dans un nouvel onglet déclenche un 2e PDF sans le nom personnalisé.
|
||||
setTimeout(() => URL.revokeObjectURL(blobUrl), 60_000);
|
||||
}
|
||||
|
||||
const frame = frameRef.value
|
||||
if (!frame) {
|
||||
return
|
||||
return {
|
||||
printPdf
|
||||
}
|
||||
|
||||
// On charge le PDF en blob pour rester en same-origin dans l'iframe.
|
||||
const blob = await api.getBlob(url)
|
||||
const blobUrl = URL.createObjectURL(blob)
|
||||
|
||||
const tryPrint = () => {
|
||||
frame.contentWindow?.focus()
|
||||
frame.contentWindow?.print()
|
||||
}
|
||||
|
||||
frame.onload = () => {
|
||||
tryPrint()
|
||||
// On libere l'URL blob apres l'impression.
|
||||
setTimeout(() => URL.revokeObjectURL(blobUrl), 2000)
|
||||
}
|
||||
frame.src = blobUrl
|
||||
setTimeout(tryPrint, 1200)
|
||||
}
|
||||
|
||||
return {
|
||||
printPdf
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type {Ref} from 'vue'
|
||||
import {computed, ref} from 'vue'
|
||||
import type {ReceptionData, WeightEntryData} from '~/services/dto/reception-data'
|
||||
import type {ReceptionData, ReceptionPayload, WeightEntryData} from '~/services/dto/reception-data'
|
||||
import type {WeightData} from '~/services/dto/weight-data'
|
||||
import {getWeight} from '~/services/reception'
|
||||
import {createWeight, updateWeight} from '~/services/weight'
|
||||
@@ -10,7 +10,7 @@ export type WeighingMode = 'gross' | 'tare'
|
||||
type UseWeighingOptions = {
|
||||
mode: WeighingMode
|
||||
reception: Ref<ReceptionData | null>
|
||||
updateReception: (id: number, payload: Partial<ReceptionData>) => Promise<ReceptionData | null>
|
||||
updateReception: (id: number, payload: ReceptionPayload) => Promise<ReceptionData | null>
|
||||
loadReception?: (id: number) => Promise<ReceptionData | null>
|
||||
}
|
||||
|
||||
|
||||
13
frontend/constants/steps.ts
Normal file
13
frontend/constants/steps.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export enum StepLabel {
|
||||
Reception = 'Réception',
|
||||
GrossWeighing = 'Pesée à plein',
|
||||
Selection = 'Sélection réceptionnées',
|
||||
TareWeighing = 'Pesée à vide'
|
||||
}
|
||||
|
||||
export const RECEPTION_STEP_LABELS = [
|
||||
StepLabel.Reception,
|
||||
StepLabel.GrossWeighing,
|
||||
StepLabel.Selection,
|
||||
StepLabel.TareWeighing
|
||||
]
|
||||
@@ -1,32 +1,72 @@
|
||||
{
|
||||
"errors": {
|
||||
"http": {
|
||||
"get": "Impossible de récupérer les données.",
|
||||
"post": "Impossible de créer la ressource.",
|
||||
"put": "Impossible de mettre à jour la ressource.",
|
||||
"patch": "Impossible de mettre à jour la ressource.",
|
||||
"delete": "Impossible de supprimer la ressource."
|
||||
"errors": {
|
||||
"http": {
|
||||
"get": "Impossible de récupérer les données.",
|
||||
"post": "Impossible de créer la ressource.",
|
||||
"put": "Impossible de mettre à jour la ressource.",
|
||||
"patch": "Impossible de mettre à jour la ressource.",
|
||||
"delete": "Impossible de supprimer la ressource."
|
||||
},
|
||||
"reception": {
|
||||
"list": "Impossible de récupérer la liste des réceptions.",
|
||||
"fetch": "Impossible de récupérer la réception.",
|
||||
"create": "Impossible de créer la réception.",
|
||||
"update": "Impossible de mettre à jour la réception.",
|
||||
"weigh": "Impossible de récupérer la pesée."
|
||||
},
|
||||
"receptionType": {
|
||||
"list": "Impossible de récupérer la liste des types de réception."
|
||||
},
|
||||
"merchandiseType": {
|
||||
"list": "Impossible de récupérer la liste des types de marchandises."
|
||||
},
|
||||
"building": {
|
||||
"list": "Impossible de récupérer la liste des bâtiments."
|
||||
},
|
||||
"pelletType": {
|
||||
"list": "Impossible de récupérer la liste des types de granulés."
|
||||
},
|
||||
"receptionPelletBuilding": {
|
||||
"list": "Impossible de récupérer la liste des dépôts de granulés.",
|
||||
"create": "Impossible d'enregistrer le dépôt de granulés.",
|
||||
"delete": "Impossible de supprimer le dépôt de granulés."
|
||||
},
|
||||
"receptionBovine": {
|
||||
"list": "Impossible de récupérer la liste des bovins de la réception.",
|
||||
"create": "Impossible d'enregistrer le bovin.",
|
||||
"delete": "Impossible de supprimer le bovin."
|
||||
},
|
||||
"supplier": {
|
||||
"list": "Impossible de récupérer la liste des fournisseurs."
|
||||
},
|
||||
"truck": {
|
||||
"list": "Impossible de récupérer la liste des camions."
|
||||
},
|
||||
"bovin": {
|
||||
"list": "Impossible de récupérer la liste des races de bovins."
|
||||
},
|
||||
"carrier": {
|
||||
"list": "Impossible de récupérer la liste des transporteurs."
|
||||
},
|
||||
"driver": {
|
||||
"list": "Impossible de récupérer la liste des chauffeurs."
|
||||
},
|
||||
"vehicle": {
|
||||
"list": "Impossible de récupérer la liste des immatriculations."
|
||||
},
|
||||
"auth": {
|
||||
"login": "Identifiants invalides.",
|
||||
"users": "Impossible de récupérer les utilisateurs.",
|
||||
"logout": "Impossible de se déconnecter."
|
||||
}
|
||||
},
|
||||
"reception": {
|
||||
"list": "Impossible de récupérer la liste des réceptions.",
|
||||
"fetch": "Impossible de récupérer la réception.",
|
||||
"create": "Impossible de créer la réception.",
|
||||
"update": "Impossible de mettre à jour la réception.",
|
||||
"weigh": "Impossible de récupérer la pesée."
|
||||
},
|
||||
"auth": {
|
||||
"login": "Identifiants invalides.",
|
||||
"users": "Impossible de récupérer les utilisateurs.",
|
||||
"logout": "Impossible de se déconnecter."
|
||||
"success": {
|
||||
"reception": {
|
||||
"update": "Réception mise à jour avec succès."
|
||||
},
|
||||
"auth": {
|
||||
"login": "Connexion réussie.",
|
||||
"logout": "Déconnexion réussie."
|
||||
}
|
||||
}
|
||||
},
|
||||
"success": {
|
||||
"reception": {
|
||||
"update": "Réception mise à jour avec succès."
|
||||
},
|
||||
"auth": {
|
||||
"login": "Connexion réussie.",
|
||||
"logout": "Déconnexion réussie."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
71
frontend/layouts/admin.vue
Normal file
71
frontend/layouts/admin.vue
Normal file
@@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<div class="min-h-screen text-neutral-900 grid grid-rows-[85px,1fr]">
|
||||
<!-- HEADER -->
|
||||
<header class="bg-primary-500 z-50 h-[85px]">
|
||||
<div class="h-full w-full px-6 grid grid-cols-[auto,1fr,auto] items-center gap-8">
|
||||
<NuxtLink to="/" class="grid place-items-center">
|
||||
<span class="grid place-items-center bg-white text-xl font-bold uppercase text-primary-500 p-4">
|
||||
LOGO
|
||||
</span>
|
||||
</NuxtLink>
|
||||
|
||||
<nav class="text-2xl font-bold uppercase text-white"></nav>
|
||||
|
||||
<NuxtLink
|
||||
to="/"
|
||||
class="text-xl font-bold uppercase text-white transition hover:opacity-80 justify-self-end"
|
||||
>
|
||||
Quitter le panel admin
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="grid grid-cols-[16rem,1fr] h-[calc(100vh-85px)] min-h-0">
|
||||
<aside class="bg-primary-500 text-white min-h-0 grid grid-rows-[auto,1fr,auto]">
|
||||
<div class="p-4 font-semibold">Tableau de bord</div>
|
||||
|
||||
<div class="overflow-y-auto min-h-0 p-4 space-y-3">
|
||||
<!-- Liste des liens à ajouter ci-dessous -->
|
||||
<!--Button pour afficher le component admin-users -->
|
||||
<NuxtLink
|
||||
to="/admin/user-list"
|
||||
class="block px-4 py-2 rounded hover:bg-primary-600 transition"
|
||||
>
|
||||
Utilisateurs
|
||||
</NuxtLink>
|
||||
</div>
|
||||
|
||||
<div class="p-4">
|
||||
<p class="font-bold text-white text-left">v{{ version }}</p>
|
||||
<button
|
||||
@click="handleLogout"
|
||||
class="w-full bg-red-600 hover:bg-red-700 py-2 rounded font-bold"
|
||||
>
|
||||
Déconnexion
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</aside>
|
||||
|
||||
<main class="min-h-0 overflow-auto px-12 py-12 ">
|
||||
<div class="w-full ">
|
||||
<slot />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script setup lang="ts">
|
||||
import auth from "~/layouts/auth.vue";
|
||||
|
||||
const { version } = useAppVersion()
|
||||
const handleLogout = async () => {
|
||||
try {
|
||||
await auth.logout()
|
||||
} finally {
|
||||
await navigateTo('/login')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,15 +1,16 @@
|
||||
<template>
|
||||
<div class="min-h-screen bg-white text-neutral-900">
|
||||
<header class="w-full border-b border-neutral-200 bg-primary-500">
|
||||
<div class="flex w-full items-center px-6 py-4">
|
||||
<NuxtLink to="/" class="flex items-center gap-3">
|
||||
<span
|
||||
class="flex items-center justify-center bg-white text-xl font-bold uppercase text-primary-500 p-4"
|
||||
>
|
||||
LOGO
|
||||
</span>
|
||||
</NuxtLink>
|
||||
<nav class="mx-8 flex flex-1 gap-8 text-2xl font-bold uppercase text-white">
|
||||
<div class="flex w-full items-center justify-center px-6 py-4">
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex items-center justify-center text-3xl text-white md:hidden"
|
||||
aria-label="Ouvrir le menu"
|
||||
@click="toggleMenu"
|
||||
>
|
||||
<span aria-hidden="true" class="flex items-center"><Icon name="mdi:menu" size="44"/></span>
|
||||
</button>
|
||||
<nav class="ml-4 hidden items-center gap-8 text-2xl font-bold uppercase text-white md:flex">
|
||||
<NuxtLink to="/" custom v-slot="{ href, navigate, isExactActive }">
|
||||
<a
|
||||
:href="href"
|
||||
@@ -19,28 +20,89 @@
|
||||
Accueil
|
||||
</a>
|
||||
</NuxtLink>
|
||||
<NuxtLink to="/reception" custom v-slot="{ href, navigate, isActive }">
|
||||
<NuxtLink to="/admin/dashboard" custom v-slot="{ href, navigate, isActive }">
|
||||
<a
|
||||
:href="href"
|
||||
@click="navigate"
|
||||
:class="isReceptionActive ? 'opacity-100' : 'opacity-50'"
|
||||
>
|
||||
Reception
|
||||
Admin
|
||||
</a>
|
||||
</NuxtLink>
|
||||
</nav>
|
||||
<NuxtLink to="/" class="flex flex-1 items-center justify-center gap-3">
|
||||
<span
|
||||
class="flex items-center justify-center bg-white text-xl font-bold uppercase text-primary-500 p-4"
|
||||
>
|
||||
LOGO
|
||||
</span>
|
||||
</NuxtLink>
|
||||
<div class="w-[44px] md:hidden"></div>
|
||||
<button
|
||||
type="button"
|
||||
class="ml-auto text-xl font-bold uppercase text-white transition hover:opacity-80"
|
||||
class="ml-auto hidden text-xl font-bold uppercase text-white transition hover:opacity-80 md:inline-flex"
|
||||
@click="handleLogout"
|
||||
>
|
||||
Déconnexion
|
||||
</button>
|
||||
</div>
|
||||
<transition
|
||||
enter-active-class="transition duration-200 ease-out"
|
||||
enter-from-class="opacity-0"
|
||||
enter-to-class="opacity-100"
|
||||
leave-active-class="transition duration-150 ease-in"
|
||||
leave-from-class="opacity-100"
|
||||
leave-to-class="opacity-0"
|
||||
>
|
||||
<div
|
||||
v-if="isMenuOpen"
|
||||
class="fixed inset-0 z-40 bg-black/40 md:hidden"
|
||||
@click="closeMenu"
|
||||
/>
|
||||
</transition>
|
||||
<transition
|
||||
enter-active-class="transition duration-200 ease-out"
|
||||
enter-from-class="-translate-x-full"
|
||||
enter-to-class="translate-x-0"
|
||||
leave-active-class="transition duration-150 ease-in"
|
||||
leave-from-class="translate-x-0"
|
||||
leave-to-class="-translate-x-full"
|
||||
>
|
||||
<aside
|
||||
v-if="isMenuOpen"
|
||||
class="fixed left-0 top-0 z-50 h-full w-full bg-primary-600 px-6 pb-8 pt-6 text-white shadow-xl md:hidden"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-2xl font-bold uppercase">Menu</span>
|
||||
<button
|
||||
type="button"
|
||||
class="text-2xl"
|
||||
aria-label="Fermer le menu"
|
||||
@click="closeMenu"
|
||||
>
|
||||
<Icon name="mdi:close" size="44"/>
|
||||
</button>
|
||||
</div>
|
||||
<nav class="mt-8 flex flex-col gap-6 text-xl font-bold uppercase">
|
||||
<NuxtLink to="/" class="opacity-100" @click="closeMenu">Accueil</NuxtLink>
|
||||
</nav>
|
||||
<button
|
||||
type="button"
|
||||
class="mt-5 text-xl font-bold uppercase"
|
||||
@click="handleLogout"
|
||||
>
|
||||
Déconnexion
|
||||
</button>
|
||||
</aside>
|
||||
</transition>
|
||||
</header>
|
||||
<main class="mx-auto w-full max-w-[1050px] px-6 pt-[90px] pb-0">
|
||||
<main class="mx-auto w-full max-w-[1280px] pb-0">
|
||||
<slot/>
|
||||
</main>
|
||||
<footer class="w-full mt-8 bg-primary-500 p-6">
|
||||
<p class="font-bold text-white text-right">v{{ version }}</p>
|
||||
</footer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -49,12 +111,22 @@ import { useAuthStore } from '~/stores/auth'
|
||||
|
||||
const route = useRoute()
|
||||
const auth = useAuthStore()
|
||||
const isReceptionActive = computed(() => route.path.startsWith('/reception'))
|
||||
const isMenuOpen = ref(false)
|
||||
const { version } = useAppVersion()
|
||||
|
||||
const closeMenu = () => {
|
||||
isMenuOpen.value = false
|
||||
}
|
||||
|
||||
const toggleMenu = () => {
|
||||
isMenuOpen.value = !isMenuOpen.value
|
||||
}
|
||||
|
||||
const handleLogout = async () => {
|
||||
try {
|
||||
await auth.logout()
|
||||
} finally {
|
||||
closeMenu()
|
||||
await navigateTo('/login')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,10 @@ export default defineNuxtConfig({
|
||||
'@nuxtjs/tailwindcss',
|
||||
'@pinia/nuxt',
|
||||
'nuxt-toast',
|
||||
'@nuxtjs/i18n'
|
||||
'@nuxtjs/i18n',
|
||||
'@nuxt/icon'
|
||||
],
|
||||
css: ['~/assets/css/toast.css'],
|
||||
css: ['~/assets/css/main.css', '~/assets/css/toast.css'],
|
||||
runtimeConfig: {
|
||||
public: {
|
||||
apiBase: process.env.NUXT_PUBLIC_API_BASE
|
||||
@@ -19,7 +20,7 @@ export default defineNuxtConfig({
|
||||
},
|
||||
toast: {
|
||||
settings: {
|
||||
timeout: 0,
|
||||
timeout: 10000,
|
||||
closeOnClick: true,
|
||||
progressBar: false
|
||||
}
|
||||
|
||||
77
frontend/package-lock.json
generated
77
frontend/package-lock.json
generated
@@ -7,6 +7,7 @@
|
||||
"name": "frontend",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@nuxt/icon": "^2.2.1",
|
||||
"@nuxtjs/i18n": "^10.2.1",
|
||||
"@pinia/nuxt": "^0.11.3",
|
||||
"izitoast": "^1.4.0",
|
||||
@@ -35,6 +36,19 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@antfu/install-pkg": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz",
|
||||
"integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"package-manager-detector": "^1.3.0",
|
||||
"tinyexec": "^1.0.1"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.27.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
|
||||
@@ -1248,6 +1262,47 @@
|
||||
"url": "https://github.com/sponsors/nzakas"
|
||||
}
|
||||
},
|
||||
"node_modules/@iconify/collections": {
|
||||
"version": "1.0.646",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/collections/-/collections-1.0.646.tgz",
|
||||
"integrity": "sha512-zA5Gr1MJm1SI0TjOUl7wu4kvBWXQ6Uh8ALEtqQ5ucXyUxP2M8m2bk2hfVtGykSdMlDB+Xs2AHbJ9pQqayz9WGQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@iconify/types": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@iconify/types": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz",
|
||||
"integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@iconify/utils": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.0.tgz",
|
||||
"integrity": "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@antfu/install-pkg": "^1.1.0",
|
||||
"@iconify/types": "^2.0.0",
|
||||
"mlly": "^1.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@iconify/vue": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@iconify/vue/-/vue-5.0.0.tgz",
|
||||
"integrity": "sha512-C+KuEWIF5nSBrobFJhT//JS87OZ++QDORB6f2q2Wm6fl2mueSTpFBeBsveK0KW9hWiZ4mNiPjsh6Zs4jjdROSg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@iconify/types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/cyberalien"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": ">=3"
|
||||
}
|
||||
},
|
||||
"node_modules/@intlify/bundle-utils": {
|
||||
"version": "11.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@intlify/bundle-utils/-/bundle-utils-11.0.3.tgz",
|
||||
@@ -2268,6 +2323,28 @@
|
||||
"devtools-wizard": "cli.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@nuxt/icon": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@nuxt/icon/-/icon-2.2.1.tgz",
|
||||
"integrity": "sha512-GI840yYGuvHI0BGDQ63d6rAxGzG96jQcWrnaWIQKlyQo/7sx9PjXkSHckXUXyX1MCr9zY6U25Td6OatfY6Hklw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@iconify/collections": "^1.0.641",
|
||||
"@iconify/types": "^2.0.0",
|
||||
"@iconify/utils": "^3.1.0",
|
||||
"@iconify/vue": "^5.0.0",
|
||||
"@nuxt/devtools-kit": "^3.1.1",
|
||||
"@nuxt/kit": "^4.2.2",
|
||||
"consola": "^3.4.2",
|
||||
"local-pkg": "^1.1.2",
|
||||
"mlly": "^1.8.0",
|
||||
"ohash": "^2.0.11",
|
||||
"pathe": "^2.0.3",
|
||||
"picomatch": "^4.0.3",
|
||||
"std-env": "^3.10.0",
|
||||
"tinyglobby": "^0.2.15"
|
||||
}
|
||||
},
|
||||
"node_modules/@nuxt/kit": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-4.2.2.tgz",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"build:dist": "nuxt generate && rm -rf dist && cp -R .output/public dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxt/icon": "^2.2.1",
|
||||
"@nuxtjs/i18n": "^10.2.1",
|
||||
"@pinia/nuxt": "^0.11.3",
|
||||
"izitoast": "^1.4.0",
|
||||
|
||||
13
frontend/pages/admin/dashboard.vue
Normal file
13
frontend/pages/admin/dashboard.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<admin-users v-if="activeCode === 'users'" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
definePageMeta({
|
||||
layout: 'admin'
|
||||
})
|
||||
const route = useRoute()
|
||||
|
||||
const activeCode = computed(() => (route.query.code as string))
|
||||
|
||||
</script>
|
||||
64
frontend/pages/admin/user-list.vue
Normal file
64
frontend/pages/admin/user-list.vue
Normal file
@@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<div class="flex items-center justify-between gap-10">
|
||||
<h1 class="text-3xl font-bold uppercase">Utilisateurs</h1>
|
||||
<button
|
||||
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]"
|
||||
@click="null"
|
||||
>
|
||||
Ajouter
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="mt-6 border border-slate-200 mb-16 ">
|
||||
<div class="grid grid-cols-3 gap-4 bg-slate-100 px-4 py-3 text-sm font-semibold uppercase tracking-wide">
|
||||
<div>Username</div>
|
||||
<div>Role</div>
|
||||
<div>Action</div>
|
||||
</div>
|
||||
<div
|
||||
v-for="user in userList"
|
||||
:key="user.id"
|
||||
class="grid grid-cols-3 gap-4 px-4 py-3 text-sm hover:bg-slate-50 cursor-pointer border-t border-slate-200 items-center"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div>
|
||||
{{ user.username}}
|
||||
</div>
|
||||
<div>
|
||||
{{ user.roles?.join(', ') || ' ---' }}
|
||||
</div>
|
||||
<div>
|
||||
<div class="p-4">
|
||||
<button
|
||||
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]"
|
||||
@click="null"
|
||||
>
|
||||
Modifier
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
|
||||
|
||||
<script setup lang="ts">
|
||||
definePageMeta({
|
||||
layout: 'admin'
|
||||
})
|
||||
|
||||
import type {UserData} from "~/services/dto/user-data";
|
||||
import {getUsers} from "~/services/auth";
|
||||
|
||||
const userList = ref<UserData[]>([])
|
||||
|
||||
|
||||
onMounted(async () => {
|
||||
userList.value = await getUsers()
|
||||
})
|
||||
</script>
|
||||
@@ -1,21 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
</script>
|
||||
<template>
|
||||
<div class="">
|
||||
<h1 class="text-3xl font-bold">Liste des receptions</h1>
|
||||
<ul>
|
||||
<li v-for="reception in receptionList" :key="reception.id">
|
||||
<NuxtLink :to="`/reception/${reception.id}`">Réception numéro {{ reception.id}}</NuxtLink>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="flex flex-wrap justify-center mt-8 gap-8 mb-8 md:mb-0">
|
||||
<card-link label="NOUVELLE RÉCEPTION" link="/reception" iconName="mdi:truck-outline" />
|
||||
<card-link label="NOUVELLE EXPÉDITION" link="/" iconName="mdi:truck-fast-outline" />
|
||||
<card-link label="PLAN DE SITE" link="/" iconName="mdi:warehouse" />
|
||||
<card-link label="RÉCEPTIONS EN ATTENTE" link="/reception/waiting-reception" iconName="mdi:truck-remove-outline" />
|
||||
<card-link label="EXPÉDITIONS EN ATTENTE" link="/" iconName="mdi:truck-cargo-container" />
|
||||
<card-link label="CASES" link="/" iconName="mdi:cube-outline" />
|
||||
<card-link label="RÉCEPTIONS FINIES" link="/reception/finish-reception" iconName="mdi:truck-check-outline" />
|
||||
<card-link label="EXPÉDITIONS FINIES" link="/" iconName="mdi:truck-delivery-outline" />
|
||||
<card-link label="PASSEPORT DU BOVIN" link="/" iconName="mdi:cow" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type {ReceptionData} from "~/services/dto/reception-data";
|
||||
import {getReceptionList} from "~/services/reception";
|
||||
|
||||
const receptionList = ref<ReceptionData[]>()
|
||||
|
||||
onMounted(async () => {
|
||||
receptionList.value = await getReceptionList()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -46,7 +46,8 @@
|
||||
>
|
||||
Connexion
|
||||
</button>
|
||||
</form>
|
||||
<p class="font-bold">v{{ version }}</p>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -57,6 +58,7 @@ import { useAuthStore } from '~/stores/auth'
|
||||
|
||||
const router = useRouter()
|
||||
const auth = useAuthStore()
|
||||
const { version } = useAppVersion()
|
||||
|
||||
definePageMeta({
|
||||
layout: 'auth'
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="flex justify-between h-[52px] mb-[90px]">
|
||||
<p class="self-center">Indicateur d’étapes</p>
|
||||
<div class="flex justify-between h-[52px] mb-[80px]">
|
||||
<div class="flex flex-1 mr-16">
|
||||
<UiStepper
|
||||
:labels="RECEPTION_STEP_LABELS"
|
||||
:current-step="storeReception?.currentStep ?? 0"
|
||||
@select="handleStepSelect"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="flex flex-col justify-center uppercase text-xl bg-black text-white h-[50px] w-[272px] text-center"
|
||||
@@ -10,20 +16,27 @@
|
||||
</div>
|
||||
<ReceptionForm v-if="!storeReception || storeReception.currentStep === 0"/>
|
||||
<ReceptionWeight v-if="storeReception?.currentStep === 1" mode="gross"/>
|
||||
<ReceptionUnloading v-if="storeReception?.currentStep === 2"/>
|
||||
<ReceptionProductReceived
|
||||
v-if="storeReception?.currentStep === 2 &&
|
||||
receptionStore.current?.receptionType?.code === RECEPTION_TYPE_CODES.MERCHANDISES"/>
|
||||
<ReceptionBovineReceived
|
||||
v-if="storeReception?.currentStep === 2 &&
|
||||
receptionStore.current?.receptionType?.code === RECEPTION_TYPE_CODES.BOVINS"/>
|
||||
<ReceptionWeight v-if="storeReception?.currentStep !== null && storeReception?.currentStep >= 3" mode="tare"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useReceptionStore } from '~/stores/reception'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import {useReceptionStore} from '~/stores/reception'
|
||||
import {storeToRefs} from 'pinia'
|
||||
import {RECEPTION_STEP_LABELS} from '~/constants/steps'
|
||||
import {RECEPTION_TYPE_CODES} from "~/utils/constants";
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const receptionStore = useReceptionStore()
|
||||
const { current: storeReception } = storeToRefs(receptionStore)
|
||||
const {current: storeReception} = storeToRefs(receptionStore)
|
||||
|
||||
const resolveReceptionId = (param: unknown) => {
|
||||
const idStr = Array.isArray(param) ? param[0] : param
|
||||
@@ -44,7 +57,7 @@ watch(
|
||||
}
|
||||
await receptionStore.loadReception(id)
|
||||
},
|
||||
{ immediate: true }
|
||||
{immediate: true}
|
||||
)
|
||||
|
||||
const saveAndHold = async () => {
|
||||
@@ -60,4 +73,19 @@ const saveAndHold = async () => {
|
||||
})
|
||||
await router.push('/')
|
||||
}
|
||||
|
||||
const handleStepSelect = async (step: number) => {
|
||||
if (!receptionStore.current) {
|
||||
return
|
||||
}
|
||||
|
||||
if (step === receptionStore.current.currentStep) {
|
||||
return
|
||||
}
|
||||
|
||||
await receptionStore.updateReception(receptionStore.current.id, {
|
||||
currentStep: step
|
||||
})
|
||||
await receptionStore.loadReception(receptionStore.current.id)
|
||||
}
|
||||
</script>
|
||||
|
||||
53
frontend/pages/reception/finish-reception.vue
Normal file
53
frontend/pages/reception/finish-reception.vue
Normal file
@@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<div class="flex items-center justify-start gap-10">
|
||||
<Icon @click="router.push('/')" name="gg:arrow-left-o" style="color: black" size="44" />
|
||||
<h1 class="text-3xl font-bold uppercase">listes des réceptions finie</h1>
|
||||
</div>
|
||||
|
||||
<div class="ps-20 " >
|
||||
<div class="mt-6 border border-slate-200 mb-16 ">
|
||||
<div class="grid grid-cols-6 gap-4 bg-slate-100 px-4 py-3 text-sm font-semibold uppercase tracking-wide">
|
||||
<div>Numéro</div>
|
||||
<div>Date</div>
|
||||
<div>Fournisseur</div>
|
||||
<div>Adresse</div>
|
||||
<div>Type réception</div>
|
||||
<div>Poids</div>
|
||||
</div>
|
||||
<div
|
||||
v-for="reception in receptionList"
|
||||
:key="reception.id"
|
||||
class="grid grid-cols-6 gap-4 px-4 py-3 text-sm hover:bg-slate-50 cursor-pointer border-t border-slate-200"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<div>{{ reception.identificationNumber}}</div>
|
||||
<div>{{ reception.receptionDate}}</div>
|
||||
<div>{{ reception.supplier?.name }}</div>
|
||||
<div>{{ reception.address?.fullAddress }}</div>
|
||||
<div>{{ reception.receptionType?.label }}</div>
|
||||
<div>{{ formatWeighing(reception, 'gross') }} | {{ formatWeighing(reception, 'tare') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type {ReceptionData} from "~/services/dto/reception-data";
|
||||
import {getReceptionList} from "~/services/reception";
|
||||
|
||||
const receptionList = ref<ReceptionData[]>()
|
||||
const router = useRouter()
|
||||
|
||||
const formatWeighing = (reception: ReceptionData, type: 'gross' | 'tare') => {
|
||||
const entry = reception.weights?.find((weight) => weight.type === type)
|
||||
if (!entry || entry.weight == null || entry.dsd == null) {
|
||||
return '—'
|
||||
}
|
||||
return `${entry.weight} kg`
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
receptionList.value = await getReceptionList(true)
|
||||
})
|
||||
</script>
|
||||
51
frontend/pages/reception/waiting-reception.vue
Normal file
51
frontend/pages/reception/waiting-reception.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<div class="flex items-center justify-between ">
|
||||
<div class="flex items-center gap-10">
|
||||
<Icon @click="router.push('/')" name="gg:arrow-left-o" style="color: black" size="44" />
|
||||
<h1 class="text-3xl font-bold uppercase">listes des réceptions en attente</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ps-20 " >
|
||||
<div class="mt-6 border border-slate-200 mb-16 ">
|
||||
<div class="grid grid-cols-5 gap-4 bg-slate-100 px-4 py-3 text-sm font-semibold uppercase tracking-wide">
|
||||
<div>Fournisseur</div>
|
||||
<div>Adresse</div>
|
||||
<div>Type réception</div>
|
||||
<div>Transporteur</div>
|
||||
<div>Immatriculation</div>
|
||||
</div>
|
||||
<div
|
||||
v-for="reception in receptionList"
|
||||
:key="reception.id"
|
||||
class="grid grid-cols-5 gap-4 px-4 py-3 text-sm hover:bg-slate-50 cursor-pointer border-t border-slate-200"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@click="goToReception(reception.id)"
|
||||
@keydown.enter="goToReception(reception.id)"
|
||||
>
|
||||
<div>{{ reception.supplier?.name }}</div>
|
||||
<div>{{ reception.address?.fullAddress }}</div>
|
||||
<div>{{ reception.receptionType?.label }}</div>
|
||||
<div>{{ reception.carrier?.name }}</div>
|
||||
<div>{{ reception.licensePlate }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type {ReceptionData} from "~/services/dto/reception-data";
|
||||
import {getReceptionList} from "~/services/reception";
|
||||
|
||||
const receptionList = ref<ReceptionData[]>()
|
||||
const router = useRouter()
|
||||
|
||||
const goToReception = (id: number) => {
|
||||
router.push(`/reception/${id}`)
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
receptionList.value = await getReceptionList(false)
|
||||
})
|
||||
</script>
|
||||
23
frontend/services/bovine-type.ts
Normal file
23
frontend/services/bovine-type.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { useApi } from '~/composables/useApi'
|
||||
import type {BovineTypeData} from "~/services/dto/bovine-type-data";
|
||||
|
||||
export type BovineTypeListResponse =
|
||||
| BovineTypeData[]
|
||||
| { 'hydra:member'?: BovineTypeData[] }
|
||||
|
||||
export async function getBovineTypeList(): Promise<BovineTypeData[]> {
|
||||
const api = useApi()
|
||||
const response = await api.get<BovineTypeListResponse>('bovine_types', {}, {
|
||||
toastErrorKey: 'errors.bovin.list'
|
||||
})
|
||||
|
||||
if (Array.isArray(response)) {
|
||||
return response
|
||||
}
|
||||
|
||||
if (response && typeof response === 'object' && Array.isArray(response['hydra:member'])) {
|
||||
return response['hydra:member']
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
23
frontend/services/building.ts
Normal file
23
frontend/services/building.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { useApi } from '~/composables/useApi'
|
||||
import type { BuildingData } from '~/services/dto/building-data'
|
||||
|
||||
export type BuildingListResponse =
|
||||
| BuildingData[]
|
||||
| { 'hydra:member'?: BuildingData[] }
|
||||
|
||||
export async function getBuildingList(): Promise<BuildingData[]> {
|
||||
const api = useApi()
|
||||
const response = await api.get<BuildingListResponse>('buildings', {}, {
|
||||
toastErrorKey: 'errors.building.list'
|
||||
})
|
||||
|
||||
if (Array.isArray(response)) {
|
||||
return response
|
||||
}
|
||||
|
||||
if (response && typeof response === 'object' && Array.isArray(response['hydra:member'])) {
|
||||
return response['hydra:member']
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
23
frontend/services/carrier.ts
Normal file
23
frontend/services/carrier.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { useApi } from '~/composables/useApi'
|
||||
import type { CarrierData } from '~/services/dto/carrier-data'
|
||||
|
||||
export type CarrierListResponse =
|
||||
| CarrierData[]
|
||||
| { 'hydra:member'?: CarrierData[] }
|
||||
|
||||
export async function getCarrierList(): Promise<CarrierData[]> {
|
||||
const api = useApi()
|
||||
const response = await api.get<CarrierListResponse>('carriers', {}, {
|
||||
toastErrorKey: 'errors.carrier.list'
|
||||
})
|
||||
|
||||
if (Array.isArray(response)) {
|
||||
return response
|
||||
}
|
||||
|
||||
if (response && typeof response === 'object' && Array.isArray(response['hydra:member'])) {
|
||||
return response['hydra:member']
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
23
frontend/services/driver.ts
Normal file
23
frontend/services/driver.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { useApi } from '~/composables/useApi'
|
||||
import type { DriverData } from '~/services/dto/driver-data'
|
||||
|
||||
export type DriverListResponse =
|
||||
| DriverData[]
|
||||
| { 'hydra:member'?: DriverData[] }
|
||||
|
||||
export async function getDriverList(): Promise<DriverData[]> {
|
||||
const api = useApi()
|
||||
const response = await api.get<DriverListResponse>('drivers', {}, {
|
||||
toastErrorKey: 'errors.driver.list'
|
||||
})
|
||||
|
||||
if (Array.isArray(response)) {
|
||||
return response
|
||||
}
|
||||
|
||||
if (response && typeof response === 'object' && Array.isArray(response['hydra:member'])) {
|
||||
return response['hydra:member']
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
10
frontend/services/dto/address-data.ts
Normal file
10
frontend/services/dto/address-data.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export interface AddressData {
|
||||
id: number
|
||||
label: string
|
||||
street: string
|
||||
street2?: string | null
|
||||
postalCode: string
|
||||
city: string
|
||||
countryCode: string
|
||||
fullAddress?: string
|
||||
}
|
||||
5
frontend/services/dto/bovine-type-data.ts
Normal file
5
frontend/services/dto/bovine-type-data.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface BovineTypeData{
|
||||
id: number
|
||||
label: string
|
||||
code: string
|
||||
}
|
||||
5
frontend/services/dto/building-data.ts
Normal file
5
frontend/services/dto/building-data.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface BuildingData {
|
||||
id: number
|
||||
label: string
|
||||
code: string
|
||||
}
|
||||
5
frontend/services/dto/carrier-data.ts
Normal file
5
frontend/services/dto/carrier-data.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface CarrierData {
|
||||
id: number
|
||||
name: string
|
||||
code: string
|
||||
}
|
||||
7
frontend/services/dto/driver-data.ts
Normal file
7
frontend/services/dto/driver-data.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { CarrierData } from '~/services/dto/carrier-data'
|
||||
|
||||
export interface DriverData {
|
||||
id: number
|
||||
name: string
|
||||
carrier?: CarrierData | null
|
||||
}
|
||||
5
frontend/services/dto/merchandise-type-data.ts
Normal file
5
frontend/services/dto/merchandise-type-data.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface MerchandiseTypeData {
|
||||
id: number
|
||||
label: string
|
||||
code: string
|
||||
}
|
||||
5
frontend/services/dto/pellet-type-data.ts
Normal file
5
frontend/services/dto/pellet-type-data.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface PelletTypeData {
|
||||
id: number
|
||||
label: string
|
||||
code: string
|
||||
}
|
||||
8
frontend/services/dto/reception-bovine-data.ts
Normal file
8
frontend/services/dto/reception-bovine-data.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import type {BovineTypeData} from "~/services/dto/bovine-type-data";
|
||||
|
||||
export interface ReceptionBovineTypeData{
|
||||
id: number
|
||||
quantity : number
|
||||
reception?: string
|
||||
bovineType: BovineTypeData
|
||||
}
|
||||
@@ -1,10 +1,36 @@
|
||||
import type { ReceptionTypeData } from '~/services/dto/reception-type-data'
|
||||
import type { MerchandiseTypeData } from '~/services/dto/merchandise-type-data'
|
||||
import type { BuildingData } from '~/services/dto/building-data'
|
||||
import type { ReceptionPelletBuildingData } from '~/services/dto/reception-pellet-building-data'
|
||||
import type { UserData } from '~/services/dto/user-data'
|
||||
import type { SupplierData } from '~/services/dto/supplier-data'
|
||||
import type { AddressData } from '~/services/dto/address-data'
|
||||
import type { TruckData } from '~/services/dto/truck-data'
|
||||
import type { CarrierData } from '~/services/dto/carrier-data'
|
||||
import type { DriverData } from '~/services/dto/driver-data'
|
||||
import type {BovineTypeData} from "~/services/dto/bovine-type-data";
|
||||
|
||||
export interface ReceptionData {
|
||||
id: number
|
||||
identificationNumber?: string | null
|
||||
licensePlate: string | null
|
||||
weights?: WeightEntryData[] | null
|
||||
receptionDate: string
|
||||
currentStep: number
|
||||
isValid: boolean
|
||||
receptionType?: ReceptionTypeData | null
|
||||
merchandiseType?: MerchandiseTypeData | null
|
||||
merchandiseDetail?: string | null
|
||||
bovineDetail?: string | null
|
||||
buildings?: BuildingData[] | null
|
||||
bovinesTypes?: BovineTypeData[] | null
|
||||
pelletBuildings?: ReceptionPelletBuildingData[] | null
|
||||
user?: UserData | null
|
||||
supplier?: SupplierData | null
|
||||
address?: AddressData | null
|
||||
truck?: TruckData | null
|
||||
carrier?: CarrierData | null
|
||||
driver?: DriverData | null
|
||||
}
|
||||
|
||||
export interface WeightEntryData {
|
||||
@@ -14,3 +40,22 @@ export interface WeightEntryData {
|
||||
weight: number | null
|
||||
weighedAt: string | null
|
||||
}
|
||||
|
||||
export type ReceptionPayload = {
|
||||
licensePlate?: string | null
|
||||
receptionDate?: string
|
||||
currentStep?: number
|
||||
isValid?: boolean
|
||||
receptionType?: string | null
|
||||
merchandiseType?: string | null
|
||||
merchandiseDetail?: string | null
|
||||
bovineDetail?: string | null
|
||||
buildings?: string[] | null
|
||||
bovinesTypes?: string[] | null
|
||||
user?: string | null
|
||||
supplier?: string | null
|
||||
address?: string | null
|
||||
truck?: string | null
|
||||
carrier?: string | null
|
||||
driver?: string | null
|
||||
}
|
||||
|
||||
9
frontend/services/dto/reception-pellet-building-data.ts
Normal file
9
frontend/services/dto/reception-pellet-building-data.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import type { BuildingData } from '~/services/dto/building-data'
|
||||
import type { PelletTypeData } from '~/services/dto/pellet-type-data'
|
||||
|
||||
export interface ReceptionPelletBuildingData {
|
||||
id: number
|
||||
reception?: string
|
||||
building: BuildingData
|
||||
pelletType: PelletTypeData
|
||||
}
|
||||
5
frontend/services/dto/reception-type-data.ts
Normal file
5
frontend/services/dto/reception-type-data.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export interface ReceptionTypeData {
|
||||
id: number
|
||||
label: string
|
||||
code: string
|
||||
}
|
||||
9
frontend/services/dto/supplier-data.ts
Normal file
9
frontend/services/dto/supplier-data.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import type { AddressData } from '~/services/dto/address-data'
|
||||
|
||||
export interface SupplierData {
|
||||
id: number
|
||||
name: string
|
||||
email?: string | null
|
||||
phone?: string | null
|
||||
addresses?: AddressData[] | null
|
||||
}
|
||||
4
frontend/services/dto/truck-data.ts
Normal file
4
frontend/services/dto/truck-data.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export interface TruckData {
|
||||
id: number
|
||||
name: string
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
export interface UserData {
|
||||
id: number
|
||||
username: string
|
||||
roles?: string[]
|
||||
}
|
||||
|
||||
9
frontend/services/dto/vehicle-data.ts
Normal file
9
frontend/services/dto/vehicle-data.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import type { CarrierData } from '~/services/dto/carrier-data'
|
||||
import type { TruckData } from '~/services/dto/truck-data'
|
||||
|
||||
export interface VehicleData {
|
||||
id: number
|
||||
plate: string
|
||||
carrier?: CarrierData | null
|
||||
truck?: TruckData | null
|
||||
}
|
||||
23
frontend/services/merchandise-type.ts
Normal file
23
frontend/services/merchandise-type.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { useApi } from '~/composables/useApi'
|
||||
import type { MerchandiseTypeData } from '~/services/dto/merchandise-type-data'
|
||||
|
||||
export type MerchandiseTypeListResponse =
|
||||
| MerchandiseTypeData[]
|
||||
| { 'hydra:member'?: MerchandiseTypeData[] }
|
||||
|
||||
export async function getMerchandiseTypeList(): Promise<MerchandiseTypeData[]> {
|
||||
const api = useApi()
|
||||
const response = await api.get<MerchandiseTypeListResponse>('merchandise_types', {}, {
|
||||
toastErrorKey: 'errors.merchandiseType.list'
|
||||
})
|
||||
|
||||
if (Array.isArray(response)) {
|
||||
return response
|
||||
}
|
||||
|
||||
if (response && typeof response === 'object' && Array.isArray(response['hydra:member'])) {
|
||||
return response['hydra:member']
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
23
frontend/services/pellet-type.ts
Normal file
23
frontend/services/pellet-type.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { useApi } from '~/composables/useApi'
|
||||
import type { PelletTypeData } from '~/services/dto/pellet-type-data'
|
||||
|
||||
export type PelletTypeListResponse =
|
||||
| PelletTypeData[]
|
||||
| { 'hydra:member'?: PelletTypeData[] }
|
||||
|
||||
export async function getPelletTypeList(): Promise<PelletTypeData[]> {
|
||||
const api = useApi()
|
||||
const response = await api.get<PelletTypeListResponse>('pellet_types', {}, {
|
||||
toastErrorKey: 'errors.pelletType.list'
|
||||
})
|
||||
|
||||
if (Array.isArray(response)) {
|
||||
return response
|
||||
}
|
||||
|
||||
if (response && typeof response === 'object' && Array.isArray(response['hydra:member'])) {
|
||||
return response['hydra:member']
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
59
frontend/services/reception-bovine.ts
Normal file
59
frontend/services/reception-bovine.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { useApi } from '~/composables/useApi'
|
||||
import type { ReceptionBovineTypeData } from '~/services/dto/reception-bovine-data'
|
||||
|
||||
export type ReceptionBovineListResponse =
|
||||
| ReceptionBovineTypeData[]
|
||||
| { 'hydra:member'?: ReceptionBovineTypeData[] }
|
||||
|
||||
export type ReceptionBovinePayload = {
|
||||
quantity: number
|
||||
reception: string
|
||||
bovineType: string
|
||||
}
|
||||
|
||||
export async function getReceptionBovineList(
|
||||
receptionIri: string
|
||||
): Promise<ReceptionBovineTypeData[]> {
|
||||
const api = useApi()
|
||||
const response = await api.get<ReceptionBovineListResponse>(
|
||||
'reception_bovines',
|
||||
{ reception: receptionIri },
|
||||
{
|
||||
toastErrorKey: 'errors.receptionBovine.list'
|
||||
}
|
||||
)
|
||||
|
||||
if (Array.isArray(response)) {
|
||||
return response
|
||||
}
|
||||
if (response && typeof response === 'object' && Array.isArray(response['hydra:member'])) {
|
||||
return response['hydra:member']
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
export async function createReceptionBovine(
|
||||
payload: ReceptionBovinePayload
|
||||
): Promise<ReceptionBovineTypeData> {
|
||||
const api = useApi()
|
||||
return api.post<ReceptionBovineTypeData>('reception_bovines', payload, {
|
||||
toastErrorKey: 'errors.receptionBovine.create'
|
||||
})
|
||||
}
|
||||
|
||||
export async function deleteReceptionBovine(id: number): Promise<void> {
|
||||
const api = useApi()
|
||||
await api.delete<void>(`reception_bovines/${id}`, {}, {
|
||||
toastErrorKey: 'errors.receptionBovine.delete'
|
||||
})
|
||||
}
|
||||
|
||||
export async function updateReceptionBovine(
|
||||
id: number,
|
||||
payload: Partial<ReceptionBovinePayload>
|
||||
): Promise<ReceptionBovineTypeData> {
|
||||
const api = useApi()
|
||||
return api.patch<ReceptionBovineTypeData>(`reception_bovines/${id}`, payload, {
|
||||
toastErrorKey: 'errors.receptionBovine.update'
|
||||
})
|
||||
}
|
||||
51
frontend/services/reception-pellet-building.ts
Normal file
51
frontend/services/reception-pellet-building.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { useApi } from '~/composables/useApi'
|
||||
import type { ReceptionPelletBuildingData } from '~/services/dto/reception-pellet-building-data'
|
||||
|
||||
export type ReceptionPelletBuildingListResponse =
|
||||
| ReceptionPelletBuildingData[]
|
||||
| { 'hydra:member'?: ReceptionPelletBuildingData[] }
|
||||
|
||||
export type ReceptionPelletBuildingPayload = {
|
||||
reception: string
|
||||
pelletType: string
|
||||
building: string
|
||||
}
|
||||
|
||||
export async function getReceptionPelletBuildingList(
|
||||
receptionIri: string
|
||||
): Promise<ReceptionPelletBuildingData[]> {
|
||||
const api = useApi()
|
||||
const response = await api.get<ReceptionPelletBuildingListResponse>(
|
||||
'reception_pellet_buildings',
|
||||
{ reception: receptionIri },
|
||||
{
|
||||
toastErrorKey: 'errors.receptionPelletBuilding.list'
|
||||
}
|
||||
)
|
||||
|
||||
if (Array.isArray(response)) {
|
||||
return response
|
||||
}
|
||||
|
||||
if (response && typeof response === 'object' && Array.isArray(response['hydra:member'])) {
|
||||
return response['hydra:member']
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
export async function createReceptionPelletBuilding(
|
||||
payload: ReceptionPelletBuildingPayload
|
||||
): Promise<ReceptionPelletBuildingData> {
|
||||
const api = useApi()
|
||||
return api.post<ReceptionPelletBuildingData>('reception_pellet_buildings', payload, {
|
||||
toastErrorKey: 'errors.receptionPelletBuilding.create'
|
||||
})
|
||||
}
|
||||
|
||||
export async function deleteReceptionPelletBuilding(id: number): Promise<void> {
|
||||
const api = useApi()
|
||||
await api.delete<void>(`reception_pellet_buildings/${id}`, {}, {
|
||||
toastErrorKey: 'errors.receptionPelletBuilding.delete'
|
||||
})
|
||||
}
|
||||
23
frontend/services/reception-type.ts
Normal file
23
frontend/services/reception-type.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { useApi } from '~/composables/useApi'
|
||||
import type { ReceptionTypeData } from '~/services/dto/reception-type-data'
|
||||
|
||||
export type ReceptionTypeListResponse =
|
||||
| ReceptionTypeData[]
|
||||
| { 'hydra:member'?: ReceptionTypeData[] }
|
||||
|
||||
export async function getReceptionTypeList(): Promise<ReceptionTypeData[]> {
|
||||
const api = useApi()
|
||||
const response = await api.get<ReceptionTypeListResponse>('reception_types', {}, {
|
||||
toastErrorKey: 'errors.receptionType.list'
|
||||
})
|
||||
|
||||
if (Array.isArray(response)) {
|
||||
return response
|
||||
}
|
||||
|
||||
if (response && typeof response === 'object' && Array.isArray(response['hydra:member'])) {
|
||||
return response['hydra:member']
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
@@ -1,14 +1,16 @@
|
||||
import {useApi} from '~/composables/useApi'
|
||||
import type {ReceptionData} from '~/services/dto/reception-data'
|
||||
import type {ReceptionData, ReceptionPayload} from '~/services/dto/reception-data'
|
||||
import type {WeightData} from '~/services/dto/weight-data'
|
||||
|
||||
export async function getReceptionList() {
|
||||
export async function getReceptionList(isValid: boolean|null = null) {
|
||||
const api = useApi()
|
||||
return api.get<ReceptionData>(`receptions`, {}, {
|
||||
const query = isValid !== null ? { isValid: isValid} : {}
|
||||
return api.get<ReceptionData[]>('receptions', query, {
|
||||
toastErrorKey: 'errors.reception.list'
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export async function getReception(id: number) {
|
||||
const api = useApi()
|
||||
return api.get<ReceptionData>(`receptions/${id}`, {}, {
|
||||
@@ -16,14 +18,14 @@ export async function getReception(id: number) {
|
||||
})
|
||||
}
|
||||
|
||||
export async function createReception(payload: Partial<ReceptionData> = {}) {
|
||||
export async function createReception(payload: ReceptionPayload = {}) {
|
||||
const api = useApi()
|
||||
return api.post<ReceptionData>('receptions', payload, {
|
||||
toastErrorKey: 'errors.reception.create'
|
||||
})
|
||||
}
|
||||
|
||||
export async function updateReception(id: number, payload: Partial<ReceptionData>) {
|
||||
export async function updateReception(id: number, payload: ReceptionPayload) {
|
||||
const api = useApi()
|
||||
return api.patch<ReceptionData>(`receptions/${id}`, payload, {
|
||||
toastErrorKey: 'errors.reception.update',
|
||||
|
||||
23
frontend/services/supplier.ts
Normal file
23
frontend/services/supplier.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { useApi } from '~/composables/useApi'
|
||||
import type { SupplierData } from '~/services/dto/supplier-data'
|
||||
|
||||
export type SupplierListResponse =
|
||||
| SupplierData[]
|
||||
| { 'hydra:member'?: SupplierData[] }
|
||||
|
||||
export async function getSupplierList(): Promise<SupplierData[]> {
|
||||
const api = useApi()
|
||||
const response = await api.get<SupplierListResponse>('suppliers', {}, {
|
||||
toastErrorKey: 'errors.supplier.list'
|
||||
})
|
||||
|
||||
if (Array.isArray(response)) {
|
||||
return response
|
||||
}
|
||||
|
||||
if (response && typeof response === 'object' && Array.isArray(response['hydra:member'])) {
|
||||
return response['hydra:member']
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
23
frontend/services/truck.ts
Normal file
23
frontend/services/truck.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { useApi } from '~/composables/useApi'
|
||||
import type { TruckData } from '~/services/dto/truck-data'
|
||||
|
||||
export type TruckListResponse =
|
||||
| TruckData[]
|
||||
| { 'hydra:member'?: TruckData[] }
|
||||
|
||||
export async function getTruckList(): Promise<TruckData[]> {
|
||||
const api = useApi()
|
||||
const response = await api.get<TruckListResponse>('trucks', {}, {
|
||||
toastErrorKey: 'errors.truck.list'
|
||||
})
|
||||
|
||||
if (Array.isArray(response)) {
|
||||
return response
|
||||
}
|
||||
|
||||
if (response && typeof response === 'object' && Array.isArray(response['hydra:member'])) {
|
||||
return response['hydra:member']
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
23
frontend/services/vehicle.ts
Normal file
23
frontend/services/vehicle.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { useApi } from '~/composables/useApi'
|
||||
import type { VehicleData } from '~/services/dto/vehicle-data'
|
||||
|
||||
export type VehicleListResponse =
|
||||
| VehicleData[]
|
||||
| { 'hydra:member'?: VehicleData[] }
|
||||
|
||||
export async function getVehicleList(): Promise<VehicleData[]> {
|
||||
const api = useApi()
|
||||
const response = await api.get<VehicleListResponse>('vehicles', {}, {
|
||||
toastErrorKey: 'errors.vehicle.list'
|
||||
})
|
||||
|
||||
if (Array.isArray(response)) {
|
||||
return response
|
||||
}
|
||||
|
||||
if (response && typeof response === 'object' && Array.isArray(response['hydra:member'])) {
|
||||
return response['hydra:member']
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
@@ -12,6 +12,11 @@ export const useAuthStore = defineStore('auth', {
|
||||
isAuthenticated: (state) => Boolean(state.user)
|
||||
},
|
||||
actions: {
|
||||
clearSession() {
|
||||
this.user = null
|
||||
this.checked = true
|
||||
this.isLoading = false
|
||||
},
|
||||
async ensureSession() {
|
||||
if (this.checked) {
|
||||
return this.user
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import type { ReceptionData } from '~/services/dto/reception-data'
|
||||
import type { ReceptionData, ReceptionPayload } from '~/services/dto/reception-data'
|
||||
import { createReception, getReception, updateReception } from '~/services/reception'
|
||||
|
||||
const isReceptionData = (value: unknown): value is ReceptionData => {
|
||||
@@ -31,7 +31,7 @@ export const useReceptionStore = defineStore('reception', {
|
||||
this.current = result
|
||||
return result
|
||||
},
|
||||
async createReception(payload: Partial<ReceptionData> = {}) {
|
||||
async createReception(payload: ReceptionPayload = {}) {
|
||||
this.isLoading = true
|
||||
const result = await createReception(payload).finally(() => {
|
||||
this.isLoading = false
|
||||
@@ -43,7 +43,7 @@ export const useReceptionStore = defineStore('reception', {
|
||||
this.current = result
|
||||
return result
|
||||
},
|
||||
async updateReception(id: number, payload: Partial<ReceptionData>) {
|
||||
async updateReception(id: number, payload: ReceptionPayload) {
|
||||
this.isLoading = true
|
||||
const result = await updateReception(id, payload).finally(() => {
|
||||
this.isLoading = false
|
||||
|
||||
@@ -3,6 +3,9 @@ import type { Config } from 'tailwindcss'
|
||||
export default <Partial<Config>>{
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
sans: ['"Helvetica Neue"', 'Helvetica', 'Arial', 'sans-serif']
|
||||
},
|
||||
colors: {
|
||||
primary: {
|
||||
50: '#f6f9ea',
|
||||
|
||||
13
frontend/utils/constants.ts
Normal file
13
frontend/utils/constants.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export const RECEPTION_TYPE_CODES = {
|
||||
MERCHANDISES: 'MARCHANDISES',
|
||||
BOVINS: 'BOVINS'
|
||||
} as const
|
||||
|
||||
export const MERCHANDISE_TYPE_CODES = {
|
||||
GRANULE: 'GRANULE',
|
||||
AUTRES: 'AUTRES'
|
||||
} as const
|
||||
|
||||
export const SUPLLIER_CODE = {
|
||||
LIOT: 'LIOT'
|
||||
}
|
||||
26
makefile
26
makefile
@@ -7,6 +7,9 @@ ENV_FILE := $(if $(wildcard $(ENV_LOCAL)),$(ENV_LOCAL),$(ENV_DEFAULT))
|
||||
include $(ENV_DEFAULT)
|
||||
-include $(ENV_LOCAL)
|
||||
|
||||
HOST_UID := $(if $(SUDO_UID),$(SUDO_UID),$(shell id -u))
|
||||
HOST_GID := $(if $(SUDO_GID),$(SUDO_GID),$(shell id -g))
|
||||
|
||||
PHP_CONTAINER = php-$(DOCKER_APP_NAME)-fpm
|
||||
SYMFONY_CONSOLE = $(EXEC_PHP) php bin/console
|
||||
|
||||
@@ -24,13 +27,13 @@ FILES =
|
||||
|
||||
env-init:
|
||||
@mkdir -p docker
|
||||
@cp --update=none $(ENV_DEFAULT) $(ENV_LOCAL)
|
||||
@cp -n $(ENV_DEFAULT) $(ENV_LOCAL)
|
||||
|
||||
# Lance le container
|
||||
start: env-init
|
||||
@echo "**** START CONTAINERS ****"
|
||||
@cp --update=none docker/.env.docker docker/.env.docker.local
|
||||
CURRENT_UID=$(shell id -u) CURRENT_GID=$(shell id -g) $(DOCKER_COMPOSE) up -d
|
||||
@cp -n docker/.env.docker docker/.env.docker.local
|
||||
CURRENT_UID=$(HOST_UID) CURRENT_GID=$(HOST_GID) $(DOCKER_COMPOSE) up -d
|
||||
|
||||
# Éteint le container
|
||||
stop:
|
||||
@@ -38,7 +41,7 @@ stop:
|
||||
|
||||
restart: env-init
|
||||
$(DOCKER_COMPOSE) down
|
||||
CURRENT_UID=$(shell id -u) CURRENT_GID=$(shell id -g) $(DOCKER_COMPOSE) up -d
|
||||
CURRENT_UID=$(HOST_UID) CURRENT_GID=$(HOST_GID) $(DOCKER_COMPOSE) up -d
|
||||
|
||||
install: copy-git-hook composer-install cache-clear node-use build-nuxtJS migration-migrate
|
||||
|
||||
@@ -57,9 +60,8 @@ dev-nuxt:
|
||||
$(EXEC_PHP) sh -c "cd frontend && npm run dev"
|
||||
|
||||
delete_built_dir:
|
||||
CURRENT_UID=$(shell id -u) CURRENT_GID=$(shell id -g) $(DOCKER_COMPOSE) up -d
|
||||
$(DOCKER) exec -u root $(PHP_CONTAINER) rm -rf vendor/
|
||||
$(DOCKER) exec -u root $(PHP_CONTAINER) rm -rf frontend/node_modules
|
||||
rm -rf vendor/
|
||||
rm -rf frontend/node_modules
|
||||
|
||||
remove_orphans:
|
||||
$(DOCKER_COMPOSE) kill
|
||||
@@ -69,12 +71,15 @@ build-without-cache:
|
||||
$(DOCKER_COMPOSE) build \
|
||||
--build-arg="DOCKER_PHP_VERSION=$(DOCKER_PHP_VERSION)" \
|
||||
--build-arg="DOCKER_NODE_VERSION=$(DOCKER_NODE_VERSION)" \
|
||||
--build-arg="CURRENT_UID=$(shell id -u)" \
|
||||
--build-arg="CURRENT_GID=$(shell id -g)" \
|
||||
--build-arg="CURRENT_UID=$(HOST_UID)" \
|
||||
--build-arg="CURRENT_GID=$(HOST_GID)" \
|
||||
--no-cache
|
||||
|
||||
migration-migrate:
|
||||
$(SYMFONY_CONSOLE) bin/console doctrine:migrations:migrate --no-interaction
|
||||
$(SYMFONY_CONSOLE) --no-interaction doctrine:migrations:migrate --allow-no-migration
|
||||
|
||||
fixtures:
|
||||
$(SYMFONY_CONSOLE) doctrine:fixtures:load
|
||||
|
||||
# Attention, supprime votre bdd local
|
||||
db-reset:
|
||||
@@ -83,6 +88,7 @@ db-reset:
|
||||
$(MAKE) wait
|
||||
$(SYMFONY_CONSOLE) doctrine:database:create --if-not-exists
|
||||
$(MAKE) migration-migrate
|
||||
$(MAKE) fixtures
|
||||
|
||||
# Restart la bdd
|
||||
db-restart:
|
||||
|
||||
32
migrations/Version20260127000100.php
Normal file
32
migrations/Version20260127000100.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20260127000100 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Add reception types and link receptions to them';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('CREATE TABLE reception_type (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, label VARCHAR(120) NOT NULL, code VARCHAR(50) NOT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('ALTER TABLE reception ADD reception_type_id INT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE reception ADD CONSTRAINT FK_83DC02E37BD5B5D FOREIGN KEY (reception_type_id) REFERENCES reception_type (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('CREATE INDEX IDX_83DC02E37BD5B5D ON reception (reception_type_id)');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE reception DROP CONSTRAINT FK_83DC02E37BD5B5D');
|
||||
$this->addSql('DROP INDEX IDX_83DC02E37BD5B5D');
|
||||
$this->addSql('ALTER TABLE reception DROP reception_type_id');
|
||||
$this->addSql('DROP TABLE reception_type');
|
||||
}
|
||||
}
|
||||
30
migrations/Version20260127000200.php
Normal file
30
migrations/Version20260127000200.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20260127000200 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Link receptions to a responsible user';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE reception ADD user_id INT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE reception ADD CONSTRAINT FK_83DC02E3A76ED395 FOREIGN KEY (user_id) REFERENCES "user" (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('CREATE INDEX IDX_83DC02E3A76ED395 ON reception (user_id)');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE reception DROP CONSTRAINT FK_83DC02E3A76ED395');
|
||||
$this->addSql('DROP INDEX IDX_83DC02E3A76ED395');
|
||||
$this->addSql('ALTER TABLE reception DROP user_id');
|
||||
}
|
||||
}
|
||||
42
migrations/Version20260127000300.php
Normal file
42
migrations/Version20260127000300.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
final class Version20260127000300 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Add suppliers and addresses, link receptions to suppliers';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$this->addSql('CREATE TABLE address (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, label VARCHAR(120) NOT NULL, street VARCHAR(180) NOT NULL, postal_code VARCHAR(20) NOT NULL, city VARCHAR(120) NOT NULL, country_code VARCHAR(2) NOT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('CREATE TABLE supplier (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, name VARCHAR(180) NOT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('CREATE TABLE supplier_address (supplier_id INT NOT NULL, address_id INT NOT NULL, PRIMARY KEY(supplier_id, address_id))');
|
||||
$this->addSql('CREATE INDEX IDX_3DCE3C74F2C1D6A8 ON supplier_address (supplier_id)');
|
||||
$this->addSql('CREATE INDEX IDX_3DCE3C746F9B8A0 ON supplier_address (address_id)');
|
||||
$this->addSql('ALTER TABLE supplier_address ADD CONSTRAINT FK_3DCE3C74F2C1D6A8 FOREIGN KEY (supplier_id) REFERENCES supplier (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('ALTER TABLE supplier_address ADD CONSTRAINT FK_3DCE3C746F9B8A0 FOREIGN KEY (address_id) REFERENCES address (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('ALTER TABLE reception ADD supplier_id INT DEFAULT NULL');
|
||||
$this->addSql('ALTER TABLE reception ADD CONSTRAINT FK_83DC02E32ADD6E01 FOREIGN KEY (supplier_id) REFERENCES supplier (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
$this->addSql('CREATE INDEX IDX_83DC02E32ADD6E01 ON reception (supplier_id)');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$this->addSql('ALTER TABLE reception DROP CONSTRAINT FK_83DC02E32ADD6E01');
|
||||
$this->addSql('DROP INDEX IDX_83DC02E32ADD6E01');
|
||||
$this->addSql('ALTER TABLE reception DROP supplier_id');
|
||||
$this->addSql('ALTER TABLE supplier_address DROP CONSTRAINT FK_3DCE3C74F2C1D6A8');
|
||||
$this->addSql('ALTER TABLE supplier_address DROP CONSTRAINT FK_3DCE3C746F9B8A0');
|
||||
$this->addSql('DROP TABLE supplier_address');
|
||||
$this->addSql('DROP TABLE supplier');
|
||||
$this->addSql('DROP TABLE address');
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user