akaunting 3.0 (the last dance)

This commit is contained in:
Burak Civan
2022-06-01 10:15:55 +03:00
parent cead09f6d4
commit d9c0764572
3812 changed files with 126831 additions and 102949 deletions

View File

@ -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();
}
}

View File

@ -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.
*

View File

@ -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.
*

View File

@ -1,44 +0,0 @@
<?php
namespace App\Models\Common;
use App\Abstracts\Model;
use Illuminate\Support\Str;
class EmailTemplate extends Model
{
protected $table = 'email_templates';
/**
* Attributes that should be mass-assignable.
*
* @var array
*/
protected $fillable = ['company_id', 'alias', 'class', 'name', 'subject', 'body', 'params', 'created_from', 'created_by'];
/**
* Scope to only include email templates of a given alias.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param mixed $alias
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeAlias($query, $alias)
{
return $query->where('alias', $alias);
}
/**
* Scope to only include email templates of a given module alias (class).
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param string $alias
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeModuleAlias($query, $alias)
{
$class = ($alias == 'core') ? 'App\\\\' : 'Modules\\\\' . Str::studly($alias) . '\\\\';
return $query->where('class', 'like', $class . '%');
}
}

View File

@ -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.
*

View File

@ -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);
}
}