def siren_siret_vat_in_name_onchange(self): if ( self.name and self.is_company and not self.parent_id and not self.siren and not self.nic and not self.siret and not self.street and not self.city and not self.zip ): name = self.name.replace(" ", "") if name: vals = False if len(name) == 9 and name.isdigit() and siren_is_valid(name): vals = self._opendatasoft_get_from_siren(name) elif len(name) == 14 and name.isdigit() and siret_is_valid(name): vals = self._opendatasoft_get_from_siret(name) elif ( len(name) == 13 and name[:2] == "FR" and name[2:].isdigit() and siren_is_valid(name[4:]) ): vals = self._opendatasoft_get_from_siren(name[4:]) if vals: self.update(vals)
def _check_siret(self): """Check the SIREN's and NIC's keys (last digits)""" for rec in self: if rec.type == "contact" and rec.parent_id: continue if rec.nic: # Check the NIC type and length if not rec.nic.isdigit() or len(rec.nic) != 5: raise ValidationError( _("The NIC '%s' is incorrect: it must have " "exactly 5 digits.") % rec.nic) if rec.siren: # Check the SIREN type, length and key if not rec.siren.isdigit() or len(rec.siren) != 9: raise ValidationError( _("The SIREN '%s' is incorrect: it must have " "exactly 9 digits.") % rec.siren) if not siren_is_valid(rec.siren): raise ValidationError( _("The SIREN '%s' is invalid: the checksum is wrong.") % rec.siren) # Check the NIC key (you need both SIREN and NIC to check it) if rec.nic and not siret_is_valid(rec.siren + rec.nic): raise ValidationError( _("The SIRET '%s%s' is invalid: " "the checksum is wrong.") % (rec.siren, rec.nic))
def _opendatasoft_get_from_siren(self, siren, vat_vies_query=True): if siren and siren_is_valid(siren): vals = self._opendatasoft_get_first_result( "siren:%s AND etablissementsiege:oui" % siren, vat_vies_query=vat_vies_query, ) if vals and vals.get("siren") == siren: return vals return False
def _inverse_siret(self): for rec in self: if rec.siret: if siret_is_valid(rec.siret): rec.write({"siren": rec.siret[:9], "nic": rec.siret[9:]}) elif siren_is_valid( rec.siret[:9]) and rec.siret[9:] == "*****": rec.write({"siren": rec.siret[:9], "nic": False}) else: raise ValidationError( _("SIRET '%s' is invalid.") % rec.siret) else: rec.write({"siren": False, "nic": False})
def vat_onchange(self): if ( self.vat and not self.name and not self.siren and not self.siret and self.is_company and not self.parent_id ): vat = self.vat.replace(" ", "").upper() if vat and vat.startswith("FR") and len(vat) == 13: siren = vat[4:] if siren_is_valid(siren): vals = self._opendatasoft_get_from_siren(siren) if vals: self.update(vals)
async def declare(request, response, siren, year): try: year = int(year) except ValueError: raise HttpError(f"Ce n'est pas une année valide: `{year}`") if not siren_is_valid(siren): raise HttpError(422, f"Numéro SIREN invalide: {siren}") if year not in constants.YEARS: years = ", ".join([str(y) for y in constants.YEARS]) raise HttpError( 422, f"Il est possible de déclarer seulement pour les années {years}" ) data = request.data declarant = request["email"] data.setdefault("déclarant", {}) # Use token email as default for declarant email. if not data["déclarant"].get("email"): data["déclarant"]["email"] = declarant schema.validate(data.raw) helpers.compute_notes(data) schema.cross_validate(data.raw) try: current = await db.declaration.get(siren, year) except db.NoData: current = None else: # Do not force new declarant, in case this is a staff person editing declarant = current["declarant"] declared_at = current["declared_at"] expired = declared_at and declared_at < utils.remove_one_year(utils.utcnow()) if expired and not request["staff"]: raise HttpError(403, "Le délai de modification est écoulé.") await db.declaration.put(siren, year, declarant, data) response.status = 204 if data.validated: await db.archive.put(siren, year, data, by=request["email"], ip=request.ip) if not request["staff"]: await db.ownership.put(siren, request["email"]) # Do not send the success email on update for now (we send too much emails that # are unwanted, mainly because when someone loads the frontend app a PUT is # automatically sent, without any action from the user.) loggers.logger.info(f"{siren}/{year} BY {declarant} FROM {request.ip}") if not current or not current.data.validated: owners = await db.ownership.emails(siren) url = request.domain + data.uri emails.success.send(owners, url=url, **data)
def siren_onchange(self): if ( self.siren and siren_is_valid(self.siren) and not self.name and self.is_company and not self.parent_id ): if self.nic: # We only execute the query if the full SIRET is OK vals = False if siret_is_valid(self.siren + self.nic): siret = self.siren + self.nic vals = self._opendatasoft_get_from_siret(siret) else: vals = self._opendatasoft_get_from_siren(self.siren) if vals: self.update(vals)
async def validate_siren(request, response): siren = request.query.get("siren") if not siren_is_valid(siren): raise HttpError(422, f"Numéro SIREN invalide: {siren}") metadata = await helpers.load_from_api_entreprises(siren) response.json = metadata
def _cross_validate(data): data = Data(data) if data.validated: # Those keys are only required if the data is validated required = [ "entreprise.région", "entreprise.département", "entreprise.adresse", "entreprise.commune", "entreprise.code_postal", "entreprise.code_naf", "déclarant.prénom", "déclarant.nom", "déclarant.téléphone", ] for path in required: assert data.path(path), f"Le champ {path} doit être défini" dep = data.path("entreprise.département") region = data.path("entreprise.région") cp = data.path("entreprise.code_postal") msg = "Le département et la région ne correspondent pas" assert dep in constants.REGIONS_TO_DEPARTEMENTS[region], msg msg = "Le département et le code postal ne correspondent pas" assert check_dep_and_cp(dep, cp), msg index = data.path("déclaration.index") mesures_correctives = data.path("déclaration.mesures_correctives") if data.year >= 2020 or index is not None: msg = "La date de publication doit être définie" assert data.path("déclaration.publication.date"), msg msg = "Les modalités de publication ou le site Internet doit être défini" assert data.path("déclaration.publication.modalités") or data.path( "déclaration.publication.url" ), msg if index is None: msg = "Les mesures correctives ne doivent pas être définies si l'index n'est pas calculable" assert not mesures_correctives, msg elif index >= 75: msg = "Les mesures correctives ne doivent pas être définies pour un index de 75 ou plus" assert not mesures_correctives, msg else: msg = "Les mesures correctives doivent être définies pour un index inférieur à 75" assert mesures_correctives, msg periode_reference = data.path("déclaration.fin_période_référence") assert ( periode_reference ), "Le champ déclaration.fin_période_référence doit être défini" try: annee_periode_reference = date.fromisoformat(periode_reference).year except ValueError: annee_periode_reference = None assert ( annee_periode_reference == data.year ), "L'année de la date de fin de période ne peut pas être différente de l'année au titre de laquelle les indicateurs sont calculés." tranche = data.path("entreprise.effectif.tranche") indicateurs_gt_250 = ("indicateurs.promotions", "indicateurs.augmentations") indicateurs_lt_250 = "indicateurs.augmentations_et_promotions" if tranche == "50:250": for path in indicateurs_gt_250: msg = f"L'indicateur {path} ne doit pas être défini pour la tranche 50 à 250" assert not data.path(path), msg msg = f"L'indicateur {indicateurs_lt_250} doit être défini pour la tranche 50 à 250" assert data.path(indicateurs_lt_250), msg else: msg = f"L'indicateur {indicateurs_lt_250} ne peut être défini que pour la tranche 50 à 250" assert not data.path(indicateurs_lt_250), msg for path in indicateurs_gt_250: msg = f"L'indicateur {path} doit être défini" assert data.path(path), msg for key in SCHEMA.indicateurs_keys: path = f"indicateurs.{key}" if data.path(f"{path}.non_calculable"): msg = f"L'indicateur {path} doit être vide s'il n'est pas calculable" assert list(data.path(path).keys()) == ["non_calculable"], msg elif data.path(path) is not None: resultat = data.path(f"{path}.résultat") msg = f"{path}.résultat doit être défini si l'indicateur est calculable" if key != "rémunérations" or data.path(f"{path}.population_favorable"): # The "rémunérations" indicator is sent through several steps # on the "formulaire" frontend. The only way the "formulaire" # sent all its data is if there's a `population_favorable` # field. However, this latter field is only provided if the # `résultat` is not `0`. assert resultat is not None, msg keys = ["rémunérations", "augmentations", "promotions"] for key in keys: path = f"indicateurs.{key}" if data.path(f"{path}.résultat") == 0: msg = f"{path}.population_favorable doit être vide si le résultat est 0" assert not data.path(f"{path}.population_favorable"), msg # Entreprise entreprises = data.path("entreprise.ues.entreprises") or [] all_siren = [e["siren"] for e in entreprises] duplicates = [v for v, c in Counter(all_siren).items() if c > 1] assert not duplicates, f"Valeur de siren en double: {','.join(duplicates)}" assert ( data.siren not in all_siren ), "L'entreprise déclarante ne doit pas être dupliquée dans les entreprises de l'UES" for ues in entreprises: msg = f"Invalid siren: {ues['siren']}" assert siren_is_valid(ues["siren"]), msg if not entreprises: msg = "Une entreprise ne doit pas avoir de nom d'UES" assert not data.path("entreprise.ues.nom"), msg # Rémunérations base = "indicateurs.rémunérations" if not data.path(f"{base}.non_calculable"): date_consultation_cse = data.path(f"{base}.date_consultation_cse") mode = data.path(f"{base}.mode") if mode == "csp": msg = f"{base}.date_consultation_cse ne doit pas être défini si indicateurs.rémunérations.mode vaut 'csp'" assert not date_consultation_cse, msg # Augmentations et promotions base = "indicateurs.augmentations_et_promotions" if ( data.path(f"{base}.résultat") == 0 and data.path(f"{base}.résultat_nombre_salariés") == 0 ): path = f"{base}.population_favorable" msg = f"{path} ne doit pas être défini si résultat=0 et résultat_nombre_salariés=0" assert not data.path(path), msg # Hautes rémunérations base = "indicateurs.hautes_rémunérations" if data.path(f"{base}.résultat") == 5: msg = f"{base}.population_favorable ne doit pas être défini si résultat vaut 5" assert not data.path(f"{base}.population_favorable"), msg