Exemple #1
0
def test_post_form(app):
    from zam_repondeur.models import Lecture

    assert not Lecture.exists(
        chambre="an", session="15", num_texte=269, organe="PO717460"
    )

    # We cannot use form.submit() given the form is dynamic and does not
    # contain choices for lectures (dynamically loaded via JS).
    resp = app.post(
        "/lectures/add",
        {"dossier": "DLR5L15N36030", "lecture": "PRJLANR5L15B0269-PO717460"},
    )

    assert resp.status_code == 302
    assert resp.location == "http://localhost/lectures/an.15.269.PO717460/"

    resp = resp.follow()

    assert resp.status_code == 200
    assert "Lecture créée avec succès." in resp.text

    lecture = Lecture.get(chambre="an", session="15", num_texte=269, organe="PO717460")
    assert lecture.chambre == "an"
    assert lecture.titre == "1ère lecture"
    assert lecture.dossier_legislatif == "Sécurité sociale : loi de financement 2018"
def test_lecture_delete(app, dummy_lecture, dummy_amendements):
    from zam_repondeur.models import Amendement, DBSession, Lecture

    assert Lecture.exists(
        chambre=dummy_lecture.chambre,
        session=dummy_lecture.session,
        num_texte=dummy_lecture.num_texte,
        organe=dummy_lecture.organe,
    )
    assert DBSession.query(Amendement).count() == 2

    form = app.get("http://localhost/lectures/an.15.269.PO717460/"
                   ).forms["delete-lecture"]

    resp = form.submit()

    assert resp.status_code == 302
    assert resp.location == "http://localhost/lectures/"

    resp = resp.follow()

    assert resp.status_code == 200
    assert "Lecture supprimée avec succès." in resp.text

    assert not Lecture.exists(
        chambre=dummy_lecture.chambre,
        session=dummy_lecture.session,
        num_texte=dummy_lecture.num_texte,
        organe=dummy_lecture.organe,
    )
    assert DBSession.query(Amendement).count() == 0
Exemple #3
0
def create_or_update_lecture(dossier: Dossier, lecture_ref: LectureRef,
                             user: Optional[User]) -> bool:
    changed = False

    lecture_created = False
    lecture_updated = False

    texte = Texte.get_or_create_from_ref(lecture_ref.texte,
                                         lecture_ref.chambre)

    lecture = Lecture.get_from_ref(lecture_ref, dossier)

    if lecture is not None and lecture.texte is not texte:
        # We probably created the Lecture before a new Texte was adopted
        # by the commission. Time to update with the final one!
        TexteMisAJour.create(lecture=lecture, texte=texte)
        lecture_updated = True

    if lecture is None:
        lecture = Lecture.create_from_ref(lecture_ref, dossier, texte)
        LectureCreee.create(lecture=lecture, user=user)
        lecture_created = True

    if lecture_created or lecture_updated:
        changed = True

        # Make sure the lecture gets its primary key.
        DBSession.flush()

        # Enqueue tasks to fetch articles and amendements.
        huey.enqueue_on_transaction_commit(fetch_articles.s(lecture.pk))
        huey.enqueue_on_transaction_commit(fetch_amendements.s(lecture.pk))

    return changed
Exemple #4
0
    def post(self) -> Response:
        dossier = self._get_dossier()
        lecture = self._get_lecture(dossier)

        chambre = lecture.chambre.value
        num_texte = lecture.texte.numero
        titre = lecture.titre
        organe = lecture.organe

        # FIXME: use date_depot to find the right session?
        if lecture.chambre == Chambre.AN:
            session = "15"
        else:
            session = "2017-2018"

        if LectureModel.exists(chambre, session, num_texte, organe):
            self.request.session.flash(
                ("warning", "Cette lecture existe déjà..."))
        else:
            LectureModel.create(chambre, session, num_texte, titre, organe,
                                dossier.titre)
            self.request.session.flash(
                ("success", "Lecture créée avec succès."))

        resource = self.context[f"{chambre}.{session}.{num_texte}.{organe}"]
        return HTTPFound(location=self.request.resource_url(resource))
Exemple #5
0
def test_derouleur_urls_plf2019_2e_partie(texte_senat, dossier_plf):
    from zam_repondeur.fetch.senat.derouleur import derouleur_urls
    from zam_repondeur.models import Lecture

    texte_senat.numero = 146
    lecture = Lecture.create(
        chambre="senat",
        session="2018-2019",
        texte=texte_senat,
        partie=2,
        titre="Première lecture – Séance publique (2e partie)",
        organe="PO78718",
        dossier=dossier_plf,
    )

    urls = list(derouleur_urls(lecture))
    assert len(urls) > 1
    assert (
        urls[0] ==
        "https://www.senat.fr/enseance/2018-2019/146/liste_discussion_103427.json"
    )
    assert (
        urls[-1] ==
        "https://www.senat.fr/enseance/2018-2019/146/liste_discussion_103394.json"
    )
Exemple #6
0
def fetch_amendements_for_dossier(
    dossier_ref: DossierRef,
    chambre: Optional[str],
    num: Optional[int],
    settings: Dict[str, Any],
) -> None:
    dossier, _ = get_one_or_create(
        Dossier,
        an_id=dossier_ref.uid,
        create_kwargs=dict(titre=dossier_ref.titre, slug=dossier_ref.slug),
    )
    for lecture_ref in dossier_ref.lectures:
        texte_ref = lecture_ref.texte
        if chambre is not None and texte_ref.chambre.name.lower() != chambre:
            continue
        if num is not None and texte_ref.numero != num:
            continue
        texte, _ = get_one_or_create(
            Texte,
            type_=texte_ref.type_,
            chambre=texte_ref.chambre,
            legislature=texte_ref.legislature,
            session=texte_ref.session,
            numero=texte_ref.numero,
            date_depot=texte_ref.date_depot,
        )
        lecture = Lecture.create(
            phase=lecture_ref.phase,
            dossier=dossier,
            texte=texte,
            partie=lecture_ref.partie,
            organe=lecture_ref.organe,
            titre=lecture_ref.titre,
        )
        fetch_amendements_for_lecture(lecture, settings)
Exemple #7
0
def test_post_shared_tables_create_form(app, lecture_an, amendements_an,
                                        user_david):
    from zam_repondeur.models import DBSession, Lecture, SharedTable

    with transaction.manager:
        DBSession.add(user_david)

    resp = app.get(
        "/dossiers/plfss-2018/lectures/an.15.269.PO717460/boites/add",
        user=user_david)
    form = resp.forms["box-upsert"]
    form["titre"] = "Test table"
    resp = form.submit()

    assert resp.status_code == 302
    assert resp.location == ("https://zam.test"
                             "/dossiers/plfss-2018"
                             "/lectures/an.15.269.PO717460"
                             "/options#shared-tables")

    resp = resp.follow()
    assert resp.status_code == 200
    assert "Test table" in resp.text

    shared_table = (DBSession.query(SharedTable).filter(
        SharedTable.titre == "Test table").one())
    assert shared_table.slug == "test-table"
    assert shared_table.lecture.pk == lecture_an.pk

    # A dedicated event should be created.
    lecture_an = Lecture.get_by_pk(lecture_an.pk)  # refresh object
    assert len(lecture_an.events) == 1
    assert lecture_an.events[0].render_summary() == (
        "<abbr title='*****@*****.**'>David</abbr> "
        "a créé la boîte « Test table »")
Exemple #8
0
    def apply(self, lecture: Lecture) -> FetchResult:
        amendement = lecture.find_amendement(self.amendement_num)
        if amendement is None:
            return FetchResult.create(errored={self.amendement_num})

        article = self._get_article(lecture)
        parent = self._get_parent(lecture, article)

        if amendement.location.batch and amendement.article.pk != article.pk:
            BatchUnset.create(amendement=amendement, request=None)

        Source.update_rectif(amendement, self.rectif)
        Source.update_corps(amendement, self.corps)
        Source.update_expose(amendement, self.expose)
        Source.update_sort(amendement, self.sort)
        Source.update_attributes(
            amendement,
            article=article,
            parent=parent,
            position=self.position,
            tri_amendement=self.tri_amendement,
            id_discussion_commune=self.id_discussion_commune,
            id_identique=self.id_identique,
            matricule=self.matricule,
            groupe=self.groupe,
            auteur=self.auteur,
            mission_titre=self.mission_titre,
            mission_titre_court=self.mission_titre_court,
            date_depot=self.date_depot,
        )

        return FetchResult.create(fetched={self.amendement_num})
Exemple #9
0
def test_upload_liasse_missing_file(
        app, lecture_essoc2018_an_nouvelle_lecture_commission_fond,
        user_david):
    from zam_repondeur.models import Lecture

    resp = app.get(
        "/dossiers/etat-service-societe-confiance/lectures/an.15.806.PO744107/options",
        user=user_david,
    )
    form = resp.forms["import-liasse-xml"]
    resp = form.submit()

    assert resp.status_code == 302
    assert resp.location == ("https://zam.test/"
                             "dossiers/etat-service-societe-confiance/"
                             "lectures/an.15.806.PO744107/"
                             "options")

    resp = resp.follow()
    assert "Veuillez d’abord sélectionner un fichier" in resp.text

    # Check the update timestamp has NOT been updated.
    lecture = Lecture.get_by_pk(
        lecture_essoc2018_an_nouvelle_lecture_commission_fond.pk)
    assert lecture.events == []
Exemple #10
0
def test_upload_liasse_with_table(
        app, lecture_essoc2018_an_nouvelle_lecture_commission_fond,
        user_david):
    from zam_repondeur.models import Lecture

    resp = app.get("/lectures/an.15.806.PO744107/options", user=user_david)
    form = resp.forms["import-liasse-xml"]
    form["liasse"] = Upload(
        "liasse.xml", (SAMPLE_DATA / "liasse_with_table.xml").read_bytes())
    resp = form.submit()

    assert resp.status_code == 302
    assert resp.location == "https://zam.test/lectures/an.15.806.PO744107/amendements"

    resp = resp.follow()
    assert "3 nouveaux amendements récupérés (import liasse XML)." in resp.text

    lecture = Lecture.get(
        chambre=lecture_essoc2018_an_nouvelle_lecture_commission_fond.chambre,
        session_or_legislature=
        lecture_essoc2018_an_nouvelle_lecture_commission_fond.session,  # noqa
        num_texte=lecture_essoc2018_an_nouvelle_lecture_commission_fond.texte.
        numero,
        partie=None,
        organe=lecture_essoc2018_an_nouvelle_lecture_commission_fond.organe,
    )
    assert ("<table>\n<tbody>\n<tr>\n<td>Durée minimale de services"
            in lecture.amendements[1].corps)
    assert ("<table>\n<tbody>\n<tr>\n<td>Durée minimale de services"
            in lecture.amendements[0].expose)
Exemple #11
0
def test_upload_liasse_success(
        app, lecture_essoc2018_an_nouvelle_lecture_commission_fond,
        user_david):
    from zam_repondeur.models import DBSession, Lecture

    with transaction.manager:
        DBSession.add(user_david)

    resp = app.get(
        "/dossiers/etat-service-societe-confiance/lectures/an.15.806.PO744107/options",
        user=user_david,
    )
    form = resp.forms["import-liasse-xml"]
    form["liasse"] = Upload("liasse.xml",
                            (SAMPLE_DATA / "liasse.xml").read_bytes())
    resp = form.submit()

    assert resp.status_code == 302
    assert resp.location == ("https://zam.test/"
                             "dossiers/etat-service-societe-confiance/"
                             "lectures/an.15.806.PO744107/"
                             "amendements/")

    resp = resp.follow()
    assert "3 nouveaux amendements récupérés (import liasse XML)." in resp.text

    lecture = Lecture.get_by_pk(
        lecture_essoc2018_an_nouvelle_lecture_commission_fond.pk)
    assert lecture.events[0].render_summary() == (
        "<abbr title='*****@*****.**'>David</abbr> a importé "
        "une liasse XML : 3 nouveaux amendements récupérés.")
Exemple #12
0
def test_upload_liasse_missing_file(
        app, lecture_essoc2018_an_nouvelle_lecture_commission_fond,
        user_david):
    from zam_repondeur.models import Lecture

    resp = app.get("/lectures/an.15.806.PO744107/options", user=user_david)
    form = resp.forms["import-liasse-xml"]
    resp = form.submit()

    assert resp.status_code == 302
    assert resp.location == "https://zam.test/lectures/an.15.806.PO744107/options"

    resp = resp.follow()
    assert "Veuillez d’abord sélectionner un fichier" in resp.text

    # Check the update timestamp has NOT been updated.
    lecture = Lecture.get(
        chambre=lecture_essoc2018_an_nouvelle_lecture_commission_fond.chambre,
        session_or_legislature=
        lecture_essoc2018_an_nouvelle_lecture_commission_fond.session,  # noqa
        num_texte=lecture_essoc2018_an_nouvelle_lecture_commission_fond.texte.
        numero,
        partie=None,
        organe=lecture_essoc2018_an_nouvelle_lecture_commission_fond.organe,
    )
    assert lecture.events == []
Exemple #13
0
def test_upload_liasse_success(
        app, lecture_essoc2018_an_nouvelle_lecture_commission_fond,
        user_david):
    from zam_repondeur.models import Lecture

    resp = app.get("/lectures/an.15.806.PO744107/options", user=user_david)
    form = resp.forms["import-liasse-xml"]
    form["liasse"] = Upload("liasse.xml",
                            (SAMPLE_DATA / "liasse.xml").read_bytes())
    resp = form.submit()

    assert resp.status_code == 302
    assert resp.location == "https://zam.test/lectures/an.15.806.PO744107/amendements"

    resp = resp.follow()
    assert "3 nouveaux amendements récupérés (import liasse XML)." in resp.text

    lecture = Lecture.get(
        chambre=lecture_essoc2018_an_nouvelle_lecture_commission_fond.chambre,
        session_or_legislature=
        lecture_essoc2018_an_nouvelle_lecture_commission_fond.session,  # noqa
        num_texte=lecture_essoc2018_an_nouvelle_lecture_commission_fond.texte.
        numero,
        partie=None,
        organe=lecture_essoc2018_an_nouvelle_lecture_commission_fond.organe,
    )
    assert lecture.events[0].render_summary() == (
        "<abbr title='*****@*****.**'>[email protected]</abbr> a importé "
        "une liasse XML : 3 nouveaux amendements récupérés.")
Exemple #14
0
def test_post_form_already_exists(app, dummy_lecture):
    from zam_repondeur.models import Lecture

    assert Lecture.exists(chambre="an",
                          session="15",
                          num_texte=269,
                          organe="PO717460")

    # We cannot use form.submit() given the form is dynamic and does not
    # contain choices for lectures (dynamically loaded via JS).
    resp = app.post(
        "/lectures/add",
        {
            "dossier": "DLR5L15N36030",
            "lecture": "PRJLANR5L15B0269-PO717460"
        },
    )

    assert resp.status_code == 302
    assert resp.location == "http://localhost/lectures/an.15.269.PO717460/"

    resp = resp.follow()

    assert resp.status_code == 200
    assert "Cette lecture existe déjà..." in resp.text
Exemple #15
0
def test_derouleur_urls_and_mission_refs_plf2019_2e_partie(
        dossier_plf_2019, texte_plf_2019):
    from zam_repondeur.models import Lecture, Phase
    from zam_repondeur.services.fetch.missions import MissionRef
    from zam_repondeur.services.fetch.senat.derouleur import (
        derouleur_urls_and_mission_refs, )

    lecture = Lecture.create(
        phase=Phase.PREMIERE_LECTURE,
        texte=texte_plf_2019,
        partie=2,
        titre="Première lecture – Séance publique (2e partie)",
        organe="PO78718",
        dossier=dossier_plf_2019,
    )

    urls = list(derouleur_urls_and_mission_refs(lecture))
    assert len(urls) == 52
    assert urls[0] == (
        "https://www.senat.fr/enseance/2018-2019/146/liste_discussion_103414.json",
        MissionRef(
            titre="Mission Action et transformation publiques",
            titre_court="Action transfo.",
        ),
    )
    assert urls[1] == (
        "https://www.senat.fr/enseance/2018-2019/146/liste_discussion_103415.json",
        MissionRef(titre="Mission Action extérieure de l'État",
                   titre_court="Action ext."),
    )
    assert urls[-1] == (
        "https://www.senat.fr/enseance/2018-2019/146/liste_discussion_103394.json",
        MissionRef(titre="", titre_court=""),
    )
Exemple #16
0
def test_derouleur_urls_and_mission_refs_plf2020_2e_partie(
        dossier_plf_2020, texte_plf_2020):
    from zam_repondeur.models import Lecture, Phase
    from zam_repondeur.services.fetch.missions import MissionRef
    from zam_repondeur.services.fetch.senat.derouleur import (
        derouleur_urls_and_mission_refs, )

    lecture = Lecture.create(
        phase=Phase.PREMIERE_LECTURE,
        texte=texte_plf_2020,
        partie=2,
        titre="Première lecture – Séance publique (2e partie)",
        organe="PO78718",
        dossier=dossier_plf_2020,
    )

    urls = list(derouleur_urls_and_mission_refs(lecture))
    assert len(urls) == 50
    assert urls[0] == (
        "https://www.senat.fr/enseance/2019-2020/139/liste_discussion_103930.json",
        MissionRef(titre="", titre_court=""),
    )
    assert urls[1] == (
        "https://www.senat.fr/enseance/2019-2020/139/liste_discussion_103931.json",
        MissionRef(
            titre="Budget annexe - Contrôle et exploitation aériens",
            titre_court="Contrôle et exploitation aériens",
        ),
    )
    assert urls[-1] == (
        "https://www.senat.fr/enseance/2019-2020/139/liste_discussion_103979.json",
        MissionRef(titre="Mission Travail et emploi",
                   titre_court="Trav. emploi"),
    )
Exemple #17
0
def test_post_form_already_exists(
    app, texte_plfss2018_an_premiere_lecture, lecture_an, user_david
):
    from zam_repondeur.models import DBSession, Lecture

    assert Lecture.exists(
        chambre="an",
        session="15",
        texte=texte_plfss2018_an_premiere_lecture,
        partie=None,
        organe="PO717460",
    )

    # We cannot use form.submit() given the form is dynamic and does not
    # contain choices for lectures (dynamically loaded via JS).
    resp = app.post(
        "/lectures/add",
        {"dossier": "DLR5L15N36030", "lecture": "PRJLANR5L15B0269-PO717460-"},
        user=user_david,
    )

    assert resp.status_code == 302
    assert resp.location == "https://zam.test/lectures/"

    resp = resp.follow()

    assert resp.status_code == 200
    assert "Cette lecture existe déjà…" in resp.text

    DBSession.add(lecture_an)
    assert len(lecture_an.events) == 0
Exemple #18
0
def test_upload_liasse_with_table(
        app, lecture_essoc2018_an_nouvelle_lecture_commission_fond,
        user_david):
    from zam_repondeur.models import Lecture

    resp = app.get(
        "/dossiers/etat-service-societe-confiance/lectures/an.15.806.PO744107/options",
        user=user_david,
    )
    form = resp.forms["import-liasse-xml"]
    form["liasse"] = Upload(
        "liasse.xml", (SAMPLE_DATA / "liasse_with_table.xml").read_bytes())
    resp = form.submit()

    assert resp.status_code == 302
    assert resp.location == ("https://zam.test/"
                             "dossiers/etat-service-societe-confiance/"
                             "lectures/an.15.806.PO744107/"
                             "amendements/")

    resp = resp.follow()
    assert "3 nouveaux amendements récupérés (import liasse XML)." in resp.text

    lecture = Lecture.get_by_pk(
        lecture_essoc2018_an_nouvelle_lecture_commission_fond.pk)
    assert ("<table>\n<tbody>\n<tr>\n<td>Durée minimale de services"
            in lecture.amendements[1].corps)
    assert ("<table>\n<tbody>\n<tr>\n<td>Durée minimale de services"
            in lecture.amendements[0].expose)
Exemple #19
0
    def test_upload_adds_an_event(self, app, lecture_an, filename, user_david):
        from zam_repondeur.models import Lecture
        from zam_repondeur.models.events.lecture import ReponsesImportees

        self._upload_csv(app, filename, user=user_david)

        lecture = Lecture.get_by_pk(lecture_an.pk)  # refresh object
        events = {type(event): event for event in lecture.events}
        assert ReponsesImportees in events
Exemple #20
0
def test_post_form(app, lecture_an, lecture_an_url, article1_an, user_david):
    from zam_repondeur.models import Amendement, DBSession, Lecture

    # Initially, we only have one amendement (#135), with a response
    with transaction.manager:
        DBSession.add(lecture_an)
        lecture_an.texte.date_depot = datetime.utcnow().date() - timedelta(
            days=5)
        Amendement.create(lecture=lecture_an,
                          article=article1_an,
                          num=135,
                          position=1)
        assert lecture_an.events == []

    # No progress status by default.
    assert lecture_an.get_fetch_progress() == {}

    with setup_mock_responses(
            lecture=lecture_an,
            liste=read_sample_data("an/269/liste.xml"),
            amendements=(
                ("177", read_sample_data("an/269/177.xml")),
                ("270", read_sample_data("an/269/270.xml")),
                ("723", read_sample_data("an/269/723.xml")),
                ("135", read_sample_data("an/269/135.xml")),
                ("192", read_sample_data("an/269/192.xml")),
            ),
    ):

        # Then we ask for a refresh
        form = app.get(
            "/dossiers/plfss-2018/lectures/an.15.269.PO717460/journal/",
            user=user_david).forms["manual-refresh"]
        resp = form.submit()

    assert resp.status_code == 302
    assert resp.location == f"https://zam.test{lecture_an_url}/amendements/"

    resp = resp.follow()

    assert resp.status_code == 200

    lecture_an = Lecture.get_by_pk(lecture_an.pk)  # refresh object

    events = lecture_an.events
    assert len(events) == 1
    assert events[0].render_summary() == "4 nouveaux amendements récupérés."
    assert "Rafraîchissement des amendements en cours." in resp.text

    # Default progress status for dummy progress bar is set.
    assert lecture_an.get_fetch_progress() == {"current": 1, "total": 10}

    # If we fetch again the journal, the refresh button is not present anymore.
    resp = app.get("/dossiers/plfss-2018/lectures/an.15.269.PO717460/journal/",
                   user=user_david)
    assert resp.status_code == 200
    assert "manual-refresh" not in resp.forms
Exemple #21
0
def _do_upload_liasse_xml(context: LectureResource,
                          request: Request) -> Response:
    try:
        liasse_field = request.POST["liasse"]
    except KeyError:
        request.session.flash(
            ("warning", "Veuillez d’abord sélectionner un fichier"))
        return

    if liasse_field == b"":
        request.session.flash(
            ("warning", "Veuillez d’abord sélectionner un fichier"))
        return

    try:
        amendements = import_liasse_xml(liasse_field.file)
    except ValueError:
        request.session.flash(
            ("danger", "Le format du fichier n’est pas valide."))
        return

    if len(amendements) == 0:
        request.session.flash(
            ("warning", "Aucun amendement n’a été trouvé dans ce fichier."))
        return

    lecture = context.model()
    filtered_amendements = [
        amendement for amendement in amendements
        if amendement.chambre == lecture.chambre and amendement.session ==
        lecture.session and amendement.num_texte == lecture.num_texte
        and amendement.organe == lecture.organe
    ]
    ignored = len(amendements) - len(filtered_amendements)

    if len(filtered_amendements) == 0:
        amendement = amendements[0]
        other_lecture = Lecture(
            chambre=amendement.chambre,
            session=amendement.session,
            num_texte=amendement.num_texte,
            organe=amendement.organe,
        )
        request.session.flash(
            ("danger",
             f"La liasse correspond à une autre lecture ({other_lecture})."))
        return

    if ignored > 0:
        request.session.flash(
            ("warning",
             f"{ignored} amendements ignorés car non liés à cette lecture."))

    added, updated, unchanged = _add_or_update_amendements(
        filtered_amendements)
    assert added + updated + unchanged == len(filtered_amendements)
    _set_flash_messages(request, added, updated, unchanged)
Exemple #22
0
def test_fetch_all_commission(db):
    from zam_repondeur.models import Chambre, Dossier, Lecture, Phase, Texte, TypeTexte
    from zam_repondeur.services.fetch.senat.amendements import _fetch_all

    with transaction.manager:
        dossier = Dossier.create(
            senat_id="pjl17-583",
            titre="Liberté de choisir son avenir professionnel",
            slug="liberte-choisir-avenir-professionnel",
        )
        texte = Texte.create(
            type_=TypeTexte.PROJET,
            chambre=Chambre.SENAT,
            session=2017,
            numero=583,
            date_depot=date(2018, 6, 20),
        )
        lecture = Lecture.create(
            phase=Phase.PREMIERE_LECTURE,
            texte=texte,
            titre="Première lecture – Commissions",
            organe=None,
            dossier=dossier,
        )

    sample_data = read_sample_data("jeu_complet_commission_2017-2018_583.csv")

    responses.add(
        responses.GET,
        "https://www.senat.fr/amendements/commissions/2017-2018/583/jeu_complet_commission_2017-2018_583.csv",  # noqa
        body=sample_data,
        status=200,
    )

    items = _fetch_all(lecture)

    assert len(items) == 434

    assert items[0] == {
        "Nature ": "Amt",
        "Numéro ": "COM-1",
        "Subdivision ": "Article 40",
        "Alinéa": "36",
        "Auteur ": "M. FORISSIER, rapporteur",
        "Au nom de ": "",
        "Date de dépôt ": "2018-06-21",
        "Dispositif ":
        "<body><p>Alin&#233;a 36</p><p>Apr&#232;s le mot :</p><p>services</p><p>Ins&#233;rer les mots :</p><p>ou &#224; des partenariats</p><p></p></body>                                                                                                                                                                                                                ",  # noqa
        "Objet ":
        "<body><p>Cet amendement vise &#224; inclure parmi les d&#233;penses pouvant &#234;tre d&#233;duites de la contribution financi&#232;re annuelle, en plus des contrats de sous-traitance et de prestations, les <b>d&#233;penses aff&#233;rentes &#224; des partenariats</b> avec les entreprises adapt&#233;es, les Esat et les travailleurs handicap&#233;s ind&#233;pendants.</p><p>En effet, le nouveau mode de d&#233;duction des montants de ces contrats de la contribution annuelle risque de moins inciter les employeurs &#224; leur conclusion. D'o&#249; l'int&#233;r&#234;t d'&#233;largir cette d&#233;duction aux autres actions qu'ils sont susceptibles de mener aupr&#232;s des EA et des Esat notamment.</p></body>                                                                                                                                                                                                                                                                                                                                                                                                                                                         ",  # noqa
        "Sort ": "Adopté",
        "Url amendement ":
        "//www.senat.fr/amendements/commissions/2017-2018/583/Amdt_COM-1.html",  # noqa
        "Fiche Sénateur": "//www.senat.fr/senfic/forissier_michel14087w.html",
    }
Exemple #23
0
    def apply_changes(self, lecture: Lecture,
                      changes: CollectedChanges) -> FetchResult:
        result = FetchResult.create(
            fetched=changes.unchanged,
            errored=changes.errored,
            next_start_index=changes.next_start_index,
        )

        # Build amendement -> position map
        moved_amendements = {
            amendement: changes.position_changes[amendement.num]
            for amendement in lecture.amendements
            if amendement.num in changes.position_changes
        }

        # Reset positions first, so that we never have two with the same position
        # (which would trigger an integrity error due to the unique constraint)
        for amendement in moved_amendements:
            amendement.position = None
        DBSession.flush()

        # Create amendements in numerical order, because a "sous-amendement"
        # must always be created after its parent
        for create_action in sorted(changes.creates, key=attrgetter("num")):
            result += create_action.apply(lecture)

        # Update amendements
        for update_action in changes.updates:
            result += update_action.apply(lecture)

        # Apply new amendement positions
        for amendement, position in moved_amendements.items():
            if amendement.position != position:
                amendement.position = position

        DBSession.flush()

        # Was it the last batch?
        if changes.next_start_index is None:
            lecture.reset_fetch_progress()

        return result
def test_post_form(app, lecture_an, article1_an, user_david):
    from zam_repondeur.models import Amendement, Lecture

    # Initially, we only have one amendement (#135), with a response
    with transaction.manager:
        Amendement.create(lecture=lecture_an, article=article1_an, num=135, position=1)
        assert lecture_an.events == []

    with setup_mock_responses(
        lecture=lecture_an,
        liste=read_sample_data("an/269/liste.xml"),
        amendements=(
            ("177", read_sample_data("an/269/177.xml")),
            ("270", read_sample_data("an/269/270.xml")),
            ("723", read_sample_data("an/269/723.xml")),
            ("135", read_sample_data("an/269/135.xml")),
            ("192", read_sample_data("an/269/192.xml")),
        ),
    ) as mock_resp:

        mock_resp.add(
            responses.GET,
            "http://www.assemblee-nationale.fr/15/projets/pl0269.asp",
            body=(Path(__file__).parent / "sample_data" / "pl0269.html").read_text(
                "utf-8", "ignore"
            ),
            status=200,
        )

        # Then we ask for a refresh
        form = app.get("/lectures/an.15.269.PO717460/journal/", user=user_david).forms[
            "manual-refresh"
        ]
        resp = form.submit()

    assert resp.status_code == 302
    assert resp.location == "https://zam.test/lectures/an.15.269.PO717460/amendements"

    resp = resp.follow()

    assert resp.status_code == 200

    lecture_an = Lecture.get(
        chambre=lecture_an.chambre,
        session_or_legislature=lecture_an.session,
        num_texte=lecture_an.texte.numero,
        partie=None,
        organe=lecture_an.organe,
    )
    events = lecture_an.events
    assert len(events) == 2
    assert events[0].render_summary() == "Le contenu des articles a été récupéré."
    assert events[1].render_summary() == "4 nouveaux amendements récupérés."
    assert "Rafraichissement des amendements et des articles en cours." in resp.text
Exemple #25
0
    def test_an_commission(self):
        from zam_repondeur.models import Lecture

        lecture = Lecture(chambre="an",
                          session="15",
                          num_texte=269,
                          titre="bla bla",
                          organe="PO59048")
        assert (
            str(lecture) ==
            "Assemblée nationale, 15e législature, Commission des finances, texte nº 269"  # noqa
        )
Exemple #26
0
 def model(self, *options: Any) -> Lecture:
     lecture = Lecture.get(
         self.chambre,
         self.session_or_legislature,
         self.num_texte,
         self.partie,
         self.organe,
         *options,
     )
     if lecture is None:
         raise ResourceNotFound(self)
     return lecture
Exemple #27
0
def lecture_plf_2e_partie(dossier_plf_2019, texte_plf_2019):
    from zam_repondeur.models import Lecture, Phase

    with transaction.manager:
        return Lecture.create(
            phase=Phase.PREMIERE_LECTURE,
            texte=texte_plf_2019,
            partie=2,
            titre="Numéro lecture – Titre lecture sénat",
            organe="PO78718",
            dossier=dossier_plf_2019,
        )
def test_lecture_delete(app, lecture_an, amendements_an, zam_user):
    from zam_repondeur.models import Amendement, DBSession, Lecture

    assert zam_user.email.endswith("@zam.beta.gouv.fr")

    assert Lecture.exists(
        chambre=lecture_an.chambre,
        session=lecture_an.session,
        texte=lecture_an.texte,
        partie=None,
        organe=lecture_an.organe,
    )
    assert DBSession.query(Amendement).count() == 2

    resp = app.get("/lectures/an.15.269.PO717460/options", user=zam_user)
    form = resp.forms["delete-lecture"]

    resp = form.submit()

    assert resp.status_code == 302
    assert resp.location == "https://zam.test/lectures/"

    resp = resp.follow()

    assert resp.status_code == 302
    assert resp.location == "https://zam.test/lectures/add"

    resp = resp.follow()

    assert resp.status_code == 200
    assert "Lecture supprimée avec succès." in resp.text

    assert not Lecture.exists(
        chambre=lecture_an.chambre,
        session=lecture_an.session,
        texte=lecture_an.texte,
        partie=None,
        organe=lecture_an.organe,
    )
    assert DBSession.query(Amendement).count() == 0
Exemple #29
0
def lecture_an(db, dossier_plfss2018, texte_plfss2018_an_premiere_lecture):
    from zam_repondeur.models import Lecture, Phase

    with transaction.manager:
        lecture = Lecture.create(
            phase=Phase.PREMIERE_LECTURE,
            texte=texte_plfss2018_an_premiere_lecture,
            titre="Numéro lecture – Titre lecture",
            organe="PO717460",
            dossier=dossier_plfss2018,
        )

    return lecture
Exemple #30
0
    def test_senat_seance_publique(self):
        from zam_repondeur.models import Lecture

        lecture = Lecture(
            chambre="senat",
            session="2017-2018",
            num_texte=63,
            titre="bla bla",
            organe="PO78718",
        )
        assert str(
            lecture
        ) == "Sénat, session 2017-2018, Séance publique, texte nº 63"