Created
April 28, 2021 17:15
-
-
Save juvuorin/161411f41cba4842bbad017e91152eab to your computer and use it in GitHub Desktop.
Koiramainen ohjelmointikisa 2021
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Koiramainen Kirjanpito | |
* | |
* Tervetuloa Koiramaisen Kirjanpidon ohjeisiin. Alla olevassa koodissa määritellään kirjanpidon tilit. | |
* Automaatio on yksinkertainen. Lasketaan alv:t erikseen, samoin kaikki verottomat koiramaisuudet. | |
* | |
* Luo samaan hakemistoon tiedosto nimeltä 'input.txt' ja aseta sen sisälle kirjanpito aineisto | |
* seuraavassa muodossa: | |
* | |
* <Otsikko> <Otsikko> | |
* <Tilinumeto> <Rahamäärä> | |
* | |
* Esimerkiksi näin: | |
* Tilinumero Rahamäärä | |
* 4008 50.7 | |
* 3010 400.6 | |
* 6000 56 | |
* | |
* Ohjelman ajamiseen tarvitset NodeJS ympäristön (vaikka versio 14.15.1 käy hyvin). | |
* | |
* Aja ohjelma komentokehotteessa käskyllä 'node index.js'. | |
* | |
* Ohjelma luo 'input.txt' tiedostossa olevasta kirjanpitomateriaalista 'output.txt' nimisen | |
* tiedoston, joka sisältää käsitellyn materiaalin valmiina kirjanpitoon vietäväksi. | |
* | |
* Voit testata ohjelman toimivuutta mukana tulevalla input.test.txt tiedostolla. Tämä tapahtuu | |
* käskyllä 'node index.js --test'. Käsky luo 'output.test.txt' tiedoston, jossa näet mallin | |
* millainen lopputulos tuotetusta materiaalista voisi tulla. | |
* | |
* Toivottavasti viihdyt ohjelman seurassa! :) | |
*/ | |
// Tarvitsemme yhden extra-tiedoston, jolla voimme lukea luomiasi tiedostoja | |
const fs = require('fs'); | |
/** | |
* Tilikirja | |
* Määrittele tähän kaikki tilit joita tarvitset ja määritä tilille tyyppi. | |
* Tyyppi voi olla 'noTax' tai 'tax' | |
* 'noTax' on tapahtumia, joista ei käsitellä veroja pois | |
* 'tax' on tapahtumia, joista käsitellään verot erikseen, tilin summa on veroton arvo | |
* | |
* On myös olemassa automaatisoituja tyyppejä: | |
* 'alv' tiliin lasketaan kaikki verot yhten | |
* 'beforeTax' tiliin lasketaan kaikki verotettavat tulot yhteen | |
* 'total' tiliin lasketaan kaikki summat yhteen | |
*/ | |
const accounts = [ | |
{ number: 4008, type: "noTax" }, | |
{ number: 3010, type: "tax" }, | |
{ number: 1700, type: "beforeTax" }, | |
{ number: 2700, type: "alv", }, | |
{ number: 6000, type: "noTax", }, | |
{ number: 9000, type: "total", }, | |
]; | |
// Määritellään mitä automaatioita halutaan milloinkin tapahtuvan. | |
const relations = [ | |
{ name: "noTax", relation: ["total", "noTax"] }, | |
{ name: "tax", relation: ["beforeTax", "alv", "total"]}, | |
]; | |
// Asetuksia, esimerkiksi joku alv-niminen verottaja ja tiedoston nimi | |
const settings = { | |
inputFile: process.argv.slice(2)[0] === '--test' ? "input.test.txt" : "input.txt", | |
outputFile: process.argv.slice(2)[0] === '--test' ? "output.test.txt" : "output.txt", | |
alv: 24 | |
} | |
const methodSelector = (name) => accounts.filter(acc => acc.type === name); | |
// Tämä funktio kattaa kaiken automaatioon liittyvän toiminnallisuuden | |
const accountFunctions = { | |
// Lisää summa verotettavien kokonaissaldoa laskeville tileille | |
beforeTax: (journal, data) => methodSelector("beforeTax").forEach(v => journal[v.number] = (journal[v.number] + data.sum).toFixed(2) * 1), | |
// Lisää summa kokonaissaldoa laskeville tileille | |
total: (journal, data) => methodSelector("total").forEach(v => journal[v.number] = (journal[v.number] + data.sum).toFixed(2) * 1), | |
// Lasketaan alvin osuus ja lisätään se alv tiliin. Lisäksi alkuperäisestä tilistä vähennetään vero. | |
alv: (journal, data) => { | |
methodSelector("alv").forEach(v => journal[v.number] = (journal[v.number] + (settings["alv"] * data.sum / (100 + settings["alv"])).toFixed(2) * 1).toFixed(2) * 1); | |
journal[data.account] += (100 * data.sum / (100 + settings["alv"])).toFixed(2) * 1; | |
}, | |
// Veroja ei tästä ryhmästä tarvitse laskea, joten pelkkä summa lisätään tiliin | |
noTax: (journal, data) => journal[data.account] = journal[data.account] ? journal[data.account] += data.sum : data.sum | |
} | |
// Tämä funktio yhdistää annetut tiedot luomaasi tilikirjaan. | |
const journalFuntion = (journal) => { | |
accounts.map(acc => journal[acc.number] = 0); | |
return (data) => { | |
data.map(d => accounts | |
.filter(acc => acc.number === d.account) | |
.map(a => relations | |
.filter(relation => relation.name === a.type) | |
.map(rel => rel.relation | |
.map(r => accountFunctions[r](journal, d))))) | |
return journal; | |
} | |
} | |
// Nyt on aika lukea luomasi input tiedosto. Onhan kaikki tiedot oikein? | |
fs.readFile(`./${settings.inputFile}`, 'utf8', ((err, data) => { | |
if (err) { | |
console.log(`Tarkista, että hakemistossa on ${settings.inputFile} niminen tiedosto ja että se on oikeassa muodossa.`); | |
return | |
} | |
// Tässä kohtaa tiedostolle tehdään kaikenlaisia taikoja, jotta antamasi arvot saadaan käyttöön | |
const accountData = data.split("\n") | |
.map(r => r.split(" ") | |
.filter(row => row !== "") | |
.map(n => parseInt(n))) | |
.filter((_, i) => i !== 0) | |
.map(dat => ({ account: dat[0], sum: dat[1] })); | |
// Nyt antamasi tieto on valmis parsittavaksi | |
const dataSet = journalFuntion({})(accountData); | |
// Aika luoda uusi tiedosto annetuista tiedoista | |
let content = "Tilinumero Rahamäärä\n"; | |
Object.keys(dataSet).forEach(key => { | |
content += `${key} ${dataSet[key]}\n` | |
}); | |
// Ja sitten kirjoitetaan tiedot lasketut kirjanpitotiedot uuteen tiedostoon...ja vola! | |
fs.writeFile(`./${settings.outputFile}`, content, err => { | |
if (err) console.log(err); | |
}); | |
})); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Vastauksen tekijä kirjoittaa suvereenisti JavaScriptiä. Koodi on kauttaaltaan luettavaa ja hyvin kommentoitua. Merkkijonojen muodostamiseksi käytetään fiksusti merkkijonointerpolointia ($). Relations lista määrittelee näppärästi automaatiotoiminnot. Tekijä on myös ajatellut testausta ja ylläpitoa; tästä kielivät rivit 64-68, joissa otetaan huomioon komentoriviltä käynnistysvaiheessa luettu testilippu --test. Nuolifunktioiden käyttö on sujuvaa ja tekijä hallitsee hyvin myös JS-oliomallin - tästä kertoo olion kenttien iterointia rivillä 124.
Funktiot, kuten alv jne. on hyvin nimetty ja ne dokumentoituvat helposti tulkittaviksi. Tekijä pyöristää summat fiksusti kahden numeron tarkkuuteen (toFixed(2)), kuten asiaan kuuluu.
AccountFunctions on niputettu näppärästi nimettyyn JS-objektiin, joten ne ovat siististi omassa "nimiavaruudessaan". Riveillä 112-117 luetaan data näpsäkästi tiedostosta ja luodaan lopulta "tuple"-tyyppinen lista objekteja, joissa on tilin numero ja saldo - näppärää.
Const ja let -määreitä käytetään kauttaaltaan oikein, lisäksi ternary-operaattoria käytetään niin ikään fiksusti kautta linjan.
Erittäin siisti JS-ratkaisu, missä käytetään "jäsää" hyvän jäsämäisesti, luokkia vältellen ja hyvin dokumentoituvasti toimintoja nimettyihin olioihin ryhmitellen.
Hauska ratkaisu kaiken kaikkiaan!