Skip to content

Commit

Permalink
feat: Modification api parcellaire
Browse files Browse the repository at this point in the history
  • Loading branch information
Hugoobx committed Nov 29, 2024
1 parent 435769b commit e49625b
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 17 deletions.
58 changes: 46 additions & 12 deletions lib/providers/cartobio.js
Original file line number Diff line number Diff line change
Expand Up @@ -1253,15 +1253,21 @@ async function getDataGouvStats () {
* @generator
* @param {NodeJS.ReadableStream} stream - a Json Stream
* @param {{ organismeCertificateur: OrganismeCertificateur }} options
* @yields {{ record: Partial<NormalizedRecord>, error: Error?}}
* @yields {{ record: Partial<NormalizedRecord>, error: Error?, warnings?: Array<[Number, String]> }}
*/
async function * parseAPIParcellaireStream (stream, { organismeCertificateur }) {
/**
* @type {Promise<InputApiRecord>[]}
*/
const streamRecords = stream.pipe(JSONStream.parse([true]))
const warnings = []

for await (const record of streamRecords) {
const correctNumeroBio = await isCorrectNumeroBio(String(record.numeroBio))
if (!correctNumeroBio) {
warnings.push([record.numeroBio, 'Numéro bio pas à jour'])
}

if (record.dateCertificationDebut && isNaN(Date.parse(record.dateCertificationDebut))) {
yield { numeroBio: String(record.numeroBio), error: new Error('champ dateCertificationDebut incorrect') }
continue
Expand All @@ -1279,9 +1285,9 @@ async function * parseAPIParcellaireStream (stream, { organismeCertificateur })

let hasFeatureError = null

const features = record.parcelles
const features = await Promise.all(record.parcelles
// turn products into features
.map(parcelle => {
.map(async (parcelle) => {
const id = !Number.isNaN(parseInt(String(parcelle.id), 10)) ? parseInt(String(parcelle.id), 10) : getRandomFeatureId()
const cultures = parcelle.culture ?? parcelle.cultures
const pac = parsePacDetailsFromComment(parcelle.commentaire)
Expand Down Expand Up @@ -1320,6 +1326,10 @@ async function * parseAPIParcellaireStream (stream, { organismeCertificateur })
}

try {
const isValidPolygon = await pool.query('SELECT ST_IsValid($1::geometry) AS valid, ST_IsEmpty($1::geometry) AS empty', [polygon(coordinates).geometry])
if (!isValidPolygon.rows[0].valid || isValidPolygon.rows[0].empty) {
warnings.push([record.numeroBio, "Une des parcelles n'est pas valide ou est vide"])
}
coordinates = JSON.parse(parcelle.geom.replace(/}$/, ''))
coordinates.forEach(ring => ring.forEach(([x, y]) => {
if (y > 90 || y < -90) {
Expand Down Expand Up @@ -1360,7 +1370,7 @@ async function * parseAPIParcellaireStream (stream, { organismeCertificateur })

hasFeatureError = new Error('geometry en dehors des régions autorisées.')
return null
})
}))

// known error, we skip the record
if (hasFeatureError) {
Expand Down Expand Up @@ -1390,32 +1400,38 @@ async function * parseAPIParcellaireStream (stream, { organismeCertificateur })
anneeReferenceControle: record.anneeReferenceControle,
...(record.anneeAssolement ? { anneeAssolement: record.anneeAssolement } : {})
}
}
},
warnings: warnings
}
}
}

/**
* @param {NodeJS.ReadableStream} stream
* @param {OrganismeCertificateur} organismeCertificateur
* @returns {Promise<{count: number, errors: Array<[Number, String]>}>}
* @returns {Promise<{count: number, errors: Array<[Number, String]>,warning: Array<[Number,Array<[Number,String]>]>}>}
*/
async function parcellaireStreamToDb (stream, organismeCertificateur) {
const generator = parseAPIParcellaireStream(stream, { organismeCertificateur })
let count = 0
/** @type {Array<[Number, String]>} */
const errors = []
/** @type {Array<[Number,Array<[Number,String]>]>} */
const warning = []

const client = await pool.connect()
await client.query('BEGIN;')

try {
for await (const { record, error } of generator) {
for await (const { record, error, warnings } of generator) {
count++
if (error) {
errors.push([count, error.message])
continue
}
if (warnings) {
warning.push([count, warnings])

Check failure on line 1433 in lib/providers/cartobio.js

View workflow job for this annotation

GitHub Actions / node-test

Type '(string | number)[][]' is not assignable to type '[number, string][]'.
}

try {
await createOrUpdateOperatorRecord(record, null, client)
Expand All @@ -1439,13 +1455,31 @@ async function parcellaireStreamToDb (stream, organismeCertificateur) {
throw error
}

if (errors.length) {
await client.query('ROLLBACK;')
await client.query('COMMIT;')
client.release()
return { count, errors, warning }
}

/**
* Checks if the given NumeroBio is correct by verifying if it has a production activity with productionId 1.
*
* @param {string} enter - The NumeroBio to be checked.
* @returns {Promise<boolean>} - A promise that resolves to true if the NumeroBio has a production activity with productionId 1, otherwise false.
*/
async function isCorrectNumeroBio (enter) {
let data
try {
data = await fetchOperatorByNumeroBio(enter)
} catch (error) {
if (error?.response?.statusCode === 404) {
return false
}
}
if (data) {
return data.isProduction
} else {
await client.query('COMMIT;')
return false
}
client.release()
return { count, errors }
}

module.exports = {
Expand Down
5 changes: 3 additions & 2 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -446,14 +446,15 @@ app.register(async (app) => {
return new PassThrough().end('{}')
}
}), (request, reply) => {
const { count, errors } = request.APIResult
const { count, errors, warnings } = request.APIResult

if (errors.length > 0) {
return reply.code(400).send({
nbObjetTraites: count,
nbObjetAcceptes: count - errors.length,
nbObjetRefuses: errors.length,
listeProblemes: errors.map(([index, message]) => `[#${index}] ${message}`)
listeProblemes: errors.map(([index, message]) => `[#${index}] ${message}`),
listeWarning: warnings && warnings.length > 0 ? warnings.map(([index, message]) => `[#${index}] ${message}`) : []
})
}

Expand Down
6 changes: 3 additions & 3 deletions server.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1286,16 +1286,16 @@ describe('POST /api/v2/certification/parcelles', () => {
.post('/api/v2/certification/parcelles')
.set('Authorization', fakeOcToken)
.send(apiParcellaire)
expect(db.query).not.toHaveBeenCalled()
expect(db.query).toHaveBeenCalled()
expect(db.connect).toHaveBeenCalled()
expect(db._clientQuery).toHaveBeenCalledWith('ROLLBACK;')
expect(db._clientRelease).toHaveBeenCalled()
expect(res.status).toBe(400)
expect(mockSentry).not.toHaveBeenCalled()
expect(res.body).toEqual({
nbObjetTraites: 8,
nbObjetAcceptes: 2,
nbObjetRefuses: 6,
listeWarning: [],
listeProblemes: [
// in case of error, check `createOrUpdateOperatorRecord()` SQL arity
'[#2] champ dateAudit incorrect',
Expand All @@ -1322,7 +1322,7 @@ describe('POST /api/v2/certification/parcelles', () => {
.set('Authorization', fakeOcToken)
.send(validApiParcellaire)

expect(db.query).not.toHaveBeenCalled()
expect(db.query).toHaveBeenCalled()
expect(db.connect).toHaveBeenCalled()
expect(db._clientQuery).toHaveBeenLastCalledWith('COMMIT;')
expect(db._clientRelease).toHaveBeenCalled()
Expand Down

0 comments on commit e49625b

Please sign in to comment.