Merge branch 'akaunting:master' into master

This commit is contained in:
Burak Civan 2022-06-07 09:19:46 +03:00 committed by GitHub
commit f19e107f76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 188 additions and 55 deletions

View File

@ -12,6 +12,7 @@ use App\Http\Requests\Common\Import as ImportRequest;
use App\Imports\Banking\Transactions as Import;
use App\Jobs\Banking\CreateTransaction;
use App\Jobs\Banking\DeleteTransaction;
use App\Jobs\Banking\DuplicateTransaction;
use App\Jobs\Banking\MatchBankingDocumentTransaction;
use App\Jobs\Banking\SplitTransaction;
use App\Jobs\Banking\UpdateTransaction;
@ -139,7 +140,7 @@ class Transactions extends Controller
*/
public function duplicate(Transaction $transaction)
{
$clone = $transaction->duplicate();
$clone = $this->dispatch(new DuplicateTransaction($transaction));
$message = trans('messages.success.duplicated', ['type' => trans_choice('general.transactions', 1)]);

View File

@ -28,6 +28,8 @@ class Neww extends Component
foreach($menu->getItems() as $item) {
if ($this->availableInSearch($item)) {
$this->neww[] = $item;
continue;
}

View File

@ -37,6 +37,8 @@ class Settings extends Component
}
if ($this->availableInSearch($item)) {
$this->settings[] = $item;
continue;
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Jobs\Banking;
use App\Abstracts\Job;
use App\Events\Banking\TransactionCreated;
use App\Models\Banking\Transaction;
class DuplicateTransaction extends Job
{
protected $clone;
public function __construct(Transaction $model)
{
$this->model = $model;
parent::__construct($model);
}
public function handle(): Transaction
{
\DB::transaction(function () {
$this->clone = $this->model->duplicate();
});
event(new TransactionCreated($this->clone, request()));
return $this->clone;
}
}

View File

@ -18,7 +18,7 @@ class Account extends Model
*
* @var array
*/
protected $appends = ['balance'];
protected $appends = ['balance', 'title'];
/**
* Attributes that should be mass-assignable.
@ -89,6 +89,20 @@ class Account extends Model
->select(['accounts.*', 'accounts.opening_balance as balance']);
}
/**
* Get the name with currency.
*
* @return string
*/
public function getTitleAttribute()
{
if ($this->currency->symbol) {
return $this->name . ' (' . $this->currency->symbol . ')';
}
return $this->name;
}
/**
* Get the current balance.
*

View File

@ -54,7 +54,7 @@ class Transfer extends Model
public function expense_transaction()
{
return $this->belongsTo('App\Models\Banking\Transaction', 'expense_transaction_id');
return $this->belongsTo('App\Models\Banking\Transaction', 'expense_transaction_id')->withDefault(['name' => trans('general.na')]);
}
public function expense_account()
@ -70,7 +70,7 @@ class Transfer extends Model
public function income_transaction()
{
return $this->belongsTo('App\Models\Banking\Transaction', 'income_transaction_id');
return $this->belongsTo('App\Models\Banking\Transaction', 'income_transaction_id')->withDefault(['name' => trans('general.na')]);
}
public function income_account()

View File

@ -13,6 +13,22 @@ class Account extends Form
public $accounts;
/** @var bool */
public $hideCurrency;
/** @var string */
public $formGroupClass;
/**
* Create a new component instance.
*
* @return void
*/
public function __construct(bool $hideCurrency = false, string $formGroupClass = 'sm:col-span-3') {
$this->hideCurrency = $hideCurrency;
$this->formGroupClass = $formGroupClass;
}
/**
* Get the view / contents that represent the component.
*
@ -26,7 +42,7 @@ class Account extends Form
$this->path = route('modals.accounts.create');
$this->accounts = Model::enabled()->orderBy('name')->pluck('name', 'id');
$this->accounts = $this->getAccounts();
if (empty($this->selected) && empty($this->getParentData('model'))) {
$this->selected = setting('default.account');
@ -34,4 +50,13 @@ class Account extends Form
return view('components.form.group.account');
}
protected function getAccounts()
{
if ($this->hideCurrency) {
return Model::enabled()->orderBy('name')->pluck('name', 'id');
}
return Model::enabled()->orderBy('name')->get()->pluck('title', 'id');
}
}

View File

@ -532,8 +532,7 @@ export default {
})
.catch(error => {
this.form.loading = false;
console.log(error);
this.form.errors.record(error.response.data.errors);
});
},

View File

@ -585,7 +585,7 @@ const app = new Vue({
this.component = Vue.component('add-new-component', (resolve, reject) => {
resolve({
template: '<div id="dynamic-payment-component"><akaunting-modal-add-new modal-dialog-class="max-w-screen-md" :show="payment.modal" @submit="onSubmit" @cancel="onCancel" :buttons="payment.buttons" :title="payment.title" :is_component=true :message="payment.html"></akaunting-modal-add-new></div>',
template: '<div id="dynamic-payment-component"><akaunting-modal-add-new modal-dialog-class="max-w-md" :show="payment.modal" @submit="onSubmit" @cancel="onCancel" :buttons="payment.buttons" :title="payment.title" :is_component=true :message="payment.html"></akaunting-modal-add-new></div>',
mixins: [
Global

View File

@ -224,6 +224,7 @@ return [
'copied' => 'Copied',
'preview_mode' => 'Preview Mode',
'go_back' => 'Go back to :type',
'validation_error' => 'Validation error',
'card' => [
'cards' => 'Card|Cards',

View File

@ -1,15 +1,23 @@
<div wire:click.stop id="menu-neww">
<div wire:click.stop id="menu-neww" class="relative">
<input type="text" name="neww_keyword" wire:model.debounce.500ms="keyword" placeholder="{{ trans('general.search_placeholder') }}" class="border-t-0 border-l-0 border-r-0 border-b border-gray-300 bg-transparent text-gray-500 text-sm mb-3 focus:outline-none focus:ring-transparent focus:border-purple placeholder-light-gray js-search-action">
{!! menu('neww') !!}
</div>
@if ($keyword)
<button type="button" class="absolute ltr:right-2 rtl:left-2 top-2 clear" wire:click="resetKeyword">
<span class="material-icons text-sm">close</span>
</button>
@endif
@push('scripts_end')
<script type="text/javascript">
window.addEventListener('click', function() {
if (Livewire.components.getComponentsByName('menu.neww')[0].data.neww.length > 0) {
Livewire.emit('resetKeyword');
}
});
</script>
@endpush
@if ($neww)
{!! menu('neww') !!}
@else
<ul class="flex flex-col justify-center">
<li class="text-sm mb-5">
<div class="flex items-start">
<p class="text-black">
{{ trans('notifications.empty') }}
</p>
</div>
</li>
</ul>
@endif
</div>

View File

@ -1,6 +1,12 @@
<div wire:click.stop id="menu-notifications">
<div wire:click.stop id="menu-notifications" class="relative">
<input type="text" name="notification_keyword" wire:model.debounce.500ms="keyword" placeholder="{{ trans('general.search_placeholder') }}" class="border-t-0 border-l-0 border-r-0 border-b border-gray-300 bg-transparent text-gray-500 text-sm mb-3 focus:outline-none focus:ring-transparent focus:border-purple placeholder-light-gray js-search-action">
@if ($keyword)
<button type="button" class="absolute ltr:right-2 rtl:left-2 top-2 clear" wire:click="resetKeyword">
<span class="material-icons text-sm">close</span>
</button>
@endif
@if ($notifications)
<div class="flex justify-end mt-1">
<x-tooltip id="notification-all" placement="right" message="Mark as All Read">
@ -53,12 +59,6 @@
@push('scripts_end')
<script type="text/javascript">
window.addEventListener('click', function() {
if (Livewire.components.getComponentsByName('menu.notifications')[0].data.notifications.length > 0) {
Livewire.emit('resetKeyword');
}
});
window.addEventListener('mark-read', event => {
if (event.detail.type == 'notifications') {
$.notify(event.detail.message, {

View File

@ -1,7 +1,25 @@
<div wire:click.stop id="menu-settings">
<div wire:click.stop id="menu-settings" class="relative">
<input type="text" name="settings_keyword" wire:model.debounce.500ms="keyword" placeholder="{{ trans('general.search_placeholder') }}" class="border-t-0 border-l-0 border-r-0 border-b border-gray-300 bg-transparent text-gray-500 text-sm mb-3 focus:outline-none focus:ring-transparent focus:border-purple placeholder-light-gray js-search-action">
{!! menu('settings') !!}
@if ($keyword)
<button type="button" class="absolute ltr:right-2 rtl:left-2 top-2 clear" wire:click="resetKeyword">
<span class="material-icons text-sm">close</span>
</button>
@endif
@if ($settings)
{!! menu('settings') !!}
@else
<ul class="flex flex-col justify-center">
<li class="text-sm mb-5">
<div class="flex items-start">
<p class="text-black">
{{ trans('notifications.empty') }}
</p>
</div>
</li>
</ul>
@endif
</div>
@push('scripts_start')
@ -9,13 +27,3 @@
var is_settings_menu = {{ $active_menu }};
</script>
@endpush
@push('scripts_end')
<script type="text/javascript">
window.addEventListener('click', function() {
if (Livewire.components.getComponentsByName('menu.settings')[0].data.settings.length > 0) {
Livewire.emit('resetKeyword');
}
});
</script>
@endpush

View File

@ -1,27 +1,70 @@
<x-form id="form-transaction" :route="$route" :model="!empty($transaction) ? $transaction : false">
<base-alert type="warning" v-if="typeof form.response !== 'undefined' && form.response.error" v-html="form.response.message"></base-alert>
<div class="rounded-xl px-5 py-3 mb-5 bg-red-100" v-if="typeof form.response !== 'undefined' && form.response.error">
<p class="text-sm mb-0 text-red-600" v-html="form.response.message"></p>
</div>
<div class="grid sm:grid-cols-6 gap-x-8 gap-y-6 my-3.5">
<x-form.group.date name="paid_at" label="{{ trans('general.date') }}" icon="calendar_today" value="{{ Date::now()->toDateString() }}" show-date-format="{{ company_date_format() }}" date-format="Y-m-d" autocomplete="off" />
<div x-data="{ active: 'general' }">
<div>
<div>
<ul class="grid grid-cols-6">
<li class="relative px-8 text-sm text-black text-center pb-2 cursor-pointer transition-all border-b tabs-link col-span-3"
id="tab-general"
data-id="tab-general"
data-tabs="general"
x-on:click="active = 'general'"
x-bind:class="active != 'general' ? '' : 'active-tabs text-purple border-purple transition-all after:absolute after:w-full after:h-0.5 after:left-0 after:right-0 after:bottom-0 after:bg-purple after:rounded-tl-md after:rounded-tr-md'"
>
{{ trans('general.general') }}
<x-form.group.money name="amount" label="{{ trans('general.amount') }}" value="{{ $document->grand_total }}" autofocus="autofocus" :currency="$currency" dynamicCurrency="currency" />
<span class="invalid-feedback block text-xs text-red whitespace-normal" v-if="form.errors.has('paid_at')||form.errors.has('amount')||form.errors.has('payment_method')||form.errors.has('account_id')">
{{ trans('general.validation_error') }}
</span>
</li>
<x-form.group.account change="onChangePaymentAccount" />
<li class="relative px-8 text-sm text-black text-center pb-2 cursor-pointer transition-all border-b tabs-link col-span-3"
id="tab-other"
data-id="tab-other"
data-tabs="other"
x-on:click="active = 'other'"
x-bind:class="active != 'other' ? '' : 'active-tabs text-purple border-purple transition-all after:absolute after:w-full after:h-0.5 after:left-0 after:right-0 after:bottom-0 after:bg-purple after:rounded-tl-md after:rounded-tr-md'"
>
{{ trans_choice('general.others', 1) }}
<x-form.group.text name="currency" label="{{ trans_choice('general.currencies', 1) }}" value="{{ $document->currency->name }}" not-required disabled />
<span class="invalid-feedback block text-xs text-red whitespace-normal" v-if="form.errors.has('number')||form.errors.has('description')||form.errors.has('recurring')">
{{ trans('general.validation_error') }}
</span>
</li>
</ul>
</div>
</div>
<x-form.group.textarea name="description" label="{{ trans('general.description') }}" rows="3" not-required />
<div id="tab-general" data-tabs-content="general" x-show="active === 'general'">
<div class="grid sm:grid-cols-6 gap-x-8 gap-y-6 my-3.5">
<x-form.group.date name="paid_at" label="{{ trans('general.date') }}" icon="calendar_today" value="{{ Date::now()->toDateString() }}" show-date-format="{{ company_date_format() }}" date-format="Y-m-d" autocomplete="off" form-group-class="col-span-6" />
<x-form.group.payment-method />
<x-form.group.money name="amount" label="{{ trans('general.amount') }}" value="{{ $document->grand_total }}" autofocus="autofocus" :currency="$currency" dynamicCurrency="currency" form-group-class="col-span-6" />
<x-form.group.text name="reference" label="{{ trans('general.reference') }}" not-required />
<x-form.group.payment-method form-group-class="col-span-6"/>
<x-form.input.hidden name="document_id" :value="$document->id" />
<x-form.input.hidden name="category_id" :value="$document->category->id" />
<x-form.input.hidden name="amount" :value="$document->grand_total" />
<x-form.input.hidden name="currency_code" :value="$document->currency_code" />
<x-form.input.hidden name="currency_rate" :value="$document->currency_rate" />
<x-form.input.hidden name="number" :value="$number" />
<x-form.input.hidden name="type" :value="config('type.document.' . $document->type . '.transaction_type')" />
<x-form.group.account change="onChangePaymentAccount" form-group-class="col-span-6" />
</div>
</div>
<div id="tab-other" data-tabs-content="other" x-show="active === 'other'">
<div class="grid sm:grid-cols-6 gap-x-8 gap-y-6 my-3.5">
<x-form.group.textarea name="description" label="{{ trans('general.description') }}" rows="3" not-required form-group-class="col-span-6" />
<x-form.group.text name="number" label="{{ trans_choice('general.numbers', 1) }}" value="{{ $number }}" form-group-class="col-span-6" />
<x-form.group.text name="reference" label="{{ trans('general.reference') }}" not-required form-group-class="col-span-6" />
<x-form.input.hidden name="document_id" :value="$document->id" />
<x-form.input.hidden name="category_id" :value="$document->category->id" />
<x-form.input.hidden name="amount" :value="$document->grand_total" />
<x-form.input.hidden name="currency_code" :value="$document->currency_code" />
<x-form.input.hidden name="currency_rate" :value="$document->currency_rate" />
<x-form.input.hidden name="type" :value="config('type.document.' . $document->type . '.transaction_type')" />
</div>
</div>
</div>
</x-form>