Add basic "receiving" support for theo mobile
This commit is contained in:
		
							parent
							
								
									3779d7b9f4
								
							
						
					
					
						commit
						22aad5e31f
					
				
					 8 changed files with 917 additions and 0 deletions
				
			
		|  | @ -11,6 +11,12 @@ | |||
|       <router-link to="/ordering/">Ordering</router-link> | ||||
|     </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> | ||||
| </template> | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ import VueRouter from 'vue-router' | |||
| import Home from '../views/Home.vue' | ||||
| import Login from '../views/Login.vue' | ||||
| import {OrderingBatches, OrderingBatch, OrderingBatchRow, OrderingBatchWorksheet} from '../views/ordering' | ||||
| import {ReceivingBatches, ReceivingBatch, ReceivingBatchRow, ReceivingBatchRowReceive} from '../views/receiving' | ||||
| 
 | ||||
| Vue.use(VueRouter) | ||||
| 
 | ||||
|  | @ -75,6 +76,44 @@ const routes = [ | |||
|         name: 'ordering.worksheet', | ||||
|         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({ | ||||
|  |  | |||
							
								
								
									
										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 | ||||
|     config.include('tailbone.api.batch.ordering') | ||||
|     config.include('tailbone.api.batch.receiving') | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Lance Edgar
						Lance Edgar