mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2025-07-08 06:14:31 -04:00
Bug fixes
This commit is contained in:
parent
0c0a71a8ed
commit
0948b46ea2
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
|||||||
/app/config/staging
|
/app/config/staging
|
||||||
/app/config/development
|
/app/config/development
|
||||||
|
/app/config/production
|
||||||
/app/config/fortrabbit
|
/app/config/fortrabbit
|
||||||
/app/config/ubuntu
|
/app/config/ubuntu
|
||||||
/app/config/packages/anahkiasen/rocketeer/
|
/app/config/packages/anahkiasen/rocketeer/
|
||||||
|
@ -13,7 +13,7 @@ return array(
|
|||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'debug' => false,
|
'debug' => true,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
@ -38,6 +38,7 @@ class AppController extends BaseController {
|
|||||||
|
|
||||||
$app = Input::get('app');
|
$app = Input::get('app');
|
||||||
$app['key'] = str_random(RANDOM_KEY_LENGTH);
|
$app['key'] = str_random(RANDOM_KEY_LENGTH);
|
||||||
|
$app['debug'] = false;
|
||||||
|
|
||||||
$database = Input::get('database');
|
$database = Input::get('database');
|
||||||
$dbType = $database['default'];
|
$dbType = $database['default'];
|
||||||
|
@ -149,15 +149,26 @@ class Account extends Eloquent
|
|||||||
return $prefix . str_pad($counter, 4, "0", STR_PAD_LEFT);
|
return $prefix . str_pad($counter, 4, "0", STR_PAD_LEFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function incrementCounter($isQuote = false)
|
public function incrementCounter($invoiceNumber, $isQuote = false, $isRecurring)
|
||||||
{
|
{
|
||||||
if ($isQuote && !$this->share_counter) {
|
// check if the user modified the invoice number
|
||||||
$this->quote_number_counter += 1;
|
if (!$isRecurring && $invoiceNumber != $this->getNextInvoiceNumber($isQuote)) {
|
||||||
} else {
|
$number = intval(preg_replace('/[^0-9]/', '', $invoiceNumber));
|
||||||
$this->invoice_number_counter += 1;
|
if ($isQuote && !$this->share_counter) {
|
||||||
}
|
$this->quote_number_counter = $number + 1;
|
||||||
|
} else {
|
||||||
|
$this->invoice_number_counter = $number + 1;
|
||||||
|
}
|
||||||
|
// otherwise, just increment the counter
|
||||||
|
} else {
|
||||||
|
if ($isQuote && !$this->share_counter) {
|
||||||
|
$this->quote_number_counter += 1;
|
||||||
|
} else {
|
||||||
|
$this->invoice_number_counter += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$this->save();
|
$this->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLocale()
|
public function getLocale()
|
||||||
|
@ -2,23 +2,23 @@
|
|||||||
|
|
||||||
class Invitation extends EntityModel
|
class Invitation extends EntityModel
|
||||||
{
|
{
|
||||||
public function invoice()
|
public function invoice()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('Invoice');
|
return $this->belongsTo('Invoice');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function contact()
|
public function contact()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('Contact');
|
return $this->belongsTo('Contact');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function user()
|
public function user()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('User');
|
return $this->belongsTo('User');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getLink()
|
public function getLink()
|
||||||
{
|
{
|
||||||
return SITE_URL . '/view/' . $this->invitation_key;
|
return SITE_URL.'/view/'.$this->invitation_key;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -222,7 +222,7 @@ class Invoice extends EntityModel
|
|||||||
|
|
||||||
Invoice::created(function($invoice)
|
Invoice::created(function($invoice)
|
||||||
{
|
{
|
||||||
$invoice->account->incrementCounter($invoice->is_quote);
|
$invoice->account->incrementCounter($invoice->invoice_number, $invoice->is_quote, $invoice->recurring_invoice_id);
|
||||||
Activity::createInvoice($invoice);
|
Activity::createInvoice($invoice);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -4,98 +4,96 @@ use Invoice;
|
|||||||
use Payment;
|
use Payment;
|
||||||
use Contact;
|
use Contact;
|
||||||
use Invitation;
|
use Invitation;
|
||||||
use URL;
|
|
||||||
use Auth;
|
|
||||||
use Activity;
|
use Activity;
|
||||||
use Utils;
|
use Utils;
|
||||||
|
|
||||||
class ContactMailer extends Mailer {
|
class ContactMailer extends Mailer
|
||||||
|
{
|
||||||
|
public function sendInvoice(Invoice $invoice)
|
||||||
|
{
|
||||||
|
$invoice->load('invitations', 'client', 'account');
|
||||||
|
$entityType = $invoice->getEntityType();
|
||||||
|
|
||||||
public function sendInvoice(Invoice $invoice)
|
$view = 'invoice';
|
||||||
{
|
$subject = trans("texts.{$entityType}_subject", ['invoice' => $invoice->invoice_number, 'account' => $invoice->account->getDisplayName()]);
|
||||||
$invoice->load('invitations', 'client', 'account');
|
$accountName = $invoice->account->getDisplayName();
|
||||||
$entityType = $invoice->getEntityType();
|
|
||||||
|
|
||||||
$view = 'invoice';
|
foreach ($invoice->invitations as $invitation) {
|
||||||
$subject = trans("texts.{$entityType}_subject", ['invoice' => $invoice->invoice_number, 'account' => $invoice->account->getDisplayName()]);
|
if (!$invitation->user || !$invitation->user->email) {
|
||||||
$accountName = $invoice->account->getDisplayName();
|
return false;
|
||||||
|
}
|
||||||
|
if (!$invitation->contact || $invitation->contact->email) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($invoice->invitations as $invitation)
|
$invitation->sent_date = \Carbon::now()->toDateTimeString();
|
||||||
{
|
$invitation->save();
|
||||||
if (!$invitation->user->email)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$invitation->sent_date = \Carbon::now()->toDateTimeString();
|
$data = [
|
||||||
$invitation->save();
|
'entityType' => $entityType,
|
||||||
|
'link' => $invitation->getLink(),
|
||||||
|
'clientName' => $invoice->client->getDisplayName(),
|
||||||
|
'accountName' => $accountName,
|
||||||
|
'contactName' => $invitation->contact->getDisplayName(),
|
||||||
|
'invoiceAmount' => Utils::formatMoney($invoice->amount, $invoice->client->currency_id),
|
||||||
|
'emailFooter' => $invoice->account->email_footer,
|
||||||
|
'showNinjaFooter' => !$invoice->account->isPro(),
|
||||||
|
];
|
||||||
|
|
||||||
$data = [
|
$fromEmail = $invitation->user->email;
|
||||||
'entityType' => $entityType,
|
$this->sendTo($invitation->contact->email, $fromEmail, $accountName, $subject, $view, $data);
|
||||||
'link' => $invitation->getLink(),
|
|
||||||
'clientName' => $invoice->client->getDisplayName(),
|
|
||||||
'accountName' => $accountName,
|
|
||||||
'contactName' => $invitation->contact->getDisplayName(),
|
|
||||||
'invoiceAmount' => Utils::formatMoney($invoice->amount, $invoice->client->currency_id),
|
|
||||||
'emailFooter' => $invoice->account->email_footer,
|
|
||||||
'showNinjaFooter' => !$invoice->account->isPro()
|
|
||||||
];
|
|
||||||
|
|
||||||
$fromEmail = $invitation->user->email;
|
Activity::emailInvoice($invitation);
|
||||||
$this->sendTo($invitation->contact->email, $fromEmail, $accountName, $subject, $view, $data);
|
}
|
||||||
|
|
||||||
Activity::emailInvoice($invitation);
|
if (!$invoice->isSent()) {
|
||||||
}
|
$invoice->invoice_status_id = INVOICE_STATUS_SENT;
|
||||||
|
$invoice->save();
|
||||||
|
}
|
||||||
|
|
||||||
if (!$invoice->isSent())
|
\Event::fire('invoice.sent', $invoice);
|
||||||
{
|
}
|
||||||
$invoice->invoice_status_id = INVOICE_STATUS_SENT;
|
|
||||||
$invoice->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
\Event::fire('invoice.sent', $invoice);
|
public function sendPaymentConfirmation(Payment $payment)
|
||||||
}
|
{
|
||||||
|
$view = 'payment_confirmation';
|
||||||
|
$subject = trans('texts.payment_subject', ['invoice' => $payment->invoice->invoice_number]);
|
||||||
|
$accountName = $payment->account->getDisplayName();
|
||||||
|
|
||||||
public function sendPaymentConfirmation(Payment $payment)
|
$data = [
|
||||||
{
|
'accountName' => $accountName,
|
||||||
$view = 'payment_confirmation';
|
'clientName' => $payment->client->getDisplayName(),
|
||||||
$subject = trans('texts.payment_subject', ['invoice' => $payment->invoice->invoice_number]);
|
'emailFooter' => $payment->account->email_footer,
|
||||||
$accountName = $payment->account->getDisplayName();
|
'paymentAmount' => Utils::formatMoney($payment->amount, $payment->client->currency_id),
|
||||||
|
'showNinjaFooter' => !$payment->account->isPro(),
|
||||||
|
];
|
||||||
|
|
||||||
$data = [
|
$user = $payment->invitation->user;
|
||||||
'accountName' => $accountName,
|
$this->sendTo($payment->contact->email, $user->email, $accountName, $subject, $view, $data);
|
||||||
'clientName' => $payment->client->getDisplayName(),
|
}
|
||||||
'emailFooter' => $payment->account->email_footer,
|
|
||||||
'paymentAmount' => Utils::formatMoney($payment->amount, $payment->client->currency_id),
|
|
||||||
'showNinjaFooter' => !$payment->account->isPro()
|
|
||||||
];
|
|
||||||
|
|
||||||
$user = $payment->invitation->user;
|
public function sendLicensePaymentConfirmation($name, $email, $amount, $license, $productId)
|
||||||
$this->sendTo($payment->contact->email, $user->email, $accountName, $subject, $view, $data);
|
{
|
||||||
}
|
$view = 'payment_confirmation';
|
||||||
|
$subject = trans('texts.payment_subject');
|
||||||
|
|
||||||
public function sendLicensePaymentConfirmation($name, $email, $amount, $license, $productId)
|
if ($productId == PRODUCT_ONE_CLICK_INSTALL) {
|
||||||
{
|
$message = "Softaculous install license: $license";
|
||||||
$view = 'payment_confirmation';
|
} elseif ($productId == PRODUCT_INVOICE_DESIGNS) {
|
||||||
$subject = trans('texts.payment_subject');
|
$message = "Invoice designs license: $license";
|
||||||
|
} elseif ($productId == PRODUCT_WHITE_LABEL) {
|
||||||
|
$message = "White label license: $license";
|
||||||
|
}
|
||||||
|
|
||||||
if ($productId == PRODUCT_ONE_CLICK_INSTALL) {
|
$data = [
|
||||||
$message = "Softaculous install license: $license";
|
'accountName' => trans('texts.email_from'),
|
||||||
} else if ($productId == PRODUCT_INVOICE_DESIGNS) {
|
'clientName' => $name,
|
||||||
$message = "Invoice designs license: $license";
|
'emailFooter' => false,
|
||||||
} else if ($productId == PRODUCT_WHITE_LABEL) {
|
'paymentAmount' => Utils::formatMoney($amount, 1),
|
||||||
$message = "White label license: $license";
|
'showNinjaFooter' => false,
|
||||||
}
|
'emailMessage' => $message,
|
||||||
|
];
|
||||||
|
|
||||||
$data = [
|
$this->sendTo($email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data);
|
||||||
'accountName' => trans('texts.email_from'),
|
}
|
||||||
'clientName' => $name,
|
|
||||||
'emailFooter' => false,
|
|
||||||
'paymentAmount' => Utils::formatMoney($amount, 1),
|
|
||||||
'showNinjaFooter' => false,
|
|
||||||
'emailMessage' => $message,
|
|
||||||
];
|
|
||||||
|
|
||||||
$this->sendTo($email, CONTACT_EMAIL, CONTACT_NAME, $subject, $view, $data);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -11,7 +11,8 @@ class ClientRepository
|
|||||||
->join('contacts', 'contacts.client_id', '=', 'clients.id')
|
->join('contacts', 'contacts.client_id', '=', 'clients.id')
|
||||||
->where('clients.account_id', '=', \Auth::user()->account_id)
|
->where('clients.account_id', '=', \Auth::user()->account_id)
|
||||||
->where('contacts.is_primary', '=', true)
|
->where('contacts.is_primary', '=', true)
|
||||||
->select('clients.public_id','clients.name','contacts.first_name','contacts.last_name','clients.balance','clients.last_login','clients.created_at','clients.work_phone','contacts.email','clients.currency_id', 'clients.deleted_at', 'clients.is_deleted');
|
->where('contacts.deleted_at', '=', null)
|
||||||
|
->select('clients.public_id','clients.name','contacts.first_name','contacts.last_name','clients.balance','clients.last_login','clients.created_at','clients.work_phone','contacts.email','clients.currency_id', 'clients.deleted_at', 'clients.is_deleted');
|
||||||
|
|
||||||
if (!\Session::get('show_trash:client'))
|
if (!\Session::get('show_trash:client'))
|
||||||
{
|
{
|
||||||
@ -201,6 +202,9 @@ class ClientRepository
|
|||||||
if ($action == 'restore')
|
if ($action == 'restore')
|
||||||
{
|
{
|
||||||
$client->restore();
|
$client->restore();
|
||||||
|
|
||||||
|
$client->is_deleted = false;
|
||||||
|
$client->save();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -5,89 +5,81 @@ use InvoiceItem;
|
|||||||
use Invitation;
|
use Invitation;
|
||||||
use Product;
|
use Product;
|
||||||
use Utils;
|
use Utils;
|
||||||
use TaxRate;
|
|
||||||
|
|
||||||
class InvoiceRepository
|
class InvoiceRepository
|
||||||
{
|
{
|
||||||
public function getInvoices($accountId, $clientPublicId = false, $entityType = ENTITY_INVOICE, $filter = false)
|
public function getInvoices($accountId, $clientPublicId = false, $entityType = ENTITY_INVOICE, $filter = false)
|
||||||
{
|
{
|
||||||
$query = \DB::table('invoices')
|
$query = \DB::table('invoices')
|
||||||
->join('clients', 'clients.id', '=','invoices.client_id')
|
->join('clients', 'clients.id', '=', 'invoices.client_id')
|
||||||
->join('invoice_statuses', 'invoice_statuses.id', '=', 'invoices.invoice_status_id')
|
->join('invoice_statuses', 'invoice_statuses.id', '=', 'invoices.invoice_status_id')
|
||||||
->join('contacts', 'contacts.client_id', '=', 'clients.id')
|
->join('contacts', 'contacts.client_id', '=', 'clients.id')
|
||||||
->where('invoices.account_id', '=', $accountId)
|
->where('invoices.account_id', '=', $accountId)
|
||||||
->where('clients.deleted_at', '=', null)
|
->where('clients.deleted_at', '=', null)
|
||||||
->where('contacts.deleted_at', '=', null)
|
->where('contacts.deleted_at', '=', null)
|
||||||
->where('invoices.is_recurring', '=', false)
|
->where('invoices.is_recurring', '=', false)
|
||||||
->where('contacts.is_primary', '=', true)
|
->where('contacts.is_primary', '=', true)
|
||||||
->select('clients.public_id as client_public_id', 'invoice_number', 'invoice_status_id', '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', 'invoices.deleted_at', 'invoices.is_deleted');
|
->select('clients.public_id as client_public_id', 'invoice_number', 'invoice_status_id', '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', 'invoices.deleted_at', 'invoices.is_deleted');
|
||||||
|
|
||||||
if (!\Session::get('show_trash:' . $entityType))
|
if (!\Session::get('show_trash:'.$entityType)) {
|
||||||
{
|
$query->where('invoices.deleted_at', '=', null);
|
||||||
$query->where('invoices.deleted_at', '=', null);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ($clientPublicId)
|
if ($clientPublicId) {
|
||||||
{
|
$query->where('clients.public_id', '=', $clientPublicId);
|
||||||
$query->where('clients.public_id', '=', $clientPublicId);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ($filter)
|
if ($filter) {
|
||||||
{
|
$query->where(function ($query) use ($filter) {
|
||||||
$query->where(function($query) use ($filter)
|
$query->where('clients.name', 'like', '%'.$filter.'%')
|
||||||
{
|
->orWhere('invoices.invoice_number', 'like', '%'.$filter.'%')
|
||||||
$query->where('clients.name', 'like', '%'.$filter.'%')
|
->orWhere('invoice_statuses.name', 'like', '%'.$filter.'%')
|
||||||
->orWhere('invoices.invoice_number', 'like', '%'.$filter.'%')
|
|
||||||
->orWhere('invoice_statuses.name', 'like', '%'.$filter.'%')
|
|
||||||
->orWhere('contacts.first_name', 'like', '%'.$filter.'%')
|
->orWhere('contacts.first_name', 'like', '%'.$filter.'%')
|
||||||
->orWhere('contacts.last_name', 'like', '%'.$filter.'%')
|
->orWhere('contacts.last_name', 'like', '%'.$filter.'%')
|
||||||
->orWhere('contacts.email', 'like', '%'.$filter.'%');
|
->orWhere('contacts.email', 'like', '%'.$filter.'%');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRecurringInvoices($accountId, $clientPublicId = false, $filter = false)
|
public function getRecurringInvoices($accountId, $clientPublicId = false, $filter = false)
|
||||||
{
|
{
|
||||||
$query = \DB::table('invoices')
|
$query = \DB::table('invoices')
|
||||||
->join('clients', 'clients.id', '=','invoices.client_id')
|
->join('clients', 'clients.id', '=', 'invoices.client_id')
|
||||||
->join('frequencies', 'frequencies.id', '=', 'invoices.frequency_id')
|
->join('frequencies', 'frequencies.id', '=', 'invoices.frequency_id')
|
||||||
->join('contacts', 'contacts.client_id', '=', 'clients.id')
|
->join('contacts', 'contacts.client_id', '=', 'clients.id')
|
||||||
->where('invoices.account_id', '=', $accountId)
|
->where('invoices.account_id', '=', $accountId)
|
||||||
->where('invoices.is_quote', '=', false)
|
->where('invoices.is_quote', '=', false)
|
||||||
->where('clients.deleted_at', '=', null)
|
->where('clients.deleted_at', '=', null)
|
||||||
->where('invoices.is_recurring', '=', true)
|
->where('contacts.deleted_at', '=', null)
|
||||||
->where('contacts.is_primary', '=', true)
|
->where('invoices.is_recurring', '=', true)
|
||||||
->select('clients.public_id as client_public_id', 'clients.name as client_name', 'invoices.public_id', 'amount', 'frequencies.name as frequency', 'start_date', 'end_date', 'clients.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email', 'invoices.deleted_at', 'invoices.is_deleted');
|
->where('contacts.is_primary', '=', true)
|
||||||
|
->select('clients.public_id as client_public_id', 'clients.name as client_name', 'invoices.public_id', 'amount', 'frequencies.name as frequency', 'start_date', 'end_date', 'clients.currency_id', 'contacts.first_name', 'contacts.last_name', 'contacts.email', 'invoices.deleted_at', 'invoices.is_deleted');
|
||||||
|
|
||||||
if ($clientPublicId)
|
if ($clientPublicId) {
|
||||||
{
|
$query->where('clients.public_id', '=', $clientPublicId);
|
||||||
$query->where('clients.public_id', '=', $clientPublicId);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!\Session::get('show_trash:invoice'))
|
if (!\Session::get('show_trash:invoice')) {
|
||||||
{
|
$query->where('invoices.deleted_at', '=', null);
|
||||||
$query->where('invoices.deleted_at', '=', null);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ($filter)
|
if ($filter) {
|
||||||
{
|
$query->where(function ($query) use ($filter) {
|
||||||
$query->where(function($query) use ($filter)
|
$query->where('clients.name', 'like', '%'.$filter.'%')
|
||||||
{
|
->orWhere('invoices.invoice_number', 'like', '%'.$filter.'%');
|
||||||
$query->where('clients.name', 'like', '%'.$filter.'%')
|
|
||||||
->orWhere('invoices.invoice_number', 'like', '%'.$filter.'%');
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return $query;
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getClientDatatable($contactId, $entityType, $search)
|
public function getClientDatatable($contactId, $entityType, $search)
|
||||||
{
|
{
|
||||||
$query = \DB::table('invitations')
|
$query = \DB::table('invitations')
|
||||||
->join('invoices', 'invoices.id', '=','invitations.invoice_id')
|
->join('invoices', 'invoices.id', '=', 'invitations.invoice_id')
|
||||||
->join('clients', 'clients.id', '=','invoices.client_id')
|
->join('clients', 'clients.id', '=', 'invoices.client_id')
|
||||||
//->join('contacts', 'contacts.client_id', '=', 'clients.id')
|
//->join('contacts', 'contacts.client_id', '=', 'clients.id')
|
||||||
->where('invitations.contact_id', '=', $contactId)
|
->where('invitations.contact_id', '=', $contactId)
|
||||||
->where('invitations.deleted_at', '=', null)
|
->where('invitations.deleted_at', '=', null)
|
||||||
@ -97,450 +89,386 @@ class InvoiceRepository
|
|||||||
->where('invoices.is_recurring', '=', false)
|
->where('invoices.is_recurring', '=', false)
|
||||||
->select('invitation_key', 'invoice_number', 'invoice_date', 'invoices.balance as balance', 'due_date', 'clients.public_id as client_public_id', 'clients.name as client_name', 'invoices.public_id', 'amount', 'start_date', 'end_date', 'clients.currency_id');
|
->select('invitation_key', 'invoice_number', 'invoice_date', 'invoices.balance as balance', 'due_date', 'clients.public_id as client_public_id', 'clients.name as client_name', 'invoices.public_id', 'amount', 'start_date', 'end_date', 'clients.currency_id');
|
||||||
|
|
||||||
$table = \Datatable::query($query)
|
$table = \Datatable::query($query)
|
||||||
->addColumn('invoice_number', function($model) use ($entityType) { return link_to('/view/' . $model->invitation_key, $model->invoice_number); })
|
->addColumn('invoice_number', function ($model) use ($entityType) { return link_to('/view/'.$model->invitation_key, $model->invoice_number); })
|
||||||
->addColumn('invoice_date', function($model) { return Utils::fromSqlDate($model->invoice_date); })
|
->addColumn('invoice_date', function ($model) { return Utils::fromSqlDate($model->invoice_date); })
|
||||||
->addColumn('amount', function($model) { return Utils::formatMoney($model->amount, $model->currency_id); });
|
->addColumn('amount', function ($model) { return Utils::formatMoney($model->amount, $model->currency_id); });
|
||||||
|
|
||||||
if ($entityType == ENTITY_INVOICE)
|
if ($entityType == ENTITY_INVOICE) {
|
||||||
{
|
$table->addColumn('balance', function ($model) { return Utils::formatMoney($model->balance, $model->currency_id); });
|
||||||
$table->addColumn('balance', function($model) { return Utils::formatMoney($model->balance, $model->currency_id); });
|
}
|
||||||
|
|
||||||
|
return $table->addColumn('due_date', function ($model) { return Utils::fromSqlDate($model->due_date); })
|
||||||
|
//->addColumn('invoice_status_name', function($model) { return $model->invoice_status_name; })
|
||||||
|
->make();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $table->addColumn('due_date', function($model) { return Utils::fromSqlDate($model->due_date); })
|
public function getDatatable($accountId, $clientPublicId = null, $entityType, $search)
|
||||||
//->addColumn('invoice_status_name', function($model) { return $model->invoice_status_name; })
|
{
|
||||||
->make();
|
$query = $this->getInvoices($accountId, $clientPublicId, $entityType, $search)
|
||||||
}
|
|
||||||
|
|
||||||
public function getDatatable($accountId, $clientPublicId = null, $entityType, $search)
|
|
||||||
{
|
|
||||||
$query = $this->getInvoices($accountId, $clientPublicId, $entityType, $search)
|
|
||||||
->where('invoices.is_quote', '=', $entityType == ENTITY_QUOTE ? true : false);
|
->where('invoices.is_quote', '=', $entityType == ENTITY_QUOTE ? true : false);
|
||||||
|
|
||||||
$table = \Datatable::query($query);
|
$table = \Datatable::query($query);
|
||||||
|
|
||||||
if (!$clientPublicId)
|
if (!$clientPublicId) {
|
||||||
{
|
$table->addColumn('checkbox', function ($model) { return '<input type="checkbox" name="ids[]" value="'.$model->public_id.'" '.Utils::getEntityRowClass($model).'>'; });
|
||||||
$table->addColumn('checkbox', function($model) { return '<input type="checkbox" name="ids[]" value="' . $model->public_id . '" ' . Utils::getEntityRowClass($model) . '>'; });
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$table->addColumn("invoice_number", function($model) use ($entityType) { return link_to("{$entityType}s/" . $model->public_id . '/edit', $model->invoice_number, ['class' => Utils::getEntityRowClass($model)]); });
|
$table->addColumn("invoice_number", function ($model) use ($entityType) { return link_to("{$entityType}s/".$model->public_id.'/edit', $model->invoice_number, ['class' => Utils::getEntityRowClass($model)]); });
|
||||||
|
|
||||||
if (!$clientPublicId)
|
if (!$clientPublicId) {
|
||||||
{
|
$table->addColumn('client_name', function ($model) { return link_to('clients/'.$model->client_public_id, Utils::getClientDisplayName($model)); });
|
||||||
$table->addColumn('client_name', function($model) { return link_to('clients/' . $model->client_public_id, Utils::getClientDisplayName($model)); });
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$table->addColumn("invoice_date", function($model) { return Utils::fromSqlDate($model->invoice_date); })
|
$table->addColumn("invoice_date", function ($model) { return Utils::fromSqlDate($model->invoice_date); })
|
||||||
->addColumn('amount', function($model) { return Utils::formatMoney($model->amount, $model->currency_id); });
|
->addColumn('amount', function ($model) { return Utils::formatMoney($model->amount, $model->currency_id); });
|
||||||
|
|
||||||
if ($entityType == ENTITY_INVOICE)
|
if ($entityType == ENTITY_INVOICE) {
|
||||||
{
|
$table->addColumn('balance', function ($model) { return Utils::formatMoney($model->balance, $model->currency_id); });
|
||||||
$table->addColumn('balance', function($model) { return Utils::formatMoney($model->balance, $model->currency_id); });
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return $table->addColumn('due_date', function($model) { return Utils::fromSqlDate($model->due_date); })
|
return $table->addColumn('due_date', function ($model) { return Utils::fromSqlDate($model->due_date); })
|
||||||
->addColumn('invoice_status_name', function($model) { return $model->invoice_status_name; })
|
->addColumn('invoice_status_name', function ($model) { return $model->invoice_status_name; })
|
||||||
->addColumn('dropdown', function($model) use ($entityType)
|
->addColumn('dropdown', function ($model) use ($entityType) {
|
||||||
{
|
|
||||||
if ($model->is_deleted)
|
|
||||||
{
|
|
||||||
return '<div style="height:38px"/>';
|
|
||||||
}
|
|
||||||
|
|
||||||
$str = '<div class="btn-group tr-action" style="visibility:hidden;">
|
if ($model->is_deleted) {
|
||||||
<button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">
|
return '<div style="height:38px"/>';
|
||||||
'.trans('texts.select').' <span class="caret"></span>
|
}
|
||||||
</button>
|
|
||||||
<ul class="dropdown-menu" role="menu">';
|
|
||||||
|
|
||||||
if (!$model->deleted_at || $model->deleted_at == '0000-00-00')
|
$str = '<div class="btn-group tr-action" style="visibility:hidden;">
|
||||||
{
|
<button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown">
|
||||||
$str .= '<li><a href="' . \URL::to("{$entityType}s/".$model->public_id.'/edit') . '">'.trans("texts.edit_{$entityType}").'</a></li>
|
'.trans('texts.select').' <span class="caret"></span>
|
||||||
<li><a href="' . \URL::to("{$entityType}s/".$model->public_id.'/clone') . '">'.trans("texts.clone_{$entityType}").'</a></li>
|
</button>
|
||||||
|
<ul class="dropdown-menu" role="menu">';
|
||||||
|
|
||||||
|
if (!$model->deleted_at || $model->deleted_at == '0000-00-00') {
|
||||||
|
$str .= '<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>
|
||||||
<li class="divider"></li>';
|
<li class="divider"></li>';
|
||||||
|
|
||||||
if ($model->invoice_status_id < INVOICE_STATUS_SENT)
|
if ($model->invoice_status_id < INVOICE_STATUS_SENT) {
|
||||||
{
|
$str .= '<li><a href="javascript:markEntity('.$model->public_id.', '.INVOICE_STATUS_SENT.')">'.trans("texts.mark_sent").'</a></li>';
|
||||||
$str .= '<li><a href="javascript:markEntity(' . $model->public_id . ', ' . INVOICE_STATUS_SENT . ')">'.trans("texts.mark_sent").'</a></li>';
|
}
|
||||||
|
|
||||||
|
if ($entityType == ENTITY_INVOICE) {
|
||||||
|
if ($model->invoice_status_id < INVOICE_STATUS_PAID) {
|
||||||
|
$str .= '<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>';
|
||||||
|
}
|
||||||
|
} elseif ($entityType == ENTITY_QUOTE) {
|
||||||
|
if ($model->quote_invoice_id) {
|
||||||
|
$str .= '<li><a href="'.\URL::to("invoices/{$model->quote_invoice_id}/edit").'">'.trans("texts.view_invoice").'</a></li>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$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>';
|
||||||
|
} else {
|
||||||
|
$str .= '<li><a href="javascript:restoreEntity('.$model->public_id.')">'.trans("texts.restore_{$entityType}").'</a></li>
|
||||||
|
<li><a href="javascript:deleteEntity('.$model->public_id.')">'.trans("texts.delete_{$entityType}").'</a></li>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($entityType == ENTITY_INVOICE)
|
return $str.'</ul>
|
||||||
{
|
</div>';
|
||||||
if ($model->invoice_status_id < INVOICE_STATUS_PAID)
|
|
||||||
{
|
|
||||||
$str .= '<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 if ($entityType == ENTITY_QUOTE)
|
|
||||||
{
|
|
||||||
if ($model->quote_invoice_id)
|
|
||||||
{
|
|
||||||
$str .= '<li><a href="' . \URL::to("invoices/{$model->quote_invoice_id}/edit") . '">' . trans("texts.view_invoice") . '</a></li>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$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>';
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$str .= '<li><a href="javascript:restoreEntity(' . $model->public_id. ')">'.trans("texts.restore_{$entityType}").'</a></li>
|
|
||||||
<li><a href="javascript:deleteEntity(' . $model->public_id . ')">'.trans("texts.delete_{$entityType}").'</a></li>';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $str . '</ul>
|
|
||||||
</div>';
|
|
||||||
})
|
})
|
||||||
->make();
|
->make();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getErrors($input)
|
public function getErrors($input)
|
||||||
{
|
|
||||||
$contact = (array) $input->client->contacts[0];
|
|
||||||
$rules = ['email' => 'required|email'];
|
|
||||||
$validator = \Validator::make($contact, $rules);
|
|
||||||
|
|
||||||
if ($validator->fails())
|
|
||||||
{
|
|
||||||
return $validator;
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoice = (array) $input;
|
|
||||||
$invoiceId = isset($invoice['public_id']) && $invoice['public_id'] ? Invoice::getPrivateId($invoice['public_id']) : null;
|
|
||||||
$rules = [
|
|
||||||
'invoice_number' => 'required|unique:invoices,invoice_number,' . $invoiceId . ',id,account_id,' . \Auth::user()->account_id,
|
|
||||||
'discount' => 'positive'
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($invoice['is_recurring'] && $invoice['start_date'] && $invoice['end_date'])
|
|
||||||
{
|
|
||||||
$rules['end_date'] = 'after:' . $invoice['start_date'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$validator = \Validator::make($invoice, $rules);
|
|
||||||
|
|
||||||
if ($validator->fails())
|
|
||||||
{
|
|
||||||
return $validator;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function save($publicId, $data, $entityType)
|
|
||||||
{
|
|
||||||
if ($publicId)
|
|
||||||
{
|
|
||||||
$invoice = Invoice::scope($publicId)->firstOrFail();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$invoice = Invoice::createNew();
|
|
||||||
|
|
||||||
if ($entityType == ENTITY_QUOTE)
|
|
||||||
{
|
|
||||||
$invoice->is_quote = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoice->client_id = $data['client_id'];
|
|
||||||
$invoice->discount = round(Utils::parseFloat($data['discount']), 2);
|
|
||||||
$invoice->is_amount_discount = $data['is_amount_discount'] ? true : false;
|
|
||||||
$invoice->invoice_number = trim($data['invoice_number']);
|
|
||||||
$invoice->is_recurring = $data['is_recurring'] && !Utils::isDemo() ? true : false;
|
|
||||||
$invoice->invoice_date = Utils::toSqlDate($data['invoice_date']);
|
|
||||||
|
|
||||||
if ($invoice->is_recurring)
|
|
||||||
{
|
{
|
||||||
$invoice->frequency_id = $data['frequency_id'] ? $data['frequency_id'] : 0;
|
$contact = (array) $input->client->contacts[0];
|
||||||
$invoice->start_date = Utils::toSqlDate($data['start_date']);
|
$rules = ['email' => 'required|email'];
|
||||||
$invoice->end_date = Utils::toSqlDate($data['end_date']);
|
$validator = \Validator::make($contact, $rules);
|
||||||
$invoice->due_date = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$invoice->due_date = Utils::toSqlDate($data['due_date']);
|
|
||||||
$invoice->frequency_id = 0;
|
|
||||||
$invoice->start_date = null;
|
|
||||||
$invoice->end_date = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoice->terms = trim($data['terms']);
|
if ($validator->fails()) {
|
||||||
$invoice->public_notes = trim($data['public_notes']);
|
return $validator;
|
||||||
$invoice->po_number = trim($data['po_number']);
|
|
||||||
$invoice->invoice_design_id = $data['invoice_design_id'];
|
|
||||||
|
|
||||||
if (isset($data['tax_name']) && isset($data['tax_rate']) && Utils::parseFloat($data['tax_rate']) > 0)
|
|
||||||
{
|
|
||||||
$invoice->tax_rate = Utils::parseFloat($data['tax_rate']);
|
|
||||||
$invoice->tax_name = trim($data['tax_name']);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$invoice->tax_rate = 0;
|
|
||||||
$invoice->tax_name = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
$total = 0;
|
|
||||||
|
|
||||||
foreach ($data['invoice_items'] as $item)
|
|
||||||
{
|
|
||||||
if (!$item->cost && !$item->product_key && !$item->notes)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoiceItemCost = Utils::parseFloat($item->cost);
|
|
||||||
$invoiceItemQty = Utils::parseFloat($item->qty);
|
|
||||||
$invoiceItemTaxRate = 0;
|
|
||||||
|
|
||||||
if (isset($item->tax_rate) && Utils::parseFloat($item->tax_rate) > 0)
|
|
||||||
{
|
|
||||||
$invoiceItemTaxRate = Utils::parseFloat($item->tax_rate);
|
|
||||||
}
|
|
||||||
|
|
||||||
$lineTotal = $invoiceItemCost * $invoiceItemQty;
|
|
||||||
|
|
||||||
$total += round($lineTotal + ($lineTotal * $invoiceItemTaxRate / 100), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($invoice->discount > 0)
|
|
||||||
{
|
|
||||||
if ($invoice->is_amount_discount)
|
|
||||||
{
|
|
||||||
$total -= $invoice->discount;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$total *= (100 - $invoice->discount) / 100;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoice->custom_value1 = round($data['custom_value1'], 2);
|
|
||||||
$invoice->custom_value2 = round($data['custom_value2'], 2);
|
|
||||||
$invoice->custom_taxes1 = $data['custom_taxes1'] ? true : false;
|
|
||||||
$invoice->custom_taxes2 = $data['custom_taxes2'] ? true : false;
|
|
||||||
|
|
||||||
// custom fields charged taxes
|
|
||||||
if ($invoice->custom_value1 && $invoice->custom_taxes1) {
|
|
||||||
$total += $invoice->custom_value1;
|
|
||||||
}
|
|
||||||
if ($invoice->custom_value2 && $invoice->custom_taxes2) {
|
|
||||||
$total += $invoice->custom_value2;
|
|
||||||
}
|
|
||||||
|
|
||||||
$total += $total * $invoice->tax_rate / 100;
|
|
||||||
$total = round($total, 2);
|
|
||||||
|
|
||||||
// custom fields not charged taxes
|
|
||||||
if ($invoice->custom_value1 && !$invoice->custom_taxes1) {
|
|
||||||
$total += $invoice->custom_value1;
|
|
||||||
}
|
|
||||||
if ($invoice->custom_value2 && !$invoice->custom_taxes2) {
|
|
||||||
$total += $invoice->custom_value2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($publicId)
|
|
||||||
{
|
|
||||||
$invoice->balance = $total - ($invoice->amount - $invoice->balance);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$invoice->balance = $total;
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoice->amount = $total;
|
|
||||||
$invoice->save();
|
|
||||||
|
|
||||||
$invoice->invoice_items()->forceDelete();
|
|
||||||
|
|
||||||
foreach ($data['invoice_items'] as $item)
|
|
||||||
{
|
|
||||||
if (!$item->cost && !$item->product_key && !$item->notes)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($item->product_key)
|
|
||||||
{
|
|
||||||
$product = Product::findProductByKey(trim($item->product_key));
|
|
||||||
|
|
||||||
if (!$product)
|
|
||||||
{
|
|
||||||
$product = Product::createNew();
|
|
||||||
$product->product_key = trim($item->product_key);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (\Auth::user()->account->update_products)
|
$invoice = (array) $input;
|
||||||
{
|
$invoiceId = isset($invoice['public_id']) && $invoice['public_id'] ? Invoice::getPrivateId($invoice['public_id']) : null;
|
||||||
$product->notes = $item->notes;
|
$rules = [
|
||||||
$product->cost = $item->cost;
|
'invoice_number' => 'required|unique:invoices,invoice_number,'.$invoiceId.',id,account_id,'.\Auth::user()->account_id,
|
||||||
//$product->qty = $item->qty;
|
'discount' => 'positive',
|
||||||
|
];
|
||||||
|
|
||||||
|
if ($invoice['is_recurring'] && $invoice['start_date'] && $invoice['end_date']) {
|
||||||
|
$rules['end_date'] = 'after:'.$invoice['start_date'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$product->save();
|
$validator = \Validator::make($invoice, $rules);
|
||||||
}
|
|
||||||
|
|
||||||
$invoiceItem = InvoiceItem::createNew();
|
if ($validator->fails()) {
|
||||||
$invoiceItem->product_id = isset($product) ? $product->id : null;
|
return $validator;
|
||||||
$invoiceItem->product_key = trim($invoice->is_recurring ? $item->product_key : Utils::processVariables($item->product_key));
|
}
|
||||||
$invoiceItem->notes = trim($invoice->is_recurring ? $item->notes : Utils::processVariables($item->notes));
|
|
||||||
$invoiceItem->cost = Utils::parseFloat($item->cost);
|
|
||||||
$invoiceItem->qty = Utils::parseFloat($item->qty);
|
|
||||||
$invoiceItem->tax_rate = 0;
|
|
||||||
|
|
||||||
if (isset($item->tax_rate) && Utils::parseFloat($item->tax_rate) > 0)
|
return false;
|
||||||
{
|
|
||||||
$invoiceItem->tax_rate = Utils::parseFloat($item->tax_rate);
|
|
||||||
$invoiceItem->tax_name = trim($item->tax_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoice->invoice_items()->save($invoiceItem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($data['set_default_terms'])
|
public function save($publicId, $data, $entityType)
|
||||||
{
|
|
||||||
$account = \Auth::user()->account;
|
|
||||||
$account->invoice_terms = $invoice->terms;
|
|
||||||
$account->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $invoice;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function cloneInvoice($invoice, $quotePublicId = null)
|
|
||||||
{
|
|
||||||
$invoice->load('invitations', 'invoice_items');
|
|
||||||
$account = $invoice->account;
|
|
||||||
|
|
||||||
$clone = Invoice::createNew($invoice);
|
|
||||||
$clone->balance = $invoice->amount;
|
|
||||||
|
|
||||||
// if the invoice prefix is diff than quote prefix, use the same number for the invoice
|
|
||||||
if (($account->invoice_number_prefix || $account->quote_number_prefix) && $account->invoice_number_prefix != $account->quote_number_prefix)
|
|
||||||
{
|
{
|
||||||
$invoiceNumber = $invoice->invoice_number;
|
if ($publicId) {
|
||||||
if (strpos($invoiceNumber, $account->quote_number_prefix) === 0)
|
$invoice = Invoice::scope($publicId)->firstOrFail();
|
||||||
{
|
} else {
|
||||||
$invoiceNumber = substr($invoiceNumber, strlen($account->quote_number_prefix));
|
$invoice = Invoice::createNew();
|
||||||
}
|
|
||||||
$clone->invoice_number = $account->invoice_number_prefix . $invoiceNumber;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$clone->invoice_number = $account->getNextInvoiceNumber();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ([
|
if ($entityType == ENTITY_QUOTE) {
|
||||||
'client_id',
|
$invoice->is_quote = true;
|
||||||
'discount',
|
}
|
||||||
'is_amount_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',
|
|
||||||
'custom_value1',
|
|
||||||
'custom_value2',
|
|
||||||
'custom_taxes1',
|
|
||||||
'custom_taxes2'] as $field)
|
|
||||||
{
|
|
||||||
$clone->$field = $invoice->$field;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($quotePublicId)
|
$invoice->client_id = $data['client_id'];
|
||||||
{
|
$invoice->discount = round(Utils::parseFloat($data['discount']), 2);
|
||||||
$clone->is_quote = false;
|
$invoice->is_amount_discount = $data['is_amount_discount'] ? true : false;
|
||||||
$clone->quote_id = $quotePublicId;
|
$invoice->invoice_number = trim($data['invoice_number']);
|
||||||
}
|
$invoice->is_recurring = $data['is_recurring'] && !Utils::isDemo() ? true : false;
|
||||||
|
$invoice->invoice_date = Utils::toSqlDate($data['invoice_date']);
|
||||||
|
|
||||||
$clone->save();
|
if ($invoice->is_recurring) {
|
||||||
|
$invoice->frequency_id = $data['frequency_id'] ? $data['frequency_id'] : 0;
|
||||||
|
$invoice->start_date = Utils::toSqlDate($data['start_date']);
|
||||||
|
$invoice->end_date = Utils::toSqlDate($data['end_date']);
|
||||||
|
$invoice->due_date = null;
|
||||||
|
} else {
|
||||||
|
$invoice->due_date = Utils::toSqlDate($data['due_date']);
|
||||||
|
$invoice->frequency_id = 0;
|
||||||
|
$invoice->start_date = null;
|
||||||
|
$invoice->end_date = null;
|
||||||
|
}
|
||||||
|
|
||||||
if ($quotePublicId)
|
$invoice->terms = trim($data['terms']);
|
||||||
{
|
$invoice->public_notes = trim($data['public_notes']);
|
||||||
$invoice->quote_invoice_id = $clone->public_id;
|
$invoice->po_number = trim($data['po_number']);
|
||||||
$invoice->save();
|
$invoice->invoice_design_id = $data['invoice_design_id'];
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($invoice->invoice_items as $item)
|
if (isset($data['tax_name']) && isset($data['tax_rate']) && Utils::parseFloat($data['tax_rate']) > 0) {
|
||||||
{
|
$invoice->tax_rate = Utils::parseFloat($data['tax_rate']);
|
||||||
$cloneItem = InvoiceItem::createNew($invoice);
|
$invoice->tax_name = trim($data['tax_name']);
|
||||||
|
} else {
|
||||||
|
$invoice->tax_rate = 0;
|
||||||
|
$invoice->tax_name = '';
|
||||||
|
}
|
||||||
|
|
||||||
foreach ([
|
$total = 0;
|
||||||
'product_id',
|
|
||||||
'product_key',
|
|
||||||
'notes',
|
|
||||||
'cost',
|
|
||||||
'qty',
|
|
||||||
'tax_name',
|
|
||||||
'tax_rate'] as $field)
|
|
||||||
{
|
|
||||||
$cloneItem->$field = $item->$field;
|
|
||||||
}
|
|
||||||
|
|
||||||
$clone->invoice_items()->save($cloneItem);
|
foreach ($data['invoice_items'] as $item) {
|
||||||
}
|
if (!$item->cost && !$item->product_key && !$item->notes) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($invoice->invitations as $invitation)
|
$invoiceItemCost = Utils::parseFloat($item->cost);
|
||||||
{
|
$invoiceItemQty = Utils::parseFloat($item->qty);
|
||||||
$cloneInvitation = Invitation::createNew($invoice);
|
$invoiceItemTaxRate = 0;
|
||||||
$cloneInvitation->contact_id = $invitation->contact_id;
|
|
||||||
$cloneInvitation->invitation_key = str_random(RANDOM_KEY_LENGTH);
|
|
||||||
$clone->invitations()->save($cloneInvitation);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $clone;
|
if (isset($item->tax_rate) && Utils::parseFloat($item->tax_rate) > 0) {
|
||||||
}
|
$invoiceItemTaxRate = Utils::parseFloat($item->tax_rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
$lineTotal = $invoiceItemCost * $invoiceItemQty;
|
||||||
|
|
||||||
public function bulk($ids, $action, $statusId = false)
|
$total += round($lineTotal + ($lineTotal * $invoiceItemTaxRate / 100), 2);
|
||||||
{
|
}
|
||||||
if (!$ids)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoices = Invoice::withTrashed()->scope($ids)->get();
|
if ($invoice->discount > 0) {
|
||||||
|
if ($invoice->is_amount_discount) {
|
||||||
|
$total -= $invoice->discount;
|
||||||
|
} else {
|
||||||
|
$total *= (100 - $invoice->discount) / 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($invoices as $invoice)
|
$invoice->custom_value1 = round($data['custom_value1'], 2);
|
||||||
{
|
$invoice->custom_value2 = round($data['custom_value2'], 2);
|
||||||
if ($action == 'mark')
|
$invoice->custom_taxes1 = $data['custom_taxes1'] ? true : false;
|
||||||
{
|
$invoice->custom_taxes2 = $data['custom_taxes2'] ? true : false;
|
||||||
$invoice->invoice_status_id = $statusId;
|
|
||||||
|
// custom fields charged taxes
|
||||||
|
if ($invoice->custom_value1 && $invoice->custom_taxes1) {
|
||||||
|
$total += $invoice->custom_value1;
|
||||||
|
}
|
||||||
|
if ($invoice->custom_value2 && $invoice->custom_taxes2) {
|
||||||
|
$total += $invoice->custom_value2;
|
||||||
|
}
|
||||||
|
|
||||||
|
$total += $total * $invoice->tax_rate / 100;
|
||||||
|
$total = round($total, 2);
|
||||||
|
|
||||||
|
// custom fields not charged taxes
|
||||||
|
if ($invoice->custom_value1 && !$invoice->custom_taxes1) {
|
||||||
|
$total += $invoice->custom_value1;
|
||||||
|
}
|
||||||
|
if ($invoice->custom_value2 && !$invoice->custom_taxes2) {
|
||||||
|
$total += $invoice->custom_value2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($publicId) {
|
||||||
|
$invoice->balance = $total - ($invoice->amount - $invoice->balance);
|
||||||
|
} else {
|
||||||
|
$invoice->balance = $total;
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoice->amount = $total;
|
||||||
$invoice->save();
|
$invoice->save();
|
||||||
}
|
|
||||||
else if ($action == 'restore')
|
|
||||||
{
|
|
||||||
$invoice->restore();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ($action == 'delete')
|
|
||||||
{
|
|
||||||
$invoice->is_deleted = true;
|
|
||||||
$invoice->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoice->delete();
|
$invoice->invoice_items()->forceDelete();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count($invoices);
|
foreach ($data['invoice_items'] as $item) {
|
||||||
}
|
if (!$item->cost && !$item->product_key && !$item->notes) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($item->product_key) {
|
||||||
|
$product = Product::findProductByKey(trim($item->product_key));
|
||||||
|
|
||||||
|
if (!$product) {
|
||||||
|
$product = Product::createNew();
|
||||||
|
$product->product_key = trim($item->product_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\Auth::user()->account->update_products) {
|
||||||
|
$product->notes = $item->notes;
|
||||||
|
$product->cost = $item->cost;
|
||||||
|
//$product->qty = $item->qty;
|
||||||
|
}
|
||||||
|
|
||||||
|
$product->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoiceItem = InvoiceItem::createNew();
|
||||||
|
$invoiceItem->product_id = isset($product) ? $product->id : null;
|
||||||
|
$invoiceItem->product_key = trim($invoice->is_recurring ? $item->product_key : Utils::processVariables($item->product_key));
|
||||||
|
$invoiceItem->notes = trim($invoice->is_recurring ? $item->notes : Utils::processVariables($item->notes));
|
||||||
|
$invoiceItem->cost = Utils::parseFloat($item->cost);
|
||||||
|
$invoiceItem->qty = Utils::parseFloat($item->qty);
|
||||||
|
$invoiceItem->tax_rate = 0;
|
||||||
|
|
||||||
|
if (isset($item->tax_rate) && Utils::parseFloat($item->tax_rate) > 0) {
|
||||||
|
$invoiceItem->tax_rate = Utils::parseFloat($item->tax_rate);
|
||||||
|
$invoiceItem->tax_name = trim($item->tax_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoice->invoice_items()->save($invoiceItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($data['set_default_terms']) {
|
||||||
|
$account = \Auth::user()->account;
|
||||||
|
$account->invoice_terms = $invoice->terms;
|
||||||
|
$account->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $invoice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cloneInvoice($invoice, $quotePublicId = null)
|
||||||
|
{
|
||||||
|
$invoice->load('invitations', 'invoice_items');
|
||||||
|
$account = $invoice->account;
|
||||||
|
|
||||||
|
$clone = Invoice::createNew($invoice);
|
||||||
|
$clone->balance = $invoice->amount;
|
||||||
|
|
||||||
|
// if the invoice prefix is diff than quote prefix, use the same number for the invoice
|
||||||
|
if (($account->invoice_number_prefix || $account->quote_number_prefix) && $account->invoice_number_prefix != $account->quote_number_prefix) {
|
||||||
|
$invoiceNumber = $invoice->invoice_number;
|
||||||
|
if (strpos($invoiceNumber, $account->quote_number_prefix) === 0) {
|
||||||
|
$invoiceNumber = substr($invoiceNumber, strlen($account->quote_number_prefix));
|
||||||
|
}
|
||||||
|
$clone->invoice_number = $account->invoice_number_prefix.$invoiceNumber;
|
||||||
|
} else {
|
||||||
|
$clone->invoice_number = $account->getNextInvoiceNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ([
|
||||||
|
'client_id',
|
||||||
|
'discount',
|
||||||
|
'is_amount_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',
|
||||||
|
'custom_value1',
|
||||||
|
'custom_value2',
|
||||||
|
'custom_taxes1',
|
||||||
|
'custom_taxes2', ] as $field) {
|
||||||
|
$clone->$field = $invoice->$field;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($quotePublicId) {
|
||||||
|
$clone->is_quote = false;
|
||||||
|
$clone->quote_id = $quotePublicId;
|
||||||
|
}
|
||||||
|
|
||||||
|
$clone->save();
|
||||||
|
|
||||||
|
if ($quotePublicId) {
|
||||||
|
$invoice->quote_invoice_id = $clone->public_id;
|
||||||
|
$invoice->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($invoice->invoice_items as $item) {
|
||||||
|
$cloneItem = InvoiceItem::createNew($invoice);
|
||||||
|
|
||||||
|
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($invoice);
|
||||||
|
$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, $statusId = false)
|
||||||
|
{
|
||||||
|
if (!$ids) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoices = Invoice::withTrashed()->scope($ids)->get();
|
||||||
|
|
||||||
|
foreach ($invoices as $invoice) {
|
||||||
|
if ($action == 'mark') {
|
||||||
|
$invoice->invoice_status_id = $statusId;
|
||||||
|
$invoice->save();
|
||||||
|
} elseif ($action == 'restore') {
|
||||||
|
$invoice->restore();
|
||||||
|
} else {
|
||||||
|
if ($action == 'delete') {
|
||||||
|
$invoice->is_deleted = true;
|
||||||
|
$invoice->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoice->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count($invoices);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
237
app/routes.php
237
app/routes.php
@ -74,73 +74,76 @@ Route::post('user/reset', 'UserController@do_reset_password');
|
|||||||
Route::get('logout', 'UserController@logout');
|
Route::get('logout', 'UserController@logout');
|
||||||
|
|
||||||
if (Utils::isNinja()) {
|
if (Utils::isNinja()) {
|
||||||
Route::post('/signup/register', 'AccountController@doRegister');
|
Route::post('/signup/register', 'AccountController@doRegister');
|
||||||
Route::get('/news_feed/{user_type}/{version}/', 'HomeController@newsFeed');
|
Route::get('/news_feed/{user_type}/{version}/', 'HomeController@newsFeed');
|
||||||
Route::get('/demo', 'AccountController@demo');
|
Route::get('/demo', 'AccountController@demo');
|
||||||
}
|
}
|
||||||
|
|
||||||
Route::group(array('before' => 'auth'), function()
|
Route::group(array('before' => 'auth'), function() {
|
||||||
{
|
Route::get('dashboard', 'DashboardController@index');
|
||||||
Route::get('dashboard', 'DashboardController@index');
|
Route::get('view_archive/{entity_type}/{visible}', 'AccountController@setTrashVisible');
|
||||||
Route::get('view_archive/{entity_type}/{visible}', 'AccountController@setTrashVisible');
|
Route::get('hide_message', 'HomeController@hideMessage');
|
||||||
Route::get('hide_message', 'HomeController@hideMessage');
|
Route::get('force_inline_pdf', 'UserController@forcePDFJS');
|
||||||
Route::get('force_inline_pdf', 'UserController@forcePDFJS');
|
|
||||||
|
|
||||||
Route::get('api/users', array('as'=>'api.users', 'uses'=>'UserController@getDatatable'));
|
Route::get('api/users', array('as'=>'api.users', 'uses'=>'UserController@getDatatable'));
|
||||||
Route::resource('users', 'UserController');
|
Route::resource('users', 'UserController');
|
||||||
Route::post('users/delete', 'UserController@delete');
|
Route::post('users/delete', 'UserController@delete');
|
||||||
|
|
||||||
Route::get('api/products', array('as'=>'api.products', 'uses'=>'ProductController@getDatatable'));
|
Route::get('api/products', array('as'=>'api.products', 'uses'=>'ProductController@getDatatable'));
|
||||||
Route::resource('products', 'ProductController');
|
Route::resource('products', 'ProductController');
|
||||||
Route::get('products/{product_id}/archive', 'ProductController@archive');
|
Route::get('products/{product_id}/archive', 'ProductController@archive');
|
||||||
|
|
||||||
Route::get('company/advanced_settings/data_visualizations', 'ReportController@d3');
|
Route::get('company/advanced_settings/data_visualizations', 'ReportController@d3');
|
||||||
Route::get('company/advanced_settings/chart_builder', 'ReportController@report');
|
Route::get('company/advanced_settings/chart_builder', 'ReportController@report');
|
||||||
Route::post('company/advanced_settings/chart_builder', 'ReportController@report');
|
Route::post('company/advanced_settings/chart_builder', 'ReportController@report');
|
||||||
|
|
||||||
Route::post('company/cancel_account', 'AccountController@cancelAccount');
|
Route::post('company/cancel_account', 'AccountController@cancelAccount');
|
||||||
Route::get('account/getSearchData', array('as' => 'getSearchData', 'uses' => 'AccountController@getSearchData'));
|
Route::get('account/getSearchData', array('as' => 'getSearchData', 'uses' => 'AccountController@getSearchData'));
|
||||||
Route::get('company/{section?}/{sub_section?}', 'AccountController@showSection');
|
Route::get('company/{section?}/{sub_section?}', 'AccountController@showSection');
|
||||||
Route::post('company/{section?}/{sub_section?}', 'AccountController@doSection');
|
Route::post('company/{section?}/{sub_section?}', 'AccountController@doSection');
|
||||||
Route::post('user/setTheme', 'UserController@setTheme');
|
Route::post('user/setTheme', 'UserController@setTheme');
|
||||||
Route::post('remove_logo', 'AccountController@removeLogo');
|
Route::post('remove_logo', 'AccountController@removeLogo');
|
||||||
Route::post('account/go_pro', 'AccountController@enableProPlan');
|
Route::post('account/go_pro', 'AccountController@enableProPlan');
|
||||||
|
|
||||||
Route::resource('clients', 'ClientController');
|
Route::resource('clients', 'ClientController');
|
||||||
Route::get('api/clients', array('as'=>'api.clients', 'uses'=>'ClientController@getDatatable'));
|
Route::get('api/clients', array('as'=>'api.clients', 'uses'=>'ClientController@getDatatable'));
|
||||||
Route::get('api/activities/{client_id?}', array('as'=>'api.activities', 'uses'=>'ActivityController@getDatatable'));
|
Route::get('api/activities/{client_id?}', array('as'=>'api.activities', 'uses'=>'ActivityController@getDatatable'));
|
||||||
Route::post('clients/bulk', 'ClientController@bulk');
|
Route::post('clients/bulk', 'ClientController@bulk');
|
||||||
|
|
||||||
Route::get('recurring_invoices', 'InvoiceController@recurringIndex');
|
Route::get('recurring_invoices', 'InvoiceController@recurringIndex');
|
||||||
Route::get('api/recurring_invoices/{client_id?}', array('as'=>'api.recurring_invoices', 'uses'=>'InvoiceController@getRecurringDatatable'));
|
Route::get('api/recurring_invoices/{client_id?}', array('as'=>'api.recurring_invoices', 'uses'=>'InvoiceController@getRecurringDatatable'));
|
||||||
|
|
||||||
Route::resource('invoices', 'InvoiceController');
|
Route::resource('invoices', 'InvoiceController');
|
||||||
Route::get('api/invoices/{client_id?}', array('as'=>'api.invoices', 'uses'=>'InvoiceController@getDatatable'));
|
Route::get('api/invoices/{client_id?}', array('as'=>'api.invoices', 'uses'=>'InvoiceController@getDatatable'));
|
||||||
Route::get('invoices/create/{client_id?}', 'InvoiceController@create');
|
Route::get('invoices/create/{client_id?}', 'InvoiceController@create');
|
||||||
Route::get('invoices/{public_id}/clone', 'InvoiceController@cloneInvoice');
|
Route::get('invoices/{public_id}/clone', 'InvoiceController@cloneInvoice');
|
||||||
Route::post('invoices/bulk', 'InvoiceController@bulk');
|
Route::post('invoices/bulk', 'InvoiceController@bulk');
|
||||||
|
|
||||||
Route::get('quotes/create/{client_id?}', 'QuoteController@create');
|
Route::get('quotes/create/{client_id?}', 'QuoteController@create');
|
||||||
Route::get('quotes/{public_id}/clone', 'InvoiceController@cloneInvoice');
|
Route::get('quotes/{public_id}/clone', 'InvoiceController@cloneInvoice');
|
||||||
Route::get('quotes/{public_id}/edit', 'InvoiceController@edit');
|
Route::get('quotes/{public_id}/edit', 'InvoiceController@edit');
|
||||||
Route::put('quotes/{public_id}', 'InvoiceController@update');
|
Route::put('quotes/{public_id}', 'InvoiceController@update');
|
||||||
Route::get('quotes/{public_id}', 'InvoiceController@edit');
|
Route::get('quotes/{public_id}', 'InvoiceController@edit');
|
||||||
Route::post('quotes', 'InvoiceController@store');
|
Route::post('quotes', 'InvoiceController@store');
|
||||||
Route::get('quotes', 'QuoteController@index');
|
Route::get('quotes', 'QuoteController@index');
|
||||||
Route::get('api/quotes/{client_id?}', array('as'=>'api.quotes', 'uses'=>'QuoteController@getDatatable'));
|
Route::get('api/quotes/{client_id?}', array('as'=>'api.quotes', 'uses'=>'QuoteController@getDatatable'));
|
||||||
Route::post('quotes/bulk', 'QuoteController@bulk');
|
Route::post('quotes/bulk', 'QuoteController@bulk');
|
||||||
|
|
||||||
Route::get('payments/{id}/edit', function() { return View::make('header'); });
|
Route::get('payments/{id}/edit', function() {
|
||||||
Route::resource('payments', 'PaymentController');
|
return View::make('header');
|
||||||
Route::get('payments/create/{client_id?}/{invoice_id?}', 'PaymentController@create');
|
});
|
||||||
Route::get('api/payments/{client_id?}', array('as'=>'api.payments', 'uses'=>'PaymentController@getDatatable'));
|
Route::resource('payments', 'PaymentController');
|
||||||
Route::post('payments/bulk', 'PaymentController@bulk');
|
Route::get('payments/create/{client_id?}/{invoice_id?}', 'PaymentController@create');
|
||||||
|
Route::get('api/payments/{client_id?}', array('as'=>'api.payments', 'uses'=>'PaymentController@getDatatable'));
|
||||||
|
Route::post('payments/bulk', 'PaymentController@bulk');
|
||||||
|
|
||||||
Route::get('credits/{id}/edit', function() { return View::make('header'); });
|
Route::get('credits/{id}/edit', function() {
|
||||||
Route::resource('credits', 'CreditController');
|
return View::make('header');
|
||||||
Route::get('credits/create/{client_id?}/{invoice_id?}', 'CreditController@create');
|
});
|
||||||
Route::get('api/credits/{client_id?}', array('as'=>'api.credits', 'uses'=>'CreditController@getDatatable'));
|
Route::resource('credits', 'CreditController');
|
||||||
Route::post('credits/bulk', 'CreditController@bulk');
|
Route::get('credits/create/{client_id?}/{invoice_id?}', 'CreditController@create');
|
||||||
|
Route::get('api/credits/{client_id?}', array('as'=>'api.credits', 'uses'=>'CreditController@getDatatable'));
|
||||||
|
Route::post('credits/bulk', 'CreditController@bulk');
|
||||||
|
|
||||||
//Route::resource('timesheets', 'TimesheetController');
|
//Route::resource('timesheets', 'TimesheetController');
|
||||||
});
|
});
|
||||||
@ -148,12 +151,12 @@ Route::group(array('before' => 'auth'), function()
|
|||||||
// Route group for API
|
// Route group for API
|
||||||
Route::group(array('prefix' => 'api/v1', 'before' => 'auth.basic'), function()
|
Route::group(array('prefix' => 'api/v1', 'before' => 'auth.basic'), function()
|
||||||
{
|
{
|
||||||
Route::resource('ping', 'ClientApiController@ping');
|
Route::resource('ping', 'ClientApiController@ping');
|
||||||
Route::resource('clients', 'ClientApiController');
|
Route::resource('clients', 'ClientApiController');
|
||||||
Route::resource('invoices', 'InvoiceApiController');
|
Route::resource('invoices', 'InvoiceApiController');
|
||||||
Route::resource('quotes', 'QuoteApiController');
|
Route::resource('quotes', 'QuoteApiController');
|
||||||
Route::resource('payments', 'PaymentApiController');
|
Route::resource('payments', 'PaymentApiController');
|
||||||
Route::post('api/hooks', 'IntegrationController@subscribe');
|
Route::post('api/hooks', 'IntegrationController@subscribe');
|
||||||
});
|
});
|
||||||
|
|
||||||
define('CONTACT_EMAIL', Config::get('mail.from.address'));
|
define('CONTACT_EMAIL', Config::get('mail.from.address'));
|
||||||
@ -312,12 +315,12 @@ HTML::macro('tab_link', function($url, $text, $active = false) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
HTML::macro('menu_link', function($type) {
|
HTML::macro('menu_link', function($type) {
|
||||||
$types = $type.'s';
|
$types = $type.'s';
|
||||||
$Type = ucfirst($type);
|
$Type = ucfirst($type);
|
||||||
$Types = ucfirst($types);
|
$Types = ucfirst($types);
|
||||||
$class = ( Request::is($types) || Request::is('*'.$type.'*')) && !Request::is('*advanced_settings*') ? ' active' : '';
|
$class = ( Request::is($types) || Request::is('*'.$type.'*')) && !Request::is('*advanced_settings*') ? ' active' : '';
|
||||||
|
|
||||||
return '<li class="dropdown '.$class.'">
|
return '<li class="dropdown '.$class.'">
|
||||||
<a href="'.URL::to($types).'" class="dropdown-toggle">'.trans("texts.$types").'</a>
|
<a href="'.URL::to($types).'" class="dropdown-toggle">'.trans("texts.$types").'</a>
|
||||||
<ul class="dropdown-menu" id="menu1">
|
<ul class="dropdown-menu" id="menu1">
|
||||||
<li><a href="'.URL::to($types.'/create').'">'.trans("texts.new_$type").'</a></li>
|
<li><a href="'.URL::to($types.'/create').'">'.trans("texts.new_$type").'</a></li>
|
||||||
@ -326,87 +329,79 @@ HTML::macro('menu_link', function($type) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
HTML::macro('image_data', function($imagePath) {
|
HTML::macro('image_data', function($imagePath) {
|
||||||
return 'data:image/jpeg;base64,' . base64_encode(file_get_contents(public_path().'/'.$imagePath));
|
return 'data:image/jpeg;base64,' . base64_encode(file_get_contents(public_path().'/'.$imagePath));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
HTML::macro('breadcrumbs', function() {
|
HTML::macro('breadcrumbs', function() {
|
||||||
$str = '<ol class="breadcrumb">';
|
$str = '<ol class="breadcrumb">';
|
||||||
|
|
||||||
// Get the breadcrumbs by exploding the current path.
|
// Get the breadcrumbs by exploding the current path.
|
||||||
$basePath = Utils::basePath();
|
$basePath = Utils::basePath();
|
||||||
$parts = explode('?', $_SERVER['REQUEST_URI']);
|
$parts = explode('?', $_SERVER['REQUEST_URI']);
|
||||||
$path = $parts[0];
|
$path = $parts[0];
|
||||||
|
|
||||||
if ($basePath != '/')
|
if ($basePath != '/') {
|
||||||
{
|
$path = str_replace($basePath, '', $path);
|
||||||
$path = str_replace($basePath, '', $path);
|
|
||||||
}
|
|
||||||
$crumbs = explode('/', $path);
|
|
||||||
|
|
||||||
foreach ($crumbs as $key => $val)
|
|
||||||
{
|
|
||||||
if (is_numeric($val))
|
|
||||||
{
|
|
||||||
unset($crumbs[$key]);
|
|
||||||
}
|
}
|
||||||
}
|
$crumbs = explode('/', $path);
|
||||||
|
|
||||||
$crumbs = array_values($crumbs);
|
foreach ($crumbs as $key => $val) {
|
||||||
for ($i=0; $i<count($crumbs); $i++) {
|
if (is_numeric($val)) {
|
||||||
$crumb = trim($crumbs[$i]);
|
unset($crumbs[$key]);
|
||||||
if (!$crumb) continue;
|
}
|
||||||
if ($crumb == 'company') return '';
|
|
||||||
$name = trans("texts.$crumb");
|
|
||||||
if ($i==count($crumbs)-1)
|
|
||||||
{
|
|
||||||
$str .= "<li class='active'>$name</li>";
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
$crumbs = array_values($crumbs);
|
||||||
$str .= '<li>'.link_to($crumb, $name).'</li>';
|
for ($i=0; $i<count($crumbs); $i++) {
|
||||||
|
$crumb = trim($crumbs[$i]);
|
||||||
|
if (!$crumb) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($crumb == 'company') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
$name = trans("texts.$crumb");
|
||||||
|
if ($i==count($crumbs)-1) {
|
||||||
|
$str .= "<li class='active'>$name</li>";
|
||||||
|
} else {
|
||||||
|
$str .= '<li>'.link_to($crumb, $name).'</li>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
return $str . '</ol>';
|
||||||
return $str . '</ol>';
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function uctrans($text)
|
function uctrans($text)
|
||||||
{
|
{
|
||||||
return ucwords(trans($text));
|
return ucwords(trans($text));
|
||||||
}
|
}
|
||||||
|
|
||||||
// optional trans: only return the string if it's translated
|
// optional trans: only return the string if it's translated
|
||||||
function otrans($text)
|
function otrans($text)
|
||||||
{
|
{
|
||||||
$locale = Session::get(SESSION_LOCALE);
|
$locale = Session::get(SESSION_LOCALE);
|
||||||
|
|
||||||
if ($locale == 'en')
|
if ($locale == 'en') {
|
||||||
{
|
return trans($text);
|
||||||
return trans($text);
|
} else {
|
||||||
}
|
$string = trans($text);
|
||||||
else
|
$english = trans($text, [], 'en');
|
||||||
{
|
return $string != $english ? $string : '';
|
||||||
$string = trans($text);
|
}
|
||||||
$english = trans($text, [], 'en');
|
|
||||||
|
|
||||||
return $string != $english ? $string : '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Validator::extend('positive', function($attribute, $value, $parameters)
|
Validator::extend('positive', function($attribute, $value, $parameters) {
|
||||||
{
|
return Utils::parseFloat($value) >= 0;
|
||||||
return Utils::parseFloat($value) >= 0;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Validator::extend('has_credit', function($attribute, $value, $parameters)
|
Validator::extend('has_credit', function($attribute, $value, $parameters) {
|
||||||
{
|
$publicClientId = $parameters[0];
|
||||||
$publicClientId = $parameters[0];
|
$amount = $parameters[1];
|
||||||
$amount = $parameters[1];
|
|
||||||
|
|
||||||
$client = Client::scope($publicClientId)->firstOrFail();
|
$client = Client::scope($publicClientId)->firstOrFail();
|
||||||
$credit = $client->getTotalCredit();
|
$credit = $client->getTotalCredit();
|
||||||
|
|
||||||
return $credit >= $amount;
|
return $credit >= $amount;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -82,12 +82,14 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach ($pastDue as $invoice)
|
@foreach ($pastDue as $invoice)
|
||||||
<tr>
|
@if (!$invoice->client->trashed())
|
||||||
<td>{{ $invoice->getLink() }}</td>
|
<tr>
|
||||||
<td>{{ $invoice->client->getDisplayName() }}</td>
|
<td>{{ $invoice->getLink() }}</td>
|
||||||
<td>{{ Utils::fromSqlDate($invoice->due_date) }}</td>
|
<td>{{ $invoice->client->getDisplayName() }}</td>
|
||||||
<td>{{ Utils::formatMoney($invoice->balance, $invoice->client->currency_id) }}</td>
|
<td>{{ Utils::fromSqlDate($invoice->due_date) }}</td>
|
||||||
</tr>
|
<td>{{ Utils::formatMoney($invoice->balance, $invoice->client->currency_id) }}</td>
|
||||||
|
</tr>
|
||||||
|
@endif
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -114,12 +116,14 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach ($upcoming as $invoice)
|
@foreach ($upcoming as $invoice)
|
||||||
<tr>
|
@if (!$invoice->client->trashed())
|
||||||
<td>{{ $invoice->getLink() }}</td>
|
<tr>
|
||||||
<td>{{ $invoice->client->getDisplayName() }}</td>
|
<td>{{ $invoice->getLink() }}</td>
|
||||||
<td>{{ Utils::fromSqlDate($invoice->due_date) }}</td>
|
<td>{{ $invoice->client->getDisplayName() }}</td>
|
||||||
<td>{{ Utils::formatMoney($invoice->balance, $invoice->client->currency_id) }}</td>
|
<td>{{ Utils::fromSqlDate($invoice->due_date) }}</td>
|
||||||
</tr>
|
<td>{{ Utils::formatMoney($invoice->balance, $invoice->client->currency_id) }}</td>
|
||||||
|
</tr>
|
||||||
|
@endif
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -135,7 +135,7 @@
|
|||||||
<i style="display:none" data-bind="visible: actionsVisible() && $parent.invoice_items().length > 1" class="fa fa-sort"></i>
|
<i style="display:none" data-bind="visible: actionsVisible() && $parent.invoice_items().length > 1" class="fa fa-sort"></i>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ Former::text('product_key')->useDatalist($products, 'product_key')->onkeyup('onItemChange()')
|
{{ Former::text('product_key')->useDatalist($products->toArray(), 'product_key')->onkeyup('onItemChange()')
|
||||||
->raw()->data_bind("value: product_key, valueUpdate: 'afterkeydown'")->addClass('datalist') }}
|
->raw()->data_bind("value: product_key, valueUpdate: 'afterkeydown'")->addClass('datalist') }}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@ -323,7 +323,7 @@
|
|||||||
@if ($invoice && $invoice->id && $entityType == ENTITY_INVOICE)
|
@if ($invoice && $invoice->id && $entityType == ENTITY_INVOICE)
|
||||||
{{ Button::primary(trans('texts.enter_payment'), array('onclick' => 'onPaymentClick()'))->append_with_icon('usd'); }}
|
{{ Button::primary(trans('texts.enter_payment'), array('onclick' => 'onPaymentClick()'))->append_with_icon('usd'); }}
|
||||||
@endif
|
@endif
|
||||||
@elseif ($invoice && $invoice->trashed())
|
@elseif ($invoice && $invoice->trashed() && !$invoice->is_deleted == '1')
|
||||||
{{ Button::success(trans('texts.restore'), ['onclick' => 'submitAction("restore")'])->append_with_icon('cloud-download') }}
|
{{ Button::success(trans('texts.restore'), ['onclick' => 'submitAction("restore")'])->append_with_icon('cloud-download') }}
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
@ -90,7 +90,7 @@ FLUSH PRIVILEGES;</pre>
|
|||||||
{{ Former::text('first_name') }}
|
{{ Former::text('first_name') }}
|
||||||
{{ Former::text('last_name') }}
|
{{ Former::text('last_name') }}
|
||||||
{{ Former::text('email') }}
|
{{ Former::text('email') }}
|
||||||
{{ Former::text('password') }}
|
{{ Former::password('password') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user