Merge branch 'master' of github.com:akaunting/akaunting
Conflicts: app/Http/Controllers/Auth/Login.php
This commit is contained in:
commit
2570dad2b7
@ -26,3 +26,5 @@ MAIL_PORT=2525
|
|||||||
MAIL_USERNAME=null
|
MAIL_USERNAME=null
|
||||||
MAIL_PASSWORD=null
|
MAIL_PASSWORD=null
|
||||||
MAIL_ENCRYPTION=null
|
MAIL_ENCRYPTION=null
|
||||||
|
MAIL_FROM_NAME=null
|
||||||
|
MAIL_FROM_ADDRESS=null
|
||||||
|
26
.travis.yml
Normal file
26
.travis.yml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
language: php
|
||||||
|
|
||||||
|
php:
|
||||||
|
- '5.6'
|
||||||
|
- '7.0'
|
||||||
|
- '7.1'
|
||||||
|
- '7.2'
|
||||||
|
|
||||||
|
env:
|
||||||
|
- DB=sqlite
|
||||||
|
|
||||||
|
sqlite:
|
||||||
|
adapter: sqlite3
|
||||||
|
database: ':memory:'
|
||||||
|
timeout: 500
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
# turn off XDebug
|
||||||
|
- phpenv config-rm xdebug.ini || return
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- cp .env.testing .env
|
||||||
|
- composer install --no-interaction
|
||||||
|
|
||||||
|
script:
|
||||||
|
- vendor/bin/phpunit
|
@ -1,6 +1,6 @@
|
|||||||
# Akaunting™
|
# Akaunting™
|
||||||
|
|
||||||
  [](https://crowdin.com/project/akaunting) [](#backers) [](#sponsors)
|
  [](https://crowdin.com/project/akaunting)  [](#backers) [](#sponsors)
|
||||||
|
|
||||||
Akaunting is a free, open source and online accounting software designed for small businesses and freelancers. It is built with modern technologies such as Laravel, Bootstrap, jQuery, RESTful API etc. Thanks to its modular structure, Akaunting provides an awesome App Store for users and developers.
|
Akaunting is a free, open source and online accounting software designed for small businesses and freelancers. It is built with modern technologies such as Laravel, Bootstrap, jQuery, RESTful API etc. Thanks to its modular structure, Akaunting provides an awesome App Store for users and developers.
|
||||||
|
|
||||||
|
78
app/Console/Commands/ModuleDelete.php
Normal file
78
app/Console/Commands/ModuleDelete.php
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\Module\Module;
|
||||||
|
use App\Models\Module\ModuleHistory;
|
||||||
|
use Artisan;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
|
|
||||||
|
class ModuleDelete extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'module:delete {alias} {company_id}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Delete the specified module.';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$alias = $this->argument('alias');
|
||||||
|
$company_id = $this->argument('company_id');
|
||||||
|
|
||||||
|
$model = Module::alias($alias)->companyId($company_id)->first();
|
||||||
|
|
||||||
|
if (!$model) {
|
||||||
|
$this->info("Module [{$alias}] not found.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$module = $this->laravel['modules']->findByAlias($alias);
|
||||||
|
$module->delete();
|
||||||
|
|
||||||
|
$model->status = 0;
|
||||||
|
$model->save();
|
||||||
|
|
||||||
|
// Add history
|
||||||
|
$data = [
|
||||||
|
'company_id' => $company_id,
|
||||||
|
'module_id' => $model->id,
|
||||||
|
'category' => $module->get('category'),
|
||||||
|
'version' => $module->get('version'),
|
||||||
|
'description' => trans('modules.deleted', ['module' => $module->get('name')]),
|
||||||
|
];
|
||||||
|
|
||||||
|
ModuleHistory::create($data);
|
||||||
|
|
||||||
|
Artisan::call('cache:clear');
|
||||||
|
|
||||||
|
$this->info("Module [{$alias}] deleted.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the console command arguments.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getArguments()
|
||||||
|
{
|
||||||
|
return array(
|
||||||
|
array('alias', InputArgument::REQUIRED, 'Module alias.'),
|
||||||
|
array('company_id', InputArgument::REQUIRED, 'Company ID.'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -54,6 +54,9 @@ class ModuleInstall extends Command
|
|||||||
|
|
||||||
ModuleHistory::create($data);
|
ModuleHistory::create($data);
|
||||||
|
|
||||||
|
// Clear cache
|
||||||
|
$this->call('cache:clear');
|
||||||
|
|
||||||
// Update database
|
// Update database
|
||||||
$this->call('migrate', ['--force' => true]);
|
$this->call('migrate', ['--force' => true]);
|
||||||
|
|
||||||
|
@ -63,43 +63,41 @@ class RecurringCheck extends Command
|
|||||||
|
|
||||||
$company->setSettings();
|
$company->setSettings();
|
||||||
|
|
||||||
foreach ($company->recurring as $recur) {
|
foreach ($company->recurring as $recurring) {
|
||||||
if (!$current = $recur->current()) {
|
foreach ($recurring->schedule() as $recur) {
|
||||||
continue;
|
$recur_date = Date::parse($recur->getStart()->format('Y-m-d'));
|
||||||
}
|
|
||||||
|
|
||||||
$current_date = Date::parse($current->format('Y-m-d'));
|
// Check if should recur today
|
||||||
|
if ($this->today->ne($recur_date)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if should recur today
|
$model = $recurring->recurable;
|
||||||
if ($this->today->ne($current_date)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$model = $recur->recurable;
|
if (!$model) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!$model) {
|
switch ($recurring->recurable_type) {
|
||||||
continue;
|
case 'App\Models\Expense\Bill':
|
||||||
}
|
$this->recurBill($company, $model);
|
||||||
|
break;
|
||||||
|
case 'App\Models\Income\Invoice':
|
||||||
|
$this->recurInvoice($company, $model);
|
||||||
|
break;
|
||||||
|
case 'App\Models\Expense\Payment':
|
||||||
|
case 'App\Models\Income\Revenue':
|
||||||
|
$model->cloneable_relations = [];
|
||||||
|
|
||||||
switch ($recur->recurable_type) {
|
// Create new record
|
||||||
case 'App\Models\Expense\Bill':
|
$clone = $model->duplicate();
|
||||||
$this->recurBill($company, $model);
|
|
||||||
break;
|
|
||||||
case 'App\Models\Income\Invoice':
|
|
||||||
$this->recurInvoice($company, $model);
|
|
||||||
break;
|
|
||||||
case 'App\Models\Expense\Payment':
|
|
||||||
case 'App\Models\Income\Revenue':
|
|
||||||
$model->cloneable_relations = [];
|
|
||||||
|
|
||||||
// Create new record
|
$clone->parent_id = $model->id;
|
||||||
$clone = $model->duplicate();
|
$clone->paid_at = $this->today->format('Y-m-d');
|
||||||
|
$clone->save();
|
||||||
|
|
||||||
$clone->parent_id = $model->id;
|
break;
|
||||||
$clone->paid_at = $this->today->format('Y-m-d');
|
}
|
||||||
$clone->save();
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,10 +13,11 @@ class Kernel extends ConsoleKernel
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $commands = [
|
protected $commands = [
|
||||||
Commands\CompanySeed::class,
|
|
||||||
Commands\BillReminder::class,
|
Commands\BillReminder::class,
|
||||||
|
Commands\CompanySeed::class,
|
||||||
Commands\Install::class,
|
Commands\Install::class,
|
||||||
Commands\InvoiceReminder::class,
|
Commands\InvoiceReminder::class,
|
||||||
|
Commands\ModuleDelete::class,
|
||||||
Commands\ModuleDisable::class,
|
Commands\ModuleDisable::class,
|
||||||
Commands\ModuleEnable::class,
|
Commands\ModuleEnable::class,
|
||||||
Commands\ModuleInstall::class,
|
Commands\ModuleInstall::class,
|
||||||
|
@ -15,4 +15,4 @@ class AdminMenuCreated
|
|||||||
{
|
{
|
||||||
$this->menu = $menu;
|
$this->menu = $menu;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,4 +15,4 @@ class BillCreated
|
|||||||
{
|
{
|
||||||
$this->bill = $bill;
|
$this->bill = $bill;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,4 +15,4 @@ class BillUpdated
|
|||||||
{
|
{
|
||||||
$this->bill = $bill;
|
$this->bill = $bill;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,4 +15,4 @@ class CompanySwitched
|
|||||||
{
|
{
|
||||||
$this->company = $company;
|
$this->company = $company;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,4 +15,4 @@ class CustomerMenuCreated
|
|||||||
{
|
{
|
||||||
$this->menu = $menu;
|
$this->menu = $menu;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,4 +15,4 @@ class InvoiceCreated
|
|||||||
{
|
{
|
||||||
$this->invoice = $invoice;
|
$this->invoice = $invoice;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,4 +15,4 @@ class InvoicePrinting
|
|||||||
{
|
{
|
||||||
$this->invoice = $invoice;
|
$this->invoice = $invoice;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,4 +15,4 @@ class InvoiceUpdated
|
|||||||
{
|
{
|
||||||
$this->invoice = $invoice;
|
$this->invoice = $invoice;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,4 +19,4 @@ class ModuleInstalled
|
|||||||
$this->alias = $alias;
|
$this->alias = $alias;
|
||||||
$this->company_id = $company_id;
|
$this->company_id = $company_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,4 +23,4 @@ class UpdateFinished
|
|||||||
$this->old = $old;
|
$this->old = $old;
|
||||||
$this->new = $new;
|
$this->new = $new;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
21
app/Filters/Banking/Reconciliations.php
Normal file
21
app/Filters/Banking/Reconciliations.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filters\Banking;
|
||||||
|
|
||||||
|
use EloquentFilter\ModelFilter;
|
||||||
|
|
||||||
|
class Reconciliations extends ModelFilter
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Related Models that have ModelFilters as well as the method on the ModelFilter
|
||||||
|
* As [relatedModel => [input_key1, input_key2]].
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $relations = [];
|
||||||
|
|
||||||
|
public function accounts($accounts)
|
||||||
|
{
|
||||||
|
return $this->whereIn('account_id', (array) $accounts);
|
||||||
|
}
|
||||||
|
}
|
@ -14,18 +14,27 @@ class Transactions extends ModelFilter
|
|||||||
*/
|
*/
|
||||||
public $relations = [];
|
public $relations = [];
|
||||||
|
|
||||||
public function account($account_id)
|
public function accounts($accounts)
|
||||||
{
|
{
|
||||||
return $this->where('account_id', $account_id);
|
return $this->whereIn('account_id', (array) $accounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function category($category_id)
|
public function categories($categories)
|
||||||
{
|
{
|
||||||
// No category for bills/invoices
|
// No category for bills/invoices
|
||||||
if (in_array($this->getModel()->getTable(), ['bill_payments', 'invoice_payments'])) {
|
if (in_array($this->getModel()->getTable(), ['bill_payments', 'invoice_payments'])) {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->where('category_id', $category_id);
|
return $this->whereIn('category_id', (array) $categories);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function date($date)
|
||||||
|
{
|
||||||
|
$dates = explode('_', $date);
|
||||||
|
$dates[0] .= ' 00:00:00';
|
||||||
|
$dates[1] .= ' 23:59:59';
|
||||||
|
|
||||||
|
return $this->whereBetween('paid_at', $dates);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -23,4 +23,13 @@ class Transfers extends ModelFilter
|
|||||||
{
|
{
|
||||||
return $this->related('revenue', 'revenues.account_id', '=', $account_id);
|
return $this->related('revenue', 'revenues.account_id', '=', $account_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function date($date)
|
||||||
|
{
|
||||||
|
$dates = explode('_', $date);
|
||||||
|
$dates[0] .= ' 00:00:00';
|
||||||
|
$dates[1] .= ' 23:59:59';
|
||||||
|
|
||||||
|
return $this->whereBetween('paid_at', $dates);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,8 +19,8 @@ class Items extends ModelFilter
|
|||||||
return $this->whereLike('name', $query);
|
return $this->whereLike('name', $query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function category($id)
|
public function categories($ids)
|
||||||
{
|
{
|
||||||
return $this->where('category_id', $id);
|
return $this->whereIn('category_id', (array) $ids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,13 +19,27 @@ class Bills extends ModelFilter
|
|||||||
return $this->whereLike('vendor_name', $query);
|
return $this->whereLike('vendor_name', $query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function vendor($vendor)
|
public function vendors($vendors)
|
||||||
{
|
{
|
||||||
return $this->where('vendor_id', $vendor);
|
return $this->whereIn('vendor_id', (array) $vendors);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function status($status)
|
public function categories($categories)
|
||||||
{
|
{
|
||||||
return $this->where('bill_status_code', $status);
|
return $this->whereIn('category_id', (array) $categories);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function statuses($statuses)
|
||||||
|
{
|
||||||
|
return $this->whereIn('bill_status_code', (array) $statuses);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function billDate($date)
|
||||||
|
{
|
||||||
|
$dates = explode('_', $date);
|
||||||
|
$dates[0] .= ' 00:00:00';
|
||||||
|
$dates[1] .= ' 23:59:59';
|
||||||
|
|
||||||
|
return $this->whereBetween('billed_at', $dates);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,18 +19,27 @@ class Payments extends ModelFilter
|
|||||||
return $this->whereLike('description', $query);
|
return $this->whereLike('description', $query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function vendor($vendor)
|
public function vendors($vendors)
|
||||||
{
|
{
|
||||||
return $this->where('vendor_id', $vendor);
|
return $this->whereIn('vendor_id', (array) $vendors);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function category($category)
|
public function categories($categories)
|
||||||
{
|
{
|
||||||
return $this->where('category_id', $category);
|
return $this->whereIn('category_id', (array) $categories);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function account($account)
|
public function accounts($accounts)
|
||||||
{
|
{
|
||||||
return $this->where('account_id', $account);
|
return $this->whereIn('account_id', (array) $accounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function date($date)
|
||||||
|
{
|
||||||
|
$dates = explode('_', $date);
|
||||||
|
$dates[0] .= ' 00:00:00';
|
||||||
|
$dates[1] .= ' 23:59:59';
|
||||||
|
|
||||||
|
return $this->whereBetween('paid_at', $dates);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,13 +19,27 @@ class Invoices extends ModelFilter
|
|||||||
return $this->whereLike('customer_name', $query);
|
return $this->whereLike('customer_name', $query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function customer($customer)
|
public function customers($customers)
|
||||||
{
|
{
|
||||||
return $this->where('customer_id', $customer);
|
return $this->whereIn('customer_id', (array) $customers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function status($status)
|
public function categories($categories)
|
||||||
{
|
{
|
||||||
return $this->where('invoice_status_code', $status);
|
return $this->whereIn('category_id', (array) $categories);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public function statuses($statuses)
|
||||||
|
{
|
||||||
|
return $this->whereIn('invoice_status_code', (array) $statuses);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function invoiceDate($date)
|
||||||
|
{
|
||||||
|
$dates = explode('_', $date);
|
||||||
|
$dates[0] .= ' 00:00:00';
|
||||||
|
$dates[1] .= ' 23:59:59';
|
||||||
|
|
||||||
|
return $this->whereBetween('invoiced_at', $dates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -19,18 +19,27 @@ class Revenues extends ModelFilter
|
|||||||
return $this->whereLike('description', $query);
|
return $this->whereLike('description', $query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function customer($customer)
|
public function customers($customers)
|
||||||
{
|
{
|
||||||
return $this->where('customer_id', $customer);
|
return $this->whereIn('customer_id', (array) $customers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function category($category)
|
public function categories($categories)
|
||||||
{
|
{
|
||||||
return $this->where('category_id', $category);
|
return $this->whereIn('category_id', (array) $categories);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function account($account)
|
public function accounts($accounts)
|
||||||
{
|
{
|
||||||
return $this->where('account_id', $account);
|
return $this->whereIn('account_id', (array) $accounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function date($date)
|
||||||
|
{
|
||||||
|
$dates = explode('_', $date);
|
||||||
|
$dates[0] .= ' 00:00:00';
|
||||||
|
$dates[1] .= ' 23:59:59';
|
||||||
|
|
||||||
|
return $this->whereBetween('paid_at', $dates);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,8 +19,8 @@ class Categories extends ModelFilter
|
|||||||
return $this->whereLike('name', $query);
|
return $this->whereLike('name', $query);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function type($type)
|
public function types($types)
|
||||||
{
|
{
|
||||||
return $this->where('type', $type);
|
return $this->whereIn('type', (array) $types);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers\Api\Incomes;
|
namespace App\Http\Controllers\Api\Incomes;
|
||||||
|
|
||||||
use App\Events\InvoiceCreated;
|
|
||||||
use App\Events\InvoiceUpdated;
|
use App\Events\InvoiceUpdated;
|
||||||
use App\Http\Controllers\ApiController;
|
use App\Http\Controllers\ApiController;
|
||||||
use App\Http\Requests\Income\Invoice as Request;
|
use App\Http\Requests\Income\Invoice as Request;
|
||||||
|
use App\Jobs\Income\CreateInvoice;
|
||||||
use App\Models\Income\Invoice;
|
use App\Models\Income\Invoice;
|
||||||
use App\Models\Income\InvoiceHistory;
|
use App\Models\Income\InvoiceHistory;
|
||||||
use App\Models\Income\InvoiceItem;
|
use App\Models\Income\InvoiceItem;
|
||||||
@ -13,13 +13,13 @@ use App\Models\Income\InvoicePayment;
|
|||||||
use App\Models\Income\InvoiceTotal;
|
use App\Models\Income\InvoiceTotal;
|
||||||
use App\Models\Common\Item;
|
use App\Models\Common\Item;
|
||||||
use App\Models\Setting\Tax;
|
use App\Models\Setting\Tax;
|
||||||
use App\Notifications\Common\Item as ItemNotification;
|
use App\Traits\Incomes;
|
||||||
use App\Transformers\Income\Invoice as Transformer;
|
use App\Transformers\Income\Invoice as Transformer;
|
||||||
use Dingo\Api\Routing\Helpers;
|
use Dingo\Api\Routing\Helpers;
|
||||||
|
|
||||||
class Invoices extends ApiController
|
class Invoices extends ApiController
|
||||||
{
|
{
|
||||||
use Helpers;
|
use Helpers, Incomes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
@ -63,114 +63,9 @@ class Invoices extends ApiController
|
|||||||
$request['amount'] = 0;
|
$request['amount'] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$invoice = Invoice::create($request->all());
|
$invoice = dispatch(new CreateInvoice($request));
|
||||||
|
|
||||||
$taxes = [];
|
return $this->response->created(url('api/invoices/' . $invoice->id));
|
||||||
$tax_total = 0;
|
|
||||||
$sub_total = 0;
|
|
||||||
|
|
||||||
$invoice_item = array();
|
|
||||||
$invoice_item['company_id'] = $request['company_id'];
|
|
||||||
$invoice_item['invoice_id'] = $invoice->id;
|
|
||||||
|
|
||||||
if ($request['item']) {
|
|
||||||
foreach ($request['item'] as $item) {
|
|
||||||
$item_id = 0;
|
|
||||||
$item_sku = '';
|
|
||||||
|
|
||||||
if (!empty($item['item_id'])) {
|
|
||||||
$item_object = Item::find($item['item_id']);
|
|
||||||
|
|
||||||
$item_id = $item['item_id'];
|
|
||||||
|
|
||||||
$item['name'] = $item_object->name;
|
|
||||||
$item_sku = $item_object->sku;
|
|
||||||
|
|
||||||
// Decrease stock (item sold)
|
|
||||||
$item_object->quantity -= $item['quantity'];
|
|
||||||
$item_object->save();
|
|
||||||
|
|
||||||
// Notify users if out of stock
|
|
||||||
if ($item_object->quantity == 0) {
|
|
||||||
foreach ($item_object->company->users as $user) {
|
|
||||||
if (!$user->can('read-notifications')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$user->notify(new ItemNotification($item_object));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} elseif (!empty($item['sku'])) {
|
|
||||||
$item_sku = $item['sku'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$tax = $tax_id = 0;
|
|
||||||
|
|
||||||
if (!empty($item['tax_id'])) {
|
|
||||||
$tax_object = Tax::find($item['tax_id']);
|
|
||||||
|
|
||||||
$tax_id = $item['tax_id'];
|
|
||||||
|
|
||||||
$tax = (($item['price'] * $item['quantity']) / 100) * $tax_object->rate;
|
|
||||||
} elseif (!empty($item['tax'])) {
|
|
||||||
$tax = $item['tax'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoice_item['item_id'] = $item_id;
|
|
||||||
$invoice_item['name'] = str_limit($item['name'], 180, '');
|
|
||||||
$invoice_item['sku'] = $item_sku;
|
|
||||||
$invoice_item['quantity'] = $item['quantity'];
|
|
||||||
$invoice_item['price'] = $item['price'];
|
|
||||||
$invoice_item['tax'] = $tax;
|
|
||||||
$invoice_item['tax_id'] = $tax_id;
|
|
||||||
$invoice_item['total'] = $item['price'] * $item['quantity'];
|
|
||||||
|
|
||||||
InvoiceItem::create($invoice_item);
|
|
||||||
|
|
||||||
if (isset($tax_object)) {
|
|
||||||
if (array_key_exists($tax_object->id, $taxes)) {
|
|
||||||
$taxes[$tax_object->id]['amount'] += $tax;
|
|
||||||
} else {
|
|
||||||
$taxes[$tax_object->id] = [
|
|
||||||
'name' => $tax_object->name,
|
|
||||||
'amount' => $tax
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$tax_total += $tax;
|
|
||||||
$sub_total += $invoice_item['total'];
|
|
||||||
|
|
||||||
unset($item_object);
|
|
||||||
unset($tax_object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($request['amount'])) {
|
|
||||||
$request['amount'] = $sub_total + $tax_total;
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoice->update($request->input());
|
|
||||||
|
|
||||||
// Add invoice totals
|
|
||||||
$this->addTotals($invoice, $request, $taxes, $sub_total, $tax_total);
|
|
||||||
|
|
||||||
$request['invoice_id'] = $invoice->id;
|
|
||||||
$request['status_code'] = $request['invoice_status_code'];
|
|
||||||
$request['notify'] = 0;
|
|
||||||
$request['description'] = trans('messages.success.added', ['type' => $request['invoice_number']]);
|
|
||||||
|
|
||||||
InvoiceHistory::create($request->input());
|
|
||||||
|
|
||||||
// Update next invoice number
|
|
||||||
$next = setting('general.invoice_number_next', 1) + 1;
|
|
||||||
setting(['general.invoice_number_next' => $next]);
|
|
||||||
setting()->save();
|
|
||||||
|
|
||||||
// Fire the event to make it extendible
|
|
||||||
event(new InvoiceCreated($invoice));
|
|
||||||
|
|
||||||
return $this->response->created(url('api/invoices/'.$invoice->id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -277,12 +172,9 @@ class Invoices extends ApiController
|
|||||||
*/
|
*/
|
||||||
public function destroy(Invoice $invoice)
|
public function destroy(Invoice $invoice)
|
||||||
{
|
{
|
||||||
|
$this->deleteRelationships($invoice, ['items', 'histories', 'payments', 'recurring', 'totals']);
|
||||||
$invoice->delete();
|
$invoice->delete();
|
||||||
|
|
||||||
InvoiceItem::where('invoice_id', $invoice->id)->delete();
|
|
||||||
InvoicePayment::where('invoice_id', $invoice->id)->delete();
|
|
||||||
InvoiceHistory::where('invoice_id', $invoice->id)->delete();
|
|
||||||
|
|
||||||
return $this->response->noContent();
|
return $this->response->noContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ class Login extends Controller
|
|||||||
public function store()
|
public function store()
|
||||||
{
|
{
|
||||||
// Attempt to login
|
// Attempt to login
|
||||||
if (!auth()->attempt(request(['email', 'password']))) {
|
if (!auth()->attempt(request(['email', 'password']), request('remember', false))) {
|
||||||
flash(trans('auth.failed'))->error();
|
flash(trans('auth.failed'))->error();
|
||||||
|
|
||||||
return back();
|
return back();
|
||||||
@ -79,6 +79,11 @@ class Login extends Controller
|
|||||||
return redirect($path);
|
return redirect($path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check wizard
|
||||||
|
if (!setting('general.wizard', false)) {
|
||||||
|
return redirect('wizard');
|
||||||
|
}
|
||||||
|
|
||||||
return redirect()->intended('/');
|
return redirect()->intended('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,9 +29,21 @@ class Roles extends Controller
|
|||||||
*/
|
*/
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
$permissions = Permission::all();
|
$names = $permissions = [];
|
||||||
|
$allPermissions = Permission::all();
|
||||||
|
|
||||||
return view('auth.roles.create', compact('permissions'));
|
foreach ($allPermissions as $permission) {
|
||||||
|
// permission code explode - and get permission type
|
||||||
|
$n = explode('-', $permission->name);
|
||||||
|
|
||||||
|
if (!in_array($n[0], $names)) {
|
||||||
|
$names[] = $n[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$permissions[$n[0]][] = $permission;
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('auth.roles.create', compact('names', 'permissions'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,11 +78,23 @@ class Roles extends Controller
|
|||||||
public function edit(Role $role)
|
public function edit(Role $role)
|
||||||
{
|
{
|
||||||
//$permissions = Permission::all()->sortBy('display_name');
|
//$permissions = Permission::all()->sortBy('display_name');
|
||||||
$permissions = Permission::all();
|
$names = $permissions = [];
|
||||||
|
$allPermissions = Permission::all();
|
||||||
|
|
||||||
$rolePermissions = $role->permissions->pluck('id', 'id')->toArray();
|
$rolePermissions = $role->permissions->pluck('id', 'id')->toArray();
|
||||||
|
|
||||||
return view('auth.roles.edit', compact('role', 'permissions', 'rolePermissions'));
|
foreach ($allPermissions as $permission) {
|
||||||
|
// permission code explode - and get permission type
|
||||||
|
$n = explode('-', $permission->name);
|
||||||
|
|
||||||
|
if (!in_array($n[0], $names)) {
|
||||||
|
$names[] = $n[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
$permissions[$n[0]][] = $permission;
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('auth.roles.edit', compact('role', 'names', 'permissions', 'rolePermissions'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -98,8 +98,15 @@ class Accounts extends Controller
|
|||||||
*/
|
*/
|
||||||
public function update(Account $account, Request $request)
|
public function update(Account $account, Request $request)
|
||||||
{
|
{
|
||||||
// Check if we can disable it
|
// Check if we can disable or change the code
|
||||||
if (!$request['enabled']) {
|
if (!$request['enabled'] || ($account->currency_code != $request['currency_code'])) {
|
||||||
|
$relationships = $this->countRelationships($account, [
|
||||||
|
'invoice_payments' => 'invoices',
|
||||||
|
'revenues' => 'revenues',
|
||||||
|
'bill_payments' => 'bills',
|
||||||
|
'payments' => 'payments',
|
||||||
|
]);
|
||||||
|
|
||||||
if ($account->id == setting('general.default_account')) {
|
if ($account->id == setting('general.default_account')) {
|
||||||
$relationships[] = strtolower(trans_choice('general.companies', 1));
|
$relationships[] = strtolower(trans_choice('general.companies', 1));
|
||||||
}
|
}
|
||||||
@ -120,7 +127,7 @@ class Accounts extends Controller
|
|||||||
|
|
||||||
return redirect('banking/accounts');
|
return redirect('banking/accounts');
|
||||||
} else {
|
} else {
|
||||||
$message = trans('messages.warning.disabled', ['name' => $account->name, 'text' => implode(', ', $relationships)]);
|
$message = trans('messages.warning.disable_code', ['name' => $account->name, 'text' => implode(', ', $relationships)]);
|
||||||
|
|
||||||
flash($message)->warning();
|
flash($message)->warning();
|
||||||
|
|
||||||
|
315
app/Http/Controllers/Banking/Reconciliations.php
Normal file
315
app/Http/Controllers/Banking/Reconciliations.php
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Banking;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\Banking\Reconciliation as Request;
|
||||||
|
use App\Models\Banking\Account;
|
||||||
|
use App\Models\Banking\Reconciliation;
|
||||||
|
use App\Models\Setting\Currency;
|
||||||
|
use Date;
|
||||||
|
|
||||||
|
class Reconciliations extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display a listing of the resource.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$reconciliations = Reconciliation::collect();
|
||||||
|
|
||||||
|
$accounts = collect(Account::enabled()->orderBy('name')->pluck('name', 'id'));
|
||||||
|
|
||||||
|
return view('banking.reconciliations.index', compact('reconciliations', 'accounts'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for viewing the specified resource.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function show()
|
||||||
|
{
|
||||||
|
return redirect()->route('reconciliations.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
$accounts = Account::enabled()->pluck('name', 'id');
|
||||||
|
|
||||||
|
$account_id = request('account_id', setting('general.default_account'));
|
||||||
|
$started_at = request('started_at', '0000-00-00');
|
||||||
|
$ended_at = request('ended_at', '0000-00-00');
|
||||||
|
|
||||||
|
$account = Account::find($account_id);
|
||||||
|
|
||||||
|
$currency = $account->currency;
|
||||||
|
|
||||||
|
$transactions = $this->getTransactions($account, $started_at, $ended_at);
|
||||||
|
|
||||||
|
$opening_balance = $this->getOpeningBalance($account, $started_at, $ended_at);
|
||||||
|
|
||||||
|
return view('banking.reconciliations.create', compact('accounts', 'account', 'currency', 'opening_balance', 'transactions'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$reconcile = $request->get('reconcile');
|
||||||
|
$transactions = $request->get('transactions');
|
||||||
|
|
||||||
|
Reconciliation::create([
|
||||||
|
'company_id' => session('company_id'),
|
||||||
|
'account_id' => $request->get('account_id'),
|
||||||
|
'started_at' => $request->get('started_at'),
|
||||||
|
'ended_at' => $request->get('ended_at'),
|
||||||
|
'closing_balance' => $request->get('closing_balance'),
|
||||||
|
'reconciled' => $reconcile ? 1 : 0,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($transactions) {
|
||||||
|
foreach ($transactions as $key => $value) {
|
||||||
|
$t = explode('_', $key);
|
||||||
|
$m = '\\' . $t['1'];
|
||||||
|
|
||||||
|
$transaction = $m::find($t[0]);
|
||||||
|
$transaction->reconciled = 1;
|
||||||
|
$transaction->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = trans('messages.success.added', ['type' => trans_choice('general.reconciliations', 1)]);
|
||||||
|
|
||||||
|
flash($message)->success();
|
||||||
|
|
||||||
|
return redirect()->route('reconciliations.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*
|
||||||
|
* @param Reconciliation $reconciliation
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function edit(Reconciliation $reconciliation)
|
||||||
|
{
|
||||||
|
$account = $reconciliation->account;
|
||||||
|
|
||||||
|
$currency = $account->currency;
|
||||||
|
|
||||||
|
$transactions = $this->getTransactions($account, $reconciliation->started_at, $reconciliation->ended_at);
|
||||||
|
|
||||||
|
$opening_balance = $this->getOpeningBalance($account, $reconciliation->started_at, $reconciliation->ended_at);
|
||||||
|
|
||||||
|
return view('banking.reconciliations.edit', compact('reconciliation', 'account', 'currency', 'opening_balance', 'transactions'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param Reconciliation $reconciliation
|
||||||
|
* @param Request $request
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function update(Reconciliation $reconciliation, Request $request)
|
||||||
|
{
|
||||||
|
$reconcile = $request->get('reconcile');
|
||||||
|
$transactions = $request->get('transactions');
|
||||||
|
|
||||||
|
$reconciliation->reconciled = $reconcile ? 1 : 0;
|
||||||
|
$reconciliation->save();
|
||||||
|
|
||||||
|
if ($transactions) {
|
||||||
|
foreach ($transactions as $key => $value) {
|
||||||
|
$t = explode('_', $key);
|
||||||
|
$m = '\\' . $t['1'];
|
||||||
|
|
||||||
|
$transaction = $m::find($t[0]);
|
||||||
|
$transaction->reconciled = 1;
|
||||||
|
$transaction->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = trans('messages.success.updated', ['type' => trans_choice('general.reconciliations', 1)]);
|
||||||
|
|
||||||
|
flash($message)->success();
|
||||||
|
|
||||||
|
return redirect()->route('reconciliations.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*
|
||||||
|
* @param Reconciliation $reconciliation
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function destroy(Reconciliation $reconciliation)
|
||||||
|
{
|
||||||
|
$reconciliation->delete();
|
||||||
|
|
||||||
|
$models = [
|
||||||
|
'App\Models\Expense\Payment',
|
||||||
|
'App\Models\Expense\BillPayment',
|
||||||
|
'App\Models\Income\Revenue',
|
||||||
|
'App\Models\Income\InvoicePayment',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($models as $model) {
|
||||||
|
$m = '\\' . $model;
|
||||||
|
|
||||||
|
$m::where('account_id', $reconciliation->account_id)
|
||||||
|
->reconciled()
|
||||||
|
->whereBetween('paid_at', [$reconciliation->started_at, $reconciliation->ended_at])->each(function ($item) {
|
||||||
|
$item->reconciled = 0;
|
||||||
|
$item->save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = trans('messages.success.deleted', ['type' => trans_choice('general.reconciliations', 1)]);
|
||||||
|
|
||||||
|
flash($message)->success();
|
||||||
|
|
||||||
|
return redirect()->route('reconciliations.index');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add transactions array.
|
||||||
|
*
|
||||||
|
* @param $account_id
|
||||||
|
* @param $started_at
|
||||||
|
* @param $ended_at
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getTransactions($account, $started_at, $ended_at)
|
||||||
|
{
|
||||||
|
$started = explode(' ', $started_at);
|
||||||
|
$ended = explode(' ', $ended_at);
|
||||||
|
|
||||||
|
$models = [
|
||||||
|
'App\Models\Expense\Payment',
|
||||||
|
'App\Models\Expense\BillPayment',
|
||||||
|
'App\Models\Income\Revenue',
|
||||||
|
'App\Models\Income\InvoicePayment',
|
||||||
|
];
|
||||||
|
|
||||||
|
$transactions = [];
|
||||||
|
|
||||||
|
foreach ($models as $model) {
|
||||||
|
$m = '\\' . $model;
|
||||||
|
|
||||||
|
$m::where('account_id', $account->id)->whereBetween('paid_at', [$started[0], $ended[0]])->each(function($item) use(&$transactions, $model) {
|
||||||
|
$item->model = $model;
|
||||||
|
|
||||||
|
if (($model == 'App\Models\Income\Invoice') || ($model == 'App\Models\Income\Revenue')) {
|
||||||
|
if ($item->invoice) {
|
||||||
|
$item->contact = $item->invoice->customer;
|
||||||
|
} else {
|
||||||
|
$item->contact = $item->customer;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($item->bill) {
|
||||||
|
$item->contact = $item->bill->vendor;
|
||||||
|
} else {
|
||||||
|
$item->contact = $item->vendor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$transactions[] = $item;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return collect($transactions)->sortByDesc('paid_at');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the opening balance
|
||||||
|
*
|
||||||
|
* @param $account
|
||||||
|
* @param $started_at
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getOpeningBalance($account, $started_at)
|
||||||
|
{
|
||||||
|
// Opening Balance
|
||||||
|
$total = $account->opening_balance;
|
||||||
|
|
||||||
|
// Sum invoices
|
||||||
|
$invoice_payments = $account->invoice_payments()->whereDate('paid_at', '<', $started_at)->get();
|
||||||
|
foreach ($invoice_payments as $item) {
|
||||||
|
$total += $item->amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sum revenues
|
||||||
|
$revenues = $account->revenues()->whereDate('paid_at', '<', $started_at)->get();
|
||||||
|
foreach ($revenues as $item) {
|
||||||
|
$total += $item->amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtract bills
|
||||||
|
$bill_payments = $account->bill_payments()->whereDate('paid_at', '<', $started_at)->get();
|
||||||
|
foreach ($bill_payments as $item) {
|
||||||
|
$total -= $item->amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtract payments
|
||||||
|
$payments = $account->payments()->whereDate('paid_at', '<', $started_at)->get();
|
||||||
|
foreach ($payments as $item) {
|
||||||
|
$total -= $item->amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function calculate()
|
||||||
|
{
|
||||||
|
$currency_code = request('currency_code');
|
||||||
|
$closing_balance = request('closing_balance');
|
||||||
|
|
||||||
|
$json = new \stdClass();
|
||||||
|
|
||||||
|
$cleared_amount = $difference = $income_total = $expense_total = 0;
|
||||||
|
|
||||||
|
if ($transactions = request('transactions')) {
|
||||||
|
$opening_balance = request('opening_balance');
|
||||||
|
|
||||||
|
foreach ($transactions as $key => $value) {
|
||||||
|
$model = explode('_', $key);
|
||||||
|
|
||||||
|
if (($model[1] == 'App\Models\Income\Invoice') || ($model[1] == 'App\Models\Income\Revenue')) {
|
||||||
|
$income_total += $value;
|
||||||
|
} else {
|
||||||
|
$expense_total += $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$cleared_amount = $opening_balance + ($income_total - $expense_total);
|
||||||
|
}
|
||||||
|
|
||||||
|
$difference = $closing_balance - $cleared_amount;
|
||||||
|
|
||||||
|
$json->closing_balance = money($closing_balance, $currency_code, true)->format();
|
||||||
|
$json->cleared_amount = money($cleared_amount, $currency_code, true)->format();
|
||||||
|
$json->difference = money($difference, $currency_code, true)->format();
|
||||||
|
$json->difference_raw = (int) $difference;
|
||||||
|
|
||||||
|
return response()->json($json);
|
||||||
|
}
|
||||||
|
}
|
@ -25,25 +25,24 @@ class Transactions extends Controller
|
|||||||
{
|
{
|
||||||
$request = request();
|
$request = request();
|
||||||
|
|
||||||
$accounts = collect(Account::enabled()->pluck('name', 'id'))
|
$accounts = collect(Account::enabled()->pluck('name', 'id'));
|
||||||
->prepend(trans('general.all_type', ['type' => trans_choice('general.accounts', 2)]), '');
|
|
||||||
|
|
||||||
$types = collect(['expense' => 'Expense', 'income' => 'Income'])
|
$types = collect(['expense' => 'Expense', 'income' => 'Income'])
|
||||||
->prepend(trans('general.all_type', ['type' => trans_choice('general.types', 2)]), '');
|
->prepend(trans('general.all_type', ['type' => trans_choice('general.types', 2)]), '');
|
||||||
|
|
||||||
$categories = collect(Category::enabled()->type('income')->pluck('name', 'id'))
|
|
||||||
->prepend(trans('general.all_type', ['type' => trans_choice('general.categories', 2)]), '');
|
|
||||||
|
|
||||||
$type = $request->get('type');
|
$type = $request->get('type');
|
||||||
|
|
||||||
|
$type_cats = empty($type) ? ['income', 'expense'] : $type;
|
||||||
|
$categories = collect(Category::enabled()->type($type_cats)->pluck('name', 'id'));
|
||||||
|
|
||||||
if ($type != 'income') {
|
if ($type != 'income') {
|
||||||
$this->addTransactions(Payment::collect(['paid_at'=> 'desc']), trans_choice('general.expenses', 1));
|
$this->addTransactions(Payment::collect(['paid_at'=> 'desc']), trans_choice('general.expenses', 1));
|
||||||
$this->addTransactions(BillPayment::collect(['paid_at'=> 'desc']), trans_choice('general.expenses', 1), trans_choice('general.bills', 1));
|
$this->addTransactions(BillPayment::collect(['paid_at'=> 'desc']), trans_choice('general.expenses', 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($type != 'expense') {
|
if ($type != 'expense') {
|
||||||
$this->addTransactions(Revenue::collect(['paid_at'=> 'desc']), trans_choice('general.incomes', 1));
|
$this->addTransactions(Revenue::collect(['paid_at'=> 'desc']), trans_choice('general.incomes', 1));
|
||||||
$this->addTransactions(InvoicePayment::collect(['paid_at'=> 'desc']), trans_choice('general.incomes', 1), trans_choice('general.invoices', 1));
|
$this->addTransactions(InvoicePayment::collect(['paid_at'=> 'desc']), trans_choice('general.incomes', 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
$transactions = $this->getTransactions($request);
|
$transactions = $this->getTransactions($request);
|
||||||
@ -56,27 +55,29 @@ class Transactions extends Controller
|
|||||||
*
|
*
|
||||||
* @param $items
|
* @param $items
|
||||||
* @param $type
|
* @param $type
|
||||||
* @param $category
|
|
||||||
*/
|
*/
|
||||||
protected function addTransactions($items, $type, $category = null)
|
protected function addTransactions($items, $type)
|
||||||
{
|
{
|
||||||
foreach ($items as $item) {
|
foreach ($items as $item) {
|
||||||
$data = [
|
if (!empty($item->category)) {
|
||||||
|
$category_name = ($item->category) ? $item->category->name : trans('general.na');
|
||||||
|
} else {
|
||||||
|
if ($type == trans_choice('general.incomes', 1)) {
|
||||||
|
$category_name = ($item->invoice->category) ? $item->invoice->category->name : trans('general.na');
|
||||||
|
} else {
|
||||||
|
$category_name = ($item->bill->category) ? $item->bill->category->name : trans('general.na');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->transactions[] = (object) [
|
||||||
'paid_at' => $item->paid_at,
|
'paid_at' => $item->paid_at,
|
||||||
'account_name' => $item->account->name,
|
'account_name' => $item->account->name,
|
||||||
'type' => $type,
|
'type' => $type,
|
||||||
'description' => $item->description,
|
'description' => $item->description,
|
||||||
'amount' => $item->amount,
|
'amount' => $item->amount,
|
||||||
'currency_code' => $item->currency_code,
|
'currency_code' => $item->currency_code,
|
||||||
|
'category_name' => $category_name,
|
||||||
];
|
];
|
||||||
|
|
||||||
if (!is_null($category)) {
|
|
||||||
$data['category_name'] = $category;
|
|
||||||
} else {
|
|
||||||
$data['category_name'] = $item->category->name;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->transactions[] = (object) $data;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,6 +264,11 @@ class Companies extends Controller
|
|||||||
event(new CompanySwitched($company));
|
event(new CompanySwitched($company));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check wizard
|
||||||
|
if (!setting('general.wizard', false)) {
|
||||||
|
return redirect('wizard');
|
||||||
|
}
|
||||||
|
|
||||||
return redirect('/');
|
return redirect('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,6 +126,7 @@ class Dashboard extends Controller
|
|||||||
$start = Date::parse(request('start', $this->today->startOfYear()->format('Y-m-d')));
|
$start = Date::parse(request('start', $this->today->startOfYear()->format('Y-m-d')));
|
||||||
$end = Date::parse(request('end', $this->today->endOfYear()->format('Y-m-d')));
|
$end = Date::parse(request('end', $this->today->endOfYear()->format('Y-m-d')));
|
||||||
$period = request('period', 'month');
|
$period = request('period', 'month');
|
||||||
|
$range = request('range', 'custom');
|
||||||
|
|
||||||
$start_month = $start->month;
|
$start_month = $start->month;
|
||||||
$end_month = $end->month;
|
$end_month = $end->month;
|
||||||
@ -135,6 +136,14 @@ class Dashboard extends Controller
|
|||||||
|
|
||||||
$s = clone $start;
|
$s = clone $start;
|
||||||
|
|
||||||
|
if ($range == 'last_12_months') {
|
||||||
|
$end_month = 12;
|
||||||
|
$start_month = 0;
|
||||||
|
} elseif ($range == 'custom') {
|
||||||
|
$end_month = $end->diffInMonths($start);
|
||||||
|
$start_month = 0;
|
||||||
|
}
|
||||||
|
|
||||||
for ($j = $end_month; $j >= $start_month; $j--) {
|
for ($j = $end_month; $j >= $start_month; $j--) {
|
||||||
$labels[$end_month - $j] = $s->format('M Y');
|
$labels[$end_month - $j] = $s->format('M Y');
|
||||||
|
|
||||||
|
@ -26,8 +26,7 @@ class Items extends Controller
|
|||||||
{
|
{
|
||||||
$items = Item::with('category')->collect();
|
$items = Item::with('category')->collect();
|
||||||
|
|
||||||
$categories = Category::enabled()->orderBy('name')->type('item')->pluck('name', 'id')
|
$categories = Category::enabled()->orderBy('name')->type('item')->pluck('name', 'id');
|
||||||
->prepend(trans('general.all_type', ['type' => trans_choice('general.categories', 2)]), '');
|
|
||||||
|
|
||||||
return view('common.items.index', compact('items', 'categories'));
|
return view('common.items.index', compact('items', 'categories'));
|
||||||
}
|
}
|
||||||
@ -51,7 +50,7 @@ class Items extends Controller
|
|||||||
{
|
{
|
||||||
$categories = Category::enabled()->orderBy('name')->type('item')->pluck('name', 'id');
|
$categories = Category::enabled()->orderBy('name')->type('item')->pluck('name', 'id');
|
||||||
|
|
||||||
$taxes = Tax::enabled()->orderBy('rate')->get()->pluck('title', 'id');
|
$taxes = Tax::enabled()->orderBy('name')->get()->pluck('title', 'id');
|
||||||
|
|
||||||
$currency = Currency::where('code', '=', setting('general.default_currency', 'USD'))->first();
|
$currency = Currency::where('code', '=', setting('general.default_currency', 'USD'))->first();
|
||||||
|
|
||||||
@ -132,7 +131,7 @@ class Items extends Controller
|
|||||||
{
|
{
|
||||||
$categories = Category::enabled()->orderBy('name')->type('item')->pluck('name', 'id');
|
$categories = Category::enabled()->orderBy('name')->type('item')->pluck('name', 'id');
|
||||||
|
|
||||||
$taxes = Tax::enabled()->orderBy('rate')->get()->pluck('title', 'id');
|
$taxes = Tax::enabled()->orderBy('name')->get()->pluck('title', 'id');
|
||||||
|
|
||||||
$currency = Currency::where('code', '=', setting('general.default_currency', 'USD'))->first();
|
$currency = Currency::where('code', '=', setting('general.default_currency', 'USD'))->first();
|
||||||
|
|
||||||
@ -323,22 +322,83 @@ class Items extends Controller
|
|||||||
$price = (double) $item['price'];
|
$price = (double) $item['price'];
|
||||||
$quantity = (double) $item['quantity'];
|
$quantity = (double) $item['quantity'];
|
||||||
|
|
||||||
$item_tax_total= 0;
|
$item_tax_total = 0;
|
||||||
|
$item_tax_amount = 0;
|
||||||
|
|
||||||
$item_sub_total = ($price * $quantity);
|
$item_sub_total = ($price * $quantity);
|
||||||
|
$item_discount_total = $item_sub_total;
|
||||||
|
|
||||||
|
// Apply discount to item
|
||||||
|
if ($discount) {
|
||||||
|
$item_discount_total = $item_sub_total - ($item_sub_total * ($discount / 100));
|
||||||
|
}
|
||||||
|
|
||||||
if (!empty($item['tax_id'])) {
|
if (!empty($item['tax_id'])) {
|
||||||
$tax = Tax::find($item['tax_id']);
|
$inclusives = $compounds = $taxes = [];
|
||||||
|
|
||||||
$item_tax_total = (($price * $quantity) / 100) * $tax->rate;
|
foreach ($item['tax_id'] as $tax_id) {
|
||||||
|
$tax = Tax::find($tax_id);
|
||||||
|
|
||||||
|
switch ($tax->type) {
|
||||||
|
case 'inclusive':
|
||||||
|
$inclusives[] = $tax;
|
||||||
|
break;
|
||||||
|
case 'compound':
|
||||||
|
$compounds[] = $tax;
|
||||||
|
break;
|
||||||
|
case 'normal':
|
||||||
|
default:
|
||||||
|
$taxes[] = $tax;
|
||||||
|
|
||||||
|
$item_tax_amount = ($item_discount_total / 100) * $tax->rate;
|
||||||
|
|
||||||
|
$item_tax_total += $item_tax_amount;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($inclusives) {
|
||||||
|
if ($discount) {
|
||||||
|
$item_tax_total = 0;
|
||||||
|
|
||||||
|
if ($taxes) {
|
||||||
|
foreach ($taxes as $tax) {
|
||||||
|
$item_tax_amount = ($item_sub_total / 100) * $tax->rate;
|
||||||
|
|
||||||
|
$item_tax_total += $item_tax_amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($inclusives as $inclusive) {
|
||||||
|
$item_sub_and_tax_total = $item_sub_total + $item_tax_total;
|
||||||
|
|
||||||
|
$item_tax_total = $item_sub_and_tax_total - (($item_sub_and_tax_total * (100 - $inclusive->rate)) / 100);
|
||||||
|
|
||||||
|
$item_sub_total = $item_sub_and_tax_total - $item_tax_total;
|
||||||
|
|
||||||
|
$item_discount_total = $item_sub_total - ($item_sub_total * ($discount / 100));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach ($inclusives as $inclusive) {
|
||||||
|
$item_sub_and_tax_total = $item_discount_total + $item_tax_total;
|
||||||
|
|
||||||
|
$item_tax_total = $item_sub_and_tax_total - (($item_sub_and_tax_total * (100 - $inclusive->rate)) / 100);
|
||||||
|
|
||||||
|
$item_sub_total = $item_sub_and_tax_total - $item_tax_total;
|
||||||
|
|
||||||
|
$item_discount_total = $item_sub_total - ($item_sub_total * ($discount / 100));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($compounds) {
|
||||||
|
foreach ($compounds as $compound) {
|
||||||
|
$item_tax_total += (($item_discount_total + $item_tax_total) / 100) * $compound->rate;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$sub_total += $item_sub_total;
|
$sub_total += $item_sub_total;
|
||||||
|
|
||||||
// Apply discount to tax
|
|
||||||
if ($discount) {
|
|
||||||
$item_tax_total = $item_tax_total - ($item_tax_total * ($discount / 100));
|
|
||||||
}
|
|
||||||
|
|
||||||
$tax_total += $item_tax_total;
|
$tax_total += $item_tax_total;
|
||||||
|
|
||||||
$items[$key] = money($item_sub_total, $currency_code, true)->format();
|
$items[$key] = money($item_sub_total, $currency_code, true)->format();
|
||||||
|
70
app/Http/Controllers/Common/Notifications.php
Normal file
70
app/Http/Controllers/Common/Notifications.php
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Common;
|
||||||
|
|
||||||
|
use Date;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Traits\Modules as RemoteModules;
|
||||||
|
use App\Http\Requests\Common\Notification as Request;
|
||||||
|
|
||||||
|
class Notifications extends Controller
|
||||||
|
{
|
||||||
|
use RemoteModules;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a listing of the resource.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$notifications = setting('notifications');
|
||||||
|
|
||||||
|
return view('common.notifications.index', compact('notifications'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for viewing the specified resource.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function show($path, $id)
|
||||||
|
{
|
||||||
|
$notification = setting('notifications.' . $path . '.' . $id);
|
||||||
|
|
||||||
|
return view('common.notifications.show', compact('notification'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable the specified resource.
|
||||||
|
*
|
||||||
|
* @param Company $company
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function disable(Request $request)
|
||||||
|
{
|
||||||
|
$id = $request['id'];
|
||||||
|
$path = str_replace('#', '/', $request['path']);
|
||||||
|
|
||||||
|
$notifications = $this->getNotifications($path);
|
||||||
|
|
||||||
|
foreach ($notifications as $notification) {
|
||||||
|
if ($notification->id == $id) {
|
||||||
|
setting()->set('notifications.'. $path . '.' . $id . '.name', $notification->name);
|
||||||
|
setting()->set('notifications.'. $path . '.' . $id . '.message', $notification->message);
|
||||||
|
setting()->set('notifications.'. $path . '.' . $id . '.date', Date::now());
|
||||||
|
setting()->set('notifications.'. $path . '.' . $id . '.status', '0');
|
||||||
|
|
||||||
|
setting()->save();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'data' => null,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -91,6 +91,10 @@ class Uploads extends Controller
|
|||||||
*/
|
*/
|
||||||
protected function getPath($media)
|
protected function getPath($media)
|
||||||
{
|
{
|
||||||
|
if (!is_object($media)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
$path = $media->basename;
|
$path = $media->basename;
|
||||||
|
|
||||||
if (!empty($media->directory)) {
|
if (!empty($media->directory)) {
|
||||||
|
@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
|
|||||||
use App\Events\InvoicePrinting;
|
use App\Events\InvoicePrinting;
|
||||||
use App\Models\Banking\Account;
|
use App\Models\Banking\Account;
|
||||||
use App\Models\Income\Customer;
|
use App\Models\Income\Customer;
|
||||||
|
use App\Models\Income\Revenue;
|
||||||
use App\Models\Income\Invoice;
|
use App\Models\Income\Invoice;
|
||||||
use App\Models\Income\InvoiceStatus;
|
use App\Models\Income\InvoiceStatus;
|
||||||
use App\Models\Setting\Category;
|
use App\Models\Setting\Category;
|
||||||
@ -16,8 +17,10 @@ use App\Traits\DateTime;
|
|||||||
use App\Traits\Uploads;
|
use App\Traits\Uploads;
|
||||||
use App\Utilities\Modules;
|
use App\Utilities\Modules;
|
||||||
use File;
|
use File;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use Image;
|
use Image;
|
||||||
use Storage;
|
use Storage;
|
||||||
|
use SignedUrl;
|
||||||
|
|
||||||
class Invoices extends Controller
|
class Invoices extends Controller
|
||||||
{
|
{
|
||||||
@ -178,4 +181,52 @@ class Invoices extends Controller
|
|||||||
|
|
||||||
return $logo;
|
return $logo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function link(Invoice $invoice, Request $request)
|
||||||
|
{
|
||||||
|
session(['company_id' => $invoice->company_id]);
|
||||||
|
|
||||||
|
$paid = 0;
|
||||||
|
|
||||||
|
foreach ($invoice->payments as $item) {
|
||||||
|
$amount = $item->amount;
|
||||||
|
|
||||||
|
if ($invoice->currency_code != $item->currency_code) {
|
||||||
|
$item->default_currency_code = $invoice->currency_code;
|
||||||
|
|
||||||
|
$amount = $item->getDynamicConvertedAmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
$paid += $amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoice->paid = $paid;
|
||||||
|
|
||||||
|
$accounts = Account::enabled()->pluck('name', 'id');
|
||||||
|
|
||||||
|
$currencies = Currency::enabled()->pluck('name', 'code')->toArray();
|
||||||
|
|
||||||
|
$account_currency_code = Account::where('id', setting('general.default_account'))->pluck('currency_code')->first();
|
||||||
|
|
||||||
|
$customers = Customer::enabled()->pluck('name', 'id');
|
||||||
|
|
||||||
|
$categories = Category::enabled()->type('income')->pluck('name', 'id');
|
||||||
|
|
||||||
|
$payment_methods = Modules::getPaymentMethods();
|
||||||
|
|
||||||
|
$payment_actions = [];
|
||||||
|
|
||||||
|
foreach ($payment_methods as $payment_method_key => $payment_method_value) {
|
||||||
|
$codes = explode('.', $payment_method_key);
|
||||||
|
|
||||||
|
if (!isset($payment_actions[$codes[0]])) {
|
||||||
|
$payment_actions[$codes[0]] = SignedUrl::sign(url('links/invoices/' . $invoice->id . '/' . $codes[0]), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$print_action = SignedUrl::sign(url('links/invoices/' . $invoice->id . '/print'), 1);
|
||||||
|
$pdf_action = SignedUrl::sign(url('links/invoices/' . $invoice->id . '/pdf'), 1);
|
||||||
|
|
||||||
|
return view('customers.invoices.link', compact('invoice', 'accounts', 'currencies', 'account_currency_code', 'customers', 'categories', 'payment_methods', 'payment_actions', 'print_action', 'pdf_action'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,12 +8,16 @@ use App\Events\BillUpdated;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\Expense\Bill as Request;
|
use App\Http\Requests\Expense\Bill as Request;
|
||||||
use App\Http\Requests\Expense\BillPayment as PaymentRequest;
|
use App\Http\Requests\Expense\BillPayment as PaymentRequest;
|
||||||
|
use App\Jobs\Expense\CreateBill;
|
||||||
|
use App\Jobs\Expense\UpdateBill;
|
||||||
|
use App\Jobs\Expense\CreateBillPayment;
|
||||||
use App\Models\Banking\Account;
|
use App\Models\Banking\Account;
|
||||||
use App\Models\Common\Media;
|
use App\Models\Common\Media;
|
||||||
use App\Models\Expense\BillStatus;
|
use App\Models\Expense\BillStatus;
|
||||||
use App\Models\Expense\Vendor;
|
use App\Models\Expense\Vendor;
|
||||||
use App\Models\Expense\Bill;
|
use App\Models\Expense\Bill;
|
||||||
use App\Models\Expense\BillItem;
|
use App\Models\Expense\BillItem;
|
||||||
|
use App\Models\Expense\BillItemTax;
|
||||||
use App\Models\Expense\BillTotal;
|
use App\Models\Expense\BillTotal;
|
||||||
use App\Models\Expense\BillHistory;
|
use App\Models\Expense\BillHistory;
|
||||||
use App\Models\Expense\BillPayment;
|
use App\Models\Expense\BillPayment;
|
||||||
@ -46,13 +50,13 @@ class Bills extends Controller
|
|||||||
{
|
{
|
||||||
$bills = Bill::with(['vendor', 'status', 'items', 'payments', 'histories'])->collect(['billed_at'=> 'desc']);
|
$bills = Bill::with(['vendor', 'status', 'items', 'payments', 'histories'])->collect(['billed_at'=> 'desc']);
|
||||||
|
|
||||||
$vendors = collect(Vendor::enabled()->orderBy('name')->pluck('name', 'id'))
|
$vendors = collect(Vendor::enabled()->orderBy('name')->pluck('name', 'id'));
|
||||||
->prepend(trans('general.all_type', ['type' => trans_choice('general.vendors', 2)]), '');
|
|
||||||
|
|
||||||
$statuses = collect(BillStatus::all()->pluck('name', 'code'))
|
$categories = collect(Category::enabled()->type('expense')->orderBy('name')->pluck('name', 'id'));
|
||||||
->prepend(trans('general.all_type', ['type' => trans_choice('general.statuses', 2)]), '');
|
|
||||||
|
|
||||||
return view('expenses.bills.index', compact('bills', 'vendors', 'statuses'));
|
$statuses = collect(BillStatus::all()->pluck('name', 'code'));
|
||||||
|
|
||||||
|
return view('expenses.bills.index', compact('bills', 'vendors', 'categories', 'statuses'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,43 +68,6 @@ class Bills extends Controller
|
|||||||
*/
|
*/
|
||||||
public function show(Bill $bill)
|
public function show(Bill $bill)
|
||||||
{
|
{
|
||||||
$paid = 0;
|
|
||||||
|
|
||||||
// Get Bill Payments
|
|
||||||
if ($bill->payments->count()) {
|
|
||||||
$_currencies = Currency::enabled()->pluck('rate', 'code')->toArray();
|
|
||||||
|
|
||||||
foreach ($bill->payments as $item) {
|
|
||||||
$default_amount = (double) $item->amount;
|
|
||||||
|
|
||||||
if ($bill->currency_code == $item->currency_code) {
|
|
||||||
$amount = $default_amount;
|
|
||||||
} else {
|
|
||||||
$default_amount_model = new BillPayment();
|
|
||||||
|
|
||||||
$default_amount_model->default_currency_code = $bill->currency_code;
|
|
||||||
$default_amount_model->amount = $default_amount;
|
|
||||||
$default_amount_model->currency_code = $item->currency_code;
|
|
||||||
$default_amount_model->currency_rate = $_currencies[$item->currency_code];
|
|
||||||
|
|
||||||
$default_amount = (double) $default_amount_model->getDivideConvertedAmount();
|
|
||||||
|
|
||||||
$convert_amount = new BillPayment();
|
|
||||||
|
|
||||||
$convert_amount->default_currency_code = $item->currency_code;
|
|
||||||
$convert_amount->amount = $default_amount;
|
|
||||||
$convert_amount->currency_code = $bill->currency_code;
|
|
||||||
$convert_amount->currency_rate = $_currencies[$bill->currency_code];
|
|
||||||
|
|
||||||
$amount = (double) $convert_amount->getDynamicConvertedAmount();
|
|
||||||
}
|
|
||||||
|
|
||||||
$paid += $amount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$bill->paid = $paid;
|
|
||||||
|
|
||||||
$accounts = Account::enabled()->orderBy('name')->pluck('name', 'id');
|
$accounts = Account::enabled()->orderBy('name')->pluck('name', 'id');
|
||||||
|
|
||||||
$currencies = Currency::enabled()->orderBy('name')->pluck('name', 'code')->toArray();
|
$currencies = Currency::enabled()->orderBy('name')->pluck('name', 'code')->toArray();
|
||||||
@ -131,7 +98,7 @@ class Bills extends Controller
|
|||||||
|
|
||||||
$items = Item::enabled()->orderBy('name')->pluck('name', 'id');
|
$items = Item::enabled()->orderBy('name')->pluck('name', 'id');
|
||||||
|
|
||||||
$taxes = Tax::enabled()->orderBy('rate')->get()->pluck('title', 'id');
|
$taxes = Tax::enabled()->orderBy('name')->get()->pluck('title', 'id');
|
||||||
|
|
||||||
$categories = Category::enabled()->type('expense')->orderBy('name')->pluck('name', 'id');
|
$categories = Category::enabled()->type('expense')->orderBy('name')->pluck('name', 'id');
|
||||||
|
|
||||||
@ -147,120 +114,7 @@ class Bills extends Controller
|
|||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
$bill = Bill::create($request->input());
|
$bill = dispatch(new CreateBill($request));
|
||||||
|
|
||||||
// Upload attachment
|
|
||||||
if ($request->file('attachment')) {
|
|
||||||
$media = $this->getMedia($request->file('attachment'), 'bills');
|
|
||||||
|
|
||||||
$bill->attachMedia($media, 'attachment');
|
|
||||||
}
|
|
||||||
|
|
||||||
$taxes = [];
|
|
||||||
|
|
||||||
$tax_total = 0;
|
|
||||||
$sub_total = 0;
|
|
||||||
$discount_total = 0;
|
|
||||||
$discount = $request['discount'];
|
|
||||||
|
|
||||||
$bill_item = [];
|
|
||||||
$bill_item['company_id'] = $request['company_id'];
|
|
||||||
$bill_item['bill_id'] = $bill->id;
|
|
||||||
|
|
||||||
if ($request['item']) {
|
|
||||||
foreach ($request['item'] as $item) {
|
|
||||||
unset($tax_object);
|
|
||||||
$item_sku = '';
|
|
||||||
|
|
||||||
if (!empty($item['item_id'])) {
|
|
||||||
$item_object = Item::find($item['item_id']);
|
|
||||||
|
|
||||||
$item['name'] = $item_object->name;
|
|
||||||
$item_sku = $item_object->sku;
|
|
||||||
|
|
||||||
// Increase stock (item bought)
|
|
||||||
$item_object->quantity += $item['quantity'];
|
|
||||||
$item_object->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
$tax = $tax_id = 0;
|
|
||||||
|
|
||||||
if (!empty($item['tax_id'])) {
|
|
||||||
$tax_object = Tax::find($item['tax_id']);
|
|
||||||
|
|
||||||
$tax_id = $item['tax_id'];
|
|
||||||
|
|
||||||
$tax = (((double) $item['price'] * (double) $item['quantity']) / 100) * $tax_object->rate;
|
|
||||||
|
|
||||||
// Apply discount to tax
|
|
||||||
if ($discount) {
|
|
||||||
$tax = $tax - ($tax * ($discount / 100));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$bill_item['item_id'] = $item['item_id'];
|
|
||||||
$bill_item['name'] = str_limit($item['name'], 180, '');
|
|
||||||
$bill_item['sku'] = $item_sku;
|
|
||||||
$bill_item['quantity'] = (double) $item['quantity'];
|
|
||||||
$bill_item['price'] = (double) $item['price'];
|
|
||||||
$bill_item['tax'] = $tax;
|
|
||||||
$bill_item['tax_id'] = $tax_id;
|
|
||||||
$bill_item['total'] = (double) $item['price'] * (double) $item['quantity'];
|
|
||||||
|
|
||||||
BillItem::create($bill_item);
|
|
||||||
|
|
||||||
// Set taxes
|
|
||||||
if (isset($tax_object)) {
|
|
||||||
if (array_key_exists($tax_object->id, $taxes)) {
|
|
||||||
$taxes[$tax_object->id]['amount'] += $tax;
|
|
||||||
} else {
|
|
||||||
$taxes[$tax_object->id] = [
|
|
||||||
'name' => $tax_object->name,
|
|
||||||
'amount' => $tax
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate totals
|
|
||||||
$tax_total += $tax;
|
|
||||||
$sub_total += $bill_item['total'];
|
|
||||||
|
|
||||||
unset($tax_object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$s_total = $sub_total;
|
|
||||||
|
|
||||||
// Apply discount to total
|
|
||||||
if ($discount) {
|
|
||||||
$s_discount = $s_total * ($discount / 100);
|
|
||||||
$discount_total += $s_discount;
|
|
||||||
$s_total = $s_total - $s_discount;
|
|
||||||
}
|
|
||||||
|
|
||||||
$amount = $s_total + $tax_total;
|
|
||||||
|
|
||||||
$request['amount'] = money($amount, $request['currency_code'])->getAmount();
|
|
||||||
|
|
||||||
$bill->update($request->input());
|
|
||||||
|
|
||||||
// Add bill totals
|
|
||||||
$this->addTotals($bill, $request, $taxes, $sub_total, $discount_total, $tax_total);
|
|
||||||
|
|
||||||
// Add bill history
|
|
||||||
BillHistory::create([
|
|
||||||
'company_id' => session('company_id'),
|
|
||||||
'bill_id' => $bill->id,
|
|
||||||
'status_code' => 'draft',
|
|
||||||
'notify' => 0,
|
|
||||||
'description' => trans('messages.success.added', ['type' => $bill->bill_number]),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Recurring
|
|
||||||
$bill->createRecurring();
|
|
||||||
|
|
||||||
// Fire the event to make it extendible
|
|
||||||
event(new BillCreated($bill));
|
|
||||||
|
|
||||||
$message = trans('messages.success.added', ['type' => trans_choice('general.bills', 1)]);
|
$message = trans('messages.success.added', ['type' => trans_choice('general.bills', 1)]);
|
||||||
|
|
||||||
@ -373,105 +227,7 @@ class Bills extends Controller
|
|||||||
*/
|
*/
|
||||||
public function update(Bill $bill, Request $request)
|
public function update(Bill $bill, Request $request)
|
||||||
{
|
{
|
||||||
$taxes = [];
|
$bill = dispatch(new UpdateBill($bill, $request));
|
||||||
$tax_total = 0;
|
|
||||||
$sub_total = 0;
|
|
||||||
$discount_total = 0;
|
|
||||||
$discount = $request['discount'];
|
|
||||||
|
|
||||||
$bill_item = [];
|
|
||||||
$bill_item['company_id'] = $request['company_id'];
|
|
||||||
$bill_item['bill_id'] = $bill->id;
|
|
||||||
|
|
||||||
if ($request['item']) {
|
|
||||||
$this->deleteRelationships($bill, 'items');
|
|
||||||
|
|
||||||
foreach ($request['item'] as $item) {
|
|
||||||
unset($tax_object);
|
|
||||||
$item_sku = '';
|
|
||||||
|
|
||||||
if (!empty($item['item_id'])) {
|
|
||||||
$item_object = Item::find($item['item_id']);
|
|
||||||
|
|
||||||
$item['name'] = $item_object->name;
|
|
||||||
$item_sku = $item_object->sku;
|
|
||||||
}
|
|
||||||
|
|
||||||
$tax = $tax_id = 0;
|
|
||||||
|
|
||||||
if (!empty($item['tax_id'])) {
|
|
||||||
$tax_object = Tax::find($item['tax_id']);
|
|
||||||
|
|
||||||
$tax_id = $item['tax_id'];
|
|
||||||
|
|
||||||
$tax = (((double) $item['price'] * (double) $item['quantity']) / 100) * $tax_object->rate;
|
|
||||||
|
|
||||||
// Apply discount to tax
|
|
||||||
if ($discount) {
|
|
||||||
$tax = $tax - ($tax * ($discount / 100));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$bill_item['item_id'] = $item['item_id'];
|
|
||||||
$bill_item['name'] = str_limit($item['name'], 180, '');
|
|
||||||
$bill_item['sku'] = $item_sku;
|
|
||||||
$bill_item['quantity'] = (double) $item['quantity'];
|
|
||||||
$bill_item['price'] = (double) $item['price'];
|
|
||||||
$bill_item['tax'] = $tax;
|
|
||||||
$bill_item['tax_id'] = $tax_id;
|
|
||||||
$bill_item['total'] = (double) $item['price'] * (double) $item['quantity'];
|
|
||||||
|
|
||||||
if (isset($tax_object)) {
|
|
||||||
if (array_key_exists($tax_object->id, $taxes)) {
|
|
||||||
$taxes[$tax_object->id]['amount'] += $tax;
|
|
||||||
} else {
|
|
||||||
$taxes[$tax_object->id] = [
|
|
||||||
'name' => $tax_object->name,
|
|
||||||
'amount' => $tax
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$tax_total += $tax;
|
|
||||||
$sub_total += $bill_item['total'];
|
|
||||||
|
|
||||||
BillItem::create($bill_item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$s_total = $sub_total;
|
|
||||||
|
|
||||||
// Apply discount to total
|
|
||||||
if ($discount) {
|
|
||||||
$s_discount = $s_total * ($discount / 100);
|
|
||||||
$discount_total += $s_discount;
|
|
||||||
$s_total = $s_total - $s_discount;
|
|
||||||
}
|
|
||||||
|
|
||||||
$amount = $s_total + $tax_total;
|
|
||||||
|
|
||||||
$request['amount'] = money($amount, $request['currency_code'])->getAmount();
|
|
||||||
|
|
||||||
$bill->update($request->input());
|
|
||||||
|
|
||||||
// Upload attachment
|
|
||||||
if ($request->file('attachment')) {
|
|
||||||
$media = $this->getMedia($request->file('attachment'), 'bills');
|
|
||||||
|
|
||||||
$bill->attachMedia($media, 'attachment');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete previous bill totals
|
|
||||||
$this->deleteRelationships($bill, 'totals');
|
|
||||||
|
|
||||||
// Add bill totals
|
|
||||||
$this->addTotals($bill, $request, $taxes, $sub_total, $discount_total, $tax_total);
|
|
||||||
|
|
||||||
// Recurring
|
|
||||||
$bill->updateRecurring();
|
|
||||||
|
|
||||||
// Fire the event to make it extendible
|
|
||||||
event(new BillUpdated($bill));
|
|
||||||
|
|
||||||
$message = trans('messages.success.updated', ['type' => trans_choice('general.bills', 1)]);
|
$message = trans('messages.success.updated', ['type' => trans_choice('general.bills', 1)]);
|
||||||
|
|
||||||
@ -509,9 +265,9 @@ class Bills extends Controller
|
|||||||
\Excel::create('bills', function ($excel) {
|
\Excel::create('bills', function ($excel) {
|
||||||
$bills = Bill::with(['items', 'histories', 'payments', 'totals'])->filter(request()->input())->get();
|
$bills = Bill::with(['items', 'histories', 'payments', 'totals'])->filter(request()->input())->get();
|
||||||
|
|
||||||
$excel->sheet('invoices', function ($sheet) use ($bills) {
|
$excel->sheet('bills', function ($sheet) use ($bills) {
|
||||||
$sheet->fromModel($bills->makeHidden([
|
$sheet->fromModel($bills->makeHidden([
|
||||||
'company_id', 'parent_id', 'created_at', 'updated_at', 'deleted_at', 'attachment', 'discount', 'items', 'histories', 'payments', 'totals', 'media'
|
'company_id', 'parent_id', 'created_at', 'updated_at', 'deleted_at', 'attachment', 'discount', 'items', 'histories', 'payments', 'totals', 'media', 'paid'
|
||||||
]));
|
]));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -581,7 +337,9 @@ class Bills extends Controller
|
|||||||
{
|
{
|
||||||
$bill = $this->prepareBill($bill);
|
$bill = $this->prepareBill($bill);
|
||||||
|
|
||||||
$html = view($bill->template_path, compact('bill'))->render();
|
$currency_style = true;
|
||||||
|
|
||||||
|
$html = view($bill->template_path, compact('bill', 'currency_style'))->render();
|
||||||
|
|
||||||
$pdf = \App::make('dompdf.wrapper');
|
$pdf = \App::make('dompdf.wrapper');
|
||||||
$pdf->loadHTML($html);
|
$pdf->loadHTML($html);
|
||||||
@ -652,20 +410,7 @@ class Bills extends Controller
|
|||||||
|
|
||||||
$bill->save();
|
$bill->save();
|
||||||
|
|
||||||
$bill_payment_request = [
|
$bill_payment = dispatch(new CreateBillPayment($request, $bill));
|
||||||
'company_id' => $request['company_id'],
|
|
||||||
'bill_id' => $request['bill_id'],
|
|
||||||
'account_id' => $request['account_id'],
|
|
||||||
'paid_at' => $request['paid_at'],
|
|
||||||
'amount' => $request['amount'],
|
|
||||||
'currency_code' => $request['currency_code'],
|
|
||||||
'currency_rate' => $request['currency_rate'],
|
|
||||||
'description' => $request['description'],
|
|
||||||
'payment_method' => $request['payment_method'],
|
|
||||||
'reference' => $request['reference']
|
|
||||||
];
|
|
||||||
|
|
||||||
$bill_payment = BillPayment::create($bill_payment_request);
|
|
||||||
|
|
||||||
// Upload attachment
|
// Upload attachment
|
||||||
if ($request->file('attachment')) {
|
if ($request->file('attachment')) {
|
||||||
@ -674,15 +419,6 @@ class Bills extends Controller
|
|||||||
$bill_payment->attachMedia($media, 'attachment');
|
$bill_payment->attachMedia($media, 'attachment');
|
||||||
}
|
}
|
||||||
|
|
||||||
$request['status_code'] = $bill->bill_status_code;
|
|
||||||
$request['notify'] = 0;
|
|
||||||
|
|
||||||
$desc_amount = money((float) $request['amount'], (string) $request['currency_code'], true)->format();
|
|
||||||
|
|
||||||
$request['description'] = $desc_amount . ' ' . trans_choice('general.payments', 1);
|
|
||||||
|
|
||||||
BillHistory::create($request->input());
|
|
||||||
|
|
||||||
$message = trans('messages.success.added', ['type' => trans_choice('general.payments', 1)]);
|
$message = trans('messages.success.added', ['type' => trans_choice('general.payments', 1)]);
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
@ -791,64 +527,4 @@ class Bills extends Controller
|
|||||||
|
|
||||||
return $bill;
|
return $bill;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function addTotals($bill, $request, $taxes, $sub_total, $discount_total, $tax_total)
|
|
||||||
{
|
|
||||||
$sort_order = 1;
|
|
||||||
|
|
||||||
// Added bill sub total
|
|
||||||
BillTotal::create([
|
|
||||||
'company_id' => $request['company_id'],
|
|
||||||
'bill_id' => $bill->id,
|
|
||||||
'code' => 'sub_total',
|
|
||||||
'name' => 'bills.sub_total',
|
|
||||||
'amount' => $sub_total,
|
|
||||||
'sort_order' => $sort_order,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$sort_order++;
|
|
||||||
|
|
||||||
// Added bill discount
|
|
||||||
if ($discount_total) {
|
|
||||||
BillTotal::create([
|
|
||||||
'company_id' => $request['company_id'],
|
|
||||||
'bill_id' => $bill->id,
|
|
||||||
'code' => 'discount',
|
|
||||||
'name' => 'bills.discount',
|
|
||||||
'amount' => $discount_total,
|
|
||||||
'sort_order' => $sort_order,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// This is for total
|
|
||||||
$sub_total = $sub_total - $discount_total;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sort_order++;
|
|
||||||
|
|
||||||
// Added bill taxes
|
|
||||||
if ($taxes) {
|
|
||||||
foreach ($taxes as $tax) {
|
|
||||||
BillTotal::create([
|
|
||||||
'company_id' => $request['company_id'],
|
|
||||||
'bill_id' => $bill->id,
|
|
||||||
'code' => 'tax',
|
|
||||||
'name' => $tax['name'],
|
|
||||||
'amount' => $tax['amount'],
|
|
||||||
'sort_order' => $sort_order,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$sort_order++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Added bill total
|
|
||||||
BillTotal::create([
|
|
||||||
'company_id' => $request['company_id'],
|
|
||||||
'bill_id' => $bill->id,
|
|
||||||
'code' => 'total',
|
|
||||||
'name' => 'bills.total',
|
|
||||||
'amount' => $sub_total + $tax_total,
|
|
||||||
'sort_order' => $sort_order,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -27,14 +27,11 @@ class Payments extends Controller
|
|||||||
{
|
{
|
||||||
$payments = Payment::with(['vendor', 'account', 'category'])->isNotTransfer()->collect(['paid_at'=> 'desc']);
|
$payments = Payment::with(['vendor', 'account', 'category'])->isNotTransfer()->collect(['paid_at'=> 'desc']);
|
||||||
|
|
||||||
$vendors = collect(Vendor::enabled()->orderBy('name')->pluck('name', 'id'))
|
$vendors = collect(Vendor::enabled()->orderBy('name')->pluck('name', 'id'));
|
||||||
->prepend(trans('general.all_type', ['type' => trans_choice('general.vendors', 2)]), '');
|
|
||||||
|
|
||||||
$categories = collect(Category::enabled()->type('expense')->orderBy('name')->pluck('name', 'id'))
|
$categories = collect(Category::enabled()->type('expense')->orderBy('name')->pluck('name', 'id'));
|
||||||
->prepend(trans('general.all_type', ['type' => trans_choice('general.categories', 2)]), '');
|
|
||||||
|
|
||||||
$accounts = collect(Account::enabled()->orderBy('name')->pluck('name', 'id'))
|
$accounts = collect(Account::enabled()->orderBy('name')->pluck('name', 'id'));
|
||||||
->prepend(trans('general.all_type', ['type' => trans_choice('general.accounts', 2)]), '');
|
|
||||||
|
|
||||||
$transfer_cat_id = Category::transfer();
|
$transfer_cat_id = Category::transfer();
|
||||||
|
|
||||||
@ -64,7 +61,7 @@ class Payments extends Controller
|
|||||||
|
|
||||||
$account_currency_code = Account::where('id', setting('general.default_account'))->pluck('currency_code')->first();
|
$account_currency_code = Account::where('id', setting('general.default_account'))->pluck('currency_code')->first();
|
||||||
|
|
||||||
$currency = Currency::where('code', '=', $account_currency_code)->first();
|
$currency = Currency::where('code', $account_currency_code)->first();
|
||||||
|
|
||||||
$vendors = Vendor::enabled()->orderBy('name')->pluck('name', 'id');
|
$vendors = Vendor::enabled()->orderBy('name')->pluck('name', 'id');
|
||||||
|
|
||||||
@ -154,9 +151,7 @@ class Payments extends Controller
|
|||||||
|
|
||||||
$currencies = Currency::enabled()->orderBy('name')->pluck('name', 'code')->toArray();
|
$currencies = Currency::enabled()->orderBy('name')->pluck('name', 'code')->toArray();
|
||||||
|
|
||||||
$account_currency_code = Account::where('id', $payment->account_id)->pluck('currency_code')->first();
|
$currency = Currency::where('code', $payment->currency_code)->first();
|
||||||
|
|
||||||
$currency = Currency::where('code', '=', $account_currency_code)->first();
|
|
||||||
|
|
||||||
$vendors = Vendor::enabled()->orderBy('name')->pluck('name', 'id');
|
$vendors = Vendor::enabled()->orderBy('name')->pluck('name', 'id');
|
||||||
|
|
||||||
@ -164,7 +159,7 @@ class Payments extends Controller
|
|||||||
|
|
||||||
$payment_methods = Modules::getPaymentMethods();
|
$payment_methods = Modules::getPaymentMethods();
|
||||||
|
|
||||||
return view('expenses.payments.edit', compact('payment', 'accounts', 'currencies', 'account_currency_code', 'currency', 'vendors', 'categories', 'payment_methods'));
|
return view('expenses.payments.edit', compact('payment', 'accounts', 'currencies', 'currency', 'vendors', 'categories', 'payment_methods'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -100,8 +100,10 @@ class Vendors extends Controller
|
|||||||
|
|
||||||
$limit = request('limit', setting('general.list_limit', '25'));
|
$limit = request('limit', setting('general.list_limit', '25'));
|
||||||
$transactions = $this->paginate($items->merge($bill_payments)->sortByDesc('paid_at'), $limit);
|
$transactions = $this->paginate($items->merge($bill_payments)->sortByDesc('paid_at'), $limit);
|
||||||
|
$bills = $this->paginate($bills->sortByDesc('paid_at'), $limit);
|
||||||
|
$payments = $this->paginate($payments->sortByDesc('paid_at'), $limit);
|
||||||
|
|
||||||
return view('expenses.vendors.show', compact('vendor', 'counts', 'amounts', 'transactions'));
|
return view('expenses.vendors.show', compact('vendor', 'counts', 'amounts', 'transactions', 'bills', 'payments'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -309,7 +311,7 @@ class Vendors extends Controller
|
|||||||
if (empty($vendor_id)) {
|
if (empty($vendor_id)) {
|
||||||
return response()->json([]);
|
return response()->json([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$vendor = Vendor::find($vendor_id);
|
$vendor = Vendor::find($vendor_id);
|
||||||
|
|
||||||
if (empty($vendor)) {
|
if (empty($vendor)) {
|
||||||
@ -332,6 +334,12 @@ class Vendors extends Controller
|
|||||||
$vendor->currency_code = $currency_code;
|
$vendor->currency_code = $currency_code;
|
||||||
$vendor->currency_rate = $currency->rate;
|
$vendor->currency_rate = $currency->rate;
|
||||||
|
|
||||||
|
$vendor->thousands_separator = $currency->thousands_separator;
|
||||||
|
$vendor->decimal_mark = $currency->decimal_mark;
|
||||||
|
$vendor->precision = (int) $currency->precision;
|
||||||
|
$vendor->symbol_first = $currency->symbol_first;
|
||||||
|
$vendor->symbol = $currency->symbol;
|
||||||
|
|
||||||
return response()->json($vendor);
|
return response()->json($vendor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,8 +100,10 @@ class Customers extends Controller
|
|||||||
|
|
||||||
$limit = request('limit', setting('general.list_limit', '25'));
|
$limit = request('limit', setting('general.list_limit', '25'));
|
||||||
$transactions = $this->paginate($items->merge($invoice_payments)->sortByDesc('paid_at'), $limit);
|
$transactions = $this->paginate($items->merge($invoice_payments)->sortByDesc('paid_at'), $limit);
|
||||||
|
$invoices = $this->paginate($invoices->sortByDesc('paid_at'), $limit);
|
||||||
|
$revenues = $this->paginate($revenues->sortByDesc('paid_at'), $limit);
|
||||||
|
|
||||||
return view('incomes.customers.show', compact('customer', 'counts', 'amounts', 'transactions'));
|
return view('incomes.customers.show', compact('customer', 'counts', 'amounts', 'transactions', 'invoices', 'revenues'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,21 +8,26 @@ use App\Events\InvoiceUpdated;
|
|||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
use App\Http\Requests\Income\Invoice as Request;
|
use App\Http\Requests\Income\Invoice as Request;
|
||||||
use App\Http\Requests\Income\InvoicePayment as PaymentRequest;
|
use App\Http\Requests\Income\InvoicePayment as PaymentRequest;
|
||||||
|
use App\Jobs\Income\CreateInvoice;
|
||||||
|
use App\Jobs\Income\UpdateInvoice;
|
||||||
|
use App\Jobs\Income\CreateInvoicePayment;
|
||||||
use App\Models\Banking\Account;
|
use App\Models\Banking\Account;
|
||||||
|
use App\Models\Common\Item;
|
||||||
use App\Models\Common\Media;
|
use App\Models\Common\Media;
|
||||||
use App\Models\Income\Customer;
|
use App\Models\Income\Customer;
|
||||||
use App\Models\Income\Invoice;
|
use App\Models\Income\Invoice;
|
||||||
use App\Models\Income\InvoiceHistory;
|
use App\Models\Income\InvoiceHistory;
|
||||||
use App\Models\Income\InvoiceItem;
|
use App\Models\Income\InvoiceItem;
|
||||||
|
use App\Models\Income\InvoiceItemTax;
|
||||||
use App\Models\Income\InvoiceTotal;
|
use App\Models\Income\InvoiceTotal;
|
||||||
use App\Models\Income\InvoicePayment;
|
use App\Models\Income\InvoicePayment;
|
||||||
use App\Models\Income\InvoiceStatus;
|
use App\Models\Income\InvoiceStatus;
|
||||||
use App\Models\Common\Item;
|
|
||||||
use App\Models\Setting\Category;
|
use App\Models\Setting\Category;
|
||||||
use App\Models\Setting\Currency;
|
use App\Models\Setting\Currency;
|
||||||
use App\Models\Setting\Tax;
|
use App\Models\Setting\Tax;
|
||||||
use App\Notifications\Income\Invoice as Notification;
|
use App\Notifications\Income\Invoice as Notification;
|
||||||
use App\Notifications\Common\Item as ItemNotification;
|
use App\Notifications\Common\Item as ItemNotification;
|
||||||
|
use App\Notifications\Common\ItemReminder as ItemReminderNotification;
|
||||||
use App\Traits\Currencies;
|
use App\Traits\Currencies;
|
||||||
use App\Traits\DateTime;
|
use App\Traits\DateTime;
|
||||||
use App\Traits\Incomes;
|
use App\Traits\Incomes;
|
||||||
@ -35,6 +40,7 @@ use File;
|
|||||||
use Illuminate\Http\Request as ItemRequest;
|
use Illuminate\Http\Request as ItemRequest;
|
||||||
use Image;
|
use Image;
|
||||||
use Storage;
|
use Storage;
|
||||||
|
use SignedUrl;
|
||||||
|
|
||||||
class Invoices extends Controller
|
class Invoices extends Controller
|
||||||
{
|
{
|
||||||
@ -49,13 +55,13 @@ class Invoices extends Controller
|
|||||||
{
|
{
|
||||||
$invoices = Invoice::with(['customer', 'status', 'items', 'payments', 'histories'])->collect(['invoice_number'=> 'desc']);
|
$invoices = Invoice::with(['customer', 'status', 'items', 'payments', 'histories'])->collect(['invoice_number'=> 'desc']);
|
||||||
|
|
||||||
$customers = collect(Customer::enabled()->orderBy('name')->pluck('name', 'id'))
|
$customers = collect(Customer::enabled()->orderBy('name')->pluck('name', 'id'));
|
||||||
->prepend(trans('general.all_type', ['type' => trans_choice('general.customers', 2)]), '');
|
|
||||||
|
|
||||||
$status = collect(InvoiceStatus::all()->pluck('name', 'code'))
|
$categories = collect(Category::enabled()->type('income')->orderBy('name')->pluck('name', 'id'));
|
||||||
->prepend(trans('general.all_type', ['type' => trans_choice('general.statuses', 2)]), '');
|
|
||||||
|
|
||||||
return view('incomes.invoices.index', compact('invoices', 'customers', 'status'));
|
$statuses = collect(InvoiceStatus::all()->pluck('name', 'code'));
|
||||||
|
|
||||||
|
return view('incomes.invoices.index', compact('invoices', 'customers', 'categories', 'statuses'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,43 +73,6 @@ class Invoices extends Controller
|
|||||||
*/
|
*/
|
||||||
public function show(Invoice $invoice)
|
public function show(Invoice $invoice)
|
||||||
{
|
{
|
||||||
$paid = 0;
|
|
||||||
|
|
||||||
// Get Invoice Payments
|
|
||||||
if ($invoice->payments->count()) {
|
|
||||||
$_currencies = Currency::enabled()->pluck('rate', 'code')->toArray();
|
|
||||||
|
|
||||||
foreach ($invoice->payments as $item) {
|
|
||||||
$default_amount = $item->amount;
|
|
||||||
|
|
||||||
if ($invoice->currency_code == $item->currency_code) {
|
|
||||||
$amount = (double)$default_amount;
|
|
||||||
} else {
|
|
||||||
$default_amount_model = new InvoicePayment();
|
|
||||||
|
|
||||||
$default_amount_model->default_currency_code = $invoice->currency_code;
|
|
||||||
$default_amount_model->amount = $default_amount;
|
|
||||||
$default_amount_model->currency_code = $item->currency_code;
|
|
||||||
$default_amount_model->currency_rate = $_currencies[$item->currency_code];
|
|
||||||
|
|
||||||
$default_amount = (double) $default_amount_model->getDivideConvertedAmount();
|
|
||||||
|
|
||||||
$convert_amount = new InvoicePayment();
|
|
||||||
|
|
||||||
$convert_amount->default_currency_code = $item->currency_code;
|
|
||||||
$convert_amount->amount = $default_amount;
|
|
||||||
$convert_amount->currency_code = $invoice->currency_code;
|
|
||||||
$convert_amount->currency_rate = $_currencies[$invoice->currency_code];
|
|
||||||
|
|
||||||
$amount = (double) $convert_amount->getDynamicConvertedAmount();
|
|
||||||
}
|
|
||||||
|
|
||||||
$paid += $amount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoice->paid = $paid;
|
|
||||||
|
|
||||||
$accounts = Account::enabled()->orderBy('name')->pluck('name', 'id');
|
$accounts = Account::enabled()->orderBy('name')->pluck('name', 'id');
|
||||||
|
|
||||||
$currencies = Currency::enabled()->orderBy('name')->pluck('name', 'code')->toArray();
|
$currencies = Currency::enabled()->orderBy('name')->pluck('name', 'code')->toArray();
|
||||||
@ -116,7 +85,9 @@ class Invoices extends Controller
|
|||||||
|
|
||||||
$payment_methods = Modules::getPaymentMethods();
|
$payment_methods = Modules::getPaymentMethods();
|
||||||
|
|
||||||
return view('incomes.invoices.show', compact('invoice', 'accounts', 'currencies', 'account_currency_code', 'customers', 'categories', 'payment_methods'));
|
$customer_share = SignedUrl::sign(url('links/invoices/' . $invoice->id));
|
||||||
|
|
||||||
|
return view('incomes.invoices.show', compact('invoice', 'accounts', 'currencies', 'account_currency_code', 'customers', 'categories', 'payment_methods', 'customer_share'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -134,7 +105,7 @@ class Invoices extends Controller
|
|||||||
|
|
||||||
$items = Item::enabled()->orderBy('name')->pluck('name', 'id');
|
$items = Item::enabled()->orderBy('name')->pluck('name', 'id');
|
||||||
|
|
||||||
$taxes = Tax::enabled()->orderBy('rate')->get()->pluck('title', 'id');
|
$taxes = Tax::enabled()->orderBy('name')->get()->pluck('title', 'id');
|
||||||
|
|
||||||
$categories = Category::enabled()->type('income')->orderBy('name')->pluck('name', 'id');
|
$categories = Category::enabled()->type('income')->orderBy('name')->pluck('name', 'id');
|
||||||
|
|
||||||
@ -152,133 +123,7 @@ class Invoices extends Controller
|
|||||||
*/
|
*/
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
{
|
{
|
||||||
$invoice = Invoice::create($request->input());
|
$invoice = dispatch(new CreateInvoice($request));
|
||||||
|
|
||||||
// Upload attachment
|
|
||||||
if ($request->file('attachment')) {
|
|
||||||
$media = $this->getMedia($request->file('attachment'), 'invoices');
|
|
||||||
|
|
||||||
$invoice->attachMedia($media, 'attachment');
|
|
||||||
}
|
|
||||||
|
|
||||||
$taxes = [];
|
|
||||||
|
|
||||||
$tax_total = 0;
|
|
||||||
$sub_total = 0;
|
|
||||||
$discount_total = 0;
|
|
||||||
$discount = $request['discount'];
|
|
||||||
|
|
||||||
$invoice_item = [];
|
|
||||||
$invoice_item['company_id'] = $request['company_id'];
|
|
||||||
$invoice_item['invoice_id'] = $invoice->id;
|
|
||||||
|
|
||||||
if ($request['item']) {
|
|
||||||
foreach ($request['item'] as $item) {
|
|
||||||
$item_sku = '';
|
|
||||||
|
|
||||||
if (!empty($item['item_id'])) {
|
|
||||||
$item_object = Item::find($item['item_id']);
|
|
||||||
|
|
||||||
$item['name'] = $item_object->name;
|
|
||||||
$item_sku = $item_object->sku;
|
|
||||||
|
|
||||||
// Decrease stock (item sold)
|
|
||||||
$item_object->quantity -= $item['quantity'];
|
|
||||||
$item_object->save();
|
|
||||||
|
|
||||||
// Notify users if out of stock
|
|
||||||
if ($item_object->quantity == 0) {
|
|
||||||
foreach ($item_object->company->users as $user) {
|
|
||||||
if (!$user->can('read-notifications')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$user->notify(new ItemNotification($item_object));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$tax = $tax_id = 0;
|
|
||||||
|
|
||||||
if (!empty($item['tax_id'])) {
|
|
||||||
$tax_object = Tax::find($item['tax_id']);
|
|
||||||
|
|
||||||
$tax_id = $item['tax_id'];
|
|
||||||
|
|
||||||
$tax = (((double) $item['price'] * (double) $item['quantity']) / 100) * $tax_object->rate;
|
|
||||||
|
|
||||||
// Apply discount to tax
|
|
||||||
if ($discount) {
|
|
||||||
$tax = $tax - ($tax * ($discount / 100));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoice_item['item_id'] = $item['item_id'];
|
|
||||||
$invoice_item['name'] = str_limit($item['name'], 180, '');
|
|
||||||
$invoice_item['sku'] = $item_sku;
|
|
||||||
$invoice_item['quantity'] = (double) $item['quantity'];
|
|
||||||
$invoice_item['price'] = (double) $item['price'];
|
|
||||||
$invoice_item['tax'] = $tax;
|
|
||||||
$invoice_item['tax_id'] = $tax_id;
|
|
||||||
$invoice_item['total'] = (double) $item['price'] * (double) $item['quantity'];
|
|
||||||
|
|
||||||
InvoiceItem::create($invoice_item);
|
|
||||||
|
|
||||||
// Set taxes
|
|
||||||
if (isset($tax_object)) {
|
|
||||||
if (array_key_exists($tax_object->id, $taxes)) {
|
|
||||||
$taxes[$tax_object->id]['amount'] += $tax;
|
|
||||||
} else {
|
|
||||||
$taxes[$tax_object->id] = [
|
|
||||||
'name' => $tax_object->name,
|
|
||||||
'amount' => $tax
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate totals
|
|
||||||
$tax_total += $tax;
|
|
||||||
$sub_total += $invoice_item['total'];
|
|
||||||
|
|
||||||
unset($tax_object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$s_total = $sub_total;
|
|
||||||
|
|
||||||
// Apply discount to total
|
|
||||||
if ($discount) {
|
|
||||||
$s_discount = $s_total * ($discount / 100);
|
|
||||||
$discount_total += $s_discount;
|
|
||||||
$s_total = $s_total - $s_discount;
|
|
||||||
}
|
|
||||||
|
|
||||||
$amount = $s_total + $tax_total;
|
|
||||||
|
|
||||||
$request['amount'] = money($amount, $request['currency_code'])->getAmount();
|
|
||||||
|
|
||||||
$invoice->update($request->input());
|
|
||||||
|
|
||||||
// Add invoice totals
|
|
||||||
$this->addTotals($invoice, $request, $taxes, $sub_total, $discount_total, $tax_total);
|
|
||||||
|
|
||||||
// Add invoice history
|
|
||||||
InvoiceHistory::create([
|
|
||||||
'company_id' => session('company_id'),
|
|
||||||
'invoice_id' => $invoice->id,
|
|
||||||
'status_code' => 'draft',
|
|
||||||
'notify' => 0,
|
|
||||||
'description' => trans('messages.success.added', ['type' => $invoice->invoice_number]),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Update next invoice number
|
|
||||||
$this->increaseNextInvoiceNumber();
|
|
||||||
|
|
||||||
// Recurring
|
|
||||||
$invoice->createRecurring();
|
|
||||||
|
|
||||||
// Fire the event to make it extendible
|
|
||||||
event(new InvoiceCreated($invoice));
|
|
||||||
|
|
||||||
$message = trans('messages.success.added', ['type' => trans_choice('general.invoices', 1)]);
|
$message = trans('messages.success.added', ['type' => trans_choice('general.invoices', 1)]);
|
||||||
|
|
||||||
@ -377,7 +222,7 @@ class Invoices extends Controller
|
|||||||
|
|
||||||
$items = Item::enabled()->orderBy('name')->pluck('name', 'id');
|
$items = Item::enabled()->orderBy('name')->pluck('name', 'id');
|
||||||
|
|
||||||
$taxes = Tax::enabled()->orderBy('rate')->get()->pluck('title', 'id');
|
$taxes = Tax::enabled()->orderBy('name')->get()->pluck('title', 'id');
|
||||||
|
|
||||||
$categories = Category::enabled()->type('income')->orderBy('name')->pluck('name', 'id');
|
$categories = Category::enabled()->type('income')->orderBy('name')->pluck('name', 'id');
|
||||||
|
|
||||||
@ -394,105 +239,7 @@ class Invoices extends Controller
|
|||||||
*/
|
*/
|
||||||
public function update(Invoice $invoice, Request $request)
|
public function update(Invoice $invoice, Request $request)
|
||||||
{
|
{
|
||||||
$taxes = [];
|
$invoice = dispatch(new UpdateInvoice($invoice, $request));
|
||||||
$tax_total = 0;
|
|
||||||
$sub_total = 0;
|
|
||||||
$discount_total = 0;
|
|
||||||
$discount = $request['discount'];
|
|
||||||
|
|
||||||
$invoice_item = [];
|
|
||||||
$invoice_item['company_id'] = $request['company_id'];
|
|
||||||
$invoice_item['invoice_id'] = $invoice->id;
|
|
||||||
|
|
||||||
if ($request['item']) {
|
|
||||||
$this->deleteRelationships($invoice, 'items');
|
|
||||||
|
|
||||||
foreach ($request['item'] as $item) {
|
|
||||||
unset($tax_object);
|
|
||||||
$item_sku = '';
|
|
||||||
|
|
||||||
if (!empty($item['item_id'])) {
|
|
||||||
$item_object = Item::find($item['item_id']);
|
|
||||||
|
|
||||||
$item['name'] = $item_object->name;
|
|
||||||
$item_sku = $item_object->sku;
|
|
||||||
}
|
|
||||||
|
|
||||||
$tax = $tax_id = 0;
|
|
||||||
|
|
||||||
if (!empty($item['tax_id'])) {
|
|
||||||
$tax_object = Tax::find($item['tax_id']);
|
|
||||||
|
|
||||||
$tax_id = $item['tax_id'];
|
|
||||||
|
|
||||||
$tax = (((double) $item['price'] * (double) $item['quantity']) / 100) * $tax_object->rate;
|
|
||||||
|
|
||||||
// Apply discount to tax
|
|
||||||
if ($discount) {
|
|
||||||
$tax = $tax - ($tax * ($discount / 100));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$invoice_item['item_id'] = $item['item_id'];
|
|
||||||
$invoice_item['name'] = str_limit($item['name'], 180, '');
|
|
||||||
$invoice_item['sku'] = $item_sku;
|
|
||||||
$invoice_item['quantity'] = (double) $item['quantity'];
|
|
||||||
$invoice_item['price'] = (double) $item['price'];
|
|
||||||
$invoice_item['tax'] = $tax;
|
|
||||||
$invoice_item['tax_id'] = $tax_id;
|
|
||||||
$invoice_item['total'] = (double) $item['price'] * (double) $item['quantity'];
|
|
||||||
|
|
||||||
if (isset($tax_object)) {
|
|
||||||
if (array_key_exists($tax_object->id, $taxes)) {
|
|
||||||
$taxes[$tax_object->id]['amount'] += $tax;
|
|
||||||
} else {
|
|
||||||
$taxes[$tax_object->id] = [
|
|
||||||
'name' => $tax_object->name,
|
|
||||||
'amount' => $tax
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$tax_total += $tax;
|
|
||||||
$sub_total += $invoice_item['total'];
|
|
||||||
|
|
||||||
InvoiceItem::create($invoice_item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$s_total = $sub_total;
|
|
||||||
|
|
||||||
// Apply discount to total
|
|
||||||
if ($discount) {
|
|
||||||
$s_discount = $s_total * ($discount / 100);
|
|
||||||
$discount_total += $s_discount;
|
|
||||||
$s_total = $s_total - $s_discount;
|
|
||||||
}
|
|
||||||
|
|
||||||
$amount = $s_total + $tax_total;
|
|
||||||
|
|
||||||
$request['amount'] = money($amount, $request['currency_code'])->getAmount();
|
|
||||||
|
|
||||||
$invoice->update($request->input());
|
|
||||||
|
|
||||||
// Upload attachment
|
|
||||||
if ($request->file('attachment')) {
|
|
||||||
$media = $this->getMedia($request->file('attachment'), 'invoices');
|
|
||||||
|
|
||||||
$invoice->attachMedia($media, 'attachment');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete previous invoice totals
|
|
||||||
$this->deleteRelationships($invoice, 'totals');
|
|
||||||
|
|
||||||
// Add invoice totals
|
|
||||||
$this->addTotals($invoice, $request, $taxes, $sub_total, $discount_total, $tax_total);
|
|
||||||
|
|
||||||
// Recurring
|
|
||||||
$invoice->updateRecurring();
|
|
||||||
|
|
||||||
// Fire the event to make it extendible
|
|
||||||
event(new InvoiceUpdated($invoice));
|
|
||||||
|
|
||||||
$message = trans('messages.success.updated', ['type' => trans_choice('general.invoices', 1)]);
|
$message = trans('messages.success.updated', ['type' => trans_choice('general.invoices', 1)]);
|
||||||
|
|
||||||
@ -532,7 +279,7 @@ class Invoices extends Controller
|
|||||||
|
|
||||||
$excel->sheet('invoices', function ($sheet) use ($invoices) {
|
$excel->sheet('invoices', function ($sheet) use ($invoices) {
|
||||||
$sheet->fromModel($invoices->makeHidden([
|
$sheet->fromModel($invoices->makeHidden([
|
||||||
'company_id', 'parent_id', 'created_at', 'updated_at', 'deleted_at', 'attachment', 'discount', 'items', 'histories', 'payments', 'totals', 'media'
|
'company_id', 'parent_id', 'created_at', 'updated_at', 'deleted_at', 'attachment', 'discount', 'items', 'histories', 'payments', 'totals', 'media', 'paid'
|
||||||
]));
|
]));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -623,6 +370,7 @@ class Invoices extends Controller
|
|||||||
unset($invoice->paid);
|
unset($invoice->paid);
|
||||||
unset($invoice->template_path);
|
unset($invoice->template_path);
|
||||||
unset($invoice->pdf_path);
|
unset($invoice->pdf_path);
|
||||||
|
unset($invoice->reconciled);
|
||||||
|
|
||||||
// Mark invoice as sent
|
// Mark invoice as sent
|
||||||
if ($invoice->invoice_status_code != 'partial') {
|
if ($invoice->invoice_status_code != 'partial') {
|
||||||
@ -670,7 +418,9 @@ class Invoices extends Controller
|
|||||||
{
|
{
|
||||||
$invoice = $this->prepareInvoice($invoice);
|
$invoice = $this->prepareInvoice($invoice);
|
||||||
|
|
||||||
$html = view($invoice->template_path, compact('invoice'))->render();
|
$currency_style = true;
|
||||||
|
|
||||||
|
$html = view($invoice->template_path, compact('invoice', 'currency_style'))->render();
|
||||||
|
|
||||||
$pdf = app('dompdf.wrapper');
|
$pdf = app('dompdf.wrapper');
|
||||||
$pdf->loadHTML($html);
|
$pdf->loadHTML($html);
|
||||||
@ -789,20 +539,7 @@ class Invoices extends Controller
|
|||||||
|
|
||||||
$invoice->save();
|
$invoice->save();
|
||||||
|
|
||||||
$invoice_payment_request = [
|
$invoice_payment = dispatch(new CreateInvoicePayment($request, $invoice));
|
||||||
'company_id' => $request['company_id'],
|
|
||||||
'invoice_id' => $request['invoice_id'],
|
|
||||||
'account_id' => $request['account_id'],
|
|
||||||
'paid_at' => $request['paid_at'],
|
|
||||||
'amount' => $request['amount'],
|
|
||||||
'currency_code' => $request['currency_code'],
|
|
||||||
'currency_rate' => $request['currency_rate'],
|
|
||||||
'description' => $request['description'],
|
|
||||||
'payment_method' => $request['payment_method'],
|
|
||||||
'reference' => $request['reference']
|
|
||||||
];
|
|
||||||
|
|
||||||
$invoice_payment = InvoicePayment::create($invoice_payment_request);
|
|
||||||
|
|
||||||
// Upload attachment
|
// Upload attachment
|
||||||
if ($request->file('attachment')) {
|
if ($request->file('attachment')) {
|
||||||
@ -811,15 +548,6 @@ class Invoices extends Controller
|
|||||||
$invoice_payment->attachMedia($media, 'attachment');
|
$invoice_payment->attachMedia($media, 'attachment');
|
||||||
}
|
}
|
||||||
|
|
||||||
$request['status_code'] = $invoice->invoice_status_code;
|
|
||||||
$request['notify'] = 0;
|
|
||||||
|
|
||||||
$desc_amount = money((float) $request['amount'], (string) $request['currency_code'], true)->format();
|
|
||||||
|
|
||||||
$request['description'] = $desc_amount . ' ' . trans_choice('general.payments', 1);
|
|
||||||
|
|
||||||
InvoiceHistory::create($request->input());
|
|
||||||
|
|
||||||
$message = trans('messages.success.added', ['type' => trans_choice('general.payments', 1)]);
|
$message = trans('messages.success.added', ['type' => trans_choice('general.payments', 1)]);
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
@ -928,64 +656,4 @@ class Invoices extends Controller
|
|||||||
|
|
||||||
return $invoice;
|
return $invoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function addTotals($invoice, $request, $taxes, $sub_total, $discount_total, $tax_total)
|
|
||||||
{
|
|
||||||
$sort_order = 1;
|
|
||||||
|
|
||||||
// Added invoice sub total
|
|
||||||
InvoiceTotal::create([
|
|
||||||
'company_id' => $request['company_id'],
|
|
||||||
'invoice_id' => $invoice->id,
|
|
||||||
'code' => 'sub_total',
|
|
||||||
'name' => 'invoices.sub_total',
|
|
||||||
'amount' => $sub_total,
|
|
||||||
'sort_order' => $sort_order,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$sort_order++;
|
|
||||||
|
|
||||||
// Added invoice discount
|
|
||||||
if ($discount_total) {
|
|
||||||
InvoiceTotal::create([
|
|
||||||
'company_id' => $request['company_id'],
|
|
||||||
'invoice_id' => $invoice->id,
|
|
||||||
'code' => 'discount',
|
|
||||||
'name' => 'invoices.discount',
|
|
||||||
'amount' => $discount_total,
|
|
||||||
'sort_order' => $sort_order,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// This is for total
|
|
||||||
$sub_total = $sub_total - $discount_total;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sort_order++;
|
|
||||||
|
|
||||||
// Added invoice taxes
|
|
||||||
if ($taxes) {
|
|
||||||
foreach ($taxes as $tax) {
|
|
||||||
InvoiceTotal::create([
|
|
||||||
'company_id' => $request['company_id'],
|
|
||||||
'invoice_id' => $invoice->id,
|
|
||||||
'code' => 'tax',
|
|
||||||
'name' => $tax['name'],
|
|
||||||
'amount' => $tax['amount'],
|
|
||||||
'sort_order' => $sort_order,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$sort_order++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Added invoice total
|
|
||||||
InvoiceTotal::create([
|
|
||||||
'company_id' => $request['company_id'],
|
|
||||||
'invoice_id' => $invoice->id,
|
|
||||||
'code' => 'total',
|
|
||||||
'name' => 'invoices.total',
|
|
||||||
'amount' => $sub_total + $tax_total,
|
|
||||||
'sort_order' => $sort_order,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -29,14 +29,11 @@ class Revenues extends Controller
|
|||||||
{
|
{
|
||||||
$revenues = Revenue::with(['account', 'category', 'customer'])->isNotTransfer()->collect(['paid_at'=> 'desc']);
|
$revenues = Revenue::with(['account', 'category', 'customer'])->isNotTransfer()->collect(['paid_at'=> 'desc']);
|
||||||
|
|
||||||
$customers = collect(Customer::enabled()->orderBy('name')->pluck('name', 'id'))
|
$customers = collect(Customer::enabled()->orderBy('name')->pluck('name', 'id'));
|
||||||
->prepend(trans('general.all_type', ['type' => trans_choice('general.customers', 2)]), '');
|
|
||||||
|
|
||||||
$categories = collect(Category::enabled()->type('income')->orderBy('name')->pluck('name', 'id'))
|
$categories = collect(Category::enabled()->type('income')->orderBy('name')->pluck('name', 'id'));
|
||||||
->prepend(trans('general.all_type', ['type' => trans_choice('general.categories', 2)]), '');
|
|
||||||
|
|
||||||
$accounts = collect(Account::enabled()->orderBy('name')->pluck('name', 'id'))
|
$accounts = collect(Account::enabled()->orderBy('name')->pluck('name', 'id'));
|
||||||
->prepend(trans('general.all_type', ['type' => trans_choice('general.accounts', 2)]), '');
|
|
||||||
|
|
||||||
$transfer_cat_id = Category::transfer();
|
$transfer_cat_id = Category::transfer();
|
||||||
|
|
||||||
@ -66,7 +63,7 @@ class Revenues extends Controller
|
|||||||
|
|
||||||
$account_currency_code = Account::where('id', setting('general.default_account'))->pluck('currency_code')->first();
|
$account_currency_code = Account::where('id', setting('general.default_account'))->pluck('currency_code')->first();
|
||||||
|
|
||||||
$currency = Currency::where('code', '=', $account_currency_code)->first();
|
$currency = Currency::where('code', $account_currency_code)->first();
|
||||||
|
|
||||||
$customers = Customer::enabled()->orderBy('name')->pluck('name', 'id');
|
$customers = Customer::enabled()->orderBy('name')->pluck('name', 'id');
|
||||||
|
|
||||||
@ -156,9 +153,7 @@ class Revenues extends Controller
|
|||||||
|
|
||||||
$currencies = Currency::enabled()->orderBy('name')->pluck('name', 'code')->toArray();
|
$currencies = Currency::enabled()->orderBy('name')->pluck('name', 'code')->toArray();
|
||||||
|
|
||||||
$account_currency_code = Account::where('id', $revenue->account_id)->pluck('currency_code')->first();
|
$currency = Currency::where('code', $revenue->currency_code)->first();
|
||||||
|
|
||||||
$currency = Currency::where('code', '=', $account_currency_code)->first();
|
|
||||||
|
|
||||||
$customers = Customer::enabled()->orderBy('name')->pluck('name', 'id');
|
$customers = Customer::enabled()->orderBy('name')->pluck('name', 'id');
|
||||||
|
|
||||||
@ -166,7 +161,7 @@ class Revenues extends Controller
|
|||||||
|
|
||||||
$payment_methods = Modules::getPaymentMethods();
|
$payment_methods = Modules::getPaymentMethods();
|
||||||
|
|
||||||
return view('incomes.revenues.edit', compact('revenue', 'accounts', 'currencies', 'account_currency_code', 'currency', 'customers', 'categories', 'payment_methods'));
|
return view('incomes.revenues.edit', compact('revenue', 'accounts', 'currencies', 'currency', 'customers', 'categories', 'payment_methods'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,8 +6,10 @@ use App\Http\Controllers\Controller;
|
|||||||
use App\Events\UpdateFinished;
|
use App\Events\UpdateFinished;
|
||||||
use App\Utilities\Updater;
|
use App\Utilities\Updater;
|
||||||
use App\Utilities\Versions;
|
use App\Utilities\Versions;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
use Artisan;
|
use Artisan;
|
||||||
use Module;
|
use Module;
|
||||||
|
use File;
|
||||||
|
|
||||||
class Updates extends Controller
|
class Updates extends Controller
|
||||||
{
|
{
|
||||||
@ -80,15 +82,20 @@ class Updates extends Controller
|
|||||||
*/
|
*/
|
||||||
public function update($alias, $version)
|
public function update($alias, $version)
|
||||||
{
|
{
|
||||||
set_time_limit(600); // 10 minutes
|
if ($alias == 'core') {
|
||||||
|
$name = 'Akaunting v' . $version;
|
||||||
|
|
||||||
if (Updater::update($alias, $version)) {
|
$installed = version('short');
|
||||||
return redirect('install/updates/post/' . $alias . '/' . version('short') . '/' . $version);
|
} else {
|
||||||
|
// Get module instance
|
||||||
|
$module = Module::findByAlias($alias);
|
||||||
|
|
||||||
|
$name = $module->get('name');
|
||||||
|
|
||||||
|
$installed = $module->get('version');
|
||||||
}
|
}
|
||||||
|
|
||||||
flash(trans('updates.error'))->error()->important();
|
return view('install.updates.edit', compact('alias', 'name', 'installed', 'version'));
|
||||||
|
|
||||||
return redirect()->back();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -117,4 +124,229 @@ class Updates extends Controller
|
|||||||
|
|
||||||
return redirect('install/updates');
|
return redirect('install/updates');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for viewing the specified resource.
|
||||||
|
*
|
||||||
|
* @param $request
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function steps(Request $request)
|
||||||
|
{
|
||||||
|
$json = [];
|
||||||
|
$json['step'] = [];
|
||||||
|
|
||||||
|
$name = $request['name'];
|
||||||
|
$version = $request['version'];
|
||||||
|
|
||||||
|
// Download
|
||||||
|
$json['step'][] = [
|
||||||
|
'text' => trans('modules.installation.download', ['module' => $name]),
|
||||||
|
'url' => url('install/updates/download')
|
||||||
|
];
|
||||||
|
|
||||||
|
// Unzip
|
||||||
|
$json['step'][] = [
|
||||||
|
'text' => trans('modules.installation.unzip', ['module' => $name]),
|
||||||
|
'url' => url('install/updates/unzip')
|
||||||
|
];
|
||||||
|
|
||||||
|
// File Copy
|
||||||
|
$json['step'][] = [
|
||||||
|
'text' => trans('modules.installation.file_copy', ['module' => $name]),
|
||||||
|
'url' => url('install/updates/file-copy')
|
||||||
|
];
|
||||||
|
|
||||||
|
// Migrate DB and trigger event UpdateFinish event
|
||||||
|
$json['step'][] = [
|
||||||
|
'text' => trans('modules.installation.migrate', ['module' => $name]),
|
||||||
|
'url' => url('install/updates/migrate')
|
||||||
|
];
|
||||||
|
|
||||||
|
// redirect update page
|
||||||
|
$json['step'][] = [
|
||||||
|
'text' => trans('modules.installation.finish'),
|
||||||
|
'url' => url('install/updates/finish')
|
||||||
|
];
|
||||||
|
|
||||||
|
return response()->json($json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for viewing the specified resource.
|
||||||
|
*
|
||||||
|
* @param $request
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function download(Request $request)
|
||||||
|
{
|
||||||
|
set_time_limit(600); // 10 minutes
|
||||||
|
|
||||||
|
$status = true;
|
||||||
|
|
||||||
|
if ($request['alias'] != 'core') {
|
||||||
|
$this->checkApiToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Download file
|
||||||
|
if (!$data = Updater::download($request['alias'], $request['version'])) {
|
||||||
|
$status = false;
|
||||||
|
|
||||||
|
$message = trans('modules.errors.download', ['module' => $request['name']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create temp directory
|
||||||
|
$path = 'temp-' . md5(mt_rand());
|
||||||
|
$temp_path = storage_path('app/temp') . '/' . $path;
|
||||||
|
|
||||||
|
if (!File::isDirectory($temp_path)) {
|
||||||
|
File::makeDirectory($temp_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
$file = $temp_path . '/upload.zip';
|
||||||
|
|
||||||
|
// Add content to the Zip file
|
||||||
|
$uploaded = is_int(file_put_contents($file, $data)) ? true : false;
|
||||||
|
|
||||||
|
if (!$uploaded) {
|
||||||
|
$status = false;
|
||||||
|
|
||||||
|
$message = trans('modules.errors.upload', ['module' => $request['name']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$json = [
|
||||||
|
'success' => ($status) ? true : false,
|
||||||
|
'errors' => (!$status) ? $message : false,
|
||||||
|
'data' => [
|
||||||
|
'path' => $path
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
return response()->json($json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for viewing the specified resource.
|
||||||
|
*
|
||||||
|
* @param $request
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function unzip(Request $request)
|
||||||
|
{
|
||||||
|
set_time_limit(600); // 10 minutes
|
||||||
|
|
||||||
|
if ($request['alias'] != 'core') {
|
||||||
|
$this->checkApiToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = storage_path('app/temp') . '/' . $request['path'];
|
||||||
|
|
||||||
|
$file = $path . '/upload.zip';
|
||||||
|
|
||||||
|
$result = Updater::unzip($file, $path);
|
||||||
|
|
||||||
|
$json = [
|
||||||
|
'success' => ($result) ? true : false,
|
||||||
|
'errors' => (!$result) ? trans('modules.errors.unzip', ['module' => $request['name']]) : false,
|
||||||
|
'data' => [
|
||||||
|
'path' => $request['path']
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
return response()->json($json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for viewing the specified resource.
|
||||||
|
*
|
||||||
|
* @param $request
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function fileCopy(Request $request)
|
||||||
|
{
|
||||||
|
set_time_limit(600); // 10 minutes
|
||||||
|
|
||||||
|
if ($request['alias'] != 'core') {
|
||||||
|
$this->checkApiToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = storage_path('app/temp') . '/' . $request['path'];
|
||||||
|
|
||||||
|
$result = Updater::fileCopy($request['alias'], $path, $request['version']);
|
||||||
|
|
||||||
|
$json = [
|
||||||
|
'success' => ($result) ? true : false,
|
||||||
|
'errors' => (!$result) ? trans('modules.errors.file_copy', ['module' => $request['name']]) : false,
|
||||||
|
'data' => [
|
||||||
|
'path' => $request['path']
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
return response()->json($json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for viewing the specified resource.
|
||||||
|
*
|
||||||
|
* @param $request
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function migrate(Request $request)
|
||||||
|
{
|
||||||
|
// Check if the file mirror was successful
|
||||||
|
if (($request['alias'] == 'core') && (version('short') != $request['version'])) {
|
||||||
|
$json = [
|
||||||
|
'success' => false,
|
||||||
|
'errors' => trans('modules.errors.migrate core', ['module' => $request['name']]),
|
||||||
|
'data' => []
|
||||||
|
];
|
||||||
|
|
||||||
|
return response()->json($json);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear cache after update
|
||||||
|
Artisan::call('cache:clear');
|
||||||
|
|
||||||
|
try {
|
||||||
|
event(new UpdateFinished($request['alias'], $request['installed'], $request['version']));
|
||||||
|
|
||||||
|
$json = [
|
||||||
|
'success' => true,
|
||||||
|
'errors' => false,
|
||||||
|
'data' => []
|
||||||
|
];
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$json = [
|
||||||
|
'success' => false,
|
||||||
|
'errors' => trans('modules.errors.migrate', ['module' => $request['name']]),
|
||||||
|
'data' => []
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json($json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for viewing the specified resource.
|
||||||
|
*
|
||||||
|
* @param $request
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function finish(Request $request)
|
||||||
|
{
|
||||||
|
$json = [
|
||||||
|
'success' => true,
|
||||||
|
'errors' => false,
|
||||||
|
'redirect' => url("install/updates"),
|
||||||
|
'data' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
return response()->json($json);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,10 +39,10 @@ class BillPayments extends Controller
|
|||||||
|
|
||||||
$currencies = Currency::enabled()->orderBy('name')->pluck('name', 'code')->toArray();
|
$currencies = Currency::enabled()->orderBy('name')->pluck('name', 'code')->toArray();
|
||||||
|
|
||||||
$currency = Currency::where('code', setting('general.default_currency'))->first();
|
|
||||||
|
|
||||||
$account_currency_code = Account::where('id', setting('general.default_account'))->pluck('currency_code')->first();
|
$account_currency_code = Account::where('id', setting('general.default_account'))->pluck('currency_code')->first();
|
||||||
|
|
||||||
|
$currency = Currency::where('code', $account_currency_code)->first();
|
||||||
|
|
||||||
$payment_methods = Modules::getPaymentMethods();
|
$payment_methods = Modules::getPaymentMethods();
|
||||||
|
|
||||||
$bill->paid = $this->getPaid($bill);
|
$bill->paid = $this->getPaid($bill);
|
||||||
@ -52,7 +52,9 @@ class BillPayments extends Controller
|
|||||||
$bill->{$bill_total->code} = $bill_total->amount;
|
$bill->{$bill_total->code} = $bill_total->amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
$bill->grand_total = $bill->total;
|
$total = money($bill->total, $currency->code, true)->format();
|
||||||
|
|
||||||
|
$bill->grand_total = money($total, $currency->code)->getAmount();
|
||||||
|
|
||||||
if (!empty($paid)) {
|
if (!empty($paid)) {
|
||||||
$bill->grand_total = $bill->total - $paid;
|
$bill->grand_total = $bill->total - $paid;
|
||||||
|
@ -52,7 +52,9 @@ class InvoicePayments extends Controller
|
|||||||
$invoice->{$invoice_total->code} = $invoice_total->amount;
|
$invoice->{$invoice_total->code} = $invoice_total->amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
$invoice->grand_total = $invoice->total;
|
$total = money($invoice->total, $currency->code, true)->format();
|
||||||
|
|
||||||
|
$invoice->grand_total = money($total, $currency->code)->getAmount();
|
||||||
|
|
||||||
if (!empty($paid)) {
|
if (!empty($paid)) {
|
||||||
$invoice->grand_total = $invoice->total - $paid;
|
$invoice->grand_total = $invoice->total - $paid;
|
||||||
@ -147,7 +149,7 @@ class InvoicePayments extends Controller
|
|||||||
$error_amount = (double) $convert_amount->getDynamicConvertedAmount();
|
$error_amount = (double) $convert_amount->getDynamicConvertedAmount();
|
||||||
}
|
}
|
||||||
|
|
||||||
$message = trans('messages.error.over_payment', ['amount' => money($error_amount, $request['currency_code'],true)]);
|
$message = trans('messages.error.over_payment', ['amount' => money($error_amount, $request['currency_code'], true)]);
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
'success' => false,
|
'success' => false,
|
||||||
|
69
app/Http/Controllers/Modals/Taxes.php
Normal file
69
app/Http/Controllers/Modals/Taxes.php
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Modals;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\Setting\Tax as Request;
|
||||||
|
use App\Models\Setting\Tax;
|
||||||
|
|
||||||
|
class Taxes extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Instantiate a new controller instance.
|
||||||
|
*/
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
// Add CRUD permission check
|
||||||
|
$this->middleware('permission:create-settings-taxes')->only(['create', 'store']);
|
||||||
|
$this->middleware('permission:read-settings-taxes')->only(['index', 'edit']);
|
||||||
|
$this->middleware('permission:update-settings-taxes')->only(['update', 'enable', 'disable']);
|
||||||
|
$this->middleware('permission:delete-settings-taxes')->only('destroy');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
$types = [
|
||||||
|
'normal' => trans('taxes.normal'),
|
||||||
|
'inclusive' => trans('taxes.inclusive'),
|
||||||
|
'compound' => trans('taxes.compound'),
|
||||||
|
];
|
||||||
|
|
||||||
|
$html = view('modals.taxes.create', compact('types'))->render();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'message' => 'null',
|
||||||
|
'html' => $html,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$request['enabled'] = 1;
|
||||||
|
|
||||||
|
$tax = Tax::create($request->all());
|
||||||
|
|
||||||
|
$message = trans('messages.success.added', ['type' => trans_choice('general.taxes', 1)]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'data' => $tax,
|
||||||
|
'message' => $message,
|
||||||
|
'html' => 'null',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@ -67,7 +67,7 @@ class Item extends Controller
|
|||||||
$module->action_url .= $character . http_build_query($parameters);
|
$module->action_url .= $character . http_build_query($parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
return view('modules.item.show', compact('module', 'about', 'installed', 'enable'));
|
return view('modules.item.show', compact('module', 'installed', 'enable'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -302,4 +302,42 @@ class Item extends Controller
|
|||||||
|
|
||||||
return redirect('apps/' . $alias);
|
return redirect('apps/' . $alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function reviews($alias, Request $request)
|
||||||
|
{
|
||||||
|
$page = $request['page'];
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'query' => [
|
||||||
|
'page' => ($page) ? $page : 1,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$reviews = $this->getModuleReviews($alias, $data);
|
||||||
|
|
||||||
|
$html = view('partials.modules.reviews', compact('reviews'))->render();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'data' => null,
|
||||||
|
'message' => null,
|
||||||
|
'html' => $html,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function documentation($alias)
|
||||||
|
{
|
||||||
|
$this->checkApiToken();
|
||||||
|
|
||||||
|
$documentation = $this->getDocumentation($alias);
|
||||||
|
|
||||||
|
if (empty($documentation)) {
|
||||||
|
return redirect('apps/' . $alias)->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
$back = 'apps/' . $alias;
|
||||||
|
|
||||||
|
return view('modules.item.documentation', compact('documentation', 'back'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,15 @@ class Tiles extends Controller
|
|||||||
{
|
{
|
||||||
$this->checkApiToken();
|
$this->checkApiToken();
|
||||||
|
|
||||||
$data = $this->getModulesByCategory($alias);
|
$page = request('page', 1);
|
||||||
|
|
||||||
|
$request = [
|
||||||
|
'query' => [
|
||||||
|
'page' => $page,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$data = $this->getModulesByCategory($alias, $request);
|
||||||
|
|
||||||
$title = $data->category->name;
|
$title = $data->category->name;
|
||||||
$modules = $data->modules;
|
$modules = $data->modules;
|
||||||
@ -32,6 +40,34 @@ class Tiles extends Controller
|
|||||||
return view('modules.tiles.index', compact('title', 'modules', 'installed'));
|
return view('modules.tiles.index', compact('title', 'modules', 'installed'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for viewing the specified resource.
|
||||||
|
*
|
||||||
|
* @param $alias
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function vendorModules($alias)
|
||||||
|
{
|
||||||
|
$this->checkApiToken();
|
||||||
|
|
||||||
|
$page = request('page', 1);
|
||||||
|
|
||||||
|
$request = [
|
||||||
|
'query' => [
|
||||||
|
'page' => $page,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$data = $this->getModulesByVendor($alias, $request);
|
||||||
|
|
||||||
|
$title = $data->vendor->name;
|
||||||
|
$modules = $data->modules;
|
||||||
|
$installed = Module::all()->pluck('status', 'alias')->toArray();
|
||||||
|
|
||||||
|
return view('modules.tiles.index', compact('title', 'modules', 'installed'));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the form for viewing the specified resource.
|
* Show the form for viewing the specified resource.
|
||||||
*
|
*
|
||||||
@ -41,8 +77,16 @@ class Tiles extends Controller
|
|||||||
{
|
{
|
||||||
$this->checkApiToken();
|
$this->checkApiToken();
|
||||||
|
|
||||||
|
$page = request('page', 1);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'query' => [
|
||||||
|
'page' => $page,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
$title = trans('modules.top_paid');
|
$title = trans('modules.top_paid');
|
||||||
$modules = $this->getPaidModules();
|
$modules = $this->getPaidModules($data);
|
||||||
$installed = Module::all()->pluck('status', 'alias')->toArray();
|
$installed = Module::all()->pluck('status', 'alias')->toArray();
|
||||||
|
|
||||||
return view('modules.tiles.index', compact('title', 'modules', 'installed'));
|
return view('modules.tiles.index', compact('title', 'modules', 'installed'));
|
||||||
@ -57,8 +101,16 @@ class Tiles extends Controller
|
|||||||
{
|
{
|
||||||
$this->checkApiToken();
|
$this->checkApiToken();
|
||||||
|
|
||||||
|
$page = request('page', 1);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'query' => [
|
||||||
|
'page' => $page,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
$title = trans('modules.new');
|
$title = trans('modules.new');
|
||||||
$modules = $this->getNewModules();
|
$modules = $this->getNewModules($data);
|
||||||
$installed = Module::all()->pluck('status', 'alias')->toArray();
|
$installed = Module::all()->pluck('status', 'alias')->toArray();
|
||||||
|
|
||||||
return view('modules.tiles.index', compact('title', 'modules', 'installed'));
|
return view('modules.tiles.index', compact('title', 'modules', 'installed'));
|
||||||
@ -73,8 +125,16 @@ class Tiles extends Controller
|
|||||||
{
|
{
|
||||||
$this->checkApiToken();
|
$this->checkApiToken();
|
||||||
|
|
||||||
|
$page = request('page', 1);
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'query' => [
|
||||||
|
'page' => $page,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
$title = trans('modules.top_free');
|
$title = trans('modules.top_free');
|
||||||
$modules = $this->getFreeModules();
|
$modules = $this->getFreeModules($data);
|
||||||
$installed = Module::all()->pluck('status', 'alias')->toArray();
|
$installed = Module::all()->pluck('status', 'alias')->toArray();
|
||||||
|
|
||||||
return view('modules.tiles.index', compact('title', 'modules', 'installed'));
|
return view('modules.tiles.index', compact('title', 'modules', 'installed'));
|
||||||
@ -90,10 +150,12 @@ class Tiles extends Controller
|
|||||||
$this->checkApiToken();
|
$this->checkApiToken();
|
||||||
|
|
||||||
$keyword = $request['keyword'];
|
$keyword = $request['keyword'];
|
||||||
|
$page = request('page', 1);
|
||||||
|
|
||||||
$data = [
|
$data = [
|
||||||
'query' => [
|
'query' => [
|
||||||
'keyword' => $keyword,
|
'keyword' => $keyword,
|
||||||
|
'page' => $page,
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -3,10 +3,13 @@
|
|||||||
namespace App\Http\Controllers\Reports;
|
namespace App\Http\Controllers\Reports;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Banking\Account;
|
||||||
use App\Models\Expense\Bill;
|
use App\Models\Expense\Bill;
|
||||||
use App\Models\Expense\BillPayment;
|
use App\Models\Expense\BillPayment;
|
||||||
use App\Models\Expense\Payment;
|
use App\Models\Expense\Payment;
|
||||||
|
use App\Models\Expense\Vendor;
|
||||||
use App\Models\Setting\Category;
|
use App\Models\Setting\Category;
|
||||||
|
use App\Utilities\Recurring;
|
||||||
use Charts;
|
use Charts;
|
||||||
use Date;
|
use Date;
|
||||||
|
|
||||||
@ -22,13 +25,16 @@ class ExpenseSummary extends Controller
|
|||||||
$dates = $totals = $expenses = $expenses_graph = $categories = [];
|
$dates = $totals = $expenses = $expenses_graph = $categories = [];
|
||||||
|
|
||||||
$status = request('status');
|
$status = request('status');
|
||||||
|
$year = request('year', Date::now()->year);
|
||||||
|
|
||||||
$categories = Category::enabled()->type('expense')->pluck('name', 'id')->toArray();
|
$categories = Category::enabled()->type('expense')->orderBy('name')->pluck('name', 'id')->toArray();
|
||||||
|
|
||||||
// Get year
|
if ($categories_filter = request('categories')) {
|
||||||
$year = request('year');
|
$cats = collect($categories)->filter(function ($value, $key) use ($categories_filter) {
|
||||||
if (empty($year)) {
|
return in_array($key, $categories_filter);
|
||||||
$year = Date::now()->year;
|
});
|
||||||
|
} else {
|
||||||
|
$cats = $categories;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dates
|
// Dates
|
||||||
@ -44,7 +50,7 @@ class ExpenseSummary extends Controller
|
|||||||
'currency_rate' => 1
|
'currency_rate' => 1
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($categories as $category_id => $category_name) {
|
foreach ($cats as $category_id => $category_name) {
|
||||||
$expenses[$category_id][$dates[$j]] = array(
|
$expenses[$category_id][$dates[$j]] = array(
|
||||||
'category_id' => $category_id,
|
'category_id' => $category_id,
|
||||||
'name' => $category_name,
|
'name' => $category_name,
|
||||||
@ -55,27 +61,47 @@ class ExpenseSummary extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bills
|
$payments = Payment::monthsOfYear('paid_at')->account(request('accounts'))->vendor(request('vendors'))->isNotTransfer()->get();
|
||||||
|
|
||||||
switch ($status) {
|
switch ($status) {
|
||||||
case 'paid':
|
case 'paid':
|
||||||
$bills = BillPayment::monthsOfYear('paid_at')->get();
|
// Bills
|
||||||
|
$bills = BillPayment::monthsOfYear('paid_at')->account(request('accounts'))->get();
|
||||||
$this->setAmount($expenses_graph, $totals, $expenses, $bills, 'bill', 'paid_at');
|
$this->setAmount($expenses_graph, $totals, $expenses, $bills, 'bill', 'paid_at');
|
||||||
|
|
||||||
|
// Payments
|
||||||
|
$this->setAmount($expenses_graph, $totals, $expenses, $payments, 'payment', 'paid_at');
|
||||||
break;
|
break;
|
||||||
case 'upcoming':
|
case 'upcoming':
|
||||||
$bills = Bill::accrued()->monthsOfYear('due_at')->get();
|
// Bills
|
||||||
|
$bills = Bill::accrued()->monthsOfYear('due_at')->vendor(request('vendors'))->get();
|
||||||
|
Recurring::reflect($bills, 'bill', 'billed_at', $status);
|
||||||
$this->setAmount($expenses_graph, $totals, $expenses, $bills, 'bill', 'due_at');
|
$this->setAmount($expenses_graph, $totals, $expenses, $bills, 'bill', 'due_at');
|
||||||
|
|
||||||
|
// Payments
|
||||||
|
Recurring::reflect($payments, 'payment', 'paid_at', $status);
|
||||||
|
$this->setAmount($expenses_graph, $totals, $expenses, $payments, 'payment', 'paid_at');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$bills = Bill::accrued()->monthsOfYear('billed_at')->get();
|
// Bills
|
||||||
|
$bills = Bill::accrued()->monthsOfYear('billed_at')->vendor(request('vendors'))->get();
|
||||||
|
Recurring::reflect($bills, 'bill', 'billed_at', $status);
|
||||||
$this->setAmount($expenses_graph, $totals, $expenses, $bills, 'bill', 'billed_at');
|
$this->setAmount($expenses_graph, $totals, $expenses, $bills, 'bill', 'billed_at');
|
||||||
|
|
||||||
|
// Payments
|
||||||
|
Recurring::reflect($payments, 'payment', 'paid_at', $status);
|
||||||
|
$this->setAmount($expenses_graph, $totals, $expenses, $payments, 'payment', 'paid_at');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Payments
|
$statuses = collect([
|
||||||
if ($status != 'upcoming') {
|
'all' => trans('general.all'),
|
||||||
$payments = Payment::monthsOfYear('paid_at')->isNotTransfer()->get();
|
'paid' => trans('invoices.paid'),
|
||||||
$this->setAmount($expenses_graph, $totals, $expenses, $payments, 'payment', 'paid_at');
|
'upcoming' => trans('dashboard.payables'),
|
||||||
}
|
]);
|
||||||
|
|
||||||
|
$accounts = Account::enabled()->pluck('name', 'id')->toArray();
|
||||||
|
$vendors = Vendor::enabled()->pluck('name', 'id')->toArray();
|
||||||
|
|
||||||
// Check if it's a print or normal request
|
// Check if it's a print or normal request
|
||||||
if (request('print')) {
|
if (request('print')) {
|
||||||
@ -86,6 +112,8 @@ class ExpenseSummary extends Controller
|
|||||||
$view_template = 'reports.expense_summary.index';
|
$view_template = 'reports.expense_summary.index';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$print_url = $this->getPrintUrl($year);
|
||||||
|
|
||||||
// Expenses chart
|
// Expenses chart
|
||||||
$chart = Charts::multi('line', 'chartjs')
|
$chart = Charts::multi('line', 'chartjs')
|
||||||
->dimensions(0, 300)
|
->dimensions(0, 300)
|
||||||
@ -95,21 +123,49 @@ class ExpenseSummary extends Controller
|
|||||||
->credits(false)
|
->credits(false)
|
||||||
->view($chart_template);
|
->view($chart_template);
|
||||||
|
|
||||||
return view($view_template, compact('chart', 'dates', 'categories', 'expenses', 'totals'));
|
return view($view_template, compact(
|
||||||
|
'chart',
|
||||||
|
'dates',
|
||||||
|
'categories',
|
||||||
|
'statuses',
|
||||||
|
'accounts',
|
||||||
|
'vendors',
|
||||||
|
'expenses',
|
||||||
|
'totals',
|
||||||
|
'print_url'
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function setAmount(&$graph, &$totals, &$expenses, $items, $type, $date_field)
|
private function setAmount(&$graph, &$totals, &$expenses, $items, $type, $date_field)
|
||||||
{
|
{
|
||||||
foreach ($items as $item) {
|
foreach ($items as $item) {
|
||||||
if ($item['table'] == 'bill_payments') {
|
switch ($item->getTable()) {
|
||||||
$bill = $item->bill;
|
case 'bill_payments':
|
||||||
|
$bill = $item->bill;
|
||||||
|
|
||||||
$item->category_id = $bill->category_id;
|
if ($vendors = request('vendors')) {
|
||||||
|
if (!in_array($bill->vendor_id, $vendors)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$item->category_id = $bill->category_id;
|
||||||
|
break;
|
||||||
|
case 'bills':
|
||||||
|
if ($accounts = request('accounts')) {
|
||||||
|
foreach ($item->payments as $payment) {
|
||||||
|
if (!in_array($payment->account_id, $accounts)) {
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$date = Date::parse($item->$date_field)->format('F');
|
$month = Date::parse($item->$date_field)->format('F');
|
||||||
|
$month_year = Date::parse($item->$date_field)->format('F-Y');
|
||||||
|
|
||||||
if (!isset($expenses[$item->category_id])) {
|
if (!isset($expenses[$item->category_id]) || !isset($expenses[$item->category_id][$month]) || !isset($graph[$month_year])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,13 +178,34 @@ class ExpenseSummary extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$expenses[$item->category_id][$date]['amount'] += $amount;
|
$expenses[$item->category_id][$month]['amount'] += $amount;
|
||||||
$expenses[$item->category_id][$date]['currency_code'] = $item->currency_code;
|
$expenses[$item->category_id][$month]['currency_code'] = $item->currency_code;
|
||||||
$expenses[$item->category_id][$date]['currency_rate'] = $item->currency_rate;
|
$expenses[$item->category_id][$month]['currency_rate'] = $item->currency_rate;
|
||||||
|
|
||||||
$graph[Date::parse($item->$date_field)->format('F-Y')] += $amount;
|
$graph[$month_year] += $amount;
|
||||||
|
|
||||||
$totals[$date]['amount'] += $amount;
|
$totals[$month]['amount'] += $amount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getPrintUrl($year)
|
||||||
|
{
|
||||||
|
$print_url = 'reports/expense-summary?print=1'
|
||||||
|
. '&status=' . request('status')
|
||||||
|
. '&year='. request('year', $year);
|
||||||
|
|
||||||
|
collect(request('accounts'))->each(function($item) use(&$print_url) {
|
||||||
|
$print_url .= '&accounts[]=' . $item;
|
||||||
|
});
|
||||||
|
|
||||||
|
collect(request('vendors'))->each(function($item) use(&$print_url) {
|
||||||
|
$print_url .= '&vendors[]=' . $item;
|
||||||
|
});
|
||||||
|
|
||||||
|
collect(request('categories'))->each(function($item) use(&$print_url) {
|
||||||
|
$print_url .= '&categories[]=' . $item;
|
||||||
|
});
|
||||||
|
|
||||||
|
return $print_url;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,17 @@
|
|||||||
namespace App\Http\Controllers\Reports;
|
namespace App\Http\Controllers\Reports;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Banking\Account;
|
||||||
|
use App\Models\Income\Customer;
|
||||||
use App\Models\Income\Invoice;
|
use App\Models\Income\Invoice;
|
||||||
use App\Models\Income\InvoicePayment;
|
use App\Models\Income\InvoicePayment;
|
||||||
use App\Models\Income\Revenue;
|
use App\Models\Income\Revenue;
|
||||||
use App\Models\Expense\Bill;
|
use App\Models\Expense\Bill;
|
||||||
use App\Models\Expense\BillPayment;
|
use App\Models\Expense\BillPayment;
|
||||||
use App\Models\Expense\Payment;
|
use App\Models\Expense\Payment;
|
||||||
|
use App\Models\Expense\Vendor;
|
||||||
use App\Models\Setting\Category;
|
use App\Models\Setting\Category;
|
||||||
|
use App\Utilities\Recurring;
|
||||||
use Charts;
|
use Charts;
|
||||||
use Date;
|
use Date;
|
||||||
|
|
||||||
@ -25,16 +29,16 @@ class IncomeExpenseSummary extends Controller
|
|||||||
$dates = $totals = $compares = $profit_graph = $categories = [];
|
$dates = $totals = $compares = $profit_graph = $categories = [];
|
||||||
|
|
||||||
$status = request('status');
|
$status = request('status');
|
||||||
|
$year = request('year', Date::now()->year);
|
||||||
|
$categories_filter = request('categories');
|
||||||
|
|
||||||
$income_categories = Category::enabled()->type('income')->pluck('name', 'id')->toArray();
|
$income_categories = Category::enabled()->type('income')->when($categories_filter, function ($query) use ($categories_filter) {
|
||||||
|
return $query->whereIn('id', $categories_filter);
|
||||||
|
})->orderBy('name')->pluck('name', 'id')->toArray();
|
||||||
|
|
||||||
$expense_categories = Category::enabled()->type('expense')->pluck('name', 'id')->toArray();
|
$expense_categories = Category::enabled()->type('expense')->when($categories_filter, function ($query) use ($categories_filter) {
|
||||||
|
return $query->whereIn('id', $categories_filter);
|
||||||
// Get year
|
})->orderBy('name')->pluck('name', 'id')->toArray();
|
||||||
$year = request('year');
|
|
||||||
if (empty($year)) {
|
|
||||||
$year = Date::now()->year;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dates
|
// Dates
|
||||||
for ($j = 1; $j <= 12; $j++) {
|
for ($j = 1; $j <= 12; $j++) {
|
||||||
@ -70,49 +74,75 @@ class IncomeExpenseSummary extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoices
|
$revenues = Revenue::monthsOfYear('paid_at')->account(request('accounts'))->customer(request('customers'))->isNotTransfer()->get();
|
||||||
|
$payments = Payment::monthsOfYear('paid_at')->account(request('accounts'))->vendor(request('vendors'))->isNotTransfer()->get();
|
||||||
|
|
||||||
switch ($status) {
|
switch ($status) {
|
||||||
case 'paid':
|
case 'paid':
|
||||||
$invoices = InvoicePayment::monthsOfYear('paid_at')->get();
|
// Invoices
|
||||||
|
$invoices = InvoicePayment::monthsOfYear('paid_at')->account(request('accounts'))->get();
|
||||||
$this->setAmount($profit_graph, $totals, $compares, $invoices, 'invoice', 'paid_at');
|
$this->setAmount($profit_graph, $totals, $compares, $invoices, 'invoice', 'paid_at');
|
||||||
break;
|
|
||||||
case 'upcoming':
|
|
||||||
$invoices = Invoice::accrued()->monthsOfYear('due_at')->get();
|
|
||||||
$this->setAmount($profit_graph, $totals, $compares, $invoices, 'invoice', 'due_at');
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$invoices = Invoice::accrued()->monthsOfYear('invoiced_at')->get();
|
|
||||||
$this->setAmount($profit_graph, $totals, $compares, $invoices, 'invoice', 'invoiced_at');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Revenues
|
// Revenues
|
||||||
if ($status != 'upcoming') {
|
$this->setAmount($profit_graph, $totals, $compares, $revenues, 'revenue', 'paid_at');
|
||||||
$revenues = Revenue::monthsOfYear('paid_at')->isNotTransfer()->get();
|
|
||||||
$this->setAmount($profit_graph, $totals, $compares, $revenues, 'revenue', 'paid_at');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bills
|
// Bills
|
||||||
switch ($status) {
|
$bills = BillPayment::monthsOfYear('paid_at')->account(request('accounts'))->get();
|
||||||
case 'paid':
|
|
||||||
$bills = BillPayment::monthsOfYear('paid_at')->get();
|
|
||||||
$this->setAmount($profit_graph, $totals, $compares, $bills, 'bill', 'paid_at');
|
$this->setAmount($profit_graph, $totals, $compares, $bills, 'bill', 'paid_at');
|
||||||
|
|
||||||
|
// Payments
|
||||||
|
$this->setAmount($profit_graph, $totals, $compares, $payments, 'payment', 'paid_at');
|
||||||
break;
|
break;
|
||||||
case 'upcoming':
|
case 'upcoming':
|
||||||
$bills = Bill::accrued()->monthsOfYear('due_at')->get();
|
// Invoices
|
||||||
|
$invoices = Invoice::accrued()->monthsOfYear('due_at')->customer(request('customers'))->get();
|
||||||
|
Recurring::reflect($invoices, 'invoice', 'due_at', $status);
|
||||||
|
$this->setAmount($profit_graph, $totals, $compares, $invoices, 'invoice', 'due_at');
|
||||||
|
|
||||||
|
// Revenues
|
||||||
|
Recurring::reflect($revenues, 'revenue', 'paid_at', $status);
|
||||||
|
$this->setAmount($profit_graph, $totals, $compares, $revenues, 'revenue', 'paid_at');
|
||||||
|
|
||||||
|
// Bills
|
||||||
|
$bills = Bill::accrued()->monthsOfYear('due_at')->vendor(request('vendors'))->get();
|
||||||
|
Recurring::reflect($bills, 'bill', 'billed_at', $status);
|
||||||
$this->setAmount($profit_graph, $totals, $compares, $bills, 'bill', 'due_at');
|
$this->setAmount($profit_graph, $totals, $compares, $bills, 'bill', 'due_at');
|
||||||
|
|
||||||
|
// Payments
|
||||||
|
Recurring::reflect($payments, 'payment', 'paid_at', $status);
|
||||||
|
$this->setAmount($profit_graph, $totals, $compares, $payments, 'payment', 'paid_at');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$bills = Bill::accrued()->monthsOfYear('billed_at')->get();
|
// Invoices
|
||||||
|
$invoices = Invoice::accrued()->monthsOfYear('invoiced_at')->customer(request('customers'))->get();
|
||||||
|
Recurring::reflect($invoices, 'invoice', 'invoiced_at', $status);
|
||||||
|
$this->setAmount($profit_graph, $totals, $compares, $invoices, 'invoice', 'invoiced_at');
|
||||||
|
|
||||||
|
// Revenues
|
||||||
|
Recurring::reflect($revenues, 'revenue', 'paid_at', $status);
|
||||||
|
$this->setAmount($profit_graph, $totals, $compares, $revenues, 'revenue', 'paid_at');
|
||||||
|
|
||||||
|
// Bills
|
||||||
|
$bills = Bill::accrued()->monthsOfYear('billed_at')->vendor(request('vendors'))->get();
|
||||||
|
Recurring::reflect($bills, 'bill', 'billed_at', $status);
|
||||||
$this->setAmount($profit_graph, $totals, $compares, $bills, 'bill', 'billed_at');
|
$this->setAmount($profit_graph, $totals, $compares, $bills, 'bill', 'billed_at');
|
||||||
|
|
||||||
|
// Payments
|
||||||
|
Recurring::reflect($payments, 'payment', 'paid_at', $status);
|
||||||
|
$this->setAmount($profit_graph, $totals, $compares, $payments, 'payment', 'paid_at');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Payments
|
$statuses = collect([
|
||||||
if ($status != 'upcoming') {
|
'all' => trans('general.all'),
|
||||||
$payments = Payment::monthsOfYear('paid_at')->isNotTransfer()->get();
|
'paid' => trans('invoices.paid'),
|
||||||
$this->setAmount($profit_graph, $totals, $compares, $payments, 'payment', 'paid_at');
|
'upcoming' => trans('general.upcoming'),
|
||||||
}
|
]);
|
||||||
|
|
||||||
|
$accounts = Account::enabled()->pluck('name', 'id')->toArray();
|
||||||
|
$customers = Customer::enabled()->pluck('name', 'id')->toArray();
|
||||||
|
$vendors = Vendor::enabled()->pluck('name', 'id')->toArray();
|
||||||
|
$categories = Category::enabled()->type(['income', 'expense'])->pluck('name', 'id')->toArray();
|
||||||
|
|
||||||
// Check if it's a print or normal request
|
// Check if it's a print or normal request
|
||||||
if (request('print')) {
|
if (request('print')) {
|
||||||
@ -123,6 +153,8 @@ class IncomeExpenseSummary extends Controller
|
|||||||
$view_template = 'reports.income_expense_summary.index';
|
$view_template = 'reports.income_expense_summary.index';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$print_url = $this->getPrintUrl($year);
|
||||||
|
|
||||||
// Profit chart
|
// Profit chart
|
||||||
$chart = Charts::multi('line', 'chartjs')
|
$chart = Charts::multi('line', 'chartjs')
|
||||||
->dimensions(0, 300)
|
->dimensions(0, 300)
|
||||||
@ -132,23 +164,72 @@ class IncomeExpenseSummary extends Controller
|
|||||||
->credits(false)
|
->credits(false)
|
||||||
->view($chart_template);
|
->view($chart_template);
|
||||||
|
|
||||||
return view($view_template, compact('chart', 'dates', 'income_categories', 'expense_categories', 'compares', 'totals'));
|
return view($view_template, compact(
|
||||||
|
'chart',
|
||||||
|
'dates',
|
||||||
|
'income_categories',
|
||||||
|
'expense_categories',
|
||||||
|
'categories',
|
||||||
|
'statuses',
|
||||||
|
'accounts',
|
||||||
|
'customers',
|
||||||
|
'vendors',
|
||||||
|
'compares',
|
||||||
|
'totals',
|
||||||
|
'print_url'
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function setAmount(&$graph, &$totals, &$compares, $items, $type, $date_field)
|
private function setAmount(&$graph, &$totals, &$compares, $items, $type, $date_field)
|
||||||
{
|
{
|
||||||
foreach ($items as $item) {
|
foreach ($items as $item) {
|
||||||
if ($item['table'] == 'bill_payments' || $item['table'] == 'invoice_payments') {
|
if ($item->getTable() == 'bill_payments' || $item->getTable() == 'invoice_payments') {
|
||||||
$type_item = $item->$type;
|
$type_item = $item->$type;
|
||||||
|
|
||||||
$item->category_id = $type_item->category_id;
|
$item->category_id = $type_item->category_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
$date = Date::parse($item->$date_field)->format('F');
|
switch ($item->getTable()) {
|
||||||
|
case 'invoice_payments':
|
||||||
|
$invoice = $item->invoice;
|
||||||
|
|
||||||
|
if ($customers = request('customers')) {
|
||||||
|
if (!in_array($invoice->customer_id, $customers)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$item->category_id = $invoice->category_id;
|
||||||
|
break;
|
||||||
|
case 'bill_payments':
|
||||||
|
$bill = $item->bill;
|
||||||
|
|
||||||
|
if ($vendors = request('vendors')) {
|
||||||
|
if (!in_array($bill->vendor_id, $vendors)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$item->category_id = $bill->category_id;
|
||||||
|
break;
|
||||||
|
case 'invoices':
|
||||||
|
case 'bills':
|
||||||
|
if ($accounts = request('accounts')) {
|
||||||
|
foreach ($item->payments as $payment) {
|
||||||
|
if (!in_array($payment->account_id, $accounts)) {
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$month = Date::parse($item->$date_field)->format('F');
|
||||||
|
$month_year = Date::parse($item->$date_field)->format('F-Y');
|
||||||
|
|
||||||
$group = (($type == 'invoice') || ($type == 'revenue')) ? 'income' : 'expense';
|
$group = (($type == 'invoice') || ($type == 'revenue')) ? 'income' : 'expense';
|
||||||
|
|
||||||
if (!isset($compares[$group][$item->category_id])) {
|
if (!isset($compares[$group][$item->category_id]) || !isset($compares[$group][$item->category_id][$month]) || !isset($graph[$month_year])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,19 +242,44 @@ class IncomeExpenseSummary extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$compares[$group][$item->category_id][$date]['amount'] += $amount;
|
$compares[$group][$item->category_id][$month]['amount'] += $amount;
|
||||||
$compares[$group][$item->category_id][$date]['currency_code'] = $item->currency_code;
|
$compares[$group][$item->category_id][$month]['currency_code'] = $item->currency_code;
|
||||||
$compares[$group][$item->category_id][$date]['currency_rate'] = $item->currency_rate;
|
$compares[$group][$item->category_id][$month]['currency_rate'] = $item->currency_rate;
|
||||||
|
|
||||||
if ($group == 'income') {
|
if ($group == 'income') {
|
||||||
$graph[Date::parse($item->$date_field)->format('F-Y')] += $amount;
|
$graph[$month_year] += $amount;
|
||||||
|
|
||||||
$totals[$date]['amount'] += $amount;
|
$totals[$month]['amount'] += $amount;
|
||||||
} else {
|
} else {
|
||||||
$graph[Date::parse($item->$date_field)->format('F-Y')] -= $amount;
|
$graph[$month_year] -= $amount;
|
||||||
|
|
||||||
$totals[$date]['amount'] -= $amount;
|
$totals[$month]['amount'] -= $amount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getPrintUrl($year)
|
||||||
|
{
|
||||||
|
$print_url = 'reports/income-expense-summary?print=1'
|
||||||
|
. '&status=' . request('status')
|
||||||
|
. '&year='. request('year', $year);
|
||||||
|
|
||||||
|
collect(request('accounts'))->each(function($item) use(&$print_url) {
|
||||||
|
$print_url .= '&accounts[]=' . $item;
|
||||||
|
});
|
||||||
|
|
||||||
|
collect(request('customers'))->each(function($item) use(&$print_url) {
|
||||||
|
$print_url .= '&customers[]=' . $item;
|
||||||
|
});
|
||||||
|
|
||||||
|
collect(request('vendors'))->each(function($item) use(&$print_url) {
|
||||||
|
$print_url .= '&vendors[]=' . $item;
|
||||||
|
});
|
||||||
|
|
||||||
|
collect(request('categories'))->each(function($item) use(&$print_url) {
|
||||||
|
$print_url .= '&categories[]=' . $item;
|
||||||
|
});
|
||||||
|
|
||||||
|
return $print_url;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,10 +3,13 @@
|
|||||||
namespace App\Http\Controllers\Reports;
|
namespace App\Http\Controllers\Reports;
|
||||||
|
|
||||||
use App\Http\Controllers\Controller;
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Models\Banking\Account;
|
||||||
|
use App\Models\Income\Customer;
|
||||||
use App\Models\Income\Invoice;
|
use App\Models\Income\Invoice;
|
||||||
use App\Models\Income\InvoicePayment;
|
use App\Models\Income\InvoicePayment;
|
||||||
use App\Models\Income\Revenue;
|
use App\Models\Income\Revenue;
|
||||||
use App\Models\Setting\Category;
|
use App\Models\Setting\Category;
|
||||||
|
use App\Utilities\Recurring;
|
||||||
use Charts;
|
use Charts;
|
||||||
use Date;
|
use Date;
|
||||||
|
|
||||||
@ -22,13 +25,16 @@ class IncomeSummary extends Controller
|
|||||||
$dates = $totals = $incomes = $incomes_graph = $categories = [];
|
$dates = $totals = $incomes = $incomes_graph = $categories = [];
|
||||||
|
|
||||||
$status = request('status');
|
$status = request('status');
|
||||||
|
$year = request('year', Date::now()->year);
|
||||||
|
|
||||||
$categories = Category::enabled()->type('income')->pluck('name', 'id')->toArray();
|
$categories = Category::enabled()->type('income')->orderBy('name')->pluck('name', 'id')->toArray();
|
||||||
|
|
||||||
// Get year
|
if ($categories_filter = request('categories')) {
|
||||||
$year = request('year');
|
$cats = collect($categories)->filter(function ($value, $key) use ($categories_filter) {
|
||||||
if (empty($year)) {
|
return in_array($key, $categories_filter);
|
||||||
$year = Date::now()->year;
|
});
|
||||||
|
} else {
|
||||||
|
$cats = $categories;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dates
|
// Dates
|
||||||
@ -44,38 +50,58 @@ class IncomeSummary extends Controller
|
|||||||
'currency_rate' => 1
|
'currency_rate' => 1
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($categories as $category_id => $category_name) {
|
foreach ($cats as $category_id => $category_name) {
|
||||||
$incomes[$category_id][$dates[$j]] = array(
|
$incomes[$category_id][$dates[$j]] = [
|
||||||
'category_id' => $category_id,
|
'category_id' => $category_id,
|
||||||
'name' => $category_name,
|
'name' => $category_name,
|
||||||
'amount' => 0,
|
'amount' => 0,
|
||||||
'currency_code' => setting('general.default_currency'),
|
'currency_code' => setting('general.default_currency'),
|
||||||
'currency_rate' => 1
|
'currency_rate' => 1
|
||||||
);
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoices
|
$revenues = Revenue::monthsOfYear('paid_at')->account(request('accounts'))->customer(request('customers'))->isNotTransfer()->get();
|
||||||
|
|
||||||
switch ($status) {
|
switch ($status) {
|
||||||
case 'paid':
|
case 'paid':
|
||||||
$invoices = InvoicePayment::monthsOfYear('paid_at')->get();
|
// Invoices
|
||||||
|
$invoices = InvoicePayment::monthsOfYear('paid_at')->account(request('accounts'))->get();
|
||||||
$this->setAmount($incomes_graph, $totals, $incomes, $invoices, 'invoice', 'paid_at');
|
$this->setAmount($incomes_graph, $totals, $incomes, $invoices, 'invoice', 'paid_at');
|
||||||
|
|
||||||
|
// Revenues
|
||||||
|
$this->setAmount($incomes_graph, $totals, $incomes, $revenues, 'revenue', 'paid_at');
|
||||||
break;
|
break;
|
||||||
case 'upcoming':
|
case 'upcoming':
|
||||||
$invoices = Invoice::accrued()->monthsOfYear('due_at')->get();
|
// Invoices
|
||||||
|
$invoices = Invoice::accrued()->monthsOfYear('due_at')->customer(request('customers'))->get();
|
||||||
|
Recurring::reflect($invoices, 'invoice', 'invoiced_at', $status);
|
||||||
$this->setAmount($incomes_graph, $totals, $incomes, $invoices, 'invoice', 'due_at');
|
$this->setAmount($incomes_graph, $totals, $incomes, $invoices, 'invoice', 'due_at');
|
||||||
|
|
||||||
|
// Revenues
|
||||||
|
Recurring::reflect($revenues, 'revenue', 'paid_at', $status);
|
||||||
|
$this->setAmount($incomes_graph, $totals, $incomes, $revenues, 'revenue', 'paid_at');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
$invoices = Invoice::accrued()->monthsOfYear('invoiced_at')->get();
|
// Invoices
|
||||||
|
$invoices = Invoice::accrued()->monthsOfYear('invoiced_at')->customer(request('customers'))->get();
|
||||||
|
Recurring::reflect($invoices, 'invoice', 'invoiced_at', $status);
|
||||||
$this->setAmount($incomes_graph, $totals, $incomes, $invoices, 'invoice', 'invoiced_at');
|
$this->setAmount($incomes_graph, $totals, $incomes, $invoices, 'invoice', 'invoiced_at');
|
||||||
|
|
||||||
|
// Revenues
|
||||||
|
Recurring::reflect($revenues, 'revenue', 'paid_at', $status);
|
||||||
|
$this->setAmount($incomes_graph, $totals, $incomes, $revenues, 'revenue', 'paid_at');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Revenues
|
$statuses = collect([
|
||||||
if ($status != 'upcoming') {
|
'all' => trans('general.all'),
|
||||||
$revenues = Revenue::monthsOfYear('paid_at')->isNotTransfer()->get();
|
'paid' => trans('invoices.paid'),
|
||||||
$this->setAmount($incomes_graph, $totals, $incomes, $revenues, 'revenue', 'paid_at');
|
'upcoming' => trans('dashboard.receivables'),
|
||||||
}
|
]);
|
||||||
|
|
||||||
|
$accounts = Account::enabled()->pluck('name', 'id')->toArray();
|
||||||
|
$customers = Customer::enabled()->pluck('name', 'id')->toArray();
|
||||||
|
|
||||||
// Check if it's a print or normal request
|
// Check if it's a print or normal request
|
||||||
if (request('print')) {
|
if (request('print')) {
|
||||||
@ -86,6 +112,8 @@ class IncomeSummary extends Controller
|
|||||||
$view_template = 'reports.income_summary.index';
|
$view_template = 'reports.income_summary.index';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$print_url = $this->getPrintUrl($year);
|
||||||
|
|
||||||
// Incomes chart
|
// Incomes chart
|
||||||
$chart = Charts::multi('line', 'chartjs')
|
$chart = Charts::multi('line', 'chartjs')
|
||||||
->dimensions(0, 300)
|
->dimensions(0, 300)
|
||||||
@ -95,21 +123,49 @@ class IncomeSummary extends Controller
|
|||||||
->credits(false)
|
->credits(false)
|
||||||
->view($chart_template);
|
->view($chart_template);
|
||||||
|
|
||||||
return view($view_template, compact('chart', 'dates', 'categories', 'incomes', 'totals'));
|
return view($view_template, compact(
|
||||||
|
'chart',
|
||||||
|
'dates',
|
||||||
|
'categories',
|
||||||
|
'statuses',
|
||||||
|
'accounts',
|
||||||
|
'customers',
|
||||||
|
'incomes',
|
||||||
|
'totals',
|
||||||
|
'print_url'
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function setAmount(&$graph, &$totals, &$incomes, $items, $type, $date_field)
|
private function setAmount(&$graph, &$totals, &$incomes, $items, $type, $date_field)
|
||||||
{
|
{
|
||||||
foreach ($items as $item) {
|
foreach ($items as $item) {
|
||||||
if ($item['table'] == 'invoice_payments') {
|
switch ($item->getTable()) {
|
||||||
$invoice = $item->invoice;
|
case 'invoice_payments':
|
||||||
|
$invoice = $item->invoice;
|
||||||
|
|
||||||
$item->category_id = $invoice->category_id;
|
if ($customers = request('customers')) {
|
||||||
|
if (!in_array($invoice->customer_id, $customers)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$item->category_id = $invoice->category_id;
|
||||||
|
break;
|
||||||
|
case 'invoices':
|
||||||
|
if ($accounts = request('accounts')) {
|
||||||
|
foreach ($item->payments as $payment) {
|
||||||
|
if (!in_array($payment->account_id, $accounts)) {
|
||||||
|
continue 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$date = Date::parse($item->$date_field)->format('F');
|
$month = Date::parse($item->$date_field)->format('F');
|
||||||
|
$month_year = Date::parse($item->$date_field)->format('F-Y');
|
||||||
|
|
||||||
if (!isset($incomes[$item->category_id])) {
|
if (!isset($incomes[$item->category_id]) || !isset($incomes[$item->category_id][$month]) || !isset($graph[$month_year])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,13 +178,34 @@ class IncomeSummary extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$incomes[$item->category_id][$date]['amount'] += $amount;
|
$incomes[$item->category_id][$month]['amount'] += $amount;
|
||||||
$incomes[$item->category_id][$date]['currency_code'] = $item->currency_code;
|
$incomes[$item->category_id][$month]['currency_code'] = $item->currency_code;
|
||||||
$incomes[$item->category_id][$date]['currency_rate'] = $item->currency_rate;
|
$incomes[$item->category_id][$month]['currency_rate'] = $item->currency_rate;
|
||||||
|
|
||||||
$graph[Date::parse($item->$date_field)->format('F-Y')] += $amount;
|
$graph[$month_year] += $amount;
|
||||||
|
|
||||||
$totals[$date]['amount'] += $amount;
|
$totals[$month]['amount'] += $amount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getPrintUrl($year)
|
||||||
|
{
|
||||||
|
$print_url = 'reports/income-summary?print=1'
|
||||||
|
. '&status=' . request('status')
|
||||||
|
. '&year='. request('year', $year);
|
||||||
|
|
||||||
|
collect(request('accounts'))->each(function($item) use(&$print_url) {
|
||||||
|
$print_url .= '&accounts[]=' . $item;
|
||||||
|
});
|
||||||
|
|
||||||
|
collect(request('customers'))->each(function($item) use(&$print_url) {
|
||||||
|
$print_url .= '&customers[]=' . $item;
|
||||||
|
});
|
||||||
|
|
||||||
|
collect(request('categories'))->each(function($item) use(&$print_url) {
|
||||||
|
$print_url .= '&categories[]=' . $item;
|
||||||
|
});
|
||||||
|
|
||||||
|
return $print_url;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,16 +25,11 @@ class ProfitLoss extends Controller
|
|||||||
$dates = $totals = $compares = $categories = [];
|
$dates = $totals = $compares = $categories = [];
|
||||||
|
|
||||||
$status = request('status');
|
$status = request('status');
|
||||||
|
$year = request('year', Date::now()->year);
|
||||||
|
|
||||||
$income_categories = Category::enabled()->type('income')->pluck('name', 'id')->toArray();
|
$income_categories = Category::enabled()->type('income')->orderBy('name')->pluck('name', 'id')->toArray();
|
||||||
|
|
||||||
$expense_categories = Category::enabled()->type('expense')->pluck('name', 'id')->toArray();
|
$expense_categories = Category::enabled()->type('expense')->orderBy('name')->pluck('name', 'id')->toArray();
|
||||||
|
|
||||||
// Get year
|
|
||||||
$year = request('year');
|
|
||||||
if (empty($year)) {
|
|
||||||
$year = Date::now()->year;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dates
|
// Dates
|
||||||
for ($j = 1; $j <= 12; $j++) {
|
for ($j = 1; $j <= 12; $j++) {
|
||||||
@ -142,6 +137,12 @@ class ProfitLoss extends Controller
|
|||||||
$this->setAmount($totals, $compares, $payments, 'payment', 'paid_at');
|
$this->setAmount($totals, $compares, $payments, 'payment', 'paid_at');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$statuses = collect([
|
||||||
|
'all' => trans('general.all'),
|
||||||
|
'paid' => trans('invoices.paid'),
|
||||||
|
'upcoming' => trans('general.upcoming'),
|
||||||
|
]);
|
||||||
|
|
||||||
// Check if it's a print or normal request
|
// Check if it's a print or normal request
|
||||||
if (request('print')) {
|
if (request('print')) {
|
||||||
$view_template = 'reports.profit_loss.print';
|
$view_template = 'reports.profit_loss.print';
|
||||||
@ -149,7 +150,7 @@ class ProfitLoss extends Controller
|
|||||||
$view_template = 'reports.profit_loss.index';
|
$view_template = 'reports.profit_loss.index';
|
||||||
}
|
}
|
||||||
|
|
||||||
return view($view_template, compact('dates', 'income_categories', 'expense_categories', 'compares', 'totals', 'gross'));
|
return view($view_template, compact('dates', 'income_categories', 'expense_categories', 'compares', 'totals', 'gross', 'statuses'));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function setAmount(&$totals, &$compares, $items, $type, $date_field)
|
private function setAmount(&$totals, &$compares, $items, $type, $date_field)
|
||||||
|
@ -27,17 +27,12 @@ class TaxSummary extends Controller
|
|||||||
$dates = $incomes = $expenses = $totals = [];
|
$dates = $incomes = $expenses = $totals = [];
|
||||||
|
|
||||||
$status = request('status');
|
$status = request('status');
|
||||||
|
$year = request('year', Date::now()->year);
|
||||||
|
|
||||||
$t = Tax::enabled()->where('rate', '<>', '0')->pluck('name')->toArray();
|
$t = Tax::enabled()->where('rate', '<>', '0')->pluck('name')->toArray();
|
||||||
|
|
||||||
$taxes = array_combine($t, $t);
|
$taxes = array_combine($t, $t);
|
||||||
|
|
||||||
// Get year
|
|
||||||
$year = request('year');
|
|
||||||
if (empty($year)) {
|
|
||||||
$year = Date::now()->year;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dates
|
// Dates
|
||||||
for ($j = 1; $j <= 12; $j++) {
|
for ($j = 1; $j <= 12; $j++) {
|
||||||
$dates[$j] = Date::parse($year . '-' . $j)->format('M');
|
$dates[$j] = Date::parse($year . '-' . $j)->format('M');
|
||||||
@ -90,6 +85,12 @@ class TaxSummary extends Controller
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$statuses = collect([
|
||||||
|
'all' => trans('general.all'),
|
||||||
|
'paid' => trans('invoices.paid'),
|
||||||
|
'upcoming' => trans('general.upcoming'),
|
||||||
|
]);
|
||||||
|
|
||||||
// Check if it's a print or normal request
|
// Check if it's a print or normal request
|
||||||
if (request('print')) {
|
if (request('print')) {
|
||||||
$view_template = 'reports.tax_summary.print';
|
$view_template = 'reports.tax_summary.print';
|
||||||
@ -97,13 +98,13 @@ class TaxSummary extends Controller
|
|||||||
$view_template = 'reports.tax_summary.index';
|
$view_template = 'reports.tax_summary.index';
|
||||||
}
|
}
|
||||||
|
|
||||||
return view($view_template, compact('dates', 'taxes', 'incomes', 'expenses', 'totals'));
|
return view($view_template, compact('dates', 'taxes', 'incomes', 'expenses', 'totals', 'statuses'));
|
||||||
}
|
}
|
||||||
|
|
||||||
private function setAmount(&$items, &$totals, $rows, $type, $date_field)
|
private function setAmount(&$items, &$totals, $rows, $type, $date_field)
|
||||||
{
|
{
|
||||||
foreach ($rows as $row) {
|
foreach ($rows as $row) {
|
||||||
if ($row['table'] == 'bill_payments' || $row['table'] == 'invoice_payments') {
|
if ($row->getTable() == 'bill_payments' || $row->getTable() == 'invoice_payments') {
|
||||||
$type_row = $row->$type;
|
$type_row = $row->$type;
|
||||||
|
|
||||||
$row->category_id = $type_row->category_id;
|
$row->category_id = $type_row->category_id;
|
||||||
@ -126,7 +127,14 @@ class TaxSummary extends Controller
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$amount = $this->convert($row_total->amount, $row->currency_code, $row->currency_rate);
|
if ($date_field == 'paid_at') {
|
||||||
|
$rate = ($row->amount * 100) / $type_row->amount;
|
||||||
|
$row_amount = ($row_total->amount / 100) * $rate;
|
||||||
|
} else {
|
||||||
|
$row_amount = $row_total->amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
$amount = $this->convert($row_amount, $row->currency_code, $row->currency_rate);
|
||||||
|
|
||||||
$items[$row_total->name][$date]['amount'] += $amount;
|
$items[$row_total->name][$date]['amount'] += $amount;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ class Categories extends Controller
|
|||||||
'income' => trans_choice('general.incomes', 1),
|
'income' => trans_choice('general.incomes', 1),
|
||||||
'item' => trans_choice('general.items', 1),
|
'item' => trans_choice('general.items', 1),
|
||||||
'other' => trans_choice('general.others', 1),
|
'other' => trans_choice('general.others', 1),
|
||||||
])->prepend(trans('general.all_type', ['type' => trans_choice('general.types', 2)]), '');
|
]);
|
||||||
|
|
||||||
return view('settings.categories.index', compact('categories', 'types', 'transfer_id'));
|
return view('settings.categories.index', compact('categories', 'types', 'transfer_id'));
|
||||||
}
|
}
|
||||||
|
@ -162,7 +162,7 @@ class Currencies extends Controller
|
|||||||
|
|
||||||
return redirect('settings/currencies');
|
return redirect('settings/currencies');
|
||||||
} else {
|
} else {
|
||||||
$message = trans('messages.warning.disabled', ['name' => $currency->name, 'text' => implode(', ', $relationships)]);
|
$message = trans('messages.warning.disable_code', ['name' => $currency->name, 'text' => implode(', ', $relationships)]);
|
||||||
|
|
||||||
flash($message)->warning();
|
flash($message)->warning();
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class Settings extends Controller
|
|||||||
|
|
||||||
$currencies = Currency::enabled()->orderBy('name')->pluck('name', 'code');
|
$currencies = Currency::enabled()->orderBy('name')->pluck('name', 'code');
|
||||||
|
|
||||||
$taxes = Tax::enabled()->orderBy('rate')->get()->pluck('title', 'id');
|
$taxes = Tax::enabled()->orderBy('name')->get()->pluck('title', 'id');
|
||||||
|
|
||||||
$payment_methods = Modules::getPaymentMethods();
|
$payment_methods = Modules::getPaymentMethods();
|
||||||
|
|
||||||
@ -67,6 +67,24 @@ class Settings extends Controller
|
|||||||
'space' => trans('settings.localisation.date.space'),
|
'space' => trans('settings.localisation.date.space'),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
$item_names = [
|
||||||
|
'settings.invoice.item' => trans('settings.invoice.item'),
|
||||||
|
'settings.invoice.product' => trans('settings.invoice.product'),
|
||||||
|
'settings.invoice.service' => trans('settings.invoice.service'),
|
||||||
|
'custom' => trans('settings.invoice.custom'),
|
||||||
|
];
|
||||||
|
|
||||||
|
$price_names = [
|
||||||
|
'settings.invoice.price' => trans('settings.invoice.price'),
|
||||||
|
'settings.invoice.rate' => trans('settings.invoice.rate'),
|
||||||
|
'custom' => trans('settings.invoice.custom'),
|
||||||
|
];
|
||||||
|
|
||||||
|
$quantity_names = [
|
||||||
|
'settings.invoice.quantity' => trans('settings.invoice.quantity'),
|
||||||
|
'custom' => trans('settings.invoice.custom'),
|
||||||
|
];
|
||||||
|
|
||||||
$email_protocols = [
|
$email_protocols = [
|
||||||
'mail' => trans('settings.email.php'),
|
'mail' => trans('settings.email.php'),
|
||||||
'smtp' => trans('settings.email.smtp.name'),
|
'smtp' => trans('settings.email.smtp.name'),
|
||||||
@ -88,6 +106,9 @@ class Settings extends Controller
|
|||||||
'payment_methods',
|
'payment_methods',
|
||||||
'date_formats',
|
'date_formats',
|
||||||
'date_separators',
|
'date_separators',
|
||||||
|
'item_names',
|
||||||
|
'price_names',
|
||||||
|
'quantity_names',
|
||||||
'email_protocols',
|
'email_protocols',
|
||||||
'percent_positions'
|
'percent_positions'
|
||||||
));
|
));
|
||||||
@ -160,17 +181,17 @@ class Settings extends Controller
|
|||||||
protected function oneCompany($key, $value)
|
protected function oneCompany($key, $value)
|
||||||
{
|
{
|
||||||
switch ($key) {
|
switch ($key) {
|
||||||
|
case 'company_name':
|
||||||
|
Installer::updateEnv(['MAIL_FROM_NAME' => '"' . $value . '"']);
|
||||||
|
break;
|
||||||
|
case 'company_email':
|
||||||
|
Installer::updateEnv(['MAIL_FROM_ADDRESS' => $value]);
|
||||||
|
break;
|
||||||
case 'default_locale':
|
case 'default_locale':
|
||||||
// Change default locale
|
Installer::updateEnv(['APP_LOCALE' => $value]);
|
||||||
Installer::updateEnv([
|
|
||||||
'APP_LOCALE' => $value
|
|
||||||
]);
|
|
||||||
break;
|
break;
|
||||||
case 'session_handler':
|
case 'session_handler':
|
||||||
// Change session handler
|
Installer::updateEnv(['SESSION_DRIVER' => $value]);
|
||||||
Installer::updateEnv([
|
|
||||||
'SESSION_DRIVER' => $value
|
|
||||||
]);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,13 @@ class Taxes extends Controller
|
|||||||
{
|
{
|
||||||
$taxes = Tax::collect();
|
$taxes = Tax::collect();
|
||||||
|
|
||||||
return view('settings.taxes.index', compact('taxes', 'rates'));
|
$types = [
|
||||||
|
'normal' => trans('taxes.normal'),
|
||||||
|
'inclusive' => trans('taxes.inclusive'),
|
||||||
|
'compound' => trans('taxes.compound'),
|
||||||
|
];
|
||||||
|
|
||||||
|
return view('settings.taxes.index', compact('taxes', 'types'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -38,7 +44,13 @@ class Taxes extends Controller
|
|||||||
*/
|
*/
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
return view('settings.taxes.create');
|
$types = [
|
||||||
|
'normal' => trans('taxes.normal'),
|
||||||
|
'inclusive' => trans('taxes.inclusive'),
|
||||||
|
'compound' => trans('taxes.compound'),
|
||||||
|
];
|
||||||
|
|
||||||
|
return view('settings.taxes.create', compact('types'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,7 +80,13 @@ class Taxes extends Controller
|
|||||||
*/
|
*/
|
||||||
public function edit(Tax $tax)
|
public function edit(Tax $tax)
|
||||||
{
|
{
|
||||||
return view('settings.taxes.edit', compact('tax'));
|
$types = [
|
||||||
|
'normal' => trans('taxes.normal'),
|
||||||
|
'inclusive' => trans('taxes.inclusive'),
|
||||||
|
'compound' => trans('taxes.compound'),
|
||||||
|
];
|
||||||
|
|
||||||
|
return view('settings.taxes.edit', compact('tax', 'types'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
81
app/Http/Controllers/Wizard/Companies.php
Normal file
81
app/Http/Controllers/Wizard/Companies.php
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Wizard;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\Wizard\Company as Request;
|
||||||
|
use App\Models\Common\Company;
|
||||||
|
use App\Traits\Uploads;
|
||||||
|
|
||||||
|
class Companies extends Controller
|
||||||
|
{
|
||||||
|
use Uploads;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function edit()
|
||||||
|
{
|
||||||
|
if (setting('general.wizard', false)) {
|
||||||
|
return redirect('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
$company = Company::find(session('company_id'));
|
||||||
|
|
||||||
|
$company->setSettings();
|
||||||
|
|
||||||
|
return view('wizard.companies.edit', compact('company'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param Company $company
|
||||||
|
* @param Request $request
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function update(Request $request)
|
||||||
|
{
|
||||||
|
// Company
|
||||||
|
$company = Company::find(session('company_id'));
|
||||||
|
|
||||||
|
$fields = $request->all();
|
||||||
|
|
||||||
|
$skip_keys = ['company_id', '_method', '_token'];
|
||||||
|
$file_keys = ['company_logo', 'invoice_logo'];
|
||||||
|
|
||||||
|
foreach ($fields as $key => $value) {
|
||||||
|
// Don't process unwanted keys
|
||||||
|
if (in_array($key, $skip_keys)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process file uploads
|
||||||
|
if (in_array($key, $file_keys)) {
|
||||||
|
// Upload attachment
|
||||||
|
if ($request->file($key)) {
|
||||||
|
$media = $this->getMedia($request->file($key), 'settings');
|
||||||
|
|
||||||
|
$company->attachMedia($media, $key);
|
||||||
|
|
||||||
|
$value = $media->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevent reset
|
||||||
|
if (empty($value)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setting()->set('general.' . $key, $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save all settings
|
||||||
|
setting()->save();
|
||||||
|
|
||||||
|
return redirect('wizard/currencies');
|
||||||
|
}
|
||||||
|
}
|
311
app/Http/Controllers/Wizard/Currencies.php
Normal file
311
app/Http/Controllers/Wizard/Currencies.php
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Wizard;
|
||||||
|
|
||||||
|
use Akaunting\Money\Currency as MoneyCurrency;
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\Setting\Currency as Request;
|
||||||
|
use App\Models\Banking\Account;
|
||||||
|
use App\Models\Setting\Currency;
|
||||||
|
|
||||||
|
class Currencies extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*
|
||||||
|
* @param Currency $currency
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
if (setting('general.wizard', false)) {
|
||||||
|
return redirect('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
$currencies = Currency::all();
|
||||||
|
|
||||||
|
return view('wizard.currencies.index', compact('currencies'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
if (setting(setting('general.wizard', false))) {
|
||||||
|
return redirect('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get current currencies
|
||||||
|
$current = Currency::pluck('code')->toArray();
|
||||||
|
|
||||||
|
// Prepare codes
|
||||||
|
$codes = array();
|
||||||
|
$currencies = MoneyCurrency::getCurrencies();
|
||||||
|
foreach ($currencies as $key => $item) {
|
||||||
|
// Don't show if already available
|
||||||
|
if (in_array($key, $current)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$codes[$key] = $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
$html = view('wizard.currencies.create', compact('codes'))->render();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'message' => 'null',
|
||||||
|
'html' => $html,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
// Force the rate to be 1 for default currency
|
||||||
|
if ($request['default_currency']) {
|
||||||
|
$request['rate'] = '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
$currency = Currency::create($request->all());
|
||||||
|
|
||||||
|
// Update default currency setting
|
||||||
|
if ($request['default_currency']) {
|
||||||
|
setting()->set('general.default_currency', $request['code']);
|
||||||
|
setting()->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = trans('messages.success.added', ['type' => trans_choice('general.currencies', 1)]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'message' => $message,
|
||||||
|
'data' => $currency,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*
|
||||||
|
* @param Currency $currency
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function edit(Currency $currency)
|
||||||
|
{
|
||||||
|
if (setting('general.wizard', false)) {
|
||||||
|
return redirect('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get current currencies
|
||||||
|
$current = Currency::pluck('code')->toArray();
|
||||||
|
|
||||||
|
// Prepare codes
|
||||||
|
$codes = array();
|
||||||
|
$currencies = MoneyCurrency::getCurrencies();
|
||||||
|
foreach ($currencies as $key => $item) {
|
||||||
|
// Don't show if already available
|
||||||
|
if (($key != $currency->code) && in_array($key, $current)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$codes[$key] = $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = $currency;
|
||||||
|
|
||||||
|
$html = view('wizard.currencies.edit', compact('item', 'codes'))->render();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'message' => 'null',
|
||||||
|
'html' => $html,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param Currency $currency
|
||||||
|
* @param Request $request
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function update(Currency $currency, Request $request)
|
||||||
|
{
|
||||||
|
// Check if we can disable or change the code
|
||||||
|
if (!$request['enabled'] || ($currency->code != $request['code'])) {
|
||||||
|
$relationships = $this->countRelationships($currency, [
|
||||||
|
'accounts' => 'accounts',
|
||||||
|
'customers' => 'customers',
|
||||||
|
'invoices' => 'invoices',
|
||||||
|
'revenues' => 'revenues',
|
||||||
|
'bills' => 'bills',
|
||||||
|
'payments' => 'payments',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($currency->code == setting('general.default_currency')) {
|
||||||
|
$relationships[] = strtolower(trans_choice('general.companies', 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($relationships)) {
|
||||||
|
// Force the rate to be 1 for default currency
|
||||||
|
if ($request['default_currency']) {
|
||||||
|
$request['rate'] = '1';
|
||||||
|
}
|
||||||
|
|
||||||
|
$currency->update($request->all());
|
||||||
|
|
||||||
|
// Update default currency setting
|
||||||
|
if ($request['default_currency']) {
|
||||||
|
setting()->set('general.default_currency', $request['code']);
|
||||||
|
setting()->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = trans('messages.success.updated', ['type' => trans_choice('general.currencies', 1)]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'message' => $message,
|
||||||
|
'data' => $currency,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$message = trans('messages.warning.disabled', ['name' => $currency->name, 'text' => implode(', ', $relationships)]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'message' => $message,
|
||||||
|
'data' => $currency,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable the specified resource.
|
||||||
|
*
|
||||||
|
* @param Currency $currency
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function enable(Currency $currency)
|
||||||
|
{
|
||||||
|
$currency->enabled = 1;
|
||||||
|
$currency->save();
|
||||||
|
|
||||||
|
$message = trans('messages.success.enabled', ['type' => trans_choice('general.currencies', 1)]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'message' => $message,
|
||||||
|
'data' => $currency,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable the specified resource.
|
||||||
|
*
|
||||||
|
* @param Currency $currency
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function disable(Currency $currency)
|
||||||
|
{
|
||||||
|
$relationships = $this->countRelationships($currency, [
|
||||||
|
'accounts' => 'accounts',
|
||||||
|
'customers' => 'customers',
|
||||||
|
'invoices' => 'invoices',
|
||||||
|
'revenues' => 'revenues',
|
||||||
|
'bills' => 'bills',
|
||||||
|
'payments' => 'payments',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($currency->code == setting('general.default_currency')) {
|
||||||
|
$relationships[] = strtolower(trans_choice('general.companies', 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($relationships)) {
|
||||||
|
$currency->enabled = 0;
|
||||||
|
$currency->save();
|
||||||
|
|
||||||
|
$message = trans('messages.success.disabled', ['type' => trans_choice('general.currencies', 1)]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'message' => $message,
|
||||||
|
'data' => $currency,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$message = trans('messages.warning.disabled', ['name' => $currency->name, 'text' => implode(', ', $relationships)]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'error' => true,
|
||||||
|
'message' => $message,
|
||||||
|
'data' => $currency,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*
|
||||||
|
* @param Currency $currency
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function destroy(Currency $currency)
|
||||||
|
{
|
||||||
|
$relationships = $this->countRelationships($currency, [
|
||||||
|
'accounts' => 'accounts',
|
||||||
|
'customers' => 'customers',
|
||||||
|
'invoices' => 'invoices',
|
||||||
|
'revenues' => 'revenues',
|
||||||
|
'bills' => 'bills',
|
||||||
|
'payments' => 'payments',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($currency->code == setting('general.default_currency')) {
|
||||||
|
$relationships[] = strtolower(trans_choice('general.companies', 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($relationships)) {
|
||||||
|
$currency->delete();
|
||||||
|
|
||||||
|
$message = trans('messages.success.deleted', ['type' => trans_choice('general.currencies', 1)]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'message' => $message,
|
||||||
|
'data' => $currency,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$message = trans('messages.warning.deleted', ['name' => $currency->name, 'text' => implode(', ', $relationships)]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'error' => true,
|
||||||
|
'message' => $message,
|
||||||
|
'data' => $currency,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
app/Http/Controllers/Wizard/Finish.php
Normal file
39
app/Http/Controllers/Wizard/Finish.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Wizard;
|
||||||
|
|
||||||
|
use Illuminate\Routing\Controller;
|
||||||
|
use App\Traits\Modules;
|
||||||
|
use App\Models\Module\Module;
|
||||||
|
|
||||||
|
class Finish extends Controller
|
||||||
|
{
|
||||||
|
use Modules;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
if (setting(setting('general.wizard', false))) {
|
||||||
|
return redirect('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
setting()->set('general.wizard', true);
|
||||||
|
|
||||||
|
// Save all settings
|
||||||
|
setting()->save();
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'query' => [
|
||||||
|
'limit' => 4
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$modules = $this->getFeaturedModules($data);
|
||||||
|
|
||||||
|
return view('wizard.finish.index', compact('modules'));
|
||||||
|
}
|
||||||
|
}
|
231
app/Http/Controllers/Wizard/Taxes.php
Normal file
231
app/Http/Controllers/Wizard/Taxes.php
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Wizard;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use App\Http\Requests\Setting\Tax as Request;
|
||||||
|
use App\Models\Setting\Tax;
|
||||||
|
|
||||||
|
class Taxes extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
if (setting(setting('general.wizard', false))) {
|
||||||
|
return redirect('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
$taxes = Tax::all();
|
||||||
|
|
||||||
|
return view('wizard.taxes.index', compact('taxes'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for creating a new resource.
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
if (setting(setting('general.wizard', false))) {
|
||||||
|
return redirect('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
$html = view('wizard.taxes.create', compact('codes'))->render();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'message' => 'null',
|
||||||
|
'html' => $html,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a newly created resource in storage.
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$tax = Tax::create($request->all());
|
||||||
|
|
||||||
|
$message = trans('messages.success.added', ['type' => trans_choice('general.tax_rates', 1)]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'message' => $message,
|
||||||
|
'data' => $tax,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the form for editing the specified resource.
|
||||||
|
*
|
||||||
|
* @param Tax $tax
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function edit(Tax $tax)
|
||||||
|
{
|
||||||
|
if (setting(setting('general.wizard', false))) {
|
||||||
|
return redirect('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = $tax;
|
||||||
|
|
||||||
|
$html = view('wizard.taxes.edit', compact('item'))->render();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'message' => 'null',
|
||||||
|
'html' => $html,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the specified resource in storage.
|
||||||
|
*
|
||||||
|
* @param Tax $tax
|
||||||
|
* @param Request $request
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function update(Tax $tax, Request $request)
|
||||||
|
{
|
||||||
|
$relationships = $this->countRelationships($tax, [
|
||||||
|
'items' => 'items',
|
||||||
|
'invoice_items' => 'invoices',
|
||||||
|
'bill_items' => 'bills',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (empty($relationships) || $request['enabled']) {
|
||||||
|
$tax->update($request->all());
|
||||||
|
|
||||||
|
$message = trans('messages.success.updated', ['type' => trans_choice('general.tax_rates', 1)]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'message' => $message,
|
||||||
|
'data' => $tax,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$message = trans('messages.warning.disabled', ['name' => $tax->name, 'text' => implode(', ', $relationships)]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'message' => $message,
|
||||||
|
'data' => $tax,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable the specified resource.
|
||||||
|
*
|
||||||
|
* @param Tax $tax
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function enable(Tax $tax)
|
||||||
|
{
|
||||||
|
$tax->enabled = 1;
|
||||||
|
$tax->save();
|
||||||
|
|
||||||
|
$message = trans('messages.success.enabled', ['type' => trans_choice('general.tax_rates', 1)]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'message' => $message,
|
||||||
|
'data' => $tax,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable the specified resource.
|
||||||
|
*
|
||||||
|
* @param Tax $tax
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function disable(Tax $tax)
|
||||||
|
{
|
||||||
|
$relationships = $this->countRelationships($tax, [
|
||||||
|
'items' => 'items',
|
||||||
|
'invoice_items' => 'invoices',
|
||||||
|
'bill_items' => 'bills',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (empty($relationships)) {
|
||||||
|
$tax->enabled = 0;
|
||||||
|
$tax->save();
|
||||||
|
|
||||||
|
$message = trans('messages.success.disabled', ['type' => trans_choice('general.tax_rates', 1)]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'message' => $message,
|
||||||
|
'data' => $tax,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$message = trans('messages.warning.disabled', ['name' => $tax->name, 'text' => implode(', ', $relationships)]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'error' => true,
|
||||||
|
'message' => $message,
|
||||||
|
'data' => $tax,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the specified resource from storage.
|
||||||
|
*
|
||||||
|
* @param Tax $tax
|
||||||
|
*
|
||||||
|
* @return Response
|
||||||
|
*/
|
||||||
|
public function destroy(Tax $tax)
|
||||||
|
{
|
||||||
|
$relationships = $this->countRelationships($tax, [
|
||||||
|
'items' => 'items',
|
||||||
|
'invoice_items' => 'invoices',
|
||||||
|
'bill_items' => 'bills',
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (empty($relationships)) {
|
||||||
|
$tax->delete();
|
||||||
|
|
||||||
|
$message = trans('messages.success.deleted', ['type' => trans_choice('general.taxes', 1)]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'error' => false,
|
||||||
|
'message' => $message,
|
||||||
|
'data' => $tax,
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$message = trans('messages.warning.deleted', ['name' => $tax->name, 'text' => implode(', ', $relationships)]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'error' => true,
|
||||||
|
'message' => $message,
|
||||||
|
'data' => $tax,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -41,6 +41,13 @@ class Kernel extends HttpKernel
|
|||||||
'company.currencies',
|
'company.currencies',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'wizard' => [
|
||||||
|
'web',
|
||||||
|
'language',
|
||||||
|
'auth',
|
||||||
|
'permission:read-admin-panel',
|
||||||
|
],
|
||||||
|
|
||||||
'admin' => [
|
'admin' => [
|
||||||
'web',
|
'web',
|
||||||
'language',
|
'language',
|
||||||
|
@ -70,7 +70,7 @@ class AdminMenu
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expences
|
// Expenses
|
||||||
if ($user->can(['read-expenses-bills', 'read-expenses-payments', 'read-expenses-vendors'])) {
|
if ($user->can(['read-expenses-bills', 'read-expenses-payments', 'read-expenses-vendors'])) {
|
||||||
$menu->dropdown(trans_choice('general.expenses', 2), function ($sub) use($user, $attr) {
|
$menu->dropdown(trans_choice('general.expenses', 2), function ($sub) use($user, $attr) {
|
||||||
if ($user->can('read-expenses-bills')) {
|
if ($user->can('read-expenses-bills')) {
|
||||||
@ -91,7 +91,7 @@ class AdminMenu
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Banking
|
// Banking
|
||||||
if ($user->can(['read-banking-accounts', 'read-banking-transfers', 'read-banking-transactions'])) {
|
if ($user->can(['read-banking-accounts', 'read-banking-transfers', 'read-banking-transactions', 'read-banking-reconciliations'])) {
|
||||||
$menu->dropdown(trans('general.banking'), function ($sub) use($user, $attr) {
|
$menu->dropdown(trans('general.banking'), function ($sub) use($user, $attr) {
|
||||||
if ($user->can('read-banking-accounts')) {
|
if ($user->can('read-banking-accounts')) {
|
||||||
$sub->url('banking/accounts', trans_choice('general.accounts', 2), 1, $attr);
|
$sub->url('banking/accounts', trans_choice('general.accounts', 2), 1, $attr);
|
||||||
@ -104,6 +104,10 @@ class AdminMenu
|
|||||||
if ($user->can('read-banking-transactions')) {
|
if ($user->can('read-banking-transactions')) {
|
||||||
$sub->url('banking/transactions', trans_choice('general.transactions', 2), 3, $attr);
|
$sub->url('banking/transactions', trans_choice('general.transactions', 2), 3, $attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($user->can('read-banking-reconciliations')) {
|
||||||
|
$sub->url('banking/reconciliations', trans_choice('general.reconciliations', 2), 4, $attr);
|
||||||
|
}
|
||||||
}, 5, [
|
}, 5, [
|
||||||
'title' => trans('general.banking'),
|
'title' => trans('general.banking'),
|
||||||
'icon' => 'fa fa-university',
|
'icon' => 'fa fa-university',
|
||||||
@ -204,4 +208,4 @@ class AdminMenu
|
|||||||
|
|
||||||
return $next($request);
|
return $next($request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ class DateFormat
|
|||||||
public function handle($request, Closure $next)
|
public function handle($request, Closure $next)
|
||||||
{
|
{
|
||||||
if (($request->method() == 'POST') || ($request->method() == 'PATCH')) {
|
if (($request->method() == 'POST') || ($request->method() == 'PATCH')) {
|
||||||
$fields = ['paid_at', 'due_at', 'billed_at', 'invoiced_at'];
|
$fields = ['paid_at', 'due_at', 'billed_at', 'invoiced_at', 'started_at', 'ended_at'];
|
||||||
|
|
||||||
foreach ($fields as $field) {
|
foreach ($fields as $field) {
|
||||||
$date = $request->get($field);
|
$date = $request->get($field);
|
||||||
|
@ -25,7 +25,7 @@ class Permission extends FormRequest
|
|||||||
{
|
{
|
||||||
// Check if store or update
|
// Check if store or update
|
||||||
if ($this->getMethod() == 'PATCH') {
|
if ($this->getMethod() == 'PATCH') {
|
||||||
$id = $this->role->getAttribute('id');
|
$id = $this->permission->getAttribute('id');
|
||||||
} else {
|
} else {
|
||||||
$id = null;
|
$id = null;
|
||||||
}
|
}
|
||||||
|
33
app/Http/Requests/Banking/Reconciliation.php
Normal file
33
app/Http/Requests/Banking/Reconciliation.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Banking;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class Reconciliation extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'account_id' => 'required|integer',
|
||||||
|
'started_at' => 'required|date_format:Y-m-d H:i:s',
|
||||||
|
'ended_at' => 'required|date_format:Y-m-d H:i:s',
|
||||||
|
'closing_balance' => 'required',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
31
app/Http/Requests/Common/Notification.php
Normal file
31
app/Http/Requests/Common/Notification.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Common;
|
||||||
|
|
||||||
|
use App\Http\Requests\Request;
|
||||||
|
|
||||||
|
class Notification extends Request
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'path' => 'required|string',
|
||||||
|
'id' => 'required|integer',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,8 @@ class Tax extends Request
|
|||||||
return [
|
return [
|
||||||
'name' => 'required|string',
|
'name' => 'required|string',
|
||||||
'rate' => 'required|min:0|max:100',
|
'rate' => 'required|min:0|max:100',
|
||||||
|
'type' => 'required|string',
|
||||||
|
'enabled' => 'integer|boolean',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
30
app/Http/Requests/Wizard/Company.php
Normal file
30
app/Http/Requests/Wizard/Company.php
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Wizard;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class Company extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'company_logo' => 'mimes:' . setting('general.file_types') . '|between:0,' . setting('general.file_size') * 1024,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -18,9 +18,16 @@ class All
|
|||||||
public function compose(View $view)
|
public function compose(View $view)
|
||||||
{
|
{
|
||||||
// Make sure it's installed
|
// Make sure it's installed
|
||||||
if (env('APP_INSTALLED')) {
|
if (!env('APP_INSTALLED') && (env('APP_ENV') !== 'testing')) {
|
||||||
// Share date format
|
return;
|
||||||
$view->with(['date_format' => $this->getCompanyDateFormat()]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Share user logged in
|
||||||
|
$auth_user = auth()->user();
|
||||||
|
|
||||||
|
// Share date format
|
||||||
|
$date_format = $this->getCompanyDateFormat();
|
||||||
|
|
||||||
|
$view->with(['auth_user' => $auth_user, 'date_format' => $date_format]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ class Header
|
|||||||
$bills = [];
|
$bills = [];
|
||||||
$invoices = [];
|
$invoices = [];
|
||||||
$items = [];
|
$items = [];
|
||||||
|
$items_reminder = [];
|
||||||
$notifications = 0;
|
$notifications = 0;
|
||||||
$company = null;
|
$company = null;
|
||||||
|
|
||||||
@ -55,6 +56,10 @@ class Header
|
|||||||
$items[$data['item_id']] = $data['name'];
|
$items[$data['item_id']] = $data['name'];
|
||||||
$notifications++;
|
$notifications++;
|
||||||
break;
|
break;
|
||||||
|
case 'App\Notifications\Common\ItemReminder':
|
||||||
|
$items_reminder[$data['item_id']] = $data['name'];
|
||||||
|
$notifications++;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,6 +73,7 @@ class Header
|
|||||||
'bills' => $bills,
|
'bills' => $bills,
|
||||||
'invoices' => $invoices,
|
'invoices' => $invoices,
|
||||||
'items' => $items,
|
'items' => $items,
|
||||||
|
'items_reminder' => $items_reminder,
|
||||||
'company' => $company,
|
'company' => $company,
|
||||||
'updates' => $updates,
|
'updates' => $updates,
|
||||||
]);
|
]);
|
||||||
|
45
app/Http/ViewComposers/InvoiceText.php
Normal file
45
app/Http/ViewComposers/InvoiceText.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\ViewComposers;
|
||||||
|
|
||||||
|
use Illuminate\View\View;
|
||||||
|
|
||||||
|
class InvoiceText
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind data to the view.
|
||||||
|
*
|
||||||
|
* @param View $view
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function compose(View $view)
|
||||||
|
{
|
||||||
|
$text_override = [];
|
||||||
|
|
||||||
|
$text_items = setting('general.invoice_item', trans_choice('general.items', 2));
|
||||||
|
|
||||||
|
if ($text_items == 'custom') {
|
||||||
|
$text_items = setting('general.invoice_item_input');
|
||||||
|
}
|
||||||
|
|
||||||
|
$text_quantity = setting('general.invoice_quantity', trans('invoices.quantity'));
|
||||||
|
|
||||||
|
if ($text_quantity == 'custom') {
|
||||||
|
$text_quantity = setting('general.invoice_quantity_input');
|
||||||
|
}
|
||||||
|
|
||||||
|
$text_price = setting('general.invoice_price', trans('invoices.price'));
|
||||||
|
|
||||||
|
if ($text_price == 'custom') {
|
||||||
|
$text_price = setting('general.invoice_price_input');
|
||||||
|
}
|
||||||
|
|
||||||
|
$text_override['items'] = $text_items;
|
||||||
|
$text_override['quantity'] = $text_quantity;
|
||||||
|
$text_override['price'] = $text_price;
|
||||||
|
|
||||||
|
$view->with(['text_override' => $text_override]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -3,7 +3,6 @@
|
|||||||
namespace App\Http\ViewComposers;
|
namespace App\Http\ViewComposers;
|
||||||
|
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
use anlutro\LaravelSettings\Facade as Settingg;
|
|
||||||
|
|
||||||
class Menu
|
class Menu
|
||||||
{
|
{
|
||||||
|
52
app/Http/ViewComposers/Notifications.php
Normal file
52
app/Http/ViewComposers/Notifications.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\ViewComposers;
|
||||||
|
|
||||||
|
use Route;
|
||||||
|
use Illuminate\View\View;
|
||||||
|
use App\Traits\Modules as RemoteModules;
|
||||||
|
|
||||||
|
class Notifications
|
||||||
|
{
|
||||||
|
use RemoteModules;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind data to the view.
|
||||||
|
*
|
||||||
|
* @param View $view
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function compose(View $view)
|
||||||
|
{
|
||||||
|
// No need to add suggestions in console
|
||||||
|
if (app()->runningInConsole() || !env('APP_INSTALLED')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$path = Route::current()->uri();
|
||||||
|
|
||||||
|
if (empty($path)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$notifications = $this->getNotifications($path);
|
||||||
|
|
||||||
|
if (empty($notifications)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push to a stack
|
||||||
|
foreach ($notifications as $notification) {
|
||||||
|
$setting = 'notifications.'. $notification->path . '.' . $notification->id . '.status';
|
||||||
|
|
||||||
|
$path = str_replace('/', '#', $notification->path);
|
||||||
|
|
||||||
|
$message = str_replace('#path#', $path, $notification->message);
|
||||||
|
$message = str_replace('#token#', csrf_token(), $message);
|
||||||
|
|
||||||
|
if (setting($setting, 1)) {
|
||||||
|
$view->getFactory()->startPush('content_content_start', $message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
191
app/Jobs/Expense/CreateBill.php
Normal file
191
app/Jobs/Expense/CreateBill.php
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs\Expense;
|
||||||
|
|
||||||
|
use App\Events\BillCreated;
|
||||||
|
use App\Models\Expense\Bill;
|
||||||
|
use App\Models\Expense\BillHistory;
|
||||||
|
use App\Models\Expense\BillTotal;
|
||||||
|
use App\Traits\Currencies;
|
||||||
|
use App\Traits\DateTime;
|
||||||
|
use App\Traits\Uploads;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
|
||||||
|
class CreateBill
|
||||||
|
{
|
||||||
|
use Currencies, DateTime, Dispatchable, Uploads;
|
||||||
|
|
||||||
|
protected $request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @param $request
|
||||||
|
*/
|
||||||
|
public function __construct($request)
|
||||||
|
{
|
||||||
|
$this->request = $request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return Invoice
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$bill = Bill::create($this->request->input());
|
||||||
|
|
||||||
|
// Upload attachment
|
||||||
|
if ($this->request->file('attachment')) {
|
||||||
|
$media = $this->getMedia($this->request->file('attachment'), 'bills');
|
||||||
|
|
||||||
|
$bill->attachMedia($media, 'attachment');
|
||||||
|
}
|
||||||
|
|
||||||
|
$taxes = [];
|
||||||
|
|
||||||
|
$tax_total = 0;
|
||||||
|
$sub_total = 0;
|
||||||
|
$discount_total = 0;
|
||||||
|
$discount = $this->request['discount'];
|
||||||
|
|
||||||
|
if ($this->request['item']) {
|
||||||
|
foreach ($this->request['item'] as $item) {
|
||||||
|
$bill_item = dispatch(new CreateBillItem($item, $bill, $discount));
|
||||||
|
|
||||||
|
// Calculate totals
|
||||||
|
$tax_total += $bill_item->tax;
|
||||||
|
$sub_total += $bill_item->total;
|
||||||
|
|
||||||
|
// Set taxes
|
||||||
|
if ($bill_item->item_taxes) {
|
||||||
|
foreach ($bill_item->item_taxes as $item_tax) {
|
||||||
|
if (isset($taxes) && array_key_exists($item_tax['tax_id'], $taxes)) {
|
||||||
|
$taxes[$item_tax['tax_id']]['amount'] += $item_tax['amount'];
|
||||||
|
} else {
|
||||||
|
$taxes[$item_tax['tax_id']] = [
|
||||||
|
'name' => $item_tax['name'],
|
||||||
|
'amount' => $item_tax['amount']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$s_total = $sub_total;
|
||||||
|
|
||||||
|
// Apply discount to total
|
||||||
|
if ($discount) {
|
||||||
|
$s_discount = $s_total * ($discount / 100);
|
||||||
|
$discount_total += $s_discount;
|
||||||
|
$s_total = $s_total - $s_discount;
|
||||||
|
}
|
||||||
|
|
||||||
|
$amount = $s_total + $tax_total;
|
||||||
|
|
||||||
|
$this->request['amount'] = money($amount, $this->request['currency_code'])->getAmount();
|
||||||
|
|
||||||
|
$bill->update($this->request->input());
|
||||||
|
|
||||||
|
// Add bill totals
|
||||||
|
$this->addTotals($bill, $this->request, $taxes, $sub_total, $discount_total, $tax_total);
|
||||||
|
|
||||||
|
// Add bill history
|
||||||
|
BillHistory::create([
|
||||||
|
'company_id' => session('company_id'),
|
||||||
|
'bill_id' => $bill->id,
|
||||||
|
'status_code' => 'draft',
|
||||||
|
'notify' => 0,
|
||||||
|
'description' => trans('messages.success.added', ['type' => $bill->bill_number]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Recurring
|
||||||
|
$bill->createRecurring();
|
||||||
|
|
||||||
|
// Fire the event to make it extendible
|
||||||
|
event(new BillCreated($bill));
|
||||||
|
|
||||||
|
return $bill;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addTotals($bill, $request, $taxes, $sub_total, $discount_total, $tax_total)
|
||||||
|
{
|
||||||
|
// Check if totals are in request, i.e. api
|
||||||
|
if (!empty($request['totals'])) {
|
||||||
|
$sort_order = 1;
|
||||||
|
|
||||||
|
foreach ($request['totals'] as $total) {
|
||||||
|
$total['bill_id'] = $bill->id;
|
||||||
|
|
||||||
|
if (empty($total['sort_order'])) {
|
||||||
|
$total['sort_order'] = $sort_order;
|
||||||
|
}
|
||||||
|
|
||||||
|
BillTotal::create($total);
|
||||||
|
|
||||||
|
$sort_order++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sort_order = 1;
|
||||||
|
|
||||||
|
// Added bill sub total
|
||||||
|
BillTotal::create([
|
||||||
|
'company_id' => $request['company_id'],
|
||||||
|
'bill_id' => $bill->id,
|
||||||
|
'code' => 'sub_total',
|
||||||
|
'name' => 'bills.sub_total',
|
||||||
|
'amount' => $sub_total,
|
||||||
|
'sort_order' => $sort_order,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$sort_order++;
|
||||||
|
|
||||||
|
// Added bill discount
|
||||||
|
if ($discount_total) {
|
||||||
|
BillTotal::create([
|
||||||
|
'company_id' => $request['company_id'],
|
||||||
|
'bill_id' => $bill->id,
|
||||||
|
'code' => 'discount',
|
||||||
|
'name' => 'bills.discount',
|
||||||
|
'amount' => $discount_total,
|
||||||
|
'sort_order' => $sort_order,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// This is for total
|
||||||
|
$sub_total = $sub_total - $discount_total;
|
||||||
|
|
||||||
|
$sort_order++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Added bill taxes
|
||||||
|
if (isset($taxes)) {
|
||||||
|
foreach ($taxes as $tax) {
|
||||||
|
BillTotal::create([
|
||||||
|
'company_id' => $request['company_id'],
|
||||||
|
'bill_id' => $bill->id,
|
||||||
|
'code' => 'tax',
|
||||||
|
'name' => $tax['name'],
|
||||||
|
'amount' => $tax['amount'],
|
||||||
|
'sort_order' => $sort_order,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$sort_order++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Added bill total
|
||||||
|
BillTotal::create([
|
||||||
|
'company_id' => $request['company_id'],
|
||||||
|
'bill_id' => $bill->id,
|
||||||
|
'code' => 'total',
|
||||||
|
'name' => 'bills.total',
|
||||||
|
'amount' => $sub_total + $tax_total,
|
||||||
|
'sort_order' => $sort_order,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
214
app/Jobs/Expense/CreateBillItem.php
Normal file
214
app/Jobs/Expense/CreateBillItem.php
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs\Expense;
|
||||||
|
|
||||||
|
use App\Models\Common\Item;
|
||||||
|
use App\Models\Expense\BillItem;
|
||||||
|
use App\Models\Expense\BillItemTax;
|
||||||
|
use App\Models\Setting\Tax;
|
||||||
|
use App\Notifications\Common\Item as ItemNotification;
|
||||||
|
use App\Notifications\Common\ItemReminder as ItemReminderNotification;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
|
||||||
|
class CreateBillItem
|
||||||
|
{
|
||||||
|
use Dispatchable;
|
||||||
|
|
||||||
|
protected $data;
|
||||||
|
|
||||||
|
protected $bill;
|
||||||
|
|
||||||
|
protected $discount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @param $data
|
||||||
|
* @param $bill
|
||||||
|
* @param $discount
|
||||||
|
*/
|
||||||
|
public function __construct($data, $bill, $discount = null)
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
$this->bill = $bill;
|
||||||
|
$this->discount = $discount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return BillItem
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$item_sku = '';
|
||||||
|
|
||||||
|
$item_id = !empty($this->data['item_id']) ? $this->data['item_id'] : 0;
|
||||||
|
$item_amount = (double) $this->data['price'] * (double) $this->data['quantity'];
|
||||||
|
|
||||||
|
$item_discount_amount = $item_amount;
|
||||||
|
|
||||||
|
// Apply discount to tax
|
||||||
|
if ($this->discount) {
|
||||||
|
$item_discount_amount = $item_amount - ($item_amount * ($this->discount / 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($item_id)) {
|
||||||
|
$item_object = Item::find($item_id);
|
||||||
|
|
||||||
|
$this->data['name'] = $item_object->name;
|
||||||
|
$item_sku = $item_object->sku;
|
||||||
|
|
||||||
|
// Increase stock (item bought)
|
||||||
|
$item_object->quantity += (double) $this->data['quantity'];
|
||||||
|
$item_object->save();
|
||||||
|
} elseif (!empty($this->data['sku'])) {
|
||||||
|
$item_sku = $this->data['sku'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$tax_amount = 0;
|
||||||
|
$item_taxes = [];
|
||||||
|
$item_tax_total = 0;
|
||||||
|
|
||||||
|
if (!empty($this->data['tax_id'])) {
|
||||||
|
$inclusives = $compounds = $taxes = [];
|
||||||
|
|
||||||
|
foreach ((array) $this->data['tax_id'] as $tax_id) {
|
||||||
|
$tax = Tax::find($tax_id);
|
||||||
|
|
||||||
|
switch ($tax->type) {
|
||||||
|
case 'included':
|
||||||
|
$inclusives[] = $tax;
|
||||||
|
break;
|
||||||
|
case 'compound':
|
||||||
|
$compounds[] = $tax;
|
||||||
|
break;
|
||||||
|
case 'normal':
|
||||||
|
default:
|
||||||
|
$taxes[] = $tax;
|
||||||
|
|
||||||
|
$tax_amount = ($item_discount_amount / 100) * $tax->rate;
|
||||||
|
|
||||||
|
$item_taxes[] = [
|
||||||
|
'company_id' => $this->bill->company_id,
|
||||||
|
'bill_id' => $this->bill->id,
|
||||||
|
'tax_id' => $tax_id,
|
||||||
|
'name' => $tax->name,
|
||||||
|
'amount' => $tax_amount,
|
||||||
|
];
|
||||||
|
|
||||||
|
$item_tax_total += $tax_amount;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($inclusives) {
|
||||||
|
if ($this->discount) {
|
||||||
|
$item_tax_total = 0;
|
||||||
|
|
||||||
|
if ($taxes) {
|
||||||
|
foreach ($taxes as $tax) {
|
||||||
|
$item_tax_amount = ($item_amount / 100) * $tax->rate;
|
||||||
|
|
||||||
|
$item_tax_total += $item_tax_amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($inclusives as $inclusive) {
|
||||||
|
$item_sub_and_tax_total = $item_amount + $item_tax_total;
|
||||||
|
|
||||||
|
$item_tax_total = $item_sub_and_tax_total - (($item_sub_and_tax_total * (100 - $inclusive->rate)) / 100);
|
||||||
|
|
||||||
|
$item_sub_total = $item_sub_and_tax_total - $item_tax_total;
|
||||||
|
|
||||||
|
$item_taxes[] = [
|
||||||
|
'company_id' => $this->bill->company_id,
|
||||||
|
'bill_id' => $this->bill->id,
|
||||||
|
'tax_id' => $inclusive->id,
|
||||||
|
'name' => $inclusive->name,
|
||||||
|
'amount' => $tax_amount,
|
||||||
|
];
|
||||||
|
|
||||||
|
$item_discount_amount = $item_sub_total - ($item_sub_total * ($this->discount / 100));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach ($inclusives as $inclusive) {
|
||||||
|
$item_sub_and_tax_total = $item_discount_amount + $item_tax_total;
|
||||||
|
|
||||||
|
$item_tax_total = $tax_amount = $item_sub_and_tax_total - ($item_sub_and_tax_total / (1 + ($inclusive->rate / 100)));
|
||||||
|
|
||||||
|
$item_taxes[] = [
|
||||||
|
'company_id' => $this->bill->company_id,
|
||||||
|
'bill_id' => $this->bill->id,
|
||||||
|
'tax_id' => $inclusive->id,
|
||||||
|
'name' => $inclusive->name,
|
||||||
|
'amount' => $tax_amount,
|
||||||
|
];
|
||||||
|
|
||||||
|
$item_amount = $item_sub_and_tax_total - $item_tax_total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($compounds) {
|
||||||
|
foreach ($compounds as $compound) {
|
||||||
|
$tax_amount = (($item_discount_amount + $item_tax_total) / 100) * $compound->rate;
|
||||||
|
|
||||||
|
$item_tax_total += $tax_amount;
|
||||||
|
|
||||||
|
$item_taxes[] = [
|
||||||
|
'company_id' => $this->bill->company_id,
|
||||||
|
'bill_id' => $this->bill->id,
|
||||||
|
'tax_id' => $compound->id,
|
||||||
|
'name' => $compound->name,
|
||||||
|
'amount' => $tax_amount,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$bill_item = BillItem::create([
|
||||||
|
'company_id' => $this->bill->company_id,
|
||||||
|
'bill_id' => $this->bill->id,
|
||||||
|
'item_id' => $item_id,
|
||||||
|
'name' => str_limit($this->data['name'], 180, ''),
|
||||||
|
'sku' => $item_sku,
|
||||||
|
'quantity' => (double) $this->data['quantity'],
|
||||||
|
'price' => (double) $this->data['price'],
|
||||||
|
'tax' => $item_tax_total,
|
||||||
|
'tax_id' => 0,
|
||||||
|
'total' => $item_amount,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$bill_item->item_taxes = false;
|
||||||
|
$bill_item->inclusives = false;
|
||||||
|
$bill_item->compounds = false;
|
||||||
|
|
||||||
|
// set item_taxes for
|
||||||
|
if (!empty($this->data['tax_id'])) {
|
||||||
|
$bill_item->item_taxes = $item_taxes;
|
||||||
|
$bill_item->inclusives = $inclusives;
|
||||||
|
$bill_item->compounds = $compounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($item_taxes) {
|
||||||
|
foreach ($item_taxes as $item_tax) {
|
||||||
|
$item_tax['bill_item_id'] = $bill_item->id;
|
||||||
|
|
||||||
|
BillItemTax::create($item_tax);
|
||||||
|
|
||||||
|
// Set taxes
|
||||||
|
if (isset($taxes) && array_key_exists($item_tax['tax_id'], $taxes)) {
|
||||||
|
$taxes[$item_tax['tax_id']]['amount'] += $item_tax['amount'];
|
||||||
|
} else {
|
||||||
|
$taxes[$item_tax['tax_id']] = [
|
||||||
|
'name' => $item_tax['name'],
|
||||||
|
'amount' => $item_tax['amount']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $bill_item;
|
||||||
|
}
|
||||||
|
}
|
52
app/Jobs/Expense/CreateBillPayment.php
Normal file
52
app/Jobs/Expense/CreateBillPayment.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs\Expense;
|
||||||
|
|
||||||
|
use App\Models\Expense\BillHistory;
|
||||||
|
use App\Models\Expense\BillPayment;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
|
||||||
|
class CreateBillPayment
|
||||||
|
{
|
||||||
|
use Dispatchable;
|
||||||
|
|
||||||
|
protected $request;
|
||||||
|
|
||||||
|
protected $bill;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @param $request
|
||||||
|
* @param $bill
|
||||||
|
*/
|
||||||
|
public function __construct($request, $bill)
|
||||||
|
{
|
||||||
|
$this->request = $request;
|
||||||
|
$this->bill = $bill;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return BillPayment
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$bill_payment = BillPayment::create($this->request->input());
|
||||||
|
|
||||||
|
$desc_amount = money((float) $bill_payment->amount, (string) $bill_payment->currency_code, true)->format();
|
||||||
|
|
||||||
|
$history_data = [
|
||||||
|
'company_id' => $bill_payment->company_id,
|
||||||
|
'bill_id' => $bill_payment->bill_id,
|
||||||
|
'status_code' => $this->bill->bill_status_code,
|
||||||
|
'notify' => '0',
|
||||||
|
'description' => $desc_amount . ' ' . trans_choice('general.payments', 1),
|
||||||
|
];
|
||||||
|
|
||||||
|
BillHistory::create($history_data);
|
||||||
|
|
||||||
|
return $bill_payment;
|
||||||
|
}
|
||||||
|
}
|
232
app/Jobs/Expense/UpdateBill.php
Normal file
232
app/Jobs/Expense/UpdateBill.php
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs\Expense;
|
||||||
|
|
||||||
|
use App\Events\BillUpdated;
|
||||||
|
use App\Models\Common\Item;
|
||||||
|
use App\Models\Expense\Bill;
|
||||||
|
use App\Models\Expense\BillTotal;
|
||||||
|
use App\Traits\Currencies;
|
||||||
|
use App\Traits\DateTime;
|
||||||
|
use App\Traits\Uploads;
|
||||||
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
|
||||||
|
class UpdateBill
|
||||||
|
{
|
||||||
|
use Currencies, DateTime, Dispatchable, Uploads;
|
||||||
|
|
||||||
|
protected $bill;
|
||||||
|
|
||||||
|
protected $request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @param $request
|
||||||
|
*/
|
||||||
|
public function __construct($bill, $request)
|
||||||
|
{
|
||||||
|
$this->bill = $bill;
|
||||||
|
$this->request = $request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return Bill
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
// Upload attachment
|
||||||
|
if ($this->request->file('attachment')) {
|
||||||
|
$media = $this->getMedia($this->request->file('attachment'), 'bills');
|
||||||
|
|
||||||
|
$this->bill->attachMedia($media, 'attachment');
|
||||||
|
}
|
||||||
|
|
||||||
|
$taxes = [];
|
||||||
|
|
||||||
|
$tax_total = 0;
|
||||||
|
$sub_total = 0;
|
||||||
|
$discount_total = 0;
|
||||||
|
$discount = $this->request['discount'];
|
||||||
|
|
||||||
|
if ($this->request['item']) {
|
||||||
|
$items = $this->bill->items;
|
||||||
|
|
||||||
|
if ($items) {
|
||||||
|
foreach ($items as $item) {
|
||||||
|
if (empty($item->item_id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$item_object = Item::find($item->item_id);
|
||||||
|
|
||||||
|
// Decrease stock
|
||||||
|
$item_object->quantity -= (double) $item->quantity;
|
||||||
|
$item_object->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->deleteRelationships($this->bill, 'items');
|
||||||
|
|
||||||
|
foreach ($this->request['item'] as $item) {
|
||||||
|
$bill_item = dispatch(new CreateBillItem($item, $this->bill, $discount));
|
||||||
|
|
||||||
|
// Calculate totals
|
||||||
|
$tax_total += $bill_item->tax;
|
||||||
|
$sub_total += $bill_item->total;
|
||||||
|
|
||||||
|
// Set taxes
|
||||||
|
if ($bill_item->item_taxes) {
|
||||||
|
foreach ($bill_item->item_taxes as $item_tax) {
|
||||||
|
if (isset($taxes) && array_key_exists($item_tax['tax_id'], $taxes)) {
|
||||||
|
$taxes[$item_tax['tax_id']]['amount'] += $item_tax['amount'];
|
||||||
|
} else {
|
||||||
|
$taxes[$item_tax['tax_id']] = [
|
||||||
|
'name' => $item_tax['name'],
|
||||||
|
'amount' => $item_tax['amount']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$s_total = $sub_total;
|
||||||
|
|
||||||
|
// Apply discount to total
|
||||||
|
if ($discount) {
|
||||||
|
$s_discount = $s_total * ($discount / 100);
|
||||||
|
$discount_total += $s_discount;
|
||||||
|
$s_total = $s_total - $s_discount;
|
||||||
|
}
|
||||||
|
|
||||||
|
$amount = $s_total + $tax_total;
|
||||||
|
|
||||||
|
$this->request['amount'] = money($amount, $this->request['currency_code'])->getAmount();
|
||||||
|
|
||||||
|
$this->bill->update($this->request->input());
|
||||||
|
|
||||||
|
// Delete previous bill totals
|
||||||
|
$this->deleteRelationships($this->bill, 'totals');
|
||||||
|
|
||||||
|
// Add bill totals
|
||||||
|
$this->addTotals($this->bill, $this->request, $taxes, $sub_total, $discount_total, $tax_total);
|
||||||
|
|
||||||
|
// Recurring
|
||||||
|
$this->bill->updateRecurring();
|
||||||
|
|
||||||
|
// Fire the event to make it extensible
|
||||||
|
event(new BillUpdated($this->bill));
|
||||||
|
|
||||||
|
return $this->bill;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addTotals($bill, $request, $taxes, $sub_total, $discount_total, $tax_total)
|
||||||
|
{
|
||||||
|
// Check if totals are in request, i.e. api
|
||||||
|
if (!empty($request['totals'])) {
|
||||||
|
$sort_order = 1;
|
||||||
|
|
||||||
|
foreach ($request['totals'] as $total) {
|
||||||
|
$total['bill_id'] = $bill->id;
|
||||||
|
|
||||||
|
if (empty($total['sort_order'])) {
|
||||||
|
$total['sort_order'] = $sort_order;
|
||||||
|
}
|
||||||
|
|
||||||
|
BillTotal::create($total);
|
||||||
|
|
||||||
|
$sort_order++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sort_order = 1;
|
||||||
|
|
||||||
|
// Added bill sub total
|
||||||
|
BillTotal::create([
|
||||||
|
'company_id' => $request['company_id'],
|
||||||
|
'bill_id' => $bill->id,
|
||||||
|
'code' => 'sub_total',
|
||||||
|
'name' => 'bills.sub_total',
|
||||||
|
'amount' => $sub_total,
|
||||||
|
'sort_order' => $sort_order,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$sort_order++;
|
||||||
|
|
||||||
|
// Added bill discount
|
||||||
|
if ($discount_total) {
|
||||||
|
BillTotal::create([
|
||||||
|
'company_id' => $request['company_id'],
|
||||||
|
'bill_id' => $bill->id,
|
||||||
|
'code' => 'discount',
|
||||||
|
'name' => 'bills.discount',
|
||||||
|
'amount' => $discount_total,
|
||||||
|
'sort_order' => $sort_order,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// This is for total
|
||||||
|
$sub_total = $sub_total - $discount_total;
|
||||||
|
|
||||||
|
$sort_order++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Added bill taxes
|
||||||
|
if (isset($taxes)) {
|
||||||
|
foreach ($taxes as $tax) {
|
||||||
|
BillTotal::create([
|
||||||
|
'company_id' => $request['company_id'],
|
||||||
|
'bill_id' => $bill->id,
|
||||||
|
'code' => 'tax',
|
||||||
|
'name' => $tax['name'],
|
||||||
|
'amount' => $tax['amount'],
|
||||||
|
'sort_order' => $sort_order,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$sort_order++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Added bill total
|
||||||
|
BillTotal::create([
|
||||||
|
'company_id' => $request['company_id'],
|
||||||
|
'bill_id' => $bill->id,
|
||||||
|
'code' => 'total',
|
||||||
|
'name' => 'bills.total',
|
||||||
|
'amount' => $sub_total + $tax_total,
|
||||||
|
'sort_order' => $sort_order,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mass delete relationships with events being fired.
|
||||||
|
*
|
||||||
|
* @param $model
|
||||||
|
* @param $relationships
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function deleteRelationships($model, $relationships)
|
||||||
|
{
|
||||||
|
foreach ((array) $relationships as $relationship) {
|
||||||
|
if (empty($model->$relationship)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$items = $model->$relationship->all();
|
||||||
|
|
||||||
|
if ($items instanceof Collection) {
|
||||||
|
$items = $items->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ((array) $items as $item) {
|
||||||
|
$item->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
195
app/Jobs/Income/CreateInvoice.php
Normal file
195
app/Jobs/Income/CreateInvoice.php
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs\Income;
|
||||||
|
|
||||||
|
use App\Events\InvoiceCreated;
|
||||||
|
use App\Models\Income\Invoice;
|
||||||
|
use App\Models\Income\InvoiceHistory;
|
||||||
|
use App\Models\Income\InvoiceTotal;
|
||||||
|
use App\Traits\Currencies;
|
||||||
|
use App\Traits\DateTime;
|
||||||
|
use App\Traits\Incomes;
|
||||||
|
use App\Traits\Uploads;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
|
||||||
|
class CreateInvoice
|
||||||
|
{
|
||||||
|
use Currencies, DateTime, Dispatchable, Incomes, Uploads;
|
||||||
|
|
||||||
|
protected $request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @param $request
|
||||||
|
*/
|
||||||
|
public function __construct($request)
|
||||||
|
{
|
||||||
|
$this->request = $request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return Invoice
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$invoice = Invoice::create($this->request->input());
|
||||||
|
|
||||||
|
// Upload attachment
|
||||||
|
if ($this->request->file('attachment')) {
|
||||||
|
$media = $this->getMedia($this->request->file('attachment'), 'invoices');
|
||||||
|
|
||||||
|
$invoice->attachMedia($media, 'attachment');
|
||||||
|
}
|
||||||
|
|
||||||
|
$taxes = [];
|
||||||
|
|
||||||
|
$tax_total = 0;
|
||||||
|
$sub_total = 0;
|
||||||
|
$discount_total = 0;
|
||||||
|
$discount = $this->request['discount'];
|
||||||
|
|
||||||
|
if ($this->request['item']) {
|
||||||
|
foreach ($this->request['item'] as $item) {
|
||||||
|
$invoice_item = dispatch(new CreateInvoiceItem($item, $invoice, $discount));
|
||||||
|
|
||||||
|
// Calculate totals
|
||||||
|
$tax_total += $invoice_item->tax;
|
||||||
|
$sub_total += $invoice_item->total;
|
||||||
|
|
||||||
|
// Set taxes
|
||||||
|
if ($invoice_item->item_taxes) {
|
||||||
|
foreach ($invoice_item->item_taxes as $item_tax) {
|
||||||
|
if (isset($taxes) && array_key_exists($item_tax['tax_id'], $taxes)) {
|
||||||
|
$taxes[$item_tax['tax_id']]['amount'] += $item_tax['amount'];
|
||||||
|
} else {
|
||||||
|
$taxes[$item_tax['tax_id']] = [
|
||||||
|
'name' => $item_tax['name'],
|
||||||
|
'amount' => $item_tax['amount']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$s_total = $sub_total;
|
||||||
|
|
||||||
|
// Apply discount to total
|
||||||
|
if ($discount) {
|
||||||
|
$s_discount = $s_total * ($discount / 100);
|
||||||
|
$discount_total += $s_discount;
|
||||||
|
$s_total = $s_total - $s_discount;
|
||||||
|
}
|
||||||
|
|
||||||
|
$amount = $s_total + $tax_total;
|
||||||
|
|
||||||
|
$this->request['amount'] = money($amount, $this->request['currency_code'])->getAmount();
|
||||||
|
|
||||||
|
$invoice->update($this->request->input());
|
||||||
|
|
||||||
|
// Add invoice totals
|
||||||
|
$this->addTotals($invoice, $this->request, $taxes, $sub_total, $discount_total, $tax_total);
|
||||||
|
|
||||||
|
// Add invoice history
|
||||||
|
InvoiceHistory::create([
|
||||||
|
'company_id' => session('company_id'),
|
||||||
|
'invoice_id' => $invoice->id,
|
||||||
|
'status_code' => 'draft',
|
||||||
|
'notify' => 0,
|
||||||
|
'description' => trans('messages.success.added', ['type' => $invoice->invoice_number]),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Update next invoice number
|
||||||
|
$this->increaseNextInvoiceNumber();
|
||||||
|
|
||||||
|
// Recurring
|
||||||
|
$invoice->createRecurring();
|
||||||
|
|
||||||
|
// Fire the event to make it extensible
|
||||||
|
event(new InvoiceCreated($invoice));
|
||||||
|
|
||||||
|
return $invoice;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addTotals($invoice, $request, $taxes, $sub_total, $discount_total, $tax_total)
|
||||||
|
{
|
||||||
|
// Check if totals are in request, i.e. api
|
||||||
|
if (!empty($request['totals'])) {
|
||||||
|
$sort_order = 1;
|
||||||
|
|
||||||
|
foreach ($request['totals'] as $total) {
|
||||||
|
$total['invoice_id'] = $invoice->id;
|
||||||
|
|
||||||
|
if (empty($total['sort_order'])) {
|
||||||
|
$total['sort_order'] = $sort_order;
|
||||||
|
}
|
||||||
|
|
||||||
|
InvoiceTotal::create($total);
|
||||||
|
|
||||||
|
$sort_order++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sort_order = 1;
|
||||||
|
|
||||||
|
// Added invoice sub total
|
||||||
|
InvoiceTotal::create([
|
||||||
|
'company_id' => $request['company_id'],
|
||||||
|
'invoice_id' => $invoice->id,
|
||||||
|
'code' => 'sub_total',
|
||||||
|
'name' => 'invoices.sub_total',
|
||||||
|
'amount' => $sub_total,
|
||||||
|
'sort_order' => $sort_order,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$sort_order++;
|
||||||
|
|
||||||
|
// Added invoice discount
|
||||||
|
if ($discount_total) {
|
||||||
|
InvoiceTotal::create([
|
||||||
|
'company_id' => $request['company_id'],
|
||||||
|
'invoice_id' => $invoice->id,
|
||||||
|
'code' => 'discount',
|
||||||
|
'name' => 'invoices.discount',
|
||||||
|
'amount' => $discount_total,
|
||||||
|
'sort_order' => $sort_order,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// This is for total
|
||||||
|
$sub_total = $sub_total - $discount_total;
|
||||||
|
|
||||||
|
$sort_order++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Added invoice taxes
|
||||||
|
if (isset($taxes)) {
|
||||||
|
foreach ($taxes as $tax) {
|
||||||
|
InvoiceTotal::create([
|
||||||
|
'company_id' => $request['company_id'],
|
||||||
|
'invoice_id' => $invoice->id,
|
||||||
|
'code' => 'tax',
|
||||||
|
'name' => $tax['name'],
|
||||||
|
'amount' => $tax['amount'],
|
||||||
|
'sort_order' => $sort_order,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$sort_order++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Added invoice total
|
||||||
|
InvoiceTotal::create([
|
||||||
|
'company_id' => $request['company_id'],
|
||||||
|
'invoice_id' => $invoice->id,
|
||||||
|
'code' => 'total',
|
||||||
|
'name' => 'invoices.total',
|
||||||
|
'amount' => $sub_total + $tax_total,
|
||||||
|
'sort_order' => $sort_order,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
241
app/Jobs/Income/CreateInvoiceItem.php
Normal file
241
app/Jobs/Income/CreateInvoiceItem.php
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs\Income;
|
||||||
|
|
||||||
|
use App\Models\Common\Item;
|
||||||
|
use App\Models\Income\InvoiceItem;
|
||||||
|
use App\Models\Income\InvoiceItemTax;
|
||||||
|
use App\Models\Setting\Tax;
|
||||||
|
use App\Notifications\Common\Item as ItemNotification;
|
||||||
|
use App\Notifications\Common\ItemReminder as ItemReminderNotification;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
|
||||||
|
class CreateInvoiceItem
|
||||||
|
{
|
||||||
|
use Dispatchable;
|
||||||
|
|
||||||
|
protected $data;
|
||||||
|
|
||||||
|
protected $invoice;
|
||||||
|
|
||||||
|
protected $discount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @param $data
|
||||||
|
* @param $invoice
|
||||||
|
* @param $discount
|
||||||
|
*/
|
||||||
|
public function __construct($data, $invoice, $discount = null)
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
$this->invoice = $invoice;
|
||||||
|
$this->discount = $discount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return InvoiceItem
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$item_sku = '';
|
||||||
|
|
||||||
|
$item_id = !empty($this->data['item_id']) ? $this->data['item_id'] : 0;
|
||||||
|
$item_amount = (double) $this->data['price'] * (double) $this->data['quantity'];
|
||||||
|
|
||||||
|
$item_discount_amount = $item_amount;
|
||||||
|
|
||||||
|
// Apply discount to tax
|
||||||
|
if ($this->discount) {
|
||||||
|
$item_discount_amount = $item_amount - ($item_amount * ($this->discount / 100));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($item_id)) {
|
||||||
|
$item_object = Item::find($item_id);
|
||||||
|
|
||||||
|
$this->data['name'] = $item_object->name;
|
||||||
|
$item_sku = $item_object->sku;
|
||||||
|
|
||||||
|
// Decrease stock (item sold)
|
||||||
|
$item_object->quantity -= (double) $this->data['quantity'];
|
||||||
|
$item_object->save();
|
||||||
|
|
||||||
|
if (setting('general.send_item_reminder')) {
|
||||||
|
$item_stocks = explode(',', setting('general.schedule_item_stocks'));
|
||||||
|
|
||||||
|
foreach ($item_stocks as $item_stock) {
|
||||||
|
if ($item_object->quantity == $item_stock) {
|
||||||
|
foreach ($item_object->company->users as $user) {
|
||||||
|
if (!$user->can('read-notifications')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->notify(new ItemReminderNotification($item_object));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify users if out of stock
|
||||||
|
if ($item_object->quantity == 0) {
|
||||||
|
foreach ($item_object->company->users as $user) {
|
||||||
|
if (!$user->can('read-notifications')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$user->notify(new ItemNotification($item_object));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif (!empty($this->data['sku'])) {
|
||||||
|
$item_sku = $this->data['sku'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$tax_amount = 0;
|
||||||
|
$item_taxes = [];
|
||||||
|
$item_tax_total = 0;
|
||||||
|
|
||||||
|
if (!empty($this->data['tax_id'])) {
|
||||||
|
$inclusives = $compounds = $taxes = [];
|
||||||
|
|
||||||
|
foreach ((array) $this->data['tax_id'] as $tax_id) {
|
||||||
|
$tax = Tax::find($tax_id);
|
||||||
|
|
||||||
|
switch ($tax->type) {
|
||||||
|
case 'inclusive':
|
||||||
|
$inclusives[] = $tax;
|
||||||
|
break;
|
||||||
|
case 'compound':
|
||||||
|
$compounds[] = $tax;
|
||||||
|
break;
|
||||||
|
case 'normal':
|
||||||
|
default:
|
||||||
|
$taxes[] = $tax;
|
||||||
|
|
||||||
|
$tax_amount = ($item_discount_amount / 100) * $tax->rate;
|
||||||
|
|
||||||
|
$item_taxes[] = [
|
||||||
|
'company_id' => $this->invoice->company_id,
|
||||||
|
'invoice_id' => $this->invoice->id,
|
||||||
|
'tax_id' => $tax_id,
|
||||||
|
'name' => $tax->name,
|
||||||
|
'amount' => $tax_amount,
|
||||||
|
];
|
||||||
|
|
||||||
|
$item_tax_total += $tax_amount;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($inclusives) {
|
||||||
|
if ($this->discount) {
|
||||||
|
$item_tax_total = 0;
|
||||||
|
|
||||||
|
if ($taxes) {
|
||||||
|
foreach ($taxes as $tax) {
|
||||||
|
$item_tax_amount = ($item_amount / 100) * $tax->rate;
|
||||||
|
|
||||||
|
$item_tax_total += $item_tax_amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($inclusives as $inclusive) {
|
||||||
|
$item_sub_and_tax_total = $item_amount + $item_tax_total;
|
||||||
|
|
||||||
|
$item_tax_total = $item_sub_and_tax_total - (($item_sub_and_tax_total * (100 - $inclusive->rate)) / 100);
|
||||||
|
|
||||||
|
$item_sub_total = $item_sub_and_tax_total - $item_tax_total;
|
||||||
|
|
||||||
|
$item_taxes[] = [
|
||||||
|
'company_id' => $this->invoice->company_id,
|
||||||
|
'invoice_id' => $this->invoice->id,
|
||||||
|
'tax_id' => $inclusive->id,
|
||||||
|
'name' => $inclusive->name,
|
||||||
|
'amount' => $tax_amount,
|
||||||
|
];
|
||||||
|
|
||||||
|
$item_discount_amount = $item_sub_total - ($item_sub_total * ($this->discount / 100));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach ($inclusives as $inclusive) {
|
||||||
|
$item_sub_and_tax_total = $item_discount_amount + $item_tax_total;
|
||||||
|
|
||||||
|
$item_tax_total = $tax_amount = $item_sub_and_tax_total - ($item_sub_and_tax_total / (1 + ($inclusive->rate / 100)));
|
||||||
|
|
||||||
|
$item_taxes[] = [
|
||||||
|
'company_id' => $this->invoice->company_id,
|
||||||
|
'invoice_id' => $this->invoice->id,
|
||||||
|
'tax_id' => $inclusive->id,
|
||||||
|
'name' => $inclusive->name,
|
||||||
|
'amount' => $tax_amount,
|
||||||
|
];
|
||||||
|
|
||||||
|
$item_amount = $item_sub_and_tax_total - $item_tax_total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($compounds) {
|
||||||
|
foreach ($compounds as $compound) {
|
||||||
|
$tax_amount = (($item_discount_amount + $item_tax_total) / 100) * $compound->rate;
|
||||||
|
|
||||||
|
$item_tax_total += $tax_amount;
|
||||||
|
|
||||||
|
$item_taxes[] = [
|
||||||
|
'company_id' => $this->invoice->company_id,
|
||||||
|
'invoice_id' => $this->invoice->id,
|
||||||
|
'tax_id' => $compound->id,
|
||||||
|
'name' => $compound->name,
|
||||||
|
'amount' => $tax_amount,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$invoice_item = InvoiceItem::create([
|
||||||
|
'company_id' => $this->invoice->company_id,
|
||||||
|
'invoice_id' => $this->invoice->id,
|
||||||
|
'item_id' => $item_id,
|
||||||
|
'name' => str_limit($this->data['name'], 180, ''),
|
||||||
|
'sku' => $item_sku,
|
||||||
|
'quantity' => (double) $this->data['quantity'],
|
||||||
|
'price' => (double) $this->data['price'],
|
||||||
|
'tax' => $item_tax_total,
|
||||||
|
'tax_id' => 0,
|
||||||
|
'total' => $item_amount,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$invoice_item->item_taxes = false;
|
||||||
|
$invoice_item->inclusives = false;
|
||||||
|
$invoice_item->compounds = false;
|
||||||
|
|
||||||
|
// set item_taxes for
|
||||||
|
if (!empty($this->data['tax_id'])) {
|
||||||
|
$invoice_item->item_taxes = $item_taxes;
|
||||||
|
$invoice_item->inclusives = $inclusives;
|
||||||
|
$invoice_item->compounds = $compounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($item_taxes) {
|
||||||
|
foreach ($item_taxes as $item_tax) {
|
||||||
|
$item_tax['invoice_item_id'] = $invoice_item->id;
|
||||||
|
|
||||||
|
InvoiceItemTax::create($item_tax);
|
||||||
|
|
||||||
|
// Set taxes
|
||||||
|
if (isset($taxes) && array_key_exists($item_tax['tax_id'], $taxes)) {
|
||||||
|
$taxes[$item_tax['tax_id']]['amount'] += $item_tax['amount'];
|
||||||
|
} else {
|
||||||
|
$taxes[$item_tax['tax_id']] = [
|
||||||
|
'name' => $item_tax['name'],
|
||||||
|
'amount' => $item_tax['amount']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $invoice_item;
|
||||||
|
}
|
||||||
|
}
|
52
app/Jobs/Income/CreateInvoicePayment.php
Normal file
52
app/Jobs/Income/CreateInvoicePayment.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs\Income;
|
||||||
|
|
||||||
|
use App\Models\Income\InvoiceHistory;
|
||||||
|
use App\Models\Income\InvoicePayment;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
|
||||||
|
class CreateInvoicePayment
|
||||||
|
{
|
||||||
|
use Dispatchable;
|
||||||
|
|
||||||
|
protected $request;
|
||||||
|
|
||||||
|
protected $invoice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @param $request
|
||||||
|
* @param $invoice
|
||||||
|
*/
|
||||||
|
public function __construct($request, $invoice)
|
||||||
|
{
|
||||||
|
$this->request = $request;
|
||||||
|
$this->invoice = $invoice;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return InvoicePayment
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$invoice_payment = InvoicePayment::create($this->request->input());
|
||||||
|
|
||||||
|
$desc_amount = money((float) $invoice_payment->amount, (string) $invoice_payment->currency_code, true)->format();
|
||||||
|
|
||||||
|
$history_data = [
|
||||||
|
'company_id' => $invoice_payment->company_id,
|
||||||
|
'invoice_id' => $invoice_payment->invoice_id,
|
||||||
|
'status_code' => $this->invoice->invoice_status_code,
|
||||||
|
'notify' => '0',
|
||||||
|
'description' => $desc_amount . ' ' . trans_choice('general.payments', 1),
|
||||||
|
];
|
||||||
|
|
||||||
|
InvoiceHistory::create($history_data);
|
||||||
|
|
||||||
|
return $invoice_payment;
|
||||||
|
}
|
||||||
|
}
|
233
app/Jobs/Income/UpdateInvoice.php
Normal file
233
app/Jobs/Income/UpdateInvoice.php
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs\Income;
|
||||||
|
|
||||||
|
use App\Events\InvoiceUpdated;
|
||||||
|
use App\Models\Common\Item;
|
||||||
|
use App\Models\Income\Invoice;
|
||||||
|
use App\Models\Income\InvoiceTotal;
|
||||||
|
use App\Traits\Currencies;
|
||||||
|
use App\Traits\DateTime;
|
||||||
|
use App\Traits\Incomes;
|
||||||
|
use App\Traits\Uploads;
|
||||||
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
|
||||||
|
class UpdateInvoice
|
||||||
|
{
|
||||||
|
use Currencies, DateTime, Dispatchable, Incomes, Uploads;
|
||||||
|
|
||||||
|
protected $invoice;
|
||||||
|
|
||||||
|
protected $request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new job instance.
|
||||||
|
*
|
||||||
|
* @param $request
|
||||||
|
*/
|
||||||
|
public function __construct($invoice, $request)
|
||||||
|
{
|
||||||
|
$this->invoice = $invoice;
|
||||||
|
$this->request = $request;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the job.
|
||||||
|
*
|
||||||
|
* @return Invoice
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
// Upload attachment
|
||||||
|
if ($this->request->file('attachment')) {
|
||||||
|
$media = $this->getMedia($this->request->file('attachment'), 'invoices');
|
||||||
|
|
||||||
|
$this->invoice->attachMedia($media, 'attachment');
|
||||||
|
}
|
||||||
|
|
||||||
|
$taxes = [];
|
||||||
|
|
||||||
|
$tax_total = 0;
|
||||||
|
$sub_total = 0;
|
||||||
|
$discount_total = 0;
|
||||||
|
$discount = $this->request['discount'];
|
||||||
|
|
||||||
|
if ($this->request['item']) {
|
||||||
|
$items = $this->invoice->items;
|
||||||
|
|
||||||
|
if ($items) {
|
||||||
|
foreach ($items as $item) {
|
||||||
|
if (empty($item->item_id)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$item_object = Item::find($item->item_id);
|
||||||
|
|
||||||
|
// Increase stock
|
||||||
|
$item_object->quantity += (double) $item->quantity;
|
||||||
|
$item_object->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->deleteRelationships($this->invoice, 'items');
|
||||||
|
|
||||||
|
foreach ($this->request['item'] as $item) {
|
||||||
|
$invoice_item = dispatch(new CreateInvoiceItem($item, $this->invoice, $discount));
|
||||||
|
|
||||||
|
// Calculate totals
|
||||||
|
$tax_total += $invoice_item->tax;
|
||||||
|
$sub_total += $invoice_item->total;
|
||||||
|
|
||||||
|
// Set taxes
|
||||||
|
if ($invoice_item->item_taxes) {
|
||||||
|
foreach ($invoice_item->item_taxes as $item_tax) {
|
||||||
|
if (isset($taxes) && array_key_exists($item_tax['tax_id'], $taxes)) {
|
||||||
|
$taxes[$item_tax['tax_id']]['amount'] += $item_tax['amount'];
|
||||||
|
} else {
|
||||||
|
$taxes[$item_tax['tax_id']] = [
|
||||||
|
'name' => $item_tax['name'],
|
||||||
|
'amount' => $item_tax['amount']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$s_total = $sub_total;
|
||||||
|
|
||||||
|
// Apply discount to total
|
||||||
|
if ($discount) {
|
||||||
|
$s_discount = $s_total * ($discount / 100);
|
||||||
|
$discount_total += $s_discount;
|
||||||
|
$s_total = $s_total - $s_discount;
|
||||||
|
}
|
||||||
|
|
||||||
|
$amount = $s_total + $tax_total;
|
||||||
|
|
||||||
|
$this->request['amount'] = money($amount, $this->request['currency_code'])->getAmount();
|
||||||
|
|
||||||
|
$this->invoice->update($this->request->input());
|
||||||
|
|
||||||
|
// Delete previous invoice totals
|
||||||
|
$this->deleteRelationships($this->invoice, 'totals');
|
||||||
|
|
||||||
|
// Add invoice totals
|
||||||
|
$this->addTotals($this->invoice, $this->request, $taxes, $sub_total, $discount_total, $tax_total);
|
||||||
|
|
||||||
|
// Recurring
|
||||||
|
$this->invoice->updateRecurring();
|
||||||
|
|
||||||
|
// Fire the event to make it extensible
|
||||||
|
event(new InvoiceUpdated($this->invoice));
|
||||||
|
|
||||||
|
return $this->invoice;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addTotals($invoice, $request, $taxes, $sub_total, $discount_total, $tax_total)
|
||||||
|
{
|
||||||
|
// Check if totals are in request, i.e. api
|
||||||
|
if (!empty($request['totals'])) {
|
||||||
|
$sort_order = 1;
|
||||||
|
|
||||||
|
foreach ($request['totals'] as $total) {
|
||||||
|
$total['invoice_id'] = $invoice->id;
|
||||||
|
|
||||||
|
if (empty($total['sort_order'])) {
|
||||||
|
$total['sort_order'] = $sort_order;
|
||||||
|
}
|
||||||
|
|
||||||
|
InvoiceTotal::create($total);
|
||||||
|
|
||||||
|
$sort_order++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sort_order = 1;
|
||||||
|
|
||||||
|
// Added invoice sub total
|
||||||
|
InvoiceTotal::create([
|
||||||
|
'company_id' => $request['company_id'],
|
||||||
|
'invoice_id' => $invoice->id,
|
||||||
|
'code' => 'sub_total',
|
||||||
|
'name' => 'invoices.sub_total',
|
||||||
|
'amount' => $sub_total,
|
||||||
|
'sort_order' => $sort_order,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$sort_order++;
|
||||||
|
|
||||||
|
// Added invoice discount
|
||||||
|
if ($discount_total) {
|
||||||
|
InvoiceTotal::create([
|
||||||
|
'company_id' => $request['company_id'],
|
||||||
|
'invoice_id' => $invoice->id,
|
||||||
|
'code' => 'discount',
|
||||||
|
'name' => 'invoices.discount',
|
||||||
|
'amount' => $discount_total,
|
||||||
|
'sort_order' => $sort_order,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// This is for total
|
||||||
|
$sub_total = $sub_total - $discount_total;
|
||||||
|
|
||||||
|
$sort_order++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Added invoice taxes
|
||||||
|
if (isset($taxes)) {
|
||||||
|
foreach ($taxes as $tax) {
|
||||||
|
InvoiceTotal::create([
|
||||||
|
'company_id' => $request['company_id'],
|
||||||
|
'invoice_id' => $invoice->id,
|
||||||
|
'code' => 'tax',
|
||||||
|
'name' => $tax['name'],
|
||||||
|
'amount' => $tax['amount'],
|
||||||
|
'sort_order' => $sort_order,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$sort_order++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Added invoice total
|
||||||
|
InvoiceTotal::create([
|
||||||
|
'company_id' => $request['company_id'],
|
||||||
|
'invoice_id' => $invoice->id,
|
||||||
|
'code' => 'total',
|
||||||
|
'name' => 'invoices.total',
|
||||||
|
'amount' => $sub_total + $tax_total,
|
||||||
|
'sort_order' => $sort_order,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mass delete relationships with events being fired.
|
||||||
|
*
|
||||||
|
* @param $model
|
||||||
|
* @param $relationships
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function deleteRelationships($model, $relationships)
|
||||||
|
{
|
||||||
|
foreach ((array) $relationships as $relationship) {
|
||||||
|
if (empty($model->$relationship)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$items = $model->$relationship->all();
|
||||||
|
|
||||||
|
if ($items instanceof Collection) {
|
||||||
|
$items = $items->all();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ((array) $items as $item) {
|
||||||
|
$item->delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,11 +3,9 @@
|
|||||||
namespace App\Listeners\Incomes\Invoice;
|
namespace App\Listeners\Incomes\Invoice;
|
||||||
|
|
||||||
use App\Events\InvoicePaid;
|
use App\Events\InvoicePaid;
|
||||||
|
use App\Http\Requests\Income\InvoicePayment as PaymentRequest;
|
||||||
use App\Models\Income\Invoice;
|
use App\Jobs\Income\CreateInvoicePayment;
|
||||||
use App\Models\Income\InvoicePayment;
|
use App\Notifications\Customer\Invoice as Notification;
|
||||||
use App\Models\Income\InvoiceHistory;
|
|
||||||
|
|
||||||
use App\Traits\DateTime;
|
use App\Traits\DateTime;
|
||||||
use Date;
|
use Date;
|
||||||
|
|
||||||
@ -19,24 +17,14 @@ class Paid
|
|||||||
* Handle the event.
|
* Handle the event.
|
||||||
*
|
*
|
||||||
* @param $event
|
* @param $event
|
||||||
* @return void
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function handle(InvoicePaid $event)
|
public function handle(InvoicePaid $event)
|
||||||
{
|
{
|
||||||
$invoice = $event->invoice;
|
$invoice = $event->invoice;
|
||||||
$request = $event->request;
|
$request = $event->request;
|
||||||
|
|
||||||
$request['invoice_id'] = $invoice->id;
|
$invoice_payment = $this->createPayment($invoice, $request);
|
||||||
$request['account_id'] = setting('general.default_account');
|
|
||||||
|
|
||||||
if (!isset($request['amount'])) {
|
|
||||||
$request['amount'] = $invoice->amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
$request['currency_code'] = $invoice->currency_code;
|
|
||||||
$request['currency_rate'] = $invoice->currency_rate;
|
|
||||||
|
|
||||||
$request['paid_at'] = Date::parse('now')->format('Y-m-d');
|
|
||||||
|
|
||||||
if ($request['amount'] > $invoice->amount) {
|
if ($request['amount'] > $invoice->amount) {
|
||||||
$message = trans('messages.error.added', ['type' => trans_choice('general.payment', 1)]);
|
$message = trans('messages.error.added', ['type' => trans_choice('general.payment', 1)]);
|
||||||
@ -53,23 +41,41 @@ class Paid
|
|||||||
|
|
||||||
$invoice->save();
|
$invoice->save();
|
||||||
|
|
||||||
InvoicePayment::create($request->input());
|
// Customer add payment on invoice send user notification
|
||||||
|
foreach ($invoice->company->users as $user) {
|
||||||
|
if (!$user->can('read-notifications')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$request['status_code'] = $invoice->invoice_status_code;
|
$user->notify(new Notification($invoice, $invoice_payment));
|
||||||
|
}
|
||||||
$request['notify'] = 0;
|
|
||||||
|
|
||||||
$desc_date = Date::parse($request['paid_at'])->format($this->getCompanyDateFormat());
|
|
||||||
|
|
||||||
$desc_amount = money((float) $request['amount'], $request['currency_code'], true)->format();
|
|
||||||
|
|
||||||
$request['description'] = $desc_date . ' ' . $desc_amount;
|
|
||||||
|
|
||||||
InvoiceHistory::create($request->input());
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'success' => true,
|
'success' => true,
|
||||||
'error' => false,
|
'error' => false,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function createPayment($invoice, $request)
|
||||||
|
{
|
||||||
|
if (!is_array($request)) {
|
||||||
|
$request = $request->input();
|
||||||
|
}
|
||||||
|
|
||||||
|
$request['invoice_id'] = $invoice->id;
|
||||||
|
$request['paid_at'] = Date::parse('now')->format('Y-m-d');
|
||||||
|
$request['company_id'] = isset($request['company_id']) ? $request['company_id'] : session('company_id');
|
||||||
|
$request['account_id'] = isset($request['account_id']) ? $request['account_id'] : setting('general.default_account');
|
||||||
|
$request['payment_method'] = isset($request['payment_method']) ? $request['payment_method'] : setting('general.default_payment_method');
|
||||||
|
$request['currency_code'] = isset($request['currency_code']) ? $request['currency_code'] : $invoice->currency_code;
|
||||||
|
$request['currency_rate'] = isset($request['currency_rate']) ? $request['currency_rate'] : $invoice->currency_rate;
|
||||||
|
$request['notify'] = isset($request['notify']) ? $request['notify'] : 0;
|
||||||
|
|
||||||
|
$payment_request = new PaymentRequest();
|
||||||
|
$payment_request->merge($request);
|
||||||
|
|
||||||
|
$invoice_payment = dispatch(new CreateInvoicePayment($payment_request, $invoice));
|
||||||
|
|
||||||
|
return $invoice_payment;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
164
app/Listeners/Updates/Version130.php
Normal file
164
app/Listeners/Updates/Version130.php
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Listeners\Updates;
|
||||||
|
|
||||||
|
use App\Events\UpdateFinished;
|
||||||
|
use App\Models\Auth\Role;
|
||||||
|
use App\Models\Auth\Permission;
|
||||||
|
use Artisan;
|
||||||
|
|
||||||
|
class Version130 extends Listener
|
||||||
|
{
|
||||||
|
const ALIAS = 'core';
|
||||||
|
|
||||||
|
const VERSION = '1.3.0';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param $event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle(UpdateFinished $event)
|
||||||
|
{
|
||||||
|
// Check if should listen
|
||||||
|
if (!$this->check($event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set new Item Reminder settings
|
||||||
|
setting(['general.send_item_reminder' => '0']);
|
||||||
|
setting(['general.schedule_item_stocks' => '3,5,7']);
|
||||||
|
setting(['general.wizard' => '1']);
|
||||||
|
setting(['general.invoice_item' => 'settings.invoice.item']);
|
||||||
|
setting(['general.invoice_price' => 'settings.invoice.price']);
|
||||||
|
setting(['general.invoice_quantity' => 'settings.invoice.quantity']);
|
||||||
|
|
||||||
|
setting()->save();
|
||||||
|
|
||||||
|
$this->updatePermissions();
|
||||||
|
|
||||||
|
// Update database
|
||||||
|
Artisan::call('migrate', ['--force' => true]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function updatePermissions()
|
||||||
|
{
|
||||||
|
$permissions = [];
|
||||||
|
|
||||||
|
// Banking Reconciliations
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'read-banking-reconciliations',
|
||||||
|
'display_name' => 'Read Banking Reconciliations',
|
||||||
|
'description' => 'Read Banking Reconciliations',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'create-banking-reconciliations',
|
||||||
|
'display_name' => 'Create Banking Reconciliations',
|
||||||
|
'description' => 'Create Banking Reconciliations',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'update-banking-reconciliations',
|
||||||
|
'display_name' => 'Update Banking Reconciliations',
|
||||||
|
'description' => 'Update Banking Reconciliations',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'delete-banking-reconciliations',
|
||||||
|
'display_name' => 'Delete Banking Reconciliations',
|
||||||
|
'description' => 'Delete Banking Reconciliations',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Create Wizard Permissions
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'create-wizard-companies',
|
||||||
|
'display_name' => 'Create Wizard Compaines',
|
||||||
|
'description' => 'Create Wizard Compaines',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'create-wizard-currencies',
|
||||||
|
'display_name' => 'Create Wizard Currencies',
|
||||||
|
'description' => 'Create Wizard Currencies',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'create-wizard-taxes',
|
||||||
|
'display_name' => 'Create Wizard Taxes',
|
||||||
|
'description' => 'Create Wizard Taxes',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'create-wizard-finish',
|
||||||
|
'display_name' => 'Create Wizard Finish',
|
||||||
|
'description' => 'Create Wizard Finish',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Read Wizard Permissions
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'read-wizard-companies',
|
||||||
|
'display_name' => 'Read Wizard Compaines',
|
||||||
|
'description' => 'Read Wizard Compaines',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'read-wizard-currencies',
|
||||||
|
'display_name' => 'Read Wizard Currencies',
|
||||||
|
'description' => 'Read Wizard Currencies',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'read-wizard-taxes',
|
||||||
|
'display_name' => 'Read Wizard Taxes',
|
||||||
|
'description' => 'Read Wizard Taxes',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'read-wizard-finish',
|
||||||
|
'display_name' => 'Read Wizard Finish',
|
||||||
|
'description' => 'Read Wizard Finish',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Update Wizard Permissions
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'update-wizard-companies',
|
||||||
|
'display_name' => 'Update Wizard Compaines',
|
||||||
|
'description' => 'Update Wizard Compaines',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'update-wizard-currencies',
|
||||||
|
'display_name' => 'Update Wizard Currencies',
|
||||||
|
'description' => 'Update Wizard Currencies',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'update-wizard-taxes',
|
||||||
|
'display_name' => 'Update Wizard Taxes',
|
||||||
|
'description' => 'Update Wizard Taxes',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'update-wizard-finish',
|
||||||
|
'display_name' => 'Update Wizard Finish',
|
||||||
|
'description' => 'Update Wizard Finish',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Attach permission to roles
|
||||||
|
$roles = Role::all();
|
||||||
|
|
||||||
|
foreach ($roles as $role) {
|
||||||
|
$allowed = ['admin', 'manager'];
|
||||||
|
|
||||||
|
if (!in_array($role->name, $allowed)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($permissions as $permission) {
|
||||||
|
$role->attachPermission($permission);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
79
app/Listeners/Updates/Version132.php
Normal file
79
app/Listeners/Updates/Version132.php
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Listeners\Updates;
|
||||||
|
|
||||||
|
use App\Events\UpdateFinished;
|
||||||
|
use App\Models\Auth\Role;
|
||||||
|
use App\Models\Auth\Permission;
|
||||||
|
use Artisan;
|
||||||
|
|
||||||
|
class Version132 extends Listener
|
||||||
|
{
|
||||||
|
const ALIAS = 'core';
|
||||||
|
|
||||||
|
const VERSION = '1.3.2';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle the event.
|
||||||
|
*
|
||||||
|
* @param $event
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle(UpdateFinished $event)
|
||||||
|
{
|
||||||
|
// Check if should listen
|
||||||
|
if (!$this->check($event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->updatePermissions();
|
||||||
|
|
||||||
|
// Update database
|
||||||
|
Artisan::call('migrate', ['--force' => true]);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function updatePermissions()
|
||||||
|
{
|
||||||
|
$permissions = [];
|
||||||
|
|
||||||
|
// Banking Reconciliations
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'read-common-notifications',
|
||||||
|
'display_name' => 'Read Common Notifications',
|
||||||
|
'description' => 'Read Common Notifications',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'create-common-notifications',
|
||||||
|
'display_name' => 'Create Common Notifications',
|
||||||
|
'description' => 'Create Common Notifications',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'update-common-notifications',
|
||||||
|
'display_name' => 'Update Common Notifications',
|
||||||
|
'description' => 'Update Common Notifications',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$permissions[] = Permission::firstOrCreate([
|
||||||
|
'name' => 'delete-common-notifications',
|
||||||
|
'display_name' => 'Delete Common Notifications',
|
||||||
|
'description' => 'Delete Common Notifications',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Attach permission to roles
|
||||||
|
$roles = Role::all();
|
||||||
|
|
||||||
|
foreach ($roles as $role) {
|
||||||
|
$allowed = ['admin', 'manager'];
|
||||||
|
|
||||||
|
if (!in_array($role->name, $allowed)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($permissions as $permission) {
|
||||||
|
$role->attachPermission($permission);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
45
app/Models/Banking/Reconciliation.php
Normal file
45
app/Models/Banking/Reconciliation.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models\Banking;
|
||||||
|
|
||||||
|
use App\Models\Model;
|
||||||
|
use Sofa\Eloquence\Eloquence;
|
||||||
|
|
||||||
|
class Reconciliation extends Model
|
||||||
|
{
|
||||||
|
use Eloquence;
|
||||||
|
|
||||||
|
protected $table = 'reconciliations';
|
||||||
|
|
||||||
|
protected $dates = ['deleted_at', 'started_at', 'ended_at'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attributes that should be mass-assignable.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = ['company_id', 'account_id', 'started_at', 'ended_at', 'closing_balance', 'reconciled'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sortable columns.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $sortable = ['created_at', 'account_id', 'started_at', 'ended_at', 'closing_balance', 'reconciled'];
|
||||||
|
|
||||||
|
public function account()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\Banking\Account');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert closing balance to double.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setClosingBalanceAttribute($value)
|
||||||
|
{
|
||||||
|
$this->attributes['closing_balance'] = (double) $value;
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
namespace App\Models\Expense;
|
namespace App\Models\Expense;
|
||||||
|
|
||||||
use App\Models\Model;
|
use App\Models\Model;
|
||||||
|
use App\Models\Setting\Currency;
|
||||||
use App\Traits\Currencies;
|
use App\Traits\Currencies;
|
||||||
use App\Traits\DateTime;
|
use App\Traits\DateTime;
|
||||||
use App\Traits\Media;
|
use App\Traits\Media;
|
||||||
@ -22,7 +23,7 @@ class Bill extends Model
|
|||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $appends = ['attachment', 'discount'];
|
protected $appends = ['attachment', 'discount', 'paid'];
|
||||||
|
|
||||||
protected $dates = ['deleted_at', 'billed_at', 'due_at'];
|
protected $dates = ['deleted_at', 'billed_at', 'due_at'];
|
||||||
|
|
||||||
@ -82,6 +83,11 @@ class Bill extends Model
|
|||||||
return $this->hasMany('App\Models\Expense\BillItem');
|
return $this->hasMany('App\Models\Expense\BillItem');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function itemTaxes()
|
||||||
|
{
|
||||||
|
return $this->hasMany('App\Models\Expense\BillItemTax');
|
||||||
|
}
|
||||||
|
|
||||||
public function payments()
|
public function payments()
|
||||||
{
|
{
|
||||||
return $this->hasMany('App\Models\Expense\BillPayment');
|
return $this->hasMany('App\Models\Expense\BillPayment');
|
||||||
@ -194,4 +200,59 @@ class Bill extends Model
|
|||||||
|
|
||||||
return $percent;
|
return $percent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the paid amount.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getPaidAttribute()
|
||||||
|
{
|
||||||
|
if (empty($this->amount)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$paid = 0;
|
||||||
|
$reconciled = $reconciled_amount = 0;
|
||||||
|
|
||||||
|
if ($this->payments->count()) {
|
||||||
|
$currencies = Currency::enabled()->pluck('rate', 'code')->toArray();
|
||||||
|
|
||||||
|
foreach ($this->payments as $item) {
|
||||||
|
if ($this->currency_code == $item->currency_code) {
|
||||||
|
$amount = (double) $item->amount;
|
||||||
|
} else {
|
||||||
|
$default_model = new BillPayment();
|
||||||
|
$default_model->default_currency_code = $this->currency_code;
|
||||||
|
$default_model->amount = $item->amount;
|
||||||
|
$default_model->currency_code = $item->currency_code;
|
||||||
|
$default_model->currency_rate = $currencies[$item->currency_code];
|
||||||
|
|
||||||
|
$default_amount = (double) $default_model->getDivideConvertedAmount();
|
||||||
|
|
||||||
|
$convert_model = new BillPayment();
|
||||||
|
$convert_model->default_currency_code = $item->currency_code;
|
||||||
|
$convert_model->amount = $default_amount;
|
||||||
|
$convert_model->currency_code = $this->currency_code;
|
||||||
|
$convert_model->currency_rate = $currencies[$this->currency_code];
|
||||||
|
|
||||||
|
$amount = (double) $convert_model->getDynamicConvertedAmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
$paid += $amount;
|
||||||
|
|
||||||
|
if ($item->reconciled) {
|
||||||
|
$reconciled_amount = +$amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->amount == $reconciled_amount) {
|
||||||
|
$reconciled = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setAttribute('reconciled', $reconciled);
|
||||||
|
|
||||||
|
return $paid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,11 @@ class BillItem extends Model
|
|||||||
return $this->belongsTo('App\Models\Common\Item');
|
return $this->belongsTo('App\Models\Common\Item');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function itemTaxes()
|
||||||
|
{
|
||||||
|
return $this->hasMany('App\Models\Expense\BillItemTax', 'bill_item_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
public function tax()
|
public function tax()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('App\Models\Setting\Tax');
|
return $this->belongsTo('App\Models\Setting\Tax');
|
||||||
@ -66,4 +71,23 @@ class BillItem extends Model
|
|||||||
{
|
{
|
||||||
$this->attributes['tax'] = (double) $value;
|
$this->attributes['tax'] = (double) $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert tax to double.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function getTaxIdAttribute($value)
|
||||||
|
{
|
||||||
|
$tax_ids = [];
|
||||||
|
|
||||||
|
if (!empty($value)) {
|
||||||
|
$tax_ids[] = $value;
|
||||||
|
|
||||||
|
return $tax_ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->itemTaxes->pluck('tax_id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
47
app/Models/Expense/BillItemTax.php
Normal file
47
app/Models/Expense/BillItemTax.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models\Expense;
|
||||||
|
|
||||||
|
use App\Models\Model;
|
||||||
|
use App\Traits\Currencies;
|
||||||
|
|
||||||
|
class BillItemTax extends Model
|
||||||
|
{
|
||||||
|
|
||||||
|
use Currencies;
|
||||||
|
|
||||||
|
protected $table = 'bill_item_taxes';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attributes that should be mass-assignable.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = ['company_id', 'bill_id', 'bill_item_id', 'tax_id', 'name', 'amount'];
|
||||||
|
|
||||||
|
public function bill()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\Expense\Bill');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function item()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\Common\Item');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tax()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\Setting\Tax');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert amount to double.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setAmountAttribute($value)
|
||||||
|
{
|
||||||
|
$this->attributes['amount'] = (double) $value;
|
||||||
|
}
|
||||||
|
}
|
@ -4,12 +4,13 @@ namespace App\Models\Expense;
|
|||||||
|
|
||||||
use App\Models\Model;
|
use App\Models\Model;
|
||||||
use Bkwld\Cloner\Cloneable;
|
use Bkwld\Cloner\Cloneable;
|
||||||
|
use App\Traits\Currencies;
|
||||||
use Sofa\Eloquence\Eloquence;
|
use Sofa\Eloquence\Eloquence;
|
||||||
use App\Traits\Media;
|
use App\Traits\Media;
|
||||||
|
|
||||||
class Vendor extends Model
|
class Vendor extends Model
|
||||||
{
|
{
|
||||||
use Cloneable, Eloquence, Media;
|
use Cloneable, Currencies, Eloquence, Media;
|
||||||
|
|
||||||
protected $table = 'vendors';
|
protected $table = 'vendors';
|
||||||
|
|
||||||
@ -18,7 +19,7 @@ class Vendor extends Model
|
|||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $fillable = ['company_id', 'name', 'email', 'tax_number', 'phone', 'address', 'website', 'currency_code', 'enabled'];
|
protected $fillable = ['company_id', 'name', 'email', 'tax_number', 'phone', 'address', 'website', 'currency_code', 'reference', 'enabled'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sortable columns.
|
* Sortable columns.
|
||||||
@ -70,4 +71,19 @@ class Vendor extends Model
|
|||||||
|
|
||||||
return $this->getMedia('logo')->last();
|
return $this->getMedia('logo')->last();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getUnpaidAttribute()
|
||||||
|
{
|
||||||
|
$amount = 0;
|
||||||
|
|
||||||
|
$bills = $this->bills()->accrued()->notPaid()->get();
|
||||||
|
|
||||||
|
foreach ($bills as $bill) {
|
||||||
|
$bill_amount = $bill->amount - $bill->paid;
|
||||||
|
|
||||||
|
$amount += $this->dynamicConvert(setting('general.default_currency'), $bill_amount, $bill->currency_code, $bill->currency_rate, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $amount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,13 @@ namespace App\Models\Income;
|
|||||||
|
|
||||||
use App\Models\Model;
|
use App\Models\Model;
|
||||||
use Bkwld\Cloner\Cloneable;
|
use Bkwld\Cloner\Cloneable;
|
||||||
|
use App\Traits\Currencies;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
use Sofa\Eloquence\Eloquence;
|
use Sofa\Eloquence\Eloquence;
|
||||||
|
|
||||||
class Customer extends Model
|
class Customer extends Model
|
||||||
{
|
{
|
||||||
use Cloneable, Eloquence, Notifiable;
|
use Cloneable, Currencies, Eloquence, Notifiable;
|
||||||
|
|
||||||
protected $table = 'customers';
|
protected $table = 'customers';
|
||||||
|
|
||||||
@ -18,7 +19,7 @@ class Customer extends Model
|
|||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $fillable = ['company_id', 'user_id', 'name', 'email', 'tax_number', 'phone', 'address', 'website', 'currency_code', 'enabled'];
|
protected $fillable = ['company_id', 'user_id', 'name', 'email', 'tax_number', 'phone', 'address', 'website', 'currency_code', 'reference', 'enabled'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sortable columns.
|
* Sortable columns.
|
||||||
@ -64,4 +65,19 @@ class Customer extends Model
|
|||||||
{
|
{
|
||||||
$this->user_id = null;
|
$this->user_id = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getUnpaidAttribute()
|
||||||
|
{
|
||||||
|
$amount = 0;
|
||||||
|
|
||||||
|
$invoices = $this->invoices()->accrued()->notPaid()->get();
|
||||||
|
|
||||||
|
foreach ($invoices as $invoice) {
|
||||||
|
$invoice_amount = $invoice->amount - $invoice->paid;
|
||||||
|
|
||||||
|
$amount += $this->dynamicConvert(setting('general.default_currency'), $invoice_amount, $invoice->currency_code, $invoice->currency_rate, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $amount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
namespace App\Models\Income;
|
namespace App\Models\Income;
|
||||||
|
|
||||||
use App\Models\Model;
|
use App\Models\Model;
|
||||||
|
use App\Models\Setting\Currency;
|
||||||
use App\Traits\Currencies;
|
use App\Traits\Currencies;
|
||||||
use App\Traits\DateTime;
|
use App\Traits\DateTime;
|
||||||
use App\Traits\Incomes;
|
use App\Traits\Incomes;
|
||||||
@ -23,7 +24,7 @@ class Invoice extends Model
|
|||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $appends = ['attachment', 'discount'];
|
protected $appends = ['attachment', 'discount', 'paid'];
|
||||||
|
|
||||||
protected $dates = ['deleted_at', 'invoiced_at', 'due_at'];
|
protected $dates = ['deleted_at', 'invoiced_at', 'due_at'];
|
||||||
|
|
||||||
@ -56,6 +57,8 @@ class Invoice extends Model
|
|||||||
'notes' => 2,
|
'notes' => 2,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
protected $reconciled_amount = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clonable relationships.
|
* Clonable relationships.
|
||||||
*
|
*
|
||||||
@ -83,6 +86,11 @@ class Invoice extends Model
|
|||||||
return $this->hasMany('App\Models\Income\InvoiceItem');
|
return $this->hasMany('App\Models\Income\InvoiceItem');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function itemTaxes()
|
||||||
|
{
|
||||||
|
return $this->hasMany('App\Models\Income\InvoiceItemTax');
|
||||||
|
}
|
||||||
|
|
||||||
public function histories()
|
public function histories()
|
||||||
{
|
{
|
||||||
return $this->hasMany('App\Models\Income\InvoiceHistory');
|
return $this->hasMany('App\Models\Income\InvoiceHistory');
|
||||||
@ -196,4 +204,59 @@ class Invoice extends Model
|
|||||||
|
|
||||||
return $percent;
|
return $percent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the paid amount.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getPaidAttribute()
|
||||||
|
{
|
||||||
|
if (empty($this->amount)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$paid = 0;
|
||||||
|
$reconciled = $reconciled_amount = 0;
|
||||||
|
|
||||||
|
if ($this->payments->count()) {
|
||||||
|
$currencies = Currency::enabled()->pluck('rate', 'code')->toArray();
|
||||||
|
|
||||||
|
foreach ($this->payments as $item) {
|
||||||
|
if ($this->currency_code == $item->currency_code) {
|
||||||
|
$amount = (double) $item->amount;
|
||||||
|
} else {
|
||||||
|
$default_model = new InvoicePayment();
|
||||||
|
$default_model->default_currency_code = $this->currency_code;
|
||||||
|
$default_model->amount = $item->amount;
|
||||||
|
$default_model->currency_code = $item->currency_code;
|
||||||
|
$default_model->currency_rate = $currencies[$item->currency_code];
|
||||||
|
|
||||||
|
$default_amount = (double) $default_model->getDivideConvertedAmount();
|
||||||
|
|
||||||
|
$convert_model = new InvoicePayment();
|
||||||
|
$convert_model->default_currency_code = $item->currency_code;
|
||||||
|
$convert_model->amount = $default_amount;
|
||||||
|
$convert_model->currency_code = $this->currency_code;
|
||||||
|
$convert_model->currency_rate = $currencies[$this->currency_code];
|
||||||
|
|
||||||
|
$amount = (double) $convert_model->getDynamicConvertedAmount();
|
||||||
|
}
|
||||||
|
|
||||||
|
$paid += $amount;
|
||||||
|
|
||||||
|
if ($item->reconciled) {
|
||||||
|
$reconciled_amount = +$amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->amount == $reconciled_amount) {
|
||||||
|
$reconciled = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setAttribute('reconciled', $reconciled);
|
||||||
|
|
||||||
|
return $paid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,11 @@ class InvoiceItem extends Model
|
|||||||
return $this->belongsTo('App\Models\Common\Item');
|
return $this->belongsTo('App\Models\Common\Item');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function itemTaxes()
|
||||||
|
{
|
||||||
|
return $this->hasMany('App\Models\Income\InvoiceItemTax', 'invoice_item_id', 'id');
|
||||||
|
}
|
||||||
|
|
||||||
public function tax()
|
public function tax()
|
||||||
{
|
{
|
||||||
return $this->belongsTo('App\Models\Setting\Tax');
|
return $this->belongsTo('App\Models\Setting\Tax');
|
||||||
@ -66,4 +71,23 @@ class InvoiceItem extends Model
|
|||||||
{
|
{
|
||||||
$this->attributes['tax'] = (double) $value;
|
$this->attributes['tax'] = (double) $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert tax to double.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function getTaxIdAttribute($value)
|
||||||
|
{
|
||||||
|
$tax_ids = [];
|
||||||
|
|
||||||
|
if (!empty($value)) {
|
||||||
|
$tax_ids[] = $value;
|
||||||
|
|
||||||
|
return $tax_ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->itemTaxes->pluck('tax_id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
47
app/Models/Income/InvoiceItemTax.php
Normal file
47
app/Models/Income/InvoiceItemTax.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models\Income;
|
||||||
|
|
||||||
|
use App\Models\Model;
|
||||||
|
use App\Traits\Currencies;
|
||||||
|
|
||||||
|
class InvoiceItemTax extends Model
|
||||||
|
{
|
||||||
|
|
||||||
|
use Currencies;
|
||||||
|
|
||||||
|
protected $table = 'invoice_item_taxes';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attributes that should be mass-assignable.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = ['company_id', 'invoice_id', 'invoice_item_id', 'tax_id', 'name', 'amount'];
|
||||||
|
|
||||||
|
public function invoice()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\Income\Invoice');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function item()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\Common\Item');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tax()
|
||||||
|
{
|
||||||
|
return $this->belongsTo('App\Models\Setting\Tax');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert amount to double.
|
||||||
|
*
|
||||||
|
* @param string $value
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setAmountAttribute($value)
|
||||||
|
{
|
||||||
|
$this->attributes['amount'] = (double) $value;
|
||||||
|
}
|
||||||
|
}
|
@ -115,4 +115,43 @@ class Model extends Eloquent
|
|||||||
{
|
{
|
||||||
return $query->where('enabled', 0);
|
return $query->where('enabled', 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scope to only include reconciled models.
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||||
|
* @param $value
|
||||||
|
* @return \Illuminate\Database\Eloquent\Builder
|
||||||
|
*/
|
||||||
|
public function scopeReconciled($query, $value = 1)
|
||||||
|
{
|
||||||
|
return $query->where('reconciled', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scopeAccount($query, $accounts)
|
||||||
|
{
|
||||||
|
if (empty($accounts)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->whereIn('account_id', (array) $accounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scopeCustomer($query, $customers)
|
||||||
|
{
|
||||||
|
if (empty($customers)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->whereIn('customer_id', (array) $customers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scopeVendor($query, $vendors)
|
||||||
|
{
|
||||||
|
if (empty($vendors)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->whereIn('vendor_id', (array) $vendors);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ class Category extends Model
|
|||||||
*/
|
*/
|
||||||
public function scopeType($query, $type)
|
public function scopeType($query, $type)
|
||||||
{
|
{
|
||||||
return $query->where('type', $type);
|
return $query->whereIn('type', (array) $type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -81,7 +81,7 @@ class Currency extends Model
|
|||||||
*/
|
*/
|
||||||
public function getPrecisionAttribute($value)
|
public function getPrecisionAttribute($value)
|
||||||
{
|
{
|
||||||
if (empty($value)) {
|
if (is_null($value)) {
|
||||||
return config('money.' . $this->code . '.precision');
|
return config('money.' . $this->code . '.precision');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ class Currency extends Model
|
|||||||
*/
|
*/
|
||||||
public function getSymbolAttribute($value)
|
public function getSymbolAttribute($value)
|
||||||
{
|
{
|
||||||
if (empty($value)) {
|
if (is_null($value)) {
|
||||||
return config('money.' . $this->code . '.symbol');
|
return config('money.' . $this->code . '.symbol');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ class Currency extends Model
|
|||||||
*/
|
*/
|
||||||
public function getSymbolFirstAttribute($value)
|
public function getSymbolFirstAttribute($value)
|
||||||
{
|
{
|
||||||
if (empty($value)) {
|
if (is_null($value)) {
|
||||||
return config('money.' . $this->code . '.symbol_first');
|
return config('money.' . $this->code . '.symbol_first');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ class Currency extends Model
|
|||||||
*/
|
*/
|
||||||
public function getDecimalMarkAttribute($value)
|
public function getDecimalMarkAttribute($value)
|
||||||
{
|
{
|
||||||
if (empty($value)) {
|
if (is_null($value)) {
|
||||||
return config('money.' . $this->code . '.decimal_mark');
|
return config('money.' . $this->code . '.decimal_mark');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ class Currency extends Model
|
|||||||
*/
|
*/
|
||||||
public function getThousandsSeparatorAttribute($value)
|
public function getThousandsSeparatorAttribute($value)
|
||||||
{
|
{
|
||||||
if (empty($value)) {
|
if (is_null($value)) {
|
||||||
return config('money.' . $this->code . '.thousands_separator');
|
return config('money.' . $this->code . '.thousands_separator');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ class Tax extends Model
|
|||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $fillable = ['company_id', 'name', 'rate', 'enabled'];
|
protected $fillable = ['company_id', 'name', 'rate', 'type', 'enabled'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sortable columns.
|
* Sortable columns.
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user