diff --git a/app/Commands/Command.php b/app/Commands/Command.php
index 018bc21924..5bc4850116 100644
--- a/app/Commands/Command.php
+++ b/app/Commands/Command.php
@@ -1,7 +1,6 @@
-where('client_id', '=', $client->id)
->orderBy('activities.id')
- ->get(['activities.id', 'activities.created_at', 'activities.activity_type_id', 'activities.message', 'activities.adjustment', 'activities.balance', 'activities.invoice_id']);
+ ->get(['activities.id', 'activities.created_at', 'activities.activity_type_id', 'activities.adjustment', 'activities.balance', 'activities.invoice_id']);
//$this->info(var_dump($activities));
foreach ($activities as $activity) {
@@ -235,7 +235,6 @@ class CheckData extends Command {
'updated_at' => new Carbon,
'account_id' => $client->account_id,
'client_id' => $client->id,
- 'message' => 'Corrected client balance',
'adjustment' => $client->actual_balance - $activity->balance,
'balance' => $client->actual_balance,
]);
diff --git a/app/Console/Commands/CreateRandomData.php b/app/Console/Commands/CreateRandomData.php
deleted file mode 100644
index de4da39cbe..0000000000
--- a/app/Console/Commands/CreateRandomData.php
+++ /dev/null
@@ -1,88 +0,0 @@
-info(date('Y-m-d') . ' Running CreateRandomData...');
-
- $user = User::first();
-
- if (!$user) {
- $this->error("Error: please create user account by logging in");
- return;
- }
-
- $productNames = ['Arkansas', 'New York', 'Arizona', 'California', 'Colorado', 'Alabama', 'Connecticut', 'Delaware', 'Florida', 'Georgia', 'Hawaii', 'Idaho', 'Illinois', 'Indiana', 'Iowa', 'Kansas', 'Kentucky', 'Louisiana', 'Maine', 'Maryland', 'Massachusetts', 'Michigan', 'Minnesota', 'Mississippi', 'Missouri', 'Montana', 'Nebraska', 'Nevada', 'New Hampshire', 'New Jersey', 'New Mexico', 'Alaska', 'North Carolina', 'North Dakota', 'Ohio', 'Oklahoma', 'Oregon', 'Pennsylvania', 'Rhode Island', 'South Carolina', 'South Dakota', 'Tennessee', 'Texas', 'Utah', 'Vermont', 'Virginia', 'Washington', 'West Virginia', 'Wisconsin', 'Wyoming'];
- $clientNames = ['IBM', 'Nestle', 'Mitsubishi UFJ Financial', 'Vodafone', 'Eni', 'Procter & Gamble', 'Johnson & Johnson', 'American International Group', 'Banco Santander', 'BHP Billiton', 'Pfizer', 'Itaú Unibanco Holding', 'Ford Motor', 'BMW Group', 'Commonwealth Bank', 'EDF', 'Statoil', 'Google', 'Siemens', 'Novartis', 'Royal Bank of Canada', 'Sumitomo Mitsui Financial', 'Comcast', 'Sberbank', 'Goldman Sachs Group', 'Westpac Banking Group', 'Nippon Telegraph & Tel', 'Ping An Insurance Group', 'Banco Bradesco', 'Anheuser-Busch InBev', 'Bank of Communications', 'China Life Insurance', 'General Motors', 'Telefónica', 'MetLife', 'Honda Motor', 'Enel', 'BASF', 'Softbank', 'National Australia Bank', 'ANZ', 'ConocoPhillips', 'TD Bank Group', 'Intel', 'UBS', 'Hewlett-Packard', 'Coca-Cola', 'Cisco Systems', 'UnitedHealth Group', 'Boeing', 'Zurich Insurance Group', 'Hyundai Motor', 'Sanofi', 'Credit Agricole', 'United Technologies', 'Roche Holding', 'Munich Re', 'PepsiCo', 'Oracle', 'Bank of Nova Scotia'];
-
- foreach ($productNames as $i => $value) {
- $product = Product::createNew($user);
- $product->id = $i+1;
- $product->product_key = $value;
- $product->save();
- }
-
- foreach ($clientNames as $i => $value) {
- $client = Client::createNew($user);
- $client->name = $value;
- $client->save();
-
- $contact = Contact::createNew($user);
- $contact->email = "client@aol.com";
- $contact->is_primary = 1;
- $client->contacts()->save($contact);
-
- $numInvoices = rand(1, 25);
- if ($numInvoices == 4 || $numInvoices == 10 || $numInvoices == 25) {
- // leave these
- } else if ($numInvoices % 3 == 0) {
- $numInvoices = 1;
- } else if ($numInvoices > 10) {
- $numInvoices = $numInvoices % 2;
- }
-
- $paidUp = rand(0, 1) == 1;
-
- for ($j=1; $j<=$numInvoices; $j++) {
-
- $price = rand(10, 1000);
- if ($price < 900) {
- $price = rand(10, 150);
- }
-
- $invoice = Invoice::createNew($user);
- $invoice->invoice_number = $user->account->getNextInvoiceNumber($invoice);
- $invoice->amount = $invoice->balance = $price;
- $invoice->created_at = date('Y-m-d', strtotime(date("Y-m-d") . ' - ' . rand(1, 100) . ' days'));
- $client->invoices()->save($invoice);
-
- $productId = rand(0, 40);
- if ($productId > 20) {
- $productId = ($productId % 2) + rand(0, 2);
- }
-
- $invoiceItem = InvoiceItem::createNew($user);
- $invoiceItem->product_id = $productId+1;
- $invoiceItem->product_key = $productNames[$invoiceItem->product_id];
- $invoiceItem->cost = $invoice->amount;
- $invoiceItem->qty = 1;
- $invoice->invoice_items()->save($invoiceItem);
-
- if ($paidUp || rand(0,2) > 1) {
- $payment = Payment::createNew($user);
- $payment->invoice_id = $invoice->id;
- $payment->amount = $invoice->amount;
- $client->payments()->save($payment);
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php
index fd97865bea..03b6ce7764 100644
--- a/app/Console/Kernel.php
+++ b/app/Console/Kernel.php
@@ -13,7 +13,6 @@ class Kernel extends ConsoleKernel
*/
protected $commands = [
'App\Console\Commands\SendRecurringInvoices',
- 'App\Console\Commands\CreateRandomData',
'App\Console\Commands\ResetData',
'App\Console\Commands\CheckData',
'App\Console\Commands\SendRenewalInvoices',
diff --git a/app/Events/ClientWasArchived.php b/app/Events/ClientWasArchived.php
new file mode 100644
index 0000000000..03ebdc09cd
--- /dev/null
+++ b/app/Events/ClientWasArchived.php
@@ -0,0 +1,21 @@
+client = $client;
+ }
+}
diff --git a/app/Events/ClientWasCreated.php b/app/Events/ClientWasCreated.php
new file mode 100644
index 0000000000..5c2d370017
--- /dev/null
+++ b/app/Events/ClientWasCreated.php
@@ -0,0 +1,21 @@
+client = $client;
+ }
+}
diff --git a/app/Events/ClientWasDeleted.php b/app/Events/ClientWasDeleted.php
new file mode 100644
index 0000000000..b87063c497
--- /dev/null
+++ b/app/Events/ClientWasDeleted.php
@@ -0,0 +1,21 @@
+client = $client;
+ }
+}
diff --git a/app/Events/ClientWasRestored.php b/app/Events/ClientWasRestored.php
new file mode 100644
index 0000000000..385a0472ab
--- /dev/null
+++ b/app/Events/ClientWasRestored.php
@@ -0,0 +1,21 @@
+client = $client;
+ }
+}
diff --git a/app/Events/ClientWasUpdated.php b/app/Events/ClientWasUpdated.php
new file mode 100644
index 0000000000..7e4790da68
--- /dev/null
+++ b/app/Events/ClientWasUpdated.php
@@ -0,0 +1,21 @@
+client = $client;
+ }
+}
diff --git a/app/Events/CreditWasArchived.php b/app/Events/CreditWasArchived.php
new file mode 100644
index 0000000000..2c680905b3
--- /dev/null
+++ b/app/Events/CreditWasArchived.php
@@ -0,0 +1,23 @@
+credit = $credit;
+ }
+
+}
diff --git a/app/Events/CreditWasCreated.php b/app/Events/CreditWasCreated.php
new file mode 100644
index 0000000000..bc20b312dc
--- /dev/null
+++ b/app/Events/CreditWasCreated.php
@@ -0,0 +1,23 @@
+credit = $credit;
+ }
+
+}
diff --git a/app/Events/CreditWasDeleted.php b/app/Events/CreditWasDeleted.php
new file mode 100644
index 0000000000..e26a5d3ab0
--- /dev/null
+++ b/app/Events/CreditWasDeleted.php
@@ -0,0 +1,23 @@
+credit = $credit;
+ }
+
+}
diff --git a/app/Events/CreditWasRestored.php b/app/Events/CreditWasRestored.php
new file mode 100644
index 0000000000..8d17d961e7
--- /dev/null
+++ b/app/Events/CreditWasRestored.php
@@ -0,0 +1,23 @@
+credit = $credit;
+ }
+
+}
diff --git a/app/Events/InvoiceInvitationWasEmailed.php b/app/Events/InvoiceInvitationWasEmailed.php
new file mode 100644
index 0000000000..1a602c867e
--- /dev/null
+++ b/app/Events/InvoiceInvitationWasEmailed.php
@@ -0,0 +1,25 @@
+invoice = $invoice;
+ $this->invitation = $invitation;
+ }
+
+}
diff --git a/app/Events/InvoiceInvitationWasViewed.php b/app/Events/InvoiceInvitationWasViewed.php
new file mode 100644
index 0000000000..bbf7e23c33
--- /dev/null
+++ b/app/Events/InvoiceInvitationWasViewed.php
@@ -0,0 +1,25 @@
+invoice = $invoice;
+ $this->invitation = $invitation;
+ }
+
+}
diff --git a/app/Events/InvoiceWasArchived.php b/app/Events/InvoiceWasArchived.php
new file mode 100644
index 0000000000..7587c071a6
--- /dev/null
+++ b/app/Events/InvoiceWasArchived.php
@@ -0,0 +1,22 @@
+invoice = $invoice;
+ }
+
+}
diff --git a/app/Events/InvoiceSent.php b/app/Events/InvoiceWasCreated.php
similarity index 88%
rename from app/Events/InvoiceSent.php
rename to app/Events/InvoiceWasCreated.php
index cbe08d0528..cfd943bcff 100644
--- a/app/Events/InvoiceSent.php
+++ b/app/Events/InvoiceWasCreated.php
@@ -4,10 +4,9 @@ use App\Events\Event;
use Illuminate\Queue\SerializesModels;
-class InvoiceSent extends Event {
+class InvoiceWasCreated extends Event {
use SerializesModels;
-
public $invoice;
/**
diff --git a/app/Events/InvoiceViewed.php b/app/Events/InvoiceWasDeleted.php
similarity index 61%
rename from app/Events/InvoiceViewed.php
rename to app/Events/InvoiceWasDeleted.php
index 8d9f129e76..316b1b5c50 100644
--- a/app/Events/InvoiceViewed.php
+++ b/app/Events/InvoiceWasDeleted.php
@@ -4,10 +4,9 @@ use App\Events\Event;
use Illuminate\Queue\SerializesModels;
-class InvoiceViewed extends Event {
+class InvoiceWasDeleted extends Event {
use SerializesModels;
-
public $invoice;
/**
@@ -15,9 +14,9 @@ class InvoiceViewed extends Event {
*
* @return void
*/
- public function __construct($invoice)
- {
- $this->invoice = $invoice;
- }
+ public function __construct($invoice)
+ {
+ $this->invoice = $invoice;
+ }
}
diff --git a/app/Events/InvoiceWasEmailed.php b/app/Events/InvoiceWasEmailed.php
new file mode 100644
index 0000000000..dc30f6a558
--- /dev/null
+++ b/app/Events/InvoiceWasEmailed.php
@@ -0,0 +1,22 @@
+invoice = $invoice;
+ }
+
+}
diff --git a/app/Events/InvoiceWasRestored.php b/app/Events/InvoiceWasRestored.php
new file mode 100644
index 0000000000..35c646612e
--- /dev/null
+++ b/app/Events/InvoiceWasRestored.php
@@ -0,0 +1,22 @@
+invoice = $invoice;
+ }
+
+}
diff --git a/app/Events/QuoteApproved.php b/app/Events/InvoiceWasUpdated.php
similarity index 87%
rename from app/Events/QuoteApproved.php
rename to app/Events/InvoiceWasUpdated.php
index 12b5384b35..87a0f8f201 100644
--- a/app/Events/QuoteApproved.php
+++ b/app/Events/InvoiceWasUpdated.php
@@ -4,10 +4,9 @@ use App\Events\Event;
use Illuminate\Queue\SerializesModels;
-class QuoteApproved extends Event {
+class InvoiceWasUpdated extends Event {
use SerializesModels;
-
public $invoice;
/**
diff --git a/app/Events/InvoicePaid.php b/app/Events/PaymentWasArchived.php
similarity index 87%
rename from app/Events/InvoicePaid.php
rename to app/Events/PaymentWasArchived.php
index 4dced73471..b8bb693dfc 100644
--- a/app/Events/InvoicePaid.php
+++ b/app/Events/PaymentWasArchived.php
@@ -4,10 +4,9 @@ use App\Events\Event;
use Illuminate\Queue\SerializesModels;
-class InvoicePaid extends Event {
+class PaymentWasArchived extends Event {
use SerializesModels;
-
public $payment;
/**
diff --git a/app/Events/PaymentWasCreated.php b/app/Events/PaymentWasCreated.php
new file mode 100644
index 0000000000..619d33e958
--- /dev/null
+++ b/app/Events/PaymentWasCreated.php
@@ -0,0 +1,22 @@
+payment = $payment;
+ }
+
+}
diff --git a/app/Events/PaymentWasDeleted.php b/app/Events/PaymentWasDeleted.php
new file mode 100644
index 0000000000..e12647c860
--- /dev/null
+++ b/app/Events/PaymentWasDeleted.php
@@ -0,0 +1,22 @@
+payment = $payment;
+ }
+
+}
diff --git a/app/Events/PaymentWasRestored.php b/app/Events/PaymentWasRestored.php
new file mode 100644
index 0000000000..b4198aab4f
--- /dev/null
+++ b/app/Events/PaymentWasRestored.php
@@ -0,0 +1,22 @@
+payment = $payment;
+ }
+
+}
diff --git a/app/Events/QuoteInvitationWasApproved.php b/app/Events/QuoteInvitationWasApproved.php
new file mode 100644
index 0000000000..954aa83b4c
--- /dev/null
+++ b/app/Events/QuoteInvitationWasApproved.php
@@ -0,0 +1,25 @@
+quote = $quote;
+ $this->invitation = $invitation;
+ }
+
+}
diff --git a/app/Events/QuoteInvitationWasEmailed.php b/app/Events/QuoteInvitationWasEmailed.php
new file mode 100644
index 0000000000..ce1b87d4a7
--- /dev/null
+++ b/app/Events/QuoteInvitationWasEmailed.php
@@ -0,0 +1,25 @@
+quote = $quote;
+ $this->invitation = $invitation;
+ }
+
+}
diff --git a/app/Events/QuoteInvitationWasViewed.php b/app/Events/QuoteInvitationWasViewed.php
new file mode 100644
index 0000000000..3cd84b0e11
--- /dev/null
+++ b/app/Events/QuoteInvitationWasViewed.php
@@ -0,0 +1,25 @@
+quote = $quote;
+ $this->invitation = $invitation;
+ }
+
+}
diff --git a/app/Events/QuoteWasArchived.php b/app/Events/QuoteWasArchived.php
new file mode 100644
index 0000000000..285a61250c
--- /dev/null
+++ b/app/Events/QuoteWasArchived.php
@@ -0,0 +1,22 @@
+quote = $quote;
+ }
+
+}
diff --git a/app/Events/QuoteWasCreated.php b/app/Events/QuoteWasCreated.php
new file mode 100644
index 0000000000..d17ef9c131
--- /dev/null
+++ b/app/Events/QuoteWasCreated.php
@@ -0,0 +1,22 @@
+quote = $quote;
+ }
+
+}
diff --git a/app/Events/QuoteWasDeleted.php b/app/Events/QuoteWasDeleted.php
new file mode 100644
index 0000000000..ce3685d7a2
--- /dev/null
+++ b/app/Events/QuoteWasDeleted.php
@@ -0,0 +1,22 @@
+quote = $quote;
+ }
+
+}
diff --git a/app/Events/QuoteWasEmailed.php b/app/Events/QuoteWasEmailed.php
new file mode 100644
index 0000000000..19b1ec12d6
--- /dev/null
+++ b/app/Events/QuoteWasEmailed.php
@@ -0,0 +1,22 @@
+quote = $quote;
+ }
+
+}
diff --git a/app/Events/QuoteWasRestored.php b/app/Events/QuoteWasRestored.php
new file mode 100644
index 0000000000..0f13a65b43
--- /dev/null
+++ b/app/Events/QuoteWasRestored.php
@@ -0,0 +1,22 @@
+quote = $quote;
+ }
+
+}
diff --git a/app/Events/QuoteWasUpdated.php b/app/Events/QuoteWasUpdated.php
new file mode 100644
index 0000000000..f01b982260
--- /dev/null
+++ b/app/Events/QuoteWasUpdated.php
@@ -0,0 +1,22 @@
+quote = $quote;
+ }
+
+}
diff --git a/app/Http/Controllers/AccountController.php b/app/Http/Controllers/AccountController.php
index d4a358ebcf..8431076731 100644
--- a/app/Http/Controllers/AccountController.php
+++ b/app/Http/Controllers/AccountController.php
@@ -45,6 +45,8 @@ use App\Events\UserLoggedIn;
use App\Events\UserSettingsChanged;
use App\Services\AuthService;
+use App\Commands\CreateClient;
+
class AccountController extends BaseController
{
protected $accountRepo;
@@ -637,49 +639,56 @@ class AccountController extends BaseController
continue;
}
- $client = Client::createNew();
- $contact = Contact::createNew();
- $contact->is_primary = true;
- $contact->send_invoice = true;
- $count++;
+ $data = [
+ 'contacts' => [[]]
+ ];
foreach ($row as $index => $value) {
$field = $map[$index];
- $value = trim($value);
+ if ( ! $value = trim($value)) {
+ continue;
+ }
- if ($field == Client::$fieldName && !$client->name) {
- $client->name = $value;
- } elseif ($field == Client::$fieldPhone && !$client->work_phone) {
- $client->work_phone = $value;
- } elseif ($field == Client::$fieldAddress1 && !$client->address1) {
- $client->address1 = $value;
- } elseif ($field == Client::$fieldAddress2 && !$client->address2) {
- $client->address2 = $value;
- } elseif ($field == Client::$fieldCity && !$client->city) {
- $client->city = $value;
- } elseif ($field == Client::$fieldState && !$client->state) {
- $client->state = $value;
- } elseif ($field == Client::$fieldPostalCode && !$client->postal_code) {
- $client->postal_code = $value;
- } elseif ($field == Client::$fieldCountry && !$client->country_id) {
+ if ($field == Client::$fieldName) {
+ $data['name'] = $value;
+ } elseif ($field == Client::$fieldPhone) {
+ $data['work_phone'] = $value;
+ } elseif ($field == Client::$fieldAddress1) {
+ $data['address1'] = $value;
+ } elseif ($field == Client::$fieldAddress2) {
+ $data['address2'] = $value;
+ } elseif ($field == Client::$fieldCity) {
+ $data['city'] = $value;
+ } elseif ($field == Client::$fieldState) {
+ $data['state'] = $value;
+ } elseif ($field == Client::$fieldPostalCode) {
+ $data['postal_code'] = $value;
+ } elseif ($field == Client::$fieldCountry) {
$value = strtolower($value);
- $client->country_id = isset($countryMap[$value]) ? $countryMap[$value] : null;
- } elseif ($field == Client::$fieldNotes && !$client->private_notes) {
- $client->private_notes = $value;
- } elseif ($field == Contact::$fieldFirstName && !$contact->first_name) {
- $contact->first_name = $value;
- } elseif ($field == Contact::$fieldLastName && !$contact->last_name) {
- $contact->last_name = $value;
- } elseif ($field == Contact::$fieldPhone && !$contact->phone) {
- $contact->phone = $value;
- } elseif ($field == Contact::$fieldEmail && !$contact->email) {
- $contact->email = strtolower($value);
+ $data['country_id'] = isset($countryMap[$value]) ? $countryMap[$value] : null;
+ } elseif ($field == Client::$fieldNotes) {
+ $data['private_notes'] = $value;
+ } elseif ($field == Contact::$fieldFirstName) {
+ $data['contacts'][0]['first_name'] = $value;
+ } elseif ($field == Contact::$fieldLastName) {
+ $data['contacts'][0]['last_name'] = $value;
+ } elseif ($field == Contact::$fieldPhone) {
+ $data['contacts'][0]['phone'] = $value;
+ } elseif ($field == Contact::$fieldEmail) {
+ $data['contacts'][0]['email'] = strtolower($value);
}
}
- $client->save();
- $client->contacts()->save($contact);
- Activity::createClient($client, false);
+ $rules = [
+ 'contacts' => 'valid_contacts',
+ ];
+ $validator = Validator::make($data, $rules);
+ if ($validator->fails()) {
+ continue;
+ }
+
+ $this->dispatch(new CreateClient($data));
+ $count++;
}
$message = Utils::pluralize('created_client', $count);
diff --git a/app/Http/Controllers/ActivityController.php b/app/Http/Controllers/ActivityController.php
index 39419f227d..02700e2330 100644
--- a/app/Http/Controllers/ActivityController.php
+++ b/app/Http/Controllers/ActivityController.php
@@ -5,20 +5,46 @@ use DB;
use Datatable;
use Utils;
use View;
+use App\Models\Client;
+use App\Models\Activity;
+use App\Ninja\Repositories\ActivityRepository;
class ActivityController extends BaseController
{
+ protected $activityRepo;
+
+ public function __construct(ActivityRepository $activityRepo)
+ {
+ parent::__construct();
+
+ $this->activityRepo = $activityRepo;
+ }
+
public function getDatatable($clientPublicId)
{
- $query = DB::table('activities')
- ->join('clients', 'clients.id', '=', 'activities.client_id')
- ->where('clients.public_id', '=', $clientPublicId)
- ->where('activities.account_id', '=', Auth::user()->account_id)
- ->select('activities.id', 'activities.message', 'activities.created_at', 'clients.currency_id', 'activities.balance', 'activities.adjustment');
+ $clientId = Client::getPrivateId($clientPublicId);
+
+ if ( ! $clientId) {
+ app()->abort(404);
+ }
+
+ $query = $this->activityRepo->findByClientId($clientId);
return Datatable::query($query)
->addColumn('activities.id', function ($model) { return Utils::timestampToDateTimeString(strtotime($model->created_at)); })
- ->addColumn('message', function ($model) { return Utils::decodeActivity($model->message); })
+ ->addColumn('activity_type_id', function ($model) {
+ $data = [
+ 'client' => link_to('/clients/' . $model->client_public_id, Utils::getClientDisplayName($model)),
+ 'user' => $model->is_system ? '' . trans('texts.system') . ' ' : Utils::getPersonDisplayName($model->user_first_name, $model->user_last_name, $model->user_email),
+ 'invoice' => $model->invoice ? link_to('/invoices/' . $model->invoice_public_id, $model->is_recurring ? trans('texts.recurring_invoice') : $model->invoice) : null,
+ 'quote' => $model->invoice ? link_to('/quotes/' . $model->invoice_public_id, $model->invoice) : null,
+ 'contact' => $model->contact_id ? link_to('/clients/' . $model->client_public_id, Utils::getClientDisplayName($model)) : Utils::getPersonDisplayName($model->user_first_name, $model->user_last_name, $model->user_email),
+ 'payment' => $model->payment ?: '',
+ 'credit' => Utils::formatMoney($model->credit, $model->currency_id)
+ ];
+
+ return trans("texts.activity_{$model->activity_type_id}", $data);
+ })
->addColumn('balance', function ($model) { return Utils::formatMoney($model->balance, $model->currency_id); })
->addColumn('adjustment', function ($model) { return $model->adjustment != 0 ? Utils::wrapAdjustment($model->adjustment, $model->currency_id) : ''; })
->make();
diff --git a/app/Http/Controllers/BaseController.php b/app/Http/Controllers/BaseController.php
index 0cc63c7c5a..1a2f6c8dc5 100644
--- a/app/Http/Controllers/BaseController.php
+++ b/app/Http/Controllers/BaseController.php
@@ -1,7 +1,11 @@
clientRepo->getErrors($data);
+ $client = $this->clientRepo->save($request->input());
- if ($error) {
- $headers = Utils::getApiHeaders();
+ $client = Client::scope($client->public_id)->with('country', 'contacts', 'industry', 'size', 'currency')->first();
+ $client = Utils::remapPublicIds([$client]);
+ $response = json_encode($client, JSON_PRETTY_PRINT);
+ $headers = Utils::getApiHeaders();
- return Response::make($error, 500, $headers);
- } else {
- $client = $this->clientRepo->save(isset($data['id']) ? $data['id'] : false, $data, false);
- $client = Client::scope($client->public_id)->with('country', 'contacts', 'industry', 'size', 'currency')->first();
- $client = Utils::remapPublicIds([$client]);
- $response = json_encode($client, JSON_PRETTY_PRINT);
- $headers = Utils::getApiHeaders();
-
- return Response::make($response, 200, $headers);
- }
+ return Response::make($response, 200, $headers);
}
}
diff --git a/app/Http/Controllers/ClientController.php b/app/Http/Controllers/ClientController.php
index 6b168751cb..badcdfc357 100644
--- a/app/Http/Controllers/ClientController.php
+++ b/app/Http/Controllers/ClientController.php
@@ -21,18 +21,23 @@ use App\Models\Industry;
use App\Models\Currency;
use App\Models\Country;
use App\Models\Task;
-
use App\Ninja\Repositories\ClientRepository;
+use App\Services\ClientService;
+
+use App\Http\Requests\CreateClientRequest;
+use App\Http\Requests\UpdateClientRequest;
class ClientController extends BaseController
{
+ protected $clientService;
protected $clientRepo;
- public function __construct(ClientRepository $clientRepo)
+ public function __construct(ClientRepository $clientRepo, ClientService $clientService)
{
parent::__construct();
$this->clientRepo = $clientRepo;
+ $this->clientService = $clientService;
}
/**
@@ -103,9 +108,13 @@ class ClientController extends BaseController
*
* @return Response
*/
- public function store()
+ public function store(CreateClientRequest $request)
{
- return $this->save();
+ $client = $this->clientService->save($request->input());
+
+ Session::flash('message', trans('texts.created_client'));
+
+ return redirect()->to($client->getRoute());
}
/**
@@ -194,6 +203,7 @@ class ClientController extends BaseController
private static function getViewModel()
{
return [
+ 'data' => Input::old('data'),
'account' => Auth::user()->account,
'sizes' => Cache::get('sizes'),
'paymentTerms' => Cache::get('paymentTerms'),
@@ -212,105 +222,20 @@ class ClientController extends BaseController
* @param int $id
* @return Response
*/
- public function update($publicId)
+ public function update(UpdateClientRequest $request)
{
- return $this->save($publicId);
- }
-
- private function save($publicId = null)
- {
- $rules = array(
- 'email' => 'email|required_without:first_name',
- 'first_name' => 'required_without:email',
- );
- $validator = Validator::make(Input::all(), $rules);
-
- if ($validator->fails()) {
- $url = $publicId ? 'clients/'.$publicId.'/edit' : 'clients/create';
-
- return Redirect::to($url)
- ->withErrors($validator)
- ->withInput(Input::except('password'));
- } else {
- if ($publicId) {
- $client = Client::scope($publicId)->firstOrFail();
- } else {
- $client = Client::createNew();
- }
-
- $client->name = trim(Input::get('name'));
- $client->id_number = trim(Input::get('id_number'));
- $client->vat_number = trim(Input::get('vat_number'));
- $client->work_phone = trim(Input::get('work_phone'));
- $client->custom_value1 = trim(Input::get('custom_value1'));
- $client->custom_value2 = trim(Input::get('custom_value2'));
- $client->address1 = trim(Input::get('address1'));
- $client->address2 = trim(Input::get('address2'));
- $client->city = trim(Input::get('city'));
- $client->state = trim(Input::get('state'));
- $client->postal_code = trim(Input::get('postal_code'));
- $client->country_id = Input::get('country_id') ?: null;
- $client->private_notes = trim(Input::get('private_notes'));
- $client->size_id = Input::get('size_id') ?: null;
- $client->industry_id = Input::get('industry_id') ?: null;
- $client->currency_id = Input::get('currency_id') ?: null;
- $client->language_id = Input::get('language_id') ?: null;
- $client->payment_terms = Input::get('payment_terms') ?: 0;
- $client->website = trim(Input::get('website'));
-
- if (Input::has('invoice_number_counter')) {
- $client->invoice_number_counter = (int) Input::get('invoice_number_counter');
- }
- if (Input::has('quote_number_counter')) {
- $client->invoice_number_counter = (int) Input::get('quote_number_counter');
- }
-
- $client->save();
-
- $data = json_decode(Input::get('data'));
- $contactIds = [];
- $isPrimary = true;
-
- foreach ($data->contacts as $contact) {
- if (isset($contact->public_id) && $contact->public_id) {
- $record = Contact::scope($contact->public_id)->firstOrFail();
- } else {
- $record = Contact::createNew();
- }
-
- $record->email = trim($contact->email);
- $record->first_name = trim($contact->first_name);
- $record->last_name = trim($contact->last_name);
- $record->phone = trim($contact->phone);
- $record->is_primary = $isPrimary;
- $isPrimary = false;
-
- $client->contacts()->save($record);
- $contactIds[] = $record->public_id;
- }
-
- foreach ($client->contacts as $contact) {
- if (!in_array($contact->public_id, $contactIds)) {
- $contact->delete();
- }
- }
-
- if ($publicId) {
- Session::flash('message', trans('texts.updated_client'));
- } else {
- Activity::createClient($client);
- Session::flash('message', trans('texts.created_client'));
- }
-
- return Redirect::to('clients/'.$client->public_id);
- }
+ $client = $this->clientService->save($request->input());
+
+ Session::flash('message', trans('texts.updated_client'));
+
+ return redirect()->to($client->getRoute());
}
public function bulk()
{
$action = Input::get('action');
- $ids = Input::get('id') ? Input::get('id') : Input::get('ids');
- $count = $this->clientRepo->bulk($ids, $action);
+ $ids = Input::get('public_id') ? Input::get('public_id') : Input::get('ids');
+ $count = $this->clientService->bulk($ids, $action);
$message = Utils::pluralize($action.'d_client', $count);
Session::flash('message', $message);
diff --git a/app/Http/Controllers/CreditController.php b/app/Http/Controllers/CreditController.php
index 505400718c..ad04651acf 100644
--- a/app/Http/Controllers/CreditController.php
+++ b/app/Http/Controllers/CreditController.php
@@ -8,18 +8,21 @@ use Utils;
use View;
use Validator;
use App\Models\Client;
-
+use App\Services\CreditService;
use App\Ninja\Repositories\CreditRepository;
+use App\Http\Requests\CreateCreditRequest;
class CreditController extends BaseController
{
protected $creditRepo;
+ protected $CreditService;
- public function __construct(CreditRepository $creditRepo)
+ public function __construct(CreditRepository $creditRepo, CreditService $creditService)
{
parent::__construct();
$this->creditRepo = $creditRepo;
+ $this->creditService = $creditService;
}
/**
@@ -106,46 +109,20 @@ class CreditController extends BaseController
return View::make('credit.edit', $data);
}
- public function store()
+ public function store(CreateCreditRequest $request)
{
- return $this->save();
- }
-
- public function update($publicId)
- {
- return $this->save($publicId);
- }
-
- private function save($publicId = null)
- {
- $rules = array(
- 'client' => 'required',
- 'amount' => 'required|positive',
- );
-
- $validator = Validator::make(Input::all(), $rules);
-
- if ($validator->fails()) {
- $url = $publicId ? 'credits/'.$publicId.'/edit' : 'credits/create';
-
- return Redirect::to($url)
- ->withErrors($validator)
- ->withInput();
- } else {
- $this->creditRepo->save($publicId, Input::all());
-
- $message = trans('texts.created_credit');
- Session::flash('message', $message);
-
- return Redirect::to('clients/'.Input::get('client'));
- }
+ $credit = $this->creditRepo->save($request->input());
+
+ Session::flash('message', trans('texts.created_credit'));
+
+ return redirect()->to($credit->client->getRoute());
}
public function bulk()
{
$action = Input::get('action');
- $ids = Input::get('id') ? Input::get('id') : Input::get('ids');
- $count = $this->creditRepo->bulk($ids, $action);
+ $ids = Input::get('public_id') ? Input::get('public_id') : Input::get('ids');
+ $count = $this->creditService->bulk($ids, $action);
if ($count > 0) {
$message = Utils::pluralize($action.'d_credit', $count);
diff --git a/app/Http/Controllers/DashboardController.php b/app/Http/Controllers/DashboardController.php
index 0b72d36691..a8b31fdb8a 100644
--- a/app/Http/Controllers/DashboardController.php
+++ b/app/Http/Controllers/DashboardController.php
@@ -62,6 +62,7 @@ class DashboardController extends BaseController
->get();
$activities = Activity::where('activities.account_id', '=', Auth::user()->account_id)
+ ->with('client.contacts', 'user', 'invoice', 'payment', 'credit')
->where('activity_type_id', '>', 0)
->orderBy('created_at', 'desc')
->take(50)
diff --git a/app/Http/Controllers/InvoiceApiController.php b/app/Http/Controllers/InvoiceApiController.php
index d3bb9b44bf..2a9bae80ea 100644
--- a/app/Http/Controllers/InvoiceApiController.php
+++ b/app/Http/Controllers/InvoiceApiController.php
@@ -58,7 +58,11 @@ class InvoiceApiController extends Controller
{
$data = Input::all();
$error = null;
-
+
+ if (isset($data['id']) || isset($data['public_id'])) {
+ die("We don't yet support updating invoices");
+ }
+
if (isset($data['email'])) {
$client = Client::scope()->whereHas('contacts', function($query) use ($data) {
$query->where('email', '=', $data['email']);
@@ -78,7 +82,7 @@ class InvoiceApiController extends Controller
}
$error = $this->clientRepo->getErrors($clientData);
if (!$error) {
- $client = $this->clientRepo->save(false, $clientData, false);
+ $client = $this->clientRepo->save($clientData);
}
}
} else if (isset($data['client_id'])) {
@@ -108,7 +112,7 @@ class InvoiceApiController extends Controller
} else {
$data = self::prepareData($data, $client);
$data['client_id'] = $client->id;
- $invoice = $this->invoiceRepo->save(false, $data, false);
+ $invoice = $this->invoiceRepo->save($data);
if (!isset($data['id'])) {
$invitation = Invitation::createNew();
diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php
index 54d74258c7..a8fb60a778 100644
--- a/app/Http/Controllers/InvoiceController.php
+++ b/app/Http/Controllers/InvoiceController.php
@@ -14,7 +14,6 @@ use Datatable;
use Request;
use DropdownButton;
use App\Models\Invoice;
-use App\Models\Invitation;
use App\Models\Client;
use App\Models\Account;
use App\Models\Product;
@@ -31,21 +30,27 @@ use App\Models\Gateway;
use App\Ninja\Mailers\ContactMailer as Mailer;
use App\Ninja\Repositories\InvoiceRepository;
use App\Ninja\Repositories\ClientRepository;
-use App\Events\InvoiceViewed;
+use App\Events\InvoiceInvitationWasViewed;
+use App\Events\QuoteInvitationWasViewed;
+
+use App\Services\InvoiceService;
+use App\Http\Requests\SaveInvoiceRequest;
class InvoiceController extends BaseController
{
protected $mailer;
protected $invoiceRepo;
protected $clientRepo;
+ protected $invoiceService;
- public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo)
+ public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService)
{
parent::__construct();
$this->mailer = $mailer;
$this->invoiceRepo = $invoiceRepo;
$this->clientRepo = $clientRepo;
+ $this->invoiceService = $invoiceService;
}
public function index()
@@ -147,12 +152,15 @@ class InvoiceController extends BaseController
}
if (!Input::has('phantomjs') && !Session::has($invitationKey) && (!Auth::check() || Auth::user()->account_id != $invoice->account_id)) {
- Activity::viewInvoice($invitation);
- Event::fire(new InvoiceViewed($invoice));
+ if ($invoice->is_quote) {
+ event(new QuoteInvitationWasViewed($invoice, $invitation));
+ } else {
+ event(new InvoiceInvitationWasViewed($invoice, $invitation));
+ }
}
- Session::set($invitationKey, true); // track this invitation has been seen
- Session::set('invitation_key', $invitationKey); // track current invitation
+ Session::put($invitationKey, true); // track this invitation has been seen
+ Session::put('invitation_key', $invitationKey); // track current invitation
$account->loadLocalizationSettings($client);
@@ -245,7 +253,7 @@ class InvoiceController extends BaseController
->select('contacts.public_id')->lists('public_id');
if ($clone) {
- $invoice->id = null;
+ $invoice->id = $invoice->public_id = null;
$invoice->invoice_number = $account->getNextInvoiceNumber($invoice);
$invoice->balance = $invoice->amount;
$invoice->invoice_status_id = 0;
@@ -347,13 +355,16 @@ class InvoiceController extends BaseController
public function create($clientPublicId = 0, $isRecurring = false)
{
$account = Auth::user()->account;
+ $entityType = $isRecurring ? ENTITY_RECURRING_INVOICE : ENTITY_INVOICE;
$clientId = null;
+
if ($clientPublicId) {
$clientId = Client::getPrivateId($clientPublicId);
}
- $entityType = $isRecurring ? ENTITY_RECURRING_INVOICE : ENTITY_INVOICE;
- $invoice = $account->createInvoice($entityType, $clientId);
+ $invoice = $account->createInvoice($entityType, $clientId);
+ $invoice->public_id = 0;
+
$data = [
'entityType' => $invoice->getEntityType(),
'invoice' => $invoice,
@@ -418,50 +429,62 @@ class InvoiceController extends BaseController
*
* @return Response
*/
- public function store()
- {
- return InvoiceController::save();
- }
-
- private function save($publicId = null)
+ public function store(SaveInvoiceRequest $request)
{
$action = Input::get('action');
$entityType = Input::get('entityType');
- $input = json_decode(Input::get('data'));
- if (in_array($action, ['archive', 'delete', 'mark', 'restore'])) {
- return InvoiceController::bulk($entityType);
+ $invoice = $this->invoiceService->save($request->input());
+ $entityType = $invoice->getEntityType();
+ $message = trans("texts.created_{$entityType}");
+
+ // check if we created a new client with the invoice
+ // TODO: replace with HistoryListener
+ $input = $request->input();
+ $clientPublicId = isset($input['client']['public_id']) ? $input['client']['public_id'] : false;
+ if ($clientPublicId == '-1') {
+ $message = $message.' '.trans('texts.and_created_client');
+ $trackUrl = URL::to('clients/' . $invoice->client->public_id);
+ Utils::trackViewed($invoice->client->getDisplayName(), ENTITY_CLIENT, $trackUrl);
}
- if ($errors = $this->invoiceRepo->getErrors($input->invoice)) {
- Session::flash('error', trans('texts.invoice_error'));
- $url = "{$entityType}s/" . ($publicId ?: 'create');
- return Redirect::to($url)->withInput()->withErrors($errors);
- } else {
- $invoice = $this->saveInvoice($publicId, $input, $entityType);
- $url = "{$entityType}s/".$invoice->public_id.'/edit';
- $message = trans($publicId ? "texts.updated_{$entityType}" : "texts.created_{$entityType}");
+ Session::flash('message', $message);
- // check if we created a new client with the invoice
- if ($input->invoice->client->public_id == '-1') {
- $message = $message.' '.trans('texts.and_created_client');
- $trackUrl = URL::to('clients/'.$invoice->client->public_id);
- Utils::trackViewed($invoice->client->getDisplayName(), ENTITY_CLIENT, $trackUrl);
- }
-
- if ($action == 'clone') {
- return $this->cloneInvoice($publicId);
- } elseif ($action == 'convert') {
- return $this->convertQuote($publicId);
- } elseif ($action == 'email') {
- return $this->emailInvoice($invoice, Input::get('pdfupload'));
- }
-
- Session::flash('message', $message);
- return Redirect::to($url);
+ if ($action == 'email') {
+ return $this->emailInvoice($invoice, Input::get('pdfupload'));
}
+
+ return redirect()->to($invoice->getRoute());
}
+ /**
+ * Update the specified resource in storage.
+ *
+ * @param int $id
+ * @return Response
+ */
+ public function update(SaveInvoiceRequest $request)
+ {
+ $action = Input::get('action');
+ $entityType = Input::get('entityType');
+
+ $invoice = $this->invoiceService->save($request->input());
+ $entityType = $invoice->getEntityType();
+ $message = trans("texts.updated_{$entityType}");
+ Session::flash('message', $message);
+
+ if ($action == 'clone') {
+ return $this->cloneInvoice($invoice->public_id);
+ } elseif ($action == 'convert') {
+ return $this->convertQuote($invoice->public_id);
+ } elseif ($action == 'email') {
+ return $this->emailInvoice($invoice, Input::get('pdfupload'));
+ }
+
+ return redirect()->to($invoice->getRoute());
+ }
+
+
private function emailInvoice($invoice, $pdfUpload)
{
$entityType = $invoice->getEntityType();
@@ -512,43 +535,6 @@ class InvoiceController extends BaseController
}
}
- private function saveInvoice($publicId, $input, $entityType)
- {
- $invoice = $input->invoice;
-
- $clientData = (array) $invoice->client;
- $client = $this->clientRepo->save($invoice->client->public_id, $clientData);
-
- $invoiceData = (array) $invoice;
- $invoiceData['client_id'] = $client->id;
- $invoice = $this->invoiceRepo->save($publicId, $invoiceData, $entityType);
-
- $client->load('contacts');
- $sendInvoiceIds = [];
-
- foreach ($client->contacts as $contact) {
- if ($contact->send_invoice || count($client->contacts) == 1) {
- $sendInvoiceIds[] = $contact->id;
- }
- }
-
- foreach ($client->contacts as $contact) {
- $invitation = Invitation::scope()->whereContactId($contact->id)->whereInvoiceId($invoice->id)->first();
-
- if (in_array($contact->id, $sendInvoiceIds) && !$invitation) {
- $invitation = Invitation::createNew();
- $invitation->invoice_id = $invoice->id;
- $invitation->contact_id = $contact->id;
- $invitation->invitation_key = str_random(RANDOM_KEY_LENGTH);
- $invitation->save();
- } elseif (!in_array($contact->id, $sendInvoiceIds) && $invitation) {
- $invitation->delete();
- }
- }
-
- return $invoice;
- }
-
/**
* Display the specified resource.
*
@@ -562,17 +548,6 @@ class InvoiceController extends BaseController
return Redirect::to("invoices/{$publicId}/edit");
}
- /**
- * Update the specified resource in storage.
- *
- * @param int $id
- * @return Response
- */
- public function update($publicId)
- {
- return InvoiceController::save($publicId);
- }
-
/**
* Remove the specified resource from storage.
*
@@ -581,10 +556,10 @@ class InvoiceController extends BaseController
*/
public function bulk($entityType = ENTITY_INVOICE)
{
- $action = Input::get('action');
+ $action = Input::get('bulk_action') ?: Input::get('action');;
+ $ids = Input::get('bulk_public_id') ?: (Input::get('public_id') ?: Input::get('ids'));
$statusId = Input::get('statusId', INVOICE_STATUS_SENT);
- $ids = Input::get('id') ? Input::get('id') : Input::get('ids');
- $count = $this->invoiceRepo->bulk($ids, $action, $statusId);
+ $count = $this->invoiceService->bulk($ids, $action, $statusId);
if ($count > 0) {
$key = $action == 'mark' ? "updated_{$entityType}" : "{$action}d_{$entityType}";
@@ -602,7 +577,7 @@ class InvoiceController extends BaseController
public function convertQuote($publicId)
{
$invoice = Invoice::with('invoice_items')->scope($publicId)->firstOrFail();
- $clone = $this->invoiceRepo->cloneInvoice($invoice, $invoice->id);
+ $clone = $this->invoiceService->approveQuote($invoice);
Session::flash('message', trans('texts.converted_to_invoice'));
return Redirect::to('invoices/'.$clone->public_id);
@@ -610,15 +585,6 @@ class InvoiceController extends BaseController
public function cloneInvoice($publicId)
{
- /*
- $invoice = Invoice::with('invoice_items')->scope($publicId)->firstOrFail();
- $clone = $this->invoiceRepo->cloneInvoice($invoice);
- $entityType = $invoice->getEntityType();
-
- Session::flash('message', trans('texts.cloned_invoice'));
- return Redirect::to("{$entityType}s/" . $clone->public_id);
- */
-
return self::edit($publicId, true);
}
@@ -636,7 +602,7 @@ class InvoiceController extends BaseController
->where('activity_type_id', '=', $activityTypeId)
->where('invoice_id', '=', $invoice->id)
->orderBy('id', 'desc')
- ->get(['id', 'created_at', 'user_id', 'json_backup', 'message']);
+ ->get(['id', 'created_at', 'user_id', 'json_backup']);
$versionsJson = [];
$versionsSelect = [];
@@ -651,7 +617,7 @@ class InvoiceController extends BaseController
$backup->account = $invoice->account->toArray();
$versionsJson[$activity->id] = $backup;
- $key = Utils::timestampToDateTimeString(strtotime($activity->created_at)) . ' - ' . Utils::decodeActivity($activity->message);
+ $key = Utils::timestampToDateTimeString(strtotime($activity->created_at)) . ' - ' . $activity->user->getDisplayName();
$versionsSelect[$lastId ? $lastId : 0] = $key;
$lastId = $activity->id;
}
diff --git a/app/Http/Controllers/PaymentApiController.php b/app/Http/Controllers/PaymentApiController.php
index 17d2e548f7..d83fcac494 100644
--- a/app/Http/Controllers/PaymentApiController.php
+++ b/app/Http/Controllers/PaymentApiController.php
@@ -60,7 +60,7 @@ class PaymentApiController extends Controller
}
if (!$error) {
- $payment = $this->paymentRepo->save(false, $data);
+ $payment = $this->paymentRepo->save($data);
$payment = Payment::scope($payment->public_id)->with('client', 'contact', 'user', 'invoice')->first();
$payment = Utils::remapPublicIds([$payment]);
diff --git a/app/Http/Controllers/PaymentController.php b/app/Http/Controllers/PaymentController.php
index 84a1405518..0ede064b44 100644
--- a/app/Http/Controllers/PaymentController.php
+++ b/app/Http/Controllers/PaymentController.php
@@ -25,6 +25,9 @@ use App\Ninja\Repositories\AccountRepository;
use App\Ninja\Mailers\ContactMailer;
use App\Services\PaymentService;
+use App\Http\Requests\CreatePaymentRequest;
+use App\Http\Requests\UpdatePaymentRequest;
+
class PaymentController extends BaseController
{
public function __construct(PaymentRepository $paymentRepo, InvoiceRepository $invoiceRepo, AccountRepository $accountRepo, ContactMailer $contactMailer, PaymentService $paymentService)
@@ -540,49 +543,36 @@ class PaymentController extends BaseController
}
}
- public function store()
+ public function store(CreatePaymentRequest $request)
{
- return $this->save();
- }
+ $input = $request->input();
+ $payment = $this->paymentRepo->save($input);
- public function update($publicId)
- {
- return $this->save($publicId);
- }
-
- private function save($publicId = null)
- {
- if (!$publicId && $errors = $this->paymentRepo->getErrors(Input::all())) {
- $url = $publicId ? 'payments/'.$publicId.'/edit' : 'payments/create';
-
- return Redirect::to($url)
- ->withErrors($errors)
- ->withInput();
+ if (Input::get('email_receipt')) {
+ $this->contactMailer->sendPaymentConfirmation($payment);
+ Session::flash('message', trans('texts.created_payment_emailed_client'));
} else {
- $payment = $this->paymentRepo->save($publicId, Input::all());
-
- if ($publicId) {
- Session::flash('message', trans('texts.updated_payment'));
-
- return Redirect::to('payments/');
- } else {
- if (Input::get('email_receipt')) {
- $this->contactMailer->sendPaymentConfirmation($payment);
- Session::flash('message', trans('texts.created_payment_emailed_client'));
- } else {
- Session::flash('message', trans('texts.created_payment'));
- }
-
- return Redirect::to('clients/'.Input::get('client'));
- }
+ Session::flash('message', trans('texts.created_payment'));
}
+
+ return redirect()->to($payment->client->getRoute());
+ }
+
+ public function update(UpdatePaymentRequest $request)
+ {
+ $input = $request->input();
+ $payment = $this->paymentRepo->save($input);
+
+ Session::flash('message', trans('texts.updated_payment'));
+
+ return redirect()->to($payment->getRoute());
}
public function bulk()
{
$action = Input::get('action');
- $ids = Input::get('id') ? Input::get('id') : Input::get('ids');
- $count = $this->paymentRepo->bulk($ids, $action);
+ $ids = Input::get('public_id') ? Input::get('public_id') : Input::get('ids');
+ $count = $this->paymentService->bulk($ids, $action);
if ($count > 0) {
$message = Utils::pluralize($action.'d_payment', $count);
diff --git a/app/Http/Controllers/PublicClientController.php b/app/Http/Controllers/PublicClientController.php
index fdf9fa36e0..a62b2f2d85 100644
--- a/app/Http/Controllers/PublicClientController.php
+++ b/app/Http/Controllers/PublicClientController.php
@@ -8,16 +8,18 @@ use Datatable;
use App\Models\Invitation;
use App\Ninja\Repositories\InvoiceRepository;
use App\Ninja\Repositories\PaymentRepository;
+use App\Ninja\Repositories\ActivityRepository;
class PublicClientController extends BaseController
{
private $invoiceRepo;
private $paymentRepo;
- public function __construct(InvoiceRepository $invoiceRepo, PaymentRepository $paymentRepo)
+ public function __construct(InvoiceRepository $invoiceRepo, PaymentRepository $paymentRepo, ActivityRepository $activityRepo)
{
$this->invoiceRepo = $invoiceRepo;
$this->paymentRepo = $paymentRepo;
+ $this->activityRepo = $activityRepo;
}
public function dashboard()
@@ -47,15 +49,22 @@ class PublicClientController extends BaseController
}
$invoice = $invitation->invoice;
- $query = DB::table('activities')
- ->join('clients', 'clients.id', '=', 'activities.client_id')
- ->where('activities.client_id', '=', $invoice->client_id)
- ->where('activities.adjustment', '!=', 0)
- ->select('activities.id', 'activities.message', 'activities.created_at', 'clients.currency_id', 'activities.balance', 'activities.adjustment');
+ $query = $this->activityRepo->findByClientId($invoice->client_id);
+ $query->where('activities.adjustment', '!=', 0);
return Datatable::query($query)
->addColumn('activities.id', function ($model) { return Utils::timestampToDateTimeString(strtotime($model->created_at)); })
- ->addColumn('message', function ($model) { return strip_tags(Utils::decodeActivity($model->message)); })
+ ->addColumn('message', function ($model) {
+ $data = [
+ 'client' => Utils::getClientDisplayName($model),
+ 'user' => $model->is_system ? ('' . trans('texts.system') . ' ') : ($model->user_first_name . ' ' . $model->user_last_name),
+ 'invoice' => trans('texts.invoice') . ' ' . $model->invoice,
+ 'contact' => Utils::getClientDisplayName($model),
+ 'payment' => trans('texts.payment') . ($model->payment ? ' ' . $model->payment : ''),
+ ];
+
+ return trans("texts.activity_{$model->activity_type_id}", $data);
+ })
->addColumn('balance', function ($model) { return Utils::formatMoney($model->balance, $model->currency_id); })
->addColumn('adjustment', function ($model) { return $model->adjustment != 0 ? Utils::wrapAdjustment($model->adjustment, $model->currency_id) : ''; })
->make();
diff --git a/app/Http/Controllers/QuoteController.php b/app/Http/Controllers/QuoteController.php
index f78a693d66..ccf1834a01 100644
--- a/app/Http/Controllers/QuoteController.php
+++ b/app/Http/Controllers/QuoteController.php
@@ -24,24 +24,24 @@ use App\Models\Invoice;
use App\Ninja\Mailers\ContactMailer as Mailer;
use App\Ninja\Repositories\InvoiceRepository;
use App\Ninja\Repositories\ClientRepository;
-use App\Ninja\Repositories\TaxRateRepository;
-use App\Events\QuoteApproved;
+use App\Events\QuoteInvitationWasApproved;
+use App\Services\InvoiceService;
class QuoteController extends BaseController
{
protected $mailer;
protected $invoiceRepo;
protected $clientRepo;
- protected $taxRateRepo;
+ protected $invoiceService;
- public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, TaxRateRepository $taxRateRepo)
+ public function __construct(Mailer $mailer, InvoiceRepository $invoiceRepo, ClientRepository $clientRepo, InvoiceService $invoiceService)
{
parent::__construct();
$this->mailer = $mailer;
$this->invoiceRepo = $invoiceRepo;
$this->clientRepo = $clientRepo;
- $this->taxRateRepo = $taxRateRepo;
+ $this->invoiceService = $invoiceService;
}
public function index()
@@ -87,7 +87,8 @@ class QuoteController extends BaseController
$clientId = Client::getPrivateId($clientPublicId);
}
$invoice = $account->createInvoice(ENTITY_QUOTE, $clientId);
-
+ $invoice->public_id = 0;
+
$data = [
'entityType' => $invoice->getEntityType(),
'invoice' => $invoice,
@@ -123,19 +124,19 @@ class QuoteController extends BaseController
public function bulk()
{
- $action = Input::get('action');
+ $action = Input::get('bulk_action') ?: Input::get('action');;
if ($action == 'convert') {
$invoice = Invoice::with('invoice_items')->scope(Input::get('id'))->firstOrFail();
- $clone = $this->invoiceRepo->cloneInvoice($invoice, $invoice->id);
+ $clone = $this->invoiceService->approveQuote($invoice);
Session::flash('message', trans('texts.converted_to_invoice'));
return Redirect::to('invoices/'.$clone->public_id);
}
-
+
$statusId = Input::get('statusId');
- $ids = Input::get('id') ? Input::get('id') : Input::get('ids');
- $count = $this->invoiceRepo->bulk($ids, $action, $statusId);
+ $ids = Input::get('bulk_public_id') ?: (Input::get('public_id') ?: Input::get('ids'));
+ $count = $this->invoiceService->bulk($ids, $action, $statusId);
if ($count > 0) {
$key = $action == 'mark' ? "updated_quote" : "{$action}d_quote";
@@ -155,19 +156,8 @@ class QuoteController extends BaseController
$invitation = Invitation::with('invoice.invoice_items', 'invoice.invitations')->where('invitation_key', '=', $invitationKey)->firstOrFail();
$invoice = $invitation->invoice;
- if ($invoice->is_quote && !$invoice->quote_invoice_id) {
- Event::fire(new QuoteApproved($invoice));
- Activity::approveQuote($invitation);
-
- $invoice = $this->invoiceRepo->cloneInvoice($invoice, $invoice->id);
- Session::flash('message', trans('texts.converted_to_invoice'));
-
- foreach ($invoice->invitations as $invitationClone) {
- if ($invitation->contact_id == $invitationClone->contact_id) {
- $invitationKey = $invitationClone->invitation_key;
- }
- }
- }
+ $invitationKey = $this->invoiceService->approveQuote($invoice, $invitation);
+ Session::flash('message', trans('texts.converted_to_invoice'));
return Redirect::to("view/{$invitationKey}");
}
diff --git a/app/Http/Controllers/TaskController.php b/app/Http/Controllers/TaskController.php
index 0fec382e74..b357f8d822 100644
--- a/app/Http/Controllers/TaskController.php
+++ b/app/Http/Controllers/TaskController.php
@@ -156,7 +156,7 @@ class TaskController extends BaseController
*/
public function edit($publicId)
{
- $task = Task::scope($publicId)->with('client', 'invoice')->firstOrFail();
+ $task = Task::scope($publicId)->with('client', 'invoice')->withTrashed()->firstOrFail();
$actions = [];
if ($task->invoice) {
@@ -240,7 +240,7 @@ class TaskController extends BaseController
public function bulk()
{
$action = Input::get('action');
- $ids = Input::get('id') ? Input::get('id') : Input::get('ids');
+ $ids = Input::get('public_id') ?: (Input::get('id') ?: Input::get('ids'));
if ($action == 'stop') {
$this->taskRepo->save($ids, ['action' => $action]);
diff --git a/app/Http/Requests/CreateClientRequest.php b/app/Http/Requests/CreateClientRequest.php
new file mode 100644
index 0000000000..2d1716cc1e
--- /dev/null
+++ b/app/Http/Requests/CreateClientRequest.php
@@ -0,0 +1,44 @@
+ 'valid_contacts',
+ ];
+ }
+
+ public function validator($factory)
+ {
+ // support submiting the form with a single client record
+ $input = $this->input();
+ if (isset($input['contact'])) {
+ $input['contacts'] = [$input['contact']];
+ unset($input['contact']);
+ $this->replace($input);
+ }
+
+ return $factory->make(
+ $this->input(), $this->container->call([$this, 'rules']), $this->messages()
+ );
+ }
+}
diff --git a/app/Http/Requests/CreateCreditRequest.php b/app/Http/Requests/CreateCreditRequest.php
new file mode 100644
index 0000000000..f2dc44d31a
--- /dev/null
+++ b/app/Http/Requests/CreateCreditRequest.php
@@ -0,0 +1,30 @@
+ 'required',
+ 'amount' => 'required|positive',
+ ];
+ }
+}
diff --git a/app/Http/Requests/CreatePaymentRequest.php b/app/Http/Requests/CreatePaymentRequest.php
new file mode 100644
index 0000000000..d0c8146872
--- /dev/null
+++ b/app/Http/Requests/CreatePaymentRequest.php
@@ -0,0 +1,44 @@
+input();
+ $rules = array(
+ 'client' => 'required',
+ 'invoice' => 'required',
+ 'amount' => 'required',
+ );
+
+ if ($input['payment_type_id'] == PAYMENT_TYPE_CREDIT) {
+ $rules['payment_type_id'] = 'has_credit:'.$input['client'].','.$input['amount'];
+ }
+
+ if (isset($input['invoice']) && $input['invoice']) {
+ $invoice = Invoice::scope($input['invoice'])->firstOrFail();
+ $rules['amount'] .= "|less_than:{$invoice->balance}";
+ }
+
+ return $rules;
+ }
+}
diff --git a/app/Http/Requests/SaveInvoiceRequest.php b/app/Http/Requests/SaveInvoiceRequest.php
new file mode 100644
index 0000000000..1e18c6b5fe
--- /dev/null
+++ b/app/Http/Requests/SaveInvoiceRequest.php
@@ -0,0 +1,44 @@
+ 'valid_contacts',
+ 'invoice_number' => 'required|unique:invoices,invoice_number,'.$invoiceId.',id,account_id,'.Auth::user()->account_id,
+ 'discount' => 'positive',
+ ];
+
+ /* There's a problem parsing the dates
+ if (Request::get('is_recurring') && Request::get('start_date') && Request::get('end_date')) {
+ $rules['end_date'] = 'after' . Request::get('start_date');
+ }
+ */
+
+ return $rules;
+ }
+}
diff --git a/app/Http/Requests/UpdateClientRequest.php b/app/Http/Requests/UpdateClientRequest.php
new file mode 100644
index 0000000000..b73e019c49
--- /dev/null
+++ b/app/Http/Requests/UpdateClientRequest.php
@@ -0,0 +1,29 @@
+ 'valid_contacts',
+ ];
+ }
+}
diff --git a/app/Http/Requests/UpdatePaymentRequest.php b/app/Http/Requests/UpdatePaymentRequest.php
new file mode 100644
index 0000000000..83b1922808
--- /dev/null
+++ b/app/Http/Requests/UpdatePaymentRequest.php
@@ -0,0 +1,28 @@
+getDisplayName() : 'System ';
- $entity = $entity ? $entity->getActivityKey() : '';
- $otherPerson = $otherPerson ? 'to '.$otherPerson->getDisplayName() : '';
- $token = Session::get('token_id') ? ' ('.trans('texts.token').')' : '';
-
- return trim("$person $token $action $entity $otherPerson");
- }
-
- public static function decodeActivity($message)
- {
- $pattern = '/\[([\w]*):([\d]*):(.*)\]/i';
- preg_match($pattern, $message, $matches);
-
- if (count($matches) > 0) {
- $match = $matches[0];
- $type = $matches[1];
- $publicId = $matches[2];
- $name = $matches[3];
-
- $link = link_to($type.'s/'.$publicId, $name);
- $message = str_replace($match, "$type $link", $message);
+ if ($firstName || $lastName) {
+ return $firstName.' '.$lastName;
+ } elseif ($email) {
+ return $email;
+ } else {
+ return trans('texts.guest');
}
-
- return $message;
}
public static function generateLicense()
@@ -598,7 +581,7 @@ class Utils
foreach ($data as $key => $val) {
if (is_array($val)) {
if ($key == 'account' || isset($mapped[$key])) {
- unset($data[$key]);
+ // do nothing
} else {
$mapped[$key] = true;
$data[$key] = Utils::hideIds($val, $mapped);
@@ -795,4 +778,30 @@ class Utils
$adjustment = Utils::formatMoney($adjustment, $currencyId);
return "
$adjustment
";
}
+
+ public static function copyContext($entity1, $entity2)
+ {
+ if (!$entity2) {
+ return $entity1;
+ }
+
+ $fields = [
+ 'contact_id',
+ 'payment_id',
+ 'invoice_id',
+ 'credit_id',
+ 'invitation_id'
+ ];
+
+ $fields1 = $entity1->getAttributes();
+ $fields2 = $entity2->getAttributes();
+
+ foreach ($fields as $field) {
+ if (isset($fields2[$field]) && $fields2[$field]) {
+ $entity1->$field = $entity2->$field;
+ }
+ }
+
+ return $entity1;
+ }
}
diff --git a/app/Listeners/ActivityListener.php b/app/Listeners/ActivityListener.php
new file mode 100644
index 0000000000..fe966d4745
--- /dev/null
+++ b/app/Listeners/ActivityListener.php
@@ -0,0 +1,337 @@
+activityRepo = $activityRepo;
+ }
+
+ // Clients
+ public function createdClient(ClientWasCreated $event)
+ {
+ $this->activityRepo->create(
+ $event->client,
+ ACTIVITY_TYPE_CREATE_CLIENT
+ );
+ }
+
+ public function deletedClient(ClientWasDeleted $event)
+ {
+ $this->activityRepo->create(
+ $event->client,
+ ACTIVITY_TYPE_DELETE_CLIENT
+ );
+ }
+
+ public function archivedClient(ClientWasArchived $event)
+ {
+ if ($event->client->is_deleted) {
+ return;
+ }
+
+ $this->activityRepo->create(
+ $event->client,
+ ACTIVITY_TYPE_ARCHIVE_CLIENT
+ );
+ }
+
+ public function restoredClient(ClientWasRestored $event)
+ {
+ $this->activityRepo->create(
+ $event->client,
+ ACTIVITY_TYPE_RESTORE_CLIENT
+ );
+ }
+
+
+ // Invoices
+ public function createdInvoice(InvoiceWasCreated $event)
+ {
+ $this->activityRepo->create(
+ $event->invoice,
+ ACTIVITY_TYPE_CREATE_INVOICE,
+ $event->invoice->getAdjustment()
+ );
+ }
+
+ public function updatedInvoice(InvoiceWasUpdated $event)
+ {
+ if ( ! $event->invoice->isChanged()) {
+ return;
+ }
+
+ $backupInvoice = Invoice::with('invoice_items', 'client.account', 'client.contacts')->find($event->invoice->id);
+
+ $activity = $this->activityRepo->create(
+ $event->invoice,
+ ACTIVITY_TYPE_UPDATE_INVOICE,
+ $event->invoice->getAdjustment()
+ );
+
+ $activity->json_backup = $backupInvoice->hidePrivateFields()->toJSON();
+ $activity->save();
+ }
+
+ public function deletedInvoice(InvoiceWasDeleted $event)
+ {
+ $this->activityRepo->create(
+ $event->invoice,
+ ACTIVITY_TYPE_DELETE_INVOICE,
+ $event->invoice->balance * -1,
+ $event->invoice->getAmountPaid() * -1
+ );
+ }
+
+ public function archivedInvoice(InvoiceWasArchived $event)
+ {
+ if ($event->invoice->is_deleted) {
+ return;
+ }
+
+ $this->activityRepo->create(
+ $event->invoice,
+ ACTIVITY_TYPE_ARCHIVE_INVOICE
+ );
+ }
+
+ public function restoredInvoice(InvoiceWasRestored $event)
+ {
+ $this->activityRepo->create(
+ $event->invoice,
+ ACTIVITY_TYPE_RESTORE_INVOICE
+ );
+ }
+
+ public function emailedInvoice(InvoiceInvitationWasEmailed $event)
+ {
+ $this->activityRepo->create(
+ $event->invoice,
+ ACTIVITY_TYPE_EMAIL_INVOICE,
+ false,
+ false,
+ $event->invitation
+ );
+ }
+
+ public function viewedInvoice(InvoiceInvitationWasViewed $event)
+ {
+ $this->activityRepo->create(
+ $event->invoice,
+ ACTIVITY_TYPE_VIEW_INVOICE,
+ false,
+ false,
+ $event->invitation
+ );
+ }
+
+
+ // Quotes
+ public function createdQuote(QuoteWasCreated $event)
+ {
+ $this->activityRepo->create(
+ $event->quote,
+ ACTIVITY_TYPE_CREATE_QUOTE
+ );
+ }
+
+ public function updatedQuote(QuoteWasUpdated $event)
+ {
+ if ( ! $event->quote->isChanged()) {
+ return;
+ }
+
+ $backupQuote = Invoice::with('invoice_items', 'client.account', 'client.contacts')->find($event->quote->id);
+
+ $activity = $this->activityRepo->create(
+ $event->quote,
+ ACTIVITY_TYPE_UPDATE_QUOTE,
+ $event->quote->getAdjustment()
+ );
+
+ $activity->json_backup = $backupQuote->hidePrivateFields()->toJSON();
+ $activity->save();
+ }
+
+ public function deletedQuote(QuoteWasDeleted $event)
+ {
+ $this->activityRepo->create(
+ $event->quote,
+ ACTIVITY_TYPE_DELETE_QUOTE
+ );
+ }
+
+ public function archivedQuote(QuoteWasArchived $event)
+ {
+ if ($event->quote->is_deleted) {
+ return;
+ }
+
+ $this->activityRepo->create(
+ $event->quote,
+ ACTIVITY_TYPE_ARCHIVE_QUOTE
+ );
+ }
+
+ public function restoredQuote(QuoteWasRestored $event)
+ {
+ $this->activityRepo->create(
+ $event->quote,
+ ACTIVITY_TYPE_RESTORE_QUOTE
+ );
+ }
+
+ public function emailedQuote(QuoteInvitationWasEmailed $event)
+ {
+ $this->activityRepo->create(
+ $event->quote,
+ ACTIVITY_TYPE_EMAIL_QUOTE,
+ false,
+ false,
+ $event->invitation
+ );
+ }
+
+ public function viewedQuote(QuoteInvitationWasViewed $event)
+ {
+ $this->activityRepo->create(
+ $event->quote,
+ ACTIVITY_TYPE_VIEW_QUOTE,
+ false,
+ false,
+ $event->invitation
+ );
+ }
+
+ public function approvedQuote(QuoteInvitationWasApproved $event)
+ {
+ $this->activityRepo->create(
+ $event->quote,
+ ACTIVITY_TYPE_APPROVE_QUOTE,
+ false,
+ false,
+ $event->invitation
+ );
+ }
+
+
+ // Credits
+ public function createdCredit(CreditWasCreated $event)
+ {
+ $this->activityRepo->create(
+ $event->credit,
+ ACTIVITY_TYPE_CREATE_CREDIT
+ );
+ }
+
+ public function deletedCredit(CreditWasDeleted $event)
+ {
+ $this->activityRepo->create(
+ $event->credit,
+ ACTIVITY_TYPE_DELETE_CREDIT
+ );
+ }
+
+ public function archivedCredit(CreditWasArchived $event)
+ {
+ if ($event->credit->is_deleted) {
+ return;
+ }
+
+ $this->activityRepo->create(
+ $event->credit,
+ ACTIVITY_TYPE_ARCHIVE_CREDIT
+ );
+ }
+
+ public function restoredCredit(CreditWasRestored $event)
+ {
+ $this->activityRepo->create(
+ $event->credit,
+ ACTIVITY_TYPE_RESTORE_CREDIT
+ );
+ }
+
+
+ // Payments
+ public function createdPayment(PaymentWasCreated $event)
+ {
+ $this->activityRepo->create(
+ $event->payment,
+ ACTIVITY_TYPE_CREATE_PAYMENT,
+ $event->payment->amount * -1,
+ $event->payment->amount
+ );
+ }
+
+ public function deletedPayment(PaymentWasDeleted $event)
+ {
+ $this->activityRepo->create(
+ $event->payment,
+ ACTIVITY_TYPE_DELETE_PAYMENT,
+ $event->payment->amount,
+ $event->payment->amount * -1
+ );
+ }
+
+ public function archivedPayment(PaymentWasArchived $event)
+ {
+ if ($event->payment->is_deleted) {
+ return;
+ }
+
+ $this->activityRepo->create(
+ $event->payment,
+ ACTIVITY_TYPE_ARCHIVE_PAYMENT
+ );
+ }
+
+ public function restoredPayment(PaymentWasRestored $event)
+ {
+ $this->activityRepo->create(
+ $event->payment,
+ ACTIVITY_TYPE_RESTORE_PAYMENT
+ );
+ }
+
+}
diff --git a/app/Listeners/CreditListener.php b/app/Listeners/CreditListener.php
new file mode 100644
index 0000000000..bed71a47f5
--- /dev/null
+++ b/app/Listeners/CreditListener.php
@@ -0,0 +1,33 @@
+creditRepo = $creditRepo;
+ }
+
+ public function deletedPayment(PaymentWasDeleted $event)
+ {
+ $payment = $event->payment;
+
+ // if the payment was from a credit we need to refund the credit
+ if ($payment->payment_type_id != PAYMENT_TYPE_CREDIT) {
+ return;
+ }
+
+ $credit = Credit::createNew();
+ $credit->client_id = $payment->client_id;
+ $credit->credit_date = Carbon::now()->toDateTimeString();
+ $credit->balance = $credit->amount = $payment->amount;
+ $credit->private_notes = $payment->transaction_reference;
+ $credit->save();
+ }
+}
diff --git a/app/Listeners/HandleInvoicePaid.php b/app/Listeners/HandleInvoicePaid.php
deleted file mode 100644
index d072abd003..0000000000
--- a/app/Listeners/HandleInvoicePaid.php
+++ /dev/null
@@ -1,48 +0,0 @@
-userMailer = $userMailer;
- $this->contactMailer = $contactMailer;
- }
-
- /**
- * Handle the event.
- *
- * @param InvoicePaid $event
- * @return void
- */
- public function handle(InvoicePaid $event)
- {
- $payment = $event->payment;
- $invoice = $payment->invoice;
-
- $this->contactMailer->sendPaymentConfirmation($payment);
-
- foreach ($invoice->account->users as $user)
- {
- if ($user->{'notify_paid'})
- {
- $this->userMailer->sendNotification($user, $invoice, 'paid', $payment);
- }
- }
- }
-
-}
diff --git a/app/Listeners/HandleInvoiceSent.php b/app/Listeners/HandleInvoiceSent.php
deleted file mode 100644
index 119936e950..0000000000
--- a/app/Listeners/HandleInvoiceSent.php
+++ /dev/null
@@ -1,42 +0,0 @@
-userMailer = $userMailer;
- }
-
- /**
- * Handle the event.
- *
- * @param InvoiceSent $event
- * @return void
- */
- public function handle(InvoiceSent $event)
- {
- $invoice = $event->invoice;
-
- foreach ($invoice->account->users as $user)
- {
- if ($user->{'notify_sent'})
- {
- $this->userMailer->sendNotification($user, $invoice, 'sent');
- }
- }
- }
-
-}
diff --git a/app/Listeners/HandleInvoiceViewed.php b/app/Listeners/HandleInvoiceViewed.php
deleted file mode 100644
index 47ee62a858..0000000000
--- a/app/Listeners/HandleInvoiceViewed.php
+++ /dev/null
@@ -1,42 +0,0 @@
-userMailer = $userMailer;
- }
-
- /**
- * Handle the event.
- *
- * @param InvoiceViewed $event
- * @return void
- */
- public function handle(InvoiceViewed $event)
- {
- $invoice = $event->invoice;
-
- foreach ($invoice->account->users as $user)
- {
- if ($user->{'notify_viewed'})
- {
- $this->userMailer->sendNotification($user, $invoice, 'viewed');
- }
- }
- }
-
-}
diff --git a/app/Listeners/HandleQuoteApproved.php b/app/Listeners/HandleQuoteApproved.php
deleted file mode 100644
index 3a49aa9b5a..0000000000
--- a/app/Listeners/HandleQuoteApproved.php
+++ /dev/null
@@ -1,42 +0,0 @@
-userMailer = $userMailer;
- }
-
- /**
- * Handle the event.
- *
- * @param QuoteApproved $event
- * @return void
- */
- public function handle(QuoteApproved $event)
- {
- $invoice = $event->invoice;
-
- foreach ($invoice->account->users as $user)
- {
- if ($user->{'notify_approved'})
- {
- $this->userMailer->sendNotification($user, $invoice, 'approved');
- }
- }
- }
-
-}
diff --git a/app/Listeners/HandleUserSignedUp.php b/app/Listeners/HandleUserSignedUp.php
index 5bc4eab28d..08961e1617 100644
--- a/app/Listeners/HandleUserSignedUp.php
+++ b/app/Listeners/HandleUserSignedUp.php
@@ -41,12 +41,6 @@ class HandleUserSignedUp
$this->accountRepo->registerNinjaUser($user);
}
- $activities = Activity::scope()->get();
- foreach ($activities as $activity) {
- $activity->message = str_replace('Guest', $user->getFullName(), $activity->message);
- $activity->save();
- }
-
session([SESSION_COUNTER => -1]);
}
}
diff --git a/app/Listeners/InvoiceListener.php b/app/Listeners/InvoiceListener.php
new file mode 100644
index 0000000000..35762d8f86
--- /dev/null
+++ b/app/Listeners/InvoiceListener.php
@@ -0,0 +1,49 @@
+payment;
+ $invoice = $payment->invoice;
+ $adjustment = $payment->amount * -1;
+ $partial = max(0, $invoice->partial - $payment->amount);
+
+ $invoice->updateBalances($adjustment, $partial);
+ $invoice->updatePaidStatus();
+ }
+
+ public function updatedInvoice(InvoiceWasUpdated $event)
+ {
+ $invoice = $event->invoice;
+ $invoice->updatePaidStatus();
+ }
+
+ public function emailedInvoice(InvoiceWasEmailed $event)
+ {
+ $invoice = $event->invoice;
+ $invoice->markSent();
+ }
+
+ public function viewedInvoice(InvoiceInvitationWasViewed $event)
+ {
+ $invitation = $event->invitation;
+ $invitation->markViewed();
+ }
+
+ public function deletedPayment(PaymentWasDeleted $event)
+ {
+ $payment = $event->payment;
+ $invoice = $payment->invoice;
+ $adjustment = $payment->amount;
+
+ $invoice->updateBalances($adjustment);
+ $invoice->updatePaidStatus();
+ }
+}
diff --git a/app/Listeners/NotificationListener.php b/app/Listeners/NotificationListener.php
new file mode 100644
index 0000000000..aba3044575
--- /dev/null
+++ b/app/Listeners/NotificationListener.php
@@ -0,0 +1,71 @@
+userMailer = $userMailer;
+ $this->contactMailer = $contactMailer;
+ }
+
+ private function sendEmails($invoice, $type, $payment = null)
+ {
+ foreach ($invoice->account->users as $user)
+ {
+ if ($user->{"notify_{$type}"})
+ {
+ $this->userMailer->sendNotification($user, $invoice, $type, $payment);
+ }
+ }
+ }
+
+ public function emailedInvoice(InvoiceWasEmailed $event)
+ {
+ $this->sendEmails($event->invoice, 'sent');
+ }
+
+ public function emailedQuote(QuoteWasEmailed $event)
+ {
+ $this->sendEmails($event->quote, 'sent');
+ }
+
+ public function viewedInvoice(InvoiceInvitationWasViewed $event)
+ {
+ $this->sendEmails($event->invoice, 'viewed');
+ }
+
+ public function viewedQuote(QuoteInvitationWasViewed $event)
+ {
+ $this->sendEmails($event->quote, 'viewed');
+ }
+
+ public function approvedQuote(QuoteInvitationWasApproved $event)
+ {
+ $this->sendEmails($event->quote, 'approved');
+ }
+
+ public function createdPayment(PaymentWasCreated $event)
+ {
+ // only send emails for online payments
+ if ( ! $event->payment->account_gateway_id) {
+ return;
+ }
+
+ $this->contactMailer->sendPaymentConfirmation($event->payment);
+ $this->sendEmails($event->payment->invoice, 'paid', $event->payment);
+ }
+
+}
\ No newline at end of file
diff --git a/app/Listeners/QuoteListener.php b/app/Listeners/QuoteListener.php
new file mode 100644
index 0000000000..a228dc1105
--- /dev/null
+++ b/app/Listeners/QuoteListener.php
@@ -0,0 +1,19 @@
+quote;
+ $quote->markSent();
+ }
+
+ public function viewedQuote(QuoteInvitationWasViewed $event)
+ {
+ $invitation = $event->invitation;
+ $invitation->markViewed();
+ }
+}
diff --git a/app/Listeners/SubscriptionListener.php b/app/Listeners/SubscriptionListener.php
new file mode 100644
index 0000000000..7ef7a1116e
--- /dev/null
+++ b/app/Listeners/SubscriptionListener.php
@@ -0,0 +1,47 @@
+checkSubscriptions(ACTIVITY_TYPE_CREATE_CLIENT, $event->client);
+ }
+
+ public function createdQuote(QuoteWasCreated $event)
+ {
+ $this->checkSubscriptions(ACTIVITY_TYPE_CREATE_QUOTE, $event->quote);
+ }
+
+ public function createdPayment(PaymentWasCreated $event)
+ {
+ $this->checkSubscriptions(ACTIVITY_TYPE_CREATE_PAYMENT, $event->payment);
+ }
+
+ public function createdCredit(CreditWasCreated $event)
+ {
+ $this->checkSubscriptions(ACTIVITY_TYPE_CREATE_CREDIT, $event->credit);
+ }
+
+ public function createdInvoice(InvoiceWasCreated $event)
+ {
+ $this->checkSubscriptions(ACTIVITY_TYPE_CREATE_INVOICE, $event->invoice);
+ }
+
+ private function checkSubscriptions($activityTypeId, $entity)
+ {
+ $subscription = $entity->account->getSubscription($activityTypeId);
+
+ if ($subscription) {
+ Utils::notifyZapier($subscription, $entity);
+ }
+ }
+}
diff --git a/app/Listeners/TaskListener.php b/app/Listeners/TaskListener.php
new file mode 100644
index 0000000000..b52c2fd5f3
--- /dev/null
+++ b/app/Listeners/TaskListener.php
@@ -0,0 +1,14 @@
+invoice->id)
+ ->update(['invoice_id' => null]);
+ }
+}
diff --git a/app/Models/Account.php b/app/Models/Account.php
index c768f0bc6f..c1637700aa 100644
--- a/app/Models/Account.php
+++ b/app/Models/Account.php
@@ -251,7 +251,7 @@ class Account extends Eloquent
$invoice->start_date = Utils::today();
$invoice->invoice_design_id = $this->invoice_design_id;
$invoice->client_id = $clientId;
-
+
if ($entityType === ENTITY_RECURRING_INVOICE) {
$invoice->invoice_number = microtime(true);
$invoice->is_recurring = true;
@@ -316,7 +316,7 @@ class Account extends Eloquent
$pattern = str_replace($search, $replace, $pattern);
- if ($invoice->client->id) {
+ if ($invoice->client_id) {
$pattern = $this->getClientInvoiceNumber($pattern, $invoice);
}
@@ -330,13 +330,11 @@ class Account extends Eloquent
}
$search = [
- //'{$clientId}',
'{$custom1}',
'{$custom2}',
];
$replace = [
- //str_pad($client->public_id, 3, '0', STR_PAD_LEFT),
$invoice->client->custom_value1,
$invoice->client->custom_value2,
];
@@ -344,17 +342,6 @@ class Account extends Eloquent
return str_replace($search, $replace, $pattern);
}
- // if we're using a pattern we don't know the next number until a client
- // is selected, to support this the default value is blank
- public function getDefaultInvoiceNumber($invoice = false)
- {
- if ($this->hasClientNumberPattern($invoice)) {
- return false;
- }
-
- return $this->getNextInvoiceNumber($invoice);
- }
-
public function getCounter($isQuote)
{
return $isQuote && !$this->share_counter ? $this->quote_number_counter : $this->invoice_number_counter;
@@ -372,7 +359,7 @@ class Account extends Eloquent
// confirm the invoice number isn't already taken
do {
- $number = $prefix.str_pad($counter, 4, "0", STR_PAD_LEFT);
+ $number = $prefix.str_pad($counter, 4, '0', STR_PAD_LEFT);
$check = Invoice::scope(false, $this->id)->whereInvoiceNumber($number)->withTrashed()->first();
$counter++;
$counterOffset++;
diff --git a/app/Models/Activity.php b/app/Models/Activity.php
index edb20a7c96..fdf41ce54a 100644
--- a/app/Models/Activity.php
+++ b/app/Models/Activity.php
@@ -23,480 +23,60 @@ class Activity extends Eloquent
public function user()
{
- return $this->belongsTo('App\Models\User');
+ return $this->belongsTo('App\Models\User')->withTrashed();
}
- private static function getBlank($entity = false)
+ public function contact()
{
- $activity = new Activity();
-
- if ($entity) {
- $activity->user_id = $entity instanceof User ? $entity->id : $entity->user_id;
- $activity->account_id = $entity->account_id;
- } elseif (Auth::check()) {
- $activity->user_id = Auth::user()->id;
- $activity->account_id = Auth::user()->account_id;
- } else {
- Utils::fatalError();
- }
-
- $activity->token_id = Session::get('token_id', null);
- $activity->ip = Request::getClientIp();
-
- return $activity;
+ return $this->belongsTo('App\Models\Contact')->withTrashed();
}
- public static function createClient($client, $notify = true)
+ public function client()
{
- $activity = Activity::getBlank();
- $activity->client_id = $client->id;
- $activity->activity_type_id = ACTIVITY_TYPE_CREATE_CLIENT;
- $activity->message = Utils::encodeActivity(Auth::user(), 'created', $client);
- $activity->save();
-
- if ($notify) {
- Activity::checkSubscriptions(EVENT_CREATE_CLIENT, $client);
- }
+ return $this->belongsTo('App\Models\Client')->withTrashed();
}
- public static function updateClient($client)
+ public function invoice()
{
- if ($client->isBeingDeleted()) {
- $activity = Activity::getBlank();
- $activity->client_id = $client->id;
- $activity->activity_type_id = ACTIVITY_TYPE_DELETE_CLIENT;
- $activity->message = Utils::encodeActivity(Auth::user(), 'deleted', $client);
- $activity->balance = $client->balance;
- $activity->save();
- }
+ return $this->belongsTo('App\Models\Invoice')->withTrashed();
}
- public static function archiveClient($client)
+ public function credit()
{
- if (!$client->is_deleted) {
- $activity = Activity::getBlank();
- $activity->client_id = $client->id;
- $activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_CLIENT;
- $activity->message = Utils::encodeActivity(Auth::user(), 'archived', $client);
- $activity->balance = $client->balance;
- $activity->save();
- }
+ return $this->belongsTo('App\Models\Credit')->withTrashed();
}
- public static function restoreClient($client)
+ public function payment()
{
- $activity = Activity::getBlank();
- $activity->client_id = $client->id;
- $activity->activity_type_id = ACTIVITY_TYPE_RESTORE_CLIENT;
- $activity->message = Utils::encodeActivity(Auth::user(), 'restored', $client);
- $activity->balance = $client->balance;
- $activity->save();
+ return $this->belongsTo('App\Models\Payment')->withTrashed();
}
- public static function createInvoice($invoice)
+ public static function calcMessage($activityTypeId, $client, $user, $invoice, $contactId, $payment, $credit, $isSystem)
{
- if (Auth::check()) {
- $message = Utils::encodeActivity(Auth::user(), 'created', $invoice);
- } else {
- $message = Utils::encodeActivity(null, 'created', $invoice);
- }
+ $data = [
+ 'client' => link_to($client->getRoute(), $client->getDisplayName()),
+ 'user' => $isSystem ? '' . trans('texts.system') . ' ' : $user->getDisplayName(),
+ 'invoice' => $invoice ? link_to($invoice->getRoute(), $invoice->getDisplayName()) : null,
+ 'quote' => $invoice ? link_to($invoice->getRoute(), $invoice->getDisplayName()) : null,
+ 'contact' => $contactId ? $client->getDisplayName() : $user->getDisplayName(),
+ 'payment' => $payment ? $payment->transaction_reference : null,
+ 'credit' => $credit ? Utils::formatMoney($credit->amount, $client->currency_id) : null,
+ ];
- $adjustment = 0;
- $client = $invoice->client;
- if (!$invoice->is_quote && !$invoice->is_recurring) {
- $adjustment = $invoice->amount;
- $client->balance = $client->balance + $adjustment;
- $client->save();
- }
-
- $activity = Activity::getBlank($invoice);
- $activity->invoice_id = $invoice->id;
- $activity->client_id = $invoice->client_id;
- $activity->activity_type_id = $invoice->is_quote ? ACTIVITY_TYPE_CREATE_QUOTE : ACTIVITY_TYPE_CREATE_INVOICE;
- $activity->message = $message;
- $activity->balance = $client->balance;
- $activity->adjustment = $adjustment;
- $activity->save();
-
- Activity::checkSubscriptions($invoice->is_quote ? EVENT_CREATE_QUOTE : EVENT_CREATE_INVOICE, $invoice);
+ return trans("texts.activity_{$activityTypeId}", $data);
}
- public static function archiveInvoice($invoice)
+ public function getMessage()
{
- if (!$invoice->is_deleted) {
- $activity = Activity::getBlank();
- $activity->invoice_id = $invoice->id;
- $activity->client_id = $invoice->client_id;
- $activity->activity_type_id = $invoice->is_quote ? ACTIVITY_TYPE_ARCHIVE_QUOTE : ACTIVITY_TYPE_ARCHIVE_INVOICE;
- $activity->message = Utils::encodeActivity(Auth::user(), 'archived', $invoice);
- $activity->balance = $invoice->client->balance;
-
- $activity->save();
- }
- }
-
- public static function restoreInvoice($invoice)
- {
- $activity = Activity::getBlank();
- $activity->invoice_id = $invoice->id;
- $activity->client_id = $invoice->client_id;
- $activity->activity_type_id = $invoice->is_quote ? ACTIVITY_TYPE_RESTORE_QUOTE : ACTIVITY_TYPE_RESTORE_INVOICE;
- $activity->message = Utils::encodeActivity(Auth::user(), 'restored', $invoice);
- $activity->balance = $invoice->client->balance;
-
- $activity->save();
- }
-
- public static function emailInvoice($invitation)
- {
- $invoice = $invitation->invoice;
- $client = $invoice->client;
-
- if (!$invoice->isSent()) {
- $invoice->invoice_status_id = INVOICE_STATUS_SENT;
- $invoice->save();
- }
-
- $activity = Activity::getBlank($invitation);
- $activity->client_id = $invitation->invoice->client_id;
- $activity->invoice_id = $invitation->invoice_id;
- $activity->contact_id = $invitation->contact_id;
- $activity->activity_type_id = $invitation->invoice ? ACTIVITY_TYPE_EMAIL_QUOTE : ACTIVITY_TYPE_EMAIL_INVOICE;
- $activity->message = Utils::encodeActivity(Auth::check() ? Auth::user() : null, 'emailed', $invitation->invoice, $invitation->contact);
- $activity->balance = $client->balance;
- $activity->save();
- }
-
- public static function updateInvoice($invoice)
- {
- $client = $invoice->client;
-
- if ($invoice->isBeingDeleted()) {
- $adjustment = 0;
- if (!$invoice->is_quote && !$invoice->is_recurring) {
- $adjustment = $invoice->balance * -1;
- $client->balance = $client->balance - $invoice->balance;
- $client->paid_to_date = $client->paid_to_date - ($invoice->amount - $invoice->balance);
- $client->save();
- }
-
- $activity = Activity::getBlank();
- $activity->client_id = $invoice->client_id;
- $activity->invoice_id = $invoice->id;
- $activity->activity_type_id = $invoice->is_quote ? ACTIVITY_TYPE_DELETE_QUOTE : ACTIVITY_TYPE_DELETE_INVOICE;
- $activity->message = Utils::encodeActivity(Auth::user(), 'deleted', $invoice);
- $activity->balance = $invoice->client->balance;
- $activity->adjustment = $adjustment;
- $activity->save();
-
- // Release any tasks associated with the deleted invoice
- Task::where('invoice_id', '=', $invoice->id)
- ->update(['invoice_id' => null]);
- } else {
- $diff = floatval($invoice->amount) - floatval($invoice->getOriginal('amount'));
-
- $fieldChanged = false;
- foreach (['invoice_number', 'po_number', 'invoice_date', 'due_date', 'terms', 'public_notes', 'invoice_footer', 'partial'] as $field) {
- if ($invoice->$field != $invoice->getOriginal($field)) {
- $fieldChanged = true;
- break;
- }
- }
-
- if ($diff != 0 || $fieldChanged) {
- $backupInvoice = Invoice::with('invoice_items', 'client.account', 'client.contacts')->find($invoice->id);
-
- if ($diff != 0 && !$invoice->is_quote && !$invoice->is_recurring) {
- $client->balance = $client->balance + $diff;
- $client->save();
- }
-
- $activity = Activity::getBlank($invoice);
- $activity->client_id = $invoice->client_id;
- $activity->invoice_id = $invoice->id;
- $activity->activity_type_id = $invoice->is_quote ? ACTIVITY_TYPE_UPDATE_QUOTE : ACTIVITY_TYPE_UPDATE_INVOICE;
- $activity->message = Utils::encodeActivity(Auth::user(), 'updated', $invoice);
- $activity->balance = $client->balance;
- $activity->adjustment = $invoice->is_quote || $invoice->is_recurring ? 0 : $diff;
- $activity->json_backup = $backupInvoice->hidePrivateFields()->toJSON();
- $activity->save();
-
- if ($invoice->isPaid() && $invoice->balance > 0) {
- $invoice->invoice_status_id = INVOICE_STATUS_PARTIAL;
- } elseif ($invoice->invoice_status_id && $invoice->balance == 0) {
- $invoice->invoice_status_id = INVOICE_STATUS_PAID;
- }
- }
- }
- }
-
- public static function viewInvoice($invitation)
- {
- if (Session::get($invitation->invitation_key)) {
- return;
- }
-
- Session::put($invitation->invitation_key, true);
- $invoice = $invitation->invoice;
-
- if (!$invoice->isViewed()) {
- $invoice->invoice_status_id = INVOICE_STATUS_VIEWED;
- $invoice->save();
- }
-
- $now = Carbon::now()->toDateTimeString();
-
- $invitation->viewed_date = $now;
- $invitation->save();
-
- $client = $invoice->client;
- $client->last_login = $now;
- $client->save();
-
- $activity = Activity::getBlank($invitation);
- $activity->client_id = $invitation->invoice->client_id;
- $activity->invitation_id = $invitation->id;
- $activity->contact_id = $invitation->contact_id;
- $activity->invoice_id = $invitation->invoice_id;
- $activity->activity_type_id = $invitation->invoice->is_quote ? ACTIVITY_TYPE_VIEW_QUOTE : ACTIVITY_TYPE_VIEW_INVOICE;
- $activity->message = Utils::encodeActivity($invitation->contact, 'viewed', $invitation->invoice);
- $activity->balance = $invitation->invoice->client->balance;
- $activity->save();
- }
-
- public static function approveQuote($invitation) {
-
- $activity = Activity::getBlank($invitation);
- $activity->client_id = $invitation->invoice->client_id;
- $activity->invitation_id = $invitation->id;
- $activity->contact_id = $invitation->contact_id;
- $activity->invoice_id = $invitation->invoice_id;
- $activity->activity_type_id = ACTIVITY_TYPE_APPROVE_QUOTE;
- $activity->message = Utils::encodeActivity($invitation->contact, 'approved', $invitation->invoice);
- $activity->balance = $invitation->invoice->client->balance;
- $activity->save();
- }
-
- public static function createPayment($payment)
- {
- $client = $payment->client;
- $client->balance = $client->balance - $payment->amount;
- $client->paid_to_date = $client->paid_to_date + $payment->amount;
- $client->save();
-
- if ($payment->contact_id) {
- $activity = Activity::getBlank($client);
- $activity->contact_id = $payment->contact_id;
- $activity->message = Utils::encodeActivity($payment->invitation->contact, 'entered '.$payment->getName().' for ', $payment->invoice);
- } else {
- $activity = Activity::getBlank($client);
- $message = $payment->payment_type_id == PAYMENT_TYPE_CREDIT ? 'applied credit for ' : 'entered '.$payment->getName().' for ';
- $activity->message = Utils::encodeActivity(Auth::user(), $message, $payment->invoice);
- }
-
- $activity->payment_id = $payment->id;
-
- if ($payment->invoice_id) {
- $activity->invoice_id = $payment->invoice_id;
-
- $invoice = $payment->invoice;
- $invoice->balance = $invoice->balance - $payment->amount;
- $invoice->invoice_status_id = ($invoice->balance > 0) ? INVOICE_STATUS_PARTIAL : INVOICE_STATUS_PAID;
- if ($invoice->partial > 0) {
- $invoice->partial = max(0, $invoice->partial - $payment->amount);
- }
- $invoice->save();
- }
-
- $activity->payment_id = $payment->id;
- $activity->client_id = $payment->client_id;
- $activity->activity_type_id = ACTIVITY_TYPE_CREATE_PAYMENT;
- $activity->balance = $client->balance;
- $activity->adjustment = $payment->amount * -1;
- $activity->save();
-
- Activity::checkSubscriptions(EVENT_CREATE_PAYMENT, $payment);
- }
-
- public static function updatePayment($payment)
- {
- if ($payment->isBeingDeleted()) {
- $client = $payment->client;
- $client->balance = $client->balance + $payment->amount;
- $client->paid_to_date = $client->paid_to_date - $payment->amount;
- $client->save();
-
- $invoice = $payment->invoice;
- $invoice->balance = $invoice->balance + $payment->amount;
- if ($invoice->isPaid() && $invoice->balance > 0) {
- $invoice->invoice_status_id = ($invoice->balance == $invoice->amount ? INVOICE_STATUS_DRAFT : INVOICE_STATUS_PARTIAL);
- }
- $invoice->save();
-
- // deleting a payment from credit creates a new credit
- if ($payment->payment_type_id == PAYMENT_TYPE_CREDIT) {
- $credit = Credit::createNew();
- $credit->client_id = $client->id;
- $credit->credit_date = Carbon::now()->toDateTimeString();
- $credit->balance = $credit->amount = $payment->amount;
- $credit->private_notes = $payment->transaction_reference;
- $credit->save();
- }
-
- $activity = Activity::getBlank();
- $activity->payment_id = $payment->id;
- $activity->client_id = $invoice->client_id;
- $activity->invoice_id = $invoice->id;
- $activity->activity_type_id = ACTIVITY_TYPE_DELETE_PAYMENT;
- $activity->message = Utils::encodeActivity(Auth::user(), 'deleted '.$payment->getName());
- $activity->balance = $client->balance;
- $activity->adjustment = $payment->amount;
- $activity->save();
- } else {
- /*
- $diff = floatval($invoice->amount) - floatval($invoice->getOriginal('amount'));
-
- if ($diff == 0)
- {
- return;
- }
-
- $client = $invoice->client;
- $client->balance = $client->balance + $diff;
- $client->save();
-
- $activity = Activity::getBlank($invoice);
- $activity->client_id = $invoice->client_id;
- $activity->invoice_id = $invoice->id;
- $activity->activity_type_id = ACTIVITY_TYPE_UPDATE_INVOICE;
- $activity->message = Utils::encodeActivity(Auth::user(), 'updated', $invoice);
- $activity->balance = $client->balance;
- $activity->adjustment = $diff;
- $activity->json_backup = $backupInvoice->hidePrivateFields()->toJSON();
- $activity->save();
- */
- }
- }
-
- public static function archivePayment($payment)
- {
- if ($payment->is_deleted) {
- return;
- }
-
- $client = $payment->client;
- $invoice = $payment->invoice;
-
- $activity = Activity::getBlank();
- $activity->payment_id = $payment->id;
- $activity->invoice_id = $invoice->id;
- $activity->client_id = $client->id;
- $activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_PAYMENT;
- $activity->message = Utils::encodeActivity(Auth::user(), 'archived '.$payment->getName());
- $activity->balance = $client->balance;
- $activity->adjustment = 0;
- $activity->save();
- }
-
- public static function restorePayment($payment)
- {
- $client = $payment->client;
- $invoice = $payment->invoice;
-
- $activity = Activity::getBlank();
- $activity->payment_id = $payment->id;
- $activity->invoice_id = $invoice->id;
- $activity->client_id = $client->id;
- $activity->activity_type_id = ACTIVITY_TYPE_RESTORE_PAYMENT;
- $activity->message = Utils::encodeActivity(Auth::user(), 'restored '.$payment->getName());
- $activity->balance = $client->balance;
- $activity->adjustment = 0;
- $activity->save();
- }
-
- public static function createCredit($credit)
- {
- $activity = Activity::getBlank();
- $activity->message = Utils::encodeActivity(Auth::user(), 'entered '.Utils::formatMoney($credit->amount, $credit->client->getCurrencyId()).' credit');
- $activity->credit_id = $credit->id;
- $activity->client_id = $credit->client_id;
- $activity->activity_type_id = ACTIVITY_TYPE_CREATE_CREDIT;
- $activity->balance = $credit->client->balance;
- $activity->save();
- }
-
- public static function updateCredit($credit)
- {
- if ($credit->isBeingDeleted()) {
- $activity = Activity::getBlank();
- $activity->credit_id = $credit->id;
- $activity->client_id = $credit->client_id;
- $activity->activity_type_id = ACTIVITY_TYPE_DELETE_CREDIT;
- $activity->message = Utils::encodeActivity(Auth::user(), 'deleted '.Utils::formatMoney($credit->balance, $credit->client->getCurrencyId()).' credit');
- $activity->balance = $credit->client->balance;
- $activity->save();
- } else {
- /*
- $diff = floatval($invoice->amount) - floatval($invoice->getOriginal('amount'));
-
- if ($diff == 0)
- {
- return;
- }
-
- $client = $invoice->client;
- $client->balance = $client->balance + $diff;
- $client->save();
-
- $activity = Activity::getBlank($invoice);
- $activity->client_id = $invoice->client_id;
- $activity->invoice_id = $invoice->id;
- $activity->activity_type_id = ACTIVITY_TYPE_UPDATE_INVOICE;
- $activity->message = Utils::encodeActivity(Auth::user(), 'updated', $invoice);
- $activity->balance = $client->balance;
- $activity->adjustment = $diff;
- $activity->json_backup = $backupInvoice->hidePrivateFields()->toJSON();
- $activity->save();
- */
- }
- }
-
- public static function archiveCredit($credit)
- {
- if ($credit->is_deleted) {
- return;
- }
-
- $activity = Activity::getBlank();
- $activity->client_id = $credit->client_id;
- $activity->credit_id = $credit->id;
- $activity->activity_type_id = ACTIVITY_TYPE_ARCHIVE_CREDIT;
- $activity->message = Utils::encodeActivity(Auth::user(), 'archived '.Utils::formatMoney($credit->balance, $credit->client->getCurrencyId()).' credit');
- $activity->balance = $credit->client->balance;
- $activity->save();
- }
-
- public static function restoreCredit($credit)
- {
- $activity = Activity::getBlank();
- $activity->client_id = $credit->client_id;
- $activity->credit_id = $credit->id;
- $activity->activity_type_id = ACTIVITY_TYPE_RESTORE_CREDIT;
- $activity->message = Utils::encodeActivity(Auth::user(), 'restored '.Utils::formatMoney($credit->balance, $credit->client->getCurrencyId()).' credit');
- $activity->balance = $credit->client->balance;
- $activity->save();
- }
-
- private static function checkSubscriptions($event, $data)
- {
- if (!Auth::check()) {
- return;
- }
-
- $subscription = Auth::user()->account->getSubscription($event);
-
- if ($subscription) {
- Utils::notifyZapier($subscription, $data);
- }
+ return static::calcMessage(
+ $this->activity_type_id,
+ $this->client,
+ $this->user,
+ $this->invoice,
+ $this->contact_id,
+ $this->payment,
+ $this->credit,
+ $this->is_system
+ );
}
}
diff --git a/app/Models/BalanceAffecting.php b/app/Models/BalanceAffecting.php
new file mode 100644
index 0000000000..0ba99f73a2
--- /dev/null
+++ b/app/Models/BalanceAffecting.php
@@ -0,0 +1,6 @@
+belongsTo('App\Models\Industry');
}
+ public function addContact($data, $isPrimary = false)
+ {
+ $publicId = isset($data['public_id']) ? $data['public_id'] : false;
+
+ if ($publicId && $publicId != '-1') {
+ $contact = Contact::scope($publicId)->firstOrFail();
+ } else {
+ $contact = Contact::createNew();
+ $contact->send_invoice = true;
+ }
+
+ $contact->fill($data);
+ $contact->is_primary = $isPrimary;
+
+ return $this->contacts()->save($contact);
+ }
+
+ public function updateBalances($balanceAdjustment, $paidToDateAdjustment)
+ {
+ if ($balanceAdjustment === 0 && $paidToDateAdjustment === 0) {
+ return;
+ }
+
+ $this->balance = $this->balance + $balanceAdjustment;
+ $this->paid_to_date = $this->paid_to_date + $paidToDateAdjustment;
+
+ $this->save();
+ }
+
+ public function getRoute()
+ {
+ return "/clients/{$this->public_id}";
+ }
+
public function getTotalCredit()
{
return DB::table('credits')
@@ -89,8 +147,11 @@ class Client extends EntityModel
return $this->name;
}
- $contact = $this->contacts()->first();
+ if ( ! count($this->contacts)) {
+ return '';
+ }
+ $contact = $this->contacts[0];
return $contact->getDisplayName();
}
@@ -178,24 +239,26 @@ class Client extends EntityModel
{
return $isQuote ? $this->quote_number_counter : $this->invoice_number_counter;
}
+
+ public function markLoggedIn()
+ {
+ $this->last_login = Carbon::now()->toDateTimeString();
+ $this->save();
+ }
}
-/*
-Client::created(function($client)
-{
- Activity::createClient($client);
+Client::creating(function ($client) {
+ $client->setNullValues();
+});
+
+Client::created(function ($client) {
+ event(new ClientWasCreated($client));
});
-*/
Client::updating(function ($client) {
- Activity::updateClient($client);
+ $client->setNullValues();
});
-Client::deleting(function ($client) {
- Activity::archiveClient($client);
+Client::updated(function ($client) {
+ event(new ClientWasUpdated($client));
});
-
-/*Client::restoring(function ($client) {
- Activity::restoreClient($client);
-});
-*/
\ No newline at end of file
diff --git a/app/Models/Contact.php b/app/Models/Contact.php
index 0856a6d431..731900e358 100644
--- a/app/Models/Contact.php
+++ b/app/Models/Contact.php
@@ -9,6 +9,14 @@ class Contact extends EntityModel
use SoftDeletes;
protected $dates = ['deleted_at'];
+ protected $fillable = [
+ 'first_name',
+ 'last_name',
+ 'email',
+ 'phone',
+ 'send_invoice',
+ ];
+
public static $fieldFirstName = 'Contact - First Name';
public static $fieldLastName = 'Contact - Last Name';
public static $fieldEmail = 'Contact - Email';
diff --git a/app/Models/Credit.php b/app/Models/Credit.php
index 9a507bc6bb..a89e9e9252 100644
--- a/app/Models/Credit.php
+++ b/app/Models/Credit.php
@@ -1,12 +1,19 @@
belongsTo('App\Models\Account');
+ }
+
public function invoice()
{
return $this->belongsTo('App\Models\Invoice')->withTrashed();
@@ -43,18 +50,10 @@ class Credit extends EntityModel
}
}
+Credit::creating(function ($credit) {
+
+});
+
Credit::created(function ($credit) {
- Activity::createCredit($credit);
-});
-
-Credit::updating(function ($credit) {
- Activity::updateCredit($credit);
-});
-
-Credit::deleting(function ($credit) {
- Activity::archiveCredit($credit);
-});
-
-Credit::restoring(function ($credit) {
- Activity::restoreCredit($credit);
-});
+ event(new CreditWasCreated($credit));
+});
\ No newline at end of file
diff --git a/app/Models/EntityModel.php b/app/Models/EntityModel.php
index f9a375dc44..9dd294cacb 100644
--- a/app/Models/EntityModel.php
+++ b/app/Models/EntityModel.php
@@ -39,7 +39,7 @@ class EntityModel extends Eloquent
{
$className = get_called_class();
- return $className::scope($publicId)->pluck('id');
+ return $className::scope($publicId)->withTrashed()->pluck('id');
}
public function getActivityKey()
@@ -112,8 +112,21 @@ class EntityModel extends Eloquent
return $data;
}
- public function isBeingDeleted()
+ public function setNullValues()
{
- return $this->is_deleted && !$this->getOriginal('is_deleted');
+ foreach ($this->fillable as $field) {
+ if (strstr($field, '_id') && !$this->$field) {
+ $this->$field = null;
+ }
+ }
+ }
+
+ // converts "App\Models\Client" to "client_id"
+ public function getKeyField()
+ {
+ $class = get_class($this);
+ $parts = explode('\\', $class);
+ $name = $parts[count($parts)-1];
+ return strtolower($name) . '_id';
}
}
diff --git a/app/Models/Invitation.php b/app/Models/Invitation.php
index 00807b1a69..821b8b8659 100644
--- a/app/Models/Invitation.php
+++ b/app/Models/Invitation.php
@@ -1,6 +1,7 @@
invitation_key;
}
+ public function markViewed()
+ {
+ $invoice = $this->invoice;
+ $client = $invoice->client;
+
+ $this->viewed_date = Carbon::now()->toDateTimeString();
+ $this->save();
+
+ $invoice->markViewed();
+ $client->markLoggedIn();
+ }
}
diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php
index 7a0a8c9535..59ea9a60de 100644
--- a/app/Models/Invoice.php
+++ b/app/Models/Invoice.php
@@ -2,9 +2,15 @@
use Utils;
use DateTime;
+use App\Models\BalanceAffecting;
use Illuminate\Database\Eloquent\SoftDeletes;
-class Invoice extends EntityModel
+use App\Events\QuoteWasCreated;
+use App\Events\QuoteWasUpdated;
+use App\Events\InvoiceWasCreated;
+use App\Events\InvoiceWasUpdated;
+
+class Invoice extends EntityModel implements BalanceAffecting
{
use SoftDeletes {
SoftDeletes::trashed as parentTrashed;
@@ -26,6 +32,64 @@ class Invoice extends EntityModel
'year',
'date:',
];
+
+ public function getRoute()
+ {
+ $entityType = $this->getEntityType();
+ return "/{$entityType}s/{$this->public_id}/edit";
+ }
+
+ public function getDisplayName()
+ {
+ return $this->is_recurring ? trans('texts.recurring') : $this->invoice_number;
+ }
+
+ public function getAdjustment()
+ {
+ if ($this->is_quote || $this->is_recurring) {
+ return 0;
+ }
+
+ return $this->getRawAdjustment();
+ }
+
+ private function getRawAdjustment()
+ {
+ return floatval($this->amount) - floatval($this->getOriginal('amount'));
+ }
+
+ public function isChanged()
+ {
+ if ($this->getRawAdjustment() != 0) {
+ return true;
+ }
+
+ foreach ([
+ 'invoice_number',
+ 'po_number',
+ 'invoice_date',
+ 'due_date',
+ 'terms',
+ 'public_notes',
+ 'invoice_footer',
+ 'partial'
+ ] as $field) {
+ if ($this->$field != $this->getOriginal($field)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function getAmountPaid()
+ {
+ if ($this->is_quote || $this->is_recurring) {
+ return 0;
+ }
+
+ return ($this->amount - $this->balance);
+ }
public function trashed()
{
@@ -81,6 +145,44 @@ class Invoice extends EntityModel
return $this->hasMany('App\Models\Invitation')->orderBy('invitations.contact_id');
}
+ public function markSent()
+ {
+ if (!$this->isSent()) {
+ $this->invoice_status_id = INVOICE_STATUS_SENT;
+ $this->save();
+ }
+ }
+
+ public function markViewed()
+ {
+ if (!$this->isViewed()) {
+ $this->invoice_status_id = INVOICE_STATUS_VIEWED;
+ $this->save();
+ }
+ }
+
+ public function updatePaidStatus()
+ {
+ if ($this->isPaid() && $this->balance > 0) {
+ $this->invoice_status_id = ($this->balance == $this->amount ? INVOICE_STATUS_SENT : INVOICE_STATUS_PARTIAL);
+ $this->save();
+ } elseif ($this->invoice_status_id && $this->amount && $this->balance == 0 && $this->invoice_status_id != INVOICE_STATUS_PAID) {
+ $this->invoice_status_id = INVOICE_STATUS_PAID;
+ $this->save();
+ }
+ }
+
+ public function updateBalances($balanceAdjustment, $partial = 0)
+ {
+ $this->balance = $this->balance + $balanceAdjustment;
+
+ if ($this->partial > 0) {
+ $this->partial = $partial;
+ }
+
+ $this->save();
+ }
+
public function getName()
{
return $this->is_recurring ? trans('texts.recurring') : $this->invoice_number;
@@ -458,17 +560,17 @@ Invoice::creating(function ($invoice) {
});
Invoice::created(function ($invoice) {
- Activity::createInvoice($invoice);
+ if ($invoice->is_quote) {
+ event(new QuoteWasCreated($invoice));
+ } else {
+ event(new InvoiceWasCreated($invoice));
+ }
});
Invoice::updating(function ($invoice) {
- Activity::updateInvoice($invoice);
-});
-
-Invoice::deleting(function ($invoice) {
- Activity::archiveInvoice($invoice);
-});
-
-Invoice::restoring(function ($invoice) {
- Activity::restoreInvoice($invoice);
+ if ($invoice->is_quote) {
+ event(new QuoteWasUpdated($invoice));
+ } else {
+ event(new InvoiceWasUpdated($invoice));
+ }
});
\ No newline at end of file
diff --git a/app/Models/Payment.php b/app/Models/Payment.php
index ee382dece1..d0a1ae466b 100644
--- a/app/Models/Payment.php
+++ b/app/Models/Payment.php
@@ -1,6 +1,7 @@
belongsTo('App\Models\Contact');
}
+ public function getRoute()
+ {
+ return "/payments/{$this->public_id}/edit";
+ }
+
public function getAmount()
{
return Utils::formatMoney($this->amount, $this->client->getCurrencyId());
@@ -53,18 +59,10 @@ class Payment extends EntityModel
}
}
+Payment::creating(function ($payment) {
+
+});
+
Payment::created(function ($payment) {
- Activity::createPayment($payment);
-});
-
-Payment::updating(function ($payment) {
- Activity::updatePayment($payment);
-});
-
-Payment::deleting(function ($payment) {
- Activity::archivePayment($payment);
-});
-
-Payment::restoring(function ($payment) {
- Activity::restorePayment($payment);
-});
+ event(new PaymentWasCreated($payment));
+});
\ No newline at end of file
diff --git a/app/Models/Task.php b/app/Models/Task.php
index 4ccbf9688a..fbdd00c46f 100644
--- a/app/Models/Task.php
+++ b/app/Models/Task.php
@@ -82,20 +82,4 @@ class Task extends EntityModel
{
return round($this->getDuration() / (60 * 60), 2);
}
-}
-
-Task::created(function ($task) {
- //Activity::createTask($task);
-});
-
-Task::updating(function ($task) {
- //Activity::updateTask($task);
-});
-
-Task::deleting(function ($task) {
- //Activity::archiveTask($task);
-});
-
-Task::restoring(function ($task) {
- //Activity::restoreTask($task);
-});
+}
\ No newline at end of file
diff --git a/app/Ninja/Mailers/ContactMailer.php b/app/Ninja/Mailers/ContactMailer.php
index ff4f28c51c..d6d5e70a18 100644
--- a/app/Ninja/Mailers/ContactMailer.php
+++ b/app/Ninja/Mailers/ContactMailer.php
@@ -9,7 +9,12 @@ use App\Models\Invoice;
use App\Models\Payment;
use App\Models\Activity;
use App\Models\Gateway;
-use App\Events\InvoiceSent;
+
+use App\Events\InvoiceWasEmailed;
+use App\Events\InvoiceInvitationWasEmailed;
+
+use App\Events\QuoteWasEmailed;
+use App\Events\QuoteInvitationWasEmailed;
class ContactMailer extends Mailer
{
@@ -44,7 +49,11 @@ class ContactMailer extends Mailer
$account->loadLocalizationSettings();
if ($sent === true) {
- Event::fire(new InvoiceSent($invoice));
+ if ($invoice->is_quote) {
+ event(new QuoteWasEmailed($invoice));
+ } else {
+ event(new InvoiceWasEmailed($invoice));
+ }
}
return $sent ?: trans('texts.email_error');
@@ -97,7 +106,12 @@ class ContactMailer extends Mailer
$response = $this->sendTo($invitation->contact->email, $fromEmail, $account->getDisplayName(), $subject, ENTITY_INVOICE, $data);
if ($response === true) {
- Activity::emailInvoice($invitation);
+ if ($invoice->is_quote) {
+ event(new QuoteInvitationWasEmailed($invoice, $invitation));
+ } else {
+ event(new InvoiceInvitationWasEmailed($invoice, $invitation));
+ }
+
return true;
} else {
return false;
diff --git a/app/Ninja/Repositories/ActivityRepository.php b/app/Ninja/Repositories/ActivityRepository.php
new file mode 100644
index 0000000000..8b06927418
--- /dev/null
+++ b/app/Ninja/Repositories/ActivityRepository.php
@@ -0,0 +1,102 @@
+invoice->client;
+ } else {
+ $client = $entity->client;
+ }
+
+ // init activity and copy over context
+ $activity = self::getBlank($altEntity ?: $client);
+ $activity = Utils::copyContext($activity, $entity);
+ $activity = Utils::copyContext($activity, $altEntity);
+
+ $activity->client_id = $client->id;
+ $activity->activity_type_id = $activityTypeId;
+ $activity->adjustment = $balanceChange;
+ $activity->balance = $client->balance + $balanceChange;
+
+ $keyField = $entity->getKeyField();
+ $activity->$keyField = $entity->id;
+
+ $activity->ip = Request::getClientIp();
+ $activity->save();
+
+ $client->updateBalances($balanceChange, $paidToDateChange);
+
+ return $activity;
+ }
+
+ private function getBlank($entity)
+ {
+ $activity = new Activity();
+
+ if (Auth::check()) {
+ $activity->user_id = Auth::user()->id;
+ $activity->account_id = Auth::user()->account_id;
+ } else {
+ $activity->user_id = $entity->user_id;
+ $activity->account_id = $entity->account_id;
+
+ if ( ! $entity instanceof Invitation) {
+ $activity->is_system = true;
+ }
+ }
+
+ $activity->token_id = session('token_id');
+
+ return $activity;
+ }
+
+ public function findByClientId($clientId)
+ {
+ return DB::table('activities')
+ ->join('users', 'users.id', '=', 'activities.user_id')
+ ->join('clients', 'clients.id', '=', 'activities.client_id')
+ ->leftJoin('contacts', 'contacts.client_id', '=', 'clients.id')
+ ->leftJoin('invoices', 'invoices.id', '=', 'activities.invoice_id')
+ ->leftJoin('payments', 'payments.id', '=', 'activities.payment_id')
+ ->leftJoin('credits', 'credits.id', '=', 'activities.credit_id')
+ ->where('activities.client_id', '=', $clientId)
+ ->where('contacts.is_primary', '=', 1)
+ ->whereNull('contacts.deleted_at')
+ ->select(
+ 'activities.id',
+ 'activities.created_at',
+ 'activities.contact_id',
+ 'activities.activity_type_id',
+ 'activities.is_system',
+ 'clients.currency_id',
+ 'activities.balance',
+ 'activities.adjustment',
+ 'users.first_name as user_first_name',
+ 'users.last_name as user_last_name',
+ 'users.email as user_email',
+ 'invoices.invoice_number as invoice',
+ 'invoices.public_id as invoice_public_id',
+ 'invoices.is_recurring',
+ 'clients.currency_id',
+ 'clients.name as client_name',
+ 'clients.public_id as client_public_id',
+ 'contacts.id as contact',
+ 'contacts.first_name as first_name',
+ 'contacts.last_name as last_name',
+ 'contacts.email as email',
+ 'payments.transaction_reference as payment',
+ 'credits.amount as credit');
+ }
+
+}
\ No newline at end of file
diff --git a/app/Ninja/Repositories/BaseRepository.php b/app/Ninja/Repositories/BaseRepository.php
new file mode 100644
index 0000000000..b9e9d0459f
--- /dev/null
+++ b/app/Ninja/Repositories/BaseRepository.php
@@ -0,0 +1,58 @@
+getClassName();
+ return new $className();
+ }
+
+ private function dispatchEvent($entity, $type)
+ {
+ $className = 'App\Events\\' . ucfirst($entity->getEntityType()) . 'Was' . $type;
+ event(new $className($entity));
+ }
+
+ public function archive($entity)
+ {
+ $entity->delete();
+
+ $this->dispatchEvent($entity, 'Archived');
+ }
+
+ public function restore($entity)
+ {
+ $entity->restore();
+
+ $entity->is_deleted = false;
+ $entity->save();
+
+ $this->dispatchEvent($entity, 'Restored');
+ }
+
+ public function delete($entity)
+ {
+ $entity->is_deleted = true;
+ $entity->save();
+
+ $entity->delete();
+
+ $this->dispatchEvent($entity, 'Deleted');
+ }
+
+ public function findByPublicIds($ids)
+ {
+ return $this->getInstance()->scope($ids)->get();
+ }
+
+ public function findByPublicIdsWithTrashed($ids)
+ {
+ return $this->getInstance()->scope($ids)->withTrashed()->get();
+ }
+}
diff --git a/app/Ninja/Repositories/ClientRepository.php b/app/Ninja/Repositories/ClientRepository.php
index 091c66f9c5..728b0bccae 100644
--- a/app/Ninja/Repositories/ClientRepository.php
+++ b/app/Ninja/Repositories/ClientRepository.php
@@ -1,11 +1,17 @@
'email|required_without:first_name',
- 'first_name' => 'required_without:email',
- ]);
- if ($validator->fails()) {
- return $validator->messages();
- }
+ $publicId = isset($data['public_id']) ? $data['public_id'] : false;
- return false;
- }
-
- public function save($publicId, $data, $notify = true)
- {
- if (!$publicId || $publicId == "-1") {
+ if (!$publicId || $publicId == '-1') {
$client = Client::createNew();
- $contact = Contact::createNew();
- $contact->is_primary = true;
- $contact->send_invoice = true;
} else {
$client = Client::scope($publicId)->with('contacts')->firstOrFail();
- $contact = $client->contacts()->where('is_primary', '=', true)->firstOrFail();
- }
-
- if (isset($data['name'])) {
- $client->name = trim($data['name']);
- }
- if (isset($data['id_number'])) {
- $client->id_number = trim($data['id_number']);
- }
- if (isset($data['vat_number'])) {
- $client->vat_number = trim($data['vat_number']);
- }
- if (isset($data['work_phone'])) {
- $client->work_phone = trim($data['work_phone']);
- }
- if (isset($data['custom_value1'])) {
- $client->custom_value1 = trim($data['custom_value1']);
- }
- if (isset($data['custom_value2'])) {
- $client->custom_value2 = trim($data['custom_value2']);
- }
- if (isset($data['address1'])) {
- $client->address1 = trim($data['address1']);
- }
- if (isset($data['address2'])) {
- $client->address2 = trim($data['address2']);
- }
- if (isset($data['city'])) {
- $client->city = trim($data['city']);
- }
- if (isset($data['state'])) {
- $client->state = trim($data['state']);
- }
- if (isset($data['postal_code'])) {
- $client->postal_code = trim($data['postal_code']);
- }
- if (isset($data['country_id'])) {
- $client->country_id = $data['country_id'] ? $data['country_id'] : null;
- }
- if (isset($data['private_notes'])) {
- $client->private_notes = trim($data['private_notes']);
- }
- if (isset($data['size_id'])) {
- $client->size_id = $data['size_id'] ? $data['size_id'] : null;
- }
- if (isset($data['industry_id'])) {
- $client->industry_id = $data['industry_id'] ? $data['industry_id'] : null;
- }
- if (isset($data['currency_id'])) {
- $client->currency_id = $data['currency_id'] ? $data['currency_id'] : null;
- }
- if (isset($data['language_id'])) {
- $client->language_id = $data['language_id'] ? $data['language_id'] : null;
- }
- if (isset($data['payment_terms'])) {
- $client->payment_terms = $data['payment_terms'];
- }
- if (isset($data['website'])) {
- $client->website = trim($data['website']);
}
+ $client->fill($data);
$client->save();
- $isPrimary = true;
+ $first = true;
+ $contacts = isset($data['contact']) ? [$data['contact']] : $data['contacts'];
$contactIds = [];
- if (isset($data['contact'])) {
- $info = $data['contact'];
- if (isset($info['email'])) {
- $contact->email = trim($info['email']);
- }
- if (isset($info['first_name'])) {
- $contact->first_name = trim($info['first_name']);
- }
- if (isset($info['last_name'])) {
- $contact->last_name = trim($info['last_name']);
- }
- if (isset($info['phone'])) {
- $contact->phone = trim($info['phone']);
- }
- $contact->is_primary = true;
- $contact->send_invoice = true;
- $client->contacts()->save($contact);
- } else {
- foreach ($data['contacts'] as $record) {
- $record = (array) $record;
-
- if ($publicId != "-1" && isset($record['public_id']) && $record['public_id']) {
- $contact = Contact::scope($record['public_id'])->firstOrFail();
- } else {
- $contact = Contact::createNew();
- }
-
- if (isset($record['email'])) {
- $contact->email = trim($record['email']);
- }
- if (isset($record['first_name'])) {
- $contact->first_name = trim($record['first_name']);
- }
- if (isset($record['last_name'])) {
- $contact->last_name = trim($record['last_name']);
- }
- if (isset($record['phone'])) {
- $contact->phone = trim($record['phone']);
- }
- $contact->is_primary = $isPrimary;
- $contact->send_invoice = isset($record['send_invoice']) ? $record['send_invoice'] : true;
- $isPrimary = false;
-
- $client->contacts()->save($contact);
- $contactIds[] = $contact->public_id;
- }
-
- foreach ($client->contacts as $contact) {
- if (!in_array($contact->public_id, $contactIds)) {
- $contact->delete();
- }
- }
+ foreach ($data['contacts'] as $contact) {
+ $contact = $client->addContact($contact, $first);
+ $contactIds[] = $contact->public_id;
+ $first = false;
}
- $client->save();
-
- if (!$publicId || $publicId == "-1") {
- Activity::createClient($client, $notify);
+ foreach ($client->contacts as $contact) {
+ if (!in_array($contact->public_id, $contactIds)) {
+ $contact->delete();
+ }
}
return $client;
}
-
- public function bulk($ids, $action)
- {
- $clients = Client::withTrashed()->scope($ids)->get();
-
- foreach ($clients as $client) {
- if ($action == 'restore') {
- $client->restore();
-
- $client->is_deleted = false;
- $client->save();
- } else {
- if ($action == 'delete') {
- $client->is_deleted = true;
- $client->save();
- }
-
- $client->delete();
- }
- }
-
- return count($clients);
- }
}
diff --git a/app/Ninja/Repositories/CreditRepository.php b/app/Ninja/Repositories/CreditRepository.php
index 7004676202..1ac543c5b2 100644
--- a/app/Ninja/Repositories/CreditRepository.php
+++ b/app/Ninja/Repositories/CreditRepository.php
@@ -1,11 +1,17 @@
firstOrFail();
} else {
@@ -50,28 +58,4 @@ class CreditRepository
return $credit;
}
-
- public function bulk($ids, $action)
- {
- if (!$ids) {
- return 0;
- }
-
- $credits = Credit::withTrashed()->scope($ids)->get();
-
- foreach ($credits as $credit) {
- if ($action == 'restore') {
- $credit->restore();
- } else {
- if ($action == 'delete') {
- $credit->is_deleted = true;
- $credit->save();
- }
-
- $credit->delete();
- }
- }
-
- return count($credits);
- }
}
diff --git a/app/Ninja/Repositories/InvoiceRepository.php b/app/Ninja/Repositories/InvoiceRepository.php
index 912310c766..0e9f9dadf4 100644
--- a/app/Ninja/Repositories/InvoiceRepository.php
+++ b/app/Ninja/Repositories/InvoiceRepository.php
@@ -8,9 +8,15 @@ use App\Models\Invitation;
use App\Models\Product;
use App\Models\Task;
use App\Services\PaymentService;
+use App\Ninja\Repositories\BaseRepository;
-class InvoiceRepository
+class InvoiceRepository extends BaseRepository
{
+ public function getClassName()
+ {
+ return 'App\Models\Invoice';
+ }
+
public function __construct(PaymentService $paymentService)
{
$this->paymentService = $paymentService;
@@ -214,51 +220,24 @@ class InvoiceRepository
}
return "$label
";
}
-
- public function getErrors($input)
- {
- $contact = (array) $input->client->contacts[0];
- $rules = [
- 'email' => 'email|required_without:first_name',
- 'first_name' => 'required_without:email',
- ];
- $validator = \Validator::make($contact, $rules);
-
- if ($validator->fails()) {
- return $validator;
- }
-
- $invoice = (array) $input;
- $invoiceId = isset($invoice['public_id']) && $invoice['public_id'] ? Invoice::getPrivateId($invoice['public_id']) : null;
- $rules = [
- 'invoice_number' => 'required|unique:invoices,invoice_number,'.$invoiceId.',id,account_id,'.\Auth::user()->account_id,
- 'discount' => 'positive',
- ];
-
- if ($invoice['is_recurring'] && $invoice['start_date'] && $invoice['end_date']) {
- $rules['end_date'] = 'after:'.$invoice['start_date'];
- }
-
- $validator = \Validator::make($invoice, $rules);
-
- if ($validator->fails()) {
- return $validator;
- }
-
- return false;
- }
-
- public function save($publicId, $data, $entityType)
+
+ public function save($data)
{
$account = \Auth::user()->account;
+ $publicId = isset($data['public_id']) ? $data['public_id'] : false;
+
+ $isNew = !$publicId || $publicId == '-1';
- if ($publicId) {
- $invoice = Invoice::scope($publicId)->firstOrFail();
- } else {
- if ($data['is_recurring']) {
+ if ($isNew) {
+ $entityType = ENTITY_INVOICE;
+ if (isset($data['is_recurring']) && $data['is_recurring']) {
$entityType = ENTITY_RECURRING_INVOICE;
+ } elseif (isset($data['is_quote']) && $data['is_quote']) {
+ $entityType = ENTITY_QUOTE;
}
$invoice = $account->createInvoice($entityType, $data['client_id']);
+ } else {
+ $invoice = Invoice::scope($publicId)->firstOrFail();
}
if ((isset($data['set_default_terms']) && $data['set_default_terms'])
@@ -280,7 +259,7 @@ class InvoiceRepository
$invoice->is_amount_discount = $data['is_amount_discount'] ? true : false;
$invoice->partial = round(Utils::parseFloat($data['partial']), 2);
$invoice->invoice_date = isset($data['invoice_date_sql']) ? $data['invoice_date_sql'] : Utils::toSqlDate($data['invoice_date']);
- $invoice->has_tasks = isset($data['has_tasks']) ? $data['has_tasks'] : false;
+ $invoice->has_tasks = isset($data['has_tasks']) ? ($data['has_tasks'] ? true : false) : false;
if ($invoice->is_recurring) {
if ($invoice->start_date && $invoice->start_date != Utils::toSqlDate($data['start_date'])) {
@@ -362,12 +341,20 @@ class InvoiceRepository
$total *= (100 - $invoice->discount) / 100;
}
}
-
- $invoice->custom_value1 = round($data['custom_value1'], 2);
- $invoice->custom_value2 = round($data['custom_value2'], 2);
- $invoice->custom_taxes1 = $data['custom_taxes1'] ? true : false;
- $invoice->custom_taxes2 = $data['custom_taxes2'] ? true : false;
-
+
+ if (isset($data['custom_value1'])) {
+ $invoice->custom_value1 = round($data['custom_value1'], 2);
+ if ($isNew) {
+ $invoice->custom_taxes1 = $account->custom_invoice_taxes1 ?: false;
+ }
+ }
+ if (isset($data['custom_value2'])) {
+ $invoice->custom_value2 = round($data['custom_value2'], 2);
+ if ($isNew) {
+ $invoice->custom_taxes2 = $account->custom_invoice_taxes2 ?: false;
+ }
+ }
+
if (isset($data['custom_text_value1'])) {
$invoice->custom_text_value1 = trim($data['custom_text_value1']);
}
@@ -543,31 +530,10 @@ class InvoiceRepository
return $clone;
}
- public function bulk($ids, $action, $statusId = false)
+ public function mark($invoice, $statusId)
{
- if (!$ids) {
- return 0;
- }
-
- $invoices = Invoice::withTrashed()->scope($ids)->get();
-
- foreach ($invoices as $invoice) {
- if ($action == 'mark') {
- $invoice->invoice_status_id = $statusId;
- $invoice->save();
- } elseif ($action == 'restore') {
- $invoice->restore();
- } else {
- if ($action == 'delete') {
- $invoice->is_deleted = true;
- $invoice->save();
- }
-
- $invoice->delete();
- }
- }
-
- return count($invoices);
+ $invoice->invoice_status_id = $statusId;
+ $invoice->save();
}
public function findInvoiceByInvitation($invitationKey)
@@ -637,10 +603,10 @@ class InvoiceRepository
$invoice->tax_name = $recurInvoice->tax_name;
$invoice->tax_rate = $recurInvoice->tax_rate;
$invoice->invoice_design_id = $recurInvoice->invoice_design_id;
- $invoice->custom_value1 = $recurInvoice->custom_value1;
- $invoice->custom_value2 = $recurInvoice->custom_value2;
- $invoice->custom_taxes1 = $recurInvoice->custom_taxes1;
- $invoice->custom_taxes2 = $recurInvoice->custom_taxes2;
+ $invoice->custom_value1 = $recurInvoice->custom_value1 ?: 0;
+ $invoice->custom_value2 = $recurInvoice->custom_value2 ?: 0;
+ $invoice->custom_taxes1 = $recurInvoice->custom_taxes1 ?: 0;
+ $invoice->custom_taxes2 = $recurInvoice->custom_taxes2 ?: 0;
$invoice->custom_text_value1 = $recurInvoice->custom_text_value1;
$invoice->custom_text_value2 = $recurInvoice->custom_text_value2;
$invoice->is_amount_discount = $recurInvoice->is_amount_discount;
diff --git a/app/Ninja/Repositories/PaymentRepository.php b/app/Ninja/Repositories/PaymentRepository.php
index c8f69325c8..67c6d9fe6f 100644
--- a/app/Ninja/Repositories/PaymentRepository.php
+++ b/app/Ninja/Repositories/PaymentRepository.php
@@ -1,13 +1,19 @@
'required',
- 'invoice' => 'required',
- 'amount' => 'required',
- );
-
- if ($input['payment_type_id'] == PAYMENT_TYPE_CREDIT) {
- $rules['payment_type_id'] = 'has_credit:'.$input['client'].','.$input['amount'];
- }
-
- if (isset($input['invoice']) && $input['invoice']) {
- $invoice = Invoice::scope($input['invoice'])->firstOrFail();
- $rules['amount'] .= "|less_than:{$invoice->balance}";
- }
-
- $validator = \Validator::make($input, $rules);
-
- if ($validator->fails()) {
- return $validator;
- }
-
- return false;
- }
-
- public function save($publicId = null, $input)
+ public function save($input)
{
+ $publicId = isset($input['public_id']) ? $input['public_id'] : false;
+
if ($publicId) {
$payment = Payment::scope($publicId)->firstOrFail();
} else {
@@ -145,28 +127,4 @@ class PaymentRepository
return $payment;
}
-
- public function bulk($ids, $action)
- {
- if (!$ids) {
- return 0;
- }
-
- $payments = Payment::withTrashed()->scope($ids)->get();
-
- foreach ($payments as $payment) {
- if ($action == 'restore') {
- $payment->restore();
- } else {
- if ($action == 'delete') {
- $payment->is_deleted = true;
- $payment->save();
- }
-
- $payment->delete();
- }
- }
-
- return count($payments);
- }
}
diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php
index 07e5f03134..efb642bfed 100644
--- a/app/Providers/AppServiceProvider.php
+++ b/app/Providers/AppServiceProvider.php
@@ -148,6 +148,19 @@ class AppServiceProvider extends ServiceProvider {
Validator::extend('has_counter', function($attribute, $value, $parameters) {
return !$value || strstr($value, '{$counter}');
});
+
+ Validator::extend('valid_contacts', function($attribute, $value, $parameters) {
+ foreach ($value as $contact) {
+ $validator = Validator::make($contact, [
+ 'email' => 'email|required_without:first_name',
+ 'first_name' => 'required_without:email',
+ ]);
+ if ($validator->fails()) {
+ return false;
+ }
+ }
+ return true;
+ });
}
/**
diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php
index 739c958686..3b7e800773 100644
--- a/app/Providers/EventServiceProvider.php
+++ b/app/Providers/EventServiceProvider.php
@@ -11,6 +11,123 @@ class EventServiceProvider extends ServiceProvider {
* @var array
*/
protected $listen = [
+
+ // Clients
+ 'App\Events\ClientWasCreated' => [
+ 'App\Listeners\ActivityListener@createdClient',
+ 'App\Listeners\SubscriptionListener@createdClient',
+ ],
+ 'App\Events\ClientWasArchived' => [
+ 'App\Listeners\ActivityListener@archivedClient',
+ ],
+ 'App\Events\ClientWasDeleted' => [
+ 'App\Listeners\ActivityListener@deletedClient',
+ ],
+ 'App\Events\ClientWasRestored' => [
+ 'App\Listeners\ActivityListener@restoredClient',
+ ],
+
+ // Invoices
+ 'App\Events\InvoiceWasCreated' => [
+ 'App\Listeners\ActivityListener@createdInvoice',
+ 'App\Listeners\SubscriptionListener@createdInvoice',
+ ],
+ 'App\Events\InvoiceWasUpdated' => [
+ 'App\Listeners\ActivityListener@updatedInvoice',
+ 'App\Listeners\InvoiceListener@updatedInvoice',
+ ],
+ 'App\Events\InvoiceWasArchived' => [
+ 'App\Listeners\ActivityListener@archivedInvoice',
+ ],
+ 'App\Events\InvoiceWasDeleted' => [
+ 'App\Listeners\ActivityListener@deletedInvoice',
+ 'App\Listeners\TaskListener@deletedInvoice',
+ ],
+ 'App\Events\InvoiceWasRestored' => [
+ 'App\Listeners\ActivityListener@restoredInvoice',
+ ],
+ 'App\Events\InvoiceWasEmailed' => [
+ 'App\Listeners\NotificationListener@emailedInvoice',
+ 'App\Listeners\InvoiceListener@emailedInvoice',
+ ],
+ 'App\Events\InvoiceInvitationWasEmailed' => [
+ 'App\Listeners\ActivityListener@emailedInvoice',
+ ],
+ 'App\Events\InvoiceInvitationWasViewed' => [
+ 'App\Listeners\ActivityListener@viewedInvoice',
+ 'App\Listeners\NotificationListener@viewedInvoice',
+ 'App\Listeners\InvoiceListener@viewedInvoice',
+ ],
+
+ // Quotes
+ 'App\Events\QuoteWasCreated' => [
+ 'App\Listeners\ActivityListener@createdQuote',
+ 'App\Listeners\SubscriptionListener@createdQuote',
+ ],
+ 'App\Events\QuoteWasUpdated' => [
+ 'App\Listeners\ActivityListener@updatedQuote',
+ ],
+ 'App\Events\QuoteWasArchived' => [
+ 'App\Listeners\ActivityListener@archivedQuote',
+ ],
+ 'App\Events\QuoteWasDeleted' => [
+ 'App\Listeners\ActivityListener@deletedQuote',
+ ],
+ 'App\Events\QuoteWasRestored' => [
+ 'App\Listeners\ActivityListener@restoredQuote',
+ ],
+ 'App\Events\QuoteWasEmailed' => [
+ 'App\Listeners\QuoteListener@emailedQuote',
+ 'App\Listeners\NotificationListener@emailedQuote',
+ ],
+ 'App\Events\QuoteInvitationWasEmailed' => [
+ 'App\Listeners\ActivityListener@emailedQuote',
+ ],
+ 'App\Events\QuoteInvitationWasViewed' => [
+ 'App\Listeners\ActivityListener@viewedQuote',
+ 'App\Listeners\NotificationListener@viewedQuote',
+ 'App\Listeners\QuoteListener@viewedQuote',
+ ],
+ 'App\Events\QuoteInvitationWasApproved' => [
+ 'App\Listeners\ActivityListener@approvedQuote',
+ 'App\Listeners\NotificationListener@approvedQuote',
+ ],
+
+ // Payments
+ 'App\Events\PaymentWasCreated' => [
+ 'App\Listeners\ActivityListener@createdPayment',
+ 'App\Listeners\SubscriptionListener@createdPayment',
+ 'App\Listeners\InvoiceListener@createdPayment',
+ 'App\Listeners\NotificationListener@createdPayment',
+ ],
+ 'App\Events\PaymentWasArchived' => [
+ 'App\Listeners\ActivityListener@archivedPayment',
+ ],
+ 'App\Events\PaymentWasDeleted' => [
+ 'App\Listeners\ActivityListener@deletedPayment',
+ 'App\Listeners\InvoiceListener@deletedPayment',
+ 'App\Listeners\CreditListener@deletedPayment',
+ ],
+ 'App\Events\PaymentWasRestored' => [
+ 'App\Listeners\ActivityListener@restoredPayment',
+ ],
+
+ // Credits
+ 'App\Events\CreditWasCreated' => [
+ 'App\Listeners\ActivityListener@createdCredit',
+ 'App\Listeners\SubscriptionListener@createdCredit',
+ ],
+ 'App\Events\CreditWasArchived' => [
+ 'App\Listeners\ActivityListener@archivedCredit',
+ ],
+ 'App\Events\CreditWasDeleted' => [
+ 'App\Listeners\ActivityListener@deletedCredit',
+ ],
+ 'App\Events\CreditWasRestored' => [
+ 'App\Listeners\ActivityListener@restoredCredit',
+ ],
+
+ // User events
'App\Events\UserSignedUp' => [
'App\Listeners\HandleUserSignedUp',
],
@@ -20,18 +137,7 @@ class EventServiceProvider extends ServiceProvider {
'App\Events\UserSettingsChanged' => [
'App\Listeners\HandleUserSettingsChanged',
],
- 'App\Events\InvoiceSent' => [
- 'App\Listeners\HandleInvoiceSent',
- ],
- 'App\Events\InvoiceViewed' => [
- 'App\Listeners\HandleInvoiceViewed',
- ],
- 'App\Events\InvoicePaid' => [
- 'App\Listeners\HandleInvoicePaid',
- ],
- 'App\Events\QuoteApproved' => [
- 'App\Listeners\HandleQuoteApproved',
- ],
+
];
/**
diff --git a/app/Services/BaseService.php b/app/Services/BaseService.php
new file mode 100644
index 0000000000..affb8a235c
--- /dev/null
+++ b/app/Services/BaseService.php
@@ -0,0 +1,28 @@
+getRepo()->findByPublicIdsWithTrashed($ids);
+
+ foreach ($entities as $entity) {
+ $this->getRepo()->$action($entity, $param);
+ }
+
+ return count($entities);
+ }
+}
diff --git a/app/Services/ClientService.php b/app/Services/ClientService.php
new file mode 100644
index 0000000000..fea373d7cb
--- /dev/null
+++ b/app/Services/ClientService.php
@@ -0,0 +1,25 @@
+clientRepo = $clientRepo;
+ }
+
+ protected function getRepo()
+ {
+ return $this->clientRepo;
+ }
+
+ public function save($data)
+ {
+ return $this->clientRepo->save($data);
+ }
+}
\ No newline at end of file
diff --git a/app/Services/CreditService.php b/app/Services/CreditService.php
new file mode 100644
index 0000000000..d1e23bfb4f
--- /dev/null
+++ b/app/Services/CreditService.php
@@ -0,0 +1,25 @@
+creditRepo = $creditRepo;
+ }
+
+ protected function getRepo()
+ {
+ return $this->creditRepo;
+ }
+
+ public function save($data)
+ {
+ return $this->creditRepo->save($data);
+ }
+}
\ No newline at end of file
diff --git a/app/Services/InvoiceService.php b/app/Services/InvoiceService.php
new file mode 100644
index 0000000000..eaa60d999a
--- /dev/null
+++ b/app/Services/InvoiceService.php
@@ -0,0 +1,81 @@
+clientRepo = $clientRepo;
+ $this->invoiceRepo = $invoiceRepo;
+ }
+
+ protected function getRepo()
+ {
+ return $this->invoiceRepo;
+ }
+
+ public function save($data)
+ {
+ if (isset($data['client'])) {
+ $client = $this->clientRepo->save($data['client']);
+ $data['client_id'] = $client->id;
+ }
+
+ $invoice = $this->invoiceRepo->save($data);
+
+ $client = $invoice->client;
+ $client->load('contacts');
+ $sendInvoiceIds = [];
+
+ foreach ($client->contacts as $contact) {
+ if ($contact->send_invoice || count($client->contacts) == 1) {
+ $sendInvoiceIds[] = $contact->id;
+ }
+ }
+
+ foreach ($client->contacts as $contact) {
+ $invitation = Invitation::scope()->whereContactId($contact->id)->whereInvoiceId($invoice->id)->first();
+
+ if (in_array($contact->id, $sendInvoiceIds) && !$invitation) {
+ $invitation = Invitation::createNew();
+ $invitation->invoice_id = $invoice->id;
+ $invitation->contact_id = $contact->id;
+ $invitation->invitation_key = str_random(RANDOM_KEY_LENGTH);
+ $invitation->save();
+ } elseif (!in_array($contact->id, $sendInvoiceIds) && $invitation) {
+ $invitation->delete();
+ }
+ }
+
+ return $invoice;
+ }
+
+ public function approveQuote($quote, $invitation = null)
+ {
+ if (!$quote->is_quote || $quote->quote_invoice_id) {
+ return null;
+ }
+
+ $invoice = $this->invoiceRepo->cloneInvoice($quote, $quote->id);
+
+ if (!$invitation) {
+ return $invoice;
+ }
+
+ event(new QuoteInvitationWasApproved($invoice, $invitation));
+
+ foreach ($invoice->invitations as $invoiceInvitation) {
+ if ($invitation->contact_id == $invoiceInvitation->contact_id) {
+ return $invoiceInvitation->invitation_key;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/Services/PaymentService.php b/app/Services/PaymentService.php
index b8ad042374..e9d99fc7ee 100644
--- a/app/Services/PaymentService.php
+++ b/app/Services/PaymentService.php
@@ -10,18 +10,26 @@ use App\Models\Payment;
use App\Models\Account;
use App\Models\Country;
use App\Models\AccountGatewayToken;
+use App\Ninja\Repositories\PaymentRepository;
use App\Ninja\Repositories\AccountRepository;
-use App\Events\InvoicePaid;
-
-class PaymentService {
+use App\Services\BaseService;
+use App\Events\PaymentWasCreated;
+class PaymentService extends BaseService
+{
public $lastError;
- public function __construct(AccountRepository $accountRepo)
+ public function __construct(PaymentRepository $paymentRepo, AccountRepository $accountRepo)
{
+ $this->paymentRepo = $paymentRepo;
$this->accountRepo = $accountRepo;
}
+ protected function getRepo()
+ {
+ return $this->paymentRepo;
+ }
+
public function createGateway($accountGateway)
{
$gateway = Omnipay::create($accountGateway->gateway->provider);
@@ -208,8 +216,6 @@ class PaymentService {
$payment->save();
- Event::fire(new InvoicePaid($payment));
-
return $payment;
}
diff --git a/database/migrations/2015_10_27_180214_add_is_system_to_activities.php b/database/migrations/2015_10_27_180214_add_is_system_to_activities.php
new file mode 100644
index 0000000000..615ea88b49
--- /dev/null
+++ b/database/migrations/2015_10_27_180214_add_is_system_to_activities.php
@@ -0,0 +1,51 @@
+boolean('is_system')->default(0);
+ });
+
+ $activities = Activity::where('message', 'like', '%System %')->get();
+ foreach ($activities as $activity) {
+ $activity->is_system = true;
+ $activity->save();
+ }
+
+ Schema::table('activities', function($table)
+ {
+ $table->dropColumn('message');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table('activities', function($table)
+ {
+ $table->dropColumn('is_system');
+ });
+
+ Schema::table('activities', function($table)
+ {
+ $table->text('message')->nullable();
+ });
+ }
+
+}
diff --git a/resources/lang/da/texts.php b/resources/lang/da/texts.php
index 71258403c6..85ae4b1df9 100644
--- a/resources/lang/da/texts.php
+++ b/resources/lang/da/texts.php
@@ -826,5 +826,62 @@
'no_longer_running' => 'This invoice is not scheduled to run',
'general_settings' => 'General Settings',
'customize' => 'Customize',
+ 'oneclick_login_help' => 'Connect an account to login without a password',
+ 'referral_code_help' => 'Earn money by sharing our app online',
+
+ 'enable_with_stripe' => 'Enable | Requires Stripe',
+ 'tax_settings' => 'Tax Settings',
+ 'create_tax_rate' => 'Add Tax Rate',
+ 'updated_tax_rate' => 'Successfully updated tax rate',
+ 'created_tax_rate' => 'Successfully created tax rate',
+ 'edit_tax_rate' => 'Edit tax rate',
+ 'archive_tax_rate' => 'Archive tax rate',
+ 'archived_tax_rate' => 'Successfully archived the tax rate',
+ 'default_tax_rate_id' => 'Default Tax Rate',
+ 'tax_rate' => 'Tax Rate',
+ 'recurring_hour' => 'Recurring Hour',
+ 'pattern' => 'Pattern',
+ 'pattern_help_title' => 'Pattern Help',
+ 'pattern_help_1' => 'Create custom invoice and quote numbers by specifying a pattern',
+ 'pattern_help_2' => 'Available variables:',
+ 'pattern_help_3' => 'For example, :example would be converted to :value',
+ 'see_options' => 'See options',
+ 'invoice_counter' => 'Invoice Counter',
+ 'quote_counter' => 'Quote Counter',
+ 'type' => 'Type',
+
+ 'activity_1' => ':user created client :client',
+ 'activity_2' => ':user archived client :client',
+ 'activity_3' => ':user deleted client :client',
+ 'activity_4' => ':user created invoice :invoice',
+ 'activity_5' => ':user updated invoice :invoice',
+ 'activity_6' => ':user emailed invoice :invoice to :contact',
+ 'activity_7' => ':contact viewed invoice :invoice',
+ 'activity_8' => ':user archived invoice :invoice',
+ 'activity_9' => ':user deleted invoice :invoice',
+ 'activity_10' => ':contact entered payment :payment for :invoice',
+ 'activity_11' => ':user updated payment :payment',
+ 'activity_12' => ':user archived payment :payment',
+ 'activity_13' => ':user deleted payment :payment',
+ 'activity_14' => ':user entered :credit credit',
+ 'activity_15' => ':user updated :credit credit',
+ 'activity_16' => ':user archived :credit credit',
+ 'activity_17' => ':user deleted :credit credit',
+ 'activity_18' => ':user created quote :quote',
+ 'activity_19' => ':user updated quote :quote',
+ 'activity_20' => ':user emailed quote :quote to :contact',
+ 'activity_21' => ':contact viewed quote :quote',
+ 'activity_22' => ':user archived quote :quote',
+ 'activity_23' => ':user deleted quote :quote',
+ 'activity_24' => ':user restored quote :quote',
+ 'activity_25' => ':user restored invoice :invoice',
+ 'activity_26' => ':user restored client :client',
+ 'activity_27' => ':user restored payment :payment',
+ 'activity_28' => ':user restored :credit credit',
+ 'activity_29' => ':contact approved quote :quote',
+
+ 'payment' => 'Payment',
+ 'system' => 'System',
+
);
diff --git a/resources/lang/de/texts.php b/resources/lang/de/texts.php
index bd0117be22..4a7945d9a7 100644
--- a/resources/lang/de/texts.php
+++ b/resources/lang/de/texts.php
@@ -841,4 +841,48 @@ return array(
'default_tax_rate_id' => 'Standard Steuersatz',
'tax_rate' => 'Steuersatz',
+ 'recurring_hour' => 'Recurring Hour',
+ 'pattern' => 'Pattern',
+ 'pattern_help_title' => 'Pattern Help',
+ 'pattern_help_1' => 'Create custom invoice and quote numbers by specifying a pattern',
+ 'pattern_help_2' => 'Available variables:',
+ 'pattern_help_3' => 'For example, :example would be converted to :value',
+ 'see_options' => 'See options',
+ 'invoice_counter' => 'Invoice Counter',
+ 'quote_counter' => 'Quote Counter',
+ 'type' => 'Type',
+
+ 'activity_1' => ':user created client :client',
+ 'activity_2' => ':user archived client :client',
+ 'activity_3' => ':user deleted client :client',
+ 'activity_4' => ':user created invoice :invoice',
+ 'activity_5' => ':user updated invoice :invoice',
+ 'activity_6' => ':user emailed invoice :invoice to :contact',
+ 'activity_7' => ':contact viewed invoice :invoice',
+ 'activity_8' => ':user archived invoice :invoice',
+ 'activity_9' => ':user deleted invoice :invoice',
+ 'activity_10' => ':contact entered payment :payment for :invoice',
+ 'activity_11' => ':user updated payment :payment',
+ 'activity_12' => ':user archived payment :payment',
+ 'activity_13' => ':user deleted payment :payment',
+ 'activity_14' => ':user entered :credit credit',
+ 'activity_15' => ':user updated :credit credit',
+ 'activity_16' => ':user archived :credit credit',
+ 'activity_17' => ':user deleted :credit credit',
+ 'activity_18' => ':user created quote :quote',
+ 'activity_19' => ':user updated quote :quote',
+ 'activity_20' => ':user emailed quote :quote to :contact',
+ 'activity_21' => ':contact viewed quote :quote',
+ 'activity_22' => ':user archived quote :quote',
+ 'activity_23' => ':user deleted quote :quote',
+ 'activity_24' => ':user restored quote :quote',
+ 'activity_25' => ':user restored invoice :invoice',
+ 'activity_26' => ':user restored client :client',
+ 'activity_27' => ':user restored payment :payment',
+ 'activity_28' => ':user restored :credit credit',
+ 'activity_29' => ':contact approved quote :quote',
+
+ 'payment' => 'Payment',
+ 'system' => 'System',
+
);
diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php
index 50bb943c1c..1468594b8b 100644
--- a/resources/lang/en/texts.php
+++ b/resources/lang/en/texts.php
@@ -852,4 +852,38 @@ return array(
'quote_counter' => 'Quote Counter',
'type' => 'Type',
+ 'activity_1' => ':user created client :client',
+ 'activity_2' => ':user archived client :client',
+ 'activity_3' => ':user deleted client :client',
+ 'activity_4' => ':user created invoice :invoice',
+ 'activity_5' => ':user updated invoice :invoice',
+ 'activity_6' => ':user emailed invoice :invoice to :contact',
+ 'activity_7' => ':contact viewed invoice :invoice',
+ 'activity_8' => ':user archived invoice :invoice',
+ 'activity_9' => ':user deleted invoice :invoice',
+ 'activity_10' => ':contact entered payment :payment for :invoice',
+ 'activity_11' => ':user updated payment :payment',
+ 'activity_12' => ':user archived payment :payment',
+ 'activity_13' => ':user deleted payment :payment',
+ 'activity_14' => ':user entered :credit credit',
+ 'activity_15' => ':user updated :credit credit',
+ 'activity_16' => ':user archived :credit credit',
+ 'activity_17' => ':user deleted :credit credit',
+ 'activity_18' => ':user created quote :quote',
+ 'activity_19' => ':user updated quote :quote',
+ 'activity_20' => ':user emailed quote :quote to :contact',
+ 'activity_21' => ':contact viewed quote :quote',
+ 'activity_22' => ':user archived quote :quote',
+ 'activity_23' => ':user deleted quote :quote',
+ 'activity_24' => ':user restored quote :quote',
+ 'activity_25' => ':user restored invoice :invoice',
+ 'activity_26' => ':user restored client :client',
+ 'activity_27' => ':user restored payment :payment',
+ 'activity_28' => ':user restored :credit credit',
+ 'activity_29' => ':contact approved quote :quote',
+
+ 'payment' => 'Payment',
+ 'system' => 'System',
+
+
);
diff --git a/resources/lang/en/validation.php b/resources/lang/en/validation.php
index bd46a6106b..3027ef372f 100644
--- a/resources/lang/en/validation.php
+++ b/resources/lang/en/validation.php
@@ -74,6 +74,7 @@ return array(
"notmasked" => "The values are masked",
"less_than" => 'The :attribute must be less than :value',
"has_counter" => 'The value must contain {$counter}',
+ "valid_contacts" => 'All of the contacts must have either an email or name',
/*
|--------------------------------------------------------------------------
diff --git a/resources/lang/es/texts.php b/resources/lang/es/texts.php
index 4f350af3fa..eaff3ef5a3 100644
--- a/resources/lang/es/texts.php
+++ b/resources/lang/es/texts.php
@@ -804,6 +804,62 @@ return array(
'no_longer_running' => 'This invoice is not scheduled to run',
'general_settings' => 'General Settings',
'customize' => 'Customize',
+ 'oneclick_login_help' => 'Connect an account to login without a password',
+ 'referral_code_help' => 'Earn money by sharing our app online',
+
+ 'enable_with_stripe' => 'Enable | Requires Stripe',
+ 'tax_settings' => 'Tax Settings',
+ 'create_tax_rate' => 'Add Tax Rate',
+ 'updated_tax_rate' => 'Successfully updated tax rate',
+ 'created_tax_rate' => 'Successfully created tax rate',
+ 'edit_tax_rate' => 'Edit tax rate',
+ 'archive_tax_rate' => 'Archive tax rate',
+ 'archived_tax_rate' => 'Successfully archived the tax rate',
+ 'default_tax_rate_id' => 'Default Tax Rate',
+ 'tax_rate' => 'Tax Rate',
+ 'recurring_hour' => 'Recurring Hour',
+ 'pattern' => 'Pattern',
+ 'pattern_help_title' => 'Pattern Help',
+ 'pattern_help_1' => 'Create custom invoice and quote numbers by specifying a pattern',
+ 'pattern_help_2' => 'Available variables:',
+ 'pattern_help_3' => 'For example, :example would be converted to :value',
+ 'see_options' => 'See options',
+ 'invoice_counter' => 'Invoice Counter',
+ 'quote_counter' => 'Quote Counter',
+ 'type' => 'Type',
+
+ 'activity_1' => ':user created client :client',
+ 'activity_2' => ':user archived client :client',
+ 'activity_3' => ':user deleted client :client',
+ 'activity_4' => ':user created invoice :invoice',
+ 'activity_5' => ':user updated invoice :invoice',
+ 'activity_6' => ':user emailed invoice :invoice to :contact',
+ 'activity_7' => ':contact viewed invoice :invoice',
+ 'activity_8' => ':user archived invoice :invoice',
+ 'activity_9' => ':user deleted invoice :invoice',
+ 'activity_10' => ':contact entered payment :payment for :invoice',
+ 'activity_11' => ':user updated payment :payment',
+ 'activity_12' => ':user archived payment :payment',
+ 'activity_13' => ':user deleted payment :payment',
+ 'activity_14' => ':user entered :credit credit',
+ 'activity_15' => ':user updated :credit credit',
+ 'activity_16' => ':user archived :credit credit',
+ 'activity_17' => ':user deleted :credit credit',
+ 'activity_18' => ':user created quote :quote',
+ 'activity_19' => ':user updated quote :quote',
+ 'activity_20' => ':user emailed quote :quote to :contact',
+ 'activity_21' => ':contact viewed quote :quote',
+ 'activity_22' => ':user archived quote :quote',
+ 'activity_23' => ':user deleted quote :quote',
+ 'activity_24' => ':user restored quote :quote',
+ 'activity_25' => ':user restored invoice :invoice',
+ 'activity_26' => ':user restored client :client',
+ 'activity_27' => ':user restored payment :payment',
+ 'activity_28' => ':user restored :credit credit',
+ 'activity_29' => ':contact approved quote :quote',
+
+ 'payment' => 'Payment',
+ 'system' => 'System',
);
diff --git a/resources/lang/es_ES/texts.php b/resources/lang/es_ES/texts.php
index 95ef2b5ca6..7c59cdc829 100644
--- a/resources/lang/es_ES/texts.php
+++ b/resources/lang/es_ES/texts.php
@@ -825,5 +825,61 @@ return array(
'no_longer_running' => 'This invoice is not scheduled to run',
'general_settings' => 'General Settings',
'customize' => 'Customize',
+ 'oneclick_login_help' => 'Connect an account to login without a password',
+ 'referral_code_help' => 'Earn money by sharing our app online',
+
+ 'enable_with_stripe' => 'Enable | Requires Stripe',
+ 'tax_settings' => 'Tax Settings',
+ 'create_tax_rate' => 'Add Tax Rate',
+ 'updated_tax_rate' => 'Successfully updated tax rate',
+ 'created_tax_rate' => 'Successfully created tax rate',
+ 'edit_tax_rate' => 'Edit tax rate',
+ 'archive_tax_rate' => 'Archive tax rate',
+ 'archived_tax_rate' => 'Successfully archived the tax rate',
+ 'default_tax_rate_id' => 'Default Tax Rate',
+ 'tax_rate' => 'Tax Rate',
+ 'recurring_hour' => 'Recurring Hour',
+ 'pattern' => 'Pattern',
+ 'pattern_help_title' => 'Pattern Help',
+ 'pattern_help_1' => 'Create custom invoice and quote numbers by specifying a pattern',
+ 'pattern_help_2' => 'Available variables:',
+ 'pattern_help_3' => 'For example, :example would be converted to :value',
+ 'see_options' => 'See options',
+ 'invoice_counter' => 'Invoice Counter',
+ 'quote_counter' => 'Quote Counter',
+ 'type' => 'Type',
+
+ 'activity_1' => ':user created client :client',
+ 'activity_2' => ':user archived client :client',
+ 'activity_3' => ':user deleted client :client',
+ 'activity_4' => ':user created invoice :invoice',
+ 'activity_5' => ':user updated invoice :invoice',
+ 'activity_6' => ':user emailed invoice :invoice to :contact',
+ 'activity_7' => ':contact viewed invoice :invoice',
+ 'activity_8' => ':user archived invoice :invoice',
+ 'activity_9' => ':user deleted invoice :invoice',
+ 'activity_10' => ':contact entered payment :payment for :invoice',
+ 'activity_11' => ':user updated payment :payment',
+ 'activity_12' => ':user archived payment :payment',
+ 'activity_13' => ':user deleted payment :payment',
+ 'activity_14' => ':user entered :credit credit',
+ 'activity_15' => ':user updated :credit credit',
+ 'activity_16' => ':user archived :credit credit',
+ 'activity_17' => ':user deleted :credit credit',
+ 'activity_18' => ':user created quote :quote',
+ 'activity_19' => ':user updated quote :quote',
+ 'activity_20' => ':user emailed quote :quote to :contact',
+ 'activity_21' => ':contact viewed quote :quote',
+ 'activity_22' => ':user archived quote :quote',
+ 'activity_23' => ':user deleted quote :quote',
+ 'activity_24' => ':user restored quote :quote',
+ 'activity_25' => ':user restored invoice :invoice',
+ 'activity_26' => ':user restored client :client',
+ 'activity_27' => ':user restored payment :payment',
+ 'activity_28' => ':user restored :credit credit',
+ 'activity_29' => ':contact approved quote :quote',
+
+ 'payment' => 'Payment',
+ 'system' => 'System',
);
diff --git a/resources/lang/fr/texts.php b/resources/lang/fr/texts.php
index e04f699fce..8651fb4755 100644
--- a/resources/lang/fr/texts.php
+++ b/resources/lang/fr/texts.php
@@ -552,7 +552,7 @@ return array(
'pay_with_paypal' => 'PayPal',
'pay_with_card' => 'Carte bancaire',
- 'change_password' => 'Changer de pot de passe',
+ 'change_password' => 'Changer le mot de passe',
'current_password' => 'Mot de passe actuel',
'new_password' => 'Nouveau mot de passe',
'confirm_password' => 'Confirmer le mot de passe',
@@ -819,5 +819,61 @@ return array(
'general_settings' => 'General Settings',
'customize' => 'Customize',
+ 'oneclick_login_help' => 'Connect an account to login without a password',
+ 'referral_code_help' => 'Earn money by sharing our app online',
+ 'enable_with_stripe' => 'Enable | Requires Stripe',
+ 'tax_settings' => 'Tax Settings',
+ 'create_tax_rate' => 'Add Tax Rate',
+ 'updated_tax_rate' => 'Successfully updated tax rate',
+ 'created_tax_rate' => 'Successfully created tax rate',
+ 'edit_tax_rate' => 'Edit tax rate',
+ 'archive_tax_rate' => 'Archive tax rate',
+ 'archived_tax_rate' => 'Successfully archived the tax rate',
+ 'default_tax_rate_id' => 'Default Tax Rate',
+ 'tax_rate' => 'Tax Rate',
+ 'recurring_hour' => 'Recurring Hour',
+ 'pattern' => 'Pattern',
+ 'pattern_help_title' => 'Pattern Help',
+ 'pattern_help_1' => 'Create custom invoice and quote numbers by specifying a pattern',
+ 'pattern_help_2' => 'Available variables:',
+ 'pattern_help_3' => 'For example, :example would be converted to :value',
+ 'see_options' => 'See options',
+ 'invoice_counter' => 'Invoice Counter',
+ 'quote_counter' => 'Quote Counter',
+ 'type' => 'Type',
+
+ 'activity_1' => ':user created client :client',
+ 'activity_2' => ':user archived client :client',
+ 'activity_3' => ':user deleted client :client',
+ 'activity_4' => ':user created invoice :invoice',
+ 'activity_5' => ':user updated invoice :invoice',
+ 'activity_6' => ':user emailed invoice :invoice to :contact',
+ 'activity_7' => ':contact viewed invoice :invoice',
+ 'activity_8' => ':user archived invoice :invoice',
+ 'activity_9' => ':user deleted invoice :invoice',
+ 'activity_10' => ':contact entered payment :payment for :invoice',
+ 'activity_11' => ':user updated payment :payment',
+ 'activity_12' => ':user archived payment :payment',
+ 'activity_13' => ':user deleted payment :payment',
+ 'activity_14' => ':user entered :credit credit',
+ 'activity_15' => ':user updated :credit credit',
+ 'activity_16' => ':user archived :credit credit',
+ 'activity_17' => ':user deleted :credit credit',
+ 'activity_18' => ':user created quote :quote',
+ 'activity_19' => ':user updated quote :quote',
+ 'activity_20' => ':user emailed quote :quote to :contact',
+ 'activity_21' => ':contact viewed quote :quote',
+ 'activity_22' => ':user archived quote :quote',
+ 'activity_23' => ':user deleted quote :quote',
+ 'activity_24' => ':user restored quote :quote',
+ 'activity_25' => ':user restored invoice :invoice',
+ 'activity_26' => ':user restored client :client',
+ 'activity_27' => ':user restored payment :payment',
+ 'activity_28' => ':user restored :credit credit',
+ 'activity_29' => ':contact approved quote :quote',
+
+ 'payment' => 'Payment',
+ 'system' => 'System',
+
);
diff --git a/resources/lang/fr_CA/texts.php b/resources/lang/fr_CA/texts.php
index 1b0e7d8228..50e4f43e28 100644
--- a/resources/lang/fr_CA/texts.php
+++ b/resources/lang/fr_CA/texts.php
@@ -819,6 +819,61 @@ return array(
'no_longer_running' => 'This invoice is not scheduled to run',
'general_settings' => 'General Settings',
'customize' => 'Customize',
+ 'oneclick_login_help' => 'Connect an account to login without a password',
+ 'referral_code_help' => 'Earn money by sharing our app online',
+ 'enable_with_stripe' => 'Enable | Requires Stripe',
+ 'tax_settings' => 'Tax Settings',
+ 'create_tax_rate' => 'Add Tax Rate',
+ 'updated_tax_rate' => 'Successfully updated tax rate',
+ 'created_tax_rate' => 'Successfully created tax rate',
+ 'edit_tax_rate' => 'Edit tax rate',
+ 'archive_tax_rate' => 'Archive tax rate',
+ 'archived_tax_rate' => 'Successfully archived the tax rate',
+ 'default_tax_rate_id' => 'Default Tax Rate',
+ 'tax_rate' => 'Tax Rate',
+ 'recurring_hour' => 'Recurring Hour',
+ 'pattern' => 'Pattern',
+ 'pattern_help_title' => 'Pattern Help',
+ 'pattern_help_1' => 'Create custom invoice and quote numbers by specifying a pattern',
+ 'pattern_help_2' => 'Available variables:',
+ 'pattern_help_3' => 'For example, :example would be converted to :value',
+ 'see_options' => 'See options',
+ 'invoice_counter' => 'Invoice Counter',
+ 'quote_counter' => 'Quote Counter',
+ 'type' => 'Type',
+
+ 'activity_1' => ':user created client :client',
+ 'activity_2' => ':user archived client :client',
+ 'activity_3' => ':user deleted client :client',
+ 'activity_4' => ':user created invoice :invoice',
+ 'activity_5' => ':user updated invoice :invoice',
+ 'activity_6' => ':user emailed invoice :invoice to :contact',
+ 'activity_7' => ':contact viewed invoice :invoice',
+ 'activity_8' => ':user archived invoice :invoice',
+ 'activity_9' => ':user deleted invoice :invoice',
+ 'activity_10' => ':contact entered payment :payment for :invoice',
+ 'activity_11' => ':user updated payment :payment',
+ 'activity_12' => ':user archived payment :payment',
+ 'activity_13' => ':user deleted payment :payment',
+ 'activity_14' => ':user entered :credit credit',
+ 'activity_15' => ':user updated :credit credit',
+ 'activity_16' => ':user archived :credit credit',
+ 'activity_17' => ':user deleted :credit credit',
+ 'activity_18' => ':user created quote :quote',
+ 'activity_19' => ':user updated quote :quote',
+ 'activity_20' => ':user emailed quote :quote to :contact',
+ 'activity_21' => ':contact viewed quote :quote',
+ 'activity_22' => ':user archived quote :quote',
+ 'activity_23' => ':user deleted quote :quote',
+ 'activity_24' => ':user restored quote :quote',
+ 'activity_25' => ':user restored invoice :invoice',
+ 'activity_26' => ':user restored client :client',
+ 'activity_27' => ':user restored payment :payment',
+ 'activity_28' => ':user restored :credit credit',
+ 'activity_29' => ':contact approved quote :quote',
+
+ 'payment' => 'Payment',
+ 'system' => 'System',
);
diff --git a/resources/lang/it/texts.php b/resources/lang/it/texts.php
index 916f78bc82..fece6b644e 100644
--- a/resources/lang/it/texts.php
+++ b/resources/lang/it/texts.php
@@ -821,5 +821,61 @@ return array(
'no_longer_running' => 'This invoice is not scheduled to run',
'general_settings' => 'General Settings',
'customize' => 'Customize',
+ 'oneclick_login_help' => 'Connect an account to login without a password',
+ 'referral_code_help' => 'Earn money by sharing our app online',
+
+ 'enable_with_stripe' => 'Enable | Requires Stripe',
+ 'tax_settings' => 'Tax Settings',
+ 'create_tax_rate' => 'Add Tax Rate',
+ 'updated_tax_rate' => 'Successfully updated tax rate',
+ 'created_tax_rate' => 'Successfully created tax rate',
+ 'edit_tax_rate' => 'Edit tax rate',
+ 'archive_tax_rate' => 'Archive tax rate',
+ 'archived_tax_rate' => 'Successfully archived the tax rate',
+ 'default_tax_rate_id' => 'Default Tax Rate',
+ 'tax_rate' => 'Tax Rate',
+ 'recurring_hour' => 'Recurring Hour',
+ 'pattern' => 'Pattern',
+ 'pattern_help_title' => 'Pattern Help',
+ 'pattern_help_1' => 'Create custom invoice and quote numbers by specifying a pattern',
+ 'pattern_help_2' => 'Available variables:',
+ 'pattern_help_3' => 'For example, :example would be converted to :value',
+ 'see_options' => 'See options',
+ 'invoice_counter' => 'Invoice Counter',
+ 'quote_counter' => 'Quote Counter',
+ 'type' => 'Type',
+
+ 'activity_1' => ':user created client :client',
+ 'activity_2' => ':user archived client :client',
+ 'activity_3' => ':user deleted client :client',
+ 'activity_4' => ':user created invoice :invoice',
+ 'activity_5' => ':user updated invoice :invoice',
+ 'activity_6' => ':user emailed invoice :invoice to :contact',
+ 'activity_7' => ':contact viewed invoice :invoice',
+ 'activity_8' => ':user archived invoice :invoice',
+ 'activity_9' => ':user deleted invoice :invoice',
+ 'activity_10' => ':contact entered payment :payment for :invoice',
+ 'activity_11' => ':user updated payment :payment',
+ 'activity_12' => ':user archived payment :payment',
+ 'activity_13' => ':user deleted payment :payment',
+ 'activity_14' => ':user entered :credit credit',
+ 'activity_15' => ':user updated :credit credit',
+ 'activity_16' => ':user archived :credit credit',
+ 'activity_17' => ':user deleted :credit credit',
+ 'activity_18' => ':user created quote :quote',
+ 'activity_19' => ':user updated quote :quote',
+ 'activity_20' => ':user emailed quote :quote to :contact',
+ 'activity_21' => ':contact viewed quote :quote',
+ 'activity_22' => ':user archived quote :quote',
+ 'activity_23' => ':user deleted quote :quote',
+ 'activity_24' => ':user restored quote :quote',
+ 'activity_25' => ':user restored invoice :invoice',
+ 'activity_26' => ':user restored client :client',
+ 'activity_27' => ':user restored payment :payment',
+ 'activity_28' => ':user restored :credit credit',
+ 'activity_29' => ':contact approved quote :quote',
+
+ 'payment' => 'Payment',
+ 'system' => 'System',
);
diff --git a/resources/lang/lt/texts.php b/resources/lang/lt/texts.php
index 2c20fc3643..9bd47ae4ad 100644
--- a/resources/lang/lt/texts.php
+++ b/resources/lang/lt/texts.php
@@ -828,6 +828,62 @@ return array(
'no_longer_running' => 'This invoice is not scheduled to run',
'general_settings' => 'General Settings',
'customize' => 'Customize',
+ 'oneclick_login_help' => 'Connect an account to login without a password',
+ 'referral_code_help' => 'Earn money by sharing our app online',
+
+ 'enable_with_stripe' => 'Enable | Requires Stripe',
+ 'tax_settings' => 'Tax Settings',
+ 'create_tax_rate' => 'Add Tax Rate',
+ 'updated_tax_rate' => 'Successfully updated tax rate',
+ 'created_tax_rate' => 'Successfully created tax rate',
+ 'edit_tax_rate' => 'Edit tax rate',
+ 'archive_tax_rate' => 'Archive tax rate',
+ 'archived_tax_rate' => 'Successfully archived the tax rate',
+ 'default_tax_rate_id' => 'Default Tax Rate',
+ 'tax_rate' => 'Tax Rate',
+ 'recurring_hour' => 'Recurring Hour',
+ 'pattern' => 'Pattern',
+ 'pattern_help_title' => 'Pattern Help',
+ 'pattern_help_1' => 'Create custom invoice and quote numbers by specifying a pattern',
+ 'pattern_help_2' => 'Available variables:',
+ 'pattern_help_3' => 'For example, :example would be converted to :value',
+ 'see_options' => 'See options',
+ 'invoice_counter' => 'Invoice Counter',
+ 'quote_counter' => 'Quote Counter',
+ 'type' => 'Type',
+
+ 'activity_1' => ':user created client :client',
+ 'activity_2' => ':user archived client :client',
+ 'activity_3' => ':user deleted client :client',
+ 'activity_4' => ':user created invoice :invoice',
+ 'activity_5' => ':user updated invoice :invoice',
+ 'activity_6' => ':user emailed invoice :invoice to :contact',
+ 'activity_7' => ':contact viewed invoice :invoice',
+ 'activity_8' => ':user archived invoice :invoice',
+ 'activity_9' => ':user deleted invoice :invoice',
+ 'activity_10' => ':contact entered payment :payment for :invoice',
+ 'activity_11' => ':user updated payment :payment',
+ 'activity_12' => ':user archived payment :payment',
+ 'activity_13' => ':user deleted payment :payment',
+ 'activity_14' => ':user entered :credit credit',
+ 'activity_15' => ':user updated :credit credit',
+ 'activity_16' => ':user archived :credit credit',
+ 'activity_17' => ':user deleted :credit credit',
+ 'activity_18' => ':user created quote :quote',
+ 'activity_19' => ':user updated quote :quote',
+ 'activity_20' => ':user emailed quote :quote to :contact',
+ 'activity_21' => ':contact viewed quote :quote',
+ 'activity_22' => ':user archived quote :quote',
+ 'activity_23' => ':user deleted quote :quote',
+ 'activity_24' => ':user restored quote :quote',
+ 'activity_25' => ':user restored invoice :invoice',
+ 'activity_26' => ':user restored client :client',
+ 'activity_27' => ':user restored payment :payment',
+ 'activity_28' => ':user restored :credit credit',
+ 'activity_29' => ':contact approved quote :quote',
+
+ 'payment' => 'Payment',
+ 'system' => 'System',
);
diff --git a/resources/lang/nb_NO/texts.php b/resources/lang/nb_NO/texts.php
index 36ad7c3aa8..16fd7c7bbb 100644
--- a/resources/lang/nb_NO/texts.php
+++ b/resources/lang/nb_NO/texts.php
@@ -826,5 +826,61 @@ return array(
'no_longer_running' => 'This invoice is not scheduled to run',
'general_settings' => 'General Settings',
'customize' => 'Customize',
+ 'oneclick_login_help' => 'Connect an account to login without a password',
+ 'referral_code_help' => 'Earn money by sharing our app online',
+
+ 'enable_with_stripe' => 'Enable | Requires Stripe',
+ 'tax_settings' => 'Tax Settings',
+ 'create_tax_rate' => 'Add Tax Rate',
+ 'updated_tax_rate' => 'Successfully updated tax rate',
+ 'created_tax_rate' => 'Successfully created tax rate',
+ 'edit_tax_rate' => 'Edit tax rate',
+ 'archive_tax_rate' => 'Archive tax rate',
+ 'archived_tax_rate' => 'Successfully archived the tax rate',
+ 'default_tax_rate_id' => 'Default Tax Rate',
+ 'tax_rate' => 'Tax Rate',
+ 'recurring_hour' => 'Recurring Hour',
+ 'pattern' => 'Pattern',
+ 'pattern_help_title' => 'Pattern Help',
+ 'pattern_help_1' => 'Create custom invoice and quote numbers by specifying a pattern',
+ 'pattern_help_2' => 'Available variables:',
+ 'pattern_help_3' => 'For example, :example would be converted to :value',
+ 'see_options' => 'See options',
+ 'invoice_counter' => 'Invoice Counter',
+ 'quote_counter' => 'Quote Counter',
+ 'type' => 'Type',
+
+ 'activity_1' => ':user created client :client',
+ 'activity_2' => ':user archived client :client',
+ 'activity_3' => ':user deleted client :client',
+ 'activity_4' => ':user created invoice :invoice',
+ 'activity_5' => ':user updated invoice :invoice',
+ 'activity_6' => ':user emailed invoice :invoice to :contact',
+ 'activity_7' => ':contact viewed invoice :invoice',
+ 'activity_8' => ':user archived invoice :invoice',
+ 'activity_9' => ':user deleted invoice :invoice',
+ 'activity_10' => ':contact entered payment :payment for :invoice',
+ 'activity_11' => ':user updated payment :payment',
+ 'activity_12' => ':user archived payment :payment',
+ 'activity_13' => ':user deleted payment :payment',
+ 'activity_14' => ':user entered :credit credit',
+ 'activity_15' => ':user updated :credit credit',
+ 'activity_16' => ':user archived :credit credit',
+ 'activity_17' => ':user deleted :credit credit',
+ 'activity_18' => ':user created quote :quote',
+ 'activity_19' => ':user updated quote :quote',
+ 'activity_20' => ':user emailed quote :quote to :contact',
+ 'activity_21' => ':contact viewed quote :quote',
+ 'activity_22' => ':user archived quote :quote',
+ 'activity_23' => ':user deleted quote :quote',
+ 'activity_24' => ':user restored quote :quote',
+ 'activity_25' => ':user restored invoice :invoice',
+ 'activity_26' => ':user restored client :client',
+ 'activity_27' => ':user restored payment :payment',
+ 'activity_28' => ':user restored :credit credit',
+ 'activity_29' => ':contact approved quote :quote',
+
+ 'payment' => 'Payment',
+ 'system' => 'System',
);
\ No newline at end of file
diff --git a/resources/lang/nl/texts.php b/resources/lang/nl/texts.php
index bacb5e9d32..2b8b55f986 100644
--- a/resources/lang/nl/texts.php
+++ b/resources/lang/nl/texts.php
@@ -821,5 +821,61 @@ return array(
'no_longer_running' => 'This invoice is not scheduled to run',
'general_settings' => 'General Settings',
'customize' => 'Customize',
+ 'oneclick_login_help' => 'Connect an account to login without a password',
+ 'referral_code_help' => 'Earn money by sharing our app online',
+
+ 'enable_with_stripe' => 'Enable | Requires Stripe',
+ 'tax_settings' => 'Tax Settings',
+ 'create_tax_rate' => 'Add Tax Rate',
+ 'updated_tax_rate' => 'Successfully updated tax rate',
+ 'created_tax_rate' => 'Successfully created tax rate',
+ 'edit_tax_rate' => 'Edit tax rate',
+ 'archive_tax_rate' => 'Archive tax rate',
+ 'archived_tax_rate' => 'Successfully archived the tax rate',
+ 'default_tax_rate_id' => 'Default Tax Rate',
+ 'tax_rate' => 'Tax Rate',
+ 'recurring_hour' => 'Recurring Hour',
+ 'pattern' => 'Pattern',
+ 'pattern_help_title' => 'Pattern Help',
+ 'pattern_help_1' => 'Create custom invoice and quote numbers by specifying a pattern',
+ 'pattern_help_2' => 'Available variables:',
+ 'pattern_help_3' => 'For example, :example would be converted to :value',
+ 'see_options' => 'See options',
+ 'invoice_counter' => 'Invoice Counter',
+ 'quote_counter' => 'Quote Counter',
+ 'type' => 'Type',
+
+ 'activity_1' => ':user created client :client',
+ 'activity_2' => ':user archived client :client',
+ 'activity_3' => ':user deleted client :client',
+ 'activity_4' => ':user created invoice :invoice',
+ 'activity_5' => ':user updated invoice :invoice',
+ 'activity_6' => ':user emailed invoice :invoice to :contact',
+ 'activity_7' => ':contact viewed invoice :invoice',
+ 'activity_8' => ':user archived invoice :invoice',
+ 'activity_9' => ':user deleted invoice :invoice',
+ 'activity_10' => ':contact entered payment :payment for :invoice',
+ 'activity_11' => ':user updated payment :payment',
+ 'activity_12' => ':user archived payment :payment',
+ 'activity_13' => ':user deleted payment :payment',
+ 'activity_14' => ':user entered :credit credit',
+ 'activity_15' => ':user updated :credit credit',
+ 'activity_16' => ':user archived :credit credit',
+ 'activity_17' => ':user deleted :credit credit',
+ 'activity_18' => ':user created quote :quote',
+ 'activity_19' => ':user updated quote :quote',
+ 'activity_20' => ':user emailed quote :quote to :contact',
+ 'activity_21' => ':contact viewed quote :quote',
+ 'activity_22' => ':user archived quote :quote',
+ 'activity_23' => ':user deleted quote :quote',
+ 'activity_24' => ':user restored quote :quote',
+ 'activity_25' => ':user restored invoice :invoice',
+ 'activity_26' => ':user restored client :client',
+ 'activity_27' => ':user restored payment :payment',
+ 'activity_28' => ':user restored :credit credit',
+ 'activity_29' => ':contact approved quote :quote',
+
+ 'payment' => 'Payment',
+ 'system' => 'System',
);
diff --git a/resources/lang/pt_BR/texts.php b/resources/lang/pt_BR/texts.php
index 0bbccacef7..d524d7f165 100644
--- a/resources/lang/pt_BR/texts.php
+++ b/resources/lang/pt_BR/texts.php
@@ -820,5 +820,61 @@ return array(
'no_longer_running' => 'Esta fatura não está agendada',
'general_settings' => 'Configurações Gerais',
'customize' => 'Personalizar',
+ 'oneclick_login_help' => 'Connect an account to login without a password',
+ 'referral_code_help' => 'Earn money by sharing our app online',
+
+ 'enable_with_stripe' => 'Enable | Requires Stripe',
+ 'tax_settings' => 'Tax Settings',
+ 'create_tax_rate' => 'Add Tax Rate',
+ 'updated_tax_rate' => 'Successfully updated tax rate',
+ 'created_tax_rate' => 'Successfully created tax rate',
+ 'edit_tax_rate' => 'Edit tax rate',
+ 'archive_tax_rate' => 'Archive tax rate',
+ 'archived_tax_rate' => 'Successfully archived the tax rate',
+ 'default_tax_rate_id' => 'Default Tax Rate',
+ 'tax_rate' => 'Tax Rate',
+ 'recurring_hour' => 'Recurring Hour',
+ 'pattern' => 'Pattern',
+ 'pattern_help_title' => 'Pattern Help',
+ 'pattern_help_1' => 'Create custom invoice and quote numbers by specifying a pattern',
+ 'pattern_help_2' => 'Available variables:',
+ 'pattern_help_3' => 'For example, :example would be converted to :value',
+ 'see_options' => 'See options',
+ 'invoice_counter' => 'Invoice Counter',
+ 'quote_counter' => 'Quote Counter',
+ 'type' => 'Type',
+
+ 'activity_1' => ':user created client :client',
+ 'activity_2' => ':user archived client :client',
+ 'activity_3' => ':user deleted client :client',
+ 'activity_4' => ':user created invoice :invoice',
+ 'activity_5' => ':user updated invoice :invoice',
+ 'activity_6' => ':user emailed invoice :invoice to :contact',
+ 'activity_7' => ':contact viewed invoice :invoice',
+ 'activity_8' => ':user archived invoice :invoice',
+ 'activity_9' => ':user deleted invoice :invoice',
+ 'activity_10' => ':contact entered payment :payment for :invoice',
+ 'activity_11' => ':user updated payment :payment',
+ 'activity_12' => ':user archived payment :payment',
+ 'activity_13' => ':user deleted payment :payment',
+ 'activity_14' => ':user entered :credit credit',
+ 'activity_15' => ':user updated :credit credit',
+ 'activity_16' => ':user archived :credit credit',
+ 'activity_17' => ':user deleted :credit credit',
+ 'activity_18' => ':user created quote :quote',
+ 'activity_19' => ':user updated quote :quote',
+ 'activity_20' => ':user emailed quote :quote to :contact',
+ 'activity_21' => ':contact viewed quote :quote',
+ 'activity_22' => ':user archived quote :quote',
+ 'activity_23' => ':user deleted quote :quote',
+ 'activity_24' => ':user restored quote :quote',
+ 'activity_25' => ':user restored invoice :invoice',
+ 'activity_26' => ':user restored client :client',
+ 'activity_27' => ':user restored payment :payment',
+ 'activity_28' => ':user restored :credit credit',
+ 'activity_29' => ':contact approved quote :quote',
+
+ 'payment' => 'Payment',
+ 'system' => 'System',
);
diff --git a/resources/lang/sv/texts.php b/resources/lang/sv/texts.php
index ed06fa1c89..e605fd758f 100644
--- a/resources/lang/sv/texts.php
+++ b/resources/lang/sv/texts.php
@@ -105,12 +105,12 @@ return array(
'recurring_invoices' => 'Återkommande fakturor',
'recurring_help' => 'Skicka automatiskt fakturor till kund varje vecka, månad, kvartal eller årsvis.
Använd :MONTH, :QUARTER eller :YEAR för dynamiskt datum. Enkla formler fungerar också, t.ex. :MONTH-1
- Exempel på dynamiska fakturavariabler::
-
- "Medlemskap för månaden :MONTH" => "Medlemskap för månaden juli"
- ":YEAR+1 årlig prenumeration" => "2015 årlig prenumeration"
- "Underhåll för :QUARTER+1" => "Underhåll för Q2"
- ',
+ Exempel på dynamiska fakturavariabler::
+
+ "Medlemskap för månaden :MONTH" => "Medlemskap för månaden juli"
+ ":YEAR+1 årlig prenumeration" => "2015 årlig prenumeration"
+ "Underhåll för :QUARTER+1" => "Underhåll för Q2"
+ ',
// dashboard
'in_total_revenue' => 'i totala intäkter',
@@ -283,19 +283,19 @@ return array(
// Security alerts
'confide' => [
- 'too_many_attempts' => 'För många felaktiga försök. Pröva igen om ett par minuter.',
- 'wrong_credentials' => 'Felaktig e-postadress eller lösenord.',
- 'confirmation' => 'Ditt konto har bekräftats!',
- 'wrong_confirmation' => 'Felaktig bekräftelsekod.',
- 'password_forgot' => 'Information angående återställning av ditt lösenord har skickats till dig via e-post.',
- 'password_reset' => 'Ditt lösenord har uppdaterats.',
- 'wrong_password_reset' => 'Felaktigt lösenord. Försök igen',
+ 'too_many_attempts' => 'För många felaktiga försök. Pröva igen om ett par minuter.',
+ 'wrong_credentials' => 'Felaktig e-postadress eller lösenord.',
+ 'confirmation' => 'Ditt konto har bekräftats!',
+ 'wrong_confirmation' => 'Felaktig bekräftelsekod.',
+ 'password_forgot' => 'Information angående återställning av ditt lösenord har skickats till dig via e-post.',
+ 'password_reset' => 'Ditt lösenord har uppdaterats.',
+ 'wrong_password_reset' => 'Felaktigt lösenord. Försök igen',
],
// Pro Plan
'pro_plan' => [
- 'remove_logo' => ':link för att ta bort Invoice Ninja loggan genom att uppgradera till Pro Plan',
- 'remove_logo_link' => 'Klicka här',
+ 'remove_logo' => ':link för att ta bort Invoice Ninja loggan genom att uppgradera till Pro Plan',
+ 'remove_logo_link' => 'Klicka här',
],
'logout' => 'Logga ut',
@@ -312,11 +312,11 @@ return array(
'pro_plan_product' => 'Pro Plan',
'pro_plan_description' => 'Ett års prenumeration på Invoice Ninja Pro.',
'pro_plan_success' => 'Tack för att du väljer Invoice Ninja\'s Pro!
- Nästa steg
En faktura har skickats till din angivna e-postadress.
- Var vänlig och följ instruktionerna på fakturan för att betala för ett års
- Pro fakturering och få tillgång till alla fantastiska Pro-funktioner.
- Hittar du inte fakturan? Behöver du support? Vi hjälper dig!
- -- maila oss på contact@invoiceninja.com',
+ Nästa steg
En faktura har skickats till din angivna e-postadress.
+ Var vänlig och följ instruktionerna på fakturan för att betala för ett års
+ Pro fakturering och få tillgång till alla fantastiska Pro-funktioner.
+ Hittar du inte fakturan? Behöver du support? Vi hjälper dig!
+ -- maila oss på contact@invoiceninja.com',
'unsaved_changes' => 'Du har osparade ändringar',
'custom_fields' => 'Anpassade fält',
@@ -748,9 +748,9 @@ return array(
'primary_user' => 'Primary User',
'help' => 'Help',
'customize_help' => 'We use pdfmake to define the invoice designs declaratively. The pdfmake playground provide\'s a great way to see the library in action.
- You can access any invoice field by adding Value
to the end. For example $invoiceNumberValue
displays the invoice number.
- To access a child property using dot notation. For example to show the client name you could use $client.nameValue
.
- If you need help figuring something out post a question to our support forum .
',
+ You can access any invoice field by adding Value
to the end. For example $invoiceNumberValue
displays the invoice number.
+ To access a child property using dot notation. For example to show the client name you could use $client.nameValue
.
+ If you need help figuring something out post a question to our support forum .
',
'invoice_due_date' => 'Due Date',
'quote_due_date' => 'Valid Until',
@@ -803,9 +803,9 @@ return array(
'invoice_charges' => 'Invoice Charges',
'invitation_status' => [
- 'sent' => 'Email Sent',
- 'opened' => 'Email Openend',
- 'viewed' => 'Invoice Viewed',
+ 'sent' => 'Email Sent',
+ 'opened' => 'Email Openend',
+ 'viewed' => 'Invoice Viewed',
],
'notification_invoice_bounced' => 'We were unable to deliver Invoice :invoice to :contact.',
'notification_invoice_bounced_subject' => 'Unable to deliver Invoice :invoice',
@@ -824,5 +824,61 @@ return array(
'no_longer_running' => 'This invoice is not scheduled to run',
'general_settings' => 'General Settings',
'customize' => 'Customize',
+ 'oneclick_login_help' => 'Connect an account to login without a password',
+ 'referral_code_help' => 'Earn money by sharing our app online',
+
+ 'enable_with_stripe' => 'Enable | Requires Stripe',
+ 'tax_settings' => 'Tax Settings',
+ 'create_tax_rate' => 'Add Tax Rate',
+ 'updated_tax_rate' => 'Successfully updated tax rate',
+ 'created_tax_rate' => 'Successfully created tax rate',
+ 'edit_tax_rate' => 'Edit tax rate',
+ 'archive_tax_rate' => 'Archive tax rate',
+ 'archived_tax_rate' => 'Successfully archived the tax rate',
+ 'default_tax_rate_id' => 'Default Tax Rate',
+ 'tax_rate' => 'Tax Rate',
+ 'recurring_hour' => 'Recurring Hour',
+ 'pattern' => 'Pattern',
+ 'pattern_help_title' => 'Pattern Help',
+ 'pattern_help_1' => 'Create custom invoice and quote numbers by specifying a pattern',
+ 'pattern_help_2' => 'Available variables:',
+ 'pattern_help_3' => 'For example, :example would be converted to :value',
+ 'see_options' => 'See options',
+ 'invoice_counter' => 'Invoice Counter',
+ 'quote_counter' => 'Quote Counter',
+ 'type' => 'Type',
+
+ 'activity_1' => ':user created client :client',
+ 'activity_2' => ':user archived client :client',
+ 'activity_3' => ':user deleted client :client',
+ 'activity_4' => ':user created invoice :invoice',
+ 'activity_5' => ':user updated invoice :invoice',
+ 'activity_6' => ':user emailed invoice :invoice to :contact',
+ 'activity_7' => ':contact viewed invoice :invoice',
+ 'activity_8' => ':user archived invoice :invoice',
+ 'activity_9' => ':user deleted invoice :invoice',
+ 'activity_10' => ':contact entered payment :payment for :invoice',
+ 'activity_11' => ':user updated payment :payment',
+ 'activity_12' => ':user archived payment :payment',
+ 'activity_13' => ':user deleted payment :payment',
+ 'activity_14' => ':user entered :credit credit',
+ 'activity_15' => ':user updated :credit credit',
+ 'activity_16' => ':user archived :credit credit',
+ 'activity_17' => ':user deleted :credit credit',
+ 'activity_18' => ':user created quote :quote',
+ 'activity_19' => ':user updated quote :quote',
+ 'activity_20' => ':user emailed quote :quote to :contact',
+ 'activity_21' => ':contact viewed quote :quote',
+ 'activity_22' => ':user archived quote :quote',
+ 'activity_23' => ':user deleted quote :quote',
+ 'activity_24' => ':user restored quote :quote',
+ 'activity_25' => ':user restored invoice :invoice',
+ 'activity_26' => ':user restored client :client',
+ 'activity_27' => ':user restored payment :payment',
+ 'activity_28' => ':user restored :credit credit',
+ 'activity_29' => ':contact approved quote :quote',
+
+ 'payment' => 'Payment',
+ 'system' => 'System',
);
diff --git a/resources/views/clients/edit.blade.php b/resources/views/clients/edit.blade.php
index 1891cc6f7c..becbfbdd95 100644
--- a/resources/views/clients/edit.blade.php
+++ b/resources/views/clients/edit.blade.php
@@ -1,4 +1,3 @@
-
@extends('header')
@@ -7,6 +6,11 @@
@stop
@section('content')
+
+@if ($errors->first('contacts'))
+ {{ trans($errors->first('contacts')) }}
+@endif
+
{!! Former::open($url)
@@ -17,6 +21,7 @@
@if ($client)
{!! Former::populate($client) !!}
+ {!! Former::hidden('public_id') !!}
@endif
@@ -75,11 +80,16 @@
- {!! Former::hidden('public_id')->data_bind("value: public_id, valueUpdate: 'afterkeydown'") !!}
- {!! Former::text('first_name')->data_bind("value: first_name, valueUpdate: 'afterkeydown'") !!}
- {!! Former::text('last_name')->data_bind("value: last_name, valueUpdate: 'afterkeydown'") !!}
- {!! Former::text('email')->data_bind('value: email, valueUpdate: \'afterkeydown\', attr: {id:\'email\'+$index()}') !!}
- {!! Former::text('phone')->data_bind("value: phone, valueUpdate: 'afterkeydown'") !!}
+ {!! Former::hidden('public_id')->data_bind("value: public_id, valueUpdate: 'afterkeydown',
+ attr: {name: 'contacts[' + \$index() + '][public_id]'}") !!}
+ {!! Former::text('first_name')->data_bind("value: first_name, valueUpdate: 'afterkeydown',
+ attr: {name: 'contacts[' + \$index() + '][first_name]'}") !!}
+ {!! Former::text('last_name')->data_bind("value: last_name, valueUpdate: 'afterkeydown',
+ attr: {name: 'contacts[' + \$index() + '][last_name]'}") !!}
+ {!! Former::text('email')->data_bind("value: email, valueUpdate: 'afterkeydown',
+ attr: {name: 'contacts[' + \$index() + '][email]', id:'email'+\$index()}") !!}
+ {!! Former::text('phone')->data_bind("value: phone, valueUpdate: 'afterkeydown',
+ attr: {name: 'contacts[' + \$index() + '][phone]'}") !!}
@@ -141,13 +151,14 @@
self.phone = ko.observable('');
if (data) {
- ko.mapping.fromJS(data, {}, this);
- }
+ ko.mapping.fromJS(data, {}, this);
+ }
}
- function ContactsModel(data) {
+ function ClientModel(data) {
var self = this;
- self.contacts = ko.observableArray();
+
+ self.contacts = ko.observableArray();
self.mapping = {
'contacts': {
@@ -155,10 +166,10 @@
return new ContactModel(options.data);
}
}
- }
+ }
if (data) {
- ko.mapping.fromJS(data, self.mapping, this);
+ ko.mapping.fromJS(data, self.mapping, this);
} else {
self.contacts.push(new ContactModel());
}
@@ -174,7 +185,11 @@
});
}
- window.model = new ContactsModel({!! $client !!});
+ @if ($data)
+ window.model = new ClientModel({!! $data !!});
+ @else
+ window.model = new ClientModel({!! $client !!});
+ @endif
model.showContact = function(elem) { if (elem.nodeType === 1) $(elem).hide().slideDown() }
model.hideContact = function(elem) { if (elem.nodeType === 1) $(elem).slideUp(function() { $(elem).remove(); }) }
diff --git a/resources/views/clients/show.blade.php b/resources/views/clients/show.blade.php
index c04e1f383e..bed5942c14 100644
--- a/resources/views/clients/show.blade.php
+++ b/resources/views/clients/show.blade.php
@@ -25,7 +25,7 @@
{!! Former::open('clients/bulk')->addClass('mainForm') !!}
{!! Former::text('action') !!}
- {!! Former::text('id')->value($client->public_id) !!}
+ {!! Former::text('public_id')->value($client->public_id) !!}
@if ($gatewayLink)
diff --git a/resources/views/dashboard.blade.php b/resources/views/dashboard.blade.php
index 247626bf62..bc9c8ff01a 100644
--- a/resources/views/dashboard.blade.php
+++ b/resources/views/dashboard.blade.php
@@ -80,7 +80,7 @@
@foreach ($activities as $activity)
{{ Utils::timestampToDateString(strtotime($activity->created_at)) }}:
- {!! Utils::decodeActivity($activity->message) !!}
+ {!! $activity->getMessage() !!}
@endforeach
diff --git a/resources/views/invoices/edit.blade.php b/resources/views/invoices/edit.blade.php
index b9094cc651..362194c81f 100644
--- a/resources/views/invoices/edit.blade.php
+++ b/resources/views/invoices/edit.blade.php
@@ -15,8 +15,7 @@
@stop
@section('content')
-
- @if ($invoice->id)
+ @if ($invoice->id)
@if ($invoice->is_recurring)
{!! link_to('invoices', trans('texts.recurring_invoice')) !!}
@@ -180,20 +179,30 @@
$parent.invoice_items().length > 1" class="fa fa-sort">
- {!! Former::text('product_key')->useDatalist($products->toArray(), 'product_key')->onkeyup('onItemChange()')
- ->raw()->data_bind("value: product_key, valueUpdate: 'afterkeydown'")->addClass('datalist') !!}
+ {!! Former::text('product_key')->useDatalist($products->toArray(), 'product_key')
+ ->data_bind("value: product_key, valueUpdate: 'afterkeydown', attr: {name: 'invoice_items[' + \$index() + '][product_key]'}")
+ ->addClass('datalist')
+ ->onkeyup('onItemChange()')
+ ->raw()
+ !!}
-
+
+
-
+
-
+
-
+
+
+
@@ -230,7 +239,7 @@
->label(false)->style('resize: none; min-width: 450px')->rows(3)
->help('') !!}
@@ -240,7 +249,7 @@
->label(false)->style('resize: none; min-width: 450px')->rows(3)
->help('') !!}
@@ -266,7 +275,7 @@
{{ $account->custom_invoice_label1 }}
-
+
@endif
@@ -275,7 +284,7 @@
{{ $account->custom_invoice_label2 }}
-
+
@endif
@@ -294,7 +303,11 @@
@if (!$account->hide_quantity)
{{ trans('texts.tax') }}
@endif
-
+
+
+
+
+
@@ -303,7 +316,7 @@
{{ $account->custom_invoice_label1 }}
-
+
@endif
@@ -312,22 +325,22 @@
{{ $account->custom_invoice_label2 }}
-
+
@endif
@if (!$account->hide_paid_to_date)
-
+
{{ trans('texts.paid_to_date') }}
-
+
@endif
-
+
{{ trans($entityType == ENTITY_INVOICE ? 'texts.balance_due' : 'texts.total') }}
@@ -345,15 +358,15 @@
{!! Former::populateField('entityType', $entityType) !!}
+
{!! Former::text('entityType') !!}
{!! Former::text('action') !!}
- {!! Former::text('data')->data_bind("value: ko.mapping.toJSON(model)") !!}
- {!! Former::text('pdfupload') !!}
-
- @if ($invoice->id)
- {!! Former::populateField('id', $invoice->public_id) !!}
- {!! Former::text('id') !!}
- @endif
+ {!! Former::text('public_id')->data_bind('value: public_id') !!}
+ {!! Former::text('is_recurring')->data_bind('value: is_recurring') !!}
+ {!! Former::text('is_quote')->data_bind('value: is_quote') !!}
+ {!! Former::text('has_tasks')->data_bind('value: has_tasks') !!}
+ {!! Former::text('data')->data_bind('value: ko.mapping.toJSON(model)') !!}
+ {!! Former::text('pdfupload') !!}
@@ -377,7 +390,7 @@
@endif
@elseif ($invoice && $invoice->trashed() && !$invoice->is_deleted == '1')
- {!! Button::success(trans('texts.restore'))->withAttributes(['onclick' => 'submitAction("restore")'])->appendIcon(Icon::create('cloud-download')) !!}
+ {!! Button::success(trans('texts.restore'))->withAttributes(['onclick' => 'submitBulkAction("restore")'])->appendIcon(Icon::create('cloud-download')) !!}
@endif
@@ -406,22 +419,37 @@
- {!! Former::text('name')->data_bind("value: name, valueUpdate: 'afterkeydown', attr { placeholder: name.placeholder }")->label('client_name') !!}
+ {!! Former::hidden('client_public_id')->data_bind("value: public_id, valueUpdate: 'afterkeydown',
+ attr: {name: 'client[public_id]'}") !!}
+ {!! Former::text('client[name]')
+ ->data_bind("value: name, valueUpdate: 'afterkeydown', attr { placeholder: name.placeholder }")
+ ->label('client_name') !!}
+
- {!! Former::text('id_number')->data_bind("value: id_number, valueUpdate: 'afterkeydown'") !!}
- {!! Former::text('vat_number')->data_bind("value: vat_number, valueUpdate: 'afterkeydown'") !!}
+ {!! Former::text('client[id_number]')
+ ->label('id_number')
+ ->data_bind("value: id_number, valueUpdate: 'afterkeydown'") !!}
+ {!! Former::text('client[vat_number]')
+ ->label('vat_number')
+ ->data_bind("value: vat_number, valueUpdate: 'afterkeydown'") !!}
- {!! Former::text('website')->data_bind("value: website, valueUpdate: 'afterkeydown'") !!}
- {!! Former::text('work_phone')->data_bind("value: work_phone, valueUpdate: 'afterkeydown'") !!}
+ {!! Former::text('client[website]')
+ ->label('website')
+ ->data_bind("value: website, valueUpdate: 'afterkeydown'") !!}
+ {!! Former::text('client[work_phone]')
+ ->label('work_phone')
+ ->data_bind("value: work_phone, valueUpdate: 'afterkeydown'") !!}
@if (Auth::user()->isPro())
@if ($account->custom_client_label1)
- {!! Former::text('custom_value1')->label($account->custom_client_label1)
+ {!! Former::text('client[custom_value1]')
+ ->label($account->custom_client_label1)
->data_bind("value: custom_value1, valueUpdate: 'afterkeydown'") !!}
@endif
@if ($account->custom_client_label2)
- {!! Former::text('custom_value2')->label($account->custom_client_label2)
+ {!! Former::text('client[custom_value2]')
+ ->label($account->custom_client_label2)
->data_bind("value: custom_value2, valueUpdate: 'afterkeydown'") !!}
@endif
@endif
@@ -429,13 +457,25 @@
- {!! Former::text('address1')->data_bind("value: address1, valueUpdate: 'afterkeydown'") !!}
- {!! Former::text('address2')->data_bind("value: address2, valueUpdate: 'afterkeydown'") !!}
- {!! Former::text('city')->data_bind("value: city, valueUpdate: 'afterkeydown'") !!}
- {!! Former::text('state')->data_bind("value: state, valueUpdate: 'afterkeydown'") !!}
- {!! Former::text('postal_code')->data_bind("value: postal_code, valueUpdate: 'afterkeydown'") !!}
- {!! Former::select('country_id')->addOption('','')->addGroupClass('country_select')
- ->fromQuery($countries, 'name', 'id')->data_bind("dropdown: country_id") !!}
+ {!! Former::text('client[address1]')
+ ->label(trans('texts.address1'))
+ ->data_bind("value: address1, valueUpdate: 'afterkeydown'") !!}
+ {!! Former::text('client[address2]')
+ ->label(trans('texts.address2'))
+ ->data_bind("value: address2, valueUpdate: 'afterkeydown'") !!}
+ {!! Former::text('client[city]')
+ ->label(trans('texts.city'))
+ ->data_bind("value: city, valueUpdate: 'afterkeydown'") !!}
+ {!! Former::text('client[state]')
+ ->label(trans('texts.state'))
+ ->data_bind("value: state, valueUpdate: 'afterkeydown'") !!}
+ {!! Former::text('client[postal_code]')
+ ->label(trans('texts.postal_code'))
+ ->data_bind("value: postal_code, valueUpdate: 'afterkeydown'") !!}
+ {!! Former::select('client[country_id]')
+ ->label(trans('texts.country_id'))
+ ->addOption('','')->addGroupClass('country_select')
+ ->fromQuery($countries, 'name', 'id')->data_bind("dropdown: country_id") !!}
@@ -444,11 +484,18 @@
- {!! Former::hidden('public_id')->data_bind("value: public_id, valueUpdate: 'afterkeydown'") !!}
- {!! Former::text('first_name')->data_bind("value: first_name, valueUpdate: 'afterkeydown'") !!}
- {!! Former::text('last_name')->data_bind("value: last_name, valueUpdate: 'afterkeydown'") !!}
- {!! Former::text('email')->data_bind('value: email, valueUpdate: \'afterkeydown\', attr: {id:\'email\'+$index()}') !!}
- {!! Former::text('phone')->data_bind("value: phone, valueUpdate: 'afterkeydown'") !!}
+
+ {!! Former::hidden('public_id')->data_bind("value: public_id, valueUpdate: 'afterkeydown',
+ attr: {name: 'client[contacts][' + \$index() + '][public_id]'}") !!}
+ {!! Former::text('first_name')->data_bind("value: first_name, valueUpdate: 'afterkeydown',
+ attr: {name: 'client[contacts][' + \$index() + '][first_name]'}") !!}
+ {!! Former::text('last_name')->data_bind("value: last_name, valueUpdate: 'afterkeydown',
+ attr: {name: 'client[contacts][' + \$index() + '][last_name]'}") !!}
+ {!! Former::text('email')->data_bind("value: email, valueUpdate: 'afterkeydown',
+ attr: {name: 'client[contacts][' + \$index() + '][email]', id:'email'+\$index()}") !!}
+ {!! Former::text('phone')->data_bind("value: phone, valueUpdate: 'afterkeydown',
+ attr: {name: 'client[contacts][' + \$index() + '][phone]'}") !!}
+
@@ -523,6 +577,14 @@
{!! Former::close() !!}
+ {!! Former::open("{$entityType}s/bulk")->addClass('bulkForm') !!}
+ {!! Former::populateField('bulk_public_id', $invoice->public_id) !!}
+
+ {!! Former::text('bulk_public_id') !!}
+ {!! Former::text('bulk_action') !!}
+
+ {!! Former::close() !!}
+
@include('invoices.knockout')
@@ -571,6 +633,7 @@
var invoice = {!! $invoice !!};
ko.mapping.fromJS(invoice, model.invoice().mapping, model.invoice);
+ model.invoice().is_recurring({{ $invoice->is_recurring ? '1' : '0' }});
@if ($invoice->id)
var invitationContactIds = {!! json_encode($invitationContactIds) !!};
@@ -770,7 +833,7 @@
function createInvoiceModel() {
var invoice = ko.toJS(window.model).invoice;
invoice.is_pro = {{ Auth::user()->isPro() ? '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});
if (invoice.is_recurring) {
@@ -909,6 +972,11 @@
$('#submitButton').click();
}
+ function submitBulkAction(value) {
+ $('#bulk_action').val(value);
+ $('.bulkForm').submit();
+ }
+
function isSaveValid() {
var isValid = false;
for (var i=0; i
{!! Former::text('action') !!}
{!! Former::text('statusId') !!}
- {!! Former::text('id') !!}
+ {!! Former::text('public_id') !!}
@if ($entityType == ENTITY_TASK)
@@ -66,37 +66,37 @@
}
function deleteEntity(id) {
- $('#id').val(id);
+ $('#public_id').val(id);
submitForm('delete');
}
function archiveEntity(id) {
- $('#id').val(id);
+ $('#public_id').val(id);
submitForm('archive');
}
function restoreEntity(id) {
- $('#id').val(id);
+ $('#public_id').val(id);
submitForm('restore');
}
function convertEntity(id) {
- $('#id').val(id);
+ $('#public_id').val(id);
submitForm('convert');
}
function markEntity(id, statusId) {
- $('#id').val(id);
+ $('#public_id').val(id);
$('#statusId').val(statusId);
submitForm('mark');
}
function stopTask(id) {
- $('#id').val(id);
+ $('#public_id').val(id);
submitForm('stop');
}
function invoiceTask(id) {
- $('#id').val(id);
+ $('#public_id').val(id);
submitForm('invoice');
}
diff --git a/resources/views/payments/edit.blade.php b/resources/views/payments/edit.blade.php
index 611751ceba..fd6d8e3e0a 100644
--- a/resources/views/payments/edit.blade.php
+++ b/resources/views/payments/edit.blade.php
@@ -12,6 +12,9 @@
{!! Former::populate($payment) !!}
@endif
+
+ {!! Former::text('public_id') !!}
+
diff --git a/resources/views/tasks/edit.blade.php b/resources/views/tasks/edit.blade.php
index 918baed9f2..fde99f6318 100644
--- a/resources/views/tasks/edit.blade.php
+++ b/resources/views/tasks/edit.blade.php
@@ -45,7 +45,7 @@
@if (Auth::user()->account->timezone_id)
{{ $timezone }}
@else
- {!! link_to('/settings/company_details?focus=timezone_id', $timezone, ['target' => '_blank']) !!}
+ {!! link_to('/settings/localization?focus=timezone_id', $timezone, ['target' => '_blank']) !!}
@endif
@@ -117,6 +117,9 @@
@if ($task && $task->is_running)
{!! Button::success(trans('texts.save'))->large()->appendIcon(Icon::create('floppy-disk'))->withAttributes(['id' => 'save-button']) !!}
{!! Button::primary(trans('texts.stop'))->large()->appendIcon(Icon::create('stop'))->withAttributes(['id' => 'stop-button']) !!}
+ @elseif ($task && $task->trashed())
+ {!! Button::normal(trans('texts.cancel'))->large()->asLinkTo(URL::to('/tasks'))->appendIcon(Icon::create('remove-circle')) !!}
+ {!! Button::success(trans('texts.restore'))->large()->withAttributes(['onclick' => 'submitAction("restore")'])->appendIcon(Icon::create('cloud-download')) !!}
@else
{!! Button::normal(trans('texts.cancel'))->large()->asLinkTo(URL::to('/tasks'))->appendIcon(Icon::create('remove-circle')) !!}
@if ($task)
diff --git a/tests/acceptance/CheckBalanceCest.php b/tests/acceptance/CheckBalanceCest.php
index f96fe85dbd..eabb30795b 100644
--- a/tests/acceptance/CheckBalanceCest.php
+++ b/tests/acceptance/CheckBalanceCest.php
@@ -25,7 +25,7 @@ class CheckBalanceCest
// create client
$I->amOnPage('/clients/create');
- $I->fillField(['name' => 'email'], $clientEmail);
+ $I->fillField(['name' => 'contacts[0][email]'], $clientEmail);
$I->click('Save');
$I->wait(1);
$I->see($clientEmail);
@@ -54,7 +54,7 @@ class CheckBalanceCest
// update the invoice
$I->amOnPage('/invoices/' . $invoiceId);
- $I->fillField(['name' => 'quantity'], 2);
+ $I->fillField(['name' => 'invoice_items[0][qty]'], 2);
$I->click('Save');
$I->wait(1);
$I->amOnPage("/clients/{$clientId}");
@@ -69,7 +69,7 @@ class CheckBalanceCest
// archive the invoice
$I->amOnPage('/invoices/' . $invoiceId);
- $I->executeJS('submitAction("archive")');
+ $I->executeJS('submitBulkAction("archive")');
$I->wait(1);
$I->amOnPage("/clients/{$clientId}");
$I->see('Balance $0.00');
@@ -77,7 +77,7 @@ class CheckBalanceCest
// delete the invoice
$I->amOnPage('/invoices/' . $invoiceId);
- $I->executeJS('submitAction("delete")');
+ $I->executeJS('submitBulkAction("delete")');
$I->wait(1);
$I->amOnPage("/clients/{$clientId}");
$I->see('Balance $0.00');
diff --git a/tests/acceptance/ClientCest.php b/tests/acceptance/ClientCest.php
index 70eb2f8e7d..e8b17e8dd2 100644
--- a/tests/acceptance/ClientCest.php
+++ b/tests/acceptance/ClientCest.php
@@ -32,10 +32,10 @@ class ClientCest
$I->fillField(['name' => 'work_phone'], $this->faker->phoneNumber);
//Contacts
- $I->fillField(['name' => 'first_name'], $this->faker->firstName);
- $I->fillField(['name' => 'last_name'], $this->faker->lastName);
- $I->fillField(['name' => 'email'], $this->faker->companyEmail);
- $I->fillField(['name' => 'phone'], $this->faker->phoneNumber);
+ $I->fillField(['name' => 'contacts[0][first_name]'], $this->faker->firstName);
+ $I->fillField(['name' => 'contacts[0][last_name]'], $this->faker->lastName);
+ $I->fillField(['name' => 'contacts[0][email]'], $this->faker->companyEmail);
+ $I->fillField(['name' => 'contacts[0][phone]'], $this->faker->phoneNumber);
//Additional Contact
//$I->click('Add contact +');
diff --git a/tests/acceptance/CreditCest.php b/tests/acceptance/CreditCest.php
index 6d7f1ac719..3c47d9ede3 100644
--- a/tests/acceptance/CreditCest.php
+++ b/tests/acceptance/CreditCest.php
@@ -24,7 +24,7 @@ class CreditCest
$I->wantTo('Create a credit');
$I->amOnPage('/clients/create');
- $I->fillField(['name' => 'email'], $clientEmail);
+ $I->fillField(['name' => 'contacts[0][email]'], $clientEmail);
$I->click('Save');
$I->see($clientEmail);
diff --git a/tests/acceptance/InvoiceCest.php b/tests/acceptance/InvoiceCest.php
index cd8238b097..5604b50830 100644
--- a/tests/acceptance/InvoiceCest.php
+++ b/tests/acceptance/InvoiceCest.php
@@ -24,7 +24,7 @@ class InvoiceCest
$I->wantTo('create an invoice');
$I->amOnPage('/clients/create');
- $I->fillField(['name' => 'email'], $clientEmail);
+ $I->fillField(['name' => 'contacts[0][email]'], $clientEmail);
$I->click('Save');
$I->see($clientEmail);
@@ -52,7 +52,7 @@ class InvoiceCest
$I->wantTo('create a recurring invoice');
$I->amOnPage('/clients/create');
- $I->fillField(['name' => 'email'], $clientEmail);
+ $I->fillField(['name' => 'contacts[0][email]'], $clientEmail);
$I->click('Save');
$I->see($clientEmail);
diff --git a/tests/acceptance/OnlinePaymentCest.php b/tests/acceptance/OnlinePaymentCest.php
index d7526a491e..9273bd1d32 100644
--- a/tests/acceptance/OnlinePaymentCest.php
+++ b/tests/acceptance/OnlinePaymentCest.php
@@ -1,4 +1,4 @@
-amOnPage('/clients/create');
- $I->fillField(['name' => 'email'], $clientEmail);
+ $I->fillField(['name' => 'contacts[0][email]'], $clientEmail);
$I->click('Save');
$I->see($clientEmail);
@@ -45,6 +45,7 @@ class OnlinePaymentCest
$I->fillField(['name' => 'notes'], $this->faker->text(80));
$I->fillField(['name' => 'cost'], $this->faker->numberBetween(1, 20));
$I->click('Save');
+ $I->wait(1);
$I->see($productKey);
// create invoice
diff --git a/tests/acceptance/PaymentCest.php b/tests/acceptance/PaymentCest.php
index 275d73909f..2808c7c8d3 100644
--- a/tests/acceptance/PaymentCest.php
+++ b/tests/acceptance/PaymentCest.php
@@ -25,7 +25,7 @@ class PaymentCest
// create client
$I->amOnPage('/clients/create');
- $I->fillField(['name' => 'email'], $clientEmail);
+ $I->fillField(['name' => 'contacts[0][email]'], $clientEmail);
$I->click('Save');
$I->see($clientEmail);
@@ -33,7 +33,7 @@ class PaymentCest
$I->amOnPage('/products/create');
$I->fillField(['name' => 'product_key'], $productKey);
$I->fillField(['name' => 'notes'], $this->faker->text(80));
- $I->fillField(['name' => 'cost'], $this->faker->numberBetween(1, 20));
+ $I->fillField(['name' => 'cost'], $this->faker->numberBetween(11, 20));
$I->click('Save');
$I->see($productKey);