This commit is contained in:
2021-05-24 20:04:32 +00:00
parent d5f961e539
commit 4d77a62f78
2 changed files with 748 additions and 3 deletions

View File

@@ -342,9 +342,8 @@ todo: many biz objects are not using new PUT methodology
CURRENTLY DOING: WorkOrderItemTravel
ORDER: Travel, tasks, parts, loans, units, outside service
CURRENTLY DOING:
ORDER: tasks, parts, loans, units, outside service
todo: WorkorderItemPart- part prices are going to change / volatile so snapshot them (cost/charge)
rates and taxes are ok to not snapshot, their values are protected once used but parts are volatile and should be snapshotted
@@ -376,6 +375,8 @@ todo: is it really feasible to duplicate a workorder? What about all the side e
todo: should be able to create a new workorder for a customer from that customers menu (same with other objects that have an identifiable customer)
this was in v7 (from main grid not inside object but can't replicate that so this instead)
todo: r4eporting - need to add pre-caching code and populate *Viz throughout graph to workorder before testing printing code.
OVERALL
- then full in front end and flow out to back end as required, remove any backend that was a defunct evolutionary path so no cruft left around

View File

@@ -0,0 +1,744 @@
<template>
<div v-if="value != null" class="mt-8">
<v-row>
<v-col cols="12">
<v-menu offset-y>
<template v-slot:activator="{ on, attrs }">
<div class="text-h6">
<v-icon large color="primary" class="mr-2">$ayiTasks</v-icon>
{{ $ay.t("WorkOrderItemTaskList") }}
<v-btn v-if="!parentDeleted" large icon v-bind="attrs" v-on="on">
<v-icon small color="primary">$ayiEllipsisV</v-icon>
</v-btn>
</div>
</template>
<v-list>
<v-list-item v-if="canAdd" @click="newItem">
<v-list-item-icon>
<v-icon>$ayiPlus</v-icon>
</v-list-item-icon>
<v-list-item-title>{{ $ay.t("New") }}</v-list-item-title>
</v-list-item>
<v-list-item v-if="canDelete && !isDeleted" @click="deleteItem">
<v-list-item-icon>
<v-icon>$ayiTrashAlt</v-icon>
</v-list-item-icon>
<v-list-item-title>{{ $ay.t("SoftDelete") }}</v-list-item-title>
</v-list-item>
<v-list-item v-if="canDelete && isDeleted" @click="unDeleteItem">
<v-list-item-icon>
<v-icon>$ayiTrashRestoreAlt</v-icon>
</v-list-item-icon>
<v-list-item-title>{{ $ay.t("Undelete") }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-col>
<template v-if="showTable">
<!-- ############################################################### -->
<v-col cols="12" class="mb-10">
<v-data-table
:headers="headerList"
:items="itemList"
item-key="index"
v-model="selectedRow"
class="elevation-1"
disable-pagination
disable-filtering
disable-sort
hide-default-footer
data-cy="expensesTable"
dense
:item-class="itemRowClasses"
@click:row="handleRowClick"
:show-select="$vuetify.breakpoint.xs"
single-select
>
<template v-slot:[`item.reimburseUser`]="{ item }">
<v-simple-checkbox
v-model="item.reimburseUser"
disabled
></v-simple-checkbox>
</template>
<template v-slot:[`item.chargeToCustomer`]="{ item }">
<v-simple-checkbox
v-model="item.chargeToCustomer"
disabled
></v-simple-checkbox>
</template>
</v-data-table>
</v-col>
</template>
<template v-if="activeItemIndex != null">
<v-btn
v-if="canDelete && isDeleted"
large
@click="unDeleteItem"
color="primary"
>{{ $ay.t("Undelete")
}}<v-icon right large>$ayiTrashRestoreAlt</v-icon></v-btn
>
<v-col
v-if="form().showMe(this, 'WorkOrderItemExpenseName')"
cols="12"
sm="6"
lg="4"
xl="3"
>
<v-text-field
v-model="
value.items[activeWoItemIndex].expenses[activeItemIndex].name
"
:readonly="formState.readOnly"
:disabled="isDeleted"
:label="$ay.t('WorkOrderItemExpenseName')"
:ref="
`Items[${activeWoItemIndex}].expenses[
${activeItemIndex}
].name`
"
:error-messages="
form().serverErrors(
this,
`Items[${activeWoItemIndex}].expenses[
${activeItemIndex}
].name`
)
"
@input="
fieldValueChanged(`Items[${activeWoItemIndex}].expenses[
${activeItemIndex}
].name`)
"
></v-text-field>
</v-col>
<v-col
v-if="form().showMe(this, 'WorkOrderItemExpenseTotalCost')"
cols="12"
sm="6"
lg="4"
xl="3"
>
<gz-currency
v-model="
value.items[activeWoItemIndex].expenses[activeItemIndex].totalCost
"
:readonly="formState.readOnly || isDeleted"
:disabled="isDeleted"
:label="$ay.t('WorkOrderItemExpenseTotalCost')"
:ref="
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].totalCost`
"
data-cy="expenseTotalCost"
:error-messages="
form().serverErrors(
this,
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].totalCost`
)
"
:rules="[
form().decimalValid(
this,
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].totalCost`
),
form().required(
this,
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].totalCost`
)
]"
@input="
fieldValueChanged(`Items[${activeWoItemIndex}].expenses[
${activeItemIndex}
].totalCost`)
"
></gz-currency>
</v-col>
<v-col
v-if="form().showMe(this, 'WorkOrderItemExpenseChargeAmount')"
cols="12"
sm="6"
lg="4"
xl="3"
>
<gz-currency
v-model="
value.items[activeWoItemIndex].expenses[activeItemIndex]
.chargeAmount
"
:readonly="formState.readOnly || isDeleted"
:disabled="isDeleted"
:label="$ay.t('WorkOrderItemExpenseChargeAmount')"
:ref="
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].chargeAmount`
"
data-cy="expenseChargeAmount"
:error-messages="
form().serverErrors(
this,
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].chargeAmount`
)
"
:rules="[
form().decimalValid(
this,
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].chargeAmount`
),
form().required(
this,
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].chargeAmount`
)
]"
@input="
fieldValueChanged(`Items[${activeWoItemIndex}].expenses[
${activeItemIndex}
].chargeAmount`)
"
></gz-currency>
</v-col>
<v-col
v-if="form().showMe(this, 'WorkOrderItemExpenseChargeToCustomer')"
cols="12"
sm="6"
lg="4"
xl="3"
>
<v-checkbox
v-model="
value.items[activeWoItemIndex].expenses[activeItemIndex]
.chargeToCustomer
"
:readonly="formState.readOnly"
:disabled="isDeleted"
:label="$ay.t('WorkOrderItemExpenseChargeToCustomer')"
:ref="
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].chargeToCustomer`
"
data-cy="chargeToCustomer"
:error-messages="
form().serverErrors(
this,
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].chargeToCustomer`
)
"
@change="
fieldValueChanged(`Items[${activeWoItemIndex}].expenses[
${activeItemIndex}
].chargeToCustomer`)
"
></v-checkbox>
</v-col>
<v-col
v-if="form().showMe(this, 'WorkOrderItemExpenseTaxPaid')"
cols="12"
sm="6"
lg="4"
xl="3"
>
<gz-currency
v-model="
value.items[activeWoItemIndex].expenses[activeItemIndex].taxPaid
"
:readonly="formState.readOnly || isDeleted"
:disabled="isDeleted"
:label="$ay.t('WorkOrderItemExpenseTaxPaid')"
:ref="
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].taxPaid`
"
data-cy="expenseTaxPaid"
:error-messages="
form().serverErrors(
this,
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].taxPaid`
)
"
:rules="[
form().decimalValid(
this,
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].taxPaid`
),
form().required(
this,
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].taxPaid`
)
]"
@input="
fieldValueChanged(`Items[${activeWoItemIndex}].expenses[
${activeItemIndex}
].taxPaid`)
"
></gz-currency>
</v-col>
<v-col
v-if="form().showMe(this, 'WorkOrderItemExpenseChargeTaxCodeID')"
cols="12"
sm="6"
lg="4"
xl="3"
>
<gz-pick-list
:aya-type="$ay.ayt().TaxCode"
:show-edit-icon="true"
v-model="
value.items[activeWoItemIndex].expenses[activeItemIndex]
.chargeTaxCodeId
"
:readonly="formState.readOnly || isDeleted"
:disabled="isDeleted"
:label="$ay.t('WorkOrderItemExpenseChargeTaxCodeID')"
:ref="
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].chargeTaxCodeId`
"
data-cy="expenseChargeTaxCode"
:error-messages="
form().serverErrors(
this,
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].chargeTaxCodeId`
)
"
@input="
fieldValueChanged(
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].chargeTaxCodeId`
)
"
@update:name="taxCodeChange"
></gz-pick-list>
</v-col>
<v-col
v-if="form().showMe(this, 'WorkOrderItemExpenseReimburseUser')"
cols="12"
sm="6"
lg="4"
xl="3"
>
<v-checkbox
v-model="
value.items[activeWoItemIndex].expenses[activeItemIndex]
.reimburseUser
"
:readonly="formState.readOnly"
:disabled="isDeleted"
:label="$ay.t('WorkOrderItemExpenseReimburseUser')"
:ref="
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].reimburseUser`
"
data-cy="expenseReimburseUser"
:error-messages="
form().serverErrors(
this,
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].reimburseUser`
)
"
@change="
fieldValueChanged(`Items[${activeWoItemIndex}].expenses[
${activeItemIndex}
].reimburseUser`)
"
></v-checkbox>
</v-col>
<v-col
v-if="form().showMe(this, 'WorkOrderItemExpenseUserID')"
cols="12"
sm="6"
lg="4"
xl="3"
>
<gz-pick-list
:aya-type="$ay.ayt().User"
variant="tech"
:show-edit-icon="true"
v-model="
value.items[activeWoItemIndex].expenses[activeItemIndex].userId
"
:readonly="formState.readOnly || isDeleted"
:disabled="isDeleted"
:label="$ay.t('WorkOrderItemExpenseUserID')"
:ref="
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].userId`
"
data-cy="expenseUser"
:error-messages="
form().serverErrors(
this,
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].userId`
)
"
@input="
fieldValueChanged(
`Items[${activeWoItemIndex}].expenses[${activeItemIndex}].userId`
)
"
@update:name="userChange"
></gz-pick-list>
</v-col>
<v-col
v-if="form().showMe(this, 'WorkOrderItemExpenseDescription')"
cols="12"
>
<v-textarea
v-model="
value.items[activeWoItemIndex].expenses[activeItemIndex]
.description
"
:readonly="formState.readOnly"
:disabled="isDeleted"
:label="$ay.t('WorkOrderItemExpenseDescription')"
:error-messages="
form().serverErrors(
this,
`Items[${activeWoItemIndex}].expenses[
${activeItemIndex}
].description`
)
"
:ref="
`Items[${activeWoItemIndex}].expenses[
${activeItemIndex}
].description`
"
data-cy="expenseDescription"
@input="
fieldValueChanged(`Items[${activeWoItemIndex}].expenses[
${activeItemIndex}
].description`)
"
auto-grow
></v-textarea>
</v-col>
</template>
</v-row>
</div>
</template>
<script>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* XXXeslint-disable */
////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
l.Add(new FormField { TKey = "Sequence", FieldKey = "WorkOrderItemTaskSequence", TKeySection = "WorkOrderItemTask" });
l.Add(new FormField { TKey = "WorkOrderItemTaskTaskID", FieldKey = "WorkOrderItemTaskTaskID", TKeySection = "WorkOrderItemTask" });
l.Add(new FormField { TKey = "WorkOrderItemTaskWorkOrderItemTaskCompletionType", FieldKey = "WorkOrderItemTaskWorkOrderItemTaskCompletionType", TKeySection = "WorkOrderItemTask" });
l.Add(new FormField { TKey = "WorkOrderItemTaskUser", FieldKey = "WorkOrderItemTaskUser", TKeySection = "WorkOrderItemTask" });
l.Add(new FormField { TKey = "WorkOrderItemTaskCompletedDate", FieldKey = "WorkOrderItemTaskCompletedDate", TKeySection = "WorkOrderItemTask" });
*/
export default {
created() {
this.setDefaultView();
},
data() {
return {
activeItemIndex: null,
selectedRow: []
};
},
props: {
value: {
default: null,
type: Object
},
pvm: {
default: null,
type: Object
},
activeWoItemIndex: {
default: null,
type: Number
}
},
watch: {
activeWoItemIndex(val, oldVal) {
if (val != oldVal) {
this.setDefaultView();
}
}
},
methods: {
userChange(newName) {
this.value.items[this.activeWoItemIndex].expenses[
this.activeItemIndex
].userViz = newName;
},
taxCodeChange(newName) {
this.value.items[this.activeWoItemIndex].expenses[
this.activeItemIndex
].chargeTaxCodeViz = newName;
},
newItem() {
let newIndex = this.value.items[this.activeWoItemIndex].expenses.length;
this.value.items[this.activeWoItemIndex].expenses.push({
id: 0,
concurrency: 0,
description: null,
name: null,
totalCost: 0,
chargeAmount: 0,
taxPaid: 0,
chargeTaxCodeId: 0,
chargeTaxCodeViz: null,
reimburseUser: false,
userId: null,
userViz: null,
chargeToCustomer: false,
isDirty: true,
workOrderItemId: this.value.items[this.activeWoItemIndex].id,
uid: Date.now() //used for error tracking / display
});
this.$emit("change");
this.selectedRow = [{ index: newIndex }];
this.activeItemIndex = newIndex;
},
unDeleteItem() {
this.value.items[this.activeWoItemIndex].expenses[
this.activeItemIndex
].deleted = false;
this.setDefaultView();
},
deleteItem() {
this.value.items[this.activeWoItemIndex].expenses[
this.activeItemIndex
].deleted = true;
this.setDefaultView();
this.$emit("change");
},
setDefaultView: function() {
//if only one record left then display it otherwise just let the datatable show what the user can click on
if (this.value.items[this.activeWoItemIndex].expenses.length == 1) {
this.selectedRow = [{ index: 0 }];
this.activeItemIndex = 0;
} else {
this.selectedRow = [];
this.activeItemIndex = null; //select nothing in essence resetting a child selects and this one too clearing form
}
},
handleRowClick: function(item) {
this.activeItemIndex = item.index;
this.selectedRow = [{ index: item.index }];
},
form() {
return window.$gz.form;
},
fieldValueChanged(ref) {
if (!this.formState.loading && !this.formState.readonly) {
//flag this record dirty so it gets picked up by save
this.value.items[this.activeWoItemIndex].expenses[
this.activeItemIndex
].isDirty = true;
window.$gz.form.fieldValueChanged(this.pvm, ref);
// //set viz if applicable
// if(ref==""){
// let selectedPartWarehouse = vm.$refs.partWarehouseId.getFullSelectionValue();
// }
}
},
itemRowClasses: function(item) {
let ret = "";
const isDeleted =
this.value.items[this.activeWoItemIndex].expenses[item.index]
.deleted === true;
const hasError = this.form().childRowHasError(
this,
`Items[${this.activeWoItemIndex}].Expenses[${item.index}].`
);
if (isDeleted) {
ret += this.form().tableRowDeletedClass();
}
if (hasError) {
ret += this.form().tableRowErrorClass();
}
return ret;
}
},
computed: {
isDeleted: function() {
if (
this.value.items[this.activeWoItemIndex].expenses[
this.activeItemIndex
] == null
) {
this.setDefaultView();
return true;
}
return (
this.value.items[this.activeWoItemIndex].expenses[this.activeItemIndex]
.deleted === true
);
},
parentDeleted: function() {
return this.value.items[this.activeWoItemIndex].deleted === true;
},
headerList: function() {
/*
If the column is a text, left-align it
If the column is a number or number + unit, (or date) right-align it (like excel)
*/
let headers = [];
if (this.form().showMe(this, "WorkOrderItemExpenseName")) {
headers.push({
text: this.$ay.t("WorkOrderItemExpenseName"),
align: "start",
value: "name"
});
}
if (this.form().showMe(this, "WorkOrderItemExpenseTotalCost")) {
headers.push({
text: this.$ay.t("WorkOrderItemExpenseTotalCost"),
align: "right",
value: "totalCost"
});
}
if (this.form().showMe(this, "WorkOrderItemExpenseChargeAmount")) {
headers.push({
text: this.$ay.t("WorkOrderItemExpenseChargeAmount"),
align: "right",
value: "chargeAmount"
});
}
if (this.form().showMe(this, "WorkOrderItemExpenseChargeToCustomer")) {
headers.push({
text: this.$ay.t("WorkOrderItemExpenseChargeToCustomer"),
align: "center",
value: "chargeToCustomer"
});
}
if (this.form().showMe(this, "WorkOrderItemExpenseTaxPaid")) {
headers.push({
text: this.$ay.t("WorkOrderItemExpenseTaxPaid"),
align: "right",
value: "taxPaid"
});
}
if (this.form().showMe(this, "WorkOrderItemExpenseChargeTaxCodeID")) {
headers.push({
text: this.$ay.t("Tax"),
align: "left",
value: "chargeTaxCodeViz"
});
}
if (this.form().showMe(this, "ExpenseTaxAViz")) {
headers.push({
text: this.$ay.t("TaxAAmt"),
align: "right",
value: "taxAViz"
});
}
if (this.form().showMe(this, "ExpenseTaxBViz")) {
headers.push({
text: this.$ay.t("TaxBAmt"),
align: "right",
value: "taxBViz"
});
}
if (this.form().showMe(this, "ExpenseLineTotalViz")) {
headers.push({
text: this.$ay.t("LineTotal"),
align: "right",
value: "lineTotalViz"
});
}
if (this.form().showMe(this, "WorkOrderItemExpenseReimburseUser")) {
headers.push({
text: this.$ay.t("WorkOrderItemExpenseReimburseUser"),
align: "center",
value: "reimburseUser"
});
}
if (this.form().showMe(this, "WorkOrderItemExpenseUserID")) {
headers.push({
text: this.$ay.t("WorkOrderItemExpenseUserID"),
align: "left",
value: "userViz"
});
}
return headers;
},
itemList: function() {
return this.value.items[this.activeWoItemIndex].expenses.map((x, i) => {
return {
index: i,
id: x.id,
name: x.name,
totalCost: window.$gz.locale.currencyLocalized(
x.totalCost,
this.pvm.languageName,
this.pvm.currencyName
),
chargeAmount: window.$gz.locale.currencyLocalized(
x.chargeAmount,
this.pvm.languageName,
this.pvm.currencyName
),
chargeToCustomer: x.chargeToCustomer,
taxPaid: window.$gz.locale.currencyLocalized(
x.taxPaid,
this.pvm.languageName,
this.pvm.currencyName
),
chargeTaxCodeViz: x.chargeTaxCodeViz,
taxAViz: window.$gz.locale.currencyLocalized(
x.taxAViz,
this.pvm.languageName,
this.pvm.currencyName
),
taxBViz: window.$gz.locale.currencyLocalized(
x.taxBViz,
this.pvm.languageName,
this.pvm.currencyName
),
lineTotalViz: window.$gz.locale.currencyLocalized(
x.lineTotalViz,
this.pvm.languageName,
this.pvm.currencyName
),
reimburseUser: x.reimburseUser,
userViz: x.userViz
};
});
},
formState: function() {
return this.pvm.formState;
},
formCustomTemplateKey: function() {
return this.pvm.formCustomTemplateKey;
},
showTable: function() {
return this.value.items[this.activeWoItemIndex].expenses.length > 1;
},
canAdd: function() {
return this.pvm.rights.change && this.pvm.subRights.expenses.create;
},
canDelete: function() {
return (
this.activeItemIndex != null &&
this.pvm.rights.change &&
this.pvm.subRights.expenses.delete
);
}
}
};
</script>