Automatiseerimine raamatupidamise esimese etapi – dokumentide kogumise 🙂
Kuidas tavaliselt edastatakse ostuarved raamatupidajale?
Olen raamatupidamisega tegelenud piisavalt kaua… 20+ aastat… et mäletada kuidas dokumente toodi paberina. Viisakad kliendid tõid kaustaga koos ning korra toodi ka prügikotiga :-/ …et vali ise mis sobib kasutada.
Järgmine edasiminek oli, ja kohati siiani, et dokumente saadetakse e-kirjaga või pannakse käsitsi kuhugi pilvepõhisesse kausta – Google Drive, Dropbox, Microsoft OneDrive, Apple Cloud on populaarsemad.
Tasuliste variantidena on kasutusele võetud erinevad äpid, millega telefoni abil dokumente sisse pildistada ja kuhu saab ka e-kirju edasi suunata. CostPocket on Eestis enim levinud, kuid on ka teisi nagu Envoice.
Tasuline on hea, kuid Tasuta on veel parem
Järgmised automatiseerime raamatupidamise esimese etapi ehk dokumentide kokku korjamise kasutades selleks tasuta Google vahendeid.
Küsi ka järgmiste etappide kohta ja raamatupidamisteenuse kohta – olen ära automatiseerinud Gemini AI abil dokumentide tuvastamise. Ja sealt edasi kokku pannud skripti dokumentide edastamiseks Merit Aktiva programmi otse Ostuarveks (jättes vahele Kinnitamata ostuarved etapi) või Müügiarveks (kui arve on kuskil mujal loodud, näiteks veebipoes või kasvõi Wordi dokumendina).
Vajalikud töövahendid
- Tasuta Gmail konto – kui Sul veel pole, siis palun tekita see endale
- Tasuta Google Drive äpp – otsi enda telefoni äpipoest äppi nimega Google Drive (see tuleb kaasa tasuta Gmaili kontoga)
- Tasuta Google Apps Script – see tuleb kaasa tasuta Gmaili kontoga
Märkus
Püüan järgnevalt vältida liigset detailsust. Samas kui midagi jääb selgusetuks, siis küsi kommentaaris lisaks.
Gmaili piirangud
Paljud teavad, et Gmailis saab kasutada Filtreid. Kuid seal on oluline piirang – filtritega pole võimalik öelda, et võta e-kirjast manus (attachment) ja salvesta see konkreetsesse Google Drive kausta.
Filtritega saame teha vajadusel muud kasulikku nagu Siltide lisamine.
Filtrid leiad Gmailis Seaded alajaotusest (hammasratas üleval paremal).
Kuna Filtrid meid käesoleva ülesande lahendamisel kuidagi ei aita, siis sellel teemal hetkel rohkem ei peatu.
Esimene praktiline samm: Teeme dokumentide jaoks uue Google Drive kausta
- Ava Google Drive
- Tee Uus kaust
- Vajuta Uus
- Vajuta Uus kaust
- Pane nimeks näiteks Raamatupidamise dokumendid
- Ava Uus kaust
- Vaata aadressiriba
- Leia sealt aadressiosa mis järgneb tekstile /folders/
- See on kausta ID ehk unikaalne kood Google süsteemis
- Kopeeri kausta ID (võid seda teha ka hiljem kui meil on seda vaja; praegu on oluline, et tead kuidas selle kätte saab)

Teine praktiline samm: Teeme skripti ehk ilma kasutajaliideseta programmi
- Ava Google Drive
- Ava eelmises sammus loodud kaust Raamatupidamise dokumendid
- Alustame uue Skripti loomist
- Vajuta Uus
- Vajuta Rohkem
- Vajuta Google Apps Script
- Avaneb uus aken ja kohe on seal hoiatus, et kui peaksid jagama kellegagi Raamatupidamise dokumendid kausta, siis too inimene näeb ka Sinu skripti sisu (ja võib selle käima panna)
- Vajuta Create script
NB! Skriptidega saab teha palju head, kuid ka palju kurja – seega päriselt tekita skript ainult sellisesse kausta kuhu ligipääs on ainult Sinul või lisaks usaldusväärsel inimesel (raamatupidajal).


Kopeeri ja pane järgmine kood Koodi kirjutamise alasse.
- Asenda allolevas koodis KAUSTA_ID enda kausta ID-ga mille enne leidsime.
- Kindlasti Salvesta kood.
- Reeglite ridu võid juurde teha. Iga reegel algab { loogelise suluga ning lõppeb }, ehk siis loogelise sulu ja komaga.
- All on mõned näited… Näidisrida ei tee midagi kuna see algab // ehk siis on kommentaar.
- Kõiki kriteeriume ei pea ära täitma, kuid ole ettevaatlik – kui jätad näiteks saatja (sender), saaja (recipientName), pealkirja (subjectContains) tühjaks ja täidad ainult kausta ID (folderId) ning labelName (sildi nimi) – siis leitakse kõik kirjad mis on Sulle tulnud ja millel on fail kaasas ning kõik need failid salvestatakse määratud kausta ning kirjadele lisatakse Silt nimega “Arved”.
- Ehk pane nii piiravad kriteeriumid kui võimalik… kuid kindlasti ära pane pealkirja arve numbrit mis on alati erinev. Pane ainult see osa kirja pealkirjast, mis on alati sama.
- Alloleva koodiga saab alla laadida PDF arveid kirjadest kus need on kaasas, kuid lisatud on ka Forus Takso ning Bolt Arve näited kus kirjades on ainult link PDF arvele.
- Küsimused kirjuta kommentaari… samuti kui Sul on soovitusi koodi täiendamiseks.
function otsiKirjadest() {
const rules = [
// Näidisrida: { sender: "saatja@example.com", recipientName: "peeter@sigma.ee", subjectContains: "Pealkiri", folderId: "KAUSTA_ID", labelName: "Arved" },
// Takso arved
{ sender: "billing@forus.eu", recipientName: "peeter@sigma.ee", subjectContains: "Arve", folderId: "KAUSTA_ID", labelName: "Arved", isLinkBased: true },
{ sender: "receipts-tallinn@bolt.eu", recipientName: "peeter@sigma.ee", subjectContains: "Bolti sõit", folderId: "KAUSTA_ID", labelName: "Arved", isLinkBased: true, isBolt: true },
// Parkimise arved
{ sender: "no-reply@pargi.ee", recipientName: "peeter@sigma.ee", subjectContains: "", folderId: "KAUSTA_ID", labelName: "Arved" },
];
// --------------------
rules.forEach(rule => { // Iga reegliga käivitatakse järgmine kood – kui soovid aru saada, mis siin toimub, siis kopeeri see kood AI-le ja palu selgitada
const folder = DriveApp.getFolderById(rule.folderId);
let label = GmailApp.getUserLabelByName(rule.labelName) || GmailApp.createLabel(rule.labelName);
let query = `from:${rule.sender} "${rule.recipientName}" is:unread`;
if (!rule.isLinkBased) query += " has:attachment";
if (rule.subjectContains) query += ` subject:(${rule.subjectContains})`;
const threads = GmailApp.search(query);
threads.forEach(thread => {
const messages = thread.getMessages();
messages.forEach(message => {
if (!message.isUnread()) return;
const fullRecipient = message.getTo();
const subject = message.getSubject();
const matchesRecipient = fullRecipient.includes(rule.recipientName);
const matchesSubject = rule.subjectContains === "" || subject.toLowerCase().includes(rule.subjectContains.toLowerCase());
if (matchesRecipient && matchesSubject) {
let success = false;
if (rule.isBolt) {
success = processBoltEmails(message, folder);
} else if (rule.isLinkBased && rule.sender === "billing@forus.eu") {
// Kutsutakse välja Foruse spetsiifiline funktsioon
success = processForusEmails(message, folder);
} else {
// Tavaline manuste salvestamine
const attachments = message.getAttachments();
attachments.forEach(attachment => {
folder.createFile(attachment);
console.log(`Salvestatud manus: ${attachment.getName()}`);
success = true;
});
}
if (success) message.markRead();
}
});
thread.addLabel(label);
thread.moveToArchive();
});
});
}
function processForusEmails(message, folder) {
const body = message.getBody();
const subject = message.getSubject();
const linkRegex = /href="([^"]+)"[^>]*>Lae alla PDF/i;
const match = body.match(linkRegex);
if (match) {
let fileUrl = match[1]
.replace(/=\r?\n/g, "")
.replace(/=3D/g, "=")
.replace(/&/g, "&")
.trim();
try {
const params = {
followRedirects: true,
muteHttpExceptions: true,
headers: {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
};
const response = UrlFetchApp.fetch(fileUrl, params);
const responseCode = response.getResponseCode();
const blob = response.getBlob();
const contentText = response.getContentText(); // Võtame sisu tekstina, et kontrollida algust
// KONTROLL: Kas kood on 200 JA (tüüp on PDF VÕI sisu algab %PDF-iga)
if (responseCode === 200 && (contentText.indexOf("%PDF") === 0 || (blob.getContentType() && blob.getContentType().indexOf("pdf") > -1))) {
// Puhastame failinime
const fileName = subject.replace(/[/\\?%*:|"<>]/g, '-') + ".pdf";
// Sunnime õige tüübi ja nime
const finalBlob = blob.copyBlob().setContentType("application/pdf").setName(fileName);
folder.createFile(finalBlob);
console.log("Edu: Foruse PDF tuvastatud sisu järgi ja salvestatud: " + fileName);
return true;
} else {
console.log(`Viga: Sisu ei ole PDF. Kood: ${responseCode}`);
return false;
}
} catch (e) {
console.log("Viga allalaadimisel: " + e.toString());
return false;
}
}
return false;
}
function processBoltEmails(message, folder) {
const body = message.getBody();
const subject = message.getSubject();
// Otsime linki teksti "Laadi alla PDF-arve" juurest
// Kasutame veidi paindlikumat regex-it, et tabada linki isegi kui seal on reavahetused
const linkRegex = /href="([^"]+)"[^>]*>Laadi alla PDF-arve/i;
const match = body.match(linkRegex);
if (match) {
// Puhastame URL-i (sama loogika mis Foruse puhul)
let fileUrl = match[1]
.replace(/=\r?\n/g, "")
.replace(/=3D/g, "=")
.replace(/&/g, "&")
.trim();
try {
const params = {
followRedirects: true,
muteHttpExceptions: true,
headers: {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
};
const response = UrlFetchApp.fetch(fileUrl, params);
const responseCode = response.getResponseCode();
const blob = response.getBlob();
const contentText = response.getContentText().substring(0, 100);
// Kontrollime, kas saime PDF-i (kas päise või sisu alguse järgi)
if (responseCode === 200 && (contentText.indexOf("%PDF") > -1 || (blob.getContentType() && blob.getContentType().indexOf("pdf") > -1))) {
const date = Utilities.formatDate(message.getDate(), "GMT+2", "yyyy-MM-dd");
const fileName = `Bolt_${date}_${subject.replace(/[/\\?%*:|"<>]/g, '-')}.pdf`;
// Sunnime tüübi PDF-iks
const finalBlob = blob.copyBlob().setContentType("application/pdf").setName(fileName);
folder.createFile(finalBlob);
console.log("Bolt PDF edukalt salvestatud: " + fileName);
return true;
} else {
console.log(`Bolt viga: Link ei viinud PDF-ini. Kood: ${responseCode}, Sisu algus: ${contentText}`);
return false;
}
} catch (e) {
console.log("Viga Bolti allalaadimisel: " + e.toString());
return false;
}
}
console.log("Bolti meilist ei leitud 'Laadi alla PDF-arve' linki.");
return false;
}
Teise sammu jätkuks: Koodi käivitamine ja õiguste andmine esimesel korral
- Vajuta nuppu Run
- Anna vajalikud õigused
- Avanenud aknas vajuta sinist nuppu “Review permissions”
- Avanenud hoiatuses “Google hasn’t verified this app” vajuta “Advanced”
- Ja avanenud osas vajuta “Go to Arvete otsija (unsafe)”
- Järnevas vaates vajuta “Select all”
- Sellega valid kolme õiguse andmise:
- Lugeda, kirjutada, saata, kustutada jne e-kirju Sinu gmaili postkastist (kahjuks eraldi ei saa neid valida)
- Näha, muuta, luua, ja kustutada faile Sinu Google Drive kaustadest (kahjuks eraldi ei saa valida õiguseid)
- Ühenduda väliste teenustega (antud juhul on need välised teenused Gmail ja Google Drive)
- Sellega valid kolme õiguse andmise:
- Vajuta samas aknas “Continue”
- Kood käivitus… nüüd vaata “Execution log” ekraaniosa, mis just avanes
- Siia tuleb info tegevuste koha ning veateated.
- TUBLI! Oled skripti käsitsi käivitanud ning programm on teinud oma töö ära 🙂
Kolmas samm: Paneme skripti automaatselt tööle
- Skripte on võimalik käivitada automaatselt ja regulaarselt
- Selleks vajuta Kella ikoonile ekraani vasakus ääres
- Seejärel vajuta sinisele “Add Trigger”
- Kui Sulle sobib, et skript käivitub korra tunnis, siis vajuta kohe “Save”
- Kui soovid muud intervalli, näiteks korra minutis, siis tee vajalikud muudatused… võid valida ka korra ööpäevas või mingid kindlad ajad.

Valmis! Oleme automatiseerinud raamatupidamise esimese etapi ehk arvete kogumise postkastist.
Vihje! Kui soovid saada tasuta e-arveid enda postkasti PDF failidena, siis kasuta teenust nimega Billberry. Billberry on ainus e-arvete operaator mille kaudu saab vastu võtta ja saata e-arveid täiesti tasuta. Selle asutaja Andri Möll ei olnud nõus maksma e-arvete liigutamise eest ning lõi seetõttu uue operaatori.
Billberrys saad määrata e-posti aadressi kuhu Sulle saadetakse e-arvega kaasa tulnud PDF failid. Ning üleolevat koodi saad kasutada ka nende salvestamiseks kindlasse Google Drive kausta.
Automatiseerimise järgmised etapid
Dokumentide tuvastamine ehk siis piltidest ja PDF failidest masinloetava dokumendi tekitamine.
E-arvete vastuvõtmise aktiveerimine, et seekaudu saada otse masinloetavaid e-arveid.
Raamatupidamisandmete ja masinloetavate dokumentide sidumine sellisel kujul, et need saab salvestada otse raamatupidamisprogrammi Ostuarved jaotusesse (ning täielikult vahele jätta Kinnitama ostuarved etapi).
Olen ka need automatiseerimised enda jaoks ära teinud 🙂
Küsimusi? Kommenteeri ja küsi.
Soovid teha koostööd?
Parim viis selleks on raamatupidamisteenuse tellimine.




