Painotettu keskihinta ja ostotilausten vastaanotto: opit oikean varastonhallinnan rakentamisesta
Mitä opin, kun rakensin pohjoismaiselle erikoistavarakaupalle ostotilausten vastaanoton ja painotetun keskihinnan (WAC) laskennan – ja miksi 'DB-light' oli oikea arkkitehtuurivalinta.
Huomio nimistä: Tämä kirjoitus perustuu omaan, oikeaan työhöni pohjoismaisen erikoistavarakaupan – kutsutaan sitä tässä nimellä Ruska – varastonhallinnan parissa. Nimi on keksitty, eikä luottamuksellista dataa jaeta. Opit ja ratkaisut ovat aitoja.
Rakensin usean kuukauden ajan Ruskalle Shopifyn päälle varastonhallintasovellusta, jonka ytimessä ovat ostotilaukset (PO), vastaanotto ja painotettu keskihinta (weighted average cost, WAC). Tämä kirjoitus kokoaa opit, jotka olisin halunnut lukea ennen aloittamista.
Miksi WAC on vaikeampi kuin miltä se näyttää
Kaava on triviaali: uusi WAC = (vanha varastoarvo + saapuneen erän arvo) / (vanha määrä + saapunut määrä). Vaikeus on kaiken muun ympärillä:
Alustus. Kun laskenta otetaan käyttöön olemassa olevassa kaupassa, jokaiselle tuotteelle tarvitaan lähtö-WAC. Jos alustus tehdään huolimattomasti, jokainen tuleva laskelma perii virheen. Rakensin alustuksen erillisenä, kovennettuna vaiheena, joka validoi lähtödatan eikä kaadu yksittäiseen puuttuvaan kustannukseen.
Rahdin ja kulujen jyvitys (landed cost). Sisäänostohinta ei ole koko totuus – rahti ja muut kulut pitää jyvittää riveille, ja käyttöliittymän pitää näyttää tämä käyttäjän omalla kielellä niin selvästi, ettei vastaanottaja arvaa. Suomenkieliset termit vaativat oman iteraationsa: "landed cost" ei käänny itsestään.
Ajantasaisuus. Vastaanottohetkellä käytettävän "nykyisen WAC:n" pitää olla oikeasti nykyinen. Toteutin tälle staleness-ikkunan: jos arvo on liian vanha, se haetaan uudelleen ennen kirjausta.
"DB-light": älä kopioi Shopifyn tietokantaa itsellesi
Arkkitehtuurin tärkein valinta oli se, mitä ei tallenneta omaan kantaan. Kutsun mallia nimellä DB-light: Shopify pysyy tuotteiden ja saldojen master-datana, ja oma kanta sisältää vain sen, mitä Shopifyssa ei ole – ostotilaukset, vastaanotot ja kustannushistorian.
Jokainen Shopifysta kopioitu taulu on synkronointivelka: se on aina jossain määrin väärässä ja vaatii oman täsmäytyksensä. Kun kopioitua dataa on vähemmän, virhetiloja on vähemmän. Tämä ratkaisu yksinkertaisti sovellusta enemmän kuin mikään yksittäinen ominaisuus.
Samasta syystä poistin aiemmin rakentamani kustannusten "karanteenijärjestelmän" – välivaiheen, jossa epäilyttävät kustannukset odottivat hyväksyntää. Se kuulosti turvalliselta, mutta käytännössä se vain siirsi ongelmat jonoon, jota kukaan ei tyhjentänyt. Suoraviivainen validointi kirjaushetkellä toimi paremmin. Ominaisuuden poistaminen oli sen viikon paras commit.
Vastaanoton UX ratkaisee datan laadun
Varastonhallinnan data on täsmälleen niin hyvää kuin vastaanottohetken kirjaukset. Siksi käytin yllättävän paljon aikaa vastaanottonäkymän yksinkertaistamiseen: vähemmän kenttiä, selkeät kustannusten ohjetekstit, nopea viivakoodilla haku – ja virhetilanteiden korjauspolut.
Konkreettisia asioita, jotka jokainen vastaava projekti kohtaa:
- CSV-tuonti ja viivakoodit tarvitsevat kovennusta: duplikaattirivit, väärät sarakkeet, skannerin ja hakukentän konfliktit. Nämä eivät ole reunatapauksia vaan arkea.
- Valuuttamuotoilu kaataa sovelluksen, jos se tehdään naiivisti – nolla-arvot, puuttuvat valuutat ja lokalisoitu desimaalierotin on testattava.
- Rivien muokkaus ja poisto luonnosvaiheessa tuntuu toissijaiselta, kunnes ensimmäinen oikea tilaus näppäillään väärin. Käyttäjän pitää pystyä korjaamaan itse.
- Peruutus (void) tarvitsee oman suunnitellun polkunsa. Väärin kirjattu vastaanotto ei saa jäädä kummittelemaan kustannushistoriaan.
Frontendin hiljainen vihollinen: revalidaatiosilmukat
Yksi ikävimmistä bugeista ei liittynyt varastologiikkaan lainkaan: ostotilausnäkymän data-fetcherit päätyivät efektiketjussa loputtomaan revalidaatiosilmukkaan. Sivu näytti toimivalta, mutta hakkasi palvelinta taustalla. Oppi: kun fetcher-kutsuja laukaistaan efekteistä, jokaiselle pitää pystyä osoittamaan terminaatioehto – ja verkkoliikenne kannattaa vilkaista devtoolsista aina ennen julkaisua.
Yhteenveto
- WAC-kaava on helppo; alustus, jyvitys ja ajantasaisuus ovat itse työ.
- Kopioi Shopifysta omaan kantaan mahdollisimman vähän – jokainen kopio on täsmäytysvelkaa.
- Poista välivaiheet, joiden jonoja kukaan ei oikeasti hoida.
- Panosta vastaanoton UX:ään: se määrää koko järjestelmän datan laadun.
- Lokalisoi kustannustermit huolella ja testaa valuuttamuotoilu reunatapauksilla.