1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 05:02:36 +01:00

Working on quotes

This commit is contained in:
Hillel Coren 2014-05-21 00:40:09 +03:00
parent ca4a3f24b7
commit 8049a27beb
38 changed files with 756 additions and 250 deletions

View File

@ -82,8 +82,20 @@ class ClientController extends \BaseController {
{
$client = Client::withTrashed()->scope($publicId)->with('contacts', 'size', 'industry')->firstOrFail();
Utils::trackViewed($client->getDisplayName(), ENTITY_CLIENT);
$actionLinks = [
[trans('texts.create_invoice'), URL::to('invoices/create/' . $client->public_id )],
[trans('texts.enter_payment'), URL::to('payments/create/' . $client->public_id )],
[trans('texts.enter_credit'), URL::to('credits/create/' . $client->public_id )]
];
if (Utils::isPro())
{
array_unshift($actionLinks, [trans('texts.create_quote'), URL::to('quotes/create/' . $client->public_id )]);
}
$data = array(
'actionLinks' => $actionLinks,
'showBreadcrumbs' => false,
'client' => $client,
'credit' => $client->getTotalCredit(),

View File

@ -35,11 +35,15 @@ class DashboardController extends \BaseController {
$pastDue = Invoice::scope()
->where('due_date', '<', date('Y-m-d'))
->where('balance', '>', 0)
->where('is_recurring', '=', false)
->where('is_quote', '=', false)
->orderBy('due_date', 'asc')->take(6)->get();
$upcoming = Invoice::scope()
->where('due_date', '>', date('Y-m-d'))
->where('balance', '>', 0)
->where('is_recurring', '=', false)
->where('is_quote', '=', false)
->orderBy('due_date', 'asc')->take(6)->get();
$data = [

View File

@ -125,16 +125,10 @@ class InvoiceController extends \BaseController {
return View::make('invoices.view', $data);
}
public function edit($publicId)
public function edit($publicId, $clone = false)
{
$invoice = Invoice::scope($publicId)->withTrashed()->with('invitations', 'account.country', 'client.contacts', 'client.country', 'invoice_items')->firstOrFail();
Utils::trackViewed($invoice->invoice_number . ' - ' . $invoice->client->getDisplayName(), ENTITY_INVOICE);
$invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date);
$invoice->due_date = Utils::fromSqlDate($invoice->due_date);
$invoice->start_date = Utils::fromSqlDate($invoice->start_date);
$invoice->end_date = Utils::fromSqlDate($invoice->end_date);
$invoice->is_pro = Auth::user()->isPro();
$entityType = $invoice->getEntityType();
$contactIds = DB::table('invitations')
->join('contacts', 'contacts.id', '=','invitations.contact_id')
@ -143,17 +137,38 @@ class InvoiceController extends \BaseController {
->where('invitations.deleted_at', '=', null)
->select('contacts.public_id')->lists('public_id');
if ($clone)
{
$invoice->id = null;
$invoice->invoice_number = Auth::user()->account->getNextInvoiceNumber();
$method = 'POST';
$url = "{$entityType}s";
}
else
{
Utils::trackViewed($invoice->invoice_number . ' - ' . $invoice->client->getDisplayName(), $invoice->getEntityType());
$method = 'PUT';
$url = "{$entityType}s/{$publicId}";
}
$invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date);
$invoice->due_date = Utils::fromSqlDate($invoice->due_date);
$invoice->start_date = Utils::fromSqlDate($invoice->start_date);
$invoice->end_date = Utils::fromSqlDate($invoice->end_date);
$invoice->is_pro = Auth::user()->isPro();
$data = array(
'showBreadcrumbs' => false,
'entityType' => $entityType,
'showBreadcrumbs' => $clone,
'account' => $invoice->account,
'invoice' => $invoice,
'data' => false,
'method' => 'PUT',
'method' => $method,
'invitationContactIds' => $contactIds,
'url' => 'invoices/' . $publicId,
'title' => '- ' . $invoice->invoice_number,
'url' => $url,
'title' => '- ' . trans("texts.edit_{$entityType}"),
'client' => $invoice->client);
$data = array_merge($data, self::getViewModel());
$data = array_merge($data, self::getViewModel());
// Set the invitation link on the client's contacts
$clients = $data['clients'];
@ -190,6 +205,7 @@ class InvoiceController extends \BaseController {
}
$data = array(
'entityType' => ENTITY_INVOICE,
'account' => $account,
'invoice' => null,
'data' => Input::old('data'),
@ -206,7 +222,6 @@ class InvoiceController extends \BaseController {
private static function getViewModel()
{
return [
'entityType' => ENTITY_INVOICE,
'account' => Auth::user()->account,
'products' => Product::scope()->orderBy('id')->get(array('product_key','notes','cost','qty')),
'countries' => Country::remember(DEFAULT_QUERY_CACHE)->orderBy('name')->get(),
@ -243,10 +258,11 @@ class InvoiceController extends \BaseController {
private function save($publicId = null)
{
$action = Input::get('action');
$entityType = Input::get('entityType');
if ($action == 'archive' || $action == 'delete')
{
return InvoiceController::bulk();
return InvoiceController::bulk($entityType);
}
$input = json_decode(Input::get('data'));
@ -257,7 +273,7 @@ class InvoiceController extends \BaseController {
{
Session::flash('error', trans('texts.invoice_error'));
return Redirect::to('invoices/create')
return Redirect::to("{$entityType}s/create")
->withInput()->withErrors($errors);
}
else
@ -269,7 +285,7 @@ class InvoiceController extends \BaseController {
$invoiceData = (array) $invoice;
$invoiceData['client_id'] = $client->id;
$invoice = $this->invoiceRepo->save($publicId, $invoiceData);
$invoice = $this->invoiceRepo->save($publicId, $invoiceData, $entityType);
$account = Auth::user()->account;
if ($account->invoice_taxes != $input->invoice_taxes
@ -311,7 +327,7 @@ class InvoiceController extends \BaseController {
}
}
$message = trans($publicId ? 'texts.updated_invoice' : 'texts.created_invoice');
$message = trans($publicId ? "texts.updated_{$entityType}" : "texts.created_{$entityType}");
if ($input->invoice->client->public_id == '-1')
{
$message = $message . ' ' . trans('texts.and_created_client');
@ -322,13 +338,17 @@ class InvoiceController extends \BaseController {
if ($action == 'clone')
{
return InvoiceController::cloneInvoice($publicId);
return $this->cloneInvoice($publicId);
}
else if ($action == 'convert')
{
return $this->convertQuote($publicId);
}
else if ($action == 'email')
{
if (Auth::user()->confirmed)
{
$message = trans('texts.emailed_invoice');
$message = trans("texts.emailed_{$entityType}");
$this->mailer->sendInvoice($invoice);
Session::flash('message', $message);
}
@ -344,7 +364,7 @@ class InvoiceController extends \BaseController {
Session::flash('message', $message);
}
$url = 'invoices/' . $invoice->public_id . '/edit';
$url = "{$entityType}s/" . $invoice->public_id . '/edit';
return Redirect::to($url);
}
}
@ -379,7 +399,7 @@ class InvoiceController extends \BaseController {
* @param int $id
* @return Response
*/
public function bulk()
public function bulk($entityType = ENTITY_INVOICE)
{
$action = Input::get('action');
$ids = Input::get('id') ? Input::get('id') : Input::get('ids');
@ -387,44 +407,33 @@ class InvoiceController extends \BaseController {
if ($count > 0)
{
$message = Utils::pluralize('Successfully '.$action.'d ? invoice', $count);
$message = Utils::pluralize("{$action}d_{$entityType}", $count);
Session::flash('message', $message);
}
return Redirect::to('invoices');
return Redirect::to("{$entityType}s");
}
public static function cloneInvoice($publicId)
public function convertQuote($publicId)
{
$invoice = Invoice::with('invoice_items')->scope($publicId)->firstOrFail();
$invoice = Invoice::with('invoice_items')->scope($publicId)->firstOrFail();
$clone = $this->invoiceRepo->cloneInvoice($invoice, $invoice->id);
$clone = Invoice::createNew();
$clone->balance = $invoice->amount;
foreach (['client_id', 'discount', 'invoice_date', 'due_date', 'is_recurring', 'frequency_id', 'start_date', 'end_date', 'terms', 'public_notes', 'invoice_design_id', 'tax_name', 'tax_rate', 'amount'] as $field)
{
$clone->$field = $invoice->$field;
}
if (!$clone->is_recurring)
{
$clone->invoice_number = Auth::user()->account->getNextInvoiceNumber();
}
$clone->save();
foreach ($invoice->invoice_items as $item)
{
$cloneItem = InvoiceItem::createNew();
foreach (['product_id', 'product_key', 'notes', 'cost', 'qty', 'tax_name', 'tax_rate'] as $field)
{
$cloneItem->$field = $item->$field;
}
$clone->invoice_items()->save($cloneItem);
}
Session::flash('message', trans('texts.cloned_invoice'));
Session::flash('message', trans('texts.converted_to_invoice'));
return Redirect::to('invoices/' . $clone->public_id);
}
public function cloneInvoice($publicId)
{
/*
$invoice = Invoice::with('invoice_items')->scope($publicId)->firstOrFail();
$clone = $this->invoiceRepo->cloneInvoice($invoice);
$entityType = $invoice->getEntityType();
Session::flash('message', trans('texts.cloned_invoice'));
return Redirect::to("{$entityType}s/" . $clone->public_id);
*/
return self::edit($publicId, true);
}
}

View File

@ -64,7 +64,8 @@ class PaymentController extends \BaseController
'clientPublicId' => Input::old('client') ? Input::old('client') : $clientPublicId,
'invoicePublicId' => Input::old('invoice') ? Input::old('invoice') : $invoicePublicId,
'invoice' => null,
'invoices' => Invoice::scope()->with('client', 'invoice_status')->orderBy('invoice_number')->get(),
'invoices' => Invoice::scope()->where('is_recurring', '=', false)->where('is_quote', '=', false)
->with('client', 'invoice_status')->orderBy('invoice_number')->get(),
'payment' => null,
'method' => 'POST',
'url' => "payments",
@ -84,7 +85,8 @@ class PaymentController extends \BaseController
$data = array(
'client' => null,
'invoice' => null,
'invoices' => Invoice::scope()->with('client', 'invoice_status')->orderBy('invoice_number')->get(array('public_id','invoice_number')),
'invoices' => Invoice::scope()->where('is_recurring', '=', false)->where('is_quote', '=', false)
->with('client', 'invoice_status')->orderBy('invoice_number')->get(),
'payment' => $payment,
'method' => 'PUT',
'url' => 'payments/' . $publicId,
@ -116,12 +118,10 @@ class PaymentController extends \BaseController
$gateway->$function($val);
}
/*
if (!Utils::isProd())
{
$gateway->setTestMode(true);
}
*/
return $gateway;
}
@ -307,7 +307,6 @@ class PaymentController extends \BaseController
$client->save();
}
try
{
if($paymentLibrary->id == PAYMENT_LIBRARY_OMNIPAY)

View File

@ -24,6 +24,11 @@ class QuoteController extends \BaseController {
public function index()
{
if (!Utils::isPro())
{
return Redirect::to('/invoices/create');
}
$data = [
'title' => '- Quotes',
'entityType'=>ENTITY_QUOTE,
@ -49,6 +54,11 @@ class QuoteController extends \BaseController {
public function create($clientPublicId = 0)
{
if (!Utils::isPro())
{
return Redirect::to('/invoices/create');
}
$client = null;
$invoiceNumber = Auth::user()->account->getNextInvoiceNumber();
$account = Account::with('country')->findOrFail(Auth::user()->account_id);
@ -64,7 +74,7 @@ class QuoteController extends \BaseController {
'data' => Input::old('data'),
'invoiceNumber' => $invoiceNumber,
'method' => 'POST',
'url' => 'quotes',
'url' => 'invoices',
'title' => '- New Quote',
'client' => $client);
$data = array_merge($data, self::getViewModel());
@ -90,5 +100,18 @@ class QuoteController extends \BaseController {
];
}
public function bulk()
{
$action = Input::get('action');
$ids = Input::get('id') ? Input::get('id') : Input::get('ids');
$count = $this->invoiceRepo->bulk($ids, $action);
if ($count > 0)
{
$message = Utils::pluralize("{$action}d_quote", $count);
Session::flash('message', $message);
}
return Redirect::to('quotes');
}
}

View File

@ -32,11 +32,18 @@ class ReportController extends \BaseController {
{
$records = DB::table($entityType.'s')
->select(DB::raw('sum(amount) as total, '.$groupBy.'('.$entityType.'_date) as '.$groupBy))
->where('account_id', '=', Auth::user()->account_id)
->where($entityType.'s.deleted_at', '=', null)
->where($entityType.'s.'.$entityType.'_date', '>=', $startDate->format('Y-m-d'))
->where($entityType.'s.'.$entityType.'_date', '<=', $endDate->format('Y-m-d'))
->groupBy($groupBy);
if ($entityType == ENTITY_INVOICE)
{
$records->where('is_quote', '=', false)
->where('is_recurring', '=', false);
}
$totals = $records->lists('total');
$dates = $records->lists($groupBy);
$data = array_combine($dates, $totals);

View File

@ -15,6 +15,9 @@ class AddQuotes extends Migration {
Schema::table('invoices', function($table)
{
$table->boolean('is_quote');
$table->unsignedInteger('quote_id')->nullable();
$table->unsignedInteger('quote_invoice_id')->nullable();
});
}
@ -28,6 +31,9 @@ class AddQuotes extends Migration {
Schema::table('invoices', function($table)
{
$table->dropColumn('is_quote');
$table->dropColumn('quote_id');
$table->dropColumn('quote_invoice_id');
});
}

View File

@ -260,12 +260,12 @@ return array(
'email_from' => 'Das InvoiceNinja Team',
'user_email_footer' => 'Um deine E-Mail Benachrichtigungen anzupassen besuche bitte '.SITE_URL.'/company/notifications',
'invoice_link_message' => 'Um deine Kundenrechnung anzuschauen, klicke auf den folgenden Link:',
'notification_paid_subject' => 'Die Rechnung :invoice wurde von :client bezahlt',
'notification_sent_subject' => 'Die Rechnung :invoice wurde an :client versendet',
'notification_viewed_subject' => 'Die Rechnung :invoice wurde von :client angeschaut',
'notification_paid' => 'Eine Zahlung von :amount wurde von :client bezüglich Rechnung :invoice getätigt.',
'notification_sent' => 'Dem folgenden Kunden :client wurde die Rechnung :invoice über :amount zugesendet.',
'notification_viewed' => 'Der folgende Kunde :client hat sich Rechnung :invoice über :amount angesehen.',
'notification_invoice_paid_subject' => 'Die Rechnung :invoice wurde von :client bezahlt',
'notification_invoice_sent_subject' => 'Die Rechnung :invoice wurde an :client versendet',
'notification_invoice_viewed_subject' => 'Die Rechnung :invoice wurde von :client angeschaut',
'notification_invoice_paid' => 'Eine Zahlung von :amount wurde von :client bezüglich Rechnung :invoice getätigt.',
'notification_invoice_sent' => 'Dem folgenden Kunden :client wurde die Rechnung :invoice über :amount zugesendet.',
'notification_invoice_viewed' => 'Der folgende Kunde :client hat sich Rechnung :invoice über :amount angesehen.',
'reset_password' => 'Du kannst dein Passwort zurücksetzen indem du auf den folgenden Link klickst:',
'reset_password_footer' => 'Wenn du das Zurücksetzen des Passworts nicht beantragt hast benachrichtige bitte unseren Support: ' . CONTACT_EMAIL,
@ -338,4 +338,45 @@ return array(
'ninja_email_footer' => 'Use :site to invoice your clients and get paid online for free!',
// Quotes
'quote' => 'Quote',
'quotes' => 'Quotes',
'quote_number' => 'Quote Number',
'quote_number_short' => 'Quote #',
'quote_date' => 'Quote Date',
'quote_total' => 'Quote Total',
'your_quote' => 'Your Quote',
'total' => 'Total',
'clone' => 'Clone',
'new_quote' => 'New Quote',
'create_quote' => 'Create Quote',
'edit_quote' => 'Edit Quote',
'archive_quote' => 'Archive Quote',
'delete_quote' => 'Delete Quote',
'save_quote' => 'Save Quote',
'email_quote' => 'Email Quote',
'clone_quote' => 'Clone Quote',
'convert_to_invoice' => 'Convert to Invoice',
'view_invoice' => 'View Invoice',
'view_quote' => 'View Quote',
'updated_quote' => 'Successfully updated quote',
'created_quote' => 'Successfully created quote',
'cloned_quote' => 'Successfully cloned quote',
'emailed_quote' => 'Successfully emailed quote',
'archived_quote' => 'Successfully archived quote',
'archived_quotes' => 'Successfully archived :count quotes',
'deleted_quote' => 'Successfully deleted quote',
'deleted_quotes' => 'Successfully deleted :count quotes',
'converted_to_invoice' => 'Successfully converted quote to invoice',
'quote_subject' => 'New quote from :account',
'quote_message' => 'To view your quote for :amount, click the link below.',
'quote_link_message' => 'To view your client quote click the link below:',
'notification_quote_sent_subject' => 'Quote :invoice was sent to :client',
'notification_quote_viewed_subject' => 'Quote :invoice was viewed by :client',
'notification_quote_sent' => 'The following client :client was emailed Quote :invoice for :amount.',
'notification_quote_viewed' => 'The following client :client viewed Quote :invoice for :amount.',
);

View File

@ -262,15 +262,16 @@ return array(
'email_from' => 'The InvoiceNinja Team',
'user_email_footer' => 'To adjust your email notification settings please visit '.SITE_URL.'/company/notifications',
'invoice_link_message' => 'To view your client invoice click the link below:',
'notification_paid_subject' => 'Invoice :invoice was paid by :client',
'notification_sent_subject' => 'Invoice :invoice was sent to :client',
'notification_viewed_subject' => 'Invoice :invoice was viewed by :client',
'notification_paid' => 'A payment of :amount was made by client :client towards Invoice :invoice.',
'notification_sent' => 'The following client :client was emailed Invoice :invoice for :amount.',
'notification_viewed' => 'The following client :client viewed Invoice :invoice for :amount.',
'notification_invoice_paid_subject' => 'Invoice :invoice was paid by :client',
'notification_invoice_sent_subject' => 'Invoice :invoice was sent to :client',
'notification_invoice_viewed_subject' => 'Invoice :invoice was viewed by :client',
'notification_invoice_paid' => 'A payment of :amount was made by client :client towards Invoice :invoice.',
'notification_invoice_sent' => 'The following client :client was emailed Invoice :invoice for :amount.',
'notification_invoice_viewed' => 'The following client :client viewed Invoice :invoice for :amount.',
'reset_password' => 'You can reset your account password by clicking the following link:',
'reset_password_footer' => 'If you did not request this password reset please email our support: ' . CONTACT_EMAIL,
// Payment page
'secure_payment' => 'Secure Payment',
'card_number' => 'Card number',
@ -351,16 +352,29 @@ return array(
'chart_builder' => 'Chart Builder',
'ninja_email_footer' => 'Use :site to invoice your clients and get paid online for free!',
// Quotes
'quote' => 'Quote',
'quotes' => 'Quotes',
'quote_number' => 'Quote Number',
'quote_number_short' => 'Quote #',
'quote_date' => 'Quote Date',
'quote_total' => 'Quote Total',
'your_quote' => 'Your Quote',
'total' => 'Total',
'clone' => 'Clone',
'new_quote' => 'New Quote',
'create_quote' => 'Create Quote',
'edit_quote' => 'Edit Quote',
'archive_quote' => 'Archive Quote',
'delete_quote' => 'Delete Quote',
'save_quote' => 'Save Quote',
'email_quote' => 'Email Quote',
'clone_quote' => 'Clone Quote',
'convert_to_invoice' => 'Convert to Invoice',
'view_invoice' => 'View Invoice',
'view_quote' => 'View Quote',
'updated_quote' => 'Successfully updated quote',
'created_quote' => 'Successfully created quote',
@ -370,6 +384,18 @@ return array(
'archived_quotes' => 'Successfully archived :count quotes',
'deleted_quote' => 'Successfully deleted quote',
'deleted_quotes' => 'Successfully deleted :count quotes',
'converted_to_invoice' => 'Successfully converted quote to invoice',
'quote_subject' => 'New quote from :account',
'quote_message' => 'To view your quote for :amount, click the link below.',
'quote_link_message' => 'To view your client quote click the link below:',
'notification_quote_sent_subject' => 'Quote :invoice was sent to :client',
'notification_quote_viewed_subject' => 'Quote :invoice was viewed by :client',
'notification_quote_sent' => 'The following client :client was emailed Quote :invoice for :amount.',
'notification_quote_viewed' => 'The following client :client viewed Quote :invoice for :amount.',
);

View File

@ -261,12 +261,12 @@ return array(
'email_from' => 'The InvoiceNinja Team',
'user_email_footer' => 'To adjust your email notification settings please visit '.SITE_URL.'/company/notifications',
'invoice_link_message' => 'To view your client invoice click the link below:',
'notification_paid_subject' => 'Invoice :invoice was paid by :client',
'notification_sent_subject' => 'Invoice :invoice was sent to :client',
'notification_viewed_subject' => 'Invoice :invoice was viewed by :client',
'notification_paid' => 'A payment of :amount was made by client :client towards Invoice :invoice.',
'notification_sent' => 'The following client :client was emailed Invoice :invoice for :amount.',
'notification_viewed' => 'The following client :client viewed Invoice :invoice for :amount.',
'notification_invoice_paid_subject' => 'Invoice :invoice was paid by :client',
'notification_invoice_sent_subject' => 'Invoice :invoice was sent to :client',
'notification_invoice_viewed_subject' => 'Invoice :invoice was viewed by :client',
'notification_invoice_paid' => 'A payment of :amount was made by client :client towards Invoice :invoice.',
'notification_invoice_sent' => 'The following client :client was emailed Invoice :invoice for :amount.',
'notification_invoice_viewed' => 'The following client :client viewed Invoice :invoice for :amount.',
'reset_password' => 'You can reset your account password by clicking the following link:',
'reset_password_footer' => 'If you did not request this password reset please email our support: ' . CONTACT_EMAIL,
@ -335,5 +335,46 @@ return array(
'chart_builder' => 'Chart Builder',
'ninja_email_footer' => 'Use :site to invoice your clients and get paid online for free!',
// Quotes
'quote' => 'Quote',
'quotes' => 'Quotes',
'quote_number' => 'Quote Number',
'quote_number_short' => 'Quote #',
'quote_date' => 'Quote Date',
'quote_total' => 'Quote Total',
'your_quote' => 'Your Quote',
'total' => 'Total',
'clone' => 'Clone',
'new_quote' => 'New Quote',
'create_quote' => 'Create Quote',
'edit_quote' => 'Edit Quote',
'archive_quote' => 'Archive Quote',
'delete_quote' => 'Delete Quote',
'save_quote' => 'Save Quote',
'email_quote' => 'Email Quote',
'clone_quote' => 'Clone Quote',
'convert_to_invoice' => 'Convert to Invoice',
'view_invoice' => 'View Invoice',
'view_quote' => 'View Quote',
'updated_quote' => 'Successfully updated quote',
'created_quote' => 'Successfully created quote',
'cloned_quote' => 'Successfully cloned quote',
'emailed_quote' => 'Successfully emailed quote',
'archived_quote' => 'Successfully archived quote',
'archived_quotes' => 'Successfully archived :count quotes',
'deleted_quote' => 'Successfully deleted quote',
'deleted_quotes' => 'Successfully deleted :count quotes',
'converted_to_invoice' => 'Successfully converted quote to invoice',
'quote_subject' => 'New quote from :account',
'quote_message' => 'To view your quote for :amount, click the link below.',
'quote_link_message' => 'To view your client quote click the link below:',
'notification_quote_sent_subject' => 'Quote :invoice was sent to :client',
'notification_quote_viewed_subject' => 'Quote :invoice was viewed by :client',
'notification_quote_sent' => 'The following client :client was emailed Quote :invoice for :amount.',
'notification_quote_viewed' => 'The following client :client viewed Quote :invoice for :amount.',
);

View File

@ -262,12 +262,12 @@ return array(
'email_from' => 'L\'équipe InvoiceNinja',
'user_email_footer' => 'Pour modifier vos paramètres de notification par email, veuillez visiter '.SITE_URL.'/company/notifications',
'invoice_link_message' => 'Pour voir la facture de votre client cliquez sur le lien ci-après :',
'notification_paid_subject' => 'La facture :invoice a été payée par le client :client',
'notification_sent_subject' => 'La facture :invoice a été envoyée au client :client',
'notification_viewed_subject' => 'La facture :invoice a été vue par le client :client',
'notification_paid' => 'Un paiement de :amount a été effectué par le client :client concernant la facture :invoice.',
'notification_sent' => 'Le client suivant :client a reçu par email la facture :invoice d\'un montant de :amount',
'notification_viewed' => 'Le client suivant :client a vu la facture :invoice d\'un montant de :amount',
'notification_invoice_paid_subject' => 'La facture :invoice a été payée par le client :client',
'notification_invoice_sent_subject' => 'La facture :invoice a été envoyée au client :client',
'notification_invoice_viewed_subject' => 'La facture :invoice a été vue par le client :client',
'notification_invoice_paid' => 'Un paiement de :amount a été effectué par le client :client concernant la facture :invoice.',
'notification_invoice_sent' => 'Le client suivant :client a reçu par email la facture :invoice d\'un montant de :amount',
'notification_invoice_viewed' => 'Le client suivant :client a vu la facture :invoice d\'un montant de :amount',
'reset_password' => 'Vous pouvez réinitialiser votre mot de passe en cliquant sur le lien suivant :',
'reset_password_footer' => 'Si vous n\'avez pas effectué de demande de réinitalisation de mot de passe veuillez contacter notre support :' . CONTACT_EMAIL,
@ -336,5 +336,47 @@ return array(
'chart_builder' => 'Chart Builder',
'ninja_email_footer' => 'Use :site to invoice your clients and get paid online for free!',
// Quotes
'quote' => 'Quote',
'quotes' => 'Quotes',
'quote_number' => 'Quote Number',
'quote_number_short' => 'Quote #',
'quote_date' => 'Quote Date',
'quote_total' => 'Quote Total',
'your_quote' => 'Your Quote',
'total' => 'Total',
'clone' => 'Clone',
'new_quote' => 'New Quote',
'create_quote' => 'Create Quote',
'edit_quote' => 'Edit Quote',
'archive_quote' => 'Archive Quote',
'delete_quote' => 'Delete Quote',
'save_quote' => 'Save Quote',
'email_quote' => 'Email Quote',
'clone_quote' => 'Clone Quote',
'convert_to_invoice' => 'Convert to Invoice',
'view_invoice' => 'View Invoice',
'view_quote' => 'View Quote',
'updated_quote' => 'Successfully updated quote',
'created_quote' => 'Successfully created quote',
'cloned_quote' => 'Successfully cloned quote',
'emailed_quote' => 'Successfully emailed quote',
'archived_quote' => 'Successfully archived quote',
'archived_quotes' => 'Successfully archived :count quotes',
'deleted_quote' => 'Successfully deleted quote',
'deleted_quotes' => 'Successfully deleted :count quotes',
'converted_to_invoice' => 'Successfully converted quote to invoice',
'quote_subject' => 'New quote from :account',
'quote_message' => 'To view your quote for :amount, click the link below.',
'quote_link_message' => 'To view your client quote click the link below:',
'notification_quote_sent_subject' => 'Quote :invoice was sent to :client',
'notification_quote_viewed_subject' => 'Quote :invoice was viewed by :client',
'notification_quote_sent' => 'The following client :client was emailed Quote :invoice for :amount.',
'notification_quote_viewed' => 'The following client :client viewed Quote :invoice for :amount.',
);

View File

@ -262,12 +262,12 @@ return array(
'email_from' => 'Il Team di InvoiceNinja',
'user_email_footer' => 'Per modificare le impostazioni di notifiche via email per favore accedi a: '.SITE_URL.'/company/notifications',
'invoice_link_message' => 'Per visualizzare la tua fattura del cliente clicca sul link qui sotto:',
'notification_paid_subject' => 'La fattura :invoice è stata pagata da :client',
'notification_sent_subject' => 'La fattura :invoice è stata inviata a :client',
'notification_viewed_subject' => 'La fattura :invoice è stata visualizzata da :client',
'notification_paid' => 'Un pagamento di :amount è stato effettuato dal cliente :client attraverso la fattura :invoice.',
'notification_sent' => 'Al seguente cliente :client è stata inviata via email la fattura :invoice di :amount.',
'notification_viewed' => 'Il seguente cliente :client ha visualizzato la fattura :invoice di :amount.',
'notification_invoice_paid_subject' => 'La fattura :invoice è stata pagata da :client',
'notification_invoice_sent_subject' => 'La fattura :invoice è stata inviata a :client',
'notification_invoice_viewed_subject' => 'La fattura :invoice è stata visualizzata da :client',
'notification_invoice_paid' => 'Un pagamento di :amount è stato effettuato dal cliente :client attraverso la fattura :invoice.',
'notification_invoice_sent' => 'Al seguente cliente :client è stata inviata via email la fattura :invoice di :amount.',
'notification_invoice_viewed' => 'Il seguente cliente :client ha visualizzato la fattura :invoice di :amount.',
'reset_password' => 'Puoi resettare la password del tuo account cliccando sul link qui sotto:',
'reset_password_footer' => 'Se non sei stato tu a voler resettare la password per favore invia un\'email di assistenza a: ' . CONTACT_EMAIL,
@ -337,4 +337,46 @@ return array(
'chart_builder' => 'Chart Builder',
'ninja_email_footer' => 'Use :site to invoice your clients and get paid online for free!',
// Quotes
'quote' => 'Quote',
'quotes' => 'Quotes',
'quote_number' => 'Quote Number',
'quote_number_short' => 'Quote #',
'quote_date' => 'Quote Date',
'quote_total' => 'Quote Total',
'your_quote' => 'Your Quote',
'total' => 'Total',
'clone' => 'Clone',
'new_quote' => 'New Quote',
'create_quote' => 'Create Quote',
'edit_quote' => 'Edit Quote',
'archive_quote' => 'Archive Quote',
'delete_quote' => 'Delete Quote',
'save_quote' => 'Save Quote',
'email_quote' => 'Email Quote',
'clone_quote' => 'Clone Quote',
'convert_to_invoice' => 'Convert to Invoice',
'view_invoice' => 'View Invoice',
'view_quote' => 'View Quote',
'updated_quote' => 'Successfully updated quote',
'created_quote' => 'Successfully created quote',
'cloned_quote' => 'Successfully cloned quote',
'emailed_quote' => 'Successfully emailed quote',
'archived_quote' => 'Successfully archived quote',
'archived_quotes' => 'Successfully archived :count quotes',
'deleted_quote' => 'Successfully deleted quote',
'deleted_quotes' => 'Successfully deleted :count quotes',
'converted_to_invoice' => 'Successfully converted quote to invoice',
'quote_subject' => 'New quote from :account',
'quote_message' => 'To view your quote for :amount, click the link below.',
'quote_link_message' => 'To view your client quote click the link below:',
'notification_quote_sent_subject' => 'Quote :invoice was sent to :client',
'notification_quote_viewed_subject' => 'Quote :invoice was viewed by :client',
'notification_quote_sent' => 'The following client :client was emailed Quote :invoice for :amount.',
'notification_quote_viewed' => 'The following client :client viewed Quote :invoice for :amount.',
);

View File

@ -260,12 +260,12 @@ return array(
'email_from' => 'Het InvoiceNinja Team',
'user_email_footer' => 'Ga alstublieft naar '.SITE_URL.'/company/notifications om je e-mail notificatie instellingen aan te passen ',
'invoice_link_message' => 'Klik op volgende link om de Factuur van je klant te bekijken:',
'notification_paid_subject' => 'Factuur :invoice is betaald door :client',
'notification_sent_subject' => 'Factuur :invoice is gezonden door :client',
'notification_viewed_subject' => 'Factuur :invoice is bekeken door :client',
'notification_paid' => 'Een betaling voor :amount is gemaakt door klant :client voor Factuur :invoice.',
'notification_sent' => 'De volgende klant :client heeft Factuur :invoice voor :amount gemaild gekregen.',
'notification_viewed' => 'De volgende klant :client heeft Factuur :invoice voor :amount bekeken.',
'notification_invoice_paid_subject' => 'Factuur :invoice is betaald door :client',
'notification_invoice_sent_subject' => 'Factuur :invoice is gezonden door :client',
'notification_invoice_viewed_subject' => 'Factuur :invoice is bekeken door :client',
'notification_invoice_paid' => 'Een betaling voor :amount is gemaakt door klant :client voor Factuur :invoice.',
'notification_invoice_sent' => 'De volgende klant :client heeft Factuur :invoice voor :amount gemaild gekregen.',
'notification_invoice_viewed' => 'De volgende klant :client heeft Factuur :invoice voor :amount bekeken.',
'reset_password' => 'Je kan het paswoord van je account resetten door op volgende link te klikken:',
'reset_password_footer' => 'Als je deze paswoord reset niet aangevraagd hebt contacteer dan onze helpdesk alstublieft: ' . CONTACT_EMAIL,
@ -337,5 +337,47 @@ return array(
'chart_builder' => 'Chart Builder',
'ninja_email_footer' => 'Use :site to invoice your clients and get paid online for free!',
// Quotes
'quote' => 'Quote',
'quotes' => 'Quotes',
'quote_number' => 'Quote Number',
'quote_number_short' => 'Quote #',
'quote_date' => 'Quote Date',
'quote_total' => 'Quote Total',
'your_quote' => 'Your Quote',
'total' => 'Total',
'clone' => 'Clone',
'new_quote' => 'New Quote',
'create_quote' => 'Create Quote',
'edit_quote' => 'Edit Quote',
'archive_quote' => 'Archive Quote',
'delete_quote' => 'Delete Quote',
'save_quote' => 'Save Quote',
'email_quote' => 'Email Quote',
'clone_quote' => 'Clone Quote',
'convert_to_invoice' => 'Convert to Invoice',
'view_invoice' => 'View Invoice',
'view_quote' => 'View Quote',
'updated_quote' => 'Successfully updated quote',
'created_quote' => 'Successfully created quote',
'cloned_quote' => 'Successfully cloned quote',
'emailed_quote' => 'Successfully emailed quote',
'archived_quote' => 'Successfully archived quote',
'archived_quotes' => 'Successfully archived :count quotes',
'deleted_quote' => 'Successfully deleted quote',
'deleted_quotes' => 'Successfully deleted :count quotes',
'converted_to_invoice' => 'Successfully converted quote to invoice',
'quote_subject' => 'New quote from :account',
'quote_message' => 'To view your quote for :amount, click the link below.',
'quote_link_message' => 'To view your client quote click the link below:',
'notification_quote_sent_subject' => 'Quote :invoice was sent to :client',
'notification_quote_viewed_subject' => 'Quote :invoice was viewed by :client',
'notification_quote_sent' => 'The following client :client was emailed Quote :invoice for :amount.',
'notification_quote_viewed' => 'The following client :client viewed Quote :invoice for :amount.',
);

View File

@ -258,12 +258,12 @@ return array(
'email_from' => 'Equipe InvoiceNinja',
'user_email_footer' => 'Para ajustar suas configurações de notificações de email acesse '.SITE_URL.'/company/notifications',
'invoice_link_message' => 'Para visualizar a fatura do seu cliente clique no link abaixo:',
'notification_paid_subject' => 'Fatura :invoice foi pago por :client',
'notification_sent_subject' => 'Fatura :invoice foi enviado por :client',
'notification_viewed_subject' => 'Fatura :invoice foi visualizada por :client',
'notification_paid' => 'Um pagamento de :amount foi realizado pelo cliente :client através da fatura :invoice.',
'notification_sent' => 'O cliente :client foi notificado por email referente à fatura :invoice de :amount.',
'notification_viewed' => 'O cliente :client visualizou a fatura :invoice de :amount.',
'notification_invoice_paid_subject' => 'Fatura :invoice foi pago por :client',
'notification_invoice_sent_subject' => 'Fatura :invoice foi enviado por :client',
'notification_invoice_viewed_subject' => 'Fatura :invoice foi visualizada por :client',
'notification_invoice_paid' => 'Um pagamento de :amount foi realizado pelo cliente :client através da fatura :invoice.',
'notification_invoice_sent' => 'O cliente :client foi notificado por email referente à fatura :invoice de :amount.',
'notification_invoice_viewed' => 'O cliente :client visualizou a fatura :invoice de :amount.',
'reset_password' => 'Você pode redefinir a sua senha clicando no seguinte link:',
'reset_password_footer' => 'Se você não solicitou a redefinição de sua senha por favor envie um email para o nosso suporte: ' . CONTACT_EMAIL,
@ -326,5 +326,47 @@ return array(
'chart_builder' => 'Chart Builder',
'ninja_email_footer' => 'Use :site to invoice your clients and get paid online for free!',
// Quotes
'quote' => 'Quote',
'quotes' => 'Quotes',
'quote_number' => 'Quote Number',
'quote_number_short' => 'Quote #',
'quote_date' => 'Quote Date',
'quote_total' => 'Quote Total',
'your_quote' => 'Your Quote',
'total' => 'Total',
'clone' => 'Clone',
'new_quote' => 'New Quote',
'create_quote' => 'Create Quote',
'edit_quote' => 'Edit Quote',
'archive_quote' => 'Archive Quote',
'delete_quote' => 'Delete Quote',
'save_quote' => 'Save Quote',
'email_quote' => 'Email Quote',
'clone_quote' => 'Clone Quote',
'convert_to_invoice' => 'Convert to Invoice',
'view_invoice' => 'View Invoice',
'view_quote' => 'View Quote',
'updated_quote' => 'Successfully updated quote',
'created_quote' => 'Successfully created quote',
'cloned_quote' => 'Successfully cloned quote',
'emailed_quote' => 'Successfully emailed quote',
'archived_quote' => 'Successfully archived quote',
'archived_quotes' => 'Successfully archived :count quotes',
'deleted_quote' => 'Successfully deleted quote',
'deleted_quotes' => 'Successfully deleted :count quotes',
'converted_to_invoice' => 'Successfully converted quote to invoice',
'quote_subject' => 'New quote from :account',
'quote_message' => 'To view your quote for :amount, click the link below.',
'quote_link_message' => 'To view your client quote click the link below:',
'notification_quote_sent_subject' => 'Quote :invoice was sent to :client',
'notification_quote_viewed_subject' => 'Quote :invoice was viewed by :client',
'notification_quote_sent' => 'The following client :client was emailed Quote :invoice for :amount.',
'notification_quote_viewed' => 'The following client :client viewed Quote :invoice for :amount.',
);

View File

@ -286,26 +286,29 @@ class Utils
$object = new stdClass;
$object->url = $url;
$object->name = ucwords($type) . ': ' . $name;
$data = [];
for ($i=0; $i<count($viewed); $i++)
{
$item = $viewed[$i];
if ($object->url == $item->url)
if ($object->url == $item->url || $object->name == $item->name)
{
array_splice($viewed, $i, 1);
break;
}
continue;
}
array_unshift($data, $item);
}
array_unshift($viewed, $object);
array_unshift($data, $object);
if (count($viewed) > RECENTLY_VIEWED_LIMIT)
if (count($data) > RECENTLY_VIEWED_LIMIT)
{
array_pop($viewed);
array_pop($data);
}
Session::put(RECENTLY_VIEWED, $viewed);
Session::put(RECENTLY_VIEWED, $data);
}
public static function processVariables($str)

View File

@ -203,6 +203,11 @@ class Account extends Eloquent
'balance_due',
'terms',
'your_invoice',
'quote',
'your_quote',
'quote_date',
'quote_number',
'total'
];
foreach ($fields as $field)

View File

@ -22,6 +22,13 @@ define("ACTIVITY_TYPE_UPDATE_CREDIT", 15);
define("ACTIVITY_TYPE_ARCHIVE_CREDIT", 16);
define("ACTIVITY_TYPE_DELETE_CREDIT", 17);
define("ACTIVITY_TYPE_CREATE_QUOTE", 18);
define("ACTIVITY_TYPE_UPDATE_QUOTE", 19);
define("ACTIVITY_TYPE_EMAIL_QUOTE", 20);
define("ACTIVITY_TYPE_VIEW_QUOTE", 21);
define("ACTIVITY_TYPE_ARCHIVE_QUOTE", 22);
define("ACTIVITY_TYPE_DELETE_QUOTE", 23);
class Activity extends Eloquent
{
@ -105,15 +112,19 @@ class Activity extends Eloquent
$message = Utils::encodeActivity(null, 'created', $invoice);
}
$adjustment = 0;
$client = $invoice->client;
$adjustment = $invoice->amount;
$client->balance = $client->balance + $adjustment;
$client->save();
if (!$invoice->is_quote)
{
$adjustment = $invoice->amount;
$client->balance = $client->balance + $adjustment;
$client->save();
}
$activity = Activity::getBlank($invoice);
$activity->invoice_id = $invoice->id;
$activity->client_id = $invoice->client_id;
$activity->activity_type_id = ACTIVITY_TYPE_CREATE_INVOICE;
$activity->activity_type_id = $invoice->is_quote ? ACTIVITY_TYPE_CREATE_QUOTE : ACTIVITY_TYPE_CREATE_INVOICE;
$activity->message = $message;
$activity->balance = $client->balance;
$activity->adjustment = $adjustment;
@ -129,18 +140,21 @@ class Activity extends Eloquent
if (!$invoice->is_deleted)
{
$client = $invoice->client;
$client->balance = $client->balance - $invoice->balance;
$client->paid_to_date = $client->paid_to_date - ($invoice->amount - $invoice->balance);
$client->save();
if (!$invoice->is_quote)
{
$client = $invoice->client;
$client->balance = $client->balance - $invoice->balance;
$client->paid_to_date = $client->paid_to_date - ($invoice->amount - $invoice->balance);
$client->save();
}
$activity = Activity::getBlank();
$activity->invoice_id = $invoice->id;
$activity->client_id = $invoice->client_id;
$activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_INVOICE;
$activity->activity_type_id = $invoice->is_quote ? ACTIVITY_TYPE_ARCHIVE_QUOTE : ACTIVITY_TYPE_ARCHIVE_INVOICE;
$activity->message = Utils::encodeActivity(Auth::user(), 'archived', $invoice);
$activity->balance = $invoice->client->balance;
$activity->adjustment = $invoice->balance;
$activity->adjustment = $invoice->is_quote ? 0 : $invoice->balance;
$activity->save();
}
@ -155,7 +169,7 @@ class Activity extends Eloquent
$activity->client_id = $invitation->invoice->client_id;
$activity->invoice_id = $invitation->invoice_id;
$activity->contact_id = $invitation->contact_id;
$activity->activity_type_id = ACTIVITY_TYPE_EMAIL_INVOICE;
$activity->activity_type_id = $invitation->invoice ? ACTIVITY_TYPE_EMAIL_QUOTE : ACTIVITY_TYPE_EMAIL_INVOICE;
$activity->message = Utils::encodeActivity(Auth::check() ? Auth::user() : null, 'emailed', $invitation->invoice, $invitation->contact);
$activity->balance = $client->balance;
$activity->save();
@ -165,18 +179,21 @@ class Activity extends Eloquent
{
if ($invoice->is_deleted && !$invoice->getOriginal('is_deleted'))
{
$client = $invoice->client;
$client->balance = $client->balance - $invoice->balance;
$client->paid_to_date = $client->paid_to_date - ($invoice->amount - $invoice->balance);
$client->save();
if (!$invoice->is_quote)
{
$client = $invoice->client;
$client->balance = $client->balance - $invoice->balance;
$client->paid_to_date = $client->paid_to_date - ($invoice->amount - $invoice->balance);
$client->save();
}
$activity = Activity::getBlank();
$activity->client_id = $invoice->client_id;
$activity->invoice_id = $invoice->id;
$activity->activity_type_id = ACTIVITY_TYPE_DELETE_INVOICE;
$activity->activity_type_id = $invoice->is_quote ? ACTIVITY_TYPE_DELETE_QUOTE : ACTIVITY_TYPE_DELETE_INVOICE;
$activity->message = Utils::encodeActivity(Auth::user(), 'deleted', $invoice);
$activity->balance = $invoice->client->balance;
$activity->adjustment = $invoice->balance * -1;
$activity->adjustment = $invoice->is_quote ? 0 : $invoice->balance * -1;
$activity->save();
}
else
@ -197,10 +214,10 @@ class Activity extends Eloquent
$activity = Activity::getBlank($invoice);
$activity->client_id = $invoice->client_id;
$activity->invoice_id = $invoice->id;
$activity->activity_type_id = ACTIVITY_TYPE_UPDATE_INVOICE;
$activity->activity_type_id = $invoice->is_quote ? ACTIVITY_TYPE_UPDATE_QUOTE : ACTIVITY_TYPE_UPDATE_INVOICE;
$activity->message = Utils::encodeActivity(Auth::user(), 'updated', $invoice);
$activity->balance = $client->balance;
$activity->adjustment = $diff;
$activity->adjustment = $invoice->is_quote ? 0 : $diff;
$activity->json_backup = $backupInvoice->hidePrivateFields()->toJSON();
$activity->save();
}
@ -236,7 +253,7 @@ class Activity extends Eloquent
$activity->invitation_id = $invitation->id;
$activity->contact_id = $invitation->contact_id;
$activity->invoice_id = $invitation->invoice_id;
$activity->activity_type_id = ACTIVITY_TYPE_VIEW_INVOICE;
$activity->activity_type_id = $invitation->invoice->is_quote ? ACTIVITY_TYPE_VIEW_QUOTE : ACTIVITY_TYPE_VIEW_INVOICE;
$activity->message = Utils::encodeActivity($invitation->contact, 'viewed', $invitation->invoice);
$activity->balance = $invitation->invoice->client->balance;
$activity->save();

View File

@ -39,7 +39,7 @@ class Invoice extends EntityModel
public function getEntityType()
{
return ENTITY_INVOICE;
return $this->is_quote ? ENTITY_QUOTE : ENTITY_INVOICE;
}
public function isSent()
@ -75,7 +75,8 @@ class Invoice extends EntityModel
'tax_rate',
'account',
'invoice_design_id',
'is_pro']);
'is_pro',
'is_quote']);
$this->client->setVisible([
'name',

View File

@ -14,9 +14,10 @@ class ContactMailer extends Mailer {
public function sendInvoice(Invoice $invoice)
{
$invoice->load('invitations', 'client', 'account');
$entityType = $invoice->getEntityType();
$view = 'invoice';
$subject = trans('texts.invoice_subject', ['invoice' => $invoice->invoice_number, 'account' => $invoice->account->getDisplayName()]);
$subject = trans("texts.{$entityType}_subject", ['invoice' => $invoice->invoice_number, 'account' => $invoice->account->getDisplayName()]);
foreach ($invoice->invitations as $invitation)
{
@ -29,6 +30,7 @@ class ContactMailer extends Mailer {
$invitation->save();
$data = [
'entityType' => $entityType,
'link' => $invitation->getLink(),
'clientName' => $invoice->client->getDisplayName(),
'accountName' => $invoice->account->getDisplayName(),

View File

@ -25,22 +25,24 @@ class UserMailer extends Mailer {
$this->sendTo($user->email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data);
}
public function sendNotification(User $user, Invoice $invoice, $type, Payment $payment = null)
public function sendNotification(User $user, Invoice $invoice, $notificationType, Payment $payment = null)
{
if (!$user->email)
{
return;
}
$view = 'invoice_' . $type;
$view = 'invoice_' . $notificationType;
$entityType = $invoice->getEntityType();
$data = [
'entityType' => $entityType,
'clientName' => $invoice->client->getDisplayName(),
'accountName' => $invoice->account->getDisplayName(),
'userName' => $user->getDisplayName(),
'invoiceAmount' => Utils::formatMoney($invoice->amount, $invoice->client->currency_id),
'invoiceNumber' => $invoice->invoice_number,
'invoiceLink' => SITE_URL . "/invoices/{$invoice->public_id}"
'invoiceLink' => SITE_URL . "/{$entityType}s/{$invoice->public_id}"
];
if ($payment)
@ -48,7 +50,7 @@ class UserMailer extends Mailer {
$data['paymentAmount'] = Utils::formatMoney($payment->amount, $invoice->client->currency_id);
}
$subject = trans('texts.notification_'.$type.'_subject', ['invoice'=>$invoice->invoice_number, 'client'=>$invoice->client->getDisplayName()]);
$subject = trans("texts.notification_{$entityType}_{$notificationType}_subject", ['invoice'=>$invoice->invoice_number, 'client'=>$invoice->client->getDisplayName()]);
$this->sendTo($user->email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data);
}

View File

@ -2,6 +2,7 @@
use Invoice;
use InvoiceItem;
use Invitation;
use Product;
use Utils;
use TaxRate;
@ -14,11 +15,11 @@ class InvoiceRepository
->join('clients', 'clients.id', '=','invoices.client_id')
->join('invoice_statuses', 'invoice_statuses.id', '=', 'invoices.invoice_status_id')
->join('contacts', 'contacts.client_id', '=', 'clients.id')
->where('invoices.account_id', '=', $accountId)
->where('clients.deleted_at', '=', null)
->where('invoices.account_id', '=', $accountId)
->where('clients.deleted_at', '=', null)
->where('invoices.is_recurring', '=', false)
->where('contacts.is_primary', '=', true)
->select('clients.public_id as client_public_id', 'invoice_number', 'clients.name as client_name', 'invoices.public_id', 'amount', 'invoices.balance', 'invoice_date', 'due_date', 'invoice_statuses.name as invoice_status_name', 'clients.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email');
->select('clients.public_id as client_public_id', 'invoice_number', 'clients.name as client_name', 'invoices.public_id', 'amount', 'invoices.balance', 'invoice_date', 'due_date', 'invoice_statuses.name as invoice_status_name', 'clients.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email', 'quote_id', 'quote_invoice_id');
if (!\Session::get('show_trash'))
{
@ -53,6 +54,7 @@ class InvoiceRepository
->join('frequencies', 'frequencies.id', '=', 'invoices.frequency_id')
->join('contacts', 'contacts.client_id', '=', 'clients.id')
->where('invoices.account_id', '=', $accountId)
->where('invoices.is_quote', '=', false)
->where('clients.deleted_at', '=', null)
->where('invoices.is_recurring', '=', true)
->where('contacts.is_primary', '=', true)
@ -82,12 +84,8 @@ class InvoiceRepository
public function getDatatable($accountId, $clientPublicId = null, $entityType, $search)
{
$query = $this->getInvoices($accountId, $clientPublicId, $search);
if ($entityType == ENTITY_QUOTE)
{
$query->where('invoices.is_quote', '=', true);
}
$query = $this->getInvoices($accountId, $clientPublicId, $search)
->where('invoices.is_quote', '=', $entityType == ENTITY_QUOTE ? true : false);
$table = \Datatable::query($query);
@ -120,17 +118,26 @@ class InvoiceRepository
'.trans('texts.select').' <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li><a href="' . \URL::to("{$entityType}s/".$model->public_id.'/edit') . '">'.trans("texts.edit_{$entityType}").'</a></li>';
<li><a href="' . \URL::to("{$entityType}s/".$model->public_id.'/edit') . '">'.trans("texts.edit_{$entityType}").'</a></li>
<li><a href="' . \URL::to("{$entityType}s/".$model->public_id.'/clone') . '">'.trans("texts.clone_{$entityType}").'</a></li>';
if ($entityType == ENTITY_INVOICE)
{
$str .= '<li><a href="' . \URL::to('payments/create/' . $model->client_public_id . '/' . $model->public_id ) . '">'.trans('texts.enter_payment').'</a></li>';
$str .= '<li class="divider"></li><li><a href="' . \URL::to('payments/create/' . $model->client_public_id . '/' . $model->public_id ) . '">'.trans('texts.enter_payment').'</a></li>';
if ($model->quote_id)
{
$str .= '<li><a href="' . \URL::to("quotes/{$model->quote_id}/edit") . '">' . trans("texts.view_quote") . '</a></li>';
}
}
else
else if ($entityType == ENTITY_QUOTE)
{
$str .= '';
if ($model->quote_invoice_id)
{
$str .= '<li class="divider"></li><li><a href="' . \URL::to("invoices/{$model->quote_invoice_id}/edit") . '">' . trans("texts.view_invoice") . '</a></li>';
}
}
return $str . '<li class="divider"></li>
<li><a href="javascript:archiveEntity(' . $model->public_id . ')">'.trans("texts.archive_{$entityType}").'</a></li>
<li><a href="javascript:deleteEntity(' . $model->public_id . ')">'.trans("texts.delete_{$entityType}").'</a></li>
@ -171,7 +178,7 @@ class InvoiceRepository
return false;
}
public function save($publicId, $data)
public function save($publicId, $data, $entityType)
{
if ($publicId)
{
@ -180,6 +187,11 @@ class InvoiceRepository
else
{
$invoice = Invoice::createNew();
if ($entityType == ENTITY_QUOTE)
{
$invoice->is_quote = true;
}
}
$invoice->client_id = $data['client_id'];
@ -305,6 +317,78 @@ class InvoiceRepository
return $invoice;
}
public function cloneInvoice($invoice, $quoteId = null)
{
$clone = Invoice::createNew();
$clone->balance = $invoice->amount;
$clone->invoice_number = $invoice->account->getNextInvoiceNumber();
foreach ([
'client_id',
'discount',
'invoice_date',
'po_number',
'due_date',
'is_recurring',
'frequency_id',
'start_date',
'end_date',
'terms',
'public_notes',
'invoice_design_id',
'tax_name',
'tax_rate',
'amount',
'is_quote'] as $field)
{
$clone->$field = $invoice->$field;
}
if ($quoteId)
{
$clone->is_quote = false;
$clone->quote_id = $quoteId;
}
$clone->save();
if ($quoteId)
{
$invoice->quote_invoice_id = $clone->id;
$invoice->save();
}
foreach ($invoice->invoice_items as $item)
{
$cloneItem = InvoiceItem::createNew();
foreach ([
'product_id',
'product_key',
'notes',
'cost',
'qty',
'tax_name',
'tax_rate'] as $field)
{
$cloneItem->$field = $item->$field;
}
$clone->invoice_items()->save($cloneItem);
}
foreach ($invoice->invitations as $invitation)
{
$cloneInvitation = Invitation::createNew();
$cloneInvitation->contact_id = $invitation->contact_id;
$cloneInvitation->invitation_key = str_random(RANDOM_KEY_LENGTH);
$clone->invitations()->save($cloneInvitation);
}
return $clone;
}
public function bulk($ids, $action)
{
if (!$ids)

View File

@ -94,14 +94,18 @@ Route::group(array('before' => 'auth'), function()
Route::resource('invoices', 'InvoiceController');
Route::get('api/invoices/{client_id?}', array('as'=>'api.invoices', 'uses'=>'InvoiceController@getDatatable'));
Route::get('invoices/create/{client_id?}', 'InvoiceController@create');
Route::get('invoices/{public_id}/clone', 'InvoiceController@cloneInvoice');
Route::post('invoices/bulk', 'InvoiceController@bulk');
Route::resource('quotes', 'QuoteController');
Route::get('api/quotes/{client_id?}', array('as'=>'api.quotes', 'uses'=>'QuoteController@getDatatable'));
/*
Route::get('invoices/create/{client_id?}', 'InvoiceController@create');
Route::post('invoices/bulk', 'InvoiceController@bulk');
*/
Route::get('quotes/create/{client_id?}', 'QuoteController@create');
Route::get('quotes/{public_id}/clone', 'InvoiceController@cloneInvoice');
Route::get('quotes/{public_id}/edit', 'InvoiceController@edit');
Route::put('quotes/{public_id}', 'InvoiceController@update');
Route::get('quotes/{public_id}', 'InvoiceController@edit');
Route::post('quotes', 'InvoiceController@store');
Route::get('quotes', 'QuoteController@index');
Route::get('api/quotes/{client_id?}', array('as'=>'api.quotes', 'uses'=>'QuoteController@getDatatable'));
Route::post('quotes/bulk', 'QuoteController@bulk');
Route::get('payments/{id}/edit', function() { return View::make('header'); });
Route::resource('payments', 'PaymentController');

View File

@ -22,17 +22,9 @@
)
, ['id'=>'normalDropDown'])->split(); }}
{{ DropdownButton::primary('Create Invoice',
Navigation::links(
[
[trans('texts.create_invoice'), URL::to('invoices/create/' . $client->public_id )],
[trans('texts.enter_payment'), URL::to('payments/create/' . $client->public_id )],
[trans('texts.enter_credit'), URL::to('credits/create/' . $client->public_id )],
]
)
, ['id'=>'primaryDropDown'])->split(); }}
{{ DropdownButton::primary('Create Invoice', Navigation::links($actionLinks), ['id'=>'primaryDropDown'])->split(); }}
{{ Former::close() }}
</div>
@endif
@ -90,6 +82,9 @@
<ul class="nav nav-tabs nav-justified">
{{ HTML::tab_link('#activity', trans('texts.activity'), true) }}
@if (Utils::isPro())
{{ HTML::tab_link('#quotes', trans('texts.quotes')) }}
@endif
{{ HTML::tab_link('#invoices', trans('texts.invoices')) }}
{{ HTML::tab_link('#payments', trans('texts.payments')) }}
{{ HTML::tab_link('#credits', trans('texts.credits')) }}
@ -113,6 +108,25 @@
</div>
@if (Utils::isPro())
<div class="tab-pane" id="quotes">
{{ Datatable::table()
->addColumn(
trans('texts.quote_number'),
trans('texts.quote_date'),
trans('texts.total'),
trans('texts.due_date'),
trans('texts.status'))
->setUrl(url('api/quotes/'. $client->public_id))
->setOptions('sPaginationType', 'bootstrap')
->setOptions('bFilter', false)
->setOptions('aaSorting', [['0', 'desc']])
->render('datatable') }}
</div>
@endif
<div class="tab-pane" id="invoices">
@if ($hasRecurringInvoices)

View File

@ -7,7 +7,7 @@
{{ $clientName }},<p/>
{{ trans('texts.invoice_message', ['amount' => $invoiceAmount]) }}<p/>
{{ trans("texts.{$entityType}_message", ['amount' => $invoiceAmount]) }}<p/>
{{ $link }}<p/>
@if ($emailFooter)

View File

@ -7,9 +7,9 @@
{{ trans('texts.email_salutation', ['name' => $userName]) }} <p/>
{{ trans('texts.notification_paid', ['amount' => $paymentAmount, 'client' => $clientName, 'invoice' => $invoiceNumber]) }} <p/>
{{ trans("texts.notification_{$entityType}_paid", ['amount' => $paymentAmount, 'client' => $clientName, 'invoice' => $invoiceNumber]) }} <p/>
{{ trans('texts.invoice_link_message') }} <br/>
{{ trans("texts.{$entityType}_link_message") }} <br/>
{{ $invoiceLink }} <p/>
{{ trans('texts.email_signature') }} <br/>

View File

@ -1,8 +1,8 @@
{{ trans('texts.email_salutation', ['name' => $userName]) }}
{{ trans('texts.notification_paid', ['amount' => $paymentAmount, 'client' => $clientName, 'invoice' => $invoiceNumber]) }}
{{ trans("texts.notification_{$entityType}_paid", ['amount' => $paymentAmount, 'client' => $clientName, 'invoice' => $invoiceNumber]) }}
{{ trans('texts.invoice_link_message') }}
{{ trans("texts.{$entityType}_link_message") }}
{{ $invoiceLink }}
{{ trans('texts.email_signature') }}

View File

@ -7,7 +7,7 @@
{{ trans('texts.email_salutation', ['name' => $userName]) }} <p/>
{{ trans('texts.notification_sent', ['amount' => $invoiceAmount, 'client' => $clientName, 'invoice' => $invoiceNumber]) }} <p/>
{{ trans("texts.notification_{$entityType}_sent", ['amount' => $invoiceAmount, 'client' => $clientName, 'invoice' => $invoiceNumber]) }} <p/>
{{ trans('texts.email_signature') }} <br/>
{{ trans('texts.email_from') }} <p/>

View File

@ -1,6 +1,6 @@
{{ trans('texts.email_salutation', ['name' => $userName]) }}
{{ trans('texts.notification_sent', ['amount' => $invoiceAmount, 'client' => $clientName, 'invoice' => $invoiceNumber]) }}
{{ trans("texts.notification_{$entityType}_sent", ['amount' => $invoiceAmount, 'client' => $clientName, 'invoice' => $invoiceNumber]) }}
{{ trans('texts.email_signature') }}
{{ trans('texts.email_from') }}

View File

@ -1,6 +1,6 @@
{{ $clientName }},
{{ trans('texts.invoice_message', ['amount' => $invoiceAmount]) }}
{{ trans("texts.{$entityType}_message", ['amount' => $invoiceAmount]) }}
{{ $link }}
@if ($emailFooter)

View File

@ -7,7 +7,7 @@
{{ trans('texts.email_salutation', ['name' => $userName]) }} <p/>
{{ trans('texts.notification_viewed', ['amount' => $invoiceAmount, 'client' => $clientName, 'invoice' => $invoiceNumber]) }} <p/>
{{ trans("texts.notification_{$entityType}_viewed", ['amount' => $invoiceAmount, 'client' => $clientName, 'invoice' => $invoiceNumber]) }} <p/>
{{ trans('texts.email_signature') }} <br/>
{{ trans('texts.email_from') }} <p/>

View File

@ -1,6 +1,6 @@
{{ trans('texts.email_salutation', ['name' => $userName]) }}
{{ trans('texts.notification_viewed', ['amount' => $invoiceAmount, 'client' => $clientName, 'invoice' => $invoiceNumber]) }}
{{ trans("texts.notification_{$entityType}_viewed", ['amount' => $invoiceAmount, 'client' => $clientName, 'invoice' => $invoiceNumber]) }}
{{ trans('texts.email_signature') }}
{{ trans('texts.email_from') }}

View File

@ -3,7 +3,6 @@
@section('head')
<meta name="csrf-token" content="<?= csrf_token() ?>">
<link href="{{ asset('built.css') }}" rel="stylesheet" type="text/css"/>
<!--

View File

@ -9,9 +9,9 @@
@section('content')
@if ($invoice)
@if ($invoice && $invoice->id)
<ol class="breadcrumb">
<li>{{ link_to('invoices', 'Invoices') }}</li>
<li>{{ link_to(($entityType == ENTITY_QUOTE ? 'quotes' : 'invoices'), trans('texts.' . ($entityType == ENTITY_QUOTE ? 'quotes' : 'invoices'))) }}</li>
<li class='active'>{{ $invoice->invoice_number }}</li>
</ol>
@endif
@ -28,7 +28,7 @@
<div class="row" style="min-height:195px" onkeypress="formEnterClick(event)">
<div class="col-md-4" id="col_1">
@if ($invoice)
@if ($invoice && $invoice->id)
<div class="form-group">
<label for="client" class="control-label col-lg-4 col-sm-4">Client</label>
<div class="col-lg-8 col-sm-8" style="padding-top: 7px">
@ -46,7 +46,7 @@
</div>
</div>
@if ($invoice)
@if ($invoice && $invoice->id)
</div>
@endif
@ -64,7 +64,7 @@
</div>
<div class="col-md-4" id="col_2">
<div data-bind="visible: !is_recurring()">
{{ Former::text('invoice_date')->data_bind("datePicker: invoice_date, valueUpdate: 'afterkeydown'")
{{ Former::text('invoice_date')->data_bind("datePicker: invoice_date, valueUpdate: 'afterkeydown'")->label(trans("texts.{$entityType}_date"))
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT))->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'invoice_date\')"></i>') }}
{{ Former::text('due_date')->data_bind("datePicker: due_date, valueUpdate: 'afterkeydown'")
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT))->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'due_date\')"></i>') }}
@ -77,22 +77,22 @@
{{ Former::text('end_date')->data_bind("datePicker: end_date, valueUpdate: 'afterkeydown'")
->data_date_format(Session::get(SESSION_DATE_PICKER_FORMAT))->append('<i class="glyphicon glyphicon-calendar" onclick="toggleDatePicker(\'end_date\')"></i>') }}
</div>
@endif
@if ($invoice && $invoice->recurring_invoice_id)
<div class="pull-right" style="padding-top: 6px">
Created by a {{ link_to('/invoices/'.$invoice->recurring_invoice_id, 'recurring invoice') }}
</div>
@else
<div data-bind="visible: invoice_status_id() < CONSTS.INVOICE_STATUS_SENT">
{{ Former::checkbox('recurring')->text(trans('texts.enable').' &nbsp;&nbsp; <a href="#" onclick="showLearnMore()"><i class="glyphicon glyphicon-question-sign"></i> '.trans('texts.learn_more').'</a>')->data_bind("checked: is_recurring")
->inlineHelp($invoice && $invoice->last_sent_date ? 'Last invoice sent ' . Utils::dateToString($invoice->last_sent_date) : '') }}
</div>
@if ($invoice && $invoice->recurring_invoice_id)
<div class="pull-right" style="padding-top: 6px">
Created by a {{ link_to('/invoices/'.$invoice->recurring_invoice_id, 'recurring invoice') }}
</div>
@else
<div data-bind="visible: invoice_status_id() < CONSTS.INVOICE_STATUS_SENT">
{{ Former::checkbox('recurring')->text(trans('texts.enable').' &nbsp;&nbsp; <a href="#" onclick="showLearnMore()"><i class="glyphicon glyphicon-question-sign"></i> '.trans('texts.learn_more').'</a>')->data_bind("checked: is_recurring")
->inlineHelp($invoice && $invoice->last_sent_date ? 'Last invoice sent ' . Utils::dateToString($invoice->last_sent_date) : '') }}
</div>
@endif
@endif
</div>
<div class="col-md-4" id="col_2">
{{ Former::text('invoice_number')->label(trans('texts.invoice_number_short'))->data_bind("value: invoice_number, valueUpdate: 'afterkeydown'") }}
{{ Former::text('invoice_number')->label(trans("texts.{$entityType}_number_short"))->data_bind("value: invoice_number, valueUpdate: 'afterkeydown'") }}
{{ Former::text('po_number')->label(trans('texts.po_number_short'))->data_bind("value: po_number, valueUpdate: 'afterkeydown'") }}
{{ Former::text('discount')->data_bind("value: discount, valueUpdate: 'afterkeydown'")->append('%') }}
{{-- Former::select('currency_id')->addOption('', '')->fromQuery($currencies, 'name', 'id')->data_bind("value: currency_id") --}}
@ -193,7 +193,7 @@
<tr>
<td class="hide-border" colspan="3"/>
<td style="display:none" class="hide-border" data-bind="visible: $root.invoice_item_taxes.show"/>
<td colspan="2"><b>{{ trans('texts.balance_due') }}</b></td>
<td colspan="2"><b>{{ trans($entityType == ENTITY_INVOICE ? 'texts.balance_due' : 'texts.total') }}</b></td>
<td style="text-align: right"><span data-bind="text: totals.total"/></td>
</tr>
</tfoot>
@ -203,8 +203,11 @@
<div class="form-actions">
<div style="display:none">
{{ Former::populateField('entityType', $entityType) }}
{{ Former::text('entityType') }}
{{ Former::text('action') }}
@if ($invoice)
@if ($invoice && $invoice->id)
{{ Former::populateField('id', $invoice->public_id) }}
{{ Former::text('id') }}
@endif
@ -219,51 +222,44 @@
{{ Button::primary(trans('texts.download_pdf'), array('onclick' => 'onDownloadClick()'))->append_with_icon('download-alt'); }}
@if (!$invoice || (!$invoice->trashed() && !$invoice->client->trashed()))
@if ($invoice)
@if ($invoice && $invoice->id)
<div id="primaryActions" style="text-align:left" class="btn-group">
<button class="btn-success btn" type="button">{{ trans('texts.save_invoice') }}</button>
<button class="btn-success btn" type="button">{{ trans("texts.save_{$entityType}") }}</button>
<button class="btn-success btn dropdown-toggle" type="button" data-toggle="dropdown">
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="javascript:onSaveClick()" id="saveButton">{{ trans('texts.save_invoice') }}</a></li>
<li><a href="javascript:onCloneClick()">{{ trans('texts.clone_invoice') }}</a></li>
<li><a href="javascript:onSaveClick()" id="saveButton">{{ trans("texts.save_{$entityType}") }}</a></li>
<li><a href="javascript:onCloneClick()">{{ trans("texts.clone_{$entityType}") }}</a></li>
@if ($invoice && $entityType == ENTITY_QUOTE)
<li class="divider"></li>
@if ($invoice->quote_invoice_id)
<li><a href="{{ URL::to("invoices/{$invoice->quote_invoice_id}/edit") }}">{{ trans("texts.view_invoice") }}</a></li>
@else
<li><a href="javascript:onConvertClick()">{{ trans("texts.convert_to_invoice") }}</a></li>
@endif
@elseif ($invoice && $entityType == ENTITY_INVOICE)
@if ($invoice->quote_id)
<li class="divider"></li>
<li><a href="{{ URL::to("invoices/{$invoice->quote_id}/edit") }}">{{ trans("texts.view_quote") }}</a></li>
@endif
@endif
<li class="divider"></li>
<li><a href="javascript:onArchiveClick()">{{ trans('texts.archive_invoice') }}</a></li>
<li><a href="javascript:onDeleteClick()">{{ trans('texts.delete_invoice') }}</a></li>
<li><a href="javascript:onArchiveClick()">{{ trans("texts.archive_{$entityType}") }}</a></li>
<li><a href="javascript:onDeleteClick()">{{ trans("texts.delete_{$entityType}") }}</a></li>
</ul>
</div>
{{-- DropdownButton::normal('Download PDF',
Navigation::links(
array(
array('Download PDF', "javascript:onDownloadClick()"),
array(Navigation::DIVIDER),
array('Create Payment', "javascript:onPaymentClick()"),
array('Create Credit', "javascript:onCreditClick()"),
)
)
, array('id'=>'relatedActions', 'style'=>'text-align:left'))->split(); --}}
{{-- DropdownButton::primary('Save Invoice',
Navigation::links(
array(
array('Save Invoice', "javascript:onSaveClick()"),
array('Clone Invoice', "javascript:onCloneClick()"),
array(Navigation::DIVIDER),
array('Archive Invoice', "javascript:onArchiveClick()"),
array('Delete Invoice', "javascript:onDeleteClick()"),
)
)
, array('id'=>'primaryActions', 'style'=>'text-align:left', 'data-bind'=>'css: $root.enable.save'))->split(); --}}
@else
{{ Button::success(trans('texts.save_invoice'), array('id' => 'saveButton', 'onclick' => 'onSaveClick()')) }}
{{ Button::success(trans("texts.save_{$entityType}"), array('id' => 'saveButton', 'onclick' => 'onSaveClick()')) }}
@endif
{{ Button::normal(trans('texts.email_invoice'), array('id' => 'email_button', 'onclick' => 'onEmailClick()'))->append_with_icon('send'); }}
{{ Button::normal(trans("texts.email_{$entityType}"), array('id' => 'email_button', 'onclick' => 'onEmailClick()'))->append_with_icon('send'); }}
@if ($invoice)
@if ($invoice && $invoice->id && $entityType == ENTITY_INVOICE)
{{ Button::primary(trans('texts.enter_payment'), array('onclick' => 'onPaymentClick()'))->append_with_icon('usd'); }}
@endif
@endif
@ -582,6 +578,7 @@
function createInvoiceModel() {
var invoice = ko.toJS(model).invoice;
invoice.is_pro = {{ Auth::user()->isPro() ? 'true' : 'false' }};
invoice.is_quote = {{ $entityType == ENTITY_QUOTE ? 'true' : 'false' }};
@if (file_exists($account->getLogoPath()))
invoice.image = "{{ HTML::image_data($account->getLogoPath()) }}";
@ -669,7 +666,7 @@
function onEmailClick() {
@if (Auth::user()->confirmed)
if (confirm('Are you sure you want to email this invoice?')) {
if (confirm('Are you sure you want to email this {{ $entityType }}?')) {
$('#action').val('email');
$('#submitButton').click();
}
@ -722,6 +719,11 @@
$('#submitButton').click();
}
function onConvertClick() {
$('#action').val('convert');
$('#submitButton').click();
}
@if ($client && $invoice)
function onPaymentClick() {
window.location = '{{ URL::to('payments/create/' . $client->public_id . '/' . $invoice->public_id ) }}';

View File

@ -5,7 +5,7 @@
@include('script')
<link href="{{ asset('vendor/bootstrap/dist/css/bootstrap.min.css') }}" rel="stylesheet" type="text/css"/>
<link href="{{ asset('vendor/bootstrap/dist/css/bootstrap.min.css') }}" rel="stylesheet" type="text/css"/>
<script src="{{ asset('js/pdf_viewer.js') }}" type="text/javascript"></script>
<script src="{{ asset('js/compatibility.js') }}" type="text/javascript"></script>
@ -23,7 +23,7 @@
<p>&nbsp;</p>
@if ($invoice->client->account->isGatewayConfigured() && !$invoice->isPaid())
@if ($invoice->client->account->isGatewayConfigured() && !$invoice->isPaid() && !$invoice->is_quote && !$invoice->is_recurring)
<div class="pull-right" style="width:270px">
{{ Button::normal(trans('texts.download_pdf'), array('onclick' => 'onDownloadClick()', 'class' => 'btn-lg')) }}
{{ Button::success_link(URL::to('payment/' . $invitation->invitation_key), trans('texts.pay_now'), array('class' => 'btn-lg pull-right')) }}

View File

@ -9,8 +9,9 @@
<div class="cell">Live .PDF invoice creation </div>
<div class="cell">4 beatiful invoice templates</div>
<div class="cell">Accept credit card payments</div>
<div class="cell">Quotes/Pro-Forma Invoices</div>
<div class="cell">Custom invoice fields and colors</div>
<div class="cell">Basic chart builder</div>
<div class="cell">Dynamic chart builder</div>
<div class="cell">Priority email support</div>
<div class="cell">Remove "Created by Invoice Ninja"</div>
<div class="cell">Latest and greatest features</div>
@ -25,8 +26,9 @@
<div class="cell"><div class="hide-desktop">Live .PDF invoice creation</div><span class="glyphicon glyphicon-ok"></div>
<div class="cell"><div class="hide-desktop">4 beatiful invoice templates</div><span class="glyphicon glyphicon-ok"></div>
<div class="cell"><div class="hide-desktop">Accept credit card payments</div><span class="glyphicon glyphicon-ok"></div>
<div class="cell"><div class="hide-desktop">Quotes/Pro-Forma Invoices</div><span class="glyphicon glyphicon-remove"></div>
<div class="cell"><div class="hide-desktop">Custom fields and invoice colors</div><span class="glyphicon glyphicon-remove"></div>
<div class="cell"><div class="hide-desktop">Basic chart builder</div><span class="glyphicon glyphicon-remove"></div>
<div class="cell"><div class="hide-desktop">Dynamic chart builder</div><span class="glyphicon glyphicon-remove"></div>
<div class="cell"><div class="hide-desktop">Priority email support</div><span class="glyphicon glyphicon-remove"></div>
<div class="cell"><div class="hide-desktop">Remove "Created by Invoice Ninja"</div><span class="glyphicon glyphicon-remove"></div>
<div class="cell"><div class="hide-desktop">Latest and greatest features</div><span class="glyphicon glyphicon-remove"></div>
@ -41,8 +43,9 @@
<div class="cell"><div class="hide-desktop">Live .PDF invoice creation</div><span class="glyphicon glyphicon-ok"></div>
<div class="cell"><div class="hide-desktop">4 beatiful invoice templates</div><span class="glyphicon glyphicon-ok"></div>
<div class="cell"><div class="hide-desktop">Accept credit card payments</div><span class="glyphicon glyphicon-ok"></div>
<div class="cell"><div class="hide-desktop">Quotes/Pro-Forma Invoices</div><span class="glyphicon glyphicon-ok"></div>
<div class="cell"><div class="hide-desktop">Custom invoice fields and colors</div><span class="glyphicon glyphicon-ok"></div>
<div class="cell"><div class="hide-desktop">Basic chart builder</div><span class="glyphicon glyphicon-ok"></div>
<div class="cell"><div class="hide-desktop">Dynamic chart builder</div><span class="glyphicon glyphicon-ok"></div>
<div class="cell"><div class="hide-desktop">Priority email support</div><span class="glyphicon glyphicon-ok"></div>
<div class="cell"><div class="hide-desktop">Remove "Created by Invoice Ninja"</div><span class="glyphicon glyphicon-ok"></div>
<div class="cell"><div class="hide-desktop">Latest and greatest features</div><span class="glyphicon glyphicon-ok"></div>

View File

@ -1,6 +1,7 @@
@extends('master')
@section('head')
<meta name="csrf-token" content="<?= csrf_token() ?>">
<link href="{{ asset('built.public.css') }}" rel="stylesheet" type="text/css"/>
<!--
@ -107,6 +108,19 @@
</div>
</div>
<div class="container">
@if (Session::has('warning'))
<div class="alert alert-warning">{{ Session::get('warning') }}</div>
@endif
@if (Session::has('message'))
<div class="alert alert-info">{{ Session::get('message') }}</div>
@endif
@if (Session::has('error'))
<div class="alert alert-danger">{{ Session::get('error') }}</div>
@endif
</div>
@yield('content')

View File

@ -37738,7 +37738,7 @@ function GetReportTemplate4(doc, invoice, layout, checkMath) {
doc.setDrawColor(200,200,200);
doc.setFillColor(230,230,230);
var detailsHeight = getInvoiceDetailsHeight(invoice, layout)
var detailsHeight = getInvoiceDetailsHeight(invoice, layout);
var left = layout.headerLeft - layout.tablePadding;
var top = layout.headerTop + detailsHeight - layout.rowHeight - layout.tablePadding;
var width = layout.headerRight - layout.headerLeft + (2 * layout.tablePadding);
@ -37803,7 +37803,7 @@ function GetReportTemplate4(doc, invoice, layout, checkMath) {
doc.rect(left, top, width, height, 'FD');
doc.setFontType("bold");
doc.text(layout.footerLeft, y, invoiceLabels.balance_due);
doc.text(layout.footerLeft, y, invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due);
total = formatMoney(invoice.balance_amount, currencyId);
var totalX = layout.headerRight - (doc.getStringUnitWidth(total) * doc.internal.getFontSize());
@ -38428,7 +38428,7 @@ function GetReportTemplate1(doc, invoice, layout, checkMath)
SetPdfColor('LightBlue', doc, 'primary');
doc.setFontSize('11');
doc.text(50, layout.headerTop, invoiceLabels.invoice.toUpperCase());
doc.text(50, layout.headerTop, (invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice).toUpperCase());
//doc.setDrawColor(220,220,220);
//doc.line(30, y, 560, y); // horizontal line
@ -38491,7 +38491,7 @@ function GetReportTemplate1(doc, invoice, layout, checkMath)
doc.setFontSize(10);
Msg = invoiceLabels.balance_due;
Msg = invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due;
var TmpMsgX = layout.unitCostRight-(doc.getStringUnitWidth(Msg) * doc.internal.getFontSize());
doc.text(TmpMsgX, y, Msg);
@ -38614,7 +38614,7 @@ function GetReportTemplate2(doc, invoice, layout, checkMath)
SetPdfColor('SomeGreen', doc, 'secondary');
doc.setFontSize('14');
doc.setFontType("bold");
doc.text(50, GlobalY, invoiceLabels.your_invoice.toUpperCase());
doc.text(50, GlobalY, (invoice.is_quote ? invoiceLabels.your_quote : invoiceLabels.your_invoice).toUpperCase());
var z=GlobalY;
@ -38671,7 +38671,7 @@ function GetReportTemplate2(doc, invoice, layout, checkMath)
doc.setFontSize(12);
x += doc.internal.getFontSize()*4;
Msg = invoiceLabels.balance_due;
Msg = invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due;
var TmpMsgX = layout.unitCostRight-(doc.getStringUnitWidth(Msg) * doc.internal.getFontSize());
@ -38893,7 +38893,7 @@ function GetReportTemplate3(doc, invoice, layout, checkMath)
SetPdfColor('White', doc);
doc.setFontSize(12);
var label = invoiceLabels.balance_due;
var label = invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due;
var labelX = layout.unitCostRight-(doc.getStringUnitWidth(label) * doc.internal.getFontSize());
doc.text(labelX, y+2, label);
@ -39124,6 +39124,16 @@ function displayGrid(doc, invoice, data, x, y, layout, hasheader, rightAlignX, r
doc.text(marginLeft, y, value);
doc.setFontType('normal');
if (invoice.is_quote) {
if (key == 'invoice_number') {
key = 'quote_number';
} else if (key == 'invoice_date') {
key = 'quote_date';
} else if (key == 'balance_due') {
key = 'total';
}
}
if (key.substring(0, 6) === 'custom') {
key = invoice.account[key];
} else {

View File

@ -22,7 +22,7 @@ function GetReportTemplate4(doc, invoice, layout, checkMath) {
doc.setDrawColor(200,200,200);
doc.setFillColor(230,230,230);
var detailsHeight = getInvoiceDetailsHeight(invoice, layout)
var detailsHeight = getInvoiceDetailsHeight(invoice, layout);
var left = layout.headerLeft - layout.tablePadding;
var top = layout.headerTop + detailsHeight - layout.rowHeight - layout.tablePadding;
var width = layout.headerRight - layout.headerLeft + (2 * layout.tablePadding);
@ -87,7 +87,7 @@ function GetReportTemplate4(doc, invoice, layout, checkMath) {
doc.rect(left, top, width, height, 'FD');
doc.setFontType("bold");
doc.text(layout.footerLeft, y, invoiceLabels.balance_due);
doc.text(layout.footerLeft, y, invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due);
total = formatMoney(invoice.balance_amount, currencyId);
var totalX = layout.headerRight - (doc.getStringUnitWidth(total) * doc.internal.getFontSize());
@ -712,7 +712,7 @@ function GetReportTemplate1(doc, invoice, layout, checkMath)
SetPdfColor('LightBlue', doc, 'primary');
doc.setFontSize('11');
doc.text(50, layout.headerTop, invoiceLabels.invoice.toUpperCase());
doc.text(50, layout.headerTop, (invoice.is_quote ? invoiceLabels.quote : invoiceLabels.invoice).toUpperCase());
//doc.setDrawColor(220,220,220);
//doc.line(30, y, 560, y); // horizontal line
@ -775,7 +775,7 @@ function GetReportTemplate1(doc, invoice, layout, checkMath)
doc.setFontSize(10);
Msg = invoiceLabels.balance_due;
Msg = invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due;
var TmpMsgX = layout.unitCostRight-(doc.getStringUnitWidth(Msg) * doc.internal.getFontSize());
doc.text(TmpMsgX, y, Msg);
@ -898,7 +898,7 @@ function GetReportTemplate2(doc, invoice, layout, checkMath)
SetPdfColor('SomeGreen', doc, 'secondary');
doc.setFontSize('14');
doc.setFontType("bold");
doc.text(50, GlobalY, invoiceLabels.your_invoice.toUpperCase());
doc.text(50, GlobalY, (invoice.is_quote ? invoiceLabels.your_quote : invoiceLabels.your_invoice).toUpperCase());
var z=GlobalY;
@ -955,7 +955,7 @@ function GetReportTemplate2(doc, invoice, layout, checkMath)
doc.setFontSize(12);
x += doc.internal.getFontSize()*4;
Msg = invoiceLabels.balance_due;
Msg = invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due;
var TmpMsgX = layout.unitCostRight-(doc.getStringUnitWidth(Msg) * doc.internal.getFontSize());
@ -1177,7 +1177,7 @@ function GetReportTemplate3(doc, invoice, layout, checkMath)
SetPdfColor('White', doc);
doc.setFontSize(12);
var label = invoiceLabels.balance_due;
var label = invoice.is_quote ? invoiceLabels.total : invoiceLabels.balance_due;
var labelX = layout.unitCostRight-(doc.getStringUnitWidth(label) * doc.internal.getFontSize());
doc.text(labelX, y+2, label);
@ -1408,6 +1408,16 @@ function displayGrid(doc, invoice, data, x, y, layout, hasheader, rightAlignX, r
doc.text(marginLeft, y, value);
doc.setFontType('normal');
if (invoice.is_quote) {
if (key == 'invoice_number') {
key = 'quote_number';
} else if (key == 'invoice_date') {
key = 'quote_date';
} else if (key == 'balance_due') {
key = 'total';
}
}
if (key.substring(0, 6) === 'custom') {
key = invoice.account[key];
} else {