added source feature

This commit is contained in:
Denis Duliçi 2021-09-07 10:33:34 +03:00
parent 0a4e066451
commit c59c71b0f9
80 changed files with 475 additions and 63 deletions

View File

@ -58,6 +58,8 @@ abstract class Module extends Command
'module_id' => $this->model->id,
'version' => $this->module->get('version'),
'description' => trans('modules.' . $action, ['module' => $this->alias]),
'created_from' => source_name(),
'created_by' => user_id(),
]);
}

View File

@ -36,6 +36,7 @@ abstract class Import implements HasLocalePreference, ShouldQueue, SkipsEmptyRow
{
$row['company_id'] = company_id();
$row['created_by'] = $this->user->id;
$row['created_from'] = 'import';
// Make enabled field integer
if (isset($row['enabled'])) {

View File

@ -4,18 +4,20 @@ namespace App\Abstracts;
use App\Abstracts\Http\FormRequest;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Interfaces\Job\ShouldDelete;
use App\Interfaces\Job\ShouldUpdate;
use App\Traits\Jobs;
use App\Traits\Relationships;
use App\Traits\Sources;
use App\Traits\Uploads;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
abstract class Job
{
use Jobs, Relationships, Uploads;
use Jobs, Relationships, Sources, Uploads;
protected $model;
@ -49,6 +51,10 @@ abstract class Job
if ($this instanceof HasOwner) {
$this->setOwner();
}
if ($this instanceof HasSource) {
$this->setSource();
}
}
public function bootUpdate(...$arguments): void
@ -106,4 +112,17 @@ abstract class Job
$this->request->merge(['created_by' => user_id()]);
}
public function setSource(): void
{
if (! $this->request instanceof Request) {
return;
}
if ($this->request->has('created_from')) {
return;
}
$this->request->merge(['created_from' => $this->getSourceName($this->request)]);
}
}

View File

@ -4,6 +4,7 @@ namespace App\Abstracts;
use App\Traits\DateTime;
use App\Traits\Owners;
use App\Traits\Sources;
use App\Traits\Tenants;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
use Illuminate\Database\Eloquent\Model as Eloquent;
@ -14,7 +15,7 @@ use Lorisleiva\LaravelSearchString\Concerns\SearchString;
abstract class Model extends Eloquent implements Ownable
{
use Cachable, DateTime, Owners, SearchString, SoftDeletes, Sortable, Tenants;
use Cachable, DateTime, Owners, SearchString, SoftDeletes, Sortable, Sources, Tenants;
protected $tenantable = true;
@ -211,6 +212,11 @@ abstract class Model extends Eloquent implements Ownable
return $query->whereIn($this->table . '.contact_id', (array) $contacts);
}
public function scopeSource($query, $source)
{
return $query->where($this->table . '.created_from', $source);
}
public function scopeIsOwner($query)
{
return $query->where($this->table . '.created_by', user_id());

View File

@ -0,0 +1,8 @@
<?php
namespace App\Interfaces\Job;
interface HasSource
{
//
}

View File

@ -3,10 +3,12 @@
namespace App\Jobs\Auth;
use App\Abstracts\Job;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Models\Auth\Role;
class CreateRole extends Job implements ShouldCreate
class CreateRole extends Job implements HasOwner, HasSource, ShouldCreate
{
public function handle(): Role
{

View File

@ -3,13 +3,15 @@
namespace App\Jobs\Auth;
use App\Abstracts\Job;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Events\Auth\UserCreated;
use App\Events\Auth\UserCreating;
use App\Models\Auth\User;
use Illuminate\Support\Facades\Artisan;
class CreateUser extends Job implements ShouldCreate
class CreateUser extends Job implements HasOwner, HasSource, ShouldCreate
{
public function handle(): User
{

View File

@ -4,10 +4,11 @@ namespace App\Jobs\Banking;
use App\Abstracts\Job;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Models\Banking\Account;
class CreateAccount extends Job implements HasOwner, ShouldCreate
class CreateAccount extends Job implements HasOwner, HasSource, ShouldCreate
{
public function handle(): Account
{

View File

@ -4,11 +4,12 @@ namespace App\Jobs\Banking;
use App\Abstracts\Job;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Models\Banking\Reconciliation;
use App\Models\Banking\Transaction;
class CreateReconciliation extends Job implements HasOwner, ShouldCreate
class CreateReconciliation extends Job implements HasOwner, HasSource, ShouldCreate
{
public function handle(): Reconciliation
{

View File

@ -6,10 +6,11 @@ use App\Abstracts\Job;
use App\Events\Banking\TransactionCreated;
use App\Events\Banking\TransactionCreating;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Models\Banking\Transaction;
class CreateTransaction extends Job implements HasOwner, ShouldCreate
class CreateTransaction extends Job implements HasOwner, HasSource, ShouldCreate
{
public function handle(): Transaction
{

View File

@ -4,6 +4,7 @@ namespace App\Jobs\Banking;
use App\Abstracts\Job;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Jobs\Banking\CreateTransaction;
use App\Models\Banking\Account;
@ -11,7 +12,7 @@ use App\Models\Banking\Transfer;
use App\Models\Setting\Category;
use App\Traits\Currencies;
class CreateTransfer extends Job implements HasOwner, ShouldCreate
class CreateTransfer extends Job implements HasOwner, HasSource, ShouldCreate
{
use Currencies;

View File

@ -6,11 +6,12 @@ use App\Abstracts\Job;
use App\Events\Common\CompanyCreated;
use App\Events\Common\CompanyCreating;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Models\Common\Company;
use Illuminate\Support\Facades\Artisan;
class CreateCompany extends Job implements HasOwner, ShouldCreate
class CreateCompany extends Job implements HasOwner, HasSource, ShouldCreate
{
public function handle(): Company
{

View File

@ -4,13 +4,14 @@ namespace App\Jobs\Common;
use App\Abstracts\Job;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Models\Auth\User;
use App\Models\Auth\Role;
use App\Models\Common\Contact;
use Illuminate\Support\Str;
class CreateContact extends Job implements HasOwner, ShouldCreate
class CreateContact extends Job implements HasOwner, HasSource, ShouldCreate
{
public function handle(): Contact
{

View File

@ -4,6 +4,7 @@ namespace App\Jobs\Common;
use App\Abstracts\Job;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Jobs\Common\CreateWidget;
use App\Models\Auth\User;
@ -13,7 +14,7 @@ use App\Models\Common\Widget;
use App\Utilities\Widgets;
use Illuminate\Support\Arr;
class CreateDashboard extends Job implements HasOwner, ShouldCreate
class CreateDashboard extends Job implements HasOwner, HasSource, ShouldCreate
{
public function handle(): Dashboard
{

View File

@ -0,0 +1,21 @@
<?php
namespace App\Jobs\Common;
use App\Abstracts\Job;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Models\Common\EmailTemplate;
class CreateEmailTemplate extends Job implements HasOwner, HasSource, ShouldCreate
{
public function handle(): EmailTemplate
{
\DB::transaction(function () {
$this->model = EmailTemplate::create($this->request->all());
});
return $this->model;
}
}

View File

@ -4,11 +4,12 @@ namespace App\Jobs\Common;
use App\Abstracts\Job;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Jobs\Common\CreateItemTaxes;
use App\Models\Common\Item;
class CreateItem extends Job implements HasOwner, ShouldCreate
class CreateItem extends Job implements HasOwner, HasSource, ShouldCreate
{
public function handle(): Item
{

View File

@ -3,11 +3,13 @@
namespace App\Jobs\Common;
use App\Abstracts\Job;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Models\Common\Item;
use App\Models\Common\ItemTax;
class CreateItemTaxes extends Job implements ShouldCreate
class CreateItemTaxes extends Job implements HasOwner, HasSource, ShouldCreate
{
protected $item;
@ -44,6 +46,8 @@ class CreateItemTaxes extends Job implements ShouldCreate
'company_id' => $this->item->company_id,
'item_id' => $this->item->id,
'tax_id' => $tax_id,
'created_from' => $this->request['created_from'],
'created_by' => $this->request['created_by'],
]);
}
});

View File

@ -4,10 +4,11 @@ namespace App\Jobs\Common;
use App\Abstracts\Job;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Models\Common\Report;
class CreateReport extends Job implements HasOwner, ShouldCreate
class CreateReport extends Job implements HasOwner, HasSource, ShouldCreate
{
public function handle(): Report
{

View File

@ -4,10 +4,11 @@ namespace App\Jobs\Common;
use App\Abstracts\Job;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Models\Common\Widget;
class CreateWidget extends Job implements HasOwner, ShouldCreate
class CreateWidget extends Job implements HasOwner, HasSource, ShouldCreate
{
public function handle(): Widget
{

View File

@ -6,12 +6,13 @@ use App\Abstracts\Job;
use App\Events\Document\DocumentCreated;
use App\Events\Document\DocumentCreating;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Jobs\Document\CreateDocumentItemsAndTotals;
use App\Models\Document\Document;
use Illuminate\Support\Str;
class CreateDocument extends Job implements HasOwner, ShouldCreate
class CreateDocument extends Job implements HasOwner, HasSource, ShouldCreate
{
public function handle(): Document
{

View File

@ -3,11 +3,13 @@
namespace App\Jobs\Document;
use App\Abstracts\Job;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Models\Document\Document;
use App\Models\Document\DocumentHistory;
class CreateDocumentHistory extends Job implements ShouldCreate
class CreateDocumentHistory extends Job implements HasOwner, HasSource, ShouldCreate
{
protected $document;
@ -35,6 +37,8 @@ class CreateDocumentHistory extends Job implements ShouldCreate
'status' => $this->document->status,
'notify' => $this->notify,
'description' => $description,
'created_from' => source_name(),
'created_by' => user_id(),
]);
return $document_history;

View File

@ -3,6 +3,8 @@
namespace App\Jobs\Document;
use App\Abstracts\Job;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Models\Document\Document;
use App\Models\Document\DocumentItem;
@ -10,7 +12,7 @@ use App\Models\Document\DocumentItemTax;
use App\Models\Setting\Tax;
use Illuminate\Support\Str;
class CreateDocumentItem extends Job implements ShouldCreate
class CreateDocumentItem extends Job implements HasOwner, HasSource, ShouldCreate
{
protected $document;
@ -182,6 +184,8 @@ class CreateDocumentItem extends Job implements ShouldCreate
$this->request['discount_type'] = !empty($this->request['discount_type']) ? $this->request['discount_type'] : 'percentage';
$this->request['discount_rate'] = !empty($this->request['discount']) ? $this->request['discount'] : 0;
$this->request['total'] = round($item_amount, $precision);
$this->request['created_from'] = source_name();
$this->request['created_by'] = user_id();
$document_item = DocumentItem::create($this->request);
@ -197,6 +201,8 @@ class CreateDocumentItem extends Job implements ShouldCreate
foreach ($item_taxes as $item_tax) {
$item_tax['document_item_id'] = $document_item->id;
$item_tax['amount'] = round(abs($item_tax['amount']), $precision);
$item_tax['created_from'] = $this->request['created_from'];
$item_tax['created_by'] = $this->request['created_by'];
DocumentItemTax::create($item_tax);
}

View File

@ -3,6 +3,8 @@
namespace App\Jobs\Document;
use App\Abstracts\Job;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Jobs\Common\CreateItem;
use App\Models\Document\Document;
@ -10,7 +12,7 @@ use App\Models\Document\DocumentTotal;
use App\Traits\Currencies;
use App\Traits\DateTime;
class CreateDocumentItemsAndTotals extends Job implements ShouldCreate
class CreateDocumentItemsAndTotals extends Job implements HasOwner, HasSource, ShouldCreate
{
use Currencies, DateTime;
@ -40,6 +42,8 @@ class CreateDocumentItemsAndTotals extends Job implements ShouldCreate
'name' => 'invoices.sub_total',
'amount' => round($sub_total, $precision),
'sort_order' => $sort_order,
'created_from' => $this->request['created_from'],
'created_by' => $this->request['created_by'],
]);
$this->request['amount'] += $sub_total;
@ -56,6 +60,8 @@ class CreateDocumentItemsAndTotals extends Job implements ShouldCreate
'name' => 'invoices.item_discount',
'amount' => round($discount_amount_total, $precision),
'sort_order' => $sort_order,
'created_from' => $this->request['created_from'],
'created_by' => $this->request['created_by'],
]);
$sort_order++;
@ -68,7 +74,7 @@ class CreateDocumentItemsAndTotals extends Job implements ShouldCreate
$discount_total = $this->request['discount'];
}
DocumentTotal::create([
DocumentTotal::create([
'company_id' => $this->document->company_id,
'type' => $this->document->type,
'document_id' => $this->document->id,
@ -76,6 +82,8 @@ class CreateDocumentItemsAndTotals extends Job implements ShouldCreate
'name' => 'invoices.discount',
'amount' => round($discount_total, $precision),
'sort_order' => $sort_order,
'created_from' => $this->request['created_from'],
'created_by' => $this->request['created_by'],
]);
$this->request['amount'] -= $discount_total;
@ -94,6 +102,8 @@ class CreateDocumentItemsAndTotals extends Job implements ShouldCreate
'name' => $tax['name'],
'amount' => round(abs($tax['amount']), $precision),
'sort_order' => $sort_order,
'created_from' => $this->request['created_from'],
'created_by' => $this->request['created_by'],
]);
$this->request['amount'] += $tax['amount'];
@ -109,6 +119,8 @@ class CreateDocumentItemsAndTotals extends Job implements ShouldCreate
$total['type'] = $this->document->type;
$total['document_id'] = $this->document->id;
$total['sort_order'] = $sort_order;
$total['created_from'] = $this->request['created_from'];
$total['created_by'] = $this->request['created_by'];
if (empty($total['code'])) {
$total['code'] = 'extra';
@ -140,6 +152,8 @@ class CreateDocumentItemsAndTotals extends Job implements ShouldCreate
'name' => 'invoices.total',
'amount' => $this->request['amount'],
'sort_order' => $sort_order,
'created_from' => $this->request['created_from'],
'created_by' => $this->request['created_by'],
]);
}
@ -167,7 +181,7 @@ class CreateDocumentItemsAndTotals extends Job implements ShouldCreate
'description' => $item['description'],
'sale_price' => $item['price'],
'purchase_price' => $item['price'],
'enabled' => '1'
'enabled' => '1',
];
if (!empty($item['tax_ids'])) {

View File

@ -4,10 +4,11 @@ namespace App\Jobs\Setting;
use App\Abstracts\Job;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Models\Setting\Category;
class CreateCategory extends Job implements HasOwner, ShouldCreate
class CreateCategory extends Job implements HasOwner, HasSource, ShouldCreate
{
public function handle(): Category
{

View File

@ -4,10 +4,11 @@ namespace App\Jobs\Setting;
use App\Abstracts\Job;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Models\Setting\Currency;
class CreateCurrency extends Job implements HasOwner, ShouldCreate
class CreateCurrency extends Job implements HasOwner, HasSource, ShouldCreate
{
public function handle(): Currency
{

View File

@ -4,10 +4,11 @@ namespace App\Jobs\Setting;
use App\Abstracts\Job;
use App\Interfaces\Job\HasOwner;
use App\Interfaces\Job\HasSource;
use App\Interfaces\Job\ShouldCreate;
use App\Models\Setting\Tax;
class CreateTax extends Job implements HasOwner, ShouldCreate
class CreateTax extends Job implements HasOwner, HasSource, ShouldCreate
{
public function handle(): Tax
{

View File

@ -35,6 +35,8 @@ class CreateModuleUpdatedHistory
'module_id' => $model->id,
'version' => $event->new,
'description' => trans('modules.updated_2', ['module' => $module->getAlias()]),
'created_from' => source_name(),
'created_by' => user_id(),
]);
}
}

View File

@ -20,7 +20,7 @@ class Role extends LaratrustRole
*
* @var array
*/
protected $fillable = ['name', 'display_name', 'description'];
protected $fillable = ['name', 'display_name', 'description', 'created_from', 'created_by'];
/**
* Scope to get all rows filtered, sorted and paginated.

View File

@ -5,6 +5,8 @@ namespace App\Models\Auth;
use App\Traits\Tenants;
use App\Notifications\Auth\Reset;
use App\Traits\Media;
use App\Traits\Owners;
use App\Traits\Sources;
use App\Traits\Users;
use App\Utilities\Date;
use Illuminate\Contracts\Translation\HasLocalePreference;
@ -18,7 +20,7 @@ use Lorisleiva\LaravelSearchString\Concerns\SearchString;
class User extends Authenticatable implements HasLocalePreference
{
use HasFactory, LaratrustUserTrait, Notifiable, SearchString, SoftDeletes, Sortable, Media, Tenants, Users;
use HasFactory, LaratrustUserTrait, Media, Notifiable, Owners, SearchString, SoftDeletes, Sortable, Sources, Tenants, Users;
protected $table = 'users';
@ -27,7 +29,7 @@ class User extends Authenticatable implements HasLocalePreference
*
* @var array
*/
protected $fillable = ['name', 'email', 'password', 'locale', 'enabled', 'landing_page'];
protected $fillable = ['name', 'email', 'password', 'locale', 'enabled', 'landing_page', 'created_from', 'created_by'];
/**
* The attributes that should be cast.
@ -258,6 +260,30 @@ class User extends Authenticatable implements HasLocalePreference
return (bool) $this->can('read-admin-panel');
}
public function scopeSource($query, $source)
{
return $query->where($this->table . '.created_from', $source);
}
public function scopeIsOwner($query)
{
return $query->where($this->table . '.created_by', user_id());
}
public function scopeIsNotOwner($query)
{
return $query->where($this->table . '.created_by', '<>', user_id());
}
public function ownerKey($owner)
{
if ($this->isNotOwnable()) {
return 0;
}
return $this->created_by;
}
/**
* Get the user's preferred locale.
*

View File

@ -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_by'];
protected $fillable = ['company_id', 'name', 'number', 'currency_code', 'opening_balance', 'bank_name', 'bank_phone', 'bank_address', 'enabled', 'created_from', 'created_by'];
/**
* The attributes that should be cast.

View File

@ -18,7 +18,7 @@ class Reconciliation extends Model
*
* @var array
*/
protected $fillable = ['company_id', 'account_id', 'started_at', 'ended_at', 'closing_balance', 'reconciled', 'created_by'];
protected $fillable = ['company_id', 'account_id', 'started_at', 'ended_at', 'closing_balance', 'reconciled', 'created_from', 'created_by'];
/**
* The attributes that should be cast.

View File

@ -43,6 +43,7 @@ class Transaction extends Model
'payment_method',
'reference',
'parent_id',
'created_from',
'created_by',
];

View File

@ -36,7 +36,7 @@ class Transfer extends Model
*
* @var array
*/
protected $fillable = ['company_id', 'expense_transaction_id', 'income_transaction_id', 'created_by'];
protected $fillable = ['company_id', 'expense_transaction_id', 'income_transaction_id', 'created_from', 'created_by'];
/**
* Sortable columns.

View File

@ -10,6 +10,7 @@ use App\Models\Document\Document;
use App\Traits\Contacts;
use App\Traits\Media;
use App\Traits\Owners;
use App\Traits\Sources;
use App\Traits\Tenants;
use App\Traits\Transactions;
use App\Utilities\Overrider;
@ -21,7 +22,7 @@ use Lorisleiva\LaravelSearchString\Concerns\SearchString;
class Company extends Eloquent implements Ownable
{
use Contacts, Media, Owners, SearchString, SoftDeletes, Sortable, Tenants, Transactions;
use Contacts, Media, Owners, SearchString, SoftDeletes, Sortable, Sources, Tenants, Transactions;
protected $table = 'companies';
@ -34,7 +35,7 @@ class Company extends Eloquent implements Ownable
protected $dates = ['deleted_at'];
protected $fillable = ['domain', 'enabled', 'created_by'];
protected $fillable = ['domain', 'enabled', 'created_from', 'created_by'];
protected $casts = [
'enabled' => 'boolean',
@ -554,14 +555,19 @@ class Company extends Eloquent implements Ownable
return static::getCurrent() !== null;
}
public function scopeSource($query, $source)
{
return $query->where($this->table . '.created_from', $source);
}
public function scopeIsOwner($query)
{
return $query->where('created_by', user_id());
return $query->where($this->table . '.created_by', user_id());
}
public function scopeIsNotOwner($query)
{
return $query->where('created_by', '<>', user_id());
return $query->where($this->table . '.created_by', '<>', user_id());
}
public function ownerKey($owner)

View File

@ -48,6 +48,7 @@ class Contact extends Model
'currency_code',
'reference',
'enabled',
'created_from',
'created_by',
];

View File

@ -18,7 +18,7 @@ class Dashboard extends Model
*
* @var array
*/
protected $fillable = ['company_id', 'name', 'enabled', 'created_by'];
protected $fillable = ['company_id', 'name', 'enabled', 'created_from', 'created_by'];
/**
* The attributes that should be cast.

View File

@ -13,7 +13,7 @@ class EmailTemplate extends Model
*
* @var array
*/
protected $fillable = ['company_id', 'alias', 'class', 'name', 'subject', 'body', 'params'];
protected $fillable = ['company_id', 'alias', 'class', 'name', 'subject', 'body', 'params', 'created_from', 'created_by'];
/**
* Scope to only include contacts of a given type.

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_by'];
protected $fillable = ['company_id', 'name', 'description', 'sale_price', 'purchase_price', 'category_id', 'enabled', 'created_from', 'created_by'];
/**
* The attributes that should be cast.

View File

@ -16,7 +16,7 @@ class ItemTax extends Model
*
* @var array
*/
protected $fillable = ['company_id', 'item_id', 'tax_id'];
protected $fillable = ['company_id', 'item_id', 'tax_id', 'created_from', 'created_by'];
public function item()
{

View File

@ -2,15 +2,17 @@
namespace App\Models\Common;
use App\Traits\Owners;
use App\Traits\Sources;
use App\Traits\Tenants;
use Illuminate\Database\Eloquent\SoftDeletes;
use Plank\Mediable\Media as BaseMedia;
class Media extends BaseMedia
{
use SoftDeletes, Tenants;
use Owners, SoftDeletes, Sources, Tenants;
protected $dates = ['deleted_at'];
protected $fillable = ['company_id'];
protected $fillable = ['company_id', 'created_from', 'created_by'];
}

View File

@ -16,7 +16,7 @@ class Recurring extends Model
*
* @var array
*/
protected $fillable = ['company_id', 'recurable_id', 'recurable_type', 'frequency', 'interval', 'started_at', 'count'];
protected $fillable = ['company_id', 'recurable_id', 'recurable_type', 'frequency', 'interval', 'started_at', 'count', 'created_from', 'created_by'];
/**
* Get all of the owning recurable models.

View File

@ -17,7 +17,7 @@ class Report extends Model
*
* @var array
*/
protected $fillable = ['company_id', 'class', 'name', 'description', 'settings', 'created_by'];
protected $fillable = ['company_id', 'class', 'name', 'description', 'settings', 'created_from', 'created_by'];
/**
* The attributes that should be cast.

View File

@ -17,7 +17,7 @@ class Widget extends Model
*
* @var array
*/
protected $fillable = ['company_id', 'dashboard_id', 'class', 'name', 'sort', 'settings', 'created_by'];
protected $fillable = ['company_id', 'dashboard_id', 'class', 'name', 'sort', 'settings', 'created_from', 'created_by'];
/**
* The attributes that should be cast.

View File

@ -51,6 +51,7 @@ class Document extends Model
'notes',
'footer',
'parent_id',
'created_from',
'created_by',
];

View File

@ -13,7 +13,7 @@ class DocumentHistory extends Model
protected $table = 'document_histories';
protected $fillable = ['company_id', 'type', 'document_id', 'status', 'notify', 'description'];
protected $fillable = ['company_id', 'type', 'document_id', 'status', 'notify', 'description', 'created_from', 'created_by'];
public function document()
{

View File

@ -30,6 +30,8 @@ class DocumentItem extends Model
'tax',
'discount_rate',
'discount_type',
'created_from',
'created_by',
];
/**

View File

@ -13,7 +13,7 @@ class DocumentItemTax extends Model
protected $table = 'document_item_taxes';
protected $fillable = ['company_id', 'type', 'document_id', 'document_item_id', 'tax_id', 'name', 'amount'];
protected $fillable = ['company_id', 'type', 'document_id', 'document_item_id', 'tax_id', 'name', 'amount', 'created_from', 'created_by'];
/**
* The attributes that should be cast.

View File

@ -13,7 +13,7 @@ class Module extends Model
*
* @var array
*/
protected $fillable = ['company_id', 'alias', 'enabled'];
protected $fillable = ['company_id', 'alias', 'enabled', 'created_from', 'created_by'];
/**
* The attributes that should be cast.

View File

@ -13,5 +13,5 @@ class ModuleHistory extends Model
*
* @var array
*/
protected $fillable = ['company_id', 'module_id', 'version', 'description'];
protected $fillable = ['company_id', 'module_id', 'version', 'description', 'created_from', 'created_by'];
}

View File

@ -18,7 +18,7 @@ class Category extends Model
*
* @var array
*/
protected $fillable = ['company_id', 'name', 'type', 'color', 'enabled', 'created_by'];
protected $fillable = ['company_id', 'name', 'type', 'color', 'enabled', 'created_from', 'created_by',];
/**
* The attributes that should be cast.

View File

@ -30,6 +30,7 @@ class Currency extends Model
'symbol_first',
'decimal_mark',
'thousands_separator',
'created_from',
'created_by',
];

View File

@ -24,7 +24,7 @@ class Tax extends Model
*
* @var array
*/
protected $fillable = ['company_id', 'name', 'rate', 'type', 'enabled', 'created_by'];
protected $fillable = ['company_id', 'name', 'rate', 'type', 'enabled', 'created_from', 'created_by'];
/**
* The attributes that should be cast.

View File

@ -4,9 +4,9 @@ namespace App\Traits;
use App\Models\Module\Module;
use App\Traits\SiteApi;
use App\Utilities\Date;
use App\Utilities\Info;
use Cache;
use Date;
use Illuminate\Support\Facades\Cache;
trait Modules
{

View File

@ -18,6 +18,8 @@ trait Recurring
$frequency = ($request['recurring_frequency'] != 'custom') ? $request['recurring_frequency'] : $request['recurring_custom_frequency'];
$interval = (($request['recurring_frequency'] != 'custom') || ($request['recurring_interval'] < 1)) ? 1 : (int) $request['recurring_interval'];
$started_at = !empty($request['paid_at']) ? $request['paid_at'] : $request['issued_at'];
$source = !empty($request['created_from']) ? $request['created_from'] : source_name();
$owner = !empty($request['created_by']) ? $request['created_by'] : user_id();
$this->recurring()->create([
'company_id' => $this->company_id,
@ -25,6 +27,8 @@ trait Recurring
'interval' => $interval,
'started_at' => $started_at,
'count' => (int) $request['recurring_count'],
'created_from' => $source,
'created_by' => $owner,
]);
}
@ -40,16 +44,27 @@ trait Recurring
$started_at = !empty($request['paid_at']) ? $request['paid_at'] : $request['issued_at'];
$recurring = $this->recurring();
$model_exists = $recurring->count();
$function = $recurring->count() ? 'update' : 'create';
$recurring->$function([
$data = [
'company_id' => $this->company_id,
'frequency' => $frequency,
'interval' => $interval,
'started_at' => $started_at,
'count' => (int) $request['recurring_count'],
]);
];
if ($model_exists) {
$recurring->update($data);
} else {
$source = !empty($request['created_from']) ? $request['created_from'] : source_name();
$owner = !empty($request['created_by']) ? $request['created_by'] : user_id();
$recurring->create(array_merge($data, [
'created_from' => $source,
'created_by' => $owner,
]));
}
}
public function getRecurringSchedule($set_until_date = true)

37
app/Traits/Sources.php Normal file
View File

@ -0,0 +1,37 @@
<?php
namespace App\Traits;
trait Sources
{
public function isSourcable(): bool
{
$sourcable = $this->sourcable ?: true;
return ($sourcable === true) && in_array('created_from', $this->getFillable());
}
public function isNotSourcable(): bool
{
return ! $this->isSourcable();
}
public function getSourceName($request = null): string
{
if (app()->runningInConsole()) {
$source = 'console';
}
if (empty($source)) {
$request = $request ?: request();
$source = $request->isApi() ? 'api' : null;
}
if (empty($source)) {
$source = 'ui';
}
return $source;
}
}

View File

@ -22,6 +22,8 @@ trait Uploads
return MediaUploader::makePrivate()
->beforeSave(function(MediaModel $media) {
$media->company_id = company_id();
$media->created_from = source_name();
$media->created_by = user_id();
})
->fromSource($file)
->toDirectory($path)
@ -41,6 +43,8 @@ trait Uploads
return MediaUploader::makePrivate()
->beforeSave(function(MediaModel $media) {
$media->company_id = company_id();
$media->created_from = source_name();
$media->created_by = user_id();
})
->importPath($disk, $path);
}

View File

@ -2,6 +2,7 @@
use App\Models\Common\Company;
use App\Traits\DateTime;
use App\Traits\Sources;
use App\Utilities\Date;
use App\Utilities\Widgets;
@ -38,7 +39,7 @@ if (!function_exists('user_id')) {
if (!function_exists('company_date_format')) {
/**
* Format the given date based on company settings.
* Get the date format of company.
*
* @return string
*/
@ -127,13 +128,30 @@ if (!function_exists('should_queue')) {
}
}
if (!function_exists('source_name')) {
/**
* Get the current source.
*
* @return string
*/
function source_name()
{
$tmp = new class() {
use Sources;
};
return $tmp->getSourceName();
}
}
if (!function_exists('cache_prefix')) {
/**
* Cache system added company_id prefix.
*
* @return string
*/
function cache_prefix() {
function cache_prefix()
{
return company_id() . '_';
}
}

View File

@ -31,6 +31,7 @@ class Account extends Factory
'bank_phone' => $this->faker->phoneNumber,
'bank_address' => $this->faker->address,
'enabled' => $this->faker->boolean ? 1 : 0,
'created_from' => 'factory',
];
}

View File

@ -29,6 +29,7 @@ class Category extends Factory
'type' => $this->faker->randomElement($types),
'color' => $this->faker->hexColor,
'enabled' => $this->faker->boolean ? 1 : 0,
'created_from' => 'factory',
];
}

View File

@ -39,6 +39,7 @@ class Contact extends Factory
'currency_code' => setting('default.currency'),
'reference' => $this->faker->text(5),
'enabled' => $this->faker->boolean ? 1 : 0,
'created_from' => 'factory',
];
}

View File

@ -47,6 +47,7 @@ class Currency extends Factory
'decimal_mark' => $currency['decimal_mark'],
'thousands_separator' => $currency['thousands_separator'],
'enabled' => $this->faker->boolean ? 1 : 0,
'created_from' => 'factory',
];
}

View File

@ -25,6 +25,7 @@ class Dashboard extends Factory
'company_id' => $this->company->id,
'name' => $this->faker->text(15),
'enabled' => $this->faker->boolean ? 1 : 0,
'created_from' => 'factory',
];
}

View File

@ -45,6 +45,7 @@ class Document extends AbstractFactory
'currency_rate' => '1',
'notes' => $this->faker->text(5),
'amount' => '0',
'created_from' => 'factory',
];
}

View File

@ -29,6 +29,7 @@ class Item extends Factory
'sale_price' => $this->faker->randomFloat(2, 10, 20),
'category_id' => $this->company->categories()->item()->get()->random(1)->pluck('id')->first(),
'enabled' => $this->faker->boolean ? 1 : 0,
'created_from' => 'factory',
];
}

View File

@ -34,6 +34,7 @@ class Reconciliation extends Factory
'started_at' => $started_at,
'ended_at' => $ended_at,
'reconcile' => $this->faker->boolean ? 1 : 0,
'created_from' => 'factory',
];
}

View File

@ -28,6 +28,7 @@ class Role extends Factory
'name' => strtolower($name),
'display_name' => $name,
'description' => $name,
'created_from' => 'factory',
];
}

View File

@ -29,6 +29,7 @@ class Tax extends Factory
'rate' => $this->faker->randomFloat(2, 10, 20),
'type' => $this->faker->randomElement($types),
'enabled' => $this->faker->boolean ? 1 : 0,
'created_from' => 'factory',
];
}

View File

@ -41,6 +41,7 @@ class Transaction extends Factory
'category_id' => $this->company->categories()->$category_type()->get()->random(1)->pluck('id')->first(),
'reference' => $this->faker->text(5),
'payment_method' => setting('default.payment_method'),
'created_from' => 'factory',
];
}

View File

@ -43,6 +43,7 @@ class Transfer extends Factory
'category_id' => Category::transfer(),
'description' => $this->faker->text(20),
'reference' => $this->faker->text(20),
'created_from' => 'factory',
];
$expense_transaction = Transaction::factory()->create(array_merge($request, [

View File

@ -34,6 +34,7 @@ class User extends Factory
'companies' => ['1'],
'roles' => ['1'],
'enabled' => $this->faker->boolean ? 1 : 0,
'created_from' => 'factory',
];
}

View File

@ -42,6 +42,7 @@ class Widget extends Factory
'dashboard_id' => $dashboard->id,
'name' => $this->faker->text(15),
'class' => $this->faker->randomElement($this->classes),
'created_from' => 'factory',
];
}
}

View File

@ -19,6 +19,127 @@ class CoreV2124 extends Migration
$table->string('zip_code')->nullable()->after('address');
$table->string('city')->nullable()->after('address');
});
Schema::table('accounts', function (Blueprint $table) {
$table->string('created_from', 30)->nullable()->after('enabled');
});
Schema::table('categories', function (Blueprint $table) {
$table->string('created_from', 30)->nullable()->after('enabled');
});
Schema::table('companies', function (Blueprint $table) {
$table->string('created_from', 30)->nullable()->after('enabled');
});
Schema::table('contacts', function (Blueprint $table) {
$table->string('created_from', 30)->nullable()->after('reference');
});
Schema::table('currencies', function (Blueprint $table) {
$table->string('created_from', 30)->nullable()->after('enabled');
});
Schema::table('dashboards', function (Blueprint $table) {
$table->string('created_from', 30)->nullable()->after('enabled');
});
Schema::table('documents', function (Blueprint $table) {
$table->string('created_from', 30)->nullable()->after('parent_id');
});
Schema::table('document_histories', function (Blueprint $table) {
$table->string('created_by', 30)->nullable()->after('description');
$table->string('created_from', 30)->nullable()->after('description');
});
Schema::table('document_items', function (Blueprint $table) {
$table->string('created_by', 30)->nullable()->after('total');
$table->string('created_from', 30)->nullable()->after('total');
});
Schema::table('document_item_taxes', function (Blueprint $table) {
$table->string('created_by', 30)->nullable()->after('amount');
$table->string('created_from', 30)->nullable()->after('amount');
});
Schema::table('document_totals', function (Blueprint $table) {
$table->string('created_by', 30)->nullable()->after('sort_order');
$table->string('created_from', 30)->nullable()->after('sort_order');
});
Schema::table('email_templates', function (Blueprint $table) {
$table->string('created_by', 30)->nullable()->after('params');
$table->string('created_from', 30)->nullable()->after('params');
});
Schema::table('items', function (Blueprint $table) {
$table->string('created_from', 30)->nullable()->after('enabled');
});
Schema::table('item_taxes', function (Blueprint $table) {
$table->string('created_by', 30)->nullable()->after('tax_id');
$table->string('created_from', 30)->nullable()->after('tax_id');
});
Schema::table('media', function (Blueprint $table) {
$table->string('created_by', 30)->nullable()->after('original_media_id');
$table->string('created_from', 30)->nullable()->after('original_media_id');
});
Schema::table('mediables', function (Blueprint $table) {
$table->string('created_by', 30)->nullable()->after('order');
$table->string('created_from', 30)->nullable()->after('order');
});
Schema::table('modules', function (Blueprint $table) {
$table->string('created_by', 30)->nullable()->after('enabled');
$table->string('created_from', 30)->nullable()->after('enabled');
});
Schema::table('module_histories', function (Blueprint $table) {
$table->string('created_by', 30)->nullable()->after('description');
$table->string('created_from', 30)->nullable()->after('description');
});
Schema::table('reconciliations', function (Blueprint $table) {
$table->string('created_from', 30)->nullable()->after('reconciled');
});
Schema::table('recurring', function (Blueprint $table) {
$table->string('created_by', 30)->nullable()->after('count');
$table->string('created_from', 30)->nullable()->after('count');
});
Schema::table('reports', function (Blueprint $table) {
$table->string('created_from', 30)->nullable()->after('settings');
});
Schema::table('roles', function (Blueprint $table) {
$table->string('created_by', 30)->nullable()->after('description');
$table->string('created_from', 30)->nullable()->after('description');
});
Schema::table('taxes', function (Blueprint $table) {
$table->string('created_from', 30)->nullable()->after('enabled');
});
Schema::table('transactions', function (Blueprint $table) {
$table->string('created_from', 30)->nullable()->after('parent_id');
});
Schema::table('transfers', function (Blueprint $table) {
$table->string('created_from', 30)->nullable()->after('income_transaction_id');
});
Schema::table('users', function (Blueprint $table) {
$table->string('created_by', 30)->nullable()->after('enabled');
$table->string('created_from', 30)->nullable()->after('enabled');
});
Schema::table('widgets', function (Blueprint $table) {
$table->string('created_from', 30)->nullable()->after('settings');
});
}
/**
@ -28,8 +149,6 @@ class CoreV2124 extends Migration
*/
public function down()
{
Schema::table('contacts', function (Blueprint $table) {
$table->dropColumn(['country','state', 'zip_code', 'city',]);
});
//
}
}

View File

@ -36,6 +36,7 @@ class Accounts extends Seeder
'currency_code' => 'USD',
'bank_name' => trans('demo.accounts.cash'),
'enabled' => '1',
'created_from' => 'seed',
]));
setting()->set('default.account', $account->id);

View File

@ -70,6 +70,8 @@ class Categories extends Seeder
$income_category_id = $expense_category_id = 0;
foreach ($rows as $row) {
$row['created_from'] = 'seed';
$category = $this->dispatch(new CreateCategory($row));
switch ($category->type) {

View File

@ -78,6 +78,8 @@ class Currencies extends Seeder
];
foreach ($rows as $row) {
$row['created_from'] = 'seed';
$this->dispatch(new CreateCurrency($row));
}
}

View File

@ -45,6 +45,7 @@ class Dashboards extends Seeder
'App\Widgets\LatestExpenses',
],
'users' => $user_id,
'created_from' => 'seed',
]));
}
}

View File

@ -3,11 +3,14 @@
namespace Database\Seeds;
use App\Abstracts\Model;
use App\Models\Common\EmailTemplate;
use App\Jobs\Common\CreateEmailTemplate;
use App\Traits\Jobs;
use Illuminate\Database\Seeder;
class EmailTemplates extends Seeder
{
use Jobs;
/**
* Run the database seeds.
*
@ -80,14 +83,15 @@ class EmailTemplates extends Seeder
];
foreach ($templates as $template) {
EmailTemplate::create([
$this->dispatch(new CreateEmailTemplate([
'company_id' => $company_id,
'alias' => $template['alias'],
'class' => $template['class'],
'name' => $template['name'],
'subject' => trans('email_templates.' . $template['alias'] . '.subject'),
'body' => trans('email_templates.' . $template['alias'] . '.body'),
]);
'created_from' => 'seed',
]));
}
}
}

View File

@ -68,6 +68,8 @@ class Reports extends Seeder
];
foreach ($rows as $row) {
$row['created_from'] = 'seed';
$this->dispatch(new CreateReport($row));
}
}

View File

@ -43,6 +43,8 @@ class InstallCommand extends Command
'company_id' => $this->company_id,
'alias' => $this->alias,
'enabled' => '1',
'created_from' => source_name(),
'created_by' => user_id(),
]);
$this->createHistory('installed');

View File

@ -0,0 +1,46 @@
<?php
namespace Tests\Feature\Common;
use Tests\Feature\FeatureTestCase;
use App\Jobs\Setting\CreateCategory;
class SourcesTest extends FeatureTestCase
{
public function testItShouldHaveAutoSource()
{
$request = $this->getRequest();
$category = $this->dispatch(new CreateCategory($request));
$this->assertDatabaseHas('categories', [
'id' => $category->id,
'created_from' => 'console',
]);
}
public function testItShouldHaveManualSource()
{
$request = $this->getRequest();
$request['created_from'] = 'manual';
$category = $this->dispatch(new CreateCategory($request));
$this->assertDatabaseHas('categories', [
'id' => $category->id,
'created_from' => 'manual',
]);
}
public function getRequest()
{
return [
'company_id' => $this->company->id,
'name' => $this->faker->text(15),
'type' => 'income',
'color' => $this->faker->hexColor,
'enabled' => $this->faker->boolean ? 1 : 0,
];
}
}