mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-08 12:12:48 +01:00
Creating re-usable products from invoice line items
This commit is contained in:
parent
7b41fbc779
commit
426e7838c9
@ -42,7 +42,7 @@ class InvoiceController extends \BaseController {
|
||||
$invoice = Invoice::with('invoice_items', 'client.account.account_gateways')->where('invoice_key', '=', $invoiceKey)->firstOrFail();
|
||||
$contact = null;
|
||||
|
||||
Activity::viewInvoice($invoice, $contact)
|
||||
Activity::viewInvoice($invoice, $contact);
|
||||
|
||||
return View::make('invoices.view')->with('invoice', $invoice);
|
||||
}
|
||||
@ -181,6 +181,7 @@ class InvoiceController extends \BaseController {
|
||||
'title' => 'New',
|
||||
'client' => $client,
|
||||
'account' => Auth::user()->account,
|
||||
'products' => Product::getProducts()->get(),
|
||||
'clients' => Client::where('account_id','=',Auth::user()->account_id)->get());
|
||||
return View::make('invoices.edit', $data);
|
||||
}
|
||||
@ -241,7 +242,7 @@ class InvoiceController extends \BaseController {
|
||||
|
||||
$invoice->client_id = $clientId;
|
||||
$invoice->number = Input::get('number');
|
||||
$invoice->discount = Input::get('discount');
|
||||
$invoice->discount = 0;
|
||||
$invoice->issued_on = $date->format('Y-m-d');
|
||||
$invoice->save();
|
||||
|
||||
@ -252,11 +253,17 @@ class InvoiceController extends \BaseController {
|
||||
continue;
|
||||
}
|
||||
|
||||
$product = new Product;
|
||||
$product->product_key = $item->product_key;
|
||||
$product->notes = $item->notes;
|
||||
$product->cost = $item->cost;
|
||||
$product->save();
|
||||
$product = Product::findProduct($item->product_key);
|
||||
|
||||
if (!$product)
|
||||
{
|
||||
$product = new Product;
|
||||
$product->account_id = Auth::user()->account_id;
|
||||
$product->product_key = $item->product_key;
|
||||
$product->notes = $item->notes;
|
||||
$product->cost = $item->cost;
|
||||
$product->save();
|
||||
}
|
||||
|
||||
$invoiceItem = new InvoiceItem;
|
||||
$invoiceItem->product_id = $product->id;
|
||||
@ -316,6 +323,7 @@ class InvoiceController extends \BaseController {
|
||||
'url' => 'invoices/' . $id,
|
||||
'title' => 'Edit',
|
||||
'account' => Auth::user()->account,
|
||||
'products' => Product::getProducts()->get(),
|
||||
'client' => $invoice->client,
|
||||
'clients' => Client::where('account_id','=',Auth::user()->account_id)->get());
|
||||
return View::make('invoices.edit', $data);
|
||||
|
@ -18,7 +18,7 @@ class Activity extends Eloquent
|
||||
$activity->user_id = $user->id;
|
||||
$activity->account_id = $user->account_id;
|
||||
|
||||
return $user;
|
||||
return $activity;
|
||||
}
|
||||
|
||||
public static function createClient($client)
|
||||
@ -26,7 +26,7 @@ class Activity extends Eloquent
|
||||
$activity = Activity::getBlank();
|
||||
$activity->client_id = $client->id;
|
||||
$activity->activity_type_id = ACTIVITY_TYPE_CREATE_CLIENT;
|
||||
$activity->message = $user->getFullName() . ' created client ' . $client->name;
|
||||
$activity->message = Auth::user()->getFullName() . ' created client ' . $client->name;
|
||||
$activity->save();
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ class Activity extends Eloquent
|
||||
$activity = Activity::getBlank();
|
||||
$activity->client_id = $client->id;
|
||||
$activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_CLIENT;
|
||||
$activity->message = $user->getFullName() . ' archived client ' . $client->name;
|
||||
$activity->message = Auth::user()->getFullName() . ' archived client ' . $client->name;
|
||||
$activity->save();
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@ class Activity extends Eloquent
|
||||
$activity->invoice_id = $invoice->id;
|
||||
$activity->client_id = $invoice->client_id;
|
||||
$activity->activity_type_id = ACTIVITY_TYPE_CREATE_INVOICE;
|
||||
$activity->message = $user->getFullName() . ' created invoice ' . $invoice->number;
|
||||
$activity->message = Auth::user()->getFullName() . ' created invoice ' . $invoice->number;
|
||||
$activity->save();
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ class Activity extends Eloquent
|
||||
$activity->invoice_id = $invoice->id;
|
||||
$activity->client_id = $invoice->client_id;
|
||||
$activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_INVOICE;
|
||||
$activity->message = $user->getFullName() . ' archived invoice ' . $invoice->number;
|
||||
$activity->message = Auth::user()->getFullName() . ' archived invoice ' . $invoice->number;
|
||||
$activity->save();
|
||||
}
|
||||
|
||||
@ -65,7 +65,7 @@ class Activity extends Eloquent
|
||||
$activity->invoice_id = $invoice->id;
|
||||
$activity->client_id = $invoice->client_id;
|
||||
$activity->activity_type_id = ACTIVITY_TYPE_EMAIL_INVOICE;
|
||||
$activity->message = $user->getFullName() . ' emailed invoice ' . $invoice->number . ' to ' . $contact->getFullName();
|
||||
$activity->message = Auth::user()->getFullName() . ' emailed invoice ' . $invoice->number . ' to ' . $contact->getFullName();
|
||||
$activity->save();
|
||||
}
|
||||
|
||||
@ -74,7 +74,7 @@ class Activity extends Eloquent
|
||||
if (Auth::check())
|
||||
{
|
||||
$activity = Activity::getBlank();
|
||||
$activity->message = $user->getFullName() . ' created invoice ' . $payment->transaction_reference;
|
||||
$activity->message = Auth::user()->getFullName() . ' created invoice ' . $payment->transaction_reference;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -96,7 +96,7 @@ class Activity extends Eloquent
|
||||
$activity->invoice_id = $invoice->id;
|
||||
$activity->client_id = $invoice->client_id;
|
||||
$activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_PAYMENT;
|
||||
$activity->message = $user->getFullName() . ' archived payment ' . $invoice->number;
|
||||
$activity->message = Auth::user()->getFullName() . ' archived payment ' . $invoice->number;
|
||||
$activity->save();
|
||||
}
|
||||
|
||||
|
@ -3,4 +3,22 @@
|
||||
class Product extends Eloquent
|
||||
{
|
||||
protected $softDelete = true;
|
||||
|
||||
public static function getProducts()
|
||||
{
|
||||
return Product::where('account_id','=',Auth::user()->account_id);
|
||||
}
|
||||
|
||||
public static function findProduct($key)
|
||||
{
|
||||
return Product::getProducts()->where('product_key','=',$key)->first();
|
||||
}
|
||||
|
||||
public static function getProductKeys($products)
|
||||
{
|
||||
$products = array_pluck($products, 'product_key');
|
||||
$products = array_combine($products, $products);
|
||||
|
||||
return $products;
|
||||
}
|
||||
}
|
@ -97,6 +97,10 @@ function toArray($data)
|
||||
return json_decode(json_encode((array) $data), true);
|
||||
}
|
||||
|
||||
define("ENV_DEVELOPMENT", "local");
|
||||
define("ENV_STAGING", "staging");
|
||||
define("ENV_PRODUCTION", "production");
|
||||
|
||||
define("ACCOUNT_DETAILS", "details");
|
||||
define("ACCOUNT_SETTINGS", "settings");
|
||||
define("ACCOUNT_IMPORT", "import");
|
||||
|
@ -197,7 +197,7 @@
|
||||
}
|
||||
|
||||
.invoice-table td {
|
||||
padding: 0px !important;
|
||||
padding: 2px !important;
|
||||
}
|
||||
|
||||
.invoice-table td input,
|
||||
@ -225,6 +225,7 @@
|
||||
|
||||
<body>
|
||||
|
||||
@if (App::environment() != ENV_DEVELOPMENT)
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
@ -235,6 +236,8 @@
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
@endif
|
||||
|
||||
<div class="container">
|
||||
|
||||
<p/>
|
||||
|
@ -32,7 +32,7 @@
|
||||
<p> </p>
|
||||
|
||||
<input type="text" name="items" data-bind="value: ko.toJSON(items)" style="display:none"/>
|
||||
<table class="table invoice-table" style="margin-bottom: 0px !important;">
|
||||
<table class="table invoice-table" style="margin-bottom: 0px !important">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="hide-border"></th>
|
||||
@ -51,23 +51,23 @@
|
||||
<i data-bind="visible: actionsVisible" class="fa fa-sort"></i>
|
||||
</td>
|
||||
<td style="width:120px">
|
||||
<input data-bind="value: product_key, valueUpdate: 'afterkeydown'" onchange="refreshPDF()"/>
|
||||
{{ Former::text('product_key')->useDatalist(Product::getProductKeys($products), 'product_key')->raw()->data_bind("value: product_key, valueUpdate: 'afterkeydown'")->addClass('datalist') }}
|
||||
</td>
|
||||
<td style="width:300px">
|
||||
<textarea data-bind="value: notes, valueUpdate: 'afterkeydown'" rows="1" cols="60" onchange="refreshPDF()"></textarea>
|
||||
<textarea data-bind="value: notes, valueUpdate: 'afterkeydown'" rows="1" cols="60" class="form-control" onchange="refreshPDF()"></textarea>
|
||||
</td>
|
||||
<td style="width:100px">
|
||||
<input data-bind="value: cost, valueUpdate: 'afterkeydown'" style="text-align: right" onchange="refreshPDF()"//>
|
||||
<input data-bind="value: cost, valueUpdate: 'afterkeydown'" style="text-align: right" class="form-control" onchange="refreshPDF()"//>
|
||||
</td>
|
||||
<td style="width:80px">
|
||||
<input data-bind="value: qty, valueUpdate: 'afterkeydown'" style="text-align: right" onchange="refreshPDF()"//>
|
||||
<input data-bind="value: qty, valueUpdate: 'afterkeydown'" style="text-align: right" class="form-control" onchange="refreshPDF()"//>
|
||||
</td>
|
||||
<!--
|
||||
<td style="width:100px">
|
||||
<input data-bind="value: tax, valueUpdate: 'afterkeydown'"/>
|
||||
</td>
|
||||
-->
|
||||
<td style="width:100px;background-color: #FFFFFF;text-align: right">
|
||||
<td style="width:100px;background-color: #FFFFFF;text-align: right;padding-top:9px !important">
|
||||
<span data-bind="text: total"></span>
|
||||
</td>
|
||||
<td style="width:20px; cursor:pointer" class="hide-border">
|
||||
@ -106,9 +106,8 @@
|
||||
<p> </p>
|
||||
|
||||
<!-- <textarea rows="20" cols="120" id="pdfText" onkeyup="runCode()"></textarea> -->
|
||||
<!-- <iframe frameborder="1" width="600" height="600" style="display:block;margin: 0 auto"></iframe> -->
|
||||
<iframe frameborder="1" width="92%" height="600" style="display:block;margin: 0 auto"></iframe>
|
||||
|
||||
<!-- <iframe frameborder="1" width="100%" height="600" style="display:block;margin: 0 auto"></iframe> -->
|
||||
<iframe frameborder="1" width="100%" height="500"></iframe>
|
||||
|
||||
|
||||
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
@ -159,6 +158,7 @@
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
$(function() {
|
||||
|
||||
$('#issued_on').datepicker({
|
||||
@ -192,10 +192,31 @@
|
||||
|
||||
$('#number').change(refreshPDF);
|
||||
|
||||
refreshPDF();
|
||||
|
||||
applyComboboxListeners();
|
||||
refreshPDF();
|
||||
});
|
||||
|
||||
function applyComboboxListeners() {
|
||||
var value;
|
||||
$('.datalist').on('focus', function() {
|
||||
value = $(this).val();
|
||||
}).on('blur', function() {
|
||||
if (value != $(this).val()) refreshPDF();
|
||||
}).on('input', function() {
|
||||
var key = $(this).val();
|
||||
for (var i=0; i<products.length; i++) {
|
||||
var product = products[i];
|
||||
if (product.product_key == key) {
|
||||
var model = ko.dataFor(this);
|
||||
console.log(model);
|
||||
model.notes(product.notes);
|
||||
model.cost(product.cost);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function runCode() {
|
||||
var text = $('#pdfText').val();
|
||||
eval(text);
|
||||
@ -317,6 +338,7 @@
|
||||
|
||||
self.addItem = function() {
|
||||
self.items.push(new ItemModel());
|
||||
applyComboboxListeners();
|
||||
}
|
||||
|
||||
this.rawSubtotal = ko.computed(function() {
|
||||
@ -389,9 +411,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
var products = {{ $products }};
|
||||
|
||||
window.model = new InvoiceModel();
|
||||
ko.applyBindings(model);
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
@ -21,6 +21,8 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@if (App::environment() != ENV_DEVELOPMENT)
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
@ -29,8 +31,9 @@
|
||||
|
||||
ga('create', 'UA-46031341-1', 'sketch-out.com');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
@endif
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
|
@ -302,3 +302,5 @@ function isStorageSupported() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user