bank reconciliation
This commit is contained in:
parent
42f6b00485
commit
268a4aa9d5
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 account($account)
|
||||
{
|
||||
return $this->where('account_id', $account);
|
||||
}
|
||||
}
|
316
app/Http/Controllers/Banking/Reconciliations.php
Normal file
316
app/Http/Controllers/Banking/Reconciliations.php
Normal file
@ -0,0 +1,316 @@
|
||||
<?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'))
|
||||
->prepend(trans('general.all_type', ['type' => trans_choice('general.accounts', 2)]), '');
|
||||
|
||||
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 ((basename($model) == 'Invoice') || (basename($model) == '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 ((basename($model[1]) == 'Invoice') || (basename($model[1]) == '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);
|
||||
}
|
||||
}
|
@ -64,43 +64,6 @@ class Bills extends Controller
|
||||
*/
|
||||
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');
|
||||
|
||||
$currencies = Currency::enabled()->orderBy('name')->pluck('name', 'code')->toArray();
|
||||
|
@ -70,43 +70,6 @@ class Invoices extends Controller
|
||||
*/
|
||||
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');
|
||||
|
||||
$currencies = Currency::enabled()->orderBy('name')->pluck('name', 'code')->toArray();
|
||||
|
@ -91,7 +91,7 @@ class AdminMenu
|
||||
}
|
||||
|
||||
// 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) {
|
||||
if ($user->can('read-banking-accounts')) {
|
||||
$sub->url('banking/accounts', trans_choice('general.accounts', 2), 1, $attr);
|
||||
@ -104,6 +104,10 @@ class AdminMenu
|
||||
if ($user->can('read-banking-transactions')) {
|
||||
$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, [
|
||||
'title' => trans('general.banking'),
|
||||
'icon' => 'fa fa-university',
|
||||
|
@ -17,7 +17,7 @@ class DateFormat
|
||||
public function handle($request, Closure $next)
|
||||
{
|
||||
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) {
|
||||
$date = $request->get($field);
|
||||
|
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|amount',
|
||||
];
|
||||
}
|
||||
}
|
@ -29,5 +29,51 @@ class Version130 extends Listener
|
||||
setting(['general.schedule_item_stocks' => '3,5,7']);
|
||||
|
||||
setting()->save();
|
||||
|
||||
$this->updatePermissions();
|
||||
|
||||
// Update database
|
||||
Artisan::call('migrate', ['--force' => true]);
|
||||
}
|
||||
|
||||
protected function updatePermissions()
|
||||
{
|
||||
$permissions = [];
|
||||
|
||||
$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',
|
||||
]);
|
||||
|
||||
// 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;
|
||||
|
||||
use App\Models\Model;
|
||||
use App\Models\Setting\Currency;
|
||||
use App\Traits\Currencies;
|
||||
use App\Traits\DateTime;
|
||||
use App\Traits\Media;
|
||||
@ -22,7 +23,7 @@ class Bill extends Model
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $appends = ['attachment', 'discount'];
|
||||
protected $appends = ['attachment', 'discount', 'paid'];
|
||||
|
||||
protected $dates = ['deleted_at', 'billed_at', 'due_at'];
|
||||
|
||||
@ -199,4 +200,55 @@ class Bill extends Model
|
||||
|
||||
return $percent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the paid amount.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPaidAttribute()
|
||||
{
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Models\Income;
|
||||
|
||||
use App\Models\Model;
|
||||
use App\Models\Setting\Currency;
|
||||
use App\Traits\Currencies;
|
||||
use App\Traits\DateTime;
|
||||
use App\Traits\Incomes;
|
||||
@ -23,7 +24,7 @@ class Invoice extends Model
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $appends = ['attachment', 'discount'];
|
||||
protected $appends = ['attachment', 'discount', 'paid'];
|
||||
|
||||
protected $dates = ['deleted_at', 'invoiced_at', 'due_at'];
|
||||
|
||||
@ -56,6 +57,8 @@ class Invoice extends Model
|
||||
'notes' => 2,
|
||||
];
|
||||
|
||||
protected $reconciled_amount = [];
|
||||
|
||||
/**
|
||||
* Clonable relationships.
|
||||
*
|
||||
@ -201,4 +204,55 @@ class Invoice extends Model
|
||||
|
||||
return $percent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the paid amount.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPaidAttribute()
|
||||
{
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
@ -115,4 +115,16 @@ class Model extends Eloquent
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class AddReconciledColumn extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('bill_payments', function ($table) {
|
||||
$table->boolean('reconciled')->default(0);
|
||||
});
|
||||
|
||||
Schema::table('invoice_payments', function ($table) {
|
||||
$table->boolean('reconciled')->default(0);
|
||||
});
|
||||
|
||||
Schema::table('payments', function ($table) {
|
||||
$table->boolean('reconciled')->default(0);
|
||||
});
|
||||
|
||||
Schema::table('revenues', function ($table) {
|
||||
$table->boolean('reconciled')->default(0);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('bill_payments', function ($table) {
|
||||
$table->dropColumn('reconciled');
|
||||
});
|
||||
|
||||
Schema::table('invoice_payments', function ($table) {
|
||||
$table->dropColumn('reconciled');
|
||||
});
|
||||
|
||||
Schema::table('payments', function ($table) {
|
||||
$table->dropColumn('reconciled');
|
||||
});
|
||||
|
||||
Schema::table('revenues', function ($table) {
|
||||
$table->dropColumn('reconciled');
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class CreateReconciliationsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('reconciliations', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('company_id');
|
||||
$table->integer('account_id');
|
||||
$table->dateTime('started_at');
|
||||
$table->dateTime('ended_at');
|
||||
$table->double('closing_balance', 15, 4)->default('0.0000');
|
||||
$table->boolean('reconciled');
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
|
||||
$table->index('company_id');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::drop('reconciliations');
|
||||
}
|
||||
}
|
3
public/css/app.css
vendored
3
public/css/app.css
vendored
@ -515,6 +515,9 @@ ul.add-new.nav.navbar-nav.pull-left {
|
||||
.amount-space {
|
||||
padding-right: 30px !important;
|
||||
}
|
||||
.amount-space-left {
|
||||
padding-left: 30px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.text-disabled {
|
||||
|
@ -38,6 +38,10 @@ return [
|
||||
'numbers' => 'Number|Numbers',
|
||||
'statuses' => 'Status|Statuses',
|
||||
'others' => 'Other|Others',
|
||||
'contacts' => 'Contact|Contacts',
|
||||
'reconciliations' => 'Reconciliation|Reconciliations',
|
||||
'deposits' => 'Deposit|Deposits',
|
||||
'withdrawals' => 'Withdrawal|Withdrawals',
|
||||
|
||||
'dashboard' => 'Dashboard',
|
||||
'banking' => 'Banking',
|
||||
@ -106,6 +110,13 @@ return [
|
||||
'disable' => 'Disable',
|
||||
'select_all' => 'Select All',
|
||||
'unselect_all' => 'Unselect All',
|
||||
'create_date' => 'Create Date',
|
||||
'period' => 'Period',
|
||||
'start' => 'Start',
|
||||
'end' => 'End',
|
||||
'clear' => 'Clear',
|
||||
'difference' => 'Difference',
|
||||
|
||||
'title' => [
|
||||
'new' => 'New :type',
|
||||
'edit' => 'Edit :type',
|
||||
|
14
resources/lang/en-GB/reconciliations.php
Normal file
14
resources/lang/en-GB/reconciliations.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
'reconcile' => 'Reconcile',
|
||||
'reconciled' => 'Reconciled',
|
||||
'closing_balance' => 'Closing Balance',
|
||||
'unreconciled' => 'Unreconciled',
|
||||
'list_transactions' => 'List Transactions',
|
||||
'start_date' => 'Start Date',
|
||||
'end_date' => 'End Date',
|
||||
'cleared_amount' => 'Cleared Amount',
|
||||
|
||||
];
|
@ -41,7 +41,7 @@
|
||||
<tbody>
|
||||
@foreach($accounts as $item)
|
||||
<tr>
|
||||
<td><a href="{{ url('banking/accounts/' . $item->id . '/edit') }}">{{ $item->name }}</a></td>
|
||||
<td><a href="{{ route('accounts.edit', $item->id) }}">{{ $item->name }}</a></td>
|
||||
<td class="hidden-xs">{{ $item->number }}</td>
|
||||
<td class="text-right amount-space">@money($item->balance, $item->currency_code, true)</td>
|
||||
<td class="hidden-xs">
|
||||
@ -57,7 +57,7 @@
|
||||
<i class="fa fa-ellipsis-h"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-right">
|
||||
<li><a href="{{ url('banking/accounts/' . $item->id . '/edit') }}">{{ trans('general.edit') }}</a></li>
|
||||
<li><a href="{{ route('accounts.edit', $item->id) }}">{{ trans('general.edit') }}</a></li>
|
||||
@if ($item->enabled)
|
||||
<li><a href="{{ route('accounts.disable', $item->id) }}">{{ trans('general.disable') }}</a></li>
|
||||
@else
|
||||
|
226
resources/views/banking/reconciliations/create.blade.php
Normal file
226
resources/views/banking/reconciliations/create.blade.php
Normal file
@ -0,0 +1,226 @@
|
||||
@extends('layouts.admin')
|
||||
|
||||
@section('title', trans('general.title.new', ['type' => trans_choice('general.reconciliations', 1)]))
|
||||
|
||||
@section('content')
|
||||
<div class="row">
|
||||
{!! Form::open(['url' => 'banking/reconciliations/create', 'role' => 'form', 'method' => 'GET']) !!}
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="box box-success">
|
||||
<div class="box-body">
|
||||
{{ Form::textGroup('started_at', trans('reconciliations.start_date'), 'calendar',['id' => 'started_at', 'class' => 'form-control', 'required' => 'required', 'data-inputmask' => '\'alias\': \'yyyy-mm-dd\'', 'data-mask' => '', 'autocomplete' => 'off'], request('started_at'), 'col-md-3') }}
|
||||
|
||||
{{ Form::textGroup('ended_at', trans('reconciliations.end_date'), 'calendar',['id' => 'ended_at', 'class' => 'form-control', 'required' => 'required', 'data-inputmask' => '\'alias\': \'yyyy-mm-dd\'', 'data-mask' => '', 'autocomplete' => 'off'], request('started_at'), 'col-md-3') }}
|
||||
|
||||
{{ Form::textGroup('closing_balance', trans('reconciliations.closing_balance'), 'money', ['required' => 'required', 'autofocus' => 'autofocus'], '0', 'col-md-2') }}
|
||||
|
||||
{{ Form::selectGroup('account_id', trans_choice('general.accounts', 1), 'university', $accounts, request('account_id', setting('general.default_account')), ['required' => 'required'], 'col-md-2') }}
|
||||
|
||||
<div class="form-group col-md-2">
|
||||
<div class="input-group" style="margin-top: 25px;">
|
||||
{!! Form::button('<span class="fa fa-list"></span> ' . trans('reconciliations.list_transactions'), ['type' => 'submit', 'class' => 'btn btn-success']) !!}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.box-body -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!! Form::close() !!}
|
||||
|
||||
<div class="col-md-12">
|
||||
<div class="box box-success">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">{{ trans_choice('general.transactions', 2) }}</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
{!! Form::open(['url' => 'banking/reconciliations', 'role' => 'form', 'class' => 'form-loading-button', 'id' => 'form-reconciliations']) !!}
|
||||
|
||||
{{ Form::hidden('account_id', $account->id) }}
|
||||
{{ Form::hidden('currency_code', $currency->code, ['id' => 'currency_code']) }}
|
||||
{{ Form::hidden('opening_balance', $opening_balance, ['id' => 'opening_balance']) }}
|
||||
{{ Form::hidden('closing_balance', request('closing_balance', '0'), ['id' => 'closing_balance']) }}
|
||||
{{ Form::hidden('started_at', request('started_at')) }}
|
||||
{{ Form::hidden('ended_at', request('ended_at')) }}
|
||||
{{ Form::hidden('reconcile', '0', ['id' => 'hidden-reconcile']) }}
|
||||
<div class="table table-responsive">
|
||||
<table class="table table-striped table-hover" id="tbl-transactions">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-md-2">{{ trans('general.date') }}</th>
|
||||
<th class="col-md-3">{{ trans('general.description') }}</th>
|
||||
<th class="col-md-2">{{ trans_choice('general.contacts', 1) }}</th>
|
||||
<th class="col-md-2 text-right">{{ trans_choice('general.deposits', 1) }}</th>
|
||||
<th class="col-md-2 text-right">{{ trans_choice('general.withdrawals', 1) }}</th>
|
||||
<th class="col-md-1 text-right">{{ trans('general.clear') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($transactions as $item)
|
||||
<tr>
|
||||
<td>{{ Date::parse($item->paid_at)->format($date_format) }}</td>
|
||||
<td>{{ $item->description }}</td>
|
||||
<td>@if (!empty($item->contact)) {{ $item->contact->name }} @else {{ trans('general.na') }}@endif</td>
|
||||
@if ((basename($item->model) == 'Invoice') || (basename($item->model) == 'Revenue'))
|
||||
<td class="text-right">@money($item->amount, $item->currency_code, true)</td>
|
||||
<td> </td>
|
||||
@else
|
||||
<td> </td>
|
||||
<td class="text-right">@money($item->amount, $item->currency_code, true)</td>
|
||||
@endif
|
||||
<td class="text-right">{{ Form::checkbox('transactions['. $item->id . '_'. $item->model . ']', $item->amount, $item->reconciled) }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
@if ($transactions->count())
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th class="text-right">{{ trans('reconciliations.closing_balance') }}:</th>
|
||||
<td id="closing-balance" class="col-md-1 text-right">@money(request('closing_balance', '0'), $account->currency_code, true)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="text-right">{{ trans('reconciliations.cleared_amount') }}:</th>
|
||||
<td id="cleared-amount" class="col-md-1 text-right">@money('0', $account->currency_code, true)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="text-right">{{ trans('general.difference') }}:</th>
|
||||
<td id="difference" class="col-md-1 text-right">@money('0', $account->currency_code, true)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
@if ($transactions->count())
|
||||
<div class="form-group no-margin">
|
||||
{!! Form::button('<span class="fa fa-save"></span> ' . trans('general.save'), ['type' => 'submit', 'class' => 'btn btn-default button-submit', 'data-loading-text' => trans('general.loading')]) !!}
|
||||
{!! Form::button('<span class="fa fa-check"></span> ' . trans('reconciliations.reconcile'), ['type' => 'button', 'id' => 'button-reconcile', 'class' => 'btn btn-success button-submit', 'data-loading-text' => trans('general.loading'), 'disabled' => 'disabled']) !!}
|
||||
<a href="{{ route('reconciliations.index') }}" class="btn btn-default"><span class="fa fa-times-circle"></span> {{ trans('general.cancel') }}</a>
|
||||
</div>
|
||||
@else
|
||||
{{ trans('general.no_records') }}
|
||||
@endif
|
||||
</div>
|
||||
{!! Form::close() !!}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('js')
|
||||
<script src="{{ asset('vendor/almasaeed2010/adminlte/plugins/datepicker/bootstrap-datepicker.js') }}"></script>
|
||||
<script src="{{ asset('vendor/almasaeed2010/adminlte/plugins/datepicker/locales/bootstrap-datepicker.' . language()->getShortCode() . '.js') }}"></script>
|
||||
@endpush
|
||||
|
||||
@push('css')
|
||||
<link rel="stylesheet" href="{{ asset('vendor/almasaeed2010/adminlte/plugins/datepicker/datepicker3.css') }}">
|
||||
@endpush
|
||||
|
||||
@push('scripts')
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){
|
||||
$("#closing_balance").maskMoney({
|
||||
thousands : '{{ $currency->thousands_separator }}',
|
||||
decimal : '{{ $currency->decimal_mark }}',
|
||||
precision : {{ $currency->precision }},
|
||||
allowZero : true,
|
||||
@if($currency->symbol_first)
|
||||
prefix : '{{ $currency->symbol }}'
|
||||
@else
|
||||
suffix : '{{ $currency->symbol }}'
|
||||
@endif
|
||||
});
|
||||
|
||||
$("#account_id").select2({
|
||||
placeholder: "{{ trans('general.form.select.field', ['field' => trans_choice('general.accounts', 1)]) }}"
|
||||
});
|
||||
|
||||
//Date picker
|
||||
$('#started_at').datepicker({
|
||||
format: 'yyyy-mm-dd',
|
||||
todayBtn: 'linked',
|
||||
weekStart: 1,
|
||||
autoclose: true,
|
||||
language: '{{ language()->getShortCode() }}'
|
||||
});
|
||||
|
||||
$('#ended_at').datepicker({
|
||||
format: 'yyyy-mm-dd',
|
||||
todayBtn: 'linked',
|
||||
weekStart: 1,
|
||||
autoclose: true,
|
||||
language: '{{ language()->getShortCode() }}'
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on('change', '#account_id', function (e) {
|
||||
$.ajax({
|
||||
url: '{{ url("banking/accounts/currency") }}',
|
||||
type: 'GET',
|
||||
dataType: 'JSON',
|
||||
data: 'account_id=' + $(this).val(),
|
||||
success: function(data) {
|
||||
$('#currency_code').val(data.currency_code);
|
||||
|
||||
amount = $('#closing_balance').maskMoney('unmasked')[0];
|
||||
|
||||
$("#closing_balance").maskMoney({
|
||||
thousands : data.thousands_separator,
|
||||
decimal : data.decimal_mark,
|
||||
precision : data.precision,
|
||||
allowZero : true,
|
||||
prefix : (data.symbol_first) ? data.symbol : '',
|
||||
suffix : (data.symbol_first) ? '' : data.symbol
|
||||
});
|
||||
|
||||
$('#closing_balance').val(amount);
|
||||
|
||||
$('#closing_balance').trigger('focus');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(document).ready(function(){
|
||||
$('#tbl-transactions input[type="checkbox"]').trigger('change');
|
||||
});
|
||||
|
||||
$(document).on('change', '#tbl-transactions input[type="checkbox"]', function (e) {
|
||||
amount = $('#closing_balance').maskMoney('unmasked')[0];
|
||||
|
||||
$('#form-reconciliations #closing_balance').val(amount);
|
||||
|
||||
$.ajax({
|
||||
url: '{{ url("banking/reconciliations/calculate") }}',
|
||||
type: 'POST',
|
||||
dataType: 'JSON',
|
||||
data: $('#form-reconciliations').serialize(),
|
||||
headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' },
|
||||
success: function(data) {
|
||||
if (data) {
|
||||
if (data.difference_raw != 0) {
|
||||
$('#button-reconcile').attr('disabled','disabled');
|
||||
$('#difference').css('background-color', '#f2dede');
|
||||
} else {
|
||||
$('#button-reconcile').removeAttr('disabled');
|
||||
$('#difference').css('background-color', '#d0e9c6');
|
||||
}
|
||||
|
||||
$('#closing-balance').html(data.closing_balance);
|
||||
$('#cleared-amount').html(data.cleared_amount);
|
||||
$('#difference').html(data.difference);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on('click', '#button-reconcile', function (e) {
|
||||
$('#hidden-reconcile').val(1);
|
||||
|
||||
$('#form-reconciliations').submit();
|
||||
});
|
||||
</script>
|
||||
@endpush
|
128
resources/views/banking/reconciliations/edit.blade.php
Normal file
128
resources/views/banking/reconciliations/edit.blade.php
Normal file
@ -0,0 +1,128 @@
|
||||
@extends('layouts.admin')
|
||||
|
||||
@section('title', trans('general.title.edit', ['type' => trans_choice('general.reconciliations', 1)]))
|
||||
|
||||
@section('content')
|
||||
<div class="box box-success">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">{{ trans_choice('general.transactions', 2) }}</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
{!! Form::model($reconciliation, [
|
||||
'method' => 'PATCH',
|
||||
'url' => ['banking/reconciliations', $reconciliation->id],
|
||||
'role' => 'form',
|
||||
'id' => 'form-reconciliations',
|
||||
'class' => 'form-loading-button'
|
||||
]) !!}
|
||||
|
||||
{{ Form::hidden('account_id', $account->id) }}
|
||||
{{ Form::hidden('currency_code', $currency->code, ['id' => 'currency_code']) }}
|
||||
{{ Form::hidden('opening_balance', $opening_balance, ['id' => 'opening_balance']) }}
|
||||
{{ Form::hidden('closing_balance', $reconciliation->closing_balance, ['id' => 'closing_balance']) }}
|
||||
{{ Form::hidden('started_at', $reconciliation->started_at) }}
|
||||
{{ Form::hidden('ended_at', $reconciliation->ended_at) }}
|
||||
{{ Form::hidden('reconcile', $reconciliation->reconcile, ['id' => 'hidden-reconcile']) }}
|
||||
<div class="table table-responsive">
|
||||
<table class="table table-striped table-hover" id="tbl-transactions">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-md-2">{{ trans('general.date') }}</th>
|
||||
<th class="col-md-3">{{ trans('general.description') }}</th>
|
||||
<th class="col-md-2">{{ trans_choice('general.contacts', 1) }}</th>
|
||||
<th class="col-md-2 text-right">{{ trans_choice('general.deposits', 1) }}</th>
|
||||
<th class="col-md-2 text-right">{{ trans_choice('general.withdrawals', 1) }}</th>
|
||||
<th class="col-md-1 text-right">{{ trans('general.clear') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($transactions as $item)
|
||||
<tr>
|
||||
<td>{{ Date::parse($item->paid_at)->format($date_format) }}</td>
|
||||
<td>{{ $item->description }}</td>
|
||||
<td>@if (!empty($item->contact)) {{ $item->contact->name }} @else {{ trans('general.na') }}@endif</td>
|
||||
@if ((basename($item->model) == 'Invoice') || (basename($item->model) == 'Revenue'))
|
||||
<td class="text-right">@money($item->amount, $item->currency_code, true)</td>
|
||||
<td> </td>
|
||||
@else
|
||||
<td> </td>
|
||||
<td class="text-right">@money($item->amount, $item->currency_code, true)</td>
|
||||
@endif
|
||||
<td class="text-right">{{ Form::checkbox('transactions['. $item->id . '_'. $item->model . ']', $item->amount, $item->reconciled) }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
@if ($transactions->count())
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th class="text-right">{{ trans('reconciliations.closing_balance') }}:</th>
|
||||
<td id="closing-balance" class="col-md-1 text-right">@money($reconciliation->closing_balance, $account->currency_code, true)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="text-right">{{ trans('reconciliations.cleared_amount') }}:</th>
|
||||
<td id="cleared-amount" class="col-md-1 text-right">@money('0', $account->currency_code, true)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th class="text-right">{{ trans('general.difference') }}:</th>
|
||||
<td id="difference" class="col-md-1 text-right">@money('0', $account->currency_code, true)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
@if ($transactions->count())
|
||||
<div class="form-group no-margin">
|
||||
{!! Form::button('<span class="fa fa-save"></span> ' . trans('general.save'), ['type' => 'submit', 'class' => 'btn btn-default button-submit', 'data-loading-text' => trans('general.loading')]) !!}
|
||||
{!! Form::button('<span class="fa fa-check"></span> ' . trans('reconciliations.reconcile'), ['type' => 'button', 'id' => 'button-reconcile', 'class' => 'btn btn-success button-submit', 'data-loading-text' => trans('general.loading'), 'disabled' => 'disabled']) !!}
|
||||
<a href="{{ route('reconciliations.index') }}" class="btn btn-default"><span class="fa fa-times-circle"></span> {{ trans('general.cancel') }}</a>
|
||||
</div>
|
||||
@else
|
||||
{{ trans('general.no_records') }}
|
||||
@endif
|
||||
</div>
|
||||
{!! Form::close() !!}
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){
|
||||
$('#tbl-transactions input[type="checkbox"]').trigger('change');
|
||||
});
|
||||
|
||||
$(document).on('change', '#tbl-transactions input[type="checkbox"]', function (e) {
|
||||
$.ajax({
|
||||
url: '{{ url("banking/reconciliations/calculate") }}',
|
||||
type: 'POST',
|
||||
dataType: 'JSON',
|
||||
data: $('#form-reconciliations').serialize(),
|
||||
headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' },
|
||||
success: function(data) {
|
||||
if (data) {
|
||||
if (data.difference_raw != 0) {
|
||||
$('#button-reconcile').attr('disabled','disabled');
|
||||
$('#difference').css('background-color', '#f2dede');
|
||||
} else {
|
||||
$('#button-reconcile').removeAttr('disabled');
|
||||
$('#difference').css('background-color', '#d0e9c6');
|
||||
}
|
||||
|
||||
$('#closing-balance').html(data.closing_balance);
|
||||
$('#cleared-amount').html(data.cleared_amount);
|
||||
$('#difference').html(data.difference);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on('click', '#button-reconcile', function (e) {
|
||||
$('#hidden-reconcile').val(1);
|
||||
|
||||
$('#form-reconciliations').submit();
|
||||
});
|
||||
</script>
|
||||
@endpush
|
85
resources/views/banking/reconciliations/index.blade.php
Normal file
85
resources/views/banking/reconciliations/index.blade.php
Normal file
@ -0,0 +1,85 @@
|
||||
@extends('layouts.admin')
|
||||
|
||||
@section('title', trans_choice('general.reconciliations', 2))
|
||||
|
||||
@permission('create-banking-reconciliations')
|
||||
@section('new_button')
|
||||
<span class="new-button"><a href="{{ route('reconciliations.create') }}" class="btn btn-success btn-sm"><span class="fa fa-plus"></span> {{ trans('general.add_new') }}</a></span>
|
||||
@endsection
|
||||
@endpermission
|
||||
|
||||
@section('content')
|
||||
<!-- Default box -->
|
||||
<div class="box box-success">
|
||||
<div class="box-header with-border">
|
||||
{!! Form::open(['url' => 'banking/reconciliations', 'role' => 'form', 'method' => 'GET']) !!}
|
||||
<div class="pull-left">
|
||||
<span class="title-filter hidden-xs">{{ trans('general.search') }}:</span>
|
||||
{!! Form::select('account', $accounts, request('account'), ['class' => 'form-control input-filter input-sm']) !!}
|
||||
{!! Form::button('<span class="fa fa-filter"></span> ' . trans('general.filter'), ['type' => 'submit', 'class' => 'btn btn-sm btn-default btn-filter']) !!}
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<span class="title-filter hidden-xs">{{ trans('general.show') }}:</span>
|
||||
{!! Form::select('limit', $limits, request('limit', setting('general.list_limit', '25')), ['class' => 'form-control input-filter input-sm', 'onchange' => 'this.form.submit()']) !!}
|
||||
</div>
|
||||
{!! Form::close() !!}
|
||||
</div>
|
||||
<!-- /.box-header -->
|
||||
|
||||
<div class="box-body">
|
||||
<div class="table table-responsive">
|
||||
<table class="table table-striped table-hover" id="tbl-reconciliations">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-md-2">@sortablelink('created_at', trans('general.create_date'))</th>
|
||||
<th class="col-md-3">@sortablelink('account_id', trans_choice('general.accounts', 1))</th>
|
||||
<th class="col-md-3 hidden-xs">{{ trans('general.period') }}</th>
|
||||
<th class="col-md-2 text-right amount-space">@sortablelink('closing_balance', trans('reconciliations.closing_balance'))</th>
|
||||
<th class="col-md-1 hidden-xs">@sortablelink('enabled', trans_choice('general.statuses', 1))</th>
|
||||
<th class="col-md-1 text-center">{{ trans('general.actions') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($reconciliations as $item)
|
||||
<tr>
|
||||
<td><a href="{{ route('reconciliations.edit', $item->id) }}">{{ Date::parse($item->created_at)->format($date_format) }}</a></td>
|
||||
<td>{{ $item->account->name }}</td>
|
||||
<td class="hidden-xs">{{ Date::parse($item->started_at)->format($date_format) }} - {{ Date::parse($item->ended_at)->format($date_format) }}</td>
|
||||
<td class="text-right amount-space">@money($item->closing_balance, $item->account->currency_code, true)</td>
|
||||
<td class="hidden-xs">
|
||||
@if ($item->reconciled)
|
||||
<span class="label label-success">{{ trans('reconciliations.reconciled') }}</span>
|
||||
@else
|
||||
<span class="label label-danger">{{ trans('reconciliations.unreconciled') }}</span>
|
||||
@endif
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" data-toggle-position="left" aria-expanded="false">
|
||||
<i class="fa fa-ellipsis-h"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-right">
|
||||
<li><a href="{{ route('reconciliations.edit', $item->id) }}">{{ trans('general.edit') }}</a></li>
|
||||
@permission('delete-banking-reconciliations')
|
||||
<li class="divider"></li>
|
||||
<li>{!! Form::deleteLink($item, 'banking/reconciliations') !!}</li>
|
||||
@endpermission
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.box-body -->
|
||||
|
||||
<div class="box-footer">
|
||||
@include('partials.admin.pagination', ['items' => $reconciliations, 'type' => 'reconciliations'])
|
||||
</div>
|
||||
<!-- /.box-footer -->
|
||||
</div>
|
||||
<!-- /.box -->
|
||||
@endsection
|
||||
|
@ -61,14 +61,18 @@
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-right">
|
||||
<li><a href="{{ url('expenses/bills/' . $item->id) }}">{{ trans('general.show') }}</a></li>
|
||||
@if ($item->paid && !$item->reconciled)
|
||||
<li><a href="{{ url('expenses/bills/' . $item->id . '/edit') }}">{{ trans('general.edit') }}</a></li>
|
||||
<li class="divider"></li>
|
||||
@endif
|
||||
@permission('create-expenses-bills')
|
||||
<li><a href="{{ url('expenses/bills/' . $item->id . '/duplicate') }}">{{ trans('general.duplicate') }}</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="{{ url('expenses/bills/' . $item->id . '/duplicate') }}">{{ trans('general.duplicate') }}</a></li>
|
||||
@endpermission
|
||||
@permission('delete-expenses-bills')
|
||||
@if (!$item->reconciled)
|
||||
<li class="divider"></li>
|
||||
<li>{!! Form::deleteLink($item, 'expenses/bills') !!}</li>
|
||||
@endif
|
||||
@endpermission
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -160,9 +160,11 @@
|
||||
|
||||
<div class="box-footer row no-print">
|
||||
<div class="col-xs-12">
|
||||
@if(!$bill->reconciled)
|
||||
<a href="{{ url('expenses/bills/' . $bill->id . '/edit') }}" class="btn btn-default">
|
||||
<i class="fa fa-pencil-square-o"></i> {{ trans('general.edit') }}
|
||||
</a>
|
||||
@endif
|
||||
<a href="{{ url('expenses/bills/' . $bill->id . '/print') }}" target="_blank" class="btn btn-success">
|
||||
<i class="fa fa-print"></i> {{ trans('general.print') }}
|
||||
</a>
|
||||
@ -170,7 +172,9 @@
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="fa fa-chevron-circle-up"></i> {{ trans('general.more_actions') }}</button>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
@if($bill->status->code != 'paid')
|
||||
@if(empty($bill->paid) || ($bill->paid != $bill->amount))
|
||||
<li><a href="#" id="button-payment">{{ trans('bills.add_payment') }}</a></li>
|
||||
@endif
|
||||
@permission('update-expenses-bills')
|
||||
@if($bill->bill_status_code == 'draft')
|
||||
<li><a href="{{ url('expenses/bills/' . $bill->id . '/received') }}">{{ trans('bills.mark_received') }}</a></li>
|
||||
@ -181,9 +185,11 @@
|
||||
<li class="divider"></li>
|
||||
@endif
|
||||
<li><a href="{{ url('expenses/bills/' . $bill->id . '/pdf') }}">{{ trans('bills.download_pdf') }}</a></li>
|
||||
<li class="divider"></li>
|
||||
@permission('delete-expenses-bills')
|
||||
@if(!$bill->reconciled)
|
||||
<li class="divider"></li>
|
||||
<li>{!! Form::deleteLink($bill, 'expenses/bills') !!}</li>
|
||||
@endif
|
||||
@endpermission
|
||||
</ul>
|
||||
</div>
|
||||
@ -276,6 +282,11 @@
|
||||
<td>@money($payment->amount, $payment->currency_code, true)</td>
|
||||
<td>{{ $payment->account->name }}</td>
|
||||
<td>
|
||||
@if ($payment->reconciled)
|
||||
<button type="button" class="btn btn-default btn-xs" data-toggle="tooltip" data-placement="top" title="{{ trans('reconciliations.reconciled') }}">
|
||||
<i class="fa fa-check"></i>
|
||||
</button>
|
||||
@else
|
||||
<a href="{{ url('expenses/bills/' . $payment->id) }}" class="btn btn-info btn-xs hidden"><i class="fa fa-eye" aria-hidden="true"></i> {{ trans('general.show') }}</a>
|
||||
<a href="{{ url('expenses/bills/' . $payment->id . '/edit') }}" class="btn btn-primary btn-xs hidden"><i class="fa fa-pencil-square-o" aria-hidden="true"></i> {{ trans('general.edit') }}</a>
|
||||
{!! Form::open([
|
||||
@ -291,6 +302,7 @@
|
||||
'onclick' => 'confirmDelete("' . '#bill-payment-' . $payment->id . '", "' . trans_choice('general.payments', 2) . '", "' . trans('general.delete_confirm', ['name' => '<strong>' . Date::parse($payment->paid_at)->format($date_format) . ' - ' . money($payment->amount, $payment->currency_code, true) . ' - ' . $payment->account->name . '</strong>', 'type' => strtolower(trans_choice('general.revenues', 1))]) . '", "' . trans('general.cancel') . '", "' . trans('general.delete') . '")'
|
||||
)) !!}
|
||||
{!! Form::close() !!}
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
@ -47,7 +47,11 @@
|
||||
<tbody>
|
||||
@foreach($payments as $item)
|
||||
<tr>
|
||||
@if ($item->reconciled)
|
||||
<td>{{ Date::parse($item->paid_at)->format($date_format) }}</td>
|
||||
@else
|
||||
<td><a href="{{ url('expenses/payments/' . $item->id . '/edit') }}">{{ Date::parse($item->paid_at)->format($date_format) }}</a></td>
|
||||
@endif
|
||||
<td class="text-right amount-space">@money($item->amount, $item->currency_code, true)</td>
|
||||
<td class="hidden-xs">{{ !empty($item->vendor->name) ? $item->vendor->name : trans('general.na') }}</td>
|
||||
<td class="hidden-xs">{{ $item->category->name }}</td>
|
||||
@ -59,14 +63,18 @@
|
||||
<i class="fa fa-ellipsis-h"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-right">
|
||||
@if (!$item->reconciled)
|
||||
<li><a href="{{ url('expenses/payments/' . $item->id . '/edit') }}">{{ trans('general.edit') }}</a></li>
|
||||
@permission('create-expenses-payments')
|
||||
<li class="divider"></li>
|
||||
@endif
|
||||
@permission('create-expenses-payments')
|
||||
<li><a href="{{ url('expenses/payments/' . $item->id . '/duplicate') }}">{{ trans('general.duplicate') }}</a></li>
|
||||
@endpermission
|
||||
@permission('delete-expenses-payments')
|
||||
@if (!$item->reconciled)
|
||||
<li class="divider"></li>
|
||||
<li>{!! Form::deleteLink($item, 'expenses/payments') !!}</li>
|
||||
@endif
|
||||
@endpermission
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -60,14 +60,18 @@
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-right">
|
||||
<li><a href="{{ url('incomes/invoices/' . $item->id) }}">{{ trans('general.show') }}</a></li>
|
||||
@if ($item->paid && !$item->reconciled)
|
||||
<li><a href="{{ url('incomes/invoices/' . $item->id . '/edit') }}">{{ trans('general.edit') }}</a></li>
|
||||
@endif
|
||||
@permission('create-incomes-invoices')
|
||||
<li class="divider"></li>
|
||||
<li><a href="{{ url('incomes/invoices/' . $item->id . '/duplicate') }}">{{ trans('general.duplicate') }}</a></li>
|
||||
@endpermission
|
||||
<li class="divider"></li>
|
||||
@permission('delete-incomes-invoices')
|
||||
@if (!$item->reconciled)
|
||||
<li class="divider"></li>
|
||||
<li>{!! Form::deleteLink($item, 'incomes/invoices') !!}</li>
|
||||
@endif
|
||||
@endpermission
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -162,9 +162,11 @@
|
||||
|
||||
<div class="box-footer row no-print">
|
||||
<div class="col-md-12">
|
||||
@if(!$invoice->reconciled)
|
||||
<a href="{{ url('incomes/invoices/' . $invoice->id . '/edit') }}" class="btn btn-default">
|
||||
<i class="fa fa-pencil-square-o"></i> {{ trans('general.edit') }}
|
||||
</a>
|
||||
@endif
|
||||
<a href="{{ url('incomes/invoices/' . $invoice->id . '/print') }}" target="_blank" class="btn btn-success">
|
||||
<i class="fa fa-print"></i> {{ trans('general.print') }}
|
||||
</a>
|
||||
@ -178,7 +180,7 @@
|
||||
@permission('update-incomes-invoices')
|
||||
<li><a href="{{ url('incomes/invoices/' . $invoice->id . '/pay') }}">{{ trans('invoices.mark_paid') }}</a></li>
|
||||
@endpermission
|
||||
@if(empty($invoice->payments()->count()) || (!empty($invoice->payments()->count()) && $invoice->paid != $invoice->amount))
|
||||
@if(empty($invoice->paid) || ($invoice->paid != $invoice->amount))
|
||||
<li><a href="#" id="button-payment">{{ trans('invoices.add_payment') }}</a></li>
|
||||
@endif
|
||||
<li class="divider"></li>
|
||||
@ -197,9 +199,11 @@
|
||||
@endif
|
||||
<li class="divider"></li>
|
||||
<li><a href="{{ url('incomes/invoices/' . $invoice->id . '/pdf') }}">{{ trans('invoices.download_pdf') }}</a></li>
|
||||
<li class="divider"></li>
|
||||
@permission('delete-incomes-invoices')
|
||||
@if(!$invoice->reconciled)
|
||||
<li class="divider"></li>
|
||||
<li>{!! Form::deleteLink($invoice, 'incomes/invoices') !!}</li>
|
||||
@endif
|
||||
@endpermission
|
||||
</ul>
|
||||
</div>
|
||||
@ -292,6 +296,11 @@
|
||||
<td>@money($payment->amount, $payment->currency_code, true)</td>
|
||||
<td>{{ $payment->account->name }}</td>
|
||||
<td>
|
||||
@if ($payment->reconciled)
|
||||
<button type="button" class="btn btn-default btn-xs">
|
||||
<i class="fa fa-check"></i> {{ trans('reconciliations.reconciled') }}
|
||||
</button>
|
||||
@else
|
||||
<a href="{{ url('incomes/invoices/' . $payment->id . '') }}" class="btn btn-info btn-xs hidden"><i class="fa fa-eye" aria-hidden="true"></i> {{ trans('general.show') }}</a>
|
||||
<a href="{{ url('incomes/revenues/' . $payment->id . '/edit') }}" class="btn btn-primary btn-xs hidden"><i class="fa fa-pencil-square-o" aria-hidden="true"></i> {{ trans('general.edit') }}</a>
|
||||
{!! Form::open([
|
||||
@ -307,6 +316,7 @@
|
||||
'onclick' => 'confirmDelete("' . '#invoice-payment-' . $payment->id . '", "' . trans_choice('general.payments', 2) . '", "' . trans('general.delete_confirm', ['name' => '<strong>' . Date::parse($payment->paid_at)->format($date_format) . ' - ' . money($payment->amount, $payment->currency_code, true) . ' - ' . $payment->account->name . '</strong>', 'type' => strtolower(trans_choice('general.revenues', 1))]) . '", "' . trans('general.cancel') . '", "' . trans('general.delete') . '")'
|
||||
)) !!}
|
||||
{!! Form::close() !!}
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
@ -47,7 +47,11 @@
|
||||
<tbody>
|
||||
@foreach($revenues as $item)
|
||||
<tr>
|
||||
@if ($item->reconciled)
|
||||
<td>{{ Date::parse($item->paid_at)->format($date_format) }}</td>
|
||||
@else
|
||||
<td><a href="{{ url('incomes/revenues/' . $item->id . '/edit') }}">{{ Date::parse($item->paid_at)->format($date_format) }}</a></td>
|
||||
@endif
|
||||
<td class="text-right amount-space">@money($item->amount, $item->currency_code, true)</td>
|
||||
<td class="hidden-xs">{{ !empty($item->customer->name) ? $item->customer->name : trans('general.na') }}</td>
|
||||
<td class="hidden-xs">{{ $item->category->name }}</td>
|
||||
@ -59,14 +63,18 @@
|
||||
<i class="fa fa-ellipsis-h"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-right">
|
||||
@if (!$item->reconciled)
|
||||
<li><a href="{{ url('incomes/revenues/' . $item->id . '/edit') }}">{{ trans('general.edit') }}</a></li>
|
||||
@permission('create-incomes-revenues')
|
||||
<li class="divider"></li>
|
||||
@endif
|
||||
@permission('create-incomes-revenues')
|
||||
<li><a href="{{ url('incomes/revenues/' . $item->id . '/duplicate') }}">{{ trans('general.duplicate') }}</a></li>
|
||||
@endpermission
|
||||
@permission('delete-incomes-revenues')
|
||||
@if (!$item->reconciled)
|
||||
<li class="divider"></li>
|
||||
<li>{!! Form::deleteLink($item, 'incomes/revenues') !!}</li>
|
||||
@endif
|
||||
@endpermission
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -77,6 +77,9 @@
|
||||
@permission('create-banking-transfers')
|
||||
<li><a href="{{ url('banking/transfers/create') }}">{{ trans_choice('general.transfers', 1) }}</a></li>
|
||||
@endpermission
|
||||
@permission('create-banking-reconciliations')
|
||||
<li><a href="{{ url('banking/reconciliations/create') }}">{{ trans_choice('general.reconciliations', 1) }}</a></li>
|
||||
@endpermission
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -106,6 +106,9 @@ Route::group(['middleware' => 'language'], function () {
|
||||
Route::resource('accounts', 'Banking\Accounts', ['middleware' => ['dateformat', 'money']]);
|
||||
Route::resource('transactions', 'Banking\Transactions');
|
||||
Route::resource('transfers', 'Banking\Transfers', ['middleware' => ['dateformat', 'money']]);
|
||||
Route::post('reconciliations/calculate', 'Banking\Reconciliations@calculate')->middleware(['money']);
|
||||
Route::patch('reconciliations/calculate', 'Banking\Reconciliations@calculate')->middleware(['money']);
|
||||
Route::resource('reconciliations', 'Banking\Reconciliations', ['middleware' => ['dateformat', 'money']]);
|
||||
});
|
||||
|
||||
Route::group(['prefix' => 'reports'], function () {
|
||||
|
Loading…
x
Reference in New Issue
Block a user