This commit is contained in:
2020-12-28 23:37:16 +00:00
parent 5c18d5d6ce
commit 08179b8582
10 changed files with 1856 additions and 92 deletions

View File

@@ -6,6 +6,16 @@
MISC ITEMS THAT CAME UP MISC ITEMS THAT CAME UP
todo: datatable numbers
currency and possibly other numbers should center justify in their columns or left or whatever it takes to not look so weird but still be comparable / lined up or whatever
OR
Maybe it's the column header itself that should be moved
todo: NEXT DEPLOY TO DEVOPS attach a photo from phone, no error just does nothing todo: NEXT DEPLOY TO DEVOPS attach a photo from phone, no error just does nothing
worked here locally latest build worked here locally latest build
retest on server after next deploy retest on server after next deploy

View File

@@ -195,6 +195,18 @@ export default {
params: { recordid: tid.id } params: { recordid: tid.id }
}); });
break; break;
case ayatype.ServiceRate:
vm.$router.push({
name: "service-rate-edit",
params: { recordid: tid.id }
});
break;
case ayatype.TravelRate:
vm.$router.push({
name: "travel-rate-edit",
params: { recordid: tid.id }
});
break;
default: default:
window.$gz.eventBus.$emit( window.$gz.eventBus.$emit(

View File

@@ -168,7 +168,8 @@ export default {
"Inventory", "Inventory",
"Accounting", "Accounting",
"TaxCodeList", "TaxCodeList",
"RateList", "ServiceRateList",
"TravelRateList",
"Administration", "Administration",
"Operations", "Operations",
"Attachments", "Attachments",

View File

@@ -0,0 +1,720 @@
<template>
<v-container fluid>
<gz-report-selector ref="reportSelector"></gz-report-selector>
<div v-if="formState.ready">
<gz-error :errorBoxMessage="formState.errorBoxMessage"></gz-error>
<v-form ref="form">
<v-row>
<v-col cols="12" sm="6" lg="4" xl="3">
<v-text-field
v-model="obj.name"
:readonly="formState.readOnly"
:label="$ay.t('Name')"
:rules="[form().required(this, 'name')]"
:error-messages="form().serverErrors(this, 'name')"
ref="name"
data-cy="name"
@input="fieldValueChanged('name')"
></v-text-field>
</v-col>
<v-col
v-if="form().showMe(this, 'Active')"
cols="12"
sm="6"
lg="4"
xl="3"
>
<v-checkbox
v-model="obj.active"
:readonly="formState.readOnly"
:label="$ay.t('Active')"
ref="active"
data-cy="active"
:error-messages="form().serverErrors(this, 'active')"
@change="fieldValueChanged('active')"
></v-checkbox>
</v-col>
<v-col
v-if="form().showMe(this, 'RateAccountNumber')"
cols="12"
sm="6"
lg="4"
xl="3"
>
<v-text-field
v-model="obj.accountNumber"
:readonly="formState.readOnly"
:label="$ay.t('RateAccountNumber')"
ref="accountNumber"
data-cy="accountNumber"
:error-messages="form().serverErrors(this, 'accountNumber')"
@input="fieldValueChanged('accountNumber')"
></v-text-field>
</v-col>
<v-col
v-if="form().showMe(this, 'RateCharge')"
cols="12"
sm="6"
lg="4"
xl="3"
>
<gz-currency
v-model="obj.charge"
:readonly="formState.readOnly"
:label="$ay.t('RateCharge')"
ref="charge"
data-cy="charge"
:rules="[
form().decimalValid(this, 'charge'),
form().required(this, 'charge')
]"
:error-messages="form().serverErrors(this, 'charge')"
@input="fieldValueChanged('charge')"
></gz-currency>
</v-col>
<v-col
v-if="form().showMe(this, 'Cost')"
cols="12"
sm="6"
lg="4"
xl="3"
>
<gz-currency
v-model="obj.cost"
:readonly="formState.readOnly"
:label="$ay.t('Cost')"
ref="cost"
data-cy="cost"
:rules="[
form().decimalValid(this, 'cost'),
form().required(this, 'cost')
]"
:error-messages="form().serverErrors(this, 'cost')"
@input="fieldValueChanged('cost')"
></gz-currency>
</v-col>
<v-col
v-if="form().showMe(this, 'RateUnitChargeDescriptionID')"
cols="12"
sm="6"
lg="4"
xl="3"
>
<v-text-field
v-model="obj.unit"
:readonly="formState.readOnly"
:label="$ay.t('RateUnitChargeDescriptionID')"
ref="unit"
data-cy="unit"
:error-messages="form().serverErrors(this, 'unit')"
@input="fieldValueChanged('unit')"
></v-text-field>
</v-col>
<!-- --------------------------------- -->
<v-col v-if="form().showMe(this, 'ServiceRateNotes')" cols="12">
<v-textarea
v-model="obj.notes"
:readonly="formState.readOnly"
:label="$ay.t('ServiceRateNotes')"
:error-messages="form().serverErrors(this, 'notes')"
ref="notes"
data-cy="notes"
@input="fieldValueChanged('notes')"
auto-grow
></v-textarea>
</v-col>
<v-col v-if="form().showMe(this, 'Tags')" cols="12">
<gz-tag-picker
v-model="obj.tags"
:readonly="formState.readOnly"
ref="tags"
data-cy="tags"
:error-messages="form().serverErrors(this, 'tags')"
@input="fieldValueChanged('tags')"
></gz-tag-picker>
</v-col>
<v-col cols="12">
<gz-custom-fields
v-model="obj.customFields"
:formKey="formCustomTemplateKey"
:readonly="formState.readOnly"
:parentVM="this"
ref="customFields"
data-cy="customFields"
:error-messages="form().serverErrors(this, 'customFields')"
@input="fieldValueChanged('customFields')"
></gz-custom-fields>
</v-col>
<v-col v-if="form().showMe(this, 'Wiki')" cols="12">
<gz-wiki
:ayaType="ayaType"
:ayaId="obj.id"
ref="wiki"
v-model="obj.wiki"
:readonly="formState.readOnly"
@input="fieldValueChanged('wiki')"
></gz-wiki
></v-col>
<v-col v-if="form().showMe(this, 'Attachments') && obj.id" cols="12">
<gz-attachments
:readonly="formState.readOnly"
:ayaType="ayaType"
:ayaId="obj.id"
></gz-attachments
></v-col>
</v-row>
</v-form>
</div>
<template v-if="!formState.ready">
<v-progress-circular
indeterminate
color="primary"
:size="60"
></v-progress-circular>
</template>
</v-container>
</template>
<script>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* Xeslint-disable */
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
const FORM_KEY = "service-rate-edit";
const API_BASE_URL = "service-rate/";
const FORM_CUSTOM_TEMPLATE_KEY = "ServiceRate"; //<-- Should always be CoreBizObject AyaType name here where possible
export default {
async created() {
let vm = this;
try {
await initForm(vm);
vm.rights = window.$gz.role.getRights(window.$gz.type.ServiceRate);
vm.formState.readOnly = !vm.rights.change;
window.$gz.eventBus.$on("menu-click", clickHandler);
//id 0 means create a new record don't load one
if (vm.$route.params.recordid != 0) {
//is there already an obj from a prior operation?
if (this.$route.params.obj) {
//yes, no need to fetch it
this.obj = this.$route.params.obj;
window.$gz.form.setFormState({
vm: vm,
loading: false
});
} else {
await vm.getDataFromApi(vm.$route.params.recordid); //let getdata handle loading
}
} else {
window.$gz.form.setFormState({
vm: vm,
loading: false
});
}
window.$gz.form.setFormState({
vm: vm,
dirty: false,
valid: true
});
generateMenu(vm);
} catch (error) {
window.$gz.errorHandler.handleFormError(error, vm);
} finally {
vm.formState.ready = true;
}
},
async beforeRouteLeave(to, from, next) {
if (!this.formState.dirty || JUST_DELETED) {
next();
return;
}
if ((await window.$gz.dialog.confirmLeaveUnsaved()) === true) {
next();
} else {
next(false);
}
},
beforeDestroy() {
window.$gz.eventBus.$off("menu-click", clickHandler);
},
data() {
return {
formCustomTemplateKey: FORM_CUSTOM_TEMPLATE_KEY,
obj:
//IMPORTANT NOTE: Fields that are NON NULLABLE in the schema for the table but *are* hideable **MUST** have a default value set here or else there will be no way to save the record
//I.E. Serial, usertype fields, ACTIVE
//Also, if it's a non-nullable Enum backed field then it should have a valid selection i.e. not zero if there is no zero
{
id: 0,
concurrency: 0,
name: null,
active: true,
notes: null,
wiki: null,
customFields: "{}",
tags: [],
cost: 0,
charge: 0,
unit: null,
accountNumber: null
},
tab: 0,
formState: {
ready: false,
dirty: false,
valid: true,
readOnly: false,
loading: true,
errorBoxMessage: null,
appError: null,
serverError: {}
},
rights: window.$gz.role.defaultRightsObject(),
ayaType: window.$gz.type.ServiceRate
};
},
//WATCHERS
watch: {
formState: {
handler: function(val) {
//,oldval is available here too if necessary
if (this.formState.loading) {
return;
}
//enable / disable save button
if (val.dirty && val.valid && !val.readOnly) {
window.$gz.eventBus.$emit("menu-enable-item", FORM_KEY + ":save");
} else {
window.$gz.eventBus.$emit("menu-disable-item", FORM_KEY + ":save");
}
//enable / disable duplicate / new button
if (!val.dirty && val.valid && !val.readOnly) {
window.$gz.eventBus.$emit(
"menu-enable-item",
FORM_KEY + ":duplicate"
);
window.$gz.eventBus.$emit("menu-enable-item", FORM_KEY + ":new");
} else {
window.$gz.eventBus.$emit(
"menu-disable-item",
FORM_KEY + ":duplicate"
);
window.$gz.eventBus.$emit("menu-disable-item", FORM_KEY + ":new");
}
},
deep: true
}
},
methods: {
canSave: function() {
return this.formState.valid && this.formState.dirty;
},
canDuplicate: function() {
return this.formState.valid && !this.formState.dirty;
},
ayaTypes: function() {
return window.$gz.type;
},
form() {
return window.$gz.form;
},
fieldValueChanged(ref) {
if (
this.formState.ready &&
!this.formState.loading &&
!this.formState.readOnly
) {
window.$gz.form.fieldValueChanged(this, ref);
}
},
async getDataFromApi(recordId) {
let vm = this;
window.$gz.form.setFormState({
vm: vm,
loading: true
});
if (!recordId) {
throw new Error(FORM_KEY + "::getDataFromApi -> Missing recordID!");
}
let url = API_BASE_URL + recordId;
try {
window.$gz.form.deleteAllErrorBoxErrors(vm);
let res = await window.$gz.api.get(url);
if (res.error) {
//Not found?
if (res.error.code == "2010") {
window.$gz.form.handleObjectNotFound(vm);
}
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
vm.obj = res.data;
//modify the menu as necessary
generateMenu(vm);
//Update the form status
window.$gz.form.setFormState({
vm: vm,
dirty: false,
valid: true,
loading: false
});
}
} catch (error) {
window.$gz.errorHandler.handleFormError(error, vm);
} finally {
window.$gz.form.setFormState({
vm: vm,
loading: false
});
}
},
async submit() {
let vm = this;
if (vm.canSave == false) {
return;
}
try {
window.$gz.form.setFormState({
vm: vm,
loading: true
});
let url = API_BASE_URL; // + vm.$route.params.recordid;
//clear any errors vm might be around from previous submit
window.$gz.form.deleteAllErrorBoxErrors(vm);
let res = await window.$gz.api.upsert(url, vm.obj);
if (res.error) {
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
//Logic for detecting if a post or put: if id then it was a post, if no id then it was a put
if (res.data.id) {
//POST - whole new object returned
vm.obj = res.data;
//Change URL to new record
//NOTE: will not cause a page re-render, almost nothing does unless forced with a KEY property or using router.GO()
this.$router.push({
name: "service-rate-edit",
params: {
recordid: res.data.id,
obj: res.data // Pass data object to new form
}
});
} else {
//PUT - only concurrency token is returned (**warning, if server changes object other fields then this needs to act more like POST above but is more efficient this way**)
//Handle "put" of an existing record (UPDATE)
vm.obj.concurrency = res.data.concurrency;
}
//Update the form status
window.$gz.form.setFormState({
vm: vm,
dirty: false,
valid: true
});
}
} catch (ex) {
window.$gz.errorHandler.handleFormError(ex, vm);
} finally {
window.$gz.form.setFormState({
vm: vm,
loading: false
});
}
},
async remove() {
let vm = this;
try {
let dialogResult = await window.$gz.dialog.confirmDelete();
if (dialogResult != true) {
return;
}
//do the delete
window.$gz.form.setFormState({
vm: vm,
loading: true
});
//No need to delete a new record, just abandon it...
if (vm.$route.params.recordid == 0) {
//this should not get offered for delete but to be safe and clear just in case:
JUST_DELETED = true;
// navigate backwards
vm.$router.go(-1);
} else {
let url = API_BASE_URL + vm.$route.params.recordid;
window.$gz.form.deleteAllErrorBoxErrors(vm);
let res = await window.$gz.api.remove(url);
if (res.error) {
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
//workaround to prevent warning about leaving dirty record
//For some reason I couldn't just reset isdirty in formstate
JUST_DELETED = true;
// navigate backwards
vm.$router.go(-1);
}
}
} catch (error) {
//Update the form status
window.$gz.form.setFormState({
vm: vm,
loading: false
});
window.$gz.errorHandler.handleFormError(error, vm);
}
},
async duplicate() {
let vm = this;
if (!vm.canDuplicate || vm.$route.params.recordid == 0) {
return;
}
window.$gz.form.setFormState({
vm: vm,
loading: true
});
let url = API_BASE_URL + "duplicate/" + vm.$route.params.recordid;
try {
window.$gz.form.deleteAllErrorBoxErrors(vm);
let res = await window.$gz.api.upsert(url);
if (res.error) {
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
//Navigate to new record
this.$router.push({
name: "service-rate-edit",
params: {
recordid: res.data.id,
obj: res.data // Pass data object to new form
}
});
}
} catch (ex) {
window.$gz.errorHandler.handleFormError(ex, vm);
} finally {
window.$gz.form.setFormState({
vm: vm,
loading: false
});
}
}
//end methods
}
};
/////////////////////////////
//
//
async function clickHandler(menuItem) {
if (!menuItem) {
return;
}
let m = window.$gz.menu.parseMenuItem(menuItem);
if (m.owner == FORM_KEY && !m.disabled) {
switch (m.key) {
case "save":
m.vm.submit();
break;
case "delete":
m.vm.remove();
break;
case "new":
m.vm.$router.push({
name: "service-rate-edit",
params: { recordid: 0, new: true }
});
break;
case "duplicate":
m.vm.duplicate();
break;
case "report":
if (m.id != null) {
//last report selected is in m.id
m.vm.$router.push({
name: "ay-report",
params: { recordid: m.id, ayatype: window.$gz.type.ServiceRate }
});
} else {
//general report selector chosen
let res = await m.vm.$refs.reportSelector.open({
ObjectType: window.$gz.type.ServiceRate,
selectedRowIds: [m.vm.obj.id]
});
//if null for no selection
//just bail out
if (res == null) {
return;
}
//persist last report selected
window.$gz.form.setLastReport(FORM_KEY, res);
//Now open the report viewer...
m.vm.$router.push({
name: "ay-report",
params: { recordid: res.id, ayatype: window.$gz.type.ServiceRate }
});
}
break;
default:
window.$gz.eventBus.$emit(
"notify-warning",
FORM_KEY + "::context click: [" + m.key + "]"
);
}
}
}
//////////////////////
//
//
function generateMenu(vm) {
let menuOptions = {
isMain: false,
readOnly: vm.formState.readOnly,
icon: "$ayiCalculator",
title: "ServiceRate",
helpUrl: "form-acc-service-rates",
formData: {
ayaType: window.$gz.type.ServiceRate,
recordId: vm.$route.params.recordid,
formCustomTemplateKey: FORM_CUSTOM_TEMPLATE_KEY,
recordName: vm.obj.name
},
menuItems: []
};
if (vm.rights.change) {
menuOptions.menuItems.push({
title: "Save",
icon: "$ayiSave",
surface: true,
key: FORM_KEY + ":save",
vm: vm
});
}
if (vm.rights.delete && vm.$route.params.recordid != 0) {
menuOptions.menuItems.push({
title: "Delete",
icon: "$ayiTrashAlt",
surface: false,
key: FORM_KEY + ":delete",
vm: vm
});
}
//REPORTS
//Report not Print, print is a further option
menuOptions.menuItems.push({
title: "Report",
icon: "$ayiFileAlt",
key: FORM_KEY + ":report",
vm: vm
});
//get last report selected
let lastReport = window.$gz.form.getLastReport(FORM_KEY);
if (lastReport != null) {
menuOptions.menuItems.push({
title: lastReport.name,
icon: "$ayiFileAlt",
key: FORM_KEY + ":report:" + lastReport.id,
vm: vm
});
}
if (vm.rights.change) {
menuOptions.menuItems.push({
title: "New",
icon: "$ayiPlus",
key: FORM_KEY + ":new",
vm: vm
});
}
if (vm.rights.change) {
menuOptions.menuItems.push({
title: "Duplicate",
icon: "$ayiClone",
key: FORM_KEY + ":duplicate",
vm: vm
});
}
menuOptions.menuItems.push({ divider: true, inset: false });
window.$gz.eventBus.$emit("menu-change", menuOptions);
}
let JUST_DELETED = false;
/////////////////////////////////
//
//
async function initForm(vm) {
await fetchTranslatedText(vm);
await window.$gz.formCustomTemplate.get(FORM_CUSTOM_TEMPLATE_KEY);
}
//////////////////////////////////////////////////////////
//
// Ensures UI translated text is available
//
async function fetchTranslatedText(vm) {
await window.$gz.translation.cacheTranslations([
"ServiceRate",
"Name",
"ServiceRateNotes",
"RateAccountNumber",
"Cost",
"RateCharge",
"RateUnitChargeDescriptionID",
"ServiceRateCustom1",
"ServiceRateCustom2",
"ServiceRateCustom3",
"ServiceRateCustom4",
"ServiceRateCustom5",
"ServiceRateCustom6",
"ServiceRateCustom7",
"ServiceRateCustom8",
"ServiceRateCustom9",
"ServiceRateCustom10",
"ServiceRateCustom11",
"ServiceRateCustom12",
"ServiceRateCustom13",
"ServiceRateCustom14",
"ServiceRateCustom15",
"ServiceRateCustom16"
]);
}
</script>

View File

@@ -0,0 +1,175 @@
<template>
<div>
<gz-report-selector ref="reportSelector"></gz-report-selector>
<gz-extensions
:ayaType="ayType"
:selectedItems="selectedItems"
ref="extensions"
>
</gz-extensions>
<gz-data-table
ref="gzdatatable"
formKey="service-rate-list"
:dataListKey="dataListKey"
:dataListFilter="dataListFilter"
:dataListSort="dataListSort"
:showSelect="rights.read"
:reload="reload"
v-on:selection-change="handleSelected"
data-cy="serviceRatesTable"
>
</gz-data-table>
</div>
</template>
<script>
const FORM_KEY = "service-rate-list";
export default {
created() {
this.rights = window.$gz.role.getRights(window.$gz.type.ServiceRate);
window.$gz.eventBus.$on("menu-click", clickHandler);
generateMenu(this);
},
beforeDestroy() {
window.$gz.eventBus.$off("menu-click", clickHandler);
},
data() {
return {
currentListViewId: 1,
dataListKey: "ServiceRateDataList",
dataListFilter: "",
dataListSort: "",
rights: window.$gz.role.defaultRightsObject(),
ayType: window.$gz.type.ServiceRate,
selectedItems: [],
reload: false
};
},
methods: {
handleSelected(selected) {
this.selectedItems = selected;
}
}
};
/////////////////////////////
//
//
async function clickHandler(menuItem) {
if (!menuItem) {
return;
}
let m = window.$gz.menu.parseMenuItem(menuItem);
if (m.owner == FORM_KEY && !m.disabled) {
switch (m.key) {
case "new":
m.vm.$router.push({
name: "service-rate-edit",
params: { recordid: 0 }
});
break;
case "extensions":
let res = await m.vm.$refs.extensions.open(
m.vm.$refs.gzdatatable.getDataListSelection(
window.$gz.type.ServiceRate
)
);
if (res && res.refresh == true) {
m.vm.reload = !m.vm.reload;
}
break;
case "report":
if (m.id != null) {
//last report selected is in m.id
m.vm.$router.push({
name: "ay-report",
params: { recordid: m.id, ayatype: window.$gz.type.ServiceRate }
});
} else {
//general report selector chosen
let res = await m.vm.$refs.reportSelector.open(
m.vm.$refs.gzdatatable.getDataListSelection(
window.$gz.type.ServiceRate
)
);
//if null for no selection
//just bail out
if (res == null) {
return;
}
//persist last report selected
window.$gz.form.setLastReport(FORM_KEY, res);
//Now open the report viewer...
m.vm.$router.push({
name: "ay-report",
params: { recordid: res.id, ayatype: window.$gz.type.ServiceRate }
});
}
break;
default:
window.$gz.eventBus.$emit(
"notify-warning",
FORM_KEY + "::context click: [" + m.key + "]"
);
}
}
}
//////////////////////
//
//
function generateMenu(vm) {
let menuOptions = {
isMain: true,
icon: "$ayiCalculator",
title: "ServiceRateList",
helpUrl: "form-acc-service-rates",
menuItems: [],
formData: {
ayaType: window.$gz.type.ServiceRate
}
};
if (vm.rights.change) {
menuOptions.menuItems.push({
title: "New",
icon: "$ayiPlus",
surface: true,
key: FORM_KEY + ":new",
vm: vm
});
}
//REPORTS
//Report not Print, print is a further option
menuOptions.menuItems.push({
title: "Report",
icon: "$ayiFileAlt",
key: FORM_KEY + ":report",
vm: vm
});
//get last report selected
let lastReport = window.$gz.form.getLastReport(FORM_KEY);
if (lastReport != null) {
menuOptions.menuItems.push({
title: lastReport.name,
icon: "$ayiFileAlt",
key: FORM_KEY + ":report:" + lastReport.id,
vm: vm
});
}
menuOptions.menuItems.push({
title: "Extensions",
icon: "$ayiPuzzlePiece",
key: FORM_KEY + ":extensions",
vm: vm
});
window.$gz.eventBus.$emit("menu-change", menuOptions);
}
</script>

View File

@@ -0,0 +1,21 @@
<template>
<UnderConstruction data-cy="underconstruction" />
</template>
<script>
import UnderConstruction from "../components/underconstruction.vue";
export default {
components: {
UnderConstruction
},
beforeCreate() {
window.$gz.eventBus.$emit("menu-change", {
isMain: true,
icon: "$ayiCalculator",
title: "Accounting",
helpUrl: "form-acc-accounting"
});
}
};
</script>

View File

@@ -0,0 +1,21 @@
<template>
<UnderConstruction data-cy="underconstruction" />
</template>
<script>
import UnderConstruction from "../components/underconstruction.vue";
export default {
components: {
UnderConstruction
},
beforeCreate() {
window.$gz.eventBus.$emit("menu-change", {
isMain: true,
icon: "$ayiCalculator",
title: "Accounting",
helpUrl: "form-acc-accounting"
});
}
};
</script>

View File

@@ -0,0 +1,720 @@
<template>
<v-container fluid>
<gz-report-selector ref="reportSelector"></gz-report-selector>
<div v-if="formState.ready">
<gz-error :errorBoxMessage="formState.errorBoxMessage"></gz-error>
<v-form ref="form">
<v-row>
<v-col cols="12" sm="6" lg="4" xl="3">
<v-text-field
v-model="obj.name"
:readonly="formState.readOnly"
:label="$ay.t('Name')"
:rules="[form().required(this, 'name')]"
:error-messages="form().serverErrors(this, 'name')"
ref="name"
data-cy="name"
@input="fieldValueChanged('name')"
></v-text-field>
</v-col>
<v-col
v-if="form().showMe(this, 'Active')"
cols="12"
sm="6"
lg="4"
xl="3"
>
<v-checkbox
v-model="obj.active"
:readonly="formState.readOnly"
:label="$ay.t('Active')"
ref="active"
data-cy="active"
:error-messages="form().serverErrors(this, 'active')"
@change="fieldValueChanged('active')"
></v-checkbox>
</v-col>
<v-col
v-if="form().showMe(this, 'RateAccountNumber')"
cols="12"
sm="6"
lg="4"
xl="3"
>
<v-text-field
v-model="obj.accountNumber"
:readonly="formState.readOnly"
:label="$ay.t('RateAccountNumber')"
ref="accountNumber"
data-cy="accountNumber"
:error-messages="form().serverErrors(this, 'accountNumber')"
@input="fieldValueChanged('accountNumber')"
></v-text-field>
</v-col>
<v-col
v-if="form().showMe(this, 'RateCharge')"
cols="12"
sm="6"
lg="4"
xl="3"
>
<gz-currency
v-model="obj.charge"
:readonly="formState.readOnly"
:label="$ay.t('RateCharge')"
ref="charge"
data-cy="charge"
:rules="[
form().decimalValid(this, 'charge'),
form().required(this, 'charge')
]"
:error-messages="form().serverErrors(this, 'charge')"
@input="fieldValueChanged('charge')"
></gz-currency>
</v-col>
<v-col
v-if="form().showMe(this, 'Cost')"
cols="12"
sm="6"
lg="4"
xl="3"
>
<gz-currency
v-model="obj.cost"
:readonly="formState.readOnly"
:label="$ay.t('Cost')"
ref="cost"
data-cy="cost"
:rules="[
form().decimalValid(this, 'cost'),
form().required(this, 'cost')
]"
:error-messages="form().serverErrors(this, 'cost')"
@input="fieldValueChanged('cost')"
></gz-currency>
</v-col>
<v-col
v-if="form().showMe(this, 'RateUnitChargeDescriptionID')"
cols="12"
sm="6"
lg="4"
xl="3"
>
<v-text-field
v-model="obj.unit"
:readonly="formState.readOnly"
:label="$ay.t('RateUnitChargeDescriptionID')"
ref="unit"
data-cy="unit"
:error-messages="form().serverErrors(this, 'unit')"
@input="fieldValueChanged('unit')"
></v-text-field>
</v-col>
<!-- --------------------------------- -->
<v-col v-if="form().showMe(this, 'TravelRateNotes')" cols="12">
<v-textarea
v-model="obj.notes"
:readonly="formState.readOnly"
:label="$ay.t('TravelRateNotes')"
:error-messages="form().serverErrors(this, 'notes')"
ref="notes"
data-cy="notes"
@input="fieldValueChanged('notes')"
auto-grow
></v-textarea>
</v-col>
<v-col v-if="form().showMe(this, 'Tags')" cols="12">
<gz-tag-picker
v-model="obj.tags"
:readonly="formState.readOnly"
ref="tags"
data-cy="tags"
:error-messages="form().serverErrors(this, 'tags')"
@input="fieldValueChanged('tags')"
></gz-tag-picker>
</v-col>
<v-col cols="12">
<gz-custom-fields
v-model="obj.customFields"
:formKey="formCustomTemplateKey"
:readonly="formState.readOnly"
:parentVM="this"
ref="customFields"
data-cy="customFields"
:error-messages="form().serverErrors(this, 'customFields')"
@input="fieldValueChanged('customFields')"
></gz-custom-fields>
</v-col>
<v-col v-if="form().showMe(this, 'Wiki')" cols="12">
<gz-wiki
:ayaType="ayaType"
:ayaId="obj.id"
ref="wiki"
v-model="obj.wiki"
:readonly="formState.readOnly"
@input="fieldValueChanged('wiki')"
></gz-wiki
></v-col>
<v-col v-if="form().showMe(this, 'Attachments') && obj.id" cols="12">
<gz-attachments
:readonly="formState.readOnly"
:ayaType="ayaType"
:ayaId="obj.id"
></gz-attachments
></v-col>
</v-row>
</v-form>
</div>
<template v-if="!formState.ready">
<v-progress-circular
indeterminate
color="primary"
:size="60"
></v-progress-circular>
</template>
</v-container>
</template>
<script>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* Xeslint-disable */
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
const FORM_KEY = "travel-rate-edit";
const API_BASE_URL = "travel-rate/";
const FORM_CUSTOM_TEMPLATE_KEY = "TravelRate"; //<-- Should always be CoreBizObject AyaType name here where possible
export default {
async created() {
let vm = this;
try {
await initForm(vm);
vm.rights = window.$gz.role.getRights(window.$gz.type.TravelRate);
vm.formState.readOnly = !vm.rights.change;
window.$gz.eventBus.$on("menu-click", clickHandler);
//id 0 means create a new record don't load one
if (vm.$route.params.recordid != 0) {
//is there already an obj from a prior operation?
if (this.$route.params.obj) {
//yes, no need to fetch it
this.obj = this.$route.params.obj;
window.$gz.form.setFormState({
vm: vm,
loading: false
});
} else {
await vm.getDataFromApi(vm.$route.params.recordid); //let getdata handle loading
}
} else {
window.$gz.form.setFormState({
vm: vm,
loading: false
});
}
window.$gz.form.setFormState({
vm: vm,
dirty: false,
valid: true
});
generateMenu(vm);
} catch (error) {
window.$gz.errorHandler.handleFormError(error, vm);
} finally {
vm.formState.ready = true;
}
},
async beforeRouteLeave(to, from, next) {
if (!this.formState.dirty || JUST_DELETED) {
next();
return;
}
if ((await window.$gz.dialog.confirmLeaveUnsaved()) === true) {
next();
} else {
next(false);
}
},
beforeDestroy() {
window.$gz.eventBus.$off("menu-click", clickHandler);
},
data() {
return {
formCustomTemplateKey: FORM_CUSTOM_TEMPLATE_KEY,
obj:
//IMPORTANT NOTE: Fields that are NON NULLABLE in the schema for the table but *are* hideable **MUST** have a default value set here or else there will be no way to save the record
//I.E. Serial, usertype fields, ACTIVE
//Also, if it's a non-nullable Enum backed field then it should have a valid selection i.e. not zero if there is no zero
{
id: 0,
concurrency: 0,
name: null,
active: true,
notes: null,
wiki: null,
customFields: "{}",
tags: [],
cost: 0,
charge: 0,
unit: null,
accountNumber: null
},
tab: 0,
formState: {
ready: false,
dirty: false,
valid: true,
readOnly: false,
loading: true,
errorBoxMessage: null,
appError: null,
serverError: {}
},
rights: window.$gz.role.defaultRightsObject(),
ayaType: window.$gz.type.TravelRate
};
},
//WATCHERS
watch: {
formState: {
handler: function(val) {
//,oldval is available here too if necessary
if (this.formState.loading) {
return;
}
//enable / disable save button
if (val.dirty && val.valid && !val.readOnly) {
window.$gz.eventBus.$emit("menu-enable-item", FORM_KEY + ":save");
} else {
window.$gz.eventBus.$emit("menu-disable-item", FORM_KEY + ":save");
}
//enable / disable duplicate / new button
if (!val.dirty && val.valid && !val.readOnly) {
window.$gz.eventBus.$emit(
"menu-enable-item",
FORM_KEY + ":duplicate"
);
window.$gz.eventBus.$emit("menu-enable-item", FORM_KEY + ":new");
} else {
window.$gz.eventBus.$emit(
"menu-disable-item",
FORM_KEY + ":duplicate"
);
window.$gz.eventBus.$emit("menu-disable-item", FORM_KEY + ":new");
}
},
deep: true
}
},
methods: {
canSave: function() {
return this.formState.valid && this.formState.dirty;
},
canDuplicate: function() {
return this.formState.valid && !this.formState.dirty;
},
ayaTypes: function() {
return window.$gz.type;
},
form() {
return window.$gz.form;
},
fieldValueChanged(ref) {
if (
this.formState.ready &&
!this.formState.loading &&
!this.formState.readOnly
) {
window.$gz.form.fieldValueChanged(this, ref);
}
},
async getDataFromApi(recordId) {
let vm = this;
window.$gz.form.setFormState({
vm: vm,
loading: true
});
if (!recordId) {
throw new Error(FORM_KEY + "::getDataFromApi -> Missing recordID!");
}
let url = API_BASE_URL + recordId;
try {
window.$gz.form.deleteAllErrorBoxErrors(vm);
let res = await window.$gz.api.get(url);
if (res.error) {
//Not found?
if (res.error.code == "2010") {
window.$gz.form.handleObjectNotFound(vm);
}
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
vm.obj = res.data;
//modify the menu as necessary
generateMenu(vm);
//Update the form status
window.$gz.form.setFormState({
vm: vm,
dirty: false,
valid: true,
loading: false
});
}
} catch (error) {
window.$gz.errorHandler.handleFormError(error, vm);
} finally {
window.$gz.form.setFormState({
vm: vm,
loading: false
});
}
},
async submit() {
let vm = this;
if (vm.canSave == false) {
return;
}
try {
window.$gz.form.setFormState({
vm: vm,
loading: true
});
let url = API_BASE_URL; // + vm.$route.params.recordid;
//clear any errors vm might be around from previous submit
window.$gz.form.deleteAllErrorBoxErrors(vm);
let res = await window.$gz.api.upsert(url, vm.obj);
if (res.error) {
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
//Logic for detecting if a post or put: if id then it was a post, if no id then it was a put
if (res.data.id) {
//POST - whole new object returned
vm.obj = res.data;
//Change URL to new record
//NOTE: will not cause a page re-render, almost nothing does unless forced with a KEY property or using router.GO()
this.$router.push({
name: "travel-rate-edit",
params: {
recordid: res.data.id,
obj: res.data // Pass data object to new form
}
});
} else {
//PUT - only concurrency token is returned (**warning, if server changes object other fields then this needs to act more like POST above but is more efficient this way**)
//Handle "put" of an existing record (UPDATE)
vm.obj.concurrency = res.data.concurrency;
}
//Update the form status
window.$gz.form.setFormState({
vm: vm,
dirty: false,
valid: true
});
}
} catch (ex) {
window.$gz.errorHandler.handleFormError(ex, vm);
} finally {
window.$gz.form.setFormState({
vm: vm,
loading: false
});
}
},
async remove() {
let vm = this;
try {
let dialogResult = await window.$gz.dialog.confirmDelete();
if (dialogResult != true) {
return;
}
//do the delete
window.$gz.form.setFormState({
vm: vm,
loading: true
});
//No need to delete a new record, just abandon it...
if (vm.$route.params.recordid == 0) {
//this should not get offered for delete but to be safe and clear just in case:
JUST_DELETED = true;
// navigate backwards
vm.$router.go(-1);
} else {
let url = API_BASE_URL + vm.$route.params.recordid;
window.$gz.form.deleteAllErrorBoxErrors(vm);
let res = await window.$gz.api.remove(url);
if (res.error) {
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
//workaround to prevent warning about leaving dirty record
//For some reason I couldn't just reset isdirty in formstate
JUST_DELETED = true;
// navigate backwards
vm.$router.go(-1);
}
}
} catch (error) {
//Update the form status
window.$gz.form.setFormState({
vm: vm,
loading: false
});
window.$gz.errorHandler.handleFormError(error, vm);
}
},
async duplicate() {
let vm = this;
if (!vm.canDuplicate || vm.$route.params.recordid == 0) {
return;
}
window.$gz.form.setFormState({
vm: vm,
loading: true
});
let url = API_BASE_URL + "duplicate/" + vm.$route.params.recordid;
try {
window.$gz.form.deleteAllErrorBoxErrors(vm);
let res = await window.$gz.api.upsert(url);
if (res.error) {
vm.formState.serverError = res.error;
window.$gz.form.setErrorBoxErrors(vm);
} else {
//Navigate to new record
this.$router.push({
name: "travel-rate-edit",
params: {
recordid: res.data.id,
obj: res.data // Pass data object to new form
}
});
}
} catch (ex) {
window.$gz.errorHandler.handleFormError(ex, vm);
} finally {
window.$gz.form.setFormState({
vm: vm,
loading: false
});
}
}
//end methods
}
};
/////////////////////////////
//
//
async function clickHandler(menuItem) {
if (!menuItem) {
return;
}
let m = window.$gz.menu.parseMenuItem(menuItem);
if (m.owner == FORM_KEY && !m.disabled) {
switch (m.key) {
case "save":
m.vm.submit();
break;
case "delete":
m.vm.remove();
break;
case "new":
m.vm.$router.push({
name: "travel-rate-edit",
params: { recordid: 0, new: true }
});
break;
case "duplicate":
m.vm.duplicate();
break;
case "report":
if (m.id != null) {
//last report selected is in m.id
m.vm.$router.push({
name: "ay-report",
params: { recordid: m.id, ayatype: window.$gz.type.TravelRate }
});
} else {
//general report selector chosen
let res = await m.vm.$refs.reportSelector.open({
ObjectType: window.$gz.type.TravelRate,
selectedRowIds: [m.vm.obj.id]
});
//if null for no selection
//just bail out
if (res == null) {
return;
}
//persist last report selected
window.$gz.form.setLastReport(FORM_KEY, res);
//Now open the report viewer...
m.vm.$router.push({
name: "ay-report",
params: { recordid: res.id, ayatype: window.$gz.type.TravelRate }
});
}
break;
default:
window.$gz.eventBus.$emit(
"notify-warning",
FORM_KEY + "::context click: [" + m.key + "]"
);
}
}
}
//////////////////////
//
//
function generateMenu(vm) {
let menuOptions = {
isMain: false,
readOnly: vm.formState.readOnly,
icon: "$ayiCalculator",
title: "TravelRate",
helpUrl: "form-acc-travel-rates",
formData: {
ayaType: window.$gz.type.TravelRate,
recordId: vm.$route.params.recordid,
formCustomTemplateKey: FORM_CUSTOM_TEMPLATE_KEY,
recordName: vm.obj.name
},
menuItems: []
};
if (vm.rights.change) {
menuOptions.menuItems.push({
title: "Save",
icon: "$ayiSave",
surface: true,
key: FORM_KEY + ":save",
vm: vm
});
}
if (vm.rights.delete && vm.$route.params.recordid != 0) {
menuOptions.menuItems.push({
title: "Delete",
icon: "$ayiTrashAlt",
surface: false,
key: FORM_KEY + ":delete",
vm: vm
});
}
//REPORTS
//Report not Print, print is a further option
menuOptions.menuItems.push({
title: "Report",
icon: "$ayiFileAlt",
key: FORM_KEY + ":report",
vm: vm
});
//get last report selected
let lastReport = window.$gz.form.getLastReport(FORM_KEY);
if (lastReport != null) {
menuOptions.menuItems.push({
title: lastReport.name,
icon: "$ayiFileAlt",
key: FORM_KEY + ":report:" + lastReport.id,
vm: vm
});
}
if (vm.rights.change) {
menuOptions.menuItems.push({
title: "New",
icon: "$ayiPlus",
key: FORM_KEY + ":new",
vm: vm
});
}
if (vm.rights.change) {
menuOptions.menuItems.push({
title: "Duplicate",
icon: "$ayiClone",
key: FORM_KEY + ":duplicate",
vm: vm
});
}
menuOptions.menuItems.push({ divider: true, inset: false });
window.$gz.eventBus.$emit("menu-change", menuOptions);
}
let JUST_DELETED = false;
/////////////////////////////////
//
//
async function initForm(vm) {
await fetchTranslatedText(vm);
await window.$gz.formCustomTemplate.get(FORM_CUSTOM_TEMPLATE_KEY);
}
//////////////////////////////////////////////////////////
//
// Ensures UI translated text is available
//
async function fetchTranslatedText(vm) {
await window.$gz.translation.cacheTranslations([
"TravelRate",
"Name",
"TravelRateNotes",
"RateAccountNumber",
"Cost",
"RateCharge",
"RateUnitChargeDescriptionID",
"TravelRateCustom1",
"TravelRateCustom2",
"TravelRateCustom3",
"TravelRateCustom4",
"TravelRateCustom5",
"TravelRateCustom6",
"TravelRateCustom7",
"TravelRateCustom8",
"TravelRateCustom9",
"TravelRateCustom10",
"TravelRateCustom11",
"TravelRateCustom12",
"TravelRateCustom13",
"TravelRateCustom14",
"TravelRateCustom15",
"TravelRateCustom16"
]);
}
</script>

View File

@@ -0,0 +1,175 @@
<template>
<div>
<gz-report-selector ref="reportSelector"></gz-report-selector>
<gz-extensions
:ayaType="ayType"
:selectedItems="selectedItems"
ref="extensions"
>
</gz-extensions>
<gz-data-table
ref="gzdatatable"
formKey="travel-rate-list"
:dataListKey="dataListKey"
:dataListFilter="dataListFilter"
:dataListSort="dataListSort"
:showSelect="rights.read"
:reload="reload"
v-on:selection-change="handleSelected"
data-cy="travelRatesTable"
>
</gz-data-table>
</div>
</template>
<script>
const FORM_KEY = "travel-rate-list";
export default {
created() {
this.rights = window.$gz.role.getRights(window.$gz.type.TravelRate);
window.$gz.eventBus.$on("menu-click", clickHandler);
generateMenu(this);
},
beforeDestroy() {
window.$gz.eventBus.$off("menu-click", clickHandler);
},
data() {
return {
currentListViewId: 1,
dataListKey: "TravelRateDataList",
dataListFilter: "",
dataListSort: "",
rights: window.$gz.role.defaultRightsObject(),
ayType: window.$gz.type.TravelRate,
selectedItems: [],
reload: false
};
},
methods: {
handleSelected(selected) {
this.selectedItems = selected;
}
}
};
/////////////////////////////
//
//
async function clickHandler(menuItem) {
if (!menuItem) {
return;
}
let m = window.$gz.menu.parseMenuItem(menuItem);
if (m.owner == FORM_KEY && !m.disabled) {
switch (m.key) {
case "new":
m.vm.$router.push({
name: "travel-rate-edit",
params: { recordid: 0 }
});
break;
case "extensions":
let res = await m.vm.$refs.extensions.open(
m.vm.$refs.gzdatatable.getDataListSelection(
window.$gz.type.TravelRate
)
);
if (res && res.refresh == true) {
m.vm.reload = !m.vm.reload;
}
break;
case "report":
if (m.id != null) {
//last report selected is in m.id
m.vm.$router.push({
name: "ay-report",
params: { recordid: m.id, ayatype: window.$gz.type.TravelRate }
});
} else {
//general report selector chosen
let res = await m.vm.$refs.reportSelector.open(
m.vm.$refs.gzdatatable.getDataListSelection(
window.$gz.type.TravelRate
)
);
//if null for no selection
//just bail out
if (res == null) {
return;
}
//persist last report selected
window.$gz.form.setLastReport(FORM_KEY, res);
//Now open the report viewer...
m.vm.$router.push({
name: "ay-report",
params: { recordid: res.id, ayatype: window.$gz.type.TravelRate }
});
}
break;
default:
window.$gz.eventBus.$emit(
"notify-warning",
FORM_KEY + "::context click: [" + m.key + "]"
);
}
}
}
//////////////////////
//
//
function generateMenu(vm) {
let menuOptions = {
isMain: true,
icon: "$ayiCalculator",
title: "TravelRateList",
helpUrl: "form-acc-travel-rates",
menuItems: [],
formData: {
ayaType: window.$gz.type.TravelRate
}
};
if (vm.rights.change) {
menuOptions.menuItems.push({
title: "New",
icon: "$ayiPlus",
surface: true,
key: FORM_KEY + ":new",
vm: vm
});
}
//REPORTS
//Report not Print, print is a further option
menuOptions.menuItems.push({
title: "Report",
icon: "$ayiFileAlt",
key: FORM_KEY + ":report",
vm: vm
});
//get last report selected
let lastReport = window.$gz.form.getLastReport(FORM_KEY);
if (lastReport != null) {
menuOptions.menuItems.push({
title: lastReport.name,
icon: "$ayiFileAlt",
key: FORM_KEY + ":report:" + lastReport.id,
vm: vm
});
}
menuOptions.menuItems.push({
title: "Extensions",
icon: "$ayiPuzzlePiece",
key: FORM_KEY + ":extensions",
vm: vm
});
window.$gz.eventBus.$emit("menu-change", menuOptions);
}
</script>

View File

@@ -520,87 +520,7 @@ export default {
loading: false loading: false
}); });
} }
},
AddressCopyToPostal() {
let vm = this;
vm.obj.postAddress = vm.obj.address;
vm.obj.postCity = vm.obj.city;
vm.obj.postRegion = vm.obj.region;
vm.obj.postCountry = vm.obj.country;
},
AddressCopyToPhysical() {
let vm = this;
vm.obj.address = vm.obj.postAddress;
vm.obj.city = vm.obj.postCity;
vm.obj.region = vm.obj.postRegion;
vm.obj.country = vm.obj.postCountry;
},
AddressCopyPhysicalToClipBoard() {
let vm = this;
let ret = "";
if (vm.obj.name) {
ret += vm.obj.name + "\n";
}
if (vm.obj.address) {
ret += vm.obj.address + "\n";
}
if (vm.obj.city) {
ret += vm.obj.city + " ";
}
if (vm.obj.region) {
ret += vm.obj.region + " ";
}
if (vm.obj.country) {
ret += vm.obj.country + "\n";
}
window.$gz.util.copyToClipboard(ret);
},
AddressCopyPostalToClipBoard() {
let vm = this;
let ret = "";
if (vm.obj.name) {
ret += vm.obj.name + "\n";
}
if (vm.obj.postAddress) {
ret += vm.obj.postAddress + "\n";
}
if (vm.obj.postCity) {
ret += vm.obj.postCity + " ";
}
if (vm.obj.postRegion) {
ret += vm.obj.postRegion + " ";
}
if (vm.obj.postCode) {
//Postal codes should have two spaces before them according to regs.
ret += " " + vm.obj.postCode + "\n";
}
if (vm.obj.postCountry) {
ret += vm.obj.postCountry + "\n";
}
window.$gz.util.copyToClipboard(ret);
},
async GeoCapture() {
let vm = this;
try {
window.$gz.form.deleteAllErrorBoxErrors(vm);
let loc = await window.$gz.util.getGeoLocation();
vm.obj.latitude = loc.latitude;
vm.fieldValueChanged("latitude");
vm.obj.longitude = loc.longitude;
vm.fieldValueChanged("longitude");
} catch (ex) {
window.$gz.errorHandler.handleFormError(ex, vm);
}
} }
//end methods //end methods
} }
}; };
@@ -661,17 +581,6 @@ async function clickHandler(menuItem) {
} }
break; break;
case "geoview":
window.$gz.util.viewGeoLocation({
latitude: m.vm.obj.latitude,
longitude: m.vm.obj.longitude,
address: m.vm.obj.address || m.vm.obj.postAddress,
city: m.vm.obj.city || m.vm.obj.postCity,
region: m.vm.obj.region || m.vm.obj.postRegion,
country: m.vm.obj.country || m.vm.obj.postCountry,
postCode: m.vm.obj.postCode
});
break;
default: default:
window.$gz.eventBus.$emit( window.$gz.eventBus.$emit(
"notify-warning", "notify-warning",