1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-09 20:52:56 +01:00

Add bulk invoice button to products

This commit is contained in:
Hillel Coren 2017-11-03 10:19:03 +02:00
parent d5411e3f08
commit a5f4a369ab
17 changed files with 129 additions and 101 deletions

View File

@ -159,7 +159,16 @@ class ProductController extends BaseController
{ {
$action = Input::get('action'); $action = Input::get('action');
$ids = Input::get('public_id') ? Input::get('public_id') : Input::get('ids'); $ids = Input::get('public_id') ? Input::get('public_id') : Input::get('ids');
$count = $this->productService->bulk($ids, $action);
if ($action == 'invoice') {
$products = Product::scope($ids)->get();
foreach ($products as $product) {
$data[] = $product->product_key;
}
return redirect("invoices/create")->with('selectedProducts', $data);
} else {
$count = $this->productService->bulk($ids, $action);
}
$message = Utils::pluralize($action.'d_product', $count); $message = Utils::pluralize($action.'d_product', $count);
Session::flash('message', $message); Session::flash('message', $message);

View File

@ -16,7 +16,7 @@ class ActivityDatatable extends EntityDatatable
function ($model) { function ($model) {
$str = Utils::timestampToDateTimeString(strtotime($model->created_at)); $str = Utils::timestampToDateTimeString(strtotime($model->created_at));
if ($model->contact_id && $model->ip != '127.0.0.1') { if ($model->contact_id && ! in_array($model->ip, ['127.0.0.1', '192.168.255.33'])) {
$ipLookUpLink = IP_LOOKUP_URL . $model->ip; $ipLookUpLink = IP_LOOKUP_URL . $model->ip;
$str .= sprintf(' &nbsp; <i class="fa fa-globe" style="cursor:pointer" title="%s" onclick="openUrl(\'%s\', \'IP Lookup\')"></i>', $model->ip, $ipLookUpLink); $str .= sprintf(' &nbsp; <i class="fa fa-globe" style="cursor:pointer" title="%s" onclick="openUrl(\'%s\', \'IP Lookup\')"></i>', $model->ip, $ipLookUpLink);
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -28,7 +28,7 @@ border-bottom: 1px solid #dfe0e1;
.redlink:hover { color:#c13b25; } .redlink:hover { color:#c13b25; }
.buttons { margin: 25px 0; } .buttons { margin: 25px 0; }
.buttons .btn { margin: 0 6px; } .buttons .btn { margin: 0 4px; }
/*forms*/ /*forms*/
.form-group { .form-group {

View File

@ -179,41 +179,40 @@
</div> </div>
</div> </div>
<p/>&nbsp;<p/>
@if (Auth::user()->hasFeature(FEATURE_EXPENSES)) @if (Auth::user()->hasFeature(FEATURE_EXPENSES))
{!! Former::actions( <center class="buttons">
count(Cache::get('banks')) > 0 ? {!! count(Cache::get('banks')) > 0 ?
Button::normal(trans('texts.cancel')) Button::normal(trans('texts.cancel'))
->withAttributes([ ->withAttributes([
'data-bind' => 'visible: !importResults()', 'data-bind' => 'visible: !importResults()',
]) ])
->large() ->large()
->asLinkTo(URL::to('/settings/bank_accounts')) ->asLinkTo(URL::to('/settings/bank_accounts'))
->appendIcon(Icon::create('remove-circle')) : false, ->appendIcon(Icon::create('remove-circle')) : false !!}
Button::success(trans('texts.validate')) {!! Button::success(trans('texts.validate'))
->withAttributes([ ->withAttributes([
'data-bind' => 'css: {disabled: disableValidate}, visible: page() == "login"', 'data-bind' => 'css: {disabled: disableValidate}, visible: page() == "login"',
'onclick' => 'validate()' 'onclick' => 'validate()'
]) ])
->large() ->large()
->appendIcon(Icon::create('lock')), ->appendIcon(Icon::create('lock')) !!}
Button::success(trans('texts.save')) {!! Button::success(trans('texts.save'))
->withAttributes([ ->withAttributes([
'data-bind' => 'css: {disabled: disableSave}, visible: page() == "setup"', 'data-bind' => 'css: {disabled: disableSave}, visible: page() == "setup"',
'style' => 'display:none', 'style' => 'display:none',
'onclick' => 'save()' 'onclick' => 'save()'
]) ])
->large() ->large()
->appendIcon(Icon::create('floppy-disk')) , ->appendIcon(Icon::create('floppy-disk')) !!}
Button::success(trans('texts.import')) {!! Button::success(trans('texts.import'))
->withAttributes([ ->withAttributes([
'data-bind' => 'css: {disabled: disableSaveExpenses}, visible: page() == "import"', 'data-bind' => 'css: {disabled: disableSaveExpenses}, visible: page() == "import"',
'style' => 'display:none', 'style' => 'display:none',
'onclick' => 'saveExpenses()' 'onclick' => 'saveExpenses()'
]) ])
->large() ->large()
->appendIcon(Icon::create('floppy-disk'))) !!} ->appendIcon(Icon::create('floppy-disk')) !!}
</center>
@endif @endif
{!! Former::close() !!} {!! Former::close() !!}

View File

@ -305,25 +305,22 @@
</div> </div>
</div> </div>
<center class="buttons">
<br/> {!! $account->getCustomDesign(CUSTOM_DESIGN1) ?
{!! Former::actions(
$account->getCustomDesign(CUSTOM_DESIGN1) ?
DropdownButton::primary(trans('texts.customize')) DropdownButton::primary(trans('texts.customize'))
->withContents($account->present()->customDesigns) ->withContents($account->present()->customDesigns)
->large() : ->large() :
Button::primary(trans('texts.customize')) Button::primary(trans('texts.customize'))
->appendIcon(Icon::create('edit')) ->appendIcon(Icon::create('edit'))
->asLinkTo(URL::to('/settings/customize_design') . '?design_id=' . CUSTOM_DESIGN1) ->asLinkTo(URL::to('/settings/customize_design') . '?design_id=' . CUSTOM_DESIGN1)
->large(), ->large() !!}
Auth::user()->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN) ? {!! Auth::user()->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN) ?
Button::success(trans('texts.save')) Button::success(trans('texts.save'))
->submit()->large() ->submit()->large()
->appendIcon(Icon::create('floppy-disk')) ->appendIcon(Icon::create('floppy-disk'))
->withAttributes(['class' => 'save-button']) : ->withAttributes(['class' => 'save-button']) :
false false !!}
) !!} </center>
<br/>
{!! Former::close() !!} {!! Former::close() !!}

View File

@ -55,10 +55,11 @@
</div> </div>
{!! Former::actions( <center class="buttons">
Button::success(trans('texts.save')) {!! Button::success(trans('texts.save'))
->submit()->large() ->submit()->large()
->appendIcon(Icon::create('floppy-disk'))) !!} ->appendIcon(Icon::create('floppy-disk')) !!}
</center>
{!! Former::close() !!} {!! Former::close() !!}

View File

@ -1,58 +1,58 @@
@extends('header') @extends('header')
@section('content') @section('content')
@parent @parent
{!! Former::open($url)->method($method) {!! Former::open($url)
->rules(['product_key' => 'required|max:255']) ->method($method)
->addClass('col-md-10 col-md-offset-1 warn-on-exit') !!} ->rules(['product_key' => 'required|max:255'])
->addClass('col-md-10 col-md-offset-1 warn-on-exit') !!}
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{!! $title !!}</h3>
</div>
<div class="panel-body form-padding-right">
<div class="panel panel-default"> @if ($product)
<div class="panel-heading"> {{ Former::populate($product) }}
<h3 class="panel-title">{!! $title !!}</h3> {{ Former::populateField('cost', Utils::roundSignificant($product->cost)) }}
</div> @endif
<div class="panel-body form-padding-right">
@if ($product) {!! Former::text('product_key')->label('texts.product') !!}
{{ Former::populate($product) }} {!! Former::textarea('notes')->rows(6) !!}
{{ Former::populateField('cost', Utils::roundSignificant($product->cost)) }}
@endif
{!! Former::text('product_key')->label('texts.product') !!} @if ($account->hasFeature(FEATURE_INVOICE_SETTINGS))
{!! Former::textarea('notes')->rows(6) !!} @if ($account->custom_invoice_item_label1)
{!! Former::text('custom_value1')->label(e($account->custom_invoice_item_label1)) !!}
@endif
@if ($account->custom_invoice_item_label2)
{!! Former::text('custom_value2')->label(e($account->custom_invoice_item_label2)) !!}
@endif
@endif
@if ($account->hasFeature(FEATURE_INVOICE_SETTINGS)) {!! Former::text('cost') !!}
@if ($account->custom_invoice_item_label1)
{!! Former::text('custom_value1')->label(e($account->custom_invoice_item_label1)) !!}
@endif
@if ($account->custom_invoice_item_label2)
{!! Former::text('custom_value2')->label(e($account->custom_invoice_item_label2)) !!}
@endif
@endif
{!! Former::text('cost') !!} @if ($account->invoice_item_taxes)
@include('partials.tax_rates')
@endif
@if ($account->invoice_item_taxes) </div>
@include('partials.tax_rates') </div>
@endif
</div> <center class="buttons">
</div> {!! Button::normal(trans('texts.cancel'))->large()->asLinkTo(HTMLUtils::previousUrl('/products'))->appendIcon(Icon::create('remove-circle')) !!}
{!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!}
</center>
{!! Former::actions( {!! Former::close() !!}
Button::normal(trans('texts.cancel'))->large()->asLinkTo(HTMLUtils::previousUrl('/products'))->appendIcon(Icon::create('remove-circle')),
Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk'))
) !!}
{!! Former::close() !!} <script type="text/javascript">
<script type="text/javascript"> $(function() {
$('#product_key').focus();
});
$(function() { </script>
$('#product_key').focus();
});
</script>
@stop @stop

View File

@ -39,10 +39,10 @@
</div> </div>
</div> </div>
{!! Former::actions( <center class="buttons">
Button::normal(trans('texts.cancel'))->large()->asLinkTo(URL::to('/settings/tax_rates'))->appendIcon(Icon::create('remove-circle')), {!! Button::normal(trans('texts.cancel'))->large()->asLinkTo(URL::to('/settings/tax_rates'))->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')) !!}
) !!} </center>
{!! Former::close() !!} {!! Former::close() !!}

View File

@ -1,6 +1,6 @@
@extends('header') @extends('header')
@section('content') @section('content')
@parent @parent
@include('accounts.nav', ['selected' => ACCOUNT_API_TOKENS]) @include('accounts.nav', ['selected' => ACCOUNT_API_TOKENS])
@ -15,7 +15,7 @@
<div class="panel-body form-padding-right"> <div class="panel-body form-padding-right">
@if ($token) @if ($token)
{!! Former::populate($token) !!} {!! Former::populate($token) !!}
@endif @endif
{!! Former::text('name') !!} {!! Former::text('name') !!}
@ -24,10 +24,10 @@
</div> </div>
@if (Auth::user()->hasFeature(FEATURE_API)) @if (Auth::user()->hasFeature(FEATURE_API))
{!! Former::actions( <center class="buttons">
Button::normal(trans('texts.cancel'))->asLinkTo(URL::to('/settings/api_tokens'))->appendIcon(Icon::create('remove-circle'))->large(), {!! Button::normal(trans('texts.cancel'))->asLinkTo(URL::to('/settings/api_tokens'))->appendIcon(Icon::create('remove-circle'))->large() !!}
Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) {!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!}
) !!} </center>
@else @else
<script> <script>
$(function() { $(function() {
@ -35,7 +35,7 @@
}); });
</script> </script>
@endif @endif
{!! Former::close() !!} {!! Former::close() !!}
@ -43,4 +43,4 @@
@section('onReady') @section('onReady')
$('#name').focus(); $('#name').focus();
@stop @stop

View File

@ -96,7 +96,7 @@
@include('accounts.partials.notifications') @include('accounts.partials.notifications')
@endif @endif
<center> <center class="buttons">
@if (Auth::user()->confirmed) @if (Auth::user()->confirmed)
{!! Button::primary(trans('texts.change_password')) {!! Button::primary(trans('texts.change_password'))
->appendIcon(Icon::create('lock')) ->appendIcon(Icon::create('lock'))

View File

@ -503,8 +503,7 @@
</div> </div>
</div> </div>
<p>&nbsp;</p> <center class="buttons">
<div class="form-actions">
<div style="display:none"> <div style="display:none">
{!! Former::populateField('entityType', $entityType) !!} {!! Former::populateField('entityType', $entityType) !!}
@ -565,8 +564,7 @@
@endif @endif
@endif @endif
</div> </center>
<p>&nbsp;</p>
@include('invoices.pdf', ['account' => Auth::user()->account, 'hide_pdf' => ! Auth::user()->account->live_preview]) @include('invoices.pdf', ['account' => Auth::user()->account, 'hide_pdf' => ! Auth::user()->account->live_preview])
@ -913,6 +911,7 @@
item.task_public_id(task.publicId); item.task_public_id(task.publicId);
} }
model.invoice().has_tasks(true); model.invoice().has_tasks(true);
NINJA.formIsChanged = true;
@endif @endif
@if (isset($expenses) && $expenses) @if (isset($expenses) && $expenses)
@ -937,8 +936,31 @@
} }
model.invoice().invoice_items_without_tasks.push(blank); model.invoice().invoice_items_without_tasks.push(blank);
model.invoice().has_expenses(true); model.invoice().has_expenses(true);
NINJA.formIsChanged = true;
@endif @endif
@if ($selectedProducts = session('selectedProducts'))
// move the blank invoice line item to the end
var blank = model.invoice().invoice_items_without_tasks.pop();
var productMap = {};
for (var i=0; i<products.length; i++) {
var product = products[i];
productMap[product.product_key] = product;
}
var selectedProducts = {!! json_encode($selectedProducts) !!}
for (var i=0; i<selectedProducts.length; i++) {
var productKey = selectedProducts[i];
product = productMap[productKey];
if (product) {
var item = model.invoice().addItem();
item.loadData(product);
item.qty(1);
}
}
model.invoice().invoice_items_without_tasks.push(blank);
NINJA.formIsChanged = true;
@endif
@endif @endif
// display blank instead of '0' // display blank instead of '0'

View File

@ -864,7 +864,7 @@ function ItemModel(data) {
owner: this owner: this
}); });
if (data) { self.loadData = function(data) {
ko.mapping.fromJS(data, {}, this); ko.mapping.fromJS(data, {}, this);
var precision = getPrecision(this.cost()); var precision = getPrecision(this.cost());
var cost = parseFloat(this.cost()); var cost = parseFloat(this.cost());
@ -876,6 +876,10 @@ function ItemModel(data) {
this.qty(roundSignificant(this.qty())); this.qty(roundSignificant(this.qty()));
} }
if (data) {
self.loadData(data);
}
this.totals = ko.observable(); this.totals = ko.observable();
this.totals.rawTotal = ko.computed(function() { this.totals.rawTotal = ko.computed(function() {

View File

@ -8,14 +8,11 @@
</div> </div>
<div class="pull-left"> <div class="pull-left">
@can('create', 'invoice') @if (in_array($entityType, [ENTITY_TASK, ENTITY_INVOICE, ENTITY_PRODUCT]))
@if ($entityType == ENTITY_TASK) @can('create', 'invoice')
{!! Button::primary(trans('texts.invoice'))->withAttributes(['class'=>'invoice', 'onclick' =>'submitForm_'.$entityType.'("invoice")'])->appendIcon(Icon::create('check')) !!} {!! Button::primary(trans('texts.invoice'))->withAttributes(['class'=>'invoice', 'onclick' =>'submitForm_'.$entityType.'("invoice")'])->appendIcon(Icon::create('check')) !!}
@endif @endcan
@if ($entityType == ENTITY_EXPENSE) @endif
{!! Button::primary(trans('texts.invoice'))->withAttributes(['class'=>'invoice', 'onclick' =>'submitForm_'.$entityType.'("invoice")'])->appendIcon(Icon::create('check')) !!}
@endif
@endcan
{!! DropdownButton::normal(trans('texts.archive')) {!! DropdownButton::normal(trans('texts.archive'))
->withContents($datatable->bulkActions()) ->withContents($datatable->bulkActions())

View File

@ -171,7 +171,7 @@
@endif @endif
<center> <center class="buttons">
{!! DropdownButton::primary(trans('texts.export')) {!! DropdownButton::primary(trans('texts.export'))
->large() ->large()
->withAttributes(array('id' => 'export-button')) ->withAttributes(array('id' => 'export-button'))
@ -185,8 +185,7 @@
->submit() ->submit()
->appendIcon(Icon::create('play')) ->appendIcon(Icon::create('play'))
->large() !!} ->large() !!}
</center><br/> </center>
{!! Former::close() !!} {!! Former::close() !!}

View File

@ -77,11 +77,11 @@
</div> </div>
</div> </div>
{!! Former::actions( <center class="buttons">
Button::normal(trans('texts.cancel'))->asLinkTo(URL::to('/settings/user_management'))->appendIcon(Icon::create('remove-circle'))->large(), {!! Button::normal(trans('texts.cancel'))->asLinkTo(URL::to('/settings/user_management'))->appendIcon(Icon::create('remove-circle'))->large() !!}
($user) ? Button::success(trans('texts.save'))->withAttributes(['onclick' => 'submitAction("save")'])->large()->appendIcon(Icon::create('floppy-disk')) : false, {!! ($user) ? Button::success(trans('texts.save'))->withAttributes(['onclick' => 'submitAction("save")'])->large()->appendIcon(Icon::create('floppy-disk')) : false !!}
(! $user || ! $user->confirmed) ? Button::info(trans($user ? 'texts.resend_invite' : 'texts.send_invite'))->withAttributes(['onclick' => 'submitAction("email")'])->large()->appendIcon(Icon::create('send')) : false {!! (! $user || ! $user->confirmed) ? Button::info(trans($user ? 'texts.resend_invite' : 'texts.send_invite'))->withAttributes(['onclick' => 'submitAction("email")'])->large()->appendIcon(Icon::create('send')) : false !!}
)!!} </center>
{!! Former::close() !!} {!! Former::close() !!}