Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Import MesParcelles #323

Merged
merged 2 commits into from
Feb 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/cartobio-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,19 @@ export async function convertShapefileArchiveToGeoJSON (archive) {
return geojson
}

/**
* Turn a Telepac XML file into a GeoJSON
*
* @param {File} archive
* @returns {GeoJSON}
*/
export async function convertTelepacXMLToGeoJSON (file) {
const form = new FormData()
form.append('file', file)
const { data: geojson } = await apiClient.post(`/v2/convert/telepac-xml/geojson`, form)
return geojson
}

/**
* Turn a geofolia archive into a GeoJSON
*
Expand Down
105 changes: 103 additions & 2 deletions src/components/OperatorSetup/Flow.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ import { sources } from '@/referentiels/imports.js'

setActivePinia(createPinia())

const activeSources = [sources.TELEPAC, sources.GEOFOLIA, sources.RPG, sources.CVI, sources.MESPARCELLES]
const operatorSetupActions = [
{
id: 'source',
selector: markRaw(ActionFromSource),
wizzard: markRaw(FlowMultiSources),
extraProps: {
sources: [sources.TELEPAC, sources.GEOFOLIA, sources.RPG, sources.CVI]
sources: activeSources
}
},
{ id: 'manual', selector: markRaw(ActionFromScratch) },
Expand Down Expand Up @@ -81,7 +82,7 @@ describe("OperatorSetupFlow", () => {
await flushPromises()

const tabs = wrapper.findAll('.fr-tabs__tab')
expect(tabs).toHaveLength(4)
expect(tabs).toHaveLength(activeSources.length)
expect(tabs.at(0).attributes()).toHaveProperty('aria-selected', 'true')
expect(tabs.at(0).text()).toBe('Telepac')

Expand Down Expand Up @@ -146,6 +147,106 @@ describe("OperatorSetupFlow", () => {
expect(wrapper.text()).toContain('Votre fichier n\'est pas reconnu comme un export Geofolia.')
})

it("should fail on unreachable server during Geofolia import", async () => {
const wrapper = mount(OperatorSetupFlow, {
props: {
actions: [ ...operatorSetupActions ],
flowId: 'source',
operator: record.operator
},
global: {
config: {
errorHandler (error) {
expect(error.message).toBe('Server is down')
}
}
}
})

await wrapper.find('ul').find('.import-source-tab--geofolia').trigger('click')

const error = new AxiosError('Server is down')
error.response = { status : 500 }
axios.__createMock.post.mockRejectedValueOnce(error)

await wrapper.find('input[type="file"]').setValue('')
await flushPromises()
expect(wrapper.text()).toContain('Erreur inconnue, merci de réessayer plus tard.')
})

it("should import successfully a MesParcelles/TelepacXML archive", async () => {
const wrapper = mount(OperatorSetupFlow, {
props: {
actions: operatorSetupActions,
flowId: 'source',
operator: record.operator
}
})

// Click on mesparcelles tab
await wrapper.find('ul').find('.import-source-tab--mesparcelles').trigger('click')
expect(wrapper.text()).toContain(`Sélectionner mon export MesParcelles (service Telepac)`)

axios.__createMock.post.mockResolvedValueOnce({
data: featureCollectionFixture
})

await wrapper.find('input[type="file"]').setValue('')
await flushPromises()

// it is now called during preview
const confirmBtn = await wrapper.find('.fr-btn')
expect(confirmBtn.text()).toEqual('Importer ces données')
})

it("should fail on invalid MesParcelles/TelepacXML archive", async () => {
const wrapper = mount(OperatorSetupFlow, {
props: {
actions: [ ...operatorSetupActions ],
flowId: 'source',
operator: record.operator
}
})

const error = new AxiosError('Fichier invalide')
error.response = { status : 400 }
axios.__createMock.post.mockRejectedValueOnce(error)

await wrapper.find('ul').find('.import-source-tab--mesparcelles').trigger('click')
await wrapper.find('input[type="file"]').setValue('')
await flushPromises()

expect(wrapper.text()).toContain('Votre fichier ne semble pas être un export MesParcelles valide.')
})

it("should fail on unreachable server during a MesParcelles/TelepacXML import", async () => {
const wrapper = mount(OperatorSetupFlow, {
props: {
actions: [ ...operatorSetupActions ],
flowId: 'source',
operator: record.operator
},
global: {
config: {
errorHandler (error) {
expect(error.message).toBe('Server is down')
}
}
}
})

await wrapper.find('ul').find('.import-source-tab--mesparcelles').trigger('click')

const error = new AxiosError('Server is down')
error.response = { status : 500 }
axios.__createMock.post.mockRejectedValueOnce(error)

await wrapper.find('input[type="file"]').setValue('')
await flushPromises()

expect(wrapper.text()).toContain('Erreur inconnue, merci de réessayer plus tard.')
})

it("should render tab content for RPG when selected", async () => {
const wrapper = mount(OperatorSetupFlow, {
props: {
Expand Down
2 changes: 1 addition & 1 deletion src/components/OperatorSetup/Flows/MultiSources.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const props = defineProps({

const featureSource = ref(DEFAULT_SOURCE)
const sourcesTabs = computed(() => Object.fromEntries(
Object.entries(featureSources).filter(([sourceId]) => props.sources.includes(sourceId))
props.sources.map(sourceId => ([sourceId, featureSources[sourceId]]))
))

function handleSelection ({ geojson, warnings = [], metadata = {} }) {
Expand Down
2 changes: 1 addition & 1 deletion src/components/OperatorSetup/Sources/Geofolia.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ async function handleFileUpload () {

emit('upload:complete', { geojson, source: sources.GEOFOLIA, warnings: [], metadata: {} })
} catch (error) {
if (error.response?.status >= 400 && error.response?.status <= 500) {
if (error.response?.status >= 400 && error.response?.status < 500) {
erreur.value = 'Votre fichier n\'est pas reconnu comme un export Geofolia.'
} else {
erreur.value = 'Erreur inconnue, merci de réessayer plus tard.'
Expand Down
58 changes: 58 additions & 0 deletions src/components/OperatorSetup/Sources/MesParcelles.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<template>
<div>
<div class="fr-upload-group fr-mb-5w">
<input type="file" ref="fileInput" accept=".xml" @change="handleFileUpload" hidden />
<button class="fr-btn fr-icon-upload-line fr-btn--icon-left" @click="fileInput.click()">
Sélectionner mon export MesParcelles (service Telepac)
</button>
</div>

<div v-if="erreur" class="fr-alert fr-alert--error fr-mb-6w">
<h3 class="fr-alert__title">Échec de l'import</h3>
<p>{{ erreur }}</p>
</div>

<div class="fr-alert fr-alert--info">
<h3 class="fr-alert__title">Où récupérer le fichier demandé ?</h3>

<p>
Consultez la page <a href="https://docs-cartobio.agencebio.org/agriculteurs.trices/pas-a-pas/importer-mon-parcellaire/import-mesparcelles" target="_blank">import MesParcelles</a>
de notre documentation pour une aide illustrée et pas à pas.
</p>
</div>
</div>
</template>

<script setup>
import { ref } from 'vue'
import { convertTelepacXMLToGeoJSON } from '@/cartobio-api.js'
import { sources } from "@/referentiels/imports.js"

const emit = defineEmits(['upload:start', 'upload:complete'])

const fileInput = ref(null)
const erreur = ref('')

async function handleFileUpload () {
const warnings = []
const [file] = fileInput.value.files

emit('upload:start')

try {
const geojson = await convertTelepacXMLToGeoJSON(file)
const metadata = {
pacage: geojson.features.at(0)?.properties?.PACAGE,
}

emit('upload:complete', { geojson, source: sources.MESPARCELLES, warnings, metadata })
} catch (error) {
if (error.response?.status >= 400 && error.response?.status < 500) {
erreur.value = 'Votre fichier ne semble pas être un export MesParcelles valide.'
} else {
erreur.value = 'Erreur inconnue, merci de réessayer plus tard.'
throw error
}
}
}
</script>
2 changes: 1 addition & 1 deletion src/components/OperatorSetup/Sources/Telepac.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ async function handleFileUpload () {

emit('upload:complete', { geojson, source, warnings, metadata })
} catch (error) {
if (error.response?.status >= 400 && error.response?.status <= 500) {
if (error.response?.status >= 400 && error.response?.status < 500) {
erreur.value = 'Votre fichier ne semble pas être une déclaration PAC valide.'
} else {
erreur.value = 'Erreur inconnue, merci de réessayer plus tard.'
Expand Down
4 changes: 3 additions & 1 deletion src/components/OperatorSetup/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { sources } from '@/referentiels/imports.js'
import GeofoliaFeaturesImport from '@/components/OperatorSetup/Sources/Geofolia.vue'
import RPGFeaturesImport from '@/components/OperatorSetup/Sources/RPG.vue'
import CviFeaturesImport from '@/components/OperatorSetup/Sources/Cvi.vue'
import MesParcellesFeaturesImport from '@/components/OperatorSetup/Sources/MesParcelles.vue'
import TelepacFeaturesImport from '@/components/OperatorSetup/Sources/Telepac.vue'

export default {
Expand All @@ -23,8 +24,9 @@ export default {
label: 'ProDouanes (CVI)',
component: markRaw(CviFeaturesImport),
},
[sources.MES_PARCELLES]: {
[sources.MESPARCELLES]: {
label: 'MesParcelles',
component: markRaw(MesParcellesFeaturesImport),
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/pages/exploitations/[numeroBio]/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ const operatorSetupActions = [
selector: markRaw(ActionFromSource),
wizzard: defineAsyncComponent(() => import('@/components/OperatorSetup/Flows/MultiSources.vue')),
extraProps: {
sources: [sources.GEOFOLIA, sources.TELEPAC, ...(permissions.isOc ? [sources.RPG] : []), sources.CVI]
sources: [sources.GEOFOLIA, sources.MESPARCELLES, sources.TELEPAC, ...(permissions.isOc ? [sources.RPG] : []), sources.CVI]
}
},
{ id: 'manual', selector: markRaw(ActionFromScratch) },
Expand Down
2 changes: 1 addition & 1 deletion src/referentiels/imports.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
export const sources = Object.freeze({
GEOFOLIA: 'geofolia',
MANUAL: '',
MES_PARCELLES: 'mesparcelles',
MESPARCELLES: 'mesparcelles',
CVI: 'cvi',
RPG: 'rpg',
SMAG_FARMER: 'smagfarmer',
Expand Down
2 changes: 1 addition & 1 deletion widget/Notification.ce.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const operatorSetupActions = [
selector: null,
wizzard: markRaw(FlowMultiSources),
extraProps: {
sources: [sources.GEOFOLIA, sources.TELEPAC, sources.CVI]
sources: [sources.GEOFOLIA, sources.MESPARCELLES, sources.TELEPAC, sources.CVI]
}
},
]
Expand Down
Loading