Add more complete support for ordering batches in mobile

can now see "all" batches, and execute if desired
This commit is contained in:
Lance Edgar 2021-02-02 19:03:34 -06:00
parent 4d36d003f2
commit ce7efd3c8b
4 changed files with 253 additions and 97 deletions

View file

@ -52,6 +52,12 @@ const routes = [
// component: OrderingBatch, // component: OrderingBatch,
// props: {mode: 'editing'}, // props: {mode: 'editing'},
// }, // },
{
path: '/ordering/:uuid/execute',
name: 'ordering.execute',
component: OrderingBatch,
props: {mode: 'executing'},
},
{ {
path: '/ordering/rows/:uuid', path: '/ordering/rows/:uuid',
name: 'ordering.rows.view', name: 'ordering.rows.view',

View file

@ -1,11 +1,11 @@
<template> <template>
<byjove-model-crud model-name="PurchaseBatch" <div>
<byjove-model-crud v-if="!showingExecutionOptions"
model-name="PurchaseBatch"
model-index-title="Ordering" model-index-title="Ordering"
model-title="Ordering Batch" model-title="Ordering Batch"
model-title-plural="Ordering Batches" model-title-plural="Ordering Batches"
model-path-prefix="/ordering" model-path-prefix="/ordering"
model-permission-prefix="ordering"
row-path-prefix="/ordering/rows"
:mode="mode" :mode="mode"
@refresh="record => { batch = record }" @refresh="record => { batch = record }"
api-index-url="/api/ordering-batches" api-index-url="/api/ordering-batches"
@ -13,45 +13,38 @@
:header-label-renderer="renderHeaderLabel" :header-label-renderer="renderHeaderLabel"
:allow-edit="false" :allow-edit="false"
has-rows has-rows
row-path-prefix="/ordering/rows"
api-rows-url="/api/ordering-batch-rows" api-rows-url="/api/ordering-batch-rows"
:row-label-renderer="renderRowLabel" :row-label-renderer="renderRowLabel"
:row-route-getter="getRowRoute" :row-route-getter="getRowRoute"
@save="save"
save-button-text="Make Ordering Batch" save-button-text="Make Ordering Batch"
@save="save"> model-permission-prefix="ordering">
<!-- :save-disabled="saveDisabled" -->
<div v-if="mode == 'creating'">
<b-field label="Vendor" <b-field label="Vendor"
:type="{'is-danger': !batch.vendor_uuid}"> :type="{'is-danger': !batch.vendor_uuid}">
<byjove-autocomplete v-model="batch.vendor_uuid" <byjove-autocomplete v-if="mode == 'creating'"
v-model="batch.vendor_uuid"
service-url="/api/vendors/autocomplete"> service-url="/api/vendors/autocomplete">
</byjove-autocomplete> </byjove-autocomplete>
</b-field> <span v-if="mode != 'creating'">
<br />
</div> <!-- creating -->
<div v-if="mode == 'viewing'">
<b-field label="Vendor">
<span>
{{ batch.vendor_display }} {{ batch.vendor_display }}
</span> </span>
</b-field> </b-field>
<b-field label="Date Ordered" <b-field label="Date Ordered"
v-if="mode != 'creating' && batch.executed"> v-if="mode == 'viewing' && batch.executed">
<span> <span>{{ batch.date_ordered }}</span>
{{ batch.date_ordered }}
</span>
</b-field> </b-field>
<b-field label="Total"> <b-field label="Total"
<span> v-if="mode == 'viewing' || mode == 'executing'">
{{ batch.po_total_calculated_display }} <span>{{ batch.po_total_calculated_display }}</span>
</span>
</b-field> </b-field>
<div v-if="mode == 'viewing'">
<b-field label="Created" <b-field label="Created"
v-if="mode != 'creating' && batch.executed"> v-if="mode != 'creating' && batch.executed">
<span> <span>
@ -66,6 +59,11 @@
</span> </span>
</b-field> </b-field>
<b-field label="Complete"
v-if="mode != 'creating' && batch.complete && !batch.executed">
<span>{{ batch.complete }}</span>
</b-field>
<br v-if="!batch.executed" /> <br v-if="!batch.executed" />
<div v-if="batch.executed"> <div v-if="batch.executed">
@ -87,7 +85,7 @@
</div> <!-- viewing --> </div> <!-- viewing -->
<template slot="quick-entry"> <template slot="quick-entry">
<div v-if="mode == 'viewing' && !batch.executed && !batch.complete"> <div v-if="mode == 'viewing' && batch.mutable">
<b-input v-model="quickEntry" <b-input v-model="quickEntry"
placeholder="Enter UPC" placeholder="Enter UPC"
icon="search" icon="search"
@ -101,20 +99,46 @@
v-if="mode == 'viewing' && !batch.executed"> v-if="mode == 'viewing' && !batch.executed">
<br /> <br />
<div class="buttons is-centered"> <div class="buttons is-centered">
<b-button v-if="!batch.complete" <!-- <b-button v-if="!batch.complete" -->
type="is-primary" <!-- type="is-primary" -->
@click="editWorksheet()"> <!-- @click="editWorksheet()"> -->
Edit as Worksheet <!-- Edit as Worksheet -->
</b-button> <!-- </b-button> -->
<b-button v-if="!batch.complete" <b-button v-if="!batch.complete"
type="is-primary" type="is-primary"
@click="markOrderingComplete()"> @click="markOrderingComplete()">
Ordering is Complete! Mark Complete
</b-button>
<b-button v-if="batch.complete"
type="is-primary"
@click="markOrderingIncomplete()">
Mark Incomplete
</b-button>
<b-button v-if="batch.complete"
type="is-primary"
tag="router-link"
:to="`/ordering/${batch.uuid}/execute`">
Execute Batch
</b-button> </b-button>
</div> </div>
</template> </template>
</byjove-model-crud> </byjove-model-crud>
<div v-if="mode == 'executing'">
<br />
<div class="buttons">
<b-button type="is-primary"
@click="executeBatch()">
Submit this Order
</b-button>
<b-button tag="router-link"
:to="`/ordering/${batch.uuid}`">
Cancel
</b-button>
</div>
<b-loading :active="executing"></b-loading>
</div>
</div>
</template> </template>
<script> <script>
@ -133,6 +157,8 @@ export default {
return { return {
batch: {}, batch: {},
quickEntry: '', quickEntry: '',
showingExecutionOptions: false,
executing: false,
} }
}, },
mounted() { mounted() {
@ -151,7 +177,10 @@ export default {
}, },
getRowRoute(row) { getRowRoute(row) {
if (this.batch.mutable) {
return `/ordering/rows/${row.uuid}/edit` return `/ordering/rows/${row.uuid}/edit`
}
return `/ordering/rows/${row.uuid}`
}, },
save(url) { save(url) {
@ -251,6 +280,55 @@ export default {
}) })
}) })
}, },
markOrderingIncomplete() {
this.$http.post(`/api/ordering-batch/${this.batch.uuid}/mark-incomplete`).then(response => {
if (response.data.error) {
this.$buefy.toast.open({
message: "Update failed: " + response.data.error,
type: 'is-danger',
})
} else {
// update our batch, which should allow user to then modify it
this.batch = response.data.data
}
}, response => {
this.$buefy.toast.open({
message: "Update failed: (unknown error)",
type: 'is-danger',
})
})
},
executeBatch() {
let url = `/api/ordering-batch/${this.batch.uuid}/execute`
let params = {
// TODO: any reason to post params?
}
this.executing = true
this.$http.post(url, params).then(response => {
this.executing = false
if (response.data.error) {
this.$buefy.toast.open({
message: "Execute failed: " + response.data.error,
type: 'is-danger',
})
} else {
// let user view the order, for confirmation
this.$router.push(`/ordering/${this.batch.uuid}`)
this.$buefy.toast.open({
message: "Ordering batch has been executed",
type: 'is-success',
})
}
}, response => {
this.executing = false
this.$buefy.toast.open({
message: "Execute failed: (unknown error)",
type: 'is-danger',
})
})
},
}, },
} }
</script> </script>

View file

@ -7,9 +7,13 @@
api-object-url="/api/ordering-batch-row/" api-object-url="/api/ordering-batch-row/"
model-path-prefix="/ordering" model-path-prefix="/ordering"
row-path-prefix="/ordering/rows" row-path-prefix="/ordering/rows"
@refresh="record => { row = record }" @refresh="refresh"
is-row is-row
@save="save"> @save="save"
:allow-edit="!row.batch_executed && !row.batch_complete"
:allow-delete="!row.batch_executed && !row.batch_complete"
quick-delete
@delete="deleteRow">
<b-field label="UPC"> <b-field label="UPC">
<span> <span>
@ -42,7 +46,7 @@
ref="unitsOrdered" ref="unitsOrdered"
@keypress.native="handleEnter"> @keypress.native="handleEnter">
</b-input> </b-input>
<span v-if="mode == 'viewing'"> <span v-if="mode == 'viewing' || mode == 'deleting'">
{{ row.units_ordered_display }} {{ row.units_ordered_display }}
</span> </span>
</b-field> </b-field>
@ -89,11 +93,23 @@ export default {
if (this.mode == 'editing') { if (this.mode == 'editing') {
this.$nextTick(function() { this.$nextTick(function() {
this.$refs.casesOrdered.focus() this.$refs.casesOrdered.focus()
// this.$refs.unitsOrdered.focus()
}) })
} }
}, },
methods: { methods: {
refresh(record) {
this.row = record
if (this.mode == 'editing' && !this.row.batch_mutable) {
this.$buefy.toast.open({
message: "Batch is not mutable.",
type: 'is-danger',
})
this.$router.push(`/ordering/rows/${this.row.uuid}`)
}
},
renderParentHeaderLabel(row) { renderParentHeaderLabel(row) {
return row.batch_id_str return row.batch_id_str
}, },
@ -118,8 +134,28 @@ export default {
url = `/api/ordering-batch-row/${this.row.uuid}` url = `/api/ordering-batch-row/${this.row.uuid}`
} }
this.$http.post(url, params).then(response => { this.$http.post(url, params).then(response => {
if (response.data.error) {
this.$buefy.toast.open({
message: response.data.error || "Save failed: " + response.data.error,
type: 'is-danger',
})
} else {
// go back to the purchase order // go back to the purchase order
this.$router.push('/ordering/' + response.data.data.batch_uuid) this.$router.push('/ordering/' + response.data.data.batch_uuid)
}
}, response => {
this.$buefy.toast.open({
message: "Save failed: (unknown error)",
type: 'is-danger',
})
})
},
deleteRow() {
let url = `/api/ordering-batch-row/${this.row.uuid}`
this.$http.delete(url).then(response => {
// go back to the purchase order
this.$router.push(`/ordering/${this.row.batch_uuid}`)
}) })
}, },
}, },

View file

@ -9,6 +9,26 @@
:api-index-sort="{field: 'id', dir: 'desc'}" :api-index-sort="{field: 'id', dir: 'desc'}"
:api-index-filters="filters" :api-index-filters="filters"
:label-renderer="renderLabel"> :label-renderer="renderLabel">
<b-field>
<b-radio-button v-model="selectedFilter"
native-value="pending">
<span>pending</span>
</b-radio-button>
<b-radio-button v-model="selectedFilter"
native-value="complete">
<span>complete</span>
</b-radio-button>
<b-radio-button v-model="selectedFilter"
native-value="executed">
<span>executed</span>
</b-radio-button>
<b-radio-button v-model="selectedFilter"
native-value="all">
<span>all</span>
</b-radio-button>
</b-field>
</byjove-model-index> </byjove-model-index>
</template> </template>
@ -22,15 +42,31 @@ export default {
}, },
data() { data() {
return { return {
filters: [ possibleFilters: {
'pending': [
{field: 'executed', op: 'is_null'}, {field: 'executed', op: 'is_null'},
{or: [ {or: [
{field: 'complete', op: 'is_null'}, {field: 'complete', op: 'is_null'},
{field: 'complete', op: 'eq', value: false}, {field: 'complete', op: 'eq', value: false},
]}, ]},
], ],
'complete': [
{field: 'executed', op: 'is_null'},
{field: 'complete', op: 'eq', value: true},
],
'executed': [
{field: 'executed', op: 'is_not_null'},
],
'all': [],
},
selectedFilter: 'pending',
} }
}, },
computed: {
filters: function() {
return this.possibleFilters[this.selectedFilter]
},
},
methods: { methods: {
renderLabel(batch) { renderLabel(batch) {
return `(${batch.id_str}) ${batch.vendor_display}` return `(${batch.id_str}) ${batch.vendor_display}`