IN3405 - Bachelorproject
Factureringsproces
Hidde Boomsma 1174371
Elger Lambert 1154273 18 juli 2008
Technische Universiteit Delft Faculteit EWI Technische Informatica
Examen Commissie Yom Schutte Arjen Schwarz Bernard Sodoyer Hans-Gerhard Gross
2 .
3
Voorwoord Studenten die Technische Informatica aan de Technische Universiteit Delft studeren moeten ter afronding van hun Bachelor zelfstandig een opdracht voor een extern bedrijf of organisatie uitvoeren. Dit document bevat een verslag van ons Bachelor-eindproject. De opdracht is uitgevoerd bij het bedrijf Hostnet in Amsterdam in een periode van tien weken tussen april en juni 2008. Wij willen graag Yom Schutte en Arjen Schwarz hartelijk danken voor hun begeleiding binnen het bedrijf. Ook Bernard Sodoyer en Hans-Gerhard Gross van de Technische Universiteit Delft zijn wij zeer dankbaar voor hun begeleiding voor het gehele project. Amsterdam, juni 2008 Elger Lambert en Hidde Boomsma
4 .
5
Samenvatting De opdracht bestond uit het koppelen van het factureringsproces aan een nieuwe productenindeling. Alle andere interne applicaties maakten al gebruik van de nieuwe structuur. Om uniformiteit, platformonafhankelijkheid en onderhoudbaarheid te bewerkstelligen hebben we er voor gekozen het factureringsproces opnieuw te ontwerpen en implementeren. We hebben het in dezelfde taal geprogrammeerd als de andere applicaties binnen Hostnet, het bestaande proces was geschreven in een andere taal. Voor het verkrijgen van de requirements hebben we voornamelijk gebruikgemaakt van interviews met medewerkers binnen Hostnet. Dit was ook de enige mogelijkheid omdat er nauwelijks technische informatie over het oude syteem beschikbaar was. Alle requirements hebben we ingedeeld volgens de MoSCoW methode. We hebben uiteindelijk alle Musts en Shoulds kunnen verwezenlijken. Om het ontwerp duidelijk te presenteren naar Hostnet hebben we gekozen om hun stijl te gebruiken en de processen in flowcharts weer te geven. Voordat we aan de implementatie begonnen, hebben we ook nog klassen en volgordediagrammen en een dataflow-diagram gemaakt. De implementatie zelf verliep redelijk voorspoedig. Wel hebben we ongeveer veertig procent van deze tijd gebruikt voor het vergelijken van de uitvoer van het nieuwe en oude systeem. We kunnen concluderen dat we in korte tijd veel werk hebben verzet. De extra motivatie die we kregen doordat het eindresultaat van onze opdracht daadwerkelijk in gebruik genomen gaat worden en de vriendelijke medewerkers van Hostnet heeft hier zeker bij geholpen.
6
Inhoudsopgave 1 Inleiding
9
2 Probleemstelling en analyse 2.1 Vooronderzoek . . . . . . . . . . . . . . . . . . . . 2.2 Probleemstelling . . . . . . . . . . . . . . . . . . . 2.3 Requirements . . . . . . . . . . . . . . . . . . . . . 2.3.1 Functionele requirements factureringsproces 2.3.2 Kortingen correct verwerken . . . . . . . . . 2.3.3 Opmaak van de Factuur . . . . . . . . . . . 2.3.4 Niet-functionele eis . . . . . . . . . . . . . . 2.4 Werkomgeving . . . . . . . . . . . . . . . . . . . . 2.5 Planning . . . . . . . . . . . . . . . . . . . . . . . . 2.5.1 Voorgenomen planning . . . . . . . . . . . . 2.5.2 Werkelijke planning . . . . . . . . . . . . . 2.6 Samenvatting . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
11 11 12 12 12 13 13 14 14 16 16 17 17
3 Ontwerp 3.1 Gobaal ontwerp . . . . . . . . 3.1.1 Contracten ophalen . 3.1.2 Factuur aanmaken . . 3.1.3 Factuurregels . . . . . 3.1.4 Factuuropmaak . . . . 3.1.5 Facturen versturen . . 3.1.6 Contracten aanpassen 3.1.7 Renewal run . . . . . 3.1.8 Kortingen . . . . . . . 3.2 Gedetailleerd ontwerp . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
19 19 19 20 20 20 21 21 21 21 22
4 Implementatie 4.1 Problemen en de oplossingen . . . . 4.1.1 Unit-tests . . . . . . . . . . . 4.1.2 Implementeren losse functies 4.1.3 Regressie testen . . . . . . . . 4.2 Integration en Operational testing . 4.2.1 Samenvatting . . . . . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
23 23 23 25 26 27 27
. . . . . . . . . .
7
. . . . . . . . . .
. . . . . . . . . .
8
INHOUDSOPGAVE
5 Evaluatie 5.1 Behaalde resultaat 5.2 Requirements . . . 5.3 Tijdsplanning . . . 5.4 Opdracht . . . . . 5.5 Kennis . . . . . . . 5.6 Conclusie . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
6 Aanbevelingen 6.1 Korting koppelen aan basisproducten . . . . 6.2 Contractendatabases synchroniseren . . . . 6.3 Samenvoegen van alle Contractendatabases 6.4 Laatste functionaliteit van het oude systeem 7 Bijlagen 7.1 Bijlagen 7.2 Bijlagen 7.3 Bijlagen 7.4 Bijlagen 7.5 Bijlagen 7.6 Bijlagen 7.7 Bijlagen 7.8 Bijlagen 7.9 Bijlagen
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
29 29 29 30 30 31 31
. . . . . . . . . . . . . . . . . . . . . . . . herontwerpen
. . . .
. . . .
. . . .
. . . .
33 33 33 33 34
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
37 38 42 51 61 62 63 65 67 69
. . . . . .
. . . . . .
. . . . . .
. . . . . .
A: Plan van Aanpak . . . . . . . . . . . . B: Onderzoeksverslag . . . . . . . . . . . C: Flowcharts . . . . . . . . . . . . . . . D: Entity-relationship Diagram . . . . . . E: Klassendiagram . . . . . . . . . . . . . F: Volgorde diagram . . . . . . . . . . . . G: Notulen flowcharts-presentatie . . . . H: Notulen kortingen vergadering . . . . I: Managing Hierarchical Data in MySQL
. . . . . .
. . . . . . . . .
. . . . . .
. . . . . . . . .
. . . . . .
. . . . . . . . .
. . . . . . . . .
Hoofdstuk 1
Inleiding Hostnet biedt alle benodigdheden voor het hosten van een website aan; van domeinnamen en webhosting tot dedicated servers. Zo’n tien jaar geleden toen Hostnet begon, werden de klanten- en productgegevens opgeslagen in excelsheets. Sindsdien is het bedrijf, de hoeveelheid klanten en producten, flink gegroeid. De excel-sheets zijn vervangen door datastructuren en er werd een systeem ontwikkeld binnen Microsoft Access om administratie te assisteren. Dit systeem, geschreven met procedurele code, is over de jaren uitgebreid en aangepast om met het bedrijf mee te groeien. Hierdoor is de code moeilijk te begrijpen, waardoor de betrouwbaarheid en onderhoudbaarheid van het hele systeem gedaald is. Tegenwoordig ontwikkelt Hostnet haar software met een object-geori¨enteerde taal binnen een framework met genormaliseerde databases. Hostnet is echter nog steeds afhankelijk van de oude processen waarvan niet meer goed begrepen wordt hoe ze werken. In 2006 is er besloten dat de structuur van de productendatabase uitgebreid moest worden. Inmiddels is dit gebeurd, echter weten de oude processen de nieuwe functionaliteiten niet te benutten. Het voornaamste probleem is dat er geen facturen automatisch gegenereerd kunnen worden voor de nieuwe producten. Het huidige systeem moet dus herontworpen worden. Er moet zowel rekening gehouden worden met het systeem als met de werknemers en er mag geen functionaliteit verloren gaan, gezien het bedrijf hier afhankelijk van is. Veel meer dan dit was ons niet bekend toen wij bij Hostnet begonnen. Gedurende het gehele ontwikkelproces hebben we ons laten begeleiden door het V-model [11] om gestructureerd te achterhalen wat er precies van ons gevraagd werd, dit vervolgens te realiseren en het hele ontwikkelproces goed te testen. In Figuur 1.1 is het V-model te zien. Het ontwikkelproces verloopt van linksboven naar beneden en dan terug omhoog langs de rechterzijde van de ’V’. De requirements-analyse wordt behandeld in hoofdstuk 2, Probleemstelling en Analyse. Zowel high level design als detailed specifications komen aan de orde in hoofdstuk 3, ontwerp. Hoofdstuk 4, implementatie, komt overeen met coding. In dit hoofdstuk word ook testing besproken. We eindigen met een evaluatie, conclusie en aanbevelingen.
9
10
HOOFDSTUK 1. INLEIDING
Figuur 1.1: Het V-Model
Hoofdstuk 2
Probleemstelling en analyse In dit hoofdstuk zullen we onze probleemstelling en de aan ons vereiste requirements presenteren. Ook zullen we de omgeving waarbinnen we het project hebben ontwikkeld omschrijven en onze planning laten zien.
2.1
Vooronderzoek
Voordat we konden beginnen met het ontwerpen van een nieuw systeem, moest het duidelijk zijn wat er van ons gevraagd werd, wat onze opties waren om dit te realiseren, of dit haalbaar was binnen de beschikbare tijd en wat de eventuele kosten zouden zijn. Moet er een heel nieuw systeem ontwikkeld worden of is het mogelijk het huidige systeem verder aan te passen en uit te breiden zodat het voldoet aan de eisen? Wat zijn de voordelen die gerealiseerd kunnen worden? De eerste twee weken hebben we de tijd genomen om onderzoek te plegen om de kennis op te doen om deze vragen te kunnen beantwoorden. Voor een verslag van deze periode verwijzen we naar bijlage B. Hierin is uitgebreid te lezen wat de overwegingen zijn geweest. We hebben onderzocht wat de invloed zou zijn voor de gebruikers van het systeem, zoals de interface, platformonafhankelijkheid, de begrijpbaarheid en uitbreidbaarheid van de code. Wat de implicaties voor ons zelf zouden zijn, zoals het wel of niet gebruik kunnen maken van ondersteunende software en de hoeveelheid werk. Ook hebben we rekening gehouden met het huidige systeem, uniformiteit, limitaties en welke voordelen het nieuwe systeem zou kunnen bieden. Hier wordt enkel de gekozen richting verder uitgewerkt. Deze richting is bepaald tijdens een vergadering met onze opdrachtgever en begeleiders waar wij de verschillende mogelijkheden en onze aanbeveling hebben gepresenteerd. We hebben aanbevolen het facturatieproces volledig te herontwerpen. Hierbij konden wij garantie geven van een robuust en goed getest systeem. Ook gaf het ons de vrijheid om zelf te beslissen welke programmeertaal we willen gebruiken. Hostnet is akkoord gegaan met onze aanbeveling. Onze probleemstelling was hiermee concreet gemaakt. 11
12
HOOFDSTUK 2. PROBLEEMSTELLING EN ANALYSE
2.2
Probleemstelling
Aan ons is gevraagd om een volledig nieuw systeem te ontwerpen en implementeren. Het is een herontwerp van het bestaande facturatie proces. Het verschil is dat de gegevens uit de nieuwe productenstructuur gehaald moeten worden en de begrijpbaarheid van het systeem significant moet verbeteren. Alle functionaliteiten die in het huidige systeem zitten, moeten ook in het nieuwe systeem aanwezig zijn. De facturen voor klanten van Hostnet moeten vrijwel hetzelfde blijven.
2.3
Requirements
In deze paragraaf presenteren we de aan ons gestelde eisen. Deze eisen hebben wij aan de hand van ons onderzoek en interviews opgesteld. Met behulp van deze interviews hebben wij proberen te achterhalen wat de functionaliteit van het huidige facturatieproces is. Ons systeem zou deze functionaliteit op zijn minst moeten evenaren. Ook als er wensen aan het licht kwamen tijdens vergaderingen werden deze door ons genoteerd. We hebben de eisen prioriteiten gegeven met de hulp van MoSCoW. Hierbij staat de M voor Must, de S voor Should en de C voor Could. De prioriteit gaat van hoog, lager, laagst. Deze lijst hebben we vervolgens geverifieerd met onze begeleiders.
2.3.1
Functionele requirements factureringsproces
M Factureringsproces moet de nieuwe productenstructuur benutten. M Geen functionaliteit verloren gaan ten opzichten van huidige systeem. M Contracten die status ’verwijdert’ hebben, mogen niet gefactureerd worden. S Rekening houden met verschillende betalingswijzen. M Rekening houden met buitenlandse klanten. Deze facturen moeten per e-mail verstuurd worden. S Rekening houden met de verschillende btw-percentages voor klanten binnen en buiten de EU en bedrijven met een btw-nummer. M Contracten die verlopen zijn moeten automatisch verlengd worden. C Verlengde contracten moeten pas verstuurd worden als de einddatum daadwerkelijk verstreken is. C Het verlengen van contracten moet een paar keer per maand uitgevoerd kunnen worden. S Wenselijk zou zijn als het systeem in ´e´en keer zowel alle nieuwe als periodieke facturen kan aanmaken. S Ook wenselijk is als zowel producten met als zonder logingegevens tegelijkertijd gefactureerd kunnen worden.
2.3. REQUIREMENTS
13
C Als de klant niet op tijd betaalt, moet er automatisch opnieuw een factuur gestuurd worden. C Factuuropmaak makkelijker kunnen aanpassen. C Factuur per post of per e-mail versturen aan de hand van de voorkeur van de klant. C Zichtbaar maken voor administratie hoe een factuur is ontvangen, per email, of per post.
S Facturen die meer dan ´e´en pagina lang zijn apart versturen naar DMDR.
C Herinnerings facturen mogen de originele niet overschrijven.
2.3.2
Kortingen correct verwerken
M Er mag nooit een creditfactuur verstuurd worden door het systeem. C Creditfacturen opvangen en doorsturen naar administratie ter controle. C Handmatig gemaakte creditfacturen moeten wel geaccepteerd worden. S Naast periodieke korting moet het ook mogelijk zijn om een eenmalige korting op een periodiek bedrag te plaatsen. S Het moet mogelijk zijn om absolute dan wel procentuele kortingen te geven. M Korting op Contract-, Product- en Klantniveau. S Korting op Soortniveau. M Korting op Contractniveau sluit andere kortingen uit. M Anders hoogste korting andere niveaus. S Combinatie van een eenmalige korting en een periodieke korting alleen mogelijk als deze kortingen allebei van hetzelfde niveau zijn.
2.3.3
Opmaak van de Factuur
S Overeenkomen met huidige factuur. C Engelse facturen voor buitenlandse klanten. C Meerdere talen voor verschillende buitenlandse klanten.
14
HOOFDSTUK 2. PROBLEEMSTELLING EN ANALYSE
2.3.4
Niet-functionele eis
M Bij het eindproduct is het van belang dat het duidelijk is hoe de kortingen ge¨ımplementeerd zijn, zodat zowel administratie, sales en de programmeurs begrijpen waarom welke korting op de factuur komt te staan. M Minimaal 200 facturen per 15 minuten verwerken. M Binnen de beschikbare geheugenlimiet van 1 gigabyte blijven. M Het systeem moet op laag niveau goed begrijpbaar zijn. Van belang is dat het in de toekomst goed onderhouden en eventueel aangepast kan worden.
2.4
Werkomgeving
Nu het duidelijk is wat er gedaan moet worden, is de volgende stap beslissen hoe we dit gaan doen. Welke hardware en software is er tot onze beschikking en is dit geschikt voor onze probleemstelling? Hostnet had twee werkplekken naast elkaar beschikbaar gemaakt op de Application Managment (AM) afdeling. We bevonden ons dus te midden van de andere programmeurs binnen Hostnet. Hierdoor konden we, als we vragen hadden, snel de antwoorden krijgen. Beide computers draaiden Linux, Ubuntu. We waren allebei vertrouwd genoeg met Linux dat dit geen probleem voor ons was. Het oude factureringsproces is geschreven binnen een Access-applicatie dat binnen Hostnet bekendstaat als Hostbase. Het merendeel van de applicaties zijn echter geschreven in PHP5 binnen een framework genaamd Symfony. PHP5 is een objectgeori¨enteerde taal zonder types en met veel standaard functies. Het is een veel gebruikte taal voor webapplicaties en bovendien gratis beschikbaar voor commercieel gebruik. Een goede handleiding en voorbeelden zijn te vinden op www.php.net. PHP draait als module in de veel gebruikte Apache Webserver. Ook is er een document beschikbaar genaamd coden bij hostnet.odt, hierin wordt duidelijk uitgelegd wat de vereisten zijn om te voldoen aan de codestyle van Hostnet. Hierin zijn ook alle constructies en veel voorkomende codeblokken uitgewerkt. [5, 6] Symfony is een framework voor PHP5 en is ontwikkeld door het Franse Sensiolabs. Het framework biedt een splitsing in Model, View en Control. Hiernaast bevat het ook ondersteuning voor zowel unit- als functionele tests. In het model gedeelte van de MVC-structuur zit de object-relationeel mapping en de database abstractie. In de View-laag komt alle opmaak op basis van templates. In deze laag zijn ook veel hulpfuncties te vinden die het leven gemakkelijker maken en veel voorkomende taken wat betreft opmaak en Javascript, maar ook Ajax te vereenvoudigen. Symfony wordt onder andere gebruikt door Askeet en Yahoo Bookmarks. [2, 9] Met oog op de vereiste om de begrijpbaarheid van ons systeem te maximaliseren was het een voor de hand liggende keuze om ons systeem ook in PHP5 binnen het Symfony-framework te ontwikkelen. Hiermee versterken we de uniformiteit en ontwikkelde we ons systeem in een, voor Hostnet en haar werknemers, vertrouwde omgeving. Nog een voordeel is dat we ons systeem makkelijker kunnen integreren en zelfs waar mogelijk bestaande code kunnen gebruiken.
2.4. WERKOMGEVING
15
Omdat Hidde al een jaar parttime voor Hostnet werkte, was hij ook zeer vertrouwd om software binnen deze omgeving te ontwikkelen. Gedurende onze studie op de TU Delft werken en leren we echter vooral omgaan met Java, een object geori¨enteerde taal net als PHP5. Met deze kennis en Hidde’s ervaring was het mogelijk de nog ontbrekende basiskennis snel over te dragen aan Elger, waardoor we relatief weinig tijd nodig hebben gehad om de benodigde kennis op te doen. De database maakt gebruik van MySQL4. MySQL4 is een relationeel database management systeem (DBMS). MySQL is vrij verkrijgbaar onder de GPLlicentie. MySQL is vanuit PHP gemakkelijk te benaderen door de library die al jaren wordt meegeleverd met PHP. Ook is er in Symfony ondersteuning voor MySQL. Mocht de database, of data in de database, aangepast moeten worden dan is dit mogenlijk via PHPMyAdmin. Dankzij de kennis opgedaan tijdens onze studie zijn we bekend met MySQL-databases en is het voor ons geen probleem om hiermee te werken. Alles wat we produceren, wordt in een subversion repository opgeslagen. Subversion (SVN) [8] is een versiebeheersysteem afgeleid van concurrent versions system (CVS) [1]. Alle bestanden worden centraal op een server opgeslagen. Eenieder kan wijzigingen doorvoeren. Als er gelijktijdig gewijzigd wordt, worden de twee documenten automatisch samengevoegd. Mocht een sectie tegelijkertijd zijn bewerkt, treedt er een conflict op en is handmatig ingrijpen vereist. Door het gebruik van subversion hebben we altijd een back-up en kunnen we ook terugbladeren naar eerdere versies als er toch iets overboord is gezet wat later nuttig blijkt. Hostnet ontwikkelt al jaren haar eigen software voor intern gebruik. Aanpassingen maken en nieuwe applicaties integreren met het bestaande systeem gebeurt regelmatig. Om dit elke keer met zo min mogelijk problemen te doen verlopen, is hier het volgende voor verzonnen. Het daadwerkelijke systeem waar Hostnet afhankelijk van is, draait op de productieserver. Daarnaast is er ook een acceptatie- en een ontwikkelserver waar aangepaste versies van het systeem, dat op de productieserver draait, op draaien. De namen van de servers spreken eigenlijk al voor zich. Elke programmeur binnen Hostnet heeft een eigen server waar een kopie van de ontwikkelserver op draait. Op deze manier is het mogelijk dat alle programmeurs onafhankelijk van elkaar software ontwikkelen. Met behulp van SVN kunnen aanpassingen en toevoegingen aangebracht worden op de ontwikkelserver zodat deze dan weer beschikbaar zijn voor anderen. Als een hele applicatie ontwikkeld is, kan deze overgeplaatst worden naar de acceptatieserver. Deze server dient om te testen of er problemen gaan ontstaan als de huidige versie van de applicatie daadwerkelijk in gebruik wordt genomen. Omdat er zoveel verschillende mensen invloed hebben op de ontwikkelserver is het mogelijk iets over het hoofd te zien bij het overzetten. Voor het schrijven van lange stukken code wordt gebruikgemaakt van Eclipse. Voor kleine aanpassingen gebruiken we Vim [10]. Een bekende tekst-editor in Linux. Hiermee is het mogelijk om snel de gevolgen van aanpassingen te zien zonder tussenkomst van versiebeheer. Alle documenten voor Hostnet moeten beschikbaar zijn in OpenOffice-formaat. Een groot deel van de verslagen zullen wij schrijven in Latex. Latex is een opmaaktaal die bestanden in platte tekst opslaat. Ook kunnen documenten gemakkelijk gesplitst worden en is er een goed systeem om referenties bij te houden. De editor die we hierbij gebruiken is Kile (KDE Integrated Latex Edi-
16
HOOFDSTUK 2. PROBLEEMSTELLING EN ANALYSE
tor). Aangezien de documenten uit platte tekst bestaat, kunnen ze gemakkelijk in een versiebeheer, zoals SVN, worden opgenomen en is gelijktijdig bewerken mogelijk. [3, 7] Voor de gemakkelijke stroomdiagrammen is OpenOffice toereikend, maar voor het maken van echte UML-diagrammen is het toch wenselijk een programma te hebben dat meer functionaliteit biedt. Umbrello is hiervoor beschikbaar. Een simpel programma voor Ubuntu. Umbrello bevat niet erg veel mogelijkheden, maar ruim voldoende voor het maken van de basisdiagrammen. Umbrello kan ook exporteren naar PHP5-code. Het maken van UML-diagrammen is geen vereiste van Hostnet, maar deze hebben we gemaakt om onszelf te assisteren.
2.5
Planning
Het allereerste wat we deden, nog voor het onderzoek was, een Plan van Aanpak schrijven. Het volledige document is te zien in bijlage A. Deel hiervan was het vastleggen van een planning.
2.5.1
Voorgenomen planning
Het ontwikkelproces hebben we globaal verdeeld in drie onderdelen, onderzoek, ontwerp en implementatie. Daarbij hadden we ook een planning gemaakt voor het eind verslag. Onderzoek Een ori¨enterende fase, zowel wennen aan onze nieuwe werkomgeving als informatie verwerven waren van belang. Deze informatie zal ons assisteren in het maken van ontwerp beslissingen, . Ontwerp Nadat er voldoende onderzoek gedaan is, kunnen we met die kennis een ontwerp maken. Implementatie Met het ontwerp in handen kunnen de functies, gespecificeerd in de ontwerpdocumenten, daadwerkelijk geschreven worden. Eindverslag Het schrijven van korte stukjes voor het eindverslag gedurende het ontwikkelproces scheelt een hoop tijd en stress aan het einde. Om die reden hebben we gepland elke vrijdagmiddag aan het eindverslag te werken. Zie Figuur 2.1 voor onze planning. Ook hebben we aangegeven welke weken wij bij Hostnet aanwezig zullen zijn.
2.6. SAMENVATTING
17
Figuur 2.1: Grafische overzicht van de planning
2.5.2
Werkelijke planning
Het werkelijke gebruik van tijd verschilde niet erg veel van de geplande hoeveelheid tijd. Ook de data waarop we bepaalde aspecten af wouden hebben, kwam redelijk overeen. Wat wel een flinke strop was, is dat Hostnet getroffen werd door een grote storing waardoor Hidde bijna een week is kwijtgeraakt aan het oplossen van andere problemen. Doordat Hidde al bij Hostnet werkte, was de eerste stap om informatie te verzamelen en ons te ori¨enteren eigenlijk veel korter dan de twee geplande weken. Dit heeft ons later weer ruimte opgeleverd in de planning waardoor we deze grotendeels gehaald hebben. Later bleek ook dat het zo mooi op schema blijven ten koste was gegaan van de tijd waarin we het eindverslag zouden schrijven. Dit heeft dus achteraf ook meer tijd gekost dan gepland.
2.6
Samenvatting
In de eerste twee weken ori¨enteerden we ons op de opdracht en verzamelde we voldoende kennis om deze opdracht aan te kunnen. Vervolgens is er tijd ingeroosterd voor de requirements, ontwerp, implementatietests, implementatie code en acceptance testing. De planning is hier en daar verstoord maar uiteindelijk hebben we ons er toch grotendeels aan kunnen houden. Met name omdat we door de al aanwezige kennis erg snel op gang konden komen.
18
HOOFDSTUK 2. PROBLEEMSTELLING EN ANALYSE
Hoofdstuk 3
Ontwerp Nu het duidelijk is wat de vereisten zijn, kunnen we een ontwerp maken die deze eisen vervult. We zullen laten zien welke componenten het systeem bevat en de relaties ertussen beschrijven.
3.1
Gobaal ontwerp
Een belangrijke gebruiker van het facturatieproces is administratie. Om die reden vonden wij het belangrijk hen te betrekken bij het ontwerpproces. Daar zij geen programmeurs zijn, hebben wij ons ontwerp met behulp van flowcharts gepresenteerd, zodat het ook voor hen duidelijk is. Deze flowcharts zijn te vinden in bijlage C. Ook hebben we een entity-relationship diagram (ERD) [4] geconstrueerd om inzicht te krijgen waar in de databases de relevante data staat (Bijlage D). Een groot voordeel vergeleken met het oude proces is dat we het nu in een objectgeori¨enteerde taal, in plaats van een procedurele taal schrijven. Dit geeft ons de mogelijkheid verschillende componenten duidelijke, zowel op hoog als laag niveau, te onderscheiden. In de flowchart is te zien dat we vijf verschillende componenten onderscheiden, tevens wordt er ook al aangegeven waar de data vandaan moet komen. De flowcharts laten zien welke acties en beslissingen er per onderdeel genomen worden. De vijf componenten van het facturatieproces die we onderscheiden zijn: contracten ophalen, factuur aanmaken, factuur regels, factuur opmaak, facturen versturen. Daarnaast is er nog een los proces genaamd de renewal run, we zullen deze en elk component van het facturatieproces apart beschrijven. Omdat het bepalen welke kortingen er op de factuur moeten komen staan redelijk complex is, zal deze, ook al maakt het deel uit van het factuurregel-component, apart uitgelegd worden.
3.1.1
Contracten ophalen
Elk contract heeft een begin-, een eind- en een factuurdatum. Bij het maken van een nieuw contract wordt er geen datum ingevuld voor de eind- en factuurdatum. Hieraan zijn nieuwe contracten makkelijk te herkennen, deze moeten meegenomen worden voor facturatie. Deze data worden door het facturatieproces ingevuld, hierover straks meer (zie 3.1.6 Contract aanpassen). De andere 19
20
HOOFDSTUK 3. ONTWERP
contracten die ook meegenomen moeten worden voor facturatie zijn contracten waarbij de factuurdatum overeenkomt met de huidige datum en deze kleiner is dan de einddatum. Dit zijn contracten die periodiek gefactureerd worden en waarvan een periode net verstreken is. Op het moment dat de einddatum verstreken is, moet dit contract uiteraard niet gefactureerd worden. Hetzelfde geldt voor als de begindatum nog niet geweest is. Alle contracten die opgehaald zijn voor facturatie, worden per persoon bij elkaar verzameld.
3.1.2
Factuur aanmaken
Het is de bedoeling dat als een klant meerdere contracten heeft die op dezelfde dag worden gefactureerd dat deze allemaal op ´e´en factuur komen te staan. Het is natuurlijk niet de bedoeling dat een klant een aparte factuur opgestuurd krijgt voor elke domeinnaam die hij op een dag heeft geregistreerd bijvoorbeeld. Hier wordt dus gecontroleerd of er al een factuur aanwezig is voor een klant, als dit het geval is moet het contract er aan toegevoegd worden, anders moet er een nieuwe factuur gemaakt worden.
3.1.3
Factuurregels
Met factuurregels wordt bedoeld: de tekst die aangeeft welk product er is gekocht, van wanneer tot wanneer het contract loopt en wat het kost. Ook de kortingsregels worden hier aangemaakt. Voor de overzichtelijkheid is dit proces losgekoppeld van de rest van de factuuropmaak. Het is van groot belang dat dit proces zonder fouten verloopt. Mocht dit wel gebeuren dan krijgt de klant een factuur opgestuurd met verkeerde bedragen of zelfs voor verkeerde producten. Er word gecontroleerd of dit de eerste factuur is, mocht dit zo zijn en er zijn eenmalige kosten en of kortingen aan het contract verbonden, wordt voor elk een aparte regel aangemaakt. Vervolgens worden er regels aangemaakt voor de periodieke kosten en eventuele kortingen. Bij het bepalen welke korting op de factuur komt te staan, komt het een en ander bij te kijken, we zullen hier later uitgebreid op terugkomen (zie 3.1.8).
3.1.4
Factuuropmaak
Dit proces cre¨eert daadwerkelijk de factuur, in pdf-formaat. Er zijn verschillende factoren die invloed hebben wat er precies op een factuur komt te staan. De gegevens die er altijd opgezet moeten worden, is de naam, adres en plaats van de contactpersoon. En uiteraard ook de factuurregels die aangemaakt waren in het vorige proces. Als de factuur voor een bedrijf is, moet de naam van het bedrijf ook vermeld worden. Daarnaast moet er gekeken worden naar de betaalwijze. Er zijn drie mogelijkheden: acceptgiro, automatische incasso en iDeal. Elk heeft zijn eigen tekst onderaan de factuur. Als de factuur bestemd is voor een buitenlandse klant, worden deze teksten in het Engels geschreven. Ook wordt er gekeken hoeveel btw de klant moet betalen, om tot slot de totale kosten te berekenen.
3.1. GOBAAL ONTWERP
3.1.5
21
Facturen versturen
Nu de facturen gemaakt zijn, moeten ze nog bezorgd worden. Dit gebeurt of via een e-mail naar een extern bedrijf, DMDR, die er vervolgens voor zorgt dat de factuur per post bezorgd wordt. Het alternatief is dat de factuur direct per e-mail naar de klant wordt gestuurd. De laatste optie geldt altijd voor buitenlandse klanten en herinneringsfacturen. De rest gaat in het algemeen via DMDR en dan via de post. DMDR ontvangt ´e´en e-mail met daarin als bijlage een paar pdf-bestanden. In elk staat een lijst van facturen. Nieuwe contracten staan in een apart bestand, omdat hier een brief aan toegevoegd moet worden door DMDR. Ook facturen die meer dan ´e´en pagina lang zijn, staan in een apart bestand, dit voor het gemak voor DMDR. Er is nog een component, maar deze was niet in de flowcharts meegenomen. Namelijk, het aanpassen van de contracten nadat de facturen zijn gemaakt.
3.1.6
Contracten aanpassen
Voor de contracten waar nu een factuur voor is aangemaakt, moet voorkomen worden dat er niet nog een factuur wordt aangemaakt voor dezelfde periode. Daarom wordt de factuurdatum gewijzigd en opgeslagen in de database. Mocht er nog geen factuurdatum en einddatum aanwezig zijn, zoals het geval is bij nieuwe contracten, dan moeten deze ingevuld worden. Dit gebeurt aan de hand van de looptijd van het contract en de facturatieperiode, beiden zijn afhankelijk van het product.
3.1.7
Renewal run
Als een contract verlopen is, in andere woorden de einddatum is verstreken, wordt deze stilzwijgend verlengd. Tenzij de klant heeft aangegeven het contract te willen be¨eindigen. Voor het verlengen van contracten hebben we een proces ontwikkeld die los van het normale facturatieproces gestart moet worden. Dit proces is te zien op de zesde pagina van de flowcharts in bijlage C. Wat er gedaan wordt, is simpel. Als het contract verlopen is en niet opgezegd is door de klant dan wordt de einddatum verschoven aan de hand van de looptijd van het vorige contract. Als het gewijzigde contract wordt opgeslagen zal deze weer in aanmerking komen om opgehaald te worden door het factureringsproces. De eerste keer dat we de flowcharts presenteerden kwamen er een aantal punten aan de orde waar we rekening mee moesten houden. De notulen hiervan staan in bijlagen G. Het meest interessant was echter de discussie die ontstond rond om de door de klanten te ontvangen korting. Er werd besloten om nog een keer te vergaderen alleen dan ook met mensen van de sales en marketing afdeling erbij. De notulen van deze vergadering staan in bijlage H. Wat er toen besloten is, is als volgt.
3.1.8
Kortingen
Het was al bekend dat er vier verschillende niveaus moesten komen voor kortingen. Voorheen waren dit er overigens slechts drie. Kortingen op dit niveau is
22
HOOFDSTUK 3. ONTWERP
er nieuw bijgekomen. De discussie ontstond echter over de prioriteiten van de verschillende niveaus en welke combinaties mogelijk mochten zijn. Voorkomen moest worden dat het systeem regelmatig creditfacturen aan zou maken. De vier niveaus zijn: contract, product, klant en soort. Korting op contractniveau is een korting die gegeven wordt voor een specifiek contract, een overeenkomst tussen Hostnet en een klant voor een specifiek product. Korting op productniveau is een actiekorting voor een bepaald product. Deze geldt voor iedereen die dat product koopt. Korting op klantniveau maakt het mogelijk om producten, alle of een selectie, altijd met korting aan te bieden voor een individu. Soortniveau is vergelijkbaar, echter is de korting niet voor een individu, maar voor een groep klanten die in een bepaalde categorie vallen, zoals resellers. Uiteindelijk is er besloten dat als er korting op contractniveau gespecificeerd is, dat deze gekozen moet worden. Contractniveau overschrijft alle andere niveaus. De reden waarom hiervoor gekozen is, is omdat het de salesafdeling volledige controle geeft over de kosten van een contract zonder dat zij rekening hoeven te houden met de andere niveaus. Als er geen korting gespecificeerd is op contractniveau, moet het kortingsniveau geselecteerd worden die voor die facturatieperiode de meeste korting voor de klant opbrengt. Dit heeft bijvoorbeeld als gevolg, wanneer een reseller een product koopt waar een eenmalige actiekorting op zit, hij in eerste instantie deze eenmalige actiekorting ontvangt, ervan uitgaande dat deze korting hoger is. De volgende keer dat het contract gefactureerd wordt, ontvangt hij zijn periodieke resellers, soort niveau, korting. Voorheen ontvingen resellers slechts hun eigen korting en konden dus niet profiteren van speciale aanbiedingen op producten. Er is ook besloten dat de enige kortingen combinatie die is toegestaan, is zowel eenmalige als periodieke korting, maar slechts als deze beiden van het zelfde niveau zijn. Een andere verbetering die ons systeem biedt ten opzichte van het vorige is dat volgens de nieuwe wetgeving klanten binnen de EU en bedrijven zonder btw-nummer ook btw moeten betalen. Vroeger moesten slechts klanten binnen Nederland btw betalen. Het oude systeem onderscheidt binnen- en buitenlandse klanten en bepaalt aan de hand daarvan of ze btw moesten betalen. Dit is een goed voorbeeld dat demonstreert dat het oude systeem moeilijk te onderhouden en aan te passen is. Het schrijven van een functie die de btw bepaalt zoals gespecificeerd in de nieuwe wetgeving was voor ons niet moeilijk. Het oude systeem was echter nog steeds niet aangepast, omdat het te veel tijd zou kosten, gezien er geen werknemers meer zijn die vertrouwd zijn met het systeem.
3.2
Gedetailleerd ontwerp
Nu dat ons ontwerp geverifieerd was, konden we hiermee voortzetten. Voordat we begonnen aan de implementatie hebben we voor eigen gebruik een gedetailleerd ontwerp uitgewerkt. In bijlage E zijn het klassendiagram en in bijlage F de volgorde diagrammen die we gemaakt hebben, terug te vinden. Hiermee was de ontwerpfase afgerond.
Hoofdstuk 4
Implementatie Bij de implementatie wordt het eindproduct daadwerkelijk gemaakt, dit gebeurt aan de hand van het ontwerp. Tijdens de implementatiefase zijn we een beetje afgeweken van het V-model. Bij het V-model wordt de code pas getest nadat deze volledig ge¨ımplementeerd is. Onze voorkeur ging ernaar uit om ’test-driven’ te werk te gaan. Dit wil zeggen dat de test geschreven wordt voordat de functionaliteit word toegevoegd. Dit heeft het voordeel dat fouten in de code snel onderschept worden, waardoor de oorzaak relatief makkelijk terug te vinden en te verbeteren is. Zodoende zijn we telkens begonnen met het schrijven van unit-tests voordat we functionaliteiten toevoegden. In dit hoofdstuk zullen we bespreken welke problemen we zijn tegengekomen en de oplossingen die we hiervoor bedacht hebben.
4.1 4.1.1
Problemen en de oplossingen Unit-tests
Symfony maakt gebruik van het Lime testing framework voor PHP [9]. Hierdoor is het erg gemakkelijk om tests geautomatiseerd uit te voeren. De tests moeten wel eerst zelf geschreven worden. Deze testing framework biedt echter niet de mogelijkheid om primary-keys van databaserecords rechtstreeks in te vullen. Dit heeft zo zijn voordelen, data kan gerelateerd worden aan elkaar en het systeem zoekt dan zelf beschikbare sleutels op. Dit is echter onhandig als je records met specifieke eigenschappen wilt opvragen. Gelukkig is het mogelijk Symfony aan te passen. Het overerven van een klasse was voldoende om het gewenste gedrag toe te voegen. Het schrijven van de unit-tests hielp ons met twee aspecten. Het gaf ons inzicht van de gewenste functionaliteit voordat we deze probeerde te implementeren. Als de unit-test eenmaal geschreven zijn, is het heel makkelijk en snel om te testen of alles nog naar verwachting functioneert. Soms heeft het wijzigen van code een negatieve invloed op een ander deel waarvan je dat niet direct van verwacht of stomweg over het hoofd had gezien. Het controleren van de unit-tests na een wijziging maakte dit meteen duidelijk. De testmethodes die we gebruikt hebben, zijn doorgaans niet erg complex. Veel unit-tests controleren slechts of objecten goed opgeslagen en opgehaald kunnen worden uit de database. Echter de complexiteit die de verschillende 23
24
HOOFDSTUK 4. IMPLEMENTATIE
Figuur 4.1: Unit-test van de kortingen kortingniveaus met zich meebracht, maakte deze tests echt onmisbaar. Door de unit-test konden we duidelijk zien of de functionaliteit die bepaalt welke korting er op de factuur komt te staan, voldeed aan de eisen. In Figuur 4.1 is de uitvoer van die unit-tests van de kortigen te zien. Er zijn zoveel plekken waar het mis kan zijn gegaan als de korting niet correct wordt weergeven op een factuur, dat het niet practisch is om slechts naar de uitvoer te kijken. Het zegt erg weinig waar de fout is opgetreden, waardoor het lang zou duren om de fout te localiseren en te verhelpen. Het ophalen van contracten uit de database die gefactureerd moeten worden is in theorie niet heel lastig. Dit viel echter erg tegen. De oorzaak is het datamodel van de contracten. De contracten zijn verdeeld over drie databases die synchroon gehouden worden door een proces genaamd ImportExport. Verder zijn er voorheen velden uit het contractentabel misbruikt. Wat een simpel querie zou zijn bij een schone database neemt nu een half a4tje aan code in beslag. Met zoveel afhankelijkheden kan een fout snel optreden, een goede en grondige test was hier van belang. Alle mogelijke permutaties van contracten moesten gegenereerd worden. Al deze mogelijkheden zijn van een actie voorzien door zowel ons als administratie. Daarna zijn deze gegevens gebruikt in de test om te controleren of we niet te veel en ook niet te weinig contracten selecteren voor facturatie. Door ons systeem zo in te delen dat het wegschrijven van data op de ontwikkeldatabase gebeurde en het de data inlas van de productiedatabase konden we ons systeem parallel draaien aan het huidige systeem. Dit gaf ons de mogelijkheid de uitvoer en de facturen met elkaar te vergelijken en zo eventuele verschillen te identificeren. Door de contracten te analyseren die afweken, konden we inzicht krijgen wat hiervoor de verklaring was. Om vervolgens de nodige aanpassingen te maken zodat deze fouten niet weer zouden optreden.
4.1. PROBLEMEN EN DE OPLOSSINGEN
4.1.2
25
Implementeren losse functies
Na de tests hebben we eerst de kleinere functies ge¨ımplementeerd. Te beginnen met alle get- en set-methodes. Normaal gesproken worden deze automatisch gegenereerd door Symfony. De naamgeving van het oude model was echter soms dusdanig inconsistent of onduidelijk dat we een aantal methodes hebben geschreven om dit te verhelpen. De oude methodes zijn hiermee deprecated. Vervolgens hebben we de functionaliteit voor het berekenen van de kortingen gemaakt en de selectie van contracten waarvoor een factuur gemaakt moest worden. De code om pdf-facturen te maken van databaserecords bestond grotendeels al. Hierdoor konden we al vrij snel facturen genereren met ons systeem. In eerste instantie bevatte deze nog geen kortingen en de omschrijvingen waren ook nog niet helemaal in orde, maar hierdoor konden we wel duidelijk laten zien aan andere wat het systeem allemaal kon en wat nog moest gebeuren. Nadat de kortingen ge¨ımplementeerd waren, zijn we aan de interface begonnen. De interface hoefde slechts ´e´en knop te bevatten, om de facturatie te starten, om de functionaliteit van het oude systeem te evenaren. Om de gebruiker enig inzicht te geven in de voortgang van een facturatie-run hebben we ook een simpele voortgangsindicator toegevoegd. Dit zorgde echter wel voor een onverwachts probleem. De indicator wordt door middel van Ajax bijgewerkt. Er wordt dus om de aantal seconden een aanvraag naar de webserver gestuurd om de indicator van nieuwe informatie te voorzien. Omdat de facturatie-pagina veel processorkracht van de server vroeg, gaf de webserver pas weer antwoord nadat het hele facturatieproces klaar was. Hierdoor gaf de indicator niets weer. Door van het factureringsproces een batch-job te maken, wordt het als losstaand proces gestart op de server. Hierdoor kan de webserver blijven antwoorden aan de client die het factureringsproces gestart heeft. Het factureringsproces schrijft zijn voortgang naar een gemakkelijk leesbaar bestand op de harde schijf. Hierdoor kan door alle sessies gelijktijdig dezelfde voortgangsindicator worden weergegeven. Zie Figuur 4.2 voor het eindresultaat. In het huidige systeem word er slechts korting verbonden aan een specifiek product. Voor klant- en soortniveau hoefde we dus slechts een verband te leggen tussen een individu of groep met een specifiek product om te voldoen aan de eisen. Producten worden echter redelijk regelmatig be¨eindigd. Bijvoorbeeld als er een prijswijziging voor een product plaatsvindt wordt het product niet aangepast in de database, maar wordt het be¨eindigd en een identiek product aangemaakt met de nieuwe prijs. Dit geldt voor elke wijziging, de rede dat er een nieuw product word aangemaakt in plaats van het huidige product te wijziging heeft te maken met de statistieken die Hostnet bijhoudt. Om die reden hebben we ook onderzocht of we kortingen aan een basisproduct konden koppelen. De verschillende producten staan in een boomstructuur, momenteel zijn de verschillende producten aan elkaar geknoopt door middel van kind objecten met een ouder id. Om te controleren of er korting verbonden is aan een basis product, waaronder het product in kwestie valt, moet de boom stapsgewijs afgegaan worden. Een ineffici¨ent proces, gezien er per stap opnieuw een verbinding met het database moet worden gelegd. We hebben onderzocht of wij hierin verbetering konden brengen en hebben het volgende gevonden. De boom moet volledig doorlopen worden en op een slimme wijze een getal als linker en rechter grens aan elk product toegevoegd worden. Met behulp van deze grenzen kan een hele tak gemakkelijk opgevraagd
26
HOOFDSTUK 4. IMPLEMENTATIE
Figuur 4.2: Interface van ons facturatie proces worden. Deze tak bestaat uit basisproducten, er kan nu met gemak gekeken worden of er korting aan een of meerdere van deze producten verbonden is. We hebben het artikel waarin uitgelegd wordt hoe deze alternatieve boomstructuur precies werkt en ge¨ımplementeerd moet worden, toegevoegd (zie Bijlage I). Later bleek dat er ook al een plugin voor Symfony bestond, compleet met unit-tests. De plugin is ge¨ımplementeerd aan de hand van hetzelfde artikel. Voor het verlengen van nog niet opgezegde contracten wordt de einddatum verzet zodat deze weer door het facturatieproces meegenomen wordt. Normaal gesproken zou dit met een SQL-querie kunnen, maar doordat we met drie databases te maken hebben die synchroon gehouden moeten worden, wordt er door middel van drie transacties voor gezorgd dat de wijzigingen in elke database wordt doorgevoerd. Bij nieuwe en verlengde contracten moet een begeleidende brief toegevoegd worden. Dit is een standaard brief en wordt door DMDR toegevoegd voordat de factuur naar de klant verstuurd wordt. Het moet dus duidelijk zijn welke facturen nieuw zijn en welke verlengd. Onze oplossing was om de batch job uit te breiden. In plaats van ´e´en bestand, met alle facturen onder elkaar, werden de verschillende soorten: nieuw, verlengd en normaal, in aparte bestanden opgeslagen die vervolgens als bijlagen per e-mail naar DMDR verstuurd worden.
4.1.3
Regressie testen
Vanaf het begin, al tijdens het maken van de ontwerp beslissingen, was het voor ons een belangrijk criterium of we de uitvoer van het huidige en ons nieuw systeem goed met elkaar konden vergelijken. Vanaf de derde week hadden we al de benodigde aanpassingen gemaakt zodat we ons systeem parallel aan, met
4.2. INTEGRATION EN OPERATIONAL TESTING
27
dezelfde invoer als, het huidige systeem konden draaien. Vanaf toen hebben we de facturen handmatig met elkaar kunnen vergelijken, zowel de opmaak als de inhoud van de facturen werden door ons vergeleken. In eerste instantie waren de verschillen veelal te verwijten aan fouten in ons systeem, maar na verloop van tijd waren de fouten voornamelijk te wijten aan synchronisatie problemen of corrupte data. Deze corrupte data hebben we telkens met de hand verbeterd. Ons systeem werkte op een gegeven moment zo goed dat onze uitvoer gebruikt werd als controle van het huidige systeem. Zo haalde ons systeem een aantal contracten boven water die in het verleden niet meegenomen waren voor facturatie. Deze klanten hebben indien het redelijk was alsnog een factuur ontvangen.
4.2
Integration en Operational testing
Dit zijn de laatste twee onderdelen van het V-model. De manier waarop Hostnet haar software ontwikkelt zorgt ervoor dat dit tijdens de implementatie grotendeels al getest wordt. De ontwikkelserver draait een kopie van het echte systeem. Dus ondanks ons systeem nog niet overgezet is naar de acceptatienog de productieserver is ons systeem wel al echt deel van het gehele systeem op de ontwikkelserver. De echte test komt weliswaar pas als ons systeem om de acceptatieserver wordt gezet, maar als het werkt op de ontwikkelserver dan moet het ook mogelijk zijn om alles werkend te krijgen op de acceptatieserver. Tijdens het regressie testen, hebben we regelmatig de uitvoer van ons systeem bekeken met anderen van Hostnet. Op die manier konden we verifi¨eren of een onderdeel van ons systeem volledig aan de vereisten voldeed. Zo nodig werden er aanpassingen gemaakt todat het hele systeem naar wens was.
4.2.1
Samenvatting
Al met al ging vooral het begin van de implementatie fase erg voorspoedig. Later liepen we tegen verschillende problemen aan waarvan slecht gesynchroniseerde databases en corrupte data de meeste problemen gaven. Maar al twee weken voor het einde van de stage hadden we een product in handen dat voor de dagelijkse facturatie minder fouten maakte dan het huidige systeem.
28
HOOFDSTUK 4. IMPLEMENTATIE
Hoofdstuk 5
Evaluatie Hier zullen we een evaluatie geven van onze stage. We evalueren wat we berijkt hebben, welke requirements nog niet gerealiseerd zijn, in hoeverre we ons aan de tijdsplanning hebben gehouden, wat we van de opdracht vonden en wat we geleerd hebben.
5.1
Behaalde resultaat
We hebben nu een platformonafhankelijke applicatie gemaakt die geschreven is in PHP5, de taal die door de ontwikkelaars binnen Hostnet wordt gebruikt. Daarnaast is alles in veel kleinere stukken opgedeeld. Dit komt de onderhoudbaarheid sterk ten goede. Het nieuwe systeem geeft voor alle bestaande contracten dezelfde uitvoer als het huidige systeem. De facturen zijn nu in het alom ondersteunde pdf-formaat en niet meer in het Microsoft snapshot formaat. Het nieuwe systeem kan nu overweg met de nieuwe productenstructuur en maakt ook meteen gebruik van een genormaliseerde database in plaats van de oude kaartenbak waar het huidige facturatieproces nog gebruik van maakt. Er is geen functionaliteit verloren gegaan. Maar nog niet alle aanverwante taken zijn meteen overgenomen. Zo is bijvoorbeeld het sturen van een herinnering of een laatste betalingsverzoek nog niet herontworpen. Hier is echter niet de contractentabel uit de database voor nodig en zal dit onderdeel van het oude systeem nog steeds werken naast ons nieuw systeem wanneer het in gebruik genomen wordt.
5.2
Requirements
We hebben zowel alle musts en zelfs alle shoulds kunnen verwezelijken. De volgende punten zijn uiteindelijk niet ge¨ımplementeerd: C Verlengde contracten moeten pas verstuurd worden als de einddatum daadwerkelijk verstreken is. C Het verlengen van contracten moet een paar keer per maand uitgevoerd kunnen worden. 29
30
HOOFDSTUK 5. EVALUATIE C Als de klant niet op tijd betaalt, moet er automatisch opnieuw een factuur gestuurd worden. C Factuuropmaak makkelijker kunnen aanpassen. C Factuur per post of per e-mail versturen aan de hand van de voorkeur van de klant. C Zichtbaar maken voor administratie hoe een factuur is ontvangen, per e-mail, of per post. C Herinnerings facturen mogen de originele niet overschrijven. C Meerdere talen voor verschillende buitenlandse klanten
Het makkelijker kunnen wijzigen van de opmaak is nog een zeer omvangrijk punt maar zeker de moeite waard om naar te kijken. Dit omdat de code voor het cre¨eren van een pdf hergebruikte code is. Deze code is nog erg rommelig en verbruikt heel erg veel geheugen omdat alle objecten in het geheugen worden geladen en deze ruimte niet meer wordt vrijggegeven tot het einde van het script. Voor het verwerken van een grote hoeveelheid facturen kan het dus van belang zijn deze code te verbeteren.
5.3
Tijdsplanning
Tijdens onze stage heeft Hostnet last gehad van een ernstige storing. De storing heeft ervoor gezorgd dat het een aantal dagen niet mogelijk was om software te ontwikkelen. Ook nadat het ergste verholpen was, had beheer Hidde nodig om hun bijstaan. In de nasleep van de storing werd er ook nog regelmatig beroep op hem gedaan om te helpen. Hierdoor is er behoorlijk wat tijd verloren gegaan. Ondanks dat wisten we, wat betreft het ontwikkelen van ons systeem, toch redelijk op schema te blijven. Het ging echter wel ten koste van de hoeveelheid tijd die we wekelijks aan ons eindverslag hebben besteed. Na dat we klaar waren in Amsterdam was er nog een aanzienlijke hoeveelheid werk te doen voordat het verslag af was.
5.4
Opdracht
Door de grote hoeveelheid werk die de opdracht omhelste, was het een behoorlijke uitdaging. Het integreren van een nieuwe applicatie met een bestaand systeem brengt vaak ook complicaties met zich mee die moeilijk van te voren zijn te voorspellen. Mede dankzij Hiddes werkervaring bij Hostnet konden we snel van start gaan. Dit heeft ons zeker geholpen de hoeveelheid werk die van ons vereist was te leveren. De opdracht was extra boeiend voor ons omdat het vanaf het begin al duidelijk was dat Hostnet onze software werkelijk wou gaan gebruiken. Met de kennis dat we een echt product moesten leveren, is de motivatie snel al hoger en de inzet groter. De betrouwbaarheid van het facturatiesysteem is van groot belang. Als er allerlei verkeerde facturen naar klanten verzonden worden, schaadt dit het
5.5. KENNIS
31
imago van het bedrijf. Vandaar dat het goed testen van ons nieuwe systeem erg belangrijk was en een significant onderdeel van ons ontwikkelproces was. Doordat we met ons systeem uiteindelijk zelfs fouten wisten te vinden in het huidige systeem hebben we de vertrouwen van Hostnet alvast weten te winnen.
5.5
Kennis
Bij aanvang van het project hadden we natuurlijk al basiskennis op het gebied van software ontwikkelen en de bijbehorende processen. Over de specifieke software, omgevingen en de gebruikte programmeertaal binnen Hostnet bezat alleen Hidde al kennis. Ondanks Elger bij aanvang geen ervaring had bij Hostnet had hij de kennis achterstand snel ingehaald. Het doorlopen van het volledige ontwikkelproces van het begin tot het einde was een zeer waardevolle ervaring. Het heeft ons inzicht gegeven hoe lastig het is om vooraf daadwerkelijk alle requirements te achterhalen. De vergaderingen die we met alle betrokkenen hebben gehad om door te spreken wat er precies moest komen en waarin we onze voorstellen presenteerden hebben ons ook meer inzicht gegeven hoe niet-technici tegen een ontwikkeltraject aan kijken en wat zij verlangen. Binnen Hostnet wordt veel gebruikgemaakt van flowcharts in plaats van Unified Modeling Language (UML) diagrammen om processen inzichtelijk te maken. Er zijn ook nog een aantal diagrammen die op Data Flow Diagrams (DFD) lijken. Tijdens vergaderingen hebben we ervoor gekozen om de presentaties op de voor hen vertrouwde mannier te doen. Voor onze eigen ontwikkeling hebben we klassen- en volgordediagrammen gemaakt. We hebben ook voorzien in een DFD om duidelijk te krijgen welke databases in welke stap van het proces nodig zouden zijn. Klassen diagrammen zijn redelijk bekend binnen het bedrijf. Volgorde diagrammen, dataflow diagrammen, use cases en state charts kwamen alleen voor in documentatie van andere stageopdrachten die bij Hostnet uitgevoerd waren. Onze interface was dusdaanig beperkt dat het maken van use cases zwaar overbodig zouden zijn. Hostnet maakt steeds meer gebruik van UML, er zijn zelfs medewerkers gesponsord om hiervoor cursussen te volgen. Voor de grotere nieuwe projecten gebruikt Hostnet normaal de waterfall methodiek. Bij de kleinere dingen ontbreekt echter al snel de structuur. Wij waren vrij te kiezen welke methodiek we wilden gebruiken. Het V-model lijkt eigenlijk ook best wel op de waterfall methode.
5.6
Conclusie
Al met al was het een geslaagde stage met een goede samenwerking met Hostnet. Wij hebben het heel erg naar ons zin gehad bij Hostnet. Het was een waardevolle ervaring. Uiteindelijk gaan we deze zomer nog verder met het project om het nieuwe systeem in gebruik te kunnen nemen. Het was een prettige samenwerking met Sales, Administratie, Productontwikkeling, Beheer en natuurlijk Applicatie Management.
32
HOOFDSTUK 5. EVALUATIE
Hoofdstuk 6
Aanbevelingen Nadat een product is opgeleverd, zijn er vaak nog dingen waar geen tijd voor was of die netter of mooier gemaakt kunnen worden. Ook kunnen er nog obstakels overgebleven zijn die overkomen moeten worden voor het product succesvol in gebruik genomen kan worden. Soms kan het nodig zijn nog extra onderzoek te doen. Hieronder staan onze aanbevelingen ten aanzien van het door ons herziene facturatieproces.
6.1
Korting koppelen aan basisproducten
Op dit moment wordt de korting op klant- en soortniveau nog gegeven op een specifiek product. Het zou zeker toegevoegde functionaliteit zijn om het mogelijk te maken om de korting aan een basisproduct te koppelen. Om dit effici¨ent te kunnen doen moet het mogelijk zijn om met ´e´en database-querie een hele tak uit de productenboom te halen. Dit zou mogelijk zijn met behulp van een symfony plugin.
6.2
Contractendatabases synchroniseren
Het bestaan van drie verschillende databases, waarvan ´e´en genormaliseerd en de andere twee niet, leidt onherroepelijk tot verschillen. Op dit moment wordt gefactuureerd aan de hand van de niet-genormaliseerde Hostnet database. Het nieuwe factureringsproces factureert aan de hand van de wel genormaliseerde database. Bij de overgang is het echter van belang dat er geen verschillen meer tussen de databases zijn.
6.3
Samenvoegen van alle Contractendatabases
Een verderstrekkende aanbeveling dan de vorige is om de contractendatabases samen te voegen tot ´e´en. Dan kunnen er geen inconsistenties tussen de verschillende versies optreden en zijn veel synchronisatie fouten verleden tijd. Dit kan nadat de contracttabel in Hostbase niet meer wordt gebruikt gemakkelijk gedaan worden. De twee overgebleven MySQL-databases zouden gesynchro33
34
HOOFDSTUK 6. AANBEVELINGEN
niseerd kunnen worden d.m.v stored procedures. Dit heeft als grote voordeel de snelheid en het kunnen uitschakelen van de ImportExport.
6.4
Laatste functionaliteit van het oude systeem herontwerpen
Uiteindelijk zou het goed zijn om de laatste overgebleven functionaliteiten uit Hostbase over te nemen in Aurora zodat alle systemen binnen Hostnet in dezelfde taal zijn geschreven en gemakkelijk door alle ontwikkelaars onderhouden kunnen worden. Alle functionaliteiten zijn dan ook vanaf niet Windows pcs beschikbaar. Bovendien zal deze ook blijven werken als er een nieuwe versie van Access uit komt. Dit is met Hostbase helaas niet het geval.
Bibliografie [1] CVS. http://en.wikipedia.org/wiki/concurrent versions system, 2008. [2] Francois Zaninotto en Fabien Potencier. The Definitive Guide to Symfony. Springer-Verslag, New York, 1st, edition, 2007. [3] Tobias Oetiker en Hubert Partl en Irene Hyna en E. Schlegl. The Not So Short Introduction to Latex, 2008. http://tobi.oetiker.ch/lshort/lshort.pdf. [4] ERD. http://nl.wikipedia.org/wiki/erd, 2008. [5] Harry Fuecks. The PHP Anthology. Object Oriented PHP Solutions Volume I. Sitepoint, Collingwood, Australia, 1st, edition, 2003. [6] Harry Fuecks. The PHP Anthology. Object Oriented PHP Solutions Volume II. Sitepoint, Collingwood, Australia, 1st, edition, 2003. [7] Kile. http://kile.sourceforge.net/, 2008. [8] SVN. http://en.wikipedia.org/wiki/subversion %28software%29, 2008. [9] Symfony. http://www.symfony-project.org/, 2008. [10] Vim. http://www.vim.org/docs.php, 2008. [11] vmodel. http://nl.wikipedia.org/wiki/v-model, 2008.
35
36
BIBLIOGRAFIE
37
38
HOOFDSTUK 7. BIJLAGEN
Hoofdstuk 7
Bijlagen 7.1
Bijlagen A: Plan van Aanpak
Plan van aanpak Introductie Hostnet is een bedrijf, gevestigd in Amsterdam, dat online producten en diensten verkoopt. Zij bieden alles aan wat je nodig hebt voor het hosten van een website. Van domeinnamen en webhosting tot dedicated servers. Het bedrijf heeft een eigen software ontwikkelteam, beheer, webdesign, helpdesk- en sales afdeling. Gedurende de afgelopen tien jaar zijn de hoeveelheid klanten en producten van het bedrijf toegenomen. Het bestaande software werd telkens aangepast om de groei bij te benen. Recent zijn de productentabellen volledig vernieuwd, de structuur is volledig herdacht en geïmplementeerd in MySQL. Het oude systeem, dat nog met MsSQL werkt, kan nog niet alle voordelen van de nieuwe productenstructuur benutten. Momenteel worden de product gegevens telkens omgezet, dit proces wordt omschreven als het maken van een cirkel van een vierkant door er met een hamer op te slaan. Zoals deze omschrijving al aantoont, het is een grof proces dat niet altijd goed gaat. Opdracht Met begeleiding van het bestaande software ontwikkelteam waar wij tevens zelf deel uit zullen maken, is het onze opdracht om ervoor te zorgen dat de nieuwe productenstructuur volledig benut kan worden en het omzetten van verschillende datatabellen niet meer nodig zal zijn. Het is een bestaand en werkend systeem waar veranderingen in aangebracht moeten worden. Met het beslissen hoe we deze verandering tot stand gaan brengen, zullen we dus rekening moeten houden met het huidige systeem. Van essentieel belang is dat er geen functionaliteit verloren gaat gezien het bedrijf hier afhankelijk van is. Aanpak Gedurende het project zullen wij fulltime aanwezig zijn bij Hostnet. Dit houd in vijf dagen in de week van negen tot half zes. De eerste twee weken wordt besteed aan onderzoek. Het huidige systeem moet geanalyseerd worden voordat beslist kan worden hoe de benodigde aanpassingen gerealiseerd kunnen worden. Tevens moet er besloten worden welke werkomgeving, programmeertaal en methodiek geschikt zijn. Deze informatie zal gedocumenteerd worden in een onderzoeksverslag. In deze periode zal ook door middel van interviews en vergaderingen vastgesteld worden wat de verwachtingen en eisen zijn van de verschillende afdelingen binnen Hostnet. Na het onderzoek zal er een ontwerp gemaakt worden. Zowel flowcharts als klassediagrammen zullen hiervoor gebruikt worden. Op deze manier is het mogelijk om met zowel programmeurs als nietprogrammeurs goed te valideren of het ontwerp voldoet aan hun eisen. Als deze goedgekeurd is, zal er begonnen worden aan de implementatie. Tijdens en na afloop zal het systeem uitgebreid getest worden om te verifiëren of onze implementatie overeen komt met ons ontwerp. Ook zal er d.m.v prototypes feedback verworven worden. Na verloop van de stage zal ons software een periode parallel lopen met het huidige systeem om feedback te verzamelen en te analyseren om te garanderen dat onze software het huidige proces kan vervangen zonder problemen op te leveren.
7.1.
BIJLAGEN A: PLAN VAN AANPAK
39
Requirements (MoSCoW) Must: Aanpassingen mogen niet ten koste gaan van de huidige functionaliteit Het oude systeem moet de nieuwe productenstructuur volledig kunnen benutten Het factureringsproces is het belangrijkste proces dat gebruikmaakt van de productentabel en zou dus aangepast moeten worden. Het proces moet: Kortingen correct verwerken Rekening houden met buitenlandse klanten (factuur wordt per e-mail gestuurd) Contracten die verlopen, automatisch verlengen. Should: In een run alle eenmalige en periodieke facturen opsturen Rekening houden met verschillende betalingswijzen Rekening houden met de verschillende btw-percentages (binnen/buiten Nederland/Europa) Could: Als de klant niet op tijd betaalt moet er automatisch opnieuw een factuur gestuurd worden Engelse facturen voor buitenlandse klanten Meerdere talen voor verschillende buitenlandse klanten Factuuropmaak makkelijker kunnen aanpassen Per post of mail aan de hand van de voorkeur van de klant Projectinrichting De volgende OPAFIT aspecten komen aan de orde: • Organisatie o Harold Douwes Opdrachtgever o David Dijkstra Opdrachtgever o Yom Schutte Projectbegeleider o Arjen Schwarz Projectbegeleider • Personeel De door ons ontwikkelde software zal voor intern gebruik zijn. We zullen dus rekening moeten houden met alle medewerkers van Hostnet. • Administratieve procedures Al onze ondervindingen en beslissingen zullen gedocumenteerd worden in verschillende documenten gedurende het project. Er zal in ieder geval een plan van aanpak, een onderzoeken een eindverslag geschreven worden • Financiering De meeste hardware en software is al aanwezig en tot onze beschikking. Mochten wij echter gebruik willen maken van een werkomgeving die nog niet beschikbaar is, dan moet er rekening gehouden worden met eventuele licenties die hieraan verbonden zijn. In overleg is het mogelijk om deze aan te schaffen, maar de voorkeur is om de software te ontwikkelen binnen de beschikbare werkomgevingen. • Informatie Er zullen tussentijdse voortgangbesprekingen gehouden worden, de belangrijkste hiervan is de midterm evaluation wanneer we besluiten om verder te gaan in de huidige richting of om hiervan af te wijken. Hostnet is een redelijk klein bedrijf, hierdoor is het makkelijk om anderen
40
HOOFDSTUK 7. BIJLAGEN
•
te benaderen om informatie te verwerven. Techniek We hebben onze eigen werkplekken bij Hostnet. We hebben beschikking tot dezelfde software en informatie als alle andere medewerkers en kunnen onze eigen programma's installeren mocht het nodig zijn.
Voorwaarden De voorwaarden die gesteld zijn aan de opdrachtnemer zijn: • • •
Het project moet binnen 10 weken afgerond zijn. De door ons ontwikkelde software moet overzichtelijk gecodeerd zijn en goed gedocumenteerd worden. Het project moet afgerond worden met een eindverslag en een presentatie.
De voorwaarden die gesteld zijn aan de opdrachtgever zijn: • De mogelijkheid bieden aan de opdrachtnemers om het huidige systeem te analyseren. • De bestaande programmacode ter beschikking stellen voor gebruik. •
Verdere informatie verstrekken indien dit nodig blijkt te zijn.
Planning Week 1. 14 t/m 18 april
2. 21 t/m 25 april
3. 28 t/m 2 mei
4. 5 t/m 9 mei
5. 12 t/m 16 mei
6. 19 t/m 23 mei
7.
Gepland MoSCoW Plan van aanpak Onderzoeks rapport (5-10 A4) Requirements analyse / functioneel ontwerp Technisch ontwerp Inhoudsopgave eindverslag Prototype eerste run Prototype dmdr koppeling (http://www.dmdr.nl/ extern bedrijf die de facturen verstuurd) Test classes eerste run Tests dmdr koppeling Eerste run klaar / dmdr klaar Prototype en test herinneringen en renewals
26 t/m 30 mei
Midterm evaluation Andere runs klaar
8.
Alle runs klaar en getest
2 t/m 6 juni
9.
Uitloop ruimte
9 t/m 13 mei
10. 16 t/m 20 mei
Grafisch overzicht
Eindpresentatie
7.1.
BIJLAGEN A: PLAN VAN AANPAK
41
Hostnet vraagt ook of wij gebruikmaken van project open. Een applicatie waarin wij aangeven welke taken ondernomen moeten worden. Hoeveel tijd wij hiervoor denken nodig te hebben, hoeveel tijd we er daadwerkelijk aan hebben besteed en in hoeverre de taak is voltooid. Dit is interessant voor management om te zien waar het bedrijf zijn tijd in investeert. Voor ons is het interessant omdat het ervoor zorgt dat we een gedetailleerde planning maken en we makkelijk onze voortgang kunnen bijhouden. Productkwaliteit Het bestaande systeem is procedurele code waar gedurende de jaren telkens code is toegevoegd, verwijderd en veranderd. Hierdoor is de betrouwbaarheid en onderhoudbaarheid afgenomen. Gewenst wordt dat dit verbetert. De betrouwbaarheid van het product is van groot belang. Als het systeem vaak problemen oplevert zal dit leiden tot ontevreden klanten waardoor het imago van Hostnet beschadigd zal worden. Ook zal dit meer werk voor de helpdesk en administratie veroorzaken. Hostnet is een groeiend bedrijf en daarom is de onderhoudbaarheid en portabiliteit ook erg belangrijk. Als onze gesuggereerde aanpassingen eenmaal in gebruik zijn, maakt het deel uit van een systeem dat dagelijks door meerdere personen aangepast en uitgebreid word. De code moet daarom goed begrijpbaar zijn zodat het mee kan groeien met het bedrijf. Hoe efficiënter de data omzet hoe langer het systeem kan groeien zonder de nood van nieuwe hardware, dus ook dit is interessant om rekening mee te houden. Belangrijker is echter dat de code begrijpbaar is dan kan het altijd nog efficiënter gemaakt worden. Ons product is alleen bedoeld voor intern gebruik. Het moet niet moeilijker worden dan het huidige systeem, anders lopen we het risico dat het niet geaccepteerd wordt en dus niet in gebruik genomen wordt. Er mag geen functionaliteit verloren gaan. Voorgestelde maatregelen • Wekelijkse updates. Aan het einde van elke week word er een e-mail naar alle medewerkers van Hostnet gestuurd, waarin vermeld wordt waar die week aan gewerkt is en wat de voortgang is. • Belangrijke beslissingen worden in overleg met projectbegeleiders zo nodig in een vergadering met de opdrachtgevers en eventuele andere partijen die beïnvloed worden, zoals Administratie, genomen. • De code en onze beslissingen moeten goed gedocumenteerd worden zodat het duidelijk is voor alle betrokkenen • We zullen zelf onze code uitvoerig testen. Het eindproduct zal na afloop van onze stage een periode parallel lopen aan het huidige systeem om te garanderen dat er geen problemen ontstaan op het moment dat het in gebruik wordt genomen.
42
7.2
HOOFDSTUK 7. BIJLAGEN
Bijlagen B: Onderzoeksverslag
IN3405 - Bachelorproject
Onderzoeksrapport
Hidde Boomsma 1174371
Elger Lambert 1154273
19 mei 2008
Samenvatting De eerste twee weken van onze stage zijn aan onderzoek besteed om vertrouwd te raken met onze nieuwe werkomgeving en om belangrijke informatie te verwerven. Het doel van dit document is om alle verworven kennis te documenteren en de beslissingen, die hier volgen, te onderbouwen. De volgende stap zal het uitwerken van de door ons aanbevolen voorstel zijn. Er zal een concept worden ontworpen in de richting die in dit document wordt bepaald.
7.2.
BIJLAGEN B: ONDERZOEKSVERSLAG
1
43
Introductie
Dit rapport is een van de documenten voor het Bachelor-eindproject van de opleiding Technische Informatica aan de Technische Universiteit Delft. Voor dit project zijn studenten gevraagd een opdracht uit te voeren voor een extern bedrijf of organisatie. In dit geval gaat het om een bedrijf genaamd Hostnet, gevestigd in Amsterdam. Zij bieden alle benodigdheden voor het hosten van een website aan; van domeinnamen en webhosting tot dedicated servers. Het bedrijf heeft een eigen software ontwikkelteam, beheer, webdesign, helpdesk, sales, productmanagement en communicatie-afdeling. Er zijn ongeveer 41 medewerkers, 12 medewerkers ontwikkelen software. Ons onderzoek begon met het analyseren van de huidige situatie. Hierna hebben we ons verdiept in onze probleemstelling en onderzoeken hoe wij deze het beste kunnen oplossen. Aan de hand van dit onderzoek hebben we een besluit genomen en zijn we nagegaan wat dit voor een invloed heeft op onze werkomgeving voor dit project. Hier hebben we ook onderzoek naar gedaan. Tot slot hebben we verschillende ontwikkelmethodieken vergeleken en gedocumenteerd waar we voor gekozen hebben en waarom. De probleemstelling is beter te begrijpen nadat het huidige systeem duidelijk is. Om die reden staat de probleemstelling in de laatste alinea van “Analyse huidige situatie“ vermeld.
2
Analyse huidige situatie
Toen Hostnet begon, werden de klanten- en productgegevens opgeslagen in excel sheets. Sindsdien is het bedrijf, de hoeveelheid klanten en producten, flink gegroeid. De excel sheets zijn vervangen door datastructuren en er werd een systeem ontwikkeld binnen Microsoft Access om administratie te assisteren. Dit systeem, geschreven met procedurele code, is over de jaren uitgebreid en aangepast om met het bedrijf mee te groeien. Hierdoor is de code moeilijk te begrijpen, waardoor de betrouwbaarheid en onderhoudbaarheid van het hele systeem is gedaald. Een ander probleem is dat dit systeem, nu bekend als Hostbase, direct zijn benodigde gegevens uit een niet-genormaliseerde MsSQL-database haalt. In 2006 is de eerste stap, om hier in verandering te brengen, gezet. De productenstructuur is volledig herontworpen, zowel deze als de klantgegevens zijn losgekoppeld van Hostbase en staan nu in een genormaliseerde MySQLdatabase. Hostbase werkt echter alleen met een MsSQL-database met de oude structuur en kan daarom de extra functionaliteit die de nieuweproducten structuur biedt nog niet benutten. Een simpele illustratie van de huidige situatie is te zien in Figuur 1. Er is een onderscheid tussen een front-, mid- en backoffice gemaakt. Het idee is dat de frontoffice bedoeld is voor het beheren van de data en communicatie met de klant. In de backoffice staan applicaties die gebruikmaken van deze data. De midoffice zorgt voor de communicatie tussen de front- en backoffice. Hostbase behoort tot de backoffice. Het facturatieproces, het verwerken van betalingen en het bijhouden van statistieken vindt hier plaats. Hostbase is slechts bereikbaar via Microsoft Access. Access werkt alleen onder Microsoft Windows. Dit is nadelig daar de meeste computers bij Hostnet standaard Linux draaien. Nog een probleem met Hostbase is, dat het geschreven is in VBScript, een gestripte versie van Visual Basic. Er zijn weinig werknemers bij Hostnet die
1
44
HOOFDSTUK 7. BIJLAGEN
Figuur 1: Huidige situatie hier goed mee overweg kunnen. In de frontoffice staat een MySQL-database genaamd Mijn Hostnet. Klanten van Hostnet hebben toegang tot deze database via een applicatie met dezelfde naam. Werknemers van Hostnet doen dit via Aurora. Aurora is web-based en daarom vanaf alle computers beschikbaar. De frontoffice is geprogrammeerd in PHP5 binnen een framework genaamd Symfony. Dankzij dit framework is het makkelijk om in de toekomst van database te veranderen. De database staat in een datacenter. In de frontoffice staat de nieuwe productenstructuur, de klantgegevens en ook de website waar klanten de mogelijkheid hebben om producten te bestellen. De midoffice heet Hostnet Full Throttle (HFT) en was ontworpen als tweede stap in het proces het huidige systeem te verbeteren. Het is geschreven om alle extra functionaliteit van de nieuwe productenstructuur te benutten. De bedoeling is dat de HFT wordt gebruikt om interessante data uit de frontoffice te halen waar de backoffice dan weer iets mee kan doen. De HFT is klaar om in gebruik te nemen, maar omdat Hostbase nog de oude structuur en een MsSQL-database gebruikt, is dit nog niet mogelijk. De extra functionaliteit die de nieuwe productenstructuur biedt, wordt dus nog helemaal niet gebruikt. Daar het nog niet mogelijk was de HFT te gebruiken, was het noodzakelijk een ondersteunend proces te ontwerpen, de Import/Export. Dit is momenteel de schakel tussen Hostbase en Mijn Hostnet. De taak van dit proces is om de data in de MySQL-database uit Mijn Hostnet en de data in het MsSQL-database van Hostbase synchroon te houden. Op die manier is het mogelijk om wel al gebruik te maken van de nieuwe MySQL-databases in het datacenter en toch ook de applicaties in Hostbase te kunnen blijven gebruiken. Maar omdat de MsSQLdatabase niet genormaliseerd is en de structuren verschillen, gaat dit niet altijd 2
7.2.
BIJLAGEN B: ONDERZOEKSVERSLAG
45
goed. Daarbij is het bijhouden van dezelfde data op twee verschillende plekken en het synchroniseren hiervan niet erg effici¨ent. Ook is het een relatief traag proces omdat de twee databases slechts met twee ADSL-verbindingen verbonden zijn. Het zou veel effici¨enter zijn als alle data op een plek bijgehouden werd. Aan ons is gevraagd het huidige systeem aan te passen, zodat er eindelijk gebruikgemaakt wordt van de nieuwe productenstructuur en alle extra functionaliteiten die het biedt. Het belangrijkste proces, die het meest zou profiteren, is het facturatieproces. Deze zal dus in ieder geval aangepast of herontworpen moeten worden zodat dit proces via de HFT zijn data uit de MySQL-database haalt en niet de door de Import/Export omgezette data uit de MsSQL-database. [8,12,14]
3
Voorgestelde oplossingen
Naar onze mening waren er drie verschillende manieren waarmee een oplossing voor de probleemstelling kon worden gerealiseerd. Van elk voorstel hebben we onderzocht wat de voor- en nadelen zouden zijn en hun invloed op de betrokkenen.
3.1
Minimale aanpassing van Hostbase
De bestaande code zou grotendeels intact blijven. Slechts de code die informatie van de producten ophaalt en verwerkt, moet worden aangepast. Sommige versies van de bestaande factuurprocedure moeten worden samengevoegd, omdat de nieuwe productenstructuur geen onderscheid maakt tussen pakketten en andere producten. Bij dit voorstel zal de code in Access blijven. In vele opzichten is dit nadelig. Het testen van code in Access is lastig, waardoor de kans op fouten in het eindproduct erg groot is. Er zijn maar een beperkt aantal mensen binnen Hostnet die hier goed mee overweg kunnen. De code is slecht uitbreidbaar. Het draaien van het facturatieproces blijft beperkt tot Microsoft Windows met Access 2000. Het zal niet mogelijk zijn om gebruik te maken van svn. Hierdoor is het moeilijker om met zijn twee¨en tegelijkertijd onafhankelijk van elkaar code te ontwikkelen. De uniformiteit zal niet stijgen. Een ander nadeel is dat de code in Hostbase niet uit kleine delen bestaat, waardoor het testen zeer complex is en er gemakkelijk zaken over het hoofd gezien worden. Ook is het veel werk om de genormaliseerde klantengegevens uit Aurora mee te nemen. Het eindproduct volgens dit voorstel is lastig om parallel te laten lopen met het huidige systeem. Er zijn voordelen van deze manier van aanpak, maar niet veel. Een voordeel is dat de interface in Hostbase bijna precies hetzelfde zal blijven. Administratie zal dus na de veranderingen binnen hun vertrouwde werkomgeving blijven werken. Een ander voordeel is dat er relatief weinig regels code geschreven hoeven te worden om deze aanpassing te realiseren.
3.2
Herontwerp van het facturatieproces
Het idee van dit voorstel is om het facturatieproces volledig opnieuw te ontwerpen en implementeren. Andere processen van Hostbase zoals bijvoorbeeld het verwerken van betalingen zullen onveranderd blijven.
3
46
HOOFDSTUK 7. BIJLAGEN
Omdat het proces volledig opnieuw geschreven wordt, is het voor ons mogelijk om het uit kleine onafhankelijke en goed testbare onderdelen op te bouwen. De kans op ernstige fouten is dus veel kleiner dan bij het eerste voorstel. Bij het herontwerpen kan er veel beter rekening gehouden worden met toekomstige wensen. Het is makkelijker om extra functionaliteiten te implementeren. Door de databases slim te kiezen, zal het dataverkeer van het nieuwe proces veel sneller zijn dan het huidige systeem. Een ander groot voordeel is dat het mogelijk is om het nieuwe ontwerp in PHP5 met het Symfony-framework te implementeren. Dit zal voor goede uniformiteit met de frontoffice zorgen. Er zijn veel medewerkers bij Hostnet die ervaring hebben en vertrouwd zijn om met PHP en Symfony software te ontwikkelen. Het eindproduct zal dus goed begrepen en onderhouden kunnen worden. Het zal mogelijk zijn bestaande code in Aurora te benutten. Het facturatieproces wordt platformonafhankelijk. Het zal namelijk vanuit een webbrowser benaderbaar worden. Het meenemen van de genormaliseerde klantengegevens zal relatief makkelijk zijn. Een nadeel voor administratie is dat de huidige interface voor het facturatieproces in Hostbase verdwijnt. Het grootste gevaar bij dit voorstel is dat het misschien niet lukt om het hele systeem volledig te implementeren in de beschikbare tijd.
3.3
Volledig herbouwen van Hostbase functionaliteit
Hierbij zouden alle functionaliteiten van Hostbase herontworpen moeten worden; het facturatieproces, de statistieken en de binnengekomen betalingen. Naast deze drie grotere processen wordt Hostbase ook nog voor een tal andere kleinere zaken gebruikt. Deze zouden dan ge¨ınvertariseerd en goed beschreven moeten worden voordat de grootte van dit project volledig duidelijk is. Dit voorstel profiteert van dezelfde voordelen als het tweede voorstel. Daarbij zou ook nog eens de Import/Export volledig kunnen verwijderen. Alle oude procedurele code, waarvan niet goed begrepen wordt hoe het werkt, zal vervangen worden. Het zou het hele systeem uniform maken. Een nadeel voor administratie is dat het huidige interface met Hostbase in een keer volledig zal verdwijnen. Dit voorstel omvat te veel werk om in de gestelde tijd te voltooien. Slechts delen kunnen behaald worden.
4
Onze aanbevelingen
Aan de hand van ons onderzoek hebben wij het tweede voorstel, het herontwerpen van het facturatieproces, aan Hostnet aanbevolen. Hierbij kunnen wij garantie geven van een robuust en goed getest systeem. Tegelijkertijd hebben we aanbevolen het nieuwe ontwerp te implementeren met PHP in het Symfonyframework. Een alternatieve keuze zou bijvoorbeeld Visual Basic zijn geweest. Hier zouden echter kosten aan verbonden zijn. Daarbij, door voor PHP en Symfony te kiezen, stijgt de uniformiteit van het systeem en is het mogelijk bestaande code te gebruiken. Het eindproduct zal ontwikkeld zijn binnen een voor Hostnet zeer bekende omgeving, waardoor het in de toekomst goed begrepen en onderhouden kan worden.
4
7.2.
BIJLAGEN B: ONDERZOEKSVERSLAG
47
Geen verandering van de interface Hoeveelheid werk Uniformiteit Platform onafhankelijk Oude en nieuwe systeem parallel draaien Tegelijkertijd code kunnen ontwikkelen Gebruik van subversion (source backup) Hergebruik van bestaande code Uitbreidbaarheid van het eindproduct Begrijpbaar voor Hostnet Centralisatie van de databases Verdwijnen van oude onbegrijpbare code Import/Export omzeilen
Voorstel 1 + + +/+/-
Voorstel 2 +/+ + + + + + + + + +/+/-
Voorstel3 + + + + + + + + + + +
Tabel 1: De drie voorstellen met elkaar vergeleken De hoeveelheid werk van het tweede voorstel is overzichtelijk. Als het ge¨ımplementeerd is, zal de nieuwe productenstructuur en alle extra functionaliteiten door het hele systeem benut worden. Ondanks dat de Import/Export nog steeds nodig zal zijn, zal er minder gebruik van gemaakt worden dan voorheen. Qua databases zijn er twee soorten tot onze beschikking. We kunnen van zowel de MsSQL- als de MySQL-database gebruikmaken, of een combinatie hiervan. Wij hebben aanbevolen om alleen gebruik te maken van de MySQLdatabase. Dan staat alles op het databasecluster gecentraliseerd. Het voordeel hiervan is dat het mogelijk is om gegevens uit meerdere databases in een aanvraag binnen te halen. Dit is zeer effici¨ent en zou een grote snelheidswinst boeken ten opzichte van de andere opties. Voor een overzicht van de sterke en zwakke aspecten van de drie voorstellen zie Tabel 1. We zien dat voorstel 2 en 3 duidelijk meer voordelen hebben dan voorstel 1. De voornaamste reden dat we voorstel 2 hebben verkozen boven 3 is gebrek aan tijd. Voorstel 2 boekt een grote verbetering van het bestaande systeem. Het project dat in 2006 gestart is, zal eindelijk voltooid worden. Na het voltooien van voorstel 2 zou Hostnet nieuwe projecten kunnen starten om de rest van de functionaliteit van Hostbase over te zetten om het gehele systeem uniform te maken en de Import/Export te kunnen verwijderen. In dat opzicht kan voorstel 2 gezien worden als de eerste stap om voorstel 3 te realiseren.
5
Werkomgeving
In de huidige situatie is alle code van het facturatieproces te vinden in de Access applicatie Hostbase. Alle andere applicaties binnen Hostnet zijn geschreven in PHP5. Er zal met de taal PHP5 binnen het Symfony-framework worden gewerkt. Voor de database wordt gebruikgemaakt van MySQL4. Alles draait op een server met CentOS4 (Linux distributie) en Apache2 als webserver. Hiernaast worden er natuurlijk ook verschillende editors gebruikt, waaronder Vim en Eclipse. Op de locale pc wordt Ubuntu (Linux) gedraaid. Alle documenten voor Hostnet
5
48
HOOFDSTUK 7. BIJLAGEN
moeten beschikbaar zijn in OpenOffice-formaat. Een groot deel van de verslagen zullen wij schrijven in latex. Kile (KDE integrated Latex Editor) gebruiken we als applicatie om de documenten in te schrijven. Voor het maken van klassendiagrammen staat Umbrello tot onze beschikking, een opensource UML-pakket beschikbaar voor KDE onder Ubuntu. PHP5 is een objectgeori¨enteerde taal zonder types en met veel standaard functies. Het is een veel gebruikte taal voor webapplicaties en bovendien gratis beschikbaar voor commercieel gebruik. Een goede handleiding en voorbeelden zijn te vinden op www.php.net. PHP draait als module in de veel gebruikte Apache Webserver. In het document coden bij hostnet.odt is de code style van Hostnet te vinden. Hierbij zijn ook alle constructies en veel voorkomende codeblokken uitgewerkt. Een erg nuttig naslagwerk. [6, 7] Symfony is een framework voor PHP5 en is ontwikkeld door het Franse Sensiolabs. Het framework biedt een splitsing in Model, View en Control. Hiernaast bevat het ook ondersteuning voor zowel unit- als functionele tests. In het model gedeelte van de MVC-structuur zit de object-relationeel mapping en de database abstractie. In de View-laag komt alle opmaak op basis van templates. In deze laag zijn ook veel hulpfuncties te vinden die het leven gemakkelijker maken en veel voorkomende taken wat betreft opmaak en Javascript, maar ook Ajax te vereenvoudigen. Symfony wordt onder andere gebruikt door Askeet en Yahoo Bookmarks. [4, 15] MySQL4 is een relationeel DBMS. MySQL is vrij verkrijgbaar onder de GPL-licentie. MySQL is vanuit PHP gemakkelijk te benaderen door de library die al jaren wordt meegeleverd met PHP. Ook is er in Symfony ondersteuning voor MySQL. Als frontend om de database zelf aan te kunnen passen, wordt PHPMyAdmin gebruikt. Apache2 is een veel gebruikte webserver die ook door Hostnet wordt gebruikt om alle websites van klanten met een standaard hostingpakket te hosten. Deze server is opensource met een eigen licentie. [13] CentOS4 en Ubuntu zijn linux-distributies. Ubuntu wordt gebruikt op de werkstations, waar iedereen gebruik van maakt en CentOS4 wordt gebruikt op de ontwikkel-, test-, acceptatie- en productie-servers. [10, 11] Voor het schrijven van lange stukken code wordt gebruikgemaakt van Eclipse. Voor kleine aanpassingen gebruiken we Vim [16]. Een bekende tekst editor in linux. Hiermee is het mogelijk om snel de gevolgen van aanpassing te zien zonder tussenkomst van versiebeheer. Voor het maken van standaard documenten staat OpenOffice tot onze beschikking. Dit wordt standaard meegeleverd met Ubuntu en kan alle gebruikelijke office bestandsformaten lezen en schrijven. Voor het maken van de documenten die we inleveren kan gebruik gemaakt worden van Latex. Latex is een opmaaktaal die bestanden in platte tekst opslaat. Ook kunnen documenten gemakkelijk gesplitst worden en is er een goed systeem om referenties bij te houden. De editor die we hierbij gebruiken is Kile (KDE Integrated Latex Editor). Aangezien de documenten uit platte tekst bestaat, kunnen ze gemakkelijk in een versiebeheer worden opgenomen en is gelijktijdig bewerken mogelijk. [5, 9] Voor de gemakkelijke stroomdiagrammen is OpenOffice toereikend, maar voor het maken van echte UML-diagrammen is het toch wenselijk een programma te hebben dat meer functionaliteit biedt. Umbrello is hiervoor beschikbaar. Een simpel programma voor Ubuntu. Umbrello bevat niet erg veel mogelijkhe6
7.2.
BIJLAGEN B: ONDERZOEKSVERSLAG
49
den, maar ruim voldoende voor het maken van de basisdiagrammen. Ubrello kan ook exporteren naar PHP5-code. Alles wat wordt geproduceerd, is opgeslagen in een subversion repository. Subversion is een versiebeheersysteem afgeleid van CVS. Alle bestanden worden centraal op de server opgeslagen. Een ieder kan wijzigingen doorvoeren. Als er gelijktijdig gewijzigd is, worden de twee documenten automatisch samengevoegd. Als er een gelijke sectie is bewerkt, treedt er een conflict op en is handmatig ingrijpen vereist. Door het gebruik van Subversion hebben we altijd een back-up en kunnen we ook terugbladeren naar eerdere versies als er toch iets overboord is gezet wat later nuttig blijkt. Over al deze applicaties is op de betreffende websites veel informatie te vinden, maar vooral op de wiki van Hostnet staat voor de meeste van deze applicaties beschreven hoe ze gebruikt kunnen worden. [8]
6
Methodiek
Ook hebben wij onderzoek gedaan welke methodiek geschikt zou zijn voor het ontwikkelen van ons project. We zijn tot de conclusie gekomen dat eXtreme Programming (XP) voor ons project het meest geschikt zal zijn. [3] Onze motivatie hiervoor is als volgt. Ons eindproduct zal een cruciaal deel zijn in het systeem waar Hostnet op draait. Het is dus van belang dat de software die wij leveren robuust en betrouwbaar is. Bij de XP-methodiek wordt de code elke dag getest en fouten verwijderd voordat er verder gegaan wordt. Het is niet ongebruikelijk dat de testcode eerst geschreven wordt, voordat de functionaliteit word ge¨ımplementeerd. Op deze wijze worden fouten snel gedetecteerd en is het relatief makkelijk om uit te vinden waar het fout gaat. Hierdoor zijn fouten snel en makkelijk op te lossen. Binnen Hostnet zijn er verschillende partijen die be¨ınvloed worden door of invloed hebben op de software die door ons ontwikkeld gaat worden. Deze partijen hebben regelmatig nieuwe idee¨en wat het nieuwe facturatieproces zou kunnen doen. XP biedt de mogelijkheid om deze idee¨en gedurende het gehele ontwikkelingsproces mee te nemen in het concept. Het idee van XP is dat er in korte tijd een prototype beschikbaar is, zodat de klant snel een idee heeft welke richting het project op gaat. Ze kunnen zien wat er op dat moment mogelijk is en door ermee te experimenteren kunnen ze beter bedenken wat ze graag nog meer of anders willen. Deze feedback wordt vervolgens in een volgende iteratie van het prototype verwerkt. Dit zorgt ervoor dat het project de goede richting in blijft gaan en zoveel mogelijk aan de eisen voldoet. Gedurende het ontwikkelproces kunnen nog eisen verzameld worden en dus kan er snel gestart worden met het ontwikkelen van de software. Daarom leent de XP-methodiek zich goed voor projecten waar tijd schaars is, zoals bij ons het geval. XP eist discipline, anders is er een gevaar dat het ontwikkelingsproces chaotisch wordt en focus verliest. XP is niet geschikt voor grote applicaties en het advies is om niet met meer dan twaalf programmeurs te werken. Ook wordt er geadviseerd om per tweetal software te ontwikkelen. Gezien we geen grote applicatie hoeven te ontwikkelen en omdat we met zijn twee¨en zijn, precies een tweetal, zal dit geen probleem moeten zijn. De XP-methodiek eist ook veel inbreng van de toekomstige gebruikers. Daar
7
50
HOOFDSTUK 7. BIJLAGEN
al onze toekomstige gebruikers zich binnen Hostnet bevinden, zijn zij bijna altijd beschikbaar. Het is een klein bedrijf, daardoor is de communicatie goed, XP geeft ons de mogelijkheid hier maximaal van te profiteren! [1–3, 17]
Referenties [1] http://nl.wikipedia.org/wiki/extreme programming, 2007. [2] http://en.wikipedia.org/wiki/extreme programming, 2008. [3] Alan Dennis en Barbara Haley Wixom. Systems Analysis & Design. John Wiley & Sons, Inc., New York, 2nd, edition, 2003. [4] Francois Zaninotto en Fabien Potencier. The Definitive Guide to Symfony. Springer-Verslag, New York, 1st, edition, 2007. [5] Tobias Oetiker en Hubert Partl en Irene Hyna en E. Schlegl. The Not So Short Introduction to Latex, 2008. http://tobi.oetiker.ch/lshort/lshort.pdf. [6] Harry Fuecks. The PHP Anthology. Object Oriented PHP Solutions Volume I. Sitepoint, Collingwood, Australia, 1st, edition, 2003. [7] Harry Fuecks. The PHP Anthology. Object Oriented PHP Solutions Volume II. Sitepoint, Collingwood, Australia, 1st, edition, 2003. [8] Hostnet. http://wiki.hostnetbv.nl/index.php/hoofdpagina, 2008. Alleen zichtbaar voor Hostnet medewerkers. [9] Kile. http://kile.sourceforge.net/, 2008. [10] Canonical Ltd. http://www.ubuntu.com/, 2008. [11] CentOS Ltd. http://www.centos.org/, 2008. [12] Marije Nijs, 2008. Interview. [13] Apache HTTP Server Project. http://httpd.apache.org/, 2008. [14] Yom Schutte, 2008. Interview. [15] Symfony. http://www.symfony-project.org/, 2008. [16] Vim. http://www.vim.org/docs.php, 2008. [17] J. Donovan Wells. http://www.extremeprogramming.org/, 2006.
8
7.3.
BIJLAGEN C: FLOWCHARTS
7.3
51
Bijlagen C: Flowcharts
Facturatieproces
1
Gebruikte symbolen H
Hostnet medewerker
Begin Process
Initalisatie process
C
klant
Factuur bij de klant
Einde process succesvol
Datastore
Eind niet succesvol
Einde proces niet succesvol
Process
factuurdatum =< einddatum
Keuze
HB Factuur
1. Contract voor facturatie ophalen
Verbinding naar Datastore Processflow
contract ophalen
Stuur mail naar DMDR
Geautomatiseerde actie
Email
2
52
HOOFDSTUK 7. BIJLAGEN
Factureringsproces – Dataflow Diagram H
Administratie
Voor elk contract
start facturatie
HB Factuur
1.
2.
Contract voor facturatie ophalen
Contract
Factuur aanmaken indien nodig
Factuur
3. Factuurregel aanmaken
HFT Contract
Factuur met regels
4.
5. Factuur in PDF
Factuur opmaken
MH Product
Factuur versturen
MH Relatie
C
Factuur bij de klant
3
Factureringsproces – Dataflow Diagram H
Administratie
Voor elk contract
start facturatie
HB Factuur
1. Contract voor facturatie ophalen
2. Contract
Factuur aanmaken indien nodig
Factuur
3. Factuurregel aanmaken
HFT Contract
MH Product
Factuur met regels
4.
5. Factuur in PDF
Factuur opmaken
Factuur versturen
MH Relatie
C
Factuur bij de klant
4
7.3.
BIJLAGEN C: FLOWCHARTS
53
Factureringsproces – 1. Contracten voor facturatie ophalen H
Begin Factureringsproces
factuurdatum =< einddatum
contract ophalen
ja
contract selecteren voor facturatie
nee
ja
factuurdatum isNULL
nee
ja
factuurdatum isEmpty
nee Eind succesvol
5
Factureringsproces – 1. Contracten voor facturatie ophalen (RENEWAL) H
Begin Factureringsproces
contract ophalen
factuurdatum >= einddatum
Nee
Constraint: de renewalrun moetzo vaak gedraait worden dat de tijd tussen twee keer uitvoeren kleiner is dan de opzegtermijn en kleiner dan de facturatieperiode
Ja
NOW > einddatum – periode
Nee
Ja
NOW > einddatum opzegtermijn
Nee
Ja
Status
Ja
Nee
Einddatum contract ophogen met periode
Contract selecteren voor facturatie
Eind succesvol
6
54
HOOFDSTUK 7. BIJLAGEN
Factureringsproces – Dataflow Diagram H
Administratie
Voor elk contract
start facturatie
HB Factuur
1.
2.
Contract voor facturatie ophalen
Contract
Factuur aanmaken indien nodig
Factuur
3. Factuurregel aanmaken
HFT Contract
4.
Factuur met regels
5. Factuur in PDF
Factuur opmaken
MH Product
Factuur versturen
MH Relatie
C
Factuur bij de klant
7
Factureringsproces – 2. Factuur aanmaken indien nodig
Begin factuur aanmken
Kijk of factuur al bestaat
ja
Eind succesvol
nee
factuur record maken
8
7.3.
BIJLAGEN C: FLOWCHARTS
55
Factureringsproces – Dataflow Diagram H
Administratie
Voor elk contract
start facturatie
HB Factuur
1.
2. Contract
Contract voor facturatie ophalen
Factuur aanmaken indien nodig
Factuur
3. Factuurregel aanmaken
HFT Contract
MH Product
4.
Factuur met regels
5. Factuur in PDF
Factuur opmaken
Factuur versturen
MH Relatie
C
Factuur bij de klant
9
Factureringsproces – 3. Factuurregel aanmaken Start
volgende_ factuur_datum =< begin_datum
ja
eenmalige kosten regel toevoegen
periodieke kosten regel toevoegen
eenmalige korting bepalen
periodieke korting bepalen
nee
volgende_factuur isNull
ja
korting > 0
nee
korting > 0
nee
nee
volgende_factuur isEmpty
ja
ja
eenmalige korting regel toevoegen
ja
volgende_factuur_datum ophogen met de facturatie periode
periodieke korting regel toevoegen
nee
Eerste factuur?
Eenmalige kosten
Periodieke kosten
Eind succesvol
10
56
HOOFDSTUK 7. BIJLAGEN
Factureringsproces – 3. Factuurregel aanmaken Start
volgende_ factuur_datum =< begin_datum
ja
eenmalige kosten regel toevoegen
periodieke kosten regel toevoegen
eenmalige korting bepalen
periodieke korting bepalen
nee
volgende_factuur isNull
ja
nee
korting > 0
korting > 0
nee
nee
volgende_factuur isEmpty
ja
volgende_factuur_datum ophogen met de facturatie periode
ja
ja
eenmalige korting regel toevoegen
periodieke korting regel toevoegen
nee
Eerste factuur?
Eenmalige kosten
Eind succesvol
Periodieke kosten
11
Factureringsproces – 3.1. Bepalen eenmalige korting Start
korting op contract niveau
nee
neem grootste korting op klant, soort of product niveau
ja
neem korting op contract niveau
Eind succesvol
12
7.3.
BIJLAGEN C: FLOWCHARTS
57
Factureringsproces – 3. Factuurregel aanmaken Start
volgende_ factuur_datum =< begin_datum
ja
eenmalige kosten regel toevoegen
periodieke kosten regel toevoegen
eenmalige korting bepalen
periodieke korting bepalen
nee
volgende_factuur isNull
ja
nee
korting > 0
korting > 0
nee
nee
volgende_factuur isEmpty
ja
volgende_factuur_datum ophogen met de facturatie periode
ja
ja
eenmalige korting regel toevoegen
periodieke korting regel toevoegen
nee
Eerste factuur?
Eenmalige kosten
Eind succesvol
Periodieke kosten
13
Factureringsproces – 3.2. Bepalen periodieke korting Start
korting op contract niveau
nee
neem grootste korting op klant, soort of product niveau
ja
neem korting op contract niveau
Eind succesvol
14
58
HOOFDSTUK 7. BIJLAGEN
Factureringsproces – Dataflow Diagram H
Administratie
Voor elk contract
start facturatie
HB Factuur
1. Contract voor facturatie ophalen
2. Contract
Factuur aanmaken indien nodig
Factuur
3. Factuurregel aanmaken
HFT Contract
4.
Factuur met regels
5. Factuur in PDF
Factuur opmaken
MH Product
Factuur versturen
MH Relatie
C
Factuur bij de klant
15
Factureringsproces – 4. Factuur opmaken Start
ja NAW gegevens ophalen
Soort factuur tekst plaatsen (factuur, herinnering laatste betalingsverzoek)
Voettekst buitenland op factuur plaatsen
Tekst herinnering op factuur plaatsen
Buitenlandse klant
nee Voettekst binnenland op factuur plaatsen
19% BTW
nee alle facuurregels op de factuur plaatsen
Buitenlands bedrijf met BTW nummer
Totaal bedrag plaatsen
ja 0% BTW Eind succesvol
16
7.3.
BIJLAGEN C: FLOWCHARTS
59
Factureringsproces – Dataflow Diagram H
Administratie
Voor elk contract
start facturatie
HB Factuur
1.
2.
Contract voor facturatie ophalen
Contract
Factuur aanmaken indien nodig
Factuur
3.
Factuur met regels
Factuurregel aanmaken
HFT Contract
4.
5. Factuur in PDF
Factuur opmaken
MH Product
Factuur versturen
MH Relatie
C
Factuur bij de klant
17
Factureringsproces – 5. Factuur versturen Start
herinnering Versturen per email
Email naar Klant
ja
Status
factuur
Buitenlandse kalnt
nee laatste betalings verzoek Versturen per post
Email naar DMDR
C
Eind succesvol
18
60
HOOFDSTUK 7. BIJLAGEN
Facturatieproces
19
omschrijving_factuur
product
1
has
1
1
1
1
n
has
has
has
id
opzeg
facturatie
n
Relatie
myhostnet
datum
kenmerk
1
n
factuur
naam
id
n
maanden
1
has
1
1
periode
n
n
has
has
has
id
1
tekst
datum_eind
datum_begin
domeinnaam
n
has
id
n
id
id
naam
datum_factuur_volgende
korting_eenmalig_bedrag
korting_percentage_bedrag
korting_periodiek_bedrag
betaling_type
tekst_voet
pdf
tekst_voet_buitenland
factuur_pdf
factuur_status
contract
1
1
BIJLAGEN D: ENTITY-RELATIONSHIP DIAGRAM
id
eenmalig
per_periode
n
pct_eenmalig
per_periode
id
pct_per_periode
omschrijving
prijs
eenmalig
id
periode_van
periode_tm
korting
omschrijving
bedrag
factuur_regel_volgnr
n
7.4
id
factuur_regel
7.4. 61
Bijlagen D: Entity-relationship Diagram
62
7.5
HOOFDSTUK 7. BIJLAGEN
Bijlagen E: Klassendiagram
7.6.
7.6
BIJLAGEN F: VOLGORDE DIAGRAM
Bijlagen F: Volgorde diagram
63
64
HOOFDSTUK 7. BIJLAGEN
7.7.
7.7
BIJLAGEN G: NOTULEN FLOWCHARTS-PRESENTATIE
65
Bijlagen G: Notulen flowcharts-presentatie
Notulen 21 April 2008 Aanwezigen: David Dijkstra, Marije Nijs, Yom Schutte, Hidde Boomsma, Elger Lambert Besproken is het voorstel van het nieuwe factureringsproces aan de hand van een flowchart presentatie. Deze flowcharts zijn momenteel te zien op de wiki: http://wiki.hostnetbv.nl/index.php/Factuurrun De rede voor deze bijeenkomst was om te valideren of alle benodigde functionaliteiten in het proces zijn opgenomen en eventueel andere extra wensen in het proces opgenomen kunnen worden. Op of aanmerkingen waar de flowcharts niet volledig waren of waar extra op gelet moet worden zijn in deze notulen genoteerd. • •
• •
•
Renewals moeten pas na de einddatum van het contract verstuurd worden. Dit voorkomt extra discussie bij klanten die het toch nog willen opzeggen. Momenteel word de renewal run 1 keer per maand uitgevoerd. Wenselijk is om dit in de toekomst twee keer, of misschien wel vier keer per maand te doen, maar niet vaker. Geattendeerd werd dat contracten die de status verwijderd hebben niet gefactureerd mogen worden. Waar ook rekening mee gehouden moet worden is dat 'order succes' niet perse betekent dat het al geleverd is. - [Wijziging] Hoeft geen rekening mee gehouden worden, als er een contract is dan is de order afgerond. Bij het maken van de factuurregels moet ervoor gezorgd worden dat eenmalige korting onderaan de factuur komt te staan met de andere kortingen zoals dat nu ook gebeurt. Gesuggereerd werd om de regels verschillende types toe te kennen zodat de opmaak van de factuur makkelijk te bepalen maar ook aan te passen is. Interessant als er voor wat voor een reden dan ook in de toekomst besloten word dat de factuurregels op een andere manier geordend moeten worden.
Er ontstond een discussie toen besproken werd hoe kortingen verwerkt moeten worden. Niet alles was duidelijk en omdat bij het bedenken van de nieuwe productenstructuur hier ook al uitgebreid over na gedacht is en hier ook rekening mee gehouden is met het ontwerp is besloten om dinsdag 22 april om 14:00 uur opnieuw hierover te vergaderen. Ditmaal met Stefan Lenselink, Merijn de Brabander en Martijn Oostdam erbij. Het doel is dan om vast te stellen hoe er met kortingen overweg gegaan moet worden. Welke kortingen en combinatie van kortingen wel en niet toegestaan zijn. Punten die vandaag tijdens de discussie naar voren zijn gekomen zijn: 1. Gecontroleerd moet worden dat de kosten in combinatie met een korting nooit minder dan 0 mag worden. 2. Er mag nooit een creditfactuur gemaakt worden door het systeem. 3. Het moet wel mogelijk zijn een creditfactuur handmatig aan te maken. 4. Het moet ook mogelijk zijn een normale factuur handmatig aan te maken. Interessant zou zijn als dit in de toekomst ook vanuit Aurora gedaan kan worden. 5. Het moet mogelijk zijn om (handmatig) een eenmalig korting op een periodiek bedrag te plaatsen. Gezegd werd dat dit eigenlijk altijd een vast bedrag is en het misschien interessant was om een procentueel bedrag te verbieden. 6. Gewaarschuwd werd dat in het huidige voorstel het mogelijk is dat een reseller zowel zijn
66
HOOFDSTUK 7. BIJLAGEN
afgesproken periodieke korting zowel als een eenmalige korting op productniveau kan ontvangen. Dit is echter niet de bedoeling! Opgemerkt werd dat het fijn zou zijn voor sales als zij zouden kunnen zien hoe een korting voor een product er op de factuur er uit komt te zien. -Leuk project voor iemand anders. De discussie wat betreft kortingen is hier toen bij gelaten. Wat nog besproken moet worden is bijvoorbeeld welke verschillende korting niveaus moeten er bestaan, hoe worden ze ingevoerd, welke prioriteit hebben ze en welke combinaties zijn er wel en niet mogelijk. • •
Herinneringsfacturen mogen de originele niet overschrijven. Suggestie is om met een volgnummer te werken. Een leuk extra zou zijn het zichtbaar maken van hoe een factuur is ontvangen (per e-mail, per post).
Gemaakte afspraken: Er word voor ons een tabel gemaakt met daarin duidelijk weergegeven hoe het zit met de verschillende btw-percentages. Morgen, dinsdag om 14:00 uur, opnieuw bespreken hoe kortingen verwerkt moeten worden.
7.8.
7.8
BIJLAGEN H: NOTULEN KORTINGEN VERGADERING
67
Bijlagen H: Notulen kortingen vergadering
Notulen 22 April 2008 Aanwezigen: David Dijkstra, Marije Nijs, Yom Schutte, Martijn Oostdam, Marijn de Brabander, Stefan Lenselink Hidde Boomsma, Elger Lambert Aan de hand van de vorige bespreking op 21 april over het gehele factureringsproces is er besloten vandaag te vergaderen over hoe kortingen verwerkt moeten worden. Het doel was om in kaart te brengen hoe ze nu verwerkt worden en hoe het in de toekomst verwerkt moet gaan worden. Huidige situatie: • Een korting op contractniveau is een afspraak met een klant voor een specifiek product. Deze overschrijft alle andere kortingen. • Op productniveau bestaat slechts een eenmalige absolute korting. • Momenteel is reseller hetzelfde als klantniveau, dit is een periodieke korting die eenmalige korting (op productniveau) overschrijft. Na deze constatering is er uitgebreid gediscussieerd wat wenselijk zou zijn voor het nieuwe systeem. Centraal in deze discussie stond de vraag hoe er omgegaan moet worden met resellers. Moeten zij automatisch profiteren van acties of niet? In het huidige systeem blijven zij het zelfde betalen ook al is er een aanbieding die goedkoper is dan hun afspraak. Gemaakte Afspraken: -De discussie is afgerond met de afspraak dat Marketing en Sales zouden beslissen hoe zij willen hoe kortingen in het nieuwe systeem moet worden geïmplementeerd. - Zie onderaan dit document wat er besloten is! -Omdat onze code uit losse modules gaat bestaan, kunnen wij toch al de code gaan schrijven zonder te weten wat het besluit van Marketing en Sales is. -Bij het eindproduct is het van belang dat het duidelijk is hoe de kortingen geïmplementeerd zijn, zodat zowel administratie als andere programmeurs begrijpen waarom welke korting op de factuur komt te staan. -Mocht een automatisch gegenereerde factuur een bedrag kleiner dan 0 bedragen (credit), dan moet deze door het systeem worden opgevangen en administratie moet er van op de hoogte gebracht worden. Op deze manier kunnen zij uitzoeken hoe dit tot stand is gekomen en eventueel actie ondernemen mocht dit nodig zijn. In het geval er een goede verklaring voor is, kunnen zij handmatig een creditfactuur aanmaken. (In de toekomst is het misschien interessant om dit soort facturen in een lijst bij administratie te plaatsen en dat deze door middel van een vinkje en een druk op de knop alsnog verstuurd dan wel verwijderd worden. Dit is echter alleen de moeite waard als er regelmatig creditfacturen worden aangemaakt, gezien de beslissing [zie hieronder] denk ik echter dat dit niet het geval gaat zijn).
Het Besluit: Tijdens het typen van deze notulen hebben David Dijkstra, Harold Douwes, Martijn Oostdam en Marijn de Brabander overlegd en hebben het volgende besloten. Er moet in eerste instantie gekeken worden naar kortingen op contractniveau. Mocht er zowel een eenmalig als periodieke korting bestaan op contractniveau dan moet deze met elkaar vergeleken worden. De hoogste van de twee word toegekend en overschrijft alle andere kortingen. Mocht er geen korting zijn op contractniveau moet er gekeken worden naar alle andere mogelijke kortingen, dit zijn:
68
HOOFDSTUK 7. BIJLAGEN
eenmalig en of periodieke korting op productniveau, soort klantniveau en klantniveau. Bij periodieke korting bestaan er zowel absolute als percentuele bedragen. Bij eenmalige kortingen bestaat er slechts een absolute korting. Degene die de klant de meeste korting oplevert moet gekozen worden en de rest overschreven. Er is dus besloten dat resellers in de toekomst met het nieuwe systeem automatisch zullen profiteren van acties als die goedkoper zijn dan hun resellerkorting.
7.9.
BIJLAGEN I: MANAGING HIERARCHICAL DATA IN MYSQL
7.9
69
Bijlagen I: Managing Hierarchical Data in MySQL
MySQL :: Managing Hierarchical Data in MySQL
http://dev.mysql.com/tech-resources/articles/hierarchical-data.html
Skip navigation links The world's most popular open source database Contact a MySQL Representative Login | Register
Managing Hierarchical Data in MySQL By Mike Hillyer
Introduction Most users at one time or another have dealt with hierarchical data in a SQL database and no doubt learned that the management of hierarchical data is not what a relational database is intended for. The tables of a relational database are not hierarchical (like XML), but are simply a flat list. Hierarchical data has a parent-child relationship that is not naturally represented in a relational database table. For our purposes, hierarchical data is a collection of data where each item has a single parent and zero or more children (with the exception of the root item, which has no parent). Hierarchical data can be found in a variety of database applications, including forum and mailing list threads, business organization charts, content management categories, and product categories. For our purposes we will use the following product category hierarchy from an fictional electronics store:
These categories form a hierarchy in much the same way as the other examples cited above. In this article we will examine two models for dealing with hierarchical data in MySQL, starting with the traditional adjacency list model.
The Adjacency List Model Typically the example categories shown above will be stored in a table like the following (I'm including full CREATE and INSERT statements so you can follow along): CREATE TABLE category( category_id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(20) NOT NULL, parent INT DEFAULT NULL);
1 of 13
7/9/08 11:59 AM
70
HOOFDSTUK 7. BIJLAGEN
MySQL :: Managing Hierarchical Data in MySQL
http://dev.mysql.com/tech-resources/articles/hierarchical-data
INSERT INTO category VALUES(1,'ELECTRONICS',NULL),(2,'TELEVISIONS',1),(3,'TUBE',2), (4,'LCD',2),(5,'PLASMA',2),(6,'PORTABLE ELECTRONICS',1), (7,'MP3 PLAYERS',6),(8,'FLASH',7), (9,'CD PLAYERS',6),(10,'2 WAY RADIOS',6); SELECT * FROM category ORDER BY category_id; +-------------+----------------------+--------+ | category_id | name | parent | +-------------+----------------------+--------+ | 1 | ELECTRONICS | NULL | | 2 | TELEVISIONS | 1 | | 3 | TUBE | 2 | | 4 | LCD | 2 | | 5 | PLASMA | 2 | | 6 | PORTABLE ELECTRONICS | 1 | | 7 | MP3 PLAYERS | 6 | | 8 | FLASH | 7 | | 9 | CD PLAYERS | 6 | | 10 | 2 WAY RADIOS | 6 | +-------------+----------------------+--------+ 10 rows in set (0.00 sec) In the adjacency list model, each item in the table contains a pointer to its parent. The topmost element, in this case electronics, has a NULL value for its parent. The adjacency list model has the advantage of being quite simple, it is easy to see that FLASH is a child of mp3 players, which is a child of portable electronics, which is a child of electronics. While the adjacency list model can be dealt with fairly easily in client-side code, working with the model can be more problematic in pure SQL.
Retrieving a Full Tree The first common task when dealing with hierarchical data is the display of the entire tree, usually with some form of indentation. The most common way of doing this is in pure SQL is through the use of a self-join: SELECT t1.name AS lev1, t2.name as lev2, t3.name as lev3, t4.name as lev4 FROM category AS t1 LEFT JOIN category AS t2 ON t2.parent = t1.category_id LEFT JOIN category AS t3 ON t3.parent = t2.category_id LEFT JOIN category AS t4 ON t4.parent = t3.category_id WHERE t1.name = 'ELECTRONICS'; +-------------+----------------------+--------------+-------+ | lev1 | lev2 | lev3 | lev4 | +-------------+----------------------+--------------+-------+ | ELECTRONICS | TELEVISIONS | TUBE | NULL | | ELECTRONICS | TELEVISIONS | LCD | NULL | | ELECTRONICS | TELEVISIONS | PLASMA | NULL | | ELECTRONICS | PORTABLE ELECTRONICS | MP3 PLAYERS | FLASH | | ELECTRONICS | PORTABLE ELECTRONICS | CD PLAYERS | NULL | | ELECTRONICS | PORTABLE ELECTRONICS | 2 WAY RADIOS | NULL | +-------------+----------------------+--------------+-------+ 6 rows in set (0.00 sec)
Finding all the Leaf Nodes We can find all the leaf nodes in our tree (those with no children) by using a LEFT JOIN query: SELECT t1.name FROM category AS t1 LEFT JOIN category as t2 ON t1.category_id = t2.parent WHERE t2.category_id IS NULL;
2 of 13
7/9/08 11:59
7.9.
BIJLAGEN I: MANAGING HIERARCHICAL DATA IN MYSQL
MySQL :: Managing Hierarchical Data in MySQL
71
http://dev.mysql.com/tech-resources/articles/hierarchical-data.html
+--------------+ | name | +--------------+ | TUBE | | LCD | | PLASMA | | FLASH | | CD PLAYERS | | 2 WAY RADIOS | +--------------+
Retrieving a Single Path The self-join also allows us to see the full path through our hierarchies: SELECT t1.name AS lev1, t2.name as lev2, t3.name as lev3, t4.name as lev4 FROM category AS t1 LEFT JOIN category AS t2 ON t2.parent = t1.category_id LEFT JOIN category AS t3 ON t3.parent = t2.category_id LEFT JOIN category AS t4 ON t4.parent = t3.category_id WHERE t1.name = 'ELECTRONICS' AND t4.name = 'FLASH'; +-------------+----------------------+-------------+-------+ | lev1 | lev2 | lev3 | lev4 | +-------------+----------------------+-------------+-------+ | ELECTRONICS | PORTABLE ELECTRONICS | MP3 PLAYERS | FLASH | +-------------+----------------------+-------------+-------+ 1 row in set (0.01 sec) The main limitation of such an approach is that you need one self-join for every level in the hierarchy, and performance will naturally degrade with each level added as the joining grows in complexity.
Limitations of the Adjacency List Model Working with the adjacency list model in pure SQL can be difficult at best. Before being able to see the full path of a category we have to know the level at which it resides. In addition, special care must be taken when deleting nodes because of the potential for orphaning an entire sub-tree in the process (delete the portable electronics category and all of its children are orphaned). Some of these limitations can be addressed through the use of client-side code or stored procedures. With a procedural language we can start at the bottom of the tree and iterate upwards to return the full tree or a single path. We can also use procedural programming to delete nodes without orphaning entire sub-trees by promoting one child element and re-ordering the remaining children to point to the new parent.
The Nested Set Model What I would like to focus on in this article is a different approach, commonly referred to as the Nested Set Model. In the Nested Set Model, we can look at our hierarchy in a new way, not as nodes and lines, but as nested containers. Try picturing our electronics categories this way:
3 of 13
7/9/08 11:59 AM
72
HOOFDSTUK 7. BIJLAGEN
MySQL :: Managing Hierarchical Data in MySQL
http://dev.mysql.com/tech-resources/articles/hierarchical-data
Notice how our hierarchy is still maintained, as parent categories envelop their children.We represent this form of hierarchy in a table through the use of left and right values to represent the nesting of our nodes: CREATE TABLE nested_category ( category_id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(20) NOT NULL, lft INT NOT NULL, rgt INT NOT NULL ); INSERT INTO nested_category VALUES(1,'ELECTRONICS',1,20),(2,'TELEVISIONS',2,9),(3,'TUBE',3,4), (4,'LCD',5,6),(5,'PLASMA',7,8),(6,'PORTABLE ELECTRONICS',10,19), (7,'MP3 PLAYERS',11,14),(8,'FLASH',12,13), (9,'CD PLAYERS',15,16),(10,'2 WAY RADIOS',17,18); SELECT * FROM nested_category ORDER BY category_id; +-------------+----------------------+-----+-----+ | category_id | name | lft | rgt | +-------------+----------------------+-----+-----+ | 1 | ELECTRONICS | 1 | 20 | | 2 | TELEVISIONS | 2 | 9 | | 3 | TUBE | 3 | 4 | | 4 | LCD | 5 | 6 | | 5 | PLASMA | 7 | 8 | | 6 | PORTABLE ELECTRONICS | 10 | 19 | | 7 | MP3 PLAYERS | 11 | 14 | | 8 | FLASH | 12 | 13 | | 9 | CD PLAYERS | 15 | 16 | | 10 | 2 WAY RADIOS | 17 | 18 | +-------------+----------------------+-----+-----+ We use lft and rgt because left and right are reserved words in MySQL, see http://dev.mysql.com/doc/mysql/en/reservedwords.html for the full list of reserved words. So how do we determine left and right values? We start numbering at the leftmost side of the outer node and continue to the right:
This design can be applied to a typical tree as well:
4 of 13
7/9/08 11:59
7.9.
BIJLAGEN I: MANAGING HIERARCHICAL DATA IN MYSQL
MySQL :: Managing Hierarchical Data in MySQL
73
http://dev.mysql.com/tech-resources/articles/hierarchical-data.html
When working with a tree, we work from left to right, one layer at a time, descending to each node's children before assigning a right-hand number and moving on to the right. This approach is called the modified preorder tree traversal algorithm.
Retrieving a Full Tree We can retrieve the full tree through the use of a self-join that links parents with nodes on the basis that a node's lft value will always appear between its parent's lft and rgt values: SELECT node.name FROM nested_category AS node, nested_category AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt AND parent.name = 'ELECTRONICS' ORDER BY node.lft; +----------------------+ | name | +----------------------+ | ELECTRONICS | | TELEVISIONS | | TUBE | | LCD | | PLASMA | | PORTABLE ELECTRONICS | | MP3 PLAYERS | | FLASH | | CD PLAYERS | | 2 WAY RADIOS | +----------------------+ Unlike our previous examples with the adjacency list model, this query will work regardless of the depth of the tree. We do not concern ourselves with the rgt value of the node in our BETWEEN clause because the rgt value will always fall within the same parent as the lft values.
Finding all the Leaf Nodes Finding all leaf nodes in the nested set model even simpler than the LEFT JOIN method used in the adjacency list model. If you
5 of 13
7/9/08 11:59 AM
74
HOOFDSTUK 7. BIJLAGEN
MySQL :: Managing Hierarchical Data in MySQL
http://dev.mysql.com/tech-resources/articles/hierarchical-data
look at the nested_category table, you may notice that the lft and rgt values for leaf nodes are consecutive numbers. To find the leaf nodes, we look for nodes where rgt = lft + 1: SELECT name FROM nested_category WHERE rgt = lft + 1; +--------------+ | name | +--------------+ | TUBE | | LCD | | PLASMA | | FLASH | | CD PLAYERS | | 2 WAY RADIOS | +--------------+
Retrieving a Single Path With the nested set model, we can retrieve a single path without having multiple self-joins: SELECT parent.name FROM nested_category AS node, nested_category AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt AND node.name = 'FLASH' ORDER BY parent.lft; +----------------------+ | name | +----------------------+ | ELECTRONICS | | PORTABLE ELECTRONICS | | MP3 PLAYERS | | FLASH | +----------------------+
Finding the Depth of the Nodes We have already looked at how to show the entire tree, but what if we want to also show the depth of each node in the tree, to better identify how each node fits in the hierarchy? This can be done by adding a COUNT function and a GROUP BY clause to our existing query for showing the entire tree: SELECT node.name, (COUNT(parent.name) - 1) AS depth FROM nested_category AS node, nested_category AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt GROUP BY node.name ORDER BY node.lft; +----------------------+-------+ | name | depth | +----------------------+-------+ | ELECTRONICS | 0 | | TELEVISIONS | 1 | | TUBE | 2 | | LCD | 2 | | PLASMA | 2 | | PORTABLE ELECTRONICS | 1 | | MP3 PLAYERS | 2 | | FLASH | 3 | | CD PLAYERS | 2 | | 2 WAY RADIOS | 2 | +----------------------+-------+
6 of 13
7/9/08 11:59
7.9.
BIJLAGEN I: MANAGING HIERARCHICAL DATA IN MYSQL
MySQL :: Managing Hierarchical Data in MySQL
75
http://dev.mysql.com/tech-resources/articles/hierarchical-data.html
We can use the depth value to indent our category names with the CONCAT and REPEAT string functions: SELECT CONCAT( REPEAT(' ', COUNT(parent.name) - 1), node.name) AS name FROM nested_category AS node, nested_category AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt GROUP BY node.name ORDER BY node.lft; +-----------------------+ | name | +-----------------------+ | ELECTRONICS | | TELEVISIONS | | TUBE | | LCD | | PLASMA | | PORTABLE ELECTRONICS | | MP3 PLAYERS | | FLASH | | CD PLAYERS | | 2 WAY RADIOS | +-----------------------+ Of course, in a client-side application you will be more likely to use the depth value directly to display your hierarchy. Web developers could loop through the tree, adding
and
tags as the depth number increases and decreases.
Depth of a Sub-Tree When we need depth information for a sub-tree, we cannot limit either the node or parent tables in our self-join because it will corrupt our results. Instead, we add a third self-join, along with a sub-query to determine the depth that will be the new starting point for our sub-tree: SELECT node.name, (COUNT(parent.name) - (sub_tree.depth + 1)) AS depth FROM nested_category AS node, nested_category AS parent, nested_category AS sub_parent, ( SELECT node.name, (COUNT(parent.name) - 1) AS depth FROM nested_category AS node, nested_category AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt AND node.name = 'PORTABLE ELECTRONICS' GROUP BY node.name ORDER BY node.lft )AS sub_tree WHERE node.lft BETWEEN parent.lft AND parent.rgt AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt AND sub_parent.name = sub_tree.name GROUP BY node.name ORDER BY node.lft; +----------------------+-------+ | name | depth | +----------------------+-------+ | PORTABLE ELECTRONICS | 0 | | MP3 PLAYERS | 1 | | FLASH | 2 | | CD PLAYERS | 1 | | 2 WAY RADIOS | 1 | +----------------------+-------+ This function can be used with any node name, including the root node. The depth values are always relative to the named node.
Find the Immediate Subordinates of a Node 7 of 13
7/9/08 11:59 AM
76
HOOFDSTUK 7. BIJLAGEN
MySQL :: Managing Hierarchical Data in MySQL
http://dev.mysql.com/tech-resources/articles/hierarchical-data
Imagine you are showing a category of electronics products on a retailer web site. When a user clicks on a category, you would want to show the products of that category, as well as list its immediate sub-categories, but not the entire tree of categories beneath it. For this, we need to show the node and its immediate sub-nodes, but no further down the tree. For example, when showing the PORTABLE ELECTRONICS category, we will want to show MP3 PLAYERS, CD PLAYERS, and 2 WAY RADIOS, but not FLASH. This can be easily accomplished by adding a HAVING clause to our previous query: SELECT node.name, (COUNT(parent.name) - (sub_tree.depth + 1)) AS depth FROM nested_category AS node, nested_category AS parent, nested_category AS sub_parent, ( SELECT node.name, (COUNT(parent.name) - 1) AS depth FROM nested_category AS node, nested_category AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt AND node.name = 'PORTABLE ELECTRONICS' GROUP BY node.name ORDER BY node.lft )AS sub_tree WHERE node.lft BETWEEN parent.lft AND parent.rgt AND node.lft BETWEEN sub_parent.lft AND sub_parent.rgt AND sub_parent.name = sub_tree.name GROUP BY node.name HAVING depth <= 1 ORDER BY node.lft; +----------------------+-------+ | name | depth | +----------------------+-------+ | PORTABLE ELECTRONICS | 0 | | MP3 PLAYERS | 1 | | CD PLAYERS | 1 | | 2 WAY RADIOS | 1 | +----------------------+-------+ If you do not wish to show the parent node, change the HAVING depth <= 1 line to HAVING depth = 1.
Aggregate Functions in a Nested Set Let's add a table of products that we can use to demonstrate aggregate functions with: CREATE TABLE product( product_id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(40), category_id INT NOT NULL ); INSERT INTO product(name, category_id) VALUES('20" TV',3),('36" TV',3), ('Super-LCD 42"',4),('Ultra-Plasma 62"',5),('Value Plasma 38"',5), ('Power-MP3 5gb',7),('Super-Player 1gb',8),('Porta CD',9),('CD To go!',9), ('Family Talk 360',10); SELECT * FROM product; +------------+-------------------+-------------+ | product_id | name | category_id | +------------+-------------------+-------------+ | 1 | 20" TV | 3 | | 2 | 36" TV | 3 | | 3 | Super-LCD 42" | 4 | | 4 | Ultra-Plasma 62" | 5 | | 5 | Value Plasma 38" | 5 | | 6 | Power-MP3 128mb | 7 | | 7 | Super-Shuffle 1gb | 8 |
8 of 13
7/9/08 11:59
7.9.
BIJLAGEN I: MANAGING HIERARCHICAL DATA IN MYSQL
MySQL :: Managing Hierarchical Data in MySQL
77
http://dev.mysql.com/tech-resources/articles/hierarchical-data.html
| 8 | Porta CD | 9 | | 9 | CD To go! | 9 | | 10 | Family Talk 360 | 10 | +------------+-------------------+-------------+ Now let's produce a query that can retrieve our category tree, along with a product count for each category: SELECT parent.name, COUNT(product.name) FROM nested_category AS node , nested_category AS parent, product WHERE node.lft BETWEEN parent.lft AND parent.rgt AND node.category_id = product.category_id GROUP BY parent.name ORDER BY node.lft; +----------------------+---------------------+ | name | COUNT(product.name) | +----------------------+---------------------+ | ELECTRONICS | 10 | | TELEVISIONS | 5 | | TUBE | 2 | | LCD | 1 | | PLASMA | 2 | | PORTABLE ELECTRONICS | 5 | | MP3 PLAYERS | 2 | | FLASH | 1 | | CD PLAYERS | 2 | | 2 WAY RADIOS | 1 | +----------------------+---------------------+ This is our typical whole tree query with a COUNT and GROUP BY added, along with a reference to the product table and a join between the node and product table in the WHERE clause. As you can see, there is a count for each category and the count of subcategories is reflected in the parent categories.
Adding New Nodes Now that we have learned how to query our tree, we should take a look at how to update our tree by adding a new node. Let's look at our nested set diagram again:
If we wanted to add a new node between the TELEVISIONS and PORTABLE ELECTRONICS nodes, the new node would have lft and rgt values of 10 and 11, and all nodes to its right would have their lft and rgt values increased by two. We would then add the new node with the appropriate lft and rgt values. While this can be done with a stored procedure in MySQL 5, I will assume for the moment that most readers are using 4.1, as it is the latest stable version, and I will isolate my queries with a LOCK TABLES statement instead: LOCK TABLE nested_category WRITE;
9 of 13
7/9/08 11:59 AM
78
HOOFDSTUK 7. BIJLAGEN
MySQL :: Managing Hierarchical Data in MySQL
http://dev.mysql.com/tech-resources/articles/hierarchical-data
SELECT @myRight := rgt FROM nested_category WHERE name = 'TELEVISIONS';
UPDATE nested_category SET rgt = rgt + 2 WHERE rgt > @myRight; UPDATE nested_category SET lft = lft + 2 WHERE lft > @myRight; INSERT INTO nested_category(name, lft, rgt) VALUES('GAME CONSOLES', @myRight + 1, @myRight + 2); UNLOCK TABLES; We can then check our nesting with our indented tree query: SELECT CONCAT( REPEAT( ' ', (COUNT(parent.name) - 1) ), node.name) AS name FROM nested_category AS node, nested_category AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt GROUP BY node.name ORDER BY node.lft; +-----------------------+ | name | +-----------------------+ | ELECTRONICS | | TELEVISIONS | | TUBE | | LCD | | PLASMA | | GAME CONSOLES | | PORTABLE ELECTRONICS | | MP3 PLAYERS | | FLASH | | CD PLAYERS | | 2 WAY RADIOS | +-----------------------+ If we instead want to add a node as a child of a node that has no existing children, we need to modify our procedure slightly. Let's add a new FRS node below the 2 WAY RADIOS node: LOCK TABLE nested_category WRITE; SELECT @myLeft := lft FROM nested_category WHERE name = '2 WAY RADIOS'; UPDATE nested_category SET rgt = rgt + 2 WHERE rgt > @myLeft; UPDATE nested_category SET lft = lft + 2 WHERE lft > @myLeft; INSERT INTO nested_category(name, lft, rgt) VALUES('FRS', @myLeft + 1, @myLeft + 2); UNLOCK TABLES; In this example we expand everything to the right of the left-hand number of our proud new parent node, then place the node to the right of the left-hand value. As you can see, our new node is now properly nested: SELECT CONCAT( REPEAT( ' ', (COUNT(parent.name) - 1) ), node.name) AS name FROM nested_category AS node, nested_category AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt GROUP BY node.name ORDER BY node.lft; +-----------------------+ | name | +-----------------------+
10 of 13
7/9/08 11:59
7.9.
BIJLAGEN I: MANAGING HIERARCHICAL DATA IN MYSQL
MySQL :: Managing Hierarchical Data in MySQL
79
http://dev.mysql.com/tech-resources/articles/hierarchical-data.html
| ELECTRONICS | | TELEVISIONS | | TUBE | | LCD | | PLASMA | | GAME CONSOLES | | PORTABLE ELECTRONICS | | MP3 PLAYERS | | FLASH | | CD PLAYERS | | 2 WAY RADIOS | | FRS | +-----------------------+
Deleting Nodes The last basic task involved in working with nested sets is the removal of nodes. The course of action you take when deleting a node depends on the node's position in the hierarchy; deleting leaf nodes is easier than deleting nodes with children because we have to handle the orphaned nodes. When deleting a leaf node, the process if just the opposite of adding a new node, we delete the node and its width from every node to its right: LOCK TABLE nested_category WRITE; SELECT @myLeft := lft, @myRight := rgt, @myWidth := rgt - lft + 1 FROM nested_category WHERE name = 'GAME CONSOLES'; DELETE FROM nested_category WHERE lft BETWEEN @myLeft AND @myRight; UPDATE nested_category SET rgt = rgt - @myWidth WHERE rgt > @myRight; UPDATE nested_category SET lft = lft - @myWidth WHERE lft > @myRight; UNLOCK TABLES; And once again, we execute our indented tree query to confirm that our node has been deleted without corrupting the hierarchy: SELECT CONCAT( REPEAT( ' ', (COUNT(parent.name) - 1) ), node.name) AS name FROM nested_category AS node, nested_category AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt GROUP BY node.name ORDER BY node.lft; +-----------------------+ | name | +-----------------------+ | ELECTRONICS | | TELEVISIONS | | TUBE | | LCD | | PLASMA | | PORTABLE ELECTRONICS | | MP3 PLAYERS | | FLASH | | CD PLAYERS | | 2 WAY RADIOS | | FRS | +-----------------------+ This approach works equally well to delete a node and all its children:
11 of 13
7/9/08 11:59 AM
80
HOOFDSTUK 7. BIJLAGEN
MySQL :: Managing Hierarchical Data in MySQL
http://dev.mysql.com/tech-resources/articles/hierarchical-data
LOCK TABLE nested_category WRITE; SELECT @myLeft := lft, @myRight := rgt, @myWidth := rgt - lft + 1 FROM nested_category WHERE name = 'MP3 PLAYERS'; DELETE FROM nested_category WHERE lft BETWEEN @myLeft AND @myRight; UPDATE nested_category SET rgt = rgt - @myWidth WHERE rgt > @myRight; UPDATE nested_category SET lft = lft - @myWidth WHERE lft > @myRight; UNLOCK TABLES; And once again, we query to see that we have successfully deleted an entire sub-tree: SELECT CONCAT( REPEAT( ' ', (COUNT(parent.name) - 1) ), node.name) AS name FROM nested_category AS node, nested_category AS parent WHERE node.lft BETWEEN parent.lft AND parent.rgt GROUP BY node.name ORDER BY node.lft; +-----------------------+ | name | +-----------------------+ | ELECTRONICS | | TELEVISIONS | | TUBE | | LCD | | PLASMA | | PORTABLE ELECTRONICS | | CD PLAYERS | | 2 WAY RADIOS | | FRS | +-----------------------+ The other scenario we have to deal with is the deletion of a parent node but not the children. In some cases you may wish to just change the name to a placeholder until a replacement is presented, such as when a supervisor is fired. In other cases, the child nodes should all be moved up to the level of the deleted parent: LOCK TABLE nested_category WRITE; SELECT @myLeft := lft, @myRight := rgt, @myWidth := rgt - lft + 1 FROM nested_category WHERE name = 'PORTABLE ELECTRONICS'; DELETE FROM nested_category WHERE lft = @myLeft; UPDATE nested_category SET rgt = rgt - 1, lft = lft - 1 WHERE lft BETWEEN @myLeft AND @myRight; UPDATE nested_category SET rgt = rgt - 2 WHERE rgt > @myRight; UPDATE nested_category SET lft = lft - 2 WHERE lft > @myRight; UNLOCK TABLES; In this case we subtract two from all elements to the right of the node (since without children it would have a width of two), and one from the nodes that are its children (to close the gap created by the loss of the parent's left value). Once again, we can confirm our elements have been promoted: SELECT CONCAT( REPEAT( ' ', (COUNT(parent.name) - 1) ), node.name) AS name FROM nested_category AS node, nested_category AS parent
12 of 13
7/9/08 11:59
7.9.
BIJLAGEN I: MANAGING HIERARCHICAL DATA IN MYSQL
MySQL :: Managing Hierarchical Data in MySQL
81
http://dev.mysql.com/tech-resources/articles/hierarchical-data.html
WHERE node.lft BETWEEN parent.lft AND parent.rgt GROUP BY node.name ORDER BY node.lft; +---------------+ | name | +---------------+ | ELECTRONICS | | TELEVISIONS | | TUBE | | LCD | | PLASMA | | CD PLAYERS | | 2 WAY RADIOS | | FRS | +---------------+ Other scenarios when deleting nodes would include promoting one of the children to the parent position and moving the child nodes under a sibling of the parent node, but for the sake of space these scenarios will not be covered in this article.
Final Thoughts While I hope the information within this article will be of use to you, the concept of nested sets in SQL has been around for over a decade, and there is a lot of additional information available in books and on the Internet. In my opinion the most comprehensive source of information on managing hierarchical information is a book called Joe Celko's Trees and Hierarchies in SQL for Smarties, written by a very respected author in the field of advanced SQL, Joe Celko. Joe Celko is often credited with the nested sets model and is by far the most prolific author on the subject. I have found Celko's book to be an invaluable resource in my own studies and highly recommend it. The book covers advanced topics which I have not covered in this article, and provides additional methods for managing hierarchical data in addition to the Adjacency List and Nested Set models. In the References / Resources section that follows I have listed some web resources that may be of use in your research of managing hierarchal data, including a pair of PHP related resources that include pre-built PHP libraries for handling nested sets in MySQL. Those of you who currently use the adjacency list model and would like to experiment with the nested set model will find sample code for converting between the two in the Storing Hierarchical Data in a Database resource listed below. © 1995-2008 MySQL AB. All rights reserved.
13 of 13
7/9/08 11:59 AM