Merge branch 'master' into task/3730/refactor_price_parameter
This commit is contained in:
		
				commit
				
					
						83b52d95ae
					
				
			
		
					 15 changed files with 806 additions and 231 deletions
				
			
		| 
						 | 
				
			
			@ -1,3 +1,12 @@
 | 
			
		|||
Pre-changelog: 1.2.3 2017-09-20
 | 
			
		||||
    * #3484: [dcl, hosting] Refactored account activation, password reset, VM order and cancellation email
 | 
			
		||||
    * #3731: [dcl, hosting] Added cdist ssh key handler 
 | 
			
		||||
    * #3628: [dcl] on hosting, VM is created at credit card info submit
 | 
			
		||||
    * #3772: [dcl] Updated hosting app billing into monthly subscription and added new text and translations
 | 
			
		||||
    * #3786: [hosting] Redesigned the hosting invoice and order-confirmation page
 | 
			
		||||
    * Feature: [cms, blog] Added /cms prefix for all the django-cms generated urls
 | 
			
		||||
    * Bugfix: [dcl, hosting] added host to celery error mails
 | 
			
		||||
    * Bugfix: [ungleich] Fixed wrong subdomain digitalglarus.ungleich.ch
 | 
			
		||||
1.2.2: 2017-09-08
 | 
			
		||||
    * #3704: [hosting] Added my settings page
 | 
			
		||||
    * #3771: [datacenterlight] Fixed the inconsistency in navbar style in billing page and onward
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -49,9 +49,14 @@ urlpatterns += i18n_patterns(
 | 
			
		|||
        include('ungleich_page.urls',
 | 
			
		||||
                namespace='ungleich_page'),
 | 
			
		||||
        name='ungleich_page'),
 | 
			
		||||
    url(r'^blog/', include('ungleich.urls',
 | 
			
		||||
                           namespace='ungleich')),
 | 
			
		||||
    url(r'^', include('cms.urls'))
 | 
			
		||||
    url(r'^cms/blog/',
 | 
			
		||||
        include('ungleich.urls', namespace='ungleich')),
 | 
			
		||||
    url(
 | 
			
		||||
        r'^blog/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<slug>\w[-\w]*)/$',
 | 
			
		||||
        RedirectView.as_view(pattern_name='ungleich:post-detail')),
 | 
			
		||||
    url(r'^blog/|cms/$', RedirectView.as_view(
 | 
			
		||||
        url=reverse_lazy('ungleich:post-list')), name='blog_list_view'),
 | 
			
		||||
    url(r'^cms/', include('cms.urls')),
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
urlpatterns += [
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ msgid ""
 | 
			
		|||
msgstr ""
 | 
			
		||||
"Project-Id-Version: PACKAGE VERSION\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2017-09-20 20:23+0000\n"
 | 
			
		||||
"POT-Creation-Date: 2017-09-23 19:00+0530\n"
 | 
			
		||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 | 
			
		||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 | 
			
		||||
"Language-Team: LANGUAGE <LL@li.org>\n"
 | 
			
		||||
| 
						 | 
				
			
			@ -321,10 +321,14 @@ msgstr "Als gelesen markieren"
 | 
			
		|||
msgid "All notifications"
 | 
			
		||||
msgstr "Alle Benachrichtigungen"
 | 
			
		||||
 | 
			
		||||
msgid "Date"
 | 
			
		||||
msgstr "Datum"
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid "%(page_header_text)s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
msgid "Status:"
 | 
			
		||||
msgid "Invoice Date"
 | 
			
		||||
msgstr "Rechnung Datum"
 | 
			
		||||
 | 
			
		||||
msgid "Status"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
msgid "Approved"
 | 
			
		||||
| 
						 | 
				
			
			@ -333,10 +337,10 @@ msgstr "Akzeptiert"
 | 
			
		|||
msgid "Declined"
 | 
			
		||||
msgstr "Abgelehnt"
 | 
			
		||||
 | 
			
		||||
msgid "Billed To:"
 | 
			
		||||
msgid "Billed to"
 | 
			
		||||
msgstr "Rechnungsadresse"
 | 
			
		||||
 | 
			
		||||
msgid "Payment Method:"
 | 
			
		||||
msgid "Payment method"
 | 
			
		||||
msgstr "Bezahlmethode"
 | 
			
		||||
 | 
			
		||||
msgid "ending in"
 | 
			
		||||
| 
						 | 
				
			
			@ -345,6 +349,9 @@ msgstr "endend in"
 | 
			
		|||
msgid "Order summary"
 | 
			
		||||
msgstr "Bestellungsübersicht"
 | 
			
		||||
 | 
			
		||||
msgid "Product"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
msgid "Cores"
 | 
			
		||||
msgstr "Prozessorkerne"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -354,15 +361,9 @@ msgstr "Arbeitsspeicher"
 | 
			
		|||
msgid "Disk space"
 | 
			
		||||
msgstr "Festplattenkapazität"
 | 
			
		||||
 | 
			
		||||
msgid "Configuration"
 | 
			
		||||
msgstr "Konfiguration"
 | 
			
		||||
 | 
			
		||||
msgid "Total"
 | 
			
		||||
msgstr "Gesamt"
 | 
			
		||||
 | 
			
		||||
msgid "Month"
 | 
			
		||||
msgstr "Monat"
 | 
			
		||||
 | 
			
		||||
#, python-format
 | 
			
		||||
msgid ""
 | 
			
		||||
"By clicking \"Place order\" this plan will charge your credit card account "
 | 
			
		||||
| 
						 | 
				
			
			@ -372,8 +373,10 @@ msgstr ""
 | 
			
		|||
"pro Monat belastet"
 | 
			
		||||
 | 
			
		||||
msgid "Place order"
 | 
			
		||||
msgstr "Bestelle"
 | 
			
		||||
msgstr "Bestellen"
 | 
			
		||||
 | 
			
		||||
msgid "BACK TO LIST"
 | 
			
		||||
msgstr "ZURÜCK ZUR LISTE"
 | 
			
		||||
 | 
			
		||||
msgid "Processing..."
 | 
			
		||||
msgstr "Abarbeitung..."
 | 
			
		||||
| 
						 | 
				
			
			@ -387,14 +390,14 @@ msgstr "Ein Problem ist aufgetreten. Bitte versuche es später noch einmal."
 | 
			
		|||
msgid "Order Nr."
 | 
			
		||||
msgstr "Bestellung Nr."
 | 
			
		||||
 | 
			
		||||
msgid "Date"
 | 
			
		||||
msgstr "Datum"
 | 
			
		||||
 | 
			
		||||
msgid "Amount"
 | 
			
		||||
msgstr "Betrag"
 | 
			
		||||
 | 
			
		||||
msgid "Status"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
msgid "See Invoice"
 | 
			
		||||
msgstr "Rechnung"
 | 
			
		||||
msgstr "Siehe Rechnung"
 | 
			
		||||
 | 
			
		||||
msgid "Page"
 | 
			
		||||
msgstr ""
 | 
			
		||||
| 
						 | 
				
			
			@ -405,9 +408,15 @@ msgstr ""
 | 
			
		|||
msgid "Your Order"
 | 
			
		||||
msgstr "Deine Bestellung"
 | 
			
		||||
 | 
			
		||||
msgid "Configuration"
 | 
			
		||||
msgstr "Konfiguration"
 | 
			
		||||
 | 
			
		||||
msgid "including VAT"
 | 
			
		||||
msgstr "inkl. Mehrwertsteuer"
 | 
			
		||||
 | 
			
		||||
msgid "Month"
 | 
			
		||||
msgstr "Monat"
 | 
			
		||||
 | 
			
		||||
msgid "Billing Address"
 | 
			
		||||
msgstr "Rechnungsadresse"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -573,9 +582,6 @@ msgstr "Wir sind hier, um Dir zu helfen!"
 | 
			
		|||
msgid "CONTACT"
 | 
			
		||||
msgstr "KONTACT"
 | 
			
		||||
 | 
			
		||||
msgid "BACK TO LIST"
 | 
			
		||||
msgstr "ZURÜCK ZUR LISTE"
 | 
			
		||||
 | 
			
		||||
msgid "Terminate your Virtual Machine"
 | 
			
		||||
msgstr "Deine Virtuelle Maschine beenden"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -639,6 +645,15 @@ msgstr "Ungültige Kreditkarte"
 | 
			
		|||
msgid "Confirm Order"
 | 
			
		||||
msgstr "Bestellung Bestätigen"
 | 
			
		||||
 | 
			
		||||
msgid ""
 | 
			
		||||
"The VM you are looking for is unavailable at the moment. Please contact Data "
 | 
			
		||||
"Center Light support."
 | 
			
		||||
msgstr "Kontaktiere den Data Center Light Support."
 | 
			
		||||
 | 
			
		||||
msgid "In order to create a VM, you need to create/upload your SSH KEY first."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Um eine VM zu erstellen musst du zuerst einen SSH-Key erstellen / hochladen."
 | 
			
		||||
 | 
			
		||||
msgid "Thank you for the order."
 | 
			
		||||
msgstr "Danke für Deine Bestellung."
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -646,12 +661,8 @@ msgid ""
 | 
			
		|||
"Your VM will be up and running in a few moments. We will send you a "
 | 
			
		||||
"confirmation email as soon as it is ready."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Deine VM ist gleich bereit. Wir senden Dir eine Bestätigungsemail, "
 | 
			
		||||
"sobald Du auf sie zugreifen kannst."
 | 
			
		||||
 | 
			
		||||
msgid "In order to create a VM, you need to create/upload your SSH KEY first."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Um eine VM zu erstellen musst du zuerst einen SSH-Key erstellen / hochladen."
 | 
			
		||||
"Deine VM ist gleich bereit. Wir senden Dir eine Bestätigungsemail, sobald Du "
 | 
			
		||||
"auf sie zugreifen kannst."
 | 
			
		||||
 | 
			
		||||
msgid ""
 | 
			
		||||
"We could not find the requested VM. Please                            "
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -355,4 +355,20 @@
 | 
			
		|||
 | 
			
		||||
.no-cards a {
 | 
			
		||||
  color: #7ca3d0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.btn-plain {
 | 
			
		||||
  background: transparent;
 | 
			
		||||
  border: none;
 | 
			
		||||
  fill: #595959;
 | 
			
		||||
  color: #595959;
 | 
			
		||||
  outline: none;
 | 
			
		||||
}
 | 
			
		||||
.btn-plain:hover,
 | 
			
		||||
.btn-plain:focus,
 | 
			
		||||
.btn-plain:active,
 | 
			
		||||
.btn-plain:active:focus {
 | 
			
		||||
  outline: none;
 | 
			
		||||
  color: #999;
 | 
			
		||||
  fill: #999;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -580,9 +580,9 @@ a.unlink:hover {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
.dcl-place-order-text{
 | 
			
		||||
   font-size: 13px;
 | 
			
		||||
   /* font-size: 13px; */
 | 
			
		||||
   color: #808080;
 | 
			
		||||
   margin-bottom: 15px;
 | 
			
		||||
   /* margin-bottom: 15px; */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dcl-order-table-total .tbl-total {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,15 @@
 | 
			
		|||
.order-detail-container {padding-top: 70px; padding-bottom: 70px; margin-bottom: 70px;}
 | 
			
		||||
.order-detail-container {
 | 
			
		||||
    max-width: 600px;
 | 
			
		||||
    margin: 100px auto 40px;
 | 
			
		||||
    border: 1px solid #ccc;
 | 
			
		||||
    padding: 15px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media(min-width: 768px) {
 | 
			
		||||
    .order-detail-container {
 | 
			
		||||
        padding: 30px;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.order-detail-container .invoice-title h2, .invoice-title h3 {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
| 
						 | 
				
			
			@ -15,3 +26,67 @@
 | 
			
		|||
.order-detail-container .table > tbody > tr > .thick-line {
 | 
			
		||||
    border-top: 2px solid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.order-detail-container .dashboard-title-thin {
 | 
			
		||||
    margin-top: 0;
 | 
			
		||||
    margin-left: -3px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.order-detail-container .dashboard-title-thin .un-icon {
 | 
			
		||||
    margin-top: -6px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.order-detail-container .dashboard-container-head {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    padding: 0;
 | 
			
		||||
    margin-bottom: 38px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.order-detail-container .dashboard-container-options {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    top: 10px;
 | 
			
		||||
    right: 0;
 | 
			
		||||
}
 | 
			
		||||
.order-detail-container .dashboard-container-options .svg-img {
 | 
			
		||||
    height: 22px;
 | 
			
		||||
    width: 22px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.order-detail-container .order-details {
 | 
			
		||||
    margin-bottom: 30px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.order-detail-container .order-details strong {
 | 
			
		||||
    color: #595959;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.order-detail-container h4 {
 | 
			
		||||
    font-size: 16px;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    margin-bottom: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.order-detail-container p {
 | 
			
		||||
    margin-bottom: 5px;
 | 
			
		||||
    color: #595959;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.order-detail-container hr {
 | 
			
		||||
    margin: 15px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media (max-width: 767px) {
 | 
			
		||||
    .order-confirm-btn {
 | 
			
		||||
        text-align: center;
 | 
			
		||||
        margin-top: 10px;
 | 
			
		||||
    }
 | 
			
		||||
    .order-detail-container .dashboard-container-options {
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        top: 4px;
 | 
			
		||||
        right: -4px;
 | 
			
		||||
    }
 | 
			
		||||
    .order-detail-container .dashboard-container-options .svg-img {
 | 
			
		||||
        height: 16px;
 | 
			
		||||
        width: 16px;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										18
									
								
								hosting/static/hosting/img/icon-pdf.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								hosting/static/hosting/img/icon-pdf.svg
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,18 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<svg width="492px" height="649px" viewBox="0 0 492 649" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 | 
			
		||||
    <!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
 | 
			
		||||
    <title>icon-pdf</title>
 | 
			
		||||
    <desc>Created with Sketch.</desc>
 | 
			
		||||
    <defs></defs>
 | 
			
		||||
    <g id="Page-1" stroke="none" stroke-width="1" fill-rule="evenodd">
 | 
			
		||||
        <g id="icon-pdf" fill-rule="nonzero">
 | 
			
		||||
            <g id="Group" transform="translate(93.000000, 269.000000)">
 | 
			
		||||
                <path d="M98,47.8 C98,54.8 97,61.7 95.1,66.6 C93.1,72.5 90.1,76.5 86.2,80.5 C82.2,84.5 76.3,87.4 70.4,89.4 C64.5,91.4 55.6,92.3 46.6,92.3 L34.7,92.3 L34.7,134 L0,134 L0,0.3 L45.5,0.3 C54.4,0.3 62.4,1.3 69.3,3.2 C76.2,5.2 81.2,8.2 85.1,12.1 C89.1,16.1 92.1,21 94,27 C96.9,32 98,38.9 98,47.8 Z M61.3,46.8 C61.3,42.8 61.3,39.9 60.3,37.9 C60.3,35.9 59.3,33.9 57.4,32 C56.4,31 54.5,30 52.4,29.1 C50.4,29.1 47.4,28.1 44.5,28.1 L34.6,28.1 L34.6,63.7 L45.5,63.7 C48.4,63.7 50.4,63.7 52.5,62.7 C54.5,61.7 56.5,61.7 57.5,59.8 C58.5,57.8 59.5,56.9 60.4,54.8 C61.3,53.8 61.3,50.8 61.3,46.8 Z" id="Shape"></path>
 | 
			
		||||
                <path d="M214.8,66.6 C214.8,78.5 213.8,89.3 210.8,97.3 C208.8,106.2 204.9,113.1 199.9,118.1 C195,123.1 189,127 182.1,130 C175.2,132 167.3,134 157.3,134 L108.8,134 L108.8,0.3 L156.3,0.3 C166.2,0.3 175.1,1.3 182,4.3 C188.9,7.2 194.9,10.2 199.8,16.2 C204.8,21.2 207.7,28.1 209.7,37 C213.8,44.8 214.8,54.7 214.8,66.6 Z M178.1,65.6 C178.1,58.7 178.1,52.7 177.1,47.8 C176.1,42.8 175.1,39.9 174.2,36.9 C172.2,34 170.2,32.9 168.3,31.9 C165.4,30.9 162.4,30.9 158.4,30.9 L145.6,30.9 L145.6,103.2 L158.4,103.2 C162.4,103.2 165.4,103.2 168.3,102.2 C171.2,101.2 173.3,99.3 174.2,97.2 C176.2,94.3 177.1,91.3 178.2,86.3 C178.1,80.5 178.1,74.5 178.1,65.6 Z" id="Shape"></path>
 | 
			
		||||
                <polygon id="Shape" points="264.3 32 264.3 55.8 304.9 55.8 304.9 85.5 264.3 85.5 264.3 135 229.7 135 229.7 0.3 312.9 0.3 313.9 31 264.4 31 264.4 32"></polygon>
 | 
			
		||||
            </g>
 | 
			
		||||
            <path d="M491.3,649 L0.7,649 L0.7,0 L346.1,0 L491.3,145.2 L491.3,649 L491.3,649 Z M44.7,605 L448.4,605 L448.4,162.8 L327.4,42.9 L44.7,42.9 L44.7,605 Z" id="Shape"></path>
 | 
			
		||||
            <polygon id="Shape" points="469.3 176 315.3 176 315.3 20.9 359.3 20.9 359.3 132 469.3 132"></polygon>
 | 
			
		||||
        </g>
 | 
			
		||||
    </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 2.3 KiB  | 
							
								
								
									
										17
									
								
								hosting/static/hosting/img/icon-print.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								hosting/static/hosting/img/icon-print.svg
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<svg width="612px" height="612px" viewBox="0 0 612 612" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
 | 
			
		||||
    <!-- Generator: Sketch 46.2 (44496) - http://www.bohemiancoding.com/sketch -->
 | 
			
		||||
    <title>54471</title>
 | 
			
		||||
    <desc>Created with Sketch.</desc>
 | 
			
		||||
    <defs></defs>
 | 
			
		||||
    <g id="Page-1" stroke="none" stroke-width="1" fill-rule="evenodd">
 | 
			
		||||
        <g id="54471" fill-rule="nonzero">
 | 
			
		||||
            <path d="M0,225.633 L0,386.367 C0,417.272 30.6,417.272 30.6,417.272 L83.454,417.272 L83.454,389.454 L27.818,389.454 L27.818,222.545 L584.181,222.545 L584.181,389.454 L528.545,389.454 L528.545,417.272 L581.4,417.272 C581.4,417.272 612,417.272 612,386.367 L612,225.633 C612,225.633 612,194.727 581.4,194.727 L30.6,194.727 C0,194.728 0,225.633 0,225.633 Z" id="Shape"></path>
 | 
			
		||||
            <polygon id="Shape" points="500.728 166.909 500.728 0 111.273 0 111.273 166.909 139.091 166.909 139.091 27.818 472.909 27.818 472.909 166.909"></polygon>
 | 
			
		||||
            <path d="M528.546,292.091 C528.546,278.182 514.358,278.182 514.358,278.182 L97.642,278.182 C97.642,278.182 83.455,278.182 83.455,292.091 C83.455,306 97.642,306 97.642,306 L514.359,306 C514.358,306 528.546,306 528.546,292.091 Z" id="Shape"></path>
 | 
			
		||||
            <rect id="Rectangle-path" x="166.909" y="500.728" width="278.182" height="27.818"></rect>
 | 
			
		||||
            <path d="M500.728,612 L500.728,389.454 L111.273,389.454 L111.273,612 L500.728,612 Z M139.091,417.272 L472.909,417.272 L472.909,584.181 L139.091,584.181 L139.091,417.272 Z" id="Shape"></path>
 | 
			
		||||
            <rect id="Rectangle-path" x="166.909" y="445.091" width="278.182" height="27.818"></rect>
 | 
			
		||||
        </g>
 | 
			
		||||
    </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 1.7 KiB  | 
							
								
								
									
										387
									
								
								hosting/static/hosting/js/html2pdf.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										387
									
								
								hosting/static/hosting/js/html2pdf.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,387 @@
 | 
			
		|||
/**
 | 
			
		||||
 * @license
 | 
			
		||||
 *
 | 
			
		||||
 * MIT License
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2017 Erik Koopmans
 | 
			
		||||
 *
 | 
			
		||||
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
			
		||||
 * of this software and associated documentation files (the "Software"), to deal
 | 
			
		||||
 * in the Software without restriction, including without limitation the rights
 | 
			
		||||
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
			
		||||
 * copies of the Software, and to permit persons to whom the Software is
 | 
			
		||||
 * furnished to do so, subject to the following conditions:
 | 
			
		||||
 *
 | 
			
		||||
 * The above copyright notice and this permission notice shall be included in all
 | 
			
		||||
 * copies or substantial portions of the Software.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
			
		||||
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
			
		||||
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
			
		||||
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
			
		||||
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
			
		||||
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
			
		||||
 * SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Generate a PDF from an HTML element or string using html2canvas and jsPDF.
 | 
			
		||||
 *
 | 
			
		||||
 * @param {Element|string} source The source element or HTML string.
 | 
			
		||||
 * @param {Object=} opt An object of optional settings: 'margin', 'filename',
 | 
			
		||||
 *    'image' ('type' and 'quality'), and 'html2canvas' / 'jspdf', which are
 | 
			
		||||
 *    sent as settings to their corresponding functions.
 | 
			
		||||
 */
 | 
			
		||||
var html2pdf = (function(html2canvas, jsPDF) {
 | 
			
		||||
 | 
			
		||||
  /* ---------- MAIN FUNCTION ---------- */
 | 
			
		||||
 | 
			
		||||
  var html2pdf = function(source, opt) {
 | 
			
		||||
    // Handle input.
 | 
			
		||||
    opt = objType(opt) === 'object' ? opt : {};
 | 
			
		||||
    var source = html2pdf.parseInput(source, opt);
 | 
			
		||||
 | 
			
		||||
    // Determine the PDF page size.
 | 
			
		||||
    var pageSize = jsPDF.getPageSize(opt.jsPDF);
 | 
			
		||||
    pageSize.inner = {
 | 
			
		||||
      width:  pageSize.width - opt.margin[1] - opt.margin[3],
 | 
			
		||||
      height: pageSize.height - opt.margin[0] - opt.margin[2]
 | 
			
		||||
    };
 | 
			
		||||
    pageSize.inner.ratio = pageSize.inner.height / pageSize.inner.width;
 | 
			
		||||
 | 
			
		||||
    // Copy the source element into a PDF-styled container div.
 | 
			
		||||
    var container = html2pdf.makeContainer(source, pageSize);
 | 
			
		||||
    var overlay = container.parentElement;
 | 
			
		||||
 | 
			
		||||
    // Get the locations of all hyperlinks.
 | 
			
		||||
    if (opt.enableLinks) {
 | 
			
		||||
      // Find all anchor tags and get the container's bounds for reference.
 | 
			
		||||
      opt.links = [];
 | 
			
		||||
      var links = container.querySelectorAll('a');
 | 
			
		||||
      var containerRect = unitConvert(container.getBoundingClientRect(), pageSize.k);
 | 
			
		||||
 | 
			
		||||
      // Treat each client rect as a separate link (for text-wrapping).
 | 
			
		||||
      Array.prototype.forEach.call(links, function(link) {
 | 
			
		||||
        var clientRects = link.getClientRects();
 | 
			
		||||
        for (var i=0; i<clientRects.length; i++) {
 | 
			
		||||
          var clientRect = unitConvert(clientRects[i], pageSize.k);
 | 
			
		||||
          clientRect.left -= containerRect.left;
 | 
			
		||||
          clientRect.top -= containerRect.top;
 | 
			
		||||
          opt.links.push({ el: link, clientRect: clientRect });
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Render the canvas and pass the result to makePDF.
 | 
			
		||||
    var onRendered = opt.html2canvas.onrendered || function() {};
 | 
			
		||||
    opt.html2canvas.onrendered = function(canvas) {
 | 
			
		||||
      onRendered(canvas);
 | 
			
		||||
      document.body.removeChild(overlay);
 | 
			
		||||
      html2pdf.makePDF(canvas, pageSize, opt);
 | 
			
		||||
    }
 | 
			
		||||
    html2canvas(container, opt.html2canvas);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  html2pdf.parseInput = function(source, opt) {
 | 
			
		||||
    // Parse the opt object.
 | 
			
		||||
    opt.jsPDF = opt.jsPDF || {};
 | 
			
		||||
    opt.html2canvas = opt.html2canvas || {};
 | 
			
		||||
    opt.filename = opt.filename && objType(opt.filename) === 'string' ? opt.filename : 'file.pdf';
 | 
			
		||||
    opt.enableLinks = opt.hasOwnProperty('enableLinks') ? opt.enableLinks : true;
 | 
			
		||||
    opt.image = opt.image || {};
 | 
			
		||||
    opt.image.type = opt.image.type || 'jpeg';
 | 
			
		||||
    opt.image.quality = opt.image.quality || 0.95;
 | 
			
		||||
 | 
			
		||||
    // Parse the margin property of the opt object.
 | 
			
		||||
    switch (objType(opt.margin)) {
 | 
			
		||||
      case 'undefined':
 | 
			
		||||
        opt.margin = 0;
 | 
			
		||||
      case 'number':
 | 
			
		||||
        opt.margin = [opt.margin, opt.margin, opt.margin, opt.margin];
 | 
			
		||||
        break;
 | 
			
		||||
      case 'array':
 | 
			
		||||
        if (opt.margin.length === 2) {
 | 
			
		||||
          opt.margin = [opt.margin[0], opt.margin[1], opt.margin[0], opt.margin[1]];
 | 
			
		||||
        }
 | 
			
		||||
        if (opt.margin.length === 4) {
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
      default:
 | 
			
		||||
        throw 'Invalid margin array.';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Parse the source element/string.
 | 
			
		||||
    if (!source) {
 | 
			
		||||
      throw 'Missing source element or string.';
 | 
			
		||||
    } else if (objType(source) === 'string') {
 | 
			
		||||
      source = createElement('div', { innerHTML: source });
 | 
			
		||||
    } else if (objType(source) === 'element') {
 | 
			
		||||
      source = cloneNode(source, opt.html2canvas.javascriptEnabled);
 | 
			
		||||
    } else {
 | 
			
		||||
      throw 'Invalid source - please specify an HTML Element or string.';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Return the parsed input (opt is modified in-place, no need to return).
 | 
			
		||||
    return source;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  html2pdf.makeContainer = function(source, pageSize) {
 | 
			
		||||
    // Define the CSS styles for the container and its overlay parent.
 | 
			
		||||
    var overlayCSS = {
 | 
			
		||||
      position: 'fixed', overflow: 'hidden', zIndex: 1000,
 | 
			
		||||
      left: 0, right: 0, bottom: 0, top: 0,
 | 
			
		||||
      backgroundColor: 'rgba(0,0,0,0.8)'
 | 
			
		||||
    };
 | 
			
		||||
    var containerCSS = {
 | 
			
		||||
      position: 'absolute', width: pageSize.inner.width + pageSize.unit,
 | 
			
		||||
      left: 0, right: 0, top: 0, height: 'auto', margin: 'auto',
 | 
			
		||||
      backgroundColor: 'white'
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Set the overlay to hidden (could be changed in the future to provide a print preview).
 | 
			
		||||
    overlayCSS.opacity = 0;
 | 
			
		||||
 | 
			
		||||
    // Create and attach the elements.
 | 
			
		||||
    var overlay = createElement('div',   { className: 'html2pdf__overlay', style: overlayCSS });
 | 
			
		||||
    var container = createElement('div', { className: 'html2pdf__container', style: containerCSS });
 | 
			
		||||
    container.appendChild(source);
 | 
			
		||||
    overlay.appendChild(container);
 | 
			
		||||
    document.body.appendChild(overlay);
 | 
			
		||||
 | 
			
		||||
    // Enable page-breaks.
 | 
			
		||||
    var pageBreaks = source.querySelectorAll('.html2pdf__page-break');
 | 
			
		||||
    var pxPageHeight = pageSize.inner.height * pageSize.k / 72 * 96;
 | 
			
		||||
    Array.prototype.forEach.call(pageBreaks, function(el) {
 | 
			
		||||
      el.style.display = 'block';
 | 
			
		||||
      var clientRect = el.getBoundingClientRect();
 | 
			
		||||
      el.style.height = pxPageHeight - (clientRect.top % pxPageHeight) + 'px';
 | 
			
		||||
    }, this);
 | 
			
		||||
 | 
			
		||||
    // Return the container.
 | 
			
		||||
    return container;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  html2pdf.makePDF = function(canvas, pageSize, opt) {
 | 
			
		||||
    // Calculate the number of pages.
 | 
			
		||||
    var ctx = canvas.getContext('2d');
 | 
			
		||||
    var pxFullHeight = canvas.height;
 | 
			
		||||
    var pxPageHeight = Math.floor(canvas.width * pageSize.inner.ratio);
 | 
			
		||||
    var nPages = Math.ceil(pxFullHeight / pxPageHeight);
 | 
			
		||||
 | 
			
		||||
    // Create a one-page canvas to split up the full image.
 | 
			
		||||
    var pageCanvas = document.createElement('canvas');
 | 
			
		||||
    var pageCtx = pageCanvas.getContext('2d');
 | 
			
		||||
    var pageHeight = pageSize.inner.height;
 | 
			
		||||
    pageCanvas.width = canvas.width;
 | 
			
		||||
    pageCanvas.height = pxPageHeight;
 | 
			
		||||
 | 
			
		||||
    // Initialize the PDF.
 | 
			
		||||
    var pdf = new jsPDF(opt.jsPDF);
 | 
			
		||||
 | 
			
		||||
    for (var page=0; page<nPages; page++) {
 | 
			
		||||
      // Trim the final page to reduce file size.
 | 
			
		||||
      if (page === nPages-1) {
 | 
			
		||||
        pageCanvas.height = pxFullHeight % pxPageHeight;
 | 
			
		||||
        pageHeight = pageCanvas.height * pageSize.inner.width / pageCanvas.width;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Display the page.
 | 
			
		||||
      var w = pageCanvas.width;
 | 
			
		||||
      var h = pageCanvas.height;
 | 
			
		||||
      pageCtx.fillStyle = 'white';
 | 
			
		||||
      pageCtx.fillRect(0, 0, w, h);
 | 
			
		||||
      pageCtx.drawImage(canvas, 0, page*pxPageHeight, w, h, 0, 0, w, h);
 | 
			
		||||
 | 
			
		||||
      // Add the page to the PDF.
 | 
			
		||||
      if (page)  pdf.addPage();
 | 
			
		||||
      var imgData = pageCanvas.toDataURL('image/' + opt.image.type, opt.image.quality);
 | 
			
		||||
      pdf.addImage(imgData, opt.image.type, opt.margin[1], opt.margin[0],
 | 
			
		||||
                   pageSize.inner.width, pageHeight);
 | 
			
		||||
 | 
			
		||||
      // Add hyperlinks.
 | 
			
		||||
      if (opt.enableLinks) {
 | 
			
		||||
        var pageTop = page * pageSize.inner.height;
 | 
			
		||||
        opt.links.forEach(function(link) {
 | 
			
		||||
          if (link.clientRect.top > pageTop && link.clientRect.top < pageTop + pageSize.inner.height) {
 | 
			
		||||
            var left = opt.margin[1] + link.clientRect.left;
 | 
			
		||||
            var top = opt.margin[0] + link.clientRect.top - pageTop;
 | 
			
		||||
            pdf.link(left, top, link.clientRect.width, link.clientRect.height, { url: link.el.href });
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Finish the PDF.
 | 
			
		||||
    pdf.save( opt.filename );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  /* ---------- UTILS ---------- */
 | 
			
		||||
 | 
			
		||||
  // Determine the type of a variable/object.
 | 
			
		||||
  var objType = function(obj) {
 | 
			
		||||
    if (typeof obj === 'undefined')                             return 'undefined';
 | 
			
		||||
    else if (typeof obj === 'string' || obj instanceof String)  return 'string';
 | 
			
		||||
    else if (typeof obj === 'number' || obj instanceof Number)  return 'number';
 | 
			
		||||
    else if (!!obj && obj.constructor === Array)                return 'array';
 | 
			
		||||
    else if (obj && obj.nodeType === 1)                         return 'element';
 | 
			
		||||
    else if (typeof obj === 'object')                           return 'object';
 | 
			
		||||
    else                                                        return 'unknown';
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // Create an HTML element with optional className, innerHTML, and style.
 | 
			
		||||
  var createElement = function(tagName, opt) {
 | 
			
		||||
    var el = document.createElement(tagName);
 | 
			
		||||
    if (opt.className)  el.className = opt.className;
 | 
			
		||||
    if (opt.innerHTML) {
 | 
			
		||||
      el.innerHTML = opt.innerHTML;
 | 
			
		||||
      var scripts = el.getElementsByTagName('script');
 | 
			
		||||
      for (var i = scripts.length; i-- > 0; null) {
 | 
			
		||||
        scripts[i].parentNode.removeChild(scripts[i]);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    for (var key in opt.style) {
 | 
			
		||||
      el.style[key] = opt.style[key];
 | 
			
		||||
    }
 | 
			
		||||
    return el;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // Deep-clone a node and preserve contents/properties.
 | 
			
		||||
  var cloneNode = function(node, javascriptEnabled) {
 | 
			
		||||
    // Recursively clone the node.
 | 
			
		||||
    var clone = node.nodeType === 3 ? document.createTextNode(node.nodeValue) : node.cloneNode(false);
 | 
			
		||||
    for (var child = node.firstChild; child; child = child.nextSibling) {
 | 
			
		||||
      if (javascriptEnabled === true || child.nodeType !== 1 || child.nodeName !== 'SCRIPT') {
 | 
			
		||||
        clone.appendChild(cloneNode(child, javascriptEnabled));
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (node.nodeType === 1) {
 | 
			
		||||
      // Preserve contents/properties of special nodes.
 | 
			
		||||
      if (node.nodeName === 'CANVAS') {
 | 
			
		||||
        clone.width = node.width;
 | 
			
		||||
        clone.height = node.height;
 | 
			
		||||
        clone.getContext('2d').drawImage(node, 0, 0);
 | 
			
		||||
      } else if (node.nodeName === 'TEXTAREA' || node.nodeName === 'SELECT') {
 | 
			
		||||
        clone.value = node.value;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // Preserve the node's scroll position when it loads.
 | 
			
		||||
      clone.addEventListener('load', function() {
 | 
			
		||||
        clone.scrollTop = node.scrollTop;
 | 
			
		||||
        clone.scrollLeft = node.scrollLeft;
 | 
			
		||||
      }, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Return the cloned node.
 | 
			
		||||
    return clone;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Convert units using the conversion value 'k' from jsPDF.
 | 
			
		||||
  var unitConvert = function(obj, k) {
 | 
			
		||||
    var newObj = {};
 | 
			
		||||
    for (var key in obj) {
 | 
			
		||||
      newObj[key] = obj[key] * 72 / 96 / k;
 | 
			
		||||
    }
 | 
			
		||||
    return newObj;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // Get dimensions of a PDF page, as determined by jsPDF.
 | 
			
		||||
  jsPDF.getPageSize = function(orientation, unit, format) {
 | 
			
		||||
    // Decode options object
 | 
			
		||||
    if (typeof orientation === 'object') {
 | 
			
		||||
      var options = orientation;
 | 
			
		||||
      orientation = options.orientation;
 | 
			
		||||
      unit = options.unit || unit;
 | 
			
		||||
      format = options.format || format;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Default options
 | 
			
		||||
    unit        = unit || 'mm';
 | 
			
		||||
    format      = format || 'a4';
 | 
			
		||||
    orientation = ('' + (orientation || 'P')).toLowerCase();
 | 
			
		||||
    var format_as_string = ('' + format).toLowerCase();
 | 
			
		||||
 | 
			
		||||
    // Size in pt of various paper formats
 | 
			
		||||
    pageFormats = {
 | 
			
		||||
      'a0'  : [2383.94, 3370.39], 'a1'  : [1683.78, 2383.94],
 | 
			
		||||
      'a2'  : [1190.55, 1683.78], 'a3'  : [ 841.89, 1190.55],
 | 
			
		||||
      'a4'  : [ 595.28,  841.89], 'a5'  : [ 419.53,  595.28],
 | 
			
		||||
      'a6'  : [ 297.64,  419.53], 'a7'  : [ 209.76,  297.64],
 | 
			
		||||
      'a8'  : [ 147.40,  209.76], 'a9'  : [ 104.88,  147.40],
 | 
			
		||||
      'a10' : [  73.70,  104.88], 'b0'  : [2834.65, 4008.19],
 | 
			
		||||
      'b1'  : [2004.09, 2834.65], 'b2'  : [1417.32, 2004.09],
 | 
			
		||||
      'b3'  : [1000.63, 1417.32], 'b4'  : [ 708.66, 1000.63],
 | 
			
		||||
      'b5'  : [ 498.90,  708.66], 'b6'  : [ 354.33,  498.90],
 | 
			
		||||
      'b7'  : [ 249.45,  354.33], 'b8'  : [ 175.75,  249.45],
 | 
			
		||||
      'b9'  : [ 124.72,  175.75], 'b10' : [  87.87,  124.72],
 | 
			
		||||
      'c0'  : [2599.37, 3676.54], 'c1'  : [1836.85, 2599.37],
 | 
			
		||||
      'c2'  : [1298.27, 1836.85], 'c3'  : [ 918.43, 1298.27],
 | 
			
		||||
      'c4'  : [ 649.13,  918.43], 'c5'  : [ 459.21,  649.13],
 | 
			
		||||
      'c6'  : [ 323.15,  459.21], 'c7'  : [ 229.61,  323.15],
 | 
			
		||||
      'c8'  : [ 161.57,  229.61], 'c9'  : [ 113.39,  161.57],
 | 
			
		||||
      'c10' : [  79.37,  113.39], 'dl'  : [ 311.81,  623.62],
 | 
			
		||||
      'letter'            : [612,   792],
 | 
			
		||||
      'government-letter' : [576,   756],
 | 
			
		||||
      'legal'             : [612,  1008],
 | 
			
		||||
      'junior-legal'      : [576,   360],
 | 
			
		||||
      'ledger'            : [1224,  792],
 | 
			
		||||
      'tabloid'           : [792,  1224],
 | 
			
		||||
      'credit-card'       : [153,   243]
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Unit conversion
 | 
			
		||||
    switch (unit) {
 | 
			
		||||
      case 'pt':  k = 1;          break;
 | 
			
		||||
      case 'mm':  k = 72 / 25.4;  break;
 | 
			
		||||
      case 'cm':  k = 72 / 2.54;  break;
 | 
			
		||||
      case 'in':  k = 72;         break;
 | 
			
		||||
      case 'px':  k = 72 / 96;    break;
 | 
			
		||||
      case 'pc':  k = 12;         break;
 | 
			
		||||
      case 'em':  k = 12;         break;
 | 
			
		||||
      case 'ex':  k = 6;          break;
 | 
			
		||||
      default:
 | 
			
		||||
        throw ('Invalid unit: ' + unit);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Dimensions are stored as user units and converted to points on output
 | 
			
		||||
    if (pageFormats.hasOwnProperty(format_as_string)) {
 | 
			
		||||
      pageHeight = pageFormats[format_as_string][1] / k;
 | 
			
		||||
      pageWidth = pageFormats[format_as_string][0] / k;
 | 
			
		||||
    } else {
 | 
			
		||||
      try {
 | 
			
		||||
        pageHeight = format[1];
 | 
			
		||||
        pageWidth = format[0];
 | 
			
		||||
      } catch (err) {
 | 
			
		||||
        throw new Error('Invalid format: ' + format);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Handle page orientation
 | 
			
		||||
    if (orientation === 'p' || orientation === 'portrait') {
 | 
			
		||||
      orientation = 'p';
 | 
			
		||||
      if (pageWidth > pageHeight) {
 | 
			
		||||
        tmp = pageWidth;
 | 
			
		||||
        pageWidth = pageHeight;
 | 
			
		||||
        pageHeight = tmp;
 | 
			
		||||
      }
 | 
			
		||||
    } else if (orientation === 'l' || orientation === 'landscape') {
 | 
			
		||||
      orientation = 'l';
 | 
			
		||||
      if (pageHeight > pageWidth) {
 | 
			
		||||
        tmp = pageWidth;
 | 
			
		||||
        pageWidth = pageHeight;
 | 
			
		||||
        pageHeight = tmp;
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      throw('Invalid orientation: ' + orientation);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Return information (k is the unit conversion ratio from pts)
 | 
			
		||||
    var info = { 'width': pageWidth, 'height': pageHeight, 'unit': unit, 'k': k };
 | 
			
		||||
    return info;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  // Expose the html2pdf function.
 | 
			
		||||
  return html2pdf;
 | 
			
		||||
}(html2canvas, jsPDF));
 | 
			
		||||
							
								
								
									
										15
									
								
								hosting/static/hosting/js/order.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								hosting/static/hosting/js/order.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
$(document).ready(function() {
 | 
			
		||||
    $('.btn-pdf').click(function(e) {
 | 
			
		||||
        e.preventDefault();
 | 
			
		||||
        var $target = $($(this).attr('data-target')) || $('body');
 | 
			
		||||
        var fileName = $target.attr('id') + '.pdf';
 | 
			
		||||
        html2pdf($target[0], {
 | 
			
		||||
            filename: fileName,
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
    $('.btn-print').click(function(e) {
 | 
			
		||||
        e.preventDefault();
 | 
			
		||||
        console.log('a');
 | 
			
		||||
        window.print();
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
$(document).ready(function () {
 | 
			
		||||
    $('.modal-text').removeClass('hide');
 | 
			
		||||
    var create_vm_form = $('#virtual_machine_create_form');
 | 
			
		||||
    create_vm_form.submit(function () {
 | 
			
		||||
        $('#btn-create-vm').prop('disabled', true);
 | 
			
		||||
| 
						 | 
				
			
			@ -22,6 +23,7 @@ $(document).ready(function () {
 | 
			
		|||
                    fa_icon = $('.modal-icon > .fa');
 | 
			
		||||
                    fa_icon.attr('class', 'fa fa-times');
 | 
			
		||||
                    $('.modal-header > .close').attr('class', 'close');
 | 
			
		||||
                    $('.modal-text').addClass('hide');
 | 
			
		||||
                    if (typeof(create_vm_error_message) !== 'undefined') {
 | 
			
		||||
                        $('#createvm-modal-title').text(create_vm_error_message);
 | 
			
		||||
                    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -94,6 +94,13 @@
 | 
			
		|||
    <!-- Init JavaScript -->
 | 
			
		||||
    <script src="{% static 'hosting/js/initial.js' %}"></script>
 | 
			
		||||
 | 
			
		||||
    {% block js_extra %}
 | 
			
		||||
        {% comment %}
 | 
			
		||||
            this block is above some files, because on stripe error scripts below the stripe
 | 
			
		||||
            script are not properly executed.
 | 
			
		||||
        {% endcomment %}
 | 
			
		||||
    {% endblock js_extra %}
 | 
			
		||||
 | 
			
		||||
    <script src="https://js.stripe.com/v3/"></script>
 | 
			
		||||
    <script src="https://js.stripe.com/v2/"></script>
 | 
			
		||||
    <!-- Stripe Lib -->
 | 
			
		||||
| 
						 | 
				
			
			@ -108,8 +115,6 @@
 | 
			
		|||
    <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
 | 
			
		||||
    <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment-with-locales.js"></script>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,206 +4,189 @@
 | 
			
		|||
{% load custom_tags %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
 | 
			
		||||
<div class="order-detail-container">
 | 
			
		||||
<div id="order-detail{{order.pk}}" class="order-detail-container">
 | 
			
		||||
    {% if messages %}
 | 
			
		||||
    <div class="row">
 | 
			
		||||
        <div class="col-xs-12 col-md-8 col-md-offset-2">
 | 
			
		||||
            <br/>
 | 
			
		||||
            <div class="alert alert-warning">
 | 
			
		||||
                {% for message in messages %}
 | 
			
		||||
        <div class="alert alert-warning">
 | 
			
		||||
            {% for message in messages %}
 | 
			
		||||
                <span>{{ message }}</span>
 | 
			
		||||
                {% endfor %}
 | 
			
		||||
            </div>
 | 
			
		||||
            {% endfor %}
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
    {% if not error %}
 | 
			
		||||
    <div class="row">
 | 
			
		||||
        <div class="col-xs-12 col-md-8 col-md-offset-2">
 | 
			
		||||
            <div class="invoice-title">
 | 
			
		||||
                <h2>{{page_header_text}}</h2>
 | 
			
		||||
                <h3 class="pull-right">
 | 
			
		||||
        <div class="dashboard-container-head">
 | 
			
		||||
            <h1 class="dashboard-title-thin">
 | 
			
		||||
                <img src="{% static 'hosting/img/billing.svg' %}" class="un-icon">{% blocktrans with page_header_text=page_header_text|default:"Invoice" %}{{page_header_text}}{% endblocktrans %}
 | 
			
		||||
            </h1>
 | 
			
		||||
            <div class="dashboard-container-options">
 | 
			
		||||
                <button type="button" class="btn-plain btn-pdf" data-target="#order-detail{{order.pk}}"><img src="{% static 'hosting/img/icon-pdf.svg' %}" class="svg-img"></button>
 | 
			
		||||
                <button type="button" class="btn-plain btn-print"><img src="{% static 'hosting/img/icon-print.svg' %}" class="svg-img"></button>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="order-details">
 | 
			
		||||
            {% if order %}
 | 
			
		||||
                <p>
 | 
			
		||||
                    <strong>{% trans "Order #" %} {{order.id}}</strong>
 | 
			
		||||
                </p>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
            <p>
 | 
			
		||||
                <strong>{% trans "Invoice Date" %}:</strong>
 | 
			
		||||
                <span id="order-created_at">
 | 
			
		||||
                    {% if order %}
 | 
			
		||||
                    {% trans "Order #"%} {{order.id}}
 | 
			
		||||
                        {{order.created_at|date:'Y-m-d H:i'}}
 | 
			
		||||
                    {% else %}
 | 
			
		||||
                        {% now "Y-m-d H:i" %}
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                </h3>
 | 
			
		||||
                </span>
 | 
			
		||||
            </p>
 | 
			
		||||
            {% if order %}
 | 
			
		||||
                <p>
 | 
			
		||||
                    <strong>{% trans "Status" %}: </strong>
 | 
			
		||||
                    <strong>
 | 
			
		||||
                        {% if order.status == 'Approved' %}
 | 
			
		||||
                            <span class="vm-color-online">{% trans "Approved" %}</span>
 | 
			
		||||
                        {% else %}
 | 
			
		||||
                            <span class="vm-status-failed">{% trans "Declined" %}</span>
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                    </strong>
 | 
			
		||||
                </p>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
            <hr>
 | 
			
		||||
            <div>
 | 
			
		||||
                <address>
 | 
			
		||||
                    <h4>{% trans "Billed to" %}:</h4>
 | 
			
		||||
                    <p>
 | 
			
		||||
                        {% if order %}
 | 
			
		||||
                            {{user.name}}<br>
 | 
			
		||||
                            {{order.billing_address.street_address}}, {{order.billing_address.postal_code}}<br>
 | 
			
		||||
                            {{order.billing_address.city}}, {{order.billing_address.country}}
 | 
			
		||||
                        {% else %}
 | 
			
		||||
                            {% with request.session.billing_address_data as billing_address %}
 | 
			
		||||
                                {{billing_address.cardholder_name}}<br>
 | 
			
		||||
                                {{billing_address.street_address}}, {{billing_address.postal_code}}<br>
 | 
			
		||||
                                {{billing_address.city}}, {{billing_address.country}}
 | 
			
		||||
                            {% endwith %}
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                    </p>
 | 
			
		||||
                </address>
 | 
			
		||||
            </div>
 | 
			
		||||
            <hr>
 | 
			
		||||
            <div class="row">
 | 
			
		||||
                <div class="col-xs-12 col-md-6 pull-right order-confirm-date">
 | 
			
		||||
                    <address>
 | 
			
		||||
                        <strong>{% trans "Date"%}:</strong><br>
 | 
			
		||||
                        <span id="order-created_at">
 | 
			
		||||
                                {% if order %}
 | 
			
		||||
                                    {{order.created_at|date:'Y-m-d H:i'}}
 | 
			
		||||
                                {% else %}
 | 
			
		||||
                                    {% now "Y-m-d H:i" %}
 | 
			
		||||
                                {% endif %}
 | 
			
		||||
                            </span><br><br>
 | 
			
		||||
                        {% if order %}
 | 
			
		||||
                        <strong>{% trans "Status:"%}</strong><br>
 | 
			
		||||
                        {% if order.status == 'Approved' %}
 | 
			
		||||
                        <strong class="text-success">
 | 
			
		||||
                            {% trans "Approved" %}
 | 
			
		||||
                        </strong>
 | 
			
		||||
                        {% else %}
 | 
			
		||||
                        <strong class="text-danger">
 | 
			
		||||
                            {% trans "Declined" %}
 | 
			
		||||
                        </strong>
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                        <br><br>
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                    </address>
 | 
			
		||||
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="col-xs-12 col-md-6">
 | 
			
		||||
                    <address>
 | 
			
		||||
                        <h3><b>{% trans "Billed To:"%}</b></h3>
 | 
			
		||||
                        {% if order %}
 | 
			
		||||
                        {{user.name}}<br>
 | 
			
		||||
                        {{order.billing_address.street_address}},{{order.billing_address.postal_code}}<br>
 | 
			
		||||
                        {{order.billing_address.city}},
 | 
			
		||||
                        {{order.billing_address.country}}.
 | 
			
		||||
                        {% else %}
 | 
			
		||||
                        {% with request.session.billing_address_data as billing_address %}
 | 
			
		||||
                        {{billing_address|get_value_from_dict:'cardholder_name'}}<br>
 | 
			
		||||
                        {{billing_address|get_value_from_dict:'street_address'}},
 | 
			
		||||
                        {{billing_address|get_value_from_dict:'postal_code'}}<br>
 | 
			
		||||
                        {{billing_address|get_value_from_dict:'city'}},
 | 
			
		||||
                        {{billing_address|get_value_from_dict:'country'}}.
 | 
			
		||||
                        {% endwith %}
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                    </address>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="row">
 | 
			
		||||
                <div class="col-xs-6">
 | 
			
		||||
                    <address>
 | 
			
		||||
                        <strong>{% trans "Payment Method:"%}</strong><br>
 | 
			
		||||
                        {% if order %}
 | 
			
		||||
            <div>
 | 
			
		||||
                <h4>{% trans "Payment method" %}:</h4>
 | 
			
		||||
                <p>
 | 
			
		||||
                    {% if order %}
 | 
			
		||||
                        {{order.cc_brand}} {% trans "ending in" %} ****
 | 
			
		||||
                        {{order.last4}}<br>
 | 
			
		||||
                        {{user.email}}
 | 
			
		||||
                        {% else %}
 | 
			
		||||
                        {{cc_brand}} {% trans "ending in" %} ****
 | 
			
		||||
                    {% else %}
 | 
			
		||||
                        {{cc_brand|default:'Card'}} {% trans "ending in" %} ****
 | 
			
		||||
                        {{cc_last4}}<br>
 | 
			
		||||
                        {{request.session.user.email}}
 | 
			
		||||
                        {% if request.user.is_authenticated %}
 | 
			
		||||
                            {{request.user.email}}
 | 
			
		||||
                        {% else %}
 | 
			
		||||
                            {{request.session.user.email}}
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                    </address>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                </p>
 | 
			
		||||
            </div>
 | 
			
		||||
            <hr>
 | 
			
		||||
            <div>
 | 
			
		||||
                <h4>{% trans "Order summary" %}</h4>
 | 
			
		||||
                <p>
 | 
			
		||||
                    <strong>{% trans "Product" %}:</strong> {{vm.name}}
 | 
			
		||||
                </p>
 | 
			
		||||
                <div class="row">
 | 
			
		||||
                    <div class="col-sm-6">
 | 
			
		||||
                        {% comment %}
 | 
			
		||||
                        <p>
 | 
			
		||||
                            <span>{% trans "Period" %}</span>
 | 
			
		||||
                            <span class="pull-right">{{}}</span>
 | 
			
		||||
                        </p>
 | 
			
		||||
                        {% endcomment %}
 | 
			
		||||
                        <p>
 | 
			
		||||
                            <span>{% trans "Cores" %}</span>
 | 
			
		||||
                            {% if vm.cores %}
 | 
			
		||||
                                <span class="pull-right">{{vm.cores|floatformat}}</span>
 | 
			
		||||
                            {% else %}
 | 
			
		||||
                                <span class="pull-right">{{vm.cpu|floatformat}}</span>
 | 
			
		||||
                            {% endif %}
 | 
			
		||||
                        </p>
 | 
			
		||||
                        <p>
 | 
			
		||||
                            <span>{% trans "Memory" %}</span>
 | 
			
		||||
                            <span class="pull-right">{{vm.memory}} GB</span>
 | 
			
		||||
                        </p>
 | 
			
		||||
                        <p>
 | 
			
		||||
                            <span>{% trans "Disk space" %}</span>
 | 
			
		||||
                            <span class="pull-right">{{vm.disk_size}} GB</span>
 | 
			
		||||
                        </p>
 | 
			
		||||
                        <p>
 | 
			
		||||
                            <span>{% trans "Total" %}</span>
 | 
			
		||||
                            <span class="pull-right">{{vm.price}} CHF</span>
 | 
			
		||||
                        </p>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="row">
 | 
			
		||||
        <div class="col-md-8 col-md-offset-2">
 | 
			
		||||
            <h3><b>{% trans "Order summary"%}</b></h3>
 | 
			
		||||
            <hr>
 | 
			
		||||
            <div class="content">
 | 
			
		||||
                {% if request.session.specs %}
 | 
			
		||||
                {% with request.session.specs as vm %}
 | 
			
		||||
                <p><b>{% trans "Cores"%}</b>
 | 
			
		||||
                    <span class="pull-right">{{vm.cpu}}</span>
 | 
			
		||||
                </p>
 | 
			
		||||
                <hr>
 | 
			
		||||
                <p><b>{% trans "Memory"%}</b>
 | 
			
		||||
                    <span class="pull-right">{{vm.memory}} GB</span>
 | 
			
		||||
                </p>
 | 
			
		||||
                <hr>
 | 
			
		||||
                <p><b>{% trans "Disk space"%}</b>
 | 
			
		||||
                    <span class="pull-right">{{vm.disk_size}} GB</span>
 | 
			
		||||
                </p>
 | 
			
		||||
                <hr>
 | 
			
		||||
                <p><b>{% trans "Configuration"%}</b>
 | 
			
		||||
                    <span class="pull-right">{{request.session.template.name}}</span>
 | 
			
		||||
                </p>
 | 
			
		||||
                <hr>
 | 
			
		||||
                <h4>{% trans "Total"%}
 | 
			
		||||
                    <p class="pull-right">
 | 
			
		||||
                        <b>{{vm.price}} CHF</b>
 | 
			
		||||
                        <span class="dcl-price-month"> /{% trans "Month" %}
 | 
			
		||||
                                </span>
 | 
			
		||||
                    </p>
 | 
			
		||||
                </h4>
 | 
			
		||||
                {% endwith %}
 | 
			
		||||
                {% else %}
 | 
			
		||||
                <p><b>{% trans "Cores"%}</b>
 | 
			
		||||
                    <span class="pull-right">{{vm.cores}}</span>
 | 
			
		||||
                </p>
 | 
			
		||||
                <hr>
 | 
			
		||||
                <p><b>{% trans "Memory"%}</b>
 | 
			
		||||
                    <span class="pull-right">{{vm.memory}} GB</span>
 | 
			
		||||
                </p>
 | 
			
		||||
                <hr>
 | 
			
		||||
                <p><b>{% trans "Disk space"%}</b>
 | 
			
		||||
                    <span class="pull-right">{{vm.disk_size}} GB</span>
 | 
			
		||||
                </p>
 | 
			
		||||
                <hr>
 | 
			
		||||
                <h4>{% trans "Total"%}<p class="pull-right"><b>{{vm.price}}
 | 
			
		||||
                    CHF</b><span
 | 
			
		||||
                        class="dcl-price-month"> /{% trans "Month" %}</span>
 | 
			
		||||
                </p></h4>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
            </div>
 | 
			
		||||
            <br/>
 | 
			
		||||
            {% if not order %}
 | 
			
		||||
                <hr>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </div>
 | 
			
		||||
        {% if not order %}
 | 
			
		||||
            <form method="post" id="virtual_machine_create_form">
 | 
			
		||||
                {% csrf_token %}
 | 
			
		||||
                <div class="row">
 | 
			
		||||
                    <div class="col-sm-8">
 | 
			
		||||
                        <p class="dcl-place-order-text">{% blocktrans with vm_price=request.session.specs.price %}By clicking "Place order" this plan will charge your credit card account with the fee of {{ vm_price }}CHF/month{% endblocktrans %}.</p>
 | 
			
		||||
                        <div class="dcl-place-order-text">{% blocktrans with vm_price=request.session.specs.price %}By clicking "Place order" this plan will charge your credit card account with the fee of {{ vm_price }}CHF/month{% endblocktrans %}.</div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="col-sm-4 content">
 | 
			
		||||
                        <button class="btn btn-info pull-right"
 | 
			
		||||
                                id="btn-create-vm"
 | 
			
		||||
                                data-href="{% url 'hosting:order-confirmation' %}"
 | 
			
		||||
                                data-toggle="modal"
 | 
			
		||||
                                data-target="#createvm-modal">
 | 
			
		||||
                            {% trans "Place order"%}
 | 
			
		||||
                    <div class="col-sm-4 order-confirm-btn text-right">
 | 
			
		||||
                        <button class="btn choice-btn" id="btn-create-vm" data-href="{% url 'hosting:order-confirmation' %}" data-toggle="modal" data-target="#createvm-modal">
 | 
			
		||||
                            {% trans "Place order" %}
 | 
			
		||||
                        </button>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </form>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    {% endif %}
 | 
			
		||||
</div>
 | 
			
		||||
<!-- Create VM Modal -->
 | 
			
		||||
<div class="modal fade" id="createvm-modal" tabindex="-1" role="dialog"
 | 
			
		||||
     aria-hidden="true" data-backdrop="static" data-keyboard="false">
 | 
			
		||||
    <div class="modal-dialog">
 | 
			
		||||
        <div class="modal-content">
 | 
			
		||||
            <div class="modal-header">
 | 
			
		||||
                <button type="button" class="close hidden" data-dismiss="modal"
 | 
			
		||||
                        aria-label="create-vm-close">
 | 
			
		||||
                    <span aria-hidden="true">×</span>
 | 
			
		||||
                </button>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="modal-body">
 | 
			
		||||
                <div class="modal-icon">
 | 
			
		||||
                    <i class="fa fa-cog fa-spin fa-3x fa-fw"></i>
 | 
			
		||||
                    <span class="sr-only">{% trans "Processing..." %}</span>
 | 
			
		||||
 | 
			
		||||
{% if order %}
 | 
			
		||||
    <div class="text-center" style="margin-bottom: 50px;">
 | 
			
		||||
        <a class="btn btn-vm-back" href="{% url 'hosting:orders' %}">{% trans "BACK TO LIST" %}</a>
 | 
			
		||||
    </div>
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
{% if not order %}
 | 
			
		||||
    <!-- Create VM Modal -->
 | 
			
		||||
    <div class="modal fade" id="createvm-modal" tabindex="-1" role="dialog"
 | 
			
		||||
         aria-hidden="true" data-backdrop="static" data-keyboard="false">
 | 
			
		||||
        <div class="modal-dialog">
 | 
			
		||||
            <div class="modal-content">
 | 
			
		||||
                <div class="modal-header">
 | 
			
		||||
                    <button type="button" class="close hidden" data-dismiss="modal"
 | 
			
		||||
                            aria-label="create-vm-close">
 | 
			
		||||
                        <span aria-hidden="true">×</span>
 | 
			
		||||
                    </button>
 | 
			
		||||
                </div>
 | 
			
		||||
                <h4 class="modal-title" id="createvm-modal-title">
 | 
			
		||||
                </h4>
 | 
			
		||||
                <div class="modal-text" id="createvm-modal-body">
 | 
			
		||||
                    {% trans "Hold tight, we are processing your request" %}
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="modal-footer">
 | 
			
		||||
                <div class="modal-body">
 | 
			
		||||
                    <div class="modal-icon">
 | 
			
		||||
                        <i class="fa fa-cog fa-spin fa-3x fa-fw"></i>
 | 
			
		||||
                        <span class="sr-only">{% trans "Processing..." %}</span>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <h4 class="modal-title" id="createvm-modal-title">
 | 
			
		||||
                    </h4>
 | 
			
		||||
                    <div class="modal-text" id="createvm-modal-body">
 | 
			
		||||
                        {% trans "Hold tight, we are processing your request" %}
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="modal-footer">
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
<!-- / Create VM Modal -->
 | 
			
		||||
 | 
			
		||||
    <!-- / Create VM Modal -->
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
<script type="text/javascript">
 | 
			
		||||
    {% trans "Some problem encountered. Please try again later." as err_msg %}
 | 
			
		||||
    var create_vm_error_message = '{{err_msg|safe}}.';
 | 
			
		||||
    var create_vm_error_message = '{{err_msg|safe}}';
 | 
			
		||||
 | 
			
		||||
    window.onload = function () {
 | 
			
		||||
        var locale_date = moment.utc(document.getElementById("order-created_at").textContent, 'YYYY-MM-DD HH:mm').toDate();
 | 
			
		||||
| 
						 | 
				
			
			@ -211,7 +194,12 @@
 | 
			
		|||
        document.getElementById('order-created_at').innerHTML = locale_date;
 | 
			
		||||
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
</script>
 | 
			
		||||
{%endblock%}
 | 
			
		||||
 | 
			
		||||
{% block js_extra %}
 | 
			
		||||
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.5/jspdf.min.js"></script>
 | 
			
		||||
    <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>
 | 
			
		||||
    <script src="{% static 'hosting/js/html2pdf.js' %}"></script>
 | 
			
		||||
    <script src="{% static 'hosting/js/order.js' %}"></script>
 | 
			
		||||
{% endblock js_extra %}
 | 
			
		||||
| 
						 | 
				
			
			@ -41,13 +41,15 @@
 | 
			
		|||
                        <td data-header="IPv6">{{vm.ipv6}}</td>
 | 
			
		||||
                    {% endif %}
 | 
			
		||||
                    <td data-header="{% trans 'Status' %}">
 | 
			
		||||
                        {% if vm.state == 'ACTIVE' %}
 | 
			
		||||
                            <span class="vm-status-active"><strong>{{vm.state|title}}</strong></span>
 | 
			
		||||
                        {% elif  vm.state == 'FAILED' %}
 | 
			
		||||
                            <span class="vm-status-failed"><strong>{{vm.state|title}}</strong></span>
 | 
			
		||||
                        {% else %}
 | 
			
		||||
                            <span class="vm-status"><strong>{{vm.state|title}}</strong></span>
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                        <strong>
 | 
			
		||||
                            {% if vm.state == 'ACTIVE' %}
 | 
			
		||||
                                <span class="vm-status-active">{{vm.state|title}}</span>
 | 
			
		||||
                            {% elif  vm.state == 'FAILED' %}
 | 
			
		||||
                                <span class="vm-status-failed">{{vm.state|title}}</span>
 | 
			
		||||
                            {% else %}
 | 
			
		||||
                                <span class="vm-status">{{vm.state|title}}</span>
 | 
			
		||||
                            {% endif %}
 | 
			
		||||
                        </strong>
 | 
			
		||||
                    </td>
 | 
			
		||||
                    <td class="text-right last-td">
 | 
			
		||||
                        <a class="btn btn-vm-detail" href="{% url 'hosting:virtual_machines' vm.vm_id %}">{% trans "View Detail" %}</a>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -645,7 +645,7 @@ class OrdersHostingDetailView(LoginRequiredMixin,
 | 
			
		|||
    model = HostingOrder
 | 
			
		||||
 | 
			
		||||
    def get_object(self):
 | 
			
		||||
        return HostingOrder.objects.filter(
 | 
			
		||||
        return HostingOrder.objects.get(
 | 
			
		||||
            pk=self.kwargs.get('pk')) if self.kwargs.get('pk') else None
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
| 
						 | 
				
			
			@ -653,54 +653,79 @@ class OrdersHostingDetailView(LoginRequiredMixin,
 | 
			
		|||
        context = super(DetailView, self).get_context_data(**kwargs)
 | 
			
		||||
        obj = self.get_object()
 | 
			
		||||
        owner = self.request.user
 | 
			
		||||
        if 'specs' not in self.request.session:
 | 
			
		||||
            return HttpResponseRedirect(
 | 
			
		||||
                reverse('hosting:create_virtual_machine'))
 | 
			
		||||
        if 'token' not in self.request.session:
 | 
			
		||||
            return HttpResponseRedirect(reverse('hosting:payment'))
 | 
			
		||||
        stripe_customer_id = self.request.session.get('customer')
 | 
			
		||||
        customer = StripeCustomer.objects.filter(id=stripe_customer_id).first()
 | 
			
		||||
        stripe_utils = StripeUtils()
 | 
			
		||||
        card_details = stripe_utils.get_card_details(customer.stripe_id,
 | 
			
		||||
                                                     self.request.session.get(
 | 
			
		||||
                                                         'token'))
 | 
			
		||||
        if not card_details.get('response_object'):
 | 
			
		||||
            msg = card_details.get('error')
 | 
			
		||||
            messages.add_message(self.request, messages.ERROR, msg,
 | 
			
		||||
                                 extra_tags='failed_payment')
 | 
			
		||||
            return HttpResponseRedirect(
 | 
			
		||||
                reverse('hosting:payment') + '#payment_error')
 | 
			
		||||
        if customer:
 | 
			
		||||
            card_details = stripe_utils.get_card_details(
 | 
			
		||||
                customer.stripe_id,
 | 
			
		||||
                self.request.session.get('token')
 | 
			
		||||
            )
 | 
			
		||||
        else:
 | 
			
		||||
            card_details = {}
 | 
			
		||||
 | 
			
		||||
        if self.request.GET.get('page', '') == 'payment':
 | 
			
		||||
        if self.request.GET.get('page') == 'payment':
 | 
			
		||||
            context['page_header_text'] = _('Confirm Order')
 | 
			
		||||
        else:
 | 
			
		||||
            context['page_header_text'] = _('Invoice')
 | 
			
		||||
 | 
			
		||||
        if obj is not None:
 | 
			
		||||
            # invoice for previous order
 | 
			
		||||
            try:
 | 
			
		||||
                manager = OpenNebulaManager(email=owner.email,
 | 
			
		||||
                                            password=owner.password)
 | 
			
		||||
                manager = OpenNebulaManager(
 | 
			
		||||
                    email=owner.email, password=owner.password
 | 
			
		||||
                )
 | 
			
		||||
                vm = manager.get_vm(obj.vm_id)
 | 
			
		||||
                context['vm'] = VirtualMachineSerializer(vm).data
 | 
			
		||||
            except WrongIdError:
 | 
			
		||||
                messages.error(self.request,
 | 
			
		||||
                               'The VM you are looking for is unavailable at the moment. \
 | 
			
		||||
                                Please contact Data Center Light support.'
 | 
			
		||||
                               )
 | 
			
		||||
                messages.error(
 | 
			
		||||
                    self.request,
 | 
			
		||||
                    _('The VM you are looking for is unavailable at the '
 | 
			
		||||
                      'moment. Please contact Data Center Light support.')
 | 
			
		||||
                )
 | 
			
		||||
                self.kwargs['error'] = 'WrongIdError'
 | 
			
		||||
                context['error'] = 'WrongIdError'
 | 
			
		||||
            except ConnectionRefusedError:
 | 
			
		||||
                messages.error(self.request,
 | 
			
		||||
                               'In order to create a VM, you need to create/upload your SSH KEY first.'
 | 
			
		||||
                               )
 | 
			
		||||
                messages.error(
 | 
			
		||||
                    self.request,
 | 
			
		||||
                    _('In order to create a VM, you need to create/upload '
 | 
			
		||||
                      'your SSH KEY first.')
 | 
			
		||||
                )
 | 
			
		||||
        elif not card_details.get('response_object'):
 | 
			
		||||
            # new order, failed to get card details
 | 
			
		||||
            context['failed_payment'] = True
 | 
			
		||||
            context['card_details'] = card_details
 | 
			
		||||
        else:
 | 
			
		||||
            # new order, confirm payment
 | 
			
		||||
            context['site_url'] = reverse('hosting:create_virtual_machine')
 | 
			
		||||
            context['cc_last4'] = card_details.get('response_object').get(
 | 
			
		||||
                'last4')
 | 
			
		||||
            context['cc_brand'] = card_details.get('response_object').get(
 | 
			
		||||
                'cc_brand')
 | 
			
		||||
            context['vm'] = self.request.session.get('specs')
 | 
			
		||||
        return context
 | 
			
		||||
 | 
			
		||||
    def get(self, request, *args, **kwargs):
 | 
			
		||||
        if not self.kwargs.get('pk'):
 | 
			
		||||
            if 'specs' not in self.request.session:
 | 
			
		||||
                return HttpResponseRedirect(
 | 
			
		||||
                    reverse('hosting:create_virtual_machine')
 | 
			
		||||
                )
 | 
			
		||||
            if 'token' not in self.request.session:
 | 
			
		||||
                return HttpResponseRedirect(reverse('hosting:payment'))
 | 
			
		||||
        self.object = self.get_object()
 | 
			
		||||
        context = self.get_context_data(object=self.object)
 | 
			
		||||
        if 'failed_payment' in context:
 | 
			
		||||
            msg = context['card_details'].get('error')
 | 
			
		||||
            messages.add_message(
 | 
			
		||||
                self.request, messages.ERROR, msg,
 | 
			
		||||
                extra_tags='failed_payment'
 | 
			
		||||
            )
 | 
			
		||||
            return HttpResponseRedirect(
 | 
			
		||||
                reverse('hosting:payment') + '#payment_error'
 | 
			
		||||
            )
 | 
			
		||||
        return self.render_to_response(context)
 | 
			
		||||
 | 
			
		||||
    def post(self, request):
 | 
			
		||||
        template = request.session.get('template')
 | 
			
		||||
        specs = request.session.get('specs')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue