Merge branch 'master' into laravel-7

This commit is contained in:
Denis Duliçi
2020-03-15 01:19:41 +03:00
committed by GitHub
184 changed files with 2472 additions and 1279 deletions

View File

@ -98,7 +98,7 @@ abstract class DocumentModel extends Model
$default_model->currency_code = $item->currency_code;
$default_model->currency_rate = $currencies[$item->currency_code];
$default_amount = (double) $default_model->getDivideConvertedAmount();
$default_amount = (double) $default_model->getAmountConvertedToDefault();
$convert_model = new Transaction();
$convert_model->default_currency_code = $item->currency_code;
@ -106,7 +106,7 @@ abstract class DocumentModel extends Model
$convert_model->currency_code = $this->currency_code;
$convert_model->currency_rate = $currencies[$this->currency_code];
$amount = (double) $convert_model->getAmountConvertedFromCustomDefault();
$amount = (double) $convert_model->getAmountConvertedFromDefault();
}
$paid += $amount;

View File

@ -30,7 +30,7 @@ abstract class Controller extends BaseController
*
* @return void
*/
protected function setPermissions()
public function setPermissions()
{
// No need to check for permission in console
if (app()->runningInConsole()) {
@ -90,33 +90,4 @@ abstract class Controller extends BaseController
return new LengthAwarePaginator($items->forPage($page, $perPage), $items->count(), $perPage, $page, $options);
}
/**
* Dispatch a job to its appropriate handler and return a response array for ajax calls.
*
* @param mixed $job
* @return mixed
*/
public function ajaxDispatch($job)
{
try {
$data = $this->dispatch($job);
$response = [
'success' => true,
'error' => false,
'data' => $data,
'message' => '',
];
} catch(\Exception $e) {
$response = [
'success' => false,
'error' => true,
'data' => null,
'message' => $e->getMessage(),
];
}
return $response;
}
}

View File

@ -0,0 +1,10 @@
<?php
namespace App\Abstracts;
use Monooso\Unobserve\CanMute;
abstract class Observer
{
use CanMute;
}

View File

@ -67,6 +67,9 @@ abstract class Report
'datasets' => [],
];
public $column_name_width = 'report-column-name';
public $column_value_width = 'report-column-value';
public function __construct(Model $model = null, $load_data = true)
{
$this->setGroups();
@ -95,6 +98,7 @@ abstract class Report
$this->setFilters();
$this->setRows();
$this->setData();
$this->setColumnWidth();
$this->loaded = true;
}
@ -198,6 +202,30 @@ abstract class Report
return \Excel::download(new Export($this->views['content'], $this), \Str::filename($this->model->name) . '.xlsx');
}
public function setColumnWidth()
{
if (empty($this->model->settings->period)) {
return;
}
$width = '';
switch ($this->model->settings->period) {
case 'quarterly':
$width = 'col-sm-2';
break;
case 'yearly':
$width = 'col-sm-4';
break;
}
if (empty($width)) {
return;
}
$this->column_name_width = $this->column_value_width = $width;
}
public function setYear()
{
$this->year = request('year', Date::now()->year);

View File

@ -32,6 +32,9 @@ class BillReminder extends Command
*/
public function handle()
{
// Disable model cache
config(['laravel-model-caching.enabled' => false]);
// Get all companies
$companies = Company::enabled()->cursor();

View File

@ -32,6 +32,9 @@ class InvoiceReminder extends Command
*/
public function handle()
{
// Disable model cache
config(['laravel-model-caching.enabled' => false]);
// Get all companies
$companies = Company::enabled()->cursor();

View File

@ -45,6 +45,9 @@ class RecurringCheck extends Command
*/
public function handle()
{
// Disable model cache
config(['laravel-model-caching.enabled' => false]);
// Get all companies
$companies = Company::enabled()->cursor();

View File

@ -0,0 +1,22 @@
<?php
namespace App\Events\Banking;
use Illuminate\Queue\SerializesModels;
class TransactionCreated
{
use SerializesModels;
public $transaction;
/**
* Create a new event instance.
*
* @param $transaction
*/
public function __construct($transaction)
{
$this->transaction = $transaction;
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Events\Banking;
use Illuminate\Queue\SerializesModels;
class TransactionCreating
{
use SerializesModels;
public $request;
/**
* Create a new event instance.
*
* @param $request
*/
public function __construct($request)
{
$this->request = $request;
}
}

View File

@ -198,7 +198,7 @@ class Reconciliations extends Controller
$total = $account->opening_balance;
// Sum income transactions
$transactions = $account->income_transacions()->whereDate('paid_at', '<', $started_at)->get();
$transactions = $account->income_transactions()->whereDate('paid_at', '<', $started_at)->get();
foreach ($transactions as $item) {
$total += $item->amount;
}

View File

@ -0,0 +1,65 @@
<?php
namespace App\Http\Controllers\Modals;
use App\Abstracts\Http\Controller;
use App\Http\Requests\Banking\Account as Request;
use App\Jobs\Banking\CreateAccount;
use App\Models\Banking\Account;
use App\Models\Setting\Currency;
class Accounts extends Controller
{
/**
* Instantiate a new controller instance.
*/
public function __construct()
{
// Add CRUD permission check
$this->middleware('permission:create-banking-accounts')->only(['create', 'store', 'duplicate', 'import']);
$this->middleware('permission:read-banking-accounts')->only(['index', 'show', 'edit', 'export']);
$this->middleware('permission:update-banking-accounts')->only(['update', 'enable', 'disable']);
$this->middleware('permission:delete-banking-accounts')->only('destroy');
}
/**
* Show the form for creating a new resource.
*
* @return Response
*/
public function create()
{
$currencies = Currency::enabled()->pluck('name', 'code');
$currency = Currency::where('code', '=', setting('default.currency'))->first();
$html = view('modals.accounts.create', compact('currencies', 'currency'))->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;
$response = $this->ajaxDispatch(new CreateAccount($request));
if ($response['success']) {
$response['message'] = trans('messages.success.added', ['type' => trans_choice('general.accounts', 1)]);
}
return response()->json($response);
}
}

View File

@ -100,7 +100,7 @@ class Invoices extends Controller
if ($invoice->currency_code != $item->currency_code) {
$item->default_currency_code = $invoice->currency_code;
$amount = $item->getAmountConvertedFromCustomDefault();
$amount = $item->getAmountConvertedFromDefault();
}
$paid += $amount;
@ -129,7 +129,7 @@ class Invoices extends Controller
if ($invoice->currency_code != $item->currency_code) {
$item->default_currency_code = $invoice->currency_code;
$amount = $item->getAmountConvertedFromCustomDefault();
$amount = $item->getAmountConvertedFromDefault();
}
$paid += $amount;

View File

@ -108,7 +108,9 @@ class Bills extends Controller
$categories = Category::type('expense')->enabled()->orderBy('name')->pluck('name', 'id');
return view('purchases.bills.create', compact('vendors', 'currencies', 'currency', 'items', 'taxes', 'categories'));
$number = $this->getNextBillNumber();
return view('purchases.bills.create', compact('vendors', 'currencies', 'currency', 'items', 'taxes', 'categories', 'number'));
}
/**
@ -369,7 +371,7 @@ class Bills extends Controller
if ($bill->currency_code != $item->currency_code) {
$item->default_currency_code = $bill->currency_code;
$amount = $item->getAmountConvertedFromCustomDefault();
$amount = $item->getAmountConvertedFromDefault();
}
$paid += $amount;

View File

@ -447,7 +447,7 @@ class Invoices extends Controller
if ($invoice->currency_code != $item->currency_code) {
$item->default_currency_code = $invoice->currency_code;
$amount = $item->getAmountConvertedFromCustomDefault();
$amount = $item->getAmountConvertedFromDefault();
}
$paid += $amount;

View File

@ -22,15 +22,10 @@ class Money
$sale_price = $request->get('sale_price');
$purchase_price = $request->get('purchase_price');
$opening_balance = $request->get('opening_balance');
$currency_code = $request->get('currency_code');
$items = $request->get('items');
if (empty($currency_code)) {
$currency_code = setting('default.currency');
}
if (!empty($amount)) {
$amount = money($request->get('amount'), $currency_code)->getAmount();
$amount = money($amount)->getAmount();
$request->request->set('amount', $amount);
}
@ -42,11 +37,7 @@ class Money
continue;
}
if (isset($item['currency']) && $item['currency'] != $currency_code) {
$items[$key]['price'] = money($item['price'], $item['currency'])->getAmount();
} else {
$items[$key]['price'] = money($item['price'], $currency_code)->getAmount();
}
$items[$key]['price'] = money($item['price'])->getAmount();
}
$request->request->set('items', $items);
@ -54,24 +45,10 @@ class Money
}
if (isset($opening_balance)) {
$opening_balance = money($opening_balance, $currency_code)->getAmount();
$opening_balance = money($opening_balance)->getAmount();
$request->request->set('opening_balance', $opening_balance);
}
/* check item price use money
if (isset($sale_price)) {
$sale_price = money($sale_price, $currency_code)->getAmount();
$request->request->set('sale_price', $sale_price);
}
if (isset($purchase_price)) {
$purchase_price = money($purchase_price, $currency_code)->getAmount();
$request->request->set('purchase_price', $purchase_price);
}
*/
}
return $next($request);

View File

@ -37,7 +37,7 @@ class Contact extends FormRequest
$id = null;
}
if (!empty($this->request->get('create_user')) && empty($this->request->get('user_id'))) {
if (($this->request->get('create_user', 'false') === 'true') && empty($this->request->get('user_id'))) {
$required = 'required|';
}

View File

@ -92,7 +92,7 @@ class CreateDocumentTransaction extends Job
$default_amount_model->currency_code = $this->request['currency_code'];
$default_amount_model->currency_rate = $currencies[$this->request['currency_code']];
$default_amount = (double) $default_amount_model->getDivideConvertedAmount();
$default_amount = (double) $default_amount_model->getAmountConvertedToDefault();
$convert_amount_model = new Transaction();
$convert_amount_model->default_currency_code = $this->request['currency_code'];
@ -100,7 +100,7 @@ class CreateDocumentTransaction extends Job
$convert_amount_model->currency_code = $this->model->currency_code;
$convert_amount_model->currency_rate = $currencies[$this->model->currency_code];
$amount = (double) $convert_amount_model->getAmountConvertedFromCustomDefault();
$amount = (double) $convert_amount_model->getAmountConvertedFromDefault();
}
$total_amount -= $this->model->paid;
@ -126,7 +126,7 @@ class CreateDocumentTransaction extends Job
$error_amount_model->currency_code = $this->model->currency_code;
$error_amount_model->currency_rate = $currencies[$this->model->currency_code];
$error_amount = (double) $error_amount_model->getDivideConvertedAmount();
$error_amount = (double) $error_amount_model->getAmountConvertedToDefault();
$convert_amount_model = new Transaction();
$convert_amount_model->default_currency_code = $this->model->currency_code;
@ -134,7 +134,7 @@ class CreateDocumentTransaction extends Job
$convert_amount_model->currency_code = $this->request['currency_code'];
$convert_amount_model->currency_rate = $currencies[$this->request['currency_code']];
$error_amount = (double) $convert_amount_model->getAmountConvertedFromCustomDefault();
$error_amount = (double) $convert_amount_model->getAmountConvertedFromDefault();
}
$message = trans('messages.error.over_payment', ['amount' => money($error_amount, $this->request['currency_code'], true)]);

View File

@ -3,12 +3,16 @@
namespace App\Jobs\Banking;
use App\Abstracts\Job;
use App\Events\Banking\TransactionCreated;
use App\Events\Banking\TransactionCreating;
use App\Models\Banking\Transaction;
class CreateTransaction extends Job
{
protected $request;
protected $transaction;
/**
* Create a new job instance.
*
@ -26,18 +30,22 @@ class CreateTransaction extends Job
*/
public function handle()
{
$transaction = Transaction::create($this->request->all());
event(new TransactionCreating($this->request));
$this->transaction = Transaction::create($this->request->all());
// Upload attachment
if ($this->request->file('attachment')) {
$media = $this->getMedia($this->request->file('attachment'), 'transactions');
$transaction->attachMedia($media, 'attachment');
$this->transaction->attachMedia($media, 'attachment');
}
// Recurring
$transaction->createRecurring();
$this->transaction->createRecurring();
return $transaction;
event(new TransactionCreated($this->transaction));
return $this->transaction;
}
}

View File

@ -64,7 +64,7 @@ class CreateTransfer extends Job
$default_amount_model->currency_code = $expense_currency_code;
$default_amount_model->currency_rate = $currencies[$expense_currency_code];
$default_amount = $default_amount_model->getAmountDivided();
$default_amount = $default_amount_model->getAmountConvertedToDefault();
}
$transfer_amount = new Transfer();
@ -74,7 +74,7 @@ class CreateTransfer extends Job
$transfer_amount->currency_code = $income_currency_code;
$transfer_amount->currency_rate = $currencies[$income_currency_code];
$amount = $transfer_amount->getAmountConvertedFromCustomDefault();
$amount = $transfer_amount->getAmountConvertedFromDefault();
} else {
$amount = $this->request->get('amount');
}

View File

@ -41,6 +41,12 @@ class DeleteTransaction extends Job
*/
public function authorize()
{
if ($this->transaction->reconciled) {
$message = trans('messages.warning.reconciled_tran');
throw new \Exception($message);
}
if ($this->transaction->category->id == Category::transfer()) {
throw new \Exception('Unauthorized');
}

View File

@ -30,6 +30,8 @@ class UpdateTransaction extends Job
*/
public function handle()
{
$this->authorize();
$this->transaction->update($this->request->all());
// Upload attachment
@ -44,4 +46,18 @@ class UpdateTransaction extends Job
return $this->transaction;
}
/**
* Determine if this action is applicable.
*
* @return void
*/
public function authorize()
{
if ($this->transaction->reconciled) {
$message = trans('messages.warning.reconciled_tran');
throw new \Exception($message);
}
}
}

View File

@ -71,7 +71,7 @@ class UpdateTransfer extends Job
$default_amount_model->currency_code = $expense_currency_code;
$default_amount_model->currency_rate = $currencies[$expense_currency_code];
$default_amount = $default_amount_model->getDivideConvertedAmount();
$default_amount = $default_amount_model->getAmountConvertedToDefault();
}
$transfer_amount = new Transfer();
@ -81,7 +81,7 @@ class UpdateTransfer extends Job
$transfer_amount->currency_code = $income_currency_code;
$transfer_amount->currency_rate = $currencies[$income_currency_code];
$amount = $transfer_amount->getAmountConvertedFromCustomDefault();
$amount = $transfer_amount->getAmountConvertedFromDefault();
} else {
$amount = $this->request->get('amount');
}

View File

@ -27,7 +27,7 @@ class CreateContact extends Job
*/
public function handle()
{
if (!empty($this->request->input('create_user'))) {
if ($this->request->get('create_user', 'false') === 'true') {
$this->createUser();
}

View File

@ -33,7 +33,7 @@ class UpdateContact extends Job
{
$this->authorize();
if (!empty($this->request->input('create_user'))) {
if ($this->request->get('create_user', 'false') === 'true') {
$this->createUser();
}

View File

@ -4,6 +4,7 @@ namespace App\Jobs\Purchase;
use App\Abstracts\Job;
use App\Models\Purchase\Bill;
use App\Observers\Transaction;
class DeleteBill extends Job
{
@ -26,7 +27,9 @@ class DeleteBill extends Job
*/
public function handle()
{
session(['deleting_bill' => true]);
$this->authorize();
Transaction::mute();
$this->deleteRelationships($this->bill, [
'items', 'item_taxes', 'histories', 'transactions', 'recurring', 'totals'
@ -34,8 +37,22 @@ class DeleteBill extends Job
$this->bill->delete();
session()->forget('deleting_bill');
Transaction::unmute();
return true;
}
/**
* Determine if this action is applicable.
*
* @return void
*/
public function authorize()
{
if ($this->bill->transactions()->isReconciled()->count()) {
$message = trans('messages.warning.reconciled_doc', ['type' => trans_choice('general.bills', 1)]);
throw new \Exception($message);
}
}
}

View File

@ -4,6 +4,7 @@ namespace App\Jobs\Sale;
use App\Abstracts\Job;
use App\Models\Sale\Invoice;
use App\Observers\Transaction;
class DeleteInvoice extends Job
{
@ -26,7 +27,9 @@ class DeleteInvoice extends Job
*/
public function handle()
{
session(['deleting_invoice' => true]);
$this->authorize();
Transaction::mute();
$this->deleteRelationships($this->invoice, [
'items', 'item_taxes', 'histories', 'transactions', 'recurring', 'totals'
@ -34,8 +37,22 @@ class DeleteInvoice extends Job
$this->invoice->delete();
session()->forget('deleting_invoice');
Transaction::unmute();
return true;
}
/**
* Determine if this action is applicable.
*
* @return void
*/
public function authorize()
{
if ($this->invoice->transactions()->isReconciled()->count()) {
$message = trans('messages.warning.reconciled_doc', ['type' => trans_choice('general.invoices', 1)]);
throw new \Exception($message);
}
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Listeners\Purchase;
use App\Events\Purchase\BillCreated as Event;
use App\Traits\Purchases;
class IncreaseNextBillNumber
{
use Purchases;
/**
* Handle the event.
*
* @param $event
* @return void
*/
public function handle(Event $event)
{
// Update next bill number
$this->increaseNextBillNumber();
}
}

View File

@ -0,0 +1,100 @@
<?php
namespace App\Listeners\Update\V20;
use App\Abstracts\Listeners\Update as Listener;
use App\Events\Install\UpdateFinished as Event;
use Illuminate\Support\Facades\DB;
class Version205 extends Listener
{
const ALIAS = 'core';
const VERSION = '2.0.5';
protected $items;
protected $categories;
/**
* Handle the event.
*
* @param $event
* @return void
*/
public function handle(Event $event)
{
if ($this->skipThisUpdate($event)) {
return;
}
$this->items = [];
$this->updateBillItems();
$this->updateInvoiceItems();
}
protected function updateBillItems()
{
$bill_items = DB::table('bill_items')->whereNull('deleted_at')->where('item_id', 0)->cursor();
foreach ($bill_items as $bill_item) {
$item_id = $this->getItemId($bill_item);
DB::table('bill_items')
->where('id', $bill_item->id)
->update(['item_id' => $item_id]);
}
}
protected function updateInvoiceItems()
{
$invoice_items = DB::table('invoice_items')->whereNull('deleted_at')->where('item_id', 0)->cursor();
foreach ($invoice_items as $invoice_item) {
$item_id = $this->getItemId($invoice_item);
DB::table('invoice_items')
->where('id', $invoice_item->id)
->update(['item_id' => $item_id]);
DB::table('items')
->where('id', $item_id)
->update(['sale_price' => $invoice_item->price]);
}
}
protected function getItemId($item)
{
// Set category_id for company.
if (!isset($this->categories[$item->company_id])) {
$this->categories[$item->company_id] = DB::table('categories')->where('company_id', $item->company_id)->where('type', 'item')->first()->id;
}
// Return set item_id for item name.
if (isset($this->items[$item->company_id]) && in_array($item->name, $this->items[$item->company_id])) {
return array_search($item->name, $this->items[$item->company_id]);
}
// Insert new item.
$item_id = DB::table('items')->insertGetId([
'company_id' => $item->company_id,
'name' => $item->name,
'description' => null,
'sale_price' => $item->price,
'purchase_price' => $item->price,
'category_id' => $this->categories[$item->company_id],
'tax_id' => null,
'enabled' => 1,
'created_at' => $item->created_at,
'updated_at' => $item->updated_at,
'deleted_at' => null,
]);
// Set item_id for item name.
$this->items[$item->company_id][$item_id] = $item->name;
return $item_id;
}
}

View File

@ -39,7 +39,7 @@ class Account extends Model
return $this->transactions()->where('type', 'expense');
}
public function income_transacions()
public function income_transactions()
{
return $this->transactions()->where('type', 'income');
}
@ -81,7 +81,7 @@ class Account extends Model
$total = $this->opening_balance;
// Sum Incomes
$total += $this->income_transacions->sum('amount');
$total += $this->income_transactions->sum('amount');
// Subtract Expenses
$total -= $this->expense_transactions->sum('amount');

View File

@ -174,6 +174,28 @@ class Transaction extends Model
return $query->sum('amount');
}
/**
* Get only reconciled.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeIsReconciled($query)
{
return $query->where('reconciled', 1);
}
/**
* Get only not reconciled.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeIsNotReconciled($query)
{
return $query->where('reconciled', 0);
}
/**
* Convert amount to double.
*
@ -211,9 +233,4 @@ class Transaction extends Model
return $this->getMedia('attachment')->last();
}
public function getDivideConvertedAmount($format = false)
{
return $this->divide($this->amount, $this->currency_code, $this->currency_rate, $format);
}
}

View File

@ -114,7 +114,7 @@ class Contact extends Model
$this->$collection()->accrued()->notPaid()->each(function ($item) use (&$amount) {
$unpaid = $item->amount - $item->paid;
$amount += $this->convertFromDefault($unpaid, $item->currency_code, $item->currency_rate, false);
$amount += $this->convertFromDefault($unpaid, $item->currency_code, $item->currency_rate);
});
return $amount;

View File

@ -99,5 +99,6 @@ class Bill extends DocumentModel
public function onCloning($src, $child = null)
{
$this->status = 'draft';
$this->bill_number = $this->getNextBillNumber();
}
}

View File

@ -27,6 +27,15 @@ class BillItem extends Model
*/
public $cloneable_relations = ['taxes'];
public static function boot()
{
parent::boot();
static::retrieved(function($model) {
$model->setTaxIds();
});
}
public function bill()
{
return $this->belongsTo('App\Models\Purchase\Bill');
@ -74,4 +83,20 @@ class BillItem extends Model
{
$this->attributes['tax'] = (double) $value;
}
/**
* Convert tax to Array.
*
* @return void
*/
public function setTaxIds()
{
$tax_ids = [];
foreach ($this->taxes as $tax) {
$tax_ids[] = (string) $tax->tax_id;
}
$this->setAttribute('tax_id', $tax_ids);
}
}

View File

@ -26,6 +26,15 @@ class InvoiceItem extends Model
*/
public $cloneable_relations = ['taxes'];
public static function boot()
{
parent::boot();
static::retrieved(function($model) {
$model->setTaxIds();
});
}
public function invoice()
{
return $this->belongsTo('App\Models\Sale\Invoice');
@ -73,4 +82,20 @@ class InvoiceItem extends Model
{
$this->attributes['tax'] = (double) $value;
}
/**
* Convert tax to Array.
*
* @return void
*/
public function setTaxIds()
{
$tax_ids = [];
foreach ($this->taxes as $tax) {
$tax_ids[] = (string) $tax->tax_id;
}
$this->setAttribute('tax_id', $tax_ids);
}
}

View File

@ -32,7 +32,7 @@ class Category extends Model
return $this->transactions()->where('type', 'expense');
}
public function income_transacions()
public function income_transactions()
{
return $this->transactions()->where('type', 'income');
}

View File

@ -2,12 +2,13 @@
namespace App\Observers;
use App\Abstracts\Observer;
use App\Jobs\Purchase\CreateBillHistory;
use App\Jobs\Sale\CreateInvoiceHistory;
use App\Models\Banking\Transaction as Model;
use App\Traits\Jobs;
class Transaction
class Transaction extends Observer
{
use Jobs;
@ -30,10 +31,6 @@ class Transaction
protected function updateInvoice($transaction)
{
if (session('deleting_invoice')) {
return;
}
$invoice = $transaction->invoice;
$invoice->status = ($invoice->transactions->count() > 1) ? 'partial' : 'sent';
@ -45,10 +42,6 @@ class Transaction
protected function updateBill($transaction)
{
if (session('deleting_bill')) {
return;
}
$bill = $transaction->bill;
$bill->status = ($bill->transactions->count() > 1) ? 'partial' : 'received';

View File

@ -16,6 +16,7 @@ class Event extends Provider
'App\Listeners\Update\CreateModuleUpdatedHistory',
'App\Listeners\Update\V20\Version200',
'App\Listeners\Update\V20\Version203',
'App\Listeners\Update\V20\Version205',
],
'Illuminate\Auth\Events\Login' => [
'App\Listeners\Auth\Login',
@ -25,6 +26,7 @@ class Event extends Provider
],
'App\Events\Purchase\BillCreated' => [
'App\Listeners\Purchase\CreateBillCreatedHistory',
'App\Listeners\Purchase\IncreaseNextBillNumber',
],
'App\Events\Purchase\BillReceived' => [
'App\Listeners\Purchase\MarkBillReceived',

View File

@ -3,46 +3,31 @@
namespace App\Traits;
use Akaunting\Money\Money;
use Akaunting\Money\Currency;
trait Currencies
{
public function convert($amount, $from, $to, $rate, $format = false)
public function convert($method, $amount, $from, $to, $rate, $format = false)
{
$money = Money::$from($amount, $format);
$money = Money::$to($amount, $format);
// No need to convert same currency
if ($from == $to) {
return $format ? $money->format() : $money->getAmount();
}
$money = $money->convert(new Currency($to), (double) $rate);
$money = $money->$method((double) $rate);
return $format ? $money->format() : $money->getAmount();
}
public function divide($amount, $code, $rate, $format = false)
{
$money = Money::$code($amount, $format);
$money = $money->divide((double) $rate);
return $format ? $money->format() : $money->getAmount();
}
public function getAmount($with_tax = true)
{
return $with_tax ? $this->amount : (isset($this->amount_without_tax) ? $this->amount_without_tax : $this->amount);
}
public function convertToDefault($amount, $from, $rate, $format = false)
{
return $this->convert($amount, $from, $this->getDefaultCurrency(), $rate, $format);
return $this->convert('divide', $amount, $from, $this->getDefaultCurrency(), $rate, $format);
}
public function convertFromDefault($amount, $to, $rate, $format = false)
{
return $this->convert($amount, $this->getDefaultCurrency(), $to, $rate, $format);
return $this->convert('multiply', $amount, $this->getDefaultCurrency(), $to, $rate, $format);
}
public function getAmountConvertedToDefault($format = false, $with_tax = true)
@ -55,18 +40,13 @@ trait Currencies
return $this->convertFromDefault($this->getAmount($with_tax), $this->currency_code, $this->currency_rate, $format);
}
public function getAmountConvertedFromCustomDefault($format = false, $with_tax = true)
public function getAmount($with_tax = true)
{
return $this->convert($this->getAmount($with_tax), $this->default_currency_code, $this->currency_code, $this->currency_rate, $format);
return $with_tax ? $this->amount : (isset($this->amount_without_tax) ? $this->amount_without_tax : $this->amount);
}
public function getAmountDivided($format = false, $with_tax = true)
public function getDefaultCurrency()
{
return $this->divide($this->getAmount($with_tax), $this->currency_code, $this->currency_rate, $format);
}
protected function getDefaultCurrency()
{
return setting('default.currency', 'USD');
return !empty($this->default_currency_code) ? $this->default_currency_code : setting('default.currency', 'USD');
}
}

View File

@ -31,6 +31,35 @@ trait Jobs
return $result;
}
/**
* Dispatch a job to its appropriate handler and return a response array for ajax calls.
*
* @param mixed $job
* @return mixed
*/
public function ajaxDispatch($job)
{
try {
$data = $this->dispatch($job);
$response = [
'success' => true,
'error' => false,
'data' => $data,
'message' => '',
];
} catch(\Exception $e) {
$response = [
'success' => false,
'error' => true,
'data' => null,
'message' => $e->getMessage(),
];
}
return $response;
}
public function getDispatchFunction()
{
$config = config('queue.default');

View File

@ -4,6 +4,33 @@ namespace App\Traits;
trait Purchases
{
/**
* Generate next bill number
*
* @return string
*/
public function getNextBillNumber()
{
$prefix = setting('bill.number_prefix', 'BIL-');
$next = setting('bill.number_next', '1');
$digit = setting('bill.number_digit', '5');
$number = $prefix . str_pad($next, $digit, '0', STR_PAD_LEFT);
return $number;
}
/**
* Increase the next bill number
*/
public function increaseNextBillNumber()
{
$next = setting('bill.number_next', 1) + 1;
setting(['bill.number_next' => $next]);
setting()->save();
}
/**
* Get a collection of bill statuses
*

View File

@ -17,7 +17,7 @@ trait Recurring
}
$frequency = ($request['recurring_frequency'] != 'custom') ? $request['recurring_frequency'] : $request['recurring_custom_frequency'];
$interval = ($request['recurring_frequency'] != 'custom') ? 1 : (int) $request['recurring_interval'];
$interval = (($request['recurring_frequency'] != 'custom') || ($request['recurring_interval'] < 1)) ? 1 : (int) $request['recurring_interval'];
$started_at = $request->get('paid_at') ?: ($request->get('invoiced_at') ?: $request->get('billed_at'));
$this->recurring()->create([
@ -39,7 +39,7 @@ trait Recurring
}
$frequency = ($request['recurring_frequency'] != 'custom') ? $request['recurring_frequency'] : $request['recurring_custom_frequency'];
$interval = ($request['recurring_frequency'] != 'custom') ? 1 : (int) $request['recurring_interval'];
$interval = (($request['recurring_frequency'] != 'custom') || ($request['recurring_interval'] < 1)) ? 1 : (int) $request['recurring_interval'];
$started_at = $request->get('paid_at') ?: ($request->get('invoiced_at') ?: $request->get('billed_at'));
$recurring = $this->recurring();

View File

@ -6,8 +6,8 @@ use Akaunting\Module\Module;
use App\Traits\SiteApi;
use Cache;
use Date;
use GrahamCampbell\Markdown\Facades\Markdown;
use Illuminate\Support\Arr;
use Parsedown;
class Versions
{
@ -27,8 +27,6 @@ class Versions
return $output;
}
$parsedown = new Parsedown();
$releases = json_decode($json);
foreach ($releases as $release) {
@ -46,7 +44,7 @@ class Versions
$output .= '<h2><span class="badge badge-pill badge-success">' . $release->tag_name . '</span></h2>';
$output .= $parsedown->text($release->body);
$output .= Markdown::convertToHtml($release->body);
$output .= '<hr>';
}

View File

@ -15,10 +15,10 @@ class IncomeByCategory extends Widget
public function show()
{
Category::with('income_transacions')->type('income')->each(function ($category) {
Category::with('income_transactions')->type('income')->each(function ($category) {
$amount = 0;
$this->applyFilters($category->income_transacions())->each(function ($transaction) use (&$amount) {
$this->applyFilters($category->income_transactions())->each(function ($transaction) use (&$amount) {
$amount += $transaction->getAmountConvertedToDefault();
});