Merge pull request #2304 from sevannerse/CU-1pbthq3_Make-Recurring-Easier-to-Find--Edit_Sevan-Nerse

Make recurring easier to find
This commit is contained in:
Cüneyt Şentürk 2021-11-11 14:22:21 +03:00 committed by GitHub
commit 82ce036771
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 230 additions and 25 deletions

View File

@ -314,6 +314,12 @@ abstract class TransactionShow extends Base
/** @var string */
public $classFooterHistories;
/** @var string */
public $textRecurringType;
/** @var bool */
public $hideRecurringMessage;
/**
* Create a new component instance.
*
@ -346,7 +352,7 @@ abstract class TransactionShow extends Base
bool $hideAttachment = false, $attachment = [],
bool $hideFooter = false, bool $hideFooterHistories = false, $histories = [],
string $textHistories = '', string $classFooterHistories = ''
string $textHistories = '', string $classFooterHistories = '', string $textRecurringType = '', bool $hideRecurringMessage = false
) {
$this->type = $type;
$this->transaction = $transaction;
@ -354,6 +360,8 @@ abstract class TransactionShow extends Base
$this->logo = $this->getLogo($logo);
$this->payment_methods = ($payment_methods) ?: Modules::getPaymentMethods('all');
$this->date_format = $this->getCompanyDateFormat();
$this->textRecurringType = $this->getTextRecurringType($type, $textRecurringType);
$this->hideRecurringMessage = $hideRecurringMessage;
// Navbar Hide
$this->hideButtonAddNew = $hideButtonAddNew;
@ -1276,4 +1284,21 @@ abstract class TransactionShow extends Base
return 'col-sm-6 col-md-6 col-lg-6 col-xl-6';
}
protected function getTextRecurringType($type, $textRecurringType)
{
if (!empty($textRecurringType)) {
return $textRecurringType;
}
$default_key = config('type.' . $type . '.translation.prefix');
$translation = $this->getTextFromConfig($type, 'recurring_tye', $default_key);
if (!empty($translation)) {
return $translation;
}
return 'general.revenues';
}
}

View File

@ -32,6 +32,8 @@ class Transaction extends FormRequest
'category_id' => 'required|integer',
'payment_method' => 'required|string',
'attachment.*' => $attachment,
'recurring_count' => 'gte:0',
'recurring_interval' => 'exclude_unless:recurring_frequency,custom|gt:0',
];
}

View File

@ -61,6 +61,8 @@ class Document extends FormRequest
'category_id' => 'required|integer',
'company_logo' => $company_logo,
'attachment.*' => $attachment,
'recurring_count' => 'gte:0',
'recurring_interval' => 'exclude_unless:recurring_frequency,custom|gt:0',
];
$items = $this->request->get('items');

View File

@ -126,6 +126,11 @@ class Transaction extends Model
return $this->belongsTo('App\Models\Auth\User', 'contact_id', 'id');
}
public function parent()
{
return $this->belongsTo('App\Models\Banking\Transaction', 'parent_id');
}
/**
* Scope to only include contacts of a given type.
*

View File

@ -144,6 +144,11 @@ class Document extends Model
return $this->totals()->orderBy('sort_order');
}
public function parent()
{
return $this->belongsTo('App\Models\Document\Document', 'parent_id');
}
public function scopeLatest(Builder $query)
{
return $query->orderBy('issued_at', 'desc');

View File

@ -89,12 +89,12 @@ class SearchString extends Component
$column = $options['key'];
}
if (isset($options['relationship'])) {
if (isset($options['foreign_key'])) {
if (isset($options['relationship']) && isset($options['foreign_key']) && !empty($options['foreign_key'])) {
$column .= '.' . $options['foreign_key'];
} else {
$column .= '.id';
}
if (isset($options['relationship']) && !isset($options['foreign_key'])) {
$column .= '.id';
}
return $column;

View File

@ -112,6 +112,12 @@ return [
'route' => 'categories.index'
],
'parent_id',
'recurring' => [
'key' => 'recurring',
'foreign_key' => '',
'relationship' => true,
'boolean' => true,
]
],
],
@ -205,6 +211,11 @@ return [
'route' => 'categories.index'
],
'parent_id',
'recurring' => [
'key' => 'recurring',
'relationship' => true,
'boolean' => true,
]
],
],
@ -243,6 +254,12 @@ return [
'route' => ['categories.index', 'search=type:expense']
],
'parent_id',
'recurring' => [
'key' => 'recurring',
'foreign_key' => '',
'relationship' => true,
'boolean' => true,
]
],
],
@ -269,6 +286,12 @@ return [
'route' => ['categories.index', 'search=type:expense']
],
'parent_id',
'recurring' => [
'key' => 'recurring',
'foreign_key' => '',
'relationship' => true,
'boolean' => true,
]
],
],
@ -308,6 +331,12 @@ return [
'route' => ['categories.index', 'search=type:income']
],
'parent_id',
'recurring' => [
'key' => 'recurring',
'foreign_key' => '',
'relationship' => true,
'boolean' => true,
]
],
],
@ -334,6 +363,12 @@ return [
'route' => ['categories.index', 'search=type:income']
],
'parent_id',
'recurring' => [
'key' => 'recurring',
'foreign_key' => '',
'relationship' => true,
'boolean' => true,
]
],
],

View File

@ -4,6 +4,15 @@
name="recurring_frequency"
:class="frequencyClasses"
:error="frequencyError">
<template slot="label">
<label v-if="title" :class="labelClasses">
{{ title }}
<el-tooltip class="item" effect="dark" placement="top-start">
<div slot="content" v-html="tooltip"></div>
<i class="far fa-question-circle fa-xs" style="vertical-align: top;"></i>
</el-tooltip>
</label>
</template>
<el-select v-model="recurring_frequency" @input="change" filterable
:placeholder="placeholder">
<template slot="prefix">
@ -20,21 +29,19 @@
</el-select>
</base-input>
<base-input :label="''"
<base-input :label="titleInterval"
name="recurring_interval"
type="number"
:value="0"
@input="change"
class="recurring-single"
:class="invertalClasses"
:error="intervalError"
v-model="recurring_interval"
>
</base-input>
<base-input :label="''"
<base-input :label="titleFrequency"
name="recurring_custom_frequency"
class="recurring-single"
:class="customFrequencyClasses"
:error="customFrequencyError">
<el-select v-model="recurring_custom_frequency" @input="change" filterable
@ -47,12 +54,11 @@
</el-select>
</base-input>
<base-input :label="''"
<base-input :label="titleCount"
name="recurring_count"
type="number"
:value="0"
@input="change"
class="recurring-single"
:class="countClasses"
:error="countError"
v-model="recurring_count">
@ -61,7 +67,7 @@
</template>
<script>
import { Select, Option } from 'element-ui'
import { Select, Option, Tooltip } from 'element-ui'
export default {
name: 'akaunting-recurring',
@ -69,6 +75,7 @@ export default {
components: {
[Select.name]: Select,
[Option.name]: Option,
[Tooltip.name]: Tooltip,
},
props: {
@ -77,6 +84,26 @@ export default {
default: '',
description: "Modal header title"
},
titleInterval: {
type: String,
default: '',
description: "Title of interval"
},
titleFrequency: {
type: String,
default: '',
description: "Title of frequency"
},
titleCount: {
type: String,
default: '',
description: "Title of count"
},
tooltip: {
type: String,
default: '',
description: "Tooltip message"
},
placeholder: {
type: String,
default: '',
@ -112,7 +139,12 @@ export default {
icon: {
type: String,
description: "Prepend icon (left)"
}
},
labelClasses: {
type: String,
description: "Input label css classes",
default: "form-control-label"
},
},
data() {

View File

@ -3,6 +3,9 @@
return [
'recurring' => 'Recurring',
'interval' => 'Interval',
'frequency' => 'Frequency',
'count' => 'Count',
'every' => 'Every',
'period' => 'Period',
'times' => 'Times',
@ -16,5 +19,7 @@ return [
'months' => 'Month(s)',
'years' => 'Year(s)',
'message' => 'This is a recurring :type and the next :type will be automatically generated on :date',
'message_parent' => 'This :type was automatically generated from :link',
'tooltip' => 'Besides the predefined periods, possible to adjust customized periods regarding the requirements. <br><b>Tip:</b> The count must be set to zero up to recur infinitely.',
];

View File

@ -15,6 +15,7 @@ return [
'reconciled' => 'Reconciled',
'expense_account' => 'From Account',
'income_account' => 'To Account',
'recurring' => 'Recurring',
],
];

View File

@ -20,4 +20,25 @@
</div>
</div>
@endif
@if ($document->parent)
<div class="row">
<div class="col-sm-12">
<div class="alert alert-info fade show" role="alert">
<div class="d-flex">
@stack('recurring_parent_message_head_start')
<h5 class="mt-0 text-white"><strong>{{ trans('recurring.recurring') }}</strong></h5>
@stack('recurring_parent_message_head_end')
</div>
@stack('recurring_parent_message_body_start')
<p class="text-sm lh-160 mb-0">{!! trans('recurring.message_parent', [
'type' => mb_strtolower(trans_choice($textRecurringType, 1)),
'link' => '<a href="' . route(mb_strtolower(trans_choice($textRecurringType, 2)) . '.show', $document->parent->id) . '"><u>' . $document->parent->document_number . '</u></a>'
]) !!}
</p>
@stack('recurring_parent_message_body_end')
</div>
</div>
</div>
@endif
@stack('recurring_message_end')

View File

@ -22,6 +22,16 @@
@endif
@stack('content_header_end')
@stack('recurring_message_start')
@if (!$hideRecurringMessage)
<x-transactions.show.recurring-message
type="{{ $type }}"
:transaction="$transaction"
text-recurring-type="{{ $textRecurringType }}"
/>
@endif
@stack('recurring_message_end')
@stack('transaction_start')
<x-transactions.show.transaction
type="{{ $type }}"

View File

@ -0,0 +1,44 @@
@stack('recurring_message_start')
@if (($recurring = $transaction->recurring) && ($next = $recurring->getNextRecurring()))
<div class="row">
<div class="col-sm-12">
<div class="alert alert-info fade show" role="alert">
<div class="d-flex">
@stack('recurring_message_head_start')
<h5 class="mt-0 text-white"><strong>{{ trans('recurring.recurring') }}</strong></h5>
@stack('recurring_message_head_end')
</div>
@stack('recurring_message_body_start')
<p class="text-sm lh-160 mb-0">{{ trans('recurring.message', [
'type' => mb_strtolower(trans_choice($textRecurringType, 1)),
'date' => $next->format($date_format)
]) }}
</p>
@stack('recurring_message_body_end')
</div>
</div>
</div>
@endif
@if ($transaction->parent)
<div class="row">
<div class="col-sm-12">
<div class="alert alert-info fade show" role="alert">
<div class="d-flex">
@stack('recurring_parent_message_head_start')
<h5 class="mt-0 text-white"><strong>{{ trans('recurring.recurring') }}</strong></h5>
@stack('recurring_parent_message_head_end')
</div>
@stack('recurring_parent_message_body_start')
<p class="text-sm lh-160 mb-0">{!! trans('recurring.message_parent', [
'type' => mb_strtolower(trans_choice($textRecurringType, 1)),
'link' => '<a href="' . route(mb_strtolower(trans_choice($textRecurringType, 2)) . '.show', $transaction->parent->id) . '"><u>' . trans_choice($textRecurringType, 1) . '#' . $transaction->parent->id . '</u></a>'
]) !!}
</p>
@stack('recurring_parent_message_body_end')
</div>
</div>
</div>
@endif
@stack('recurring_message_end')

View File

@ -18,6 +18,10 @@
<a href="{{ route($routeButtonShow , $item->id) }}">{{ $item->document_number }}</a>
@endif
@if ($item->recurring)
<i class="fas fa-redo-alt fa-xs" title="{{ trans('recurring.recurring') }}"></i>
@endif
@stack('document_number_td_inside_end')
</td>
@endif

View File

@ -17,6 +17,10 @@
<akaunting-recurring
:form-classes="[{'has-error': form.errors.get('recurring_frequency')}, '{{ $col }}']"
title="{{ trans('recurring.recurring') }}"
title-interval="{{ trans('recurring.interval') }}"
title-frequency="{{ trans('recurring.frequency') }}"
title-count="{{ trans('recurring.count') }}"
tooltip="{{ trans('recurring.tooltip') }}"
placeholder="{{ trans('general.form.select.field', ['field' => trans('recurring.recurring')]) }}"
:frequency-options="{{ json_encode($recurring_frequencies) }}"

View File

@ -46,11 +46,16 @@
@foreach($payments as $item)
<tr class="row align-items-center border-top-1">
<td class="col-sm-2 col-md-2 col-lg-1 col-xl-1 d-none d-sm-block">{{ Form::bulkActionGroup($item->id, $item->contact->name) }}</td>
<td class="col-xs-4 col-sm-4 col-md-3 col-lg-1 col-xl-1">
@if ($item->reconciled)
<td class="col-xs-4 col-sm-4 col-md-3 col-lg-1 col-xl-1"><a class="col-aka" href="#">@date($item->paid_at)</a></td>
<a class="col-aka" href="#">@date($item->paid_at)</a>
@else
<td class="col-xs-4 col-sm-4 col-md-3 col-lg-1 col-xl-1"><a class="col-aka" href="{{ route('payments.show', $item->id) }}">@date($item->paid_at)</a></td>
<a class="col-aka" href="{{ route('revenues.show', $item->id) }}">@date($item->paid_at)</a>
@endif
@if ($item->recurring)
<i class="fas fa-redo-alt fa-xs" title="{{ trans('recurring.recurring') }}"></i>
@endif
</td>
<td class="col-xs-4 col-sm-4 col-md-3 col-lg-2 col-xl-2 text-right">@money($item->amount, $item->currency_code, true)</td>
<td class="col-md-2 col-lg-3 col-xl-3 d-none d-md-block text-left">
{{ $item->contact->name }}

View File

@ -46,11 +46,16 @@
@foreach($revenues as $item)
<tr class="row align-items-center border-top-1">
<td class="col-sm-2 col-md-2 col-lg-1 col-xl-1 d-none d-sm-block">{{ Form::bulkActionGroup($item->id, $item->contact->name) }}</td>
<td class="col-xs-4 col-sm-4 col-md-3 col-lg-1 col-xl-1">
@if ($item->reconciled)
<td class="col-xs-4 col-sm-4 col-md-3 col-lg-1 col-xl-1"><a class="col-aka" href="#">@date($item->paid_at)</a></td>
<a class="col-aka" href="#">@date($item->paid_at)</a>
@else
<td class="col-xs-4 col-sm-4 col-md-3 col-lg-1 col-xl-1"><a class="col-aka" href="{{ route('revenues.show', $item->id) }}">@date($item->paid_at)</a></td>
<a class="col-aka" href="{{ route('revenues.show', $item->id) }}">@date($item->paid_at)</a>
@endif
@if ($item->recurring)
<i class="fas fa-redo-alt fa-xs" title="{{ trans('recurring.recurring') }}"></i>
@endif
</td>
<td class="col-xs-4 col-sm-4 col-md-3 col-lg-2 col-xl-2 text-right">@money($item->amount, $item->currency_code, true)</td>
<td class="col-md-2 col-lg-3 col-xl-3 d-none d-md-block text-left">
{{ $item->contact->name }}