def læs_lokation(lokation: str) -> GeometriObjekt: """Skab GeometriObjekt ud fra en brugerangivet lokationskoordinat""" lok = lokation.split() assert len(lok) in ( 2, 4, ), f"Lokation '{lokation}' matcher ikke format: 55.443322 [N] 12.345678 [Ø]." if len(lok) == 2: lok = [lok[0], "", lok[1], ""] try: e = float(lok[2].replace(",", ".")) n = float(lok[0].replace(",", ".")) except ValueError as ex: fire.cli.print( f"Ikke-numerisk lokationskoordinat anført: {lokation} ({ex})") sys.exit(1) # Håndter verdenshjørner Nn/ØøEe/VvWw/Ss if lok[3].upper() in ("S", "N"): lok = [lok[2], lok[3], lok[0], lok[1]] if lok[1].upper() == "S": n = -n if lok[3].upper() in ("W", "V"): e = -e # Håndter UTM zone 32 og geografiske koordinater ensartet e, n = normaliser_lokationskoordinat(e, n) go = GeometriObjekt() go.geometri = Point([e, n]) return go
def test_punkt_geometri(): p = Punkt() go = GeometriObjekt() go.geometri = Point([1, 2]) p.geometriobjekter.append(go) assert p.geometri.koordinater[0] == 1 assert p.geometri.koordinater[1] == 2
def test_indset_punkt_with_invalid_sagsevent_eventtype(firedb: FireDb, sag: Sag): p = Punkt() go = GeometriObjekt() go.geometri = Point([1, 1]) p.geometriobjekter.append(go) with pytest.raises(Exception, match="KOMMENTAR"): firedb.indset_punkt(Sagsevent(sag=sag, eventtype=EventType.KOMMENTAR), p)
def test_indset_punkt(firedb: FireDb, sag: Sag): p = Punkt() go = GeometriObjekt() go.geometri = Point([1, 1]) p.geometriobjekter.append(go) firedb.indset_sagsevent( Sagsevent( sag=sag, sagseventinfos=[ SagseventInfo(beskrivelse="Testindsættelse af et punkt") ], eventtype=EventType.PUNKT_OPRETTET, punkter=[p], ))
def test_unit_tilknyt_landsnumre_fejl_punkttyper_exceptions(dummydb, mocker): """ Test at der er smides en exception ved ugyldige FikspunktsTyper. """ pktid = fire.uuid() pit_landsnr = PunktInformationType(name="IDENT:landsnr") mocker.patch("fire.api.FireDb.hent_punktinformationtype", return_value=pit_landsnr) mocker.patch("fire.api.FireDb._opmålingsdistrikt_fra_punktid", return_value=[("K-63", pktid)]) mocker.patch( "fire.api.FireDb._løbenumre_i_distrikt", return_value=[str(i).zfill(5) for i in range(1, 9)], ) punkter = [ Punkt( id=pktid, geometriobjekter=[GeometriObjekt(geometri=Point((56.15, 10.20)))]) ] fikspunktstyper = [FikspunktsType.VANDSTANDSBRÆT] with pytest.raises(NotImplementedError): dummydb.tilknyt_landsnumre(punkter, fikspunktstyper) fikspunktstyper = ["IKKE_EN_FIKSPUNKSTYPE"] with pytest.raises(ValueError): dummydb.tilknyt_landsnumre(punkter, fikspunktstyper)
def test_unit_tilknyt_landsnumre_har_landsnr(dummydb, mocker): """ Test at punkter der allerede har et landsnummer frasorteres. """ pktid = fire.uuid() pit_landsnr = PunktInformationType(name="IDENT:landsnr") mocker.patch("fire.api.FireDb.hent_punktinformationtype", return_value=pit_landsnr) mocker.patch("fire.api.FireDb._opmålingsdistrikt_fra_punktid", return_value=[("K-63", pktid)]) mocker.patch( "fire.api.FireDb._løbenumre_i_distrikt", return_value=[str(i).zfill(5) for i in range(1, 9)], ) punkter = [ Punkt( id=pktid, geometriobjekter=[GeometriObjekt(geometri=Point((56.15, 10.20)))], punktinformationer=[ PunktInformation(infotype=pit_landsnr, tekst="K-63-00001") ], ) ] fikspunktstyper = [FikspunktsType.GI] landsnumre = dummydb.tilknyt_landsnumre(punkter, fikspunktstyper) assert len(landsnumre) == 0
def test_unit_tilknyt_landsnumre_flere_typer(dummydb, mocker): """ Test løbenummerudvælgelse for flere typer fikspunktpunkter i samme kald. """ punkt_ider = [fire.uuid() for _ in range(5)] se = (("K-63", pid) for pid in punkt_ider) mocker.patch( "fire.api.FireDb.hent_punktinformationtype", return_value=PunktInformationType(name="IDENT:landsnr"), ) mocker.patch("fire.api.FireDb._opmålingsdistrikt_fra_punktid", return_value=se) mocker.patch( "fire.api.FireDb._løbenumre_i_distrikt", return_value=[], ) punkter = [ Punkt( id=pktid, geometriobjekter=[GeometriObjekt(geometri=Point((56.15, 10.20)))]) for pktid in punkt_ider ] fikspunktstyper = [ FikspunktsType.GI, FikspunktsType.MV, FikspunktsType.HØJDE, FikspunktsType.JESSEN, FikspunktsType.HJÆLPEPUNKT, ] print(fikspunktstyper) print(punkter) landsnumre = dummydb.tilknyt_landsnumre(punkter, fikspunktstyper) assert len(landsnumre) == 5 forventede_landsnumre = [ "K-63-00001", "K-63-00011", "K-63-09001", "K-63-81001", "K-63-90001", ] for landsnr, forventet in zip(landsnumre, forventede_landsnumre): assert landsnr.tekst == forventet
def test_unit_tilknyt_landsnumre_gi(dummydb, mocker): """ Test løbenummerudvælgelse for GI-punkter hvor der er løbenumrene befinder sig i to intervaller. Specifikt testes om overgangen fra det første interval til det andet forløber som det skal. """ punkt_ider = [fire.uuid() for _ in range(4)] se = (("K-63", pid) for pid in punkt_ider) mocker.patch( "fire.api.FireDb.hent_punktinformationtype", return_value=PunktInformationType(name="IDENT:landsnr"), ) mocker.patch("fire.api.FireDb._opmålingsdistrikt_fra_punktid", return_value=se) mocker.patch( "fire.api.FireDb._løbenumre_i_distrikt", return_value=[str(i).zfill(5) for i in range(1, 9)], ) punkter = [ Punkt( id=pktid, geometriobjekter=[GeometriObjekt(geometri=Point((56.15, 10.20)))]) for pktid in punkt_ider ] fikspunktstyper = [ FikspunktsType.GI, FikspunktsType.GI, FikspunktsType.GI, FikspunktsType.GI, ] print(fikspunktstyper) print(punkter) landsnumre = dummydb.tilknyt_landsnumre(punkter, fikspunktstyper) assert len(landsnumre) == 4 forventede_landsnumre = [ "K-63-00009", "K-63-00010", "K-63-00801", "K-63-00802", ] for landsnr, forventet in zip(landsnumre, forventede_landsnumre): assert landsnr.tekst == forventet
def test_geometriobjekt_afregistrering(firedb: FireDb, sag: Sag): """ Test at forudgående geometrier afregistreres korrekt ved indsættelse af ny. """ p = firedb.hent_punkt("SKEJ") n = len(p.geometriobjekter) go = GeometriObjekt() go.geometri = Point([10.17983, 56.18759]) go.punkt = p firedb.indset_sagsevent( Sagsevent( sag=sag, sagseventinfos=[SagseventInfo(beskrivelse="Opdater geometri")], eventtype=EventType.PUNKT_OPRETTET, geometriobjekter=[go], )) geom = p.geometriobjekter assert n + 1 == len(p.geometriobjekter) assert geom[-2].registreringtil == geom[-1].registreringfra assert geom[-2].sagseventtilid == geom[-1].sagseventfraid
def test_luk_punkt( firedb: FireDb, punkt: Punkt, sagsevent: Sagsevent, observationer: List[Observation], koordinat: Koordinat, punktinformationtype: PunktInformationType, ): # byg et punkt der har tilknyttet geometri, koordinat, # punktinfo og observationer geometri = GeometriObjekt(punkt=punkt, geometri=Point([10, 55]), sagsevent=sagsevent) firedb.session.add(geometri) observationer[0].opstillingspunkt = punkt observationer[1].sigtepunkt = punkt koordinat.punkt = punkt punkt.punktinformationer = [ PunktInformation(infotype=punktinformationtype, sagsevent=sagsevent) ] firedb.session.commit() firedb.luk_punkt(punkt, sagsevent) assert punkt.registreringtil is not None assert punkt.sagsevent.eventtype == EventType.PUNKT_NEDLAGT assert punkt.sagseventtilid == sagsevent.id assert geometri.registreringtil is not None assert geometri.sagsevent.eventtype == EventType.PUNKT_NEDLAGT for koordinat in punkt.koordinater: assert koordinat.registreringtil is not None assert koordinat.sagsevent.eventtype == EventType.PUNKT_NEDLAGT assert koordinat.sagseventtilid == sagsevent.id for punktinfo in punkt.punktinformationer: assert punktinfo.registreringtil is not None assert punktinfo.sagsevent.eventtype == EventType.PUNKT_NEDLAGT assert punktinfo.sagseventtilid == sagsevent.id for observation in chain(punkt.observationer_fra, punkt.observationer_til): assert observation.registreringtil is not None assert observation.sagsevent.eventtype == EventType.PUNKT_NEDLAGT assert observation.sagseventtilid == sagsevent.id with pytest.raises(TypeError): firedb.luk_punkt(999)
def test_unit_tilknyt_landsnumre(dummydb, mocker): """ Test at løbenumre tildeles korrekt med afsæt i allerede tildelte løbenumre. """ punkt_ider = [fire.uuid() for _ in range(3)] se = (("K-63", pid) for pid in punkt_ider) mocker.patch( "fire.api.FireDb.hent_punktinformationtype", return_value=PunktInformationType(name="IDENT:landsnr"), ) mocker.patch("fire.api.FireDb._opmålingsdistrikt_fra_punktid", return_value=se) mocker.patch( "fire.api.FireDb._løbenumre_i_distrikt", return_value=["09001", "09002", "09003"], ) punkter = [ Punkt( id=pktid, geometriobjekter=[GeometriObjekt(geometri=Point((56.15, 10.20)))]) for pktid in punkt_ider ] fikspunktstyper = [ FikspunktsType.HØJDE, FikspunktsType.HØJDE, FikspunktsType.HØJDE, ] print(fikspunktstyper) print(punkter) landsnumre = dummydb.tilknyt_landsnumre(punkter, fikspunktstyper) assert len(landsnumre) == 3 for i, landsnummer in enumerate(landsnumre, 4): assert landsnummer.tekst == f"K-63-0900{i}"
def ilæg_nye_punkter(projektnavn: str, sagsbehandler: str, **kwargs) -> None: """Registrer nyoprettede punkter i databasen""" er_projekt_okay(projektnavn) sag = find_sag(projektnavn) sagsgang = find_sagsgang(projektnavn) fire.cli.print(f"Sags/projekt-navn: {projektnavn} ({sag.id})") fire.cli.print(f"Sagsbehandler: {sagsbehandler}") # Opbyg oversigt over nyetablerede punkter nyetablerede = find_faneblad(projektnavn, "Nyetablerede punkter", arkdef.NYETABLEREDE_PUNKTER) n = nyetablerede.shape[0] if n == 0: fire.cli.print("Ingen nyetablerede punkter at registrere") return landsnummer_pit = fire.cli.firedb.hent_punktinformationtype( "IDENT:landsnr") beskrivelse_pit = fire.cli.firedb.hent_punktinformationtype( "ATTR:beskrivelse") bemærkning_pit = fire.cli.firedb.hent_punktinformationtype( "ATTR:bemærkning") h_over_terræn_pit = fire.cli.firedb.hent_punktinformationtype( "AFM:højde_over_terræn") attr_gi_pit = fire.cli.firedb.hent_punktinformationtype("ATTR:GI_punkt") attr_mv_pit = fire.cli.firedb.hent_punktinformationtype("ATTR:MV_punkt") attr_højde_pit = fire.cli.firedb.hent_punktinformationtype( "ATTR:højdefikspunkt") attr_vandstand_pit = fire.cli.firedb.hent_punktinformationtype( "ATTR:vandstandsmåler") assert landsnummer_pit is not None, "IDENT:landsnr ikke fundet i database" assert beskrivelse_pit is not None, "ATTR:beskrivelse ikke fundet i database" assert bemærkning_pit is not None, "ATTR:bemærkning ikke fundet i database" assert h_over_terræn_pit is not None, "AFM:højde_over_terræn ikke fundet i database" assert attr_gi_pit is not None, "ATTR:GI_punkt ikke fundet i database" assert attr_mv_pit is not None, "ATTR:MV_punkt ikke fundet i database" assert attr_højde_pit is not None, "ATTR:højdefikspunkt ikke fundet i database" assert attr_vandstand_pit is not None, "ATTR:vandstandsmåler ikke fundet i database" punkter = {} fikspunktstyper = [] punktinfo = [] # Opret punkter fire.cli.print(f"Behandler punkter") # Index frasorterer automatisk blanke linjer og er dermed mere robust. # Bemærkes, at felter med usynlige tegn som mellemrum IKKE resulterer # i en tom linje og en sådan vil fremtvinge en fejl pga ugyldigt input for i in nyetablerede.index: # Et tomt tekstfelt kan repræsenteres på en del forskellige måder... # Punkter udstyret med uuid er allerede registrerede if str(nyetablerede.uuid[i]) not in ["", "None", "nan"]: continue lokation = normaliser_lokationskoordinat(nyetablerede["Øst"][i], nyetablerede["Nord"][i], "DK") # Skab nyt punktobjekt punkter[i] = Punkt( id=uuid(), geometriobjekter=[GeometriObjekt(geometri=Point(lokation))], ) try: fikspunktstype = FIKSPUNKTSYPER[nyetablerede["Fikspunktstype"] [i].upper()] except KeyError: fire.cli.print( f"FEJL: '{nyetablerede['Fikspunktstype'][i]}' er ikke en gyldig fikspunktsype! Vælg mellem GI, MV, HØJDE, JESSEN og VANDSTANDSBRÆT", bg="red", bold=True, ) sys.exit(1) fikspunktstyper.append(fikspunktstype) # sagsevent for punkter er = "er" if len(punkter) > 1 else "" sagsevent_punkter = Sagsevent( sag=sag, eventtype=EventType.PUNKT_OPRETTET, sagseventinfos=[ SagseventInfo( beskrivelse=f"Oprettelse af punkt{er} ifm. {projektnavn}", ) ], punkter=list(punkter.values()), ) fire.cli.firedb.indset_sagsevent(sagsevent_punkter, commit=False) fire.cli.firedb.session.flush() # hvis noget ikke virker får vi fejl her! # Generer dokumentation til fanebladet "Sagsgang" sagsgangslinje = { "Dato": sagsevent_punkter.registreringfra, "Hvem": sagsbehandler, "Hændelse": "punktoprettelse", "Tekst": sagsevent_punkter.sagseventinfos[0].beskrivelse, "uuid": sagsevent_punkter.id, } sagsgang = sagsgang.append(sagsgangslinje, ignore_index=True) # Opret punktinfo fire.cli.print(f"Behandler punktinformationer") for i, punkt in punkter.items(): # Tilføj punktets højde over terræn som punktinformation, hvis anført try: ΔH = float(nyetablerede["Højde over terræn"][i]) except (TypeError, ValueError): ΔH = 0 if math.isnan(ΔH): ΔH = 0.0 if not pd.isna(nyetablerede["Højde over terræn"][i]): pi_h = PunktInformation( infotype=h_over_terræn_pit, punkt=punkt, tal=ΔH, ) punktinfo.append(pi_h) # Tilføj punktets afmærkning som punktinformation, selv hvis ikke anført afm_id = 4999 # AFM:4999 = "ukendt" afm_ids = { "ukendt": 4999, "bolt": 2700, "lodret bolt": 2701, "skruepløk": 2950, "ingen": 5998, } if not pd.isna(nyetablerede["Afmærkning"][i]): # Afmærkningsbeskrivelse afm = str(nyetablerede["Afmærkning"][i]).lower() # Første ord i afmærkningsbeskrivelsen afm_første = afm.split()[0].rstrip(":;,.- ").lstrip("afm:") if afm_første.isnumeric(): afm_id = int(afm_første) else: afm_id = afm_ids.get(afm, 4999) afmærkning_pit = fire.cli.firedb.hent_punktinformationtype( f"AFM:{afm_id}") if afmærkning_pit is None: afm_id = 4999 afmærkning_pit = fire.cli.firedb.hent_punktinformationtype( "AFM:4999") beskrivelse = (afmærkning_pit.beskrivelse.replace( "-\n", "").replace("\n", " ").rstrip(".").strip()) if afm_id == 4999: fire.cli.print( f"ADVARSEL: Nyoprettet punkt index {i} har ingen gyldig afmærkning anført", fg="red", bg="white", bold=True, ) # Grundet den lidt kluntede løsning med AFM:nnnn punktinfo er fx AFM:2700 (bolt) # registreret som en tekst-punktinformation (frem for flag, som ville være den # ideelle løsning) og tekst attributten skal derfor udfyldes. Vi bruger # tekstnøgle til afm_ids. afm_txts = {v: k for k, v in afm_ids.items()} punktinfo.append( PunktInformation( infotype=afmærkning_pit, punkt=punkt, tekst=afm_txts[afm_id].capitalize(), )) # Tilføj punktbeskrivelsen som punktinformation, hvis anført beskrivelse = nyetablerede["Beskrivelse"][i] if pd.isna(beskrivelse) or beskrivelse == "": navn = nyetablerede["Foreløbigt navn"][i] fire.cli.print( f"FEJL: Beskrivelse for punkt '{navn}' ikke angivet!", fg="white", bg="red", bold=True, ) fire.cli.firedb.session.rollback() raise SystemExit punktinfo.append( PunktInformation( infotype=beskrivelse_pit, punkt=punkt, tekst=beskrivelse, )) # Tilknyt regionskode til punktet punktinfo.append(opret_region_punktinfo(punkt)) # Tilknyt ATTR:bemærkning punktinfo.append( PunktInformation( infotype=bemærkning_pit, punkt=punkt, tekst=f"Nyetb. {datetime.now().year} {sagsbehandler}", )) # tilknyt diverse punktinfo baseret på fikspunktstypen gi_punkter = [] for punkt, fikspunktstype in zip(punkter.values(), fikspunktstyper): if fikspunktstype == FikspunktsType.GI: gi_punkter.append(punkt) punktinfo.append( PunktInformation(infotype=attr_gi_pit, punkt=punkt)) if fikspunktstype == FikspunktsType.HØJDE: punktinfo.append( PunktInformation(infotype=attr_højde_pit, punkt=punkt)) if fikspunktstype == FikspunktsType.MV: punktinfo.append( PunktInformation(infotype=attr_mv_pit, punkt=punkt)) if fikspunktstype == FikspunktsType.VANDSTANDSBRÆT: punktinfo.append( PunktInformation(infotype=attr_vandstand_pit, punkt=punkt)) # Tilknyt G.I-numre gi_identer = fire.cli.firedb.tilknyt_gi_numre(gi_punkter) punktinfo.extend(gi_identer) # Tilknyt landsnumre til punkter landsnumre = dict( zip( punkter.keys(), fire.cli.firedb.tilknyt_landsnumre(punkter.values(), fikspunktstyper), )) punktinfo.extend(landsnumre.values()) # sagsevent for punktinfo sagsevent_punktinfo = Sagsevent( sag=sag, eventtype=EventType.PUNKTINFO_TILFOEJET, sagseventinfos=[ SagseventInfo( beskrivelse=f"Oprettelse af punktinfo ifm. {projektnavn}", ) ], punktinformationer=punktinfo, ) fire.cli.firedb.indset_sagsevent(sagsevent_punktinfo, commit=False) fire.cli.firedb.session.flush() # hvis noget ikke virker får vi fejl her! # Generer dokumentation til fanebladet "Sagsgang" sagsgangslinje = { "Dato": sagsevent_punktinfo.registreringfra, "Hvem": sagsbehandler, "Hændelse": "punktinfoindsættelse", "Tekst": sagsevent_punktinfo.sagseventinfos[0].beskrivelse, "uuid": sagsevent_punktinfo.id, } sagsgang = sagsgang.append(sagsgangslinje, ignore_index=True) # Opdater regneark for k in punkter.keys(): nyetablerede.at[k, "uuid"] = punkter[k].id nyetablerede.at[k, "Landsnummer"] = landsnumre[k].tekst # Drop numerisk index nyetablerede = nyetablerede.reset_index(drop=True) # Forbered resultater til resultatregneark resultater = {"Sagsgang": sagsgang, "Nyetablerede punkter": nyetablerede} spørgsmål = click.style("Du indsætter nu ", fg="white", bg="red") spørgsmål += click.style(f"{len(punkter)} punkter ", fg="white", bg="red", bold=True) spørgsmål += click.style(f"i ", fg="white", bg="red") spørgsmål += click.style(f"{fire.cli.firedb.db}", fg="white", bg="red", bold=True) spørgsmål += click.style("-databasen - er du sikker?", fg="white", bg="red") if bekræft(spørgsmål): # Indsæt rækker i database og skriv resultater til regneark fire.cli.firedb.session.commit() if skriv_ark(projektnavn, resultater): fire.cli.print( f"Punkter oprettet. Resultater skrevet til '{projektnavn}.xlsx'" ) else: fire.cli.firedb.session.rollback()
def test_indset_punkt(firedb: FireDb, sag: Sag): p = Punkt() go = GeometriObjekt() go.geometri = Point([1, 1]) p.geometriobjekter.append(go) firedb.indset_punkt(Sagsevent(sag=sag), p)