Migrera data till Infor M3: det som ställer till det vid driftsättning
Av Isak La Fleur EngdahlDe flesta artiklar om M3-migrering säger åt dig att involvera nyckelanvändarna, städa datan tidigt och se migreringen som en nystart. Allt sant. Allt lika sant för precis varje migrering som någonsin byggts. Inget av det säger något om vad som faktiskt är annorlunda med M3, eller varför projektet som såg fint ut i test rasar ihop på cutover-natten.
Så det här är den andra versionen. Den som är skriven inifrån cutover-fönstret, efter några sådana här.
Begränsningen som ändrar allt: du kommer inte åt databasen
Om din referenspunkt är gamla, on-prem-M3 – glöm det mesta av den. I M3 CloudSuite (multi-tenant) kommer du inte åt databasen. Inga direkta laddningar mot DB2-tabeller, inga bulkladdningar mot filsystemet, ingen smart SQL som fixar en miljon rader i efterhand. Allt går in genom API-lagret.
Det får en konsekvens du måste designa runt från dag ett: varje enskild post valideras av M3:s egen affärslogik på vägen in. Ett M3-API är, enligt Infors egen definition, en rutin som validerar poster och skapar eller uppdaterar filer i databasen – inte en rå skrivning. Så API:t låter dig inte skapa en artikel/lager-post innan lagret finns. Det låter dig inte ladda en kundorder för en kund som inte finns ännu. Det kontrollerar, och det avvisar.
Folk behandlar det här som det jobbiga. Det är egentligen det bästa med att migrera in i M3. Skräp stoppas i dörren i stället för att ligga tyst i en tabell tills månadsbokslutet smäller. Din avvisningslogg blir din städningsbacklog, gratis. Men det betyder att två saker nu är icke förhandlingsbara: laddningsordning och felhantering. Mer om båda nedan.
Mekaniken är M3-API:t – MI-transaktionerna – anropade genom ION API-gatewayen över REST med OAuth2. Artiklar går in via MMS200MI (artikel-API:t – notera att namnet inte följer panelprogrammet MMS001, ett av fallen där API:t och programmet skiljer sig åt), kunder via CRS610MI, leverantörer via CRS620MI, och så vidare, var och en med sina Add- och Chg-transaktioner. Du bygger ETL – Python funkar utmärkt – som gör om din källdata till de API-anropen och skickar in dem genom gatewayen. Det är hela spelet. Det svåra är inte att anropa. Det svåra är att bestämma vad som ska anropas, i vilken ordning, med vilken data.
Master data och transaktioner är två olika projekt
Det vanligaste misstaget är att behandla "artiklar, leverantörer, kunder, inköpsordrar, kundordrar" som en migrering med en strategi. Det är det inte. De delar sig rakt i två problem som beter sig helt olika.
Master data – artiklar, kunder, leverantörer, priser, produktstrukturer – är stabilt, idempotent och förlåtande. Du laddar det, och i morgon är det fortfarande sant. Du kan ladda det veckor i förväg, köra om det utan risk och diffa det utan dramatik.
Transaktionsdata – öppna ordrar, balanser, dokument i rörelse – är flyktigt och tidskänsligt. Det ändras ända fram till sekunden du går live, och en post som var rätt på tisdagen är fel på fredagen. Behandla det som master data så får du tillbringa cutover-natten med att jaga ordrar som hunnit skeppas ifrån dig.
Håll dem i separata mentala fack – ända ner till att ge var och en sitt eget frysdatum – så blir hela planen enklare.
Laddningsordningen är inte en smaksak, den är strukturell
Eftersom API:t upprätthåller referensintegritet är ordningen inte en finess – den dikteras av datan. Du bygger utåt från grunden:
Först grund- och konfigurationsdata – länder, valutor, enheter, artikelgrupper, lager. Sedan master data – artikelgrunddata (MMS200MI), kunder (CRS610MI) och leverantörer (CRS620MI); de refererar inte till varandra, så de kan laddas i valfri ordning. Grundartikeln bär ingen leverantör, så – till skillnad från ett artikelkort i Business Central – behöver du inte ladda leverantörerna först. Sedan objekten som kopplar ihop master data och därför kräver att föräldrarna finns först – artikel/lager (MMS200MI, AddItmWhs), artikel–leverantörskopplingen med inköpspriser (PPS040MI), produktstrukturer. Sist av allt: ingående balanser och eventuella öppna transaktioner.
Gör fel och API:t avvisar helt enkelt den beroende posten. Artiklar före strukturer. Lager före saldon. Kunder före ordrar. Det finns ingen genväg, och att leta efter en är hur man slutar med halvladdade objekt som ingen kan stämma av.
Bulkladdning först, sedan deltaladdning
Du migrerar inte allt i en enda heroisk nattkörning. Du fasar in det: en bulkladdning av varje objekt i god tid före go-live, sedan deltaladdningar som kör i kapp det som hunnit ändras i källan sedan dess. Master data och transaktioner fryses på olika datum, du rensar öppna ordrar före transaktionsstoppet, och alltihop körs efter en daterad runbook – men den där fas- och frys-koreografin är generell för vilken migrering som helst, så jag har brutit ut den till en egen text: migreringsplanen. Här håller jag mig till det som är specifikt för M3: hur du faktiskt räknar fram deltat.
För master data är deltat enkelt: det som är nytt får ett Add, det som ändrats får ett Chg. Det du måste få rätt är hur du avgör att en post ändrats – och det avgörs på källsidan. Källan här är ditt legacy-system, och dess data finns inte i M3 ännu, så M3:s egen metadata kan inte tala om vad som rört sig där. Har källan en last-modified- eller revisionskolumn du litar på, använd den. Ofta kan du inte – många legacy-system ljuger, eftersom batchjobb och direkta SQL-fixar inte alltid rör revisionskolumnen – så den pålitliga standardvägen är en full extrahering vid cutover, hash-diffad mot din bulkladdnings-snapshot. För de flesta migreringar in i M3 är den hash-diffen normalvägen, inte undantaget.
Undantaget är när källan själv ligger på Infor Data Fabric – en M3-till-M3-omimplementation eller tenant-konsolidering, eller en annan Infor-app som matar samma Data Lake. Då ligger källans poster redan i Data Lake med Infors egen metadata, och deltat blir en Compass-fråga: allt där infor.lastmodified() ligger efter din bulkladdnings-cutoff, redan upplöst till den senaste versionen av varje objekt. Du bläddrar bland objekten i Atlas, frågar dem i Compass och låter Purge sköta gallringen. Men ha klart för dig vad den tidsstämpeln är: infor.lastmodified() är Data Lakes egen publiceringsmarkör, och den finns bara för data som redan ligger i Data Lake. En icke-Infor-källa som migreras in i M3 finns inte där att fråga – vilket är precis därför du i normalfallet faller tillbaka på källans revisionskolumn eller hash-diffen.
Fällorna med öppna ordrar (det här är den riktiga artikeln)
Allt ovan är process. Det här är där migreringar faktiskt går fel, och det ligger helt i transaktionsfacket.
Instinkten är att migrera tre år av inköps- och kundordrar så att det nya systemet "har historiken". Låt bli. Avslutade, fullt fakturerade ordrar är inte operativ data – de är rapporteringshistorik, och rapporteringshistorik hör hemma i Data Lake, frågbart genom Compass, inte i M3:s aktiva ordertabeller. Det är hela poängen med Infor Data Fabric: M3 publicerar redan sin data dit, så tre år av avslutade ordrar är fullt rapporterbara utan att någonsin laddas som aktiva dokument. Hur datan tar sig dit är värt att känna till, för vid massförflyttning av data styr Infor numera in dig på Data Lake-ingestionsramverket snarare än den äldre ION/BOD-vägen. De aktuella vägarna är direkta: streaming-ingestion (i realtid, över WebSocket) för löpande ändringar, och batch-ingestion (källan paketerar datan som NDJSON och laddar upp via API) för precis det här jobbet – initiala fullladdningar och arkivering av kall historik ut ur det aktiva affärssystemet. På M3-sidan styr Data Lake Publisher vilka tabeller som publiceras och låter dig köra en initial eller partiell omladdning vid behov. Så att parkera historik i Data Lake är ingen nödlösning – det är den stödda vägen. Att ladda avslutade ordrar som aktiva dokument bränner nummerserier, skapar spök-saldon av öppna kvantiteter och saktar ner systemet utan någon nytta. Det som faktiskt migreras som aktiva dokument är bara de öppna ordrarna. Och öppna ordrar är precis de flyktiga posterna som inte vill ligga still.
Öppna inköpsordrar migreras på återstående kvantitet – beställt minus mottaget – inte på ursprunglig kvantitet. Det redan mottagna godset kommer in via din ingående lagerbalans. Du spelar inte upp inleveransen igen. Fällan är den delvis mottagna, ännu ej fakturerade raden: beställt 100, mottaget 60, fakturerat 40. Den enda raden är både öppen att ta emot (40 kvar) och mottaget men ej fakturerat (20 som ligger som en GRNI-avsättning i balansräkningen). Om din fack-logik klassar hela raden som ett enda tillstånd har du redan förlorat. Och den GRNI:n måste stämma mot din ingående finansiella balans exakt en gång – bokför den två gånger och du har dubblat en skuld.
Kundordrar har samma problem speglat: levererat men ej fakturerat är kundorder-sidans motsvarighet till GRNI. Godset har lämnat lagret, intäkten är inte bokförd ännu, och att stänga ordern i legacy-systemet får inte den balansen att försvinna. Den måste ändå landa i dina ingående finansiella balanser, oavsett om själva orderdokumentet migreras eller inte.
Det renaste sättet att migrera ett svårt objekt är att inte migrera det
De svåraste transaktionsobjekten är öppna ordrar. Så töm dem i verkligheten före cutover, så finns det inget att migrera.
På en nyligen genomförd retail-driftsättning var regeln för kundordrar precis denna. Distributionscentralen tog ägarskap för att rensa bordet: avbryt varje rad som inte ska skeppas, och se till att allt skeppbart faktiskt skeppas och stängs några dagar före go-live. På cutover-natten fanns det i praktiken inga öppna kundordrar kvar att ta med. Det stökiga dataobjektet löstes operativt, av lagret, inte tekniskt, av migreringsteamet.
Det är tankeskiftet. En del av dina värsta dataproblem är inte dataproblem. En restorder är verklig kundefterfrågan – du kan inte bara "stänga" den i ett skript utan att antingen tappa efterfrågan eller knappa in den på nytt i det nya systemet, och det är ett verksamhetsbeslut, inte en ETL-regel. En framåtdaterad order går inte att skeppa i förtid för att rensa den. Så du skjuter de besluten till dem som äger processen, tidigt, och krymper den tekniska migreringen till bara det som verkligen måste flyttas. Planen för det här är inte ett mappnings-Excel; det är en daterad cutover-runbook med namngivna ägare.
Att bevisa det: stäm av på värde, testa två gånger
När du kontrollerar en laddning räcker det inte att räkna poster. En inköpsorderrad kan laddas in korrekt genom API:t och ändå bära fel återstående kvantitet. Så för transaktionsobjekt stämmer du av på öppen kvantitet och öppet värde, per objekt, varje körning – källsiffra, laddad siffra, avvisad siffra. Källsiffran är en Compass-fråga rakt mot Data Lake; den laddade siffran kommer tillbaka genom M3-API:t; gapet mellan dem är din problemlista. Antal rader säger att API:t inte kraschade. Värdeavstämning säger att datan faktiskt stämmer. Det är två olika frågor.
Det finns en andra avstämning som blir viktig när du väl är live, och den är inte samma sak som migreringskontrollen. Migreringskontrollen frågar: stämde laddningen in i M3 mot legacy-källan? Data Ledger frågar något annat: kom verkligen allt som M3 publicerar fram till Data Lake? Det är en Infor Data Fabric-komponent byggd just för leveransavstämning källa-till-Lake – källan publicerar replikeringsstatistik (antal dataobjekt, instanser och rader) och Data Ledger jämför den mot vad som faktiskt landade i Data Lake och flaggar varje glapp. Den stämmer av batch-publicerad data på egen hand; för data som strömmas post för post kan den inte klassificera leveransen automatiskt, så du bekräftar den genom att köra en Compass-fråga från Data Ledger. Du använder den inte för att bevisa din cutover. Du använder den efteråt, för att lita på den Data Lake-kopia som din rapportering och revision nu vilar på.
Och testa det två gånger, på riktigt. En första testmigrering i en DEV-miljö där det tekniska teamet bekräftar att skripten kör och objekten landar. Sedan ett bredare test, i en TEST-miljö, där riktiga verksamhetsanvändare – de som vet hur datan ska se ut – öppnar de migrerade posterna och säger vad som är fel. De fångar saker som inget skript någonsin kunde, eftersom de känner igen sin egen data. Det bredare testet är där du hittar problemen som annars hade blivit go-live-problem.
Vad verksamheten ska ta med sig
Att migrera in i M3 är mindre av en data-övning än folk tror och mer av en operativ. API-begränsningen tvingar fram en disciplin du ändå hade velat ha. Uppdelningen master kontra transaktion talar om vad som är svårt. Och de verkligt svåra delarna – öppna ordrar, balanser i rörelse, halvlevererade rader – löses oftast bäst av verksamheten som rensar dem innan du ens skrivit en rad ETL.
Bestäm tidigt vad som är historik och vad som är aktivt: historik går till en data lake, bara öppna transaktioner migreras som dokument – och rensa de öppna transaktionerna i verkligheten, inte i ett skript, före cutover. Gör det, så krymper den tekniska migreringen till något du faktiskt kan stämma av och lita på.
Teamen som kämpar är de som behandlar det som en ren teknisk lift-and-shift och upptäcker verksamhetsfrågorna på cutover-natten. Teamen som glider igenom har redan tagit de obekväma samtalen – vilket är frysdatumet, vem rensar restordrarna, var bor historiken egentligen – veckor tidigare, när det fanns tid att svara på dem.
Gör det tråkiga planeringsarbetet. Migreringen är den enkla biten.
Står du inför en flytt till Infor M3 och vill ha en driftsättning som inte håller dig vaken om nätterna? Hör av dig – jag delar gärna med mig av hur jag arbetar.
Den här artikeln beskriver ett generellt arbetssätt, inte implementeringsråd för en specifik miljö. Referenser: Infor M3 API overview (API:er validerar poster och skapar/uppdaterar filer i databasen); API-repositoryt och MI-programmen MRS001/MRS002; M3 API-säkerhet och multi-tenant-auktoriseringsmodellen; ION API-gatewayens gränssnitt mot M3; samt Infor M3 CloudSuite solution overview om API-lagret och Infor Data Lake; och Infor Data Fabric – Atlas (utforska), Compass (fråga), Purge (gallring); Data Fabric Ledger för leveransavstämning källa-till-Lake; och Streaming Ingestion. Vidare tittande: Infors webbinarium New Features in Data Fabric (april 2025-releasen).