Add basic "receiving" support for theo mobile
This commit is contained in:
parent
3779d7b9f4
commit
22aad5e31f
|
@ -11,6 +11,12 @@
|
||||||
<router-link to="/ordering/">Ordering</router-link>
|
<router-link to="/ordering/">Ordering</router-link>
|
||||||
</b-dropdown-item>
|
</b-dropdown-item>
|
||||||
|
|
||||||
|
<b-dropdown-item v-if="$hasPerm('receiving.list')"
|
||||||
|
aria-role="menuitem"
|
||||||
|
has-link>
|
||||||
|
<router-link to="/receiving/">Receiving</router-link>
|
||||||
|
</b-dropdown-item>
|
||||||
|
|
||||||
</byjove-menu>
|
</byjove-menu>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ import VueRouter from 'vue-router'
|
||||||
import Home from '../views/Home.vue'
|
import Home from '../views/Home.vue'
|
||||||
import Login from '../views/Login.vue'
|
import Login from '../views/Login.vue'
|
||||||
import {OrderingBatches, OrderingBatch, OrderingBatchRow, OrderingBatchWorksheet} from '../views/ordering'
|
import {OrderingBatches, OrderingBatch, OrderingBatchRow, OrderingBatchWorksheet} from '../views/ordering'
|
||||||
|
import {ReceivingBatches, ReceivingBatch, ReceivingBatchRow, ReceivingBatchRowReceive} from '../views/receiving'
|
||||||
|
|
||||||
Vue.use(VueRouter)
|
Vue.use(VueRouter)
|
||||||
|
|
||||||
|
@ -75,6 +76,44 @@ const routes = [
|
||||||
name: 'ordering.worksheet',
|
name: 'ordering.worksheet',
|
||||||
component: OrderingBatchWorksheet,
|
component: OrderingBatchWorksheet,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
//////////////////////////////
|
||||||
|
// Receiving
|
||||||
|
//////////////////////////////
|
||||||
|
{
|
||||||
|
path: '/receiving/',
|
||||||
|
name: 'receiving',
|
||||||
|
component: ReceivingBatches,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/receiving/new',
|
||||||
|
name: 'receiving.new',
|
||||||
|
component: ReceivingBatch,
|
||||||
|
props: {mode: 'creating'},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/receiving/:uuid',
|
||||||
|
name: 'receiving.view',
|
||||||
|
component: ReceivingBatch,
|
||||||
|
props: {mode: 'viewing'},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/receiving/:uuid/edit',
|
||||||
|
name: 'receiving.edit',
|
||||||
|
component: ReceivingBatch,
|
||||||
|
props: {mode: 'editing'},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/receiving/rows/:uuid',
|
||||||
|
name: 'receiving.rows.view',
|
||||||
|
component: ReceivingBatchRow,
|
||||||
|
props: {mode: 'viewing'},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/receiving/rows/:uuid/receive',
|
||||||
|
name: 'receiving.rows.receive',
|
||||||
|
component: ReceivingBatchRowReceive,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
const router = new VueRouter({
|
const router = new VueRouter({
|
||||||
|
|
608
mobile/src/views/receiving/ReceivingBatch.vue
Normal file
608
mobile/src/views/receiving/ReceivingBatch.vue
Normal file
|
@ -0,0 +1,608 @@
|
||||||
|
<template>
|
||||||
|
<byjove-model-crud model-name="PurchaseBatch"
|
||||||
|
model-index-title="Receiving"
|
||||||
|
model-title="Receiving Batch"
|
||||||
|
model-title-plural="Receiving Batches"
|
||||||
|
model-path-prefix="/receiving"
|
||||||
|
model-permission-prefix="receiving"
|
||||||
|
row-path-prefix="/receiving/rows"
|
||||||
|
:mode="mode"
|
||||||
|
@refresh="refreshData"
|
||||||
|
api-index-url="/api/receiving-batches"
|
||||||
|
api-object-url="/api/receiving-batch/"
|
||||||
|
:header-label-renderer="renderHeaderLabel"
|
||||||
|
:row-label-renderer="renderRowLabel"
|
||||||
|
:allow-edit="false"
|
||||||
|
has-rows
|
||||||
|
api-rows-url="/api/receiving-batch-rows"
|
||||||
|
@save="save"
|
||||||
|
:save-disabled="saveDisabled()"
|
||||||
|
:hide-buttons="hideButtons"
|
||||||
|
:row-filters="rowFilters"
|
||||||
|
:row-route-getter="getRowRoute"
|
||||||
|
ref="modelCrud"
|
||||||
|
>
|
||||||
|
|
||||||
|
<div v-if="mode == 'creating'">
|
||||||
|
|
||||||
|
<b-field label="Vendor"
|
||||||
|
:type="{'is-danger': !batch.vendor_uuid}">
|
||||||
|
<byjove-autocomplete v-model="batch.vendor_uuid"
|
||||||
|
service-url="/api/vendors/autocomplete">
|
||||||
|
</byjove-autocomplete>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<div v-show="batch.vendor_uuid">
|
||||||
|
|
||||||
|
<div v-show="!createMode"
|
||||||
|
class="buttons">
|
||||||
|
|
||||||
|
<b-button type="is-primary"
|
||||||
|
@click="receiveFromPO()">
|
||||||
|
Receive from PO
|
||||||
|
</b-button>
|
||||||
|
|
||||||
|
<b-button type="is-primary"
|
||||||
|
@click="receiveFromScratch()">
|
||||||
|
Receive from Scratch
|
||||||
|
</b-button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-show="createMode == 'from_po'">
|
||||||
|
<p>Please choose a Purchase Order to receive:</p>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<b-menu>
|
||||||
|
<b-menu-list>
|
||||||
|
<b-menu-item v-for="po in purchaseOrders"
|
||||||
|
:key="po.uuid"
|
||||||
|
tag="a" href="#"
|
||||||
|
@click.prevent="receivePO(po)">
|
||||||
|
<template slot="label" slot-scope="props">
|
||||||
|
<span>{{ po.display }}</span>
|
||||||
|
</template>
|
||||||
|
</b-menu-item>
|
||||||
|
</b-menu-list>
|
||||||
|
</b-menu>
|
||||||
|
|
||||||
|
<div v-if="!fetchingPurchaseOrders && !purchaseOrders.length"
|
||||||
|
class="has-text-info">
|
||||||
|
(no purchase orders found)
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<b-loading :active="fetchingPurchaseOrders || postingFormData"></b-loading>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
<b-button type="is-primary"
|
||||||
|
@click="receiveFromScratch()">
|
||||||
|
Receive from Scratch
|
||||||
|
</b-button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <b-field label="Description"> -->
|
||||||
|
<!-- <b-input v-model="batch.description"> -->
|
||||||
|
<!-- </b-input> -->
|
||||||
|
<!-- </b-field> -->
|
||||||
|
|
||||||
|
<!-- <b-field label="Notes"> -->
|
||||||
|
<!-- <b-input v-model="batch.notes" -->
|
||||||
|
<!-- type="textarea"> -->
|
||||||
|
<!-- </b-input> -->
|
||||||
|
<!-- </b-field> -->
|
||||||
|
</div>
|
||||||
|
<br />
|
||||||
|
</div> <!-- end creating -->
|
||||||
|
|
||||||
|
<div v-if="mode == 'viewing'">
|
||||||
|
|
||||||
|
<b-field label="Vendor">
|
||||||
|
<span>
|
||||||
|
{{ batch.vendor_display }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Department">
|
||||||
|
<span>
|
||||||
|
{{ batch.department_display }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<!-- <div v-if="!batch.executed && unprintedSpecialOrders" -->
|
||||||
|
<!-- class="buttons"> -->
|
||||||
|
<!-- <b-button type="is-primary" -->
|
||||||
|
<!-- @click="printSpecialOrderTickets()"> -->
|
||||||
|
<!-- Print {{ batch.special_orders.length }} Special Order Tickets -->
|
||||||
|
<!-- </b-button> -->
|
||||||
|
<!-- </div> -->
|
||||||
|
|
||||||
|
<div v-if="!batch.executed && batch.complete">
|
||||||
|
<b-field label="Description">
|
||||||
|
<span>
|
||||||
|
{{ batch.description }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Notes"
|
||||||
|
v-show="batch.notes">
|
||||||
|
<span>
|
||||||
|
{{ batch.notes }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br v-if="!batch.executed" />
|
||||||
|
|
||||||
|
<div v-if="batch.executed">
|
||||||
|
|
||||||
|
<b-field label="Created">
|
||||||
|
<span>
|
||||||
|
{{ batch.created }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Created By">
|
||||||
|
<span>
|
||||||
|
{{ batch.created_by_display }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Row Count">
|
||||||
|
<span>
|
||||||
|
{{ batch.rowcount }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Executed">
|
||||||
|
<span>
|
||||||
|
{{ batch.executed }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Executed By">
|
||||||
|
<span>
|
||||||
|
{{ batch.executed_by_display }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
</div> <!-- end executed -->
|
||||||
|
|
||||||
|
</div> <!-- end viewing -->
|
||||||
|
|
||||||
|
<!-- <b-field label="Vendor" -->
|
||||||
|
<!-- :type="{'is-danger': mode == 'creating' && !batch.vendor_uuid}"> -->
|
||||||
|
<!-- <byjove-autocomplete v-if="mode == 'creating'" -->
|
||||||
|
<!-- v-model="batch.vendor_uuid" -->
|
||||||
|
<!-- service-url="/api/vendors/autocomplete"> -->
|
||||||
|
<!-- </byjove-autocomplete> -->
|
||||||
|
<!-- <span v-if="mode != 'creating'"> -->
|
||||||
|
<!-- {{ batch.vendor_display }} -->
|
||||||
|
<!-- </span> -->
|
||||||
|
<!-- </b-field> -->
|
||||||
|
|
||||||
|
<!-- <b-field label="Description"> -->
|
||||||
|
<!-- <b-input v-if="mode == 'creating'" -->
|
||||||
|
<!-- v-model="batch.description"> -->
|
||||||
|
<!-- </b-input> -->
|
||||||
|
<!-- <span v-if="mode != 'creating'"> -->
|
||||||
|
<!-- {{ batch.description }} -->
|
||||||
|
<!-- </span> -->
|
||||||
|
<!-- </b-field> -->
|
||||||
|
|
||||||
|
<!-- <b-field label="Notes" -->
|
||||||
|
<!-- > -->
|
||||||
|
<!-- <\!-- v-show="mode == 'creating' || batch.notes" -\-> -->
|
||||||
|
<!-- <b-input v-if="mode == 'creating'" -->
|
||||||
|
<!-- v-model="batch.notes" -->
|
||||||
|
<!-- type="textarea"> -->
|
||||||
|
<!-- </b-input> -->
|
||||||
|
<!-- <span v-if="mode != 'creating'"> -->
|
||||||
|
<!-- {{ batch.notes }} -->
|
||||||
|
<!-- </span> -->
|
||||||
|
<!-- </b-field> -->
|
||||||
|
|
||||||
|
<!-- <b-field label="Created" -->
|
||||||
|
<!-- v-if="mode != 'creating' && batch.executed"> -->
|
||||||
|
<!-- <span> -->
|
||||||
|
<!-- {{ batch.created }} -->
|
||||||
|
<!-- </span> -->
|
||||||
|
<!-- </b-field> -->
|
||||||
|
|
||||||
|
<!-- <b-field label="Created By" -->
|
||||||
|
<!-- v-if="mode != 'creating' && batch.executed"> -->
|
||||||
|
<!-- <span> -->
|
||||||
|
<!-- {{ batch.created_by_display }} -->
|
||||||
|
<!-- </span> -->
|
||||||
|
<!-- </b-field> -->
|
||||||
|
|
||||||
|
<!-- <b-field label="Row Count" -->
|
||||||
|
<!-- v-if="mode != 'creating' && batch.executed"> -->
|
||||||
|
<!-- <span> -->
|
||||||
|
<!-- {{ batch.rowcount }} -->
|
||||||
|
<!-- </span> -->
|
||||||
|
<!-- </b-field> -->
|
||||||
|
|
||||||
|
<!-- <b-field label="Executed" -->
|
||||||
|
<!-- v-if="mode != 'creating' && batch.executed"> -->
|
||||||
|
<!-- <span> -->
|
||||||
|
<!-- {{ batch.executed }} -->
|
||||||
|
<!-- </span> -->
|
||||||
|
<!-- </b-field> -->
|
||||||
|
|
||||||
|
<!-- <b-field label="Executed By" -->
|
||||||
|
<!-- v-if="mode != 'creating' && batch.executed"> -->
|
||||||
|
<!-- <span> -->
|
||||||
|
<!-- {{ batch.executed_by_display }} -->
|
||||||
|
<!-- </span> -->
|
||||||
|
<!-- </b-field> -->
|
||||||
|
|
||||||
|
<template slot="quick-entry">
|
||||||
|
<div v-if="mode == 'viewing' && !batch.executed && !batch.complete">
|
||||||
|
<b-input v-model="quickEntry"
|
||||||
|
placeholder="Enter UPC"
|
||||||
|
icon="search"
|
||||||
|
@keypress.native="quickKey">
|
||||||
|
</b-input>
|
||||||
|
<br />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template slot="row-filters">
|
||||||
|
<b-field grouped group-multiline>
|
||||||
|
<b-radio-button v-model="selectedRowFilter"
|
||||||
|
native-value="is_incomplete">
|
||||||
|
<span>incomplete</span>
|
||||||
|
</b-radio-button>
|
||||||
|
<b-radio-button v-model="selectedRowFilter"
|
||||||
|
native-value="is_unexpected">
|
||||||
|
<span>unexpected</span>
|
||||||
|
</b-radio-button>
|
||||||
|
<b-radio-button v-model="selectedRowFilter"
|
||||||
|
native-value="is_damaged">
|
||||||
|
<span>damaged</span>
|
||||||
|
</b-radio-button>
|
||||||
|
<b-radio-button v-model="selectedRowFilter"
|
||||||
|
native-value="is_invalid">
|
||||||
|
<span>invalid</span>
|
||||||
|
</b-radio-button>
|
||||||
|
<b-radio-button v-model="selectedRowFilter"
|
||||||
|
native-value="all">
|
||||||
|
<span>all</span>
|
||||||
|
</b-radio-button>
|
||||||
|
</b-field>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template slot="footer"
|
||||||
|
v-if="mode == 'viewing' && !batch.executed">
|
||||||
|
<br />
|
||||||
|
<div class="buttons is-centered">
|
||||||
|
<b-button v-if="!batch.complete"
|
||||||
|
type="is-primary"
|
||||||
|
@click="markReceivingComplete()">
|
||||||
|
Receiving is Complete!
|
||||||
|
</b-button>
|
||||||
|
<!-- <b-button v-if="batch.special_orders && (ticketsPrinted || !unprintedSpecialOrders)" -->
|
||||||
|
<!-- type="is-primary" -->
|
||||||
|
<!-- @click="printSpecialOrderTickets()"> -->
|
||||||
|
<!-- Re-print {{ batch.special_orders.length }} Special Order Tickets -->
|
||||||
|
<!-- </b-button> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</byjove-model-crud>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {ByjoveModelCrud, ByjoveAutocomplete} from 'byjove'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ReceivingBatch',
|
||||||
|
props: {
|
||||||
|
mode: String,
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
ByjoveModelCrud,
|
||||||
|
ByjoveAutocomplete,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
createMode: null,
|
||||||
|
purchaseOrders: [],
|
||||||
|
fetchingPurchaseOrders: false,
|
||||||
|
postingFormData: false,
|
||||||
|
batch: {},
|
||||||
|
quickEntry: '',
|
||||||
|
ticketsPrinted: false,
|
||||||
|
|
||||||
|
selectedRowFilter: 'is_incomplete',
|
||||||
|
possibleRowFilters: {
|
||||||
|
'is_incomplete': [
|
||||||
|
{field: 'is_incomplete', op: 'eq', value: true},
|
||||||
|
],
|
||||||
|
'is_unexpected': [
|
||||||
|
{field: 'is_unexpected', op: 'eq', value: true},
|
||||||
|
],
|
||||||
|
'is_damaged': [
|
||||||
|
{field: 'is_damaged', op: 'eq', value: true},
|
||||||
|
],
|
||||||
|
'is_invalid': [
|
||||||
|
{field: 'is_invalid', op: 'eq', value: true},
|
||||||
|
],
|
||||||
|
'all': [],
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
hideButtons: function() {
|
||||||
|
if (this.mode == 'creating') {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
// unprintedSpecialOrders() {
|
||||||
|
// if (!this.batch.special_orders) {
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
// if (!this.batch.special_orders.length) {
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
// if (!this.batch.params) {
|
||||||
|
// return true
|
||||||
|
// }
|
||||||
|
// if (this.batch.params.special_order_tickets_printed) {
|
||||||
|
// return false
|
||||||
|
// }
|
||||||
|
// return true
|
||||||
|
// },
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
|
||||||
|
'batch.vendor_uuid' (to, from) {
|
||||||
|
// when vendor selection is cleared, we must also "forget" our
|
||||||
|
// batch creation mode, so UI behaves as expected
|
||||||
|
if (!to) {
|
||||||
|
this.createMode = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
'selectedRowFilter' (to, from) {
|
||||||
|
// when user changes row filter, tell model-crud to fetch rows
|
||||||
|
this.$refs.modelCrud.fetchRows(this.batch.uuid)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
window.addEventListener('keypress', this.globalKey)
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
window.removeEventListener('keypress', this.globalKey)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
renderHeaderLabel(batch) {
|
||||||
|
let label = batch.id_str
|
||||||
|
if (batch.executed) {
|
||||||
|
label += " (executed)"
|
||||||
|
} else if (batch.complete) {
|
||||||
|
label += " (complete)"
|
||||||
|
} else {
|
||||||
|
label += " (pending)"
|
||||||
|
}
|
||||||
|
return label
|
||||||
|
},
|
||||||
|
|
||||||
|
renderRowLabel(row) {
|
||||||
|
return `(${row.cases_received || 0} / ${row.units_received || 0}) ${row.full_description}`
|
||||||
|
},
|
||||||
|
|
||||||
|
globalKey(event) {
|
||||||
|
if (event.target.tagName == 'BODY') {
|
||||||
|
|
||||||
|
// mimic keyboard wedge
|
||||||
|
if (event.charCode >= 48 && event.charCode <= 57) { // numeric (qwerty)
|
||||||
|
this.$nextTick(function() {
|
||||||
|
this.quickEntry += event.key
|
||||||
|
})
|
||||||
|
|
||||||
|
} else if (event.keyCode == 13) { // enter
|
||||||
|
this.submitQuickEntry()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
quickKey(event) {
|
||||||
|
if (event.keyCode == 13) { // enter
|
||||||
|
this.submitQuickEntry()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
submitQuickEntry() {
|
||||||
|
if (!this.quickEntry) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let params = {
|
||||||
|
batch_uuid: this.batch.uuid,
|
||||||
|
quick_entry: this.quickEntry,
|
||||||
|
}
|
||||||
|
let url = '/api/receiving-batch-rows/quick-entry'
|
||||||
|
this.$http.post(url, params).then(response => {
|
||||||
|
if (response.data.data) {
|
||||||
|
this.$router.push(`/receiving/rows/${response.data.data.uuid}/receive`)
|
||||||
|
} else {
|
||||||
|
this.$buefy.toast.open({
|
||||||
|
message: response.data.error || "Failed to post quick entry!",
|
||||||
|
type: 'is-danger',
|
||||||
|
position: 'is-bottom',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, response => {
|
||||||
|
this.$buefy.toast.open({
|
||||||
|
message: "Failed to post quick entry!",
|
||||||
|
type: 'is-danger',
|
||||||
|
position: 'is-bottom',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
markReceivingComplete() {
|
||||||
|
this.$http.post(`/api/receiving-batch/${this.batch.uuid}/mark-receiving-complete`).then(response => {
|
||||||
|
if (response.data.data) {
|
||||||
|
this.batch = response.data.data
|
||||||
|
this.$router.push('/receiving')
|
||||||
|
} else {
|
||||||
|
this.$buefy.toast.open({
|
||||||
|
message: response.data.error || "Failed to mark receiving complete!",
|
||||||
|
type: 'is-danger',
|
||||||
|
position: 'is-bottom',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, response => {
|
||||||
|
this.$buefy.toast.open({
|
||||||
|
message: "Failed to mark receiving complete!",
|
||||||
|
type: 'is-danger',
|
||||||
|
position: 'is-bottom',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
receiveFromPO() {
|
||||||
|
// here we will fetch all "eligible" purchase orders from backend,
|
||||||
|
// so user can then choose one to receive from/against
|
||||||
|
this.purchaseOrders = []
|
||||||
|
this.fetchingPurchaseOrders = true
|
||||||
|
this.createMode = 'from_po'
|
||||||
|
|
||||||
|
let url = '/api/receiving-batches/eligible-purchases'
|
||||||
|
let params = {
|
||||||
|
'vendor_uuid': this.batch.vendor_uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$http.get(url, {params: params}).then(response => {
|
||||||
|
if (response.data.purchases) {
|
||||||
|
this.purchaseOrders = response.data.purchases
|
||||||
|
this.fetchingPurchaseOrders = false
|
||||||
|
} else {
|
||||||
|
this.$buefy.toast.open({
|
||||||
|
message: response.data.error || "Failed to fetch available purchases!",
|
||||||
|
type: 'is-danger',
|
||||||
|
position: 'is-bottom',
|
||||||
|
})
|
||||||
|
this.fetchingPurchaseOrders = false
|
||||||
|
}
|
||||||
|
}, response => {
|
||||||
|
this.$buefy.toast.open({
|
||||||
|
message: "Failed to fetch available purchases!",
|
||||||
|
type: 'is-danger',
|
||||||
|
position: 'is-bottom',
|
||||||
|
})
|
||||||
|
this.fetchingPurchaseOrders = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
receivePO(po) {
|
||||||
|
// user has chosen a purchase order (PO) for which they wish to do
|
||||||
|
// receiving. so we create a new batch from that PO
|
||||||
|
this.batch.purchase_key = po.key
|
||||||
|
this.batch.description = "(from PO)"
|
||||||
|
this.postingFormData = true
|
||||||
|
this.save()
|
||||||
|
},
|
||||||
|
|
||||||
|
receiveFromScratch() {
|
||||||
|
// if user intends to receive "from scratch" then we can
|
||||||
|
// immediately create a new (empty) batch and send them to it
|
||||||
|
this.batch.description = "(from scratch)"
|
||||||
|
this.save()
|
||||||
|
},
|
||||||
|
|
||||||
|
getRowRoute(row) {
|
||||||
|
return `/receiving/rows/${row.uuid}/receive`
|
||||||
|
},
|
||||||
|
|
||||||
|
rowFilters(uuid) {
|
||||||
|
let filters = [{field: 'batch_uuid', op: 'eq', value: uuid}]
|
||||||
|
filters = filters.concat(this.possibleRowFilters[this.selectedRowFilter])
|
||||||
|
return JSON.stringify(filters)
|
||||||
|
},
|
||||||
|
|
||||||
|
refreshData(record) {
|
||||||
|
this.batch = record
|
||||||
|
if (this.batch.complete) {
|
||||||
|
this.selectedRowFilter = 'all'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
saveDisabled() {
|
||||||
|
|
||||||
|
// vendor is required when creating
|
||||||
|
if (this.mode == 'creating' && !this.batch.vendor_uuid) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// save is allowed by default
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
|
||||||
|
save(url) {
|
||||||
|
if (url === undefined) {
|
||||||
|
url = '/api/receiving-batches'
|
||||||
|
}
|
||||||
|
let params = {
|
||||||
|
vendor_uuid: this.batch.vendor_uuid,
|
||||||
|
description: this.batch.description,
|
||||||
|
notes: this.batch.notes,
|
||||||
|
}
|
||||||
|
if (this.mode == 'creating') {
|
||||||
|
params.purchase_key = this.batch.purchase_key
|
||||||
|
}
|
||||||
|
this.$http.post(url, params).then(response => {
|
||||||
|
if (response.data.data) {
|
||||||
|
this.$router.push('/receiving/' + response.data.data.uuid)
|
||||||
|
} else {
|
||||||
|
this.$buefy.toast.open({
|
||||||
|
message: response.data.error || "Failed to save batch!",
|
||||||
|
type: 'is-danger',
|
||||||
|
position: 'is-bottom',
|
||||||
|
})
|
||||||
|
this.postingFormData = false
|
||||||
|
}
|
||||||
|
}, response => {
|
||||||
|
this.$buefy.toast.open({
|
||||||
|
message: "Failed to save batch!",
|
||||||
|
type: 'is-danger',
|
||||||
|
position: 'is-bottom',
|
||||||
|
})
|
||||||
|
this.postingFormData = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// printSpecialOrderTickets() {
|
||||||
|
// let url = `/api/receiving-batch/${this.batch.uuid}/print-special-order-tickets`
|
||||||
|
// this.$http.post(url).then(response => {
|
||||||
|
// if (response.data.ok) {
|
||||||
|
// // must update our batch, so we know tickets were printed
|
||||||
|
// this.batch = response.data.batch
|
||||||
|
// this.$buefy.toast.open({
|
||||||
|
// message: `${response.data.printed} tickets were sent to the printer`,
|
||||||
|
// type: 'is-success',
|
||||||
|
// })
|
||||||
|
|
||||||
|
// } else {
|
||||||
|
// this.$buefy.toast.open({
|
||||||
|
// message: response.data.error || "Something went wrong!",
|
||||||
|
// type: 'is-danger',
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// }, response => {
|
||||||
|
// this.$buefy.toast.open({
|
||||||
|
// message: response.data.error,
|
||||||
|
// type: 'is-danger',
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
// },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
193
mobile/src/views/receiving/ReceivingBatchRow.vue
Normal file
193
mobile/src/views/receiving/ReceivingBatchRow.vue
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
<template>
|
||||||
|
<byjove-model-crud model-name="ReceivingBatchRow"
|
||||||
|
model-index-title="Receiving"
|
||||||
|
:mode="mode"
|
||||||
|
:header-label-renderer="renderHeaderLabel"
|
||||||
|
:parent-header-label-renderer="renderParentHeaderLabel"
|
||||||
|
api-object-url="/api/receiving-batch-row/"
|
||||||
|
model-path-prefix="/receiving"
|
||||||
|
@refresh="record => { row = record }"
|
||||||
|
is-row
|
||||||
|
:allow-edit="false"
|
||||||
|
>
|
||||||
|
<!-- TODO: allow-edit should be be true if batch still open -->
|
||||||
|
<!-- model-title="Ordering Batch" -->
|
||||||
|
<!-- model-title-plural="Ordering Batches" -->
|
||||||
|
<!-- api-index-url="/api/ordering-batches" -->
|
||||||
|
<!-- :row-label-renderer="renderRowLabel" -->
|
||||||
|
<!-- @save="save" -->
|
||||||
|
|
||||||
|
<b-field label="UPC">
|
||||||
|
<span>
|
||||||
|
{{ row.upc_pretty }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Brand">
|
||||||
|
<span>
|
||||||
|
{{ row.brand_name }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Description">
|
||||||
|
<span>
|
||||||
|
{{ row.description }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Size">
|
||||||
|
<span>
|
||||||
|
{{ row.size }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Case Size">
|
||||||
|
<span>
|
||||||
|
{{ row.case_quantity }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Cases Ordered">
|
||||||
|
<span>
|
||||||
|
{{ row.cases_ordered }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Units Ordered">
|
||||||
|
<span>
|
||||||
|
{{ row.units_ordered }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Cases Shipped">
|
||||||
|
<span>
|
||||||
|
{{ row.cases_shipped }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Units Shipped">
|
||||||
|
<span>
|
||||||
|
{{ row.units_shipped }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Cases Received">
|
||||||
|
<span>
|
||||||
|
{{ row.cases_received }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Units Received">
|
||||||
|
<span>
|
||||||
|
{{ row.units_received }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Cases Damaged">
|
||||||
|
<span>
|
||||||
|
{{ row.cases_damaged }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Units Damaged">
|
||||||
|
<span>
|
||||||
|
{{ row.units_damaged }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Cases Expired">
|
||||||
|
<span>
|
||||||
|
{{ row.cases_expired }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Units Expired">
|
||||||
|
<span>
|
||||||
|
{{ row.units_expired }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<b-field label="Status">
|
||||||
|
<span>
|
||||||
|
{{ row.status_display }}
|
||||||
|
</span>
|
||||||
|
</b-field>
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
<div class="buttons">
|
||||||
|
<b-button type="is-primary"
|
||||||
|
tag="router-link"
|
||||||
|
:to="`/receiving/rows/${row.uuid}/receive`">
|
||||||
|
Receive against this Row
|
||||||
|
</b-button>
|
||||||
|
<b-button type="is-primary"
|
||||||
|
tag="router-link"
|
||||||
|
:to="`/receiving/rows/${row.uuid}/edit`"
|
||||||
|
disabled>
|
||||||
|
Edit this Row
|
||||||
|
</b-button>
|
||||||
|
<b-button type="is-danger"
|
||||||
|
disabled>
|
||||||
|
Delete this Row
|
||||||
|
</b-button> </div>
|
||||||
|
|
||||||
|
</byjove-model-crud>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {ByjoveModelCrud} from 'byjove'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ReceivingBatchRow',
|
||||||
|
props: {
|
||||||
|
mode: String,
|
||||||
|
allowCases: { // TODO
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
allowExpired: { // TODO
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
orderQuantitiesKnown: { // TODO
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
ByjoveModelCrud,
|
||||||
|
},
|
||||||
|
data: function() {
|
||||||
|
return {
|
||||||
|
row: {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
renderParentHeaderLabel(row) {
|
||||||
|
return row.batch_id_str
|
||||||
|
},
|
||||||
|
|
||||||
|
renderHeaderLabel(row) {
|
||||||
|
return row.upc_pretty
|
||||||
|
},
|
||||||
|
|
||||||
|
// save(url) {
|
||||||
|
// let params = {
|
||||||
|
// item_id: this.product.item_id,
|
||||||
|
// description: this.product.description,
|
||||||
|
// }
|
||||||
|
// this.$http.post(url, params).then(response => {
|
||||||
|
// this.$router.push('/products/' + response.data.data.uuid)
|
||||||
|
// })
|
||||||
|
// },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- <style> -->
|
||||||
|
<!-- table.receiving-quantities td { -->
|
||||||
|
<!-- padding: 0px 10px 0px 0px; -->
|
||||||
|
<!-- } -->
|
||||||
|
<!-- </style> -->
|
15
mobile/src/views/receiving/ReceivingBatchRowReceive.vue
Normal file
15
mobile/src/views/receiving/ReceivingBatchRowReceive.vue
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<template>
|
||||||
|
<byjove-receiving>
|
||||||
|
</byjove-receiving>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {ByjoveReceiving} from 'byjove'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ReceivingBatchRowReceive',
|
||||||
|
components: {
|
||||||
|
ByjoveReceiving,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
44
mobile/src/views/receiving/ReceivingBatches.vue
Normal file
44
mobile/src/views/receiving/ReceivingBatches.vue
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<template>
|
||||||
|
<byjove-model-index model-name="PurchaseBatch"
|
||||||
|
model-index-title="Receiving"
|
||||||
|
model-title="Receiving Batch"
|
||||||
|
model-title-plural="Receiving Batches"
|
||||||
|
model-path-prefix="/receiving"
|
||||||
|
model-permission-prefix="receiving"
|
||||||
|
api-index-url="/api/receiving-batches"
|
||||||
|
:api-index-sort="{field: 'id', dir: 'desc'}"
|
||||||
|
:api-index-filters="filters"
|
||||||
|
:label-renderer="renderLabel">
|
||||||
|
</byjove-model-index>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {ByjoveModelIndex} from 'byjove'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ReceivingBatches',
|
||||||
|
components: {
|
||||||
|
ByjoveModelIndex,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
filters: [
|
||||||
|
{field: 'executed', op: 'is_null'},
|
||||||
|
{or: [
|
||||||
|
{field: 'receiving_complete', op: 'is_null'},
|
||||||
|
{field: 'receiving_complete', op: 'eq', value: false},
|
||||||
|
]},
|
||||||
|
{or: [
|
||||||
|
{field: 'complete', op: 'is_null'},
|
||||||
|
{field: 'complete', op: 'eq', value: false},
|
||||||
|
]},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
renderLabel(batch) {
|
||||||
|
return `(${batch.id_str}) ${batch.vendor_display}; ${batch.description || ''} (${batch.rowcount} rows)`
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
11
mobile/src/views/receiving/index.js
Normal file
11
mobile/src/views/receiving/index.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import ReceivingBatches from './ReceivingBatches'
|
||||||
|
import ReceivingBatch from './ReceivingBatch'
|
||||||
|
import ReceivingBatchRow from './ReceivingBatchRow'
|
||||||
|
import ReceivingBatchRowReceive from './ReceivingBatchRowReceive'
|
||||||
|
|
||||||
|
export {
|
||||||
|
ReceivingBatches,
|
||||||
|
ReceivingBatch,
|
||||||
|
ReceivingBatchRow,
|
||||||
|
ReceivingBatchRowReceive,
|
||||||
|
}
|
|
@ -36,3 +36,4 @@ def includeme(config):
|
||||||
|
|
||||||
# batches
|
# batches
|
||||||
config.include('tailbone.api.batch.ordering')
|
config.include('tailbone.api.batch.ordering')
|
||||||
|
config.include('tailbone.api.batch.receiving')
|
||||||
|
|
Loading…
Reference in a new issue