Change comment:
There is no comment for this version
Summary
-
Page properties (3 modified, 0 added, 0 removed)
-
Attachments (0 modified, 3 added, 0 removed)
-
Objects (0 modified, 0 added, 2 removed)
Details
- Page properties
-
- Title
-
... ... @@ -1,0 +1,1 @@ 1 +Pricing tab - Hidden
-
... ... @@ -1,1 +1,1 @@ 1 - true1 +false - Content
-
... ... @@ -1,308 +1,46 @@ 1 -{{include reference="Store.Code.Macros" /}} 1 +{{velocity}} 2 += Extension price = 3 +#if("$!price" == '' && $hasAdmin) 2 2 3 -{{velocity output="false"}} 4 -#macro (getPriceMatrix $skus) 5 - #set ($priceMatrix = { 6 - 'columns': $collectionstool.sortedSet, 7 - 'rows': $collectionstool.orderedMap 8 - }) 9 - #foreach ($sku in $skus) 10 - #set ($support = "$!sku.support") 11 - #set ($users = $mathtool.toNumber($sku.users)) 12 - #set ($price = "$!sku.price") 13 - #if ($support && $users && $price) 14 - #set ($pricePerUsers = $priceMatrix.rows.get($support)) 15 - #if (!$pricePerUsers) 16 - #set ($pricePerUsers = {}) 17 - #set ($discard = $priceMatrix.rows.put($support, $pricePerUsers)) 18 - #end 19 - #set ($discard = $pricePerUsers.put($users, $price)) 20 - #set ($discard = $priceMatrix.columns.add($users)) 21 - #end 22 - #end 23 -#end 5 + {{error}}Admin error: The price field is empty. Please set a price for this extension in the **Store.PayingApps.Code.PayingAppsClass**.{{/error}} 24 24 25 -#macro (findSKUMatchingCurrentLicense $priceMatrix $minUserCount $currentLicenseDetails) 26 - #set ($skuMatchingCurrentLicense = $NULL) 27 - #if ($priceMatrix.rows.containsKey($currentLicenseDetails.support)) 28 - ## Select the best match for the specified support level. 29 - #foreach ($column in $priceMatrix.columns) 30 - #set ($price = $priceMatrix.rows.get($currentLicenseDetails.support).get($column)) 31 - #if ($price && $column >= $mathtool.max($minUserCount, $currentLicenseDetails.maxUserCount)) 32 - #set ($skuMatchingCurrentLicense = "$currentLicenseDetails.support,$column") 33 - #break 34 - #end 35 - #end 36 - #end 37 - #if (!$skuMatchingCurrentLicense) 38 - ## Select the best match for the specified user limit. 39 - #foreach ($entry in $priceMatrix.rows.entrySet()) 40 - #foreach ($column in $priceMatrix.columns) 41 - #set ($price = $entry.value.get($column)) 42 - #if ($price && $column >= $mathtool.max($minUserCount, $currentLicenseDetails.maxUserCount)) 43 - #set ($skuMatchingCurrentLicense = "$entry.key,$column") 44 - #break 45 - #end 46 - #end 47 - #if ($skuMatchingCurrentLicense) 48 - #break 49 - #end 50 - #end 51 - #end 7 + #set($price = "{{{--}}}") 52 52 #end 53 53 54 -#macro (displayPriceMatrix $priceMatrix $minUserCount $currentLicenseDetails $readOnly) 55 - <table class="prices"> 56 - <tr> 57 - <th class="legend">$escapetool.xml($services.localization.render('store.buyLicense.support')) 58 - / $escapetool.xml($services.localization.render('store.buyLicense.users'))</th> 59 - #foreach ($column in $priceMatrix.columns) 60 - <th class="users#if ($column < $minUserCount) disabled#end" 61 - title="$escapetool.xml($services.localization.render('store.buyLicense.users.hint', [$column]))" 62 - >$escapetool.xml($column)<span class="icon">$services.icon.renderHTML('user')</span></th> 63 - #end 64 - </tr> 65 - #set ($selectedSKU = $NULL) 66 - #if (!$readOnly && $currentLicenseDetails) 67 - #findSKUMatchingCurrentLicense($priceMatrix $minUserCount $currentLicenseDetails) 68 - #set ($selectedSKU = $skuMatchingCurrentLicense) 69 - #end 70 - #foreach ($entry in $priceMatrix.rows.entrySet()) 71 - <tr class="support-$escapetool.xml($entry.key)"> 72 - <th><a tabindex="0" role="button" data-toggle="popover" data-trigger="focus" data-html="true" 73 - title="$escapetool.xml($services.localization.render("store.buyLicense.support.${entry.key}.title"))" 74 - data-content="$escapetool.xml($services.localization.render( 75 - "store.buyLicense.support.${entry.key}.description"))" 76 - >$escapetool.xml($services.localization.render("store.buyLicense.support.$entry.key"))<span 77 - class="icon">$services.icon.renderHTML('info')</span></a></th> 78 - #foreach ($column in $priceMatrix.columns) 79 - #set ($price = $entry.value.get($column)) 80 - #if ($price) 81 - #set ($sku = "$entry.key,$column") 82 - #set ($disabled = $column < $minUserCount) 83 - #if (!$disabled && !$selectedSKU && !$readOnly) 84 - #set ($selectedSKU = $sku) 85 - #end 86 - <td class="price price-euro#if ($disabled) disabled#elseif ($selectedSKU == $sku) active#end" 87 - data-support="$escapetool.xml($entry.key)" data-users="$escapetool.xml($column)"> 88 - <label>#if (!$readOnly)<input type="radio" name="sku" value="$escapetool.xml($sku)" required="required" 89 - #if ($disabled)disabled="disabled"#elseif ($selectedSKU == $sku)checked="checked"#end 90 - />#end$escapetool.xml($price)</label> 91 - </td> 92 - #else 93 - <td/> 94 - #end 95 - #end 96 - </tr> 97 - #end 98 - </table> 99 -#end 10 +This application costs **$price euros/year** and you get the following: 100 100 101 -#macro (getLicenseDetails) 102 - #set ($licenseDetails = {}) 103 - #foreach ($name in ['firstName', 'lastName', 'email', 'instanceId']) 104 - #set ($discard = $licenseDetails.put($name, $request.session.getAttribute("com.xwiki.store.buyer.$name"))) 105 - #end 106 - #set ($licenseDetails.featureId = $doc.getValue('id')) 107 - #set ($licenseDetails.extensionVersion = $request.version) 108 - #if ("$!licenseDetails.extensionVersion" == '') 109 - ## Use the latest stable version. 110 - #set ($versions = $services.extension.resolveVersions($licenseDetails.featureId, 0, -1)) 111 - ## The versions are returned in ascending order and we want the latest. 112 - ## Note that we can't access the last item directly. We're forced to iterate. 113 - #foreach ($version in $versions) 114 - #if ($version.type == 'STABLE') 115 - #set ($licenseDetails.extensionVersion = $version.value) 116 - #end 117 - #end 118 - #end 119 - #set ($licenseDetails.licenseType = 'paid') 120 -#end 12 + (% class="col-xs-12 col-lg-12" id="benefits" %) ((( 13 + (% class="col-xs-12 col-s-4 col-lg-4" %) ((( 14 + image:key.png 15 + == 1 year license == 16 + By purchasing an XWiki Application License, you'll benefit from it during one year. 17 + ))) 18 + (% class="col-xs-12 col-s-4 col-lg-4" %) ((( 19 + image:recycle.png 20 + == Free updates == 21 + You benefit from all the application updates during one year. You are always up to date. 22 + ))) 23 + (% class="col-xs-12 col-s-4 col-lg-4" %) ((( 24 + image:tool.png 25 + == Support included == 26 + If you are facing an issue, you can reach the XWiki support. Our team is always available to help. 27 + ))) 28 + ))) 121 121 122 -#macro (benefits) 123 - <p>What do you get when you purchase an XWiki extension?</p> 124 - <div class="row" id="benefits"> 125 - <div class="col-xs-12 col-sm-4"> 126 - <div class="icon">$services.icon.renderHTML('key')</div> 127 - <h2>1 year license</h2> 128 - <p>By purchasing an XWiki extension license, you'll benefit from it during one year.</p> 129 - </div> 130 - <div class="col-xs-12 col-sm-4"> 131 - <div class="icon">$services.icon.renderHTML('refresh')</div> 132 - <h2>Free updates</h2> 133 - <p>You benefit from all the extension updates during one year. You are always up to date.</p> 134 - </div> 135 - <div class="col-xs-12 col-sm-4"> 136 - <div class="icon">$services.icon.renderHTML('wrench')</div> 137 - <h2>Support included</h2> 138 - <p>If you are facing an issue, you can reach the XWiki support. Our team is always available to help.</p> 139 - </div> 140 - </div> 141 -#end 30 +{{comment}} 31 +* __1 year license__: By purchasing an XWiki Application License, you'll benefit from it during one year. 32 +* __Free updates__: You benefit from all the application updates during one year. You are always up to date. 33 +* __Support included__: If you are facing an issue, you can reach the [[XWiki support>>mailto:support@xwiki.com]]. Our team is always available to help. 34 +{{/comment}} 142 142 143 -#macro (getCurrentLicense $licenseDetails) 144 - ## Get the best license for the specified instance and feature. 145 - #set ($currentLicenseDetails = $NULL) 146 - #getLicenseQuery($licenseDetails.instanceId $licenseDetails.featureId $query) 147 - #set ($results = $query.setLimit(1).execute()) 148 - #if ($results && $results.size() > 0) 149 - #set ($currentLicenseDetailsDocument = $xwiki.getDocument($results[0])) 150 - #set ($oldLicenseDetails = $licenseDetails) 151 - #readLicenseDetailsFromDocument($currentLicenseDetailsDocument) 152 - ## Check if the best license is paid and still active. 153 - #if ($licenseDetails.type == 'paid' && $licenseDetails.expirationDate 154 - && $licenseDetails.expirationDate.time > $datetool.date.time) 155 - #set ($currentLicenseDetails = $licenseDetails) 156 - #end 157 - #set ($licenseDetails = $oldLicenseDetails) 158 - #end 159 -#end 36 +== VAT information == 160 160 161 -#macro (displayCurrentLicense $currentLicenseDetails) 162 - #if ($currentLicenseDetails) 163 - <dt> 164 - <label>$escapetool.xml($services.localization.render('store.buyLicense.currentLicense'))</label> 165 - </dt> 166 - <dd> 167 - ## 168 - ## Extension name 169 - ## 170 - #if ("$!currentLicenseDetails.extensionName" == '') 171 - #getLicensedExtension($currentLicenseDetails) 172 - #if ($extension) 173 - #set ($currentLicenseDetails.extensionName = $extension.name) 174 - #else 175 - #set ($currentLicenseDetails.extensionName = $currentLicenseDetails.featureId) 176 - #end 177 - #end 178 - ## 179 - ## User limit 180 - ## 181 - #set ($LONG_MAX_VALUE = $mathtool.pow(2,63)) 182 - #if (!$currentLicenseDetails.maxUserCount || $currentLicenseDetails.maxUserCount == $LONG_MAX_VALUE) 183 - ## Unlimited user count. 184 - #set ($currentLicenseDetails.maxUserCount = -1) 185 - #end 186 - ## 187 - ## Days left 188 - ## 189 - #set ($remainingTime = $currentLicenseDetails.expirationDate.time - $datetool.date.time) 190 - #set ($daysLeft = $xwiki.jodatime.getDuration($remainingTime).standardDays) 191 - ## 192 - ## Support 193 - ## 194 - #if ("$!currentLicenseDetails.support" != '') 195 - #set ($support = $services.localization.render("store.buyLicense.support.$currentLicenseDetails.support")) 196 - $escapetool.xml($services.localization.render('store.buyLicense.currentLicense.summary', 197 - [$currentLicenseDetails.extensionName, $support, $currentLicenseDetails.maxUserCount, $daysLeft])) 198 - #else 199 - <div class="text-info"> 200 - $services.icon.renderHTML('info') 201 - $escapetool.xml($services.localization.render('store.buyLicense.currentLicense.summaryWithoutSupport', 202 - [$currentLicenseDetails.extensionName, $currentLicenseDetails.maxUserCount, $daysLeft])) 203 - </div> 204 - <p class="xHint">$escapetool.xml($services.localization.render('store.buyLicense.currentLicense.hint'))</p> 205 - #end 206 - </dd> 207 - #end 208 -#end 38 +* If you are in the EU and have a VAT number there is no VAT to add to the price 39 +* If you are in the EU and don't have a VAT number there is the VAT of your country to add to the price 40 +* If you are outside the EU there is no VAT to add to the price 209 209 210 -#macro (buyLicenseForm $licenseDetails $priceMatrix $minUserCount) 211 - <form id="buyLicense" class="xform" action="" method="post"> 212 - <p>Fill in the form below to get your license.</p> 213 - <div class="hidden"> 214 - <input type="hidden" name="instanceId" value="$!escapetool.xml($licenseDetails.instanceId)"/> 215 - <input type="hidden" name="featureId" value="$!escapetool.xml($licenseDetails.featureId)"/> 216 - <input type="hidden" name="extensionVersion" value="$!escapetool.xml($licenseDetails.extensionVersion)"/> 217 - </div> 218 - <dl> 219 - <dt> 220 - <label>$escapetool.xml($services.localization.render('store.buyLicense.buyer'))</label> 221 - </dt> 222 - <dd> 223 - $!licenseDetails.firstName $!licenseDetails.lastName, $licenseDetails.email 224 - <a href="#editBuyer" class="editBuyer" 225 - title="$escapetool.xml($services.localization.render('store.buyLicense.buyer.edit'))" 226 - >$services.icon.renderHTML('pencil')</a> 227 - </dd> 228 - <dt class="hidden"> 229 - <label for="firstName"> 230 - $escapetool.xml($services.localization.render('store.buyLicense.firstName')) 231 - </label> 232 - </dt> 233 - <dd class="hidden"> 234 - <input type="text" name="firstName" id="firstName" value="$!escapetool.xml($licenseDetails.firstName)" 235 - required="required"/> 236 - </dd> 237 - <dt class="hidden"> 238 - <label for="lastName"> 239 - $escapetool.xml($services.localization.render('store.buyLicense.lastName')) 240 - </label> 241 - </dt> 242 - <dd class="hidden"> 243 - <input type="text" name="lastName" id="lastName" value="$!escapetool.xml($licenseDetails.lastName)" 244 - required="required"/> 245 - </dd> 246 - <dt class="hidden"> 247 - <label for="email"> 248 - $escapetool.xml($services.localization.render('store.buyLicense.email')) 249 - </label> 250 - <span class="xHint"> 251 - $escapetool.xml($services.localization.render('store.buyLicense.email.hint')) 252 - </span> 253 - </dt> 254 - <dd class="hidden"> 255 - <input type="email" name="email" id="email" value="$!escapetool.xml($licenseDetails.email)" 256 - class="form-control" required="required"/> 257 - </dd> 258 - #getCurrentLicense($licenseDetails) 259 - #displayCurrentLicense($currentLicenseDetails) 260 - <dt> 261 - <label>$escapetool.xml($services.localization.render('store.buyLicense.options'))</label> 262 - <span class="xHint">$escapetool.xml($services.localization.render('store.buyLicense.options.hint'))</span> 263 - </dt> 264 - <dd> 265 - #displayPriceMatrix($priceMatrix $minUserCount $currentLicenseDetails) 266 - </dd> 267 - </dl> 268 - #benefits 269 - <p> 270 - <input type="submit" class="button btn-success"#if (!$selectedSKU) disabled="disabled" #end 271 - value="$escapetool.xml($services.localization.render('store.buyLicense.submit'))"/> 272 - </p> 273 - </form> 274 -#end 42 +== How to buy == 275 275 276 -#macro (accessPurchaseOrderForm $licenseDetails) 277 - <form id="accessPurchaseOrder" class="hidden" action="$services.extension.store.activePurchaseOrderURL" method="post"> 278 - <input type="hidden" name="instanceId" value="$!escapetool.xml($licenseDetails.instanceId)"/> 279 - <input type="hidden" name="email" value="$!escapetool.xml($licenseDetails.email)"/> 280 - <input type="submit"/> 281 - </form> 282 -#end 44 +## Note: this is temporary until we implement the buy button 45 +To buy, (% id='install' %)[[install this extension from inside your XWiki instance and follow the instructions>>path:#installation]](%%). 283 283 {{/velocity}} 284 - 285 -{{velocity}} 286 -{{html clean="false"}} 287 -#set ($discard = $xwiki.ssx.use('Store.Content.Pricing')) 288 -#set ($discard = $xwiki.jsx.use('Store.Content.Pricing')) 289 -#getLicenseDetails 290 -#getPriceMatrix($prices.skus) 291 -#set ($minUserCount = $request.session.getAttribute('com.xwiki.store.buyer.userCount')) 292 -#if (!$minUserCount) 293 - #set ($minUserCount = 1) 294 -#end 295 -#if ("$!licenseDetails.instanceId" != '') 296 - #buyLicenseForm($licenseDetails $priceMatrix $minUserCount) 297 - #accessPurchaseOrderForm($licenseDetails) 298 -#else 299 - <h2>Options</h2> 300 - <p>The price varies depending on the support level and the number of users.</p> 301 - #displayPriceMatrix($priceMatrix $minUserCount $NULL true) 302 - <h2>Benefits</h2> 303 - #benefits 304 - <h2>How to Buy</h2> 305 - <p>To buy, install this extension from inside your XWiki instance and <a href="#installation">follow the instructions</a>.</p> 306 -#end 307 -{{/html}} 308 -{{/velocity}}
- key.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.Admin - Size
-
... ... @@ -1,0 +1,1 @@ 1 +1.9 KB - Content
- recycle.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.Admin - Size
-
... ... @@ -1,0 +1,1 @@ 1 +1.9 KB - Content
- tool.png
-
- Author
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.Admin - Size
-
... ... @@ -1,0 +1,1 @@ 1 +1.9 KB - Content
- XWiki.JavaScriptExtension[0]
-
- Caching policy
-
... ... @@ -1,1 +1,0 @@ 1 -long - Code
-
... ... @@ -1,57 +1,0 @@ 1 -require(['jquery', 'bootstrap'], function($) { 2 - // Activate the support information. 3 - $('table.prices [data-toggle="popover"]').popover(); 4 - 5 - // Manage the selected SKU from the price matrix. 6 - var updateSelectedSKU = function() { 7 - $(this).closest('table.prices').find('td.price.active').removeClass('active'); 8 - $(this).closest('td.price').toggleClass('active'); 9 - } 10 - $('form table.prices td.price input:checked').each(updateSelectedSKU); 11 - $('form table.prices').on('change', 'td.price input[type="radio"]', updateSelectedSKU); 12 - 13 - var showBuyerFields = function(editBuyerLink) { 14 - editBuyerLink.closest('dd').hide().prev('dt').hide() 15 - .nextAll('.hidden').removeClass('hidden') 16 - .first().css('margin-top', 0); 17 - }; 18 - 19 - // Edit buyer details link. 20 - $('a.editBuyer').click(function (event) { 21 - event.preventDefault(); 22 - showBuyerFields($(this)); 23 - }); 24 - 25 - // We need to register the event directly on the input field because it doesn't bubble up. 26 - $('form#buyLicense input').on('invalid', function() { 27 - if ($(this).is(':hidden')) { 28 - showBuyerFields($(this).closest('form').find('a.editBuyer')); 29 - } 30 - }); 31 - 32 - $('form#buyLicense').submit(function(event) { 33 - event.preventDefault(); 34 - var buyLicenseForm = $(this); 35 - var submitButton = buyLicenseForm.find('input[type="submit"]').prop('disabled', true); 36 - var progressNotification = new XWiki.widgets.Notification($jsontool.serialize($services.localization.render( 37 - 'store.buyLicense.submit.inProgress')), 'inprogress'); 38 - var url = new XWiki.Document('BuyLicense', 'Store').getURL('get', 'outputSyntax=plain'); 39 - $.post(url, buyLicenseForm.serialize()).done(function(result) { 40 - if (result && result.order) { 41 - progressNotification.replace(new XWiki.widgets.Notification($jsontool.serialize( 42 - $services.localization.render('store.buyLicense.submit.done')), 'done')); 43 - var accessPurchaseOrderForm = $('form#accessPurchaseOrder'); 44 - accessPurchaseOrderForm.find('input[name="email"]').val(buyLicenseForm.find('input[name="email"]').val()); 45 - accessPurchaseOrderForm.submit(); 46 - } else { 47 - progressNotification.replace(new XWiki.widgets.Notification($jsontool.serialize( 48 - $services.localization.render('store.buyLicense.submit.failed')), 'error')); 49 - } 50 - }).fail(function() { 51 - progressNotification.replace(new XWiki.widgets.Notification($jsontool.serialize( 52 - $services.localization.render('store.buyLicense.submit.failed')), 'error')); 53 - }).always(function() { 54 - submitButton.prop('disabled', false); 55 - }); 56 - }); 57 -}); - Parse content
-
... ... @@ -1,1 +1,0 @@ 1 -1 - Use this extension
-
... ... @@ -1,1 +1,0 @@ 1 -onDemand
- XWiki.StyleSheetExtension[0]
-
- Caching policy
-
... ... @@ -1,1 +1,0 @@ 1 -long - Code
-
... ... @@ -1,21 +1,0 @@ 1 -table.prices a[data-toggle="popover"] { 2 - color: inherit; 3 - text-decoration: none; 4 -} 5 - 6 -table.prices th span.icon { 7 - margin-left: .3em; 8 -} 9 - 10 -table.prices th.users, 11 -table.prices td.price { 12 - text-align: right; 13 -} 14 - 15 -table.prices td.price-euro label { 16 - display: block; 17 -} 18 - 19 -table.prices td.price-euro label:after { 20 - content: ' \20ac'; 21 -} - Content Type
-
... ... @@ -1,1 +1,0 @@ 1 -CSS - Parse content
-
... ... @@ -1,1 +1,0 @@ 1 -0 - Use this extension
-
... ... @@ -1,1 +1,0 @@ 1 -onDemand