akaunting 3.0 (the last dance)
This commit is contained in:
@ -2,16 +2,15 @@
|
||||
|
||||
namespace App\Models\Auth;
|
||||
|
||||
use Akaunting\Sortable\Traits\Sortable;
|
||||
use App\Traits\Tenants;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Laratrust\Models\LaratrustPermission;
|
||||
use Laratrust\Traits\LaratrustPermissionTrait;
|
||||
use Kyslik\ColumnSortable\Sortable;
|
||||
use Lorisleiva\LaravelSearchString\Concerns\SearchString;
|
||||
|
||||
class Permission extends LaratrustPermission
|
||||
{
|
||||
use HasFactory, LaratrustPermissionTrait, SearchString, Sortable, Tenants;
|
||||
use LaratrustPermissionTrait, SearchString, Sortable, Tenants;
|
||||
|
||||
protected $table = 'permissions';
|
||||
|
||||
@ -79,14 +78,4 @@ class Permission extends LaratrustPermission
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory instance for the model.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Factories\Factory
|
||||
*/
|
||||
protected static function newFactory()
|
||||
{
|
||||
return \Database\Factories\Permission::new();
|
||||
}
|
||||
}
|
||||
|
@ -2,16 +2,15 @@
|
||||
|
||||
namespace App\Models\Auth;
|
||||
|
||||
use Akaunting\Sortable\Traits\Sortable;
|
||||
use App\Traits\Tenants;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Laratrust\Models\LaratrustRole;
|
||||
use Laratrust\Traits\LaratrustRoleTrait;
|
||||
use Kyslik\ColumnSortable\Sortable;
|
||||
use Lorisleiva\LaravelSearchString\Concerns\SearchString;
|
||||
|
||||
class Role extends LaratrustRole
|
||||
{
|
||||
use HasFactory, LaratrustRoleTrait, SearchString, Sortable, Tenants;
|
||||
use LaratrustRoleTrait, SearchString, Sortable, Tenants;
|
||||
|
||||
protected $table = 'roles';
|
||||
|
||||
@ -22,6 +21,40 @@ class Role extends LaratrustRole
|
||||
*/
|
||||
protected $fillable = ['name', 'display_name', 'description', 'created_from', 'created_by'];
|
||||
|
||||
/**
|
||||
* Get the line actions.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLineActionsAttribute()
|
||||
{
|
||||
$actions = [];
|
||||
|
||||
$actions[] = [
|
||||
'title' => trans('general.edit'),
|
||||
'icon' => 'edit',
|
||||
'url' => route('roles.roles.edit', $this->id),
|
||||
'permission' => 'update-roles-roles',
|
||||
];
|
||||
|
||||
$actions[] = [
|
||||
'title' => trans('general.duplicate'),
|
||||
'icon' => 'file_copy',
|
||||
'url' => route('roles.roles.duplicate', $this->id),
|
||||
'permission' => 'create-roles-roles',
|
||||
];
|
||||
|
||||
$actions[] = [
|
||||
'type' => 'delete',
|
||||
'icon' => 'delete',
|
||||
'route' => 'roles.roles.destroy',
|
||||
'permission' => 'delete-roles-roles',
|
||||
'model' => $this,
|
||||
];
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope to get all rows filtered, sorted and paginated.
|
||||
*
|
||||
@ -39,14 +72,4 @@ class Role extends LaratrustRole
|
||||
|
||||
return $query->usingSearchString($search)->sortable($sort)->paginate($limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory instance for the model.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Factories\Factory
|
||||
*/
|
||||
protected static function newFactory()
|
||||
{
|
||||
return \Database\Factories\Role::new();
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,12 @@
|
||||
|
||||
namespace App\Models\Auth;
|
||||
|
||||
use App\Traits\Tenants;
|
||||
use Akaunting\Sortable\Traits\Sortable;
|
||||
use App\Notifications\Auth\Reset;
|
||||
use App\Traits\Media;
|
||||
use App\Traits\Owners;
|
||||
use App\Traits\Sources;
|
||||
use App\Traits\Tenants;
|
||||
use App\Traits\Users;
|
||||
use App\Utilities\Date;
|
||||
use Illuminate\Contracts\Translation\HasLocalePreference;
|
||||
@ -14,7 +15,6 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Kyslik\ColumnSortable\Sortable;
|
||||
use Laratrust\Traits\LaratrustUserTrait;
|
||||
use Lorisleiva\LaravelSearchString\Concerns\SearchString;
|
||||
|
||||
@ -65,11 +65,11 @@ class User extends Authenticatable implements HasLocalePreference
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::retrieved(function($model) {
|
||||
static::retrieved(function ($model) {
|
||||
$model->setCompanyIds();
|
||||
});
|
||||
|
||||
static::saving(function($model) {
|
||||
static::saving(function ($model) {
|
||||
$model->unsetCompanyIds();
|
||||
});
|
||||
}
|
||||
@ -94,6 +94,10 @@ class User extends Authenticatable implements HasLocalePreference
|
||||
*/
|
||||
public function getNameAttribute($value)
|
||||
{
|
||||
if (empty($value)) {
|
||||
return trans('general.na');
|
||||
}
|
||||
|
||||
return ucfirst($value);
|
||||
}
|
||||
|
||||
@ -106,7 +110,7 @@ class User extends Authenticatable implements HasLocalePreference
|
||||
if (setting('default.use_gravatar', '0') == '1') {
|
||||
try {
|
||||
// Check for gravatar
|
||||
$url = 'https://www.gravatar.com/avatar/' . md5(strtolower($this->getAttribute('email'))).'?size=90&d=404';
|
||||
$url = 'https://www.gravatar.com/avatar/' . md5(strtolower($this->getAttribute('email'))) . '?size=90&d=404';
|
||||
|
||||
$client = new \GuzzleHttp\Client(['verify' => false]);
|
||||
|
||||
@ -141,14 +145,6 @@ class User extends Authenticatable implements HasLocalePreference
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send reset link to user via email
|
||||
*/
|
||||
public function sendPasswordResetNotification($token)
|
||||
{
|
||||
$this->notify(new Reset($token));
|
||||
}
|
||||
|
||||
/**
|
||||
* Always capitalize the name when we save it to the database
|
||||
*/
|
||||
@ -165,6 +161,14 @@ class User extends Authenticatable implements HasLocalePreference
|
||||
$this->attributes['password'] = bcrypt($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send reset link to user via email
|
||||
*/
|
||||
public function sendPasswordResetNotification($token)
|
||||
{
|
||||
$this->notify(new Reset($token));
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope to get all rows filtered, sorted and paginated.
|
||||
*
|
||||
@ -294,6 +298,48 @@ class User extends Authenticatable implements HasLocalePreference
|
||||
return $this->locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the line actions.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLineActionsAttribute()
|
||||
{
|
||||
$actions = [];
|
||||
|
||||
if (user()->id == $this->id) {
|
||||
return $actions;
|
||||
}
|
||||
|
||||
if (! $this->hasPendingInvitation()) {
|
||||
$actions[] = [
|
||||
'title' => trans('general.edit'),
|
||||
'icon' => 'edit',
|
||||
'url' => route('users.edit', $this->id),
|
||||
'permission' => 'update-auth-users',
|
||||
];
|
||||
}
|
||||
|
||||
if ($this->hasPendingInvitation()) {
|
||||
$actions[] = [
|
||||
'title' => trans('general.resend') . ' ' . trans_choice('general.invitations', 1),
|
||||
'icon' => 'replay',
|
||||
'url' => route('users.invite', $this->id),
|
||||
'permission' => 'update-auth-users',
|
||||
];
|
||||
}
|
||||
|
||||
$actions[] = [
|
||||
'type' => 'delete',
|
||||
'icon' => 'delete',
|
||||
'route' => 'users.destroy',
|
||||
'permission' => 'delete-auth-users',
|
||||
'model' => $this,
|
||||
];
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory instance for the model.
|
||||
*
|
||||
|
40
app/Models/Auth/UserInvitation.php
Normal file
40
app/Models/Auth/UserInvitation.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Auth;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
|
||||
class UserInvitation extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'user_invitations';
|
||||
|
||||
protected $tenantable = false;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected $fillable = ['user_id', 'company_id', 'token'];
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Auth\User');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope a query to only include given token value.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return void
|
||||
*/
|
||||
public function scopeToken($query, $token)
|
||||
{
|
||||
$query->where('token', $token);
|
||||
}
|
||||
}
|
@ -4,8 +4,8 @@ namespace App\Models\Banking;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Traits\Transactions;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Bkwld\Cloner\Cloneable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
||||
class Account extends Model
|
||||
{
|
||||
@ -25,7 +25,7 @@ class Account extends Model
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['company_id', 'name', 'number', 'currency_code', 'opening_balance', 'bank_name', 'bank_phone', 'bank_address', 'enabled', 'created_from', 'created_by'];
|
||||
protected $fillable = ['company_id', 'type', 'name', 'number', 'currency_code', 'opening_balance', 'bank_name', 'bank_phone', 'bank_address', 'enabled', 'created_from', 'created_by'];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
@ -42,7 +42,7 @@ class Account extends Model
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $sortable = ['name', 'number', 'opening_balance', 'enabled'];
|
||||
public $sortable = ['name', 'number', 'balance', 'bank_name', 'bank_phone'];
|
||||
|
||||
public function currency()
|
||||
{
|
||||
@ -74,6 +74,21 @@ class Account extends Model
|
||||
return $query->where('number', '=', $number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by balance
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param $direction
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function balanceSortable($query, $direction)
|
||||
{
|
||||
return $query//->join('transactions', 'transactions.account_id', '=', 'accounts.id')
|
||||
->orderBy('balance', $direction)
|
||||
->select(['accounts.*', 'accounts.opening_balance as balance']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current balance.
|
||||
*
|
||||
@ -127,6 +142,39 @@ class Account extends Model
|
||||
return $total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the line actions.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLineActionsAttribute()
|
||||
{
|
||||
$actions = [];
|
||||
|
||||
$actions[] = [
|
||||
'title' => trans('general.show'),
|
||||
'icon' => 'visibility',
|
||||
'url' => route('accounts.show', $this->id),
|
||||
'permission' => 'read-banking-accounts',
|
||||
];
|
||||
|
||||
$actions[] = [
|
||||
'title' => trans('general.edit'),
|
||||
'icon' => 'edit',
|
||||
'url' => route('accounts.edit', $this->id),
|
||||
'permission' => 'update-banking-accounts',
|
||||
];
|
||||
|
||||
$actions[] = [
|
||||
'type' => 'delete',
|
||||
'icon' => 'delete',
|
||||
'route' => 'accounts.destroy',
|
||||
'permission' => 'delete-banking-accounts',
|
||||
'model' => $this,
|
||||
];
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory instance for the model.
|
||||
|
@ -42,6 +42,33 @@ class Reconciliation extends Model
|
||||
return $this->belongsTo('App\Models\Banking\Account');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the line actions.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLineActionsAttribute()
|
||||
{
|
||||
$actions = [];
|
||||
|
||||
$actions[] = [
|
||||
'title' => trans('general.edit'),
|
||||
'icon' => 'edit',
|
||||
'url' => route('reconciliations.edit', $this->id),
|
||||
'permission' => 'update-banking-reconciliations',
|
||||
];
|
||||
|
||||
$actions[] = [
|
||||
'type' => 'delete',
|
||||
'icon' => 'delete',
|
||||
'route' => 'reconciliations.destroy',
|
||||
'permission' => 'delete-banking-reconciliations',
|
||||
'model' => $this,
|
||||
];
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory instance for the model.
|
||||
*
|
||||
|
@ -12,6 +12,7 @@ use App\Traits\Media;
|
||||
use App\Traits\Recurring;
|
||||
use App\Traits\Transactions;
|
||||
use Bkwld\Cloner\Cloneable;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
@ -19,6 +20,13 @@ class Transaction extends Model
|
||||
{
|
||||
use Cloneable, Currencies, DateTime, HasFactory, Media, Recurring, Transactions;
|
||||
|
||||
public const INCOME_TYPE = 'income';
|
||||
public const INCOME_SPLIT_TYPE = 'income-split';
|
||||
public const INCOME_RECURRING_TYPE = 'income-recurring';
|
||||
public const EXPENSE_TYPE = 'expense';
|
||||
public const EXPENSE_SPLIT_TYPE = 'expense-split';
|
||||
public const EXPENSE_RECURRING_TYPE = 'expense-recurring';
|
||||
|
||||
protected $table = 'transactions';
|
||||
|
||||
protected $dates = ['deleted_at', 'paid_at'];
|
||||
@ -31,6 +39,7 @@ class Transaction extends Model
|
||||
protected $fillable = [
|
||||
'company_id',
|
||||
'type',
|
||||
'number',
|
||||
'account_id',
|
||||
'paid_at',
|
||||
'amount',
|
||||
@ -43,6 +52,7 @@ class Transaction extends Model
|
||||
'payment_method',
|
||||
'reference',
|
||||
'parent_id',
|
||||
'split_id',
|
||||
'created_from',
|
||||
'created_by',
|
||||
];
|
||||
@ -62,7 +72,7 @@ class Transaction extends Model
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $sortable = ['paid_at', 'amount','category.name', 'account.name'];
|
||||
public $sortable = ['type', 'number', 'paid_at', 'amount','category.name', 'account.name', 'customer.name', 'invoice.document_number'];
|
||||
|
||||
/**
|
||||
* Clonable relationships.
|
||||
@ -96,6 +106,11 @@ class Transaction extends Model
|
||||
return $this->belongsTo('App\Models\Setting\Category')->withDefault(['name' => trans('general.na')]);
|
||||
}
|
||||
|
||||
public function children()
|
||||
{
|
||||
return $this->hasMany('App\Models\Banking\Transaction', 'parent_id');
|
||||
}
|
||||
|
||||
public function contact()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Common\Contact')->withDefault(['name' => trans('general.na')]);
|
||||
@ -116,29 +131,27 @@ class Transaction extends Model
|
||||
return $this->belongsTo('App\Models\Document\Document', 'document_id');
|
||||
}
|
||||
|
||||
public function parent()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Banking\Transaction', 'parent_id');
|
||||
}
|
||||
|
||||
public function recurring()
|
||||
{
|
||||
return $this->morphOne('App\Models\Common\Recurring', 'recurable');
|
||||
}
|
||||
|
||||
public function splits()
|
||||
{
|
||||
return $this->hasMany('App\Models\Banking\Transaction', 'split_id');
|
||||
}
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Auth\User', 'contact_id', 'id');
|
||||
}
|
||||
|
||||
public function parent()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Banking\Transaction', 'parent_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope to only include contacts of a given type.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param mixed $types
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeType($query, $types)
|
||||
public function scopeType(Builder $query, $types): Builder
|
||||
{
|
||||
if (empty($types)) {
|
||||
return $query;
|
||||
@ -147,167 +160,110 @@ class Transaction extends Model
|
||||
return $query->whereIn($this->qualifyColumn('type'), (array) $types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope to include only income.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeIncome($query)
|
||||
public function scopeIncome(Builder $query): Builder
|
||||
{
|
||||
return $query->whereIn($this->qualifyColumn('type'), (array) $this->getIncomeTypes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope to include only expense.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeExpense($query)
|
||||
public function scopeIncomeRecurring(Builder $query): Builder
|
||||
{
|
||||
return $query->where($this->qualifyColumn('type'), '=', self::INCOME_RECURRING_TYPE);
|
||||
}
|
||||
|
||||
public function scopeExpense(Builder $query): Builder
|
||||
{
|
||||
return $query->whereIn($this->qualifyColumn('type'), (array) $this->getExpenseTypes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get only transfers.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeIsTransfer($query)
|
||||
public function scopeExpenseRecurring(Builder $query): Builder
|
||||
{
|
||||
return $query->where($this->qualifyColumn('type'), '=', self::EXPENSE_RECURRING_TYPE);
|
||||
}
|
||||
|
||||
public function scopeIsRecurring(Builder $query): Builder
|
||||
{
|
||||
return $query->where($this->qualifyColumn('type'), 'like', '%-recurring');
|
||||
}
|
||||
|
||||
public function scopeIsNotRecurring(Builder $query): Builder
|
||||
{
|
||||
return $query->where($this->qualifyColumn('type'), 'not like', '%-recurring');
|
||||
}
|
||||
|
||||
public function scopeIsTransfer(Builder $query): Builder
|
||||
{
|
||||
return $query->where('category_id', '=', Category::transfer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip transfers.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeIsNotTransfer($query)
|
||||
public function scopeIsNotTransfer(Builder $query): Builder
|
||||
{
|
||||
return $query->where('category_id', '<>', Category::transfer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get only documents (invoice/bill).
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeIsDocument($query)
|
||||
public function scopeIsDocument(Builder $query): Builder
|
||||
{
|
||||
return $query->whereNotNull('document_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get only transactions (revenue/payment).
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeIsNotDocument($query)
|
||||
public function scopeIsNotDocument(Builder $query): Builder
|
||||
{
|
||||
return $query->whereNull('document_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get by document id.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param integer $document_id
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeDocumentId($query, $document_id)
|
||||
public function scopeDocumentId(Builder $query, int $document_id): Builder
|
||||
{
|
||||
return $query->where('document_id', '=', $document_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get by account id.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param integer $account_id
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeAccountId($query, $account_id)
|
||||
public function scopeAccountId(Builder $query, int $account_id): Builder
|
||||
{
|
||||
return $query->where('account_id', '=', $account_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get by contact id.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param integer $contact_id
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeContactId($query, $contact_id)
|
||||
public function scopeContactId(Builder $query, int $contact_id): Builder
|
||||
{
|
||||
return $query->where('contact_id', '=', $contact_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get by category id.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param integer $category_id
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeCategoryId($query, $category_id)
|
||||
public function scopeCategoryId(Builder $query, int $category_id): Builder
|
||||
{
|
||||
return $query->where('category_id', '=', $category_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Order by paid date.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeLatest($query)
|
||||
public function scopeLatest(Builder $query): Builder
|
||||
{
|
||||
return $query->orderBy('paid_at', 'desc');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope paid invoice.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopePaid($query)
|
||||
public function scopePaid(Builder $query): Builder
|
||||
{
|
||||
return $query->sum('amount');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get only reconciled.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeIsReconciled($query)
|
||||
public function scopeIsReconciled(Builder $query): Builder
|
||||
{
|
||||
return $query->where('reconciled', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get only not reconciled.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeIsNotReconciled($query)
|
||||
public function scopeIsNotReconciled(Builder $query): Builder
|
||||
{
|
||||
return $query->where('reconciled', 0);
|
||||
}
|
||||
|
||||
public function onCloning($src, $child = null)
|
||||
{
|
||||
$this->document_id = null;
|
||||
if (app()->has(\App\Console\Commands\RecurringCheck::class)) {
|
||||
$suffix = '';
|
||||
} else {
|
||||
$suffix = $src->isRecurringTransaction() ? '-recurring' : '';
|
||||
}
|
||||
|
||||
$this->number = $this->getNextTransactionNumber($suffix);
|
||||
$this->document_id = null;
|
||||
$this->split_id = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -346,6 +302,16 @@ class Transaction extends Model
|
||||
return $this->getMedia('attachment')->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the splittable status.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getIsSplittableAttribute()
|
||||
{
|
||||
return is_null($this->split_id);
|
||||
}
|
||||
|
||||
public function delete_attachment()
|
||||
{
|
||||
if ($attachments = $this->attachment) {
|
||||
@ -362,7 +328,7 @@ class Transaction extends Model
|
||||
*/
|
||||
public function getHasTransferRelationAttribute()
|
||||
{
|
||||
return (bool) (optional($this->category)->id == optional($this->category)->transfer());
|
||||
return (bool) ($this->category?->id == $this->category?->transfer());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -372,7 +338,9 @@ class Transaction extends Model
|
||||
*/
|
||||
public function getTypeTitleAttribute($value)
|
||||
{
|
||||
return $value ?? trans_choice('general.' . Str::plural($this->type), 1);
|
||||
$type = $this->getRealTypeOfRecurringTransaction($this->type);
|
||||
|
||||
return $value ?? trans_choice('general.' . Str::plural($type), 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -387,18 +355,18 @@ class Transaction extends Model
|
||||
}
|
||||
|
||||
if ($this->isIncome()) {
|
||||
if (! empty($this->document) && $this->document->type != 'invoice') {
|
||||
if (! empty($this->document_id) && $this->document->type != 'invoice') {
|
||||
return $this->getRouteFromConfig();
|
||||
} else {
|
||||
return ! empty($this->document_id) ? 'invoices.show' : 'revenues.show';
|
||||
return !empty($this->document_id) ? 'invoices.show' : 'transactions.show';
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isExpense()) {
|
||||
if (! empty($this->document) && $this->document->type != 'bill') {
|
||||
if (! empty($this->document_id) && $this->document->type != 'bill') {
|
||||
return $this->getRouteFromConfig();
|
||||
} else {
|
||||
return ! empty($this->document_id) ? 'bills.show' : 'payments.show';
|
||||
return !empty($this->document_id) ? 'bills.show' : 'transactions.show';
|
||||
}
|
||||
}
|
||||
|
||||
@ -409,8 +377,8 @@ class Transaction extends Model
|
||||
{
|
||||
$route = '';
|
||||
|
||||
$alias = config('type.' . $this->document->type . '.alias');
|
||||
$prefix = config('type.' . $this->document->type . '.route.prefix');
|
||||
$alias = config('type.document.' . $this->document->type . '.alias');
|
||||
$prefix = config('type.document.' . $this->document->type . '.route.prefix');
|
||||
|
||||
// if use module set module alias
|
||||
if (!empty($alias)) {
|
||||
@ -438,10 +406,195 @@ class Transaction extends Model
|
||||
return !empty($value) ? $value : (!empty($this->document_id) ? $this->document_id : $this->id);
|
||||
}
|
||||
|
||||
public function getTemplatePathAttribute($value = null)
|
||||
/**
|
||||
* Get the line actions.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLineActionsAttribute()
|
||||
{
|
||||
$type_for_theme = ($this->type == 'income') ? 'sales.revenues.print_default' : 'purchases.payments.print_default';
|
||||
return $value ?: $type_for_theme;
|
||||
$actions = [];
|
||||
|
||||
$prefix = 'transactions';
|
||||
|
||||
if (Str::contains($this->type, 'recurring')) {
|
||||
$prefix = 'recurring-transactions';
|
||||
}
|
||||
|
||||
try {
|
||||
$actions[] = [
|
||||
'title' => trans('general.show'),
|
||||
'icon' => 'visibility',
|
||||
'url' => route($prefix. '.show', $this->id),
|
||||
'permission' => 'read-banking-transactions',
|
||||
'attributes' => [
|
||||
'id' => 'index-more-actions-show-' . $this->id,
|
||||
],
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
try {
|
||||
if (! $this->reconciled) {
|
||||
$actions[] = [
|
||||
'title' => trans('general.edit'),
|
||||
'icon' => 'edit',
|
||||
'url' => route($prefix. '.edit', $this->id),
|
||||
'permission' => 'update-banking-transactions',
|
||||
'attributes' => [
|
||||
'id' => 'index-more-actions-edit-' . $this->id,
|
||||
],
|
||||
];
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
try {
|
||||
if (empty($this->document_id)) {
|
||||
$actions[] = [
|
||||
'title' => trans('general.duplicate'),
|
||||
'icon' => 'file_copy',
|
||||
'url' => route($prefix. '.duplicate', $this->id),
|
||||
'permission' => 'create-banking-transactions',
|
||||
'attributes' => [
|
||||
'id' => 'index-more-actions-duplicate-' . $this->id,
|
||||
],
|
||||
];
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
try {
|
||||
if ($this->is_splittable && empty($this->document_id) && empty($this->recurring)) {
|
||||
$conenct = [
|
||||
'type' => 'button',
|
||||
'title' => trans('general.connect'),
|
||||
'icon' => 'sensors',
|
||||
'permission' => 'create-banking-transactions',
|
||||
'attributes' => [
|
||||
'id' => 'index-transactions-more-actions-connect-' . $this->id,
|
||||
],
|
||||
];
|
||||
|
||||
$transaction = $this->load('account')->toJson();
|
||||
$currency = $this->currency->toJson();
|
||||
|
||||
if ($this->contact->exists) {
|
||||
$document = $this->contact->invoices()->notPaid()->where('currency_code', $this->currency_code)->with(['media', 'totals', 'transactions'])->get()->toJson();
|
||||
|
||||
$conenct['attributes']['@click'] = 'onConnect()';
|
||||
} else {
|
||||
$document = \App\Models\Document\Document::invoice()->notPaid()->where('currency_code', $this->currency_code)->with(['media', 'totals', 'transactions'])->get()->toJson();
|
||||
|
||||
$conenct['attributes']['@click'] = 'onConnect()';
|
||||
}
|
||||
|
||||
$actions[] = $conenct;
|
||||
|
||||
$actions[] = [
|
||||
'type' => 'divider',
|
||||
];
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
try {
|
||||
$actions[] = [
|
||||
'title' => trans('general.print'),
|
||||
'icon' => 'print',
|
||||
'url' => route($prefix. '.print', $this->id),
|
||||
'permission' => 'read-banking-transactions',
|
||||
'attributes' => [
|
||||
'id' => 'index-more-actions-print-' . $this->id,
|
||||
'target' => '_blank',
|
||||
],
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
try {
|
||||
$actions[] = [
|
||||
'title' => trans('general.download_pdf'),
|
||||
'icon' => 'pdf',
|
||||
'url' => route($prefix. '.pdf', $this->id),
|
||||
'permission' => 'read-banking-transactions',
|
||||
'attributes' => [
|
||||
'id' => 'index-more-actions-pdf-' . $this->id,
|
||||
'target' => '_blank',
|
||||
],
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
if ($prefix != 'recurring-transactions') {
|
||||
$actions[] = [
|
||||
'type' => 'divider',
|
||||
];
|
||||
|
||||
try {
|
||||
$actions[] = [
|
||||
'type' => 'button',
|
||||
'title' => trans('general.share_link'),
|
||||
'icon' => 'share',
|
||||
'url' => route('modals.transactions.share.create', $this->id),
|
||||
'permission' => 'read-banking-transactions',
|
||||
'attributes' => [
|
||||
'id' => 'index-more-actions-share-' . $this->id,
|
||||
'@click' => 'onShareLink("' . route('modals.transactions.share.create', $this->id) . '")',
|
||||
],
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
try {
|
||||
$actions[] = [
|
||||
'type' => 'button',
|
||||
'title' => trans('invoices.send_mail'),
|
||||
'icon' => 'email',
|
||||
'url' => route('modals.transactions.emails.create', $this->id),
|
||||
'permission' => 'read-banking-transactions',
|
||||
'attributes' => [
|
||||
'id' => 'index-more-actions-send-email-' . $this->id,
|
||||
'@click' => 'onEmail("' . route('modals.transactions.emails.create', $this->id) . '")',
|
||||
],
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
$actions[] = [
|
||||
'type' => 'divider',
|
||||
];
|
||||
|
||||
try {
|
||||
if (! $this->reconciled) {
|
||||
$actions[] = [
|
||||
'type' => 'delete',
|
||||
'icon' => 'delete',
|
||||
'text' => ! empty($this->recurring) ? 'transactions' : 'recurring_template',
|
||||
'route' => $prefix. '.destroy',
|
||||
'permission' => 'delete-banking-transactions',
|
||||
'model' => $this,
|
||||
];
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
} else {
|
||||
try {
|
||||
$actions[] = [
|
||||
'title' => trans('general.end'),
|
||||
'icon' => 'block',
|
||||
'url' => route($prefix. '.end', $this->id),
|
||||
'permission' => 'update-banking-transactions',
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the recurring status label.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRecurringStatusLabelAttribute()
|
||||
{
|
||||
return match($this->recurring->status) {
|
||||
'active' => 'status-partial',
|
||||
'ended' => 'status-success',
|
||||
default => 'status-success',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -224,6 +224,47 @@ class Transfer extends Model
|
||||
return $value ?: $this->expense_transaction->reference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the line actions.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLineActionsAttribute()
|
||||
{
|
||||
$actions = [];
|
||||
|
||||
$actions[] = [
|
||||
'title' => trans('general.show'),
|
||||
'icon' => 'visibility',
|
||||
'url' => route('transfers.show', $this->id),
|
||||
'permission' => 'read-banking-transfers',
|
||||
];
|
||||
|
||||
$actions[] = [
|
||||
'title' => trans('general.edit'),
|
||||
'icon' => 'edit',
|
||||
'url' => route('transfers.edit', $this->id),
|
||||
'permission' => 'update-banking-transfers',
|
||||
];
|
||||
|
||||
$actions[] = [
|
||||
'title' => trans('general.duplicate'),
|
||||
'icon' => 'file_copy',
|
||||
'url' => route('transfers.duplicate', $this->id),
|
||||
'permission' => 'update-banking-transfers',
|
||||
];
|
||||
|
||||
$actions[] = [
|
||||
'type' => 'delete',
|
||||
'icon' => 'delete',
|
||||
'route' => 'transfers.destroy',
|
||||
'permission' => 'delete-banking-transfers',
|
||||
'model' => $this,
|
||||
];
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory instance for the model.
|
||||
*
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Models\Common;
|
||||
|
||||
use Akaunting\Sortable\Traits\Sortable;
|
||||
use App\Events\Common\CompanyForgettingCurrent;
|
||||
use App\Events\Common\CompanyForgotCurrent;
|
||||
use App\Events\Common\CompanyMadeCurrent;
|
||||
@ -14,15 +15,15 @@ use App\Traits\Sources;
|
||||
use App\Traits\Tenants;
|
||||
use App\Traits\Transactions;
|
||||
use App\Utilities\Overrider;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model as Eloquent;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Kyslik\ColumnSortable\Sortable;
|
||||
use Laratrust\Contracts\Ownable;
|
||||
use Lorisleiva\LaravelSearchString\Concerns\SearchString;
|
||||
|
||||
class Company extends Eloquent implements Ownable
|
||||
{
|
||||
use Contacts, Media, Owners, SearchString, SoftDeletes, Sortable, Sources, Tenants, Transactions;
|
||||
use Contacts, HasFactory, Media, Owners, SearchString, SoftDeletes, Sortable, Sources, Tenants, Transactions;
|
||||
|
||||
protected $table = 'companies';
|
||||
|
||||
@ -48,33 +49,21 @@ class Company extends Eloquent implements Ownable
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $sortable = ['name', 'domain', 'email', 'enabled', 'created_at'];
|
||||
public $sortable = ['id', 'name', 'domain', 'email', 'enabled', 'created_at', 'tax_number', 'country', 'currency'];
|
||||
|
||||
/**
|
||||
* Create a new Eloquent model instance.
|
||||
* Fill the model with an array of attributes.
|
||||
*
|
||||
* @param array $attributes
|
||||
* @return void
|
||||
* @return $this
|
||||
*
|
||||
* @throws \Illuminate\Database\Eloquent\MassAssignmentException
|
||||
*/
|
||||
public function __construct(array $attributes = [])
|
||||
public function fill(array $attributes)
|
||||
{
|
||||
$this->allAttributes = $attributes;
|
||||
|
||||
parent::__construct($attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the model in the database.
|
||||
*
|
||||
* @param array $attributes
|
||||
* @param array $options
|
||||
* @return bool
|
||||
*/
|
||||
public function update(array $attributes = [], array $options = [])
|
||||
{
|
||||
$this->allAttributes = $attributes;
|
||||
|
||||
return parent::update($attributes, $options);
|
||||
return parent::fill($attributes);
|
||||
}
|
||||
|
||||
public static function boot()
|
||||
@ -90,7 +79,7 @@ class Company extends Eloquent implements Ownable
|
||||
$model->unsetCommonSettingsFromAttributes();
|
||||
});
|
||||
} catch(\Throwable $e) {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,7 +165,7 @@ class Company extends Eloquent implements Ownable
|
||||
|
||||
public function email_templates()
|
||||
{
|
||||
return $this->hasMany('App\Models\Common\EmailTemplate');
|
||||
return $this->hasMany('App\Models\Setting\EmailTemplate');
|
||||
}
|
||||
|
||||
public function expense_transactions()
|
||||
@ -298,7 +287,7 @@ class Company extends Eloquent implements Ownable
|
||||
list($group, $key) = explode('.', $setting->getAttribute('key'));
|
||||
|
||||
// Load only general settings
|
||||
if (!in_array($group, $groups)) {
|
||||
if (! in_array($group, $groups)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -315,8 +304,13 @@ class Company extends Eloquent implements Ownable
|
||||
if ($this->getAttribute('logo') == '') {
|
||||
$this->setAttribute('logo', 'public/img/company.png');
|
||||
}
|
||||
|
||||
// Set default default company currency if empty
|
||||
if ($this->getAttribute('currency') == '') {
|
||||
$this->setAttribute('currency', config('setting.fallback.default.currency'));
|
||||
}
|
||||
} catch(\Throwable $e) {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -334,7 +328,7 @@ class Company extends Eloquent implements Ownable
|
||||
list($group, $key) = explode('.', $setting->getAttribute('key'));
|
||||
|
||||
// Load only general settings
|
||||
if (!in_array($group, $groups)) {
|
||||
if (! in_array($group, $groups)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -343,7 +337,7 @@ class Company extends Eloquent implements Ownable
|
||||
|
||||
$this->offsetUnset('logo');
|
||||
} catch(\Throwable $e) {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -430,6 +424,54 @@ class Company extends Eloquent implements Ownable
|
||||
->select('companies.*');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by company tax number
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param $direction
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function taxNumberSortable($query, $direction)
|
||||
{
|
||||
return $query->join('settings', 'companies.id', '=', 'settings.company_id')
|
||||
->where('key', 'company.tax_number')
|
||||
->orderBy('value', $direction)
|
||||
->select('companies.*');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by company country
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param $direction
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function countrySortable($query, $direction)
|
||||
{
|
||||
return $query->join('settings', 'companies.id', '=', 'settings.company_id')
|
||||
->where('key', 'company.country')
|
||||
->orderBy('value', $direction)
|
||||
->select('companies.*');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort by company currency
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param $direction
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function currencySortable($query, $direction)
|
||||
{
|
||||
return $query->join('settings', 'companies.id', '=', 'settings.company_id')
|
||||
->where('key', 'default.currency')
|
||||
->orderBy('value', $direction)
|
||||
->select('companies.*');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope autocomplete.
|
||||
*
|
||||
@ -489,6 +531,42 @@ class Company extends Eloquent implements Ownable
|
||||
return implode(', ', $location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the line actions.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLineActionsAttribute()
|
||||
{
|
||||
$actions = [];
|
||||
|
||||
if ($this->enabled) {
|
||||
$actions[] = [
|
||||
'title' => trans('general.switch'),
|
||||
'icon' => 'settings_ethernet',
|
||||
'url' => route('companies.switch', $this->id),
|
||||
'permission' => 'read-common-companies',
|
||||
];
|
||||
}
|
||||
|
||||
$actions[] = [
|
||||
'title' => trans('general.edit'),
|
||||
'icon' => 'edit',
|
||||
'url' => route('companies.edit', $this->id),
|
||||
'permission' => 'update-common-companies',
|
||||
];
|
||||
|
||||
$actions[] = [
|
||||
'type' => 'delete',
|
||||
'icon' => 'delete',
|
||||
'route' => 'companies.destroy',
|
||||
'permission' => 'delete-common-companies',
|
||||
'model' => $this,
|
||||
];
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
public function makeCurrent($force = false)
|
||||
{
|
||||
if (!$force && $this->isCurrent()) {
|
||||
@ -502,9 +580,6 @@ class Company extends Eloquent implements Ownable
|
||||
// Bind to container
|
||||
app()->instance(static::class, $this);
|
||||
|
||||
// Set session for backward compatibility @deprecated
|
||||
//session(['company_id' => $this->id]);
|
||||
|
||||
// Load settings
|
||||
setting()->setExtraColumns(['company_id' => $this->id]);
|
||||
setting()->forgetAll();
|
||||
@ -521,7 +596,7 @@ class Company extends Eloquent implements Ownable
|
||||
|
||||
public function isCurrent()
|
||||
{
|
||||
return optional(static::getCurrent())->id === $this->id;
|
||||
return static::getCurrent()?->id === $this->id;
|
||||
}
|
||||
|
||||
public function isNotCurrent()
|
||||
@ -551,9 +626,6 @@ class Company extends Eloquent implements Ownable
|
||||
// Remove from container
|
||||
app()->forgetInstance(static::class);
|
||||
|
||||
// Unset session for backward compatibility @deprecated
|
||||
//session()->forget('company_id');
|
||||
|
||||
// Remove settings
|
||||
setting()->forgetAll();
|
||||
|
||||
@ -590,4 +662,14 @@ class Company extends Eloquent implements Ownable
|
||||
|
||||
return $this->created_by;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory instance for the model.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Factories\Factory
|
||||
*/
|
||||
protected static function newFactory()
|
||||
{
|
||||
return \Database\Factories\Company::new();
|
||||
}
|
||||
}
|
||||
|
@ -2,21 +2,28 @@
|
||||
|
||||
namespace App\Models\Common;
|
||||
|
||||
use App\Traits\Media;
|
||||
use App\Abstracts\Model;
|
||||
use App\Models\Document\Document;
|
||||
use App\Scopes\Contact as Scope;
|
||||
use App\Traits\Contacts;
|
||||
use App\Traits\Currencies;
|
||||
use App\Traits\Media;
|
||||
use App\Traits\Transactions;
|
||||
use App\Scopes\Contact as Scope;
|
||||
use App\Models\Document\Document;
|
||||
use App\Utilities\Date;
|
||||
use App\Utilities\Str;
|
||||
use Bkwld\Cloner\Cloneable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
|
||||
|
||||
class Contact extends Model
|
||||
{
|
||||
use Cloneable, Contacts, Currencies, HasFactory, Media, Notifiable, Transactions;
|
||||
|
||||
public const CUSTOMER_TYPE = 'customer';
|
||||
public const VENDOR_TYPE = 'vendor';
|
||||
public const EMPLOYEE_TYPE = 'employee';
|
||||
|
||||
protected $table = 'contacts';
|
||||
|
||||
/**
|
||||
@ -169,6 +176,11 @@ class Contact extends Model
|
||||
$this->user_id = null;
|
||||
}
|
||||
|
||||
public function getInitialsAttribute($value)
|
||||
{
|
||||
return Str::getInitials($this->name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current balance.
|
||||
*
|
||||
@ -191,7 +203,35 @@ class Contact extends Model
|
||||
|
||||
$collection = $this->isCustomer() ? 'invoices' : 'bills';
|
||||
|
||||
$this->$collection->whereNotIn('status', ['draft', 'cancelled', 'paid'])->each(function ($item) use (&$amount) {
|
||||
$this->$collection->whereIn('status', ['sent', 'received', 'viewed', 'partial'])->each(function ($item) use (&$amount) {
|
||||
$amount += $this->convertToDefault($item->amount_due, $item->currency_code, $item->currency_rate);
|
||||
});
|
||||
|
||||
return $amount;
|
||||
}
|
||||
|
||||
public function getOpenAttribute()
|
||||
{
|
||||
$amount = 0;
|
||||
$today = Date::today()->toDateString();
|
||||
|
||||
$collection = $this->isCustomer() ? 'invoices' : 'bills';
|
||||
|
||||
$this->$collection->whereIn('status', ['sent', 'received', 'viewed', 'partial'])->where('due_at', '>=', $today)->each(function ($item) use (&$amount) {
|
||||
$amount += $this->convertToDefault($item->amount_due, $item->currency_code, $item->currency_rate);
|
||||
});
|
||||
|
||||
return $amount;
|
||||
}
|
||||
|
||||
public function getOverdueAttribute()
|
||||
{
|
||||
$amount = 0;
|
||||
$today = Date::today()->toDateString();
|
||||
|
||||
$collection = $this->isCustomer() ? 'invoices' : 'bills';
|
||||
|
||||
$this->$collection->whereIn('status', ['sent', 'received', 'viewed', 'partial'])->where('due_at', '<', $today)->each(function ($item) use (&$amount) {
|
||||
$amount += $this->convertToDefault($item->amount_due, $item->currency_code, $item->currency_rate);
|
||||
});
|
||||
|
||||
@ -221,6 +261,71 @@ class Contact extends Model
|
||||
return implode(', ', $location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the line actions.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLineActionsAttribute()
|
||||
{
|
||||
$actions = [];
|
||||
|
||||
$group = config('type.contact.' . $this->type . '.group');
|
||||
$prefix = config('type.contact.' . $this->type . '.route.prefix');
|
||||
$permission_prefix = config('type.contact.' . $this->type . '.permission.prefix');
|
||||
$translation_prefix = config('type.contact.' . $this->type . '.translation.prefix');
|
||||
|
||||
if (empty($prefix)) {
|
||||
if (in_array($this->type, (array) $this->getCustomerTypes())) {
|
||||
$prefix = config('type.contact.customer.route.prefix');
|
||||
} elseif (in_array($this->type, (array) $this->getVendorTypes())) {
|
||||
$prefix = config('type.contact.vendor.route.prefix');
|
||||
} else {
|
||||
return $actions;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$actions[] = [
|
||||
'title' => trans('general.show'),
|
||||
'icon' => 'visibility',
|
||||
'url' => route($prefix . '.show', $this->id),
|
||||
'permission' => 'read-' . $group . '-' . $permission_prefix,
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
try {
|
||||
$actions[] = [
|
||||
'title' => trans('general.edit'),
|
||||
'icon' => 'edit',
|
||||
'url' => route($prefix . '.edit', $this->id),
|
||||
'permission' => 'update-' . $group . '-' . $permission_prefix,
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
try {
|
||||
$actions[] = [
|
||||
'title' => trans('general.duplicate'),
|
||||
'icon' => 'file_copy',
|
||||
'url' => route($prefix . '.duplicate', $this->id),
|
||||
'permission' => 'create-' . $group . '-' . $permission_prefix,
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
try {
|
||||
$actions[] = [
|
||||
'type' => 'delete',
|
||||
'icon' => 'delete',
|
||||
'title' => $translation_prefix,
|
||||
'route' => $prefix . '.destroy',
|
||||
'permission' => 'delete-' . $group . '-' . $permission_prefix,
|
||||
'model' => $this,
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory instance for the model.
|
||||
*
|
||||
|
@ -114,6 +114,42 @@ class Dashboard extends Model
|
||||
return $alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the line actions.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLineActionsAttribute()
|
||||
{
|
||||
$actions = [];
|
||||
|
||||
if ($this->enabled) {
|
||||
$actions[] = [
|
||||
'title' => trans('general.switch'),
|
||||
'icon' => 'settings_ethernet',
|
||||
'url' => route('dashboards.switch', $this->id),
|
||||
'permission' => 'read-common-dashboards',
|
||||
];
|
||||
}
|
||||
|
||||
$actions[] = [
|
||||
'title' => trans('general.edit'),
|
||||
'icon' => 'edit',
|
||||
'url' => route('dashboards.edit', $this->id),
|
||||
'permission' => 'update-common-dashboards',
|
||||
];
|
||||
|
||||
$actions[] = [
|
||||
'type' => 'delete',
|
||||
'icon' => 'delete',
|
||||
'route' => 'dashboards.destroy',
|
||||
'permission' => 'delete-common-dashboards',
|
||||
'model' => $this,
|
||||
];
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory instance for the model.
|
||||
*
|
||||
|
@ -27,7 +27,7 @@ class Item extends Model
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['company_id', 'name', 'description', 'sale_price', 'purchase_price', 'category_id', 'enabled', 'created_from', 'created_by'];
|
||||
protected $fillable = ['company_id', 'type', 'name', 'description', 'sale_price', 'purchase_price', 'category_id', 'enabled', 'created_from', 'created_by'];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
@ -45,7 +45,7 @@ class Item extends Model
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $sortable = ['name', 'category', 'sale_price', 'purchase_price', 'enabled'];
|
||||
protected $sortable = ['name', 'category.name', 'sale_price', 'purchase_price', 'enabled'];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
@ -82,6 +82,11 @@ class Item extends Model
|
||||
return $query->where('name', '=', $name);
|
||||
}
|
||||
|
||||
public function scopeBilling($query, $billing)
|
||||
{
|
||||
return $query->where($billing . '_price', '=', null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the item id.
|
||||
*
|
||||
@ -149,6 +154,40 @@ class Item extends Model
|
||||
return $this->getMedia('picture')->last();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the line actions.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLineActionsAttribute()
|
||||
{
|
||||
$actions = [];
|
||||
|
||||
$actions[] = [
|
||||
'title' => trans('general.edit'),
|
||||
'icon' => 'edit',
|
||||
'url' => route('items.edit', $this->id),
|
||||
'permission' => 'update-common-items',
|
||||
];
|
||||
|
||||
$actions[] = [
|
||||
'title' => trans('general.duplicate'),
|
||||
'icon' => 'file_copy',
|
||||
'url' => route('items.duplicate', $this->id),
|
||||
'permission' => 'create-common-items',
|
||||
];
|
||||
|
||||
$actions[] = [
|
||||
'type' => 'delete',
|
||||
'icon' => 'delete',
|
||||
'route' => 'items.destroy',
|
||||
'permission' => 'delete-common-items',
|
||||
'model' => $this,
|
||||
];
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory instance for the model.
|
||||
*
|
||||
|
@ -4,11 +4,16 @@ namespace App\Models\Common;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Traits\Recurring as RecurringTrait;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class Recurring extends Model
|
||||
{
|
||||
use RecurringTrait;
|
||||
|
||||
public const ACTIVE_STATUS = 'active';
|
||||
public const END_STATUS = 'ended';
|
||||
public const COMPLETE_STATUS = 'completed';
|
||||
|
||||
protected $table = 'recurring';
|
||||
|
||||
/**
|
||||
@ -16,7 +21,30 @@ class Recurring extends Model
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['company_id', 'recurable_id', 'recurable_type', 'frequency', 'interval', 'started_at', 'count', 'created_from', 'created_by'];
|
||||
protected $fillable = [
|
||||
'company_id',
|
||||
'recurable_id',
|
||||
'recurable_type',
|
||||
'frequency',
|
||||
'interval',
|
||||
'started_at',
|
||||
'status',
|
||||
'limit_by',
|
||||
'limit_count',
|
||||
'limit_date',
|
||||
'auto_send',
|
||||
'created_from',
|
||||
'created_by',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'auto_send' => 'boolean',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get all of the owning recurable models.
|
||||
@ -25,4 +53,19 @@ class Recurring extends Model
|
||||
{
|
||||
return $this->morphTo();
|
||||
}
|
||||
|
||||
public function scopeActive(Builder $query): Builder
|
||||
{
|
||||
return $query->where($this->qualifyColumn('status'), '=', static::ACTIVE_STATUS);
|
||||
}
|
||||
|
||||
public function scopeEnded(Builder $query): Builder
|
||||
{
|
||||
return $query->where($this->qualifyColumn('status'), '=', static::END_STATUS);
|
||||
}
|
||||
|
||||
public function scopeCompleted(Builder $query): Builder
|
||||
{
|
||||
return $query->where($this->qualifyColumn('status'), '=', static::COMPLETE_STATUS);
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,9 @@ class Document extends Model
|
||||
use HasFactory, Documents, Cloneable, Currencies, DateTime, Media, Recurring;
|
||||
|
||||
public const INVOICE_TYPE = 'invoice';
|
||||
public const INVOICE_RECURRING_TYPE = 'invoice-recurring';
|
||||
public const BILL_TYPE = 'bill';
|
||||
public const BILL_RECURRING_TYPE = 'bill-recurring';
|
||||
|
||||
protected $table = 'documents';
|
||||
|
||||
@ -94,6 +96,11 @@ class Document extends Model
|
||||
return $this->belongsTo('App\Models\Setting\Category')->withDefault(['name' => trans('general.na')]);
|
||||
}
|
||||
|
||||
public function children()
|
||||
{
|
||||
return $this->hasMany('App\Models\Document\Document', 'parent_id');
|
||||
}
|
||||
|
||||
public function contact()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Common\Contact')->withDefault(['name' => trans('general.na')]);
|
||||
@ -119,6 +126,19 @@ class Document extends Model
|
||||
return $this->hasMany('App\Models\Document\DocumentHistory', 'document_id');
|
||||
}
|
||||
|
||||
public function last_history()
|
||||
{
|
||||
return $this->hasOne('App\Models\Document\DocumentHistory', 'document_id')->latest()->withDefault([
|
||||
'description' => trans('messages.success.added', ['type' => $this->document_number]),
|
||||
'created_at' => $this->created_at
|
||||
]);
|
||||
}
|
||||
|
||||
public function parent()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Document\Document', 'parent_id');
|
||||
}
|
||||
|
||||
public function payments()
|
||||
{
|
||||
return $this->transactions();
|
||||
@ -144,56 +164,66 @@ class Document extends Model
|
||||
return $this->totals()->orderBy('sort_order');
|
||||
}
|
||||
|
||||
public function parent()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Document\Document', 'parent_id');
|
||||
}
|
||||
|
||||
public function scopeLatest(Builder $query)
|
||||
public function scopeLatest(Builder $query): Builder
|
||||
{
|
||||
return $query->orderBy('issued_at', 'desc');
|
||||
}
|
||||
|
||||
public function scopeNumber(Builder $query, string $number)
|
||||
public function scopeNumber(Builder $query, string $number): Builder
|
||||
{
|
||||
return $query->where('document_number', '=', $number);
|
||||
}
|
||||
|
||||
public function scopeDue($query, $date)
|
||||
public function scopeDue(Builder $query, $date): Builder
|
||||
{
|
||||
return $query->whereDate('due_at', '=', $date);
|
||||
}
|
||||
|
||||
public function scopeAccrued($query)
|
||||
public function scopeAccrued(Builder $query): Builder
|
||||
{
|
||||
return $query->whereNotIn('status', ['draft', 'cancelled']);
|
||||
}
|
||||
|
||||
public function scopePaid($query)
|
||||
public function scopePaid(Builder $query): Builder
|
||||
{
|
||||
return $query->where('status', '=', 'paid');
|
||||
}
|
||||
|
||||
public function scopeNotPaid($query)
|
||||
public function scopeNotPaid(Builder $query): Builder
|
||||
{
|
||||
return $query->where('status', '<>', 'paid');
|
||||
}
|
||||
|
||||
public function scopeType(Builder $query, string $type)
|
||||
public function scopeFuture(Builder $query): Builder
|
||||
{
|
||||
return $query->whereIn('status', $this->getDocumentStatusesForFuture());
|
||||
}
|
||||
|
||||
public function scopeType(Builder $query, string $type): Builder
|
||||
{
|
||||
return $query->where($this->qualifyColumn('type'), '=', $type);
|
||||
}
|
||||
|
||||
public function scopeInvoice(Builder $query)
|
||||
public function scopeInvoice(Builder $query): Builder
|
||||
{
|
||||
return $query->where($this->qualifyColumn('type'), '=', self::INVOICE_TYPE);
|
||||
}
|
||||
|
||||
public function scopeBill(Builder $query)
|
||||
public function scopeInvoiceRecurring(Builder $query): Builder
|
||||
{
|
||||
return $query->where($this->qualifyColumn('type'), '=', self::INVOICE_RECURRING_TYPE);
|
||||
}
|
||||
|
||||
public function scopeBill(Builder $query): Builder
|
||||
{
|
||||
return $query->where($this->qualifyColumn('type'), '=', self::BILL_TYPE);
|
||||
}
|
||||
|
||||
public function scopeBillRecurring(Builder $query): Builder
|
||||
{
|
||||
return $query->where($this->qualifyColumn('type'), '=', self::BILL_RECURRING_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
@ -202,8 +232,14 @@ class Document extends Model
|
||||
*/
|
||||
public function onCloning($src, $child = null)
|
||||
{
|
||||
if (app()->has(\App\Console\Commands\RecurringCheck::class)) {
|
||||
$type = $this->getRealTypeOfRecurringDocument($src->type);
|
||||
} else {
|
||||
$type = $src->type;
|
||||
}
|
||||
|
||||
$this->status = 'draft';
|
||||
$this->document_number = $this->getNextDocumentNumber($src->type);
|
||||
$this->document_number = $this->getNextDocumentNumber($type);
|
||||
}
|
||||
|
||||
public function getSentAtAttribute(string $value = null)
|
||||
@ -354,29 +390,29 @@ class Document extends Model
|
||||
*/
|
||||
public function getStatusLabelAttribute()
|
||||
{
|
||||
switch ($this->status) {
|
||||
case 'paid':
|
||||
$label = 'success';
|
||||
break;
|
||||
case 'partial':
|
||||
$label = 'info';
|
||||
break;
|
||||
case 'sent':
|
||||
case 'received':
|
||||
$label = 'danger';
|
||||
break;
|
||||
case 'viewed':
|
||||
$label = 'warning';
|
||||
break;
|
||||
case 'cancelled':
|
||||
$label = 'dark';
|
||||
break;
|
||||
default:
|
||||
$label = 'primary';
|
||||
break;
|
||||
}
|
||||
return match($this->status) {
|
||||
'paid' => 'status-success',
|
||||
'partial' => 'status-partial',
|
||||
'sent' => 'status-danger',
|
||||
'received' => 'status-danger',
|
||||
'viewed' => 'status-sent',
|
||||
'cancelled' => 'status-canceled',
|
||||
default => 'status-draft',
|
||||
};
|
||||
}
|
||||
|
||||
return $label;
|
||||
/**
|
||||
* Get the recurring status label.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getRecurringStatusLabelAttribute()
|
||||
{
|
||||
return match($this->recurring->status) {
|
||||
'active' => 'status-partial',
|
||||
'ended' => 'status-success',
|
||||
default => 'status-success',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -429,6 +465,167 @@ class Document extends Model
|
||||
return implode(', ', $location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the line actions.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLineActionsAttribute()
|
||||
{
|
||||
$actions = [];
|
||||
|
||||
$group = config('type.document.' . $this->type . '.group');
|
||||
$prefix = config('type.document.' . $this->type . '.route.prefix');
|
||||
$permission_prefix = config('type.document.' . $this->type . '.permission.prefix');
|
||||
$translation_prefix = config('type.document.' . $this->type . '.translation.prefix');
|
||||
|
||||
if (empty($prefix)) {
|
||||
return $actions;
|
||||
}
|
||||
|
||||
try {
|
||||
$actions[] = [
|
||||
'title' => trans('general.show'),
|
||||
'icon' => 'visibility',
|
||||
'url' => route($prefix . '.show', $this->id),
|
||||
'permission' => 'read-' . $group . '-' . $permission_prefix,
|
||||
'attributes' => [
|
||||
'id' => 'index-more-actions-show-' . $this->id,
|
||||
],
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
try {
|
||||
if (! $this->reconciled) {
|
||||
$actions[] = [
|
||||
'title' => trans('general.edit'),
|
||||
'icon' => 'edit',
|
||||
'url' => route($prefix . '.edit', $this->id),
|
||||
'permission' => 'update-' . $group . '-' . $permission_prefix,
|
||||
'attributes' => [
|
||||
'id' => 'index-more-actions-edit-' . $this->id,
|
||||
],
|
||||
];
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
try {
|
||||
$actions[] = [
|
||||
'title' => trans('general.duplicate'),
|
||||
'icon' => 'file_copy',
|
||||
'url' => route($prefix . '.duplicate', $this->id),
|
||||
'permission' => 'create-' . $group . '-' . $permission_prefix,
|
||||
'attributes' => [
|
||||
'id' => 'index-more-actions-duplicate-' . $this->id,
|
||||
],
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
try {
|
||||
$actions[] = [
|
||||
'title' => trans('general.print'),
|
||||
'icon' => 'print',
|
||||
'url' => route($prefix . '.print', $this->id),
|
||||
'permission' => 'read-' . $group . '-' . $permission_prefix,
|
||||
'attributes' => [
|
||||
'id' => 'index-more-actions-print-' . $this->id,
|
||||
'target' => '_blank',
|
||||
],
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
try {
|
||||
$actions[] = [
|
||||
'title' => trans('general.download_pdf'),
|
||||
'icon' => 'pdf',
|
||||
'url' => route($prefix . '.pdf', $this->id),
|
||||
'permission' => 'read-' . $group . '-' . $permission_prefix,
|
||||
'attributes' => [
|
||||
'id' => 'index-more-actions-pdf-' . $this->id,
|
||||
'target' => '_blank',
|
||||
],
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
if (!str_contains($this->type, 'recurring')) {
|
||||
$actions[] = [
|
||||
'type' => 'divider',
|
||||
];
|
||||
|
||||
try {
|
||||
$actions[] = [
|
||||
'type' => 'button',
|
||||
'title' => trans('general.share_link'),
|
||||
'icon' => 'share',
|
||||
'url' => route('modals.'. $prefix . '.share.create', $this->id),
|
||||
'permission' => 'read-' . $group . '-' . $permission_prefix,
|
||||
'attributes' => [
|
||||
'id' => 'index-more-actions-share-link-' . $this->id,
|
||||
'@click' => 'onShareLink("' . route('modals.'. $prefix . '.share.create', $this->id) . '")',
|
||||
],
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
try {
|
||||
if ($this->type == 'invoice') {
|
||||
$actions[] = [
|
||||
'type' => 'button',
|
||||
'title' => trans('invoices.send_mail'),
|
||||
'icon' => 'email',
|
||||
'url' => route('modals.'. $prefix . '.emails.create', $this->id),
|
||||
'permission' => 'read-' . $group . '-' . $permission_prefix,
|
||||
'attributes' => [
|
||||
'id' => 'index-more-actions-send-email-' . $this->id,
|
||||
'@click' => 'onEmail("' . route('modals.'. $prefix . '.emails.create', $this->id) . '")',
|
||||
],
|
||||
];
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
$actions[] = [
|
||||
'type' => 'divider',
|
||||
];
|
||||
|
||||
try {
|
||||
$actions[] = [
|
||||
'title' => trans('general.cancel'),
|
||||
'icon' => 'cancel',
|
||||
'url' => route($prefix . '.cancelled', $this->id),
|
||||
'permission' => 'update-' . $group . '-' . $permission_prefix,
|
||||
'attributes' => [
|
||||
'id' => 'index-more-actions-cancel-' . $this->id,
|
||||
],
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
$actions[] = [
|
||||
'type' => 'divider',
|
||||
];
|
||||
|
||||
try {
|
||||
$actions[] = [
|
||||
'type' => 'delete',
|
||||
'icon' => 'delete',
|
||||
'title' => $translation_prefix,
|
||||
'route' => $prefix . '.destroy',
|
||||
'permission' => 'delete-' . $group . '-' . $permission_prefix,
|
||||
'model' => $this,
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
} else {
|
||||
try {
|
||||
$actions[] = [
|
||||
'title' => trans('general.end'),
|
||||
'icon' => 'block',
|
||||
'url' => route($prefix. '.end', $this->id),
|
||||
'permission' => 'update-' . $group . '-' . $permission_prefix,
|
||||
];
|
||||
} catch (\Exception $e) {}
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
protected static function newFactory(): Factory
|
||||
{
|
||||
return DocumentFactory::new();
|
||||
|
@ -3,14 +3,24 @@
|
||||
namespace App\Models\Setting;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use App\Builders\Category as Builder;
|
||||
use App\Models\Document\Document;
|
||||
use App\Relations\HasMany\Category as HasMany;
|
||||
use App\Scopes\Category as Scope;
|
||||
use App\Traits\Transactions;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model as EloquentModel;
|
||||
|
||||
class Category extends Model
|
||||
{
|
||||
use HasFactory, Transactions;
|
||||
|
||||
public const INCOME_TYPE = 'income';
|
||||
public const EXPENSE_TYPE = 'expense';
|
||||
public const ITEM_TYPE = 'item';
|
||||
public const OTHER_TYPE = 'other';
|
||||
|
||||
protected $table = 'categories';
|
||||
|
||||
/**
|
||||
@ -18,7 +28,7 @@ class Category extends Model
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = ['company_id', 'name', 'type', 'color', 'enabled', 'created_from', 'created_by'];
|
||||
protected $fillable = ['company_id', 'name', 'type', 'color', 'enabled', 'created_from', 'created_by', 'parent_id'];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
@ -36,6 +46,65 @@ class Category extends Model
|
||||
*/
|
||||
public $sortable = ['name', 'type', 'enabled'];
|
||||
|
||||
/**
|
||||
* The "booted" method of the model.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
static::addGlobalScope(new Scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Eloquent query builder for the model.
|
||||
*
|
||||
* @param \Illuminate\Database\Query\Builder $query
|
||||
* @return \App\Builders\Category
|
||||
*/
|
||||
public function newEloquentBuilder($query)
|
||||
{
|
||||
return new Builder($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate a new HasMany relationship.
|
||||
*
|
||||
* @param EloquentBuilder $query
|
||||
* @param EloquentModel $parent
|
||||
* @param string $foreignKey
|
||||
* @param string $localKey
|
||||
* @return HasMany
|
||||
*/
|
||||
protected function newHasMany(EloquentBuilder $query, EloquentModel $parent, $foreignKey, $localKey)
|
||||
{
|
||||
return new HasMany($query, $parent, $foreignKey, $localKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the model for a bound value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|null $field
|
||||
* @return \Illuminate\Database\Eloquent\Model|null
|
||||
*/
|
||||
public function resolveRouteBinding($value, $field = null)
|
||||
{
|
||||
return $this->resolveRouteBindingQuery($this, $value, $field)
|
||||
->withoutGlobalScope(Scope::class)
|
||||
->first();
|
||||
}
|
||||
|
||||
public function categories()
|
||||
{
|
||||
return $this->hasMany(Category::class, 'parent_id')->withSubCategory();
|
||||
}
|
||||
|
||||
public function sub_categories()
|
||||
{
|
||||
return $this->hasMany(Category::class, 'parent_id')->withSubCategory()->with('categories')->orderBy('name');
|
||||
}
|
||||
|
||||
public function documents()
|
||||
{
|
||||
return $this->hasMany('App\Models\Document\Document');
|
||||
@ -147,6 +216,50 @@ class Category extends Model
|
||||
return (int) $query->other()->pluck('id')->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope gets only parent categories.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeWithSubCategory($query)
|
||||
{
|
||||
return $query->withoutGlobalScope(new Scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the line actions.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLineActionsAttribute()
|
||||
{
|
||||
$actions = [];
|
||||
|
||||
$actions[] = [
|
||||
'title' => trans('general.edit'),
|
||||
'icon' => 'create',
|
||||
'url' => route('categories.edit', $this->id),
|
||||
'permission' => 'update-settings-categories',
|
||||
];
|
||||
|
||||
$transfer_id = Category::transfer();
|
||||
|
||||
if ($this->id == $transfer_id) {
|
||||
return $actions;
|
||||
}
|
||||
|
||||
$actions[] = [
|
||||
'type' => 'delete',
|
||||
'icon' => 'delete',
|
||||
'route' => 'categories.destroy',
|
||||
'permission' => 'delete-settings-categories',
|
||||
'model' => $this,
|
||||
];
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory instance for the model.
|
||||
*
|
||||
|
@ -101,6 +101,18 @@ class Currency extends Model
|
||||
return $this->contacts()->whereIn('type', (array) $this->getVendorTypes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope currency by code.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param mixed $code
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function scopeCode($query, $code)
|
||||
{
|
||||
return $query->where($this->qualifyColumn('code'), $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current precision.
|
||||
*
|
||||
@ -172,15 +184,30 @@ class Currency extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope currency by code.
|
||||
* Get the line actions.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param mixed $code
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
* @return array
|
||||
*/
|
||||
public function scopeCode($query, $code)
|
||||
public function getLineActionsAttribute()
|
||||
{
|
||||
return $query->where($this->qualifyColumn('code'), $code);
|
||||
$actions = [];
|
||||
|
||||
$actions[] = [
|
||||
'title' => trans('general.edit'),
|
||||
'icon' => 'edit',
|
||||
'url' => route('currencies.edit', $this->id),
|
||||
'permission' => 'update-settings-currencies',
|
||||
];
|
||||
|
||||
$actions[] = [
|
||||
'type' => 'delete',
|
||||
'icon' => 'delete',
|
||||
'route' => 'currencies.destroy',
|
||||
'permission' => 'delete-settings-currencies',
|
||||
'model' => $this,
|
||||
];
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Common;
|
||||
namespace App\Models\Setting;
|
||||
|
||||
use App\Abstracts\Model;
|
||||
use Illuminate\Support\Str;
|
||||
@ -9,6 +9,13 @@ class EmailTemplate extends Model
|
||||
{
|
||||
protected $table = 'email_templates';
|
||||
|
||||
/**
|
||||
* The accessors to append to the model's array form.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $appends = ['title'];
|
||||
|
||||
/**
|
||||
* Attributes that should be mass-assignable.
|
||||
*
|
||||
@ -16,6 +23,26 @@ class EmailTemplate extends Model
|
||||
*/
|
||||
protected $fillable = ['company_id', 'alias', 'class', 'name', 'subject', 'body', 'params', 'created_from', 'created_by'];
|
||||
|
||||
public function getTitleAttribute()
|
||||
{
|
||||
return trans($this->name);
|
||||
}
|
||||
|
||||
public function getGroupAttribute()
|
||||
{
|
||||
if (Str::startsWith($this->alias, 'invoice_')) {
|
||||
$group = 'general.invoices';
|
||||
} elseif (Str::startsWith($this->alias, 'bill_')) {
|
||||
$group = 'general.bills';
|
||||
} elseif (Str::startsWith($this->alias, 'payment_')) {
|
||||
$group = 'general.payments';
|
||||
} else {
|
||||
$group = 'general.others';
|
||||
}
|
||||
|
||||
return $group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope to only include email templates of a given alias.
|
||||
*
|
@ -45,7 +45,7 @@ class Tax extends Model
|
||||
|
||||
public function items()
|
||||
{
|
||||
return $this->hasMany('App\Models\Common\Item');
|
||||
return $this->hasMany('App\Models\Common\ItemTax');
|
||||
}
|
||||
|
||||
public function document_items()
|
||||
@ -136,6 +136,33 @@ class Tax extends Model
|
||||
return $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the line actions.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLineActionsAttribute()
|
||||
{
|
||||
$actions = [];
|
||||
|
||||
$actions[] = [
|
||||
'title' => trans('general.edit'),
|
||||
'icon' => 'edit',
|
||||
'url' => route('taxes.edit', $this->id),
|
||||
'permission' => 'update-settings-taxes',
|
||||
];
|
||||
|
||||
$actions[] = [
|
||||
'type' => 'delete',
|
||||
'icon' => 'delete',
|
||||
'route' => 'taxes.destroy',
|
||||
'permission' => 'delete-settings-taxes',
|
||||
'model' => $this,
|
||||
];
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new factory instance for the model.
|
||||
*
|
||||
|
Reference in New Issue
Block a user