fix : ajout d'une date de mouvement et protection sur le rôle Bureau

This commit is contained in:
2026-05-13 14:10:54 +02:00
parent 5b24d642bb
commit 754898da39
8 changed files with 150 additions and 78 deletions

View File

@@ -4,7 +4,9 @@
"Bash(npm run:*)", "Bash(npm run:*)",
"WebFetch(domain:geo.api.gouv.fr)", "WebFetch(domain:geo.api.gouv.fr)",
"Bash(pip3 install:*)", "Bash(pip3 install:*)",
"Bash(python3 -c \":*)" "Bash(python3 -c \":*)",
"Bash(make cache-clear *)",
"Bash(make test *)"
] ]
} }
} }

View File

@@ -1,5 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="db-forest-configuration">
<data version="2">.
----------------------------------------
1:0:9cad43df-2147-4989-b7a4-443067034884
2:0:ae622167-c834-4e7b-87a5-c1721036f5dc
3:0:f407a514-c6b4-4b26-9555-445a85892502
4:0:09e221b8-067a-488b-9c1d-4e155a333079
5:0:9d8c1ad3-2491-4642-964a-666003c14128
.</data>
</component>
<component name="db-tree-configuration"> <component name="db-tree-configuration">
<option name="data" value="----------------------------------------&#10;1:0:f407a514-c6b4-4b26-9555-445a85892502&#10;2:0:ae622167-c834-4e7b-87a5-c1721036f5dc&#10;3:0:9cad43df-2147-4989-b7a4-443067034884&#10;4:0:09e221b8-067a-488b-9c1d-4e155a333079&#10;" /> <option name="data" value="----------------------------------------&#10;1:0:f407a514-c6b4-4b26-9555-445a85892502&#10;2:0:ae622167-c834-4e7b-87a5-c1721036f5dc&#10;3:0:9cad43df-2147-4989-b7a4-443067034884&#10;4:0:09e221b8-067a-488b-9c1d-4e155a333079&#10;" />
</component> </component>

5
.idea/ferme.iml generated
View File

@@ -155,6 +155,11 @@
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/data-fixtures" /> <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/doctrine/doctrine-fixtures-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/maker-bundle" /> <excludeFolder url="file://$MODULE_DIR$/vendor/symfony/maker-bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/maennchen/zipstream-php" />
<excludeFolder url="file://$MODULE_DIR$/vendor/markbaker/complex" />
<excludeFolder url="file://$MODULE_DIR$/vendor/markbaker/matrix" />
<excludeFolder url="file://$MODULE_DIR$/vendor/phpoffice/phpspreadsheet" />
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/simple-cache" />
<excludePattern pattern="reference.php" /> <excludePattern pattern="reference.php" />
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />

5
.idea/php.xml generated
View File

@@ -174,6 +174,11 @@
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-fixtures-bundle" /> <path value="$PROJECT_DIR$/vendor/doctrine/doctrine-fixtures-bundle" />
<path value="$PROJECT_DIR$/vendor/doctrine/data-fixtures" /> <path value="$PROJECT_DIR$/vendor/doctrine/data-fixtures" />
<path value="$PROJECT_DIR$/vendor/symfony/maker-bundle" /> <path value="$PROJECT_DIR$/vendor/symfony/maker-bundle" />
<path value="$PROJECT_DIR$/vendor/maennchen/zipstream-php" />
<path value="$PROJECT_DIR$/vendor/psr/simple-cache" />
<path value="$PROJECT_DIR$/vendor/markbaker/matrix" />
<path value="$PROJECT_DIR$/vendor/markbaker/complex" />
<path value="$PROJECT_DIR$/vendor/phpoffice/phpspreadsheet" />
</include_path> </include_path>
</component> </component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.4" /> <component name="PhpProjectSharedConfiguration" php_language_level="8.4" />

145
.idea/workspace.xml generated
View File

@@ -4,12 +4,16 @@
<option name="autoReloadType" value="SELECTIVE" /> <option name="autoReloadType" value="SELECTIVE" />
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="7c107abe-5995-4428-8429-b146aaca8386" name="Changes" comment="fix : les non-admin ne peuvent plus supprimer de réception/expédition en attente"> <list default="true" id="7c107abe-5995-4428-8429-b146aaca8386" name="Changes" comment="fix : label age bovin">
<change beforePath="$PROJECT_DIR$/.claude/settings.local.json" beforeDir="false" afterPath="$PROJECT_DIR$/.claude/settings.local.json" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/db-forest-config.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/db-forest-config.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/ferme.iml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/ferme.iml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/php.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/php.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/CHANGELOG.md" beforeDir="false" afterPath="$PROJECT_DIR$/CHANGELOG.md" afterDir="false" />
<change beforePath="$PROJECT_DIR$/config/reference.php" beforeDir="false" afterPath="$PROJECT_DIR$/config/reference.php" afterDir="false" /> <change beforePath="$PROJECT_DIR$/config/reference.php" beforeDir="false" afterPath="$PROJECT_DIR$/config/reference.php" afterDir="false" />
<change beforePath="$PROJECT_DIR$/frontend/pages/reception/waiting-reception.vue" beforeDir="false" afterPath="$PROJECT_DIR$/frontend/pages/reception/waiting-reception.vue" afterDir="false" /> <change beforePath="$PROJECT_DIR$/frontend/pages/bovine/[id].vue" beforeDir="false" afterPath="$PROJECT_DIR$/frontend/pages/bovine/[id].vue" afterDir="false" />
<change beforePath="$PROJECT_DIR$/frontend/pages/shipment/waiting-shipment.vue" beforeDir="false" afterPath="$PROJECT_DIR$/frontend/pages/shipment/waiting-shipment.vue" afterDir="false" /> <change beforePath="$PROJECT_DIR$/src/Entity/BovineMovement.php" beforeDir="false" afterPath="$PROJECT_DIR$/src/Entity/BovineMovement.php" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/State/Bovin/BovineMovementProcessor.php" beforeDir="false" afterPath="$PROJECT_DIR$/src/State/Bovin/BovineMovementProcessor.php" afterDir="false" />
</list> </list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -41,7 +45,7 @@
<component name="Git.Settings"> <component name="Git.Settings">
<option name="RECENT_BRANCH_BY_REPOSITORY"> <option name="RECENT_BRANCH_BY_REPOSITORY">
<map> <map>
<entry key="$PROJECT_DIR$" value="feature/FER-13-faire-des-recherches-sur-le-scanner-des-betes" /> <entry key="$PROJECT_DIR$" value="feat/entree-sortie" />
</map> </map>
</option> </option>
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" /> <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
@@ -213,6 +217,11 @@
<path value="$PROJECT_DIR$/vendor/doctrine/doctrine-fixtures-bundle" /> <path value="$PROJECT_DIR$/vendor/doctrine/doctrine-fixtures-bundle" />
<path value="$PROJECT_DIR$/vendor/doctrine/data-fixtures" /> <path value="$PROJECT_DIR$/vendor/doctrine/data-fixtures" />
<path value="$PROJECT_DIR$/vendor/symfony/maker-bundle" /> <path value="$PROJECT_DIR$/vendor/symfony/maker-bundle" />
<path value="$PROJECT_DIR$/vendor/maennchen/zipstream-php" />
<path value="$PROJECT_DIR$/vendor/psr/simple-cache" />
<path value="$PROJECT_DIR$/vendor/markbaker/matrix" />
<path value="$PROJECT_DIR$/vendor/markbaker/complex" />
<path value="$PROJECT_DIR$/vendor/phpoffice/phpspreadsheet" />
</include_path> </include_path>
</component> </component>
<component name="ProjectColorInfo">{ <component name="ProjectColorInfo">{
@@ -232,7 +241,9 @@
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true", "RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
"RunOnceActivity.git.unshallow": "true", "RunOnceActivity.git.unshallow": "true",
"RunOnceActivity.typescript.service.memoryLimit.init": "true", "RunOnceActivity.typescript.service.memoryLimit.init": "true",
"git-widget-placeholder": "fix/FER-15-fix-droit-de-suppression-reception-expedition-util", "codeWithMe.voiceChat.enabledByDefault": "false",
"git-widget-placeholder": "feat/vie-du-bovin",
"git.auto.fetch.suggestion.counter": "3",
"last_opened_file_path": "//wsl.localhost/Ubuntu-24.04/home/m-tristan/workspace/Ferme", "last_opened_file_path": "//wsl.localhost/Ubuntu-24.04/home/m-tristan/workspace/Ferme",
"node.js.detected.package.eslint": "true", "node.js.detected.package.eslint": "true",
"node.js.detected.package.tslint": "true", "node.js.detected.package.tslint": "true",
@@ -274,7 +285,7 @@
<component name="SharedIndexes"> <component name="SharedIndexes">
<attachedChunks> <attachedChunks>
<set> <set>
<option value="bundled-php-predefined-a98d8de5180a-0e0d91225499-com.jetbrains.php.sharedIndexes-PS-253.32098.40" /> <option value="bundled-php-predefined-a98d8de5180a-022fa7b8ab75-com.jetbrains.php.sharedIndexes-PS-261.23567.149" />
</set> </set>
</attachedChunks> </attachedChunks>
</component> </component>
@@ -327,54 +338,16 @@
<workItem from="1773824491213" duration="24805000" /> <workItem from="1773824491213" duration="24805000" />
<workItem from="1774275549972" duration="51000" /> <workItem from="1774275549972" duration="51000" />
<workItem from="1774276665015" duration="33750000" /> <workItem from="1774276665015" duration="33750000" />
</task> <workItem from="1776755742205" duration="88521000" />
<task id="LOCAL-00037" summary="feat : finalisation de l'étape 1 &quot;Réception&quot; (formulaire)"> <workItem from="1777453284124" duration="86000" />
<option name="closed" value="true" /> <workItem from="1777453433907" duration="337000" />
<created>1769529522614</created> <workItem from="1777454070632" duration="17254000" />
<option name="number" value="00037" /> <workItem from="1777540415843" duration="13205000" />
<option name="presentableId" value="LOCAL-00037" /> <workItem from="1777877316149" duration="29389000" />
<option name="project" value="LOCAL" /> <workItem from="1777982616362" duration="23909000" />
<updated>1769529522614</updated> <workItem from="1778482021120" duration="1280000" />
</task> <workItem from="1778656317630" duration="279000" />
<task id="LOCAL-00038" summary="feat : ajout du numéro identification des receptions et ajustement du bon de reception"> <workItem from="1778664396844" duration="2576000" />
<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>
<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"> <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" /> <option name="closed" value="true" />
@@ -720,7 +693,55 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1774543840891</updated> <updated>1774543840891</updated>
</task> </task>
<option name="localTasksCounter" value="86" /> <task id="LOCAL-00086" summary="fix : update icon entrée/sortie">
<option name="closed" value="true" />
<created>1777896558092</created>
<option name="number" value="00086" />
<option name="presentableId" value="LOCAL-00086" />
<option name="project" value="LOCAL" />
<updated>1777896558092</updated>
</task>
<task id="LOCAL-00087" summary="fix : wording">
<option name="closed" value="true" />
<created>1777983048277</created>
<option name="number" value="00087" />
<option name="presentableId" value="LOCAL-00087" />
<option name="project" value="LOCAL" />
<updated>1777983048278</updated>
</task>
<task id="LOCAL-00088" summary="fix : wording">
<option name="closed" value="true" />
<created>1777983581324</created>
<option name="number" value="00088" />
<option name="presentableId" value="LOCAL-00088" />
<option name="project" value="LOCAL" />
<updated>1777983581324</updated>
</task>
<task id="LOCAL-00089" summary="feat : update CHANGELOG.md">
<option name="closed" value="true" />
<created>1778073247660</created>
<option name="number" value="00089" />
<option name="presentableId" value="LOCAL-00089" />
<option name="project" value="LOCAL" />
<updated>1778073247660</updated>
</task>
<task id="LOCAL-00090" summary="feat : amélioration du tableau bovin">
<option name="closed" value="true" />
<created>1778135981350</created>
<option name="number" value="00090" />
<option name="presentableId" value="LOCAL-00090" />
<option name="project" value="LOCAL" />
<updated>1778135981350</updated>
</task>
<task id="LOCAL-00091" summary="fix : label age bovin">
<option name="closed" value="true" />
<created>1778136373027</created>
<option name="number" value="00091" />
<option name="presentableId" value="LOCAL-00091" />
<option name="project" value="LOCAL" />
<updated>1778136373027</updated>
</task>
<option name="localTasksCounter" value="92" />
<servers /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
@@ -770,10 +791,6 @@
</option> </option>
</component> </component>
<component name="VcsManagerConfiguration"> <component name="VcsManagerConfiguration">
<MESSAGE value="feat : changelog update" />
<MESSAGE value="fix : color tab" />
<MESSAGE value="feat : modification front de la page admin transporteur" />
<MESSAGE value="fix : espacement et changelog" />
<MESSAGE value="fix : espacement" /> <MESSAGE value="fix : espacement" />
<MESSAGE value="fix : text" /> <MESSAGE value="fix : text" />
<MESSAGE value="feat : front page admin bovin et changelog" /> <MESSAGE value="feat : front page admin bovin et changelog" />
@@ -792,10 +809,14 @@
<MESSAGE value="feat : système de blocage utilisateur" /> <MESSAGE value="feat : système de blocage utilisateur" />
<MESSAGE value="feat : ajout d'un système de scanner bovin" /> <MESSAGE value="feat : ajout d'un système de scanner bovin" />
<MESSAGE value="feat : mise à jour du CLAUDE.md" /> <MESSAGE value="feat : mise à jour du CLAUDE.md" />
<MESSAGE value="feat : update CHANGELOG.md" />
<MESSAGE value="feat : la page de scanner est accessible que pour les admins" /> <MESSAGE value="feat : la page de scanner est accessible que pour les admins" />
<MESSAGE value="fix : les non-admin ne peuvent plus supprimer de réception/expédition en attente" /> <MESSAGE value="fix : les non-admin ne peuvent plus supprimer de réception/expédition en attente" />
<option name="LAST_COMMIT_MESSAGE" value="fix : les non-admin ne peuvent plus supprimer de réception/expédition en attente" /> <MESSAGE value="fix : update icon entrée/sortie" />
<MESSAGE value="fix : wording" />
<MESSAGE value="feat : update CHANGELOG.md" />
<MESSAGE value="feat : amélioration du tableau bovin" />
<MESSAGE value="fix : label age bovin" />
<option name="LAST_COMMIT_MESSAGE" value="fix : label age bovin" />
</component> </component>
<component name="XDebuggerManager"> <component name="XDebuggerManager">
<breakpoint-manager> <breakpoint-manager>

View File

@@ -14,14 +14,10 @@
<UiTabs <UiTabs
v-model="activeTab" v-model="activeTab"
:tabs="[ :tabs="tabs"
{ key: 'mouvement', label: 'Mouvement' },
{ key: 'passeport', label: 'Passeport bovin' },
{ key: 'sante', label: 'Santé' }
]"
/> />
<div v-show="activeTab === 'mouvement'"> <div v-if="auth.isBureau" v-show="activeTab === 'mouvement'">
<form :class="{ submitted: movementSubmitted }" @submit.prevent="submitMovement"> <form :class="{ submitted: movementSubmitted }" @submit.prevent="submitMovement">
<div class="flex flex-cols-3 justify-between mb-10"> <div class="flex flex-cols-3 justify-between mb-10">
<UiSelect <UiSelect
@@ -41,7 +37,13 @@
wrapper-class="w-[280px]" wrapper-class="w-[280px]"
required required
/> />
<div class="w-[280px]" /> <UiDateInput
id="movement-date"
v-model="newMovementDate"
label="Date mouvement"
wrapper-class="w-[280px]"
required
/>
</div> </div>
<div class="flex items-center justify-center mb-11"> <div class="flex items-center justify-center mb-11">
@@ -158,11 +160,19 @@
<script setup lang="ts"> <script setup lang="ts">
import { getBuildingList } from '~/services/building' import { getBuildingList } from '~/services/building'
import type { BuildingData } from '~/services/dto/building-data' import type { BuildingData } from '~/services/dto/building-data'
import { useAuthStore } from '~/stores/auth'
useHead({ title: 'Vie du bovin' }) useHead({ title: 'Vie du bovin' })
const auth = useAuthStore()
type BovineTab = 'mouvement' | 'passeport' | 'sante' type BovineTab = 'mouvement' | 'passeport' | 'sante'
const activeTab = ref<BovineTab>('mouvement') const tabs = computed(() => [
...(auth.isBureau ? [{ key: 'mouvement' as const, label: 'Mouvement' }] : []),
{ key: 'passeport' as const, label: 'Passeport bovin' },
{ key: 'sante' as const, label: 'Santé' }
])
const activeTab = ref<BovineTab>(auth.isBureau ? 'mouvement' : 'passeport')
interface BovineTypeRef { interface BovineTypeRef {
id: number id: number
@@ -215,10 +225,13 @@ const goBack = () => {
} }
} }
const todayIso = () => new Date().toISOString().slice(0, 10)
const bovine = ref<BovinePassportData | null>(null) const bovine = ref<BovinePassportData | null>(null)
const buildings = ref<BuildingData[]>([]) const buildings = ref<BuildingData[]>([])
const newMovementBuildingId = ref<string | number | null>(null) const newMovementBuildingId = ref<string | number | null>(null)
const newMovementCaseId = ref<string | number | null>(null) const newMovementCaseId = ref<string | number | null>(null)
const newMovementDate = ref<string>(todayIso())
const isSubmittingMovement = ref(false) const isSubmittingMovement = ref(false)
const movementSubmitted = ref(false) const movementSubmitted = ref(false)
const movementFilters = ref({ building: '', case: '' }) const movementFilters = ref({ building: '', case: '' })
@@ -307,16 +320,27 @@ const filteredMovementRows = computed(() => {
}) })
const submitMovement = async () => { const submitMovement = async () => {
if (!newMovementCaseId.value || bovineId.value === null) return if (!newMovementCaseId.value || !newMovementDate.value || bovineId.value === null) return
const buildingLabel = buildingOptions.value.find(o => o.value === Number(newMovementBuildingId.value))?.label ?? '—'
const caseLabel = caseOptions.value.find(o => o.value === Number(newMovementCaseId.value))?.label ?? '—'
const dateLabel = formatDate(newMovementDate.value)
const confirmed = window.confirm(
`Confirmer la création du mouvement ?\n\nBâtiment : ${buildingLabel}\nCase : ${caseLabel}\nDate : ${dateLabel}`
)
if (!confirmed) return
isSubmittingMovement.value = true isSubmittingMovement.value = true
try { try {
await api.post('bovine_movements', { await api.post('bovine_movements', {
bovine: `/api/bovines/${bovineId.value}`, bovine: `/api/bovines/${bovineId.value}`,
buildingCase: `/api/building_cases/${newMovementCaseId.value}` buildingCase: `/api/building_cases/${newMovementCaseId.value}`,
enteredAt: newMovementDate.value
}, { toastSuccessMessage: 'Mouvement enregistré' }) }, { toastSuccessMessage: 'Mouvement enregistré' })
bovine.value = await api.get<BovinePassportData>(`bovines/${bovineId.value}`) bovine.value = await api.get<BovinePassportData>(`bovines/${bovineId.value}`)
newMovementBuildingId.value = null newMovementBuildingId.value = null
newMovementCaseId.value = null newMovementCaseId.value = null
newMovementDate.value = todayIso()
movementSubmitted.value = false movementSubmitted.value = false
} finally { } finally {
isSubmittingMovement.value = false isSubmittingMovement.value = false

View File

@@ -24,7 +24,7 @@ use Symfony\Component\Serializer\Attribute\Groups;
processor: BovineMovementProcessor::class, processor: BovineMovementProcessor::class,
), ),
], ],
security: "is_granted('ROLE_USER')", security: "is_granted('ROLE_BUREAU')",
)] )]
class BovineMovement class BovineMovement
{ {
@@ -50,7 +50,7 @@ class BovineMovement
private ?Building $building = null; private ?Building $building = null;
#[ORM\Column(type: 'datetime_immutable')] #[ORM\Column(type: 'datetime_immutable')]
#[Groups(['bovine:read'])] #[Groups(['bovine:read', 'bovine_movement:write'])]
private DateTimeImmutable $enteredAt; private DateTimeImmutable $enteredAt;
#[ORM\Column(type: 'datetime_immutable', nullable: true)] #[ORM\Column(type: 'datetime_immutable', nullable: true)]
@@ -103,6 +103,11 @@ class BovineMovement
return $this->enteredAt; return $this->enteredAt;
} }
public function hasEnteredAt(): bool
{
return isset($this->enteredAt);
}
public function setEnteredAt(DateTimeImmutable $enteredAt): static public function setEnteredAt(DateTimeImmutable $enteredAt): static
{ {
$this->enteredAt = $enteredAt; $this->enteredAt = $enteredAt;

View File

@@ -25,8 +25,8 @@ final class BovineMovementProcessor implements ProcessorInterface
return $this->persistProcessor->process($data, $operation, $uriVariables, $context); return $this->persistProcessor->process($data, $operation, $uriVariables, $context);
} }
$now = new DateTimeImmutable(); $enteredAt = $data->hasEnteredAt() ? $data->getEnteredAt() : new DateTimeImmutable();
$data->setEnteredAt($now); $data->setEnteredAt($enteredAt);
$data->setLeftAt(null); $data->setLeftAt(null);
$data->setBuilding(null); $data->setBuilding(null);
@@ -34,7 +34,7 @@ final class BovineMovementProcessor implements ProcessorInterface
$openMovement = $this->movementRepository->findOpenMovement($bovine); $openMovement = $this->movementRepository->findOpenMovement($bovine);
if (null !== $openMovement) { if (null !== $openMovement) {
$openMovement->setLeftAt($now); $openMovement->setLeftAt($enteredAt);
} }
$bovine->setBuildingCase($data->getBuildingCase()); $bovine->setBuildingCase($data->getBuildingCase());