SharpRestoVRII: Difference between revisions

From ICO wiki
Jump to navigationJump to search
Luksti (talk | contribs)
Hannilo (talk | contribs)
 
(11 intermediate revisions by 2 users not shown)
Line 5: Line 5:
* Lauri Üksti
* Lauri Üksti


== Lähtekood ==
== Esitused ==
Link[Link http://enos.itcollege.ee/~luksti/CSharp/CSharpResto.zip]
Lähtekood: [http://enos.itcollege.ee/~luksti/CSharp/CSharpResto.zip CSharpResto]
 
Retsensioonid:


== Tehnoloogia ==
== Tehnoloogia ==
Line 24: Line 26:


== API ==
== API ==
'''Täpsema implementatsiooni lõplikest teenustest leiab [http://csharprestoapp.azurewebsites.net/swagger/ siit]'''
''Lisatud on paar tehnilist teenust (health'i ja security tokeni tarbeks) ja mõned teenused tulevikuks (nt kuupäeva vahemikuga arvete tagastamine).''<br>
Esialgne analüüs:
'''Menüü teenus'''<br>
'''Menüü teenus'''<br>
'''''GET api/menu'''''<br>
'''''GET api/menu'''''<br>
Tagastab kõik menuitemid menüü vaate jaoks<br>
Tagastab kõik menüü artiklid menüü vaate jaoks<br>
Parameetrid:
Parameetrid:
<source>
<source>
Line 35: Line 43:
{
{
"MenuItem":
"MenuItem":
[{
[{ //menuitem objekt},
"Id": 3,
"Name": "Pelmeenid",
"Description": "Venepärased isetehtud pelmeenid",
"Available": 1,
"Spice": 1,
"ItemType": [{
        "id": 4,
        "Type": "Starter"
}],
"ItemPrices": [{
        "Id": 8,
        "Price": 6.5,
        "Active": 1,
        "StartDate": "2018-01-05 14:03:07",
        "EndDate": null
}],
"ItemIngredients": [{
        "id": 2,
        "Name": "Jahu"
},
{
        "id": 5,
        "Name": "Hakkliha"
}]
},
{ //menuitem 2 },
{ //menuitem 2 },
{ //menuitem 3 }
{ //menuitem 3 }
Line 75: Line 58:
</source>
</source>


Väljund:
Tagastab 201 või 400
<source>
{
    "Success": <true|false>,
    "Message": <info|error>,
    "Data": {"id": <id>}
}
</source>


'''''PUT api/menu/{id}'''''<br>
'''''PUT api/menu/{id}'''''<br>
Line 92: Line 68:
}
}
</source>
</source>
Väljund:
Tagastab 200, 400 või 404
<source>
{
    "Success": <true|false>,
    "Message": <info|error>,
    "Data": {"id": <id>}
}
</source>


'''Tellimuste teenus'''<br>
'''Tellimuste teenus'''<br>
'''''GET api/orders'''''<br>
'''''GET api/orders'''''<br>
Tagastab kõik tellimused, vaikimisi filter on otsustamisel<br>
Tagastab kõik tellimused<br>
Parameetrid:
Parameetrid:
<source>
<source>
status (valikuline)
id (valikuline)
table (valikuline)
startDate (valikuline)
endDate (valikuline)
</source>
</source>
Väljund:
Väljund:
Line 115: Line 81:
{
{
     [{order1 object}, {order2 object}]
     [{order1 object}, {order2 object}]
}
</source>
'''''GET api/orders/{id}'''''<br>
Tagastab valitud tellimuse<br>
Väljund:
<source>
{
    Id: <id>,
    MenuItem: {menuItem object},
    Status: <new|ready|served|complete>
    Table: <table>
}
}
</source>
</source>
Line 135: Line 89:
<source>
<source>
{
{
     menuItemId: <menuitem_id>,
     <uus order objekt>   
    tableId: <table_id>,
    course: <?>,
    clientComment: <comment>   
}
</source>
Väljund:
<source>
{
"Success": <true|false>,
"Message": <info|error>,
"Data": {"id": <id>}
}
}
</source>
</source>
Tagastab 201 või 400


'''''PUT api/orders/{id}'''''<br>
'''''PUT api/orders/{id}'''''<br>
Line 155: Line 99:
<source>
<source>
{
{
     menuItemId: <menuitem_id>,
     <muudetud order objekt>   
    tableId: <table_id>,
    course: <?>,
    status: <status>,
    clientComment: <comment>   
}
}
</source>
</source>
Väljund:
Tagastab 200, 400, või 404
<source>
{
    "Success": <true|false>,
    "Message": <info|error>,
    "Data": {"id": <id>}
}
</source>
</source>


Line 177: Line 111:
{status: <status>}
{status: <status>}
</source>
</source>
Väljund:
Tagastab 200, 400 või 404
<source>
{
    "Success": <true|false>,
    "Message": <info|error>,
    "Data": {"id": <id>}
}
</source>


'''Arvete teenus'''<br>
'''Arvete teenus'''<br>
Line 196: Line 123:
<source>
<source>
{  
{  
   “Id”: int,
   <Bill objekt>
  “ItemList”: string,
  “Sum”: decimal,
  “Status”: varchar
  “Date”: datetime,
  “Waiter”: string
}
}
</source>
</source>


Väljund:
Tagastab 200, 400
<source>
{
    success: <true|false>
    message: <info>
    result: {orderItem object}
}
</source>
</source>


Line 217: Line 133:
Parameetrid:
Parameetrid:
<source>
<source>
status (valikuline)
id (valikuline)
table (valikuline)
startDate (valikuline)
endDate (valikuline)
waiter (valikuline)
</source>
</source>


Line 227: Line 139:
<source>
<source>
{
{
   [{bill1 object}, { bill2 object}]
   [{bill1 object},  
    {bill2 object}]
}
}
</source>
== XML ==
XML fail
<source>
<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet type="text/xsl" href="test.xslt"?>
<bills>
  <bill id="1" quantity="2" totalCost="5" notPaid="true">
    <menuArticle id="1">
<name><![CDATA[Hamburger]]></name>
<itemType id="2">
<itemTypeName><![CDATA[Mains]]></itemTypeName>
</itemType>
<price id = "3">
<startTime>2018-01-01-00:00</startTime>
<endTime>2019-01-01-00:00</endTime>
<priceInEur currency="€">3</priceInEur>
</price>
<ingredients>
<ingredient id= "4">
<ingredientName><![CDATA[Sai]]></ingredientName>
</ingredient>
<ingredient id= "5">
<ingredientName><![CDATA[Hakkliha]]></ingredientName>
</ingredient>
<ingredient id= "6">
<ingredientName><![CDATA[Salat]]></ingredientName>
</ingredient>
<ingredient id= "7">
<ingredientName><![CDATA[Kaste]]></ingredientName>
</ingredient>
</ingredients>
    </menuArticle>
        <menuArticle id="9">
<name><![CDATA[Fanta 0,5l]]></name>
<itemType id="2">
<itemTypeName><![CDATA[Drinks]]></itemTypeName>
</itemType>
<price id = "8">
<startTime>2018-01-01-00:00</startTime>
<endTime>2019-01-01-00:00</endTime>
<priceInEur currency="€">2</priceInEur>
</price>
    </menuArticle>
  </bill>
  <bill id="2" quantity="1" totalCost="5" notPaid="false">
    <menuArticle id="1">
<name><![CDATA[Lõbusa Lauri burks]]></name>
<itemType id="2">
<itemTypeName><![CDATA[Mains]]></itemTypeName>
</itemType>
<price id = "5">
<startTime>2018-01-01-00:00</startTime>
<endTime>2019-01-01-00:00</endTime>
<priceInEur currency="€">5</priceInEur>
</price>
<ingredients>
<ingredient id= "4">
<ingredientName><![CDATA[Sai]]></ingredientName>
</ingredient>
<ingredient id= "5">
<ingredientName><![CDATA[Hakkiliha]]></ingredientName>
</ingredient>
<ingredient id= "6">
<ingredientName><![CDATA[Salat]]></ingredientName>
</ingredient>
<ingredient id= "7">
<ingredientName><![CDATA[Salajane Kaste]]></ingredientName>
</ingredient>
</ingredients>
    </menuArticle>
  </bill>
    <bill id="3" quantity="1" totalCost="6" notPaid="true">
    <menuArticle id="1">
<name><![CDATA[Kanapraad]]></name>
<itemType id="2">
<itemTypeName><![CDATA[Mains]]></itemTypeName>
</itemType>
<price id = "7">
<startTime>2018-01-01-00:00</startTime>
<endTime>2019-01-01-00:00</endTime>
<priceInEur currency="€">6</priceInEur>
</price>
<ingredients>
<ingredient id= "4">
<ingredientName><![CDATA[Friikartulid]]></ingredientName>
</ingredient>
<ingredient id= "5">
<ingredientName><![CDATA[Krõbekana]]></ingredientName>
</ingredient>
<ingredient id= "6">
<ingredientName><![CDATA[Salat]]></ingredientName>
</ingredient>
<ingredient id= "7">
<ingredientName><![CDATA[Salajane Kaste]]></ingredientName>
</ingredient>
</ingredients>
    </menuArticle>
  </bill>
 
</bills>
</source>
XSD
<source>
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="bills" type="billsType"/>
  <xs:complexType name="ingredientType">
    <xs:sequence>
      <xs:element name="ingredientName">
        <xs:simpleType>
          <xs:restriction base="xs:string">
            <xs:enumeration value="Sai"/>
            <xs:enumeration value="Hakkliha"/>
            <xs:enumeration value="Salat"/>
            <xs:enumeration value="Kaste"/>
            <xs:enumeration value="Salajane Kaste"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:element>
    </xs:sequence>
    <xs:attribute type="xs:string" name="id" use="optional"/>
  </xs:complexType>
  <xs:complexType name="billsType">
    <xs:sequence>
      <xs:element type="billType" name="bill" maxOccurs="unbounded" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="ingredientsType">
    <xs:sequence>
      <xs:element type="ingredientType" name="ingredient" maxOccurs="32" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="itemTypeType">
    <xs:sequence>
      <xs:element type="xs:string" name="itemTypeName"/>
    </xs:sequence>
    <xs:attribute type="xs:string" name="id" use="optional"/>
  </xs:complexType>
  <xs:complexType name="billType">
    <xs:sequence>
      <xs:element type="menuArticleType" name="menuArticle" maxOccurs="unbounded" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute type="xs:string" name="id" use="optional"/>
    <xs:attribute type="xs:string" name="quantity" use="optional"/>
    <xs:attribute type="xs:string" name="totalCost" use="optional"/>
    <xs:attribute type="xs:string" name="notPaid" use="optional"/>
  </xs:complexType>
  <xs:complexType name="priceType">
    <xs:sequence>
      <xs:element type="xs:string" name="startTime"/>
      <xs:element type="xs:string" name="endTime"/>
      <xs:element type="priceInEurType" name="priceInEur"/>
    </xs:sequence>
    <xs:attribute type="xs:string" name="id" use="optional"/>
  </xs:complexType>
  <xs:complexType name="menuArticleType">
    <xs:sequence>
      <xs:element name="name">
        <xs:simpleType>
          <xs:restriction base="xs:string">
            <xs:enumeration value="Hamburger"/>
            <xs:enumeration value="Fanta 0,5l"/>
            <xs:enumeration value="Lõbusa Lauri burks"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:element>
      <xs:element type="itemTypeType" name="itemType"/>
      <xs:element type="priceType" name="price"/>
      <xs:element type="ingredientsType" name="ingredients" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute type="xs:string" name="id" use="optional"/>
  </xs:complexType>
  <xs:complexType name="priceInEurType">
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute type="xs:string" name="currency" use="optional"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
</xs:schema>
</source>
</source>


'''''GET api/bills/{id}'''''<br>
XLST 1 - Kõik arved ja nende koostised
Tagastab ühe arve id alusel.
<source>
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="/">
    <html>
      <head>
        <h1>Arved</h1>
      </head>
      <body>
  <ol>
<xsl:variable name="notPaid">true</xsl:variable>
<xsl:for-each select="bills/bill">
<li>Arve: <xsl:choose>
<xsl:when test="@notPaid = $notPaid">
<b style="color:red;">MAKSMATA SUMMAS: <xsl:value-of select="@totalCost"/> €</b>
</xsl:when>
<xsl:otherwise>
<b style="color:green;">makstud summas: <xsl:value-of select="@totalCost"/> €</b>
</xsl:otherwise>
</xsl:choose>
<xsl:for-each select="menuArticle">
<xsl:sort select="@id"/>
<ul>Menüü artikkel: <xsl:value-of select="name"/>
<br/>Menüü kategooria: <xsl:value-of select="itemType/itemTypeName"/>
<br/>Hind: <xsl:value-of select="price/priceInEur"/> €
</ul>
<br/>
<xsl:if test="ingredients">Koostisosad:<br/>
<ul style="list-style-type:disc">
<xsl:for-each select="ingredients/ingredient">
<li>
<xsl:value-of select="ingredientName"/>
</li>
</xsl:for-each>
</ul>
<br/>
</xsl:if>
</xsl:for-each>
</li>
<br/>
</xsl:for-each>
</ol>
</body>
    </html>
  </xsl:template>
</xsl:stylesheet>


Väljund:
</source>
 
XLST 2 - Maksmata arved
<source>
<source>
{
<?xml version="1.0" encoding="utf-8"?>
  “Id”: int,
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  “ItemList”: string,
  <xsl:template match="/">
  “Sum”: decimal,
    <html>
  “Status”: varchar
      <head>
  “Date”: datetime,
        <h1>Maksmata arved</h1>
  “Waiter”: string
      </head>
}
      <body>
  <ol>
<xsl:variable name="notPaid">true</xsl:variable>
<xsl:for-each select="bills/bill[@notPaid=$notPaid]">
<li>Arve: <xsl:choose>
<xsl:when test="@notPaid = $notPaid">
<b style="color:red;">MAKSMATA SUMMAS: <xsl:value-of select="@totalCost"/> €</b>
</xsl:when>
<xsl:otherwise>
<b style="color:green;">makstud summas: <xsl:value-of select="@totalCost"/> €</b>
</xsl:otherwise>
</xsl:choose>
<xsl:for-each select="menuArticle">
<xsl:sort select="@id"/>
<ul>Menüü artikkel: <xsl:value-of select="name"/>
<br/>Menüü kategooria: <xsl:value-of select="itemType/itemTypeName"/>
<br/>Hind: <xsl:value-of select="price/priceInEur"/> €
</ul>
<br/>
</xsl:for-each>
</li>
<br/>
</xsl:for-each>
</ol>
</body>
    </html>
  </xsl:template>
</xsl:stylesheet>
 
</source>
</source>
== Retsensioon meeskonnale Hammas ==
'''''Üldine'''''
Retsenseeritav lõi e-poe lahenduse hambaraviseadmeid ja -tehnikat müüvale ettevõttele. Rakendust esimest korda käima pannes tundub, et tegu ei olegi kooli projektiga. Kõik tundub ’nagu päris’ veebipood, mida võiks esmapilgul julgelt juba potentsiaalsele kliendile demoks pakkuda.
Rakenduse kõik komponendid on ühes solution’is: front-end on WebApp moodulis ja back-end API moodulis. Kasutatakse MVC loogikat, mis serveerib angulari komponente. Security eest vastutab IdentityServer4. Samuti kasutatakse Cache’i.
'''''API'''''
Pealtnäha on projekt väga põhjalik ja viimistletud. API, Security, äriloogika on jagatud eri projektidesse. Töötav lahendus on deploytud Azure keskkonda.
Positiivne:
* Väga professionaalne lahendus. Põhimõtteliselt valmistoode.
* On kasutatud tehnoloogiaid, mida antud aine raames ei nõuta.
* Mudelis on string tüüpi muutujatel pikkuse piirangu annotatsioonid.
Murekohad:
* Versioonihalduses leidub suvalisi tühju klasse, mis ei ole nähtavasti Solutionisse kaasatud. (Resources kaust)
* Sellise suure projekti puhul võiks solution’i nimi olla määratud, mitte default.
* Osad klassid on eestikeelsete nimedega (ILD.Business.ViewModels.Maksekeskus_payment_return)
* Kohati segamini camelCase, snake_case ja erinevad suure-väiketähe kombinatsioonid, just nendes samades eestikeelsetes klassides.
* Osad controllerid (ILD.Api.Controllers.CampaignController) on otse ApplicationDbContexti pihta arendatud, teistes jällegi on sisse toodud oma service’id.
* DTO mustri kasutamine on segane. Osades kohtades on juskui VM sisse pandud andmete liigutamine, teistes jällegi töötab controller otse mudeliga.
* Mudelitel on H ja R vormid, tundub, nagu oleks Header(?) ja Row(?) tüüpi olemitega tegu, aga täpsemat dokumentatsiooni ei ole.
* Sellise skoobiga tööl oleks kindlasti võinud kaaluda uow kasutamist, sest sellise projekti edasiarendamisel võib tänu sellele tekkida tagasilööke või tekkida liigne ajakulu. Samuti kui muu kood on nii mitmeks mooduliks jaotatud, siis võiks eeldada, et projektis kasutatakse ka uow’d.
Tõsisemad probleemid:
* API dokumentatsiooni ei ole leitav. Readme failis sellele ei viidata, ei leidnud ka kirjalikul kujul dokumenti.
* Projektil puudub versioonihalduse ajalugu. Enamikel tiimidel pole avalikku VCSi, kuid sealsed projektid ei eristunud nii tugevalt loengumaterjalidest ja -mustritest. Käesoleva projekti professionaalset taset ja toodud versioonihalduse vabandust vaadates tekivad mõned kahtlused.
Kuna leht paistab olevat suunatud reaalse ettevõtte tarbeks tekib küsimusi:
* Kas tegu on ikka ühemeheprojektiga? See ei ole kuidagi välistatud, ent hea oleks taust ära mainida.
* Kas selle lähtekoodi avaldamiseks on kõikide osapoolte nõusolek?
'''''Klientrakendus'''''
Rakendus on loodud dünaamilisena ning kasutajasõbralikuna, toodete juures on välja toodud isegi allahindlusprotsent ning see, kas tegemist on uue tootega.
Tooteid saab kategooria ja kaubamärgi järgi filtreerida, seejärel saab sobivad tooted ostukorvi lisada. Kui tooted on valitud, siis saab minna ostukorvi sisu vaatama, seal saab veel koguseid muuta ning tooteid kustutada, kui vaja. Kui soovitud tooted valitud, saab ostu ka vormistama minna, kus tuleb sisestada enda andmed ning soovitud tarneviis. (Ka makseviiside valik on ära toodud, mis suurendab eespool mainitud ’nagu päris’ tunnet veelgi.)
Lisatud on ka kasutaja loomise võimalus, mis küll õigusi juurde ei anna. Küll aga on rohkem õigusi administraatori õigustega kasutajal. Tema saab kasutajaid hallata ning lisada/muuta hinnakirja. Samuti saab administraator hallata tarnijate informatsiooni.
Rakendust saab kasutada lisaks eesti keelele ka inglise ja vene keeles.
Arhitektuuriliselt on frontend arendatud väga modulaarselt, mis jätab palju ruumi edasisteks arendusteks ning projekti täiustamiseks.
Tähelepanekud:
* Admin vaates arusaamatud input väljad
Visuaalse poole ning frontendi mooduliteks jagamise oskuse poolest ei saaks grupile (üks inimene!) anda madalamat hinnet, kui maksimum.
'''''XML'''''
XML’is on kasutatud loogilisi andmeid ning elementide string väärtused on käsitletud CDATA’ga, mis välistab selle, et infot kuvatakse täpselt nii, kuidas ette on nähtud. XMLis on kasutatud ülesandes nõutud nelja dimensiooni.
XSD on koostatud loogiliselt ning pea kõikidele elementidele on määratud asjakohased tüübid - näiteks id on integerid, quantity on decimal, name on string jne. Lisaks on kasutatud erinevaid skeemi kirjeldavaid atribuute nagu näiteks minOccurs/maxOccurs atribuudid, nimetused, use atribuut (kas väli on required või optional) jne. Retsenseerijate arvates on kasutusele võetud atribuudid ja nende väärtused antud kontekstis asjakohased.
XML näidisfail valideerub edukalt vastu XSD’d. Seda testisid retsenseerijad online xsd validaatoriga, mille võib leida aadressilt: http://www.utilities-online.info/xsdvalidation/ .
Kodutöös on kirjeldatud kahte tüüpi transformatsioone - üks, mis väljastab transformatsiooni html’i ja teine xml’i. Mõlemas transformatsioonis kasutatakse for each tsükleid ja if-tingimusi. HTML väljundiga transformatsioon kuvab tooteid, koos tõlgete, hinna, saadavuse ja erinevate atribuutidega. XML’i transformatsioon grupeerib tooted vastavalt laole.
'''''Kokkuvõte'''''
Meeskond Hammas on saanud ülesandega hästi hakkama, sest kõik tingimused on täidetud (ja rohkemgi) ning arvestades seda, et meeskonnas on üks inimene, siis on retsensentide arvates tehtud töö suurepärane.


== Ajalogi ==
== Ajalogi ==
TBD
Analüüsi tegemine 25.03-01.04 <br/>
Programmeerimine 04.02-27.05

Latest revision as of 18:59, 11 June 2018

Meeskond

  • Andres Aava (lahkunud liige)
  • Henri Annilo
  • Jaan Koolmeister
  • Lauri Üksti

Esitused

Lähtekood: CSharpResto

Retsensioonid:

Tehnoloogia

Server: ASP.NET Core 2.0
Klient: WPF
DB: SQL Server (Azure)

Ülevaade

Tegemist on SharpResto jätkuprojektiga.

Eesmärk on luua restoranihalduse teenus

  • kasutaja saab pärida, lisada ja muuta menüü komponente
  • kasutaja saab pärida, lisada ja muuta esitatud tellimusi
  • kasutaja saab pärida statistikat tellimuste kohta
  • eri teenuste ligipääs on piiratav kasutaja- ning grupipõhiselt
  • staatiline informatsioon hoitakse serveri vahemälus

API

Täpsema implementatsiooni lõplikest teenustest leiab siit Lisatud on paar tehnilist teenust (health'i ja security tokeni tarbeks) ja mõned teenused tulevikuks (nt kuupäeva vahemikuga arvete tagastamine).

Esialgne analüüs:

Menüü teenus
GET api/menu
Tagastab kõik menüü artiklid menüü vaate jaoks
Parameetrid:

id (valikuline)

Väljund:

{
"MenuItem":
[{ //menuitem objekt},
{ //menuitem 2 },
{ //menuitem 3 }
]}

POST api/menu/
Loob uue menuItem’i
Body:

{ 
//new MenuItem object
}

Tagastab 201 või 400

PUT api/menu/{id}
Muudab olemasolevat menuItem’it
Body:

{ 
// changed MenuItem object
}

Tagastab 200, 400 või 404

Tellimuste teenus
GET api/orders
Tagastab kõik tellimused
Parameetrid:

id (valikuline)

Väljund:

{
    [{order1 object}, {order2 object}]
}

POST api/orders
Loob uue tellimuse
Body:

{
    <uus order objekt>  
}

Tagastab 201 või 400

PUT api/orders/{id}
Muudab tellimust (üldine)
Body:

{
    <muudetud order objekt>  
}

Tagastab 200, 400, või 404 </source>

PUT api/orders/setStatus/{id}
Muudab vaid tellimuse staatust
Body:

{status: <status>}

Tagastab 200, 400 või 404

Arvete teenus
Lõpetatud/serveeritud tellimuste salvestamine arveteks.
Hilisem arvete küsimine.

POST api/bills Arvete sisestamine.

Body:

{ 
   <Bill objekt>
}

Tagastab 200, 400 </source>

GET api/bills
Parameetrid:

id (valikuline)

Väljund:

{
   [{bill1 object}, 
    {bill2 object}]
}

XML

XML fail

<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet type="text/xsl" href="test.xslt"?>
<bills>
  <bill id="1" quantity="2" totalCost="5" notPaid="true">
    <menuArticle id="1">
		<name><![CDATA[Hamburger]]></name>
		<itemType id="2">
			<itemTypeName><![CDATA[Mains]]></itemTypeName>
		</itemType>
		<price id = "3">
			<startTime>2018-01-01-00:00</startTime>
			<endTime>2019-01-01-00:00</endTime>
			<priceInEur currency="€">3</priceInEur>
		</price>
		<ingredients>
			<ingredient id= "4">
				<ingredientName><![CDATA[Sai]]></ingredientName>
			</ingredient>
			<ingredient id= "5">
				<ingredientName><![CDATA[Hakkliha]]></ingredientName>
			</ingredient>
			<ingredient id= "6">
				<ingredientName><![CDATA[Salat]]></ingredientName>
			</ingredient>
			<ingredient id= "7">
				<ingredientName><![CDATA[Kaste]]></ingredientName>
			</ingredient>
		</ingredients>
    </menuArticle>
        <menuArticle id="9">
		<name><![CDATA[Fanta 0,5l]]></name>
		<itemType id="2">
			<itemTypeName><![CDATA[Drinks]]></itemTypeName>
		</itemType>
		<price id = "8">
			<startTime>2018-01-01-00:00</startTime>
			<endTime>2019-01-01-00:00</endTime>
			<priceInEur currency="€">2</priceInEur>
		</price>
    </menuArticle>
  </bill>
  <bill id="2" quantity="1" totalCost="5" notPaid="false">
    <menuArticle id="1">
		<name><![CDATA[Lõbusa Lauri burks]]></name>
		<itemType id="2">
			<itemTypeName><![CDATA[Mains]]></itemTypeName>
		</itemType>
		<price id = "5">
			<startTime>2018-01-01-00:00</startTime>
			<endTime>2019-01-01-00:00</endTime>
			<priceInEur currency="€">5</priceInEur>
		</price>
		<ingredients>
			<ingredient id= "4">
				<ingredientName><![CDATA[Sai]]></ingredientName>
			</ingredient>
			<ingredient id= "5">
				<ingredientName><![CDATA[Hakkiliha]]></ingredientName>
			</ingredient>
			<ingredient id= "6">
				<ingredientName><![CDATA[Salat]]></ingredientName>
			</ingredient>
			<ingredient id= "7">
				<ingredientName><![CDATA[Salajane Kaste]]></ingredientName>
			</ingredient>
		</ingredients>
    </menuArticle>
  </bill>
    <bill id="3" quantity="1" totalCost="6" notPaid="true">
    <menuArticle id="1">
		<name><![CDATA[Kanapraad]]></name>
		<itemType id="2">
			<itemTypeName><![CDATA[Mains]]></itemTypeName>
		</itemType>
		<price id = "7">
			<startTime>2018-01-01-00:00</startTime>
			<endTime>2019-01-01-00:00</endTime>
			<priceInEur currency="€">6</priceInEur>
		</price>
		<ingredients>
			<ingredient id= "4">
				<ingredientName><![CDATA[Friikartulid]]></ingredientName>
			</ingredient>
			<ingredient id= "5">
				<ingredientName><![CDATA[Krõbekana]]></ingredientName>
			</ingredient>
			<ingredient id= "6">
				<ingredientName><![CDATA[Salat]]></ingredientName>
			</ingredient>
			<ingredient id= "7">
				<ingredientName><![CDATA[Salajane Kaste]]></ingredientName>
			</ingredient>
		</ingredients>
    </menuArticle>
  </bill>
  
</bills>

XSD

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="bills" type="billsType"/>
  <xs:complexType name="ingredientType">
    <xs:sequence>
      <xs:element name="ingredientName">
        <xs:simpleType>
          <xs:restriction base="xs:string">
            <xs:enumeration value="Sai"/>
            <xs:enumeration value="Hakkliha"/>
            <xs:enumeration value="Salat"/>
            <xs:enumeration value="Kaste"/>
            <xs:enumeration value="Salajane Kaste"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:element>
    </xs:sequence>
    <xs:attribute type="xs:string" name="id" use="optional"/>
  </xs:complexType>
  <xs:complexType name="billsType">
    <xs:sequence>
      <xs:element type="billType" name="bill" maxOccurs="unbounded" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="ingredientsType">
    <xs:sequence>
      <xs:element type="ingredientType" name="ingredient" maxOccurs="32" minOccurs="0"/>
    </xs:sequence>
  </xs:complexType>
  <xs:complexType name="itemTypeType">
    <xs:sequence>
      <xs:element type="xs:string" name="itemTypeName"/>
    </xs:sequence>
    <xs:attribute type="xs:string" name="id" use="optional"/>
  </xs:complexType>
  <xs:complexType name="billType">
    <xs:sequence>
      <xs:element type="menuArticleType" name="menuArticle" maxOccurs="unbounded" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute type="xs:string" name="id" use="optional"/>
    <xs:attribute type="xs:string" name="quantity" use="optional"/>
    <xs:attribute type="xs:string" name="totalCost" use="optional"/>
    <xs:attribute type="xs:string" name="notPaid" use="optional"/>
  </xs:complexType>
  <xs:complexType name="priceType">
    <xs:sequence>
      <xs:element type="xs:string" name="startTime"/>
      <xs:element type="xs:string" name="endTime"/>
      <xs:element type="priceInEurType" name="priceInEur"/>
    </xs:sequence>
    <xs:attribute type="xs:string" name="id" use="optional"/>
  </xs:complexType>
  <xs:complexType name="menuArticleType">
    <xs:sequence>
      <xs:element name="name">
        <xs:simpleType>
          <xs:restriction base="xs:string">
            <xs:enumeration value="Hamburger"/>
            <xs:enumeration value="Fanta 0,5l"/>
            <xs:enumeration value="Lõbusa Lauri burks"/>
          </xs:restriction>
        </xs:simpleType>
      </xs:element>
      <xs:element type="itemTypeType" name="itemType"/>
      <xs:element type="priceType" name="price"/>
      <xs:element type="ingredientsType" name="ingredients" minOccurs="0"/>
    </xs:sequence>
    <xs:attribute type="xs:string" name="id" use="optional"/>
  </xs:complexType>
  <xs:complexType name="priceInEurType">
    <xs:simpleContent>
      <xs:extension base="xs:string">
        <xs:attribute type="xs:string" name="currency" use="optional"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
</xs:schema>

XLST 1 - Kõik arved ja nende koostised

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="/">
    <html>
      <head>
        <h1>Arved</h1>
      </head>
      <body>
	  <ol>
					<xsl:variable name="notPaid">true</xsl:variable>
					<xsl:for-each select="bills/bill">
						<li>Arve: <xsl:choose>
								<xsl:when test="@notPaid = $notPaid">
									<b style="color:red;">MAKSMATA SUMMAS: <xsl:value-of select="@totalCost"/> €</b>
								</xsl:when>
								<xsl:otherwise>
									<b style="color:green;">makstud summas: <xsl:value-of select="@totalCost"/> €</b>
								</xsl:otherwise>
							</xsl:choose>
							<xsl:for-each select="menuArticle">
								<xsl:sort select="@id"/>
								<ul>Menüü artikkel: <xsl:value-of select="name"/>
									<br/>Menüü kategooria: <xsl:value-of select="itemType/itemTypeName"/>
									<br/>Hind: <xsl:value-of select="price/priceInEur"/> €
								</ul>
								<br/>
								<xsl:if test="ingredients">Koostisosad:<br/>
									<ul style="list-style-type:disc">
										<xsl:for-each select="ingredients/ingredient">
											<li>
												<xsl:value-of select="ingredientName"/>
											</li>
										</xsl:for-each>
									</ul>
									<br/>
								</xsl:if>
							</xsl:for-each>
						</li>
						<br/>
					</xsl:for-each>
				</ol>
			</body>
    </html>
  </xsl:template>
</xsl:stylesheet>

XLST 2 - Maksmata arved

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:template match="/">
    <html>
      <head>
        <h1>Maksmata arved</h1>
      </head>
      <body>
	  <ol>
					<xsl:variable name="notPaid">true</xsl:variable>
					<xsl:for-each select="bills/bill[@notPaid=$notPaid]">
						<li>Arve: <xsl:choose>
								<xsl:when test="@notPaid = $notPaid">
									<b style="color:red;">MAKSMATA SUMMAS: <xsl:value-of select="@totalCost"/> €</b>
								</xsl:when>
								<xsl:otherwise>
									<b style="color:green;">makstud summas: <xsl:value-of select="@totalCost"/> €</b>
								</xsl:otherwise>
							</xsl:choose>
							<xsl:for-each select="menuArticle">
								<xsl:sort select="@id"/>
								<ul>Menüü artikkel: <xsl:value-of select="name"/>
									<br/>Menüü kategooria: <xsl:value-of select="itemType/itemTypeName"/>
									<br/>Hind: <xsl:value-of select="price/priceInEur"/> €
								</ul>
								<br/>
							</xsl:for-each>
						</li>
						<br/>
					</xsl:for-each>
				</ol>
			</body>
    </html>
  </xsl:template>
</xsl:stylesheet>

Retsensioon meeskonnale Hammas

Üldine

Retsenseeritav lõi e-poe lahenduse hambaraviseadmeid ja -tehnikat müüvale ettevõttele. Rakendust esimest korda käima pannes tundub, et tegu ei olegi kooli projektiga. Kõik tundub ’nagu päris’ veebipood, mida võiks esmapilgul julgelt juba potentsiaalsele kliendile demoks pakkuda.

Rakenduse kõik komponendid on ühes solution’is: front-end on WebApp moodulis ja back-end API moodulis. Kasutatakse MVC loogikat, mis serveerib angulari komponente. Security eest vastutab IdentityServer4. Samuti kasutatakse Cache’i.

API

Pealtnäha on projekt väga põhjalik ja viimistletud. API, Security, äriloogika on jagatud eri projektidesse. Töötav lahendus on deploytud Azure keskkonda.

Positiivne:

  • Väga professionaalne lahendus. Põhimõtteliselt valmistoode.
  • On kasutatud tehnoloogiaid, mida antud aine raames ei nõuta.
  • Mudelis on string tüüpi muutujatel pikkuse piirangu annotatsioonid.

Murekohad:

  • Versioonihalduses leidub suvalisi tühju klasse, mis ei ole nähtavasti Solutionisse kaasatud. (Resources kaust)
  • Sellise suure projekti puhul võiks solution’i nimi olla määratud, mitte default.
  • Osad klassid on eestikeelsete nimedega (ILD.Business.ViewModels.Maksekeskus_payment_return)
  • Kohati segamini camelCase, snake_case ja erinevad suure-väiketähe kombinatsioonid, just nendes samades eestikeelsetes klassides.
  • Osad controllerid (ILD.Api.Controllers.CampaignController) on otse ApplicationDbContexti pihta arendatud, teistes jällegi on sisse toodud oma service’id.
  • DTO mustri kasutamine on segane. Osades kohtades on juskui VM sisse pandud andmete liigutamine, teistes jällegi töötab controller otse mudeliga.
  • Mudelitel on H ja R vormid, tundub, nagu oleks Header(?) ja Row(?) tüüpi olemitega tegu, aga täpsemat dokumentatsiooni ei ole.
  • Sellise skoobiga tööl oleks kindlasti võinud kaaluda uow kasutamist, sest sellise projekti edasiarendamisel võib tänu sellele tekkida tagasilööke või tekkida liigne ajakulu. Samuti kui muu kood on nii mitmeks mooduliks jaotatud, siis võiks eeldada, et projektis kasutatakse ka uow’d.

Tõsisemad probleemid:

  • API dokumentatsiooni ei ole leitav. Readme failis sellele ei viidata, ei leidnud ka kirjalikul kujul dokumenti.
  • Projektil puudub versioonihalduse ajalugu. Enamikel tiimidel pole avalikku VCSi, kuid sealsed projektid ei eristunud nii tugevalt loengumaterjalidest ja -mustritest. Käesoleva projekti professionaalset taset ja toodud versioonihalduse vabandust vaadates tekivad mõned kahtlused.

Kuna leht paistab olevat suunatud reaalse ettevõtte tarbeks tekib küsimusi:

  • Kas tegu on ikka ühemeheprojektiga? See ei ole kuidagi välistatud, ent hea oleks taust ära mainida.
  • Kas selle lähtekoodi avaldamiseks on kõikide osapoolte nõusolek?

Klientrakendus

Rakendus on loodud dünaamilisena ning kasutajasõbralikuna, toodete juures on välja toodud isegi allahindlusprotsent ning see, kas tegemist on uue tootega. Tooteid saab kategooria ja kaubamärgi järgi filtreerida, seejärel saab sobivad tooted ostukorvi lisada. Kui tooted on valitud, siis saab minna ostukorvi sisu vaatama, seal saab veel koguseid muuta ning tooteid kustutada, kui vaja. Kui soovitud tooted valitud, saab ostu ka vormistama minna, kus tuleb sisestada enda andmed ning soovitud tarneviis. (Ka makseviiside valik on ära toodud, mis suurendab eespool mainitud ’nagu päris’ tunnet veelgi.) Lisatud on ka kasutaja loomise võimalus, mis küll õigusi juurde ei anna. Küll aga on rohkem õigusi administraatori õigustega kasutajal. Tema saab kasutajaid hallata ning lisada/muuta hinnakirja. Samuti saab administraator hallata tarnijate informatsiooni. Rakendust saab kasutada lisaks eesti keelele ka inglise ja vene keeles. Arhitektuuriliselt on frontend arendatud väga modulaarselt, mis jätab palju ruumi edasisteks arendusteks ning projekti täiustamiseks.

Tähelepanekud:

  • Admin vaates arusaamatud input väljad

Visuaalse poole ning frontendi mooduliteks jagamise oskuse poolest ei saaks grupile (üks inimene!) anda madalamat hinnet, kui maksimum.

XML

XML’is on kasutatud loogilisi andmeid ning elementide string väärtused on käsitletud CDATA’ga, mis välistab selle, et infot kuvatakse täpselt nii, kuidas ette on nähtud. XMLis on kasutatud ülesandes nõutud nelja dimensiooni.

XSD on koostatud loogiliselt ning pea kõikidele elementidele on määratud asjakohased tüübid - näiteks id on integerid, quantity on decimal, name on string jne. Lisaks on kasutatud erinevaid skeemi kirjeldavaid atribuute nagu näiteks minOccurs/maxOccurs atribuudid, nimetused, use atribuut (kas väli on required või optional) jne. Retsenseerijate arvates on kasutusele võetud atribuudid ja nende väärtused antud kontekstis asjakohased.

XML näidisfail valideerub edukalt vastu XSD’d. Seda testisid retsenseerijad online xsd validaatoriga, mille võib leida aadressilt: http://www.utilities-online.info/xsdvalidation/ .

Kodutöös on kirjeldatud kahte tüüpi transformatsioone - üks, mis väljastab transformatsiooni html’i ja teine xml’i. Mõlemas transformatsioonis kasutatakse for each tsükleid ja if-tingimusi. HTML väljundiga transformatsioon kuvab tooteid, koos tõlgete, hinna, saadavuse ja erinevate atribuutidega. XML’i transformatsioon grupeerib tooted vastavalt laole.

Kokkuvõte

Meeskond Hammas on saanud ülesandega hästi hakkama, sest kõik tingimused on täidetud (ja rohkemgi) ning arvestades seda, et meeskonnas on üks inimene, siis on retsensentide arvates tehtud töö suurepärane.

Ajalogi

Analüüsi tegemine 25.03-01.04
Programmeerimine 04.02-27.05