mirror of
https://github.com/invoiceninja/invoiceninja.git
synced 2024-11-11 21:52:35 +01:00
Merge branch 'develop' of https://github.com/turbo124/invoiceninja into develop
iiiiiespecially if it merges an updated upstream into a topic branch.
This commit is contained in:
commit
b6c862aa46
@ -36,7 +36,7 @@ class SendReminders extends Command
|
|||||||
$this->info(count($accounts).' accounts found');
|
$this->info(count($accounts).' accounts found');
|
||||||
|
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
if (!$account->isPro()) {
|
if (!$account->hasFeature(FEATURE_EMAIL_TEMPLATES_REMINDERS)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ use DateTime;
|
|||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
use Symfony\Component\Console\Input\InputOption;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
use App\Models\Account;
|
use App\Models\Company;
|
||||||
use App\Ninja\Mailers\ContactMailer as Mailer;
|
use App\Ninja\Mailers\ContactMailer as Mailer;
|
||||||
use App\Ninja\Repositories\AccountRepository;
|
use App\Ninja\Repositories\AccountRepository;
|
||||||
|
|
||||||
@ -30,24 +30,32 @@ class SendRenewalInvoices extends Command
|
|||||||
$today = new DateTime();
|
$today = new DateTime();
|
||||||
$sentTo = [];
|
$sentTo = [];
|
||||||
|
|
||||||
// get all accounts with pro plans expiring in 10 days
|
// get all accounts with plans expiring in 10 days
|
||||||
$accounts = Account::whereRaw('datediff(curdate(), pro_plan_paid) = 355')
|
$companies = Company::whereRaw('datediff(plan_expires, curdate()) = 10')
|
||||||
->orderBy('id')
|
->orderBy('id')
|
||||||
->get();
|
->get();
|
||||||
$this->info(count($accounts).' accounts found');
|
$this->info(count($companies).' companies found');
|
||||||
|
|
||||||
foreach ($accounts as $account) {
|
foreach ($companies as $company) {
|
||||||
// don't send multiple invoices to multi-company users
|
if (!count($company->accounts)) {
|
||||||
if ($userAccountId = $this->accountRepo->getUserAccountId($account)) {
|
continue;
|
||||||
if (isset($sentTo[$userAccountId])) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
$sentTo[$userAccountId] = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$account = $company->accounts->sortBy('id')->first();
|
||||||
|
$plan = $company->plan;
|
||||||
|
$term = $company->plan_term;
|
||||||
|
|
||||||
|
if ($company->pending_plan) {
|
||||||
|
$plan = $company->pending_plan;
|
||||||
|
$term = $company->pending_term;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($plan == PLAN_FREE || !$plan || !$term ){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$client = $this->accountRepo->getNinjaClient($account);
|
$client = $this->accountRepo->getNinjaClient($account);
|
||||||
$invitation = $this->accountRepo->createNinjaInvoice($client, $account);
|
$invitation = $this->accountRepo->createNinjaInvoice($client, $account, $plan, $term);
|
||||||
|
|
||||||
// set the due date to 10 days from now
|
// set the due date to 10 days from now
|
||||||
$invoice = $invitation->invoice;
|
$invoice = $invitation->invoice;
|
||||||
|
@ -71,11 +71,10 @@ class Handler extends ExceptionHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent::render($request, $e);
|
|
||||||
|
|
||||||
/*
|
|
||||||
// In production, except for maintenance mode, we'll show a custom error screen
|
// In production, except for maintenance mode, we'll show a custom error screen
|
||||||
if (Utils::isNinjaProd() && !Utils::isDownForMaintenance()) {
|
if (Utils::isNinjaProd()
|
||||||
|
&& !Utils::isDownForMaintenance()
|
||||||
|
&& !($e instanceof HttpResponseException)) {
|
||||||
$data = [
|
$data = [
|
||||||
'error' => get_class($e),
|
'error' => get_class($e),
|
||||||
'hideHeader' => true,
|
'hideHeader' => true,
|
||||||
@ -85,6 +84,5 @@ class Handler extends ExceptionHandler {
|
|||||||
} else {
|
} else {
|
||||||
return parent::render($request, $e);
|
return parent::render($request, $e);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ use App\Ninja\Mailers\ContactMailer;
|
|||||||
use App\Events\UserSignedUp;
|
use App\Events\UserSignedUp;
|
||||||
use App\Events\UserSettingsChanged;
|
use App\Events\UserSettingsChanged;
|
||||||
use App\Services\AuthService;
|
use App\Services\AuthService;
|
||||||
|
use App\Services\PaymentService;
|
||||||
|
|
||||||
use App\Http\Requests\UpdateAccountRequest;
|
use App\Http\Requests\UpdateAccountRequest;
|
||||||
|
|
||||||
@ -40,8 +41,9 @@ class AccountController extends BaseController
|
|||||||
protected $userMailer;
|
protected $userMailer;
|
||||||
protected $contactMailer;
|
protected $contactMailer;
|
||||||
protected $referralRepository;
|
protected $referralRepository;
|
||||||
|
protected $paymentService;
|
||||||
|
|
||||||
public function __construct(AccountRepository $accountRepo, UserMailer $userMailer, ContactMailer $contactMailer, ReferralRepository $referralRepository)
|
public function __construct(AccountRepository $accountRepo, UserMailer $userMailer, ContactMailer $contactMailer, ReferralRepository $referralRepository, PaymentService $paymentService)
|
||||||
{
|
{
|
||||||
//parent::__construct();
|
//parent::__construct();
|
||||||
|
|
||||||
@ -49,6 +51,7 @@ class AccountController extends BaseController
|
|||||||
$this->userMailer = $userMailer;
|
$this->userMailer = $userMailer;
|
||||||
$this->contactMailer = $contactMailer;
|
$this->contactMailer = $contactMailer;
|
||||||
$this->referralRepository = $referralRepository;
|
$this->referralRepository = $referralRepository;
|
||||||
|
$this->paymentService = $paymentService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function demo()
|
public function demo()
|
||||||
@ -111,10 +114,135 @@ class AccountController extends BaseController
|
|||||||
|
|
||||||
public function enableProPlan()
|
public function enableProPlan()
|
||||||
{
|
{
|
||||||
$invitation = $this->accountRepo->enableProPlan();
|
if (Auth::user()->isPro() && ! Auth::user()->isTrial()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$invitation = $this->accountRepo->enablePlan();
|
||||||
|
|
||||||
return $invitation->invitation_key;
|
return $invitation->invitation_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function changePlan() {
|
||||||
|
$user = Auth::user();
|
||||||
|
$account = $user->account;
|
||||||
|
|
||||||
|
$plan = Input::get('plan');
|
||||||
|
$term = Input::get('plan_term');
|
||||||
|
|
||||||
|
$planDetails = $account->getPlanDetails(false, false);
|
||||||
|
|
||||||
|
$credit = 0;
|
||||||
|
if ($planDetails) {
|
||||||
|
if ($planDetails['plan'] == PLAN_PRO && $plan == PLAN_ENTERPRISE) {
|
||||||
|
// Upgrade from pro to enterprise
|
||||||
|
if($planDetails['term'] == PLAN_TERM_YEARLY && $term == PLAN_TERM_MONTHLY) {
|
||||||
|
// Upgrade to yearly for now; switch to monthly in a year
|
||||||
|
$pending_monthly = true;
|
||||||
|
$term = PLAN_TERM_YEARLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
$new_plan = array(
|
||||||
|
'plan' => PLAN_ENTERPRISE,
|
||||||
|
'term' => $term,
|
||||||
|
);
|
||||||
|
} elseif ($planDetails['plan'] == $plan) {
|
||||||
|
// Term switch
|
||||||
|
if ($planDetails['term'] == PLAN_TERM_YEARLY && $term == PLAN_TERM_MONTHLY) {
|
||||||
|
$pending_change = array(
|
||||||
|
'plan' => $plan,
|
||||||
|
'term' => $term
|
||||||
|
);
|
||||||
|
} elseif ($planDetails['term'] == PLAN_TERM_MONTHLY && $term == PLAN_TERM_YEARLY) {
|
||||||
|
$new_plan = array(
|
||||||
|
'plan' => $plan,
|
||||||
|
'term' => $term,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Cancel the pending change
|
||||||
|
$account->company->pending_plan = null;
|
||||||
|
$account->company->pending_term = null;
|
||||||
|
$account->company->save();
|
||||||
|
Session::flash('message', trans('texts.updated_plan'));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Downgrade
|
||||||
|
$refund_deadline = clone $planDetails['started'];
|
||||||
|
$refund_deadline->modify('+30 days');
|
||||||
|
|
||||||
|
if ($plan == PLAN_FREE && $refund_deadline >= date_create()) {
|
||||||
|
// Refund
|
||||||
|
$account->company->plan = null;
|
||||||
|
$account->company->plan_term = null;
|
||||||
|
$account->company->plan_started = null;
|
||||||
|
$account->company->plan_expires = null;
|
||||||
|
$account->company->plan_paid = null;
|
||||||
|
$account->company->pending_plan = null;
|
||||||
|
$account->company->pending_term = null;
|
||||||
|
|
||||||
|
if ($account->company->payment) {
|
||||||
|
$payment = $account->company->payment;
|
||||||
|
|
||||||
|
$gateway = $this->paymentService->createGateway($payment->account_gateway);
|
||||||
|
$refund = $gateway->refund(array(
|
||||||
|
'transactionReference' => $payment->transaction_reference,
|
||||||
|
'amount' => $payment->amount * 100
|
||||||
|
));
|
||||||
|
$refund->send();
|
||||||
|
$payment->delete();
|
||||||
|
Session::flash('message', trans('texts.plan_refunded'));
|
||||||
|
\Log::info("Refunded Plan Payment: {$account->name} - {$user->email}");
|
||||||
|
} else {
|
||||||
|
Session::flash('message', trans('texts.updated_plan'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$account->company->save();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$pending_change = array(
|
||||||
|
'plan' => $plan,
|
||||||
|
'term' => $plan == PLAN_FREE ? null : $term,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($new_plan)) {
|
||||||
|
$time_used = $planDetails['paid']->diff(date_create());
|
||||||
|
$days_used = $time_used->days;
|
||||||
|
|
||||||
|
if ($time_used->invert) {
|
||||||
|
// They paid in advance
|
||||||
|
$days_used *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$days_total = $planDetails['paid']->diff($planDetails['expires'])->days;
|
||||||
|
|
||||||
|
$percent_used = $days_used / $days_total;
|
||||||
|
$old_plan_price = Account::$plan_prices[$planDetails['plan']][$planDetails['term']];
|
||||||
|
$credit = $old_plan_price * (1 - $percent_used);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$new_plan = array(
|
||||||
|
'plan' => $plan,
|
||||||
|
'term' => $term,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($pending_change) && empty($new_plan)) {
|
||||||
|
$account->company->pending_plan = $pending_change['plan'];
|
||||||
|
$account->company->pending_term = $pending_change['term'];
|
||||||
|
$account->company->save();
|
||||||
|
|
||||||
|
Session::flash('message', trans('texts.updated_plan'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($new_plan)) {
|
||||||
|
$invitation = $this->accountRepo->enablePlan($new_plan['plan'], $new_plan['term'], $credit, !empty($pending_monthly));
|
||||||
|
return Redirect::to('payment/'.$invitation->invitation_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Redirect::to('/settings/'.ACCOUNT_MANAGEMENT, 301);
|
||||||
|
}
|
||||||
|
|
||||||
public function setTrashVisible($entityType, $visible)
|
public function setTrashVisible($entityType, $visible)
|
||||||
{
|
{
|
||||||
@ -149,6 +277,8 @@ class AccountController extends BaseController
|
|||||||
return self::showInvoiceSettings();
|
return self::showInvoiceSettings();
|
||||||
} elseif ($section == ACCOUNT_IMPORT_EXPORT) {
|
} elseif ($section == ACCOUNT_IMPORT_EXPORT) {
|
||||||
return View::make('accounts.import_export', ['title' => trans('texts.import_export')]);
|
return View::make('accounts.import_export', ['title' => trans('texts.import_export')]);
|
||||||
|
} elseif ($section == ACCOUNT_MANAGEMENT) {
|
||||||
|
return self::showAccountManagement();
|
||||||
} elseif ($section == ACCOUNT_INVOICE_DESIGN || $section == ACCOUNT_CUSTOMIZE_DESIGN) {
|
} elseif ($section == ACCOUNT_INVOICE_DESIGN || $section == ACCOUNT_CUSTOMIZE_DESIGN) {
|
||||||
return self::showInvoiceDesign($section);
|
return self::showInvoiceDesign($section);
|
||||||
} elseif ($section == ACCOUNT_CLIENT_PORTAL) {
|
} elseif ($section == ACCOUNT_CLIENT_PORTAL) {
|
||||||
@ -232,6 +362,18 @@ class AccountController extends BaseController
|
|||||||
return View::make('accounts.details', $data);
|
return View::make('accounts.details', $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function showAccountManagement()
|
||||||
|
{
|
||||||
|
$account = Auth::user()->account;
|
||||||
|
$data = [
|
||||||
|
'account' => $account,
|
||||||
|
'planDetails' => $account->getPlanDetails(true),
|
||||||
|
'title' => trans('texts.account_management'),
|
||||||
|
];
|
||||||
|
|
||||||
|
return View::make('accounts.management', $data);
|
||||||
|
}
|
||||||
|
|
||||||
public function showUserDetails()
|
public function showUserDetails()
|
||||||
{
|
{
|
||||||
$oauthLoginUrls = [];
|
$oauthLoginUrls = [];
|
||||||
@ -379,7 +521,7 @@ class AccountController extends BaseController
|
|||||||
|
|
||||||
$invoice->client = $client;
|
$invoice->client = $client;
|
||||||
$invoice->invoice_items = [$invoiceItem];
|
$invoice->invoice_items = [$invoiceItem];
|
||||||
//$invoice->documents = $account->isPro() ? [$document] : [];
|
//$invoice->documents = $account->hasFeature(FEATURE_DOCUMENTS) ? [$document] : [];
|
||||||
$invoice->documents = [];
|
$invoice->documents = [];
|
||||||
|
|
||||||
$data['account'] = $account;
|
$data['account'] = $account;
|
||||||
@ -389,6 +531,58 @@ class AccountController extends BaseController
|
|||||||
$data['invoiceDesigns'] = InvoiceDesign::getDesigns();
|
$data['invoiceDesigns'] = InvoiceDesign::getDesigns();
|
||||||
$data['invoiceFonts'] = Cache::get('fonts');
|
$data['invoiceFonts'] = Cache::get('fonts');
|
||||||
$data['section'] = $section;
|
$data['section'] = $section;
|
||||||
|
|
||||||
|
$pageSizes = [
|
||||||
|
'A0',
|
||||||
|
'A1',
|
||||||
|
'A2',
|
||||||
|
'A3',
|
||||||
|
'A4',
|
||||||
|
'A5',
|
||||||
|
'A6',
|
||||||
|
'A7',
|
||||||
|
'A8',
|
||||||
|
'A9',
|
||||||
|
'A10',
|
||||||
|
'B0',
|
||||||
|
'B1',
|
||||||
|
'B2',
|
||||||
|
'B3',
|
||||||
|
'B4',
|
||||||
|
'B5',
|
||||||
|
'B6',
|
||||||
|
'B7',
|
||||||
|
'B8',
|
||||||
|
'B9',
|
||||||
|
'B10',
|
||||||
|
'C0',
|
||||||
|
'C1',
|
||||||
|
'C2',
|
||||||
|
'C3',
|
||||||
|
'C4',
|
||||||
|
'C5',
|
||||||
|
'C6',
|
||||||
|
'C7',
|
||||||
|
'C8',
|
||||||
|
'C9',
|
||||||
|
'C10',
|
||||||
|
'RA0',
|
||||||
|
'RA1',
|
||||||
|
'RA2',
|
||||||
|
'RA3',
|
||||||
|
'RA4',
|
||||||
|
'SRA0',
|
||||||
|
'SRA1',
|
||||||
|
'SRA2',
|
||||||
|
'SRA3',
|
||||||
|
'SRA4',
|
||||||
|
'Executive',
|
||||||
|
'Folio',
|
||||||
|
'Legal',
|
||||||
|
'Letter',
|
||||||
|
'Tabloid',
|
||||||
|
];
|
||||||
|
$data['pageSizes'] = array_combine($pageSizes, $pageSizes);
|
||||||
|
|
||||||
$design = false;
|
$design = false;
|
||||||
foreach ($data['invoiceDesigns'] as $item) {
|
foreach ($data['invoiceDesigns'] as $item) {
|
||||||
@ -501,7 +695,7 @@ class AccountController extends BaseController
|
|||||||
|
|
||||||
private function saveCustomizeDesign()
|
private function saveCustomizeDesign()
|
||||||
{
|
{
|
||||||
if (Auth::user()->account->isPro()) {
|
if (Auth::user()->account->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN)) {
|
||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
$account->custom_design = Input::get('custom_design');
|
$account->custom_design = Input::get('custom_design');
|
||||||
$account->invoice_design_id = CUSTOM_DESIGN;
|
$account->invoice_design_id = CUSTOM_DESIGN;
|
||||||
@ -516,7 +710,7 @@ class AccountController extends BaseController
|
|||||||
private function saveClientPortal()
|
private function saveClientPortal()
|
||||||
{
|
{
|
||||||
// Only allowed for pro Invoice Ninja users or white labeled self-hosted users
|
// Only allowed for pro Invoice Ninja users or white labeled self-hosted users
|
||||||
if ((Utils::isNinja() && Auth::user()->account->isPro()) || Auth::user()->account->isWhiteLabel()) {
|
if (Auth::user()->account->hasFeature(FEATURE_CLIENT_PORTAL_CSS)) {
|
||||||
$input_css = Input::get('client_view_css');
|
$input_css = Input::get('client_view_css');
|
||||||
if (Utils::isNinja()) {
|
if (Utils::isNinja()) {
|
||||||
// Allow referencing the body element
|
// Allow referencing the body element
|
||||||
@ -567,7 +761,7 @@ class AccountController extends BaseController
|
|||||||
|
|
||||||
private function saveEmailTemplates()
|
private function saveEmailTemplates()
|
||||||
{
|
{
|
||||||
if (Auth::user()->account->isPro()) {
|
if (Auth::user()->account->hasFeature(FEATURE_EMAIL_TEMPLATES_REMINDERS)) {
|
||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
|
|
||||||
foreach ([ENTITY_INVOICE, ENTITY_QUOTE, ENTITY_PAYMENT, REMINDER1, REMINDER2, REMINDER3] as $type) {
|
foreach ([ENTITY_INVOICE, ENTITY_QUOTE, ENTITY_PAYMENT, REMINDER1, REMINDER2, REMINDER3] as $type) {
|
||||||
@ -629,7 +823,7 @@ class AccountController extends BaseController
|
|||||||
|
|
||||||
private function saveEmailSettings()
|
private function saveEmailSettings()
|
||||||
{
|
{
|
||||||
if (Auth::user()->account->isPro()) {
|
if (Auth::user()->account->hasFeature(FEATURE_CUSTOM_EMAILS)) {
|
||||||
$rules = [];
|
$rules = [];
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
$iframeURL = preg_replace('/[^a-zA-Z0-9_\-\:\/\.]/', '', substr(strtolower(Input::get('iframe_url')), 0, MAX_IFRAME_URL_LENGTH));
|
$iframeURL = preg_replace('/[^a-zA-Z0-9_\-\:\/\.]/', '', substr(strtolower(Input::get('iframe_url')), 0, MAX_IFRAME_URL_LENGTH));
|
||||||
@ -672,7 +866,7 @@ class AccountController extends BaseController
|
|||||||
|
|
||||||
private function saveInvoiceSettings()
|
private function saveInvoiceSettings()
|
||||||
{
|
{
|
||||||
if (Auth::user()->account->isPro()) {
|
if (Auth::user()->account->hasFeature(FEATURE_INVOICE_SETTINGS)) {
|
||||||
$rules = [
|
$rules = [
|
||||||
'invoice_number_pattern' => 'has_counter',
|
'invoice_number_pattern' => 'has_counter',
|
||||||
'quote_number_pattern' => 'has_counter',
|
'quote_number_pattern' => 'has_counter',
|
||||||
@ -701,6 +895,7 @@ class AccountController extends BaseController
|
|||||||
$account->custom_invoice_item_label1 = trim(Input::get('custom_invoice_item_label1'));
|
$account->custom_invoice_item_label1 = trim(Input::get('custom_invoice_item_label1'));
|
||||||
$account->custom_invoice_item_label2 = trim(Input::get('custom_invoice_item_label2'));
|
$account->custom_invoice_item_label2 = trim(Input::get('custom_invoice_item_label2'));
|
||||||
|
|
||||||
|
$account->invoice_number_padding = Input::get('invoice_number_padding');
|
||||||
$account->invoice_number_counter = Input::get('invoice_number_counter');
|
$account->invoice_number_counter = Input::get('invoice_number_counter');
|
||||||
$account->quote_number_prefix = Input::get('quote_number_prefix');
|
$account->quote_number_prefix = Input::get('quote_number_prefix');
|
||||||
$account->share_counter = Input::get('share_counter') ? true : false;
|
$account->share_counter = Input::get('share_counter') ? true : false;
|
||||||
@ -752,7 +947,7 @@ class AccountController extends BaseController
|
|||||||
|
|
||||||
private function saveInvoiceDesign()
|
private function saveInvoiceDesign()
|
||||||
{
|
{
|
||||||
if (Auth::user()->account->isPro()) {
|
if (Auth::user()->account->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN)) {
|
||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
$account->hide_quantity = Input::get('hide_quantity') ? true : false;
|
$account->hide_quantity = Input::get('hide_quantity') ? true : false;
|
||||||
$account->hide_paid_to_date = Input::get('hide_paid_to_date') ? true : false;
|
$account->hide_paid_to_date = Input::get('hide_paid_to_date') ? true : false;
|
||||||
@ -764,9 +959,20 @@ class AccountController extends BaseController
|
|||||||
$account->primary_color = Input::get('primary_color');
|
$account->primary_color = Input::get('primary_color');
|
||||||
$account->secondary_color = Input::get('secondary_color');
|
$account->secondary_color = Input::get('secondary_color');
|
||||||
$account->invoice_design_id = Input::get('invoice_design_id');
|
$account->invoice_design_id = Input::get('invoice_design_id');
|
||||||
|
$account->font_size = intval(Input::get('font_size'));
|
||||||
|
$account->page_size = Input::get('page_size');
|
||||||
|
$account->live_preview = Input::get('live_preview') ? true : false;
|
||||||
|
|
||||||
if (Input::has('font_size')) {
|
// Automatically disable live preview when using a large font
|
||||||
$account->font_size = intval(Input::get('font_size'));
|
$fonts = Cache::get('fonts')->filter(function($font) use ($account) {
|
||||||
|
if ($font->google_font) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return $font->id == $account->header_font_id || $font->id == $account->body_font_id;
|
||||||
|
});
|
||||||
|
if ($account->live_preview && count($fonts)) {
|
||||||
|
$account->live_preview = false;
|
||||||
|
Session::flash('warning', trans('texts.live_preview_disabled'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$labels = [];
|
$labels = [];
|
||||||
@ -990,7 +1196,7 @@ class AccountController extends BaseController
|
|||||||
$user->registered = true;
|
$user->registered = true;
|
||||||
$user->save();
|
$user->save();
|
||||||
|
|
||||||
$user->account->startTrial();
|
$user->account->startTrial(PLAN_PRO);
|
||||||
|
|
||||||
if (Input::get('go_pro') == 'true') {
|
if (Input::get('go_pro') == 'true') {
|
||||||
Session::set(REQUESTED_PRO_PLAN, true);
|
Session::set(REQUESTED_PRO_PLAN, true);
|
||||||
@ -1046,6 +1252,9 @@ class AccountController extends BaseController
|
|||||||
\Log::info("Canceled Account: {$account->name} - {$user->email}");
|
\Log::info("Canceled Account: {$account->name} - {$user->email}");
|
||||||
|
|
||||||
$this->accountRepo->unlinkAccount($account);
|
$this->accountRepo->unlinkAccount($account);
|
||||||
|
if ($account->company->accounts->count() == 1) {
|
||||||
|
$account->company->forceDelete();
|
||||||
|
}
|
||||||
$account->forceDelete();
|
$account->forceDelete();
|
||||||
|
|
||||||
Auth::logout();
|
Auth::logout();
|
||||||
@ -1062,12 +1271,12 @@ class AccountController extends BaseController
|
|||||||
return Redirect::to('/settings/'.ACCOUNT_USER_DETAILS)->with('message', trans('texts.confirmation_resent'));
|
return Redirect::to('/settings/'.ACCOUNT_USER_DETAILS)->with('message', trans('texts.confirmation_resent'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function startTrial()
|
public function startTrial($plan)
|
||||||
{
|
{
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
|
|
||||||
if ($user->isEligibleForTrial()) {
|
if ($user->isEligibleForTrial($plan)) {
|
||||||
$user->account->startTrial();
|
$user->account->startTrial($plan);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Redirect::back()->with('message', trans('texts.trial_success'));
|
return Redirect::back()->with('message', trans('texts.trial_success'));
|
||||||
|
@ -178,9 +178,12 @@ class AppController extends BaseController
|
|||||||
|
|
||||||
$config = '';
|
$config = '';
|
||||||
foreach ($_ENV as $key => $val) {
|
foreach ($_ENV as $key => $val) {
|
||||||
if (preg_match('/\s/',$val)) {
|
if (is_array($val)) {
|
||||||
$val = "'{$val}'";
|
continue;
|
||||||
}
|
}
|
||||||
|
if (preg_match('/\s/', $val)) {
|
||||||
|
$val = "'{$val}'";
|
||||||
|
}
|
||||||
$config .= "{$key}={$val}\n";
|
$config .= "{$key}={$val}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +133,9 @@ class AuthController extends Controller {
|
|||||||
if (Auth::check() && !Auth::user()->registered) {
|
if (Auth::check() && !Auth::user()->registered) {
|
||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
$this->accountRepo->unlinkAccount($account);
|
$this->accountRepo->unlinkAccount($account);
|
||||||
|
if ($account->company->accounts->count() == 1) {
|
||||||
|
$account->company->forceDelete();
|
||||||
|
}
|
||||||
$account->forceDelete();
|
$account->forceDelete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ class AuthController extends Controller {
|
|||||||
$client = $invoice->client;
|
$client = $invoice->client;
|
||||||
$account = $client->account;
|
$account = $client->account;
|
||||||
|
|
||||||
$data['hideLogo'] = $account->isWhiteLabel();
|
$data['hideLogo'] = $account->hasFeature(FEATURE_WHITE_LABEL);
|
||||||
$data['clientViewCSS'] = $account->clientViewCSS();
|
$data['clientViewCSS'] = $account->clientViewCSS();
|
||||||
$data['clientFontUrl'] = $account->getFontsUrl();
|
$data['clientFontUrl'] = $account->getFontsUrl();
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,7 @@ class PasswordController extends Controller {
|
|||||||
$client = $invoice->client;
|
$client = $invoice->client;
|
||||||
$account = $client->account;
|
$account = $client->account;
|
||||||
|
|
||||||
$data['hideLogo'] = $account->isWhiteLabel();
|
$data['hideLogo'] = $account->hasFeature(FEATURE_WHITE_LABEL);
|
||||||
$data['clientViewCSS'] = $account->clientViewCSS();
|
$data['clientViewCSS'] = $account->clientViewCSS();
|
||||||
$data['clientFontUrl'] = $account->getFontsUrl();
|
$data['clientFontUrl'] = $account->getFontsUrl();
|
||||||
}
|
}
|
||||||
@ -117,7 +117,7 @@ class PasswordController extends Controller {
|
|||||||
$client = $invoice->client;
|
$client = $invoice->client;
|
||||||
$account = $client->account;
|
$account = $client->account;
|
||||||
|
|
||||||
$data['hideLogo'] = $account->isWhiteLabel();
|
$data['hideLogo'] = $account->hasFeature(FEATURE_WHITE_LABEL);
|
||||||
$data['clientViewCSS'] = $account->clientViewCSS();
|
$data['clientViewCSS'] = $account->clientViewCSS();
|
||||||
$data['clientFontUrl'] = $account->getFontsUrl();
|
$data['clientFontUrl'] = $account->getFontsUrl();
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ class ClientController extends BaseController
|
|||||||
if(Task::canCreate()){
|
if(Task::canCreate()){
|
||||||
$actionLinks[] = ['label' => trans('texts.new_task'), 'url' => URL::to('/tasks/create/'.$client->public_id)];
|
$actionLinks[] = ['label' => trans('texts.new_task'), 'url' => URL::to('/tasks/create/'.$client->public_id)];
|
||||||
}
|
}
|
||||||
if (Utils::isPro() && Invoice::canCreate()) {
|
if (Utils::hasFeature(FEATURE_QUOTES) && Invoice::canCreate()) {
|
||||||
$actionLinks[] = ['label' => trans('texts.new_quote'), 'url' => URL::to('/quotes/create/'.$client->public_id)];
|
$actionLinks[] = ['label' => trans('texts.new_quote'), 'url' => URL::to('/quotes/create/'.$client->public_id)];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +201,7 @@ class ClientController extends BaseController
|
|||||||
|
|
||||||
if (Auth::user()->account->isNinjaAccount()) {
|
if (Auth::user()->account->isNinjaAccount()) {
|
||||||
if ($account = Account::whereId($client->public_id)->first()) {
|
if ($account = Account::whereId($client->public_id)->first()) {
|
||||||
$data['proPlanPaid'] = $account['pro_plan_paid'];
|
$data['planDetails'] = $account->getPlanDetails(false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ class DocumentController extends BaseController
|
|||||||
|
|
||||||
public function postUpload()
|
public function postUpload()
|
||||||
{
|
{
|
||||||
if (!Utils::isPro()) {
|
if (!Utils::hasFeature(FEATURE_DOCUMENTS)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +132,11 @@ class InvoiceController extends BaseController
|
|||||||
$invoice->start_date = Utils::fromSqlDate($invoice->start_date);
|
$invoice->start_date = Utils::fromSqlDate($invoice->start_date);
|
||||||
$invoice->end_date = Utils::fromSqlDate($invoice->end_date);
|
$invoice->end_date = Utils::fromSqlDate($invoice->end_date);
|
||||||
$invoice->last_sent_date = Utils::fromSqlDate($invoice->last_sent_date);
|
$invoice->last_sent_date = Utils::fromSqlDate($invoice->last_sent_date);
|
||||||
$invoice->is_pro = Auth::user()->isPro();
|
$invoice->features = [
|
||||||
|
'customize_invoice_design' => Auth::user()->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN),
|
||||||
|
'remove_created_by' => Auth::user()->hasFeature(FEATURE_REMOVE_CREATED_BY),
|
||||||
|
'invoice_settings' => Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS),
|
||||||
|
];
|
||||||
|
|
||||||
$actions = [
|
$actions = [
|
||||||
['url' => 'javascript:onCloneClick()', 'label' => trans("texts.clone_{$entityType}")],
|
['url' => 'javascript:onCloneClick()', 'label' => trans("texts.clone_{$entityType}")],
|
||||||
@ -573,7 +577,11 @@ class InvoiceController extends BaseController
|
|||||||
$invoice->load('user', 'invoice_items', 'documents', 'expenses', 'expenses.documents', 'account.country', 'client.contacts', 'client.country');
|
$invoice->load('user', 'invoice_items', 'documents', 'expenses', 'expenses.documents', 'account.country', 'client.contacts', 'client.country');
|
||||||
$invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date);
|
$invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date);
|
||||||
$invoice->due_date = Utils::fromSqlDate($invoice->due_date);
|
$invoice->due_date = Utils::fromSqlDate($invoice->due_date);
|
||||||
$invoice->is_pro = Auth::user()->isPro();
|
$invoice->features = [
|
||||||
|
'customize_invoice_design' => Auth::user()->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN),
|
||||||
|
'remove_created_by' => Auth::user()->hasFeature(FEATURE_REMOVE_CREATED_BY),
|
||||||
|
'invoice_settings' => Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS),
|
||||||
|
];
|
||||||
$invoice->is_quote = intval($invoice->is_quote);
|
$invoice->is_quote = intval($invoice->is_quote);
|
||||||
|
|
||||||
$activityTypeId = $invoice->is_quote ? ACTIVITY_TYPE_UPDATE_QUOTE : ACTIVITY_TYPE_UPDATE_INVOICE;
|
$activityTypeId = $invoice->is_quote ? ACTIVITY_TYPE_UPDATE_QUOTE : ACTIVITY_TYPE_UPDATE_INVOICE;
|
||||||
@ -591,7 +599,11 @@ class InvoiceController extends BaseController
|
|||||||
$backup = json_decode($activity->json_backup);
|
$backup = json_decode($activity->json_backup);
|
||||||
$backup->invoice_date = Utils::fromSqlDate($backup->invoice_date);
|
$backup->invoice_date = Utils::fromSqlDate($backup->invoice_date);
|
||||||
$backup->due_date = Utils::fromSqlDate($backup->due_date);
|
$backup->due_date = Utils::fromSqlDate($backup->due_date);
|
||||||
$backup->is_pro = Auth::user()->isPro();
|
$invoice->features = [
|
||||||
|
'customize_invoice_design' => Auth::user()->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN),
|
||||||
|
'remove_created_by' => Auth::user()->hasFeature(FEATURE_REMOVE_CREATED_BY),
|
||||||
|
'invoice_settings' => Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS),
|
||||||
|
];
|
||||||
$backup->is_quote = isset($backup->is_quote) && intval($backup->is_quote);
|
$backup->is_quote = isset($backup->is_quote) && intval($backup->is_quote);
|
||||||
$backup->account = $invoice->account->toArray();
|
$backup->account = $invoice->account->toArray();
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ class PaymentController extends BaseController
|
|||||||
'currencyId' => $client->getCurrencyId(),
|
'currencyId' => $client->getCurrencyId(),
|
||||||
'currencyCode' => $client->currency ? $client->currency->code : ($account->currency ? $account->currency->code : 'USD'),
|
'currencyCode' => $client->currency ? $client->currency->code : ($account->currency ? $account->currency->code : 'USD'),
|
||||||
'account' => $client->account,
|
'account' => $client->account,
|
||||||
'hideLogo' => $account->isWhiteLabel(),
|
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
||||||
'hideHeader' => $account->isNinjaAccount(),
|
'hideHeader' => $account->isNinjaAccount(),
|
||||||
'clientViewCSS' => $account->clientViewCSS(),
|
'clientViewCSS' => $account->clientViewCSS(),
|
||||||
'clientFontUrl' => $account->getFontsUrl(),
|
'clientFontUrl' => $account->getFontsUrl(),
|
||||||
|
@ -72,7 +72,11 @@ class PublicClientController extends BaseController
|
|||||||
|
|
||||||
$invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date);
|
$invoice->invoice_date = Utils::fromSqlDate($invoice->invoice_date);
|
||||||
$invoice->due_date = Utils::fromSqlDate($invoice->due_date);
|
$invoice->due_date = Utils::fromSqlDate($invoice->due_date);
|
||||||
$invoice->is_pro = $account->isPro();
|
$invoice->features = [
|
||||||
|
'customize_invoice_design' => $account->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN),
|
||||||
|
'remove_created_by' => $account->hasFeature(FEATURE_REMOVE_CREATED_BY),
|
||||||
|
'invoice_settings' => $account->hasFeature(FEATURE_INVOICE_SETTINGS),
|
||||||
|
];
|
||||||
$invoice->invoice_fonts = $account->getFontsData();
|
$invoice->invoice_fonts = $account->getFontsData();
|
||||||
|
|
||||||
if ($invoice->invoice_design_id == CUSTOM_DESIGN) {
|
if ($invoice->invoice_design_id == CUSTOM_DESIGN) {
|
||||||
@ -122,10 +126,10 @@ class PublicClientController extends BaseController
|
|||||||
'account' => $account,
|
'account' => $account,
|
||||||
'showApprove' => $showApprove,
|
'showApprove' => $showApprove,
|
||||||
'showBreadcrumbs' => false,
|
'showBreadcrumbs' => false,
|
||||||
'hideLogo' => $account->isWhiteLabel(),
|
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
||||||
'hideHeader' => $account->isNinjaAccount() || !$account->enable_client_portal,
|
'hideHeader' => $account->isNinjaAccount() || !$account->enable_client_portal,
|
||||||
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
||||||
'showDocuments' => $account->isPro(),
|
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
||||||
'clientViewCSS' => $account->clientViewCSS(),
|
'clientViewCSS' => $account->clientViewCSS(),
|
||||||
'clientFontUrl' => $account->getFontsUrl(),
|
'clientFontUrl' => $account->getFontsUrl(),
|
||||||
'invoice' => $invoice->hidePrivateFields(),
|
'invoice' => $invoice->hidePrivateFields(),
|
||||||
@ -140,7 +144,7 @@ class PublicClientController extends BaseController
|
|||||||
'phantomjs' => Input::has('phantomjs'),
|
'phantomjs' => Input::has('phantomjs'),
|
||||||
);
|
);
|
||||||
|
|
||||||
if($account->isPro() && $this->canCreateZip()){
|
if($account->hasFeature(FEATURE_DOCUMENTS) && $this->canCreateZip()){
|
||||||
$zipDocs = $this->getInvoiceZipDocuments($invoice, $size);
|
$zipDocs = $this->getInvoiceZipDocuments($invoice, $size);
|
||||||
|
|
||||||
if(count($zipDocs) > 1){
|
if(count($zipDocs) > 1){
|
||||||
@ -220,8 +224,8 @@ class PublicClientController extends BaseController
|
|||||||
'color' => $color,
|
'color' => $color,
|
||||||
'account' => $account,
|
'account' => $account,
|
||||||
'client' => $client,
|
'client' => $client,
|
||||||
'hideLogo' => $account->isWhiteLabel(),
|
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
||||||
'showDocuments' => $account->isPro(),
|
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
||||||
'clientViewCSS' => $account->clientViewCSS(),
|
'clientViewCSS' => $account->clientViewCSS(),
|
||||||
'clientFontUrl' => $account->getFontsUrl(),
|
'clientFontUrl' => $account->getFontsUrl(),
|
||||||
];
|
];
|
||||||
@ -273,9 +277,9 @@ class PublicClientController extends BaseController
|
|||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'color' => $color,
|
'color' => $color,
|
||||||
'hideLogo' => $account->isWhiteLabel(),
|
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
||||||
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
||||||
'showDocuments' => $account->isPro(),
|
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
||||||
'clientViewCSS' => $account->clientViewCSS(),
|
'clientViewCSS' => $account->clientViewCSS(),
|
||||||
'clientFontUrl' => $account->getFontsUrl(),
|
'clientFontUrl' => $account->getFontsUrl(),
|
||||||
'title' => trans('texts.invoices'),
|
'title' => trans('texts.invoices'),
|
||||||
@ -310,9 +314,9 @@ class PublicClientController extends BaseController
|
|||||||
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||||
$data = [
|
$data = [
|
||||||
'color' => $color,
|
'color' => $color,
|
||||||
'hideLogo' => $account->isWhiteLabel(),
|
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
||||||
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
||||||
'showDocuments' => $account->isPro(),
|
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
||||||
'clientViewCSS' => $account->clientViewCSS(),
|
'clientViewCSS' => $account->clientViewCSS(),
|
||||||
'clientFontUrl' => $account->getFontsUrl(),
|
'clientFontUrl' => $account->getFontsUrl(),
|
||||||
'entityType' => ENTITY_PAYMENT,
|
'entityType' => ENTITY_PAYMENT,
|
||||||
@ -354,9 +358,9 @@ class PublicClientController extends BaseController
|
|||||||
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||||
$data = [
|
$data = [
|
||||||
'color' => $color,
|
'color' => $color,
|
||||||
'hideLogo' => $account->isWhiteLabel(),
|
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
||||||
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
||||||
'showDocuments' => $account->isPro(),
|
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
||||||
'clientViewCSS' => $account->clientViewCSS(),
|
'clientViewCSS' => $account->clientViewCSS(),
|
||||||
'clientFontUrl' => $account->getFontsUrl(),
|
'clientFontUrl' => $account->getFontsUrl(),
|
||||||
'title' => trans('texts.quotes'),
|
'title' => trans('texts.quotes'),
|
||||||
@ -392,9 +396,9 @@ class PublicClientController extends BaseController
|
|||||||
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
$color = $account->primary_color ? $account->primary_color : '#0b4d78';
|
||||||
$data = [
|
$data = [
|
||||||
'color' => $color,
|
'color' => $color,
|
||||||
'hideLogo' => $account->isWhiteLabel(),
|
'hideLogo' => $account->hasFeature(FEATURE_WHITE_LABEL),
|
||||||
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
'hideDashboard' => !$account->enable_client_portal_dashboard,
|
||||||
'showDocuments' => $account->isPro(),
|
'showDocuments' => $account->hasFeature(FEATURE_DOCUMENTS),
|
||||||
'clientViewCSS' => $account->clientViewCSS(),
|
'clientViewCSS' => $account->clientViewCSS(),
|
||||||
'clientFontUrl' => $account->getFontsUrl(),
|
'clientFontUrl' => $account->getFontsUrl(),
|
||||||
'title' => trans('texts.documents'),
|
'title' => trans('texts.documents'),
|
||||||
|
@ -47,7 +47,7 @@ class QuoteController extends BaseController
|
|||||||
|
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
if (!Utils::isPro()) {
|
if (!Utils::hasFeature(FEATURE_QUOTES)) {
|
||||||
return Redirect::to('/invoices/create');
|
return Redirect::to('/invoices/create');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ class QuoteController extends BaseController
|
|||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Utils::isPro()) {
|
if (!Utils::hasFeature(FEATURE_QUOTES)) {
|
||||||
return Redirect::to('/invoices/create');
|
return Redirect::to('/invoices/create');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ class ReportController extends BaseController
|
|||||||
$message = '';
|
$message = '';
|
||||||
$fileName = storage_path().'/dataviz_sample.txt';
|
$fileName = storage_path().'/dataviz_sample.txt';
|
||||||
|
|
||||||
if (Auth::user()->account->isPro()) {
|
if (Auth::user()->account->hasFeature(FEATURE_REPORTS)) {
|
||||||
$account = Account::where('id', '=', Auth::user()->account->id)
|
$account = Account::where('id', '=', Auth::user()->account->id)
|
||||||
->with(['clients.invoices.invoice_items', 'clients.contacts'])
|
->with(['clients.invoices.invoice_items', 'clients.contacts'])
|
||||||
->first();
|
->first();
|
||||||
@ -99,7 +99,7 @@ class ReportController extends BaseController
|
|||||||
'title' => trans('texts.charts_and_reports'),
|
'title' => trans('texts.charts_and_reports'),
|
||||||
];
|
];
|
||||||
|
|
||||||
if (Auth::user()->account->isPro()) {
|
if (Auth::user()->account->hasFeature(FEATURE_REPORTS)) {
|
||||||
if ($enableReport) {
|
if ($enableReport) {
|
||||||
$isExport = $action == 'export';
|
$isExport = $action == 'export';
|
||||||
$params = array_merge($params, self::generateReport($reportType, $startDate, $endDate, $dateField, $isExport));
|
$params = array_merge($params, self::generateReport($reportType, $startDate, $endDate, $dateField, $isExport));
|
||||||
|
@ -93,7 +93,7 @@ class TokenController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function save($tokenPublicId = false)
|
public function save($tokenPublicId = false)
|
||||||
{
|
{
|
||||||
if (Auth::user()->account->isPro()) {
|
if (Auth::user()->account->hasFeature(FEATURE_API)) {
|
||||||
$rules = [
|
$rules = [
|
||||||
'name' => 'required',
|
'name' => 'required',
|
||||||
];
|
];
|
||||||
|
@ -164,7 +164,7 @@ class UserController extends BaseController
|
|||||||
*/
|
*/
|
||||||
public function save($userPublicId = false)
|
public function save($userPublicId = false)
|
||||||
{
|
{
|
||||||
if (Auth::user()->isPro() && ! Auth::user()->isTrial()) {
|
if (Auth::user()->hasFeature(FEATURE_USERS)) {
|
||||||
$rules = [
|
$rules = [
|
||||||
'first_name' => 'required',
|
'first_name' => 'required',
|
||||||
'last_name' => 'required',
|
'last_name' => 'required',
|
||||||
@ -190,8 +190,10 @@ class UserController extends BaseController
|
|||||||
$user->last_name = trim(Input::get('last_name'));
|
$user->last_name = trim(Input::get('last_name'));
|
||||||
$user->username = trim(Input::get('email'));
|
$user->username = trim(Input::get('email'));
|
||||||
$user->email = trim(Input::get('email'));
|
$user->email = trim(Input::get('email'));
|
||||||
$user->is_admin = boolval(Input::get('is_admin'));
|
if (Auth::user()->hasFeature(FEATURE_USER_PERMISSIONS)) {
|
||||||
$user->permissions = Input::get('permissions');
|
$user->is_admin = boolval(Input::get('is_admin'));
|
||||||
|
$user->permissions = Input::get('permissions');
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$lastUser = User::withTrashed()->where('account_id', '=', Auth::user()->account_id)
|
$lastUser = User::withTrashed()->where('account_id', '=', Auth::user()->account_id)
|
||||||
->orderBy('public_id', 'DESC')->first();
|
->orderBy('public_id', 'DESC')->first();
|
||||||
@ -202,12 +204,14 @@ class UserController extends BaseController
|
|||||||
$user->last_name = trim(Input::get('last_name'));
|
$user->last_name = trim(Input::get('last_name'));
|
||||||
$user->username = trim(Input::get('email'));
|
$user->username = trim(Input::get('email'));
|
||||||
$user->email = trim(Input::get('email'));
|
$user->email = trim(Input::get('email'));
|
||||||
$user->is_admin = boolval(Input::get('is_admin'));
|
|
||||||
$user->registered = true;
|
$user->registered = true;
|
||||||
$user->password = str_random(RANDOM_KEY_LENGTH);
|
$user->password = str_random(RANDOM_KEY_LENGTH);
|
||||||
$user->confirmation_code = str_random(RANDOM_KEY_LENGTH);
|
$user->confirmation_code = str_random(RANDOM_KEY_LENGTH);
|
||||||
$user->public_id = $lastUser->public_id + 1;
|
$user->public_id = $lastUser->public_id + 1;
|
||||||
$user->permissions = Input::get('permissions');
|
if (Auth::user()->hasFeature(FEATURE_USER_PERMISSIONS)) {
|
||||||
|
$user->is_admin = boolval(Input::get('is_admin'));
|
||||||
|
$user->permissions = Input::get('permissions');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$user->save();
|
$user->save();
|
||||||
@ -286,6 +290,9 @@ class UserController extends BaseController
|
|||||||
if (!Auth::user()->registered) {
|
if (!Auth::user()->registered) {
|
||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
$this->accountRepo->unlinkAccount($account);
|
$this->accountRepo->unlinkAccount($account);
|
||||||
|
if ($account->company->accounts->count() == 1) {
|
||||||
|
$account->company->forceDelete();
|
||||||
|
}
|
||||||
$account->forceDelete();
|
$account->forceDelete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,8 +175,8 @@ class VendorController extends BaseController
|
|||||||
$data = array_merge($data, self::getViewModel());
|
$data = array_merge($data, self::getViewModel());
|
||||||
|
|
||||||
if (Auth::user()->account->isNinjaAccount()) {
|
if (Auth::user()->account->isNinjaAccount()) {
|
||||||
if ($account = Account::whereId($vendor->public_id)->first()) {
|
if ($account = Account::whereId($client->public_id)->first()) {
|
||||||
$data['proPlanPaid'] = $account['pro_plan_paid'];
|
$data['planDetails'] = $account->getPlanDetails(false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class ApiCheck {
|
|||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Utils::isPro() && !$loggingIn) {
|
if (!Utils::hasFeature(FEATURE_API) && !$loggingIn) {
|
||||||
return Response::json('API requires pro plan', 403, $headers);
|
return Response::json('API requires pro plan', 403, $headers);
|
||||||
} else {
|
} else {
|
||||||
$key = Auth::check() ? Auth::user()->account->id : $request->getClientIp();
|
$key = Auth::check() ? Auth::user()->account->id : $request->getClientIp();
|
||||||
|
@ -42,7 +42,7 @@ class Authenticate {
|
|||||||
|
|
||||||
// Does this account require portal passwords?
|
// Does this account require portal passwords?
|
||||||
$account = Account::whereId($account_id)->first();
|
$account = Account::whereId($account_id)->first();
|
||||||
if($account && (!$account->enable_portal_password || !$account->isPro())){
|
if($account && (!$account->enable_portal_password || !$account->hasFeature(FEATURE_CLIENT_PORTAL_PASSWORD))){
|
||||||
$authenticated = true;
|
$authenticated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,9 +141,10 @@ class StartupCheck
|
|||||||
}
|
}
|
||||||
} elseif ($productId == PRODUCT_WHITE_LABEL) {
|
} elseif ($productId == PRODUCT_WHITE_LABEL) {
|
||||||
if ($data == 'valid') {
|
if ($data == 'valid') {
|
||||||
$account = Auth::user()->account;
|
$company = Auth::user()->account->company;
|
||||||
$account->pro_plan_paid = date_create()->format('Y-m-d');
|
$company->plan_paid = date_create()->format('Y-m-d');
|
||||||
$account->save();
|
$company->plan = PLAN_WHITE_LABEL;
|
||||||
|
$company->save();
|
||||||
|
|
||||||
Session::flash('message', trans('texts.bought_white_label'));
|
Session::flash('message', trans('texts.bought_white_label'));
|
||||||
}
|
}
|
||||||
|
@ -188,7 +188,8 @@ Route::group([
|
|||||||
Route::resource('users', 'UserController');
|
Route::resource('users', 'UserController');
|
||||||
Route::post('users/bulk', 'UserController@bulk');
|
Route::post('users/bulk', 'UserController@bulk');
|
||||||
Route::get('send_confirmation/{user_id}', 'UserController@sendConfirmation');
|
Route::get('send_confirmation/{user_id}', 'UserController@sendConfirmation');
|
||||||
Route::get('start_trial', 'AccountController@startTrial');
|
Route::get('start_trial/{plan}', 'AccountController@startTrial')
|
||||||
|
->where(['plan'=>'pro']);
|
||||||
Route::get('restore_user/{user_id}', 'UserController@restoreUser');
|
Route::get('restore_user/{user_id}', 'UserController@restoreUser');
|
||||||
Route::post('users/change_password', 'UserController@changePassword');
|
Route::post('users/change_password', 'UserController@changePassword');
|
||||||
Route::get('/switch_account/{user_id}', 'UserController@switchAccount');
|
Route::get('/switch_account/{user_id}', 'UserController@switchAccount');
|
||||||
@ -212,6 +213,7 @@ Route::group([
|
|||||||
Route::get('settings/charts_and_reports', 'ReportController@showReports');
|
Route::get('settings/charts_and_reports', 'ReportController@showReports');
|
||||||
Route::post('settings/charts_and_reports', 'ReportController@showReports');
|
Route::post('settings/charts_and_reports', 'ReportController@showReports');
|
||||||
|
|
||||||
|
Route::post('settings/change_plan', 'AccountController@changePlan');
|
||||||
Route::post('settings/cancel_account', 'AccountController@cancelAccount');
|
Route::post('settings/cancel_account', 'AccountController@cancelAccount');
|
||||||
Route::post('settings/company_details', 'AccountController@updateDetails');
|
Route::post('settings/company_details', 'AccountController@updateDetails');
|
||||||
Route::get('settings/{section?}', 'AccountController@showSection');
|
Route::get('settings/{section?}', 'AccountController@showSection');
|
||||||
@ -354,6 +356,7 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('ACCOUNT_LOCALIZATION', 'localization');
|
define('ACCOUNT_LOCALIZATION', 'localization');
|
||||||
define('ACCOUNT_NOTIFICATIONS', 'notifications');
|
define('ACCOUNT_NOTIFICATIONS', 'notifications');
|
||||||
define('ACCOUNT_IMPORT_EXPORT', 'import_export');
|
define('ACCOUNT_IMPORT_EXPORT', 'import_export');
|
||||||
|
define('ACCOUNT_MANAGEMENT', 'account_management');
|
||||||
define('ACCOUNT_PAYMENTS', 'online_payments');
|
define('ACCOUNT_PAYMENTS', 'online_payments');
|
||||||
define('ACCOUNT_BANKS', 'bank_accounts');
|
define('ACCOUNT_BANKS', 'bank_accounts');
|
||||||
define('ACCOUNT_IMPORT_EXPENSES', 'import_expenses');
|
define('ACCOUNT_IMPORT_EXPENSES', 'import_expenses');
|
||||||
@ -552,7 +555,6 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('NINJA_WEB_URL', 'https://www.invoiceninja.com');
|
define('NINJA_WEB_URL', 'https://www.invoiceninja.com');
|
||||||
define('NINJA_APP_URL', 'https://app.invoiceninja.com');
|
define('NINJA_APP_URL', 'https://app.invoiceninja.com');
|
||||||
define('NINJA_VERSION', '2.5.1.3');
|
define('NINJA_VERSION', '2.5.1.3');
|
||||||
define('NINJA_DATE', '2000-01-01');
|
|
||||||
|
|
||||||
define('SOCIAL_LINK_FACEBOOK', 'https://www.facebook.com/invoiceninja');
|
define('SOCIAL_LINK_FACEBOOK', 'https://www.facebook.com/invoiceninja');
|
||||||
define('SOCIAL_LINK_TWITTER', 'https://twitter.com/invoiceninja');
|
define('SOCIAL_LINK_TWITTER', 'https://twitter.com/invoiceninja');
|
||||||
@ -582,6 +584,10 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
define('SELF_HOST_AFFILIATE_KEY', '8S69AD');
|
define('SELF_HOST_AFFILIATE_KEY', '8S69AD');
|
||||||
|
|
||||||
define('PRO_PLAN_PRICE', 50);
|
define('PRO_PLAN_PRICE', 50);
|
||||||
|
define('PLAN_PRICE_PRO_MONTHLY', 5);
|
||||||
|
define('PLAN_PRICE_PRO_YEARLY', 50);
|
||||||
|
define('PLAN_PRICE_ENTERPRISE_MONTHLY', 10);
|
||||||
|
define('PLAN_PRICE_ENTERPRISE_YEARLY', 100);
|
||||||
define('WHITE_LABEL_PRICE', 20);
|
define('WHITE_LABEL_PRICE', 20);
|
||||||
define('INVOICE_DESIGNS_PRICE', 10);
|
define('INVOICE_DESIGNS_PRICE', 10);
|
||||||
|
|
||||||
@ -644,7 +650,46 @@ if (!defined('CONTACT_EMAIL')) {
|
|||||||
|
|
||||||
define('RESELLER_REVENUE_SHARE', 'A');
|
define('RESELLER_REVENUE_SHARE', 'A');
|
||||||
define('RESELLER_LIMITED_USERS', 'B');
|
define('RESELLER_LIMITED_USERS', 'B');
|
||||||
|
|
||||||
|
// These must be lowercase
|
||||||
|
define('PLAN_FREE', 'free');
|
||||||
|
define('PLAN_PRO', 'pro');
|
||||||
|
define('PLAN_ENTERPRISE', 'enterprise');
|
||||||
|
define('PLAN_WHITE_LABEL', 'white_label');
|
||||||
|
define('PLAN_TERM_MONTHLY', 'month');
|
||||||
|
define('PLAN_TERM_YEARLY', 'year');
|
||||||
|
|
||||||
|
// Pro
|
||||||
|
define('FEATURE_CUSTOMIZE_INVOICE_DESIGN', 'customize_invoice_design');
|
||||||
|
define('FEATURE_REMOVE_CREATED_BY', 'remove_created_by');
|
||||||
|
define('FEATURE_DIFFERENT_DESIGNS', 'different_designs');
|
||||||
|
define('FEATURE_EMAIL_TEMPLATES_REMINDERS', 'email_templates_reminders');
|
||||||
|
define('FEATURE_INVOICE_SETTINGS', 'invoice_settings');
|
||||||
|
define('FEATURE_CUSTOM_EMAILS', 'custom_emails');
|
||||||
|
define('FEATURE_PDF_ATTACHMENT', 'pdf_attachment');
|
||||||
|
define('FEATURE_MORE_INVOICE_DESIGNS', 'more_invoice_designs');
|
||||||
|
define('FEATURE_QUOTES', 'quotes');
|
||||||
|
define('FEATURE_REPORTS', 'reports');
|
||||||
|
define('FEATURE_API', 'api');
|
||||||
|
define('FEATURE_CLIENT_PORTAL_PASSWORD', 'client_portal_password');
|
||||||
|
define('FEATURE_CUSTOM_URL', 'custom_url');
|
||||||
|
|
||||||
|
define('FEATURE_MORE_CLIENTS', 'more_clients'); // No trial allowed
|
||||||
|
|
||||||
|
// Whitelabel
|
||||||
|
define('FEATURE_CLIENT_PORTAL_CSS', 'client_portal_css');
|
||||||
|
define('FEATURE_WHITE_LABEL', 'feature_white_label');
|
||||||
|
|
||||||
|
// Enterprise
|
||||||
|
define('FEATURE_DOCUMENTS', 'documents');
|
||||||
|
|
||||||
|
// No Trial allowed
|
||||||
|
define('FEATURE_USERS', 'users');// Grandfathered for old Pro users
|
||||||
|
define('FEATURE_USER_PERMISSIONS', 'user_permissions');
|
||||||
|
|
||||||
|
// Pro users who started paying on or before this date will be able to manage users
|
||||||
|
define('PRO_USERS_GRANDFATHER_DEADLINE', '2016-05-15');
|
||||||
|
|
||||||
$creditCards = [
|
$creditCards = [
|
||||||
1 => ['card' => 'images/credit_cards/Test-Visa-Icon.png', 'text' => 'Visa'],
|
1 => ['card' => 'images/credit_cards/Test-Visa-Icon.png', 'text' => 'Visa'],
|
||||||
2 => ['card' => 'images/credit_cards/Test-MasterCard-Icon.png', 'text' => 'Master Card'],
|
2 => ['card' => 'images/credit_cards/Test-MasterCard-Icon.png', 'text' => 'Master Card'],
|
||||||
|
@ -118,6 +118,11 @@ class Utils
|
|||||||
return Auth::check() && Auth::user()->isPro();
|
return Auth::check() && Auth::user()->isPro();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function hasFeature($feature)
|
||||||
|
{
|
||||||
|
return Auth::check() && Auth::user()->hasFeature($feature);
|
||||||
|
}
|
||||||
|
|
||||||
public static function isAdmin()
|
public static function isAdmin()
|
||||||
{
|
{
|
||||||
return Auth::check() && Auth::user()->is_admin;
|
return Auth::check() && Auth::user()->is_admin;
|
||||||
@ -440,7 +445,12 @@ class Utils
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$dateTime = new DateTime($date);
|
if ($date instanceof DateTime) {
|
||||||
|
$dateTime = $date;
|
||||||
|
} else {
|
||||||
|
$dateTime = new DateTime($date);
|
||||||
|
}
|
||||||
|
|
||||||
$timestamp = $dateTime->getTimestamp();
|
$timestamp = $dateTime->getTimestamp();
|
||||||
$format = Session::get(SESSION_DATE_FORMAT, DEFAULT_DATE_FORMAT);
|
$format = Session::get(SESSION_DATE_FORMAT, DEFAULT_DATE_FORMAT);
|
||||||
|
|
||||||
@ -961,38 +971,6 @@ class Utils
|
|||||||
return $entity1;
|
return $entity1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function withinPastYear($date)
|
|
||||||
{
|
|
||||||
if (!$date || $date == '0000-00-00') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$today = new DateTime('now');
|
|
||||||
$datePaid = DateTime::createFromFormat('Y-m-d', $date);
|
|
||||||
$interval = $today->diff($datePaid);
|
|
||||||
|
|
||||||
return $interval->y == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getInterval($date)
|
|
||||||
{
|
|
||||||
if (!$date || $date == '0000-00-00') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$today = new DateTime('now');
|
|
||||||
$datePaid = DateTime::createFromFormat('Y-m-d', $date);
|
|
||||||
|
|
||||||
return $today->diff($datePaid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function withinPastTwoWeeks($date)
|
|
||||||
{
|
|
||||||
$interval = Utils::getInterval($date);
|
|
||||||
|
|
||||||
return $interval && $interval->d <= 14;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function addHttp($url)
|
public static function addHttp($url)
|
||||||
{
|
{
|
||||||
if (!preg_match("~^(?:f|ht)tps?://~i", $url)) {
|
if (!preg_match("~^(?:f|ht)tps?://~i", $url)) {
|
||||||
|
@ -14,10 +14,11 @@ class InvoiceListener
|
|||||||
{
|
{
|
||||||
public function createdInvoice(InvoiceWasCreated $event)
|
public function createdInvoice(InvoiceWasCreated $event)
|
||||||
{
|
{
|
||||||
if (Utils::isPro()) {
|
if (Utils::hasFeature(FEATURE_DIFFERENT_DESIGNS)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure the account has the same design set as the invoice does
|
||||||
if (Auth::check()) {
|
if (Auth::check()) {
|
||||||
$invoice = $event->invoice;
|
$invoice = $event->invoice;
|
||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
|
@ -18,6 +18,17 @@ class Account extends Eloquent
|
|||||||
{
|
{
|
||||||
use PresentableTrait;
|
use PresentableTrait;
|
||||||
use SoftDeletes;
|
use SoftDeletes;
|
||||||
|
|
||||||
|
public static $plan_prices = array(
|
||||||
|
PLAN_PRO => array(
|
||||||
|
PLAN_TERM_MONTHLY => PLAN_PRICE_PRO_MONTHLY,
|
||||||
|
PLAN_TERM_YEARLY => PLAN_PRICE_PRO_YEARLY,
|
||||||
|
),
|
||||||
|
PLAN_ENTERPRISE => array(
|
||||||
|
PLAN_TERM_MONTHLY => PLAN_PRICE_ENTERPRISE_MONTHLY,
|
||||||
|
PLAN_TERM_YEARLY => PLAN_PRICE_ENTERPRISE_YEARLY,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
protected $presenter = 'App\Ninja\Presenters\AccountPresenter';
|
protected $presenter = 'App\Ninja\Presenters\AccountPresenter';
|
||||||
protected $dates = ['deleted_at'];
|
protected $dates = ['deleted_at'];
|
||||||
@ -57,6 +68,7 @@ class Account extends Eloquent
|
|||||||
ACCOUNT_PRODUCTS,
|
ACCOUNT_PRODUCTS,
|
||||||
ACCOUNT_NOTIFICATIONS,
|
ACCOUNT_NOTIFICATIONS,
|
||||||
ACCOUNT_IMPORT_EXPORT,
|
ACCOUNT_IMPORT_EXPORT,
|
||||||
|
ACCOUNT_MANAGEMENT,
|
||||||
];
|
];
|
||||||
|
|
||||||
public static $advancedSettings = [
|
public static $advancedSettings = [
|
||||||
@ -176,6 +188,11 @@ class Account extends Eloquent
|
|||||||
return $this->hasMany('App\Models\Payment','account_id','id')->withTrashed();
|
return $this->hasMany('App\Models\Payment','account_id','id')->withTrashed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function company()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\Company');
|
||||||
|
}
|
||||||
|
|
||||||
public function setIndustryIdAttribute($value)
|
public function setIndustryIdAttribute($value)
|
||||||
{
|
{
|
||||||
$this->attributes['industry_id'] = $value ?: null;
|
$this->attributes['industry_id'] = $value ?: null;
|
||||||
@ -516,7 +533,7 @@ class Account extends Eloquent
|
|||||||
|
|
||||||
public function getNumberPrefix($isQuote)
|
public function getNumberPrefix($isQuote)
|
||||||
{
|
{
|
||||||
if ( ! $this->isPro()) {
|
if ( ! $this->hasFeature(FEATURE_INVOICE_SETTINGS)) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -525,7 +542,7 @@ class Account extends Eloquent
|
|||||||
|
|
||||||
public function hasNumberPattern($isQuote)
|
public function hasNumberPattern($isQuote)
|
||||||
{
|
{
|
||||||
if ( ! $this->isPro()) {
|
if ( ! $this->hasFeature(FEATURE_INVOICE_SETTINGS)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -551,7 +568,7 @@ class Account extends Eloquent
|
|||||||
$replace = [date('Y')];
|
$replace = [date('Y')];
|
||||||
|
|
||||||
$search[] = '{$counter}';
|
$search[] = '{$counter}';
|
||||||
$replace[] = str_pad($this->getCounter($invoice->is_quote), 4, '0', STR_PAD_LEFT);
|
$replace[] = str_pad($this->getCounter($invoice->is_quote), $this->invoice_number_padding, '0', STR_PAD_LEFT);
|
||||||
|
|
||||||
if (strstr($pattern, '{$userId}')) {
|
if (strstr($pattern, '{$userId}')) {
|
||||||
$search[] = '{$userId}';
|
$search[] = '{$userId}';
|
||||||
@ -617,7 +634,7 @@ class Account extends Eloquent
|
|||||||
|
|
||||||
// confirm the invoice number isn't already taken
|
// confirm the invoice number isn't already taken
|
||||||
do {
|
do {
|
||||||
$number = $prefix . str_pad($counter, 4, '0', STR_PAD_LEFT);
|
$number = $prefix . str_pad($counter, $this->invoice_number_padding, '0', STR_PAD_LEFT);
|
||||||
$check = Invoice::scope(false, $this->id)->whereInvoiceNumber($number)->withTrashed()->first();
|
$check = Invoice::scope(false, $this->id)->whereInvoiceNumber($number)->withTrashed()->first();
|
||||||
$counter++;
|
$counter++;
|
||||||
$counterOffset++;
|
$counterOffset++;
|
||||||
@ -645,7 +662,7 @@ class Account extends Eloquent
|
|||||||
$default = $this->invoice_number_counter;
|
$default = $this->invoice_number_counter;
|
||||||
$actual = Utils::parseInt($invoice->invoice_number);
|
$actual = Utils::parseInt($invoice->invoice_number);
|
||||||
|
|
||||||
if ( ! $this->isPro() && $default != $actual) {
|
if ( ! $this->hasFeature(FEATURE_INVOICE_SETTINGS) && $default != $actual) {
|
||||||
$this->invoice_number_counter = $actual + 1;
|
$this->invoice_number_counter = $actual + 1;
|
||||||
} else {
|
} else {
|
||||||
$this->invoice_number_counter += 1;
|
$this->invoice_number_counter += 1;
|
||||||
@ -766,17 +783,80 @@ class Account extends Eloquent
|
|||||||
return $this->account_key === NINJA_ACCOUNT_KEY;
|
return $this->account_key === NINJA_ACCOUNT_KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function startTrial()
|
public function startTrial($plan)
|
||||||
{
|
{
|
||||||
if ( ! Utils::isNinja()) {
|
if ( ! Utils::isNinja()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->pro_plan_trial = date_create()->format('Y-m-d');
|
$this->company->trial_plan = $plan;
|
||||||
$this->save();
|
$this->company->trial_started = date_create()->format('Y-m-d');
|
||||||
|
$this->company->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isPro()
|
public function hasFeature($feature)
|
||||||
|
{
|
||||||
|
$planDetails = $this->getPlanDetails();
|
||||||
|
$selfHost = !Utils::isNinjaProd();
|
||||||
|
|
||||||
|
if (!$selfHost && function_exists('ninja_account_features')) {
|
||||||
|
$result = ninja_account_features($this, $feature);
|
||||||
|
|
||||||
|
if ($result != null) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($feature) {
|
||||||
|
// Pro
|
||||||
|
case FEATURE_CUSTOMIZE_INVOICE_DESIGN:
|
||||||
|
case FEATURE_REMOVE_CREATED_BY:
|
||||||
|
case FEATURE_DIFFERENT_DESIGNS:
|
||||||
|
case FEATURE_EMAIL_TEMPLATES_REMINDERS:
|
||||||
|
case FEATURE_INVOICE_SETTINGS:
|
||||||
|
case FEATURE_CUSTOM_EMAILS:
|
||||||
|
case FEATURE_PDF_ATTACHMENT:
|
||||||
|
case FEATURE_MORE_INVOICE_DESIGNS:
|
||||||
|
case FEATURE_QUOTES:
|
||||||
|
case FEATURE_REPORTS:
|
||||||
|
case FEATURE_API:
|
||||||
|
case FEATURE_CLIENT_PORTAL_PASSWORD:
|
||||||
|
case FEATURE_CUSTOM_URL:
|
||||||
|
return $selfHost || !empty($planDetails);
|
||||||
|
|
||||||
|
// Pro; No trial allowed, unless they're trialing enterprise with an active pro plan
|
||||||
|
case FEATURE_MORE_CLIENTS:
|
||||||
|
return $selfHost || !empty($planDetails) && (!$planDetails['trial'] || !empty($this->getPlanDetails(false, false)));
|
||||||
|
|
||||||
|
// White Label
|
||||||
|
case FEATURE_WHITE_LABEL:
|
||||||
|
if ($this->isNinjaAccount() || (!$selfHost && $planDetails && !$planDetails['expires'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Fallthrough
|
||||||
|
case FEATURE_CLIENT_PORTAL_CSS:
|
||||||
|
return !empty($planDetails);// A plan is required even for self-hosted users
|
||||||
|
|
||||||
|
// Enterprise; No Trial allowed; grandfathered for old pro users
|
||||||
|
case FEATURE_USERS:// Grandfathered for old Pro users
|
||||||
|
if($planDetails && $planDetails['trial']) {
|
||||||
|
// Do they have a non-trial plan?
|
||||||
|
$planDetails = $this->getPlanDetails(false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $selfHost || !empty($planDetails) && ($planDetails['plan'] == PLAN_ENTERPRISE || $planDetails['started'] <= date_create(PRO_USERS_GRANDFATHER_DEADLINE));
|
||||||
|
|
||||||
|
// Enterprise; No Trial allowed
|
||||||
|
case FEATURE_DOCUMENTS:
|
||||||
|
case FEATURE_USER_PERMISSIONS:
|
||||||
|
return $selfHost || !empty($planDetails) && $planDetails['plan'] == PLAN_ENTERPRISE && !$planDetails['trial'];
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isPro(&$plan_details = null)
|
||||||
{
|
{
|
||||||
if (!Utils::isNinjaProd()) {
|
if (!Utils::isNinjaProd()) {
|
||||||
return true;
|
return true;
|
||||||
@ -786,14 +866,113 @@ class Account extends Eloquent
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
$datePaid = $this->pro_plan_paid;
|
$plan_details = $this->getPlanDetails();
|
||||||
$trialStart = $this->pro_plan_trial;
|
|
||||||
|
return !empty($plan_details);
|
||||||
|
}
|
||||||
|
|
||||||
if ($datePaid == NINJA_DATE) {
|
public function isEnterprise(&$plan_details = null)
|
||||||
|
{
|
||||||
|
if (!Utils::isNinjaProd()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Utils::withinPastTwoWeeks($trialStart) || Utils::withinPastYear($datePaid);
|
if ($this->isNinjaAccount()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$plan_details = $this->getPlanDetails();
|
||||||
|
|
||||||
|
return $plan_details && $plan_details['plan'] == PLAN_ENTERPRISE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPlanDetails($include_inactive = false, $include_trial = true)
|
||||||
|
{
|
||||||
|
if (!$this->company) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$plan = $this->company->plan;
|
||||||
|
$trial_plan = $this->company->trial_plan;
|
||||||
|
|
||||||
|
if(!$plan && (!$trial_plan || !$include_trial)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$trial_active = false;
|
||||||
|
if ($trial_plan && $include_trial) {
|
||||||
|
$trial_started = DateTime::createFromFormat('Y-m-d', $this->company->trial_started);
|
||||||
|
$trial_expires = clone $trial_started;
|
||||||
|
$trial_expires->modify('+2 weeks');
|
||||||
|
|
||||||
|
if ($trial_expires >= date_create()) {
|
||||||
|
$trial_active = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$plan_active = false;
|
||||||
|
if ($plan) {
|
||||||
|
if ($this->company->plan_expires == null) {
|
||||||
|
$plan_active = true;
|
||||||
|
$plan_expires = false;
|
||||||
|
} else {
|
||||||
|
$plan_expires = DateTime::createFromFormat('Y-m-d', $this->company->plan_expires);
|
||||||
|
if ($plan_expires >= date_create()) {
|
||||||
|
$plan_active = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$include_inactive && !$plan_active && !$trial_active) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should we show plan details or trial details?
|
||||||
|
if (($plan && !$trial_plan) || !$include_trial) {
|
||||||
|
$use_plan = true;
|
||||||
|
} elseif (!$plan && $trial_plan) {
|
||||||
|
$use_plan = false;
|
||||||
|
} else {
|
||||||
|
// There is both a plan and a trial
|
||||||
|
if (!empty($plan_active) && empty($trial_active)) {
|
||||||
|
$use_plan = true;
|
||||||
|
} elseif (empty($plan_active) && !empty($trial_active)) {
|
||||||
|
$use_plan = false;
|
||||||
|
} elseif (!empty($plan_active) && !empty($trial_active)) {
|
||||||
|
// Both are active; use whichever is a better plan
|
||||||
|
if ($plan == PLAN_ENTERPRISE) {
|
||||||
|
$use_plan = true;
|
||||||
|
} elseif ($trial_plan == PLAN_ENTERPRISE) {
|
||||||
|
$use_plan = false;
|
||||||
|
} else {
|
||||||
|
// They're both the same; show the plan
|
||||||
|
$use_plan = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Neither are active; use whichever expired most recently
|
||||||
|
$use_plan = $plan_expires >= $trial_expires;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($use_plan) {
|
||||||
|
return array(
|
||||||
|
'trial' => false,
|
||||||
|
'plan' => $plan,
|
||||||
|
'started' => DateTime::createFromFormat('Y-m-d', $this->company->plan_started),
|
||||||
|
'expires' => $plan_expires,
|
||||||
|
'paid' => DateTime::createFromFormat('Y-m-d', $this->company->plan_paid),
|
||||||
|
'term' => $this->company->plan_term,
|
||||||
|
'active' => $plan_active,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return array(
|
||||||
|
'trial' => true,
|
||||||
|
'plan' => $trial_plan,
|
||||||
|
'started' => $trial_started,
|
||||||
|
'expires' => $trial_expires,
|
||||||
|
'active' => $trial_active,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isTrial()
|
public function isTrial()
|
||||||
@ -801,35 +980,54 @@ class Account extends Eloquent
|
|||||||
if (!Utils::isNinjaProd()) {
|
if (!Utils::isNinjaProd()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$plan_details = $this->getPlanDetails();
|
||||||
|
|
||||||
if ($this->pro_plan_paid && $this->pro_plan_paid != '0000-00-00') {
|
return $plan_details && $plan_details['trial'];
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Utils::withinPastTwoWeeks($this->pro_plan_trial);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isEligibleForTrial()
|
public function isEligibleForTrial($plan = null)
|
||||||
{
|
{
|
||||||
return ! $this->pro_plan_trial || $this->pro_plan_trial == '0000-00-00';
|
if (!$this->company->trial_plan) {
|
||||||
|
if ($plan) {
|
||||||
|
return $plan == PLAN_PRO || $plan == PLAN_ENTERPRISE;
|
||||||
|
} else {
|
||||||
|
return array(PLAN_PRO, PLAN_ENTERPRISE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->company->trial_plan == PLAN_PRO) {
|
||||||
|
if ($plan) {
|
||||||
|
return $plan != PLAN_PRO;
|
||||||
|
} else {
|
||||||
|
return array(PLAN_ENTERPRISE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCountTrialDaysLeft()
|
public function getCountTrialDaysLeft()
|
||||||
{
|
{
|
||||||
$interval = Utils::getInterval($this->pro_plan_trial);
|
$planDetails = $this->getPlanDetails(true);
|
||||||
|
|
||||||
return $interval ? 14 - $interval->d : 0;
|
if(!$planDetails || !$planDetails['trial']) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$today = new DateTime('now');
|
||||||
|
$interval = $today->diff($planDetails['expires']);
|
||||||
|
|
||||||
|
return $interval ? $interval->d : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRenewalDate()
|
public function getRenewalDate()
|
||||||
{
|
{
|
||||||
if ($this->pro_plan_paid && $this->pro_plan_paid != '0000-00-00') {
|
$planDetails = $this->getPlanDetails();
|
||||||
$date = DateTime::createFromFormat('Y-m-d', $this->pro_plan_paid);
|
|
||||||
$date->modify('+1 year');
|
if ($planDetails) {
|
||||||
|
$date = $planDetails['expires'];
|
||||||
$date = max($date, date_create());
|
$date = max($date, date_create());
|
||||||
} elseif ($this->isTrial()) {
|
|
||||||
$date = date_create();
|
|
||||||
$date->modify('+'.$this->getCountTrialDaysLeft().' day');
|
|
||||||
} else {
|
} else {
|
||||||
$date = date_create();
|
$date = date_create();
|
||||||
}
|
}
|
||||||
@ -837,23 +1035,6 @@ class Account extends Eloquent
|
|||||||
return $date->format('Y-m-d');
|
return $date->format('Y-m-d');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isWhiteLabel()
|
|
||||||
{
|
|
||||||
if ($this->isNinjaAccount()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Utils::isNinjaProd()) {
|
|
||||||
return self::isPro() && $this->pro_plan_paid != NINJA_DATE;
|
|
||||||
} else {
|
|
||||||
if ($this->pro_plan_paid == NINJA_DATE) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Utils::withinPastYear($this->pro_plan_paid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getLogoSize()
|
public function getLogoSize()
|
||||||
{
|
{
|
||||||
if(!$this->hasLogo()){
|
if(!$this->hasLogo()){
|
||||||
@ -930,7 +1111,7 @@ class Account extends Eloquent
|
|||||||
|
|
||||||
public function getEmailSubject($entityType)
|
public function getEmailSubject($entityType)
|
||||||
{
|
{
|
||||||
if ($this->isPro()) {
|
if ($this->hasFeature(FEATURE_CUSTOM_EMAILS)) {
|
||||||
$field = "email_subject_{$entityType}";
|
$field = "email_subject_{$entityType}";
|
||||||
$value = $this->$field;
|
$value = $this->$field;
|
||||||
|
|
||||||
@ -950,7 +1131,7 @@ class Account extends Eloquent
|
|||||||
|
|
||||||
$template = "<div>\$client,</div><br>";
|
$template = "<div>\$client,</div><br>";
|
||||||
|
|
||||||
if ($this->isPro() && $this->email_design_id != EMAIL_DESIGN_PLAIN) {
|
if ($this->hasFeature(FEATURE_CUSTOM_EMAILS) && $this->email_design_id != EMAIL_DESIGN_PLAIN) {
|
||||||
$template .= "<div>" . trans("texts.{$entityType}_message_button", ['amount' => '$amount']) . "</div><br>" .
|
$template .= "<div>" . trans("texts.{$entityType}_message_button", ['amount' => '$amount']) . "</div><br>" .
|
||||||
"<div style=\"text-align: center;\">\$viewButton</div><br>";
|
"<div style=\"text-align: center;\">\$viewButton</div><br>";
|
||||||
} else {
|
} else {
|
||||||
@ -969,7 +1150,7 @@ class Account extends Eloquent
|
|||||||
{
|
{
|
||||||
$template = false;
|
$template = false;
|
||||||
|
|
||||||
if ($this->isPro()) {
|
if ($this->hasFeature(FEATURE_CUSTOM_EMAILS)) {
|
||||||
$field = "email_template_{$entityType}";
|
$field = "email_template_{$entityType}";
|
||||||
$template = $this->$field;
|
$template = $this->$field;
|
||||||
}
|
}
|
||||||
@ -1065,7 +1246,7 @@ class Account extends Eloquent
|
|||||||
|
|
||||||
public function showCustomField($field, $entity = false)
|
public function showCustomField($field, $entity = false)
|
||||||
{
|
{
|
||||||
if ($this->isPro()) {
|
if ($this->hasFeature(FEATURE_INVOICE_SETTINGS)) {
|
||||||
return $this->$field ? true : false;
|
return $this->$field ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1081,18 +1262,18 @@ class Account extends Eloquent
|
|||||||
|
|
||||||
public function attatchPDF()
|
public function attatchPDF()
|
||||||
{
|
{
|
||||||
return $this->isPro() && $this->pdf_email_attachment;
|
return $this->hasFeature(FEATURE_PDF_ATTACHMENT) && $this->pdf_email_attachment;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getEmailDesignId()
|
public function getEmailDesignId()
|
||||||
{
|
{
|
||||||
return $this->isPro() ? $this->email_design_id : EMAIL_DESIGN_PLAIN;
|
return $this->hasFeature(FEATURE_CUSTOM_EMAILS) ? $this->email_design_id : EMAIL_DESIGN_PLAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function clientViewCSS(){
|
public function clientViewCSS(){
|
||||||
$css = null;
|
$css = '';
|
||||||
|
|
||||||
if ($this->isPro()) {
|
if ($this->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN)) {
|
||||||
$bodyFont = $this->getBodyFontCss();
|
$bodyFont = $this->getBodyFontCss();
|
||||||
$headerFont = $this->getHeaderFontCss();
|
$headerFont = $this->getHeaderFontCss();
|
||||||
|
|
||||||
@ -1100,27 +1281,15 @@ class Account extends Eloquent
|
|||||||
if ($headerFont != $bodyFont) {
|
if ($headerFont != $bodyFont) {
|
||||||
$css .= 'h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{'.$headerFont.'}';
|
$css .= 'h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{'.$headerFont.'}';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if ((Utils::isNinja() && $this->isPro()) || $this->isWhiteLabel()) {
|
if ($this->hasFeature(FEATURE_CLIENT_PORTAL_CSS)) {
|
||||||
// For self-hosted users, a white-label license is required for custom CSS
|
// For self-hosted users, a white-label license is required for custom CSS
|
||||||
$css .= $this->client_view_css;
|
$css .= $this->client_view_css;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $css;
|
return $css;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function hasLargeFont()
|
|
||||||
{
|
|
||||||
foreach (['chinese', 'japanese'] as $language) {
|
|
||||||
if (stripos($this->getBodyFontName(), $language) || stripos($this->getHeaderFontName(), $language)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFontsUrl($protocol = ''){
|
public function getFontsUrl($protocol = ''){
|
||||||
$bodyFont = $this->getHeaderFontId();
|
$bodyFont = $this->getHeaderFontId();
|
||||||
$headerFont = $this->getBodyFontId();
|
$headerFont = $this->getBodyFontId();
|
||||||
@ -1137,11 +1306,11 @@ class Account extends Eloquent
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getHeaderFontId() {
|
public function getHeaderFontId() {
|
||||||
return ($this->isPro() && $this->header_font_id) ? $this->header_font_id : DEFAULT_HEADER_FONT;
|
return ($this->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN) && $this->header_font_id) ? $this->header_font_id : DEFAULT_HEADER_FONT;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBodyFontId() {
|
public function getBodyFontId() {
|
||||||
return ($this->isPro() && $this->body_font_id) ? $this->body_font_id : DEFAULT_BODY_FONT;
|
return ($this->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN) && $this->body_font_id) ? $this->body_font_id : DEFAULT_BODY_FONT;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getHeaderFontName(){
|
public function getHeaderFontName(){
|
||||||
|
@ -155,7 +155,7 @@ class Client extends EntityModel
|
|||||||
$contact->send_invoice = true;
|
$contact->send_invoice = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Utils::isPro() || $this->account->enable_portal_password){
|
if (Utils::hasFeature(FEATURE_CLIENT_PORTAL_PASSWORD) && $this->account->enable_portal_password){
|
||||||
if(!empty($data['password']) && $data['password']!='-%unchanged%-'){
|
if(!empty($data['password']) && $data['password']!='-%unchanged%-'){
|
||||||
$contact->password = bcrypt($data['password']);
|
$contact->password = bcrypt($data['password']);
|
||||||
} else if(empty($data['password'])){
|
} else if(empty($data['password'])){
|
||||||
|
21
app/Models/Company.php
Normal file
21
app/Models/Company.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php namespace App\Models;
|
||||||
|
|
||||||
|
use Eloquent;
|
||||||
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
|
class Company extends Eloquent
|
||||||
|
{
|
||||||
|
use SoftDeletes;
|
||||||
|
|
||||||
|
protected $dates = ['deleted_at'];
|
||||||
|
|
||||||
|
public function accounts()
|
||||||
|
{
|
||||||
|
return $this->hasMany('App\Models\Account');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function payment()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\Payment');
|
||||||
|
}
|
||||||
|
}
|
@ -40,7 +40,7 @@ class Invitation extends EntityModel
|
|||||||
$url = SITE_URL;
|
$url = SITE_URL;
|
||||||
$iframe_url = $this->account->iframe_url;
|
$iframe_url = $this->account->iframe_url;
|
||||||
|
|
||||||
if ($this->account->isPro()) {
|
if ($this->account->hasFeature(FEATURE_CUSTOM_URL)) {
|
||||||
if ($iframe_url && !$forceOnsite) {
|
if ($iframe_url && !$forceOnsite) {
|
||||||
return "{$iframe_url}?{$this->invitation_key}";
|
return "{$iframe_url}?{$this->invitation_key}";
|
||||||
} elseif ($this->account->subdomain) {
|
} elseif ($this->account->subdomain) {
|
||||||
|
@ -409,7 +409,7 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
'invoice_design',
|
'invoice_design',
|
||||||
'invoice_design_id',
|
'invoice_design_id',
|
||||||
'invoice_fonts',
|
'invoice_fonts',
|
||||||
'is_pro',
|
'features',
|
||||||
'is_quote',
|
'is_quote',
|
||||||
'custom_value1',
|
'custom_value1',
|
||||||
'custom_value2',
|
'custom_value2',
|
||||||
@ -474,7 +474,8 @@ class Invoice extends EntityModel implements BalanceAffecting
|
|||||||
'custom_invoice_text_label2',
|
'custom_invoice_text_label2',
|
||||||
'custom_invoice_item_label1',
|
'custom_invoice_item_label1',
|
||||||
'custom_invoice_item_label2',
|
'custom_invoice_item_label2',
|
||||||
'invoice_embed_documents'
|
'invoice_embed_documents',
|
||||||
|
'page_size',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
foreach ($this->invoice_items as $invoiceItem) {
|
foreach ($this->invoice_items as $invoiceItem) {
|
||||||
|
@ -112,9 +112,14 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
|||||||
return $this->account->isPro();
|
return $this->account->isPro();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function hasFeature($feature)
|
||||||
|
{
|
||||||
|
return $this->account->hasFeature($feature);
|
||||||
|
}
|
||||||
|
|
||||||
public function isPaidPro()
|
public function isPaidPro()
|
||||||
{
|
{
|
||||||
return $this->isPro() && ! $this->isTrial();
|
return $this->isPro($accountDetails) && !$accountDetails['trial'];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isTrial()
|
public function isTrial()
|
||||||
@ -122,14 +127,14 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
|||||||
return $this->account->isTrial();
|
return $this->account->isTrial();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isEligibleForTrial()
|
public function isEligibleForTrial($plan = null)
|
||||||
{
|
{
|
||||||
return $this->account->isEligibleForTrial();
|
return $this->account->isEligibleForTrial($plan);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function maxInvoiceDesignId()
|
public function maxInvoiceDesignId()
|
||||||
{
|
{
|
||||||
return $this->isPro() ? 11 : (Utils::isNinja() ? COUNT_FREE_DESIGNS : COUNT_FREE_DESIGNS_SELF_HOST);
|
return $this->hasFeature(FEATURE_MORE_INVOICE_DESIGNS) ? 11 : (Utils::isNinja() ? COUNT_FREE_DESIGNS : COUNT_FREE_DESIGNS_SELF_HOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getDisplayName()
|
public function getDisplayName()
|
||||||
@ -173,7 +178,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
|||||||
|
|
||||||
public function getMaxNumClients()
|
public function getMaxNumClients()
|
||||||
{
|
{
|
||||||
if ($this->isPro() && ! $this->isTrial()) {
|
if ($this->hasFeature(FEATURE_MORE_CLIENTS)) {
|
||||||
return MAX_NUM_CLIENTS_PRO;
|
return MAX_NUM_CLIENTS_PRO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +191,7 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
|
|||||||
|
|
||||||
public function getMaxNumVendors()
|
public function getMaxNumVendors()
|
||||||
{
|
{
|
||||||
if ($this->isPro() && ! $this->isTrial()) {
|
if ($this->hasFeature(FEATURE_MORE_CLIENTS)) {
|
||||||
return MAX_NUM_VENDORS_PRO;
|
return MAX_NUM_VENDORS_PRO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ class ContactMailer extends Mailer
|
|||||||
'amount' => $invoice->getRequestedAmount()
|
'amount' => $invoice->getRequestedAmount()
|
||||||
];
|
];
|
||||||
|
|
||||||
if (empty($invitation->contact->password) && $account->isPro() && $account->enable_portal_password && $account->send_portal_password) {
|
if (empty($invitation->contact->password) && $account->hasFeature(FEATURE_CLIENT_PORTAL_PASSWORD) && $account->enable_portal_password && $account->send_portal_password) {
|
||||||
// The contact needs a password
|
// The contact needs a password
|
||||||
$variables['password'] = $password = $this->generatePassword();
|
$variables['password'] = $password = $this->generatePassword();
|
||||||
$invitation->contact->password = bcrypt($password);
|
$invitation->contact->password = bcrypt($password);
|
||||||
@ -291,7 +291,7 @@ class ContactMailer extends Mailer
|
|||||||
$passwordHTML = isset($data['password'])?'<p>'.trans('texts.password').': '.$data['password'].'<p>':false;
|
$passwordHTML = isset($data['password'])?'<p>'.trans('texts.password').': '.$data['password'].'<p>':false;
|
||||||
$documentsHTML = '';
|
$documentsHTML = '';
|
||||||
|
|
||||||
if($account->isPro() && $invoice->hasDocuments()){
|
if($account->hasFeature(FEATURE_DOCUMENTS) && $invoice->hasDocuments()){
|
||||||
$documentsHTML .= trans('texts.email_documents_header').'<ul>';
|
$documentsHTML .= trans('texts.email_documents_header').'<ul>';
|
||||||
foreach($invoice->documents as $document){
|
foreach($invoice->documents as $document){
|
||||||
$documentsHTML .= '<li><a href="'.HTML::entities($document->getClientUrl($invitation)).'">'.HTML::entities($document->name).'</a></li>';
|
$documentsHTML .= '<li><a href="'.HTML::entities($document->getClientUrl($invitation)).'">'.HTML::entities($document->name).'</a></li>';
|
||||||
|
@ -17,6 +17,7 @@ use App\Models\Client;
|
|||||||
use App\Models\Language;
|
use App\Models\Language;
|
||||||
use App\Models\Contact;
|
use App\Models\Contact;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
|
use App\Models\Company;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\UserAccount;
|
use App\Models\UserAccount;
|
||||||
use App\Models\AccountToken;
|
use App\Models\AccountToken;
|
||||||
@ -25,9 +26,13 @@ class AccountRepository
|
|||||||
{
|
{
|
||||||
public function create($firstName = '', $lastName = '', $email = '', $password = '')
|
public function create($firstName = '', $lastName = '', $email = '', $password = '')
|
||||||
{
|
{
|
||||||
|
$company = new Company();
|
||||||
|
$company->save();
|
||||||
|
|
||||||
$account = new Account();
|
$account = new Account();
|
||||||
$account->ip = Request::getClientIp();
|
$account->ip = Request::getClientIp();
|
||||||
$account->account_key = str_random(RANDOM_KEY_LENGTH);
|
$account->account_key = str_random(RANDOM_KEY_LENGTH);
|
||||||
|
$account->company_id = $company->id;
|
||||||
|
|
||||||
// Track referal code
|
// Track referal code
|
||||||
if ($referralCode = Session::get(SESSION_REFERRAL_CODE)) {
|
if ($referralCode = Session::get(SESSION_REFERRAL_CODE)) {
|
||||||
@ -205,21 +210,23 @@ class AccountRepository
|
|||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function enableProPlan()
|
public function enablePlan($plan = PLAN_PRO, $term = PLAN_TERM_MONTHLY, $credit = 0, $pending_monthly = false)
|
||||||
{
|
{
|
||||||
if (Auth::user()->isPro() && ! Auth::user()->isTrial()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$account = Auth::user()->account;
|
$account = Auth::user()->account;
|
||||||
$client = $this->getNinjaClient($account);
|
$client = $this->getNinjaClient($account);
|
||||||
$invitation = $this->createNinjaInvoice($client, $account);
|
$invitation = $this->createNinjaInvoice($client, $account, $plan, $term, $credit, $pending_monthly);
|
||||||
|
|
||||||
return $invitation;
|
return $invitation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function createNinjaInvoice($client, $clientAccount)
|
public function createNinjaInvoice($client, $clientAccount, $plan = PLAN_PRO, $term = PLAN_TERM_MONTHLY, $credit = 0, $pending_monthly = false)
|
||||||
{
|
{
|
||||||
|
if ($credit < 0) {
|
||||||
|
$credit = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$plan_cost = Account::$plan_prices[$plan][$term];
|
||||||
|
|
||||||
$account = $this->getNinjaAccount();
|
$account = $this->getNinjaAccount();
|
||||||
$lastInvoice = Invoice::withTrashed()->whereAccountId($account->id)->orderBy('public_id', 'DESC')->first();
|
$lastInvoice = Invoice::withTrashed()->whereAccountId($account->id)->orderBy('public_id', 'DESC')->first();
|
||||||
$publicId = $lastInvoice ? ($lastInvoice->public_id + 1) : 1;
|
$publicId = $lastInvoice ? ($lastInvoice->public_id + 1) : 1;
|
||||||
@ -230,19 +237,39 @@ class AccountRepository
|
|||||||
$invoice->client_id = $client->id;
|
$invoice->client_id = $client->id;
|
||||||
$invoice->invoice_number = $account->getNextInvoiceNumber($invoice);
|
$invoice->invoice_number = $account->getNextInvoiceNumber($invoice);
|
||||||
$invoice->invoice_date = $clientAccount->getRenewalDate();
|
$invoice->invoice_date = $clientAccount->getRenewalDate();
|
||||||
$invoice->amount = PRO_PLAN_PRICE;
|
$invoice->amount = $invoice->balance = $plan_cost - $credit;
|
||||||
$invoice->balance = PRO_PLAN_PRICE;
|
|
||||||
$invoice->save();
|
$invoice->save();
|
||||||
|
|
||||||
$item = new InvoiceItem();
|
if ($credit) {
|
||||||
$item->account_id = $account->id;
|
$credit_item = InvoiceItem::createNew($invoice);
|
||||||
$item->user_id = $account->users()->first()->id;
|
$credit_item->qty = 1;
|
||||||
$item->public_id = $publicId;
|
$credit_item->cost = -$credit;
|
||||||
|
$credit_item->notes = trans('texts.plan_credit_description');
|
||||||
|
$credit_item->product_key = trans('texts.plan_credit_product');
|
||||||
|
$invoice->invoice_items()->save($credit_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = InvoiceItem::createNew($invoice);
|
||||||
$item->qty = 1;
|
$item->qty = 1;
|
||||||
$item->cost = PRO_PLAN_PRICE;
|
$item->cost = $plan_cost;
|
||||||
$item->notes = trans('texts.pro_plan_description');
|
$item->notes = trans("texts.{$plan}_plan_{$term}_description");
|
||||||
$item->product_key = trans('texts.pro_plan_product');
|
|
||||||
|
// Don't change this without updating the regex in PaymentService->createPayment()
|
||||||
|
$item->product_key = 'Plan - '.ucfirst($plan).' ('.ucfirst($term).')';
|
||||||
$invoice->invoice_items()->save($item);
|
$invoice->invoice_items()->save($item);
|
||||||
|
|
||||||
|
if ($pending_monthly) {
|
||||||
|
$term_end = $term == PLAN_MONTHLY ? date_create('+1 month') : date_create('+1 year');
|
||||||
|
$pending_monthly_item = InvoiceItem::createNew($invoice);
|
||||||
|
$item->qty = 1;
|
||||||
|
$pending_monthly_item->cost = 0;
|
||||||
|
$pending_monthly_item->notes = trans("texts.plan_pending_monthly", array('date', Utils::dateToString($term_end)));
|
||||||
|
|
||||||
|
// Don't change this without updating the text in PaymentService->createPayment()
|
||||||
|
$pending_monthly_item->product_key = 'Pending Monthly';
|
||||||
|
$invoice->invoice_items()->save($pending_monthly_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$invitation = new Invitation();
|
$invitation = new Invitation();
|
||||||
$invitation->account_id = $account->id;
|
$invitation->account_id = $account->id;
|
||||||
@ -355,7 +382,7 @@ class AccountRepository
|
|||||||
$user->last_name = $lastName;
|
$user->last_name = $lastName;
|
||||||
$user->registered = true;
|
$user->registered = true;
|
||||||
|
|
||||||
$user->account->startTrial();
|
$user->account->startTrial(PLAN_PRO);
|
||||||
}
|
}
|
||||||
|
|
||||||
$user->oauth_provider_id = $providerId;
|
$user->oauth_provider_id = $providerId;
|
||||||
@ -471,10 +498,10 @@ class AccountRepository
|
|||||||
$item = new stdClass();
|
$item = new stdClass();
|
||||||
$item->id = $record->id;
|
$item->id = $record->id;
|
||||||
$item->user_id = $user->id;
|
$item->user_id = $user->id;
|
||||||
|
$item->public_id = $user->public_id;
|
||||||
$item->user_name = $user->getDisplayName();
|
$item->user_name = $user->getDisplayName();
|
||||||
$item->account_id = $user->account->id;
|
$item->account_id = $user->account->id;
|
||||||
$item->account_name = $user->account->getDisplayName();
|
$item->account_name = $user->account->getDisplayName();
|
||||||
$item->pro_plan_paid = $user->account->pro_plan_paid;
|
|
||||||
$item->logo_url = $user->account->hasLogo() ? $user->account->getLogoUrl() : null;
|
$item->logo_url = $user->account->hasLogo() ? $user->account->getLogoUrl() : null;
|
||||||
$data[] = $item;
|
$data[] = $item;
|
||||||
}
|
}
|
||||||
@ -487,43 +514,6 @@ class AccountRepository
|
|||||||
return self::prepareUsersData($record);
|
return self::prepareUsersData($record);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function syncAccounts($userId, $proPlanPaid) {
|
|
||||||
$users = self::loadAccounts($userId);
|
|
||||||
self::syncUserAccounts($users, $proPlanPaid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function syncUserAccounts($users, $proPlanPaid = false) {
|
|
||||||
if (!$users) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$proPlanPaid) {
|
|
||||||
foreach ($users as $user) {
|
|
||||||
if ($user->pro_plan_paid && $user->pro_plan_paid != '0000-00-00') {
|
|
||||||
$proPlanPaid = $user->pro_plan_paid;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$proPlanPaid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$accountIds = [];
|
|
||||||
foreach ($users as $user) {
|
|
||||||
if ($user->pro_plan_paid != $proPlanPaid) {
|
|
||||||
$accountIds[] = $user->account_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count($accountIds)) {
|
|
||||||
DB::table('accounts')
|
|
||||||
->whereIn('id', $accountIds)
|
|
||||||
->update(['pro_plan_paid' => $proPlanPaid]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function associateAccounts($userId1, $userId2) {
|
public function associateAccounts($userId1, $userId2) {
|
||||||
|
|
||||||
$record = self::findUserAccounts($userId1, $userId2);
|
$record = self::findUserAccounts($userId1, $userId2);
|
||||||
@ -542,8 +532,59 @@ class AccountRepository
|
|||||||
|
|
||||||
$record->save();
|
$record->save();
|
||||||
|
|
||||||
$users = self::prepareUsersData($record);
|
$users = $this->getUserAccounts($record);
|
||||||
self::syncUserAccounts($users);
|
|
||||||
|
// Pick the primary user
|
||||||
|
foreach ($users as $user) {
|
||||||
|
if (!$user->public_id) {
|
||||||
|
$useAsPrimary = false;
|
||||||
|
if(empty($primaryUser)) {
|
||||||
|
$useAsPrimary = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$planDetails = $user->account->getPlanDetails(false, false);
|
||||||
|
$planLevel = 0;
|
||||||
|
|
||||||
|
if ($planDetails) {
|
||||||
|
$planLevel = 1;
|
||||||
|
if ($planDetails['plan'] == PLAN_ENTERPRISE) {
|
||||||
|
$planLevel = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$useAsPrimary && (
|
||||||
|
$planLevel > $primaryUserPlanLevel
|
||||||
|
|| ($planLevel == $primaryUserPlanLevel && $planDetails['expires'] > $primaryUserPlanExpires)
|
||||||
|
)) {
|
||||||
|
$useAsPrimary = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($useAsPrimary) {
|
||||||
|
$primaryUser = $user;
|
||||||
|
$primaryUserPlanLevel = $planLevel;
|
||||||
|
if ($planDetails) {
|
||||||
|
$primaryUserPlanExpires = $planDetails['expires'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge other companies into the primary user's company
|
||||||
|
if (!empty($primaryUser)) {
|
||||||
|
foreach ($users as $user) {
|
||||||
|
if ($user == $primaryUser || $user->public_id) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->account->company_id != $primaryUser->account->company_id) {
|
||||||
|
foreach ($user->account->company->accounts as $account) {
|
||||||
|
$account->company_id = $primaryUser->account->company_id;
|
||||||
|
$account->save();
|
||||||
|
}
|
||||||
|
$user->account->company->forceDelete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $users;
|
return $users;
|
||||||
}
|
}
|
||||||
@ -563,6 +604,15 @@ class AccountRepository
|
|||||||
$userAccount->removeUserId($userId);
|
$userAccount->removeUserId($userId);
|
||||||
$userAccount->save();
|
$userAccount->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$user = User::whereId($userId)->first();
|
||||||
|
|
||||||
|
if (!$user->public_id && $user->account->company->accounts->count() > 1) {
|
||||||
|
$company = Company::create();
|
||||||
|
$company->save();
|
||||||
|
$user->account->company_id = $company->id;
|
||||||
|
$user->account->save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function findWithReminders()
|
public function findWithReminders()
|
||||||
|
@ -284,7 +284,14 @@ class InvoiceRepository extends BaseRepository
|
|||||||
$invoice->end_date = null;
|
$invoice->end_date = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$invoice->terms = (isset($data['terms']) && trim($data['terms'])) ? trim($data['terms']) : (!$publicId && $account->invoice_terms ? $account->invoice_terms : '');
|
if (isset($data['terms']) && trim($data['terms'])) {
|
||||||
|
$invoice->terms = trim($data['terms']);
|
||||||
|
} elseif ($isNew && $account->{"{$entityType}_terms"}) {
|
||||||
|
$invoice->terms = $account->{"{$entityType}_terms"};
|
||||||
|
} else {
|
||||||
|
$invoice->terms = '';
|
||||||
|
}
|
||||||
|
|
||||||
$invoice->invoice_footer = (isset($data['invoice_footer']) && trim($data['invoice_footer'])) ? trim($data['invoice_footer']) : (!$publicId && $account->invoice_footer ? $account->invoice_footer : '');
|
$invoice->invoice_footer = (isset($data['invoice_footer']) && trim($data['invoice_footer'])) ? trim($data['invoice_footer']) : (!$publicId && $account->invoice_footer ? $account->invoice_footer : '');
|
||||||
$invoice->public_notes = isset($data['public_notes']) ? trim($data['public_notes']) : null;
|
$invoice->public_notes = isset($data['public_notes']) ? trim($data['public_notes']) : null;
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ use App\Models\Account;
|
|||||||
|
|
||||||
class NinjaRepository
|
class NinjaRepository
|
||||||
{
|
{
|
||||||
public function updateProPlanPaid($clientPublicId, $proPlanPaid)
|
public function updatePlanDetails($clientPublicId, $data)
|
||||||
{
|
{
|
||||||
$account = Account::whereId($clientPublicId)->first();
|
$account = Account::whereId($clientPublicId)->first();
|
||||||
|
|
||||||
@ -12,7 +12,13 @@ class NinjaRepository
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$account->pro_plan_paid = $proPlanPaid;
|
$company = $account->company;
|
||||||
$account->save();
|
$company->plan = !empty($data['plan']) && $data['plan'] != PLAN_FREE?$data['plan']:null;
|
||||||
|
$company->plan_term = !empty($data['plan_term'])?$data['plan_term']:null;
|
||||||
|
$company->plan_paid = !empty($data['plan_paid'])?$data['plan_paid']:null;
|
||||||
|
$company->plan_started = !empty($data['plan_started'])?$data['plan_started']:null;
|
||||||
|
$company->plan_expires = !empty($data['plan_expires'])?$data['plan_expires']:null;
|
||||||
|
|
||||||
|
$company->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,31 +1,32 @@
|
|||||||
<?php namespace App\Ninja\Repositories;
|
<?php namespace App\Ninja\Repositories;
|
||||||
|
|
||||||
use DB;
|
use App\Models\Account;
|
||||||
use Utils;
|
use Utils;
|
||||||
|
|
||||||
class ReferralRepository
|
class ReferralRepository
|
||||||
{
|
{
|
||||||
public function getCounts($userId)
|
public function getCounts($userId)
|
||||||
{
|
{
|
||||||
$accounts = DB::table('accounts')
|
$accounts = Account::where('referral_user_id', $userId);
|
||||||
->where('referral_user_id', $userId)
|
|
||||||
->get(['id', 'pro_plan_paid']);
|
|
||||||
|
|
||||||
$counts = [
|
$counts = [
|
||||||
'free' => 0,
|
'free' => 0,
|
||||||
'pro' => 0
|
'pro' => 0,
|
||||||
|
'enterprise' => 0
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($accounts as $account) {
|
foreach ($accounts as $account) {
|
||||||
$counts['free']++;
|
$counts['free']++;
|
||||||
if (Utils::withinPastYear($account->pro_plan_paid)) {
|
$plan = $account->getPlanDetails(false, false);
|
||||||
|
|
||||||
|
if ($plan) {
|
||||||
$counts['pro']++;
|
$counts['pro']++;
|
||||||
|
if ($plan['plan'] == PLAN_ENTERPRISE) {
|
||||||
|
$counts['enterprise']++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $counts;
|
return $counts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -68,7 +68,7 @@ class AppServiceProvider extends ServiceProvider {
|
|||||||
if(!empty($items))$items[] = '<li class="divider"></li>';
|
if(!empty($items))$items[] = '<li class="divider"></li>';
|
||||||
$items[] = '<li><a href="'.URL::to('recurring_invoices').'">'.trans("texts.recurring_invoices").'</a></li>';
|
$items[] = '<li><a href="'.URL::to('recurring_invoices').'">'.trans("texts.recurring_invoices").'</a></li>';
|
||||||
if(Invoice::canCreate())$items[] = '<li><a href="'.URL::to('recurring_invoices/create').'">'.trans("texts.new_recurring_invoice").'</a></li>';
|
if(Invoice::canCreate())$items[] = '<li><a href="'.URL::to('recurring_invoices/create').'">'.trans("texts.new_recurring_invoice").'</a></li>';
|
||||||
if (Auth::user()->isPro()) {
|
if (Auth::user()->hasFeature(FEATURE_QUOTES)) {
|
||||||
$items[] = '<li class="divider"></li>';
|
$items[] = '<li class="divider"></li>';
|
||||||
$items[] = '<li><a href="'.URL::to('quotes').'">'.trans("texts.quotes").'</a></li>';
|
$items[] = '<li><a href="'.URL::to('quotes').'">'.trans("texts.quotes").'</a></li>';
|
||||||
if(Invoice::canCreate())$items[] = '<li><a href="'.URL::to('quotes/create').'">'.trans("texts.new_quote").'</a></li>';
|
if(Invoice::canCreate())$items[] = '<li><a href="'.URL::to('quotes/create').'">'.trans("texts.new_quote").'</a></li>';
|
||||||
|
@ -32,8 +32,8 @@ class ClientService extends BaseService
|
|||||||
|
|
||||||
public function save($data)
|
public function save($data)
|
||||||
{
|
{
|
||||||
if (Auth::user()->account->isNinjaAccount() && isset($data['pro_plan_paid'])) {
|
if (Auth::user()->account->isNinjaAccount() && isset($data['plan'])) {
|
||||||
$this->ninjaRepo->updateProPlanPaid($data['public_id'], $data['pro_plan_paid']);
|
$this->ninjaRepo->updatePlanDetails($data['public_id'], $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->clientRepo->save($data);
|
return $this->clientRepo->save($data);
|
||||||
@ -134,7 +134,7 @@ class ClientService extends BaseService
|
|||||||
return URL::to("quotes/create/{$model->public_id}");
|
return URL::to("quotes/create/{$model->public_id}");
|
||||||
},
|
},
|
||||||
function ($model) {
|
function ($model) {
|
||||||
return Auth::user()->isPro() && Invoice::canCreate();
|
return Auth::user()->hasFeature(FEATURE_QUOTES) && Invoice::canCreate();
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
@ -100,7 +100,7 @@ class InvoiceService extends BaseService
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($account->auto_convert_quote || ! $account->isPro()) {
|
if ($account->auto_convert_quote || ! $account->hasFeature(FEATURE_QUOTES)) {
|
||||||
$invoice = $this->convertQuote($quote, $invitation);
|
$invoice = $this->convertQuote($quote, $invitation);
|
||||||
|
|
||||||
event(new QuoteInvitationWasApproved($quote, $invoice, $invitation));
|
event(new QuoteInvitationWasApproved($quote, $invoice, $invitation));
|
||||||
|
@ -39,18 +39,7 @@ class PaymentService extends BaseService
|
|||||||
public function createGateway($accountGateway)
|
public function createGateway($accountGateway)
|
||||||
{
|
{
|
||||||
$gateway = Omnipay::create($accountGateway->gateway->provider);
|
$gateway = Omnipay::create($accountGateway->gateway->provider);
|
||||||
$config = $accountGateway->getConfig();
|
$gateway->initialize((array) $accountGateway->getConfig());
|
||||||
|
|
||||||
foreach ($config as $key => $val) {
|
|
||||||
if (!$val) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$function = "set".ucfirst($key);
|
|
||||||
if (method_exists($gateway, $function)) {
|
|
||||||
$gateway->$function($val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($accountGateway->isGateway(GATEWAY_DWOLLA)) {
|
if ($accountGateway->isGateway(GATEWAY_DWOLLA)) {
|
||||||
if ($gateway->getSandbox() && isset($_ENV['DWOLLA_SANDBOX_KEY']) && isset($_ENV['DWOLLA_SANSBOX_SECRET'])) {
|
if ($gateway->getSandbox() && isset($_ENV['DWOLLA_SANDBOX_KEY']) && isset($_ENV['DWOLLA_SANSBOX_SECRET'])) {
|
||||||
@ -216,17 +205,6 @@ class PaymentService extends BaseService
|
|||||||
{
|
{
|
||||||
$invoice = $invitation->invoice;
|
$invoice = $invitation->invoice;
|
||||||
|
|
||||||
// enable pro plan for hosted users
|
|
||||||
if ($invoice->account->account_key == NINJA_ACCOUNT_KEY && $invoice->amount == PRO_PLAN_PRICE) {
|
|
||||||
$account = Account::with('users')->find($invoice->client->public_id);
|
|
||||||
$account->pro_plan_paid = $account->getRenewalDate();
|
|
||||||
$account->save();
|
|
||||||
|
|
||||||
// sync pro accounts
|
|
||||||
$user = $account->users()->first();
|
|
||||||
$this->accountRepo->syncAccounts($user->id, $account->pro_plan_paid);
|
|
||||||
}
|
|
||||||
|
|
||||||
$payment = Payment::createNew($invitation);
|
$payment = Payment::createNew($invitation);
|
||||||
$payment->invitation_id = $invitation->id;
|
$payment->invitation_id = $invitation->id;
|
||||||
$payment->account_gateway_id = $accountGateway->id;
|
$payment->account_gateway_id = $accountGateway->id;
|
||||||
@ -236,13 +214,66 @@ class PaymentService extends BaseService
|
|||||||
$payment->contact_id = $invitation->contact_id;
|
$payment->contact_id = $invitation->contact_id;
|
||||||
$payment->transaction_reference = $ref;
|
$payment->transaction_reference = $ref;
|
||||||
$payment->payment_date = date_create()->format('Y-m-d');
|
$payment->payment_date = date_create()->format('Y-m-d');
|
||||||
|
|
||||||
if ($payerId) {
|
if ($payerId) {
|
||||||
$payment->payer_id = $payerId;
|
$payment->payer_id = $payerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
$payment->save();
|
$payment->save();
|
||||||
|
|
||||||
|
// enable pro plan for hosted users
|
||||||
|
if ($invoice->account->account_key == NINJA_ACCOUNT_KEY) {
|
||||||
|
foreach ($invoice->invoice_items as $invoice_item) {
|
||||||
|
// Hacky, but invoices don't have meta fields to allow us to store this easily
|
||||||
|
if (1 == preg_match('/^Plan - (.+) \((.+)\)$/', $invoice_item->product_key, $matches)) {
|
||||||
|
$plan = strtolower($matches[1]);
|
||||||
|
$term = strtolower($matches[2]);
|
||||||
|
} elseif ($invoice_item->product_key == 'Pending Monthly') {
|
||||||
|
$pending_monthly = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($plan)) {
|
||||||
|
$account = Account::with('users')->find($invoice->client->public_id);
|
||||||
|
|
||||||
|
if(
|
||||||
|
$account->company->plan != $plan
|
||||||
|
|| DateTime::createFromFormat('Y-m-d', $account->company->plan_expires) >= date_create('-7 days')
|
||||||
|
) {
|
||||||
|
// Either this is a different plan, or the subscription expired more than a week ago
|
||||||
|
// Reset any grandfathering
|
||||||
|
$account->company->plan_started = date_create()->format('Y-m-d');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
$account->company->plan == $plan
|
||||||
|
&& $account->company->plan_term == $term
|
||||||
|
&& DateTime::createFromFormat('Y-m-d', $account->company->plan_expires) >= date_create()
|
||||||
|
) {
|
||||||
|
// This is a renewal; mark it paid as of when this term expires
|
||||||
|
$account->company->plan_paid = $account->company->plan_expires;
|
||||||
|
} else {
|
||||||
|
$account->company->plan_paid = date_create()->format('Y-m-d');
|
||||||
|
}
|
||||||
|
|
||||||
|
$account->company->payment_id = $payment->id;
|
||||||
|
$account->company->plan = $plan;
|
||||||
|
$account->company->plan_term = $term;
|
||||||
|
$account->company->plan_expires = DateTime::createFromFormat('Y-m-d', $account->company->plan_paid)
|
||||||
|
->modify($term == PLAN_TERM_MONTHLY ? '+1 month' : '+1 year')->format('Y-m-d');
|
||||||
|
|
||||||
|
if (!empty($pending_monthly)) {
|
||||||
|
$account->company->pending_plan = $plan;
|
||||||
|
$account->company->pending_term = PLAN_TERM_MONTHLY;
|
||||||
|
} else {
|
||||||
|
$account->company->pending_plan = null;
|
||||||
|
$account->company->pending_term = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$account->company->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $payment;
|
return $payment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,8 +28,8 @@ class VendorService extends BaseService
|
|||||||
|
|
||||||
public function save($data)
|
public function save($data)
|
||||||
{
|
{
|
||||||
if (Auth::user()->account->isNinjaAccount() && isset($data['pro_plan_paid'])) {
|
if (Auth::user()->account->isNinjaAccount() && isset($data['plan'])) {
|
||||||
$this->ninjaRepo->updateProPlanPaid($data['public_id'], $data['pro_plan_paid']);
|
$this->ninjaRepo->updatePlanDetails($data['public_id'], $data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->vendorRepo->save($data);
|
return $this->vendorRepo->save($data);
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
"anahkiasen/former": "4.0.*@dev",
|
"anahkiasen/former": "4.0.*@dev",
|
||||||
"barryvdh/laravel-debugbar": "~2.0",
|
"barryvdh/laravel-debugbar": "~2.0",
|
||||||
"chumper/datatable": "dev-develop#04ef2bf",
|
"chumper/datatable": "dev-develop#04ef2bf",
|
||||||
"omnipay/omnipay": "~2.3.0",
|
"omnipay/omnipay": "~2.3",
|
||||||
"intervention/image": "dev-master",
|
"intervention/image": "dev-master",
|
||||||
"webpatser/laravel-countries": "dev-master",
|
"webpatser/laravel-countries": "dev-master",
|
||||||
"barryvdh/laravel-ide-helper": "dev-master",
|
"barryvdh/laravel-ide-helper": "dev-master",
|
||||||
|
8
composer.lock
generated
8
composer.lock
generated
@ -4,8 +4,8 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"hash": "2ab7ab9013e31d8a2f0dcf43b31beefa",
|
"hash": "cf82d2ddb25cb1a7d6b4867bcc8692b8",
|
||||||
"content-hash": "188fba7fcc31b702098d5417bc0e63e2",
|
"content-hash": "481a95753b873249aebceb99e7426421",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "agmscode/omnipay-agms",
|
"name": "agmscode/omnipay-agms",
|
||||||
@ -127,7 +127,7 @@
|
|||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/formers/former/zipball/d97f907741323b390f43954a90a227921ecc6b96",
|
"url": "https://api.github.com/repos/formers/former/zipball/78ae8c65b1f8134e2db1c9491c251c03638823ca",
|
||||||
"reference": "d97f907741323b390f43954a90a227921ecc6b96",
|
"reference": "d97f907741323b390f43954a90a227921ecc6b96",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
@ -4229,7 +4229,7 @@
|
|||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/thephpleague/omnipay-bitpay/zipball/cf813f1d5436a1d2f942d3df6666695d1e2b5280",
|
"url": "https://api.github.com/repos/thephpleague/omnipay-bitpay/zipball/9cadfb7955bd361d1a00ac8f0570aee4c05c6bb4",
|
||||||
"reference": "cf813f1d5436a1d2f942d3df6666695d1e2b5280",
|
"reference": "cf813f1d5436a1d2f942d3df6666695d1e2b5280",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
|
@ -63,6 +63,7 @@ class AddDocuments extends Migration {
|
|||||||
$table->dropColumn('logo_height');
|
$table->dropColumn('logo_height');
|
||||||
$table->dropColumn('logo_size');
|
$table->dropColumn('logo_size');
|
||||||
$table->dropColumn('invoice_embed_documents');
|
$table->dropColumn('invoice_embed_documents');
|
||||||
|
$table->dropColumn('document_email_attachment');
|
||||||
});
|
});
|
||||||
|
|
||||||
Schema::dropIfExists('documents');
|
Schema::dropIfExists('documents');
|
||||||
|
156
database/migrations/2016_04_16_103943_enterprise_plan.php
Normal file
156
database/migrations/2016_04_16_103943_enterprise_plan.php
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use App\Models\Company;
|
||||||
|
use App\Models\Account;
|
||||||
|
|
||||||
|
class EnterprisePlan extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up() {
|
||||||
|
|
||||||
|
Schema::create('companies', function($table)
|
||||||
|
{
|
||||||
|
$table->increments('id');
|
||||||
|
|
||||||
|
$table->enum('plan', array('pro', 'enterprise', 'white_label'))->nullable();
|
||||||
|
$table->enum('plan_term', array('month', 'year'))->nullable();
|
||||||
|
$table->date('plan_started')->nullable();
|
||||||
|
$table->date('plan_paid')->nullable();
|
||||||
|
$table->date('plan_expires')->nullable();
|
||||||
|
|
||||||
|
$table->unsignedInteger('payment_id')->nullable();
|
||||||
|
$table->foreign('payment_id')->references('id')->on('payments');
|
||||||
|
|
||||||
|
$table->date('trial_started')->nullable();
|
||||||
|
$table->enum('trial_plan', array('pro', 'enterprise'))->nullable();
|
||||||
|
|
||||||
|
$table->enum('pending_plan', array('pro', 'enterprise', 'free'))->nullable();
|
||||||
|
$table->enum('pending_term', array('month', 'year'))->nullable();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
$table->softDeletes();
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('accounts', function($table)
|
||||||
|
{
|
||||||
|
$table->unsignedInteger('company_id')->nullable();
|
||||||
|
$table->foreign('company_id')->references('id')->on('companies');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$single_account_ids = \DB::table('users')
|
||||||
|
->leftJoin('user_accounts', function ($join) {
|
||||||
|
$join->on('user_accounts.user_id1', '=', 'users.id');
|
||||||
|
$join->orOn('user_accounts.user_id2', '=', 'users.id');
|
||||||
|
$join->orOn('user_accounts.user_id3', '=', 'users.id');
|
||||||
|
$join->orOn('user_accounts.user_id4', '=', 'users.id');
|
||||||
|
$join->orOn('user_accounts.user_id5', '=', 'users.id');
|
||||||
|
})
|
||||||
|
->whereNull('user_accounts.id')
|
||||||
|
->where(function ($query) {
|
||||||
|
$query->whereNull('users.public_id');
|
||||||
|
$query->orWhere('users.public_id', '=', 0);
|
||||||
|
})
|
||||||
|
->lists('users.account_id');
|
||||||
|
|
||||||
|
$group_accounts = \DB::select(
|
||||||
|
'SELECT u1.account_id as account1, u2.account_id as account2, u3.account_id as account3, u4.account_id as account4, u5.account_id as account5 FROM `user_accounts`
|
||||||
|
LEFT JOIN users u1 ON (u1.public_id IS NULL OR u1.public_id = 0) AND user_accounts.user_id1 = u1.id
|
||||||
|
LEFT JOIN users u2 ON (u2.public_id IS NULL OR u2.public_id = 0) AND user_accounts.user_id2 = u2.id
|
||||||
|
LEFT JOIN users u3 ON (u3.public_id IS NULL OR u3.public_id = 0) AND user_accounts.user_id3 = u3.id
|
||||||
|
LEFT JOIN users u4 ON (u4.public_id IS NULL OR u4.public_id = 0) AND user_accounts.user_id4 = u4.id
|
||||||
|
LEFT JOIN users u5 ON (u5.public_id IS NULL OR u5.public_id = 0) AND user_accounts.user_id5 = u5.id');
|
||||||
|
|
||||||
|
foreach (Account::find($single_account_ids) as $account) {
|
||||||
|
$this->upAccounts($account);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($group_accounts as $group_account) {
|
||||||
|
$this->upAccounts(null, Account::find(get_object_vars($group_account)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Schema::table('accounts', function($table)
|
||||||
|
{
|
||||||
|
$table->dropColumn('pro_plan_paid');
|
||||||
|
$table->dropColumn('pro_plan_trial');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private function upAccounts($primaryAccount, $otherAccounts = array()) {
|
||||||
|
if(!$primaryAccount) {
|
||||||
|
$primaryAccount = $otherAccounts->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
$company = Company::create();
|
||||||
|
if ($primaryAccount->pro_plan_paid && $primaryAccount->pro_plan_paid != '0000-00-00') {
|
||||||
|
$company->plan = 'pro';
|
||||||
|
$company->plan_term = 'year';
|
||||||
|
$company->plan_started = $primaryAccount->pro_plan_paid;
|
||||||
|
$company->plan_paid = $primaryAccount->pro_plan_paid;
|
||||||
|
|
||||||
|
if (!Utils::isNinjaProd()) {
|
||||||
|
$company->plan = 'white_label';
|
||||||
|
$company->plan_term = null;
|
||||||
|
} elseif ($company->plan_paid != '2000-01-01'/* NINJA_DATE*/) {
|
||||||
|
$expires = DateTime::createFromFormat('Y-m-d', $primaryAccount->pro_plan_paid);
|
||||||
|
$expires->modify('+1 year');
|
||||||
|
$company->plan_expires = $expires->format('Y-m-d');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($primaryAccount->pro_plan_trial && $primaryAccount->pro_plan_trial != '0000-00-00') {
|
||||||
|
$company->trial_started = $primaryAccount->pro_plan_trial;
|
||||||
|
$company->trial_plan = 'pro';
|
||||||
|
}
|
||||||
|
|
||||||
|
$company->save();
|
||||||
|
|
||||||
|
$primaryAccount->company_id = $company->id;
|
||||||
|
$primaryAccount->save();
|
||||||
|
|
||||||
|
if (!empty($otherAccounts)) {
|
||||||
|
foreach ($otherAccounts as $account) {
|
||||||
|
if ($account && $account->id != $primaryAccount->id) {
|
||||||
|
$account->company_id = $company->id;
|
||||||
|
$account->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('accounts', function($table)
|
||||||
|
{
|
||||||
|
$table->date('pro_plan_paid')->nullable();
|
||||||
|
$table->date('pro_plan_trial')->nullable();
|
||||||
|
});
|
||||||
|
|
||||||
|
foreach (Company::all() as $company) {
|
||||||
|
foreach ($company->accounts as $account) {
|
||||||
|
$account->pro_plan_paid = $company->plan_paid;
|
||||||
|
$account->pro_plan_trial = $company->trial_started;
|
||||||
|
$account->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Schema::table('accounts', function($table)
|
||||||
|
{
|
||||||
|
$table->dropForeign('accounts_company_id_foreign');
|
||||||
|
$table->dropColumn('company_id');
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::dropIfExists('companies');
|
||||||
|
}
|
||||||
|
}
|
72
database/migrations/2016_04_18_174135_add_page_size.php
Normal file
72
database/migrations/2016_04_18_174135_add_page_size.php
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class AddPageSize extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('accounts', function ($table) {
|
||||||
|
$table->string('page_size')->default('A4');
|
||||||
|
$table->boolean('live_preview')->default(true);
|
||||||
|
$table->smallInteger('invoice_number_padding')->default(4);
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('fonts', function ($table) {
|
||||||
|
$table->dropColumn('is_early_access');
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('expense_categories', function($table)
|
||||||
|
{
|
||||||
|
$table->increments('id');
|
||||||
|
$table->unsignedInteger('user_id');
|
||||||
|
$table->unsignedInteger('account_id')->index();
|
||||||
|
$table->timestamps();
|
||||||
|
$table->softDeletes();
|
||||||
|
|
||||||
|
$table->string('name')->nullable();
|
||||||
|
|
||||||
|
$table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
|
||||||
|
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||||
|
|
||||||
|
$table->unsignedInteger('public_id')->index();
|
||||||
|
$table->unique( array('account_id','public_id') );
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('expenses', function ($table) {
|
||||||
|
$table->unsignedInteger('expense_category_id')->nullable()->index();
|
||||||
|
|
||||||
|
$table->foreign('expense_category_id')->references('id')->on('expense_categories')->onDelete('cascade');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('accounts', function ($table) {
|
||||||
|
$table->dropColumn('page_size');
|
||||||
|
$table->dropColumn('live_preview');
|
||||||
|
$table->dropColumn('invoice_number_padding');
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::table('fonts', function ($table) {
|
||||||
|
$table->boolean('is_early_access');
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::dropIfExists('expense_categories');
|
||||||
|
|
||||||
|
Schema::table('expenses', function ($table) {
|
||||||
|
$table->dropColumn('expense_category_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -246,7 +246,6 @@ class FontsSeeder extends Seeder
|
|||||||
|
|
||||||
foreach ($fonts as $font) {
|
foreach ($fonts as $font) {
|
||||||
if (!DB::table('fonts')->where('name', '=', $font['name'])->get()) {
|
if (!DB::table('fonts')->where('name', '=', $font['name'])->get()) {
|
||||||
$font['is_early_access'] = false;
|
|
||||||
Font::create($font);
|
Font::create($font);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use App\Models\Account;
|
use App\Models\Account;
|
||||||
|
use App\Models\Company;
|
||||||
use App\Models\Affiliate;
|
use App\Models\Affiliate;
|
||||||
|
|
||||||
class UserTableSeeder extends Seeder
|
class UserTableSeeder extends Seeder
|
||||||
@ -13,10 +14,13 @@ class UserTableSeeder extends Seeder
|
|||||||
|
|
||||||
Eloquent::unguard();
|
Eloquent::unguard();
|
||||||
|
|
||||||
|
$company = Company::create();
|
||||||
|
|
||||||
$account = Account::create([
|
$account = Account::create([
|
||||||
//'name' => 'Test Account',
|
//'name' => 'Test Account',
|
||||||
'account_key' => str_random(RANDOM_KEY_LENGTH),
|
'account_key' => str_random(RANDOM_KEY_LENGTH),
|
||||||
'timezone_id' => 1,
|
'timezone_id' => 1,
|
||||||
|
'company_id' => $company->id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
User::create([
|
User::create([
|
||||||
|
File diff suppressed because one or more lines are too long
@ -55,7 +55,7 @@ function GetPdfMake(invoice, javascript, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// determine whether or not to show the header/footer
|
// determine whether or not to show the header/footer
|
||||||
if (invoice.is_pro) {
|
if (invoice.features.customize_invoice_design) {
|
||||||
if (key === 'header') {
|
if (key === 'header') {
|
||||||
return function(page, pages) {
|
return function(page, pages) {
|
||||||
return page === 1 || invoice.account.all_pages_header == '1' ? val : '';
|
return page === 1 || invoice.account.all_pages_header == '1' ? val : '';
|
||||||
@ -86,7 +86,7 @@ function GetPdfMake(invoice, javascript, callback) {
|
|||||||
// Add ninja logo to the footer
|
// Add ninja logo to the footer
|
||||||
var dd = JSON.parse(javascript, jsonCallBack);
|
var dd = JSON.parse(javascript, jsonCallBack);
|
||||||
var designId = invoice.invoice_design_id;
|
var designId = invoice.invoice_design_id;
|
||||||
if (!invoice.is_pro) {
|
if (!invoice.features.remove_created_by) {
|
||||||
if (designId == NINJA.TEMPLATES.CLEAN || designId == NINJA.TEMPLATES.NORMAL) {
|
if (designId == NINJA.TEMPLATES.CLEAN || designId == NINJA.TEMPLATES.NORMAL) {
|
||||||
dd.footer.columns.push({image: logoImages.imageLogo1, alignment: 'right', width: 130, margin: [0, 0, 0, 0]})
|
dd.footer.columns.push({image: logoImages.imageLogo1, alignment: 'right', width: 130, margin: [0, 0, 0, 0]})
|
||||||
} else if (designId == NINJA.TEMPLATES.BOLD) {
|
} else if (designId == NINJA.TEMPLATES.BOLD) {
|
||||||
@ -96,7 +96,8 @@ function GetPdfMake(invoice, javascript, callback) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set page size
|
||||||
|
dd.pageSize = invoice.account.page_size;
|
||||||
|
|
||||||
pdfMake.fonts = {}
|
pdfMake.fonts = {}
|
||||||
fonts = window.invoiceFonts || invoice.invoice_fonts;
|
fonts = window.invoiceFonts || invoice.invoice_fonts;
|
||||||
@ -269,10 +270,10 @@ NINJA.invoiceColumns = function(invoice)
|
|||||||
|
|
||||||
columns.push("*")
|
columns.push("*")
|
||||||
|
|
||||||
if (invoice.is_pro && account.custom_invoice_item_label1) {
|
if (invoice.features.invoice_settings && account.custom_invoice_item_label1) {
|
||||||
columns.push("10%");
|
columns.push("10%");
|
||||||
}
|
}
|
||||||
if (invoice.is_pro && account.custom_invoice_item_label2) {
|
if (invoice.features.invoice_settings && account.custom_invoice_item_label2) {
|
||||||
columns.push("10%");
|
columns.push("10%");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,7 +293,7 @@ NINJA.invoiceColumns = function(invoice)
|
|||||||
|
|
||||||
NINJA.invoiceFooter = function(invoice)
|
NINJA.invoiceFooter = function(invoice)
|
||||||
{
|
{
|
||||||
if (!invoice.is_pro && invoice.invoice_design_id == 3) {
|
if (!invoice.features.invoice_settings && invoice.invoice_design_id == 3) {
|
||||||
return invoice.invoice_footer ? invoice.invoice_footer.substring(0, 200) : ' ';
|
return invoice.invoice_footer ? invoice.invoice_footer.substring(0, 200) : ' ';
|
||||||
} else {
|
} else {
|
||||||
return invoice.invoice_footer || ' ';
|
return invoice.invoice_footer || ' ';
|
||||||
@ -324,10 +325,10 @@ NINJA.invoiceLines = function(invoice) {
|
|||||||
|
|
||||||
grid[0].push({text: invoiceLabels.description, style: ['tableHeader', 'descriptionTableHeader']});
|
grid[0].push({text: invoiceLabels.description, style: ['tableHeader', 'descriptionTableHeader']});
|
||||||
|
|
||||||
if (invoice.is_pro && account.custom_invoice_item_label1) {
|
if (invoice.features.invoice_settings && account.custom_invoice_item_label1) {
|
||||||
grid[0].push({text: account.custom_invoice_item_label1, style: ['tableHeader', 'custom1TableHeader']});
|
grid[0].push({text: account.custom_invoice_item_label1, style: ['tableHeader', 'custom1TableHeader']});
|
||||||
}
|
}
|
||||||
if (invoice.is_pro && account.custom_invoice_item_label2) {
|
if (invoice.features.invoice_ettings && account.custom_invoice_item_label2) {
|
||||||
grid[0].push({text: account.custom_invoice_item_label2, style: ['tableHeader', 'custom2TableHeader']});
|
grid[0].push({text: account.custom_invoice_item_label2, style: ['tableHeader', 'custom2TableHeader']});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,10 +385,10 @@ NINJA.invoiceLines = function(invoice) {
|
|||||||
row.push({style:["productKey", rowStyle], text:productKey || ' '}); // product key can be blank when selecting from a datalist
|
row.push({style:["productKey", rowStyle], text:productKey || ' '}); // product key can be blank when selecting from a datalist
|
||||||
}
|
}
|
||||||
row.push({style:["notes", rowStyle], stack:[{text:notes || ' '}]});
|
row.push({style:["notes", rowStyle], stack:[{text:notes || ' '}]});
|
||||||
if (invoice.is_pro && account.custom_invoice_item_label1) {
|
if (invoice.features.invoice_settings && account.custom_invoice_item_label1) {
|
||||||
row.push({style:["customValue1", rowStyle], text:item.custom_value1 || ' '});
|
row.push({style:["customValue1", rowStyle], text:item.custom_value1 || ' '});
|
||||||
}
|
}
|
||||||
if (invoice.is_pro && account.custom_invoice_item_label2) {
|
if (invoice.features.invoice_settings && account.custom_invoice_item_label2) {
|
||||||
row.push({style:["customValue2", rowStyle], text:item.custom_value2 || ' '});
|
row.push({style:["customValue2", rowStyle], text:item.custom_value2 || ' '});
|
||||||
}
|
}
|
||||||
row.push({style:["cost", rowStyle], text:cost});
|
row.push({style:["cost", rowStyle], text:cost});
|
||||||
@ -554,7 +555,7 @@ NINJA.accountAddress = function(invoice) {
|
|||||||
{text: account.country ? account.country.name : ''},
|
{text: account.country ? account.country.name : ''},
|
||||||
];
|
];
|
||||||
|
|
||||||
if (invoice.is_pro) {
|
if (invoice.features.invoice_settings) {
|
||||||
data.push({text: invoice.account.custom_value1 ? invoice.account.custom_label1 + ' ' + invoice.account.custom_value1 : false});
|
data.push({text: invoice.account.custom_value1 ? invoice.account.custom_label1 + ' ' + invoice.account.custom_value1 : false});
|
||||||
data.push({text: invoice.account.custom_value2 ? invoice.account.custom_label2 + ' ' + invoice.account.custom_value2 : false});
|
data.push({text: invoice.account.custom_value2 ? invoice.account.custom_label2 + ' ' + invoice.account.custom_value2 : false});
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ $LANG = array(
|
|||||||
'company_details' => 'Company Details',
|
'company_details' => 'Company Details',
|
||||||
'online_payments' => 'Online Payments',
|
'online_payments' => 'Online Payments',
|
||||||
'notifications' => 'Email Notifications',
|
'notifications' => 'Email Notifications',
|
||||||
'import_export' => 'Import | Export | Cancel',
|
'import_export' => 'Import | Export',
|
||||||
'done' => 'Done',
|
'done' => 'Done',
|
||||||
'save' => 'Save',
|
'save' => 'Save',
|
||||||
'create' => 'Create',
|
'create' => 'Create',
|
||||||
@ -268,7 +268,6 @@ $LANG = array(
|
|||||||
'erase_data' => 'This will permanently erase your data.',
|
'erase_data' => 'This will permanently erase your data.',
|
||||||
'password' => 'Password',
|
'password' => 'Password',
|
||||||
'pro_plan_product' => 'Pro Plan',
|
'pro_plan_product' => 'Pro Plan',
|
||||||
'pro_plan_description' => 'One year enrollment in the Invoice Ninja Pro Plan.',
|
|
||||||
'pro_plan_success' => 'Thanks for choosing Invoice Ninja\'s Pro plan!<p/> <br/>
|
'pro_plan_success' => 'Thanks for choosing Invoice Ninja\'s Pro plan!<p/> <br/>
|
||||||
<b>Next Steps</b><p/>A payable invoice has been sent to the email
|
<b>Next Steps</b><p/>A payable invoice has been sent to the email
|
||||||
address associated with your account. To unlock all of the awesome
|
address associated with your account. To unlock all of the awesome
|
||||||
@ -368,7 +367,7 @@ $LANG = array(
|
|||||||
'confirm_email_invoice' => 'Are you sure you want to email this invoice?',
|
'confirm_email_invoice' => 'Are you sure you want to email this invoice?',
|
||||||
'confirm_email_quote' => 'Are you sure you want to email this quote?',
|
'confirm_email_quote' => 'Are you sure you want to email this quote?',
|
||||||
'confirm_recurring_email_invoice' => 'Are you sure you want this invoice emailed?',
|
'confirm_recurring_email_invoice' => 'Are you sure you want this invoice emailed?',
|
||||||
'cancel_account' => 'Cancel Account',
|
'cancel_account' => 'Delete Account',
|
||||||
'cancel_account_message' => 'Warning: This will permanently erase all of your data, there is no undo.',
|
'cancel_account_message' => 'Warning: This will permanently erase all of your data, there is no undo.',
|
||||||
'go_back' => 'Go Back',
|
'go_back' => 'Go Back',
|
||||||
'data_visualizations' => 'Data Visualizations',
|
'data_visualizations' => 'Data Visualizations',
|
||||||
@ -976,9 +975,9 @@ $LANG = array(
|
|||||||
'expense_error_mismatch_currencies' => 'The client\'s currency does not match the expense currency.',
|
'expense_error_mismatch_currencies' => 'The client\'s currency does not match the expense currency.',
|
||||||
'trello_roadmap' => 'Trello Roadmap',
|
'trello_roadmap' => 'Trello Roadmap',
|
||||||
'header_footer' => 'Header/Footer',
|
'header_footer' => 'Header/Footer',
|
||||||
'first_page' => 'first page',
|
'first_page' => 'First page',
|
||||||
'all_pages' => 'all pages',
|
'all_pages' => 'All pages',
|
||||||
'last_page' => 'last page',
|
'last_page' => 'Last page',
|
||||||
'all_pages_header' => 'Show header on',
|
'all_pages_header' => 'Show header on',
|
||||||
'all_pages_footer' => 'Show footer on',
|
'all_pages_footer' => 'Show footer on',
|
||||||
'invoice_currency' => 'Invoice Currency',
|
'invoice_currency' => 'Invoice Currency',
|
||||||
@ -1126,6 +1125,57 @@ $LANG = array(
|
|||||||
'enable_client_portal_help' => 'Show/hide the client portal.',
|
'enable_client_portal_help' => 'Show/hide the client portal.',
|
||||||
'enable_client_portal_dashboard' => 'Dashboard',
|
'enable_client_portal_dashboard' => 'Dashboard',
|
||||||
'enable_client_portal_dashboard_help' => 'Show/hide the dashboard page in the client portal.',
|
'enable_client_portal_dashboard_help' => 'Show/hide the dashboard page in the client portal.',
|
||||||
|
|
||||||
|
// Plans
|
||||||
|
'account_management' => 'Account Management',
|
||||||
|
'plan_status' => 'Plan Status',
|
||||||
|
|
||||||
|
'plan_upgrade' => 'Upgrade',
|
||||||
|
'plan_change' => 'Change Plan',
|
||||||
|
'pending_change_to' => 'Changes To',
|
||||||
|
'plan_changes_to' => ':plan on :date',
|
||||||
|
'plan_term_changes_to' => ':plan (:term) on :date',
|
||||||
|
'cancel_plan_change' => 'Cancel Change',
|
||||||
|
'plan' => 'Plan',
|
||||||
|
'expires' => 'Expires',
|
||||||
|
'renews' => 'Renews',
|
||||||
|
'plan_expired' => ':plan Plan Expired',
|
||||||
|
'trial_expired' => ':plan Plan Trial Ended',
|
||||||
|
'never' => 'Never',
|
||||||
|
'plan_free' => 'Free',
|
||||||
|
'plan_pro' => 'Pro',
|
||||||
|
'plan_enterprise' => 'Enterprise',
|
||||||
|
'plan_white_label' => 'Self Hosted (White labeled)',
|
||||||
|
'plan_free_self_hosted' => 'Self Hosted (Free)',
|
||||||
|
'plan_trial' => 'Trial',
|
||||||
|
'plan_term' => 'Term',
|
||||||
|
'plan_term_monthly' => 'Monthly',
|
||||||
|
'plan_term_yearly' => 'Yearly',
|
||||||
|
'plan_term_month' => 'Month',
|
||||||
|
'plan_term_year' => 'Year',
|
||||||
|
'plan_price_monthly' => '$:price/Month',
|
||||||
|
'plan_price_yearly' => '$:price/Year',
|
||||||
|
'updated_plan' => 'Updated plan settings',
|
||||||
|
'plan_paid' => 'Term Started',
|
||||||
|
'plan_started' => 'Plan Started',
|
||||||
|
'plan_expires' => 'Plan Expires',
|
||||||
|
|
||||||
|
'white_label_button' => 'White Label',
|
||||||
|
|
||||||
|
'pro_plan_year_description' => 'One year enrollment in the Invoice Ninja Pro Plan.',
|
||||||
|
'pro_plan_month_description' => 'One month enrollment in the Invoice Ninja Pro Plan.',
|
||||||
|
'enterprise_plan_product' => 'Enterprise Plan',
|
||||||
|
'enterprise_plan_year_description' => 'One year enrollment in the Invoice Ninja Enterprise Plan.',
|
||||||
|
'enterprise_plan_month_description' => 'One month enrollment in the Invoice Ninja Enterprise Plan.',
|
||||||
|
'plan_credit_product' => 'Credit',
|
||||||
|
'plan_credit_description' => 'Credit for unused time',
|
||||||
|
'plan_pending_monthly' => 'Will switch to monthly on :date',
|
||||||
|
'plan_refunded' => 'A refund has been issued.',
|
||||||
|
|
||||||
|
'live_preview' => 'Live Preview',
|
||||||
|
'page_size' => 'Page Size',
|
||||||
|
'live_preview_disabled' => 'Live preview has been disabled to support selected font',
|
||||||
|
'invoice_number_padding' => 'Padding',
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -929,267 +929,264 @@ return array(
|
|||||||
|
|
||||||
'client_portal' => 'Portal do Cliente',
|
'client_portal' => 'Portal do Cliente',
|
||||||
'admin' => 'Admin',
|
'admin' => 'Admin',
|
||||||
'disabled' => 'Disabilitado',
|
'disabled' => 'Desabilitado',
|
||||||
'show_archived_users' => 'Mostrar usuários arquivados',
|
'show_archived_users' => 'Mostrar usuários arquivados',
|
||||||
'notes' => 'Observações',
|
'notes' => 'Observações',
|
||||||
'invoice_will_create' => 'cliente será criado',
|
'invoice_will_create' => 'cliente será criado',
|
||||||
'invoices_will_create' => 'faturas serão criadas',
|
'invoices_will_create' => 'faturas serão criadas',
|
||||||
'failed_to_import' => 'A importação dos seguintes registros falhou',
|
'failed_to_import' => 'A importação dos seguintes registros falhou',
|
||||||
|
|
||||||
'publishable_key' => 'Publishable Key',
|
'publishable_key' => 'Chave Publicável',
|
||||||
'secret_key' => 'Secret Key',
|
'secret_key' => 'Chave Secreta',
|
||||||
'missing_publishable_key' => 'Set your Stripe publishable key for an improved checkout process',
|
'missing_publishable_key' => 'Defina o sua chave publicável do Stripe para um processo de pagamento melhorado',
|
||||||
|
|
||||||
'email_design' => 'Email Design',
|
'email_design' => 'Template de E-mail',
|
||||||
'due_by' => 'Due by :date',
|
'due_by' => 'Vencido em :date',
|
||||||
'enable_email_markup' => 'Enable Markup',
|
'enable_email_markup' => 'Habilitar Marcação',
|
||||||
'enable_email_markup_help' => 'Make it easier for your clients to pay you by adding schema.org markup to your emails.',
|
'enable_email_markup_help' => 'Tornar mais fácil para os seus clientes efetuarem seus pagamentos, acrescentando marcação schema.org a seus e-mails.',
|
||||||
'template_help_title' => 'Templates Help',
|
'template_help_title' => 'Ajuda de Templates',
|
||||||
'template_help_1' => 'Available variables:',
|
'template_help_1' => 'Variáveis disponíveis:',
|
||||||
'email_design_id' => 'Email Style',
|
'email_design_id' => 'Estilo de e-mails',
|
||||||
'email_design_help' => 'Make your emails look more professional with HTML layouts',
|
'email_design_help' => 'Deixe seus e-mails mais profissionais com layouts HTML',
|
||||||
'plain' => 'Plain',
|
'plain' => 'Plano',
|
||||||
'light' => 'Light',
|
'light' => 'Claro',
|
||||||
'dark' => 'Dark',
|
'dark' => 'Escuro',
|
||||||
|
|
||||||
'industry_help' => 'Used to provide comparisons against the averages of companies of similar size and industry.',
|
'industry_help' => 'Usado para fornecer comparações contra as médias das empresas de tamanho e indústria similar.',
|
||||||
'subdomain_help' => 'Customize the invoice link subdomain or display the invoice on your own website.',
|
'subdomain_help' => 'Personalizar o link da fatura ou exibir a fatura em seu próprio site.',
|
||||||
'invoice_number_help' => 'Specify a prefix or use a custom pattern to dynamically set the invoice number.',
|
'invoice_number_help' => 'Especifique um prefixo ou usar um padrão personalizado para definir dinamicamente o número da fatura.',
|
||||||
'quote_number_help' => 'Specify a prefix or use a custom pattern to dynamically set the quote number.',
|
'quote_number_help' => 'Especifique um prefixo ou usar um padrão personalizado para definir dinamicamente o número do orçamento.',
|
||||||
'custom_client_fields_helps' => 'Add a text input to the client create/edit page and display the label and value on the PDF.',
|
'custom_client_fields_helps' => 'Adicionar uma entrada de texto na página Criar/Editar Cliente e exibir no PDF.',
|
||||||
'custom_account_fields_helps' => 'Add a label and value to the company details section of the PDF.',
|
'custom_account_fields_helps' => 'Adicionar um rótulo e um valor para a seção detalhes da empresa do PDF.',
|
||||||
'custom_invoice_fields_helps' => 'Add a text input to the invoice create/edit page and display the label and value on the PDF.',
|
'custom_invoice_fields_helps' => 'Adicionar uma entrada de texto na página Criar/Editar Fatura e exibir no PDF.',
|
||||||
'custom_invoice_charges_helps' => 'Add a text input to the invoice create/edit page and include the charge in the invoice subtotals.',
|
'custom_invoice_charges_helps' => 'Adicionar uma entrada de texto na página Criar/Editar Fatura e incluir nos subtotais da fatura.',
|
||||||
'color_help' => 'Note: the primary color is also used in the client portal and custom email designs.',
|
'color_help' => 'Nota: A cor primária também é utilizada nos projetos do portal do cliente e-mail personalizado.',
|
||||||
|
|
||||||
'token_expired' => 'Validation token was expired. Please try again.',
|
'token_expired' => 'Token de acesso expirado. Tente novamente!',
|
||||||
'invoice_link' => 'Invoice Link',
|
'invoice_link' => 'Link da Fatura',
|
||||||
'button_confirmation_message' => 'Click to confirm your email address.',
|
'button_confirmation_message' => 'Clique para confirmar seu endereço de e-mail.',
|
||||||
'confirm' => 'Confirm',
|
'confirm' => 'Confirmar',
|
||||||
'email_preferences' => 'Email Preferences',
|
'email_preferences' => 'Preferências de E-mails',
|
||||||
'created_invoices' => 'Successfully created :count invoice(s)',
|
'created_invoices' => ':count fatura(s) criadas com sucesso',
|
||||||
'next_invoice_number' => 'The next invoice number is :number.',
|
'next_invoice_number' => 'O número da próxima fatura será :number.',
|
||||||
'next_quote_number' => 'The next quote number is :number.',
|
'next_quote_number' => 'O número do próximo orçamento será :number.',
|
||||||
|
|
||||||
'days_before' => 'days before',
|
'days_before' => 'dias antes',
|
||||||
'days_after' => 'days after',
|
'days_after' => 'dias depois',
|
||||||
'field_due_date' => 'due date',
|
'field_due_date' => 'data de vencimento',
|
||||||
'field_invoice_date' => 'invoice date',
|
'field_invoice_date' => 'data da fatura',
|
||||||
'schedule' => 'Schedule',
|
'schedule' => 'Agendamento',
|
||||||
'email_designs' => 'Email Designs',
|
'email_designs' => 'Design de E-mails',
|
||||||
'assigned_when_sent' => 'Assigned when sent',
|
'assigned_when_sent' => 'Assinar quando enviar',
|
||||||
|
|
||||||
'white_label_custom_css' => ':link for $'.WHITE_LABEL_PRICE.' to enable custom styling and help support our project.',
|
'white_label_custom_css' => ':link apenas $'.WHITE_LABEL_PRICE.' para permitir um estilo personalizado e apoiar o nosso projecto.',
|
||||||
'white_label_purchase_link' => 'Purchase a white label license',
|
'white_label_purchase_link' => 'Adquira uma licença white label',
|
||||||
|
|
||||||
// Expense / vendor
|
// Expense / vendor
|
||||||
'expense' => 'Expense',
|
'expense' => 'Despesa',
|
||||||
'expenses' => 'Expenses',
|
'expenses' => 'Despesas',
|
||||||
'new_expense' => 'Enter Expense',
|
'new_expense' => 'Adicionar Despesa',
|
||||||
'enter_expense' => 'Enter Expense',
|
'enter_expense' => 'Incluir Despesa',
|
||||||
'vendors' => 'Vendors',
|
'vendors' => 'Fornecedor',
|
||||||
'new_vendor' => 'New Vendor',
|
'new_vendor' => 'Novo Fornecedor',
|
||||||
'payment_terms_net' => 'Net',
|
'payment_terms_net' => 'Rede',
|
||||||
'vendor' => 'Vendor',
|
'vendor' => 'Fornecedor',
|
||||||
'edit_vendor' => 'Edit Vendor',
|
'edit_vendor' => 'Editar Fornecedor',
|
||||||
'archive_vendor' => 'Archive Vendor',
|
'archive_vendor' => 'Arquivar Fornecedor',
|
||||||
'delete_vendor' => 'Delete Vendor',
|
'delete_vendor' => 'Deletar Fornecedor',
|
||||||
'view_vendor' => 'View Vendor',
|
'view_vendor' => 'Visualizar Fornecedor',
|
||||||
'deleted_expense' => 'Successfully deleted expense',
|
'deleted_expense' => 'Despesa excluída com sucesso',
|
||||||
'archived_expense' => 'Successfully archived expense',
|
'archived_expense' => 'Despesa arquivada com sucesso',
|
||||||
'deleted_expenses' => 'Successfully deleted expenses',
|
'deleted_expenses' => 'Despesas excluídas com sucesso',
|
||||||
'archived_expenses' => 'Successfully archived expenses',
|
'archived_expenses' => 'Despesas arquivada com sucesso',
|
||||||
|
|
||||||
// Expenses
|
// Expenses
|
||||||
'expense_amount' => 'Expense Amount',
|
'expense_amount' => 'Total de Despesas',
|
||||||
'expense_balance' => 'Expense Balance',
|
'expense_balance' => 'Saldo de Despesas',
|
||||||
'expense_date' => 'Expense Date',
|
'expense_date' => 'Data da Despesa',
|
||||||
'expense_should_be_invoiced' => 'Should this expense be invoiced?',
|
'expense_should_be_invoiced' => 'Esta despesa deve ser faturada?',
|
||||||
'public_notes' => 'Public Notes',
|
'public_notes' => 'Notas Públicas',
|
||||||
'invoice_amount' => 'Invoice Amount',
|
'invoice_amount' => 'Total da Fatura',
|
||||||
'exchange_rate' => 'Exchange Rate',
|
'exchange_rate' => 'Taxa de Câmbio',
|
||||||
'yes' => 'Yes',
|
'yes' => 'Sim',
|
||||||
'no' => 'No',
|
'no' => 'Não',
|
||||||
'should_be_invoiced' => 'Should be invoiced',
|
'should_be_invoiced' => 'Deve ser Faturada',
|
||||||
'view_expense' => 'View expense # :expense',
|
'view_expense' => 'Visualizar despesa # :expense',
|
||||||
'edit_expense' => 'Edit Expense',
|
'edit_expense' => 'Editar Despesa',
|
||||||
'archive_expense' => 'Archive Expense',
|
'archive_expense' => 'Arquivar Despesa',
|
||||||
'delete_expense' => 'Delete Expense',
|
'delete_expense' => 'Deletar Despesa',
|
||||||
'view_expense_num' => 'Expense # :expense',
|
'view_expense_num' => 'Despesa # :expense',
|
||||||
'updated_expense' => 'Successfully updated expense',
|
'updated_expense' => 'Despesa atualizada com sucesso',
|
||||||
'created_expense' => 'Successfully created expense',
|
'created_expense' => 'Despesa criada com sucesso',
|
||||||
'enter_expense' => 'Enter Expense',
|
'enter_expense' => 'Incluir Despesa',
|
||||||
'view' => 'View',
|
'view' => 'Visualizar',
|
||||||
'restore_expense' => 'Restore Expense',
|
'restore_expense' => 'Restaurar Despesa',
|
||||||
'invoice_expense' => 'Invoice Expense',
|
'invoice_expense' => 'Faturar Despesa',
|
||||||
'expense_error_multiple_clients' => 'The expenses can\'t belong to different clients',
|
'expense_error_multiple_clients' => 'Despesas não podem pertencer a clientes diferentes',
|
||||||
'expense_error_invoiced' => 'Expense has already been invoiced',
|
'expense_error_invoiced' => 'Despeja já faturada',
|
||||||
'convert_currency' => 'Convert currency',
|
'convert_currency' => 'Converter moeda',
|
||||||
|
|
||||||
// Payment terms
|
// Payment terms
|
||||||
'num_days' => 'Number of days',
|
'num_days' => 'Número de dias',
|
||||||
'create_payment_term' => 'Create Payment Term',
|
'create_payment_term' => 'Criar Termo de Pagamento',
|
||||||
'edit_payment_terms' => 'Edit Payment Term',
|
'edit_payment_terms' => 'Editar Termos de Pagamento',
|
||||||
'edit_payment_term' => 'Edit Payment Term',
|
'edit_payment_term' => 'Editar Termo de Pagamento',
|
||||||
'archive_payment_term' => 'Archive Payment Term',
|
'archive_payment_term' => 'Arquivar Termo de Pagamento',
|
||||||
|
|
||||||
// recurring due dates
|
// recurring due dates
|
||||||
'recurring_due_dates' => 'Recurring Invoice Due Dates',
|
'recurring_due_dates' => 'Data de Vencimento das Faturas Recorrentes',
|
||||||
'recurring_due_date_help' => '<p>Automatically sets a due date for the invoice.</p>
|
'recurring_due_date_help' => '<p>Definir automaticamente a data de vencimento da fatura.</p>
|
||||||
<p>Invoices on a monthly or yearly cycle set to be due on or before the day they are created will be due the next month. Invoices set to be due on the 29th or 30th in months that don\'t have that day will be due the last day of the month.</p>
|
<p>Faturas em um ciclo mensal ou anual com vencimento anterior ou na data em que são criadas serão faturadas para o próximo mês. Faturas com vencimento no dia 29 ou 30 nos meses que não tem esse dia será faturada no último dia do mês..</p>
|
||||||
<p>Invoices on a weekly cycle set to be due on the day of the week they are created will be due the next week.</p>
|
<p>Faturas em um clclo mensal com vencimento no dia da semana em que foi criada serão faturadas para a próxima semana.</p>
|
||||||
<p>For example:</p>
|
<p>Exemplo:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Today is the 15th, due date is 1st of the month. The due date should likely be the 1st of the next month.</li>
|
<li>Hoje é dia 15, vencimento no primeiro dia do mês. O Vencimento será no primeiro dia do próximo mês.</li>
|
||||||
<li>Today is the 15th, due date is the last day of the month. The due date will be the last day of the this month.
|
<li>Hoje é dia 15, vencimento no último dia do mês. O Vencimento será no último dia do mês corrente</li>
|
||||||
</li>
|
<li>Hoje é dia 15, vencimento no dia 15. O venciemnto será no dia 15 do <strong>próximo</strong> mês.</li>
|
||||||
<li>Today is the 15th, due date is the 15th day of the month. The due date will be the 15th day of <strong>next</strong> month.
|
<li>Hoje é Sexta-Feira, vencimento na primeira sexta-feira. O venciemnto será na próxima sexta-feira, não hoje.</li>
|
||||||
</li>
|
|
||||||
<li>Today is the Friday, due date is the 1st Friday after. The due date will be next Friday, not today.
|
|
||||||
</li>
|
|
||||||
</ul>',
|
</ul>',
|
||||||
'due' => 'Due',
|
'due' => 'Vencimento',
|
||||||
'next_due_on' => 'Due Next: :date',
|
'next_due_on' => 'Próximo Vencimento: :date',
|
||||||
'use_client_terms' => 'Use client terms',
|
'use_client_terms' => 'Usar condições do cliente',
|
||||||
'day_of_month' => ':ordinal day of month',
|
'day_of_month' => ':ordinal dia do mês ',
|
||||||
'last_day_of_month' => 'Last day of month',
|
'last_day_of_month' => 'Último dia do mês',
|
||||||
'day_of_week_after' => ':ordinal :day after',
|
'day_of_week_after' => ':ordinal :day depois',
|
||||||
'sunday' => 'Sunday',
|
'sunday' => 'Domingo',
|
||||||
'monday' => 'Monday',
|
'monday' => 'Segunda-Feira',
|
||||||
'tuesday' => 'Tuesday',
|
'tuesday' => 'Terça-Feira',
|
||||||
'wednesday' => 'Wednesday',
|
'wednesday' => 'Quarta-Feira',
|
||||||
'thursday' => 'Thursday',
|
'thursday' => 'Quinta-Feira',
|
||||||
'friday' => 'Friday',
|
'friday' => 'Sexta-Feira',
|
||||||
'saturday' => 'Saturday',
|
'saturday' => 'Sábado',
|
||||||
|
|
||||||
// Fonts
|
// Fonts
|
||||||
'header_font_id' => 'Header Font',
|
'header_font_id' => 'Fonte do Cabeçalho',
|
||||||
'body_font_id' => 'Body Font',
|
'body_font_id' => 'Fonte dos Textos',
|
||||||
'color_font_help' => 'Note: the primary color and fonts are also used in the client portal and custom email designs.',
|
'color_font_help' => 'Nota: A cor primária também é utilizada nos projetos do portal do cliente e-mail personalizado.',
|
||||||
|
|
||||||
'live_preview' => 'Live Preview',
|
'live_preview' => 'Preview',
|
||||||
'invalid_mail_config' => 'Unable to send email, please check that the mail settings are correct.',
|
'invalid_mail_config' => 'Falha ao enviar e-mail, verifique as configurações.',
|
||||||
|
|
||||||
'invoice_message_button' => 'To view your invoice for :amount, click the button below.',
|
'invoice_message_button' => 'Para visualizar sua fatura de :amount, clique no botão abaixo.',
|
||||||
'quote_message_button' => 'To view your quote for :amount, click the button below.',
|
'quote_message_button' => 'Para visualizar seu orçamento de :amount, clique no botão abaixo.',
|
||||||
'payment_message_button' => 'Thank you for your payment of :amount.',
|
'payment_message_button' => 'Obrigado pelo seu pagamento de :amount.',
|
||||||
'payment_type_direct_debit' => 'Direct Debit',
|
'payment_type_direct_debit' => 'Débito',
|
||||||
'bank_accounts' => 'Bank Accounts',
|
'bank_accounts' => 'Contas Bancárias',
|
||||||
'add_bank_account' => 'Add Bank Account',
|
'add_bank_account' => 'Adicionar Conta Bancária',
|
||||||
'setup_account' => 'Setup Account',
|
'setup_account' => 'Configurar Conta',
|
||||||
'import_expenses' => 'Import Expenses',
|
'import_expenses' => 'Importar Despesas',
|
||||||
'bank_id' => 'bank',
|
'bank_id' => 'banco',
|
||||||
'integration_type' => 'Integration Type',
|
'integration_type' => 'Tipo de Integração',
|
||||||
'updated_bank_account' => 'Successfully updated bank account',
|
'updated_bank_account' => 'Conta bancária atualizada com sucesso',
|
||||||
'edit_bank_account' => 'Edit Bank Account',
|
'edit_bank_account' => 'Editar Conta Bancária',
|
||||||
'archive_bank_account' => 'Archive Bank Account',
|
'archive_bank_account' => 'Arquivar Conta Bancária',
|
||||||
'archived_bank_account' => 'Successfully archived bank account',
|
'archived_bank_account' => 'Conta bancária arquivada com sucesso',
|
||||||
'created_bank_account' => 'Successfully created bank account',
|
'created_bank_account' => 'Conta bancária criada com sucesso',
|
||||||
'validate_bank_account' => 'Validate Bank Account',
|
'validate_bank_account' => 'Validar Conta Bancária',
|
||||||
'bank_accounts_help' => 'Connect a bank account to automatically import expenses and create vendors. Supports American Express and <a href="'.OFX_HOME_URL.'" target="_blank">400+ US banks.</a>',
|
'bank_accounts_help' => 'Conecte sua conta bancária para importar suas despesas e criar fornecedores. Suporte ao American Express e <a href="'.OFX_HOME_URL.'" target="_blank">400+ bancos americanos.</a>',
|
||||||
'bank_password_help' => 'Note: your password is transmitted securely and never stored on our servers.',
|
'bank_password_help' => 'Nota: sua senha é transferida de forma segura e não será armazenada em nossos servidores.',
|
||||||
'bank_password_warning' => 'Warning: your password may be transmitted in plain text, consider enabling HTTPS.',
|
'bank_password_warning' => 'Atenção: sua senha será transferida de forma não segura, considere habilitar HTTPS.',
|
||||||
'username' => 'Username',
|
'username' => 'Usuário',
|
||||||
'account_number' => 'Account Number',
|
'account_number' => 'Conta',
|
||||||
'account_name' => 'Account Name',
|
'account_name' => 'Nome da Conta',
|
||||||
'bank_account_error' => 'Failed to retreive account details, please check your credentials.',
|
'bank_account_error' => 'Falha ao receber os detalhes da sua conta, verifique seus dados de acesso.',
|
||||||
'status_approved' => 'Approved',
|
'status_approved' => 'Aprovado',
|
||||||
'quote_settings' => 'Quote Settings',
|
'quote_settings' => 'Configuração de Orçamentos',
|
||||||
'auto_convert_quote' => 'Auto convert quote',
|
'auto_convert_quote' => 'Auto converter orçamento',
|
||||||
'auto_convert_quote_help' => 'Automatically convert a quote to an invoice when approved by a client.',
|
'auto_convert_quote_help' => 'Converter automaticamente um orçamento quando for aprovado pelo cliente.',
|
||||||
'validate' => 'Validate',
|
'validate' => 'Validado',
|
||||||
'info' => 'Info',
|
'info' => 'Info',
|
||||||
'imported_expenses' => 'Successfully created :count_vendors vendor(s) and :count_expenses expense(s)',
|
'imported_expenses' => ':count_vendors fornecedor(s) e :count_expenses despesa(s) importadas com sucesso',
|
||||||
|
|
||||||
'iframe_url_help3' => 'Note: if you plan on accepting credit cards details we strongly recommend enabling HTTPS on your site.',
|
'iframe_url_help3' => 'Nota: se o seu plano aceita detalhes do cartão de crédito recomendamos que seja habilitado o HTTPS em seu site.',
|
||||||
'expense_error_multiple_currencies' => 'The expenses can\'t have different currencies.',
|
'expense_error_multiple_currencies' => 'As despesas não podem ter diferentes moedas.',
|
||||||
'expense_error_mismatch_currencies' => 'The client\'s currency does not match the expense currency.',
|
'expense_error_mismatch_currencies' => 'As configurações de moeda do cliente não coincide com a moeda nesta despesa.',
|
||||||
'trello_roadmap' => 'Trello Roadmap',
|
'trello_roadmap' => 'Trello Roadmap',
|
||||||
'header_footer' => 'Header/Footer',
|
'header_footer' => 'Cabeçalho/Rodapé',
|
||||||
'first_page' => 'first page',
|
'first_page' => 'primeira página',
|
||||||
'all_pages' => 'all pages',
|
'all_pages' => 'todas as páginas',
|
||||||
'last_page' => 'last page',
|
'last_page' => 'última página',
|
||||||
'all_pages_header' => 'Show header on',
|
'all_pages_header' => 'Mostrar cabeçalho on',
|
||||||
'all_pages_footer' => 'Show footer on',
|
'all_pages_footer' => 'Mostrar rodapé on',
|
||||||
'invoice_currency' => 'Invoice Currency',
|
'invoice_currency' => 'Moeda da Fatura',
|
||||||
'enable_https' => 'We strongly recommend using HTTPS to accept credit card details online.',
|
'enable_https' => 'Recomendamos a utilização de HTTPS para receber os detalhes do cartão de crédito online.',
|
||||||
'quote_issued_to' => 'Quote issued to',
|
'quote_issued_to' => 'Orçamento emitido para',
|
||||||
'show_currency_code' => 'Currency Code',
|
'show_currency_code' => 'Código da Moeda',
|
||||||
'trial_message' => 'Your account will receive a free two week trial of our pro plan.',
|
'trial_message' => 'Sua conta receberá duas semanas receberá duas semanas gratuitamente para testar nosso plano pro.',
|
||||||
'trial_footer' => 'Your free trial lasts :count more days, :link to upgrade now.',
|
'trial_footer' => 'Seu período de teste expira em :count dias, :link para adquirir o plano pro.',
|
||||||
'trial_footer_last_day' => 'This is the last day of your free trial, :link to upgrade now.',
|
'trial_footer_last_day' => 'Seu período de testes encerra hoje, :link para adiquirir o plano pro.',
|
||||||
'trial_call_to_action' => 'Start Free Trial',
|
'trial_call_to_action' => 'Iniciar período de testes',
|
||||||
'trial_success' => 'Successfully enabled two week free pro plan trial',
|
'trial_success' => 'Duas semanas de testes foi habilitado com sucesso',
|
||||||
'overdue' => 'Overdue',
|
'overdue' => 'Vencido',
|
||||||
'white_label_text' => 'Purchase a ONE YEAR white label license for $'.WHITE_LABEL_PRICE.' to remove the Invoice Ninja branding from the client portal and help support our project.',
|
'white_label_text' => 'Adquira UM ano de licença white label por $'.WHITE_LABEL_PRICE.' para remover a marca Invoice Ninja do portal do cliente e ajudar nosso projeto.',
|
||||||
|
|
||||||
'navigation' => 'Navigation',
|
'navigation' => 'Navegação',
|
||||||
'list_invoices' => 'List Invoices',
|
'list_invoices' => 'Listar Faturas',
|
||||||
'list_clients' => 'List Clients',
|
'list_clients' => 'Listar Clientes',
|
||||||
'list_quotes' => 'List Quotes',
|
'list_quotes' => 'Listar Orçamentos',
|
||||||
'list_tasks' => 'List Tasks',
|
'list_tasks' => 'Listar Tarefas',
|
||||||
'list_expenses' => 'List Expenses',
|
'list_expenses' => 'Listar Despesas',
|
||||||
'list_recurring_invoices' => 'List Recurring Invoices',
|
'list_recurring_invoices' => 'Listar Faturas Recorrentes',
|
||||||
'list_payments' => 'List Payments',
|
'list_payments' => 'Listar Pagamentos',
|
||||||
'list_credits' => 'List Credits',
|
'list_credits' => 'Listar Créditos',
|
||||||
'tax_name' => 'Tax Name',
|
'tax_name' => 'Nome da Taxa',
|
||||||
'report_settings' => 'Report Settings',
|
'report_settings' => 'Configuração de Relatórios',
|
||||||
'search_hotkey' => 'shortcut is /',
|
'search_hotkey' => 'atalho /',
|
||||||
|
|
||||||
'new_user' => 'New User',
|
'new_user' => 'Novo Usuário',
|
||||||
'new_product' => 'New Product',
|
'new_product' => 'Novo Produto',
|
||||||
'new_tax_rate' => 'New Tax Rate',
|
'new_tax_rate' => 'Nova Taxa de Juro',
|
||||||
'invoiced_amount' => 'Invoiced Amount',
|
'invoiced_amount' => 'Total Faturado',
|
||||||
'invoice_item_fields' => 'Invoice Item Fields',
|
'invoice_item_fields' => 'Campos de Ítens da Fatura',
|
||||||
'custom_invoice_item_fields_help' => 'Add a field when creating an invoice item and display the label and value on the PDF.',
|
'custom_invoice_item_fields_help' => 'Adicionar um campo ao adicionar um ítem na fatura e exibir no PDF.',
|
||||||
'recurring_invoice_number' => 'Recurring Invoice Number',
|
'recurring_invoice_number' => 'Número da Fatura Recorrente',
|
||||||
'recurring_invoice_number_prefix_help' => 'Speciy a prefix to be added to the invoice number for recurring invoices. The default value is \'R\'.',
|
'recurring_invoice_number_prefix_help' => 'Informe um prefixo para a numeração das faturas recorrentes. O valor padrão é \'R\'.',
|
||||||
'enable_client_portal' => 'Dashboard',
|
'enable_client_portal' => 'Painel',
|
||||||
'enable_client_portal_help' => 'Show/hide the dashboard page in the client portal.',
|
'enable_client_portal_help' => 'Mostrar/Ocultar o painel no portal do cliente.',
|
||||||
|
|
||||||
// Client Passwords
|
// Client Passwords
|
||||||
'enable_portal_password'=>'Password protect invoices',
|
'enable_portal_password'=>'Faturas protegidas por senha',
|
||||||
'enable_portal_password_help'=>'Allows you to set a password for each contact. If a password is set, the contact will be required to enter a password before viewing invoices.',
|
'enable_portal_password_help'=>'Permite definir uma senha para cada contato. Se uma senha for definida, o contato deverá informar sua senha antes de visualizar a fatura.',
|
||||||
'send_portal_password'=>'Generate password automatically',
|
'send_portal_password'=>'Gerar senha automaticamente',
|
||||||
'send_portal_password_help'=>'If no password is set, one will be generated and sent with the first invoice.',
|
'send_portal_password_help'=>'Se uma senha não for definida, uma senha será gerada e enviada juntamente com a primeira fatura.',
|
||||||
|
|
||||||
'expired' => 'Expired',
|
'expired' => 'Expireda',
|
||||||
'invalid_card_number' => 'The credit card number is not valid.',
|
'invalid_card_number' => 'Cartão de Crédito inválido.',
|
||||||
'invalid_expiry' => 'The expiration date is not valid.',
|
'invalid_expiry' => 'Data para expirar não é valida.',
|
||||||
'invalid_cvv' => 'The CVV is not valid.',
|
'invalid_cvv' => 'O código CVV não é válido.',
|
||||||
'cost' => 'Cost',
|
'cost' => 'Custo',
|
||||||
'create_invoice_for_sample' => 'Note: create your first invoice to see a preview here.',
|
'create_invoice_for_sample' => 'Nota: cria sua primeira fatura para visualizar aqui.',
|
||||||
|
|
||||||
// User Permissions
|
// User Permissions
|
||||||
'owner' => 'Owner',
|
'owner' => 'Proprietário',
|
||||||
'administrator' => 'Administrator',
|
'administrator' => 'Administrador',
|
||||||
'administrator_help' => 'Allow user to manage users, change settings and modify all records',
|
'administrator_help' => 'Permite usuário gerenciar usuários, configurações e alterar todos os cadastros',
|
||||||
'user_create_all' => 'Create clients, invoices, etc.',
|
'user_create_all' => 'Criar clientes, faturas, etc.',
|
||||||
'user_view_all' => 'View all clients, invoices, etc.',
|
'user_view_all' => 'Visualizar todos os clientes, faturas, etc.',
|
||||||
'user_edit_all' => 'Edit all clients, invoices, etc.',
|
'user_edit_all' => 'Editar todos os clientes, faturas, etc.',
|
||||||
'gateway_help_20' => ':link to sign up for Sage Pay.',
|
'gateway_help_20' => ':link para habilitar Sage Pay.',
|
||||||
'gateway_help_21' => ':link to sign up for Sage Pay.',
|
'gateway_help_21' => ':link para habilitar Sage Pay.',
|
||||||
'partial_due' => 'Partial Due',
|
'partial_due' => 'Vencimento Parcial',
|
||||||
'restore_vendor' => 'Restore Vendor',
|
'restore_vendor' => 'Restaurar Fornecedor',
|
||||||
'restored_vendor' => 'Successfully restored vendor',
|
'restored_vendor' => 'Fornecedor restarurado com sucesso',
|
||||||
'restored_expense' => 'Successfully restored expense',
|
'restored_expense' => 'Despesa restaurada com sucesso',
|
||||||
'permissions' => 'Permissions',
|
'permissions' => 'Permissões',
|
||||||
'create_all_help' => 'Allow user to create and modify records',
|
'create_all_help' => 'Permite o usuário criar e alterar todos os regitros',
|
||||||
'view_all_help' => 'Allow user to view records they didn\'t create',
|
'view_all_help' => 'Permite usuario visualizar regitros que ele não criou',
|
||||||
'edit_all_help' => 'Allow user to modify records they didn\'t create',
|
'edit_all_help' => 'Permite usuario editar regitros que ele não criou',
|
||||||
'view_payment' => 'View Payment',
|
'view_payment' => 'Visualizar ',
|
||||||
|
|
||||||
'january' => 'January',
|
'january' => 'Janeiro',
|
||||||
'february' => 'February',
|
'february' => 'Fevereiro',
|
||||||
'march' => 'March',
|
'march' => 'Março',
|
||||||
'april' => 'April',
|
'april' => 'Abril',
|
||||||
'may' => 'May',
|
'may' => 'Maio',
|
||||||
'june' => 'June',
|
'june' => 'Junho',
|
||||||
'july' => 'July',
|
'july' => 'Julho',
|
||||||
'august' => 'August',
|
'august' => 'Agosto',
|
||||||
'september' => 'September',
|
'september' => 'Setembro',
|
||||||
'october' => 'October',
|
'october' => 'Outubro',
|
||||||
'november' => 'November',
|
'november' => 'Novembro',
|
||||||
'december' => 'December',
|
'december' => 'Dezembro',
|
||||||
|
|
||||||
);
|
);
|
@ -9,7 +9,7 @@
|
|||||||
@if (Utils::isNinja())
|
@if (Utils::isNinja())
|
||||||
{!! Button::normal(trans('texts.zapier'))->asLinkTo(ZAPIER_URL)->withAttributes(['target' => '_blank']) !!}
|
{!! Button::normal(trans('texts.zapier'))->asLinkTo(ZAPIER_URL)->withAttributes(['target' => '_blank']) !!}
|
||||||
@endif
|
@endif
|
||||||
@if (Utils::isPro())
|
@if (Utils::hasFeature(FEATURE_API))
|
||||||
{!! Button::primary(trans('texts.add_token'))->asLinkTo(URL::to('/tokens/create'))->appendIcon(Icon::create('plus-sign')) !!}
|
{!! Button::primary(trans('texts.add_token'))->asLinkTo(URL::to('/tokens/create'))->appendIcon(Icon::create('plus-sign')) !!}
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
{!! Former::populateField('enable_portal_password', intval($enable_portal_password)) !!}
|
{!! Former::populateField('enable_portal_password', intval($enable_portal_password)) !!}
|
||||||
{!! Former::populateField('send_portal_password', intval($send_portal_password)) !!}
|
{!! Former::populateField('send_portal_password', intval($send_portal_password)) !!}
|
||||||
|
|
||||||
@if (!Utils::isNinja() && !Auth::user()->account->isWhiteLabel())
|
@if (!Utils::isNinja() && !Auth::user()->account->hasFeature(FEATURE_WHITE_LABEL))
|
||||||
<div class="alert alert-warning" style="font-size:larger;">
|
<div class="alert alert-warning" style="font-size:larger;">
|
||||||
<center>
|
<center>
|
||||||
{!! trans('texts.white_label_custom_css', ['link'=>'<a href="#" onclick="$(\'#whiteLabelModal\').modal(\'show\');">'.trans('texts.white_label_purchase_link').'</a>']) !!}
|
{!! trans('texts.white_label_custom_css', ['link'=>'<a href="#" onclick="$(\'#whiteLabelModal\').modal(\'show\');">'.trans('texts.white_label_purchase_link').'</a>']) !!}
|
||||||
@ -59,6 +59,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@if (Utils::hasFeature(FEATURE_CLIENT_PORTAL_CSS))
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h3 class="panel-title">{!! trans('texts.custom_css') !!}</h3>
|
<h3 class="panel-title">{!! trans('texts.custom_css') !!}</h3>
|
||||||
@ -74,6 +75,7 @@
|
|||||||
->style("min-width:100%;max-width:100%;font-family:'Roboto Mono', 'Lucida Console', Monaco, monospace;font-size:14px;'") !!}
|
->style("min-width:100%;max-width:100%;font-family:'Roboto Mono', 'Lucida Console', Monaco, monospace;font-size:14px;'") !!}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -45,7 +45,11 @@
|
|||||||
var customDesign = origCustomDesign = {!! $customDesign ?: 'JSON.parse(invoiceDesigns[0].javascript);' !!};
|
var customDesign = origCustomDesign = {!! $customDesign ?: 'JSON.parse(invoiceDesigns[0].javascript);' !!};
|
||||||
|
|
||||||
function getPDFString(cb, force) {
|
function getPDFString(cb, force) {
|
||||||
invoice.is_pro = {!! Auth::user()->isPro() ? 'true' : 'false' !!};
|
invoice.features = {
|
||||||
|
customize_invoice_design:{{ Auth::user()->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN) ? 'true' : 'false' }},
|
||||||
|
remove_created_by:{{ Auth::user()->hasFeature(FEATURE_REMOVE_CREATED_BY) ? 'true' : 'false' }},
|
||||||
|
invoice_settings:{{ Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS) ? 'true' : 'false' }}
|
||||||
|
};
|
||||||
invoice.account.hide_quantity = {!! Auth::user()->account->hide_quantity ? 'true' : 'false' !!};
|
invoice.account.hide_quantity = {!! Auth::user()->account->hide_quantity ? 'true' : 'false' !!};
|
||||||
invoice.account.hide_paid_to_date = {!! Auth::user()->account->hide_paid_to_date ? 'true' : 'false' !!};
|
invoice.account.hide_paid_to_date = {!! Auth::user()->account->hide_paid_to_date ? 'true' : 'false' !!};
|
||||||
invoice.invoice_design_id = {!! Auth::user()->account->invoice_design_id !!};
|
invoice.invoice_design_id = {!! Auth::user()->account->invoice_design_id !!};
|
||||||
@ -194,7 +198,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@if (!Auth::user()->isPro())
|
@if (!Auth::user()->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN))
|
||||||
$(function() {
|
$(function() {
|
||||||
$('form.warn-on-exit input, .save-button').prop('disabled', true);
|
$('form.warn-on-exit input, .save-button').prop('disabled', true);
|
||||||
});
|
});
|
||||||
|
@ -86,7 +86,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if (Auth::user()->isPro())
|
@if (Auth::user()->hasFeature(FEATURE_CUSTOM_EMAILS))
|
||||||
<center>
|
<center>
|
||||||
{!! Button::success(trans('texts.save'))->large()->submit()->appendIcon(Icon::create('floppy-disk')) !!}
|
{!! Button::success(trans('texts.save'))->large()->submit()->appendIcon(Icon::create('floppy-disk')) !!}
|
||||||
</center>
|
</center>
|
||||||
|
@ -73,51 +73,7 @@
|
|||||||
{!! Former::close() !!}
|
{!! Former::close() !!}
|
||||||
|
|
||||||
|
|
||||||
{!! Former::open('settings/cancel_account')->addClass('cancel-account') !!}
|
|
||||||
<div class="panel panel-default">
|
|
||||||
<div class="panel-heading">
|
|
||||||
<h3 class="panel-title">{!! trans('texts.cancel_account') !!}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body">
|
|
||||||
{!! Former::actions( Button::danger(trans('texts.cancel_account'))->large()->withAttributes(['onclick' => 'showConfirm()'])->appendIcon(Icon::create('trash'))) !!}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal fade" id="confirmCancelModal" tabindex="-1" role="dialog" aria-labelledby="confirmCancelModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog" style="min-width:150px">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
|
||||||
<h4 class="modal-title" id="confirmCancelModalLabel">{!! trans('texts.cancel_account') !!}</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="background-color: #fff; padding-left: 16px; padding-right: 16px">
|
|
||||||
<p>{{ trans('texts.cancel_account_message') }}</p>
|
|
||||||
<p>{!! Former::textarea('reason')->placeholder(trans('texts.reason_for_canceling'))->raw() !!}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer" style="margin-top: 0px">
|
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{ trans('texts.go_back') }}</button>
|
|
||||||
<button type="button" class="btn btn-danger" onclick="confirmCancel()">{{ trans('texts.cancel_account') }}</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{!! Former::close() !!}
|
|
||||||
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
function showConfirm() {
|
|
||||||
$('#confirmCancelModal').modal('show');
|
|
||||||
}
|
|
||||||
|
|
||||||
function confirmCancel() {
|
|
||||||
$('form.cancel-account').submit();
|
|
||||||
}
|
|
||||||
|
|
||||||
function setEntityTypesVisible() {
|
function setEntityTypesVisible() {
|
||||||
var selector = '.entity-types input[type=checkbox]';
|
var selector = '.entity-types input[type=checkbox]';
|
||||||
if ($('#format').val() === 'JSON') {
|
if ($('#format').val() === 'JSON') {
|
||||||
|
@ -46,21 +46,23 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getPDFString(cb) {
|
function getPDFString(cb) {
|
||||||
invoice.is_pro = {!! Auth::user()->isPro() ? 'true' : 'false' !!};
|
invoice.features = {
|
||||||
|
customize_invoice_design:{{ Auth::user()->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN) ? 'true' : 'false' }},
|
||||||
|
remove_created_by:{{ Auth::user()->hasFeature(FEATURE_REMOVE_CREATED_BY) ? 'true' : 'false' }},
|
||||||
|
invoice_settings:{{ Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS) ? 'true' : 'false' }}
|
||||||
|
};
|
||||||
invoice.account.hide_quantity = $('#hide_quantity').is(":checked");
|
invoice.account.hide_quantity = $('#hide_quantity').is(":checked");
|
||||||
invoice.account.invoice_embed_documents = $('#invoice_embed_documents').is(":checked");
|
invoice.account.invoice_embed_documents = $('#invoice_embed_documents').is(":checked");
|
||||||
invoice.account.hide_paid_to_date = $('#hide_paid_to_date').is(":checked");
|
invoice.account.hide_paid_to_date = $('#hide_paid_to_date').is(":checked");
|
||||||
invoice.invoice_design_id = $('#invoice_design_id').val();
|
invoice.invoice_design_id = $('#invoice_design_id').val();
|
||||||
|
invoice.account.page_size = $('#page_size option:selected').text();
|
||||||
|
|
||||||
NINJA.primaryColor = $('#primary_color').val();
|
NINJA.primaryColor = $('#primary_color').val();
|
||||||
NINJA.secondaryColor = $('#secondary_color').val();
|
NINJA.secondaryColor = $('#secondary_color').val();
|
||||||
NINJA.fontSize = parseInt($('#font_size').val());
|
NINJA.fontSize = parseInt($('#font_size').val());
|
||||||
@if (Auth::user()->isPro())
|
NINJA.headerFont = $('#header_font_id option:selected').text();
|
||||||
NINJA.headerFont = $('#header_font_id option:selected').text();
|
NINJA.bodyFont = $('#body_font_id option:selected').text();
|
||||||
NINJA.bodyFont = $('#body_font_id option:selected').text();
|
|
||||||
@else
|
|
||||||
NINJA.headerFont = NINJA.bodyFont = 'Roboto';
|
|
||||||
@endif
|
|
||||||
var fields = [
|
var fields = [
|
||||||
'item',
|
'item',
|
||||||
'description',
|
'description',
|
||||||
@ -89,7 +91,7 @@
|
|||||||
$(function() {
|
$(function() {
|
||||||
var options = {
|
var options = {
|
||||||
preferredFormat: 'hex',
|
preferredFormat: 'hex',
|
||||||
disabled: {!! Auth::user()->isPro() ? 'false' : 'true' !!},
|
disabled: {!! Auth::user()->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN) ? 'false' : 'true' !!},
|
||||||
showInitial: false,
|
showInitial: false,
|
||||||
showInput: true,
|
showInput: true,
|
||||||
allowEmpty: true,
|
allowEmpty: true,
|
||||||
@ -112,7 +114,16 @@
|
|||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
|
|
||||||
{!! Former::open()->addClass('warn-on-exit')->onchange('if(!window.loadingFonts)refreshPDF()') !!}
|
{!! Former::open()->addClass('warn-on-exit')->onchange('if(!window.loadingFonts)refreshPDF()') !!}
|
||||||
{!! Former::populate($account) !!}
|
|
||||||
|
{!! Former::populateField('invoice_design_id', $account->invoice_design_id) !!}
|
||||||
|
{!! Former::populateField('body_font_id', $account->body_font_id) !!}
|
||||||
|
{!! Former::populateField('header_font_id', $account->header_font_id) !!}
|
||||||
|
{!! Former::populateField('live_preview', intval($account->live_preview)) !!}
|
||||||
|
{!! Former::populateField('font_size', $account->font_size) !!}
|
||||||
|
{!! Former::populateField('page_size', $account->page_size) !!}
|
||||||
|
{!! Former::populateField('invoice_embed_documents', intval($account->invoice_embed_documents)) !!}
|
||||||
|
{!! Former::populateField('primary_color', $account->primary_color) !!}
|
||||||
|
{!! Former::populateField('secondary_color', $account->secondary_color) !!}
|
||||||
{!! Former::populateField('hide_quantity', intval($account->hide_quantity)) !!}
|
{!! Former::populateField('hide_quantity', intval($account->hide_quantity)) !!}
|
||||||
{!! Former::populateField('hide_paid_to_date', intval($account->hide_paid_to_date)) !!}
|
{!! Former::populateField('hide_paid_to_date', intval($account->hide_paid_to_date)) !!}
|
||||||
{!! Former::populateField('all_pages_header', intval($account->all_pages_header)) !!}
|
{!! Former::populateField('all_pages_header', intval($account->all_pages_header)) !!}
|
||||||
@ -143,7 +154,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
|
|
||||||
@if (!Utils::isPro() || \App\Models\InvoiceDesign::count() == COUNT_FREE_DESIGNS_SELF_HOST)
|
@if (!Utils::hasFeature(FEATURE_MORE_INVOICE_DESIGNS) || \App\Models\InvoiceDesign::count() == COUNT_FREE_DESIGNS_SELF_HOST)
|
||||||
{!! Former::select('invoice_design_id')
|
{!! Former::select('invoice_design_id')
|
||||||
->fromQuery($invoiceDesigns, 'name', 'id')
|
->fromQuery($invoiceDesigns, 'name', 'id')
|
||||||
->addOption(trans('texts.more_designs') . '...', '-1') !!}
|
->addOption(trans('texts.more_designs') . '...', '-1') !!}
|
||||||
@ -156,13 +167,17 @@
|
|||||||
{!! Former::select('header_font_id')
|
{!! Former::select('header_font_id')
|
||||||
->fromQuery($invoiceFonts, 'name', 'id') !!}
|
->fromQuery($invoiceFonts, 'name', 'id') !!}
|
||||||
|
|
||||||
|
{!! Former::checkbox('live_preview')->text(trans('texts.enable')) !!}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
|
|
||||||
|
|
||||||
{{ Former::setOption('TwitterBootstrap3.labelWidths.large', 6) }}
|
{{ Former::setOption('TwitterBootstrap3.labelWidths.large', 6) }}
|
||||||
{{ Former::setOption('TwitterBootstrap3.labelWidths.small', 6) }}
|
{{ Former::setOption('TwitterBootstrap3.labelWidths.small', 6) }}
|
||||||
|
|
||||||
|
{!! Former::select('page_size')
|
||||||
|
->options($pageSizes) !!}
|
||||||
|
|
||||||
{!! Former::text('font_size')
|
{!! Former::text('font_size')
|
||||||
->type('number')
|
->type('number')
|
||||||
->min('0')
|
->min('0')
|
||||||
@ -171,6 +186,7 @@
|
|||||||
{!! Former::text('primary_color') !!}
|
{!! Former::text('primary_color') !!}
|
||||||
{!! Former::text('secondary_color') !!}
|
{!! Former::text('secondary_color') !!}
|
||||||
|
|
||||||
|
|
||||||
{{ Former::setOption('TwitterBootstrap3.labelWidths.large', 4) }}
|
{{ Former::setOption('TwitterBootstrap3.labelWidths.large', 4) }}
|
||||||
{{ Former::setOption('TwitterBootstrap3.labelWidths.small', 4) }}
|
{{ Former::setOption('TwitterBootstrap3.labelWidths.small', 4) }}
|
||||||
|
|
||||||
@ -249,7 +265,7 @@
|
|||||||
) !!}
|
) !!}
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
@if (!Auth::user()->isPro())
|
@if (!Auth::user()->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN))
|
||||||
<script>
|
<script>
|
||||||
$(function() {
|
$(function() {
|
||||||
$('form.warn-on-exit input, .save-button').prop('disabled', true);
|
$('form.warn-on-exit input, .save-button').prop('disabled', true);
|
||||||
|
@ -59,12 +59,13 @@
|
|||||||
|
|
||||||
{!! Former::text('invoice_number_prefix')
|
{!! Former::text('invoice_number_prefix')
|
||||||
->addGroupClass('invoice-prefix')
|
->addGroupClass('invoice-prefix')
|
||||||
->label(' ') !!}
|
->label(trans('texts.prefix')) !!}
|
||||||
{!! Former::text('invoice_number_pattern')
|
{!! Former::text('invoice_number_pattern')
|
||||||
->appendIcon('question-sign')
|
->appendIcon('question-sign')
|
||||||
->addGroupClass('invoice-pattern')
|
->addGroupClass('invoice-pattern')
|
||||||
->label(' ')
|
->label(trans('texts.pattern'))
|
||||||
->addGroupClass('number-pattern') !!}
|
->addGroupClass('number-pattern') !!}
|
||||||
|
{!! Former::text('invoice_number_padding') !!}
|
||||||
{!! Former::text('invoice_number_counter')
|
{!! Former::text('invoice_number_counter')
|
||||||
->label(trans('texts.counter'))
|
->label(trans('texts.counter'))
|
||||||
->help(trans('texts.invoice_number_help') . ' ' .
|
->help(trans('texts.invoice_number_help') . ' ' .
|
||||||
@ -84,12 +85,12 @@
|
|||||||
|
|
||||||
{!! Former::text('quote_number_prefix')
|
{!! Former::text('quote_number_prefix')
|
||||||
->addGroupClass('quote-prefix')
|
->addGroupClass('quote-prefix')
|
||||||
->label(' ') !!}
|
->label(trans('texts.prefix')) !!}
|
||||||
{!! Former::text('quote_number_pattern')
|
{!! Former::text('quote_number_pattern')
|
||||||
->appendIcon('question-sign')
|
->appendIcon('question-sign')
|
||||||
->addGroupClass('quote-pattern')
|
->addGroupClass('quote-pattern')
|
||||||
->addGroupClass('number-pattern')
|
->addGroupClass('number-pattern')
|
||||||
->label(' ') !!}
|
->label(trans('texts.pattern')) !!}
|
||||||
{!! Former::text('quote_number_counter')
|
{!! Former::text('quote_number_counter')
|
||||||
->label(trans('texts.counter'))
|
->label(trans('texts.counter'))
|
||||||
->addGroupClass('pad-checkbox')
|
->addGroupClass('pad-checkbox')
|
||||||
@ -264,7 +265,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
@if (Auth::user()->isPro())
|
@if (Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS))
|
||||||
<center>
|
<center>
|
||||||
{!! Button::success(trans('texts.save'))->large()->submit()->appendIcon(Icon::create('floppy-disk')) !!}
|
{!! Button::success(trans('texts.save'))->large()->submit()->appendIcon(Icon::create('floppy-disk')) !!}
|
||||||
</center>
|
</center>
|
||||||
|
225
resources/views/accounts/management.blade.php
Normal file
225
resources/views/accounts/management.blade.php
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
@extends('header')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
@parent
|
||||||
|
|
||||||
|
@include('accounts.nav', ['selected' => ACCOUNT_MANAGEMENT])
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
{!! Former::open('settings/change_plan')->addClass('change-plan') !!}
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h3 class="panel-title">{!! trans('texts.plan_status') !!}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-4 control-label">{{ trans('texts.plan') }}</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<p class="form-control-static">
|
||||||
|
@if ($planDetails && $planDetails['active'])
|
||||||
|
{{ trans('texts.plan_'.$planDetails['plan']) }}
|
||||||
|
@if ($planDetails['trial'])
|
||||||
|
({{ trans('texts.plan_trial') }})
|
||||||
|
@elseif ($planDetails['expires'])
|
||||||
|
({{ trans('texts.plan_term_'.$planDetails['term'].'ly') }})
|
||||||
|
@endif
|
||||||
|
@elseif(Utils::isNinjaProd())
|
||||||
|
{{ trans('texts.plan_free') }}
|
||||||
|
@else
|
||||||
|
{{ trans('texts.plan_free_self_hosted') }}
|
||||||
|
@endif
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if ($planDetails && $planDetails['active'])
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-4 control-label">
|
||||||
|
@if((!$account->company->pending_plan || $account->company->pending_plan == $planDetails['plan']) && $planDetails['expires'] && !$planDetails['trial'])
|
||||||
|
{{ trans('texts.renews') }}
|
||||||
|
@else
|
||||||
|
{{ trans('texts.expires') }}
|
||||||
|
@endif
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<p class="form-control-static">
|
||||||
|
@if ($planDetails['expires'] === false)
|
||||||
|
{{ trans('texts.never') }}
|
||||||
|
@else
|
||||||
|
{{ Utils::dateToString($planDetails['expires']) }}
|
||||||
|
@endif
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if ($account->company->pending_plan)
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-4 control-label">{{ trans('texts.pending_change_to') }}</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<p class="form-control-static">
|
||||||
|
@if ($account->company->pending_plan == PLAN_FREE)
|
||||||
|
{{ trans('texts.plan_changes_to', [
|
||||||
|
'plan'=>trans('texts.plan_free'),
|
||||||
|
'date'=>Utils::dateToString($planDetails['expires'])
|
||||||
|
]) }}
|
||||||
|
@else
|
||||||
|
{{ trans('texts.plan_term_changes_to', [
|
||||||
|
'plan'=>trans('texts.plan_'.$account->company->pending_plan),
|
||||||
|
'term'=>trans('texts.plan_term_'.$account->company->pending_term.'ly'),
|
||||||
|
'date'=>Utils::dateToString($planDetails['expires'])
|
||||||
|
]) }}
|
||||||
|
@endif<br>
|
||||||
|
<a href="#" onclick="cancelPendingChange()">{{ trans('texts.cancel_plan_change') }}</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@if (Utils::isNinjaProd())
|
||||||
|
{!! Former::actions( Button::info(trans('texts.plan_change'))->large()->withAttributes(['onclick' => 'showChangePlan()'])->appendIcon(Icon::create('edit'))) !!}
|
||||||
|
@endif
|
||||||
|
@else
|
||||||
|
@if ($planDetails)
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-sm-4 control-label">
|
||||||
|
@if ($planDetails['trial'])
|
||||||
|
{{ trans('texts.trial_expired', ['plan'=>trans('texts.plan_'.$planDetails['plan'])]) }}
|
||||||
|
@else
|
||||||
|
{{ trans('texts.plan_expired', ['plan'=>trans('texts.plan_'.$planDetails['plan'])]) }}
|
||||||
|
@endif
|
||||||
|
</label>
|
||||||
|
<div class="col-sm-8">
|
||||||
|
<p class="form-control-static">
|
||||||
|
{{ Utils::dateToString($planDetails['expires']) }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
@if (Utils::isNinjaProd())
|
||||||
|
{!! Former::actions( Button::success(trans('texts.plan_upgrade'))->large()->withAttributes(['onclick' => 'showChangePlan()'])->appendIcon(Icon::create('plus-sign'))) !!}
|
||||||
|
@else
|
||||||
|
{!! Former::actions( Button::success(trans('texts.white_label_button'))->large()->withAttributes(['onclick' => 'loadImages("#whiteLabelModal");$("#whiteLabelModal").modal("show");'])->appendIcon(Icon::create('plus-sign'))) !!}
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if (Utils::isNinjaProd())
|
||||||
|
<div class="modal fade" id="changePlanModel" tabindex="-1" role="dialog" aria-labelledby="changePlanModelLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog" style="min-width:150px">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
|
<h4 class="modal-title" id="changePlanModelLabel">
|
||||||
|
@if ($planDetails && $planDetails['active'])
|
||||||
|
{!! trans('texts.plan_change') !!}
|
||||||
|
@else
|
||||||
|
{!! trans('texts.plan_upgrade') !!}
|
||||||
|
@endif
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
@if ($planDetails && $planDetails['active'])
|
||||||
|
{!! Former::select('plan')
|
||||||
|
->addOption(trans('texts.plan_enterprise'), PLAN_ENTERPRISE)
|
||||||
|
->addOption(trans('texts.plan_pro'), PLAN_PRO)
|
||||||
|
->addOption(trans('texts.plan_free'), PLAN_FREE)!!}
|
||||||
|
@else
|
||||||
|
{!! Former::select('plan')
|
||||||
|
->addOption(trans('texts.plan_enterprise'), PLAN_ENTERPRISE)
|
||||||
|
->addOption(trans('texts.plan_pro'), PLAN_PRO)!!}
|
||||||
|
@endif
|
||||||
|
{!! Former::select('plan_term')
|
||||||
|
->addOption(trans('texts.plan_term_yearly'), PLAN_TERM_YEARLY)
|
||||||
|
->addOption(trans('texts.plan_term_monthly'), PLAN_TERM_MONTHLY)!!}
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer" style="margin-top: 0px">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">{{ trans('texts.go_back') }}</button>
|
||||||
|
@if ($planDetails && $planDetails['active'])
|
||||||
|
<button type="button" class="btn btn-primary" onclick="confirmChangePlan()">{{ trans('texts.plan_change') }}</button>
|
||||||
|
@else
|
||||||
|
<button type="button" class="btn btn-success" onclick="confirmChangePlan()">{{ trans('texts.plan_upgrade') }}</button>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
{!! Former::close() !!}
|
||||||
|
|
||||||
|
{!! Former::open('settings/cancel_account')->addClass('cancel-account') !!}
|
||||||
|
<div class="panel panel-default">
|
||||||
|
<div class="panel-heading">
|
||||||
|
<h3 class="panel-title">{!! trans('texts.cancel_account') !!}</h3>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
{!! Former::actions( Button::danger(trans('texts.cancel_account'))->large()->withAttributes(['onclick' => 'showConfirm()'])->appendIcon(Icon::create('trash'))) !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" id="confirmCancelModal" tabindex="-1" role="dialog" aria-labelledby="confirmCancelModalLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog" style="min-width:150px">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
|
<h4 class="modal-title" id="confirmCancelModalLabel">{!! trans('texts.cancel_account') !!}</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="background-color: #fff; padding-left: 16px; padding-right: 16px">
|
||||||
|
<p>{{ trans('texts.cancel_account_message') }}</p>
|
||||||
|
<p>{!! Former::textarea('reason')->placeholder(trans('texts.reason_for_canceling'))->raw() !!}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-footer" style="margin-top: 0px">
|
||||||
|
<button type="button" class="btn btn-default" data-dismiss="modal">{{ trans('texts.go_back') }}</button>
|
||||||
|
<button type="button" class="btn btn-danger" onclick="confirmCancel()">{{ trans('texts.cancel_account') }}</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{!! Former::close() !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function showChangePlan() {
|
||||||
|
$('#changePlanModel').modal('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirmChangePlan() {
|
||||||
|
$('form.change-plan').submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
function showConfirm() {
|
||||||
|
$('#confirmCancelModal').modal('show');
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirmCancel() {
|
||||||
|
$('form.cancel-account').submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@if ($account->company->pending_plan)
|
||||||
|
function cancelPendingChange(){
|
||||||
|
$('#plan').val('{{ $planDetails['plan'] }}')
|
||||||
|
$('#plan_term').val('{{ $planDetails['term'] }}')
|
||||||
|
confirmChangePlan();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@endif
|
||||||
|
|
||||||
|
jQuery(document).ready(function($){
|
||||||
|
function updatePlanModal() {
|
||||||
|
var plan = $('#plan').val();
|
||||||
|
$('#plan_term').closest('.form-group').toggle(plan!='free');
|
||||||
|
|
||||||
|
if(plan=='{{PLAN_PRO}}'){
|
||||||
|
$('#plan_term option[value=month]').text({!! json_encode(trans('texts.plan_price_monthly', ['price'=>PLAN_PRICE_PRO_MONTHLY])) !!});
|
||||||
|
$('#plan_term option[value=year]').text({!! json_encode(trans('texts.plan_price_yearly', ['price'=>PLAN_PRICE_PRO_YEARLY])) !!});
|
||||||
|
} else if(plan=='{{PLAN_ENTERPRISE}}') {
|
||||||
|
$('#plan_term option[value=month]').text({!! json_encode(trans('texts.plan_price_monthly', ['price'=>PLAN_PRICE_ENTERPRISE_MONTHLY])) !!});
|
||||||
|
$('#plan_term option[value=year]').text({!! json_encode(trans('texts.plan_price_yearly', ['price'=>PLAN_PRICE_ENTERPRISE_YEARLY])) !!});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$('#plan_term, #plan').change(updatePlanModal);
|
||||||
|
updatePlanModal();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@stop
|
@ -125,7 +125,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if (Auth::user()->isPro())
|
@if (Auth::user()->hasFeature(FEATURE_EMAIL_TEMPLATES_REMINDERS))
|
||||||
<center>
|
<center>
|
||||||
{!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!}
|
{!! Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk')) !!}
|
||||||
</center>
|
</center>
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if (Auth::user()->isPro())
|
@if (Auth::user()->hasFeature(FEATURE_API))
|
||||||
{!! Former::actions(
|
{!! Former::actions(
|
||||||
Button::normal(trans('texts.cancel'))->asLinkTo(URL::to('/settings/api_tokens'))->appendIcon(Icon::create('remove-circle'))->large(),
|
Button::normal(trans('texts.cancel'))->asLinkTo(URL::to('/settings/api_tokens'))->appendIcon(Icon::create('remove-circle'))->large(),
|
||||||
Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk'))
|
Button::success(trans('texts.save'))->submit()->large()->appendIcon(Icon::create('floppy-disk'))
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
@if (Utils::isPro() && ! Utils::isTrial())
|
@if (Utils::hasFeature(FEATURE_USERS))
|
||||||
{!! Button::primary(trans('texts.add_user'))->asLinkTo(URL::to('/users/create'))->appendIcon(Icon::create('plus-sign')) !!}
|
{!! Button::primary(trans('texts.add_user'))->asLinkTo(URL::to('/users/create'))->appendIcon(Icon::create('plus-sign')) !!}
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
{!! Former::text('last_name')->data_bind("value: last_name, valueUpdate: 'afterkeydown'") !!}
|
{!! Former::text('last_name')->data_bind("value: last_name, valueUpdate: 'afterkeydown'") !!}
|
||||||
{!! Former::text('email')->data_bind("value: email, valueUpdate: 'afterkeydown'") !!}
|
{!! Former::text('email')->data_bind("value: email, valueUpdate: 'afterkeydown'") !!}
|
||||||
{!! Former::text('phone')->data_bind("value: phone, valueUpdate: 'afterkeydown'") !!}
|
{!! Former::text('phone')->data_bind("value: phone, valueUpdate: 'afterkeydown'") !!}
|
||||||
@if ($account->isPro() && $account->enable_portal_password)
|
@if ($account->hasFeature(FEATURE_CLIENT_PORTAL_PASSWORD) && $account->enable_portal_password)
|
||||||
{!! Former::password('password')->data_bind("value: password()?'-%unchanged%-':'', valueUpdate: 'afterkeydown'") !!}
|
{!! Former::password('password')->data_bind("value: password()?'-%unchanged%-':'', valueUpdate: 'afterkeydown'") !!}
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
{!! Former::text('website') !!}
|
{!! Former::text('website') !!}
|
||||||
{!! Former::text('work_phone') !!}
|
{!! Former::text('work_phone') !!}
|
||||||
|
|
||||||
@if (Auth::user()->isPro())
|
@if (Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS))
|
||||||
@if ($customLabel1)
|
@if ($customLabel1)
|
||||||
{!! Former::text('custom_value1')->label($customLabel1) !!}
|
{!! Former::text('custom_value1')->label($customLabel1) !!}
|
||||||
@endif
|
@endif
|
||||||
@ -93,7 +93,7 @@
|
|||||||
attr: {name: 'contacts[' + \$index() + '][email]', id:'email'+\$index()}") !!}
|
attr: {name: 'contacts[' + \$index() + '][email]', id:'email'+\$index()}") !!}
|
||||||
{!! Former::text('phone')->data_bind("value: phone, valueUpdate: 'afterkeydown',
|
{!! Former::text('phone')->data_bind("value: phone, valueUpdate: 'afterkeydown',
|
||||||
attr: {name: 'contacts[' + \$index() + '][phone]'}") !!}
|
attr: {name: 'contacts[' + \$index() + '][phone]'}") !!}
|
||||||
@if ($account->isPro() && $account->enable_portal_password)
|
@if ($account->hasFeature(FEATURE_CLIENT_PORTAL_PASSWORD) && $account->enable_portal_password)
|
||||||
{!! Former::password('password')->data_bind("value: password()?'-%unchanged%-':'', valueUpdate: 'afterkeydown',
|
{!! Former::password('password')->data_bind("value: password()?'-%unchanged%-':'', valueUpdate: 'afterkeydown',
|
||||||
attr: {name: 'contacts[' + \$index() + '][password]'}") !!}
|
attr: {name: 'contacts[' + \$index() + '][password]'}") !!}
|
||||||
@endif
|
@endif
|
||||||
@ -134,15 +134,43 @@
|
|||||||
{!! Former::textarea('private_notes') !!}
|
{!! Former::textarea('private_notes') !!}
|
||||||
|
|
||||||
|
|
||||||
@if (isset($proPlanPaid))
|
@if (Auth::user()->account->isNinjaAccount())
|
||||||
{!! Former::populateField('pro_plan_paid', $proPlanPaid) !!}
|
@if (isset($planDetails))
|
||||||
{!! Former::text('pro_plan_paid')
|
{!! Former::populateField('plan', $planDetails['plan']) !!}
|
||||||
|
{!! Former::populateField('plan_term', $planDetails['term']) !!}
|
||||||
|
@if (!empty($planDetails['paid']))
|
||||||
|
{!! Former::populateField('plan_paid', $planDetails['paid']->format('Y-m-d')) !!}
|
||||||
|
@endif
|
||||||
|
@if (!empty($planDetails['expires']))
|
||||||
|
{!! Former::populateField('plan_expires', $planDetails['expires']->format('Y-m-d')) !!}
|
||||||
|
@endif
|
||||||
|
@if (!empty($planDetails['started']))
|
||||||
|
{!! Former::populateField('plan_started', $planDetails['started']->format('Y-m-d')) !!}
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
{!! Former::select('plan')
|
||||||
|
->addOption(trans('texts.plan_free'), PLAN_FREE)
|
||||||
|
->addOption(trans('texts.plan_pro'), PLAN_PRO)
|
||||||
|
->addOption(trans('texts.plan_enterprise'), PLAN_ENTERPRISE)!!}
|
||||||
|
{!! Former::select('plan_term')
|
||||||
|
->addOption()
|
||||||
|
->addOption(trans('texts.plan_term_yearly'), PLAN_TERM_YEARLY)
|
||||||
|
->addOption(trans('texts.plan_term_monthly'), PLAN_TERM_MONTHLY)!!}
|
||||||
|
{!! Former::text('plan_started')
|
||||||
->data_date_format('yyyy-mm-dd')
|
->data_date_format('yyyy-mm-dd')
|
||||||
->addGroupClass('pro_plan_paid_date')
|
->addGroupClass('plan_start_date')
|
||||||
|
->append('<i class="glyphicon glyphicon-calendar"></i>') !!}
|
||||||
|
{!! Former::text('plan_paid')
|
||||||
|
->data_date_format('yyyy-mm-dd')
|
||||||
|
->addGroupClass('plan_paid_date')
|
||||||
|
->append('<i class="glyphicon glyphicon-calendar"></i>') !!}
|
||||||
|
{!! Former::text('plan_expires')
|
||||||
|
->data_date_format('yyyy-mm-dd')
|
||||||
|
->addGroupClass('plan_expire_date')
|
||||||
->append('<i class="glyphicon glyphicon-calendar"></i>') !!}
|
->append('<i class="glyphicon glyphicon-calendar"></i>') !!}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function() {
|
$(function() {
|
||||||
$('#pro_plan_paid').datepicker();
|
$('#plan_started, #plan_paid, #plan_expires').datepicker();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@endif
|
@endif
|
||||||
|
@ -230,7 +230,7 @@
|
|||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
|
||||||
@if (Utils::isPro() && $hasQuotes)
|
@if (Utils::hasFeature(FEATURE_QUOTES) && $hasQuotes)
|
||||||
<div class="tab-pane" id="quotes">
|
<div class="tab-pane" id="quotes">
|
||||||
|
|
||||||
{!! Datatable::table()
|
{!! Datatable::table()
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<link href="{{ isset($account) ? $account->getFontsUrl('http') : '' }}" rel="stylesheet" type="text/css" />
|
<link href="{{ isset($account) ? $account->getFontsUrl('http') : '' }}" rel="stylesheet" type="text/css" />
|
||||||
<!--<![endif]-->
|
<!--<![endif]-->
|
||||||
</head>
|
</head>
|
||||||
<body style="min-height: 700px; color: #000000;{!! isset($account) ? $account->getBodyFontCss() : '' !!}font-size: 12px; -webkit-text-size-adjust: none; -ms-text-size-adjust: none; background: #F4F5F5; margin: 0; padding: 0;"
|
<body style="color: #000000;{!! isset($account) ? $account->getBodyFontCss() : '' !!}font-size: 12px; -webkit-text-size-adjust: none; -ms-text-size-adjust: none; background: #F4F5F5; margin: 0; padding: 0;"
|
||||||
alink="#FF0000" link="#FF0000" bgcolor="#F4F5F5" text="#000000" yahoo="fix">
|
alink="#FF0000" link="#FF0000" bgcolor="#F4F5F5" text="#000000" yahoo="fix">
|
||||||
@yield('markup')
|
@yield('markup')
|
||||||
|
|
||||||
@ -50,8 +50,8 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div id="body_style" style="min-height: 700px;{!! isset($account) ? $account->getBodyFontCss() : '' !!};color: #2E2B2B; font-size: 16px;
|
<div id="body_style" style="{!! isset($account) ? $account->getBodyFontCss() : '' !!};color: #2E2B2B; font-size: 16px;
|
||||||
background: #F4F5F5; padding: 0px 15px;">
|
background: #F4F5F5; padding: 0px 0px 15px;">
|
||||||
|
|
||||||
<table cellpadding="0" cellspacing="0" border="0" bgcolor="#FFFFFF" width="580" align="center">
|
<table cellpadding="0" cellspacing="0" border="0" bgcolor="#FFFFFF" width="580" align="center">
|
||||||
|
|
||||||
|
@ -362,7 +362,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (Auth::user()->account->isPro())
|
@if (Auth::user()->account->hasFeature(FEATURE_DOCUMENTS))
|
||||||
function handleDocumentAdded(file){
|
function handleDocumentAdded(file){
|
||||||
if(file.mock)return;
|
if(file.mock)return;
|
||||||
file.index = model.documents().length;
|
file.index = model.documents().length;
|
||||||
|
@ -431,7 +431,7 @@
|
|||||||
|
|
||||||
<div class="btn-group user-dropdown">
|
<div class="btn-group user-dropdown">
|
||||||
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown">
|
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown">
|
||||||
<div id="myAccountButton" class="ellipsis nav-account-name" style="max-width:{{ Utils::isPro() && ! Utils::isTrial() ? '130' : '100' }}px;">
|
<div id="myAccountButton" class="ellipsis nav-account-name" style="max-width:{{ Utils::hasFeature(FEATURE_USERS) ? '130' : '100' }}px;">
|
||||||
@if (session(SESSION_USER_ACCOUNTS) && count(session(SESSION_USER_ACCOUNTS)))
|
@if (session(SESSION_USER_ACCOUNTS) && count(session(SESSION_USER_ACCOUNTS)))
|
||||||
{{ Auth::user()->account->getDisplayName() }}
|
{{ Auth::user()->account->getDisplayName() }}
|
||||||
@else
|
@else
|
||||||
@ -726,8 +726,8 @@
|
|||||||
<center>
|
<center>
|
||||||
<h2>{{ trans('texts.pro_plan_title') }}</h2>
|
<h2>{{ trans('texts.pro_plan_title') }}</h2>
|
||||||
<img class="img-responsive price" alt="Only $50 Per Year" src="{{ asset('images/pro_plan/price.png') }}"/>
|
<img class="img-responsive price" alt="Only $50 Per Year" src="{{ asset('images/pro_plan/price.png') }}"/>
|
||||||
@if (Auth::user()->isEligibleForTrial())
|
@if (Auth::user()->isEligibleForTrial(PLAN_PRO))
|
||||||
<a class="button" href="{{ URL::to('start_trial') }}">{{ trans('texts.trial_call_to_action') }}</a>
|
<a class="button" href="{{ URL::to('start_trial/'.PLAN_PRO) }}">{{ trans('texts.trial_call_to_action') }}</a>
|
||||||
@else
|
@else
|
||||||
<a class="button" href="#" onclick="submitProPlan()">{{ trans('texts.pro_plan_call_to_action') }}</a>
|
<a class="button" href="#" onclick="submitProPlan()">{{ trans('texts.pro_plan_call_to_action') }}</a>
|
||||||
@endif
|
@endif
|
||||||
@ -769,7 +769,7 @@
|
|||||||
{{-- Per our license, please do not remove or modify this section. --}}
|
{{-- Per our license, please do not remove or modify this section. --}}
|
||||||
{!! link_to('https://www.invoiceninja.com/?utm_source=powered_by', 'InvoiceNinja.com', ['target' => '_blank', 'title' => 'invoiceninja.com']) !!} -
|
{!! link_to('https://www.invoiceninja.com/?utm_source=powered_by', 'InvoiceNinja.com', ['target' => '_blank', 'title' => 'invoiceninja.com']) !!} -
|
||||||
{!! link_to(RELEASES_URL, 'v' . NINJA_VERSION, ['target' => '_blank', 'title' => trans('texts.trello_roadmap')]) !!} |
|
{!! link_to(RELEASES_URL, 'v' . NINJA_VERSION, ['target' => '_blank', 'title' => trans('texts.trello_roadmap')]) !!} |
|
||||||
@if (Auth::user()->account->isWhiteLabel())
|
@if (Auth::user()->account->hasFeature(FEATURE_WHITE_LABEL))
|
||||||
{{ trans('texts.white_labeled') }}
|
{{ trans('texts.white_labeled') }}
|
||||||
@else
|
@else
|
||||||
<a href="#" onclick="loadImages('#whiteLabelModal');$('#whiteLabelModal').modal('show');">{{ trans('texts.white_label_link') }}</a>
|
<a href="#" onclick="loadImages('#whiteLabelModal');$('#whiteLabelModal').modal('show');">{{ trans('texts.white_label_link') }}</a>
|
||||||
|
@ -296,7 +296,7 @@
|
|||||||
<li role="presentation" class="active"><a href="#notes" aria-controls="notes" role="tab" data-toggle="tab">{{ trans('texts.note_to_client') }}</a></li>
|
<li role="presentation" class="active"><a href="#notes" aria-controls="notes" role="tab" data-toggle="tab">{{ trans('texts.note_to_client') }}</a></li>
|
||||||
<li role="presentation"><a href="#terms" aria-controls="terms" role="tab" data-toggle="tab">{{ trans("texts.terms") }}</a></li>
|
<li role="presentation"><a href="#terms" aria-controls="terms" role="tab" data-toggle="tab">{{ trans("texts.terms") }}</a></li>
|
||||||
<li role="presentation"><a href="#footer" aria-controls="footer" role="tab" data-toggle="tab">{{ trans("texts.footer") }}</a></li>
|
<li role="presentation"><a href="#footer" aria-controls="footer" role="tab" data-toggle="tab">{{ trans("texts.footer") }}</a></li>
|
||||||
@if ($account->isPro())
|
@if ($account->hasFeature(FEATURE_DOCUMENTS))
|
||||||
<li role="presentation"><a href="#attached-documents" aria-controls="attached-documents" role="tab" data-toggle="tab">{{ trans("texts.invoice_documents") }}</a></li>
|
<li role="presentation"><a href="#attached-documents" aria-controls="attached-documents" role="tab" data-toggle="tab">{{ trans("texts.invoice_documents") }}</a></li>
|
||||||
@endif
|
@endif
|
||||||
</ul>
|
</ul>
|
||||||
@ -330,7 +330,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>') !!}
|
</div>') !!}
|
||||||
</div>
|
</div>
|
||||||
@if ($account->isPro())
|
@if ($account->hasFeature(FEATURE_DOCUMENTS))
|
||||||
<div role="tabpanel" class="tab-pane" id="attached-documents" style="position:relative;z-index:9">
|
<div role="tabpanel" class="tab-pane" id="attached-documents" style="position:relative;z-index:9">
|
||||||
<div id="document-upload">
|
<div id="document-upload">
|
||||||
<div class="dropzone">
|
<div class="dropzone">
|
||||||
@ -493,13 +493,7 @@
|
|||||||
{!! Former::text('pdfupload') !!}
|
{!! Former::text('pdfupload') !!}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if ($account->hasLargeFont())
|
@if (!Utils::hasFeature(FEATURE_MORE_INVOICE_DESIGNS) || \App\Models\InvoiceDesign::count() == COUNT_FREE_DESIGNS_SELF_HOST)
|
||||||
<label for="livePreview" class="control-label" style="padding-right:10px">
|
|
||||||
<input id="livePreview" type="checkbox"/> {{ trans('texts.live_preview') }}
|
|
||||||
</label>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
@if (!Utils::isPro() || \App\Models\InvoiceDesign::count() == COUNT_FREE_DESIGNS_SELF_HOST)
|
|
||||||
{!! Former::select('invoice_design_id')->style('display:inline;width:150px;background-color:white !important')->raw()->fromQuery($invoiceDesigns, 'name', 'id')->data_bind("value: invoice_design_id")->addOption(trans('texts.more_designs') . '...', '-1') !!}
|
{!! Former::select('invoice_design_id')->style('display:inline;width:150px;background-color:white !important')->raw()->fromQuery($invoiceDesigns, 'name', 'id')->data_bind("value: invoice_design_id")->addOption(trans('texts.more_designs') . '...', '-1') !!}
|
||||||
@else
|
@else
|
||||||
{!! Former::select('invoice_design_id')->style('display:inline;width:150px;background-color:white !important')->raw()->fromQuery($invoiceDesigns, 'name', 'id')->data_bind("value: invoice_design_id") !!}
|
{!! Former::select('invoice_design_id')->style('display:inline;width:150px;background-color:white !important')->raw()->fromQuery($invoiceDesigns, 'name', 'id')->data_bind("value: invoice_design_id") !!}
|
||||||
@ -571,7 +565,7 @@
|
|||||||
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
@if (Auth::user()->isPro())
|
@if (Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS))
|
||||||
@if ($account->custom_client_label1)
|
@if ($account->custom_client_label1)
|
||||||
{!! Former::text('client[custom_value1]')
|
{!! Former::text('client[custom_value1]')
|
||||||
->label($account->custom_client_label1)
|
->label($account->custom_client_label1)
|
||||||
@ -626,7 +620,7 @@
|
|||||||
->addClass('client-email') !!}
|
->addClass('client-email') !!}
|
||||||
{!! Former::text('phone')->data_bind("value: phone, valueUpdate: 'afterkeydown',
|
{!! Former::text('phone')->data_bind("value: phone, valueUpdate: 'afterkeydown',
|
||||||
attr: {name: 'client[contacts][' + \$index() + '][phone]'}") !!}
|
attr: {name: 'client[contacts][' + \$index() + '][phone]'}") !!}
|
||||||
@if ($account->isPro() && $account->enable_portal_password)
|
@if ($account->hasFeature(FEATURE_CLIENT_PORTAL_PASSWORD) && $account->enable_portal_password)
|
||||||
{!! Former::password('password')->data_bind("value: (typeof password=='function'?password():null)?'-%unchanged%-':'', valueUpdate: 'afterkeydown',
|
{!! Former::password('password')->data_bind("value: (typeof password=='function'?password():null)?'-%unchanged%-':'', valueUpdate: 'afterkeydown',
|
||||||
attr: {name: 'client[contacts][' + \$index() + '][password]'}") !!}
|
attr: {name: 'client[contacts][' + \$index() + '][password]'}") !!}
|
||||||
@endif
|
@endif
|
||||||
@ -966,7 +960,7 @@
|
|||||||
|
|
||||||
applyComboboxListeners();
|
applyComboboxListeners();
|
||||||
|
|
||||||
@if (Auth::user()->account->isPro())
|
@if (Auth::user()->account->hasFeature(FEATURE_DOCUMENTS))
|
||||||
$('.main-form').submit(function(){
|
$('.main-form').submit(function(){
|
||||||
if($('#document-upload .dropzone .fallback input').val())$(this).attr('enctype', 'multipart/form-data')
|
if($('#document-upload .dropzone .fallback input').val())$(this).attr('enctype', 'multipart/form-data')
|
||||||
else $(this).removeAttr('enctype')
|
else $(this).removeAttr('enctype')
|
||||||
@ -1062,7 +1056,11 @@
|
|||||||
var model = ko.toJS(window.model);
|
var model = ko.toJS(window.model);
|
||||||
if(!model)return;
|
if(!model)return;
|
||||||
var invoice = model.invoice;
|
var invoice = model.invoice;
|
||||||
invoice.is_pro = {{ Auth::user()->isPro() ? 'true' : 'false' }};
|
invoice.features = {
|
||||||
|
customize_invoice_design:{{ Auth::user()->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN) ? 'true' : 'false' }},
|
||||||
|
remove_created_by:{{ Auth::user()->hasFeature(FEATURE_REMOVE_CREATED_BY) ? 'true' : 'false' }},
|
||||||
|
invoice_settings:{{ Auth::user()->hasFeature(FEATURE_INVOICE_SETTINGS) ? 'true' : 'false' }}
|
||||||
|
};
|
||||||
invoice.is_quote = {{ $entityType == ENTITY_QUOTE ? 'true' : 'false' }};
|
invoice.is_quote = {{ $entityType == ENTITY_QUOTE ? 'true' : 'false' }};
|
||||||
invoice.contact = _.findWhere(invoice.client.contacts, {send_invoice: true});
|
invoice.contact = _.findWhere(invoice.client.contacts, {send_invoice: true});
|
||||||
|
|
||||||
@ -1097,8 +1095,8 @@
|
|||||||
|
|
||||||
window.generatedPDF = false;
|
window.generatedPDF = false;
|
||||||
function getPDFString(cb, force) {
|
function getPDFString(cb, force) {
|
||||||
@if ($account->hasLargeFont())
|
@if (!$account->live_preview)
|
||||||
if (!$('#livePreview').is(':checked') && window.generatedPDF) {
|
if (window.generatedPDF) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@endif
|
@endif
|
||||||
@ -1375,7 +1373,7 @@
|
|||||||
model.invoice().invoice_number(number);
|
model.invoice().invoice_number(number);
|
||||||
}
|
}
|
||||||
|
|
||||||
@if ($account->isPro())
|
@if ($account->hasFeature(FEATURE_DOCUMENTS))
|
||||||
function handleDocumentAdded(file){
|
function handleDocumentAdded(file){
|
||||||
if(file.mock)return;
|
if(file.mock)return;
|
||||||
file.index = model.invoice().documents().length;
|
file.index = model.invoice().documents().length;
|
||||||
@ -1399,7 +1397,7 @@
|
|||||||
@endif
|
@endif
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@if ($account->isPro() && $account->invoice_embed_documents)
|
@if ($account->hasFeature(FEATURE_DOCUMENTS) && $account->invoice_embed_documents)
|
||||||
@foreach ($invoice->documents as $document)
|
@foreach ($invoice->documents as $document)
|
||||||
@if($document->isPDFEmbeddable())
|
@if($document->isPDFEmbeddable())
|
||||||
<script src="{{ $document->getVFSJSUrl() }}" type="text/javascript" async></script>
|
<script src="{{ $document->getVFSJSUrl() }}" type="text/javascript" async></script>
|
||||||
|
@ -57,7 +57,7 @@
|
|||||||
|
|
||||||
@include('invoices.pdf', ['account' => Auth::user()->account, 'pdfHeight' => 800])
|
@include('invoices.pdf', ['account' => Auth::user()->account, 'pdfHeight' => 800])
|
||||||
|
|
||||||
@if (Utils::isPro() && $invoice->account->invoice_embed_documents)
|
@if (Utils::hasFeature(FEATURE_DOCUMENTS) && $invoice->account->invoice_embed_documents)
|
||||||
@foreach ($invoice->documents as $document)
|
@foreach ($invoice->documents as $document)
|
||||||
@if($document->isPDFEmbeddable())
|
@if($document->isPDFEmbeddable())
|
||||||
<script src="{{ $document->getVFSJSUrl() }}" type="text/javascript" async></script>
|
<script src="{{ $document->getVFSJSUrl() }}" type="text/javascript" async></script>
|
||||||
|
@ -84,7 +84,7 @@
|
|||||||
@endif
|
@endif
|
||||||
|
|
||||||
var NINJA = NINJA || {};
|
var NINJA = NINJA || {};
|
||||||
@if ($account->isPro())
|
@if ($account->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN))
|
||||||
NINJA.primaryColor = "{{ $account->primary_color }}";
|
NINJA.primaryColor = "{{ $account->primary_color }}";
|
||||||
NINJA.secondaryColor = "{{ $account->secondary_color }}";
|
NINJA.secondaryColor = "{{ $account->secondary_color }}";
|
||||||
NINJA.fontSize = {{ $account->font_size }};
|
NINJA.fontSize = {{ $account->font_size }};
|
||||||
|
@ -65,7 +65,7 @@
|
|||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if ($account->isPro() && $account->invoice_embed_documents)
|
@if ($account->hasFeature(FEATURE_DOCUMENTS) && $account->invoice_embed_documents)
|
||||||
@foreach ($invoice->documents as $document)
|
@foreach ($invoice->documents as $document)
|
||||||
@if($document->isPDFEmbeddable())
|
@if($document->isPDFEmbeddable())
|
||||||
<script src="{{ $document->getClientVFSJSUrl() }}" type="text/javascript" async></script>
|
<script src="{{ $document->getClientVFSJSUrl() }}" type="text/javascript" async></script>
|
||||||
@ -82,7 +82,11 @@
|
|||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
window.invoice = {!! $invoice->toJson() !!};
|
window.invoice = {!! $invoice->toJson() !!};
|
||||||
invoice.is_pro = {{ $invoice->client->account->isPro() ? 'true' : 'false' }};
|
invoice.features = {
|
||||||
|
customize_invoice_design:{{ $invoice->client->account->hasFeature(FEATURE_CUSTOMIZE_INVOICE_DESIGN) ? 'true' : 'false' }},
|
||||||
|
remove_created_by:{{ $invoice->client->account->hasFeature(FEATURE_REMOVE_CREATED_BY) ? 'true' : 'false' }},
|
||||||
|
invoice_settings:{{ $invoice->client->account->hasFeature(FEATURE_INVOICE_SETTINGS) ? 'true' : 'false' }}
|
||||||
|
};
|
||||||
invoice.is_quote = {{ $invoice->is_quote ? 'true' : 'false' }};
|
invoice.is_quote = {{ $invoice->is_quote ? 'true' : 'false' }};
|
||||||
invoice.contact = {!! $contact->toJson() !!};
|
invoice.contact = {!! $contact->toJson() !!};
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
<div id="top_right_buttons" class="pull-right">
|
<div id="top_right_buttons" class="pull-right">
|
||||||
<input id="tableFilter" type="text" style="width:140px;margin-right:17px;background-color: white !important"
|
<input id="tableFilter" type="text" style="width:140px;margin-right:17px;background-color: white !important"
|
||||||
class="form-control pull-left" placeholder="{{ trans('texts.filter') }}" value="{{ Input::get('filter') }}"/>
|
class="form-control pull-left" placeholder="{{ trans('texts.filter') }}" value="{{ Input::get('filter') }}"/>
|
||||||
@if (Auth::user()->isPro() && $entityType == ENTITY_INVOICE)
|
@if (Auth::user()->hasFeature(FEATURE_QUOTES) && $entityType == ENTITY_INVOICE)
|
||||||
{!! Button::normal(trans('texts.quotes'))->asLinkTo(URL::to('/quotes'))->appendIcon(Icon::create('list')) !!}
|
{!! Button::normal(trans('texts.quotes'))->asLinkTo(URL::to('/quotes'))->appendIcon(Icon::create('list')) !!}
|
||||||
{!! Button::normal(trans('texts.recurring'))->asLinkTo(URL::to('/recurring_invoices'))->appendIcon(Icon::create('list')) !!}
|
{!! Button::normal(trans('texts.recurring'))->asLinkTo(URL::to('/recurring_invoices'))->appendIcon(Icon::create('list')) !!}
|
||||||
@elseif ($entityType == ENTITY_EXPENSE)
|
@elseif ($entityType == ENTITY_EXPENSE)
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
Button::success(trans('texts.run'))->withAttributes(array('id' => 'submitButton'))->submit()->appendIcon(Icon::create('play'))
|
Button::success(trans('texts.run'))->withAttributes(array('id' => 'submitButton'))->submit()->appendIcon(Icon::create('play'))
|
||||||
) !!}
|
) !!}
|
||||||
|
|
||||||
@if (!Auth::user()->isPro())
|
@if (!Auth::user()->hasFeature(FEATURE_REPORTS))
|
||||||
<script>
|
<script>
|
||||||
$(function() {
|
$(function() {
|
||||||
$('form.warn-on-exit').find('input, button').prop('disabled', true);
|
$('form.warn-on-exit').find('input, button').prop('disabled', true);
|
||||||
|
@ -268,7 +268,7 @@
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
var dayInSeconds = 1000*60*60*24;
|
var dayInSeconds = 1000*60*60*24;
|
||||||
@if (Auth::user()->account->isPro())
|
@if (Auth::user()->account->hasFeature(FEATURE_REPORTS))
|
||||||
var date = convertToJsDate(invoice.created_at);
|
var date = convertToJsDate(invoice.created_at);
|
||||||
@else
|
@else
|
||||||
var date = new Date().getTime() - (dayInSeconds * Math.random() * 100);
|
var date = new Date().getTime() - (dayInSeconds * Math.random() * 100);
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@if (Utils::hasFeature(FEATURE_USER_PERMISSIONS))
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading">
|
<div class="panel-heading">
|
||||||
<h3 class="panel-title">{!! trans('texts.permissions') !!}</h3>
|
<h3 class="panel-title">{!! trans('texts.permissions') !!}</h3>
|
||||||
@ -59,6 +60,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
{!! Former::actions(
|
{!! Former::actions(
|
||||||
Button::normal(trans('texts.cancel'))->asLinkTo(URL::to('/settings/user_management'))->appendIcon(Icon::create('remove-circle'))->large(),
|
Button::normal(trans('texts.cancel'))->asLinkTo(URL::to('/settings/user_management'))->appendIcon(Icon::create('remove-circle'))->large(),
|
||||||
|
38
resources/views/vendors/edit.blade.php
vendored
38
resources/views/vendors/edit.blade.php
vendored
@ -114,15 +114,43 @@
|
|||||||
{!! Former::textarea('private_notes')->rows(6) !!}
|
{!! Former::textarea('private_notes')->rows(6) !!}
|
||||||
|
|
||||||
|
|
||||||
@if (isset($proPlanPaid))
|
@if (Auth::user()->account->isNinjaAccount())
|
||||||
{!! Former::populateField('pro_plan_paid', $proPlanPaid) !!}
|
@if (isset($planDetails))
|
||||||
{!! Former::text('pro_plan_paid')
|
{!! Former::populateField('plan', $planDetails['plan']) !!}
|
||||||
|
{!! Former::populateField('plan_term', $planDetails['term']) !!}
|
||||||
|
@if (!empty($planDetails['paid']))
|
||||||
|
{!! Former::populateField('plan_paid', $planDetails['paid']->format('Y-m-d')) !!}
|
||||||
|
@endif
|
||||||
|
@if (!empty($planDetails['expires']))
|
||||||
|
{!! Former::populateField('plan_expires', $planDetails['expires']->format('Y-m-d')) !!}
|
||||||
|
@endif
|
||||||
|
@if (!empty($planDetails['started']))
|
||||||
|
{!! Former::populateField('plan_started', $planDetails['started']->format('Y-m-d')) !!}
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
{!! Former::select('plan')
|
||||||
|
->addOption(trans('texts.plan_free'), PLAN_FREE)
|
||||||
|
->addOption(trans('texts.plan_pro'), PLAN_PRO)
|
||||||
|
->addOption(trans('texts.plan_enterprise'), PLAN_ENTERPRISE)!!}
|
||||||
|
{!! Former::select('plan_term')
|
||||||
|
->addOption()
|
||||||
|
->addOption(trans('texts.plan_term_yearly'), PLAN_TERM_YEARLY)
|
||||||
|
->addOption(trans('texts.plan_term_monthly'), PLAN_TERM_MONTHLY)!!}
|
||||||
|
{!! Former::text('plan_started')
|
||||||
->data_date_format('yyyy-mm-dd')
|
->data_date_format('yyyy-mm-dd')
|
||||||
->addGroupClass('pro_plan_paid_date')
|
->addGroupClass('plan_start_date')
|
||||||
|
->append('<i class="glyphicon glyphicon-calendar"></i>') !!}
|
||||||
|
{!! Former::text('plan_paid')
|
||||||
|
->data_date_format('yyyy-mm-dd')
|
||||||
|
->addGroupClass('plan_paid_date')
|
||||||
|
->append('<i class="glyphicon glyphicon-calendar"></i>') !!}
|
||||||
|
{!! Former::text('plan_expires')
|
||||||
|
->data_date_format('yyyy-mm-dd')
|
||||||
|
->addGroupClass('plan_expire_date')
|
||||||
->append('<i class="glyphicon glyphicon-calendar"></i>') !!}
|
->append('<i class="glyphicon glyphicon-calendar"></i>') !!}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function() {
|
$(function() {
|
||||||
$('#pro_plan_paid').datepicker();
|
$('#plan_started, #plan_paid, #plan_expires').datepicker();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@endif
|
@endif
|
||||||
|
Loading…
Reference in New Issue
Block a user