1212 lines
32 KiB
Vue
1212 lines
32 KiB
Vue
<template>
|
|
<div>
|
|
<gz-report-selector ref="reportSelector"></gz-report-selector>
|
|
<div v-if="formState.ready">
|
|
<gz-error :error-box-message="formState.errorBoxMessage"></gz-error>
|
|
<v-form ref="form">
|
|
<GzWoHeader
|
|
v-model="obj"
|
|
:form-key="formCustomTemplateKey"
|
|
:readonly="formState.readOnly"
|
|
:pvm="this"
|
|
data-cy="woHeader"
|
|
@change="setDirty()"
|
|
/>
|
|
<GzWoItems
|
|
v-model="obj"
|
|
:form-key="formCustomTemplateKey"
|
|
:readonly="formState.readOnly"
|
|
:pvm="this"
|
|
data-cy="woItems"
|
|
@change="setDirty()"
|
|
@graph-item-deleted="flagGraphItemForDelete($event)"
|
|
/>
|
|
</v-form>
|
|
</div>
|
|
<template v-if="!formState.ready">
|
|
<v-progress-circular
|
|
indeterminate
|
|
color="primary"
|
|
:size="60"
|
|
></v-progress-circular>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/* Xeslint-disable */
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
import GzWoHeader from "../components/work-order-header.vue";
|
|
import GzWoItems from "../components/work-order-items.vue";
|
|
|
|
const FORM_KEY = "workorder-edit";
|
|
const API_BASE_URL = "workorder/";
|
|
const FORM_CUSTOM_TEMPLATE_KEY = "WorkOrder"; //<-- Should always be CoreBizObject AyaType name here where possible
|
|
|
|
export default {
|
|
components: {
|
|
GzWoHeader,
|
|
GzWoItems
|
|
},
|
|
async created() {
|
|
let vm = this;
|
|
|
|
try {
|
|
await initForm(vm);
|
|
|
|
vm.rights = window.$gz.role.getRights(window.$gz.type.WorkOrder);
|
|
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
|
|
});
|
|
//preset object so do things normally done in getdata
|
|
generateMenu(vm);
|
|
//update which areas are available to user
|
|
setSubRights(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: {
|
|
id: 0,
|
|
concurrency: 0,
|
|
serial: 0,
|
|
notes: null,
|
|
wiki: null,
|
|
customFields: "{}",
|
|
tags: [],
|
|
customerId: null,
|
|
projectId: null,
|
|
internalReferenceNumber: null,
|
|
customerReferenceNumber: null,
|
|
customerContactName: null,
|
|
fromQuoteId: null,
|
|
fromPMId: null,
|
|
fromCSRId: null,
|
|
serviceDate: null,
|
|
completeByDate: null,
|
|
invoiceNumber: null,
|
|
customerSignature: null,
|
|
customerSignatureName: null,
|
|
customerSignatureCaptured: null,
|
|
postAddress: null,
|
|
postCity: null,
|
|
postRegion: null,
|
|
postCountry: null,
|
|
postCode: null,
|
|
address: null,
|
|
city: null,
|
|
region: null,
|
|
country: null,
|
|
latitude: null,
|
|
longitude: null,
|
|
items: [],
|
|
states: [],
|
|
isDirty: false,
|
|
isLockedAtServer: false
|
|
},
|
|
formState: {
|
|
ready: false,
|
|
dirty: false,
|
|
valid: true,
|
|
readOnly: false,
|
|
loading: true,
|
|
errorBoxMessage: null,
|
|
appError: null,
|
|
serverError: {}
|
|
},
|
|
rights: window.$gz.role.defaultRightsObject(), //overall workorder rights, supersedes subrights
|
|
ayaType: window.$gz.type.WorkOrder,
|
|
currencyName: window.$gz.locale.getCurrencyName(),
|
|
timeZoneName: window.$gz.locale.getResolvedTimeZoneName(),
|
|
languageName: window.$gz.locale.getResolvedLanguage(),
|
|
hour12: window.$gz.locale.getHour12(),
|
|
deletedGraphItems: { items: [], scheduledUsers: [] }, //todo: other grandchildren
|
|
selectLists: {
|
|
wostatus: [],
|
|
allowedwostatus: []
|
|
},
|
|
subRights: {
|
|
items: {
|
|
visible: true,
|
|
create: true,
|
|
change: true,
|
|
delete: true
|
|
},
|
|
states: {
|
|
visible: true,
|
|
create: true, //no change, only create it's write only
|
|
delete: true
|
|
},
|
|
labors: {
|
|
visible: true,
|
|
create: true,
|
|
change: true,
|
|
delete: true
|
|
},
|
|
parts: {
|
|
visible: true,
|
|
create: true,
|
|
change: true,
|
|
delete: true
|
|
},
|
|
partRequests: {
|
|
visible: true,
|
|
create: true,
|
|
change: true,
|
|
delete: true
|
|
},
|
|
expenses: {
|
|
visible: true,
|
|
create: true,
|
|
change: true,
|
|
delete: true
|
|
},
|
|
loans: {
|
|
visible: true,
|
|
create: true,
|
|
change: true,
|
|
delete: true
|
|
},
|
|
scheduledUsers: {
|
|
visible: true,
|
|
create: true,
|
|
change: true,
|
|
delete: true
|
|
},
|
|
tasks: {
|
|
visible: true,
|
|
create: true,
|
|
change: true,
|
|
delete: true
|
|
},
|
|
travels: {
|
|
visible: true,
|
|
create: true,
|
|
change: true,
|
|
delete: true
|
|
},
|
|
units: {
|
|
visible: true,
|
|
create: true,
|
|
change: true,
|
|
delete: true
|
|
},
|
|
outsideServices: {
|
|
visible: true,
|
|
create: true,
|
|
change: true,
|
|
delete: true
|
|
}
|
|
}
|
|
};
|
|
},
|
|
//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
|
|
}
|
|
},
|
|
computed: {
|
|
currentState() {
|
|
//return actual status object from top level shell based on current state
|
|
//if state is unknown then it should return a placeholder dummy state showing an error condition or empty I guess
|
|
|
|
if (this.obj.states != null && this.obj.states.length > 0) {
|
|
//find it in the status collection
|
|
//and return here
|
|
let laststate = this.obj.states[this.obj.states.length - 1];
|
|
let found = this.selectLists.wostatus.find(
|
|
z => z.id == laststate.workOrderStatusId
|
|
);
|
|
if (found) {
|
|
return found;
|
|
}
|
|
}
|
|
//default
|
|
return {
|
|
id: 0,
|
|
name: "NOT SET YET",
|
|
active: true,
|
|
color: "#ffffff", //invisible
|
|
completed: false,
|
|
locked: false
|
|
};
|
|
}
|
|
},
|
|
methods: {
|
|
flagGraphItemForDelete: function(item) {
|
|
switch (item.atype) {
|
|
case window.$gz.type.WorkOrderItem:
|
|
this.deletedGraphItems.items.push(item.id);
|
|
break;
|
|
case window.$gz.type.WorkOrderItemScheduledUser:
|
|
this.deletedGraphItems.scheduledUsers.push(item.id);
|
|
break;
|
|
|
|
//todo: other grandchildren
|
|
}
|
|
this.setDirty();
|
|
},
|
|
setDirty: function() {
|
|
this.formState.dirty = true;
|
|
},
|
|
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 which areas are available to user
|
|
setSubRights(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);
|
|
|
|
//#######################################################
|
|
// ███████╗ █████╗ ██╗ ██╗███████╗
|
|
// ██╔════╝██╔══██╗██║ ██║██╔════╝
|
|
// ███████╗███████║██║ ██║█████╗
|
|
// ╚════██║██╔══██║╚██╗ ██╔╝██╔══╝
|
|
// ███████║██║ ██║ ╚████╔╝ ███████╗
|
|
// ╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚══════╝
|
|
//walk the tree and save dirty
|
|
//items in correct order
|
|
//########################################################
|
|
let noProblem = true;
|
|
|
|
//UNSAVED HEADER MUST BE FIRST
|
|
//(otherwise there's nothing to hang the other things off of)
|
|
let headerSaved = false;
|
|
if (this.obj.concurrency == 0) {
|
|
noProblem = await saveHeader(vm);
|
|
headerSaved = true;
|
|
}
|
|
|
|
//LOCKED? State must be saved first then (assuming it unlocks)
|
|
let stateSaved = false;
|
|
if (this.obj.isLockedAtServer) {
|
|
noProblem = await saveState(vm);
|
|
stateSaved = true;
|
|
}
|
|
|
|
//############# DELETE GRAPH ###############
|
|
//SCHEDULED USERS
|
|
if (noProblem) {
|
|
noProblem = await deleteScheduledUsers(vm);
|
|
}
|
|
|
|
//todo: other grandchildren
|
|
|
|
//WOITEMS
|
|
if (noProblem) {
|
|
noProblem = await deleteItems(vm);
|
|
}
|
|
|
|
//############ SAVE GRAPH ###############
|
|
//HEADER
|
|
if (noProblem && !headerSaved) {
|
|
noProblem = await saveHeader(vm);
|
|
}
|
|
|
|
//WOITEMS
|
|
if (noProblem) {
|
|
//This saves all bottom level collections as well
|
|
noProblem = await saveItems(vm);
|
|
}
|
|
|
|
//### STATE last normally
|
|
//in case it locks or is completed
|
|
if (!stateSaved && noProblem) {
|
|
noProblem = await saveState(vm);
|
|
}
|
|
|
|
//## ALL PARTIAL UPDATES SUCCEEDED
|
|
if (!noProblem) {
|
|
//this assumes error is already displayed from save op
|
|
window.$gz.form.setFormState({
|
|
vm: vm,
|
|
dirty: true,
|
|
valid: false
|
|
});
|
|
} else {
|
|
window.$gz.form.setFormState({
|
|
vm: vm,
|
|
dirty: false,
|
|
valid: true
|
|
});
|
|
}
|
|
|
|
//TODO: Nav to this again if it's a post
|
|
|
|
// 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: "workorder-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;
|
|
// }
|
|
|
|
// }
|
|
} 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: "workorder-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
|
|
}
|
|
};
|
|
|
|
//########################################## SAVE METHODS ##############################################
|
|
|
|
/////////////////////////////
|
|
// HEADER
|
|
//
|
|
async function saveHeader(vm) {
|
|
if (!vm.obj.isDirty) {
|
|
return true;
|
|
}
|
|
let isPost = vm.obj.id == 0;
|
|
let res = await window.$gz.api.upsert(`${API_BASE_URL}`, vm.obj);
|
|
if (res.error) {
|
|
displayResError(vm, res);
|
|
return false;
|
|
} else {
|
|
//update any server changed fields
|
|
vm.obj.concurrency = res.data.concurrency;
|
|
vm.obj.isDirty = false;
|
|
if (isPost) {
|
|
vm.obj.id = res.data.id;
|
|
vm.obj.serial = res.data.serial;
|
|
//walk all unsaved direct children and set the workorder id so they can save
|
|
vm.obj.states.forEach(z => (z.workOrderId = vm.obj.id));
|
|
vm.obj.items.forEach(z => (z.workOrderId = vm.obj.id));
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/////////////////////////////
|
|
// STATES
|
|
//
|
|
async function saveState(vm) {
|
|
//CHANGED?
|
|
let totalItems = vm.obj.states.length;
|
|
if (totalItems == 0) {
|
|
return;
|
|
}
|
|
for (let i = 0; i < totalItems; i++) {
|
|
let o = vm.obj.states[i];
|
|
if (o.concurrency == null) {
|
|
//it's new so save it
|
|
let res = await window.$gz.api.upsert(`${API_BASE_URL}states`, o);
|
|
if (res.error) {
|
|
displayResError(vm, res);
|
|
return false;
|
|
} else {
|
|
vm.obj.states[i] = res.data;
|
|
//set locked status of entire wo now
|
|
vm.obj.isLockedAtServer = vm.currentState.locked;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/////////////////////////////
|
|
// ITEMS
|
|
//
|
|
async function deleteItems(vm) {
|
|
while (vm.deletedGraphItems.items.length) {
|
|
let res = await window.$gz.api.remove(
|
|
`${API_BASE_URL}items/${vm.deletedGraphItems.items[0]}`
|
|
);
|
|
if (res.error) {
|
|
displayResError(vm, res);
|
|
return false;
|
|
} else {
|
|
vm.deletedGraphItems.items.splice(0, 1);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
async function saveItems(vm) {
|
|
let totalItems = vm.obj.items.length;
|
|
if (totalItems == 0) {
|
|
return true;
|
|
}
|
|
|
|
for (let i = 0; i < totalItems; i++) {
|
|
let o = vm.obj.items[i];
|
|
// console.log("checking for save item: ", { item: o, index: i });
|
|
if (o.isDirty) {
|
|
// console.log("Is dirty, saving now for ", i);
|
|
let isPost = o.id == 0;
|
|
let res = await window.$gz.api.upsert(`${API_BASE_URL}items`, o);
|
|
if (res.error) {
|
|
displayResError(vm, res);
|
|
return false;
|
|
} else {
|
|
//update any server changed fields
|
|
//put fields
|
|
o.concurrency = res.data.concurrency;
|
|
o.isDirty = false;
|
|
|
|
//fields to update if post
|
|
if (isPost) {
|
|
o.id = res.data.id;
|
|
o.workorderId = res.data.workorderId;
|
|
//walk all unsaved children and set the workorder id so they can save
|
|
o.scheduledUsers.forEach(z => (z.workorderItemId = o.id));
|
|
//todo: other grandchildren
|
|
}
|
|
}
|
|
} else {
|
|
// console.log("Item not dirty skipping save of ", i);
|
|
}
|
|
//------
|
|
//save grandchildren
|
|
if (!(await saveScheduledUsers(vm, i))) {
|
|
return false;
|
|
}
|
|
//------
|
|
// console.log("Bottom of items loop", { totalItems: totalItems, i: i });
|
|
}
|
|
return true; //made it through
|
|
}
|
|
//####################################################################################
|
|
//## GRANDCHILDREN
|
|
|
|
/////////////////////////////
|
|
// SCHEDULED USERS
|
|
//
|
|
async function deleteScheduledUsers(vm) {
|
|
while (vm.deletedGraphItems.scheduledUsers.length) {
|
|
let res = await window.$gz.api.remove(
|
|
`${API_BASE_URL}items/scheduledusers/${vm.deletedGraphItems.scheduledUsers[0]}`
|
|
);
|
|
if (res.error) {
|
|
displayResError(vm, res);
|
|
return false;
|
|
} else {
|
|
vm.deletedGraphItems.scheduledUsers.splice(0, 1);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
async function saveScheduledUsers(vm, woitemindex) {
|
|
let totalItems = vm.obj.items[woitemindex].scheduledUsers.length;
|
|
if (totalItems == 0) {
|
|
return true;
|
|
}
|
|
for (let i = 0; i < totalItems; i++) {
|
|
let o = vm.obj.items[woitemindex].scheduledUsers[i];
|
|
if (o.isDirty) {
|
|
let isPost = o.id == 0;
|
|
let res = await window.$gz.api.upsert(
|
|
`${API_BASE_URL}items/scheduledusers`,
|
|
o
|
|
);
|
|
if (res.error) {
|
|
displayResError(vm, res);
|
|
return false;
|
|
} else {
|
|
//update any server changed fields
|
|
//always updated:
|
|
o.concurrency = res.data.concurrency;
|
|
o.isDirty = false;
|
|
|
|
//new records only...
|
|
if (isPost) {
|
|
o.id = res.data.id;
|
|
o.workOrderItemId = res.data.workOrderItemId;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true; //made it
|
|
}
|
|
|
|
//todo: other grandchildren
|
|
|
|
/////////////////////////////
|
|
// Error display
|
|
//
|
|
function displayResError(vm, res) {
|
|
console.log("DISPLAY RES ERROR: ", res);
|
|
vm.formState.serverError = res.error;
|
|
window.$gz.form.setErrorBoxErrors(vm);
|
|
}
|
|
|
|
//######################################### UTILITY METHODS ###########################################
|
|
/////////////////////////////
|
|
//
|
|
//
|
|
function setSubRights(vm) {
|
|
//determine rights to each which sections are hidden due to form customized out or rights / roles
|
|
//todo: determine this and set accordingly, for now all set to available true during init
|
|
//## NOTE: these are subrights only, descendants still need to first check if workorder isLockedAtServer and rights are read only etc before this level is checked
|
|
/*
|
|
*/
|
|
}
|
|
|
|
/////////////////////////////
|
|
//
|
|
//
|
|
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: "workorder-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.WorkOrder }
|
|
});
|
|
} else {
|
|
//general report selector chosen
|
|
|
|
let res = await m.vm.$refs.reportSelector.open({
|
|
AType: window.$gz.type.WorkOrder,
|
|
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.WorkOrder }
|
|
});
|
|
}
|
|
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: "$ayiTools",
|
|
title: "WorkOrder",
|
|
helpUrl: "svc-workorder",
|
|
formData: {
|
|
ayaType: window.$gz.type.WorkOrder,
|
|
recordId: vm.$route.params.recordid,
|
|
formCustomTemplateKey: FORM_CUSTOM_TEMPLATE_KEY,
|
|
recordName: vm.obj.serial
|
|
},
|
|
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
|
|
});
|
|
}
|
|
|
|
//--- /show all ---
|
|
|
|
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);
|
|
await populateSelectionLists(vm);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////
|
|
//
|
|
// Ensures UI translated text is available
|
|
//
|
|
async function fetchTranslatedText(vm) {
|
|
await window.$gz.translation.cacheTranslations([
|
|
"WorkOrder",
|
|
"WorkOrderSerialNumber",
|
|
"WorkOrderSummary",
|
|
"WorkOrderStatus",
|
|
"WorkOrderCustom1",
|
|
"WorkOrderCustom2",
|
|
"WorkOrderCustom3",
|
|
"WorkOrderCustom4",
|
|
"WorkOrderCustom5",
|
|
"WorkOrderCustom6",
|
|
"WorkOrderCustom7",
|
|
"WorkOrderCustom8",
|
|
"WorkOrderCustom9",
|
|
"WorkOrderCustom10",
|
|
"WorkOrderCustom11",
|
|
"WorkOrderCustom12",
|
|
"WorkOrderCustom13",
|
|
"WorkOrderCustom14",
|
|
"WorkOrderCustom15",
|
|
"WorkOrderCustom16",
|
|
"WorkOrderItemList",
|
|
"WorkOrderItemTechNotes",
|
|
"WorkOrderItemScheduledUserList",
|
|
"WorkOrderItemSummary",
|
|
"WorkOrderItemWorkOrderStatusID",
|
|
"WorkOrderItemRequestDate",
|
|
"WorkOrderItemPriorityID",
|
|
"WorkOrderItemWarrantyService",
|
|
"WorkOrderItemScheduledUserStartDate",
|
|
"WorkOrderItemScheduledUserStopDate",
|
|
"WorkOrderItemScheduledUserEstimatedQuantity",
|
|
"WorkOrderItemScheduledUserUserID",
|
|
"WorkOrderItemScheduledUserServiceRateID"
|
|
]);
|
|
}
|
|
|
|
//////////////////////
|
|
//
|
|
//
|
|
async function populateSelectionLists(vm) {
|
|
let res = await window.$gz.api.get("work-order-status/list");
|
|
if (res.error) {
|
|
vm.formState.serverError = res.error;
|
|
window.$gz.form.setErrorBoxErrors(vm);
|
|
//window.$gz.errorHandler.handleFormError(res.error, vm);
|
|
} else {
|
|
vm.selectLists.wostatus = res.data.all;
|
|
vm.selectLists.allowedwostatus = res.data.allowed;
|
|
}
|
|
|
|
//---------
|
|
}
|
|
|
|
/*
|
|
Example workorder
|
|
{
|
|
id: 10,
|
|
concurrency: 7728489,
|
|
serial: 10,
|
|
notes: "Quae officia placeat aliquid ducimus consequatur quia.",
|
|
wiki: null,
|
|
customFields: null,
|
|
tags: ["green", "zone6"],
|
|
customerId: 12,
|
|
projectId: null,
|
|
internalReferenceNumber: "irf-3339",
|
|
customerReferenceNumber: "crf-1889",
|
|
customerContactName: "contact name here",
|
|
fromQuoteId: null,
|
|
fromPMId: null,
|
|
fromCSRId: null,
|
|
serviceDate: "2021-05-29T21:25:31.421011Z",
|
|
completeByDate: "2021-06-03T21:25:31.421011Z",
|
|
invoiceNumber: null,
|
|
customerSignature: null,
|
|
customerSignatureName: null,
|
|
customerSignatureCaptured: "0001-01-01T00:00:00Z",
|
|
postAddress: null,
|
|
postCity: null,
|
|
postRegion: null,
|
|
postCountry: null,
|
|
postCode: null,
|
|
address: null,
|
|
city: null,
|
|
region: null,
|
|
country: null,
|
|
latitude: null,
|
|
longitude: null,
|
|
items: [
|
|
{
|
|
id: 21,
|
|
concurrency: 7728489,
|
|
notes: "itemnotes",
|
|
wiki: null,
|
|
customFields: null,
|
|
tags: [],
|
|
workOrderId: 10,
|
|
techNotes: "technotes",
|
|
workorderItemStatusId: null,
|
|
workorderItemPriorityId: null,
|
|
requestDate: "2021-05-29T21:25:31.421011Z",
|
|
warrantyService: false,
|
|
isDirty: false,
|
|
expenses: [],
|
|
labors: [],
|
|
loans: [],
|
|
parts: [],
|
|
partRequests: [],
|
|
scheduledUsers: [
|
|
{
|
|
id: 41,
|
|
concurrency: 7728489,
|
|
userId: 15,
|
|
estimatedQuantity: 1.0,
|
|
startDate: null,
|
|
stopDate: null,
|
|
serviceRateId: null,
|
|
isDirty: false,
|
|
workOrderItemId: 21
|
|
},
|
|
{
|
|
id: 42,
|
|
concurrency: 7728489,
|
|
userId: 22,
|
|
estimatedQuantity: 2.0,
|
|
startDate: null,
|
|
stopDate: null,
|
|
serviceRateId: null,
|
|
isDirty: false,
|
|
workOrderItemId: 21
|
|
}
|
|
],
|
|
tasks: [],
|
|
travels: [],
|
|
units: [],
|
|
outsideServices: []
|
|
},
|
|
{
|
|
id: 22,
|
|
concurrency: 7728489,
|
|
notes: "itemnotes",
|
|
wiki: null,
|
|
customFields: null,
|
|
tags: [],
|
|
workOrderId: 10,
|
|
techNotes: "technotes",
|
|
workorderItemStatusId: null,
|
|
workorderItemPriorityId: null,
|
|
requestDate: "2021-05-29T21:25:31.421011Z",
|
|
warrantyService: false,
|
|
isDirty: false,
|
|
expenses: [],
|
|
labors: [],
|
|
loans: [],
|
|
parts: [],
|
|
partRequests: [],
|
|
scheduledUsers: [
|
|
{
|
|
id: 43,
|
|
concurrency: 7728489,
|
|
userId: 24,
|
|
estimatedQuantity: 1.0,
|
|
startDate: null,
|
|
stopDate: null,
|
|
serviceRateId: null,
|
|
isDirty: false,
|
|
workOrderItemId: 22
|
|
},
|
|
{
|
|
id: 44,
|
|
concurrency: 7728489,
|
|
userId: 40,
|
|
estimatedQuantity: 2.0,
|
|
startDate: null,
|
|
stopDate: null,
|
|
serviceRateId: null,
|
|
isDirty: false,
|
|
workOrderItemId: 22
|
|
}
|
|
],
|
|
tasks: [],
|
|
travels: [],
|
|
units: [],
|
|
outsideServices: []
|
|
}
|
|
],
|
|
states: [
|
|
{
|
|
id: 37,
|
|
concurrency: 7728489,
|
|
workOrderId: 10,
|
|
workOrderStatusId: 2,
|
|
created: "2021-05-29T21:30:31.421011Z",
|
|
userId: 37,
|
|
isDirty: false,
|
|
workOrderStatus: null
|
|
},
|
|
{
|
|
id: 38,
|
|
concurrency: 7728489,
|
|
workOrderId: 10,
|
|
workOrderStatusId: 3,
|
|
created: "2021-05-29T22:25:31.421011Z",
|
|
userId: 10,
|
|
isDirty: false,
|
|
workOrderStatus: null
|
|
},
|
|
{
|
|
id: 39,
|
|
concurrency: 7728489,
|
|
workOrderId: 10,
|
|
workOrderStatusId: 1,
|
|
created: "2021-05-29T22:30:31.421011Z",
|
|
userId: 31,
|
|
isDirty: false,
|
|
workOrderStatus: null
|
|
},
|
|
{
|
|
id: 40,
|
|
concurrency: 7728489,
|
|
workOrderId: 10,
|
|
workOrderStatusId: 3,
|
|
created: "2021-05-29T23:25:31.421011Z",
|
|
userId: 2,
|
|
isDirty: false,
|
|
workOrderStatus: null
|
|
},
|
|
{
|
|
id: 41,
|
|
concurrency: 7728489,
|
|
workOrderId: 10,
|
|
workOrderStatusId: 9,
|
|
created: "2021-04-06T00:10:44.636Z",
|
|
userId: 1,
|
|
isDirty: false,
|
|
workOrderStatus: null
|
|
}
|
|
],
|
|
isDirty: false,
|
|
isLockedAtServer: false
|
|
};
|
|
|
|
|
|
*/
|
|
</script>
|