<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>En dansk blog om Javascript og Webudvikling</title>
	<atom:link href="http://rune.gronkjaer.dk/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://rune.gronkjaer.dk/blog</link>
	<description>Rune Grønkjær</description>
	<lastBuildDate>Fri, 30 Sep 2016 11:21:33 +0000</lastBuildDate>
	<language>da-DK</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.6.4</generator>
	<item>
		<title>Tea Commerce Master product</title>
		<link>http://rune.gronkjaer.dk/blog/2011/09/08/tea-commerce-master-product/</link>
		<pubDate>Thu, 08 Sep 2011 09:30:59 +0000</pubDate>
		<dc:creator><![CDATA[Rune Grønkjær]]></dc:creator>
				<category><![CDATA[e-commerce]]></category>
		<category><![CDATA[sprog]]></category>
		<category><![CDATA[sprogversionering]]></category>
		<category><![CDATA[Tea Commerce]]></category>
		<category><![CDATA[umbraco]]></category>
		<category><![CDATA[xslt]]></category>
		<category><![CDATA[ecommerce]]></category>

		<guid isPermaLink="false">http://rune.gronkjaer.dk/blog/?p=982</guid>
		<description><![CDATA[Denne blogpost vil forklare hvordan basisprodukter, de såkaldte Master produkter, fungerer i Tea Commerce. ]]></description>
				<content:encoded><![CDATA[Denne blogpost vil forklare hvordan basisprodukter, de såkaldte Master produkter, fungerer i Tea Commerce. 
<h2>Hvad er et Master produkt i Tea Commerce?</h2>
Først og fremmest skal man forstå, at Tea Commerce produkter bare er ganske almindelige indholdsnoder i Umbraco. Noderne har en række properties, som webudvikleren selv giver dem. Umbraco lader alle sine noder nedarve properties fra noder længere oppe i træstrukturen. 
<h3>Varianter</h3>
For produktnoder betyder det, at man kan lave varianter, som undernoder til en produktnode. Det benytter vi os fx af i <a href="http://www.teacommerce.dk/en/products/tea-commerce-starter-kit.aspx">Tea Commerce Starter Kit&#8217;et</a>, hvor nogle produkter har varianter.<br /><br />
Som man kan se på figur 1 herunder ligger der en rød og en blå variant under &#8220;Product A1&#8221;. Det giver mulighed for, at lade hovedproduktet indeholde hovedparten af produktinformationerne, så varianterne bare skal have informationer omkring lagerstand, navn og eventuelt andre properties, som afviger fra hovedproduktet. Pilen angiver hvordan varianter arver fra deres hovedprodukt.
<h4>Fig. 1 &#8211; Varianter i Tea Commerce</h4>
<img src="http://www.teacommerce.dk/blogmedia/images/normal-variants.png" alt="Variants in Tea Commerce" class="illustration" />
<h3>Tea Commerce Master product</h3>
Med et Tea Commerce Master product går vi skridtet videre og lader et produkt arve fra et produkt, som er placeret et helt andet sted i indholdstræet. Denne type opsætning benytter vi i <a href="http://www.teacommerce.dk/en/products/tea-commerce-multilanguage-starter-kit.aspx">Tea Commerce Multilanguage Kit&#8217;et</a>. <br /><br />
På figur 2 viser jeg hvordan nedarvningen ville foregå hvis den røde variant havde et Master product tilknyttet. På figur 3 kan man se hvordan det foregår uden varianter. Mere om det lidt senere.
<h4>Fig. 2 &#8211; Master product og varianter i Tea Commerce</h4>
<img src="http://www.teacommerce.dk/blogmedia/images/variants-masterproduct.png" alt="Master product and variants in Tea Commerce" class="illustration" />
<h4>Fig. 3 &#8211; Master product uden varianter i Tea Commerce</h4>
<img src="http://www.teacommerce.dk/blogmedia/images/masterproduct-no-variants.png" alt="Master product without variants in Tea Commerce" class="illustration" />
<h2>Hvordan sættes Tea Commerce Master products op?</h2>
For at få dine produkter til at snakke sammen med et Master product, skal der sættes et par ting op i Tea Commerce og Umbraco. For at se et eksempel på hvordan det ser ud når Master products er sat korrekt op kan du prøve at installere <a href="http://www.teacommerce.dk/en/products/tea-commerce-multilanguage-starter-kit.aspx">Tea Commerce Multilanguage Kit&#8217;et</a>, som benytter Master products.
<h3>1. Produktets dokumenttype</h3>
De produkter, som skal kunne have et Master product, skal have en property til valg af en anden Umbraco node. Denne property kan vi kalde &#8220;Master product&#8221; og give den alias&#8217;et &#8220;masterProduct&#8221;. Dets type skal være noget, som kan give os id&#8217;et på den Master product noden. Typen kan derfor godt være et almindeligt tekstfelt, men en Content Picker eller en UComponents Multinode tree picker vil være at foretrække for brugeren. Sidstnævnte er specielt god, da den kan begrænse brugerens valgmuligheder.
<h3>2. Opsætning i Tea Commerce sektionen</h3>
Nu skal du ind under &#8220;Generelle indstillinger i Tea Commerce sektionen. Her skal du skrive alias&#8217;et, på den property vi lige har lavet, i feltet &#8220;Hovedprodukt property alias&#8221;. Nu ved Tea Commerce, hvad den skal kigge efter, for at finde produktets Master product.
<h3>3. Vælg et Master product på et af dine produkter</h3>
Nu skal du have oprettet et Master produkt og derefter lave et produkt, som peger ned på Master produktet med dets &#8220;masterProduct&#8221; property.
<h3>4. Udskriv produktinfo på din produktside</h3>
Nu skal vi have hentet nogle informationer om produktet ud på websitets produktvisning. For at hente en property ud fra produktet har Tea Commerce xslt library&#8217;et en metode kaldet GetProperty, som klarer ærterne for dig. GetProperty tager to parametre, hvor den første er produktnoden selv og den anden er alias&#8217;et på den property man ønsker at hente.
<h2>Hvordan fungerer Tea Commerce Master products?</h2>
Der er indtil nu tre scenarier hvori Master products bliver brugt. Det ene er GetProperty, som er nævnt herover. Det anden er en anden library metode, GetStock, som benyttes til at hente lagerstanden for et produkt. Det tredje scenarie, hvori Master products bliver brugt, er når et produkt tilføjes til kurven og den nye ordrelinie skal have tilføjet informationer fra produktet.<br /><br />
Fælles for alle tre er måden Tea Commerce vil forsøge at hente informationerne ud fra produktet. Med udgangspunkt i opsætningen i figur 2 kan man forklare det således:
<ol>
<li>Der forespørges fx efter property&#8217;en &#8220;productPrice&#8221;, på produktet &#8220;Red&#8221;, med library metoden GetPropert.y</li>
<li>Tea Commerce leder først på noden &#8220;Red&#8221;. Hvis den har en property kaldet &#8220;productPrice&#8221; og den property ikke er tom stopper den søgningen.</li>
<li>Har den ikke fundet noget laver den samme søgning op igennem nodetræet med udgangspunkt i noden &#8220;Red&#8221;. Nu vil den altså gennemsøge blandt anden &#8220;Product A1&#8221;, men også &#8220;Category A&#8221;, &#8220;Products&#8221; osv. Selve søgningen foregår med xpath i Umbraco&#8217;s cachede XML, så performance holdes høj.</li>
<li>Har Tea Commerce stadig ikke fundet det den søger, vil den finde &#8220;Red&#8221; nodens Master product og med udgangspunkt i den vil den lave samme søgning op igennem træet.</li>
</ol>
<h2>Hvad kan Tea Commerce Master products bruges til?</h2>
<h3>Sprogversionering af Tea Commerce produkter</h3>
Hele ideen med Master products i Tea Commerce, har fra starten været, at gøre det let at sprogversionere dine produkter. Ideen i denne situation at lade Master products indeholde alle de informationer om produktet, som ikke er sprogspecifikke. På den måde vil man ikke skulle indtaste disse informationer igen og igen, på samtlige sprog, hvilket også giver store problemer med at holde data konsistente. På det enkelte produkt kan man så fokusere på at taste teskter ind på det sprog man er på. Læs eventuelt lidt mere om dette i <a href="http://rune.gronkjaer.dk/blog/?p=968">denne blogpost omkring sprog, lande og valutaer</a>.
<h3>Samme produkt i flere kategorier</h3>
Man kan også benytte Master products til at placere samme produkt i flere kategorier. Man vil kunne lave alle produkter uden for det regulære indholdstræ og så lave nogle &#8220;tynde&#8221; produkter, som bare linker ned til et Master product. De tynde produkter behøver så ikke at have indtastet nogen informationer overhovedet og Tea Commerce vil så hente alle informationer fra deres Master product.
<h2>Et konkret eksempel</h2>
I nedenstående eksempel vil jeg hente et produkts navn, lagerstand og pris ud. I eksemplet benyttes der varianter, som i figur 2, og for at være sikker på, at jeg får en variant at tage udgangspunkt i, vælger jeg varianten, som jeg ved er en leaf node. En leaf node er en af de yderste noder i træet. Hvis jeg allerede står på en af varianterne vil den pågældende variant blive valgt. Hvis jeg står på hovedproduktet vil den først variant blive valgt. Hvis der slet ikke er varianter vil hovedproduktet selv bare blive valgt.
<h4>Eksempel i brugen af Master products</h4>
<pre class="brush: xslt">
<xsl:template match="Product">
  <!-- Get the variant. -->
  <xsl:variable name="variant" select="./descendant-or-self::Product [not(child::Product)][1]"/>

  <!-- Use GetProperty to get the productName property value -->
  <xsl:variable name="productName" select="teacommerce:GetProperty($variant, 'productName')" />

  <!-- Use GetStock to fetch the stock of the product -->
  <xsl:variable name="stock" select="teacommerce:GetStock($variant)" />

  <!-- Use GetProperty to get the price of the product and FormatPriceNoSymbol to format it nicely -->
  <xsl:variable name="price" select="teacommerce:FormatPriceNoSymbol(teacommerce:GetProperty($variant, 'productPrice'))" />
</xsl:template>
</pre>
<h2>Tea Commerce links</h2>
<ul>
<li><a href="http://www.teacommerce.dk">Official Tea Commerce Website</a></li>
<li><a href="http://www.teacommerce.dk/en/documentation.aspx" alt="List of all Tea Commerce Documentation pages" title="List of all Tea Commerce 
Documentation pages">Tea Commerce Documentation</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-multilanguage-starter-kit.aspx">Tea Commerce Multilanguage Kit</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-starter-kit.aspx">Tea Commerce Starter Kit</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-demo-webshop.aspx">Tea Commerce Demo Webshop</a></li>
</ul>]]></content:encoded>
			</item>
		<item>
		<title>Tea Commerce serverside validation</title>
		<link>http://rune.gronkjaer.dk/blog/2011/08/18/tea-commerce-serverside-validation/</link>
		<pubDate>Thu, 18 Aug 2011 10:48:41 +0000</pubDate>
		<dc:creator><![CDATA[Rune Grønkjær]]></dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[e-commerce]]></category>
		<category><![CDATA[Tea Commerce]]></category>
		<category><![CDATA[umbraco]]></category>
		<category><![CDATA[xslt]]></category>

		<guid isPermaLink="false">http://rune.gronkjaer.dk/blog/?p=1005</guid>
		<description><![CDATA[Tea Commerce handler om fedt design og fede JavaScripts. Af den årsag er det let at glemme behovet for serversidevalidering af kundens data. For at kunne gennemføre en ordre skal en bruger gerne have lagt noget i sin kurv, men han skal muligvis også have indtastet nogle bestemte data om sig selv eller den pågældende ordre. I de fleste tilfælde er det rigeligt med almindelig javascript validering, men JavaScript validering kan snydes. Hvis det er vigtigt med korrekte data skal der serverside validering til.]]></description>
				<content:encoded><![CDATA[Tea Commerce handler om fedt design og fede JavaScripts. Af den årsag er det let at glemme behovet for serversidevalidering af kundens data. For at kunne gennemføre en ordre skal en bruger gerne have lagt noget i sin kurv, men han skal muligvis også have indtastet nogle bestemte data om sig selv eller den pågældende ordre. I de fleste tilfælde er det rigeligt med almindelig javascript validering, men JavaScript validering kan snydes. Hvis det er vigtigt med korrekte data skal der serverside validering til.
<h2>Scenariet for serversidevalidering i Tea Commerce</h2>
Helt grundlæggende har jeg tænkt mig, at validere det der oftest er step 2, hvor der skal indtastes kundeoplysninger. Min løsning skal tage sørge for, at tjekke om data er udfyldt korrekt, hvis man er på et step højere end 2.<br /><br />
Der skal også tages højde for sprogversionering af kurven. Det betyder at jeg ikke vil hardcode nogen id&#8217;er i min serverside kode. Der skal også tjekkes om der er en ordre og om ordren har tilknyttet ordrelinier. Hvis ikke ordren validerer vil jeg sende folk tilbage til det step, som ikke validerer.
<h2>Hvordan man kan lave serversidevalidering i Tea Commerce</h2>
Serversidevalidering er ikke standard i Tea Commerce. Til gengæld er det med Tea Commerce&#8217;s .NET API let, at lave det selv. Der er uden tvivl masser af måder, at løse problemstillingen på. Jeg har dog valgt, at gøre det med en Umbraco XSLT library extension.<br /><br />
Jeg vil derfor lave en Umbraco XSLT library metode, som kan kaldes fra alle xslt&#8217;er. Nærmere bestemt skal den kaldes på de steps der kommer efter step 2, for på den måde at kunne sende kunden tilbage.
<h2>Umbraco XSLT library extensionen</h2>
Der er ikke meget at sige og jeg vil egentligt mest lade koden og de indlagte kommentarer tale for sig. Dog kan jeg give denne huskeliste med de ting man skal have ordnet før det vil virke. Koden til det hele har jeg sat ind lidt længere nede.
<ol>
<li>
Byg en dll med library extensionen og smid den op i bin mappen
</li>
<li>
Registrer din XSLT extension i filen /config/xsltExtensions.config
</li>
<li>
Lav kaldet i dine xslt&#8217;er. Husk at den nye extension også skal registreres i selve xslt&#8217;en. Nye xslt&#8217;er får automatisk din extension sat ind i xsl:stylesheet tag&#8217;et. Du kan derfor eventuelt lave en ny og kopiere hele toppen fra den
</li>
</ol>
<h4>Fuld XSLT library extension kode</h4>
<pre class="brush: csharp">
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using TeaCommerce;
using TeaCommerce.Data;

namespace ServersideValidation {
  public class Library {

    public Library() {
      //This has to be here, because of the way umbraco runs xslt extension
    }

    public static string ValidateOrder( int currentStepId, int cartStep2Id ) {
      try {
        //Test to make sure we are not logged in at the back end
        var test = HttpContext.Current.CurrentHandler as umbraco.BasePages.UmbracoEnsuredPage;
        if ( test == null ) {

          //Get the order
          Order order = TeaCommerce.Razor.TeaCommerce.GetOrder();

          //If there is no order we redirect to step 1 of the cart
          if ( order == null || order.OrderLines.Count() == 0 )
            HttpContext.Current.Response.Redirect( umbraco.library.NiceUrl( cartStep2Id ) + "?validate=false", true );

          //If the current step is not step 1 we validate the data on that step
          if ( currentStepId != cartStep2Id ) {
            //Get the values we must validate
            string firstName = order.GetPropertyValue( "firstName" ),
                  lastName = order.GetPropertyValue( "lastName" ),
                  streetAddress = order.GetPropertyValue( "streetAddress" ),
                  zipCode = order.GetPropertyValue( "zipCode" ),
                  city = order.GetPropertyValue( "city" ),
                  email = order.GetPropertyValue( "email" );

            //Simple validation of the values
            if ( string.IsNullOrEmpty( firstName ) ||
                 string.IsNullOrEmpty( lastName ) ||
                 string.IsNullOrEmpty( streetAddress ) ||
                 string.IsNullOrEmpty( zipCode ) ||
                 string.IsNullOrEmpty( city ) ||
                 string.IsNullOrEmpty( email ) ) {
              //Go back to step 1 if validation fails
              HttpContext.Current.Response.Redirect( umbraco.library.NiceUrl( cartStep2Id ) + "?validate=false", true );
            }
          }
        }
      } catch ( Exception ex ) {
        return ex.Message;
      }
      return string.Empty;
    }
  }
}
</pre>
<h4>Registreringen i Umbraco&#8217;s /config/xsltExtensions.config fil</h4>
<pre class="brush: xml">
<?xml version="1.0" encoding="utf-8"?>
<XsltExtensions>
  <ext assembly="/TeaCommerce" type="TeaCommerce.Library" alias="teacommerce"></ext>
  <ext assembly="/ServersideValidation" type="ServersideValidation.Library" alias="ServersideValidation"></ext>
</XsltExtensions>
</pre>
<h4>Kaldet i cartStep03.xslt (Og eventuelt andre efterfølgende)</h4>
<pre class="brush: xml">
&lt;xsl:template match="/">
<!-- I have chosen to use a dictionary item to save the id of the step 2 page -->
&lt;xsl:variable name="step2PageId" select="umbraco.library:GetDictionaryItem('step2PageId')"/>
&lt;xsl:value-of select="ServersideValidation:ValidateOrder($currentPage/@id, $step2PageId)" />
</pre>
<h2>Tea Commerce links</h2>
<ul>
<li><a href="http://www.teacommerce.dk">Official Tea Commerce Website</a></li>
<li><a href="http://www.teacommerce.dk/en/documentation.aspx" alt="List of all Tea Commerce Documentation pages" title="List of all Tea Commerce 
Documentation pages">Tea Commerce Documentation</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-multilanguage-starter-kit.aspx">Tea Commerce Multilanguage Kit</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-starter-kit.aspx">Tea Commerce Starter Kit</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-demo-webshop.aspx">Tea Commerce Demo Webshop</a></li>
</ul>]]></content:encoded>
			</item>
		<item>
		<title>Google Analytics e-commerce</title>
		<link>http://rune.gronkjaer.dk/blog/2011/08/10/google-analytics-e-commerce/</link>
		<pubDate>Wed, 10 Aug 2011 06:06:22 +0000</pubDate>
		<dc:creator><![CDATA[Rune Grønkjær]]></dc:creator>
				<category><![CDATA[Analytics]]></category>
		<category><![CDATA[e-commerce]]></category>
		<category><![CDATA[Tea Commerce]]></category>
		<category><![CDATA[umbraco]]></category>
		<category><![CDATA[xslt]]></category>
		<category><![CDATA[ecommerce]]></category>

		<guid isPermaLink="false">http://rune.gronkjaer.dk/blog/?p=991</guid>
		<description><![CDATA[Har du helt styr på hvem de kunder, som køber noget på dit site er? Og har du samtidig et overblik over hvad og hvor meget de køber? For at vide det, har du behov for at vide hvordan dine kunder færdes på dit website. Google analytics giver, som standard masser af muligheder for at undersøge dine brugeres adfærd, men med et par tilføjelser til analytics og til din webshop, kan du få endnu mere viden.]]></description>
				<content:encoded><![CDATA[Har du helt styr på hvem de kunder, som køber noget på dit site, er? Og har du samtidig et overblik over hvad og hvor meget de køber? For at vide det, har du behov for at vide hvordan dine kunder færdes på dit website. Google analytics giver, som standard masser af muligheder for at undersøge dine brugeres adfærd, men med et par tilføjelser til analytics og til din webshop, kan du få endnu mere viden.<br /><br />
Denne blogpost vil jeg bruge på at vise hvordan du kan udnytte Google Analytics E-commerce funktion. Det er ikke så svært, og giver dig masser af muligheder.
<h2>Hvad kan jeg bruge Google Analytics e-commerce til?</h2>
Google Analytics e-commerce skal bruges til at overskue den handel der er foregået på dit site. Du kan se hvor godt dit site konverterer brugerne til salg og hvor meget de køber. Der hvor det måske bliver rigtigt spændende er, at e-commerce statistikken også bliver flettet sammen med den normale statistik på websitet. I denne blogpost vil jeg dog ikke gennemgå alle mulighederne, men derimod skrive hvordan du kommer til at udnytte dem.
<h2>Tea Commerce og Google Analytics e-commerce</h2>
For at føre statistik over dine brugeres køb på din webshop skal vi have sat to ting op. For det første skal e-commerce slåes til i Google Analytics. For det anden skal der indsættes en stump kode i Googles tracking JavaScript på din webshop.
<h3>Opsætning af Google Analytics e-commerce</h3>
For at slå Google Analytics e-commerce til skal du ind i indstillingerne til dit websites Google Analytics. Google forklarer det ret godt selv på <a href="http://www.google.com/support/analytics/bin/answer.py?answer=55528" title="Hvordan sporer jeg e-handelstransaktioner?">denne side</a>, men herunder har jeg lige 
gentaget hvad der skal gøres.
<h4>Hvordan sporer jeg e-handelstransaktioner?</h4>
<ol>
<li>
Log ind på din konto.
</li>
<li>
Klik på Rediger ud for den profil, du ønsker at aktivere.
</li>
<li>
På siden Profilindstillinger skal du klikke på Rediger ud for Oplysninger om hovedwebstedsprofil.
</li>
<li>
Skift alternativknappen Websted til e-handel fra Nej til Ja.
</li>
</ol>
Når du har gjort det dukker der et nyt menupunkt kaldet &#8220;E-Handel&#8221; inde under dit websites statistik i Google Analytics. Der vil også være E-Handelsfaner forskellige steder i den normale statistik. Der er selvfølgelig ingen data endnu, og det kommer der heller ikke, før du har gjort det følgende.
<h2>Tracking af din webshops ordrer</h2>
Nu skal der indsættes noget JavaScript i det normale tracking script fra google. Udgangspunktet skulle gerne være noget lignende nedenstående, og det skulle gerne ligge i din header. Jeg har indsat en kommentar der hvor vores tracking kode til e-commerce skal ligge.
<h4>Google analytics standard tracking kode</h4>
<pre class="brush: js">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-3982655-28']);
_gaq.push(['_trackPageview']);

/* INSERT E-COMMERCE TRACKING HERE */

(function () {
  var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
  ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
  var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</pre>
<br /><br/>
Nu Skal vi have genereret det JavaScript, som skal give informationer omkring ordren. Vi skal sørge for at det kun fremkommer når brugeren har gennemført sin ordre og vi skal have sendt en del forskellig information om ordren og dens ordrelinier. Google har selv skrevet en masse om emnet selvfølgelig, <a href="http://code.google.com/apis/analytics/docs/tracking/gaTrackingEcommerce.html" title="Google code - Ecommerce Tracking">så du kan læse teorien bag her</a>.
<h3>Udskrivning af Tea Commerce ordrens data med xslt</h3>
Jeg har lavet en stump kode, som kan bruges i alle Tea Commerce webshops. Du skal bare tjekke at mine aliaser stemmer overens med dine. Opret en ny xslt fil og macro kaldet &#8220;googleEcommcereTracking.xslt&#8221; og indsæt nedenstående i template tagget. Husk at rette id&#8217;et på confirmation siden, som står i den først &#8220;if&#8221; condition.
<h4>Tea Commerce Google Analytics e-commerce tracking code</h4>
<pre class="brush: xslt">
<!-- Only write the script if we are on the order confirmation page -->
<xsl:if test="$currentPage/@id = 1174">
  <!-- The finalized order -->
  <xsl:variable name="order" select="teacommerce:GetFinalizedOrderXml()" />
  <!-- If theres no order, theres no point in continueing -->
  <xsl:if test="$order != ''">
    <!-- General information about the order -->
    _gaq.push(['_addTrans',
      '<xsl:value-of select="$order/@id" />',           // order ID - required
      'runeswebshop.com',  // affiliation or store name
      '<xsl:value-of select="$order/@totalPriceWithoutVAT" />', // total - required
      '<xsl:value-of select="$order/@totalVAT" />',             // tax
      '<xsl:value-of select="$order/shipping/@feeWithoutVAT" />',// shipping
      '<xsl:value-of select="$order/properties/city" />',        // city
      '',                                                        // state or province
      '<xsl:value-of select="$order/properties/country" />'      // country
    ]);
    <!-- Loop the order lines -->
    <xsl:for-each select="$order/orderLine">
     // add item might be called for every item in the shopping cart
     // where your ecommerce engine loops through each item in the cart and
     // prints out _addItem for each
    _gaq.push(['_addItem',
      '<xsl:value-of select="$order/@id" />',               // order ID - required
      '<xsl:value-of select="properties/productNumber" />', // SKU/code - required
      '<xsl:value-of select="properties/productName" />',   // product name
      '<xsl:value-of select="umbraco.library:GetXmlNodeById(@nodeId)/ancestor-or-self::ProductCategory/@nodeName" />',   // category or variation
      '<xsl:value-of select="@unitPriceWithoutVAT" />',     // unit price - required
      '<xsl:value-of select="@quantity" />'                 // quantity - required
    ]);
    </xsl:for-each>
    _gaq.push(['_trackTrans']); //submits transaction to the Analytics servers
  </xsl:if>
</xsl:if>
</pre>
<br /><br/>
Nu skal vi have indsat vores nye macro i Google Analytics tracking koden i websitets header. Tracking koden kommer nu til at se ud som følger.
<h4>Tracking kode med e-commerce tracking macroen</h4>
<pre class="brush: js">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-3982655-28']);
_gaq.push(['_trackPageview']);

<umbraco:Macro Alias="GoogleEcommcereTracking" runat="server"></umbraco:Macro>

(function () {
  var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
  ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
  var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</pre>
<br /><br />
Det skulle gøre det. Når vi nu prøver at køre en testordre igennem og når til ordrebekræftelsen skulle der gerne være blevet skrevet noget ud alá det herunder. På alle andre sider vil den se ud lige som den plejer. Nu vil din webshop begynde at indsamle data&#8217;ene, og du vil ikke gå glip af nogle fede statistikker.
<h4>Google Analytics tracking koden på ordrebekræftelsen</h4>
<pre class="brush: js">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-3982655-15']);
_gaq.push(['_setDomainName', 'none']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


_gaq.push(['_addTrans',
      '56',                 // order ID - required
      'runeswebshop.com',   // affiliation or store name
      '10400.0000000000',   // total - required
      '2600.00000000000000',// tax
      '0.00000',            // shipping
      'Herning',            // city
      '',                   // state or province
      '1'                   // country
    ]);


// add item might be called for every item in the shopping cart
// where your ecommerce engine loops through each item in the cart and
// prints out _addItem for each
_gaq.push(['_addItem',
      '56',                                 // order ID - required
      '8040000065',                         // SKU/code - required
      'Vedligeholdelsesfrit havemøbelsæt',  // product name
      'Havemøbler',                         // category or variation
      '8000.0',                             // unit price - required
      '1'                                   // quantity - required
    ]);


// add item might be called for every item in the shopping cart
// where your ecommerce engine loops through each item in the cart and
// prints out _addItem for each
_gaq.push(['_addItem',
      '56',           // order ID - required
      '1130000001',   // SKU/code - required
      'RENSDYRSKIND', // product name
      'Interiør',     // category or variation
      '1200.0',       // unit price - required
      '2'             // quantity - required
    ]);

_gaq.push(['_trackTrans']); //submits transaction to the Analytics servers


(function () {
  var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
  ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
  var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</pre>
<h2>Tea Commerce links</h2>
<ul>
<li><a href="http://www.teacommerce.dk">Official Tea Commerce Website</a></li>
<li><a href="http://www.teacommerce.dk/en/documentation.aspx" alt="List of all Tea Commerce Documentation pages" title="List of all Tea Commerce 
Documentation pages">Tea Commerce Documentation</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-multilanguage-starter-kit.aspx">Tea Commerce Multilanguage Kit</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-starter-kit.aspx">Tea Commerce Starter Kit</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-demo-webshop.aspx">Tea Commerce Demo Webshop</a></li>
</ul>]]></content:encoded>
			</item>
		<item>
		<title>Tea Commerce sprog, lande og valuta</title>
		<link>http://rune.gronkjaer.dk/blog/2011/07/15/tea-commerce-sprog-lande-og-valuta/</link>
		<comments>http://rune.gronkjaer.dk/blog/2011/07/15/tea-commerce-sprog-lande-og-valuta/#comments</comments>
		<pubDate>Fri, 15 Jul 2011 13:01:06 +0000</pubDate>
		<dc:creator><![CDATA[Rune Grønkjær]]></dc:creator>
				<category><![CDATA[Tea Commerce]]></category>
		<category><![CDATA[countries]]></category>
		<category><![CDATA[currencies]]></category>
		<category><![CDATA[lande]]></category>
		<category><![CDATA[languages]]></category>
		<category><![CDATA[sprog]]></category>
		<category><![CDATA[umbraco]]></category>
		<category><![CDATA[valuta]]></category>

		<guid isPermaLink="false">http://rune.gronkjaer.dk/blog/?p=968</guid>
		<description><![CDATA[Lande, valuta og sprog har en meget central funktion i Tea Commerce og af den årsag
er det også vigtigt at forstå hvordan de fungerer. Jeg vil derfor liste de vigtigste
ting der er at vide omkring dem.]]></description>
				<content:encoded><![CDATA[Disse tre begreber har en meget central funktion i Tea Commerce og af den årsag
er det også vigtigt at forstå hvordan de fungerer. Jeg vil derfor liste de vigtigste
ting der er at vide omkring dem.
<h2>
  Hvordan fungerer lande i Tea Commerce?</h2>
<ul>
  <li>Når en ny ordre bliver oprettet bliver dets land sat til standard landet. </li>
  <li>Du kan til enhver tid ændre ordrens land via JavaScript API eller .NET API&#8217;et.
  </li>
<li>Landet indeholder en masse standard information for ordren inklusiv valuta, leveringsmetode, betalingsmetode og momsgruppe.</li>
</ul>
<h2>
  Hvordan fungerer valua i Tea Commerce?</h2>
<ul>
  <li>Når en ny ordre bliver oprettet bliver ordrens valuta automatisk den stadard valuta,
    som er valgt på ordrens land.</li>
  <li>Du kan til enhver tid ændre ordrens valuta via JavaScript API eller .NET API&#8217;et.
  </li>
  <li>For at kunne skrifte til en valuta, kræver det at den pågældende valuta er tilgængelig
    i det valgte land på ordren. Dette gøres på den enkelte valuta i Tea Commerce sektionen.
  </li>
  <li>Når man skifter land vil Tea Commerce automatisk tjekke om den nuværende valuta
    er tilgængelig i det nye land
    <ul>
      <li>Hvis den er tilgængelig bliver der ikke ændret på noget. </li>
      <li>Hvis den IKKE er tilgængelig vil Tea Commerce vælge det nye lands standard valuta
        i stedet.</li>
    </ul>
  </li>
</ul>
<h2>
  Hvad er sprog i Tea Commerce?</h2>
<ul>
<li>Du får mest ud af sprog i Tea Commerce, hvis du benytter et setup alá det i <a
    title="Download the Tea Commerce Multilanguage Kit" href="http://www.teacommerce.dk/en/products/tea-commerce-multilanguage-starter-kit.aspx">
    Tea Commerce Multilanguage Kit</a></li>
  <li>Sprog har intet med lande og valuta at gøre!</li>
  <li>Tea Commerce ordrer har en umbracoLanguage property. Den værdi er et id, som matcher
    et af Umbraco&#8217;s sprog under Umbraco&#8217;s &#8220;Settings&#8221; område.</li>
  <li>Hver gang et produkt tilføjes til ordren, bliver umbracoLanguage automatisk opdateret.</li>
  <li>Når Tea Commerce skal opdatere umbracoLanguage id&#8217;et starter den på den produktnode,
    som er blevet tilføjet til ordren. Den vil så kigge op i nodetræet og finde de den
    første node, som har tilknyttet 1 eller flere domæner.</li>
  <li>Idet der kan være mere end et domæne tilknyttet til en node, vil Tea Commerce
    først prøve at finde en der mathcer det domæne brugeren er på lige nu.</li>
  <li>Hvis ikke den kan finde et match, vil den bare tage den første den bedste.</li>
  <li>Det fundne domænes sprog vil derefter blive tilføjet til ordrens umbracoLanguage.</li>
  <li>Hvis ingen sprog bliver fundet bliver umbracoLanguage sat til 0. I det tilfælde
    kører ordren bare uden lokalisering.</li>
</ul>
<h2>
  Hvordan bruges Tea Commerce ordrens sprog?</h2>
<ul>
  <li>Det handler i al sin enkelthed om lokalisering. Altså at vise et ordrelinies tekster
    på det rigtige sprog.</li>
  <li>Hvis du har en multisprogs webshop, som benytter et setup alá det i vores <a
    title="Download the Tea Commerce Multilanguage Kit" href="http://www.teacommerce.dk/en/products/tea-commerce-multilanguage-starter-kit.aspx">
    Tea Commerce Multilanguage Kit</a>, er der produkter på forskellige sprog.</li>
    <li>Hvert produkt har et basis produkt, som indeholder netop alle produktets basisinformationer. Altså det, som ikke er sprogspecifikt.</li>
    <li>Hver gang et produkt tilføjes til kurven, vil Tea Commerce forsøge at finde produktets basisprodukt.</li>
    <li>Derefter vil Tea Commerce finde alle andre produkter, som er knyttet til basisproduktet. Altså produkterne på de andre sprog.</li>
    <li>Derefter vil Tea Commerce tilføje ordrelinie properties til ordrelinien, på alle de sprogvarianter den har fundet.</li>
    <li>Alle produkter, som ikke har et bestemt sprog får deres ordrelinie properties tilføjet med et umbracoLanguage = 0.</li>
    <li>Når en ordre forespørges via JavaScriptet eller xslt&#8217;en bliver alle ordrelinieproperties flettet sammen. Faktisk nærmere klasket sammen, idet Tea Commerce først udvælger de properties hvor umbracoLanguage = 0 og derefter overskriver dem med de sprogspecifikke.</li>
    <li>Properties med et sprog overskriver altså dem uden et sprog.</li>
    <li>Dette betyder at du ender op med sprogspecifikke ordrelinie properties, lige til at skrive ud i UI.</li>
    <li>Når der ændres på ordrens umbracoLanguage bliver alle ordrelinie properties også rettet til.</li>
</ul>
<h2>Tea Commerce links</h2>
<ul>
<li><a href="http://www.teacommerce.dk">Official Tea Commerce Website</a></li>
<li><a href="http://www.teacommerce.dk/en/documentation.aspx" alt="List of all Tea Commerce Documentation pages" title="List of all Tea Commerce 
Documentation pages">Tea Commerce Documentation</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-multilanguage-starter-kit.aspx">Tea Commerce Multilanguage Kit</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-starter-kit.aspx">Tea Commerce Starter Kit</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-demo-webshop.aspx">Tea Commerce Demo Webshop</a></li>
</ul>]]></content:encoded>
			<wfw:commentRss>http://rune.gronkjaer.dk/blog/2011/07/15/tea-commerce-sprog-lande-og-valuta/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Opgradering til Tea Commerce 1.4</title>
		<link>http://rune.gronkjaer.dk/blog/2011/06/29/opgradering-til-tea-commerce-1-4/</link>
		<pubDate>Wed, 29 Jun 2011 11:47:27 +0000</pubDate>
		<dc:creator><![CDATA[Rune Grønkjær]]></dc:creator>
				<category><![CDATA[Blog post]]></category>

		<guid isPermaLink="false">http://rune.gronkjaer.dk/blog/?p=947</guid>
		<description><![CDATA[UNDSKYLD! Nu gør vi det ikke igen! Vi har en gang for alle, efter opfordring fra jer herlige mennesker i Umbraco Community, refactored JavaScript API&#8217;et. Det vi har gjort nu er at indføre et settings objekt, som kan udvides i det uendelige. Først skal du installere Tea Commerce igen Start med at hente Tea Commerce [&#8230;]]]></description>
				<content:encoded><![CDATA[UNDSKYLD! Nu gør vi det ikke igen! Vi har en gang for alle, efter opfordring fra jer herlige mennesker i Umbraco Community, refactored JavaScript API&#8217;et. Det vi har gjort nu er at indføre et settings objekt, som kan udvides i det uendelige.<br /><br />
<h2>Først skal du installere Tea Commerce igen</h2>
Start med at hente <a href="http://our.umbraco.org/projects/website-utilities/tea-commerce">Tea Commerce på our Umbraco</a>. Derefter skal du bare installere Tea Commerce i din Umbraco løsning, som du normalt installerer alle andre pakker. Tea Commerce opdaterer sig selv uden du behøver at gøre andet. Derefter skal du rette dine egne JavaScript filer, som benytter Tea Commerce JavaScript API&#8217;et. Læs hvordan herunder.
<h2>Alle Tea Commerce Kit&#8217;s er opdateret</h2>
Alle Kit&#8217;s er blevet opdateret til at bruge den nye opsætning af Tea Commerce JavaScript API&#8217;et, så dem vil du altid kunne downloade og kigge i.
<ul>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-starter-kit.aspx">Tea Commerce Starter Kit</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-demo-webshop.aspx">Tea Commerce Demo Webshop</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-multilanguage-starter-kit.aspx">Tea Commerce Multi Language Starter Kit</a></li>
</li>
</ul>
<h2>JavaScript API dokumentationen er opdateret</h2>
<a href="http://rune.gronkjaer.dk/blog/2010/11/16/tea-commerce-javascript-api/">JavaScript API dokumentationen</a> er opdateret til at vise hvordan man bruger det nye API. Så her kan du finde info om alle metoderne, som ikke bliver nævnt i denne blogpost.
<h2>Hvad er blevet ændret?</h2>
Kort og godt har vi flyttet alle de frivillige parametre ind i settingsobjekter, på ALLE metoder. Nærmere bestemt skal du være opmærksom på følgende parametre, hvis du bruger dem.
<ul>
<li>
umbracoLanguageId
</li>
<li>
async
</li>
<li>
successfn
</li>
<li>
errorfn
</li>
<li>
dataType
</li>
<li>
properties
</li>
</ul>
<h2>Et par eksempler</h2>
Herunder har jeg indsat et par eksempler på hvordan man let kan rette sine metodekald til. Læg mærke til at jeg benytter to forskellige fremgangsmåder i de to eksempler, til at sende settings objektet med. Begge muligheder kan bruges på alle metoder.
<h4>addOrderLine</h4>
<pre class="brush: js">
//BEFORE 1.4
TeaCommerce.addOrderLine(productid, quantity, true, function (data) {
    //Success function content
  }, function (data) {
    //Error function content
  }
);

//AFTER 1.4
TeaCommerce.addOrderLine(productid, quantity,
  {
  async: true,
  successfn: function (data) {
    //Success function content
  },
  errorfn: function (data) {
    //Error function content
  }
});
</pre>
<h4>removeOrderLine</h4>
<pre class="brush: js">
//BEFORE 1.4
TeaCommerce.removeOrderLine(productId, true, function (data) {
    //Success function content
  }
);

//AFTER 1.4
var settings = {
  async: true,
  successfn: function (data) {
    //When the server answers we update the orderline in the UI
    removeOrderLineFromUI(orderlineEle);
  } 
}
TeaCommerce.removeOrderLine(productId, settings);
</pre>
<h2>Tea Commerce links</h2>
<ul>
<li><a href="http://www.teacommerce.dk">Official Tea Commerce Website</a></li>
<li><a href="http://www.teacommerce.dk/en/documentation.aspx" alt="List of all Tea Commerce Documentation pages" title="List of all Tea Commerce 
Documentation pages">Tea Commerce Documentation</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-multilanguage-starter-kit.aspx">Tea Commerce Multilanguage Kit</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-starter-kit.aspx">Tea Commerce Starter Kit</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-demo-webshop.aspx">Tea Commerce Demo Webshop</a></li>
</ul>]]></content:encoded>
			</item>
		<item>
		<title>Opgradering til Tea Commerce 1.3</title>
		<link>http://rune.gronkjaer.dk/blog/2011/06/10/opgradering-til-tea-commerce-1-3/</link>
		<pubDate>Fri, 10 Jun 2011 10:21:47 +0000</pubDate>
		<dc:creator><![CDATA[Rune Grønkjær]]></dc:creator>
				<category><![CDATA[ajax]]></category>
		<category><![CDATA[e-commerce]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[sprog]]></category>
		<category><![CDATA[sprogversionering]]></category>
		<category><![CDATA[Tea Commerce]]></category>
		<category><![CDATA[umbraco]]></category>
		<category><![CDATA[xslt]]></category>

		<guid isPermaLink="false">http://rune.gronkjaer.dk/blog/?p=916</guid>
		<description><![CDATA[Denne blogpost beskriver hvordan du kan opdatere din Tea Commerce webshop fra en pre v1.3 Tea Commerce til en v1.3+.<br />
Opgradering af din Tea Commerce løsning til 1.3 betyder at du sikkert skal have rettet lidt i dit JavaScript. Som du kan læse i <a href="http://www.teacommerce.dk/en/documentation/revision-history.aspx">Tea Commerce revision history</a>, er der blevet lavet nogle <strong>breaking changes</strong> i core JavaScript filen. Gå dog ikke i panik... Det lader sig let løse.]]></description>
				<content:encoded><![CDATA[<h4>UPDATE</h4>
I <strong>Tea Commerce 1.4</strong> har vi en gang for alle ændret på Tea Commerce JavaScript API&#8217;et. <a href="http://rune.gronkjaer.dk/blog/2011/06/29/opgradering-til-tea-commerce-1-4/">Læs her hvad du skal gøre!</a>
<hr />
Denne blogpost beskriver hvordan du kan opdatere din Tea Commerce webshop fra en pre v1.3 Tea Commerce til en v1.3+.<br />
Opgradering af din Tea Commerce løsning til 1.3 betyder at du sikkert skal have rettet lidt i dit JavaScript. Som du kan læse i <a href="http://www.teacommerce.dk/en/documentation/revision-history.aspx">Tea Commerce revision history</a>, er der blevet lavet nogle <strong>breaking changes</strong> i core JavaScript filen. Gå dog ikke i panik&#8230; Det lader sig let løse.
<h2>Berørte Tea Commerce metoder</h2>
<ul>
    <li>TeaCommerce.invokeXSLT(xsltFile, nodeId, umbracoLanguageId, async, successfn, errorfn, dataType)</li>
    <li>TeaCommerce.updateOrderLineProperty(nodeId, propertyAlias, propertyValue, umbracoLanguageId, async, successfn, errorfn)</li>
    <li>TeaCommerce.updateUniqueOrderLineProperty( orderLineId, propertyAlias, propertyValue, umbracoLanguageId, async, successfn, errorfn)</li>
    <li>TeaCommerce.updateOrderLineProperties(nodeId, propertyList, umbracoLanguageId, async, successfn, errorfn)</li>
    <li>TeaCommerce.updateUniqueOrderLineProperties(orderLineId, propertyList, umbracoLanguageId, async, successfn, errorfn)</li>
</ul>
De fem ovenstående metoder har fået nye signaturer. Alle skal de nu have sendt et umbracoLanguageId, som skal bruges til at sprogversionere ordrelinien.<br /><br />
<strong>BEMÆRK: </strong> updateUniqueOrderLineProperty og updateUniqueOrderLineProperties har yderligere fået fjernet deres nodeId fra parametrene, da der ikke var brug for den. De skal udelukkende bruge et ordrelinie id til identificering.
<h2>Sådan fixer du hurtigt dit website</h2>
<h3>1. Sørg for at alle dine produkter har tilknyttet et domæne</h3>
Der skal være et domæne på en node oppe i nodetræet i umbraco. Domænet har tilknyttet et sprog og på den måde vil vi kunne få fat på sproget og benytte det. Ved at højreklikke på en af dine yderste noder (Måske en root node) og vælge &#8220;Manage Hostnames&#8221; kan du tilføje et domæne.
<h3>2. Opdater Tea Commerce til version 1.3+</h3>
Nu skal du have opdateret Tea Commerce til version 1.3+. Du kan hente den nyeste version <a href="http://our.umbraco.org/projects/website-utilities/tea-commerce">her</a>.
<h3>3. Tilføje sproget til global JavaScript parameter</h3>
I din master template skal vi nu have tilføjet en global JavaScript parameter med sproget. Vi skal bruge den til at sende med de ovennævnte metoder.
<h4>I din header har du allerede noget lignende</h4>
<pre class="brush: html">
<script type="text/javascript">
  //Used by invokeXSLT to know which page we are currently on
  var _nodeId = <umbraco:Item field="pageID" runat="server"></umbraco:Item>;
</script>
</pre>
<h4>Tilføj nu en ekstra linie med variablen _languageId</h4>
<pre class="brush: html">
<script type="text/javascript">
  //Used by invokeXSLT to know which page we are currently on
  var _nodeId = <umbraco:Item field="pageID" runat="server"></umbraco:Item>;
  var _languageId = <umbraco:Item field="pageID" runat="server" xslt="teacommerce:GetUmbracoLanguageIdByNodeId({0})"></umbraco:Item>;
</script>
</pre>
Metoden &#8220;teacommerce:GetUmbracoLanguageIdByNodeId&#8221; er en xslt extension i Tea Commerce, som kan hente et sprog id ud fra en hvilken som helst node i Umbraco hvis eller step 1 i denne gennemgang er opfyldt.
<h3>4. Ret dine JavaScripts</h3>
Nu skal vi have benyttet  _languageId variablen fra step 3, i dine JavaScripts. Vi skal have dine kald til TeaCommerce til at overholde signaturerne, som de er nævnt herover. I al sin enkelthed betyder det at du skal sende _languageId med de nødvendige steder.<br />
I eksemplet herunder tager jeg udgangspunkt i Tea Commerce Starter Kit&#8217;ets teaCommerce_Advanced.js. Du skal lægge mærke til linien med &#8220;invokeXSLT&#8221; kaldet, som er den eneste, der bliver ændret.<br /><br />
<strong>BEMÆRK: </strong> Husk også at fjerne nodeId fra de berørte metoder!<br />
<strong>BEMÆRK: </strong> Hvis du ønsker at tilføje en ordrelinie property, som IKKE tilhører et bestemt sprog skal du blot sende 0 (nul) med i stedet for _languageId.
<h4>Uddrag fra Tea Commerce Starter Kit&#8217;ets teaCommerce_Advanced.js</h4>
<pre class="brush: javascript">
/*
When the currency is changed we need to update product prices
all over the page.
To do this, we need to know what xslt's to run to get the desired html.
We have written the name of the xslt's in each xslt, and can fetch it from the html.
*/
function updatePageUI() {
  /*
  All xslt's that can be invoked in this way have information in a div
  with the class "invokeXSLT". For every one of them we update the UI.
  */
  jQuery('div.invokeXSLT').each(function () {
    var invokeXSLT = jQuery(this),
        parent = invokeXSLT.parent(),
        htmlFromServer = TeaCommerce.invokeXSLT(invokeXSLT.text(), _nodeId, false);
    parent.before(htmlFromServer).remove();
  });
}
</pre>
<h4>Den samme kode efter den er blevet rettet til</h4>
<pre class="brush: javascript">
/*
When the currency is changed we need to update product prices
all over the page.
To do this, we need to know what xslt's to run to get the desired html.
We have written the name of the xslt's in each xslt, and can fetch it from the html.
*/
function updatePageUI() {
  /*
  All xslt's that can be invoked in this way have information in a div
  with the class "invokeXSLT". For every one of them we update the UI.
  */
  jQuery('div.invokeXSLT').each(function () {
    var invokeXSLT = jQuery(this),
        parent = invokeXSLT.parent(),
        htmlFromServer = TeaCommerce.invokeXSLT(invokeXSLT.text(), _nodeId, _languageId, false);
    parent.before(htmlFromServer).remove();
  });
}
</pre>
<h2>Rart at vide</h2>
<h3>Hvad bruges umbracoLanguageId til?</h3>
Det bruges til at gemme ordreliniens properties på alle de mulige sprog. Hvis du laver en webshop med flere sprog vil der bliver gemt properties på alle sprog.
<h3>Hvorfor ikke også order properties?</h3>
Den opmærksomme læser har måske opdaget at der kun sende sprog id med til ordrelinie properties og ikke til ordrens properties. Ordrens properties er generelle og formodes ikke at tilhøre et bestemt sprog.<br /><br />
<strong>TIP: </strong> Har du alligevel behov for, at have en ordre property på flere sprog, kan du altid vælge at navngive din property med sprogid&#8217;et. Fx &#8220;name1&#8221;, &#8220;name2&#8221; og &#8220;name3&#8221;, hvor tallet er sprogid&#8217;et. I det sjældne tilfælde at du har brug for det, kan den løsning være ganske fin.
<h3>Hvordan tilgår jeg properties på forskellige sprog?</h3>
De værdier du får med i din ordre, være det i JavaScriptet eller XML&#8217;en, er kun på ét sprog. Det sprog er ordrens sprog, som du kan tilgå direkte på ordren med værdien umbracoLanguageId i XML&#8217;en og UmbracoLanguageId i JavaScriptet.<br /><br />
Du kan ændre ordrens sprog med den nye JavaScript metode TeaCommerce.setOrderUmbracoLanguage(umbracoLanguageId, async, successfn, errorfn). Så snart du kalder den vil alle property værdier ændres til det nye sprog.
<h3>Kan jeg ikke have sproguafhængige ordrelinie properties?</h3>
Jo, dem som Tea Commerce automatisk tilføjer dine ordrelinier har ikke nødvendigvis et sprog. I så fald vil deres værdi ALTID være tilgængelig, uanset ordrens sprog.<br />
Hvis du selv ønsker at tilføje en ordrelinie property, som IKKE tilhører et bestemt sprog skal du blot sende 0 (nul) med, som language ID
<h2>Tea Commerce links</h2>
<ul>
<li><a href="http://www.teacommerce.dk">Official Tea Commerce Website</a></li>
<li><a href="http://www.teacommerce.dk/en/documentation.aspx" alt="List of all Tea Commerce Documentation pages" title="List of all Tea Commerce 
Documentation pages">Tea Commerce Documentation</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-multilanguage-starter-kit.aspx">Tea Commerce Multilanguage Kit</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-starter-kit.aspx">Tea Commerce Starter Kit</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-demo-webshop.aspx">Tea Commerce Demo Webshop</a></li>
</ul>]]></content:encoded>
			</item>
		<item>
		<title>Tea Commerce Umbraco Razor</title>
		<link>http://rune.gronkjaer.dk/blog/2011/05/24/tea-commerce-razor/</link>
		<pubDate>Tue, 24 May 2011 06:54:13 +0000</pubDate>
		<dc:creator><![CDATA[Rune Grønkjær]]></dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[e-commerce]]></category>
		<category><![CDATA[Razor]]></category>
		<category><![CDATA[Tea Commerce]]></category>
		<category><![CDATA[umbraco]]></category>
		<category><![CDATA[ecommerce]]></category>
		<category><![CDATA[razor]]></category>
		<category><![CDATA[webshop]]></category>

		<guid isPermaLink="false">http://rune.gronkjaer.dk/blog/?p=688</guid>
		<description><![CDATA[Tea Commerce stiller et API til rådighed for dine Razor scripts. Metoderne giver i bund og grund samme funktionalitet til rådighed, som du får i XSLT extension API'et. I denne blog post får du en liste med metoderne og deres signatur. ]]></description>
				<content:encoded><![CDATA[Tea Commerce stiller et API til rådighed for dine Razor scripts. Metoderne giver i bund og grund samme funktionalitet til rådighed, som du får i XSLT extension API&#8217;et. I denne blog post får du en liste med metoderne og deres signatur. 
<br /><br />
Som hovedregel returnerer alle metoderne et Tea Commerce objekt med alle de muligheder et sådant indeholder. Metoder, properties og deres klasser er alle godt kommenterede, så check dem ud i din Visual Studio.
<h2>Hvordan bruger du T Commerce Razor API&#8217;et</h2>
Jeg har lavet et lille eksempel på hvordan man kan bruge API&#8217;et. I eksemplet skriver jeg nodenavnet ud på alle ordrelinier i kurven. <br />Bemærk at jeg skal have en using på både Tea Commerce razor, samt Tea Commerce Data name spaces, så jeg har adgang til alle de klasser jeg skal bruge.
<br />
Bemærk også at jeg benytter UmbracoLanguageId som først er tilgængelig i Multisprogsversionen af Tea Commerce v1.3.0.0. Kører du en lavere version af Tea Commerce end den kan du uden videre slette den del af scriptet.
<pre class="brush: csharp">
@using TeaCommerce.Razor
@using TeaCommerce.Data

Order lines in the cart:
@{
  Order order = TeaCommerce.GetOrder();
  if (order.OrderLines.Count() > 0) {
  <ul>
    @foreach (OrderLine orderline in TeaCommerce.GetOrder().OrderLines) {
      <li>
        @orderline.Properties.Single(p => p.Alias.Equals("nodeName") && p.UmbracoLanguageId == order.UmbracoLanguageId).Value
      </li>
    }
  </ul>
  }
}
</pre>
<h2>Tea Commerce Razor API&#8217;et</h2>
<pre class="brush: csharp">
namespace TeaCommerce.Razor {
  public class TeaCommerce {

    /// &lt;summary&gt;
    /// Indication if current customer has an order
    /// &lt;/summary&gt;
    public static bool HasOrder()

    /// &lt;summary&gt;
    /// Generates a Json string representing the current order
    /// &lt;/summary&gt;
    public static Order GetOrder()

    /// &lt;summary&gt;
    /// Indication if current customer has an finalized order
    /// &lt;/summary&gt;
    public static bool HasFinalizedOrder()

    /// &lt;summary&gt;
    /// Get the users current finalized order
    /// &lt;/summary&gt;
    public static Order GetFinalizedOrder()

    /// &lt;summary&gt;
    /// Get the users current order
    /// &lt;/summary&gt;
    public static Order GetOrder( long orderId )

    /// &lt;summary&gt;
    /// Gets all available shipping methods filtered by the current country
    /// &lt;/summary&gt;
    public static IEnumerable&lt;ShippingMethod&gt; GetShippingMethods()

    /// &lt;summary&gt;
    /// Gets all available payment methods filtered by the current country
    /// &lt;/summary&gt;
    public static IEnumerable&lt;PaymentMethod&gt; GetPaymentMethods()

    /// &lt;summary&gt;
    /// Gets all available countries
    /// &lt;/summary&gt;
    public static IEnumerable&lt;Country&gt; GetCountries()

    /// &lt;summary&gt;
    /// Gets the current country
    /// &lt;/summary&gt;
    public static Country GetCurrentCountry()

    /// &lt;summary&gt;
    /// Gets all available currencies
    /// &lt;/summary&gt;
    public static IEnumerable&lt;Currency&gt; GetCurrencies()

    /// &lt;summary&gt;
    /// Gets the current currency
    /// &lt;/summary&gt;
    public static Currency GetCurrentCurrency()

    /// &lt;summary&gt;
    /// Formats a price with the current currency's culturename
    /// &lt;/summary&gt;
    /// &lt;param name="price"&gt;The price as a decimal&lt;/param&gt;
    /// &lt;returns&gt;The formatted price as string&lt;/returns&gt;
    public static string FormatPrice( decimal price ) 

    /// &lt;summary&gt;
    /// Formats a price with the chosen culturename
    /// &lt;/summary&gt;
    /// &lt;param name="price"&gt;The price as a decimal&lt;/param&gt;
    /// &lt;param name="cultureName"&gt;A culture name&lt;/param&gt;
    /// &lt;returns&gt;The formatted price as string&lt;/returns&gt;
    public static string FormatPriceWithSpecificCulture( decimal price, string cultureName )

    /// &lt;summary&gt;
    /// Formats a price with the current currency's culturename
    /// No currency symbol will be added
    /// &lt;/summary&gt;
    /// &lt;param name="price"&gt;The price as a decimal&lt;/param&gt;
    /// &lt;returns&gt;The formatted price as string&lt;/returns&gt;
    public static string FormatPriceNoSymbol( decimal price )

    /// &lt;summary&gt;
    /// Formats a price with the chosen culturename
    /// No currency symbol will be added
    /// &lt;/summary&gt;
    /// &lt;param name="price"&gt;The price as a decimal&lt;/param&gt;
    /// &lt;param name="cultureName"&gt;A culture name&lt;/param&gt;
    /// &lt;returns&gt;The formatted price as string&lt;/returns&gt;
    public static string FormatPriceNoSymbolWithSpecificCulture( decimal price, string cultureName )

    /// &lt;summary&gt;
    /// Gets the stock of a specific product
    /// &lt;/summary&gt;
    /// &lt;param name="nodeId"&gt;Node id of the product&lt;/param&gt;
    /// &lt;returns&gt;Will return null if the product does not use stock&lt;/returns&gt;
    public static decimal? GetStock( int nodeId )
  }
}
</pre>
<h2>Tea Commerce links</h2>
<ul>
<li><a href="http://www.teacommerce.dk">Official Tea Commerce Website</a></li>
<li><a href="http://www.teacommerce.dk/en/documentation.aspx" alt="List of all Tea Commerce Documentation pages" title="List of all Tea Commerce 
Documentation pages">Tea Commerce Documentation</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-multilanguage-starter-kit.aspx">Tea Commerce Multilanguage Kit</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-starter-kit.aspx">Tea Commerce Starter Kit</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-demo-webshop.aspx">Tea Commerce Demo Webshop</a></li>
</ul>]]></content:encoded>
			</item>
		<item>
		<title>Hvordan man laver en licens webshop</title>
		<link>http://rune.gronkjaer.dk/blog/2011/04/20/hvordan-man-laver-en-licens-webshop/</link>
		<pubDate>Wed, 20 Apr 2011 13:34:31 +0000</pubDate>
		<dc:creator><![CDATA[Rune Grønkjær]]></dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[e-commerce]]></category>
		<category><![CDATA[Tea Commerce]]></category>
		<category><![CDATA[umbraco]]></category>
		<category><![CDATA[ecommerce]]></category>
		<category><![CDATA[Licens]]></category>

		<guid isPermaLink="false">http://rune.gronkjaer.dk/blog/?p=803</guid>
		<description><![CDATA[Flere og flere i Umbraco communitiet efterspørger en billig måde at sælge license
(Mange mindre eller mellemstore udviklere har nogle produkter de ønsker at sælge. Måske sælger de dem allerede, men alt foregår manuelt og der mistes måske nogle kunder, som syntes det er for besværligt, eller som bare ikke kender til produktet. Løsningen er i mange tilfælde at sælge sine produkter i en webshop. Problemet er bare at de ofte er for dyre, for besværlige eller bare ikke lever op til kravene.)<br /><br />
Jeg har i samarbejde med Anders Burla Johansen udviklet en udvidelse til <a href="http://www.teacommerce.dk">Tea Commerce</a>, som gør det nemmere end nemt at få sin egen licens webshop op at køre. Her på siden kan du finde alt hvad du skal gøre for at få din egen licens webshop med Tea Commerce og Umbraco.]]></description>
				<content:encoded><![CDATA[Flere og flere i Umbraco communitiet efterspørger en billig måde at sælge license
(Mange mindre eller mellemstore udviklere har nogle produkter de ønsker at sælge. Måske sælger de dem allerede, men alt foregår manuelt og der mistes måske nogle kunder, som syntes det er for besværligt, eller som bare ikke kender til produktet. Løsningen er i mange tilfælde at sælge sine produkter i en webshop. Problemet er bare at de ofte er for dyre, for besværlige eller bare ikke lever op til kravene.)<br /><br />
Jeg har i samarbejde med Anders Burla Johansen udviklet en udvidelse til <a href="http://www.teacommerce.dk">Tea Commerce</a>, som gør det nemmere end nemt at få sin egen licens webshop op at køre. Her på siden kan du finde alt hvad du skal gøre for at få din egen licens webshop med Tea Commerce og Umbraco.
<h2>Mål</h2>
jeg skal have fundet en simpel men effektiv måde at licensere et stykke software. Jeg vil fokusere på at kunne sælge licenser til web software, som skal være begrænset til et top level domæne. Det skal dog være muligt med få justeringer, at kunne lave licenser der er begrænset på andre måder eller som fungerer til eksempelvis desktop applikationer. Det vil dog være helt op til den enkelte udvikler, at tilpasse denne blogposts eksempler til den konkrete opgave han/hun står overfor.<br /><br />
Jeg vil også lave en License Kit package til Umbraco, som giver en simpel og god bund for en licens webshop. License Kit packagen skal fungere på samme måde, som <a href="http://our.umbraco.org/projects/website-utilities/tea-commerce-starter-kit">Tea Commerce Starter Kit&#8217;et</a>. Man skal altså kunne installere de javascripts, xslt&#8217;er, dokumenttyper osv., som kan bruges i den færdige licens webshop.<br /><br />
Når du har gennemgået denne guide vil du stå med en webshop, som kan sælge dine, eller andres licenser. <a href="#tutorialStart">Gå direkte til tutorial</a>
<h2>Udgangspunkt</h2>
Inden du går igang skal du først have en ren Umbraco løsning, med en <a href="http://www.teacommerce.dk">installation af Tea Commerce</a>. Denne tutorial understøtter Umbraco 4.5+ og Tea Commerce 1.2.1.1+.
<h2>Løsning</h2>
Løsningen består af 4 forskellige produkter, som hver især løser en lille del af problemstillingen. Du kan vælge at bruge dem alle fire, ændre dem efter dit behov og så har du et setup, som kan sælge dine licenser. Den ene er en package til umbraco og <a href="http://www.teacommerce.dk/blogmedia/Tea_Commerce_License_Kit_1.1.1.0 .NET 4.0.zip">kan hentes her</a>. De tre sidste produkter ligger samlet i en Visual Studio solution, <a href="www.teacommerce.dk/blogmedia/TeaCommerce.LicenseKit.Developer.zip">som du også kan hente på License Kit siden</a>.  I det følgende vil jeg kort gennemgå de fire produkter.
<h4>De fire produkter til denne tutorial</h4>
<ol>
<li><a href="#product1">License Kit package til Umbraco</a></li>
<li><a href="#product2">Asymmetric key generator</a></li>
<li><a href="#product3">License generation for Tea Commerce</a></li>
<li><a href="#product4">License checker til produktet</a></li>
</ol>
<h3 id="product1">License Kit package til Umbraco</h3>
Vil du hurtigt igang har jeg lavet <a href="http://www.teacommerce.dk/blogmedia/Tea_Commerce_License_Kit_1.1.1.0 .NET 4.0.zip">License Kit packagen til Tea Commerce og Umbraco</a>. Den installerer et starter kit på din Umbraco løsning og sørger for at lave de mest basale opsætningsændringer i selve Tea Commerce.
<h4>Med License Kit&#8217;et får du:</h4>
<ol>
<li>Ændring af Tea Commerce basis opsætninger</li>
<li>Dokumenttyper</li>
<li>Templates</li>
<li>CSS</li>
<li>Javascript</li>
<li>XSLT&#8217;er og macroer</li>
<li>Sider og et produkt i indholdssektionen</li>
</ol>
Alt sammen målrettet en licens webshop og med alle de best practices vi har opbygget i <a href="http://www.teasolutions.dk">Tea Solutions</a>.<br />
<img src="http://rune.gronkjaer.dk/blog/wp-content/uploads/2011/04/Content-Umbraco-CMS-licensekit.teacommerce.dk_1302675511201.png" alt="License Kit Content tree" title="Content - Umbraco CMS - licensekit.teacommerce.dk_1302675511201" width="442" height="354" class="alignnone size-full wp-image-812" srcset="http://rune.gronkjaer.dk/blog/wp-content/uploads/2011/04/Content-Umbraco-CMS-licensekit.teacommerce.dk_1302675511201.png 442w, http://rune.gronkjaer.dk/blog/wp-content/uploads/2011/04/Content-Umbraco-CMS-licensekit.teacommerce.dk_1302675511201-300x240.png 300w" sizes="(max-width: 442px) 100vw, 442px" /><br />
<small>Content tree efter installation</small>
<h3 id="product2">Asymmetric key generator</h3>
Projekt: <strong>TeaCommerce.LicenseKit.AsymmetricKeyGeneration</strong><br />
Dette lille projekt er yderst simpelt og ligger som sagt i Visual Studio .NET solutionen. Kører man det, genererer den to XML filer, som den gemmer i roden af dit C-drev. I den ene gemmer den en hemmelig private key, i den anden en knapt så hemmelig public key. Hvor og hvordan de skal bruges kommer jeg ind på senere.
<h3 id="product3">License generation for Tea Commerce</h3>
Projekt: <strong>TeaCommerce.LicenseKit.Webshop</strong><br />
Dette class library er en extension til Tea Commerce, som giver shoppen mulighed for at generere selve licenserne. I al sin enkelthed hooker den sig ind på eventen AfterOrderFinalized, som fyres når ordren er blevet betalt og gennemført. Den genererer i min opsætning en licensfil og vedhæfter den en e-mail, som den sender til køber.<br />
Ud over selve Tea Commerce extensionen medfølger en LicenseHelper klasse, som genererer licensnøglen til filen. Har man behov for yderligere sikkerhed omkring sin licens vil det være den man skal udvide.
<h3 id="product4">License checker til produktet</h3>
Projekt: <strong>TeaCommerce.LicenseKit.Product</strong><br />
Dette projekt skal forestille dit produkt. I mit eksempel kan produktet skrive ud om det er licenseret eller ej. Der medfølger en LicenseHelper klasse, som i dette tilfælde kan tjekke efter gyldige licenser. Med et enkelt metodekald kan man få at vide om produktet er licenseret. Denne funktionalitet kan indsættes i et hvilket som helst .NET website produkt.<br /><br />
<h1 id="tutorialStart" class="entry-title">Tutorial &#8211; Sådan gør du</h1>
Følg nedenstående tutorial for at sætte din egen shop op.
<h3 id="tutorial1">1. Download de ting der skal bruges</h3>
Som nævnt ovenfor har jeg lavet et License Kit og Anders Burla har lavet tre .NET projekter, som kan hjælpe dig godt igang. Dem skal du downloade.
<ol>
<li><a href="http://www.teacommerce.dk/blogmedia/Tea_Commerce_License_Kit_1.1.1.0 .NET 4.0.zip">Tea Commerce License Kit package til Umbraco</a></li>
<li><a href="www.teacommerce.dk/blogmedia/TeaCommerce.LicenseKit.Developer.zip">LicenseKit projects (.NET visual studio solution)</a></li>
</ol>
<h3 id="tutorial2">2. Installer License Kit packagen</h3>
Dette gør du, som man installerer alle andre Umbraco packages. Husk at du skal installere denne pakke på en ren Umbraco installation hvor du allerede har installeret <a href="http://www.teacommerce.dk">Tea Commerce v1.2.1.1+</a>.<br />
Efter installationen kan du tjekke om det virker ved at lægge en licens i kurven og gennemføre ordren. På nuværende tidspunkt vil den IKKE generere nogen licensfiler. Du vil dog kunne se at ordren går igennem som den skal, og at vi nu bare mangler at kunne generere licensfilerne.
<h3 id="tutorial3">3. Generer et private public key pair</h3>
Nu skal vi have genereret et private/public key pair. Til formålet skal du starte den solution, du lige har downloadet, i Visual Studio 2010. Projektet TeaCommerce.LicenseKit.AsymmetricKeyGeneration har den funktionalitet du skal bruge. Kører du projektet, vil der blive gemt to xml-filer på dit C-drev.<br /><br />
Den ene fil er din private key, den anden er din public key. Private key filen skal nu kopieres ind i din webshops App_Data mappe. Derefter skal du taste navnet på filen ind på produktets &#8220;License Key Private key file&#8221; property i Umbraco&#8217;s content. Jeg har skrevet defaultnavnet ind allerede, så hvis ikke du ændrer navnet på filen, behøver du ikke gøre mere.<br />
Vi skal kun bruge indholdet af public key filen. Det skal senere <a href="#tutorial5">kopieres ind i dit produkt</a>.<br /><br />
<strong>OBS: </strong> For hvert af dine produkter skal du generere et unikt key pair, som nævnt herover. På den måde vil man ikke kunne genbruge en licens imellem to forskellige produkter.
<h4>Teorien bag</h4>
Til at beskytte dit produkts ophavsret laver vi i dette eksempel en licens, som produktet kan verificere. Ved at signe licensen med vores private key kan vi med vores public key verificere den. På den måde kan vi læse indholdet af licensen i vores produkt og sikre os at produktet er licenseret. Metoden er relativt sikker, da man har meget svært ved at bryde krypteringen uden den private key. Den er også simpel, da produktet ikke behøver at tjekke op imod en webservice for at blive authenticated. 
<h4>Indstillinger du kan ændre</h4>
Du kan vælge at ændre det meste i dette projekt. Det vigtigste er at du får genereret de to keys. Hvad du kalder filerne eller hvor og hvordan du gemmer dem er underordnet.<br />
<strong>OBS:</strong> Vær dog opmærksom på at hvis du ændrer på private key filens navn eller placering på webserveren, vil du også skulle ændre det i <a href="#tutorial4">TeaCommerce.LicenseKit.Webshop projektet</a>, hvor den læser filen.<br />
<strong>OBS:</strong> Din private key SKAL være sikret. Den må altså under ingen omstændigheder kunne downloades fra webshoppen. Derfor har vi valgt at ligge den i App_Data mappen, som er sikret fra IIS&#8217;ens side.


<h3 id="tutorial4">4. Udvide webshoppen</h3>
Nu skal vi have webshoppen til at generere licenser. Til det formål skal vi have bygget TeaCommerce.LicenseKit.Webshop projektet. Den DLL du får ud af projektet skal ligges op i webshoppens bin mappe. I bund og grund er det nok. Nu kan din webshop generere licenser.<br />
Den lille extension sørger også for at generere en email, hvori licensnøglerne attach&#8217;es. Emailens body bliver genereret med Tea Commerce&#8217;s egen InvokeXSLT, som benyttes til at hente indholdet af en bestemt xslt fil. I xslt filen har du adgang til ordren og kan skrive en pæn tekst eller hvad du nu har lyst til.<br /><br />
Du kan nu teste om det fungerer ved at køre endnu en ordre igennem. Så længe websitet har adgang til en smtp server, vil den nu sende en e-mail med licensnøglen.
<strong>OBS: </strong> Husk at der i dette projekt ligger en reference til Tea Commerce DLL&#8217;en TeaCommerce.Data. Den skal du sørge for svarer til den du har liggende på webshoppen.
<h4>Teorien bag</h4>
I projektet ligger en LicenseHelper klasse. Det er den som genererer selve licensnøglen med din private key, som den selvfølgelig skal kende til.<br />
I licensen bliver der gemt en tekst, som senere kan hives ud og benyttes til at verificere licensen. I den tekst har jeg indsat det domæne, som brugeren taster ind, når han lægger licensen i kurven. Foran domænet er indsat &#8220;0001&#8221;. Dette er en anordning der skal sikre at vi i fremtiden kan generere andre typer af licenser. Dette kunne fx være en serverlicens, som havde så kunne have prefixet &#8220;0002&#8221;. Meningen er at produktet skal tjekke dette firecifrede tal og så vide hvilken metode den skal <a href="#tutorial5">benytte til at tjekke licensen</a>.
<h4>Indstillinger du kan ændre</h4>
Du kan ændre på flere forskellige parametre i dette projekt.
<ul>
<li>
  E-mail &#8211; Du kan rette så meget du har lyst til på den e-mail der bliver sendt ud. I eksemplet har vi hardcoded subject, sender osv., men du kan hente disse informationer fra andre steder.
</li>
<li>
E-mail body &#8211; I koden er hardcoded navnet på en xslt fil. Den kan du ændre eller finde en anden måde at generere e-mailens body
</li>
<li>
Licens private key &#8211; Kommer i eksemplet fra selve produktnoden, hvor den er blevet indtastet. Du kan også hardcode placeringen ind eller finde en anden måde at kæde et produkt sammen med sin private key. Det vigtige er bare at private key&#8217;en forbliver sikker. Måden jeg har gjort det på her er både sikker, men også fleksibel, da man nemt vil kunne oprette nye licensprodukter.
</li>
<li>
Navnet på licens filen &#8211; Lige nu kalder jeg bare licensfilen for &#8220;[produktnavn]-[domænenavn].lic&#8221;. Du kan kalde den hvad som helst, da vi i produktet tjekker alle *.lic filer, for at finde en korrekt licens.
</li>
<li>
  Private key &#8211; Du kan vælge at flytte eller omnavngive din private key fil.
</li>
<li>
  productSaltLength &#8211; Skal bare passe med den salt, der bruges til at dekryptere licensen
</li>
</ul>
<h3 id="tutorial5">5. Lav tjekket i produktet</h3>
Nu har vi en licensnøgle, som skal testes. For nemhedens skyld kan du vælge at teste den direkte på webshop sitet. I .NET solutionen ligger projektet TeaCommerce.LicenseKit.Product, som skal gøre det ud for vores produkt.<br />
Det første du gør, er at kopiere indholdet af din public key xml-fil, som ligger i roden af dit C-drev.<br />
I LicenseHelper klassen skal indholdet sættes ind i konstanten &#8220;publicLicenseKey&#8221;.<br /><br />
Når du har gjort det rebuilder du projektet og kopierer DLL&#8217;en ind i bin mappen og LicenseCheckTest.ascx ind i usercontrols mappen. LicenseCheckTest.ascx skal forestille sig dit produkt, som vi nu skal sætte ind på sitet. Det gør du ved at oprette en ny macro og vælge LicenseCheckTest.ascx i usercontrol dropdown&#8217;en. Klikker du &#8220;Use in editor&#8221; til kan du indsætte macroen på en af dine sider.<br />
Åben siden. Hvis den skriver &#8220;Domain is licensed&#8221; har du gjort det hele rigtigt. Hvis ikke skal du lige tjekke de tidligere steps i denne tutorial igen.
<h4>Teorien bag</h4>
I LicenseCheckTest.ascx.cs kan du se hvor nemt selve licenstjekket foregår i selve produktet. LicenseHelper.HasLicense() returnerer true, hvis der findes en valid licens. Hvor og hvordan du bruger denne metode i dit produkt er helt op til dig.<br />
I LicenseHelper klassen kan du se hvordan selve tjekket bliver lavet. Så snart klassen initialiseres findes licenserne og gemmes i en statisk variabel, hvorfra de vil kunne hentes senere.<br />
HasLicense metoden tjekker de gemte licenser op imod det domæne sitet køres på og returnerer true så snart et match er fundet.<br />
Bemærk at der er lavet en switch case hvori vi undersøge hvilken type licens vi har fat i. Derefter behandles licensen derefter.
<h4>Indstillinger du kan ændre</h4>
<ul>
<li>
  publicLicenseKey &#8211; public key&#8217;en er hardcoded ind i projektet, men kan selvfølgelig også ligges på serveren som en fil. Alt efter brugssituationen er det dog meget praktisk at beholde den her, da der så er samling på tingene.
</li>
<li>
  productSaltLength &#8211; Skal bare passe med den salt, der er brugt til at kryptere licensen
</li>
<li>
  Placering af licensfilen &#8211; I eksemplet placerer vi den i bin mappen. Den kan dog ligges hvorend du lyster, så længe Helperen kan komme til dens indhold.
</li>
</ul>
<h2>Mange tak til</h2>
Mine kolleger <a href="http://anders.burla.dk/">Anders Burla Johansen</a> og Morten Vejhe. Anders for hans store arbejde med licensdelen og Morten for hans viden om alt muligt underligt. Også tak til <a href="http://blog.mattbrailsford.com/">Matt Brailsford</a>, som har testet denne tutorial.
<h2>Tea Commerce Links</h2>
<ul>
<li><a href="http://www.teacommerce.dk">Official Tea Commerce Website</a></li>
<li><a href="http://www.teacommerce.dk/en/documentation.aspx" alt="List of all Tea Commerce Documentation pages" title="List of all Tea Commerce 
Documentation pages">Tea Commerce Documentation</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-starter-kit.aspx">Tea Commerce Starter Kit</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-demo-webshop.aspx">Tea Commerce Demo Webshop</a></li>
</ul>]]></content:encoded>
			</item>
		<item>
		<title>Nyt website til Jensen&#8217;s Foods</title>
		<link>http://rune.gronkjaer.dk/blog/2011/04/16/nyt-website-til-jensens-foods/</link>
		<pubDate>Sat, 16 Apr 2011 13:33:48 +0000</pubDate>
		<dc:creator><![CDATA[Rune Grønkjær]]></dc:creator>
				<category><![CDATA[Image Viewer]]></category>
		<category><![CDATA[umbraco]]></category>
		<category><![CDATA[umbraco nyt website]]></category>

		<guid isPermaLink="false">http://rune.gronkjaer.dk/blog/?p=834</guid>
		<description><![CDATA[For ganske nylig lagde vi <a href="http://jensensfoods.dk/">Jensen's Foods nye website online</a>. Firmaet med hjemsted i Struer har fra starten haft dejligt store ambitioner med det nye site og har samtidig haft viljen til at lægge ressourcerne i det. Det har derfor været et rigtigt spændende site at sætte op. Ud over et godt samarbejde med <a href="http://jensensfoods.dk/">Jensen's Foods</a>, har det været en fornøjelse, at arbejde med <a href="http://happyadvertising.dk/">Happy Advertising</a>, som har stået for designet af opgaven.]]></description>
				<content:encoded><![CDATA[For ganske nylig lagde vi <a href="http://jensensfoods.dk/">Jensen&#8217;s Foods nye website online</a>. Firmaet med hjemsted i Struer har fra starten haft dejligt store ambitioner med det nye site og har samtidig haft viljen til at lægge ressourcerne i det. Det har derfor været et rigtigt spændende site at sætte op. Ud over et godt samarbejde med <a href="http://jensensfoods.dk/">Jensen&#8217;s Foods</a>, har det været en fornøjelse, at arbejde med <a href="http://happyadvertising.dk/">Happy Advertising</a>, som har stået for designet af opgaven.
<h2>Store Ambitioner</h2>
Jensen&#8217;s Foods lagde fra starten op til at det skulle være et website uden blinde veje. De ønskede at brugeren altid havde mulighed for at kunne komme videre til noget nyt interresant indhold, uanset hvor på sitet han/hun måtte befinde sig. De ville også gerne give brugerne mulighed for, at dele sitets indhold med deres venner og kolleger via sociale medier.<br /><br />
Den slags sammenkædning af indhold kræver meget af både systemet, såvel som af personerne der skal vedligeholde det. Det tager tid at flette sitet sammen på kryds og tværs og systemet skal helst gøre opgaven let.
<h2>Løsningen</h2>
Det nye website skulle selvfølgelig sættes op i <a href="http://umbraco.com/">Umbraco</a>. Både fordi det er et fantastisk CMS at udvikle på, men også fordi det ville give mulighed for at lave den store sammenfletning af indholdet. Derudover kan man få en lang perlerække af udvidelsespakker til Umbraco. Nogle gratis og nogle få som koster penge. Dem der koster noget betaler man dog gladeligt for, da de dækker nogle helt basale behov.<br /><br />
I vores oplæg til Jensen&#8217;s Foods foreslog vi, at lave en række bokse i højre kolonne af websitet. Det var dem der skulle binde sitet sammen ved, at linke til indhold relateret til den side man står på. Boksene skulle benyttes på forsiden også, hvor de linker ud til det mest populære eller relavante indhold.<br /><br />
Med hjælp fra Umbraco CMS&#8217;et har jeg kunne gøre det let at tilføje og fjerne boksene, på undersiderne såvel som på forsiden. Jeg besluttede fra starten at alle sider skulle kunne &#8220;være&#8221; en boks. Alle sider giver derfor mulighed for at tilføje en overskrift, et billede og en lille tekst, som skal bruges i boksen. I højre kolonne af vælger man så nogle sider ud, som så skal vises, som bokse. Når man klikker på boksen linkes der til den pågældende side. Alle sider kan altså være en boks, og alle sider kan have tilknyttet et antal bokse, som så bliver vist i højre spalte.<br /><br />
Systemet er det samme for almindelige sider, opskrifter såvel som produkter. Med nogle få klik kan Jensen&#8217;s Foods nu sætte en opskrift på forsiden, på en produktside og på en almindelig tekstside og fra de steder kan brugeren nu finde hen til opskriften. De har fået indført det over hele sitet og det skulle gerne få brugerne til at bruge endnu mere tid på sitet.
<h2>Produkter og opskrifter</h2>
Produkter og opskrifter udgør en stor del af Jensen&#8217;s Foods indhold på websitet. Til begge typer indhold har de haft et super billedmateriale, som har været vigtigt at vise til brugeren. Jeg har derfor brugt mit <a href="http://rune.gronkjaer.dk/blog/image-viewer/">jQuery plugin Image Viewer</a>, til at vise billederne i store formater. Fordelen ved jQuery Image Viewer er, at den kan vise billedet i så stort et format, som brugerens skærm tillader det. Så alle vil få en optimal oplevelse.
<h3>Image gen</h3>
Det har været vigtigt for mig at gøre det til en overkommelig opgave at vedligeholde websitet. Derfor sørgede vi for at alle grafikker af henholdsvis produkter og opskrifter, var i samme størrelsesforhold. På den måde kunne jeg lade dem uploade et enkelt billede og så genbruge det billede alle andre steder på sitet. For at lave de forskellige størrelser af billederne har jeg benyttet den super gode <a href="http://our.umbraco.org/projects/website-utilities/imagegen">ImageGen</a> pakke til Umbraco. ImageGen sørger for at resize billeder og cache dem til næste gang. Det er et fantastisk værktøj, og for en mindre betaling får man en udvidet licens, der giver ImageGen endnu flere muligheder.
<h3>Social Media</h3>
Opskrifter og Produkter kan deles på alle de gængse sociale medier. Det gøres ved hjælp af den efterhånden meget genkendelige <a href="http://www.addthis.com/">Addthis</a> bookmarking service. Den giver mulighed for at man selv kan fokusere på nogle sociale medier, men giver samtidig brugeren mulighed for at vælge imellem en lang række andre sociale medier. Jeg bruger den fordi det er nemt, godt lavet og gratis.
<h2>Billedbank</h2>
Vi har sat en billedbank op til at udgive Jensen&#8217;s Foods pressebilleder. Egentligt en ret ordninær opgave, men Umbraco har igen kunnet gøre vedligeholdelsen nem og bekvem. Billedbanken er lavet, så man bare skal lægge billederne ind i Umbraco &#8217;s mediearkiv. Derefter trækker jeg dem automatisk ud med xslt og lister dem på siden. Med muligheden for at tilføje ekstra data til billederne i mediearkivet har Jensen&#8217;s Foods tilføje et link og en tekst til alle billederne. Endnu en gang kæder det noget indhold sammen på kryds af grænserne. Til billedbanken har jeg også brugt ImageGen til at generere en mindre version af alle billeder. 
<h2>Contour</h2>
Jensen&#8217;s Foods har indtil videre to formularer på siden. Begge er lavet med <a href="http://umbraco.com/products/more-add-ons/contour">Umbraco&#8217;s eget produkt &#8211; Contour</a>. Countour er et stort og flexibelt system til at generere formularer. Mulighederne er gode for at style formularerne efter behov. Det er også let at bruge, så kunderne vil have mulighed for selv at vedligeholde eller oprette nye formularer.
<h2>Google site search</h2>
Søgning på Jensen&#8217;s Foods er implementeret med Google site search. Jeg har fiflet noget JavaScript sammen, til at understøtte Google site search. Det har gjort det muligt at sende søgeord med i querystring’en og stadig få vist et søgeresultat på siden. Dette har været nødvendigt, eftersom Jensen&#8217;s Foods ønskede en søgeboks i toppen af designet på alle sider. Søger man med den, sender javascriptet automatisk brugeren til søgesiden og initialiserer søgningen. Google Site Search er et stærkt værktøj der stiller Googles søgealgoritmer til rådighed direkte på websitet. Brugerne vil uden problemer kunne finde alt indhold på sitet.
]]></content:encoded>
			</item>
		<item>
		<title>Tea Commerce dynamisk moms</title>
		<link>http://rune.gronkjaer.dk/blog/2011/04/12/tea-commerce-dynamisk-moms/</link>
		<pubDate>Tue, 12 Apr 2011 11:06:22 +0000</pubDate>
		<dc:creator><![CDATA[Rune Grønkjær]]></dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[e-commerce]]></category>
		<category><![CDATA[Tea Commerce]]></category>
		<category><![CDATA[umbraco]]></category>
		<category><![CDATA[custom]]></category>
		<category><![CDATA[event model]]></category>
		<category><![CDATA[events]]></category>
		<category><![CDATA[manipulation]]></category>
		<category><![CDATA[moms]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[VAT]]></category>

		<guid isPermaLink="false">http://rune.gronkjaer.dk/blog/?p=685</guid>
		<description><![CDATA[Skal man sælge varer i flere lande kan man få behov for at have en flexibel momsopsætning. Under opsætning af vores egen Tea Commerce webshop til salg af Tea Commerce licenser har jeg udviklet en stump kode, som netop ændrer på momsen efter nogle bestemte kriterier]]></description>
				<content:encoded><![CDATA[Skal man sælge varer i flere lande kan man få behov for at have en flexibel momsopsætning. Under opsætning af vores egen Tea Commerce webshop til salg af Tea Commerce licenser har jeg udviklet en stump kode, som netop ændrer på momsen efter nogle bestemte kriterier.<br />
<h2>Moms scenariet</h2>
I vores scenarie er webshoppen registreret i Danmark og vi har derfor følgende muligheder, bygget på viden om kundens land og momsnummer.
<ol>
<li>
Kunden er fra Danmark og skal derfor betale dansk moms uanset hvad.
</li>
<li>
Kunden er fra et EU-land og har ikke noget gyldigt VAT nummer. Kunden vil skulle betale dansk moms.
</li>
<li>
Kunden er fra et EU-land og har et gyldigt VAT nummer. Kunden skal ikke betale moms.
</li>
<li>
Kunden er fra et land uden for EU og skal derfor ikke betale moms.
</li>
</ol>
<h2>Værd at notere</h2>
I min løsning benytter jeg en officiel webservice fra europa parlamentet til at tjekke de momsnumre, som kunderne indtaster. Til andre interresserede er her adressen til webservicen: http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl.
<br /><br />
Jeg vælger at tilmelde mig to <a href="http://rune.gronkjaer.dk/blog/2010/11/26/sadan-bruger-man-tea-commerce-events/">Tea Commerce events</a> hvor jeg så har muligheden for at manipulere ordren. Den ene er &#8220;CountryChanged&#8221;, som selvfølgelig skal bruges hver gang der vælges et nyt land. Hver gang der skiftes land skal jeg lave valideringen eftersom man skal matche landet op med det indtastede VAT nummer.<br /><br />
Den anden er &#8220;OrderPropertiesUpdated&#8221;. Her sørger jeg for kun, at lave valideringen hver gang der er ændringer til propertien &#8220;companyVATNo&#8221;. Dette tjek er vigtigt for performance, da kaldet til webservicen vil kunne være meget dyrt og vil kunne gøre oplevelsen af sitet dårligere.
<br /><br />
Fra <a href="http://www.iso.org/iso/country_codes/iso_3166_code_lists/english_country_names_and_code_elements.htm">iso.org</a> hentede jeg en liste med alle officielle lande og importerede dem til Tea Commerce. <a href="http://www.teacommerce.dk/media/4818/allthemcountries.csv">Her er en csv med alle landende.</a> Jeg har markeret alle de officielle medlemmer af EU, som jeg har brugt til at lave en ekstra tabel med deres Id&#8217;er. På den måde kan jeg lave et simpelt opslag for at tjekke om det valgte land er medlem af EU.
<h4>Det fulde eksempel</h4>
<pre class="brush: csharp">
using System.Collections.Generic;
using System.Linq;
using TeaCommerce.Data;
using TeaCommerce.Data.Extensibility;
using TeaCommerce.WebShop.Integration.DB;
using umbraco;

namespace TeaCommerce.WebShop.Integration {
  public class LicenseExtension : ITeaCommerceExtension {

    const long danishVATGroupId = 1;
    const long noVATGroupId = 2;

    /// <summary>
    /// Initialize wil automatically be run by Tea Commerce on apllication load.
    /// Any events you want to hook into is done here.
    /// </summary>
    public void Initialize() {
      //The only custom thing we want to do happens after the order has been finalized
      WebshopEvents.OrderPropertiesUpdated += WebshopEvents_OrderPropertiesUpdated;
      WebshopEvents.CountryChanged += WebshopEvents_CountryChanged;
    }

    void WebshopEvents_CountryChanged( Order order, Country country ) {
      ValidateAndSetVat( order );
    }

    void WebshopEvents_OrderPropertiesUpdated( Order order, IEnumerable&lt;OrderProperty&gt; properties ) {
      OrderProperty vatProperty = properties.SingleOrDefault( p => p.Alias.Equals( "companyVATNo" ) );
      if ( vatProperty != null )
        ValidateAndSetVat( order );
    }

    #region Private methods

    /// <summary>
    /// Checks the VAT number in the european unions own database
    /// </summary>
    /// <param name="vatNumber">The customer VAT number</param>
    /// <param name="countryCode">The customers country code</param>
    /// <returns>true if the VAT number is a valid (EUROPEAN only)</returns>
    private bool CheckVatNumber( string vatNumber, string countryCode ) {
      bool isValid = false;
      string name = string.Empty, address = string.Empty;
      if ( !vatNumber.Equals( string.Empty ) && !countryCode.Equals( string.Empty ) ) {
        CheckVatService.checkVatRequest cvr = new CheckVatService.checkVatRequest( countryCode, vatNumber );
        CheckVatService.checkVatPortTypeClient cvptc = new CheckVatService.checkVatPortTypeClient();
        cvptc.checkVat( ref countryCode, ref vatNumber, out isValid, out name, out address );
      }
      return isValid;
    }

    /// <summary>
    /// Validates the order country and VAT number and sets the VAT group accordingly
    /// </summary>
    private void ValidateAndSetVat( Order order ) {
      if ( order.Country.CountryCode.ToLower().Equals( "dk" ) ) {
        //We are in Denmark and 25% VAT is applicable
        order.VATGroupId = danishVATGroupId;
      } else {
        //The country is not Denmark. Where is it?
        using ( TeaCustomDataContext dc = new TeaCustomDataContext( GlobalSettings.DbDSN ) ) {
          if ( dc.Tea_EuropeanCountries.Any( ec => ec.CountryId == order.CountryId ) ) {
            //The country is a member of the European Union and we need to check the VAT number
            OrderProperty vatProperty = order.Properties.SingleOrDefault( p => p.Alias.Equals( "companyVATNo" ) );

            if ( vatProperty != null && CheckVatNumber( vatProperty.Value, order.Country.CountryCode ) )
              //We are in Europe and the customer has a valid VAT number - 0% VAT is applicable
              order.VATGroupId = noVATGroupId;
            else
              //We are in Europe and the customer does not have a valid VAT number - 25% VAT is applicable
              order.VATGroupId = danishVATGroupId;

          } else {
            //The country is NOT a member of the European Union - 0% VAT is applicable
            order.VATGroupId = noVATGroupId;
          }
        }

      }
      order.Save();
    }
    #endregion
  }
}
</pre>
<h2>Tea Commerce links</h2>
<ul>
<li><a href="http://www.teacommerce.dk">Official Tea Commerce Website</a></li>
<li><a href="http://www.teacommerce.dk/en/documentation.aspx" alt="List of all Tea Commerce Documentation pages" title="List of all Tea Commerce 
Documentation pages">Tea Commerce Documentation</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-multilanguage-starter-kit.aspx">Tea Commerce Multilanguage Kit</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-starter-kit.aspx">Tea Commerce Starter Kit</a></li>
<li><a href="http://www.teacommerce.dk/en/products/tea-commerce-demo-webshop.aspx">Tea Commerce Demo Webshop</a></li>
</ul>]]></content:encoded>
			</item>
	</channel>
</rss>
