examensarbete - diva portalltu.diva-portal.org/smash/get/diva2:1030317/fulltext02.pdf · 2016. 10....

38
EXAMENSARBETE Förbättrad orderhantering Andreas Gustavsson Högskoleexamen Datornätverk Luleå tekniska universitet Institutionen för system- och rymdteknik

Upload: others

Post on 09-Sep-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

EXAMENSARBETE

Förbättrad orderhantering

Andreas Gustavsson

HögskoleexamenDatornätverk

Luleå tekniska universitetInstitutionen för system- och rymdteknik

Page 2: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Förbättrad OrderhanteringAndreas Gustavsson

LTU SkellefteåDatornätverk 120HP1 september 2011

Page 3: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Förord

Mitt syfte med detta arbete är att, för montörerna på företaget, ta fram ettverktyg som underlättar hanteringen av orderunderlag. En montör ska enkeltkunna hämta och lämna orderunderlagen samt fylla i arbetsrapporten. Jagvill med denna rapport visa hur jag tänkt och implementerat min lösningrunt företagets nuvarande förutsättningar.

Jag vill tacka Per Eriksson, VD Norr-Don AB, samt alla anställda för attjag fick göra mitt examensarbete där. Hoppas att resultaten ska hjälpa ochförenkla deras arbete.

Page 4: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Abstract

I worked with my final exam at Norr-Don AB. I came in contactwith Per Eriksson, MD at Norr-Don, who wanted a simpler solution tothe assembly personel for order operations and reporting.

For this task i chose the Python programming language to createthe application needed as we read a Python course in the beginning ofour education.

Sammanfattning

Mitt examensarbete gjorde jag på Norr-Don AB. Jag kontaktadePer Eriksson, VD:n på Norr-Don, som ville ha en enklare lösning förmontörerna att hantera ordrar och rapportera arbetet.

Jag valde att använda Python för att koda en applikation till dettaändamål då vi i utbildningen läst en kurs i just Python.

Page 5: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Innehåll

Förord i

Abstract ii

Sammanfattning ii

1 Introduktion 11.1 Bakgrund . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 Problemställning . . . . . . . . . . . . . . . . . . . . . . . . . 21.3 Syfte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.4 Förkortningar . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

2 Genomförandet 32.1 Inledning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32.2 Verktyg . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

2.2.1 Python IDLE . . . . . . . . . . . . . . . . . . . . . . . 32.2.2 Eclipse IDE . . . . . . . . . . . . . . . . . . . . . . . . 3

2.3 Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42.3.1 GUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.3.2 Klasser och funktioner . . . . . . . . . . . . . . . . . . 6

2.4 Distribution . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

3 Resultat 12

4 Diskussion 13

5 Källförteckning 15

6 Bilagor 166.1 Bilaga 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166.2 Bilaga 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266.3 Bilaga 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276.4 Bilaga 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286.5 Bilaga 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306.6 Bilaga 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

Page 6: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

1 Introduktion

Jag kontaktade Per Eriksson, Norr-Don AB, och fick i uppgift av honom attförbättra hanteringen av orderunderlag, främst till montörsidan men att detäven kunde gå utveckla till att innefatta administrationssidan.

Norr-Don AB är ett litet företag beläget i Åmliden, Norsjö Kommun.Dom tillverkar och säljer olika produkter inom El, exempelvis kablage, bygg-och kombicentraler och även många kundanpassade lösningar.

1.1 Bakgrund

Tidigare har dom skrivit ut orderunderlagen på papper och lagt dessa iplastmappar. För att spara pengar och på miljön valde dom att lägga dessai kataloger på deras server istället. Varje arbetsplats har dessutom en bärbardator för att kunna hämta och lämna orderunderlagen från servern. Varjeorderkatalog innehåller pdf-filer med ritningar, materiallistor och annat somär specifikt för den ordern.

En montör som ska hämta en tillverkningsorder öppnar då katalogen medordrar och flyttar en order till sin egna katalog. Montören skriver då in i ettexceldokument, när ordern påbörjats samt en signatur för att visa vem sompåbörjat ordern. När ordern är klar ska orderkatalogen flyttas till en katalogför faktureringsunderlag. Dessutom ska det i excel dokumentet skrivas in närordern var monterad klart, vikten på paketet och testresultat.

Bild 1.1.1Företagets katalogstruktur

1

Page 7: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

1.2 Problemställning

I detta förfarande finns ett par scenarion som skulle kunna uppstå. Exem-pelvis när en montör ska manuellt flytta kataloger kan det fort gå fel. Antin-gen kan den hamna i fel katalog eller av misstag raderas helt. Detta skaparjobb i onödan och bör kunna undvikas.

En annan sak jag upptäckte var att de som redigerade excel filen for-materade texten lite olika. Detta gör den mycket svår att överskåda och fården att se lite slarvig ut. Dessutom händer det ibland att någon missar ellerfyller i fel kolumner vilket även där skapar onödigt arbete.

1.3 Syfte

Mitt syfte med arbetet är att underlätta hela förfarandet för montören.Genom att applikationen ska sköta allt som tidigare gjordes manuellt börmånga av problemen kunna undvikas. Formateringen i exceldokumentet blirenhetlig och katalogerna flyttas till och från montörens katalog på rätt sätt.

1.4 Förkortningar

LTU - Luleå Tekniska UniversitetIDE - Integrated Development EnvironmentGUI - Graphical User Interface

2

Page 8: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

2 Genomförandet

2.1 Inledning

Applikationen är helt skriven i Python[1]. Python är ett programspråk somenligt utvecklarna har flera bra egenskaper:

• very clear, readable syntax

• strong introspection capabilities

• intuitive object orientation

• natural expression of procedural code

• full modularity, supporting hierarchical packages

• exception-based error handling

• very high level dynamic data types

• extensive standard libraries and third party modules for virtually everytask

• extensions and modules easily written in C, C++ (or Java for Jython,or .NET languages for IronPython)

• embeddable within applications as a scripting interface

Eftersom vi under första terminen läste en kurs i just Python gjorde attvalet var enkelt. Dessutom är Python det enda programspråk jag har någonerfarenhet av. Ännu en fördel är att det är “cross-platform”, vilket gör attdet fungerar på olika plattformar, vare sig det är Windows eller Linux.

2.2 Verktyg

2.2.1 Python IDLE

Med Python-paketet följer även IDLE med. Det är en mycket enkel IDEför just Python, men den täcker många användares behov. Till en börjananvände jag mig av IDLE, främst eftersom det skeppades med Python menäven för att jag hade jobbat med det tidigare.

2.2.2 Eclipse IDE

Under tiden jag kodade halkade jag in på en diskussion om bästa IDE förPython. Jag tänkte att man skulle testa en annan, lite mer avancerad, merfunktionsrik utvecklingsmiljö. Jag hittade en som verkade vara en kompetentIDE som dessutom var gratis att använda.

3

Page 9: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

Eclipse[2] är en open-source utvecklad IDE främst för java och c++, menmed Pydev går det alldeles utmärkt att koda i python. Jag tycker att manmed Eclipse fick en mycket bättre vy över koden, samt att den har mångaandra bra funktioner som underlättar arbetet.

2.3 Design

Hur ska man utforma en applikation för att den ska vara lätt att använda,även för de som har liten datorvana? Jag började skissa på papper ungefärhur jag tänkte att gränssnittet skulle se ut, detta gav lite större överblick påhur alla funktioner skulle fungera ihop med gränssnittet.

Bild 2.3.0.1Tidig skiss på gränssnittet

När en montör först startar programmet får den upp en dialogruta för attvälja bassökväg, där alla kataloger som används finns, samt vilken excelfilsom ska skrivas och läsas ifrån. För att slippa hårdkoda applikationen attpassa till varje användare beslöt jag mig att göra en universiell funktion pådet hela.

Genom att lägga in en funktion för att kunna välja användare, där valenav användare genereras av de kataloger som finns i bassökvägen, slipper mandetta. Ifall två anställda skulle byta arbetsplats går det även bra i efterhandatt byta användare.

4

Page 10: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

Efter lite funderingar och hackande av kod kom jag fram till ett uppläggjag tycker fungerade bra. Detta blev den slutgiltiga varianten på applikatio-nens gränssnitt.

Bild 2.3.0.2Slutgiltig version av gränssnittet

2.3.1 GUI

Det finns flera moduler till Python att bygga gränssnitt av. wxPython, PyQtoch Tkinter är de som verkade vanligast att använda sig av. Vilket som ärbäst är nog en smakfråga och beroende på hur komplicerad applikation manska göra.

wxPythonJag började med att testa wxPython[4]. I början kändes det relativt enkelt

att använda, men det började bli mycket med alla event-handlers. Det blevsnabbt mer invecklat och svårt att hålla reda på dessa. Däremot fick jagkänslan att wxPython erbjuder fler funktioner än många andra GUI:s, samtatt det arbetar närmare operativsystemet.

TkinterValet föll då på Tkinter [3] istället. Det är en inofficiell standard modul för

att bygga gränssnitt i Python, den är inkluderad i Python-paketet. Mycketav syntaxen från wxPython känns igen, men det var mycket lättare medeventen och callbacks i Tkinter. För att binda en funktion till exempelvisen knapp behövdes det bara anges command=<funktion> i <options> förknappen. (Ex: knapp1 = Button(<ParentFrame>, <options>) )

5

Page 11: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

2.3.2 Klasser och funktioner

Min applikation delade jag upp i olika klasser. Detta för att få en bättre blicköver applikationen, det blir lättare att lägga till och ändra kod i den. Helaapplikationen initieras från __main__. (Se Bilaga 3 ) i filen NDProd.py. Jaglistar här de klasser jag använder mig av.

askBaseDir (Bilaga 4)Klassen askBaseDir används för att kontrollera om det konfigurerats någon

sökväg samt ifall rätt kataloger finns i sökvägen. Den är i princip uppdeladi två delar.

Första delen i klassens initfunktion körs först ett try, except statementsom kontrollerar ifall en korrekt sökväg är konfigurerad genom att helt enkeltförsöka lista filer och kataloger i den. I annat fall höjs en varningsdialog medfelmeddelande och sedan höjs en dialogruta där användaren får välja en nysökväg.

I den andra delen finns en if-sats som ifall ingen sökväg finns höjer endialogruta för att fråga efter sökväg. Trycker användaren avbryt stängs helaapplikationen ned. Sökvägen kontrolleras sedan i funktionen validateDirec-tory. Funktionen tar den tidigare valda sökvägen som parameter. I klassenmain finns en dictionary, "main.setPath", vars värden är de kataloger somska finnas i sökvägen. Genom en for-loop kontrolleras den valda sökvägenmot dessa värden. Den returnerar True ifall katalogerna finns, annars re-turneras False. Returneras True kommer användaren till huvudfönstret. Ifall"validateDirectory" returnerar False visas en dialogruta med felmedde-lande och användaren får på nytt välja sökväg.

MainWin (Bilaga 1)Klassen MainWin innehåller alla widgets för huvudfönstret samt de vari-

abler som används i dessa widgets.Den innehåller även två dicitonarys. "setPath", vilken innehåller nam-

nen på de kataloger som ska finnas i huvudsökvägen, samt "colID" som harnycklar som identifierar vilken kolumn som ska skrivas till i excelfilen samtvärden som visar vad kolumnerna heter.

Variabeln "excelFile" är sökvägen till den excelfil som skrivs och läsesfrån. Sedan finns en del variabler med värdet "IntVar()" eller "StringVar()",dessa används till label widgetarna och ifall de ändras uppdateras dessa au-tomatiskt i labelwidgeten. Mycket smidigt får jag säga.

Ett par variabler som används i huvudfönstret är dessa:

• OrderFolderInnehåller en tuple med de kataloger som finns i den valda orderkata-logen. Den sätts som värde till listboxwidgeten "OrderList".

6

Page 12: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

• UserFolderInnehåller en tuple med de orderkataloger som finns i användarenskatalog. Denna sätts som värde till listboxwidgeten "UserList".

• currentUserFolderEn sträng med sökvägen till användarens katalog.

• workDirEn sträng med sökvägen till huvudkatalogen vilken innehåller alla or-derkataloger, användarnas kataloger samt faktureringskatalogen ochexcelfilen.

• currentUserSignEn strängvariabel som innehåller användarens signatur och används föratt fylla i exceldokumentet när en order flyttas till användarens katalog.

Funktioner i klassen “MainWin”

• __init__Ritar upp alla widgets i huvudfönstret.

• infoLabelsGenererar labels flr att visa information om ordern. Det görs på sammasätt som beskrivs ovan.

• clearEntriesRensar textboxarna som användaren fyller i när ordern är klar. (Bild2.3.2.1)

• setDateGjordes för att användaren inte skulle behöva fylla i dagens datum,utan det görs då automatiskt. Men ifall den av någon anledning behöverändras, är det bara att ändra den innan man skickar ordern vidare.

• onOrderToUserFolderFyller i excelfilen med dagens datum samt användarens signatur ochhöjer sedan en inforuta, där OK skriver till excelfilen och flyttar katalo-gen. Kan ej excelfilen skrivas till höjs ett felmeddelande och katalogenflyttas inte.

• onOrderFinishedVärdena som användaren fyllt textboxarna (Bild 2.3.2.1) skrivs tillexcelfilen och flyttar sedan ordern till faktureringskatalogen. Även härhöjs en inforuta innan excelfilen skrivs till och ett felmeddelande ifallexcelfilen inte går att skriva till. Då flyttas inte heller ordern.

7

Page 13: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

• orderSelAnropas när användaren markerar en order i listboxarna (se bild x.x.x).Jag gjorde en if-sats som kollar ifall ett värde i OrderListboxen är mark-erad och returnerar värdet, om inte något markerats i den returnerasvärdet på markeringen i den andra listboxen istället.

• onOrderHighlightDenna funktion har som uppgift att hämta information om ordern sommarkerats i en listbox från excelfilen.

• setUserFunktionen anropas av knappen "välj användare". Den öppnar endialogruta där användare väljs. Hur den fungerar förklaras i klassen"userSelect" nedan.

• noUserOm ingen användare valts när en order ska flyttas till en användarkata-log anropas denna funktion. Den höjer en infomeddelande och anroparsedan funktionen "setUser".

• move2userHuvudfunktionen för denna är att flytta ordern från orderkatalogentill användarens katalog. Finns ingen användare konfigurerad anropas"noUser", annars flyttas den order som är markerad i Order Listboxen.Pythonmodulen "os.path.join" används för att slå ihop de strängarsom skickas till den sökväg som ordern ska flyttas till.

• move2faktPrecis som funktionen ovan, fast ordern skickas från användarens kat-alog till faktureringskatalogen. Den anropar "onOrderFinished" ochflyttar sedan katalogen ifall den returnerar "True".

• UpdateUserFolderDen uppdaterar listboxen som listar katalogerna i användarmappen.

Bild 2.3.2.1

8

Page 14: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

userSelect (Bilaga 4)Denna klass innehåller widgets för att rita upp fönstret där man väljer

användare. Den innehåller ett par funktioner för detta.

• FramesDefinerar de frames som fönstret ska innehålla. I Tkinter är "Frame"en typ av behållare där man lägger olika widgets. Detta för att delaupp och kunna placera ut exempelvis en knapp på rätt ställe.

• radiobuttonsDen anropar funktionen "generateUsers" och av det den funktionenreturnerar ritas radiobutton widgets upp i fönstret för de användaresom går att välja bland.

• buttonsFunktionen ritar upp en OK och Cancel knapp i fönstret. OK kallarfunktionen "setUser" och Cancel kallar funktionen "Cancel".

• CancelDenna funktion stänger fönstret.

• setUserFunktionerna sätter variablerna i mainfönstret. Dessa variabler är"main.currentUserSign", vilket är den signatur som skrivs till ex-celfilen. "main.currentUser", namnet på användaren, samt "main.currentUserFolder",vilket är sökvägen till användarens katalog.

• generateUsersFunktionen returnerar en dictionary, samt två listor. Dictionaryn in-nehåller en integer som nyckel och katalognamnet som värde till den.Den ena listan, "radiolist", har namnen på radioknapparna (radio1,radio2.. osv.) Dessa läggs till listan beroende på hur många användark-ataloger som finns. Andra listan, "labellist", fylls med namnen påanvändarna. Dessa namn hämtas ur namnet på användarkatalogerna.

configFile (Bilaga 2)Detta objekt innehåller funktioner och variabler som används för att läsa

och skriva från en konfigurationsfil. Filen läses in vid uppstart och skrivstill när programmet stängs ner. Den innehåller ett par funktioner för dettaändamål.

• __init__Initierar klassen och definerar en instans av modulen ConfigParser.

• readLäser från configfilen och sätter värdena till variablerna i applikationen.

9

Page 15: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

• writeSparar värdena på de variabler som berörs för att sedan kunna skrivadessa till en konfigurationsfil.

• writeToFileSkriver värdena till konfigurationsfilen.

När sedan applikationen ska startas görs det från filen "NDProd_main.py".Satsen " if __name__ == ’__main__’: ", kollar ifall filen NDProd_main.pykörs som huvudprogram. Pythontolken sätter variabeln __name__ till ’__main__’ifall den körs som huvudprogram. Om så är fallet exekveras koden i det if-blocket vilket initierar huvudfönstret i applikationen och dess widgets. Denläser även från konfigurationsfilen och frågar efter bassökvägen och sökvägentill exceldokumentet.

Ifall det var många widgets med samma funktion men med olika namnoch labels gjorde jag en for-loop som itererade över ett dictionary vars nyckelvar "rowID". Det är den rad som widgeten ligger på i dess grid. Värdena ären lista där index 0 är namnet på widgetklassen och index 1 är texten iwidgeten, ifall det är en knapp, label eller liknande. Denna lösning tyckerjag ser kodmässigt snyggare ut, samt att ifall man ska lägga till ännu enwidget är det bara att lägga till det i dictionaryn.

readExcel (Bilaga 5)"excelMod.py" innehåller en klass jag använder för att läsa och skriva

till excelfilen. Jag använder mig av modulerna xlrd [4], xlwt[4], xlutils[4]samt tkMessageBox.Xlrd, xlwt och xlutils är python bibliotek som används för att läsa, skapaoch modifiera exceldokument med hjälp av python. Klassen innehåller ettpar olika funktioner som behövs av huvudapplikationen.

• __init__Initieraren av klassen. Har en variabel som heter "colID", vilken skainnehålla de kolumner som ska skrivas till. Variabeln "variables" ärde värden som läses ur excelfilen. Dessa läser sedan huvudapplikationenav.

• readDokFunktionen öppnar ett exceldokument för att skrivas eller läsas ifrån.Den anropar sedan "readFile" vilket beskrivs nedanför.

• readFileFunktionen tar "orderNr" samt ett kommando som argument. "OrderNr"är det ordernummer som ska läsas av i excelfilen. Kommandot är antin-gen en 0:a för att läsa ur filen, eller en 1:a ifall den ska skrivas till.

10

Page 16: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

• setVariablesTar "sheet" och "rowIndex" som argument där "sheet" är det excel-blad som ska läsas och "rowIndex" är den rad ordernumret ligger på.Funktionen lägger sedan värdena i dictionaryn "colID".

• writeExcelDenna funktion är den som skriver till excelfilen. På grund av begrän-sningar i excelmodulerna går det inte att redigera excelfilen utan manmåste kopiera den och för att sedan skriva över orginalfilen. Funktio-nen tar argumenten "sheet", "index" och "rowIndex". "sheet" ärexcelbladet där ordern finns representerad, "index" är numret på ex-celbladet och "rowIndex" är den rad ordernumret finns på. En for-loopitererar sedan över "colID" dictionaryn för att sedan skriva värdenai den till excelfilen. Värdena i "colID" är de som sätts när klasseninstantieras av den funktion som vill skriva till excelfilen.

11

Page 17: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

2.4 Distribution

För att underlätta distributionen av programmet letade jag med ljus ochlykta efter ett enkelt installationsscript, eller liknande, för att installera app-likationen på klienterna. Till slut hittade jag ett mycket smidigt verktyg fördetta ändamål, InnoSetup[3].

Med i installationspaketet följer även InnoIDE, det fungerar som enutvecklingsmiljö för att enkelt skripta sitt installationsprogram. Jag användemig av en “wizard” som frågar efter namnet på applikationen, vilka filer ochkataloger som ska packeteras i installationsfilen samt vilken fil som startarapplikationen. Det frågar även om vilken vilken grundkatalog den ska läggaapplikationen i vid installationen.

Trots att det går att göra rätt avancerade installationsscript är det enkeltatt snabbt komma igång och skapa en installationsfil.

3 Resultat

Programmet testkördes kontinuerligt under utvecklingen på både min miljöhemma och lokalt på en laptop. Min miljö hemma består av en Linux Servermed Ubuntu Server 11.04 med samba för att dela ut kataloger på nätver-ket, en klientdator som kör windows 7 professional och en D-Link DIR655konsumentrouter.

Företaget har en server som kör Windows Server 2003, klienter i formav laptops som kör Windows XP Professional och en trådlös accesspunkttillverkad av D-Link.

Jag installerade applikationen på företagets klientdatorer och testade denunder en arbetsdag. Applikationen fungerade som väntat vid testkörning imin hemmamiljö. Dock uppstod många problem i företagets miljö. Fram-förallt klagade den på att sökvägarna inte fanns, detta verkar ha något medteckenkodningen att göra. För att undvika problemet fick jag döpa om ettpar sökvägar och ta bort tecknen ÅÄÖ i dessa.

Applikationen fungerade som förväntat i min miljö hemma, men på före-taget gjorde den inte det. Dock fanns inte tid kvar att åtgärda alla fel somhittades.

12

Page 18: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

4 Diskussion

Norr-Don är som sagt ett mindre företag, men alla hjälpmedel som fören-klar och snabbar upp i deras vardag är välkomna. Det stora målet med minapplikation var just detta. Att för montörerna utveckla en applikation somskulle underlätta och snabba upp orderhanteringen och rapporteringen avdessa.

Min erfarenhet av att programmera sträcker sig inte längre än det vi lästei kursen som ingick i programmet. Däremot tycker jag att det verkade somen riktigt utmaning. Mitt första mål med hela examensarbetet var att fåen uppfattning om det var genomförbart på den tid examensarbetet pågick.Genom att konsultera Google[5] gick det bra att få en bild av omfattningenpå arbetet bakom. Jag började sedan med att koda applikationens grafiskadel. Det var just den delen jag såg som det största hindret. Som tur är varTkinter väl dokumenterat på många håll och kanter, det gjorde att det varlätt att komma igång och koda.

När jag börjat få en hyfsat bra struktur på den grafiska delen börjadejag klura på de funktioner applikationen skulle ha. Kraven var att den skullekunna flytta katalogerna samt rapportera till en excelfil. Delen med att flyttakataloger var enkelt. Python har många inbyggda moduler och en av dessa,“os”, har många bra funktioner bland annat för att flytta kataloger och listasökvägar.

Vad som däremot orsakade en del huvudbry till en början var hur manskulle kunna skriva till och läsa en excelfil. Svaret på den frågan blev PythonEx-cel, som innefattar modulerna “xlwt”, “xlwr” och “xlutils”. Ett problem jagstötte på då var att jag började koda min applikation i Python 3.2. Dessamoduler var skrivna för Python 2.6. Detta gjorde att jag fick skriva om ap-plikationen för Python 2.6, vilket tog en del tid i anspråk. Dessa modulervar även dom rätt bra dokumenterade, det gick då rätt bra att förstå dessfunktion.

Jag hade nu en applikation med ett grafiskt interface, som kunde flyttakataloger, läsa och skriva till och från ett exceldokument. En sak jag tycktemig sakna då var ett sätt att distribuera applikationen till alla användare. Ettalternativ till detta heter Inno Setup[3]. Med detta program följer även enIDE. För att skapa min installationsfil startade jag en “wizard”, eller guide,för att skapa denna. Efter guiden kunde jag sedan modifiera delar av instal-lationsprogrammet.

När jag sedan gick in i testfasen av programmet stötte jag på stor patrull.Hemma gick det bra att köra det och dess funktioner fungerade som domskulle. Men när jag sedan började testa skarpt på företagets miljö blev det

13

Page 19: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

tvärstopp. Det gick inte flytta katalogerna och klientdatorerna kom inte åtexcelfilen. Jag fick då tillåtelse att flytta excelfilen vilket löste det problemet.Men det gick fortfarande inte att flytta katalogerna. Men då min tid höll påatt rinna ut hann jag inte med att felsöka detta helt. Det jag tror var attteckenkodningen av någon anledning inte stämde överens med programmets.Eftersom katalognamnen innehöll specialtecken som ÅÄÖ fungerade det intesom tänkt.

Jag tycker att jag lärt mig massor av detta arbete. Framförallt att det ären god idé att ha lite erfarenhet av att programmera applikationer. En saksom jag skulle lagt ner mer tid på var hela planeringen, nu blev egentligen detmesta improviserat. Men att ha skrivit upp en projektplan, kollat upp vadsom hade behövts av Python för att klara alla funktioner, hade varit mycketi värde. Problem som att Python Excel modulerna inte var kompatibla medPython 3.2 hade upptäckts direkt och sparat mycket tid. Applikationen gåri sitt nuvarande utförande inte att köra på företaget och jag tror inte helleratt det finns någon möjlighet att slutföra det just nu.

14

Page 20: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

5 Källförteckning

1. Python Programming Language - Official Website, Python SoftwareFoundation, 2011, Hämtad 01 Juni 2011 från:http://www.python.org

2. Eclipse Downloads, The Eclipse Foundation, Hämtad 01 Juni 2011 från:http://www.eclipse.org

3. Inno Setup, jrsoftware.org, Hämtad 01 Juni 2011 från:http://www.jrsoftware.org/isinfo.php

4. Python Excel modules, http://www.python-excel.org/, Hämtad 04 Juni2011 från:http://pypi.python.org/pypi/

5. Google, www.google.com, Hämtad 26 Juni 2011 från:http://www.google.com

15

Page 21: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

6 Bilagor

6.1 Bilaga 1MainWin class object, innehåller alla widgets, variabler och funktioner för huvudfönstret.Från NDProd_main.py

class MainWin:"""Innehåller hela programfönstret och alla variabler som används."""def __init__(self, master):

""" Initieringsfunktionen för fönstret.Anropar funktionen "init" som skapar MainFrame,samt Frame1, 2 och 3 med innehåll."""

##-- Kataloger som ska finnas i workingDirself.setPath = {

1:’1. Kombi’,2:’2. Kablage’,3:’3. Apparatskåp’,4:’4. Elfördelning’,6:’6. Administration Fakuteringsunderlag’}

##-- Lista på vilka kolumner som ska läsas av i Exceldokumentet.self.colID = {

0:’TVO’,1:’OrderNr’,2:’Kund’,12:’LeveransDag’}

##-- Sökväg till excelfil.self.excelFile = ’’

##-- Variablerself.SetOrderFolder = IntVar()self.OrderFolderList = StringVar()self.UserFolderList = StringVar()self.currentUser = StringVar()self.orderFinishedVar = StringVar()self.packageWeightVar = StringVar()self.testedOKVar = StringVar()

##-- String Variabler för infoLabelself.TVO = StringVar()self.OrderNr = StringVar()self.Kund = StringVar()self.LeveransDag = StringVar()

self.OrderFolder = ’’self.UserFolder = ’’self.currentUserFolder = ’’self.workDir = ’’self.currentUserSign = ’’

##-- Initieringsfunktion för Fönstret anropas här.self.init(master)

16

Page 22: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

def init(self, master):"""Initieringsfunktion för allt innehåll i huvudfönstret."""mainframe = self.mainframe = Frame(master)mainframe.grid(column=0, row=0, padx=10, pady=10, sticky=(N, S, E, W))

##-- FRAME 1 --##self.Frame1 = Frame1 = Frame(mainframe)Frame1.grid(column=0, row=0, sticky=(W, E, N, S))Frame1.columnconfigure(2, weight=3)##-- FRAME 1 innehåll --##self.nd_logo = nd_logo = PhotoImage(file=’images/norr-don.gif’)self.logo = logo = Label(self.Frame1, relief=GROOVE, image=nd_logo)logo.grid(column=0, row=0, columnspan=3)

##-- blank frame under logoblankframe1 = Frame(Frame1, height=20)blankframe1.grid(column=0, row=1, columnspan=3)##-------------------------------------------------------------------------

##-- blank frame mellan chooseUserButton & chooseUserFrameblankframe6 = Frame(self.Frame1, width=5)blankframe6.grid(column=1, row=2, sticky=(W))##-------------------------------------------------------------------------

##-- Knapp som anropar funktionen för att välja användareself.chooseUserButton = button1 = Button(

self.Frame1,text=’Välj Användare’,command=self.setUser)

button1.grid(column=0, row=2, ipadx=2, sticky=(W, E, N))self.updateUserFolderButton = button2 = Button(

self.Frame1,text=’Uppdatera Katalog’,command=self.UpdateUserFolder)

button2.grid(column=0, row=3, ipadx=2, sticky=(W,E,N))

##-- LabelFrameself.chooseUserFrame = chooseUserFrame = LabelFrame(

self.Frame1,text=’Vald Användare’)

chooseUserFrame.grid(column=2, row=2, rowspan=2, sticky=(W, E))##-- Label som visar vald användareself.UserLabel = UserLabel = Label(

self.chooseUserFrame,textvariable=self.currentUser)

UserLabel.grid(column=0, row=0, padx=5, sticky=(W, E))

blankframe2 = Frame(Frame1, height=10)blankframe2.grid(column=0, row=3, columnspan=3)##-------------------------------------------------------------------------

##-- FRAME 2 --##self.Frame2 = Frame2 = Frame(mainframe)Frame2.grid(column=0, row=1, sticky=(W, E, N, S))Frame2.grid_columnconfigure(0, weight=0)Frame2.grid_columnconfigure(1, weight=0)

17

Page 23: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

Frame2.grid_columnconfigure(2, weight=1)

##-- FRAME 2 CONTENTS --####-- LabelFrame2, ramLabelFrame2 = LabelFrame(Frame2, text=’Välj Order’)LabelFrame2.grid(column=0, row=0, ipadx=5, ipady=5, sticky=(W, N))

"""Frame med radiobuttons för att välja Orderkatalog"""radioFrame = Frame(LabelFrame2)radioFrame.grid(column=0, row=0, rowspan=2, sticky=(W))##-- Dictionary med value, radiobutton namn och text.radios = {

0:[’radio1’, ’Kombi’],1:[’radio2’, ’Kablage’],2:[’radio3’, ’Apparatskåp’],3:[’radio4’, ’Elfördelning’]}

##-- For-loop som genererar radiobuttons.vals = 1for rowid, label in radios.items():

label[0] = Radiobutton(radioFrame,text=label[1],variable=self.SetOrderFolder,value=vals,command=self.UpdateOrderFolder).grid(

column=0,row=rowid,padx=5,sticky=(W))

vals += 1

"""Ram med vilka ordrar som finns i vald orderkatalog,samt "välj orderkatalog" radioknappar och "välj order" knapp"""self.orderlistFrame = orderlistFrame = Frame(

LabelFrame2,borderwidth=1,relief=SUNKEN)

orderlistFrame.configure(background="white")orderlistFrame.grid(column=2, row=0, sticky=(N))#-- Scrollist för OrderList ListboxorderlistScrollbar = Scrollbar(

orderlistFrame,orient=VERTICAL)

#-- OrderList med Ordrar från vald orderkatalog (radiobuttons)self.OrderList = OrderList = Listbox(

orderlistFrame,listvariable=self.OrderFolderList,borderwidth=0,activestyle="none",

18

Page 24: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

highlightthickness=0,width=4,height=5,yscrollcommand=orderlistScrollbar.set)

##-- Klick på listitem visar info om ordern, hämtas från excelfilen.OrderList.bind(’<ButtonRelease-1>’, self.onOrderHighlight)

#-- Positionering för OrderList samt scrollbar till OrderList.OrderList.grid(column=0, row=0, padx=5, pady=5, sticky=(W, E))orderlistScrollbar.config(command=OrderList.yview)orderlistScrollbar.grid(column=1, row=0, sticky=(N, S))

##-- Knapp för att flytta Order till Användarkatalog,##-- använder funktionen move2user för detta.self.MoveButton = MoveButton = Button(

LabelFrame2,text=’Välj Order’,command=self.move2user)

MoveButton.grid(column=2, row=1, sticky=(N, W, E))##-- SLUT LABELFRAME2 --##

blankframe3 = Frame(LabelFrame2, width=15)##--------------------------------------------------blankframe3.grid(column=1, row=0, sticky=(W,E))

##-- INFOLABELFRAME --##"""Informationsruta, värden hämtas från ExcelFilbaserat på markerad order i chooseOrderList"""self.infoLabelFrame = infoLabelFrame = LabelFrame(Frame2, text=’Order Info’,)infoLabelFrame.grid(column=2, row=0, padx=5, sticky=(W,E,S,N))self.infoFrame = infoFrame = Frame(infoLabelFrame)infoFrame.grid(column=0, row=0, padx=5, pady=15, sticky=(W))self.variablesFrame = variablesFrame = Frame(infoLabelFrame)variablesFrame.grid(column=1, row=0, pady=15, sticky=(W))

self.infoLabels()

blankframe2 = Frame(Frame2, height=10)blankframe2.grid(column=0, row=1, columnspan=3)##----------------------------------------------------------

## FRAME 3 ##self.Frame3 = Frame3 = Frame(mainframe)Frame3.grid(column=0, row=2, sticky=(W, E))

self.LabelFrame3 = LabelFrame3 = LabelFrame(Frame3,text=’Påbörjade Ordrar’)

LabelFrame3.grid(column=0, row=0, ipadx=5, ipady=5, sticky=(W,E,N))

blankframe4 = Frame(LabelFrame3, height=5)blankframe4.grid(column=0, row=0, sticky=(N))##------------------------------------------------------------self.userlistFrame = userlistFrame = Frame(

LabelFrame3,

19

Page 25: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

borderwidth=1,relief=SUNKEN)

userlistFrame.configure(background="white")userlistFrame.grid(column=0, row=1, padx=5, sticky=(N))

userlistScrollbar = Scrollbar(userlistFrame,orient=VERTICAL)

self.UserList = UserList = Listbox(userlistFrame,listvariable=self.UserFolderList,borderwidth=0,activestyle="none",highlightthickness=0,width=4,height=5,yscrollcommand=userlistScrollbar.set)

UserList.grid(column=0, row=0, padx=5, pady=5, sticky=(W))UserList.bind(’<ButtonRelease-1>’, self.setDate)userlistScrollbar.config(command=UserList.yview)userlistScrollbar.grid(column=1, row=0, sticky=(N, S))

containerFrame = Frame(LabelFrame3)containerFrame.grid(column=1, row=1, ipadx=5, ipady=5, sticky=(N, S, E, W))InfoLabel = Label(

containerFrame,text=’När en order är klar, markera den på listan och tryck "KLAR"’,wraplength=120,anchor=W)

InfoLabel.grid(column=0, row=0, padx=10, sticky=(W, N, S, E))self.finishedOrderButton = button2 = Button(

containerFrame,text=’KLAR’,command=self.move2fakt)

button2.grid(column=0, row=1, padx=10)"""valuesFrame innehåller Entries som fylls i excelfilen."""self.valuesFrame = valuesFrame = Frame(LabelFrame3)valuesFrame.grid(column=2, row=0, rowspan=2, sticky=(W,N,S,E))

self.orderFinished = Label(valuesFrame,text=’Order Klar: ’,anchor=E).grid(

column=2,row=0,sticky=E)

self.orderFinishedEntry = Entry(valuesFrame,textvariable=self.orderFinishedVar,width=10,justify=CENTER).grid(

column=3,

20

Page 26: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

row=0,sticky=W)

self.packageWeight = Label(valuesFrame,text=’Vikt i kg: ’,anchor=E).grid(

column=2,row=1,sticky=E)

self.packageWeightEntry = Entry(valuesFrame,textvariable=self.packageWeightVar,width=10,justify=CENTER).grid(

column=3,row=1,sticky=W)

self.testedOK = Label(valuesFrame,text=’Test: ’,anchor=E).grid(

column=2,row=2,sticky=E)

self.testedOKEntry = Entry(valuesFrame,textvariable=self.testedOKVar,width=10,justify=CENTER).grid(

column=3,row=2,sticky=W)

root.update_idletasks()

for child in self.mainframe.winfo_children():child.grid_configure(padx=5, pady=5)

def infoLabels(self):"""GENERERAR LABELS FÖR ATT VISA INFO OM ORDERDETTA GÖRS MHA EN FOR-LOOP & ETT DICTIONARY"""infoList = {

0:[’varTVO’, self.TVO, ’infoTVO’, ’TVO: ’],1:[’varOrderNr’,self.OrderNr, ’infoOrderNr’, ’OrderNr: ’],2:[’varKund’,self.Kund, ’infoKund’, ’Kund: ’],3:[’varLevDag’, self.LeveransDag, ’infoLevDag’, ’LeveransDag: ’]}

for rowx, label in infoList.items():label[0] = Label(self.variablesFrame, textvariable=label[1], fg=’#f00’)

21

Page 27: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

label[0].grid(column=0, row=rowx, sticky=(W))label[2] = Label(self.infoFrame, text=label[3], anchor=E)label[2].grid(column=1, row=rowx, sticky=(E))

def clearEntries(self):""" Rensar Entries efter att ordern är klar """self.orderFinishedVar.set(’’)self.packageWeightVar.set(’’)self.testedOKVar.set(’’)

def setDate(self, event):"""Sätter automatiskt dagens datum i self.orderFinishedEntry"""currentDate = str(date.today())currentDate = currentDate.split(’-’)[-1]self.orderFinishedVar.set(currentDate)self.onOrderHighlight(event)

def onOrderToUserfolder(self):"""Funktion som anropas av move2user för att flytta order till montörens katalog.Den fyller sedan in dagens datum samt vilken montör som påbörjade arbetet i excelfilen."""currentDate = str(date.today())currentDate = currentDate.split(’-’)[-1]cellsToWrite = {

7:self.currentUserSign,8:currentDate}

orderInfo = readExcel(cellsToWrite)selection = self.OrderList.curselection()

if tkMessageBox.askokcancel(title=’Verkligen klar?’,message=’Vill du verkligen flytta Ordern till \

%s och skriva till Exceldokumentet?’ % (self.currentUser.get())) == True:

if len(selection) == 1:value = int(selection[0])Order = str(self.OrderFolder[value])try:

if orderInfo.readDok(self.excelFile, Order, ’1’) == True:return True

except Exception as error:tkMessageBox.showerror(title=’ERROR’, message=error)

else:return False, ’Aborted’

def onOrderFinished(self):"""Hämtar info från Entrylabels och skickardessa att skrivas till excelfil"""var1 = str(self.orderFinishedVar.get())var2 = str(self.packageWeightVar.get())var3 = str(self.testedOKVar.get())try:

for string in (var1, var2, var3):

22

Page 28: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

if string == ’’:question = tkMessageBox.askokcancel(

’Empty MessageBox’,message=’En eller flera textrutor är ej ifyllda’)

if question == True:break

else:return False

else:pass

##-- Anger vilka celler som ska skrivas till samt skickar##-- med dessa vid definitionen av orderInfo.cellsToWrite = {9:var1, 10:var2, 11:var3}orderInfo = readExcel(cellsToWrite)selection = self.UserList.curselection()

if tkMessageBox.askokcancel(title=’Verkligen klar?’,message=’Vill du verkligen flytta Ordern och skriva till Exceldokumentet?’) == True:if len(selection) == 1:

value = int(selection[0])Order = str(self.UserFolder[value])if orderInfo.readDok(self.excelFile, Order, ’1’) == True:

return True

else:tkMessageBox.showerror(title=’Avbröts’, message=’Avbröts av användaren!’)

except Exception as error:tkMessageBox.showerror(title=’Error’, message=error)

def orderSel(self):"""Kollar vilken variabel som markerats i User- eller OrderList.Returnerar sel1[0] och 1 för OrderList, sel2[0], 2 för UserList"""sel1 = self.OrderList.curselection()sel2 = self.UserList.curselection()

if len(sel1) == 1:return sel1[0], 1

else:return sel2[0], 2

def onOrderHighlight(self, event):"""Hämtar information om Order i columner angivna i self.colID"""selection = self.orderSel()orderInfo = readExcel(self.colID)

if len(selection[0]) == 1:value = int(selection[0])

if selection[1] == 1:Order = str(self.OrderFolder[value])

else:Order = str(self.UserFolder[value])

orderInfo.readDok(self.excelFile, Order, ’0’)

23

Page 29: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

if len(orderInfo.variables) == 0:self.TVO.set(’’)self.OrderNr.set(’’)self.Kund.set(’’)self.LeveransDag.set(’’)

else:for key, value in orderInfo.variables.items():

if key == 0:self.TVO.set(value)

if key == 1:self.OrderNr.set(value)

if key == 2:self.Kund.set(value)

if key == 12:self.LeveransDag.set(value)

def setUser(self):""" Öppnar dialogruta för att välja användare """userSelect(root)

def noUser(self):""" Ifall ingen användare är vald när en katalog ska

flyttas anropas denna funktion av move2user och move2fakt """if tkMessageBox.askokcancel(

title=’Välj Användare Först!’,message=’Tryck OK för att välja användare’) == True:self.setUser()

else: pass

def move2user(self):"""Funktion för att flytta ordermapp till användarens katalogKontrollerar först ifall en användare har valts."""if self.currentUser.get() == ’’:

self.noUser()

else:selection = self.OrderList.curselection()

if len(selection) == 1:value = int(selection[0])Order = self.OrderFolder[value]OrderFolder = self.setPath[self.SetOrderFolder.get()]

##-- Genererar sökvägen till den mapp som ska flyttassourceFolder = os.path.join(self.workDir, OrderFolder, Order)

##-- Flyttar mappen till Montörens egen mapptry:

if self.onOrderToUserfolder() == True:shutil.move(sourceFolder, self.currentUserFolder)tkMessageBox.showinfo(

title=’Flyttade Order’,message=’Flyttade %s till %s’ % (Order, self.currentUser.get()))

self.UpdateUserFolder()self.UpdateOrderFolder()

except Exception as error:tkMessageBox.showerror(title=’ERROR’, message=error)

24

Page 30: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

else:return

def move2fakt(self):"""Flyttar färdig order till faktureringsunderlagsmappensamt skriver till excelfilen information från Entry boxarna."""if self.currentUser.get() == ’’:

self.noUser()

else:selection = self.UserList.curselection()

if len(selection) == 1:value = int(selection[0])Order = self.UserFolder[value]TargetFolder = os.path.join(self.workDir, self.setPath[6])

##-- Genererar sökvägen till den mapp som ska flyttassourceFolder = os.path.join(self.currentUserFolder, Order)

##-- Flyttar mappen till Montörens egen mapp##-- och skriver sedan till excelfilentry:

if self.onOrderFinished() == True:shutil.move(sourceFolder, TargetFolder)

##-- Uppdaterar Listboxarna och tar bort entries.self.UpdateUserFolder()self.clearEntries()

except Exception as error:tkMessageBox.showerror(title=’Error’, message=error)

else:return

def UpdateOrderFolder(self):""" Uppdaterar Orderkatalog listboxen """value = self.SetOrderFolder.get()self.OrderFolder = tuple(

os.listdir(os.path.join(

self.workDir,self.setPath[value])

))

self.OrderFolderList.set(self.OrderFolder)

def UpdateUserFolder(self):""" Uppdaterar Användarkatalog listboxen """self.UserFolder = tuple(

os.listdir(self.currentUserFolder)

)self.UserFolderList.set(

self.UserFolder)

25

Page 31: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

6.2 Bilaga 2Python class object för att läsa och skriva configfil.(Från NDProd_main.py:)

class configFile:"""Objekt för att läsa och skriva till config fil."""def __init__(self):

self.config = ConfigParser.SafeConfigParser()

def read(self, configFile):"""Läser från config fil"""try:

self.config.read(configFile)main.currentUser.set(self.config.get(’Directories’, ’user’))main.currentUserFolder = self.config.get(’Directories’, ’userfolder’)main.workDir = self.config.get(’Directories’, ’workingdir’)main.excelFile = self.config.get(’Directories’, ’excelpath’)main.currentUserSign = self.config.get(’Directories’, ’usersign’)main.UpdateUserFolder()

except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):pass

def writeToFile(self):""" Skriver till filen """with open(’NDProd.cfg’, ’w’) as configfile:

self.config.write(configfile)

def write(self):"""Sätter vilka värden som ska skrivas till config fil."""if self.config.has_section(’Directories’):

self.config.set(’Directories’, ’workingdir’, main.workDir)self.config.set(’Directories’, ’user’, main.currentUser.get())self.config.set(’Directories’, ’userfolder’, main.currentUserFolder)self.config.set(’Directories’, ’excelpath’, main.excelFile)self.config.set(’Directories’, ’usersign’, main.currentUserSign)self.writeToFile()root.destroy()

else:""" Skapar sektion ifall den inte finns """self.config.add_section(’Directories’)self.writeToFile()self.write()

26

Page 32: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

6.3 Bilaga 3Initieringsfunktion för applikationen.(Från NDProd_main.py)

"""Initieringsfunktion för applikationen"""if __name__ == ’__main__’:

config = configFile()

root = Tk()root.title("Norr-Don Produktion")root.iconwindow()root.protocol("WM_DELETE_WINDOW", config.write) #Vid avslut, skriv till config.root.wm_iconbitmap(’images/cable.ico’)root.resizable(width=FALSE, height=FALSE)root.geometry(’+250+200’)

##-- Anropar MainWin för att bygga upp huvudfönstret.main = MainWin(root)

##-- Uppdaterar värden från .cfg filtry:

config.read(’NDProd.cfg’)if main.excelFile == ’’:

main.excelFile = tkFileDialog.askopenfilename(filetypes=[(’excel files’, ’.xls*’)],title=’Specifiera Exceldokument’)

##-- Kollar ifall excelfilen går öppna.open(main.excelFile, ’r’)

except (WindowsError, IOError):##-- Öppnar dialogruta för att välja excelfil vid error.main.excelFile = tkFileDialog.askopenfilename()

##-- Frågar efter bassökväg.askBaseDir()##-- Startar applikationenroot.mainloop()

27

Page 33: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

6.4 Bilaga 4Klass som används för att välja bassökväg via dialogruta.(Från NDProd_main.py)

class askBaseDir():"""Kontrollerar ifall sökvägen kan nås, eller innehåller rätt kataloger.Uppnås inte dessa mål frågar den efter ny sökväg."""def __init__(self):

try:#-- Kollar ifall sökvägen finns genom att försöka lista filer i sökvägen.

os.listdir(main.workDir)

#-- Vid exception öppnas en inforuta med felmeddelandet och#-- sedan dialogruta för att välja sökväg.except Exception as error:

message = str(error)+’\n Tryck OK för att välja sökväg’tkMessageBox.showerror(title=’Error’, message=message)main.workDir = str(tkFileDialog.askdirectory())

#-- Skickar workDir strängen till funktionen validateDirectory#-- för att kontrollera att alla kataloger finns i sökvägenif main.workDir == ’’:

workDir = str(tkFileDialog.askdirectory())validDir = self.validateDirectory(workDir)

#-- Om användaren trycker Avbryt i dialogrutan där#-- sökväg väljs öppnas ed MessageBox med ett felmeddelande.if workDir == ’’:

ask = tkMessageBox.askokcancel(title=’Felaktig sökväg’,message=’Tryck OK för att välja sökväg, AVBRYT för att avsluta’)

if ask == False:root.destroy() #-- Avslutar applikationen.

else:askBaseDir()

##-- Ifall inte alla kataloger finns i sökvägen öppnas en MessageBox med ett felmeddelande.if validDir == False:

tkMessageBox.showerror(title=’Ogiltig sökväg’,message=’En eller flera Orderkataloger saknas eller Fel sökväg, Välj igen!’)

askBaseDir()else:

main.workDir = workDirelse:

#-- Kollar ifall nuvarande sökväg innehåller rätt kataloger.if self.validateDirectory(main.workDir) == True:

passelse:

workDir = str(tkFileDialog.askdirectory())askBaseDir(workDir)

28

Page 34: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

def validateDirectory(self, directory):"""Funktion för att kontrollera att rätt kataloger finns i sökvägen.main.setPath innehåller vilka kataloger som ska finnas där."""for dirs in main.setPath.values():

if dirs in os.listdir(directory):return True

else:return False

29

Page 35: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

6.5 Bilaga 5Python class object för att läsa och skriva exceldokumentet.(Från excelMod.py:)

# -*- coding: cp1252 -*-

import xlrdimport xlwtfrom xlwt import easyxfimport xlutils.copy as xlutilsimport tkMessageBox

class readExcel:def __init__(self, colID):

self.colID = colIDself.variables={}

def readDok(self, excelFile, orderNr, command):try:

self.excFile = xlrd.open_workbook(excelFile, formatting_info=True)self.excelFile = excelFileif self.readFile(orderNr, command) == True:

return True

except Exception as error:tkMessageBox.showerror(title=’ERROR’, message=error)

def readFile(self, orderNr, command):try:

""" Itererar över antalet flikar i excelfilen """for index in range(self.excFile.nsheets):

sheet = self.excFile.sheet_by_index(index)""" Itererar raderna i varje flik. """for rowIndex in range(sheet.nrows):

""" Kollar ifall orderNr finns på rad x, kolumn 0 """if orderNr in str(sheet.cell_value(rowIndex, 0)):

""" Kollar om cellen på rad x, kolumn 13 är ifylld """if str(sheet.cell_value(rowIndex, 13)) == ’’:

"""Är den tom skickas data vidare antingen för att läsas (0)eller skrivas (1) till exceldokumentet.True returneras ifall funktionen lyckades."""if int(command) == 0:

if self.setVariables(sheet, rowIndex) == True:return True

if int(command) == 1:if self.writeExcel(sheet, index, rowIndex) == True:

return True

else:pass

else:pass

except Exception as error:print error

def setVariables(self, sheet, rowIndex):""" Itererar colID dictionary vilken innehåller de kolumner som ska skrivas till """for col in self.colID.keys():

30

Page 36: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

"""Om datat i cellen är float konverteras den till en integeroch sedan till sträng. Detta läggs sedan till variables dictionaryn."""if type(sheet.cell_value(rowIndex, col)) == type(1.1):

cell = str(int(sheet.cell_value(rowIndex, col)))

if col == 12:cell = cell+’ ’+str(sheet.name)self.variables[col] = cell

else:self.variables[col] = cell

else:self.variables[col] = str(sheet.cell_value(rowIndex, col))

def writeExcel(self, sheet, index, rowIndex):"""sheet = Vilken flik som innehåller ordernumret.index = Indexnr på fliken med ordernumret.rowIndex = Vilken rad ordernumret finns på."""File = xlutils.copy(self.excFile) #-- Kopierar data i excelfil till ny workbook.Sheet = File.get_sheet(index) #-- Den flik som ska redigeras

style = easyxf(’borders: left thin, right thin, top thin, bottom thin;’’font: name Arial, bold true, height 240;’’alignment: horizontal center;’)

"""itererar över dictionaryn med de kolumner som ska skrivas tilldessa läggs till den nya workbooken."""for col, value in self.colID.items():

Sheet.write(rowIndex, col, value, style)try:

""" Sparar den nya excelfilen """File.save(self.excelFile)tkMessageBox.showinfo(

title=’Värden skrevs till cell’,message=’Skrivning till excelfil lyckades!’)

return Trueexcept Exception as error:

tkMessageBox.showerror(title=’Error’, message=error)

31

Page 37: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

6.6 Bilaga 6Python class object, ritar upp fönster för att välja användare(Från excelMod.py:)

class userSelect():"""Öppnar ett fönster för att välja Användare.Genererar användarna från katalogerna som börjar med ’5.’

Då kan användare läggas till i efterhand utan att bråka med scriptet."""

def __init__(self, parent):

self.top = top = Toplevel()top.title(’Välj Användare’)top.transient(parent)top.resizable(width=FALSE, height=FALSE)self.UserVar = IntVar()self.users = {}self.labels = []

self.Frames()

self.radiobuttons()self.buttons()

top.grab_set()

top.protocol("WM_DELETE_WINDOW", self.Cancel)

top.geometry("+%d+%d" % (parent.winfo_rootx() + 50,parent.winfo_rooty() + 50))

def Frames(self):self.UserFrame = Frame(self.top)self.UserFrame.grid(column=0, row=0, columnspan=2, sticky=(W, S, E, N))

self.ButtonFrame = Frame(self.top)self.ButtonFrame.grid(column=0, row=1, sticky=(W, S, E, N))

def radiobuttons(self):"""Anropar ’generateUsers’ för att generera användarna som kan väljas bland.Utifrån vad som returneras genererar den sedan fram radiobuttons för varje användare."""users, radio, labels = self.generateUsers()self.labels = labelsself.users = usersfor value, directory in users.items():

radio[value] = Radiobutton(self.UserFrame,text=labels[value],variable=self.UserVar,value=value).grid(

column=0,row=value,sticky=(W))

32

Page 38: EXAMENSARBETE - DiVA portalltu.diva-portal.org/smash/get/diva2:1030317/FULLTEXT02.pdf · 2016. 10. 4. · "excelMod.py" innehåller en klass jag använder för att läsa och skriva

Andreas GustavssonLTU SkellefteåDatornätverk 120HP

Förbättrad OrderhanteringExamensarbete 7,5HP

def buttons(self):"""OK - väljer den markerade användarenCANCEL - stänger ner rutan."""self.ok = Button(

self.ButtonFrame,text=’OK’,command=self.setUser)

self.ok.grid(column=0, row=0, pady=5, padx=10, sticky=(W))self.cancel = Button(

self.ButtonFrame,text=’Cancel’,command=self.Cancel)

self.cancel.grid(column=1, row=0, pady=5, padx=5, sticky=(E))

def Cancel(self):self.top.destroy() # Stänger ner dialogrutan.

def setUser(self):"""Sätter variablerna i:1. main.currentUserSign (Användarens signering i exceldok)2. main.currentUser (Namn på användaren)3. main.currentUserFolder (Sökväg till användarens katalog)"""value = self.UserVar.get()main.currentUserSign = self.labels[value][:5]currentUser = self.labels[value] + ’ ( "’ + os.path.join(main.workDir, self.users[value]) + ’" )’

main.currentUser.set(currentUser)

main.currentUserFolder = os.path.join(main.workDir, self.users[value])

main.UpdateUserFolder()self.top.destroy()

def generateUsers(self):"""Genererar vilka användare som kan väljas mellan"""userlist = {}radiolist = []labellist = []value = 0for i in os.listdir(main.workDir):

if ’5. ’ in i:userlist[value] = iradiolist.append(’radio’ + str(value))temp = i.split(’ ’)[-1]labellist.append(temp[0] + str.lower(temp[1:]))value += 1

return userlist, radiolist, labellist

33