Merge pull request #1181 from betagouv/quickfix-johan

Quickfix johan
pull/1187/head
Johan Girod 2020-11-03 12:00:58 +01:00 committed by GitHub
commit 2292c9f6b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 190 additions and 143 deletions

View File

@ -64,11 +64,7 @@
content="<%= htmlWebpackPlugin.options.shareImage %>"
/>
<!-- data-helmet pour que React Helmet puisse écraser ce meta par défaut -->
<link
href="https://fonts.googleapis.com/css?family=Roboto:400,400i,600|Montserrat:400,600"
rel="stylesheet"
type="text/css"
/>
<link rel="manifest" href="/manifest.webmanifest" />
<title>
<%= htmlWebpackPlugin.options.title %>

View File

@ -67,6 +67,24 @@ async function fetchSimulatorsMonth() {
}
async function fetchSimulators(dt) {
async function fetchSubTableData(data, label) {
const subTable = data.find(page => page.label === label)
if (!subTable) {
console.log('No subtable for ' + label + ' for the period ' + dt + '.')
return []
}
const response = await fetch(
apiURL({
date: `${dt}`,
method: 'Actions.getPageUrls',
search_recursive: 1,
filter_limits: -1,
idSubtable: subTable.idsubdatatable
})
)
return await response.json()
}
try {
const response = await fetch(
apiURL({
@ -83,38 +101,11 @@ async function fetchSimulators(dt) {
)
// Visits on simulators pages
const idSubTableSimulateurs = firstLevelData.find(
page => page.label === 'simulateurs'
).idsubdatatable
const dataSimulateurs = await fetchSubTableData(firstLevelData, 'simulateurs')
const dataGérer = await fetchSubTableData(firstLevelData, 'gérer')
const dataProfessionLiberale = await fetchSubTableData(dataSimulateurs, 'profession-liberale')
const responseSimulateurs = await fetch(
apiURL({
date: `${dt}`,
method: 'Actions.getPageUrls',
search_recursive: 1,
filter_limits: -1,
idSubtable: idSubTableSimulateurs
})
)
const dataSimulateurs = await responseSimulateurs.json()
// Visits on "manage" pages
const idSubTableManage = firstLevelData.find(page => page.label === 'gérer')
.idsubdatatable
const responseManage = await fetch(
apiURL({
date: `${dt}`,
method: 'Actions.getPageUrls',
search_recursive: 1,
filter_limits: -1,
idSubtable: idSubTableManage
})
)
const dataManage = await responseManage.json()
const resultSimulateurs = [...dataSimulateurs, ...dataManage]
const resultSimulateurs = [...dataSimulateurs, ...dataProfessionLiberale, ...dataGérer]
.filter(({ label }) =>
[
'/salaire-brut-net',
@ -127,10 +118,12 @@ async function fetchSimulators(dt) {
'/aide-declaration-independants',
'/demande-mobilité',
'/profession-liberale',
'/profession-liberale/medecin',
'/profession-liberale/auxiliaire-medical',
'/profession-liberale/sage-femme',
'/profession-liberale/chirugien-dentiste',
'/medecin',
'/auxiliaire-medical',
'/sage-femme',
'/chirugien-dentiste',
'/avocat',
'/expert-comptable',
'/économie-collaborative'
].includes(label)
)
@ -146,33 +139,25 @@ async function fetchSimulators(dt) {
.reduce((a, b) => Math.min(a, b.nb_visits), 1000)
)
// Add iframes
const idTableIframes = firstLevelData.find(page => page.label == 'iframes')
.idsubdatatable
const responseIframes = await fetch(
apiURL({
date: `${dt}`,
method: 'Actions.getPageUrls',
search_recursive: 1,
filter_limits: -1,
idSubtable: idTableIframes
})
)
const dataIframes = await responseIframes.json()
const resultIframes = dataIframes.filter(x =>
[
'/simulateur-embauche',
'/simulateur-autoentrepreneur',
'/simulateur-assimilesalarie',
'/simulateur-artiste-auteur',
'/simulateur-independant',
'/demande-mobilite',
'/profession-liberale',
'/chirugien-dentiste',
'/auxiliaire-medical',
'/sage-femme'
].some(path => x.label.startsWith(path))
)
const resultIframes = (await fetchSubTableData(firstLevelData, 'iframes'))
.filter(x =>
[
'/simulateur-embauche',
'/simulateur-autoentrepreneur',
'/simulateur-assimilesalarie',
'/simulateur-artiste-auteur',
'/simulateur-independant',
'/demande-mobilite',
'/profession-liberale',
'/medecin',
'/auxiliaire-medical',
'/sage-femme',
'/chirugien-dentiste',
'/avocat',
'/expert-comptable',
].some(path => x.label.startsWith(path))
)
const groupSimulateursIframesVisits = ({ label }) =>
label.startsWith('/coronavirus')
@ -204,6 +189,8 @@ async function fetchSimulators(dt) {
.map(([label, nb_visits]) => ({ label, nb_visits }))
.sort((a, b) => b.nb_visits - a.nb_visits)
} catch (e) {
console.error(e)
console.log('fail to fetch Simulators Visits')
return null
}

View File

@ -0,0 +1,43 @@
/* roboto-regular - latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'),
url('./fonts/roboto-v20-latin-regular.woff2') format('woff2'),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url('./fonts/roboto-v20-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* roboto-italic - latin */
@font-face {
font-family: 'Roboto';
font-style: italic;
font-weight: 400;
src: local('Roboto Italic'), local('Roboto-Italic'),
url('./fonts/roboto-v20-latin-italic.woff2') format('woff2'),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url('./fonts/roboto-v20-latin-italic.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* roboto-500 - latin */
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: bold;
src: local('Roboto Medium'), local('Roboto-Medium'),
url('./fonts/roboto-v20-latin-500.woff2') format('woff2'),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url('./fonts/roboto-v20-latin-500.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}
/* montserrat-600 - latin */
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 600;
src: local('Montserrat SemiBold'), local('Montserrat-SemiBold'),
url('./fonts/montserrat-v15-latin-600.woff2') format('woff2'),
/* Chrome 26+, Opera 23+, Firefox 39+ */
url('./fonts/montserrat-v15-latin-600.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
}

View File

@ -23,6 +23,7 @@ html {
font-size: 1em;
}
}
body {
font-weight: 400;
color: #040e19;
@ -120,7 +121,7 @@ a:not(:disabled):not(.button):not(.button-choice):hover {
strong,
b {
font-weight: 600;
font-weight: bold;
}
textarea {

View File

@ -3,6 +3,7 @@
@import './Card.css';
@import './Toggle.css';
@import './reset.css';
@import './Fonts.css';
:root {
--color: rgb(41, 117, 209);

View File

@ -979,11 +979,11 @@ contrat salarié . activité partielle . heures travaillées:
titre.fr: contrôle temps de travail
contrat salarié . activité partielle . indemnisation entreprise:
description.en: '[automatic] In the context of the Coronavirus crisis, the
government has announced that the short-time working allowance will be 100%
paid by the state.'
government announced that the partial unemployment benefit for closed
businesses will be paid 100% by the state.'
description.fr: Dans le cadre de la crise du Coronavirus, le gouvernement a
annoncé que l'indemnité de chômage partiel sera prise à 100% en charge par
l'état.
annoncé que l'indemnité de chômage partiel pour les commerces fermés sera
prise à 100% en charge par l'état.
titre.en: '[automatic] Reimbursement of partial activity allowance'
titre.fr: Remboursement de l'indemnité d'activité partielle
? contrat salarié . activité partielle . indemnisation entreprise . taux d'indemnisation
@ -1053,11 +1053,28 @@ contrat salarié . activité partielle . rémunération mensuelle minimale:
titre.en: '[automatic] minimum monthly pay'
titre.fr: rémunération mensuelle minimale
contrat salarié . activité partielle . secteur d'activité restreint:
description.en: >-
[automatic] Companies accommodating the public that experience a partial or
total interruption of their activity due to the Covid-19 epidemic receive an
increased partial activity allocation rate.
This concerns in particular the hotel and catering, sports, culture and events sectors.
The other companies benefit from an ordinary rate of compensation.
description.fr: >-
Les entreprises accueillant du public qui connaissent une interruption
partielle ou totale de leur activité en raison de l'épidémie de Covid-19
percoivent un taux d'allocation d'activité partielle majoré.
Il concerne notamment les secteurs de l'hôtellerie-restauration, du sport, de la culture et de lévénementiel.
Les autres entreprises bénéficient d'un taux d'indemnité de droit commun.
question.en:
"[automatic] Are there any regulatory restrictions on the company's
line of business? (e.g. tourism, catering, culture)"
line of business? (e.g. tourism, catering, culture, events)"
question.fr: "Le secteur d'activité de l'entreprise fait-il l'objet de
restrictions réglementaires ? (ex. : tourisme, restauration, culture)"
restrictions réglementaires ? (ex. : tourisme, restauration, culture,
événementiel)"
titre.en: '[automatic] narrow focus'
titre.fr: secteur d'activité restreint
contrat salarié . aides employeur:
@ -3690,19 +3707,10 @@ dirigeant . auto-entrepreneur . cotisations et contributions . TFC . métiers:
contribution à la formation professionnelle leur permettant de bénéficier du
droit à la formation professionnelle (à condition davoir déclaré un chiffre
daffaires positif au cours des 12 derniers mois).
note.en: >
[automatic] The rules specified on the autoentrepreneur.urssaf.fr website
and those of the
in the text of the law differ. We have chosen to implement those
of the USSAF documentation while waiting for more information from them.
note.fr: >
Les règles précisées sur le site autoentrepreneur.urssaf.fr et celles
inscrites dans le texte de loi diffèrent. Nous avons choisi d'implémenter celles
de la documentation urssaf en attendant plus d'informations de leur part.
note.en: |
[automatic] The rates implemented are those levied by URSSAF.
note.fr: |
Les taux implémentés sont ceux prélevés par l'Urssaf.
titre.en: Contribution to vocational trainingyay
titre.fr: Contribution à la formation professionnelle
dirigeant . auto-entrepreneur . cotisations et contributions . cotisations:
@ -6144,14 +6152,14 @@ entreprise . effectif . seuil . moins de 50:
titre.fr: moins de 50
entreprise . franchise de TVA:
description.en: |
[automatic] The VAT exemption is an exemption from VAT for businesses.
[automatic] The VAT exemption is a device that exempts businesses from the
declaration and payment of VAT. It applies below a threshold of
annual turnover depending on the activity.
The professional covered by this scheme invoices his services or his
The professional covered by this scheme shall invoice his services or his
sales excluding tax, and cannot deduct VAT from its purchases.
description.fr: |
La franchise de TVA est un dispotif qui exonère les entreprises de la
La franchise de TVA est un dispositif qui exonère les entreprises de la
déclaration et du paiement de la TVA. Il s'applique en dessous d'un seuil de
chiffre d'affaire annuel dépendant de l'activité.

View File

@ -200,10 +200,7 @@ dirigeant . auto-entrepreneur . cotisations et contributions . contribution form
Fiche service-public.fr: https://www.service-public.fr/professionnels-entreprises/vosdroits/F23459
shine.fr: https://www.shine.fr/blog/formation-professionnelle-auto-entrepreneur/
note: |
Les règles précisées sur le site autoentrepreneur.urssaf.fr et celles
inscrites dans le texte de loi diffèrent. Nous avons choisi d'implémenter celles
de la documentation urssaf en attendant plus d'informations de leur part.
Les taux implémentés sont ceux prélevés par l'Urssaf.
formule:
produit:
assiette: base des cotisations
@ -235,13 +232,10 @@ dirigeant . auto-entrepreneur . cotisations et contributions . cotisations:
formule:
variations:
- si: entreprise . ACRE
alors:
barème:
assiette: base des cotisations
tranches:
- taux: taux de cotisation * taux ACRE
plafond: plafond ACRE
- taux: taux de cotisation
alors:
produit:
assiette: base des cotisations [€/mois]
taux: taux ACRE * taux de cotisation
- sinon:
produit:
assiette: base des cotisations [€/mois]

View File

@ -185,7 +185,7 @@ entreprise . ACRE par défaut:
entreprise . franchise de TVA:
description: |
La franchise de TVA est un dispotif qui exonère les entreprises de la
La franchise de TVA est un dispositif qui exonère les entreprises de la
déclaration et du paiement de la TVA. Il s'applique en dessous d'un seuil de
chiffre d'affaire annuel dépendant de l'activité.

View File

@ -353,7 +353,8 @@ contrat salarié . activité partielle . indemnisation entreprise:
titre: Remboursement de l'indemnité d'activité partielle
description: >-
Dans le cadre de la crise du Coronavirus, le gouvernement a annoncé que
l'indemnité de chômage partiel sera prise à 100% en charge par l'état.
l'indemnité de chômage partiel pour les commerces fermés sera prise à
100% en charge par l'état.
formule:
multiplication:
assiette: retrait absence
@ -381,7 +382,20 @@ contrat salarié . activité partielle . indemnisation entreprise . taux d'indem
contrat salarié . activité partielle . secteur d'activité restreint:
question: >-
Le secteur d'activité de l'entreprise fait-il l'objet de restrictions
réglementaires ? (ex. : tourisme, restauration, culture)
réglementaires ? (ex. : tourisme, restauration, culture, événementiel)
description: >-
Les entreprises accueillant du public qui connaissent une interruption partielle
ou totale de leur activité en raison de l'épidémie de Covid-19 percoivent un taux
d'allocation d'activité partielle majoré.
Il concerne notamment les secteurs de l'hôtellerie-restauration, du sport,
de la culture et de lévénementiel.
Les autres entreprises bénéficient d'un taux d'indemnité de droit commun.
références:
Liste des secteurs concernés: https://travail-emploi.gouv.fr/actualites/presse/communiques-de-presse/article/prise-en-charge-a-100-de-l-activite-partielle-par-l-etat-pour-les-entreprises
Actualité service-public.fr: https://www.service-public.fr/particuliers/actualites/A14386
par défaut: non
# TODO : This should be merged with other convention collectives

View File

@ -130,7 +130,7 @@ export default function Stats() {
{stats.simulators[choicesimulators].visites.map(
({ label, nb_visits }) => {
const details = simulators.find(({ path }) => path?.includes(label))
const details = simulators.find(({ path }) => path?.endsWith(label))
if (!details) {
return null
}

View File

@ -77,23 +77,6 @@ module.exports = {
clientsClaim: true,
skipWaiting: true,
swDest: 'sw.js',
runtimeCaching: [
{
urlPattern: new RegExp(
'https://fonts.(?:googleapis|gstatic).com/(.*)'
),
handler: 'cacheFirst',
options: {
cacheName: 'google-fonts',
expiration: {
maxEntries: 5
},
cacheableResponse: {
statuses: [0, 200]
}
}
}
],
navigateFallback: '/fallback',
navigateFallbackWhitelist: [/^\/[^_]+$/], // fallback for anything that doesn't start with
navigateFallbackBlacklist: [

View File

@ -4,9 +4,10 @@ import React from 'react'
import { Trans } from 'react-i18next'
import { Mecanism } from './common'
export default function Recalcul({ nodeValue, explanation }) {
export default function Recalcul({ nodeValue, explanation, unit }) {
console.log(nodeValue, explanation)
return (
<Mecanism name="recalcul" value={nodeValue} unit={explanation.unit}>
<Mecanism name="recalcul" value={nodeValue} unit={unit}>
<>
{explanation.recalcul && (
<Trans i18nKey="calcul-avec">
@ -16,10 +17,10 @@ export default function Recalcul({ nodeValue, explanation }) {
</Trans>
)}
<ul>
{Object.keys(explanation.amendedSituation).map(dottedName => (
<li key={dottedName}>
<RuleLinkWithContext dottedName={dottedName} /> ={' '}
{makeJsx(explanation.amendedSituation[dottedName])}
{explanation.amendedSituation.map(([origin, replacement]) => (
<li key={origin.dottedName}>
<RuleLinkWithContext dottedName={origin.dottedName} /> ={' '}
{makeJsx(replacement)}
</li>
))}
</ul>

View File

@ -7,19 +7,17 @@ const evaluateRecalcul = (cache, situation, parsedRules, node) => {
return defaultNode(false)
}
const amendedSituation = Object.fromEntries(
node.explanation.amendedSituation
.map(([originRule, replacement]) => [
evaluateNode(cache, situation, parsedRules, originRule),
evaluateNode(cache, situation, parsedRules, replacement)
])
.filter(
([originRule, replacement]) =>
originRule.nodeValue !== replacement.nodeValue ||
serializeUnit(originRule.unit) !== serializeUnit(replacement.unit)
)
.map(([originRule, replacement]) => [originRule.dottedName, replacement])
)
const amendedSituation = node.explanation.amendedSituation
.map(([originRule, replacement]) => [
evaluateNode(cache, situation, parsedRules, originRule),
evaluateNode(cache, situation, parsedRules, replacement)
])
.filter(
([originRule, replacement]) =>
originRule.nodeValue !== replacement.nodeValue ||
serializeUnit(originRule.unit) !== serializeUnit(replacement.unit)
)
// Optimisation : no need for recalcul if situation is the same
const recalculCache = Object.keys(amendedSituation).length
? { _meta: { ...cache._meta, inRecalcul: true } } // Create an empty cache
@ -27,7 +25,15 @@ const evaluateRecalcul = (cache, situation, parsedRules, node) => {
const evaluatedNode = evaluateNode(
recalculCache,
{ ...situation, ...amendedSituation },
{
...situation,
...Object.fromEntries(
amendedSituation.map(([originRule, replacement]) => [
originRule.dottedName,
replacement
])
)
},
parsedRules,
node.explanation.recalcul
)

View File

@ -65,6 +65,19 @@ module.exports.commonLoaders = ({ legacy = false, file = true } = {}) => {
}
]
: []),
{
test: /\.(ttf|woff2?)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts',
publicPath: '/fonts'
}
}
]
},
{
test: /\.yaml$/,
use: ['json-loader', 'yaml-loader']
@ -82,7 +95,7 @@ module.exports.commonLoaders = ({ legacy = false, file = true } = {}) => {
use: ['raw-loader']
},
{
test: /\.(ttf|pdf)$/,
test: /\.pdf$/,
use: ['file-loader']
}
]