Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0beb80199 | ||
| c378b402c4 | |||
|
|
6e707484a0 | ||
| 0067e51e6e | |||
|
|
1c0cdeb085 | ||
| 465339cdd6 |
@@ -2,7 +2,9 @@
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(npm run:*)",
|
||||
"WebFetch(domain:geo.api.gouv.fr)"
|
||||
"WebFetch(domain:geo.api.gouv.fr)",
|
||||
"Bash(pip3 install:*)",
|
||||
"Bash(python3 -c \":*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
71
.idea/workspace.xml
generated
71
.idea/workspace.xml
generated
@@ -4,9 +4,10 @@
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="7c107abe-5995-4428-8429-b146aaca8386" name="Changes" comment="feat : ajout de l'api de l'état pour chercher les villes via le CP">
|
||||
<list default="true" id="7c107abe-5995-4428-8429-b146aaca8386" name="Changes" comment="fix : order récéption/expédition + correction style bouton récéption">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/scripts/deploy-release.sh" beforeDir="false" afterPath="$PROJECT_DIR$/scripts/deploy-release.sh" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/config/reference.php" beforeDir="false" afterPath="$PROJECT_DIR$/config/reference.php" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/templates/reception_voucher.html.twig" beforeDir="false" afterPath="$PROJECT_DIR$/templates/reception_voucher.html.twig" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
@@ -261,8 +262,8 @@
|
||||
<recent name="\\wsl.localhost\Ubuntu-24.04\home\kevin\Stage\Ferme\frontend\components\shipment" />
|
||||
</key>
|
||||
<key name="MoveFile.RECENT_KEYS">
|
||||
<recent name="C:\Users\m-tristan\AppData\Roaming\JetBrains\PhpStorm2025.3\scratches" />
|
||||
<recent name="\\wsl.localhost\Ubuntu-24.04\home\m-tristan\workspace\Ferme" />
|
||||
<recent name="C:\Users\m-tristan\AppData\Roaming\JetBrains\PhpStorm2025.3\scratches" />
|
||||
<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" />
|
||||
@@ -271,7 +272,7 @@
|
||||
<component name="SharedIndexes">
|
||||
<attachedChunks>
|
||||
<set>
|
||||
<option value="bundled-php-predefined-a98d8de5180a-0e0d91225499-com.jetbrains.php.sharedIndexes-PS-253.31033.138" />
|
||||
<option value="bundled-php-predefined-a98d8de5180a-0e0d91225499-com.jetbrains.php.sharedIndexes-PS-253.32098.40" />
|
||||
</set>
|
||||
</attachedChunks>
|
||||
</component>
|
||||
@@ -321,31 +322,9 @@
|
||||
<workItem from="1773215356754" duration="5754000" />
|
||||
<workItem from="1773756072697" duration="5450000" />
|
||||
<workItem from="1773766075191" duration="6202000" />
|
||||
<workItem from="1773824491213" duration="16281000" />
|
||||
</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>
|
||||
<workItem from="1773824491213" duration="24805000" />
|
||||
<workItem from="1774275549972" duration="51000" />
|
||||
<workItem from="1774276665015" duration="4910000" />
|
||||
</task>
|
||||
<task id="LOCAL-00029" summary="fix : gitea workflow">
|
||||
<option name="closed" value="true" />
|
||||
@@ -715,7 +694,31 @@
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1773842791819</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="75" />
|
||||
<task id="LOCAL-00075" summary="fix : script de déploiement + CI/CD build de l'app">
|
||||
<option name="closed" value="true" />
|
||||
<created>1773843922376</created>
|
||||
<option name="number" value="00075" />
|
||||
<option name="presentableId" value="LOCAL-00075" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1773843922377</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00076" summary="fix : order navbar + modification création fournisseur et client">
|
||||
<option name="closed" value="true" />
|
||||
<created>1773852806120</created>
|
||||
<option name="number" value="00076" />
|
||||
<option name="presentableId" value="LOCAL-00076" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1773852806121</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00077" summary="fix : order récéption/expédition + correction style bouton récéption">
|
||||
<option name="closed" value="true" />
|
||||
<created>1774283204849</created>
|
||||
<option name="number" value="00077" />
|
||||
<option name="presentableId" value="LOCAL-00077" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1774283204849</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="78" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
@@ -765,9 +768,6 @@
|
||||
</option>
|
||||
</component>
|
||||
<component name="VcsManagerConfiguration">
|
||||
<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 : creer une nouvelle expedtion (WIP)" />
|
||||
<MESSAGE value="feat : ajout d'une page de creation d'une expedition" />
|
||||
<MESSAGE value="feat : changelog" />
|
||||
@@ -790,7 +790,10 @@
|
||||
<MESSAGE value="fix : on ne pèse plus automatiquement + fix message de création réception" />
|
||||
<MESSAGE value="fix : correction des retours de la V0" />
|
||||
<MESSAGE value="feat : ajout de l'api de l'état pour chercher les villes via le CP" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="feat : ajout de l'api de l'état pour chercher les villes via le CP" />
|
||||
<MESSAGE value="fix : script de déploiement + CI/CD build de l'app" />
|
||||
<MESSAGE value="fix : order navbar + modification création fournisseur et client" />
|
||||
<MESSAGE value="fix : order récéption/expédition + correction style bouton récéption" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="fix : order récéption/expédition + correction style bouton récéption" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
parameters:
|
||||
app.version: '0.0.73'
|
||||
app.version: '0.0.76'
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
<div class="flex justify-center">
|
||||
<UiButton
|
||||
type="submit"
|
||||
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px] justify-self-end"
|
||||
class="text-xl mb-16 uppercase bg-primary-500 text-white h-[50px] w-[272px] justify-self-end"
|
||||
@click="submitted = true"
|
||||
>Valider
|
||||
</UiButton>
|
||||
|
||||
@@ -72,23 +72,6 @@
|
||||
</a>
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink
|
||||
v-if="auth.isAdmin"
|
||||
to="/admin/carrier/carrier-list"
|
||||
custom
|
||||
v-slot="{ href, navigate }"
|
||||
>
|
||||
<a
|
||||
:href="href"
|
||||
@click="navigate"
|
||||
:class="route.path.startsWith('/admin/carrier')
|
||||
? 'opacity-100'
|
||||
: 'opacity-65 hover:opacity-100 transition'"
|
||||
>
|
||||
Transporteurs
|
||||
</a>
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink
|
||||
v-if="auth.isAdmin"
|
||||
to="/admin/customer/customer-list"
|
||||
@@ -106,6 +89,23 @@
|
||||
</a>
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink
|
||||
v-if="auth.isAdmin"
|
||||
to="/admin/carrier/carrier-list"
|
||||
custom
|
||||
v-slot="{ href, navigate }"
|
||||
>
|
||||
<a
|
||||
:href="href"
|
||||
@click="navigate"
|
||||
:class="route.path.startsWith('/admin/carrier')
|
||||
? 'opacity-100'
|
||||
: 'opacity-65 hover:opacity-100 transition'"
|
||||
>
|
||||
Transporteurs
|
||||
</a>
|
||||
</NuxtLink>
|
||||
|
||||
<NuxtLink
|
||||
v-if="auth.isAdmin"
|
||||
to="/admin/bovin/bovin-list"
|
||||
|
||||
@@ -14,6 +14,19 @@
|
||||
<UiTextInput id="customer-phone" v-model="form.phone" label="Téléphone" :disabled="!auth.isAdmin" wrapper-class="w-[280px]" required/>
|
||||
<UiTextInput id="customer-email" v-model="form.email" label="Email" :disabled="!auth.isAdmin" wrapper-class="w-[280px]"/>
|
||||
</div>
|
||||
<div v-if="!customerId" class="flex flex-cols-3 justify-between mb-11">
|
||||
<UiTextInput id="address-street" v-model="addressForm.street" label="Rue" wrapper-class="w-[280px]" required />
|
||||
<UiTextInput id="address-street2" v-model="addressForm.street2" label="Complément" wrapper-class="w-[280px]" />
|
||||
<UiTextInput id="address-country" v-model="addressForm.countryCode" label="Pays (code)" wrapper-class="w-[280px]" />
|
||||
</div>
|
||||
<div v-if="!customerId" class="flex flex-cols-3 justify-between mb-11">
|
||||
<UiTextInput id="address-postalCode" v-model="addressForm.postalCode" label="Code postal" wrapper-class="w-[280px]" required />
|
||||
<UiSelect id="address-city" v-model="addressForm.city" label="Ville"
|
||||
:options="communeOptions" :loading="isLoadingCities"
|
||||
wrapper-class="w-[280px]" required />
|
||||
<div class="w-[280px]" />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-center">
|
||||
<UiButton
|
||||
class="inline-flex mb-28 items-center justify-center text-xl min-w-[194px] text-white uppercase bg-primary-500 h-[50px] rounded hover:opacity-80 justify-self-end"
|
||||
@@ -26,6 +39,7 @@
|
||||
</UiButton>
|
||||
</div>
|
||||
|
||||
<template v-if="customerId">
|
||||
<div class="flex items-center justify-between mb-7">
|
||||
<h2 class="text-3xl text-primary-500 font-bold uppercase">Adresses du client</h2>
|
||||
</div>
|
||||
@@ -77,6 +91,7 @@
|
||||
Ajouter
|
||||
</UiButton>
|
||||
</div>
|
||||
</template>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
@@ -84,6 +99,8 @@
|
||||
import {computed, reactive, ref, watch} from "vue"
|
||||
import {createCustomer, getCustomer, updateCustomer} from "~/services/customer"
|
||||
import type {CustomerData, CustomerFormData, CustomerPayload} from "~/services/dto/customer-data"
|
||||
import {createAddress, type AddressPayload} from "~/services/address"
|
||||
import {getCommunesByPostalCode, type CommuneData} from "~/services/geo"
|
||||
import {useAuthStore} from "~/stores/auth"
|
||||
|
||||
const route = useRoute()
|
||||
@@ -106,6 +123,30 @@ const form = reactive<CustomerFormData>({
|
||||
addresses: [],
|
||||
})
|
||||
|
||||
// Address form (creation mode only)
|
||||
const addressForm = reactive<AddressPayload>({
|
||||
street: "", street2: null, postalCode: "", city: "", countryCode: "FR",
|
||||
})
|
||||
const communes = ref<CommuneData[]>([])
|
||||
const isLoadingCities = ref(false)
|
||||
const communeOptions = computed(() => communes.value.map(c => ({ value: c.nom, label: c.nom })))
|
||||
|
||||
let debounceTimer: ReturnType<typeof setTimeout> | null = null
|
||||
watch(() => addressForm.postalCode, (cp) => {
|
||||
if (debounceTimer) clearTimeout(debounceTimer)
|
||||
if (!cp || cp.length < 5) { communes.value = []; addressForm.city = ''; return }
|
||||
if (cp.length === 5) {
|
||||
debounceTimer = setTimeout(async () => {
|
||||
isLoadingCities.value = true
|
||||
try {
|
||||
communes.value = await getCommunesByPostalCode(cp)
|
||||
if (communes.value.length === 1) addressForm.city = communes.value[0].nom
|
||||
else addressForm.city = ''
|
||||
} finally { isLoadingCities.value = false }
|
||||
}, 300)
|
||||
}
|
||||
})
|
||||
|
||||
const goToAddAddress = () => {
|
||||
if (customerId.value === null || !auth.isAdmin) return
|
||||
router.push({
|
||||
@@ -187,8 +228,11 @@ async function validate() {
|
||||
await updateCustomer(customerId.value, customerPayload)
|
||||
targetId = customerId.value
|
||||
} else {
|
||||
const addressData = await createAddress({ ...addressForm })
|
||||
const addressIRI = `/api/addresses/${addressData.id}`
|
||||
const creationPayload = {
|
||||
...customerPayload,
|
||||
addresses: [addressIRI],
|
||||
...(auth.user?.id ? { createdBy: `/api/users/${auth.user.id}` } : {}),
|
||||
}
|
||||
const created = await createCustomer(creationPayload)
|
||||
|
||||
@@ -15,6 +15,19 @@
|
||||
<UiTextInput id="supplier-phone" v-model="form.phone" label="Téléphone" :disabled="!auth.isAdmin" wrapper-class="w-[280px]" required/>
|
||||
<UiTextInput id="supplier-email" v-model="form.email" label="Email" :disabled="!auth.isAdmin" wrapper-class="w-[280px]"/>
|
||||
</div>
|
||||
<div v-if="!supplierId" class="flex flex-cols-3 justify-between mb-11">
|
||||
<UiTextInput id="address-street" v-model="addressForm.street" label="Rue" wrapper-class="w-[280px]" required />
|
||||
<UiTextInput id="address-street2" v-model="addressForm.street2" label="Complément" wrapper-class="w-[280px]" />
|
||||
<UiTextInput id="address-country" v-model="addressForm.countryCode" label="Pays (code)" wrapper-class="w-[280px]" />
|
||||
</div>
|
||||
<div v-if="!supplierId" class="flex flex-cols-3 justify-between mb-11">
|
||||
<UiTextInput id="address-postalCode" v-model="addressForm.postalCode" label="Code postal" wrapper-class="w-[280px]" required />
|
||||
<UiSelect id="address-city" v-model="addressForm.city" label="Ville"
|
||||
:options="communeOptions" :loading="isLoadingCities"
|
||||
wrapper-class="w-[280px]" required />
|
||||
<div class="w-[280px]" />
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-center">
|
||||
<UiButton
|
||||
class="inline-flex mb-28 items-center justify-center text-xl min-w-[194px] text-white uppercase bg-primary-500 h-[50px] rounded hover:opacity-80 justify-self-end"
|
||||
@@ -27,6 +40,7 @@
|
||||
</UiButton>
|
||||
</div>
|
||||
|
||||
<template v-if="supplierId">
|
||||
<div class="flex items-center justify-between mb-7">
|
||||
<h2 class="text-3xl text-primary-500 font-bold uppercase">Adresses du fournisseur</h2>
|
||||
</div>
|
||||
@@ -78,6 +92,7 @@
|
||||
Ajouter
|
||||
</UiButton>
|
||||
</div>
|
||||
</template>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
@@ -85,6 +100,8 @@
|
||||
import {computed, reactive, ref, watch} from "vue"
|
||||
import {createSupplier, getSupplier, updateSupplier} from "~/services/supplier"
|
||||
import type {SupplierData, SupplierFormData, SupplierPayload} from "~/services/dto/supplier-data"
|
||||
import {createAddress, type AddressPayload} from "~/services/address"
|
||||
import {getCommunesByPostalCode, type CommuneData} from "~/services/geo"
|
||||
import {useAuthStore} from "~/stores/auth"
|
||||
|
||||
const route = useRoute()
|
||||
@@ -107,6 +124,30 @@ const form = reactive<SupplierFormData>({
|
||||
addresses: [],
|
||||
})
|
||||
|
||||
// Address form (creation mode only)
|
||||
const addressForm = reactive<AddressPayload>({
|
||||
street: "", street2: null, postalCode: "", city: "", countryCode: "FR",
|
||||
})
|
||||
const communes = ref<CommuneData[]>([])
|
||||
const isLoadingCities = ref(false)
|
||||
const communeOptions = computed(() => communes.value.map(c => ({ value: c.nom, label: c.nom })))
|
||||
|
||||
let debounceTimer: ReturnType<typeof setTimeout> | null = null
|
||||
watch(() => addressForm.postalCode, (cp) => {
|
||||
if (debounceTimer) clearTimeout(debounceTimer)
|
||||
if (!cp || cp.length < 5) { communes.value = []; addressForm.city = ''; return }
|
||||
if (cp.length === 5) {
|
||||
debounceTimer = setTimeout(async () => {
|
||||
isLoadingCities.value = true
|
||||
try {
|
||||
communes.value = await getCommunesByPostalCode(cp)
|
||||
if (communes.value.length === 1) addressForm.city = communes.value[0].nom
|
||||
else addressForm.city = ''
|
||||
} finally { isLoadingCities.value = false }
|
||||
}, 300)
|
||||
}
|
||||
})
|
||||
|
||||
const goToAddAddress = () => {
|
||||
if (supplierId.value === null || !auth.isAdmin) return
|
||||
router.push({
|
||||
@@ -190,8 +231,11 @@ async function validate() {
|
||||
await updateSupplier(supplierId.value, supplierPayload)
|
||||
targetId = supplierId.value
|
||||
} else {
|
||||
const addressData = await createAddress({ ...addressForm })
|
||||
const addressIRI = `/api/addresses/${addressData.id}`
|
||||
const creationPayload = {
|
||||
...supplierPayload,
|
||||
addresses: [addressIRI],
|
||||
...(auth.user?.id ? { createdBy: `/api/users/${auth.user.id}` } : {}),
|
||||
}
|
||||
const created = await createSupplier(creationPayload)
|
||||
|
||||
@@ -31,6 +31,7 @@ use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
|
||||
#[ORM\Table(name: 'reception')]
|
||||
#[ApiFilter(BooleanFilter::class, properties: ['isValid'])]
|
||||
#[ApiResource(
|
||||
order: ['id' => 'DESC'],
|
||||
operations: [
|
||||
new Get(
|
||||
requirements: ['id' => '\d+'],
|
||||
|
||||
@@ -31,6 +31,7 @@ use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
|
||||
#[ORM\Table(name: 'shipment')]
|
||||
#[ApiFilter(BooleanFilter::class, properties: ['isValid'])]
|
||||
#[ApiResource(
|
||||
order: ['id' => 'DESC'],
|
||||
operations: [
|
||||
new Get(
|
||||
requirements: ['id' => '\d+'],
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
</td>
|
||||
|
||||
<td style="width:30%; text-align:right; vertical-align:top; font-size: 14px;">
|
||||
<div style="display:inline-block; width:75mm; line-height:1.3;">
|
||||
<div style="display:inline-block; line-height:1.3; border: 1px solid black; padding: 8px; border-radius: 8px; width: 60mm">
|
||||
<strong>{{ reception.supplier ? reception.supplier.name : '-' }}</strong><br>
|
||||
<span>{{ reception.address ? reception.address.street : '' }}</span><br>
|
||||
{% if reception.address and reception.address.street2 %}
|
||||
|
||||
Reference in New Issue
Block a user