diff --git a/app/Events/ExpenseWasArchived.php b/app/Events/ExpenseWasArchived.php
new file mode 100644
index 000000000000..7ff42b7b97e2
--- /dev/null
+++ b/app/Events/ExpenseWasArchived.php
@@ -0,0 +1,23 @@
+expense = $expense;
+ }
+
+}
diff --git a/app/Events/ExpenseWasCreated.php b/app/Events/ExpenseWasCreated.php
new file mode 100644
index 000000000000..efeb308d9bc9
--- /dev/null
+++ b/app/Events/ExpenseWasCreated.php
@@ -0,0 +1,22 @@
+expense = $expense;
+ }
+}
diff --git a/app/Events/ExpenseWasDeleted.php b/app/Events/ExpenseWasDeleted.php
new file mode 100644
index 000000000000..a058cf1666e1
--- /dev/null
+++ b/app/Events/ExpenseWasDeleted.php
@@ -0,0 +1,23 @@
+expense = $expense;
+ }
+
+}
diff --git a/app/Events/ExpenseWasRestored.php b/app/Events/ExpenseWasRestored.php
new file mode 100644
index 000000000000..ca308e4ca0f8
--- /dev/null
+++ b/app/Events/ExpenseWasRestored.php
@@ -0,0 +1,23 @@
+expense = $expense;
+ }
+
+}
diff --git a/app/Http/Controllers/ExpenseController.php b/app/Http/Controllers/ExpenseController.php
new file mode 100644
index 000000000000..c441a62dd0f6
--- /dev/null
+++ b/app/Http/Controllers/ExpenseController.php
@@ -0,0 +1,131 @@
+expenseRepo = $expenseRepo;
+ $this->expenseService = $expenseService;
+ }
+
+ /**
+ * Display a listing of the resource.
+ *
+ * @return Response
+ */
+ public function index()
+ {
+ return View::make('list', array(
+ 'entityType' => ENTITY_EXPENSE,
+ 'title' => trans('texts.expenses'),
+ 'sortCol' => '4',
+ 'columns' => Utils::trans([
+ 'checkbox',
+ 'vendor',
+ 'expense_amount',
+ 'expense_balance',
+ 'expense_date',
+ 'private_notes',
+ ''
+ ]),
+ ));
+ }
+
+ public function getDatatable($vendorPublicId = null)
+ {
+ return $this->expenseService->getDatatable($vendorPublicId, Input::get('sSearch'));
+ }
+
+ public function create($vendorPublicId = 0)
+ {
+ $vendor = Vendor::scope($vendorPublicId)->with('vendorcontacts')->firstOrFail();
+ $data = array(
+ 'vendorPublicId' => Input::old('vendor') ? Input::old('vendor') : $vendorPublicId,
+ 'expense' => null,
+ 'method' => 'POST',
+ 'url' => 'expenses',
+ 'title' => trans('texts.new_expense'),
+ 'vendors' => Vendor::scope()->with('vendorcontacts')->orderBy('name')->get(),
+ );
+
+ $data = array_merge($data, self::getViewModel());
+
+ return View::make('expenses.edit', $data);
+ }
+
+ public function edit($publicId)
+ {
+ $expense = Expense::scope($publicId)->firstOrFail();
+ $expense->expense_date = Utils::fromSqlDate($expense->expense_date);
+
+ $data = array(
+ 'vendor' => null,
+ 'expense' => $expense,
+ 'method' => 'PUT',
+ 'url' => 'expenses/'.$publicId,
+ 'title' => 'Edit Expense',
+ 'vendors' => Vendor::scope()->with('vendorcontacts')->orderBy('name')->get(), );
+
+ return View::make('expense.edit', $data);
+ }
+
+ public function store(CreateExpenseRequest $request)
+ {
+ $expense = $this->expenseRepo->save($request->input());
+
+ Session::flash('message', trans('texts.created_expense'));
+
+ return redirect()->to('expenses');
+ }
+
+ public function bulk()
+ {
+ $action = Input::get('action');
+ $ids = Input::get('public_id') ? Input::get('public_id') : Input::get('ids');
+ $count = $this->expenseService->bulk($ids, $action);
+
+ if ($count > 0) {
+ $message = Utils::pluralize($action.'d_expense', $count);
+ Session::flash('message', $message);
+ }
+
+ return Redirect::to('expenses');
+ }
+
+ private static function getViewModel()
+ {
+ return [
+ 'data' => Input::old('data'),
+ 'account' => Auth::user()->account,
+ 'sizes' => Cache::get('sizes'),
+ 'paymentTerms' => Cache::get('paymentTerms'),
+ 'industries' => Cache::get('industries'),
+ 'currencies' => Cache::get('currencies'),
+ 'languages' => Cache::get('languages'),
+ 'countries' => Cache::get('countries'),
+ 'customLabel1' => Auth::user()->account->custom_vendor_label1,
+ 'customLabel2' => Auth::user()->account->custom_vendor_label2,
+ ];
+ }
+
+}
diff --git a/app/Http/Requests/CreateExpenseRequest.php b/app/Http/Requests/CreateExpenseRequest.php
new file mode 100644
index 000000000000..0a0c71dd8208
--- /dev/null
+++ b/app/Http/Requests/CreateExpenseRequest.php
@@ -0,0 +1,29 @@
+ 'required|positive',
+ ];
+ }
+}
diff --git a/app/Http/Requests/UpdateExpenseRequest.php b/app/Http/Requests/UpdateExpenseRequest.php
new file mode 100644
index 000000000000..83b192280849
--- /dev/null
+++ b/app/Http/Requests/UpdateExpenseRequest.php
@@ -0,0 +1,28 @@
+ 'required|positive',
+ ];
+
}
}
diff --git a/app/Http/routes.php b/app/Http/routes.php
index 3f7ed3a84969..f4bdc8865d9c 100644
--- a/app/Http/routes.php
+++ b/app/Http/routes.php
@@ -188,6 +188,21 @@ Route::group(['middleware' => 'auth'], function() {
Route::get('api/vendor', array('as'=>'api.vendors', 'uses'=>'VendorController@getDatatable'));
Route::get('api/vendoractivities/{vendor_id?}', array('as'=>'api.vendoractivities', 'uses'=>'VendorActivityController@getDatatable'));
Route::post('vendors/bulk', 'VendorController@bulk');
+
+ // Expense
+ Route::get('expenses/{id}/edit', function() {
+ return View::make('header');
+ });
+
+ Route::resource('expenses', 'ExpenseController');
+ Route::get('expenses/create/{vendor_id?}', 'ExpenseController@create');
+ Route::get('api/expenses/{vendor_id?}', array('as'=>'api.expenses', 'uses'=>'ExpenseController@getDatatable'));
+
+ //Route::get('api/expenseactivities/{vendor_id?}', array('as'=>'api.expenseactivities', 'uses'=>'ExpenseActivityController@getDatatable'));
+ //Route::post('vendors/bulk', 'VendorController@bulk');
+
+
+ Route::post('expenses/bulk', 'ExpenseController@bulk');
});
@@ -252,6 +267,7 @@ if (!defined('CONTACT_EMAIL')) {
define('ENV_STAGING', 'staging');
define('RECENTLY_VIEWED', 'RECENTLY_VIEWED');
+
define('ENTITY_CLIENT', 'client');
define('ENTITY_CONTACT', 'contact');
define('ENTITY_INVOICE', 'invoice');
@@ -346,6 +362,12 @@ if (!defined('CONTACT_EMAIL')) {
define('ACTIVITY_TYPE_DELETE_VENDOR', 32);
define('ACTIVITY_TYPE_RESTORE_VENDOR', 33);
+ // expenses
+ define('ACTIVITY_TYPE_CREATE_EXPENSE', 34);
+ define('ACTIVITY_TYPE_ARCHIVE_EXPENSE', 35);
+ define('ACTIVITY_TYPE_DELETE_EXPENSE', 36);
+ define('ACTIVITY_TYPE_RESTORE_EXPENSE', 37);
+
define('DEFAULT_INVOICE_NUMBER', '0001');
define('RECENTLY_VIEWED_LIMIT', 8);
define('LOGGED_ERROR_LIMIT', 100);
@@ -379,7 +401,6 @@ if (!defined('CONTACT_EMAIL')) {
define('MAX_NUM_VENDORS_PRO', 20000);
define('MAX_NUM_VENDORS_LEGACY', 500);
-
define('INVOICE_STATUS_DRAFT', 1);
define('INVOICE_STATUS_SENT', 2);
define('INVOICE_STATUS_VIEWED', 3);
diff --git a/app/Listeners/ExpenseListener.php b/app/Listeners/ExpenseListener.php
new file mode 100644
index 000000000000..8d02f00ff4db
--- /dev/null
+++ b/app/Listeners/ExpenseListener.php
@@ -0,0 +1,16 @@
+expenseRepo = $expenseRepo;
+ }
+}
diff --git a/app/Listeners/SubscriptionListener.php b/app/Listeners/SubscriptionListener.php
index 60643a25e6dd..fab5a2c57493 100644
--- a/app/Listeners/SubscriptionListener.php
+++ b/app/Listeners/SubscriptionListener.php
@@ -10,6 +10,7 @@ use App\Events\CreditWasCreated;
use App\Events\PaymentWasCreated;
use App\Events\VendorWasCreated;
+use App\Events\ExpenseWasCreated;
class SubscriptionListener
{
@@ -51,4 +52,10 @@ class SubscriptionListener
{
$this->checkSubscriptions(ACTIVITY_TYPE_CREATE_VENDOR, $event->vendor);
}
+
+ public function createdExpense(ExpenseWasCreated $event)
+ {
+ $this->checkSubscriptions(ACTIVITY_TYPE_CREATE_EXPENSE, $event->expense);
+ }
+
}
diff --git a/app/Models/Expense.php b/app/Models/Expense.php
new file mode 100644
index 000000000000..c1522fa1bda4
--- /dev/null
+++ b/app/Models/Expense.php
@@ -0,0 +1,79 @@
+belongsTo('App\Models\Account');
+ }
+
+ public function user()
+ {
+ return $this->belongsTo('App\Models\User');
+ }
+
+ public function vendor()
+ {
+ return $this->belongsTo('App\Models\Vendor')->withTrashed();
+ }
+
+ public function getName()
+ {
+ return '';
+ }
+
+ public function getEntityType()
+ {
+ return ENTITY_EXPENSE;
+ }
+
+ public function apply($amount)
+ {
+ if ($amount > $this->balance) {
+ $applied = $this->balance;
+ $this->balance = 0;
+ } else {
+ $applied = $amount;
+ $this->balance = $this->balance - $amount;
+ }
+
+ $this->save();
+
+ return $applied;
+ }
+}
+
+Expense::creating(function ($expense) {
+ $expense->setNullValues();
+});
+
+Expense::created(function ($expense) {
+ event(new ExpenseWasCreated($expense));
+});
+
+Expense::updating(function ($expense) {
+ $expense->setNullValues();
+});
+
+Expense::updated(function ($expense) {
+ event(new ExpenseWasUpdated($expense));
+});
+
+
+
diff --git a/app/Models/ExpenseAcitvity.php b/app/Models/ExpenseAcitvity.php
new file mode 100644
index 000000000000..5a4166141668
--- /dev/null
+++ b/app/Models/ExpenseAcitvity.php
@@ -0,0 +1,56 @@
+whereAccountId(Auth::user()->account_id);
+ }
+
+ public function account()
+ {
+ return $this->belongsTo('App\Models\Account');
+ }
+
+ public function user()
+ {
+ return $this->belongsTo('App\Models\User')->withTrashed();
+ }
+
+ public function vendor()
+ {
+ return $this->belongsTo('App\Models\Vendor')->withTrashed();
+ }
+
+ public function getMessage()
+ {
+ $activityTypeId = $this->activity_type_id;
+ $account = $this->account;
+ $vendor = $this->vendor;
+ $user = $this->user;
+ $contactId = $this->contact_id;
+ $isSystem = $this->is_system;
+
+ if($vendor) {
+ $route = $vendor->getRoute();
+
+ $data = [
+ 'vendor' => link_to($route, $vendor->getDisplayName()),
+ 'user' => $isSystem ? '' . trans('texts.system') . '' : $user->getDisplayName(),
+ 'vendorcontact' => $contactId ? $vendor->getDisplayName() : $user->getDisplayName(),
+ ];
+ } else {
+ return trans("texts.invalid_activity");
+ }
+ return trans("texts.activity_{$activityTypeId}", $data);
+ }
+}
diff --git a/app/Ninja/Presenters/ExpensePresenter.php b/app/Ninja/Presenters/ExpensePresenter.php
new file mode 100644
index 000000000000..72da1cfef2f1
--- /dev/null
+++ b/app/Ninja/Presenters/ExpensePresenter.php
@@ -0,0 +1,17 @@
+entity->vendor ? $this->entity->vendor->getDisplayName() : '';
+ }
+
+ public function expense_date()
+ {
+ return Utils::fromSqlDate($this->entity->expense_date);
+ }
+}
\ No newline at end of file
diff --git a/app/Ninja/Repositories/ExpenseRepository.php b/app/Ninja/Repositories/ExpenseRepository.php
new file mode 100644
index 000000000000..f585b740436b
--- /dev/null
+++ b/app/Ninja/Repositories/ExpenseRepository.php
@@ -0,0 +1,94 @@
+join('accounts', 'accounts.id', '=', 'expenses.account_id')
+ ->join('vendors', 'vendors.id', '=', 'expenses.vendor_id')
+ ->join('vendor_contacts', 'vendor_contacts.vendor_id', '=', 'vendors.id')
+ ->where('vendors.account_id', '=', \Auth::user()->account_id)
+ ->where('vendors.deleted_at', '=', null)
+ ->where('vendor_contacts.deleted_at', '=', null)
+ ->where('vendor_contacts.is_primary', '=', true)
+ ->select(
+ DB::raw('COALESCE(vendors.currency_id, accounts.currency_id) currency_id'),
+ DB::raw('COALESCE(vendors.country_id, accounts.country_id) country_id'),
+ 'expenses.public_id',
+ 'vendors.name as vendor_name',
+ 'vendors.public_id as vendor_public_id',
+ 'expenses.amount',
+ 'expenses.balance',
+ 'expenses.expense_date',
+ 'vendor_contacts.first_name',
+ 'vendor_contacts.last_name',
+ 'vendor_contacts.email',
+ 'expenses.private_notes',
+ 'expenses.deleted_at',
+ 'expenses.is_deleted'
+ );
+
+ if ($vendorPublicId) {
+ $query->where('vendors.public_id', '=', $vendorPublicId);
+ }
+
+ if (!\Session::get('show_trash:expense')) {
+ $query->where('expenses.deleted_at', '=', null);
+ }
+
+ if ($filter) {
+ $query->where(function ($query) use ($filter) {
+ $query->where('vendors.name', 'like', '%'.$filter.'%');
+ });
+ }
+
+ return $query;
+ }
+
+ public function save($input)
+ {
+ $publicId = isset($input['public_id']) ? $input['public_id'] : false;
+
+ if ($publicId) {
+ $expense = Expense::scope($publicId)->firstOrFail();
+ } else {
+ $expense = Expense::createNew();
+ }
+
+ // First auto fille
+ $expense->fill($input);
+
+ // We can have an expense without a vendor
+ if(isset($input['vendor'])) {
+ $expense->vendor_id = Vendor::getPrivateId($input['vendor']);
+ }
+
+ $expense->expense_date = Utils::toSqlDate($input['expense_date']);
+ $expense->amount = Utils::parseFloat($input['amount']);
+
+ if(isset($input['amountcur']))
+ $expense->amountcur = Utils::parseFloat($input['amountcur']);
+
+ $expense->balance = Utils::parseFloat($input['amount']);
+ $expense->private_notes = trim($input['private_notes']);
+
+ if(isset($input['exchange_rate']))
+ $expense->exchange_rate = Utils::parseFloat($input['exchange_rate']);
+
+ $expense->save();
+
+ return $expense;
+ }
+}
diff --git a/app/Ninja/Transformers/VendorContactTransformer.php b/app/Ninja/Transformers/VendorContactTransformer.php
new file mode 100644
index 000000000000..9a34ac740289
--- /dev/null
+++ b/app/Ninja/Transformers/VendorContactTransformer.php
@@ -0,0 +1,24 @@
+ (int) $contact->public_id,
+ 'first_name' => $contact->first_name,
+ 'last_name' => $contact->last_name,
+ 'email' => $contact->email,
+ 'updated_at' => $this->getTimestamp($contact->updated_at),
+ 'archived_at' => $this->getTimestamp($contact->deleted_at),
+ 'is_primary' => (bool) $contact->is_primary,
+ 'phone' => $contact->phone,
+ 'last_login' => $contact->last_login,
+ 'account_key' => $this->account->account_key,
+ ];
+ }
+}
\ No newline at end of file
diff --git a/app/Ninja/Transformers/VendorTransformer.php b/app/Ninja/Transformers/VendorTransformer.php
new file mode 100644
index 000000000000..3ef965a15b97
--- /dev/null
+++ b/app/Ninja/Transformers/VendorTransformer.php
@@ -0,0 +1,91 @@
+account, $this->serializer);
+ return $this->includeCollection($vendor->contacts, $transformer, ENTITY_CONTACT);
+ }
+
+ public function includeInvoices(Vendor $vendor)
+ {
+ $transformer = new InvoiceTransformer($this->account, $this->serializer);
+ return $this->includeCollection($vendor->invoices, $transformer, ENTITY_INVOICE);
+ }
+
+ public function transform(Vendor $vendor)
+ {
+ return [
+ 'id' => (int) $vendor->public_id,
+ 'name' => $vendor->name,
+ 'balance' => (float) $vendor->balance,
+ 'paid_to_date' => (float) $vendor->paid_to_date,
+ 'user_id' => (int) $vendor->user->public_id + 1,
+ 'account_key' => $this->account->account_key,
+ 'updated_at' => $this->getTimestamp($vendor->updated_at),
+ 'archived_at' => $this->getTimestamp($vendor->deleted_at),
+ 'address1' => $vendor->address1,
+ 'address2' => $vendor->address2,
+ 'city' => $vendor->city,
+ 'state' => $vendor->state,
+ 'postal_code' => $vendor->postal_code,
+ 'country_id' => (int) $vendor->country_id,
+ 'work_phone' => $vendor->work_phone,
+ 'private_notes' => $vendor->private_notes,
+ 'last_login' => $vendor->last_login,
+ 'website' => $vendor->website,
+ 'industry_id' => (int) $vendor->industry_id,
+ 'size_id' => (int) $vendor->size_id,
+ 'is_deleted' => (bool) $vendor->is_deleted,
+ 'payment_terms' => (int) $vendor->payment_terms,
+ 'vat_number' => $vendor->vat_number,
+ 'id_number' => $vendor->id_number,
+ 'language_id' => (int) $vendor->language_id,
+ 'currency_id' => (int) $vendor->currency_id
+ ];
+ }
+}
\ No newline at end of file
diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php
index def84e1fdddd..dbdfe9b7395b 100644
--- a/app/Providers/EventServiceProvider.php
+++ b/app/Providers/EventServiceProvider.php
@@ -151,6 +151,21 @@ class EventServiceProvider extends ServiceProvider {
'App\Events\VendorWasRestored' => [
'App\Listeners\VendorActivityListener@restoredVendor',
],
+
+ // Expense events
+ 'App\Events\ExpenseWasCreated' => [
+ 'App\Listeners\ExpenseActivityListener@createdExpense',
+ 'App\Listeners\SubscriptionListener@createdExpense',
+ ],
+ 'App\Events\ExpenseWasArchived' => [
+ 'App\Listeners\ExpenseActivityListener@archivedExpense',
+ ],
+ 'App\Events\ExpenseWasDeleted' => [
+ 'App\Listeners\ExpenseActivityListener@deletedExpense',
+ ],
+ 'App\Events\ExpenseWasRestored' => [
+ 'App\Listeners\ExpenseActivityListener@restoredExpense',
+ ],
];
diff --git a/app/Services/ExpenseService.php b/app/Services/ExpenseService.php
new file mode 100644
index 000000000000..fb6333622315
--- /dev/null
+++ b/app/Services/ExpenseService.php
@@ -0,0 +1,84 @@
+expenseRepo = $expenseRepo;
+ $this->datatableService = $datatableService;
+ }
+
+ protected function getRepo()
+ {
+ return $this->expenseRepo;
+ }
+
+ public function save($data)
+ {
+ return $this->expenseRepo->save($data);
+ }
+
+ public function getDatatable($vendorPublicId, $search)
+ {
+ $query = $this->expenseRepo->find($vendorPublicId, $search);
+
+ return $this->createDatatable(ENTITY_CREDIT, $query, !$vendorPublicId);
+ }
+
+ protected function getDatatableColumns($entityType, $hideClient)
+ {
+ return [
+ [
+ 'vendor_name',
+ function ($model) {
+ return $model->vendor_public_id ? link_to("vendors/{$model->vendor_public_id}", Utils::getVendorDisplayName($model)) : '';
+ },
+ ! $hideClient
+ ],
+ [
+ 'amount',
+ function ($model) {
+ return Utils::formatMoney($model->amount, $model->currency_id, $model->country_id) . '';
+ }
+ ],
+ [
+ 'balance',
+ function ($model) {
+ return Utils::formatMoney($model->balance, $model->currency_id, $model->country_id);
+ }
+ ],
+ [
+ 'expense_date',
+ function ($model) {
+ return Utils::fromSqlDate($model->expense_date);
+ }
+ ],
+ [
+ 'private_notes',
+ function ($model) {
+ return $model->private_notes;
+ }
+ ]
+ ];
+ }
+
+ protected function getDatatableActions($entityType)
+ {
+ return [
+ [
+ trans('texts.apply_expense'),
+ function ($model) {
+ return URL::to("espense/create/{$model->vendor_public_id}") . '?paymentTypeId=1';
+ }
+ ]
+ ];
+ }
+}
\ No newline at end of file
diff --git a/database/migrations/2016_01_06_155001_create_expenses_table.php b/database/migrations/2016_01_06_155001_create_expenses_table.php
new file mode 100644
index 000000000000..12dc669203f4
--- /dev/null
+++ b/database/migrations/2016_01_06_155001_create_expenses_table.php
@@ -0,0 +1,56 @@
+increments('id');
+ $table->timestamps();
+
+ $table->unsignedInteger('account_id')->index();
+ $table->unsignedInteger('vendor_id')->nullable();
+ $table->unsignedInteger('user_id');
+
+ $table->softDeletes();
+
+ $table->boolean('is_deleted')->default(false);
+ $table->decimal('amount', 13, 2);
+ $table->decimal('amountcur', 13, 2);
+ $table->decimal('exchange_rate', 13, 2);
+ $table->decimal('balance', 13, 2);
+ $table->date('expense_date')->nullable();
+ $table->string('expense_number')->nullable();
+ $table->text('private_notes');
+ $table->integer('currency_id',false, true)->nullable();
+ $table->boolean('is_invoiced')->default(false);
+ $table->boolean('should_be_invoiced')->default(true);
+
+ $table->foreign('account_id')->references('id')->on('accounts')->onDelete('cascade');
+ $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');;
+
+ $table->unsignedInteger('public_id')->index();
+ $table->unique( array('account_id','public_id') );
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::drop('expenses');
+ }
+}
diff --git a/public/js/built.js b/public/js/built.js
index 6c00fbe7cbbe..b3186d0b7aef 100644
--- a/public/js/built.js
+++ b/public/js/built.js
@@ -30298,6 +30298,17 @@ function getClientDisplayName(client)
return '';
}
+function getVendorDisplayName(vendor)
+{
+ var contact = vendor.contacts ? vendor.vendorcontacts[0] : false;
+ if (vendor.name) {
+ return vendor.name;
+ } else if (contact) {
+ return getContactDisplayName(contact);
+ }
+ return '';
+}
+
function populateInvoiceComboboxes(clientId, invoiceId) {
var clientMap = {};
var invoiceMap = {};
diff --git a/resources/lang/en/texts.php b/resources/lang/en/texts.php
index dbed40c5fa3c..9687bf330869 100644
--- a/resources/lang/en/texts.php
+++ b/resources/lang/en/texts.php
@@ -893,6 +893,13 @@ return array(
'activity_28' => ':user restored :credit credit',
'activity_29' => ':contact approved quote :quote',
'activity_30' => ':user created :vendor',
+ 'activity_31' => ':user created :vendor',
+ 'activity_32' => ':user created :vendor',
+ 'activity_33' => ':user created :vendor',
+ 'activity_34' => ':user created :vendor',
+ 'activity_35' => ':user created :vendor',
+ 'activity_36' => ':user created :vendor',
+ 'activity_37' => ':user created :vendor',
'payment' => 'Payment',
'system' => 'System',
@@ -1018,4 +1025,9 @@ return array(
'archive_vendor' => 'Archive vendor',
'delete_vendor' => 'Delete vendor',
'view_vendor' => 'View vendor',
+
+ // Expenses
+ 'expense_amount' => 'Expense amount',
+ 'expense_balance' => 'Expense balance',
+ 'expense_date' => 'Expense date',
);