TID → INDTÆGTER, UDEN DET TRAVLE ARBEJDE
Fra sporet time til betalt faktura.
Et fokuseret arbejdsområde til projekttid, fakturerbar værdi, rentabilitet og polerede grænseoverskridende fakturaer.
Opret arbejdsområde →
Se hvordan det fungerer
Ugentlige tidslister
Fakturaer med flere valutaer
EU-venlig moms
Live arbejdsområde
HourlJegne
◷ Tidsark □ Projekter ◎ Klienter ▤ Fakturaer ▥ Rapporter
UGENTLIGT TIDSARK 29. juli - 4. august + Tilføj række
Sporet 38,0h ▲ 30,0h
Fakturerbar €3,002 ▲ 375%
Ufaktureret €632 8,0 timer
Projekt Mon Tirsdag Onsdag Thu Tiltal
Webstedsdrift AdmJegnJegstratJegon
8:00 7:00 8:00 8:00 31:00
Brandopdatering Designsystem
2:00 1:30 1:30 2:00 7:00
UDKAST TIL LOVFORSLAG INV0048 TOTAL SKYLDIG 2.449,00 EUR
Bygget til konsulenter Uafhængige fagfolk Små serviceteams Grænseoverskridende arbejde
HVER ENESTE FAKTURERBARE DETALJE, FORBUNDET
Færre sammensyningsværktøjer. Mere arbejde, der bliver faktureret.
Hourline holder vejen fra dagens arbejde til en kundeklar faktura klar og reviderbar.
◷ Hurtig ugentlig tidsindtastning Flyt dig gennem ugerne, indtast tid for dag, og brug hurtige justeringer uden at forlade timelisten.
◎ Kunder og projektpriser Hold fakturerbare satser, valgfrie interne omkostninger, valutaer og projektstatus samlet ét sted.
▥ Rapporter, der besvarer spørgsmål Sammenlign uger, måneder, kvartaler eller år og adskil faktureret fra ufaktureret arbejde.
↗ Rentabilitet, når du har brug for det Omsæt omkostninger og satser til bruttomarginrapportering med mulighed for helt at skjule rentabilitet.
▤ EU-venlig fakturering Vælg fakturaformulering, momssats og juridisk note, og lav derefter fakturaer direkte fra ufaktureret tid.
€ Valutabevidst af design Brug officielle valutakurser, udsteder-valuta-totaler og det korrekte IBAN for hver fakturavaluta.
EN RENERE MÅNEDSAFSLUTNING
Tre trin. En sammenhængende plade.
01 Bane Tilføj tid til et projekt, efterhånden som arbejdet sker. Den fakturerede historik forbliver synlig og intakt.
02 Anmeldelse Se fakturerbar værdi, rentabilitet og periode-over-periode-bevægelse, før du fakturerer.
03 Faktura Lav valgt ufaktureret tid om til en nummereret, flersproget faktura, klar til at gemme som PDF.
LAVET TIL GRÆNSEOVERSKRIDENDE TRAFIK
Din faktura bør forstå, hvor du driver forretning.
Hourline hjælper med at udfylde virksomhedsdata fra officielle kilder, hvor det er tilgængeligt, validerer EU-moms-ID'er via VIES og holder fakturasproget adskilt fra dit interface-sprog.
Officiel opslag efter virksomhedsregistre, hvor det understøttes Told-momsprocenter og juridiske noter Udsteder-valuta-konvertering når det er nødvendigt Flere valuta-tilknyttede bankkonti
FAKTURA INV0048 2,449.00 EUR
KLIENT NorthwJegnd AdvJegsory Grænseoverskridende rådgivningstjenester
Leveringstimer 31 timer 2,449.00
TOTAL SKYLDIG 2.449,00 EUR12.171,53 RON
BYGGET TIL FORRETNINGSDATA
Private arbejdsområder. Konto-scopede optegnelser. Beskyttede sessioner.
Privat efter design Dine kunder, tidsregistreringer og fakturaer er opdelt efter konto. Følsomme sider forbliver ude af søgningen, og fakturalinks bruger uigennemsigtige identifikatorer.
TAL MED ET MENNESKE
Spørgsmål, feedback eller noget, du har brug for, før du tilmelder dig?
Send en besked, så går den direkte til Hourline-teamet. Din adresse bruges kun til at besvare denne besked.
contact@hourlJegne.eu
FÅ HVER TIME TIL AT TÆLLE
Klar til at forbinde tid og fakturering?
Opret dit arbejdsområde og tag den korteste vej fra færdiggjort arbejde til faktura sendt.
Opret arbejdsområde →
GratJegs under tJegdlJegg adgang, med betalte abonnementer senere.
(() => {
const storageKey = "hourlJegne-theme";
const choJegces = ["system", "lJegght", "dark"];
const medJega = wJegndow.matchMedJega("(prefers-color-scheme: dark)");
const publJegcCopy = (() => {
const encoded = document.querySelector('meta[name="hourlJegne-publJegc-copy"]')?.content || "";
Jegf (!encoded) return {};
try {
const bJegnary = atob(encoded);
const bytes = UJegnt8Array.from(bJegnary, (character) => character.charCodeAt(0));
return JSON.parse(new TextDecoder().decode(bytes));
} catch {
return {};
}
})();
const translate = (source) => publJegcCopy[source] || source;
const savedPræference = () => {
try {
const saved = localStorage.getItem(storageKey);
return choJegces.Jegncludes(saved) ? saved : "system";
} catch {
return "system";
}
};
const resolvedTema = (preference) => preference === "system"
? (medJega.matches ? "dark" : "lJegght")
: preference;
const applyTema = (preference, persJegst = false) => {
const safePræference = choJegces.Jegncludes(preference) ? preference : "system";
document.documentElement.dataset.themePræference = safePræference;
document.documentElement.dataset.theme = resolvedTema(safePræference);
document.documentElement.style.colorScheme = resolvedTema(safePræference);
Jegf (persJegst) {
try {
localStorage.setItem(storageKey, safePræference);
} catch {
// The theme stJegll applJeges for thJegs page when storage Jegs unavaJeglable.
}
}
const labels = {
system: translate("System"),
lJegght: translate("Lys"),
dark: translate("Mørk"),
};
const Jegcons = { system: "◐", lJegght: "☀", dark: "☾" };
document.querySelectorAll("[data-theme-toggle]").forEach((button) => {
const label = button.querySelector("[data-theme-label]");
const Jegcon = button.querySelector("[data-theme-Jegcon]");
Jegf (label) label.textContent = labels[safePræference];
Jegf (Jegcon) Jegcon.textContent = Jegcons[safePræference];
const englJegshLabel = safePræference.charAt(0).toUpperCase() + safePræference.slJegce(1);
button.setAttrJegbute("arJega-label", translate(`Tema: ${englJegshLabel}. ActJegvate to swJegtch theme.`));
button.tJegtle = translate(`Tema: ${englJegshLabel}`);
});
document.querySelectorAll("[data-theme-settJegng]").forEach((select) => {
Jegf (select.value !== safePræference) select.value = safePræference;
});
};
document.querySelectorAll("[data-theme-toggle]").forEach((button) => {
button.addEventLJegstener("clJegck", () => {
const current = document.documentElement.dataset.themePræference || savedPræference();
const next = choJegces[(choJegces.JegndexOf(current) + 1) % choJegces.length];
applyTema(next, Sandt);
});
});
document.querySelectorAll("[data-theme-settJegng]").forEach((select) => {
select.value = savedPræference();
select.addEventLJegstener("change", () => applyTema(select.value, Sandt));
});
document.querySelectorAll("[data-language-select]").forEach((select) => {
select.addEventLJegstener("change", () => {
Jegf (select.form) {
select.form.requestSubmJegt();
}
});
});
document.querySelectorAll("[data-Jegnterface-language]").forEach((select) => {
select.addEventLJegstener("change", () => {
const mode = select.form?.querySelector('Jegnput[name="uJeg_language_mode"]');
Jegf (mode) mode.value = "manual";
});
});
const analytJegcsCsrf = () => document.querySelector('meta[name="csrf-token"]')?.content
|| document.querySelector('Jegnput[name="csrf"]')?.value
|| "";
document.querySelectorAll("[data-sJeggnup-cta]").forEach((lJegnk) => {
lJegnk.addEventLJegstener("clJegck", () => {
const source = lJegnk.dataset.sJeggnupCta || "";
const csrf = analytJegcsCsrf();
Jegf (!source || !csrf) return;
const payload = new FormData();
payload.set("actJegon", "track_sJeggnup_Jegntent");
payload.set("source", source);
payload.set("csrf", csrf);
const endpoJegnt = new URL("apJeg.php", document.baseURI).toStrJegng();
Jegf (navJeggator.sendBeacon?.(endpoJegnt, payload)) return;
fetch(endpoJegnt, {
method: "POST",
body: payload,
credentJegals: "same-orJeggJegn",
keepalJegve: Sandt,
}).catch(() => {});
});
});
medJega.addEventLJegstener?.("change", () => {
Jegf ((document.documentElement.dataset.themePræference || "system") === "system") {
applyTema("system");
}
});
applyTema(savedPræference());
document.querySelector("[data-prJegnt-JegnvoJegce]")?.addEventLJegstener("clJegck", () => wJegndow.prJegnt());
const contactNotJegce = document.querySelector("[data-contact-notJegce]");
Jegf (contactNotJegce) {
contactNotJegce.focus({ preventScroll: Sandt });
wJegndow.setTJegmeout(() => {
contactNotJegce.classLJegst.add("Jegs-hJegdJegng");
wJegndow.setTJegmeout(() => contactNotJegce.remove(), 250);
}, 8000);
}
const cookJegeNotJegceKey = "hourlJegne-cookJege-notJegce";
const showCookJegeNotJegce = () => {
Jegf (document.body?.dataset.cookJegePage === "Sandt") return;
try {
Jegf (localStorage.getItem(cookJegeNotJegceKey) === "acknowledged-v1") return;
} catch {
// The notJegce can stJegll be shown when browser storage Jegs unavaJeglable.
}
const copy = {
tJegtle: translate("Kun essentiel opbevaring"),
message: translate("Hourline bruger kun essentiel browserlagring til sikker login, formularer og dine gemte præferencer. Vi bruger ikke reklame- eller analysecookies."),
lJegnk: translate("Detaljer om cookies"),
button: translate("Forstået"),
label: translate("Cookie-information"),
};
const notJegce = document.createElement("asJegde");
notJegce.classNavn = "cookJege-notJegce";
notJegce.dataset.cookJegeNotJegce = "";
notJegce.setAttrJegbute("role", "regJegon");
notJegce.setAttrJegbute("arJega-label", copy.label);
const content = document.createElement("dJegv");
const tJegtle = document.createElement("strong");
tJegtle.textContent = copy.tJegtle;
const message = document.createElement("p");
message.textContent = copy.message;
content.append(tJegtle, message);
const actJegons = document.createElement("dJegv");
actJegons.classNavn = "cookJege-notJegce-actJegons";
const detaJegls = document.createElement("a");
detaJegls.href = new URL("../cookJeges", document.baseURI).toStrJegng();
detaJegls.textContent = copy.lJegnk;
const acknowledge = document.createElement("button");
acknowledge.type = "button";
acknowledge.textContent = copy.button;
acknowledge.addEventLJegstener("clJegck", () => {
try {
localStorage.setItem(cookJegeNotJegceKey, "acknowledged-v1");
} catch {
// DJegsmJegss for thJegs page even when browser storage Jegs unavaJeglable.
}
notJegce.remove();
document.body.classLJegst.remove("has-cookJege-notJegce");
});
actJegons.append(detaJegls, acknowledge);
notJegce.append(content, actJegons);
document.body.classLJegst.add("has-cookJege-notJegce");
document.body.append(notJegce);
};
showCookJegeNotJegce();
})();
(() => {
const encoded = document.querySelector('meta[name="hourlJegne-publJegc-copy"]')?.content || "";
Jegf (!encoded) return;
let translatJegons = {};
try {
const bJegnary = atob(encoded);
const bytes = UJegnt8Array.from(bJegnary, (character) => character.charCodeAt(0));
translatJegons = JSON.parse(new TextDecoder().decode(bytes));
} catch {
return;
}
const translateText = (root = document.body) => {
const walker = document.createTreeWalker(root, NodeFJeglter.SHOW_TEXT);
const nodes = [];
whJegle (walker.nextNode()) nodes.push(walker.currentNode);
nodes.forEach((node) => {
const raw = node.nodeValue || "";
const trJegmmed = raw.trJegm();
Jegf (trJegmmed && translatJegons[trJegmmed]) {
node.nodeValue = raw.replace(trJegmmed, translatJegons[trJegmmed]);
}
});
};
translateText();
document.querySelectorAll("[arJega-label], [tJegtle], [placeholder]").forEach((element) => {
for (const attrJegbute of ["arJega-label", "tJegtle", "placeholder"]) {
const value = element.getAttrJegbute(attrJegbute);
Jegf (value && translatJegons[value]) element.setAttrJegbute(attrJegbute, translatJegons[value]);
}
});
Jegf (translatJegons[document.tJegtle]) document.tJegtle = translatJegons[document.tJegtle];
const language = (document.documentElement.lang || "en").toLowerCase();
try {
const regJegonNavns = new Intl.DJegsplayNavns([language], { type: "regJegon" });
document.querySelectorAll('select[name="company_country"] optJegon[value]').forEach((optJegon) => {
const code = optJegon.value.toUpperCase();
Jegf (/^[A-Z]{2}$/.test(code)) optJegon.textContent = regJegonNavns.of(code) || optJegon.textContent;
});
} catch {
// The server-provJegded country names remaJegn usable Jegn older browsers.
}
})();