mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-08 12:12:48 +01:00
Working on statements
This commit is contained in:
parent
afda597198
commit
fb469240a0
@ -34,7 +34,7 @@ class UpdateInvoiceAPIRequest extends InvoiceRequest
|
||||
$invoiceId = $this->entity()->id;
|
||||
|
||||
$rules = [
|
||||
'invoice_items' => 'required|valid_invoice_items',
|
||||
'invoice_items' => 'valid_invoice_items',
|
||||
'invoice_number' => 'unique:invoices,invoice_number,' . $invoiceId . ',id,account_id,' . $this->user()->account_id,
|
||||
'discount' => 'positive',
|
||||
//'invoice_date' => 'date',
|
||||
|
@ -31,7 +31,7 @@ class UpdateInvoiceRequest extends InvoiceRequest
|
||||
|
||||
$rules = [
|
||||
'client' => 'required',
|
||||
'invoice_items' => 'required|valid_invoice_items',
|
||||
'invoice_items' => 'valid_invoice_items',
|
||||
'invoice_number' => 'required|unique:invoices,invoice_number,' . $invoiceId . ',id,account_id,' . $this->user()->account_id,
|
||||
'discount' => 'positive',
|
||||
'invoice_date' => 'required',
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Jobs\Client;
|
||||
|
||||
use App\Models\Invoice;
|
||||
use App\Models\Payment;
|
||||
|
||||
class GenerateStatementData
|
||||
{
|
||||
@ -22,20 +23,29 @@ class GenerateStatementData
|
||||
$client = $this->client;
|
||||
$account = $client->account;
|
||||
|
||||
$options = $this->options;
|
||||
$statusId = intval($options['status_id']);
|
||||
$startDate = $options['start_date'];
|
||||
$endDate = $options['end_date'];
|
||||
|
||||
$invoice = $account->createInvoice(ENTITY_INVOICE);
|
||||
$invoice->client = $client;
|
||||
$invoice->date_format = $account->date_format ? $account->date_format->format_moment : 'MMM D, YYYY';
|
||||
|
||||
$invoice->invoice_items = $this->getInvoices();
|
||||
|
||||
if ($this->options['show_payments']) {
|
||||
$invoice->invoice_items = $invoice->invoice_items->merge($this->getPayments());
|
||||
}
|
||||
|
||||
return json_encode($invoice);
|
||||
}
|
||||
|
||||
private function getInvoices()
|
||||
{
|
||||
$statusId = intval($this->options['status_id']);
|
||||
|
||||
$invoices = Invoice::scope()
|
||||
->with(['client'])
|
||||
->invoices()
|
||||
->whereClientId($client->id)
|
||||
->whereClientId($this->client->id)
|
||||
->whereIsPublic(true)
|
||||
->withArchived()
|
||||
->orderBy('invoice_date', 'asc');
|
||||
|
||||
if ($statusId == INVOICE_STATUS_PAID) {
|
||||
@ -45,12 +55,27 @@ class GenerateStatementData
|
||||
}
|
||||
|
||||
if ($statusId == INVOICE_STATUS_PAID || ! $statusId) {
|
||||
$invoices->where('invoice_date', '>=', $startDate)
|
||||
->where('invoice_date', '<=', $endDate);
|
||||
$invoices->where('invoice_date', '>=', $this->options['start_date'])
|
||||
->where('invoice_date', '<=', $this->options['end_date']);
|
||||
}
|
||||
|
||||
$invoice->invoice_items = $invoices->get();
|
||||
return $invoices->get();
|
||||
}
|
||||
|
||||
private function getPayments()
|
||||
{
|
||||
$payments = Payment::scope()
|
||||
->with('invoice', 'payment_type')
|
||||
->withArchived()
|
||||
->whereClientId($this->client->id)
|
||||
->where('payment_date', '>=', $this->options['start_date'])
|
||||
->where('payment_date', '<=', $this->options['end_date']);
|
||||
|
||||
return $payments->get();
|
||||
}
|
||||
|
||||
private function getAging()
|
||||
{
|
||||
|
||||
return json_encode($invoice);
|
||||
}
|
||||
}
|
||||
|
@ -337,6 +337,10 @@ trait PresentsInvoice
|
||||
'custom_value2',
|
||||
'delivery_note',
|
||||
'date',
|
||||
'method',
|
||||
'payment_date',
|
||||
'reference',
|
||||
'amount',
|
||||
];
|
||||
|
||||
foreach ($fields as $field) {
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -15,8 +15,9 @@ NINJA.TEMPLATES = {
|
||||
|
||||
function GetPdfMake(invoice, javascript, callback) {
|
||||
var itemsTable = false;
|
||||
|
||||
// check if we need to add a second table for tasks
|
||||
if (invoice.hasTasks) {
|
||||
// check if we need to add a second table for tasks
|
||||
if (invoice.hasSecondTable) {
|
||||
var json = JSON.parse(javascript);
|
||||
for (var i=0; i<json.content.length; i++) {
|
||||
@ -36,6 +37,16 @@ function GetPdfMake(invoice, javascript, callback) {
|
||||
javascript = javascript.replace('$invoiceLineItems', '$taskLineItems');
|
||||
javascript = javascript.replace('$invoiceLineItemColumns', '$taskLineItemColumns');
|
||||
}
|
||||
} else if (invoice.is_statement) {
|
||||
var json = JSON.parse(javascript);
|
||||
for (var i=0; i<json.content.length; i++) {
|
||||
var item = json.content[i];
|
||||
if (item.table && item.table.body == '$invoiceLineItems') {
|
||||
json.content.splice(i, 2);
|
||||
json.content.splice(i, 0, "$statementDetails");
|
||||
}
|
||||
}
|
||||
javascript = JSON.stringify(json);
|
||||
}
|
||||
|
||||
javascript = NINJA.decodeJavascript(invoice, javascript);
|
||||
@ -244,18 +255,19 @@ NINJA.decodeJavascript = function(invoice, javascript)
|
||||
'accountAddress': NINJA.accountAddress(invoice),
|
||||
'invoiceDetails': NINJA.invoiceDetails(invoice),
|
||||
'invoiceDetailsHeight': (NINJA.invoiceDetails(invoice).length * 16) + 16,
|
||||
'invoiceLineItems': invoice.is_statement ? NINJA.statementLines(invoice) : NINJA.invoiceLines(invoice),
|
||||
'invoiceLineItemColumns': invoice.is_statement ? NINJA.statementColumns(invoice) : NINJA.invoiceColumns(invoice, javascript),
|
||||
'invoiceLineItems': NINJA.invoiceLines(invoice),
|
||||
'invoiceLineItemColumns': NINJA.invoiceColumns(invoice, javascript),
|
||||
'taskLineItems': NINJA.invoiceLines(invoice, true),
|
||||
'taskLineItemColumns': NINJA.invoiceColumns(invoice, javascript, true),
|
||||
'invoiceDocuments' : NINJA.invoiceDocuments(invoice),
|
||||
'quantityWidth': NINJA.quantityWidth(invoice),
|
||||
'taxWidth': NINJA.taxWidth(invoice),
|
||||
'clientDetails': NINJA.clientDetails(invoice),
|
||||
'statementDetails': NINJA.statementDetails(invoice),
|
||||
'notesAndTerms': NINJA.notesAndTerms(invoice),
|
||||
'subtotals': invoice.is_statement ? NINJA.statementSubtotals(invoice) : NINJA.subtotals(invoice),
|
||||
'subtotals': NINJA.subtotals(invoice),
|
||||
'subtotalsHeight': (NINJA.subtotals(invoice).length * 16) + 16,
|
||||
'subtotalsWithoutBalance': invoice.is_statement ? [[]] : NINJA.subtotals(invoice, true),
|
||||
'subtotalsWithoutBalance': NINJA.subtotals(invoice, true),
|
||||
'subtotalsBalance': NINJA.subtotalsBalance(invoice),
|
||||
'balanceDue': formatMoneyInvoice(invoice.balance_amount, invoice),
|
||||
'invoiceFooter': NINJA.invoiceFooter(invoice),
|
||||
@ -402,6 +414,123 @@ NINJA.decodeJavascript = function(invoice, javascript)
|
||||
return javascript;
|
||||
}
|
||||
|
||||
NINJA.statementDetails = function(invoice) {
|
||||
if (! invoice.is_statement) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var data = {
|
||||
"stack": []
|
||||
};
|
||||
|
||||
var table = {
|
||||
"style": "invoiceLineItemsTable",
|
||||
"table": {
|
||||
"headerRows": 1,
|
||||
"widths": false,
|
||||
"body": false,
|
||||
},
|
||||
"layout": {
|
||||
"hLineWidth": "$notFirst:.5",
|
||||
"vLineWidth": "$none",
|
||||
"hLineColor": "#D8D8D8",
|
||||
"paddingLeft": "$amount:8",
|
||||
"paddingRight": "$amount:8",
|
||||
"paddingTop": "$amount:14",
|
||||
"paddingBottom": "$amount:14"
|
||||
}
|
||||
};
|
||||
|
||||
var hasPayments = false;
|
||||
var hasAging = false;
|
||||
for (var i = 0; i < invoice.invoice_items.length; i++) {
|
||||
var item = invoice.invoice_items[i];
|
||||
if (! item.invoice_number) {
|
||||
if (item.invoice_id) {
|
||||
hasPayments = true;
|
||||
} else {
|
||||
hasAging = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var clone = JSON.parse(JSON.stringify(table));
|
||||
clone.table.body = NINJA.prepareDataTable(NINJA.statementInvoices(invoice), 'invoiceItems');
|
||||
clone.table.widths = ["22%", "22%", "22%", "17%", "17%"];
|
||||
data.stack.push(clone);
|
||||
|
||||
if (hasPayments) {
|
||||
var clone = JSON.parse(JSON.stringify(table));
|
||||
clone.table.body = NINJA.prepareDataTable(NINJA.statementPayments(invoice), 'invoiceItems');
|
||||
clone.table.widths = ["22%", "22%", "39%", "17%"];
|
||||
data.stack.push(clone);
|
||||
}
|
||||
|
||||
if (hasAging) {
|
||||
var clone = JSON.parse(JSON.stringify(table));
|
||||
clone.table.body = NINJA.prepareDataTable(NINJA.statementAging(invoice), 'invoiceItems');
|
||||
data.stack.push(clone);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
NINJA.statementInvoices = function(invoice) {
|
||||
var grid = [[]];
|
||||
grid[0].push({text: invoiceLabels.invoice_number, style: ['tableHeader', 'itemTableHeader']});
|
||||
grid[0].push({text: invoiceLabels.invoice_date, style: ['tableHeader', 'invoiceDateTableHeader']});
|
||||
grid[0].push({text: invoiceLabels.due_date, style: ['tableHeader', 'dueDateTableHeader']});
|
||||
grid[0].push({text: invoiceLabels.total, style: ['tableHeader', 'totalTableHeader']});
|
||||
grid[0].push({text: invoiceLabels.balance, style: ['tableHeader', 'balanceTableHeader']});
|
||||
|
||||
for (var i = 0; i < invoice.invoice_items.length; i++) {
|
||||
var item = invoice.invoice_items[i];
|
||||
if (! item.invoice_number) {
|
||||
continue;
|
||||
}
|
||||
var rowStyle = (i % 2 == 0) ? 'odd' : 'even';
|
||||
grid.push([
|
||||
{text: item.invoice_number, style:['invoiceNumber', 'productKey', rowStyle]},
|
||||
{text: item.invoice_date && item.invoice_date != '0000-00-00' ? moment(item.invoice_date).format(invoice.date_format) : ' ', style:['invoiceDate', rowStyle]},
|
||||
{text: item.due_date && item.due_date != '0000-00-00' ? moment(item.due_date).format(invoice.date_format) : ' ', style:['dueDate', rowStyle]},
|
||||
{text: formatMoneyInvoice(item.amount, invoice), style:['subtotals', rowStyle]},
|
||||
{text: formatMoneyInvoice(item.balance, invoice), style:['lineTotal', rowStyle]},
|
||||
]);
|
||||
}
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
NINJA.statementPayments = function(invoice) {
|
||||
var grid = [[]];
|
||||
grid[0].push({text: invoiceLabels.invoice_number, style: ['tableHeader', 'itemTableHeader']});
|
||||
grid[0].push({text: invoiceLabels.payment_date, style: ['tableHeader', 'invoiceDateTableHeader']});
|
||||
grid[0].push({text: invoiceLabels.method, style: ['tableHeader', 'dueDateTableHeader']});
|
||||
//grid[0].push({text: invoiceLabels.reference, style: ['tableHeader', 'totalTableHeader']});
|
||||
grid[0].push({text: invoiceLabels.amount, style: ['tableHeader', 'balanceTableHeader']});
|
||||
|
||||
for (var i = 0; i < invoice.invoice_items.length; i++) {
|
||||
var item = invoice.invoice_items[i];
|
||||
if (! item.invoice_id) {
|
||||
continue;
|
||||
}
|
||||
var rowStyle = (i % 2 == 0) ? 'odd' : 'even';
|
||||
grid.push([
|
||||
{text: item.invoice.invoice_number, style:['invoiceNumber', 'productKey', rowStyle]},
|
||||
{text: item.payment_date && item.payment_date != '0000-00-00' ? moment(item.payment_date).format(invoice.date_format) : ' ', style:['invoiceDate', rowStyle]},
|
||||
{text: item.payment_type ? item.payment_type.name : ' ', style:['dueDate', rowStyle]},
|
||||
//{text: item.transaction_reference, style:['subtotals', rowStyle]},
|
||||
{text: formatMoneyInvoice(item.amount - item.refunded, invoice), style:['lineTotal', rowStyle]},
|
||||
]);
|
||||
}
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
NINJA.statementAging = function(invoice) {
|
||||
|
||||
}
|
||||
|
||||
NINJA.signature = function(invoice) {
|
||||
var invitation = NINJA.getSignatureInvitation(invoice);
|
||||
if (invitation) {
|
||||
@ -502,36 +631,6 @@ NINJA.notesAndTerms = function(invoice)
|
||||
return NINJA.prepareDataList(data, 'notesAndTerms');
|
||||
}
|
||||
|
||||
NINJA.statementColumns = function(invoice)
|
||||
{
|
||||
return ["22%", "22%", "22%", "17%", "17%"];
|
||||
}
|
||||
|
||||
NINJA.statementLines = function(invoice)
|
||||
{
|
||||
var grid = [[]];
|
||||
grid[0].push({text: invoiceLabels.invoice_number, style: ['tableHeader', 'itemTableHeader']});
|
||||
grid[0].push({text: invoiceLabels.invoice_date, style: ['tableHeader', 'invoiceDateTableHeader']});
|
||||
grid[0].push({text: invoiceLabels.due_date, style: ['tableHeader', 'dueDateTableHeader']});
|
||||
grid[0].push({text: invoiceLabels.total, style: ['tableHeader', 'totalTableHeader']});
|
||||
grid[0].push({text: invoiceLabels.balance, style: ['tableHeader', 'balanceTableHeader']});
|
||||
|
||||
for (var i = 0; i < invoice.invoice_items.length; i++) {
|
||||
var item = invoice.invoice_items[i];
|
||||
var row = [];
|
||||
var rowStyle = (i % 2 == 0) ? 'odd' : 'even';
|
||||
grid.push([
|
||||
{text: item.invoice_number, style:['invoiceNumber', 'productKey', rowStyle]},
|
||||
{text: item.invoice_date && item.invoice_date != '0000-00-00' ? moment(item.invoice_date).format(invoice.date_format) : ' ', style:['invoiceDate', rowStyle]},
|
||||
{text: item.due_date && item.due_date != '0000-00-00' ? moment(item.due_date).format(invoice.date_format) : ' ', style:['dueDate', rowStyle]},
|
||||
{text: formatMoneyInvoice(item.amount, invoice), style:['subtotals', rowStyle]},
|
||||
{text: formatMoneyInvoice(item.balance, invoice), style:['lineTotal', rowStyle]},
|
||||
]);
|
||||
}
|
||||
|
||||
return NINJA.prepareDataTable(grid, 'invoiceItems');
|
||||
}
|
||||
|
||||
NINJA.invoiceColumns = function(invoice, design, isTasks)
|
||||
{
|
||||
var account = invoice.account;
|
||||
@ -922,16 +1021,6 @@ NINJA.invoiceDocuments = function(invoice) {
|
||||
return stack.length?{stack:stack}:[];
|
||||
}
|
||||
|
||||
NINJA.statementSubtotals = function(invoice)
|
||||
{
|
||||
var data = [[
|
||||
{ text: invoiceLabels.balance_due, style: ['subtotalsLabel', 'subtotalsBalanceDueLabel'] },
|
||||
{ text: formatMoneyInvoice(invoice.balance_amount, invoice), style: ['subtotals', 'subtotalsBalanceDue'] }
|
||||
]];
|
||||
|
||||
return NINJA.prepareDataPairs(data, 'subtotals');
|
||||
}
|
||||
|
||||
NINJA.subtotals = function(invoice, hideBalance)
|
||||
{
|
||||
if (! invoice || invoice.is_delivery_note) {
|
||||
|
@ -2841,6 +2841,7 @@ $LANG = array(
|
||||
'gateway_fee_description' => 'Gateway Fee Surcharge',
|
||||
'show_payments' => 'Show Payments',
|
||||
'show_aging' => 'Show Aging',
|
||||
'reference' => 'Reference',
|
||||
|
||||
);
|
||||
|
||||
|
@ -102,8 +102,8 @@
|
||||
'?status_id=' + statusId +
|
||||
'&start_date=' + statementStartDate.format('YYYY-MM-DD') +
|
||||
'&end_date=' + statementEndDate.format('YYYY-MM-DD') +
|
||||
'&show_payments=' + $('#show_payments').is(':checked') +
|
||||
'&show_aging=' + $('#show_aging').is(':checked') +
|
||||
'&show_payments=' + ($('#show_payments').is(':checked') ? '1' : '') +
|
||||
'&show_aging=' + ($('#show_aging').is(':checked') ? '1' : '') +
|
||||
'&json=true';
|
||||
console.log(url);
|
||||
|
||||
|
@ -123,6 +123,7 @@
|
||||
throw exception;
|
||||
}
|
||||
@else
|
||||
console.log(exception);
|
||||
console.warn('Failed to generate PDF: %s', exception.message);
|
||||
var href = location.href;
|
||||
if (href.indexOf('/view/') > 0 && href.indexOf('phantomjs') == -1) {
|
||||
|
Loading…
Reference in New Issue
Block a user