Merge branch 'master' into invoice_template

This commit is contained in:
Cüneyt Şentürk
2022-07-27 14:32:30 +03:00
committed by GitHub
35 changed files with 12855 additions and 906 deletions

View File

@ -10,8 +10,10 @@
]"
:error="formError">
<el-select v-model="selected" :placeholder="placeholder" filterable
<el-select v-model="selected" :placeholder="dynamicPlaceholder" filterable
@change="change" @visible-change="visibleChange" @remove-tag="removeTag" @clear="clear" @blur="blur" @focus="focus"
:remote="remote"
:remote-method="serchableMethod"
:clearable="clearable"
:disabled="disabled"
:multiple="multiple"
@ -66,7 +68,7 @@
</template>
<el-option v-if="!group" v-for="(option, index) in sortedOptions"
:key="index"
:key="option.key"
:disabled="disabledOptions.includes(option.key)"
:label="option.value"
:value="option.key">
@ -81,7 +83,7 @@
:label="group_options.key">
<el-option
v-for="(option, option_index) in group_options.value"
:key="option_index"
:key="option.key"
:disabled="disabledOptions.includes(option.key)"
:label="option.value"
:value="option.key">
@ -189,6 +191,8 @@ export default {
dynamicOptions: null,
fullOptions: null,
disabledOptions: {
type: Array,
default: function () {
@ -283,10 +287,23 @@ export default {
default: 'No Matchign Data',
description: "Selectbox search option not found item message"
},
searchable: {
type: Boolean,
default: false,
description: "Selectbox searchable"
},
searchText: {
type: String,
default: '',
description: "Selectbox input search placeholder text"
},
},
data() {
return {
dynamicPlaceholder: this.placeholder,
add_new: {
text: this.addNew.text,
show: false,
@ -301,18 +318,26 @@ export default {
form: {},
sorted_options: [],
full_options:[],
new_options: {},
loading: false,
remote: false,
}
},
created() {
this.setSortedOptions();
if (this.searchable) {
this.remote = true;
this.setFullOptions();
}
},
computed: {
sortedOptions() {
if (!this.sortOptions) {
if (! this.sortOptions) {
return this.sorted_options
}
@ -344,7 +369,6 @@ export default {
} catch (e) {
this.selected = this.model;
}
}
if (this.multiple && !this.selected.length) {
@ -453,6 +477,82 @@ export default {
}
},
setFullOptions() {
// Reset full_options
this.full_options = [];
let created_options = (this.dynamicOptions) ? this.dynamicOptions : this.fullOptions;
if (this.group) {
// Option set sort_option data
if (!Array.isArray(created_options)) {
for (const [index, options] of Object.entries(created_options)) {
let values = [];
for (const [key, value] of Object.entries(options)) {
values.push({
key: key,
value: value,
level: 0
});
}
this.full_options.push({
key: index,
value: values
});
}
} else {
created_options.forEach(function (option, index) {
if (typeof(option) == 'string') {
this.full_options.push({
index: index,
key: index.toString(),
value: option,
level: 0
});
} else {
this.full_options.push({
index: index,
key: option.id.toString(),
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name,
level: (option.level) ? option.level : 0
});
}
}, this);
}
} else {
// Option set sort_option data
if (!Array.isArray(created_options)) {
for (const [key, value] of Object.entries(created_options)) {
this.full_options.push({
key: key,
value: value,
level: 0
});
}
} else {
created_options.forEach(function (option, index) {
if (typeof(option) == 'string') {
this.full_options.push({
index: index,
key: index.toString(),
value: option,
level: 0
});
} else {
this.full_options.push({
index: index,
key: option.id.toString(),
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name,
level: (option.level) ? option.level : 0
});
}
}, this);
}
}
},
change() {
// This controll added add new changed..
if (typeof(this.selected) === 'object' && typeof(this.selected.type) !== 'undefined') {
@ -531,6 +631,30 @@ export default {
visibleChange(event) {
this.$emit('visible-change', event);
this.dynamicPlaceholder = this.placeholder;
if (event && this.searchText) {
this.dynamicPlaceholder = this.searchText;
}
if (this.searchable) {
let selected = this.selected;
this.sorted_options = [];
this.setSortedOptions();
for (const [key, value] of Object.entries(this.full_options)) {
if (selected == value.key) {
this.sorted_options.push({
index: value.index,
key: value.key,
value: value.value,
level: value.level
});
}
}
}
},
removeTag(event) {
@ -724,6 +848,23 @@ export default {
addModal() {
},
serchableMethod(query) {
if (query !== '') {
this.loading = true;
setTimeout(() => {
this.loading = false;
this.sorted_options = this.full_options.filter(item => {
return item.value.toLowerCase()
.indexOf(query.toLowerCase()) > -1;
});
}, 200);
} else {
this.setSortedOptions();
}
},
},
watch: {

View File

@ -11,7 +11,7 @@
]"
:error="formError">
<el-select v-model="selected" :placeholder="placeholder" filterable remote reserve-keyword
<el-select v-model="selected" :placeholder="dynamicPlaceholder" filterable remote reserve-keyword
@change="change" @visible-change="visibleChange" @remove-tag="removeTag" @clear="clear" @blur="blur" @focus="focus"
:clearable="clearable"
:disabled="disabled"
@ -111,7 +111,7 @@
</base-input>
<span v-else>
<el-select v-model="selected" :placeholder="placeholder" filterable remote reserve-keyword
<el-select v-model="selected" :placeholder="dynamicPlaceholder" filterable remote reserve-keyword
@change="change" @visible-change="visibleChange" @remove-tag="removeTag" @clear="clear" @blur="blur" @focus="focus"
:clearable="clearable"
:disabled="disabled"
@ -288,6 +288,8 @@ export default {
dynamicOptions: null,
fullOptions: null,
disabledOptions: {
type: Array,
default: function () {
@ -389,11 +391,24 @@ export default {
description: "Selectbox search option not found item message"
},
searchable: {
type: Boolean,
default: false,
description: "Selectbox searchable"
},
searchText: {
type: String,
default: '',
description: "Selectbox input search placeholder text"
},
remoteAction: {
type: String,
default: null,
description: "Selectbox remote action path"
},
currencyCode: {
type: String,
default: 'USD',
@ -403,6 +418,7 @@ export default {
data() {
return {
dynamicPlaceholder: this.placeholder,
add_new: {
text: this.addNew.text,
show: false,
@ -417,6 +433,7 @@ export default {
form: {},
sorted_options: [],
full_options:[],
new_options: {},
loading: false,
}
@ -424,11 +441,15 @@ export default {
created() {
this.setSortedOptions();
if (this.searchable) {
this.setFullOptions();
}
},
computed: {
sortedOptions() {
if (!this.sortOptions) {
if (! this.sortOptions) {
return this.sorted_options;
}
@ -460,7 +481,6 @@ export default {
} catch (e) {
this.selected = this.model;
}
}
if (this.multiple && !this.selected.length) {
@ -569,6 +589,82 @@ export default {
}
},
setFullOptions() {
// Reset full_options
this.full_options = [];
let created_options = (this.dynamicOptions) ? this.dynamicOptions : this.fullOptions;
if (this.group) {
// Option set sort_option data
if (!Array.isArray(created_options)) {
for (const [index, options] of Object.entries(created_options)) {
let values = [];
for (const [key, value] of Object.entries(options)) {
values.push({
key: key,
value: value,
level: 0
});
}
this.full_options.push({
key: index,
value: values
});
}
} else {
created_options.forEach(function (option, index) {
if (typeof(option) == 'string') {
this.full_options.push({
index: index,
key: index.toString(),
value: option,
level: 0
});
} else {
this.full_options.push({
index: index,
key: option.id.toString(),
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name,
level: (option.level) ? option.level : 0
});
}
}, this);
}
} else {
// Option set sort_option data
if (!Array.isArray(created_options)) {
for (const [key, value] of Object.entries(created_options)) {
this.full_options.push({
key: key,
value: value,
level: 0
});
}
} else {
created_options.forEach(function (option, index) {
if (typeof(option) == 'string') {
this.full_options.push({
index: index,
key: index.toString(),
value: option,
level: 0
});
} else {
this.full_options.push({
index: index,
key: option.id.toString(),
value: (option.title) ? option.title : (option.display_name) ? option.display_name : option.name,
level: (option.level) ? option.level : 0
});
}
}, this);
}
}
},
change() {
// This controll added add new changed..
if (typeof(this.selected) === 'object' && typeof(this.selected.type) !== 'undefined') {
@ -647,6 +743,30 @@ export default {
visibleChange(event) {
this.$emit('visible-change', event);
this.dynamicPlaceholder = this.placeholder;
if (event && this.searchText) {
this.dynamicPlaceholder = this.searchText;
}
if (this.searchable) {
let selected = this.selected;
this.sorted_options = [];
this.setSortedOptions();
for (const [key, value] of Object.entries(this.full_options)) {
if (selected == value.key) {
this.sorted_options.push({
index: value.index,
key: value.key,
value: value.value,
level: value.level
});
}
}
}
},
removeTag(event) {
@ -670,6 +790,10 @@ export default {
document.getElementById('form-select-' + this.name).getElementsByTagName("input")[0].readOnly = false;
}
if (this.searchable) {
return this.serchableMethod(query);
}
if (query !== '') {
this.loading = true;
@ -742,6 +866,23 @@ export default {
}
},
serchableMethod(query) {
if (query !== '') {
this.loading = true;
setTimeout(() => {
this.loading = false;
this.sorted_options = this.full_options.filter(item => {
return item.value.toLowerCase()
.indexOf(query.toLowerCase()) > -1;
});
}, 200);
} else {
this.setSortedOptions();
}
},
async onAddItem() {
// Get Select Input value
if (this.multiple) {

View File

@ -29,7 +29,7 @@ const app = new Vue({
return {
form: new Form('reconciliation'),
bulk_action: new BulkAction('reconciliations'),
reconcile: true,
reconcile: false,
difference: null,
totals: {
closing_balance: 0,
@ -48,8 +48,6 @@ const app = new Vue({
if (this.form._method == 'PATCH') {
this.onCalculate();
}
this.currencyConversion();
},
methods:{
@ -57,18 +55,6 @@ const app = new Vue({
this.min_due_date = date;
},
currencyConversion() {
setTimeout(() => {
if (document.querySelectorAll('.js-conversion-input')) {
let currency_input = document.querySelectorAll('.js-conversion-input');
for (let input of currency_input) {
input.setAttribute('size', input.value.length);
}
}
}, 250)
},
onReconcilition() {
let form = document.getElementById('form-create-reconciliation');
@ -78,7 +64,7 @@ const app = new Vue({
},
onCalculate() {
this.reconcile = true;
this.reconcile = false;
this.difference = null;
let transactions = this.form.transactions;
@ -120,10 +106,10 @@ const app = new Vue({
if (difference != 0) {
this.difference = 'bg-orange-300';
this.reconcile = true;
this.reconcile = false;
} else {
this.difference = 'bg-green-100';
this.reconcile = false;
this.reconcile = true;
}
this.totals.cleared_amount = parseFloat(cleared_amount);

View File

@ -162,10 +162,17 @@ const app = new Vue({
sub_total += item.total;
grand_total += item.grand_total;
let item_tax_ids = [];
item.tax_ids.forEach(function(item_tax, item_tax_index) {
item_tax_ids.push(item_tax.id);
});
this.form.items[index].name = item.name;
this.form.items[index].description = item.description;
this.form.items[index].quantity = item.quantity;
this.form.items[index].price = item.price;
this.form.items[index].tax_ids = item_tax_ids;
this.form.items[index].discount = item.discount;
this.form.items[index].discount_type = item.discount_type;
this.form.items[index].total = item.total;
@ -262,6 +269,7 @@ const app = new Vue({
if (inclusives.length) {
inclusives.forEach(function(inclusive) {
item.tax_ids[inclusive.tax_index].name = inclusive.tax_name;
item.tax_ids[inclusive.tax_index].price = item.grand_total - (item.grand_total / (1 + inclusive.tax_rate / 100));
inclusive_tax_total += item.tax_ids[inclusive.tax_index].price;
@ -274,6 +282,7 @@ const app = new Vue({
if (fixed.length) {
fixed.forEach(function(fixed) {
item.tax_ids[fixed.tax_index].name = fixed.tax_name;
item.tax_ids[fixed.tax_index].price = fixed.tax_rate * item.quantity;
total_tax_amount += item.tax_ids[fixed.tax_index].price;
@ -290,6 +299,7 @@ const app = new Vue({
if (normal.length) {
normal.forEach(function(normal) {
item.tax_ids[normal.tax_index].name = normal.tax_name;
item.tax_ids[normal.tax_index].price = price_for_tax * (normal.tax_rate / 100);
total_tax_amount += item.tax_ids[normal.tax_index].price;
@ -300,6 +310,7 @@ const app = new Vue({
if (withholding.length) {
withholding.forEach(function(withholding) {
item.tax_ids[withholding.tax_index].name = withholding.tax_name;
item.tax_ids[withholding.tax_index].price = -(price_for_tax * (withholding.tax_rate / 100));
total_tax_amount += item.tax_ids[withholding.tax_index].price;
@ -312,6 +323,7 @@ const app = new Vue({
if (compounds.length) {
compounds.forEach(function(compound) {
item.tax_ids[compound.tax_index].name = compound.tax_name;
item.tax_ids[compound.tax_index].price = (item.grand_total / 100) * compound.tax_rate;
totals_taxes = this.calculateTotalsTax(totals_taxes, compound.tax_id, compound.tax_name, item.tax_ids[compound.tax_index].price);
@ -448,6 +460,7 @@ const app = new Vue({
},
onSelectedTax(item_index) {
if (! this.tax_id) {
return;
}
@ -476,6 +489,7 @@ const app = new Vue({
}
this.tax_id = '';
this.items[item_index].add_tax = false;
this.onCalculateTotal();
},
@ -954,6 +968,7 @@ const app = new Vue({
form_html.querySelectorAll('[type="submit"]').forEach((submit) => {
submit.addEventListener('click', () => {
this.minor_form_loading = false;
window.onbeforeunload = null;
});
});
@ -968,9 +983,33 @@ const app = new Vue({
},
onSubmitViaSendEmail() {
let type_submit_icon = document.querySelector('[type="submit"]').querySelector('i');
let type_submit_span = document.querySelector('[type="submit"]').querySelector('span');
this.form['senddocument'] = true;
this.minor_form_loading = true;
if (this.form.loading) {
type_submit_icon.classList.add('hidden');
type_submit_span.classList.add('opacity-100');
}
setTimeout(() => {
if (type_submit_icon && type_submit_span) {
type_submit_icon.classList.remove('hidden');
type_submit_span.classList.remove('opacity-100');
}
}, 5000);
this.onSubmit();
setTimeout(() => {
if (Object.keys(this.form.errors.errors.length > 0)) {
this.minor_form_loading = false;
return;
}
}, 200);
},
},

View File

@ -19,5 +19,7 @@ return [
'404' => 'We could not find the page you were looking for.',
'500' => 'We will work on fixing that right away.',
'record' => 'We could not find the record you were looking for.',
'amount' => 'This page contains invalid amounts! Please, contact the system administrator.',
],
];

View File

@ -79,7 +79,7 @@ return [
],
'sticky' => [
'description' => 'You are previewing how your customer will see the web version of your invoice.',
'description' => 'You are previewing how your customer will see the web version of your invoice.',
],
];

View File

@ -41,6 +41,7 @@ return [
'reconciled_doc' => 'Warning: You are not allowed to change/delete :type because it has reconciled transactions!',
'disable_code' => 'Warning: You are not allowed to disable or change the currency of <b>:name</b> because it has :text related.',
'payment_cancel' => 'Warning: You have cancelled your recent :method payment!',
'missing_transfer' => 'Warning: The transfer related to this transaction is missing. You should consider deleting this transaction.',
],
];

View File

@ -13,7 +13,6 @@ return [
|
*/
'password' => 'Passwords must be at least six characters and match the confirmation.',
'reset' => 'Your password has been reset!',
'sent' => 'We have emailed your password reset link!',
'throttled' => 'Please wait before retrying.',

View File

@ -14,6 +14,7 @@ return [
*/
'accepted' => 'The :attribute must be accepted.',
'accepted_if' => 'The :attribute must be accepted when :other is :value.',
'active_url' => 'The :attribute is not a valid URL.',
'after' => 'The :attribute must be a date after :date.',
'after_or_equal' => 'The :attribute must be a date after or equal to :date.',
@ -24,10 +25,10 @@ return [
'before' => 'The :attribute must be a date before :date.',
'before_or_equal' => 'The :attribute must be a date before or equal to :date.',
'between' => [
'numeric' => 'The :attribute must be between :min and :max.',
'file' => 'The :attribute must be between :min and :max kilobytes.',
'string' => 'The :attribute must be between :min and :max characters.',
'array' => 'The :attribute must have between :min and :max items.',
'file' => 'The :attribute must be between :min and :max kilobytes.',
'numeric' => 'The :attribute must be between :min and :max.',
'string' => 'The :attribute must be between :min and :max characters.',
],
'boolean' => 'The :attribute field must be true or false.',
'confirmed' => 'The :attribute confirmation does not match.',
@ -35,27 +36,31 @@ return [
'date' => 'The :attribute is not a valid date.',
'date_equals' => 'The :attribute must be a date equal to :date.',
'date_format' => 'The :attribute does not match the format :format.',
'declined' => 'The :attribute must be declined.',
'declined_if' => 'The :attribute must be declined when :other is :value.',
'different' => 'The :attribute and :other must be different.',
'digits' => 'The :attribute must be :digits digits.',
'digits_between' => 'The :attribute must be between :min and :max digits.',
'dimensions' => 'The :attribute has invalid image dimensions.',
'distinct' => 'The :attribute field has a duplicate value.',
'doesnt_start_with' => 'The :attribute may not start with one of the following: :values.',
'email' => 'The :attribute must be a valid email address.',
'ends_with' => 'The :attribute must end with one of the following: :values.',
'enum' => 'The selected :attribute is invalid.',
'exists' => 'The selected :attribute is invalid.',
'file' => 'The :attribute must be a file.',
'filled' => 'The :attribute field must have a value.',
'gt' => [
'numeric' => 'The :attribute must be greater than :value.',
'file' => 'The :attribute must be greater than :value kilobytes.',
'string' => 'The :attribute must be greater than :value characters.',
'array' => 'The :attribute must have more than :value items.',
'file' => 'The :attribute must be greater than :value kilobytes.',
'numeric' => 'The :attribute must be greater than :value.',
'string' => 'The :attribute must be greater than :value characters.',
],
'gte' => [
'numeric' => 'The :attribute must be greater than or equal :value.',
'file' => 'The :attribute must be greater than or equal :value kilobytes.',
'string' => 'The :attribute must be greater than or equal :value characters.',
'array' => 'The :attribute must have :value items or more.',
'file' => 'The :attribute must be greater than or equal to :value kilobytes.',
'numeric' => 'The :attribute must be greater than or equal to :value.',
'string' => 'The :attribute must be greater than or equal to :value characters.',
],
'image' => 'The :attribute must be an image.',
'in' => 'The selected :attribute is invalid.',
@ -66,61 +71,70 @@ return [
'ipv6' => 'The :attribute must be a valid IPv6 address.',
'json' => 'The :attribute must be a valid JSON string.',
'lt' => [
'numeric' => 'The :attribute must be less than :value.',
'file' => 'The :attribute must be less than :value kilobytes.',
'string' => 'The :attribute must be less than :value characters.',
'array' => 'The :attribute must have less than :value items.',
'file' => 'The :attribute must be less than :value kilobytes.',
'numeric' => 'The :attribute must be less than :value.',
'string' => 'The :attribute must be less than :value characters.',
],
'lte' => [
'numeric' => 'The :attribute must be less than or equal :value.',
'file' => 'The :attribute must be less than or equal :value kilobytes.',
'string' => 'The :attribute must be less than or equal :value characters.',
'array' => 'The :attribute must not have more than :value items.',
'file' => 'The :attribute must be less than or equal to :value kilobytes.',
'numeric' => 'The :attribute must be less than or equal to :value.',
'string' => 'The :attribute must be less than or equal to :value characters.',
],
'mac_address' => 'The :attribute must be a valid MAC address.',
'max' => [
'numeric' => 'The :attribute must not be greater than :max.',
'file' => 'The :attribute must not be greater than :max kilobytes.',
'string' => 'The :attribute must not be greater than :max characters.',
'array' => 'The :attribute must not have more than :max items.',
'file' => 'The :attribute must not be greater than :max kilobytes.',
'numeric' => 'The :attribute must not be greater than :max.',
'string' => 'The :attribute must not be greater than :max characters.',
],
'mimes' => 'The :attribute must be a file of type: :values.',
'mimetypes' => 'The :attribute must be a file of type: :values.',
'min' => [
'numeric' => 'The :attribute must be at least :min.',
'file' => 'The :attribute must be at least :min kilobytes.',
'string' => 'The :attribute must be at least :min characters.',
'array' => 'The :attribute must have at least :min items.',
'file' => 'The :attribute must be at least :min kilobytes.',
'numeric' => 'The :attribute must be at least :min.',
'string' => 'The :attribute must be at least :min characters.',
],
'multiple_of' => 'The :attribute must be a multiple of :value.',
'not_in' => 'The selected :attribute is invalid.',
'not_regex' => 'The :attribute format is invalid.',
'numeric' => 'The :attribute must be a number.',
'password' => 'The password is incorrect.',
'password' => [
'letters' => 'The :attribute must contain at least one letter.',
'mixed' => 'The :attribute must contain at least one uppercase and one lowercase letter.',
'numbers' => 'The :attribute must contain at least one number.',
'symbols' => 'The :attribute must contain at least one symbol.',
'uncompromised' => 'The given :attribute has appeared in a data leak. Please choose a different :attribute.',
],
'present' => 'The :attribute field must be present.',
'prohibited' => 'The :attribute field is prohibited.',
'prohibited_if' => 'The :attribute field is prohibited when :other is :value.',
'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.',
'prohibits' => 'The :attribute field prohibits :other from being present.',
'regex' => 'The :attribute format is invalid.',
'required' => 'The :attribute field is required.',
'required_array_keys' => 'The :attribute field must contain entries for: :values.',
'required_if' => 'The :attribute field is required when :other is :value.',
'required_unless' => 'The :attribute field is required unless :other is in :values.',
'required_with' => 'The :attribute field is required when :values is present.',
'required_with_all' => 'The :attribute field is required when :values are present.',
'required_without' => 'The :attribute field is required when :values is not present.',
'required_without_all' => 'The :attribute field is required when none of :values are present.',
'prohibited' => 'The :attribute field is prohibited.',
'prohibited_if' => 'The :attribute field is prohibited when :other is :value.',
'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.',
'same' => 'The :attribute and :other must match.',
'size' => [
'numeric' => 'The :attribute must be :size.',
'file' => 'The :attribute must be :size kilobytes.',
'string' => 'The :attribute must be :size characters.',
'array' => 'The :attribute must contain :size items.',
'file' => 'The :attribute must be :size kilobytes.',
'numeric' => 'The :attribute must be :size.',
'string' => 'The :attribute must be :size characters.',
],
'starts_with' => 'The :attribute must start with one of the following: :values.',
'string' => 'The :attribute must be a string.',
'timezone' => 'The :attribute must be a valid zone.',
'timezone' => 'The :attribute must be a valid timezone.',
'unique' => 'The :attribute has already been taken.',
'uploaded' => 'The :attribute failed to upload.',
'url' => 'The :attribute format is invalid.',
'url' => 'The :attribute must be a valid URL.',
'uuid' => 'The :attribute must be a valid UUID.',
/*

View File

@ -51,7 +51,10 @@
:currency="$currency"
/>
<x-form.group.account form-group-class="col-span-10 lg:col-span-5 xl:col-span-2 account-input" />
<x-form.group.account
form-group-class="col-span-10 lg:col-span-5 xl:col-span-2 account-input"
selected="{{ request('account_id', setting('default.account')) }}"
/>
<div class="flex items-end lg:justify-end xl:justify-start col-span-10 xl:col-span-2">
<x-button
@ -167,11 +170,11 @@
<table class="min-w-full divide-y divide-gray-200">
<tbody class="float-right">
<tr class="border-b">
<th class="w-11/12 ltr:pr-6 rtl:pl-6 py-4 ltr:text-left rtl:text-right whitespace-nowrap text-sm font-bold text-black">
<th class="w-9/12 ltr:pr-6 rtl:pl-6 py-4 ltr:text-left rtl:text-right whitespace-nowrap text-sm font-bold text-black">
{{ trans('reconciliations.opening_balance') }}:
</th>
<td id="closing-balance" class="w-1/12 ltr:text-right rtl:text-left">
<td id="closing-balance" class="w-3/12 ltr:text-right rtl:text-left">
<span class="w-auto pl-6 text-sm">
<x-money :amount="$opening_balance" :currency="$account->currency_code" convert />
</span>
@ -179,11 +182,11 @@
</tr>
<tr class="border-b">
<th class="w-11/12 ltr:pr-6 rtl:pl-6 py-4 ltr:text-left rtl:text-right whitespace-nowrap text-sm font-bold text-black">
<th class="w-9/12 ltr:pr-6 rtl:pl-6 py-4 ltr:text-left rtl:text-right whitespace-nowrap text-sm font-bold text-black">
{{ trans('reconciliations.closing_balance') }}:
</th>
<td id="closing-balance" class="w-1/12 text-right">
<td id="closing-balance" class="w-3/12 text-right">
<x-form.input.money
name="closing_balance_total"
value="0"
@ -192,18 +195,18 @@
v-model="totals.closing_balance"
:currency="$currency"
dynamicCurrency="currency"
money-class="text-right disabled-money banking-price-text w-auto position-absolute right-4 ltr:pr-0 rtl:pl-0 text-sm js-conversion-input"
money-class="text-right disabled-money banking-price-text w-auto position-absolute right-4 ltr:pr-0 rtl:pl-0 text-sm"
form-group-class="text-right disabled-money"
/>
</td>
</tr>
<tr class="border-b">
<th class="w-11/12 ltr:pr-6 rtl:pl-6 py-4 ltr:text-left rtl:text-right whitespace-nowrap text-sm font-bold text-black">
<th class="w-9/12 ltr:pr-6 rtl:pl-6 py-4 ltr:text-left rtl:text-right whitespace-nowrap text-sm font-bold text-black">
{{ trans('reconciliations.cleared_amount') }}:
</th>
<td id="cleared-amount" class="w-1/12 text-right">
<td id="cleared-amount" class="w-3/12 text-right">
<x-form.input.money
name="cleared_amount_total"
value="0"
@ -212,20 +215,20 @@
v-model="totals.cleared_amount"
:currency="$currency"
dynamicCurrency="currency"
money-class="text-right disabled-money banking-price-text w-auto position-absolute right-4 ltr:pr-0 rtl:pl-0 text-sm js-conversion-input"
money-class="text-right disabled-money banking-price-text w-auto position-absolute right-4 ltr:pr-0 rtl:pl-0 text-sm"
form-group-class="text-right disabled-money"
/>
</td>
</tr>
<tr class="border-b">
<th class="w-11/12 ltr:pr-6 rtl:pl-6 py-4 ltr:text-left rtl:text-right whitespace-nowrap text-sm font-bold text-black cursor-pointer">
<th class="w-9/12 ltr:pr-6 rtl:pl-6 py-4 ltr:text-left rtl:text-right whitespace-nowrap text-sm font-bold text-black cursor-pointer">
<span class="px-2 py-1 rounded-xl" :class="difference">
{{ trans('general.difference') }}
</span>
</th>
<td id="difference" class="w-1/12 ltr:pl-6 rtl:pr-0 text-right">
<td id="difference" class="w-3/12 ltr:pl-6 rtl:pr-0 text-right">
<div class="difference-money">
<x-form.input.money
name="difference_total"
@ -235,7 +238,7 @@
v-model="totals.difference"
:currency="$currency"
dynamicCurrency="currency"
money-class="text-right disabled-money banking-price-text w-auto position-absolute right-4 ltr:pr-0 rtl:pl-0 text-sm js-conversion-input"
money-class="text-right disabled-money banking-price-text w-auto position-absolute right-4 ltr:pr-0 rtl:pl-0 text-sm"
form-group-class="text-right disabled-money"
/>
</div>
@ -264,37 +267,38 @@
class="flex items-center justify-center bg-transparent hover:bg-gray-200 px-3 py-1.5 text-base rounded-lg disabled:opacity-50"
override="class"
>
<x-button.loading>
<x-button.loading action="! reconcile && form.loading">
{{ trans('reconciliations.save_draft') }}
</x-button.loading>
</x-button>
<div v-if="reconcile">
<div v-if="! reconcile">
<x-tooltip id="tooltip-reconcile" placement="top" message="{{ trans('reconciliations.irreconcilable') }}">
<x-button
type="button"
::disabled="reconcile || form.loading"
class="relative flex items-center justify-center px-3 py-1.5 ltr:ml-2 rtl:mr-2 text-white text-base rounded-lg bg-blue-300 hover:bg-blue-500 disabled:bg-blue-100"
::disabled="! reconcile"
class="relative flex items-center justify-center px-3 py-1.5 ltr:ml-2 rtl:mr-2 text-white text-base rounded-lg bg-blue hover:bg-blue-700 disabled:bg-blue-100"
override="class"
@click="onReconcileSubmit"
data-loading-text="{{ trans('general.loading') }}"
>
<x-button.loading action="! reconcile">
<x-button.loading action="reconcile && form.loading">
{{ trans('reconciliations.reconcile') }}
</x-button.loading>
</x-button>
</x-tooltip>
</div>
<div v-else>
<x-button
type="button"
::disabled="reconcile || form.loading"
class="relative flex items-center justify-center px-3 py-1.5 ltr:ml-2 rtl:mr-2 text-white text-base rounded-lg bg-blue-300 hover:bg-blue-500 disabled:bg-blue-100"
::disabled="! reconcile"
class="relative flex items-center justify-center px-3 py-1.5 ltr:ml-2 rtl:mr-2 text-white text-base rounded-lg bg-blue hover:bg-blue-700 disabled:bg-blue-100"
override="class"
@click="onReconcileSubmit"
data-loading-text="{{ trans('general.loading') }}"
>
<x-button.loading action="! reconcile">
<x-button.loading action="reconcile && form.loading">
{{ trans('reconciliations.reconcile') }}
</x-button.loading>
</x-button>

View File

@ -105,11 +105,11 @@
<table class="min-w-full divide-y divide-gray-200">
<tbody class="float-right">
<tr class="border-b">
<th class="w-11/12 ltr:pr-6 rtl:pl-6 py-4 ltr:text-left rtl:text-right whitespace-nowrap text-sm font-bold text-black">
<th class="w-9/12 ltr:pr-6 rtl:pl-6 py-4 ltr:text-left rtl:text-right whitespace-nowrap text-sm font-bold text-black">
{{ trans('reconciliations.opening_balance') }}:
</th>
<td id="closing-balance" class="w-1/12 text-right">
<td id="closing-balance" class="w-3/12 text-right">
<span class="w-auto pl-6 text-sm">
<x-money :amount="$opening_balance" :currency="$account->currency_code" convert />
</span>
@ -117,11 +117,11 @@
</tr>
<tr class="border-b">
<th class="w-11/12 ltr:pr-6 rtl:pl-6 py-4 ltr:text-left rtl:text-right whitespace-nowrap text-sm font-bold text-black">
<th class="w-9/12 ltr:pr-6 rtl:pl-6 py-4 ltr:text-left rtl:text-right whitespace-nowrap text-sm font-bold text-black">
{{ trans('reconciliations.closing_balance') }}:
</th>
<td id="closing-balance" class="w-1/12 text-right">
<td id="closing-balance" class="w-3/12 text-right">
<x-form.input.money
name="closing_balance_total"
value="0"
@ -130,18 +130,18 @@
v-model="totals.closing_balance"
:currency="$currency"
dynamicCurrency="currency"
money-class="text-right disabled-money banking-price-text w-auto position-absolute right-4 ltr:pr-0 rtl:pl-0 text-sm js-conversion-input"
money-class="text-right disabled-money banking-price-text w-auto position-absolute right-4 ltr:pr-0 rtl:pl-0 text-sm"
form-group-class="text-right disabled-money"
/>
</td>
</tr>
<tr class="border-b">
<th class="w-11/12 ltr:pr-6 rtl:pl-6 py-4 ltr:text-left rtl:text-right whitespace-nowrap text-sm font-bold text-black">
<th class="w-9/12 ltr:pr-6 rtl:pl-6 py-4 ltr:text-left rtl:text-right whitespace-nowrap text-sm font-bold text-black">
{{ trans('reconciliations.cleared_amount') }}:
</th>
<td id="cleared-amount" class="w-1/12 text-right">
<td id="cleared-amount" class="w-3/12 text-right">
<x-form.input.money
name="cleared_amount_total"
value="0"
@ -150,20 +150,20 @@
v-model="totals.cleared_amount"
:currency="$currency"
dynamicCurrency="currency"
money-class="text-right disabled-money banking-price-text w-auto position-absolute right-4 ltr:pr-0 rtl:pl-0 text-sm js-conversion-input"
money-class="text-right disabled-money banking-price-text w-auto position-absolute right-4 ltr:pr-0 rtl:pl-0 text-sm"
form-group-class="text-right disabled-money"
/>
</td>
</tr>
<tr>
<th class="w-11/12 ltr:pr-6 rtl:pl-6 py-4 ltr:text-left rtl:text-right whitespace-nowrap text-sm font-bold text-black cursor-pointer">
<th class="w-9/12 ltr:pr-6 rtl:pl-6 py-4 ltr:text-left rtl:text-right whitespace-nowrap text-sm font-bold text-black cursor-pointer">
<span class="px-2 py-1 rounded-xl" :class="difference">
{{ trans('general.difference') }}
</span>
</th>
<td id="difference" class="w-1/12 ltr:pl-6 rtl:pr-0 text-right">
<td id="difference" class="w-3/12 ltr:pl-6 rtl:pr-0 text-right">
<div class="difference-money">
<x-form.input.money
name="difference_total"
@ -173,7 +173,7 @@
v-model="totals.difference"
:currency="$currency"
dynamicCurrency="currency"
money-class="text-right disabled-money banking-price-text w-auto position-absolute right-4 ltr:pr-0 rtl:pl-0 text-sm js-conversion-input"
money-class="text-right disabled-money banking-price-text w-auto position-absolute right-4 ltr:pr-0 rtl:pl-0 text-sm"
form-group-class="text-right disabled-money"
/>
</div>
@ -203,22 +203,22 @@
class="relative flex items-center justify-center bg-transparent hover:bg-gray-200 px-3 py-1.5 text-base rounded-lg disabled:opacity-50"
override="class"
>
<x-button.loading>
<x-button.loading action="! reconcile && form.loading">
{{ trans('general.save') }}
</x-button.loading>
</x-button>
<div v-if="reconcile">
<div v-if="! reconcile">
<x-tooltip id="tooltip-reconcile" placement="top" message="{{ trans('reconciliations.irreconcilable') }}">
<x-button
type="button"
::disabled="reconcile || form.loading"
class="relative flex items-center justify-center px-3 py-1.5 ltr:ml-2 rtl:mr-2 text-white text-base rounded-lg bg-blue-300 hover:bg-blue-500 disabled:bg-blue-100"
::disabled="! reconcile"
class="relative flex items-center justify-center px-3 py-1.5 ltr:ml-2 rtl:mr-2 text-white text-base rounded-lg bg-blue hover:bg-blue-700 disabled:bg-blue-100"
override="class"
@click="onReconcileSubmit"
data-loading-text="{{ trans('general.loading') }}"
>
<x-button.loading action="! reconcile">
<x-button.loading action="reconcile && form.loading">
{{ trans('reconciliations.reconcile') }}
</x-button.loading>
</x-button>
@ -228,13 +228,13 @@
<div v-else>
<x-button
type="button"
::disabled="reconcile || form.loading"
class="relative flex items-center justify-center px-3 py-1.5 ltr:ml-2 rtl:mr-2 text-white text-base rounded-lg bg-blue-300 hover:bg-blue-500 disabled:bg-blue-100"
::disabled="! reconcile"
class="relative flex items-center justify-center px-3 py-1.5 ltr:ml-2 rtl:mr-2 text-white text-base rounded-lg bg-blue hover:bg-blue-700 disabled:bg-blue-100"
override="class"
@click="onReconcileSubmit"
data-loading-text="{{ trans('general.loading') }}"
>
<x-button.loading action="! reconcile">
<x-button.loading action="reconcile && form.loading">
{{ trans('reconciliations.reconcile') }}
</x-button.loading>
</x-button>

View File

@ -6,7 +6,6 @@
add-new
path="{{ $path }}"
add-new
name="{{ $name }}"
label="{!! $label !!}"
:options="$contacts"
@ -26,7 +25,6 @@
add-new
path="{{ $path }}"
add-new
name="{{ $name }}"
label="{!! $label !!}"
:options="$contacts"

View File

@ -47,6 +47,24 @@
:dynamic-options="{{ $attributes['dynamicOptions'] }}"
@endif
@if (! empty($attributes['searchable']))
searchable
@elseif (! empty($searchable))
searchable
@endif
@if (isset($attributes['fullOptions']) || isset($attributes['full-options']))
:full-options="{{ json_encode(! empty($attributes['fullOptions']) ? $attributes['fullOptions'] : $attributes['full-options']) }}"
@else
:full-options="{{ json_encode($fullOptions) }}"
@endif
@if (isset($attributes['searchText']) || isset($attributes['search-text']))
search-text="{{ ! empty($attributes['searchText']) ? $attributes['searchText'] : $attributes['search-text'] }}"
@else
search-text="{{ $searchText }}"
@endif
@if (empty($multiple))
@if (isset($selected) || old($name))
value="{{ old($name, $selected) }}"
@ -107,6 +125,10 @@
@change="{{ $attributes['change'] }}($event)"
@endif
@if (! empty($attributes['focus']))
@focus="{{ $attributes['focus'] }}"
@endif
@if (! empty($attributes['visible-change']))
@visible-change="{{ $attributes['visible-change'] }}"
@endif

View File

@ -47,6 +47,24 @@
:dynamic-options="{{ $attributes['dynamicOptions'] }}"
@endif
@if (! empty($attributes['searchable']))
searchable
@elseif (! empty($searchable))
searchable
@endif
@if (isset($attributes['fullOptions']) || isset($attributes['full-options']))
:full-options="{{ json_encode(! empty($attributes['fullOptions']) ? $attributes['fullOptions'] : $attributes['full-options']) }}"
@else
:full-options="{{ json_encode($fullOptions) }}"
@endif
@if (isset($attributes['searchText']) || isset($attributes['search-text']))
search-text="{{ ! empty($attributes['searchText']) ? $attributes['searchText'] : $attributes['search-text'] }}"
@else
search-text="{{ $searchText }}"
@endif
@if (empty($multiple))
@if (isset($selected) || old($name))
value="{{ old($name, $selected) }}"

View File

@ -1,10 +1,15 @@
@if ($transaction->isTransferTransaction())
@php
$from_account = '<span class="font-medium">' . $transaction->transfer->expense_account->title . '</span>';
$to_account = '<span class="font-medium">' . $transaction->transfer->income_account->title . '</span>';
@endphp
@php $transfer = $transaction->transfer; @endphp
<div class="border-b pb-4" x-data="{ transfer : null }">
@if ($transfer)
@php
$from_account = '<span class="font-medium">' . $transfer->expense_account->title . '</span>';
$to_account = '<span class="font-medium">' . $transfer->income_account->title . '</span>';
$date = '<a href="' . route('transfers.show', $transfer->id) . '" class="text-purple">' . company_date($transaction->paid_at) . '</a>';
@endphp
@endif
<div class="border-b pb-4" x-data="{ transfer : 1 }">
<button class="relative w-full text-left cursor-pointer group"
x-on:click="transfer !== 1 ? transfer = 1 : transfer = null"
>
@ -12,9 +17,11 @@
{{ trans_choice('general.transfers', 1) }}
</span>
<div class="text-black-400 text-sm">
{!! trans('transactions.slider.transfer_headline', ['from_account' => $from_account, 'to_account' => $to_account]) !!}
</div>
@if ($transfer)
<div class="text-black-400 text-sm">
{!! trans('transactions.slider.transfer_headline', ['from_account' => $from_account, 'to_account' => $to_account]) !!}
</div>
@endif
<span class="material-icons absolute right-0 top-0 transition-all transform"
x-bind:class="transfer === 1 ? 'rotate-180' : ''"
@ -25,13 +32,19 @@
x-ref="container1"
x-bind:class="transfer === 1 ? 'h-auto' : 'scale-y-0 h-0'"
>
@php
$date = '<a href="' . route('transfers.show', $transaction->transfer->id) . '" class="text-purple">' . company_date($transaction->paid_at) . '</a>';
@endphp
<div class="my-2">
{!! trans('transactions.slider.transfer_desc', ['date' => $date]) !!}
</div>
@if ($transfer)
<div class="my-2">
{!! trans('transactions.slider.transfer_desc', ['date' => $date]) !!}
</div>
@else
<div class="mt-2">
<div class="alert alert-notify p-4 text-black font-bold rounded-lg bg-orange-100 text-orange-600">
<span class="alert-text">
<span>{{ trans('messages.warning.missing_transfer') }}</span>
</span>
</div>
</div>
@endif
</div>
</div>
@endif

View File

@ -14,6 +14,12 @@
{{ trans('errors.title.403') }}
</span>
@if (! empty($message))
<span class="text-lg">
{{ $message }}
</span>
@endif
@php $landing_page = user() ? user()->getLandingPageOfUser() : route('login'); @endphp
<a href="{{ $landing_page }}" class="relative flex items-center justify-center bg-green hover:bg-green-700 text-white px-6 py-1.5 text-base rounded-lg disabled:bg-green-100 mt-3">
{{ trans('general.go_to_dashboard') }}

View File

@ -14,6 +14,12 @@
{{ trans('errors.title.404') }}
</span>
@if (! empty($message))
<span class="text-lg">
{{ $message }}
</span>
@endif
@php $landing_page = user() ? user()->getLandingPageOfUser() : route('login'); @endphp
<a href="{{ $landing_page }}" class="relative flex items-center justify-center bg-green hover:bg-green-700 text-white px-6 py-1.5 text-base rounded-lg disabled:bg-green-100 mt-3">
{{ trans('general.go_to_dashboard') }}

View File

@ -14,6 +14,12 @@
{{ trans('errors.title.500') }}
</span>
@if (! empty($message))
<span class="text-lg">
{{ $message }}
</span>
@endif
@php $landing_page = user() ? user()->getLandingPageOfUser() : route('login'); @endphp
<a href="{{ $landing_page }}" class="relative flex items-center justify-center bg-green hover:bg-green-700 text-white px-6 py-1.5 text-base rounded-lg disabled:bg-green-100 mt-3">
{{ trans('general.go_to_dashboard') }}

View File

@ -4,7 +4,9 @@
<x-form.group.color name="color" label="{{ trans('general.color') }}" form-group-class="col-span-6" />
<x-form.input.hidden name="type" :value="$type" />
<x-form.group.select name="parent_id" label="{{ trans('general.parent') . ' ' . trans_choice('general.categories', 1) }}" :options="$categories" not-required sort-options="false" searchable form-group-class="col-span-6" />
<x-form.input.hidden name="type" :value="'{{ $type }}'" @change="updateParentCategories" />
<x-form.input.hidden name="enabled" value="1" />
</div>
</x-form>

View File

@ -14,9 +14,21 @@
</x-slot>
<x-slot name="content">
<x-modules.purchased />
@if (! empty($purchase) || ! empty($installed))
<x-modules.purchased />
<x-modules.installed />
<x-modules.installed />
@else
<div class="py-6 font-medium">
<div class="flex items-center justify-between mb-5 lg:mb-0">
<h4 class="py-3 font-medium lg:text-2xl">
{{ trans('modules.my_apps') }}
</h4>
</div>
<x-modules.no-apps />
</div>
@endif
</x-slot>
<x-script folder="modules" file="apps" />

View File

@ -24,7 +24,7 @@
<x-form.group.select name="type" label="{{ trans_choice('general.types', 1) }}" :options="$types" :selected="config('general.types')" change="updateParentCategories" />
<x-form.group.select name="parent_id" label="{{ trans('general.parent') . ' ' . trans_choice('general.categories', 1) }}" :options="[]" not-required dynamicOptions="categoriesBasedTypes" sort-options="false" disabled="isParentCategoryDisabled" />
<x-form.group.select name="parent_id" label="{{ trans('general.parent') . ' ' . trans_choice('general.categories', 1) }}" :options="[]" not-required dynamicOptions="categoriesBasedTypes" sort-options="false" v-disabled="isParentCategoryDisabled" />
<x-form.input.hidden name="categories" value="{{ json_encode($categories) }}" />
</x-slot>

View File

@ -24,7 +24,7 @@
<x-form.group.select name="type" label="{{ trans_choice('general.types', 1) }}" :options="$types" change="updateParentCategories" />
@endif
<x-form.group.select name="parent_id" label="{{ trans('general.parent') . ' ' . trans_choice('general.categories', 1) }}" :options="$categories[$category->type]" not-required dynamicOptions="categoriesBasedTypes" sort-options="false" />
<x-form.group.select name="parent_id" label="{{ trans('general.parent') . ' ' . trans_choice('general.categories', 1) }}" :options="$categories[$category->type]" not-required dynamicOptions="categoriesBasedTypes" sort-options="false" v-disabled="isParentCategoryDisabled" />
<x-form.input.hidden name="categories" value="{{ json_encode($categories) }}" />
<x-form.input.hidden name="parent_category_id" :value="$category->parent_id" />

View File

@ -20,7 +20,7 @@
<x-slot name="body">
<x-form.group.text name="name" label="{{ trans('general.name') }}" />
<x-form.group.select name="code" label="{{ trans('currencies.code') }}" :options="$codes" change="onChangeCode" />
<x-form.group.select name="code" label="{{ trans('currencies.code') }}" :options="$codes" searchable change="onChangeCode" />
<x-form.group.text name="rate" label="{{ trans('currencies.rate') }}" @input="onChangeRate" />

View File

@ -14,7 +14,7 @@
<x-slot name="body">
<x-form.group.text name="name" label="{{ trans('general.name') }}" />
<x-form.group.select name="code" label="{{ trans('currencies.code') }}" :options="$codes" change="onChangeCode" />
<x-form.group.select name="code" label="{{ trans('currencies.code') }}" :options="$codes" searchable change="onChangeCode" />
<x-form.group.text name="rate" label="{{ trans('currencies.rate') }}" @input="onChangeRate" />