v1.7 RC.1

This commit is contained in:
carodej
2020-07-20 16:03:39 +02:00
parent 6f95fc2565
commit b67297f160
22 changed files with 766 additions and 320 deletions

133
README.md
View File

@@ -2,18 +2,29 @@
## Contents
- [Server Requirements](#server-requirements)
- [Installation](#installation)
- [Installation Failed](#installation-failed)
- [Update VueFileManager](#update-vuefilemanager)
- [For Developers](#for-developers)
- [Supported Storages](#supported-storages)
- [How to Create New Language](#how-to-create-new-language)
- [Changelog](#changelog)
- [GitHub Repository](#github-repository)
- [Support](#support)
- [Security Vulnerabilities](#security-vulnerabilities)
- [Server Requirements](#server-requirements)
- [Installation](#installation)
- [PHP Configuration](#php-configuration)
- [Nginx Configuration](#nginx-configuration)
- [Apache Configuration](#apache-configuration)
- [Recover Failed Installation](#installation-failed)
- [Update VueFileManager from 1.6.x to 1.7 ](#update-vuefilemanager)
- [Payments](#payments)
- [Get your active plans](#get-your-active-plans)
- [Manage Failed Payments](#manage-failed-payments)
- [Technical Informations](#technical-informations)
- [For Developers](#for-developers)
- [Supported Storages](#supported-storages)
- [How to Create New Language](#how-to-create-new-language)
- [Others](#others)
- [Changelog](#changelog)
- [GitHub Repository](#github-repository)
- [Support](#support)
- [Security Vulnerabilities](#security-vulnerabilities)
# Installation
## Server Requirements
@@ -54,6 +65,77 @@ At first step you have to verify your purchase code. **Subscription service with
That was the hardest part of installation proces. Please follow instructions in every step of Setup Wizard to successfully install VueFileManager.
## PHP Configuration
There are several PHP settings good to know to setup before you try upload any file. Please set these values in your php.ini, we provide minimal setup for you. When you set `-1` then you set infinity limits.
```
memory_limit = 512M
upload_max_filesize = 1024M
post_max_size = 1024M
max_file_uploads = 50
```
## Nginx Configuration
If you running VueFileManager undex Nginx, don't forget set this value in your `nginx.conf` file:
```
http {
client_max_body_size 1024M;
}
```
And example Nginx config for your domain:
```
server {
listen 80;
listen [::]:80;
# Log files for Debugging
access_log /var/log/nginx/laravel-access.log;
error_log /var/log/nginx/laravel-error.log;
# Webroot Directory for Laravel project
root /var/www/vuefilemanager/public;
index index.php index.html index.htm;
# Your Domain Name
server_name example.com;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# PHP-FPM Configuration Nginx
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.3-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
```
## Apache Configuration
Make sure you have enabled mod_rewrite. There is an example config for running VueFileManager under apache:
```
<VirtualHost example.com:80>
DocumentRoot /var/www/vuefilemanager/public
ServerName example.com
<Directory "/var/www/vuefilemanager/public">
AllowOverride All
allow from all
Options +Indexes
Require all granted
</Directory>
RewriteEngine on
RewriteCond %{SERVER_NAME} =example.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
```
## Installation Failed
What to do when installation fail and you can't continue, at first, try to fix issue why installation fail. Probably missing PHP extension or permissions wasn't set correctly.
@@ -62,14 +144,40 @@ At worst scenarios, to reset Setup Wizard, delete all tables in your previously
After these steps, installation will be reseted.
## Update VueFileManager
Don't forget create backup of your database and storage before make any changes in your production application.
## Update VueFileManager from 1.6.x to 1.7
`Don't forget create backup of your database and storage before make any changes in your production application.`
For those, who purchase extended licence, place these lines at the end of your `/.env` file:
```
CASHIER_LOGGER=stack
CASHIER_CURRENCY=
STRIPE_KEY=
STRIPE_SECRET=
STRIPE_WEBHOOK_SECRET=
CASHIER_PAYMENT_NOTIFICATION=App\Notifications\ConfirmPayment
```
Then follow this steps:
- Make sure you have PHP >= 7.2.5 version
- Make a backup of the .env config file located on your server.
- Upload and replace all the files on your server with what's inside the app folder.
- Restore your `.env` config file on your server.
- Go to https://your-domain.com/upgrade and follow the setup wizard instructions.
#Payments
VueFileManager is packed with **Stripe** payment options. To configure Stripe, you will be asked in Setup Wizard to set up. Or, if you skip this installation process, you will find stripe set up in you admin `Dashboard / Settings / Payments`.
## Get your active plans
Would you like to get your subscription plans for your custom front-end page? Create GET request and get all your active plans:
```
GET /api/public/pricing
```
## Manage Failed Payments
VueFileManager manage failed payments with additional email notification. But, there is more you can do for better User Experience. There is some additionals option in Stripe, look on [prevent failed payments](https://dashboard.stripe.com/settings/billing/automatic).
# Technical Informations
## For Developers
Installation process on your localhost is the same. But, there are some good hints.
@@ -160,6 +268,7 @@ To set your locale in app, go to `/config/app.php` and set your locale string in
**Small hint:** We use for translating localizations this awesome software, [check it](https://www.codeandweb.com/babeledit).
# Others
## Changelog
Refer to the [Changelog](https://vuefilemanager.com/changelog) for a full history of the project.

View File

@@ -2,6 +2,7 @@
namespace App\Http\Controllers;
use App\Services\StripeService;
use App\Setting;
use App\User;
use Illuminate\Http\Request;
@@ -10,6 +11,11 @@ use Laravel\Cashier\Http\Controllers\WebhookController as CashierController;
class WebhookController extends CashierController
{
public function __construct(StripeService $stripe)
{
$this->stripe = $stripe;
}
/**
* Handle a cancelled customer from a Stripe subscription.
*

View File

@@ -20,14 +20,49 @@ class PricingResource extends JsonResource
'id' => $this['plan']['id'],
'type' => 'plans',
'attributes' => [
'name' => $this['product']['name'],
'description' => $this['product']['description'],
'price' => Cashier::formatAmount($this['plan']['amount']),
'capacity_formatted' => format_gigabytes($this['product']['metadata']['capacity']),
'capacity' => (int) $this['product']['metadata']['capacity'],
'currency' => 'USD',
'name' => $this['product']['name'],
'description' => $this['product']['description'],
'price' => Cashier::formatAmount($this['plan']['amount']),
'capacity_formatted' => format_gigabytes($this['product']['metadata']['capacity']),
'capacity' => (int)$this['product']['metadata']['capacity'],
'currency' => config('cashier.currency'),
'tax_rates' => $this->get_tax_rates(),
]
]
];
}
/**
* Get plan tax rates
*
* @return array
*/
private function get_tax_rates(): array
{
$stripe = resolve('App\Services\StripeService');
$rates_puplic = [];
// Get tax rates
$rates = $stripe->getTaxRates();
foreach ($rates as $rate) {
// Continue when is not active
if (!$rate['active']) continue;
// Calculate tax
$tax = $this['plan']['amount'] * ($rate['percentage'] / 100);
array_push($rates_puplic, [
'id' => $rate['id'],
'active' => $rate['active'],
'jurisdiction' => $rate['jurisdiction'],
'percentage' => $rate['percentage'],
'plan_price_formatted' => Cashier::formatAmount(round($this['plan']['amount'] + $tax)),
]);
}
return $rates_puplic;
}
}

View File

@@ -49,6 +49,17 @@ class StripeService
return $user->createSetupIntent();
}
/**
* Get tax rate ids
* @return array
*/
public function getTaxRates()
{
$tax_rates = $this->stripe->taxRates()->all();
return $tax_rates['data'];
}
/**
* Get default payment option or set new default payment
*

View File

@@ -114,6 +114,26 @@ class User extends Authenticatable
'used_capacity', 'storage'
];
/**
* Get tax rate id for user
*
* @return array
*/
public function taxRates()
{
$stripe = resolve('App\Services\StripeService');
// Get tax rates
$rates = collect($stripe->getTaxRates());
// Find tax rate
$user_tax_rate = $rates->first(function ($item) {
return $item['jurisdiction'] === $this->settings->billing_country && $item['active'];
});
return $user_tax_rate ? [$user_tax_rate['id']] : [];
}
/**
* Get user used storage details
*

2
public/js/main.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -16,6 +16,7 @@
<footer class="plan-footer">
<b class="price">
{{ plan.data.attributes.price }}/{{ $t('global.monthly_ac') }}
<small v-if="plan.data.attributes.tax_rates.length > 0" class="vat-disclaimer">{{ $t('page_pricing_tables.vat_excluded') }}</small>
</b>
</footer>
</div>
@@ -116,6 +117,15 @@
@include font-size(18);
display: block;
padding-top: 5px;
.vat-disclaimer {
@include font-size(11);
color: $text;
display: block;
font-weight: 300;
opacity: 0.45;
margin-top: 5px;
}
}
}
}
@@ -184,6 +194,13 @@
color: $theme;
}
}
.price {
.vat-disclaimer {
color: $dark_mode_text_primary;
}
}
}
}
}

View File

@@ -16,6 +16,7 @@
<footer class="plan-footer">
<b class="price">
{{ plan.data.attributes.price }}/{{ $t('global.monthly_ac') }}
<small v-if="plan.data.attributes.tax_rates.length > 0" class="vat-disclaimer">{{ $t('page_pricing_tables.vat_excluded') }}</small>
</b>
<ButtonBase @click.native="selectPlan(plan)" type="submit" button-style="secondary" class="sign-in-button">
{{ $t('global.get_it') }}
@@ -133,6 +134,15 @@
@include font-size(18);
display: block;
margin-bottom: 20px;
.vat-disclaimer {
@include font-size(11);
color: $text;
display: block;
font-weight: 300;
opacity: 0.45;
margin-top: 5px;
}
}
}
}
@@ -190,6 +200,13 @@
color: $theme;
}
}
.price {
.vat-disclaimer {
color: $dark_mode_text_primary;
}
}
}
}
}

View File

@@ -14,7 +14,7 @@
'size'
],
computed: {
...mapGetters(['user']),
...mapGetters(['user', 'config']),
isIncompletePayment() {
return this.user.data.attributes.incomplete_payment
},

View File

@@ -411,6 +411,7 @@
"page_pricing_tables": {
"description": "选择计划巫婆完全适合您的需求。所有计划都会通过您的信用卡每月自动结算。",
"storage_capacity": "储存容量",
"vat_excluded": "Price displayed excludes VAT.",
"title": "选择您的计划"
},
"page_registration": {
@@ -463,7 +464,9 @@
"summary": {
"period": "每月计费",
"submit_button": "用信用卡付款",
"submit_disclaimer": "通过提交表单,您同意在您的{app}帐户中保存付款方式和帐单信息。"
"submit_disclaimer": "通过提交表单,您同意在您的{app}帐户中保存付款方式和帐单信息。",
"total_with_vat": "Total with VAT",
"vat": "VAT"
},
"title": "选择付款方式"
},

View File

@@ -411,6 +411,7 @@
"page_pricing_tables": {
"description": "Choose plan witch perfect fit your needs. All plans is billed monthly automatically via your credit card.",
"storage_capacity": "Of Storage Capacity",
"vat_excluded": "Price displayed excludes VAT.",
"title": "Choose Your Plan"
},
"page_registration": {
@@ -461,6 +462,8 @@
"section_card": "Payment Card",
"section_summary": "Order Summary",
"summary": {
"total_with_vat": "Total with VAT",
"vat": "VAT",
"period": "Billed monthly",
"submit_button": "Pay with credit card",
"submit_disclaimer": "By submit form, you agree to save the payment method and billing information in your {app} account."
@@ -722,7 +725,7 @@
"city": "City",
"city_plac": "Type your billing city",
"country": "Country",
"country_plac": "Type your billing country",
"country_plac": "Select your billing country",
"name": "Name",
"name_plac": "Type your billing name",
"phone_number": "Phone Number",

View File

@@ -411,6 +411,7 @@
"page_pricing_tables": {
"description": "Vyberte si plán, ktorý dokonale vyhovuje vašim potrebám. Všetky plány sa fakturujú mesačne automaticky prostredníctvom vašej kreditnej karty.",
"storage_capacity": "Kapacita úložiska",
"vat_excluded": "Ceny nezahrňajú DPH.",
"title": "Vyberte si svoj plán"
},
"page_registration": {
@@ -461,6 +462,8 @@
"section_card": "Platobná karta",
"section_summary": "Zhrnutie objednávky",
"summary": {
"total_with_vat": "Spolu s DPH",
"vat": "DPH",
"period": "Účtované mesačne",
"submit_button": "Zaplatiť kreditnou kartou",
"submit_disclaimer": "Odoslaním formulára súhlasíte s uložením spôsobu platby a fakturačných údajov vo svojom účte {app}."
@@ -722,7 +725,7 @@
"city": "Mesto",
"city_plac": "Zadajte svoje fakturačné mesto",
"country": "Krajina",
"country_plac": "Zadajte svoju fakturačnú krajinu",
"country_plac": "Vyberte svoju fakturačnú krajinu",
"name": "Meno",
"name_plac": "Zadajte svoje fakturačné meno",
"phone_number": "Telefónne číslo",

View File

@@ -18,6 +18,251 @@ const defaultState = {
value: 'user',
},
],
countries: [
{label: 'Afghanistan', value: 'AF'},
{label: 'Åland Islands', value: 'AX'},
{label: 'Albania', value: 'AL'},
{label: 'Algeria', value: 'DZ'},
{label: 'American Samoa', value: 'AS'},
{label: 'AndorrA', value: 'AD'},
{label: 'Angola', value: 'AO'},
{label: 'Anguilla', value: 'AI'},
{label: 'Antarctica', value: 'AQ'},
{label: 'Antigua and Barbuda', value: 'AG'},
{label: 'Argentina', value: 'AR'},
{label: 'Armenia', value: 'AM'},
{label: 'Aruba', value: 'AW'},
{label: 'Australia', value: 'AU'},
{label: 'Austria', value: 'AT'},
{label: 'Azerbaijan', value: 'AZ'},
{label: 'Bahamas', value: 'BS'},
{label: 'Bahrain', value: 'BH'},
{label: 'Bangladesh', value: 'BD'},
{label: 'Barbados', value: 'BB'},
{label: 'Belarus', value: 'BY'},
{label: 'Belgium', value: 'BE'},
{label: 'Belize', value: 'BZ'},
{label: 'Benin', value: 'BJ'},
{label: 'Bermuda', value: 'BM'},
{label: 'Bhutan', value: 'BT'},
{label: 'Bolivia', value: 'BO'},
{label: 'Bosnia and Herzegovina', value: 'BA'},
{label: 'Botswana', value: 'BW'},
{label: 'Bouvet Island', value: 'BV'},
{label: 'Brazil', value: 'BR'},
{label: 'British Indian Ocean Territory', value: 'IO'},
{label: 'Brunei Darussalam', value: 'BN'},
{label: 'Bulgaria', value: 'BG'},
{label: 'Burkina Faso', value: 'BF'},
{label: 'Burundi', value: 'BI'},
{label: 'Cambodia', value: 'KH'},
{label: 'Cameroon', value: 'CM'},
{label: 'Canada', value: 'CA'},
{label: 'Cape Verde', value: 'CV'},
{label: 'Cayman Islands', value: 'KY'},
{label: 'Central African Republic', value: 'CF'},
{label: 'Chad', value: 'TD'},
{label: 'Chile', value: 'CL'},
{label: 'China', value: 'CN'},
{label: 'Christmas Island', value: 'CX'},
{label: 'Cocos (Keeling) Islands', value: 'CC'},
{label: 'Colombia', value: 'CO'},
{label: 'Comoros', value: 'KM'},
{label: 'Congo', value: 'CG'},
{label: 'Congo, The Democratic Republic of the', value: 'CD'},
{label: 'Cook Islands', value: 'CK'},
{label: 'Costa Rica', value: 'CR'},
{label: 'Cote D\'Ivoire', value: 'CI'},
{label: 'Croatia', value: 'HR'},
{label: 'Cuba', value: 'CU'},
{label: 'Cyprus', value: 'CY'},
{label: 'Czech Republic', value: 'CZ'},
{label: 'Denmark', value: 'DK'},
{label: 'Djibouti', value: 'DJ'},
{label: 'Dominica', value: 'DM'},
{label: 'Dominican Republic', value: 'DO'},
{label: 'Ecuador', value: 'EC'},
{label: 'Egypt', value: 'EG'},
{label: 'El Salvador', value: 'SV'},
{label: 'Equatorial Guinea', value: 'GQ'},
{label: 'Eritrea', value: 'ER'},
{label: 'Estonia', value: 'EE'},
{label: 'Ethiopia', value: 'ET'},
{label: 'Falkland Islands (Malvinas)', value: 'FK'},
{label: 'Faroe Islands', value: 'FO'},
{label: 'Fiji', value: 'FJ'},
{label: 'Finland', value: 'FI'},
{label: 'France', value: 'FR'},
{label: 'French Guiana', value: 'GF'},
{label: 'French Polynesia', value: 'PF'},
{label: 'French Southern Territories', value: 'TF'},
{label: 'Gabon', value: 'GA'},
{label: 'Gambia', value: 'GM'},
{label: 'Georgia', value: 'GE'},
{label: 'Germany', value: 'DE'},
{label: 'Ghana', value: 'GH'},
{label: 'Gibraltar', value: 'GI'},
{label: 'Greece', value: 'GR'},
{label: 'Greenland', value: 'GL'},
{label: 'Grenada', value: 'GD'},
{label: 'Guadeloupe', value: 'GP'},
{label: 'Guam', value: 'GU'},
{label: 'Guatemala', value: 'GT'},
{label: 'Guernsey', value: 'GG'},
{label: 'Guinea', value: 'GN'},
{label: 'Guinea-Bissau', value: 'GW'},
{label: 'Guyana', value: 'GY'},
{label: 'Haiti', value: 'HT'},
{label: 'Heard Island and Mcdonald Islands', value: 'HM'},
{label: 'Holy See (Vatican City State)', value: 'VA'},
{label: 'Honduras', value: 'HN'},
{label: 'Hong Kong', value: 'HK'},
{label: 'Hungary', value: 'HU'},
{label: 'Iceland', value: 'IS'},
{label: 'India', value: 'IN'},
{label: 'Indonesia', value: 'ID'},
{label: 'Iran, Islamic Republic Of', value: 'IR'},
{label: 'Iraq', value: 'IQ'},
{label: 'Ireland', value: 'IE'},
{label: 'Isle of Man', value: 'IM'},
{label: 'Israel', value: 'IL'},
{label: 'Italy', value: 'IT'},
{label: 'Jamaica', value: 'JM'},
{label: 'Japan', value: 'JP'},
{label: 'Jersey', value: 'JE'},
{label: 'Jordan', value: 'JO'},
{label: 'Kazakhstan', value: 'KZ'},
{label: 'Kenya', value: 'KE'},
{label: 'Kiribati', value: 'KI'},
{label: 'Korea, Democratic People\'S Republic of', value: 'KP'},
{label: 'Korea, Republic of', value: 'KR'},
{label: 'Kuwait', value: 'KW'},
{label: 'Kyrgyzstan', value: 'KG'},
{label: 'Lao People\'S Democratic Republic', value: 'LA'},
{label: 'Latvia', value: 'LV'},
{label: 'Lebanon', value: 'LB'},
{label: 'Lesotho', value: 'LS'},
{label: 'Liberia', value: 'LR'},
{label: 'Libyan Arab Jamahiriya', value: 'LY'},
{label: 'Liechtenstein', value: 'LI'},
{label: 'Lithuania', value: 'LT'},
{label: 'Luxembourg', value: 'LU'},
{label: 'Macao', value: 'MO'},
{label: 'Macedonia, The Former Yugoslav Republic of', value: 'MK'},
{label: 'Madagascar', value: 'MG'},
{label: 'Malawi', value: 'MW'},
{label: 'Malaysia', value: 'MY'},
{label: 'Maldives', value: 'MV'},
{label: 'Mali', value: 'ML'},
{label: 'Malta', value: 'MT'},
{label: 'Marshall Islands', value: 'MH'},
{label: 'Martinique', value: 'MQ'},
{label: 'Mauritania', value: 'MR'},
{label: 'Mauritius', value: 'MU'},
{label: 'Mayotte', value: 'YT'},
{label: 'Mexico', value: 'MX'},
{label: 'Micronesia, Federated States of', value: 'FM'},
{label: 'Moldova, Republic of', value: 'MD'},
{label: 'Monaco', value: 'MC'},
{label: 'Mongolia', value: 'MN'},
{label: 'Montserrat', value: 'MS'},
{label: 'Morocco', value: 'MA'},
{label: 'Mozambique', value: 'MZ'},
{label: 'Myanmar', value: 'MM'},
{label: 'Namibia', value: 'NA'},
{label: 'Nauru', value: 'NR'},
{label: 'Nepal', value: 'NP'},
{label: 'Netherlands', value: 'NL'},
{label: 'Netherlands Antilles', value: 'AN'},
{label: 'New Caledonia', value: 'NC'},
{label: 'New Zealand', value: 'NZ'},
{label: 'Nicaragua', value: 'NI'},
{label: 'Niger', value: 'NE'},
{label: 'Nigeria', value: 'NG'},
{label: 'Niue', value: 'NU'},
{label: 'Norfolk Island', value: 'NF'},
{label: 'Northern Mariana Islands', value: 'MP'},
{label: 'Norway', value: 'NO'},
{label: 'Oman', value: 'OM'},
{label: 'Pakistan', value: 'PK'},
{label: 'Palau', value: 'PW'},
{label: 'Palestinian Territory, Occupied', value: 'PS'},
{label: 'Panama', value: 'PA'},
{label: 'Papua New Guinea', value: 'PG'},
{label: 'Paraguay', value: 'PY'},
{label: 'Peru', value: 'PE'},
{label: 'Philippines', value: 'PH'},
{label: 'Pitcairn', value: 'PN'},
{label: 'Poland', value: 'PL'},
{label: 'Portugal', value: 'PT'},
{label: 'Puerto Rico', value: 'PR'},
{label: 'Qatar', value: 'QA'},
{label: 'Reunion', value: 'RE'},
{label: 'Romania', value: 'RO'},
{label: 'Russian Federation', value: 'RU'},
{label: 'RWANDA', value: 'RW'},
{label: 'Saint Helena', value: 'SH'},
{label: 'Saint Kitts and Nevis', value: 'KN'},
{label: 'Saint Lucia', value: 'LC'},
{label: 'Saint Pierre and Miquelon', value: 'PM'},
{label: 'Saint Vincent and the Grenadines', value: 'VC'},
{label: 'Samoa', value: 'WS'},
{label: 'San Marino', value: 'SM'},
{label: 'Sao Tome and Principe', value: 'ST'},
{label: 'Saudi Arabia', value: 'SA'},
{label: 'Senegal', value: 'SN'},
{label: 'Serbia and Montenegro', value: 'CS'},
{label: 'Seychelles', value: 'SC'},
{label: 'Sierra Leone', value: 'SL'},
{label: 'Singapore', value: 'SG'},
{label: 'Slovakia', value: 'SK'},
{label: 'Slovenia', value: 'SI'},
{label: 'Solomon Islands', value: 'SB'},
{label: 'Somalia', value: 'SO'},
{label: 'South Africa', value: 'ZA'},
{label: 'South Georgia and the South Sandwich Islands', value: 'GS'},
{label: 'Spain', value: 'ES'},
{label: 'Sri Lanka', value: 'LK'},
{label: 'Sudan', value: 'SD'},
{label: 'Suriname', value: 'SR'},
{label: 'Svalbard and Jan Mayen', value: 'SJ'},
{label: 'Swaziland', value: 'SZ'},
{label: 'Sweden', value: 'SE'},
{label: 'Switzerland', value: 'CH'},
{label: 'Syrian Arab Republic', value: 'SY'},
{label: 'Taiwan, Province of China', value: 'TW'},
{label: 'Tajikistan', value: 'TJ'},
{label: 'Tanzania, United Republic of', value: 'TZ'},
{label: 'Thailand', value: 'TH'},
{label: 'Timor-Leste', value: 'TL'},
{label: 'Togo', value: 'TG'},
{label: 'Tokelau', value: 'TK'},
{label: 'Tonga', value: 'TO'},
{label: 'Trinidad and Tobago', value: 'TT'},
{label: 'Tunisia', value: 'TN'},
{label: 'Turkey', value: 'TR'},
{label: 'Turkmenistan', value: 'TM'},
{label: 'Turks and Caicos Islands', value: 'TC'},
{label: 'Tuvalu', value: 'TV'},
{label: 'Uganda', value: 'UG'},
{label: 'Ukraine', value: 'UA'},
{label: 'United Arab Emirates', value: 'AE'},
{label: 'United Kingdom', value: 'GB'},
{label: 'United States', value: 'US'},
{label: 'United States Minor Outlying Islands', value: 'UM'},
{label: 'Uruguay', value: 'UY'},
{label: 'Uzbekistan', value: 'UZ'},
{label: 'Vanuatu', value: 'VU'},
{label: 'Venezuela', value: 'VE'},
{label: 'Viet Nam', value: 'VN'},
{label: 'Virgin Islands, British', value: 'VG'},
{label: 'Virgin Islands, U.S.', value: 'VI'},
{label: 'Wallis and Futuna', value: 'WF'},
{label: 'Western Sahara', value: 'EH'},
{label: 'Yemen', value: 'YE'},
{label: 'Zambia', value: 'ZM'},
{label: 'Zimbabwe', value: 'ZW'}
],
}
const actions = {
changePreviewType: ({commit, dispatch, state, getters}) => {
@@ -77,6 +322,7 @@ const getters = {
FilePreviewType: state => state.FilePreviewType,
homeDirectory: state => state.homeDirectory,
requestedPlan: state => state.requestedPlan,
countries: state => state.countries,
api: state => state.config.api,
config: state => state.config,
index: state => state.index,

View File

@@ -82,9 +82,9 @@
</div>
</div>
<div class="block-wrapper">
<label>{{ $t('user_settings.state') }}:</label>
<label>{{ $t('user_settings.country') }}:</label>
<div class="input-wrapper">
<input :value="user.relationships.settings.data.attributes.billing_state"
<input :value="user.relationships.settings.data.attributes.billing_country"
type="text"
disabled
/>
@@ -111,9 +111,9 @@
</div>
</div>
<div class="block-wrapper">
<label>{{ $t('user_settings.country') }}:</label>
<label>{{ $t('user_settings.state') }}:</label>
<div class="input-wrapper">
<input :value="user.relationships.settings.data.attributes.billing_country"
<input :value="user.relationships.settings.data.attributes.billing_state"
type="text"
disabled
/>

View File

@@ -64,6 +64,9 @@
},
computed: {
status() {
if (this.subscription.attributes.incomplete) {
return this.$t('global.incomplete')
}
if (this.subscription.attributes.canceled) {
return this.$t('global.canceled')
}

View File

@@ -132,254 +132,12 @@
required,
InfoBox,
},
computed: {
...mapGetters(['countries']),
},
data() {
return {
isLoading: false,
countries: [
{label: 'Afghanistan', value: 'AF'},
{label: 'Åland Islands', value: 'AX'},
{label: 'Albania', value: 'AL'},
{label: 'Algeria', value: 'DZ'},
{label: 'American Samoa', value: 'AS'},
{label: 'AndorrA', value: 'AD'},
{label: 'Angola', value: 'AO'},
{label: 'Anguilla', value: 'AI'},
{label: 'Antarctica', value: 'AQ'},
{label: 'Antigua and Barbuda', value: 'AG'},
{label: 'Argentina', value: 'AR'},
{label: 'Armenia', value: 'AM'},
{label: 'Aruba', value: 'AW'},
{label: 'Australia', value: 'AU'},
{label: 'Austria', value: 'AT'},
{label: 'Azerbaijan', value: 'AZ'},
{label: 'Bahamas', value: 'BS'},
{label: 'Bahrain', value: 'BH'},
{label: 'Bangladesh', value: 'BD'},
{label: 'Barbados', value: 'BB'},
{label: 'Belarus', value: 'BY'},
{label: 'Belgium', value: 'BE'},
{label: 'Belize', value: 'BZ'},
{label: 'Benin', value: 'BJ'},
{label: 'Bermuda', value: 'BM'},
{label: 'Bhutan', value: 'BT'},
{label: 'Bolivia', value: 'BO'},
{label: 'Bosnia and Herzegovina', value: 'BA'},
{label: 'Botswana', value: 'BW'},
{label: 'Bouvet Island', value: 'BV'},
{label: 'Brazil', value: 'BR'},
{label: 'British Indian Ocean Territory', value: 'IO'},
{label: 'Brunei Darussalam', value: 'BN'},
{label: 'Bulgaria', value: 'BG'},
{label: 'Burkina Faso', value: 'BF'},
{label: 'Burundi', value: 'BI'},
{label: 'Cambodia', value: 'KH'},
{label: 'Cameroon', value: 'CM'},
{label: 'Canada', value: 'CA'},
{label: 'Cape Verde', value: 'CV'},
{label: 'Cayman Islands', value: 'KY'},
{label: 'Central African Republic', value: 'CF'},
{label: 'Chad', value: 'TD'},
{label: 'Chile', value: 'CL'},
{label: 'China', value: 'CN'},
{label: 'Christmas Island', value: 'CX'},
{label: 'Cocos (Keeling) Islands', value: 'CC'},
{label: 'Colombia', value: 'CO'},
{label: 'Comoros', value: 'KM'},
{label: 'Congo', value: 'CG'},
{label: 'Congo, The Democratic Republic of the', value: 'CD'},
{label: 'Cook Islands', value: 'CK'},
{label: 'Costa Rica', value: 'CR'},
{label: 'Cote D\'Ivoire', value: 'CI'},
{label: 'Croatia', value: 'HR'},
{label: 'Cuba', value: 'CU'},
{label: 'Cyprus', value: 'CY'},
{label: 'Czech Republic', value: 'CZ'},
{label: 'Denmark', value: 'DK'},
{label: 'Djibouti', value: 'DJ'},
{label: 'Dominica', value: 'DM'},
{label: 'Dominican Republic', value: 'DO'},
{label: 'Ecuador', value: 'EC'},
{label: 'Egypt', value: 'EG'},
{label: 'El Salvador', value: 'SV'},
{label: 'Equatorial Guinea', value: 'GQ'},
{label: 'Eritrea', value: 'ER'},
{label: 'Estonia', value: 'EE'},
{label: 'Ethiopia', value: 'ET'},
{label: 'Falkland Islands (Malvinas)', value: 'FK'},
{label: 'Faroe Islands', value: 'FO'},
{label: 'Fiji', value: 'FJ'},
{label: 'Finland', value: 'FI'},
{label: 'France', value: 'FR'},
{label: 'French Guiana', value: 'GF'},
{label: 'French Polynesia', value: 'PF'},
{label: 'French Southern Territories', value: 'TF'},
{label: 'Gabon', value: 'GA'},
{label: 'Gambia', value: 'GM'},
{label: 'Georgia', value: 'GE'},
{label: 'Germany', value: 'DE'},
{label: 'Ghana', value: 'GH'},
{label: 'Gibraltar', value: 'GI'},
{label: 'Greece', value: 'GR'},
{label: 'Greenland', value: 'GL'},
{label: 'Grenada', value: 'GD'},
{label: 'Guadeloupe', value: 'GP'},
{label: 'Guam', value: 'GU'},
{label: 'Guatemala', value: 'GT'},
{label: 'Guernsey', value: 'GG'},
{label: 'Guinea', value: 'GN'},
{label: 'Guinea-Bissau', value: 'GW'},
{label: 'Guyana', value: 'GY'},
{label: 'Haiti', value: 'HT'},
{label: 'Heard Island and Mcdonald Islands', value: 'HM'},
{label: 'Holy See (Vatican City State)', value: 'VA'},
{label: 'Honduras', value: 'HN'},
{label: 'Hong Kong', value: 'HK'},
{label: 'Hungary', value: 'HU'},
{label: 'Iceland', value: 'IS'},
{label: 'India', value: 'IN'},
{label: 'Indonesia', value: 'ID'},
{label: 'Iran, Islamic Republic Of', value: 'IR'},
{label: 'Iraq', value: 'IQ'},
{label: 'Ireland', value: 'IE'},
{label: 'Isle of Man', value: 'IM'},
{label: 'Israel', value: 'IL'},
{label: 'Italy', value: 'IT'},
{label: 'Jamaica', value: 'JM'},
{label: 'Japan', value: 'JP'},
{label: 'Jersey', value: 'JE'},
{label: 'Jordan', value: 'JO'},
{label: 'Kazakhstan', value: 'KZ'},
{label: 'Kenya', value: 'KE'},
{label: 'Kiribati', value: 'KI'},
{label: 'Korea, Democratic People\'S Republic of', value: 'KP'},
{label: 'Korea, Republic of', value: 'KR'},
{label: 'Kuwait', value: 'KW'},
{label: 'Kyrgyzstan', value: 'KG'},
{label: 'Lao People\'S Democratic Republic', value: 'LA'},
{label: 'Latvia', value: 'LV'},
{label: 'Lebanon', value: 'LB'},
{label: 'Lesotho', value: 'LS'},
{label: 'Liberia', value: 'LR'},
{label: 'Libyan Arab Jamahiriya', value: 'LY'},
{label: 'Liechtenstein', value: 'LI'},
{label: 'Lithuania', value: 'LT'},
{label: 'Luxembourg', value: 'LU'},
{label: 'Macao', value: 'MO'},
{label: 'Macedonia, The Former Yugoslav Republic of', value: 'MK'},
{label: 'Madagascar', value: 'MG'},
{label: 'Malawi', value: 'MW'},
{label: 'Malaysia', value: 'MY'},
{label: 'Maldives', value: 'MV'},
{label: 'Mali', value: 'ML'},
{label: 'Malta', value: 'MT'},
{label: 'Marshall Islands', value: 'MH'},
{label: 'Martinique', value: 'MQ'},
{label: 'Mauritania', value: 'MR'},
{label: 'Mauritius', value: 'MU'},
{label: 'Mayotte', value: 'YT'},
{label: 'Mexico', value: 'MX'},
{label: 'Micronesia, Federated States of', value: 'FM'},
{label: 'Moldova, Republic of', value: 'MD'},
{label: 'Monaco', value: 'MC'},
{label: 'Mongolia', value: 'MN'},
{label: 'Montserrat', value: 'MS'},
{label: 'Morocco', value: 'MA'},
{label: 'Mozambique', value: 'MZ'},
{label: 'Myanmar', value: 'MM'},
{label: 'Namibia', value: 'NA'},
{label: 'Nauru', value: 'NR'},
{label: 'Nepal', value: 'NP'},
{label: 'Netherlands', value: 'NL'},
{label: 'Netherlands Antilles', value: 'AN'},
{label: 'New Caledonia', value: 'NC'},
{label: 'New Zealand', value: 'NZ'},
{label: 'Nicaragua', value: 'NI'},
{label: 'Niger', value: 'NE'},
{label: 'Nigeria', value: 'NG'},
{label: 'Niue', value: 'NU'},
{label: 'Norfolk Island', value: 'NF'},
{label: 'Northern Mariana Islands', value: 'MP'},
{label: 'Norway', value: 'NO'},
{label: 'Oman', value: 'OM'},
{label: 'Pakistan', value: 'PK'},
{label: 'Palau', value: 'PW'},
{label: 'Palestinian Territory, Occupied', value: 'PS'},
{label: 'Panama', value: 'PA'},
{label: 'Papua New Guinea', value: 'PG'},
{label: 'Paraguay', value: 'PY'},
{label: 'Peru', value: 'PE'},
{label: 'Philippines', value: 'PH'},
{label: 'Pitcairn', value: 'PN'},
{label: 'Poland', value: 'PL'},
{label: 'Portugal', value: 'PT'},
{label: 'Puerto Rico', value: 'PR'},
{label: 'Qatar', value: 'QA'},
{label: 'Reunion', value: 'RE'},
{label: 'Romania', value: 'RO'},
{label: 'Russian Federation', value: 'RU'},
{label: 'RWANDA', value: 'RW'},
{label: 'Saint Helena', value: 'SH'},
{label: 'Saint Kitts and Nevis', value: 'KN'},
{label: 'Saint Lucia', value: 'LC'},
{label: 'Saint Pierre and Miquelon', value: 'PM'},
{label: 'Saint Vincent and the Grenadines', value: 'VC'},
{label: 'Samoa', value: 'WS'},
{label: 'San Marino', value: 'SM'},
{label: 'Sao Tome and Principe', value: 'ST'},
{label: 'Saudi Arabia', value: 'SA'},
{label: 'Senegal', value: 'SN'},
{label: 'Serbia and Montenegro', value: 'CS'},
{label: 'Seychelles', value: 'SC'},
{label: 'Sierra Leone', value: 'SL'},
{label: 'Singapore', value: 'SG'},
{label: 'Slovakia', value: 'SK'},
{label: 'Slovenia', value: 'SI'},
{label: 'Solomon Islands', value: 'SB'},
{label: 'Somalia', value: 'SO'},
{label: 'South Africa', value: 'ZA'},
{label: 'South Georgia and the South Sandwich Islands', value: 'GS'},
{label: 'Spain', value: 'ES'},
{label: 'Sri Lanka', value: 'LK'},
{label: 'Sudan', value: 'SD'},
{label: 'Suriname', value: 'SR'},
{label: 'Svalbard and Jan Mayen', value: 'SJ'},
{label: 'Swaziland', value: 'SZ'},
{label: 'Sweden', value: 'SE'},
{label: 'Switzerland', value: 'CH'},
{label: 'Syrian Arab Republic', value: 'SY'},
{label: 'Taiwan, Province of China', value: 'TW'},
{label: 'Tajikistan', value: 'TJ'},
{label: 'Tanzania, United Republic of', value: 'TZ'},
{label: 'Thailand', value: 'TH'},
{label: 'Timor-Leste', value: 'TL'},
{label: 'Togo', value: 'TG'},
{label: 'Tokelau', value: 'TK'},
{label: 'Tonga', value: 'TO'},
{label: 'Trinidad and Tobago', value: 'TT'},
{label: 'Tunisia', value: 'TN'},
{label: 'Turkey', value: 'TR'},
{label: 'Turkmenistan', value: 'TM'},
{label: 'Turks and Caicos Islands', value: 'TC'},
{label: 'Tuvalu', value: 'TV'},
{label: 'Uganda', value: 'UG'},
{label: 'Ukraine', value: 'UA'},
{label: 'United Arab Emirates', value: 'AE'},
{label: 'United Kingdom', value: 'GB'},
{label: 'United States', value: 'US'},
{label: 'United States Minor Outlying Islands', value: 'UM'},
{label: 'Uruguay', value: 'UY'},
{label: 'Uzbekistan', value: 'UZ'},
{label: 'Vanuatu', value: 'VU'},
{label: 'Venezuela', value: 'VE'},
{label: 'Viet Nam', value: 'VN'},
{label: 'Virgin Islands, British', value: 'VG'},
{label: 'Virgin Islands, U.S.', value: 'VI'},
{label: 'Wallis and Futuna', value: 'WF'},
{label: 'Western Sahara', value: 'EH'},
{label: 'Yemen', value: 'YE'},
{label: 'Zambia', value: 'ZM'},
{label: 'Zimbabwe', value: 'ZW'}
],
billingInformation: {
billing_phone_number: '',
billing_postal_code: '',
@@ -406,17 +164,15 @@
// Send request to get verify account
axios
.post('/api/setup/stripe-billings', this.billingInformation)
.then(response => {
// End loading
this.isLoading = false
.then(() => {
// Redirect to next step
this.$router.push({name: 'SubscriptionPlans'})
})
.catch(error => {
// End loading
})
.finally(() => {
this.isLoading = false
})
},

View File

@@ -114,20 +114,6 @@
</ValidationProvider>
</div>
<div class="block-wrapper">
<label>{{ $t('user_settings.state') }}:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper"
rules="required"
name="billing_state" v-slot="{ errors }">
<input v-model="billing.billing_state"
:placeholder="$t('user_settings.state_plac')"
type="text"
:class="{'is-error': errors[0]}"
/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="wrapper-inline">
<div class="block-wrapper">
<label>{{ $t('user_settings.city') }}:</label>
@@ -163,11 +149,28 @@
<ValidationProvider tag="div" mode="passive" class="input-wrapper"
rules="required"
name="billing_country" v-slot="{ errors }">
<input v-model="billing.billing_country"
:placeholder="$t('user_settings.country_plac')"
<SelectInput v-model="billing.billing_country"
:default="billing.billing_country"
:options="countries"
:placeholder="$t('user_settings.country_plac')"
:isError="errors[0]" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="block-wrapper">
<label>{{ $t('user_settings.state') }}:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper"
rules="required"
name="billing_state" v-slot="{ errors }">
<input v-model="billing.billing_state"
:placeholder="$t('user_settings.state_plac')"
type="text"
:class="{'is-error': errors[0]}"
/>
<small class="input-help">
State, county, province, or region.
</small>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
@@ -201,7 +204,17 @@
<b>{{ requestedPlan.data.attributes.price }}</b>
</div>
</div>
<div class="row">
<div class="row" v-if="taxRates">
<div class="cell">
<b>{{ $t('page_upgrade_account.summary.vat') }} - ({{ taxRates.jurisdiction }} {{ taxRates.percentage }}%)</b>
</div>
<div class="cell">
<b>{{ taxRates.plan_price_formatted }}</b>
</div>
</div>
<!--Show total when tax rates is not specified-->
<div class="row" v-if="! taxRates">
<div class="cell">
<b>{{ $t('global.total') }}</b>
</div>
@@ -209,6 +222,17 @@
<b>{{ requestedPlan.data.attributes.price }}</b>
</div>
</div>
<!--Show total when is tax rates-->
<div class="row" v-if="taxRates">
<div class="cell">
<b>{{ $t('page_upgrade_account.summary.total_with_vat') }}</b>
</div>
<div class="cell">
<b>{{ taxRates.plan_price_formatted }}</b>
</div>
</div>
<ButtonBase :disabled="isSubmitted" :loading="isSubmitted" @click.native="submitOrder"
type="submit" button-style="theme-solid" class="next-submit">
{{ $t('page_upgrade_account.summary.submit_button') }}
@@ -231,6 +255,7 @@
<script>
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
import PlanPricingTables from '@/components/Others/PlanPricingTables'
import SelectInput from '@/components/Others/Forms/SelectInput'
import FormLabel from '@/components/Others/Forms/FormLabel'
import MobileHeader from '@/components/Mobile/MobileHeader'
import ButtonBase from '@/components/FilesView/ButtonBase'
@@ -254,6 +279,7 @@
PlanPricingTables,
CreditCardIcon,
MobileHeader,
SelectInput,
ButtonBase,
PageHeader,
ColorLabel,
@@ -263,9 +289,14 @@
InfoBox,
},
computed: {
...mapGetters(['requestedPlan', 'config']),
...mapGetters(['requestedPlan', 'config', 'countries']),
billing() {
return this.$store.getters.user.relationships.settings.data.attributes
},
taxRates() {
return this.requestedPlan.data.attributes.tax_rates.find(taxRate => {
return taxRate.jurisdiction === this.billing.billing_country
})
}
},
data() {
@@ -326,6 +357,16 @@
this.isError = true
this.errorMessage = error.response.data.message
}
if (error.response.status === 500) {
this.isError = true
this.errorMessage = error.response.data.message
events.$emit('alert:open', {
title: this.$t('popup_error.title'),
message: this.$t('popup_error.message'),
})
}
},
async submitOrder() {

View File

@@ -48,16 +48,6 @@
/>
</div>
</div>
<div class="block-wrapper">
<label>{{ $t('user_settings.state') }}:</label>
<div class="input-wrapper">
<input @keyup="$updateText('/user/relationships/settings', 'billing_state', billingInfo.billing_state)"
v-model="billingInfo.billing_state"
:placeholder="$t('user_settings.state_plac')"
type="text"
/>
</div>
</div>
<div class="wrapper-inline">
<div class="block-wrapper">
<label>{{ $t('user_settings.city') }}:</label>
@@ -83,11 +73,24 @@
<div class="block-wrapper">
<label>{{ $t('user_settings.country') }}:</label>
<div class="input-wrapper">
<input @keyup="$updateText('/user/relationships/settings', 'billing_country', billingInfo.billing_country)"
v-model="billingInfo.billing_country"
:placeholder="$t('user_settings.country_plac')"
<SelectInput @input="$updateText('/user/relationships/settings', 'billing_country', billingInfo.billing_country)"
v-model="billingInfo.billing_country"
:default="billingInfo.billing_country"
:options="countries"
:placeholder="$t('user_settings.country_plac')"/>
</div>
</div>
<div class="block-wrapper">
<label>{{ $t('user_settings.state') }}:</label>
<div class="input-wrapper">
<input @keyup="$updateText('/user/relationships/settings', 'billing_state', billingInfo.billing_state)"
v-model="billingInfo.billing_state"
:placeholder="$t('user_settings.state_plac')"
type="text"
/>
<small class="input-help">
State, county, province, or region.
</small>
</div>
</div>
<div class="block-wrapper">
@@ -108,6 +111,7 @@
<script>
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
import PageTabGroup from '@/components/Others/Layout/PageTabGroup'
import SelectInput from '@/components/Others/Forms/SelectInput'
import FormLabel from '@/components/Others/Forms/FormLabel'
import MobileHeader from '@/components/Mobile/MobileHeader'
import ButtonBase from '@/components/FilesView/ButtonBase'
@@ -124,19 +128,20 @@
'user'
],
components: {
PageTabGroup,
FormLabel,
PageTab,
ValidationProvider,
ValidationObserver,
PageTabGroup,
MobileHeader,
SelectInput,
PageHeader,
ButtonBase,
ThemeLabel,
FormLabel,
required,
PageTab,
},
computed: {
...mapGetters(['config']),
...mapGetters(['config', 'countries']),
},
data() {
return {

View File

@@ -19,6 +19,13 @@ return [
// Invoice
'print_button' => 'Print Document',
'vat' => 'VAT',
'vat_included' => 'incl.',
'subtotal' => 'Subtotal',
'tax_exempted' => 'Tax is exempted',
'tax_be_paid_reverse' => 'Tax to be paid on reverse charge basis',
'invoice_title' => 'Invoice',
'date' => 'Date',
'product' => 'Product',

View File

@@ -19,6 +19,13 @@ return [
// Invoice
'print_button' => 'Print Document',
'vat' => 'VAT',
'vat_included' => 'incl.',
'subtotal' => 'Subtotal',
'tax_exempted' => 'Tax is exempted',
'tax_be_paid_reverse' => 'Tax to be paid on reverse charge basis',
'invoice_title' => 'Invoice',
'date' => 'Date',
'product' => 'Product',

View File

@@ -19,6 +19,13 @@ return [
// Invoice
'print_button' => 'Vytlačiť dokument',
'vat' => 'Daň',
'vat_included' => 'zah.',
'subtotal' => 'Medzisúčet',
'tax_exempted' => 'Daň je oslobodená',
'tax_be_paid_reverse' => 'Daň, ktorá sa má zaplatiť na základe prenesenia daňovej povinnosti',
'invoice_title' => 'Faktúra',
'date' => 'Dátum',
'product' => 'Produkt',

View File

@@ -35,7 +35,8 @@
<header class="invoice-header">
<div class="logo">
@if(isset($settings->app_logo_horizontal))
<img src="{{ url($settings->app_logo_horizontal) }}" alt="{{ $settings->app_title ?? 'VueFileManager' }}">
<img src="{{ url($settings->app_logo_horizontal) }}"
alt="{{ $settings->app_title ?? 'VueFileManager' }}">
@else
<h1>{{ $settings->app_title ?? 'VueFileManager' }}</h1>
@endif
@@ -58,6 +59,14 @@
<b>@lang('vuefilemanager.invoice_number'):</b>
<span>{{ $invoice->number }}</span>
</li>
<!-- Extra / VAT Information -->
@if (isset($vat))
<li class="list-item">
<b>@lang('vuefilemanager.vat'):</b>
<span>{{ $vat }}</span>
</li>
@endif
</ul>
</section>
<div class="invoice-partners">
@@ -179,31 +188,172 @@
</div>
</div>
<div class="invoice-order">
<table class="table" width="100%" class="table" border="0">
{{--<table class="table" width="100%" border="0">
<thead class="table-header">
<tr>
<td>@lang('vuefilemanager.col_description')</td>
<td>@lang('vuefilemanager.col_date')</td>
<td>@lang('vuefilemanager.col_amount')</td>
</tr>
</thead>
<tbody class="table-body">
--}}{{--Display invoices--}}{{--
@foreach($invoice->invoiceItems() as $item)
<tr>
<td colspan="2">{{ $item->description }}</td>
<td>{{ $item->total() }}</td>
</tr>
@endforeach
--}}{{--Display subscription--}}{{--
@foreach($invoice->subscriptions() as $subscription)
<tr>
<td>@lang('vuefilemanager.subscription') ({{ $subscription->quantity }})</td>
<td>{{ $subscription->startDateAsCarbon()->formatLocalized('%d. %B. %Y') }} -
{{ $subscription->endDateAsCarbon()->formatLocalized('%d. %B. %Y') }}</td>
<td>{{ $subscription->total() }}</td>
</tr>
@endforeach
<!-- Display The Taxes -->
@unless ($invoice->isNotTaxExempt())
<tr>
<td colspan="{{ $invoice->hasTax() ? 2 : 1 }}" style="text-align: right;">
@if ($invoice->isTaxExempt())
Tax is exempted
@else
Tax to be paid on reverse charge basis
@endif
</td>
<td></td>
</tr>
@else
@foreach ($invoice->taxes() as $tax)
<tr>
<td colspan="2" style="text-align: right;">
{{ $tax->display_name }} {{ $tax->jurisdiction ? ' - '.$tax->jurisdiction : '' }}
({{ $tax->percentage }}%{{ $tax->isInclusive() ? ' incl.' : '' }})
</td>
<td>{{ $tax->amount() }}</td>
</tr>
@endforeach
@endunless
</tbody>
</table>--}}
<!-- Invoice Table -->
<table width="100%" class="table" border="0">
<thead class="table-header">
<tr>
<td>@lang('vuefilemanager.col_description')</td>
<td>@lang('vuefilemanager.col_date')</td>
@if ($invoice->hasTax())
<td align="right">@lang('vuefilemanager.vat')</td>
@endif
<td>@lang('vuefilemanager.col_amount')</td>
</tr>
</thead>
<tbody class="table-body">
@foreach($invoice->invoiceItems() as $item)
<tr>
<!-- Display The Invoice Items -->
@foreach ($invoice->invoiceItems() as $item)
<tr class="row">
<td colspan="2">{{ $item->description }}</td>
@if ($invoice->hasTax())
<td>
@if ($inclusiveTaxPercentage = $item->inclusiveTaxPercentage())
{{ $inclusiveTaxPercentage }}% incl.
@endif
@if ($item->hasBothInclusiveAndExclusiveTax())
+
@endif
@if ($exclusiveTaxPercentage = $item->exclusiveTaxPercentage())
{{ $exclusiveTaxPercentage }}%
@endif
</td>
@endif
<td>{{ $item->total() }}</td>
</tr>
@endforeach
@foreach($invoice->subscriptions() as $subscription)
<tr>
<!-- Display The Subscriptions -->
@foreach ($invoice->subscriptions() as $subscription)
<tr class="row">
<td>@lang('vuefilemanager.subscription') ({{ $subscription->quantity }})</td>
<td>{{ $subscription->startDateAsCarbon()->formatLocalized('%d. %B. %Y') }} -
{{ $subscription->endDateAsCarbon()->formatLocalized('%d. %B. %Y') }}</td>
<td>
{{ $subscription->startDateAsCarbon()->formatLocalized('%B %e, %Y') }} -
{{ $subscription->endDateAsCarbon()->formatLocalized('%B %e, %Y') }}
</td>
@if ($invoice->hasTax())
<td>
@if ($inclusiveTaxPercentage = $subscription->inclusiveTaxPercentage())
{{ $inclusiveTaxPercentage }}% @lang('vuefilemanager.vat_included')
@endif
@if ($subscription->hasBothInclusiveAndExclusiveTax())
+
@endif
@if ($exclusiveTaxPercentage = $subscription->exclusiveTaxPercentage())
{{ $exclusiveTaxPercentage }}%
@endif
</td>
@endif
<td>{{ $subscription->total() }}</td>
</tr>
@endforeach
<!-- Display The Subtotal -->
@if ($invoice->hasDiscount() || $invoice->hasTax() || $invoice->hasStartingBalance())
<tr>
<td colspan="{{ $invoice->hasTax() ? 3 : 2 }}" style="text-align: right;">@lang('vuefilemanager.subtotal')</td>
<td>{{ $invoice->subtotal() }}</td>
</tr>
@endif
<!-- Display The Taxes -->
@unless ($invoice->isNotTaxExempt())
<tr>
<td colspan="{{ $invoice->hasTax() ? 3 : 2 }}" style="text-align: right;">
@if ($invoice->isTaxExempt())
@lang('vuefilemanager.tax_exempted')
@else
@lang('vuefilemanager.tax_be_paid_reverse')
@endif
</td>
<td></td>
</tr>
@else
@foreach ($invoice->taxes() as $tax)
<tr>
<td colspan="3" style="text-align: right;">
{{ $tax->display_name }} {{ $tax->jurisdiction ? ' - '.$tax->jurisdiction : '' }}
({{ $tax->percentage }}%{{ $tax->isInclusive() ? ' ' . __('vuefilemanager.vat_included') : '' }})
</td>
<td>{{ $tax->amount() }}</td>
</tr>
@endforeach
@endunless
<!-- Display The Final Total -->
<tr>
<td colspan="{{ $invoice->hasTax() ? 3 : 2 }}" style="text-align: right;">
<strong>@lang('vuefilemanager.total')</strong>
</td>
<td>
<strong>{{ $invoice->total() }}</strong>
</td>
</tr>
</tbody>
</table>
</div>
<div class="invoice-summary">