Cesta k dostatočne dobrému softvéru pre faktúry bola dosť tŕnistá, povedal by som. Rok a pol som používal vlastnoručne hostovanú inštanciu Craterapp. Crater fungoval takmer dobre. Nemal žiadne zásadné problémy, povedal by som. Ale mal veľa menších problémov, ktoré ma veľmi otravovali. Dalo sa to prežiť, ale hej, toto je administratívna práca. Zvyčajne nie je veľmi zábavná, je nudná a zdĺhavá. Používanie softvéru, ktorý to robí ešte bolestivejším, hoci len trochu, bolo pre mňa smrťou tisícimi rezmi.
Nejakú dobu som hľadal riešenie tohto problému. Vyskúšal som fakturačnú platformu Revolut Business. Tá bola veľmi obmedzená na funkcie. Jedinou výhodou bolo automatické párovanie platieb, čo je fajn, ale pri malom objeme faktúr to nebolo rozhodujúce. Potom som zistil, že Paypal má tiež pomerne vyspelú fakturačnú platformu a chvíľu som sa s ňou pohrával. Takmer by som sa tam usadil, nebyť odporúčania od priateľa.
Prichádza faktury-online.com #
Pred rokom som začal používať https://faktury-online.com na správu faktúr a cenových ponúk. Spočiatku som bol skeptický, ani si nepamätám prečo. Ale keďže je to robené slovenským tímom, okamžite som sa zamiloval, pretože mali vyriešené všetky byrokratické prekážky nášho štátu, na rozdiel od všetkých vyššie spomínaných možností, ktoré boli buď veľmi všeobecné alebo dokonca optimalizované pre USA.
Ako ubehol rok, nenašiel som žiadnu zásadnú prekážku v tomto softvéri. Bol len jeden háčik: nemal som zálohu dát, okrem PDF-iek, ktoré uchovávam v elektronickej forme a účtovník má vo svojom archíve. Poznámka: nemám žiadne prepojenie s faktury-online.com a nikdy som od nich nedostal žiadne sponzorstvo. Ak sa vám páčia, jednoducho ich používajte a plaťte im, prvý rok je zadarmo.
Späť k problému zálohovania. Ponúkajú zálohovací servis, ktorý stojí zhruba dvojnásobok základného poplatku za používanie, ak sa nemýlim. Stále je to v nízkych desiatkach eur za celý rok, takže vôbec nie drahé, ale ponúkajú aj API. Po zvážení jeho schopností som sa rozhodol, že zálohu si urobím sám cez API.
Záloha cez API #
Tento recept potreboval tieto ingrediencie:
- skript, buď v PHP alebo JS, ktorý zavolá API a získa všetky dáta
- spôsob uloženia dát, najlepšie ako JSON súbor
- spôsob spustenia skriptu buď pri zmene alebo aspoň periodicky
Začnite inštaláciou potrebných závislostí:
npm i @actions/core @actions/github @vercel/ncc
Teraz aktualizujte package.json tak, aby obsahoval build:
"scripts": {
"build": "ncc build index.js --license licenses.txt"
},
Teraz vytvorte index.js, ktorý bude skutočne volať API:
const fs = require("fs").promises
const path = require("path")
const key = process.env.API_KEY
const email = process.env.EMAIL
const baseUrl = process.env.BASE_URL
let phpSessionId
async function fetchData(endpoint, code = "") {
const data = JSON.stringify({ key, email, code })
const url = `${baseUrl}/${endpoint}?data=${encodeURIComponent(data)}`
const options = {
method: "GET",
credentials: "include",
headers: phpSessionId ? { Cookie: `PHPSESSID=${phpSessionId}` } : {},
}
try {
const response = await fetch(url, options)
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`)
}
const setCookieHeader = response.headers.get("set-cookie")
if (setCookieHeader) {
const matches = setCookieHeader.match(/PHPSESSID=([^;]+)/)
if (matches) {
phpSessionId = matches[1]
}
}
return await response.json()
} catch (error) {
console.error(error)
}
}
async function writeOutputToFile(data, filePath, sortBy) {
try {
data.sort((a, b) => b[sortBy].localeCompare(a[sortBy]))
await fs.writeFile(filePath, JSON.stringify(data, null, 2))
console.log("Output written to:", path.resolve(filePath))
} catch (error) {
console.error("Error writing to file:", error)
}
}
;(async () => {
await fetchData("init")
const invoicesList = await fetchData("list/created")
const invoicesOutput = await Promise.all(
invoicesList.invoices.map(async invoice =>
fetchData("status", invoice.code)
)
)
await writeOutputToFile(
invoicesOutput,
"invoices.json",
"invoice_number"
)
const offersList = await fetchData("cp-list/created")
const offersOutput = await Promise.all(
offersList.offers.map(async offer =>
fetchData("cp-status", offer.code)
)
)
await writeOutputToFile(offersOutput, "offers.json", "offer_number")
})()
Pokračujte s .github/workflows/main.yml, aby sa celý proces mohol
automatizovať:
name: Faktury-online.com backup
on:
workflow_dispatch:
schedule:
- cron: "15 0 1 * *"
jobs:
run:
runs-on: ubuntu-latest
permissions:
contents: write
env:
BASE_URL: ${{ secrets.BASE_URL }}
API_KEY: ${{ secrets.API_KEY }}
EMAIL: ${{ secrets.EMAIL }}
steps:
- uses: actions/checkout@v4
- run: node dist/index.js
- uses: stefanzweifel/git-auto-commit-action@v5
A nakoniec nakonfigurujte GitHub Action secrets pre API_KEY, EMAIL a
BASE_URL, tieto nájdete na <faktury-online.com>. Taktiež je potrebné
povoliť write oprávnenia pre GitHub actions, keďže toto vytvára automatické
commity.
Niekoľko ďalších poznámok:
- ak vykonáte akékoľvek zmeny v
index.js, najprv spustitenpm run build - spúšťa sa na začiatku mesiaca alebo manuálne
- je možné to spustiť do istej miery manuálne cez
act workflow_dispatch, ale vyžadujeGITHUB_TOKEN
Toto bola skvelá príležitosť využiť silu Github Actions. Mám k dispozícii veľa voľných minút GitHub Actions, ktoré len tak sedia a mohli by robiť nejakú užitočnú automatizáciu. Ale doteraz som sa nenaučil, ako ich používať, tak som sa cez víkend prinútil to urobiť. Užite si to!
Odkazy #
- https://docs.github.com/en/actions/creating-actions/creating-a-javascript-action
- https://docs.github.com/en/actions/quickstart
- https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions#accessing-your-secrets
- https://docs.github.com/en/actions/using-workflows/manually-running-a-workflow
- https://jasonet.co/posts/scheduled-actions/
- https://joht.github.io/johtizen/build/2022/01/20/github-actions-push-into-repository.html
- https://www.faktury-online.com/faktury-online-api/manual
- https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows