Merge remote-tracking branch 'invoiceninja/develop' into develop

This commit is contained in:
Gilbert Paquin 2017-07-31 22:48:47 -04:00
commit 0997f94cbc
24 changed files with 300 additions and 20 deletions

View File

@ -84,9 +84,9 @@ class CheckData extends Command
if (! $this->option('client_id')) { if (! $this->option('client_id')) {
$this->checkOAuth(); $this->checkOAuth();
$this->checkInvitations(); $this->checkInvitations();
$this->checkFailedJobs();
$this->checkAccountData(); $this->checkAccountData();
$this->checkLookupData(); $this->checkLookupData();
$this->checkFailedJobs();
} }
$this->logMessage('Done: ' . strtoupper($this->isValid ? RESULT_SUCCESS : RESULT_FAILURE)); $this->logMessage('Done: ' . strtoupper($this->isValid ? RESULT_SUCCESS : RESULT_FAILURE));
@ -371,6 +371,10 @@ class CheckData extends Command
private function checkFailedJobs() private function checkFailedJobs()
{ {
if (Utils::isTravis()) {
return;
}
$current = config('database.default'); $current = config('database.default');
config(['database.default' => env('QUEUE_DATABASE')]); config(['database.default' => env('QUEUE_DATABASE')]);

View File

@ -132,9 +132,11 @@ class HomeController extends BaseController
public function contactUs() public function contactUs()
{ {
Mail::raw(request()->contact_us_message, function ($message) { Mail::raw(request()->contact_us_message, function ($message) {
$subject = 'Customer Message'; $subject = 'Customer Message: ';
if (! Utils::isNinja()) { if (Utils::isNinja()) {
$subject .= ': v' . NINJA_VERSION; $subject .= config('database.default');
} else {
$subject .= 'v' . NINJA_VERSION;
} }
$message->to(env('CONTACT_EMAIL', 'contact@invoiceninja.com')) $message->to(env('CONTACT_EMAIL', 'contact@invoiceninja.com'))
->from(CONTACT_EMAIL, Auth::user()->present()->fullName) ->from(CONTACT_EMAIL, Auth::user()->present()->fullName)

View File

@ -339,6 +339,9 @@ class OnlinePaymentController extends BaseController
if (request()->currency_code) { if (request()->currency_code) {
$data['currency_code'] = request()->currency_code; $data['currency_code'] = request()->currency_code;
} }
if (request()->country_code) {
$data['country_code'] = request()->country_code;
}
$client = $clientRepo->save($data, $client); $client = $clientRepo->save($data, $client);
} }

View File

@ -31,7 +31,7 @@ class RegisterRequest extends Request
public function rules() public function rules()
{ {
$rules = [ $rules = [
'email' => 'required|unique:users', 'email' => 'email|required|unique:users',
'first_name' => 'required', 'first_name' => 'required',
'last_name' => 'required', 'last_name' => 'required',
'password' => 'required', 'password' => 'required',

View File

@ -115,6 +115,8 @@ class Invoice extends EntityModel implements BalanceAffecting
'terms', 'terms',
'product', 'product',
'quantity', 'quantity',
'tax1',
'tax2',
]; ];
} }
@ -135,6 +137,7 @@ class Invoice extends EntityModel implements BalanceAffecting
'notes' => 'notes', 'notes' => 'notes',
'product|item' => 'product', 'product|item' => 'product',
'quantity|qty' => 'quantity', 'quantity|qty' => 'quantity',
'tax' => 'tax1',
]; ];
} }

View File

@ -156,6 +156,30 @@ class BaseTransformer extends TransformerAbstract
return isset($this->maps['countries2'][$name]) ? $this->maps['countries2'][$name] : null; return isset($this->maps['countries2'][$name]) ? $this->maps['countries2'][$name] : null;
} }
/**
* @param $name
*
* @return null
*/
public function getTaxRate($name)
{
$name = strtolower(trim($name));
return isset($this->maps['tax_rates'][$name]) ? $this->maps['tax_rates'][$name] : 0;
}
/**
* @param $name
*
* @return null
*/
public function getTaxName($name)
{
$name = strtolower(trim($name));
return isset($this->maps['tax_names'][$name]) ? $this->maps['tax_names'][$name] : '';
}
/** /**
* @param $name * @param $name
* *

View File

@ -41,6 +41,10 @@ class InvoiceTransformer extends BaseTransformer
'notes' => $this->getString($data, 'notes') ?: $this->getProductNotes($this->getString($data, 'product')), 'notes' => $this->getString($data, 'notes') ?: $this->getProductNotes($this->getString($data, 'product')),
'cost' => $this->getFloat($data, 'amount') ?: $this->getProductCost($this->getString($data, 'product')), 'cost' => $this->getFloat($data, 'amount') ?: $this->getProductCost($this->getString($data, 'product')),
'qty' => $this->getFloat($data, 'quantity') ?: 1, 'qty' => $this->getFloat($data, 'quantity') ?: 1,
'tax_name1' => $this->getTaxName($this->getString($data, 'tax1')),
'tax_rate1' => $this->getTaxRate($this->getString($data, 'tax1')),
'tax_name2' => $this->getTaxName($this->getString($data, 'tax2')),
'tax_rate2' => $this->getTaxRate($this->getString($data, 'tax2')),
], ],
], ],
]; ];

View File

@ -285,7 +285,11 @@ class InvoicePresenter extends EntityPresenter
$label = trans('texts.fee'); $label = trans('texts.fee');
} }
return ' - ' . $fee . ' ' . $label; $label = ' - ' . $fee . ' ' . $label;
$label .= '&nbsp;&nbsp; <i class="fa fa-info-circle" data-toggle="tooltip" data-placement="bottom" title="' . trans('texts.fee_help') . '"></i>';
return $label;
} }
public function multiAccountLink() public function multiAccountLink()

View File

@ -13,6 +13,11 @@ class TaxRateRepository extends BaseRepository
return 'App\Models\TaxRate'; return 'App\Models\TaxRate';
} }
public function all()
{
return TaxRate::scope()->get();
}
public function find($accountId) public function find($accountId)
{ {
return DB::table('tax_rates') return DB::table('tax_rates')

View File

@ -19,6 +19,7 @@ use App\Ninja\Repositories\InvoiceRepository;
use App\Ninja\Repositories\PaymentRepository; use App\Ninja\Repositories\PaymentRepository;
use App\Ninja\Repositories\ProductRepository; use App\Ninja\Repositories\ProductRepository;
use App\Ninja\Repositories\VendorRepository; use App\Ninja\Repositories\VendorRepository;
use App\Ninja\Repositories\TaxRateRepository;
use App\Ninja\Serializers\ArraySerializer; use App\Ninja\Serializers\ArraySerializer;
use Auth; use Auth;
use Cache; use Cache;
@ -126,7 +127,8 @@ class ImportService
ProductRepository $productRepo, ProductRepository $productRepo,
ExpenseRepository $expenseRepo, ExpenseRepository $expenseRepo,
VendorRepository $vendorRepo, VendorRepository $vendorRepo,
ExpenseCategoryRepository $expenseCategoryRepo ExpenseCategoryRepository $expenseCategoryRepo,
TaxRateRepository $taxRateRepository
) { ) {
$this->fractal = $manager; $this->fractal = $manager;
$this->fractal->setSerializer(new ArraySerializer()); $this->fractal->setSerializer(new ArraySerializer());
@ -139,6 +141,7 @@ class ImportService
$this->expenseRepo = $expenseRepo; $this->expenseRepo = $expenseRepo;
$this->vendorRepo = $vendorRepo; $this->vendorRepo = $vendorRepo;
$this->expenseCategoryRepo = $expenseCategoryRepo; $this->expenseCategoryRepo = $expenseCategoryRepo;
$this->taxRateRepository = $taxRateRepository;
} }
/** /**
@ -849,6 +852,8 @@ class ImportService
'invoice_ids' => [], 'invoice_ids' => [],
'vendors' => [], 'vendors' => [],
'expense_categories' => [], 'expense_categories' => [],
'tax_rates' => [],
'tax_names' => [],
]; ];
$clients = $this->clientRepo->all(); $clients = $this->clientRepo->all();
@ -886,6 +891,13 @@ class ImportService
foreach ($expenseCaegories as $category) { foreach ($expenseCaegories as $category) {
$this->addExpenseCategoryToMaps($category); $this->addExpenseCategoryToMaps($category);
} }
$taxRates = $this->taxRateRepository->all();
foreach ($taxRates as $taxRate) {
$name = trim(strtolower($taxRate->name));
$this->maps['tax_rates'][$name] = $taxRate->rate;
$this->maps['tax_names'][$name] = $taxRate->name;
}
} }
/** /**

View File

@ -40,6 +40,7 @@
"digitickets/omnipay-realex": "~5.0", "digitickets/omnipay-realex": "~5.0",
"dioscouri/omnipay-cybersource": "dev-master", "dioscouri/omnipay-cybersource": "dev-master",
"doctrine/dbal": "2.5.x", "doctrine/dbal": "2.5.x",
"dompdf/dompdf": "^0.8.0",
"ezyang/htmlpurifier": "~v4.7", "ezyang/htmlpurifier": "~v4.7",
"fotografde/omnipay-checkoutcom": "~2.0", "fotografde/omnipay-checkoutcom": "~2.0",
"fruitcakestudio/omnipay-sisow": "~2.0", "fruitcakestudio/omnipay-sisow": "~2.0",

181
composer.lock generated
View File

@ -4,8 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"hash": "e8611674b74a220909d4c70784f2e227", "hash": "2d3dd60225cc67588bbab64398253148",
"content-hash": "8d418324fd6e8b5af5c7b2058e31d898", "content-hash": "deed4ab682dc6d6cb5bdc56a7d60a872",
"packages": [ "packages": [
{ {
"name": "agmscode/omnipay-agms", "name": "agmscode/omnipay-agms",
@ -2041,6 +2041,68 @@
], ],
"time": "2014-09-09 13:34:57" "time": "2014-09-09 13:34:57"
}, },
{
"name": "dompdf/dompdf",
"version": "v0.8.0",
"source": {
"type": "git",
"url": "https://github.com/dompdf/dompdf.git",
"reference": "0f418c6b58fdeafc2a0e80eb1fa5e644e185089c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dompdf/dompdf/zipball/0f418c6b58fdeafc2a0e80eb1fa5e644e185089c",
"reference": "0f418c6b58fdeafc2a0e80eb1fa5e644e185089c",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-gd": "*",
"ext-mbstring": "*",
"phenx/php-font-lib": "0.5.*",
"phenx/php-svg-lib": "0.2.*",
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "4.8.*",
"squizlabs/php_codesniffer": "2.*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-develop": "0.7-dev"
}
},
"autoload": {
"psr-4": {
"Dompdf\\": "src/"
},
"classmap": [
"lib/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1"
],
"authors": [
{
"name": "Fabien Ménager",
"email": "fabien.menager@gmail.com"
},
{
"name": "Brian Sweeney",
"email": "eclecticgeek@gmail.com"
},
{
"name": "Gabriel Bull",
"email": "me@gabrielbull.com"
}
],
"description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter",
"homepage": "https://github.com/dompdf/dompdf",
"time": "2017-02-16 02:40:40"
},
{ {
"name": "dwolla/omnipay-dwolla", "name": "dwolla/omnipay-dwolla",
"version": "dev-master", "version": "dev-master",
@ -6891,6 +6953,80 @@
], ],
"time": "2015-02-28 17:09:35" "time": "2015-02-28 17:09:35"
}, },
{
"name": "phenx/php-font-lib",
"version": "0.5",
"source": {
"type": "git",
"url": "https://github.com/PhenX/php-font-lib.git",
"reference": "19ad2bebc35be028fcc0221025fcbf3d436a3962"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PhenX/php-font-lib/zipball/19ad2bebc35be028fcc0221025fcbf3d436a3962",
"reference": "19ad2bebc35be028fcc0221025fcbf3d436a3962",
"shasum": ""
},
"require-dev": {
"phpunit/phpunit": "^4.8"
},
"type": "library",
"autoload": {
"psr-4": {
"FontLib\\": "src/FontLib"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0"
],
"authors": [
{
"name": "Fabien Ménager",
"email": "fabien.menager@gmail.com"
}
],
"description": "A library to read, parse, export and make subsets of different types of font files.",
"homepage": "https://github.com/PhenX/php-font-lib",
"time": "2017-02-11 10:58:43"
},
{
"name": "phenx/php-svg-lib",
"version": "v0.2",
"source": {
"type": "git",
"url": "https://github.com/PhenX/php-svg-lib.git",
"reference": "de291bec8449b89acfe85691b5c71434797959dc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PhenX/php-svg-lib/zipball/de291bec8449b89acfe85691b5c71434797959dc",
"reference": "de291bec8449b89acfe85691b5c71434797959dc",
"shasum": ""
},
"require": {
"sabberworm/php-css-parser": "6.0.*"
},
"type": "library",
"autoload": {
"psr-0": {
"Svg\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0"
],
"authors": [
{
"name": "Fabien Ménager",
"email": "fabien.menager@gmail.com"
}
],
"description": "A library to read, parse and export to PDF SVG files.",
"homepage": "https://github.com/PhenX/php-svg-lib",
"time": "2016-12-13 20:25:45"
},
{ {
"name": "phpoffice/phpexcel", "name": "phpoffice/phpexcel",
"version": "1.8.1", "version": "1.8.1",
@ -7537,6 +7673,47 @@
], ],
"time": "2017-06-14 03:57:53" "time": "2017-06-14 03:57:53"
}, },
{
"name": "sabberworm/php-css-parser",
"version": "6.0.1",
"source": {
"type": "git",
"url": "https://github.com/sabberworm/PHP-CSS-Parser.git",
"reference": "9ea4b00c569b19f731d0c2e0e802055877ff40c2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sabberworm/PHP-CSS-Parser/zipball/9ea4b00c569b19f731d0c2e0e802055877ff40c2",
"reference": "9ea4b00c569b19f731d0c2e0e802055877ff40c2",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"type": "library",
"autoload": {
"psr-0": {
"Sabberworm\\CSS": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Raphael Schweikert"
}
],
"description": "Parser for CSS Files written in PHP",
"homepage": "http://www.sabberworm.com/blog/2010/6/10/php-css-parser",
"keywords": [
"css",
"parser",
"stylesheet"
],
"time": "2015-08-24 08:48:52"
},
{ {
"name": "simshaun/recurr", "name": "simshaun/recurr",
"version": "dev-master", "version": "dev-master",

View File

@ -67,6 +67,7 @@ Troubleshooting
- We suggest using PhantomJS version >= 2.1.1, users have reported seeing 'Error: 0' with older versions. - We suggest using PhantomJS version >= 2.1.1, users have reported seeing 'Error: 0' with older versions.
- You can use `this script <https://raw.githubusercontent.com/invoiceninja/invoiceninja/develop/resources/test.pjs>`_ to test from the command line, change ``__YOUR_LINK_HERE__`` to a 'View as recipient' link. - You can use `this script <https://raw.githubusercontent.com/invoiceninja/invoiceninja/develop/resources/test.pjs>`_ to test from the command line, change ``__YOUR_LINK_HERE__`` to a 'View as recipient' link.
- If you require contacts to enter a password to see their invoice you'll need to set a random value for ``PHANTOMJS_SECRET``. - If you require contacts to enter a password to see their invoice you'll need to set a random value for ``PHANTOMJS_SECRET``.
- If you're using a proxy and/or self-signed certificate `this comment <https://github.com/invoiceninja/dockerfiles/issues/39#issuecomment-282489039>`_ may help.
Custom Fonts Custom Fonts
"""""""""""" """"""""""""

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -287,3 +287,7 @@ fieldset[disabled] .btn-success.active {
.btn-success .badge { .btn-success .badge {
color: #5cb85c; color: #5cb85c;
} }
.tooltip-inner {
white-space: normal;
}

View File

@ -2389,6 +2389,9 @@ $LANG = array(
'currency_peruvian_sol' => 'Peruvian Sol', 'currency_peruvian_sol' => 'Peruvian Sol',
'use_english_version' => 'Make sure to use the English version of the files.<br/>We use the column headers to match the fields.', 'use_english_version' => 'Make sure to use the English version of the files.<br/>We use the column headers to match the fields.',
'tax1' => 'First Tax',
'tax2' => 'Second Tax',
'fee_help' => 'Gateway fees are the costs charged for access to the financial networks that handle the processing of online payments.',
'download_pdf' => 'Download PDF' 'download_pdf' => 'Download PDF'
); );

View File

@ -36,7 +36,7 @@
<center class="buttons"> <center class="buttons">
{!! Button::normal(trans('texts.cancel'))->large()->asLinkTo(url('/expense_categories'))->appendIcon(Icon::create('remove-circle')) !!} {!! Button::normal(trans('texts.cancel'))->large()->asLinkTo(HTMLUtils::previousUrl('/expense_categories'))->appendIcon(Icon::create('remove-circle')) !!}
{!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!} {!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!}
@if ($category && Auth::user()->can('create', ENTITY_EXPENSE)) @if ($category && Auth::user()->can('create', ENTITY_EXPENSE))
{!! Button::primary(trans('texts.new_expense'))->large() {!! Button::primary(trans('texts.new_expense'))->large()

View File

@ -190,8 +190,6 @@
} }
}); });
$('[data-toggle="tooltip"]').tooltip();
// set timeout onDomReady // set timeout onDomReady
setTimeout(delayedFragmentTargetOffset, 500); setTimeout(delayedFragmentTargetOffset, 500);

View File

@ -1,6 +1,6 @@
<thead {!! $isTasks ? 'style="display:none;" data-bind="visible: $root.hasTasks"' : '' !!}> <thead {!! $isTasks ? 'style="display:none;" data-bind="visible: $root.hasTasks"' : '' !!}>
@if ($isTasks) @if ($isTasks)
<tr><td style="20px"></td></tr> <tr><td style="20px" colspan="20"></td></tr>
@endif @endif
<tr> <tr>
<th style="min-width:32px;" class="hide-border"></th> <th style="min-width:32px;" class="hide-border"></th>

View File

@ -128,7 +128,7 @@
@if (count($paymentTypes) > 1) @if (count($paymentTypes) > 1)
{!! DropdownButton::success(trans('texts.pay_now'))->withContents($paymentTypes)->large() !!} {!! DropdownButton::success(trans('texts.pay_now'))->withContents($paymentTypes)->large() !!}
@elseif (count($paymentTypes) == 1) @elseif (count($paymentTypes) == 1)
<a href='{!! $paymentURL !!}' class="btn btn-success btn-lg">{{ trans('texts.pay_now') }} {{ $invoice->present()->gatewayFee($gatewayTypeId) }}</a> <a href='{!! $paymentURL !!}' class="btn btn-success btn-lg">{{ trans('texts.pay_now') }} {!! $invoice->present()->gatewayFee($gatewayTypeId) !!}</a>
@endif @endif
@else @else
{!! Button::normal(trans('texts.download_pdf'))->withAttributes(['onclick' => 'onDownloadClick()'])->large() !!} {!! Button::normal(trans('texts.download_pdf'))->withAttributes(['onclick' => 'onDownloadClick()'])->large() !!}

View File

@ -50,10 +50,43 @@
class="form-control pull-left" placeholder="{{ trans('texts.filter') }}" value="{{ Input::get('filter') }}"/> class="form-control pull-left" placeholder="{{ trans('texts.filter') }}" value="{{ Input::get('filter') }}"/>
@if ($entityType == ENTITY_EXPENSE) @if ($entityType == ENTITY_EXPENSE)
{!! Button::normal(trans('texts.recurring'))->asLinkTo(URL::to('/recurring_expenses'))->appendIcon(Icon::create('list')) !!} {!! DropdownButton::normal(trans('texts.recurring'))
{!! Button::normal(trans('texts.categories'))->asLinkTo(URL::to('/expense_categories'))->appendIcon(Icon::create('list')) !!} ->withAttributes(['class'=>'recurringDropdown'])
->withContents([
['label' => trans('texts.new_recurring_expense'), 'url' => url('/recurring_expenses/create')],
]
)->split() !!}
{!! DropdownButton::normal(trans('texts.categories'))
->withAttributes(['class'=>'categoriesDropdown'])
->withContents([
['label' => trans('texts.new_expense_category'), 'url' => url('/expense_categories/create')],
]
)->split() !!}
<script type="text/javascript">
$(function() {
$('.recurringDropdown:not(.dropdown-toggle)').click(function() {
window.location = '{{ url('/recurring_expenses') }}';
});
$('.categoriesDropdown:not(.dropdown-toggle)').click(function() {
window.location = '{{ url('/expense_categories') }}';
});
});
</script>
@elseif ($entityType == ENTITY_TASK) @elseif ($entityType == ENTITY_TASK)
{!! Button::normal(trans('texts.projects'))->asLinkTo(URL::to('/projects'))->appendIcon(Icon::create('list')) !!} {!! DropdownButton::normal(trans('texts.projects'))
->withAttributes(['class'=>'projectsDropdown'])
->withContents([
['label' => trans('texts.new_project'), 'url' => url('/projects/create')],
]
)->split() !!}
<script type="text/javascript">
$(function() {
$('.projectsDropdown:not(.dropdown-toggle)').click(function() {
window.location = '{{ url('projects') }}';
});
});
</script>
@endif @endif
@if (Auth::user()->can('create', $entityType) && empty($vendorId)) @if (Auth::user()->can('create', $entityType) && empty($vendorId))

View File

@ -268,6 +268,8 @@
@endif @endif
@endif @endif
$('[data-toggle="tooltip"]').tooltip();
@if (Session::has('onReady')) @if (Session::has('onReady'))
{{ Session::get('onReady') }} {{ Session::get('onReady') }}
@endif @endif

View File

@ -48,7 +48,7 @@
<center class="buttons"> <center class="buttons">
{!! Button::normal(trans('texts.cancel'))->large()->asLinkTo(url('/projects'))->appendIcon(Icon::create('remove-circle')) !!} {!! Button::normal(trans('texts.cancel'))->large()->asLinkTo(HTMLUtils::previousUrl('/projects'))->appendIcon(Icon::create('remove-circle')) !!}
{!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!} {!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!}
@if ($project && Auth::user()->can('create', ENTITY_TASK)) @if ($project && Auth::user()->can('create', ENTITY_TASK))
{!! Button::primary(trans('texts.new_task'))->large() {!! Button::primary(trans('texts.new_task'))->large()